孔子曰,吾日三省吾身。我们如果跟程序打交道,除了一日三省吾身外,还要三日一省吾代码。看代码是否可以更简洁,更易懂,更容易扩展,更通用,算法是否可以再优化,结构是否可以再往上抽象。代码在不断的重构过程中,更臻化境。佝偻者承蜩如是,大匠铸剑亦复如是,艺虽小,其道一也。所谓苟日新,再日新,日日新。

本次对前两篇文章代码进行重构,主要重构函数接口体系,和权重矩阵的封装。

简单函数

所说函数,是数学概念上的函数。数学上的函数,一般有一自变量$x$(输入)和对应的值$y=f(x)$(输出)。其中$x$可以是个数字,一个向量,一个矩阵等等。我们用泛型定义如下:

  1. public interface Function<I,O> {
  2. O valueAt(I x);
  3. }

I代表输入类型,O代表输出类型。

有的函数是可微的,比如神经网络的激活函数。可微函数除了是一个函数,还可求出给定$x$处的导数,或者梯度。而且梯度类型与自变量类型一致。用泛型定义如下:

  1. public interface DifferentiableFunction<I,O> extends Function<I,O> {
  2. I derivativeAt(I x);
  3. }

同时,考虑到某些函数,在求得值和导数时,共同用到了一些中间变量,或者后一个可以用到前一个的结果,我们定义了PreCaculate接口。当我们判定一个函数实现了PreCaculate接口时,我们首先调用它的PreCaculate接口,让它预先计算出一些有用的中间变量,然后再调用其valueAt和derivativeAt求得其具体的值,这样可以节省一些操作步骤。定义如下:

  1. public interface PreCaculate<I> {
  2. void preCaculate(I x);
  3. }

基于上面的定义,我们定义神经网络的激活函数的类型为:

  1. public interface ActivationFunction extends DifferentiableFunction<DoubleMatrix, DoubleMatrix>

即我们激活函数是一个可微函数,输入为一个矩阵(netResult),输出为一个矩阵(finalResult)。

带参函数

有些函数,除了自变量外,还有一些其它的系数,或者参数,我们称为超参数。比如误差函数,目标值为参数,输出值为自变量。这类函数接口定义如下:

  1. public interface ParamFunction<I,O,P> {
  2. O valueAt(I x,P param);
  3. }

类似的,定义其微分接口如下:

  1. public interface DifferentiableParamFunction<I, O, P> extends ParamFunction<I, O, P> {
  2. I derivativeAt(I x,P param);
  3. }

我们的误差函数定义如下:

  1. public interface CostFunction extends DifferentiableParamFunction<DoubleMatrix,DoubleMatrix,DoubleMatrix>

输入,输出,参数都为矩阵。

组合矩阵

在神经网络的概念中,每两层之间有一个权重矩阵,偏置矩阵,如果输入字向量也要调整,那么还有一个字典矩阵。这些所有的矩阵随着迭代过程不断更新,以期使误差函数达到最小。从广义上来讲,训练样本就是超参数,这些所有的矩阵为自变量,误差函数就是优化函数。那么实质上,在调整权重矩阵时,自变量即这一系列的矩阵可以展开拉长拼接成一个超长的向量而已,其内部的结构已无关紧要。在jare的源码中,是把这些权重矩阵的值存储在一个长的double[]中,计算完毕后,再从这个doulbe[]中还原出各矩阵的结构。在这里,我们定义了一个类CompactDoubleMatrix名为超矩阵来从更高一层封装这些矩阵变量,使其对外表现出好像就是一个矩阵。

