強化学習 PPOアルゴリズム 徹底解説!手法と理論
はじめに
強化学習は、エージェントが環境と相互作用しながら試行錯誤を通じて最適な行動方策を獲得する機械学習のパラダイムです。近年、特に深層学習と組み合わせた深層強化学習の発展により、ゲーム(Go、チェス、Atari、StarCraftなど)やロボット制御といった複雑なタスクで目覚ましい成果を上げています。
強化学習の主要な手法の一つに、「ポリシー勾配法 (Policy Gradient Methods)」があります。これは、エージェントの行動方策(ポリシー)をパラメータ化し、そのパラメータを直接、期待報酬を最大化するように勾配 ascent によって更新していく手法です。ポリシー勾配法は、連続行動空間のタスクや、確率的な方策が必要なタスクにおいて特に有効です。
しかし、単純なポリシー勾配法にはいくつかの課題があります。最も顕著な課題の一つは、学習の不安定性です。ポリシーを大きく更新しすぎると、それまでの経験から大きくかけ離れた状態に遷移しやすくなり、学習が収束しにくくなったり、性能が突然劣化したりする可能性があります。特に、一度収集したデータ(経験)を複数回利用するOff-policy手法と比較して、ポリシー勾配法の多くの手法は、データを収集したポリシーとは異なるポリシーで学習を進めると、そのデータの「価値」が古くなりすぎて勾配が信頼できなくなる、いわゆる「Off-policy問題」に直面しやすいOn-policy手法に分類されます。このため、On-policy手法では、データを収集したポリシーで一度だけ学習を行い、すぐに新しいポリシーでデータを再収集する必要があり、データ効率が非常に悪いという欠点がありました。
このデータ効率の悪さを克服し、より安定した学習を実現するために、信頼領域ポリシー最適化 (Trust Region Policy Optimization, TRPO) というアルゴリズムが提案されました。TRPOは、ポリシーの更新が前回のポリシーから大きく乖離しないように、KLダイバージェンス(カルバック・ライブラー情報量)を使ってポリシー間の距離を制約として設けることで、学習の安定化を図りました。これにより、収集したデータを複数回、ある程度安心して再利用できるようになり、データ効率が改善されました。TRPOは多くのタスクで高い性能を示しましたが、その実装は比較的複雑であり、特に制約付き最適化問題を解くために二次計画法や共役勾配法などの手法を用いる必要がありました。
そこで登場したのが、近接ポリシー最適化 (Proximal Policy Optimization, PPO) です。PPOは、TRPOの主要なアイデアである「ポリシーの更新幅を適切に制限する」という概念を引き継ぎつつ、実装の複雑さを大幅に軽減したアルゴリズムです。PPOは、目的関数そのものを工夫することで、ポリシーの更新が信頼領域内に留まるように促します。これにより、TRPOと同等またはそれ以上の性能を、よりシンプルな実装で実現できることが示され、現在では強化学習の分野で最も広く使われているアルゴリズムの一つとなっています。
本記事では、このPPOアルゴリズムについて、その核となる理論と具体的な手法を徹底的に解説します。特に、ポリシー更新を制限するための「クリップされた代替目的関数」を中心に、その仕組み、なぜそれが機能するのか、そしてアルゴリズム全体の構造について詳しく見ていきます。
PPOの核心:クリップされた代替目的関数
PPOの最も特徴的なアイデアは、「クリップされた代替目的関数 (Clipped Surrogate Objective Function)」です。この目的関数は、ポリシーの更新を制御し、学習の不安定性を防ぐために設計されています。
なぜ目的関数を改良する必要があるのか?
ポリシー勾配法は、期待割引累積報酬(リターン)の勾配を計算し、その勾配方向にポリシーパラメータを更新することでリターンを最大化しようとします。基本的なポリシー勾配の定理によれば、ある状態 s
における行動 a
の対数確率 log pi(a|s; theta)
に関する目的関数の勾配は、その行動を選択したことによる利得 A(s, a)
に比例します。つまり、
grad E[R] propto E[ grad log pi(a|s; theta) * A(s, a) ]
ここで、E[R]
は期待リターン、pi(a|s; theta)
はパラメータ theta
を持つポリシー、A(s, a)
は状態 s
で行動 a
をとった際の利得(ある行動の価値がその状態の平均的な価値よりどれだけ優れているかを示す値)です。
この勾配を使ってポリシーパラメータ theta
を更新する際、学習率を大きく設定すると、ポリシーが大きく変化する可能性があります。前述のように、ポリシーの大きな変化は、収集したデータと新しいポリシーとの間に大きな乖離を生じさせ、学習の不安定化や収束の失敗を招きがちです。特にOn-policy設定で収集したデータを複数回再利用しようとする際に、この問題はより深刻になります。
TRPOは、この問題を「ポリシーの更新幅をKLダイバージェンスで制約する」という方法で解決しました。これは、目的関数 L(theta)
を最大化しつつ、KL[pi_old(.|s) || pi(.|s)] <= delta
の制約を満たすようにパラメータ theta
を更新するというものです。ここで pi_old
は更新前のポリシー、pi
は更新後のポリシー、delta
は許容されるKLダイバージェンスの上限値です。
PPOは、TRPOのこのアイデアを、制約付き最適化ではなく「目的関数そのものに組み込む」というアプローチで実現します。
ポリシー比率 (Probability Ratio) の導入
PPOでは、目的関数を定義するために「ポリシー比率 (Probability Ratio)」という概念を導入します。これは、現在のポリシー pi(a|s; theta)
で行動 a
を選択する確率と、データを収集した古いポリシー pi_old(a|s; theta_old)
で同じ行動 a
を選択する確率との比です。
r(theta) = pi(a|s; theta) / pi_old(a|s; theta_old)
この比率 r(theta)
は、古いポリシー theta_old
からパラメータ theta
にポリシーが更新された際に、特定の状態 s
で特定の行動 a
を取る確率がどれだけ変化したかを示します。r(theta)
が1に近いほど、新しいポリシーは古いポリシーに似ています。
基本的なポリシー勾配の目的関数は、期待利得 E[A]
を最大化するように、
L_PG(theta) = E_hat[ log pi(a|s; theta) * A_hat ]
のように表現できます。(E_hat
は収集されたサンプルに関する期待値、A_hat
は推定された利得です)。
ここで、log pi(a|s; theta) = log (pi(a|s; theta) / pi_old(a|s; theta_old)) + log pi_old(a|s; theta_old)
であることを利用すると、
L_PG(theta) = E_hat[ (log r(theta) + log pi_old(a|s; theta_old)) * A_hat ]
古いポリシー theta_old
は固定されているため、log pi_old(a|s; theta_old)
はパラメータ theta
に関して定数とみなせます(勾配には影響しません)。したがって、L_PG(theta)
を最大化することは、以下の目的関数を最大化することと等価になります。
L(theta) = E_hat[ (pi(a|s; theta) / pi_old(a|s; theta_old)) * A_hat ] = E_hat[ r(theta) * A_hat ]
この目的関数 L(theta)
は、古いポリシー pi_old
で収集されたデータ (s, a)
とその利得 A_hat
を用いて、新しいポリシー pi
の性能を評価しようとするものです。r(theta) * A_hat
の項は、古いポリシーのもとで得られた利得 A_hat
を、新しいポリシーのもとでの確率比率 r(theta)
で重み付けしていると解釈できます。
しかし、このままでは r(theta)
が非常に大きくなる(ポリシーが大きく変化する)ことを防ぐ仕組みがありません。A_hat
が正の場合、r(theta)
を大きくすれば目的関数はいくらでも増加してしまいます。これは、ポリシーの確率を不当に増加させてしまう可能性があり、学習を不安定にします。
クリップされた代替目的関数 L_CLIP(theta)
PPOは、上記の目的関数 L(theta) = E_hat[ r(theta) * A_hat ]
を改良し、ポリシー比率 r(theta)
にクリッピングを施します。クリップされた代替目的関数 L_CLIP(theta)
は以下のように定義されます。
L_CLIP(theta) = E_hat[ min(r(theta) * A_hat, clip(r(theta), 1 - epsilon, 1 + epsilon) * A_hat) ]
ここで、epsilon
は小さなハイパーパラメータ(例えば0.1や0.2など)であり、clip(x, l, r)
関数は、x
が [l, r]
の範囲に収まるように値を制限する関数です。
clip(x, l, r) = max(l, min(x, r))
つまり、clip(r(theta), 1 - epsilon, 1 + epsilon)
は、ポリシー比率 r(theta)
の値を [1 - epsilon, 1 + epsilon]
の範囲にクリップします。
目的関数 L_CLIP(theta)
は、r(theta) * A_hat
と、クリップされた r(theta)
を使った clip(r(theta), 1 - epsilon, 1 + epsilon) * A_hat
の最小値をとる形で定義されています。
この「最小値」と「クリッピング」の組み合わせが、ポリシーの更新幅を適切に制御するPPOの核となります。この式の意味を、利得 A_hat
の符号に注目して考えてみましょう。
-
A_hat > 0
の場合(その行動が平均より良かった場合):- エージェントは、この良い行動を取る確率を増やしたいと考えます。つまり、
r(theta) = pi(a|s; theta) / pi_old(a|s; theta_old)
を1より大きくしたいと考えます。 - 目的関数の項
r(theta) * A_hat
は、r(theta)
が増加するにつれて大きくなります。 - しかし、
L_CLIP
ではr(theta) * A_hat
とclip(r(theta), 1 - epsilon, 1 + epsilon) * A_hat
の最小値をとります。 - もし
r(theta)
が1 + epsilon
より大きくなると、clip(r(theta), 1 - epsilon, 1 + epsilon)
の値は1 + epsilon
に固定されます。 - このとき、
r(theta) * A_hat
は(1 + epsilon) * A_hat
より大きくなりますが、clip(r(theta), 1 - epsilon, 1 + epsilon) * A_hat
は(1 + epsilon) * A_hat
のままです。 - したがって、
min(r(theta) * A_hat, clip(r(theta), 1 - epsilon, 1 + epsilon) * A_hat)
の値は(1 + epsilon) * A_hat
で頭打ちになります。 - これは、良い行動 (
A_hat > 0
) の確率を増やそうとする際に、古いポリシーからの乖離率 (r(theta)
) が1 + epsilon
を超えても、目的関数はそれ以上増加しないことを意味します。つまり、ポリシーを際限なく変化させることによる利益を打ち消します。
- エージェントは、この良い行動を取る確率を増やしたいと考えます。つまり、
-
A_hat < 0
の場合(その行動が平均より悪かった場合):- エージェントは、この悪い行動を取る確率を減らしたいと考えます。つまり、
r(theta)
を1より小さくしたいと考えます。 - 目的関数の項
r(theta) * A_hat
は、A_hat
が負であるため、r(theta)
が減少するにつれて(例えば0に近づくにつれて)大きくなります(負の値がゼロに近づく)。 - しかし、
L_CLIP
ではr(theta) * A_hat
とclip(r(theta), 1 - epsilon, 1 + epsilon) * A_hat
の最小値をとります。 - もし
r(theta)
が1 - epsilon
より小さくなると(例えば0に近づく)、clip(r(theta), 1 - epsilon, 1 + epsilon)
の値は1 - epsilon
に固定されます。 - このとき、
r(theta) * A_hat
は(1 - epsilon) * A_hat
より小さくなります(A_hat
が負なので、r(theta)
が1 - epsilon
より小さくなるにつれてr(theta) * A_hat
の絶対値は大きくなり、より大きな負の値になる)。一方、clip(r(theta), 1 - epsilon, 1 + epsilon) * A_hat
は(1 - epsilon) * A_hat
のままです。 - したがって、
min(r(theta) * A_hat, clip(r(theta), 1 - epsilon, 1 + epsilon) * A_hat)
の値は(1 - epsilon) * A_hat
で頭打ちになります(より小さな負の値になることを防ぐ)。 - これは、悪い行動 (
A_hat < 0
) の確率を減らそうとする際に、古いポリシーからの乖離率 (r(theta)
) が1 - epsilon
を下回っても、目的関数はそれ以上増加しないことを意味します。つまり、悪い行動の確率を過度に減少させることによる利益を打ち消します。
- エージェントは、この悪い行動を取る確率を減らしたいと考えます。つまり、
まとめると、L_CLIP(theta)
は:
* 良い行動 (A_hat > 0
) については、その行動を選択する確率を増やすことを奨励するが、ポリシー比率 r(theta)
が 1 + epsilon
を超えた場合の目的関数の増加を制限します。これにより、ポリシーが古いポリシーから急激に離れることを防ぎます。
* 悪い行動 (A_hat < 0
) については、その行動を選択する確率を減らすことを奨励するが、ポリシー比率 r(theta)
が 1 - epsilon
を下回った場合の目的関数の増加を制限します。これにより、ポリシーが古いポリシーから急激に離れることを防ぎます。
このように、PPOのクリップされた目的関数は、ポリシーの更新が、古いポリシーからの乖離率 r(theta)
が [1 - epsilon, 1 + epsilon]
の範囲に収まるように「誘導」します。この範囲外への急激な変化は、目的関数の増加に寄与しないため、最適化プロセスはその範囲内に留まろうとします。これは、TRPOが制約として明示的に課していた「ポリシー間の距離制限」を、目的関数に implicitly に組み込んだものと解釈できます。
このクリッピング機構により、PPOは古いポリシーで収集したデータを複数回(複数エポック)にわたって再利用することが可能になります。各エポックで、収集されたデータバッチを用いて勾配降下法(またはAdamなどの最適化手法)によってポリシーパラメータ theta
を複数回更新します。複数回の更新を行っても、クリッピングによってポリシーの急激な変化が抑制されるため、収集したデータがある程度有効なまま利用できるのです。これがPPOのデータ効率の良さにつながっています。
PPOのもう一つの目的関数:アダプティブKLペナルティ
PPOのオリジナルの論文(Schulman et al., 2017)では、主にクリップされた目的関数が提案されていますが、もう一つ別の選択肢として「アダプティブKLペナルティ (Adaptive KL Penalty)」を用いる方法も提案されています。これは、TRPOのアイデアにより近いアプローチで、目的関数にKLダイバージェンスを用いたペナルティ項を加えることで、ポリシーの乖離を抑制します。
アダプティブKLペナルティを用いた目的関数 L_KL(theta)
は以下のように定義されます。
L_KL(theta) = E_hat[ r(theta) * A_hat - beta * KL[pi_old(.|s) || pi(.|s)] ]
ここで、
* r(theta) * A_hat
は、前述のポリシー比率を用いた基本となる目的関数項です。
* KL[pi_old(.|s) || pi(.|s)]
は、古いポリシー pi_old
と新しいポリシー pi
の間のKLダイバージェンスです。これは、ポリシーが状態 s
においてどれだけ乖離したかを示す指標です。
* beta
は、KLダイバージェンスに課されるペナルティの強度を調整するハイパーパラメータです。
この目的関数を最大化することは、期待利得 E_hat[r(theta) * A_hat]
を増加させつつ、ポリシーの乖離度 KL[pi_old(.|s) || pi(.|s)]
を抑制することに相当します。beta
が大きいほど、ポリシーの乖離に対するペナルティが強くなります。
さらに、「アダプティブ」なKLペナルティとは、このペナルティ係数 beta
を学習の進行に合わせて動的に調整する仕組みを導入するものです。具体的には、あるターゲットKLダイバージェンス値 d_target
を設定しておき、収集されたデータ全体における平均KLダイバージェンス d_KL = E_hat[KL[pi_old(.|s) || pi(.|s)]]
がこの d_target
からどれだけ乖離しているかに応じて beta
を調整します。
一般的な beta
の更新ルールは以下のようになります。
* もし d_KL > 1.5 * d_target
であれば、beta
を増やします(例えば beta = 2 * beta
)。これは、ポリシーが目標以上に乖離しているため、ペナルティを強化する必要があることを意味します。
* もし d_KL < 1 / 1.5 * d_target
であれば、beta
を減らします(例えば beta = beta / 2
)。これは、ポリシーの乖離が目標より小さい(ペナルティが強すぎる)ため、ペナルティを弱める必要があることを意味します。
* それ以外の場合 (1 / 1.5 * d_target <= d_KL <= 1.5 * d_target
) は、beta
を変更しません。
このアダプティブな調整により、学習プロセスを通じてポリシーの乖離を望ましい範囲に保とうとします。これはTRPOが制約としていた KL <= delta
を、目的関数へのペナルティと動的なペナルティ強度調整によって近似的に実現するアプローチと言えます。
PPOの論文では、クリップされた目的関数 (L_CLIP
) とアダプティブKLペナルティを用いた目的関数 (L_KL
) の両方が提案されていますが、実験的には L_CLIP
の方がわずかに良い性能を示す傾向があり、実装もよりシンプルであることから、現在PPOとして一般的に参照されるのは L_CLIP
を用いたバージョンです。そのため、以降の解説も主に L_CLIP
を用いたPPOを前提とします。
Value Function (価値関数) の導入
PPOは、アクター・クリティック (Actor-Critic) 型のアルゴリズムに分類されます。これは、ポリシー(アクター)と価値関数(クリティック)という二つの要素を持つことを意味します。
- アクター (Actor): 環境の状態
s
を入力として受け取り、取るべき行動a
を決定するポリシーpi(a|s; theta)
を担当します。ポリシーパラメータtheta
を学習します。 - クリティック (Critic): 環境の状態
s
がどれだけ良い状態であるかを評価する価値関数V(s; theta_v)
を担当します。価値関数パラメータtheta_v
を学習します。
ポリシー勾配法では、行動の良し悪しを評価するために「利得 (Advantage)」を用います。利得 A(s, a)
は、特定の状態 s
で特定の行動 a
をとったことによる価値が、その状態 s
の平均的な価値と比べてどれだけ優れているかを示します。
最も簡単な利得の定義は、以下のようになります。
A(s_t, a_t) = Q(s_t, a_t) - V(s_t)
ここで、Q(s_t, a_t)
は状態行動価値関数(状態 s_t
で行動 a_t
をとった後、最適なポリシーで進んだ場合に得られる期待割引累積報酬)です。
しかし、実環境では Q(s, a)
を直接知ることは難しく、推定する必要があります。価値関数 V(s)
を用いると、Q(s_t, a_t)
は、行動 a_t
をとった後に得られる即時報酬 R_t
と、次の状態 s_{t+1}
の価値 V(s_{t+1})
を用いて推定できます。
Q(s_t, a_t) approx R_t + gamma * V(s_{t+1})
ここで gamma
は割引率です。
これを利得の定義に代入すると、以下のようになります。
A(s_t, a_t) approx R_t + gamma * V(s_{t+1}) - V(s_t)
これはTD誤差 (Temporal Difference Error) に近い形をしています。V(s; theta_v)
は、クリティックによって学習される価値関数です。クリティックは、環境との相互作用で得られた経験 (s_t, a_t, R_t, s_{t+1})
を用いて、V(s_t)
が R_t + gamma * V(s_{t+1})
に近くなるように学習されます。これは、典型的には平均二乗誤差 (Mean Squared Error, MSE) などの誤差関数を最小化することで行われます。
L_VF(theta_v) = E_hat[ (V(s_t; theta_v) - (R_t + gamma * V(s_{t+1}; theta_v^-)))^2 ]
ここで、theta_v^-
はターゲットネットワーク(少し前の価値関数のパラメータ)を用いることもありますが、PPOの実装では単に現在の theta_v
を使うことが多いです。ターゲット値 R_t + gamma * V(s_{t+1}; theta_v)
はTDターゲットと呼ばれます。クリティックの目的は、V(s_t)
がTDターゲットに近づくように theta_v
を更新することです。
Generalized Advantage Estimation (GAE) の活用
上記で示した利得 A(s_t, a_t) = R_t + gamma * V(s_{t+1}) - V(s_t)
は、TD(0)誤差に基づいた利得の推定です。しかし、実際のPPOの実装では、Generalized Advantage Estimation (GAE) という手法を用いて利得を推定することが一般的です。
GAEは、バイアス(TD(0)誤差に基づく推定のバイアス)とバリアンス(長いエピソードに基づくモンテカルロ推定のバリアンス)のトレードオフを調整するための手法です。GAEでは、以下の式で利得を計算します。
delta_t = R_t + gamma * V(s_{t+1}) - V(s_t)
(これはTD(0)誤差)
A_t^{GAE(gamma, lambda)} = sum_{l=0}^{T-t-1} (gamma * lambda)^l * delta_{t+l}
ここで、
* gamma
は割引率です(価値関数やTDターゲット計算と同じ)。
* lambda
はGAE特有のハイパーパラメータで、0 <= lambda <= 1
の範囲をとります。
* lambda = 0
の場合、GAEはTD(0)誤差に基づく利得推定 delta_t
と一致します。これはバイアスが低いですが、バリアンスが高い可能性があります。
* lambda = 1
の場合、GAEはモンテカルロ法に基づく利得推定(全エピソードの割引報酬和から状態価値を引いたもの)に近づきます。これはバリアンスが低いですが、エピソードが長い場合にバイアスが大きくなる可能性があります。
* 通常は lambda
を0.9から0.99程度の値に設定し、バイアスとバリアンスのバランスを取ります。
GAEによって計算された利得 A_t^{GAE}
を、ポリシー目的関数 L_CLIP
の A_hat
として用います。
ポリシー(アクター)と価値関数(クリティック)は、多くの場合、パラメータの一部または全てを共有する一つのニューラルネットワークとして実装されます。例えば、入力層といくつかの隠れ層を共有し、最後の層でポリシーの出力(行動の確率分布や平均・分散)と価値関数の出力(状態価値)に分岐する、という形が一般的です。これにより、特徴抽出層を共有し、学習効率を高めることができます。
PPOの総合目的関数と学習プロセス
PPOは、ポリシーの更新 (L_CLIP
) と価値関数の学習 (L_VF
) を同時に行います。また、探索を促進するために、ポリシーのエントロピー(行動選択のランダム性)を目的関数に加えることがよくあります。
総合的な目的関数 L(theta, theta_v)
は、これらの要素を組み合わせたものとなります。
L(theta, theta_v) = E_hat[ L_CLIP(theta) - c1 * L_VF(theta_v) + c2 * S(pi(.|s; theta)) ]
ここで、
* L_CLIP(theta)
は、前述のクリップされたポリシー目的関数です。E_hat[ min(r(theta) * A_hat, clip(r(theta), 1 - epsilon, 1 + epsilon) * A_hat) ]
の形式をとります。これを最大化します。
* L_VF(theta_v)
は、価値関数の誤差関数です。E_hat[ (V(s_t; theta_v) - (R_t + gamma * V(s_{t+1}; theta_v^-)))^2 ]
や E_hat[ (V(s_t; theta_v) - V_{target})^2 ]
の形式をとります。これを最小化します。目的関数全体としては最大化したいので、マイナス符号 c1
を付けて加算します。
* S(pi(.|s; theta))
は、ポリシーのエントロピーです。E_hat[ H(pi(.|s; theta)) ]
の形式をとります。エントロピーを大きくすることは、ポリシーの出力分布をより平坦にする(様々な行動を取りやすくする)ことで、探索を促進します。これを最大化したいので、プラス符号 c2
を付けて加算します。
* c1
と c2
は、それぞれ価値関数誤差項とエントロピー項の重みを調整するハイパーパラメータです。
学習プロセスは、以下のようなステップで進行します。
- 初期化: ポリシーネットワークと価値ネットワークのパラメータ
theta
とtheta_v
を初期化します。古いポリシーパラメータtheta_old
をtheta
と同じ値に設定します。 - データ収集: 現在のポリシー
pi(a|s; theta)
を用いて、環境と相互作用し、一定量の経験データ(状態、行動、報酬、次の状態の遷移列)を収集します。通常、複数の並列環境で同時にデータを収集します。このデータは経験バッファに蓄積されます。 - 利得の計算: 収集されたデータに対して、現在の価値関数
V(s; theta_v)
を用いて、各タイムステップにおける利得A_hat
を計算します。GAEを用いる場合は、GAEの計算を行います。また、価値関数のターゲット値 (R_t + gamma * V(s_{t+1})
など) も計算します。 - 古いポリシーの確率の計算: データ収集時に使用したポリシー
pi_old(a|s; theta_old)
で各行動が選択される確率を計算しておきます(これは固定)。これにより、後続の最適化ステップでポリシー比率r(theta)
を計算できます。 - 目的関数の最適化: 収集したデータバッチを用いて、総合目的関数
L(theta, theta_v)
を勾配 ascent によって最適化します(誤差関数L_VF
の部分は勾配 descent)。この最適化は、収集したデータに対して複数エポック行います。各エポックでは、データをさらにミニバッチに分割し、各ミニバッチでパラメータを更新します。- ポリシーパラメータ
theta
の更新は、L_CLIP
とS
の勾配に基づいて行われます。 - 価値関数パラメータ
theta_v
の更新は、L_VF
の勾配に基づいて行われます。 - ネットワークがポリシーと価値関数でパラメータを共有している場合は、総合目的関数
L
全体の勾配を計算し、共有パラメータと非共有パラメータの両方を更新します。
- ポリシーパラメータ
- 古いポリシーの更新: 複数エポックの最適化が完了したら、現在のポリシーパラメータ
theta
をtheta_old
にコピーし、次のデータ収集フェーズで使用する古いポリシーを更新します。 - 繰り返し: ステップ2に戻り、データ収集と最適化を繰り返します。
この学習プロセスにおける重要な点は、データ収集(ステップ2-4)と目的関数の最適化(ステップ5)が分離されていることです。一度データを収集したら、そのデータを使って複数回パラメータを更新します。そして、一定量の更新を行った後に、ポリシーを更新し、再度データ収集を行います。これにより、On-policyでありながらデータ効率を改善しています。クリッピング機構(あるいはアダプティブKLペナルティ)は、この複数回のパラメータ更新の際にも、ポリシーが収集時ポリシーから大きく乖離することを防ぐ役割を果たします。
PPOの実装上の詳細とテクニック
PPOを効果的に実装・運用するためには、いくつかの詳細やテクニックを理解しておく必要があります。
Generalized Advantage Estimation (GAE)
前述の通り、PPOではGAEを用いて利得を計算するのが標準的です。GAEのハイパーパラメータ lambda
は重要な調整要素です。lambda
を1に近づけると、よりバイアスは低いがバリアンスが高い推定値となり、0に近づけるとバイアスは高いがバリアンスは低い推定値となります。実際の応用では、lambda
を0.9や0.95、0.99といった値に設定し、エピソードの長さやタスクの特性に合わせて調整することが多いです。
ネットワークアーキテクチャ
PPOは、ポリシーと価値関数を表現するためにニューラルネットワークを用います。使用するネットワークアーキテクチャは、入力される状態のタイプによって異なります。
* 離散的な状態空間やベクトル状態: 多層パーセプトロン (MLP) がよく使われます。
* 画像状態: 畳み込みニューラルネットワーク (CNN) が必須となります。ゲーム画面などを入力とする場合に使用されます。
* 系列データや記憶が必要なタスク: 回帰型ニューラルネットワーク (RNN, LSTM, GRU) が用いられることがあります。
ポリシーネットワークの出力層は、行動空間のタイプによって異なります。
* 離散行動空間: Softmax関数を通して、各行動の確率分布を出力します。
* 連続行動空間: 平均 mu
と標準偏差 sigma
を出力し、正規分布やベータ分布などの確率分布を構成します。この分布から行動をサンプリングします。標準偏差 sigma
は、状態に依存するように学習させる場合と、全状態で共通のパラメータとして学習させる場合があります。
価値ネットワークの出力層は、単一のニューロンで状態価値 V(s)
を出力します。
ハイパーパラメータチューニング
PPOの性能は、ハイパーパラメータに大きく依存します。主要なハイパーパラメータとその役割を理解し、タスクに合わせて適切にチューニングすることが重要です。
* epsilon (クリップ幅): L_CLIP
におけるクリッピング範囲 [1 - epsilon, 1 + epsilon]
を決定します。ポリシーの更新幅をどの程度制限するかを制御します。小さすぎると学習が遅くなり、大きすぎると不安定になります。0.1や0.2が一般的な値です。
* gamma (割引率): 将来の報酬をどれだけ重視するかを決定します。0に近いほど近視眼的なポリシーになり、1に近いほど長期的な報酬を重視します。通常0.9から0.999の間の値が用いられます。
* lambda (GAEパラメータ): 利得推定におけるバイアスとバリアンスのトレードオフを調整します。0.9から0.99の間で設定されることが多いです。
* c1 (価値関数誤差の重み): 総合目的関数における価値関数誤差項の寄与度を調整します。ポリシー学習と価値関数学習のバランスを取ります。
* c2 (エントロピーボーナスの重み): 総合目的関数におけるエントロピー項の寄与度を調整します。探索の度合いを制御します。大きいほどランダムな探索が増えます。
* 学習率 (Learning Rate): パラメータ更新のステップサイズを決定します。最適化手法(Adamなど)の学習率です。学習初期には高い値で始め、徐々に減衰させることも一般的です。
* バッチサイズ (Batch Size): データ収集フェーズで一度に収集する経験遷移の数(あるいはエピソード数)です。大きいほど勾配推定のバリアンスは下がりますが、メモリが必要になります。
* ミニバッチサイズ (Minibatch Size): 最適化フェーズで、収集したデータバッチをさらに分割するミニバッチのサイズです。勾配計算の効率とバリアンスに影響します。
* エポック数 (Number of Epochs): 収集したデータバッチに対して、何回パラメータ更新のエポックを行うかです。多すぎるとポリシーがデータ収集時ポリシーから乖離しすぎる可能性があり、少なすぎるとデータ再利用の恩恵が少なくなります。通常は数回(例えば3〜10回)程度に設定されます。
これらのハイパーパラメータは相互に関連しており、最適な組み合わせを見つけるためには体系的な実験(グリッドサーチやランダムサーチなど)が必要になる場合があります。
バッチ処理とミニバッチ学習
PPOでは、効率的な学習のためにバッチ処理とミニバッチ学習が重要です。
1. データ収集: 複数の環境インスタンスを並列で実行し、一定のタイムステップまたはエピソード数だけデータを収集します。これにより、多様な経験を効率的に集めることができます。収集されたデータは、(状態, 行動, 報酬, 次の状態, 終了フラグ, 行動の対数確率, 状態価値) の形式で一時的に保存されます。
2. 利得・ターゲット計算: 収集されたデータを用いて、GAEによる利得と価値関数のターゲット値を計算します。これらはネットワークの順伝播と簡単な計算で行えます。
3. 最適化: 収集された全データを一つの大きなバッチと見なし、このバッチをさらに小さなミニバッチに分割します。複数エポックにわたって、これらのミニバッチを用いてネットワークパラメータの更新を行います。例えば、収集したデータがN個の遷移から成り、ミニバッチサイズがM、エポック数がKであれば、合計で K * (N/M) 回のパラメータ更新が行われます。
ミニバッチ学習は、データバッチ全体で一度に勾配計算を行うよりも計算効率が良く、Stochastic Gradient Descent (SGD) の性質により局所最適に陥りにくいという利点があります。
PPOの利点と欠点
PPOがなぜ広く使われているのか、その利点と限界をまとめます。
利点
- 実装の容易さ: TRPOと比較して、PPOは目的関数にクリッピングを導入するという比較的シンプルな変更で実現されています。これにより、共役勾配法のような二次最適化手法を用いる必要がなく、標準的な深層学習ライブラリ(TensorFlow, PyTorchなど)の自動微分機能と勾配降下法(またはAdamなど)を用いて容易に実装できます。
- 安定した学習: クリップされた目的関数やアダプティブKLペナルティにより、ポリシーの更新幅が適切に制限されるため、学習が不安定になりにくく、性能の急激な劣化を防ぎやすいです。
- 優れた性能: 多くの連続行動空間や複雑なタスクにおいて、PPOはTRPOと同等またはそれ以上の高い性能を発揮することが示されています。OpenAI Five (Dota 2) や AlphaStar (StarCraft II) など、大規模な強化学習システムでもPPOが採用されています。
- データ効率の改善: On-policyアルゴリズムでありながら、収集したデータを複数エポックにわたって再利用できるため、標準的なポリシー勾配法(例: REINFORCE)やA2Cなどと比較してデータ効率が良いです。
- 並列化しやすい: データ収集を複数の環境で並列に行い、そのデータをまとめて学習に使うという構造が、マルチコアCPUや複数のGPUを用いた並列学習と相性が良いです。
欠点
- On-policyアルゴリズム: 収集したデータは、そのデータを収集したポリシーからの乖離が大きくなりすぎると利用できなくなります。このため、Off-policyアルゴリズム(例: DQN, DDPG, SAC)と比較すると、根本的なデータ効率では劣る場合があります。特定のタスクや環境では、Off-policy手法の方が少ない環境インタラクションで学習できることがあります。
- ハイパーパラメータチューニング: 前述のように、PPOには複数の重要なハイパーパラメータがあり、タスクや環境によって最適な値が異なります。これらのチューニングには試行錯誤が必要です。特にクリップ幅
epsilon
、GAEパラメータlambda
、そして学習率、エポック数などは性能に大きく影響します。 - 連続行動空間における確率分布の仮定: 連続行動空間でポリシーを表現する際、通常は正規分布などの特定の確率分布を仮定します。タスクによっては、この仮定が適切でない場合があり、より複雑な分布やノンパラメトリックな手法が必要になる可能性があります。
PPOの応用例
PPOは、その安定性と汎用性の高さから、様々な分野の強化学習タスクで広く応用されています。
- ロボット制御: 関節の多いロボットアームの操作、歩行ロボットの制御、ドローンの操縦など、連続行動空間を持つ複雑な物理シミュレーションや実機での制御タスク。
- ゲームAI: OpenAI Five (Dota 2)、AlphaStar (StarCraft II) など、複雑な戦略と大規模な行動空間を持つリアルタイム戦略ゲームやMOBAゲームでのAIエージェント開発。また、AtariゲームやMuJoCo物理シミュレーション環境など、様々なベンチマークタスクでも高い性能を発揮しています。
- 自動運転: 経路計画、行動決定、車両制御など、自動運転スタックの一部における意思決定モジュール。
- 金融トレーディング: 市場データに基づいて売買の意思決定を行うエージェント。
- 自然言語処理: 強化学習を用いたテキスト生成(RLHF – Reinforcement Learning from Human Feedbackなど)、対話システムの応答生成。
- レコメンデーションシステム: ユーザーの長期的なエンゲージメントを最大化するためのアイテム提示ポリシーの最適化。
- 資源管理: エネルギーグリッド管理、データセンターのクーリング制御など、動的なシステムにおける資源配分や制御。
PPOは、OpenAIによって公開されたBaselinesライブラリに含まれており、多くの研究者や開発者によって容易に利用・改変されてきました。これにより、様々なタスクへのPPOの適用が進んでいます。
TRPOとの比較
PPOはTRPOの後継として開発された経緯があるため、両者の比較はPPOの理解を深める上で有用です。
特徴 | TRPO | PPO (Clip) |
---|---|---|
ポリシー更新制御 | 明示的な制約 (KL[pi_old || pi] <= delta ) |
目的関数内のクリッピング (L_CLIP ) |
最適化手法 | 二次最適化 (共役勾配法など) が必要 | 勾配降下法 (Adamなど) |
実装の複雑さ | 比較的複雑 | 比較的容易 |
計算コスト | 比較的高い | 比較的低い |
データ効率 | On-policy、データ再利用可 | On-policy、データ再利用可 (TRPOと同等以上) |
性能 | 高い性能 | TRPOと同等またはそれ以上の高い性能 |
TRPOは理論的には信頼領域内の最適化を保証しようとしますが、その計算は複雑です。PPOは、この「信頼領域内での更新」というアイデアを、より計算しやすい「目的関数へのペナルティまたはクリッピング」という形で実現します。これにより、理論的な厳密さは若干犠牲になるものの、実践的な実装の容易さと性能の両立を達成しました。特に大規模なニューラルネットワークを用いた場合、PPOのような一次勾配法ベースの手法の方が効率的にスケールしやすいという利点もあります。
今後の展望
PPOは広く普及していますが、研究開発は続いています。
* さらなる改良: PPOの安定性やデータ効率をさらに向上させるための改良版(例: PPO2のバリエーション、新しい目的関数など)が提案されています。
* Off-policy手法との融合: On-policyであるPPOのデータ効率を、Off-policy手法のアイデアを取り入れることで改善する試みがあります。
* 新しいアーキテクチャとの組み合わせ: Transformerのような新しいネットワークアーキテクチャや、アテンション機構、グラフニューラルネットワークなどと組み合わせることで、より複雑なタスクに対応できるPPOベースのエージェントが開発される可能性があります。
* マルチエージェント強化学習: 複数のエージェントが協調または競合する環境におけるPPOの適用と拡張。
PPOはそのシンプルな構造と高い性能から、今後も強化学習研究および応用の基盤となるアルゴリズムの一つであり続けると考えられます。
まとめ
本記事では、強化学習における主要なアルゴリズムであるPPO (Proximal Policy Optimization) について、その手法と理論を詳細に解説しました。
PPOは、従来のポリシー勾配法における学習の不安定性や、On-policy手法のデータ効率の悪さを克服するために開発されました。TRPOのアイデアである「ポリシーの更新幅を制限する」という概念を引き継ぎつつ、より実装が容易な方法で実現しています。
PPOの核となるのは、「クリップされた代替目的関数 (L_CLIP
)」です。この目的関数は、ポリシー比率 (pi(a|s; theta) / pi_old(a|s; theta_old)
) にクリッピングを施すことで、ポリシーが古いポリシーから急激に乖離することを防ぎます。これにより、収集したデータを複数回の学習更新に再利用できるようになり、データ効率が向上します。利得 (A_hat
) の符号に応じて、良い行動の確率を増やそうとする際の上限と、悪い行動の確率を減らそうとする際の下限が設定されることで、ポリシーの暴走を防ぎます。
PPOはアクター・クリティック構造を採用しており、ポリシーネットワーク(アクター)と価値ネットワーク(クリティック)を同時に学習します。価値関数は、行動の良し悪しを示す利得を推定するために使用され、一般的にはGeneralized Advantage Estimation (GAE) を用いて計算されます。
PPOの学習プロセスは、環境からのデータ収集と、そのデータを用いた複数エポックのミニバッチ学習というサイクルを繰り返します。総合目的関数は、クリップされたポリシー目的関数、価値関数誤差、そして探索を促進するためのエントロピーボーナス項から構成されます。
PPOの主な利点は、実装の容易さ、学習の安定性、優れた性能、および比較的良好なデータ効率です。一方で、On-policyであることや、ハイパーパラメータチューニングが必要であることなどが欠点として挙げられます。
その汎用性と性能から、PPOはロボット制御、ゲームAI、自動運転、金融トレーディング、自然言語処理など、幅広い分野で成功を収めています。
PPOは、強化学習の分野における重要なブレークスルーであり、多くの実応用に道を開きました。その基本的なアイデアと実装手法を理解することは、現代の深層強化学習を学ぶ上で不可欠です。本記事が、PPOアルゴリズムの深い理解の一助となれば幸いです。