Список форумов neuroproject.ru neuroproject.ru
Форум сайта компании НейроПроект
 
 FAQFAQ   ПоискПоиск   ПользователиПользователи   ГруппыГруппы   РегистрацияРегистрация 
 ПрофильПрофиль   Войти и проверить личные сообщенияВойти и проверить личные сообщения   ВходВход 

Сеть обучает неправильно

 
Начать новую тему   Ответить на тему    Список форумов neuroproject.ru -> Нейронные сети
Предыдущая тема :: Следующая тема  
Автор Сообщение
Fireman2806
Новый посетитель
Новый посетитель


Зарегистрирован: 04 Май 2013
Сообщения: 1

СообщениеДобавлено: Сб Май 04, 2013 2:30 pm    Заголовок сообщения: Сеть обучает неправильно Ответить с цитатой

Помогите, пожалуйста, найти ошибку в программе. Её цель состоит в распознавании рукописных цифр с изображения. Для простоты используется специальная база MNIST (картинки 28х28 представлены в виде набора значений пикселей от 0 до 255). Также имеется база цифр, которые соответствуют данным наборам пикселей (нужна для обучения). В сети один скрытый слой с активационной функцией сигмоида, выходной слой содержит функцию softmax. Для обучения используется метод обратного распространения ошибки. Брал с Википедии: http://ru.wikipedia.org/wiki/Метод_обратного_распространения_ошибки. Суть проблемы состоит в том, что сеть просто не правильно обучается (распознает неправильно большинство чисел). Пробовал менять параметры сети (число нейронов в слоях, скорость обучения, коэффициент инерциальности) - не помогает.

Код на С++:

Код:
#include "stdafx.h"
#include "fstream"
#include "iostream"
#include "math.h"
#include <conio.h>
#include <ctype.h>
#include <random>
using namespace std;
const int x = 28, y = 28, k0 = 50, k = 10, steps = 1000, study_part = 10000, valid_part = 15000, test_part = 60000, base_size = 60000; //x * y - число пикселей в картинке, k0 - число нейронов во внутреннем слое, k - число нейронов в последнем слое, steps - максимальное количество эпох обучения, study, valid и test part - верхние границы частей БД, разбитой для обучения, валидации и тестирования.
const double a = 0.7; // коэффициент инерциальнности для сглаживания резких скачков при перемещении по поверхности целевой функции
const double n = 0.04; // скорость
const float e = exp(1.0);
int current = valid_part, int_label[base_size]; // current - позиция в БД (номер картинки), которая тестируется в данный момент, int_label - массив цифр, которые соответствуют каждому набору пикселей в БД.
string adress;
double int_input[base_size][x][y], sum1[k0], sum2[k], act[k0], weight1[k0][x][y], weight2[k][k0], out[k], answer[base_size][k], b2[k0], b3[k], d_weight1[k0][x][y], d_weight2[k][k0]; // int_input - преобразованные в int входные данные, sum1 - массив сумм для скрытого слоя, sum2 - массив сумм для последнего слоя, act - массив значений сигмоиды (скрытый слой), weight1 (weight2) - наборы весов, out - выходной вектор (обработанный функцией softmax), answer - массив ответов (заранее известных), b2 и b3 - величины, необходимые для обучения, d_weight1 и d_weight2 - изменения весов.
unsigned char input[base_size][x][y], label[base_size]; // считанные данные (набор картинок в виде пикселей и числа соответствующие каждому набору) - непреобразованные в численный тип.

ifstream file_labels ("C:\\train-labels.idx1-ubyte", ios::binary);
ifstream file ("C:\\train-images.idx3-ubyte", ios::binary);

