一.阈值逻辑单元
阈值逻辑单元(threshold logic unit ,TLU),它可以输入一组加权系数的量,对它们进行求和,如果这个和达到或者超过了某个阈值,输出一个量。例如,输入为a1, a2, ..., an和权值 w1, w2, ..., wn。接着是求和计算出的 ai x wi ,产生了激发层 t,换一种方法表示:
t = f((a1 x w1)+(a2 x w2)+...+(aI x wI)+...+ (an x wn)+b)
我理解的阈值逻辑单元就是用于解决多维线性加权求和问题的工具,那么遇到复杂问题该如何做呢?
二.人工神经网络
人工神经网络(Artificial Neural Networks,简写为ANNs)也简称为神经网络(NNs)或称作连接模型(Connection Model),它是一种模仿动物神经网络行为特征,进行分布式并行信息处理的算法数学模型。这种网络依靠系统的复杂程度,通过调整内部大量节点之间相互连接的关系,从而达到处理信息的目的。
通过将多个阈值逻辑单元组合,形成网络,用来模拟非线性的问题。有研究证明,三层的人工神经网络可以模拟各种函数。
三.BP神经网络
BP(Back Propagation)神经网络是一种按误差反向传播算法训练的多层前馈网络,是目前应用最广泛的神经网络模型之一。BP网络能学习和存贮大量的输入-输出模式映射关系,而无需事前揭示描述这种映射关系的数学方程。它的学习规则是使用梯度下降法,通过反向传播来不断调整网络的权值和阈值,使网络的误差平方和最小。
这里利用了偏导数的知识去推导计算公式,具体我没有列出,我自己在理解的时候是读了《人工智能》(机械工业出版社),感兴趣的朋友可以自己看一下。
BP神经网络调整权值的过程更像是一种函数图像逼近的过程,首先猜测一个函数,然后读入一个数据点,根据数据点和函数图像之间的差距调整函数,使得函数图像更符合数据。不断迭代,使得整个数据样本都较为符合我们估计得函数。
四.步骤:
1.对权系数置初值
2.输入一组样本及它的希望输出
3.计算实际输出值
4.计算误差值
5.反向传播误差值并调整权值
6.不断训练(重复步骤2~5)
7.利用完成后的神经网络进行预测
五.Java代码:
import java.io.File;
import java.io.RandomAccessFile;
import java.util.Random;
public class FaceRecognition {
private int picSize = 19 * 19;// 图像大小
private int hiddenSize = 12;// 隐藏层节点个数
private byte[] imageinfor = new byte[374];// 存放图像信息
private double[] input = new double[picSize + 1];// 归一化后的图像信息
private double[][] inputWeight = new double[hiddenSize][picSize + 1];// 输入层参数
private double[] alpha1 = new double[hiddenSize];// 隐藏层调整的梯度
private double[] hiddenWeight = new double[hiddenSize + 1];// 隐藏层参数
private double[] hiddenOutput = new double[hiddenSize + 1];// 隐藏层输出
private double alpha2;// 输出层调整的梯度
private double output;// 输出层
private double ci = 0.3;// 学习率
private double opt;// 期望输出
Random random = new Random();
private double [] pro;
public FaceRecognition() {
}
// 初始化
public void init() {
for (int i = 0; i < hiddenSize; i++) {
for (int j = 0; j < picSize + 1; j++)
inputWeight[i][j] = random.nextDouble() * 2 - 1;
// inputWeight[i][j] =0;
}
for (int i = 0; i < hiddenSize + 1; i++) {
hiddenWeight[i] = random.nextDouble() * 2 - 1;
// hiddenWeight[i]=0;
}
}
// sigmoid
private double Sigmoid(double x) {
return 1.0d / (1.0d + Math.exp(-x));
}
// 图像文件读入
public void PGMReader(String filename) {
File file = new File(filename);
try {
RandomAccessFile in = new RandomAccessFile(file, "r");
in.read(imageinfor);
in.close();
} catch (Exception e) {
e.printStackTrace();
}
for (int i = 0; i < picSize; i++) {
int temp = (int) imageinfor[i + 13];
input[i] = (double) (temp + 128) / 255;
}
input[picSize] = 1.0;
}
public void PGMReader(File file) {
try {
RandomAccessFile in = new RandomAccessFile(file, "r");
in.read(imageinfor);
in.close();
} catch (Exception e) {
e.printStackTrace();
}
for (int i = 0; i < picSize; i++) {
int temp = (int) imageinfor[i + 13];
input[i] = (double) (temp + 128) / 255;
}
input[picSize] = 1.0;
}
public void setOpt(double opt) {
this.opt = opt;
}
private void forward() {
for (int i = 0; i < hiddenSize; i++) {
double temp = 0;
for (int j = 0; j < picSize + 1; j++) {
temp += input[j] * inputWeight[i][j];
}
hiddenOutput[i] = Sigmoid(temp);
}
hiddenOutput[hiddenSize] = 1.0;
double temp = 0;
for (int i = 0; i < hiddenSize + 1; i++) {
temp += hiddenOutput[i] * hiddenWeight[i];
}
output = Sigmoid(temp);
}
public void BP() {
// 计算各层的梯度
alpha2 = (opt - output) * output * (1 - output);
for (int i = 0; i < hiddenSize; i++) {
alpha1[i] = hiddenOutput[i] * (1 - hiddenOutput[i]) * alpha2 * hiddenWeight[i];
}
// 反向传播
for (int i = 0; i < hiddenSize; i++) {
hiddenWeight[i] += ((hiddenOutput[i] * alpha2 * ci) );
for (int j = 0; j < picSize + 1; j++) {
inputWeight[i][j] +=((input[j] * alpha1[i] * ci));
}
}
hiddenWeight[hiddenSize]+=(hiddenOutput[hiddenSize] * alpha2 * ci);
}
public void train() {
String non_facePath = "D://人工智能//face.train//train//non-face";
File non_facFile = new File(non_facePath);
File[] non_faceList = non_facFile.listFiles();
String facePath = "D://人工智能//face.train//train/face";
File faceFile = new File(facePath);
File[] faceList = faceFile.listFiles();
init();
pro =new double [151];
for(int i =0;i<151;i++){
int right = 0;
int facenumber =0;
int nonfacenumber =0;
for (int j = 0; j < 4000; j++) {
int temp = random.nextInt();
if(temp%2 ==0)
{ // 正例训练
this.setOpt(1.0);
this.PGMReader(faceList[facenumber]);
this.forward();
this.BP();
facenumber++;
}
else{ // 反例训练
this.setOpt(0.0);
this.PGMReader(non_faceList[nonfacenumber]);
this.forward();
this.BP();
nonfacenumber++;
}
}
for (int j = 2000; j <2400; j++) {
{ // 正例测试
this.PGMReader(faceList[j]);
this.forward();
if (output > 0.5)
right++;
}
{ // 反例测试
this.PGMReader(non_faceList[j]);
this.forward();
if (output < 0.5)
right++;
}
}
pro[i] = (double) right / 800;
if(i%10==0)
{
System.out.println("第"+i+"次迭代估算正确率为:" + pro[i]);
}
if(pro[i]>=0.95){
System.out.println("第"+i+"次迭代估算正确率为:" + pro[i]);
break;
}
}
}
}
这里我采用的数据的格式是PGM,19*19大小的,训练集一共有4800张,一半正例一半反例。
具体的实现,我感觉代码写的比较清楚,我就不赘述了。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。