Java Back Propagation Neural Network(JAVA反向传播神经网络)

EDITOR: KJ021320

BLOG: http://blog.csdn.net/kj021320

TEAM: I.S.T.O

 

好久没写东西了,随便记一下~~如果不记录忘记了真是很浪费啊~

 

下面贴的这个是JAVA写的反向传播神经网络,面向对象,把神经元和连结都抽象成对象。

其实这个已经不是什么新奇的玩意了,对于分类 回归而言 神经网络是一个选择但并不一定是最好的选择。

类似很多进化计算都存在同样的问题,如GA遗传算法。

NN迭代学习过后,每个神经元权重的含义很难被理解,所以才有人提出神经网络的规则抽取,如何对网络的神经元进行裁剪

接下来就是NN 的学习过程中,最具有价值的

 

1. 计算 delta规则 ,一般采用梯度下降法等等(有本书说得不错的《最优化理论与方法》讲了很多牛顿法 最速下降法等等)

2. 激活函数,其实这个最终目的就是让数据2值化,神经网络设计一书上标准的方式,其实你也可以通过这个思想自己搞一个

3. 当然是NN的整个数据结构模型,模拟了大脑神经的信息传递过程。

 

以下代码 main函数是使用DEMO

 

package cn.isto.ai.algorithm.nn;
import java.util.HashMap;
import java.util.Random;
import java.util.Set;
import java.util.Map.Entry;

/**
 * JAVA 反向传输神经网络
 * @author kj021320  , codeby 2008.12.10
 *
 */
public class JavaBackPropagationNeuralNetwork {
    /**
     * 神经元
     */
    public class Neuron {
        HashMap<Integer, Link> target = new HashMap<Integer, Link>();// 连接其他神经元的
        HashMap<Integer, Link> source = new HashMap<Integer, Link>();// 被其他神经元连接的
        double data = 0.0;
        public Link sourceGet(int index) {
            return source.get(index);
        }
        public Link targetGet(int index) {
            return target.get(index);
        }
        public boolean targetContains(Link l) {
            return target.containsValue(l);
        }
        public boolean sourceContains(Link l) {
            return source.containsValue(l);
        }
        public Link sourceLink(int index, Link l) {
            if (l.linker != this) {
                l.setLinker(this);
            }
            return source.put(index, l);
        }
        public Link targetLink(int index, Link l) {
            if (l.owner != this) {
                l.setOwner(this);
            }
            return target.put(index, l);
        }
    }

    /**
     * 神经链
     */
    public class Link {
        Neuron owner;
        public void setOwner(Neuron o) {
            owner = o;
            if (!o.targetContains(this)) {
                o.targetLink(o.target.size(), this);
            }
        }
        public Link() {
            weight = rand(-1, 1);
        }
        public void setLinker(Neuron o) {
            linker = o;
            if (!o.sourceContains(this)) {
                o.sourceLink(o.source.size(), this);
            }
        }
        @Override
        public String toString(){
            return super.toString()+" weight:"+weight;
        }
        Neuron linker;
        double weight;
    }

    Random random = new Random();
    {
        random.setSeed(System.nanoTime());
    }
    Neuron[] inputnode;    //输入层神经元
    Neuron[] hiddennode;    //隐含层神经元
    Neuron[] outputnode;    //输出层神经元
    double learnrate;// 学习速度
    double threshold;// 阀值,误差允许度

