日記とか、工作記録とか

自分に書けることを何でも書いてゆきます。作った物、買ったもの、コンピュータ系の話題が多くなるかもしれません。

Docker + StableDiffusion(CPU) + streamlitでお手軽画像生成

streamlitというPythonのライブラリがあり、簡単にWebフロントエンドを作成することができるそうです。すでにGitHubで作られている方がいたので、それとCPU版StableDiffusionを組み合わせて使えるようにしてみました。

サバンナから昇る朝日

github.com

Dockerが必要なので、Windows 10の場合はPro版が必要です。ビルドについては前回のブログと大体同じになります。gitのレポジトリは私のアカウント領域に変わっていますのでご注意ください。

windvoice.hatenablog.jp

Webサービスとして使うにあたり、ポート8501を公開しています。ここにアクセスできるよう、docker runを実行するとき、8501/tcpをローカルPCの8501にマッピングします。

docker run -it --rm -p 8501:8501 stable_diffusion:openvino bash

bashのターミナルが開いたら、streamlitを起動します。

(openvino_env) stable_diffusion@3e775d837d9a:~/stable_diffusion.openvino$ streamlit run demo_web.py

  You can now view your Streamlit app in your browser.

  Network URL: http://172.17.0.2:8501
  External URL: http://219.113.238.136:8501

ここでURLが表示されてここへアクセス!となっていますが、実際にはこれらのポートはローカルのPCのポートにマッピングされていますので、ブラウザで(PCのIPアドレス):8501へアクセスすることで使えます。

Windows 10 Pro + DockerでStableDiffusion

いま、流行のStableDiffusion、メモリ多めのGPUが必要なため、Colabなどで動かす例が多いです。しかし、日々いろいろな方の貢献が進んでいまして、CPUで動かせるバージョンがGitHubに公開されています。お手軽そうなので、飛びつくように試してみました。

注:この絵はMidjourneyさんに描いてもらったもの(にぎやかしのため)

ご参考のため、私のPCスペック

DIMM64GBありますし、こちらのほうがいいかも、ということで試してみることにしました。

結果

環境構築

  • Windows 10がPro版であることが必要です。「プログラムの追加と削除」→「アプリと機能」の画面で、「プログラムと機能」を選択、さらに「Windowsの機能の有効化または無効化」を選択して、「仮想マシンプラットフォーム」を有効にしておきます(要再起動)。


  • Docker Hubにアクセスして、IDを登録します。登録したら、Windows版Docker Hubをダウンロードしてインストールします。

hub.docker.com

  • Docker Desktopを起動するとチュートリアルを勧められるので、一通り流して終わります。
  • wsl2をインストールします(したような気がする)
  • powershellを開いて、gitコマンドで以下のレポジトリをcloneします。終わったら、docker buildで環境を構築します。

github.com

# git clone https://github.com/atinfinity/stable_diffusion.openvino-docker
# cd stable_diffusion.openvino-docker
# docker build --build-arg UID=1000 --build-arg GID=1000 -t stable_diffusion:openvino .
  • 環境ができあがるまでしばらく待ちます。Dockerすごい!裏で必要なことは全部やってくれるのでコーヒーでも飲んで待ちます。
  • Docker DesktopのImagesメニューから、stable_diffusionを選んでrunで環境を起動します。

  • recursing_neumannから、ターミナルを起動します(OPEN IN TERMINAL)。

  • ターミナルが開くので、bashを起動します。このbash環境は、StableDiffusionを動かす準備が整っています。
$ bash
To run a command as administrator (user "root"), use "sudo <command>".
See "man sudo_root" for details.

(openvino_env) stable_diffusion@9c929807267a:~/stable_diffusion.openvino$

さぁ!

ここまで来たら、準備OKです。ここまでいろいろ作ってくれた方に感謝しつつ呪文を唱えましょう。

