1、BP 神经网络结构与原理
由于 BP 神经网络参数超级多,如果不先定义好变量,后面非常难理解,故针对上述图形,定义如下:
2、BP 神经网络的第一种实现
采用误差平方和作为损失函数,基于反向传播算法推导,可得最终的 4 个方程式,如下:
3.1 前向计算
def feedforward(self, a):
"""Return the output of the network if ``a`` is input."""
for b, w in zip(self.biases, self.weights):
a = sigmoid(np.dot(w, a) + b)
return a
3.2 反向传播
def backprop(self, x, y):
"""Return a tuple ``(nabla_b, nabla_w)`` representing the
gradient for the cost function C_x. ``nabla_b`` and
``nabla_w`` are layer-by-layer lists of numpy arrays, similar
to ``self.biases`` and ``self.weights``."""
nabla_b = [np.zeros(b.shape) for b in self.biases]
nabla_w = [np.zeros(w.shape) for w in self.weights]
# feedforward
activation = x # 存储每层的z和a值
activations = [x] # list to store all the activations, layer by layer
zs = [] # list to store all the z vectors, layer by layer
for b, w in zip(self.biases, self.weights):
z = np.dot(w, activation) + b
zs.append(z)
activation = sigmoid(z)
activations.append(activation)
# backward pass 计算最后一层的误差
delta = self.cost_derivative(activations[-1], y) * \
sigmoid_prime(zs[-1])
nabla_b[-1] = delta
nabla_w[-1] = np.dot(delta, activations[-2].transpose())
# 计算从倒数第二层至第二层的误差
for l in range(2, self.num_layers):
z = zs[-l]
sp = sigmoid_prime(z)
delta = np.dot(self.weights[-l + 1].transpose(), delta) * sp
nabla_b[-l] = delta
nabla_w[-l] = np.dot(delta, activations[-l - 1].transpose())
return (nabla_b, nabla_w)
4、BP 神经网络的改进和第二种实现
4.1 BP 神经网络改进
4.1.1 交叉熵代价函数
“严重错误”导致学习缓慢,如果在初始化权重和偏置时,故意产生一个背离预期较大的 输出,那么训练网络的过程中需要用很多次迭代,才能抵消掉这种背离,恢复正常的学习。
(1) 引入交叉熵代价函数目的是解决一些实例在刚开始训练时学习得非常慢的问题,其 主要针对激活函数为 Sigmod 函数
(2) 如果采用一种不会出现饱和状态的激活函数,那么可以继续使用误差平方和作为损 失函数
(3) 如果在输出神经元是 S 型神经元时,交叉熵一般都是更好的选择
(4) 输出神经元是线性的那么二次代价函数不再会导致学习速度下降的问题。在此情形 下,二次代价函数就是一种合适的选择
(5) 交叉熵无法改善隐藏层中神经元发生的学习缓慢
(6) 交叉熵损失函数只对网络输出“明显背离预期”时发生的学习缓慢有改善效果
(7) 应用交叉熵损失并不能改善或避免神经元饱和,而是当输出层神经元发生饱和时, 能够避免其学习缓慢的问题。
4.1.2 4 种规范化技术
(1) 早停止。跟踪验证数据集上的准确率随训练变化情况。如果我们看到验证数据上的 准确率不再提升,那么我们就停止训练
(2) 正则化
(3) 弃权(Dropout)
(4) 扩增样本集 4.1.3 更好的权重初始化方法 不好的权重初始化方法会导致出现饱和问题,好的权重初始化方法不仅仅能够带来训练 速度的加快,有时候在最终性能上也有很大的提升。