神经网络误差随每个训练样例而振荡

我已经实现了一个反向传播的神经网络并对我的数据进行了训练 . 数据在英语和非洲语句子之间交替 . 神经网络应该识别输入的语言 .

网络的结构是27 * 16 * 2输入层有26个输入,用于字母表的每个字母加上一个偏置单元 .

我的问题是,当遇到每个新的训练样例时,错误会在相反的方向上猛烈地抛出 . 正如我所提到的,培训实例以交替方式阅读(英语,非洲语,英语......)

我可以训练网络识别所有英语或所有非洲人,但不能识别同一通道中的任何一个(两者) .

下面的y轴是两个输出节点(英语和非洲语)中每一个的输出信号错误,x轴是训练示例的编号 . 在某种程度上,它完全符合我的编程要求;当示例是英语时,它会更改权重以更好地识别英语 . 然而,这样做会使网络在预测非洲人方面变得更糟 . 这就是误差在正值和负值之间的原因 .

显然这不是它应该如何工作,但我被卡住了 .

enter image description here

我觉得错误是我的概念,但这里是相关的代码:

public void train() throws NumberFormatException, IOException{

    // Training Accuracy
    double at = 0;

    //epoch
    int epoch = 0;

    int tNum = 0;

    for(; epoch < epochMax; epoch++){

        // Reads stock files from TestPackage package in existing project
        BufferedReader br = new BufferedReader(new InputStreamReader(this.getClass().
                getResourceAsStream("/TrainingData/" + trainingData.getName())));

        while ((line = br.readLine()) != null) {

            Boolean classified = false;

            tNum++;

            // Set the correct classification Tk
            t[0] = Integer.parseInt(line.split("\t")[0]); //Africaans
            t[1] = (t[0] == 0) ? 1 : 0; // English


            // Convert training string to char array
            char trainingLine[] = line.split("\t")[1].toLowerCase().toCharArray();


            // Increment idx of input layer z, that matches
            // the position of the char in the alphabet
            // a == 0, b == 2, etc.....
            for(int l = 0; l < trainingLine.length; l++){
                if((int)trainingLine[l] >= 97 && (int)trainingLine[l] <= 122)
                    z[(int)trainingLine[l] % 97]++;
            }


            /*System.out.println("Z   " + Arrays.toString(z));
            System.out.println();*/

            // Scale Z
            for(int i = 0; i < z.length-1; i++){
                z[i] = scale(z[i], 0, trainingLine.length, -Math.sqrt(3),Math.sqrt(3));
            }

         /*----------------------------------------------------------------
          *                  SET NET HIDDEN LAYER 
          * Each ith unit of the hidden Layer = 
          * each ith unit of the input layer
          * multiplied by every j in the ith level of the weights matrix ij*/


            for(int j = 0; j < ij.length; j++){  // 3
                double[] dotProduct = multiplyVectors(z, ij[j]);
                y[j] = sumVector(dotProduct);   

            }


            /*----------------------------------------------------------------
             *                 SET ACTIVATION HIDDEN LAYER 
             */

            for(int j = 0; j < y.length-1; j++){
                y[j] = sigmoid(y[j], .3, .7);
            }

            /*----------------------------------------------------------------
             *                       SET NET OUTPUT LAYER 
             * Each jth unit of the hidden Layer = 
             * each jth unit of the input layer
             * multiplied by every k in the jth level of the weights matrix jk*/


            for(int k = 0; k < jk.length; k++){  // 3
                double[] dotProduct = multiplyVectors(y, jk[k]);
                o[k] = sumVector(dotProduct);
            }

            /*----------------------------------------------------------------
             *                   SET ACTIVATION OUTPUT LAYER
             */

            for(int k = 0; k < o.length; k++){
                o[k] = sigmoid(o[k], .3, .7);
            }

            /*----------------------------------------------------------------
             *                     SET OUTPUT ERROR
             * For each traing example, evalute the error.
             * Error is defined as (Tk - Ok)
             * Correct classifications will result in zero error:
             *          (1 - 1) = 0
             *          (0 - 0) = 0
             */

            for(int k = 0; k < o.length; k++){
                oError[k] = t[k] - o[k];
            }

            /*----------------------------------------------------------------
             *                     SET TRAINING ACCURACY
             * If error is 0, then a 1 indicates a succesful prediction.
             * If error is 1, then a 0 indicates an unsucessful prediction.
             */

            if(quantize(o[0],.3, .7) == t[0] && quantize(o[1], .3, .7) == t[1]){
                classified = true;
                at += 1;
            }


            // Only compute errors and change weiths for classification errors
            if(classified){
                continue;
            }

            /*----------------------------------------------------------------
             *                  CALCULATE OUTPUT SIGNAL ERROR
             *                 Error of ok = -(tk - ok)(1 - ok)ok
             */


            for(int k = 0; k < o.length; k++){
                oError[k] = outputError(t[k], o[k]);

            }

            /*----------------------------------------------------------------
             *                  CALCULATE HIDDEN LAYER SIGNAL ERROR
             *                  
             */

            // The term (1-yk)yk is expanded to yk - yk squared

            // For each k-th output unit, multiply it by the
            // summed dot product of the two terms (1-yk)yk and jk[k]


            for(int j = 0; j < y.length; j++){
                for(int k = 0; k < o.length; k++){
                    /*System.out.println(j+"-"+k);*/
                    yError[j] +=  oError[k] * jk[k][j] * (1 -  y[j]) * y[j];

                }
            }   
            /*----------------------------------------------------------------
             *                  CALCULATE NEW WIGHTS FOR HIDDEN-JK-OUTPUT
             *                  
             */

            for(int k = 0; k < o.length; k++){
                for(int j = 0; j < y.length; j++){
                    djk[k][j] = (-1*learningRate)*oError[k]*y[j] + momentum*djk[k][j];

                    // Old weights = themselves + new delta weight
                    jk[k][j] += djk[k][j]; 

                }
            }

            /*----------------------------------------------------------------
             *         CALCULATE NEW WIGHTS FOR INPUT-IJ-HIDDEN
             *                  
             */

            for(int j = 0; j < y.length-1; j++){
                for(int i = 0; i < z.length; i++){

                    dij[j][i] = (-1*learningRate)*yError[j]*z[i] + momentum*dij[j][i];

                    // Old weights = themselves + new delta weight
                    ij[j][i] += dij[j][i]; 

                }
            }
        }
    }
    // Accuracy Percentage
    double at_prec = (at/tNum) * 100;

    System.out.println("Training Accuracy: " + at_prec);    
}

