手写串行BP算法,可调batch_size

既要:1、输入层f(x)=x  隐藏层sigmoid 输出层f(x)=x

2、run函数实现单条数据的一次前馈

3、train函数读入所有数据for循环处理每条数据。

循环中:

首先调用run函数,得到各层的值

self.input_nodes_value

self.hidden_nodes_value

self.output_nodes_value

然后计算输出层误差和delta

4、关键函数:用于前馈的sigmoid和用于反馈的sigmoid的导数

  1. self.activation_function = lambda x : 1/(1+np.exp(-x)) # sigmoid函数,用于正向传播
  2. self.delta_activation_function = lambda x: x-x**2 # sigmoid一阶导,用于反向传播

5、反向传播

使用梯度下降方法

下面是推导隐藏层(实际上为relu层)到输出层的权重w[h][o]的梯度下降公式的过程,对应的几个变量在下面的代码中用红色标出

关于梯度下降公式推导:

https://blog.csdn.net/wfei101/article/details/80807749

https://www.jianshu.com/p/17191c57d7e9

  1. batch_size=1
  2.  
  3. # 输入层没有激活函数f(x)=x,隐藏层激活函数sigmoid,输出层激活函数f(x)=x
  4. class NeuralNetwork(object):
  5. def __init__(self, input_nodes, hidden_nodes, output_nodes, learning_rate):
  6.  
  7. # 各层节点个数
  8. self.input_nodes = input_nodes
  9. self.hidden_nodes = hidden_nodes
  10. self.output_nodes = output_nodes
  11.  
  12. # 创建三个一维数组存放三层节点的值
  13. # print(str(self.input_nodes)+" "+str(self.hidden_nodes)+" "+str(self.output_nodes))
  14. self.input_nodes_value=[0.0]*input_nodes
  15. self.hidden_nodes_value=[0.0]*hidden_nodes
  16. self.output_nodes_value=[0.0]*output_nodes
  17.  
  18. # Initialize weights
  19. self.weights_input_to_hidden = np.random.normal(0.0, self.input_nodes**-0.5, (self.input_nodes, self.hidden_nodes))#输入层>>隐藏层权重矩阵
  20.  
  21. self.weights_hidden_to_output = np.random.normal(0.0, self.hidden_nodes**-0.5, (self.hidden_nodes, self.output_nodes))#隐藏层>>输出层权重矩阵
  22.  
  23. self.learning_rate = learning_rate#学习率
  24.  
  25. self.activation_function = lambda x : 1/(1+np.exp(-x)) # sigmoid函数,用于正向传播
  26. self.delta_activation_function = lambda x: x-x**2 # sigmoid一阶导,用于反向传播
  27.  
  28. self.change_to_fix_weights_h2o=[[0.0]*self.output_nodes]*self.hidden_nodes#存储隐藏层>>输出层权重调整量
  29. self.change_to_fix_weights_i2h=[[0.0]*self.hidden_nodes]*self.input_nodes#存储输入层>>隐藏层权重调整量
  30. # print("xxxx")
  31. # print(self.change_to_fix_weights_h2o)
  32. # print(self.change_to_fix_weights_i2h)
  33.  
  34. def train(self, features, targets):#完成n条数据的一次前向传递和反向传递,每个batch调整一次权重矩阵
  35. '''
  36. features: 2D array, each row is one data record, each column is a feature
  37. targets: 1D array of target values
  38.  
  39. '''
  40. n=features.shape[0]#数据条数
  41. # print(features)
  42. # print(targets)
  43.  
  44. counter=batch_size
  45. for ii in range(0,n):
  46.  
  47. self.run(features[ii])#调用前向传播
  48.  
  49. print(self.output_nodes_value)
  50.  
  51. error_o=[0.0]*self.output_nodes#输出层误差
  52. error_h=[0.0]*self.hidden_nodes#隐藏层误差
  53. output_deltas=[0.0]*self.output_nodes
  54. hidden_deltas=[0.0]*self.hidden_nodes
  55.  
  56. for o in range(self.output_nodes): # 输 出 层
  57. error_o[o]=targets[ii][o]-self.output_nodes_value[o]#计算输出层误差
  58. # output_deltas[o]=self.delta_activation_function(self.output_nodes_value[o])*error_o[o]#输出层反向传播(求导)
  59. output_deltas[o]=1*error_o[o]#输出层反向传播(求导)
  60.  
  61. for h in range(self.hidden_nodes): # 隐 藏 层
  62. for o in range(self.output_nodes):
  63. # print('weight::',self.weights_hidden_to_output[h][o])
  64. error_h[h]+=output_deltas[o]*self.weights_hidden_to_output[h][o]#计算隐藏层误差
  65.  
  66. # print('....')
  67. # print(self.hidden_nodes_value[h])
  68. # print(error_h[h])
  69. hidden_deltas[h]=self.delta_activation_function(self.hidden_nodes_value[h])*error_h[h]#隐藏层反向传播
  70. # print(hidden_deltas[h])
  71.  
  72. for h in range(self.hidden_nodes):
  73. for o in range(self.output_nodes):
  74. self.change_to_fix_weights_h2o[h][o]+=output_deltas[o]*self.hidden_nodes_value[h]#累计隐藏层>>输出层的权重矩阵的调整量
  75.  
  76. for i in range(self.input_nodes):
  77. for h in range(self.hidden_nodes):
  78. # print("......")
  79. # print(hidden_deltas[h])
  80. # print(self.input_nodes_value[i])
  81. # print(self.change_to_fix_weights_i2h[i][h])
  82. self.change_to_fix_weights_i2h[i][h]+=hidden_deltas[h]*self.input_nodes_value[i]#累计输入层>>隐藏层的权重矩阵的调整量
  83.  
  84. counter-=1
  85. if counter==0:#完成一个batch的输入和计算后,调整一次权重
  86. #调整隐藏层>>输出层权重
  87. for h in range(self.hidden_nodes):
  88. for o in range(self.output_nodes):
  89. self.weights_hidden_to_output[h][o] += self.learning_rate*self.change_to_fix_weights_h2o[h][o]
  90.  
  91. #调整输入层>>隐藏层权重
  92. for i in range(self.input_nodes):
  93. for h in range(self.hidden_nodes):
  94. # print("......")
  95. # print(self.weights_input_to_hidden[i][h])
  96. # print(self.learning_rate)
  97. # print(self.change_to_fix_weights_i2h[i][h])
  98. self.weights_input_to_hidden[i][h] += self.learning_rate*self.change_to_fix_weights_i2h[i][h]
  99. # print(self.weights_input_to_hidden[i][h])
  100. #将权值调整量归零,计数器复位,开始输入下一个batch
  101. self.change_to_fix_weights_h2o=[[0.0]*self.output_nodes]*self.hidden_nodes
  102. self.change_to_fix_weights_i2h=[[0.0]*self.hidden_nodes]*self.input_nodes
  103. counter=batch_size
  104. return self.weights_hidden_to_output
  105.  
  106. def run(self, features):#完成一条数据的一次前向传递
  107. '''
  108. features: 1D array of feature values
  109. '''
  110. # print(self.input_nodes_value)
  111. for i in range(self.input_nodes):
  112. self.input_nodes_value[i]=features[i]
  113. # self.input_nodes_value[i]=self.activation_function(features[i])
  114. # print(self.input_nodes_value)
  115.  
  116. # print(self.hidden_nodes_value)
  117. for h in range(self.hidden_nodes):
  118. temp=0
  119. for i in range(self.input_nodes):
  120. temp+=self.input_nodes_value[i]*self.weights_input_to_hidden[i][h]
  121. temp=self.activation_function(temp)
  122. self.hidden_nodes_value[h]=temp
  123. # print(self.hidden_nodes_value)
  124.  
  125. # print(self.output_nodes_value)
  126. for o in range(self.output_nodes):
  127. temp=0
  128. for h in range(self.hidden_nodes):
  129. temp+=self.hidden_nodes_value[h]*self.weights_hidden_to_output[h][o]
  130. # temp=self.activation_function(temp)
  131. self.output_nodes_value[o]=temp
  132. # print(self.output_nodes_value)
  133.  
  134. return self.output_nodes_value

