やっている事
現在,書籍(https://www.ohmsha.co.jp/book/9784274222535/)
とchainerのドキュメントを参考に,DQNを用いてOpen AI gymの倒立振子(cartpole.py)を通して深層強化学習の実装方法を学んでいます.
実現したいこと
学習済みのエージェントの保存・読み込みを行い,学習時と同程度のスコアを出せる(再利用)ような仕組みを作ろうと試みています
発生している問題
結論,学習時・保存時のエージェントのスコアと,保存したものを再度読み込んでテストした時のエージェントのスコアが大きく異なってしまっています.
エージェント保存時,.npzファイルと一緒に保存時のエピソードでのスコアもあとから確認できるようにdfにまとめて出力しているのですが,そのスコアが保存したエージェントを読み込んで使用した時の結果と一致しません(読み込んで使用した際,どのエピソードで保存されたモデルでも最大スコアである[R:200]に近い値が出てしまっている)
エラーは発生しておらず,実行自体はできている状態です.
以下が学習・保存時のスコアと,保存したものを読み込んで使用した際のスコアです.
※[num_ep]列がエージェントが保存された時のエピソード番号です(50エピソードごとに1つのエージェントを保存しています)
※同じ[num_ep]のエージェントが保存時と,読み込み時で対応するイメージです
-↓学習・保存時のスコア
num_ep | R | average_Q |
---|---|---|
0 | 34 | -0.006249658 |
50 | 44 | 16.69693047 |
100 | 29 | 32.16324093 |
150 | 200 | 48.54096041 |
200 | 200 | 80.91322302 |
250 | 170 | 94.64694452 |
-↓保存したエージェント読み込んで使用した際のスコア
num_ep | R | average_Q |
---|---|---|
0 | 195 | 98.00143342 |
50 | 199 | 97.67563928 |
100 | 189 | 97.38097469 |
150 | 186 | 97.1402428 |
200 | 197 | 96.96119497 |
250 | 179 | 96.77948363 |
学習・保存時のソースコード
python
1import gym #倒立振子(cartpole)の実行環境 2import numpy as np 3import time 4import chainer 5import chainer.functions as F 6import chainer.links as L 7import chainerrl 8import pandas as pd 9 10# Q-関数の定義 11class QFunction(chainer.Chain): 12 def __init__(self, obs_size, n_actions, n_hidden_channels=50): 13 super(QFunction, self).__init__() 14 with self.init_scope(): 15 self.l0=L.Linear(obs_size, n_hidden_channels) 16 self.l1=L.Linear(n_hidden_channels, n_hidden_channels) 17 self.l2=L.Linear(n_hidden_channels, n_actions) 18 def __call__(self, x, test=False): 19 h = F.tanh(self.l0(x)) 20 h = F.tanh(self.l1(h)) 21 return chainerrl.action_value.DiscreteActionValue(self.l2(h)) 22 23env = gym.make('CartPole-v0') 24 25gamma = 0.99 26alpha = 0.5 27max_number_of_steps = 200 #総試行回数 28num_episodes = 300 #総試行回数 29 30q_func = QFunction(env.observation_space.shape[0], env.action_space.n) 31optimizer = chainer.optimizers.Adam(eps=1e-2) 32optimizer.setup(q_func) 33explorer = chainerrl.explorers.LinearDecayEpsilonGreedy(start_epsilon=1.0, end_epsilon=0.1, decay_steps=num_episodes, random_action_func=env.action_space.sample) 34replay_buffer = chainerrl.replay_buffer.ReplayBuffer(capacity=10 ** 6) 35phi = lambda x: x.astype(np.float32, copy=False) 36agent = chainerrl.agents.DoubleDQN( 37 q_func, optimizer, replay_buffer, gamma, explorer, 38 replay_start_size=500, update_interval=1, target_update_interval=100, phi=phi) 39#agent.load('agent') 40 41train_analysis_df=pd.DataFrame(columns=['num_ep','R','average_Q']) 42saved_agent_df=pd.DataFrame(columns=['num_ep','R','average_Q']) 43for episode in range(num_episodes): #試行数分繰り返す 44 observation = env.reset() 45 done = False 46 reward = 0 47 R = 0 48 add_s=pd.Series(index=train_analysis_df.columns, dtype='object') 49 for t in range(max_number_of_steps): #1試行のループ 50 action = agent.act_and_train(observation, reward) 51 observation, reward, done, info = env.step(action) 52 R += reward 53 if done: 54 break 55 agent.stop_episode_and_train(observation, reward, done) 56 if episode % 10 == 0: 57 print('episode:', episode, 'R:', R, 'statistics:', agent.get_statistics()) 58 add_s['num_ep']=episode 59 add_s['R']=R 60 add_s['average_Q']=agent.get_statistics()[0][1] 61 add_s['end_t']=t 62 if episode % 50 == 0: 63 saved_agent_df=saved_agent_df.append(add_s,ignore_index=True) 64 agent.save('agent/cartpole/agent_ep{}'.format(episode)) 65 66saved_agent_df.to_csv('agent/cartpole/saved_agent_df.csv')
保存したエージェントを読み込んで使用する際のソースコード
python
1eps=[0,50,100,150,200,250] 2class QFunction(chainer.Chain): 3 def __init__(self, obs_size, n_actions, n_hidden_channels=50): 4 super(QFunction, self).__init__() 5 with self.init_scope(): 6 self.l0=L.Linear(obs_size, n_hidden_channels) 7 self.l1=L.Linear(n_hidden_channels, n_hidden_channels) 8 self.l2=L.Linear(n_hidden_channels, n_actions) 9 def __call__(self, x, test=False): 10 h = F.tanh(self.l0(x)) 11 h = F.tanh(self.l1(h)) 12 return chainerrl.action_value.DiscreteActionValue(self.l2(h)) 13 14env = gym.make('CartPole-v0') 15 16gamma = 0.99 17alpha = 0.5 18max_number_of_steps = 200 #総試行回数 19num_episodes = 300 #総試行回数 20 21 22 23 24test_log_df=pd.DataFrame(columns=['num_ep','R','average_Q','end_t']) 25for episode in eps: #試行数分繰り返す 26 q_func = QFunction(env.observation_space.shape[0], env.action_space.n) 27 optimizer = chainer.optimizers.Adam(eps=1e-2) 28 optimizer.setup(q_func) 29 explorer = chainerrl.explorers.LinearDecayEpsilonGreedy(start_epsilon=1.0, end_epsilon=0.1, decay_steps=num_episodes, random_action_func=env.action_space.sample) 30 replay_buffer = chainerrl.replay_buffer.ReplayBuffer(capacity=10 ** 6) 31 phi = lambda x: x.astype(np.float32, copy=False) 32 load_agent = chainerrl.agents.DoubleDQN( 33 q_func, optimizer, replay_buffer, gamma, explorer, 34 replay_start_size=500, update_interval=1, target_update_interval=100, phi=phi) 35 agent_pass='agent/cartpole/agent_ep{}'.format(episode) 36 load_agent.load(agent_pass) 37 observation = env.reset() 38 done = False 39 reward = 0 40 R = 0 41 add_s=pd.Series(index=train_analysis_df.columns, dtype='object') 42 for t in range(max_number_of_steps): #1試行のループ 43 #action = agent.act_and_train(observation, reward) 44 action = agent.act(observation) 45 observation, reward, done, info = env.step(action) 46 R += reward 47 if done: 48 break 49 add_s['num_ep']=episode 50 add_s['R']=R 51 add_s['average_Q']=agent.get_statistics()[0][1] 52 add_s['end_t']=t 53 test_log_df=test_log_df.append(add_s,ignore_index=True) 54 55test_log_df.to_csv('agent/cartpole/test_log.csv') 56 57
試したこと・自分が想定していたこと
エージェントの読み込み方法は↓を参考にしました.
https://chainerrl.readthedocs.io/en/latest/agents.html
自分の方で調べた限りでは,あまりload()メソッドの使用例が見つけられず,かつ今回のような問題が発生したため質問した次第です.
個人的には保存したエージェント読み込み時の
python
1optimizer = chainer.optimizers.Adam(eps=1e-2) 2 optimizer.setup(q_func) 3 explorer = chainerrl.explorers.LinearDecayEpsilonGreedy(start_epsilon=1.0, end_epsilon=0.1, decay_steps=num_episodes, random_action_func=env.action_space.sample) 4 replay_buffer = chainerrl.replay_buffer.ReplayBuffer(capacity=10 ** 6) 5 phi = lambda x: x.astype(np.float32, copy=False) 6 load_agent = chainerrl.agents.DoubleDQN( 7 q_func, optimizer, replay_buffer, gamma, explorer, 8 replay_start_size=500, update_interval=1, target_update_interval=100, phi=phi) 9 agent_pass='agent/cartpole/agent_ep{}'.format(episode) 10 load_agent.load(agent_pass)
の読み込み用のエージェント定義部分・読み込み部が何か間違っているのかな?と考えていたのですが,解決方法が見つけられませんでした.
(自分の考えでは仮のload_agentおよびexplorer やoptimizer を定義して,.load()メソッドを使用すればパラメータが上書きされるような形となり使用できると思っていました.)
まだ自分自身も理解が浅い部分も多いですが,ミス・および参考になる記事等があったら教示のほどよろしくお願い致します。
あなたの回答
tips
プレビュー