神经网络之反向传播训练(8行代码)

多少行代码可以实现神经网络,并且了解反向传播算法。

import numpy as np
X = np.array([[0,0,1], [0,1,1], [1,0,1], [1,1,1]])
y = np.array([[0, 0, 1, 1]]).T
syn = 2 * np.random.random((3, 1)) - 1
for i in range(10000):
    l = 1 / (1 + np.exp(-np.dot(X, syn)))
    l_delta = (y - l) * (l * (1 - l))
    syn += np.dot(X.T, l_delta)
复制代码

如上,通过给定的输入的输出进行训练,最后根据给定输入预测输出。

x1 x2 x3 y
0 0 1 0
1 1 1 1
1 0 1 1
0 1 1 0

训练数据如上。


下面对代码进行解释:
X:表示输出数据
y: 表述输出数据
syn: 3 * 1维的初始化随机权重
网络结构如下所示:

如上,上部分为网络结构, 下部分为后面的辅助链式求导过程。


其过程大概为:
输入数据x乘以对应的权重w,得到的值z经过非线性函数转换(sigmoid)得到预测值l
计算l的目标值y的误差。训练的目标为将误差最小化,因此可以通过调节输入x和权重w。因为x为输入数据,不可以调节。因此目标为:通过不断的调节权重w,使其得到的预测值与目标的值的误差最小(或者小于某个阈值),完成训练。可以使用权重w对新的输入进行预测。
其迭代过程为最后3行代码,稍作解释:
第6行:输入x乘以权重w,经过sigmoid函数变化得到l。 第7行:将误差最小化的过程就是不断调节w的过程。根据链式法则求loss关于w的导数,找到损失函数最快降低的方法。如上图片所示:
loss关于w的导数 = loss关于l的导数 * l 关于z 的导数 * z 关于w的导数, 也即是最后两行的内容。


下面我将扩展一下代码, 以便更好的理解:

import numpy as np
def sigmoid(z):
    return 1 / (1 + np.exp(-z))
def sigmoid_derivative(x):
    return x * (1 - x)

X = np.array([[0,0,1], [0,1,1], [1,0,1], [1,1,1]])
y = np.array([[0, 0, 1, 1]]).T

syn = 2 * np.random.random((3, 1)) - 1
for i in range(10000):
    l = sigmoid(np.dot(X, syn))
    loss = (y - l) ** 2
    if i % 1000 == 0:
        print("Loss: ", np.sum(loss))
    loss_derivative = 2  * (y - l)
    l_delta = loss_derivative * sigmoid_derivative(l)
    syn += np.dot(X.T, l_delta)
print("syn:\n" ,syn)
print("l:\n", l)
复制代码

下面是打印结果:

Loss:  0.8505452956411994
Loss:  0.0013461667714825178
Loss:  0.0006585827213748538
Loss:  0.0004348364571153864
Loss:  0.00032425670465056856
Loss:  0.0002583897080090336
Loss:  0.00021470251268552865
Loss:  0.00018361751185635365
Loss:  0.000160374621766103
Loss:  0.00014234163846899023
syn:
 [[10.38061079]
 [-0.20679655]
 [-4.98439294]]
l:
 [[0.00679775]
 [0.00553486]
 [0.99548654]
 [0.9944554 ]]
复制代码

可以看到随着迭代次数的增加,loss变的越来越小,说明计算得到的值越接近真实值。 最后打印的权重syn和预测值l也证明了这一点。

后面打算加入隐藏层,提高神经网络的泛化能力。

参考资料:
A Neural Network in 11 lines of Python (Part 1)
深度学习之反向传播算法 上/下 Part 3 ver 0.9 beta

github源码