Оптимизация на хиперпараметри с Optuna в Python: Пълно ръководство (2026)

Практическо ръководство за Optuna 4.x в Python: TPE и GP samplers, pruning, multi-objective оптимизация и работещи примери със Scikit-learn и XGBoost за 2026 г.

Optuna 4.x Hyperparameter Tuning: Guide 2026

Изборът на правилните хиперпараметри често е разликата между моделен прототип и решение, готово за продукция. Звучи драматично, нали? Истината обаче е, че съм виждал XGBoost модел да скочи от 0.82 на 0.91 AUC само заради смислено tuning — без нито един нов feature. Точно тук на сцената излиза Optuna.

Тя се превърна в де факто стандарт за автоматизирана оптимизация на хиперпараметри в Python, и то с пълно основание — благодарение на интуитивния си define-by-run API, ефективния TPE алгоритъм и вградените механизми за pruning.

В това ръководство ще преминем през всичко, което ви трябва, за да започнете с Optuna 4.x през 2026 г.: от инсталация и базови концепции до интеграция със Scikit-learn и XGBoost, multi-objective оптимизация и нови samplers като GPSampler и AutoSampler. Хайде да започваме.

Какво е Optuna и защо изобщо да я ползваме?

Optuna е framework за автоматизирана оптимизация на хиперпараметри, проектиран специално за машинно обучение. За разлика от класическите подходи като GridSearchCV и RandomizedSearchCV в Scikit-learn, Optuna използва Байесова оптимизация, за да насочи търсенето към най-обещаващите комбинации.

С други думи — вместо сляпо да изпробва всичко (или произволни точки), тя „учи" от резултатите на предишните trials и предлага следващите по-умно.

Основни предимства спрямо GridSearch

  • Define-by-run API — пространството за търсене се дефинира динамично в Python код, а не статично в речник.
  • TPE (Tree-structured Parzen Estimator) — интелигентно sampling, което се подобрява с всеки опит.
  • Pruning — Optuna автоматично прекратява безперспективните trials, спестявайки часове изчислителна мощност.
  • Multi-objective — оптимизирайте едновременно accuracy и inference time, например.
  • Persistence — съхранение на резултатите в SQLite, PostgreSQL или MySQL за продължаване по-късно.
  • Framework-agnostic — работи със Scikit-learn, XGBoost, LightGBM, PyTorch, TensorFlow и т.н.

Инсталация и подготовка на средата

Към май 2026 г. последната стабилна версия е Optuna 4.7. Инсталацията е стандартна с pip — никакви изненади тук:

pip install optuna optuna-dashboard scikit-learn xgboost

За работа с напреднали samplers като GPSampler и AutoSampler от OptunaHub ще ви трябва още един пакет:

pip install optunahub

Първият ви Optuna study: минимален пример

Преди да минем към реални ML модели, нека разгледаме каноничния минимален пример — намиране на минимума на квадратична функция. Това е „hello world"-ът на Optuna:

import optuna

def objective(trial):
    x = trial.suggest_float("x", -10, 10)
    return (x - 2) ** 2

study = optuna.create_study(direction="minimize")
study.optimize(objective, n_trials=100)

print(f"Best value: {study.best_value:.4f}")
print(f"Best params: {study.best_params}")

Ключовите концепции тук са три:

  • Trial — едно изпълнение на objective функцията с конкретен набор параметри.
  • Study — колекция от trials, които заедно формират процеса на оптимизация.
  • suggest_* методите — те съобщават на Optuna какви параметри да предложи.

Типове suggest методи

Optuna поддържа доста широк набор от типове параметри. На практика тези четири покриват около 95% от случаите:

# Числови параметри
trial.suggest_float("learning_rate", 1e-5, 1e-1, log=True)
trial.suggest_int("n_estimators", 50, 1000, step=50)

# Категориални параметри
trial.suggest_categorical("optimizer", ["adam", "sgd", "rmsprop"])

# Дискретни числа с фиксирана стъпка
trial.suggest_float("dropout", 0.1, 0.5, step=0.05)

Малка, но важна подробност: аргументът log=True е особено важен за параметри като learning rate или regularization. Те почти винаги се изследват най-добре в логаритмична скала — иначе хабите trials в нерелевантни области.

Optuna със Scikit-learn: реален пример

