简述
随着互联网的高速发展,a(ai)b(bigdata)c(cloud)已经成为当下的核心发展方向,假如三者深度结合的话,ai是其中最核心的部分。所以如果说在未来社会,每个人都必须要学会编程的话,那么对于程序员来说,人工智能则是他们所必须掌握的技术(科技发展真tm快)。
这篇文章介绍并用java实现了一种最简单的感知器网络,不纠结于公式的推导,旨在给大家提供一下学习神经网络的思路,对神经网络有一个大概的认识。
感知器网络模型分析
首先看一张图
如果稍微对神经网络感兴趣的一定对这张图不陌生,这张图是神经元的结构图
x1~xm表示输入,w1~wm表示突触权值,σ表示求和结点,activation function表示激活函数,之后输出一个结果,具体的流程是
神经元接收到输入,每个输入都会与其相对路径上的权值相乘,到了求和结点进行求和,这里把求和结点的结果设为z :
z = x1 * w1 + x2 * w2 + x3 * w3 + ...... + xm * wm
之后将 z 传入到激活函数(这里我们称激活函数为 f)进行二分类模式识别 :
1
2
3
4
5
|
if f(x) > e,y = 1 else y = - 1 e 为阈值 y 为分类结果 |
这里可以看出,如果 f(x) 的值大于阈值,得到分类 y = 1,反之 y = -1
注:相对于生物神经元受到刺激表示的反应,如果刺激在可接受范围之内,则神经元会抑制刺激(y = -1),如果超过范围则会兴奋(y = 1),而这个范围的分水岭就是阈值(e)
学习
我们发现,如果权值和阈值都固定的话,那么这个神经网络就没有存在的意义了,所以我们引入学习的概念,通过学习,让神经网络去修改权值和阈值,从而可以动态的修正模式识别的正确率,这才是机器学习的本质。
那么如何学习呢?当我们在使用之前我们需要提供给此网络一组样本数据(这里采取的是有教师模式学习),样本数据包括输入数据x和正确的识别结果y'。
当我们输入训练数据x得到模式识别y之后进行判断,如果 y != y' ,则会去调整此网络的权值和阈值,调整请看公式,μ 表示学习率(修正率),update 表示需要修正值:
1
2
3
4
5
6
7
8
|
update = μ * (yi - y') update = (f(x) - y') m σ wi += update * xi i= 1 e += update |
当感知器分类结果等于正确分类,update = 0,不调整网络;如果不等于正确分类,则会调整全部的权值(w)与阈值(e)
以上就是我所介绍的感知器最简单的学习流程:
输入数据->求和得到z->通过激活函数等到分类结果->分类结果与正确结果不符则调整网络
下面就让我们来实现这个简单的神经网络吧
java代码实现
这里我所实现的是通过神经网络学习识别整数的正负
首先定义一个感知器的类
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
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
|
/** * created by cimzzz on 12/2/17. * */ public class perceptron { /** * 学习率 */ private final float learnrate; /** * 学习次数 */ private final int studycount; /** * 阈值 */ private float e; /** * 权值 * 因为判断整数正负只需要一条输入,所以这里只有一个权值,多条输入可以设置为数组 */ private float w; /** * 每次学习的正确率 */ private float [] correctrate; // /** * 构造函数初始化学习率,学习次数,权值、阈值初始化为0 * @param learnrate 学习率(取值范围 0 < learnrate < 1) * @param studycount 学习次数 */ public perceptron( float learnrate, int studycount) { this .learnrate = learnrate; this .studycount = studycount; this .e = 0 ; this .w = 0 ; this .correctrate = new float [studycount]; } /** * 学习函数,samples 是一个包含输入数据和分类结果的二维数组, * samples[][0] 表示输入数据 * samples[][1] 表示正确的分类结果 * @param samples 训练数据 */ public void fit( int [][] samples) { int samplelength = samples.length; for ( int i = 0 ; i < studycount ; i ++) { int errorcount = 0 ; for ( int [] sample : samples) { float update = learnrate * (sample[ 1 ]-predict(sample[ 0 ])); //更新权值、阈值 w += update * sample[ 0 ]; e += update; //计算错误次数 if (update != 0 ) errorcount++; } //计算此次学习的正确率 correctrate[i] = 1 - errorcount * 1 .0f / samplelength; } } /** * 求和函数,模拟求和结点操作 输入数据 * 权值 * @param num 输入数据 * @return 求和结果 z */ private float sum( int num) { return num * w + e; } /** * 激活函数,通过求和结果 z 和阈值 e 进行判断 * @param num 输入数据 * @return 分类结果 */ public int predict( int num) { return sum(num) >= 0 ? 1 : - 1 ; } /** * 打印正确率 */ public void printcorrectrate() { for ( int i = 0 ; i < studycount ; i ++) system.out.printf( "第%d次学习的正确率 -> %.2f%%\n" ,i + 1 ,correctrate[i] * 100 ); } } |
然后写生成训练数据的函数
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
|
/** * 生成训练数据 * @return 训练数据 */ private static int [][] genstudydata() { //这里我们取 -100 ~ 100 之间的整数,大于0的设为模式 y = 1,反之为 y = -1 int [][] data = new int [ 201 ][ 2 ]; for ( int i = - 100 , j = 0 ; i <= 100 ; i ++ , j ++) { data[j][ 0 ] = i; data[j][ 1 ] = i >= 0 ? 1 : - 1 ; } return data; } /** * 生成训练数据 * @return 训练数据 */ private static int [][] genstudydata2() { //这里我们取 1~250 之间的整数,大于125的设为模式 y = 1,反之为 y = -1 int [][] data = new int [ 250 ][ 2 ]; for ( int i = 1 , j = 0 ; i <= 250 ; i ++ , j ++) { data[j][ 0 ] = i; data[j][ 1 ] = i >= 125 ? 1 : - 1 ; } return data; } |
最后是主函数
1
2
3
4
5
6
7
8
9
10
|
public static void main(string[] args) { //这里的学习率和训练次数可以根据情况人为调整 perceptron perceptron = new perceptron( 0 .4f, 500 ); perceptron.fit(genstudydata()); perceptron.printcorrectrate(); system.out.println(perceptron.predict(- 1 )); system.out.println(perceptron.predict( 126 )); } |
大家可以测试一下
局限性
这个感知器神经网络比较简单,是适用于可线性划分的数据,比如一维的话正数和负数,二维的坐标象限分类;对于不可线性划分的数据无法进行正确的分类,如寻找质数等
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。
原文链接:http://blog.csdn.net/wang19950207/article/details/78693107