アクタークリティック(actor‐critic) - Shinichi0713/RL-study GitHub Wiki
概要
アクター - クリティックは行動を選択するアクターと、アクターが選択くした行動を評価するクリティックで構成される強化学習のフレームワーク。
graph TD
A[アクターは方策πで行動を選択] --> B[環境からクリティックが観測]
B --> C[得られた状態、報酬を使ってアクターを評価]
C --> D[アクターが評価をもとに方策の更新]
D --> A
アクター
アクターは実際の行動を決定し実行するので、行動器とも呼ばれる。
実際に行動した結果に関しては、クリティックにより評価されます。
クリティックにより評価された結果(例:TD誤差)を使って、自らの行動の価値を修正します。
アクターが保持するもの
方策π(s, a) : 状態sにおいて、行動aを選択する確率
行動優先度p(s, a) : 行動優先を行う度数
π(s,a)=e^{p(s,a)}∑_{b∈A}e^{p(s,b)}
行動優先度の更新方法はクリティックより得られるTD誤差を用いて更新する方法。
基本的には良い報酬が得られるように行動を多くとるような行動優先度を修正していく。
数式で更新式を表現する場合は以下。
p(s, a) ← p(s, a) + βδ
β: 学習率。どの程度TD誤差を反映するかを決定するパラメータ
p(s,a)←p(s,a)+βδ(1−π(s,a))
クリティック(critic)
クリティックとは評価器と呼ばれる。
アクターを批評する役割を持つ。
シンプルなクリティックは以下のように記載される。
δ←r+γV(s′)–V(s)
V(s)は得られた報酬rにより更新する。
import gym
import torch
import torch.nn as nn
import torch.optim as optim
import numpy as np
# Actor-Critic ネットワーク
class ActorCritic(nn.Module):
def __init__(self, state_dim, action_dim):
super(ActorCritic, self).__init__()
self.actor = nn.Sequential(
nn.Linear(state_dim, 128),
nn.ReLU(),
nn.Linear(128, action_dim),
nn.Softmax(dim=-1)
)
self.critic = nn.Sequential(
nn.Linear(state_dim, 128),
nn.ReLU(),
nn.Linear(128, 1)
)
def forward(self, x):
action_probs = self.actor(x)
state_value = self.critic(x)
return action_probs, state_value
# 環境の設定
env = gym.make('CartPole-v1')
state_dim = env.observation_space.shape[0]
action_dim = env.action_space.n
# ハイパーパラメータ
learning_rate = 0.01
gamma = 0.99
# モデル、オプティマイザ、損失関数の設定
model = ActorCritic(state_dim, action_dim)
optimizer = optim.Adam(model.parameters(), lr=learning_rate)
# トレーニングループ
for episode in range(1000):
state = env.reset()
log_probs = []
rewards = []
values = []
done = False
while not done:
state = torch.FloatTensor(state).unsqueeze(0)
action_probs, state_value = model(state)
action_dist = torch.distributions.Categorical(action_probs)
action = action_dist.sample()
log_probs.append(action_dist.log_prob(action))
values.append(state_value)
next_state, reward, done, _ = env.step(action.item())
rewards.append(reward)
state = next_state
if done:
Qval = 0
values.append(torch.FloatTensor([0]))
# 報酬の計算
Qvals = []
for r in reversed(rewards):
Qval = r + gamma * Qval
Qvals.insert(0, Qval)
# 損失の計算とパラメータの更新
Qvals = torch.FloatTensor(Qvals)
values = torch.cat(values)
log_probs = torch.cat(log_probs)
advantage = Qvals - values[:-1]
actor_loss = -(log_probs * advantage.detach()).mean()
critic_loss = advantage.pow(2).mean()
loss = actor_loss + critic_loss
optimizer.zero_grad()
loss.backward()
optimizer.step()
break
if episode % 100 == 0:
print(f'Episode {episode}, Loss: {loss.item()}')
env.close()
Actor-Criticアルゴリズムの仕組み
2.1 Actor(行動決定)の役割
Actorは、与えられた状態 $s$ に対して、どの行動 $a$ を取るかの確率分布 $π(a∣s)\pi(a|s)$ を出力します。 この出力は、エージェントが環境内での行動を選択する際の戦略となります。
Actorは、試行錯誤を通じて、最も有望な行動を選ぶための方策更新を行います。
2.2 Critic(評価)の役割
Criticは、各状態 $s$ と行動 $a$ に対する価値を評価し、通常は行動価値関数 $Q(s, a)$ や状態価値関数 $V(s)$ の推定値を算出します。 Criticの評価に基づいて、Actorは自身の方策を改善するためのフィードバックを受け取ります。
このプロセスにより、Criticは環境から得られる実際の報酬と予測値との差(TD誤差)を計算し、その結果を用いて行動価値関数の更新や、Actorの方策の改善を行います。
2.3 学習の流れ
Actor-Criticアルゴリズムは、エピソードごとまたはステップごとに以下のプロセスを繰り返します。
状態の観測 エージェントが環境から現在の状態 $s$ を観測します。
行動の選択 Actorが状態 $s$ に基づいて、行動 $a$ の確率分布 $\pi(a|s)$ を出力し、その中から行動を選択します。
環境との相互作用 選択した行動 $a$ を環境に適用し、報酬 $r$ と次の状態 $s'$ を観測します。
価値の評価 Criticが現在の状態 $s$ と行動 $a$ に対する行動価値 $Q(s, a)$ を推定し、TD誤差を計算します。
パラメータ更新 Actorは、TD誤差に基づいて方策パラメータを更新し、Criticは、価値関数を更新します。
この一連の学習プロセスを通じて、エージェントはより良い行動を選択するための最適なポリシーを獲得していきます。
Actor-Criticの効果
メリット
学習の安定化
REINFORCEでは価値関数を実際の報酬の平均で近似し, 特に学習を行うことはありませんでした. 一方, 行動を決めるActor(行動器)を直接改善しながら, 方策を評価するCritic(評価器)も同時に学習させるのが, Actor-Criticのアプローチです. 一般に, Actor-Criticを用いると報酬のブレに惑わされにくくなり, 学習を安定して速くすることができます.
探索と活用のバランス改善
Criticの評価をもとにActorが方策を更新するため、探索と活用のトレードオフが適切に処理され、より効率的な学習が可能です。
柔軟なアルゴリズム設計
複数のバリエーション(A2C、A3C、DDPG、PPOなど)が存在し、環境やタスクに応じた最適な手法を選択できます。
デメリット
計算コストの高さ
特にA3Cのような非同期学習では、複数のエージェントを同時に実行するため、計算資源が大量に必要になることがあります。
最適化の難しさ
方策と価値関数の同時学習は、ハイパーパラメータの調整が複雑になりがちで、学習が不安定になる場合もあります。
環境依存性
連続状態・行動空間を扱う場合や、報酬がスパースな環境では、十分な探索が難しくなる可能性があり、アルゴリズムのパフォーマンスが低下することがあります。