使用optuna對模型的超參數(shù)進行自動優(yōu)化

使用前先安裝optuna.
pip install optuna
optuna適用于多種機器學習框架包括pytorch,tensorflow等。可以optuna examples github查看所有支持的框架的教程。

使用optuna優(yōu)化pytorch的模型

先有基本的pytorch經(jīng)驗,可以更快的理解下面的代碼。這里使用了gpu,如果沒有GPU,可以修改最開始的DEVICE=torch.device("cuda")DEVICE=torch.device("cpu")

import os
import optuna
from optuna.trial import TrialState
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
import torch.utils.data
from torchvision import datasets
from torchvision import transforms


"""
Optuna example that optimizes multi-layer perceptrons using PyTorch.

In this example, we optimize the validation accuracy of fashion product recognition using
PyTorch and FashionMNIST. We optimize the neural network architecture as well as the optimizer
configuration. As it is too time consuming to use the whole FashionMNIST dataset,
we here use a small subset of it.

"""


DEVICE = torch.device("cuda")
BATCHSIZE = 128 #每次訓練時數(shù)據(jù)被分為小批次的大小
CLASSES = 10 #
DIR = os.getcwd()
EPOCHS = 10 #所有的小批次完成后,即為1個epoch,此處是設置總的訓練的epoch次數(shù)
N_TRAIN_EXAMPLES = BATCHSIZE * 30 #訓練集的樣本數(shù)量
N_VALID_EXAMPLES = BATCHSIZE * 10 #測試集的樣本數(shù)量

#定義神經(jīng)網(wǎng)絡模型,在里面使用了2個自優(yōu)化超參數(shù)
def define_model(trial):
    # We optimize the number of layers, hidden units and dropout ratio in each layer.
    n_layers = trial.suggest_int("n_layers", 1, 3) #定義一個自由化超參數(shù):訓練的層數(shù),從1到3
    layers = []

    in_features = 28 * 28
    #循環(huán)構建卷積塊
    for i in range(n_layers):
        out_features = trial.suggest_int("n_units_l{}".format(i), 4, 128)#定義一個自優(yōu)化超參數(shù)out_features,是輸出feature的維度,從4到128
        layers.append(nn.Linear(in_features, out_features))#使用了上面定義的輸出特征維度超參數(shù)
        layers.append(nn.ReLU())#層添加上激活函數(shù)ReLU
        p = trial.suggest_float("dropout_l{}".format(i), 0.2, 0.5)#定義一個自優(yōu)化超參數(shù)p,是丟棄率,從0.2到0.5
        layers.append(nn.Dropout(p))#添加上上面的丟棄層
        in_features = out_features#再把最后的輸出層維度賦值給輸出層
    layers.append(nn.Linear(in_features, CLASSES))#最后添加上線性輸出層
    layers.append(nn.LogSoftmax(dim=1))#再轉(zhuǎn)為0-1分布函數(shù),此處是分類模型,所以需要這個函數(shù),轉(zhuǎn)成概率值
    return nn.Sequential(*layers)#返回的就是一個多層神經(jīng)網(wǎng)絡的所有層

#在線加載FashionMNIST數(shù)據(jù)集,pytorch的基本操作
def get_mnist():
    # Load FashionMNIST dataset.
    train_loader = torch.utils.data.DataLoader(
        datasets.FashionMNIST(DIR, train=True, download=True, transform=transforms.ToTensor()),
        batch_size=BATCHSIZE,
        shuffle=True,
    )
    valid_loader = torch.utils.data.DataLoader(
        datasets.FashionMNIST(DIR, train=False, transform=transforms.ToTensor()),
        batch_size=BATCHSIZE,
        shuffle=True,
    )
    return train_loader, valid_loader


