マイノート

いろいろ勉強したことをまとめていきます

MENU

強化学習の枠組み

強化学習は一言で言うと、試行錯誤しながら、最適な行動を学習する学習アルゴリズム です。

何かしらの行動をし、その行動に対する報酬(正解ではない)を受け取り、その行動を 報酬値によって「強化」 していきます。

一番シンプルな強化学習のフレームワークとしては、以下のようになります。

1. 行動の選択(高い報酬を貰えそうな行動を優先的に)

などの多くの手法があります。

2. 実際に行動

3. 行動によって変化した状態と、報酬を受け取る

4. 報酬から学習する

  • Q学習
  • actor-critic

などの多くの手法があります。

5. 上記を繰り返し、報酬値が最大になるような行動を学習する

【keras】keras-rlでcartpole問題

目的

  • keras-rlを試したい

背景

keras-rlとは

kerasを用いて、deep q networkが実装されているossです。

ただ、ここ最近は更新されていないようです。

install方法

pip install h5py
pip install keras-rl
注意点

kerasの2.0に対応していないようです!
なので、kerasのバージョン1.2.0をインストールして使ってみます。

pip install keras==1.2.0

OpenAI Gym

強化学習のベンチマーク問題を集めたOSSです。

keras-rlの強化学習エージェントを解かせる問題は、 OpenAI Gymのインターフェースに準じて作成する必要がある。

OpenAI Gymでのインストール方法

pip install gym

cartpoleとは

名前の通り、cartに上にpoleがあって、
poleが倒れないように、うまくcartをコントロールする問題です。

エージェントはタイムステップ毎に状態(詳しくは参考サイトを参照)と報酬を受け取り、学習します。

以下のサイトがcartpoleについての説明はわかりやすいです。
http://qiita.com/namakemono/items/9b75d1c0c98916b396ba

実験、

ソースコード(DQN)

keras-rlのexmplesに格納されているサンプルプログラムに
多少コメントを加えたものです。

import numpy as np
import gym

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

from rl.agents.dqn import DQNAgent
from rl.policy import BoltzmannQPolicy
from rl.memory import SequentialMemory


ENV_NAME = 'CartPole-v0'

env = gym.make(ENV_NAME)
np.random.seed(123)
env.seed(123)
nb_actions = env.action_space.n # アクション数

# モデルの定義
model = Sequential()
model.add(Flatten(input_shape=(1,) + env.observation_space.shape))
model.add(Dense(16))
model.add(Activation('relu'))
model.add(Dense(16))
model.add(Activation('relu'))
model.add(Dense(16))
model.add(Activation('relu'))
model.add(Dense(nb_actions))
model.add(Activation('linear'))
print(model.summary())

memory = SequentialMemory(limit=50000, window_length=1) # experience reply で用いるmemory
policy = BoltzmannQPolicy() # 行動選択手法の定義
dqn = DQNAgent(model=model, nb_actions=nb_actions, memory=memory, nb_steps_warmup=10,
               target_model_update=1e-2, policy=policy)
dqn.compile(Adam(lr=1e-3), metrics=['mae'])

history = dqn.fit(env, nb_steps=50000, visualize=True, verbose=2) # 学習。ここでnb_stepsは全エピソードのステップ数の合計が50000(だと思う)

dqn.save_weights('dqn_{}_weights.h5f'.format(ENV_NAME), overwrite=True)

dqn.test(env, nb_episodes=5, visualize=True)

実験結果

上記のソースコードをただ実行すると、以下のような結果をプロットします。 うまく学習できているようです。

省略

Testing for 5 episodes ...
Episode 1: reward: 200.000, steps: 200
Episode 2: reward: 200.000, steps: 200
Episode 3: reward: 200.000, steps: 200
Episode 4: reward: 200.000, steps: 200
Episode 5: reward: 200.000, steps: 200

エピソード毎の報酬の変化の推移

エピソード毎の報酬の変化の推移をプロットしてみました。(参考程度) f:id:ttt242242:20170905060828p:plain

徐々に累計報酬は上昇しているように見えます。
ただ、もちろん試行錯誤しながら、学習しているので、突然報酬が減少したりもしてます。
これは、探査を行ったためだと考えられます。

【keras】kerasでmnistデータの数字分類

今更ながら、単純なmnistの数値分類問題をkerasでやってみようと思います

前提

keras

keras はニューラルネットを非常に簡単に構築可能なライブラリです。

install方法

シンプルに以下のコマンドでインストールできる

pip install keras

mnistデータ・セット

手書き文字の認識用データ・セットです。 

