简而言之,我的最后一句话是正确答案。“目标”是选定动作的一个单键,但有一个技巧。
A2C 损失函数
我错过的 A2C 实现的一个非常关键的部分是考虑到优势的自定义损失函数。损失函数将优势乘以当前概率的负对数来选择被选择的动作。
诀窍是,如果优势为负,损失函数将切换符号,因此梯度将应用于相反的方向。
在一个维度上,它更容易理解。假设我的目标预测是1
,而我的实际预测是0.6
。一个简单的损失将被定义为target - prediction
,或者在这种情况下0.4
,未来的预测将更接近 1。如果我的预测是1.4
,那么损失将是-0.4
。负损失意味着预测未来的结果会更低,而正的结果意味着预测未来的结果会更高。
如果损失函数的符号被切换,预测实际上将远离1
。
当您将损失函数中的优势相乘时,也会发生同样的事情。负优势意味着该动作比状态值差,因此我们需要避免它,正优势意味着该动作受到鼓励。
在 Keras(Tensorflow 2.0)中:
这是自定义损失函数:
def custom_actor_loss(y_true, y_prediction, advantage):
prediction = K.clip(y_prediction, 1e-8, 1 - 1e-8)
log_probabilities = y_true * K.log(prediction)
return K.sum(-log_probabilities*advantage)
由于未定义 0 的对数,因此对这些值进行了剪裁。
其余的网络建设:
input_layer = Input(shape=self._state_size, name='state_in')
advantage = Input(shape=[1], name='advantage')
target_prediction = Input(shape=self._actions_num, name='target')
inner_layer = Dense(units=layer_size, activation='relu')(input_layer)
actor_out = Dense(units=self._actions_num, activation='softmax', name='actor_out')(inner_layer)
self._actor = Model([input_layer, target_prediction, advantage], actor_out, name='actor')
self._actor.add_loss(custom_actor_loss(actor_out, target_prediction, advantage))
self._actor.compile(optimizer=Adam(learning_rate=actor_learning_rate))
在训练循环中(其中future_rewards_prediction
和critic_prediction
是当前和下一个状态的批评者的输出(除了设置为 的终端状态future_rewards_prediction
)0
:
# Train actor
target_probabilities = np.zeros([1, self._actions_num])
target_probabilities[0][memory[step_idx].action] = 1.0
advantage = memory[step_idx].reward + future_rewards_prediction * self._future_discount - critic_prediction
self._actor.fit((memory[step_idx].state, target_probabilities, advantage), verbose=0)
*请注意,我并没有y
在fit
通话中真正指定 a 。这是因为我在尝试在 Keras 中实现自定义损失函数时遇到了一个问题,这个问题已经解决了。