这个CompactDoubleMatrix的实现方式为,在内部维护一个DoubleMatrix的有序列表List<DoubleMatrix>,然后再执行加减乘除操作时,会批量的对列表中的所有矩阵执行。这样的封装,我们随后会发现将简化了我们大量代码。先把完整定义放上来。

  1. public class CompactDoubleMatrix {
  2. List<DoubleMatrix> mats = new ArrayList<DoubleMatrix>();
  3.  
  4. @SafeVarargs
  5. public CompactDoubleMatrix(List<DoubleMatrix>... matListArray) {
  6. super();
  7. this.append(matListArray);
  8. }
  9.  
  10. public CompactDoubleMatrix(DoubleMatrix... matArray) {
  11. super();
  12. this.append(matArray);
  13. }
  14.  
  15. public CompactDoubleMatrix() {
  16. super();
  17. }
  18.  
  19. public CompactDoubleMatrix addi(CompactDoubleMatrix other) {
  20. this.assertSize(other);
  21. for (int i = 0; i < this.length(); i++)
  22. this.get(i).addi(other.get(i));
  23. return this;
  24. }
  25.  
  26. public void subi(CompactDoubleMatrix other) {
  27. this.assertSize(other);
  28. for (int i = 0; i < this.length(); i++)
  29. this.get(i).subi(other.get(i));
  30. }
  31.  
  32. public CompactDoubleMatrix add(CompactDoubleMatrix other) {
  33. this.assertSize(other);
  34. CompactDoubleMatrix result = new CompactDoubleMatrix();
  35. for (int i = 0; i < this.length(); i++) {
  36. result.append(this.get(i).add(other.get(i)));
  37. }
  38. return result;
  39. }
  40.  
  41. public CompactDoubleMatrix sub(CompactDoubleMatrix other) {
  42. this.assertSize(other);
  43. CompactDoubleMatrix result = new CompactDoubleMatrix();
  44. for (int i = 0; i < this.length(); i++) {
  45. result.append(this.get(i).sub(other.get(i)));
  46. }
  47. return result;
  48. }
  49.  
  50. public CompactDoubleMatrix mul(CompactDoubleMatrix other) {
  51. this.assertSize(other);
  52. CompactDoubleMatrix result = new CompactDoubleMatrix();
  53. for (int i = 0; i < this.length(); i++) {
  54. result.append(this.get(i).mul(other.get(i)));
  55. }
  56. return result;
  57. }
  58.  
  59. public CompactDoubleMatrix muli(double d) {
  60.  
  61. for (int i = 0; i < this.length(); i++) {
  62. this.get(i).muli(d);
  63. }
  64. return this;
  65. }
  66.  
  67. public CompactDoubleMatrix mul(double d) {
  68. CompactDoubleMatrix result = new CompactDoubleMatrix();
  69. for (int i = 0; i < this.length(); i++) {
  70. result.append(this.get(i).mul(d));
  71. }
  72. return result;
  73. }
  74.  
  75. public CompactDoubleMatrix dup() {
  76. CompactDoubleMatrix result = new CompactDoubleMatrix();
  77. for (int i = 0; i < this.length(); i++) {
  78. result.append(this.get(i).dup());
  79. }
  80. return result;
  81. }
  82.  
  83. public double dot(CompactDoubleMatrix other) {
  84. double sum = 0;
  85. for (int i = 0; i < this.length(); i++) {
  86. sum += this.get(i).dot(other.get(i));
  87. }
  88. return sum;
  89. }
  90.  
  91. public double norm() {
  92. double sum = 0;
  93. for (int i = 0; i < this.length(); i++) {
  94. double subNorm = this.get(i).norm2();
  95. sum += subNorm * subNorm;
  96. }
  97. return Math.sqrt(sum);
  98. }
  99.  
  100. public void assertSize(CompactDoubleMatrix other) {
  101. assert (other != null && this.length() == other.length());
  102. for (int i = 0; i < this.length(); i++) {
  103. assert (this.get(i).sameSize(other.get(i)));
  104. }
  105. }
  106.  
  107. @SuppressWarnings("unchecked")
  108. public void append(List<DoubleMatrix>... matListArray) {
  109. for (List<DoubleMatrix> list : matListArray) {
  110. this.mats.addAll(list);
  111. }
  112. }
  113.  
  114. public void append(DoubleMatrix... matArray) {
  115. for (DoubleMatrix mat : matArray)
  116. this.mats.add(mat);
  117. }
  118.  
  119. public int length() {
  120. return mats.size();
  121. }
  122.  
  123. public DoubleMatrix get(int index) {
  124. return this.mats.get(index);
  125. }
  126.  
  127. public DoubleMatrix getLast() {
  128. return this.mats.get(this.length() - 1);
  129. }
  130. }

以上介绍了对各抽象概念的封装,下章介绍使用这些封装如何简化我们的代码。

