LINUX.ORG.RU

Странное поведение нейросети

 


0

1

Здравствуйте!

Запрограммировал нейросеть в соответствии с этой статьей: https://microtechnics.ru/obuchenie-nejronnyh-setej-obratnoe-rasprostranenie-oshibki/.

N слоев, M нейронов в каждом слое.

Делаю обучение. На вход много раз подаю вектор, например, такой: (2, 2, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1), использую учитель, например, такой: (0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 2, 2).

В результате на первом слое образуются одинаковые веса, такие, что сигма-функция от них = 0.5. То есть входной вектор просто сглаживается.

То же происходит и на прочих слоях, а на последнем веса такие, что формируют на выходе вектор-учитель.

То есть какой бы я не подал вектор на вход обученной сети, на выходе получаю «ОК».

В принципе, мне понятно, почему сеть так себя ведет. Но ведь так не должно быть.

Видимо, я что-то не понимаю, прошу помочь.

Ответ на: комментарий от unDEFER

Я делал еще так: через раз подавал 2 разных входных и 2 учителя для них. Результат - такой же, первые слои сглаживают вход.

Это тоже слишком примитивное обучение? А как надо? Или где можно про это почитать?

markata
() автор топика
Ответ на: комментарий от markata

Ну вот у вас даже по вашей ссылке есть табличка «Допустим, сеть выполняет суммирование значений на входе». И в этой табличке 1000 строчек.

Вот это гораздо больше походит на типичное обучение нейросетей.

unDEFER ★★★★★
()
Ответ на: комментарий от markata

Это тоже слишком примитивное обучение?

смысл обучения в том, чтобы ваша нейросеть для разных входных данных давала разный результат и этот результат был статистически близок к ожидаемому, правильно? То есть обучающая выборка должна быть достаточно большой, чтобы покрыть все возможные варианты входных данных. А вы, я так понял, обучаете нейросеть ровно на одном примере.

FishHook
()

В результате на первом слое образуются одинаковые веса, такие, что сигма-функция от них = 0.5. То есть входной вектор просто сглаживается.

Входяйщий слой сети просто отмер, за ненадобностью.

То же происходит и на прочих слоях, а на последнем веса такие, что формируют на выходе вектор-учитель.

Тоже отмерли, не нужны в данной задаче.

То же происходит и на прочих слоях, а на последнем веса такие, что формируют на выходе вектор-учитель.

Эта ситуация называется переобучением.

Но ведь так не должно быть.

Именно так и должно быть. Слишком мало вариантов данных для обучения. В итоге сеть просто «заучила» ответ. Чтобы этого не происходило данных должно быть много и они должны быть разнообразными.

Другими словами - вы буквально требуете от сети заучить выходные данные из обучающего набора (то что вы называете учителем), она это и делает.

Видимо, я что-то не понимаю, прошу помочь.

Почитайте про проблему переобучения сети и про правильную подготовку данных для обучающей выборки. Правильные данные это 50% успеха в обучении сети.

Obezyan
()
Ответ на: комментарий от Obezyan

В общем, я сдаюсь. Перепробовал много вариантов, все время одно и то же. Усредняет и привет.

Кто бы мне помог, возможно платно, разобраться со всем этим. Отталкиваясь от моих исходников (лучше) или от чужих.

Старый стал, времени не хватает 🙂

markata
() автор топика
Ответ на: комментарий от Obezyan

Ниже - код под кнопкой Обучение. Здесь в цикле формируются входной и обучающий вектор, функция Teach() - шаг обучения.

void __fastcall TForm1::bTrainClick(TObject *Sender) { int i, j, k;

FStop = 0; lOK->Caption = "";

int N = 10;//100; // слоев int M = 8;//2; // штук в слое

double alpha = 0.5;//0.005; double gamma = 0.0; //0.0 double a = 1;//0.7; //40.0
double Em = 1.0e-7; int qtyEm = 20; int kEm = 0;

if(perc1) { delete perc1; perc1 = NULL; }

perc1 = new PERCEPTRON(); perc1->regime = 0; // îáó÷åíèå if(perc1->Ini(M, N, alpha, gamma, a, Em, qtyEm, kEm) == 0) Application->MessageBox(«Íå óäàëîñü âûäåëèòü ïàìÿòü!», "", MB_OK);

while(FStop == 0) { int x0 = rand() % 256; BYTE xb, msk = 1; xb = x0;

  perc1->X[0] = (double)x0 / 256;  perc1->X[1] = (double)x0 / 256;  perc1->X[2] = (double)x0 / 256;  perc1->X[3] = (double)x0 / 256;  perc1->X[4] = (double)x0 / 256;  perc1->X[5] = (double)x0 / 256;  perc1->X[6] = (double)x0 / 256;  perc1->X[7] = (double)x0 / 256;

  if(perc1->X[0] < 0.1)  { perc1->D[0] = 1;  perc1->D[1] = 1;  perc1->D[2] = 0;  perc1->D[3] = 0;  perc1->D[4] = 0;  perc1->D[5] = 0;  perc1->D[6] = 0;  perc1->D[7] = 0; }
  else         { perc1->D[0] = 0;  perc1->D[1] = 0;  perc1->D[2] = 0;  perc1->D[3] = 0;  perc1->D[4] = 0;  perc1->D[5] = 0;  perc1->D[6] = 1;  perc1->D[7] = 1; }

Application->ProcessMessages();
if(perc1->Teach())  { lOK->Caption = "OK";  break; }

}

delete perc1; perc1 = NULL; }

