【3目並べで学ぶ強化学習】Q-LearningとDQNを徹底解説:Web解析にも使える! 強化学習超入門(2)(2/2 ページ)
3目並べで強化学習を行うと、どうなるのだろうか。強化学習のアルゴリズムの一つである「Q-Learning」を説明しつつ、Q-LearningにDeep Learningを組み合わせた「Deep Q-Network」を使って、強化学習を実装する方法を紹介する。
ChainerRLの環境構築の仕方と基本的な使い方
ChainerRLは、Pythonから利用します。2019年2月現在、Pythonのバージョンは2.7以上、もしくは3.5.1以上で動作が保障されています。今回はPython3.6.5を使います。Pythonの環境設定が完了したら、下記でChainerRLをインストールします。
pip install chainerrl==5.2.0
これにより、他に必要な「NumPy」や「Chainer」などのライブラリを自動でインストールできます。これだけで準備は完了です。
では、DQNを実装していきましょう。※本稿のサンプルでは、「ChainerRLで三目並べを深層強化学習(Double DQN)してみた - Qiita」のソースコードを引用して一部改変させていただきました。
まずはDeep Learningのネットワーク構成は、今回は「中間層2層」「レイヤー数は81」「活性化関数を“leaky_relu”」としています。ここはタスクによってさまざまで、ゲームの場合は画像を入力としたCNN(Convolutional Neural Network)を使用することもあります。
dqn.py import chainer import chainer.functions as F import chainer.links as L import chainerrl class QFunctions(chainer.Chain): def __init__(self, obs_size, n_actions, n_hidden_channels=81): super().__init__( l0=L.Linear(obs_size, n_hidden_channels), l1=L.Linear(n_hidden_channels,n_hidden_channels), l2=L.Linear(n_hidden_channels,n_hidden_channels), l3=L.Linear(n_hidden_channels,n_actions) ) def __call__(self, x, test=False): h = F.leaky_relu(self.l0(x)) h = F.leaky_relu(self.l1(h)) h = F.leaky_relu(self.l2(h)) return chainerrl.action_value.DiscreteActionValue(self.l3(h))
18行目の「chainerrl.action_value.DiscreteActionValue」でQ値の推定値を出力できます。
次に、強化学習をするに当たって、エージェント(学習するオブジェクト自身)を作成します。
q_func = QFunctions(obs_size,n_actions) optimizer = chainer.optimizers.Adam(eps=1e-2) optimizer.setup(q_func) # 報酬の割引率 gamma = 0.95 # epsilon-greedyを使ってたまに冒険 explorer = chainerrl.explorers.LinearDecayEpsilonGreedy( start_epsilon=1.0, end_epsilon=0.3, decay_steps=50000, random_action_func=ra.random_action ) replay_buffer = chainerrl.replay_buffer.ReplayBuffer(capacity=10**6) agent = chainerrl.agents.DQN( q_func, optimizer, replay_buffer, gamma, explorer, replay_start_size=500, update_interval=1, target_update_interval=100 )
「dqn.py」で作成した「QFunctions」などでエージェントを作成する際に必要な変数を定義した後、11行目の「chainerrl.agents.DQN」でエージェントを定義できます。
5行目で定義した「gamma」は割引率と呼ばれ、報酬につながったがあまりにも報酬から遠い行動を少し低めの価値に設定するためのパラメーターです。また7行目で定義した「explorer」とは探索に関する方針を定義するものです。今回、最初の方はデータがなく学習できないため、ランダムに行動する探索の割合を高く設定しています。ランダムの行動をする内に良い行動、悪い行動を学んでいくので、徐々にランダムの行動の割合を減らし、Q値を活用した行動を多くする方針にしています。
さらに10行目で定義した「replay_buffer」は、今までの状態と行動をためておいて、Q値を更新して使う際に、ここからサンプリングして使用するもので、DQNの学習を高い精度で行うための工夫です。
DQNを使って3目並べを学習
これら用いて実際に3目並べを学習していきます。下記は今回の3目並べの盤面やランダムに行動する関数を定義したものです。ここはやりたいことに合わせて適宜ルールを設定します。
train.py from bord import Board from randomAct import RandomActor from dqn import QFunctions import chainer import chainerrl import numpy as np if __name__ == "__main__": b = Board() ra = RandomActor(b)
今回両プレイヤーともコンピュータということで2つ目のエージェントを用意します。また、3目並べの場合は盤面が3×3なので、「obs_size」(2行目)を状態の、「n_actions」(4行目)を行動の次元数とし、両方とも9に設定しています。
# 環境の次元数 obs_size = 9 # 行動の次元数 n_actions = 9 q_func = QFunctions(obs_size,n_actions) optimizer = chainer.optimizers.Adam(eps=1e-2) optimizer.setup(q_func) # 報酬の割引率 gamma = 0.95 # epsilon-greedyを使ってたまに冒険 explorer = chainerrl.explorers.LinearDecayEpsilonGreedy( start_epsilon=1.0, end_epsilon=0.3, decay_steps=50000, random_action_func=ra.random_action ) replay_buffer = chainerrl.replay_buffer.ReplayBuffer(capacity=10**6) # agentの生成 agent_p1 = chainerrl.agents.DQN( q_func, optimizer, replay_buffer, gamma, explorer, replay_start_size=500, update_interval=1, target_update_interval=100 ) agent_p2 = chainerrl.agents.DQN( q_func, optimizer, replay_buffer, gamma, explorer, replay_start_size=500, update_interval=1, target_update_interval=100)
ここから学習スタートです。今回は2万回学習(2万回試合)させます。今回は報酬として勝った場合「+1」、負けた場合「−1」と設計しました。そして、1ゲームが終わったら、「stop_episode_and_train」で報酬が与えられ(27行目)、それ以前に行った状態と行動のセットの価値推定に用いられます(29行目)。
# 学習ゲーム回数 n_episodes = 20000 miss = 0 win = 0 draw = 0 # 繰り返し実行 for i in range(1, n_episodes+1): b.reset() reward = 0 agents = [agent_p1,agent_p2] turn = np.random.choice([0,1]) last_state = None while not b.done: action = agents[turn].act_and_train(b.board.copy(),reward) b.move(action,1) #ゲームが終わった場合 if b.done == True: if b.winner == 1: reward = 1 win += 1 elif b.winner == 0: draw += 1 else: reward = -1 if b.missed is True: miss += 1 agents[turn].stop_episode_and_train(b.board.copy(), reward, True) if agents[1 if turn == 0 else 0].last_state is not None and b.missed is False: agents[1 if turn == 0 else 0].stop_episode_and_train(last_state, reward*-1, True) else: last_state = b.board.copy() b.board = b.board * -1 turn = 1 if turn == 0 else 0
下記コマンドで学習が走ります。
python train.py
最初は探索によるランダムでの行動が多く学習できていないので、ミスの回数(置けないところに置いてしまうこと)が多くなります。しかし、学習が進んでくると、「勝たないと報酬がもらえない」と学習するため、勝利するよう動き、ミスの回数が減っていきます。さらに先手/後手両方とも学習するため、学習回数が増えるにつれ引き分けの回数が増えていくことが観察できました。
次に、3目並べを2万回試合させたエージェントと私が対戦したところ、私自身も最適解が分かっているので毎回引き分けになりました。故に強化学習がうまくいっていることが分かります。
まとめ
連載第2回目では、強化学習アルゴリズムの一つであるQ-Learning、DQNについて解説しました。さらに3目並べを例にしてChainerRLを活用し、実際にDQNを実装してみました。
第3回目では、これまで学んだ仕組みを利用して、リクルートのメインビジネスであるWebサービスへの適用について解説します。問題設定は3目並べのときと同様ですが、Webサービスの場合、ゲームと異なり「シミュレーションで学習できない」「状態の定義が曖昧になる」といった問題が起こります。それに対してどのように対処したかを解説していきます。
著者プロフィール
蓑田和麻(みのだかずま)
大学4年から修士2年まで統計学を専攻し、2016年リクルートホールディングスに新卒入社。リクルートテクノロジーズ配属後、データテクノロジーラボ部でスタッフ業務効率化のためのプロダクト開発や原稿校閲のプロダクトの導入、推進業務を行いながら、機械学習技術の研究開発に従事。趣味は麻雀と人狼。
Copyright © ITmedia, Inc. All Rights Reserved.
関連記事
- 囲碁プロ棋士に勝ったAI「Alpha Go」で使われた、「強化学習」って何?
昨今、多くのサービスに使われ、注目を浴びる「機械学習」。しかし、機械学習にはさまざまな学習方法が存在する。今回は、学習方法を比較しつつ、「強化学習」の概要を紹介する。 - ニューラルネットワーク、Deep Learning、Convolutional Neural Netの基礎知識と活用例、主なDeep Learningフレームワーク6選
最近注目を浴びることが多くなった「Deep Learning」と、それを用いた画像に関する施策周りの実装・事例について、リクルートグループにおける実際の開発経験を基に解説していく連載。初回は、ニューラルネットワーク、Deep Learning、Convolutional Neural Netの基礎知識と活用例、主なDeep Learningフレームワーク6選を紹介する。 - BFF(Backends For Frontends)超入門――Netflix、Twitter、リクルートテクノロジーズが採用する理由
マイクロサービス/API時代のフロントエンド開発に求められる技術の1つBackends For Frontends(BFF)について解説する連載。初回は「超入門」としてBFFの概要や事例を中心に紹介する。