• 【学习笔记】BP神经网络


    转自 的CSDN博客  链接 https://blog.csdn.net/huaweizte123/article/details/78803045

    第一步、向前传播得到预测数据:向前传播的过程,即数据从输入层输入,经过隐含层,输出层的计算得到预测值,预测值为输出层的输出结果。网络层的输出即,该层中所有节点(神经元)的输出值的集合。我们以图一的神经网络结构为例,分析向前传播过程。

    1.得到隐含层的输出y1,y2,y3

    2.获取到第二层的隐含层输出y4,y5,输入的数据也就是第一层隐含层的输出数据y1,y2,y3

     

    3、通过输出层,得到最后的预测值y。

    第二步、反向传播更新权重:根据样本的真实类标,计算模型预测的结果与真实类标的误差。然后将该误差反向传播到各个隐含层。计算出各层的误差,再根据各层的误差,更新权重。

    1.计算输出层的误差:其中z为该样本的类标

    2计算第二层隐含层的误差

    3.计算第一次隐含层的误差:

    4、更新权重:新的权值=原权值+学习速率×该节点的误差×激励函数的导函数的值(f(e)的倒数)×与该节点相连的输入值

     4.1更新输入层与第一层隐含层之间的权值:

     

    4.2更新第一层隐含层与第二层隐含层之间的权值

    4.3更新第二层隐含层与输出层之间的权值

    以上就是反向传播的过程。误差从输出层反向的传到输入层,然后再从输入层向前更新权值。

    BP神经网络的设计与实现

      (一) BP神经网络的设计

    1.设计网络的结构:

    本次实验采用java语言实现。设计了包含一个隐含层的神经网络,即一个2层的神经网络。

    每层都含有一个一维X特征矩阵即为输入数据,一个二维W权值矩阵,一个一维的误差矩阵error,同时该神经网络中还包含了一个一维的目标矩阵target,记录样本的真实类标。

    X特征矩阵:第一层隐含层的X矩阵的长度为输入层输入数据的特征个数+1,隐含层的X矩阵的长度则是上一层的节点的个数+1,X[0]=1。

    W权值矩阵:第一维的长度设计为节点(即神经元)的个数,第二维的长度设计为上一层节点的个数+1;W[0][0]为该节点的偏置量

    error误差矩阵:数组长度设计为该层的节点个数。 

    目标矩阵target:输出层的节点个数与其一致。

    激活函数:采用sigmoid函数:1/1+e-x

    2.神经网络的计算过程

    按照以上的设计,向前传播得到下一层的输出结果,如图所示: 

    求误差过程,如图所示:

    反向传播过程,调整权值,如图所示:

    (二) BP神经网络的实现

    一、向前传播得到预测数据:

    1.初始化权值
    2.训练数据集:
      2.1、导入训练数据集和目标值;
      2.2、向前传播得到输出值;
        2.2.1、获取隐含层的输出
        2.2.2、获取输出层的输出
    二、反向传播更新权重
     1、获取输出层的误差;
     2、获取隐含层的误差;
     3、更新隐含层的权值;
     4、更新输出层的权值;
    三.测试神经网络
      3.3 向前传播得到预测值;

    代码如下:

    1 public class Bp {
      2 
      3     private double[] hide1_x;//// 输入层即第一层隐含层的输入;hide1_x[数据的特征数目+1], hide1_x[0]为1
      4     private double[][] hide1_w;// 隐含层权值,hide1_w[本层的节点的数目][数据的特征数目+1];hide_w[0][0]为偏置量
      5     private double[] hide1_errors;// 隐含层的误差,hide1_errors[节点个数]
      6 
      7     private double[] out_x;// 输出层的输入值即第二次层隐含层的输出 out_x[上一层的节点数目+1], out_x[0]为1
      8     private double[][] out_w;// 输出层的权值 hide1_w[节点的数目][上一层的节点数目+1]//
      9                                 // out_w[0][0]为偏置量
     10     private double[] out_errors;// 输出层的误差 hide1_errors[节点个数]
     11 
     12     private double[] target;// 目标值,target[输出层的节点个数]
     13 
     14     private double rate;// 学习速率
     15 
     16     public Bp(int input_node, int hide1_node, int out_node, double rate) {
     17         super();
     18 
     19         // 输入层即第一层隐含层的输入
     20         hide1_x = new double[input_node + 1];
     21 
     22         // 第一层隐含层
     23         hide1_w = new double[hide1_node][input_node + 1];
     24         hide1_errors = new double[hide1_node];
     25 
     26         // 输出层
     27         out_x = new double[hide1_node + 1];
     28         out_w = new double[out_node][hide1_node + 1];
     29         out_errors = new double[out_node];
     30 
     31         target = new double[out_node];
     32 
     33         // 学习速率
     34         this.rate = rate;
     35         init_weight();// 1.初始化网络的权值
     36     }
     37 
     38     /**
     39      * 初始化权值
     40      */
     41     public void init_weight() {
     42 
     43         set_weight(hide1_w);
     44         set_weight(out_w);
     45     }
     46 
     47     /**
     48      * 初始化权值
     49      * 
     50      * @param w
     51      */
     52     private void set_weight(double[][] w) {
     53         for (int i = 0, len = w.length; i != len; i++)
     54             for (int j = 0, len2 = w[i].length; j != len2; j++) {
     55                 w[i][j] = 0;
     56             }
     57     }
     58 
     59     /**
     60      * 获取原始数据
     61      * 
     62      * @param Data
     63      *            原始数据矩阵
     64      */
     65     private void setHide1_x(double[] Data) {
     66         if (Data.length != hide1_x.length - 1) {
     67             throw new IllegalArgumentException("数据大小与输出层节点不匹配");
     68         }
     69         System.arraycopy(Data, 0, hide1_x, 1, Data.length);
     70         hide1_x[0] = 1.0;
     71     }
     72 
     73     /**
     74      * @param target
     75      *            the target to set
     76      */
     77     private void setTarget(double[] target) {
     78         this.target = target;
     79     }
     80 
     81     /**
     82      * 2.训练数据集
     83      * 
     84      * @param TrainData
     85      *            训练数据
     86      * @param target
     87      *            目标
     88      */
     89     public void train(double[] TrainData, double[] target) {
     90         // 2.1导入训练数据集和目标值
     91         setHide1_x(TrainData);
     92         setTarget(target);
     93 
     94         // 2.2:向前传播得到输出值;
     95         double[] output = new double[out_w.length + 1];
     96         forword(hide1_x, output);
     97 
     98         // 2.3、方向传播:
     99         backpropagation(output);
    100 
    101     }
    102 
    103     /**
    104      * 反向传播过程
    105      * 
    106      * @param output
    107      *            预测结果
    108      */
    109     public void backpropagation(double[] output) {
    110 
    111         // 2.3.1、获取输出层的误差;
    112         get_out_error(output, target, out_errors);
    113         // 2.3.2、获取隐含层的误差;
    114         get_hide_error(out_errors, out_w, out_x, hide1_errors);
    115         //// 2.3.3、更新隐含层的权值;
    116         update_weight(hide1_errors, hide1_w, hide1_x);
    117         // * 2.3.4、更新输出层的权值;
    118         update_weight(out_errors, out_w, out_x);
    119     }
    120 
    121     /**
    122      * 预测
    123      * 
    124      * @param data
    125      *            预测数据
    126      * @param output
    127      *            输出值
    128      */
    129     public void predict(double[] data, double[] output) {
    130 
    131         double[] out_y = new double[out_w.length + 1];
    132         setHide1_x(data);
    133         forword(hide1_x, out_y);
    134         System.arraycopy(out_y, 1, output, 0, output.length);
    135 
    136     }
    137 
    138     
    139     public void update_weight(double[] err, double[][] w, double[] x) {
    140 
    141         double newweight = 0.0;
    142         for (int i = 0; i < w.length; i++) {
    143             for (int j = 0; j < w[i].length; j++) {
    144                 newweight = rate * err[i] * x[j];
    145                 w[i][j] = w[i][j] + newweight;
    146             }
    147 
    148         }
    149     }
    150 
    151     /**
    152      * 获取输出层的误差
    153      * 
    154      * @param output
    155      *            预测输出值
    156      * @param target
    157      *            目标值
    158      * @param out_error
    159      *            输出层的误差
    160      */
    161     public void get_out_error(double[] output, double[] target, double[] out_error) {
    162         for (int i = 0; i < target.length; i++) {
    163             out_error[i] = (target[i] - output[i + 1]) * output[i + 1] * (1d - output[i + 1]);
    164         }
    165 
    166     }
    167 
    168     /**
    169      * 获取隐含层的误差
    170      * 
    171      * @param NeLaErr
    172      *            下一层的误差
    173      * @param Nextw
    174      *            下一层的权值
    175      * @param output 下一层的输入
    176      * @param error
    177      *            本层误差数组
    178      */
    179     public void get_hide_error(double[] NeLaErr, double[][] Nextw, double[] output, double[] error) {
    180 
    181         for (int k = 0; k < error.length; k++) {
    182             double sum = 0;
    183             for (int j = 0; j < Nextw.length; j++) {
    184                 sum += Nextw[j][k + 1] * NeLaErr[j];
    185             }
    186             error[k] = sum * output[k + 1] * (1d - output[k + 1]);
    187         }
    188     }
    189 
    190     /**
    191      * 向前传播
    192      * 
    193      * @param x
    194      *            输入值
    195      * @param output
    196      *            输出值
    197      */
    198     public void forword(double[] x, double[] output) {
    199 
    200         // 2.2.1、获取隐含层的输出
    201         get_net_out(x, hide1_w, out_x);
    202         // 2.2.2、获取输出层的输出
    203         get_net_out(out_x, out_w, output);
    204 
    205     }
    206 
    207     /**
    208      * 获取单个节点的输出
    209      * 
    210      * @param x
    211      *            输入矩阵
    212      * @param w
    213      *            权值
    214      * @return 输出值
    215      */
    216     private double get_node_put(double[] x, double[] w) {
    217         double z = 0d;
    218 
    219         for (int i = 0; i < x.length; i++) {
    220             z += x[i] * w[i];
    221         }
    222         // 2.激励函数
    223         return 1d / (1d + Math.exp(-z));
    224     }
    225 
    226     /**
    227      * 获取网络层的输出
    228      * 
    229      * @param x
    230      *            输入矩阵
    231      * @param w
    232      *            权值矩阵
    233      * @param net_out
    234      *            接收网络层的输出数组
    235      */
    236     private void get_net_out(double[] x, double[][] w, double[] net_out) {
    237 
    238         net_out[0] = 1d;
    239         for (int i = 0; i < w.length; i++) {
    240             net_out[i + 1] = get_node_put(x, w[i]);
    241         }
    242 
    243     }
    244 
    245 }
    

      

    (二) BP神经网络的测试

    用上面实现的BP神经网络来训练模型,自动判断它是正数还是复数,奇数还是偶数.

    1 public class Test {
     2 
     3     /**
     4      * @param args
     5      * @throws IOException
     6      */
     7     public static void main(String[] args) throws IOException {
     8         
     9     
    10         Bp bp = new Bp(32, 15, 4, 0.05);
    11 
    12         Random random = new Random();
    13         
    14         List<Integer> list = new ArrayList<Integer>();
    15         for (int i = 0; i != 6000; i++) {
    16             int value = random.nextInt();
    17             list.add(value);
    18         }
    19 
    20         for (int i = 0; i !=25; i++) {
    21             for (int value : list) {
    22                 double[] real = new double[4];
    23                 if (value >= 0)
    24                     if ((value & 1) == 1)
    25                         real[0] = 1;
    26                     else
    27                         real[1] = 1;
    28                 else if ((value & 1) == 1)
    29                     real[2] = 1;
    30                 else
    31                     real[3] = 1;
    32                 
    33                 double[] binary = new double[32];
    34                 int index = 31;
    35                 do {
    36                     binary[index--] = (value & 1);
    37                     value >>>= 1;
    38                 } while (value != 0);
    39 
    40                 bp.train(binary, real);
    41                
    42                 
    43 
    44             }
    45         }
    46         
    47 
    48         
    49         
    50         System.out.println("训练完毕,下面请输入一个任意数字,神经网络将自动判断它是正数还是复数,奇数还是偶数。");
    51 
    52         while (true) {
    53             
    54             byte[] input = new byte[10];
    55             System.in.read(input);
    56             Integer value = Integer.parseInt(new String(input).trim());
    57             int rawVal = value;
    58             double[] binary = new double[32];
    59             int index = 31;
    60             do {
    61                 binary[index--] = (value & 1);
    62                 value >>>= 1;
    63             } while (value != 0);
    64 
    65             double[] result =new double[4];
    66              bp.predict(binary,result);
    67 
    68              
    69             double max = -Integer.MIN_VALUE;
    70             int idx = -1;
    71 
    72             for (int i = 0; i != result.length; i++) {
    73                 if (result[i] > max) {
    74                     max = result[i];
    75                     idx = i;
    76                 }
    77             }
    78 
    79             switch (idx) {
    80             case 0:
    81                 System.out.format("%d是一个正奇数
    ", rawVal);
    82                 break;
    83             case 1:
    84                 System.out.format("%d是一个正偶数
    ", rawVal);
    85                 break;
    86             case 2:
    87                 System.out.format("%d是一个负奇数
    ", rawVal);
    88                 break;
    89             case 3:
    90                 System.out.format("%d是一个负偶数
    ", rawVal);
    91                 break;
    92             }
    93         }
    94     }
    95 }

    在BP神经网络中, 学习速率,训练集,以及训练次数,都会影响到最终模型的泛化能力。因此,在设计模型时,节点的个数,学习速率的大小,以及训练次数都是需要考虑的。

  • 相关阅读:
    ubuntu18安装net-snmp
    virtual box安装ubuntu系统 ping通 && xshell可以连接
    高中操场所见所思
    如何写好研究生开题报告
    在加州考驾照
    一个软件工程项目竞赛网站
    结对项目总结
    喜马拉雅随车听开通啦
    裘老师赠书
    推荐博客链接
  • 原文地址:https://www.cnblogs.com/lau1997/p/12210613.html
Copyright © 2020-2023  润新知