Не могу обучить модель keras приближаться к простой функции - PullRequest
0 голосов
/ 10 июня 2018

Я только начал заниматься машинным обучением и попытался написать простую программу, в которой nn изучит простую функцию y = f (x) = 2x.

Вот код:

#x is a 1D array of 1 to 1000
x = np.arange(1,1000, 1)
y = x*2

xtrain = x[:750]
ytrain = y[:750]
xtest = x[750:]
ytest = y[750:]

from keras.models import Sequential
from keras.layers import Dense, Dropout, Activation, Flatten, Conv2D

model = Sequential()

model.add(Dense(128, input_dim=1, activation='relu'))

model.add(Dense(1, activation='relu'))

model.compile(loss='mean_squared_error', 
          optimizer='sgd', 
          metrics=['accuracy'])

model.summary()

history = model.fit(xtrain, ytrain, 
                batch_size=100, 
                epochs=20, 
                verbose=1, 
                validation_split=0.2)

Я получаю следующий вывод, независимо от того, как я изменяю архитектуру или гиперпараметры:

79999/79999 [==============================] - 1s 13us/step - loss: 8533120007.8465 - acc: 0.0000e+00 - val_loss: 32532613324.8000 - val_acc: 0.0000e+00

точность всегда равна 0.что я делаю не так?

Ответы [ 2 ]

0 голосов
/ 11 июня 2018

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

  1. Производная, которую SGD использует для обновления весов, на самом деле зависит от входных данных.Возьмем очень простой случай y = f(wx + b), производная от y по w равна f'(wx + b)*x с использованием правила цепочки.Поэтому, когда есть обновление для ввода, которое является чрезвычайно большим / ненормализованным, оно взрывается.Теперь обновление в основном w' = w - alpha*gradient, поэтому вес внезапно становится очень маленьким, фактически отрицательным.
  2. После одного обновления градиента выходной сигнал становится отрицательным, поскольку SGD просто перезагружается.Так как у вас снова есть relu в последнем слое, это просто выводит 0, и обучающие срывы, потому что, когда выходной сигнал является отрицательной производной от relu, равен 0.

Вы можете уменьшить размер данных до np.arange(1, 10) и уменьшите количество скрытых нейронов, скажем до 12 (больше нейронов делают выход еще более отрицательным после однократного обновления, так как все их веса также становятся отрицательными), и вы сможете обучать сеть.

0 голосов
/ 10 июня 2018

Я думаю, что это работает, проверьте это.Я использовал randn вместо arange.В остальном все почти так же.

x = np.random.randn(1000)
y = x*2

xtrain = x[0:750]
ytrain = y[0:750]


model = Sequential()

model.add(Dense(128, input_dim=1, activation='relu'))
model.add(Dense(1))
model.summary()
sgd = optimizers.SGD(lr=0.01, decay=1e-6)
model.compile(loss='mean_squared_error', 
          optimizer=sgd, 
          metrics=['mae'])

history = model.fit(xtrain, ytrain,
                batch_size=100, 
                epochs=20, 
                verbose=1, 
                validation_split=0.2)

Если вы хотите использовать более ранний набор данных (например, arange).Вот сопроводительный код для этого.

x = np.arange(1,1000, 1)
y = x*2

xtrain = x[0:750]
ytrain = y[0:750]


model = Sequential()

model.add(Dense(128, input_dim=1, activation='relu'))
model.add(Dense(1))
model.summary()
sgd = optimizers.Adam(lr=0.0001)
model.compile(loss='mean_squared_error', 
          optimizer=sgd, 
          metrics=['mae'])

history = model.fit(xtrain, ytrain,
                batch_size=100, 
                epochs=200, 
                verbose=1, 
                validation_split=0.2)
...