数式とPython実装から理解する方策勾配法
強化学習における方策勾配法は、エージェントがどのように行動方策を学習していくかを示す重要な手法です。特に連続空間や大きな状態空間を扱う際に有効で、直接方策のパラメータを最適化するアプローチとして注目されています。初心者の方でも理解しやすいように、数式の基礎からPythonコードまで順を追って解説します。
この記事で学べることは以下の通りです:
- 方策勾配法の基本的な数式の意味と導出
- 代表的な方策勾配アルゴリズムの仕組み
- Pythonでの簡単な実装例と動作の確認
- 方策勾配法の強みや活用シーンの理解
方策勾配法は、方策のパラメータ \(\theta\) を直接更新するため、例えば次のような形で表されます。
\[
\theta \leftarrow \theta + \alpha \nabla_\theta J(\theta)
\]
ここで、\(J(\theta)\) は方策の期待報酬であり、勾配 \(\nabla_\theta J(\theta)\) を計算してパラメータを更新することで、より良い行動方策を学習します。これをPythonでどのように実装するかも詳しく見ていきましょう。
まとめ
本記事では、方策勾配法の数式的背景とPythonによる実装例を通じて、その基本的な仕組みと動作を理解しました。方策勾配法は直接方策をパラメータ化し、勾配上昇法で期待報酬を最大化するため、連続的な行動空間や複雑な問題にも適用しやすい特徴があります。
実装面では、勾配の計算や報酬の扱い方に注意が必要ですが、シンプルなコードから段階的に学ぶことで理解が深まります。今回の内容をベースに、より実践的な強化学習アルゴリズムへの応用も視野に入れてみてください。
次に読むと良い関連記事候補の観点としては、「価値関数ベースの手法との比較」が挙げられます。方策勾配法と価値関数を使う手法では学習のアプローチが異なるため、それぞれのメリット・デメリットを理解することで、より適切なアルゴリズム選択が可能になります。
次のステップ
- 価値関数ベースの強化学習アルゴリズム(例:Q学習、DQN)を学ぶ
- 実環境での方策勾配法の応用例を調査する
- TensorFlowやPyTorchを用いた深層強化学習の実装に挑戦する
方策勾配法とは何か
方策勾配法(policy gradient method)は、強化学習の分野で使われる重要なアルゴリズムの一つです。強化学習では、エージェントが環境と相互作用しながら報酬を最大化する行動を学習します。方策勾配法は、エージェントの「方策(policy)」を直接パラメータ化し、そのパラメータを勾配上昇法によって最適化する手法です。
ここでいう「方策」とは、状態 \( s \) においてどの行動 \( a \) を取るかの確率分布を表す関数です。従来の値関数ベースの方法と異なり、方策勾配法は行動の確率を直接調整するため、連続空間の行動や確率的な行動選択に適しています。
具体的には、パラメータ \(\theta\) を持つ方策 \(\pi_\theta(a|s)\) を考え、期待される累積報酬の期待値を最大化します。目的関数は以下のように表せます。
J(\theta) = \mathbb{E}_{\pi_\theta} \left[ \sum_{t=0}^\infty \gamma^t r_t \right]
\]
ここで、\(\gamma\) は割引率、\(r_t\) は時刻 \(t\) の報酬です。方策勾配法の中心的な考え方は、この目的関数の勾配を計算し、パラメータを更新することです。代表的な勾配の式は次の通りです。
\nabla_\theta J(\theta) = \mathbb{E}_{\pi_\theta} \left[ \nabla_\theta \log \pi_\theta(a|s) \, Q^{\pi_\theta}(s,a) \right]
\]
この式は「Policy Gradient Theorem」と呼ばれています。ここで、\(Q^{\pi_\theta}(s,a)\) は状態 \(s\)、行動 \(a\) における価値関数で、将来の報酬の期待値を表します。直感的には、行動の確率を増やす方向にパラメータを調整し、価値の高い行動を促進することを意味します。
Pythonで簡単に方策勾配法の更新ステップを表現すると、以下のようになります。
import numpy as np
def policy_gradient_update(theta, states, actions, q_values, learning_rate):
for s, a, q in zip(states, actions, q_values):
grad_log_pi = compute_grad_log_policy(theta, s, a) # 方策の勾配を計算する関数
theta += learning_rate * grad_log_pi * q
return theta
このコードは、収集した状態・行動・価値の情報を用いてパラメータ \(\theta\) を更新しています。実際の実装では、ニューラルネットワークで方策を表現し、勾配を自動計算することが一般的です。
まとめると、方策勾配法は「方策を確率分布として直接パラメータ化し、そのパラメータを報酬最大化のために勾配上昇で更新する」方法であり、連続行動や確率的行動に強い柔軟性を持つ強化学習アルゴリズムの一つです。
方策勾配法の基本概念
方策勾配法は、強化学習においてエージェントが最適な行動方策を直接学習するための代表的な手法です。ここでいう「方策」とは、ある状態における行動の選択確率を示す関数のことを指します。方策勾配法は、この方策のパラメータを微分可能な関数として定義し、そのパラメータを勾配上昇法などで更新することで、報酬を最大化する方向に方策を改善していきます。
数式で表すと、方策をパラメータ \(\theta\) で表現した場合、目標は期待報酬の期待値を最大化することです。期待報酬の期待値は以下のように定義できます。
\[
J(\theta) = \mathbb{E}_{\tau \sim p_{\theta}(\tau)} \left[ R(\tau) \right]
\]
ここで、\(\tau\) は状態と行動の軌跡(トラジェクトリ)、\(R(\tau)\) はその軌跡に沿った累積報酬を示します。方策勾配法では、この目的関数 \(J(\theta)\) の勾配を計算し、パラメータ \(\theta\) を更新します。
方策勾配の基本的な定理により、勾配は次のように表されます。
\[
\nabla_{\theta} J(\theta) = \mathbb{E}_{\tau \sim p_{\theta}(\tau)} \left[ \sum_{t=0}^{T} \nabla_{\theta} \log \pi_{\theta}(a_t | s_t) \cdot R(\tau) \right]
\]
ここで、\(\pi_{\theta}(a_t | s_t)\) は状態 \(s_t\) における行動 \(a_t\) の選択確率を示す方策関数です。この式は、得られた報酬に基づいて確率のログを重み付けし、その勾配を計算することで方策を改善します。
この数式の意味を理解するために、Pythonで簡単な実装例を示します。以下のコードでは、ある単純な状態・行動空間で方策パラメータ \(\theta\) を勾配上昇法により更新するイメージを表現しています。
import numpy as np
# 方策のパラメータ(例として1次元)
theta = 0.5
learning_rate = 0.1
# 方策関数(シグモイド関数を用いた確率)
def policy(theta, state):
z = theta * state
return 1 / (1 + np.exp(-z))
# ある状態における行動(0または1)
state = 1.0
action = 1 # 例えば行動1を選択
# 得られた報酬
reward = 1.0
# 方策のログ確率の勾配
prob = policy(theta, state)
grad_log_policy = (action - prob) * state
# パラメータ更新(方策勾配)
theta += learning_rate * grad_log_policy * reward
print(f"Updated theta: {theta:.3f}")
このコードでは、シグモイド関数を用いて方策の確率を計算し、実際の行動と確率との差分を利用してパラメータを更新しています。これが方策勾配法の基本的な考え方であり、報酬に応じて方策のパラメータを勾配方向に調整することで、より良い行動選択を学習します。
強化学習における方策の役割
強化学習において「方策(ポリシー)」とは、エージェントがどの行動を選択すべきかを決定するルールや戦略のことを指します。環境の状態を入力として受け取り、その状態に基づいて次に取るべき行動を出力する関数のようなものです。方策は、エージェントが報酬を最大化するための意思決定の基盤となり、強化学習アルゴリズムの中心的な役割を果たします。
方策には主に2種類あります:
- 決定的方策(Deterministic Policy): 状態に対して一つの行動を決定的に選択します。つまり、ある状態 \( s \) において、次の行動は常に一定です。
- 確率的方策(Stochastic Policy): 状態に対して行動の確率分布を返します。例えば、状態 \( s \) において、行動 \( a \) を選択する確率が \( \pi(a|s) \) と表されます。
方策勾配法では、確率的方策をパラメータ \(\theta\) で表現し、そのパラメータを最適化します。具体的には、期待される総報酬を最大化するために、方策のパラメータ \(\theta\) を勾配上昇法で更新します。数式で表すと、目的関数(期待報酬)は
\[
J(\theta) = \mathbb{E}_{\tau \sim \pi_\theta} \left[ \sum_{t=0}^T r_t \right]
\]
ここで、\(\tau\) は方策 \(\pi_\theta\) に従って生成される状態・行動の軌跡、\(r_t\) は時刻 \(t\) の報酬です。方策勾配法はこの関数の勾配を計算し、パラメータを更新します。
Pythonでの簡単な方策勾配更新のコード例を示します。
import numpy as np
def policy_gradient_update(theta, grad, learning_rate=0.01):
"""
パラメータthetaを勾配gradに沿って更新する
"""
return theta + learning_rate * grad
# 例: 勾配ベクトル
grad_example = np.array([0.1, -0.2, 0.05])
theta = np.array([0.5, 0.3, -0.1])
theta = policy_gradient_update(theta, grad_example)
print(theta) # 更新後のパラメータ
このように、方策は「どの行動を選ぶか」の戦略を定め、方策勾配法ではその戦略をパラメータ化して最適化します。これにより、エージェントは環境からのフィードバックをもとに学習し、より良い行動を取ることが可能になります。
方策勾配法の数式表現
方策勾配法は、強化学習において直接方策(行動選択の確率分布)をパラメータ化し、そのパラメータを最適化する手法です。ここでは、方策勾配法の基本的な数式表現を初心者向けに解説します。
まず、方策をパラメータ \(\theta\) で表した関数 \(\pi_\theta(a|s)\) を考えます。これは「状態 \(s\) において行動 \(a\) を選択する確率」を意味します。方策勾配法では、このパラメータを調整して期待報酬を最大化します。
期待報酬の関数は通常、以下のように定義されます。
\[
J(\theta) = \mathbb{E}_{\tau \sim \pi_\theta} \left[ R(\tau) \right]
\]
ここで、\(\tau\) は状態と行動の軌跡(エピソード)、\(R(\tau)\) はその軌跡で得られる累積報酬です。方策勾配法の目的は、この \(J(\theta)\) を最大化することです。
方策のパラメータを更新する勾配は、以下の「方策勾配定理」に基づき計算されます。
\[
\nabla_\theta J(\theta) = \mathbb{E}_{s \sim d^{\pi_\theta}, a \sim \pi_\theta} \left[ \nabla_\theta \log \pi_\theta(a|s) Q^{\pi_\theta}(s,a) \right]
\]
ここで、
- \(d^{\pi_\theta}(s)\) は方策 \(\pi_\theta\) に従う状態分布(訪問頻度)
- \(Q^{\pi_\theta}(s,a)\) は状態 \(s\) で行動 \(a\) を取ったときの期待累積報酬(行動価値関数)
この式の意味は、方策のパラメータ \(\theta\) を変えたときに、どのように期待報酬が変化するかを示しています。特に、確率の対数の勾配 \(\nabla_\theta \log \pi_\theta(a|s)\) によって方策の更新方向を決め、価値関数 \(Q^{\pi_\theta}(s,a)\) がその重みづけを担います。
この理論をシンプルなPythonコードで表すと以下のようになります。
import numpy as np
def policy_gradient_update(theta, states, actions, rewards, learning_rate):
# 仮の方策の対数勾配(例:softmax方策の勾配)
def grad_log_policy(theta, state, action):
# ここでは単純化のため、勾配は状態・行動に依存しないとしている
return np.ones_like(theta)
# 累積報酬の計算(例:単純な合計)
G = sum(rewards)
# 勾配の初期化
grad = np.zeros_like(theta)
for s, a in zip(states, actions):
grad += grad_log_policy(theta, s, a) * G
# パラメータの更新
theta += learning_rate * grad
return theta
このコードは方策勾配法の基本的な考え方を模擬的に示したもので、実際には行動価値関数の推定や状態ごとの勾配計算などが必要ですが、数式のイメージを掴むのに役立ちます。
方策勾配定理の導出
方策勾配法は、強化学習において方策のパラメータを直接最適化する手法の一つです。ここでは、方策勾配定理の基本的な導出を初心者向けにわかりやすく説明します。
まず、方策 \(\pi_\theta(a|s)\) は状態 \(s\) で行動 \(a\) を選択する確率であり、パラメータ \(\theta\) に依存しています。強化学習の目的は、期待収益(価値関数)
\[
J(\theta) = \mathbb{E}_{\pi_\theta} \left[ \sum_{t=0}^\infty \gamma^t r_t \right]
\]
を最大化することです。ここで、\(\gamma\) は割引率、\(r_t\) は時刻 \(t\) の報酬です。
方策勾配定理は、\(J(\theta)\) の勾配を次の形で表現します:
\[
\nabla_\theta J(\theta) = \mathbb{E}_{\pi_\theta} \left[ \nabla_\theta \log \pi_\theta(a|s) \, Q^{\pi_\theta}(s,a) \right]
\]
この式の意味を順に解説します。
- \(\nabla_\theta \log \pi_\theta(a|s)\):方策の確率の対数微分で、方策のパラメータ変化が行動確率にどう影響するかを示します。
- \(Q^{\pi_\theta}(s,a)\):状態 \(s\) で行動 \(a\) を取ったときに得られる期待収益(行動価値関数)です。
この定理の導出は、期待値の微分とマルコフ連鎖の性質を利用しますが、ここでは直感的な理解に重点を置きます。方策のパラメータを微小に変えたとき、どの行動の確率を増やせば期待収益が上がるかを示す指標がこの勾配です。
実際の実装では、サンプルを用いてこの期待値を近似し、勾配上昇法でパラメータ更新を行います。以下は簡単なPythonコード例です。
import numpy as np
def policy_gradient_update(theta, states, actions, rewards, gamma=0.99, lr=0.01):
# 簡易的な方策の対数微分とQ値(ここでは累積報酬をQ値の代わりに使用)
G = 0
returns = []
for r in rewards[::-1]:
G = r + gamma * G
returns.insert(0, G)
returns = np.array(returns)
for s, a, Gt in zip(states, actions, returns):
# ここでは方策の対数微分の例を仮定(実際にはモデルに依存)
grad_log_pi = compute_grad_log_policy(theta, s, a) # ユーザ定義関数と想定
theta += lr * grad_log_pi * Gt
return theta
このように、方策勾配定理は方策のパラメータ更新の理論的基盤となり、強化学習の多くのアルゴリズムで活用されています。次のステップでは、より具体的な数式展開や実装例に進んでいきます。
方策のパラメータ化方法
方策勾配法を理解する上で重要なのが、方策のパラメータ化方法です。方策とは、エージェントがどの行動を取るかを決める確率的ルールのことですが、これを数学的に表現し、計算可能な形にする必要があります。パラメータ化とは、この方策をパラメータ(重み)を用いて表現することを指します。
一般的には、方策をパラメータ \(\theta\) を用いた確率分布として表現します。例えば、状態 \(s\) における行動 \(a\) の選択確率を
\[
\pi_{\theta}(a|s)
\]
と書きます。ここで \(\theta\) は、方策のパラメータベクトルです。これにより、方策は「ある状態でどの行動をとるか」の確率を決定する関数として定義されます。
方策のパラメータ化の具体例として、ソフトマックス関数を使った方法があります。これは、各行動に対してスコア関数 \(h_{\theta}(s,a)\) を計算し、そのスコアを指数関数に通して正規化することで確率を得ます。式で表すと次のようになります。
\[
\pi_{\theta}(a|s) = \frac{\exp(h_{\theta}(s,a))}{\sum_{b} \exp(h_{\theta}(s,b))}
\]
この方法の利点は、全ての行動確率が正の値で、合計が1になることが保証される点です。例えば、\(h_{\theta}(s,a)\) を線形関数として
\[
h_{\theta}(s,a) = \theta_a^{\top} \phi(s)
\]
のように表現し、\(\phi(s)\) を状態の特徴ベクトル、\(\theta_a\) を行動 \(a\) に対応するパラメータベクトルとすると、状態ごとに違う行動確率を計算できます。
Pythonで実装する場合、numpyを用いて次のように書けます。
import numpy as np
def softmax(x):
e_x = np.exp(x - np.max(x))
return e_x / e_x.sum()
def policy(state_features, theta):
"""
state_features: numpy array of shape (feature_dim,)
theta: numpy array of shape (num_actions, feature_dim)
"""
scores = theta.dot(state_features) # 各行動のスコア計算
probs = softmax(scores) # ソフトマックスで確率化
return probs
ここで、`theta` は各行動に対応するパラメータ行列で、`state_features` は状態の特徴量ベクトルです。この関数は、入力された状態の特徴に基づいて各行動の確率を返します。
まとめると、方策勾配法ではまず方策をパラメータ化し、そのパラメータを勾配法で更新していくことで最適方策を探索します。パラメータ化の方法としては、ソフトマックス関数を使った確率分布の表現が最も一般的であり、これにより連続的かつ微分可能な方策表現が可能になります。
方策勾配法のアルゴリズム概要
方策勾配法は、強化学習においてエージェントが最適な行動方策(ポリシー)を直接学習する手法です。従来の価値ベースの手法と異なり、方策のパラメータを微分可能な関数で表現し、その勾配を用いて方策を改善していきます。ここでは、方策勾配法の基本的なアルゴリズムの流れを初心者向けに解説します。
まず、方策をパラメータ \(\theta\) で表した関数 \(\pi_\theta(a|s)\) を考えます。これは状態 \(s\) における行動 \(a\) の確率を示します。方策勾配法の目的は、期待報酬を最大化するように \(\theta\) を更新することです。そのために、期待報酬の勾配を計算し、それに沿ってパラメータを調整します。
期待報酬の勾配は以下のように表されます。
\[
\nabla_\theta J(\theta) = \mathbb{E}_{\pi_\theta}\left[ \nabla_\theta \log \pi_\theta(a|s) \cdot G_t \right]
\]
ここで、\(J(\theta)\) は方策の期待報酬、\(G_t\) は時刻 \(t\) からの割引累積報酬です。この式は「方策勾配の定理」と呼ばれ、報酬の高い行動に対して方策の確率を増やす方向にパラメータを更新することを意味します。
実際のアルゴリズムは以下のステップで進みます。
- 現在の方策 \(\pi_\theta\) に従って環境からエピソードをサンプルする。
- 各時刻の割引累積報酬 \(G_t\) を計算する。
- 方策の勾配 \(\nabla_\theta \log \pi_\theta(a_t|s_t)\) を求める。
- 方策パラメータ \(\theta\) を勾配上昇法により更新する。
これをPythonで簡単に表すと、以下のようになります。
import numpy as np
def update_policy(theta, states, actions, rewards, gamma=0.99, alpha=0.01):
G = 0
returns = []
# 割引累積報酬を計算(逆順で計算)
for r in rewards[::-1]:
G = r + gamma * G
returns.insert(0, G)
returns = np.array(returns)
for s, a, Gt in zip(states, actions, returns):
# 方策の勾配の計算(例としてソフトマックス方策を仮定)
probs = np.exp(np.dot(theta, s)) / np.sum(np.exp(np.dot(theta, s)))
grad_log_pi = s * (1 if a == np.argmax(probs) else 0 - probs)
# パラメータ更新
theta += alpha * grad_log_pi * Gt
return theta
このコードは、各ステップで得られた報酬を用いて方策のパラメータ \(\theta\) を更新しています。実際には方策の具体的な表現や環境によって詳細は異なりますが、基本的な流れはこのように「報酬を重みとした勾配更新」であることが理解できます。
方策勾配法は、連続的な行動空間や確率的方策の最適化に適しており、深層強化学習の基盤技術としても広く活用されています。数式とコードの対応を理解することで、より実践的な実装や応用へとつなげやすくなるでしょう。
Pythonでの方策勾配法実装準備
方策勾配法は強化学習の中でも基本的かつ強力な手法の一つです。これからPythonで実装を始めるにあたり、まずは必要なライブラリの準備と基本的な数式の理解を行いましょう。初心者の方でも理解しやすいように、数式の意味からコードへの落とし込みまで丁寧に解説します。
必要なライブラリのインストールとインポート
方策勾配法の実装では、数値計算に便利な numpy や強化学習環境を用意するための gym などがよく使われます。まずはこれらのライブラリをインストールしましょう。
- NumPy: ベクトルや行列の計算を効率的に行うためのライブラリ
- Gym: OpenAIが提供する強化学習環境のフレームワーク
インストールは以下のコマンドで行えます。
!pip install numpy gym
方策勾配法の基本数式
方策勾配法の核心は、パラメータ \(\theta\) で表される方策 \(\pi_{\theta}(a|s)\) を直接最適化することです。期待報酬を最大化するため、勾配上昇法でパラメータを更新します。更新式は以下のように表されます。
式:
\[
\theta \leftarrow \theta + \alpha \nabla_{\theta} J(\theta)
\]
ここで、\(J(\theta)\) は期待報酬、\(\alpha\) は学習率です。方策勾配の具体的な形はモンテカルロ法を用いる場合、
\[
\nabla_{\theta} J(\theta) \approx \mathbb{E}_{\pi_{\theta}} \left[ \nabla_{\theta} \log \pi_{\theta}(a|s) \cdot G_t \right]
\]
となります。\(G_t\) は時刻 \(t\) から得られる累積報酬です。この考え方をコードに落とし込むために、まずは方策の確率分布とその対数微分を計算できるようにします。
Pythonコード例:ソフトマックス方策の実装
ソフトマックス関数を用いた方策は、状態 \(s\) に対する各行動 \(a_i\) の選択確率を以下のように定義します。
\[
\pi_{\theta}(a_i|s) = \frac{e^{\theta_i^\top x(s)}}{\sum_j e^{\theta_j^\top x(s)}}
\]
ここで、\(\theta_i\) は行動 \(a_i\) に対応するパラメータベクトル、\(x(s)\) は状態の特徴ベクトルです。以下のコードは、この方策を計算し、対数確率の勾配を求める関数の例です。
import numpy as np
def softmax(theta, x):
z = np.dot(theta, x)
exp_z = np.exp(z - np.max(z)) # オーバーフロー防止
return exp_z / np.sum(exp_z)
def grad_log_policy(theta, x, action):
probs = softmax(theta, x)
grad = -probs[:, None] * x[None, :]
grad[action] += x
return grad
このコードでは、まず状態特徴ベクトル x とパラメータ行列 theta を使って各行動の確率を計算しています。grad_log_policy 関数は、選択された行動に関する対数方策の勾配を計算し、方策勾配法のパラメータ更新に利用できます。
次のステップでは、この勾配情報を使い、実際に方策パラメータを更新していくアルゴリズムの実装に進みましょう。
環境設定と必要なライブラリ紹介
方策勾配法をPythonで実装するためには、まず適切な開発環境と必要なライブラリを整えることが重要です。ここでは初心者の方でもスムーズに始められるよう、環境設定の手順と方策勾配法でよく使われる主要なライブラリを紹介します。
Python環境の準備
Pythonのバージョンは3.7以上を推奨します。Anacondaなどのディストリビューションを使うと、パッケージ管理が容易になり、環境構築が簡単です。もしまだインストールされていなければ、公式サイトからインストールしてください。
必要なライブラリ
方策勾配法の実装では主に以下のライブラリを使います:
- NumPy:数値計算の基盤ライブラリ。行列演算や乱数生成に利用。
- Matplotlib:結果の可視化に便利なグラフ描画ライブラリ。
- Gym:強化学習の環境を提供するライブラリ。実際の方策勾配法の学習環境として使います。
これらはpipで簡単にインストール可能です。以下のコマンドを実行してください。
pip install numpy matplotlib gym
方策勾配法の基本数式とPythonでの乱数生成例
方策勾配法は、方策パラメータ \(\theta\) を更新するために以下の式を用います:
\[
\theta \leftarrow \theta + \alpha \nabla_\theta J(\theta)
\]
ここで、\(\alpha\) は学習率、\(\nabla_\theta J(\theta)\) は方策の性能指標の勾配です。この勾配をサンプリングした行動から推定します。
例えば、確率的な行動選択を表すためにPythonで乱数を生成するコードは以下の通りです:
import numpy as np
# 行動の確率分布(例として2つの行動)
action_probs = np.array([0.7, 0.3])
# 行動をサンプリング
action = np.random.choice([0, 1], p=action_probs)
print(f"選択された行動: {action}")
このようにして得られた行動を元に、方策のパラメータを更新していくのが方策勾配法の基本的な流れです。次章以降で詳しく解説します。
方策ネットワークの構築方法
方策勾配法における方策ネットワークは、エージェントの行動方策 \(\pi_\theta(a|s)\) をパラメータ \(\theta\) で表現するニューラルネットワークです。ここで、\(s\) は状態、\(a\) は行動を表します。方策ネットワークは、状態を入力として受け取り、各行動の確率分布を出力します。これにより、エージェントは確率的に行動を選択できるようになります。
具体的には、ネットワークの出力層にはソフトマックス関数を用いて、全行動の確率が正規化されるようにします。方策ネットワークの構築は以下のステップで進めます。
- 1. 入力層:環境の状態 \(s\) を表す特徴量を受け取る。
- 2. 隠れ層:複数の全結合層や活性化関数(例:ReLU)で非線形な関係を学習。
- 3. 出力層:行動の数に対応するユニット数で、各行動のロジットを出力。
- 4. ソフトマックス関数を適用し、行動確率に変換。
数式で表すと、出力層のロジットを \(z_i\) とすると、行動 \(a_i\) の確率は次のようになります。
\[ \pi_\theta(a_i|s) = \frac{\exp(z_i)}{\sum_j \exp(z_j)} \]
この式は、各行動のスコアを指数関数で変換し、全ての行動スコアの合計で割ることで、確率分布を作り出しています。
Pythonの代表的な実装例を示します。ここではPyTorchを用いて、シンプルな全結合ネットワークを構築します。
import torch
import torch.nn as nn
import torch.nn.functional as F
class PolicyNetwork(nn.Module):
def __init__(self, state_dim, action_dim, hidden_dim=128):
super(PolicyNetwork, self).__init__()
self.fc1 = nn.Linear(state_dim, hidden_dim)
self.fc2 = nn.Linear(hidden_dim, action_dim)
def forward(self, x):
x = F.relu(self.fc1(x))
logits = self.fc2(x)
action_probs = F.softmax(logits, dim=-1)
return action_probs
上記のコードでは、入力の状態ベクトル \(x\) をまず隠れ層で活性化関数ReLUを通し、次に行動数分のロジットを出力しています。最後にソフトマックス関数で行動確率を計算し、これを返します。
このように、方策ネットワークは状態から直接行動の確率分布を学習するためのモデルであり、方策勾配法の基盤となります。初心者の方はまず、この基本構造を理解し、実際にコードを書いて動かしてみることをおすすめします。
方策勾配法のPythonコード解説
方策勾配法は、強化学習において直接行動の確率分布(方策)をパラメータ化し、報酬を最大化するようにパラメータを更新する手法です。ここでは、基本的な方策勾配法の数式とそれをPythonで実装する例を解説します。
まず、方策をパラメータ \(\theta\) で表し、状態 \(s\) における行動 \(a\) の確率を \(\pi_\theta(a|s)\) とします。方策勾配法では、期待累積報酬の勾配を以下の式で計算します。
\[
\nabla_\theta J(\theta) = \mathbb{E}_{\pi_\theta} \left[ \nabla_\theta \log \pi_\theta(a|s) \cdot G_t \right]
\]
ここで、\(G_t\) は時刻 \(t\) からの割引累積報酬を表し、方策のパラメータ \(\theta\) を更新するための勾配となります。
この式の意味は、「方策の対数確率の勾配に報酬を掛けたものを期待値で取る」ということです。これにより、良い行動(高い報酬を得た行動)をとる確率を増やす方向にパラメータを調整できます。
以下に、簡単なPythonコード例を示します。この例では、状態・行動空間が小さく、方策をソフトマックス関数でパラメータ化しています。
import numpy as np
def softmax(x):
e_x = np.exp(x - np.max(x))
return e_x / e_x.sum()
# 方策パラメータ初期化(状態数=1, 行動数=3)
theta = np.random.rand(3)
# 行動確率の計算
def policy(theta):
return softmax(theta)
# 行動のサンプリング
def sample_action(probs):
return np.random.choice(len(probs), p=probs)
# 割引累積報酬(例として単一報酬)
G_t = 1.0
# 方策の勾配計算と更新
probs = policy(theta)
action = sample_action(probs)
# 方策の対数確率の勾配(one-hotベクトルで表現)
grad_log_pi = -probs
grad_log_pi[action] += 1
# パラメータ更新
learning_rate = 0.1
theta += learning_rate * grad_log_pi * G_t
print("更新後のtheta:", theta)
このコードでは、まずソフトマックス関数で方策の確率を計算し、行動をサンプリングします。次に、選択した行動の対数確率の勾配を計算し、それを累積報酬で重み付けしてパラメータを更新しています。
初心者の方は、この基本形を理解し、環境や報酬の設計に応じて拡張していくことから始めると良いでしょう。実際の問題では、状態が複雑になったり、割引率やバッチ学習を用いたりと様々な工夫が必要ですが、本質的な考え方はここで示した方策勾配の原理に基づいています。
実装例:簡単な強化学習問題への適用
ここでは、方策勾配法を用いて単純な強化学習問題を解く例を示します。具体的には、1次元の状態空間で行動が2つある問題を考え、方策をパラメータ化して学習を進める方法を説明します。
まず、方策をパラメータ \(\theta\) を使って表現します。例えば、行動 \(a \in \{0,1\}\) の確率をシグモイド関数で表すと、
\[
\pi_\theta(a=1|s) = \sigma(\theta s) = \frac{1}{1 + e^{-\theta s}}
\]
となります。ここで、状態 \(s\) は環境から観測される数値です。
方策勾配法では、期待報酬を最大化するためにパラメータ \(\theta\) を更新します。更新式は以下のように表されます。
\[
\theta \leftarrow \theta + \alpha \cdot R \cdot \nabla_\theta \log \pi_\theta(a|s)
\]
ここで、\(\alpha\) は学習率、\(R\) はその行動によって得られた報酬です。この式は「行動の確率の対数の勾配に報酬を掛けてパラメータを更新する」という意味で、方策を良い方向に改善していきます。
次に、Pythonでの簡単な実装例を示します。このコードは1ステップの状態と行動、報酬からパラメータ更新を行います。
import numpy as np
def sigmoid(x):
return 1 / (1 + np.exp(-x))
def policy(s, theta):
return sigmoid(theta * s)
def update_theta(theta, s, a, r, alpha):
# 行動の確率
p = policy(s, theta)
# \(\nabla_\theta \log \pi_\theta(a|s)\) の計算
grad_logp = (a - p) * s
# パラメータ更新
theta += alpha * r * grad_logp
return theta
# パラメータ初期化
theta = 0.0
alpha = 0.1
# 状態、行動、報酬の例
s = 1.0
a = 1
r = 1.0
# パラメータ更新
theta = update_theta(theta, s, a, r, alpha)
print("Updated theta:", theta)
この例では、状態 \(s\) と行動 \(a\)、報酬 \(r\) に対して方策のパラメータ \(\theta\) を更新しています。行動の確率はシグモイド関数で計算し、その対数の勾配を使って報酬に応じたパラメータ調整を行います。
このように、方策勾配法は数式とシンプルなコードで直感的に理解でき、様々な強化学習問題に応用可能です。初心者の方はまず単純な例から試し、徐々に複雑な方策や状態空間に挑戦してみてください。
方策勾配法の収束性と安定性
方策勾配法は強化学習において、方策のパラメータを直接最適化する手法であり、その収束性と安定性は実用上非常に重要なポイントです。初心者の方にわかりやすく説明すると、収束性とは「学習が進むにつれて方策が安定し、最適な行動選択に近づくこと」を指します。一方、安定性は「学習中に方策の変動が大きすぎず、学習が暴走しないこと」を意味します。
方策勾配法の代表的な更新式は以下のように表されます。
式:
\[
\theta_{t+1} = \theta_t + \alpha \nabla_\theta J(\theta_t)
\]
ここで、\(\theta_t\)は時刻tにおける方策のパラメータ、\(\alpha\)は学習率、\(\nabla_\theta J(\theta_t)\)は方策のパフォーマンス指標J(\theta)の勾配です。
この式の解釈は「現在のパラメータに対して、パフォーマンスが良くなる方向へ少しずつ調整を加える」というものです。勾配の計算には、実際に環境から得られた報酬を用いるため、ノイズが多く含まれます。これが収束性や安定性に影響を与えます。
実際のPythonコード例を示します。ここでは、簡単な方策勾配の更新ステップを模擬的に実装しています。
import numpy as np
def policy_gradient_update(theta, grad, alpha=0.01):
"""
方策勾配の更新
theta: 現在のパラメータ(numpy配列)
grad: パフォーマンス関数の勾配(numpy配列)
alpha: 学習率(float)
"""
return theta + alpha * grad
# 例: パラメータ初期値と勾配
theta = np.array([0.5, -0.3])
grad = np.array([0.1, 0.05])
# 更新
theta_new = policy_gradient_update(theta, grad)
print("更新後のパラメータ:", theta_new)
このように、方策勾配法は勾配に基づいてパラメータを更新しますが、収束性を高めるためには以下の点に注意が必要です。
- 学習率の適切な設定:大きすぎると発散しやすく、小さすぎると収束が遅くなります。
- 勾配の分散を抑える方法の導入:例えば、ベースラインを使ったり、ミニバッチ学習を行うことで安定化が図れます。
- 方策の表現力の適切さ:パラメータ空間が複雑すぎると、局所解に陥りやすくなります。
まとめると、方策勾配法は理論的にも実務的にも収束性と安定性が保証されるわけではありませんが、適切な設計と調整を行うことで、効果的に強化学習問題を解くことが可能です。初心者の方は、まずは小さな学習率から試し、徐々にパラメータを調整しながら学習の様子を観察することをおすすめします。
方策勾配法のメリットとデメリット
方策勾配法は強化学習における代表的な手法の一つであり、直接的に方策(policy)をパラメータ化して最適化を行います。ここでは初心者の方にも分かりやすく、方策勾配法のメリットとデメリットを整理しながら、数式とPythonコード例を交えて解説します。
メリット
- 連続空間でも扱いやすい:方策勾配法は確率的な方策を直接最適化するため、離散的な選択肢だけでなく、連続的な行動空間に対しても自然に対応できます。
- 方策の表現が柔軟:ニューラルネットワークなどの関数近似器と組み合わせることで複雑な方策を表現可能です。
- モーダルな最適解を探索しやすい:価値関数を介さず直接方策を更新するため、多峰性の問題でも他の手法に比べて解の多様性を保ちやすい傾向があります。
デメリット
- 高い分散による学習の不安定さ:方策の勾配推定はサンプルのばらつきが大きいため、学習が収束しにくいことがあります。
- 学習効率がやや低い:価値関数を使った手法に比べて、必要なサンプル数が多くなることが一般的です。
- ハイパーパラメータの調整が必要:学習率やバッチサイズなどの設定が性能に大きく影響します。
方策勾配の基本的な数式とPython実装例
方策勾配法の核となるのは、方策のパラメータ \(\theta\) に関する勾配を計算し、それを用いてパラメータを更新することです。勾配は以下のように表されます。
\[
\nabla_\theta J(\theta) = \mathbb{E}_{\tau \sim \pi_\theta} \left[ \sum_{t=0}^T \nabla_\theta \log \pi_\theta(a_t | s_t) \, R(\tau) \right]
\]
ここで、\( \pi_\theta(a_t | s_t) \) は状態 \(s_t\) における行動 \(a_t\) の確率、\(R(\tau)\) は軌跡 \(\tau\) における累積報酬です。この勾配を用いてパラメータを次のように更新します。
\[
\theta \leftarrow \theta + \alpha \, \nabla_\theta J(\theta)
\]
Pythonでの簡単な勾配計算のイメージは以下の通りです。
import numpy as np
# 仮の方策確率と報酬の例
log_probs = np.array([-0.2, -0.1, -0.3]) # \log \pi_\theta(a_t|s_t)
rewards = np.array([1.0, 0.5, 2.0]) # R(\tau)
# 方策勾配の推定(モンテカルロ法)
policy_gradient = np.sum(log_probs * rewards)
# 学習率
alpha = 0.01
# パラメータ更新(例)
theta = 0.5
theta += alpha * policy_gradient
print(f"Updated theta: {theta:.4f}")
このように方策勾配法はシンプルな数式から始まり、実装も直感的ですが、分散の大きさやサンプル効率の問題を理解しながら使うことが重要です。
方策勾配法と他の強化学習手法の比較
強化学習にはさまざまな手法がありますが、特に「方策勾配法」は価値ベースの手法(例:Q学習)やモデルベースの手法と比べて特徴的な利点があります。ここでは、方策勾配法が他の強化学習手法とどう異なるのかを初心者向けにわかりやすく解説します。
- 価値ベース手法との違い
価値ベース手法は、状態価値関数や行動価値関数を学習し、その最大値をもとに行動を決定します。代表的なものにQ学習があります。一方、方策勾配法は直接「方策(policy)」、つまり行動選択の確率分布をパラメータ化し、そのパラメータを最適化します。この違いにより、方策勾配法は連続的な行動空間や確率的な方策を扱いやすいというメリットがあります。 - モデルベース手法との違い
モデルベース手法は環境の動的モデルを学習し、そのモデルを使って最適な行動を計画します。一方、方策勾配法は環境モデルを必要とせず、直接経験から方策を改善します。これにより、モデルの不確実性が高い環境でも安定して学習しやすいという特徴があります。 - 方策勾配法の数学的特徴
方策勾配法はパラメータ \(\theta\) で表される方策 \(\pi_\theta(a|s)\) の性能指標 \(J(\theta)\) を最大化するため、勾配上昇法を用います。一般的な方策勾配の式は次のようになります:
\[
\nabla_\theta J(\theta) = \mathbb{E}_{s \sim d^\pi, a \sim \pi_\theta} \left[ \nabla_\theta \log \pi_\theta(a|s) Q^\pi(s,a) \right]
\]
ここで、\(d^\pi\) は方策 \(\pi\) に従った状態の分布、\(Q^\pi(s,a)\) は状態\(s\)で行動\(a\)を取ったときの期待収益を表します。直感的には「行動選択の確率を増やす方向にパラメータを更新する」ことを意味します。
例えば、Pythonで簡単に方策勾配の更新を行うコードは以下のようになります。
import numpy as np
def policy_gradient_update(theta, states, actions, Q_values, learning_rate=0.01):
for s, a, q in zip(states, actions, Q_values):
# ログ確率の勾配の計算(ここでは簡略化)
grad_log_pi = compute_grad_log_policy(theta, s, a)
# パラメータ更新
theta += learning_rate * grad_log_pi * q
return theta
def compute_grad_log_policy(theta, state, action):
# 例:線形ソフトマックス方策の勾配計算(擬似コード)
# 実際は方策の形に応じて実装が必要
return np.random.randn(*theta.shape) # ダミーの勾配
このように、方策勾配法は方策のパラメータを直接更新するため、方策の表現力が高く、探索と利用の両立がしやすい点が特徴です。初心者でも数式の直感的な意味を理解しやすいため、強化学習の基礎を学ぶ上で非常に有用な手法と言えます。
方策勾配法の応用例
方策勾配法は強化学習の中でも特に応用範囲が広く、ロボット制御やゲームAI、さらには広告最適化や金融取引などの分野で利用されています。ここでは、より具体的にどのようなケースで方策勾配法が役立つかを初心者向けに解説します。
1. ゲームAIにおける方策勾配法
例えば、囲碁や将棋のような複雑なゲームにおいて、方策勾配法は「どの手を打つべきか」という方策を直接学習します。従来の価値関数ベースの方法と異なり、方策勾配法は確率的に行動を選択するため、探索の多様性が保たれやすい特徴があります。
方策勾配法の基本的な更新式は以下のように表されます。
式:
\[
\nabla_{\theta}J(\theta) = \mathbb{E}_{\tau \sim \pi_{\theta}} \left[ \sum_{t=0}^{T} \nabla_{\theta} \log \pi_{\theta}(a_t|s_t) R(\tau) \right]
\]
解釈:この式は、パラメータ \(\theta\) を持つ方策 \(\pi_{\theta}\) の性能指標 \(J(\theta)\) の勾配を計算しています。軌跡 \(\tau\) は状態と行動の系列で、報酬 \(R(\tau)\) を最大化するように方策を更新します。
Pythonでの簡単な実装例を示します。
import numpy as np
def policy_gradient_update(theta, states, actions, rewards, learning_rate):
for s, a, r in zip(states, actions, rewards):
grad_log_policy = compute_grad_log_policy(s, a, theta) # 方策の勾配を計算
theta += learning_rate * grad_log_policy * r
return theta
def compute_grad_log_policy(state, action, theta):
# ここでは単純なソフトマックス方策の勾配を仮定
logits = np.dot(state, theta)
probs = np.exp(logits) / np.sum(np.exp(logits))
grad = -probs
grad[action] += 1
return grad[:, np.newaxis] * state[np.newaxis, :]
2. 広告最適化での活用
オンライン広告のクリック率を最大化するために、ユーザーの行動に応じて広告表示の方策をリアルタイムで改善する場合にも方策勾配法が有効です。ここでの「方策」はどの広告を表示するかの確率分布を意味し、報酬はクリックや購入といった成果に対応します。
このように、方策勾配法は「直接的に方策を最適化する」特徴を活かして、連続的に変わる環境に柔軟に対応できる点が強みです。
学習効率を高めるテクニック
方策勾配法は強化学習の中でも直感的かつ強力な手法ですが、実際に効率よく学習を進めるためにはいくつかの工夫が必要です。ここでは、初心者の方にも分かりやすく、学習効率を向上させる代表的なテクニックを紹介します。
1. 割引率γの適切な設定
方策勾配法において、将来の報酬の重要度を決める割引率 \( \gamma \) は非常に大切です。割引率は0から1の間で設定し、値が大きいほど長期的な報酬を重視します。例えば、\(\gamma = 0.99\) はほぼ将来の報酬も評価対象に含める設定です。逆に、\(\gamma\) が小さいと即時の報酬に集中します。
割引率はタスクの性質によって最適な値が変わるため、適切に調整することで学習の安定性と効率が向上します。
2. バッチ学習とミニバッチの活用
方策勾配法はサンプルに依存するため、1回の更新で複数のエピソードやステップから得られたデータを使うバッチ学習が効果的です。データ量が多いほど勾配の推定が安定し、学習がスムーズになります。
3. 方策勾配の計算例と実装
方策勾配法の基本的な勾配計算は、期待報酬を最大化するために方策パラメータ \( \theta \) を更新することです。方策の確率分布を \( \pi_\theta(a|s) \)、状態価値関数を \( Q^\pi(s,a) \) とすると、勾配は次のように表されます。
\[
\nabla_\theta J(\theta) = \mathbb{E}_{\pi_\theta} \left[ \nabla_\theta \log \pi_\theta(a|s) Q^\pi(s,a) \right]
\]
この式は「方策の対数確率の勾配」に「行動価値」を掛けたものの期待値として理解できます。実装例は以下の通りです。
import numpy as np
def policy_gradient_update(states, actions, rewards, policy, optimizer):
discounted_rewards = discount_rewards(rewards, gamma=0.99)
for state, action, Gt in zip(states, actions, discounted_rewards):
log_prob = np.log(policy(state)[action])
gradient = log_prob * Gt
optimizer.step(gradient)
ここで、discount_rewardsは報酬を割引率を用いて計算し、policy(state)は状態に対する行動確率分布を返します。このように、数式の理解からコード実装まで一連の流れを押さえることで、学習効率を高めるための工夫がより明確になります。
4. バリアンスの低減
方策勾配法はサンプルのばらつき(バリアンス)が大きいことが課題です。これを減らすために、ベースライン(通常は状態価値関数)を導入して以下のように修正します。
\[
\nabla_\theta J(\theta) = \mathbb{E}_{\pi_\theta} \left[ \nabla_\theta \log \pi_\theta(a|s) \left( Q^\pi(s,a) – b(s) \right) \right]
\]
このベースラインにより、勾配のばらつきが減り、より安定した学習が可能です。初心者の方はまずベースラインなしで実装し、慣れてきたら導入を検討すると良いでしょう。
よくあるエラーと対処法
方策勾配法を実装していると、初心者の方がよく直面するエラーがいくつかあります。ここでは代表的な問題とその対処法を、数式とPythonコードを交えて解説します。
1. 勾配の計算ミスによる学習の停止
方策勾配法の基本は、方策パラメータ \(\theta\) の更新式にあります。一般的な更新式は以下のように表されます。
\[
\theta \leftarrow \theta + \alpha \nabla_\theta J(\theta)
\]
ここで、勾配 \(\nabla_\theta J(\theta)\) は、実際には期待報酬を最大化するために以下の式で計算されます。
\[
\nabla_\theta J(\theta) = \mathbb{E}_{\tau \sim \pi_\theta} \left[ \sum_{t=0}^T \nabla_\theta \log \pi_\theta(a_t | s_t) G_t \right]
\]
この勾配計算を間違えると、学習が進まなかったり、値が発散したりします。特に、logの計算や報酬の扱いに注意が必要です。
以下はPythonでの正しい勾配部分の実装例です。
import numpy as np
def compute_policy_gradient(log_probs, rewards, gamma=0.99):
discounted_rewards = []
cumulative = 0
for r in reversed(rewards):
cumulative = r + gamma * cumulative
discounted_rewards.insert(0, cumulative)
discounted_rewards = np.array(discounted_rewards)
discounted_rewards = (discounted_rewards - discounted_rewards.mean()) / (discounted_rewards.std() + 1e-8)
policy_gradient = []
for log_prob, Gt in zip(log_probs, discounted_rewards):
policy_gradient.append(-log_prob * Gt)
return np.sum(policy_gradient)
このコードは、報酬を割引計算し標準化したうえで、\(\log \pi_\theta(a_t|s_t)\) と掛け合わせ、全ステップの勾配を合計しています。
もし勾配が常にゼロや非常に大きな値になる場合は、報酬の割引計算や標準化の部分を疑いましょう。
2. 方策の確率がゼロまたは不正な値になる問題
方策関数 \(\pi_\theta(a|s)\) は確率なので、必ず \(0 \leq \pi_\theta(a|s) \leq 1\) を満たし、全アクションで和が1になる必要があります。
ニューラルネットワークなどで方策を出力するときは、出力層に softmax 関数を用いないと、確率が正しく計算されません。
例えば、PyTorchでのsoftmax適用例:
import torch
import torch.nn.functional as F
logits = torch.tensor([2.0, 1.0, 0.1])
probabilities = F.softmax(logits, dim=0)
print(probabilities)
これにより、出力はアクションの確率分布として正規化されます。
もし確率が0になったり負の値になる場合は、ネットワークの出力や活性化関数を見直しましょう。
まとめ
- 勾配計算は報酬の割引計算と標準化を正しく行うことが重要
- \(\log \pi_\theta(a|s)\) の計算ミスに注意し、勾配がゼロや発散しないか確認する
- 方策出力には必ず確率分布を保証する関数(softmaxなど)を用いる
これらのポイントを押さえれば、方策勾配法の実装でよくあるエラーを減らし、安定した学習が期待できます。
まとめ:方策勾配法の理解と実装のポイント
方策勾配法は、強化学習において直接方策のパラメータを最適化する手法であり、環境の報酬構造を効率的に活かすことができます。初心者にとっては数式やコードの理解が難しく感じられるかもしれませんが、基本的な考え方を押さえることで実装の自信につながります。
本記事で押さえておきたい方策勾配法のポイントは以下の通りです。
- 方策のパラメータ表現:方策はパラメータ \(\theta\) を持つ確率分布として定義され、行動を確率的に選択します。
- 方策勾配の計算:期待報酬を最大化するために、勾配上昇法でパラメータを更新します。代表的な更新式は次のようになります。
\[
\theta \leftarrow \theta + \alpha \nabla_\theta J(\theta)
\]
ここで、勾配は
\[
\nabla_\theta J(\theta) = \mathbb{E}_{\tau \sim \pi_\theta}\left[\sum_{t=0}^T \nabla_\theta \log \pi_\theta(a_t|s_t) R(\tau)\right]
\]
と表されます。 - 実装時の工夫:報酬の分散を減らすために、基準値(ベースライン)を使うことが一般的です。これにより学習が安定します。
具体的なPythonによる方策勾配法の実装例を以下に示します。ここでは、行動選択確率をソフトマックス関数で表し、報酬に基づく勾配上昇を行います。
import numpy as np
def softmax(x):
e_x = np.exp(x - np.max(x))
return e_x / e_x.sum()
# パラメータ初期化
theta = np.random.rand(2) # 例: 2つの行動パラメータ
alpha = 0.1 # 学習率
# 簡単な報酬例
reward = 1.0
state = None # 状態はここでは単純化
# 方策による行動確率計算
prob = softmax(theta)
# 行動サンプリング(例として行動0を選択)
action = 0
# 勾配計算:log方策の微分は one-hot ベクトルで表現可能
grad_log = -prob
grad_log[action] += 1
# パラメータ更新
theta += alpha * reward * grad_log
print("Updated theta:", theta)
このコードは、方策パラメータ \(\theta\) を報酬に基づき更新するシンプルな例です。実際の環境では状態やエピソードの取り扱いがより複雑になりますが、勾配の計算とパラメータ更新の基本構造は同じです。
まとめると、方策勾配法は「方策の確率的表現」「勾配の期待値の計算」「パラメータの勾配上昇更新」という3つの要素を理解することが鍵です。数式の意味を押さえつつ、実装例を通して動きを確認すれば、初学者でも理解しやすくなるでしょう。