El gradiente que se desvanece
28 min read
La lección anterior, sobre backpropagation through time (BPTT), cerró con un gradiente exacto y un cabo suelto. Exacto porque el sondeo numérico lo confirmó casilla por casilla; suelto porque la forma de calcularlo repite un mismo gesto sin que nadie mirara sus consecuencias: para arrastrar el error de una posición a la de más atrás hay que multiplicarlo por la matriz recurrente , y en una secuencia de cuarenta tokens ese producto se repite casi cuarenta veces. Esta lección mide qué le hace al gradiente repetir la misma multiplicación tantas veces seguidas, y encuentra que todo se decide en un único número asociado a .
Y no es una curiosidad numérica: en juego está la única razón para preferir una RNN a la red del principio del bloque. Toma una reseña que arranca con Dudo que a alguien le sirva y, treinta palabras más tarde, cierra con su valoración. Ese Dudo inicial invierte el signo de todo lo que viene después, pero la red solo puede aprender esa conexión si el gradiente calculado en la última palabra consigue volver hasta la primera. Si por el camino se apaga, la red jamás registrará que el principio importaba, y la memoria que la definía se quedará, en la práctica, en memoria de lo reciente.
Antes de mirar la matriz entera, quítale coordenadas hasta que quede una sola. Con el estado es un número, es un número , y arrastrar el error un paso hacia atrás es multiplicarlo por . Repetir el paso veces lo multiplica por .
Y no tiene término medio. Si se hunde: con , cuarenta pasos dejan el error en , doce órdenes de magnitud por debajo de donde salió. Si se dispara: . Solo mantiene el error en su tamaño, y es un filo de un solo punto —basta desviarse un pelo para caer a un lado o al otro—. Con más de una coordenada, ese papel de lo hereda una propiedad de la matriz; el explorable la llama radio espectral, y la formalización la define enseguida. Deslízala a un lado y a otro de y verás las dos mitades del fenómeno: por debajo, la curva se desploma; por encima, se va por arriba.
El producto que conecta dos posiciones
Volvamos a la recurrencia hacia atrás de la lección anterior y sigámosla más de un paso. Allí, el error de un paso salía del siguiente con dos gestos —transportar y enmascarar—:
El con la pendiente del es multiplicar por una matriz diagonal —, con esas pendientes en la diagonal y ceros fuera—, así que un paso de la vuelta multiplica por dos matrices: primero , luego esa diagonal. Encadena la recurrencia desde el último paso hasta uno lejano y las dos se repiten, una pareja por posición:
El producto tiene parejas, una por cada paso entre y —la distancia que el error recorre—. Y dentro de cada pareja, la misma que en todas las demás: esto no es una capa distinta por posición, como lo eran los bloques de la primera capa concatenada de la lección sobre por qué el MLP falla con secuencias, sino una sola matriz elevada, en la práctica, a la potencia de la distancia. Ese es el gesto que la lección anterior repetía sin mirarlo.
Por qué decae o explota
Un producto de matrices es difícil de mirar; su tamaño, no. Toma normas a los dos lados y usa que la norma de un producto no supera el producto de las normas:
Los dos factores de cada pareja tienen un techo. El de la diagonal es la pendiente del , que nunca pasa de y en cuanto el estado se satura se acerca a —son las bandas rojas que el explorador de activaciones de la lección sobre funciones de activación ya te dejó ver—; llámalo . El de es el único hecho nuevo que necesitas aquí: una matriz estira la longitud de un vector como mucho por su mayor valor singular , así que multiplicar por ella veces la estira, a lo sumo, por . Junta las dos cotas sobre las parejas:
Ahí está el exponente. El error que llega a la posición es, como mucho, el del final multiplicado por un número elevado a la distancia. Si ese número es menor que , el gradiente se desvanece —cae en picado, y sin remedio, porque solo puede empujarlo más abajo, nunca rescatarlo—. Si es mayor que , explota.
Cuál de los dos lados te toca lo decide una propiedad de : su radio espectral —el mayor de los módulos de sus valores propios—, que marca el ritmo del producto a la larga. Por debajo de el gradiente se hunde, por encima se dispara, y entre las dos cosas no hay más que ese filo. No necesitas calcular valores propios en esta lección; lo único que hace falta es saber que ese número existe, que gobierna el exponente y que es el que el explorable te dejó mover.
Ver por qué el ritmo lo marca el radio espectral y no el valor singular
La cota es un techo, y suele sobrar: un vector concreto rara vez se estira el máximo posible en cada paso, y puede ser bastante mayor que . Lo que sí se cumple a la larga es que tiende al radio espectral cuando crece. Por eso garantiza el desvanecimiento y la explosión, aunque para una distancia corta la cota con vaya por delante del ritmo real.
Verlo y domarlo en NumPy
Dos celdas. La primera reduce todo al caso de una coordenada y mira el exponente crudo; la segunda ataca la mitad del problema que sí tiene un parche barato.
El caso escalar no es un juguete: es la fórmula de arriba con , donde , y son el mismo número. Ejecútala y lee la fila del medio —— contra las otras dos.
# atras lo multiplica por w**d. La mascara del tanh (pendiente <= 1) solo lo
# encoge mas, asi que w = 1 ya es el caso mas favorable.
print(" w d=10 d=20 d=40")
for w in [0.5, 1.0, 1.5]:
print("%.1f %9.2e %9.2e %9.2e" % (w, w ** 10, w ** 20, w ** 40))
La primera ejecución descarga el intérprete de Python (~15 MB). Después queda en la caché del navegador.
La primera fila se hunde, la última se dispara y la del medio no se mueve, tal como decía la intuición. Con el error llega a los cuarenta pasos convertido en de lo que era, y ningún descenso de gradiente aprende de una señal tan pequeña. Y esto es el mejor caso: la máscara del , en cuanto el estado se satura, lo empuja todavía más abajo.
La explosión, en cambio, tiene una respuesta directa. Si el problema es que la norma del gradiente crece sin freno, ponle un techo: fija un umbral y, cuando lo pase, reescala el gradiente para devolverlo justo a ese tamaño. Es el recorte del gradiente (gradient clipping):
El con es la clave: si el gradiente ya es pequeño, el factor vale y no lo toca; solo actúa sobre el que se ha pasado, y lo hace multiplicándolo por un número positivo, que cambia su longitud pero no su dirección. Compruébalo.
rng = np.random.default_rng(1)
theta = 5.0 # el techo que le ponemos a la norma
def recorta(g):
n = np.linalg.norm(g)
return g * min(1.0, theta / n), n # factor <= 1: encoge o deja igual, no gira
for nombre, g in [("normal ", rng.normal(size=100) * 0.3),
("explotado", rng.normal(size=100) * 3.0)]:
g_rec, n = recorta(g)
coseno = float(g @ g_rec) / (n * np.linalg.norm(g_rec))
print("%s ||g|| = %6.2f -> ||recortado|| = %.2f (coseno con g: %.4f)"
% (nombre, n, np.linalg.norm(g_rec), coseno))
La primera ejecución descarga el intérprete de Python (~15 MB). Después queda en la caché del navegador.
El gradiente normal pasa intacto; el explotado, con norma casi , sale recortado a exacto, y el coseno con el original es —misma dirección, otro tamaño—. El recorte salva el entrenamiento cuando el gradiente explota y no cuesta casi nada. Lo que no hace —y conviene decirlo en voz alta— es nada por el desvanecimiento: un gradiente que ya llegó valiendo tiene norma minúscula, el vale , y se queda como estaba.
Comprueba tu intuición
Cinco preguntas: qué desvanece o explota el gradiente, qué arregla el recorte y qué no, cómo se ve el exponente en un número, si la máscara del puede salvar la situación y qué se pierde cuando no.
¿Qué hace que el gradiente de una RNN se desvanezca o explote al retroceder por una secuencia larga?
El recorte del gradiente reescala cuando su norma pasa de un umbral . ¿Qué problema resuelve y cuál no?
El caso de una sola coordenada: es un número , y a distancia el error se ha multiplicado por . ¿Qué imprime?
w = 0.5
for d in [0, 4, 8]:
print(round(w ** d, 4))
La máscara que aparece en cada paso de la vuelta es la pendiente del . ¿Puede rescatar un gradiente que se desvanece?
¿Qué pierde una RNN cuando el gradiente que conecta el final de la secuencia con el principio se ha desvanecido?
El recorte le pone un techo a la explosión, pero deja el otro lado del problema donde estaba. Un gradiente que se ha multiplicado camino a cero no se recupera multiplicándolo por , y ninguna elección de arregla las dos cosas a la vez: bajar su radio espectral para no explotar es justo lo que garantiza el desvanecimiento. El problema no está en los pesos, sino en el camino —cualquier ruta que multiplique por la misma matriz en cada paso acaba en uno de los dos extremos—.
La salida es cambiar el camino. Hace falta una vía por la que el estado avance de un paso al siguiente sumando, en lugar de volver a pasar por : sobre una suma el gradiente fluye sin multiplicarse una vez por posición, y así ni se hunde ni se dispara. Esa vía aditiva es el estado de celda de la LSTM (long short-term memory), y construirla —una compuerta cada vez, cada una arreglando un fallo concreto de la RNN vanilla— es la siguiente lección, sobre la LSTM: memoria con compuertas.
Further reading2 sources · 1 paper, 1 book
Where this lesson comes from, and where to go next. None of it is needed to carry on with the course.
- On the difficulty of training Recurrent Neural Networks
De aquí salen las dos piezas de la lección: el radio espectral de W_hh como frontera entre desvanecerse y explotar, y el recorte que limita la norma del gradiente a un umbral θ. Lo justifica con más aparato; las compuertas no las toca.
- Gradient Flow in Recurrent Nets: the Difficulty of Learning Long-Term Dependencies
Su §2 demuestra lo que aquí ves en una gráfica: el error que retrocede por la secuencia decae o crece de forma exponencial en el número de pasos. Reúne las pruebas de 1991 y 1994; se queda en el diagnóstico, sin proponer arreglo.