BP神经网络—java实现
神经网络的结构
神经网络的网络结构由输入层,隐含层,输出层组成。隐含层的个数+输出层的个数=神经网络的层数,也就是说神经网络的层数不包括输入层。下面是一个三层的神经网络,包含了两层隐含层,一个输出层。其中第一层隐含层的节点数为3,第二层的节点数为2,输出层的节点数为1;输入层为样本的两个特征X1,X2.
图1 三层神经网络
在神经网络中每一个节点的都与上一层的所有节点相连,称为全连接。神经网络的上一层输出的数据是下一层的输入数据。在图中的神经网络中,原始的输入数据,通过第一层隐含层的计算得出的输出数据,会传到第二层隐含层。而第二层的输出,又会作为输出层的输入数据。
神经网络中的每一层(除了输入层)都是由神经元组成,也称为节点。每一个神经元都相当于一个感知器。如下图:
图2 单个神经元
在神经网络中,每个节点都将计算出特征矩阵X与权值矩阵的加权和,得到净输入e,然后通过激励函数f(e)得到该节点的输出y。在图1中,每条连线都可以看做是一个权值。
在神经网络中,可以添加输出层节点的个数来解决多分类问题。有四个类别需要分类则,则输出层的节点个数可以设为4个节点,每一个节点代表一个类别。
BP神经网络的训练过程
神经网络的训练过程分为两个过程:1、向前传播得到预测数据;2、反向传播更新权重。如下图所示:
图3 神经网络的训练过程
第一步、向前传播得到预测数据:向前传播的过程,即数据从输入层输入,经过隐含层,输出层的计算得到预测值,预测值为输出层的输出结果。网络层的输出即,该层中所有节点(神经元)的输出值的集合。我们以图一的神经网络结构为例,分析向前传播过程。
1.得到隐含层的输出y1,y2,y3:
2.获取到第二层的隐含层输出y4,y5,输入的数据也就是第一层隐含层的输出数据y1,y2,y3。
3、通过输出层,得到最后的预测值y。
第二步、反向传播更新权重:根据样本的真实类标,计算模型预测的结果与真实类标的误差。然后将该误差反向传播到各个隐含层。计算出各层的误差,再根据各层的误差,更新权重。
1.计算输出层的误差:其中z为该样本的类标
2计算第二层隐含层的误差
3.计算第一次隐含层的误差:
4、更新权重:新的权值=原权值+学习速率×该节点的误差×激励函数的导函数的值(f(e)的倒数)×与该节点相连的输入值
4.1更新输入层与第一层隐含层之间的权值:
4.2更新第一层隐含层与第二层隐含层之间的权值
4.3更新第二层隐含层与输出层之间的权值
以上就是反向传播的过程。误差从输出层反向的传到输入层,然后再从输入层向前更新权值。
BP神经网络的设计与实现
(一) BP神经网络的设计
1.设计网络的结构:
本次实验采用java语言实现。设计了包含一个隐含层的神经网络,即一个2层的神经网络。
每层都含有一个一维X特征矩阵即为输入数据,一个二维W权值矩阵,一个一维的误差矩阵error,同时该神经网络中还包含了一个一维的目标矩阵target,记录样本的真实类标。
X特征矩阵:第一层隐含层的X矩阵的长度为输入层输入数据的特征个数+1,隐含层的X矩阵的长度则是上一层的节点的个数+1,X[0]=1。
W权值矩阵:第一维的长度设计为节点(即神经元)的个数,第二维的长度设计为上一层节点的个数+1;W[0][0]为该节点的偏置量
error误差矩阵:数组长度设计为该层的节点个数。
目标矩阵target:输出层的节点个数与其一致。
激活函数:采用sigmoid函数:1/1+e-x
2.神经网络的计算过程
按照以上的设计,向前传播得到下一层的输出结果,如图所示:
求误差过程,如图所示:
反向传播过程,调整权值,如图所示:
(二) BP神经网络的实现
一、向前传播得到预测数据:
1.初始化权值
2.训练数据集:
2.1、导入训练数据集和目标值;
2.2、向前传播得到输出值;
2.2.1、获取隐含层的输出
2.2.2、获取输出层的输出
二、反向传播更新权重
1、获取输出层的误差;
2、获取隐含层的误差;
3、更新隐含层的权值;
4、更新输出层的权值;
三.测试神经网络
3.3 向前传播得到预测值;
代码如下:
1 public class Bp {
2
3 private double[] hide1_x;//// 输入层即第一层隐含层的输入;hide1_x[数据的特征数目+1], hide1_x[0]为1
4 private double[][] hide1_w;// 隐含层权值,hide1_w[本层的节点的数目][数据的特征数目+1];hide_w[0][0]为偏置量
5 private double[] hide1_errors;// 隐含层的误差,hide1_errors[节点个数]
6
7 private double[] out_x;// 输出层的输入值即第二次层隐含层的输出 out_x[上一层的节点数目+1], out_x[0]为1
8 private double[][] out_w;// 输出层的权值 hide1_w[节点的数目][上一层的节点数目+1]//
9 // out_w[0][0]为偏置量
10 private double[] out_errors;// 输出层的误差 hide1_errors[节点个数]
11
12 private double[] target;// 目标值,target[输出层的节点个数]
13
14 private double rate;// 学习速率
15
16 public Bp(int input_node, int hide1_node, int out_node, double rate) {
17 super();
18
19 // 输入层即第一层隐含层的输入
20 hide1_x = new double[input_node + 1];
21
22 // 第一层隐含层
23 hide1_w = new double[hide1_node][input_node + 1];
24 hide1_errors = new double[hide1_node];
25
26 // 输出层
27 out_x = new double[hide1_node + 1];
28 out_w = new double[out_node][hide1_node + 1];
29 out_errors = new double[out_node];
30
31 target = new double[out_node];
32
33 // 学习速率
34 this.rate = rate;
35 init_weight();// 1.初始化网络的权值
36 }
37
38 /**
39 * 初始化权值
40 */
41 public void init_weight() {
42
43 set_weight(hide1_w);
44 set_weight(out_w);
45 }
46
47 /**
48 * 初始化权值
49 *
50 * @param w
51 */
52 private void set_weight(double[][] w) {
53 for (int i = 0, len = w.length; i != len; i++)
54 for (int j = 0, len2 = w[i].length; j != len2; j++) {
55 w[i][j] = 0;
56 }
57 }
58
59 /**
60 * 获取原始数据
61 *
62 * @param Data
63 * 原始数据矩阵
64 */
65 private void setHide1_x(double[] Data) {
66 if (Data.length != hide1_x.length - 1) {
67 throw new IllegalArgumentException("数据大小与输出层节点不匹配");
68 }
69 System.arraycopy(Data, 0, hide1_x, 1, Data.length);
70 hide1_x[0] = 1.0;
71 }
72
73 /**
74 * @param target
75 * the target to set
76 */
77 private void setTarget(double[] target) {
78 this.target = target;
79 }
80
81 /**
82 * 2.训练数据集
83 *
84 * @param TrainData
85 * 训练数据
86 * @param target
87 * 目标
88 */
89 public void train(double[] TrainData, double[] target) {
90 // 2.1导入训练数据集和目标值
91 setHide1_x(TrainData);
92 setTarget(target);
93
94 // 2.2:向前传播得到输出值;
95 double[] output = new double[out_w.length + 1];
96 forword(hide1_x, output);
97
98 // 2.3、方向传播:
99 backpropagation(output);
100
101 }
102
103 /**
104 * 反向传播过程
105 *
106 * @param output
107 * 预测结果
108 */
109 public void backpropagation(double[] output) {
110
111 // 2.3.1、获取输出层的误差;
112 get_out_error(output, target, out_errors);
113 // 2.3.2、获取隐含层的误差;
114 get_hide_error(out_errors, out_w, out_x, hide1_errors);
115 //// 2.3.3、更新隐含层的权值;
116 update_weight(hide1_errors, hide1_w, hide1_x);
117 // * 2.3.4、更新输出层的权值;
118 update_weight(out_errors, out_w, out_x);
119 }
120
121 /**
122 * 预测
123 *
124 * @param data
125 * 预测数据
126 * @param output
127 * 输出值
128 */
129 public void predict(double[] data, double[] output) {
130
131 double[] out_y = new double[out_w.length + 1];
132 setHide1_x(data);
133 forword(hide1_x, out_y);
134 System.arraycopy(out_y, 1, output, 0, output.length);
135
136 }
137
138
139 public void update_weight(double[] err, double[][] w, double[] x) {
140
141 double newweight = 0.0;
142 for (int i = 0; i < w.length; i++) {
143 for (int j = 0; j < w[i].length; j++) {
144 newweight = rate * err[i] * x[j];
145 w[i][j] = w[i][j] + newweight;
146 }
147
148 }
149 }
150
151 /**
152 * 获取输出层的误差
153 *
154 * @param output
155 * 预测输出值
156 * @param target
157 * 目标值
158 * @param out_error
159 * 输出层的误差
160 */
161 public void get_out_error(double[] output, double[] target, double[] out_error) {
162 for (int i = 0; i < target.length; i++) {
163 out_error[i] = (target[i] - output[i + 1]) * output[i + 1] * (1d - output[i + 1]);
164 }
165
166 }
167
168 /**
169 * 获取隐含层的误差
170 *
171 * @param NeLaErr
172 * 下一层的误差
173 * @param Nextw
174 * 下一层的权值
175 * @param output 下一层的输入
176 * @param error
177 * 本层误差数组
178 */
179 public void get_hide_error(double[] NeLaErr, double[][] Nextw, double[] output, double[] error) {
180
181 for (int k = 0; k < error.length; k++) {
182 double sum = 0;
183 for (int j = 0; j < Nextw.length; j++) {
184 sum += Nextw[j][k + 1] * NeLaErr[j];
185 }
186 error[k] = sum * output[k + 1] * (1d - output[k + 1]);
187 }
188 }
189
190 /**
191 * 向前传播
192 *
193 * @param x
194 * 输入值
195 * @param output
196 * 输出值
197 */
198 public void forword(double[] x, double[] output) {
199
200 // 2.2.1、获取隐含层的输出
201 get_net_out(x, hide1_w, out_x);
202 // 2.2.2、获取输出层的输出
203 get_net_out(out_x, out_w, output);
204
205 }
206
207 /**
208 * 获取单个节点的输出
209 *
210 * @param x
211 * 输入矩阵
212 * @param w
213 * 权值
214 * @return 输出值
215 */
216 private double get_node_put(double[] x, double[] w) {
217 double z = 0d;
218
219 for (int i = 0; i < x.length; i++) {
220 z += x[i] * w[i];
221 }
222 // 2.激励函数
223 return 1d / (1d + Math.exp(-z));
224 }
225
226 /**
227 * 获取网络层的输出
228 *
229 * @param x
230 * 输入矩阵
231 * @param w
232 * 权值矩阵
233 * @param net_out
234 * 接收网络层的输出数组
235 */
236 private void get_net_out(double[] x, double[][] w, double[] net_out) {
237
238 net_out[0] = 1d;
239 for (int i = 0; i < w.length; i++) {
240 net_out[i + 1] = get_node_put(x, w[i]);
241 }
242
243 }
244
245 }
(二) BP神经网络的测试
用上面实现的BP神经网络来训练模型,自动判断它是正数还是复数,奇数还是偶数.
1 public class Test {
2
3 /**
4 * @param args
5 * @throws IOException
6 */
7 public static void main(String[] args) throws IOException {
8
9
10 Bp bp = new Bp(32, 15, 4, 0.05);
11
12 Random random = new Random();
13
14 List<Integer> list = new ArrayList<Integer>();
15 for (int i = 0; i != 6000; i++) {
16 int value = random.nextInt();
17 list.add(value);
18 }
19
20 for (int i = 0; i !=25; i++) {
21 for (int value : list) {
22 double[] real = new double[4];
23 if (value >= 0)
24 if ((value & 1) == 1)
25 real[0] = 1;
26 else
27 real[1] = 1;
28 else if ((value & 1) == 1)
29 real[2] = 1;
30 else
31 real[3] = 1;
32
33 double[] binary = new double[32];
34 int index = 31;
35 do {
36 binary[index--] = (value & 1);
37 value >>>= 1;
38 } while (value != 0);
39
40 bp.train(binary, real);
41
42
43
44 }
45 }
46
47
48
49
50 System.out.println("训练完毕,下面请输入一个任意数字,神经网络将自动判断它是正数还是复数,奇数还是偶数。");
51
52 while (true) {
53
54 byte[] input = new byte[10];
55 System.in.read(input);
56 Integer value = Integer.parseInt(new String(input).trim());
57 int rawVal = value;
58 double[] binary = new double[32];
59 int index = 31;
60 do {
61 binary[index--] = (value & 1);
62 value >>>= 1;
63 } while (value != 0);
64
65 double[] result =new double[4];
66 bp.predict(binary,result);
67
68
69 double max = -Integer.MIN_VALUE;
70 int idx = -1;
71
72 for (int i = 0; i != result.length; i++) {
73 if (result[i] > max) {
74 max = result[i];
75 idx = i;
76 }
77 }
78
79 switch (idx) {
80 case 0:
81 System.out.format("%d是一个正奇数\n", rawVal);
82 break;
83 case 1:
84 System.out.format("%d是一个正偶数\n", rawVal);
85 break;
86 case 2:
87 System.out.format("%d是一个负奇数\n", rawVal);
88 break;
89 case 3:
90 System.out.format("%d是一个负偶数\n", rawVal);
91 break;
92 }
93 }
94 }
95 }
在BP神经网络中, 学习速率,训练集,以及训练次数,都会影响到最终模型的泛化能力。因此,在设计模型时,节点的个数,学习速率的大小,以及训练次数都是需要考虑的。
BP神经网络—java实现的更多相关文章
- BP神经网络—java实现(转载)
神经网络的结构 神经网络的网络结构由输入层,隐含层,输出层组成.隐含层的个数+输出层的个数=神经网络的层数,也就是说神经网络的层数不包括输入层.下面是一个三层的神经网络,包含了两层隐含层,一个输出层. ...
- 用java写bp神经网络(一)
根据前篇博文<神经网络之后向传播算法>,现在用java实现一个bp神经网络.矩阵运算采用jblas库,然后逐渐增加功能,支持并行计算,然后支持输入向量调整,最后支持L-BFGS学习算法. ...
- BP神经网络的直观推导与Java实现
人工神经网络模拟人体对于外界刺激的反应.某种刺激经过人体多层神经细胞传递后,可以触发人脑中特定的区域做出反应.人体神经网络的作用就是把某种刺激与大脑中的特定区域关联起来了,这样我们对于不同的刺激就可以 ...
- JAVA实现BP神经网络算法
工作中需要预测一个过程的时间,就想到了使用BP神经网络来进行预测. 简介 BP神经网络(Back Propagation Neural Network)是一种基于BP算法的人工神经网络,其使用BP算法 ...
- 数据挖掘系列(9)——BP神经网络算法与实践
神经网络曾经很火,有过一段低迷期,现在因为深度学习的原因继续火起来了.神经网络有很多种:前向传输网络.反向传输网络.递归神经网络.卷积神经网络等.本文介绍基本的反向传输神经网络(Backpropaga ...
- BP神经网络的数学原理及其算法实现
什么是BP网络 BP网络的数学原理 BP网络算法实现 转载请声明出处http://blog.csdn.net/zhongkejingwang/article/details/44514073 上一篇 ...
- BP神经网络的手写数字识别
BP神经网络的手写数字识别 ANN 人工神经网络算法在实践中往往给人难以琢磨的印象,有句老话叫“出来混总是要还的”,大概是由于具有很强的非线性模拟和处理能力,因此作为代价上帝让它“黑盒”化了.作为一种 ...
- 【学习笔记】BP神经网络
转自 huaweizte123的CSDN博客 链接 https://blog.csdn.net/huaweizte123/article/details/78803045 第一步.向前传播得到预测数 ...
- BP神经网络原理及python实现
[废话外传]:终于要讲神经网络了,这个让我踏进机器学习大门,让我读研,改变我人生命运的四个字!话说那么一天,我在乱点百度,看到了这样的内容: 看到这么高大上,这么牛逼的定义,怎么能不让我这个技术宅男心 ...
随机推荐
- C++队列和链表
1.什么是队列[queue] 队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表. 关于队列 ...
- iOS-图形绘制(全)
画阴影: CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSetFillColorWithColor(contex ...
- (四)Asp.net web api中的坑-【api的返回值】
void无返回值 IHttpActionResult HttpResponseMessage 自定义类型 我这里并不想赘述这些返回类型, 可以参考博文http://blog.csdn.net/leon ...
- Andrew Ng机器学习课程17(1)
Andrew Ng机器学习课程17(1) 声明:引用请注明出处http://blog.csdn.net/lg1259156776/ 说明:主要介绍了强化学习与监督学习的设定上的区别,以及强化学习的框架 ...
- Spring 多对对实体
package com.wangshenghua.entity; import java.io.Serializable; import java.util.Set; import javax.per ...
- pod install安装第三方库异常
使用pod install安装第三方插件时,可能会出现如下异常: Installing SDWebImage (3.7.3) [!] Error installing SDWebImage[!] /u ...
- 综合练习1,划分vlan,单臂路由,DHCP服务及其限制网段、租期,设置根桥,OSPF路由通告综合练习
实验要求: 1.在LSW1上分别给vlan10和vlan20做DHCP网段分别为192.168.10.0/24.192.168.20.0/24禁用192.168.10.200-253,192.168. ...
- 重新渲染layui的radio
修改后添加这一段 layui.use('form', function() { var form = layui.form; form.render(); }); 也可以用官方的方法:https:// ...
- @ResponseBody使用
@responseBody注解的作用是将controller的方法返回的对象通过适当的转换器转换为指定的格式之后,写入到response对象的body区,通常用来返回JSON数据或者是XML 数据,需 ...
- POJ2449 【第k短路/A*】
题目链接:http://poj.org/problem?id=2449 题目大意: 给出n个点,m条有向边,最后一行给出起点到终点的第k短路.求长度. 题解思路: 这是我第一道第k短路题以及A*算法的 ...