您的位置:首页 > 理论基础 > 计算机网络

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

2010-03-28 10:02 591 查看
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();

        }

       

    }

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息