超参数优化框架Optuna

深度学习调参是一门玄学,有时候想改进自己的模型,比如把LSTM替换为Transformer,好不容易模型框架照着论文搭好了,超参数也和论文一致,照理说acc、auc等各种评价指标应该远远超过LSTM,理想是丰满的,现实却是惨不忍睹的,在自己的数据集上跑时,有时效果反而还不如原本已经fine tune过的简单模型性能好,我要这模型有何用?别急,下面我来教你如何解放双手,让它来帮你找到最优参数。

本文介绍超参数优化框架Optuna,并用示例代码简要展示其在pytorch上的使用。

首先简单介绍下Optuna,Optuna是一种自动超参优化框架,专为机器学习而设计。它具有命令式,按运行定义的用户API。使用Optuna编写的代码具有很高的模块性,Optuna的用户可以动态构建超参数的搜索空间。

它目前支持的部分库有(全部请参见官网):

  • XGBoost
  • LightGBM
  • Sklearn
  • Keras
  • TensorFlow
  • tf.keras
  • MXNet
  • PyTorch
  • FastAI

它的安装就一步:pip install optuna

下面我通过代码示例,简要展示其如何使用,数据的加载、训练等函数都将略去,只需要添加两个函数define_modelobjective就能将Optuna框架零感地插入到我们现有的代码中去。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
import optuna
from torch import optim, nn

'''
# 这个定义的model只是个示例,实际并没什么用
class model(nn.Module):

def __init__(self, input_size, output_size, hidden_size=200, dropout=p):
super(model, self).__init__()
self.embedding = nn.Embedding(num_embeddings=input_size,
embedding_dim=hidden_size)
self.linear = nn.Linear(in_features=hidden_size, out_features=output_size)
self.dropout = nn.Dropout(dropout)
def forward(self, x):
x = self.dropout(self.embedding(x))
outputs = self.linear(x)
return outputs
'''

def define_model(trial):
# 在100到200之间搜索hidden_size
hidden_size = trial.suggest_int('hidden_size', 100, 200)
# 在0.2到0.5之间搜索dropout rate
p = trial.suggest_uniform('dropout', 0.2, 0.5)
# 假设vocab_size, output_size都已经定义了
m = model(input_size=vocab_size, output_size=output_size,
hidden_size=hiddensize, dropout=p)
return m

def objective(trial):
# 尝试不同的optimizer
optimizer_name = trial.suggest_categorical('optimizer',
['Adam', 'RMSprop', 'SGD'])
# 搜索学习率
lr = trial.suggest_uniform('lr', 1e-5, 1e-1)
m = define_model(trial)
optimizer = getattr(optim, optimizer_name)(m.parameters(), lr=lr)
# 这里省略了run函数,内部应该将数据喂给model训练,训练完成后在验证集上测试,计算并返回acc
acc = run(m, optimizer=optimizer)
return acc

if __name__ == '__main__':
# 创建一个学习实例,因为objective返回的评价指标是acc,因此目标是最大化,如果是loss就该是minimize
study = optuna.create_study(direction='maximize')
# n_trials代表搜索100种,n_jobs是并行搜索的个数,-1代表使用所有的cpu核心
study.optimize(objective, n_trials=100, n_jobs=-1)
print('Number of finished trials: ', len(study.trials))
print('Best trial:')
trial = study.best_trial
print(' Value: ', trial.value)
print(' Params: ')
for key, value in trial.params.items():
print(' {}: {}'.format(key, value))

这里只是简单地展示了一下如何在pytorch中使用optuna,以此来解放调参师的双手,更详细的使用请参见官方网站。

答应我,别再用手调参了。(前提是你得有好的GPU来搜,逃。。。

祝大家都能超参最优!