随每个训练示例振荡的神经网络误差

Neural Network Error oscillating with each training example

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

网络的结构是27*16*2 输入层的每个字母都有 26 个输入加上一个偏置单元。

我的问题是,当遇到每个新的训练示例时,错误会向相反的方向猛烈抛出。正如我提到的,训练示例以交替方式读入(英语、非洲语、英语....)

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

下面的y轴是两个输出节点(English和Africaans)各自的Output signal error,x轴是训练样例的个数。在某种程度上,它完全按照我的程序进行操作;当示例是英语时,它会更改权重以更好地识别英语。然而,这样做会使网络在预测非洲人方面变得更糟。这就是误差在正值和负值之间的原因。

显然这不是它应该的工作方式,但我被卡住了。

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

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。所以你在一个句子上“训练”它,为了论证,它选择字母“a”作为确定输入,这是一个很常见的字母。它设置网络权重,当它看到“a”时,输出为 1,而所有其他字母输入的权重都会降低,这样它们就不会影响输出。它可能不是那么黑白分明,但它可能在做一些非常相似的事情。现在,每次你输入另一个英文句子时,它只需要看到一个“a”就可以给出正确的输出。对非洲人做同样的事情作为输出零,它将“a”映射到零。因此,每次您在两种语言之间切换时,它都会完全重新分配权重……您不是在结构上构建。错误的反向传播基本上总是一个固定值,因为没有正确或错误的程度,它是一个或另一个。所以我希望它会像您所看到的那样振荡。

编辑:我认为这归结为诸如用于对语言类别进行分类的字母的存在并期望两个极性输出之一,而不是关于定义语言的字母之间的关系的任何事情。

在概念层面上,我会有一个完整的预处理阶段来获得一些统计数据。在我的脑海中,我可能会计算(我不懂语言): - 字母“a”和“c”在句子中出现的比例 - 字母“d”与“p”在句子中出现的比例 - 句子中单词的平均长度

对每种语言做 50 个句子。一次输入所有数据并对整个数据集进行训练(70% 用于训练,15% 用于验证,15% 用于测试)。您不能每次都在单个值上训练网络(就像我想的那样?),它需要看到整个画面。现在你的输出不是那么黑白分明,它可以灵活地映射到 0 到 1 之间的值,而不是每次都映射到绝对值。高于 0.5 的是英国人,低于 0.5 的是非洲人。例如,从语言的 10 个统计参数开始,隐藏层中有 5 个神经元,输出层中有 1 个神经元。