Kerasメモ(強化学習)その3
前回の続き。
DQN(Deep Q Learning)の中身について見ていく。
AgentとしてDQNAgentを使う場合、指定しなければデフォルトで「Double DQN」が有効になる。
rl/agents/dqn.py
class DQNAgent(AbstractDQNAgent): def __init__(self, model, policy=None, test_policy=None, enable_double_dqn=True, # <--- enable_dueling_network=False, dueling_type='avg', *args, **kwargs):
「Double DQN」は2つのQ-networkを使う。
役割 | 学習の有無 | ソースコード | |
---|---|---|---|
target network | estimate the Q value | 学習しない | sefl.target_model |
online network | predicts the actions | 学習する | self.model |
rl/agents/dqn.py
class DQNAgent(AbstractDQNAgent): def compile(self, optimizer, metrics=[]): # We never train the target model self.target_model = clone_model(self.model, {}) self.target_model.compile(optimizer='sgd', loss='mse') self.model.compile(optimizer='sgd', loss='mse') ... self.trainable_model = trainable_model # 後述
trainable_modelの組み上げ
# 「online network」 ins = [self.model.input] y_pred = self.model.output # Q value y_true = Input(name='y_true', shape=(self.nb_actions,)) mask = Input(name='mask', shape=(self.nb_actions,)) loss_out = Lambda(clipped_masked_error, output_shape=(1,), name='loss')([y_true, y_pred, mask]) trainable_model = Model(inputs=ins + [y_true, mask], outputs=[loss_out, y_pred])
インプット
- ins: 状態(Observation)
- y_true: 実際にとった行動に対する報酬
- mask: 行動のmaskデータ(「実際にとった行動」は「1」、とらなかった行動は「0」)
アウトプット
- Huber損失(mask=1の行動に対する「y_true」と「y_pred」)
- y_pred: 「online network」のアウトプット(Q値)
報酬が低い行動は、Q値が低くなるように学習される。
「online network」の学習結果を「target network」に反映していく。
# self.target_model_update: 0.01 (soft-update) # Soft update with `0.99 * old(self.target_model) + 0.01 * new(self.model)`. updates = get_soft_target_model_updates(self.target_model, self.model, 0.01) optimizer = AdditionalUpdatesOptimizer(optimizer, updates)
順伝播
「online network」からQ値を得る。
Q値は「その行動の選びやすさ」を示すので、値が大きいほど、選択される確率が高くなるが、あくまでも「選ばれる確率が高い」ということ。
行動の選択はポリシーに従う。
偶然の発見のために、ランダム性を持たせる。
rl/agents/dqn.py
class DQNAgent(AbstractDQNAgent): def forward(self, observation): # Select an action. state = self.memory.get_recent_state(observation) q_values = self.compute_q_values(state) # self.model.predict_on_batch() if self.training: action = self.policy.select_action(q_values=q_values) return action
rl/policy.py
class BoltzmannQPolicy(Policy): # Example q_values: [-0.01126872, -0.00710144] def select_action(self, q_values): exp_values = np.exp(q_values) # --> [0.98879454, 0.99292371] probs = exp_values / np.sum(exp_values) # --> [0.49895818, 0.50104182] action = np.random.choice([0, 1], p=probs) # --> 0(move to the left) or 1(move to the right)
実際のコードは、numpy.exp()コール前に値をclipしているが省略
逆伝播
経過となるデータは「Experience Replay」に蓄積する。
class DQNAgent(AbstractDQNAgent): def backward(self, reward, terminal): self.memory.append(self.recent_observation, self.recent_action, reward, terminal, training=self.training)
データの取り出し。
experiences = self.memory.sample(self.batch_size)
データの中身の一例。
[Experience(state0=[array([0.02735838, -0.2061478 , -0.0381168 , 0.20968898])], action=1, reward=1.0, state1=[array([ 0.02323542, -0.01050215, -0.03392302, -0.09476996])], terminal1=False)]
報酬を計算する。
# 「online network」から、s_t+1における最も高いQ値のactionを選ぶ q_values = self.model.predict_on_batch(state1_batch) actions = np.argmax(q_values, axis=1) # 「target network」から、s_t+1におけるQ値(対象は上のaction)を得る target_q_values = self.target_model.predict_on_batch(state1_batch) # self.batch_size: 32 q_batch = target_q_values[range(32), actions] # 「target network」から得たQ値を使ってrewardを計算する # self.gamma: 0.99 discounted_reward_batch = self.gamma * q_batch # ゲームオーバ(terminal1=True)なら「0」 # Set discounted reward to zero for all states that were terminal. discounted_reward_batch *= terminal1_batch # R: reward_batch + discounted_reward_batch # Rが「y_true」に該当する # targets[idx][action] = R # dummy_targets[idx] = R # train_on_batch()でlabelを与えているが、ダミー # We use a dummy target # since the actual loss is computed in a Lambda layer metrics = self.trainable_model.train_on_batch(ins + [targets, masks], [dummy_targets, targets])
train_on_batch()でインプットとして渡すデータの中身の一例。
ins: [0.02735838, -0.2061478 , -0.0381168 , 0.20968898] targets: [0. , 1.0051814] masks: [0., 1.]
今回は「ゲームオーバを避ける」ように行動を学習した。
時刻tにおいてアクション「a_t」をとり、時刻t+1における報酬が低かったとする。
その場合、時刻tにおけるアクション「a_t」に対するQ値は低く設定される。
ハイスコアを競うようなゲームなら報酬が高くなるように行動を学習する。
時刻tにおいてアクション「a_t」をとり、時刻t+1における報酬が高かったとする。
その場合、時刻tにおけるアクション「a_t」に対するQ値は高く設定される。