神经网络的计算步骤
- 输入层
- 1、数据输入
- 隐藏层
- 正向传播:输入端向输出端传递信息
- 2、得到输出值:直线方程进行预测
- 反向传播:输出端向输入端传递信息
- 3、得到误差:损失函数计算误差
- 4、得到偏导数:计算图高效计算偏导数
- 5、更新权重偏置:梯度下降法学习,最小化误差
- 输出层
一个神经网络分为输入层、隐藏层、输出层。
- 输入层:输入数据
- 隐藏层:负责计算
- 输出层:计算和输出结果
输入层
1、数据输入
- 语音/图像/传感器数据都会转成数字形式(如矩阵),再把他们转化为一个特征向量(向量),将其输入到神经网络中。
比如图像数据,世界上的所有颜色都可以通过,红绿蓝三种颜色调配出来。
计算机保存一张图片,要保存三个独立矩阵,分别对应红、绿、蓝三个颜色通道。
假设图片是 64x64
像素的,就有 3 个 64x64
的矩阵,分别对应红绿蓝三个像素的亮度。
为了方便计算,我们会把 3 个矩阵转化为 1 个列向量(特征向量)。
这个向量的总维数就是 64*64*3
,结果是 12288
个特征。
隐藏层
正向传播:输入端向输出端传递信息
2、得到输出值:直线方程进行预测
将待预测数据,这些特征
单层神经元的计算,就是一个直线方程:
前置知识:为什么是一个直线方程,请猛击《神经元的计算》。
现在我们来看多层神经元:
如果第 层神经元有 个,那第 层的每个神经元都得存储
如果第 层神经元有 个,则第 层神经元共有 m*n
个权重。
我们会用一个 m*n
矩阵来存储:
当前层的神经网络计算:
编程实现:
u = np.dot(x, w) + b # dot() 实现矩阵乘法
再计算激活函数,如
def sigmod(x):
return 1 / (1 + e.exp(-x))
y = sigmod(u)
得到当前层输出 ,再把
我们以一个三层神经网络举例:
- 输入层神经元个数:2
- 中间层神经元个数:2
- 输出层神经元个数:1
# 权重
w_im = np.array( [ [4.0, 4.0], [4.0, 4.0] ] ) # 输入层 * 中间层,即 2 * 2
w_mo = np.array( [ [1.0], [1.0] ] ) # 中间层 * 输出层,即 2 * 1
# 偏置
b_im = np.array( [3.0, -3.0] ) # 中间层有 2 个神经元,就 2 个偏置
b_mo = np.array( [0.1] ) # 输出层有 1 个神经元,就 1 个偏置
def middle_layer( x , w, b ): # 中间层/隐藏层,输入 x、权重 w、偏置 b
u = np.dot( x, w ) + b # 直线方程
return 1/(1+np.exp(-u)) # 激活处理
def output_layer( x , w, b ): # 输出层,输入 x、权重 w、偏置 b
u = np.dot( x, w ) + b # 直线方程
return u # 恒等函数,不做激活处理
# 正向传播过程
imp = np.array([...]) # 输入层,直接输入数据即可,不用计算
mid = middle_layer(imp, w_im, b_im) # 中间层
out = output_layer(mid, w_mo, b_mo) # 输出层
这是处理回归问题的正向传播过程,还有一类问题是分类。
比如处理二分类任务,输出层需要俩个神经元:
除了输出层的激活函数使用
def output_layer( x , w, b ): # 输出层,输入 x、权重 w、偏置 b
u = np.dot( x, w ) + b # 直线方程
return np.exp( u ) / np.sum( np.exp( u ) ) # softmax 函数
输出层输出的是一个概率值,我们比较俩个神经元的概率值,取最大值。
反向传播:输出端向输入端传递信息
反向传播过程:
- 前向传播过程:直线方程计算权重参数把输入值相加,再加入偏移值得到一个处理结果,加上激活函数形成一个输出值。
- 反向传播过程:损失函数计算误差,通过计算图先计算第 N 层的偏导数(变化比例),再计算第 N-1 层的,输出层反向往前推,直到输入层;再通过梯度下降法学习,最小化误差。
这样来回不停的进行前向传播、反向传播,来训练(更新)参数使损失函数越来越小(预测越来越准确)。
原理:每次新的训练数据进来,就根据正确答案对参数进行一次微调,使得神经网络输出数值更接近正确答案。
计算过程图示:
首先把数据,分为:输入数据、正确答案。
正向传播输出与正确答案对比:
3、得到误差:损失函数计算误差
对输出和正确答案的误差,进行定义的就是损失函数。
理论上我们可以用平方,但是在工程中,我们一般会用这个损失函数:
这是对单个训练样本(一张图)的损失函数,但我们输入都神经网络的通常是一个训练集(大量的图片)。
我们需要累加单个训练样本的结果,再求平均值:
为什么使用这个损失函数呢?
这个损失函数(逻辑回归)的函数图像是一个向下凸的图形。
因为学习,就是找到一组 和 ,使这个损失函数最小。
也就是在这个函数图像的底部找到一组 和 。
这个损失函数叫逻辑回归,具体内容记录在同名博客:《逻辑回归》。
这个损失函数没有局部最优解,只存在唯一的全局最优解。
我们要做的,是求出损失函数的梯度,而后运用梯度下降法求出损失最小的一组 w 和 b。
4、得到偏导数:计算图高效计算偏导数
我们用函数
为了让神经网络计算,函数
一开始,我们随机初始化 分别为 ,前向传播过程如下图:
前向传播得到输出值。反向传播用于计算函数 关于各个参数的偏导数(变化比例),而后对参数进行梯度下降。
我们先计算 关于 的偏导数,记为 。
偏导数、斜率就是变化比例,即 变化一点后
所以,为了计算 的偏导数,我们假设让 变化一点点,比如 加上 (11.001),而后看 改变了多少, 从 变成了 。
的变化量除以 的变化量(0.003 / 0.001 = 3),即偏导数(变化比例)为 。
- 同理, 关于 的偏导数为 。
- 同理, 关于 的偏导数为 。
那么, 关于
- 我们让 改变一点点,从 变成 ,这会导致 从 变成 ,而 的改变会导致 从 变成 , 的改变量除以 的改变量等于 (0.003/0.001=3),即偏导数 为 。
其实间接传导的计算,我们用链式法则求导:
- 关于 的偏导数 = 关于 的偏导数 * 关于 的偏导数,即
同理, 关于参数 的偏导数 。
这个偏导数才是我们最终需要的,我们需要的是函数 关于参数
为了得到这三个偏导数,我们需要先计算出关于 的偏导数,而后再计算出关于 的偏导数,最后计算出关于参数
反向传播后更新
计算得到新的 的值,然后再进行前向传播的到新的
- 人工神经网络就是一个多层的复合函数。
- 这种复合函数求偏导时是不能直接对 求偏导,只能对中间函数求依次求偏导从而得出 的偏导数,即链式法则。
5、更新权重偏置:梯度下降法学习,最小化误差
所谓学习,就是最小化误差的处理。
以最小的神经网络举例,给定一个样本(1, 0) 训练。
- 单样本的误差平方函数:
- 损失函数为:
损失函数图像:
一开始有一个初始值(左边的红点),我们需要找到最合适的w(谷底的w),使J最小。
那如何自动找到这个谷底呢?
当寻找点在左边时,梯度是负数,在右边时,梯度是正数。
梯度下降公式:
- :变化比例,w变化时,J相应变化多少
- 点在左边时,梯度是负的,负负得正,w会增加,体现在图中是在 x 轴向右方向走
- 点在右边时,梯度是正的,w会减少,体现在图中是在 x 轴上向左方向走
- 最终都会向谷底靠拢
除此之外,还有一个参数 a,代表学习率:
一般 a = 0.01,太高会造成震荡,在俩边跳来跳去;太小下降很慢。
梯度下降法的寻找思路是:粗调 + 精调。
- 首先粗调:迭代步长要大,很快确定大致范围
- 其次精调:迭代步长要小,速度很慢,确定精度
就好像用显微镜一样,粗体可以看到大致图像,精调可以看清楚图像。
具体步骤就是,先随机在曲线上找一个点,然后求出该点的斜率,也称为梯度。
顺着这个梯度的方向往下走一步,到达一个新的点之后,重复以上步骤,直到到达最低点(或达到我们满足的某个条件)。
如,对
其中 代表 “用后面的值更新”, 代表学习率(learning rate), 就是 对
梯度下降法完整内容:《梯度下降法》。
输出层
项目驱动:《识别猫的项目》。