• トップ
  • ブログ一覧
  • 【前編】YAMLを使ってPyTorchのOptimizerのパラメータ管理をすごく簡単にする方法
  • 【前編】YAMLを使ってPyTorchのOptimizerのパラメータ管理をすごく簡単にする方法

    広告メディア事業部広告メディア事業部
    2020.09.17

    IT技術

    前編~YAML で Optimizer のパラメータ管理が簡単に!~

    みなさんは、Optimizer をどのように設定していますか?

    よくあるのは、ArgumentParser などでコマンドラインから指定する方法だと思います。

    でも、Optimizer やパラメータ追加のたびに、いちいちコードを書き換えるのは面倒…

    そんな悩みを解決してくれるのが「YAML」です!

    Optimizer のパラメータ管理が簡単になるだけでなく、コード自体もより単純でスッキリしたものになりますよ。

    YAML とは

    「YAML(YAML Ain't a Markup Language)」は、構造化データをわかりやすく記述するために生まれたデータフォーマットです。

    設定ファイルやデータの保存・交換をする際によく用いられています。

    同じデータフォーマットである XML と似ていますが、XML よりは読みやすく書きやすい傾向にあります。

    また、Python と同じくインデントを使うのが特徴です。

    【YAML 公式ドキュメント】
    https://yaml.org/

    YAML がないと面倒なケース

    YAML の利便性を知ってもらうため、まずは「できないこともないけど、ちょっと面倒だな…」というケースを見ていきましょう!

    サンプルコード:main1.py

    まずは、Optimizer を作成するだけのプログラムを作成していきます。

    1# -*- coding: UTF-8 -*-
    2# ファイル名:main1.py
    3import argparse
    4import torch
    5import torch.optim as optim
    6import torch.nn as nn
    7
    8
    9def make_optimizer(params, name, lr):
    10    # Optimizer作成
    11    if name=='SGD':
    12        optimizer = optim.SGD(params, lr=lr)
    13    elif name=='Adam':
    14        optimizer = optim.Adam(params, lr=lr)
    15    else:
    16        raise Exception('{} はサポートされていません'.format(name))
    17    return optimizer
    18
    19
    20def get_args():
    21    # 引数の導入
    22    parser = argparse.ArgumentParser(description='YAML example')
    23    parser.add_argument('--optim', type=str, required=True, help='optimizer name')
    24    parser.add_argument('--lr', type=float, required=True, help='learning rate')
    25    args = parser.parse_args()
    26    return args
    27
    28
    29def main(args):
    30    # Model作成
    31    model = nn.Linear(1, 1)
    32    optimizer = make_optimizer(model.parameters(), args.optim, args.lr)
    33
    34    print(optimizer)
    35
    36
    37if __name__=='__main__':
    38    main(get_args())

    実行するときには、「Optimizerの名前」--optim と「学習率」--lr を引数として指定します。

    SGD 作成

    以下では、SGD を作成します。

    > はコマンドプロンプトのことです。

    1> python main1.py --optim SGD --lr 0.05 
    2
    3SGD (
    4Parameter Group 0
    5    dampening: 0
    6    lr: 0.5
    7    momentum: 0
    8    nesterov: False
    9    weight_decay: 0
    10)

    Adam 作成

    次に、Adam を作成します。

    1> python main.py --optim Adam --lr 0.05 
    2
    3Adam (
    4Parameter Group 0
    5    amsgrad: False
    6    betas: (0.9, 0.999)
    7    eps: 1e-08
    8    lr: 0.5
    9    weight_decay: 0
    10)

    拡張性がない!

    これ以上拡張しないのであれば、コーディングの量も少ないですし、特に問題はありません。

    ただし、機械学習の訓練中は様々な Optimizer やパラメータを試す必要があります。

    「拡張性」という点から考えると、上記のコードは後々面倒なことになりますね。

    サンプルコード:main2.py

    次に、SGD 特有の引数である「momentum」を追加でサポートしましょう。

    上記の main1.py をコピーして main2.py を作り、下記の変更を加えます。

    momentum を追加

    まず、新しい引数である momentum をつけたします。

    1def get_args():
    2    # 引数の導入
    3    parser = argparse.ArgumentParser(description='YAMLなしの例')
    4    parser.add_argument('--optim', type=str, required=True, help='optimizer name')
    5    parser.add_argument('--lr', type=float, required=True, help='learning rate')
    6    parser.add_argument('--momentum', type=float, default=0.0, help='SGDのmomentum') # momentum 追加
    7    args = parser.parse_args()
    8    return args

    make_optimizer に momentum 引数を追加

    make_optimizer に momentum の引数をつけたします。

    1def make_optimizer(params, name, lr, momentum): # momentum 追加
    2    # Optimizer作成
    3    if name=='SGD':
    4        optimizer = optim.SGD(params, lr=lr, momentum=momentum) # momentum 追加
    5    elif name=='Adam':
    6        optimizer = optim.Adam(params, lr=lr)
    7    else:
    8        raise Exception('{} はサポートされていません'.format(args.optim))
    9
    10    return optimizer

    args.momentum を追加

    make_optimizer を呼び出すときに、args.momentum を追加で渡します。

    1def main(args):
    2    # Model作成
    3    model = nn.Linear(1, 1)
    4    optimizer = make_optimizer(model.parameters(), args.optim, args.lr, args.momentum) # momentum 追加

    momentum の指定なし実行はデフォルト「0」が適用される

    momentum はオプションです。

    そのため、指定しないで実行すると、デフォルトの「0」が採用されます。

    1> python main2.py --optim SGD --lr 0.05
    2
    3SGD (
    4Parameter Group 0
    5    dampening: 0
    6    lr: 0.05
    7    momentum: 0.0
    8    nesterov: False
    9    weight_decay: 0
    10)

    指定して実行した場合

    momentum を指定して実行すれば、結果に値が反映されます。

    1> python main2.py --optim SGD --lr 0.05 --momentum 0.9
    2
    3SGD (
    4Parameter Group 0
    5    dampening: 0
    6    lr: 0.05
    7    momentum: 0.9
    8    nesterov: False
    9    weight_decay: 0
    10)

    Adam は指定にかかわらず変化なし

    ちなみに、Adam は momentum を使わないので、指定しても変化はありません。

    1> python main2.py --optim Adam --lr 0.05 --momentum 0.9
    2
    3Adam (
    4Parameter Group 0
    5    amsgrad: False
    6    betas: (0.9, 0.999)
    7    eps: 1e-08
    8    lr: 0.05
    9    weight_decay: 0
    10)

    コード修正に手間がかかりすぎる!

    この調子でもっと引数を追加したり、より多くの Optimizer をサポートしていく事は可能です。

    ただし、新しいパラメータを追加する毎に3箇所でコード修正を施さなければなりません。

    その上、コマンドラインからの指定だと、使うべきパラメータの判断がしにくい問題もあります。

    YAML で設定を簡単にしよう!

    上記のようなサンプルコードは、設定を YAML で記述し、ファイルから読み込むようにすれば、面倒がなくなります。

    コマンドラインをシンプルにする

    config1.yaml を作成

    新たに main3.py として書き直したプログラムを使います(後ほど解説します)。

    例として、config1.yaml を以下のように記述します。

    1optimizer:
    2    name: SGD
    3    lr: 0.05

    main3.py を実行

    この設定ファイルを使って、main3.py を実行します。

    1> python main3.py config1.yaml
    2
    3SGD (
    4Parameter Group 0
    5    dampening: 0
    6    lr: 0.05
    7    momentum: 0
    8    nesterov: False
    9    weight_decay: 0
    10)

    SGD が正しく作成されました。

    YAML なしの場合と比べて、コマンドラインがスッキリしましたね。

    パラメータを追加する

    次は、パラメータを追加してみましょう。

    config2.yaml を作成し、momentum を追加

    config1.yaml をコピーして config2.yaml を作り、momentum を追加します。

    1optimizer:
    2    name: SGD
    3    lr: 0.05
    4    momentum: 0.9

    main3.py を実行

    実行の仕方は、さっきと同じです。

    設定ファイルのパスを指定して実行しましょう!

    1> python main3.py config2.yaml
    2
    3SGD (
    4Parameter Group 0
    5    dampening: 0
    6    lr: 0.05
    7    momentum: 0.9
    8    nesterov: False
    9    weight_decay: 0
    10)

    コード変更は不要

    ちゃんと momentum の値が反映されていますね。

    YAML でパラメータ値を記述しただけで、コードの変更は必要ありません

    異なる Optimizer を設定する

    今度は、異なる Optimizer を設定しましょう。

    config3.yaml を作成し、Adam を設定

    config3.yaml を作って、Adam を設定します。

    1optimizer:
    2    name: Adam
    3    lr: 0.05

    main3.py を実行

    実行すると、こちらも期待通りの結果になります。

    1> python main3.py config3.yaml 
    2
    3Adam (
    4Parameter Group 0
    5    amsgrad: False
    6    betas: (0.9, 0.999)
    7    eps: 1e-08
    8    lr: 0.05
    9    weight_decay: 0
    10)

    コード変更は不要

    Optimizer の設定を変えましたが、やはりコードの変更は必要ありません

    YAML で記述した設定ファイルのみの変更です。

    YAML 設定ファイルを書き換え、別の Optimizer を作成する

    もう一つ、別の Optimizer を使ってみましょう。

    config4.yaml を作成し、Adagrad を設定

    config4.yaml を作って、Adagrad を設定します。

    パラメータの数も増やしましょう。

    1optimizer:
    2    name: Adagrad
    3    lr: 0.05
    4    lr_decay: 0.9
    5    weight_decay: 5.0e-5

    main3.py を実行

    これも、期待通りに動作します。

    1> python main3.py config4.yaml 
    2
    3Adagrad (
    4Parameter Group 0
    5    initial_accumulator_value: 0
    6    lr: 0.05
    7    lr_decay: 0.9
    8    weight_decay: 5e-05
    9)

    パラメータ管理が楽になる

    このように、YAML 形式で書いた設定ファイルの中身を変えるだけで、様々な Optimizer を作成する事ができます。

    この方法だと、訓練用の設定ファイルを複数準備して使い分けができるので、パラメータ管理が楽になります。

    後半へつづく!

    後半の記事はこちら!

    featureImg2020.09.19【後編】YAMLを使ってPyTorchのOptimizerのパラメータ管理をすごく簡単にする方法後編~YAML で Optimizer のパラメータ管理が簡単に!~ArgumentParser などで、Optimi...

    こちらの記事もオススメ!

    featureImg2020.07.28機械学習 特集知識編人工知能・機械学習でよく使われるワード徹底まとめ!機械学習の元祖「パーセプトロン」とは?【人工知能】ニューラルネ...
    featureImg2020.07.30Python 特集実装編※最新記事順Responder + Firestore でモダンかつサーバーレスなブログシステムを作ってみた!P...

    featureImg2020.07.17ライトコード的「やってみた!」シリーズ「やってみた!」を集めました!(株)ライトコードが今まで作ってきた「やってみた!」記事を集めてみました!※作成日が新し...

    広告メディア事業部

    広告メディア事業部

    おすすめ記事