【前編】YAMLを使ってPyTorchのOptimizerのパラメータ管理をすごく簡単にする方法
2021.12.20
前編~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 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 | # -*- coding: UTF-8 -*- # ファイル名:main1.py import argparse import torch import torch.optim as optim import torch.nn as nn def make_optimizer(params, name, lr): # Optimizer作成 if name=='SGD': optimizer = optim.SGD(params, lr=lr) elif name=='Adam': optimizer = optim.Adam(params, lr=lr) else: raise Exception('{} はサポートされていません'.format(name)) return optimizer def get_args(): # 引数の導入 parser = argparse.ArgumentParser(description='YAML example') parser.add_argument('--optim', type=str, required=True, help='optimizer name') parser.add_argument('--lr', type=float, required=True, help='learning rate') args = parser.parse_args() return args def main(args): # Model作成 model = nn.Linear(1, 1) optimizer = make_optimizer(model.parameters(), args.optim, args.lr) print(optimizer) if __name__=='__main__': main(get_args()) |
実行するときには、「Optimizerの名前」 --optim と「学習率」 --lr を引数として指定します。
SGD 作成
以下では、SGD を作成します。
> はコマンドプロンプトのことです。
1 2 3 4 5 6 7 8 9 10 | > python main1.py --optim SGD --lr 0.05 SGD ( Parameter Group 0 dampening: 0 lr: 0.5 momentum: 0 nesterov: False weight_decay: 0 ) |
Adam 作成
次に、Adam を作成します。
1 2 3 4 5 6 7 8 9 10 | > python main.py --optim Adam --lr 0.05 Adam ( Parameter Group 0 amsgrad: False betas: (0.9, 0.999) eps: 1e-08 lr: 0.5 weight_decay: 0 ) |
拡張性がない!
これ以上拡張しないのであれば、コーディングの量も少ないですし、特に問題はありません。
ただし、機械学習の訓練中は様々な Optimizer やパラメータを試す必要があります。
「拡張性」という点から考えると、上記のコードは後々面倒なことになりますね。
サンプルコード:main2.py
次に、SGD 特有の引数である「momentum」を追加でサポートしましょう。
上記の main1.py をコピーして main2.py を作り、下記の変更を加えます。
momentum を追加
まず、新しい引数である momentum をつけたします。
1 2 3 4 5 6 7 8 | def get_args(): # 引数の導入 parser = argparse.ArgumentParser(description='YAMLなしの例') parser.add_argument('--optim', type=str, required=True, help='optimizer name') parser.add_argument('--lr', type=float, required=True, help='learning rate') parser.add_argument('--momentum', type=float, default=0.0, help='SGDのmomentum') # momentum 追加 args = parser.parse_args() return args |
make_optimizer に momentum 引数を追加
make_optimizer に momentum の引数をつけたします。
1 2 3 4 5 6 7 8 9 10 | def make_optimizer(params, name, lr, momentum): # momentum 追加 # Optimizer作成 if name=='SGD': optimizer = optim.SGD(params, lr=lr, momentum=momentum) # momentum 追加 elif name=='Adam': optimizer = optim.Adam(params, lr=lr) else: raise Exception('{} はサポートされていません'.format(args.optim)) return optimizer |
args.momentum を追加
make_optimizer を呼び出すときに、args.momentum を追加で渡します。
1 2 3 4 | def main(args): # Model作成 model = nn.Linear(1, 1) optimizer = make_optimizer(model.parameters(), args.optim, args.lr, args.momentum) # momentum 追加 |
momentum の指定なし実行はデフォルト「0」が適用される
momentum はオプションです。
そのため、指定しないで実行すると、デフォルトの「0」が採用されます。
1 2 3 4 5 6 7 8 9 10 | > python main2.py --optim SGD --lr 0.05 SGD ( Parameter Group 0 dampening: 0 lr: 0.05 momentum: 0.0 nesterov: False weight_decay: 0 ) |
指定して実行した場合
momentum を指定して実行すれば、結果に値が反映されます。
1 2 3 4 5 6 7 8 9 10 | > python main2.py --optim SGD --lr 0.05 --momentum 0.9 SGD ( Parameter Group 0 dampening: 0 lr: 0.05 momentum: 0.9 nesterov: False weight_decay: 0 ) |
Adam は指定にかかわらず変化なし
ちなみに、Adam は momentum を使わないので、指定しても変化はありません。
1 2 3 4 5 6 7 8 9 10 | > python main2.py --optim Adam --lr 0.05 --momentum 0.9 Adam ( Parameter Group 0 amsgrad: False betas: (0.9, 0.999) eps: 1e-08 lr: 0.05 weight_decay: 0 ) |
コード修正に手間がかかりすぎる!
この調子でもっと引数を追加したり、より多くの Optimizer をサポートしていく事は可能です。
ただし、新しいパラメータを追加する毎に3箇所でコード修正を施さなければなりません。
その上、コマンドラインからの指定だと、使うべきパラメータの判断がしにくい問題もあります。
YAML で設定を簡単にしよう!
上記のようなサンプルコードは、設定を YAML で記述し、ファイルから読み込むようにすれば、面倒がなくなります。
コマンドラインをシンプルにする
config1.yaml を作成
新たに main3.py として書き直したプログラムを使います(後ほど解説します)。
例として、config1.yaml を以下のように記述します。
1 2 3 | optimizer: name: SGD lr: 0.05 |
main3.py を実行
この設定ファイルを使って、main3.py を実行します。
1 2 3 4 5 6 7 8 9 10 | > python main3.py config1.yaml SGD ( Parameter Group 0 dampening: 0 lr: 0.05 momentum: 0 nesterov: False weight_decay: 0 ) |
SGD が正しく作成されました。
YAML なしの場合と比べて、コマンドラインがスッキリしましたね。
パラメータを追加する
次は、パラメータを追加してみましょう。
config2.yaml を作成し、momentum を追加
config1.yaml をコピーして config2.yaml を作り、momentum を追加します。
1 2 3 4 | optimizer: name: SGD lr: 0.05 momentum: 0.9 |
main3.py を実行
実行の仕方は、さっきと同じです。
設定ファイルのパスを指定して実行しましょう!
1 2 3 4 5 6 7 8 9 10 | > python main3.py config2.yaml SGD ( Parameter Group 0 dampening: 0 lr: 0.05 momentum: 0.9 nesterov: False weight_decay: 0 ) |
コード変更は不要
ちゃんと momentum の値が反映されていますね。
YAML でパラメータ値を記述しただけで、コードの変更は必要ありません。
異なる Optimizer を設定する
今度は、異なる Optimizer を設定しましょう。
config3.yaml を作成し、Adam を設定
config3.yaml を作って、Adam を設定します。
1 2 3 | optimizer: name: Adam lr: 0.05 |
main3.py を実行
実行すると、こちらも期待通りの結果になります。
1 2 3 4 5 6 7 8 9 10 | > python main3.py config3.yaml Adam ( Parameter Group 0 amsgrad: False betas: (0.9, 0.999) eps: 1e-08 lr: 0.05 weight_decay: 0 ) |
コード変更は不要
Optimizer の設定を変えましたが、やはりコードの変更は必要ありません。
YAML で記述した設定ファイルのみの変更です。
YAML 設定ファイルを書き換え、別の Optimizer を作成する
もう一つ、別の Optimizer を使ってみましょう。
config4.yaml を作成し、Adagrad を設定
config4.yaml を作って、Adagrad を設定します。
パラメータの数も増やしましょう。
1 2 3 4 5 | optimizer: name: Adagrad lr: 0.05 lr_decay: 0.9 weight_decay: 5.0e-5 |
main3.py を実行
これも、期待通りに動作します。
1 2 3 4 5 6 7 8 9 | > python main3.py config4.yaml Adagrad ( Parameter Group 0 initial_accumulator_value: 0 lr: 0.05 lr_decay: 0.9 weight_decay: 5e-05 ) |
パラメータ管理が楽になる
このように、YAML 形式で書いた設定ファイルの中身を変えるだけで、様々な Optimizer を作成する事ができます。
この方法だと、訓練用の設定ファイルを複数準備して使い分けができるので、パラメータ管理が楽になります。
後半へつづく!
後半の記事はこちら!
こちらの記事もオススメ!
書いた人はこんな人
- 「好きを仕事にするエンジニア集団」の(株)ライトコードです!
ライトコードは、福岡、東京、大阪の3拠点で事業展開するIT企業です。
現在は、国内を代表する大手IT企業を取引先にもち、ITシステムの受託事業が中心。
いずれも直取引で、月間PV数1億を超えるWebサービスのシステム開発・運営、インフラの構築・運用に携わっています。
システム開発依頼・お見積もり大歓迎!
また、現在「WEBエンジニア」「モバイルエンジニア」「営業」「WEBデザイナー」「WEBディレクター」を積極採用中です!
インターンや新卒採用も行っております。
以下よりご応募をお待ちしております!
https://rightcode.co.jp/recruit
- ライトコードの日常2月 29, 2024座談会はじめました!ライトコードの話ちょっと聞いてみませんか?
- ライトコードの日常12月 27, 2023年忘れ!ライトコード大忘年会2023
- ライトコードの日常12月 1, 2023ライトコードクエスト〜東京オフィス歴史編〜
- ITエンタメ10月 13, 2023Netflixの成功はレコメンドエンジン?