⽤Python实现BP神经⽹络(附代码)
⽤Python实现出来的机器学习算法都是什么样⼦呢?前两期线性回归及逻辑回归项⽬已发布(见⽂末链接),今天来讲讲BP神经⽹络。BP神经⽹络
全部代码
github/lawlite19/MachineLearning_Python/blob/master/NeuralNetwok/NeuralNetwork.py
神经⽹络model
先介绍个三层的神经⽹络,如下图所⽰
输⼊层(input layer)有三个units(
为补上的bias,通常设为1)
表⽰第j层的第i个激励,也称为为单元unit
为第j层到第j+1层映射的权重矩阵,就是每条边的权重
所以可以得到:
隐含层:
输出层
其中,S型函数
,也成为激励函数
可以看出
为3x4的矩阵,
为1x4的矩阵
==》j+1的单元数x(j层的单元数+1)
代价函数
假设最后输出的
,即代表输出层有K个单元
其中,
代表第i个单元输出与逻辑回归的代价函数
差不多,就是累加上每个输出(共有K个输出)
正则化
L-->所有层的个数
-->第l层unit的个数
正则化后的代价函数为
共有L-1层,然后是累加对应每⼀层的theta矩阵,注意不包含加上偏置项对应的theta(0)
正则化后的代价函数实现代码:
# 代价函数
def nnCostFunction(nn_params,input_layer_size,hidden_layer_size,num_labels,X,y,Lambda):
length = nn_params.shape[0] # theta的中长度
# 还原theta1和theta2
Theta1 = nn_params[0:hidden_layer_size*(input_layer_size+1)].reshape(hidden_layer_size,input_layer_size+1)
Theta2 = nn_params[hidden_layer_size*(input_layer_size+1):length].reshape(num_labels,hidden_layer_size+1)
# np.savetxt("Theta1.csv",Theta1,delimiter=',')
m = X.shape[0]
class_y = np.zeros((m,num_labels)) # 数据的y对应0-9,需要映射为0/1的关系
# 映射y
for i in range(num_labels):
class_y[:,i] = np.int32(y==i).reshape(1,-1) # 注意reshape(1,-1)才可以赋值
'''去掉theta1和theta2的第⼀列,因为正则化时从1开始'''
Theta1_colCount = Theta1.shape[1]
Theta1_x = Theta1[:,1:Theta1_colCount]
Theta2_colCount = Theta2.shape[1]
Theta2_x = Theta2[:,1:Theta2_colCount]
# 正则化向theta^2
term = np.anspose(np.vstack((shape(-1,1),shape(-1,1)))),np.vstack((shape(-1,1),shape(-1,1))))
'''正向传播,每次需要补上⼀列1的偏置bias'''
a1 = np.hstack((np.ones((m,1)),X))
z2 = np.dot(anspose(Theta1))
正则化网络
a2 = sigmoid(z2)
a2 = np.hstack((np.ones((m,1)),a2))
z3 = np.dot(anspose(Theta2))
h = sigmoid(z3)
'''代价'''
J = -(np.anspose(shape(-1,1)),np.shape(-1,1)))+np.anspose(shape(-1,1)),np.shape(-1,1)))-Lambda*term/2)/m
return np.ravel(J)
反向传播BP
上⾯正向传播可以计算得到J(θ),使⽤梯度下降法还需要求它的梯度
BP反向传播的⽬的就是求代价函数的梯度
假设4层的神经⽹络,
记为-->l层第j个单元的误差
《===》
(向量化)
没有
,因为对于输⼊没有误差
因为S型函数
的倒数为:
所以上⾯的
可以在前向传播中计算出来
反向传播计算梯度的过程为:
是⼤写的
for i=1-m:-
-正向传播计算
(l=2,L)
-反向计算
...
-
-
最后
,即得到代价函数的梯度
实现代码:
# 梯度
def nnGradient(nn_params,input_layer_size,hidden_layer_size,num_labels,X,y,Lambda):
length = nn_params.shape[0]
Theta1 = nn_params[0:hidden_layer_size*(input_layer_size+1)].reshape(hidden_layer_size,input_layer_size+1) Theta2 = nn_params[hidden_layer_size*(input_layer_size+1):length].reshape(num_labels,hidden_layer_size+1) m = X.shape[0]
class_y = np.zeros((m,num_labels)) # 数据的y对应0-9,需要映射为0/1的关系
# 映射y
for i in range(num_labels):
class_y[:,i] = np.int32(y==i).reshape(1,-1) # 注意reshape(1,-1)才可以赋值
'''去掉theta1和theta2的第⼀列,因为正则化时从1开始'''
Theta1_colCount = Theta1.shape[1]
Theta1_x = Theta1[:,1:Theta1_colCount]
Theta2_colCount = Theta2.shape[1]
Theta2_x = Theta2[:,1:Theta2_colCount]
Theta1_grad = np.zeros((Theta1.shape)) #第⼀层到第⼆层的权重
Theta2_grad = np.zeros((Theta2.shape)) #第⼆层到第三层的权重
Theta1[:,0] = 0;
Theta2[:,0] = 0;
'''正向传播,每次需要补上⼀列1的偏置bias'''
a1 = np.hstack((np.ones((m,1)),X))
z2 = np.dot(anspose(Theta1))
a2 = sigmoid(z2)
a2 = np.hstack((np.ones((m,1)),a2))
z3 = np.dot(anspose(Theta2))
h = sigmoid(z3)
'''反向传播,delta为误差,'''
delta3 = np.zeros((m,num_labels))
delta2 = np.zeros((m,hidden_layer_size))
for i in range(m):
delta3[i,:] = h[i,:]-class_y[i,:]
Theta2_grad = Theta2_grad+np.anspose(delta3[i,:].reshape(1,-1)),a2[i,:].reshape(1,-1))
delta2[i,:] = np.dot(delta3[i,:].reshape(1,-1),Theta2_x)*sigmoidGradient(z2[i,:])
Theta1_grad = Theta1_grad+np.anspose(delta2[i,:].reshape(1,-1)),a1[i,:].reshape(1,-1))
'''梯度'''
grad = (np.vstack((shape(-1,1),shape(-1,1)))+Lambda*np.vstack((shape(-
1,1),shape(-1,1))))/m
return np.ravel(grad)
BP可以求梯度的原因
实际是利⽤了链式求导法则
因为下⼀层的单元利⽤上⼀层的单元作为输⼊进⾏计算
⼤体的推导过程如下,最终我们是想预测函数与已知的y⾮常接近,求均⽅差的梯度沿着此梯度⽅向可使代价函数最⼩化。可对照上⾯求梯度的过程。
求误差更详细的推导过程:
梯度检查
检查利⽤BP求的梯度是否正确
利⽤导数的定义验证:
求出来的数值梯度应该与BP求出的梯度⾮常接近
验证BP正确后就不需要再执⾏验证梯度的算法了
实现代码:
# 检验梯度是否计算正确
# 检验梯度是否计算正确
def checkGradient(Lambda = 0):
'''构造⼀个⼩型的神经⽹络验证,因为数值法计算梯度很浪费时间,⽽且验证正确后之后就不再需要验证了'''

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。