Сега ще оптимизираме RandomForestClassifier върху Breast Cancer датасета. Това е често срещан baseline за класификация и (честно казано) перфектен пример, на който да видите Optuna в действие:

import optuna
from sklearn.datasets import load_breast_cancer
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import cross_val_score

X, y = load_breast_cancer(return_X_y=True)

def objective(trial):
    params = {
        "n_estimators": trial.suggest_int("n_estimators", 100, 1000, step=50),
        "max_depth": trial.suggest_int("max_depth", 3, 30),
        "min_samples_split": trial.suggest_int("min_samples_split", 2, 20),
        "min_samples_leaf": trial.suggest_int("min_samples_leaf", 1, 10),
        "max_features": trial.suggest_categorical(
            "max_features", ["sqrt", "log2", None]
        ),
        "bootstrap": trial.suggest_categorical("bootstrap", [True, False]),
    }

    model = RandomForestClassifier(**params, random_state=42, n_jobs=-1)
    score = cross_val_score(model, X, y, cv=5, scoring="roc_auc").mean()
    return score

study = optuna.create_study(direction="maximize", study_name="rf_tuning")
study.optimize(objective, n_trials=50, n_jobs=-1)

print(f"Best AUC: {study.best_value:.4f}")
print(f"Best params: {study.best_params}")

Забележете два важни детайла:

  1. direction="maximize" — защото искаме да максимизираме AUC.
  2. n_jobs=-1 в study.optimize позволява паралелно изпълнение на trials.

Optuna с XGBoost и pruning

За градиентни boosting модели като XGBoost pruning е просто незаменим. Тя позволява на Optuna да спре trial по средата на тренировката, ако той не показва обещаващи резултати — нещо като „виждам накъде вървиш, спести ми още 400 boost rounds":

import optuna
import xgboost as xgb
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split

X, y = load_breast_cancer(return_X_y=True)
X_train, X_val, y_train, y_val = train_test_split(
    X, y, test_size=0.2, random_state=42, stratify=y
)

dtrain = xgb.DMatrix(X_train, label=y_train)
dvalid = xgb.DMatrix(X_val, label=y_val)

def objective(trial):
    params = {
        "objective": "binary:logistic",
        "eval_metric": "auc",
        "booster": trial.suggest_categorical("booster", ["gbtree", "dart"]),
        "lambda": trial.suggest_float("lambda", 1e-8, 1.0, log=True),
        "alpha": trial.suggest_float("alpha", 1e-8, 1.0, log=True),
        "subsample": trial.suggest_float("subsample", 0.5, 1.0),
        "colsample_bytree": trial.suggest_float("colsample_bytree", 0.5, 1.0),
        "max_depth": trial.suggest_int("max_depth", 3, 10),
        "learning_rate": trial.suggest_float("learning_rate", 1e-3, 0.3, log=True),
    }

    # Pruning callback — спира trial-а ако не се представя добре
    pruning_callback = optuna.integration.XGBoostPruningCallback(
        trial, "validation-auc"
    )

    booster = xgb.train(
        params,
        dtrain,
        num_boost_round=500,
        evals=[(dvalid, "validation")],
        callbacks=[pruning_callback],
        early_stopping_rounds=20,
        verbose_eval=False,
    )

    return booster.best_score

study = optuna.create_study(
    direction="maximize",
    pruner=optuna.pruners.HyperbandPruner(min_resource=10, max_resource=500),
    sampler=optuna.samplers.TPESampler(seed=42),
)
study.optimize(objective, n_trials=100, timeout=600)

print(f"Best AUC: {study.best_value:.4f}")
print(f"Number of pruned trials: {len([t for t in study.trials if t.state == optuna.trial.TrialState.PRUNED])}")

Комбинацията TPESampler + HyperbandPruner е сред най-ефективните според официалните бенчмаркове на Optuna. В мой неотдавнашен проект с tabular data това намали времето за tuning от около 4 часа до под един — без забележим спад в крайното качество.

Samplers: коя стратегия да изберем?

Optuna предлага няколко стратегии за sampling. Изборът зависи от вашия проблем — няма универсален победител.

TPESampler (по подразбиране)

Tree-structured Parzen Estimator е стандартният избор за повечето задачи. От версия 4.x подобрението multivariate=True допълнително повишава ефективността:

