用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实现批量转换文件编码的方法
Jul 28 Python
Python基于pygame实现的font游戏字体(附源码)
Nov 11 Python
Python中二维列表如何获取子区域元素的组成
Jan 19 Python
浅谈python中的占位符
Nov 09 Python
python操作列表的函数使用代码详解
Dec 28 Python
Python实现iOS自动化打包详解步骤
Oct 03 Python
python的set处理二维数组转一维数组的方法示例
May 31 Python
wxpython+pymysql实现用户登陆功能
Nov 19 Python
flask的orm框架SQLAlchemy查询实现解析
Dec 12 Python
Python函数参数定义及传递方式解析
Jun 10 Python
详解Django关于StreamingHttpResponse与FileResponse文件下载的最优方法
Jan 07 Python
详解Python中下划线的5种含义
Jul 15 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冒泡排序算法代码详细解读
2011/07/17 PHP
dhtmlxTree目录树增加右键菜单以及拖拽排序的实现方法
2013/04/26 PHP
Zend Framework教程之Loader以及PluginLoader用法详解
2016/03/09 PHP
php连接mysql之mysql_connect()与mysqli_connect()的区别
2020/07/19 PHP
jQuery 遍历json数组的实现代码
2020/09/22 Javascript
JS解析json数据并将json字符串转化为数组的实现方法
2012/12/25 Javascript
js点击更换背景颜色或图片的实例代码
2013/06/25 Javascript
javascript不可用的问题探究
2013/10/01 Javascript
谈谈Jquery ajax中success和complete有哪些不同点
2015/11/20 Javascript
JS中的进制转换以及作用
2016/06/26 Javascript
原生js开发的日历插件
2017/02/04 Javascript
mongoose中利用populate处理嵌套的方法
2017/05/26 Javascript
详解React native全局变量的使用(跨组件的通信)
2017/09/07 Javascript
ng-alain表单使用方式详解
2018/07/10 Javascript
nodejs之koa2请求示例(GET,POST)
2018/08/07 NodeJs
vue项目在安卓低版本机显示空白的原因分析(两种)
2018/09/04 Javascript
HTML元素拖拽功能实现的完整实例
2020/12/04 Javascript
[03:17]史诗级大片应援2018DOTA2国际邀请赛 致敬每一位坚守遗迹的勇士
2018/07/20 DOTA
Python 的类、继承和多态详解
2017/07/16 Python
python数据抓取分析的示例代码(python + mongodb)
2017/12/25 Python
利用python对Excel中的特定数据提取并写入新表的方法
2018/06/14 Python
对Python使用mfcc的两种方式详解
2019/01/09 Python
Python封装成可带参数的EXE安装包实例
2019/08/24 Python
Django 路由层URLconf的实现
2019/12/30 Python
Python单元测试模块doctest的具体使用
2020/02/10 Python
Django实现内容缓存实例方法
2020/06/30 Python
python 实现汉诺塔游戏
2020/11/28 Python
深入理解css中vertical-align属性
2017/04/18 HTML / CSS
canvas拼图功能实现代码示例
2018/11/21 HTML / CSS
打造完美自荐信
2014/01/24 职场文书
读书小明星事迹材料
2014/05/03 职场文书
个人批评与自我批评总结
2014/10/17 职场文书
党员对十八届四中全会的期盼思想汇报范文
2014/10/17 职场文书
病危通知单
2015/04/17 职场文书
芙蓉镇观后感
2015/06/10 职场文书
Python使用MapReduce进行简单的销售统计
2022/04/22 Python