(openvino_env) stable_diffusion@9c929807267a:~/stable_diffusion.openvino$ python stable_diffusion.py --prompt "A plate full of fried chicken, photoreal, 8K"
Downloading: 100%|█████████████████████████████████████████████████████████████████████| 905/905 [00:00<00:00, 1.75MB/s]
Downloading: 100%|████████████████████████████████████████████████████████████████████| 939k/939k [00:00<00:00, 979kB/s]
Downloading: 100%|████████████████████████████████████████████████████████████████████| 512k/512k [00:00<00:00, 640kB/s]
Downloading: 100%|██████████████████████████████████████████████████████████████████████| 389/389 [00:00<00:00, 824kB/s]
Downloading: 100%|█████████████████████████████████████████████████████████████████| 2.12M/2.12M [00:01<00:00, 1.66MB/s]
ftfy or spacy is not installed using BERT BasicTokenizer instead of ftfy.
Downloading: 100%|████████████████████████████████████████████████████████████████████| 464k/464k [00:00<00:00, 564kB/s]
Downloading: 100%|███████████████████████████████████████████████████████████████████| 492M/492M [00:16<00:00, 30.5MB/s]
Downloading: 100%|█████████████████████████████████████████████████████████████████| 3.02M/3.02M [00:01<00:00, 2.04MB/s]
Downloading: 100%|█████████████████████████████████████████████████████████████████| 3.44G/3.44G [02:39<00:00, 21.6MB/s]
Downloading: 100%|████████████████████████████████████████████████████████████████████| 329k/329k [00:00<00:00, 508kB/s]
Downloading: 100%|███████████████████████████████████████████████████████████████████| 198M/198M [00:04<00:00, 45.7MB/s]
32it [01:47,  3.35s/it]
(openvino_env) stable_diffusion@9c929807267a:~/stable_diffusion.openvino$

最初の1回は実行に時間がかかります。プロンプトが戻ってきたら、output.pngがそこにあるのが確認できます。

(openvino_env) stable_diffusion@9c929807267a:~/stable_diffusion.openvino$ ls -l
total 524
-rw-r--r-- 1 stable_diffusion stable_diffusion  11357 Aug 30 11:33 LICENSE
-rw-r--r-- 1 stable_diffusion stable_diffusion  14384 Aug 30 11:33 LICENSE_MODEL
-rw-r--r-- 1 stable_diffusion stable_diffusion   1876 Aug 30 11:33 README.md
drwxr-xr-x 2 stable_diffusion stable_diffusion   4096 Aug 30 11:33 data
-rw-r--r-- 1 stable_diffusion stable_diffusion 486600 Aug 31 11:54 output.png
-rw-r--r-- 1 stable_diffusion stable_diffusion    144 Aug 30 11:33 requirements.txt
-rw-r--r-- 1 stable_diffusion stable_diffusion   7080 Aug 30 11:33 stable_diffusion.py
(openvino_env) stable_diffusion@9c929807267a:~/stable_diffusion.openvino$

できました!

(追記 2022/09/01)

一日経ったら、もう内容が古くなっていました。いまはstable_diffusion.pyの代わりにdemo.pyとすると動きます。詳細は同じディレクトリにあるREADME.mdを読みましょう。

で、そのoutput.pngはどこにあるの?

実は、このPNGファイルを探すのが一番大変でした。結論から言うと、以下の通り探せます。


  • docker-desktop-dataを開き、ファイルの検索から「output.png」を探します。
  • output.pngが見つかったら右クリックして「ファイルの場所を開く」で開きます。やっとみつかりました。


まとめ

ということで、ローカルなPC環境でStableDiffusionを動かす例を少しだけ詳しめにご紹介しました。流行に乗って波乗りしたい方、ぜひどうぞ。

Midjourneyでお絵描きして考えたこと

Midjourneyに描いてもらった絵を描く女性

いま、世の中でAIが描くイラストが話題です。

OpenAI: DALL-E2
openai.com

独立系: Midjourney
www.midjourney.com

Google: Imagen
imagen.research.google

Stable Diffusion
stability.ai

私はこのうちDALL-E2とMidjourneyを使ってみました。Midjourneyは$10/月のサービスも購入しました。絵の活用も自由とされたことで、実際に活用を試みる人が増えると思います。すでにたくさんのブログや動画で「呪文」の組み合わせかたを解説しているものがあり、私も読ませてもらっています。

