2

Я реализовал обратную нейронную сеть и обучил ее своим данным. Данные чередуются между предложениями на английском языке & Africa. Предполагается, что нейронная сеть идентифицирует язык ввода.Ошибка нейронной сети с каждым примером обучения

Структура сети 27 * 16 * 2 Входной слой содержит 26 входов для каждой буквы алфавита плюс блок смещения.

Моя проблема заключается в том, что ошибка бросается бурно в противоположных направлениях, так как каждый новый пример обучения встречается. Как я уже упоминал, примеры обучения читаются чередующимся образом (английский, африканский, английский ...)

Я могу обучить сеть, чтобы идентифицировать всех англичан или всех африканцев, но не идентифицировать ни один (оба) в тот же проход.

Ось ниже - это ошибка выходного сигнала для каждого из двух выходных узлов (английский и африканец), а ось 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);  
} 
+3

Не имея возможности увидеть весь ваш код, моим первым предложением было бы уменьшить ваш показатель скорости обучения ('learningRate'). – bogatron

+0

Я пробовал много разных параметров, но я не думаю, что это проблема с параметрами. – COOLBEANS

+0

Не совсем понятно, что вы рисуете, но поскольку ваши примеры чередуются между двумя классами, не кажется необоснованным, что и результаты будут чередоваться. Было бы лучше построить функцию потерь. – cfh

ответ

2

Я согласен с комментариями, что эта модель, вероятно, не самое лучшее для вашего но если вы заинтересованы в попытке заставить это работать, я дам вам причину, по которой я думаю, что это колеблется и как я попытаюсь решить эту проблему.

Из моего понимания вашего вопроса и комментариев я не могу понять, что сеть фактически «учит» в этом случае. Вы пишете буквы в (это количество раз, которое письмо имеет в предложении?), И вы вынуждаете его отображать на выход. Предположим, вы просто используете английский язык сейчас, а английский соответствует выходу 1. Таким образом, вы «тренируете» его на одном предложении, и для аргументации он выбирает букву «a» как определяющий вход, что является довольно общей буквой. Он устанавливает сетевой вес таким образом, что когда он видит «a», выход равен 1, а все другие буквенные входы становятся взвешенными, так что они не влияют на выход. Это может быть не так черно-белое, но это может быть нечто очень похожее. Теперь, каждый раз, когда вы пишете другое английское предложение, ему нужно увидеть только «a», чтобы дать правильный результат. Выполняя то же самое для просто африканцев, как выход из нуля, он отображает «а» на ноль. Таким образом, каждый раз, когда вы чередуетесь между двумя языками, он полностью переназначает весы ... вы не строите структуру. Обратное распространение ошибки в основном всегда является фиксированным значением, потому что нет степеней правильности или неправильности, это одно или другое. Поэтому я ожидаю, что он будет колебаться точно так же, как вы видите.

EDIT: Я думаю, что это сводится к чему-то вроде присутствия букв, используемых для классификации языковой категории и ожидающих одного из двух полярных выходов, а не что-либо о связи между буквами, которые определяют язык.

На концептуальном уровне у меня будет полная предварительная обработка, чтобы получить статистику.В верхней части моей головы я мог бы рассчитать (я не знаю языка): - Отношение буквы «a» к «c», имеющейся в предложении - Отношение буквы «d» к «p» в предложении - Средняя длина слова в предложении

Сделайте это для 50 предложений каждого языка. Сначала загружайте все данные и тренируйтесь по всему набору (70% для обучения, 15% для проверки, 15% для тестирования). Вы не можете тренировать сеть по одному значению каждый раз (как я думаю, вы делаете?), Он должен видеть всю картину. Теперь ваш вывод не так черно-белый, он имеет гибкость при сопоставлении со значением от 0 до 1, а не абсолютом каждый раз. Все, что выше 0,5, является английским, ниже 0,5 - это африканцы. Начните с, скажем, 10 статистических параметров для языков, 5 нейронов в скрытом слое, 1 нейрон в выходном слое.

+0

Я думаю, что ваш совет может быть на месте. Я смог классифицировать примеры, которые были все и все b, но я думаю, что оба языка слишком похожи. Чтобы усугубить ситуацию, они являются одинаковыми предложениями на любом языке, поэтому они имеют много сходства. Я дам вам знать, как только я создам еще некоторые функции. Благодарю. – COOLBEANS

+0

Во всяком случае, это должно быть проще, если они являются одинаковыми предложениями, потому что вы можете видеть, какая статистика имеет отношение к тому, чтобы помочь * вы * различать их и передавать это на NN. Просто помните, что вы не можете капать NN, он может только улучшить, если он может оценить влияние своих новых весов на все данные. Если мой совет поможет найти решение, я был бы признателен за то, что он был отмечен/отмечен как правильный, поскольку я новичок и еще не имею репутацию, чтобы прокомментировать ваш вопрос, чтобы просить о каких-либо разъяснениях, я должен был стреляйте прямо для ответа! – roganjosh

+0

У меня теперь есть только шесть функций, и, похоже, он работает, когда я использую небольшой импульс обучения и скорость обучения. Я использовал двойные гласные как одну особенность, потому что они распространены в Африке и короткий список общих слов типа («the, it and» на обоих языках. Спасибо. – COOLBEANS

Смежные вопросы