神经网络的实现看似复杂,但只要理清各层关系,实现也不难。这里以CNN网络为例,用python实现一个简单的神经网络。
主要思路
神经网络运算,主要有:
- Forward-propagate
- Backward-propagate
- Parameters update
数据集
使用数据集](http://archive.ics.uci.edu/ml/datasets/seeds
实现
构建网络
CNN网络由输入层、隐藏层、输出层构成。隐藏层和输出层的每个神经元都有自己的weight和bias,在运算过程中,还要有输出output和导数derivative。构建网络时,神经元的output和derivative可以没有初始值。
Python实现时,网络由List构成,每一层也是一个List。层中包含神经元,每一个神经网也是List,神经元包含weight、bias、output、derivative,这些可以有Dict的key-value结构表示,value是数值或List。
CNN网络由$k$层,每层神经元个数为$ni$,则$net= List[n_0, n1, \dotc, n{k-1}]$,构建网络时,第$ni$层每个神经元的权重个数为第$n{i-1}$层神经元个数,第一层为输入层,不需权重。
def InitializeNet(net):
#0 层为输入层,初始化 [1 len(net) -1]层
cnn_net = list()
for layer_index in range(1, len(net)):
layer = [{'weight':[random() for num in range(net[layer_index - 1])],
'bias': random(),
'derivative':0,
'output':0}
for num in range(net[layer_index])]
cnn_net.append(layer)
return cnn_net
前向传播
激活函数
用sigmod作为激活函数
def Activation(value):
return 1.0 / (1 + exp(-value) )
前向传播
前向传播是从第0层到n-1层,具体计算是计算每层每个神经元的输出。
先定义一个神经元的前向传播:
1 | def ForwardNeuron(inputs, weight, bias): |
前向传播是按层传播,计算每层输出时,即为计算每层中每个神经元的输出,因此可以定义出前向传播函数:
1 | def Forward(cnn_net, inputs): |
反向传播
反向传播时,误差由输出层,依次向前传播,传播过程中,计算weight和bias的权重。
输出层误差计算,为了简便,采用均方误差。
$$
error = \frac{1}{2}(true_label - output)^2
$$
激活函数为sigmod,它的导数可以求得,为
1 | def Derivative(value): |
那么输出层误差为:
$$
error = \frac{1}{2}(true_label - output)^2 * Derivate(output)
$$
隐藏层误差的计算,与它连接下一层的权重以及下一层每个神经元的误差相关。下一层第k个神经元到当前层某一个神经元的误差:
$$
error = (weight_k error_k) Derivate(output)
$$
其中$weight_k$为第当前神经元到下一层第k个神经元的权重,$error_k$是下一层第k个神经元的误差,output是当前神经元的输出。
可以实现反向传播算法:
1 | def BackForward(cnn_net, true_label): |
梯度更新
上面的导数部分,已经对激活函数求导,更新梯度,只需对对应梯度求导。
$$
e=\sum_i x_i w_i
$$
$$
output= activation(e)
$$
可以看出,对梯度$w_i$求导,即为乘以输入$x_i$。
因此梯度更新公式为:
weight += lr neuron[‘derivative’] input
1 | def UpdateWeight(cnn_net, inputs, lr): |
训练
训练神经网络