DDN's Library

強化学習に関する論文まとめやちょっとしたシステム開発について

論文紹介: Bridging the Gap Between Value and Policy Based Reinforcement Learning

紹介する論文

Bridging the Gap Between Value and Policy Based Reinforcement Learning

概要

  • on-policyの学習の安定性とoff-policyのサンプル効率の高さを備えた手法

  • エントロピー正則化強化学習の考え方に基づいた時に導き出される,価値関数と政策関数の関係式に基づいて両者を最適化

  • 離散行動空間タスクでA3CやDQNと比べて良い成果をあげた

f:id:ddnpaa:20191103142120p:plain

1. モチベーション

on-policy,off-policy手法の特徴

  • on-policyによる学習

 →学習の安定性は高いが,サンプル効率が悪い

  • off-policyによる学習

 →サンプル効率は高いが,学習の安定性は低い

on-policyの安定性とoff-policyのサンプル効率を兼ね備えた手法が理想!!

2.手法

結論から言うと,以下のように表される誤差関数を通して,政策,価値関数を最適化する

{\begin{align}
O_{\mathrm{PCL}}(\theta, \phi)=\sum_{s_{i: i+d} \in E} \frac{1}{2} C\left(s_{i: i+d}, \theta, \phi\right)^{2}
\end{align}}

 {\begin{aligned} C\left(s_{i: i+d}, \theta, \phi\right)=-V_{\phi}\left(s_{i}\right)+\gamma^{d} V_{\phi}\left(s_{i+d}\right) +\sum_{j=0}^{d-1} \gamma^{j} \biggl[r\left(s_{i+j}, a_{i+j}\right)-\tau \log \pi_{\theta}(a_{i+j} | s_{i+j})\biggl]    \end{aligned}}

学習には,ある部分軌跡 {\boldsymbol{s}_{i: i+d} \equiv\left(s_{i}, a_{i}, \cdots, \boldsymbol{s}_{i+d-1}, a_{i+d-1}, \boldsymbol{s}_{i+d}\right)} を用いる.

これにより,

  1. 過去のサンプルの利用によるサンプル効率化
  2. 確率的な政策の利用による学習の安定化

の2点を実現できる.

1. エントロピー正則化付き強化学習

以下の関数{O_{ENT}(s,\pi)}を考える.

 {\begin{align}
O_{\mathrm{ENT}}(s, \pi)=O_{\mathrm{ER}}(s, \pi)+\tau \mathbb{H}(s, \pi)
\end{align}}

ただし,{O_{\mathrm{ER}}(s, \pi)}{\mathbb{H}(s, \pi)}

{\begin{align}
O_{\mathrm{ER}}(s, \pi)=\sum \pi(a | s)\left[r(s, a)+\gamma O_{\mathrm{ER}}\left(s^{\prime}, \pi\right)\right], \quad \text { where } s^{\prime}=f(s, a)
\end{align}}

{\begin{align}
\mathbb{H}(s, \pi)=\sum_{a} \pi(a | s)\left[-\log \pi(a | s)+\gamma \mathbb{H}\left(s^{\prime}, \pi\right)\right]
\end{align}}

である.

ここで,{O_{ENT}(s,\pi)}は以下のように再帰的に表すことができる.

{\begin{align}
O_{\mathrm{ENT}}(s, \pi)=\sum_{a} \pi(a | s)\left[r(s, a)-\tau \log \pi(a | s)+\gamma O_{\mathrm{ENT}}\left(s^{\prime}, \pi\right)\right]
\end{align}}

2. 政策と価値関数の関係性

次に最適な状態価値{V^{\ast}(s)}と政策{\pi^{\ast}}の関係について考える.

まず,政策をボルツマン分布で表現すると

{\begin{align}
\pi^{*}(a | s)=\frac{\exp (r(s, a)+\gamma V^{\ast}(s^{\prime})) / \tau}{\sum_{a} \exp {(r(s, a)+\gamma V^{\ast}(s^{\prime})) / \tau}}
\end{align}}

となる.

ここでこれを,「1. エントロピー正則化付き強化学習」で導き出した{
O_{\mathrm{ENT}}(s, \pi)=\sum_{a} \pi(a | s)\left[r(s, a)-\tau \log \pi(a | s)+\gamma O_{\mathrm{ENT}}\left(s^{\prime}, \pi\right)\right]
}に代入すると

