Como seguimiento a Mi red neuronal ni siquiera puede aprender la distancia euclidiana , simplifiqué aún más y traté de entrenar una única ReLU (con peso aleatorio) en una sola ReLU. Esta es la red más simple que existe y, sin embargo, la mitad del tiempo no logra converger.
Si la suposición inicial está en la misma orientación que el objetivo, aprende rápidamente y converge al peso correcto de 1:
Si la suposición inicial es "al revés", se queda atascado en un peso de cero y nunca pasa a la región de menor pérdida:
No entiendo por qué. ¿No debería el descenso de gradiente seguir fácilmente la curva de pérdida a los mínimos globales?
Código de ejemplo:
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()
Suceden cosas similares si agrego sesgo: la función de pérdida 2D es suave y simple, pero si el relu comienza al revés, da vueltas y se atasca (puntos de inicio rojos), y no sigue el gradiente hacia abajo al mínimo (como hace para puntos de partida azules):
Suceden cosas similares si agrego también el peso de salida y el sesgo. (Se moverá de izquierda a derecha o de abajo hacia arriba, pero no ambas).
Respuestas:
Esto está relacionado con el fenómeno de la muerte relu; para alguna discusión, vea Mi red ReLU no se inicia
Un enfoque que podría ser más exitoso sería utilizar una no linealidad diferente, como la fuga relu, que no tiene el llamado problema del "gradiente de fuga". La función relu permeable es
LeakyReLU
ReLU
El código relevante está debajo; usar
opt_sgd
oopt_adam
.fuente