用Python实现BP神经网络(附代码)


Posted in Python onJuly 10, 2019

用Python实现出来的机器学习算法都是什么样子呢? 前两期线性回归及逻辑回归项目已发布(见文末链接),今天来讲讲BP神经网络。

BP神经网络

全部代码

https://github.com/lawlite19/MachineLearning_Python/blob/master/NeuralNetwok/NeuralNetwork.py

神经网络model

先介绍个三层的神经网络,如下图所示

输入层(input layer)有三个units(

用Python实现BP神经网络(附代码)

为补上的bias,通常设为1)

用Python实现BP神经网络(附代码)

表示第j层的第i个激励,也称为为单元unit

用Python实现BP神经网络(附代码)

为第j层到第j+1层映射的权重矩阵,就是每条边的权重

用Python实现BP神经网络(附代码)

所以可以得到:

隐含层:

用Python实现BP神经网络(附代码)

用Python实现BP神经网络(附代码)

用Python实现BP神经网络(附代码)

输出层

用Python实现BP神经网络(附代码)

其中,S型函数

用Python实现BP神经网络(附代码)

,也成为激励函数

可以看出

用Python实现BP神经网络(附代码)

为3x4的矩阵,

用Python实现BP神经网络(附代码)

为1x4的矩阵

用Python实现BP神经网络(附代码)

==》j+1的单元数x(j层的单元数+1)

代价函数

假设最后输出的

用Python实现BP神经网络(附代码)

,即代表输出层有K个单元

用Python实现BP神经网络(附代码)

其中,

用Python实现BP神经网络(附代码)

代表第i个单元输出与逻辑回归的代价函数

用Python实现BP神经网络(附代码)

差不多,就是累加上每个输出(共有K个输出)

正则化

L-->所有层的个数

用Python实现BP神经网络(附代码)

-->第l层unit的个数

正则化后的代价函数为

用Python实现BP神经网络(附代码)

用Python实现BP神经网络(附代码)

共有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.dot(np.transpose(np.vstack((Theta1_x.reshape(-1,1),Theta2_x.reshape(-1,1)))),np.vstack((Theta1_x.reshape(-1,1),Theta2_x.reshape(-1,1))))

'''正向传播,每次需要补上一列1的偏置bias'''

a1 = np.hstack((np.ones((m,1)),X))

z2 = np.dot(a1,np.transpose(Theta1))

a2 = sigmoid(z2)

a2 = np.hstack((np.ones((m,1)),a2))

z3 = np.dot(a2,np.transpose(Theta2))

h = sigmoid(z3)

'''代价'''

J = -(np.dot(np.transpose(class_y.reshape(-1,1)),np.log(h.reshape(-1,1)))+np.dot(np.transpose(1-class_y.reshape(-1,1)),np.log(1-h.reshape(-1,1)))-Lambda*term/2)/m

return np.ravel(J)

反向传播BP

上面正向传播可以计算得到J(θ),使用梯度下降法还需要求它的梯度

BP反向传播的目的就是求代价函数的梯度

假设4层的神经网络,

用Python实现BP神经网络(附代码)

记为-->l层第j个单元的误差

用Python实现BP神经网络(附代码)

《===》

用Python实现BP神经网络(附代码)

(向量化)

用Python实现BP神经网络(附代码)

用Python实现BP神经网络(附代码)

没有

用Python实现BP神经网络(附代码)

,因为对于输入没有误差

因为S型函数

用Python实现BP神经网络(附代码)

的倒数为:

用Python实现BP神经网络(附代码)

所以上面的

用Python实现BP神经网络(附代码)

用Python实现BP神经网络(附代码)

可以在前向传播中计算出来

反向传播计算梯度的过程为:

用Python实现BP神经网络(附代码)

用Python实现BP神经网络(附代码)

是大写的

用Python实现BP神经网络(附代码)

for i=1-m:-

用Python实现BP神经网络(附代码)

-正向传播计算

用Python实现BP神经网络(附代码)

(l=2,3,4...L)

-反向计算

用Python实现BP神经网络(附代码)

用Python实现BP神经网络(附代码)

...

用Python实现BP神经网络(附代码)

-

用Python实现BP神经网络(附代码)

-

用Python实现BP神经网络(附代码)

用Python实现BP神经网络(附代码)

最后

用Python实现BP神经网络(附代码)

,即得到代价函数的梯度

实现代码:

# 梯度

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(a1,np.transpose(Theta1))

a2 = sigmoid(z2)

a2 = np.hstack((np.ones((m,1)),a2))