0〜9までの手書きの数字の画像が、学習用、テスト用でそれぞれ60000枚、10000枚用意されています。

特別ダウンロードする必要はありません。

下のサンプルコードを実行すれば、自動的にダウンロードされます。

実験

mnistの手書きの文字をうまく分類できるように、 ニューラルネットに学習させたいと思います。

kerasのexampleに格納されているサンプルコードを用いて、 学習と評価を行ってみます。

ソースコード

kerasのexampleのソースコードに少し変更を加えたコード。

基本的には、参考文献のページを参照してもらえば、以下のコードは理解できると思います。

import numpy as np
import json
np.random.seed(1337)  # for reproducibility

from keras.datasets import mnist
from keras.models import Sequential
from keras.layers.core import Dense, Dropout, Activation
from keras.optimizers import SGD, Adam, RMSprop
from keras.utils import np_utils


batch_size = 128
nb_classes = 10 # クラス数。今回は0〜9の10クラスなので、10
nb_epoch = 20

# mnistデータ・セットの取得
(X_train, y_train), (X_test, y_test) = mnist.load_data()

X_train = X_train.reshape(60000, 784)
X_test = X_test.reshape(10000, 784)
X_train = X_train.astype('float32')
X_test = X_test.astype('float32')
X_train /= 255
X_test /= 255
print(X_train.shape[0], 'train samples')
print(X_test.shape[0], 'test samples')

# 数値をone-hotの形に変更 例) 5 => array([ 0.,  0.,  0.,  0.,  0.,  1.,  0.,  0.,  0.,  0.])
Y_train = np_utils.to_categorical(y_train, nb_classes)
Y_test = np_utils.to_categorical(y_test, nb_classes)

model = Sequential()
model.add(Dense(512, input_shape=(784,)))
model.add(Activation('relu'))
model.add(Dropout(0.2))

model.add(Dense(512))
model.add(Activation('relu'))
model.add(Dropout(0.2))

model.add(Dense(10))
model.add(Activation('softmax'))

model.summary()

model.compile(loss='categorical_crossentropy',
              optimizer=RMSprop(),
              metrics=['accuracy'])

history = model.fit(X_train, Y_train,
                    batch_size=batch_size, nb_epoch=nb_epoch,
                    verbose=1, validation_data=(X_test, Y_test))
score = model.evaluate(X_test, Y_test, verbose=0)
print('Test score:', score[0])
print('Test accuracy:', score[1])

# 学習historyを保存
with open("history.json", "w") as f:↲
    json.dump(history.history, f)↲

結果

epochが進む毎にloss(誤差)が減少し、acc(正解率)が上昇していることがわかります。 学習できているようです。

f:id:ttt242242:20170827142440p:plain

f:id:ttt242242:20170827142815p:plain

おまけ実験

隠れ層を増やしてやってみました。

f:id:ttt242242:20170827142825p:plainf:id:ttt242242:20170827143051p:plain

隠れ層が増加すればするほど、精度が低下するという結果に。

層が増えれば増えるほど、勾配が適切に入力層に近い層まで、逆伝搬されないのが、問題なのかと思います。 まぁ先人達が層を増やす時にぶつかった基本的な問題だと思います。

なので、問題が比較的簡単な今回の問題のような場合などでは、

むやみに層や各層のノード数を増やすと逆に精度が落ちるので注意しましょう。

最後に

kerasはわかりやすく良い

参考文献

以下の参考サイトはとてもわかりやすかったです。ありがとうございました。

aidiary.hatenablog.com

PythonでMNISTを利用する方法まとめ - Qiita

Sequentialモデルのガイド - Keras Documentation

rubyでk-meansを手軽に使えるライブラリ

k-meansをrubyから使えるライブラリ作りました。

k-meansについては前に軽くまとめたので、そちらを

www.tcom242242.net

本ライブラリの使い方

gem install t_learn

サンプル

今回は以下のようなデータをk-meansでクラスタリングしようと思います。 rubyからpythonのライブラリを使用できるpyCallを使い描画します。

f:id:ttt242242:20170629044640p:plain

以下のプログラムで使用しているサンプルデータ(sample_2dim.json)はgithubにおいてあります。

gist5e8111b0cc66613eaacca1e03277032a

クラスタリング結果

f:id:ttt242242:20170629044847p:plain

大きな点はクラスターの重心を表しています。うまくクラスタリングできてるようです。

EMアルゴリズムで混合ガウス分布のパラメータ推定できるライブラリ(ruby)

作ったもの

EMアルゴリズムで混合ガウス分布のパラメータ推定ができるライブラリをrubyで作りました。