{\begin{align}
V {\ast}(s)=O_{\mathrm{ENT}}(s, \pi^{\ast})=\tau \log \sum_{a} \exp {(r(s, a)+\gamma V^{\ast}(s^{\prime})) / \tau}
\end{align}}

となる.

さらにこれを変形すると,

{\begin{align}
\exp (V^{\ast}(s) / \tau)=\sum_{a} \exp \{(r(s, a)+\gamma V^{*}(s^{\prime})) / \tau\}
\end{align}}

最後に,この式を{\pi^{\ast}}の分母に代入すると

{\begin{align}
\pi^{*}(a | s)=\frac{\exp (r(s, a)+\gamma V^{\ast}(s^{\prime})) / \tau}{\exp V^{\ast}(s) / \tau}
\end{align}}

となる.

3. 誤差関数の導出

先ほどの{\pi^{\ast}}の式に対して,両辺に対数をとって変形すると

{\begin{align}
V^{\ast}(s)-\gamma V^{\ast}(s^{\prime})=r(s, a)-\tau \log \pi^{\ast}(a | s)
\end{align}}

の方程式が得られる.

さらに,{V^{\ast}(s’)}に関して,tステップ目まで展開すると以下のようになる.

{\begin{align}
V^{\ast}(s_{1})-\gamma^{t-1} V^{\ast}(s_{t})= \sum_{i=1}^{t-1} \gamma^{i-1}[r(s_{i}, a_{i})-\tau \log \pi^{\ast}(a_{i} | s_{i})]
\end{align}}

ここで,この方程式が成立する状態価値関数,政策が最適であるため,この方程式の左辺と右辺の2乗誤差を誤差関数とする! (両辺が等しい→両辺の差が0→両辺の二乗誤差を誤差関数として最小化を目指す!)

{\begin{align}
O_{\mathrm{PCL}}(\theta, \phi)=\sum_{s_{i: i+d} \in E} \frac{1}{2} C\left(s_{i: i+d}, \theta, \phi\right)^{2}
\end{align}}

 {\begin{aligned} C\left(s_{i: i+d}, \theta, \phi\right)=-V_{\phi}\left(s_{i}\right)+\gamma^{d} V_{\phi}\left(s_{i+d}\right) +\sum_{j=0}^{d-1} \gamma^{j} \biggl[r\left(s_{i+j}, a_{i+j}\right)-\tau \log \pi_{\theta}(a_{i+j} | s_{i+j})\biggl]    \end{aligned}}

3.メリット

1. サンプル効率が高い

誤差関数が全ての部分軌跡で成立するように学習を行う →リプレイバッファで格納した過去の軌跡を利用することができる(サンプル効率の向上)

2.政策の学習の安定性が高い

従来のoff-policy手法・・・Q学習をベースとしていたため,行動評価が決定的で不安定

本手法・・・行動評価が決定的でなく,かつエントロピー正則化により探索不足による収束の不安定性も緩和!

4.まとめ

エントロピー正則化付き強化学習の考え方により,on-policyとoff-policyのメリットを共存させたアルゴリズムを開発した

arxivライブラリを用いたSlackでの翻訳bot

「arxivAPIを叩いてsummaryをとってきて,その翻訳結果をSlackに投げる」という内容のブログが既に多く公開されています.

ただ,Pythonarxivライブラリを用いて処理を行なっているものが見当たらなかったため,これを用いて簡単に行う方法を掲載します.

流れとしては以下の通りです.

  1. arxivライブラリを用いてを情報を抽出する
  2. Googletranslatorライブラリを用いて翻訳
  3. Slackへ翻訳結果を返す

実行例

f:id:ddnpaa:20191024105508p:plain

さらに,herokuを用いて定期実行を設定することで,定期的に翻訳結果をslackに返すことができます.

1. arxivライブラリによるsummaryの抽出

はじめに,arxivライブラリを用いてsummaryの情報を抽出します.

今回は以下のようなフォーマットにするため,

  1. タイトル
  2. URL
  3. summary

の3つを抽出します.

''タイトル:
{}

URL:
{}