    private final int inputCount;
    private final int hiddenCount;
    private final int outputCount;
    /**
     *
     * @param input        输入层的神经元个数
     * @param hidden    隐含层的神经元个数
     * @param output    输出层的神经元的个数
     */
    public JavaBackPropagationNeuralNetwork(int input, int hidden, int output) {
        inputCount = input;
        hiddenCount = hidden;
        outputCount = output;
        build();
    }
    public void reBuildNeuralNetwork(){
        build();
    }
    private void build(){
        inputnode = new Neuron[inputCount+1];
        hiddennode = new Neuron[hiddenCount];
        outputnode = new Neuron[outputCount];
        initNeurons(inputnode);
        initNeurons(hiddennode);
        initNeurons(outputnode);
        makeLink(inputnode, hiddennode);
        makeLink(hiddennode, outputnode);
    }
    /**
     * 思考方法
     * @param inputs    前馈层神经个数相符的浮点数    -1~1之间
     * @return            思考后的结果,个数与后端的神经个数相符,每个浮点为-1~1之间
     */
    public double[] thinking(double[] inputs) {
        /**把数据映射到前馈层的神经元里面*/
        makeNeuron(inputnode, inputs);
        /**通过每个神经链的权重 从隐藏层计算到最终输出层的值*/
        thinking();
        /**把输出层的值映为return的double数组*/
        return makeMatrix();
    }
    public double[][] batchThinking(double[][] inputs){
        double[][] ret = new double[inputs.length][];
        for(int i = 0; i< inputs.length ; i++){
            makeNeuron(inputnode, inputs[i]);
            thinking();
            ret[i]=makeMatrix();
        }
        return ret;
    }
    /**
     * 总体训练
     * @param inputs       
     * @param outputs       
     * @param learnrate        学习精细度
     * @param error            容许误差
     * @param maxlearn        最大学习次数
     * @return 是否完成训练
     */
    public boolean train(double[][] inputs, double[][] outputs, double learnrate,
            double error,int maxlearn) {
        this.learnrate = learnrate;
        this.threshold = error;
        boolean complete = false;
        int count = 0;
        double e =0;
        while (!complete) {
            count++;
            e = 0;
            complete = true;
            for (int size = 0; size < inputs.length; size++) {
                e += learn(inputs[size], outputs[size]);
                if (e > threshold) {
                    complete = false;
                }
            }
            if(count>=maxlearn){
                System.err.println("convergence fail  error:"+e);
                return false;
            }
        }
        System.out.println("convergence success    error:"+e);
        return true;
    }

    /**
     * 单次学习
     *
     * @param input
     * @param output
     * @return 误差
     */
    private double learn(double[] input, double[] output) {
        /**把数据映射到前馈层的神经元里面*/
        makeNeuron(inputnode, input);
        /**通过每个神经链的权重 从隐藏层计算到最终输出层的值*/
        thinking();
        /**误差计算*/
        return evolutionComputing(output);
    }

    private void thinking() {
        transmitComputing(hiddennode);
        transmitComputing(outputnode);
    }

    /**
     * 神经元传输计算
     *
     * @param ns
     */
    private void transmitComputing(Neuron[] ns) {
        for (Neuron ne : ns) {
            double sum = 0.0;
            Set<Entry<Integer, Link>> linkset = ne.source.entrySet();
            for (Entry<Integer, Link> ent : linkset) {
                Link l = ent.getValue();
                Neuron n = l.owner;
                // 这里是重点,计算神经元*神经权重
                sum += n.data * l.weight;
            }
            // 计算完毕后通过 S型激活函数把数据存储在隐藏层的神经节点上
            ne.data = sigmoid(sum);
        }
    }
    /**
     * 最速梯度下降法 来计算 delta规则
     * @param datas
     * @return
     */
    private double evolutionComputing(double[] datas) {
        double[] output_deltaDatas = new double[outputnode.length];
        double totalError = 0.0;
        for (int i = 0; i < outputnode.length; i++) {
            /**
             * Erri = Ti – Oi O is the predicted output T is the correct output
             * Δi = Erri * g’(ini) g’ is the derivative of the activation
             * function g
             */
            output_deltaDatas[i] = (datas[i] - outputnode[i].data)
                    * sigmoidDerivative(datas[i]);
        }

        double[] hidden_deltaDatas = new double[hiddennode.length];
        for (int i = 0; i < hiddennode.length; i++) {
            /**
             * Δj = g’(inj) * Σi(Wj,i * Δi)
             */
            double error = 0.0;
            Set<Entry<Integer, Link>> linkSet = hiddennode[i].target.entrySet();
            for (Entry<Integer, Link> ent : linkSet) {
                error += output_deltaDatas[ent.getKey()]
                        * ent.getValue().weight;
            }
            hidden_deltaDatas[i] = sigmoidDerivative(hiddennode[i].data)
                    * error;
        }
        /**
         * Wj,i = Wj,i + α * Hj * Δi    Hj is the activation of the hidden unit
         */
        for (int i = 0; i < hiddennode.length; i++) {
            Set<Entry<Integer, Link>> linkSet = hiddennode[i].target.entrySet();
            for (Entry<Integer, Link> ent : linkSet) {
                Link hidden2output = ent.getValue();
                hidden2output.weight += output_deltaDatas[ent.getKey()]
                        * hiddennode[ent.getKey()].data * learnrate;
                //System.out.println("hidden2output:"+hidden2output);
            }
        }
        //System.out.println();
        /**
         * Wk,j = Wk,j + α * Ik * Δj Ik is the activation of the input unit
         */
        for (int i = 0; i < inputnode.length; i++) {
            Set<Entry<Integer, Link>> linkSet = inputnode[i].target.entrySet();
            for (Entry<Integer, Link> ent : linkSet) {
                Link input2hidden = ent.getValue();
                input2hidden.weight += hidden_deltaDatas[ent.getKey()]
                        * inputnode[i].data * learnrate;
                //System.out.println("inputnode[i].data:"+inputnode[i].data+"input2hidden:"+input2hidden);
            }
        }
        //System.out.println();
        /**
         * E = 1/2 Σi((Ti – Oi)^2)
         */
        for (int i = 0; i < outputnode.length; i++) {
            double temp = outputnode[i].data - datas[i];
            totalError +=  temp * temp;
        }
        return totalError * 0.5;
    }

