В качестве продолжения Моей нейронной сети не могу даже изучить евклидово расстояние, я упростил еще больше и попытался обучить один ReLU (со случайным весом) одному ReLU. Это самая простая сеть, которая существует, и все же половину времени она не может сходиться.
Если исходное предположение имеет ту же ориентацию, что и цель, оно быстро учится и сходится к правильному весу 1:
Если первоначальное предположение «назад», оно застревает с нулевым весом и никогда не попадает в область с меньшими потерями:
Я не понимаю почему. Разве градиентный спуск не должен легко следовать кривой потерь к глобальным минимумам?
Пример кода:
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, ReLU
from tensorflow import keras
import numpy as np
import matplotlib.pyplot as plt
batch = 1000
def tests():
while True:
test = np.random.randn(batch)
# Generate ReLU test case
X = test
Y = test.copy()
Y[Y < 0] = 0
yield X, Y
model = Sequential([Dense(1, input_dim=1, activation=None, use_bias=False)])
model.add(ReLU())
model.set_weights([[[-10]]])
model.compile(loss='mean_squared_error', optimizer='sgd')
class LossHistory(keras.callbacks.Callback):
def on_train_begin(self, logs={}):
self.losses = []
self.weights = []
self.n = 0
self.n += 1
def on_epoch_end(self, batch, logs={}):
self.losses.append(logs.get('loss'))
w = model.get_weights()
self.weights.append([x.flatten()[0] for x in w])
self.n += 1
history = LossHistory()
model.fit_generator(tests(), steps_per_epoch=100, epochs=20,
callbacks=[history])
fig, (ax1, ax2) = plt.subplots(2, 1, True, num='Learning')
ax1.set_title('ReLU learning ReLU')
ax1.semilogy(history.losses)
ax1.set_ylabel('Loss')
ax1.grid(True, which="both")
ax1.margins(0, 0.05)
ax2.plot(history.weights)
ax2.set_ylabel('Weight')
ax2.set_xlabel('Epoch')
ax2.grid(True, which="both")
ax2.margins(0, 0.05)
plt.tight_layout()
plt.show()
Подобные вещи случаются, если я добавляю смещение: функция двухмерных потерь является плавной и простой, но если откат начинается вверх ногами, он вращается вокруг и застревает (красные начальные точки), и не следует градиенту до минимума (как это делает для синих стартовых точек):
Подобные вещи случаются, если я добавлю выходной вес и смещение тоже. (Он будет переворачиваться слева направо или снизу вверх, но не одновременно.)