本篇本来是想写神经网络反向传播算法,但感觉光写这个不是很完整,所以就在前面将相关的求导内容一并补上。所谓的神经网络求导,核心是损失函数对线性输出 求导,即反向传播中的 ,求出了该值以后后面的对参数求导就相对容易了。
矩阵
函数 ,则 矩阵为:
即
神经网络中的激活函数多为对应元素运算 ( element-wise ) ,设输入为K维向量 , 输出为K维向量 ,则激活函数为 ,即 ,则其导数按 矩阵的定义为一个对角矩阵:
激活函数
函数的形式为:
其导数为:
若输入为 K 维向量 ,根据上文的定义,其导数为
激活函数
函数可以看作是放大并平移的 函数,但因为是零中心化的 (zero-centered) ,通常收敛速度快于 函数,下图是二者的对比:
其导数为:
激活函数
函数可以看作是 函数的平滑版本,形式为:
而其导数则恰好就是 函数:
激活函数
函数将多个标量映射为一个概率分布,其形式为:
表示第 个输出值,也可表示属于类别 的概率, 。
首先求标量形式的导数,即第 个输出对于第 个输入的偏导:
其中 对 求导要分情况讨论,即:
那么当 时:
当 时:
于是二者综合:
其中
当 函数的输入为K 维向量 时,转换形式为 :
其导数同样为 矩阵 ( 同时利用 和 式 ):
交叉熵损失函数
交叉熵损失有两种表示形式,设真实标签为 ,预测值为 :
(一) 为标量,即 ,则交叉熵损失为:
(二) 为one-hot向量,即 ,则交叉熵损失为:
交叉熵损失函数 + Sigmoid激活函数
已知 , ,求 :
交叉熵损失函数 + Softmax激活函数
已知 , ,求 :
运用和式
若输入为 维向量 ,则梯度为:
另外运用对数除法运算,上面的求导过程可以简化:
神经网络反向传播算法
通常所谓的“学习”指的是通过最小化损失函数进而求得相应参数的过程,神经网络中一般采用梯度下降来实现这个过程,即:
用神经网络中的常用参数符号替换,并用矩阵形式表示:
其中 表示第 层。
导数是梯度的组成部分,通常采用数值微分的方法近似下式:
表示函数 在 处的斜率,但是由于运算时 不可能无限接近于零,上式容易引起数值计算问题,所以实际中常采用中心差分来近似:
这样整个梯度的计算可以用以下代码实现:
import numpy as np
def numerical_gradient(f, x): # f为函数,x为输入向量
h = 1e-4
grad = np.zeros_like(x)
it = np.nditer(x, flags=['multi_index'], op_flags=['readwrite'])
while not it.finished:
idx = it.multi_index
temp = x[idx]
x[idx] = temp + h
fxh1 = f(x)
x[idx] = temp - h
fxh2 = f(x)
grad[idx] = (fxh1 + fxh2) / (2*h)
x[idx] = temp
it.iternext()
return grad
由于数值微分对每个参数都要计算 和 ,假设神经网络中有100万个参数,则需要计算200万次损失函数。如果是使用 SGD,则是每个样本计算200万次,显然是不可承受的。所以才需要反向传播算法这样能够高效计算梯度的方法。
接下来先定义神经网络中前向传播的式子 ( 表示隐藏层, 表示输出层):
现在我们的终极目标是得到 和 ,为了计算方便,先来看各自的分量 和 。
这里定义 , 根据 式使用链式法则:
所以接下来的问题就是求 :
(1) 对于输出层 :
(2) 对于隐藏层 ,由 式可知:
可见 对于 的每个分量都有影响,使用链式法则时需要加和每个分量,下图是一个形象表示:
所以下面求 时会用 加和:
将上面的 式写成矩阵形式,就得到了传说中反向传播算法的四大公式:
而 的计算可以直接套用上面损失函数 + 激活函数的计算结果。
反向传播算法 + 梯度下降算法流程
(1) 前向传播阶段:使用下列式子计算每一层的 和 ,直到最后一层。
(2) 反向传播阶段:
(2.1) 计算输出层的误差:
(2.2) 由后一层反向传播计算前一层的误差:
(2.3) 计算梯度: ,
(3) 参数更新:
Reference
神经网络反向传播算法
How the backpropagation algorithm works
The Softmax function and its derivative
Notes on Backpropagation
Computational Graph & Backpropagationhttps://www.cnblogs.com/massquantity/p/10138489.html