Documentos de Académico
Documentos de Profesional
Documentos de Cultura
com
CAPÍTULO 11
Con los libros electrónicos Early Release, obtiene libros en su forma más
temprana, el contenido sin editar y sin editar del autor mientras escribe,
para que pueda aprovechar estas tecnologías mucho antes del
lanzamiento oficial de estos títulos. El siguiente será el Capítulo 11 en la
versión final del libro.
• En segundo lugar, es posible que no tenga suficientes datos de entrenamiento para una red tan grande o que sea
demasiado costoso etiquetarlos.
• Cuarto, un modelo con millones de parámetros correría el grave riesgo de sobreajustar el conjunto de
entrenamiento, especialmente si no hay suficientes instancias de entrenamiento o si son demasiado
ruidosas.
En este capítulo, analizaremos cada uno de estos problemas y presentaremos técnicas para resolverlos.
Comenzaremos explicando el problema de los gradientes que se desvanecen y explorando algunas de las
soluciones más populares para este problema. A continuación, veremos el aprendizaje de transferencia y la
capacitación previa no supervisada, que pueden ayudarlo a abordar situaciones complejas.
325
tareas incluso cuando tiene pocos datos etiquetados. Luego, analizaremos varios optimizadores que pueden
acelerar enormemente el entrenamiento de modelos grandes en comparación con el descenso de gradiente
simple. Finalmente, veremos algunas técnicas de regularización populares para redes neuronales grandes.
Con estas herramientas podrás entrenar redes muy profundas: ¡bienvenido a Deep Learning!
Desafortunadamente, los gradientes a menudo se vuelven más y más pequeños a medida que el algoritmo
avanza hacia las capas inferiores. Como resultado, la actualización de Gradient Descent deja los pesos de
conexión de la capa inferior prácticamente sin cambios y el entrenamiento nunca converge en una buena
solución. Esto se llama elGradientes que se desvanecenproblema. En algunos casos, puede suceder lo
contrario: los gradientes pueden crecer más y más, por lo que muchas capas obtienen actualizaciones de
peso increíblemente grandes y el algoritmo diverge. Este es elgradientes explosivosproblema, que se
encuentra principalmente en redes neuronales recurrentes (ver???). De manera más general, las redes
neuronales profundas sufren gradientes inestables; diferentes capas pueden aprender a velocidades muy
diferentes.
1 "Comprender la dificultad de entrenar redes neuronales de alimentación directa profunda", X. Glorot, Y Bengio (2010).
Inicialización de Glorot y He
En su artículo, Glorot y Bengio proponen una forma de aliviar significativamente este problema.
Necesitamos que la señal fluya correctamente en ambas direcciones: en la dirección de avance
cuando se hacen predicciones, y en la dirección de retroceso cuando se propagan gradientes
hacia atrás. No queremos que la señal se apague, ni queremos que explote y se sature. Para
que la señal fluya correctamente, los autores argumentan que necesitamos que la varianza de
las salidas de cada capa sea igual a la varianza de sus entradas,2y también necesitamos que los
gradientes tengan la misma variación antes y después de fluir a través de una capa en la
dirección inversa (consulte el documento si está interesado en los detalles matemáticos). En
realidad, no es posible garantizar ambos a menos que la capa tenga el mismo número de
entradas y neuronas (estos números se denominanfan-inydesplieguede la capa), pero
propusieron un buen compromiso que ha demostrado funcionar muy bien en la práctica: los
pesos de conexión de cada capa deben inicializarse aleatoriamente como
2 He aquí una analogía: si coloca la perilla de un amplificador de micrófono demasiado cerca de cero, las personas no escucharán su voz, pero
si lo configura demasiado cerca del máximo, su voz se saturará y la gente no entenderá lo que está diciendo.
Ahora imagine una cadena de tales amplificadores: todos deben configurarse correctamente para que su voz se
escuche alta y clara al final de la cadena. Tu voz tiene que salir de cada amplificador con la misma amplitud con la
que entró.
1
Distribución normal con media 0 y varianzaσ2=
fanavg
3
O una distribución uniforme entre −ry +r, conr=
fanavg
3 Como "Profundizando en los rectificadores: superando el rendimiento a nivel humano en la clasificación de ImageNet", K.
Él et al. (2015).
he_avg_init=queras.inicializadores.Escalado de varianza(escala=2.,modo='fan_avg',
distribución='uniforme')
queras.capas.Denso(10,activación="sigmoideo",kernel_initializer=he_avg_init)
Para resolver este problema, es posible que desee utilizar una variante de la función ReLU, como la
ReLU con fugas. Esta función se define como LeakyReLUα(z) = máx(az,z) (ver Figura 11-2). El
hiperparámetroαdefine cuánto “pierde” la función: es la pendiente de la función paraz<0, y
normalmente se establece en 0,01. Esta pequeña pendiente asegura que los ReLU con fugas nunca
mueran; pueden entrar en un coma prolongado, pero tienen la oportunidad de despertarse
eventualmente. Apapel de 20155comparó varias variantes de la función de activación de ReLU y una de
sus conclusiones fue que las variantes con fugas siempre superaron la estricta función de activación
de ReLU. De hecho, establecerα= 0.2 (gran fuga) parecía dar como resultado un mejor rendimiento
queα= 0,01 (pequeña fuga). También evaluaron la ReLU aleatorio con fugas(RReLU), dondeαse elige al
azar en un rango determinado durante el entrenamiento y se fija en un valor promedio durante la
prueba. También se desempeñó bastante bien y pareció actuar como un regularizador (reduciendo el
riesgo de sobreajustar el conjunto de entrenamiento).
4 A menos que sea parte de la primera capa oculta, una neurona muerta a veces puede volver a la vida: descenso de gradiente
de hecho, puede modificar las neuronas en las capas inferiores de tal manera que la suma ponderada de las entradas de la neurona muerta
Por último, pero no menos importante, unpapel de 2015por Djork-Arné Clevert et al.6propuso una
nueva función de activación llamadaunidad lineal exponencial(ELU) que superó a todas las variantes
de ReLU en sus experimentos: el tiempo de entrenamiento se redujo y la red neuronal se desempeñó
mejor en el conjunto de prueba. se representa enFigura 11-3, yEcuación 11-2 muestra su definición.
αExpz−1 siz<0 z
ELUαz=
siz≥ 0
6 “Aprendizaje de red profundo rápido y preciso mediante unidades lineales exponenciales (ELU)”, D. Clevert, T. Unterthiner,
S. Hochreiter (2015).
• Primero toma valores negativos cuandoz<0, lo que permite que la unidad tenga una salida
promedio más cercana a 0. Esto ayuda a aliviar el problema de los gradientes que se desvanecen,
como se discutió anteriormente. El hiperparámetroαdefine el valor al que se aproxima la función
ELU cuandozes un gran número negativo. Por lo general, se establece en 1, pero puede
modificarlo como cualquier otro hiperparámetro si lo desea.
• Segundo, tiene un gradiente distinto de cero paraz<0, lo que evita el problema de las neuronas muertas.
• Tercero, siαes igual a 1, entonces la función es suave en todas partes, incluso alrededorz=0,
lo que ayuda a acelerar el descenso de gradiente, ya que no rebota tanto a la izquierda
como a la derecha dez=0.
El principal inconveniente de la función de activación ELU es que es más lenta de calcular que
ReLU y sus variantes (debido al uso de la función exponencial), pero durante el entrenamiento
esto se compensa con una tasa de convergencia más rápida. Sin embargo, en el momento de la
prueba, una red ELU será más lenta que una red ReLU.
• Las características de entrada deben estar estandarizadas (media 0 y desviación estándar 1).
• Los pesos de cada capa oculta también deben inicializarse utilizando la inicialización normal de LeCun.
zación En Keras, esto significa establecerkernel_initializer="lecun_normal".
• La arquitectura de la red debe ser secuencial. Desafortunadamente, si intenta usar
SELU en arquitecturas no secuenciales, como redes recurrentes (ver???) o redes con
omitir conexiones(es decir, conexiones que saltan capas, como en redes anchas y
profundas), no se garantizará la autonormalización, por lo que SELU no
necesariamente superará otras funciones de activación.
• El papel solo garantiza la autonormalización si todas las capas son densas. Sin embargo, en la
práctica, la función de activación SELU parece funcionar muy bien también con redes neuronales
convolucionales (vercapitulo 14).
Entonces, ¿qué función de activación debería usar para las capas ocultas
de sus redes neuronales profundas? Aunque su kilometraje variará, en
general SELU> ELU> ReLU con fugas (y sus variantes)> ReLU> tanh
> logística. Si la arquitectura de la red evita que se autonormalice,
entonces ELU puede funcionar mejor que SELU (ya que SELU no es fluido
enz=0). Si le importa mucho la latencia del tiempo de ejecución, es posible
que prefiera ReLU con fugas. Si no desea modificar otro hiperparámetro,
puede usar el valor predeterminadoαvalores utilizados por Keras (p. ej.,
0,3 para ReLU con fugas). Si tiene tiempo libre y poder de cómputo,
puede usar la validación cruzada para evaluar otras funciones de
activación, en particular RReLU si su red está sobreajustada, o PReLU si
tiene un gran conjunto de entrenamiento.
Para usar la función de activación de ReLU con fugas, debe crear unaLeakyReLUinstancia como esta:
gotera_relu=queras.capas.LeakyReLU(alfa=0.2) capa=queras
.capas.Denso(10,activación=gotera_relu,
kernel_initializer="él_normal")
Aunque el uso de la inicialización de He junto con ELU (o cualquier variante de ReLU) puede reducir
significativamente los problemas de gradientes de desaparición/explosión al comienzo del
entrenamiento, no garantiza que no vuelvan a aparecer durante el entrenamiento.
en unpapel de 2015,8Sergey Ioffe y Christian Szegedy propusieron una técnica llamada Normalización
por lotes(BN) para abordar los problemas de gradientes de desaparición/explosión. La técnica consiste
en agregar una operación en el modelo justo antes o después de la función de activación de cada capa
oculta, simplemente centrando en cero y normalizando cada entrada, luego escalando y cambiando el
resultado usando dos nuevos vectores de parámetros por capa: uno para escalar, el otro para
cambiar. En otras palabras, esta operación permite que el modelo aprenda la escala y la media
óptimas de cada una de las entradas de la capa. En muchos casos, si agrega una capa BN como la
primera capa de su red neuronal, no necesita estandarizar su conjunto de entrenamiento (por
ejemplo, usando unescalador estándar):la capa BN lo hará por usted (bueno, aproximadamente, ya
que solo mira un lote a la vez, y también puede cambiar la escala y cambiar cada función de entrada).
Para centrar en cero y normalizar las entradas, el algoritmo necesita estimar la media
y la desviación estándar de cada entrada. Lo hace evaluando la media y la desviación
estándar de cada entrada sobre el mini lote actual (de ahí el nombre de
“normalización de lotes”). Toda la operación se resume enEcuación 11-3.
1
megabyte
1. mB= ∑Xi
B yo=1
metro
B
metro
1 2
2. σB2 = ∑ X i − mB
metroB yo=1
Xi−m B
3. Xi =
σB2 + �
4. zi =γ⊗Xi+β
8 “Normalización por lotes: Aceleración del entrenamiento profundo de redes mediante la reducción del cambio interno de covariables”, S. Ioffe
y C. Szegedy (2015).
• γes el vector de parámetros de escala de salida para la capa (contiene un parámetro de escala
por entrada).
• βes el vector de parámetro de desplazamiento (desplazamiento) de salida para la capa (contiene un parámetro de
desplazamiento por entrada). Cada entrada se compensa con su parámetro de desplazamiento correspondiente.
• ϵes un número pequeño para evitar la división por cero (típicamente 10–5). Esto se llama un
término de suavizado.
Entonces, durante el entrenamiento, BN simplemente estandariza sus entradas, luego las vuelve a
escalar y las compensa. ¡Bueno! ¿Qué pasa en el momento de la prueba? Bueno, no es tan simple. De
hecho, es posible que necesitemos hacer predicciones para instancias individuales en lugar de lotes de
instancias: en este caso, no tendremos forma de calcular la media y la desviación estándar de cada
entrada. Además, incluso si tenemos un lote de instancias, puede ser demasiado pequeño, o las
instancias pueden no ser independientes e idénticamente distribuidas (IID), por lo que calcular
estadísticas sobre las instancias del lote no sería confiable (durante el entrenamiento, los lotes no
debe ser demasiado pequeño, si es posible más de 30 instancias, y todas las instancias deben ser IID,
como vimos enCapítulo 4). Una solución podría ser esperar hasta el final del entrenamiento, luego
ejecutar todo el conjunto de entrenamiento a través de la red neuronal y calcular la media y la
desviación estándar de cada entrada de la capa BN. Estas medias de entrada y desviaciones estándar
"finales" se pueden usar en lugar de las medias y desviaciones estándar de entrada por lotes al hacer
predicciones. Sin embargo, a menudo se prefiere estimar estas estadísticas finales durante el
entrenamiento utilizando un promedio móvil de las medias de entrada y las desviaciones estándar de
la capa. En resumen, se aprenden cuatro vectores de parámetros en cada capa normalizada por lotes:
γ(el vector de escala de salida) yβ(el vector de compensación de salida) se aprenden a través de la
retropropagación regular, ym(el vector medio de entrada final), yσ(el vector de desviación estándar de
entrada final) se estiman utilizando un promedio móvil exponencial. Tenga en cuenta quemyσse
estiman durante el entrenamiento, pero no se usan en absoluto durante el entrenamiento, solo
después del entrenamiento (para reemplazar las medias de entrada por lotes y las desviaciones
estándar en Ecuación 11-3).
Los autores demostraron que esta técnica mejoró considerablemente todas las redes neuronales
profundas con las que experimentaron, lo que llevó a una gran mejora en la tarea de clasificación de
ImageNet (ImageNet es una gran base de datos de imágenes clasificadas en muchas clases y
comúnmente utilizada para evaluar sistemas de visión por computadora). la desaparición-
Sin embargo, la normalización por lotes agrega algo de complejidad al modelo (aunque puede
eliminar la necesidad de normalizar los datos de entrada, como discutimos anteriormente). Además,
existe una penalización de tiempo de ejecución: la red neuronal hace predicciones más lentas debido a
los cálculos adicionales requeridos en cada capa. Entonces, si necesita que las predicciones sean
ultrarrápidas, es posible que desee verificar qué tan bien funciona la inicialización simple de ELU + He
antes de jugar con la normalización por lotes.
Puede encontrar que el entrenamiento es bastante lento, porque cada época toma
mucho más tiempo cuando usa la normalización por lotes. Sin embargo, esto suele
verse contrarrestado por el hecho de que la convergencia es mucho más rápida con
BN, por lo que se necesitarán menos épocas para alcanzar el mismo rendimiento.
Considerándolo todo,tiempo de paredgeneralmente será más pequeño (este es el
tiempo medido por el reloj en su pared).
Como ocurre con la mayoría de las cosas con Keras, implementar la normalización por lotes es
bastante simple. Solo agrega unNormalización por lotescapa antes o después de la función de
activación de cada capa oculta y, opcionalmente, agregue una capa BN, así como la primera capa en
su modelo. Por ejemplo, este modelo aplica BN después de cada capa oculta y como la primera capa
del modelo (después de aplanar las imágenes de entrada):
modelo=queras.modelos.Secuencial([
queras.capas.Aplanar(entrada_forma=[28,28]),
queras.capas.Normalización por lotes(),
queras.capas.Denso(300,activación="elú",kernel_initializer="él_normal"), queras.
capas.Normalización por lotes(),
queras.capas.Denso(100,activación="elú",kernel_initializer="él_normal"), queras.
capas.Normalización por lotes(), queras.capas.Denso(10,activación="softmax")
])
Hagamos un poco de zoom. Si muestra el resumen del modelo, puede ver que cada capa
BN agrega 4 parámetros por entrada:γ,β,myσ(por ejemplo, la primera capa BN agrega
3136 parámetros, que es 4 veces 784). Los dos últimos parámetros,myσ, son los
promedios móviles, no se ven afectados por la retropropagación, por lo que Keras los
llama "No entrenables".9(si cuenta el número total de parámetros BN, 3136 + 1200 + 400, y
lo divide por dos, obtiene 2368, que es el número total de parámetros no entrenables en
este modelo).
==================================================
=============== flatten_3 (Aplanar)
(Ninguno, 784) 0
_________________________________________________________________
lote_normalización_v2 (Batc (Ninguno, 784) 3136
________________________________________________________________ denso_50
(Denso) (Ninguno, 300) 235500
_________________________________________________________________
lote_normalización_v2_1 (Ba (Ninguno, 300) 1200
________________________________________________________________ denso_51
(Denso) (Ninguno, 100) 30100
_________________________________________________________________
lote_normalización_v2_2 (Ba (Ninguno, 100) 400
________________________________________________________________ denso_52
(Denso) (Ninguno, 10) 1010
================================================== ===============
Parámetros totales: 271,346
Parámetros entrenables: 268,978
Parámetros no entrenables: 2,368
Veamos los parámetros de la primera capa BN. Dos son entrenables (por backprop), y dos
no lo son:
Ahora, cuando crea una capa BN en Keras, también crea dos operaciones que serán llamadas
por Keras en cada iteración durante el entrenamiento. Estas operaciones actualizarán el
9 Sin embargo, se estiman durante el entrenamiento, en función de los datos de entrenamiento, por lo que podría decirse quesonentrenable. En
Los autores del artículo de BN argumentaron a favor de agregar las capas de BN antes de las
funciones de activación, en lugar de después (como acabamos de hacer). Existe cierto debate sobre
esto, ya que parece depender de la tarea. Así que esa es una cosa más con la que puede experimentar
para ver qué opción funciona mejor en su conjunto de datos. Para agregar las capas BN antes de las
funciones de activación, debemos eliminar la función de activación de las capas ocultas y agregarlas
como capas separadas después de las capas BN. Además, dado que una capa de normalización por
lotes incluye un parámetro de compensación por entrada, puede eliminar el término de sesgo de la
capa anterior (simplemente paseuse_bias=Falsoal crearlo):
modelo=queras.modelos.Secuencial([
queras.capas.Aplanar(entrada_forma=[28,28]),
queras.capas.Normalización por lotes(),
queras.capas.Denso(300,kernel_initializer="él_normal",use_bias=Falso), queras.
capas.Normalización por lotes(), queras.capas.Activación("elú"),
queras.capas.Denso(100,kernel_initializer="él_normal",use_bias=Falso), queras.
capas.Activación("elú"), queras.capas.Normalización por lotes(), queras.capas.
Denso(10,activación="softmax")
])
losNormalización por lotesLa clase tiene bastantes hiperparámetros que puede modificar. Por lo
general, los valores predeterminados estarán bien, pero es posible que de vez en cuando necesite
modificar elimpulso. Este hiperparámetro se utiliza al actualizar las medias móviles exponenciales:
dado un nuevo valorv(es decir, un nuevo vector de medias de entrada o desviaciones estándar
calculadas sobre el lote actual), el promedio móvil�se actualiza usando la siguiente ecuación:
Un buen valor de impulso suele ser cercano a 1, por ejemplo, 0,9, 0,99 o 0,999 (quiere más 9
para conjuntos de datos más grandes y minilotes más pequeños).
Otro hiperparámetro importante eseje:determina qué eje debe normalizarse. El valor predeterminado
es -1, lo que significa que, de manera predeterminada, normalizará el último eje (usando las medias y
las desviaciones estándar calculadas en elotroejes). Por ejemplo, cuando el lote de entrada es 2D (es
decir, la forma del lote es [tamaño del lote, características]), esto significa que cada característica de
entrada se normalizará en función de la media y la desviación estándar calculadas en todas las
instancias del lote. Por ejemplo, la primera capa BN en el ejemplo de código anterior normalizará (y
cambiará de escala y desplazará) de forma independiente cada una de las 784 características de
entrada. Sin embargo, si movemos la primera capa BN antes de laAplanar
sicapacitaciónesNinguna:
capacitación=queras.back-end.fase_de_aprendizaje()
[...]
losllamar()El método es el que realmente realiza los cálculos y, como puede ver, tiene un extra
capacitaciónargumento: si esNingunavuelve a caerkeras.backend.fase_de_aprendizaje(),que
regresa1durante el entrenamiento (eladaptar()el método lo asegura). De lo contrario, vuelve0.Si
alguna vez necesita escribir una capa personalizada y debe comportarse de manera diferente
durante el entrenamiento y la prueba, simplemente use el mismo patrón (hablaremos sobre las
capas personalizadas enCapítulo 12).
La normalización por lotes se ha convertido en una de las capas más utilizadas en las redes
neuronales profundas, hasta el punto de que a menudo se omite en los diagramas, ya que se supone
que se agrega BN después de cada capa. Sin embargo, una muy recientepapel10por Hongyi Zhang et
al. bien puede cambiar esto: los autores muestran que mediante el uso de una nueva técnica de
inicialización de peso de actualización fija (fixup), logran entrenar una red neuronal muy profunda
(¡10,000 capas!) sin BN, logrando un estado del arte. rendimiento en tareas complejas de clasificación
de imágenes.
Recorte de degradado
Otra técnica popular para disminuir el problema de los gradientes explosivos es simplemente
recortar los gradientes durante la retropropagación para que nunca excedan algún umbral. Se
llamaRecorte de degradado.11Esta técnica se usa con más frecuencia en las neu‐
10 “Inicialización de corrección: aprendizaje residual sin normalización”, Hongyi Zhang, Yann N. Dauphin, Tengyu
Mamá (2019).
En Keras, implementar Gradient Clipping es solo una cuestión de configurar elvalor de clipo
clipnormargumento al crear un optimizador. Por ejemplo:
optimizador=queras.optimizadores.USD(valor de clip=1.0)
modelo.compilar(pérdida="mse",optimizador=optimizador)
Esto recortará todos los componentes del vector de gradiente a un valor entre -1.0 y 1.0. Esto
significa que todas las derivadas parciales de la pérdida (con respecto a todos y cada uno de los
parámetros entrenables) se recortarán entre –1,0 y 1,0. El umbral es un hiperparámetro que
puede ajustar. Tenga en cuenta que puede cambiar la orientación del vector de gradiente: por
ejemplo, si el vector de gradiente original es [0.9, 100.0], apunta principalmente en la dirección
del segundo eje, pero una vez que lo recorta por valor, obtiene [0.9, 1.0], que apunta
aproximadamente en la diagonal entre los dos ejes. En la práctica, sin embargo, este enfoque
funciona bien. Si desea asegurarse de que el recorte de degradado no cambie la dirección del
vector de degradado, debe recortar por norma configurandoclipnorm
en vez devalor de clip.Esto recortará todo el degradado si es ℓ2norma es mayor que el
umbral que eligió. Por ejemplo, si establececlipnorm=1.0,entonces el vector [0.9, 100.0] se
recortará a [0.00899964, 0.9999595], preservando su orientación, pero casi eliminando el
primer componente. Si observa que los gradientes explotan durante el entrenamiento
(puede realizar un seguimiento del tamaño de los gradientes con TensorBoard), puede
probar el recorte por valor y el recorte por norma, con un umbral diferente, y ver qué
opción funciona mejor en el conjunto de validación. .
Por lo general, no es una buena idea entrenar un DNN muy grande desde cero: en su lugar, siempre debe
intentar encontrar una red neuronal existente que realice una tarea similar a la que está tratando de abordar
(hablaremos sobre cómo encontrarlos encapitulo 14), luego simplemente reutilice las capas inferiores de esta
red: esto se llamatransferir el aprendizaje. No solo acelerará considerablemente el entrenamiento, sino que
también requerirá muchos menos datos de entrenamiento.
Por ejemplo, suponga que tiene acceso a un DNN que fue entrenado para clasificar imágenes
en 100 categorías diferentes, incluidos animales, plantas, vehículos y objetos cotidianos. Ahora
desea entrenar un DNN para clasificar tipos específicos de vehículos. Estas tareas son muy
similares, incluso se superponen parcialmente, por lo que debe intentar reutilizar partes de la
primera red (verFigura 11-4).
Si las imágenes de entrada de su nueva tarea no tienen el mismo tamaño que las
utilizadas en la tarea original, normalmente tendrá que agregar un paso de
preprocesamiento para cambiarlas al tamaño esperado por el modelo original. En
términos más generales, el aprendizaje por transferencia funcionará mejor cuando
las entradas tengan características similares de bajo nivel.
La capa de salida del modelo original generalmente debe reemplazarse, ya que lo más probable es
que no sea útil para la nueva tarea y es posible que ni siquiera tenga la cantidad correcta de salidas
para la nueva tarea.
De manera similar, es menos probable que las capas ocultas superiores del modelo original sean tan útiles
como las capas inferiores, ya que las características de alto nivel que son más útiles para la nueva tarea
pueden diferir significativamente de las que fueron más útiles para la tarea original. . Desea encontrar el
número correcto de capas para reutilizar.
Cuanto más similares sean las tareas, más capas querrás reutilizar (empezando
por las capas inferiores). Para tareas muy similares, puede intentar mantener
todas las capas ocultas y simplemente reemplazar la capa de salida.
Intente congelar todas las capas reutilizadas primero (es decir, haga que sus pesos no se puedan entrenar, de
modo que el descenso de gradiente no los modifique), luego entrene su modelo y vea cómo funciona. Luego
intente descongelar una o dos de las capas ocultas superiores para permitir que la retropropagación las
ajuste y vea si el rendimiento mejora. Cuantos más datos de entrenamiento tengas, más
Si aún no puede obtener un buen rendimiento y tiene pocos datos de entrenamiento, intente eliminar
las capas ocultas superiores y congele todas las capas ocultas restantes nuevamente. Puede iterar
hasta encontrar el número correcto de capas para reutilizar. Si tiene muchos datos de entrenamiento,
puede intentar reemplazar las capas ocultas superiores en lugar de eliminarlas, e incluso agregar más
capas ocultas.
Veamos un ejemplo. Supongamos que el conjunto de datos MNIST de moda solo contiene 8 clases,
por ejemplo, todas las clases excepto sandalias y camisas. Alguien construyó y entrenó un modelo de
Keras en ese conjunto y obtuvo un rendimiento razonablemente bueno (>90 % de precisión).
Llamemos a este modelo A. Ahora quiere abordar una tarea diferente: tiene imágenes de sandalias y
camisas, y quiere entrenar un clasificador binario (positivo=camisas, negativo=sandalias). Sin
embargo, su conjunto de datos es bastante pequeño, solo tiene 200 imágenes etiquetadas. Cuando
entrena un nuevo modelo para esta tarea (llamémoslo modelo B), con la misma arquitectura que el
modelo A, funciona razonablemente bien (97,2 % de precisión), pero como es una tarea mucho más
fácil (solo hay 2 clases), esperabas más. Mientras toma su café de la mañana, se da cuenta de que su
tarea es bastante similar a la tarea A, entonces, ¿quizás el aprendizaje por transferencia pueda
ayudar? ¡Vamos a averiguar!
Primero, necesita cargar el modelo A y crear un nuevo modelo basado en las capas del modelo A.
Reutilicemos todas las capas excepto la capa de salida:
modelo_A=queras.modelos.cargar_modelo("mi_modelo_A.h5")
modelo_B_en_A=queras.modelos.Secuencial(modelo_A.capas[:-1])
modelo_B_en_A.agregar(queras.capas.Denso(1,activación="sigmoideo"))
modelo_A_clon=queras.modelos.clon_modelo(modelo_A)
modelo_A_clon.establecer_pesos(modelo_A.obtener_pesos())
Ahora podríamos simplemente entrenarmodelo_B_en_Apara la tarea B, pero dado que la nueva capa de salida
se inicializó aleatoriamente, cometerá grandes errores, al menos durante las primeras épocas, por lo que
habrá grandes gradientes de error que pueden arruinar los pesos reutilizados. Para evitar esto, un enfoque
es congelar las capas reutilizadas durante las primeras épocas, dando a la nueva capa algo de tiempo para
aprender pesos razonables. Para hacer esto, simplemente establezca la configuración de cada capa.entrenar
capazatribuir aFalsoy compilar el modelo:
porcapaenmodelo_B_en_A.capas[:-1]:
capa.entrenable=Falso
A continuación, podemos entrenar el modelo durante algunas épocas, luego descongelar las capas
reutilizadas (lo que requiere volver a compilar el modelo) y continuar entrenando para ajustar las capas
reutilizadas para la tarea B. Después de descongelar las capas reutilizadas, suele ser una buena idea para
reducir la tasa de aprendizaje, una vez más para evitar dañar los pesos reutilizados:
historia=modelo_B_en_A.adaptar(Tren_X_B,y_tren_B,épocas=4,
datos_de_validación=(X_válido_B,y_válido_B))
porcapaenmodelo_B_en_A.capas[:-1]:
capa.entrenable=Verdadero
Entonces, ¿cuál es el veredicto final? Bueno, la precisión de la prueba de este modelo es del 99,25 %, lo que
significa que el aprendizaje por transferencia redujo la tasa de error del 2,8 % a casi el 0,7 %. ¡Eso es un factor
de 4!
¿Estás convencido? Bueno, no deberías estarlo: ¡hice trampa! :) Probé muchas configuraciones
hasta que encontré una que demostró una gran mejora. Si intenta cambiar las clases o la
semilla aleatoria, verá que la mejora generalmente cae, o incluso desaparece o se invierte. Lo
que hice se llama "torturar los datos hasta que confiesen". Cuando un artículo parece
demasiado positivo, debe sospechar: tal vez la nueva y llamativa técnica no ayude mucho (de
hecho, incluso puede degradar el rendimiento), pero los autores probaron muchas variantes y
solo informaron los mejores resultados (lo que puede deberse a para esquilar la suerte), sin
mencionar cuántos fracasos encontraron en el camino. La mayoría de las veces, esto no es
malicioso en absoluto, pero es parte de la razón por la cual tantos resultados en Science nunca
se pueden reproducir.
Entonces, ¿por qué hice trampa? Bueno, resulta que el aprendizaje por transferencia no funciona muy
bien con redes pequeñas y densas: funciona mejor con redes neuronales convolucionales profundas,
por lo que revisaremos el aprendizaje por transferencia encapitulo 14, utilizando las mismas técnicas
(¡y esta vez no habrá trampas, lo prometo!).
Suponga que desea abordar una tarea compleja para la que no tiene muchos datos de entrenamiento
etiquetados, pero lamentablemente no puede encontrar un modelo entrenado en una tarea similar. ¡No
pierdas toda esperanza! Primero, por supuesto, debe intentar recopilar más datos de entrenamiento
etiquetados, pero si esto es demasiado difícil o demasiado costoso, es posible que aún pueda realizar
preentrenamiento no supervisado(verFigura 11-5). A menudo es bastante barato recopilar ejemplos de
capacitación sin etiquetar, pero bastante costoso etiquetarlos. Si puede recopilar una gran cantidad de datos
de entrenamiento sin etiquetar, puede intentar entrenar las capas una por una, comenzando con la capa más
baja y luego subiendo, usando un algoritmo detector de características no supervisado comoMáquinas
Boltzmann restringidas(RBM; ver???) o codificadores automáticos (ver???). Cada capa se entrena en la salida
de las capas previamente entrenadas (todas las capas excepto la que se está entrenando se congelan). Una
vez que todas las capas hayan sido entrenadas de esta manera, puede agregar la capa de salida para su tarea
y ajustar la red final usando el aprendizaje supervisado (es decir, con los ejemplos de entrenamiento
etiquetados). En este punto, puede descongelar todas las capas preentrenadas, o solo algunas de las
superiores.
Este es un proceso bastante largo y tedioso, pero a menudo funciona bien; de hecho, es esta técnica la
que usaron Geoffrey Hinton y su equipo en 2006 y que condujo al resurgimiento de las redes
neuronales y al éxito del aprendizaje profundo. Hasta 2010, el preentrenamiento no supervisado
(típicamente usando RBM) era la norma para las redes profundas, y fue solo después de que se alivió
el problema de los gradientes que se desvanecían que se volvió mucho más común.
(hoy en día normalmente se usan codificadores automáticos en lugar de RBM) sigue siendo una buena opción cuando tiene una
tarea compleja que resolver, no hay un modelo similar que pueda reutilizar y hay pocos datos de entrenamiento etiquetados
Si no tiene muchos datos de entrenamiento etiquetados, una última opción es entrenar una primera red
neuronal en una tarea auxiliar para la que pueda obtener o generar fácilmente datos de entrenamiento
etiquetados, luego reutilice las capas inferiores de esa red para su tarea real. Las capas inferiores de la
primera red neuronal aprenderán detectores de características que probablemente serán reutilizables por la
segunda red neuronal.
Por ejemplo, si desea crear un sistema para reconocer caras, es posible que solo tenga unas pocas
imágenes de cada individuo, lo que claramente no es suficiente para entrenar a un buen clasificador.
No sería práctico reunir cientos de fotografías de cada persona. Sin embargo, podría recopilar muchas
imágenes de personas aleatorias en la web y entrenar una primera red neuronal para detectar si dos
imágenes diferentes muestran o no a la misma persona. Tal red aprendería buenos detectores de
características para rostros, por lo que reutilizar sus capas inferiores le permitiría entrenar un buen
clasificador de rostros usando pocos datos de entrenamiento.
Entrenar una red neuronal profunda muy grande puede ser terriblemente lento. Hasta ahora hemos visto
cuatro formas de acelerar el entrenamiento (y llegar a una mejor solución): aplicar una buena estrategia de
inicialización para los pesos de conexión, usar una buena función de activación, usar Batch Normalization y
reutilizar partes de una red preentrenada (posiblemente construido sobre una tarea auxiliar o usando
aprendizaje no supervisado). Otro gran impulso de velocidad proviene del uso de un optimizador más rápido
que el optimizador de descenso de gradiente normal. En esta sección
Optimización de impulso
Imagine una bola de bolos rodando por una pendiente suave sobre una superficie lisa:
comenzará lentamente, pero rápidamente tomará impulso hasta que finalmente alcance la
velocidad terminal (si hay algo de fricción o resistencia del aire). Esta es la idea muy simple
detrás optimización de impulso,propuesto por Boris Polyak en 1964.12Por el contrario, el
Descenso de gradiente regular simplemente dará pequeños pasos regulares por la pendiente,
por lo que llevará mucho más tiempo llegar al fondo.
La optimización del momento se preocupa mucho por cuáles eran los gradientes
anteriores: en cada iteración, resta el gradiente local delvector de impulsometro(
multiplicado por la tasa de aprendizajeη), y actualiza los pesos simplemente agregando
este vector de impulso (verEcuación 11-4). En otras palabras, la pendiente se usa para la
aceleración, no para la velocidad. Para simular algún tipo de mecanismo de fricción y
evitar que el impulso crezca demasiado, el algoritmo introduce un nuevo hiperparámetro
β, llamado simplemente elimpulso, que debe configurarse entre 0 (alta fricción) y 1 (sin
fricción). Un valor de impulso típico es 0,9.
1. metro βmetro−η∇θjθ
2. θ θ+metro
Puede verificar fácilmente que si el gradiente permanece constante, la velocidad terminal (es decir, el
tamaño máximo de las actualizaciones de peso) es igual a ese gradiente multiplicado por el
12 “Algunos métodos para acelerar la convergencia de los métodos de iteración”, B. Polyak (1964).
optimizador=queras.optimizadores.USD(yo=0.001,impulso=0.9)
1. metro βmetro−η∇θjθ+βm θ+
2. θ metro
13 “Un método para el problema de minimización convexa sin restricciones con la tasa de convergencia O(1/k2)”, Yuri
Nésterov (1983).
optimizador=queras.optimizadores.USD(yo=0.001,impulso=0.9,nésterov=Verdadero)
adagrad
Considere nuevamente el problema del cuenco alargado: el descenso de gradiente comienza descendiendo
rápidamente por la pendiente más empinada, luego desciende lentamente por el fondo del valle. Sería bueno
si el algoritmo pudiera detectar esto desde el principio y corregir su dirección para apuntar un poco más
hacia el óptimo global.
1. s s+∇θjθ⊗∇θjθ
2. θ θ−η∇θjθ⊘s+�
14 “Métodos adaptativos de subgradiente para el aprendizaje en línea y la optimización estocástica”, J. Duchi et al. (2011).
El segundo paso es casi idéntico a Gradient Descent, pero con una gran diferencia: el
vector de gradiente se reduce en un factor de� + � (la⊘El símbolo representa la división
por elementos, y ϵ es un término de suavizado para evitar la división por cero,
normalmente establecido en 10–10). Esta forma vectorizada es equivalente a calcular
θi θi−η∂jθ/∂θi/si+�para todos los parámetrosθi(simultaneamente).
En resumen, este algoritmo decae la tasa de aprendizaje, pero lo hace más rápido para dimensiones
empinadas que para dimensiones con pendientes más suaves. Esto se llama untasa de aprendizaje
adaptativo. Ayuda a apuntar las actualizaciones resultantes más directamente hacia el óptimo global
(ver Figura 11-7). Un beneficio adicional es que requiere mucho menos ajuste del hiperparámetro de
tasa de aprendizaje.η.
AdaGrad a menudo funciona bien para problemas cuadráticos simples, pero desafortunadamente, a
menudo se detiene demasiado pronto cuando se entrenan redes neuronales. La tasa de aprendizaje
se reduce tanto que el algoritmo termina deteniéndose por completo antes de alcanzar el óptimo
global. Entonces, aunque Keras tiene unAdagradoOptimizer, no debe usarlo para entrenar redes
neuronales profundas (aunque puede ser eficiente para tareas más simples como la regresión lineal).
Sin embargo, comprender Adagrad es útil para comprender los otros optimizadores de la tasa de
aprendizaje adaptativo.
1. s βs+1 -β∇θjθ⊗∇θjθ
2. θ θ−η∇θjθ⊘s+�
La tasa de descomposiciónβnormalmente se establece en 0,9. Sí, una vez más es un nuevo hiperparámetro, pero este valor
predeterminado a menudo funciona bien, por lo que es posible que no necesite ajustarlo en absoluto.
optimizador=queras.optimizadores.RMSprop(yo=0.001,ro=0.9)
Excepto en problemas muy simples, este optimizador casi siempre funciona mucho mejor que
AdaGrad. De hecho, fue el algoritmo de optimización preferido de muchos investigadores hasta
que surgió la optimización de Adam.
15 Este algoritmo fue creado por Geoffrey Hinton y Tijmen Tieleman en 2012 y presentado por Geoffrey
Hinton en su clase de Coursera sobre redes neuronales (diapositivas:https://homl.info/57; video:https://homl.info/58). Curiosamente, dado que los
autores no escribieron un artículo para describirlo, los investigadores a menudo citan la "diapositiva 29 en la lección 6" en sus artículos.
17 Estas son estimaciones de la media y la varianza (no centrada) de los gradientes. La media a menudo se llama
primer momento, mientras que la varianza a menudo se denominasegundo momento, de ahí el nombre del algoritmo.
3.
metro
metro
1 -βt 1
s
4. s
1 -β t 2
5. θ θ+ηmetro⊘s+�
Si solo observa los pasos 1, 2 y 5, notará la gran similitud de Adam con la optimización
Momentum y RMSProp. La única diferencia es que el paso 1 calcula un promedio decreciente
exponencialmente en lugar de una suma decreciente exponencialmente, pero en realidad son
equivalentes excepto por un factor constante (el promedio decreciente es solo 1 –β1veces la
suma decreciente). Los pasos 3 y 4 son algo así como un detalle técnico: dado que metroysse
inicializan en 0, estarán sesgados hacia 0 al comienzo del entrenamiento, por lo que estos dos
pasos ayudarán a impulsarmetroysal comienzo del entrenamiento.
Dado que Adam es un algoritmo de tasa de aprendizaje adaptativo (como AdaGrad y RMSProp), requiere
menos ajustes del hiperparámetro de tasa de aprendizaje.η. A menudo puede utilizar el valor
predeterminadoη= 0,001, lo que hace que Adam sea aún más fácil de usar que Gradient Descent.
Todas las técnicas de optimización discutidas hasta ahora solo se basan en laderivadas parciales de
primer orden(Jacobianos). La literatura de optimización contiene sorprendentes algoritmos basados
en laderivadas parciales de segundo orden(laarpilleras, que son las derivadas parciales de los
jacobianos). Desafortunadamente, estos algoritmos son muy difíciles de aplicar a las redes neuronales
profundas porque haynorte2Arpilleras por salida (dondenortees el número de parámetros), en lugar
de simplementenorteJacobianos por salida. Dado que las DNN suelen tener decenas de miles de
parámetros, los algoritmos de optimización de segundo orden
19 “El valor marginal de los métodos de gradiente adaptativo en el aprendizaje automático”, AC Wilson et al. (2017).
Todos los algoritmos de optimización que acabamos de presentar producen modelos densos, lo que significa
que la mayoría de los parámetros serán distintos de cero. Si necesita un modelo ultrarrápido en tiempo de
ejecución, o si necesita que ocupe menos memoria, es posible que prefiera terminar con un modelo disperso.
Una forma trivial de lograr esto es entrenar al modelo como de costumbre, luego deshacerse de los
pequeños pesos (establecerlos en 0). Sin embargo, esto normalmente no conducirá a un modelo muy
disperso y puede degradar el rendimiento del modelo.
Una mejor opción es aplicar fuerte ℓ1regularización durante el entrenamiento, ya que empuja al
optimizador a cero tantos pesos como sea posible (como se discutió enCapítulo 4sobre la regresión de
Lasso).
Sin embargo, en algunos casos estas técnicas pueden resultar insuficientes. Una última opción es
aplicarDoble promedio, llamado a menudoSiga al líder regularizado(FTRL), untécnica propuesta
por Yurii Nesterov.20Cuando se usa con ℓ1regularización, esta técnica a menudo conduce a
modelos muy dispersos. Keras implementa una variante de FTRL llamadaFTRL-Proximal21en el
FTRLoptimizador
Encontrar una buena tasa de aprendizaje puede ser complicado. Si lo establece demasiado alto, el
entrenamiento en realidad puede divergir (como discutimos enCapítulo 4). Si lo configura demasiado bajo, el
entrenamiento eventualmente convergerá al óptimo, pero llevará mucho tiempo. Si lo configura un poco
demasiado alto, progresará muy rápidamente al principio, pero terminará bailando alrededor del nivel
óptimo, sin llegar a estabilizarse realmente. Si tiene un presupuesto informático limitado, es posible que deba
interrumpir la capacitación antes de que haya convergido correctamente, lo que generará una solución
subóptima (consulteFigura 11-8).
“Predicción de clics en anuncios: una vista desde las trincheras”, H. McMahan et al. (2013).
Como discutimos enCapítulo 10, un enfoque es comenzar con una gran tasa de aprendizaje y dividirla
por 3 hasta que el algoritmo de entrenamiento deje de divergir. No estará demasiado lejos de la tasa
de aprendizaje óptima, que aprenderá rápidamente y convergerá en una buena solución.
Sin embargo, puede hacerlo mejor que una tasa de aprendizaje constante: si comienza con una tasa
de aprendizaje alta y luego la reduce una vez que deja de progresar rápidamente, puede llegar a una
buena solución más rápido que con la tasa de aprendizaje constante óptima. Hay muchas estrategias
diferentes para reducir la tasa de aprendizaje durante el entrenamiento. Estas estrategias se llaman
horarios de aprendizaje(presentamos brevemente este concepto enCapítulo 4), los más comunes de
los cuales son:
Programación de energía
Establecer la tasa de aprendizaje en función del número de iteraciónt:η(t) =η0/ (1 +t/k)C. La tasa de
aprendizaje inicialη0, el poderC(normalmente establecido en 1) y los pasossson hiperparámetros.
La tasa de aprendizaje cae en cada paso, y despuésspasos a los que se reduceη0/ 2. Despuéssmás
pasos, se reduce aη0/ 3. Luego hacia abajo hastaη0/ 4, entoncesη0/ 5, y así sucesivamente. Como
puede ver, este horario primero desciende rápidamente, luego cada vez más lentamente. Por
supuesto, esto requiere ajusteη0,s(y posiblementeC).
Programación exponencial
Establezca la tasa de aprendizaje en:η(t) =η00.1t/s. La tasa de aprendizaje se reducirá gradualmente en un
factor de 10 cadaspasos. Mientras que la programación de energía reduce la tasa de aprendizaje cada
vez más lentamente, la programación exponencial sigue reduciéndola en un factor de10cada spasos.
Programación de rendimiento
Medir el error de validación cadanortepasos (al igual que para la parada temprana) y
reducir la tasa de aprendizaje por un factor deλcuando el error deja de caer.
Apapel de 201322por Andrew Senior et al. comparó el rendimiento de algunos de los programas de
aprendizaje más populares al entrenar redes neuronales profundas para el reconocimiento de voz
utilizando la optimización de Momentum. Los autores concluyeron que, en este entorno, tanto la
programación por desempeño como la programación exponencial funcionaron bien. Favorecieron la
programación exponencial porque era fácil de ajustar y convergía un poco más rápido a la solución
óptima (también mencionaron que era más fácil de implementar que la programación por
desempeño, pero en Keras ambas opciones son fáciles).
Implementar la programación de energía en Keras es la opción más fácil: simplemente configure eldecadencia
optimizador=queras.optimizadores.USD(yo=0.01,decadencia=1e-4)
La programación exponencial y la programación por partes también son bastante simples. Primero
debe definir una función que tome la época actual y devuelva la tasa de aprendizaje. Por ejemplo,
implementemos la programación exponencial:
definitivamenteexponential_decay_fn(época):
devolver0.01*0.1**(época/20)
Si no desea codificarη0ys, puede crear una función que devuelva una función
configurada:
definitivamenteDecrecimiento exponencial(lr0,s):
definitivamenteexponential_decay_fn(época):
devolverlr0*0.1**(época/s)
devolverexponential_decay_fn
exponential_decay_fn=Decrecimiento exponencial(lr0=0.01,s=20)
lr_scheduler=queras.devoluciones de llamada.LearningRateScheduler(exponential_decay_fn)
historia=modelo.adaptar(X_train_scaled,y_tren, [...],devoluciones de llamada=[lr_scheduler])
22 “Un estudio empírico de las tasas de aprendizaje en redes neuronales profundas para el reconocimiento de voz”, A. Senior et al.
(2013).
La función de programación puede tomar opcionalmente la tasa de aprendizaje actual como un segundo
argumento. Por ejemplo, la siguiente función de programación simplemente multiplica la tasa de aprendizaje
anterior por 0,1&1/20, lo que da como resultado el mismo decaimiento exponencial (excepto que el
decaimiento ahora comienza al comienzo de la época 0 en lugar de 1). Esta implementación se basa en la tasa
de aprendizaje inicial del optimizador (al contrario de la implementación anterior), así que asegúrese de
configurarla correctamente.
definitivamenteexponential_decay_fn(época,yo):
devolveryo*0.1**(1/20)
Cuando guarda un modelo, el optimizador y su tasa de aprendizaje se guardan junto con él. Esto
significa que con esta nueva función de programación, puede simplemente cargar un modelo
entrenado y continuar entrenando donde lo dejó, sin problema. Sin embargo, las cosas no son tan
simples si su función de programación utiliza elépocaargumento: de hecho, la época no se guarda y se
restablece a 0 cada vez que llama aladaptar()método. Esto podría conducir a una tasa de aprendizaje
muy grande cuando continúa entrenando a un modelo donde lo dejó, lo que probablemente dañaría
los pesos de su modelo. Una solución es configurar manualmente eladaptar()
métodosépoca_inicialargumento por lo que elépocacomienza en el valor correcto.
Para la programación constante por partes, puede usar una función de programación como la
siguiente (como antes, puede definir una función más general si lo desea, vea el cuaderno para ver un
ejemplo), luego cree unaLearningRateSchedulerdevolución de llamada con esta función y pásela al
adaptar()método, tal como lo hicimos para la programación exponencial:
definitivamentepor partes_constante_fn(época):
siépoca<5:
devolver0.01
elifépoca<15:
devolver0.005
más:
devolver0.001
lr_scheduler=queras.devoluciones de llamada.ReducirLROnPlateau(factor=0.5,paciencia=5)
Por último, tf.keras ofrece una forma alternativa de implementar la programación de la tasa de aprendizaje:
simplemente defina la tasa de aprendizaje utilizando uno de los horarios disponibles enkeras.optimiz
Con miles de parámetros puedes ajustar todo el zoológico. Las redes neuronales profundas suelen
tener decenas de miles de parámetros, a veces incluso millones. Con tantos parámetros, la red tiene
una increíble cantidad de libertad y puede adaptarse a una gran variedad de conjuntos de datos
complejos. Pero esta gran flexibilidad también significa que es propenso a sobreajustar el conjunto de
entrenamiento. Necesitamos la regularización.
ℓ 1y ℓ Regularización
2
Al igual que lo hiciste enCapítulo 4para modelos lineales simples, puede usar ℓ1y ℓ2regularización para
restringir los pesos de conexión de una red neuronal (pero normalmente no sus sesgos). Aquí está
cómo aplicar ℓ2regularización a los pesos de conexión de una capa de Keras, usando un factor de
regularización de 0.01:
capa=queras.capas.Denso(100,activación="elú",
kernel_initializer="él_normal", kernel_regularizer=
queras.regularizadores.l2(0.01))
losl2()La función devuelve un regularizador que será llamado para calcular la pérdida de
regularización, en cada paso durante el entrenamiento. Esta pérdida de regularización se suma
luego a la pérdida final. Como era de esperar, solo puede usarkeras.regularizadores.l1()si tu
Como normalmente querrá aplicar el mismo regularizador a todas las capas de su red, así como
la misma función de activación y la misma estrategia de inicialización en todas las capas ocultas,
es posible que se encuentre repitiendo los mismos argumentos una y otra vez. Esto lo hace feo
y propenso a errores. Para evitar esto, puede intentar refactorizar su código para usar bucles.
Otra opción es usar Pythonfunctools.parcial()función: le permite crear un contenedor delgado
para cualquier invocable, con algunos valores de argumento predeterminados. Por ejemplo:
deherramientas funcionalesimportarparcial
RegularizadoDenso=parcial(queras.capas.Denso,
activación="elú", kernel_initializer="él_normal",
kernel_regularizer=queras.regularizadores.l2(0.01))
modelo=queras.modelos.Secuencial([
queras.capas.Aplanar(entrada_forma=[28,28]),
RegularizadoDenso(300), RegularizadoDenso(
100), RegularizadoDenso(10,activación=
"softmax",
kernel_initializer="glorot_uniforme")
])
Abandonar
Abandonares una de las técnicas de regularización más populares para redes neuronales
profundas. Fuepropuesto23por Geoffrey Hinton en 2012 y más detallado en unpapel24
por Nitish Srivastava et al., y ha demostrado ser un gran éxito: incluso las redes neuronales de última
generación obtuvieron un aumento de precisión del 1% al 2% simplemente agregando abandono. Puede que
esto no parezca mucho, pero cuando un modelo ya tiene una precisión del 95 %, obtener un aumento de
precisión del 2 % significa reducir la tasa de error en casi un 40 % (pasar del 5 % de error a aproximadamente
el 3 %).
Es un algoritmo bastante simple: en cada paso de entrenamiento, cada neurona (incluidas las de
entrada, pero siempre excluyendo las de salida) tiene una probabilidadpagsde ser "abandonado"
temporalmente, lo que significa que se ignorará por completo durante este paso de entrenamiento,
pero puede estar activo durante el siguiente paso (verFigura 11-9). El hiperparámetro pagsse llama el
tasa de deserción escolar, y normalmente se establece en 50%. Después del entrenamiento, las
neuronas ya no se caen. Y eso es todo (salvo un detalle técnico que comentaremos
momentáneamente).
23 “Mejora de las redes neuronales mediante la prevención de la coadaptación de los detectores de características”, G. Hinton et al.
(2012). 24 “Deserción: una forma sencilla de evitar el sobreajuste de las redes neuronales”, N. Srivastava et al. (2014).
Es bastante sorprendente al principio que esta técnica bastante brutal funcione. ¿Se
desempeñaría mejor una empresa si a sus empleados se les dijera que lanzaran una moneda
todas las mañanas para decidir si van o no a trabajar? Bueno, quién sabe; ¡tal vez lo haría! La
empresa obviamente se vería obligada a adaptar su organización; no podía depender de una
sola persona para llenar la máquina de café o realizar otras tareas críticas, por lo que esta
experiencia tendría que distribuirse entre varias personas. Los empleados tendrían que
aprender a cooperar con muchos de sus compañeros de trabajo, no solo con un puñado de
ellos. La empresa se volvería mucho más resistente. Si una persona renuncia, no haría mucha
diferencia. No está claro si esta idea realmente funcionaría para las empresas, pero ciertamente
lo hace para las redes neuronales. Las neuronas entrenadas con abandono no pueden
coadaptarse con sus neuronas vecinas; tienen que ser lo más útiles posible por sí mismos.
Tampoco pueden depender excesivamente de unas pocas neuronas de entrada; deben prestar
atención a cada una de sus neuronas de entrada. Terminan siendo menos sensibles a ligeros
cambios en las entradas. Al final, obtienes una red más robusta que generaliza mejor.
Otra forma de comprender el poder de la deserción es darse cuenta de que se genera una red
neuronal única en cada paso de entrenamiento. Como cada neurona puede estar presente o ausente,
hay un total de 2norteposibles redes (dondenortees el número total de neuronas descartables). Este es
un número tan grande que es prácticamente imposible que la misma red neuronal se muestree dos
veces. Una vez que haya ejecutado 10 000 pasos de entrenamiento, esencialmente habrá entrenado
10 000 redes neuronales diferentes (cada una con solo una instancia de entrenamiento). Estas redes
neuronales obviamente no son independientes ya que comparten muchos de sus pesos, pero sin
embargo son todas diferentes. La red neuronal resultante puede verse como un conjunto promedio
de todas estas redes neuronales más pequeñas.
Hay un pequeño pero importante detalle técnico. Suponerpags=50%, en cuyo caso, durante la
prueba, una neurona se conectará al doble de neuronas de entrada que (en promedio) durante
el entrenamiento. Para compensar este hecho, necesitamos multiplicar cada
modelo=queras.modelos.Secuencial([
queras.capas.Aplanar(entrada_forma=[28,28]),
queras.capas.Abandonar(Velocidad=0.2),
queras.capas.Denso(300,activación="elú",kernel_initializer="él_normal"), queras.
capas.Abandonar(Velocidad=0.2),
queras.capas.Denso(100,activación="elú",kernel_initializer="él_normal"), queras.
capas.Abandonar(Velocidad=0.2),
queras.capas.Denso(10,activación="softmax")
])
Dado que el abandono solo está activo durante el entrenamiento, la pérdida de entrenamiento se
penaliza en comparación con la pérdida de validación, por lo que comparar los dos puede ser
embargo, tener pérdidas de entrenamiento y validación similares. Así que asegúrese de evaluar la
Si observa que el modelo se está sobreajustando, puede aumentar la tasa de abandono. Por el contrario,
debe intentar disminuir la tasa de abandono si el modelo no se ajusta al conjunto de entrenamiento. También
puede ayudar a aumentar la tasa de abandono para las capas grandes y reducirla para las pequeñas.
Además, muchas arquitecturas de última generación solo usan el abandono después de la última capa oculta,
por lo que es posible que desee probar esto si el abandono total es demasiado fuerte.
La deserción tiende a ralentizar significativamente la convergencia, pero generalmente da como resultado un modelo
mucho mejor cuando se ajusta correctamente. Por lo tanto, generalmente vale la pena el tiempo y el esfuerzo extra.
25 Esto es específico de tf.keras, por lo que es posible que prefiera utilizarkeras.backend.set_learning_phase(1)antes de llamar
laadaptar()método (y configúrelo de nuevo en 0 justo después).
En 2016, unpapel26por Yarin Gal y Zoubin Ghahramani agregaron más buenas razones para usar
abandono:
• Primero, el documento establece una conexión profunda entre las redes de abandono (es decir,
las redes neuronales que contienen una capa de abandono antes de cada capa de ponderación) y
la inferencia bayesiana aproximada.27, dando a la deserción una sólida justificación matemática.
• En segundo lugar, introducen una poderosa técnica llamadaAbandono de MC, que puede aumentar el
rendimiento de cualquier modelo de abandono entrenado, sin tener que volver a entrenarlo ni
modificarlo en absoluto.
26 "Abandono como aproximación bayesiana: representación de la incertidumbre del modelo en el aprendizaje profundo", Y. Gal y Z.
Ghahramani (2016).
27 Específicamente, muestran que entrenar una red de deserción es matemáticamente equivalente a aproximar Bayesian
inferencia en un tipo específico de modelo probabilístico llamadoProceso gaussiano profundo.
El modelo parece casi seguro de que esta imagen pertenece a la clase 9 (botín). ¿Deberías
confiar en él? ¿Hay realmente tan poco lugar para la duda? Compare esto con las predicciones
realizadas cuando se activa el abandono:
Esto cuenta una historia muy diferente: aparentemente, cuando activamos el abandono, el modelo ya
no está seguro. Todavía parece preferir la clase 9, pero a veces duda con las clases 5 (sandalias) y 7
(zapatillas), lo cual tiene sentido dado que son todo calzado. Una vez que promediamos sobre la
primera dimensión, obtenemos las siguientes predicciones de abandono de MC:
El modelo todavía cree que esta imagen pertenece a la clase 9, pero solo con un 62 % de confianza, lo
que parece mucho más razonable que el 99 %. Además, es útil saber exactamente qué otras clases
cree que son probables. Y también puedes echar un vistazo a ladesviación estándar de las
estimaciones de probabilidad:
Si su modelo contiene otras capas que se comportan de una manera especial durante el entrenamiento
(como las capas de normalización por lotes), entonces no debe forzar el modo de entrenamiento como
acabamos de hacer. En su lugar, debe reemplazar elAbandonarcapas con lo siguienteMCAbandono
clase:
claseMCAbandono(queras.capas.Abandonar):
definitivamentellamar(uno mismo,entradas):
devolversúper().llamar(entradas,capacitación=Verdadero)
En resumen, MC Dropout es una técnica fantástica que potencia los modelos de abandono y proporciona
mejores estimaciones de incertidumbre. Y por supuesto, dado que es solo un abandono regular durante el
entrenamiento, también actúa como un regularizador.
Regularización Max-Norm
Otra técnica de regularización que es bastante popular para las redes neuronales se
llama regularización de norma máxima: para cada neurona, restringe los pesoswde
las conexiones entrantes tal que∥ *w*∥2≤ _r_, donderes el hiperparámetro max-norm
y∥·∥2es el ℓ2norma.
queras.capas.Denso(100,activación="elú",kernel_initializer="él_normal",
kernel_constraint=queras.restricciones.max_norm(1.))
Optimizador: Nadam
¡No olvide estandarizar las funciones de entrada! Por supuesto, también debe intentar reutilizar partes de una red
neuronal previamente entrenada si puede encontrar una que resuelva un problema similar, o usar un entrenamiento
previo no supervisado si tiene muchos datos sin etiquetar, o un entrenamiento previo en una tarea auxiliar si tiene
muchos datos. de datos etiquetados para una tarea similar.
— Puede intentar usar ELU (u otra función de activación) en lugar de SELU, puede
funcionar mejor. Asegúrese de cambiar el método de inicialización en
consecuencia (p. ej., He init para ELU o ReLU).
— Si se trata de una red profunda, debe usar la normalización por lotes después de cada capa oculta. Si
se ajusta demasiado al conjunto de entrenamiento, también puede intentar usar max-norm o ℓ2
regularización.
• Si necesita un modelo disperso, puede usar ℓ1regularización (y opcionalmente poner a cero los
pesos diminutos después del entrenamiento). Si necesita un modelo aún más disperso, puede
intentar usar FTRL en lugar de la optimización de Nadam, junto con ℓ1regularización En cualquier
caso, esto interrumpirá la autonormalización, por lo que deberá cambiar a BN si su modelo es
profundo.
• Si necesita un modelo de baja latencia (uno que realice predicciones ultrarrápidas), es posible que
deba usar menos capas, evitar la normalización por lotes y posiblemente reemplazar la función
de activación de SELU con ReLU con fugas. Tener un modelo disperso también ayudará. También
es posible que desee reducir la precisión flotante de 32 bits a 16 bits (o incluso a 8 bits) (consulte
???).
• Si está creando una aplicación sensible al riesgo o la latencia de inferencia no es muy importante
en su aplicación, puede usar MC Dropout para aumentar el rendimiento y obtener estimaciones
de probabilidad más confiables, junto con estimaciones de incertidumbre.
Con estas pautas, ¡ahora estás listo para entrenar redes muy profundas! Espero que ahora esté
convencido de que puede recorrer un largo camino usando solo Keras. Sin embargo, puede llegar un
momento en el que necesite tener aún más control, por ejemplo, para escribir una función de pérdida
personalizada o modificar el algoritmo de entrenamiento. Para tales casos, deberá usar la API de nivel
inferior de TensorFlow, como veremos en el próximo capítulo.
Ejercicios
1. ¿Está bien inicializar todos los pesos con el mismo valor siempre y cuando ese valor se
seleccione al azar usando la inicialización He?
8. Aprendizaje profundo.
una. Cree una DNN con cinco capas ocultas de 100 neuronas cada una, la inicialización de He y la
función de activación de ELU.
b. Usando la optimización de Adam y la detención temprana, intente entrenarlo en MNIST pero solo en
los dígitos 0 a 4, ya que usaremos el aprendizaje de transferencia para los dígitos 5 a 9 en el
próximo ejercicio. Necesitará una capa de salida softmax con cinco neuronas y, como siempre,
asegúrese de guardar los puntos de control a intervalos regulares y guarde el modelo final para
poder reutilizarlo más tarde.
C. Ajuste los hiperparámetros mediante validación cruzada y vea qué precisión puede
lograr.
d. Ahora intente agregar Normalización por lotes y compare las curvas de aprendizaje: ¿está
convergiendo más rápido que antes? ¿Produce un modelo mejor?
mi. ¿El modelo está sobreajustando el conjunto de entrenamiento? Intente agregar abandono a cada
capa y vuelva a intentarlo. ¿Ayuda?
9. Transferir el aprendizaje.
una. Cree un nuevo DNN que reutilice todas las capas ocultas previamente entrenadas del
modelo anterior, las congele y reemplace la capa de salida softmax por una nueva.
b. Entrene este nuevo DNN en los dígitos 5 a 9, usando solo 100 imágenes por dígito, y mida
cuánto tiempo lleva. A pesar de este pequeño número de ejemplos, ¿puede lograr una alta
precisión?
C. Intente almacenar en caché las capas congeladas y vuelva a entrenar el modelo: ¿cuánto más rápido es
ahora?
d. Vuelva a intentar reutilizar solo cuatro capas ocultas en lugar de cinco. ¿Se puede lograr una
mayor precisión?
mi. Ahora descongele las dos capas superiores ocultas y continúe entrenando: ¿puede lograr que
el modelo funcione aún mejor?
una. En este ejercicio, construirá un DNN que compare dos imágenes de dígitos
MNIST y prediga si representan el mismo dígito o no. Luego reutilizará las capas
inferiores de esta red para entrenar un clasificador MNIST usando muy poco
Ejercicios | 365
datos de entrenamiento. Comience por construir dos DNN (llamémoslos DNN A y B),
ambos similares al que creó anteriormente pero sin la capa de salida: cada DNN debe
tener cinco capas ocultas de 100 neuronas cada una, inicialización de He y activación de
ELU. A continuación, agregue una capa oculta más con 10 unidades encima de ambos
DNN. Para hacer esto, debe usar unkeras.layers.Concatenarcapa para concatenar las
salidas de ambos DNN para cada instancia, luego alimentar el resultado a la capa
oculta. Finalmente, agregue una capa de salida con una sola neurona utilizando la
función de activación logística.
b. Divida el conjunto de entrenamiento MNIST en dos conjuntos: la división n.º 1 debe contener
55 000 imágenes y la división n.º 2 debe contener 5000 imágenes. Cree una función que
genere un lote de entrenamiento en el que cada instancia sea un par de imágenes MNIST
seleccionadas de la división n.º 1. La mitad de las instancias de entrenamiento deben ser
pares de imágenes que pertenezcan a la misma clase, mientras que la otra mitad deben ser
imágenes de diferentes clases. Para cada par, la etiqueta de entrenamiento debe ser 0 si las
imágenes son de la misma clase o 1 si son de diferentes clases.
C. Entrene el DNN en este conjunto de entrenamiento. Para cada par de imágenes, puede
enviar simultáneamente la primera imagen a DNN A y la segunda imagen a DNN B.
Toda la red aprenderá gradualmente a distinguir si dos imágenes pertenecen a la
misma clase o no.
d. Ahora cree un nuevo DNN reutilizando y congelando las capas ocultas de DNN A y agregando
una capa de salida softmax en la parte superior con 10 neuronas. Entrene esta red en la
división n.º 2 y vea si puede lograr un alto rendimiento a pesar de tener solo 500 imágenes
por clase.
TensorFlow
Con los libros electrónicos Early Release, obtiene libros en su forma más
temprana, el contenido sin editar y sin editar del autor mientras escribe,
para que pueda aprovechar estas tecnologías mucho antes del
lanzamiento oficial de estos títulos. El siguiente será el Capítulo 12 en la
versión final del libro.
Hasta ahora, solo hemos usado la API de alto nivel de TensorFlow, tf.keras, pero ya hemos llegado
bastante lejos: construimos varias arquitecturas de redes neuronales, incluidas redes de regresión y
clasificación, redes amplias y profundas y redes de autonormalización, utilizando todo tipo de técnicas,
como la normalización por lotes, la deserción, los horarios de tasa de aprendizaje y más. De hecho, el
95% de los casos de uso que encontrará no requerirán nada más que tf.keras (y tf.data, consulte
Capítulo 13). Pero ahora es el momento de profundizar en TensorFlow y echar un vistazo a su nivel
inferiorAPI de Python. Esto será útil cuando necesite control adicional, para escribir funciones de
pérdida personalizadas, métricas personalizadas, capas, modelos, inicializadores, regularizadores,
restricciones de peso y más. Es posible que incluso necesite controlar completamente el ciclo de
entrenamiento en sí mismo, por ejemplo, para aplicar transformaciones o restricciones especiales a
los gradientes (más allá de simplemente recortarlos), o usar múltiples optimizadores para diferentes
partes de la red. Cubriremos todos estos casos en este capítulo, luego también veremos cómo puede
mejorar sus modelos personalizados y algoritmos de entrenamiento utilizando la función de
generación automática de gráficos de TensorFlow. Pero primero, hagamos un recorrido rápido por
TensorFlow.
367
TensorFlow 2.0 se lanzó en marzo de 2019, lo que hace que TensorFlow sea
mucho más fácil de usar. La primera edición de este libro usó TF 1, mientras
que esta edición usa TF 2.
Como sabes,TensorFlowes una biblioteca poderosa para el cálculo numérico, especialmente adecuada
y ajustada para el aprendizaje automático a gran escala (pero podría usarla para cualquier otra cosa
que requiera cálculos pesados). Fue desarrollado por el equipo de Google Brain y potencia muchos de
los servicios a gran escala de Google, como Google Cloud Speech, Google Photos y Google Search. Fue
de código abierto en noviembre de 2015 y ahora es la biblioteca de aprendizaje profundo más popular
(en términos de citas en artículos, adopción en empresas, estrellas en github, etc.): innumerables
proyectos usan TensorFlow para todo tipo de tareas de aprendizaje automático, tales como
clasificación de imágenes, procesamiento de lenguaje natural (NLP), sistemas de recomendación,
pronóstico de series temporales y mucho más.
• Incluye una especie de compilador justo a tiempo (JIT) que le permite optimizar los cómputos en
cuanto a velocidad y uso de memoria: funciona extrayendo elgráfico de cálculodesde una función
de Python, luego optimizándola (p. ej., eliminando los nodos no utilizados) y finalmente
ejecutándola de manera eficiente (p. ej., ejecutando automáticamente operaciones
independientes en paralelo).
• Los gráficos de cómputo se pueden exportar a un formato portátil, por lo que puede
entrenar un modelo de TensorFlow en un entorno (p. ej., usando Python en Linux) y
ejecutarlo en otro (p. ej., usando Java en un dispositivo Android).
• TensorFlow ofrece muchas más funciones, construidas sobre estas funciones principales: la más importante es,
por supuesto, tf.keras1, pero también tiene operaciones de preprocesamiento y carga de datos (tf.data, tf.io,
etc.), operaciones de procesamiento de imágenes (tf.image), operaciones de procesamiento de señales
(tf.signal) y más (verFigura 12-1para obtener una descripción general de la API de Python de TensorFlow).
1 TensorFlow también incluye otra API de aprendizaje profundo llamadaAPI de estimadores, pero ahora se recomienda
para usar tf.keras en su lugar.
En el nivel más bajo, cada operación de TensorFlow se implementa utilizando código C++ altamente
eficiente.2. Muchas operaciones (ooperacionespara abreviar) tienen múltiples implementaciones,
llamadas granos: cada núcleo está dedicado a un tipo de dispositivo específico, como CPU, GPU o
incluso TPU (Unidades de procesamiento de tensores). Como sabrá, las GPU pueden acelerar
drásticamente los cálculos al dividirlos en muchos fragmentos más pequeños y ejecutarlos en paralelo
en muchos subprocesos de GPU. Los TPU son aún más rápidos. Puede comprar sus propios
dispositivos GPU (por ahora, TensorFlow solo admite tarjetas Nvidia con CUDA Compute Capability
3.5+), pero las TPU solo están disponibles enMotor de aprendizaje automático de Google Cloud(ver???).
3
La arquitectura de TensorFlow se muestra enFigura 12-2: la mayoría de las veces su código usará las
API de alto nivel (especialmente tf.keras y tf.data), pero cuando necesite más flexibilidad, usará la API
de Python de nivel inferior, manejando los tensores directamente. Tenga en cuenta que las API para
otros idiomas también están disponibles. En cualquier caso, la ejecución de TensorFlow
2 Si alguna vez lo necesita (pero probablemente no lo necesite), puede escribir sus propias operaciones utilizando la API de C++.
3 Si es un investigador, puede ser elegible para usar estos TPU de forma gratuita, consultehttps://tensorflow.org/tfrc/para más
detalles.
Hay más en TensorFlow que solo la biblioteca. TensorFlow está en el centro de un extenso ecosistema
de bibliotecas. Primero, está TensorBoard para la visualización (ver Capítulo 10). A continuación, hay
TensorFlow extendido (TFX), que es un conjunto de bibliotecas creadas por Google para producir
proyectos de TensorFlow: incluye herramientas para validación de datos, preprocesamiento, análisis
de modelos y entrega (con TF Serving, consulte???). Google también lanzóCentro TensorFlow, una
forma de descargar y reutilizar fácilmente redes neuronales preentrenadas. También puede obtener
muchas arquitecturas de redes neuronales, algunas de ellas preentrenadas, en TensorFlow'sjardín
modelo. Revisar laRecursos de TensorFlow, ohttps://github.com/jtoy/awesome-tensorflowpara más
proyectos basados en TensorFlow. Encontrará cientos de proyectos de TensorFlow en GitHub, por lo
que a menudo es fácil encontrar el código existente para cualquier cosa que intente hacer.
Tensores y Operaciones
Puedes crear fácilmente un tensor, usandotf.constante().Por ejemplo, aquí hay un tensor que
representa una matriz con dos filas y tres columnas de flotantes:
Tenga en cuenta que escribirt + 10es equivalente a llamartf.añadir(t, 10) (de hecho, Python
llama al método mágicot.__añadir__(10),que solo llamatf.añadir(t, 10)).También se admiten
otros operadores (como -, *, etc.). El operador @ se agregó en Python 3.5, para la
multiplicación de matrices: es equivalente a llamar altf.matmul()función.
Encontrará todas las operaciones matemáticas básicas que necesita (p. ej.,tf.añadir(),
tf.multiplicar(), tf.cuadrado(), tf.exp(), tf.sqrt()…) y, en general, la mayoría de las operaciones
que puede encontrar en NumPy (p. ej.,tf.remodelar(), tf.apretar(), tf.tile()),pero a veces
con un nombre diferente (por ejemplo,tf.reduce_mean(), tf.reduce_sum(), tf.reduce_max(),
tf.math.log()son el equivalente denp.media(), np.suma(), np.max()ynp.log()).
Cuando el nombre difiere, a menudo hay una buena razón para ello: por ejemplo, en Tensor-Flow
debes escribirtf.transponer(t),no puedes simplemente escribirtTcomo en NumPy. La razón es que no
hace exactamente lo mismo: en TensorFlow, se crea un nuevo tensor con su propia copia de los datos
transpuestos, mientras que en NumPy,tTes solo una vista transpuesta de los mismos datos. Del
mismo modo, eltf.reduce_sum()La operación recibe este nombre porque su kernel de GPU (es decir, la
implementación de GPU) utiliza un algoritmo de reducción que no garantiza el orden en que se
agregan los elementos: debido a que los elementos flotantes de 32 bits tienen una precisión limitada,
esto significa que el resultado puede cambiar siempre ligeramente cada vez que llame a esta
operación. Lo mismo es cierto detf.reduce_mean() (pero por supuesto
tf.reduce_max()es determinista).
La API de Keras en realidad tiene su propia API de bajo nivel, ubicada enkeras.backend.Incluye
funciones comocuadrado(), exp(), raíz cuadrada()y así. En tf.keras, estas funciones generalmente
solo llaman a las operaciones correspondientes de TensorFlow. Si desea escribir código que sea
portátil para otras implementaciones de Keras, debe usar estas funciones de Keras. Sin embargo,
solo cubren un subconjunto de todas las funciones disponibles en TensorFlow, por lo que en este
libro usaremos las operaciones de TensorFlow directamente. Aquí hay un ejemplo simple usando
keras.backend,que comúnmente se nombrakpara abreviar:
Tensores y NumPy
Los tensores funcionan bien con NumPy: puede crear un tensor a partir de una matriz NumPy y
viceversa, e incluso puede aplicar operaciones TensorFlow a matrices NumPy y operaciones
NumPy a tensores:
4 Una notable excepción estf.matemáticas.log()que se usa comúnmente pero no haytf.log()alias (como podría ser
confundirse con registro).
Tensor‐Flow utiliza una precisión de 32 bits. Esto se debe a que la precisión de 32 bits generalmente
es más que suficiente para las redes neuronales, además se ejecuta más rápido y usa menos RAM.
establecerdtype=tf.float32.
Tipo de conversiones
Esto puede ser un poco molesto al principio, ¡pero recuerda que es por una buena causa! Y, por
supuesto, puedes usartf.cast()cuando realmente necesitas convertir tipos:
Variables
Hasta ahora, hemos usado tensores constantes: como su nombre indica, no puedes modificarlos. Sin
embargo, los pesos en una red neuronal deben modificarse mediante la retropropagación, y es posible que
otros parámetros también deban cambiar con el tiempo (p. ej., un optimizador de momento realiza un
seguimiento de los gradientes anteriores). Lo que necesitamos es untf.Variable:
Atf.Variableactúa como un tensor constante: puede realizar las mismas operaciones con él,
también funciona bien con NumPy y es igual de exigente con los tipos. Pero también se
puede modificar en su lugar usando elasignar()método (oasignar_añadir()o
asignar_sub()que incrementan o decrementan la variable por el valor dado). También
puede modificar celdas individuales (o sectores), usando la celda (o sector)asignar()
(la asignación directa de elementos no funcionará), o usando el métododispersión_actualizar()o
dispersión_nd_actualizar()métodos: