Comme suivi de Mon réseau de neurones ne peut même pas apprendre la distance euclidienne, j'ai encore simplifié et essayé de former un seul ReLU (avec un poids aléatoire) à un seul ReLU. Il s'agit du réseau le plus simple qui existe et pourtant, la moitié du temps, il ne parvient pas à converger.
Si la supposition initiale est dans la même orientation que la cible, elle apprend rapidement et converge vers le poids correct de 1:
Si la supposition initiale est "à l'envers", elle reste bloquée à un poids de zéro et ne la traverse jamais jusqu'à la région de perte la plus faible:
Je ne comprends pas pourquoi. La descente de gradient ne devrait-elle pas suivre facilement la courbe de perte jusqu'aux minima globaux?
Exemple de code:
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()
Des choses similaires se produisent si j'ajoute un biais: la fonction de perte 2D est lisse et simple, mais si la relu démarre à l'envers, elle tourne autour et se coince (points de départ rouges), et ne suit pas le gradient au minimum (comme ça fait pour les points de départ bleus):
Des choses similaires se produisent si j'ajoute également le poids et le biais de sortie. (Il basculera de gauche à droite ou de bas en haut, mais pas les deux.)
Réponses:
Ceci est lié au phénomène relu mourant; pour une discussion, voir Mon réseau ReLU ne parvient pas à se lancer
Une approche qui pourrait être plus efficace consisterait à utiliser une non-linéarité différente telle que la relu qui fuit, qui n'a pas le problème dit de "gradient de fuite". La fonction relu qui fuit est
LeakyReLU
ReLU
D'un autre côté, si vous changez l'initialisation enw(0)=−1 w(0)=−1 w(0)=−1
Le code correspondant est ci-dessous; utiliser
opt_sgd
ouopt_adam
.la source