z3 = np.dot(a2,np.transpose(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.dot(np.transpose(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.dot(np.transpose(delta2[i,:].reshape(1,-1)),a1[i,:].reshape(1,-1))

'''梯度'''

grad = (np.vstack((Theta1_grad.reshape(-1,1),Theta2_grad.reshape(-1,1)))+Lambda*np.vstack((Theta1.reshape(-1,1),Theta2.reshape(-1,1))))/m

return np.ravel(grad)

BP可以求梯度的原因

实际是利用了链式求导法则

因为下一层的单元利用上一层的单元作为输入进行计算

大体的推导过程如下,最终我们是想预测函数与已知的y非常接近,求均方差的梯度沿着此梯度方向可使代价函数最小化。可对照上面求梯度的过程。

用Python实现BP神经网络(附代码)

求误差更详细的推导过程:

用Python实现BP神经网络(附代码)

梯度检查

检查利用BP求的梯度是否正确

利用导数的定义验证:

用Python实现BP神经网络(附代码)

求出来的数值梯度应该与BP求出的梯度非常接近

验证BP正确后就不需要再执行验证梯度的算法了

实现代码:

# 检验梯度是否计算正确

# 检验梯度是否计算正确

def checkGradient(Lambda = 0):

'''构造一个小型的神经网络验证,因为数值法计算梯度很浪费时间,而且验证正确后之后就不再需要验证了'''

input_layer_size = 3

hidden_layer_size = 5

num_labels = 3

m = 5

initial_Theta1 = debugInitializeWeights(input_layer_size,hidden_layer_size);

initial_Theta2 = debugInitializeWeights(hidden_layer_size,num_labels)

X = debugInitializeWeights(input_layer_size-1,m)

y = 1+np.transpose(np.mod(np.arange(1,m+1), num_labels))# 初始化y

y = y.reshape(-1,1)

nn_params = np.vstack((initial_Theta1.reshape(-1,1),initial_Theta2.reshape(-1,1))) #展开theta

'''BP求出梯度'''

grad = nnGradient(nn_params, input_layer_size, hidden_layer_size,

num_labels, X, y, Lambda)

'''使用数值法计算梯度'''

num_grad = np.zeros((nn_params.shape[0]))

step = np.zeros((nn_params.shape[0]))

e = 1e-4

for i in range(nn_params.shape[0]):

step[i] = e

loss1 = nnCostFunction(nn_params-step.reshape(-1,1), input_layer_size, hidden_layer_size,

num_labels, X, y,

Lambda)

loss2 = nnCostFunction(nn_params+step.reshape(-1,1), input_layer_size, hidden_layer_size,

num_labels, X, y,

Lambda)

num_grad[i] = (loss2-loss1)/(2*e)

step[i]=0

# 显示两列比较

res = np.hstack((num_grad.reshape(-1,1),grad.reshape(-1,1)))

print res

权重的随机初始化

神经网络不能像逻辑回归那样初始化theta为0,因为若是每条边的权重都为0,每个神经元都是相同的输出,在反向传播中也会得到同样的梯度,最终只会预测一种结果。

所以应该初始化为接近0的数

实现代码

# 随机初始化权重theta

def randInitializeWeights(L_in,L_out):

W = np.zeros((L_out,1+L_in)) # 对应theta的权重

epsilon_init = (6.0/(L_out+L_in))**0.5

W = np.random.rand(L_out,1+L_in)*2*epsilon_init-epsilon_init # np.random.rand(L_out,1+L_in)产生L_out*(1+L_in)大小的随机矩阵

return W

预测

正向传播预测结果

实现代码

# 预测

def predict(Theta1,Theta2,X):

m = X.shape[0]

num_labels = Theta2.shape[0]

#p = np.zeros((m,1))

'''正向传播,预测结果'''

X = np.hstack((np.ones((m,1)),X))

h1 = sigmoid(np.dot(X,np.transpose(Theta1)))

h1 = np.hstack((np.ones((m,1)),h1))

h2 = sigmoid(np.dot(h1,np.transpose(Theta2)))

'''

返回h中每一行最大值所在的列号

- np.max(h, axis=1)返回h中每一行的最大值(是某个数字的最大概率)

- 最后where找到的最大概率所在的列号(列号即是对应的数字)

'''

#np.savetxt("h2.csv",h2,delimiter=',')

p = np.array(np.where(h2[0,:] == np.max(h2, axis=1)[0]))

for i in np.arange(1, m):

t = np.array(np.where(h2[i,:] == np.max(h2, axis=1)[i]))

p = np.vstack((p,t))

return p

输出结果

梯度检查:

用Python实现BP神经网络(附代码)

随机显示100个手写数字

用Python实现BP神经网络(附代码)

显示theta1权重

用Python实现BP神经网络(附代码)

训练集预测准确度

用Python实现BP神经网络(附代码)

归一化后训练集预测准确度

用Python实现BP神经网络(附代码)

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
python flask 多对多表查询功能
Jun 25 Python
Python 逐行分割大txt文件的方法
Oct 10 Python
浅谈Tensorflow模型的保存与恢复加载
Apr 26 Python
Python3爬虫学习之MySQL数据库存储爬取的信息详解
Dec 12 Python
python读文件的步骤
Oct 08 Python
使用python实现对元素的长截图功能
Nov 14 Python
vue学习笔记之动态组件和v-once指令简单示例
Feb 29 Python
Python dict和defaultdict使用实例解析
Mar 12 Python
Django 解决上传文件时,request.FILES为空的问题
May 20 Python
Python+PyQt5+MySQL实现天气管理系统
Jun 16 Python
基于K.image_data_format() == 'channels_first' 的理解
Jun 29 Python
python中time、datetime模块的使用
Dec 14 Python
OpenCV 模板匹配
Jul 10 #Python
8种用Python实现线性回归的方法对比详解
Jul 10 #Python
Python实现计算对象的内存大小示例
Jul 10 #Python
Python画图高斯分布的示例
Jul 10 #Python
使用Python实现跳一跳自动跳跃功能
Jul 10 #Python
windows安装TensorFlow和Keras遇到的问题及其解决方法
Jul 10 #Python
使用python对多个txt文件中的数据进行筛选的方法
Jul 10 #Python
You might like
PHP flush()与ob_flush()的区别详解
2013/06/03 PHP
javascript得到XML某节点的子节点个数的脚本
2008/10/11 Javascript
ExtJS下 Ext.Direct加载和提交过程排错小结
2013/04/02 Javascript
用jQuery获取IE9下拉框默认值问题探讨
2013/07/22 Javascript
原生javaScript做得动态表格(注释写的很清楚)
2013/12/29 Javascript
两个select多选模式的选项相互移动(示例代码)
2014/01/11 Javascript
纯js代码实现简单计算器
2015/12/02 Javascript
jQuery头像裁剪工具jcrop用法实例(附演示与demo源码下载)
2016/01/22 Javascript
javascript实现数组去重的多种方法
2016/03/14 Javascript
关于javascript原型的修改与重写(覆盖)差别详解
2016/08/31 Javascript
浅谈Vue 初始化性能优化
2017/08/31 Javascript
Bootstrap Table快速完美搭建后台管理系统
2017/09/20 Javascript
three.js实现3D模型展示的示例代码
2017/12/31 Javascript
微信小程序以7天为周期连续签到7天功能效果的示例代码
2020/08/20 Javascript
解决vue props传Array/Object类型值,子组件报错的情况
2020/11/07 Javascript
举例讲解Python程序与系统shell交互的方式
2015/04/09 Python
Python实时获取cmd的输出
2015/12/13 Python
Django 2.0版本的新特性抢先看!
2018/01/05 Python
对python读写文件去重、RE、set的使用详解
2018/12/11 Python
Python中栈、队列与优先级队列的实现方法
2019/06/30 Python
python爬虫 爬取超清壁纸代码实例
2019/08/16 Python
Python高级property属性用法实例分析
2019/11/19 Python
用openCV和Python 实现图片对比,并标识出不同点的方式
2019/12/19 Python
你需要学会的8个Python列表技巧
2020/06/24 Python
Pytest单元测试框架如何实现参数化
2020/09/05 Python
美津浓巴西官方网站:Mizuno巴西
2019/07/24 全球购物
教师找工作推荐信
2013/11/23 职场文书
2014年公务员思想汇报范文:全心全意为人民服务
2014/03/06 职场文书
2015年乡镇平安建设工作总结
2015/05/13 职场文书
原告离婚代理词
2015/05/23 职场文书
英语专业毕业论文答辩开场白
2015/05/27 职场文书
2015暑期工社会实践报告
2015/07/13 职场文书
2019毕业典礼主持词!
2019/07/05 职场文书
 Python 中 logging 模块使用详情
2022/03/03 Python
Python之Matplotlib绘制热力图和面积图
2022/04/13 Python
python获取带有返回值的多线程
2022/05/02 Python