用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使用pil生成图片验证码的方法
May 08 Python
不可错过的十本Python好书
Jul 06 Python
Python实现求笛卡尔乘积的方法
Sep 16 Python
python实现zabbix发送短信脚本
Sep 17 Python
Python 处理文件的几种方式
Aug 23 Python
Python实时监控网站浏览记录实现过程详解
Jul 14 Python
python实现数字炸弹游戏程序
Jul 17 Python
学python爬虫能做什么
Jul 29 Python
解决Windows下python和pip命令无法使用的问题
Aug 31 Python
Python爬虫爬取有道实现翻译功能
Nov 27 Python
基于pycharm 项目和项目文件命名规则的介绍
Jan 15 Python
python实现简单的井字棋游戏(gui界面)
Jan 22 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应用程序来获取Web服务器的状态信息
2006/10/09 PHP
PHP 身份证号验证函数
2009/05/07 PHP
php header示例代码(推荐)
2010/09/08 PHP
用php的ob_start来生成静态页面的方法分析
2011/03/09 PHP
php计算两个文件相对路径的方法
2015/03/14 PHP
PHP使用flock实现文件加锁的方法
2015/07/01 PHP
PHP远程调试之XDEBUG
2015/12/29 PHP
微信开发之获取JSAPI TICKET
2017/07/07 PHP
Javascript 对象的解释
2008/11/24 Javascript
详解JavaScript的策略模式编程
2015/06/24 Javascript
浅析JavaScript 箭头函数 generator Date JSON
2016/05/23 Javascript
一次$.getJSON不执行的简单记录
2016/07/19 Javascript
canvas实现钟表效果
2017/02/13 Javascript
基于Axios 常用的请求方法别名(详解)
2018/03/13 Javascript
vue中使用heatmapjs的示例代码(结合百度地图)
2018/09/05 Javascript
详解关于Vue版本不匹配问题(Vue packages version mismatch)
2018/09/17 Javascript
详解小程序中h5页面onShow实现及跨页面通信方案
2019/05/30 Javascript
解决微信小程序中的滚动穿透问题
2019/09/16 Javascript
vue中更改数组中属性,在页面中不生效的解决方法
2019/10/30 Javascript
JS实现电脑虚拟键盘打字测试
2020/06/24 Javascript
微信小程序中data-key属性之数据传输(经验总结)
2020/08/22 Javascript
[03:03]2014DOTA2西雅图国际邀请赛 Alliance战队巡礼
2014/07/07 DOTA
python实现ipsec开权限实例
2014/11/11 Python
Python简单实现安全开关文件的两种方式
2016/09/19 Python
python和shell获取文本内容的方法
2018/06/05 Python
详解pandas的外部数据导入与常用方法
2019/05/01 Python
PyQt5 QTableView设置某一列不可编辑的方法
2019/06/25 Python
Python logging模块写入中文出现乱码
2020/05/21 Python
详解CSS3 用border写 空心三角箭头 (两种写法)
2017/09/29 HTML / CSS
利用CSS3 动画 绘画 圆形动态时钟
2018/03/20 HTML / CSS
甲方资料员岗位职责
2013/12/13 职场文书
家教广告词
2014/03/19 职场文书
《美丽的南沙群岛》教学反思
2014/04/27 职场文书
工作汇报开头与结尾怎么写
2014/11/08 职场文书
2016年党员干部廉政承诺书
2016/03/24 职场文书
MySQL Shell import_table数据导入的实现
2021/08/07 MySQL