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

2023-11-18

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

 大家好 我是毕加锁(锁!)

今天教大家用Python实现BP神经网络(附代码)

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

BP神经网络

神经网络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)

正则化后的代价函数实现代码:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

# 代价函数

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层的神经网络,

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

《===》

(向量化)

没有

,因为对于输入没有误差

因为S型函数

的倒数为:

所以上面的

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

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

是大写的

for i=1-m:-

-正向传播计算

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

-反向计算

...

-

-

最后

,即得到代价函数的梯度

实现代码:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

# 梯度

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非常接近,求均方差的梯度沿着此梯度方向可使代价函数最小化。可对照上面求梯度的过程。

                                             字比较草 勿喷

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

梯度检查

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

利用导数的定义验证:

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

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

实现代码:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

# 检验梯度是否计算正确

# 检验梯度是否计算正确

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的数

实现代码

1

2

3

4

5

6

7

8

9

10

11

# 随机初始化权重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

预测

正向传播预测结果

实现代码

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

# 预测

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

输出结果

梯度检查:

随机显示100个手写数字

显示theta1权重

训练集预测准确度

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

 我是毕加锁 期待你的关注

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

用Python实现BP神经网络(附代码) 的相关文章

随机推荐

  • C++中在类中重载输出运算符时遇到error: declaration of ‘class T‘的问题的解决

    一 问题代码及报错提示 include
  • 5 神经网络(PRML)

    之前我们讨论的模型是对于分类的回归模型 包含了线性组合的多个基础函数 但是他的应用范围有一定的限制 另外一个方法在于事先限定基础函数的个数并且使得他可自适应的 也就是说使得他的参数值在训练当中是可以发生变化的 其中最成功的模型是前向神经网络
  • 微信小程序开发(六)WXML 模板

    WXML模板
  • AttributeError: module ‘distutils‘ has no attribute ‘version‘ 解决方案

    问题描述 今天在执行时出现了题述错误 查阅了半天才找到解决方案 特此记录 LooseVersion distutils version LooseVersion 解决方案 将以上代码改写成 from distutils version im
  • JDBC基础

    JDBC是什么 用java语言操作关系型数据库的一套api JDBC是用来干什么的 用java语言来操作数据库 JDBC怎么写 1 加载驱动类Driver全限定名 包 类名 2 获取连接 getConnection url username
  • maven.plugins.enforcer.BannedDependences 异常解决方案

    maven plugins enforcer BannedDependences 异常解决方案 简介 maven enforce plugin是一个规范maven构建环境的插件 例如 Maven版本 JDK版本和OS系列以及更多内置规则和用
  • 图的基本操作(无向图)

    图的定义 图 Graph 在是一种较线性表和树更为复杂的数据结构 在线性表中 数据元素之间是被串起来的 只有线性关系 每个数据元素只有一个直接前驱和一个直接后继 在树形结构中 数据元素之间有着很明显的层次关系 并且每一层的数据元素可能和下一
  • 证明:Java代码在执行过程中,并不一定是从上到下,每句代码依次顺序执行的

    今天给大家带来一个毁三观的结论 Java代码在执行过程中 并不一定是从上到下 每句代码依次顺序执行的 这是不是很颠覆你的认知 计算机在执行程序的时候 并不会严格按照代码来顺序执行 比如第一个指令 是从内存中读取一个数据 而第二个指令 是寄存
  • zabbix设定监控指标每天调用一次

    添加了数据库备份的监控项 因为备份每天只做一次 如果一直取数意义不大 所以设定在每条早上9点取一次值 设定方式如图 更新间隔需要修改为0 否则还会按照间隔获取信息 选择调度 h表示小时 h9表示每天九点
  • 蓝桥杯第十一届青少年Python组省赛试题

    选择题答案 ADDCA s input if s 2 er or s 2 ly s s 2 elif s 3 ing s s 3 print s n int input cnt 0 for i in range 2 n s 0 for j
  • Unity平台如何实现RTSP转RTMP推送?

    技术背景 Unity平台下 RTSP RTMP播放和RTMP推送 甚至包括轻量级RTSP服务这块都不再赘述 今天探讨的一位开发者提到的问题 如果在Unity下 实现RTSP播放的同时 随时转RTMP推送出去 RTSP转RTMP 在原生环境下
  • 开始做一个平台程序

    先赚个积分吧 公司的项目 从0开始
  • BP、CNN、ResNet:图片分类FashionMnist和CIFAR-10

    源码 GitHub jeanMrx FashionMnist CIFAR10 一 实验目的 理解BP神经网络和卷积神经网络的结构和原理 掌握反向传播学习算法对神经元的训练过程 了解损失函数的反向传播和梯度下降 通过构建BP神经网络和卷积神经
  • Ubuntu Desktop 启用远程桌面(Vino和TigerVNC方式)

    文章目录 前言 使用Vino方式 无显示器使用 使用TigerVNC方式 前言 在很多领域的生产开发工作中常常需要用到 Ubuntu Desktop 系统 但是在一些日常的工作交流中又离不开Windows系统 这种时候比较常用的解决方案就是
  • ElasticSearch-DSL语句使用-Kibana界面操作

    Query DSL结构化查询介绍 Query DSL是一个Java开源框架用于构建类型安全的SQL查询语句 采用API代替传统的拼接字符串来构造查询语句 目前Querydsl支持的平台包括JPA JDO SQL Java Collectio
  • R语言数据分析案例合集

    案例一 汽车数据可视化分析 R ggplot2 案例二 房价指数的分析与预测 时间序列
  • 简单了解照相机

    以上是随便找网上找的一张正经的照相机图片 如今照相机各种各样 今天我们会简单了解一下照相机的工作原理 涉及的工作原理 主要是这两个原理 话说很早很早的时候 我们的老祖宗 墨子就发现了 用一个带有小孔的板遮挡在墙体与物体之间 墙体上就会形成物
  • idea中使用git stash和git unstash

    一 git中没有提交到本地仓库的改变内容会带到别的分支 git 切换分支时会把未add或未commit的内容带过去 这样可能造成代码覆盖的问题 这个在工作中会经常遇到 二 对本地仓库的文件进行了修改 但没有提交到本地仓库 切换分支时会造成代
  • 小程序微信支付功能逻辑

    官方的思维图在下看不懂 自己整理一份以备后用 1 打开Pay付款页面 2 用订单号 查看订单信息前端展示 3 点击付款按钮 提交订单ID到后台 创建微信预支付交易订单 用JSAPI下单 4 返回创建后的 预支付订单编号信息 存入数据表 5
  • 用Python实现BP神经网络(附代码)

    用Python实现BP神经网络 附代码 大家好 我是毕加锁 锁 今天教大家用Python实现BP神经网络 附代码 用Python实现出来的机器学习算法都是什么样子呢 前两期线性回归及逻辑回归项目已发布 见文末链接 今天来讲讲BP神经网络 B