    /**
     * 把数据映射到每个神经元里面
     *
     * @param neurons
     * @param datas
     */
    private void makeNeuron(Neuron[] neurons, double[] datas) {
        for (int len = 0; len < neurons.length; len++) {
            if(len >= datas.length){
                neurons[len].data = 1.0;
            }else{
                neurons[len].data = datas[len];
            }
        }
    }

    /**
     * 把output的神经元数据映射为矩阵
     *
     * @return
     */
    private double[] makeMatrix() {
        double[] temp = new double[outputnode.length];
        for (int i = 0; i < outputnode.length; i++) {
            temp[i] = outputnode[i].data;
        }
        return temp;
    }

    private void initNeurons(Neuron[] startns) {
        for (int lenN = 0; lenN < startns.length; lenN++) {
            if (startns[lenN] == null) {
                startns[lenN] = new Neuron();
            }
        }
    }

    /**
     * 这里是互相交叉连接
     *
     * @param startns
     * @param endns
     */
    private void makeLink(Neuron[] startns, Neuron[] endns) {
        for (int lenN = 0; lenN < startns.length; lenN++) {
            for (int len = 0; len < endns.length; len++) {
                Link target = startns[lenN].targetGet(len);
                if (target == null) {
                    target = new Link();
                    startns[lenN].targetLink(len, target);
                }
                target.setLinker(endns[len]);
            }
        }
    }

    /**
     * 这里是S型激活函数.最终目的是把所有数据都2值化
     *
     * @param x
     * @return
     */
    private double sigmoid(double x) {
        return Math.tanh(x);
    }

    /*
     * calculate a random number where: a <= rand < b def rand(a, b): return
     * (b-a)*random.random() + a
     */
    private double rand(double min, double max) {
        return (max - min) * random.nextDouble() + min;
    }

    // derivative of our sigmoid function
    private double sigmoidDerivative(double y) {
        // return (1.0 - sigmoid(y)) * sigmoid(y);
        // return 1.0-y*y;
        return 1.0 - sigmoid(y) * y;
    }

    /**
     * @param args
     * @throws Throwable
     */
    public static void main(String[] args) throws Throwable {
        //创建一个 反向传输神经网络
        JavaBackPropagationNeuralNetwork jbpn = new JavaBackPropagationNeuralNetwork(2, 4, 1);
       
        //训练XOR
        while(!jbpn.train(
                new double[][] { new double[] { -1, -1 },new double[] { 1, 1 }, new double[] { -1, 1 },new double[] { 1, -1 } },//这个为输入值
                new double[][] { new double[] {-1},new double[] {-1},new double[] {1},new double[] {1} },//这个是监督指导结果
                0.3, 0.05,1000)){
            jbpn.reBuildNeuralNetwork();
        }
        //思考
        double[] res = jbpn.thinking(new double[] { -1, -1 });
        for(double s:res){
            System.out.println("thinking:"+s);
        }
        //批量思考
        double[][] ress = jbpn.batchThinking(new double[][] { new double[] { -0.8, -0.9 },new double[] { 0.7, 0.3 }, new double[] { -.6, .85 },new double[] { 1, -1 } });
        for(double[] s:ress){
            for(double d:s){
                System.out.print("batchThinking:"+d+"    ");
            }
            System.out.println();
        }
       
    }

}

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值