【翻译】What is the natural gradient, and how does it work?

最近的研究需要用到natural gradient,但是2002年的那篇ICML看不懂。外网有大佬在2016年写了一篇博客,很好,翻译一下搬运过来了。

链接: http://kvfrans.com/what-is-the-natural-gradient-and-where-does-it-appear-in-trust-region-policy-optimization/


  • 阅读本文只需要少许线代和统计知识即可
  •  What is the natural gradient?

    • 首先,我们理解一下 标准梯度下降。
    • 我们有一个参数化的神经网络。大多数情况下,我们需要有一个loss function来告诉我们网络的参数应该如何改变。
    • 利用BP,我们计算网络中每个参数对loss function的导数。这些导数,代表了我们应该如何改变参数才能在loss function上获得最大的改变——这个导数就是 gradient 梯度。
    • 然后我们把参数,按照导数的方向,调整“一小段距离”。
    • 问题在于如何定义 “一小段距离”?在标准梯度下降中,“距离”意味着“参数空间的欧式距离”。
    • 然而,根据“参数变化幅度”来定义“距离”并不总是正确的。
    • 为了形象说明这个道理,我们来看两对高斯分布。我们让两对高斯分布的mean,从-1变化到1。我们用一组参数(mean,stddev)来表示高斯分布。
    •                        【翻译】What is the natural gradient, and how does it work?_第1张图片参数空间距离变化:(-1,1)到(1,1)  =  2
    •          【翻译】What is the natural gradient, and how does it work?_第2张图片参数空间距离变化:(-1,5)到(1,5)  =  2
    • 很明显,第一个分布的变化比第二个分布变化的更剧烈。
    •  这引出了一个关键直觉:梯度度量了输出受参数变化影响的程度。然而,必须结合上下文,才能看到这种参数对输出的影响到底有多大:第一个分布中+2的偏移比第二个分布中+2的偏移,意义大得多。
    •  nature gradient的作用是重新定义我们更新参数的“小距离”。并不是所有的参数都相等。我们需要根据——每个参数对网络输出分布的影响程度,来控制每个参数的变化幅度,而不是一视同仁的处理每个参数的变化。
  •  How do we do that?

    •  首先,我们定义一种新的距离形式,它对应于基于KL散度的距离,KL散度是衡量新分布和旧分布差异的一种手段。
    •  我们通过定义一个度量矩阵来做到这一点。这个度量矩阵允许我们根据一些custom measurement来计算向量的距离。
    • 以一个“具有5个参数的神经网络”为例,网络参数记为delta——我们对应的度量矩阵的shape=5x5,记为metric。
    • totaldistance = 0  
      for i in xrange(5):  
          for j in xrange(5):
              totaldistance += delta[i] * delta[j] * metric[i][j]

      如果metric矩阵是单位矩阵,那么很容易发现,这个totaldistance就变成了参数空间的欧式距离。

    • 然而,大多数时候我们的metric不是单位矩阵。有了metric,我们就可以测量距离,以说明各种参数之间的关系。

    • 事实证明,我们可以使用Fisher Information Matrix作为一个metric——这样做,可以从KL divergence的角度衡量delta的距离。

    • Fisher Information Matrix是网络自身KL散度的二阶导数。更多信息,请参阅。

    • Fisher Information Matrix的概念让我很困惑:下面的代码能说清楚问题。

    • # 两个参数化的高斯分布之间的 KL散度
      def gauss_KL(mu1, logstd1, mu2, logstd2):  
          var1 = tf.exp(2*logstd1)
          var2 = tf.exp(2*logstd2)
          kl = tf.reduce_sum(logstd2 - logstd1 + (var1 + tf.square(mu1 - mu2))/(2*var2) - 0.5)
          return kl
      
      
      # KL divergence of a gaussian with itself
      # 第一个参数 mu1, logstd1 通过tf.stop_gradient这个op进行固化,BP时候不进行更新.
      def gauss_KL_firstfixed(mu, logstd):  
          mu1, logstd1 = map(tf.stop_gradient, [mu, logstd])
          mu2, logstd2 = mu, logstd
          return gauss_KL(mu1, logstd1, mu2, logstd2)
      
      
      # self.action_mu 和 self.action_logstd 是网络计算出的输出,没有在本代码片段给出
      kl_fixed = gauss_KL_firstfixed(self.action_mu, self.action_logstd)
      
      # 一阶导数
      first_derivative = self.gradients(kl_fixed, parameter_list)  
      # 二阶导数
      fisher_matrix = self.gradients(first_derivative, parameter_list)  

      于是,我们现在有了这么一个度量矩阵,当网络参数发生变化时,可以根据KL divergence来衡量距离变化。

    • 接下来,我们用这个度量矩阵来展示,标准梯度应该如何被scaled。

    • natural_grad = inverse(fisher) * standard_grad  

      注意,如果 Fisher 是单位矩阵,那么natural gradient就变成了standard gradient。

    • 最后,我想指出——计算natural gradient可能需要大量的计算。

  •  

你可能感兴趣的:(神经网络)