【问题标题】:MLP Neural Network: calculating the gradient (matrices)MLP 神经网络:计算梯度(矩阵)
【发布时间】:2013-06-07 14:39:05
【问题描述】:

在 n 层神经网络中计算梯度的好方法是什么?

权重层:

  1. 第一层权重:    (n_inputs+1, n_units_layer)-matrix
  2. 隐藏层权重:(n_units_layer+1, n_units_layer)-matrix
  3. 最后一层权重:    (n_units_layer+1, n_outputs)-matrix

注意事项:

  • 如果只有一个隐藏层,我们将只使用两个(权重)层来表示网络:
    inputs --first_layer-> network_unit --second_layer-> output
  • 对于具有多个隐藏层的 n 层网络,我们需要实现 (2) 步骤。

有点模糊的伪代码:

    weight_layers = [ layer1, layer2 ]             # a list of layers as described above
    input_values  = [ [0,0], [0,0], [1,0], [0,1] ] # our test set (corresponds to XOR)
    target_output = [ 0, 0, 1, 1 ]                 # what we want to train our net to output
    output_layers = []                             # output for the corresponding layers

    for layer in weight_layers:
        output <-- calculate the output     # calculate the output from the current layer
        output_layers <-- output            # store the output from each layer
    
    n_samples = input_values.shape[0]
    n_outputs = target_output.shape[1]
    
    error = ( output-target_output )/( n_samples*n_outputs )

    """ calculate the gradient here """

最终实现

The final implementation is available at github.

【问题讨论】:

  • 嗨,只是好奇。这段代码可以用于多变量输出吗?(即输出层有超过 1 个神经元)
  • 可以,只要指定网络对象初始化时的输出数量即可。

标签: python numpy neural-network gradient


【解决方案1】:

使用 Python 和 numpy 很容易。

你有两个选择:

  1. 您可以为 num_instances 实例并行计算所有内容,或者
  2. 您可以计算一个实例的梯度(实际上是 1 的一个特例)。

我现在将给出一些提示如何实现选项 1。我建议您创建一个名为 Layer 的新类。它应该有两个功能:

向前: 输入: X: 形状 = [num_instances, num_inputs] 输入 W: 形状 = [num_outputs, num_inputs] 权重 b: 形状 = [num_outputs] 偏见 克:功能 激活函数 输出: Y: 形状 = [num_instances, num_outputs] 输出 反向传播: 输入: dE/dY: 形状 = [num_instances, num_outputs] 反向传播梯度 W: 形状 = [num_outputs, num_inputs] 权重 b: 形状 = [num_outputs] 偏见 gd:函数 计算 g(A) = Y 的导数 基于 Y,即 gd(Y) = g'(A) Y: 形状 = [num_instances, num_outputs] 输出 X: 形状 = [num_instances, num_inputs] 输入 输出: dE/dX:形状 = [num_instances, num_inputs] 将被反向传播(下层的 dE/dY) dE/dW:形状 = [num_outputs, num_inputs] 关于权重的累积导数 dE/db:形状 = [num_outputs] 关于偏差的累积导数

实现很简单:

def forward(X, W, b):
    A = X.dot(W.T) + b # will be broadcasted
    Y = g(A)
    return Y

def backprop(dEdY, W, b, gd, Y, X):
    Deltas = gd(Y) * dEdY # element-wise multiplication
    dEdX = Deltas.dot(W)
    dEdW = Deltas.T.dot(X)
    dEdb = Deltas.sum(axis=0)
    return dEdX, dEdW, dEdb

第一层的X 是您从数据集中获取的,然后您将每个Y 作为前向传递中下一层的X 传递。

输出层的dE/dY被计算为Y-T,其中Y是网络的输出(shape = [num_instances, num_outputs]) 和T (shape = [num_instances, num_outputs]) 是所需的输出。然后可以反向传播,即每一层的dE/dX是上一层的dE/dY

现在您可以使用每一层的dE/dWdE/db 来更新Wb

以下是 C++ 示例:OpenANN

顺便说一句。您可以比较 instance-wise 和 batch-wise 前向传播的速度:

In [1]: import timeit

In [2]: setup = """import numpy
   ...: W = numpy.random.rand(10, 5000)
   ...: X = numpy.random.rand(1000, 5000)"""

In [3]: timeit.timeit('[W.dot(x) for x in X]', setup=setup, number=10)
Out[3]: 0.5420958995819092

In [4]: timeit.timeit('X.dot(W.T)', setup=setup, number=10)
Out[4]: 0.22001314163208008

【讨论】:

  • 超级方便的格式化!我会一直投票给你! 读者须知:对于共轭梯度法,backprop() 方法中只需要 dE/dX 方法
  • 谢谢。 :) 但通常非线性共轭梯度也需要 (dEdW, dEdb) 来更新 (W, b) 以使 E 最小化。 dEdX 仅用于反向传播。
  • 实现的代码sn-p是一个缩放共轭梯度算法,使用Polak-Ribiere公式更新搜索方向。这加起来就是一个非线性 cg 算法,尽管我可能弄错了!无论哪种方式:backpropagation() 中唯一需要的计算是 np.dot( error, weights )*dAdY(output_values) 其中def A() # activation function
  • 那么你究竟是如何更新权重的呢?当然,也可以调整神经网络(数据集)的输入,使其最小化误差函数。 :D
  • 我不直接调整权重,而是调整Δw_i使得perfect_weight_i = initial_weight_i + Δw_i
猜你喜欢
  • 2018-11-24
  • 2020-07-25
  • 2014-11-25
  • 2011-03-28
  • 1970-01-01
  • 2013-10-09
  • 2018-02-05
  • 1970-01-01
  • 2020-01-21
相关资源
最近更新 更多