void open() // открытие файлов БД
{
   ifstream file_labels ("C:\\train-labels.idx1-ubyte", ios::binary);
   ifstream file ("C:\\train-images.idx3-ubyte", ios::binary);
}
void Ini() // инициализация
{
   memset(sum1,0,sizeof(sum1));
   memset(sum2,0,sizeof(sum2));
   memset(d_weight1,0,sizeof(d_weight1));
    memset(d_weight2,0,sizeof(d_weight2));
   for (int i = 0; i < k0; i++)
      for (int j = 0; j < x; j++)
         for (int u = 0; u < y; u++)
            weight1[i][j][u] = (rand() % 100) / 100.0 / 5.0 - 0.1;
   for (int i = 0; i < k; i++)
      for (int j = 0; j < k0; j++)
         weight2[i][j] = (rand() % 100) / 100.0 / 5.0 - 0.1;
}
void Set_Network(int g) // построение сети
{
   memset(sum1,0,sizeof(sum1));
   memset(sum2,0,sizeof(sum2));
   double ss = 0;
   for (int t = 0; t < k0; t++)
   {
      for (int i = 0; i < x; i++)
         for (int j = 0; j < y; j++)
            sum1[t] += weight1[t][i][j] * int_input[g][i][j];
      act[t] = 1/(1 + exp(-2*a*sum1[t]));  // функция активации скрытого слоя - сигмоида
      for (int i = 0; i < k; i++)
      {
         sum2[i] += weight2[i][t] * act[t];
         ss += exp(sum2[i]);
      }
   }
   for (int i = 0; i < k; i++)
      out[i] = pow(e, sum2[i]) / ss;  // функция активации последнего слоя - softmax
}
int Rez()  // вывод результата работы сети исходя из полученного выходного вектора out
{
   double max = -1;
   int max_index = -1;
   for (int i = 0; i < k; i++)
      if (out[i] > max)
      {
         max = out[i];
         max_index = i;
      }
   return max_index;
}
double Error(int g) // подсчет ошибки  распознавания для одного построения сети
{
   double s = 0;
   for (int i = 0; i < k; i++)
      s += (answer[g][i] - out[i]) * (answer[g][i] - out[i]);
   return (s / 2);
}
void Teach(int g)
{
   for (int i = 0; i < k0; i++)
   {
      double s = 0;
      for (int j = 0; j < k; j++)
      {
         b3[j] = -out[j] * (1 - out[j]) * (answer[g][j] - out[j]);
         s += b3[j] * weight2[j][i];
      }
      b2[i] = - act[i] * (1 - act[i]) * s;
      for (int j = 0; j < x; j++)
         for (int u = 0; u < y; u++)
         {
            d_weight1[i][j][u] = a * d_weight1[i][j][u] + (1 - a) * n * b2[i] * int_input[g][j][u];            
            weight1[i][j][u] += d_weight1[i][j][u];
         }
      for (int j = 0; j < k; j++)
      {
         d_weight2[j][i] = a * d_weight2[j][i] + (1 - a) * n * b3[j] * act[i];
         weight2[j][i] += d_weight2[j][i];
      }
   }
}
int reverseInt (int i) // приведение чисел, считанных в Read_mnist() к нормальному виду
{
    unsigned char c1, c2, c3, c4;

    c1 = i & 255;
    c2 = (i >> 8) & 255;
    c3 = (i >> 16) & 255;
    c4 = (i >> 24) & 255;

    return ((int)c1 << 24) + ((int)c2 << 16) + ((int)c3 << 8) + c4;
}
void Read_mnist() // считывание входных данных из файлов
{
    if (file.is_open())
    {
        int magic_number=0;
        int number_of_images=0;
        int n_rows=0;
        int n_cols=0;
      int labels_magic_number = 0;
      int number_of_items = 0;
      file_labels.read((char*)&labels_magic_number,sizeof(labels_magic_number));
        labels_magic_number = reverseInt(labels_magic_number);
      file_labels.read((char*)&number_of_items,sizeof(number_of_items));
        number_of_items= reverseInt(number_of_items);
        file.read((char*)&magic_number,sizeof(magic_number));
        magic_number= reverseInt(magic_number);
        file.read((char*)&number_of_images,sizeof(number_of_images));
        number_of_images= reverseInt(number_of_images);
        file.read((char*)&n_rows,sizeof(n_rows));
        n_rows= reverseInt(n_rows);
        file.read((char*)&n_cols,sizeof(n_cols));
        n_cols= reverseInt(n_cols);   
      file.read((char*)&input,sizeof(input));
      file_labels.read((char*)&label,sizeof(label));
      for(int i=0;i<number_of_items;i++)
      {         
         for(int r=0;r<n_rows;++r)
            {
                for(int c=0;c<n_cols;++c)
               int_input[i][r][c] = (double)input[i][r][c] / 255.0;
            }            
         int_label[i] = (int)label[i];
         //memset(answer,0,sizeof(answer));
         for (int j = 0; j < k; j++)  // построение вектора ответа (везде нули, кроме элемента с индексом, равным текущей поданной на вход цифре)
         {
            answer[i][j] = 0;
            if (j == int_label[i])
               answer[i][j] = 1;
         }
        }
    }
}
void save_weight() // сохранение весов в файл
{
   ofstream fout("weights.txt", ios::out);
   fout.write((char *)&weight1,sizeof(weight1));
   fout.write((char *)&weight2,sizeof(weight2));
   fout.close();
}
void load_weight() // загрузка весов из файла
{
   ifstream fin("weights.txt", ios::in);
   fin.read((char*)&weight1,sizeof(weight1));
   fin.read((char*)&weight2,sizeof(weight2));
   fin.close();
}
/*void save_labels_and_input() // сохранение считанных из БД данных (для проверки корректности)
{
   ofstream fout("labels.doc", ios::out);
   fout.write((char*)&int_label,sizeof(int_label));
   fout.close();
   ofstream fout2("input.doc", ios::out);
   fout2.write((char*)&int_input,sizeof(int_input));
   fout2.close();
}*/
void save_labels_and_input() // сохранение считанных из БД данных (для проверки корректности)
{
   ofstream fout;
   fout.open("labels.txt");
   for (int i = 0; i < base_size; i++)
      fout << int_label[i] << " ";
   fout.close();
   ofstream fout2;
   double k;
   fout2.open("input.txt");
   for (int i = 0; i < 20; i++)
      for (int j = 0; j < x; j++)
         for (int h = 0; h < y; h++)
         {
            if (int_input[i][j][h] > 0)
               k = 1;
            else
               k = 0;
            fout2 << k << " ";
         }
   fout2.close();
}

