前言
深度神经网络(DNN)12 是最基本的神经网络之一,人工神经网络(ANN)、BP神经网络、全连接神经网络 都在它在不同时期、不同领域等方面下的别称(主要是从不同实现方法上进行命名的,本质都差不多)。
本次任务是使用Python还原深度神经网络,并且不使用任何深度学习框架,只使用numpy包进行矩阵运算。
训练数据与处理
这次使用的训练数据是 某地区20年的公路运量相关数据3,经典。
任务是根据人数、机动车辆、公路面积对公路客运量和运货量进行预测。
# 年份years = [1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009]# 人数(万人)population = [20.55, 22.44, 25.37, 27.13, 29.45, 30.10, 30.96, 34.06, 36.42, 38.09, 39.13, 39.99, 41.93, 44.59, 47.30, 52.89, 55.73, 56.76, 59.17, 60.63]# 机动车数(万辆)vehicle = [0.6, 0.75, 0.85, 0.9, 1.05, 1.35, 1.45, 1.6, 1.7, 1.85, 2.15, 2.2, 2.25, 2.35, 2.5, 2.6, 2.7, 2.85, 2.95, 3.1]# 公路面积(万平方公里)roadarea = [0.09, 0.11, 0.11, 0.14, 0.20, 0.23, 0.23, 0.32, 0.32, 0.34, 0.36, 0.36, 0.38, 0.49, 0.56, 0.59, 0.59, 0.67, 0.69, 0.79]# 公路客运量(万人)passengertraffic = [5126, 6217, 7730, 9145, 10460, 11387, 12353, 15750, 18304, 19836, 21024, 19490, 20433, 22598, 25107, 33442, 36836, 40548, 42927, 43462]# 公路货运量(万吨)freighttraffic = [1237, 1379, 1385, 1399, 1663, 1714, 1834, 4322, 8132, 8936, 11099, 11203, 10524, 11115, 13320, 16762, 18673, 20724, 20803, 21804]
将数据进行 最大最小归一法 处理,将离散数据限定在一个范围,使数据更规范,提高 梯度下降算法 的效率,同时避免 数据溢出。
网络结构
如图所示,网络分为输入层、隐藏层和输出层。
输入层 是对数据的一个简单调用过程,很多时候算网络层的时候会进行忽略。我这个网络单次输入需要人数、机动车辆、公路面积3个数据,所有包含有3个节点。
隐藏层 是对数据进行复杂运算的过程,通过权重与偏置,经过多层复杂运算,提取出在数据中的特征。这里我只设立了1层隐藏层,该隐藏层中包含有8个节点。
输出层 是对隐藏层运算结果的输出过程,需要将运算结果输出到指定格式。这里我图上标了2个节点,这两个节点生成的结果就是网络根据输入获得的预测结果。
网络推导过程
前向传播
前向传播 就是将输入参数按网络的构造顺序逐步进行计算,最后得到的结果就是网络的预测或判断结果,简单来说就是一个通过输入参数进行结果预测的过程。
输入层
确定输入向量 = [[20.55], [0.6], [0.09]]
。
- 既可以看作是输入层的输入,也可以看作是输入层的输出。
隐藏层
STEP1: 确定净输入(未经激活):
- 是隐藏层的权重矩阵 weight,矩阵大小为(8,3)
- 是隐藏层的偏置矩阵 bias,矩阵大小为(8,1)
- 是隐藏层的净输入,矩阵大小为(8,1)
从这里可以看出,其实BP神经网络中每个节点就是一个 线性回归(Linear Regression) 问题,即:
STEP2: 确定隐藏层的输出,即通过 激活函数 进行激活,我选择的是 Sigmoid函数(逻辑函数):
激活方式则如下所示:
- 是隐藏层通过激活函数后的输出,矩阵大小为(8,1)
在我的理解中,激活函数主要功能有两个,分别是局限或限制住输出大小 和 保留有效信息。
输出层
这里我没有再添加激活函数,所有输出层的净输入就是输出:
- 是输出层的权重矩阵,矩阵大小为(2,8)
- 是输出层的偏置矩阵,矩阵大小为(2,1)
- 是输出层的净输入和实际输出,矩阵大小为(2,1)
损失函数/代价函数
训练过程中,在完成推理后,需要计算 预期值 与 实际值 之间的误差,也被称为 损失函数4,这里使用的是最基础的方法,L2 Loss(最小二乘法)。
- 是样本量
- 是预期值/期望值
- 是实际值
- 是预期值与实际值之间的误差
其他常见的损失函数有 绝对值损失、log对数损失、指数损失、交叉熵损失 等等。
反向传播
梯度下降
反向传播 是训练过程中的一个步骤,根据损失函数计算不同层之间的梯度,然后通过梯度更新之前的权重和偏置,而 梯度计算 的方法就是 链式求导,整个过程也被称为 反向传播 或 梯度下降。
更新权重和偏置 的方法如下:
由于 反向传播的目的是使损失函数最小,所以从负方向出发梯度下降速率是最快的,即:
- 是学习率
- 是权重或偏置
,是损失函数对预期值进行求导,即:
\begin{equation} \frac{\partial{e}}{\partial{\hat{y}}} = \hat{y} - y \end{equation}
注意:L2Loss 中原先系数是 ,得到结果应该是 ,但我了解到,大多数时候为了运算方便,会使 ,使系数为 ,只会对下降速度有所影响,等于是只改变了学习率。
剩下的就是,开导!
权重和偏置
需要更新的是每层的 权重矩阵 和 偏置矩阵,因此需要计算 和 ,即实际结果与各层权重矩阵和偏置矩阵的梯度(导数)。
的输出梯度变化,需要输出损失对 的偏导:
的梯度变化:
的梯度变化:
的输出梯度变化,中间还需要求一层 Sigmoid 的导数:
的梯度变化:
的梯度变化:
以上就是各层梯度变化的推导过程!