回答(1)

3 years ago

我同意这个模型可能不是最适合你的分类问题的评论,但如果你有兴趣尝试让它工作,我会告诉你我认为这种振荡的原因以及我试图解决这个问题的方式 .

根据我对您的问题和评论的理解,我无法理解网络在这种情况下实际“学习”了什么 . 你输入字母(这是字母在句子中出现的次数吗?),你强制它映射到输出 . 假设你现在只使用英语而英语对应于1的输出 . 所以你在一个句子上“训练”它,为了参数的缘故,它选择字母“a”作为确定输入,这是一个非常普遍的字母 . 它设置网络权重,使得当它看到“a”时输出为1,并且所有其他字母输入被加权,使得它们不影响输出 . 它可能不是那么黑白,但可能会做一些非常相似的事情 . 现在,每当你输入另一个英文句子时,它只需要看到一个“a”来给出正确的输出 . 只为非洲人做零输出,它将“a”映射到零 . 所以,每当你在两种语言之间交替时,它就会完全重新分配权重......你不是 Build 在一个结构上 . 误差的反向传播基本上总是固定值,因为没有正确度或错误度,它是一个或另一个 . 所以我希望它能像你看到的那样完全摆动 .

编辑:我认为这归结为类似于字母的存在被用来对语言类别进行分类并期望两个极性输出中的一个,而不是关于定义语言的字母之间的关系 .

从概念上讲,我会有一个完整的预处理阶段来获取一些统计数据 . 在我的头顶,我可能会计算(我不知道语言): - 句子中出现的字母“a”与“c”的比率 - 在句子中出现字母“d”与“p”的比例 - 句子中单词的平均长度

为每种语言的50个句子执行此操作 . 立即输入所有数据并在整个训练集上训练(70%用于训练,15%用于验证,15%用于测试) . 你不能每次都训练一个网络(我认为你在做什么?),它需要看到整个画面 . 现在你的输出不是那么黑白,它可以灵活地映射到介于0和1之间的值,而不是每次都是绝对值 . 高于0.5的任何东西都是英语,低于0.5的是非洲人 . 例如,从语言的10个统计参数开始,隐藏层中的5个神经元,输出层中的1个神经元 .