github.com

使い方

まず、本ライブラリのインストー

gem install t_learn

1次元データに対して

githubにおいてある “sample_1dim.json” を使います。

このデータは正規化(各データ数を表す縦軸に対して)すると以下の画像のようなデータになります。

f:id:ttt242242:20170624211109p:plain

この混合ガウス分布のパラメータを推定します。

require 't_learn'

em = TLearn::EM_Gaussian.new()
data_list = JSON.load(open("./sample_1dim.json"))
history = em.fit(data_list, k_num=2) # k_num はガウス分布の個数

以下、実行結果

likelihood: -3088.0358230172806
likelihood: -3087.7133321058004
省略
likelihood: -2943.95823100874
likelihood: -2943.9582300846514
====================================
pi : [0.29168644105123087, 0.70831355894877]
mu : [[0.029483770596389985], [10.033090965120484]]
conv : [[[4.166929409854276]], [[8.88533611395374]]]

出力されたパラメータを用いると、以下のような(緑のグラフ)混合正規分布を表していることがわかります

f:id:ttt242242:20170624211123p:plain

うまく、パラメータを推定できているようです。

2次元データに対して

PRMLのサンプルデータを今回作成したライブラリ用に加工して、使用させていただきます。 ちなみにサンプルデータfaithful.jsongithubにおいてあります。 下のソースコードと同じディレクトリにサンプルデータを配置して、以下のソースコードを実行します。

require 't_learn'

em = TLearn::EM_Gaussian.new()
data_list = JSON.load(open("./faithful.json"))
history = em.fit(data_list, k_num=2) # k_num はガウス分布の個数

以下、実行結果

likelihood: -1264.5079209519638
likelihood: -1240.5772871778106
省略
likelihood: -1130.2639602913885
likelihood: -1130.263960190925
====================================
pi : [0.6441275620663266, 0.3558724379336733]
mu : [[4.28966107037274, 79.96810425509231], [2.0363874344782444, 54.47850611640881]]
conv : [[[0.1699695817230504, 0.9406238960300867], [0.9406238960300867, 36.04637543657748]], [[0.06916686263691188, 0.4351591734475339], [0.4351591734475339, 33.69722446174996]]]

ここでは、グラフをプロットしていませんが、 参考サイトと同じような値が得られています。(今回データを標準化していないため、対数尤度の値は異なります。)

まぁうまくいっているようです。

参考

今回、このライブラリを作成するのに以下のサイトを特に参考にしました。 ありがとうございました。

aidiary.hatenablog.com

CNNの伝搬と逆伝搬

※これから少しづつ改良していきます。

はじめに

少しCNNを触る機会があったので、

CNNにおいての伝搬、逆伝搬のところを勉強して自分用としてまとめた。

正直、数式はほとんど以下のサイトと同じである。

こちらの都合により $a$ を $y$ と変更しているなど、いくつか変更してある。

まず以下のサイトで理解してみることをおすすめする。

数式で書き下す Convolutional Neural Networks (CNN) - Yusuke Sugomori's Blog

上記のサイトの前半部分と同様に、

カーネル数が1の場合を今回は紹介する。

下記の2つの層の伝搬と逆伝搬についてのみ扱う。

  • Convolution Layer
  • MaxPooling Layer

Convolution Layer

まず、Convolution Layerの伝搬と逆伝搬について説明する。

伝搬

畳込みは以下の式で表現される。

\begin{equation} y_{ij} = \sum^{m–1}_{s=0}\sum^{n–1}_{t=0} w^{k}_{st} x_{(i+s)(j+t)} + b^k \end{equation}

やっていることは、以下の図がわかりやすい。

f:id:ttt242242:20170423213119p:plain:w200

f:id:ttt242242:20170423212953p:plain:w300

参考:http://hokuts.com/2016/12/13/cnn1/

逆伝搬

f:id:ttt242242:20170423212023j:plain:w300

カーネルの重み $w$ とバイアスである $b$ を更新する。

\begin{equation} w^{k}_{st} = w^{k}_{st} – \epsilon \frac{\partial E}{\partial w^{k}_{st}} \\ b^k = b^k – \epsilon \frac{\partial E}{\partial b^{k}} \end{equation}

カーネルの $w_{ij}$ は 畳み込んだ結果の二次元データ $y$ すべてに影響を与えているので、以下のように $y$ から勾配 $\frac{\partial E}{\partial w^{k}_{st}}$,$\frac{\partial E}{\partial b^{k}}$ を求める。