def objective(trial):
    # Generate the model.
    model = define_model(trial).to(DEVICE)

    # Generate the optimizers.
    optimizer_name = trial.suggest_categorical("optimizer", ["Adam", "RMSprop", "SGD"])#定義自優(yōu)化的超參數(shù):模型優(yōu)化器
    lr = trial.suggest_float("lr", 1e-5, 1e-1, log=True) #定義自由化的超參數(shù),學習率,從1e-5到1
    optimizer = getattr(optim, optimizer_name)(model.parameters(), lr=lr)#創(chuàng)建優(yōu)化器對象

    # Get the FashionMNIST dataset.使用在線獲取FashionMNIST數(shù)據(jù)集,前者是訓練數(shù)據(jù)集,后者是測試數(shù)據(jù)集
    train_loader, valid_loader = get_mnist()

    # Training of the model.
    for epoch in range(EPOCHS):
        model.train()#訓練模型
        for batch_idx, (data, target) in enumerate(train_loader):
            # 當訓練的樣本總數(shù)超過我們最開始設置的訓練樣本數(shù)之后,就停止訓練
            if batch_idx * BATCHSIZE >= N_TRAIN_EXAMPLES:
                break

            #轉(zhuǎn)換為特定硬件設備的張量,view是用于改變張量的形狀,data.size(0)表示第1維度的大小,-1,表示自動計算其他維度的大小
            data, target = data.view(data.size(0), -1).to(DEVICE), target.to(DEVICE)

            optimizer.zero_grad()#清空優(yōu)化器的梯度
            output = model(data)#得到模型的輸出結(jié)果
            loss = F.nll_loss(output, target)#使用負對數(shù)似然損失(nll_loss)作為損失函數(shù)
            loss.backward()#反向傳播
            optimizer.step()#根據(jù)計算得到的梯度,通過優(yōu)化器更新模型的參數(shù)

        # 測試集,評估模型
        model.eval()
        correct = 0
        with torch.no_grad():
            for batch_idx, (data, target) in enumerate(valid_loader):
                # 如果測試數(shù)據(jù)量大于最開始設置的測試數(shù)據(jù)量就停止測試
                if batch_idx * BATCHSIZE >= N_VALID_EXAMPLES:
                    break
                data, target = data.view(data.size(0), -1).to(DEVICE), target.to(DEVICE)
                output = model(data)
                # 獲取最大值的索引,后面的keepdim是在原來的張量相同的維度上保存。
                pred = output.argmax(dim=1, keepdim=True)
                #累加計算結(jié)果正確的所有的次數(shù),
                correct += pred.eq(target.view_as(pred)).sum().item()
        #這里是計算準確率,
        accuracy = correct / min(len(valid_loader.dataset), N_VALID_EXAMPLES)

        trial.report(accuracy, epoch)#將當前的準確率和迭代次數(shù)傳遞給optuna

        #optuna評估是否需要剪枝,如果需要剪枝(說明模型的參數(shù)性能不佳),則拋出TrialPruned異常。
        if trial.should_prune():
            raise optuna.exceptions.TrialPruned()
    return accuracy

#判斷當前腳本是否是作為主程序運行,只有作為主程序時,才會執(zhí)行下面的代碼,作為模塊被引入時,不會執(zhí)行下面的代碼
if __name__ == "__main__":
    #創(chuàng)建一個optuna研究對象,名字是maxmize
    study = optuna.create_study(direction="maximize")
    #對目標函數(shù)進行優(yōu)化,objective是要優(yōu)化的目標函數(shù),n_trials=100表示最多進行100次實驗,timeout=600表示優(yōu)化過程的超時時間為600秒。
    study.optimize(objective, n_trials=100, timeout=600)
    #獲取所有被提前停止的實驗
    pruned_trials = study.get_trials(deepcopy=False, states=[TrialState.PRUNED])
    #獲取所有成功的實驗,deepcopy=False表示返回的是原始對象的引用,而不是復制,這可以節(jié)省內(nèi)存
    complete_trials = study.get_trials(deepcopy=False, states=[TrialState.COMPLETE])

    print("Study statistics: ")
    print("  Number of finished trials: ", len(study.trials))
    print("  Number of pruned trials: ", len(pruned_trials))
    print("  Number of complete trials: ", len(complete_trials))

    print("Best trial:")
    #獲取結(jié)果最佳的實驗
    trial = study.best_trial
    #輸出最佳實驗時的超參數(shù)設定
    print("  Value: ", trial.value)
    print("  Params: ")
    for key, value in trial.params.items():
        print("    {}: {}".format(key, value))

程序最終輸出內(nèi)容如下:

Study statistics: 
  Number of finished trials:  100
  Number of pruned trials:  61
  Number of complete trials:  39
Best trial:
  Value:  0.85078125
  Params: 
    n_layers: 1
    n_units_l0: 81
    dropout_l0: 0.22233836180755426
    optimizer: Adam
    lr: 0.0037253244556814374

即最優(yōu)的超參數(shù)組合的模型的準確率是0.85078125,最優(yōu)超參數(shù)設置是:

  • 層數(shù)是1,
  • 輸出維度是81,
  • 損失函數(shù)是0.22233836180755426,
  • 模型優(yōu)化器是Adam,
  • 學習率是 0.0037253244556814374
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,316評論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,481評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,241評論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,939評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,697評論 6 409
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,182評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,247評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,406評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,933評論 1 334
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 40,772評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,973評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,516評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,209評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,638評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,866評論 1 285
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,644評論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,953評論 2 373

推薦閱讀更多精彩內(nèi)容