【後編】YAMLを使ってPyTorchのOptimizerのパラメータ管理をすごく簡単にする方法
IT技術
後編~YAML で Optimizer のパラメータ管理が簡単に!~
ArgumentParser などで、Optimizer やパラメータ追加のたびに、いちいちコードを書き換えるのは面倒…
そんな悩みを解決してくれるのが「YAML」です。
Optimizer のパラメータ管理が簡単になるだけでなく、コード自体もより単純でスッキリしたものになります。
前回に引き続き、「YAMLを使ってPyTorchのOptimizerのパラメータ管理をすごく簡単にする方法」をご紹介します!
前編をお読みでない方は、こちらをまずお読みください。
YAML でシンプルなコーディングを実現
さて、これを実現するコード「main3.py」は、冒頭のサンプルコード「main1.py」や「main2.py」よりも複雑で巨大なものなのでしょうか?
いいえ、そんな事はありません。
実は、コードそのものがよりシンプルになります。
YAML を使うための下準備
Python | バージョンは3.6以上 |
PyTorch | バージョンは1.0以上 |
環境については、上記を想定しています。
YAML を使えるようにインストールします。
1> pip install pyyaml
準備はこれだけです。
サンプルコード:main3.py
main3.py の中身は、下記のとおりです。
1# -*- coding: UTF-8 -*-
2# ファイル名:main3.py
3import argparse
4import torch
5import torch.optim as optim
6import torch.nn as nn
7import yaml
8
9
10def make_optimizer(params, name, **kwargs):
11 # Optimizer作成
12 return optim.__dict__[name](params, **kwargs)
13
14
15def get_args():
16 # 引数の導入
17 parser = argparse.ArgumentParser(description='YAMLありの例')
18 parser.add_argument('config_path', type=str, help='設定ファイル(.yaml)')
19 args = parser.parse_args()
20 return args
21
22
23def main(args):
24 # 設定ファイル(.yaml)の読み込み
25 with open(args.config_path, 'r') as f:
26 config = yaml.safe_load(f)
27
28 # Model作成
29 model = nn.Linear(1, 1)
30 optimizer = make_optimizer(model.parameters(), **config['optimizer'])
31
32 print(optimizer)
33
34
35if __name__=='__main__':
36 main(get_args())
ご覧のとおり、main1.py や main2.py に比べて、よりシンプルなコードに変更されています。
では、変更箇所を一つ一つ見ていきましょう。
引数を導入する
まずは、「引数の導入」のコードです。
1def get_args():
2 # 引数の導入
3 parser = argparse.ArgumentParser(description='YAMLありの例')
4 parser.add_argument('config_path', type=str, help='設定ファイル(.yaml)')
5 args = parser.parse_args()
6 return args
ここでは、設定ファイル「.yaml」を指定するconfig_path のみを引数として扱っています。
Optimizer を作成する
次は、make_optimizer で、Optimizer を作成するコードです。
1def make_optimizer(params, name, **kwargs):
2 # Optimizer作成
3 return optim.__dict__[name](params, **kwargs)
名前空間 optim
ここの optim は、下記のところでインポートされた名前空間です。
1import torch.optim as optim
optim._dict_ に Optimizer の名前を渡すと、そのクラスを取得できます。
Optimizer のオブジェクトを作成する際に渡した**kwargs に、YAML で設定されたパラメータの値が入ってきます。
設定ファイルを読み込み、make_optimizer に渡す
次は、main のコードを見てみましょう。
1def main(args):
2 # 設定ファイル(.yaml)の読み込み
3 with open(args.config_path, 'r') as f:
4 config = yaml.safe_load(f)
5
6 # Model作成
7 model = nn.Linear(1, 1)
8 optimizer = make_optimizer(model.parameters(), **config['optimizer'])
9
10 print(optimizer)
ここでは、設定ファイルを読み込み、返り値のconfig から取り出した'optimizer' セクションをmake_optimizer に渡します。
この部分は、設定ファイルの YAML がプログラムでどのように処理されていくのか、順番に見ていくとよりわかりやすいでしょう。
パラメータを追加
まずは、パラメータを追加する config2.yaml の内容を思い出して下さい。
1optimizer:
2 name: SGD
3 lr: 0.05
4 momentum: 0.9
YAML 設定ファイルを読み込む
下記のコードで、YAML の設定ファイルが読み込まれ、config に格納されます。
1with open(args.config_path, 'r') as f:
2 config = yaml.safe_load(f)
このconfig はdict オブジェクトです。
Python だとどうなる?
Python では、このようになります。
1{'optimizer': {'name': 'SGD', 'lr': 0.05, 'momentum': 0.9}}
config['optimizer'] のところは、'optimizer' をキーとして値を取り出しています。
1{'name': 'SGD', 'lr': 0.05, 'momentum': 0.9}
記述は違っても呼び方は同じ
よって、以下の2つのコードは、まったく同じ呼び方ということになります。
1optimizer = make_optimizer(model.parameters(), **config['optimizer'])
1optimizer = make_optimizer(model.parameters(), name='SGD', lr=0.05, momentum=0.9)
引数の名前が指定されているなら、順番は気にしなくていい
ここで、name lr momentum それぞれの順番は重要ではありません。
Python では引数の名前が指定されている場合、その順番は関数の宣言通りでなくても良いからです。
よって、YAML の設定ファイルが以下のように記述されていても、同様に動作します。
1optimizer:
2 momentum: 0.9
3 name: SGD
4 lr: 0.05
name は最初に記述しよう
ただし、どの Optimizer 設定にも必須なname は、一番最初に記述しておいた方が違和感が少ないです。
YAML の設定変更だけで、どんなOptimizer もサポート可能
make_optimizer ではname で Optimizer のクラスを取り出し、**kwargs にある残り全てのパラメータをそのまま渡します。
1def make_optimizer(params, name, **kwargs):
2 # Optimizer作成
3 return optim.__dict__[name](params, **kwargs)
上記のコードが、下記のように実行されているイメージになります。
1def make_optimizer(params, name='SGD', lr=0.05, momentum=0.9):
2 # Optimizer作成
3 optimizer_class = optim.__dict__[name] # optim.SGD class
4 return optimizer_class(params, lr=lr, momentum=momentum)
以上をまとめると、「YAML で指定したname で Optimizer のクラスを取り出し、残り全てのパラメータを、そのクラスのオブジェクトを作るときに渡している」となります。
このやり方だと、どの Optimizer のどのパラメータでも、YAML の設定を変えるだけでサポートできるようになります。
YAMLを使う際の注意点
ここからは、YAML の設定時に注意したいポイントをまとめてみました。
name で指定する Optimizer の名前は PyTorch で定義されているもののみ
例えば、SGD のところがsgd と書かれていたらエラーになります。
設定できる Optimizer の名前は、下記のリンクで確認できます。
【Github ソースコード】
https://github.com/pytorch/pytorch/blob/master/torch/optim/__init__.py
独自定義のクラスを使いたい場合
また、独自に定義した Optimizer のクラスを取り入れたい場合もあるでしょう。
その時は、「make_optimizer で、独自の名前空間をはじめにチェックする」などの工夫が必要になります。
Optimizer のパラメータ名は定義されたものを使う
lr をlearning_rate など、違う名前で設定したら PyTorch から怒られます。
これは、ソースコードと設定ファイルでパラメータ名が統一されるので、利点でもあります。
Optimizer ごとの設定の詳細は、下記のリンクを参照してください。
【pytorch 公式ドキュメント】
https://pytorch.org/docs/stable/optim.html
「true」と「false」を使う
Python ではTrue とFalse なのですが、YAML では全て小文字です。
慣れないうちは間違えやすいので、気をつけましょう。
小数点を忘れずに
「1.0e-4」なら OK ですが、「1e-4」と記述すると、Python のstr 型として認識されてしまいます。
「1.0」のように、必ず小数点をつけましょう。
ちなみに、「1.e-4」でも大丈夫ですが、「1.0e-4」の方が読みやすいと思います。
list 型は[]を使う
YAML では[0.9, 0.09]はlist 型として認識されますが、(0.9, 0.09)はstr 型になってしまいます。
Adam の betas パラメータはtuple 型ですが、list 型で渡しても問題ありません。
よって、YAML では[] で記述しましょう。
さいごに
いかがでしょうか?
YAML を使えば、「Optimizer のパラメータ管理」や「簡潔かつ分かりやすいコーディング」が簡単にできます。
また、YAML でパラメータ設定をする方法は、Scheduler や DataLoader にも適用できます。
とても便利なので、ぜひ応用してみてくださいね。
こちらの記事もオススメ!
2020.07.28機械学習 特集知識編人工知能・機械学習でよく使われるワード徹底まとめ!機械学習の元祖「パーセプトロン」とは?【人工知能】ニューラルネ...
2020.07.17ライトコード的「やってみた!」シリーズ「やってみた!」を集めました!(株)ライトコードが今まで作ってきた「やってみた!」記事を集めてみました!※作成日が新し...
ライトコードでは、エンジニアを積極採用中!
ライトコードでは、エンジニアを積極採用しています!社長と一杯しながらお話しする機会もご用意しております。そのほかカジュアル面談等もございますので、くわしくは採用情報をご確認ください。
採用情報へ
「好きを仕事にするエンジニア集団」の(株)ライトコードです! ライトコードは、福岡、東京、大阪の3拠点で事業展開するIT企業です。 現在は、国内を代表する大手IT企業を取引先にもち、ITシステムの受託事業が中心。 いずれも直取引で、月間PV数1億を超えるWebサービスのシステム開発・運営、インフラの構築・運用に携わっています。 システム開発依頼・お見積もり大歓迎! また、現在「WEBエンジニア」「モバイルエンジニア」「営業」「WEBデザイナー」「WEBディレクター」を積極採用中です! インターンや新卒採用も行っております。 以下よりご応募をお待ちしております! https://rightcode.co.jp/recruit