一个神经网络分为输入层、隐藏层、输出层。

比如图像数据,世界上的所有颜色都可以通过,红绿蓝三种颜色调配出来。
计算机保存一张图片,要保存三个独立矩阵,分别对应红、绿、蓝三个颜色通道。
假设图片是 64x64 像素的,就有 3 个 64x64 的矩阵,分别对应红绿蓝三个像素的亮度。
为了方便计算,我们会把 3 个矩阵转化为 1 个列向量(特征向量)。

这个向量的总维数就是 64*64*3,结果是 12288 个特征。
将待预测数据,这些特征 x 1 ⋅ ⋅ ⋅ x 1288 x_{1}···x_{1288} x1⋅⋅⋅x1288 输入到神经网络中:

单层神经元的计算,就是一个直线方程:
前置知识:为什么是一个直线方程,请猛击《神经元的计算》。
现在我们来看多层神经元:

如果第
i
i
i 层神经元有
m
m
m 个,那第
i
+
1
i+1
i+1 层的每个神经元都得存储
m
m
m 个权重。
如果第
i
+
1
i+1
i+1 层神经元有
n
n
n 个,则第
i
+
1
i+1
i+1 层神经元共有 m*n 个权重。
我们会用一个 m*n 矩阵来存储:

当前层的神经网络计算:

编程实现:
u = np.dot(x, w) + b # dot() 实现矩阵乘法
再计算激活函数,如 s i g m o d sigmod sigmod 函数:
def sigmod(x):
return 1 / (1 + e.exp(-x))
y = sigmod(u)
得到当前层输出 y y y,再把 y y y 当成下一层的输入。
我们以一个三层神经网络举例:

# 权重
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) # 输出层
这是处理回归问题的正向传播过程,还有一类问题是分类。
比如处理二分类任务,输出层需要俩个神经元:

除了输出层的激活函数使用 s o f t m a x softmax softmax 函数外,其他地方都不变。
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 层的,输出层反向往前推,直到输入层;再通过梯度下降法学习,最小化误差。
这样来回不停的进行前向传播、反向传播,来训练(更新)参数使损失函数越来越小(预测越来越准确)。
原理:每次新的训练数据进来,就根据正确答案对参数进行一次微调,使得神经网络输出数值更接近正确答案。
计算过程图示:

首先把数据,分为:输入数据、正确答案。

正向传播输出与正确答案对比:

对输出和正确答案的误差,进行定义的就是损失函数。

理论上我们可以用平方,但是在工程中,我们一般会用这个损失函数:
这是对单个训练样本(一张图)的损失函数,但我们输入都神经网络的通常是一个训练集(大量的图片)。
我们需要累加单个训练样本的结果,再求平均值:
为什么使用这个损失函数呢?
这个损失函数(逻辑回归)的函数图像是一个向下凸的图形。

因为学习,就是找到一组
w
w
w 和
b
b
b,使这个损失函数最小。
也就是在这个函数图像的底部找到一组 w w w 和 b b b。
这个损失函数叫逻辑回归,具体内容记录在同名博客:《逻辑回归》。
这个损失函数没有局部最优解,只存在唯一的全局最优解。
我们要做的,是求出损失函数的梯度,而后运用梯度下降法求出损失最小的一组 w 和 b。
我们用函数 J ( a , b , c ) = 3 ( a + b c ) J(a,~b,~c) = 3(a+bc) J(a, b, c)=3(a+bc) 来演示传播过程。
为了让神经网络计算,函数 J J J 以计算图的形式计算:

一开始,我们随机初始化
a
、
b
、
c
a、b、c
a、b、c 分别为
5
、
3
、
2
5、3、2
5、3、2,前向传播过程如下图:

前向传播得到输出值。
反向传播用于计算函数
C
C
C 关于各个参数的偏导数(变化比例),而后对参数进行梯度下降。

我们先计算
C
C
C 关于
B
B
B 的偏导数,记为
d
C
d
B
\frac{dC}{dB}
dBdC。
偏导数、斜率就是变化比例,即 B B B 变化一点后 C C C 会相应的变化多少。
所以,为了计算 B B B 的偏导数,我们假设让 B B B 变化一点点,比如 B B B 加上 0.001 0.001 0.001(11.001),而后看 C C C 改变了多少, C C C 从 33 33 33 变成了 33.003 33.003 33.003。
C C C 的变化量除以 B B B 的变化量(0.003 / 0.001 = 3),即偏导数(变化比例)为 3 3 3。
同理, B B B 关于 A A A 的偏导数为 d B d A = 1 \frac{dB}{dA} = 1 dAdB=1。
同理, A A A 关于 b b b 的偏导数为 d A d b = 2 \frac{dA}{db} = 2 dbdA=2。
那么, C C C 关于 A A A 的偏导数是多少呢?
其实间接传导的计算,我们用链式法则求导:
同理, C C C 关于参数 b b b 的偏导数 d C d b = d C d B ∗ d B d A ∗ d A d b = 3 ∗ 1 ∗ 2 = 6 \frac{dC}{db}=\frac{dC}{dB}*\frac{dB}{dA}*\frac{dA}{db}=3*1*2=6 dbdC=dBdC∗dAdB∗dbdA=3∗1∗2=6。
d C d b \frac{dC}{db} dbdC 这个偏导数才是我们最终需要的,我们需要的是函数 C C C 关于参数 a 、 b 、 c a、b、c a、b、c 的偏导数。
为了得到这三个偏导数,我们需要先计算出关于 B B B 的偏导数,而后再计算出关于 A A A 的偏导数,最后计算出关于参数 a 、 b 、 c a、b、c a、b、c 的偏导数。
反向传播后更新 d a 、 d b 、 d c da、db、dc da、db、dc 的值是通过:
计算得到新的 a 、 b 、 c a、b、c a、b、c 的值,然后再进行前向传播的到新的 J J J 函数,再进行反向传播,直到寻到最小误差。
所谓学习,就是最小化误差的处理。
以最小的神经网络举例,给定一个样本(1, 0) 训练。
损失函数图像:

一开始有一个初始值(左边的红点),我们需要找到最合适的w(谷底的w),使J最小。
那如何自动找到这个谷底呢?

当寻找点在左边时,梯度是负数,在右边时,梯度是正数。
梯度下降公式: w = w − a d J d w w=w-a\frac{dJ}{dw} w=w−adwdJ
w − d J d w w-\frac{dJ}{dw} w−dwdJ 中间是负号:
除此之外,还有一个参数 a,代表学习率:

一般 a = 0.01,太高会造成震荡,在俩边跳来跳去;太小下降很慢。
梯度下降法的寻找思路是:粗调 + 精调。
就好像用显微镜一样,粗体可以看到大致图像,精调可以看清楚图像。

具体步骤就是,先随机在曲线上找一个点,然后求出该点的斜率,也称为梯度。
顺着这个梯度的方向往下走一步,到达一个新的点之后,重复以上步骤,直到到达最低点(或达到我们满足的某个条件)。
如,对 w w w 进行梯度下降,则就是重复一下步骤(重复一次称为一个迭代):
其中 = = = 代表 “用后面的值更新”, r r r 代表学习率(learning rate), d J d w \frac{dJ}{dw} dwdJ 就是 J J J 对 w w w 求偏导。
梯度下降法完整内容:《梯度下降法》。
项目驱动:《识别猫的项目》。