abstract 原文:
{}

abstract 日本語訳:
{}

arxiv.queryで情報を抽出します.今回は例として「off policy」という用語がabstractに含まれている論文のなかで,最も新しいものを1つ抽出します.

l = arxiv.query(query='abs:"off policy"',max_results=1,sort_by="lastUpdatedDate")

また,抽出したデータに対してKeyを指定することで,狙ったデータをさらに抽出することができます.詳しくは以下のリンク先をご参照ください.

https://note.nkmk.me/python-arxiv-api-download-rss/

今回は.[“title”],[“id”],[“summary”]でタイトル,URL,abstractを抽出します.

title=l[0]["title"]
url=l[0]["id"]
summary_en=l[0]["summary"]

実装コードまとめ

import arxiv
import time

l = arxiv.query(query='abs:"off policy"',max_results=1,sort_by="lastUpdatedDate")

#情報の抽出
title=l[0]["title"]
url=l[0]["id"]
summary_en=l[0]["summary"]

2. Googletranslatorライブラリを用いて翻訳

次に,抽出したデータを翻訳します.翻訳にはGoogletranslatorを用います.

from googletrans import Translator
translator = Translator() 

ここで,単に抽出したデータを翻訳関数に渡すと,改行により翻訳精度が落ちるため

summary_en = summary_en.replace('\n', ' ')

によって,改行を省きます.

翻訳はGoogletranslatorインスタンスのtranslate関数に,(翻訳したい文章,翻訳後の言語)を渡すことで行えます.

summary=translator.translate(summary_en,dest="ja").text

実装コードまとめ

from googletrans import Translator
translator = Translator() 

summary_en = summary_en.replace('\n', ' ')

summary=translator.translate(summary_en,dest="ja").text

3. slackへ翻訳結果を送信

次に,2で翻訳した結果をslackに送信します.

そのために,slackの拡張機能である「Incomming Webhook」を用います.

Incomming Webhookの設定

簡単に説明すると,以下の手順でWebhook URLを取得するのが目的となります.

  1. Slackをインストールし,チャンネルを作成する
  2. slackアプリストアの検索エンジンで「incoming-webhooks」を検索しページに飛ぶ
  3. incoming-webhooksを設定に追加する

f:id:ddnpaa:20191023180520p:plain

4.最後に得られる「Webhook URL」をコピーしておく

実装コード

まず,Webhook URLを変数に格納します.

slack_url ='Webhook URL'

続いて,2での翻訳結果を含めたタイトルなどの情報を,1で示したフォーマットにして変数に格納します.

text = '''タイトル:
{}

URL:
{}

abstract 原文:
{}

abstract 日本語訳:
{}


'''.format(title, url, summary_en,summary)

最後に,json形式で「requests.post」で渡して,slackに翻訳結果を送信します.

data = json.dumps({
'username': 'arxiv summary',
'text': text
})

requests.post(slack_url, data=data)

実装コードまとめ

import requests
import json

slack_url ='https://hooks.slack.com/services/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'

text = '''タイトル:
{}

URL:
{}

abstract 原文:
{}

abstract 日本語訳:
{}


'''.format(title, url, summary_en,summary)


data = json.dumps({
'username': 'arxiv summary',
'text': text
})

requests.post(slack_url, data=data)

4. herokuによる定期的に実行

定期的に実行するためにherokuを用います.

準備

会員登録をしてから以下の手順でコマンドを実行してください

  1. heroku login
  2. heroku create -a 任意の名前
  3. heroku buildpacks:set heroku/python -a 2で決めた名前
  4. 必要なライブラリが記述されたファイルを「requirements.txt」として作成
  5. git init
  6. heroku git:remote -a アプリ名 1.git add .
  7. git commit -m ‘init’
  8. git push heroku master

requirements.txtの中身

arxiv==0.5.1
googletrans==2.4.0
requests==2.21.0

テスト

ファイル名をmain.pyとした場合

heroku run python main.py

でプログラムが動作すればok

定期実行

  1. heroku addons:create scheduler:standard --app アプリ名
  2. heroku addons:open scheduler
  3. 以下の画面がブラウザで開くため,「Create job」をクリック

f:id:ddnpaa:20191023204601p:plain

