我正在尝试为连续动作空间实现REINFORCE算法。我创建了一个玩具单状态MDP,其中奖励是所选择的操作与目标值之间的绝对差的负值。最佳策略是使动作与目标值相同。可能的操作范围是-inf到inf。例如,如果目标值为5且代理采取行动2.2,则奖励为-2.8 = -abs(2.2-5),情节终止。具有单个线性神经元的神经网络可预测高斯分布的均值,该高斯分布具有固定的标准偏差,代理可以从中取样其作用。 MDP状态的特征向量仅为[1.0]。
当标准偏差小(例如0.05)时,网络将很好地收敛。但是,当标准偏差较大(例如0.5)时,网络的预测会在与目标值相反的方向上发散。
代码如下:
import numpy as np
import tensorflow as tf
import tensorflow_probability as tfp
tf.enable_eager_execution()
if __name__ == '__main__':
mean_input_layer = tf.keras.Input(shape=(1,))
mean_output_layer = tf.keras.layers.Dense(
1, activation='linear')(mean_input_layer)
mean_model = tf.keras.Model(inputs=mean_input_layer,
outputs=mean_output_layer)
optimizer = tf.keras.optimizers.SGD(learning_rate=0.001)
target_mean = 5
standard_deviation = 0.05 # Works
# standard_deviation = 0.5 # Diverges
for t in range(10000):
with tf.GradientTape() as tape:
mean = mean_model(np.array([[1]]), training=True)
stdev = np.array([[standard_deviation]], dtype=np.float32)
dist = tfp.distributions.Normal(loc=mean, scale=stdev)
samp = dist.sample()
ascent = -(dist.log_prob(samp)*(-tf.math.abs(samp-target_mean)))
mean_grads = tape.gradient(ascent, mean_model.trainable_variables)
optimizer.apply_gradients(
zip(mean_grads, mean_model.trainable_variables))
print('#' + str(t)
+ ' Sample: ' + str(samp.numpy()[0])
+ ' Mean: ' + str(mean.numpy()[0]))
变量“ ascent”为负,目的是执行梯度上升而不是下降。
这是一个示例,目标值为5,标准差为0.05:
#0样本:[-0.3368746]均值:[-0.400553]
#1样本:[-0.35207522]均值:[-0.3980214]
#2样本:[-0.39965397]均值:[-0.3947122]
#3样本:[-0.3883655]均值:[-0.39056838]
...
#2460样本:[5.0231776]均值:[4.9940543]
#2461样本:[5.030905]均值:[4.99024]
#2462样本:[4.853626]均值:[4.9867477]
#2463样本:[4.8647094]均值:[4.983813]
#2464样本:[4.9929175]均值:[4.982292]
它收敛。
这是一个示例,目标值为5,标准差为0.5:
#1样本:[0.6297094]均值:[1.4340767]
#2样本:[0.75481075]均值:[1.4310371]
#3样本:[0.9269088]均值:[1.4287564]
#4样本:[1.2933123]均值:[1.4272974]
...
#3210样本:[-3.4329443]均值:[-3.322072]
#3211样本:[-3.755511]均值:[-3.3225727]
#3212样本:[-3.6817236]均值:[-3.3237739]
#3213样本:[-3.4897459]均值:[-3.324738]
...
#9996样本:[-13.280873]均值:[-13.032175]
#9997样本:[-13.879341]均值:[-13.032874]
#9998样本:[-12.796365]均值:[-13.036192]
#9999样本:[-13.04003]均值:[-13.036874]
它在与目标值相反的方向上发散。 这里发生了什么?我的实现中有错误吗?感谢您的帮助。
更新:如果我将“ samp = dist.sample()”替换为均匀分布的样本,该样本的均值为中心,均值的宽度为+-2标准差,则标准差为0.5收敛。具体而言,“ samp = tf.constant([[mean.numpy()[0]-2 * standard_deviation + 4 * standard_deviation * np.random.random(random()]]))”。显然,这不是解决问题的真正方法,但可能为试图找出问题所在的人提供一些见识。我还在寻找解决方案。
更新2:作为难题的另一部分,如果我翻转上升变量的符号,则0.5个标准偏差的情况会收敛,而0.05个标准偏差的情况会发散。