void Stop_reading() // закрытие файлов
{
   file.close();
   file_labels.close();
}
int main(array<System::String ^> ^args)
{
   Ini();
   Read_mnist();
   //save_labels_and_input();
   int ans;
   while (ans != 6)
   {
      system("cls");
      cout << "1 - teach" << endl;
      cout << "2 - analise" << endl;
      cout << "3 - nothing" << endl;
      cout << "4 - save weigths" << endl;
      cout << "5 - load weights" << endl;
      cout << "6 - exit" << endl << endl;
      cin >> ans;
      bool stop = false;
      double error_arr[4] = {9999,9999,9999,9999}, error_of_step = 0;
      int o = 1, z = 0; // o - номер эпохи обучения
      switch (ans)
      {
      case 1:
          while (!stop && o != steps)  // эпохи обучения
          {
             error_of_step = 0;
             cout << endl << endl << "!!!  " << o << "  !!!" << endl << endl;
             for (int i = 0; i < study_part; i++)  // часть БД на обучение
             {
               //if (i == 1253)
                  //system("pause");
               Set_Network(i);
               Teach(i);
               if (i % 1000 == 0)
                  cout << i << " ";
             }
             cout << endl << endl;
             for (int j = study_part; j < valid_part; j++) // часть БД на валидацию (подсчет ошибки)
             {
               Set_Network(j);
               error_of_step += Error(j);
               if (j % 1000 == 0)
                  cout << j << " ";
             }
             error_arr[z] = error_of_step / (valid_part - study_part);
             cout << endl << endl << error_arr[z];
             if (z == 3)
                z = 0;
             else
                z++;
             if (error_arr[0] < error_arr[1] && error_arr[1] < error_arr[2] && error_arr[2] < error_arr[3] && (o % 4) == 0 && o > 31) // если ошибка некоторое время увеличивается - окончание обучения
               stop = true;
             else  // иначе открытие файла для чтения заного
             {
                Stop_reading();
                open();
             }
             o++;
         }
         cout << endl << "Teaching completed" << endl;
         system("pause");
         break;
      case 2:
         cout << "label: " << int_label[current] << endl;
         if (current == base_size)
             cout << "End of base!";
         else
         {
            Set_Network(current);
            cout << "Answer: " << Rez() << endl;
         }
         current++;
         system("pause");
         break;
      case 3:
         
         break;
      case 4:
         save_weight();
         break;
      case 5:
         load_weight();
         break;
      default:
         break;
      o++;
      }
   }
    return 0;
}
Вернуться к началу
Посмотреть профиль Отправить личное сообщение
Victor G. Tsaregorodtsev
Эксперт
Эксперт