私は先行者がたくさんいるそういった話題はさけて、今現在の水準でどんな実用が考えられるか、書いてみようと思います。

挿絵として使う場合

端的に言って、挿絵として使うのはありかなと思っています。既存のやりかたとして、フリー素材がよくつかわれているので、これらとの違いが気になります。

フリー素材のイラストや写真を提供するサービスは、すでにたくさんあります。技術系の記事を大量生産するWebサイトは、たいていこの手の写真を記事の冒頭に置いています。ただ、記事の内容と写真の内容は特に関係がないのが普通です(オフィスっぽい風景とか、モニターの画面とか、授業風景とか……)。検索エンジンから、ページに写真や解説図が含まれることが評価されるためだと思います。私もPinterestにアカウントを作りましたが、意図がないなら画像は不要かなとか、フリー素材の写真を使うとソレ系のブログだと認識されるな(実際、しますよね?)、などと思って結局使わずにいます。

AIに描いてもらう挿絵は、まだ記事を書いた人の意図が反映されるので『何かを伝えたいけど文字ばかりの記事は寂しい、当たり障りのない挿絵が欲しい』用途で使えると思います。図解イラストと違って凝視されるものでもないので、細部が「?」なイラストでも気になりません。費用も、$10/月なら使ってもいいかな、とならないでしょうか。

一方、説明の補助として絵を使う場合は、AI系イラストをうまく当てはめるのはいまのところ難しそうに思います(場合によってはできるかもしれないけれど、思い通りにならなくて記事を書く以上に時間がかかりそう)。いらすとやさんのような「どうしてこんなものまであるの?」というような品揃えのイラストサイトの役割は、まだ当分なくなりそうにありません。

SNSのアイコンとして使う場合

私のSNSのアイコンは、フリー写真素材サイトから借りてきたものです。もとは非常に高解像度の写真なのですが、SNSのアイコンは普通小さく表示されるだけなので、オーバースペックです。イラストをSNSアイコンにしている人もいますが、他人の絵を借りるのは著作権的に心配です。写真を使うにも、私は犬も猫も飼っていないし…… ということで、こういった形になっています。

SNSのアイコンは、小さいためAIの生成した画像でも使える可能性が十分あります。細部が気にならないこういった用途はいいですね。


背景画像として使う場合

自作のゲームの背景画像に使っている人を見かけました(リンクを残すのを忘れていて探せなくなってしまいました)。背景はあまり見つめられないので、こうした用途もありだと思います。ただ、何枚も使う場合は画像の雰囲気をそろえたりする必要があり少しだけコツが必要ですね。作風を指定したりすることで、実用の範囲内と思います。

AI絵画自体をクリエイティブな用途で使う場合

AI画像を多数生成して漫画にしてみた、などの試みも複数見つかりますね。ホットな話題になっている今は注目されますけど、実際に漫画として読めるかというと、いまのところ相当無理があるので、「やってみた」レベルにとどまるかなと思います。構図やポーズを細かく指定できるようになると、一気に現実的になるかもしれません。


私は、SNSとかブログで当たり障りのないイラストでページをにぎやかす用途でしばらく使ってみようと思います。多少でも、個性が出せるといいのですが、どうなりますか……

【8-1クリア】OpenAI Gym + Colab NotebookでAIマリオを強化学習

Midjourneyに描いてもらったコンセプトアート

AIマリオチャレンジ、私は長いトライアルを終えることにしましたので、チャレンジにかかわる皆さんへの感謝の気持ちも込めて、区切りとしてブログのエントリを残しておきます。

以前は挑戦中だったAIマリオのチャレンジですが、最難関だったステージ8-1をクリアしました。平凡な表現になりますが、この一言が書けるのはとてもうれしいです。

