MLP神经网络:计算梯度(矩阵)



在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 """

<标题> 最终实现

最终实现可以在github上找到

使用Python和numpy很容易。

你有两个选择:

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

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

<>之前转发:输入:X: shape = [num_instances, num_inputs]输入W: shape = [num_outputs, num_inputs]权重B: shape = [num_outputs]偏见旅客:函数激活函数输出:Y: shape = [num_instances, num_outputs]输出backprop:输入:dE/dY: shape = [num_instances, num_outputs]backpropagated梯度W: shape = [num_outputs, num_inputs]权重B: shape = [num_outputs]偏见gd:函数计算g(A) = Y的导数基于Y,即gd(Y) = g'(A)Y: shape = [num_instances, num_outputs]输出X: shape = [num_instances, num_inputs]输入输出:dE/dX: shape = [num_instances, num_inputs]将反向传播(下层dE/dY)dE/dW: shape = [num_outputs, num_inputs]对权重的累积导数dE/db: shape = [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(对于softmax激活函数和交叉熵误差函数或对于线性激活函数和误差平方和),其中Y是网络的输出(shape = [num_instances, num_outputs]), T (shape = [num_instances, num_outputs])是期望的输出。然后你可以反向传播,即每一层的dE/dX是前一层的dE/dY

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

下面是c++的一个例子:

顺便说一句。您可以比较实例转发和批处理转发的速度:

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

最新更新