\begin{equation} \frac{\partial E}{\partial w^{k}_{st}} = \sum^{M–2(m/2)}_{i=0}\sum^{N–2(n/2)}_{j=0} \frac{\partial E}{\partial y^{k}_{ij}}\frac{\partial y^{k}_{ij}}{\partial w^{k}_{ij}} \\ = \sum^{M–2(m/2)}_{i=0}\sum^{N–2(n/2)}_{j=0} \frac{\partial E}{\partial y^{k}_{ij}} x_{(i+s)(j+t)} \\ \frac{\partial E}{\partial b^k} = \sum^{M–2(m/2)}_{i=0}\sum^{N–2(m/2)}_{j=0} \frac{\partial E}{\partial y^{k}_{ij}}\frac{\partial y^{k}_{ij}}{\partial b^{k}} \end{equation}

$\frac{\partial y^{k}_{ij}}{\partial b^{k}}$ は1より、

\begin{equation} = \sum^{M–2(m/2)}_{i=0}\sum^{N–2(n/2)}_{j=0} \frac{\partial E}{\partial y^{k}_{ij}} \end{equation}

さらにその後ろに伝搬させる必要がある場合

f:id:ttt242242:20170423212029j:plain:w300

$\frac{\partial E}{\partial x_{ij}}$は

\begin{equation} \frac{\partial E}{\partial x_{ij}} = \sum^{m–1}_{s=0}\sum^{n–1}_{t=0} \frac{\partial E}{\partial y^{k}_{(i–s)(j–t)}}\frac{\partial y^{k}_{(i–s)(j–t)}}{\partial x_{ij}} \\ = \sum^{m–1}_{s=0}\sum^{n–1}_{t=0} \frac{\partial E}{\partial y^{k}_{(i–s)(j–t)}}w^{(k)}_{st} \end{equation}

$i-s < 0$ もしくは $j-t < 0$ の場合は

\begin{equation} \frac{\partial E}{\partial y^{k}_{(i–s)(j–t)}} = 0 \end{equation}

と計算する。

MaxPooling Layer

f:id:ttt242242:20170423212037j:plain:w300

伝搬は単純に、二次元データのフィルタ適応部分で最も高い値を次の層に伝搬させる。

伝搬

\begin{equation} y_{ij} = max(x_{(li+s)(lj+t)})\ \ \ \ \ where \ \ (s \in l)\,(t \in l) \end{equation}

逆伝搬

逆伝搬は単純に、最も高い値だったユニットに逆伝搬させるだけ。

\begin{equation} \frac{\partial E}{\partial x_{(li+s)(lj+t)}} = \begin{cases} \frac{\partial E}{\partial y^{k}_{ij}} \ \ \ \ (y_{ij} = x_{(li+s)(lj+t)}) \\ 0 \ \ \ \ \ (otherwise) \end{cases} \end{equation}

Activation Layer

ここは参考サイトを見ればわかると思うので省略。

伝搬

\begin{equation} y_{ij} = ReLU(x_{ij}) = max(0,x_{ij}) \end{equation}

逆伝搬

\begin{equation} \frac{\partial E}{\partial x^{k}_{ij}} = \begin{cases} \frac{\partial E}{\partial x^{k}_{ij}} \ \ \ (y_{ij} \geq 0) \\ 0 \ \ \ \ \ (otherwise) \end{cases} \end{equation}

大脳皮質についてのメモ

大脳の外側2〜4ミリメートルの層があり、「大脳皮質」と呼ばれている。 この大脳皮質は約140億個のニューロンから構成されている。

f:id:ttt242242:20170408160120j:plain

参考: 無料イラスト 脳(png・CSeps)

各部位についてのまとめ

頭頂葉

  • 感覚情報の統合を行っている
  • 一部は視覚の処理に関わっている
  • 物体の位置や方向などを捉えるために重要な部位

前頭葉

  • 体の動きを司る「運動野」が存在し、歩行などの運動をコントロールしている
  • 理性的思考や感情のコントロールも行っている

側頭葉

  • 主に聴覚の処理に関わる
  • 音声や文字の意味を理解する働きを持つ

後頭葉

  • 目からの情報を制御する「視覚野」の大部分が位置している

大脳皮質ではないが重要な部位のメモ

海馬

イラストにはないが重要な部位なのでメモ。 - 記憶に重要な役割を果たす

嗅内皮質

イラストにはないが、嗅内皮質は海馬の前方に位置する - 互換から入力される信号のほとんどは、嗅内皮質を通して伝わる

参考文献

Newton(ニュートン) 2017年 03 月号 [雑誌]

Newton(ニュートン) 2017年 03 月号 [雑誌]