AIマリオにチャレンジし始めたのが2021年12月30日、8-1にチャレンジを始めたのが2月27日(これらは手元のEvernoteに記録されています)でした。着手時点でからあげさんのプロジェクトでは、8-1と8-4を残すのみの状態でした。私がクリアしたのが7月24日ですから、約5か月の期間、あれもダメ、これもダメ、次はどうしよう、と思いながら試行錯誤を続けていました。今考えれば、良くあきらめずにやり続けたなと感心します。

着手当初は、ほかの協力者の皆さんが苦労されている理由が知りたかった、というのがきっかけでした。そのうち誰かがクリアしてしまうだろうから、いまのうちに着手しないとやらないまま終わりそう、とも思いました。まさか自分でクリアするとは、思っていなかったのです。

最初は、1-1をクリアしたときのNotebookから始めました。Double Q Network(DQN)を実装したもので、ほかの方のサンプルをもとに、ログや統計がとれるようにカスタマイズしていました。もともと、私は長いこと某UNIX系OSの障害解析を専門にしていました。動かない理由を何日もかけて調べて原因を突き止める(注:直すとはいってない)のが役割です。思うように動かないのは、ある意味慣れていました。

最初のうち、Newral Network(MarioNet)を何倍も大きくしたり、学習率を調整して長く学習させてみたり、そういうことでゴールに迫れると想定していたのですが、状況は想定以上に厳しく、パラメータの調整では8-1の半分くらいまでしか到達できません。そもそも、8-1は難所が多いだけではなく、1-1よりもずっと長さもあります。やりながら、子供のころよくタイムアップで死んだよなぁ、なんて思っていました。

マリオの動きを観察していて、DQNではそもそも難しいように感じてきました。というのも、DQNには確率εというパラメータがあり、この確率でランダムな操作をします。これは「新しい発見」をするために必要なことではあるのですが、実際のところεが低めの0.1に設定されていたとしても、stepが1000回あれば、100回は適当な操作をするわけです。これでは、マリオは挙動不審になりすぎてしまいます。ステージ上の新しい場所に到達する前に、ほとんどのマリオがイージーミスでやられてしまい、学習が進まないわけです。手堅く操作するところと、いろいろ試す場面とを切り替える必要性を感じました。

そこで、ひとりのマリオ(1エピソード)中にX座標の値を確認しながらεの値を動的に調整する、ということをしばらく試みました。が、εをゼロにすると、今度はステージ上の同じところで同じミスを繰り返すようになりやられてしまいます。微妙な調整をいくつも試みたのですが、このアプローチはうまくいきませんでした。

マリオを走らせている間、私も勉強して新しい技術の導入を試みました。

画面の認識を強化するために畳み込み層を改良してRESnetのような構造を取り入れました。これはある程度、最長不倒地点を延ばす効果がありました。

さらに、上で説明したε-greedy法をやめて、Noisy Networkを導入することもしてみました。こちらは、聞いているほどうまくいきませんでした。私の推定ですが、マリオの操作が離散的な選択肢から選ぶ形式であるかぎり、Noisy Networkはε-greedyとあまり変わらないのかもしれません。

ひととおり自分で実装できそうなことはやってみて、自分の手に負えそうな論文もいくつか読んでみても、目の前のマリオに応用するのはなかなか簡単ではありません。著名な論文でも(スーパーマリオより単純そうな)ATARI2600での適用結果を載せていたりしますから、自分の取り組みはそれよりずっと複雑で無謀な挑戦のように思えてきました。

ネタ切れは近づいていましたが、とはいえ正直やめるきっかけもない、という感じで、初心にもどってほかの方のNotebookを読んで、DQNからPPO(Proximal Policy Optimization)に乗り換えることにしました。これが7月18日です。ここから先は、あっという間でした。DQNのときに作成していたRESNetほかいくつかの作りこみを移植して、パフォーマンスを確認するための仕組みも移植して、観察をしながら微妙なパラメータを調整して…… とやっているうちに、もうあと一歩というところまできました。

この時点ではまだまったくクリアを信じていません。機械学習アルゴリズムの改良がこれほどクリティカルに影響することに驚き、「巨人の肩に乗る」のは大事だと思いなおしました。先行している人たちの苦労をやっと実感できるところまできた、さぁここからが大変だ、という印象です。

