【初学者向け】
実機で動かす!
深層強化学習ワークショップ
山梨大学
牧野浩二 西崎博光
2019/9/25 1
自己紹介(牧野)
所属:
山梨大学
工学部附属ものづくり教育実践教育センター
研究:
医療福祉ロボット
暗黙知の工学的解析
人工知能
著書:
歩行ロボット 歩行解析 LEGOxChainer
連載
2019/9/25 2
自己紹介(西崎博光)
所属:
山梨大学 大学院総合教育部(工学部情報メカトロニクス工学科)
研究:
• マルチメディア(音・信号・テキスト・画像)に対する情報処理
• 音声言語処理: 音声認識,音声インタフェース
• 文字認識 (実用化志向の研究)
• 生体信号処理
著書:
ノート編集部
書き込み候補語句表示部
(音声認識結果)
タッチで選択した単語が
編集フィールド上に出現
キーボード・手書きでの
文字入力も可能
2019/9/25 3
本日の内容
深層強化学習の学習を実際に行いながら、深層学習とはどんなも
のなのか説明を行います。
西崎研の学生が来ています。
質問がありましたら彼を呼んでください。
初学者向けですので気軽に聞いてください。
飲み(食い)OKです。
2019/9/25 4
自己紹介(レオ チーシャン)
所属:
• 山梨大学 大学院医工農学総合教育部
工学専攻修士課程メカトロニクス工学コース 2年生
• 合同会社Artibrains※
研究(修士論文):
• 技術伝承システム(動画からのマニュアル作成支援)
• 深層学習を用いた雑音環境下音声認識
• 文字認識
出身国:
マレーシア
特技:
• 日本語,英語,中国語,マレー語が話せるクワドリンガル
• 深層学習に深く精通
その他:
大学院修了後は 「合同会社Artibrains」 のCEO・CTOに就任予定
※先月設立されたAI-OCR(ディープラーニングを用いた文字認識)のベンチャー企業
目次
• 問題設定と深層学習の関連技術
• 強化学習
• 深層学習
• 深層強化学習
• 実験結果
2019/9/25 6
問題設定
FRISK FRISK
FRISK
開ける
傾ける
閉める
箱を開けて、傾けるとFRISKを食べることができる。
FRISKを食べるとなくなる。
箱を閉めてから開けると、FRISKが入っている。
FRISKを食べる問題
2019/9/25 7
実験との対応
パソコン
カメラ LED
サーボホーン
が動く
サーボモータ:
ケースが開いているかどうか
LED:
FRISKが入っているかどうか
12345678910111213
GND
AREF
SDA
SCL
A5A4A3A2A1A0
Vin
GND
GND
5V
3.3V
RESET
IOREF
U
N
O
ATMEGA328P-PU
L
TX
RX
ON
~
~
~
~
~
~
DIGITAL (PWM~)
ANALOG IN
POWER
0
2019/9/25 8
実験の成功
FRISK FRISK FRISK
開ける 傾ける
閉める
目標
2019/9/25 9
2019/9/25 10
コンピュータが
知っていることできること
状態を知るために画像を得ることはできる。
• サーボモータがケースの開閉
• LEDがFRISKの有り無し
ということは知らない。
サーボモータの操作と傾けたという信号
FRISKをとれたことは知ることができる
入力
出力
• サーボモータがケースの開閉
に直結していることは知らない。
入出力
傾けるという指令を送ることはできる。
その結果、FRISKをとれたことを知ることはできる。
深層強化学習のすごいところ
なんだかわからない画像を見ながら、
動作をしているうちに、
画像の特徴を抽出し、
悪い動作を避けて、良い動作をするように
勝手にルールを構築できる。
ゴミ拾いロボット
よい動作:ごみを拾う
悪い動作:人にぶつかる
対戦ゲーム
よい動作:相手に勝つ
悪い動作:相手に負ける
テレビゲーム(スーパーマリオなど)
よい動作:良い得点でクリアする
悪い動作:敵に触れて死ぬ
相手が「へたっぴ」だと成長しない
良い動作、悪い動作の時に得られる値:報酬
人にぶつからないように動かない
同じ場所をくるくる回る
2019/9/25 12
目次
• 深層強化学習とは
• 強化学習
• 深層学習
• 深層強化学習
• 実験結果
2019/9/25 13
深層学習と深層強化学習
強化学習
ニューラルネットワーク
Qラーニング
Qネットワーク
ディープニューラルネットワーク
ディープQネットワーク
畳み込み
ニューラルネットワーク
リカレント
ニューラルネットワーク
深層学習の
拡張
深層学習
深層
強化学習
パーセプトロン
などいろいろ
深層学習の
組み込み
1960年代
1980年代
2000年代
2010年代
1990年代
様々な学習方法
の実装
様々な深層学習の組み合わせ
深層学習と深層強化学習の連携
第1次
人工知能ブーム
第2次
人工知能ブーム
第3次
人工知能ブーム
2019/9/25 14
人間に勝る深層学習技術
• 囲碁の世界チャンピオンに勝利: Alpha Go (Zero)
• By Google DeepMind
• 対話などの自然発話に対する音声認識
• By Microsoft
• 機械翻訳(一部の言語対)
• By Google
• 読唇術
• By Oxford and Google
• 音声合成
• By Google
• 手書き文字認識
• 画像からの「ガン」発見
“I’m from Japan”
→“7”
cancer
深層強化学習でできること
それぞれの操作の良し悪しはわからない
目的がはっきりしている
パックマン スペースインベーダー
ChainerRL(Chainerの深層強化学習版)のサンプルプログラム
こんな問題に向いている
「深層強化学習ライブラリChainerRL」で検索
2019/9/25 16
atari
二足歩行ロボット
バラ済みの
ピックアップ
深層強化学習でできること
実世界で応用可能な問題
ロボットへの応用リアルタイム翻訳
https://youtu.be/auJJrHgG9Mc https://youtu.be/uimyyGFwv2M
https://youtu.be/ATXJ5dzOcDwhttps://www.youtube.com/watch?v=8RILnqPxo1s
ドローン飛行制御
2019/9/25 17
目次
• 深層強化学習とは
• 強化学習
• 深層学習
• 深層強化学習
• 実験結果
2019/9/25 18
強化学習の枠組み
FRISK FRISK
FRISK
開ける
傾ける
閉める
エージェント
状態を観測
次の行動を決定
環境
環境が変化
報酬
1. エージェントは環境を認識し。
2. その環境(と過去の履歴)に応じて行動する。
3. 行動によって報酬を受け取る。
4. 環境が変化する。
2019/9/25 19
FRISKを食べる問題
FRISK FRISK
FRISK
開閉動作
傾ける
開閉動作
開閉動作
傾ける
傾ける
食
2019/9/25 20
状態遷移図
ケース:閉
FRISK:あり
ケース:開
FRISK:あり
ケース:開
FRISK:なし
操作
操作
操作
傾ける
傾ける
傾ける
FRISK FRISK
FRISK
操作
傾ける
操作
操作
傾ける
傾ける
食
食
2019/9/25 21
強化学習のための問題設定
Qラーニング(強化学習の一種)
• 状態:𝑠𝑡
• 行動:𝑎
• 報酬:𝑟
• Q値:Q(𝑠𝑡, 𝑎)
𝑄 𝑠𝑡, 𝑎 ← 1 − 𝛼 𝑄 𝑠𝑡, 𝑎 + 𝛼(𝑟 + 𝛾max𝑄)
Q値によって次の行動を決める
ケース:閉
FRISK:?
ケース:開
FRISK:あり
ケース:開
FRISK:なし
開閉動作
開閉動作
開閉動作
傾ける
傾ける
傾ける
更新式
食
2019/9/25 22
強化学習のための問題設定
Qラーニング(強化学習の一種)
• 状態:𝑠𝑡
• 行動:𝒂
• 報酬:𝑟
• Q値:Q(𝑠𝑡, 𝑎)
Q値によって次の行動を決める
ケース:閉
FRISK:あり
ケース:開
FRISK:あり
ケース:開
FRISK:なし
開閉動作
(行動:1)
開閉動作
(行動:1)
開閉動作
(行動:1)
傾ける
(行動:0)
傾ける
(行動:0)
傾ける
(行動:0)
𝑄 𝑠𝑡, 𝑎 ← 1 − 𝛼 𝑄 𝑠𝑡, 𝑎 + 𝛼(𝑟 + 𝛾max𝑄)
更新式
行動に番号を付ける
傾ける:0
開閉動作:1
食
2019/9/25 23
強化学習のための問題設定
Qラーニング(強化学習の一種)
• 状態:𝒔 𝒕
• 行動:𝑎
• 報酬:𝑟
• Q値:Q(𝑠𝑡, 𝑎)
Q値によって次の行動を決める
ケース:閉
FRISK:あり
[0 1]
ケース:開
FRISK:あり
[1 1]
ケース:開
FRISK:なし
[1 0]
開閉動作
(行動:1)
開閉動作
(行動:1)
開閉動作
(行動:1)
傾ける
(行動:0)
傾ける
(行動:0)
傾ける
(行動:0)
𝑄 𝑠𝑡, 𝑎 ← 1 − 𝛼 𝑄 𝑠𝑡, 𝑎 + 𝛼(𝑟 + 𝛾max𝑄)
更新式
状態に番号を付ける
ケース
閉:0 開:1
FRISK:
なし:0 あり:1
食
2019/9/25 24
傾ける
(行動:0 報酬:1)
強化学習のための問題設定
Qラーニング(強化学習の一種)
• 状態:𝑠𝑡
• 行動:𝑎
• 報酬:𝒓
• Q値:Q(𝑠𝑡, 𝑎)
Q値によって次の行動を決める
ケース:閉
FRISK:あり
[0 1]
ケース:開
FRISK:あり
[1 1]
ケース:開
FRISK:なし
[1 0]
開閉動作
(行動:1 報酬:0)
開閉動作
(行動:1 報酬:0 )
開閉動作
(行動:1 報酬:0 )
傾ける
(行動:0 報酬:0 )
傾ける
(行動:0 報酬:0 )
𝑄 𝑠𝑡, 𝑎 ← 1 − 𝛼 𝑄 𝑠𝑡, 𝑎 + 𝛼(𝑟 + 𝛾max𝑄)
更新式
行動によって報酬
あり:1
なし:0
食
2019/9/25 25
強化学習のための
問題設定
Qラーニング(強化学習の一種)
• 状態:𝑠𝑡
• 行動:𝑎
• 報酬:𝑟
• Q値:Q(𝑠𝑡, 𝑎)
Q値によって次の行動を決める
𝑠𝑡 = [0 1]
𝑎 = 1 𝑟 = 0
𝑎 = 1 𝑟 = 0𝑎 = 0
𝑟 = 0
𝑄 𝑠𝑡, 𝑎 ← 1 − 𝛼 𝑄 𝑠𝑡, 𝑎 + 𝛼(𝑟 + 𝛾max𝑄)
更新式
𝑎 = 1
𝑟 = 1
𝑎 = 0
𝑟 = 0
𝑎 = 1
𝑟 = 0
𝑠𝑡 = [1 1]
𝑠𝑡 = [1 0]
状態、行動、報酬を
すべて数字で表せた。
FRISK FRISK
FRISK
操作
傾ける
操作
操作
傾ける
傾ける
食
2019/9/25 26
強化学習のための
問題設定
Qラーニング(強化学習の一種)
• 状態:𝑠𝑡
• 行動:𝑎
• 報酬:𝑟
• Q値:𝐐(𝒔 𝒕, 𝒂)
Q値によって次の行動を決める
𝑠𝑡 = [0 1]
𝑎 = 1 𝑟 = 0
𝑎 = 1 𝑟 = 0𝑎 = 0
𝑟 = 0
𝑄 𝑠𝑡, 𝑎 ← 1 − 𝛼 𝑄 𝑠𝑡, 𝑎 + 𝛼(𝑟 + 𝛾max𝑄)
更新式
𝑎 = 1
𝑟 = 1
𝑎 = 0
𝑟 = 0
𝑎 = 1
𝑟 = 0
𝑠𝑡 = [1 1]
𝑠𝑡 = [1 0]
Q 𝑠𝑡, 0 = 0
Q 𝑠𝑡, 1 = 0
Q 𝑠𝑡, 0 = 0
Q 𝑠𝑡, 1 = 0
Q 𝑠𝑡, 0 = 0
Q 𝑠𝑡, 1 = 0
Q値とは
それぞれの状態で
行動の選びやすさ
を示す値
初めはすべて0にしておく
FRISK FRISK
FRISK
操作
傾ける
操作
操作
傾ける
傾ける
食
2019/9/25 27
学ぶ手順
𝑠𝑡 = [0 1]
𝑎 = 1 𝑟 = 0
𝑎 = 1 𝑟 = 0𝑎 = 0
𝑟 = 0 𝑎 = 1
𝑟 = 1
𝑎 = 0
𝑟 = 0
𝑎 = 1
𝑟 = 0
𝑠𝑡 = [1 1]
𝑠𝑡 = [1 0]
Q 𝑠𝑡, 0 = 0
𝐐 𝒔 𝒕, 𝟏 = 𝟎
Q 𝑠𝑡, 0 = 0
Q 𝑠𝑡, 1 = 0
Q 𝑠𝑡, 0 = 0
Q 𝑠𝑡, 1 = 0
𝑄 [0 1], 1 ← 1 − 0.6 𝑄 [0 1], 1 + 0.6(0 + 0.8max𝑄)
「ケース:閉」から「操作」を選んだとする
以下のように設定
𝛼 = 0.6
𝛾 = 0.8
𝑄 𝑠𝑡, 𝑎 ← 1 − 𝛼 𝑄 𝑠𝑡, 𝑎 + 𝛼(𝑟 + 𝛾max𝑄)
次の状態の
最も大きいQ値
= 1 − 0.6 𝑄 [0 1], 1 + 0.6 0 + 0.8 × 0 = 0 変わらず2019/9/25 28
変化
学ぶ手順
𝑠𝑡 = [0 1]
𝑎 = 1 𝑟 = 0
𝑎 = 1 𝑟 = 0𝑎 = 0
𝑟 = 0 𝒂 = 𝟏
𝒓 = 𝟏
𝑎 = 0
𝑟 = 0
𝑎 = 1
𝑟 = 0
𝑠𝑡 = [1 1]
𝑠𝑡 = [1 0]
Q 𝑠𝑡, 0 = 0
Q 𝑠𝑡, 1 = 0
𝐐 𝒔 𝒕, 𝟎 = 𝟎
𝑄 𝑠𝑡, 1 = 0
Q 𝑠𝑡, 0 = 0
Q 𝑠𝑡, 1 = 0
𝑄 [1 1], 0 ← 1 − 0.6 𝑄 [1 1], 0 + 0.6 𝟏 + 0.8 × 0 = 0.6
「ケース:開、FRISK:あり」から「食べる」を選んだとする
𝑄 𝑠𝑡, 𝑎 ← 1 − 𝛼 𝑄 𝑠𝑡, 𝑎 + 𝛼(𝑟 + 𝛾max𝑄)
2019/9/25 29
学ぶ手順
𝑠𝑡 = [0 1]
𝑎 = 1 𝑟 = 0
𝑎 = 1 𝑟 = 0𝑎 = 0
𝑟 = 0 𝑎 = 1
𝑟 = 1
𝑎 = 0
𝑟 = 0
𝑎 = 1
𝑟 = 0
𝑠𝑡 = [1 1]
𝑠𝑡 = [1 0]
Q 𝑠𝑡, 0 = 0
Q 𝑠𝑡, 1 = 0
𝐐 𝒔 𝒕, 𝟎 = 𝟎. 𝟔
Q 𝑠𝑡, 1 = 0
Q 𝑠𝑡, 0 = 0
Q 𝑠𝑡, 1 = 0
「ケース:開、FRISK:なし」の状態
報酬が得られるとQ値に値が入る
2019/9/25 30
学ぶ手順
𝑠𝑡 = [0 1]
𝑎 = 1 𝑟 = 0
𝑎 = 1 𝑟 = 0𝑎 = 0
𝑟 = 0 𝑎 = 1
𝑟 = 1
𝑎 = 0
𝑟 = 0
𝒂 = 𝟏
𝒓 = 𝟎
𝑠𝑡 = [1 1]
𝑠𝑡 = [1 0]
Q 𝑠𝑡, 0 = 0
Q 𝑠𝑡, 1 = 0
Q 𝑠𝑡, 0 = 0
Q 𝑠𝑡, 1 = 0
Q 𝑠𝑡, 0 = 0
𝐐 𝒔 𝒕, 𝟏 = 𝟎
𝑄 [1 0], 1 ← 1 − 0.6 𝑄 [1 0], 1 + 0.6(0 + 0.8 × 0)
「ケース:開、FRISK:あり」から「食べる」を選んだとする
𝑄 𝑠𝑡, 𝑎 ← 1 − 𝛼 𝑄 𝑠𝑡, 𝑎 + 𝛼(𝑟 + 𝛾max𝑄)
2019/9/25 31
学ぶ手順
𝑠𝑡 = [0 1]
𝑎 = 1 𝑟 = 0
𝑎 = 1 𝑟 = 0𝑎 = 0
𝑟 = 0 𝑎 = 1
𝑟 = 1
𝑎 = 0
𝑟 = 0
𝑎 = 1
𝑟 = 0
𝑠𝑡 = [1 1]
𝑠𝑡 = [1 0]
Q 𝑠𝑡, 0 = 0
𝐐 𝒔 𝒕, 𝟏 = 𝟎
Q 𝑠𝑡, 0 = 0.6
Q 𝑠𝑡, 1 = 0
Q 𝑠𝑡, 0 = 0
Q 𝑠𝑡, 1 = 0
𝑄 [0 1], 1 ← 1 − 0.6 𝑄 [0 1], 1 + 0.6(0 + 0.8max𝑄)
もう一度、「ケース:閉」から「操作」を選んだとする
𝑄 𝑠𝑡, 𝑎 ← 1 − 𝛼 𝑄 𝑠𝑡, 𝑎 + 𝛼(𝑟 + 𝛾max𝑄)
次の状態の
最も大きいQ値
= 1 − 0.6 𝑄 [0 1], 1 + 0.6 0 + 0.8 × 0.6 = 0.288 変化2019/9/25 32
学ぶ手順
𝑠𝑡 = [0 1]
𝑎 = 1 𝑟 = 0
𝑎 = 1 𝑟 = 0𝑎 = 0
𝑟 = 0 𝑎 = 1
𝑟 = 1
𝑎 = 0
𝑟 = 0
𝑎 = 1
𝑟 = 0
𝑠𝑡 = [1 1]
𝑠𝑡 = [1 0]
Q 𝑠𝑡, 0 = 0
𝐐 𝒔 𝒕, 𝟏 = 𝟎
Q 𝑠𝑡, 0 = 0.6
Q 𝑠𝑡, 1 = 0
Q 𝑠𝑡, 0 = 0
Q 𝑠𝑡, 1 = 0
𝑄 [0 1], 1 ← 1 − 0.6 𝑄 [0 1], 1 + 0.6(0 + 0.8max𝑄)
もう一度、「ケース:閉」から「操作」を選んだとする
𝑄 𝑠𝑡, 𝑎 ← 1 − 𝛼 𝑄 𝑠𝑡, 𝑎 + 𝛼(𝑟 + 𝛾max𝑄)
次の状態の
最も大きいQ値
= 1 − 0.6 𝑄 [0 1], 1 + 0.6 0 + 0.8 × 0.6 = 0.288 変化2019/9/25 33
学ぶ手順
𝑠𝑡 = [0 1]
𝑎 = 1 𝑟 = 0
𝑎 = 1 𝑟 = 0𝑎 = 0
𝑟 = 0
𝑎 = 1
𝑟 = 1
𝑎 = 0
𝑟 = 0
𝑎 = 1
𝑟 = 0
𝑠𝑡 = [1 1]
𝑠𝑡 = [1 0]
Q 𝑠𝑡, 0 = 0
Q 𝑠𝑡, 1 = 0.288
Q 𝑠𝑡, 0 = 0.6
Q 𝑠𝑡, 1 = 0
Q 𝑠𝑡, 0 = 0
Q 𝑠𝑡, 1 = 0
Q値の大きい選択をすると報酬が得られる。
それぞれの行動に答えがなくともQ値というものを使って自ら報酬が得ら
れる行動を選択できるようになる。
2019/9/25 34
テーブルで書ける
状態[1 1]の場合
参照 出力
行動0を選択
行動
0 1
状態 [0 1] 0 0.7
[1 1] 0.8 0.4
[1 0] 0 0.2
強化学習(Qラーニング)はこの表を自動的に作成することに相当
2019/9/25 35
追加の説明
Q値が同じとき
同じQ値の中から
ランダムに行動を選ぶ
ランダムな行動
Q 𝑠𝑡, 0 = 0.0
Q 𝑠𝑡, 𝟏 = 0.5
Q 𝑠𝑡, 2 = 0.2
Q 𝑠𝑡, 𝟑 = 0.5
Q 𝑠𝑡, 𝟒 = 0.5
𝑠𝑡 = [0 1]
𝑎 = 1 𝑟 = 0
𝑎 = 1 𝑟 = 0𝑎 = 0
𝑟 = 0
𝑎 = 1
𝑟 = 1
𝑎 = 0
𝑟 = 0
𝑎 = 1
𝑟 = 0
𝑠𝑡 = [1 1]
𝑠𝑡 = [1 0]
Q 𝑠𝑡, 0 = 0
Q 𝑠𝑡, 1 = 0.288
Q 𝑠𝑡, 0 = 0.6
Q 𝑠𝑡, 1 = 0
Q 𝑠𝑡, 0 = 0
Q 𝑠𝑡, 1 = 0
1,3,4のいずれかの
行動をランダムに選ぶ
ある確率で
Q値に関係なく
行動を選ぶ
深層強化学習でも
設定が必須な機能 本来選ばれる
行動
ランダムに選ばれた行動
2019/9/25 36
プログラムで実装する
# coding:utf-8
import numpy as np
def random_action():
return np.random.choice([0, 1])
def get_action(next_state, episode):
ns = next_state[0]+next_state[1]*2-1
epsilon = 0.5 * (1 / (episode + 1))
if epsilon <= np.random.uniform(0,1):
a = np.where(q_table[ns]==q_table[ns].max())[0]
next_action= np.random.choice(a)
else:
next_action= random_action()
return next_action
def step(state, action):
reward = 0
if state[0]==0:
if action==1:
state = [1,1]
else:
if state[1]==1:
if action==0:
state = [1,0]
reward= 1
else:
state = [0,1]
else:
if action==1:
state = [0,1]
return state, reward
def update_Qtable(q_table, state, action, reward, next_state):
gamma = 0.9
alpha = 0.5
ns = next_state[0]+next_state[1]*2-1
s = state[0]+state[1]*2-1
next_maxQ=max(q_table[ns])
q_table[s, action] = (1 - alpha) * q_table[s, action] +¥
alpha * (reward+ gamma * next_maxQ)
return q_table
max_number_of_steps = 5
num_episodes = 10
q_table = np.zeros((3, 2))
for episode in range(num_episodes):
state = [0,1]
episode_reward= 0
for t in range(max_number_of_steps): #1???s?̃??[?v
action = get_action(state, episode) # a_{t+1}
next_state, reward = step(state, action)
print(state, action, reward)
episode_reward+= reward #? V? ヌ?チ
q_table= update_Qtable(q_table, state, action, reward, next_state)
state = next_state
print('episode: %d total reward %d' %(episode+1, episode_reward))
print(q_table)
Q値を基に次の行動を決める
Q値の更新
行動による状態と報酬の更新
ランダムな行動
変数の設定
2019/9/25 37
変数の設定
max_number_of_steps = 5
num_episodes = 10
q_table = np.zeros((3, 2))
for episode in range(num_episodes):
state = [0,1]
episode_reward = 0
ほかの処理
1エピソードでの行動の回数
エピソードの回数
行動
0 1
状態 [0 1] 0 0.7
[1 1] 0.8 0.4
[1 0] 0 0.2
Q値のテーブル
𝒔 𝒕 = [𝟎 𝟏]
𝑎 = 1 𝑟 = 0
𝑎 = 1 𝑟 = 0𝑎 = 0
𝑟 = 0
𝑎 = 1
𝑟 = 1
𝑎 = 0
𝑟 = 0
𝑎 = 1
𝑟 = 0
𝑠𝑡 = [1 1]
𝑠𝑡 = [1 0]
Q 𝑠𝑡, 0 = 0
Q 𝑠𝑡, 1 = 0.288
Q 𝑠𝑡, 0 = 0.6
Q 𝑠𝑡, 1 = 0
Q 𝑠𝑡, 0 = 0
Q 𝑠𝑡, 1 = 0
報酬の合計
Q値を基に次の行動を決める
Q値の更新
行動による状態と報酬の更新
ランダムな行動
変数の設定
2019/9/25 38
次の行動&ランダム行動
def random_action():
return np.random.choice([0, 1])
def get_action(next_state, episode):
ns = next_state[0]+next_state[1]*2-1
epsilon = 0.5 * (1 / (episode + 1))
if epsilon <= np.random.uniform(0, 1):
a = np.where(q_table[ns]==q_table[ns].max())[0]
next_action = np.random.choice(a)
else:
next_action = random_action()
return next_action
Q値を基に次の行動を決める
Q値の更新
行動による状態と報酬の更新
ランダムな行動
変数の設定
ランダムな行動をとるため
の関数を作っておく
深層強化学習でも必要
ある確率でランダムな
行動を起こすように
最も大きいQ値を持つ行動を選択
このように書くことで、最も大きい
Q値となる行動が複数の場合には
リストで値が得られる。
Q 𝑠𝑡, 0 = 0.0
Q 𝑠𝑡, 𝟏 = 0.5
Q 𝑠𝑡, 2 = 0.2
Q 𝑠𝑡, 𝟑 = 0.5
Q 𝑠𝑡, 𝟒 = 0.5
1,3,4のいずれかの
行動をランダムに選ぶ
2019/9/25 39
状態の更新
def step(state, action):
reward = 0
if state[0]==0:
if action==1:
state = [1,1]
else:
if state[1]==1:
if action==0:
state = [1,0]
reward = 1
else:
state = [0,1]
else:
if action==1:
state = [0,1]
return state, reward
𝒔 𝒕 = [𝟎 𝟏]
𝑎 = 1 𝑟 = 0
𝑎 = 1 𝑟 = 0𝑎 = 0
𝑟 = 0
𝑎 = 1
𝑟 = 1
𝑎 = 0
𝑟 = 0
𝑎 = 1
𝑟 = 0
𝑠𝑡 = [1 1]
𝑠𝑡 = [1 0]
Q 𝑠𝑡, 0 = 0
Q 𝑠𝑡, 1 = 0.288
Q 𝑠𝑡, 0 = 0.6
Q 𝑠𝑡, 1 = 0
Q 𝑠𝑡, 0 = 0
Q 𝑠𝑡, 1 = 0
Q値を基に次の行動を決める
Q値の更新
行動による状態と報酬の更新
ランダムな行動
変数の設定
状態遷移図通りの行動
確認しましょう。
2019/9/25 40
Q値の更新
def update_Qtable(q_table, state, action, reward, next_state):
gamma = 0.9
alpha = 0.5
ns = next_state[0]+next_state[1]*2-1
s = state[0]+state[1]*2-1
next_maxQ=max(q_table[ns])
q_table[s, action] = (1 - alpha) * q_table[s, action] +alpha * (reward + gamma * next_maxQ)
return q_table
𝑄 𝑠𝑡, 𝑎 ← 1 − 𝛼 𝑄 𝑠𝑡, 𝑎 + 𝛼(𝑟 + 𝛾max𝑄)
更新式
Q値を基に次の行動を決める
Q値の更新
行動による状態と報酬の更新
ランダムな行動
変数の設定
2019/9/25 41
実行結果
[[0. 1.15432465]
[0. 1.55835535]
[1.9273458 0. ]]
[0, 1] 1 0
[1, 1] 0 1
[1, 0] 1 0
[0, 1] 1 0
[1, 1] 0 1
episode : 10 total reward 2
[[0. 0.]
[0. 0.]
[0. 0.]]
[0, 1] 0 0
[0, 1] 0 0
[0, 1] 0 0
[0, 1] 1 0
[1, 1] 1 0
episode : 1 total reward 0
𝑠𝑡 = [0 1]
𝑎 = 1 𝑟 = 0
𝑎 = 1 𝑟 = 0𝑎 = 0
𝑟 = 0
𝑎 = 1
𝑟 = 1
𝑎 = 0
𝑟 = 0
𝑎 = 1
𝑟 = 0
𝑠𝑡 = [1 1]
𝑠𝑡 = [1 0]
Q 𝑠𝑡, 0 = 0
Q 𝑠𝑡, 1 = 0
Q 𝑠𝑡, 0 = 0
Q 𝑠𝑡, 1 = 0
Q 𝑠𝑡, 0 = 0
Q 𝑠𝑡, 1 = 0
𝑠𝑡 = [0 1]
𝑎 = 1 𝑟 = 0
𝑎 = 1 𝑟 = 0𝑎 = 0
𝑟 = 0
𝑎 = 1
𝑟 = 1
𝑎 = 0
𝑟 = 0
𝑎 = 1
𝑟 = 0
𝑠𝑡 = [1 1]
𝑠𝑡 = [1 0]
Q 𝑠𝑡, 0 = 0
Q 𝑠𝑡, 1 = 1.15
Q 𝑠𝑡, 0 = 1.92
Q 𝑠𝑡, 1 = 0
Q 𝑠𝑡, 0 = 0
Q 𝑠𝑡, 1 = 1.55
食
食
𝑠𝑡 = [0 1]
𝑠𝑡 = [1 0]
𝑠𝑡 = [1 1]
𝑠𝑡 = [0 1]
𝑠𝑡 = [1 0]
𝑠𝑡 = [1 1]
2019/9/25 42
目次
• 深層強化学習とは
• 強化学習
• 深層学習
• 深層強化学習
• 実験結果
2019/9/25 43
深層学習とは
ディープニューラルネットワーク
Deep Neural Network, DNN
畳み込みニューラルネットワーク
Convolution Neural Network, CNN
ニューラルネットワーク
Neural Network, NN 従来の技術
ブレークスルー
得意分野:未来予測や自動作文 得意分野:ノイズ除去や画像生成得意分野:画像認識
オートエンコーダー
Auto Encoder, AE
リカレントニューラルネットワーク
Recurrnet Neural Network, RNN
深層学習
深層学習とはニューラルネットワークの発展版
2019/9/25 44
パーセプトロン
𝑥1
𝑥2
1
𝑦1
𝑦2
ノード
入力層 出力層
リンク
パーセプトロンの基本構造
2019/9/25 45
AERNNCNN
DNN
NN
この時代にできたこと
学習スイッチ回答スイッチ
反射型光センサ
青透明のふた
LED
1000
千円
1000
日本銀行券
5か所の色の濃さ(明るさ)を測る
明るさ
位置
お札の分別機
中野馨(元東大教授)から写真をいただきました。
現役で動いているそうです。
2019/9/25 46
ニューラルネットワーク
𝑥1
𝑥2
1
ℎ1
1
ℎ2
ℎ3
𝑦1
𝑦2
ノード
リンク
入力層 中間層 出力層
リンク
ニューラルネットワークの基本構造
2019/9/25 47
AERNNCNN
DNN
NN
深層学習
𝑦1
𝑦2
ℎ1
𝑚
1
ℎ2
𝑚
ℎ3
𝑚
ℎ 𝑛 𝑚
1
𝑥1
𝑥2
1
ℎ1
1
1
ℎ2
1
ℎ3
1
ℎ 𝑛1
1
入力層 出力層中間層
𝑥 𝑛 𝑥
𝑦𝑛 𝑥
ディープニューラルネットワークの構造
2019/9/25 48
AERNNCNN
DNN
NN
深層学習
入力層 出力層中間層
リカレントニューラルネットワークの構造
1
𝑠2
𝑦1𝑠1
𝑦2
1
𝑥2
𝑥1
「過去の情報も使って答えを出す」
特徴
2019/9/25 49
AERNNCNN
DNN
NN
これがキーとなった技術
• 自動翻訳
• 作文(ニュース、小説、俳句)
• 音声認識
• 音声(歌声)合成
• (音声)対話システム
• 読唇術
• 株価・為替の予測
• 天気予報
• 消費電力予想
• などなど
2019/9/25 50
こんなことが簡単にできる
単語を入力>>> 吾輩
自動作文結果: 吾輩 は また 主人 の 顔 を 見 て <unk> 主人 は 「 先生 」 と 云う 。
単語を入力>>> 我
自動作文結果: 我 は 猫 で ある 。
単語を入力>>> 猫
自動作文結果: 猫 の もの は なかなか ない 。
単語を入力>>> 僕
自動作文結果: 僕 は どう し て いる の か 」
単語を入力>>> 机
自動作文結果: 机 の 上 に は ある が <unk> この 時 は 吾輩 の ごとく <unk> この
時 に は <unk> その 時 に は <unk> その 時 に は <unk> その 時 に は <unk> その
時 に は <unk>
単語を入力>>> 時計
自動作文結果: 時計 は 無論 <unk> 主人 は また 一 人 に なっ た 。
単語を入力>>> 主人
自動作文結果: 主人 は また 主人 の 顔 を し て いる 。
2019/9/25 51
畳み込みニューラルネットワーク
畳み込みニューラルネットワークの構造
出力は10個
一列に並べて
ニューラルネットワークの入力にする.
畳み込み
(画像が増える)
集めてから増やす
畳み込み プーリング
プーリング
(画像が小さくなる)
特徴
「画像処理に強い」
2019/9/25 52
AERNNCNN
DNN
NN
これがキーとなった技術
• 物体認識
• 顔認識
• 文字認識
• 不良品検査
• 画像生成
• 画像処理用だと思われがちだが、画像のみに関わら
ず、音・テキスト処理など幅広く利用されている
2019/9/25 53
https://medium.com/@jonathan_hui/real-
time-object-detection-with-yolo-yolov2-
28b1b93e2088
画像中にある物
体を認識する研
究画像
こんなことが簡単にできる
2019/9/25 54
オートエンコーダー
入力層 出力層中間層
オートエンコーダーの構造
特徴
「教師データを必要とせず、勝手に学習できる」
これは「まねっこ」を得意としています。
2019/9/25 55
AERNNCNN
DNN
NN
これがキーとなった技術
顔の表情を変える 絵を混ぜ合わせる
2019/9/25 56
深層生成モデルを用いたマ
ルチモーダル学習
https://www.slideshare.net/masa_s/ss-
62920389
画風を変換するアルゴリズム
https://research.preferred.jp/
2015/09/chainer-gogh/
学習手順
学習データ1 教師データ1
学習データ2 教師データ2
学習データ3 教師データ3
学習データN 教師データN
学習モデル
テストデータ 答え
①データを集めるプログラム ②学習モデルを
生成するプログラム
③学習結果を使うプログラム
2019/9/25 57
プログラムで書く
𝑥1
𝑥2
1
ℎ1
1
1
ℎ2
1
ℎ3
1
𝑦1
𝑦2
ℎ4
1
ℎ5
1
ℎ6
1
ℎ1
2
1
ℎ2
2
ℎ3
2
ℎ4
2
ℎ5
2
ℎ6
2
𝑥3 𝑦3
𝑦4
l1 = L.Linear(3, 6)
6つのノードに
つながっている
ソ
フ
ト
マ
ッ
ク
ス
・
ク
ロ
ス
エ
ン
ト
ロ
ピ
ー
出力
F.softmax_cross_entropy
教師データ
入力
h1 = F.relu(self.l1(x))
xをl1で処理してから
ReLU関数で処理し,
それをh1とする
y = self.l3(h2)
h2をl3で処理し,
それをyとする
l2 = L.Linear(6, 6)
6つのノードに
つながっている
l13= L.Linear(6, 4)
4つのノードに
つながっている
h2 = F.relu(self.l2(h1))
h1をl2で処理してから
ReLU関数で処理し,
それをh2とする
2019/9/25 58
プログラムで実装する
# -*- coding: utf-8 -*-
import numpy as np
import chainer
import chainer.functions as F
import chainer.links as L
import chainer.initializers as I
from chainer import training
from chainer.training import extensions
from sklearn.datasets import load_digits
from sklearn.model_selection importtrain_test_split
class MyChain(chainer.Chain):
def __init__(self):
super(MyChain, self).__init__()
with self.init_scope():
self.conv1=L.Convolution2D(1,16, 3, 1, 1) # 1層目の畳み込み層(フィルタ数は16)
self.conv2=L.Convolution2D(16, 64, 3, 1, 1) # 2層目の畳み込み層(フィルタ数は64)
self.l3=L.Linear(256,10) #クラス分類用
def __call__(self,x):
h1 = F.max_pooling_2d(F.relu(self.conv1(x)),2, 2) # 最大値プーリングは2×2,活性化関数はReLU
h2 = F.max_pooling_2d(F.relu(self.conv2(h1)),2, 2)
y = self.l3(h2)
return y
epoch = 20
batchsize = 100
# データの作成
digits = load_digits()
data_train, data_test, label_train, label_test = train_test_split(digits.data, digits.target, test_size=0.2)
data_train= data_train.reshape((len(data_train),1, 8, 8))#8x8の行列に変更
data_test = data_test.reshape((len(data_test), 1, 8, 8))#
data_train= (data_train).astype(np.float32)
data_test = (data_test).astype(np.float32)
train = chainer.datasets.TupleDataset(data_train, label_train)
test = chainer.datasets.TupleDataset(data_test, label_test)
# ニューラルネットワークの登録
model = L.Classifier(MyChain(), lossfun=F.softmax_cross_entropy)
optimizer = chainer.optimizers.Adam()
optimizer.setup(model)
# イテレータの定義
train_iter = chainer.iterators.SerialIterator(train, batchsize)# 学習用
test_iter = chainer.iterators.SerialIterator(test, batchsize, repeat=False, shuffle=False)# 評価用
# アップデータの登録
updater = training.StandardUpdater(train_iter, optimizer)
# トレーナーの登録
trainer = training.Trainer(updater, (epoch, 'epoch'))
# 学習状況の表示や保存
trainer.extend(extensions.LogReport())#ログ
trainer.extend(extensions.Evaluator(test_iter, model))# エポック数の表示
trainer.extend(extensions.PrintReport(['epoch', 'main/loss', 'validation/main/loss','main/accuracy', 'validation/main/accuracy', 'elapsed_time'] ))#計算状態の表示
#trainer.extend(extensions.dump_graph('main/loss'))#ニューラルネットワークの構造
#trainer.extend(extensions.PlotReport(['main/loss', 'validation/main/loss'], 'epoch',file_name='loss.png'))#誤差のグラフ
#trainer.extend(extensions.PlotReport(['main/accuracy', 'validation/main/accuracy'],'epoch', file_name='accuracy.png'))#精度のグラフ
#trainer.extend(extensions.snapshot(), trigger=(100, 'epoch'))# 再開のためのファイル出力
#chainer.serializers.load_npz("result/snapshot_iter_500",trainer)#再開用
# 学習開始
trainer.run()
# 途中状態の保存
chainer.serializers.save_npz("result/CNN.model", model)
ネットワークの設定
実行の設定
データの読み込み
変数などの設定
2019/9/25 59
ネットワークの設定
class MyChain(chainer.Chain):
def __init__(self):
super(MyChain, self).__init__()
with self.init_scope():
self.conv1=L.Convolution2D(1, 16, 3, 1, 1) # 1層目の畳み込み層(フィルタ数は16)
self.conv2=L.Convolution2D(16, 64, 3, 1, 1) # 2層目の畳み込み層(フィルタ数は64)
self.l3=L.Linear(256, 10) #クラス分類用
def __call__(self, x):
h1 = F.max_pooling_2d(F.relu(self.conv1(x)), 2, 2) # 最大値プーリングは2×2,活性化関数はReLU
h2 = F.max_pooling_2d(F.relu(self.conv2(h1)), 2, 2)
y = self.l3(h2)
return y
出力は10個
一列に並べて
ニューラルネットワークの入力にする.
畳み込み
(画像が増える)
集めてから増やす
畳み込み プーリング
プーリング
(画像が小さくなる)
ネットワークの設定
実行の設定
データの読み込み
変数などの設定
2019/9/25 60
実行結果
>python mnist.py
epoch main/loss validation/main/loss main/accuracy validation/main/accuracy elapsed_time
1 5.46093 2.02874 0.152 0.4025 0.327999
2 1.56683 0.914883 0.485714 0.695833 0.588135
3 0.697993 0.539513 0.778 0.838333 0.878696
4 0.409058 0.362783 0.881429 0.895 1.17705
5 0.291148 0.294352 0.917857 0.926667 1.46583
6 0.22085 0.229565 0.943333 0.940833 1.76791
7 0.17051 0.203781 0.955714 0.945833 2.0469
8 0.145418 0.165399 0.963571 0.958333 2.3306
9 0.118005 0.158992 0.974667 0.959167 2.61197
10 0.107213 0.143939 0.972857 0.961667 2.90681
11 0.0862933 0.119904 0.982 0.968333 3.17674
12 0.0750509 0.112208 0.983571 0.968333 3.47204
13 0.0680135 0.099219 0.987857 0.973333 3.74383
14 0.0627778 0.10707 0.989333 0.975833 4.02273
15 0.0472515 0.0970788 0.992857 0.973333 4.3252
16 0.0462799 0.0840994 0.994286 0.980833 4.63587
17 0.0419316 0.0802513 0.993333 0.978333 4.93195
18 0.0374346 0.0763587 0.994286 0.9775 5.20532
19 0.0336064 0.0713333 0.995333 0.980833 5.52942
20 0.0319847 0.0736449 0.997143 0.979167 5.82344
経過時間
テストデータの損失と精度
学習データの損失と精度
エポック数
2019/9/25 61
目次
• 深層強化学習とは
• 強化学習
• 深層学習
• 深層強化学習
• 実験結果
2019/9/25 62
強化学習との違い
状態[1 1]の場合
入力 出力
行動0を選択
𝑥2
𝑥1
𝑥3
ℎ2
ℎ1
ℎ3
ℎ4
𝑦1
𝑦2
状態[1 1]の場合
参照 出力
行動0を選択
行動
0 1
状態 [0 1] 0 0.7
[1 1] 0.8 0.4
[1 0] 0 0.2
強化学習(Qラーニング)の場合:表を参照して行動を選択
深層強化学習の場合:表の代わりにニューラルネットワーク
2019/9/25 63
何が難しかったのか?
リンクの更新
𝑥1
𝑥2
1
ℎ1
1
ℎ2
ℎ3
𝑦1
𝑦2
入力層 中間層 出力層
学習用データ1 教師用データ1出力値1入力 出力 比較
②入力 ③比較
④更新
リンクの更新
学習用データN 教師用データN出力値N入力 出力 比較
⑤繰り返す
②出力
①データを作る ①データを作る
ニューラルネットワーク
ニューラルネットワークの学習手順
学習データに対応した教師データが必ずある
2019/9/25 64
何が難しかったのか?
強化学習の学習
行動1手目
行動2手目
行動3手目
行動N手目
ゲームなど
深層強化学習 ②判定
③手順と判定を考慮した学習
①行動する
報酬が得られたときにそれまでの行動手順を学習する
行動に対する教師データがない
2019/9/25 65
学習の仕組み
…
…
環境の入力
行動
A
行動
B
0.8
2.6
各行動の
評価値
• 環境を入力とし、出力層で各行動の評価値を出力するような
ニューラルネットワークを学習
• 目標となる行動(正解データ)がないのに、どうやってニューラル
ネットワークのパラメータを最適化するの?2019/9/25 66
学習の仕組み
…
…
環境の入力
行動
A
行動
B
0.8
2.6
各行動の
評価値
• 環境を入力とし、出力層で各行動の評価値を出力するような
ニューラルネットワークを学習
• 目標となる行動(正解データ)がないのに、どうやってニューラル
ネットワークのパラメータを最適化するの?2019/9/25 67
プログラムで実装する# coding:utf-8
import numpy as np
import chainer
import chainer.functions as F
import chainer.links as L
import chainerrl
import copy
class QFunction(chainer.Chain):
def __init__(self, obs_size, n_actions, n_hidden_channels=10):
super(QFunction, self).__init__()
with self.init_scope():
self.l1=L.Linear(obs_size, n_hidden_channels)
self.l2=L.Linear(n_hidden_channels, n_hidden_channels)
self.l3=L.Linear(n_hidden_channels, n_actions)
def __call__(self,x, test=False):
h1 = F.relu(self.l1(x))
h2 = F.relu(self.l2(h1))
y = chainerrl.action_value.DiscreteActionValue(self.l3(h2))
return y
def random_action():
return np.random.choice([0, 1])
def step(_state, action):
state = _state.copy()
reward = 0
if state[0]==0 and state[1]==1:
if action==1:
state[0] = 1
elif state[0]==1 and state[1]==1:
if action==1:
state[0] = 0
elifaction==0:
state[1] = 0
reward = 1
elif state[0]==1 and state[1]==0:
if action==1:
state[0] = 0
state[1] = 1
return np.array(state), reward
gamma = 0.8
alpha = 0.5
max_number_of_steps = 15 #1試行のstep数
num_episodes = 50 #総試行回数
q_func = QFunction(2, 2)
optimizer= chainer.optimizers.Adam(eps=1e-2)
optimizer.setup(q_func)
explorer = chainerrl.explorers.LinearDecayEpsilonGreedy(start_epsilon=1.0,
end_epsilon=0.0, decay_steps=num_episodes,
random_action_func=random_action)
replay_buffer = chainerrl.replay_buffer.PrioritizedReplayBuffer(capacity=10** 6)
phi = lambda x: x.astype(np.float32,copy=False)
agent = chainerrl.agents.DoubleDQN(
q_func, optimizer, replay_buffer, gamma, explorer,
replay_start_size=50,update_interval=1, target_update_interval=10, phi=phi)
#agent.load('agent')
for episode in range(num_episodes): #試行数分繰り返す
state = np.array([0,1])
R = 0
reward = 0
done = True
for t in range(max_number_of_steps): #1試行のループ
action = agent.act_and_train(state, reward)
next_state, reward = step(state, action)
print(state, action, reward, next_state)
R += reward #報酬を追加
state = next_state
agent.stop_episode_and_train(state, reward, done)
print('episode: ', episode+1, 'R', R, 'statistics:', agent.get_statistics())
agent.save('agent')
ネットワークを設定する
Qネットワークの更新
行動による状態と報酬の更新
ランダムな行動
変数の設定
実行の設定
2019/9/25 68
Qネットワークの設定class QFunction(chainer.Chain):
def __init__(self, obs_size, n_actions, n_hidden_channels=10):
super(QFunction, self).__init__()
with self.init_scope():
self.l1=L.Linear(obs_size, n_hidden_channels)
self.l2=L.Linear(n_hidden_channels, n_hidden_channels)
self.l3=L.Linear(n_hidden_channels, n_actions)
def __call__(self, x, test=False):
h1 = F.relu(self.l1(x))
h2 = F.relu(self.l2(h1))
y = chainerrl.action_value.DiscreteActionValue(self.l3(h2))
return y
𝑥1
𝑥2
1
ℎ1
1
1
ℎ2
1
ℎ3
1
𝑦1
𝑦2
ℎ4
1
ℎ5
1
ℎ6
1
ℎ1
2
1
ℎ2
2
ℎ3
2
ℎ4
2
ℎ5
2
ℎ6
2
𝑥3 𝑦3
𝑦4
self.l1=L.Linear(obs_size, n_hidden_channels)
出力
入力
h1 = F.relu(self.l1(x))
xをl1で処理してから
ReLU関数で処理し,
それをh1とする
y = chainerrl.action_value.DiscreteActionValue(self.l3(h2))
h2をl3で処理し,
それをyとする
self.l2=L.Linear(n_hidden_channels, n_hidden_channels)
self.l3=L.Linear(n_hidden_channels, n_actions)
h2 = F.relu(self.l2(h1))
h1をl2で処理してから
ReLU関数で処理し,
それをh2とする
ネットワークを設定する
Q値の更新
行動による状態と報酬の更新
ランダムな行動
変数の設定
実行の設定
2019/9/25 69
Qネットワークの更新
1: q_func = QFunction(2, 2)
2: optimizer = chainer.optimizers.Adam(eps=1e-2)
3: optimizer.setup(q_func)
4: explorer = chainerrl.explorers.LinearDecayEpsilonGreedy(start_epsilon=1.0, end_epsilon=0.0,
decay_steps=num_episodes, random_action_func=random_action)
5: replay_buffer = chainerrl.replay_buffer.PrioritizedReplayBuffer(capacity=10 ** 6)
6: phi = lambda x: x.astype(np.float32, copy=False)
7: agent = chainerrl.agents.DoubleDQN(
q_func, optimizer, replay_buffer, gamma, explorer,
replay_start_size=50, update_interval=1, target_update_interval=10, phi=phi)
ネットワークを設定する
Q値の更新
行動による状態と報酬の更新
ランダムな行動
変数の設定
実行の設定
1: Qネットーワークの定義
2,3: オプティマイザの宣言とセットアップ
4: ε-グリーディ法による行動設定(ε初期値1.0,終了時0,εの減衰率の設定,
行動選択方法の設定(ランダム))
5: replay bufferのサイズ定義(10^6)
6: 型をfloat32に変換するためのラムダ関数
7: エージェントの宣言。
replay bufferに50個行動が溜まったらNNを更新。更新間隔は1ステップ毎。
target networkの更新間隔は10ステップ
2019/9/25 70
実行結果
[0 1] 1 0 [1 1]
[1 1] 0 1 [1 0]
[1 0] 1 0 [0 1]
[0 1] 1 0 [1 1]
[1 1] 0 1 [1 0]
[1 0] 1 0 [0 1]
[0 1] 1 0 [1 1]
[1 1] 0 1 [1 0]
[1 0] 1 0 [0 1]
[0 1] 1 0 [1 1]
[1 1] 0 1 [1 0]
[1 0] 1 0 [0 1]
[0 1] 1 0 [1 1]
[1 1] 0 1 [1 0]
[1 0] 1 0 [0 1]
episode : 50 R 5 statistics: [('average_q', 0.13289504909633182),
('average_loss', 0.012309854020095313), ('n_updates', 700)]
𝑠𝑡 = [0 1]
𝑎 = 1 𝑟 = 0
𝑎 = 1 𝑟 = 0𝑎 = 0
𝑟 = 0
𝑎 = 1
𝑟 = 1
𝑎 = 0
𝑟 = 0
𝑎 = 1
𝑟 = 0
𝑠𝑡 = [1 1]
𝑠𝑡 = [1 0]
食
𝑠𝑡 = [0 1]
𝑠𝑡 = [1 0]
𝑠𝑡 = [1 1]
𝑠𝑡 = [1 1]
𝑠𝑡 = [1 0] 𝑠𝑡 = [0 1]
食
𝑠𝑡 = [0 1]
𝑠𝑡 = [1 0]
𝑠𝑡 = [1 1]
𝑠𝑡 = [1 1]
𝑠𝑡 = [1 0] 𝑠𝑡 = [0 1]
食
𝑠𝑡 = [0 1]
𝑠𝑡 = [1 0]
𝑠𝑡 = [1 1]
𝑠𝑡 = [1 1]
𝑠𝑡 = [1 0] 𝑠𝑡 = [0 1]
食
𝑠𝑡 = [0 1]
𝑠𝑡 = [1 0]
𝑠𝑡 = [1 1]
𝑠𝑡 = [1 1]
𝑠𝑡 = [1 0] 𝑠𝑡 = [0 1]
食
𝑠𝑡 = [0 1]
𝑠𝑡 = [1 0]
𝑠𝑡 = [1 1]
𝑠𝑡 = [1 1]
𝑠𝑡 = [1 0] 𝑠𝑡 = [0 1]
2019/9/25 71
目次
• 深層強化学習とは
• 強化学習
• 深層学習
• 深層強化学習
• 実験結果
2019/9/25 72
パソコン
カメラ
実験の構成
カメラは
パソコンに接続
サーボモータとLEDは
Arduino(マイコンボード)
に接続
パソコンとArduinoはシリアル通信2019/9/25 73
カメラテストプログラム
サーボモータとLEDがどのように映っているのか確認するためのプログラム
camera.py
ウィンドウにこのような画像が表示
されるので、位置を調整する。
# coding:utf-8
import cv2
n0 = 0
cap = cv2.VideoCapture(0)
while True:
ret, frame = cap.read()
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
xp = int(frame.shape[1]/2)
yp = int(frame.shape[0]/2)
d = 200
cv2.rectangle(gray, (xp-d, yp-d), (xp+d, yp+d), color=0,
thickness=10)
cv2.imshow('gray', gray)
gray = cv2.resize(gray[yp-d:yp + d, xp-d:xp + d],(32, 32))
c =cv2.waitKey(10)
if c == 48:
cv2.imwrite('img/0/{0}.png'.format(n0), gray)
n0 = n0 + 1
elif c == 27:
break
cap.release()
「1」:画像の保存
「ESC」:終了
2019/9/25 74
Arduinoとは
簡単に電子工作ができるマイコン
• 書き込みボードが内蔵している
• 実行するために回路を作らなくてよい
• ジャンプワイヤーがボードに刺さる
• C言語ライクなプログラム
• シリアル通信がすぐに使える
12345678910111213
GND
AREF
SDA
SCL A5A4A3A2A1A0
Vin
GND
GND
5V
3.3V
RESET
IOREF
UNO
ATMEGA328P-PU
L
TX
RX
ON
~
~
~
~
~
~
DIGITAL (PWM~)
ANALOG IN
POWER
0
デジタルピングランドピン
アナログピン
グランドピン
5Vピン
リセットボタン
USBコネクタ
電源ジャック
電源用LED
確認用LED
通信用LED
2019/9/25 75
通信の内容
パソコン
UNO
Arduino
開閉:p
傾ける:i
報酬あり:1
報酬なし:0
初期化のため
の指令:c
状態の初期化
何度も繰り返す
2019/9/25 76
Pythonでシリアル通信
>pip install pyserial
ライブラリ(pyserial)のインストール
> python
>>> import serial
>>> ser = serial.Serial("COM6")
>>> print(ser)
Serial<id=0x1ff19904b00, open=True>(port='COM6', baudrate=9600, bytesize=8,
parity='N', stopbits=1, timeout=None, xonxoff=False, rtscts=False, dsrdtr=False)
>>> ser.close()
インストールの確認
2019/9/25 77
送受信プログラム
PythonからArduinoに送信する。
Arduinoは受信したデータをそのままPython へ送信する。
PythonはArduinoから受信したデータをそのまま表示する。
UNO
ABC¥n
ABC¥n
2019/9/25 78
Pythonの送受信プログラム
import serial
import time
ser = serial.Serial('COM6', 9600)
ser.write(b“ABC¥n")
while True:
c = ser.read()
print(c)
if c == b'¥n':
break
ser.close()
1文字受信
文字を送信
受信した文字をコンソールに表示
¥nを受信したら終了
2019/9/25 79
Arduinoの送受信プログラム
void setup() {
Serial.begin(9600);
}
void loop() {
if(Serial.available()>0){
char c = Serial.read();
Serial.print(c);
}
}
受信したかどうかを調べる
1文字受信
その文字を送信
2019/9/25 80
プログラムで実装する
ネットワークを設定する
Qネットワークの更新
カメラ画像の処理
ランダムな行動
変数の設定
実行の設定
# coding:utf-8
import numpy as np
import chainer
import chainer.functions as F
import chainer.links as L
import chainerrl
import copy
import time
import serial
import cv2
ser = serial.Serial("COM6")
cap = cv2.VideoCapture(0)
class QFunction(chainer.Chain):
def __init__(self):
super(QFunction, self).__init__()
with self.init_scope():
self.conv1 = L.Convolution2D(1, 8, 5, 1, 0) # 1層目の畳み込み層(フィルタ数は8)
self.conv2 = L.Convolution2D(8, 16, 5, 1, 0) # 2層目の畳み込み層(フィルタ数は16)
self.l3 = L.Linear(400, 2) # アクションは2通り
def __call__(self, x, test=False):
h1 = F.max_pooling_2d(F.relu(self.conv1(x)), ksize=2, stride=2)
h2 = F.max_pooling_2d(F.relu(self.conv2(h1)), ksize=2, stride=2)
y = chainerrl.action_value.DiscreteActionValue(self.l3(h2))
return y
def random_action():
return np.random.choice([0, 1])
def step(_state, action):
reward = 0
if action==0:
ser.write(b"p")
else:
ser.write(b"i")
# time.sleep(1.0)
reward = ser.read();
return int(reward)
def capture(ndim=3):
ret, frame = cap.read()
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
xp = int(frame.shape[1]/2)
yp = int(frame.shape[0]/2)
d = 200
cv2.rectangle(gray, (xp-d, yp-d), (xp+d, yp+d), color=0, thickness=10)
cv2.imshow('gray', gray)
gray = cv2.resize(gray[yp-d:yp + d, xp-d:xp + d],(32, 32))
env = np.asarray(gray, dtype=np.float32)
if ndim == 3:
return env[np.newaxis, :, :] # 2次元→3次元テンソル(replay用)
else:
return env[np.newaxis, np.newaxis, :, :] # 4次元テンソル(判定用)
gamma = 0.8
alpha = 0.5
max_number_of_steps = 15 #1試行のstep数
num_episodes = 500 #総試行回数
q_func = QFunction()
optimizer = chainer.optimizers.Adam(eps=1e-2)
optimizer.setup(q_func)
explorer = chainerrl.explorers.LinearDecayEpsilonGreedy(start_epsilon=1.0, end_epsilon=0.0, decay_steps=num_episodes, random_action_func=random_action)
replay_buffer = chainerrl.replay_buffer.PrioritizedReplayBuffer(capacity=10 ** 6)
phi = lambda x: x.astype(np.float32, copy=False)
agent = chainerrl.agents.DoubleDQN(
q_func, optimizer, replay_buffer, gamma, explorer,
replay_start_size=50, update_interval=1, target_update_interval=10, phi=phi)
#agent.load('agent')
time.sleep(5.0)
for episode in range(num_episodes): #試行数分繰り返す
state = np.array([0])
R = 0
reward = 0
done = True
ser.write(b"c")
for t in range(max_number_of_steps): #1試行のループ
camera_state = capture(ndim=3)
action = agent.act_and_train(camera_state, reward)
reward = step(state, action)
print(t, action, reward)
R += reward #報酬を追加
agent.stop_episode_and_train(capture(ndim=3), reward, done)
# print('episode : %d total reward %d' %(episode+1, R))
print('episode : ', episode+1, 'R', R, 'statistics:', agent.get_statistics())
ser.close()
cap.release()
agent.save('agent')
行動を送信+報酬を受信
frisk_exp.py
2019/9/25 81
Qネットワーク
class QFunction(chainer.Chain):
def __init__(self):
super(QFunction, self).__init__()
with self.init_scope():
self.conv1 = L.Convolution2D(1, 8, 5, 1, 0) # 1層目の畳み込み層(フィルタ数は8)
self.conv2 = L.Convolution2D(8, 16, 5, 1, 0) # 2層目の畳み込み層(フィルタ数は16)
self.l3 = L.Linear(400, 2) # アクションは2通り
def __call__(self, x, test=False):
h1 = F.max_pooling_2d(F.relu(self.conv1(x)), ksize=2, stride=2)
h2 = F.max_pooling_2d(F.relu(self.conv2(h1)), ksize=2, stride=2)
y = chainerrl.action_value.DiscreteActionValue(self.l3(h2))
return y
深層強化学習用の出力用関数
出力は2個
一列に並べて
ニューラルネットワークの入力にする.
畳み込み
(画像が増える)
集めてから増やす
畳み込み プーリング
プーリング
(画像が小さくなる)
行動
2019/9/25 82
Qネットワークの更新
for t in range(max_number_of_steps): #1試行のループ
camera_state = capture(ndim=3)
action = agent.act_and_train(camera_state, reward)
reward = step(state, action)
print(t, action, reward)
R += reward #報酬を追加
agent.stop_episode_and_train(capture(ndim=3), reward, done)
カメラ画像の取得
Qネットワークの更新と
次の行動決定
行動を送信し、
報酬を受信
Qネットワークの更新
Qネットワークの更新
カメラ画像の処理
行動を送信+報酬を受信
次の行動の決定
2019/9/25 83
カメラ画像の処理def capture(ndim=3):
ret, frame = cap.read()
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
xp = int(frame.shape[1]/2)
yp = int(frame.shape[0]/2)
d = 200
cv2.rectangle(gray, (xp-d, yp-d), (xp+d, yp+d), color=0, thickness=10)
cv2.imshow('gray', gray)
gray = cv2.resize(gray[yp-d:yp + d, xp-d:xp + d],(32, 32))
env = np.asarray(gray, dtype=np.float32)
if ndim == 3:
return env[np.newaxis, :, :] # 2次元→3次元テンソル(replay用)
else:
return env[np.newaxis, np.newaxis, :, :] # 4次元テンソル(判定用)
画面の中央だけ使う
2019/9/25 84
送受信
def step(_state, action):
reward = 0
if action==0:
ser.write(b"p")
else:
ser.write(b"i")
reward = ser.read();
return int(reward)
パソコン
UNO
Arduino
開閉:p
傾ける:i
報酬あり:1
報酬なし:0
何度も繰り返す2019/9/25 85
Arduino #include <Servo.h>
Servo mServo;
int state[2];
void setup() {
mServo.attach(9);
mServo.write(10);
delay(500);
Serial.begin(9600);
pinMode(10, OUTPUT);
state[0] = 0;
state[1] = 1;
digitalWrite(10,LOW);
}
void loop() {
if (Serial.available() > 0) {
char c = Serial.read();
if (c == 'p') {
if (state[0] == 0) {
Serial.print("0");
mServo.write(90);
delay(500);
state[0] = 1;
}
else {
Serial.print("0");
mServo.write(10);
delay(500);
state[0] = 0;
state[1] = 1;
digitalWrite(10, LOW);
}
}
else if (c == 'i') {
if (state[0] == 1 && state[1] == 1) {
Serial.print("1");
digitalWrite(10, HIGH);
state[1] = 0;
}
else {
Serial.print("0");
}
}
else if (c == 'c') {
state[0] = 0;
state[1] = 1;
digitalWrite(10,LOW);
mServo.write(10);
delay(500);
}
}
}
受信時の処理
報酬の送信
サーボモータの角度を変える
状態の遷移
LEDの点灯状態を変える
if (c == 'p') {
if (state[0] == 0) {
Serial.print("0");
mServo.write(10);
delay(500);
state[0] = 0;
state[1] = 1;
digitalWrite(10, LOW);
}
初期設定
受信したか?
受信時の処理
No
Yes
Frisk_Ar
2019/9/25 86
うまくできました
0 0 0 操作(開ける)
1 1 1 傾ける(食べる)
2 0 0 操作(閉める)
3 0 0 操作(開ける)
4 1 1 傾ける(食べる)
5 0 0 操作(開ける)
6 0 0 操作(開ける)
7 1 1 傾ける(食べる)
8 0 0 操作(開ける)
9 0 0 操作(開ける)
10 1 1 傾ける(食べる)
11 0 0 操作(開ける)
12 0 0 操作(開ける)
13 1 1 傾ける(食べる)
14 0 0 操作(開ける)
episode : 500 R 5 statistics:
[('average_q', 0.5532538031364947),
('average_loss',
0.028086873774230445), ('n_updates',
7450)]
食
食
食
食
食
FRISK FRISK
FRISK
開ける
傾ける
閉める
2019/9/25 87
うまくできなかった時のために・・・
ネットワークを設定する
Qネットワークの更新
画像の読み取り
ランダムな行動
変数の設定
実行の設定
# coding:utf-8
import numpy as np
import chainer
import chainer.functions as F
import chainer.links as L
import chainerrl
import copy
import time
import serial
import cv2
ser = serial.Serial("COM6")
cap = cv2.VideoCapture(0)
class QFunction(chainer.Chain):
def __init__(self):
super(QFunction, self).__init__()
with self.init_scope():
self.conv1 = L.Convolution2D(1, 8, 5, 1, 0) # 1層目の畳み込み層(フィルタ数は8)
self.conv2 = L.Convolution2D(8, 16, 5, 1, 0) # 2層目の畳み込み層(フィルタ数は16)
self.l3 = L.Linear(400, 2) # アクションは2通り
def __call__(self, x, test=False):
h1 = F.max_pooling_2d(F.relu(self.conv1(x)), ksize=2, stride=2)
h2 = F.max_pooling_2d(F.relu(self.conv2(h1)), ksize=2, stride=2)
y = chainerrl.action_value.DiscreteActionValue(self.l3(h2))
return y
def random_action():
return np.random.choice([0, 1])
def step(_state, action):
reward = 0
if action==0:
ser.write(b"p")
else:
ser.write(b"i")
# time.sleep(1.0)
reward = ser.read();
return int(reward)
# USBカメラから画像を取得(ラズパイ用)
def capture(ndim=3):
ret, frame = cap.read()
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
xp = int(frame.shape[1]/2)
yp = int(frame.shape[0]/2)
d = 200
cv2.rectangle(gray, (xp-d, yp-d), (xp+d, yp+d), color=0, thickness=10)
cv2.imshow('gray', gray)
gray = cv2.resize(gray[yp-d:yp + d, xp-d:xp + d],(32, 32))
env = np.asarray(gray, dtype=np.float32)
if ndim == 3:
return env[np.newaxis, :, :] # 2次元→3次元テンソル(replay用)
else:
return env[np.newaxis, np.newaxis, :, :] # 4次元テンソル(判定用)
gamma = 0.8
alpha = 0.5
max_number_of_steps = 15 #1試行のstep数
num_episodes = 500 #総試行回数
q_func = QFunction()
optimizer = chainer.optimizers.Adam(eps=1e-2)
optimizer.setup(q_func)
explorer = chainerrl.explorers.LinearDecayEpsilonGreedy(start_epsilon=1.0, end_epsilon=0.0, decay_steps=num_episodes, random_action_func=random_action)
replay_buffer = chainerrl.replay_buffer.PrioritizedReplayBuffer(capacity=10 ** 6)
phi = lambda x: x.astype(np.float32, copy=False)
agent = chainerrl.agents.DoubleDQN(
q_func, optimizer, replay_buffer, gamma, explorer,
replay_start_size=50, update_interval=1, target_update_interval=10, phi=phi)
#agent.load('agent')
time.sleep(5.0)
for episode in range(num_episodes): #試行数分繰り返す
state = np.array([0])
R = 0
reward = 0
done = True
ser.write(b"c")
for t in range(max_number_of_steps): #1試行のループ
camera_state = capture(ndim=3)
action = agent.act_and_train(camera_state, reward)
reward = step(state, action)
print(t, action, reward)
R += reward #報酬を追加
agent.stop_episode_and_train(capture(ndim=3), reward, done)
# print('episode : %d total reward %d' %(episode+1, R))
print('episode : ', episode+1, 'R', R, 'statistics:', agent.get_statistics())
ser.close()
cap.release()
agent.save('agent')
行動による状態変化+報酬
frisk_exp_image.py
2019/9/25 88
まとめ
2019/9/25 89
• 強化学習
• Qラーニングを手計算で
• 深層学習
• 歴史を含めて紹介
• 深層強化学習
• 組み合わせて実行
• 実験結果
• 実機に応用

実機で動かす深層強化学習(画像なし)