はじめに
前回のロボットアーム制御では、強化学習を使っています。強化学習にはPPOと使いましたが、アームの到達位置の精度がいまいちだったので、SACに変更しました。かなりよく改善されたので、ご紹介いたします。
強化学習は、状態(state)に基づいて、行動(action)を決めて、その行動の結果として変化した環境(environment)をもとに報酬(reward)を算出し、この報酬を最大化するように学習を進めます。
ロボットアームでの状態は、関節角度、関節速度、ターゲット位置などが対象です。状態が観察可能であれば、状態を(obs, observation)と表記する場合もあります。また、行動は、モーター・トルクなどが想定されます。いずれも連続値を扱います。
この連続値を強化学習で取り扱うことで、ロボットアームの角度を微妙に調整し、滑らかな動きでアーム先端を目標位置に移動させます。
PPO 強化学習
前回は連続値制御ができる強化学習の中で割と標準的な PPO を使いました。
PPO は、Proximal Policy Optimization Algorithms のことであり、Proximal(近傍)を探索する、つまり、policy(方策)を大きく変更せずにじわじわと変えていく安定性重視のアルゴリズムです。policy は多層マルチレイヤー・パーセプトロン(MLP)を利用して賢くさせていきます。
「新policyは、ある行動をどれくらい重視するようになった?」つまり、
「新policyは、ある行動をとる確率を以前のpolicyより高めたか?」を以下の式で計算して学習に利用します。
$r_t(\theta)=\frac{\pi_\theta(a_t|s_t)}{\pi_{\theta_{old}}(a_t|s_t)}$
${s_t}$: 時刻tの 状態 state、${a_t}$: 時刻tで取った行動 action
${π_θ}$ : ニューラルネットの重み θ に基づいて計算されるpolicy(ある行動をとる確率)
${π_θ(a_t∣s_t)}$ : 新しいpolicyで、状態が ${s_t}$ のとき、行動 ${a_t}$ を出す確率
${\pi_{\theta_{old}}(a_t|s_t)}$: 古いpolicyで、状態が ${s_t}$ のとき、行動 ${a_t}$ を出す確率
PPOでは、この ${r_t(\theta)}$をそのまま使わず、クリッピングすることにより、ある範囲内に制限をかけます。具体的には次式で求めた目的関数${L^{CLIP}(\theta)}$を利用します。これによりpolicy が「じわじわと変わるる」ようになります。
$$
L^{CLIP}(\theta)=
\hat{\mathbb{E}}_t
\left[
\min\left(
r_t(\theta)\hat{A}_t,\
\mathrm{clip}\left(
r_t(\theta),
1-\epsilon,
1+\epsilon
\right)\hat{A}_t
\right)
\right]
$$
SAC 強化学習
今回は、別の強化学習である SAC を使ってみます。SAC は Soft Actor-Critic のことです。探索においてランダム性を重視します。別の言い方をすると、entropy(乱雑さ)を大きくする方針で探索を行います。
探索性能が高いので、動きがなめらか、安定性が高い、目標値へ寄りやすい、という特徴があります。逆にPPO は entropy を使わないので探索性は低くなります。
その際に、Q関数(Action-Value Function / 行動価値関数)を批評家(クリティック)として使用します。Q関数が表すのは「現在の状態」で「ある具体的な行動」をとった後に、そこから将来にわたって得られる累積の価値(報酬の合計)です。
「今その行動をとることの、将来まで見据えた総合的な価値」であり、「アクター(ポリシー)をより良い方向へ育てるための羅針盤」および「自分自身の予測精度を高めるための自己採点基準」として活用されます。
ここで、経験再生バッファ(Replay Buffer)を「過去の体験談が詰まった日記帳(データベース)」として使います。過去の学習経験をこのバッファに経験を保存して、後からランダムにサンプリングして学習に利用します。これを使うことで、「直近の特定の状態」に過剰に適合してしまう過学習を抑制できます。また、サンプリング効率が向上するメリットもあります。
なお、PPOは経験再生バッファを使わない Actor-Critic の強化学習です。そのため、サンプリング効率がSACよりも低下します。
以上で述べたことから、PPOでは制御精度が若干ものたりなかったり、振動したり、する場合がありますが、SACでは(PPOよりも)ロボットの行動が滑らかに、安定的になることが期待されます。
実装
前回のプログラム train_6.py から変更する箇所だけを示します。train_sac.py の名前で保存しました。
from stable_baselines3 import PPO
を、以下に変更します。
from stable_baselines3 import SAC
model の行を以下に変更します。
model = SAC(
"MlpPolicy",
train_env,
verbose=1
)
ステップ数は多めの500000にして計算しました。
model.learn(total_timesteps=500000)
500000ステップでの結果だけ示します。
---------------------------------
| rollout/ | |
| ep_len_mean | 50 |
| ep_rew_mean | -4.52 |
| time/ | |
| episodes | 10000 |
| fps | 56 |
| time_elapsed | 8839 |
| total_timesteps | 500000 |
| train/ | |
| actor_loss | 8.09 |
| critic_loss | 0.000357 |
| ent_coef | 0.0214 |
| ent_coef_loss | 0.0122 |
| learning_rate | 0.0003 |
| n_updates | 499899 |
---------------------------------
表示プログラムも前回の train_6_disp.py のうち以下の2行を修正し、train_sac_disp.py の名前で保存し、実行しました。
from stable_baselines3 import SAC
model = SAC.load("sac_Reacher-v5")
PPOの場合よりも、目標値に近く、かつ、スムーズに、到達できるようになりました。
終わりに
強化学習アルゴリズムの比較がすぐにできてよかったです。