- Authors

- Name
- Youngju Kim
- @fjvbn20031
概要
このシリーズで多様な深層強化学習アルゴリズムを見てきました。最後の記事では、すべての手法を体系的に整理し、どのような状況でどのアルゴリズムを選択すべきかのガイドを提供します。また現在活発に研究されている最新分野と学習リソースも紹介します。
アルゴリズム分類体系
全体の分類図
深層強化学習アルゴリズムは大きく4つの軸で分類できます:
1. 価値ベース(Value-Based)
- 状態または行動の価値を学習
- 価値から方策を導出(通常は貪欲選択)
- 代表:DQN、Double DQN、Dueling DQN、Rainbow
2. 方策ベース(Policy-Based)
- 方策を直接パラメータ化して学習
- REINFORCE、進化戦略、遺伝的アルゴリズム
3. Actor-Critic
- 方策(Actor)と価値(Critic)を同時に学習
- A2C、A3C、PPO、TRPO、ACKTR、DDPG、SAC
4. モデルベース(Model-Based)
- 環境モデルを学習して計画に活用
- I2A、World Models、Dreamer、MuZero
価値ベース手法の整理
DQN系列
# DQN系列アルゴリズムの核心的な違いを示す疑似コード
def dqn_target(reward, next_state, done, gamma, q_network, target_network):
"""基本DQN:ターゲットネットワークで最大Q値を計算"""
with torch.no_grad():
max_q = target_network(next_state).max(dim=-1)[0]
target = reward + gamma * (1 - done) * max_q
return target
def double_dqn_target(reward, next_state, done, gamma,
q_network, target_network):
"""Double DQN:行動選択と評価を分離"""
with torch.no_grad():
# メインネットワークで行動選択
best_actions = q_network(next_state).argmax(dim=-1)
# ターゲットネットワークで価値評価
q_values = target_network(next_state)
max_q = q_values.gather(1, best_actions.unsqueeze(1)).squeeze()
target = reward + gamma * (1 - done) * max_q
return target
def dueling_network_forward(features, advantage_stream, value_stream):
"""Dueling DQN:価値とアドバンテージを分離"""
value = value_stream(features) # V(s)
advantage = advantage_stream(features) # A(s,a)
# Q(s,a) = V(s) + A(s,a) - mean(A)
q_values = value + advantage - advantage.mean(dim=-1, keepdim=True)
return q_values
価値ベース手法の比較
| アルゴリズム | 核心改善 | 離散/連続 | 主な長所 |
|---|---|---|---|
| DQN | 経験リプレイ + ターゲットネットワーク | 離散 | 安定した学習 |
| Double DQN | 過大推定バイアスの低減 | 離散 | 正確なQ値 |
| Dueling DQN | VとAの分離 | 離散 | 状態価値学習の効率 |
| Prioritized ER | 重要経験の優先学習 | 離散 | サンプル効率 |
| Noisy DQN | パラメータノイズ探索 | 離散 | 適応的探索 |
| Categorical DQN | リターン分布の学習 | 離散 | 安定性、豊富な信号 |
| Rainbow | 上記すべての技法の統合 | 離散 | 最高性能 |
方策ベース手法の整理
REINFORCEと変形
import torch
def reinforce_loss(log_probs, returns):
"""基本REINFORCE:高分散"""
return -(log_probs * returns).mean()
def reinforce_with_baseline(log_probs, returns, values):
"""ベースラインREINFORCE:分散低減"""
advantages = returns - values.detach()
policy_loss = -(log_probs * advantages).mean()
value_loss = (returns - values).pow(2).mean()
return policy_loss + 0.5 * value_loss
def ppo_clipped_loss(log_probs, old_log_probs, advantages,
clip_epsilon=0.2):
"""PPO:安定した方策更新"""
ratio = torch.exp(log_probs - old_log_probs)
surr1 = ratio * advantages
surr2 = torch.clamp(ratio, 1 - clip_epsilon,
1 + clip_epsilon) * advantages
return -torch.min(surr1, surr2).mean()
Actor-Critic手法の整理
On-Policy vs Off-Policy
| 属性 | On-Policy | Off-Policy |
|---|---|---|
| データ使用 | 現在の方策からのみ収集 | 過去データの再利用が可能 |
| サンプル効率 | 低い | 高い |
| 安定性 | 高い | 比較的低い |
| 代表アルゴリズム | A2C, PPO, TRPO | DDPG, SAC, TD3 |
SAC(Soft Actor-Critic)
SACはエントロピーを最大化して探索と活用を自動的にバランスするアルゴリズムです:
import torch
import torch.nn as nn
import copy
class SACAgent:
"""SAC:最大エントロピー強化学習"""
def __init__(self, obs_size, act_size, hidden=256,
lr=3e-4, gamma=0.99, tau=0.005):
self.gamma = gamma
self.tau = tau
self.q1 = self._make_q(obs_size, act_size, hidden)
self.q2 = self._make_q(obs_size, act_size, hidden)
self.q1_target = copy.deepcopy(self.q1)
self.q2_target = copy.deepcopy(self.q2)
self.actor = self._make_actor(obs_size, act_size, hidden)
self.log_alpha = torch.zeros(1, requires_grad=True)
self.target_entropy = -act_size
self.q1_opt = torch.optim.Adam(self.q1.parameters(), lr=lr)
self.q2_opt = torch.optim.Adam(self.q2.parameters(), lr=lr)
self.actor_opt = torch.optim.Adam(self.actor.parameters(), lr=lr)
self.alpha_opt = torch.optim.Adam([self.log_alpha], lr=lr)
def _make_q(self, obs_size, act_size, hidden):
return nn.Sequential(
nn.Linear(obs_size + act_size, hidden), nn.ReLU(),
nn.Linear(hidden, hidden), nn.ReLU(),
nn.Linear(hidden, 1),
)
def _make_actor(self, obs_size, act_size, hidden):
return GaussianActor(obs_size, act_size, hidden)
@property
def alpha(self):
return self.log_alpha.exp()
def update(self, batch):
states, actions, rewards, next_states, dones = batch
with torch.no_grad():
next_actions, next_log_probs = self.actor.sample(next_states)
q1_next = self.q1_target(torch.cat([next_states, next_actions], -1))
q2_next = self.q2_target(torch.cat([next_states, next_actions], -1))
q_next = torch.min(q1_next, q2_next)
target = rewards + self.gamma * (1 - dones) * (
q_next - self.alpha * next_log_probs
)
q1_val = self.q1(torch.cat([states, actions], -1))
q2_val = self.q2(torch.cat([states, actions], -1))
q1_loss = (q1_val - target).pow(2).mean()
q2_loss = (q2_val - target).pow(2).mean()
self.q1_opt.zero_grad(); q1_loss.backward(); self.q1_opt.step()
self.q2_opt.zero_grad(); q2_loss.backward(); self.q2_opt.step()
new_actions, log_probs = self.actor.sample(states)
q1_new = self.q1(torch.cat([states, new_actions], -1))
q2_new = self.q2(torch.cat([states, new_actions], -1))
q_new = torch.min(q1_new, q2_new)
actor_loss = (self.alpha.detach() * log_probs - q_new).mean()
self.actor_opt.zero_grad(); actor_loss.backward(); self.actor_opt.step()
alpha_loss = -(self.log_alpha * (log_probs.detach() + self.target_entropy)).mean()
self.alpha_opt.zero_grad(); alpha_loss.backward(); self.alpha_opt.step()
self._soft_update(self.q1, self.q1_target)
self._soft_update(self.q2, self.q2_target)
def _soft_update(self, source, target):
for s, t in zip(source.parameters(), target.parameters()):
t.data.copy_(self.tau * s.data + (1 - self.tau) * t.data)
class GaussianActor(nn.Module):
def __init__(self, obs_size, act_size, hidden):
super().__init__()
self.net = nn.Sequential(
nn.Linear(obs_size, hidden), nn.ReLU(),
nn.Linear(hidden, hidden), nn.ReLU(),
)
self.mu = nn.Linear(hidden, act_size)
self.log_std = nn.Linear(hidden, act_size)
def forward(self, obs):
features = self.net(obs)
return self.mu(features), self.log_std(features).clamp(-20, 2)
def sample(self, obs):
mu, log_std = self.forward(obs)
std = log_std.exp()
dist = torch.distributions.Normal(mu, std)
z = dist.rsample()
action = torch.tanh(z)
log_prob = (dist.log_prob(z) - torch.log(1 - action.pow(2) + 1e-6)).sum(dim=-1, keepdim=True)
return action, log_prob
総合比較表
アルゴリズム選択ガイド
| 状況 | 推奨アルゴリズム | 理由 |
|---|---|---|
| 離散行動、オフラインデータあり | DQN/Rainbow | リプレイバッファ活用 |
| 離散行動、高速プロトタイピング | A2C | 実装簡単、高速実験 |
| 連続行動、安定性重視 | PPO | 実装簡単で安定的 |
| 連続行動、サンプル効率重視 | SAC | Off-policy + 自動探索 |
| 連続行動、決定的方策が必要 | DDPG/TD3 | 決定的方策 |
| ボードゲーム | AlphaZero | MCTS + 自己対局 |
| 微分不可の報酬 | ES/GA | 勾配不要 |
| シミュレータあり、サンプル制限 | Dreamer/MuZero | モデルベースの効率性 |
ハイパーパラメータ感度
# 各アルゴリズムの主要ハイパーパラメータと一般的な値
hyperparams = {
'DQN': {
'lr': 1e-4,
'batch_size': 32,
'buffer_size': 1000000,
'target_update_freq': 1000,
'epsilon_decay': 'linear to 0.01 over 1M steps',
'sensitivity': 'medium',
},
'PPO': {
'lr': 3e-4,
'clip_epsilon': 0.2,
'num_epochs': 10,
'batch_size': 64,
'gae_lambda': 0.95,
'entropy_coef': 0.01,
'sensitivity': 'low',
},
'SAC': {
'lr': 3e-4,
'batch_size': 256,
'buffer_size': 1000000,
'tau': 0.005,
'auto_alpha': True,
'sensitivity': 'low',
},
'DDPG': {
'lr_actor': 1e-4,
'lr_critic': 1e-3,
'batch_size': 256,
'tau': 0.005,
'noise_type': 'OU or Gaussian',
'sensitivity': 'high',
},
}
現在の研究最前線
オフラインRL(バッチ強化学習)
事前に収集された固定データセットのみで学習する方法。追加の環境相互作用なしに既存データを最大限活用します。
class ConservativeQLearning:
"""CQL:保守的Q学習の核心アイデア"""
def compute_cql_loss(self, q_network, states, actions, alpha=1.0):
td_loss = self.compute_td_loss(q_network, states, actions)
random_actions = torch.rand_like(actions) * 2 - 1
random_q = q_network(states, random_actions)
data_q = q_network(states, actions)
cql_penalty = (
torch.logsumexp(random_q, dim=0).mean() - data_q.mean()
)
return td_loss + alpha * cql_penalty
核心アルゴリズム:CQL、IQL、Decision Transformer、Diffusion Policy
マルチエージェントRL(多重エージェント)
複数のエージェントが同時に学習する環境:
- 協力(Cooperative):チームメイトが共通目標を追求
- 競争(Competitive):エージェント間の競争
- 混合(Mixed):協力と競争が混在
核心課題:非定常性(non-stationarity)、通信、クレジット割当
安全なRL(Safe RL)
報酬最大化と同時に安全制約を満たす方法:
class SafeRLObjective:
"""制約ベースの安全強化学習の目的"""
def compute_objective(self, policy, states):
expected_reward = self.estimate_reward(policy, states)
expected_cost = self.estimate_cost(policy, states)
cost_limit = 25.0
lagrangian = (expected_reward
- self.lambda_multiplier
* (expected_cost - cost_limit))
return lagrangian
核心アルゴリズム:CPO(Constrained Policy Optimization)、WCSAC、SafeOpt
その他の研究方向
- メタ強化学習(Meta-RL):新しいタスクに素早く適応するエージェント
- 階層的強化学習(Hierarchical RL):高レベル/低レベルの方策を分離して長期計画を立てる
- 表現学習:良い状態表現を自動的に学習
- 大規模言語モデル + RL:LLMの推論能力をRLに活用
学習ロードマップ
推奨学習順序
-
基礎(1〜2週間)
- MDP、ベルマン方程式の理解
- 動的プログラミング(方策/価値反復)
- 探索と活用のジレンマ
-
価値ベース(2〜3週間)
- Q-learningの実装
- DQNの実装とAtari実験
- Double/Dueling DQNの理解
-
方策ベース(2〜3週間)
- REINFORCEの実装
- A2C/A3Cの理解と実装
- PPOの実装(最も重要)
-
連続行動(1〜2週間)
- DDPGの実装
- SACの実装
- MuJoCo/PyBullet実験
-
発展(2〜4週間)
- モデルベースRL(Dreamer)
- マルチエージェントRL
- オフラインRL
- 実践プロジェクト
核心実装フレームワーク
# 主要RLライブラリ
# 1. Stable-Baselines3: 検証済み実装、高速実験
# pip install stable-baselines3
from stable_baselines3 import PPO, SAC, DQN
model = PPO("MlpPolicy", "CartPole-v1", verbose=1)
model.learn(total_timesteps=100000)
# 2. CleanRL: 単一ファイル実装、教育用に最高
# 各アルゴリズムが1つのファイルに完全実装
# 3. RLlib (Ray): 分散学習、プロダクションレベル
# pip install ray[rllib]
# 4. Tianshou: PyTorchベース、柔軟な構造
# pip install tianshou
シリーズ回顧
このシリーズで扱った内容を時系列で整理すると:
| 記事番号 | テーマ | 核心アルゴリズム/概念 |
|---|---|---|
| 11 | A3C | 非同期並列学習、データ/勾配並列化 |
| 12 | チャットボットRL | Seq2Seq、SCST、報酬設計 |
| 13 | ウェブナビゲーション | MiniWoB、グリッド行動空間、人間のデモンストレーション |
| 14 | 連続行動 | DDPG、OUノイズ、分布方策(D4PG) |
| 15 | Trust Region | PPO、TRPO、ACKTR |
| 16 | Black-Box | 進化戦略(ES)、遺伝的アルゴリズム(GA) |
| 17 | モデルベース | I2A、環境モデル、ロールアウトエンコーダ |
| 18 | AlphaGo Zero | MCTS、自己対局、Connect4実装 |
| 19 | 応用事例 | ロボット、自律走行、推薦、RLHF |
| 20 | 総まとめ | アルゴリズム比較、選択ガイド |
終わりに
深層強化学習は急速に発展している分野です。このシリーズで扱った基本アルゴリズムは現在の最新研究を理解するための必須の土台となります。
最も重要なアドバイス3つ:
- 自分で実装すること:コードを自分で書いてこそアルゴリズムを真に理解できる
- 簡単な環境から始めること:CartPoleで動かないものは複雑な環境でも動かない
- 常にベースラインと比較すること:新しい方法がシンプルな方法より本当に良いか確認すること
強化学習の旅に終わりはありません。このシリーズが出発点となることを願います。