sampler = optuna.samplers.TPESampler(
    multivariate=True,
    group=True,
    seed=42,
)

GPSampler (Gaussian Process)

За много скъпи objective функции (например тренировка на дълбоки невронни мрежи), GPSampler постига по-висока sample-efficiency. В Optuna 4.6 беше сериозно оптимизиран и работи около 8 пъти по-бързо от предишните версии:

sampler = optuna.samplers.GPSampler(seed=42)
study = optuna.create_study(direction="maximize", sampler=sampler)

AutoSampler (OptunaHub)

Не сте сигурни кой sampler да изберете? AutoSampler автоматично избира най-подходящия алгоритъм според характеристиките на задачата. Прекрасен default за неопитни потребители:

import optunahub

module = optunahub.load_module("samplers/auto_sampler")
sampler = module.AutoSampler()

study = optuna.create_study(direction="maximize", sampler=sampler)

Multi-objective оптимизация

В реални продукционни системи често искате да оптимизирате повече от една метрика — например да постигнете висока точност и ниско време за inference. (Особено ако моделът ви ще обслужва трафик в реално време.) Optuna поддържа това директно:

import time
import optuna
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import cross_val_score

X, y = load_breast_cancer(return_X_y=True)

def objective(trial):
    n_estimators = trial.suggest_int("n_estimators", 50, 1000, step=50)
    max_depth = trial.suggest_int("max_depth", 3, 30)

    model = RandomForestClassifier(
        n_estimators=n_estimators,
        max_depth=max_depth,
        n_jobs=-1,
        random_state=42,
    )

    accuracy = cross_val_score(model, X, y, cv=3, scoring="roc_auc").mean()

    start = time.perf_counter()
    model.fit(X, y)
    _ = model.predict(X[:100])
    inference_time = time.perf_counter() - start

    return accuracy, inference_time

study = optuna.create_study(directions=["maximize", "minimize"])
study.optimize(objective, n_trials=50)

# Pareto-оптимални trials
for trial in study.best_trials:
    print(f"Trial {trial.number}: AUC={trial.values[0]:.4f}, Time={trial.values[1]:.4f}s")

Резултатът е Pareto front — множество решения, при които не можете да подобрите едната метрика без да влошите другата. Изборът кое от тях да отиде в продукция вече е чисто бизнес решение.

Визуализация на резултатите

Optuna идва с богат набор от вградени визуализации, базирани на Plotly. Лично аз винаги започвам с plot_param_importances — често разкрива, че половината от параметрите, които tune-вам, реално не влияят на нищо:

import optuna.visualization as vis

# История на оптимизацията
vis.plot_optimization_history(study).show()

# Важност на параметрите
vis.plot_param_importances(study).show()

# Parallel coordinate plot
vis.plot_parallel_coordinate(study).show()

# Slice plot за всеки параметър
vis.plot_slice(study).show()

# Contour plot за двойки параметри
vis.plot_contour(study, params=["learning_rate", "max_depth"]).show()

За интерактивно проследяване на оптимизацията в реално време, използвайте Optuna Dashboard:

# Запазете study-то в SQLite
study = optuna.create_study(
    storage="sqlite:///optuna_study.db",
    study_name="my_experiment",
    load_if_exists=True,
)

# В отделен терминал:
# optuna-dashboard sqlite:///optuna_study.db

Persistence и разпределена оптимизация

За дълги оптимизации (часове или дни) винаги използвайте persistent storage. Това позволява:

  • Продължаване след прекъсване на процеса.
  • Паралелна оптимизация от множество машини.
  • Анализ на резултатите по-късно.
# Първа машина
study = optuna.create_study(
    storage="postgresql://user:pass@db-server/optuna",
    study_name="distributed_run",
    direction="maximize",
    load_if_exists=True,
)
study.optimize(objective, n_trials=100)

# Втора машина — същият study_name и storage
study = optuna.load_study(
    storage="postgresql://user:pass@db-server/optuna",
    study_name="distributed_run",
)
study.optimize(objective, n_trials=100)

