Keras: простая нейронная сеть с простыми данными не работает

Aug 20 2020

Я пытаюсь создать очень простую нейронную сеть: один скрытый слой с двумя нейронами. Для очень простых данных: только одна функция.

import numpy as np
X=np.concatenate([np.linspace(0,10,100),np.linspace(11,20,100),np.linspace(21,30,100)])
y=np.concatenate([np.repeat(0,100),np.repeat(1,100),np.repeat(0,100)])

Вот модель

from keras.models import Sequential
from keras.layers import Dense
model = Sequential()
model.add(Dense(2, activation='sigmoid'))
model.add(Dense(1, activation='sigmoid'))
model.compile(loss='binary_crossentropy', optimizer='sgd', metrics=['accuracy'])
model.fit(X, y, epochs=200)

По идее, эта модель должна работать. Но даже после 1000 эпох точность все еще составляет 0,667.

Epoch 999/1000
10/10 [==============================] - 0s 1ms/step - loss: 0.5567 - accuracy: 0.6667
Epoch 1000/1000
10/10 [==============================] - 0s 2ms/step - loss: 0.5566 - accuracy: 0.6667

Я думаю, что я что-то не так сделал. Не могли бы вы предложить некоторые модификации?

Похоже, что там много локальных минимумов и инициализация может изменить итоговую модель. Это тот случай, когда при тестировании с пакетом nnetв R. Мне пришлось тестировать много семян, я нашел эту модель (среди прочих).

И это структура, которую я хотел создать с помощью keras: один скрытый слой с 2 ​​нейронами. Функция активации - сигмовидная.

Поэтому мне интересно, есть ли у keras такая же проблема с инициализацией. С этим пакетом nnetв R я подумал, что это не «идеальный» пакет. И я подумал, что керас будет более производительным. Если инициализация важна, проверяет ли keras другую инициализацию? Если не почему? Может быть, потому что в целом с большим количеством данных (и большего количества функций) он работает лучше (без тестирования множества инициализаций)?

Например, с kmeans вроде тестируются разные инициализации.

Ответы

3 Mitiku Aug 26 2020 at 16:19

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

Я хочу начать с визуализации набора данных. Набор данных является одномерным, и после его нормализации с помощью стандартной нормализации он выглядит следующим образом.

X_original = np.concatenate([np.linspace(0, 10, 100), np.linspace(
11, 20, 100), np.linspace(21, 30, 100)])
X = (X_original - X_original.mean())/X_original.std()

y = np.concatenate(
        [np.repeat(0, 100), np.repeat(1, 100), np.repeat(0, 100)])
plt.figure()
plt.scatter(X, np.zeros(X.shape[0]), c=y)
plt.show()

Лучший способ разделить эти точки данных на соответствующие классы - нарисовать две линии во входном пространстве. Поскольку входное пространство одномерное, границы классификации - это всего лишь одномерные точки.

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

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

model = Sequential()
model.add(Dense(2, activation='sigmoid'))
model.add(Dense(1, activation='sigmoid'))
model.compile(loss='binary_crossentropy',
                  optimizer=keras.optimizers.Adam(1e-1), metrics=['accuracy'])
model.fit(X, y, epochs=20)

Train on 300 samples
Epoch 1/20
300/300 [==============================] - 1s 2ms/sample - loss: 0.6455 - accuracy: 0.6467
Epoch 2/20
300/300 [==============================] - 0s 79us/sample - loss: 0.6493 - accuracy: 0.6667
Epoch 3/20
300/300 [==============================] - 0s 85us/sample - loss: 0.6397 - accuracy: 0.6667
Epoch 4/20
300/300 [==============================] - 0s 100us/sample - loss: 0.6362 - accuracy: 0.6667
Epoch 5/20
300/300 [==============================] - 0s 115us/sample - loss: 0.6342 - accuracy: 0.6667
Epoch 6/20
300/300 [==============================] - 0s 96us/sample - loss: 0.6317 - accuracy: 0.6667
Epoch 7/20
300/300 [==============================] - 0s 93us/sample - loss: 0.6110 - accuracy: 0.6667
Epoch 8/20
300/300 [==============================] - 0s 110us/sample - loss: 0.5746 - accuracy: 0.6667
Epoch 9/20
300/300 [==============================] - 0s 142us/sample - loss: 0.5103 - accuracy: 0.6900
Epoch 10/20
300/300 [==============================] - 0s 124us/sample - loss: 0.4207 - accuracy: 0.9367
Epoch 11/20
300/300 [==============================] - 0s 124us/sample - loss: 0.3283 - accuracy: 0.9833
Epoch 12/20
300/300 [==============================] - 0s 124us/sample - loss: 0.2553 - accuracy: 0.9800
Epoch 13/20
300/300 [==============================] - 0s 138us/sample - loss: 0.2030 - accuracy: 1.0000
Epoch 14/20
300/300 [==============================] - 0s 124us/sample - loss: 0.1624 - accuracy: 1.0000
Epoch 15/20
300/300 [==============================] - 0s 150us/sample - loss: 0.1375 - accuracy: 1.0000
Epoch 16/20
300/300 [==============================] - 0s 122us/sample - loss: 0.1161 - accuracy: 1.0000
Epoch 17/20
300/300 [==============================] - 0s 115us/sample - loss: 0.1025 - accuracy: 1.0000
Epoch 18/20
300/300 [==============================] - 0s 126us/sample - loss: 0.0893 - accuracy: 1.0000
Epoch 19/20
300/300 [==============================] - 0s 121us/sample - loss: 0.0804 - accuracy: 1.0000
Epoch 20/20
300/300 [==============================] - 0s 132us/sample - loss: 0.0720 - accuracy: 1.0000

Поскольку модель очень проста, выбор скорости обучения и оптимизатора влияет на скорость обучения. С оптимизатором SGD и скоростью обучения 1e-1 обучение модели может занять больше времени, чем оптимизатору Adam с такой же скоростью обучения.