前面说到了一个简单的可学习的分类数学模型-感知器。在这一节里就来具体说一下感知器是如何学习的以及它的能力有多大!首先明确一下条件,假设两类点集合A,B,感知器的参数为ω,b.学习的目的就是求一个满足ω
T*X
a+b≥0,X
a∈A;ω
T*X
b+b<0,X
b∈B;聪明的朋友一眼就会发现他有可能有无数个解,话虽这么说但是求一个满足要求的解也不是那么容易的,在这我们给出一个Frank Rosenblatt提出的感知器学习算法,具体过程如下:
这里假定被学习的样本集合S=(X,y)大小为l.其中y是该样本隶属于那个集合的象征值,例如当属于A是y=1,属于 B时y=-1,说他是个象征值是因为除却其符号有意义外其绝对大小并无意义可以任意取值。上述的学习算法是一个迭代学习的过程,当某一时刻他最终会停止学习并得到我们想要的值。在此我们给出感知器学习的java实现来看看它的威力吧!
public class Perceptron {
/**
* 第一位到倒数第二位为权重ω<br>
* 最后一位是偏置
*/
private final double[] weights;
/**
*
* @param dim
* 感知器分类的空间维数
*/
public Perceptron(int dim) {
this.weights = new double[dim + 1];
init();
}
/**
*
*/
private void init() {
for (int i = 0; i < weights.length; i++) {
weights[i] = 0;
}
}
/**
* 对给定的向量进行分类,大于等于零一类,小于零一类
*
* @param x
* @return
*/
public double classfiy(double[] x) {
double value = weights[weights.length - 1];
for (int i = 0; i < weights.length - 1; i++) {
value += weights[i] * x[i];
}
return value;
}
/**
* 计算第dim个分量的取值
*
* @param x
* @return
*/
public double clalute(double[] x, int dim) {
double value = weights[weights.length - 1];
for (int i = 0; i < weights.length - 1; i++) {
if (i == dim - 1) {
continue;
}
value += weights[i] * x[i];
}
x[dim - 1] = -value / weights[dim - 1];
return x[dim - 1];
}
/**
* 利用给定的样本进行学习,每个样本的最后一个值是它的象征分类值
*
* @param simples
*/
public void train(double[][] simples) {
long k = 0;
double yelta = 0.5;
init();
double r = max(simples);
int tem = 0;
int times = 0;
while (true) {
tem = 0;
++times;
for (int i = 0; i < simples.length; i++) {
if (simples[i][simples[i].length - 1] * classfiy(simples[i]) <= 0) {
update(simples[i], yelta, r);
++k;
++tem;
}
}
System.out.println("the " + times + "'s iterator,errorNum=" + tem);
if (tem == 0) {
break;
}
}
System.out.println("totle errorNum=" + k);
}
/**
* @param ds
*/
private void update(double[] ds, double ylta, double r) {
for (int i = 0; i < weights.length - 1; i++) {
weights[i] += ylta * ds[ds.length - 1] * ds[i];
}
weights[weights.length - 1] += ylta * ds[ds.length - 1] * r;
}
/**
* @param simples
* @return
*/
private double max(double[][] simples) {
double max = 0.0;
double abs = 0;
for (int i = 0; i < simples.length; i++) {
abs = abs(simples[i]);
if (max < abs) {
max = abs;
}
}
return max;
}
/**
* @param ds
* @return
*/
private double abs(double[] ds) {
double abs = 0;
for (int i = 0; i < weights.length - 1; i++) {
abs += (ds[i] * ds[i]);
}
return abs;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "Perceptron [weights=" + Arrays.toString(weights) + "]";
}
}
我们随机产生图(3)所示的绿色与黄色随机点各1000个,一次迭代学习的结果如下,并输出其分类的超平面,图(3)中的红色部分。在这我们可以感性的认识到感知器的算法确实能够正确的分类所给的样本,而且效率还算不错!
the 1's iterator,errorNum=2
the 2's iterator,errorNum=3
the 3's iterator,errorNum=3
the 4's iterator,errorNum=2
the 5's iterator,errorNum=2
the 6's iterator,errorNum=2
the 7's iterator,errorNum=2
the 8's iterator,errorNum=2
the 9's iterator,errorNum=2
the 10's iterator,errorNum=2
the 11's iterator,errorNum=2
the 12's iterator,errorNum=2
the 13's iterator,errorNum=2
the 14's iterator,errorNum=2
the 15's iterator,errorNum=1
the 16's iterator,errorNum=0
totle errorNum=31
Perceptron [weights=[-335.7439017931607, 693.3534881006469, 38317.48519392383]]
|
图(3)