……などといっているうちに、急に見えたこのGOALの文字。

待てあわてるな、これは孔明の罠だ、という例のセリフが思い浮かびますが、罠ではなく本当にクリアしていました。学習を途中で止めて、再現動画を撮るために200エピソードほど走らせると、最初の動画が録画できました。

月並みな言い方ですが、この半年でかなりいろいろ勉強させてもらいました。コンピュータに機械学習をさせると、プログラマーが一番学習します。これは真理です。結局学習結果がでるのに半日や一日が必要ですので、それまで勉強して次のネタを作って…… という作業とのルーチンが組みやすいんですね。ポモドーロタイマーみたいなものです。

プロジェクトは8-4を残していますが、私はほかのテーマを探そうと考えています。私はクリエイターというよりはデータ分析官のような性格なので、Kaggleに行こうかなと思っています。ともかく、このプロジェクトでは多くのことを学びました。ありがとうございました。

追記

からあげさんのGitHubにクリア報告を載せました。こちらにクリアしたときのColab Notebookとモデルをリンクしておきます。
github.com

OpenAI Gym + Colab NotebookでAIマリオを強化学習

AIにはいろいろな分野がありますが、いまは強化学習で遊んでいます(ずいぶん前にも記事にしました)。
からあげさんが主催されている、mario-ai-challengeで興味を持って触り始めました。これ、最初に書いたの今年の初めなんですね。もう半年が経ってしまいました。

karaage0703.github.io

OpenAI Gymという強化学習用のライブラリがあるのですが、これと、gym-super-mario-brosを使用して、エミュレータ上でスーパーマリオブラザーズが動きます。この環境をAIにプレイさせることで徐々にプレイが上達していく様子を観察しながらクリアを目指そう、というものです。

現在、このプロジェクトではすでにほとんどのステージがクリアされており、残りは2ステージ(8-1と、8-4)を残すのみとなっています。
私は8-1にずいぶん前からチャレンジしているのですが、ちっともクリアできそうな気配がありません……

こちらは、私が学習させたマリオで1-1をクリアする様子です。
www.youtube.com

このとき使用しているColab Notebookを公開してありますので、興味のある方はぜひ遊んでみてください。
そんな中から8-1をクリアする猛者が現れることを期待しています!
colab.research.google.com

学習には保存用のGoogle Driveと、Google Colab(たぶん無料利用の範囲で大丈夫)が必要です。
学習の所要時間は5時間ほどです。

Notebookをそのままポチポチしていくだけでも、1-1はクリアできます。
ほかの難しいステージにもぜひ挑戦してみてください。

トンガの火山噴火の衝撃波を自宅でも観測しました(M5Stick+BME280)

日本時間の2022年1月15日13時ころ、トンガのフンガトンガ・フンガハアパイという場所で大きな海底火山噴火がありました。日本でも津波のようなもの(気象庁によれば従来の津波とは違うものらしいですが)が観測されました。火山の噴火は爆発的なものなので、その衝撃波があります。7800km離れた日本でも、衝撃波が観測されました。ウェザーニュースのツイートを見てびっくりしました。

それで、そういえば自宅にもセンサーがあるな、ということを思い出しました。確認してみたところ衝撃波が記録されていましたので、記録を残しておこうと思います。7800kmを渡ってきた衝撃です。

f:id:WindVoice:20220116142354p:plain

センサーはM5stickとBME280でできており、30秒おきにデータをAmbientにPOSTしています。
維持していたというより正直放置してあっただけなのですが、たまたま取れていたので記録を可視化してみました。

f:id:WindVoice:20220116143333p:plain

Ambientからダウンロードしたデータを散布図としてプロットしたのがこちら。20:09ころから急に気圧があがり(といっても2hPaに満たないくらいですが)、下降し、落ち着いたのが22:00過ぎといったところ。途中気圧が乱れているところもわかります。

f:id:WindVoice:20220116143431p:plain

ちょっと計算