markata
() автор топика
Ответ на: комментарий от Obezyan

int __fastcall PERCEPTRON::Teach() { int i, j, k, res = 0; double s0;

// Проход вперед for(k = 0; k < N; k++) { for(j = 0; j < M; j++) // сумма и сигма для j-го нейрона данного слоя { S[k][j] = 0; for(i = 0; i < M; i++) { if(k == 0) S[k][j] += w[k][i][j] * X[i]; else S[k][j] += w[k][i][j] * Y[k - 1][i][0]; } Y[k][j][0] = Sigma(S[k][j] - b[k][j]); Y[k][j][1] = a * Y[k][j][0] * (1 - Y[k][j][0]); // значение производной k=k; } }

// Считаем E. Если он меньше Em, то res = 1; иначе - делаем обратное распространение. E = 0; for(i = 0; i < M; i++) { s0 = Y[N - 1][i][0] - D[i]; E += 0.5 * s0 * s0; }

if(E < Em) kEm++; else kEm = 0; if(kEm >= qtyEm) res = 1; else // Проход назад { // Расчет ошибок выходного слоя for(j = 0; j < M; j++) delta[N - 1][j] = (D[j] - Y[N - 1][j][0]) * Y[N - 1][j][1]; // Расчет ошибок по скрытым слоям for(k = N - 2; k >= 0; k–) { for(i = 0; i < M; i++) { delta[k][i] = 0; for(j = 0; j < M; j++) delta[k][i] += delta[k + 1][j] * w[k + 1][i][j] * Y[k][i][1]; } }

// Пересчет весов и порогов
for(k = 0; k < N; k++)
  for(i = 0; i < M; i++)
    for(j = 0; j < M; j++)
    {
      w[k][i][j] = w[k][i][j] * (1 + gamma) + alpha * delta[k][j] * Y[k][i][0];
      b[k][j] = b[k][j] - alpha * delta[k][j];
    }

}

return res; }

markata
() автор топика
Ответ на: комментарий от markata

Глаза вытекли, ну ладно.

  1. Зачем вам 10 слоев? Для аппроксимации любой гладкой непрерывной функции (в теории) достаточно одного скрытого слоя. Поэкспериментируйте с 1-2 скрытыми слоями. Скрытые это не выходной и не выходной слои.

  2. В выходном слое нейроны 2,3,4 и 5 всегда нулевые. Это не имеет смысла. А нейроны 1 и 2 - дублируют друг друга, те всегда имеют одинаковое значение. Как и нейроны 6,7.

Измените выходной слой, оставьте один нейрон.

if (perc1->X[0] < 0.1)  { 
    perc1->D[0] = 1;
} else { 
    perc1->D[0] = 0;
}
  1. Из п2 явно видно что в ваших данных только первое значение (X[0]) играет какую либо роль. Все остальное - несущественные признаки. Те их можно отбросить и оставить один входной нейрон.

Итого у вас сеть с одним входным и одним выходным нейроном которая полностью описывает предоставляемые ей данные.

У вас ошибка в качестве данных.

Obezyan
()
Последнее исправление: Obezyan (всего исправлений: 1)
Ответ на: комментарий от Obezyan

int __fastcall PERCEPTRON::Teach() { int i, j, k, res = 0; double s0;

// Проход вперед for(k = 0; k < N; k++) { for(j = 0; j < M; j++) // сумма и сигма для j-го нейрона данного слоя { S[k][j] = 0; for(i = 0; i < M; i++) {

if(k == 0)

S[k][j] += w[k][i][j] * X[i];

else

S[k][j] += w[k][i][j] * Y[k - 1][i][0]; }

Y[k][j][0] = Sigma(S[k][j] - b[k][j]);

Y[k][j][1] = a * Y[k][j][0] * (1 - Y[k][j][0]); // значение производной k=k; } }

// Считаем E. Если он меньше Em, то res = 1; иначе - делаем обратное распространение.

E = 0;

for(i = 0; i < M; i++)

{ s0 = Y[N - 1][i][0] - D[i]; E += 0.5 * s0 * s0; }

if(E < Em) kEm++; else kEm = 0;

if(kEm >= qtyEm) res = 1;

else

// Проход назад

