#学びの軌跡
-
相手が賢くなると、環境が変わってしまう — 強化学習を対戦ゲームに持ち込むとき
強化学習の基礎(TD法、モンテカルロ法、DQN)を学んだ直後に、対戦ゲームを作ってみようとして ぶつかった問いの記録。 教科書で学んだ世界観は「エージェントと環境の2者」だった。エージェントが行動すると、環境が報酬と 次の状態を返す。FrozenLake も CartPole も、登場人物は自分だけ。ところが五目並べのような対戦ゲームでは 相手がいる。相手の動きを環境の一部とみなせばよいのか? しかしそれだと、環境の振る舞いが 「相手の賢さ」に依存してしまう。相手が学習して強くなれば、環境そのものが変わってしまう—— これは全然別のパラダイムが要るのではないか、と考えた。 答えは「その直感は正しい」だった。相手込みで環境とみなすのが最もシンプルで、エージェントから見た インターフェースは FrozenLake と全く同じになる。ただし相手が成長すると、同じ状態・行動に対する 報酬の分布が時間とともに変わる。これは非定常環境問題と呼ばれる、名前のついた問題だった。 対処は難易度順に、相手を固定する/カリキュラム学習(段階的に相手を強化)/Self-play(AlphaGo 方式)。 そして実際に実装して動かしたら、学習が収束しなかった。勝率は 5000 エピソード回しても 37% 前後で 頭打ち。「そんなものでしょうか?」と聞いたら、「そんなものではなく、設計上の問題が複数重なっている」 という診断が返ってきた。ε の減衰が速すぎる、報酬が sparse すぎる、ネットワークが浅い、 バッファが小さい。修正したら 500 エピソードで勝率 80% を超えた。 理論を学ぶ → 実装する → 失敗する → 診断する → 直す、という一周が丸ごと入っている。
-
同じ「VM」という名前の、別の概念 — 抽象化の階層はどこに挟まるのか
Java のバイトコードを動かす「VM」と、ハイパーバイザーの上に乗る「VM(仮想マシン)」は、 同じ概念なのか、それとも名前が似ているだけの別物なのか——という素朴な問いから始めた対話。 答えは「名前が似ているだけの別物。ただし、どちらも『抽象化レイヤー』という共通の思想から来ている」 だった。そこから、Java・C・Python の変換経路を一つずつ対比していくことになる。 Java は「Write Once, Run Anywhere」のために、自由に書ける高級言語と、CPU ごとに違うアセンブリの間に、 「高級言語ほど高級ではないが、CPU の仕様まで踏み込む必要がない」中間の層を挟んだ。それがバイトコード。 C は中間層を持たず、コンパイル時に機械語まで落とす。つまり**アーキテクチャの差を、Java は実行時に JVM が吸収し、C はコンパイル時に gcc が吸収する**。 この対比から、いくつかの理解が芋づる式に繋がった。Java が C より逆コンパイルしやすいのは、 バイトコードが元のソースの構造を保っているから。gcc は「動くマシン」と「生成する機械語のターゲット」を 分離できる(クロスコンパイル)。そして最後に、思い込みが一つ壊れた—— **Java は最初から JIT で全部コンパイルするわけではなく、まずインタプリタで実行し、 よく使われる部分だけを JIT でコンパイルする**。JIT とインタプリタは排他ではなかった。