4.「Choose an 〜〜」で実行頻度を設定,「Run Command」で実行コマンドを記述

f:id:ddnpaa:20191023204811p:plain

5.以下の画面でscheduleを確認

f:id:ddnpaa:20191023204841p:plain

まとめ

arxivで取得した文章を翻訳し,Slackに送信するプログラムを定期的に実行する方法を掲載しました. また,文章取得はarxivライブラリ,翻訳モデルはgoogletranslatorを用いるため,簡潔に実装することができました. 今後は,翻訳モデルを自分で構築して,自然言語処理の知見を高めようと考えております.

論文紹介:Reverse Curriculum Generation for Reinforcement Learning

 

紹介する論文

Reverse Curriculum Generation for Reinforcement Learning

概要

  • 目標地点付近で目標を達成しやすい状態を初期状態とする(徐々に初期位置に近づける)

  • 逆順に学習を行うことで,最終ゴールを知ることができ,局所解に陥りにくくなる

  • 単純な初期状態の場合にほぼ達成できないタスクで,比較的高い成功率を誇る

f:id:ddnpaa:20191014133929p:plain

1. モチベーション

強化学習における報酬設定に関する問題

  • スパースな報酬設定での学習
    →高次元空間を探索する場合,報酬が得られる頻度が極めて少なく(得られない場合も...),学習が進まない.

  • 密な報酬設定での学習
    →報酬設定のエンジニアリングが難しい

提案法

スパースな報酬設定において,初期状態を目標地点に近い状態とする!!

  • 目標地点の近くからエピソードを開始し,目標地点に到達する確率が高いため,スパースな報酬設定でも学習が進むと期待できる.

2. 仮定

提案法は,以下の3つの仮定をおいている.

  1. すべてのエピソードの開始時に、エージェントを任意の開始状態 {s_0∈S}にリセットできる

  2. {s_g∈S_g}となるような、少なくとも1つの状態{s_g}が存在する,つまり,最終状態が1つは存在する.

  3. すべての開始状態{S_0}と与えられた目標状態{s_g}は任意の行動によって遷移可能である.

3.良い初期状態の定義

良い初期状態を,「エージェントが時々目標に到達するが、常にではない状態」と定義する.

ここで,スパース報酬設定の場合,{R(\pi,s_0)}を以下のように定義すると,ある時間ステップ内で目標を達成する確率を表す. f:id:ddnpaa:20191014173325p:plain

この{R(\pi,s_0)}を利用して,{S_0 = \left\{s_0|R_{min}\lt R(\pi,s_0)\lt R_{max}\right\}}を満たすような初期状態{s_0}を出来るだけ利用する.

{R_{min}}{R_{max}}はハイパーパラメータ.成功確率の限界値を表す)

4. ゴール近くの初期状態の生成方法

初期状態の生成のために、直接,ゴール状態にノイズを加えると

  1. 取り得ない状態を生成してしまう可能性がある
  2. 各次元においては大した変化でなくても、全体としては大きくずれるような状態の可能性がある

以上の2点より,直接,ゴール状態にノイズを加えるのはよくない.

よって,一定ステップの間ノイズ的な行動を行い、実際に行動した結果を新たな初期状態として生成する.

5. 手法全体のアルゴリズム

  1. 「ゴールから{T_B}ステップの間,ランダムに行動を行なって,新たな状態を取得し{start_{new}}に格納」を繰り返す.
  2. {start_{new}}がMとなるまで,1を繰り返す
  3. {start_{new}}の中 から,{N_{new}}個サンプリングし、今回の初期状態抽出バッファ{starts}に加える
  4. 前のイテレーションで格納したバッファ{start_{old}}から{N_{old}}個を{starts}に加える(この{start_{old}}によって加えるサンプルは{R_{min}}以上{R_{max}}以下の条件を満たすサンプル)
  5. {starts}から初期状態を抽出して学習を行う
  6. {starts}から「{R_{min}}以上{R_{max}}以下のサンプル」を選択し、次の更新で用いる{start_{old}}として保存しておく

f:id:ddnpaa:20191014135313p:plain

今後の展望

個人的に気になる点

  • 論文内では「任意のon-policy手法で用いることができる」と記述があるが,off-policyでも利用可能に思えるが??