今回の衝撃波は7800kmを約7時間で伝わったことになり、速度は1,114km/時です。地球1周は40,075kmだそうなので、地球を反対周りに伝わってくる衝撃波は32,275kmを旅してくることになります。速度が変わらないならば(ホントは気温や気圧で変わるでしょうが)、29時間で届くことになります。つまり、本日の18時くらいですね。それが観測できるかどうか、確認しようと思います。

追記

地球を大回りしてくる衝撃波らしいもの、見えませんでした。

f:id:WindVoice:20220116202813p:plain

OpenAI Gymを使ったAIスーパーマリオの強化学習

からあげさん( Twitter: @karaage0703 )が呼びかけていた、強化学習を使ってAIにスーパーマリオをクリアさせようという企画をみかけて、とてもおもしろそうなので挑戦しました。ただ単に実行するだけ、というわけにはいかず自分なりの工夫が必要だったので、試行錯誤の記録を残します。

AIマリオは、OpenAI gymを基盤として公開されているもので、GitHubにレポジトリがあります。
github.com

f:id:WindVoice:20220102175206p:plain

からあげさんのJupyter Notebookでのお試し

最初は、からあげさんがこちらのURLで記事にされていたのを見かけたのがきっかけでした。書かれている通り、AIがスーパーマリオをプレイするというのは私にはとても魅力的に見えます。子供の頃、8-4まで必死になってプレイしました。私にとっては珍しく最後までプレイしたアクションゲームでした。

GitHubにJupyter Notebookを用意していただいているので、まずはこれをコピーしてはじめました。確かに実行はできるのですが、どこに工夫の余地があるのかとっかかりがわからず(PPOとは?)、変更した場合にうまくいっているのかどうかの判断基準もわからないため、しばらく考え込んでしまいました。

別の方が用意している、DDQN版でチャレンジ

からあげさんのNotebookと大本が同じ、別のかたの取り組みがあることがわかったので、そちらを読んでみました。使っている学習アルゴリズムはDDQN(Double Deep Q-Network)とありました。過去にUinityでQ学習を使う簡単なものを実装してみたことがあり、こちらのほうが何をやっているのか分かりそうでした。環境、行動、報酬、学習という枠があり改造するにも少し考えるとっかかりがあります。ということでこちらを基点に触っていくことにしました。

まずは実行

まずは手習いということで実行してみるとたしかに動くのですが、学習を最小限(マリオ105人分=105エピソード)しかすることができず、学習成果があるのか、よくわかりません。かといって単純にループを増やすと、マリオ320人分あたりでCUDA(GPUを使った機械学習用のライブラリ)がメモリ不足でエラーとなり、学習を続けることができませんでした。

RuntimeError: CUDA out of memory. Tried to allocate 20.00 MiB (GPU 0; 15.90 GiB total capacity; 14.51 GiB already allocated; 39.75 MiB free; 14.85 GiB reserved in total by PyTorch) If reserved memory is >> allocated memory try setting max_split_size_mb to avoid fragmentation.  See documentation for Memory Management and PYTORCH_CUDA_ALLOC_CONF

安定したループを回すために①

強化学習では、All You Need Is Killみたいなもので、とにかく長時間トライ&エラーを繰り返し続けるマリオを作る必要があります。メモリ不足の原因を探るために、まずはGPUの状態を調べます。Colab環境にはnvidia-smiというコマンドがあり、これで状況を表示できます。CLIなので、実行時は ! をつけておく必要があります。

!nvidia-smi

f:id:WindVoice:20220102175321p:plain

この場合、GPUはTesla P100であることがわかりますし、GPUメモリは約16GBあることがわかります。マリオ300人分ほどがトライ&エラーしたあと同じコマンドを実行すると、メモリの使用量が14GBくらいになっていました。どうやらここがメモリ不足に陥っています。メモリを消費しそうな原因を探してゆくと、全てのマリオが共有している記憶があり(Mario.memory)、これはキューであり一定以上には増えないようになっているのですが、それでもGPUのメモリが少ないためあふれているようです。たぶん、最初にこのコードを書いた方の環境はもっとGPUのメモリが豊富だったのでしょう。いくらか試してmaxlen=100000とあるところを最終的には57800まで減らしました。これで散っていったマリオの記憶を学習して次のマリオが熟練することができます。まさにAll You Need Is Kill状態です。