单元测试:

  1. import unittest
  2.  
  3. inputs = np.array([[0.5, -0.2, 0.1]])
  4. targets = np.array([[0.4]])
  5. test_w_i_h = np.array([[0.1, -0.2],
  6. [0.4, 0.5],
  7. [-0.3, 0.2]])
  8. test_w_h_o = np.array([[0.3],
  9. [-0.1]])
  10.  
  11. class TestMethods(unittest.TestCase):
  12.  
  13. ##########
  14. # Unit tests for data loading
  15. ##########
  16.  
  17. def test_data_path(self):
  18. # Test that file path to dataset has been unaltered
  19. self.assertTrue(data_path.lower() == 'bike-sharing-dataset/hour.csv')
  20.  
  21. def test_data_loaded(self):
  22. # Test that data frame loaded
  23. self.assertTrue(isinstance(rides, pd.DataFrame))
  24.  
  25. ##########
  26. # Unit tests for network functionality
  27. ##########
  28.  
  29. def test_activation(self):
  30. network = NeuralNetwork(3, 2, 1, 0.5)
  31. # Test that the activation function is a sigmoid
  32. self.assertTrue(np.all(network.activation_function(0.5) == 1/(1+np.exp(-0.5))))
  33.  
  34. def test_train(self):
  35. # Test that weights are updated correctly on training
  36. network = NeuralNetwork(3, 2, 1, 0.5)
  37. network.weights_input_to_hidden = test_w_i_h.copy()
  38. network.weights_hidden_to_output = test_w_h_o.copy()
  39.  
  40. network.train(inputs, targets)
  41. print('@@@@test_train')
  42. print("$$$$$$$$1")
  43. print(network.weights_hidden_to_output)
  44. print(network.weights_input_to_hidden)
  45.  
  46. # network.train(inputs,targets)
  47.  
  48. # print("$$$$$$$$2")
  49. # print(network.weights_hidden_to_output)
  50. # print(network.weights_input_to_hidden)
  51.  
  52. self.assertTrue(np.allclose(network.weights_hidden_to_output,
  53. np.array([[ 0.37275328],
  54. [-0.03172939]])))
  55. self.assertTrue(np.allclose(network.weights_input_to_hidden,
  56. np.array([[ 0.10562014, -0.20185996],
  57. [0.39775194, 0.50074398],
  58. [-0.29887597, 0.19962801]])))
  59.  
  60. def test_run(self):
  61. # Test correctness of run method
  62. network = NeuralNetwork(3, 2, 1, 0.5)
  63. network.weights_input_to_hidden = test_w_i_h.copy()
  64. network.weights_hidden_to_output = test_w_h_o.copy()
  65.  
  66. self.assertTrue(np.allclose(network.run(inputs[0]), 0.09998924))
  67.  
  68. suite = unittest.TestLoader().loadTestsFromModule(TestMethods())
  69. unittest.TextTestRunner().run(suite)