用java写bp神经网络(三)的更多相关文章

  1. 用java写bp神经网络(一)

    根据前篇博文<神经网络之后向传播算法>,现在用java实现一个bp神经网络.矩阵运算采用jblas库,然后逐渐增加功能,支持并行计算,然后支持输入向量调整,最后支持L-BFGS学习算法. ...

  2. 用java写bp神经网络(四)

    接上篇. 在(一)和(二)中,程序的体系是Net,Propagation,Trainer,Learner,DataProvider.这篇重构这个体系. Net 首先是Net,在上篇重新定义了激活函数和 ...

  3. 用java写bp神经网络(二)

    接上篇. Net和Propagation具备后,我们就可以训练了.训练师要做的事情就是,怎么把一大批样本分成小批训练,然后把小批的结果合并成完整的结果(批量/增量):什么时候调用学习师根据训练的结果进 ...

  4. JAVA写JSON的三种方法,java对象转json数据

    JAVA写JSON的三种方法,java对象转json数据 转自:http://www.xdx97.com/#/single?bid=5afe2ff9-8cd1-67cf-e7bc-437b74c07a ...

  5. python手写bp神经网络实现人脸性别识别1.0

    写在前面:本实验用到的图片均来自google图片,侵删! 实验介绍 用python手写一个简单bp神经网络,实现人脸的性别识别.由于本人的机器配置比较差,所以无法使用网上很红的人脸大数据数据集(如lf ...

  6. JAVA实现BP神经网络算法

    工作中需要预测一个过程的时间,就想到了使用BP神经网络来进行预测. 简介 BP神经网络(Back Propagation Neural Network)是一种基于BP算法的人工神经网络,其使用BP算法 ...

  7. java写卷积神经网络---CupCnn简介

    https://blog.csdn.net/u011913612/article/details/79253450

  8. 【机器学习】BP神经网络实现手写数字识别

    最近用python写了一个实现手写数字识别的BP神经网络,BP的推导到处都是,但是一动手才知道,会理论推导跟实现它是两回事.关于BP神经网络的实现网上有一些代码,可惜或多或少都有各种问题,在下手写了一 ...

  9. BP神经网络—java实现(转载)

    神经网络的结构 神经网络的网络结构由输入层,隐含层,输出层组成.隐含层的个数+输出层的个数=神经网络的层数,也就是说神经网络的层数不包括输入层.下面是一个三层的神经网络,包含了两层隐含层,一个输出层. ...

随机推荐

  1. linux下常用网络操作汇总

    首先说明下RHEL6下设置IP地址的确和RHEL5下有几点是不同的. 我装完RHEL6中默认选择的是DHCP自动获取方式: [root@localhost ~]# vi /etc/sysconfig/ ...

  2. magic c c++ unix 注册机 注册码 破解版 下载

    说起来都是伤心的事情前段时间,忙于找工作,面试的公司和入职的公司,想想都觉得很奇葩,其中有一家叫什么湖南普天科技有限公司的,他们是从国防科大接项目做的,那天他们叫我去面试,面试完了,说我们这里有个c+ ...

  3. [LeetCode#260]Single Number III

    Problem: Given an array of numbers nums, in which exactly two elements appear only once and all the ...

  4. Nginx windows下搭建过程

    内容列表: 简要介绍 下载安装 配置测试 一.简要介绍 Nginx ("engine x") 是一个高性能的 HTTP 和 反向代理 服务器,也是一个 IMAP/POP3/SMTP ...

  5. position: absolute 的元素自动对齐父元素 border 外边缘

    Position with border outer edge CSS box-flex align-items justify-content

  6. ☀【HTML5】Modernizr

    Modernizr 使用Modernizr探测HTML5/CSS3新特性

  7. Windows进程

    一.Windows进程 1.进程 进程是一种容器,包含了应用程序实例的各种资源. 2.Windows进程的一些特点 2.1.进程中包含了执行代码等资源 2.2.进程都具有私有的地址空间 2.3.每个进 ...

  8. git bash【初级入门篇】

    最近公司打算使用git代替之前的svn版本控制工具,趁此机会打算好好学学git,这个号称当今世界最牛的分布式版本控制工具. 一.[git和svn的主要区别] 1.去中心化 svn以及微软的TFS均采用 ...

  9. HDOJ1020 Encoding

    Problem Description Given a string containing only 'A' - 'Z', we could encode it using the following ...

  10. JavaScript高级程序设计12.pdf

    第六章 面向对象的程序设计 ECMA中有两种属性:数据属性和访问器属性 数据属性的特性 [[Configurable]] 表示是否通过delete删除属性,是否重新定义属性,是否能把属性修改为访问器属 ...