機械学習(特に強化学習)が好きな人のノート

機械学習関連のことをまとめていきます。強化学習関連が多いかもしれません

状態価値関数と状態行動価値関数について

今回は、強化学習で重要な状態価値と状態行動価値についてお話しようと思います。

状態価値関数$V(s)$とは、名前の通り各状態$s$の価値であり、
状態行動価値関数$Q(s, a)$とは、各状態$s$での各行動$a$の価値を表しています。

ここで言う価値というのは期待報酬値を表しています。
つまり、そこの状態に遷移することでどの程度これから報酬が得られそうか?を表しています。

迷路問題を用いた状態価値と状態行動価値の例

以下のような迷路問題を解く強化学習エージェントを用いて、
状態価値と状態行動価値の具体的な例を示します。

f:id:ttt242242:20190418135132j:plain:w400

今回用いる迷路問題の例では、
Sがスタート地点、Gが目的地とします。
なので、Gに着くと高い報酬がもらえるとしています。

状態は、各マス(座標)とし、
行動は上下左右としています。

で、学習が終わっているとします。
つまり、状態価値関数、及び、行動価値関数ともに適切な値になっているとします。

状態価値$V(s)$

まず、状態価値$V(s)$を見てみます。
状態価値という通り、
各状態に対して、価値が割り振られています。
ゴールに近ければ近い状態ほど価値が高くなっています。 エージェントはこれを元に方策を改善したりします。

f:id:ttt242242:20190418135209j:plain:w400

状態行動価値$Q(s,a)$

次に状態行動価値$Q(s, a)$について見てみます。
状態行動価値では、各状態$s$においての各行動$a$の価値となっています。
なので、下の図では、各マス(状態)に各行動の価値が入ってます。
状態価値と異なり、ある状態で各行動をとった時の期待報酬値が保持しているので、 方策を別に用意しなくても学習を行えます(Q Learning等)。
ゴールに近い状態であり、さらに、ゴールに近づくような状態行動価値には、高い値が割り振られています。
状態行動価値が正しく学習できていれば、各状態で最も高い行動価値の行動を選択していけば、最短ルートになります。

f:id:ttt242242:20190418134904j:plain:w400

強化学習

強化学習

  • 作者: Richard S.Sutton,Andrew G.Barto,三上貞芳,皆川雅章
  • 出版社/メーカー: 森北出版
  • 発売日: 2000/12/01
  • メディア: 単行本(ソフトカバー)
  • 購入: 5人 クリック: 76回
  • この商品を含むブログ (29件) を見る

【深層強化学習、keras-rl】 keras-rlで連続値の行動を扱えるDDPGを試す

深層強化学習ライブラリであるkeras-rlを用いて、 DDPGを動かしてみます。
Open AI gym で提供されているPendulumという問題を解きます。
基本的にはkeras-rlのexmpleコードを用います。
適宜、日本語のコメントや学習結果を表示するためのコードを加えています。

ちなみに私の環境は

です。

kears-rlのインストール

keras-rlを動かすためにいくつかインストールする必要があります。

pip install numpy
pip install gym
pip install tensorflow
pip install keras
pip install keras-rl

DDPGについて

Deep Deterministic Policy Gradient(DDPG) は
モデルフリーの深層強化学習アルゴリズムです。
Actor-Critic を用いて構成されています。

www.tcom242242.net

なので、ActorとCtiricの2つのニューラルネットワークを用います。
詳しくは以下の論文を参照していただければと思います。

https://arxiv.org/pdf/1509.02971v2.pdf

プログラム

Pendulumという振り子の問題を解かせます。
学習エージェントは、振り子を立たせて置くことが目的となる問題です。

問題については以下の公式サイトを確認していただければと思います。 https://github.com/openai/gym/wiki/Pendulum-v0

以下にサンプルコードを示します。
以下のコードはコピーしてそのまま実行できます。

import numpy as np
import gym
import matplotlib.pyplot as plt

from keras.models import Sequential, Model
from keras.layers import Dense, Activation, Flatten, Input, Concatenate
from keras.optimizers import Adam