class Mario(Mario):
    def __init__(self, state_dim, action_dim, save_dir):
        super().__init__(state_dim, action_dim, save_dir)
        self.memory = deque(maxlen=57800)
        self.batch_size = 32

安定したループを回すために②

これで一応学習ループは回るようになったのですが、Google Colabフリー版で実行していると、不意に環境がリセットされることがあります。せっかく1000人のマリオが頑張ったのに、その記憶がなくなってしまい、また最初からやり直し、ということが発生しました。そもそも、強化学習は相当まとまった量の学習を続ける必要があり(元の版を作った方の解説によると、1-1をクリアするには4万マリオほど必要とのこと)、24時間以上かかりそうです。

途中の状態を保存して学習再開ができないと、不意の中断で心が折れてしまいます。このため、3つのことをしました。

  1. Google Driveの接続
  2. 学習状態の保存
  3. 学習結果の復元

保存については最初からMario.save()がありましたのでこれを使いました。
しかしどういうわけかMario.load()がなく、ここだけ自作しました。

LOAD_PATH = '/content/drive/My Drive/gym_mario/checkpoints/2022-01-01T00-00-00/mario_net_xxx.chkpt'
# checkpointからデータを読み込み
loaded_data = torch.load(LOAD_PATH)
# marioオブジェクトに値をロード
mario.net.load_state_dict(loaded_data['model'])
mario.exploration_rate = loaded_data['exploration_rate']

マリオのニューラルネットワークはMarioNetクラス(なんとオシャレな名前!)に実装されており、Mario.netから参照されます。ニューラルネットワークの復元はMario.net.load_stete_dictで行います。exploration_rate(マリオの行動を決めるとき、ランダムに行動を決めるか報酬が高そうな行動を取るか、の大きく2択になるのですが、ランダムな行動を取る割合を示す値)だけはニューラルネットワークとは別に保存されており、これも復元します。他のパラメータを保存しておきたい場合も、Mario.save()と合わせて追加するだけでOKなはずです。

その他細かな変更

マリオがクリアしたときにはぜひ知りたいので(というのも、高速で学習を回すために肝心のプレイ画面がでないため)、クリアがわかるように学習ループの中にメッセージを追加しました。

        # ゲームが終了したかどうかを確認
        if done or info["flag_get"]:
            if info["flag_get"]:
                # ゴールできたら知りたいですよね
                print(f"<<< Mario get the flag. GOOOOOAL! >>>")
            break

ひたすら学習

さて、安定的に実行できるようになったのでひたすら回すべし…… となるのですが、無料版は数時間ごとに止められてしまうこともあり、色々調べてColab Proを買うことにしました。月1180円くらいで(ほぼ)安定的にGPUインスタンスが使えます。良いGPUは高価なので、自分で買うよりこちらのほうがお安いと思っています。機械学習の環境を自分で作るのも大変ですし、継続的に機械学習をやってみるつもりなら、おすすめです。

途中経過の記録

約10000マリオのころ。落ち着きのないプレイ。
youtu.be

約15000マリオのころ。
youtu.be

約25000マリオのころ。だんだん動きが洗練されてきます。
youtu.be

約40000マリオ。当初の目標回数です。
なお、この動画は何度も実行して良いものを使っています。実際のクリア率は0.5%ほどです。
youtu.be

今後について

もう少し継続的に学習を回して、なんとかクリア率1%超えを狙いたいところです。

今回、マリオの行動の選択肢は最小限(右に移動するか、Aボタンを押してジャンプ)しかなく、1-1以外のステージに進んでも、クリア不可能になることが想定されます。そもそもBボタンダッシュができません。また、行動の選択肢を増やすと学習は初めからやりなおしになります。これは選択肢を増やすとニューラルネットワークを大きくしなければならないためです。またそれだけ多くの学習が必要になるはずです。その後どうするかは、いくつか試してから決めようと思っています。