強化学習による二足歩行の獲得 Part2<既存の実装で学習>

# 今回やりたいこと

前回に[強化学習による二足歩行の獲得 Part1<環境構築編>](https://qiita.com/kinziro/items/c6b01561658d7a2b6ab8)でAI Gymのroboschoolで強化学習を行うための環境を構築しました。
今回はその環境で[stable baseline](https://github.com/hill-a/stable-baselines)で実装済みの強化学習手法PPOを用いて二足歩行を学習してみます。

# 強化学習手法PPOとは

[PPO](https://arxiv.org/abs/1707.06347)とは2017年にOPEN AIから発表された強化学習手法です。そしてOPEN AIが公開している[baselines](https://github.com/openai/baselines)とそれをフォークして作成された[stable baseline](https://github.com/hill-a/stable-baselines)に実装が含まれています。

PPOは先行研究の[TRPO](https://arxiv.org/abs/1502.05477)を改良したものとなっています。TRPOは方策が急激に変化しないように、方策の前後のKLダイバージェンスを一定値以下に抑えるという工夫をしており、ロボット制御などでよい性能が示されていました。ただ方策のKLダイバージェンスの比較を行うための実装が複雑になるという問題点があったため、PPOでは代わりに方策の前後の比率が一定値以上であれば規定値にクリッピングすることで実装を簡略化しています。

詳細に関しては[【論文】Proximal Policy Optimization Algorithms (PPO, 2017)](https://qiita.com/keisuke-nakata/items/87b742bcb09149b6d8d1)などでご確認ください。

# 実行用スクリプト
実行用スクリプトは以下になります。
実装済みモデルを使うことで学習部分が僅か3行で書けてしまいます。

学習と評価(学習済みモデルによるシミュレーション)がしたいときは変数trainとvalidationをTrueにします。もしくは評価だけしたいときはtrainはFalse, validationはTrueにします。
学習タイムステップはlearn_timestepsで設定します。

学習を実行するとスクリプト直下に「./stable_baselines/RoboschoolHumanoid-v1/」ディレクトリが作成され、その中に学習済みモデル「ppo2_model.pkl」とtensorboard用ログの「tensorboard_log/」が作成されます。
評価を行うとシミュレーション結果の動画が「video/openaigym.video.***.video000000.mp4」として保存されます。※ ***は適当な数値が入ります

``` python:PPO2.py
import numpy as np
import gym, roboschool
import os
import time
from datetime import datetime
from OpenGL import GLU

from stable_baselines.common.policies import MlpPolicy
from stable_baselines.common import set_global_seeds
from stable_baselines.common.vec_env import DummyVecEnv, SubprocVecEnv
from stable_baselines.results_plotter import load_results, ts2xy
from stable_baselines import PPO2

# tensorflow gpu 設定
#import tensorflow as tf
#tf.Session(config=tf.ConfigProto(device_count = {'GPU': 2}))


def make_env(env_name, rank, seed=0):
    """
    Utility function for multiprocessed env.

    :param env_name: (str) the environment ID
    :param rank: (int) index of the subprocess
    :param seed: (int) the inital seed for RNG
    """
    def _init():
        env = gym.make(env_name)
        env.seed(seed + rank)
        return env
    set_global_seeds(seed)
    return _init


# 学習設定
train = True       # 学習をするかどうか
validation = True   # 学習結果を使って評価をするかどうか

env_name = 'RoboschoolHumanoid-v1'
num_cpu = 1         # 学習に使用するCPU数
learn_timesteps = 10**3     # 学習タイムステップ

ori_env = gym.make(env_name)
#env = DummyVecEnv([lambda: ori_env])
env = SubprocVecEnv([make_env(env_name, i) for i in range(num_cpu)])
env.reset()
#env.render()
#time.sleep(5)

savedir = './stable_baselines/{}/'.format(env_name)
logdir = '{}tensorboard_log/'.format(savedir)
os.makedirs(savedir, exist_ok=True)

starttime = datetime.now().strftime("%Y/%m/%d %H:%M:%S")
# 学習の実行
if train:
    model = PPO2(MlpPolicy, env, verbose=1, tensorboard_log=logdir)
    model.learn(total_timesteps=learn_timesteps)
    model.save('{}ppo2_model'.format(savedir))

endtime = datetime.now().strftime("%Y/%m/%d %H:%M:%S")


# 学習結果の確認
if validation:
    model = PPO2.load('{}ppo2_model'.format(savedir))
    from gym import wrappers

    video_path = '{}video'.format(savedir)
    wrap_env = wrappers.Monitor(ori_env, video_path, force=True)

    done = False
    obs = wrap_env.reset()

    for step in range(10000):
        if step % 10 == 0: print("step :", step)
        if done:
            time.sleep(1)
            o = wrap_env.reset()
            break

        action, _states = model.predict(obs)
        obs, rewards, done, info = wrap_env.step(action)

    wrap_env.close()
env.close()

print(starttime)
print(endtime)
```

# 学習結果

まず learn_timesteps = 4*10**8 (4億)で学習を行ってみます。
![result_4-10e8.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392863/396f91d2-e44d-d998-f5ae-1a304717e220.gif)

どうにか前進していますが、少し歩いたところで転倒してしまっています。
これでは少しつまらないので、もう少し学習タイムステップを増やして改善できないかを確認してみます。

次は learn_timesteps = 12*10**8 (12億)での学習になります。
![result_12-10e8.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392863/a745aaca-53f4-b456-afea-002309bd0cca.gif)

今度は転けずに歩き続けることができるようになりました。PPOすごい！！
歩き方が気持ち悪いのは気になりますが・・・笑

# 学習過程の評価

今回は簡単に獲得報酬を比較してみます。

- 学習タイムステップ 4億回
![reward_4-10e8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392863/40ef1024-87ed-d04a-b9b1-11f4c3a867ac.png)

- 学習タイムステップ 12億回
![reward_12-10e8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392863/591e719f-c187-e6a5-8438-563d01d73d7e.png)

4億回では安定して歩けず、12億回で歩けるようになったのですが、獲得報酬を見ると特に大きく改善していっているわけではないようです。こんなもんなんでしょうか？
理由がよくわからないので今後調査してみようと思います。

# まとめ

今回は実装済みモデルPPOを用いて二足歩行動作の学習をさせてみました。
結果としては学習回数を増やせばとりあえず歩き続けることができるようになりました。
もっとハイパーパラメータのチューニングとか必要だと思っていたのですが、やってみるとできるもんですね。最近の手法の進化を感じます。
次回はもう少し詳細な解析や手法違いの比較、歩き方の改良などができればと思っています。