The Problem
Machine‑learning teams need a reproducible way to search hyper‑parameter spaces without writing boilerplate optimisation loops. Manual grid or random search quickly becomes unmanageable as models and constraints grow.
What This Does
optuna supplies a Python‑first API that lets users declare search spaces inline (optuna.trial.Trial.suggest_*), launch studies with optuna.create_study, and let the library drive sampling, pruning and persistence. Core logic lives in optuna/__init__.py, optuna/trial/__init__.py and optuna/study/__init__.py, which together expose 187 downstream imports. The distribution layer (optuna/storages/_base.py, optuna/storages/_rdb/storage.py) abstracts SQLite, PostgreSQL or RDB‑backed storage, while the CLI (optuna/cli.py) offers a command‑line front‑end for common actions such as create-study and optimize.
How It Is Wired
Execution begins at optuna/cli.py. The main function (line 977) parses arguments, builds a Storage via _get_storage (line 57) and then calls the high‑traffic helper create_study (called from 463 sites). create_study lives in optuna/storages/_base.py; it opens a scoped DB session (_create_scoped_session) and writes a new study row (outbound DB write).
From there the typical optimisation loop proceeds: Study.optimize repeatedly invokes Trial._suggest_* (defined in optuna/trial/_base.py) which ultimately calls the sampler (optuna/samplers/_tpe/sampler.py for TPE, optuna/samplers/_random.py for random). The most frequently invoked sampler class is TPESampler (referenced from 54 places). Each trial records results via Trial.report and may be pruned through Pruner implementations (optuna/pruners/_hyperband.py is called from 32 places).
All persistence routes back through the storage layer: optuna/storages/_rdb/storage.py performs the actual SQLAlchemy commits, while optuna/storages/journal/_storage.py writes replay logs to the filesystem. The CLI also writes human‑readable output via _format_output (line 244).
The import graph shows a dense hub: optuna/__init__.py is imported by 187 modules and participates in a circular dependency with optuna/trial/__init__.py and optuna/study/__init__.py. This cycle inflates change impact because any modification to the hub propagates widely. The largest single file, optuna/study/study.py (1 280 lines), defines the public Study API and is called from 86 other files, making it a high‑blast‑radius target for refactoring.
How To Use It
# Clone the fork
git clone https://github.com/moses-y/optuna
cd optuna
# Install in editable mode (pyproject.toml is the only manifest)
pip install -e .
# Run a simple optimisation from the CLI
python -m optuna.cli create-study --storage sqlite:///example.db --study-name demo
python -m optuna.cli optimize demo --n-trials 20
The CLI accepts a SQLAlchemy URL via --storage; no additional environment files are required. For programmatic use, import the public API:
import optuna
def objective(trial):
x = trial.suggest_float("x", -10, 10)
return (x - 2) ** 2
study = optuna.create_study(storage="sqlite:///example.db")
study.optimize(objective, n_trials=30)
Real‑World Use
A data‑science platform can spin up a Docker container that runs the above script on each model version. The study metadata is persisted in a shared PostgreSQL instance (--storage postgresql://user:pwd@host/db), enabling multiple workers to pull pending trials via the same Study.optimize call, achieving horizontal scaling without custom orchestration.
Code Health & Issues
- High – Lockfile missing –
pyproject.tomldeclares dependencies but no lockfile; reproducible builds are not guaranteed. - Medium – GITHUB_TOKEN permissions –
.github/workflows/checks-optional.yamllacks explicit permissions, giving the default write scope. - Medium – No automated dependency updater – No Dependabot or Renovate configuration.
- Medium – No dependency‑vulnerability gate – CI does not run a vulnerability scanner.
- Low – No workflow timeouts – Jobs in
.github/workflows/checks-optional.yamllacktimeout-minutes.
Measured static findings (high confidence):
- Import cycles (32) –
optuna/__init__.py,optuna/trial/__init__.py,optuna/study/__init__.py. Break cycles to reduce churn. - Hub module (14) – Same three files import 187 modules; keep them stable.
- Deep nesting (9) – Functions in
optuna/distributions.py,optuna/exceptions.py,optuna/study/study.pyreach 6‑level indentation. Refactor for readability. - Oversized file –
optuna/study/study.py(1 280 lines) is a maintenance hotspot; consider splitting by responsibility. - File opened without context –
optuna/testing/storages.py,optuna/artifacts/_protocol.py. Usewith open(...). - Broad exception handling –
optuna/storages/_rdb/storage.py,optuna/storages/journal/_storage.py. Catch specific errors.
No missing license, tests, or secret leaks were detected.
The Bottom Line
optuna delivers a mature, well‑tested hyper‑parameter optimisation stack with a clean Python API and flexible storage back‑ends. Its main drawbacks are a central import hub that creates a large change surface and the absence of a lockfile, which hampers reproducible deployments. Teams comfortable managing Python dependencies and willing to isolate the hub for future refactoring will find it a solid foundation for scalable model tuning.