前向传播、损失函数、反向传播、神经网络函数

从零开始用Python构建神经网络

这是一份用于理解深度学习内部运作方式的初学者指南,内容涵盖

  • 神经网络定义
  • 损失函数
  • 前向传播
  • 反向传播
  • 梯度下降算法

什么是神经网络?

可以理解为一个从输入映射到输出的数学函数,即对复杂函数的拟合。

神经网络由以下部分组成:

  • 一个输入层,x
  • 任意数量的隐藏层
  • 一个输出层,ŷ
  • 每两层之间都有一组权重和偏置,W 和 b
  • 每个隐藏层都要选择一个激活函数 σ

写成矩阵形式,即:

PS: 为什么需要非线性激活函数?

增强模型对复杂函数的拟合能力。

神经网络的基本训练过程

训练过程的每一次迭代包含以下步骤:

  • 计算预测的输出 ŷ,称为前向传播;
  • 更新权重和偏置,称为反向传播;

简单的计算流程图:

img

前提条件

  1. 首先是我们已经有了训练数据
  2. 我们已经根据数据的规模、领域,建立了神经网络的基本结构,比如有几层,每一层有几个神经元
  3. 定义好损失函数来合理地计算误差

前向传播

一个简单 2 层神经网络的输出 ŷ 可以表示为:

也可以写成:

其中,权重 和偏置 是影响输出 ŷ 的参数。

我们可以在 Python 代码中添加一个前向传播函数来做到这一点。(把b的值永远设置为1):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def sigmoid(x):
return 1/(1+np.exp(-x))

class NeuralNetwork:
def __init__(self, x, y):
self.input = x
self.weights1 = np.random.rand(self.input.shape[1],4)
self.weights2 = np.random.rand(4,1)
self.y = y
self.output = np.zeros(self.y.shape)

def feedforward(self):
self.layer1 = sigmoid(np.dot(self.input, self.weights1))
self.output = sigmoid(np.dot(self.layer1, self.weights2))

得到输出 ŷ 之后,如何判断预测结果的好坏呢?这就需要用到损失函数了。

损失函数

其目标是根据数据自动学习网络的权重,以便让所有输入 𝑥的预测输出 ŷ 接近目标 𝑦

为了衡量与该目标的差距,我们使用了一个误差平方和损失函数:

误差平方和,即每个预测值和真实值之间差值的平均值。这个差值是取了平方项的,所以我们测量的是差值的绝对值。在训练过程中,我们的目标是找到一组最佳的权重和偏置,使损失函数最小化。

反向传播

现在,我们已经找到了预测误差的方法(损失函数),那么我们需要一种方法将错误「传播」回去,从而更新权重和偏置。为了确定权重和偏置调整的适当值,我们需要知道损失函数对权重和偏置的偏导数。如果我们知道了偏导数,我们可以通过简单增加或减少偏导数的方式来更新权重和偏置。这就是所谓的梯度下降 $w=w-\alpha \frac{dL}{dw}$。

下面,我们开始反向传播误差导数。 根据我们的误差函数 ,我们通过链式法则得出可以得出:

反向传播函数的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
def sigmoid(x):
return 1/(1+np.exp(-x))

def sigmoid_derivative(x):
return x * (1-x) # sigmoid函数的导数

class NeuralNetwork:
def __init__(self, x, y):
self.input = x
self.weights1 = np.random.rand(self.input.shape[1],4)
self.weights2 = np.random.rand(4,1)
self.y = y
self.output = np.zeros(self.y.shape)

def feedforward(self):
self.layer1 = sigmoid(np.dot(self.input, self.weights1))
self.output = sigmoid(np.dot(self.layer1, self.weights2))

def backprop(self):
# application of the chain rule to find derivative of the loss function with respect to weights2 and weights1
d_weights2 = np.dot(self.layer1.T, (2*(self.y - self.output) * sigmoid_derivative(self.output)))
d_weights1 = np.dot(self.input.T, (np.dot(2*(self.y - self.output) * sigmoid_derivative(self.output), self.weights2.T) * sigmoid_derivative(self.layer1)))

# update the weights with the derivative (slope) of the loss function
self.weights1 += d_weights1
self.weights2 += d_weights2

为了更深入地理解微积分和链式法则在反向传播中的应用,我强烈推荐 3Blue1Brown 的视频教程。

测试

既然我们已经有了做前向传播和反向传播的完整 Python 代码,我们可以将神经网络应用到一个示例中,看看它的效果。

1
2
3
4
5
6
7
x = np.array([[0,0,1], [0,1,1], [1,0,1], [1,1,1]])	# data
y = np.array([[0],[1],[1],[0]]) # label
nn = NeuralNetwork(x,y)
for i in range(1000): # 迭代1000次
nn.feedforward()
nn.backprop()
print(nn.output)

结果

prediction Y
0.02191928 0
0.97279658 1
0.95721863 1
0.04292296 0

通过前向传播和反向传播算法成功训练了神经网络,预测值收敛到了真实值。

参考

无需深度学习框架,如何从零开始用Python构建神经网络

Google 反向传播演示

MarkDown 插入数学公式实验大集合


从零开始用Python搭建神经网络
http://example.com/2018/11/12/2018-11-12-从零开始用Python搭建神经网络/
作者
NSX
发布于
2018年11月12日
许可协议