Зарегистрирован: 28 Июн 2005
Сообщения: 248
Откуда: Красноярск

СообщениеДобавлено: Сб Май 04, 2013 4:11 pm    Заголовок сообщения: Ответить с цитатой

Инерцию в морг, скорость обучения уменьшить на порядок. И при таких настройках - добивайтесь правильности обучения бэкпропом "на кошках" (на простых тестах - сначала аппроксимация прямой y=x, потом - аппроксимация нескольких периодов синуса, и т.д., переходя от сети с одним входом и одним выходом к многовходовой и многовыходовой сети).
Да - Вашу сигмоиду тоже в морг, а на её место - гиперболический тангенс.
Ну и, может, персептрону нафиг не нужен софтмакс. Сначала поиграйтесь с обычной МНК (в роли целевой функции), поставив на выходной слой сначала нейроны без нелинейностей, потом нейроны с тем же tanh. Ориентиры по точности распознавания тестовой выборки - возьмёте с картинки тут: http://neuropro.ru/memo315.shtml
Т.е. когда у Вас "классика" заработает правильно - тогда и лезьте в использование инерции и софтмакса. А до этого - лучше отлаживать программу, сократив число возможностей настройки (т.е. идя от простой правильно работающей программы - к сложной).
_________________
neuropro.ru - нейронные сети, анализ данных, прогнозирование
Вернуться к началу
Посмотреть профиль Отправить личное сообщение Отправить e-mail Посетить сайт автора
postrop
Новый посетитель
Новый посетитель


Зарегистрирован: 14 Ноя 2013
Сообщения: 3
Откуда: Питер

СообщениеДобавлено: Пт Ноя 15, 2013 1:31 am    Заголовок сообщения: сеть Ответить с цитатой

Все нужно побить на кубики с одним входом, когда все заработает, то кубики объединять в квадраты по 4 кубика на стороне с удвоением входов. Я бы как то так строила тему. В СИ залезла, но что то не поняла некоторых функций, описание дайте?
_________________
Вернуться к началу
Посмотреть профиль Отправить личное сообщение Посетить сайт автора
ledydy
Новый посетитель
Новый посетитель


Зарегистрирован: 04 Дек 2013
Сообщения: 3
Откуда: Дружковка

СообщениеДобавлено: Ср Дек 04, 2013 6:40 pm    Заголовок сообщения: Сеть Ответить с цитатой

Все нужно побить на кубики с одним входом, когда все заработает, то кубики объединять в квадраты по 4 кубика на стороне с удвоением входов. Я бы как то так строила тему. В СИ залезла, но что то не поняла некоторых функций, описание дайте?
--------
Да какая же это сеть нейронная? Просто кусок кода кто то влупил и хочет размусолить темуSmile) Где тут намек на нейронные сети????
_________________
Вернуться к началу
Посмотреть профиль Отправить личное сообщение Посетить сайт автора
Показать сообщения:   
Начать новую тему   Ответить на тему    Список форумов neuroproject.ru -> Нейронные сети Часовой пояс: GMT + 4
Страница 1 из 1

 
Перейти:  
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах


Rambler's Top100 Rambler's Top100