流行りの機械学習でなにか動かしたいなぁとチュートリアルを動かそうとするも大抵エラーで動かない、動いたとしてもちょっと経つとライブラリの更新だか環境の変化でエラーになってしまい、その依存関係も解決できない。 ローカルで動かそうとするが環境構築でつまずく。
そんな感じで挫折を繰り返してるので、ちゃんと環境構築できるようにやってみた。
環境構築編
強化学習や機械学習のチュートリアルといえばPython、なのでその環境をある程度固定して、安心して動かせる環境を用意できるようにしたい。
Python:pyenv
Python自体のインストール、バージョン更新・変更はpyenvでできる。 詳細なインストール・使用方法は略。
pyenv local <バージョン番号>
を実行すると.python-version
というファイルに保存され、そのフォルダ以下にいるとpython
としたときに自動的にそのバージョンが使われる- その状態で
pip install
してもローカルフォルダ以下ではなく、pyenvのバージョン/lib以下にインストールされる (なので他のフォルダで同じPythonバージョンを使うとバッティングする可能性があると思う)
Python仮想環境:venv
Pythonで仮想環境を作る方法が何種類かあるみたいで歴史的経緯・使用感などは自分では把握してないのだけど、venvを使うことにした。
- 初期設定:
python -m venv .venv
とすると.venv
というフォルダが生成される - 仮想環境を有効化:
source .venv/bin/activate
- 有効化すると、
pip install
したものが.venv/lib
以下にインストールされる
- 有効化すると、
仮想環境を有効化した状態でPythonスクリプトを実行することで、想定している環境上で動作させることができる。
- 仮想環境を無効化:
deactivate
モジュールのリスト化:pip freeze
venvでローカルに作成された依存ライブラリ自体はリポジトリにコミットしないので、別のマシンで動かそうとした時に困る。 そこでインストールしたモジュールを書き出し、再利用できるようにする:
- インストールしたモジュールの書き出し:
pip freeze > requirements.txt
- 自分でインストールしたモジュール以外にも、依存するモジュールも書き出される
- 復元:
pip install -r requirements.txt
以上で環境を固定できるようになったので、安心してスクリプトを動作させることができる(たぶん…)。
強化学習を動かしてみる
機械学習(教師あり学習)はデータを用意する必要があって、なかなか好き勝手なことをするには難しい。 なので強化学習が動かせると楽しめそう。
OpenAI Gymはdeprecated
強化学習の手始めといえばOpenAI Gymという感じでさすがに動かせるものかと思ってたんだが、少し古いコードだとenv.step
の戻り値が違うというエラーが出てしまう。
バージョン0.26.0で変更されてしまったらしい。
で対応して動かそうとしてたんだけどGym自体がすでにdepreatedになってたらしく、 Gymnasiumに引き継がれたとのこと。
pip install gymnasium
import gymnasium as gym
とすれば、一応互換で使えるらしい
倒立振子を動かしてみる
Gymnasiumで強化学習の環境は用意できるけど、強化学習のコード自体はまた別に用意する必要がある。 自分で組むだけの知識も理解も足りないのでなにかサンプルを参考にしたい、と思ったらドキュメントにいろいろ紹介されていた。 その中で倒立振子:
- Training using REINFORCE for Mujoco - Gymnasium Documentation
- 環境の説明はInverted Pendulum - Gymnasium Documentation
- 行動空間:カートにどのくらいの力を与えるかの連続値
- 観測空間:カートの位置、ポールの角度、カートの速度、ポールの角速度
Mujocoという物理エンジンを使った倒立振子の環境を「REINFORCE」という方法(紛らわしい)で学習するサンプルとなっている。 ソースコードが添付されているのでダウンロードして必要なモジュールをインストールすることで動かすことができる。
- 方策ネットワーク:状態を入力、行動を正規分布の平均と標準偏差を出力とするニューラルネットワーク。共有部分として活性化関数がtanhの全結合層を2段(次元は16と32)、平均と標準偏差にそれぞれ全結合層、という構成。
- 最適化はAdamW
sample_action
関数内の正規分布作成時に平均値にもeps
を足しているのは間違いじゃないか?
学習結果の動作を再生させる
上で公開されているコードは学習を5回行ってエピソード数に従った報酬の推移のグラフが表示されるだけで、実際にどのような動作になるのか自分にとってはイメージしづらい。 なので実際に再生・表示させたい:
- 動作をリアルタイムに描画:
gym.make("InvertedPendulum-v4")
にキーワード引数render_mode='human'
を追加- 表示内容やキー操作をいじりたかったがやり方わからず…
- 学習結果の保存:
torch.save(agent.net.state_dict(), 'ファイル名.pt')
- 学習結果の読込:
agent.net.load_state_dict(torch.load('ファイル名.pt'))
- 行動の選択:学習時に使われる
agent.sample_action
では正規分布からサンプルするため乱数要素が含まれてしまうので、 ベストな行動(平均の値そのもの)を取り出すには、action_means[0].detach().numpy()
とする
二重倒立振子を動かしてみる
読み込む環境を二重倒立振子に変えて遊んでみた。
- 観測できる状態は11個
- 得られる報酬には距離ペナルティと速度ペナルティが入っている。1タイムステップごとに、
- 生存ボーナス:10
- 距離ペナルティ: (x,yは第2ポール先端の座標)
- 速度ペナルティ:
- 最大タイムステップは最大1,000なので、最大の累積報酬は1万になる
ネットワーク構成をいじってみる
逆振子が二重になっている分元の構成より複雑になっているだろうはずなので、方策のネットワーク構造をあれこれいじってみる:
- 活性化関数をtanhからReLUなど他のものに変えてみたが性能は劣化した
- 隠れ層の段数を増やすと良くなる(3段:32-16-32にしてみた)
- 3万〜5万エピソードくらい学習をさせると、倒立できるようになることもある(かなりムラがある)
雑多メモ
- JupyterLabなどを使った場合にも裏ではノートごとに仮想環境を作ってくれているんじゃないかと推測するんだけど真偽は不明
- venv設定したフォルダをVSCodeで開くと自動的に
activate
してくれる pip freeze
で生成されるリストが冗長なのをなんとかしたい:Pigarを使うと良さげ- “Simple Statistical Gradient-Following Algorithms for Connectionist Reinforcement Learning“, Ronald J. Williams, 1992
- REINFORCE(REward Increment = Non-negative Factor × Offset Reinforcement × Characteristic Eligibility) の論文
- 方策勾配法:価値関数を扱わず、観測の状態に対する行動の確率分布(方策:ポリシー)を直接学習する、らしい(読んではいない)