Не может приблизиться к простой функции умножения в нейронной сети с 1 скрытым слоем

Я просто хотел проверить, насколько хорошо нейронная сеть может приблизиться к функции умножения (задача регрессии). Я использую Azure Studio для машинного обучения. У меня 6500 образцов, 1 скрытый слой (я тестировал 5 /30 /100 нейронов на скрытый слой), без нормализации. И параметры по умолчанию Скорость обучения - 0,005, Количество итераций обучения - 200, Начальный вес обучения - 0,1, Импульс - 0 [описание]. Я получил очень плохую точность, близкую к 0.В то же время усиленная лесная регрессия решений показывает очень хорошее приближение.

Что я делаю неправильно? Эта задача должна быть очень простой для NN.

4 ответа

Решение

Большой градиент функции умножения переводит сеть, вероятно, почти сразу в ужасающее состояние, где все ее скрытые узлы имеют нулевой градиент. Мы можем использовать два подхода:

1) Разделить на постоянное. Мы просто делим все до обучения и размножаемся после.

2) Сделайте лог-нормализацию. Это делает умножение в дополнение:

m = x*y => ln(m) = ln(x) + ln(y).

Вот как я делаю умножение с помощью нейронной сети:

import numpy as np
from keras import layers
from keras import models

model = models.Sequential()
model.add(layers.Dense(150, activation='relu', input_shape=(2,)))
model.add(layers.Dense(1, activation='relu'))

data = np.random.random((10000, 2))
results = np.asarray([a * b for a, b in data])
model.compile(optimizer='sgd', loss='mae')

model.fit(data, results, epochs=1, batch_size=1)
model.predict([[0.8, 0.5]])

Оно работает.

Некоторые вещи, чтобы проверить:

  1. Ваш выходной слой должен иметь линейную функцию активации. Если он сигмоидальный, он не сможет представлять значения за пределами своего диапазона (например, от -1 до 1)
  2. Вы должны использовать функцию потерь, которая подходит для регрессии (например, квадрат ошибки)
  3. Если ваш скрытый слой использует сигмоидальные функции активации, убедитесь, что вы не насыщаете их. Умножение может работать на сколь угодно малых / больших значениях. И, если вы передадите большое число в качестве входных данных, вы можете получить насыщение, что приведет к потере информации. При использовании ReLU убедитесь, что они не застряли на 0 во всех примерах (хотя в любом конкретном примере активации обычно будут редкими).
  4. Убедитесь, что ваша учебная процедура работает так, как задумано. Составьте график ошибки во времени во время тренировки. Как это выглядит? Ваши градиенты хорошо себя ведут или они взрываются? Одним из источников проблем может быть слишком высокая скорость обучения (нестабильная ошибка, взрывные градиенты) или слишком низкая (очень медленный прогресс, ошибка не уменьшается достаточно быстро).

"Два подхода: разделить на константу или сделать нормализацию журнала"

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

Подход с журналом хорош, но если у вас есть два набора данных с набором входных данных и целевым значением y, где:

  • В первом наборе данных целью является сумма двух входных данных.

  • В наборе данных два цель является последовательно произведением двух входных данных.

Тогда мне не ясно, как спроектировать нейронную сеть, которая найдет цель y в обоих наборах данных, используя обратное распространение. Если это невозможно, то я нахожу это удивительным ограничением в способности нейронной сети находить "приближение к любой функции". Но я новичок в этой игре, и мои ожидания могут быть нереальными.

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

m = x*y => ln(m) = ln(x) + ln(y), но только если x, y > 0