【神经网络入门】用JAVA实现感知器算法

简述

随着互联网的高速发展,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)进行二分类模式识别 :

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 表示需要修正值:

update = μ * (yi - y')
update = (f(x) - y')

m
Σ    Wi += update * Xi
i=1

e += update

当感知器分类结果等于正确分类,update = 0,不调整网络;如果不等于正确分类,则会调整全部的权值(w)与阈值(e)

以上就是我所介绍的感知器最简单的学习流程:

输入数据->求和得到z->通过激活函数等到分类结果->分类结果与正确结果不符则调整网络

下面就让我们来实现这个简单的神经网络吧

Java代码实现

这里我所实现的是通过神经网络学习识别整数的正负
首先定义一个感知器的类

 /**
 * 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);
    }
}

然后写生成训练数据的函数

    /**
     * 生成训练数据
     * @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;
    }

最后是主函数


    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));
    }

大家可以测试一下

局限性

这个感知器神经网络比较简单,是适用于可线性划分的数据,比如一维的话正数和负数,二维的坐标象限分类;对于不可线性划分的数据无法进行正确的分类,如寻找质数等

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值