from rl.agents import DDPGAgent
from rl.memory import SequentialMemory
from rl.random import OrnsteinUhlenbeckProcess


# 環境(タスク)の設定
ENV_NAME = 'Pendulum-v0'
env = gym.make(ENV_NAME)
np.random.seed(123)
env.seed(123)
assert len(env.action_space.shape) == 1
nb_actions = env.action_space.shape[0]

# actorの設定
actor = Sequential()
actor.add(Flatten(input_shape=(1,) + env.observation_space.shape))
actor.add(Dense(16))
actor.add(Activation('relu'))
actor.add(Dense(16))
actor.add(Activation('relu'))
actor.add(Dense(16))
actor.add(Activation('relu'))
actor.add(Dense(nb_actions))
# 出力は連続値なので、linerを使う
actor.add(Activation('linear'))
print(actor.summary())

# criticの設定。上記で設定したactorのinputを入力に含める
action_input = Input(shape=(nb_actions,), name='action_input')
observation_input = Input(shape=(1,) + env.observation_space.shape, name='observation_input')
flattened_observation = Flatten()(observation_input)
x = Concatenate()([action_input, flattened_observation])
x = Dense(32)(x)
x = Activation('relu')(x)
x = Dense(32)(x)
x = Activation('relu')(x)
x = Dense(32)(x)
x = Activation('relu')(x)
x = Dense(1)(x)
x = Activation('linear')(x)
critic = Model(inputs=[action_input, observation_input], outputs=x)
print(critic.summary())

# Experience Bufferの設定
memory = SequentialMemory(limit=100000, window_length=1)
# 行動選択時に加えるノイズ(探索のため)
# 平均回帰課程を用いている。単純にノイズが、muに収束していく。
# ここでは、mu=0に設定しているので、ノイズはゼロになっていく。つまり、探索を行わなくなる。
random_process = OrnsteinUhlenbeckProcess(size=nb_actions, theta=.15, mu=0., sigma=.3)

# DDPGエージェントの設定
agent = DDPGAgent(nb_actions=nb_actions, actor=actor, critic=critic, critic_action_input=action_input,
                  memory=memory, nb_steps_warmup_critic=100, nb_steps_warmup_actor=100,
                  random_process=random_process, gamma=.99, target_model_update=1e-3)
agent.compile(Adam(lr=.001, clipnorm=1.), metrics=['mae'])

# エージェントの学習
# visualizeで学習中のゲーム画面を表示するか。verboseで学習プロセスの表示をするか
history = agent.fit(env, nb_steps=50000, visualize=False, verbose=1, nb_max_episode_steps=200)

# 学習曲線のプロット
history = history.history
plt.plot(np.arange(len(history["episode_reward"])), history["episode_reward"])

# 学習したモデルの読み込み
# agent.load_weights('ddpg_{}_weights.h5f'.format(ENV_NAME))

# 学習したのモデルの保存
agent.save_weights('ddpg_{}_weights.h5f'.format(ENV_NAME), overwrite=True)

# 評価
agent.test(env, nb_episodes=5, visualize=False, nb_max_episode_steps=200)

上述したコードを実行すると、 下記のような学習曲線をプロットします。
f:id:ttt242242:20190416140700p:plain

学習が進むにつれて、得られる報酬が向上しているのがわかります。

深層強化学習のライブラリまとめ

とりあえず、深層強化学習ライブラリをまとめてみました。
ただ思ったより数が多いので、とりあえず列挙しておくだけです。
まだ完成していませんが、現状を挙げておきます。
最終的には全部試してみたいと思っています。

tensorforce