Най-добри практики през 2026 г.

  1. Никога не tunirайте върху test set. Разделете данните на train / validation / test. Optuna използва само validation set.
  2. Използвайте cross-validation в objective функцията за по-стабилни резултати, особено при малки датасети.
  3. Винаги фиксирайте seed на sampler-а за репродуцируеми експерименти: TPESampler(seed=42).
  4. Активирайте pruning за iterative модели (XGBoost, LightGBM, neural networks) — спестява 50–80% от изчислителното време.
  5. Дефинирайте search space логаритмично за параметри като learning rate, regularization (log=True).
  6. Започнете с малък брой trials (20–30), анализирайте важността на параметрите и след това стеснете обхвата.
  7. Използвайте n_jobs внимателно — паралелизмът на ниво trial може да влоши TPE sampling-а; често е по-добре да паралелизирате вътре в самия модел.

Често срещани грешки

Грешка 1: Прекалено широк search space

Дефинирането на learning_rate между 0 и 1 без log scale води до загуба на trials в нерелевантни области. Винаги използвайте domain knowledge за разумни граници — няма нужда да изпробвате learning rate от 0.5, освен ако нямате много специфична причина.

Грешка 2: Игнориране на pruning при iterative модели

Без pruning, XGBoost trial с 1000 boost rounds може да отнеме минути дори когато първите 50 rounds ясно показват слаб резултат. Това е директно изгорено време и електричество.

Грешка 3: Объркване на directions при multi-objective

При multi-objective задайте directions (множествено число) — списък със стойности като ["maximize", "minimize"], а не единичното direction. Малка разлика в правописа, голяма разлика в поведението.

Сравнение: Optuna vs алтернативи

ИнструментAPIPruningMulti-objectiveDistributed
Optuna 4.xDefine-by-run
HyperoptDefine-and-runОграниченоSpark
Ray TuneDefine-and-run✅ (Ray)
Scikit-learn GridSearchDefine-and-runjoblib

Optuna остава най-добрият baseline за повечето Python ML проекти през 2026 г., особено когато се търси баланс между производителност, простота и гъвкавост.

Често задавани въпроси (FAQ)

Колко trials са нужни за добра оптимизация с Optuna?

Зависи от размера на search space-а. Като общо правило: 20–50 trials за прост модел с 3–5 параметъра, 100–300 trials за по-сложни модели с 8–15 параметъра, и 500+ за neural network архитектури. С активирано pruning може да се пуснат значително повече trials за същото време.

Каква е разликата между TPE и Bayesian optimization в Optuna?

TPE (Tree-structured Parzen Estimator) е форма на Bayesian optimization. Той моделира p(x|y) вместо p(y|x), което го прави особено ефективен при високомерни и категориални search space-ове. GPSampler е алтернативна Bayesian имплементация, която използва Gaussian Processes — по-добра за непрекъснати ниско-измерни задачи.

Мога ли да използвам Optuna с PyTorch или TensorFlow?

Да. Optuna има вградени integration callbacks за PyTorch Lightning, TensorFlow/Keras, FastAI и др. За PyTorch Lightning например използвайте optuna.integration.PyTorchLightningPruningCallback за автоматичен pruning по validation метриката.

Как се прекратява Optuna study преждевременно?

Има три основни начина: задаване на timeout в study.optimize(timeout=3600) (в секунди), задаване на конкретен брой trials с n_trials, или дефиниране на собствен callback, който извиква study.stop() при определено условие (например достигане на целева метрика).

Защо Optuna е по-добра от Scikit-learn's GridSearchCV?

GridSearchCV изпробва всяка комбинация в дефинирания мрежов формат (exhaustive search), което експоненциално нараства с броя параметри. Optuna използва Bayesian методи, за да насочи интелигентно търсенето към обещаващи области, плюс предлага pruning и multi-objective оптимизация — функционалност, която GridSearchCV изобщо няма.

Заключение

Optuna 4.x предлага най-зрелия и гъвкав инструмент за оптимизация на хиперпараметри в Python екосистемата за 2026 г. Комбинацията от define-by-run API, ефективен TPE sampler, pruning и multi-objective поддръжка я прави идеален избор както за начинаещи, така и за продукционни ML системи.

Започнете с базовия пример, добавете pruning при iterative модели и постепенно разширявайте към multi-objective и distributed optimization, когато проектът ви го изисква. Резултатът ще бъдат по-добри модели за по-малко време — а кой не би искал такава сделка?

За Автора Editorial Team

Our team of expert writers and editors.