Optuna๋ ํ์ด์ฌ ๊ธฐ๋ฐ์ ํ์ดํผํ๋ผ๋ฏธํฐ ์ต์ ํ (hyperparameter optimization) ํ๋ ์์ํฌ๋ก, ์ฌํํ๊ณ ์ ์ฐํ API๋ฅผ ์ ๊ณตํ๋ค. ๋ณธ ๊ธ์์๋ Optuna์ ์ฃผ์ ๊ธฐ๋ฅ๊ณผ ์ฌ์ฉ๋ฐฉ๋ฒ์ ๊ฐ๋จํ ์๊ฐํ๊ณ ์ ํ๋ค.
๊ณต์ Docs: https://optuna.readthedocs.io/en/stable/index.html
Optuna: A hyperparameter optimization framework — Optuna 3.4.0 documentation
© Copyright 2018, Optuna Contributors. Revision 4ea580fc.
optuna.readthedocs.io
Basic concepts
Optuna๋ study์ trial์ ๋ค์๊ณผ ๊ฐ์ด ์ ์ํ๋ค.
- Study: objective ํจ์์ ๊ธฐ๋ฐํ์ฌ optimization์ ์ํํ๋ ํ๋์ ํ๋ก์ ํธ
- Trial: Study ๋ด์ optimization ๋จ์ผ ์ํ
Hyperparameter optimization์ ์ํํ๊ธฐ ์ํด objective์ study๋ฅผ ์ ์ํ๊ณ , n_trials ํ๋ผ๋ฏธํฐ๋ฅผ ์กฐ์ ํ์ฌ ๋ช ํ์ trial์ ์ํํ ์ง ์ค์ ํ ์ ์๋ค.
๋ค์๊ณผ ๊ฐ์ด study๋ฅผ ์ ์ํ ์ ์๋ค. objective๋ ๋งค trial์ input์ผ๋ก ๋ฐ๋ ํจ์์ด๋ค.
import optuna
def objective(trial):
...
model.fit(train_x, train_y)
error = get_error(model, valid_x, valid_y)
return error
study = optuna.create_study()
study.optimize(objective, n_trials=100)
Search space์ Sampling algorithms
์ฌ์ฉ์๊ฐ ํ์ํ hyperparameter์ search space๋ฅผ ์ ์ํด์ฃผ๋ฉด, optuna๋ ๊ทธ ์์์ hyperparmeter์ samplingํ์ฌ ์ต์ ํ๋ฅผ ์งํํ๋ค.
Search space๋ objective ์์์ ์ค์ ํ ์ ์๋ค. ๋ค์์ ๋ค์ํ search space๋ฅผ ์ ์ํ๋ ๋ฐฉ๋ฒ์ ์์์ด๋ค.
import optuna
def objective(trial):
# Categorical parameter
optimizer = trial.suggest_categorical("optimizer", ["MomentumSGD", "Adam"])
# Integer parameter
n_layers = trial.suggest_int("n_layers", 1, 3)
# Loops
layers = []
for i in range(n_layers):
n_units = trial.suggest_int("n_units_l{}".format(i), 4, 128, log=True)
layers.append(nn.Linear(in_size, n_units))
layers.append(nn.ReLU())
in_size = n_units
layers.append(nn.Linear(in_size, 10))
# Integer parameter (discretized)
num_units = trial.suggest_int("num_units", 10, 100, step=5)
# Floating point parameter
dropout_rate = trial.suggest_float("dropout_rate", 0.0, 1.0)
# Floating point parameter (log)
learning_rate = trial.suggest_float("learning_rate", 1e-5, 1e-2, log=True)
# Floating point parameter (discretized)
drop_path_rate = trial.suggest_float("drop_path_rate", 0.0, 1.0, step=0.1)
Categorial, int, float ๋ฑ ๋ค์ํ ํํ์ hyperparameter์ ์ง์ ํด์ค ์ ์๋ค. ๋ ๋ง์ suggest_* ํจ์๋ ์ฌ๊ธฐ์์ ํ์ธํ ์ ์๋ค.
search space์์ hyperparameter์ samplingํ๋ ์๊ณ ๋ฆฌ์ฆ ์ญ์ ์ฌ์ฉ์๊ฐ ์ ์ํ ์ ์๋๋ฐ, create_study๋ฅผ ํ ๋ sampler ์ธ์์ ๋๊ฒจ์ฃผ๋ฉด ๋๋ค.
study = optuna.create_study(sampler=optuna.samplers.RandomSampler())
print(f"Sampler is {study.sampler.__class__.__name__}") #print
Optuna์์ ์ฌ์ฉ๊ฐ๋ฅํ sampler์ ์ข ๋ฅ๋ ๋ค์๊ณผ ๊ฐ๋ค.
- GridSampler
- RandomSampler
- TPESampler (default)
- CmaEsSampler
- PartialFixedSampler
- NSGAIISampler
- QMCSampler
๊ฐ sampler์ ๋ํ ์์ธํ ์ค๋ช ์ ์ฌ๊ธฐ์์ ์ฌ์ฉํ ์ ์๋ค.
์ด๋ค sampler์ ์ฌ์ฉํ๋ฉด ์ข์์ง์ ๋ํ ํํธ๋ ์ฐพ์๋ณผ ์ ์๋ค.
Pruning algorithms
Pruning์ ํ์ต ์ด๊ธฐ ๋จ๊ณ์์ ๊ฐ๋ฅ์ฑ์ด ๋ฎ์๋ณด์ด๋ trial์ ์๋์ผ๋ก ์ค๋จํ๋ ๊ธฐ๋ฅ์ด๋ค. "automated early-stopping"์ด๋ผ๊ณ ๋ณผ ์ ์๋ค.
Pruner์ ์ข ๋ฅ๋ ๋ค์๊ณผ ๊ฐ๋ค.
- MedianPruner
- NopPruner
- PatientPruner
- PercentilePruner
- SuccessiveHalvingPruner
- HyperbandPruner
- ThresholdPruner
์ ์ฒด pruner์ ์ข ๋ฅ์ ์์ธํ ์ค๋ช ์ ์ฌ๊ธฐ์์ ํ์ธํ ์ ์๋ค.
Pruner์ ์ฌ์ฉ๋ฒ์ ๋ค์๊ณผ ๊ฐ๋ค.
- training์ each step ์งํ์ report() ์ should_prune() ํจ์๋ฅผ ํธ์ถํ๋ค.
- report(): ์ค๊ฐ objective value๋ฅผ ์ฃผ๊ธฐ์ ์ผ๋ก ๋ชจ๋ํฐ๋งํ๋ค.
- should_prune(): ์ฌ์ ์ ์ ์๋ ์กฐ๊ฑด์ ์ถฉ์กฑํ์ง ์๋ trial์ ์กฐ๊ธฐ ์ข ๋ฃ๋ฅผ ๊ฒฐ์ ํ๋ค.
def objective(trial):
...
for step in range(100):
model.fit(train_x, train_y, classes=classes)
# Report intermediate objective value.
intermediate_error = get_error(valid_x, valid_y)
trial.report(intermediate_error, step)
# Handle pruning based on the intermediate value.
if trial.should_prune():
raise optuna.TrialPruned()
return get_error(valid_x, valid_y)
# Add stream handler of stdout to show the messages
optuna.logging.get_logger("optuna").addHandler(logging.StreamHandler(sys.stdout))
study = optuna.create_study(pruner=optuna.pruners.MedianPruner())
study.optimize(objective, n_trials=20)
#out
A new study created in memory with name: no-name-e9380357-f153-4409-b874-c302ee358494
Trial 0 finished with value: 0.2894736842105263 and parameters: {'alpha': 0.07567537350404895}. Best is trial 0 with value: 0.2894736842105263.
Trial 1 finished with value: 0.02631578947368418 and parameters: {'alpha': 1.0132167782206652e-05}. Best is trial 1 with value: 0.02631578947368418.
Trial 2 finished with value: 0.02631578947368418 and parameters: {'alpha': 0.011064776558365616}. Best is trial 1 with value: 0.02631578947368418.
Trial 3 finished with value: 0.3157894736842105 and parameters: {'alpha': 3.096403335234504e-05}. Best is trial 1 with value: 0.02631578947368418.
Trial 4 finished with value: 0.07894736842105265 and parameters: {'alpha': 0.027787238399605656}. Best is trial 1 with value: 0.02631578947368418.
Trial 5 pruned.
Trial 6 pruned.
Trial 7 pruned.
Trial 8 pruned.
Trial 9 pruned.
Trial 10 pruned.
Trial 11 pruned.
Trial 12 pruned.
Trial 13 finished with value: 0.02631578947368418 and parameters: {'alpha': 0.0005226670470560228}. Best is trial 1 with value: 0.02631578947368418.
Trial 14 pruned.
Trial 15 pruned.
Trial 16 pruned.
Trial 17 pruned.
Trial 18 pruned.
Trial 19 pruned.
Docs์์๋ ๋ค์์ sampler-pruner ์กฐํฉ์ ์ถ์ฒํ๊ณ ์๋ค.
- RandomSampler ์ฌ์ฉ ์ MedianPruner ์ฌ์ฉ
- TPESampler ์ฌ์ฉ ์ HyperbandPruner ์ฌ์ฉ
Visualization
optuna์ ์ต์ ํ ๊ฒฐ๊ณผ์ ๋ํ ์๊ฐํ๋ฅผ ๋์์ฃผ๋ optuna-dashboard๋ผ๋ ํด์ด ์๋ค.
GitHub - optuna/optuna-dashboard: Real-time Web Dashboard for Optuna.
Real-time Web Dashboard for Optuna. Contribute to optuna/optuna-dashboard development by creating an account on GitHub.
github.com
์ฌ์ฉ๋ฒ์ ๋ค์๊ณผ ๊ฐ๋ค.
import optuna
if __name__ == "__main__":
study_name = "quadratic-simple"
study = optuna.create_study(
storage=f"sqlite:///{study_name}.db", # Specify the storage URL here.
study_name=study_name
)
study.optimize(objective, n_trials=100)
print(f"Best value: {study.best_value} (params: {study.best_params})")
pip install optuna-dashboard
optuna-dashboard sqlite:///quadratic-simple.db
logging
ํ์ผ์ trial์ ๊ธฐ๋ก์ ๋จ๊ธฐ๋ ค๋ฉด ๋ค์๊ณผ ๊ฐ์ด logging ์ต์ ์ ์ค์ ํ์ฌ ํ ์ ์๋ค.
optuna.logging.enable_propagation — Optuna 3.4.0 documentation
© Copyright 2018, Optuna Contributors. Revision 4ea580fc.
optuna.readthedocs.io
import optuna
import logging
logger = logging.getLogger()
logger.setLevel(logging.INFO) # Setup the root logger.
logger.addHandler(logging.FileHandler("foo.log", mode="w"))
optuna.logging.enable_propagation() # Propagate logs to the root logger.
optuna.logging.disable_default_handler() # Stop showing logs in sys.stderr.
study = optuna.create_study()
logger.info("Start optimization.")
study.optimize(objective, n_trials=10)
with open("foo.log") as f:
assert f.readline().startswith("A new study created")
assert f.readline() == "Start optimization.\n"
Examples
Optuna๋ ๋ค์ํ ๋ฅ๋ฌ๋ ํ๋ ์์ํฌ๋ค๊ณผ ์ ์ฐํ๊ฒ ๊ฒฐํฉํ์ฌ ์ฌ์ฉํ ์ ์๋๋ฐ, ์์ ๋ค์ ๋ค์ ๋งํฌ์์ ํ์ธํ ์ ์๋ค.
FAQ
๊ณต์ docs์ FAQ ์ค ์ ์ฉํ ๋ช๊ฐ์ง๋ฅผ ์๊ฐํ๋ค.
FAQ — Optuna 3.4.0 documentation
When you want to suggest \(n\) variables which represent the proportion, that is, \(p[0], p[1], ..., p[n-1]\) which satisfy \(0 \le p[k] \le 1\) for any \(k\) and \(p[0] + p[1] + ... + p[n-1] = 1\), try the below. For example, these variables can be used a
optuna.readthedocs.io
How to define objective functions that have own arguments?
How to avoid OOM when optimizing studies?
'๐ Python & library > Etc.' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[Tensorboard] ์ฐจํธ ์๊น ๋ณ๊ฒฝํ๊ธฐ (0) | 2022.10.12 |
---|---|
[matplotlib] matplotlib.pyplot์ ์ด์ฉํ ์ด๋ฏธ์ง ์๊ฐํ ์ด์ ๋ฆฌ (0) | 2022.08.29 |
[h5py] hdf5 ์๊ฐ, h5py ์ฌ์ฉ๋ฒ ๊ฐ๋จ ์ ๋ฆฌ (0) | 2021.12.14 |