Tensorflowを用いた深層強化学習ライブラリ。
reinforce.io(https://twitter.com/reinforceio)というイギリスの組織?が管理している

pip install tensorforce

keras-rl

Kerasを用いた深層強化学習ライブラリ。

pip install keras-rl

www.tcom242242.net

chanear-rl

Chainer を用いた深層強化学習ライブラリ。
Chainerを開発してるPreferred Networksが作成しているので、
日本語で書かれた公式の紹介サイトもある

pip install chainerrl

baselines

複数の深層強化学習アルゴリズムが実装されている。
ライブラリとは言えないかもしれない。
OpenAIが開発している。
baselinesとある通り、研究のためのベースラインとして提供している。
OpenAIが開発しているので、OpenAI gymの問題を解かせるサンプルが多数ある。

machina

Deep Xという日本の会社が作ってる。
恐らく東大の松尾研究室絡みのベンチャー企業かな?

Rlib

@todo

Coach

@todo

https://github.com/NervanaSystems/coach

強化学習用ライブラリ

深層強化学習ではないですが、強化学習用ライブラリを1つ紹介します。

trfl

Deep Mindが公開しているTensorFlowを用いた強化学習ライブラリ。
Deep Mindが作っているので、かなりの数のアルゴリズムが実装されている模様

pip install trfl

つくりながら学ぶ! 深層強化学習 ~PyTorchによる実践プログラミング~

つくりながら学ぶ! 深層強化学習 ~PyTorchによる実践プログラミング~

【強化学習、モデルベース強化学習】Dyna-Q

恐らく最もシンプルであり、
最初に考案されたモデルベース強化学習であるDyna-Qについて紹介します。

モデルベース強化学習

一言で簡単に言ってしまえば、
モデルベース強化学習とは、
学習エージェントが環境のモデルを保持していて、
そのモデルも利用して学習する強化学習です。

エージェントは環境から実際に得られた経験を用いて、
通常の価値関数を学習(直接的強化学習)し、さらに環境のモデルを学習します。
そして、学習して得られたモデルを用いて価値関数の学習(間接的強化学習)も行います。

Dyna-Q

Dyna-qはモデルベースの強化学習の最もシンプルな手法です。
エージェントは通常のQ学習に加えて環境のモデルを保持しています。
Q学習は以下の記事を参照

www.tcom242242.net

エージェントは一回の行動によって得られた経験をもとに、
価値関数と環境のモデルを学習。
そしてその後に複数回、環境のモデルを用いて
価値関数の更新を行うシンプルな手法です。
以下にDyna-Qの構成図を示します。

f:id:ttt242242:20190409203506j:plain:w350

アルゴリズム

以下の操作を繰り返す。  

  1. 現在の状態s においてQ値$Q(s, a)$を基に行動選択($\epsilon$-greedy, softmax行動選択などを用いる。)
  2. 環境から遷移先状態$s'$、報酬$r$の観測
  3. 得られた経験$e=\langle s, a, r, s' \rangle$ を用いて、環境モデルの更新(モデル学習)
  4. 得られた経験$e$ を用いて、Q値の更新。更新式はQ学習と同様
  5. モデルを用いて学習
    • 任意の回数$N$以下の操作を繰り返す
      1. 現在までで得られている状態とその状態で行ったことのある行動を選択
      2. 環境モデルから得られた擬似的な遷移先状態$\hat{s}'$と$\hat{r}$を観測
      3. $\langle s,a,\hat{r},\hat{s}' \rangle$を使ってQ値を更新。更新式はQ学習と同様

f:id:ttt242242:20190409203526j:plain:w250:h200 f:id:ttt242242:20190409203537j:plain:w250:h200

$\epsilon$-greedy, softmax行動選択は以下を参照

www.tcom242242.net

www.tcom242242.net

実験

グリッドワールドを用いて、評価を行います。
f:id:ttt242242:20190409203215j:plain:w400

エージェントはスタート地点からGにたどり着くための最短経路を学習する問題です。
エージェントの行動は、上、下、左、右の4択、
状態は座標、
報酬は、Gについたら報酬=100、
壁(黒いマス)に当たったら報酬=-100、
それ以外の地点では報酬=0
とします。

プログラム

プログラムはgithubに挙げました

github.com

結果

f:id:ttt242242:20190409200949j:plain
N毎の累積報酬の推移

ステップ毎の環境のモデルを用いて学習する回数毎の累積報酬によって比較を行いました。
環境のモデルを用いて学習する回数が多いほど、早い段階で、良い累積報酬に収束していることがわかります。
今回の問題は決定論的な問題ですので、環境のモデルを正確に学習できるので、
環境のモデルを用いてば用いるほど学習が早く進みます。
一方で、環境のモデルを正しく学習できていない場合、
そのモデルを用いるほど学習性能が下がる可能性があるので、注意が必要です。

参考文献

強化学習

強化学習

  • 作者: Richard S.Sutton,Andrew G.Barto,三上貞芳,皆川雅章
  • 出版社/メーカー: 森北出版
  • 発売日: 2000/12/01
  • メディア: 単行本(ソフトカバー)
  • 購入: 5人 クリック: 76回
  • この商品を含むブログ (29件) を見る

その他

用語

参考文献で出てくる用語について整理しておきます。

  • プランニング:保持しているモデルから方策を計算すること
  • モデル学習:環境のモデルを学習すること
  • 直接的強化学習:環境から得られた生の経験を用いて価値関数、方策を改善すること
  • 間接的強化学習:環境のモデルを用いて価値関数と方策を改善すること

【強化学習】SARSAとQ Learningとの違い

SARSAとQ Learningの違いについて参考文献をもとにお話したいと思います。
SARSAとQ Learningのそれぞれのアルゴリズムとプログラムについては下記の記事で紹介しています。

www.tcom242242.net

www.tcom242242.net

SARSAとQ Learningの学習方法の違い

SARSAとQ Learningの違いは学習に用いるTD誤差にあります。
いかにSARSAとQ Learningの更新式を示します。
まず、Q Learningの更新式、 $$ Q(s,a) \leftarrow Q(s,a) + \alpha(r + \gamma \color{red}{\max_{a' \in A}Q(s',a')}-Q(s,a)) $$

次にSARSAの更新式、
$$ \begin{eqnarray} Q(s, a) \leftarrow Q(s, a) + \alpha (r +\gamma \color{red}{Q(s', a')} - Q(s, a)) \end{eqnarray} $$ SARSAは遷移先の状態において実際に取る行動の情報$Q(s', a')$を用いて学習し、
Q Learningでは、遷移先の最大行動価値$\max_{a' \in A}Q(s',a')$を用いて学習します。
SARSAは現在の方策に依存し、Q Learningは方策には依存しないのが特徴です。
また、Q Learningは遷移先状態の良い部分しか見ていないというものも大きな特徴です。

では、2つのトイプロブレムで、どのような性能差がでるかを
崖があるグリッドワールドで試してみます。

崖があるグリッドワールド

通常のグリッドワールドとは異なり、崖があるグリッドワールドを用いて、評価します。
図で表すと以下のような問題になります。

f:id:ttt242242:20190404180402j:plain

エージェントが崖に行くと報酬が-100となり、さらにスタート地点に戻されます。 それ以外の地点ではひたすら-1の報酬が得られるようなゲームです。

プログラム

githubに挙げました。
クローンして、run.pyを実行するとグラフが出力されます。

github.com

実験と考察

この実験では$\epsilon$-greedyを用いて、$\epsilon=0.1$に固定して学習を行います。
複数回試行し、、エピソード毎の平均報酬で評価します。
以下のグラフがQ LearningとSARSAによる実験結果です。

[f:id:ttt242242:20190404175948j:plain:250]
Q LearningとSARSAの比較

横軸はエピソード、縦軸が累積報酬を表しています。
SARSAのほうがQ Learningに比べて良い報酬を得ていることがわかります。
これはなぜか?
各手法によって得られた方策を見てみます。
プログラムで出力されただと見にくいので、図で示します。

f:id:ttt242242:20190404180311j:plain:h200
Q Learningが学習した方策

f:id:ttt242242:20190404180110j:plain:h200
sarsaが学習した方策

基本的に参考文献と変わりません。

Q Learningは危険(崖に近い)な近道を学習して、
SARSAは安定した方策を学習してます。

なぜそのような結果になったかというと
Q Learningは遷移先状態の最大行動価値だけを用いるため、
単純にゴールがどれだけ近いかのみを見みます。
そのため、近い道を見つけています。
逆に言えば、遷移先状態の最大行動価値以外の価値は見ないため、
危険かどうかは考慮ぜず行動します。
崖に近い道を選択しているので、 探索行動によってと崖から落ちているため、
報酬が小さくなっています。

一方で、SARSAは $\epsilon$-greedyで、$\epsilon$を0にしない限り、
遷移先状態のすべての行動価値を考慮して学習します。
そのため、危険な道も考慮して学習することになり、
安全な道を学習したと言えます。

もちろん最終的に$\epsilon$を0にした場合には両者とも
最も近い道を最適経路として学習します。

参考文献

強化学習

強化学習

  • 作者: Richard S.Sutton,Andrew G.Barto,三上貞芳,皆川雅章
  • 出版社/メーカー: 森北出版
  • 発売日: 2000/12/01
  • メディア: 単行本(ソフトカバー)
  • 購入: 5人 クリック: 76回
  • この商品を含むブログ (29件) を見る

【強化学習】アクタークリティック

アクタークリティック(actor-critic)とは

アクタークリティックは
行動を選択肢するアクター(actor)と、
アクターが選択した行動を評価するクリティック(critic)で構成される
強化学習フレームワークの1つです。

以下はイメージ図です。

f:id:ttt242242:20190402183908j:plain:w350

学習の流れはシンプルで、
①で、アクターは、方策$\pi(s,a)$をもとに行動を選択し、実行します。
②で、環境から状態$s'$及び報酬$r$をクリティックが観測します。
③で、得られた状態$s'$、報酬$r$を使ってアクターの取った行動の評価し、アクターに通知。アクターは評価をもとに方策の更新します。

この①、②、③を繰り返します。

アクターとクリティックが具体的にどのような操作をするかを
述べていきます。

アクター(actor)

アクターは実際の行動を決定し実行するので、行動器とも呼ばれます。
実際に行動した結果に関しては、クリティックにより評価されます。
クリティックにより評価された結果(例:TD誤差)を使って、
自らの行動の価値を修正します。

アクターは 方策$\pi(s, a)$と行動優先度 $p(s, a)$を保持しています。
ちなみに方策$\pi(s, a)$は状態$s$において行動$a$を行う確率を表しています。
方策$\pi(s, a)$は行動が離散値であり、softmax行動選択を行動選択手法とする場合には、行動優先度 $p(s, a)$を用いて、以下のように表現できます。

$$ \pi(s, a) = \frac{\mathrm{e}^{p(s, a)}}{\sum_{b \in A}\mathrm{e}^{p(s, b)}} $$

最もシンプルな行動優先度 $p(s, a)$の更新方法は、
クリティックから得られるTD誤差に用いて更新する方法です。
基本的には良い報酬が得られる行動を多く取るように行動優先度を修正していきます。
参考文献では、2つの方法を紹介しています。
1つが単純にTD誤差$\delta$分だけ行動優先度を更新する方法です。

$$ p(s, a) \leftarrow p(s, a) + \beta \delta $$

$\beta$ は学習率で、どの程度TD誤差を反映するかを決定するパラメータです。

もう1つの行動優先度の更新方法が、
更新度合いに方策を用いるものになります。
頻繁に選択する行動の、更新幅を小さく、
逆に選択確率の低い行動(珍しい行動)は更新幅を大きくとる方法
です。

$$ p(s, a) \leftarrow p(s, a) + \beta \delta (1-\pi(s, a)) $$

クリティック(critic)

クリティックとは評価器と呼ばれますが、
クリティック(critic)は批評家という意味で、
アクターを批評するという役割を持ちます。
参考文献でも紹介されている
シンプルなクリティックでは、
得られた報酬や遷移先の状態を用いてTD誤差$\delta$を計算します。

$$ \delta \leftarrow r + \gamma V(s') - V(s) $$

$V(s)$ は状態価値関数です。 アクターに計算したTD誤差$\delta$を送ります。
$V(s)$ に関しても、得られた報酬$r$をもとに更新していきます。
最もシンプルな形は以下のようになると思います。

$$ V(s) \leftarrow V(s) + \alpha (r - V(s)) $$

$\alpha$ も学習率になります。

終わりに

今回は簡単にアクタークリティックの紹介をしました。
アクタークリティック自体はフレームワークですので、
目的に合わせてアクターとクリティックを適切に設計することが重要になります。

参考文献

強化学習

強化学習

  • 作者: Richard S.Sutton,Andrew G.Barto,三上貞芳,皆川雅章
  • 出版社/メーカー: 森北出版
  • 発売日: 2000/12/01
  • メディア: 単行本(ソフトカバー)
  • 購入: 5人 クリック: 76回
  • この商品を含むブログ (29件) を見る

【深層学習、keras】mnistの数字の回帰モデルをkerasで作る

kerasでmnistの数字の画像を入力したら、その数字を出力するような回帰モデルを
作ってみます。 0と書いてある画像を入力したら、0を出力し、
9と書いてある画像を入力したら、9と出力するようにモデルを作成します。
以下はイメージ図

f:id:ttt242242:20190331135232j:plain

ちなみにCNNは使いません!

データセット

有名なmnistを用います。
手書き文字の認識用データセットです。
0〜9までの手書きの数字の画像が、学習用、テスト用でそれぞれ60000枚、10000枚用意されています。
特別ダウンロードする必要はありません。
下のプログラムを実行すれば、自動的にダウンロードされます。

プログラム

import keras
from keras.datasets import mnist
import numpy as np
from keras.models import Sequential
from keras.layers.core import Dense, Activation

# mnistのデータの取得
(x_train, y_train), (x_test, y_test) = mnist.load_data()

# 二次元配列から一次元に変換
x_train = np.array(x_train).reshape(len(x_train), 784)  
x_test = np.array(x_test).reshape(len(x_test), 784)
x_train = np.array(x_train).astype("float32")
x_test = np.array(x_test).astype("float32")
# 0〜1に正規化
x_train /= 255
x_test /= 255

y_train = np.array(y_train)
y_test = np.array(y_test)

# モデルの構築
model = Sequential()
model.add(Dense(256, input_shape=(784,)))
model.add(Activation('relu'))

model.add(Dense(32))
model.add(Activation('relu'))

model.add(Dense(1))
model.add(Activation('linear'))

# 誤差関数は平均二乗誤差、最適化手法はrmsprop
model.compile(loss="mean_squared_error", optimizer="rmsprop")

# 学習
history = model.fit(x_train, y_train,
                    batch_size=32, nb_epoch=100,
                    verbose=1, validation_split=0.2)

# 20個程度のテストデータを使って予測結果の確認
print("正解:予測")
for x, y in zip(x_test[0:20], y_test[0:20]):
    predicted_y = model.predict(np.array([x]))[0][0]
    print("{}:{}".format(y,predicted_y))

結果

プログラムにある通り、いくつかtestデータを取り出して、結果を簡易的に見てみます。

正解:予測
7:7.071030616760254
2:1.9824368953704834
1:1.0134353637695312
0:0.13662612438201904
4:4.098000526428223
1:0.9860554933547974
4:4.018962383270264
9:7.225198745727539
5:6.004607200622559
9:9.107109069824219
0:0.09038352966308594
6:6.015869140625
9:9.079833984375
0:0.18159937858581543
1:0.9922631978988647
5:4.972866058349609
9:9.171490669250488
7:7.072229385375977
3:2.5052080154418945
4:3.9980337619781494

今回は過学習とかは特に考慮していませんが、ある程度うまくいってそうです。
あと、正解データも正規化したほうが良かったのですが、
今回はしませんでした。

終わりに

さすがにkerasを使うとシンプルに記述できます。
kerasでもう少しいろいろやってみたいです。