张量流中的损失限幅(在DeepMind的DQN上)

时间:2016-04-06 21:47:13

标签: neural-network tensorflow deep-learning conv-neural-network

我正在尝试使用Deepmind在张量流中自己实现DQN文件,并且在剪切损失函数时遇到了困难。

以下是描述损失裁剪的自然纸的摘录:

  

我们还发现将更新中的错误项剪切到介于-1和1之间是有帮助的。因为绝对值损失函数| x |对于x的所有正值,其导数为-1,对于x的所有正值,导数为1,将平方误差限制在-1和1之间,对应于使用绝对值损失函数( - 1,1)间隔。这种形式的错误裁剪进一步提高了算法的稳定性。

(链接到完整论文:http://www.nature.com/nature/journal/v518/n7540/full/nature14236.html

到目前为止我尝试使用

clipped_loss_vec = tf.clip_by_value(loss, -1, 1)

修剪我在-1和+1之间计算的损失。在这种情况下,代理商没有学习正确的政策。我打印出网络的渐变,并意识到如果损失低于-1,渐变都会突然变为0!

我发生这种情况的原因是削减损失是(-inf,-1)U(1,inf)中的常数函数,这意味着它在这些区域中具有零梯度。这反过来确保整个网络中的梯度为零(想象一下,无论我提供网络的输入图像是什么,损失在本地邻域中保持为-1,因为它已被剪切)。

所以,我的问题分为两部分:

  1. Deepmind在摘录中的确含义是什么?它们是否意味着低于-1的损失被限制为-1,高于+1的损失被限制为+1。如果是这样,他们是如何处理渐变的(即关于绝对值函数的那部分是什么?)

  2. 如何在张量流中实现损耗限幅,使得梯度在限幅范围之外不会变为零(但可能保持在+1和-1)? 谢谢!

4 个答案:

答案 0 :(得分:8)

我怀疑他们的意思是你应该将渐变剪辑为[-1,1],而不是剪辑损失函数。因此,您像往常一样计算渐变,但随后将渐变的每个分量剪切到[-1,1]范围内(因此,如果它大于+1,则将其替换为+1;如果小于+1; -1,用-1)替换它;然后在梯度下降更新步骤中使用结果,而不是使用未修改的渐变。

等效:定义函数f,如下所示:

f(x) = x^2          if x in [-0.5,0.5]
f(x) = |x| - 0.25   if x < -0.5 or x > 0.5

他们建议使用s^2作为损失函数,而不是使用s形式的某些东西作为损失函数(其中f(s)是一些复杂的表达式)。这是平方损失和绝对值损失之间的某种混合:当s^2很小时会表现得像s,但当s变大时,它会表现得像绝对值价值(|s|)。

请注意,f的导数具有良好的属性,其导数总是在[-1,1]范围内:

f'(x) = 2x    if x in [-0.5,0.5]
f'(x) = +1    if x > +1
f'(x) = -1    if x < -1

因此,当你采用这个基于f的损失函数的梯度时,结果将与计算平方损失的梯度然后剪切它相同。

因此,他们正在做的是用Huber loss有效地取代平方损失。对于delta = 0.5,函数f只是Huber损失的两倍。

现在重点是以下两个选择是等价的:

  • 使用平方损失函数。计算此损失函数的梯度,但在执行梯度下降的更新步骤之前,梯度为[-1,1]。

  • 使用Huber损失函数代替平方损失函数。在梯度下降中直接(未更改)计算此损失函数的梯度。

前者易于实施。后者具有良好的性能(提高稳定性;它比绝对值损失更好,因为它避免了在最小值附近振荡)。因为这两者是等价的,这意味着我们得到一个易于实现的方案,具有平方损失的简单性以及Huber损失的稳定性和鲁棒性。

答案 1 :(得分:1)

  1. 没有。他们实际上谈论的是错误剪辑,而不是关于损失裁剪,但据我所知,同样的事情会引起混淆。它们并不意味着低于-1的损失被限制为-1,高于+1的损失被限制为+1,因为这会导致误差范围[-1; 1]之外的零梯度。相反,他们建议使用线性损耗而不是二次损失来表示误差值<1。 -1和错误值&gt; 1。

  2. 计算错误值(r + \ gamma \ max_ {a&#39;} Q(s&#39;,a&#39 ;; \ theta_i ^ - ) - Q(s,a; \ theta_i) )。如果该误差值在[-1; 1]范围内,则将其平方,如果误差值是&lt; -1如果误差值> 1,则乘以-1。 1保持原样。如果你使用它作为损失函数,区间[-1; 1]之外的渐变不会消失。

  3. 为了拥有一个平滑的&#34;复合损失函数你也可以用边界值-1和1的一阶泰勒近似来代替误差范围[-1; 1]之外的平方损失。在这种情况下,如果e是你的误差值,你就可以如果e&in [-1; 1],则情况e&lt;在e> 1的情况下,将其替换为-2e-1。 1,将其替换为2e-1。

答案 2 :(得分:1)

首先,论文的代码是available online,这是一个非常宝贵的参考。

第1部分

如果您看一下代码,您会在nql:getQUpdateNeuralQLearner.lua,第180行)中看到它们,它们会剪切Q学习函数的错误术语:

-- delta = r + (1-terminal) * gamma * max_a Q(s2, a) - Q(s, a)
if self.clip_delta then
    delta[delta:ge(self.clip_delta)] = self.clip_delta
    delta[delta:le(-self.clip_delta)] = -self.clip_delta
end

第2部分

在TensorFlow中,假设您的神经网络的最后一层被称为self.outputself.actions是所有操作的一个热门编码,self.q_targets_是一个包含目标的占位符,并且self.q是您的计算Q:

# The loss function
one = tf.Variable(1.0)
delta = self.q - self.q_targets_
absolute_delta = tf.abs(delta)
delta = tf.where(
    absolute_delta < one,
    tf.square(delta),
    tf.ones_like(delta) # squared error: (-1)^2 = 1
)

或者,使用tf.clip_by_value(并使实现更接近原始版本):

delta = tf.clip_by_value(
    self.q - self.q_targets_,               
    -1.0,                
    +1.0                 
)                                                 

答案 3 :(得分:0)

  1. 在您引用的Deep Mind论文中,它们限制了损失的渐变。这可以防止巨大的梯度,从而提高稳健性。他们通过对小范围内的误差使用二次损失函数,并对较大的误差使用绝对值损失来实现此目的。
  2. 我建议实施Huber loss function。下面是一个python tensorflow实现。

    def huber_loss(y_true, y_pred, max_grad=1.):
        """Calculates the huber loss.
    
        Parameters
        ----------
        y_true: np.array, tf.Tensor
          Target value.
        y_pred: np.array, tf.Tensor
          Predicted value.
        max_grad: float, optional
          Positive floating point value. Represents the maximum possible
          gradient magnitude.
    
        Returns
        -------
        tf.Tensor
          The huber loss.
        """
        err = tf.abs(y_true - y_pred, name='abs')
        mg = tf.constant(max_grad, name='max_grad')
    
        lin = mg*(err-.5*mg)
        quad=.5*err*err
    
        return tf.where(err < mg, quad, lin)