结果:

结果虽然比较接近,但是代码比较丑陋,并没有用numpy的矩阵相乘,而是用for循环实现了矩阵乘法,代码复杂,而且都是串行的。

贪玩ML系列之一个BP玩一天的更多相关文章

  1. 贪玩ML系列之CIFAR-10调参

    调参方法:网格调参 tf.layers.conv2d()中的padding参数 取值“same”,表示当filter移出边界时,给空位补0继续计算.该方法能够更多的保留图像边缘信息.当图片较小(如CI ...

  2. 每日一译系列-模块化css怎么玩(译文)

    原文链接:How Css Modules Work 原文作者是Preact的作者 这是一篇关于如何使用Css Modules的快速介绍,使用到的工具是Webpack吊炸的css-loader 首先,我 ...

  3. ROS与Matlab系列:一个简单的运动控制

    ROS与Matlab系列:一个简单的运动控制 转自:http://blog.exbot.net/archives/2594 Matlab拥有强大的数据处理.可视化绘图能力以及众多成熟的算法函数,非常适 ...

  4. net core天马行空系列: 一个接口多个实现类,利用mixin技术通过自定义服务名,实现精准属性注入

    系列目录 1.net core天马行空系列:原生DI+AOP实现spring boot注解式编程 2.net core天马行空系列: 泛型仓储和声明式事物实现最优雅的crud操作 哈哈哈哈,大家好,我 ...

  5. NET中小型企业项目开发框架系列(一个)

    当时的前端,我们开发了基于Net一组结构sprint.NET+NHibernate+MVC+WCF+EasyUI等中小型企业级系统开发平台,如今把整个开发过程中的步步进展整理出来和大家分享,这个系列可 ...

  6. Office365开发系列——开发一个全功能的Word Add-In

    2016年10月我参加了在北京举行的DevDays Asia 2016 - Office 365应用开发”48小时黑客马拉松“,我开发的一个Word Add-In Demo——WordTemplate ...

  7. http协议学习系列(一个博文链接)

    深入理解HTTP协议(转) http协议学习系列(转自:http://www.blogjava.net/zjusuyong/articles/304788.html) 1. 基础概念篇 1.1 介绍 ...

  8. 造轮子系列(三): 一个简单快速的html虚拟语法树(AST)解析器

    前言 虚拟语法树(Abstract Syntax Tree, AST)是解释器/编译器进行语法分析的基础, 也是众多前端编译工具的基础工具, 比如webpack, postcss, less等. 对于 ...

  9. 爱上MVC3系列~开发一个站点地图(俗称面包屑)

    回到目录 原来早在webform控件时代就有了SiteMap这个东西,而进行MVC时代后,我们也希望有这样一个东西,它为我们提供了不少方便,如很方便的实现页面导航的内容修改,页面导航的样式换肤等. 我 ...

随机推荐

  1. Atitit.swt 线程调用ui控件的方法

    Atitit.swt 线程调用ui控件的方法 1 SwingUtilities.invokeLater1 2 display.asyncExec方法1 3  display.timerExec(500 ...

  2. nginx 查看访问 IP 并封禁 IP 详解

    1.查找服务器所有访问者ip方法: awk '{print $1}' nginx_access.log |sort |uniq -c|sort -n nginx.access.log 为nginx访问 ...

  3. ORACLE建立物化视图

    --使用 on commit 的方式建立物化视图 create materialized view emp_dept refresh on commit as select t.*,d.dname f ...

  4. linux时间同步-NTP服务

    作者:曹世军链接:https://www.zhihu.com/question/30252609/answer/108840850来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注 ...

  5. python学习笔记2---函数

    函数主要是为了代码复用. 函数分为两种:系统库预定义函数,自定义函数. 函数格式: def functionName(): statement 函数调用: funtionName() 函数的参数:形参 ...

  6. [待解决]ColumnPrefixFilter 不能过滤出全部满足条件的,

    Scan scan = new Scan(); ColumnPrefixFilter columnPrefixFilter = new hbase(main)::> scan 't4' ROW ...

  7. VMware网络连接失败解决方法

    假如你碰到了VMware 网络被断开,明明已经分配了适配器,客户端却显示网络断开没有连接. 一. 可用恢复默认的方法重置所有网卡及服务. 如图片操作: 进主工具首页.点击: 虚拟网络编辑器 然后点击下 ...

  8. MySQL定义异常和异常处理方法

    在MySQL中.特定异常须要特定处理.这些异常可以联系到错误,以及子程序中的一般流程控制.定义异常是事先定义程序运行过程中遇到的问题,异常处理定义了在遇到问题时相应当採取的处理方式.而且保证存储过程或 ...

  9. Linux CentOS 修改内核引导顺序

    CentOS 7.0 系统更改内核启动顺序 可以 uname -a查下当前的 由于 CentOS 7 使用 grub2 作为引导程序,所以和 CentOS 6 有所不同,并不是修改 /etc/grub ...

  10. ARGOX 力象 OS-214Plus 条码打印机 B/S 打印

    官网demo下载地址: http://www.argox.com.cn/servicedev/5/c 页面中嵌入activeX控件: <object id="ArgoxPrinter& ...