{

// Расчет ошибок выходного слоя

for(j = 0; j < M; j++)

delta[N - 1][j] = (D[j] - Y[N - 1][j][0]) * Y[N - 1][j][1];

// Расчет ошибок по скрытым слоям

for(k = N - 2; k >= 0; k–)

{ for(i = 0; i < M; i++)

{ delta[k][i] = 0;

for(j = 0; j < M; j++)

delta[k][i] += delta[k + 1][j] * w[k + 1][i][j] * Y[k][i][1]; } }

// Пересчет весов и порогов for(k = 0; k < N; k++) for(i = 0; i < M; i++) for(j = 0; j < M; j++) { w[k][i][j] = w[k][i][j] * (1 + gamma) + alpha * delta[k][j] * Y[k][i][0]; b[k][j] = b[k][j] - alpha * delta[k][j]; } }

return res; }

markata
() автор топика
Ответ на: комментарий от markata

А можете привести пример с вектором на входе размерностью > 1 и с такой же размерностью вектора-учителя? Который бы работал?

Обычно такая архитектура используется в RNN или LST сетях и всяких автоэнкодерах. Это более сложные варианты сетей, попробуйте разобраться сначала с сетями которые «выглядят как воронка», те на выходе гораздо меньше нейронов чем на входе.

Obezyan
()
Ответ на: комментарий от Obezyan

Хорошо!

Только тут надо немного перепрограммировать, а у мне сейчас надо бежать, займусь завтра.

Была у меня мысль насчет воронки, но все пытался обойтись прямоугольником по неопытности!

markata
() автор топика

Как бы для обучения нейросети нужно не одну пару вход-выход ей скормить, а как минимум столько же, сколько в нейросети есть коэффициентов. Это же банальщина - в системе уравнений с N неизвестными должно быть минимум N законченных уравнений чтобы она была решаемой.

Для нейросетки, разумеется, минимальный набор тренировочных данных позволит лишь хоть как-то определить все коэффициенты но это вовсе не значит что после этого нейросеть будет выдавать сколь-нибудь годные данные. Ей нужно скормить на порядки больше данных, чтобы оно как-то что-то стало делать.

Stanson ★★★★★
()
Ответ на: комментарий от Obezyan

Докладываю.

Сделал сеть типа «воронка»: в первом слое N нейронов, в следующем - на 1 меньше и т.д.

В результате наконец-то заработало на простейших задачах, а именно:

  1. Распознает, к какому из нескольких интервалов принадлежит число, само по себе или преобразованное монотонной функцией.

  2. Распознает параболы с разными к-тами при x^2.

Обучаемость моей сети сейчас сильно зависит от ее настроек. Например, от коэффициета при показателе экспоненты в сигма-функции.

Думаю, куда двигаться дальше.


Вообще, я собираюсь решить следующую задачу:

Есть устройство (двигатель), на нем разные датчики (виброускорение, обороты, температуры, …). Все эти данные поступают в компьютер.

Данные, их производные, степени и прочее связаны уравнением. Уравнение решается онлайн относительно своих коэффициеннтов. Все это у меняя уже много лет как налажено, код отлажен до невозможности.

Требуется по найденному набору к-тов уравнения выявить наличие неисправности, точнее - приближения момента наступления неисправности.

Проблема: как для «хороших» механизмов, так и для изношенных, нет строго фиксированных наборов параметров уравнения. Есть некие наборы точек в гиперпространстве, для хороших - свой набор, для плохих - свой. Формализовать это сложно, уже несколько лет строю критерии, они работают, но с ошибками, которые не удовлетворяют эксплуатантов. Ошибка 15% при 20 испытаниях - это для них ужас-ужас, им надо за 1 испытание выявить неисправность с ошибкой 5%.

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

markata
() автор топика
Ответ на: комментарий от anonymous

Вот интересно, заниматься серьёзными делами при этом не осилить разметку для кода на сайте.

Некоторые учёные, шнурки завязывать не умеют.

anonymous
()
Ответ на: комментарий от markata

А я сейчас думаю о том, в какую сторону двигаться, чтобы научиться строить хорошие нейросети.

сначала почитать в энторнетах «neural net for engine diagnostics». не забыв спросить то же самое у чатгпт.

вопрос давно обсосан со всех сторон.

вообще чатгпт(или что-то вроде) про нейронные сети вам расскажет все.

alysnix ★★★
()
Ответ на: комментарий от markata

Думаю, куда двигаться дальше.

  1. Почитайте про эмпирические правила в организации слоев нейронной сети. Сколько слоев делать и какого размера с определенным количеством входных нерйонов.

  2. Почитайте о видах функций активации (линейная, сигмоид, ReLU и тд)

  3. Почитайте зачем разделять набор данных на 3 выборки: обучающую, валидационную и тестовую. Как это делать правильно.

Уравнение решается онлайн относительно своих коэффициеннтов.

В таких случаях переменные обычно нормализуются в интервале 0..1, а выходной слой делают из одного нейрона, также в интервале 0..1, где 0 - например, полностью исправен, 1 - неисправен.

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

Obezyan
()