2

一.阈值逻辑单元

 阈值逻辑单元(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张,一半正例一半反例。
具体的实现,我感觉代码写的比较清楚,我就不赘述了。


kr9226
22 声望1 粉丝

Java菜鸟,目前在找工作,未来的方向希望是在web开发