100% encontró este documento útil (8 votos)
5K vistas557 páginas

Chollet 2018 Español

Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
100% encontró este documento útil (8 votos)
5K vistas557 páginas

Chollet 2018 Español

Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd

Traducido del inglés al español - www.onlinedoctranslator.

com

francoisC h o l l e t

MANEJO
Aprendizaje profundo con Python

Con licencia para


Con licencia para
Aprendizaje
profundo
con Python
FRANÇOIS CHOLLET

MANEJO
SHELTERyoISLA

Con licencia para


Para obtener información en línea y solicitar este y otros libros de Manning, visite
www.manning.com. La editorial ofrece descuentos en este libro cuando se pide en cantidad.
Para obtener más información, póngase en contacto
Departamento de Ventas
Especiales Manning
Publications Co. 20
Baldwin Road
apartado de correos 761
Shelter Island, Nueva York
11964 Correo
electrónico:pedidos@manning
.com

©2018 por Manning Publications Co. Todos los derechos reservados.

Ninguna parte de esta publicación puede reproducirse, almacenarse en un sistema de


recuperación o transmitirse de ninguna forma o por medios electrónicos, mecánicos,
fotocopiados o de otro modo, sin el permiso previo por escrito del editor.

Muchas de las designaciones utilizadas por los fabricantes y vendedores para distinguir sus
productos se reclaman como marcas comerciales. Donde esas designaciones aparecen en el
libro, y Manning Publications estaba al tanto de un reclamo de marca registrada, las
designaciones se han impreso en mayúsculas iniciales o en mayúsculas.

Reconociendo la importancia de preservar lo que hasido escrito, es política de Manning


imprimir los libros que publicamos en papel libre de ácido, y realizamos nuestros mejores
esfuerzos con ese fin.
Reconociendo también nuestra responsabilidad de conservar los recursos de nuestro planeta,
los libros de Manning se imprimen en papel que es al menos un 15 por ciento reciclado y
procesado sin el uso de cloro elemental.

Publicaciones de ManningCo.Desarrollo editor: Toni Arritola 20


BaldwinLa carretera Editor de desarrollo técnico: Jerry Gaines
apartado de correos761 Editor de reseñas: Aleksandar Dragosavljevi´c
Shelter Island, Nueva York11964Proyecto editora: Tiffany Taylor
Correctora de estilo: Tiffany
Taylor Correctora: Katie
Tennant
Correctores técnicos: Alex Ott y Richard Tobias
Tipografista: Dottie Marsico
Diseño de portada: Marija Tudor

ISBN 9781617294433
Impreso en los Estados Unidos de América
1 2 3 4 5 6 7 8 9 10 – MBE – 22 21 20 19 18 17

Con licencia para


contenidos
breves
PARTE1F
FUNDAMENTALES DE PROFUNDIDADAPRENDIZAJE ........................ 1
1 que es profundoaprendizaje?3

2 Antes de comenzar: los bloques de construcción matemáticos


de neuralredes25
3 ■ Comenzando con neuralredes56
4 ■ fundamentos de maquinaaprendizaje93

PARTE2D ............................................................................................ EEP


APRENDIZAJE ENPRÁCTICA ......................................................................................117
5 ■ Aprendizaje profundo para computadoravisión119
6 ■ Aprendizaje profundo para texto ysecuencias178
7 ■ Aprendizaje profundo avanzado mejorpracticas233

8 ■ Profundo generativoaprendizaje269

9 ■ Conclusiones314

Con licencia para


v

Con licencia para


Con licencia para
contenido
prefacio xiii
expresiones de
gratitudXVsobre este
libro xvi sobre el
autor xxsobre la
portada xxi

PAGSARTE1F
FUNDAMENTALES DE PROFUNDIDADAPRENDIZAJE .. 1

1 que es profundo¿aprendizaje?
1.1 Inteligencia artificial, aprendizaje
3

automático y profundidadaprendizaje4

Artificialinteligencia 4 Máquinaaprendizaje4


Aprendizaje representaciones dedatos 6 El

“profundo” en lo profundoaprendizaje 8
Comprender cómo funciona el aprendizaje profundo, entres figuras 9
Lo que ha logrado el aprendizaje profundohasta aquí
11 Nocreerel

bombo a corto plazo 12 la promesa deAI 13


1.2 Antes del aprendizaje profundo: una breve


historia de la máquinaaprendizaje14
probabilísticomodelado 14 Primeras redes neuronales

14
Núcleométodos 15 Árboles de decisión, bosques

aleatorios, y aumento de gradientemáquinas


dieciséis volver a neural redes17


lo que hace profundoaprendiendo diferente 17
El aprendizaje automático modernopaisaje 18

Con licencia para


viii

Con licencia para


viii CONTENIDO

1.3 ¿Por qué aprendizaje profundo? Por quéahora?20


ferreteria 20 datos21

Algoritmos 21 un nuevo
■ ■

Ola deinversión22 La democratización de lo


profundo aprendizaje23 lo haráúltimo?23


2 Antes de comenzar: los bloques de construcción


matemáticos de neuralredes 25
2.1 Un primer vistazo a una neuralred27
2.2 Representaciones de datos para neuralredes31
Escalares (0Dtensores) 31 Vectores (tensores 1D)

31Matrices (2Dtensores) 31 tensores 3D y


superiores- tensores dimensionales 32 Atributos ■

clave 32 Manipulación de tensores enNumpy34



La noción de datoslotes 34 Ejemplos de datos

del mundo real tensores 35 Vectordatos 35



Datos de series temporales o
secuenciadatos 35 Imagendatos36
■ ■
Videodatos 37
2.3 Los engranajes de las redes neuronales: tensoroperaciones38
Elemento sabiooperaciones 38 Radiodifusión39 Tensor
■ ■

dot40 ■
Remodelación de tensores 42 Interpretación ■

geométrica de tensoroperaciones 43 Una ■

interpretación geométrica de lo profundo aprendizaje44

2.4 El motor de las redes neuronales: basado en


gradientesoptimización46
Qué es un¿derivado? 47 Derivada de una operación

tensorial:ladegradado 48 Gradiente

estocásticodescendencia 48
Encadenamiento de derivadas: la retropropagaciónalgoritmo
51
2.5 Mirando hacia atrás a nuestro primerejemplo53
2.6 Capítuloresumen55

3 Comenzando con neuralredes


3.1 Anatomía de un neuralred58
56

Capas: los componentes básicos de la


profundidadaprendizaje 58 Modelos: redes

decapas 59 Funciones de pérdida y


optimizadores: clavesconfigurar el aprendizajeproceso


60
3.2 Introducción aKeras61
Keras, TensorFlow,Teano, yCNTK62 ■
Desarrollando
con Keras: un rápidovisión general 62

Con licencia para


3.3 Configuración de un aprendizaje profundoestación de trabajo65
Cuadernos Jupyter: la forma preferida de ejecutar el
aprendizaje profundo experimentos 65 getting Keras

corriendo: dosopciones 66

Con licencia para


CONTENIDO ix

Ejecución de trabajos de aprendizaje profundo en la nube: pros ycontras 66


¿Cuál es la mejor GPU para profundidad?¿aprendizaje? 66
3.4 Clasificación de críticas de películas: un
binarioclasificaciónejemplo68
El IMDBconjunto de datos68 preparando eldatos69

Construyendo tula red 70 Validando tuAcercarse



73
Usar una red entrenada para generar predicciones sobre
nuevos datos76 Más lejosexperimentos

77 Envasearriba77

3.5 Clasificación de los cables de noticias: una


clasificación multiclaseejemplo78
El Reutersconjunto de datos 78 preparando eldatos

79
Construyendo tula red 79 Validando tuAcercarse

80
Generar predicciones sobre nuevosdatos 83 Una ■

forma diferente de manejar las etiquetas y la pérdida 83 La ■

importancia de tener un intermedio suficientemente


grandecapas 83 Más lejos

experimentos 84 Envasearriba84

3.6 Predicción de los precios de la vivienda: una regresiónejemplo85


El precio de la vivienda en Bostonconjunto de datos
85 preparando eldatos86

Construyendo

tula red 86 Validando■

tu enfoque usando K-foldvalidación 87 Envasearriba91


3.7 Capítuloresumen92

4 fundamentos de maquinaaprendizaje 93
4.1 cuatro ramas deaprendizaje automático94
supervisadoaprendizaje 94 sin ■

supervisiónaprendizaje 94
Auto-supervisadoaprendizaje 94

Reforzamientoaprendizaje 95
4.2 Evaluación del aprendizaje automáticomodelos97
Entrenamiento, validación y pruebaconjuntos97
Cosas paraMantener dentromente100

4.3 Preprocesamiento de datos, ingeniería


de características y
característicasaprendizaje101
Preprocesamiento de datospara neuralredes 101

Rasgo ingeniería102
4.4 Sobreequipamiento yinfravalorar104
Reduciendo la redTalla 104 Agregando

pesoregularización107

agregandoabandono109
Con licencia para
4.5 El flujo de trabajo universal de la máquinaaprendizaje111
Definición del problema y montaje de unconjunto de datos 111
Elegir una medida del éxito 112 Decidirse por un

Con licencia para


X CONTENIDO

evaluaciónprotocolo 112 Preparando sus datos 112


Desarrollar un modelo que funciona mejor que una línea


de base 113Ampliación: desarrollo de un modelo
quesobreajustes 114
Regularizando su modelo y afinando suhiperparámetros 114
4.6 Capítuloresumen116

PAGSARTE2D ........................................................................EEP
APRENDIZAJE ENPRÁCTICA ..................................................................117

5 Aprendizaje profundo para computadoravisión


5.1 Introducción aconvnets120
119

la convoluciónoperación 122 La agrupación


máximaoperación127
5.2 Entrenando un convnet desde cero en un pequeñoconjunto de datos130

La relevancia del aprendizaje profundo para pequeños datosproblemas 130


Descargando eldatos 131 Construyendo tula red

133
Datospreprocesamiento 135 usando ■

datosaumento138
5.3 Usando un preentrenadoconvnet143
Rasgoextracción 143 Ajuste fino152
■ ■
Envase
arriba159
5.4 Visualizando lo que convenceaprender160
visualización intermediaactivaciones 160 Visualizante

convnetfiltros 167 Visualización de mapas de calor


de clase activación172
5.5 Capítuloresumen177

6 Aprendizaje profundo para texto ysecuencias


6.1 Laboralcon textodatos180
178

Codificación one-hot de palabras ycaracteres 181



Usando incrustaciones de palabras 184 Poniéndolo ■

todo junto: desde crudo texto a palabraincrustaciones 188



Envasearriba195
6.2 Comprensión de las neuronas recurrentesredes196
Una capa recurrente enKeras 198 Entendiendo el

LSTM y GRUcapas202 Un ejemplo concreto de LSTM


en Keras 204 Envasearriba206


6.3 Uso avanzado de neural recurrenteredes207


Un pronóstico de temperaturaproblema 207
preparando el datos210

Un sentido común,

Con licencia para


sin aprendizaje automático línea base 212 Un aprendizaje

automático básicoAcercarse 213


Un primer recurrentebase 215 Uso de abandono recurrente

Con licencia para


CONTENIDO xi

lucharsobreajuste 216 Apilamiento recurrentecapas



217
Usando bidireccionalRNN 219 yendo inclusomás lejos

222
Envasearriba223
6.4 Procesamiento de secuencias conconvnets225
Comprender la convolución 1D para la secuenciadatos 225
Agrupación 1D para secuenciadatos 226

Implementando un 1D convnet226 Combinando

CNN y RNN para procesar largas secuencias


228 Envasearriba231

6.5 Capítuloresumen232

7 Aprendizaje profundo avanzado mejorprácticas 233


7.1 Más allá del modelo Secuencial: el funcional
de KerasAPI 234
Introducción a lo funcionalAPI 236 Entrada múltiple

modelos238 ■
Multi-salidamodelos 240

acíclico dirigido gráficos decapas 242 Peso de la

capaintercambio 246 Modeloscomocapas



247

Envasearriba248
7.2 Inspeccionar y monitorear modelos de aprendizaje
profundo usando devoluciones de llamada de Keras
yTensorTablero 249
Uso de devoluciones de llamada para actuar en un modelo durantecapacitación 249
Introducción a TensorBoard: la visualización de
TensorFlowmarco252 Envasearriba259

7.3 Sacar el máximo partido a sumodelos260


Avanzadopatrones de arquitectura 260

hiperparámetro optimización263

Modeloensamblando 264 Envasearriba266

7.4 Capítuloresumen268

8 Profundo generativoaprendizaje 269


8.1 Generación de textoconLSTM271
Una breve historia de lo generativorecurrenteredes
271 Cómogeneras

secuencia¿datos? 272 La importancia de el


muestreoestrategia 272 Implementación de nivel de


personaje texto LSTMgeneracion274



Envasearriba279
8.2 sueño profundo280
Implementando DeepDream enKeras 281 Envasearriba286

Con licencia para


8.3 estilo neuronaltransferir287
El contenidopérdida 288 La pérdida

de estilo 288 estilo neuronaltransferenciaKeras


289 Envasearriba295

Con licencia para


xi CONTENIDO

8.4 Generación de imágenes con variacióncodificadores automáticos296

Muestreo de espacios latentes de imágenes 296 Vectores■

conceptualespor imagenedición 297 Codificadores


automáticos variacionales 298 Envasearriba304


8.5 Introducción al adversario generativoredes305
Un GAN esquemáticoimplementación 307 Una bolsa ■

detrucos 307 losgenerador 308 losdiscriminado 309



el adversario red310 como entrenar a

tuDCGAN310 Envase arriba312


8.6 Capítuloresumen313

9 Conclusiones 314
9.1 Conceptos clave enrevisión 315
Diversos enfoques paraAI 315 Lo que hace que el

aprendizaje profundoespecial dentro del campo de la


máquinaaprendizaje 315 Cómo■

piensa en lo profundoaprendizaje 316 Tecnologías


habilitadoras clave 317 El aprendizaje automático universalflujo de


trabajo 318 red clave arquitecturas

319 El ■

espaciodeposibilidades 322
9.2 Las limitaciones de lo profundoaprendizaje325
El riesgo de antropomorfizar el aprendizaje automáticomodelos
325Generalización local vs
extremogeneralización 327
Envasearriba329
9.3 El futuro de lo profundoaprendizaje330
Modelos como programas 330 Más allá de la

retropropagación y diferenciablecapas 332



Aprendizaje automático automatizado 332 Aprendizaje
permanente y subrutina modularreutilizar 333
el largo plazovisión 335
9.4 Mantenerse al día en un mundo en rápido movimientocampo337
Practica en problemas del mundo real usando
Kaggle 337 Lea sobre los últimos desarrollos en
arXiv 337 Explora el ecosistema de Keras 338
9.5 Palabras finales 339

apéndiceA Instalación de Keras y sus dependencias enubuntu 340


apéndiceB Ejecución de portátiles Jupyter en una GPU EC2instancia
345
índice353

Con licencia para


prefacio
Si ha leído este libro, probablemente sea consciente del extraordinario progreso que
ha representado el aprendizaje profundo para el campo de la inteligencia artificial en
el pasado reciente. En apenas cinco años, hemos pasado de un reconocimiento de
imágenes y una transcripción de voz casi inutilizables a un rendimiento
sobrehumano en estas tareas.
Las consecuencias de este avance repentino se extienden a casi todas las
industrias. Pero para comenzar a implementar la tecnología de aprendizaje profundo
en todos los problemas que podría resolver, debemos hacerla accesible a tantas
personas como sea posible, incluidos los no expertos, personas que no son
investigadores o estudiantes de posgrado. Para que el aprendizaje profundo alcance
su máximo potencial, necesitamos democratizarlo radicalmente.
Cuando lancé la primera versión del marco de aprendizaje profundo de Keras en
marzo de 2015, la democratización de la IA no era lo que tenía en mente. Había
estado investigando sobre aprendizaje automático durante varios años y había
creado Keras para que me ayudara con mis propios experimentos. Pero a lo largo de
2015 y 2016, decenas de miles de personas nuevas ingresaron al campo del
aprendizaje profundo; muchos de ellos eligieron Keras porque era, y sigue siendo, el
marco más fácil para comenzar. Mientras observaba a decenas de recién llegados
usar Keras de maneras inesperadas y poderosas, llegué a preocuparme
profundamente por la accesibilidad y la democratización de la IA. Me di cuenta de
que cuanto más difundimos estas tecnologías, más útiles y valiosas se vuelven. La
accesibilidad se convirtió rápidamente en un objetivo explícito en el desarrollo de
Keras y, en unos pocos años, la comunidad de desarrolladores de Keras ha logrado
fantásticos logros en este frente. Hemos puesto el aprendizaje profundo en manos de
decenas de miles de personas, quienes a su vez lo están utilizando para resolver
problemas importantes que ni siquiera sabíamos que existían hasta hace poco.
El libro que tiene en sus manos es otro paso en el camino para hacer que el
aprendizaje profundo esté disponible para tantas personas como sea posible. Keras
siempre había necesitado un curso complementario para

Con licencia para


XIII

Con licencia para


xiv PREFACIO

cubren simultáneamente los fundamentos del aprendizaje profundo, los patrones de uso
de Keras y las mejores prácticas de aprendizaje profundo. Este libro es mi mejor
esfuerzo para producir tal curso. Lo escribí con un enfoque en hacer que los conceptos
detrás del aprendizaje profundo y su implementación sean lo más accesibles posible.
Hacerlo no requirió que simplifique nada; creo firmemente que no hay ideas difíciles en
el aprendizaje profundo. Espero que este libro le resulte valioso y que le permita
comenzar a crear aplicaciones inteligentes y resolver los problemas que le interesan.

Con licencia para


expresiones de
gratitud
Me gustaría agradecer a la comunidad de Keras por hacer posible este libro. Keras ha
crecido hasta tener cientos de colaboradores de código abierto y más de 200 000
usuarios. Sus contribuciones y comentarios han convertido a Keras en lo que es hoy.
También me gustaría agradecer a Google por respaldar el proyecto Keras. Ha sido
fantástico ver la adopción de Keras como la API de alto nivel de TensorFlow. Una
integración fluida entre Keras y TensorFlow beneficia enormemente tanto a los usuarios
de TensorFlow como a los usuarios de Keras y hace que el aprendizaje profundo sea
accesible para la mayoría.
Quiero agradecer a la gente de Manning que hizo posible este libro: la editora
Marjan Bace y todos los miembros de los equipos editorial y de producción,
incluidas Christina Taylor, Janet Vail, Tiffany Taylor, Katie Tennant, Dottie
Marsico y muchos otros que trabajaron detrás de escena. .
METROningúntmadejas Vamos a la técnico
parcríticosledbyAleksandarDragosavljevic´ — Diego Acuña Rozas, Geoff Barto, David
Blumenthal-Barby, Abel Brown, Clark Dorman, Clark Gaylord, Thomas Heiman, Wilson
Mar, Sumit Pal, Vladimir Pasman, Gustavo Patino, Peter Rabinovitch, Alvin Raj, Claudio
Rodriguez, Srdjan Santic, Richard Tobias, Martin Verzilli, William E. Wheeler y Daniel
Williams, y los colaboradores del foro. Sus contribuciones incluyeron detectar errores
técnicos, errores de terminología y errores tipográficos, y hacer sugerencias de temas. Cada
paso por el proceso de revisión y cada pieza de retroalimentación implementada a través de
los temas del foro dieron forma y moldearon el manuscrito.
En el aspecto técnico, un agradecimiento especial para Jerry Gaines, quien se
desempeñó como editor técnico del libro; y Alex Ott y Richard Tobias, quienes se
desempeñaron como correctores técnicos del libro. Son los mejores editores
técnicos que podría haber esperado.
Finalmente, me gustaría expresar mi gratitud a mi esposa María por su gran
apoyo durante el desarrollo de Keras y la redacción de este libro.

Con licencia para


XV

Con licencia para


sobre este libro
Este libro fue escrito para cualquiera que deseepara explorar el aprendizaje profundo
desde cero o ampliar su comprensión del aprendizaje profundo. Tanto si es un
ingeniero de aprendizaje automático en ejercicio, un desarrollador de software o un
estudiante universitario, encontrará valor en estas páginas.
Este libro ofrece una exploración práctica del aprendizaje profundo. Evita la
notación matemática y prefiere explicar los conceptos cuantitativos a través de
fragmentos de código y desarrollar una intuición práctica sobre las ideas centrales del
aprendizaje automático y el aprendizaje profundo.
Aprenderá de más de 30 ejemplos de código que incluyen comentarios
detallados, recomendaciones prácticas y explicaciones simples de alto nivel de todo
lo que necesita saber para comenzar a usar el aprendizaje profundo para resolver
problemas concretos.
Los ejemplos de código utilizan el marco de trabajo de aprendizaje profundo de
Python, Keras, con Tensor-Flow como motor de back-end. Keras, uno de los marcos
de aprendizaje profundo más populares y de más rápido crecimiento, es
ampliamente recomendado como la mejor herramienta para comenzar con el
aprendizaje profundo.
Después de leer este libro, tendrá una sólida comprensión de lo que es el
aprendizaje profundo, cuándo es aplicable y cuáles son sus limitaciones. Estará
familiarizado con el flujo de trabajo estándar para abordar y resolver problemas de
aprendizaje automático, y sabrá cómo abordar los problemas más comunes. Podrá
utilizar Keras para abordar problemas del mundo real que van desde la visión por
computadora hasta el procesamiento del lenguaje natural: clasificación de imágenes,
pronóstico de series temporales, análisis de sentimientos, generación de imágenes y
texto, y más.

Con licencia para


xvi

Con licencia para


SOBRE ESTOLIBRO xvii

Quién debería leer este libro


Este libro está escrito para personas con experiencia en programación de Python que
desean comenzar con el aprendizaje automático y el aprendizaje profundo. Pero este
libro también puede ser valioso para muchos tipos diferentes de lectores:
◾ Si es un científico de datos familiarizado con el aprendizaje automático, este libro
le brindará una introducción sólida y práctica al aprendizaje profundo, el
subcampo más importante y de más rápido crecimiento del aprendizaje
automático.
◾ Si es un experto en aprendizaje profundo que busca comenzar con el marco
de trabajo de Keras, encontrará que este libro es el mejor curso intensivo de
Keras disponible.
◾ Si es un estudiante de posgrado que estudia el aprendizaje profundo en un
entorno formal, encontrará que este libro es un complemento práctico para su
educación, lo que lo ayudará a desarrollar la intuición en torno al
comportamiento de las redes neuronales profundas y lo familiarizará con las
mejores prácticas clave.
Incluso las personas con mentalidad técnica que no programan regularmente
encontrarán este libro útil como una introducción a los conceptos básicos y avanzados
de aprendizaje profundo.
Para usar Keras, necesitará un dominio razonable de Python. Además, será útil
familiarizarse con la biblioteca Numpy, aunque no es obligatorio. No necesita
experiencia previa con el aprendizaje automático o el aprendizaje profundo: este libro
cubre desde cero todos los conceptos básicos necesarios. Tampoco necesita una base
matemática avanzada: las matemáticas de nivel secundario deberían ser suficientes para
seguir adelante.

Mapa vial
Este libro está estructurado en dos partes. Si no tiene experiencia previa con el
aprendizaje automático, le recomiendo encarecidamente que complete la parte 1 antes
de abordar la parte 2. Comenzaremos con ejemplos simples y, a medida que avance el
libro, nos acercaremos cada vez más al estado de la cuestión. -Técnicas artísticas.
La Parte 1 es una introducción de alto nivel al aprendizaje profundo, brinda
contexto y definiciones, y explica todas las nociones necesarias para comenzar con
el aprendizaje automático y las redes neuronales:
◾ El Capítulo 1 presenta el contexto esencial y el conocimiento previo en torno
aAI, aprendizaje automático y aprendizaje profundo.
◾ El Capítulo 2 presenta los conceptos fundamentales necesarios para abordar el
aprendizaje profundo: tensores, operaciones de tensor, descenso de gradiente
y retropropagación. Este capítulo también presenta el primer ejemplo del libro
de una red neuronal en funcionamiento.
◾ El Capítulo 3 incluye todo lo que necesita para comenzar con las redes
neuronales: una introducción a Keras, nuestro marco de aprendizaje profundo
elegido; una guía para configurar su estación de trabajo; y tres ejemplos de
código fundamental con explicaciones detalladas. Al final de este capítulo,
Con licencia para
podrá entrenar neuronas simples

Con licencia para


xviii SOBRE ESTE LIBRO

redes para manejar tareas de clasificación y regresión, y tendrá una idea


sólida de lo que sucede en segundo plano a medida que las entrena.
◾ El capítulo 4 explora el flujo de trabajo de aprendizaje automático canónico.
También aprenderá acerca de las trampas comunes y sus soluciones.
La Parte 2 profundiza en las aplicaciones prácticas del aprendizaje profundo en la
visión artificial y el procesamiento del lenguaje natural. Muchos de los ejemplos
presentados en esta parte se pueden usar como plantillas para resolver problemas
que encontrará en la práctica del aprendizaje profundo en el mundo real:
◾ El Capítulo 5 examina una variedad de ejemplos prácticos de visión por
computadora, con un enfoque en la clasificación de imágenes.
◾ El Capítulo 6 le brinda práctica con técnicas para procesar datos de secuencia,
como texto y series de tiempo.
◾ El Capítulo 7 presenta técnicas avanzadas para construir modelos de aprendizaje
profundo de última generación.
◾ El Capítulo 8 explica los modelos generativos: modelos de aprendizaje
profundo capaces de crear imágenes y texto, a veces con resultados
sorprendentemente artísticos.
◾ El Capítulo 9 está dedicado a consolidar lo que ha aprendido a lo largo del
libro, además de abrir perspectivas sobre las limitaciones del aprendizaje
profundo y explorar su futuro probable.

software/hardware requisitos
Todos los ejemplos de código de este libro utilizan el marco de aprendizaje
profundo de Keras (https:// keras.io), que es de código abierto y de descarga
gratuita. Necesitará acceso a una máquina UNIX; también es posible usar Windows,
pero no lo recomiendo. El Apéndice A lo guía a través de la configuración
completa.
También le recomiendo que tenga una GPU NVIDIA reciente en su máquina,
como TITAN X. Esto no es obligatorio, pero mejorará su experiencia al permitirle
ejecutar los ejemplos de código varias veces más rápido. Consulte la sección 3.3
para obtener más información sobre cómo configurar una estación de trabajo de
aprendizaje profundo.
Si no tiene acceso a una estación de trabajo local con una GPU NVIDIA reciente,
puede usar un entorno de nube en su lugar. En particular, puede usar instancias de
Google Cloud (como una instancia n1-standard-8 con un complemento NVIDIA Tesla
K80) o instancias de GPU de Amazon Web Services (AWS) (como una instancia
p2.xlarge). El Apéndice B presenta en detalle un posible flujo de trabajo en la nube que
ejecuta una instancia de AWS a través de cuadernos Jupyter, accesible en su navegador.

Código fuente
Todos los ejemplos de código de este libro están disponibles para su descarga como
cuadernos de Jupyter desde el sitio web del libro,www.manning.com/books/deep-
learning-with-pythony en GitHub a https://github.com/fchollet/aprendizaje-
profundo-con-notebooks-python.

Con licencia para


SOBRE ESTOLIBRO xix

Foro de libros
La compra de Deep Learning con Python incluye acceso gratuito a un foro web privado
administrado por Manning Publications donde puede hacer comentarios sobre el libro, hacer
preguntas técnicas y recibir ayuda del autor y de otros usuarios. Para acceder al foro, vaya
ahttps://foros.manning.com/forums/aprendizaje-profundo-con-python.También puede
obtener más información sobre los foros de Manning y las reglas de conducta
enhttps://foros
.manning.com/forums/about.
El compromiso de Manning con nuestros lectores es proporcionar un lugar
donde pueda tener lugar un diálogo significativo entre lectores individuales y entre
lectores y el autor. No es un compromiso de participación específica por parte del
autor, cuya contribución al foro es voluntaria (y no remunerada). ¡Le sugerimos que
intente hacerle algunas preguntas desafiantes para que su interés no se desvíe! El
foro y los archivos de debates anteriores estarán accesibles desde el sitio web de la
editorial mientras el libro esté impreso.

Con licencia para


Sobre el Autor
François Chollet trabaja en aprendizaje profundo en Google
en Mountain View, CA. Es el creador de la biblioteca de
aprendizaje profundo Keras, así como colaborador del marco
de aprendizaje automático TensorFlow. También realiza
investigaciones de aprendizaje profundo, con un enfoque en
la visión por computadora y la aplicación del aprendizaje
automático al razonamiento formal. Sus artículos han sido
publicados en las principales conferencias en el campo,
incluida la Conferencia sobre visión por computadora y
reconocimiento de patrones (CVPR), la Conferencia y el
taller sobre información neuronal.
tion Processing Systems (NIPS), la Conferencia Internacional sobre
Representaciones de Aprendizaje (ICLR) y otros.

XX

Con licencia para


sobre la portada
La figura de la portada de Aprendizaje profundo con Python se titula "Hábito de un
persaSeñora en 1568.” La ilustración está tomada de A Collection of the Dresses of
Different Nations, Ancient and Modern de Thomas Jefferys (cuatro volúmenes), Londres,
publicado entre 1757 y 1772. La página del título indica que se trata de grabados en cobre
coloreados a mano, realzados con goma arábiga.
Thomas Jefferys (1719-1771) fue llamado "Geógrafo del rey Jorge III". Fue un
cartógrafo inglés que fue el principal proveedor de mapas de su época. Grabó e
imprimió mapas para el gobierno y otros organismos oficiales y produjo una amplia
gama de mapas y atlas comerciales, especialmente de América del Norte. Su trabajo
como cartógrafo despertó el interés por las costumbres locales de vestimenta de las
tierras que estudió y cartografió, que se muestran brillantemente en esta colección. La
fascinación por tierras lejanas y los viajes de placer eran fenómenos relativamente
nuevos a finales del siglo XVIII, y colecciones como esta eran populares, introduciendo
tanto al turista como al viajero de sillón a los habitantes de otros países.
La diversidad de los dibujos en los volúmenes de Jefferys habla vívidamente de la
singularidad e individualidad de las naciones del mundo hace unos 200 años. Los
códigos de vestimenta han cambiado desde entonces, y la diversidad por regiones y
países, tan rica en ese momento, se ha desvanecido. Ahora a menudo es difícil distinguir
a los habitantes de un continente de otro. Tal vez, tratando de verlo con optimismo,
hemos cambiado una diversidad cultural y visual por una vida personal más variada, o
una vida intelectual y técnica más variada e interesante.
En un momento en que es difícil distinguir un libro de computadora de otro,
Manning celebra la inventiva y la iniciativa del negocio de las computadoras con
portadas de libros basadas en la rica diversidad de la vida regional de hace dos siglos,
revividas por las fotografías de Jefferys. .

xxx

Con licencia para


Con licencia para
Parte 1
Fundamentos
del aprendizaje
profundo

C Los capítulos 1 a 4 de este libro le brindarán una comprensión


fundamental de lo que es el aprendizaje profundo, lo que puede lograr y cómo
funciona. También lo familiarizará con el flujo de trabajo canónico para
resolver problemas de datos mediante el aprendizaje profundo. Si aún no tiene
un gran conocimiento sobre el aprendizaje profundo, definitivamente debe
comenzar leyendo la parte 1 en su totalidad antes de pasar a las aplicaciones
prácticas en la parte 2.

Con licencia para


Con licencia para
¿Qué es el aprendizaje
profundo?

Este capítulo cubre


◾ Definiciones de alto nivel de conceptos
fundamentales
◾ Cronología del desarrollo del aprendizaje
automático
◾ Factores clave detrás del auge del
aprendizaje profundopopularidad y
potencial futuro

En los últimos años, la inteligencia artificial (IA) ha sido un tema de intensa


publicidad mediática. El aprendizaje automático, el aprendizaje profundo y la IA
aparecen en innumerables artículos, a menudo fuera de las publicaciones de
mentalidad tecnológica. Se nos promete un futuro de chatbots inteligentes, autos
autónomos y asistentes virtuales, un futuro a veces pintado con una luz sombría y
otras veces utópico, donde los trabajos humanos serán escasos y la mayor parte
de la actividad económica estará a cargo de robots o IA. agentes Para un
practicante futuro o actual del aprendizaje automático, es importante poder
reconocer la señal en el ruido para que pueda distinguir los desarrollos que
cambian el mundo a partir de comunicados de prensa exagerados. Nuestro futuro
está en juego, y es un futuro en el que usted tiene un papel activo que
desempeñar: después de leer este libro, será uno de los que desarrollen los
agentes de IA. Entonces, abordemos estas preguntas: ¿Qué ha logrado el
aprendizaje profundo hasta ahora? ¿Qué tan importante es? ¿Hacia dónde nos
dirigimos ahora? ¿Deberías creer el bombo?
Este capítulo proporciona un contexto esencial en torno a la inteligencia
artificial, el aprendizaje automático y el aprendizaje profundo.

3
Con licencia para
4 CPASADO1¿Qué es el aprendizaje profundo?

1.1 Inteligencia artificial, aprendizaje


automático,y aprendizaje profundo
Primero, debemos definir claramente de qué estamos hablando cuando
mencionamos la IA. ¿Qué son la inteligencia artificial, el aprendizaje automático y
el aprendizaje profundo (consulte la figura 1.1)? ¿Cómo se relacionan entre sí?

Inteligenc
ia artificial

Aprendi
zaje
automáti
co Apren
dizaje
profund
o
Figura 1.1 Inteligencia artificial,
aprendizaje automático y
aprendizaje profundo

1.1.1 Artificial inteligencia


La inteligencia artificial nació en la década de 1950, cuando un puñado de pioneros del
incipiente campo de la informática comenzó a preguntarse si se podía hacer que las
computadoras "pensaran", una pregunta cuyas ramificaciones todavía estamos
explorando hoy. Una definición concisación del campo sería la siguiente: el esfuerzo por
automatizar las tareas intelectuales normalmente realizadas por los humanos. Como tal, la
IA es un campo general que abarca el aprendizaje automático y el aprendizaje profundo,
pero que también incluye muchos más enfoques que no implican ningún tipo de aprendizaje.
Los primeros programas de ajedrez, por ejemplo, solo involucraban reglas codificadas
creadas por programadores y no calificaban como aprendizaje automático. Durante bastante
tiempo, muchos expertos creyeron que la inteligencia artificial a nivel humano podría
lograrse haciendo que los programadores crearan a mano un conjunto suficientemente
grande de reglas explícitas para manipular el conocimiento. Este enfoque se conoce como IA
simbólica y fue el paradigma dominante en la IA desde la década de 1950 hasta finales de la
década de 1980. Alcanzó su máxima popularidad durante el auge de los sistemas expertos de
la década de 1980.
Aunque la IA simbólica demostró ser adecuada para resolver problemas lógicos bien
definidos, como jugar al ajedrez, resultó ser intratable descubrir reglas explícitas para
resolver problemas más complejos y confusos, como la clasificación de imágenes, el
reconocimiento de voz y el lenguaje. traducción. Surgió un nuevo enfoque para tomar el
lugar de la IA simbólica: el aprendizaje automático.

1.1.2 Aprendizaje automático


En la Inglaterra victoriana, Lady Ada Lovelace era amiga y colaboradora de Charles
Babbage, el inventor de la máquina analítica: la primera computadora mecánica de
propósito general conocida. Aunque visionaria y muy adelantada a su tiempo, la
Con licencia para
Analítica

Con licencia para


Inteligencia artificial, aprendizaje automático y profundidadaprendizaje 5

Engine no se pensó como una computadora de propósito general cuando se diseñó


en las décadas de 1830 y 1840, porque el concepto de computación de propósito
general aún no se había inventado. Simplemente pretendía ser una forma de utilizar
operaciones mecánicas para automatizar ciertos cálculos del campo del análisis
matemático, de ahí el nombre de motor analítico. En 1843, Ada Lovelace comentó
sobre la invención: “La máquina analítica no tiene ninguna pretensión de originar
nada. Puede hacer cualquier cosa que sepamos cómo ordenarle que realice… Su
competencia es ayudarnos a poner a nuestra disposición lo que ya conocemos”.
Esta observación fue citada posteriormente por el pionero de la IA, Alan Turing,
como “la objeción de Lady Lovelace” en su artículo histórico de 1950 “Computing
Machinery and Intelligence”,1 que introdujo la prueba de Turing, así como los
conceptos clave que llegarían a dar forma a la IA. Turing estaba citando a Ada Lovelace
mientras se preguntaba si las computadoras de propósito general podrían ser capaces de
aprender y ser originales, y llegó a la conclusión de que sí. El aprendizaje automático
surge de esta pregunta: ¿podría una computadora ir más allá de “lo que sabemos cómo
ordenarle que realice” y aprender por sí misma cómo realizar una tarea específica?
¿Podría una computadora sorprendernos? En lugar de que los programadores elaboren
reglas de procesamiento de datos a mano, ¿podría una computadora aprender
automáticamente estas reglas al observar los datos?
Esta pregunta abre la puerta a un nuevo paradigma de programación. En la
programación clásica, el paradigma de la IA simbólica, los humanos ingresan reglas
(un programa) y datos para ser procesados de acuerdo con estas reglas, y obtienen
respuestas (ver figura 1.2). Con el aprendizaje automático, los humanos ingresan
datos, así como las respuestas esperadas de los datos, y obtienen las reglas. Estas
reglas pueden luego aplicarse a nuevos datos para producir respuestas originales.

Dato programaci
respuestas
s de ón clásica

regl

as

Res Aprendi
Normas Figura 1.2 Aprendizaje
puestas zaje automático: un nuevo
automáti
de datos paradigma de programación
co

Un sistema de aprendizaje automático se entrena en lugar de programarse


explícitamente. Se presenta con muchos ejemplos relevantes para una tarea y encuentra
una estructura estadística en estos ejemplos que finalmente permite que el sistema
genere reglas para automatizar la tarea. Por ejemplo, si desea automatizar la tarea de
etiquetar las imágenes de sus vacaciones, podría presentar un sistema de aprendizaje
automático con muchos ejemplos de imágenes ya etiquetadas por humanos, y el sistema
aprendería reglas estadísticas para asociar imágenes específicas a etiquetas específicas.

Con licencia para


1 AM Turing, "Maquinaria informática e inteligencia", Mind 59, no. 236 (1950): 433-460.

Con licencia para


6 CPASADO1¿Qué es el aprendizaje profundo?

Aunque el aprendizaje automático solo comenzó a florecer en la década de 1990, se


ha convertido rápidamente en el subcampo más popular y exitoso de la IA, una
tendencia impulsada por la disponibilidad de hardware más rápido y conjuntos de datos
más grandes. El aprendizaje automático está estrechamente relacionado con las
estadísticas matemáticas, pero difiere de las estadísticas en varios aspectos importantes.
A diferencia de las estadísticas, el aprendizaje automático tiende a manejar conjuntos de
datos grandes y complejos (como un conjunto de datos de millones de imágenes, cada
una de las cuales consta de decenas de miles de píxeles) para los cuales el análisis
estadístico clásico, como el análisis bayesiano, no sería práctico. Como resultado, el
aprendizaje automático, y especialmente el aprendizaje profundo, exhibe
comparativamente poca teoría matemática, tal vez demasiado poca, y está orientado a la
ingeniería. Es una disciplina práctica en la que las ideas se prueban empíricamente con
más frecuencia que teóricamente.

1.1.3 Aprendizaje de representaciones a partir de datos


Para definir el aprendizaje profundo y comprender la diferencia entre el aprendizaje
profundo y otros enfoques de aprendizaje automático, primero necesitamos tener
una idea de lo que hacen los algoritmos de aprendizaje automático. Acabo de decir
que el aprendizaje automático descubre reglas para ejecutar una tarea de
procesamiento de datos, dando ejemplos de lo que se espera. Entonces, para hacer
aprendizaje automático, necesitamos tres cosas:
◾ Puntos de datos de entrada—Por ejemplo, si la tarea es el reconocimiento de voz,
estos puntos de datos podrían ser archivos de sonido de personas hablando. Si la
tarea es el etiquetado de imágenes, podrían ser fotografías.
◾ Ejemplos de la salida esperada—En una tarea de reconocimiento de voz, estos
podrían ser transcripciones de archivos de sonido generadas por humanos. En una
tarea de imagen, los resultados esperados podrían ser etiquetas como "perro",
"gato", etc.
◾ Una forma de medir si el algoritmo está haciendo un buen trabajo—Esto es
necesario para determinar la distancia entre la salida actual del algoritmo y su salida
esperada. La medición se usa como una señal de retroalimentación para ajustar la
forma en que funciona el algoritmo. Este paso de ajuste es lo que llamamos
aprendizaje.
Un modelo de aprendizaje automático transforma sus datos de entrada en salidas
significativas, un proceso que se “aprende” a partir de la exposición a ejemplos
conocidos de entradas y salidas. Por lo tanto, el problema central en el aprendizaje
automático y el aprendizaje profundo es transformar los datos de manera significativa:
en otras palabras, aprender representaciones útiles de los datos de entrada disponibles,
representaciones que nos acercan al resultado esperado. Antes de continuar: ¿qué es una
representación? En esencia, es una forma diferente de ver los datos: representar o
codificar datos. Por ejemplo, una imagen en color se puede codificar en formato RGB
(rojo-verde-azul) o en formato HSV (tono-saturación-valor): estas son dos
representaciones diferentes de los mismos datos. Algunas tareas que pueden ser difíciles
con una representación pueden volverse fáciles con otra. Por ejemplo, la tarea
"seleccionar todos los píxeles rojos de la imagen" es más sencilla en el formato RG,
Con licencia para
mientras que "hacer la imagen menos saturada" es más sencilla en el formato HSV. Los
modelos de aprendizaje automático tienen que ver con encontrar representaciones
adecuadas para sus datos de entrada: transformaciones de los datos que los hacen más
aptos para la tarea en cuestión, como una tarea de clasificación.

Con licencia para


Inteligencia artificial, aprendizaje automático y profundidadaprendizaje 7

Hagamos esto concreto. Considere un eje x, un eje y y y


algunos puntos representados por sus coordenadas en el
sistema (x, y), como se muestra en la figura 1.3.
Como puede ver, tenemos algunos puntos blancos y
algunos puntos negros. Digamos que queremos desarrollar un
algoritmo que pueda tomar las coordenadas (x, y) de un punto
y mostrar si es probable que ese punto sea negro o blanco. En
este caso, X

◾ Las entradas son las coordenadas de nuestros puntos. Figura 1.3


◾ Los resultados esperados son los colores de nuestros Algunos datos de muestra
puntos.
◾ Una forma de medir si nuestro algoritmo está
haciendo un buen trabajo podría ser, por ejemplo, el
porcentaje de puntos que se clasifican correctamente.
Lo que necesitamos aquí es una nueva representación de nuestros datos que separe
claramente los puntos blancos de los puntos negros. Una transformación que
podríamos usar, entre muchas otras posibilidades, sería un cambio de coordenadas,
ilustrado en la figura 1.4.

1:Raw data2: cambio de coordenadas 3: Mejor representación


y
y y

X X

Figura 1.4 cambio de coordenadas

En este nuevo sistema de coordenadas, se puede decir que las coordenadas de


nuestros puntos son una nueva representación de nuestros datos. ¡Y es una buena!
Con esta representación, el problema de clasificación blanco/negro se puede
expresar como una regla simple: "Los puntos negros son tales que x > 0" o "Los
puntos blancos son tales que x < 0". Esta nueva representación resuelve básicamente
el problema de clasificación.
En este caso, definimos el cambio de coordenadas a mano. Pero si, en cambio,
intentáramos buscar sistemáticamente diferentes cambios de coordenadas posibles y
usáramos como retroalimentación el porcentaje de puntos que se clasificaron
correctamente, entonces estaríamos haciendo aprendizaje automático. El
aprendizaje, en el contexto del aprendizaje automático, describe un proceso de
búsqueda automática de mejores representaciones.
Todos los algoritmos de aprendizaje automático consisten en encontrar
automáticamente tales transformaciones que convierten los datos en representaciones
más útiles para una tarea determinada. Estas operaciones pueden ser cambios de

Con licencia para


coordenadas, como acabas de ver, o proyecciones lineales (que pueden destruir
información), traslaciones, operaciones no lineales (como “seleccionar todos los puntos
tales que x > 0”), etc. Los algoritmos de aprendizaje automático no suelen ser creativos
en

Con licencia para


8 CPASADO1¿Qué es el aprendizaje profundo?

encontrar estas transformaciones; simplemente están buscando a través de un


conjunto predefinido de operaciones, llamado espacio de hipótesis.
Entonces, eso es lo que es el aprendizaje automático, técnicamente: buscar
representaciones útiles de algunos datos de entrada, dentro de un espacio predefinido de
posibilidades, utilizando la guía de una señal de retroalimentación. Esta idea simple
permite resolver una gama notablemente amplia de tareas intelectuales, desde el
reconocimiento de voz hasta la conducción autónoma de automóviles.
Ahora que entiende lo que queremos decir con aprender, echemos un vistazo a lo que hace
aprendizaje profundoespecial.

1.1.4 Lo “profundo” en el aprendizaje profundo


El aprendizaje profundo es un subcampo específico del aprendizaje automático: una
nueva forma de aprender representaciones a partir de datos que pone énfasis en aprender
capas sucesivas de representaciones cada vez más significativas. Lo profundo en el
aprendizaje profundo no es una referencia a ningún tipo de comprensión más profunda
lograda por el enfoque; más bien, representa esta idea de capas sucesivas de
representaciones. La cantidad de capas que contribuyen a un modelo de los datos se
denomina profundidad del modelo. Otros nombres apropiados para el campo podrían
haber sidoaprendizaje de representaciones en capasy el aprendizaje de representaciones
jerárquicas. El aprendizaje profundo moderno a menudo implica decenas o incluso cientos
de capas sucesivas de representaciones, y todas se aprenden automáticamente a partir de la
exposición a los datos de entrenamiento. Mientras tanto, otros enfoques del aprendizaje
automático tienden a centrarse en aprender solo una o dos capas de representaciones de los
datos; por lo tanto, a veces se les llama aprendizaje superficial.
En el aprendizaje profundo, estas representaciones en capas se aprenden (casi
siempre) a través de modelos llamados redes neuronales, estructurados en capas
literales apiladas una encima de la otra. El término red neuronal es una referencia a
la neurobiología, pero aunque algunos de los conceptos centrales del aprendizaje
profundo se desarrollaron en parte inspirándose en nuestra comprensión del cerebro,
los modelos de aprendizaje profundo no son modelos del cerebro. No hay evidencia
de que el cerebro implemente algo parecido a los mecanismos de aprendizaje
utilizados en los modelos modernos de aprendizaje profundo. Es posible que se
encuentre con artículos de ciencia popular que proclamen que el aprendizaje
profundo funciona como el cerebro o fue modelado a partir del cerebro, pero ese no
es el caso. Sería confuso y contraproducente para los recién llegados al campo
pensar que el aprendizaje profundo está relacionado de alguna manera con la
neurobiología; no necesita ese manto de mística y misterio "como nuestras mentes",
y también puede olvidar todo lo que haya leído sobre los vínculos hipotéticos entre
el aprendizaje profundo y la biología. Para nuestros propósitos, el aprendizaje
profundo es un marco matemático para aprender representaciones a partir de datos.

Con licencia para


Inteligencia artificial, aprendizaje automático y profundidadaprendizaje 9

¿Cómo son las representaciones aprendidas por un algoritmo de aprendizaje


profundo? Examinemos cómo una red de varias capas de profundidad (ver figura
1.5) transforma la imagen de un dígito para reconocer qué dígito es.

Capa 1 Capa 2 Capa 3 Capa 4


entrada 0
origin 1
al 2
3
4 Final
5 produ
cción6
Figura 1.5 Una red neuronal
7
8 profunda para la clasificación
9 de dígitos

Como puede ver en la figura 1.6, la red transforma la imagen del dígito en
representaciones que son cada vez más diferentes de la imagen original y cada vez más
informativas sobre el resultado final. Puedes pensar en una red profunda como una
operación de destilación de información en varias etapas, donde la información pasa por
sucesivos filtros y sale cada vez más depurada (es decir, útil con respecto a alguna
tarea).

Representa Representa Representa


ciones de capa ciones de capa ciones de capa
1 2 3

Representacio
nes de capa 4
(salida final)

entrada 0
1
origin
2
al
3
4
5
6
7
8
9
Capa1Capa 2Capa 3Capa 4

Figura 1.6 Representaciones profundas aprendidas por un modelo de clasificación de dígitos

Así que eso es lo que es el aprendizaje profundo, técnicamente: una forma de múltiples
etapas para aprender representaciones de datos. Es una idea simple, pero resulta que
mecanismos muy simples, suficientemente escalados, pueden terminar pareciendo
magia.

1.1.5 Comprender cómo funciona el aprendizaje profundo, en tres cifras


En este punto, sabe que el aprendizaje automático se trata de asignar entradas (como
imágenes) a objetivos (como la etiqueta "gato"), lo que se hace observando muchos
ejemplos de entradas y objetivos. También sabe que las redes neuronales profundas
Con licencia para
hacen esta entrada al objetivo

Con licencia para


10 CPASADO1¿Qué es el aprendizaje profundo?

mapeo a través de una secuencia profunda de transformaciones de datos simples


(capas) y que estas transformaciones de datos se aprenden mediante la exposición a
ejemplos. Ahora veamos cómo ocurre este aprendizaje, concretamente.
La especificación de lo que hace una capa con sus datos de entrada se almacena
en los pesos de la capa, que en esencia son un montón de números. En términos
técnicos, diríamos que la transformación que implementa una capa está
parametrizada por sus pesos (ver figura 1.7). (Los pesos también se denominan a
veces los parámetros de una capa). En este contexto, aprender significa encontrar un
conjunto de valores para los pesos de todas las capas en una red, de modo que la red
asigne correctamente las entradas de ejemplo a sus objetivos asociados. Pero aquí
está la cuestión: una red neuronal profunda puede contener decenas de millones de
parámetros. Encontrar el valor correcto para todos ellos puede parecer una tarea
abrumadora, ¡especialmente dado que modificar el valor de un parámetro afectará el
comportamiento de todos los demás!

Entrada X

Capa
Pesos
Objetivo: (transformación de
encontrar los datos)
valores
Capa
correctos para
(transformación de
estos pesos datos)
Pesos
Prediccion
es Y'
Figura 1.7 Una red neuronal está
parametrizada por sus pesos.

Para controlar algo, primero necesitas ser capaz de observarlo. Para controlar la
salida de una red neuronal, debe poder medir qué tan lejos está esta salida de lo que
esperaba. Este es el trabajo de la función de pérdida de la red, también llamada
función objetivo. La función de pérdida toma las predicciones de la red y el
verdadero objetivo (lo que usted quería que generara la red) y calcula una
puntuación de distancia, capturando qué tan bien le ha ido a la red en este ejemplo
específico (consulte la figura 1.8).

Entrada X

Capa
Pesos
(transformación de
datos)

Capa
Pesos (transformación de
datos)

Prediccion Verdaderos
es Y' objetiv
os Y

Función de
pérdida

Figura 1.8Una función de pérdida


Puntuación
de pérdida
Con licencia para
mide la calidad de la salida de la red.

Con licencia para


Inteligencia artificial, aprendizaje automático y profundidadaprendizaje 11

El truco fundamental en el aprendizaje profundo es usar este puntaje como una


señal de retroalimentación para ajustar un poco el valor de los pesos, en una
dirección que reduzca el puntaje de pérdida para el ejemplo actual (ver figura 1.9).
Este ajuste es el trabajo del optimizador, que implementa lo que se llama el
algoritmo Backpropagation: el algoritmo central en el aprendizaje profundo. El
siguiente capítulo explica con más detalle cómo funciona la retropropagación.

Entrada X

Capa
Pesos
(transformación de
datos)

Capa
Pesos
(transformación de
datos)

Pesoa Prediccion Verdaderos


ctualiz es Y' objetiv
ar os Y

Optimiza Función de
dor pérdida

Figura 1.9 Se utiliza la puntuación de


Puntuación
pérdidacomo una señal de
de pérdida
retroalimentación para ajustar los pesos.

Inicialmente, a los pesos de la red se les asignan valores aleatorios, por lo que la red
simplemente implementa una serie de transformaciones aleatorias. Naturalmente, su
producción está lejos de lo que debería ser idealmente y, en consecuencia, la
puntuación de pérdida es muy alta. Pero con cada ejemplo que procesa la red, los
pesos se ajustan un poco en la dirección correcta y la puntuación de pérdida
disminuye. Este es el bucle de entrenamiento que, repetido un número suficiente de
veces (típicamente decenas de iteraciones en miles de ejemplos), produce valores de
peso que minimizan la función de pérdida. Una red con una pérdida mínima es
aquella en la que los resultados están lo más cerca posible de los objetivos: una red
entrenada. Una vez más, es un mecanismo simple que, una vez escalado, termina
pareciendo magia.

1.1.6 Lo que el aprendizaje profundo ha logrado hasta ahora


Aunque el aprendizaje profundo es un subcampo bastante antiguo del aprendizaje
automático, solo saltó a la fama a principios de la década de 2010. En los pocos
años transcurridos desde entonces, ha logrado nada menos que una revolución en el
campo, con resultados notables en problemas de percepción como la vista y el oído,
problemas que involucran habilidades que parecen naturales e intuitivas para los
humanos pero que han sido esquivas para las máquinas durante mucho tiempo.
En particular, el aprendizaje profundo ha logrado los siguientes avances, todos
en áreas históricamente difíciles del aprendizaje automático:
◾ Clasificación de imágenes casi a nivel humano
◾ Reconocimiento de voz casi a nivel humano

Con licencia para


◾ Transcripción de escritura a mano casi a nivel humano
◾ Traducción automática mejorada

Con licencia para


12 CPASADO1¿Qué es el aprendizaje profundo?

◾ Conversión de texto a voz mejorada


◾ Asistentes digitales como Google Now y Amazon Alexa
◾ Conducción autónoma casi a nivel humano
◾ Orientación de anuncios mejorada, tal como la utilizan Google, Baidu y Bing
◾ Resultados de búsqueda mejorados en la web
◾ Capacidad para responder preguntas en lenguaje natural.
◾ Sobrehumano Ve a jugar

Todavía estamos explorando el alcance total de lo que puede hacer el aprendizaje


profundo. Hemos comenzado a aplicarlo a una amplia variedad de problemas fuera de la
percepción de la máquina y la comprensión del lenguaje natural, como el razonamiento
formal. Si tiene éxito, esto puede presagiar una era en la que el aprendizaje profundo
ayude a los humanos en la ciencia, el desarrollo de software y más.

1.1.7 No creas el bombo a corto plazo


Aunque el aprendizaje profundo ha llevado a logros notables en los últimos años,
las expectativas de lo que el campo podrá lograr en la próxima década tienden a ser
mucho más altas de lo que probablemente será posible. Si bien algunas aplicaciones
que cambiarán el mundo, como los automóviles autónomos, ya están al alcance de
la mano, es probable que muchas más sigan siendo esquivas durante mucho tiempo,
como los sistemas de diálogo creíbles, la traducción automática a nivel humano en
idiomas arbitrarios y la comprensión del lenguaje natural a nivel humano. En
particular, hablar de inteligencia general a nivel humano no debe tomarse
demasiado en serio. El riesgo con altas expectativas a corto plazo es que, a medida
que la tecnología no funcione, la inversión en investigación se agotará, lo que
ralentizará el progreso durante mucho tiempo.
Esto ha sucedido antes. Dos veces en el pasado, AI pasó por un ciclo de intenso
optimismo seguido de decepción y escepticismo, lo que resultó en una escasez de
fondos. Comenzó con la IA simbólica en la década de 1960. En aquellos primeros
días, las proyecciones sobre la IA eran muy altas. Uno de los pioneros y defensores
más conocidos del enfoque de la IA simbólica fue Marvin Minsky, quien afirmó en
1967: "Dentro de una generación... el problema de crear 'inteligencia artificial' se
resolverá sustancialmente". Tres años después, en 1970, hizo una predicción
cuantificada con mayor precisión: “Dentro de tres a ocho años tendremos una
máquina con la inteligencia general de un ser humano promedio”. En 2016, tal logro
todavía parece estar muy lejos en el futuro, tan lejos que no tenemos forma de
predecir cuánto tiempo tomará, pero en la década de 1960 y principios de la de
1970, varios expertos creían que estaba a la vuelta de la esquina (al igual que
muchas personas hoy en día). Unos años más tarde, cuando estas altas expectativas
no se materializaron, los investigadores y los fondos del gobierno se apartaron del
campo, lo que marcó el comienzo del primer invierno de IA (una referencia a un
invierno nuclear, porque esto fue poco después del apogeo de la IA). Guerra Fría).
No sería el último. En la década de 1980, una nueva versión de la IA simbólica, los
sistemas expertos, comenzó a cobrar fuerza entre las grandes empresas. Algunas
historias de éxito iniciales desencadenaron una ola de inversión, con corporaciones de
todo el mundo que comenzaron sus propios departamentos de IA internos para
Con licencia para
desarrollar sistemas expertos. Alrededor de 1985, las empresas gastaban más de mil
millones de dólares cada año en tecnología; pero a principios de la década de 1990,
estos sistemas habían demostrado ser costosos de mantener, difíciles de escalar y de
alcance limitado, y el interés se extinguió. Así comenzó el segundo invierno AI.

Con licencia para


Inteligencia artificial, aprendizaje automático y profundidadaprendizaje 13

Es posible que actualmente estemos presenciando el tercer ciclo de exageración


y decepción de la IA, y todavía estamos en la fase de intenso optimismo. Es mejor
moderar nuestras expectativas a corto plazo y asegurarnos de que las personas
menos familiarizadas con el aspecto técnico del campo tengan una idea clara de lo
que el aprendizaje profundo puede y no puede ofrecer.

1.1.8 La promesa de la IA
Aunque es posible que tengamos expectativas poco realistas a corto plazo para la
IA, el panorama a largo plazo se ve brillante. Apenas estamos comenzando a aplicar
el aprendizaje profundo a muchos problemas importantes para los que podría
resultar transformador, desde diagnósticos médicos hasta asistentes digitales. La
investigación de la IA ha avanzado sorprendentemente rápido en los últimos cinco
años, en gran parte debido a un nivel de financiación nunca antes visto en la corta
historia de la IA, pero hasta ahora, relativamente poco de este progreso ha llegado a
los productos y procesos. que forman nuestro mundo. La mayoría de los hallazgos
de la investigación sobre el aprendizaje profundo aún no se aplican, o al menos no
se aplican a la gama completa de problemas que pueden resolver en todas las
industrias. Su médico aún no usa IA, y tampoco su contador. Probablemente no
utilice tecnologías de inteligencia artificial en su vida cotidiana. Por supuesto, puede
hacer preguntas sencillas a su teléfono inteligente y obtener respuestas razonables,
puede obtener recomendaciones de productos bastante útiles en Amazon.com y
puede buscar "cumpleaños" en Google Photos y encontrar instantáneamente las
imágenes de la fiesta de cumpleaños de su hija del mes pasado. Eso está muy lejos
de donde solían estar tales tecnologías. Pero tales herramientas siguen siendo solo
accesorios para nuestra vida diaria. La IA aún tiene que hacer la transición para ser
central en la forma en que trabajamos, pensamos y vivimos. Pero tales herramientas
siguen siendo solo accesorios para nuestra vida diaria. La IA aún tiene que hacer la
transición para ser central en la forma en que trabajamos, pensamos y vivimos. Pero
tales herramientas siguen siendo solo accesorios para nuestra vida diaria. La IA aún
tiene que hacer la transición para ser central en la forma en que trabajamos,
pensamos y vivimos.
En este momento, puede parecer difícil creer que la IA podría tener un gran
impacto en nuestro mundo, porque aún no está ampliamente implementada, al igual
que, en 1995, hubiera sido difícil creer en el impacto futuro de Internet. . En aquel
entonces, la mayoría de la gente no veía cómo Internet era relevante para ellos y
cómo iba a cambiar sus vidas. Lo mismo es cierto para el aprendizaje profundo y la
IA en la actualidad. Pero no se equivoquen: la IA está llegando. En un futuro no
muy lejano, la IA será su asistente, incluso su amiga; responderá a sus preguntas,
ayudará a educar a sus hijos y velará por su salud. Entregará sus compras en su
puerta y lo llevará del punto A al punto B. Será su interfaz para un mundo cada vez
más complejo e intensivo en información. Y, lo que es más importante, la IA
ayudará a la humanidad en su conjunto a avanzar,
En el camino, es posible que enfrentemos algunos contratiempos y tal vez un
nuevo invierno de IA, de la misma manera que la industria de Internet fue
sobrevalorada en 1998-1999 y sufrió un colapso que agotó la inversión a principios

Con licencia para


de la década de 2000. Pero llegaremos allí eventualmente. La IA terminará
aplicándose a casi todos los procesos que conforman nuestra sociedad y nuestra vida
diaria, al igual que Internet en la actualidad.
No crea en la exageración a corto plazo, pero crea en la visión a largo plazo.
Puede tomar un tiempo para que la IA se despliegue en su verdadero potencial, un
potencial con el que nadie se ha atrevido a soñar todavía, pero la IA está llegando y
transformará nuestro mundo de una manera fantástica.

Con licencia para


14 CPASADO1¿Qué es el aprendizaje profundo?

1.2 Antes del aprendizaje profundo:


una breve historia del aprendizaje automático
El aprendizaje profundo ha alcanzado un nivel de atención pública e inversión de la
industria nunca antes visto en la historia de la IA, pero no es la primera forma
exitosa de aprendizaje automático. Es seguro decir que la mayoría de los algoritmos
de aprendizaje automático utilizados en la industria hoy en día no son algoritmos de
aprendizaje profundo. El aprendizaje profundo no siempre es la herramienta
adecuada para el trabajo: a veces no hay suficientes datos para que el aprendizaje
profundo sea aplicable y, a veces, el problema se resuelve mejor con un algoritmo
diferente. Si el aprendizaje profundo es su primer contacto con el aprendizaje
automático, es posible que se encuentre en una situación en la que todo lo que tiene
es un martillo de aprendizaje profundo y cada problema de aprendizaje automático
comienza a parecerse a un clavo. La única forma de no caer en esta trampa es
familiarizarse con otros enfoques y practicarlos cuando sea apropiado.
Una discusión detallada de los enfoques clásicos de aprendizaje automático está
fuera del alcance de este libro, pero los repasaremos brevemente y describiremos el
contexto histórico en el que se desarrollaron. Esto nos permitirá ubicar el
aprendizaje profundo en el contexto más amplio del aprendizaje automático y
comprender mejor de dónde proviene el aprendizaje profundo y por qué es
importante.

1.2.1 Modelado probabilístico


Modelado probabilísticoes la aplicación de los principios de la estadística al análisis de
datos. Fue una de las primeras formas de aprendizaje automático y todavía se usa
ampliamente hasta el día de hoy. Uno de los algoritmos más conocidos en esta categoría
es el algoritmo Naive Bayes.
Naive Bayes es un tipo de clasificador de aprendizaje automático que se basa en la
aplicación del teorema de Bayes al asumir que las características en los datos de entrada
son todas independientes (una suposición fuerte o “ingenua”, de donde proviene el
nombre). Esta forma de análisis de datos es anterior a las computadoras y se aplicó a
mano décadas antes de su primera implementación en computadora (probablemente en
la década de 1950). El teorema de Bayes y los fundamentos de la estadística se
remontan al siglo XVIII, y esto es todo lo que necesita para comenzar a utilizar los
clasificadores Naive Bayes.
Un modelo estrechamente relacionado es la regresión logística (logreg para
abreviar), que a veces se considera el “hola mundo” del aprendizaje automático
moderno. No se deje engañar por su nombre: logreg es un algoritmo de clasificación en
lugar de un algoritmo de regresión. Al igual que Naive Bayes, logreg es anterior a la
informática por mucho tiempo, pero sigue siendo útil hasta el día de hoy, gracias a su
naturaleza simple y versátil. A menudo, es lo primero que un científico de datos probará
en un conjunto de datos para tener una idea de la tarea de clasificación en cuestión.

1.2.2 Primeras redes neuronales


Las primeras iteraciones de las redes neuronales han sido suplantadas por completo por
las variantes modernas cubiertas en estas páginas, pero es útil saber cómo se originó el
Con licencia para
aprendizaje profundo. Aunque las ideas centrales de las redes neuronales se investigaron
en formas de juguete ya en la década de 1950, el enfoque tardó décadas en comenzar.
Durante mucho tiempo, la pieza que faltaba era una forma eficiente de entrenar grandes
redes neuronales. Esto cambió a mediados de la década de 1980,

Con licencia para


Antes del aprendizaje profundo: una breve historia de la máquinaaprendizaje 15

cuando varias personas redescubrieron de forma independiente el algoritmo


Backpropagation, una forma de entrenar cadenas de operaciones paramétricas
mediante la optimización de descenso de gradiente (más adelante en el libro,
definiremos con precisión estos conceptos), y comenzaron a aplicarlo a las redes
neuronales.
La primera aplicación práctica exitosa de redes neuronales se produjo en 1989
de Bell Labs, cuando Yann LeCun combinó las ideas anteriores de redes neuronales
convolucionales y retropropagación, y las aplicó al problema de clasificar dígitos
escritos a mano. La red resultante, denominada LeNet, fue utilizada por el Servicio
Postal de los Estados Unidos en la década de 1990 para automatizar la lectura de
códigos postales en sobres de correo.

1.2.3 Métodos del núcleo


A medida que las redes neuronales comenzaron a ganar cierto respeto entre los
investigadores en la década de 1990, gracias a este primer éxito, un nuevo enfoque para
el aprendizaje automático saltó a la fama y rápidamente hizo que las redes neuronales
volvieran al olvido: los métodos kernel. Los métodos del núcleo son un grupo de
algoritmos de clasificación, el más conocido de los cuales es la máquina de vectores de
soporte (SVM). La formulación moderna de una SVM fue desarrollada por Vladimir
Vapnik y Corinna Cortes a principios de la década de 1990 en
Bell Labs y publicado en 1995,2 aunque Vapnik y Alexey
Chervonenkis publicaron una formulación lineal más antigua
ya en 1963.3 Las SVM tienen como objetivo resolver
problemas de clasificación encontrando buenos límites de
decisión (consulte la figura 1.10) entre dos conjuntos de puntos
pertenecientes a dos categorías diferentes. Un límite de
decisión se puede considerar como una línea o superficie que
separa los datos de entrenamiento en dos espacios
correspondientes a dos categorías. Para clasificar nuevos
puntos de datos, solo necesita verificar de qué lado del límite Figura 1.10
de decisión se encuentran. Un límite de decisión
Las SVM proceden a encontrar estos límites en dos pasos:
1Los datos se asignan a una nueva representación de alta dimensión donde el
límite de decisión se puede expresar como un hiperplano (si los datos fueran
bidimensionales, como en la figura 1.10, un hiperplano sería una línea recta).
2Un buen límite de decisión (un hiperplano de separación) se calcula tratando de
maximizar la distancia entre el hiperplano y los puntos de datos más cercanos de
cada clase, un paso denominado maximizar el margen. Esto permite que el límite
se generalice bien a nuevas muestras fuera del conjunto de datos de
entrenamiento.
La técnica de mapear datos a una representación de alta dimensión donde un
problema de clasificación se vuelve más simple puede verse bien en el papel, pero
en la práctica a menudo es computacionalmente intratable. Ahí es donde entra en
juego el truco del kernel (la idea clave que da nombre a los métodos del kernel).
Aquí está la esencia de esto: encontrar una buena decisión
Con licencia para
2
Vladimir Vapnik y Corinna Cortes, "Redes de vectores de apoyo", Machine Learning 20, no. 3 (1995): 273–297.
3
Vladimir Vapnik y Alexey Chervonenkis, "Una nota sobre una clase de perceptrones", Automatización y control
remoto 25 (1964).

Con licencia para


dieciséis CPASADO1¿Qué es el aprendizaje profundo?

hiperplanos en el nuevo espacio de representación, no tiene que calcular


explícitamente las coordenadas de sus puntos en el nuevo espacio; solo necesita
calcular la distancia entre pares de puntos en ese espacio, lo que se puede hacer de
manera eficiente usando una función del núcleo. Una función kernel es una
operación manejable computacionalmente que mapea dos puntos cualquiera en su
espacio inicial a la distancia entre estos puntos en su espacio de representación de
destino, omitiendo por completo el cálculo explícito de la nueva representación. Las
funciones del kernel generalmente se elaboran a mano en lugar de aprenderse de los
datos; en el caso de una SVM, solo se aprende el hiperplano de separación.
En el momento en que se desarrollaron, las SVM exhibían un rendimiento de
vanguardia en problemas de clasificación simples y eran uno de los pocos métodos
de aprendizaje automático respaldados por una teoría extensa y susceptibles de un
análisis matemático serio, haciéndolos bien comprensibles y fáciles de interpretar.
Debido a estas útiles propiedades, las SVM se volvieron extremadamente populares
en el campo durante mucho tiempo.
Pero las SVM resultaron difíciles de escalar a grandes conjuntos de datos y no
proporcionaron buenos resultados para problemas de percepción como la clasificación
de imágenes. Debido a que una SVM es un método superficial, aplicar una SVM a los
problemas de percepción requiere primero extraer manualmente representaciones útiles
(un paso llamado ingeniería de características), lo cual es difícil y frágil.

1.2.4 Árboles de decisión, bosques aleatorios y máquinas potenciadoras de gradientes


Árboles de decisiónson estructuras similares a diagramas de flujo que le permiten
clasificar puntos de datos de entrada o predecir valores de salida dadas las entradas
(consulte la figura 1.11). Son fáciles de visualizar e interpretar. Los árboles de
decisiones aprendidos de los datos comenzaron a recibir un interés de investigación
significativo en la década de 2000 y, para 2010, a menudo se preferían a los métodos
kernel.

Datos de entrada

Pregunta

Pregunta Pregunta Figura 1.11 Un árbol de decisión: los


parámetros que se aprenden son las preguntas
sobre los datos. Una pregunta podría ser, por
Categoría Categoría ejemplo, "¿Es el coeficiente 2 en los datos
Categorí Categorí
a a
mayor que 3.5?"

En particular, el algoritmo Random Forest introdujo una versión sólida y práctica


del aprendizaje de árboles de decisión que implica construir una gran cantidad de
árboles de decisión especializados y luego ensamblar sus resultados. Los bosques
aleatorios son aplicables a una amplia gama de problemas; se podría decir que casi
siempre son el segundo mejor algoritmo para cualquier tarea superficial de
aprendizaje automático. Cuando el popular sitio web de competencia de aprendizaje

Con licencia para


automático Kaggle (http://kaggle.com) comenzó en 2010, los bosques aleatorios se
convirtieron rápidamente en uno de los favoritos en la plataforma, hasta 2014,
cuando las máquinas de aumento de gradiente se hicieron cargo. Una máquina de
aumento de gradiente, al igual que un bosque aleatorio, es una técnica de
aprendizaje automático basada en el ensamblaje de modelos de predicción débiles,
generalmente árboles de decisión. Eso

Con licencia para


Antes del aprendizaje profundo: una breve historia de la máquinaaprendizaje 17

utiliza el refuerzo de gradiente, una forma de mejorar cualquier modelo de aprendizaje


automático mediante el entrenamiento iterativo de nuevos modelos que se especializan en
abordar los puntos débiles de los modelos anteriores. Aplicado a los árboles de decisión, el
uso de la técnica de aumento de gradiente da como resultado modelos que superan
estrictamente a los bosques aleatorios la mayor parte del tiempo, mientras que tienen
propiedades similares. Puede ser uno de los mejores, si no el mejor, algoritmo para tratar con
datos no perceptivos en la actualidad. Junto con el aprendizaje profundo, es una de las
técnicas más utilizadas en las competiciones de Kaggle.

1.2.5 volver a neuralredes


Alrededor de 2010, aunque las redes neuronales fueron rechazadas casi por
completo por la comunidad científica en general, varias personas que todavía
trabajaban en redes neuronales comenzaron a hacer avances importantes: los grupos
de Geoffrey Hinton en la Universidad de Toronto, Yoshua Bengio en la Universidad
de Montreal, Yann LeCun en la Universidad de Nueva York e IDSIA en Suiza.
En 2011, Dan Ciresan de IDSIA comenzó a ganar concursos académicos de
clasificación de imágenes con redes neuronales profundas entrenadas en GPU, el primer
éxito práctico del aprendizaje profundo moderno. Pero el momento decisivo llegó en
2012, con la entrada del grupo de Hinton en el desafío anual de clasificación de
imágenes a gran escala ImageNet. El desafío de ImageNet era notoriamente difícil en
ese momento, consistía en clasificar imágenes en color de alta resolución en 1000
categorías diferentes después de entrenar con 1,4 millones de imágenes. En 2011, la
precisión entre los cinco primeros del modelo ganador, basado en los enfoques clásicos
de la visión artificial, fue solo del 74,3 %. Luego, en 2012, un equipo dirigido por Alex
Krizhevsky y asesorado por Geoffrey Hinton pudo lograr una precisión entre los cinco
primeros del 83,6 %, un avance significativo. La competencia ha estado dominada por
redes neuronales convolucionales profundas cada año desde entonces. Para 2015, el
ganador alcanzó una precisión del 96,4% y la tarea de clasificación en ImageNet se
consideró como un problema completamente resuelto.
Desde 2012, las redes neuronales convolucionales profundas (convnets) se han
convertido en el algoritmo de referencia para todas las tareas de visión artificial; más
generalmente, trabajan en todas las tareas perceptivas. En las principales conferencias
de visión por computadora en 2015 y 2016, fue casi imposible encontrar presentaciones
que no involucraran convenciones de alguna forma. Al mismo tiempo, el aprendizaje
profundo también ha encontrado aplicaciones en muchos otros tipos de problemas,
como el procesamiento del lenguaje natural. Ha reemplazado por completo las SVM y
los árboles de decisión en una amplia gama de aplicaciones. Por ejemplo, durante varios
años, la Organización Europea para la Investigación Nuclear, CERN, utilizó métodos
basados en árboles de decisión para el análisis de datos de partículas del detector
ATLAS en el Gran Colisionador de Hadrones (LHC);

1.2.6 Qué hace que el aprendizaje profundo sea diferente


La razón principal por la que el aprendizaje profundo despegó tan rápidamente es
que ofrecía un mejor rendimiento en muchos problemas. Pero esa no es la única
razón. El aprendizaje profundo también hace

Con licencia para


18 CPASADO1¿Qué es el aprendizaje profundo?

la resolución de problemas es mucho más fácil, porque automatiza por completo lo


que solía ser el paso más crucial en un flujo de trabajo de aprendizaje automático: la
ingeniería de características.
Las técnicas anteriores de aprendizaje automático (aprendizaje superficial) solo
involucraban la transformación de los datos de entrada en uno o dos espacios de
representación sucesivos, generalmente a través de transformaciones simples como
proyecciones no lineales (SVM) de alta dimensión o árboles de decisión. Pero las
representaciones refinadas requeridas por problemas complejos generalmente no se
pueden lograr con tales técnicas. Como tal, los humanos tuvieron que hacer todo lo
posible para que los datos de entrada iniciales fueran más fáciles de procesar con estos
métodos: tuvieron que diseñar manualmente buenas capas de representaciones para sus
datos. Esto se llama ingeniería de características. El aprendizaje profundo, por otro lado,
automatiza completamente este paso: con el aprendizaje profundo, aprende todas las
funciones de una vez en lugar de tener que diseñarlas usted mismo. Esto ha simplificado
enormemente los flujos de trabajo de aprendizaje automático,
Puede preguntarse, si el quid de la cuestión es tener múltiples capas sucesivas de
representaciones, ¿podrían aplicarse repetidamente métodos superficiales para emular
los efectos del aprendizaje profundo? En la práctica, hay rendimientos rápidamente
decrecientes para aplicaciones sucesivas.ciones de métodos de aprendizaje superficial,
porque la primera capa de representación óptima en un modelo de tres capas no es la primera
capa óptima en un modelo de una o dos capas. Lo transformador del aprendizaje profundo es
que permite que un modelo aprenda todas las capas de representación de forma conjunta, al
mismo tiempo, en lugar de en sucesión (con avidez, como se le llama). Con el aprendizaje
conjunto de características, cada vez que el modelo ajusta una de sus características internas,
todas las demás características que dependen de él se adaptan automáticamente al cambio,
sin necesidad de intervención humana. Todo está supervisado por una única señal de
retroalimentación: cada cambio en el modelo sirve al objetivo final. Esto es mucho más
poderoso que apilar modelos superficiales con avidez, porque permite modelos complejos y
representaciones abstractas para ser aprendidas descomponiéndolas en largas series de
espacios intermedios (capas); cada espacio es solo una simple transformación del anterior.
Estas son las dos características esenciales de cómo el aprendizaje profundo aprende
de los datos: la forma incremental, capa por capa, en la que se desarrollan
representaciones cada vez más complejas,y el hecho de que estoslas representaciones
incrementales intermedias se aprenden conjuntamente, cada capa se actualiza para seguir
tanto las necesidades de representación de la capa superior como las necesidades de la capa
inferior. Juntas, estas dos propiedades han hecho que el aprendizaje profundo sea mucho
más exitoso que los enfoques anteriores del aprendizaje automático.

1.2.7 El panorama moderno del aprendizaje automático


Una excelente manera de tener una idea del panorama actual de los algoritmos y
herramientas de aprendizaje automático es observar las competencias de aprendizaje
automático en Kaggle. Debido a su entorno altamente competitivo (algunos
concursos tienen miles de participantes y premios de millones de dólares) y a la
amplia variedad de problemas de aprendizaje automático cubiertos, Kaggle ofrece
una forma realista de evaluar qué funciona y qué no. Entonces, ¿qué tipo de

Con licencia para


algoritmo está ganando competencias de manera confiable? ¿Qué herramientas
utilizan los principales participantes?

Con licencia para


Antes del aprendizaje profundo: una breve historia de la máquinaaprendizaje 19

En 2016 y 2017, Kaggle estuvo dominado por dos enfoques: máquinas de aumento
de gradiente y aprendizaje profundo. Específicamente, el aumento de gradiente se usa
para problemas en los que hay datos estructurados disponibles, mientras que el
aprendizaje profundo se usa para problemas de percepción como la clasificación de
imágenes. Los practicantes del primero casi siempre usan la excelente biblioteca
XGBoost, que ofrece soporte para los dos lenguajes más populares de la ciencia de
datos: Python y R. Mientras tanto, la mayoría de los participantes de Kaggle que usan
aprendizaje profundo usan la biblioteca Keras, debido a su facilidad. de uso, flexibilidad
y soporte de Python.
Estas son las dos técnicas con las que debe estar más familiarizado para tener
éxito en el aprendizaje automático aplicado hoy en día: máquinas potenciadoras de
gradientes, para problemas de aprendizaje superficial; y aprendizaje profundo, para
problemas de percepción. En términos técnicos, esto significa que deberá estar
familiarizado con XGBoost y Keras, las dos bibliotecas que actualmente dominan
las competencias de Kaggle. Con este libro en la mano, ya estás un paso más cerca.

Con licencia para


20 CPASADO1¿Qué es el aprendizaje profundo?

1.3 ¿Por qué aprendizaje profundo? ¿Porqué ahora?


Las dos ideas clave del aprendizaje profundo para la visión por computadora (redes
neuronales convolucionales y retropropagación) ya se entendían bien en 1989. El
algoritmo de memoria a corto plazo (LSTM), que es fundamental para el
aprendizaje profundo para series temporales, se desarrolló en 1997. y apenas ha
cambiado desde entonces. Entonces, ¿por qué el aprendizaje profundo solo despegó
después de 2012? ¿Qué cambió en estas dos décadas?
En general, tres fuerzas técnicas están impulsando los avances en el aprendizaje
automático:
◾ Hardware
◾ Conjuntos de datos y puntos de referencia
◾ Avances algorítmicos

Debido a que el campo está guiado por hallazgos experimentales en lugar de teoría,
los avances algorítmicos solo son posibles cuando los datos y el hardware
apropiados están disponibles para probar nuevas ideas (o ampliar ideas antiguas,
como suele ser el caso). El aprendizaje automático no son matemáticas o física,
donde se pueden lograr grandes avances con un lápiz y una hoja de papel. Es una
ciencia de la ingeniería.
Los cuellos de botella reales a lo largo de las décadas de 1990 y 2000 fueron los
datos y el hardware. Pero esto es lo que sucedió durante ese tiempo: Internet
despegó y se desarrollaron chips gráficos de alto rendimiento para las necesidades
del mercado de los juegos.

1.3.1 Hardware
Entre 1990 y 2010, las CPU comerciales se volvieron más rápidas en un factor de
aproximadamente 5000. Como resultado, hoy en día es posible ejecutar pequeños
modelos de aprendizaje profundo en su computadora portátil, mientras que esto habría
sido intratable hace 25 años.
Pero los modelos típicos de aprendizaje profundo utilizados en la visión por
computadora o el reconocimiento de voz requieren órdenes de magnitud más de
poder computacional que lo que su computadora portátil puede ofrecer. A lo largo
de la década de 2000, empresas como NVIDIA y AMD han estado invirtiendo miles
de millones de dólares en el desarrollo de chips (unidades de procesamiento gráfico
[GPU]) rápidos y masivamente paralelos para potenciar los gráficos de videojuegos
cada vez más fotorrealistas: supercomputadoras baratas de un solo propósito
diseñadas para renderizar complejos. Escenas 3D en tu pantalla en tiempo real. Esta
inversión vino a beneficiar a la comunidad científica cuando, en 2007, NVIDIAlanzó
CUDA (https://developer.nvidia.com/about-cuda), ap a g s interfaz de programación
para su línea de GPU. Una pequeña cantidad de GPU comenzó a reemplazar
grupos masivos de CPU en varias aplicaciones altamente paralelizables,
comenzando con el modelado físico. Las redes neuronales profundas, que
consisten principalmente en muchas pequeñas multiplicaciones de matriz,
también son altamente paralelizables; y alrededor de 2011, algunos
investigadores comenzaron a escribir implementaciones CUDA de redes
neuronales: Dan Ciresan4 y Alex Krizhevsky5 estuvieron entre los primeros.
Con licencia para
4 Véase “Redes neuronales convolucionales flexibles y de alto rendimiento para la clasificación de imágenes”, Actas de la 22. ª Conferencia Internacional Conjunta sobre
Inteligencia Artificial (2011),
www.ijcai.org/Proceedings/11/Papers/ 210.pdf.
5
Consulte "Clasificación de ImageNet con redes neuronales convolucionales profundas", Avances en los sistemas de
procesamiento de información neuronal 25 (2012),http://mng.bz/2286.

Con licencia para


¿Por qué aprendizaje profundo? Por qué¿ahora? 21

Lo que pasó es que el mercado del juego subsidió la supercomputación para la


próxima generación de aplicaciones de inteligencia artificial. A veces, las cosas
grandes comienzan como juegos. Hoy, NVIDIA TITAN X, una GPU para juegos
que costó $1000 a finales de 2015, puede ofrecer un máximo de 6,6 TFLOPS en
precisión simple: 6,6 billones de operaciones float32 por segundo. Eso es
aproximadamente 350 veces más de lo que puede obtener de una computadora
portátil moderna. En una TITAN X, solo se necesitan un par de días para entrenar
un modelo ImageNet del tipo que habría ganado la competencia ILSVRC hace unos
años. Mientras tanto, las grandes empresas entrenan modelos de aprendizaje
profundo en clústeres de cientos de GPU de un tipo desarrollado específicamente
para las necesidades de aprendizaje profundo, como NVIDIA Tesla K80.
Además, la industria del aprendizaje profundo está comenzando a ir más allá de
las GPU y está invirtiendo en chips cada vez más especializados y eficientes para el
aprendizaje profundo. En 2016, en su convención anual de E/S, Google reveló su
proyecto de unidad de procesamiento de tensor (TPU): un nuevo diseño de chip
desarrollado desde cero para ejecutar redes neuronales profundas, que según se
informa es 10 veces más rápido y mucho más eficiente energéticamente que los
mejores. GPU de última generación.

1.3.2 Datos
La IA a veces se anuncia como la nueva revolución industrial. Si el aprendizaje
profundo es la máquina de vapor de esta revolución, entonces los datos son su carbón: la
materia prima que impulsa nuestras máquinas inteligentes, sin la cual nada sería posible.
Cuando se trata de datos, además del progreso exponencial en el hardware de
almacenamiento en los últimos 20 años (siguiendo la ley de Moore), el cambio de juego
ha sido el auge de Internet, que hace factible recopilar y distribuir grandes cantidades de
datos. conjuntos de datos para el aprendizaje automático. Hoy en día, las grandes
empresas trabajan con conjuntos de datos de imágenes, conjuntos de datos de video y
conjuntos de datos en lenguaje natural que no podrían haberse recopilado sin Internet.
Las etiquetas de imágenes generadas por los usuarios en Flickr, por ejemplo, han sido
un tesoro de datos para la visión artificial. También lo son los videos de YouTube. Y
Wikipedia es un conjunto de datos clave para el procesamiento del lenguaje natural.
Si hay un conjunto de datos que ha sido un catalizador para el auge del
aprendizaje profundo, es el conjunto de datos de ImageNet, que consta de 1,4
millones de imágenes que se han anotado a mano con 1000 categorías de imágenes
(1 categoría por imagen). Pero lo que hace que ImageNet sea especial no es solo su
gran tamaño, sino también la competencia anual asociada con él.6
Como ha estado demostrando Kaggle desde 2010, los concursos públicos son
una forma excelente de motivar a los investigadores e ingenieros a ir más allá. Tener
puntos de referencia comunes por los que los investigadores compiten ha ayudado
en gran medida al reciente aumento del aprendizaje profundo.

1.3.3 Algoritmos
Además del hardware y los datos, hasta finales de la década de 2000, nos faltaba una
forma confiable de entrenar redes neuronales muy profundas. Como resultado, las redes
neuronales aún eran bastante superficiales,
Con licencia para
6 El desafío de reconocimiento visual a gran escala de ImageNet (ILSVRC),
www.image-net.org/challenges/LSVRC.

Con licencia para


22 CPASADO1¿Qué es el aprendizaje profundo?

usando solo una o dos capas de representaciones; por lo tanto, no pudieron brillar contra
métodos superficiales más refinados, como SVM y bosques aleatorios. El tema clave
fue el de la propagación del gradiente a través de pilas profundas de capas. La señal de
retroalimentación utilizada para entrenar las redes neuronales se desvanecería a medida
que aumentara el número de capas.
Esto cambió alrededor de 2009-2010 con la llegada de varias mejoras algorítmicas simples
pero importantes que permitieron una mejor propagación del gradiente:
◾ Mejores funciones de activación para las capas neuronales
◾ Mejores esquemas de inicialización de peso, comenzando con el entrenamiento
previo por capas, que se abandonó rápidamente
◾ Mejores esquemas de optimización, tales como RMSProp y adam

Solo cuando estas mejoras comenzaron a permitir modelos de entrenamiento con 10


o más capas, el aprendizaje profundo comenzó a brillar.
Finalmente, en 2014, 2015 y 2016, se descubrieron formas aún más avanzadas de
ayudar a la propagación de gradientes, como la normalización por lotes, las conexiones
residuales y las circunvoluciones separables en profundidad. Hoy podemos entrenar
desde cero modelos que tienen miles de capas de profundidad.

1.3.4 Una nueva ola de inversión


A medida que el aprendizaje profundo se convirtió en el nuevo estado del arte para
la visión por computadora en 2012-2013 y, finalmente, para todas las tareas de
percepción, los líderes de la industria tomaron nota. Lo que siguió fue una ola
gradual de inversión de la industria mucho más allá de lo visto anteriormente en la
historia de la IA.
En 2011, justo antes de que el aprendizaje profundo tomara protagonismo, la
inversión total de capital de riesgo en IA fue de alrededor de $19 millones, que se
destinaron casi en su totalidad a aplicaciones prácticas de enfoques de aprendizaje
automático superficial. Para 2014, había aumentado a un nivel asombroso
$ 394 millones. Docenas de nuevas empresas se lanzaron en estos tres años, tratando de
capitalizar la exageración del aprendizaje profundo. Mientras tanto, las grandes
empresas tecnológicas como Google, Facebook, Baidu y Microsoft han invertido en
departamentos de investigación internos en cantidades que muy probablemente
eclipsarían el flujo de dinero de capital de riesgo. Solo han surgido unos pocos números:
en 2013, Google adquirió la startup de aprendizaje profundo DeepMind por 500
millones de dólares, la mayor adquisición de una empresa de IA en la historia. En 2014,
Baidu inició un centro de investigación de aprendizaje profundo en Silicon Valley,
invirtiendo $300 millones en el proyecto. Intel adquirió la startup de hardware de
aprendizaje profundo Nervana Systems en 2016 por más de 400 millones de dólares.
El aprendizaje automático, en particular, el aprendizaje profundo, se ha vuelto
fundamental para la estrategia de producto de estos gigantes tecnológicos. A fines
de 2015, el CEO de Google, Sundar Pichai, declaró: “El aprendizaje automático es
una forma central y transformadora mediante la cual estamos repensando cómo lo
hacemos todo. Lo estamos aplicando cuidadosamente en todos nuestros productos,
ya sea búsqueda, anuncios, YouTube o Play. Y estamos en los primeros días, pero

Con licencia para


nos verá, de manera sistemática, aplicar el aprendizaje automático en todas estas
áreas”.7
7 Sundar Pichai, llamada de ganancias de Alphabet, 22 de octubre de 2015.

Con licencia para


¿Por qué aprendizaje profundo? Por qué¿ahora? 23

Como resultado de esta ola de inversión, la cantidad de personas que trabajan en el


aprendizaje profundo pasó de unos pocos cientos a decenas de miles en solo cinco años,
y el progreso de la investigación ha alcanzado un ritmo frenético. Actualmente no hay
señales de que esta tendencia se desacelerará en el corto plazo.

1.3.5 La democratización del aprendizaje profundo


Uno de los factores clave que impulsan este flujo de nuevas caras en el aprendizaje
profundo ha sido la democratización de los conjuntos de herramientas que se
utilizan en el campo. En los primeros días, el aprendizaje profundo requería una
experiencia significativa en C++ y CUDA, que pocas personas poseían. Hoy en día,
las habilidades básicas de secuencias de comandos de Python son suficientes para
realizar una investigación avanzada de aprendizaje profundo. Esto ha sido
impulsado más notablemente por el desarrollo de Theano y luego TensorFlow, dos
marcos simbólicos de manipulación de tensores para Python que admiten la
diferenciación automática, lo que simplifica enormemente la implementación de
nuevos modelos, y por el surgimiento de bibliotecas fáciles de usar como Keras, lo
que hace que el aprendizaje profundo sea tan fácil como manipular ladrillos LEGO.
Después de su lanzamiento a principios de 2015, Keras se convirtió rápidamente en
la solución de aprendizaje profundo para un gran número de nuevas empresas,
estudiantes de posgrado y

1.3.6 ¿Durará?
¿Hay algo especial en las redes neuronales profundas que las convierta en el
enfoque "correcto" para que las empresas inviertan y los investigadores acudan en
masa? ¿O el aprendizaje profundo es solo una moda pasajera que puede no durar?
¿Seguiremos usando redes neuronales profundas dentro de 20 años?
El aprendizaje profundo tiene varias propiedades que justifican su condición de
revolución de la IA, y llegó para quedarse. Es posible que no usemos redes
neuronales dentro de dos décadas, pero cualquier cosa que usemos heredará
directamente del aprendizaje profundo moderno y sus conceptos básicos. Estas
propiedades importantes se pueden clasificar en términos generales en tres
categorías:
◾ Sencillez—El aprendizaje profundo elimina la necesidad de la ingeniería de
características, reemplazando canalizaciones complejas, frágiles y con mucha
ingeniería por modelos simples que se pueden entrenar de un extremo a otro que
normalmente se construyen utilizando solo cinco o seis operaciones de tensor
diferentes.
◾ Escalabilidad—El aprendizaje profundo es muy susceptible a la paralelización
enGPUs oTPUs, por lo que puede aprovechar al máximo la ley de Moore.
Además, los modelos de aprendizaje profundo se entrenan iterando sobre
pequeños lotes de datos, lo que les permite entrenarse en conjuntos de datos
de tamaño arbitrario. (El único cuello de botella es la cantidad de potencia
computacional paralela disponible que, gracias a la ley de Moore, es una
barrera que se mueve rápidamente).
◾ Versatilidad y reutilización—A diferencia de muchos enfoques de aprendizaje

Con licencia para


automático anteriores, los modelos de aprendizaje profundo se pueden entrenar
con datos adicionales sin reiniciar desde cero, lo que los hace viables para el
aprendizaje en línea continuo, una propiedad importante para modelos de
producción muy grandes. Además, los modelos de aprendizaje profundo
entrenados son reutilizables y, por lo tanto, reutilizables: por ejemplo, es posible
tomar un modelo de aprendizaje profundo entrenado para la clasificación de
imágenes y colocarlo en una canalización de procesamiento de video. Esto nos
permite reinvertir el trabajo anterior en proyectos cada vez más

Con licencia para


24 CPASADO1¿Qué es el aprendizaje profundo?

modelos complejos y poderosos. Esto también hace que el aprendizaje


profundo sea aplicable a conjuntos de datos bastante pequeños.
El aprendizaje profundo solo ha estado en el centro de atención durante algunos
años y aún no hemos establecido el alcance completo de lo que puede hacer. Con
cada mes que pasa, aprendemos sobre nuevos casos de uso y mejoras de ingeniería
que eliminan las limitaciones anteriores. Después de una revolución científica, el
progreso generalmente sigue una curva sigmoidea: comienza con un período de
progreso rápido, que se estabiliza gradualmente a medida que los investigadores
enfrentan limitaciones difíciles, y luego las mejoras adicionales se vuelven
incrementales. El aprendizaje profundo en 2017 parece estar en la primera mitad de
ese sigmoide, con mucho más progreso por venir en los próximos años.

Con licencia para


Antes de comenzar:
elbloques de
construcción
matemáticos de las
redes neuronales

Este capítulo cubre


◾ Un primer ejemplo de una red neuronal
◾ Tensores y operaciones tensoriales
◾ Cómo aprenden las redes neuronales a través de
la retropropagacióny descenso de gradiente

Comprender el aprendizaje profundo requiere familiaridad con muchos conceptos


matemáticos simples: tensores, operaciones de tensores, diferenciación, descenso
de gradiente, etc. Nuestro objetivo en este capítulo será desarrollar su intuición
acerca de estas nociones sin ser demasiado técnicos. En particular, nos
alejaremos de la notación matemática, que puede resultar desagradable para
quienes no tienen conocimientos matemáticos y no es estrictamente necesaria
para explicar bien las cosas.
Para agregar algo de contexto para los tensores y el descenso de gradiente,
comenzaremos el capítulo con un ejemplo práctico de una red neuronal. Luego
repasaremos cada nuevo concepto.

25

Con licencia para


26 CPASADO2 Antes de comenzar: los componentes básicos matemáticos de las redes neuronales

ese essido introducido, punto por punto. ¡Tenga en cuenta que estos conceptos serán
esenciales para comprender los ejemplos prácticos que vendrán en los siguientes
capítulos!
Después de leer este capítulo, tendrá una comprensión intuitiva de cómo funcionan
las redes neuronales y podrá pasar a las aplicaciones prácticas, que comenzarán en el
capítulo 3.

Con licencia para


Un primer vistazo a una neuralla red 27

2.1 Un primer vistazo a una red neuronal


Veamos un ejemplo concreto de una red neuronal que utiliza la biblioteca Keras de
Python para aprender a clasificar dígitos escritos a mano. A menos que ya tenga
experiencia con Keras o bibliotecas similares, no entenderá todo sobre este primer
ejemplo de inmediato. Probablemente ni siquiera hayas instalado Keras todavía; está
bien. En el próximo capítulo, revisaremos cada elemento del ejemplo y los explicaremos
en detalle. ¡Así que no te preocupes si algunos pasos te parecen arbitrarios o mágicos!
Tenemos que empezar en alguna parte.
El problema que intentamos resolver aquí es clasificar imágenes en escala de grises
de dígitos escritos a mano (28 × 28 píxeles) en sus 10 categorías (0 a 9). Usaremos el
conjunto de datos MNIST, un clásico en la comunidad de aprendizaje automático, que
ha existido casi tanto tiempo como el campo en sí y se ha estudiado intensamente. Es un
conjunto de 60 000 imágenes de entrenamiento, más 10 000 imágenes de prueba,
ensambladas por el Instituto Nacional de Estándares y Tecnología (NIST en MNIST) en
la década de 1980. Puede pensar en "resolver" MNIST como el "Hola mundo" del
aprendizaje profundo: es lo que hace para verificar que sus algoritmos funcionan como
se espera. A medida que se convierta en un practicante del aprendizaje automático, verá
que MNIST aparece una y otra vez, en artículos científicos, publicaciones de blogs, etc.
Puede ver algunos ejemplos de MNIST en la figura 2.1.

Nota sobre clases y etiquetas


En el aprendizaje automático, uncategoríaen un problema de clasificación se
llamaclase. Los puntos de datos se llamanmuestras. La clase asociada con una
muestra específica se llamaetiqueta.

Figura 2.1 Dígitos de muestra del MNIST

No es necesario que intente reproducir este ejemplo en su máquina en este momento. Si


lo desea, primero deberá configurar Keras, que se trata en la sección 3.3.
El conjunto de datos MNIST viene precargado en Keras, en forma de un
conjunto de cuatro matrices Numpy.

Listado 2.1 Cargando el conjunto de datos MNIST enKeras

desde keras.datasets import mnist

(imágenes_tren, etiquetas_tren), (imágenes_prueba, etiquetas_prueba) =


mnist.load_data()

tren_imágenesytren_etiquetasforman el conjunto de entrenamiento, los datos de los


que aprenderá el modelo. Luego, el modelo se probará en el conjunto de
prueba,imágenes_de_pruebayetiquetas_de_prueba.
Con licencia para
28 CPASADO2 Antes de comenzar: los componentes básicos matemáticos de las redes neuronales

Las imágenes están codificadas como matrices Numpy y las etiquetas son una matriz de
dígitos, que van del 0 al 9. Las imágenes y las etiquetas tienen una correspondencia uno
a uno.
Veamos los datos de entrenamiento:
>>>
tren_imagenes.forma
(60000, 28, 28)
>>>
len(tren_etiquetas)
60000
>>> tren_etiquetas
matriz ([5, 0, 4, ..., 5, 6, 8], dtype=uint8)

Y aquí están los datos de la prueba:


>>> test_images.shape
(10000, 28, 28)
>>>
len(prueba_etiquetas
) 10000
>>> etiquetas_de_prueba
matriz ([7, 2, 1, ..., 4, 5, 6], dtype=uint8)

El flujo de trabajo será el siguiente: primero, alimentaremos la red neuronal con los
datos de entrenamiento, tren_imágenes y tren_etiquetas. La red
aprenderá entonces a asociar imágenes y etiquetas. Finalmente, le
pediremos a la red que produzca predicciones para test_images y
verificaremos si estas predicciones coinciden con las etiquetas
de test_labels.
Construyamos la red; nuevamente, recuerde que no se espera que usted entienda
todo acerca de este ejemplo todavía.

Listado 2.2 La arquitectura de red

desde keras importar


modelos desde keras
importar capas
red = modelos. Secuencial()
red.añadir(capas.Dense(512, activación='relu', input_shape=(28 * 28,)))
red.añadir(capas.Densa(10, activación='softmax'))

El bloque de construcción central de las redes neuronales es la capa, un módulo de


procesamiento de datos que se puede considerar como un filtro de datos. Algunos datos
entran y salen en una forma más útil. Específicamente, las capas extraen
representaciones de los datos que se introducen en ellas, con suerte, representaciones
que son más significativas para el problema en cuestión. La mayor parte del aprendizaje
profundo consiste en encadenar capas simples que implementarán una forma de
destilación progresiva de datos. Un modelo de aprendizaje profundo es como un tamiz
para el procesamiento de datos, hecho de una sucesión de filtros de datos cada vez más
refinados: las capas.
Aquí, nuestra red consta de una secuencia de dos capas densas, que son capas
neuronales densamente conectadas (también llamadas totalmente conectadas). La
Con licencia para
segunda (y última) capa es una capa softmax de 10 vías, lo que significa que devolverá
una matriz de 10 puntuaciones de probabilidad (que suman 1). Cada puntaje será la
probabilidad de que la imagen del dígito actual pertenezca a una de nuestras clases de
10 dígitos.

Con licencia para


Un primer vistazo a una neuralla red 29

Para que la red esté lista para el entrenamiento, debemos elegir tres cosas más,
como parte del paso de compilación:
◾ Una función de pérdida—Cómo la red podrá medir su rendimiento en los
datos de entrenamiento y, por lo tanto, cómo podrá orientarse en la dirección
correcta.
◾ un optimizador—El mecanismo a través del cual la red se actualizará en función
de los datos que ve y su función de pérdida.
◾ Métricas para monitorear durante el entrenamiento y las pruebas—Aquí sólo
nos importará la precisión (la fracción de las imágenes que se clasificaron
correctamente).
El propósito exacto de la función de pérdida y el optimizador se aclarará a lo largo
de los próximos dos capítulos.

Listado 2.3 El paso de compilación

red.compile(optimizador='rmsprop',
loss='categorical_crossentropy',métricas=['precis
ión'])

Antes del entrenamiento, preprocesaremos los datos dándoles la forma que espera la red
y escalando para que todos los valores estén en el intervalo [0, 1]. Anteriormente,
nuestro tren-Las imágenes de navegación, por ejemplo, se almacenaron en una matriz de
forma (60000, 28, 28) de tipo uint8 con valores en el intervalo [0, 255]. Lo transformamos
en una matriz float32 de forma (60000, 28 * 28) con valores entre 0 y 1.

Listado 2.4 Preparando la imagendatos

imágenes_tren = imágenes_tren.reshape((60000, 28 *
28)) imágenes_tren = imágenes_tren.astype('float32')
/ 255
test_images = test_images.reshape((10000, 28 * 28))
test_images = test_images.astype('float32') / 255

También necesitamos codificar categóricamente las etiquetas, un paso que se explica en el


capítulo 3.

Listado 2.5 Preparando eletiquetas

de keras.utils importar a_categorical

entrenar_etiquetas =
to_categorical(train_labels) test_labels =
to_categorical(test_labels)

Ahora estamos listos para entrenar la red, lo que en Keras se hace a través de una
llamada al método de ajuste de la red: ajustamos el modelo a sus datos de
entrenamiento:
>>> red.fit(imágenes_de_tren, etiquetas_de_tren, épocas=5,
tamaño_de_lote=128)Época 1/5
60000/60000 [==============================] - 9s - pérdida: 0,2524 - acc: 0,9273
Con licencia para
Época 2/5
51328/60000 [========================>.....] - ETA: 1s - pérdida: 0,1035 - acc: 0,9692

Con licencia para


30 CPASADO2 Antes de comenzar: los componentes básicos matemáticos de las redes neuronales

Se muestran dos cantidades durante el entrenamiento: la pérdida de la red sobre los


datos de entrenamiento y la precisión de la red sobre los datos de entrenamiento.
Alcanzamos rápidamente una precisión de 0,989 (98,9 %) en los datos de
entrenamiento. Ahora, verifiquemos que el modelo también funcione bien en el
conjunto de prueba:
>>> test_loss, test_acc = network.evaluate(test_images, test_labels)
>>> print('prueba_acc:',
prueba_acc) prueba_acc: 0.9785

La precisión del conjunto de prueba resulta ser del 97,8 %, que es un poco más baja
que la precisión del conjunto de entrenamiento. Esta brecha entre la precisión del
entrenamiento y la precisión de la prueba es un ejemplo de sobreajuste: el hecho de
que los modelos de aprendizaje automático tienden a funcionar peor con los datos
nuevos que con los datos de entrenamiento. El sobreajuste es un tema central en el
capítulo 3.
Esto concluye nuestro primer ejemplo: acaba de ver cómo puede construir y entrenar
una red neuronal para clasificar dígitos escritos a mano en menos de 20 líneas de código
Python. En el próximo capítulo, entraré en detalles sobre cada pieza en movimiento que
acabamos de ver y aclararé lo que sucede detrás de escena. Aprenderá sobre tensores,
los objetos de almacenamiento de datos que ingresan a la red; operaciones de tensor, de
las que están hechas las capas; y descenso de gradiente, que permite que su red aprenda
de sus ejemplos de entrenamiento.

Con licencia para


Representaciones de datos para neuralredes 31

2.2 Representaciones de datos para redes neuronales


En el ejemplo anterior, partimos de datos almacenados en matrices Numpy
multidimensionales, también llamadas tensores. En general, todos los sistemas de
aprendizaje automático actuales utilizan tensores como estructura de datos básica.
Los tensores son fundamentales para el campo, tan fundamentales que TensorFlow
de Google recibió su nombre. Entonces, ¿qué es un tensor?
En esencia, un tensor es un contenedor de datos, casi siempre datos numéricos.
Entonces, es un contenedor para números. Es posible que ya esté familiarizado con las
matrices, que son tensores 2D: los tensores son una generalización de las matrices a un
número arbitrario de dimensiones (tenga en cuenta que, en el contexto de los tensores,
una dimensión suele denominarse eje).

2.2.1 Escalares (tensores 0D)


Un tensor que contiene solo un número se llama escalar (o tensor escalar, o tensor de
dimensión 0, o tensor 0D). En Numpy, un número float32 o float64 es un tensor escalar
(o matriz escalar). Puede mostrar el número de ejes de un tensor Numpy a través del
atributo ndim; una esca-el tensor lar tiene 0 ejes (ndim == 0). El número de ejes de un
tensor también se llama su rango. Aquí hay un escalar Numpy:
>>> importar numpy como np
>>> x = np.matriz(12)
>>> x
matriz(12)
>>> x.ndim
0

2.2.2 Vectores (tensores 1D)


Una matriz de números se llama vector o tensor 1D. Se dice que un tensor 1D tiene
exactamente un eje. El siguiente es un vector Numpy:
>>> x = np.matriz([12, 3, 6, 14])
>>> x
matriz ([12, 3, 6, 14])
>>> x.ndim
1

Este vector tiene cinco entradas y por eso se le llama vector de 5 dimensiones. ¡No
confundas un vector 5D con un tensor 5D! Un vector 5D tiene solo un eje y tiene cinco
dimensiones a lo largo de su eje, mientras que un tensor 5D tiene cinco ejes (y puede
tener cualquier número de dimensiones a lo largo de cada eje). La dimensionalidad
puede denotar el número de entradas a lo largo de un eje específico (como en el caso de
nuestro vector 5D) o el número de ejes en un tensor (como un tensor 5D), lo que a veces
puede resultar confuso. En el último caso, técnicamente es más correcto hablar de un
tensor de rango 5 (el rango de un tensor es el número de ejes), pero la notación ambigua
del tensor 5D es común independientemente.

2.2.3 Matrices(tensores 2D)


Una matriz de vectores es una matriz o tensor 2D. Una matriz tiene dos ejes (a menudo
denominados filas y columnas). Puede interpretar visualmente una matriz como una

Con licencia para


cuadrícula rectangular de números. Esta es una matriz Numpy:

Con licencia para


32 CPASADO2 Antes de comenzar: los componentes básicos matemáticos de las redes neuronales

>>> x = np.matriz([[5, 78, 2, 34, 0],


[6, 79, 3, 35, 1],
[7, 80, 4, 36, 2]])
>>> x.ndim
2

Las entradas del primer eje se denominan filas y las entradas del segundo ejese llaman
las columnas. En el ejemplo anterior, [5, 78, 2, 34, 0] es la primera fila de x y [5, 6, 7] es la
primera columna.

2.2.4 Tensores 3D y tensores de dimensiones superiores


Si empaqueta tales matrices en una nueva matriz, obtiene un tensor 3D, que puede
interpretar visualmente como un cubo de números. El siguiente es un tensor 3D Numpy:
>>> x = np.matriz([[[5, 78, 2, 34, 0],
[6, 79, 3, 35, 1],
[7, 80, 4, 36, 2]],
[[5, 78, 2, 34, 0],
[6, 79, 3, 35, 1],
[7, 80, 4, 36, 2]],
[[5, 78, 2, 34, 0],
[6, 79, 3, 35, 1],
[7, 80, 4, 36, 2]]])
>>> x.ndim
3

Al empaquetar tensores 3D en una matriz, puede crear un tensor 4D, y así


sucesivamente. En el aprendizaje profundo, generalmente manipulará tensores de 0D a
4D, aunque puede llegar hasta 5D si procesa datos de video.

2.2.5 Atributos claves


Un tensor se define por tres atributos clave:
◾ Número de ejes (rango)—Por ejemplo, un3Dtensor tiene tres ejes, y una matriz
tiene dos ejes. Esto también se llama el tensor ndimen bibliotecas de Python
como Numpy.
◾ Forma—Esta es una tupla de enteros que describe cuántas dimensiones tiene el
tensor a lo largo de cada eje. Por ejemplo, el ejemplo de matriz anterior tiene
forma(3, 5), y el3Dejemplo de tensor tiene forma(3, 3, 5). Un vector tiene una
forma con un solo elemento, como(5,), mientras que un escalar tiene una forma
vacía,().
◾ Tipo de datos(generalmente llamadotipo de den las bibliotecas de Python): este es
el tipo de datos contenidos en el tensor; por ejemplo, el tipo de un tensor podría
serflotar32,uint8,flotar64, y así. En raras ocasiones, es posible que vea
uncarbonizarsetensor. Tenga en cuenta que los tensores de cadena no existen en
Numpy (o en la mayoría de las otras bibliotecas), porque los tensores viven en
segmentos de memoria contiguos preasignados: y las cadenas, al ser de longitud
variable, impedirían el uso de esta implementación.

Con licencia para


Representaciones de datos para neuralredes 33

Para hacer esto más concreto, echemos un vistazo a los datos que procesamos en el MNIST
ejemplo. Primero, cargamos el conjunto de datos MNIST:
desde keras.datasets import mnist

(imágenes_tren, etiquetas_tren), (imágenes_prueba, etiquetas_prueba) =


mnist.load_data()

A continuación, mostramos el número de ejes del tensor tren_imágenes, landimatributo:


>>>
imprimir(tren_imagenes.ndim)
3

Aquí está su forma:


>>>
print(tren_imagenes.forma)
(60000, 28, 28)

Y este es sutipo de datos, el atributo dtype:


>>>
print(tren_imagenes.dtype)
uint8

Así que lo que tenemos aquí es un tensor 3D de números enteros de 8 bits. Más
precisamente, es una matriz de 60.000 matrices de 28 × 8 enteros. Cada matriz es una
imagen en escala de grises, con coeficientes entre 0 y 255.
Mostremos el cuarto dígito en este tensor 3D, usando la biblioteca Matplotlib
(parte del conjunto científico estándar de Python); ver figura 2.2.

Listado 2.6 Mostrando el cuarto dígito

dígito = tren_imágenes[4]

importar matplotlib.pyplot como plt


plt.imshow(dígito,
cmap=plt.cm.binary) plt.show()

Figura 2.2 La cuarta muestra en nuestro conjunto de datos.

Con licencia para


34 CPASADO2 Antes de comenzar: los componentes básicos matemáticos de las redes neuronales

2.2.6 Manipulando tensores en Numpy


En el ejemplo anterior, seleccionamos un dígito específico junto al primer eje usando la
sintaxis train_images[i]. La selección de elementos específicos en un tensor se denomina
corte de tensor. Veamos las operaciones de corte de tensor que puede realizar en matrices
Numpy.
El siguiente ejemplo selecciona los dígitos del 10 al 100 (el 100 no está incluido) y
los coloca en una matriz de formas (90, 28, 28):
>>> mi_rebanada = entrenar_imágenes[10:100]
>>>
print(mi_rebanada.forma)
(90, 28, 28)

Es equivalente a esta notación más detallada, que especifica un índice de inicio y un


índice de finalización para el segmento a lo largo de cada eje del tensor. Tenga en
cuenta que : es equivalente a seleccionar todo el eje:
Equivalente al ejemplo
>>> my_slice = entrenar_imágenes[10:100, anterior
:, :]
>>> mi_corte.forma También equivalente a la
(90, 28, 28)
>>> my_slice = entrenar_imágenes[10:100, 0:28, ejemplo anterior
0:28]
>>> mi_corte.forma
(90, 28, 28)

En general, puede seleccionar entre dos índices a lo largo de cada eje del tensor. Por
ejemplo, para seleccionar 14 × 14 píxeles en la esquina inferior derecha de todas las
imágenes, haga lo siguiente:
my_slice = train_images[:, 14:, 14:]

También es posible utilizar índices negativos. Al igual que los índices negativos en las
listas de Python, indican una posición relativa al final del eje actual. Para recortar las
imágenes en parches de 14 × 14 píxeles centrados en el medio, haga lo siguiente:
my_slice = train_images[:, 7:-7, 7:-7]

2.2.7 La noción de lotes de datos


En general, el primer eje (eje 0, porque la indexación comienza en 0) en todos los
tensores de datos que encontrará en el aprendizaje profundo será el eje de muestras (a
veces llamado dimensión de muestras). En el ejemplo de MNIST, las muestras son
imágenes de dígitos.
Además, los modelos de aprendizaje profundo no procesan un conjunto de datos
completo a la vez; más bien, dividen los datos en pequeños lotes. Concretamente,
aquí hay un lote de nuestros dígitos MNIST, con un tamaño de lote de 128:
lote = tren_imágenes[:128]

Y aquí está el siguiente lote:

lote = tren_imágenes[128:256]

Y el enésimo lote:
Con licencia para
lote = tren_imágenes[128 * n:128 * (n + 1)]

Con licencia para


Representaciones de datos para neuralredes 35

Al considerar un tensor de lote de este tipo, el primer eje (eje 0) se denomina eje de
lote o dimensión de lote. Este es un término que encontrará con frecuencia al usar
Keras y otras bibliotecas de aprendizaje profundo.

2.2.8 Ejemplos del mundo real de tensores de datos


Hagamos los tensores de datos más concretos con algunos ejemplos similares a los que
encontrará más adelante. Los datos que manipulará casi siempre caerán en una de las
siguientes categorías:
◾ Datos vectoriales—2Dtensores de forma (muestras, características)
◾ Datos de series temporales o datos de secuencia—3Dtensores de forma (muestras,
intervalos de tiempo,caracteristicas)
◾ Imágenes—4Dtensores de forma(muestras, alto, ancho, canales)o
(muestras,canales, alto, ancho)
◾ Video—5Dtensores de forma(muestras, marcos, alto, ancho, canales) o
(muestras, marcos, canales, alto, ancho)

2.2.9 Datos vectoriales


Este es el caso más común. En dicho conjunto de datos, cada punto de datos individual
se puede codificar como un vector y, por lo tanto, un lote de datos se codificará como
un tensor 2D (es decir, una matriz de vectores), donde el primer eje es el eje de muestras
y el segundo El eje es el eje de características.
Veamos dos ejemplos:
◾ Un conjunto de datos actuariales de personas, donde consideramos la edad de
cada persona,CÓDIGO POSTALcódigo e ingresos. Cada persona se puede
caracterizar como un vector de 3 valores y, por lo tanto, se puede almacenar
un conjunto de datos completo de 100,000 personas en un 2Dtensor de
forma(100000, 3).
◾ Un conjunto de datos de documentos de texto, donde representamos cada
documento por el conteo de cuántas veces aparece cada palabra en él (de un
diccionario de 20,000 palabras comunes). Cada documento se puede codificar
como un vector de 20 000 valores (un recuento por palabra en el diccionario)
y, por lo tanto, un conjunto de datos completo de 500 documentosse puede
almacenar en un tensor de forma(500, 20000).

2.2.10 Datos de series temporales o datos de secuencia


Siempre que el tiempo importe en sus datos (o la noción de orden de secuencia),
tiene sentido almacenarlo en un tensor 3D con un eje de tiempo explícito. Cada
muestra se puede codificar como una secuencia de vectores (un tensor 2D) y, por lo
tanto, un lote de datos se codificará como un tensor 3D (consulte la figura 2.3).

Características

Muestra
s
Pasos de Figura 2.3 Un tensor de datos de series temporales 3D
tiempo
Con licencia para
36 CPASADO2 Antes de comenzar: los componentes básicos matemáticos de las redes neuronales

El eje de tiempo es siempre el segundo eje (eje de índice 1), por convención. Veamos
algunos ejemplos:
◾ Un conjunto de datos de precios de acciones. Cada minuto, almacenamos el
precio actual de la acción, el precio más alto en el último minuto y el precio
más bajo en el último minuto. Por lo tanto, cada minuto se codifica como
un3Dvector, un día completo de negociación se codifica como un 2Dtensor de
forma(390, 3)(hay 390 minutos en un día de negociación) y se pueden
almacenar 250 días de datos en un3Dtensor de forma(250, 390, 3). Aquí,
cada muestra sería el valor de un día de datos.
◾ Un conjunto de datos de tweets, donde codificamos cada tweet como una
secuencia de 280 caracteres de un alfabeto de 128 caracteres únicos. En esta
configuración, cada carácter se puede codificar como un vector binario de tamaño
128 (un vector de todos ceros excepto por una entrada 1 en el índice
correspondiente al carácter). Entonces cada tweet se puede codificar como
un2Dtensor de forma(280, 128), y un conjunto de datos de 1 millón de
tweets se puede almacenar en un tensor de forma (1000000, 280, 128).

2.2.11 Datos de imagen


Las imágenes suelen tener tres dimensiones: alto, ancho y profundidad de color. Aunque
las imágenes en escala de grises (como nuestros dígitos MNIST) tienen un solo canal de
color y, por lo tanto, podrían almacenarse en tensores 2D, por convención, los tensores
de imagen siempre son 3D, con un canal de color unidimensional para imágenes en
escala de grises. Un lote de 128 imágenes en escala de grises detamaño 256 × 256 podría
almacenarse en un tensor de forma (128, 256, 256, 1), y un lote de 128 imágenes en color
podría almacenarse en un tensor de forma (128, 256, 256, 3) (ver figura 2.4).

Canales de color

Altura

Muestras

Figura 2.4 Un tensor de datos


Ancho de imagen 4D (convención de
canales primero)

Hay dos convenciones para las formas de los tensores de imágenes: la convención de los
últimos canales (utilizada por TensorFlow) y la convención de los primeros canales
(utilizada por Theano). El marco de aprendizaje automático Tensor-Flow, de Google,
coloca el eje de profundidad de color al final: (muestras, alto, ancho,
color_profundidad). Mientras tanto, Theano coloca el eje de profundidad de color justo
después del eje de lote: (muestras, color_profundidad, alto, ancho) . Con
Con licencia para
Representaciones de datos para neuralredes 37

la convención de Theano, los ejemplos anteriores se convertirían (128, 1, 256, 256)


y(128, 3, 256, 256). El marco Keras proporciona soporte para ambos formatos.

2.2.12 datos de vídeo


Los datos de video son uno de los pocos tipos de datos del mundo real para los que
necesitará5Dtensores. Un vídeo puede entenderse como una secuencia de fotogramas,
siendo cada fotograma una imagen en color.Debido a que cada cuadro se puede almacenar
en un3Dtensor(alto, ancho, color_profundidad), una secuencia de fotogramas se
puede almacenar en un4Dtensor(marcos, alto, ancho, color_profundidad)y,
por lo tanto, se puede almacenar un lote de videos diferentes en un 5Dtensor de
forma(muestras, marcos, altura,ancho, color_profundidad).
Por ejemplo, un videoclip de YouTube de 60 segundos y 144 × 256 muestreado a 4
fotogramas por segundo tendría 240 fotogramas. Un lote de cuatro clips de vídeo de este
tipo se almacenaría en untensor de forma (4, 240, 144, 256, 3). ¡Eso es un total de
106,168,320 valores! Si el dtype del tensor fuera float32, cada valor se almacenaría en 32
bits, por lo que el tensor representaría 405 MB. ¡Pesado! Los videos que encuentras en la
vida real son mucho más livianos, porque no están almacenados en float32 y, por lo general,
están comprimidos en gran medida (como en el formato MPEG).

Con licencia para


38 CPASADO2 Antes de comenzar: los componentes básicos matemáticos de las redes neuronales

2.3 Los engranajes de las redes neuronales: operaciones tensoriales


Al igual que cualquier programa informático puede reducirse en última instancia a
un pequeño conjunto de operaciones binarias en entradas binarias (AND, OR, NOR,
etc.), todas las transformaciones aprendidas por las redes neuronales profundas
pueden reducirse a un puñado de operaciones tensoriales aplicadas a los tensores. de
datos numéricos. Por ejemplo, es posible sumar tensores, multiplicar tensores, etc.
En nuestro ejemplo inicial, estábamos construyendo nuestra red apilando capas
densas una encima de la otra. Una instancia de capa de Keras se ve así:

keras.layers.Dense(512, activación='relu')

Esta capa se puede interpretar como una función, que toma como entrada un tensor
2D y devuelve otro tensor 2D, una nueva representación para el tensor de entrada.
En concreto, la función es la siguiente (donde W es un tensor 2D y b es un vector,
ambos atributos de la capa):

salida = relu(punto(W, entrada) + b)

Desempaquemos esto. Aquí tenemos tres operaciones de tensor: un producto punto


(punto) entre el tensor de entrada y un tensor llamado W; una suma (+) entre la
resultante 2D ten-sor y un vector b; y, finalmente, una operación de relu. relu(x) es max(x,
0).

NOTAAunque esta sección trata exclusivamente de expresiones de álgebra


lineal, aquí no encontrará ninguna notación matemática. Descubrí que los
programadores sin conocimientos matemáticos pueden dominar más fácilmente
los conceptos matemáticos si se expresan como fragmentos cortos de Python en
lugar de ecuaciones matemáticas. Así que usaremos el código Numpy en todo
momento.

2.3.1 Operaciones elementales


La operación relu y la suma son operaciones elementales: operaciones que se aplican de
forma independiente a cada entrada en los tensores que se están considerando. Esto
significa que estas operaciones son muy aptas para implementaciones paralelas masivas
(implementaciones vectorizadas, un término que proviene de la arquitectura de
supercomputadora de procesador vectorial del período 1970-1990). Si desea escribir una
implementación ingenua en Python de una operación por elementos, use un bucle for,
como en esta implementación ingenua de una operación relu por elementos:
def ingenuo_relu(x):
afirmar len(x.forma) == 2 x es un tensor Numpy 2D.
x = x.copiar() Evite sobrescribir el tensor de entrada.
for i in range(x.shape[0]): for
j in range(x.shape[1]):
x[i, j] = máx(x[i, j], 0)
volver x

Con licencia para


Los engranajes de las redes neuronales: tensoroperaciones 39

Haces lo mismo para la suma:


def naive_add(x, y): x e y son
afirmar len(x.shape) == 2 tensores Numpy
afirmar x.shape == 2D.
y.shape
x = x.copiar() Evite sobrescribir el
for i in range(x.shape[0]): for tensor de entrada.
j in range(x.shape[1]):
x[yo, j] += y[yo, j]
volver x

Con el mismo principio, puedes hacer multiplicaciones, restas, etc., por elementos. En la
práctica, cuando se trata de matrices Numpy, estas operaciones están disponibles como
funciones Numpy integradas bien optimizadas, que a su vez delegan el trabajo pesado a
una implementación de subprogramas de álgebra lineal básica (BLAS) si tiene uno
instalado (que debería). Los BLAS son de bajo nivel, altamente paralelos y eficientes de
manipulación de tensores.
rutinas que normalmente se implementan en Fortran o C.
Entonces, en Numpy, puedes hacer la siguiente operación por elementos, y será
increíblemente rápido:
importar numpy

como np z = x + y Adición por elementos


z = np.máximo(z, 0.) relu elemento-sabio

2.3.2 Radiodifusión
Nuestra implementación ingenua anterior de naive_add solo admite la adición de
tensores 2D con formas idénticas. Pero en la capa densa que presentamos anteriormente,
agregamos un tensor 2D con un vector. ¿Qué sucede con la suma cuando las formas de
los dos tensores que se suman difieren?
Cuando sea posible, y si no hay ambigüedad, el tensor más pequeño se transmitirá
para que coincida con la forma del tensor más grande. La transmisión consta de dos
pasos:
1Los ejes (llamados ejes de transmisión) se agregan al tensor más pequeño para que
coincida con elndimdel tensor mayor.
2El tensor más pequeño se repite junto con estos nuevos ejes para que coincida
con la forma completa del tensor más grande.
Veamos un ejemplo concreto. Considere X con forma (32, 10) e y con forma (10,).
Primero, agregamos un primer eje vacío a y, cuya forma se
convierte en (1, 10). Luego, repetimos y 32 veces a lo largo de
este nuevo eje, de modo que terminamos con un tensor Y con forma
(32, 10), donde Y[i, :] == y para i en el rango (0, 32). En este
punto, podemos proceder a sumar X e Y, porque tienen la misma
forma.
En términos de implementación, no se crea ningún tensor 2D nuevo, porque
sería terriblemente ineficiente. La operación de repetición es completamente virtual:
ocurre a nivel algorítmico en lugar de a nivel de memoria. Pero pensando en el
Con licencia para
vector siendo

Con licencia para


40 CPASADO2 Antes de comenzar: los componentes básicos matemáticos de las redes neuronales

repetido 10 veces junto con un nuevo eje es un modelo mental útil. Así es como se vería una
implementación ingenua:

def naive_add_matrix_and_vector(x, y): x es un tensor Numpy 2D.


afirmar len(x.shape) == 2
afirmar len(y.shape) == 1 y es un vector Numpy.
afirmar x.forma[1] == y.forma[0]

x = x.copiar() Evite sobrescribir


for i in range(x.shape[0]): for el tensor de
j in range(x.shape[1]): entrada.
x[i, j] += y[j]
volver x

Con la transmisión, generalmente puede aplicar operaciones de elementos de dos


tensores si unotensor tiene forma (a, b,... n, n + 1,... m) y el otro tiene forma (n, n + 1,... m).
La transmisión se realizará automáticamente para los ejes a a n - 1.
El siguiente ejemplo aplica la operación máxima por elementos a dos tensores de
diferentes formas a través de la transmisión:
importar numpy como np x es aleatoriotensor con
x = np.aleatorio.aleatorio((64, 3, forma (64, 3, 32,10).
32, 10)) y =
y es un tensor
np.aleatorio.aleatorio((32, 10))
aleatoriocon forma
z = np.máximo(x,y) (32,10).
La salida z tiene forma
(64, 3, 32,10) como x.
2.3.3 Tensorpun
to
La operación de punto, también llamada producto tensorial (que no debe
confundirse con un producto por elementos) es la operación tensorial más común y
útil. Al contrario de las operaciones con elementos, combina entradas en los
tensores de entrada.
Un producto de elementos se realiza con el operador * en Numpy, Keras, Theano y
TensorFlow. dot usa una sintaxis diferente en TensorFlow, pero tanto en Numpy como
en Keras se hace usando el operador de punto estándar:
importar numpy
como np z =
np.dot(x, y)

En notación matemática, anotaría la operación con un punto (.):


z = x . y

Matemáticamente, ¿qué hace la operación de punto? Comencemos con el producto


escalar dedos vectores x e y. Se calcula de la siguiente manera:
afirmar x.forma[0] == y.forma[0]
def naive_vector_dot(x, y):
afirmar len(forma x) ==
1 afirmar len(forma y)
== 1

Con licencia para


xey son vectores Numpy.

Con licencia para


Los engranajes de las redes neuronales: tensoroperaciones 41

z = 0.
for i in range(x.shape[0]):
z += x[i] * y[i]
volver z

Habrás notado que el producto punto entre dos vectores es un escalar y que solo los
vectores con el mismo número de elementos son compatibles para un producto
punto.
También puede tomar el producto punto entre una matriz x y un vector y, que
devuelve un vector donde los coeficientes son los productos punto entre y y las filas de
x. Lo implementas de la siguiente manera:
importar numpy como np x es una matriz Numpy.
def naive_matrix_vector_dot(x, y):
afirmar len(x.forma) == 2 y es un vector Numpy.
afirmar len(y.forma) == 1
afirmar x.forma[1] ==
y.forma[0]
¡La primera dimensión de x debe ser la
z =np.ceros(x.forma[0]) misma que la dimensión 0 de y!
para i en el rango (x.shape[0]):
para j en el rango Esta operación devuelve un vector
(x.shape[1]): z[i] += de 0s con la misma forma que y.
x[i, j] * y[j]
volver z

También podría reutilizar el código que escribimos anteriormente, que destaca la


relación entre un producto matriz-vector y un producto vectorial:
def naive_matrix_vector_dot(x, y):
z = np.zeros(x.shape[0])
para i en el rango (x.shape[0]):
z[i] = naive_vector_dot(x[i, :], y)
devuelve z

Tenga en cuenta que tan pronto como uno de los dos tensores tiene un ndim mayor que
1, el punto deja de ser largo.ger simétrico, lo que quiere decir que el punto (x, y) no es lo
mismo que el punto (y, x).
Por supuesto, un producto escalar se generaliza a tensores con un número arbitrario
de ejes. Las aplicaciones más comunes pueden ser el producto escalar entre dos
matrices. Puede tomar el producto escalar de dos matrices x e y (punto(x, y)) si y solo si
x.shape[1] == y.shape[0]. El resultado es una matriz con forma (x.shape[0], y.shape[1]),
donde los coeficientes son los productos vectoriales entre las filas de x y las columnas
de y. Aquí está la implementación ingenua:
def naive_matrix_dot(x, y):
XyY afirmar len(x.shape) == ¡La primera dimensión de x debe ser
son 2 afirmar len(y.shape) la misma que la dimensión 0 de y!
matrices == 2
Esta operación devuelve una
Numpy. afirmar x.forma[1] == y.forma[0]
matriz de ceros con una forma
z = np.zeros((x.shape[0], específica.
y.shape[1])) for i in Itera sobre las filas de x...
range(x.shape[0]): … y sobre las columnas de y.
for j in range(y.shape[1]):
fila_x = x[i, :]
columna_y = y[:, j]

Con licencia para


z[i, j] = ingenuo_vector_punto(fila_x, columna_y)
volver z

Con licencia para


42 CPASADO2 Antes de comenzar: los componentes básicos matemáticos de las redes neuronales

Para comprender la compatibilidad de la forma del producto escalar, es útil visualizar los
tensores de entrada y salida alineándolos como se muestra en la figura 2.5.

forma
de
X.y=z Y:(ant
es de
Cristo)
b

columna de y
b

x.forma: forma z:
(a, b) (a, c)
a
z [ yo, j ] Figura 2.5 Producto escalar
Fila de x de matrizdiagrama de caja

x, y y z se representan como rectángulos (cajas literales de


coeficientes). Debido a que las filas y x y las columnas de y
deben tener el mismo tamaño, se deduce que el ancho de x debe
coincidir con la altura de y. Si continúa desarrollando nuevos
algoritmos de aprendizaje automático, probablemente dibujará
diagramas de este tipo con frecuencia.
De manera más general, puede tomar el producto escalar entre tensores de mayor
dimensión, siguiendo las mismas reglas de compatibilidad de formas que se
describieron anteriormente para el caso 2D:
(a B C D) . (d,) -> (a, b, c)
(a B C D) . (d, e) -> (a, b, c, e)

Y así.

2.3.4 Remodelación de tensores


Un tercer tipo de operación de tensor que es esencial comprender es la
remodelación de tensor. Aunque no se usó en las capas densas en nuestro primer
ejemplo de red neuronal, lo usamos cuando preprocesamos los datos de los dígitos
antes de introducirlos en nuestra red:
imágenes_tren = imágenes_tren.reshape((60000, 28 * 28))

Reformar un tensor significa reorganizar sus filas y columnas para que coincidan con
una forma de destino. Naturalmente, el tensor remodelado tiene el mismo número total
de coeficientes que el tensor inicial. La remodelación se entiende mejor a través de
ejemplos simples:
>>> x = np.matriz([[0., 1.],
[2., 3.],
[4., 5.]])
>>>
Con licencia para
imprimir(x.forma)
(3, 2)

Con licencia para


Los engranajes de las redes neuronales: tensoroperaciones 43

>>> x = x.reforma((6, 1))


>>> x
matriz([[ 0.],
[ 1.],
[ 2.],
[ 3.],
[4.],
[5.]])
>>> x = x.reforma((2, 3))
>>> x
matriz([[ 0., 1., 2.],
[ 3., 4., 5.]])

Un caso especial de remodelación que se encuentra comúnmente es la transposición.


Transponiendo unmatriz significa intercambiar sus filas y sus columnas, de modo
quex[yo,:]se conviertex[:, yo]:
>>> x = np.ceros((300,
Crea una matriz de forma de
20))
todos ceros (300, 20)
>>> x = np.transponer(x)
>>>
imprimir(x.forma)
(20, 300)

2.3.5 Interpretación geométrica de operaciones tensoriales


Debido a que los contenidos de los tensores manipulados por las operaciones de
tensor pueden interpretarse como coordenadas de puntos en algún espacio
geométrico, todas las operaciones de tensor tienen una interpretación geométrica.
Por ejemplo, consideremos la suma. Empezaremos con el siguiente vector:
A = [0.5, 1]

Es un punto en un espacio 2D (ver figura 2.6). Es común imaginar un vector como


una flecha que une el origen con el punto, como se muestra en la figura 2.7.

1 A [0.5, 1] 1 A [0.5, 1]

1 1

Figura 2.6 Un punto en un Figura 2.7 Un punto en un espacio 2D


espacio 2D representado como una flecha

Con licencia para


44 CPASADO2 Antes de comenzar: los componentes básicos matemáticos de las redes neuronales

Consideremos un nuevo punto, B = [1, 0.25], que sumaremos al anterior. Esto se hace
geométricamente encadenando las flechas vectoriales, siendo la ubicación resultante el
vector que representa la suma de los dos vectores anteriores (ver figura 2.8).

A+B

1 A

B
1 Figura 2.8 Interpretación geométrica
dela suma de dos vectores

En general, las operaciones geométricas elementales, como transformaciones afines,


rotaciones, escalas, etc., se pueden expresar como operaciones tensoriales. Por ejemplo,
se puede lograr una rotación de un vector 2D por un ángulo theta a través de un
producto escalar con una matriz de 2 × 2 R = [u, v], donde u y v son ambos
vectores del plano: u = [cos(theta), sin(theta)] y v = [-
sin(theta), cos(theta)].

2.3.6 Una interpretación geométrica del aprendizaje profundo


Acaba de aprender que las redes neuronales consisten completamente en cadenas de
operaciones de tensor y que todas estas operaciones de tensor son solo transformaciones
geométricas de los datos de entrada. De ello se deduce que puede interpretar una red
neuronal como una transformación geométrica muy compleja en un espacio de alta
dimensión, implementada a través de una larga serie de pasos simples.
En 3D, la siguiente imagen mental puede resultar útil. Imagina dos hojas de papel de
colores: una roja y otra azul. Pon uno encima del otro. Ahora arrúguelos juntos en una
pequeña bola. Esa bola de papel arrugada son sus datos de entrada, y cada hoja de papel
es una clase de datos en un problema de clasificación. Lo que se supone que debe hacer
una red neuronal (o cualquier otro modelo de aprendizaje automático) es descubrir una
transformación de la bola de papel que la desarrugue, para que las dos clases vuelvan a
separarse limpiamente. Con el aprendizaje profundo, esto se implementaría como una
serie de transformaciones simples del espacio 3D, como las que podría aplicar en la bola
de papel con los dedos, un movimiento a la vez.

Figura 2.9 Desglosando una


variedad complicada de
datos

Con licencia para


Los engranajes de las redes neuronales: tensoroperaciones 45

De lo que se trata el aprendizaje automático es de desarrugar bolas de papel:


encontrar representaciones ordenadas para múltiples datos complejos y altamente
plegados. En este punto, debe tener una intuición bastante buena de por qué el
aprendizaje profundo sobresale en esto: adopta el enfoque de descomponer
gradualmente una transformación geométrica complicada en una larga cadena de
transformadas elementales, que es más o menos la estrategia que seguiría un ser
humano para desarrugar una bola de papel. Cada capa en una red profunda aplica
una transformación que desenreda un poco los datos, y una pila profunda de capas
hace manejable un proceso de desenredo extremadamente complicado.

Con licencia para


46 CPASADO2 Antes de comenzar: los componentes básicos matemáticos de las redes neuronales

2.4 El motor de las redes


neuronales: optimización
basada en gradientes
Como vio en la sección anterior, cada capa neuronal de nuestro primer ejemplo de
red transforma sus datos de entrada de la siguiente manera:
salida = relu(punto(W, entrada) + b)

En esta expresión, W y b son tensores que son atributos de la capa. Ellos se llamanlos
pesos o parámetros entrenables de la capa (los atributos kernel y bias, respectivamente).
Estos pesos contienen la información aprendida por la red a partir de la exposición a los
datos de entrenamiento.
Inicialmente, estas matrices de peso se llenan con pequeños valores aleatorios (un
paso llamado ran-inicialización de dom). Por supuesto, no hay razón para esperar que
relu(dot(W, input) + b), cuando W y b son aleatorios, produzcan representaciones útiles. Las
representaciones resultantes no tienen sentido, pero son un punto de partida. Lo que sigue es
ajustar gradualmente estos pesos, en función de una señal de retroalimentación. Este ajuste
gradual, también llamado entrenamiento, es básicamente el aprendizaje de lo que se trata el
aprendizaje automático.
Esto sucede dentro de lo que se llama un ciclo de entrenamiento, que funciona de la
siguiente manera. Repita estos pasos en un bucle, siempre que sea necesario:
1Dibuje un lote de muestras de entrenamiento x y objetivos correspondientes y.
2Ejecutarla red enX(un paso llamado pase hacia adelante) para obtener prediccionesy_pred.
3Calcule la pérdida de la red en el lote, una medida del desajuste entre y_pred e
y.
4Actualice todos los pesos de la red de forma que reduzca ligeramente la pérdida
en este lote.
Eventualmente terminará con una red que tiene una pérdida muy baja en sus datos
de entrenamiento: un desajuste bajo entre las predicciones y_pred y los objetivos
esperados y. La red ha "aprendido" a asignar sus entradas a los objetivos correctos.
De lejos, puede parecer magia, pero cuando lo reduce a pasos elementales, resulta
ser simple.
El paso 1 suena bastante fácil: solo código de E/S. Los pasos 2 y 3 son
simplemente la aplicación de un puñado de operaciones tensoriales, por lo que
podría implementar estos pasos únicamente a partir de lo que aprendió en la sección
anterior. La parte difícil es el paso 4: actualizar los pesos de la red. Dado un
coeficiente de peso individual en la red, ¿cómo puede calcular si el coeficiente debe
aumentar o disminuir, y en qué medida?
Una solución ingenua sería congelar todos los pesos en la red, excepto el coeficiente
escalar que se está considerando, y probar diferentes valores para este coeficiente.
Digamos que el valor inicial del coeficiente es 0.3. Después del paso directo de un lote
de datos, la pérdida de la red en el lote es de 0,5. Si cambia el valor del coeficiente a
0,35 y vuelve a ejecutar el pase hacia adelante, la pérdida aumenta a 0,6. Pero si bajas el
coeficiente a 0,25, la pérdida cae a 0,4. En este caso, parece que actualizando el
coeficiente por -0.05

Con licencia para


El motor de las redes neuronales: basado en gradientesmejoramiento 47

contribuiría a minimizar la pérdida. Esto tendría que repetirse para todos los
coeficientes de la red.
Pero tal enfoque sería terriblemente ineficiente, porque necesitaría calcular dos
pases hacia adelante (que son costosos) para cada coeficiente individual (de los cuales
hay muchos, generalmente miles y, a veces, hasta millones). Un enfoque mucho mejor
es aprovechar el hecho de que todas las operaciones utilizadas en la red son
diferenciables y calcular el gradiente de la pérdida con respecto a los coeficientes de la
red. Luego puede mover los coeficientes en la dirección opuesta al gradiente,
disminuyendo así la pérdida.
Si ya sabe qué significa diferenciable y qué es un gradiente, puede pasar
directamente a la sección 2.4.3. De lo contrario, las siguientes dos secciones lo ayudarán
a comprender estos conceptos.

2.4.1 ¿Qué es un derivado?


Considere una función suave y continua f(x) = y, asignando un número real x a un
nuevo número real y. Debido a que la función es continua, un pequeño cambio en x solo
puede resultar en un pequeño cambio en y; esa es la intuición detrás de la continuidad.
Digamos que aumentas xpor un pequeño factor epsilon_x: esto da como resultado un
pequeño cambio de epsilon_y a y:
f(x + epsilon_x) = y + epsilon_y

Además, debido a que la función es suave (su curva no tiene ángulos abruptos), cuando
epsilon_x es lo suficientemente pequeño, alrededor de cierto punto p, es posible
aproximarmate f como una función lineal de la pendiente a, de modo que epsilon_y se
convierte en * epsilon_x:
f(x + epsilon_x) = y + a * epsilon_x

Obviamente, esta aproximación lineal es válida solo cuando x está lo suficientemente cerca de p.
La pendiente a se llama la derivada de f en p. Si a es negativo, significa que un pequeño
cambio de x alrededor de p resultará en una disminución de f(x) (como se muestra en la
figura 2.10); y si a es positivo, un pequeño cambio en x resultará en un aumento de f(x).
Además, el valor absoluto de a (la magnitud de la derivada) te dice qué tan rápido ocurrirá
este aumento o disminución.

Aproximación
lineal local de f,
con pendiente a

F Figura 2.10D e r i v a d o deFenpags

Para cada función diferenciable f(x) (diferenciable significa “puede derivarse”: por ejemplo,
pueden derivarse funciones continuas y uniformes), existe una función derivada f'(x) que
relaciona los valores de x con la pendiente de la aproximación lineal local de f en aquellos

Con licencia para


48 CPASADO2 Antes de comenzar: los componentes básicos matemáticos de las redes neuronales

puntos. Por ejemplo, la derivada deporque(x)es-sin(x), la derivada def(x) = un * x


esf'(x) = un,y así.
Si está tratando de actualizar x por un factor epsilon_x para minimizar f(x), y conoce la
derivada de f, entonces su trabajo está hecho: la derivada describe completamente cómo
evoluciona f(x) a medida que cambia x. Si quieres reducir el valor de f(x), solo necesitas
mover xa un poco en la dirección opuesta a la derivada.

2.4.2 Derivada de una operación tensorial: el gradiente


Un gradiente es la derivada de una operación tensorial. Es la generalización del
concepto de derivadas a funciones de entradas multidimensionales, es decir, a funciones
que toman tensores como entradas.
Considere un vector de entrada x, una matriz W, un objetivo y y una función de
pérdida loss. Puede utilizar W para calcular un candidato objetivo y_pred y calcular la
pérdida o la falta de coincidencia entre el candidato objetivo y_pred y el objetivo y:
y_pred = punto (W, x)
pérdida_valor = pérdida
(y_pred, y)

Silas entradas de datos x e y están congeladas, entonces esto puede interpretarse


como una función que asigna valores de W a valores de pérdida:
valor_pérdida = f(W)

Digamos el valor actual deWesW0. Entonces la derivada de Fen el puntoW0es un


tensorgradiente(f)(W0)con la misma forma queW, donde cada
coeficientegradiente(f) (W0)[i, j]indica la dirección y la magnitud del cambio
envalor_pérdidaobservas al modificarW0[yo, j]. ese tensorgradiente(f)(W0)es
el gradiente de la funciónf(W) = valor_pérdida enW0.
Viste anteriormente que la derivada de una función f(x) de un solo coeficiente puede
serinterpretada como la pendiente de la curva de f. Asimismo, el gradiente(f)(W0) se puede
interpretar como el tensor que describe la curvatura de f(W) alrededor de W0.
Por esta razón, de la misma manera que, para una función f(x), se puede reducir el
valor de f(x) moviéndose xa poco en dirección opuesta a la derivada, con una función
f(W) de a tensor, puede reducir f(W) moviendo W en el sentido opuestodirección desde
el gradiente: por ejemplo, W1 = W0 - paso * gradiente (f)(W0) (donde el paso es un factor
de escala pequeño). Eso significa ir en contra de la curvatura, lo que intuitivamente debería
colocarlo más abajo en la curva. Tenga en cuenta que el paso del factor de escala es
necesario porque el gradiente (f) (W0) solo se aproxima a la curvatura cuando está cerca de
W0, por lo que no desea alejarse demasiado de W0.

2.4.3 Descenso de gradiente estocástico


Dada una función diferenciable, es teóricamente posible encontrar su mínimo
analíticamente: se sabe que el mínimo de una función es un punto donde la derivada es
0, así que todo lo que tienes que hacer es encontrar todos los puntos donde la derivada
tiende a 0 y comprobar para cuál de estos puntos la función tiene el valor más bajo.

Con licencia para


El motor de las redes neuronales: basado en gradientesmejoramiento 49

Aplicado a una red neuronal, eso significa encontrar analíticamente la combinación


de valores de peso que produce la función de pérdida más pequeña posible. Esto se
puede hacer resolviendoing la ecuación gradiente(f)(W) = 0 para W. Esta es una ecuación
polinomial de N variables, donde N es el número de coeficientes en la red. Aunque sería
posible resolver una ecuación de este tipo para N = 2 o N = 3, hacerlo es intratable para las
redes neuronales reales, donde el número de parámetros nunca es inferior a unos pocos miles
y, a menudo, puede ser de varias decenas de millones.
En su lugar, puede utilizar el algoritmo de cuatro pasos descrito al principio de
esta sección: modifique los parámetros poco a poco en función del valor de pérdida
actual en un lote aleatorio de datos. Debido a que se trata de una función
diferenciable, puede calcular su gradiente, lo que le brinda una manera eficiente de
implementar el paso 4. Si actualiza los pesos en la dirección opuesta al gradiente, la
pérdida será un poco menor cada vez:
1Dibuje un lote de muestras de entrenamiento x y objetivos correspondientes y.
2Ejecutarla red en Xpara obtener prediccionesy_pred.
3Calcule la pérdida de la red en el lote, una medida del desajuste entre y_pred e
y.
4Calcular el gradiente de pérdida con respecto a los parámetros de la red (a
pase hacia atrás).
5Mueva los parámetros un poco en la dirección opuesta al gradiente, por ejemplo W
-= paso * gradiente, reduciendo así un poco la pérdida en el lote.
¡Suficientemente fácil! Lo que acabo de describir se llama descenso de gradiente estocástico
de mini lotes (mini-batchEUR). El término estocástico se refiere al hecho de que cada lote
de datos se extrae al azar (estocástico es un sinónimo científico de aleatorio). La figura
2.11 ilustra lo que ocurre en1D, cuando la red tiene solo un parámetro y solo tiene una
muestra de entrenamiento.

Valo Paso, también llamado tasa de aprendizaje


r de
Comen
pérdi zando
da
punto (t=0)

t=1

t=2
t=3

Valor del Figura 2.11 SGD en una curva de


parámetro pérdida 1D (un parámetro que se
puede aprender)

Con licencia para


50 CPASADO2 Antes de comenzar: los componentes básicos matemáticos de las redes neuronales

Como puede ver, intuitivamente es importante elegir un valor razonable para el factor
de paso. Si es demasiado pequeño, el descenso por la curva requerirá muchas
iteraciones y podría atascarse en un mínimo local. Si el paso es demasiado grande, sus
actualizaciones pueden terminar llevándolo a ubicaciones completamente aleatorias en
la curva.
Tenga en cuenta que una variante del algoritmo SGD de minilotes sería extraer una
sola muestra y objetivo en cada iteración, en lugar de extraer un lote de datos. Esto sería
SGD verdadero (a diferencia de SGD de mini lotes). Alternativamente, yendo al
extremo opuesto, podría ejecutar cada paso en todos los datos disponibles, lo que se
denomina SGD por lotes. Cada actualización sería entonces más precisa, pero mucho
más costosa. El compromiso eficiente entre estos dos extremos es utilizar mini lotes de
tamaño razonable.
Aunque la figura 2.11 ilustra el descenso de gradiente en un espacio de parámetros
1D, en la práctica usará el descenso de gradiente en espacios altamente dimensionales:
cada coeficiente de peso en una red neuronal es una dimensión libre en el espacio, y
puede haber decenas de miles. arenas o incluso millones de ellas. Para ayudarlo a
generar intuición sobre las superficies de pérdida, también puede visualizar el descenso
de gradiente a lo largo de una superficie de pérdida 2D, como se muestra en la figura
2.12. Pero es imposible visualizar cómo se ve el proceso real de entrenar una red
neuronal; no se puede representar un espacio de 1.000.000 de dimensiones de una
manera que tenga sentido para los humanos. Como tal, es bueno tener en cuenta que las
intuiciones que desarrolla a través de estas representaciones de baja dimensión pueden
no ser siempre precisas en la práctica. Históricamente, esto ha sido una fuente de
problemas en el mundo de la investigación del aprendizaje profundo.

Punto de
partida
45
40
35
30
25
20
15
10
5
Figura 2.12 Descenso de
gradientepor una superficie
Punto final de pérdida 2D (dos
parámetros aprendibles)

Además, existen múltiples variantes de SGD que se diferencian al tener en cuenta las
actualizaciones de peso anteriores al calcular la próxima actualización de peso, en lugar
de solo mirar el valor actual de los gradientes. Hay, por ejemplo, SGD con impulso, así
como Adagrad, RMSProp y varios otros. Tales variantes se conocen como métodos de
optimización u optimizadores. En particular, el concepto de cantidad de movimiento,
que se utiliza en muchas de estas variantes, merece su atención. Momentum aborda dos
problemas con SGD: velocidad de convergencia y mínimos locales. Considere la figura
Con licencia para
2.13, que muestra la curva de una pérdida en función de un parámetro de red.

Con licencia para


El motor de las redes neuronales: basado en gradientesmejoramiento 51

Valor
de
pérdi
da

Mínimo
local

Mínimo
mundial

Valor del Figura 2.13 Un mínimo localy


parámet un mínimo global
ro

Como puede ver, alrededor de cierto valor de parámetro, hay un mínimo local:
alrededor de ese punto, moverse hacia la izquierda daría como resultado un aumento
de la pérdida, pero también lo haría hacia la derecha. Si el parámetro bajo
consideración se optimizara a través de SGD con una pequeña tasa de aprendizaje,
entonces el proceso de optimización se atascaría en el mínimo local en lugar de
llegar al mínimo global.
Puede evitar estos problemas utilizando el impulso, que se inspira en la física. Una
imagen mental útil aquí es pensar en el proceso de optimización como una pequeña bola
que rueda por la curva de pérdidas. Si tiene suficiente impulso, la bola no se atascará en
un barranco y terminará en el mínimo global. El impulso se implementa moviendo la
pelota en cada paso basándose no solo en el valor de pendiente actual (aceleración
actual) sino también en la velocidad actual (resultante de la aceleración pasada). En la
práctica, esto significa actualizar el parámetro w en función no solo del valor de
gradiente actual, sino también de la actualización anterior del parámetro, como en esta
implementación ingenua:
velocidad_pasada = Factor de impulso constante Bucle de
0.
optimización
impulso = 0.1
mientras pérdida >
0.01:
w, pérdida, gradiente = get_current_parameters()
velocidad = velocidad_pasada * impulso + tasa_de_aprendizaje *
gradiente w = w + cantidad de movimiento * velocidad -
tasa_de_aprendizaje * gradiente velocidad_pasada = velocidad
actualizar_parámetro(w)

2.4.4 Encadenamiento de derivadas: el algoritmo Backpropagation


En el algoritmo anterior, casualmente asumimos que debido a que una función es
diferenciable, podemos calcular explícitamente su derivada. En la práctica, una función
de red neuronal consta de muchas operaciones de tensor encadenadas, cada una de las
cuales tiene una derivada simple y conocida. Por ejemplo, esta es una red f compuesta
por tres operaciones tensoriales, a, b y c, con matrices de peso W1, W2 y W3:
f(W1, W2, W3) = a(W1, b(W2, c(W3)))

El cálculo nos dice que tal cadena de funciones se puede derivar usando la siguiente
Con licencia para
identificacióndad, llamada la regla de la cadena: f(g(x)) = f'(g(x)) * g'(x). La aplicación de
la regla de la cadena al cálculo de los valores de gradiente de una red neuronal da lugar a un
algoritmo

Con licencia para


52 CPASADO2 Antes de comenzar: los componentes básicos matemáticos de las redes neuronales

llamado Backpropagation (también llamado a veces diferenciación de modo inverso). La


retropropagación comienza con el valor de pérdida final y trabaja hacia atrás desde las capas
superiores hasta las capas inferiores, aplicando la regla de la cadena para calcular la
contribución que cada parámetro tuvo en el valor de pérdida.
Hoy en día, y en los próximos años, las personas implementarán redes en
marcos modernos que sean capaces de diferenciación simbólica, como TensorFlow.
Esto significa que, dada una cadena de operaciones con una derivada conocida,
pueden calcular una función de gradiente para la cadena (aplicando la regla de la
cadena) que asigna valores de parámetros de red a valores de gradiente. Cuando
tiene acceso a dicha función, el paso hacia atrás se reduce a una llamada a esta
función de gradiente. Gracias a la diferenciación simbólica, nunca tendrá que
implementar manualmente el algoritmo Backpropagation. Por esta razón, no
haremos perder su tiempo y su enfoque en derivar la formulación exacta del
algoritmo de propagación hacia atrás en estas páginas. Todo lo que necesita es una
buena comprensión de cómo funciona la optimización basada en gradientes.

Con licencia para


Mirando hacia atrás a nuestro primerejemplo 53

2.5 Mirando hacia atrás en nuestro primer ejemplo


Ha llegado al final de este capítulo y ahora debería tener una comprensión general
de lo que sucede detrás de escena en una red neuronal. Volvamos al primer ejemplo
y revisemos cada parte a la luz de lo que ha aprendido en las tres secciones
anteriores.
Estos fueron los datos de entrada:
(imágenes_tren, etiquetas_tren), (imágenes_prueba, etiquetas_prueba) =
mnist.load_data() imágenes_tren = imágenes_tren.reshape((60000, 28 * 28))
tren_imágenes = tren_imágenes.astype('float32') / 255
test_images = test_images.reshape((10000, 28 * 28))
test_images = test_images.astype('float32') / 255

Ahora comprende que las imágenes de entrada se almacenan en tensores Numpy, que
sonaquí formateado como tensores de forma float32 (60000, 784) (datos de entrenamiento)
y (10000, 784) (datos de prueba), respectivamente.
Esta fue nuestra red:
red = modelos. Secuencial()
red.añadir(capas.Dense(512, activación='relu', input_shape=(28 * 28,)))
red.añadir(capas.Densa(10, activación='softmax'))

Ahora comprende que esta red consta de una cadena de dos capas densas, que cada capa
aplica algunas operaciones de tensor simples a los datos de entrada y que estas
operaciones involucran tensores de peso. Los tensores de peso, que son atributos de las
capas, es donde persiste el conocimiento de la red.
Este fue el paso de compilación de la red:
red.compile(optimizador='rmsprop',
loss='categorical_crossentropy',métricas=['precis
ión'])

Ahora comprende que categorical_crossentropy es la función de pérdida que se utiliza como


señal de retroalimentación para aprender los tensores de peso, y que la fase de entrenamiento
intentará minimizar. También sabe que esta reducción de la pérdida ocurre a través del
descenso de gradiente estocástico de mini lotes. Las reglas exactas que rigen un uso
específico del descenso de gradiente están definidas por el optimizador rmsprop pasado
como primer argumento.
Finalmente, este fue el ciclo de entrenamiento:
red.fit(tren_imágenes, tren_etiquetas, épocas=5, tamaño_lote=128)

Ahora comprende lo que sucede cuando llama al ajuste: la red comenzará a iterar sobre
los datos de entrenamiento en mini lotes de 128 muestras, 5 veces (cada iteración sobre
todos los datos de entrenamiento se denomina época). En cada iteración, la red calculará
los gradientes de los pesos con respecto a la pérdida en el lote y actualizará los pesos

Con licencia para


54 CPASADO2 Antes de comenzar: los componentes básicos matemáticos de las redes neuronales

respectivamente. Después de estas 5 épocas, la red habrá realizado 2345 actualizaciones


de gradiente (469 por época), y la pérdida de la red será lo suficientemente baja como
para que la red sea capaz de clasificar dígitos escritos a mano con gran precisión.
En este punto, ya sabe la mayor parte de lo que hay que saber sobre las redes neuronales.

Con licencia para


Mirando hacia atrás a nuestro primerejemplo 55

Resumen del capítulo


◾ Aprendizajesignifica encontrar una combinación de parámetros del
modelo que minimice una función de pérdida para un conjunto dado de
muestras de datos de entrenamiento y sus objetivos correspondientes.
◾ El aprendizaje ocurre dibujando lotes aleatorios de muestras de datos y
sus objetivos, y calculando el gradiente de los parámetros de red con
respecto a la pérdida en el lote. Luego, los parámetros de la red se
mueven un poco (la magnitud del movimiento se define por la tasa de
aprendizaje) en la dirección opuesta al gradiente.
◾ Todo el proceso de aprendizaje es posible gracias al hecho de que las
redes neuronales son cadenas de operaciones de tensor diferenciables y,
por lo tanto, es posible aplicar la regla de derivación de la cadena para
encontrar la función de gradiente que mapea los parámetros actuales y el
lote actual de datos para un valor de gradiente.
◾ Dos conceptos clave que verá con frecuencia en capítulos futuros son la
pérdida y los optimizadores. Estas son las dos cosas que necesita definir
antes de comenzar a introducir datos en una red.
◾ La pérdida es la cantidad que intentará minimizar durante el
entrenamiento, por lo que debería representar una medida del éxito de la
tarea que está tratando de resolver.
◾ El optimizador especifica la forma exacta en que se utilizará el gradiente de
la pérdida para actualizar los parámetros: por ejemplo, podría ser
elRMSPoptimizador de rop,EURcon impulso, y así sucesivamente.

Con licencia para


Primeros
pasos con las redes
neuronales

Este capítulo cubre


◾ Componentes centrales de las redes neuronales
◾ Una introducción a Keras
◾ Configuración de una estación de trabajo de
aprendizaje profundo
◾ Uso de redes neuronales para
resolver problemas básicos de
clasificación y regresión

Este capítulo está diseñado para que comience a usar redes neuronales para resolver
problemas reales. Consolidará el conocimiento que obtuvo de nuestro primer ejemplo
práctico en el capítulo 2, y aplicará lo aprendido a tres nuevos problemas que cubren
los tres casos de uso más comunes de las redes neuronales: clasificación binaria,
clasificación multiclase, y regresión escalar.
En este capítulo, veremos más de cerca los componentes centrales de las redes
neuronales que presentamos en el capítulo 2: capas, redes, funciones objetivo y
optimizadores. Le daremos una introducción rápida a Keras, la biblioteca de
aprendizaje profundo de Python que usaremos a lo largo del libro. Configurará una
estación de trabajo de aprendizaje profundo, con

56

Con licencia para


57

Compatibilidad con TensorFlow, Keras y GPU. Nos sumergiremos en tres ejemplos


introductorios de cómo usar las redes neuronales para abordar problemas reales:
◾ Clasificación de críticas de películas como positivas o negativas (clasificación binaria)
◾ Clasificación de cables de noticias por tema (clasificación multiclase)
◾ Estimación del precio de una casa, dados datos inmobiliarios (regresión)

Al final de este capítulo, podrá usar redes neuronales para resolver problemas de
máquinas simples, como clasificación y regresión sobre datos vectoriales. Entonces
estará listo para comenzar a construir una comprensión más basada en principios y
teoría del aprendizaje automático en el capítulo 4.

Con licencia para


58 CPASADO3Primeros pasos con las redes neuronales

3.1 Anatomía de una red neuronal


Como vio en los capítulos anteriores, el entrenamiento de una red neuronal gira en torno a
los siguientes objetos:
◾ Capas, que se combinan en una red (o modelo)
◾ Los datos de entrada y los objetivos correspondientes
◾ La función de pérdida, que define la señal de retroalimentación utilizada para el aprendizaje.
◾ El optimizador, que determina cómo procede el aprendizaje.

Puede visualizar su interacción como se ilustra en la figura 3.1: la red, compuesta


por capas que están encadenadas, asigna los datos de entrada a las predicciones. La
función de pérdida luego compara estas predicciones con los objetivos, produciendo
un valor de pérdida: una medida de qué tan bien las predicciones de la red coinciden
con lo que se esperaba. El optimizador utiliza este valor de pérdida para actualizar
los pesos de la red.

Entrada X

Capa
Pesos
(transformación de
datos)

Capa
Pesos
(transformación de
datos)

Pesoa Prediccion Verdaderos


ctualiz es Y' objetiv
ar os Y

Optimiza Función de
dor pérdida

Figura 3.1 Relación entre la red, las


Puntuación
de pérdida
capas, la función de pérdida y el
optimizador

Echemos un vistazo más de cerca a las capas, redes, funciones de pérdida y optimizadores.

3.1.1 Capas: los componentes básicos del aprendizaje profundo


La estructura de datos fundamental en las redes neuronales es la capa, a la que se le
presentó en el capítulo 2. Una capa es un módulo de procesamiento de datos que toma
como entrada uno o más tensores y que genera uno o más tensores. Algunas capas no
tienen estado, pero más frecuentemente las capas tienen un estado: los pesos de la capa,
uno o varios tensores aprendidos con descenso de gradiente estocástico, que juntos
contienen el conocimiento de la red.
Diferentes capas son apropiadas para diferentes formatos de tensor y diferentes tipos
de procesamiento de datos. Por ejemplo, datos vectoriales simples, almacenados
en2Dtensores de forma(muestras, características), a menudo es procesado por
capas densamente conectadas, también llamadas totalmente conectadas o densas.capas
(laDensoclase en Keras). Datos de secuencia, almacenados en3Dtensores de
forma(muestras, intervalos de tiempo, características), normalmente se
procesapor capas recurrentes como una LSTMcapa. Datos de imagen, almacenados en4Dtensores,
Con licencia para
generalmente se procesa por2Dcapas de convolución (Conv2D).

Con licencia para


Anatomía de un neuralla red 59

Puede pensar en las capas como los ladrillos LEGO del aprendizaje profundo,
una metáfora que se hace explícita en marcos como Keras. La construcción de
modelos de aprendizaje profundo en Keras se realiza recortando capas compatibles
para formar conductos de transformación de datos útiles. La noción de
compatibilidad de capas aquí se refiere específicamente al hecho de que cada capa
solo aceptará tensores de entrada de cierta forma y devolverá tensores de salida de
cierta forma. Considere el siguiente ejemplo:
de keras importar capas
un densocapa con 32
capa = capas. Densa (32, input_shape = unidades de salida
(784,))

Estamos creando una capa que solo aceptará como entrada tensores 2D donde la
primera dimensión sea 784 (el eje 0, la dimensión del lote, no está especificado y,
por lo tanto, se aceptaría cualquier valor). Esta capa devolverá un tensor donde la
primera dimensión ha sido transformada a 32.
Por lo tanto, esta capa solo se puede conectar a una capa descendente que espera
vectores de 32 dimensiones como entrada. Cuando usa Keras, no tiene que preocuparse
por la compatibilidad, porque las capas que agrega a sus modelos se construyen
dinámicamente para que coincidan con la forma de la capa entrante. Por ejemplo,
suponga que escribe lo siguiente:
desde keras importar
modelos desde keras
importar capas
modelo = modelos.Sequential()
modelo.add(capas.Dense(32, input_shape=(784,)))
modelo.add(capas.Dense(32))

La segunda capa no recibió un argumento de forma de entrada; en cambio, infirió


automáticamente su forma de entrada como la forma de salida de la capa anterior.

3.1.2 Modelos: redes de capas


Un modelo de aprendizaje profundo es un gráfico acíclico dirigido de capas. La
instancia más común es una pila lineal de capas, asignando una sola entrada a una
sola salida.
Pero a medida que avance, estará expuesto a una variedad mucho más amplia de
topologías de red. Algunos comunes incluyen los siguientes:
◾ Redes de dos ramas
◾ Redes multicabezal
◾ Bloques de inicio

La topología de una red define un espacio de hipótesis. Tal vez recuerde que en el
capítulo 1, definimos el aprendizaje automático como "buscar representaciones útiles de
algunos datos de entrada, dentro de un espacio predefinido de posibilidades, utilizando
la guía de una señal de retroalimentación". Al elegir una topología de red, restringe su
espacio de posibilidades (espacio de hipótesis) a una serie específica de operaciones de
tensor, asignando datos de entrada a datos de salida. Lo que entonces estará buscando es
Con licencia para
un buen conjunto de valores para los tensores de peso involucrados en estas operaciones
de tensor.

Con licencia para


60 CPASADO3Primeros pasos con las redes neuronales

Elegir la arquitectura de red correcta es más un arte que una ciencia; y aunque
existen algunas mejores prácticas y principios en los que puede confiar, solo la
práctica puede ayudarlo a convertirse en un arquitecto de redes neuronales
adecuado. Los próximos capítulos le enseñarán principios explícitos para construir
redes neuronales y le ayudarán a desarrollar la intuición sobre lo que funciona o no
para problemas específicos.

3.1.3 Funciones de pérdida y optimizadores:


claves para configurar el proceso de aprendizaje
Una vez que se define la arquitectura de la red, aún debe elegir dos cosas más:
◾ Función de pérdida (función objetivo)—La cantidad que se minimizará durante el
entrenamiento. Representa una medida del éxito de la tarea en cuestión.
◾ Optimizador—Determina cómo se actualizará la redbasado en la función de
pérdida. Implementa una variante específica de descenso de gradiente estocástico
(EUR).
Una red neuronal que tiene múltiples salidas puede tener múltiples funciones de
pérdida (una por salida). Pero el proceso de descenso de gradiente debe basarse en
un único valor de pérdida escalar; por lo tanto, para redes de pérdidas múltiples,
todas las pérdidas se combinan (a través del promedio) en una sola cantidad escalar.
Elegir la función objetivo correcta para el problema correcto es extremadamente
importante: su red tomará cualquier atajo que pueda para minimizar la pérdida; por lo
tanto, si el objetivo no se correlaciona completamente con el éxito de la tarea en
cuestión, su red terminará haciendo cosas que quizás no deseaba. Imagine una IA
estúpida y omnipotente entrenada a través de SGD, con esta función objetivo mal
elegida: "maximizar el bienestar promedio de todos los humanos vivos". Para facilitar
su trabajo, esta IA podría optar por matar a todos los humanos excepto a unos pocos y
centrarse en el bienestar de los restantes, porque el bienestar promedio no se ve afectado
por la cantidad de humanos que quedan. ¡Eso podría no ser lo que pretendías! Solo
recuerde que todas las redes neuronales que construya serán igual de implacables a la
hora de reducir su función de pérdida, así que elija el objetivo sabiamente,
Afortunadamente, cuando se trata de problemas comunes como la clasificación, la
regresión y la predicción de secuencias, existen pautas simples que puede seguir para
elegir la pérdida correcta. Por ejemplo, utilizará la entropía cruzada binaria para un
problema de clasificación de dos clases, la entropía cruzada categórica para un problema
de clasificación de muchas clases, el error cuadrático medio para un problema de
regresión, la clasificación temporal conexionista (CTC) para un problema de
aprendizaje de secuencias y pronto. Solo cuando esté trabajando en problemas de
investigación verdaderamente nuevos tendrá que desarrollar sus propias funciones
objetivas. En los próximos capítulos, detallaremos explícitamente qué funciones de
pérdida elegir para una amplia gama de tareas comunes.

Con licencia para


Introduccióna Keras 61

3.2 Introducción a Keras


A lo largo de este libro, los ejemplos de código usan Keras (https://keras.io). Keras
es un marco de aprendizaje profundo para Python que proporciona una forma
conveniente de definir y entrenar casi cualquier tipo de modelo de aprendizaje
profundo. Keras se desarrolló inicialmente para investigadores, con el objetivo de
permitir una experimentación rápida.
Keras tiene las siguientes características clave:
◾ Permite el mismo códigopara funcionar sin problemas en UPCoGPU.
◾ Tiene un fácil de usar APIeso facilita la creación rápida de prototipos de
modelos de aprendizaje profundo.
◾ Tiene soporte incorporado para redes convolucionales (para visión por
computadora), redes recurrentes (para procesamiento de secuencias) y
cualquier combinación de ambas.
◾ Admite arquitecturas de red arbitrarias: modelos de múltiples entradas o
múltiples salidas, uso compartido de capas, uso compartido de modelos, etc.
Esto significa que Keras es apropiado para construir esencialmente cualquier
modelo de aprendizaje profundo, desde una red antagónica generativa hasta
una máquina neuronal de Turing.
Keras se distribuye bajo la licencia permisiva del MIT, lo que significa que puede
usarse libremente en proyectos comerciales. Es compatible con cualquier versión de
Python desde la 2.7 hasta la 3.6 (desde mediados de 2017).
Keras tiene más de 200 000 usuarios, que van desde investigadores académicos
e ingenieros tanto de nuevas empresas como de grandes empresas hasta estudiantes
graduados y aficionados. Keras se utiliza en Google, Netflix, Uber, CERN, Yelp,
Square y cientos de nuevas empresas que trabajan en una amplia gama de
problemas. Keras también es un marco popular en Kaggle, el sitio web de la
competencia de aprendizaje automático, donde casi todas las competencias recientes
de aprendizaje profundo se han ganado utilizando modelos de Keras.

Figura 3.2 Interés de búsqueda web de Google por diferentes marcos de aprendizaje profundo a lo largo del tiempo
Con licencia para
62 CPASADO3Primeros pasos con las redes neuronales

3.2.1 Keras, TensorFlow, Theano y CNTK


Keras es una biblioteca a nivel de modelo que proporciona componentes básicos de
alto nivel para desarrollar modelos de aprendizaje profundo. No maneja operaciones
de bajo nivel como la manipulación y diferenciación de tensores. En su lugar, se
basa en una biblioteca de tensores especializada y bien optimizada para hacerlo, que
actúa como el motor de fondo de Keras. En lugar de elegir una sola biblioteca de
tensores y vincular la implementación de Keras a esa biblioteca, Keras maneja el
problema de forma modular (consulte la figura 3.3); por lo tanto, varios motores
back-end diferentes se pueden conectar sin problemas a Keras. Actualmente, las tres
implementaciones de backend existentes son el backend de TensorFlow, el backend
de Theano y el backend de Microsoft Cognitive Toolkit (CNTK). En el futuro, es
probable que Keras se amplíe para trabajar con más motores de ejecución de
aprendizaje profundo.

Figura 3.3 La pila de software y


hardware de aprendizaje
profundo

TensorFlow, CNTK y Theano son algunas de las plataformas principales para el


aprendizaje profundo en la actualidad.
Teano(http://deeplearning.net/software/theano) es desarrollado por
laMETRO ILAlaboratorio en la Universidad de Montreal, TensorFlow
(www.tensorflow.org) es desarrollado por Google y CNTK
(https://github.com/Microsoft/ CNTK)es desarrollado por Microsoft. Cualquier pieza de
código que escriba con Keras se puede ejecutar con cualquiera de estos backends sin tener
que cambiar nada en el código: puede cambiar sin problemas entre los dos durante el
desarrollo, lo que a menudo resulta útil, por ejemplo, si uno de estos backends demuestra
para ser más rápido para una tarea específica. Recomendamos usar el backend de
TensorFlow como predeterminado para la mayoría de sus necesidades de aprendizaje
profundo, porque es el más adoptado, escalable y listo para producción.
A través de TensorFlow (o Theano, o CNTK), Keras puede ejecutarse sin
problemas tanto en CPU como en GPU. Cuando se ejecuta en la CPU, TensorFlow
envuelve una biblioteca de bajo nivelpara operaciones tensoriales llamadas Eigen
(http://eigen.tuxfamily.org).En la GPU, TensorFlow envuelve una
biblioteca de operaciones de aprendizaje profundo bien optimizadas denominada biblioteca
NVIDIA CUDA Deep Neural Network (cuDNN).

3.2.2 Desarrollar con Keras: una descripción general rápida


Ya ha visto un ejemplo de un modelo Keras: el ejemplo MNIST. El flujo de trabajo
típico de Keras se parece a ese ejemplo:

Con licencia para


1Defina sus datos de entrenamiento: tensores de entrada y tensores objetivo.
2Defina una red de capas (o modelo) que mapee sus entradas a sus objetivos.

Con licencia para


Introduccióna Keras 63

3Configure el proceso de aprendizaje eligiendo una función de pérdida, un


optimizador y algunas métricas para monitorear.
4Repita sus datos de entrenamiento llamando al método fit() de su modelo.

Hay dos formas de definir un modelo: usando la clase Sequential (solo para pilas lineales de
capas, que es la arquitectura de red más común con diferencia) o la API funcional (para
gráficos acíclicos dirigidos de capas, que le permite construir completamente arquitecturas
arbitrarias).
Como repaso, aquí hay un modelo de dos capas definido usando la clase Sequential
(tenga en cuenta que estamos pasando la forma esperada de los datos de entrada a la primera
capa):
desde keras importar
modelos desde keras
importar capas
modelo = modelos. Secuencial()
modelo.add(capas.Dense(32, activación='relu', input_shape=(784,)))
modelo.add(capas.Dense(10, activación='softmax'))

Y aquí está el mismo modelo definido usando la API funcional:


input_tensor = capas.Input(forma=(784,))
x = capas.Densa(32, activación='relu')(entrada_tensor)
salida_tensor = capas.Densa(10, activación='softmax')(x)

modelo = modelos.Modelo(entradas=tensor_de_entrada, salidas=tensor_de_salida)

Con la API funcional, está manipulando los tensores de datos que procesa el modelo
y aplicando capas a este tensor como si fueran funciones.

NOTAPuede encontrar una guía detallada de lo que puede hacer con la API
funcional en el capítulo 7. Hasta el capítulo 7, solo usaremos la clase
Sequential en nuestros ejemplos de código.

Una vez que se define la arquitectura de su modelo, no importa si usó un


Modelo secuencial o funcionalAPI. Todos los pasos siguientes son iguales.
El proceso de aprendizaje se configura en el paso de compilación, donde
especifica el optimizador y las funciones de pérdida que debe usar el modelo, así
como las métricas que desea monitorear durante el entrenamiento. Aquí hay un
ejemplo con una función de pérdida única, que es, con mucho, el caso más común:
desde keras importan optimizadores
model.compile(optimizer=optimizers.RMSprop(lr=0.001),
pérdida='mse',
métricas=['precisión'])

Finalmente, el proceso de aprendizaje consiste en pasar matrices Numpy de datos de


entrada (y los datos de destino correspondientes) al modelo a través del método fit(),
similar a lo que haría en Scikit-Learn y varias otras bibliotecas de aprendizaje
automático:
modelo.fit(entrada_tensor, objetivo_tensor, lote_tamaño=128, épocas=10)

Con licencia para


64 CPASADO3Primeros pasos con las redes neuronales

En los próximos capítulos, desarrollará una intuición sólida sobre qué tipo de
arquitecturas de red funcionan para diferentes tipos de problemas, cómo elegir la
configuración de aprendizaje adecuada y cómo ajustar un modelo hasta que
proporcione los resultados que desea. ver. Veremos tres ejemplos básicos en las
secciones 3.4, 3.5 y 3.6: un ejemplo de clasificación de dos clases, un ejemplo de
clasificación de muchas clases y un ejemplo de regresión.

Con licencia para


Configuración de un aprendizaje profundopuesto de trabajosesenta y cinco

3.3 Configuración de una estación de trabajo de aprendizaje profundo


Antes de que pueda comenzar a desarrollar aplicaciones de aprendizaje profundo,
debe configurar su estación de trabajo. Se recomienda encarecidamente, aunque no
es estrictamente necesario, que ejecute código de aprendizaje profundo en una GPU
NVIDIA moderna. Algunas aplicaciones, en particular, el procesamiento de
imágenes con redes convolucionales y el procesamiento de secuencias con redes
neuronales recurrentes, serán terriblemente lentos en la CPU, incluso en una CPU
multinúcleo rápida. E incluso para las aplicaciones que se pueden ejecutar de
manera realista en la CPU, generalmente verá un aumento de la velocidad en un
factor de 5 o 10 al usar una GPU moderna. Si no desea instalar una GPU en su
máquina, también puede considerar ejecutar sus experimentos en una instancia de
GPU AWS EC2 o en Google Cloud Platform. Pero tenga en cuenta que las
instancias de GPU en la nube pueden volverse costosas con el tiempo.
Ya sea que esté ejecutando localmente o en la nube, es mejor usar una estación
de trabajo Unix. Aunque es técnicamente posible usar Keras en Windows (los tres
backends de Keras son compatibles con Windows), no lo recomendamos. En las
instrucciones de instalación del apéndice A, consideraremos una máquina con
Ubuntu. Si es un usuario de Windows, la solución más simple para que todo
funcione es configurar un arranque dual de Ubuntu en su máquina. Puede parecer
una molestia, pero usar Ubuntu le ahorrará mucho tiempo y problemas a largo
plazo.
Tenga en cuenta que para usar Keras, debe instalar TensorFlow o CNTK o Theano
(o todos ellos, si desea poder alternar entre los tres back-end). En este libro, nos
centraremos en TensorFlow, con algunas instrucciones sencillas relativas a Theano. No
cubriremos CNTK.

3.3.1 Cuadernos Jupyter: la forma


preferida de ejecutar experimentos de
aprendizaje profundo
Los cuadernos de Jupyter son una excelente manera de ejecutar experimentos de
aprendizaje profundo, en particular, los numerosos ejemplos de código de este libro.
Son ampliamente utilizados en las comunidades de ciencia de datos y aprendizaje
automático. Un cuaderno es un archivo generado por la aplicación Jupyter
Notebook (https://jupyter.org), cual tú pueden editar en su navegador. Eso mezclas
la capacidad para ejecutar código de Python con capacidades de edición de texto
enriquecidas para anotar lo que está haciendo. Un cuaderno también le permite
dividir experimentos largos en partes más pequeñas que se pueden ejecutar de
forma independiente, lo que hace que el desarrollo sea interactivo y significa que
no tiene que volver a ejecutar todo su código anterior si algo sale mal al final de un
experimento.
Recomendamos usar portátiles Jupyter para comenzar con Keras, aunque no es
un requisito: también puede ejecutar secuencias de comandos de Python
independientes o ejecutar código desde un IDE como PyCharm. Todos los ejemplos
de código de este libro están disponibles como cuadernos de código abierto; Puedes
descargarlos del sitio web del libro enwww.manning

Con licencia para


.com/books/aprendizaje-profundo-con-python.

Con licencia para


66 CPASADO3Primeros pasos con las redes neuronales

3.3.2 Hacer funcionar Keras: dos opciones


Para empezar en la práctica, recomendamos una de las siguientes dos opciones:
◾ usa el oficialEC2Aprendizaje profundoIAM(https://aws.amazon.com/amazon-
ai/amis), y ejecutar experimentos de Keras como cuadernos de Jupyter en EC2.
Haga esto si aún no tiene un GPUen su máquina local. El Apéndice B
proporciona una guía paso a paso.
◾ Instale todo desde cero en una estación de trabajo Unix local. A continuación,
puede ejecutar cuadernos de Jupyter locales o una base de código de Python
normal. Haz esto si ya tienes un gama altaGPU NVIDIA. El Apéndice A
proporciona una guía paso a paso específica de Ubuntu.
Echemos un vistazo más de cerca a algunos de los compromisos involucrados en
elegir una opción sobre la otra.

3.3.3 Ejecutar trabajos de aprendizaje profundo en la nube: pros y contras


Si aún no tiene una GPU que pueda usar para el aprendizaje profundo (una GPU
NVIDIA reciente y de gama alta), ejecutar experimentos de aprendizaje profundo en
la nube es una forma simple y económica de comenzar sin tener que comprar
cualquier hardware adicional. Si usa portátiles Jupyter, la experiencia de ejecutar en
la nube no es diferente de ejecutar localmente. A partir de mediados de 2017, la
oferta en la nube que hace que sea más fácil comenzar con el aprendizaje profundo
es definitivamente AWS EC2. El Apéndice B proporciona una guía paso a paso para
ejecutar portátiles Jupyter en una instancia de GPU EC2.
Pero si es un gran usuario del aprendizaje profundo, esta configuración no es
sostenible a largo plazo, ni siquiera por más de unas pocas semanas. Las instancias EC2
son costosas: el tipo de instancia recomendado en el apéndice B (la instancia p2.xlarge,
que no le proporcionará mucha potencia) cuesta $0.90 por hora a partir de mediados de
2017. Mientras tanto, una GPU sólida de clase de consumidor le costará entre $ 1000 y
$ 1500, un precio que se ha mantenido bastante estable a lo largo del tiempo, incluso
cuando las especificaciones de estas GPU siguen mejorando. Si se toma en serio el
aprendizaje profundo, debe configurar una estación de trabajo local con una o más GPU.
En resumen, EC2 es una excelente manera de comenzar. Puede seguir los
ejemplos de código de este libro en su totalidad en una instancia de GPU EC2. Pero
si va a ser un usuario avanzado del aprendizaje profundo, obtenga sus propias GPU.

3.3.4 ¿Cuál es la mejor GPU para el aprendizaje profundo?


Si vas a comprar una GPU, ¿cuál deberías elegir? Lo primero a tener en cuenta es
que debe ser una GPU NVIDIA. NVIDIA es la única empresa de computación
gráfica que ha invertido mucho en aprendizaje profundo hasta el momento, y los
marcos modernos de aprendizaje profundo solo pueden ejecutarse en tarjetas
NVIDIA.
Desde mediados de 2017, recomendamos NVIDIA TITAN Xp como la mejor tarjeta
del mercado para aprendizaje profundo. Para presupuestos más bajos, es posible que
desee considerar la GTX 1060. Si está leyendo estas páginas en 2018 o más tarde,
tómese el tiempo para buscar en línea recomendaciones más actualizadas, porque todos

Con licencia para


los años salen nuevos modelos.

Con licencia para


Configuración de un aprendizaje profundopuesto de trabajo 67

A partir de esta sección, supondremos que tiene acceso a una máquina con Keras y
sus dependencias instaladas, preferiblemente con compatibilidad con GPU. Asegúrese
de terminar este paso antes de continuar. Lea las guías paso a paso en los apéndices y
busque en línea si necesita más ayuda. No faltan tutoriales sobre cómo instalar Keras y
las dependencias comunes de aprendizaje profundo.
Ahora podemos sumergirnos en ejemplos prácticos de Keras.

Con licencia para


68 CPASADO3Primeros pasos con las redes neuronales

3.4 Clasificación de las reseñas de películas:


un ejemplo de clasificación binaria
La clasificación de dos clases, o clasificación binaria, puede ser el tipo de problema de
aprendizaje automático más aplicado. En este ejemplo, aprenderá a clasificar las reseñas
de películas como positivas o negativas, según el contenido del texto de las reseñas.

3.4.1 El conjunto de datos de IMDB


Trabajará con el conjunto de datos de IMDB: un conjunto de 50 000 reseñas altamente
polarizadas de Internet Movie Database. Se dividen en 25 000 revisiones para
capacitación y 25 000 revisiones para pruebas, cada conjunto consta de 50 % de
revisiones negativas y 50 % de revisiones positivas.
¿Por qué usar conjuntos de prueba y entrenamiento separados? ¡Porque nunca
debe probar un modelo de aprendizaje automático con los mismos datos que usó
para entrenarlo! El hecho de que un modelo funcione bien con sus datos de
entrenamiento no significa que funcionará bien con datos que nunca ha visto; y lo
que le importa es el rendimiento de su modelo en datos nuevos (porque ya conoce
las etiquetas de sus datos de entrenamiento; obviamente, no necesita su modelo para
predecirlos). Por ejemplo, es posible que su modelo termine simplemente
memorizando un mapeo entre sus muestras de entrenamiento y sus objetivos, lo que
sería inútil para la tarea de predecir objetivos para datos que el modelo nunca antes
había visto. Abordaremos este punto con mucho más detalle en el próximo capítulo.
Al igual que el conjunto de datos MNIST, el conjunto de datos IMDB viene
empaquetado con Keras. Ya ha sido preprocesado: las revisiones (secuencias de
palabras) se han convertido en secuencias de números enteros, donde cada número
entero representa una palabra específica en un diccionario.
El siguiente código cargará el conjunto de datos (cuando lo ejecute por primera
vez, se descargarán alrededor de 80 MB de datos en su máquina).

Listado 3.1 Cargando la IMDBconjunto de datos

desde keras.datasets importar imdb

(datos_de_entrenamiento, etiquetas_de_entrenamiento),
(datos_de_prueba, etiquetas_de_prueba) =
imdb.load_data(num_words=10000)

El argumento num_words=10000 significa que solo conservará las 10 000 palabras más
frecuentes en los datos de entrenamiento. Las palabras raras serán descartadas. Esto le
permite trabajar con datos vectoriales de tamaño manejable.
las variablestren_datosydatos de pruebason listas dereseñas; cada reseña es una
lista de índices de palabras (que codifican una secuencia de
palabras).tren_etiquetasyetiquetas_de_pruebason listas de 0 y 1, donde 0
representa negativo y 1 representa positivo:
>>> tren_datos[0]
[1, 14, 22, 16, ... 178, 32]

>>>
tren_etiquetas[0] 1

Con licencia para


Clasificación de críticas de cine: una clasificación binariaejemplo 69

Debido a que se está restringiendo a las 10 000 palabras más frecuentes, ningún
índice de palabras superará las 10 000:
>>> max([max(secuencia) para secuencia en
train_data]) 9999

Por diversión, así es como puede decodificar rápidamente una de estas reseñas en
palabras en inglés:
word_index es un mapeo de diccionario
word_index = imdb.get_word_index() palabras a un índice entero.
reverse_word_index = dict(
[(valor, clave) para (clave, valor) en
word_index.items()]) decoded_review = ' '.join(
[reverse_word_index.get(i - 3, '?') for i in train_data[0]])

Lo invierte, Decodifica la revisión. Tenga en cuenta


mapeandoíndices enteros que los índices están compensados por 3
a palabras porque 0,1, y 2 son índices reservados
para "relleno", "inicio de
secuencia” y “desconocido”.
3.4.2 Preparando los
datos
No puede alimentar listas de enteros en una red neuronal. Tienes que convertir tus
listas en tensores. Hay dos maneras de hacerlo:
◾ Rellene sus listas para que todas tengan la misma longitud, conviértalas en un
número enterotensor de forma(muestras, word_indices), y luego use como
la primera capa en su red una capa capaz de manejar tales tensores enteros
(elincrustacióncapa, que veremos en detalle más adelante en el libro).
◾ Codifique en caliente sus listas para convertirlas en vectores de 0 y 1. Esto
significaría, por ejemplo, cambiar la secuencia [3, 5]en un vector de 10,000
dimensiones que sería todo 0 excepto los índices 3 y 5, que serían 1. Entonces
podría usar como primera capa en su red un Densocapa, capaz de manejar datos
vectoriales de coma flotante.
Vayamos con la última solución para vectorizar los datos, lo que hará manualmente
para obtener la máxima claridad.

Listado 3.2 Codificando las secuencias enteras en una matriz binaria

importar numpy como np


Crea una matriz de forma
def vectorize_sequences(secuencias, de todos ceros
dimensión=10000): resultados = (len(secuencias),
np.zeros((len(secuencias), dimensión)) para i, dimensión)
secuencia en enumerar(secuencias):
resultados[i, secuencia] Establece índices
= 1. resultados devueltos específicos de
x_tren = resultados[i] para1s
vectorizar_secuencias(datos_de_entrenamie Datos de entrenamiento
nto) x_prueba = vectorizados Datos de
vectorizar_secuencias(datos_de_prueba) prueba vectorizados

Con licencia para


70 CPASADO3Primeros pasos con las redes neuronales

Así es como se ven las muestras ahora:


>>> tren_x[0]
matriz ([ 0., 1., 1., ..., 0., 0., 0.])

También debe vectorizar sus etiquetas, lo cual es sencillo:


y_train = np.asarray(train_labels).astype('float32')
y_test = np.asarray(test_labels).astype('float32')

Ahora los datos están listos para ser alimentados a una red neuronal.

3.4.3 Construyendo tu red


Los datos de entrada son vectores y las etiquetas son escalares (1 y 0): esta es la
configuración más fácil que jamás encontrará. Un tipo de red que funciona bien en tal
problema esuna pila simple de capas (Densas) completamente conectadas con activaciones
relu: Dense(16, activación='relu').
El argumento que se pasa a cada capa densa (16) es el número de unidades ocultas
de la capa. Una unidad oculta es una dimensión en el espacio de representación de la
capa. Puede recordar del capítulo 2 que cada una de esas capas densas con una
activación relu implementa la siguiente cadena de operaciones de tensor:
salida = relu(punto(W, entrada) + b)

Tener 16 unidades ocultas significa que la matriz de peso W tendrá forma (input_dimension,
16): el producto escalar con W proyectará los datos de entrada en un espacio de
representación de 16 dimensiones (y luego agregará el vector de sesgo b y aplicará la
operación relu). Puede entender intuitivamente la dimensionalidad de su espacio de
representación como “cuánta libertad permite que tenga la red cuando aprende
representaciones internas”. Tener más unidades ocultas (un espacio de representación de
mayor dimensión) le permite a su red aprender representaciones más complejas, pero hace
que la red sea más costosa desde el punto de vista computacional y puede conducir al
aprendizaje de patrones no deseados (patrones que mejorarán el rendimiento en los datos de
entrenamiento pero no en los datos de prueba).
Hay dos decisiones clave de arquitectura que se deben tomar sobre una pila de capas densas de
este tipo:
◾ Cuantas capas usar
◾ Cuántas unidades ocultas elegir para cada capa

En el capítulo 4, aprenderá los principios formales que lo guiarán al tomar estas


decisiones. Por el momento, tendrá que confiar en mí con la siguiente elección de
arquitectura:
◾ Dos capas intermedias con 16 unidades ocultas cada una
◾ Una tercera capa que generará la predicción escalar con respecto al
sentimiento de la revisión actual
Las capas intermedias usarán relu como su función de activación, y la capa final usará
una activación sigmoidea para generar una probabilidad (una puntuación entre 0 y 1,

Con licencia para


Clasificación de críticas de cine: una clasificación binariaejemplo 71

indicando la probabilidad de que la muestra tenga el objetivo "1": la probabilidad de que


la revisión sea positiva). Una relu (unidad lineal rectificada) es una función destinada a
poner a cero los valores negativos (consulte la figura 3.4), mientras que un sigmoide
"aplasta" los valores arbitrarios en el intervalo [0, 1] (consulte la figura 3.5), generando
algo que se puede interpretar como una probabilidad.

Figura 3.4 La función de unidad lineal rectificada

Figura 3.5 La función sigmoidea

Con licencia para


72 CPASADO3Primeros pasos con las redes neuronales

Salida
(probabilida
d)

Denso (unidades=1)

Denso (unidades=16)

Denso (unidades=16)

Secuencial
Aporte
(vectorizadotext Figura 3.6 La red de tres capas
o)

La figura 3.6 muestra cómo se ve la red. Y aquí está la implementación de Keras,


similar al ejemplo de MNIST que viste anteriormente.

Listado 3.3 La definición del modelo

desde keras importar


modelos desde keras
importar capas
modelo = modelos. Secuencial()
modelo.add(capas.Dense(16, activación='relu', input_shape=(10000,)))
modelo.add(capas.Dense(16, activación='relu'))
modelo.add(capas.Dense(1 , activación='sigmoide'))

¿Qué son las funciones de activación y por qué son necesarias?


Sin una función de activación comorelu(también llamado unno linealidad),
laDensocapaconsistiría en dos operaciones lineales: un producto escalar y una
suma:
salida = punto (W, entrada) + b

Entonces la capa solo podía aprendertransformaciones lineales(transformaciones


afines) de los datos de entrada: elespacio de hipótesisde la capa sería el
conjunto de todas las transformaciones lineales posibles de los datos de entrada
en un espacio de 16 dimensiones. Tal espacio de hipótesis es demasiado
restringido y no se beneficiaría de múltiples capas de representaciones, porque
una pila profunda de capas lineales aún implementaría una operación lineal:
agregar más capas no extendería el espacio de hipótesis.
Para obtener acceso a un espacio de hipótesis mucho más rico que se
beneficiaría de representaciones profundas, necesita una función de no
linealidad o activación.relues elfunción de activación más popular en el
aprendizaje profundo, pero hay muchasotros candidatos, que vienen con nombres
igualmente extraños:prelu,elu, y así.
Finalmente, debe elegir una función de pérdida y un optimizador. Debido a que
enfrenta un problema de clasificación binaria y la salida de su red es una
probabilidad (termina su red con una capa de una sola unidad con una activación
sigmoidea), es mejor usar el
Con licencia para
Clasificación de críticas de cine: una clasificación binariaejemplo 73

pérdida de entropía cruzada binaria. No es la única opción


viable: podría usar, por ejemplo, mean_squared_error. Pero la
entropía cruzada suele ser la mejor opción cuando se trata de
modelos que generan probabilidades. La entropía cruzada es una
cantidad del campo de la teoría de la información que mide la
distancia entre las distribuciones de probabilidad o, en este
caso, entre la distribución de la verdad fundamental y sus
predicciones.
Este es el paso en el que configura el modelo con el optimizador rmsprop y la
función de pérdida binary_crossentropy. Tenga en cuenta que también controlará la
precisión durante el entrenamiento.

Listado 3.4 Compilando elmodelo

modelo.compilar(optimizador='rmsprop',
loss='binary_crossentropy',métricas=['precisi
ón'])

Está pasando su optimizador, función de pérdida y métricas como cadenas, lo cual es


posible porque rmsprop, binary_crossentropy y precision están empaquetados como
parte de Keras. En ocasiones, es posible que desee configurar los parámetros de su
optimizador o pasar una función de pérdida personalizada o una función métrica. Lo
primero se puede hacer pasando una instancia de clase de optimizador como argumento
del optimizador, como se muestra en el listado 3.5; esto último se puede hacer pasando
objetos de función como argumentos de pérdida y/o métrica, como se muestra en el
listado 3.6.

Listado 3.5 Configurando el optimizador

de los optimizadores de importación de keras


modelo.compilar(optimizador=optimizadores.RMSprop(lr=0.001)
,loss='binary_crossentropy',
metrics=['accuracy'])

Listado 3.6 Uso de pérdidas aduaneras ymétrica

de pérdidas de
importación de keras de
métricas de importación
de keras
modelo.compilar(optimizador=optimizadores.RMSprop(lr=0.001),loss=losses.binary
_crossentropy, metrics=[metrics.binary_accuracy])

3.4.4 Validando su enfoque


Para monitorear durante el entrenamiento la precisión del modelo en datos que nunca
antes había visto, creará un conjunto de validación separando 10,000 muestras de los
datos de entrenamiento originales.

Listado 3.7 Dejando de lado una validaciónestablecer

Con licencia para


valor_x = tren_x[:10000]
tren_x_parcial = tren_x[10000:]

Con licencia para


74 CPASADO3Primeros pasos con las redes neuronales

y_val = tren_y[:10000]
tren_y_parcial = tren_y[10000:]

Ahora entrenará el modelo durante 20 épocas (20 iteraciones sobre todas las muestras
en eltensores x_train y y_train), en mini-lotes de 512 muestras.
Al mismo tiempo, controlará la pérdida y la precisión de las
10 000 muestras que separó. Lo hace pasando los datos de
validación como el argumento validation_data.

Listado 3.8 Entrenando tu modelo

modelo.compilar(optimizador='rmsprop',
loss='binary_crossentropy',métricas=['acc
'])
historia = modelo.ajuste(parcial_x_tren,
tren_y_parcial,é
pocas=20,
tamaño_lote=512,
validación_datos=(x_val, y_val))

En la CPU, esto tomará menos de 2 segundos por época; el entrenamiento finaliza


en 20 segundos. Al final de cada época, hay una pequeña pausa mientras el modelo
calcula su pérdida y precisión en las 10 000 muestras de los datos de validación.
Tenga en cuenta que la llamada a model.fit() devuelve un objeto Historial. Este objeto
tiene un historial de miembros, que es un diccionario que contiene datos sobre todo lo que
sucedió durante el entrenamiento. Veámoslo:
>>> historia_dict = historia.historia
>>> historia_dict.keys()
[u'acc', u'loss', u'val_acc', u'val_loss']

El diccionario contiene cuatro entradas: una por métrica que se estaba monitoreando
durante el entrenamiento y durante la validación. En las siguientes dos listas, usemos
Matplotlib para trazar la pérdida de entrenamiento y validación una al lado de la otra
(consulte la figura 3.7), así como la precisión del entrenamiento y la validación
(consulte la figura 3.8). Tenga en cuenta que sus propios resultados pueden variar
ligeramente debido a una inicialización aleatoria diferente de su red.

Listado 3.9 Graficando la pérdida de entrenamiento y validación

importar matplotlib.pyplot como plt


history_dict = history.history
loss_values = history_dict['loss']
val_loss_values = history_dict['val_loss']

epochs = range(1, len(acc) + 1)


"bo" es para
plt.plot(epochs, loss_values, 'bo', label='Training loss') "punto
plt.plot(epochs, val_loss_values, 'b', label='Validation loss') azul".
plt.title('Pérdida de entrenamiento y validación')
plt.xlabel('Épocas') "b" es para "sólido
línea azul."
plt.ylabel('Pérdida'
) plt.leyenda()
plt.mostrar()
Con licencia para
Clasificación de críticas de cine: una clasificación binariaejemplo 75

Figura 3.7 Pérdida de entrenamiento y validación

Listado 3.10 Trazado de la precisión de entrenamiento y validación

plt.clf() Borra la figura


acc_values = history_dict['acc']
val_acc_values = history_dict['val_acc']
plt.plot(epochs, acc, 'bo', label='Entrenamiento acc')
plt.plot(epochs, val_acc, 'b', label='Validation acc')
plt.title('Precisión de entrenamiento y validación')
plt .xlabel('Épocas')
plt.ylabel('Pérdid
a')plt.leyenda()
plt.mostrar()

Figura 3.8 Precisión de entrenamiento y validación

Con licencia para


76 CPASADO3Primeros pasos con las redes neuronales

Como puede ver, la pérdida de entrenamiento disminuye con cadaépoca, y la


precisión del entrenamiento aumenta con cada época. Eso es lo que esperaría al
ejecutar la optimización de descenso de gradiente: la cantidad que intenta minimizar
debe ser menor con cada iteración. Pero ese no es el caso de la pérdida de
validación y la precisión: parecen alcanzar su punto máximo en la cuarta época.
Este es un ejemplo de lo que advertimos anteriormente: un modelo que funciona
mejor con los datos de entrenamiento no es necesariamente un modelo que
funcionará mejor con datos que nunca antes había visto. En términos precisos, lo
que está viendo es un ajuste excesivo: después de la segunda época, está
optimizando en exceso los datos de entrenamiento y termina aprendiendo
representaciones que son específicas de los datos de entrenamiento y no se
generalizan a datos fuera de el conjunto de entrenamiento.
En este caso, para evitar el sobreajuste, podría dejar de entrenar después de tres
épocas. En general, puede usar una variedad de técnicas para mitigar el sobreajuste, que
trataremos en el capítulo 4.
Entrenemos una nueva red desde cero durante cuatro épocas y luego la
evaluaremos en los datos de prueba.

Listado 3.11 Reentrenamiento de un modelo desde cero

modelo = modelos. Secuencial()


modelo.add(capas.Dense(16, activación='relu', input_shape=(10000,)))
modelo.add(capas.Dense(16, activación='relu'))
modelo.add(capas.Dense(1 , activación='sigmoide'))

modelo.compilar(optimizador='rmsprop',
loss='binary_crossentropy',métricas=['precisión
'])
model.fit(x_train, y_train, epochs=4, batch_size=512)
resultados = model.evaluate(x_test, y_test)

Los resultados finales son los siguientes:


>>> resultados
[0.2929924130630493, 0.88327999999999995]

Este enfoque bastante ingenuo logra una precisión del 88%. Con enfoques de última
generación, debería poder acercarse al 95 %.

3.4.5 Usar una red entrenada para generar prediccionesen nuevos datos
Después de haber entrenado una red, querrá usarla en un entorno práctico. Puede generar
la probabilidad de que las reseñas sean positivas utilizando el método de predicción:
>>>
modelo.predecir(x_test)
array([[ 0.98006207]
[ 0.99758697]
[ 0.99975556]
...,
[ 0.82167041]
[ 0.02885115]
[ 0.65371346]], dtype=float32)
Con licencia para
Clasificación de críticas de cine: una clasificación binariaejemplo 77

Como puede ver, la red tiene confianza para algunas muestras (0,99 o más, o 0,01 o
menos) pero menos confianza para otras (0,6, 0,4).

3.4.6 Más experimentos


Los siguientes experimentos lo ayudarán a convencerse de que las elecciones de
arquitectura que ha realizado son bastante razonables, aunque todavía hay margen de
mejora:
◾ Usaste dos capas ocultas. Intente usar una o tres capas ocultas y vea cómo esto
afecta la validación y la precisión de la prueba.
◾ Intente usar capas con más unidades ocultas o menos unidades ocultas: 32
unidades, 64 unidades, etc.
◾ Intenta usar el msefunción de pérdida en lugar de entropía_cruzada_binaria.
◾ Intenta usar elbronceadoactivación (una activación que era popular en los
primeros días de las redes neuronales) en lugar de relu.

3.4.7 Terminando
Esto es lo que debe sacar de este ejemplo:
◾ Por lo general, necesita hacer un poco de preprocesamiento en sus datos sin
procesar para poder alimentarlos, como tensores, en una red neuronal. Las
secuencias de palabras se pueden codificar como vectores binarios, pero
también hay otras opciones de codificación.
◾ montones deDensocapas conrelulas activaciones pueden resolver una amplia gama
de problemas (incluida la clasificación de opiniones) y es probable que las utilice con
frecuencia.
◾ En un problema de clasificación binaria (dos clases de salida), su red debe
terminar con unDensocapa con una unidad y unasigmoideoactivación:la salida
de su red debe ser un escalar entre 0 y 1, codificando una probabilidad.
◾ Con tal salida sigmoidea escalar en un problema de clasificación binaria, la
función de pérdida que debe usar es entropía_cruzada_binaria.
◾ losrmspropEl optimizador es generalmente una opción lo suficientemente
buena, cualquiera que sea su problema. Eso es una cosa menos de la que
preocuparse.
◾ A medida que mejoran sus datos de entrenamiento, las redes neuronales
eventualmente comienzan a sobreajustarse y terminan obteniendo resultados
cada vez peores en datos que nunca antes habían visto. Asegúrese de
monitorear siempre el rendimiento de los datos que están fuera del conjunto
de entrenamiento.

Con licencia para


78 CPASADO3Primeros pasos con las redes neuronales

3.5 clasificandocables de noticias:


un ejemplo de clasificación multiclase
En la sección anterior, vio cómo clasificar entradas vectoriales en dos clases
mutuamente excluyentes utilizando una red neuronal densamente conectada. Pero, ¿qué
sucede cuando tienes más de dos clases?
En esta sección, construirá una red para clasificar los cables de noticias de Reuters
en 46 temas mutuamente excluyentes. Debido a que tiene muchas clases, este problema
es una instancia de clasificación multiclase; y porque cada punto de datos debe
clasificarse en una sola categoría.sangriento, el problema es más específicamente una
instancia de clasificación multiclase de una sola etiqueta. Si cada punto de datos pudiera
pertenecer a varias categorías (en este caso, temas), se enfrentaría a un problema de
clasificación multietiqueta y multiclase.

3.5.1 El conjunto de datos de Reuters


Trabajará con el conjunto de datos de Reuters, un conjunto de noticias breves y sus
temas, publicado por Reuters en 1986. Es un conjunto de datos de juguete simple y
ampliamente utilizado para la clasificación de textos. Hay 46 temas diferentes; algunos
temas están más representados que otros, pero cada tema tiene al menos 10 ejemplos en
el conjunto de entrenamiento.
Al igual que IMDB y MNIST, el conjunto de datos de Reuters viene
empaquetado como parte de Keras. Vamos a ver.

Listado 3.12 Cargando el Reutersconjunto de datos

de keras.datasets importar Reuters


(datos_de_entrenamiento, etiquetas_de_entrenamiento), (datos_de_prueba,
etiquetas_de_prueba) = reuters.load_data(num_words=10000)

Al igual que con el conjunto de datos de IMDB, el argumento num_words=10000


restringe los datos a las 10 000 palabras más frecuentes que se encuentran en los datos.
Tienes 8982 ejemplos de entrenamiento y 2246 ejemplos de prueba:
>>>
len(datos_de_tren)
8982
>>>
len(datos_de_prueb
a) 2246

Al igual que con las revisiones de IMDB, cada ejemplo es una lista de números enteros (índices de
palabras):
>>> tren_datos[10]
[1, 245, 273, 207, 156, 53, 74, 160, 26, 14, 46, 296, 26, 39, 74, 2979,
3554, 14, 46, 4689, 4329, 86, 61, 3499, 4795, 14, 61, 451, 4329, 17, 12]

Así es como puedesdescifrarlo en palabras, en caso de que tenga curiosidad.

Listado 3.13 Decodificación de cables de noticias de vuelta atexto

índice_palabra = reuters.get_índice_palabra()
reverse_word_index = dict([(valor, clave) para (clave, valor) en word_index.items()])

Con licencia para


decoded_newswire=''.join([reverse_word_index.get(i -3,'?')parar iinorte
tren_datos[0]])
Tenga en cuenta que los índices están compensados por 3 porque 0,1, y 2
son índices reservados para "relleno", "inicio de secuencia" y "desconocido".

Con licencia para


Clasificación de los cables de noticias: una clasificación multiclaseejemplo 79

La etiqueta asociada con un ejemplo es un número entero entre 0 y 45, un índice de tema:
>>>
entrenar_etiquetas[1
0] 3

3.5.2 Preparando los datos


Puede vectorizar los datos con exactamente el mismo código que en el ejemplo anterior.

Listado 3.14 Codificando eldatos

importar numpy como np

def vectorize_sequences(secuencias,
dimensión=10000): resultados =
np.zeros((len(secuencias), dimensión)) para i,
secuencia en enumerar(secuencias):
resultados[i, secuencia] = 1.
devolver
resultados Datos de entrenamiento

x_tren = vectorizados Datos de prueba


vectorizar_secuencias(datos_de_entrenamie
nto) x_prueba = vectorizados
vectorizar_secuencias(datos_de_prueba)
Para vectorizar las etiquetas, hay dos posibilidades: puede convertir la lista de etiquetas
como un tensor entero, o puede usar la codificación one-hot. La codificación one-hot es
un formato ampliamente utilizado para datos categóricos, también llamado codificación
categórica. Para obtener una explicación más detallada de la codificación one-hot,
consulte la sección 6.1. En este caso, la codificación one-hot de las etiquetas consiste en
incrustar cada etiqueta como un vector todo cero con un 1 en lugar del índice de la
etiqueta. Aquí hay un ejemplo:
def to_one_hot(etiquetas, dimensión=46):
resultados = np.zeros((len(etiquetas),
dimensión)) para i, etiqueta en
enumerar(etiquetas):
resultados[i,
Etiquetas de entrenamiento
etiqueta] = 1. devolver
resultados
vectorizadas Etiquetas de prueba
one_hot_train_labels = to_one_hot(train_labels)
one_hot_test_labels = to_one_hot(test_labels) vectorizadas

Tenga en cuenta que hay una forma integrada de hacer esto en Keras, que ya ha visto en
acción en el ejemplo de MNIST:
de keras.utils.np_utils importar a_categorical
one_hot_train_labels = to_categorical(train_labels)
one_hot_test_labels = to_categorical(test_labels)

3.5.3 Construyendo tu red


Este problema de clasificación de temas se parece al problema anterior de clasificación
de reseñas de películas: en ambos casos, está tratando de clasificar fragmentos cortos de
texto. Pero aquí hay una nueva restricción: el número de clases de salida ha pasado de 2
Con licencia para
a 46. La dimensionalidad del espacio de salida es mucho mayor.
En una pila de capas densas como la que ha estado usando, cada capa solo puede acceder
a la información presente en la salida de la capa anterior. Si una capa deja caer alguna
información

Con licencia para


80 CPASADO3Primeros pasos con las redes neuronales

relevante para el problema de clasificación, esta información nunca puede ser


recuperada por capas posteriores: cada capa puede convertirse potencialmente en un
cuello de botella de información. En el ejemplo anterior, usó capas intermedias de 16
dimensiones, pero un espacio de 16 dimensiones puede ser demasiado limitado para
aprender a separar 46 clases diferentes: capas tan pequeñas pueden actuar como cuellos
de botella de información, eliminando información relevante de forma permanente.
Por esta razón, utilizará capas más grandes. Vamos con 64 unidades.

Listado 3.15 Modelodefinición

desde keras importar


modelos desde keras
importar capas
modelo = modelos. Secuencial()
modelo.add(capas.Dense(64, activación='relu', input_shape=(10000,)))
modelo.add(capas.Dense(64, activación='relu'))
modelo.add(capas.Dense(46 , activación='softmax'))

Hay otras dos cosas que debe tener en cuenta sobre esta arquitectura:
◾ Terminas la red con unDensocapa de tamaño 46. Esto significa que para cada
muestra de entrada, la red generará un vector de 46 dimensiones. Cada entrada en
este vector (cada dimensión) codificará una clase de salida diferente.
◾ La última capa utiliza unsoftmaxactivación. Usted vio este patrón en
elMNISTejemplo. Significa que la red generará una distribución de probabilidad
sobre las 46 clases de salida diferentes: para cada muestra de entrada, la red
producirá un vector de salida de 46 dimensiones, donde salida[yo]es la
probabilidad de que la muestra pertenezca a la clase i. Las 46 puntuaciones
sumarán 1.
La mejor función de pérdida para usar en este casoes categorical_crossentropy. Mide la
distancia entre dos distribuciones de probabilidad: aquí, entre la salida de distribución
de probabilidad de la red y la distribución real de las etiquetas. Al minimizar la distancia
entre estas dos distribuciones, entrenas a la red para generar algo lo más cercano posible
a las etiquetas verdaderas.

Listado 3.16 Compilando elmodelo

modelo.compilar(optimizador='rmsprop',
loss='categorical_crossentropy',métricas=['prec
isión'])

3.5.4 Validando su enfoque


Separaremos 1000 muestras en los datos de entrenamiento para usarlas como un conjunto de
validación.

Listado 3.17 Dejando de lado una validaciónestablecer

valor_x = tren_x[:1000]
tren_x_parcial = tren_x[1000:]
y_val = etiquetas_de_un_tren_caliente[:1000]
Con licencia para
tren_y_parcial =
etiquetas_de_un_tren_caliente_uno[1000:]

Con licencia para


Clasificación de los cables de noticias: una clasificación multiclaseejemplo 81

Ahora, entrenemos la red durante 20 épocas.

Listado 3.18 Entrenando el modelo

historia = modelo.ajuste(parcial_x_tren,
tren_y_parcial,é
pocas=20,
tamaño_lote=512,
validación_datos=(x_val, y_val))

Y finalmente, mostremos sus curvas de pérdida y precisión (ver figuras 3.9 y 3.10).

Listado 3.19 Graficando la pérdida de entrenamiento y validación

importar matplotlib.pyplot como plt

pérdida = historia.historia['pérdida']
val_pérdida =
historia.historia['val_pérdida']

épocas = rango (1, len (pérdida) + 1)

plt.plot(épocas, pérdida, 'bo', label='Pérdida de


entrenamiento') plt.plot(épocas, val_loss, 'b',
label='Pérdida de validación') plt.title('Pérdida de
entrenamiento y validación') plt .xlabel('Épocas')
plt.ylabel('Pérdid
a')plt.leyenda()
plt.mostrar()

Listado 3.20 Trazado de la precisión de entrenamiento y validación


plt.clf() Borra la figura
acc = historia.historia['acc']
val_acc = historia.historia['val_acc']

plt.plot(epochs, acc, 'bo', label='Entrenamiento acc')


plt.plot(epochs, val_acc, 'b', label='Validation acc')
plt.title('Precisión de entrenamiento y validación')
plt .xlabel('Épocas')
plt.ylabel('Pérdid
a')plt.leyenda()
plt.mostrar()

Figura 3.9 Pérdida de entrenamiento y validación

Con licencia para


82 CPASADO3Primeros pasos con las redes neuronales

Figura 3.10 Capacitación


yprecisión de validación

La red comienza a sobreajustarse después de nueve épocas. Entrenemos una nueva red
desde cero durante nueve épocas y luego la evaluaremos en el conjunto de prueba.

Listado 3.21 Reentrenamiento de un modelo desde cero

modelo = modelos. Secuencial()


modelo.add(capas.Dense(64, activación='relu', input_shape=(10000,)))
modelo.add(capas.Dense(64, activación='relu'))
modelo.add(capas.Dense(46 , activación='softmax'))
modelo.compilar(optimizador='rmsprop',
loss='categorical_crossentropy',métricas=['prec
isión'])
model.fit(parcial_x_tren,
tren_y_parcial,
épocas=9,
tamaño_lote=512,
validación_datos=(x_val, y_val))
resultados = modelo.evaluar(x_test, one_hot_test_labels)

Aquí están los resultados finales:


>>> resultados
[0.9565213431445807, 0.79697239536954589]

Este enfoque alcanza una precisión de ~80%. Con un problema de clasificación binaria
balanceada, la precisión alcanzada por un clasificador puramente aleatorio sería del
50%. Pero en este caso está más cerca del 19 %, por lo que los resultados parecen
bastante buenos, al menos en comparación con una línea de base aleatoria:
>>> importar copia
>>> prueba_etiquetas_copia = copiar.copiar(prueba_etiquetas)
>>> np.random.shuffle(prueba_etiquetas_copia)
>>> hits_array = np.array(test_labels) == np.array(test_labels_copy)
>>> float(np.sum(hits_array)) / len(test_labels)
0.18655387355298308

Con licencia para


Clasificación de los cables de noticias: una clasificación multiclaseejemplo 83

3.5.5 Generación de predicciones sobre nuevos datos


Puede verificar que el método de predicción de la instancia del modelo devuelve una distribución
de probabilidad sobre los 46 temas. Generemos predicciones de temas para todos los datos de
prueba.

Listado 3.22 Generando predicciones para nuevos datos

predicciones = modelo.predecir(x_test)

Cada entrada enprediccioneses un vector de longitud 46:


>>>
predicciones[0].forma
(46,)

Los coeficientes en este vector suman 1:


>>>
np.sum(predicciones[0])
1.0

La entrada más grande es la clase predicha, la clase con la probabilidad más alta:
>>>
np.argmax(predicciones[0]) 4

3.5.6 Una forma diferente de manejarlas etiquetas y la pérdida


Anteriormente mencionamos que otra forma de codificar las etiquetas sería
convertirlas en un tensor entero, así:
y_tren =
np.array(tren_etiquetas) y_test
= np.array(prueba_etiquetas)

Lo único que cambiaría este enfoque es la elección de la función de pérdida. La


pérdidafunción utilizada en el listado 3.21,categorical_crossentropy, espera que las
etiquetas sigan una codificación categórica. Con etiquetas enteras, debe
usarsparse_categorical_ crossentropy:
modelo.compilar(optimizador='rmsprop',
loss='parse_categorical_crossentropy',métricas=['ac
c'])

Esta nueva función de pérdida sigue siendo matemáticamente la misma


quecategorical_crossentropy; simplemente tiene una interfaz diferente.

3.5.7 La importancia de tener capas intermedias suficientemente grandes


Mencionamos anteriormente que debido a que los resultados finales son de 46
dimensiones, debe evitar las capas intermedias con muchas menos de 46 unidades
ocultas. Ahora veamos qué sucede cuando introduce un cuello de botella de información
al tener capas intermedias que son significativamente menos de 46 dimensiones: por
ejemplo, 4 dimensiones.

Con licencia para


84 CPASADO3Primeros pasos con las redes neuronales

Listado 3.23 Un modelo con un cuello de botella de información


modelo = modelos. Secuencial()
modelo.add(capas.Dense(64, activación='relu', input_shape=(10000,)))
modelo.add(capas.Dense(4, activación='relu'))
modelo.add(capas.Dense(46 , activación='softmax'))
modelo.compilar(optimizador='rmsprop',
loss='categorical_crossentropy',métricas=['prec
isión'])
model.fit(parcial_x_tren,
tren_y_parcial,
épocas=20,
tamaño_lote=128,
validación_datos=(x_val, y_val))

La red ahora alcanza su punto máximo con una precisión de validación de ~71 %,
una caída absoluta del 8 %. Esta caída se debe principalmente al hecho de que está
tratando de comprimir mucha información (información suficiente para recuperar
los hiperplanos de separación de 46 clases) en un espacio intermedio que tiene una
dimensión demasiado baja. La red puede incluir la mayor parte de la información
necesaria en estas representaciones de ocho dimensiones, pero no toda.

3.5.8 Más experimentos


◾ Intente usar capas más grandes o más pequeñas: 32 unidades, 128 unidades, etc.
◾ Usaste dos capas ocultas. Ahora intente usar una sola capa oculta o tres capas
ocultas.

3.5.9 Terminando
Esto es lo que debe sacar de este ejemplo:
◾ Si está tratando de clasificar puntos de datos entre norteclases, su red debe
terminar con unDensocapa de tamañonorte.
◾ En un problema de clasificación multiclase de una sola etiqueta, su red debe
terminar con unasoftmaxactivación para que genere una distribución de
probabilidad sobre las N clases de salida.
◾ La entropía cruzada categórica es casi siempre la función de pérdida que debe
usar para tales problemas. Minimiza la distancia entre las distribuciones de
probabilidad generadas por la red y la verdadera distribución de los objetivos.
◾ Hay dos formas de manejar las etiquetas en la clasificación multiclase:
– Codificación de las etiquetas a través de categoríascodificación (también
conocida como codificación one-hot) y
usocategorical_crossentropycomo una función de pérdida
– Codificando las etiquetas como enteros yutilizando elsparse_categorical_crossentropy
función de pérdida
◾ Si necesita clasificar datos en una gran cantidad de categorías, debe evitar
crear cuellos de botella de información en su red debido a capas intermedias
que son demasiado pequeñas.

Con licencia para


Predicción de los precios de la vivienda: una regresiónejemplo 85

3.6 Predicción de los precios de la vivienda: un ejemplo de regresión


Los dos ejemplos anteriores se consideraron problemas de clasificación, donde el
objetivo era predecir una sola etiqueta discreta de un punto de datos de entrada. Otro
tipo común de problema de aprendizaje automático es la regresión, que consiste en
predecir un valor continuo en lugar de una etiqueta discreta: por ejemplo, predecir la
temperatura de mañana, dados los datos meteorológicos; o predecir el tiempo que
tardará en completarse un proyecto de software, dadas sus especificaciones.

NOTANo confunda la regresión y la regresión logística del algoritmo. De


manera confusa, la regresión logística no es un algoritmo de regresión, es un
algoritmo de clasificación.

3.6.1 El conjunto de datos del precio de la vivienda de Boston


Intentará predecir el precio medio de las viviendas en un determinado suburbio de
Boston a mediados de la década de 1970, dados los puntos de datos sobre el
suburbio en ese momento, como la tasa de criminalidad, la tasa de impuestos locales
sobre la propiedad, etc. El conjunto de datos que usará tiene una diferencia
interesante con respecto a los dos ejemplos anteriores. Tiene relativamente pocos
puntos de datos: solo 506, divididos entre 404 muestras de entrenamiento y 102
muestras de prueba. Y cada característica en los datos de entrada (por ejemplo, la
tasa de criminalidad) tiene una escala diferente. Por ejemplo, algunos valores son
proporciones, que toman valores entre 0 y 1; otros toman valores entre 1 y 12, otros
entre 0 y 100, y así sucesivamente.

Listado 3.24 Cargando la carcasa Bostonconjunto de datos

de keras.datasets importar boston_housing


(datos_de_entrenamiento, objetivos_de_entrenamiento), (datos_de_prueba,
objetivos_de_prueba) =
➥boston_housing.load_data()
Veamos los datos:
>>> tren_datos.forma
(404, 13)
>>>
prueba_datos.forma
(102, 13)

Como puede ver, tiene 404 muestras de capacitación y 102 muestras de prueba,
cada una con 13 características numéricas, como la tasa de criminalidad per cápita,
el número promedio de habitaciones por vivienda, la accesibilidad a las carreteras,
etc.
Los objetivos son los valores medios de las viviendas ocupadas por sus
propietarios, en miles de dólares:
>>> entrenar_objetivos
[ 15.2, 42.3, 50. ... 19.4, 19.4, 29.1]

Los precios suelen oscilar entre $ 10,000 y $ 50,000. Si eso suena barato, recuerde
Con licencia para
que esto fue a mediados de la década de 1970, y estos precios no están ajustados por
inflación.

Con licencia para


86 CPASADO3Primeros pasos con las redes neuronales

3.6.2 Preparando los datos


Sería problemático alimentar una red neuronal con valores que toman rangos muy
diferentes. La red podría adaptarse automáticamente a datos tan heterogéneos, pero
definitivamente dificultaría el aprendizaje. Una buena práctica generalizada para tratar
con tales datos es hacer una normalización por características: para cada característica
en los datos de entrada (una columna en la matriz de datos de entrada), se resta la media
de la característica y se divide por la desviación estándar, de modo que la característica
se centra alrededor de 0 y tiene una desviación estándar unitaria. Esto se hace
fácilmente en Numpy.

Listado 3.25 Normalizando los datos

media =
datos_del_tren.media(eje=0)
datos_del_tren -= media
std = train_data.std(axis=0)
train_data /= std
test_data -=
media test_data
/= std

Tenga en cuenta que las cantidades utilizadas para normalizar los datos de prueba se
calculan utilizando los datos de entrenamiento. Nunca debe usar en su flujo de
trabajo ninguna cantidad calculada en los datos de prueba, incluso para algo tan
simple como la normalización de datos.

3.6.3 Construyendo tu red


Debido a que hay tan pocas muestras disponibles, utilizará una red muy pequeña con
dos capas ocultas, cada una con 64 unidades. En general, cuantos menos datos de
entrenamiento tenga, peor será el sobreajuste, y el uso de una red pequeña es una forma
de mitigar el sobreajuste.

Listado 3.26 Modelodefinición

desde keras importar


Debido a que necesitará instanciar el
modelos desde keras mismo modelo varias veces, use una
importar capas función para construirlo.
def construir_modelo():
modelo = modelos.
Secuencial()
modelo.add(capas.Dense(64, activación='relu',
input_shape=(tren_datos.forma[1],)))mode
lo.add(capas.Dense(64, activación='relu'))
modelo.add(capas.Dense(1))
model.compile(optimizer='rmsprop', loss='mse', metrics=['mae'])
modelo de retorno

La red termina con una sola unidad y sin activación (será una capa lineal). Esta es
una configuración típica para la regresión escalar (una regresión en la que intenta
predecir un único valor continuo). La aplicación de una función de activación

Con licencia para


limitaría el rango que puede tomar la salida; por ejemplo, si aplicó una función de
activación sigmoidea a la última capa, la red solo podría aprender a predecir valores
entre 0 y 1. Aquí, debido a que la última capa es puramente lineal, la red puede
aprender a predecir valores en cualquier rango. .

Con licencia para


Predicción de los precios de la vivienda: una regresiónejemplo 87

Tenga en cuenta que compila la red con la función de pérdida mse: error cuadrático
medio, el cuadrado de la diferencia entre las predicciones y los objetivos. Esta es una
función de pérdida ampliamente utilizada para problemas de regresión.
También está monitoreando una nueva métrica durante el entrenamiento: error
absoluto medio (MAE). Es el valor absoluto de la diferencia entre las predicciones y los
objetivos. Por ejemplo, un MAE de 0,5 en este problema significaría que sus
predicciones tienen un error de $500 en promedio.

3.6.4 Validación de su enfoque utilizando la validación K-fold


Para evaluar su red mientras sigue ajustando sus parámetros (como el número de épocas
utilizadas para el entrenamiento), podría dividir los datos en un conjunto de
entrenamiento y un conjunto de validación, como lo hizo en los ejemplos anteriores.
Pero debido a que tiene tan pocos puntos de datos, el conjunto de validación terminaría
siendo muy pequeño (por ejemplo, alrededor de 100 ejemplos). Como consecuencia, los
puntajes de validación pueden cambiar mucho según los puntos de datos que elija usar
para la validación y los que elija para el entrenamiento: los puntajes de validación
pueden tener una gran variación con respecto a la división de validación. Esto le
impediría evaluar de forma fiable su modelo.
La mejor práctica en tales situaciones es utilizar la validación cruzada K-fold
(consulte la figura 3.11). Consiste en dividir los datos disponibles en K particiones
(típicamente K = 4 o 5), crear instancias de K modelos idénticos y entrenar cada uno en
K – 1 particiones mientras se evalúa en la partición restante. El puntaje de validación
para el modelo utilizado es entonces el promedio de los puntajes de validación K
obtenidos. En términos de código, esto es sencillo.

Datos divididos en 3 particiones

Validació
Doblar 1 Validación Capacitació Capacitació npuntuaci
n n ón #1

Validació Finalpuntaj
Doblar 2
n e:
puntuació promedio
Validación Validación Capacitació
n #2
n
Doblar 3
Validació
Validación Capacitació Validación
n
n
Figura 3.11 Validación cruzada puntuació
triple n #3

Listado 3.27 Validación de K-fold

importar numpy como np


k = 4
num_val_muestras = len(tren_datos)// k
num_epochs = 100
todas las puntuaciones = []
Con licencia para
88 CPASADO3Primeros pasos con las redes neuronales

Prepara los datos de Prepara los datos de


validación: datos de la entrenamiento: datos de todas
partición #k las demás particiones
for i in range(k):
print('procesando pliegue
#', i)
val_data = train_data[i * num_val_samples: (i + 1) * num_val_samples]
val_targets = train_targets[i * num_val_samples: (i + 1) * num_val_samples]
datos_tren_parciales =
np.concatenar([datos_tren[:i *
num_val_muestras],
tren_datos[(i + 1) * Construye el Kerasmodelo
num_val_samples:]],eje=0) (ya compilado)
objetivos_tren_parciales =
np.concatenar([objetivos_de_entrenamiento[: Entrena el
i * num_val_muestras], modelo (en modo
entrenar_objetivos[(i + 1) * silencioso,
num_val_samples:]],eje=0) detallado = 0)
modelo = build_model()
modelo.fit(datos_tren_parciales, objetivos_tren_parciales,
época
s=número_épocas, tamaño_lote=1, detallado=0)
val_mse, val_mae = model.evaluate(val_data, val_targets,detallado=0)
all_scores.append(val_mae)
Evalúa el modelo
sobre los datos de
validación.

Ejecutar esto connum_epochs = 100arroja los siguientes resultados:


>>> todas las puntuaciones
[2.588258957792037, 3.1289568449719116, 3.1856116051248984, 3.0763342615401386]
>>>
np.media(todas_las_punt
uaciones)2.99479041735
72462

De hecho, las diferentes ejecuciones muestran puntajes de validación bastante


diferentes, de 2.6 a 3.2. El promedio (3.0) es una métrica mucho más confiable que
cualquier puntaje único; ese es el objetivo de la validación cruzada de K-fold. En este
caso, tiene una diferencia de $ 3,000 en promedio, lo cual es significativo si se tiene en
cuenta que los precios oscilan entre $ 10,000 y $ 50,000.
Intentemos entrenar la red un poco más: 500 épocas. Para mantener un registro de
qué tan bien funciona el modelo en cada época, modificará el ciclo de entrenamiento
para guardar el registro de puntuación de validación por época.

Listado 3.28 Guardando los registros de validación en cadadoblar

num_epochs = 500
all_mae_histories =
Prepara los datos de
validación: datos de la
[] for i in range(k):
partición #k
imprimir('procesandodoblar
#', i)
val_data = train_data[i * num_val_samples: (i + 1) * num_val_samples]
Con licencia para
val_targets = train_targets[i * num_val_samples: (i + 1) * num_val_samples]
datos_tren_parciales =
Prepara los datos de
np.concatenar([datos_tren[:i *
entrenamiento: datos de
num_val_muestras],
todas las demás
tren_datos[(i + 1) * particiones
num_val_samples:]],eje=0)

Con licencia para


Predicción de los precios de la vivienda: un 89
ejemplo de regresión

objetivos_tren_parciales = Construye el
np.concatenar([objetivos_de_entrenamiento[:i Kerasmodelo (ya
* num_val_muestras], compilado)
entrenar_objetivos[(i + 1) *
num_val_samples:]],eje=0)
modelo = build_model()
history = model.fit(datos_tren_parciales, objetivos_tren_parciales,

validación_datos=(val_datos, val_objetivos),
épocas=num_épocas, tamaño_lote=1, detallado=0)
mae_history = historia.historia['val_mean_absolute_error']
all_mae_histories.append(mae_history) Entrena el modelo
(en modo silencioso,
detallado=0)

A continuación, puede calcular el promedio de las puntuaciones MAE por época para todos los pliegues.

Listado 3.29 Construyendo el historial de puntuaciones medias sucesivas de validación de K-fold

promedio_mae_historia = [
np.mean([x[i] for x in all_mae_histories]) for i in range(num_epochs)]

Tracemos esto; ver figura 3.12.

Listado 3.30 Validación de ploteopuntuaciones

importar matplotlib.pyplot como plt


plt.plot(rango(1, len(historial_mae_promedio) + 1),
historial_mae_promedio) plt.xlabel('Épocas')
plt.ylabel('Validación MAE')
plt.show()

Figura 3.12
ValidaciónMAE por
época

Puede ser un poco difícil ver el gráfico, debido a problemas de escala y una varianza
relativamente alta. Hagamos lo siguiente:
◾ omitir el primero10 puntos de datos, que están en una escala diferente al resto de la curva.

Con licencia para


◾ Reemplace cada punto con un promedio móvil exponencial de los puntos
anteriores, para obtener una curva suave.

Con licencia para


90 CPASADO3Primeros pasos con las redes neuronales

El resultado se muestra en la figura 3.13.

Listado 3.31 Trazado de puntajes de validación, excluyendo los primeros 10 datospuntos

def suavizar_curva(puntos,
factor=0.9): suavizar_puntos = []
para punto en puntos:
si
puntos_suavizados:
anterior = puntos_suavizados[-1]
smoothed_points.append(previous * factor + point * (1 - factor))
else:
puntos_suavizados.append(punto)de
volver puntos_suavizados
smooth_mae_history = smooth_curve(average_mae_history[10:])
plt.plot(rango(1, len(smooth_mae_history) + 1), smooth_mae_history)
plt.xlabel('Épocas')
plt.ylabel('Validación MAE')
plt.show()

Figura 3.13 Validación MAE


por época, excluyendo la
primera10 puntos de datos

Según este gráfico, la validación MAE deja de mejorar significativamente después de


80 épocas. Más allá de ese punto, comienzas a sobreajustarte.
Una vez que haya terminado de ajustar otros parámetros del modelo (además de
la cantidad de épocas, también puede ajustar el tamaño de las capas ocultas), puede
entrenar un modelo de producción final con todos los datos de entrenamiento, con
los mejores parámetros. y, a continuación, mire su rendimiento en los datos de
prueba.

Listado 3.32 Entrenando el modelo final

Obtiene un modelo nuevo y compilado


modelo = build_model() Lo entrena en la totalidad de los datos.
model.fit(train_data, train_targets,
épocas=80, tamaño_lote=16,
detallado=0)
test_mse_score, test_mae_score = model.evaluate(test_data, test_targets)

Con licencia para


Predicción de los precios de la vivienda: una regresiónejemplo 91

Aquí está el resultado final:


>>> test_mae_score
2.5532484335057877

Todavía te faltan unos $2,550.

3.6.5 Terminando
Esto es lo que debe sacar de este ejemplo:
◾ La regresión se realiza usando funciones de pérdida diferentes a las que usamos
para la clasificación. Error medio cuadrado ( MSE) es una función de pérdida
comúnmente utilizada para la regresión.
◾ De manera similar, las métricas de evaluación que se usarán para la regresión
difieren de las que se usan para la clasificación; naturalmente, el concepto de
precisión no se aplica a la regresión. Una métrica de regresión común es el error
absoluto medio (MAE).
◾ Cuando las características en los datos de entrada tienen valores en diferentes
rangos, cada característica debe escalarse de forma independiente como un
paso de preprocesamiento.
◾ Cuando hay pocos datos disponibles, el uso de la validación K-fold es una
excelente manera de evaluar un modelo de manera confiable.
◾ Cuando hay pocos datos de entrenamiento disponibles, es preferible usar una red
pequeña con pocas capas ocultas (normalmente solo una o dos), para evitar un
sobreajuste severo.

Con licencia para


92 CPASADO3Primeros pasos con las redes neuronales

Resumen del capítulo


◾ Ahora puede manejar los tipos más comunes de tareas de aprendizaje
automático en datos vectoriales: clasificación binaria, clasificación
multiclase y regresión escalar. Las secciones de “Conclusión” anteriores
en el capítulo resumen los puntos importantes que ha aprendido con
respecto a este tipo de tareas.
◾ Por lo general, deberá preprocesar los datos sin procesar antes de
introducirlos en una red neuronal.
◾ Cuando sus datos tengan características con diferentes rangos, escale
cada característica de forma independiente como parte del
preprocesamiento.
◾ A medida que avanza el entrenamiento, las redes neuronales eventualmente
comienzan a sobreajustarse y obtienen peores resultados en datos nunca
antes vistos.
◾ Si no tiene muchos datos de entrenamiento, use una red pequeña con solo
una o dos capas ocultas para evitar un sobreajuste severo.
◾ Si sus datos están divididos en muchas categorías, puede causar cuellos
de botella de información si hace que las capas intermedias sean
demasiado pequeñas.
◾ La regresión usa diferentes funciones de pérdida y diferentes métricas
de evaluación que la clasificación.
◾ Cuando trabaja con pocos datos, la validación K-fold puede ayudarlo a
evaluar su modelo de manera confiable.

Con licencia para


Fundamentos del
aprendizaje
automático

Este capítulo cubre


◾ Formas de aprendizaje automático más allá de la
clasificacióny regresión
◾ Procedimientos formales de evaluación de
máquinas.modelos de aprendizaje
◾ Preparación de datos para el aprendizaje profundo
◾ Ingeniería de características
◾ Abordar el sobreajuste
◾ El flujo de trabajo universal para acercarse a la
máquina.problemas de aprendizaje

Después de los tres ejemplos prácticos del capítulo 3, debería empezar a


familiarizarse con la forma de abordar los problemas de clasificación y regresión
utilizando redes neuronales, y habrá sido testigo del problema central del
aprendizaje automático: el sobreajuste. Este capítulo formalizará parte de su
nueva intuición en un marco conceptual sólido para atacar y resolver problemas
de aprendizaje profundo. Consolidaremos todos estos conceptos (evaluación de
modelos, preprocesamiento de datos e ingeniería de funciones, y abordar el
sobreajuste) en un flujo de trabajo detallado de siete pasos para abordar cualquier
tarea de aprendizaje automático.

93

Con licencia para


94 CPASADO4fundamentos de maquinaaprendizaje

4.1 Cuatro ramas del aprendizaje automático


En nuestros ejemplos anteriores, se ha familiarizado con tres tipos específicos de
problemas de aprendizaje automático: clasificación binaria, clasificación multiclase
y regresión escalar. Los tres son instancias de aprendizaje supervisado, donde el
objetivo es aprender la relación entre los insumos de capacitación y los objetivos de
capacitación.
El aprendizaje supervisado es solo la punta del iceberg: el aprendizaje
automático es un campo amplio con una compleja taxonomía de subcampos. Los
algoritmos de aprendizaje automático generalmente se dividen en cuatro categorías
amplias, que se describen en las siguientes secciones.

4.1.1 supervisadoaprendizaje
Este es, con mucho, el caso más común. Consiste en aprender a asignar datos de entrada
a objetivos conocidos (también llamados anotaciones), dado un conjunto de ejemplos (a
menudo anotados por humanos). Los cuatro ejemplos que ha encontrado en este libro
hasta ahora son ejemplos canónicos de aprendizaje supervisado. En general, casi todas
las aplicaciones de aprendizaje profundo que están en el centro de atención en estos días
pertenecen a esta categoría, como el reconocimiento óptico de caracteres, el
reconocimiento de voz, la clasificación de imágenes y la traducción de idiomas.
Aunque el aprendizaje supervisado consiste principalmente en clasificación y
regresión, también existen variantes más exóticas, incluidas las siguientes (con
ejemplos):
◾ Generación de secuencias—Dada una imagen, predice un pie de foto que la describa.
La generación de secuencias a veces se puede reformular como una serie de
problemas de clasificación (como predecir repetidamente una palabra o un token en
una secuencia).
◾ Predicción del árbol de sintaxis— Dada una oración, predecir su descomposición
en un árbol sintáctico.
◾ Detección de objetos—Dada una imagen, dibuja un cuadro delimitador alrededor
de ciertos objetos dentro de la imagen. Esto también se puede expresar como un
problema de clasificación (dados muchos cuadros delimitadores candidatos,
clasifique el contenido de cada uno) o como un problema conjunto de
clasificación y regresión, donde las coordenadas del cuadro delimitador se
predicen a través de una regresión vectorial.
◾ Segmentación de imagen—Dada una imagen, dibuje una máscara a nivel de píxel en un objeto
específico.

4.1.2 sin supervisiónaprendizaje


Esta rama del aprendizaje automático consiste en encontrar transformaciones
interesantes de los datos de entrada sin la ayuda de ningún objetivo, con fines de
visualización de datos, compresión de datos o eliminación de ruido de datos, o para
comprender mejor las correlaciones presentes en los datos disponibles. El aprendizaje
no supervisado es el pan y la mantequilla del análisis de datos y, a menudo, es un paso
necesario para comprender mejor un conjunto de datos antes de intentar resolver un
problema de aprendizaje supervisado. La reducción de la dimensionalidad y el
Con licencia para
agrupamiento son categorías bien conocidas de aprendizaje no supervisado.

4.1.3 Aprendizaje autosupervisado


Esta es una instancia específica de aprendizaje supervisado, pero es lo suficientemente
diferente como para merecer su propia categoría. El aprendizaje autosupervisado es un
aprendizaje supervisado sin

Con licencia para


Cuatro ramas de la máquinaaprendizaje 95

etiquetas anotadas por humanos: puede pensar en ello como un aprendizaje


supervisado sin humanos en el circuito. Todavía hay etiquetas involucradas (porque
el aprendizaje tiene que ser supervisado por algo), pero se generan a partir de los
datos de entrada, generalmente usando un algoritmo heurístico.
Por ejemplo, los codificadores automáticos son una instancia bien conocida de
aprendizaje autosupervisado, donde los objetivos generados son la entrada, sin
modificar. De la misma manera, tratar de predecir el siguiente cuadro en un video,
dados los cuadros pasados, o la siguiente palabra en un texto, dada la previsión
previa.palabras, son ejemplos de aprendizaje autosupervisado (aprendizaje supervisado
temporalmente, en este caso: la supervisión proviene de datos de entrada futuros). Tenga en
cuenta que la distinción entre el aprendizaje supervisado, autosupervisado y no supervisado
puede ser borrosa a veces; estas categorías son más bien un continuo sin fronteras sólidas. El
aprendizaje autosupervisado se puede reinterpretar como aprendizaje supervisado o no
supervisado, según se preste atención al mecanismo de aprendizaje o al contexto de su
aplicación.

NOTAEn este libro, nos centraremos específicamente en el aprendizaje


supervisado, porque es, con mucho, la forma dominante de aprendizaje
profundo en la actualidad, con una amplia gama de aplicaciones
industriales. También daremos una mirada más breve al aprendizaje
autosupervisado en capítulos posteriores.

4.1.4 Aprendizaje reforzado


Pasada por alto durante mucho tiempo, esta rama del aprendizaje automático
recientemente comenzó a recibir mucha atención después de que Google DeepMind
la aplicó con éxito para aprender a jugar juegos de Atari (y, más tarde, aprender a
jugar Go al más alto nivel). En el aprendizaje por refuerzo, un agente recibe
información sobre su entorno y aprende a elegir acciones que maximizarán alguna
recompensa. Por ejemplo, una red neuronal que "mira" la pantalla de un videojuego
y genera acciones del juego para maximizar su puntaje puede entrenarse mediante el
aprendizaje por refuerzo.
Actualmente, el aprendizaje por refuerzo es principalmente un área de
investigación y aún no ha tenido éxitos prácticos significativos más allá de los
juegos. Con el tiempo, sin embargo, esperamos ver que el aprendizaje por refuerzo
se apodere de una gama cada vez mayor de aplicaciones del mundo real:
automóviles autónomos, robótica, gestión de recursos, educación, etc. Es una idea
cuyo momento ha llegado, o llegará pronto.

Glosario de clasificación y regresión


La clasificación y la regresión involucran muchos términos especializados. Se ha
encontrado con algunos de ellos en ejemplos anteriores y verá más en capítulos
futuros. Tienen definiciones precisas y específicas del aprendizaje automático, y
debería estar familiarizado con ellas:
◾ Muestraoaporte—Un punto de datosque va en su modelo.
◾ Predicciónoproducción—Lo que sale de tu maqueta.
◾ Objetivo-La verdad. Lo que idealmente debería haber predicho su modelo,
segúna una fuente externa de datos.
Con licencia para
96 CPASADO4fundamentos de maquinaaprendizaje

(continuado)
◾ Error de predicciónovalor de pérdida: una medida de la distancia entre la
predicción de su modelo y el objetivo.
◾ Clases—Un conjunto de etiquetas posibles para elegir en un problema de
clasificación. Por ejemplo, al clasificar imágenes de gatos y perros, "perro"
y "gato" son las dos clases.
◾ Etiqueta: una instancia específica de una anotación de clase en un
problema de clasificación. Por ejemplo, si se anota que la imagen #1234
contiene la clase "perro", entonces "perro" es una etiqueta de la imagen
#1234.
◾ verdad básicaoanotaciones: todos los objetivos de un conjunto de datos,
normalmente recopilados porhumanos
◾ clasificación binaria—Una tarea de clasificación en la que cada muestra de
entrada debe categorizarse en dos categorías exclusivas.
◾ Clasificación multiclase—Una tarea de clasificación en la que cada muestra
de entrada debe categorizarse en más de dos categorías: por ejemplo,
clasificar dígitos escritos a mano.
◾ Clasificación multietiqueta: una tarea de clasificación en la que a cada
muestra de entrada se le pueden asignar varias etiquetas. Por ejemplo,
una imagen determinada puede contener tanto un gato como un perro y
debe anotarse tanto con la etiqueta "gato" como con la etiqueta "perro".
El número de etiquetas por imagen suele ser variable.
◾ regresión escalar: una tarea en la que el objetivo es un valor escalar
continuo. Predecir los precios de la vivienda es un buen ejemplo: los
diferentes precios objetivo forman un espacio continuo.
◾ Regresión vectorial: una tarea en la que el objetivo es un conjunto de
valores continuos: por ejemplo, un vector continuo. Si está realizando una
regresión contra varios valores (como las coordenadas de un cuadro
delimitador en una imagen), entonces está realizando una regresión
vectorial.
◾ mini-loteolote—Un pequeño conjunto de muestras (normalmente entre 8 y
128) que el modelo procesa simultáneamente. El número de muestras
suele ser una potencia de 2, para facilitar la asignación de memoria en la
GPU. Durante el entrenamiento, se utiliza un mini lote para calcular una
única actualización de descenso de gradiente aplicada a los pesos del
modelo.

Con licencia para


Evaluación del aprendizaje automáticomodelos 97

4.2 Evaluación de modelos de aprendizaje automático


En los tres ejemplos presentados en el capítulo 3, dividimos los datos en un conjunto de
entrenamiento, un conjunto de validación y un conjunto de prueba. La razón para no
evaluar los modelos con los mismos datos con los que fueron entrenados rápidamente se
hizo evidente: después de unas pocas épocas, los tres modelos comenzaron a
sobreajustarse. Es decir, su desempeño en datos nunca antes vistos comenzó a
estancarse (o empeorar) en comparación con su desempeño en los datos de
entrenamiento, que siempre mejora a medida que avanza el entrenamiento.
En el aprendizaje automático, el objetivo es lograr modelos que generalicen, que
funcionen bien con datos nunca antes vistos, y el sobreajuste es el obstáculo central.
Solo puede controlar lo que puede observar, por lo que es crucial poder medir de
manera confiable el poder de generalización de su modelo. Las siguientes secciones
analizan las estrategias para mitigar el sobreajuste y maximizar la generalización. En
esta sección, nos centraremos en cómo medir la generalización: cómo evaluar modelos
de aprendizaje automático.

4.2.1 Conjuntos de entrenamiento, validación y prueba


La evaluación de un modelo siempre se reduce a dividir los datos disponibles en tres
conjuntos: entrenamiento, validación y prueba. Entrena con los datos de entrenamiento
y evalúa su modelo con los datos de validación. Una vez que su modelo esté listo para el
horario de máxima audiencia, lo prueba una última vez en los datos de prueba.
Puede preguntarse, ¿por qué no tener dos conjuntos: un conjunto de entrenamiento y
un conjunto de prueba? Entrenaría con los datos de entrenamiento y evaluaría con los
datos de prueba. ¡Mucho más sencillo!
La razón es que desarrollar un modelo implica siempre afinar su configuración: por
ejemplo, elegir el número de capas o el tamaño de las capas (llamados hiperparámetros
del modelo, para distinguirlos de los parámetros, que son los de la red). pesos). Este
ajuste se realiza utilizando como señal de retroalimentación el rendimiento del modelo
en los datos de validación. En esencia, esta sintonización es una forma de aprendizaje:
una búsqueda de una buena configuración en algún espacio de parámetros. Como
resultado, ajustar la configuración del modelo en función de su rendimiento en el
conjunto de validación puede resultar rápidamente en un ajuste excesivo del conjunto de
validación, aunque su modelo nunca se entrene directamente en él.
Central a este fenómeno es la noción de fugas de información. Cada vez que ajusta
un hiperparámetro de su modelo en función del rendimiento del modelo en el conjunto
de validación, alguna información sobre los datos de validación se filtra en el modelo.
Si hace esto solo una vez, para un parámetro, se filtrarán muy pocos bits de información
y su conjunto de validación seguirá siendo confiable para evaluar el modelo. Pero si
repite esto muchas veces (ejecutando un experimento, evaluando el conjunto de
validación y modificando su modelo como resultado), entonces filtrará una cantidad
cada vez más significativa de información sobre el conjunto de validación en el modelo.
Al final del día, obtendrá un modelo que funciona artificialmente bien en los datos
de validación, porque para eso lo optimizó. Le importa el rendimiento en datos
completamente nuevos, no los datos de validación, por lo que necesita usar un conjunto
de datos completamente diferente y nunca antes visto para evaluar el modelo: el
Con licencia para
conjunto de datos de prueba. Su modelo no debería haber tenido acceso a ninguna
información sobre el conjunto de prueba, ni siquiera indirectamente.

Con licencia para


98 CPASADO4fundamentos de maquinaaprendizaje

Si algo sobre el modelo se ha ajustado en función del rendimiento del conjunto de


prueba, entonces su medida de generalización será defectuosa.
Dividir sus datos en conjuntos de entrenamiento, validación y prueba puede parecer
sencillo, pero hay algunas formas avanzadas de hacerlo que pueden ser útiles cuando
hay pocos datos disponibles. Revisemos tres recetas clásicas de evaluación: validación
de retención simple, validación de K-fold y validación de K-fold iterada con barajado.
SSUJECIÓN IMPLEMENTAL-SALIDA DE VALIDACIÓN
Separa una fracción de tus datos como tu conjunto de prueba. Entrene con los datos
restantes y evalúe en el conjunto de prueba. Como viste en las secciones anteriores, para
evitar fugas de información, no debes ajustar tu modelo en función del conjunto de
prueba y, por lo tanto, también debes reservar un conjunto de validación.
Esquemáticamente, la validación de exclusión se parece a la figura 4.1. La siguiente
lista muestra una implementación simple.

Totaldatos etiquetados disponibles

Conjunto
Conjunto de de Figura 4.1 Sujeción
entrenamie validació simplefuera de la
nto n división de validación
retenido

Entrenar enestoEvaluar en este

Listado 4.1 Validación de espera

núm_validación_muestras = Mezclar los datos es


10000
normalmenteadecuado.
Define el
np.random.shuffle(datos)
validación_datos = datos[:num_validation_samples] conjunto de validación
datos =
Define el conjunto de entrenamiento.
datos[num_validation_samples:]
datos_entrenamiento = datos[:] Entrena un modelo en los datos
de entrenamiento y lo evalúa
modelo = obtener_modelo() en el
modelo.tren(entrenamiento_datos)
puntuación_validación = validación datos
modelo.evaluar(datos_validación)

# En este punto puedes ajustar tu modelo,


# volver a entrenarlo, evaluarlo, ajustarlo de
Una vez que haya ajustado sus
nuevo...
hiperparámetros, es común
modelo = get_model() entrenar su modelo final desde
model.train(np.concatenate([training_data, cero en todos los datos disponibles
validación_datos]))pun que no sean de prueba.
tuación_prueba = modelo.evaluar(datos_prueba)

Con licencia para


Evaluación del aprendizaje automáticomodelos 99

Este es el protocolo de evaluación más simple y tiene una falla: si hay pocos datos
disponibles, entonces sus conjuntos de validación y prueba pueden contener muy pocas
muestras para ser estadísticamente representativas de los datos disponibles. Esto es fácil
de reconocer: si diferentes rondas aleatorias de barajado de los datos antes de la división
terminan generando medidas muy diferentes del rendimiento del modelo, entonces tiene
este problema. La validación K-fold y la validación K-fold iterada son dos formas de
abordar esto, como se explica a continuación.
K-VALIDACIÓN DEL PLEGADO
Con este enfoque, divide sus datos en K particiones de igual tamaño. Para cada
partición i, entrene un modelo en las particiones K – 1 restantes y evalúelo en la
partición i. Su puntaje final es entonces el promedio de los puntajes K obtenidos.
Este método es útil cuando el rendimiento de su modelo muestra una variación
significativa en función de su división de prueba de tren. Al igual que la validación
de exclusión, este método no lo exime de usar un conjunto de validación distinto
para la calibración del modelo.
Esquemáticamente, la validación cruzada de K-fold se parece a la figura 4.2. El listado
4.2 muestra un simpleimplementación.

Datos divididos en 3 particiones

Validació
Doblar 1 Validación Capacitació Capacitació npuntuaci
n n ón #1

Validació Finalpuntaj
Doblar 2
n e:
puntuació promedio
Validación Validación Capacitació
n #2
n
Doblar 3
Validació
Validación Capacitació Validación
n
n
Figura 4.2 Validación triple puntuació
n #3

Listado 4.2 Validación cruzada de K-fold


k = 4
num_validation_samples = len(datos) // k
np.random.shuffle(datos
) Selecciona la validación-
partición de datos
puntuaciones_validaci
ón = []para plegar en
el rango (k):
validación_datos = datos[num_validation_samples * puntu
fold:num_validation_samples * (fold + 1)] ación
datos_entrenamiento = datos[:num_validation_samples * _vali
fold] +data[num_validation_samples * (fold + 1):] dació
n =
modelo = get_model()
model
model.train(training_data)
o.eva
Con licencia para
luar(datos_validación)puntuaciones_de_validación.
append(puntuación_de_validación)

Utiliza el resto de los datos como


datos de entrenamiento. Tenga
en cuenta que el
El operador + es una
concatenación de listas, no una
suma.
Crea una nueva instancia
del modelo (no entrenado)

Con licencia para


100 CPASADO4fundamentos de maquinaaprendizaje

puntuación_validación = Puntuación de
np.promedio(puntuaciones_validación) validación:
modelo = promedio de las
Entrena el modelo puntuaciones de
obtener_modelo()mo final en todos los
delo.tren(datos)
validación de los k
datos que no son pliegues
puntuación_prueba = de prueba
modelo.evaluar(datos_prueba) disponibles

yoTERADOK-VALIDACIÓN DEL PLEGADO CON SHUFFLING


Este es para situaciones en las que tiene relativamente pocos datos disponibles y
necesita evaluar su modelo con la mayor precisión posible. Descubrí que es
extremadamente útil en las competiciones de Kaggle. Consiste en aplicar la validación
de K-fold varias veces, barajando los datos cada vez antes de dividirlos en K formas. La
puntuación final es el promedio de las puntuaciones obtenidas en cada ejecución de la
validación de K-fold. Tenga en cuenta que termina entrenando y evaluando modelos P ×
K (donde P es la cantidad de iteraciones que usa), lo que puede ser muy costoso.

4.2.2 Cosas a tener en cuenta


Esté atento a lo siguiente cuando elija un protocolo de evaluación:
◾ Representatividad de los datos—Desea que tanto su conjunto de entrenamiento
como su conjunto de prueba sean representativos de los datos disponibles. Por
ejemplo, si está tratando de clasificar imágenes de dígitos y está comenzando con
una matriz de muestras donde las muestras están ordenadas por su clase, tomando
el primer 80 % de la matriz como su conjunto de entrenamiento y el 20 %
restante ya que su conjunto de prueba dará como resultado que su conjunto de
entrenamiento contenga solo las clases 0–7, mientras que su conjunto de prueba
contenga solo las clases 8–9. Esto parece un error ridículo, pero es
sorprendentemente común. Por esta razón, por lo general, debe mezclar
aleatoriamente sus datos antes de dividirlos en conjuntos de entrenamiento y
prueba.
◾ la flecha del tiempo—Si está tratando de predecir el futuro dado el pasado (por
ejemplo, el clima de mañana, los movimientos de las acciones, etc.), no debe
barajar aleatoriamente sus datos antes de dividirlos, porque hacerlo creará un
espacio temporal. fuga: su modelo se entrenará efectivamente con datos del
futuro. En tales situaciones, siempre debe asegurarse de que todos los datos en su
conjunto de prueba sean posteriores a los datos en el conjunto de entrenamiento.
◾ Redundancia en tus datos—Si algunos puntos de datos en sus datos aparecen dos
veces (bastante común con los datos del mundo real), entonces mezclar los datos y
dividirlos en un conjunto de entrenamiento y un conjunto de validación resultará en
una redundancia entre los conjuntos de entrenamiento y validación. De hecho, estarás
probando parte de tus datos de entrenamiento, ¡lo cual es lo peor que puedes hacer!
Asegúrese de que su conjunto de entrenamiento y su conjunto de validación sean
disjuntos.

Con licencia para


Preprocesamiento de datos, ingeniería de características y característicasaprendizaje101

4.3 Preprocesamiento de datos, ingeniería de


características,y características de
aprendizaje
Además de la evaluación del modelo, una pregunta importante que debemos abordar
antes de profundizar en el desarrollo del modelo es la siguiente: ¿cómo se preparan
los datos de entrada y los objetivos antes de introducirlos en una red neuronal?
Muchas técnicas de preprocesamiento de datos e ingeniería de características son
específicas del dominio (por ejemplo, específicas de datos de texto o datos de
imágenes); los cubriremos en los siguientes capítulos a medida que los encontremos
en ejemplos prácticos. Por ahora, revisaremos los conceptos básicos que son
comunes a todos los dominios de datos.

4.3.1 Preprocesamiento de datos para redes neuronales


El preprocesamiento de datos tiene como objetivo hacer que los datos sin procesar
disponibles sean más accesibles para las redes neuronales. Esto incluye
vectorización, normalización, manejo de valores faltantes y extracción de
características.
VECTORIZACIÓN
Todas las entradas y objetivos en una red neuronal deben ser tensores de datos de punto
flotante (o, en casos específicos, tensores de números enteros). Independientemente de
los datos que necesite procesar (sonido, imágenes, texto), primero debe convertirlos en
tensores, un paso llamado vectorización de datos. Por ejemplo, en los dos ejemplos
anteriores de clasificación de texto, partimos del texto representado como listas de
números enteros (que representan secuencias de palabras) y usamos una codificación
one-hot para convertirlos en un tensor de datos float32. En los ejemplos de clasificación
de dígitos y predicción de precios de viviendas, los datos ya venían en forma de vector,
por lo que pudo omitir este paso.
VNORMALIZACIÓN DE ALORES
En el ejemplo de clasificación de dígitos, comenzó con datos de imagen codificados
como números enteros en el rango de 0 a 255, codificando valores en escala de grises.
Antes de introducir estos datos en su redtrabajo, tenías que convertirlo a float32 y dividirlo
por 255 para terminar con valores de punto flotante en el rango de 0–1. De manera similar,
al predecir los precios de la vivienda, comenzó con características que tomaron una variedad
de rangos: algunas características tenían valores pequeños de punto flotante, otras tenían
valores enteros bastante grandes. Antes de introducir estos datos en su red, tenía que
normalizar cada función de forma independiente para que tuviera una desviación estándar de
1 y una media de 0.
En general, no es seguro introducir en una red neuronal datos que toman valores
relativamente grandes (por ejemplo, números enteros de varios dígitos, que son mucho
más grandes que los valores iniciales tomados por los pesos de una red) o datos que son
heterogéneos. (por ejemplo, datos en los que una característica está en el rango de 0 a 1
y otra en el rango de 100 a 200). Si lo hace, puede desencadenar grandes actualizaciones
de gradiente que evitarán que la red converja. Para facilitar el aprendizaje de su red, sus
datos deben tener las siguientes características:

Con licencia para


◾ Toma valores pequeños—Normalmente, la mayoría de los valores deben estar en el rango de 0
a 1.
◾ Ser homogéneo—Es decir, todas las características deben tomar valores en
aproximadamente el mismo rango.

Con licencia para


102 CPASADO4fundamentos de maquinaaprendizaje

Además, la siguiente práctica de normalización más estricta es común y puede


ayudar, aunque no siempre es necesaria (por ejemplo, no hizo esto en el ejemplo de
clasificación de dígitos):
◾ Normalice cada característica de forma independiente para tener una media de 0.
◾ Normalice cada función de forma independiente para tener una

desviación estándar de 1. Esto es fácil de hacer con matrices Numpy:


x -= x.media(eje=0)
Suponiendo que x es una
x /= x.std(eje=0)
matriz de datos 2D de forma
(muestras, características)
HVALORES FALTANTES DE
ANDLING
Es posible que a veces le falten valores a sus datos. Por ejemplo, en el ejemplo del
precio de la vivienda, la primera característica (la columna del índice 0 en los datos) fue
la tasa de criminalidad per cápita. ¿Qué pasaría si esta función no estuviera disponible
para todas las muestras? Entonces tendría valores faltantes en los datos de
entrenamiento o prueba.
En general, con las redes neuronales, es seguro ingresar valores faltantes como 0,
con la condición de que 0 no sea ya un valor significativo. La red aprenderá de la
exposición a los datos que el valor 0 significa que faltan datos y comenzará a ignorar el
valor.
Tenga en cuenta que si espera valores faltantes en los datos de prueba, pero la
red se entrenó con datos sin valores faltantes, ¡la red no habrá aprendido a ignorar
los valores faltantes! En esta situación, debe generar muestras de entrenamiento
artificialmente con entradas faltantes: copie algunas muestras de entrenamiento
varias veces y elimine algunas de las características que espera que puedan faltar en
los datos de prueba.

4.3.2 Ingeniería de características


Ingeniería de característicases el proceso de utilizar su propio conocimiento sobre los
datos y sobre el algoritmo de aprendizaje automático disponible (en este caso, una red
neuronal) para hacer que el algoritmo funcione mejor aplicando
transformación codificada (no aprendida)
cambios a los datos antes de que u e a
entren en el modelo. En muchos n d
casos, no es razonable esperar que e
un modelo de aprendizaje r
automático pueda aprender de datos e g
completamente arbitrarios. Los l e
datos deben presentarse al modelo o n
de una manera que facilite el trabajo j e
del modelo. r
Veamos un ejemplo intuitivo. y a
Suponga que está tratando de r
desarrollar un modelo que puede p
tomar como entrada una imagen de u l
Con licencia para
Datos sin procesar:cuadrícula de píxeles

Mejores características: coordenadas de las manecillas del reloj


{x1: 0,7, {x1:
y1: 0.7} 0.0,
{x2: 0.5, y2:
Características aún mejores: ángulos de las manecillas del reloj y2: 0.0} 1.0}
{x2: -
0.38,
2:
theta1: 45 0,32
theta2: 0 }

theta1
: 90
theta2
: 140
hora del día (ver figura 4.3). Figura 4.3 Ingeniería de funciones para leer la hora
enun reloj

Con licencia para


Preprocesamiento de datos, ingeniería de características y característicasaprendizaje103

Si elige usar los píxeles sin procesar de la imagen como datos de entrada, entonces
tiene un problema difícil de aprendizaje automático en sus manos. Necesitará una
red neuronal convolucional para resolverlo y tendrá que gastar bastantes recursos
computacionales para entrenar la red.
Pero si ya comprende el problema en un nivel alto (entiende cómo los humanos
leen la hora en la esfera de un reloj), entonces puede encontrar características de
entrada mucho mejores para un algoritmo de aprendizaje automático: por ejemplo,
es fácil de escribir un script Python de cinco líneas para seguir los píxeles negros de
las manecillas del reloj y generar las coordenadas (x, y) de la punta de cada
manecilla. Luego, un simple algoritmo de aprendizaje automático puede aprender a
asociar estas coordenadas con la hora adecuada del día.
Puede ir aún más lejos: realice un cambio de coordenadas y exprese las
coordenadas (x, y) como coordenadas polares con respecto al centro de la imagen.
Su entrada se convertirá en el ángulo theta de cada manecilla del reloj. En este
punto, sus funciones hacen que el problema sea tan fácil que no se requiere
aprendizaje automático; una simple operación de redondeo y una búsqueda en el
diccionario son suficientes para recuperar la hora aproximada del día.
Esa es la esencia de la ingeniería de características: simplificar un problema
expresándolo de una manera más simple. Por lo general, requiere comprender el
problema en profundidad.
Antes del aprendizaje profundo, la ingeniería de características solía ser
fundamental, porque los algoritmos superficiales clásicos no tenían espacios de
hipótesis lo suficientemente ricos como para aprender características útiles por sí
mismos. La forma en que presentó los datos al algoritmo fue esencial para su éxito. Por
ejemplo, antes de que las redes neuronales convolucionales tuvieran éxito en el
problema de clasificación de dígitos del MNIST, las soluciones se basaban típicamente
en características codificadas como el número de bucles en una imagen de dígito, la
altura de cada dígito en una imagen, un histograma de píxeles valores, y así
sucesivamente.
Afortunadamente, el aprendizaje profundo moderno elimina la necesidad de la
mayor parte de la ingeniería de funciones, porque las redes neuronales son capaces
de extraer automáticamente funciones útiles de los datos sin procesar. ¿Significa
esto que no tiene que preocuparse por la ingeniería de características siempre que
use redes neuronales profundas? No, por dos razones:
◾ Las buenas características aún le permiten resolver problemas de manera más
elegante utilizando menos recursos. Por ejemplo, sería ridículo resolver el
problema de leer la esfera de un reloj utilizando una red neuronal convolucional.
◾ Las buenas funciones le permiten resolver un problema con muchos menos
datos. La capacidad de los modelos de aprendizaje profundo para aprender
características por sí mismos depende de tener muchos datos de
entrenamiento disponibles; si solo tiene unas pocas muestras, entonces el
valor de la información en sus características se vuelve crítico.

Con licencia para


104 CPASADO4fundamentos de maquinaaprendizaje

4.4 Overfitting y underfitting


En los tres ejemplos del capítulo anterior (predicción de reseñas de películas,
clasificación de temas y regresión del precio de la vivienda), el rendimiento del modelo
en los datos de validación retenidos siempre alcanzó su punto máximo después de
algunas épocas y luego comenzó a degradarse: el modelo rápidamente comenzó a
sobreajustarse a los datos de entrenamiento. El sobreajuste ocurre en todos los
problemas de aprendizaje automático. Aprender a lidiar con el sobreajuste es esencial
para dominar el aprendizaje automático.
El problema fundamental en el aprendizaje automático es la tensión entre la
optimización y la generalización. La optimización se refiere al proceso de ajustar un
modelo para obtener el mejor rendimiento posible en los datos de entrenamiento (el
aprendizaje en el aprendizaje automático), mientras que la generalización se refiere
a qué tan bien se desempeña el modelo entrenado en datos que nunca antes había
visto. El objetivo del juego es obtener una buena generalización, por supuesto, pero
no controlas la generalización; solo puede ajustar el modelo en función de sus datos
de entrenamiento.
Al comienzo del entrenamiento, la optimización y la generalización están
correlacionadas: cuanto menor es la pérdida de datos de entrenamiento, menor es la
pérdida de datos de prueba. Mientras esto sucede, se dice que su modelo no es apto:
todavía hay progreso por hacer; la red aún no ha modelado todos los patrones
relevantes en los datos de entrenamiento. Pero después de un cierto número de
iteraciones en los datos de entrenamiento, la generalización deja de mejorar y las
métricas de validación se estancan y luego comienzan a degradarse: el modelo
comienza a sobreajustarse. Es decir, está comenzando a aprender patrones que son
específicos de los datos de entrenamiento pero que son engañosos o irrelevantes
cuando se trata de datos nuevos.
Para evitar que un modelo aprenda patrones engañosos o irrelevantes que se
encuentran en los datos de entrenamiento, la mejor solución es obtener más datos de
entrenamiento. Un modelo entrenado con más datos, naturalmente, generalizará
mejor. Cuando eso no es posible, la siguiente mejor solución es modular la cantidad
de información que su modelo puede almacenar o agregar restricciones sobre qué
información puede almacenar. Si una red solo puede darse el lujo de memorizar una
pequeña cantidad de patrones, el proceso de optimización la obligará a centrarse en
los patrones más destacados, que tienen más posibilidades de generalizarse bien.
El procesamiento de la lucha contra el sobreajuste de esta manera se denomina
regularización. Revisemos algunas de las técnicas de regularización más comunes y
apliquémoslas en la práctica para mejorar el modelo de clasificación de películas de la
sección 3.4.

4.4.1 Reducir el tamaño de la red


La forma más sencilla de evitar el sobreajuste es reducir el tamaño del modelo: la
cantidad de parámetros que se pueden aprender en el modelo (que está determinada
por la cantidad de capas y la cantidad de unidades por capa). En el aprendizaje
profundo, la cantidad de parámetros que se pueden aprender en un modelo a
menudo se denomina capacidad del modelo. Intuitivamente, un modelo con más
Con licencia para
parámetros tiene más capacidad de memorización y, por lo tanto, puede aprender
fácilmente un mapeo perfecto similar a un diccionario entre las muestras de
entrenamiento y sus objetivos, un mapeo sin ningún poder de generalización. Por
ejemplo, un modelo con 500.000 parámetros binarios se podría hacer fácilmente
para aprender la clase de cada dígito en el conjunto de entrenamiento MNIST:

Con licencia para


sobreajustey desajustado 105

solo necesitaríamos 10 parámetros binarios para cada uno de los 50.000 dígitos.
Pero tal modelo sería inútil para clasificar nuevas muestras de dígitos. Siempre
tenga esto en cuenta: los modelos de aprendizaje profundo tienden a adaptarse bien
a los datos de entrenamiento, pero el verdadero desafío es la generalización, no la
adaptación.
Por otro lado, si la red tiene recursos de memorización limitados, no podrá aprender
este mapeo tan fácilmente; por lo tanto, para minimizar su pérdida, deberá recurrir al
aprendizaje de representaciones comprimidas que tengan poder predictivo sobre los
objetivos, precisamente el tipo de representaciones que nos interesan. Al mismo tiempo,
tenga en cuenta que debe utilizar modelos que tengan suficientes parámetros que no se
ajusten mal: su modelo no debería estar hambriento de recursos de memorización. Hay
que encontrar un compromiso entre demasiada capacidad y poca capacidad.
Desafortunadamente, no existe una fórmula mágica para determinar el número
correcto de capas o el tamaño correcto para cada capa. Debe evaluar una serie de
arquitecturas diferentes (en su conjunto de validación, no en su conjunto de prueba,
por supuesto) para encontrar el tamaño de modelo correcto para sus datos. El flujo
de trabajo general para encontrar un tamaño de modelo apropiado es comenzar con
relativamente pocas capas y parámetros, y aumentar el tamaño de las capas o
agregar nuevas capas hasta que vea rendimientos decrecientes con respecto a la
pérdida de validación.
Probemos esto en la red de clasificación de reseñas de películas. La red original
se muestra a continuación.

Listado 4.3 Modelo original

desde keras importar


modelos desde keras
importar capas
modelo = modelos. Secuencial()
modelo.add(capas.Dense(16, activación='relu', input_shape=(10000,)))
modelo.add(capas.Dense(16, activación='relu'))
modelo.add(capas.Dense(1 , activación='sigmoide'))

Ahora intentemos reemplazarlo con esta red más pequeña.

Listado 4.4 Versión del modelo con menor capacidad

modelo = modelos. Secuencial()


modelo.add(capas.Dense(4, activación='relu', input_shape=(10000,)))
modelo.add(capas.Dense(4, activación='relu'))
modelo.add(capas.Dense(1 , activación='sigmoide'))

La Figura 4.4 muestra una comparación de las pérdidas de validación de la red


original y la red más pequeña. Los puntos son los valores de pérdida de validación
de la red más pequeña y las cruces son la red inicial (recuerde, una pérdida de
validación más baja indica un mejor modelo).

Con licencia para


106 CPASADO4fundamentos de maquinaaprendizaje

Figura 4.4 Efecto de la


capacidad del modelo en la
pérdida de validación:
probando un modelo más
pequeño

Como puede ver, la red más pequeña comienza a adaptarse más tarde que la red de
referencia (después de seis épocas en lugar de cuatro), y su rendimiento se degrada
más lentamente una vez que comienza a adaptarse.
Ahora, para divertirnos, agreguemos a este punto de referencia una red que tiene
mucha más capacidad, mucho más de lo que justifica el problema.

Listado 4.5 Versión del modelo con mayor capacidad

modelo = modelos. Secuencial()


modelo.add(capas.Dense(512, activación='relu', input_shape=(10000,)))
modelo.add(capas.Dense(512, activación='relu'))
modelo.add(capas.Dense(1 , activación='sigmoide'))

La Figura 4.5 muestra cómo se comporta la red más grande en comparación con la
red de referencia. Los puntos son los valores de pérdida de validación de la red más
grande y las cruces son la red inicial.

Figura 4.5 Efecto de la


capacidad del modelo en la
pérdida de
validación:probando un
modelo mas grande

Con licencia para


sobreajustey desajustado 107

La red más grande comienza a sobreajustarse casi de inmediato, después de solo una
época, y lo hace de manera mucho más severa. Su pérdida de validación también es más
ruidosa.
Mientras tanto, la figura 4.6 muestra las pérdidas de entrenamiento para las dos
redes. Como puede ver, la red más grande obtiene su pérdida de entrenamiento cercana
a cero muy rápidamente. Cuanta más capacidad tiene la red, más rápido puede modelar
los datos de entrenamiento (lo que da como resultado una baja pérdida de
entrenamiento), pero más susceptible es al sobreajuste (lo que da como resultado una
gran diferencia entre la pérdida de entrenamiento y la de validación).

Figura 4.6 Efecto del


modelocapacidad sobre la
pérdida de
entrenamiento: probando
un modelo más grande

4.4.2 Adición de regularización de peso


Puede que estés familiarizado con el principio de la navaja de Occam: dadas dos
explicaciones para algo, la explicación más probable que sea correcta es la más simple, la
que hace menos suposiciones. Esta idea también se aplica a los modelos aprendidos por
redes neuronales: dados algunos datos de entrenamiento y una arquitectura de red, múltiples
conjuntos de valores de peso (múltiples modelos) podrían explicar los datos. Los modelos
más simples tienen menos probabilidades de sobreajustarse que los complejos.
Un modelo simple en este contexto es un modelo donde la distribución de los
valores de los parámetros tiene menos entropía (o un modelo con menos parámetros,
como viste en la sección anterior). Por lo tanto, una forma común de mitigar el
sobreajuste es imponer restricciones a la complejidad de una red al obligar a sus pesos a
tomar solo valores pequeños, lo que hace que la distribución de los valores de peso sea
más regular. Esto se denomina regularización de peso y se realiza agregando a la
función de pérdida de la red un costo asociado con tener pesos grandes. Este costo viene
en dos sabores:
◾ L1regularización—El coste añadido es proporcional al valor absoluto de los
coeficientes de ponderación (elL1normade los pesos).
◾ L2regularización—El costo agregado es proporcional al cuadrado del valor de los
coeficientes de peso (el L2normade los pesos).L2la regularización también se
denomina disminución del peso en el contexto de las redes neuronales. No deje
Con licencia para
que el nombre diferente lo confunda: la disminución del peso es
matemáticamente lo mismo que la regularización L2.

Con licencia para


108 CPASADO4fundamentos de maquinaaprendizaje

En Keras, la regularización de peso se agrega pasando instancias de regularizador de


peso a capas como argumentos de palabras clave. Agreguemos la regularización del
peso L2 a la red de clasificación de reseñas de películas.

Listado 4.6 Agregando regularización de peso L2 al modelo

de regularizadores de importación de keras


modelo = modelos. Secuencial()
model.add(layers.Dense(16, kernel_regularizer=regularizers.l2(0.001),
activación='relu', input_shape=(10000,)))
model.add(layers.Dense(16,
kernel_regularizer=regularizers.l2(0.001),
activación='relu'))
modelo.add(capas.Dense(1,
activación='sigmoide'))

l2(0.001)significa que cada coeficiente en la matriz de peso de la capa se sumará0.001


* peso_coeficiente_valora la pérdida total de la red. Tenga en cuenta que debido a
que esta penalización solo se agrega en el momento del entrenamiento, la pérdida de esta red
será mucho mayor en el momento del entrenamiento que en el momento de la prueba.
La figura 4.7 muestra el impacto de la sanción de regularización de L2. Como
puede ver, el modelo con regularización L2 (puntos) se ha vuelto mucho más
resistente al sobreajuste que el modelo de referencia (cruces), a pesar de que ambos
modelos tienen el mismo número de parámetros.

Figura 4.7 Efecto de la


regularización del peso L2 en la
pérdida de validación

Como alternativa a la regularización L2, puedes utilizar uno de los siguientes


regularizadores de peso de Keras.

Listado 4.7 Diferentes regularizadores de peso disponibles en Keras

de regularizadores de
importación de keras
L1regularización L1 y simultáneos
regularizadores.l1(0.001)
regularizadores.l1_l2(l1=0.001, l2=0.001) regularización L2

Con licencia para


sobreajustey desajustado 109

4.4.3 agregandoAbandonar
Abandonares una de las técnicas de regularización más efectivas y más utilizadas
para redes neuronales, desarrollada por Geoff Hinton y sus estudiantes en la
Universidad de Toronto. El abandono, aplicado a una capa, consiste en eliminar
aleatoriamente (establecer en cero) una serie de características de salida de la capa
durante el entrenamiento. Digamos que una capa dada normalmente devolvería un
vector [0.2, 0.5, 1.3, 0.8, 1.1] para una muestra de entrada dada durante el
entrenamiento. Después de aplicar el abandono, este vector tendrá algunas entradas
cero distribuidas al azar: por ejemplo, [0, 0.5, 1.3, 0, 1.1]. La tasa de abandono es la
fracción de las funciones que se ponen a cero; generalmente se establece entre 0.2 y
0.5. En el momento de la prueba, no se abandona ninguna unidad; en cambio, los
valores de salida de la capa se reducen por un factor igual a la tasa de abandono,
Considere una matriz Numpy que contiene la salida de una capa, layer_output,
deforma (batch_size, características). En el momento del entrenamiento, ponemos a cero
aleatoriamente una fracción de los valores de la matriz:
capa_salida *= np.random.randint(0, alto=2, tamaño=capa_salida.forma)
En el momento del
entrenamiento,
abandona el 50% de las
unidades en la salida

En el momento de la prueba, reducimos la salida según la tasa de abandono. Aquí,


escalamos en 0,5 (porque anteriormente eliminamos la mitad de las unidades):
capa_salida *= 0.5 en tiempo de prueba
Tenga en cuenta que este proceso se puede implementar realizando ambas
operaciones en el momento del entrenamiento y dejando el resultado sin cambios en
el momento de la prueba, que es a menudo la forma en que se implementa en la
práctica (consulte la figura 4.8):
capa_salida *= np.random.randint(0, alto=2, tamaño=capa_salida.forma)
capa_salida /= 0.5
Tenga en cuenta que estamos En tiempo de entrenamiento
ampliando en lugar de reducir en
este caso.

0.3 0.2 1.5 0.0 0.0 0.2 1.5 0.0


50%
0.6 0.1 0.0 0.3 Abandonar 0.6 0.1 0.0 0.3 Figura 4.8 Abandono aplicado a un
*2 matriz de activación en el momento
0.2 1.9 0.3 1.2 0.0 1.9 0.3 0.0 del entrenamiento,con
reescaladosucediendo durante el
0.7 0.5 1.0 0.0 0.7 0.0 0.0 0.0
entrenamiento. En el momento de
la prueba, la matriz de activación
no cambia.

Esta técnica puede parecer extraña y arbitraria. ¿Por qué ayudaría esto a reducir el
sobreajuste? Hinton dice que se inspiró, entre otras cosas, en un mecanismo de
Con licencia para
prevención del fraude utilizado por los bancos. En sus propias palabras, “Fui a mi
banco. Los cajeros seguían cambiando y le pregunté a uno de ellos por qué. Dijo
que no sabía, pero que se movían mucho.

Con licencia para


110 CPASADO4fundamentos de maquinaaprendizaje

Supuse que debía ser porque requeriría la cooperación entre los empleados para
defraudar con éxito al banco. Esto me hizo darme cuenta de que la eliminación
aleatoria de un subconjunto diferente de neuronas en cada ejemplo evitaría
conspiraciones y, por lo tanto, reduciría el ajuste excesivo”. significativos (a lo que
Hinton se refiere como conspiraciones), que la red comenzará a memorizar si no
hay ruido presente.
En Keras, puede introducir el abandono en una red a través de la capa de abandono,
que se aplica a la salida de la capa justo antes:
modelo.add(capas.Abandono(0.5))

Agreguemos dos capas de abandono en la red IMDB para ver qué tan bien funcionan para
reducir el sobreajuste.

Listado 4.8 Agregando dropout a la IMDBla red

modelo = modelos. Secuencial()


modelo.add(capas.Dense(16, activación='relu', input_shape=(10000,)))
modelo.add(capas.Dropout(0.5))
model.add(capas.Dense(16, activación='relu'))
modelo.add(capas.Dropout(0.5))
modelo.add(capas.Dense(1,
activación='sigmoide'))

La figura 4.9 muestra un gráfico de los resultados. Nuevamente, esta es una clara mejora
con respecto a la red de referencia.

Figura 4.9 Efecto de la


deserciónen la pérdida de
validación

En resumen, estas son las formas más comunes de evitar el sobreajuste en las redes neuronales:
◾ Obtén más datos de entrenamiento.
◾ Reducir la capacidad de la red.
◾ Añadir regularización de peso.
◾ Añadir abandono.

1 Ver el hilo de Reddit “AMA: Somos el equipo de Google Brain. Nos encantaría responder a sus preguntas sobre la máquina
aprendizaje,"
http://mng.bz/XrsS.

Con licencia para


El flujo de trabajo universal de la máquinaaprendizaje 111

4.5 El flujo de trabajo universal del aprendizaje automático


En esta sección, presentaremos un modelo universal que puede usar para atacar y
resolver cualquier problema de aprendizaje automático. El proyecto une los
conceptos que ha aprendido en este capítulo: definición de problemas, evaluación,
ingeniería de funciones y lucha contra el sobreajuste.

4.5.1 Definición del problema y ensamblaje de un conjunto de datos


En primer lugar, debe definir el problema en cuestión:
◾ ¿Cuáles serán sus datos de entrada? ¿Qué estás tratando de predecir? Solo puede
aprender a predecir algo si tiene datos de entrenamiento disponibles: por ejemplo,
solo puede aprender a clasificar el sentimiento de las reseñas de películas si tiene
disponibles reseñas de películas y anotaciones de sentimientos. Como tal, la
disponibilidad de datos suele ser el factor limitante en esta etapa (a menos que
tenga los medios para pagarle a las personas para que recolecten datos por usted).
◾ ¿A qué tipo de problema te enfrentas? ¿Es una clasificación binaria?
¿Clasificación multiclase? ¿Regresión escalar? ¿Regresión vectorial?
¿Clasificación multiclase, multietiqueta? ¿Algo más, como agrupamiento,
generación o aprendizaje por refuerzo? La identificación del tipo de problema
guiará la elección de la arquitectura del modelo, la función de pérdida, etc.
No puede pasar a la siguiente etapa hasta que sepa cuáles son sus entradas y salidas, y
qué datos usará. Sea consciente de las hipótesis que haga en esta etapa:
◾ Tiene la hipótesis de que sus salidas se pueden predecir dadas sus entradas.
◾ Tiene la hipótesis de que sus datos disponibles son lo suficientemente
informativos para aprender la relación entre entradas y salidas.
Hasta que tenga un modelo de trabajo, estas son meras hipótesis, esperando ser
validadas o invalidadas. No todos los problemas se pueden resolver; solo porque ha
ensamblado ejemplos de entradas X y objetivosY no significa que X contiene suficiente
información para predecir
Y. Por ejemplo, si intenta predecir los movimientos de una acción en el mercado de valores dado
su historial de precios reciente, es poco probable que tenga éxito, porque el historial de precios no
contiene mucha información predictiva.
Una clase de problemas irresolubles que debe tener en cuenta son los problemas no
estacionarios. Suponga que está intentando crear un motor de recomendaciones para
ropa, lo está entrenando con un mes de datos (agosto) y desea comenzar a generar
recomendaciones en el invierno. Un gran problema es que los tipos de ropa que la gente
compra cambian de una temporada a otra: la compra de ropa es un fenómeno no
estacionario en la escala de unos pocos meses. Lo que estás tratando de modelar cambia
con el tiempo. En este caso, el movimiento correcto es volver a entrenar constantemente
su modelo con datos del pasado reciente o recopilar datos en una escala de tiempo en la
que el problema es estacionario. Para un problema cíclico como la compra de ropa, los
datos de algunos años serán suficientes para capturar la variación estacional, ¡pero
recuerde que la época del año es una entrada de su modelo!

Con licencia para


112 CPASADO4fundamentos de maquinaaprendizaje

Tenga en cuenta que el aprendizaje automático solo se puede usar para


memorizar patrones que están presentes en sus datos de entrenamiento. Solo puedes
reconocer lo que has visto antes. Usar el aprendizaje automático entrenado en datos
pasados para predecir el futuro es suponer que el futuro se comportará como el
pasado. Eso a menudo no es el caso.

4.5.2 Elegir una medida del éxito


Para controlar algo, necesitas ser capaz de observarlo. Para lograr el éxito, debe
definir lo que quiere decir con éxito: ¿precisión? ¿Precisión y memoria? tasa de
retención de clientes? Su métrica de éxito guiará la elección de una función de
pérdida: lo que optimizará su modelo. Debe alinearse directamente con sus
objetivos de nivel superior, como el éxito de su negocio.
Para problemas de clasificación balanceada, donde cada clase es igualmente
probable, la precisión yárea bajo la curva característica operativa del receptor(ROC
AUC) son métricas comunes. Para problemas de clase desequilibrada, puede usar precisión y
recuperación. Para problemas de clasificación o clasificación multietiqueta, puede usar la
precisión media promedio. Y no es raro tener que definir su propia métrica personalizada
para medir el éxito. Para tener una idea de la diversidad de las métricas de éxito del
aprendizaje automático y cómo se relacionan con diferentes dominios de problemas, es útil
explorar las competencias de ciencia de datos en Kaggle (https://kaggle.com); ellos
escaparate a amplio rango de problemas y evaluación métrica.

4.5.3 Decidir sobre un protocolo de evaluación


Una vez que sepa cuál es su objetivo, debe establecer cómo medirá su progreso actual.
Hemos revisado previamente tres protocolos de evaluación comunes:
◾ Mantenimiento de un conjunto de validación de reserva—El camino a seguir cuando
tienes muchos datos
◾ Haciendo validación cruzada K-fold—La opción correcta cuando tiene muy
pocas muestras para que la validación de retención sea confiable
◾ Haciendo una validación iterada de K-fold—Para realizar evaluaciones de modelos
de alta precisión cuando hay pocos datos disponibles
Sólo elige uno de estos. En la mayoría de los casos, el primero funcionará lo suficientemente bien.

4.5.4 Preparando tus datos


Una vez que sepa en qué está entrenando, para qué está optimizando y cómo evaluar su
enfoque, estará casi listo para comenzar a entrenar modelos. Pero primero, debe
formatear sus datos de una manera que pueda incorporarse a un modelo de aprendizaje
automático; aquí, supondremos una red neuronal profunda:
◾ Como vio anteriormente, sus datos deben formatearse como tensores.
◾ Los valores que toman estos tensores normalmente deben escalarse a valores
pequeños: por ejemplo, en el rango [-1, 1] o [0, 1].

Con licencia para


El flujo de trabajo universal de la máquinaaprendizaje 113

◾ Si diferentes características toman valores en diferentes rangos (datos


heterogéneos), entonces los datos deben normalizarse.
◾ Es posible que desee hacer algo de ingeniería de funciones, especialmente para

problemas de datos pequeños. Una vez que sus tensores de datos de entrada y de destino
estén listos, puede comenzar a entrenar modelos.

4.5.5 Desarrollandoun modelo que funciona mejor que una línea de base
Su objetivo en esta etapa es lograr poder estadístico: es decir, desarrollar un modelo pequeño
que sea capaz de superar una línea de base tonta. En el ejemplo de clasificación de dígitos
del MNIST, se puede decir que cualquier cosa que logre una precisión superior a 0,1 tiene
poder estadístico; en el ejemplo de IMDB, es cualquier cosa con una precisión superior a
0,5.
Tenga en cuenta que no siempre es posible lograr el poder estadístico. Si no puede
superar una línea de base aleatoria después de probar varias arquitecturas razonables, es
posible que la respuesta a la pregunta que está haciendo no esté presente en los datos de
entrada. Recuerda que haces dos hipótesis:
◾ Tiene la hipótesis de que sus salidas se pueden predecir dadas sus entradas.
◾ Plantea la hipótesis de que los datos disponibles son suficientemente
informativos para aprender la relación entre entradas y salidas.
Bien puede ser que estas hipótesis sean falsas, en cuyo caso deberás volver a la
mesa de dibujo.
Suponiendo que las cosas van bien, debe tomar tres decisiones clave para
construir su primer modelo de trabajo:
◾ Activación de última capa—Esto establece restricciones útiles en la salida de la
red. por ejemplo, elIMDBejemplo de clasificación utilizado sigmoideoen la
última capa; el ejemplo de regresión no usó ninguna activación de última capa; y
así.
◾ Función de pérdida—Esto debería coincidir con el tipo de problema que está
tratando de resolver. por ejemplo, el IMDBejemplo
usadoentropía_cruzada_binaria, el ejemplo de regresión utilizado mse, y
así.
◾ Configuración de optimización—¿Qué optimizador usarás? ¿Cuál será su tasa de
aprendizaje? En la mayoría de los casos, es seguro ir con rmspropy su tasa de
aprendizaje predeterminada.
Con respecto a la elección de una función de pérdida, tenga en cuenta que no
siempre es posible optimizar directamente la métrica que mide el éxito de un
problema. A veces, no existe una manera fácil de convertir una métrica en una
función de pérdida; Después de todo, las funciones de pérdida deben ser
computables dado solo un mini lote de datos (idealmente, una función de pérdida
debe ser computable para un solo punto de datos) y debe ser diferenciable (de lo
contrario, no puede usar retropropagación para entrenar su red). Por ejemplo, la
métrica de clasificación ampliamente utilizada ROC AUC no se puede optimizar
directamente. Por lo tanto, en las tareas de clasificación, es común optimizar para
Con licencia para
una métrica proxy de ROC AUC, como la entropía cruzada. En general, puede
esperar que cuanto menor sea la entropía cruzada, mayor será el ROC AUC.
La Tabla 4.1 puede ayudarlo a elegir una activación de última capa y una función de
pérdida para algunos tipos de problemas comunes.

Con licencia para


114 CPASADO4fundamentos de maquinaaprendizaje

Tabla 4.1 Elegir la función de activación y pérdida de última capa adecuada para su modelo

tipo de problema Activación de última Función de pérdida


capa
clasificación binaria sigmoid entropía_cruzada_binaria

Clasificación multiclase, etiqueta e mse

única Clasificación multiclase, softmax mse o binary_crossentropy

etiqueta múltipleRegresión a sigmoid

valores arbitrarios e

Ninguno
Regresión a valores entre 0 y 1
sigmoideo

4.5.6 Ampliación: desarrollo de un modelo que sobreajuste


Una vez que haya obtenido un modelo que tenga poder estadístico, la pregunta es: ¿su
modelo es lo suficientemente poderoso? ¿Tiene suficientes capas y parámetros para
modelar adecuadamente el problema en cuestión? Por ejemplo, una red con una sola
capa oculta con dos unidades tendría poder estadístico en MNIST pero no sería
suficiente para resolver bien el problema. Recuerde que la tensión universal en el
aprendizaje automático es entre optimización y generalización; el modelo ideal es aquel
que se encuentra justo en el límite entre el ajuste insuficiente y el ajuste excesivo; entre
la subcapacidad y la sobrecapacidad. Para averiguar dónde se encuentra este límite,
primero debe cruzarlo.
Para calcular el tamaño del modelo que necesitará, debe desarrollar un modelo que se ajuste
demasiado.
Esto es bastante fácil:
1Añadir capas.
2Haz las capas más grandes.

3Entrena para más épocas.

Supervise siempre la pérdida de entrenamiento y la pérdida de validación, así como los


valores de entrenamiento y validación para cualquier métrica que le interese. Cuando
vea que el rendimiento del modelo en los datos de validación comienza a degradarse,
habrá logrado el sobreajuste.
La siguiente etapa es comenzar a regularizar y afinar el modelo, para acercarse
lo más posible al modelo ideal que no se ajusta ni se ajusta demasiado.

4.5.7 Regularización de su modelo y ajuste de sus hiperparámetros


Este paso tomará la mayor parte del tiempo: modificará repetidamente su modelo, lo
entrenará, evaluará sus datos de validación (no los datos de prueba, en este punto),
lo modificará nuevamente y repetirá, hasta que el modelo sea tan bueno como se
puede conseguir. Estas son algunas cosas que deberías probar:
◾ Añadir abandono.
◾ Pruebe diferentes arquitecturas: agregue o elimine capas.
◾ AgregarL1y/oL2regularización

Con licencia para


El flujo de trabajo universal de la máquinaaprendizaje 115

◾ Pruebe diferentes hiperparámetros (como el número de unidades por capa o la


tasa de aprendizaje del optimizador) para encontrar la configuración óptima.
◾ Opcionalmente, repita la ingeniería de funciones: agregue nuevas funciones o
elimine funciones que no parezcan ser informativas.
Tenga en cuenta lo siguiente: cada vez que utiliza los comentarios de su proceso de
validación para ajustar su modelo, filtra información sobre el proceso de validación en
el modelo. Repetido solo unas pocas veces, esto es inocuo; pero si se hace de manera
sistemática durante muchas iteraciones, eventualmente hará que su modelo se ajuste
demasiado al proceso de validación (aunque ningún modelo se entrene directamente en
ninguno de los datos de validación). Esto hace que el proceso de evaluación sea menos
confiable.
Una vez que haya desarrollado una configuración de modelo satisfactoria, puede
entrenar su modelo de producción final con todos los datos disponibles (entrenamiento y
validación) y evaluarlo por última vez en el conjunto de prueba. Si resulta que el
desempeño en el conjunto de prueba es significativamente peor que el desempeño
medido en los datos de validación, esto puede significar que su procedimiento de
validación no fue confiable después de todo, o que comenzó a sobreajustarse a los datos
de validación. mientras se ajustan los parámetros del modelo. En este caso, es posible
que desee cambiar a un protocolo de evaluación más confiable (como la validación de
K-fold iterada).

Con licencia para


116 CPASADO4fundamentos de maquinaaprendizaje

Resumen del capítulo


◾ Defina el problema en cuestión y los datos sobre los que entrenará.
Recopile estos datos o anótelos con etiquetas si es necesario.
◾ Elija cómo medirá el éxito de su problema. ¿Qué métricas monitoreará en
sus datos de validación?
◾ Determine su protocolo de evaluación: ¿validación de exclusión?
¿Validación de K-fold? ¿Qué parte de los datos debe usar para la
validación?
◾ Desarrolle un primer modelo que funcione mejor que una línea de base
básica: un modelo con poder estadístico.
◾ Desarrolle un modelo que sobreajuste.

◾ Regularice su modelo y ajuste sus hiperparámetros, en función del


rendimiento de los datos de validación. Gran parte de la investigación
sobre el aprendizaje automático tiende a centrarse solo en este paso,
pero tenga en cuenta el panorama general.

Con licencia para


Parte 2
Aprendizaje profundo en
la práctica
C
Los capítulos 5 a 9 lo ayudarán a obtener una intuición práctica sobre
cómo resolver problemas del mundo real mediante el aprendizaje profundo y lo
familiarizarán con las mejores prácticas esenciales de aprendizaje profundo. La
mayoría de los ejemplos de código del libro se concentran en esta segunda mitad.

Con licencia para


Con licencia para
Aprendizaje
profundo para la
visión artificial

Este capítulo cubre


◾ Comprender las redes neuronales
convolucionales(convnets)
◾ Uso del aumento de datos para mitigar el
sobreajuste
◾ Uso de una convnet preentrenada para
hacer funcionesextracción
◾ Ajuste fino de una convnet preentrenada
◾ Visualizar lo que aprenden los convnets y
cómotomar decisiones de clasificación

Este capítulo presenta las redes neuronales convolucionales, también conocidas como
convnets, un tipo de modelo de aprendizaje profundo utilizado casi universalmente
en aplicaciones de visión artificial. Aprenderá a aplicar convnets a problemas de
clasificación de imágenes, en particular aquellos que involucran pequeños conjuntos
de datos de entrenamiento, que son el caso de uso más común si no es una gran
empresa de tecnología.

119

Con licencia para


120 CPASADO5Aprendizaje profundo para la visión artificial

5.1 Introducción a las convenciones


Estamos a punto de sumergirnos en la teoría de qué son las convnets y por qué han
tenido tanto éxito en las tareas de visión artificial. Pero primero, echemos un vistazo
práctico a un ejemplo simple de convnet. Utiliza una convnet para clasificar los
dígitos MNIST, una tarea que realizamos en el capítulo 2 usando una red
densamente conectada (la precisión de nuestra prueba entonces era del 97,8 %).
Aunque la convnet será básica, su precisión superará a la del modelo densamente
conectado del capítulo 2.
Las siguientes líneas de código le muestran cómo se ve una convnet básica. es una pila de
Conv2DyMaxPooling2Dcapas. Verás en un minuto exactamente lo que hacen.

Listado 5.1 Instanciando un pequeñoconvnet

desde keras importar


capas desde keras
importar modelos
modelo = modelos. Secuencial()
modelo.add(capas.Conv2D(32, (3, 3), activación='relu', input_shape=(28, 28, 1)))
modelo.añadir(capas.MaxPooling2D((2, 2)))
modelo.add(capas.Conv2D(64, (3, 3), activación='relu'))
modelo.añadir(capas.MaxPooling2D((2, 2)))
modelo.add(capas.Conv2D(64, (3, 3), activación='relu'))

Es importante destacar que un convnet toma como entrada tensores de


forma(altura_imagen, ancho_imagen, canales_imagen)(sin incluir la
dimensión del lote). En estocaso, configuraremos el convnet para procesar entradas de
tamaño(28, 28, 1), que es el formato de MNISTimágenes Haremos esto pasando el
argumentoentrada_forma=(28, 28, 1)a la primera capa.
Vamos a mostrar la arquitectura de la convnet hasta ahora:
>>> modelo.resumen()

Capa(tipo)Salida ShapeParam #
================================================== ==============
conv2d_1 (Conv2D) (Ninguno, 26, 26, 320
32)
maxpooling2d_1 (MaxPooling2D) (Ninguno, 13, 13, 0
32)
conv2d_2 (Conv2D) (Ninguno, 11, 11, 18496
64)
maxpooling2d_2 (MaxPooling2D) (Ninguno, 5, 5, 64) 0

conv2d_3 (Conv2D) (Ninguno, 3, 3, 64) 36928


================================================== ==============
Parámetros totales: 55.744
Parámetros entrenables: 55,744
Parámetros no entrenables: 0

Puede ver que la salida de cadaConv2DyMaxPooling2Dcapa es un3Dtensor de


forma(alto, ancho, canales). Las dimensiones de ancho y alto tienden a encogerse

Con licencia para


Introducción aconvenciones 121

a medida que profundiza en la red. El número de canales está controlado por el


primer argumento pasado a las capas Conv2D (32 o 64).
El siguiente paso es alimentar el último tensor de salida (de forma (3, 3, 64)) en un
densamente
red clasificadora conectada como aquellas con las que ya está familiarizado: una pila de
capas densas. Estos clasificadores procesan vectores, que son 1D, mientras que la salida
actual es un tensor 3D. Primero tenemos que aplanar las salidas 3D a 1D, y luego
agregar algunas capas densas encima.

Listado 5.2 Agregando un clasificador encima delconvnet

modelo.añadir(capas.Aplanar())
modelo.añadir(capas.Densa(64, activación='relu'))
modelo.añadir(capas.Densa(10,
activación='softmax'))

Haremos una clasificación de 10 vías, usando una capa final con 10 salidas y una
activación softmax. Así es como se ve la red ahora:
>>> modelo.resumen()
Capa(tipo)Salida ShapeParam #
================================================== ==============
conv2d_1 (Conv2D) (Ninguno, 26, 26, 320
32)
maxpooling2d_1 (MaxPooling2D) (Ninguno, 13, 13, 0
32)
conv2d_2 (Conv2D) (Ninguno, 11, 11, 18496
64)
maxpooling2d_2 (MaxPooling2D) (Ninguno, 5, 5, 64) 0

conv2d_3 (Conv2D) (Ninguno, 3, 3, 64) 36928

flatten_1 (Aplanar) (Ninguno, 576) 0

denso_1 (Denso) (Ninguno, 64) 36928

denso_2 (Denso) (Ninguno, 10) 650


================================================== ==============
Parámetros totales: 93.322
Parámetros entrenables: 93,322
Parámetros no entrenables: 0

Como puedes ver, el(3, 3, 64)las salidas se aplanan en vectores de forma(576,)


antes depasando por dos capas densas.
Ahora, entrenemos la convnet en los dígitos MNIST. Reutilizaremos gran parte del
código del ejemplo MNIST en el capítulo 2.

Listado 5.3 Entrenando el convnet en MNISTimágenes

desde keras.datasets import mnist


de keras.utils importar a_categorical

(imágenes_tren, etiquetas_tren), (imágenes_prueba, etiquetas_prueba) =


mnist.load_data()

Con licencia para


122 CPASADO5Aprendizaje profundo para la visión artificial

imágenes_tren = imágenes_tren.reshape((60000, 28, 28,


1)) imágenes_tren = imágenes_tren.astype('float32') /
255
test_images = test_images.reshape((10000, 28, 28, 1))
test_images = test_images.astype('float32') / 255
entrenar_etiquetas =
to_categorical(train_labels) test_labels =
to_categorical(test_labels)
modelo.compilar(optimizador='rmsprop',
loss='categorical_crossentropy',métricas=['prec
isión'])
modelo.fit(tren_imágenes, tren_etiquetas, épocas=5, tamaño_lote=64)

Evaluemos el modelo en los datos de prueba:


>>> test_loss, test_acc = model.evaluate(test_images, test_labels)
>>> cuenta_prueba
0.99080000000000001

Mientras que la red densamente conectada del capítulo 2 tenía una precisión de
prueba del 97,8 %, la convnet básica tiene una precisión de prueba del 99,3 %:
redujimos la tasa de error en un 68 % (relativo). ¡Nada mal!
Pero, ¿por qué funciona tan bien esta convnet simple, en comparación con una
red densamente conectada?¿modelo? Para responder a esto, profundicemos en lo que
hacen las capas Conv2D y MaxPooling2D.

5.1.1 La operación de convolución


La diferencia fundamental entre una capa densamente conectada y una capa de
convolución es la siguiente: las capas densas aprenden patrones globales en su
espacio de características de entrada (por ejemplo, para un dígito MNIST, patrones
que involucran a todos los píxeles), mientras que las capas de convolución aprenden
patrones locales (ver figura 5.1): en el caso de imágenes, patrones que se encuentran
en pequeñas ventanas 2D de las entradas. En el ejemplo anterior, estas ventanas
eran todas de 3 × 3.

Figura 5.1 Las imágenes se


pueden dividir en patrones
locales como bordes, texturas,
etc.

Con licencia para


Introducción aconvenciones 123

Esta característica clave le da a convnets dos propiedades interesantes:


◾ Los patrones que aprenden son invariantes a la traducción.Después de aprender
un determinado patrón en la esquina inferior derecha de una imagen, una convnet
puede reconocerlo en cualquier lugar: por ejemplo, en la esquina superior
izquierda. Una red densamente conectada tendría que aprender el patrón
nuevamente si apareciera en una nueva ubicación. Esto hace que los datos de
convnets sean eficientes al procesar imágenes (porque el mundo visual es
fundamentalmente invariable a la traducción): necesitan menos muestras de
entrenamiento para aprender representaciones que tienen poder de generalización.
◾ Pueden aprender jerarquías espaciales de patrones (ver figura 5.2). Una primera
capa de convolución aprenderá pequeños patrones locales como bordes, una segunda
capa de convolución aprenderá patrones más grandes hechos de las características de
las primeras capas, y así sucesivamente. Esto permite que los convenios aprendan de
manera eficiente conceptos visuales cada vez más complejos y abstractos (porque el
mundo visual es fundamentalmente espacialmente jerárquico).

"gat
o"

Figura 5.2 El mundo visual forma una jerarquía espacial de


módulos visuales: los bordes hiperlocales se combinan en objetos
locales como ojos u oídos, que se combinan en conceptos de alto
nivel como “gato”.

Las convoluciones operan sobre tensores 3D, llamados mapas de características, con
dos ejes espaciales (alto y ancho) así como un eje de profundidad (también llamado eje
de canales). Para una imagen RGB, la dimensión del eje de profundidad es 3, porque la
imagen tiene tres canales de color: rojo, verde y azul. Para una imagen en blanco y
negro, como los dígitos del MNIST, la profundidad es 1 (niveles de gris). La operación
de convolución extrae parches de su mapa de características de entrada y aplica la
misma transformación a todos estos parches, produciendo un mapa de características de
salida. Este mapa de características de salida sigue siendo un tensor 3D: tiene un ancho
y una altura. Su profundidad puede ser arbitraria, porque la profundidad de salida es un
Con licencia para
parámetro de la capa, y la

Con licencia para


124 CPASADO5Aprendizaje profundo para la visión artificial

los diferentes canales en ese eje de profundidad ya no representan colores


específicos como en la entrada RGB; más bien, representan filtros. Los filtros
codifican aspectos específicos de los datos de entrada: en un nivel alto, un solo filtro
podría codificar el concepto "presencia de una cara en la entrada", por ejemplo.
En el ejemplo de MNIST, la primera capa de convolución toma un mapa de
características de tamaño (28, 28, 1) y genera un mapa de características
de tamaño (26, 26, 32): calcula 32 filtros sobre su entrada. Cada
uno de estos 32 canales de salida contiene una cuadrícula de
valores de 26 × 26, que es un mapa de respuesta del filtro sobre
la entrada, que indica la respuesta de ese patrón de filtro en
diferentes ubicaciones en la entrada (consulte la figura 5.3).
Eso es lo que significa el término mapa de características: cada
dimensión en el eje de profundidad es una característica (o
filtro), y eltensor 2Doutput[:, :, n] es el mapa espacial 2D de la
respuesta de este filtro sobre la entrada.

Mapa de respuesta, que


cuantifica la presencia
del patrón del filtro en
entrada original diferentes ubicaciones

Filtro único

Figura 5.3 El concepto de


unmapa de respuesta: un mapa
2D de la presencia de un patrón
en diferentesubicaciones en una
entrada

Las circunvoluciones se definen mediante dos parámetros clave:


◾ Tamaño de los parches extraídos de las entradas—Estos son típicamente 3 × 3 o 5 × 5.
En elejemplo, eran 3 × 3, que es una elección común.
◾ Profundidad del mapa de características de salida: el número de filtros
calculados por la convolución. El ejemplo comenzó con una profundidad de 32 y
terminó con una profundidad de 64.
En las capas Keras Conv2D, estos parámetros son los primeros argumentos que se pasan a la capa:
Conv2D(profundidad_salida, (alto_ventana, ancho_ventana)) .
Una convolución funciona deslizando estas ventanas de tamaño 3 × 3 o 5 × 5 sobre
el mapa de características de entrada 3D, deteniéndose en cada ubicación posible y
extrayendo el parche 3D de la superficie.funciones de redondeo (forma (ventana_altura,
ventana_ancho, entrada_profundidad)).Luego, cada parche 3D de este tipo se transforma (a
través de un producto tensorial con la misma matriz de peso aprendida, llamada núcleo de
convolución) en un vector de forma 1D (profundidad_salida). Luego, todos estos vectores se
vuelven a ensamblar espacialmente en un mapa de forma de salida 3D (alto, ancho,
profundidad de salida). Cada ubicación espacial en el mapa de características de salida
corresponde a la misma ubicación en el mapa de características de entrada (por ejemplo, la
esquina inferior derecha de la salida contiene información sobre la esquina inferior derecha
de la entrada). Por ejemplo, con ventanas de 3 × 3, la salida vectorial [i, j, :] proviene de la
Con licencia para
entrada del parche 3D [i-1:i+1, j-1:j+1, :]. El proceso completo se detalla en la figura 5.4.

Con licencia para


Introducción aconvenciones 125

Anch Altura
o
Prof Mapa de características de entrada
undid
ad de
entra
da

3 × 3 parches de entrada

producto
punto
connúcleo

Profun
didad Parches transformados
de
salid
a

Mapa de características de salida

Profun
didad
de
salid
a

Figura 5.4 Cómo funciona la convolución

Tenga en cuenta que el ancho y alto de salida pueden diferir del ancho y alto de
entrada. Pueden diferir por dos razones:
◾ Efectos de borde, que se pueden contrarrestar rellenando el mapa de características de
entrada
◾ El uso de zancadas, que definiré en un segundo

Echemos un vistazo más profundo a estas nociones.


tuENTENDEREFECTOS DE BORDE Y RELLENO
Considere un mapa de características de 5 × 5 (25 mosaicos en total). Solo hay 9
mosaicos alrededor de los cuales puede centrar una ventana de 3 × 3, formando una
cuadrícula de 3 × 3 (consulte la figura 5.5). Por lo tanto, el mapa de características
de salida será 3 × 3. Se reduce un poco: en este caso, exactamente dos mosaicos a lo
Con licencia para
largo de cada dimensión. Puede ver este efecto de borde en acción en el ejemplo
anterior: comienza con entradas de 28 × 28, que se convierten en 26 × 26 después
de la primera capa de convolución.

Con licencia para


126 CPASADO5Aprendizaje profundo para la visión artificial

Figura 5.5 Ubicaciones válidas de parches de 3 × 3 en un mapa de características de entrada de 5 × 5

Si desea obtener un mapa de características de salida con las mismas dimensiones


espaciales que la entrada, puede usar el relleno. El relleno consiste en agregar un
número apropiado de filas y columnas a cada lado del mapa de características de
entrada para que sea posible ajustar las ventanas de convolución central alrededor
de cada mosaico de entrada. Para una ventana de 3 × 3, agrega una columna a la
derecha, una columna a la izquierda, una fila en la parte superior y una fila en la
parte inferior. Para una ventana de 5 × 5, agrega dos filas (ver figura 5.6).

etc.

Figura 5.6 Relleno de una entrada de 5 × 5 para poder extraer 25 parches de 3 × 3

En las capas Conv2D, el relleno se puede configurar a través del argumento de relleno, que
toma dos valores: "válido", lo que significa que no hay relleno (solo se utilizarán
ubicaciones de ventana válidas); y "mismo", que significa "almohadilla de tal manera que
tenga una salida con el mismo ancho y alto que la entrada". El argumento de relleno por
defecto es "válido".

Con licencia para


Introducción aconvenciones 127

tuENTENDIENDO LOS PASOS DE CONVOLUCIÓN


El otro factor que puede influir en el tamaño de la producción es la noción de
zancadas. Hasta ahora, la descripción de la convolución ha asumido que los
mosaicos centrales de las ventanas de convolución son todos contiguos. Pero la
distancia entre dos ventanas sucesivas es un parámetro de la convolución, llamado
su zancada, que por defecto es 1. Es posible tener convoluciones con zancadas:
convoluciones con una zancada superior a 1. En la figura 5.7, puede ver los parches
extraídos por una convolución de 3 × 3 con paso 2 sobre una entrada de 5 × 5 (sin
relleno).

1 2
1 2

3 4
3 4

Figura 5.7 Parches de convolución de 3 × 3 con pasos de 2 × 2

El uso de zancada 2 significa que el ancho y la altura del mapa de funciones se


reducen en un factor de 2 (además de los cambios inducidos por los efectos de
borde). Las convoluciones estriadas rara vez se usan en la práctica, aunque pueden
ser útiles para algunos tipos de modelos; es bueno estar familiarizado con el
concepto.
Para reducir la muestra de los mapas de características, en lugar de pasos,
tendemos a usar la operación de agrupación máxima, que vio en acción en el primer
ejemplo de convnet. Veámoslo con más profundidad.

5.1.2 La operación de agrupación máxima


En el ejemplo de convnet, es posible que haya notado que el tamaño de los mapas
de características esreducido a la mitaddespués de cada capa MaxPooling2D. Por ejemplo,
antes de las primeras capas de MaxPooling2D, el mapa de características es de 26 × 26, pero
la operación de agrupación máxima lo reduce a la mitad a 13 × 13. Esa es la función de la
agrupación máxima: reducir agresivamente la muestra de los mapas de características, como
las circunvoluciones estriadas.
La agrupación máxima consiste en extraer ventanas de los mapas de
características de entrada y generar el valor máximo de cada canal. Es
conceptualmente similar a la convolución, excepto que en lugar de transformar
parches locales a través de una transformación lineal aprendida (el núcleo de
convolución), se transforman a través de una operación de tensor máximo
codificada. Una gran diferencia con la convolución es que la agrupación máxima
Con licencia para
generalmente se realiza con ventanas de 2 × 2 y

Con licencia para


128 CPASADO5Aprendizaje profundo para la visión artificial

zancada 2, para reducir la muestra de los mapas de características en un factor de 2.


Por otro lado, la convolución se suele realizar con ventanas de 3 × 3 y sin zancada
(zancada 1).
¿Por qué reducir la resolución de los mapas de características de esta manera? ¿Por
qué no eliminar las capas de agrupación máxima y mantener mapas de características
bastante grandes hasta el final? Veamos esta opción. La base convolucional del modelo
se vería así:
model_no_max_pool = models.Sequential()
model_no_max_pool.add(capas.Conv2D(32, (3, 3), activación='relu',
entrada_forma=(28, 28, 1)))
model_no_max_pool.add(layers.Conv2D(64, (3, 3), activación='relu'))
model_no_max_pool.add(layers.Conv2D(64, (3, 3), activación='relu'))

He aquí un resumen del modelo:


>>> modelo_no_max_pool.resumen()

Capa(tipo)Salida ShapeParam #
================================================== ==============
conv2d_4(Conv2D)(Ninguno, 26, 26,32) 320

conv2d_5(Conv2D)(Ninguno, 24, 24,64)18496

conv2d_6(Conv2D)(Ninguno, 22, 22,64)36928


================================================== ==============
Parámetros totales: 55.744
Parámetros entrenables: 55,744
Parámetros no entrenables: 0

¿Qué tiene de malo esta configuración? Dos cosas:


◾ No es propicio para aprender una jerarquía espacial de características. Las
ventanas de 3 × 3 en la tercera capa solo contendrán información proveniente
de las ventanas de 7 × 7 en la entrada inicial. Los patrones de alto nivel
aprendidos por el convnet seguirán siendo muy pequeños con respecto a la
entrada inicial, lo que puede no ser suficiente para aprender a clasificar
dígitos (intente reconocer un dígito mirándolo solo a través de ventanas de 7
× 7). píxeles!). Necesitamos que las características de la última capa de
convolución contengan información sobre la totalidad de la entrada.
◾ El mapa de características final tiene 22 × 22 × 64 = 30 976 coeficientes totales
por muestra.esto es enorme Si tuviera que aplanarlo para pegar unDensocapa de
tamaño 512 en la parte superior, esa capa tendría 15,8 millones de parámetros. Esto es
demasiado grande para un modelo tan pequeño y daría como resultado un sobreajuste
intenso.
En resumen, la razón para usar la reducción de muestreo es reducir el número de
coeficientes del mapa de características a procesar, así como inducir jerarquías de
filtros espaciales al hacer que las sucesivas capas de convolución miren ventanas
cada vez más grandes (en términos de la fracción de la entrada original que cubren).
Tenga en cuenta que la agrupación máxima no es la única forma en que puede lograr
Con licencia para
dicha reducción de muestreo. Como ya sabes, también puedes usar zancadas en la capa
de convolución anterior. Y tu puedes

Con licencia para


Introducción aconvenciones 129

use la agrupación promedio en lugar de la agrupación máxima, donde cada parche


de entrada local se transforma tomando el valor promedio de cada canal sobre el
parche, en lugar del valor máximo. Pero la agrupación máxima tiende a funcionar
mejor que estas soluciones alternativas. En pocas palabras, la razón es que las
características tienden a codificar la presencia espacial de algún patrón o concepto
sobre los diferentes mosaicos del mapa de características (de ahí el término mapa de
características), y es más informativo observar la presencia máxima de
características diferentes que en su presencia promedio. Entonces, la estrategia de
submuestreo más razonable es producir primero mapas densos de características (a
través de convoluciones sin estrías) y luego observar la activación máxima de las
características en parches pequeños, en lugar de mirar ventanas más dispersas de las
entradas (a través de convoluciones con estrías) o promediar la entrada parches,
En este punto, debe comprender los conceptos básicos de las convnets (mapas de
características, convolución y agrupación máxima) y sabe cómo construir una
pequeña convnet para resolver un problema de juguete como la clasificación de
dígitos MNIST. Ahora pasemos a aplicaciones más útiles y prácticas.

Con licencia para


130 CPASADO5Aprendizaje profundo para la visión artificial

5.2 Entrenando una convnet desde cero en un pequeño conjunto de datos


Tener que entrenar un modelo de clasificación de imágenes usando muy pocos datos es
una situación común, que probablemente encontrará en la práctica si alguna vez hace
visión artificial en un contexto profesional. Unas "pocas" muestras pueden significar
desde unos pocos cientos hasta unas pocas decenas de miles de imágenes. Como
ejemplo práctico, nos centraremos en clasificar imágenes como perros o gatos, en un
conjunto de datos que contiene 4000 imágenes de gatos y perros (2000 gatos, 2000
perros). Usaremos 2000 imágenes para el entrenamiento: 1000 para la validación y 1000
para las pruebas.
En esta sección, revisaremos una estrategia básica para abordar este problema:
entrenar un nuevo modelo desde cero utilizando los pocos datos que tiene. Comenzará
entrenando ingenuamente un pequeño convnet en las 2000 muestras de entrenamiento,
sin ninguna regularización, para establecer una línea base de lo que se puede lograr.
Esto le llevará a una precisión de clasificación del 71%. En ese punto, el problema
principal será el sobreajuste. Luego, presentaremos el aumento de datos, una poderosa
técnica para mitigar el sobreajuste en la visión artificial. Al utilizar el aumento de datos,
mejorará la red para alcanzar una precisión del 82 %.
En la siguiente sección, revisaremos dos técnicas esenciales más para aplicar
profundaaprender a conjuntos de datos pequeños: extracción de características con una red
preentrenada (lo que le dará una precisión del 90 % al 96 %) y ajuste fino de una red
preentrenada (esto le llevará a una precisión final del 97 %). Juntas, estas tres estrategias
(entrenar un modelo pequeño desde cero, extraer características usando un modelo
previamente entrenado y ajustar un modelo previamente entrenado) constituirán su futura
caja de herramientas para abordar el problema de realizar la clasificación de imágenes con
pequeños conjuntos de datos.

5.2.1 La relevancia del aprendizaje profundo para problemas de datos pequeños


A veces escuchará que el aprendizaje profundo solo funciona cuando hay muchos
datos disponibles. Esto es válido en parte: una característica fundamental del
aprendizaje profundo es que puede encontrar características interesantes en los datos
de entrenamiento por sí mismo, sin necesidad de ingeniería de características
manual, y esto solo se puede lograr cuando hay muchos ejemplos de entrenamiento
disponibles. . Esto es especialmente cierto para problemas en los que las muestras
de entrada son de dimensiones muy altas, como las imágenes.
Pero lo que constituye un montón de muestras es relativo, en relación con el tamaño
y la profundidad de la red que intenta entrenar, para empezar. No es posible entrenar un
convnet para resolver un problema complejo con solo unas pocas decenas de muestras,
pero unos pocos cientos pueden ser suficientes si el modelo es pequeño y está bien
regularizado y la tarea es simple. Debido a que los convnets aprenden características
locales invariantes a la traducción, son altamente eficientes con los datos en problemas
de percepción. El entrenamiento de una convnet desde cero en un conjunto de datos de
imagen muy pequeño aún producirá resultados razonables a pesar de la relativa falta de
datos, sin necesidad de ninguna ingeniería de características personalizada. Verá esto en
acción en esta sección.
Además, los modelos de aprendizaje profundo son, por naturaleza, altamente
Con licencia para
reutilizables: puede tomar, por ejemplo, un modelo de clasificación de imágenes o de
voz a texto entrenado en un conjunto de datos a gran escala y reutilizarlo en un
problema significativamente diferente con solo cambios menores. Específicamente,

Con licencia para


Entrenando un convnet desde cero en un pequeñoconjunto de datos 131

En el caso de la visión por computadora, muchos modelos previamente entrenados


(generalmente entrenados en el conjunto de datos de Image-Net) ahora están disponibles
públicamente para su descarga y se pueden usar para arrancar modelos de visión
potentes con muy pocos datos. Eso es lo que hará en la siguiente sección. Comencemos
por tener en sus manos los datos.

5.2.2 Descargando los datos


El conjunto de datos Dogs vs. Cats que utilizará no está empaquetado con Keras.
Kaggle lo puso a disposición como parte de una competencia de visión por computadora
a fines de 2013, cuando las redes de convección no eran la corriente principal. Puede
descargar el conjunto de datos original dewww.kaggle
.com/c/perros-vs-gatos/datos(Deberá crear una cuenta de Kaggle si aún no tiene
una; no se preocupe, el proceso es sencillo).
Las imágenes son archivos JPEG en color de resolución media. La Figura 5.8 muestra
algunos ejemplos.

Figura 5.8 Muestras del conjunto de datos Perros vs. Gatos. No se modificaron las tallas: las muestras
sonheterogénea en tamaño, apariencia, etc.

Como era de esperar, la competencia Kaggle de perros contra gatos en 2013 fue ganada
por los participantes que usaron convnets. Las mejores entradas lograron hasta un 95%
de precisión. En este ejemplo, se acercará bastante a esta precisión (en la siguiente
sección), aunque entrenará sus modelos con menos del 10 % de los datos que estaban
disponibles para los competidores.
Este conjunto de datos contiene 25 000 imágenes de perros y gatos (12 500 de
cada clase) y tiene 543 MB (comprimidos). Después de descargarlo y
descomprimirlo, creará un nuevo conjunto de datos que contiene tres subconjuntos:
un conjunto de entrenamiento con 1000 muestras de cada clase, un conjunto de
validación con 500 muestras de cada clase y un conjunto de prueba con 500

Con licencia para


muestras de cada clase.

Con licencia para


132 CPASADO5Aprendizaje profundo para la visión artificial

El siguiente es el código para hacer esto.

Listado 5.4 Copiando imágenes a directorios de entrenamiento, validación y prueba

Ruta al directorio donde se Directorio donde almacenará su


descomprimió el conjunto de datos conjunto de datos más
original pequeño
importar os, shutil

original_dataset_dir = '/Usuarios/fchollet/Descargas/kaggle_original_data'

base_dir =
'/Usuarios/fchollet/Descargas/gatos_y_perros_pequeños'
os.mkdir(base_dir)

tren_dir = os.path.join(base_dir, 'tren') Directorios


para las
os.mkdir(tren_dir)
divisiones de
validación_dir = os.path.join(base_dir, 'validación') entrenamiento
os.mkdir(validación_dir) , validación y
test_dir = os.path.join(base_dir, 'test') prueba
os.mkdir(test_dir)

tren_gatos_dir = os.path.join(tren_dir, 'gatos') Directorio con fotos


os.mkdir(tren_gatos_dir) de gatos entrenando
entrenar_perros_dir = os.path.join(entrenar_dir, Directorio con fotos
'perros') os.mkdir(entrenar_perros_dir) de perros de
entrenamiento
validación_cats_dir = os.path.join(validation_dir, 'cats') Directorio con fotos de
os.mkdir(validation_cats_dir) gatos de validación

validación_perros_dir = os.path.join(validación_dir, Directorio con fotos de


'perros') os.mkdir(validación_perros_dir) perros de validación

test_cats_dir = os.path.join(test_dir, 'cats') Directorio con fotos de gatos de


os.mkdir(test_cats_dir)

test_dogs_dir = os.path.join(test_dir, 'dogs')


prueba Directorio con fotos de
os.mkdir(test_dogs_dir)

perros de prueba

fnames = ['cat.{}.jpg'.format(i) for i in


range(1000)] copia la
para fname en fnames: primera1,000imá
src = os.path.join(original_dataset_dir, fname) genes de gatos a
dst = os.path.join(train_cats_dir, fname) train_cats_dir
shutil.copyfile(src, dst)
d
fnames = ['cat.{}.jpg'.format(i) for i in range(1000, 1500)] s
for fname in fnames: t
src = os.path.join(original_dataset_dir, fname)
dst = os.path.join(validation_cats_dir, fname) =
shutil.copyfile(src, dst)
o
fnames = ['cat.{}.jpg'.format(i) for i in range(1500, 2000)]
s
for fname in fnames:
.
src = os.path.join(original_dataset_dir, fname)
Con licencia para
path.join(test_cats_dir, fname)
shutil.copyfile(src, dst)
Copia las próximas 500
imágenes de gatos a
validation_cats_dir

Copia las siguientes


500 imágenes de gatos
en test_cats_dir

Con licencia para


Entrenando una convnet desde cero en un pequeño 133
conjunto de datos

fnames = ['dog.{}.jpg'.format(i) for i in range(1000)] copia la


for fname in fnames: primera1,000
src = os.path.join(original_dataset_dir, fname) imágenes de
dst = os.path.join(train_dogs_dir, fname) perros a
shutil.copyfile(src, dst) train_dogs_dir

fnames = ['dog.{}.jpg'.format(i) for i in range(1000, 1500)]


for fname in fnames: Copia las siguientes
src = os.path.join(original_dataset_dir, fname) 500 imágenes de
dst = os.path.join(validation_dogs_dir, fname) perros a
shutil.copyfile(src, dst) validation_dogs_dir

fnames = ['dog.{}.jpg'.format(i) for i in range(1500, 2000)]


for fname in fnames:
src = os.path.join(original_dataset_dir, fname) Copia las siguientes
dst = os.path.join(test_dogs_dir, fname) 500 imágenes de
shutil.copyfile(src, dst) perros a
test_dogs_dir

Como control de cordura, contemos cuántas imágenes hay en cada división de


entrenamiento (entrenamiento/validación/prueba):
>>> print('imágenes totales de entrenamiento de gatos:',
len(os.listdir(train_cats_dir)))imágenes de gato de entrenamiento total:
1000
>>> print('imágenes totales de perros de entrenamiento:',
len(os.listdir(train_dogs_dir)))total de imágenes de perros de
entrenamiento: 1000
>>> print('imágenes cat de validación total:',
len(os.listdir(validation_cats_dir)))validación total imágenes gato: 500
>>> print('imágenes totales de validación de perros:',
len(os.listdir(validation_dogs_dir)))validación total de imágenes de perros:
500
>>> print('total de imágenes de gatos de prueba:',
len(os.listdir(test_cats_dir)))total de imágenes de gatos de prueba:
500
>>> print('total de imágenes de perros de prueba:',
len(os.listdir(test_dogs_dir)))total de imágenes de perros de
prueba: 500

Entonces, de hecho, tiene 2000 imágenes de entrenamiento, 1000 imágenes de


validación y 1000 imágenes de prueba. Cada división contiene el mismo número de
muestras de cada clase: este es un problema de clasificación binaria balanceada, lo que
significa que la precisión de la clasificación será una medida adecuada del éxito.

5.2.3 Construyendo tu red


Construyó una pequeña red de convnet para MNIST en el ejemplo anterior, por lo que
debe estar familiarizado con tales convnets. Reutilizará la misma estructura general: la
convnet será unpila de capas alternadas Conv2D (con activación relu) y MaxPooling2D.
Pero como se trata de imágenes más grandes y de un problema más complejo, tendrá que
haga su red más grande, en consecuencia: tendrá una etapa más de Conv2D +
MaxPooling2D. Esto sirve tanto para aumentar la capacidad de la red como para reducir aún
más el tamaño de los mapas de características para que no sean demasiado grandes cuando

Con licencia para


llegue a la capa Flatten. Aquí, debido a que comienza con entradas de tamaño 150 × 150
(una elección un tanto arbitraria), termina con mapas de características de tamaño 7 × 7 justo
antes de la capa Flatten.

Con licencia para


134 CPASADO5Aprendizaje profundo para la visión artificial

NOTALa profundidad de los mapas de características aumenta progresivamente


en la red (de 32 a 128), mientras que el tamaño de los mapas de características
disminuye (de 148 × 148 a 7 × 7). Este es un patrón que verá en casi todas las
convenciones.

Debido a que está atacando un problema de clasificación binaria, terminará la red con
ununa sola unidad (una capa densa de tamaño 1) y una activación sigmoidea. Esta unidad
codificará la probabilidad de que la red esté mirando una clase u otra.

Listado 5.5 Instanciando una pequeña convnet para perros vs. gatosclasificación

desde keras importar


capas desde keras
importar modelos
modelo = modelos.Sequential()
modelo.add(capas.Conv2D(32, (3, 3), activación='relu',
entrada_forma=(150, 150, 3)))
modelo.añadir(capas.MaxPooling2D((2, 2)))
modelo.add(capas.Conv2D(64, (3, 3), activación='relu'))
modelo.añadir(capas.MaxPooling2D((2, 2)))
modelo.add(capas.Conv2D(128, (3, 3), activación='relu'))
modelo.añadir(capas.MaxPooling2D((2, 2)))
modelo.add(capas.Conv2D(128, (3, 3), activación='relu'))
modelo.añadir(capas.MaxPooling2D((2, 2)))
modelo.añadir(capas.Aplanar())
modelo.añadir(capas.Densa(512,
activación='relu')) modelo.añadir(capas.Densa(
1, activación='sigmoide'))

Veamos cómo cambian las dimensiones de los mapas de características con cada
capa sucesiva:
>>> modelo.resumen()
Capa(tipo)Salida ShapeParam #
================================================== ==============
conv2d_1 (Conv2D) (Ninguna 148, 148, 32) 896
,
maxpooling2d_1 (MaxPooling2D) (Ninguna 74, 74, 32) 0
,
conv2d_2 (Conv2D) (Ninguna 72, 72, 64) 18496
,
maxpooling2d_2 (MaxPooling2D) (Ninguna 36, 36, 64) 0
,
conv2d_3 (Conv2D) (Ninguna 34, 34, 128) 73856
,
maxpooling2d_3 (MaxPooling2D) (Ninguna 17, 17, 128) 0
,
conv2d_4 (Conv2D) (Ninguna 15, 15, 128) 147584
,
maxpooling2d_4 (MaxPooling2D) (Ninguna 7, 7, 128) 0
,
flatten_1 (Aplanar) (Ninguna 6272) 0
,

Con licencia para


denso_1 (Denso) (Ninguna 512) 3211776
,

Con licencia para


Entrenando un convnet desde cero en un pequeñoconjunto de datos 135

denso_2(Denso)(Ninguno, 1)513
================================================== ==============
Parámetros totales: 3.453.121
Parámetros entrenables: 3,453,121
Parámetros no entrenables: 0

Parael paso de compilación, irá con el optimizador RMSprop, como de costumbre.


Debido a que terminó la red con una sola unidad sigmoidea, utilizará la entropía cruzada
binaria como la pérdida (como recordatorio, consulte la tabla 4.1 para ver una hoja de
trucos sobre qué función de pérdida usar en varias situaciones).

Listado 5.6 Configurando el modelo para entrenamiento

de los optimizadores de importación de keras

model.compile(pérdida='binary_crossentropy',
optimizador=optimizadores.RMSprop(lr=1e-
4),métricas=['acc'])

5.2.4 Preprocesamiento de datos


Como ya sabe, los datos deben formatearse en tensores de coma flotante debidamente
preprocesados antes de introducirlos en la red. Actualmente, los datos se encuentran en
una unidad como archivos JPEG, por lo que los pasos para ingresarlos a la red son más
o menos los siguientes:
1Lea los archivos de imágenes.
2Decodificar eljpegcontenido aRGBcuadrículas de píxeles.
3Conviértalos en tensores de punto flotante.

4Vuelva a escalar los valores de píxel (entre 0 y 255) al intervalo [0, 1] (como sabe,
las redes neuronales prefieren trabajar con valores de entrada pequeños).
Puede parecer un poco desalentador, pero afortunadamente Keras tiene utilidades
para encargarse de estos pasos automáticamente. Keras tiene un módulo con
herramientas auxiliares de procesamiento de imágenes, ubicado en
keras.preprocessing.image. En particular, contiene la clase ImageDataGenerator,
que le permite configurar rápidamente generadores de Python que pueden convertir
automáticamente archivos de imagen en el disco en lotes de tensores preprocesados.
Esto es lo que usarás aquí.

Listado 5.7 UsandoGenerador de datos de imagenpara leer imágenes de directorios

de keras.preprocessing.image importar ImageDataGenerator


train_datagen = Cambia la escala de todas las imágenes
ImageDataGenerator(reescalar=1./255) test_datagen por1/255
= ImageDataGenerator(reescalar=1./255)
train_generator = train_datagen.flow_from_directory(
train_dir,
direct tamaño_objetivo=(150, Cambia el tamaño de todas las imágenes a150 ×150
orio de 150) tamaño_lote=20,
destino modo_clase='binario') porque usas
validacion_generador = test_
datag
Con licencia para
en.flow_from_directory(validacion_dir, pérdida de
binary_crossentropy
, necesita etiquetas
binarias.

Con licencia para


136 CPASADO5Aprendizaje profundo para la visión artificial

tamaño_objetivo=(150,
150), tamaño_lote=20,
modo_clase='binario')

Comprender los generadores de Python


AGenerador de Pythones un objeto que actúa como un iterador: es un objeto que
puedes usar con elpara... enoperador. Los generadores se construyen usando
elrendiroperador.
Aquí hay un ejemplo de un generador que produce números enteros:
generador de
definición()
: i = 0
while True:
yo += 1
rendimiento yo

para artículo en
generador ():
imprimir (artículo)
si elemento
> 4:
romper

Imprime esto:
1
2
3
4
Veamos la salida de uno de estos generadores: produce lotes de 150 × 150
5
RGBimágenes (forma (20, 150, 150, 3)) y etiquetas binarias (forma (20,)). Hay 20 muestras
en cada lote (el tamaño del lote). Tenga en cuenta que el generador produce estos lotes
indefinidamente: recorre sin cesar las imágenes en la carpeta de destino. Por esta razón, debe
interrumpir el ciclo de iteración en algún momento:
>>> para data_batch, label_batch en train_generator:
>>>imprimir('datos forma de lote:', data_batch.shape)
>>>imprimir('etiquetas forma de lote:', etiquetas_batch.shape)
>>>descanso
forma de lote de datos: (20, 150,
150, 3) forma de lote de etiquetas:
(20,)

Ajustemos el modelo a los datos usando el generador. Lo hace utilizando el método


fit_generator, el equivalente de fit para generadores de datos como este. Espera como
primer argumento un generador de Python que producirá lotes de entradas y objetivos
indefinidamente, como lo hace este. Debido a que los datos se generan sin cesar, el
modelo de Keras necesita saber cuántas muestras extraer del generador antes de declarar
unépoca superada. Esta es la función del argumento pasos_por_época: después de haber
extraído lotes de pasos_por_época del generador, es decir, después de haberlos ejecutado
durante

Con licencia para


Entrenando un convnet desde cero en un pequeñoconjunto de datos 137

steps_per_epoch pasos de descenso de gradiente: el proceso de


ajuste pasará a la siguiente época. En este caso, los lotes
son 20 muestras, por lo que necesitará 100 lotes hasta que vea
su objetivo de 2000 muestras.
Al usar fit_generator, puede pasar un argumento de validación_datos, muchocomo con el
método de ajuste. Es importante tener en cuenta que este argumento puede ser un generador
de datos, pero también podría ser una tupla de matrices Numpy. Si pasa un generador como
validation_data, se espera que este generador produzca lotes de datos de validación sin fin;
por lo tanto, también debe especificar el argumento validation_steps, que le indica al
proceso cuántos lotes debe extraer del generador de validación para su evaluación.

Listado 5.8 Ajustando el modelo usando un generador por lotes

history =
model.fit_generator(trai
n_generator,
steps_per_epoch=100,
epochs=30,
validación_datos=generador_validación,validación_paso
s=50)

Es una buena práctica guardar siempre sus modelos después del entrenamiento.

Listado 5.9 Guardando elmodelo

modelo.save('gatos_y_perros_pequeños_1.h5')

Tracemos la pérdida y precisión del modelo sobre los datos de entrenamiento y


validación durante el entrenamiento (ver figuras 5.9 y 5.10).

Listado 5.10 Visualización de curvas de pérdida y precisión durantecapacitación

importar matplotlib.pyplot como plt


acc = historia.historia['acc']
val_acc = historia.historia['val_acc']
pérdida = historia.historia['pérdida']
val_pérdida =
historia.historia['val_pérdida']

épocas = rango (1, len (acc) + 1)


plt.plot(epochs, acc, 'bo', label='Entrenamiento acc')
plt.plot(epochs, val_acc, 'b', label='Validation acc')
plt.title('Precisión de entrenamiento y validación')
plt .leyenda()
plt.figura()

plt.plot(épocas, pérdida, 'bo', label='Pérdida de


entrenamiento') plt.plot(epochs, val_loss, 'b',
label='Pérdida de validación') plt.title('Pérdida de
entrenamiento y validación')
plt.leyenda(
)plt.mostrar

Con licencia para


()

Con licencia para


138 CPASADO5Aprendizaje profundo para la visión artificial

Figura 5.9 Capacitación


yprecisión de validación

Figura 5.10 Capacitación


ypérdida de validación

Estos gráficos son característicos del sobreajuste. La precisión del entrenamiento


aumenta linealmente con el tiempo, hasta que alcanza casi el 100 %, mientras que la
precisión de la validación se detiene en un 70–72 %. La pérdida de validación
alcanza su mínimo después de solo cinco épocas y luego se detiene, mientras que la
pérdida de entrenamiento sigue disminuyendo linealmente hasta que llega casi a 0.
Debido a que tiene relativamente pocas muestras de entrenamiento (2000), el
sobreajuste será su principal preocupación. Ya conoce una serie de técnicas que
pueden ayudar a mitigar el sobreajuste, como la deserción y la disminución del peso
(regularización L2). Ahora vamos a trabajar con uno nuevo, específico para la
visión por computadora y utilizado casi universalmente cuando se procesan
imágenes con modelos de aprendizaje profundo: el aumento de datos.

5.2.5 Uso del aumento de datos


El sobreajuste se debe a que tiene muy pocas muestras de las que aprender, lo que le
impide entrenar un modelo que pueda generalizarse a nuevos datos. Dados datos
infinitos, su modelo

Con licencia para


Entrenando un convnet desde cero en un pequeñoconjunto de datos 139

estaría expuesto a todos los aspectos posibles de la distribución de datos en cuestión:


nunca se sobreajustaría. El aumento de datos adopta el enfoque de generar más datos de
entrenamiento a partir de muestras de entrenamiento existentes, aumentando las
muestras a través de una serie de transformaciones aleatorias que producen imágenes de
aspecto creíble. El objetivo es que en el momento del entrenamiento, su modelo nunca
vea exactamente la misma imagen dos veces. Esto ayuda a exponer el modelo a más
aspectos de los datos y a generalizar mejor.
En Keras, esto se puede hacer configurando una serie de transformaciones
aleatorias pararealizarse en las imágenes leídas por la instancia de ImageDataGenerator.
Comencemos con un ejemplo.

Listado 5.11 Estableciendo una configuración de aumento de datos a través deGenerador de


datos de imagen

datagen = ImageDataGenerator(
rango_de_rotación=40,
rango_de_desplazamiento
_de_ancho=0.2,
rango_de_desplazamiento
_de_altura=0.2,
rango_de_corte=0.2,
rango_de_zoom=0.2,
giro_horizontal=Verdade
ro, modo_relleno='más
cercano')

Estas son solo algunas de las opciones disponibles (para obtener más información,
consulte la documentación de Keras). Repasemos rápidamente este código:
◾ rango_de_rotaciónes un valor en grados (0–180), un rango dentro del cual rotar
aleatoriamente las imágenes.
◾ desplazamiento_anchoycambio_de_alturason rangos (como una fracción
del ancho o la altura total) dentro de los cuales se pueden traducir aleatoriamente las
imágenes vertical u horizontalmente.
◾ rango_de_cortees para aplicar aleatoriamente transformaciones de corte.
◾ zoom_rangees para hacer zoom al azar dentro de las imágenes.
◾ giro_horizontales para voltear aleatoriamente la mitad de las imágenes
horizontalmente, relevante cuando no hay supuestos de asimetría horizontal (por
ejemplo, imágenes del mundo real).
◾ modo_rellenoes la estrategia utilizada para rellenar píxeles recién creados, que
pueden aparecer después de una rotación o un cambio de ancho/alto.
Veamos las imágenes aumentadas (ver figura 5.11).

Listado 5.12 Mostrando algunas imágenes de entrenamiento aumentadas aleatoriamente

de keras.imagen de importación de
preprocesamiento
Módulo con utilidades de
preprocesamiento de imágenes
fnames = [os.path.join(train_cats_dir, fname) for
fname in os.listdir(train_cats_dir)]
img_ruta = fnames[3]

Con licencia para


Elige una imagen para aumentar
img = imagen.load_img(img_path, target_size=(150,
150)) Lee la imagen y
la redimensiona

Con licencia para


140 CPASADO5Aprendizaje profundo para la visión artificial

x = imagen.img_to_array(img) Lo convierte en una matriz Numpy con forma (150,150, 3) Le


x = x.reforma((1,) + x.forma) cambia la forma a (1,150,150, 3)
i = 0
para lote en datagen.flow(x, Genera lotes de
lote_tamaño=1): plt.figure(i) imágenes transformadas
imgplot = plt.imshow(imagen.array_to_img(lote[0]))
aleatoriamente. Los bucles
son indefinidos, ¡así que
i += 1
necesitas romper el bucle
si yo % 4 == en algún momento!
0:
descanso

plt.mostrar()

Figura 5.11 Generación de imágenes de gatos a través del aumento de datos aleatorios

Si entrena una nueva red con esta configuración de aumento de datos, la red nunca
verá la misma entrada dos veces. Pero las entradas que ve todavía están fuertemente
interrelacionadas, porque provienen de un pequeño número de imágenes originales:
no puede producir información nueva, solo puede mezclar la información existente.
Como tal, esto puede no ser suficiente para deshacerse por completo del sobreajuste.
Para luchar aún más contra el sobreajuste, también agregará una capa Dropout a su
modelo, justo antes del clasificador densamente conectado.

Con licencia para


Entrenando un convnet desde cero en un pequeñoconjunto de datos 141

Listado 5.13 Definiendo una nueva convnet que incluye dropout


modelo = modelos.Sequential()
modelo.add(capas.Conv2D(32, (3, 3), activación='relu',
entrada_forma=(150, 150, 3)))
modelo.añadir(capas.MaxPooling2D((2, 2)))
modelo.add(capas.Conv2D(64, (3, 3), activación='relu'))
modelo.añadir(capas.MaxPooling2D((2, 2)))
modelo.add(capas.Conv2D(128, (3, 3), activación='relu'))
modelo.añadir(capas.MaxPooling2D((2, 2)))
modelo.add(capas.Conv2D(128, (3, 3), activación='relu'))
modelo.añadir(capas.MaxPooling2D((2, 2)))
modelo.añadir(capas.Flatten())
modelo.añadir(capas.Dropout(0.5))
modelo.añadir(capas.Densa(512, activación='relu
')) modelo.add(capas.Dense(1,
activación='sigmoide'))

model.compile(pérdida='binary_crossentropy',
optimizador=optimizadores.RMSprop(lr=1e-
4),métricas=['acc'])

Entrenemos la red usando aumento y abandono de datos.

Listado 5.14 Entrenando la convnet usando generadores de aumento de datos

train_datagen =
ImageDataGenerator(reescalar=1.
/255, rango_de_rotación=40,
rango_de_cambio_de_ancho=0.2,
rango_de_cambio_de_altura=0.2,
rango_de_corte=0.2,
rango_de_zoom=0.2, ¡Tenga en cuenta que
giro_horizontal=Verdadero,)
los datos de validación
no deben aumentarse!
test_datagen = ImageDataGenerator(rescale=1./255)
train_generator = train_datagen.flow_from_directory(
train_dir,
direct
orio de
target_size=(150, 150), Cambia el tamaño de todas las imágenes a150 ×150
batch_size=32,
destino
class_mode='binary')
porque usas
validacion_generador = pérdida de
test_datagen.flow_from_directory(validacion_dir, binary_crossentropy
tamaño_objetivo=(150, , necesita etiquetas
150), tamaño_lote=32,
binarias.
modo_clase='binario')
history =
model.fit_generator(trai
n_generator,
steps_per_epoch=100,
epochs=100,
validación_datos=generador_validación,validación_p
asos=50)

Con licencia para


142 CPASADO5Aprendizaje profundo para la visión artificial

Guardemos el modelo; lo usará en la sección 5.4.

Listado 5.15 Guardando elmodelo

modelo.save('gatos_y_perros_pequeños_2.h5')

Y graficamos los resultados nuevamente: vea las figuras 5.12 y 5.13. Gracias al
aumento y abandono de datos, ya no se sobreajusta: las curvas de entrenamiento
siguen de cerca las curvas de validación. Ahora alcanza una precisión del 82%, una
mejora relativa del 15% con respecto al modelo no regularizado.

Figura 5.12 Precisión de entrenamiento y


validación con aumento de datos

Figura 5.13 Entrenamiento y


validaciónpérdida con aumento de
datos

Al usar aún más las técnicas de regularización y ajustar los parámetros de la red
(como el número de filtros por capa de convolución o el número de capas en la red),
es posible que pueda obtener una precisión aún mejor, probablemente hasta 86% o
87%. Pero resultaría difícil llegar más alto simplemente entrenando su propia
convnet desde cero, porque tiene muy pocos datos con los que trabajar. Como
siguiente paso para mejorar su precisión en este problema, deberá usar un modelo
previamente entrenado, que es el enfoque de las próximas dos secciones.

Con licencia para


Usando un preentrenadoconvnet 143

5.3 Usando una convnet preentrenada


Un enfoque común y altamente efectivo para el aprendizaje profundo en pequeños
conjuntos de datos de imágenes es usar una red previamente entrenada. Una red
preentrenada es una red guardada que se entrenó previamente en un gran conjunto de
datos, generalmente en una tarea de clasificación de imágenes a gran escala. Si este
conjunto de datos original es lo suficientemente grande y general, entonces la jerarquía
espacial de características aprendidas por la red preentrenada puede actuar
efectivamente como un modelo genérico del mundo visual y, por lo tanto, sus
características pueden resultar útiles para muchos problemas diferentes de visión
artificial. , aunque estos nuevos problemas pueden involucrar clases completamente
diferentes a las de la tarea original. Por ejemplo, puede entrenar una red en ImageNet
(donde las clases son principalmente animales y objetos cotidianos) y luego reutilizar
esta red entrenada para algo tan remoto como identificar muebles en imágenes.
En este caso, consideremos una gran convnet entrenada en el conjunto de datos
de ImageNet (1,4 millones de imágenes etiquetadas y 1000 clases diferentes).
ImageNet contiene muchas clases de animales, incluidas diferentes especies de
gatos y perros, por lo que puede esperar un buen desempeño en el problema de
clasificación de perros contra gatos.
Utilizará la arquitectura VGG16, desarrollada por Karen Simonyan y Andrew
Zisserman en 2014; es una arquitectura convnet simple y ampliamente utilizada para
ImageNet.1 Aunque es un modelo más antiguo, alejado del estado del arte actual y
algo más pesado que muchos otros modelos recientes, lo elegí porque su
arquitectura es similar a la que ya conoce con y es fácil de entender sin introducir
nuevos conceptos. Este puede ser su primer encuentro con uno de estos lindos
nombres de modelos: VGG, ResNet, Inception, Inception-ResNet, Xception, etc.; se
acostumbrará a ellos, porque aparecerán con frecuencia si continúa haciendo
aprendizaje profundo para la visión por computadora.
Hay dos formas de usar una red preentrenada: extracción de características y ajuste fino.
Los cubriremos a ambos. Comencemos con la extracción de características.

5.3.1 Rasgo extracción


La extracción de características consiste en utilizar las representaciones aprendidas
por una red anterior para extraer características interesantes de nuevas muestras.
Estas características luego se ejecutan a través de un nuevo clasificador, que se
entrena desde cero.
Como vio anteriormente, las convnets utilizadas para la clasificación de imágenes
constan de dos partes: comienzan con una serie de capas de agrupación y convolución, y
terminan con un clasificador densamente conectado. La primera parte se llama la base
convolucional del modelo. En el caso de convnets, la extracción de características
consiste en tomar la base convolucional de un

1 Karen Simonyan y Andrew Zisserman, “Redes convolucionales muy profundas para el reconocimiento de imágenes a gran escala,”
arXiv (2014),
https://arxiv.org/abs/1409.1556.

Con licencia para


144 CPASADO5Aprendizaje profundo para la visión artificial

red previamente entrenada, ejecutando los nuevos datos a través de ella, y entrenando
un nuevo clasificador encima de la salida (ver figura 5.14).

Predicció Predicció Predicción


n n

Entrena Entrena Nuevo


doclasifi doclasifi clasificador(inicializa
cador cador do aleatoriamente)

Entrenadoba Entrenadoba Entrenadob


se se ase
convoluciona convoluciona convoluciona
l l l (congelada)

Aporte
Aporte Aporte

Figura 5.14 Intercambio de clasificadores manteniendo la misma base convolucional

¿Por qué solo reutilizar la base convolucional? ¿Podría reutilizar también el clasificador
densamente conectado? En general, se debe evitar hacerlo. La razón es que las
representaciones aprendidas por la base convolucional probablemente sean más
genéricas y, por lo tanto, más reutilizables: los mapas de características de una convnet
son mapas de presencia de conceptos genéricos sobre una imagen, lo que probablemente
sea útil independientemente de la computadora. -problema de visión en cuestión. Pero
las representaciones aprendidas por el clasificador serán necesariamente específicas para
el conjunto de clases en las que se entrenó el modelo: solo contendrán información
sobre la probabilidad de presencia de esta o aquella clase en la imagen completa.
Además, las representaciones que se encuentran en capas densamente conectadas ya no
contienen información sobre la ubicación de los objetos en la imagen de entrada: estas
capas se deshacen de la noción de espacio, mientras que la ubicación del objeto aún se
describe mediante mapas de características convolucionales. Para problemas en los que
importa la ubicación del objeto, las características densamente conectadas son en gran
medida inútiles.
Tenga en cuenta que el nivel de generalidad (y, por lo tanto, de reutilización) de
las representaciones extraídas por capas de convolución específicas depende de la
profundidad de la capa en el modelo. Las capas que aparecen antes en el modelo
extraen mapas de características locales altamente genéricos (como bordes visuales,
colores y texturas), mientras que las capas que están más arriba extraen conceptos
más abstractos (como "oreja de gato" u "ojo de perro"). . Por lo tanto, si su nuevo
conjunto de datos difiere mucho del conjunto de datos en el que se entrenó el
modelo original, es mejor que use solo las primeras capas del modelo para realizar
la extracción de características, en lugar de usar toda la base convolucional.
Con licencia para
Usando un preentrenadoconvnet 145

En este caso, debido a que el conjunto de clases de ImageNet contiene varias


clases de perros y gatos, es probable que sea beneficioso reutilizar la información
contenida en las capas densamente conectadas del modelo original. Pero elegiremos
no hacerlo, para cubrir el caso más general donde el conjunto de clases del nuevo
problema no se superpone al conjunto de clases del modelo original. Pongamos esto
en práctica utilizando la base convolucional de la red VGG16, entrenada en
ImageNet, para extraer características interesantes de imágenes de perros y gatos, y
luego entrenar un clasificador de perros contra gatos sobre estas características.
El modelo VGG16, entre otros, viene preempaquetado con Keras. Puede importarlo
desde el módulo keras.applications. Aquí está la lista de modelos de clasificación de
imágenes (todos preentrenados en el conjunto de datos de ImageNet) que están
disponibles como parte de keras
.aplicaciones:
◾ Xcepción
◾ ComienzoV3
◾ ResNet50
◾ VGG16
◾ VGG19
◾ MobileNet

Instanciamos el modelo VGG16.

Listado 5.16 Instanciando el convolucional VGG16base

de keras.applications importar VGG16


conv_base = VGG16(pesos='imagennet',
include_top=Falso,
input_shape=(150, 150, 3))

Pasas tres argumentos al constructor:


◾ pesosespecifica el punto de control de peso desde el que inicializar el modelo.
◾ include_topse refiere a incluir (o no) el clasificador densamente conectado en
la parte superior de la red. De forma predeterminada, este clasificador
densamente conectado corresponde a las 1000 clases de ImageNet. Porque tiene
la intención de usar su propio clasificador densamente conectado (con solo dos
clases:gatoyperro), no es necesario incluirlo.
◾ entrada_formaes elforma de los tensores de imagen que alimentará a la red.
Este argumento es puramente opcional: si no lo pasa, la red podrá procesar
entradas de cualquier tamaño.
Aquí está el detalle de la arquitectura de la base convolucional VGG16. Es similar a
las convnets simples con las que ya está familiarizado:
>>> conv_base.resumen()
Capa(tipo)Salida ShapeParam #
================================================== ==============
entrada_1(Capa de entrada)(Ninguno, 150, 150,3)0

Con licencia para


146 CPASADO5Aprendizaje profundo para la visión artificial

bloque1_conv (Convolución2D) (Ninguna 150, 150, 64) 1792


1 ,
bloque1_conv (Convolución2D) (Ninguna 150, 150, 64) 36928
2 ,
block1_pool (Posición (Ninguna 75, 75, 64) 0
máxima2D) ,
block2_conv1 (Convolución2D) (Ninguna 75, 75, 128) 73856
,
block2_conv2 (Convolución2D) (Ninguna 75, 75, 128) 147584
,
block2_pool (Posición (Ninguna 37, 37, 128) 0
máxima2D) ,
block3_conv1 (Convolución2D) (Ninguna 37, 37, 256) 295168
,
block3_conv2 (Convolución2D) (Ninguna 37, 37, 256) 590080
,
block3_conv3 (Convolución2D) (Ninguna 37, 37, 256) 590080
,
block3_pool (Posición (Ninguna 18, 18, 256) 0
máxima2D) ,
block4_conv1 (Convolución2D) (Ninguna 18, 18, 512) 1180160
,
block4_conv2 (Convolución2D) (Ninguna 18, 18, 512) 2359808
,
block4_conv3 (Convolución2D) (Ninguna 18, 18, 512) 2359808
,
block4_pool (Posición (Ninguna 9, 9, 512) 0
máxima2D) ,
block5_conv1 (Convolución2D) (Ninguna 9, 9, 512) 2359808
,
block5_conv2 (Convolución2D) (Ninguna 9, 9, 512) 2359808
,
block5_conv3 (Convolución2D) (Ninguna 9, 9, 512) 2359808
,
block5_pool (Posición (Ninguna 4, 4, 512) 0
máxima2D) ,
================================================== ==============
Parámetros totales: 14.714.688
Parámetros entrenables: 14,714,688
Parámetros no entrenables: 0

El mapa de características final tiene forma (4, 4, 512). Esa es la característica encima
de la cual colocará un clasificador densamente conectado.
En este punto, hay dos formas de proceder:
◾ Ejecutar la base convolucional sobre su conjunto de datos, registrar su salida
en una matriz Numpy en el disco y luego usar estos datos como entrada para
un clasificador autónomo densamente conectado similar a los que vio en la
parte 1 de este libro. Esta solución es rápida y económica de ejecutar, porque
solo requiere ejecutar la base convolucional una vez para cada imagen de
entrada, y la base convolucional es, con mucho, la parte más costosa de la
canalización. Pero por la misma razón, esta técnica no le permitirá usar el
aumento de datos.

Con licencia para


Usando un preentrenadoconvnet 147

◾ Extendiendo el modelo que tienes ( conv_base) añadiendoDensocapas en la parte


superior, y ejecutando todo de principio a fin en los datos de entrada. Esto le
permitirá utilizar el aumento de datos, porque cada imagen de entrada pasa por la
base convolucional cada vez que el modelo la ve. Pero por la misma razón, esta
técnica es mucho más costosa que la primera.
Cubriremos ambas técnicas. Repasemos el código requerido para configurar el
primero: registrar la salida de conv_base en sus datos y usar estas salidas como
entradas para un nuevo modelo.
FEXTRACCIÓN DE CARACTERÍSTICAS AST SIN AUMENTO DE DATOS
Comenzará ejecutando instancias del ImageDataGenerator presentado anteriormente para
extraer imágenes como matrices Numpy, así como sus etiquetas. Extraerá características de
estas imágenes llamando al método de predicción del modelo conv_base.

Listado 5.17 Extracción de características usando la base convolucional preentrenada

importar sistema operativo


importar numpy como np
de keras.preprocessing.image importar ImageDataGenerator

base_dir =
'/Usuarios/fchollet/Descargas/gatos_y_perros_pequeños'tren_d
ir = os.path.join(base_dir, 'tren')
validación_dir = os.path.join(base_dir,
'validación')prueba_dir = os.path.join(base_dir, 'prueba')
datagen =
ImageDataGenerator(reescalar=1./255)tamaño_lote = 20
def extract_features(directorio, sample_count):
características = np.zeros (forma = (muestra_recuento,
4, 4, 512))etiquetas =
np.zeros(forma=(muestra_recuento))
generador = Tenga en cuenta que debido a
datagen.flow_from_directory(directorio, que los generadores generan
tamaño_objetivo=(150, datos indefinidamente en un
150),tamaño_lote=tamaño bucle, debe interrumpir después
_lote, de que cada imagen se haya
modo_clase='binario') visto una vez.
y o = 0
para inputs_batch, labels_batch en el
generador:
características_lote = conv_base.predict(entradas_lote)
características[i * tamaño_lote: (i + 1) * tamaño_lote] =
características_lote etiquetas[i * tamaño_lote: (i + 1) *
tamaño_lote] = etiquetas_lote
i+=1
si i * lote_tamaño >= sample_count:
break
características de retorno, etiquetas

entrenar_características, entrenar_etiquetas =
extraer_características(dir_tren, 2000) validar_características,
validar_etiquetas = extraer_características(validación_dir, 1000)
probar_características, probar_etiquetas = extraer_características(prueba_dir,
1000)

Con licencia para


Las características extraídas son actualmente de forma(muestras, 4, 4, 512). Los
alimentará a un clasificador densamente conectado, por lo que primero debe aplanarlos
para(muestras, 8192):

Con licencia para


148 CPASADO5Aprendizaje profundo para la visión artificial

características_de_entrenamiento =
np.reshape(características_de_entrenamiento, (2000, 4 * 4 * 512))
características_de_validación = np.reshape(características_de_validación,
(1000, 4 * 4 * 512)) características_de_prueba =
np.reshape(características_de_prueba, (1000, 4 * 4) * 512))

En este punto, puede definir su clasificador densamente conectado (tenga en cuenta


el uso de abandono para la regularización) y entrenarlo con los datos y las etiquetas
que acaba de registrar.

Listado 5.18 Definición y entrenamiento del clasificador densamente conectado

de keras importar modelos de


keras importar capas de
keras importar optimizadores
modelo = modelos. Secuencial()
modelo.add(capas.Dense(256, activación='relu', input_dim=4 * 4 * 512))
modelo.add(capas.Dropout(0.5))
modelo.add(capas.Densa(1, activación='sigmoide'))
modelo.compilar(optimizador=optimizadores.RMSprop(lr=2e
-5),loss='binary_crossentropy',
metrics=['acc'])

history = model.fit(train_features, train_labels,


epochs=30,
lote_tamaño=20,
validación_datos=(validación_características, validación_etiquetas))

El entrenamiento es muy rápido, porque solo tiene que lidiar con dos capas densas: una época
tarda menos de un segundo, incluso en la CPU.
Veamos las curvas de pérdida y precisión durante el entrenamiento (ver figuras 5.15 y
5.16).

Listado 5.19 Trazando elresultados

importar matplotlib.pyplot como plt


acc = historia.historia['acc']
val_acc = historia.historia['val_acc']
pérdida = historia.historia['pérdida']
val_pérdida =
historia.historia['val_pérdida']

épocas = rango (1, len (acc) + 1)

plt.plot(epochs, acc, 'bo', label='Entrenamiento acc')


plt.plot(epochs, val_acc, 'b', label='Validation acc')
plt.title('Precisión de entrenamiento y validación')
plt .leyenda()

plt.figura()

plt.plot(épocas, pérdida, 'bo', label='Pérdida de


entrenamiento') plt.plot(epochs, val_loss, 'b',
label='Pérdida de validación') plt.title('Pérdida de
entrenamiento y validación')
plt.leyenda(
Con licencia para
)plt.mostrar
()

Con licencia para


Usando un preentrenadoconvnet 149

Figura 5.15 Precisión de entrenamiento


y validación para la extracción de
características simples

Figura 5.16 Pérdida de


entrenamiento y validación para
extracción de características simple

Alcanza una precisión de validación de alrededor del 90 %, mucho mejor que la que
logró en la sección anterior con el modelo pequeño entrenado desde cero. Pero los
gráficos también indican que se está sobreajustando casi desde el principio, a pesar
de usar la deserción con una tasa bastante grande. Esto se debe a que esta técnica no
utiliza el aumento de datos, que es esencial para evitar el sobreajuste con conjuntos
de datos de imágenes pequeños.
FEXTRACCIÓN DE CARACTERÍSTICAS CON AUMENTO DE DATOS
Ahora, revisemos la segunda técnica que mencioné para realizar la extracción de
características, que es mucho más lenta y costosa, pero que le permite usar el
aumento de datos durante el entrenamiento: extender el modelo conv_base y
ejecutarlo de extremo a extremo en las entradas.

NOTAEsta técnica es tan costosa que solo debe intentarla si tiene acceso a una
GPU; es absolutamente intratable en la CPU. Si no puede ejecutar su código en
GPU, entonces la técnica anterior es el camino a seguir.

Con licencia para


150 CPASADO5Aprendizaje profundo para la visión artificial

Dado que los modelos se comportan como capas, puede agregar un modelo (como conv_base) a un
Secuencialmodele como si agregara una capa.

Listado 5.20 Agregando un clasificador densamente conectado encima de la base convolucional

desde keras importar


modelos desde keras
importar capas
modelo = modelos.Sequential()
modelo.add(conv_base)
modelo.add(capas.Flatten())
modelo.add(capas.Dense(256, activación='relu'))
modelo.add(capas.Densa(1, activación='sigmoide'))

Así luce el modelo ahora:


>>> modelo.resumen()
Capa(tipo)Salida ShapeParam #
================================================== ==============
vgg16 (Modelo) (Ninguno, 4, 4, 14714688
512)
flatten_1 (Aplanar) (Ninguno, 8192) 0

denso_1 (Denso) (Ninguno, 256) 2097408

denso_2 (Denso) (Ninguno, 1) 257


================================================== ==============
Parámetros totales: 16.812.353
Parámetros entrenables: 16,812,353
Parámetros no entrenables: 0

Como puedes ver, ella base convolucional de VGG16 tiene 14.714.688 parámetros,
que es muy grande. El clasificador que está agregando en la parte superior tiene 2
millones de parámetros.
Antes de compilar y entrenar el modelo, es muy importante congelar la base
convolucional. Congelar una capa o conjunto de capas significa evitar que sus pesos
se actualicen durante el entrenamiento. Si no hace esto, las representaciones que la
base convolucional aprendió previamente se modificarán durante el entrenamiento.
Debido a que las capas densas en la parte superior se inicializan aleatoriamente, las
actualizaciones de peso muy grandes se propagarían a través de la red, destruyendo
efectivamente las representaciones aprendidas previamente.
En Keras, congela una red configurando su atributo entrenable en False:
>>> print('Este es el número de pesos entrenables'
'antes de congelar la base de conversión:',
len(model.trainable_weights)) Esta es la cantidad de pesos entrenables
antes de congelar la base de conversión: 30
>>> conv_base.entrenable = Falso
>>> print('Este es el número de pesos entrenables'
'después de congelar la base de conversión:',
len(model.trainable_weights)) Esta es la cantidad de pesos entrenables
después de congelar la base de conversión: 4

Con licencia para


Usando un preentrenadoconvnet 151

Con esta configuración, solo se entrenarán los pesos de las dos capas densas que agregó.
Eso es un total de cuatro tensores de peso: dos por capa (la matriz de peso principal y el
vector de polarización). Tenga en cuenta que para que estos cambios surtan efecto,
primero debe compilar el modelo. Si alguna vez modifica la capacidad de entrenamiento
con pesas después de la compilación, debe volver a compilar el modelo, o estos cambios
se ignorarán.
Ahora puede comenzar a entrenar su modelo, con la misma configuración de
aumento de datos que utilizó en el ejemplo anterior.

Listado 5.21 Entrenando el modelo de extremo a extremo con una base convolucional congelada

desde keras.preprocessing.image importar


ImageDataGenerator desde keras importar optimizadores
train_datagen =
ImageDataGenerator(reescala=1
./255, rango_de_rotación=40,
ancho_cambio_rango=0.2,
altura_cambio_rango=0.2 ¡Tenga en
,shear_range=0.2, cuenta que los
zoom_range=0.2, datos de
horizontal_flip=True, validación no
deben
fill_mode='más
aumentarse!
cercano')
test_datagen = ImageDataGenerator(reescalar=1./255)

tren_generador = tren_datagen.flow_from_directory(
train_dir,
direct
orio de
target_size=(150, 150), Cambia el tamaño de todas las imágenes a150 ×150
batch_size=20,
destino
class_mode='binary')
porque usas
validacion_generador = pérdida de
test_datagen.flow_from_directory(validacion_dir, binary_crossentropy
tamaño_objetivo=(150, , necesita etiquetas
binarias.
150), tamaño_lote=20,
modo_clase='binario')

model.compile(pérdida='binary_crossentropy',
optimizador=optimizadores.RMSprop(lr=2e-
5),métricas=['acc'])
history =
model.fit_generator(trai
n_generator,
steps_per_epoch=100,
epochs=30,
validación_datos=generador_validación,validación_p
asos=50)

Grafiquemos los resultados nuevamente (ver figuras 5.17 y 5.18). Como puede ver,
alcanza una precisión de validación de alrededor del 96%. Esto es mucho mejor de lo
que logró con el pequeño convnet entrenado desde cero.

Con licencia para


152 CPASADO5Aprendizaje profundo para la visión artificial

Figura 5.17 Precisión de


entrenamiento y validación para la
extracción de características
conaumento de datos

Figura 5.18 Pérdida de


entrenamiento y validación para
extracción de características con
datosaumento

5.3.2 Sintonia FINA


Otra técnica ampliamente utilizada para la reutilización de modelos,
complementaria a la extracción de características, es el ajuste fino (ver figura 5.19).
El ajuste fino consiste en descongelar algunas de las capas superiores de una base de
modelo congelada utilizada para la extracción de características y entrenar
conjuntamente tanto la parte recién agregada del modelo (en este caso, el
clasificador completamente conectado) como estas capas superiores. Esto se llama
ajuste fino porque ajusta ligeramente las representaciones más abstractas del modelo
que se está reutilizando, para hacerlas más relevantes para el problema en cuestión.

Con licencia para


Usando un preentrenadoconvnet 153

Convolución2D

Bloque de
Convolución2D
conversión 1:
congelado
MaxPooling2D

Convolución2D

Convolución2D
Bloque de
conversión 2:
MaxPooling2D congelado

Convolución2D

Convolución2D

Convolución2D Bloque de
conversión 3:
MaxPooling2D congelado

Convolución2D

Convolución2D

Convolución2D
Bloque de
MaxPooling2D conversión 4:
congelado

Convolución2D

Convolución2D

Convolución2D

MaxPooling2D Afinamos el
bloque Conv
5.
Aplanar

Denso

Denso
afinamosco
mpletamente
nuestro
conectado

clasificador
Figura 5.19 Afinando el último
bloque convolucional de la red VGG16

Con licencia para


154 CPASADO5Aprendizaje profundo para la visión artificial

Dije anteriormente que es necesario congelar la base de convolución de VGG16


para poder entrenar un clasificador inicializado aleatoriamente en la parte superior.
Por la misma razón, solo es posible ajustar las capas superiores de la base
convolucional una vez que el clasificador en la parte superior ya ha sido entrenado.
Si el clasificador aún no está entrenado, entonces la señal de error que se propaga a
través de la red durante el entrenamiento será demasiado grande y las
representaciones previamente aprendidas por las capas que se están ajustando serán
destruidas. Por lo tanto, los pasos para ajustar una red son los siguientes:
1Agregue su red personalizada sobre una red base ya entrenada.
2Congelar la red base.
3Entrena la parte que agregaste.

4Descongele algunas capas en la red base.

5Entrene conjuntamente estas capas y la parte que agregó.

Ya completó los primeros tres pasos al realizar la extracción de características.


Procedamos con el paso 4: descongelará su conv_base y luego congelará capas
individuales dentro de él.
Como recordatorio, así es como se ve tu base convolucional:
>>> conv_base.resumen()
Capa(tipo)Salida ShapeParam #
================================================== ==============
input_1 (capa de entrada) (Ninguna 150, 150, 3) 0
,
block1_conv1 (Convolución2D) (Ninguna 150, 150, 64) 1792
,
block1_conv2 (Convolución2D) (Ninguna 150, 150, 64) 36928
,
block1_pool (Posición (Ninguna 75, 75, 64) 0
máxima2D) ,
block2_conv1 (Convolución2D) (Ninguna 75, 75, 128) 73856
,
block2_conv2 (Convolución2D) (Ninguna 75, 75, 128) 147584
,
block2_pool (Posición (Ninguna 37, 37, 128) 0
máxima2D) ,
block3_conv1 (Convolución2D) (Ninguna 37, 37, 256) 295168
,
block3_conv2 (Convolución2D) (Ninguna 37, 37, 256) 590080
,
block3_conv3 (Convolución2D) (Ninguna 37, 37, 256) 590080
,
block3_pool (Posición (Ninguna 18, 18, 256) 0
máxima2D) ,
block4_conv1 (Convolución2D) (Ninguna 18, 18, 512) 1180160
,
block4_conv2 (Convolución2D) (Ninguna 18, 18, 512) 2359808
,
block4_conv3 (Convolución2D) (Ninguna 18, 18, 512) 2359808
,
block4_pool (Posición (Ninguna 9, 9, 512) 0
máxima2D) ,

Con licencia para


Usando un preentrenadoconvnet 155

block5_conv1 (Convolución2D) (Ninguno, 9, 9, 2359808


512)
block5_conv2 (Convolución2D) (Ninguno, 9, 9, 2359808
512)
block5_conv3 (Convolución2D) (Ninguno, 9, 9, 2359808
512)
block5_pool (Posición (Ninguno, 4, 4, 0
máxima2D) 512)
================================================== ==============
Parámetros totales: 14714688

Ajustará las últimas tres capas convolucionales, lo que significa que todas las capas
hastablock4_pooldeben congelarse, y las capasbloque5_conv1,bloque5_conv2,
ybloque5_conv3debe ser entrenable.
¿Por qué no afinar más capas? ¿Por qué no afinar toda la base convolucional?
Tú podrías. Pero debes considerar lo siguiente:
◾ Las capas anteriores en la base convolucional codifican características más
genéricas y reutilizables, mientras que las capas superiores codifican
características más especializadas. Es más útil afinar las características más
especializadas, porque estas son las que necesitan reutilizarse en su nuevo
problema. Habría rendimientos rápidamente decrecientes en el ajuste fino de las
capas inferiores.
◾ Cuantos más parámetros esté entrenando, mayor será el riesgo de sobreajuste.
La base convolucional tiene 15 millones de parámetros, por lo que sería
arriesgado intentar entrenarla en su pequeño conjunto de datos.
Por lo tanto, en esta situación, es una buena estrategia ajustar solo las dos o tres
capas superiores en la base convolucional. Configuremos esto, comenzando desde
donde lo dejó en el ejemplo anterior.

Listado 5.22 Congelando todas las capas hasta una específica

conv_base.trainable = Verdadero

set_entrenable = Falso
para capa en conv_base.layers:
if capa.nombre ==
'block5_conv1':
set_trainable = True
si set_trainable:
capa.trainable =
Verdadero
más:
capa.entrenable = Falso

Ahora puede comenzar a ajustar la red. Hará esto con el optimizador RMSProp,
utilizando una tasa de aprendizaje muy baja. La razón para utilizar una tasa de
aprendizaje baja es que desea limitar la magnitud de las modificaciones que realiza
en las representaciones de las tres capas que está ajustando. Las actualizaciones
demasiado grandes pueden dañar estas representaciones.

Con licencia para


156 CPASADO5Aprendizaje profundo para la visión artificial

Listado 5.23 Afinando el modelo


model.compile(pérdida='binary_crossentropy',
optimizador=optimizadores.RMSprop(lr=1e-
5),métricas=['acc'])

history =
model.fit_generator(trai
n_generator,
steps_per_epoch=100,
epochs=100,
validación_datos=generador_validación,validación_pasos=
50)

Grafiquemos los resultados usando el mismo código de trazado que antes (vea las figuras 5.20 y
5.21).

Figura 5.20 Precisión de


entrenamiento y validación
para el ajuste fino

Figura 5.21 Pérdida de


entrenamiento y validación
por ajuste fino

Estas curvas parecen ruidosas. Para hacerlos más legibles, puede suavizarlos
reemplazando cada pérdida y precisión con promedios móviles exponenciales de

Con licencia para


estas cantidades. Aquí hay una función de utilidad trivial para hacer esto (vea las
figuras 5.22 y 5.23).

Con licencia para


Usando un preentrenadoconvnet 157

Listado 5.24 Suavizar elparcelas


def suavizar_curva(puntos,
factor=0.8): suavizar_puntos = []
para punto en puntos:
si
puntos_suavizados:
anterior = puntos_suavizados[-1]
smoothed_points.append(previous * factor + point * (1 - factor))
else:
puntos_suavizados.append(punto)
devolver puntos_suavizados

plt.plot(épocas,
smooth_curve(acc), 'bo', label='Entrenamiento suavizado
acc') plt.plot(epochs,
smooth_curve(val_acc), 'b', label='Validación suavizada
acc') plt.title('Precisión de entrenamiento y validación')
plt.leyenda()
plt.figure()
plt.plot(épocas,
smooth_curve(pérdida), 'bo', label='Pérdida de
entrenamiento suavizada') plt.plot(epochs,
smooth_curve(val_loss), 'b', label='Pérdida de validación
suavizada') plt.title('Pérdida de entrenamiento y validación')
plt.leyenda(
)plt.mostrar
()

Figura 5.22 Curvas suavizadas para entrenamiento y precisión de


validaciónpara afinar

Con licencia para


158 CPASADO5Aprendizaje profundo para la visión artificial

Figura 5.23 Curvas suavizadas para entrenamiento y pérdida de validación para ajuste fino

La curva de precisión de validación se ve mucho más limpia. Está viendo una buena
mejora absoluta del 1 % en la precisión, de alrededor del 96 % a más del 97 %.
Tenga en cuenta que la curva de pérdida no muestra ninguna mejora real (de hecho,
se está deteriorando). Quizás se pregunte, ¿cómo podría la precisión permanecer estable
o mejorar si la pérdida no disminuye? La respuesta es simple: lo que muestra es un
promedio de valores de pérdida puntuales; pero lo que importa para la precisión es la
distribución de los valores de pérdida, no su promedio, porque la precisión es el
resultado de un umbral binario de la probabilidad de clase predicha por el modelo. El
modelo aún puede estar mejorando incluso si esto no se refleja en la pérdida promedio.
Ahora puede finalmente evaluar este modelo en los datos de prueba:
test_generator = test_datagen.flow_from_directory(
test_dir,
tamaño_objetivo=(150,
150), tamaño_lote=20,
modo_clase='binario')

test_loss, test_acc = model.evaluate_generator(test_generator, steps=50)


print('test acc:', test_acc)

Aquí obtiene una precisión de prueba del 97%. En la competencia original de


Kaggle en torno a este conjunto de datos, este habría sido uno de los mejores
resultados. Pero utilizando técnicas modernas de aprendizaje profundo, logró
alcanzar este resultado utilizando solo una pequeña fracción de los datos de
capacitación disponibles (alrededor del 10%). ¡Hay una gran diferencia entre poder
entrenar con 20 000 muestras y 2000 muestras!

Con licencia para


Usando un preentrenadoconvnet 159

5.3.3 Terminando
Esto es lo que debe aprender de los ejercicios de las dos secciones anteriores:
◾ Convnets son el mejor tipo de modelos de aprendizaje automático para tareas
de visión por computadora. Es posible entrenar uno desde cero, incluso en un
conjunto de datos muy pequeño, con resultados decentes.
◾ En un conjunto de datos pequeño, el problema principal será el sobreajuste. El
aumento de datos es una forma poderosa de combatir el sobreajuste cuando se
trabaja con datos de imágenes.
◾ Es fácil reutilizar una convnet existente en un nuevo conjunto de datos a
través de la extracción de características. Esta es una técnica valiosa para
trabajar con pequeños conjuntos de datos de imágenes.
◾ Como complemento a la extracción de características, puede utilizar el ajuste
fino, que adapta a un nuevo problema algunas de las representaciones aprendidas
previamente por un modelo existente. Esto empuja el rendimiento un poco más.
Ahora tiene un sólido conjunto de herramientas para tratar los problemas de
clasificación de imágenes, en particular con pequeños conjuntos de datos.

Con licencia para


160 CPASADO5Aprendizaje profundo para la visión artificial

5.4 Visualizando lo que aprenden los convnets


A menudo se dice que los modelos de aprendizaje profundo son "cajas negras":
representaciones de aprendizaje que son difíciles de extraer y presentar en una
forma legible por humanos. Si bien esto es parcialmente cierto para ciertos tipos de
modelos de aprendizaje profundo, definitivamente no es cierto para convnets. Las
representaciones aprendidas por convnets son altamente susceptibles de
visualización, en gran parte porque son representaciones de conceptos visuales.
Desde 2013, se ha desarrollado una amplia gama de técnicas para visualizar e
interpretar estas representaciones. No los examinaremos todos, pero cubriremos tres
de los más accesibles y útiles:
◾ Visualización de salidas intermedias de convnet (activaciones intermedias)—Útil para
comprender cómo las sucesivas capas de convnet transforman su entrada y para obtener
una primera idea del significado de los filtros de convnet individuales.
◾ Visualización de filtros de convnets—Útil para comprender con precisión a qué
patrón visual o concepto es receptivo cada filtro en un convnet.
◾ Visualización de mapas de calor de activación de clases en una imagen—Útil
para comprender qué partes de una imagen se identificaron como pertenecientes a
una clase determinada, lo que le permite localizar objetos en las imágenes.
Para el primer método, visualización de activación, utilizará la pequeña convnet que
entrenó desde cero en el problema de clasificación de perros contra gatos en la
sección 5.2. Para los siguientes dos métodos, utilizará el modelo VGG16 presentado
en la sección 5.3.

5.4.1 Visualización de activaciones intermedias


La visualización de activaciones intermedias consiste en mostrar los mapas de
características que generan varias capas de convolución y agrupación en una red,
dada una determinada entrada (la salida de una capa a menudo se denomina su
activación, la salida de la función de activación). Esto da una idea de cómo se
descompone una entrada en los diferentes filtros aprendidos por la red. Desea
visualizar mapas de características con tres dimensiones: ancho, alto y profundidad
(canales). Cada canal codifica funciones relativamente independientes, por lo que la
forma adecuada de visualizar estos mapas de funciones es trazar de forma
independiente los contenidos de cada canal como una imagen 2D. Comencemos
cargando el modelo que guardó en la sección 5.2:
>>> desde keras.models import load_model
>>> modelo = load_model('gatos_y_perros_pequeños_2.h5')
>>> model.summary() <1> Como recordatorio.

Capa(tipo)Salida ShapeParam #
================================================== ==============
conv2d_5 (Conv2D) (Ninguno, 148, 148, 896
32)
maxpooling2d_5 (MaxPooling2D) (Ninguno, 74, 74, 0
32)
conv2d_6 (Conv2D) (Ninguno, 72, 72, 18496
64)
maxpooling2d_6 (MaxPooling2D) (Ninguno, 36, 36, 0
Con licencia para
64)

Con licencia para


Visualizando lo que convenceaprender 161

conv2d_7 (Conv2D) (Ninguno, 34, 34, 73856


128)
maxpooling2d_7 (MaxPooling2D) (Ninguno, 17, 17, 0
128)
conv2d_8 (Conv2D) (Ninguno, 15, 15, 147584
128)
maxpooling2d_8 (MaxPooling2D) (Ninguno, 7, 7, 128) 0

flatten_2 (Aplanar) (Ninguno, 6272) 0

dropout_1 (Abandono) (Ninguno, 6272) 0

denso_3 (Denso) (Ninguno, 512) 3211776

denso_4 (Denso) (Ninguno, 1) 513


================================================== ==============
Parámetros totales: 3.453.121
Parámetros entrenables: 3,453,121
Parámetros no entrenables: 0

A continuación, obtendrá una imagen de entrada: una imagen de un gato, que no


forma parte de las imágenes en las que se entrenó la red.

Listado 5.25 Preprocesando un soloimagen

img_path =
'/Usuarios/fchollet/Descargas/gatos_y_perros_pequeños/prueba/gatos/cat.1700.jpg'

de keras.imagen de importación de Preprocesa la imagen en un


preprocesamientoimportar numpy como tensor 4D
np

img = imagen.load_img(img_path, target_size=(150,


150))img_tensor = imagen.img_to_array(img)
img_tensor = np.expand_dims(img_tensor, eje=0)
img_tensor /= 255.
Recuerde que el modelo fue
<1> Su formaes (1, 150, 150, 3)
entrenado en entradas que
fueron preprocesadas de esta
imprimir (img_tensor.shape)
manera.

Vamos a mostrar la imagen (ver figura


5.24).

Listado 5.26 Mostrando la pruebaimagen

importar matplotlib.pyplot como plt

plt.imshow(img_tensor[0])plt
.mostrar()

Con licencia para


162 CPASADO5Aprendizaje profundo para la visión artificial

Figura 5.24 La foto del gato de prueba

Para extraer los mapas de características que desea ver, creará un modelo de Keras
que toma lotes de imágenes como entrada y genera las activaciones de todas las
capas de convolución y agrupación. Para hacer esto, usará el modelo de clase de
Keras. Un modelo se instancia usando dos argumentos: un tensor de entrada (o lista
de tensores de entrada) y un tensor de salida (o lista de tensores de salida). La clase
resultante es un modelo de Keras, al igual que los modelos secuenciales con los que
está familiarizado, asignando las entradas especificadas a las salidas especificadas.
Lo que distingue a la clase Modelo es que permite modelos con múltiples salidas, a
diferencia deSecuencial. Para obtener más información sobre la clase
Model, consulte la sección 7.1.

Listado 5.27 Instanciando un modelo a partir de un tensor de entrada y una lista de tensores de salida

de modelos de importación de keras

salidas_capa = [capa.salida para capa en modelo.capas[:8]]


modelo_activación = modelos.Modelo(entradas=modelo.entrada,
salidas=salidas_capa)

Extrae las salidas de las Crea un modelo que devolverá estos


ocho capas superiores. resultados, dada la entrada del modelo

Cuando se alimenta con una entrada de imagen, este modelo devuelve los valores de
las activaciones de capa en el modelo original. Esta es la primera vez que encuentra
un modelo de múltiples salidas en este libro: hasta ahora, los modelos que ha visto
tenían exactamente una entrada y una salida. En el caso general, un modelo puede
tener cualquier número de entradas y salidas. Este tiene una entrada y ocho salidas:
una salida por activación de capa.

Con licencia para


Visualizando lo que convenceaprender 163

Listado 5.28 Ejecutando el modelo en modo predicción


activaciones =
Devuelve una lista de
modelo_activación.predict(img_tensor) cinco matrices Numpy:
una matriz por activación
de capa

Por ejemplo, esta es la activación de la primera capa de convolución para la entrada de la imagen
del gato:
>>> primera_capa_activacion = activaciones[0]
>>>
imprimir(primera_capa_activacion.forma)
(1, 148, 148, 32)

Es un mapa de funciones de 148 × 148 con 32 canales. Intentemos trazar el cuarto canal
de la activación de la primera capa del modelo original (ver figura 5.25).

Listado 5.29 Visualizando el cuarto canal

importar matplotlib.pyplot como plt


plt.matshow(first_layer_activation[0, :, :, 4], cmap='viridis')

Figura 5.25 Cuarto canal de la activaciónde


la primera capa en la imagen del gato de
prueba

Este canal parece codificar un detector de borde diagonal. Probemos con el séptimo
canal (consulte la figura 5.26), pero tenga en cuenta que sus propios canales pueden
variar, porque los filtros específicos aprendidos por las capas de convolución no son
deterministas.

Listado 5.30 Visualizando el séptimo canal

plt.matshow(activación_primera_capa[0, :, :, 7], cmap='viridis')

Con licencia para


164 CPASADO5Aprendizaje profundo para la visión artificial

Figura 5.26 Séptimo canal de activaciónde la


primera capa en la imagen del gato de
prueba

Este parece un detector de "punto verde brillante", útil para codificar ojos de gato. En
este punto, vamos a trazar una visualización completa de todas las activaciones en la red
(ver figura 5.27). Extraerá y trazará cada canal en cada uno de los ocho mapas de
activación, y apilará los resultados en un tensor de imagen grande, con los canales
apilados uno al lado del otro.

Listado 5.31 Visualizando cada canal en cada activación intermedia

nombres_capas = []
Nombres de las capas, para que
para capa en modelo.capas[:8]: puedas tenerlas como parte de tu
nombre_capa.append(capa.nombr trama
e)

imágenes_por_fila = 16 Muestra los mapas de características

para nombre_capa, activación_capa en zip(nombres_capa, activaciones):


n_features = capa_activación.forma[-1] El mapa de características
Número de
características tamaño = capa_activación.forma[1] tiene forma (1, tamaño,
en el mapa de tamaño, n_características).
características n_cols = n_features //
imágenes_por_fila
display_grid = np.zeros((tamaño * n_columnas, imágenes_por_fila * tamaño))
Azulejos
el
canales para col en rango (n_cols):
Coloca cada filtro en
de para fila en rango (imágenes_por_fila): mosaicos en una
activación imagen_canal = activación_capa[0, gran cuadrícula
en esta :, horizontal
matriz :,
col * imágenes_por_fila +
Post- fila] imagen_canal -= imagen_canal.media()
procesosla imagen_canal /= imagen_canal.std()
característica imagen_canal *= 64
para hacerlo imagen_canal += 128
visualmente imagen_canal = np.clip(imagen_canal, 0, 255).astype('uint8')
sabroso display_grid[col * tamaño : (col + 1) * tamaño,
fila * tamaño: (fila + 1) * tamaño] = channel_image

escala = 1. / tamaño scala


plt.figure(figsize=(escala * display_grid.shape[1], *

Con licencia para


display_grid.shape[0])) plt.title(layer_name)
plt.grid(Falso) Muestra la cuadrícula
plt.imshow(display_grid, aspecto='auto',
cmap='viridis')

Con licencia para


Visualizando lo que convenceaprender 165

Figura 5.27 Cada canal de activación de cada capa en la imagen del gato de prueba

Con licencia para


166 CPASADO5Aprendizaje profundo para la visión artificial

Hay algunas cosas a tener en cuenta aquí:


◾ La primera capa actúa como una colección de varios detectores de bordes. En
esa etapa, las activaciones conservan casi toda la información presente en la
imagen inicial.
◾ A medida que asciende, las activacionesvolverse cada vez más abstractos y
menos interpretables visualmente. Comienzan a codificar conceptos de nivel
superior como "oreja de gato" y "ojo de gato". Las presentaciones superiores
llevan cada vez menos información sobre los contenidos visuales de la
imagen, y cada vez más información relacionada con la clase de la imagen.
◾ La escasez de activaciones aumenta con la profundidad de la capa: en la primera
capa, todos los filtros son activados por la imagen de entrada; pero en las
siguientes capas, cada vez más filtros están en blanco. Esto significa que el patrón
codificado por el filtro no se encuentra en la imagen de entrada.
Acabamos de evidenciar una importante característica universal de las
representaciones aprendidas por redes neuronales profundas: las características
extraídas por una capa se vuelven cada vez más abstractas con la profundidad de la
capa. Las activaciones de las capas superiores llevan cada vez menos información
sobre la entrada específica que se está viendo y cada vez más información sobre el
objetivo (en este caso, la clase de la imagen: gato o perro). Una red neuronal
profunda actúa efectivamente como un canal de destilación de información, con
datos sin procesar que ingresan (en este caso, imágenes RGB) y se transforman
repetidamente para que la información irrelevante se filtre (por ejemplo, la
apariencia visual específica del imagen), y la información útil se amplía y refina
(por ejemplo, la clase de la imagen).
Esto es análogo a la forma en que los humanos y los animales perciben el mundo:
después de observar una escena durante unos segundos, un ser humano puede recordar
qué objetos abstractos estaban presentes en ella (bicicleta, árbol), pero no puede
recordar la apariencia específica de estos. objetos. De hecho, si trataste de dibujar una
bicicleta genérica de memoria, es probable que no pudieras hacerlo ni remotamente
bien, aunque hayas visto miles de bicicletas en tu vida (ver, por ejemplo, la figura 5.28).
Pruébalo ahora mismo: este efecto es absolutamente real. Tu cerebro ha aprendido a
abstraer por completo su entrada visual, a transformarla en conceptos visuales de alto
nivel mientras filtra los detalles visuales irrelevantes, lo que hace que sea
tremendamente difícil recordar cómo se ven las cosas a tu alrededor.

Figura 5.28 Izquierda:


intentosdibujar una
bicicleta de memoria.
Derecha: cómo debería
ser una bicicleta
Con licencia para
esquemática.

Con licencia para


Visualizando lo que convenceaprender 167

5.4.2 Visualización de filtros convnet


Otra manera fácil de inspeccionar los filtros aprendidos por convnets es mostrar el
patrón visual al que debe responder cada filtro. Esto se puede hacer con ascenso de
gradiente enespacio de entrada: aplicar descenso de gradiente al valor de la imagen de
entrada de un convnet para maximizar la respuesta de un filtro específico, a partir de una
imagen de entrada en blanco. La imagen de entrada resultante será una a la que el filtro
elegido responda al máximo.
El proceso es simple: construirá una función de pérdida que maximice el valor
de un filtro dado en una capa de convolución dada, y luego usará el descenso de
gradiente estocástico para ajustar los valores de la imagen de entrada para
maximizar este valor de activación .Por ejemplo, aquí hay una pérdida por la activación
del filtro 0 en la capa block3_conv1 de la red VGG16, preentrenada en ImageNet.

Listado 5.32 Definiendo el tensor de pérdida para la visualización de filtros

desde keras.applications importar


VGG16 desde keras importar backend
como K
modelo = VGG16(pesos='imagenet',
include_top=Falso)
nombre_capa =
'block3_conv1'
índice_filtro = 0
salida_capa =
modelo.obtener_capa(nombre_capa).pérdida de salida
= K.media(salida_capa[:, ::,:, índice_filtro])

Para implementar el descenso de gradiente, necesitará el gradiente de esta pérdida


con respecto a la entrada del modelo. Para hacer esto, usará la función de gradientes
empaquetada con el módulo de back-end de Keras.

Listado 5.33 Obteniendo el gradiente de pérdida con respecto a la entrada

grads = K.gradients(loss, La llamada a gradientes devuelve una


model.input)[0] lista de tensores (de tamaño1en este
caso). Por lo tanto, conservas solo el
primer elemento, que es un tensor.

Un truco que no es obvio para ayudar a que el proceso de descenso de gradiente se


desarrolle sin problemas es normalizar el tensor de gradiente dividiéndolo por su
norma L2 (la raíz cuadrada del promedio del cuadrado de los valores en el tensor).
Esto asegura que la magnitud de las actualizaciones realizadas en la imagen de
entrada esté siempre dentro del mismo rango.

Listado 5.34 Truco de normalización de gradiente

graduados /= (K.sqrt(K.mean(K.square(grads))) + Agregar1e–5 antes de


1e-5) dividir para evitar
dividir accidentalmente
por 0.

Con licencia para


Ahora necesita una forma de calcular el valor del tensor de pérdida y el tensor de
gradiente, dada una imagen de entrada. Puede definir una función de servidor de Keras
para hacer esto: iterar es

Con licencia para


168 CPASADO5Aprendizaje profundo para la visión artificial

una función que toma un tensor Numpy (como una lista de tensores de tamaño 1) y
devuelve una lista de dos tensores Numpy: el valor de pérdida y el valor de gradiente.

Listado 5.35 Obtener valores de salida Numpy dados valores de entrada Numpy

iterar = K.función([modelo.entrada], [pérdida, graduados])

importar numpy como np


loss_value, grads_value = iterar ([np.zeros ((1, 150, 150, 3))])

En este punto, puede definir un bucle de Python para hacer un descenso de gradiente estocástico.

Listado 5.36 Maximización de pérdidas vía gradiente estocásticodescendencia

Comienza a partir de
una imagen gris con
algo de ruido.
input_img_data = np.random.random((1, 150, 150, 3)) * 20 + 128.

paso = 1. Magnitud de cada actualización de gradiente


para i en el rango
(40):
loss_value, grads_value = iterar Ejecuta
([input_img_data]) gradienteasce
nso por 40
input_img_data += grads_value * paso escalones

Calcula el valor de Ajusta la imagen de entrada en la


pérdida y el valor de dirección que maximiza la pérdida
gradiente

El tensor de imagen resultante es un tensor de punto flotante de forma (1, 150, 150, 3),
con valores que pueden no ser números enteros dentro de [0, 255]. Por lo tanto, debe
posprocesar este tensor para convertirlo en una imagen visualizable. Lo hace con la
siguiente función de utilidad sencilla.

Listado 5.37 Función de utilidad para convertir un tensor en una imagen válida

def
deprocesar_imagen(x Normaliza el tensor: se
): x -= x.media() centra en 0, asegura
x /= (x.std() + 1e-5) que std es 0.1
x *= 0.1
Clips a [0,1]
x += 0.5
x = np.clip(x, 0, 1)

x*= 255
x = np.clip(x, 0, Conviertea una matriz RGB
255).astype('uint8') devuelve x

Ahora tienes todas las piezas. Reunámoslos en una función de Python que toma
como entrada un nombre de capa y un índice de filtro, y devuelve un tensor de
imagen válido que representa el patrón que maximiza la activación del filtro
especificado.

Con licencia para


Visualizando lo que convenceaprender 169

Listado 5.38 Función para generar visualizaciones de filtros

Construye una función de pérdida que Calcula el


maximiza la activación del filtro n de la gradiente de la
capa en consideración imagen de
entrada con
def generar_patrón(nombre_capa, índice_filtro, respecto a esta
tamaño=150): salida_capa = pérdida
modelo.obtener_capa(nombre_capa).pérdida de salida =
K.media(salida_capa[:, :, :, índice_filtro]) Normalizacióntru
co: normaliza el
grads = K.gradients(loss, model.input)[0] gradiente

graduados /= Devuelve la
pérdida y las
(K.sqrt(K.media(K.cuadrado(graduados))) + 1e-5)
graduaciones
dada la imagen
iterar = K.función([modelo.entrada], [pérdida,
de entrada
graduados])

input_img_data = np.random.random((1, tamaño, tamaño, 3)) * 20 + 128.

Ejec paso = 1. Comienza


uta el para i en el rango (40): desdeuna
ascenso loss_value, grads_value = iterar ([input_img_data]) imagen gris con
de input_img_data += grads_value * paso algo de ruido
gradiente
durante img = input_img_data[0]
40 pasos devuelve
deprocess_image(img)

Intentémoslo (ver figura 5.29):


>>> plt.imshow(generar_patrón('block3_conv1', 0))

Figura 5.29 Patrón que el cerocanal


en capabloque3_conv1responde al
máximo

Parece que el filtro 0 en la capa block3_conv1 responde a un patrón de lunares. Ahora la


parte divertida: puede comenzar a visualizar cada filtro en cada capa. Para simplificar, solo
observará los primeros 64 filtros de cada capa y solo observará la primera capa de cada
bloque de convolución (block1_conv1, block2_conv1, block3_conv1, block4_conv1,
Con licencia para
block5_conv1). Organizará las salidas en una cuadrícula de 8 × 8 de 64 × 64 patrones de
filtro, con algunos márgenes negros entre cada patrón de filtro (consulte las figuras 5.30–
5.33).

Con licencia para


170 CPASADO5Aprendizaje profundo para la visión artificial

Listado 5.39 Generando una cuadrícula de todos los patrones de respuesta de filtro en una capa
nombre_capa =
Imagen vacía (negra)
'bloque1_conv1' tamaño = 64 para almacenar
margen = 5 resultados

resultados = np.zeros((8 * tamaño + 7 * margen, 8 * tamaño + 7 * margen, 3))

para i en el rango Itera sobre las filas de la cuadrícula de


(8): resultados Itera sobre las columnas de la
para j en el rango cuadrícula de resultados
(8):
filter_img = generar_patrón(nombre_capa, i + (j * 8), tamaño=tamaño)

Genera el horizontal_start = i * tamaño + i * margen


patrón final_horizontal = inicio_horizontal + Pone el
para filtro i + (j tamaño inicio_vertical = j * tamaño + j * resultado en
* 8) en el cuadrado(i,
nombre_capa margen final_vertical = inicio_vertical +
j) de la tabla
tamaño resultados[inicio_horizontal: de resultados
final_horizontal,
vertical_start: vertical_end, :] =
filter_img

plt.figure(figsize=(20, 20))
Muestra elcuadrícula de resultados
plt.imshow(resultados)

Figura 5.30 Filtrar patrones por capabloque1_conv1

Con licencia para


Visualizando lo que convenceaprender 171

Figura 5.31 Filtrar patrones por capabloque2_conv1

Figura 5.32 Filtrar patrones por capabloque3_conv1

Con licencia para


172 CPASADO5Aprendizaje profundo para la visión artificial

Figura 5.33 Filtrar patrones por capabloque4_conv1

Estas visualizaciones de filtros le dicen mucho sobre cómo las capas de convnet ven el
mundo: cada capa en un convnet aprende una colección de filtros de modo que sus
entradas se pueden expresar como una combinación de los filtros. Esto es similar a
cómo la transformada de Fourier descompone las señales en un banco de funciones
coseno. Los filtros en estos bancos de filtros de convnet se vuelven cada vez más
complejos y refinados a medida que avanza en el modelo:
◾ Los filtros de la primera capa del modelo ( bloque1_conv1) codifican
bordes y colores direccionales simples (o bordes coloreados, en algunos
casos).
◾ Los filtros debloque2_conv1codificar texturas simples hechas de combinaciones
de bordes y colores.
◾ Los filtros de las capas superiores empiezan a parecerse a las texturas que se
encuentran en las imágenes naturales: plumas, ojos, hojas, etc.

5.4.3 Visualización de mapas de calor de activación de clases


Presentaré una técnica de visualización más: una que es útil para comprender qué partes
de una imagen dada llevaron a un convnet a su decisión de clasificación final. Esto es
útil para depurar el proceso de decisión de un convnet, particularmente en el caso de un
error de clasificación. También le permite localizar objetos específicos en una imagen.
Esta categoría general de técnicas se denomina visualización de mapas de activación de
clases (CAM), y consiste en producir mapas de calor de activación de clases sobre imágenes
de entrada. Un mapa de calor de activación de clase es una cuadrícula 2D de puntajes
asociados con una clase de salida específica, calculada para cada ubicación en cualquier
imagen de entrada, que indica qué tan importante es cada ubicación para

Con licencia para


Visualizando lo que convenceaprender 173

con respecto a la clase en consideración. Por ejemplo, dada una imagen alimentada
en una convnet de perros contra gatos, la visualización CAM le permite generar un
mapa de calor para la clase "gato", que indica qué tan similares a los gatos son las
diferentes partes de la imagen, y también un mapa de calor para la clase. “perro”,
que indica cuán parecidas a perros son las partes de la imagen.
La implementación específica que utilizará es la que se describe en "Grad-CAM:
explicaciones visuales de redes profundas a través de la localización basada en
gradientes". 2 Es muy simple: consiste en tomar el mapa de características de salida
de una capa de convolución, dada una entrada imagen y pesando cada canal en ese
mapa de características por el gradiente de la clase con respecto al canal.
Intuitivamente, una forma de entender este truco es que está ponderando un mapa
espacial de "cuán intensamente la imagen de entrada activa diferentes canales" por
"cuán importante es cada canal con respecto a la clase", lo que da como resultado un
mapa espacial de “Cuán intensamente la imagen de entrada activa la clase”.
Demostraremos esta técnica usando la red VGG16 previamente entrenada nuevamente.

Listado 5.40 Cargando la red VGG16 con pesos preentrenados

Tenga en cuenta que incluye el


de keras.applications.vgg16 importar
clasificador densamente
modelo VGG16 = VGG16(pesos='imagen') conectado en la parte superior; en
todos los casos anteriores, lo
descartaste.
Considere la imagen de dos elefantes africanos que se muestra en la figura 5.34
(bajo una licencia Creative Commons), posiblemente una madre y su cría, paseando
por la sabana. Convirtamos esta imagen en algo que el modelo VGG16 pueda leer:
el modelo fue entrenado en imágenes de tamaño 224 × 244, preprocesadas de
acuerdo con algunas reglas que se empaquetan enla función de utilidad
keras.applications.vgg16.preprocess_input. Entonces necesitascargue la imagen, cambie su
tamaño a 224 × 224, conviértala en un tensor Numpy float32 y aplique estas reglas de
preprocesamiento.

Figura 5.34 Foto de prueba de elefantes africanos

Con licencia para


2
Ramprasaath R. Selvaraju et al., arXiv (2017),https://arxiv.org/abs/ 1610.02391.

Con licencia para


174 CPASADO5Aprendizaje profundo para la visión artificial

Listado 5.41 Preprocesando una imagen de entrada paraVGG16


de keras.imagen de importación de preprocesamiento
desde keras.applications.vgg16 importar preprocess_input,
decode_predictions importar numpy como np

img_path =

'/Usuarios/fchollet/Descargas/creative_commons_elephant.jpg' img =

image.load_img(img_path, target_size=(224, 224))

x = imagen.img_to_array(img) float32 Numpy matriz de


forma (224, 224, 3)
x = np.expand_dims(x, eje=0)

x = preprocess_input(x) Agrega una dimensión para transformar la


matriz en un lote de tamaño (1, 224, 224,
Imagen de Python Imaging Library 3)
(PIL) de tamaño 224 × 224 Preprocesa el lote (esto hace la
Ruta local a la imagen de destino normalización del color por canal)

Ahora puede ejecutar la red preentrenada en la imagen y decodificar su vector de


predicción a un formato legible por humanos:
>>> preds = modelo.predecir(x)
>>> print('Predicted:', decode_predictions(preds, top=3)[0])
Predicted:', [(u'n02504458', u'African_elephant', 0.92546833),
(u'n01871265', u'tusker ', 0.070257246),
(u'n02504013', u'Indian_elephant', 0.0042589349)]

Las tres clases principales previstas para esta imagen son las siguientes:
◾ elefante africano(con 92,5% de probabilidad)
◾ Tusker (con 7% de probabilidad)
◾ Elefante indio (con 0,4% de probabilidad)

La red ha reconocido que la imagen contiene una cantidad indeterminada de


elefantes africanos. La entrada en el vector de predicción que se activó al máximo
es la correspondiente a la clase "Elefante africano", en el índice 386:
>>> np.argmax(preds[0])
386

Para visualizar qué partes de la imagen son más parecidas a un elefante africano,
configuremos el proceso Grad-CAM.

Listado 5.42 Configuración de la Grad-CAMalgoritmo

Entrada “elefante africano” en el


predicciónvector
Mapa de características de salida de
african_e66lephant_output = model.output[:, 386] la capa block5_conv3, la
última capa convolucional
last_conv_layer = model.get_layer('block5_conv3') en VGG16

Con licencia para


Visualizando lo que convenceaprender 175

Gradiente de la clase "elefante Vector de forma(512,), donde cada


africano" con respecto al mapa entrada es la intensidad media del
de características de salida de gradiente sobre un canal de mapa de
block5_conv3 características específico
graduados = K.gradients(african_elephant_output,

last_conv_layer.output)[0] pooled_grads = K.mean(grads, axis=(0, 1, 2))

iterar = K.función([modelo.entrada],
[graduados_agrupados,

última_capa_conv.salida[0]]) valor_graduados_agrupados,

valor_salida_capa_conv = iterar([x])

para i en el rango (512):


conv_layer_output_value[:, :, i] *= pooled_grads_value[i]

mapa de calor = np.mean(conv_layer_output_value, axis=-1)

La media por canal del Multiplica cada


Valores de estas dos cantidades, como canal en la matriz
matrices Numpy, dada la imagen de mapa de características
resultante es el mapa de del mapa de
muestra de dos elefantes características
calor de la activación de
la clase. por “lo
Le permite acceder a los valores de las importante que
cantidades que acaba de definir: es este canal”
pooled_grads y el mapa de características con respecto a la
de salida de block5_conv3, dada una clase “elefante”
imagen de muestra

Para fines de visualización, también normalizará el mapa de calor entre 0 y 1. El


resultado se muestra en la figura 5.35.

Listado 5.43 Mapa de calorPostprocesamiento

mapa de calor = np.maximum(mapa


de calor, 0) mapa de calor /=
np.max(mapa de calor)
plt.matshow(mapa de calor)

0246810
12
0

10
Figura 5.35 Mapa de calor de
12 activación de clase de elefante
Con licencia para
africano sobre la imagen de
prueba

Con licencia para


176 CPASADO5Aprendizaje profundo para la visión artificial

Finalmente, usará OpenCV para generar una imagen que superponga la imagen original
en el mapa de calor que acaba de obtener (vea la figura 5.36).

Listado 5.44 Superponiendo el mapa de calor con la imagen original

importar cv2 Cambia el tamaño del


Usa cv2 para cargar
mapa de calor para que
img = la imagen original
sea del mismo tamaño
cv2.imread(ruta_img) que el
originalimagen
mapa de calor = cv2.resize(mapa de calor, (img.forma[1], img.forma[0]))
mapa de calor = np.uint8(255 * mapa de calor)
Convierte
mapa de calor = cv2.applyColorMap(mapa de calor, elmapa de calor
a RGB
cv2.COLORMAP_JET) superimposed_img = mapa de calor *
0.4 + img

cv2.imwrite('/Usuarios/fchollet/Descargas/elephant_cam.jpg', superimposed_img)
0.4 aquí hay un factor
de intensidad del
mapa de calor.
Guarda la imagen en el disco
Aplica el mapa de calor a la
imagen original

Figura 5.36 Superposición del mapa de calor de activación de clase en la imagen original

Esta técnica de visualización responde a dos preguntas importantes:


◾ ¿Por qué la red pensó que esta imagen contenía un elefante africano?
◾ ¿Dónde se encuentra el elefante africano en la imagen?

En particular, es interesante notar que las orejas de la cría de elefante están


fuertemente activadas: probablemente así es como la red puede diferenciar entre
elefantes africanos e indios.

Con licencia para


Visualizando lo que convenceaprender 177

Resumen del capítulo


◾ Las Convnets son la mejor herramienta para atacar problemas de clasificación
visual.
◾ Convnets funciona aprendiendo una jerarquía de patrones y conceptos
modulares para representar el mundo visual.
◾ Las representaciones que aprenden son fáciles de inspeccionar: ¡las
convenciones son lo opuesto a las cajas negras!
◾ Ahora puede entrenar su propio convnet desde cero para resolver un
problema de clasificación de imágenes.
◾ Entiende cómo usar el aumento de datos visuales para combatir el sobreajuste.
◾ Sabe cómo usar una convnet preentrenada para realizar la extracción y
el ajuste fino de funciones.
◾ Puede generar visualizaciones de los filtros aprendidos por sus convnets, así
como mapas de calor de la actividad de la clase.

Con licencia para


Aprendizaje
profundo para
texto y secuencias

Este capítulo cubre


◾ Preprocesamiento de datos de
texto en útilesrepresentaciones
◾ Trabajando con redes neuronales recurrentes
◾ Uso de convnets 1D para el procesamiento de
secuencias

Este capítulo explora modelos de aprendizaje profundo que pueden procesar


texto (entendido como secuencias de palabras o secuencias de caracteres), series
de tiempo y secuencias de datos en general. Los dos algoritmos fundamentales de
aprendizaje profundo para el procesamiento de secuencias son las redes
neuronales recurrentes y las convnets 1D, la versión unidimensional de las
convnets 2D que cubrimos en los capítulos anteriores. Discutiremos ambos
enfoques en este capítulo.
Las aplicaciones de estos algoritmos incluyen lo siguiente:
◾ Clasificación de documentos y clasificación de series de tiempo, como
identificar el tema de un artículo o el autor de un libro.
◾ Comparaciones de series de tiempo, como estimar qué tan estrechamente
relacionados están dos documentos o dos cotizaciones bursátiles

178

Con licencia para


179

◾ Aprendizaje de secuencia a secuencia, como decodificar una oración en inglés


a francés
◾ Análisis de opinión, como clasificar la opinión de tuits o reseñas de películas
como positivas o negativas.
◾ Pronóstico de series temporales, como predecir el clima futuro en un lugar
determinado, dados los datos meteorológicos recientes
Los ejemplos de este capítulo se centran en dos tareas específicas: el análisis de
sentimientos en el conjunto de datos de IMDB, una tarea que abordamos
anteriormente en el libro, y el pronóstico de temperatura. Pero las técnicas
demostradas para estas dos tareas son relevantes para todas las aplicaciones que
acabamos de enumerar y muchas más.

Con licencia para


180 CPASADO 6Aprendizaje profundopara texto y secuencias

6.1 Trabajar con datos de texto


El texto es una de las formas más extendidas de datos de secuencia. Puede entenderse
como una secuencia de caracteres o como una secuencia de palabras, pero lo más común
es trabajar a nivel de palabras. Los modelos de procesamiento de secuencias de
aprendizaje profundo presentados en las siguientes secciones pueden usar texto para
producir una forma básica de comprensión del lenguaje natural, suficiente para
aplicaciones que incluyen clasificación de documentos, análisis de opiniones,
identificación de autores e incluso respuesta a preguntas (QA). (en un contexto
restringido). Por supuesto, tenga en cuenta a lo largo de este capítulo que ninguno de
estos modelos de aprendizaje profundo comprende realmente el texto en un sentido
humano; más bien, estos modelos pueden mapear la estructura estadística del lenguaje
escrito, lo cual es suficiente para resolver muchas tareas textuales simples.
Como todas las demás redes neuronales, los modelos de aprendizaje profundo no
toman como entrada texto sin procesar: solo funcionan con tensores numéricos.
Vectorizar texto es el proceso de transformar texto en tensores numéricos. Esto se
puede hacer de múltiples maneras:
◾ Segmente el texto en palabras y transforme cada palabra en un vector.
◾ Segmente el texto en caracteres y transforme cada carácter en un vector.
◾ Extraiga n-gramas de palabras o caracteres y transforme cada n-grama en un vector.
N-gramasson grupos superpuestos de varias palabras o caracteres consecutivos.

Colectivamente, las diferentes unidades en las que puede descomponer el texto


(palabras, caracteres o n-gramas) se denominan tokens, y dividir el texto en dichos
tokens se denomina tokenización. Todos los procesos de vectorización de texto
consisten en aplicar algún esquema de tokenización y luego asociar vectores numéricos
con los tokens generados. Estos vectores, empaquetados en tensores de secuencia, se
introducen en redes neuronales profundas. Hay varias formas de asociar un vector con
un token. En esta sección, presentaré dos principales: one-hotcodificaciónde tokens e
incrustación de tokens (normalmente se usa exclusivamente para palabras y se denomina
incrustación de palabras). El resto de esta sección explica estas técnicas y muestra cómo
usarlas para pasar de texto sin formato a un tensor Numpy que puede enviar a una red Keras.

Texto
"El gato se sentó en la
alfombra."

fichas
"el gato se sentó en la alfombra", "."

Codificación vectorial de los tokens


0,0 0,0 0,4 0,0 0,0 1,0 0,0
0,5 1,0 0,5 0,2 0,5 0,5 0,0
1,0 0,2 1,0 1,0 1,0 0,0 0,0 Figura 6.1 Del textoa
el gato se sentó en elestera.
tokens a vectores

Con licencia para


Trabajar con textodatos 181

Comprender los n-gramas y la bolsa de palabras


Los n-gramas de palabras son grupos denorte(o menos) palabras consecutivas que
puede extraer deuna sentencia. el mismo conceptotambién se puede aplicar a
caracteres en lugar de palabras.
Aquí hay un ejemplo simple. Considere la oración "El gato se sentó en la alfombra".
Puede serdescompuesto en el siguiente conjunto de 2 gramos:
{"El", "El gato", "gato", "gato se sentó", "se sentó",
"se sentó en", "en", "en el", "el", "el tapete", "tapete"}

También se puede descomponer en el siguiente conjuntode 3 gramos:


{"El", "El gato", "gato", "gato sentado", "El gato sentado",
"sentado", "sentado en", "en", "gato sentado en", "en
el", "el", "sentado en el", "el tapete", "tapete",
"en el tapete"}

Tal conjunto se llamabolsa-de-2-gramosobolsa-de-3-gramos, respectivamente. El


términobolsaaquí se refiere al hecho de que estás tratando con unestablecerde
tokens en lugar de una lista o secuencia: los tokens no tienen un orden
específico. Esta familia de métodos de tokenización se llamabolsa de palabras.
Debido a que la bolsa de palabras no es un método de tokenización que preserva el
orden (los tokens generados se entienden como un conjunto, no como una secuencia,
y se pierde la estructura general de las oraciones), tiende a usarse en modelos
superficiales de procesamiento del lenguaje en lugar deen aprendizaje
profundomodelos La extracción de n-gramas es una forma de ingeniería de
funciones, y el aprendizaje profundo elimina este tipo de enfoque rígido y frágil,
reemplazándolo con el aprendizaje de funciones jerárquico. Los convenios
unidimensionales y las redes neuronales recurrentes, que se presentan más
adelante en este capítulo, son capaces de aprender representaciones para
grupos de palabras y caracteres sin que se les informe explícitamente sobre la
existencia de dichos grupos, al observar secuencias continuas de palabras o
caracteres. Por esta razón, no trataremos más los n-gramas en este libro. Pero
tenga en cuenta que son una herramienta poderosa e inevitable de ingeniería de
funciones cuando se utilizan modelos de procesamiento de texto ligeros y poco
profundos, como la regresión logística y los bosques aleatorios.

6.1.1 Codificación one-hot de palabras y caracteres


La codificación one-hot es la forma más común y básica de convertir un token en un
vector. Lo vio en acción en los ejemplos iniciales de IMDB y Reuters en el capítulo
3 (hecho con palabras, en ese caso). Consiste en asociar un único índice entero a
cada palabra y luego convertir este índice entero i en un vector binario de tamaño N
(el tamaño del vocabulario); el vector es todo ceros excepto por la i-ésima entrada,
que es 1.
Por supuesto, la codificación one-hot también se puede realizar a nivel de
carácter. Para aclarar sin ambigüedades qué es la codificación one-hot y cómo
implementarla, los listados 6.1 y 6.2 muestran dos ejemplos de juguetes: uno para
Con licencia para
palabras y otro para caracteres.

Con licencia para


182 CPASADO 6Aprendizaje profundopara texto y secuencias

Listado 6.1 Codificación one-hot a nivel de palabra (ejemplo de juguete)

Construye un índice de todos los tokens en los datos


Tokeniza las muestras a través del
Datos iniciales: una entrada por método de división. En la vida real,
muestra (en este ejemplo, una también eliminarías la puntuación y
muestra es una oración, pero podría los caracteres especiales.
ser un documento completo) de las muestras
importar numpy como np
samples = ['El gato se sentó en el tapete.', 'El perro se comió
mi tarea.'] token_index = {}
para muestra en muestras:
para word en sample.split():
si la palabra no está en token_index:
token_index[palabra] = len(token_index)
+ 1

longitud_máx = 10
resultados = np.zeros(forma=(len(muestras),
max_length,
max(token_index.values()) + 1))
para i, muestra en enumerar (muestras):
para j, palabra en la lista (enumerar (muestra. dividir ()))
[: max_length]: index = token_index.get (palabra)
resultados[i, j, índice] Aquí es donde
= 1. almacenas los
resultados.
Asigna un índice único a cada palabra
única. Tenga en cuenta que no Vectoriza las muestras. Solo tendrá
atribuye el índice 0 a nada. en cuenta las primeras
palabras de max_length en
cada muestra.

Listado 6.2 Codificación one-hot a nivel de caracteres (ejemplo de juguete)

cadena de importación

samples = ['El gato se sentó en el tapete.', 'El perro se comió


mi tarea.'] caracteres = string.printable
token_index = dict(zip(rango(1, len(caracteres) + 1), caracteres))

longitud_máx = 50
resultados = np.zeros((len(muestras), max_length, max(token_index.keys())
+ 1)) para i, muestra en enumerar(muestras):
para j, carácter en enumerar (muestra):
index = token_index.get(character) Todo ASCII imprimible
resultados[i, j, index] = 1. caracteres

Tenga en cuenta que Keras tiene utilidades integradas para realizar una codificación de
texto en caliente a nivel de palabra o de carácter, a partir de datos de texto sin procesar.
Debe utilizar estas utilidades, ya que se encargan de una serie de funciones importantes,
como quitar caracteres especiales de las cadenas y solo tener en cuenta las N palabras
más comunes en su conjunto de datos (una restricción común, para evitar tener que
lidiar con espacios de vectores de entrada muy grandes). ).
Con licencia para
Trabajar con textodatos 183

Listado 6.3 Uso de Keras para la codificación one-hot a nivel de palabra

Crea un tokenizador,
configurado para tener en
cuenta solo el
de keras.preprocessing.text import Tokenizer 1,000 palabras más comunes
samples = ['El gato se sentó en el tapete.', 'El perro se comió

mi tarea.'] tokenizer = Tokenizer(num_words=1000)


tokenizer.fit_on_texts (muestras)
Construye convierte cuerdasen
la secuencias = listas de índices
pala tokenizer.texts_to_sequences(muestras) enteros
bra
índic one_hot_results = tokenizer.texts_to_matrix(muestras, modo='binario')
e
índice_palabra = tokenizador.índice_palabra
print('Encontrados %s tokens únicos.' %
len(word_index))
Cómo puede
recuperar el índice
También puede obtener directamente de palabras que se
las representaciones binarias one-hot. calculó
Este tokenizador admite modos de
vectorización distintos de la
codificación one-hot.

Una variante de la codificación one-hot es el llamado truco one-hot hash, que puede
usar cuando la cantidad de tokens únicos en su vocabulario es demasiado grande para
manejarla explícitamente. En lugar de asignar explícitamente un índice a cada palabra y
mantener una referencia de estos índices en un diccionario, puede codificar palabras en
vectores de tamaño fijo. Esto normalmente se hace con una función hash muy ligera. La
principal ventaja de este método es que elimina el mantenimiento de un índice de
palabras explícito, lo que ahorra memoria y permite la codificación en línea de los datos
(puede generar vectores token de inmediato, antes de haber visto todos los datos
disponibles). El único inconveniente de este enfoque es que es susceptible a colisiones
de hash: dos palabras diferentes pueden terminar con el mismo hash, y, posteriormente,
cualquier modelo de aprendizaje automático que observe estos valores hash no podrá
distinguir la diferencia entre estas palabras. La probabilidad de colisiones de hash
disminuye cuando la dimensionalidad del espacio de hash es mucho mayor que el
número total de tokens únicos que se están sometiendo a hash.

Listado 6.4 Codificación one-hot a nivel de palabra con truco hash (ejemplo de juguete)

muestras = ['El gato se sentó en el tapete.', 'El perro se comió


mi tarea.'] dimensionalidad = 1000
longitud_máx = 10

resultados = np.zeros((len(muestras), longitud_máxima,


dimensionalidad)) para i, muestra en enumerar(muestras):
para j, palabra en la lista (enumerar (muestra. dividir ()))
[: max_length]: índice = abs (hash (palabra)) %
dimensionalidad
resultados[i, j, índice] = 1.
tienes cerca1,000 palabras (o más),
Almacena las palabras como vectores de tamaño.1,000. Si verá muchas colisiones hash,lo que

Con licencia para


disminuirá la precisión de este método de codificación. Hashes la palabra enun
índice entero aleatorio
entre 0 y1,000

Con licencia para


184 CPASADO 6Aprendizaje profundopara texto y secuencias

6.1.2 Uso de incrustaciones de palabras


Otra forma popular y poderosa de asociar un vector con una palabra es el uso de
densosvectores de palabras, también llamado incrustaciones de palabras. Mientras que los
vectores obtenidos a través de la codificación one-hot son binarios, dispersos
(principalmente hechos de ceros) y de muy alta dimensión (la misma dimensionalidad que el
número de palabras en el vocabulario), las incrustaciones de palabras son vectores de coma
flotante de baja dimensión (que es decir, vectores densos, en oposición a vectores dispersos);
ver figura 6.2. A diferencia de los vectores de palabras obtenidos a través de la codificación
one-hot, las incrustaciones de palabras se aprenden a partir de los datos. Es común ver
incrustaciones de palabras de 256, 512 o 1024 dimensiones cuando se trata de vocabularios
muy grandes. Por otro lado, las palabras de codificación one-hot generalmente conducen a
vectores que tienen 20 000 dimensiones o más (capturando un vocabulario de 20 000 tokens,
en este caso). Por lo tanto, las incrustaciones de palabras empaquetan más información en
muchas menos dimensiones.

Figura 6.2 Mientras que las representaciones


de palabras obtenidas de la codificación one-
Vectores de palabras incrustaciones de
calientes: palabras: hot o hash son escasas, de gran dimensión y
- Escaso - Denso codificadas de forma rígida, las palabraslas
- de alta dimensión - de menor incrustaciones son densas, de dimensiones
- codificado dimensión relativamente bajas y se aprenden de los
- Aprendido de los datos.
datos

Hay dos formas de obtener incrustaciones de palabras:


◾ Aprenda incrustaciones de palabras junto con la tarea principal que le interesa
(como la clasificación de documentos o la predicción de sentimientos). En esta
configuración, comienza con vectores de palabras aleatorias y luego aprende
vectores de palabras de la misma manera que aprende los pesos de una red
neuronal.
◾ Cargue en su modelo incrustaciones de palabras que fueron precalculadas
usando una tarea de aprendizaje automático diferente a la que está tratando de
resolver. Estos se denominan incrustaciones de palabras preentrenadas.
Veamos ambos.

Con licencia para


Trabajar con textodatos 185

LGANAR INCORPORACIONES DE PALABRAS CON ELmiCAPA DE LECHO


La forma más sencilla de asociar un vector denso con una palabra es elegir el vector
al azar. El problema con este enfoque es que el espacio de incrustación resultante no
tiene estructura: por ejemplo, las palabras preciso y exacto pueden terminar con
incrustaciones completamente diferentes, aunque sean intercambiables en la
mayoría de las oraciones. Es difícil para una red neuronal profunda dar sentido a un
espacio de incrustación tan ruidoso y desestructurado.
Para ser un poco más abstracto, las relaciones geométricas entre los vectores de
palabras deberían reflejar las relaciones semánticas entre estas palabras. Las
incrustaciones de palabras están destinadas a mapear el lenguaje humano en un
espacio geométrico. Por ejemplo, en un espacio de incrustación razonable, esperaría
que los sinónimos se incrustaran en vectores de palabras similares; y, en general,
esperaría que la distancia geométrica (como la distancia L2) entre dos vectores de
palabras cualesquiera se relacione con la distancia semántica entre las palabras
asociadas (las palabras que significan cosas diferentes están incrustadas en puntos
alejados entre sí, mientras que las palabras relacionadas). las palabras están más
cerca). Además de la distancia, es posible que desee que las direcciones específicas
en el espacio de incrustación sean significativas. Para que esto quede más claro,
veamos un ejemplo concreto.
En la figura 6.3, cuatro palabras están incrustadas en un
plano 2D:
gato, perro, lobo y tigre. Con las representaciones vectoriales
Lobo
elegido aquí, algunas relaciones semánticas entre estas 1 Tigre

palabras se pueden codificar como transformaciones


geométricas. Por ejemplo, el mismo vector nos permite Perr
o
pasar de gato a tigre y de perro a lobo: este vector podría Gato
interpretarse como el vector “de mascota a animal
0X
salvaje”. Del mismo modo, otro vector nos permite pasar 01
de perro a gato y de lobo a tigre, lo que podría
Figura 6.3 Un ejemplo de
interpretarse como un vector “de canino a felino”. juguete de un espacio de
En los espacios de incrustación de palabras del mundo incrustación de palabras.
real, los ejemplos comunes de transformaciones
geométricas significativas son “género”
vectores y vectores “plurales”. Por ejemplo, al agregar un vector "femenino" al
vector "rey", obtenemos el vector "reina". Al agregar un vector "plural", obtenemos
"reyes". Los espacios de incrustación de palabras suelen presentar miles de dichos
vectores interpretables y potencialmente útiles.
¿Existe algún espacio ideal para incrustar palabras que mapee perfectamente el
lenguaje humano y pueda usarse para cualquier tarea de procesamiento de lenguaje
natural? Posiblemente, pero todavía tenemos que calcular algo por el estilo.
Además, no existe el lenguaje humano: hay muchos lenguajes diferentes y no son
isomorfos, porque un lenguaje es el reflejo de una cultura específica y un contexto
específico. Pero, desde un punto de vista más pragmático, lo que hace que un
espacio de inserción de palabras sea bueno depende en gran medida de su tarea: el
espacio de inserción de palabras perfecto para un modelo de análisis de sentimientos
de reseñas cinematográficas en inglés puede verse diferente del espacio de inserción
Con licencia para
perfecto para un modelo legal en inglés. -Modelo de clasificación de documentos,
porque la importancia de ciertas relaciones semánticas varía de una tarea a otra.

Con licencia para


186 CPASADO 6Aprendizaje profundopara texto y secuencias

Por lo tanto, es razonable aprender un nuevo espacio de integración con cada nueva
tarea. Afortunadamente, la retropropagación lo hace fácil, y Keras lo hace aún más fácil.
Se trata deaprender los pesos de una capa: la capa de incrustación.

Listado 6.5 Instanciando unincrustacióncapa

de keras.layers import Embedding La capa de incrustación toma al menos dos


argumentos: el número de tokens posibles
embedding_layer = Embedding(1000, 64) (aquí,1,000:1+ índice máximo de palabras)
y la dimensionalidad de las incrustaciones
(aquí, 64).
La capa de incrustación se entiende mejor como un diccionario que asigna índices
enteros (que representan palabras específicas) a vectores densos. Toma enteros como
entrada, busca estos enteros en un diccionario interno y devuelve los vectores asociados.
Es efectivamente una consulta de diccionario (ver figura 6.4).

PalabraindexEmbedding capa Vector de palabra correspondiente


Figura 6.4 losincrustacióncapa

La capa Embedding toma como entrada un tensor 2D de números enteros, de forma


(muestras, secuencia_longitud), donde cada entrada es una secuencia de números enteros.
Puede incrustar secuencias de longitudes variables: por ejemplo, podría introducir en la capa
de incrustación en los lotes de ejemplo anterior con formas (32, 10) (lote de 32 secuencias
de longitud 10) o (64, 15) (lote de 64 secuencias de longitud 15). Sin embargo, todas las
secuencias en un lote deben tener la misma longitud (porque debe empaquetarlas en un solo
tensor), por lo que las secuencias que son más cortas que otras deben rellenarse con ceros y
las secuencias que son más largas deben truncarse.
Esta capa devuelve un 3D punto flotantetensor de forma(muestras,
secuencia_longitud, incrustación_dimensionalidad). tal3DEl tensor puede
entonces ser procesado por unRNNcapa o una1Dcapa de convolución (ambos se
presentarán en las siguientes secciones).
Cuando crea una instancia de una capa de incrustación, suLos pesos (su diccionario
interno de vectores token) son inicialmente aleatorios, al igual que con cualquier otra
capa. Durante el entrenamiento, estos vectores de palabras se ajustan gradualmente a
través de la retropropagación, estructurando el espacio en algo que el modelo posterior
pueda explotar. Una vez entrenado completamente, el espacio de incrustación mostrará
mucha estructura, un tipo de estructura especializada para el problema específico para el
que está entrenando su modelo.
Apliquemos esta idea a la tarea de predicción de sentimientos de revisión de
películas de IMDB con la que ya está familiarizado. Primero, preparará rápidamente
los datos. Restringirá las reseñas de películas a las 10 000 palabras más comunes
(como hizo la primera vez que trabajó con este conjunto de datos) y eliminará las
reseñas después de solo 20 palabras. La red aprenderá incrustaciones de 8
dimensiones para cada una de las 10,000 palabras, convierta el entero de entrada

Con licencia para


Trabajar con textodatos 187

secuencias (tensor entero 2D) en secuencias incrustadas (tensor flotante 3D), aplane
el tensor a 2D y entrene una sola capa densa en la parte superior para la
clasificación.

Listado 6.6 Cargando los datos IMDB para usar con unincrustacióncapa

desde keras.datasets importar


imdb desde keras importar Número depalabras Corta el texto después de
a considerar como esta cantidad de palabras
preprocesamiento
características (entre las palabras más
max_features = 10000 comunes de max_features)
longitud máxima = 20
(tren_x, tren_y), (prueba_x, prueba_y) = imdb.load_data(
num_words=max_features) Carga los datos como listas de enteros.
x_tren = preprocesamiento.secuencia.pad_secuencias(x_tren,
maxlen=maxlen x_prueba =
preprocesamiento.secuencia.pad_secuencias(x_prueba, maxlen=maxlen)
Convierte las listas de enteros
en un tensor de forma de
enteros 2D
(muestras, maxlen)

Listado 6.7 Usando unincrustacióncapa y clasificador en los datos de IMDB

Especifica la longitud máxima de entrada a la


capa de incrustación para que luego pueda
aplanar la
entradas integradas. Después de la incrustación
capa, las activaciones tienen forma (muestras, Aplana el tensor 3D de
maxlen, 8). incrustaciones en un tensor
2D de forma (muestras,
desde keras.models import Sequential maxlen * 8)
from keras.layers import Flatten,
Dense
modelo = Secuencial()
modelo.add(Embedding(10000, 8, Agrega el
clasificador en
input_length=maxlen))modelo.add(Aplanar()) la parte
superior
modelo.add(Dense(1, activación='sigmoide'))
model.compile(optimizador='rmsprop', pérdida='binary_crossentropy',
métricas=['acc'])Resumen Modelo()
historia = modelo.ajuste(x_tren, y_tren,
épocas=10,
tamaño_lote=32,
división_validación=
0.2)

Obtiene una precisión de validación de ~ 76%, lo cual es bastante bueno considerando


que solo está mirando las primeras 20 palabras en cada revisión. Pero tenga en cuenta
que simplemente aplanar las secuencias incrustadas y entrenar una sola capa densa en la
parte superior conduce a un modelo que trata cada palabra en la secuencia de entrada
por separado, sin considerar las relaciones entre palabras y la estructura de la oración
(por ejemplo, este modelo probablemente trataría ambos " esta película es una bomba” y
Con licencia para
“esta película es la bomba” como críticas negativas). Es mucho mejor agregar capas
recurrentes o capas convolucionales 1D encima de las secuencias incrustadas para
aprender características que tengan en cuenta cada secuencia como un todo. Eso es en lo
que nos centraremos en las próximas secciones.

Con licencia para


188 CPASADO 6Aprendizaje profundopara texto y secuencias

tuSING INCORPORACIONES DE PALABRAS PREENTRENADAS


A veces, tiene tan pocos datos de entrenamiento disponibles que no puede usar sus datos
solos para aprender una incrustación adecuada de su vocabulario específica de la tarea.
¿Que haces entonces?
En lugar de aprender incrustaciones de palabras junto con el problema que desea
resolver, puede cargar vectores de incrustación desde un espacio de incrustación
precalculado que sabe que está altamente estructurado y exhibe propiedades útiles,
que captura aspectos genéricos de la estructura del lenguaje. La lógica detrás del uso
de incrustaciones de palabras preentrenadas en el procesamiento del lenguaje
natural es muy similar a la del uso de convnets preentrenadas en la clasificación de
imágenes: no tiene suficientes datos disponibles para aprender características
verdaderamente poderosas por su cuenta, pero espera que características que
necesita para ser bastante genéricas, es decir, características visuales comunes o
características semánticas. En este caso, tiene sentido reutilizar las funciones
aprendidas en un problema diferente.
Dichas incrustaciones de palabras generalmente se calculan utilizando
estadísticas de ocurrencia de palabras (observaciones sobre qué palabras coexisten
en oraciones o documentos), utilizando una variedad de técnicas, algunas que
involucran redes neuronales, otras no. La idea de un espacio incrustado denso y de
baja dimensión para las palabras, calculado sin supervisión, fue inicialmente
explorada por Bengio et al. a principios de la década de 2000,1 pero solo comenzó a
despegar en aplicaciones industriales y de investigación después del lanzamiento de
uno de los esquemas de incrustación de palabras más famosos y exitosos: el
algoritmo Word2vec (https://code.google.com/ archivo/p/word2vec), desarrollado
por Tomas Mikolov en Google en 2013. Las dimensiones de Word2vec capturan
propiedades semánticas específicas, como el género.
Hay varias bases de datos precalculadas de incrustaciones de palabras que puede
descargar y usar en una capa de incrustaciones de Keras. Word2vec es uno de ellos.
Otro popular se llama Vectores Globales para Representación de Palabras
(GloVe,https://nlp.stanford
.edu/proyectos/guante), que fue desarrollado por investigadores de Stanford en
2014. Esta técnica de incrustación se basa en la factorización de una matriz de
estadísticas de coocurrencia de palabras. Sus desarrolladores han puesto a
disposición incrustaciones precalculadas para millones de tokens en inglés,
obtenidos de datos de Wikipedia y datos de Common Crawl.
Veamos cómo puede comenzar a usar las incrustaciones de GloVe en un modelo
de Keras. El mismo método es válido para incrustaciones de Word2vec o cualquier
otra base de datos de incrustación de palabras. También usará este ejemplo para
actualizar las técnicas de tokenización de texto que se introdujeron hace unos
párrafos: comenzará desde el texto sin formato y avanzará hacia arriba.

6.1.3 Poniéndolo todo junto: desde texto sin procesar hasta incrustaciones de palabras
Utilizará un modelo similar al que acabamos de ver: incrustar oraciones en
secuencias de vectores, aplanarlos y entrenar una capa densa en la parte superior.
Pero lo hará usando incrustaciones de palabras previamente entrenadas; y en lugar
de usar los datos IMDB pretokenizados empaquetados en Keras, comenzará desde
Con licencia para
cero descargando los datos de texto originales.

1 Yoshua Bengio et al., Neural Probabilistic Language Models (Springer, 2003).

Con licencia para


Trabajar con textodatos 189

DDESCARGAR ELIMDBDATOS COMO TEXTO SIN PROCESAR


Primero, dirígete ahttp://mng.bz/0tIoy descargue el conjunto de datos sin procesar de IMDB.
Descomprimirlo.
Ahora, recopilemos las revisiones de capacitación individuales en una lista de
cadenas, una cadena porrevisión. También recopilará las etiquetas de revisión
(positivas/negativas) en una lista de etiquetas.

Listado 6.8 Procesando las etiquetas de la IMDB sin procesardatos

importar sistema operativo


imdb_dir =
'/Usuarios/fchollet/Descargas/aclImdb'
train_dir = os.path.join(imdb_dir, 'train')
etiquetas =
[] textos =
[]
para label_type en ['neg', 'pos']:
dir_name = os.path.join(train_dir, label_type)
para fname en os.listdir(dir_name):
if fnombre[-4:] == '.txt':
f = open(os.path.join(dir_name, fname))
textos.append(f.read())
f.cerrar()
if label_type == 'neg':
etiquetas.append(0)
más:
etiquetas.append(1)

TOKENIZANDO LOS DATOS


Vectoricemos el texto y preparemos una división de entrenamiento y validación,
utilizando los conceptos presentados anteriormente en esta sección. Debido a que
las incrustaciones de palabras preentrenadas están destinadas a ser particularmente
útiles en problemas donde hay pocos datos de entrenamiento disponibles (de lo
contrario, es probable que las incrustaciones específicas de tareas los superen),
agregaremos el siguiente giro: restringir los datos de entrenamiento a las primeras
200 muestras. Entonces, aprenderá a clasificar reseñas de películas después de ver
solo 200 ejemplos.

Listado 6.9 Tokenizando el texto de la IMDB sin procesardatos

de keras.preprocessing.text import Tokenizer


desde keras.preprocessing.sequence import
pad_sequences import numpy as np

maxlen = 100 Corta las reseñas después100 palabras


muestras_entrenamiento Trenesen 200 muestras
= 200
validacion_muestras = Validaen10,000 muestras
10000
max_palabras = 10000 Considera solo laparte
superior
tokenizer = Tokenizer(num_words=max_words) secuencias =
tokenizer.fit_on_texts(textos) tokenizer.texts_to_se
quences(textos)
Con licencia para
10,000palabras en el conjunto de datos

Con licencia para


190 CPASADO 6Aprendizaje profundopara texto y secuencias

índice_palabra = tokenizador.índice_palabra
print('Encontrados %s tokens únicos.' %

len(word_index)) data = pad_sequences(secuencias,

maxlen=maxlen)

etiquetas = np.asarray(etiquetas)
print('Forma del tensor de datos:',
datos.forma) print('Forma del tensor de
etiquetas:', etiquetas.forma)

índices =np.arange(datos.forma[0]) Divide los datos en un conjunto de


np.random.shuffle(índices) entrenamiento y un conjunto de validación,
datos = datos[índices] pero primero mezcla los datos, porque
etiquetas = comienza con datos en los que se ordenan
las muestras (primero todos los negativos,
etiquetas[índices]
luego todos los positivos)
x_train = data[:training_samples]
y_train =
etiquetas[:training_samples]
x_val = datos[muestras_entrenamiento: muestras_entrenamiento +
muestras_validación] y_val = etiquetas[muestras_entrenamiento:
muestras_entrenamiento + muestras_validación]

DDESCARGAR ELGRAMOLOVE INCORPORACIONES DE PALABRAS


GRAMOoahttps://nlp.stanford.edu/projects/glove,y descargue las incrustaciones
precalculadas de Wikipedia en inglés de 2014. Es un archivo zip de 822 MB llamado
guante.6B.zip, que contiene vectores incrustados de 100 dimensiones para 400 000 palabras
(o tokens sin palabras). Descomprímelo.
PAGSREPROCESAMIENTO DE LOS EMPOTRADOS
Analicemos el archivo descomprimido (un archivo .txt) para crear un índice que
asigne palabras (como cadenas) a su representación vectorial (como vectores
numéricos).

Listado 6.10 Analizando el archivo de incrustaciones de palabras de GloVe

guante_dir = '/Usuarios/fchollet/Descargas/glove.6B'
incrustaciones_index = {}
f = open(os.path.join(glove_dir, 'glove.6B.100d.txt'))
para la línea en f:
valores =
línea.split() palabra
= valores[0]
coefs = np.asarray(valores[1:],
dtype='float32') incrustaciones_index[palabra]
= coefs
f.cerrar()
print('Encontrados %s vectores de palabras.' % len(incrustaciones_index))

A continuación, creará una matriz de incrustación que puede cargar en una capa de
incrustación. Esodebe ser una matriz de forma (max_words, embedding_dim), donde cada
entrada i contiene el vector dimensional embedding_dim para la palabra del índice i en el
Con licencia para
índice de palabras de referencia (creado durante la tokenización). Tenga en cuenta que el
índice 0 no debe representar ninguna palabra o token, es un marcador de posición.

Con licencia para


Trabajar con textodatos 191

Listado 6.11 Preparando la matriz de incrustaciones de palabras GloVe


incrustación_dim = 100
embedding_matrix = np.zeros((max_words, embedding_dim))
for word, i in word_index.items():
si yo < max_words:
incrustar_vector = Palabrasno encontrado
incrustaciones_index.get(palabra) si en el índice de
incrustar_vector no es Ninguno: incrustación será todo
matriz_incrustación[i] = ceros.
vector_incrustación

DDEFINIR UN MODELO
Usará la misma arquitectura modelo que antes.

Listado 6.12 Modelodefinición

de keras.models import Secuencial


de keras.layers import Embedding, Flatten, Dense
modelo = Secuencial()
modelo.add(Embedding(max_words, embedding_dim,
input_length=maxlen)) model.add(Flatten())
modelo.add(Dense(32, activación='relu'))
modelo.add(Dense(1,
activación='sigmoid')) modelo.resumen()

LCARGANDO ELGRAMOLOVE INTEGRACIONES EN EL MODELO


La capa de incrustación tiene una matriz de ponderación única: una matriz flotante 2D donde
cada entrada i es el vector de palabras destinado a asociarse con el índice i. Suficientemente
simple. Cargue la matriz GloVe que preparó en la capa de incrustación, la primera capa del
modelo.

Listado 6.13 Cargar incrustaciones de palabras preentrenadas en elincrustacióncapa

modelo.capas[0].set_weights([embedding_matrix])modelo.capas[0].en
trenable = Falso

Además, congelará la capa de incrustación (establecerá su atributo entrenable en Falso),


siguiendo la misma lógica con la que ya está familiarizado en el contexto de las funciones de
convnet preentrenadas: cuando partes de un modelo están preentrenadas (como su capa de
incrustación) y las partes se inicializan aleatoriamente (como su clasificador), las partes
preentrenadas no deben actualizarse durante el entrenamiento, para evitar olvidar lo que ya
saben. Las grandes actualizaciones de gradiente desencadenadas por las capas inicializadas
aleatoriamente interrumpirían las características ya aprendidas.

Con licencia para


192 CPASADO 6Aprendizaje profundopara texto y secuencias

TLLUVIA Y EVALUACIÓN DEL MODELO


Compile y entrene el modelo.

Listado 6.14 Capacitación y evaluación

modelo.compilar(optimizador='rmsprop',
loss='binary_crossentropy',métricas=['acc
'])
historia = modelo.ajuste(x_tren, y_tren,
épocas=10,
tamaño_lote=32
,
validación_datos=(x_val,
y_val))
modelo.save_weights('pre_trained_glove_model.h5')

Ahora, grafique el desempeño del modelo a lo largo del tiempo (vea las figuras 6.5 y 6.6).

Listado 6.15 Trazando elresultados

importar matplotlib.pyplot como plt


acc = historia.historia['acc']
val_acc = historia.historia['val_acc']
pérdida = historia.historia['pérdida']
val_pérdida =
historia.historia['val_pérdida']

épocas = rango (1, len (acc) + 1)


plt.plot(epochs, acc, 'bo', label='Entrenamiento acc')
plt.plot(epochs, val_acc, 'b', label='Validation acc')
plt.title('Precisión de entrenamiento y validación')
plt .leyenda()
plt.figura()

plt.plot(épocas, pérdida, 'bo', label='Pérdida de


entrenamiento') plt.plot(epochs, val_loss, 'b',
label='Pérdida de validación') plt.title('Pérdida de
entrenamiento y validación')
plt.leyenda(
)plt.mostrar
()

Figura 6.5 Pérdida de entrenamiento y


Con licencia para
validación cuando se usan
incrustaciones de palabras previamente
entrenadas

Con licencia para


Trabajar con textodatos 193

Figura 6.6 Precisión de


entrenamiento y validación
cuando se usan
incrustaciones de palabras
previamente entrenadas

El modelo rápidamente comienza a sobreajustarse, lo que no sorprende dada la


pequeña cantidad de muestras de entrenamiento. La precisión de la validación tiene
una variación alta por la misma razón, pero parece alcanzar los 50 altos.
Tenga en cuenta que su kilometraje puede variar: debido a que tiene muy pocas
muestras de entrenamiento, el rendimiento depende en gran medida de las 200 muestras
exactas que elija, y las está eligiendo al azar. Si esto no le funciona bien, intente elegir
un conjunto aleatorio diferente de 200 muestras, por el bien del ejercicio (en la vida real,
no puede elegir sus datos de entrenamiento).
También puede entrenar el mismo modelo sin cargar las incrustaciones de
palabras previamente entrenadas y sin congelar la capa de incrustación. En ese caso,
aprenderá una incrustación específica de la tarea de los tokens de entrada, que
generalmente es más poderosa que las incrustaciones de palabras entrenadas
previamente cuando hay muchos datos disponibles. Pero en este caso, solo tiene 200
muestras de capacitación. Probemos (ver figuras 6.7 y 6.8).

Listado 6.16 Entrenando el mismo modelo sin incrustaciones de palabras preentrenadas

de keras.models import Secuencial


de keras.layers import Embedding, Flatten, Dense
modelo = Secuencial()
modelo.add(Embedding(max_words, embedding_dim,
input_length=maxlen)) model.add(Flatten())
modelo.add(Dense(32, activación='relu'))
modelo.add(Dense(1,
activación='sigmoid')) modelo.resumen()

modelo.compilar(optimizador='rmsprop',
loss='binary_crossentropy',métricas=['a
cc'])
historia = modelo.ajuste(x_tren, y_tren,
épocas=10,
tamaño_lote=32
,
validación_datos=(x_val, y_val))

Con licencia para


194 CPASADO 6Aprendizaje profundopara texto y secuencias

Figura 6.7 Pérdida de


capacitación y validación sin
usar incrustaciones de
palabras preentrenadas

Figura 6.8 Precisión de


entrenamiento y validación sin
usar
preentrenamientoincrustaciones
de palabras

La precisión de la validación se detiene en los 50 bajos. Entonces, en este caso, las


incrustaciones de palabras preentrenadas superan a las incrustaciones aprendidas
conjuntamente. Si aumenta el número de muestras de entrenamiento, esto dejará de
ser el caso rápidamente; pruébelo como un ejercicio.
Finalmente, evalúemos el modelo en los datos de prueba. Primero, necesita tokenizar
los datos de prueba.

Listado 6.17 Tokenización de los datos del conjunto de prueba

prueba_dir = os.path.join(imdb_dir, 'prueba')

etiquetas =
[] textos =
[]
para label_type en ['neg', 'pos']:
dir_name = os.path.join(test_dir, label_type)
for fname in sorted(os.listdir(dir_name)):
if fnombre[-4:] == '.txt':
f = open(os.path.join(dir_name, fname))
Con licencia para
textos.append(f.read())

Con licencia para


Trabajar con textodatos 195

f.cerrar()
if label_type == 'neg':
etiquetas.append(0)
más:
etiquetas.append(1)

secuencias =
tokenizer.texts_to_sequences(textos) x_test =
pad_sequences(secuencias, maxlen=maxlen) y_test
= np.asarray(etiquetas)

A continuación, cargue y evalúe el primer modelo.

Listado 6.18 Evaluando el modelo en la pruebaestablecer

modelo.load_weights('pre_trained_glove_model.h5')modelo.evaluar(x
_test, y_test)

Obtiene una precisión de prueba espantosa del 56%. ¡Trabajar con solo un puñado de
muestras de entrenamiento es difícil!

6.1.4 Terminando
Ahora puedes hacer lo siguiente:
◾ Convierta texto sin procesar en algo que una red neuronal pueda procesar
◾ Utilizar elincrustacióncapa en un modelo de Keras para aprender incrustaciones
de tokens específicos de tareas
◾ Use incrustaciones de palabras previamente entrenadas para obtener un
impulso adicional en pequeños problemas de procesamiento de lenguaje
natural

Con licencia para


196 CPASADO 6Aprendizaje profundopara texto y secuencias

6.2 Comprender las redes neuronales recurrentes


Una característica importante de todas las redes neuronales que ha visto hasta ahora,
como las redes y los convnets densamente conectados, es que no tienen memoria.
Cada entrada que se les muestra se procesa de forma independiente, sin que se
mantenga ningún estado entre las entradas. Con este tipo de redes, para procesar una
secuencia o una serie temporal de puntos de datos, debe mostrar la secuencia
completa a la red a la vez: convertirla en un solo punto de datos. Por ejemplo, esto
es lo que hizo en el ejemplo de IMDB: una reseña completa de una película se
transformó en un solo vector grande y se procesó de una sola vez. Estas redes se
denominan redes feedforward.
Por el contrario, mientras lee la oración actual, la procesa palabra por palabra, o
más bien, sacada ocular por sacada ocular, mientras guarda recuerdos de lo que vino
antes; esto le da una representación fluida del significado transmitido por esta
oración. La inteligencia biológica procesa la información de manera incremental
mientras mantiene un modelo interno de lo que está procesando, construido a partir
de información pasada y constantemente actualizado a medida que ingresa nueva
información.
Una red neuronal recurrente (RNN) adopta el mismo principio, aunque en una
versión extremadamente simplificada: procesa secuencias iterando a través de los
elementos de secuencia y manteniendo un estado que contiene información relativa Produ
a lo que ha visto hasta ahora. En efecto, una RNN es un cción

tipo de red neuronal que tiene un bucle interno (ver


figura 6.9). El estado de la RNN se restablece entre el RNN
Conexión
procesamiento de dos secuencias diferentes e recurrente
independientes (como dos revisiones diferentes de
IMDB), por lo que aún considera una secuencia como Apor
te
un único punto de datos: una única entrada a la red.
Qué
cambios es que este punto de datos ya no se procesa en Figura 6.9 Una red
un solo paso; más bien, la red realiza un bucle interno recurrente: una red con un
sobre elementos de secuencia. bucle
Para aclarar estas nociones de bucle y estado, implementemos el pase hacia adelante
de un RNN de juguete en Numpy. Este RNN toma como entrada una secuencia de
vectores, que codificaráscomo un tensor 2D de tamaño (timesteps, input_features). Recorre
los pasos de tiempo y, en cada paso de tiempo, considera su estado actual en t y la entrada en
t (de forma (entrada_características), y los combina para obtener la salida en t. Luego
establecerá el estado para el el siguiente paso será esta salida anterior. Para el primer paso de
tiempo, la salida anterior no está definida; por lo tanto, no hay un estado actual. Entonces,
inicializará el estado como un vector todo cero llamado estado inicial de la red. .
En pseudocódigo, este es el RNN.

Listado 6.19 PseudocódigoRNN

estado_t = 0 El estado en t
para input_t en Itera sobre elementos de secuencia
input_sequence:
salida_t = f(entrada_t, estado_t)
Con licencia para
estado_t = La salida anterior se convierte en el estado para la siguiente iteración.
salida_t

Con licencia para


Comprensión de las neuronas recurrentesredes 197

Incluso puede desarrollar la función f: la transformación de la entrada y el estado en


una salida estará parametrizada por dos matrices, W y U, y un vector de
polarización. Es similar a la transformación operada por una capa densamente
conectada en una red de avance.

Listado 6.20 Pseudocódigo más detallado para la RNN

estado_t = 0
para input_t en input_sequence:
salida_t = activación(punto(W, entrada_t) + punto(U,
estado_t) + b) estado_t = salida_t

Para hacer estas nociones absolutamente inequívocas, escribamos una implementación


ingenua de Numpy del paso hacia adelante del RNN simple.

Listado 6.21 Implementación numpy de un RNN simple

Número de pasos de Dimensionalidad del


tiempo en la secuencia de espacio de características
entrada de entrada Datos de entrada:
importar numpy como ruido aleatorio por
np el bien del ejemplo
Dimensionalidad del
intervalos de tiempo espacio de
= 100 características de Estado inicial: un
características_de_e salida
ntrada = 32
características_sali
da = 64
entradas = np.random.random((timesteps, vector todo cero
input_features)) state_t =
np.zeros((output_features,))
Crea matrices
W = np.random.random((output_features, input_features)) de peso
U = np.random.random((output_features, output_features)) aleatorio
b = np.random.random((output_features,))
input_t es un vector de
sucesivas_salidas = [] forma (entrada_características,).
para input_t en
entradas:
salida_t = np.tanh(np.punto(W, entrada_t) + np.punto(U,
estado_t) + b) salidas_sucesivas.append(salida_t)

estado_t = salida_t
final_output_sequence = np.concatenate(successive_outputs, eje=0)

Almacena esta salida en una lista El resultado final es un tensor de


forma 2D (pasos de tiempo,
Combina la entrada con el estado características de salida).
actual (la salida anterior) para
obtener la salida actual Actualiza el estado de la
red para el próximo paso de
tiempo

Bastante fácil: en resumen, un RNN es un bucle for que reutiliza las cantidades
calculadas durante la iteración anterior del bucle, nada más. Por supuesto, hay muchos
Con licencia para
RNN diferentes que se ajustan a esta definición que podría crear; este ejemplo es una de
las formulaciones de RNN más simples. Las RNN se caracterizan por su función
escalonada, como en este caso la siguiente función (ver figura 6.10):
salida_t = np.tanh(np.punto(W, entrada_t) + np.punto(U, estado_t) + b)

Con licencia para


198 CPASADO 6Aprendizaje profundopara texto y secuencias

producciónsalida t-1 salida t+1

salida_t =
activación
... ( ...
Estad W•entrada_ Estado
ot t+ t+1
U•estado_t
+ bo)

aportet-1 entrada tin entrada t+1

Figura 6.10 Un RNN simple, desenrollado en el tiempo

NOTAEn este ejemplo, la salida final es un tensor de forma 2D (pasos de


tiempo, características de salida), donde cada paso de tiempo es la salida del
bucle en el tiempo t. Cada paso de tiempo t en el tensor de salida contiene
información sobre los pasos de tiempo 0 a t en la secuencia de entrada, sobre
todo el pasado. Por esta razón, en muchos casos, no necesita esta secuencia
completa de salidas; solo necesita la última salida (output_t al final del ciclo),
porque ya contiene información sobre toda la secuencia.

6.2.1 Una capa recurrente en Keras


El proceso que acabas de implementar ingenuamente en Numpy corresponde a una capa
real de Keras: la capa SimpleRNN:
desde keras.layers importar SimpleRNN

Hay una pequeña diferencia:SimpleRNNprocesa lotes de secuencias, como todas las


demás capas de Keras, no una sola secuencia como en el ejemplo de Numpy. Esto
significa que toma entradas de forma (batch_size, timesteps, input_features),
más bien que(pasos de tiempo, input_features).
Como todas las capas recurrentes en Keras, SimpleRNNse puede ejecutar en dos
modos diferentes: puede devolver las secuencias completas de salidas sucesivas para
cada paso de tiempo (un3Dten- sor de forma(batch_size, timesteps,
output_features)) o solo la última salida paracada secuencia de entrada (un tensor 2D de
forma(tamaño_de_lote, características_de_salida)). Estos dos modos están
controlados por elvolver_secuenciasargumento del constructor. Veamos un ejemplo
que utilizaSimpleRNNy devuelve solo la salida en el último paso de tiempo:
>>> desde keras.models import Secuencial
>>> desde keras.layers import Incrustación, SimpleRNN
>>> modelo = Secuencial()
>>> modelo.add(Incrustación(10000, 32))
>>> modelo.añadir(SimpleRNN(32))
>>> modelo.resumen()

Con licencia para


Comprensión de las neuronas recurrentesredes 199

Capa(tipo)Salida ShapeParam #
================================================== ==============
embedding_22 (Incrustación) (Ninguno, Ninguno, 320000
32)
simplernn_10 (SimpleRNN) (Ninguno, 32) 2080
================================================== ==============
Parámetros totales: 322.080
Parámetros entrenables: 322,080
Parámetros no entrenables: 0

El siguiente ejemplo devuelve la secuencia de estado completa:


>>> modelo = Secuencial()
>>> modelo.add(Incrustación(10000, 32))
>>> modelo.add(SimpleRNN(32, return_sequences=True))
>>> modelo.resumen()

Capa(tipo)Salida ShapeParam #
================================================== ==============
embedding_23 (Incrustación) (Ninguno, Ninguno, 320000
32)
simplernn_11 (SimpleRNN) (Ninguno, Ninguno, 2080
32)
================================================== ==============
Parámetros totales: 322.080
Parámetros entrenables: 322,080
Parámetros no entrenables: 0

A veces es útil apilar varias capas recurrentes una tras otra para aumentar el poder
de representación de una red. En tal configuración, debe obtener todas las capas
intermedias para devolver la secuencia completa de salidas:
>>> modelo = Secuencial()
>>> modelo.add(Incrustación(10000, 32))
>>> modelo.add(SimpleRNN(32, return_sequences=True))
>>> modelo.add(SimpleRNN(32, return_sequences=True))
>>> modelo.add(SimpleRNN(32, return_sequences=True)) La última capa solo
>>> modelo.añadir(SimpleRNN(32)) devuelve la última salida
>>> modelo.resumen()

Capa(tipo)Salida ShapeParam #
================================================== ==============
embedding_24 (Incrustación) (Ninguno, Ninguno, 320000
32)
simplernn_12 (SimpleRNN) (Ninguno, Ninguno, 2080
32)
simplernn_13 (SimpleRNN) (Ninguno, Ninguno, 2080
32)
simplernn_14 (SimpleRNN) (Ninguno, Ninguno, 2080
32)
simplernn_15 (SimpleRNN) (Ninguno, 32) 2080
================================================== ==============
Parámetros totales: 328,320
Parámetros entrenables: 328,320
Parámetros no entrenables: 0

Con licencia para


200 CPASADO 6Aprendizaje profundopara texto y secuencias

Ahora, usemos un modelo de este tipo en el problema de clasificación de reseñas de


películas de IMDB. Primero, preprocesar los datos.

Listado 6.22 Preparando la IMDBdatos

desde keras.datasets importar imdb


de la secuencia de importación de Númerode palabras
keras.preprocessing
a considerar como
max_features = 10000 características
maxlen = 500
Corta los textos después de esta cantidad de
tamaño_lote = 32 palabras (entre las palabras más comunes de
imprimir('Cargando max_features)
datos...')
(input_train, y_train), (input_test, y_test) =
imdb.load_data(num_words=max_features)
print(len(input_train), 'secuencias de
entrenamiento') print(len(input_test),
'secuencias de prueba')
print('Secuencias de pad (muestras x tiempo)')
input_train = secuencia.pad_sequences(input_train,
maxlen=maxlen) input_test = secuencia.pad_sequences(input_test,
maxlen=maxlen) print('input_train forma:', input_train.shape)
imprimir ('forma de entrada_prueba:', entrada_prueba.forma)

Entrenemos una red recurrente simple usando un incrustacióncapa y unaSimpleRNN


capa.

Listado 6.23 Entrenando el modelo conincrustaciónySimpleRNNcapas

de keras.layers import
Densemodelo = Secuencial()
modelo.add(Incrustación(max_features,
32))modelo.add(SimpleRNN(32))
modelo.add(Dense(1,
activación='sigmoide'))

model.compile(optimizador='rmsprop', pérdida='binary_crossentropy',
métricas=['acc'])historia = modelo.fit(entrada_tren, y_tren,
épocas=10,
tamaño_lote=128,
división_validación=0.
2)

Ahora, mostremos la pérdida y la precisión del entrenamiento y la validación (consulte las figuras
6.11 y 6.12).

Listado 6.24 Trazadoresultados

importar matplotlib.pyplot como plt


acc = historia.historia['acc']
val_acc = historia.historia['val_acc']
pérdida = historia.historia['pérdida']
val_pérdida =
historia.historia['val_pérdida']

Con licencia para


épocas = rango (1, len (acc) + 1)

plt.plot(epochs, acc, 'bo', label='Training acc')


plt.plot(epochs, val_acc, 'b', label='Validation acc')

Con licencia para


Comprensión de las neuronas recurrentesredes 201

plt.title('Precisión de entrenamiento y
validación') plt.legend()

plt.figura()

plt.plot(épocas, pérdida, 'bo', label='Pérdida de


entrenamiento') plt.plot(epochs, val_loss, 'b',
label='Pérdida de validación') plt.title('Pérdida de
entrenamiento y validación')
plt.leyenda(
)plt.mostrar
()

Figura 6.11 Entrenamiento y


validaciónpérdida en IMDB
conSimpleRNN

Figura 6.12 Entrenamiento y


validaciónprecisión en IMDB
conSimpleRNN

Como recordatorio, en el capítulo 3, el primer enfoque ingenuo de este conjunto de


datos le permitió obtener una precisión de prueba del 88 %. Desafortunadamente,
esta pequeña red recurrente no funciona bien en comparación con esta línea de base
(solo un 85 % de precisión de validación). Parte del problema es que sus entradas
solo consideran las primeras 500 palabras, en lugar de secuencias completas; por lo
tanto, la RNN tiene acceso a menos información que el modelo de referencia

Con licencia para


anterior. El resto del problema es que SimpleRNN no es bueno para procesar
secuencias largas, como texto.

Con licencia para


202 CPASADO 6Aprendizaje profundopara texto y secuencias

Otros tipos de capas recurrentes funcionan mucho mejor. Veamos algunas capas
más avanzadas.

6.2.2 Comprender las capas LSTM y GRU


SimpleRNN no es la única capa recurrente disponible en Keras. Hay
otros dos: LSTM y GRU. En la práctica, siempre usará uno de
estos, porque SimpleRNN generalmente es demasiado simplista para
ser de uso real. SimpleRNN tiene un problema importante: aunque
teóricamente debería ser capaz de retener en el momento t
información sobre las entradas vistas muchos pasos de tiempo
antes, en la práctica, tales dependencias a largo plazo son
imposibles de aprender. Esto se debe al problema del gradiente
que se desvanece, un efecto similar al que se observa con las
redes no recurrentes (redes feedforward) que tienen muchas capas
de profundidad: a medida que agrega capas a una red, la red
eventualmente se vuelve imposible de entrenar. Las razones
teóricas de este efecto fueron estudiadas por Hochreiter,
Schmidhuber y Bengio a principios de la década de 1990.2 Las
capas LSTM y GRU están diseñadas para resolver este problema.
Consideremos la capa LSTM. El algoritmo subyacente de memoria a corto plazo
(LSTM) fue desarrollado por Hochreiter y Schmidhuber en 1997;3 fue la culminación
de su investigación sobre el problema del gradiente de fuga.
Esta capa es una variante de la capa SimpleRNN que ya conoce; agrega una forma de
transportar información a través de muchos pasos de tiempo. Imagine una cinta
transportadora que corre paralela a la secuencia que está procesando. La información de la
secuencia puede saltar a la cinta transportadora en cualquier punto, ser transportada a un
paso de tiempo posterior y saltar, intacta, cuando la necesite. Esto es esencialmente lo que
hace LSTM: guarda información para más tarde, evitando así que las señales más antiguas
desaparezcan gradualmente durante el procesamiento.
Para entender esto en detalle, comencemos desde la celda SimpleRNN (ver figura
6.13). Debido a que tendrá muchas matrices de peso, indexe las matrices W y U en la
celda con la letra o (Wo y Uo) para la salida.

producciónsalida t-1 salida t+1

salida_t =
activación
... ( ...
Estad Wo•input_t+ Estado
ot Uo•estado_t t+1
+ bo)

aportet-1 entrada tin entrada t+1

Figura 6.13 El punto de partida de unLSTMcapa: unaSimpleRNN

2 Véase, por ejemplo, Yoshua Bengio, Patrice Simard y Paolo Frasconi, "Learning Long-Term Dependencies with Gradient Descent Is Difficult", IEEE Transactions on

Con licencia para


Neural Networks 5, no. 2 (1994).
3 Sepp Hochreiter y Jürgen Schmidhuber, “Long Short-Term Memory”, Neural Computation 9, no. 8 (1997).

Con licencia para


Comprensión de las neuronas recurrentesredes 203

Agreguemos a esta imagen un flujo de datos adicional que transporta información a


través de pasos de tiempo. Llame a sus valores en diferentes intervalos de tiempo
Ct, donde C significa acarreo. Esta información tendrá el siguiente impacto en la
celda: se combinará con la conexión de entrada y la conexión recurrente (a través de
una transformación densa: un producto escalar con una matriz de peso seguido de
una suma de polarización y la aplicación de una función de activación). - ción), y
afectará el estado que se envía al siguiente paso de tiempo (a través de una función
de activación y una operación de multiplicación). Conceptualmente, el flujo de
datos de acarreo es una forma de modular la siguiente salida y el siguiente estado
(ver figura 6.14). Sencillo hasta ahora.

producciónsalida t-1 salida t+1

c t-1 C c t+1 Llevar


on pista
ne
cti
cu
t C salida_t = C
on activación on
ne ( ne
... cti Wo•entrada cti ...
Estadcu Estadocu
_t +
ot t t+1 t
Uo•estado_t
+ Vo•c_t +
bo)

aportet-1 entrada tin entrada t+1

Figura 6.14 pasando de unSimpleRNNa unaLSTM: agregar una pista de acarreo

Ahora la sutileza: la forma en que se calcula el siguiente valor del flujo de datos de
acarreo. Implica tres transformaciones distintas. Los tres tienen la forma de una celda
SimpleRNN:
y = activación(punto(estado_t, U) + punto(entrada_t, W) + b)

Pero las tres transformaciones tienen sus propias matrices de ponderación, que
indexará con las letras i, f y k. Esto es lo que tienes hasta ahora (puede parecer un
poco arbitrario, pero ten paciencia conmigo).

Listado 6.25 Detalles de pseudocódigo de la arquitectura LSTM(1/2)

salida_t = activación(punto(estado_t, Uo) + punto(entrada_t, Wo) + punto(C_t, Vo) +


bo)

i_t = activación(punto(estado_t, Ui) + punto(entrada_t,


Wi) + bi) f_t = activación(punto(estado_t, Uf) +
punto(entrada_t, Wf) + bf) k_t =
activación(punto(estado_t, Reino Unido) + punto
(entrada_t, semana) + fondo)

Obtiene el nuevo estado de acarreo (el siguiente c_t) combinando i_t, f_t y k_t.

Listado 6.26 Detalles de pseudocódigo de la arquitectura LSTM(2/2)

c_t+1 = i_t * k_t + c_t * f_t

Con licencia para


Agregue esto como se muestra en la figura 6.15. Y eso es. No tan complicado,
simplemente un poco complejo.

Con licencia para


204 CPASADO 6Aprendizaje profundopara texto y secuencias

producciónsalida t-1 salida t+1

c t-1 C c t+1 Llevar


Calcular on Calcular pista
nuevo ne nuevo
acarre cti acarre
o cu o
t C salida_t = C
on activación on
ne ( ne
... cti Wo•entrada cti ...
Estad Estado
cu _t + cu
ot t+1
t Uo•estado_t t
+ Vo•c_t +
bo)

aportet-1 entrada tin entrada t+1

Figura 6.15 Anatomía de unLSTM

Si quiere ponerse filosófico, puede interpretar lo que se supone que haga cada una
de estas operaciones. Por ejemplo, puede decir que multiplicar c_t y f_t es una
forma de olvidar deliberadamente información irrelevante en el flujo de datos de
acarreo. Mientras tanto, i_t y k_t brindan información sobre el presente,
actualizando la pista de acarreo con nueva información. Pero al final del día, estas
interpretaciones no significan mucho, porque lo que realmente hacen estas
operaciones está determinado por los contenidos de los pesos que las parametrizan;
y los pesos se aprenden de punta a punta, comenzando de nuevo con cada ronda de
entrenamiento, lo que hace imposible acreditar tal o cual operación con un propósito
específico. La especificación de una celda RNN (como se acaba de describir)
determina su espacio de hipótesis, el espacio en el que buscará una buena
configuración de modelo durante el entrenamiento, pero no determina lo que hace la
celda; eso depende de los pesos de las celdas. La misma celda con diferentes pesos
puede estar haciendo cosas muy diferentes. Entonces, la combinación de
operaciones que componen una celda RNN se interpreta mejor como un conjunto de
restricciones en su búsqueda, no como un diseño en un sentido de ingeniería.
Para un investigador, parece que la elección de tales restricciones, la cuestión de
cómo implementar las células RNN, es mejor dejarla en manos de los algoritmos de
optimización (como los algoritmos genéticos o los procesos de aprendizaje por refuerzo)
que en los ingenieros humanos. Y en el futuro, así construiremos redes. En resumen: no
necesita comprender nada sobre la arquitectura específica de una celda LSTM; como
humano, no debería ser tu trabajo entenderlo. Solo tenga en cuenta lo que la celda
LSTM está destinada a hacer: permitir que la información pasada se reinyecte en un
momento posterior, combatiendo así el problema del gradiente de fuga.

6.2.3 Un ejemplo concreto de LSTM en Keras


Ahora pasemos a asuntos más prácticos: configurará un modelo usando una capa LSTM
y lo entrenará en los datos de IMDB (vea las figuras 6.16 y 6.17). La red es similar a
launo con SimpleRNN que se acaba de presentar. Solo especifica la dimensionalidad de
salida de la capa LSTM; deja cualquier otro argumento (hay muchos) en el Keras

Con licencia para


Comprensión de las neuronas recurrentesredes 205

valores predeterminados Keras tiene buenos valores predeterminados, y las cosas casi
siempre "simplemente funcionarán" sin tener que dedicar tiempo a ajustar los
parámetros a mano.

Listado 6.27 Usando elLSTMcapa en Keras

de keras.layers importar

modelo LSTM = Sequential()


modelo.add(Embedding(max_features,
32)) modelo.add(LSTM(32))
modelo.add(Dense(1, activación='sigmoide'))
modelo.compilar(optimizador='rmsprop',
loss='binary_crossentropy',métri
cas=['acc'])
historia = modelo.fit(entrada_tren, y_tren,
épocas=10,
tamaño_lote=128,
división_validación=0.2)

Figura 6.16 Entrenamiento y


validaciónpérdida en IMDB con LSTM

Figura 6.17 Entrenamiento y


validaciónprecisión en IMDB con LSTM

Con licencia para


206 CPASADO 6Aprendizaje profundopara texto y secuencias

Esta vez, logra una precisión de validación de hasta el 89 %. No está mal: ciertamente
mucho mejor que la red SimpleRNN, en gran parte porque LSTM sufre mucho menos
del problema del gradiente de fuga, y un poco mejor que el enfoque completamente
conectado del capítulo 3, a pesar de que está viendo menos datos de los que estaba.
capítulo 3. Estás truncando secuencias después de 500 pasos de tiempo, mientras que en
el capítulo 3, estabas considerando secuencias completas.
Pero este resultado no es innovador para un enfoque tan computacionalmente
intensivo. ¿Por qué LSTM no funciona mejor? Una de las razones es que no hizo ningún
esfuerzo por ajustar hiperparámetros como la dimensionalidad de incrustaciones o la
dimensionalidad de salida de LSTM. Otro puede ser la falta de regularización. Pero,
sinceramente, la razón principal es que analizar la estructura global a largo plazo de las
revisiones (en qué es bueno LSTM) no es útil para un problema de análisis de
sentimientos. Este problema básico se resuelve bien observando qué palabras aparecen
en cada reseña y con qué frecuencia. Eso es lo que analizó el primer enfoque totalmente
conectado. Pero existen problemas de procesamiento de lenguaje natural mucho más
difíciles, donde la fuerza de LSTM se hará evidente: en particular, la respuesta a
preguntas y la traducción automática.

6.2.4 Terminando
Ahora entiendes lo siguiente:
◾ QuéRNNs son y cómo funcionan
◾ QuéLSTMes, y por qué funciona mejor en secuencias largas que en una ingenua RNN
◾ Cómo usar KerasRNNcapas para procesar datos de secuencia

A continuación, revisaremos una serie de características más avanzadas de RNN,


que pueden ayudarlo a aprovechar al máximo sus modelos de secuencia de
aprendizaje profundo.

Con licencia para


Uso avanzado de neural recurrenteredes 207

6.3 Uso avanzado de redes neuronales recurrentes


En esta sección, revisaremos tres técnicas avanzadas para mejorar el rendimiento y
el poder de generalización de las redes neuronales recurrentes. Al final de la
sección, sabrá la mayor parte de lo que hay que saber sobre el uso de redes
recurrentes con Keras. Demostraremos los tres conceptos en un problema de
pronóstico de temperatura, donde tiene acceso a una serie temporal de puntos de
datos provenientes de sensores instalados en el techo de un edificio, como la
temperatura, la presión del aire y la humedad, que utiliza para predecir cuál será la
temperatura 24 horas después del último punto de datos. Este es un problema
bastante desafiante que ejemplifica muchas dificultades comunes que se encuentran
cuando se trabaja con series de tiempo.
Cubriremos las siguientes técnicas:
◾ Abandono recurrente—Esta es una forma específica e integrada de usar la omisión
para combatir el sobreajuste en capas recurrentes.
◾ Apilar capas recurrentes—Esto aumenta el poder de representación de la red (a
costa de mayores cargas computacionales).
◾ Capas recurrentes bidireccionales—Estos presentan la misma información a una
red recurrente de diferentes maneras, lo que aumenta la precisión y mitiga los
problemas de olvido.

6.3.1 Un problema de pronóstico de temperatura


Hasta ahora, los únicos datos de secuencia que hemos cubierto han sido datos de texto,
como el conjunto de datos de IMDB y el conjunto de datos de Reuters. Pero los datos de
secuencia se encuentran en muchos más problemas además del procesamiento del
lenguaje. En todos los ejemplos de esta sección, jugará con un conjunto de datos
meteorológicos de series temporales registrado en la estación meteorológica del
Instituto Max Planck de biogeoquímica en Jena, Alemania.4
En este conjunto de datos, se registraron 14 cantidades diferentes (como la
temperatura del aire, la presión atmosférica, la humedad, la dirección del viento,
etc.) cada 10 minutos, durante varios años. Los datos originales se remontan a 2003,
pero este ejemplo se limita a los datos de 2009 a 2016. Este conjunto de datos es
perfecto para aprender a trabajar con series temporales numéricas. Lo usará para
crear un modelo que tome como entrada algunos datos del pasado reciente (puntos
de datos de algunos días) y prediga la temperatura del aire dentro de 24 horas.
Descargar y descomprimir los datoscomo sigue:
cd ~/Descargas
mkdir jena_climate
cd jena_climate
wget https://s3.amazonaws.com/keras-datasets/jena_climate_2009_2016.csv.zip
descomprimir jena_climate_2009_2016.csv.zip

Veamos los datos.

4 Olaf Kollé,
www.bgc-jena.mpg.de/wetter.

Con licencia para


208 CPASADO 6Aprendizaje profundopara texto y secuencias

Listado 6.28 Inspeccionando los datos del conjunto de datos meteorológicos de Jena
importar sistema operativo
data_dir = '/usuarios/fchollet/Descargas/jena_climate'
fname = os.path.join(data_dir, 'jena_climate_2009_2016.csv')

f =
abrir(fname)
datos =
f.leer()
f.cerrar()

líneas = data.split('\n')
encabezado =
líneas[0].split(',') líneas =
líneas[1:]

imprimir
(encabezado)
imprimir (largo
(líneas))

Esto genera un recuento de 420 551 líneas de datos (cada línea es un intervalo de
tiempo: un registro de una fecha y 14 valores relacionados con el clima), así como el
siguiente encabezado:
["Fecha y hora",
"p (mbar)",
"T (grados C)",
"Tpot (K)",
"Trocío (grados C)",
"Rh (%)",
"VPmáx (mbar)",
"VPact (mbar)",
"VPdef (mbar)",
"sh (g/kg)",
"H2OC (mmol/mol)",
"rho (g/m**3)",
"vv (m/s)",
"wv máx. (m/s)",
"wd (grados)"]

Ahora, convierta las 420 551 líneas de datos en una matriz Numpy.

Listado 6.29 Analizando eldatos

importar numpy como np

float_data = np.zeros((len(líneas), len(encabezado)


- 1)) para i, línea en enumerar(líneas):
valores = [float(x) for x in
line.split(',')[1:]] float_data[i, :] = valores

Por ejemplo, aquí está la gráfica de la temperatura (en grados Celsius) a lo largo del
tiempo (vea la figura 6.18). En este gráfico, puede ver claramente la periodicidad
anual de la temperatura.

Con licencia para


Uso avanzado de neural recurrenteredes 209

Listado 6.30 Trazado de series temporales de temperatura


desde matplotlib importar pyplot como plt
temp = float_data[:, 1] <1> temperatura (en grados Celsius)
plt.plot(rango(len(temp)), temp)

Figura 6.18 Temperatura en


todo el rango temporal deel
conjunto de datos (ºC)

Aquí hay una gráfica más estrecha de los primeros 10 días de datos de temperatura (ver
figura 6.19). Debido a que los datos se registran cada 10 minutos, obtiene 144 puntos de
datos por día.

Listado 6.31 Trazado de los primeros 10 días de la serie temporal de temperatura

plt.plot(rango(1440), temperatura[:1440])

Figura 6.19 Temperatura


durante los primeros 10
días delconjunto de datos
(ºC)

Con licencia para


210 CPASADO 6Aprendizaje profundopara texto y secuencias

En este gráfico, puede ver la periodicidad diaria, especialmente evidente durante los
últimos 4 días. También tenga en cuenta que este período de 10 días debe provenir de
un mes de invierno bastante frío.
Si estuviera tratando de predecir la temperatura promedio para el próximo mes
dados algunos meses de datos anteriores, el problema sería fácil debido a la
periodicidad confiable de la escala anual de los datos. Pero al observar los datos en
una escala de días, la temperatura parece mucho más caótica. ¿Es esta serie
temporal predecible a escala diaria? Vamos a averiguar.

6.3.2 Preparando los datos


La formulación exacta del problema será la siguiente: datos dados que se remontan
acomo pasos de tiempo retrospectivos (un paso de tiempo es de 10 minutos) y muestreados
cada paso de tiempo, ¿puede predecir la temperatura en pasos de tiempo de retraso?
Utilizará los siguientes valores de parámetro:
◾ retrospectiva = 720—Las observaciones retrocederán 5 días.
◾ pasos = 6—Las observaciones se muestrearán en un punto de datos por hora.
◾ retraso = 144—Objetivosserán 24 horas en el

futuro. Para comenzar, debe hacer dos cosas:


◾ Preprocesar los datos en un formato que una red neuronal pueda ingerir. Esto es
fácil: los datos ya son numéricos, por lo que no es necesario realizar ninguna
vectorización. Pero cada serie de tiempo en los datos está en una escala diferente
(por ejemplo, la temperatura suele estar entre -20 y +30, pero la presión
atmosférica, medida en mbar, es de alrededor de 1000). Normalizará cada serie
temporal de forma independiente para que todas tomen valores pequeños en una
escala similar.
◾ Escriba un generador de Python que tome la matriz actual de datos flotantes y
produzca lotes de datos del pasado reciente, junto con una temperatura
objetivo en el futuro. Debido a que las muestras en el conjunto de datos son
altamente redundantes (la muestra N y la muestra N + 1 tendrán la mayoría de
sus intervalos de tiempo en común), sería un desperdicio asignar
explícitamente cada muestra. En su lugar, generará las muestras sobre la
marcha utilizando los datos originales.
Preprocesará los datos restando la media de cada serie temporal y dividiéndola por
la desviación estándar. Vas a utilizar los primeros 200 000 intervalos de tiempo
como datos de entrenamiento, así que calcula la media y la desviación estándar solo
en esta fracción de los datos.

Listado 6.32 Normalizando los datos

media =
datos_flotantes[:200000].media(eje=0)
datos_flotantes -= media
estándar =
datos_flotantes[:200000].std(eje=0)
datos_flotantes /= estándar

Con licencia para


El listado 6.33 muestra el generador de datos que usará. Produce una tupla (muestras,
objetivos), donde muestras es un lote de datos de entrada y objetivos es la matriz
correspondiente de temperaturas objetivo. Toma los siguientes argumentos:

Con licencia para


Uso avanzado de neural recurrenteredes 211

◾ datos—La matriz original de datos de coma flotante, que normalizó en el listado 6.32.
◾ mirar atrás: cuántos pasos de tiempo deben retroceder los datos de entrada.
◾ demora: cuántos intervalos de tiempo en el futuro debería tener el objetivo.
◾ min_indexymax_index—Índices en eldatosmatriz que delimita de qué pasos de
tiempo se debe extraer. Esto es útil para mantener un segmento de los datos para
validación y otro para prueba.
◾ barajar—Ya sea barajar las muestras o dibujarlas en orden cronológico.
◾ tamaño del lote—El número de muestras por lote.
◾ paso: el período, en intervalos de tiempo, en el que muestrea los datos. Lo
establecerá en 6 para dibujar un punto de datos cada hora.

Listado 6.33 Generador que produce muestras de series temporales y sus objetivos

generador de definición (datos, retrospectiva, retraso,


min_index, max_index, shuffle=False,
batch_size=128, step=6):
si max_index es Ninguno:
max_index = len(datos) - retraso
- 1 i = min_index + retrospectiva
mientras que 1:
si baraja:
filas = np.random.randint(
min_index + retrospectiva, max_index, size=batch_size)
más:
si i + tamaño_lote >=
max_index: i = min_index +
lookback
filas = np.arange(i, min(i + lote_tamaño,
max_index)) i += len(filas)
muestras = np.zeros((len(filas),
retrospectiva //
paso,
data.shape[-1]))
objetivos =
np.zeros((len(filas),)) para j,
fila en enumerar(filas):
índices = rango (filas [j] - retrospectiva, filas
[j], paso) muestras [j] = datos [índices]
objetivos[j] = datos[filas[j] +
retraso][1] muestras de rendimiento,
objetivos

Ahora, usemos la función de generador abstracto para instanciar tres generadores: uno
para entrenamiento, uno para validación y otro para prueba. Cada uno mirará diferentes
segmentos temporales de los datos originales: el generador de entrenamiento mira los
primeros 200 000 pasos de tiempo, el generador de validación mira los siguientes 100
000 y el generador de prueba mira el resto.

Listado 6.34 Preparando los generadores de entrenamiento, validación y prueba

retrospectiva = 1440
paso = 6
retraso = 144
Con licencia para
lote_tamaño = 128

Con licencia para


212 CPASADO 6Aprendizaje profundopara texto y secuencias

tren_gen = generador(float_data,
lookback=lookback,
delay=delay,
min_index=0,
max_index=200000,
shuffle=True,
step=step,
batch_size=batch_size)
val_gen = generador(float_data,
lookback=lookback,
retraso=retraso,
min_index=200001,
max_index=300000,
paso=paso,
tamaño_lote=tamaño_lote)
test_gen = generador (float_data,
lookback=lookback,
delay=retraso, cuantos pasospara dibujar
min_index=300001, desde val_gen para ver todo
max_index=Ninguno, el conjunto de validación
step=step,
batch_size=batch_size)
¿Cuántos pasos dibujar
val_pasos = (300000 - 200001 -mirar atrás)
desde test_gen para
test_steps = (len(float_data) - 300001 - ver todo el conjunto de pruebas
retrospectiva)

6.3.3 Una línea de base de sentido común, sin aprendizaje automático


Antes de comenzar a usar modelos de aprendizaje profundo de caja negra para
resolver el problema de predicción de la temperatura, probemos un enfoque simple
y de sentido común. Servirá como una verificación de cordura y establecerá una
línea de base que tendrá que superar para demostrar la utilidad de los modelos de
aprendizaje automático más avanzados. Estas líneas de base de sentido común
pueden ser útiles cuando se está abordando un problema nuevo para el cual no
existe una solución conocida (todavía). Un ejemplo clásico es el de las tareas de
clasificación desequilibradas, donde algunas clases son mucho más comunes que
otras. Si su conjunto de datos contiene un 90 % de instancias de clase A y un 10 %
de instancias de clase B, entonces un enfoque de sentido común para la tarea de
clasificación es predecir siempre "A" cuando se le presente una nueva muestra. Tal
clasificador tiene una precisión del 90% en general, y, por lo tanto, cualquier
enfoque basado en el aprendizaje debería superar esta puntuación del 90 % para
demostrar su utilidad. A veces, estas líneas de base elementales pueden resultar
sorprendentemente difíciles de superar.
En este caso, se puede suponer con seguridad que las series de tiempo de
temperatura son continuas (es probable que las temperaturas de mañana estén cerca
de las temperaturas de hoy), así como también periódicas con un período diario. Por
lo tanto, un enfoque de sentido común es predecir siempre que la temperatura dentro
de 24 horas será igual a la temperatura en este momento. Evaluemos este enfoque,
utilizando la métrica del error absoluto medio (MAE):
np.mean(np.abs(preds - objetivos))

Con licencia para


Uso avanzado de neural recurrenteredes 213

Aquí está el bucle de evaluación.

Listado 6.35 Cálculo de la línea base de sentido comúnMAE

def
evaluar_método_ingenuo()
: lote_maes = []
para paso en rango (val_steps):
muestras, objetivos = siguiente
(val_gen) preds = muestras [:, -
1, 1]
mae = np.mean(np.abs(preds -
objetivos)) lote_maes.append(mae)
imprimir (np.mean

(batch_maes))evaluar_método_ingenuo()

Esto produce un MAE de 0,29. Debido a que los datos de temperatura se


normalizaron para centrarse en 0 y tener una desviación estándar de 1, este número
no se intercala inmediatamente.pretable Se traduce en un error absoluto promedio de 0,29
× temperatura_std grados Celsius: 2,57˚C.

Listado 6.36 Convirtiendo el MAE de nuevo a Celsiuserror

celsius_mae = 0.29 * std[1]

Ese es un error absoluto promedio bastante grande. Ahora el juego es usar su


conocimiento de aprendizaje profundo para hacerlo mejor.

6.3.4 Un enfoque básico de aprendizaje automático


De la misma manera que es útil establecer una línea de base de sentido común antes
de intentar enfoques de aprendizaje automático, es útil probar modelos de
aprendizaje automático simples y económicos (como redes pequeñas y densamente
conectadas) antes de buscar modelos complicados y computacionalmente costosos.
modelos como RNN. Esta es la mejor manera de asegurarse de que cualquier
complejidad adicional que arroje al problema sea legítima y brinde beneficios
reales.
La siguiente lista muestra un modelo completamente conectado que comienza
aplanando los datos y luego los ejecuta a través de dos capas densas. Tenga en cuenta la
falta de función de activación enla última capa densa, que es típica de un problema de
regresión. Usas MAE como la pérdida. Debido a que evalúa exactamente los mismos datos y
con exactamente la misma métrica que hizo con el enfoque de sentido común, los resultados
serán directamente comparables.

Listado 6.37 Entrenamiento y evaluación de un modelo densamente conectado

de keras.models import Secuencialde


keras importar capas
de keras.optimizers importar RMSprop
modelo = Secuencial()
model.add(layers.Flatten(input_shape=(mirar hacia atrás // paso, float_data.shape[-
1])))modelo.add(capas.Dense(32, activación='relu'))
Con licencia para
modelo.add(capas.Densa(1))

Con licencia para


214 CPASADO 6Aprendizaje profundopara texto y secuencias

modelo.compilar(optimizador=RMSprop(),
pérdida='mae')historia =
modelo.fit_generator(tren_gen,
pasos_por_época=500,
épocas=20,
validación_datos=val_gen,
validación_pasos=val_pasos)

Vamos a mostrar las curvas de pérdida para validación y entrenamiento (ver figura 6.20).

Listado 6.38 Trazadoresultados

importar matplotlib.pyplot como plt

pérdida = historia.historia['pérdida']
val_pérdida =
historia.historia['val_pérdida']

épocas = rango (1, len (pérdida)


+ 1) plt.figure ()

plt.plot(épocas, pérdida, 'bo', label='Pérdida de


entrenamiento') plt.plot(epochs, val_loss, 'b',
label='Pérdida de validación') plt.title('Pérdida de
entrenamiento y validación')
plt.leyenda(
)plt.mostrar
()

Figura 6.20 Entrenamiento y


validaciónpérdida en la tarea de
pronóstico de temperatura de Jena
con una red simple y densamente
conectada

Algunas de las pérdidas de validación están cerca de la línea de base sin


aprendizaje, pero no de manera confiable. Esto demuestra el mérito de tener esta
línea de base en primer lugar: resulta que no es fácil de superar. Su sentido común
contiene mucha información valiosa a la que un modelo de aprendizaje automático
no tiene acceso.
Quizás se pregunte, si existe un modelo simple y de buen rendimiento para pasar de
los datos a los objetivos (la línea base de sentido común), ¿por qué el modelo que está
entrenando no lo encuentra y lo mejora? Porque esta solución simple no es lo que busca
Con licencia para
su equipo de entrenamiento. El espacio de modelos en el que está buscando una
solución, es decir, su espacio de hipótesis, es el espacio de todas las redes de dos capas
posibles con la configuración que definió. Estas redes ya son bastante complicadas.
Cuando estás buscando un

Con licencia para


Uso avanzado de neural recurrenteredes 215

solución con un espacio de modelos complicados, la línea de base simple y de buen


rendimiento puede ser imposible de aprender, incluso si es técnicamente parte del
espacio de hipótesis. Esa es una limitación bastante significativa del aprendizaje
automático en general: a menos que el algoritmo de aprendizaje esté codificado para
buscar un tipo específico de modelo simple, el aprendizaje de parámetros a veces puede
no encontrar una solución simple a un problema simple.

6.3.5 Una primera línea de base recurrente


El primer enfoque totalmente conectado no funcionó bien, pero eso no significa que
el aprendizaje automático no sea aplicable a este problema. El enfoque anterior
primero aplanó las series temporales, lo que eliminó la noción de tiempo de los
datos de entrada. En cambio, veamos los datos como lo que son: una secuencia,
donde la causalidad y el orden son importantes. Probarás un modelo de
procesamiento de secuencias recurrentes; debería encajar perfectamente con dichos
datos de secuencias, precisamente porque explota el ordenamiento temporal de los
puntos de datos, a diferencia del primer enfoque.
En lugar de la capa LSTM presentada en la sección anterior, utilizará la capa GRU,
desarrollada por Chung et al. en 2014.5 Las capas de unidades recurrentes cerradas
(GRU) funcionan con el mismo principio que LSTM, pero son un tanto simplificadas y,
por lo tanto, más baratas de ejecutar (aunque es posible que no tengan tanto poder de
representación como LSTM). Esta compensación entre el costo computacional y el
poder de representación se ve en todas partes en el aprendizaje automático.

Listado 6.39 Entrenamiento y evaluación de un modelo basado en GRU

desde keras.models importa


Secuencial desde keras importa
capas
de keras.optimizers importar RMSprop
modelo = Secuencial()
model.add(layers.GRU(32, input_shape=(Ninguno, float_data.shape[-
1]))) model.add(layers.Dense(1))
model.compile(optimizer=RMSprop(), loss='mae')
history = model.fit_generator(train_gen,
pasos_por_época=500,
épocas=20,
validación_datos=val_gen,
validación_pasos=val_pasos)

La Figura 6.21 muestra los resultados. ¡Mucho mejor! Puede superar


significativamente la línea de base del sentido común, lo que demuestra el valor del
aprendizaje automático, así como la superioridad de las redes recurrentes en
comparación con las redes densas de aplanamiento de secuencias en este tipo de
tarea.

5 Junyoung Chung et al., “Emplirical Evaluation of Gated Recurrent Neural Networks on Sequence Modeling,” Conferencia
en Neural Información
Con licencia para
Procesando Sistemas(2014), https://arxiv.org/abs/1412.3555.

Con licencia para


216 CPASADO 6Aprendizaje profundopara texto y secuencias

Figura 6.21 Entrenamiento y


validaciónpérdida en la tarea de
pronóstico de temperatura de Jena
con una GRU

La nueva validación MAE de ~0,265 (antes de que comience a sobreajustar


significativamente) se traduce en un error absoluto medio de 2,35 ˚C después de la
desnormalización. Esa es una ganancia sólida en el error inicial de 2.57˚C, pero
probablemente todavía tenga un poco de margen para mejorar.

6.3.6 Uso de la deserción recurrente para combatir el sobreajuste


Es evidente a partir de las curvas de entrenamiento y validación que el modelo se
está sobreajustando: las pérdidas de entrenamiento y validación comienzan a
divergir considerablemente después de algunas épocas. Ya está familiarizado con
una técnica clásica para luchar contra este fenómeno: el abandono, que pone a cero
aleatoriamente las unidades de entrada de una capa para romper las correlaciones
casuales en los datos de entrenamiento a los que está expuesta la capa. Pero cómo
aplicar correctamente el abandono en redes recurrentes no es una pregunta trivial.
Hace tiempo que se sabe que aplicar el abandono antes de una capa recurrente
dificulta el aprendizaje en lugar de ayudar con la regularización. En 2015, Yarin
Gal, como parte de su tesis doctoral sobre aprendizaje profundo bayesiano,6
determinó la forma adecuada de utilizar el abandono con una red recurrente: se debe
aplicar la misma máscara de abandono (el mismo patrón de unidades eliminadas) en
todo momento. - paso, en lugar de una máscara de abandono que varía
aleatoriamente de un período de tiempo a otro. Además, para regularizar las
representaciones formadas por las puertas recurrentes de capas como GRU y LSTM,
se debe aplicar una máscara de abandono temporalmente constante a las
activaciones recurrentes internas de la capa (una máscara de abandono recurrente).
El uso de la misma máscara de abandono en cada paso de tiempo permite que la red
propague correctamente su error de aprendizaje a lo largo del tiempo; una máscara
de abandono temporalmente aleatoria interrumpiría esta señal de error y sería
perjudicial para el proceso de aprendizaje. El uso de la misma máscara de abandono

Con licencia para


en cada paso de tiempo permite que la red propague correctamente su error de
aprendizaje a lo largo del tiempo; una máscara de abandono temporalmente
aleatoria interrumpiría esta señal de error y sería perjudicial para el proceso de
aprendizaje. El uso de la misma máscara de abandono en cada paso de tiempo
permite que la red propague correctamente su error de aprendizaje a lo largo del
tiempo; una máscara de abandono temporalmente aleatoria interrumpiría esta señal
de error y sería perjudicial para el proceso de aprendizaje.
Yarin Gal hizo su investigación usando Keras y ayudó a construir este
mecanismo directamente en las capas recurrentes de Keras. Cada capa recurrente en
Keras tiene dos argumentos relacionados con el abandono: abandono, un flotante
que especifica la tasa de abandono para las unidades de entrada de la capa,

6
Consulte Yarin Gal, "Uncertainty in Deep Learning (PhD Thesis)", 13 de octubre de 2016,http://mlg.eng.cam.ac.uk/
yarin/blog_2248.html.

Con licencia para


Uso avanzado de neural recurrenteredes 217

y recurrent_dropout, que especifica la tasa de abandono de las unidades recurrentes.


Agreguemos el abandono y el abandono recurrente a la capa GRU y veamos cómo esto
afecta el sobreajuste. Debido a que las redes que se regularizan con deserción siempre
tardan más en converger por completo, entrenará la red para el doble de épocas.

Listado 6.40 Capacitación y evaluación de un modelo basado en GRU regularizado por deserción

desde keras.models importa


Secuencial desde keras importa
capas
de keras.optimizers importar RMSprop

modelo = Sequential()
modelo.add(capas.GRU(32,
abandono=0.2,
abandono_recurrente=0.2,
input_shape=(Ninguno, float_data.shape[-
1]))) model.add(layers.Dense(1))
model.compile(optimizer=RMSprop(), loss='mae')
history = model.fit_generator(train_gen,
pasos_por_época=500,
épocas=40,
validación_datos=val_gen,
validación_pasos=val_pasos)

La figura 6.22 muestra los resultados. ¡Éxito! Ya no se sobreajusta durante las primeras
30 épocas. Pero aunque tiene puntajes de evaluación más estables, sus mejores puntajes
no son mucho más bajos que antes.

Figura 6.22 Entrenamiento y


validaciónpérdida en la tarea de
pronóstico de temperatura de
Jena con un GRU regularizado por
deserción

6.3.7 Apilar capas recurrentes


Debido a que ya no está sobreajustando pero parece haber encontrado un cuello de
botella en el rendimiento, debe considerar aumentar la capacidad de la red.
Recuerde la descripción del flujo de trabajo de aprendizaje automático universal:
generalmente es una buena idea aumentar la capacidad de su red hasta que el
sobreajuste se convierta en el principal obstáculo (suponiendo que
Con licencia para
218 CPASADO 6Aprendizaje profundopara texto y secuencias

ya está tomando medidas básicas para mitigar el sobreajuste, como el uso de la


deserción). Siempre que no esté sobreajustando demasiado, es probable que esté por
debajo de su capacidad.
El aumento de la capacidad de la red generalmente se realiza aumentando la
cantidad de unidades en las capas o agregando más capas. El apilamiento de capas
recurrentes es una forma clásica de construir redes recurrentes más poderosas: por
ejemplo, lo que actualmente impulsa el algoritmo de Google Translate es una pila de
siete capas LSTM grandes, eso es enorme.
Para apilar capas recurrentes una encima de otra en Keras, todas las capas intermedias
debe devolver su secuencia completa de salidas (un tensor 3D) en lugar de su salida
en el último paso de tiempo. Esto se hace especificando return_sequences=True.

Listado 6.41 Capacitación y evaluación de un modelo GRU apilado regularizado por deserción

desde keras.models importa


Secuencial desde keras importa
capas
de keras.optimizers importar RMSprop
modelo = Sequential()
modelo.add(capas.GRU(32,
abandono=0.1,
abandono_recurrente=0.5,
return_sequences=Verdadero,
input_shape=(Ninguno, float_data.shape[-
1]))) modelo.add(capas.GRU(64, activación='relu',
abandono=0.1,
abandono_recurrente=0.5))
modelo.add(capas.Densa(1))
model.compile(optimizer=RMSprop(), loss='mae')
history = model.fit_generator(train_gen,
pasos_por_época=500,
épocas=40,
validación_datos=val_gen,
validación_pasos=val_pasos)

La Figura 6.23 muestra los resultados. Puede ver que la capa agregada mejora un poco
los resultados, aunque no significativamente. Puedes sacar dos conclusiones:
◾ Debido a que todavía no está sobreajustando demasiado, podría aumentar con
seguridad el tamaño de sus capas en una búsqueda de mejora de la pérdida de
validación. Sin embargo, esto tiene un costo computacional no despreciable.
◾ La adición de una capa no ayudó en gran medida, por lo que es posible que vea
rendimientos decrecientes al aumentar la capacidad de la red en este momento.

Con licencia para


Uso avanzado de neural recurrenteredes 219

Figura 6.23 Entrenamiento y


validaciónpérdida en la tarea de
pronóstico de temperatura de
Jena con una red GRU apilada

6.3.8 Uso de RNN bidireccionales


La última técnica presentada en esta sección se denomina RNN bidireccionales. Un
RNN bidireccional es una variante común de RNN que puede ofrecer un mayor
rendimiento que un RNN regular en ciertas tareas. Se usa con frecuencia en el
procesamiento del lenguaje natural; podría llamarlo la navaja suiza del aprendizaje
profundo para el procesamiento del lenguaje natural.
Los RNN son notablemente dependientes del orden o del tiempo: procesan los pasos de
tiempo de sus secuencias de entrada en orden, y barajar o invertir los pasos de tiempo puede
cambiar completamente las representaciones que el RNN extrae de la secuencia. Esta es
precisamente la razón por la que se desempeñan bien en problemas donde el orden es
significativo, como el problema de pronóstico de temperatura. Un RNN bidireccional explota
la sensibilidad al orden.idad de RNN: consiste en utilizar dos RNN regulares, como las capas
GRU y LSTM con las que ya está familiarizado, cada una de las cuales procesa la secuencia
de entrada en una dirección (cronológica y anticronológicamente), y luego fusiona su
representación. ciones. Al procesar una secuencia en ambos sentidos, un RNN bidireccional
puede detectar patrones que un RNN unidireccional puede pasar por alto.
Sorprendentemente, el hecho de que las capas RNN en esta sección hayan procesado
secuencias en orden cronológico (los pasos de tiempo más antiguos primero) puede
haber sido una decisión arbitraria. Al menos, es una decisión que no intentamos
cuestionar hasta ahora. ¿Podrían los RNN haber funcionado lo suficientemente bien si
procesaran secuencias de entrada en orden anticronológico, por ejemplo (los pasos de
tiempo más nuevos primero)? Intentemos esto en la práctica y veamos qué sucede. Todo
lo que necesita hacer es escribir una variante del generador de datos donde las
secuencias de entrada se revierten a lo largola dimensión de tiempo (reemplace la última
línea con muestras de rendimiento [:, ::-1,:], objetivos).Entrenando la misma red de una
capa GRU que usó en el primer experimento de esta sección, obtiene los resultados
que se muestran en la figura 6.24.

Con licencia para


220 CPASADO 6Aprendizaje profundopara texto y secuencias

Figura 6.24 Entrenamiento y


validaciónpérdida en la tarea de
pronóstico de temperatura de
Jena con una GRU entrenada en
secuencias inversas

La GRU de orden inverso tiene un desempeño muy inferior incluso a la línea base
de sentido común, lo que indica que, en este caso, el procesamiento cronológico es
importante para el éxito de su enfoque. Esto tiene mucho sentido: la capa GRU
subyacente normalmente recordará mejor el pasado reciente que el pasado distante
y, naturalmente, los puntos de datos meteorológicos más recientes son más
predictivos que los puntos de datos más antiguos para el problema (eso es lo que
hace que la línea de base de sentido común bastante fuerte). Por lo tanto, la versión
cronológica de la capa está destinada a superar a la versión en orden inverso. Es
importante destacar que esto no es cierto para muchos otros problemas, incluido el
lenguaje natural: intuitivamente, la importancia de una palabra para comprender una
oración no suele depender de su posición en la oración. Probemos el mismo truco en
el ejemplo LSTM IMDB de la sección 6.2.

Listado 6.42 Entrenamiento y evaluación de unLSTMutilizando secuencias inversas

desde keras.datasets importar imdb


de la secuencia de importación de keras.preprocessing
de keras importar capas
de keras.models import Secuencial Número de Corta los textos después
palabras a de esta cantidad de
max_features = 10000 considerar como palabras (entre las
maxlen = 500 características palabras más comunes de
max_features)
(x_train, y_train), (x_test, y_test) =
imdb.load_data(num_words=max_features)
carga
s
datos tren_x = [x[::-1] para x en tren_x] Secuencias
prueba_x = [x[::-1] para x en inversas
prueba_x]
activaci
x_tren = secuencia.pad_secuencias(x_tren, maxlen=maxlen)
ón='sigm
x_prueba = secuencia.pad_secuencias(x_prueba,
oide'))
maxlen=maxlen)
modelo.compilar(
modelo = Sequential() optimizador='rms
modelo.añadir(capas.Embedding(max_features, prop',
128)) modelo.añadir(capas.LSTM(32)) l
modelo.añadir(capas.Densa(1, o
Con licencia para
ss='binary_crossentropy',métricas=
['acc'])
Secuenci
as de
pads

Con licencia para


Uso avanzado de neural recurrenteredes 221

historia = modelo.ajuste(x_tren, y_tren,


épocas=10,
tamaño_lote=128,
división_validación=0.2
)

Obtiene un rendimiento casi idéntico al del LSTM de orden cronológico.


Sorprendentemente, en un conjunto de datos de texto de este tipo, el procesamiento
de orden inverso funciona tan bien como el procesamiento cronológico, lo que
confirma la hipótesis de que, aunque el orden de las palabras es importante para
comprender el lenguaje, el orden que usa no es crucial. Es importante destacar que
una RNN entrenada en secuencias inversas aprenderá representaciones diferentes a
las de una entrenada en las secuencias originales, de la misma manera que tendría
diferentes modelos mentales si el tiempo fluyera hacia atrás en el mundo real, si
viviera una vida en la que murió en su primer día y naciste en tu último día. En el
aprendizaje automático, siempre vale la pena explotar las representaciones que son
diferentes pero útiles, y cuanto más difieran, mejor: ofrecen un nuevo ángulo desde
el cual mirar sus datos, capturar aspectos de los datos que otros enfoques pasaron
por alto y, por lo tanto, pueden ayudar a mejorar el rendimiento en una tarea. Esta es
la intuición detrás del conjunto, un concepto que exploraremos en el capítulo 7.
Un RNN bidireccional explotaesta idea para mejorar el rendimiento de las RNN en
orden cronológico. Mira su secuencia de entrada en ambos sentidos (ver figura 6.25),
obteniendo representaciones potencialmente más ricas y capturando patrones que
pueden haber sido pasados por alto solo por la versión de orden cronológico.
Datos de entrada

Fusionar
(añadir,
concatenar)

RNN RNN

aBCDe e, d, c, b,
un
Secuencia secuenci Figura 6.25 Cómo funciona
aBCDe
cronológica a inversa una capa RNN bidireccional

Para instanciar un RNN bidireccional en Keras, utiliza la capa bidireccional, que toma como
primer argumento una instancia de capa recurrente. Bidireccional crea una segunda instancia
separada de esta capa recurrente y usa una instancia para procesar las secuencias de entrada
en orden cronológico y la otra instancia para procesar las secuencias de entrada en orden
inverso. Intentémoslo en la tarea de análisis de sentimientos de IMDB.

Listado 6.43 Entrenamiento y evaluación de un bidireccionalLSTM

modelo = Secuencial()
modelo.añadir(capas.Embedding(max_features, 32))
modelo.añadir(capas.Bidireccional(capas.LSTM(32)))
modelo.añadir(capas.Densa(1, activación='sigmoide') )
Con licencia para
222 CPASADO 6Aprendizaje profundopara texto y secuencias

model.compile(optimizador='rmsprop', pérdida='binary_crossentropy',
métricas=['acc'])historia = modelo.ajuste(x_tren, y_tren,
épocas=10,
tamaño_lote=128,
división_validación=0.
2)

Funciona ligeramente mejor que el LSTM normal que probó en la sección anterior,
logrando una precisión de validación de más del 89 %. También parece sobreajustarse
más rápidamente, lo que no sorprende porque una capa bidireccional tiene el doble de
parámetros que un LSTM cronológico. Con cierta regularización, el enfoque
bidireccional probablemente tendría un buen desempeño en esta tarea.
Ahora intentemos el mismo enfoque en la tarea de predicción de temperatura.

Listado 6.44 Entrenando un bidireccionalGRU

desde keras.models importa


Secuencial desde keras importa
capas
de keras.optimizers importar RMSprop
modelo = Sequential()
modelo.add(capas.Bidireccional(
capas.GRU(32), input_shape=(Ninguno, float_data.shape[-
1]))) model.add(layers.Dense(1))
model.compile(optimizer=RMSprop(), loss='mae')
history = model.fit_generator(train_gen,
pasos_por_época=500,
épocas=40,
validación_datos=val_gen,
validación_pasos=val_pasos)

Esto funciona tan bien como la capa GRU normal. Es fácil entender por qué: toda la
capacidad predictiva debe provenir de la mitad cronológica de la red, porque se sabe
que la mitad anticronológica tiene un rendimiento muy bajo en esta tarea (nuevamente,
porque el pasado reciente importa mucho más que el pasado distante en este caso ).

6.3.9 Yendo aún más lejos


Hay muchas otras cosas que podría intentar para mejorar el rendimiento en el
problema de pronóstico de temperatura:
◾ Ajuste el número de unidades en cada capa recurrente en la configuración
apilada. Las opciones actuales son en gran medida arbitrarias y, por lo tanto,
probablemente subóptimas.
◾ Ajustar la velocidad de aprendizaje utilizada por el RMSpropoptimizador
◾ Intenta usarLSTMcapas en lugar deGRUcapas.
◾ Intente usar un regresor más grande densamente conectado encima de las
capas recurrentes:es decir, más grandeDensocapa o incluso una pila
deDensocapas.
◾ No olvide ejecutar eventualmente los modelos de mejor rendimiento (en
términos de validación).MAE) en el equipo de prueba! De lo contrario,
Con licencia para
desarrollará arquitecturas que se ajustarán demasiado al conjunto de
validación.

Con licencia para


Uso avanzado de neural recurrenteredes 223

Como siempre, el aprendizaje profundo es más un arte que una ciencia. Podemos
proporcionar pautas que sugieran qué es probable que funcione o no en un problema
dado, pero, en última instancia, cada problema es único; tendrás que evaluar diferentes
estrategias empíricamente. Actualmente no existe una teoría que le diga de antemano
con precisión lo que debe hacer para resolver un problema de manera óptima. Debe
iterar.

6.3.10 Terminando
Esto es lo que debe sacar de esta sección:
◾ Como aprendió por primera vez en el capítulo 4, al abordar un nuevo problema,
es bueno establecer primero líneas de base de sentido común para la métrica de su
elección. Si no tiene una línea de base para superar, no puede saber si está
haciendo un progreso real.
◾ Prueba modelos sencillos antes que caros, para justificar el gasto adicional. A
veces, un modelo simple resultará ser su mejor opción.
◾ Cuando tiene datos en los que el orden temporal es importante, las redes
recurrentes encajan perfectamente y superan fácilmente a los modelos que
primero aplanan los datos temporales.
◾ Para usar el abandono con redes recurrentes, debe usar una máscara de abandono
constante en el tiempo y una máscara de abandono recurrente. Estos están
integrados en la capa recurrente de Keras.ers, así que todo lo que tienes que hacer
es usar elAbandonaryabandono_recurrenteargumentos de capas recurrentes.
◾ apiladoRNNs proporcionan más poder de representación que un solo RNNcapa.
También son mucho más caros y, por lo tanto, no siempre valen la pena.
Aunque ofrecen beneficios claros en problemas complejos (como la
traducción automática), es posible que no siempre sean relevantes para
problemas más pequeños y simples.
◾ BidireccionalRNNs, que miran una secuencia en ambos sentidos, son útiles en
problemas de procesamiento de lenguaje natural. Pero no tienen un buen
desempeño en datos de secuencia donde el pasado reciente es mucho más
informativo que el comienzo de la secuencia.

NOTAHay dos conceptos importantes que no cubriremos en detalle aquí:


atención recurrente y enmascaramiento de secuencia. Ambos tienden a ser
especialmente relevantes para el procesamiento del lenguaje natural y no son
particularmente aplicables al problema de pronóstico de temperatura. Los
dejaremos para futuros estudios fuera de este libro.

Con licencia para


224 CPASADO 6Aprendizaje profundopara texto y secuencias

Mercados y aprendizaje automático


Algunos lectores seguramente querrán tomar las técnicasLos hemos presentado
aquí y los probamos en el problema de pronosticar el precio futuro de valores en
el mercado de valores (o tipos de cambio de divisas, etc.). Los mercados
tienencaracterísticas estadísticas muy diferentesque los fenómenos naturales
como los patrones climáticos. Intentar utilizar el aprendizaje automático para
vencer a los mercados, cuando solo tiene acceso a datos disponibles
públicamente, es una tarea difícil y es probable que pierda su tiempo y recursos
sin nada que mostrar.
Recuerde siempre que cuando se trata de mercados, el rendimiento pasado
esnoun buen predictor de rendimientos futuros: mirar por el espejo retrovisor es
una mala forma de conducir. El aprendizaje automático, por otro lado, es
aplicable a conjuntos de datos donde el pasadoesun buen predictor del futuro.

Con licencia para


Procesamiento de secuencias conconvenciones 225

6.4 Procesamiento de secuencias con convnets


En el capítulo 5, aprendió sobre las redes neuronales convolucionales (convnets) y
cómo se desempeñan particularmente bien en problemas de visión por computadora,
debido a su capacidad para operar de manera convolucional, extrayendo
características de parches de entrada locales y permitiendo la modularidad de
representación y la eficiencia de datos. Las mismas propiedades que hacen que las
conv-nets sobresalgan en la visión por computadora también las hacen muy
relevantes para el procesamiento de secuencias. El tiempo se puede tratar como una
dimensión espacial, como la altura o el ancho de una imagen 2D.
Tales convnets 1D pueden ser competitivos con RNN en ciertos problemas de
procesamiento de secuencias, generalmente a un costo computacional
considerablemente más bajo. Recientemente, las conv-nets 1D, típicamente usadas
con núcleos dilatados, se han usado con gran éxito para la generación de audio y la
traducción automática. Además de estos éxitos específicos, se sabe desde hace
tiempo que las pequeñas redes 1D pueden ofrecer una alternativa rápida a las RNN
para tareas simples como la clasificación de texto y la previsión de series
temporales.

6.4.1 Comprensión de la convolución 1D para datos de secuencia


Las capas de convolución introducidas anteriormente eran convoluciones 2D,
extrayendo parches 2D de tensores de imagen y aplicando una transformación
idéntica a cada parche. De la misma manera, puede usar convoluciones 1D,
extrayendo parches 1D locales (subsecuencias) de secuencias (ver figura 6.26).

Ventanad
e talla 5

Caracte
Aporte
rísticas
de
entrada

Tiempo

Parche
extraído

Producto
escalar con
pesos
Figura 6.26 Cómo convolución
Funcion 1Dobras:cada paso de tiempo de
Producción
es de salida se obtiene de un parche
salida temporal en la secuencia de
entrada.

Tales capas de convolución 1D pueden reconocer patrones locales en una secuencia.


Debido a que se realiza la misma transformación de entrada en cada parche, un
patrón aprendido en una determinada posición en una oración se puede reconocer
Con licencia para
más tarde en una posición diferente, lo que hace que la traducción 1D conv-nets sea
invariable (para traducciones temporales). Por ejemplo, una convnet 1D que procesa
secuencias de caracteres usando ventanas de convolución de tamaño 5 debería ser
capaz de aprender palabras o fragmentos de palabras de longitud 5 o menos, y
debería ser capaz de reconocer

Con licencia para


226 CPASADO 6Aprendizaje profundopara texto y secuencias

estas palabras en cualquier contexto en una secuencia de entrada. Por lo tanto, un


convnet 1D a nivel de carácter puede aprender sobre la morfología de las palabras.

6.4.2 Agrupación 1D para datos de secuencia


Ya está familiarizado con las operaciones de agrupación 2D, como la agrupación
promedio 2D y la agrupación máxima, que se utilizan en convnets para reducir la
muestra espacial de los tensores de imagen. La operación de agrupación 2D tiene un
equivalente 1D: extraer parches 1D (subsecuencias) de una entrada y generar el
valor máximo (agrupación máxima) o el valor promedio (agrupación promedio). Al
igual que con las convnets 2D, esto se usa para reducir la longitud de las entradas
1D (submuestreo).

6.4.3 Implementando una convnet 1D


En Keras,utiliza una convnet 1D a través de la capa Conv1D, que tiene una interfaz
similar aConv2D. Toma como entradatensores 3D con forma(muestras, tiempo,
características) y devoluciones de forma similartensores 3D. La ventana
de convolución es una ventana 1D en el eje temporal: eje 1 en el tensor de entrada.
Construyamos una convnet 1D simple de dos capas y aplíquela a la tarea de
clasificación de sentimientos de IMDB con la que ya está familiarizado. Como
recordatorio, este es el código para obtener y preprocesar los datos.

Listado 6.45 Preparando la IMDBdatos

desde keras.datasets importar imdb


de la secuencia de importación de keras.preprocessing
max_features = 10000
longitud_máx = 500
imprimir('Cargando datos...')
(x_train, y_train), (x_test, y_test) = imdb.load_data(num_words=max_features)
print(len(x_train), 'tren secuencias')
print(len(x_test), 'secuencias de prueba')
print('Secuencias de pad (muestras x tiempo)')
x_tren = secuencia.pad_secuencias(x_tren, maxlen=max_len)
x_prueba = secuencia.pad_sequences(x_prueba,
maxlen=max_len) print('x_tren forma:', x_tren.forma)
imprimir('x_test forma:', x_test.forma)

Las convnets 1D están estructuradas de la misma manera que sus contrapartes 2D, que usó en el
capítulo 5: consisten en una pila de capas Conv1D y MaxPooling1D, que terminan en una
capa de agrupación global o una capa Flatten, que convierten las salidas 3D en salidas 2D, lo
que le permite agregar una o más capas densas al modelo para clasificación o regresión.
Sin embargo, una diferencia es el hecho de que puede permitirse usar ventanas
de convolución más grandes con convnets 1D. Con una capa de convolución 2D,
una ventana de convolución de 3 × 3 contiene 3 × 3 = 9 vectores de características;
pero con una capa de convolución 1D, una ventana de convolución de tamaño 3
contiene solo 3 vectores de características. Por lo tanto, puede permitirse fácilmente
ventanas de convolución 1D de tamaño 7 o 9.

Con licencia para


Procesamiento de secuencias conconvenciones 227

Este es el convnet 1D de ejemplo para el conjunto de datos de IMDB.

Listado 6.46 Entrenamiento y evaluación de un convnet 1D simple en IMDBdatos

desde keras.models importa


Secuencial desde keras importa
capas
de keras.optimizers importar RMSprop
modelo = Secuencial()
modelo.añadir(capas.Embedding(max_features, 128, input_length=max_len))
modelo.add(capas.Conv1D(32, 7, activación='relu'))
modelo.add(capas.MaxPooling1D(5))
modelo.add(capas.Conv1D(32, 7, activación='relu'))
modelo .add(layers.GlobalMaxPooling1D())
modelo.add(layers.Dense(1))
Resumen Modelo()
modelo.compilar(optimizador=RMSprop(lr=1e-4),
loss='binary_crossentropy',métricas=['a
cc'])
historia = modelo.ajuste(x_tren, y_tren,
épocas=10,
tamaño_lote=128,
división_validación=0.2
)

Las Figuras 6.27 y 6.28 muestran los resultados del entrenamiento y la validación. La
precisión de la validación es algo menor que la del LSTM, pero el tiempo de ejecución
es más rápido tanto en la CPU como en la GPU (el aumento exacto de la velocidad
variará mucho según la configuración exacta). En este punto, podría volver a entrenar
este modelo durante el número correcto de épocas (ocho) y ejecutarlo en el conjunto de
prueba. Esta es una demostración convincente de que una convnet 1D puede ofrecer una
alternativa rápida y económica a una red recurrente en una tarea de clasificación de
sentimientos a nivel de palabra.

Figura 6.27 Pérdida de


entrenamiento y validación
en IMDB con una convnet 1D
simple

Con licencia para


228 CPASADO 6Aprendizaje profundopara texto y secuencias

Figura 6.28 Precisión de


entrenamiento y validación
en IMDB con una convnet
1D simple

6.4.4 Combinación de CNN y RNN para procesar secuencias largas


Debido a que las convnets 1D procesan los parches de entrada de forma independiente,
no son sensibles al orden de los intervalos de tiempo (más allá de una escala local, el
tamaño de las ventanas de convolución), a diferencia de las RNN. Por supuesto, para
reconocer patrones a más largo plazo, puede apilar muchas capas de convolución y
capas de agrupación, lo que da como resultado capas superiores que verán grandes
fragmentos de las entradas originales, pero esa es todavía una forma bastante débil de
inducir la sensibilidad al orden. Una forma de evidenciar esta debilidad es probar
convnets 1D en el problema de pronóstico de temperatura, donde la sensibilidad al
orden es clave para producir buenas predicciones. El siguiente ejemplo reutiliza las
siguientes variables definidas anteriormente: float_data, train_gen, val_gen y val_steps.

Listado 6.47 Entrenamiento y evaluación de un convnet 1D simple en los datos de Jena

desde keras.models importa


Secuencial desde keras importa
capas
de keras.optimizers importar RMSprop
modelo = Secuencial()
modelo.add(capas.Conv1D(32, 5, activación='relu',
input_shape=(Ninguno, float_data.shape[-
1]))) model.add(layers.MaxPooling1D(3))
modelo.add(capas.Conv1D(32, 5, activación='relu'))
modelo.add(capas.MaxPooling1D(3))
modelo.add(capas.Conv1D(32, 5, activación='relu'))
modelo .add(layers.GlobalMaxPooling1D())
modelo.add(layers.Dense(1))
model.compile(optimizer=RMSprop(), loss='mae')
history = model.fit_generator(train_gen,
pasos_por_época=500,
épocas=20,
validación_datos=val_gen,
validación_pasos=val_pasos)

Con licencia para


Procesamiento de secuencias conconvenciones 229

La Figura 6.29 muestra los MAEs de entrenamiento y validación.

Figura 6.29 Pérdida de


entrenamiento y validación
en la tarea de pronóstico
de temperatura de Jena
con una convnet 1D simple

La validación MAE se mantiene en los 0,40: ni siquiera se puede superar la línea de


base de sentido común utilizando la pequeña convnet. De nuevo, esto se debe a que la
convnet busca patrones en cualquier parte de la serie temporal de entrada y no tiene
conocimiento de la posición temporal de un patrón que ve (hacia el principio, hacia el
final, etc.). Debido a que los puntos de datos más recientes deben interpretarse de
manera diferente a los puntos de datos más antiguos en el caso de este problema de
pronóstico específico, el convnet no produce resultados significativos. Esta limitación
de convnets no es un problema con los datos de IMDB, porque los patrones de palabras
clave asociadas con un sentimiento positivo o negativo son informativos
independientemente de dónde se encuentren en las oraciones de entrada.
Una estrategia para combinar la velocidad y la ligereza de las convnets con la
sensibilidad al orden de las RNN es usar una convnet 1D como paso de
preprocesamiento antes de una RNN (consulte la figura 6.30). Esto es especialmente
beneficioso cuando se trata de
ing con secuencias que son tan largas que no
se pueden procesar de manera realista con
RNN, como
secuencias con miles de pasos. la conv-net RNN
convertirá la secuencia de entrada larga en
secuencias mucho más cortas (reducidas) de
funciones de nivel superior. Esta secuencia Secuenci
Características de CNN
a más
de características extraídas luego se
corta
convierte en la entrada a la parte RNN de la
red.
Esta técnica no se ve a menudo en 1D CNN
trabajos de investigación y aplicaciones
prácticas, posiblemente porque no es muy
conocida. Es efectivo y debería ser más Secuencia
común. Probémoslo en el conjunto de datos larga

de pronóstico de temperatura.
Con licencia para
Debido a que esta estrategia le permite Figura 6.30 Combinación de una convnet
manipular secuencias mucho más largas, 1D yun RNN para procesar secuencias
puede largas

Con licencia para


230 CPASADO 6Aprendizaje profundopara texto y secuencias

mire datos de hace más tiempo (aumentando el parámetro retrospectivo del generador
de datos) o mire series temporales de alta resolución (disminuyendo el parámetro de
paso del generador). Aquí, de forma un tanto arbitraria, utilizará un paso que es la mitad
de grande, lo que da como resultado una serie de tiempo el doble de larga, donde los
datos de temperatura se muestrean a una velocidad de 1 punto cada 30 minutos. El
ejemplo reutiliza la función de generador definida anteriormente.

Listado 6.48 Preparación de generadores de datos de mayor resolución para el conjunto de datos de Jena

paso = 3
retrospectiva
Establecido previamente en 6 (1punto por
Sin alterar hora); ahora 3 (1punto por 30 min)
= 720
retraso = 144
tren_gen = generador(float_data,
mirar hacia atrás
= mirar hacia
atrás,retraso=retr
aso, min_index=0,
max_index=200000,
reproducción
aleatoria=Verdader
o, paso=paso)
val_gen = generador(float_data,
mirar hacia atrás
= mirar hacia
atrás,retraso=retr
aso,
min_index=200001,
max_index=300000,
paso=paso)
test_gen = generador (float_data,
mirar hacia atrás
= mirar hacia
atrás,retraso=retr
aso,
min_index=300001,
max_index=Ninguno,
paso=paso)
val_steps = (300000 - 200001 - retrospectiva) // 128
test_steps = (len(float_data) - 300001 - retrospectiva)
// 128

Este es el modelo, comenzando con dos capas Conv1D y siguiendo con una capa GRU. La
figura 6.31 muestra los resultados.

Listado 6.49 Modelo que combina una base convolucional 1D y unaGRUcapa

desde keras.models importa


Secuencial desde keras importa
capas
de keras.optimizers importar RMSprop
modelo = Secuencial()
modelo.add(capas.Conv1D(32, 5, activación='relu',
input_shape=(Ninguno, float_data.shape[-

Con licencia para


1]))) model.add(layers.MaxPooling1D(3))
modelo.añadir(capas.Conv1D(32, 5, activación='relu'))
modelo.añadir(capas.GRU(32, abandono=0.1,
abandono_recurrente=0.5)) modelo.añadir(capas.Dense(1))
modelo.resumen()

modelo.compile(optimizador=RMSprop(),

pérdida='mae')

Con licencia para


Procesamiento de secuencias conconvenciones 231

historia = modelo.fit_generator(tren_gen,
pasos_por_época=500,
épocas=20,
validación_datos=val_gen,
validación_pasos=val_pasos)

Figura 6.31 Entrenamiento y


validaciónpérdida en la tarea de
pronóstico de temperatura de Jena
con una convnet 1D seguida de
unaGRU

A juzgar por la pérdida de validación, esta configuración no es tan buena como la GRU
regularizada sola, pero es significativamente más rápida. Analiza el doble de datos, lo
que en este caso no parece ser muy útil, pero puede ser importante para otros conjuntos
de datos.

6.4.5 Terminando
Esto es lo que debe sacar de esta sección:
◾ De la misma manera que2DConvnets funcionan bien para procesar patrones
visuales en2Despacio,1DLos convnets funcionan bien para procesar patrones
temporales. Ofrecen una alternativa más rápida a RNNs en algunos problemas,
en particular tareas de procesamiento de lenguaje natural.
◾ Típicamente,1DLos convnets están estructurados de manera muy similar a
sus2Dequivalentes de lamundo de la visión artificial: consisten en pilas
deConv1Dcapas yMax- Pooling1Dcapas, terminando en una operación de
agrupación global o una operación de aplanamiento.
◾ PorqueRNNLos s son extremadamente caros para procesar secuencias muy largas,
pero1DConvnets son baratos, puede ser una buena idea usar un 1Dconvnet
como un paso de preprocesamiento antes de un RNN, acortando la secuencia y
extrayendo representaciones útiles para elRNNprocesar.

Con licencia para


232 CPASADO 6Aprendizaje profundopara texto y secuencias

Resumen del capítulo


◾ En este capítulo, aprendió las siguientes técnicas, que son ampliamente
aplicables a cualquier conjunto de datos de secuencias, desde texto hasta
series de tiempo:
– Cómo tokenizar texto
– Qué son las incrustaciones de palabras y cómo usarlas
– Qué son las redes recurrentes y cómo usarlas
– Cómo apilar capas de RNN y usar RNN bidireccionales para generar más
potenciamodelos completos de procesamiento de secuencias
– Cómo usar convnets 1D para el procesamiento de secuencias
– Cómo combinar convnets 1D y RNN para procesar secuencias largas
◾ Puede usar RNN para regresión de series temporales ("predecir el futuro"),
clasificación de series temporales, detección de anomalías en series
temporales y etiquetado de secuencias (como identificar nombres o fechas
en oraciones).
◾ De manera similar, puede usar convnets 1D para traducción automática
(modelos convolucionales de secuencia a secuencia, como SliceNeta),
clasificación de documentos y corrección ortográfica.
◾ Si el orden global es importante en sus datos de secuencia, entonces es
preferible usar una red recurrente para procesarlos. Este suele ser el caso de
las series temporales, en las que es probable que el pasado reciente sea más
informativo que el pasado lejano.
◾ Si el pedido global no es fundamentalmente significativo, entonces las redes 1D
funcionarán al menos igual de bien y serán más baratas. Este suele ser el caso
de los datos de texto, donde una palabra clave que se encuentra al principio de
una oración es tan significativa como una palabra clave que se encuentra al
final.
un ver
https://arxiv.org/abs/1706.03059.

Con licencia para


Aprendizaje profundo
avanzado
mejor prácticas

Este capítulo cubre


◾ La API funcional de Keras
◾ Uso de devoluciones de llamada de Keras
◾ Trabajar con la herramienta de visualización
TensorBoard
◾ Mejores prácticas importantes para desarrollar
el estado delos modelos de arte

Este capítulo explora una serie de herramientas poderosas que lo acercarán a


poder desarrollar modelos de última generación sobre problemas difíciles. Con la
API funcional de Keras, puede crear modelos similares a gráficos, compartir una
capa en diferentes entradas y usar modelos de Keras como funciones de Python.
Las devoluciones de llamada de Keras y la herramienta de visualización basada
en navegador TensorBoard le permiten monitorear modelos durante el
entrenamiento. También analizaremos otras prácticas recomendadas, como la
normalización por lotes, las conexiones residuales, la optimización de
hiperparámetros y el ensamblaje de modelos.

233

Con licencia para


234 CPASADO7Aprendizaje profundo avanzadomejores prácticas

7.1 Más allá del modelo secuencial:la


API funcional de Keras
Hasta ahora, todas las redes neuronales presentadas en Producción
este libro se han implementado utilizando el modelo
secuencial. El modelo secuencial supone que la red
tiene exactamente una entrada y exactamente una Capa
salida, y que consta de una pila lineal de capas (consulte
la figura 7.1). Capa
Esta es una suposición comúnmente verificada; la
configuración es tan común que hemos podido cubrir Capa
muchos temas y aplicaciones prácticas en estas páginas
hasta ahorausando solo la clase de modelo secuencial. Pero Secuencia
este conjunto de suposiciones es demasiado inflexible en l Aporte
varios casos. Algunas redes requieren varias entradas
independientes, otras
requieren múltiples salidas, y algunas redes tienen Figura 7.1ASecuencial
bifurcaciones internas entre capas que las hacen parecer modelo: una pila lineal de capas
gráficos de capas en lugar de pilas lineales de capas.
Algunas tareas, por ejemplo, requieren entradas multimodales: fusionan datos
provenientes de diferentes fuentes de entrada, procesando cada tipo de datos utilizando
diferentes tipos de capas neuronales. Imagine un modelo de aprendizaje profundo que
intente predecir el precio de mercado más probable de una prenda de vestir de segunda
mano, utilizando las siguientes entradas: metadatos proporcionados por el usuario
(como la marca del artículo, la edad, etc.), un descripción del texto y una imagen del
artículo. Si solo tuviera los metadatos disponibles, podría codificarlos en caliente y usar
una red densamente conectada para predecir el precio. Si solo tuviera la descripción de
texto disponible, podría usar un RNN o un convnet 1D. Si solo tuviera la imagen, podría
usar una convnet 2D. Pero, ¿cómo puedes usar los tres al mismo tiempo? Un enfoque
ingenuo sería entrenar tres modelos separados y luego hacer un promedio ponderado de
sus predicciones. Pero esto puede ser subóptimo, porque la información extraída por los
modelos puede ser redundante. Una mejor manera es aprender conjuntamente un
modelo más preciso de los datos mediante el uso de un modelo que pueda ver todas las
modalidades de entrada disponibles simultáneamente: un modelo con tres ramas de
entrada (consulte la figura 7.2).

Predicción de precios

Módulo
de
fusión

DensomóduloRNN móduloConvnet módulo

Metadatos Descripción del Image Figura 7.2 Un modelo multientrada


texto n

Con licencia para


Más allá del modelo Secuencial: el funcional de KerasAPI 235

Del mismo modo, algunas tareas necesitan predecir objetivos múltiplesatributos de


los datos de entrada. Dado el texto de una novela o cuento, es posible que desee
clasificarlo automáticamente por género (como romance o suspenso), pero también
predecir la fecha aproximada en que se escribió. Por supuesto, podría entrenar dos
modelos separados: uno para el género y otro para la fecha. Pero debido a que estos
atributos no son estadísticamente independientes, podría construir un mejor modelo
aprendiendo a predecir conjuntamente el género y la fecha al mismo tiempo. Tal
modelo conjunto tendría entonces dos salidas o cabezas (ver figura 7.3). Debido a
las correlaciones entre el género y la fecha, conocer la fecha de una novela ayudaría
al modelo a aprender representaciones ricas y precisas del espacio de los géneros
novedosos, y viceversa.

GéneroFecha

clasific regres
ador de or de
género fecha

procesamiento
de
textomódul
o
Texto de novela

Figura 7.3 Un modelo multisalida (o multicabezal)

Además, muchas arquitecturas neuronales desarrolladas recientemente requieren una


topología de red no lineal: redes estructuradas como gráficos acíclicos dirigidos. La
familia de redes Inception (desarrollada por Szegedy et al. en Google),1 por ejemplo, se
basa en módulos Inception, donde la entrada es procesada por varias ramas
convolucionales paralelas cuyas salidas luego se fusionan nuevamente en un solo tensor
(ver figura 7.4) . También existe la tendencia reciente de agregar conexiones residuales
a un modelo, que comenzó con la familia de redes ResNet (desarrollada por He et al. en
Microsoft).2 Una conexión residual consiste en reinyectar representaciones previas en el
flujo de datos descendente mediante agregar un tensor de salida anterior a un tensor de
salida posterior (consulte la figura 7.5), lo que ayuda a evitar la pérdida de información
a lo largo del flujo de procesamiento de datos.

1 Christian Szegedy et al., "Going Deeper with Convolutions", Conferencia sobre visión artificial y reconoc imiento de patrones
(2014),
https://arxiv.org/abs/1409.4842.
2 Kaiming He et al., "Deep Residual Learning for Image Recognition", Conferencia sobre visión artificial y patrones
Reconocimiento (2015),
https://arxiv.org/abs/1512.03385.

Con licencia para


236 CPASADO7Aprendizaje profundo avanzadomejores prácticas

Producción

Concatenar

Conv2D
3 × 3, pasos =
2

Conv2D Conv2D Conv2D


3 × 3, pasos = 3×3 3×3
2

Conv2D Conv2D PromedioGrup Conv2D


1 × 1, pasos = 1×1 o2D 1×1
2 3 × 3, pasos =
2

Aporte

Figura 7.4 Un módulo Inception: un subgrafo de capas con variasramas


convolucionales paralelas

Capa

Capa Conexión
residual

Capa

Figura 7.5Una conexión residual:


reinyección de información
Capa
anterior aguas abajo a través de la
adición de mapas de características

Estos tres casos de uso importantes: modelos de múltiples entradas, modelos de


múltiples salidas ymodelos similares a gráficos: no son posibles cuando se usa solo la clase
de modelo Sequential en Keras. Pero hay otra forma mucho más general y flexible de usar
Keras: la API funcional. Esta sección explica en detalle qué es, qué puede hacer y cómo
usarlo.

7.1.1 Introducción a la API funcional


En la API funcional, manipulas directamente los tensores y usas capas como funciones
que toman tensores y vuelventensores (de ahí el nombre funcionalAPI):
desde keras import Input, capas
input_tensor = Input(shape=(32,)) un tensor

Con licencia para


Más allá del modelo Secuencial: el funcional de KerasAPI 237

denso = capas.Denso (32, activación = Una capa es una función.


'relu') salida_tensor =denso
Se puede llamar a una capa en
(entrada_tensor) un tensor y devuelve un tensor.

Comencemos con un ejemplo mínimo que muestra lado a lado un modelo secuencial simple
y su equivalente en la API funcional:
desde keras.models import Sequential,
Model from keras import layers
desde la entrada de importación de keras Modelo secuencial, que ya
conoces
seq_model = Secuencial()
seq_model.add(capas.Dense(32, activación='relu', input_shape=(64,)))
seq_model.add(capas.Dense(32, activación='relu'))
seq_model.add(capas.Dense(10 , activación='softmax'))
input_tensor = Entrada (forma = (64,))
x = capas.Densa(32, Su
activación='relu')(entrada_tensor) x = equivalente
capas.Densa(32, activación='relu')(x) funcional
salida_tensor = capas.Dense (10, activación = 'softmax')
(x)
modelo = Modelo(entrada_tensor,
La clase Model convierte una entradatensor
salida_tensor)
Resumen ¡Veámoslo! y tensor de salida en un modelo.
Modelo()

Esto es lo que la llamada a Resumen Modelo()muestra:

Capa(tipo)Salida ShapeParam #
================================================== ===============
input_1 (capa de (Ninguno, 64) 0
entrada)
denso_1 (Denso) (Ninguno, 32) 2080

denso_2 (Denso) (Ninguno, 32) 1056

denso_3 (Denso) (Ninguno, 10) 330


================================================== ===============
Parámetros totales: 3.466
Parámetros entrenables: 3466
Parámetros no entrenables: 0

La única parte que puede parecer un poco mágica en este punto es instanciar un objeto
Modelo usando solo un tensor de entrada y un tensor de salida. Detrás de escena, Keras
recuperacada capa involucrada enpasando de input_tensor a output_tensor, reuniéndolos en
una estructura de datos similar a un gráfico: un modelo. Por supuesto, la razón por la que
funciona es que output_tensor se obtuvo transformando repetidamente input_tensor. Si
intentara construir un modelo a partir de entradas y salidas que no estuvieran relacionadas,
obtendría un RuntimeError:
>>> entrada_no_relacionada = Entrada(forma=(32,))
>>> modelo_malo = modelo = Modelo(entrada_no relacionada, tensor_de_salida)

Con licencia para


238 CPASADO7Aprendizaje profundo avanzadomejores prácticas

RuntimeError: gráfico desconectado: no


se puede obtener el valor para el tensor
➥Tensor("input_1:0", shape=(?, 64), dtype=float32) en la capa "input_1".

Este error te dice, en esencia, que Keras no pudo llegar a input_1 desde el tensor de salida
proporcionado.
Cuando se trata de compilar, entrenar o evaluar dicha instancia de Model, el
APIes el mismo que el deSecuencial:
modelo.compile(optimizador='rmsprop',
Compila
pérdida='categorical_crossentropy')
importar numpy como np el modelo
Genera datos Numpy ficticios
tren_x = np.aleatorio.aleatorio((1000,
para entrenar
64)) tren_y =
np.aleatorio.aleatorio((1000, 10))
model.fit(x_train, y_train, epochs=10,
Entrena al modelo
batch_size=128)
puntuación = modelo.evaluar(x_tren, por10 épocas
Evalúa el
y_tren)
modelo

7.1.2 Modelos de entradas múltiples


La API funcional se puede usar para construir modelos que tienen múltiples entradas.
Por lo general, estos modelos en algún momento fusionan sus diferentes ramas de
entrada utilizando una capa que puede combinar varios tensores: agregándolos,
concatenándolos, etc. Esto es usu-aliado hecho a través de una operación de fusión de
Keras como keras.layers.add, keras.layers
.concatenar, y así sucesivamente. Veamos un ejemplo muy simple de un
modelo de múltiples entradas:
un modelo de pregunta-respuesta.
Un modelo típico de preguntas y respuestas tiene dos entradas: una pregunta en
lenguaje natural y un fragmento de texto (como un artículo de noticias) que proporciona
información para responder a la pregunta. Luego, el modelo debe producir una
respuesta: en la configuración más simple posible, esta es una respuesta de una palabra
obtenida a través de un softmax sobre un vocabulario predefinido (ver figura 7.6).

Responder

Denso

Concatenar

LSTM LSTM

incrustació incrustació
n n

Referenciatexto Pregunta Figura 7.6 Un modelo de preguntas y respuestas

Con licencia para


Más allá del modelo Secuencial: el funcional de KerasAPI 239

A continuación se muestra un ejemplo de cómo puede crear un modelo de este tipo


con la API funcional. Configura dos ramas independientes, codificando la entrada
de texto y la entrada de preguntas como vectores de representación; luego,
concatenar estos vectores; y finalmente, agregue un clasificador softmax encima de
las representaciones concatenadas.

Listado 7.1 Implementación API funcional de un modelo de pregunta-respuesta de dos entradas

desde keras.models importar


Modelo desde keras importar
capas La entrada de texto es una
desde la entrada de importación secuencia de enteros de
de keras longitud variable. Tenga en
texto_vocabulario_tamaño = 10000
cuenta que puede
opcionalmente
question_vocabulary_size =
10000
nombrar las entradas.
tamaño_respuesta_vocabulario =
500

entrada_texto = Entrada(forma=(Ninguno,), dtype='int32', nombre='texto')

texto_incrustado = capas.Embedding(
64,
Incrusta las
entradasen una
tamaño_vocabulario_texto)(entrada_texto)
secuencia de
texto_codificado =
vectores de
tamaño 64
capas.LSTM(32)(texto_incrustado) Codifica los vectores en
un solo vector a través de
question_input = Entrada (forma = (Ninguno,), un LSTM
dtype='int32',
nombre='pregunta
Mismo proceso (con diferentes instancias
')
de capa) para la pregunta
incrustado_pregunta = capas.Embedding(
32,
tamaño_vocabulario_pregunta)(entrada_pregunta
)
pregunta_codificada = capas.LSTM(16)(pregunta_incrustada)

concatenado = capas.concatenar([texto_codificado, pregunta_codificado],


eje=-1)
Concatena la pregunta codificada y
respuesta = el texto codificado.
capas.Dense(answer_vocabulary_size,
activación='softmax')(concatenado) Agrega un
modelo = Modelo ([text_input, question_input], respuesta) clasificador
softmax en la
parte superior
modelo.compilar(optimizador='rmsprop',
En la instanciación del modelo,
loss='categorical_crossentropy', especifica las dos entradas y la salida.
métricas=['acc'])

Ahora, ¿cómo entrenas este modelo de dos entradas? Hay dos API posibles: puede
alimentar al modelo con una lista de matrices Numpy como entradas, o puede
alimentarlo con un diccionario que asigna nombres de entrada a matrices Numpy.
Con licencia para
Naturalmente, la última opción está disponible solo si da nombres a sus entradas.

Listado 7.2 Alimentando datos a un modelo de múltiples entradas

importar numpy genera ficticio


entumecidodatos
como np

num_samples = 1000
longitud_máx = 100
texto = np.random.randint(1, text_vocabulary_size,
tamaño=(num_muestras, max_longitud))

Con licencia para


240 CPASADO7Aprendizaje profundo avanzadomejores prácticas

Las respuestas
pregunta = np.random.randint(1, question_vocabulary_size, están
size=(num_samples, max_length)) codificadas
respuestas = np.random.randint(0, 1, en caliente,
no en
números
enteros.
tamaño=(núm_muestras,respuesta_vocabulario_tamaño))
modelo.ajuste([texto, pregunta], respuestas, épocas=10,
tamaño_lote=128) modelo.ajuste({'texto': texto, 'pregunta':
pregunta}, respuestas,
épocas=10, tamaño_lote=128)

Adecuadoutilizando una lista deentradas Ajuste utilizando un


diccionario de entradas (solo si se
nombran las entradas)

7.1.3 Modelos multisalida


De la misma manera, puede usar la API funcional para construir modelos con múltiples
salidas (o múltiples cabezas). Un ejemplo simple es una red que intenta predecir
simultáneamente diferentes propiedades de los datos, como una red que toma como
entrada una serie de publicaciones en redes sociales de una sola persona anónima e
intenta predecir atributos de esa persona, como edad, género. y nivel de ingreso (ver
figura 7.7).

Listado 7.3 Implementación funcional de la API de un modelo de tres salidas

desde keras importar


capas desde keras
importar Entrada
de keras.models modelo de importación

vocabulario_tamaño = 50000
núm_ingresos_grupos = 10

publicaciones_entrada = Entrada(forma=(Ninguno,), dtype='int32',


nombre='publicaciones') incrustadas_publicaciones =
capas.Incrustación(256, tamaño_vocabulario)(publicaciones_entrada) x
= capas.Conv1D(128, 5, activación='relu
')(publicaciones_incrustadas)
x = capas.MaxPooling1D(5)(x)
x = capas.Conv1D(256, 5, activación='relu')(x)
x = capas.Conv1D(256, 5, activación='relu')(x)
x = capas.MaxPooling1D(5)(x)
x = capas.Conv1D(256, 5, activación='relu')(x)
x = capas.Conv1D(256, 5, activación='relu')(x)
x = capas.GlobalMaxPooling1D()(x)
x = capas.Densa(128, activación='relu')(x) Tenga en cuenta que ellas
capas de salida reciben
predicción_de_edad = capas.Densa(1, nombres.
nombre='edad')(x) predicción_de_ingresos =
capas.Densa(num_grupos_de_ingresos,
activación='softmax',
nombre='ingresos')(x)
Con licencia para
género_predicción = capas. Dense (1, activación = 'sigmoide', nombre = 'género') (x)
modelo = Modelo (entrada_mensajes,
[predicción_de_edad, predicción_de_ingresos, predicción_de_género])

Con licencia para


Más allá del modelo Secuencial: el funcional de KerasAPI 241

Años Ingres Género


o

Denso Denso Denso

Convnet
1D

Figura7.7 Un modelo de redes


Publicaciones en redes sociales sociales con tres cabezas

Es importante destacar que entrenar dicho modelo requiere la capacidad de


especificar diferentes funciones de pérdida para diferentes cabezas de la red: por
ejemplo, la predicción de edad es una tarea de regresión escalar, pero la predicción
de género es una tarea de clasificación binaria, que requiere un procedimiento de
entrenamiento diferente. . Pero debido a que el descenso de gradiente requiere que
minimices un escalar, debes combinar estas pérdidas en un solo valor para entrenar
el modelo. La forma más sencilla de combinar diferentes pérdidas es sumarlas
todas. En Keras, puede usar una lista o un diccionario de pérdidas en compilación
para especificar diferentes objetos para diferentes salidas; los valores de pérdida
resultantes se suman en una pérdida global, que se minimiza durante el
entrenamiento.

Listado 7.4 Opciones de compilación de un modelo multisalida: pérdidas múltiples

modelo.compilar(optimizador='rmsprop',
loss=['mse', 'categorical_crossentropy', 'binary_crossentropy'])
modelo.compilar(optimizador='rmsprop', Equivalente (posible
pérdida={'edad':'mse', solo si da nombres a
'ingresos': las capas de salida)
'categorical_crossentropy','género':
'binary_crossentropy'})

Tenga en cuenta que las contribuciones de pérdida muy desequilibradas harán que las
representaciones del modelo se optimicen preferentemente para la tarea con la mayor
pérdida individual, a expensas de las demás tareas. Para remediarlo, puede asignar
diferentes niveles de importancia a los valores de pérdida en su contribución a la
pérdida final. Esto es útil en particular si los valores de las pérdidas utilizan diferentes
escalas. Por ejemplo, la pérdida del error cuadrático medio (MSE) utilizada para la tarea
de regresión de edad suele tener un valor de alrededor de 3 a 5, mientras que la pérdida
de entropía cruzada utilizada para la tarea de clasificación de género puede ser tan baja
como 0,1. En tal situación, para equilibrar la contribución de las diferentes pérdidas,
puede asignar un peso de 10 a la pérdida de entropía cruzada y un peso de 0,25 a la
pérdida de MSE.

Listado 7.5 Opciones de compilación de un modelo de múltiples salidas: ponderación de pérdidas

modelo.compilar(optimizador='rmsprop',
loss=['mse', 'categorical_crossentropy',
Con licencia para
'binary_crossentropy'],loss_weights=[0.25, 1., 10.])

Con licencia para


242 CPASADO7Aprendizaje profundo avanzadomejores prácticas

modelo.compilar(optimizador='rmsprop',
pérdida={'edad':'mse',
'ingresos': Equivalente (posible
'categorical_crossentropy','género': solo si da nombres a
'binary_crossentropy'}, las capas de salida)
loss_weights={'edad':0.25,
'ingresos': 1.,
'género': 10.})

Al igual que en el caso de los modelos de múltiples entradas, puede pasar datos Numpy al
modelo para su entrenamiento a través de una lista de matrices o mediante un diccionario
de matrices.

Listado 7.6 Alimentando datos a un modelo de múltiples salidas

model.fit(publicaciones, [edad_objetivos, ingresos_objetivos,


género_objetivos], épocas=10, tamaño_lote=64)
model.fit(publicaciones, {'edad': edad_objetivos,
'ingresos': Equivalente (posible solo si da
objetivos_ingresos, nombres a las capas de salida)
'género':
objetivos_género},
épocas=10, tamaño_lote=64)
Se supone que age_targets,
income_targets y gender_targets
son matrices Numpy.

7.1.4 Gráficos acíclicos dirigidos de capas


Con la API funcional, no solo puede crear modelos con múltiples entradas y
múltiples salidas, sino que también puede implementar redes con una topología
interna compleja.Las redes neuronales en Keras pueden ser gráficos acíclicos dirigidos
arbitrariamente de capas. El calificador acíclico es importante: estos gráficos no pueden tener
ciclos. Es imposible que un tensor x se convierta en la entrada de una de las capas que generó
x. Los únicos bucles de procesamiento que están permitidos (es decir, conexiones
recurrentes) son los internos de las capas recurrentes. Varios componentes comunes de redes
neuronales se implementan como gráficos. Dos notables son los módulos Inception y las
conexiones residuales. Para comprender mejor cómo se puede usar la API funcional para
crear gráficos de capas, echemos un vistazo a cómo
puedes implementar ambos en Keras.
yoMÓDULOS DE NCEPCIÓN
Comienzo3 es un tipo popular de arquitectura de red para redes neuronales convolucionales; fue desarrollado por Christian

Szegedy y sus colegas en Google en 2013–2014, inspirado en la arquitectura de red en red anterior.4 Consiste en una pila de módulos

que parecen pequeñas redes independientes, divididas en varias ramas paralelas. La forma más básica de un módulo Inception tiene de
tres a cuatro ramas que comienzan con una convolución de 1 × 1, seguida de una convolución de 3 × 3 y terminan con la concatenación

de las características resultantes. Esta configuración ayuda a la red a aprender por separado

3
https://arxiv.org/abs/1409.4842.
4 Min Lin, Qiang Chen y Shuicheng Yan, “Red en red”, Conferencia internacional sobre representaciones de aprendizaje
(2013), https://arxiv.org/abs/1312.4400.

Con licencia para


Más allá del modelo Secuencial: el funcional de KerasAPI 243

características espaciales y características de canal, que es más eficiente que aprenderlas


conjuntamente. También son posibles versiones más complejas de un módulo Inception,
que generalmente involucran operaciones de agrupación, diferentes tamaños de
convolución espacial (por ejemplo, 5 × 5 en lugar de 3 × 3 en algunas ramas) y ramas
sin una convolución espacial (solo un 1 × 1 circunvolución). Un ejemplo de dicho
módulo, tomado de Inception V3, se muestra en la figura 7.8.

Producción

Concatenar

Conv2D
3 × 3, pasos =
2

Conv2D Conv2D Conv2D


3 × 3, pasos = 3×3 3×3
2

Conv2D Conv2D PromedioGrup Conv2D Figura 7.8 Un


1 × 1, pasos = 1×1 o2D 1×1
2 3 × 3, pasos = comienzomódulo
2

Aporte

El propósito de las circunvoluciones 1 × 1


TúYa sabe que las convoluciones extraen parches espaciales alrededor de cada
mosaico en un tensor de entrada y aplican la misma transformación a cada
parche. Un caso límite es cuando los parches extraídos consisten en un solo
mosaico. La operación de convolución entonces se convierte en equivalente a
ejecutar cada vector de mosaico a través de unDensocapa: calculará características
que mezclan información de los canales del tensor de entrada, pero no mezclará
información a través del espacio (porque está mirando un mosaico a la vez). Tales
circunvoluciones 1 × 1 (también llamadascircunvoluciones puntuales) aparecen en los
módulos Inception, dóndetOye contribuirtoFactuaciónoUtah canal sabio rasgo
aprendizaje yspas-Aprendizaje inteligente de características: algo razonable si se
supone que cada canal está altamente autocorrelacionado en el espacio, pero es
posible que los diferentes canales no estén altamente correlacionados entre sí.

Así es como implementaría el módulo presentado en la figura 7.8 usando el funcional


API. Este ejemplo asume la existencia de un tensor de entrada 4DX:

Con licencia para


244 CPASADO7Aprendizaje profundo avanzadomejores prácticas

Cada rama tiene el mismo valor de zancada (2),


que es necesario para mantener todas las En esta rama se da la zancadaen
salidas de rama del mismo tamaño para que la capa de convolución espacial.
pueda concatenarlas.

de keras importar capas


branch_a = capas.Conv2D(128, 1,
activación='relu',
zancadas=2)(x) branch_b = capas.Conv2D(128, 1,
activación='relu')(x)
rama_b = capas.Conv2D(128, 3, activación='relu', zancadas=2)(rama_b)
branch_c = capas.AveragePooling2D(3, zancadas=2)(x)
branch_c = capas.Conv2D(128, 3, activación='relu')(branch_c)

branch_d = capas.Conv2D(128, 1, activación='relu')(x)


branch_d = capas.Conv2D(128, 3, activación='relu')(branch_d)
rama_d = capas.Conv2D(128, 3, activación='relu', zancadas=2)(rama_d)
salida = capas.concatenar(
[sucursal_a, sucursal_b, sucursal_c, sucursal_d], Concatena las
eje=-1) salidas de rama
para obtener la
En esta rama, la zancadaocurre salida del módulo
en la capa de agrupación
promedio.

Tenga en cuenta que el Inception completo V3arquitectura está disponible en Keras


comokeras.aplicaciones
.inception_v3.InceptionV3, incluidas las ponderaciones
preentrenadas en el conjunto de datos de ImageNet. Otro modelo
estrechamente relacionado disponible como parte del módulo de
aplicaciones de Keras es Xception.5 Xception, que significa
inicio extremo, es una arquitectura de convnet inspirada
libremente en Inception. Lleva la idea de separar el aprendizaje
de las funciones de canal y de espacio a su extremo lógico, y
reemplaza los módulos de Inception con circunvoluciones
separables en profundidad que consisten en una convolución en
profundidad (una convolución espacial en la que cada canal de
entrada se maneja por separado). ) seguido de una convolución
puntual (una convolución de 1 × 1)—efectivamente, una forma
extrema de un módulo Inception, donde las características
espaciales y las características del canal están completamente
separadas. Xception tiene aproximadamente la misma cantidad de
parámetros que InceptionV3, pero muestra un mejor rendimiento en tiempo de
ejecución y una mayor precisión en ImageNet, así como en otros conjuntos de datos a gran escala,
debido a un uso más eficiente de los parámetros del modelo.
RCONEXIONES ESIDUALES
Conexiones residualesson un componente de red similar a un gráfico común que se
encuentra en muchas arquitecturas de red posteriores a 2015, incluido Xception. Fueron
introducidos por He et al. de Microsoft en su entrada ganadora en el desafío ILSVRC

Con licencia para


ImageNet a fines de 2015.6 Abordan dos problemas comunes que afectan a cualquier
modelo de aprendizaje profundo a gran escala: gradientes que se desvanecen y cuellos
de botella de representación. En general, es probable que sea beneficioso agregar
conexiones residuales a cualquier modelo que tenga más de 10 capas.
5 François Chollet, “Xception: aprendizaje profundo con
Convoluciones separables en profundidad”, Conference on Computer
Visión y Patróngrabacióncognición(2017), https://arxiv.org/abs/1610.02357.
6
He et al., "Aprendizaje residual profundo para el reconocimiento de imágenes",https://arxiv.org/abs/1512.03385.

Con licencia para


Más allá del modelo Secuencial: el funcional de KerasAPI 245

Una conexión residual consiste en hacer que la salida de una capa anterior esté
disponible como entrada para una capa posterior, creando efectivamente un atajo en
una red secuencial. En lugar de concatenarse con la activación posterior, la salida
anterior se suma a la activación posterior, lo que supone que ambas activaciones
tienen el mismo tamaño. Si son de diferentes tamaños, puede usar una
transformación lineal para remodelar la activación anterior en la forma de destino
(por ejemplo, una capa densa sin activación o, para mapas de características
convolucionales, una convolución 1 × 1 sin activación) .
Aquí se explica cómo implementar una conexión residual en Keras cuando los
tamaños del mapa de características son iguales, utilizando conexiones residuales de
identidad. Este ejemplo asume la existencia de un tensor de entrada 4D x:
de keras importar capas Aplica una transformación a x
x = ...
y = capas.Conv2D(128, 3, activación='relu', relleno='igual')(x)
y = capas.Conv2D(128, 3, activación='relu', relleno='igual')(y)
y = capas.Conv2D(128, 3, activación='relu', relleno='igual')(y)
y =capas.add([y, x])
Vuelve a agregar la x original a
las entidades de salida.

Y lo siguiente implementa una conexión residual cuando los tamaños del mapa de
características difieren, usando una conexión residual lineal (nuevamente,
asumiendo la existencia de un tensor x de entrada 4D):
utiliza un1×1convolución
de keras importar capas para reducir linealmente la
muestra del tensor x original a
x = ... la misma forma que y
y = capas.Conv2D(128, 3, activación='relu', relleno='igual')(x)
y = capas.Conv2D(128, 3, activación='relu', relleno='igual')(y)
y = capas.MaxPooling2D(2, zancadas=2)(y)
residual = capas.Conv2D(128, 1, zancadas=2, relleno='igual')(x)
y = capas.add([y, residual]) Agrega el residuotensor de
vuelta a las características
de salida

Cuellos de botella representacionales en el aprendizaje profundo


en unSecuencialmodelo, cada capa de representación sucesiva se construye sobre
la anterior, lo que significa que solo tiene acceso a la información contenida en la
activación de la capa anterior. Si una capa es demasiado pequeña (por ejemplo,
tiene características que tienen dimensiones demasiado bajas), el modelo estará
limitado por la cantidad de información.ción se puede meter en las activaciones de
esta capa.

Con licencia para


246 CPASADO7Aprendizaje profundo avanzadomejores prácticas

(continuado)
Puede comprender este concepto con una analogía de procesamiento de señales:
si tiene una tubería de procesamiento de audio que consta de una serie de
operaciones, cada una de las cuales toma como entrada la salida de la operación
anterior, entonces si una operación recorta su señal a un rango de baja
frecuencia (por ejemplo, 0–15 kHz), las operaciones posteriores nunca podrán
recuperar las frecuencias caídas. Cualquier pérdida de información es
permanente. Las conexiones residuales, al reinyectar información anterior en
sentido descendente, resuelven parcialmente este problema para los modelos de
aprendizaje profundo.

Gradientes que se desvanecen en el aprendizaje profundo


Backpropagation, el algoritmo maestro utilizado para entrenar redes neuronales
profundas, funciona propagando una señal de retroalimentación desde la pérdida de
salida hasta las capas anteriores. Si este feed-la señal trasera tiene que propagarse
a través de una pila profunda de capas, la señal puede volverse tenue o incluso
perderse por completo, lo que hace que la red no se pueda entrenar. Este
problema se conoce comoGradientes que se desvanecen.
Este problema ocurre tanto con redes profundas como con redes recurrentes sobre
muysecuencias largas: en ambos casos, una señal de retroalimentación debe
propagarse a través de una larga serie de operaciones. Ya está familiarizado con
la solución que elLSTMcapautiliza para abordar este problema en redes
recurrentes: introduce unllevar pistaque propaga la información en paralelo a la
pista de procesamiento principal. Las conexiones residuales funcionan de manera
similar en las redes profundas feedforward, pero son aún más simples:
introducen una pista de transporte de información puramente lineal paralela a la
pila de capas principal, lo que ayuda a propagar gradientes a través de pilas de
capas arbitrariamente profundas.
7.1.5 Compartir peso de capa
Otra característica importante de la API funcional es la capacidad de reutilizar una
instancia de capa varias veces. Cuando llama a una instancia de capa dos veces, en lugar
de crear instancias de una nueva capa para cada llamada, reutiliza los mismos pesos con
cada llamada. Esto le permite crear modelos que tienen ramas compartidas: varias ramas
que comparten el mismo conocimiento y realizan las mismas operaciones. Es decir,
comparten las mismas representaciones y aprenden estas representaciones
simultáneamente para diferentes conjuntos de entradas.
Por ejemplo, considere un modelo que intente evaluar la similitud semántica
entre dos oraciones. El modelo tiene dos entradas (las dos oraciones para comparar)
y genera una puntuación entre 0 y 1, donde 0 significa oraciones no relacionadas y 1
significa oraciones que son idénticas o reformulaciones entre sí. Tal modelo podría
ser útil en muchas aplicaciones, incluida la deduplicación de consultas en lenguaje
natural en un sistema de diálogo.
En esta configuración, las dos oraciones de entrada son intercambiables, porque
la similitud semántica es una relación simétrica: la similitud de A con B es idéntica
a la similitud de B con A. Por esta razón, no tendría sentido aprender dos modelos
independientes para

Con licencia para


Más allá del modelo Secuencial: el funcional de KerasAPI 247

procesar cada frase de entrada. Más bien, desea procesar ambos con una sola capa
LSTM. Las representaciones de esta capa LSTM (sus pesos) se aprenden en función de
ambas entradas simultáneamente. Esto es lo que llamamos un modelo LSTM siamés o
un LSTM compartido.
Aquí se explica cómo implementar un modelo de este tipo mediante el uso
compartido de capas (reutilización de capas) en la API funcional de Keras:
Instancia un
desde keras importar soloCapa LSTM, una
capas desde keras vez
importar Entrada
de keras.models modelo de Construcción de la rama izquierda
del modelo: las entradas son
importación lstm =capas.LSTM(32)
secuencias de longitud variable de
vectores de tamaño128

entrada_izquierda =
Entrada(forma=(Ninguno, 128)) Construyendo la rama derecha del
salida_izquierda = modelo: cuando llama a una instancia de
lstm(entrada_izquierda) capa existente, reutiliza sus pesos.
entrada_derecha =
Entrada(forma=(Ninguna, 128))
salida_derecha = lstm(entrada_derecha)
combinado = capas.concatenar([salida_izquierda, salida_derecha],
eje=-1) predicciones = capas.Densa(1,
activación='sigmoide')(combinado)
modelo = Modelo([entrada_izquierda, entrada_derecha],
predicciones) modelo.ajuste([datos_izquierda,
datos_derecha], objetivos)

Construye el clasificador enparte superior Creación de instancias y entrenamiento del modelo: cuando
entrenar un modelo de este tipo, los pesos de la
capa LSTM se actualizan en función
de ambas entradas.

Naturalmente, una instancia de capa se puede usar más de una vez; se puede llamar
arbitrariamente muchas veces, reutilizando el mismo conjunto de pesos cada vez.

7.1.6 Modelos como capas


Es importante destacar que, en la API funcional, los modelos se pueden usar como si se
usaran capas; de hecho, puede pensar en un modelo como una "capa más grande". Esto
es cierto para las clases Sequential y Model. Esto significa que puede llamar a un
modelo en un tensor de entrada y recuperar un tensor de salida:
y = modelo(x)

Si el modelo tiene múltiples tensores de entrada y múltiples tensores de salida, debe


llamarse con una lista de tensores:
y1, y2 = modelo([x1, x2])

Cuando llama a una instancia de modelo, está reutilizando los pesos del modelo,
exactamente como sucede cuando llama a una instancia de capa. Llamar a una instancia,
ya sea una instancia de capa o una instancia de modelo, siempre reutilizará las

Con licencia para


representaciones aprendidas existentes de la instancia, lo cual es intuitivo.
Un ejemplo práctico simple de lo que puede construir al reutilizar una instancia
de modelo es un modelo de visión que usa una cámara dual como entrada: dos
cámaras paralelas, separadas unos pocos centímetros (una pulgada). Dicho modelo
puede percibir la profundidad, lo que puede ser útil en muchas aplicaciones. No
debería necesitar dos modelos independientes para extraer visual

Con licencia para


248 CPASADO7Aprendizaje profundo avanzadomejores prácticas

características de la cámara izquierda y la cámara derecha antes de fusionar las dos


fuentes. Dicho procesamiento de bajo nivel se puede compartir entre las dos
entradas: es decir, se realiza a través de capas que usan los mismos pesos y, por lo
tanto, comparten las mismas representaciones. Así es como implementaría un
modelo de visión siamesa (base convolucional compartida) en Keras:
de keras importar capas El modelo básico de
de las aplicaciones de procesamiento de imágenes es
importación de keras de la la red Xception (solo base
entrada de importación de convolucional).
keras
xception_base = aplicaciones.Xception(pesos=Ninguno,
include_top=Falso)
entrada_izquierda = Entrada(forma=(250, las entradasson
250, 3)) imágenes de 250 × 250
entrada_derecha = Entrada(forma=(250, RGB.
250, 3))
Llama dos veces al mismo
características_izquierda = modelo de visión
xception_base(entrada_izquierda)
entrada_derecha =
xception_base(entrada_derecha)
merged_features = capas.concatenar(
[características_izquierda,
Las funciones combinadas
entrada_derecha],eje=-1)
contienen información de la
fuente visual derecha y la fuente
visual izquierda.

7.1.7 Terminando
Esto concluye nuestra introducción a la API funcional de Keras, una herramienta
esencial para crear arquitecturas de redes neuronales profundas avanzadas. Ahora ya
sabes lo siguiente:
◾ Para salir de la SecuencialAPIsiempre que necesite algo más que una pila
lineal de capas
◾ Cómo construir modelos de Keras con varias entradas, varias salidas y una
topología de red interna compleja, utilizando el funcional de Keras API
◾ Cómo reutilizar los pesos de una capa o modelo en diferentes ramas de
procesamiento llamando a la misma instancia de capa o modelo varias veces

Con licencia para


Inspeccionar y monitorear modelos de aprendizaje profundo usando devoluciones de llamada de Keras
yTensorTablero 249

7.2 Inspeccionar y monitorear modelos de aprendizaje


profundo usandoDevoluciones de llamada de
Keras y TensorBoard
En esta sección, revisaremos formas de obtener un mayor acceso y control sobre lo
que sucede dentro de su modelo durante el entrenamiento. Iniciar una ejecución de
entrenamiento en un gran conjunto de datos paradecenas de épocas usando model.fit() o
model.fit_generator() puede ser un poco como lanzar un avión de papel: más allá del
impulso inicial, no tienes ningún control sobre su trayectoria o su lugar de aterrizaje. Si
desea evitar malos resultados (y, por lo tanto, aviones de papel desperdiciados), es más
inteligente no usar un avión de papel, sino un dron que pueda sentir su entorno, enviar datos
a su operador y automáticamente tomar decisiones de dirección basadas en su estado actual.
Las técnicas que presentamos aquí transformarán la llamada a model.fit() de un avión de
papel a un dron inteligente y autónomo que puede auto-introspeccionarse y tomar acción
dinámicamente.

7.2.1 Usar devoluciones de llamada para actuar en un modelo durante el entrenamiento


Cuando entrenas a un modelo, hay muchas cosas que no puedes predecir desde el
principio. En particular, no puede saber cuántas épocas se necesitarán para llegar a una
pérdida de validación óptima. Los ejemplos hasta ahora han adoptado la estrategia de
entrenar durante suficientes épocas para comenzar a sobreajustar, usando la primera
ejecución para determinar la cantidad adecuada de épocas para las que entrenar y luego,
finalmente, lanzando una nueva ejecución de entrenamiento desde cero usando este
número óptimo. Por supuesto, este enfoque es un desperdicio.
Una forma mucho mejor de manejar esto es detener el entrenamiento cuando mida
que la pérdida de validación ya no mejora. Esto se puede lograr mediante una
devolución de llamada de Keras. Una devolución de llamada es un objeto (una instancia
de clase que implementa métodos específicos) que se pasa al modelo en la llamada para
ajustar y que el modelo llama en varios puntos durante el entrenamiento. Tiene acceso a
todos los datos disponibles sobre el estado del modelo y su rendimiento, y puede tomar
medidas: interrumpir el entrenamiento, guardar un modelo, cargar un conjunto de pesas
diferente o alterar el estado del modelo.
Estos son algunos ejemplos de formas en que puede usar las devoluciones de llamada:
◾ modelo de puntos de control—Guardar los pesos actuales del modelo en
diferentes puntos del entrenamiento.
◾ Parada temprana—Interrumpir el entrenamiento cuando la pérdida de validación
ya no mejora (y por supuesto, guardar el mejor modelo obtenido durante el
entrenamiento).
◾ Ajustar dinámicamente el valor de ciertos parámetros durante el entrenamiento-Tales
como eltasa de aprendizaje del optimizador.
◾ Registrar métricas de entrenamiento y validación durante el entrenamiento, o
visualizar las representaciones aprendidas por el modelo a medida que se
actualizan—La barra de progreso de Keras con la que está familiarizado es una
devolución de llamada.
El módulo keras.callbacks incluye una serie de devoluciones de llamada integradas (esta no
Con licencia para
es una lista exhaustiva):
keras.callbacks.ModelCheckpointkeras.callbacks.EarlyStoppin
g

Con licencia para


250 CPASADO7Aprendizaje profundo avanzadomejores prácticas

keras.callbacks.LearningRateSchedulerkeras.callbacks.Re
duceLROnPlateau keras.callbacks.CSVLogger

Repasemos algunos de ellos para darle una idea de cómo usarlos: ModeloPunto de
control,Parada Temprana, yReducirLROnPlateau.
TÉLMETROODELCHECKPOINT YmiARLYSMEJORES DEVOLUCIONES DE LLAMADA
Puedes usar elDevolución de llamada EarlyStopping para interrumpir
el entrenamiento una vez que una métrica objetivo que se está
monitoreando ha dejado de mejorar durante un número fijo de
épocas. Por ejemplo, esta devolución de llamada le permite
interrumpir el entrenamiento tan pronto como comience a
sobreajustar, evitando así tener que volver a entrenar su
modelo por un número menor de épocas. Esta devolución de
llamada generalmente se usa en combinación con
ModelCheckpoint, que le permite guardar continuamente el
modelo durante el entrenamiento (y, opcionalmente, guardar
solo el mejor modelo actual hasta el momento: la versión del
modelo que logró el mejor rendimiento al final de una época) :

Las devoluciones de llamada se pasan al modelo a Interrumpe el


través del argumento de devoluciones de llamada entrenamiento
en ajuste, que toma una lista de devoluciones de cuandoparadas de
llamada. Puede pasar cualquier número de mejora
devoluciones de llamada.
Supervisa el
importar keras modeloprecisión de
validación
callbacks_list = [
keras.callbacks.EarlyStopping( Interrumpe el
entrenamientocuando la
precisión se ha detenido
monitor='cuenta', mejorando para mas de uno
paciencia=1 época (es decir, dos épocas)
,
),
keras.callbacks.ModelCheckpoint( Guarda los pesos actuales después de cada
filepath='my_model.h5', época Ruta al archivo del modelo de destino
monitor='val_loss',
save_best_only=True, Estos dos argumentos significan que no sobrescribirá el
) archivo del modelo a menos que val_loss haya mejorado,
] lo que le permite mantener el mejor modelo visto
durante el entrenamiento.
modelo.compilar(optimizador='rmsprop', TÉLREDUCIRLROnortePAGSDEVOLUCIÓN
loss='binary_crossentropy', DE LLAMADA LATEAU
métricas=['acc'])
modelo.ajuste(x, y,
épocas=10,
tamaño_lote=32,
devoluciones de
llamada=lista_de
devoluciones de llamada,
validación_datos=(x_val,
y_val))

Con licencia para


de llamada controlará la pérdida de
Supervisa la precisión, por lo que debería ser validación y la precisión de la
parte de las métricas del modelo. validación, debe pasar la
validación_datos a la llamada para
que se ajuste.
Tenga en cuenta que debido a que la devolución
Puede usar esta devolución de llamada para reducir la tasa de aprendizaje cuando la
pérdida de validación ha dejado de mejorar. Reducir o aumentar la tasa de aprendizaje
en caso de meseta de pérdida es una estrategia efectiva para salir de los mínimos locales
durante el entrenamiento. El siguiente ejemplo utiliza la devolución de llamada
ReduceLROnPlateau:

Con licencia para


Inspeccionar y monitorear modelos de aprendizaje profundo usando devoluciones de llamada de Keras
yTensorTablero 251

callbacks_list = [ Supervisa la pérdida


keras.callbacks.ReduceLROnPlateau de validación del
( modelo.
monitor='valor_pérdida'
factor=0.1, Divide la tasa de aprendizaje por10 cuando se activa
paciencia=10
, La devolución de llamada se activa después de
)
que la pérdida de validación haya dejado de
mejorar para10 épocas.
]
modelo.ajuste(x, y,
épocas=10, Debido a que la devolución de
tamaño_lote=32,
llamada monitoreará la pérdida
de validación, debe pasar
devoluciones de
validation_data a la llamada para
llamada=lista_de que se ajuste.
devoluciones de llamada,
validación_datos=(x_val,
y_val))

WESCRIBIR SU PROPIA DEVOLUCIÓN DE LLAMADA


Si necesita realizar una acción específica durante el entrenamiento que no está
cubierta por una de las devoluciones de llamada integradas, puede escribir su propia
devolución de llamada. Las devoluciones de llamada son implementadas por sub-
clasificar la clase keras.callbacks.Callback. Luego puede implementar cualquier número de
los siguientes métodos con nombres transparentes, que se llaman en varios puntos durante el
entrenamiento:
en_epoch_begin Llamado al comienzo de cada época
al_final_de_la Llamado al final de cada época
_época
Llamado justo antes de procesar cada lote
en_batch_begin Llamado justo después de procesar cada lote
al_final_del_l
ote Llamado al inicio del
entrenamiento Llamado al final del
en_tren_comien entrenamiento
zoal_final_del
_tren

Todos estos métodos se llaman con un argumento de registros, que es un diccionario


que contiene información sobre el lote, la época o la ejecución de entrenamiento
anterior: métricas de entrenamiento y validación, etc. Además, la devolución de llamada
tiene acceso a los siguientes atributos:
◾ auto.modelo: la instancia del modelo desde la que se llama a la devolución de llamada
◾ self.validation_data—El valor de lo que se pasó a adaptarcomo datos de validación

Aquí hay un ejemplo simple de una devolución de llamada personalizada que guarda en
el disco (como matrices Numpy) las activaciones de cada capa del modelo al final de
cada época, calculadas en la primera muestra del conjunto de validación:
importar keras def
importar numpy set_model(s
como np elf,
modelo):
clase ActivationLogger(keras.callbacks.Callback): self.mo

Con licencia para


delo =modelo

Llamado por el modelo


principal antes del
entrenamiento, para
informar a la devolución de
llamada qué modelo lo
llamará
salidas_capa = [capa.salida para capa en modelo.capas]
self.activaciones_modelo =
keras.modelos.Modelo(modelo.entrada,
capas_salidas)
def on_epoch_end(self, epoch, Instancia de
logs=Ninguno): si modelo que
self.validation_data es Ninguno: devuelve las
aumentar RuntimeError ('Requiere activaciones de
validación_datos.') cada capa

Con licencia para


252 CPASADO7Aprendizaje profundo avanzadomejores prácticas

validación_muestra = self.validation_data[0][0:1]
activaciones =
self.activations_model.predict(validation_sample) f =
open('activations_at_epoch_' + str(epoch) + '.npz', 'w')
np.savez(f, activaciones)
f.cerrar()

Obtiene la primera muestra de Guarda matrices en


entrada de los datos de
el disco
validación

Esto es todo lo que necesita saber sobre las devoluciones de llamada; el resto son
detalles técnicos, que puede buscar fácilmente. Ahora está equipado para realizar
cualquier tipo de registro o intervención preprogramada en un modelo Keras durante el
entrenamiento.

7.2.2 Introducción a TensorBoard:


el marco de visualización de TensorFlow
Para hacer una buena investigación o desarrollar buenos modelos, necesita
comentarios ricos y frecuentes sobre lo que sucede dentro de sus modelos durante
sus experimentos. Ese es el objetivo de realizar experimentos: obtener información
sobre qué tan bien funciona un modelo, tanta información como sea posible.
Progresar es un proceso iterativo o ciclo: comienzas con una idea y la expresas
como un experimento, intentando validar o invalidar tu idea. Usted ejecuta este
experimento y procesa la información que genera. Esto inspira tu próxima idea.
Cuantas más iteraciones de este bucle pueda ejecutar, más refinadas y poderosas
serán sus ideas. Keras lo ayuda a pasar de la idea al experimento en el menor tiempo
posible, y las GPU rápidas pueden ayudarlo a pasar del experimento al resultado lo
más rápido posible. Pero, ¿qué pasa con el procesamiento de los resultados del
experimento? Ahí es donde entra Tensor-Board.

Ocurrencia

Marco de Marco de
visualización aprendizaje
: profundo:
TensorBoar Keras
d

Resultados
Experiment
o Figura 7.9 El bucle del progreso
Infraestructura

Esta sección presenta TensorBoard, una herramienta de visualización basada en


navegador que viene con TensorFlow. Tenga en cuenta que solo está disponible para los
modelos de Keras cuando usa Keras con el backend de TensorFlow.
El propósito clave de TensorBoard es ayudarlo a monitorear visualmente todo lo
que sucede dentro de su modelo durante el entrenamiento. Si está monitoreando más
Con licencia para
información que solo la pérdida final del modelo, puede desarrollar una visión más
clara de lo que hace y lo que no hace el modelo, y puede progresar más
rápidamente. TensorBoard le brinda acceso a varias funciones interesantes, todas en
su navegador:

Con licencia para


Inspeccionar y monitorear modelos de aprendizaje profundo usando devoluciones de llamada de Keras
yTensorTablero 253

◾ Supervisión visualmétricas durante el entrenamiento


◾ Visualización de la arquitectura de su modelo
◾ Visualización de histogramas de activaciones y gradientes
◾ Explorando incrustaciones en 3D

Demostremos estas características en un ejemplo simple. Capacitará a un convnet 1D en


la tarea de análisis de opinión de IMDB.
El modeloes similar al que vio en la última sección del capítulo 6. Considerará
solo las 2000 palabras principales en el vocabulario de IMDB, para que la
visualización de incrustaciones de palabras sea más manejable.

Listado 7.7 Modelo de clasificación de texto para usar con TensorBoard

importar kera
de keras importar capas Númerode palabras
desde keras.datasets importar imdb a considerar como
de la secuencia de importación de características
keras.preprocessing Corta los textos después de esta
max_features = 2000 cantidad de palabras (entre
longitud_máx = 500
max_features palabras más
comunes)
(x_train, y_train), (x_test, y_test) = imdb.load_data(num_words=max_features)
x_train = secuencia.pad_sequences(x_train, maxlen=max_len)
x_test = secuencia.pad_secuencias(x_test, maxlen=max_len)
modelo = keras.models.Sequential()
model.add(layers.Embedding(max_features, 128,
input_length=max_len,nombre='inc
rustar'))
modelo.add(capas.Conv1D(32, 7, activación='relu'))
modelo.add(capas.MaxPooling1D(5))
modelo.add(capas.Conv1D(32, 7, activación='relu'))
modelo .add(layers.GlobalMaxPooling1D())
modelo.add(layers.Dense(1))
modelo.resumen()
modelo.compile(optimizador='rmsprop',
loss='binary_crossentropy',métricas=['a
cc'])

Antes de comenzar a usar TensorBoard, debe crear un directorio donde almacenará


los archivos de registro que genera.

Listado 7.8 Creando un directorio para los archivos de registro de TensorBoard

psmkdir mi_log_dir

Iniciemos el entrenamiento con una instancia de devolución de llamada de TensorBoard.


Esta devolución de llamada escribirá eventos de registro en el disco en la ubicación
especificada.

Con licencia para


254 CPASADO7Aprendizaje profundo avanzadomejores prácticas

Listado 7.9 Entrenando el modelo con unTensorTablerollamar de vuelta

devoluciones de llamada = [ Los archivos de registro


keras.callbacks.TensorBoard(log_d se escribirán en esta
ir='my_log_dir', ubicación.
histogram_freq=1,
incrustaciones_freq=1, Registra histogramas de activación cada1época
)
]
Registra datos de
historia = modelo.ajuste(x_tren,
incrustación
y_tren,
cada1época
épocas=20,
tamaño_lote=128
,
validación_dividir=0.2,devoluciones de
llamada = devoluciones de llamada)

En este punto, puede iniciar el servidor TensorBoard desde la línea de comando,


indicándole que lea los registros que está escribiendo actualmente la devolución de
llamada. La utilidad tensorboard debería haberse instalado automáticamente en su
máquina en el momento en que instaló TensorFlow (por ejemplo, a través de pip):
pstensorboard --logdir=my_log_dir
A continuación, puede navegar hasta http://localhost:6006 y ver el entrenamiento de
su modelo (consulte la figura 7.10). Además de los gráficos en vivo de las métricas
de entrenamiento y validación, tiene acceso a la pestaña Histogramas, donde puede
encontrar bonitas visualizaciones de histogramas de valores de activación tomados
por sus capas (consulte la figura 7.11).

Figura 7.10 TensorBoard: monitoreo de métricas

Con licencia para


Inspeccionar y monitorear modelos de aprendizaje profundo usando devoluciones de llamada de Keras
yTensorTablero 255

Figura 7.11 TensorBoard: histogramas de activación

La pestaña Incrustaciones le brinda una manera de inspeccionar las ubicaciones de


incrustación y las relaciones espaciales de las 10,000 palabras en el vocabulario de
entrada, según lo aprendido por la capa de incrustación inicial. Debido a que el
espacio de incrustación tiene 128 dimensiones, TensorBoard lo reduce
automáticamente a 2D o 3D usando un algoritmo de reducción de dimensionalidad
de su elección: ya sea análisis de componentes principales (PCA) o incrustación de
vecinos estocásticos distribuidos en t (t-SNE). En la figura 7.12, en la nube de
puntos, se pueden ver claramente dos clusters: palabras con connotación positiva y
palabras con connotación negativa. La visualización hace inmediatamente obvio que
las incorporaciones entrenadas conjuntamente con un objetivo específico dan como
resultado modelos que son completamente específicos para la tarea subyacente; esa
es la razón por la cual usar incrustaciones de palabras genéricas previamente
entrenadas rara vez es una buena idea.

Con licencia para


256 CPASADO7Aprendizaje profundo avanzado mejorprácticas

Figura 7.12 TensorBoard: visualización interactiva de incrustación de palabras en 3D

La pestaña Gráficos muestra una visualización interactiva del gráfico de las operaciones
de TensorFlow de bajo nivel subyacentes a su modelo de Keras (consulte la figura
7.13). Como puede ver, están sucediendo muchas más cosas de las que cabría esperar.
El modelo que acaba de crear puede parecer simple cuando se define en Keras (una
pequeña pila de capas básicas), pero bajo el capó, necesita construir una estructura
gráfica bastante compleja para que funcione. Mucho de esto está relacionado con el
proceso de descenso de gradiente. Este diferencial de complejidad entre lo que ve y lo
que está manipulando es la motivación clave para usar Keras como su forma de
construir modelos, en lugar de trabajar con TensorFlow sin procesar para definir todo
desde cero. Keras simplifica enormemente su flujo de trabajo.

Con licencia para


Inspeccionar y monitorear modelos de aprendizaje profundo usando devoluciones de llamada de Keras
yTensorTablero 257

Figura 7.13 TensorBoard: visualización de gráficos de TensorFlow

Tenga en cuenta que Keras también proporciona otra forma más limpia de trazar
modelos como gráficos de capas en lugar de gráficos de operaciones de TensorFlow: la
utilidad keras.utils.plot_model.Su uso requiere que haya instalado las bibliotecas Python
pydot y pydot-ng, así como la biblioteca graphviz. Echemos un vistazo rápido:
de keras.utils import plot_model
plot_model(modelo,
to_file='model.png')

Esto crea el PNGimagen que se muestra en la figura 7.14.

Con licencia para


258 CPASADO7Aprendizaje profundo avanzadomejores prácticas

Figura 7.14 Una gráfica modelo como un gráfico de


capas,generado conmodelo_parcela

También tienes la opción de mostrar información de forma en el gráfico de capas.


EsteEl ejemplo visualiza la topología del modelo usando plot_model y la opción
show_shapes (ver figura 7.15):
de keras.utils importar plot_model
plot_model(modelo, mostrar_formas=Verdadero, to_file='modelo.png')

Con licencia para


Inspeccionar y monitorear modelos de aprendizaje profundo usando devoluciones de llamada de Keras
yTensorTablero 259

Figura 7.15 Una gráfica modelo con información de forma

7.2.3 Terminando
◾ Las devoluciones de llamada de Keras brindan una manera simple de monitorear
modelos durante el entrenamiento y tomar medidas automáticamente según el
estado del modelo.
◾ Cuando usa TensorFlow, TensorBoard es una excelente manera de visualizar el
modeloactividad en su navegador. Puedes usarlo en los modelos Keras a través de
laTensorTablerollamar de vuelta.

Con licencia para


260 CPASADO7Aprendizaje profundo avanzadomejores prácticas

7.3 Saca el máximo partido a tus modelos


Probar arquitecturas a ciegas funciona lo suficientemente bien si solo necesita algo
que funcione bien. En esta sección, iremos más allá de "funciona bien" a "funciona
muy bien y gana competencias de aprendizaje automático" ofreciéndole una guía
rápida de un conjunto de técnicas imprescindibles para crear aprendizaje profundo
de última generación. modelos

7.3.1 Patrones de arquitectura avanzada


Cubrimos un patrón de diseño importante en detalle en la sección anterior:
conexiones residuales. Hay dos patrones de diseño más que debe conocer: la
normalización y la convolución separable en profundidad. Estos patrones son
especialmente relevantes cuando crea redes de comunicación profundas de alto
rendimiento, pero también se encuentran comúnmente en muchos otros tipos de
arquitecturas.
BNORMALIZACIÓN DE VISUALIZACIÓN
Normalizaciónes una categoría amplia de métodos que buscan hacer que diferentes
muestras vistas por un modelo de aprendizaje automático sean más similares entre sí, lo
que ayuda al modelo a aprender y generalizar bien a nuevos datos. La forma más común
de normalización de datos es una que ya ha visto varias veces en este libro: centrar los
datos en 0 restando la media de los datos y dando a los datos una desviación estándar
unitaria dividiendo los datos por su desviación estándar. En efecto, esto supone que los
datos siguen una distribución normal (o gaussiana) y asegura que esta distribución esté
centrada y escalada a la varianza unitaria:
datos_normalizados = (datos - np.mean(datos, eje=...)) / np.std(datos, eje=...)

Los ejemplos anteriores normalizaron los datos antes de introducirlos en los modelos.
Pero la normalización de los datos debe ser una preocupación después de cada
transformación operada por la red: incluso si los datos que ingresan a una red Dense o
Conv2D tienen una media y una varianza unitaria de 0, no hay razón para esperar a
priori que este será el caso para la red. datos que salen.
La normalización por lotes es un tipo de capa (BatchNormalization en Keras)
introducida en 2015 por Ioffe y Szegedy;7 puede normalizar datos de forma adaptativa
incluso cuando la media y la varianza cambian con el tiempo durante el entrenamiento.
Funciona manteniendo internamente un promedio móvil exponencial de la media por lotes y
la varianza de los datos vistos durante el entrenamiento. El efecto principal de la
normalización por lotes es que ayuda con la propagación de gradientes, al igual que las
conexiones residuales, y por lo tanto permite redes más profundas. Algunas redes muy
profundas solo se pueden entrenar si incluyen varias capas de BatchNormalization. Por
ejemplo, BatchNormalization se usa generosamente en muchas de las arquitecturas de
convnet avanzadas que vienen empaquetadas con Keras, como ResNet50, Inception V3 y
Xception.

7 Sergey Ioffe y Christian Szegedy, “Normalización por lotes: Aceleración del entrenamiento de redes profundas al reducir el cambio interno de covariables”, Actas de la 32.ª
Conferencia internacional sobre aprendizaje automático (2015),
https://arxiv.org/abs/1502.03167.

Con licencia para


Sacar el máximo partido a sumodelos 261

La capa BatchNormalization generalmente se usa después de una capa convolucional o


densamente conectada:
conv_model.add(capas.Conv2D(32, 3, activación='relu')) Después de una
conv_model.add(capas.BatchNormalization())

modelo_denso.add(capas.Dense(32, activación='relu')) capa Conv Después de


modelo_denso.add(capas.Normalización por lotes())
una capa Densa

losNormalización por lotescapa toma unejeargumento, que especifica el eje de


características que debe normalizarse. Este argumento tiene como valor predeterminado -1,
el último eje en el tensor de entrada. Este es el valor correcto cuando se
usaDensocapas,Conv1Dcapas,RNNcapas, yConv2Dcapas conformato de datosajustado
a"canales_último". Pero en el caso de uso de nicho de Conv2Dcapas conformato de
datosajustado a"canales_primero", el eje de características es el eje 1;laejeargumento
enNormalización por lotesen consecuencia, debe establecerse en 1.

Renormalización por lotes


Una mejora reciente sobrela normalización por lotes regular esrenormalización por
lotes, presentado por Ioffe en 2017.aOfrece claros beneficios sobre la normalización
por lotes, sin costo aparente.costo ent. En el momento de redactar este informe,
es demasiado pronto para saber si sustituirá a batchnormalización, pero creo que es
probable. Incluso más recientemente, Klambauer et al. introducidoredes neuronales
autonormalizantes,bque logran mantener los datos normalizados después de pasara
través de cualquierDensocapa usando una función de activación específica (selu) y un
inicializador específico (lecun_normal). Este esquema, aunque muy interesante, se
limita a densamenteredes conectadas por ahora, y su utilidad aún no se ha replicado
ampliamente.

a Sergey Ioffe, “Renormalización de lotes: hacia la reducción de la dependencia de minilotes en modelos normalizados por lotes”
(2017),
https://arxiv.org/abs/1702.03275.
b Günter Klambauer et al., “Self-Normalizing Neural Networks,” Conferencia sobre Información Neural
Sistemas de procesamiento
de información (2017),https://arxiv.org/abs/1706.02515.
DCONVOLUCIÓN SEPARABLE POR EPTIMO
¿Qué pasaría si le dijera que hay una capa que puede usar como reemplazo directo de
Conv2D que hará que su modelo sea más liviano (menos parámetros de peso
entrenables) y más rápido (menos operaciones de punto flotante) y hará que funcione en
algunos puntos porcentuales? mejor en su tarea? Eso es precisamente lo que hace la
capa de convolución separable en profundidad (SeparableConv2D). Esta capa realiza
una convolución espacial en cada canal de su entrada, de forma independiente, antes de
mezclar los canales de salida a través de una convolución puntual (una convolución 1 ×
1), como se muestra en la figura 7.16. Esto es equivalente a separar el aprendizaje de las
características espaciales y el aprendizaje de las características del canal, lo que tiene
mucho sentido si asume que las ubicaciones espaciales en la entrada están altamente
correlacionadas, pero los diferentes canales son bastante independientes. Requiere
significativamente menos parámetros e involucra menos cálculos, lo que da como
resultado modelos más pequeños y más rápidos. Y debido a que es una forma más

Con licencia para


eficiente desde el punto de vista de la representación para realizar la convolución, tiende
a aprender mejores representaciones utilizando menos datos, lo que da como resultado
modelos con un mejor rendimiento.

Con licencia para


262 CPASADO7Aprendizaje profundo avanzadomejores prácticas

1 × 1 conv
(conv puntual)

Concatenar
Convolución en profundidad:
espacial independiente
conversión 3 × 3 3× 3 conv3 ×3 conversió conversiones por canal
conversión n3×3

Figura 7.16 Convolución separable


Dividir canales
en profundidad: una convolución
en profundidad seguida de una
convolución en punto

Estas ventajas se vuelven especialmente importantes cuando entrena modelos pequeños


desde cero con datos limitados. Por ejemplo, así es como puede crear una convnet
separable en profundidad y liviana para una tarea de clasificación de imágenes
(clasificación categórica softmax) en un pequeño conjunto de datos:
desde keras.models import Sequential,
Model from keras import layers
altura = 64
ancho = 64
canales = 3
num_clases = 10

modelo = Sequential()
model.add(layers.SeparableConv2D(32, 3,
activación='relu',
input_shape=(alto, ancho, canales,)))
modelo.añadir(capas.SeparableConv2D(64, 3, activación='relu'))
modelo.añadir(capas.MaxPooling2D(2))

modelo.add(capas.SeparableConv2D(64, 3, activación='relu'))
modelo.añadir(capas.SeparableConv2D(128, 3,
activación='relu')) modelo.añadir(capas.MaxPooling2D(2))

modelo.add(capas.SeparableConv2D(64, 3, activación='relu'))
modelo.add(capas.SeparableConv2D(128, 3, activación='relu'))
modelo.add(capas.GlobalAveragePooling2D())

modelo.add(capas.Dense(32, activación='relu'))
modelo.add(capas.Denso(núm_clases, activación='softmax'))

modelo.compile(optimizador='rmsprop', pérdida='categorical_crossentropy')

Cuando se trata de modelos a mayor escala, las circunvoluciones separables en


profundidad son la base de la arquitectura Xception, una convnet de alto
rendimiento que viene empaquetada con Keras. Puede leer más sobre la base teórica
para separables en profundidad

Con licencia para


Sacar el máximo partido a sumodelos 263

convoluciones y Xception en mi artículo “Xception: aprendizaje profundo con


convoluciones separables en profundidad”. 8

7.3.2 hiperparámetro mejoramiento


Al construir un modelo de aprendizaje profundo, debe tomar muchas decisiones
aparentemente arbitrarias: ¿Cuántas capas debe apilar? ¿Cuántas unidades o filtros
deben ir en cada capa? ¿Debería usar relu como activación o una función diferente?
¿Deberías usarBatchNormalization después de una capa dada? ¿Cuánta
caída debería usar? Y así. Estos parámetros de nivel de
arquitectura se denominan hiperparámetros para distinguirlos de
los parámetros de un modelo, que se entrenan mediante
retropropagación.
En la práctica, los ingenieros e investigadores experimentados en aprendizaje
automático crean intuición con el tiempo sobre lo que funciona y lo que no cuando
se trata de estas opciones: desarrollan habilidades de ajuste de hiperparámetros.
Pero no hay reglas formales. Si desea llegar al límite de lo que se puede lograr en
una tarea determinada, no puede contentarse con elecciones arbitrarias hechas por
un ser humano falible. Sus decisiones iniciales casi siempre son subóptimas, incluso
si tiene una buena intuición. Puede refinar sus opciones ajustándolas a mano y
volviendo a entrenar el modelo repetidamente; eso es lo que los ingenieros e
investigadores de aprendizaje automático pasan la mayor parte de su tiempo
haciendo. Pero no debería ser su trabajo como ser humano jugar con los
hiperparámetros todo el día; eso es mejor dejarlo en manos de una máquina.
Por lo tanto, debe explorar el espacio de las posibles decisiones de forma
automática, sistemática y basada en principios. Debe buscar en el espacio de la
arquitectura y encontrar empíricamente las que mejor funcionan. De eso se trata el
campo de la optimización automática de hiperparámetros: es todo un campo de
investigación, y muy importante.
El proceso de optimización de hiperparámetros suele tener este aspecto:
1Elija un conjunto de hiperparámetros (automáticamente).
2Construye el modelo correspondiente.
3Ajústelo a sus datos de entrenamiento y mida el rendimiento final con los datos
de validación.
4Elija el siguiente conjunto de hiperparámetros para probar (automáticamente).

5Repetir.

6Eventualmente, mida el rendimiento en sus datos de prueba.

La clave de este proceso es el algoritmo que utiliza este historial de rendimiento de


validación, dados varios conjuntos de hiperparámetros, para elegir el siguiente
conjunto de hiperparámetros para evaluar. Son posibles muchas técnicas diferentes:
optimización bayesiana, algoritmos genéticos, búsqueda aleatoria simple, etc.
Entrenar los pesos de un modelo es relativamente fácil: calcula una función de
pérdida en un mini lote de datos y luego usa el algoritmo Backpropagation para mover
los pesos.

Con licencia para


8 Véase la nota 5 anterior.

Con licencia para


264 CPASADO7Aprendizaje profundo avanzadomejores prácticas

en la dirección correcta. Actualizar hiperparámetros, por otro lado, es


extremadamente desafiante. Considera lo siguiente:
◾ Calcular la señal de retroalimentación (¿este conjunto de hiperparámetros
conduce a un modelo de alto rendimiento en esta tarea?) puede ser
extremadamente costoso: requiere crear y entrenar un nuevo modelo desde
cero en su conjunto de datos.
◾ El espacio de hiperparámetros normalmente está formado por decisiones
discretas y, por lo tanto, no es continuo ni diferenciable. Por lo tanto,
normalmente no puede hacer un descenso de gradiente en el espacio de
hiperparámetros. En su lugar, debe confiar en las técnicas de optimización sin
gradientes, que naturalmente son mucho menos eficientes que el descenso de
gradientes.
Debido a que estos desafíos son difíciles y el campo aún es joven, actualmente solo
tenemos acceso a herramientas muy limitadas para optimizar modelos. A menudo,
resulta que la búsqueda aleatoria (elegir hiperparámetros para evaluar al azar,
repetidamente) es la mejor solución, a pesar de ser la más ingenua. Pero una
herramienta que he encontrado confiablemente mejor que aleatoriala búsqueda es
Hyperopt (https://github.com/hyperopt/hyperopt),una biblioteca de Python para la
optimización de hiperparámetros que utiliza internamente árboles de estimadores de Parzen
para predecir conjuntos de hiperparámetros que probablemente funcionen bien. Otra
biblioteca llamada Hyperas (https://github.com/maxpumperla/hyperas)integra
Hyperopt para usar con modelos Keras. Compruébalo.

NOTAUna cuestión importante a tener en cuenta al realizar la optimización


automática de hiperparámetros a escala es el sobreajuste del conjunto de
validación. Debido a que está actualizando los hiperparámetros en función
de una señal que se calcula utilizando sus datos de validación, los está
entrenando de manera efectiva en los datos de validación y, por lo tanto, se
sobreajustarán rápidamente a los datos de validación. Siempre tenga esto en
cuenta.

En general, la optimización de hiperparámetros es una técnica poderosa que es un


requisito absoluto para obtener modelos de última generación en cualquier tarea o
para ganar competencias de aprendizaje automático. Piénselo: érase una vez, las
personas crearon a mano las funciones que se incluyeron en modelos superficiales
de aprendizaje automático. Eso fue muy subóptimo. Ahora, el aprendizaje profundo
automatiza la tarea de la ingeniería de funciones jerárquicas: las funciones se
aprenden mediante una señal de retroalimentación, no se ajustan a mano, y así es
como debe ser. De la misma manera, no debe fabricar sus arquitecturas modelo a
mano; debe optimizarlos de una manera basada en principios. Al momento de
escribir este artículo, el campo de la optimización automática de hiperparámetros es
muy joven e inmaduro, como lo fue el aprendizaje profundo hace algunos años,
pero espero que crezca en los próximos años.

7.3.3 montaje de modelos


Otra técnica poderosa para obtener los mejores resultados posibles en una tarea es el
Con licencia para
ensamblaje de modelos. El conjunto consiste en agrupar las predicciones de un
conjunto de diferentes modelos para producir mejores predicciones. Si observa las
competencias de aprendizaje automático, en particular en Kaggle, verá que los
ganadores usan conjuntos muy grandes de modelos que inevitablemente superan a
cualquier modelo, sin importar cuán bueno sea.

Con licencia para


Sacar el máximo partido a sumodelos 265

El conjunto se basa en la suposición de que es probable que diferentes buenos


modelos entrenados de forma independiente sean buenos por diferentes razones:
cada modelo analiza aspectos ligeramente diferentes de los datos para hacer sus
predicciones, obteniendo parte de la "verdad" pero no toda la información. eso.
Puede que esté familiarizado con la antigua parábola de los ciegos y el elefante: un
grupo de ciegos se encuentra con un elefante por primera vez y trata de entender qué
es el elefante tocándolo. Cada hombre toca una parte diferente del cuerpo del
elefante, solo una parte, como la trompa o una pata. Luego, los hombres se
describen unos a otros qué es un elefante: “Es como una serpiente”, “Como un pilar
o un árbol”, etc. Los ciegos son esencialmente modelos de aprendizaje automático
que intentan comprender la variedad de datos de entrenamiento, cada uno desde su
propia perspectiva. utilizando sus propios supuestos (proporcionados por la
arquitectura única del modelo y la inicialización de peso aleatorio única). Cada uno
de ellos obtiene parte de la verdad de los datos, pero no toda la verdad. Al agrupar
sus perspectivas, puede obtener una descripción mucho más precisa de los datos. El
elefante es una combinación de partes: ningún ciego lo entiende del todo bien, pero,
entrevistados juntos, pueden contar una historia bastante precisa.
Usemos la clasificación como ejemplo. La forma más fácil de agrupar las
predicciones de un conjunto de clasificadores (para ensamblar los clasificadores) es
promediar sus predicciones en el momento de la inferencia:
Utilice cuatro modelos diferentes para calcular las predicciones iniciales.
preds_a = modelo_a.predict(x_val)
preds_b = model_b.predict(x_val) Esta nueva matriz de
preds_c = model_c.predict(x_val) predicción debería ser más
preds_d = model_d.predict(x_val) precisa que cualquiera de
las iniciales.
finales_preds = 0,25 * (preds_a + preds_b + preds_c + preds_d)

Esto funcionará solo si los clasificadores son más o menos igualmente buenos. Si uno
de ellos es significativamente peor que los demás, las predicciones finales pueden no ser
tan buenas como las del mejor clasificador del grupo.
Una forma más inteligente de agrupar clasificadores es hacer un promedio
ponderado, donde los pesos se aprenden en los datos de validación; por lo general, los
mejores clasificadores reciben un peso más alto y los peores clasificadores reciben un
peso más bajo. Para buscar un buen conjunto de pesos de conjunto, puede utilizar la
búsqueda aleatoria o un algoritmo de optimización simple como Nelder-Mead:
preds_a = modelo_a.predict(x_val)
preds_b = Estos pesos (0.5, 0.25,
model_b.predict(x_val) preds_c 0.1, 0.15) sonSe supone
= model_c.predict(x_val) que se aprende
preds_d = empíricamente.
model_d.predict(x_val)
final_preds = 0,5 * preds_a + 0,25 * preds_b + 0,1 * preds_c + 0,15 * preds_d

Hay muchas variantes posibles: puedes hacer un promedio de una exponencial de


las predicciones, por ejemplo. En general, un promedio ponderado simple con pesos
optimizados en los datos de validación proporciona una base de referencia muy
Con licencia para
sólida.
La clave para hacer que el ensamblaje funcione es la diversidad del conjunto de
clasificadores. La diversidad es fuerza. Si todos los ciegos tocaran la trompa del
elefante, estarían de acuerdo

Con licencia para


266 CPASADO7Aprendizaje profundo avanzadomejores prácticas

que los elefantes son como serpientes, y que siempre permanecerían ignorantes de
la verdad del elefante. La diversidad es lo que hace que el ensamblaje funcione. En
términos de aprendizaje automático, si todos sus modelos están sesgados de la
misma manera, su conjunto conservará este mismo sesgo. Si sus modelos están
sesgados de diferentes maneras, los sesgos se anularán entre sí y el conjunto será
más sólido y preciso.
Por esta razón, debe ensamblar modelos que sean lo mejor posible y que sean lo más
diferentes posible. Esto generalmente significa usar arquitecturas muy diferentes o
incluso diferentes marcas de enfoques de aprendizaje automático. Una cosa que en gran
medida no vale la pena hacer es ensamblar la misma red entrenada varias veces de
forma independiente, a partir de diferentes inicializaciones aleatorias. Si la única
diferencia entre sus modelos es su inicialización aleatoria y el orden en que fueron
expuestos a los datos de entrenamiento, entonces su conjunto será de baja diversidad y
proporcionará solo una pequeña mejora sobre cualquier modelo único.
Una cosa que he encontrado que funciona bien en la práctica, pero que no se
generaliza a todos los dominios de problemas, es el uso de un conjunto de métodos
basados en árboles (como bosques aleatorios o árboles potenciados por gradientes)
y redes neuronales profundas. . En 2014, mi socio Andrei Kolev y yo obtuvimos el
cuarto lugar en el desafío de detección de descomposición del bosón de Higgs en
Kaggle.(www.kaggle.com/c/higgs-boson)utilizando un conjunto de varios modelos
de árboles y redes neuronales profundas. Sorprendentemente, uno de los modelos
del conjunto se originó a partir de un método diferente al de los demás (era un
bosque codicioso regularizado) y obtuvo una puntuación significativamente peor
que los demás. Como era de esperar, se le asignó un pequeño peso en el conjunto.
Pero, para nuestra sorpresa, resultó mejorar el conjunto general en gran medida,
porque era muy diferente de cualquier otro modelo: proporcionaba información a la
que los otros modelos no tenían acceso. Ese es precisamente el punto de ensamblar.
No se trata tanto de cuán bueno es tu mejor modelo; se trata de la diversidad de su
conjunto de modelos candidatos.
En tiempos recientes, un estilo de conjunto básico que ha tenido mucho éxito en
la práctica es la categoría amplia y profunda de modelos, que combina el
aprendizaje profundo con el aprendizaje superficial. Dichos modelos consisten en
entrenar conjuntamente una red neuronal profunda con un gran modelo lineal. El
entrenamiento conjunto de una familia de modelos diversos es otra opción más para
lograr el ensamblaje de modelos.

7.3.4 Terminando
◾ Al construir alto rendimientoconexiones profundas, necesitará usar
conexiones residuales, normalización por lotes y convoluciones separables en
profundidad. En el futuro, es probable que las circunvoluciones separables en
profundidad reemplacen por completo a las circunvoluciones regulares, ya sea
para1D,2D, o3Daplicaciones, debido a su mayor eficiencia representacional.
◾ La construcción de redes profundas requiere hacer muchas elecciones
pequeñas de arquitectura e hiperparámetros, que en conjunto definen qué tan
bueno será su modelo. En lugar de basar estas elecciones en la intuición o en

Con licencia para


el azar, es mejor buscar sistemáticamente en el espacio de hiperparámetros
para encontrar opciones óptimas. En este

Con licencia para


Sacar el máximo partido a sumodelos 267

tiempo, el proceso es costoso y las herramientas para hacerlo no son muy


buenas. Pero las bibliotecas Hyperopt y Hyperas pueden ayudarlo. Al realizar
la optimización de hiperparámetros, tenga en cuenta el sobreajuste del
conjunto de validación.
◾ Ganar competencias de aprendizaje automático u obtener los mejores
resultados posibles en una tarea solo se puede lograr con grandes conjuntos de
modelos. El conjunto a través de un promedio ponderado bien optimizado
suele ser lo suficientemente bueno. Recuerda: la diversidad es fuerza. Es en
gran medida inútil ensamblar modelos muy similares; los mejores conjuntos
son conjuntos de modelos que son lo más diferentes posible (mientras que
tienen tanto poder predictivo como sea posible, naturalmente).

Con licencia para


268 CPASADO7Aprendizaje profundo avanzadomejores prácticas

Resumen del capítulo


◾ En este capítulo, aprendió lo siguiente:
– Cómo construir modelos como gráficos arbitrarios de capas, reutilizar
capas (compartir el peso de las capas) y usar modelos como funciones
de Python (plantillas de modelos).
– Puede usar las devoluciones de llamada de Keras para monitorear sus
modelos durante el entrenamiento y tomar medidas según el estado del
modelo.
– TensorBoard le permite visualizar métricas, histogramas de activación e
incluso espacios incrustados.
– Qué normalización por lotes, en profundidadla convolución separable
y las conexiones residuales lo son.
– Por qué debería utilizar la optimización de hiperparámetros y el ensamblaje
de modelos.
◾ Con estas nuevas herramientas, estará mejor equipado para usar el
aprendizaje profundo en el mundo real y comenzar a crear modelos de
aprendizaje profundo altamente competitivos.

Con licencia para


Aprendizaje profundo
generativo

Este capítulo cubre


◾ Generación de texto con LSTM
◾ Implementando DeepDream
◾ Realización de transferencia de estilo neuronal
◾ Codificadores automáticos variacionales
◾ Comprender las redes antagónicas generativas

El potencial de la inteligencia artificial para emular los procesos de pensamiento


humano va más allá de tareas pasivas como el reconocimiento de objetos y, en su
mayoría, tareas reactivas como conducir un automóvil. Se extiende bien a las
actividades creativas. Cuando afirmé por primera vez que en un futuro no muy
lejano, la mayor parte del contenido cultural que consumimos se creará con la
ayuda sustancial de las IA, me encontré con una incredulidad total, incluso del
aprendizaje automático de larga data. practicantes Eso fue en 2014. Avance
rápido tres años y la incredulidad ha retrocedido, a una velocidad increíble. En el
verano de 2015, nos entretuvo el algoritmo DeepDream de Google que convertía
una imagen en un lío psicodélico de ojos de perro y artefactos pareidólicos; en
2016 utilizamos la aplicación Prisma para convertir fotos en cuadros de varios
estilos. En el verano de 2016, un cortometraje experimental, Sunspring, fue
dirigida utilizando un guión escrito por un algoritmo de memoria a corto plazo
largo (LSTM), completo con diálogo. Tal vez haya escuchado recientemente
música generada tentativamente por una red neuronal.

269

Con licencia para


270 CPASADO8Aprendizaje profundo generativo

De acuerdo, las producciones artísticas que hemos visto de AI hasta ahora han sido
de bastante baja calidad. La IA no está ni cerca de rivalizar con los guionistas, pintores
y compositores humanos. Pero reemplazar a los humanos siempre estuvo fuera de lugar:
la inteligencia artificial no se trata de reemplazar nuestra propia inteligencia con otra
cosa, se trata de traer a nuestras vidas y trabajar más inteligencia, inteligencia de un tipo
diferente. En muchos campos, pero especialmente en los creativos, los humanos
utilizarán la IA como una herramienta para aumentar sus propias capacidades: más
inteligencia aumentada que inteligencia artificial.
Una gran parte de la creación artística consiste en el reconocimiento de patrones
simples y la habilidad técnica. Y esa es precisamente la parte del proceso que
muchos encuentran menos atractiva o incluso prescindible. Ahí es donde entra la
IA. Nuestras modalidades de percepción, nuestro lenguaje y nuestra obra de arte
tienen una estructura estadística. Aprender esta estructura es en lo que se destacan
los algoritmos de aprendizaje profundo. Los modelos de aprendizaje automático
pueden aprender el espacio latente estadístico de imágenes, música e historias, y
luego pueden tomar muestras de este espacio, creando nuevas obras de arte con
características similares a las que el modelo ha visto en sus datos de entrenamiento.
Naturalmente, tal muestreo no es un acto de creación artística en sí mismo. Es una
mera operación matemática: el algoritmo no se basa en la vida humana, las
emociones humanas o nuestra experiencia del mundo; en cambio, aprende de una
experiencia que tiene poco en común con la nuestra. Es sólo nuestra interpretación,
como espectadores humanos, la que dará sentido a lo que genera el modelo. Pero en
manos de un artista habilidoso, la generación algorítmica puede ser dirigida para
que se vuelva significativa y hermosa. El muestreo del espacio latente puede
convertirse en un pincel que empodera al artista, aumenta nuestras capacidades
creativas y expande el espacio de lo que podemos imaginar. Es más, puede hacer
que la creación artística sea más accesible al eliminar la necesidad de habilidad
técnica y práctica, estableciendo un nuevo medio de expresión pura, diferenciando
el arte de la artesanía. La generación algorítmica se puede dirigir para que se vuelva
significativa y hermosa. El muestreo del espacio latente puede convertirse en un
pincel que empodera al artista, aumenta nuestras capacidades creativas y expande el
espacio de lo que podemos imaginar. Es más, puede hacer que la creación artística
sea más accesible al eliminar la necesidad de habilidad técnica y práctica,
estableciendo un nuevo medio de expresión pura, diferenciando el arte de la
artesanía. La generación algorítmica se puede dirigir para que se vuelva
significativa y hermosa. El muestreo del espacio latente puede convertirse en un
pincel que empodera al artista, aumenta nuestras posibilidades creativas y expande
el espacio de lo que podemos imaginar. Es más, puede hacer que la creación
artística sea más accesible al eliminar la necesidad de habilidad técnica y práctica,
estableciendo un nuevo medio de expresión pura, diferenciando el arte de la
artesanía.
Iannis Xenakis, un visionario pionero de la música electrónica y algorítmica,
expresó bellamente esta misma idea en la década de 1960, en el contexto de la
aplicación de la tecnología de automatización a la composición musical:1
Liberado de tediosos cálculos, el compositor es capaz de dedicarse a los problemas
generales que plantea la nueva forma musical y a explorar los recovecos de
Con licencia para
estamientras modifica los valores de los datos de entrada. Por ejemplo, puede
probar todas las combinaciones instrumentales, desde solistas hasta orquestas de
cámara y grandes orquestas. Con la ayuda de computadoras electrónicas, el
compositor se convierte en una especie de piloto: presiona los botones, introduce
coordenadas y supervisa los controles de una nave cósmica que navega en el
espacio del sonido, a través de constelaciones sónicas y galaxias que antes solo
podía vislumbrar como un sueño lejano.
En este capítulo, exploraremos desde varios ángulos el potencial del aprendizaje
profundo para aumentar la creación artística. Revisaremos la generación de datos de
secuencia (que se puede usar para generar texto o música), DeepDream y la
generación de imágenes usando codificadores automáticos variacionales y redes
antagónicas generativas. Haremos que su computadora sueñe contenido nunca antes
visto; y tal vez hagamos que usted también sueñe con las fantásticas posibilidades
que se encuentran en la intersección de la tecnología y el arte. Empecemos.
1
Iannis Xenakis, “Musiques formelles: nouveaux principes formels de composition musicale”, número especial de
La Revue musicale, núms. 253 -254 (1963).

Con licencia para


Textogeneración con LSTM 271

8.1 Generación de texto con LSTM


En esta sección, exploraremos cómo se pueden usar las redes neuronales recurrentes
para generar datos de secuencia. Usaremos la generación de texto como ejemplo,
pero exactamente las mismas técnicas se pueden generalizar a cualquier tipo de
datos de secuencia: puede aplicarlo a secuencias de notas musicales para generar
nueva música, a series temporales de datos de pinceladas. (por ejemplo, grabado
mientras un artista pinta en un iPad) para generar pinturas trazo a trazo, y así
sucesivamente.
La generación de datos de secuencia no se limita de ninguna manera a la generación
de contenido artístico. Se ha aplicado con éxito a la síntesis de voz ya la generación de
diálogos para chatbots. La función Smart Reply que Google lanzó en 2016, capaz de
generar automáticamente una selección de respuestas rápidas a correos electrónicos o
mensajes de texto, funciona con técnicas similares.

8.1.1 Una breve historia de las redes recurrentes generativas


A fines de 2014, pocas personas habían visto las iniciales LSTM, incluso en la
comunidad de aprendizaje automático. Las aplicaciones exitosas de generación de datos
de secuencia con redes recurrentes solo comenzaron a aparecer en la corriente principal
en 2016. Pero estas técnicas tienen una historia bastante larga, comenzando con el
desarrollo del algoritmo LSTM en 1997.2 Este nuevo algoritmo se usó desde el
principio para generar texto. personaje por personaje.
En 2002, Douglas Eck, entonces en el laboratorio de Schmidhuber en Suiza,
aplicó LSTM a la generación de música por primera vez, con resultados
prometedores. Eck ahora es investigador en Google Brain, y en 2016 comenzó un
nuevo grupo de investigación allí, llamado Magenta, enfocado en aplicar técnicas
modernas de aprendizaje profundo para producir música atractiva. A veces, las
buenas ideas tardan 15 años en comenzar.
A fines de la década de 2000 y principios de la de 2010, Alex Graves realizó un
importante trabajo pionero en el uso de redes recurrentes para la generación de datos
de secuencia. En particular, su trabajo de 2013 sobre la aplicación de redes de
densidad de mezcla recurrentes para generar una escritura similar a la humana
utilizando series temporales de posiciones de lápiz es visto por algunos como un
punto de inflexión.3 Esta aplicación específica de redes neuronales en ese momento
específico capturó para mí la noción de máquinas que sueñan y fue una inspiración
importante en el momento en que comencé a desarrollar Keras. Graves dejó un
comentario comentado similar oculto en un archivo LaTeX de 2013 cargado en el
servidor de preimpresión arXiv: "generar datos secuenciales es lo más cercano que
las computadoras pueden soñar". Varios años después, damos por hecho muchos de
estos desarrollos; pero en ese momento,
Desde entonces, las redes neuronales recurrentes se han utilizado con éxito para la
generación de música, generación de diálogos, generación de imágenes, síntesis de voz
y diseño de moléculas. Incluso se utilizaron para producir un guión de película que
luego se interpretó con actores en vivo.

2
Sepp Hochreiter y Jürgen Schmidhuber, "Memoria a largo plazo a corto plazo", Neural Computation 9, no. 8 (1997).
Con licencia para
3
Alex Graves, "Generación de secuencias con redes neuronales recurrentes", arXiv (2013),https://arxiv.org/ abs/1308.0850.

Con licencia para


272 CPASADO8Aprendizaje profundo generativo

8.1.2 ¿Cómo se generan datos de secuencia?


La forma universal de generar datos de secuencia en el aprendizaje profundo es entrenar
una red (generalmente una RNN o una convnet) para predecir el próximo token o los
próximos tokens en una secuencia, utilizando los tokens anteriores como entrada. Por
ejemplo, dada la entrada "el gato está en el ma", la red está entrenada para predecir el
objetivo t, el siguiente carácter. Como es habitual cuando se trabaja con datos de texto,
los tokens suelen ser palabras o caracteres, y cualquier red que pueda modelar la
probabilidad del siguiente token dados los anteriores se denomina modelo de lenguaje.
Un modelo de lenguaje captura el espacio latente del lenguaje: su estructura estadística.
Una vez que tenga dicho modelo de lenguaje entrenado, puede muestrearlo (generar
nuevas secuencias): lo alimenta con una cadena inicial de texto (llamados datos de
acondicionamiento), le pide que genere el siguiente carácter o la siguiente palabra
(incluso puede generar varios tokens a la vez), agregue la salida generada de nuevo a los
datos de entrada y repita el proceso muchas veces (consulte la figura 8.1). Este ciclo le
permite generar secuencias de longitud arbitraria que reflejan la estructura de los datos
en los que se entrenó el modelo: secuencias que parecen casi oraciones escritas por
humanos. En el ejemplo que presentamos en esta sección, tomará una capa LSTM, la
alimentará con cadenas de N caracteres extraídos de un corpus de texto y la entrenará
para predecir el carácter N + 1. La salida del modelo será un softmax sobre todo
caracteres posibles: una distribución de probabilidad para el siguiente carácter.

Distribución de
probabilidad para muestreadosi
Texto inicial Texto inicial el siguiente guiente
carácter personaje
modelo estrategi
El gato se sentó en
de a de
el m a
lenguaj muestre
e o

modelo estrategi
El gato se sentó en el
de a de
ma
lenguaj muestre
t
e o

...

Figura 8.1 El proceso de generación de texto carácter por carácter usando un modelo de lenguaje

8.1.3 La importancia de la estrategia de muestreo


Al generar texto, la forma en que elige el siguiente carácter es de vital importancia. Un
enfoque ingenuo es el muestreo codicioso, que consiste en elegir siempre el siguiente
carácter más probable. Pero tal enfoque da como resultado cadenas repetitivas y predecibles
que no parecen un lenguaje coherente. Un enfoque más interesante hace elecciones un poco
más sorprendentes: introduce aleatoriedad en el proceso de muestreo, tomando muestras de
la distribución de probabilidad para el siguiente carácter. Esto se llama muestreo estocástico
(recuerde que la estocasticidad es lo que llamamos aleatoriedad en este campo). En tal
configuración, si e tiene una probabilidad de 0,3 de ser el siguiente carácter, según el
Con licencia para
modelo, lo elegirá

Con licencia para


Textogeneración con LSTM 273

30% del tiempo. Tenga en cuenta que el muestreo codicioso también puede
interpretarse como un muestreo de una distribución de probabilidad: uno en el que
cierto carácter tiene probabilidad 1 y todos los demás tienen probabilidad 0.
El muestreo probabilístico de la salida softmax del modelo es ordenado: permite
que incluso los caracteres poco probables se muestreen en algún momento,
generando oraciones de aspecto más interesante y, a veces, mostrando creatividad al
pensar en palabras nuevas que suenan realistas que no ocurrieron. en los datos de
entrenamiento. Pero hay un problema con estoestrategia: no ofrece una forma de
controlar la cantidad de aleatoriedad en el proceso de muestreo. ¿Por qué querrías más o
menos aleatoriedad? Considere un caso extremo: el muestreo aleatorio puro, donde extrae el
siguiente carácter de una distribución de probabilidad uniforme, y cada carácter tiene la
misma probabilidad. Este esquema tiene máxima aleatoriedad; en otras palabras, esta
distribución de probabilidad tiene una entropía máxima. Naturalmente, no producirá nada
interesante. En el otro extremo, el muestreo codicioso tampoco produce nada interesante y
no tiene aleatoriedad: la distribución de probabilidad correspondiente tiene una entropía
mínima. El muestreo de la distribución de probabilidad “real”, la distribución que genera la
función softmax del modelo, constituye un punto intermedio entre estos dos extremos. Pero
hay muchos otros puntos intermedios de mayor o menor entropía que tal vez desee explorar.
Menos entropía dará a las secuencias generadas una estructura más predecible (y, por lo
tanto, tendrán un aspecto potencialmente más realista), mientras que más entropía dará como
resultado secuencias más sorprendentes y creativas. Al tomar muestras de modelos
generativos, siempre es bueno explorar diferentes grados de aleatoriedad en el proceso de
generación. Debido a que nosotros, los humanos, somos los jueces finales de cuán
interesantes son los datos generados, el interés es altamente subjetivo, y no se sabe de
antemano cuál es el punto de interés. mientras que más entropía resultará en secuencias más
sorprendentes y creativas. Al tomar muestras de modelos generativos, siempre es bueno
explorar diferentes grados de aleatoriedad en el proceso de generación. Debido a que
nosotros, los humanos, somos los jueces finales de cuán interesantes son los datos
generados, el interés es altamente subjetivo, y no se sabe de antemano cuál es el punto de
interés. mientras que más entropía resultará en secuencias más sorprendentes y creativas. Al
tomar muestras de modelos generativos, siempre es bueno explorar diferentes grados de
aleatoriedad en el proceso de generación. Debido a que nosotros, los humanos, somos los
jueces finales de cuán interesantes son los datos generados, el interés es altamente subjetivo,
y no se sabe de antemano cuál es el punto de interés.
mentiras de la entropía óptima.
Para controlar la cantidad de estocasticidad en el proceso de muestreo,
introduciremos un parámetro llamado temperatura softmax que caracteriza la
entropía de la distribución de probabilidad utilizada para el muestreo: caracteriza
qué tan sorprendente o predictivo escapaz será la elección del siguiente personaje. Dado
un valor de temperatura, se calcula una nueva distribución de probabilidad a partir de la
original (la salida softmax del modelo) al volver a ponderarla de la siguiente manera.

Listado 8.1 Reponderando una distribución de probabilidad a una temperatura diferente

importar numpy como np

def reweight_distribution(original_distribution, temperature=0.5):

Con licencia para


distribución = np.log(original_distribution) / distribución de
temperatura = np.exp(distribution)
distribución de devolución / np.sum (distribución)

Devuelve una versión ponderada de


distribución_original es una1D Numpy la distribución original. La suma de
array de valores de probabilidad que la distribución ya no puede ser1,
deben sumar1. la temperatura es un entonces lo divides por su suma
factor que cuantifica la entropía de la para obtener la nueva distribución.
distribución de salida.

Con licencia para


274 CPASADO8Aprendizaje profundo generativo

Las temperaturas más altas dan como resultado distribuciones de muestreo de mayor
entropía que generarán datos generados más sorprendentes y no estructurados, mientras que
una temperatura más baja dará como resultado menos aleatoriedad y datos generados mucho
más predecibles (consulte la figura 8.2).

la temperatura= 0,01 temperatura = 0,2 temperatura = 0,4


Probabilidad del elemento de
muestreo

Elementos discretos
(caracteres)

temperatura = 0,8 temperatura = 1,0


temperatura = 0,6

Figura 8.2 Diferentes reponderaciones de una probabilidaddistribución. Baja temperatura


= másdeterminista, alta temperatura = más aleatorio.

8.1.4 Implementación de la generación de texto LSTM a nivel de carácter


Pongamos estas ideas en práctica en una implementación de Keras. Lo primero que
necesita es una gran cantidad de datos de texto que puede usar para aprender un modelo
de lenguaje. Puede utilizar cualquier archivo de texto o conjunto de archivos de texto lo
suficientemente grande: Wikipedia, El señor de los anillos, etc. En este ejemplo,
utilizará algunos de los escritos de Nietzsche, el filósofo alemán de finales del siglo
XIX (traducidos al inglés). El modelo de lenguaje que aprenderá será, por lo tanto,
específicamente un modelo del estilo de escritura y los temas de elección de Nietzsche,
en lugar de un modelo más genérico del idioma inglés.
PAGSREPARANDO LOS DATOS
Comencemos por descargar el corpus y convertirlo a minúsculas.

Listado 8.2 Descargando y analizando el archivo de texto inicial

importar keras
importar numpy
como np
ruta =
keras.utils.get_file('ni
etzsche.txt',
origen='https://s3.amazonaws.com/text-
datasets/nietzsche.txt')texto = abrir (ruta). leer (). inferior ()
Con licencia para
print('Longitud del cuerpo:', len(texto))

Con licencia para


Textogeneración con LSTM 275

A continuación, extraerá secuencias parcialmente superpuestas de longitud maxlen, las


codificará en caliente y las empaquetará en una matriz 3D Numpy x de forma
(secuencias, maxlen, caracteres_únicos). Simultáneamente, preparará una
matriz y que contenga los objetivos correspondientes: los
caracteres codificados en caliente que vienen después de cada
secuencia extraída.

Listado 8.3 Vectorización de secuencias de caracteres

Extraerás secuencias de
60 caracteres.
maxlen = 60
Probarás una nueva secuencia cada
paso = 3 tres caracteres.
oraciones = [] Contiene las secuencias extraídas
next_chars = [] Sostiene los objetivos (el
for i in range(0, len(text) - maxlen, step): personajes de seguimiento)
frases.append(text[i: i + maxlen])
Lista de caracteres únicos
next_chars.append(text[i + maxlen])
en el corpus
print('Número de secuencias:', len(frases)) Diccionario
chars = sorted(list(set(text))) queasigna caracteres
únicos a su índice en la
print('Caracteres únicos:', len(chars)) lista "chars"
char_indices = dict((char, chars.index(char)) for char in chars)

print('Vectorización...')
x = np.zeros((len(frases), maxlen, len(caracteres)),
dtype=np.bool) y = np.zeros((len(frases), len(caracteres)),
dtype=np.bool) One-hot codifica
los caracteres en
para i, oración en enumerar (oraciones): matrices binarias
para t, char en enumerar (oración):
x[i, t, char_indices[char]] = 1
y[i, char_indices[next_chars[i]]] = 1

BCONSTRUYENDO LA RED
Esta red es una sola capa LSTM seguida de un clasificador denso y softmax sobre todos los
caracteres posibles. Pero tenga en cuenta que las redes neuronales recurrentes no son la
única forma de generar secuencias de datos; Las redes de convección 1D también han
demostrado ser extremadamente exitosas en esta tarea en los últimos tiempos.

Listado 8.4 Modelo LSTM de una sola capa para la predicción del siguiente carácter

de keras importar capas

modelo = keras.modelos.secuencial()
modelo.add(capas.LSTM(128, input_shape=(maxlen,
len(caracteres)))) modelo.add(capas.Dense(len(caracteres),
activación='softmax'))

Con licencia para


276 CPASADO8Aprendizaje profundo generativo

Debido a que sus objetivos están codificados en caliente,


usarácategorical_crossentropycomo la pérdida de entrenar el modelo.

Listado 8.5 Configuración de la compilación del modelo

optimizador = keras.optimizadores.RMSprop(lr=0.01)
modelo.compile(pérdida='categorical_crossentropy',
optimizador=optimizador)

TLLUVIA DEL MODELO DE LENGUAJE Y MUESTREO A PARTIR DE ÉL


Dado un modelo entrenado y un fragmento de texto inicial, puede generar texto
nuevo haciendo lo siguiente repetidamente:
1Extraiga del modelo una distribución de probabilidad para el siguiente carácter,
dado el texto generado disponible hasta el momento.
2Repesar la distribución a una determinada temperatura.

3Muestra el siguiente carácter al azar de acuerdo con la distribución ponderada.

4Agregue el nuevo carácter al final del texto disponible.

Este es el código que usa para volver a ponderar la distribución de probabilidad


original que sale del modelo y dibujar un índice de caracteres a partir de ella (la
función de muestreo).

Listado 8.6 Función para muestrear el siguiente carácter dadas las predicciones del modelo

def muestra(pres, temperatura=1.0):


preds = np.asarray(preds).astype('float64')
preds = np.log(preds) / temperatura
exp_preds = np.exp(preds)
preds = exp_preds / np.sum(exp_preds)
probas = np.random.multinomial(1, preds, 1)
return np.argmax(probas)

Finalmente, el siguiente ciclo entrena y genera texto repetidamente. Comienzas a


generar texto usando un rango de temperaturas diferentes después de cada época.
Esto le permite ver cómo evoluciona el texto generado a medida que el modelo
comienza a converger, así como el impacto de la temperatura en la estrategia de
muestreo.

Listado 8.7 Bucle de generación de texto

importar
sistema de Entrena al modelo durante 60 épocas.
importación
aleatoria Se ajusta al modelo para una
iteración de los datos
para la época en el rango
(1, 60): imprimir
('época', época)
model.fit(x, y, lote_tamaño=128, épocas=1)
índice_inicial = random.randint(0, len(texto) - maxlen - 1) Selecciona
texto_generado = texto[índice_inicial: índice_inicial + una semilla
maxlen] print('--- Generando con semilla: "' + de texto al
texto_generado + '"')
azar

Con licencia para


para temperatura en [0.2, 0.5, 1.0, 1.2]:
Prueba un rango de diferentes
print('------ temperatura:', temperatura) temperaturas de muestreo
sys.stdout.write(generated_text)

Con licencia para


Textogeneración con LSTM 277

Genera 400 para i en el rango (400):


caracteres, a sampled = np.zeros((1, maxlen, len(chars))) One-hot codifica los
partir del for t, char in enumerate(generated_text): caracteres
texto semilla muestreado[0, t, char_indices[char]] = generados hasta el
1. momento
preds = model.predict(muestreado, Muestre
detallado=0)[0] next_index = muestra(preds, a el
temperatura) next_char = chars[next_index] siguient
e
texto_generado += carácter
siguiente_caracter texto_generado =
texto_generado[1:]
sys.stdout.write(next_char)

Aquí, usamos el texto semilla aleatorio “nueva facultad, y el júbilo alcanzó su


clímax cuando kant”. Esto es lo que obtienes en la época 20, mucho antes de que el
modelo haya convergido por completo, con temperatura = 0,2:
nueva facultad, y el júbilo alcanzó su clímax cuando Kant y tal hombre al
mismo tiempo el espíritu de lo seguro y lo tal lo tal
como un hombre es la luz del sol y sujeto el presente a la superioridad
del dolor especial el más hombre y extraño el sometimiento del
conciencia especial lo especial y la naturaleza y tales hombres la sujeción
de los hombres especiales, con toda seguridad la sujeción de los especiales
entendimiento de la sujeción de las mismas cosas y

Aquí está el resultado contemperatura=0.5:

nueva facultad, y el júbilo alcanzó su clímax cuando kant en el hombre


eterno y tal como él mismo se convierte también en la condición del
experiencia fuera de la base de la superioridad y la morty especial de la
fuerza, en el langus, como que al mismo tiempo la vida e "incluso quien
discless la humanidad, con un tema y hecho todo lo que tienes que ser el
soporte y lave no viene un troveración del hombre y seguramente la
conciencia la superioridad, y cuando uno debe ser w

Y esto es lo que obtienes contemperatura=1.0:

nueva facultad, y el júbilo alcanzó su clímax cuando Kant, como un


peligro de manera a todos los definidos y transpects it tan
hicable and ont him artiar resull
demasiado como si alguna vez el apuntalamiento hace como cnecience.
para ser juden, todo lo que cada uno podría frío como una pasión, las
capas como las que podrían tener en cuenta, germinando
indiferentemente, que todo
cierta destrucción, intelecto en el origen deteriorablen de moralian, y
una menosoridad o

En la época 60, el modelo ha convergido en su mayoría y el texto comienza a verse


significativamente más coherente. Aquí está el resultado con temperatura = 0.2:
la alegría, la simpatía y la bondad de un corazón son el sentido del
espíritu es un hombre con el sentido del sentido del mundo del
egoísmo y egoísmo en cuanto a la sujeción de las fuerzas orixes, las

Con licencia para


278 CPASADO8Aprendizaje profundo generativo

sujeción de la sujeción de la sujeción de la


preocuparse por los sentimientos en la superioridad en la sujeción de la
sujeción del espíritu no es ser un hombre del sentido de la sujeción y
dicho a la fuerza del sentido de la

Aquí estátemperatura=0.5:

la alegría, la simpatía y la bondad de un corazón son la parte del alma que


ha sido el arte de los filósofos, y que el uno
no diré, cuál es el más alto y con la religión de los frences. la vida
del espíritu entre las más continuas de la
fortalecedor del sentido la conciencia de los hombres de precisamente
ante bastante presunción, y puede la humanidad, y algo las concepciones,
la sujeción del sentido y el sufrimiento y el

y aquí estátemperatura=1.0:

la alegría, la amistad y la bondad de un corazón son espirituales por


el ciuture para el
¡Entalled es, él astrajo, o errores a nuestro idstood--y necesita,
pensar por largueros a entero los amvives de los newoatly,
perfectamente raals! era
nombre, por ejemplo, pero voludd atu-especity"--o rank onee, o
incluso todo "solett increessic of the world and
experiencia de tragedia implussional, transf, o insiderar, - debe
tener si los deseos de la estructura son más fuertes

Como puede ver, un valor de temperatura bajo da como resultado un texto


extremadamente repetitivo y predecible, pero la estructura local es muy realista: en
particular, todas las palabras (una palabra es un patrón local de caracteres) son palabras
reales en inglés. Con temperaturas más altas, el texto generado se vuelve más
interesante, sorprendente, incluso creativo; a veces inventa palabras completamente
nuevas que suenan algo plausibles (como eterned y troveration). Con una temperatura
alta, la estructura local comienza a desmoronarse y la mayoría de las palabras parecen
cadenas de caracteres semialeatorias. Sin duda, 0,5 es la temperatura más interesante
para la generación de texto en esta configuración específica. ¡Experimente siempre con
múltiples estrategias de muestreo! Un equilibrio inteligente entre la estructura aprendida
y la aleatoriedad es lo que hace que la generación sea interesante.
Tenga en cuenta que al entrenar un modelo más grande, más largo y con más
datos, puede lograr muestras generadas que se vean mucho más coherentes y
realistas que esta. Pero, por supuesto, no espere generar ningún texto significativo,
salvo por casualidad: todo lo que está haciendo es muestrear datos de un modelo
estadístico de qué caracteres vienen después de qué caracteres. El lenguaje es un
canal de comunicación, y existe una distinción entre de qué tratan las
comunicaciones y la estructura estadística de los mensajes en los que se codifican
las comunicaciones. Para evidenciar esta distinción, aquí hay un experimento
mental: ¿y si el lenguaje humano hiciera un mejor trabajo al comprimir las
comunicaciones, como lo hacen las computadoras con la mayoría de las
comunicaciones digitales? El lenguaje no sería menos significativo, pero carecería
de cualquier estructura estadística intrínseca,

Con licencia para


Textogeneración con LSTM 279

8.1.5 Terminando
◾ Puede generar datos de secuencia discreta entrenando un modelo para
predecir los siguientes tokens, dados los tokens anteriores.
◾ En el caso del texto, dicho modelo se denomina modelo de lenguaje. Puede
basarse en palabras o caracteres.
◾ Muestrear el siguiente token requiere un equilibrio entre adherirse a lo que el
modelo juzga probable e introducir aleatoriedad.
◾ Una forma de manejar esto es la noción de temperatura softmax. Siempre
experimente con diferentes temperaturas para encontrar la correcta.

Con licencia para


280 CPASADO8Aprendizaje profundo generativo

8.2 sueño profundo


sueño profundoes una técnica artística de modificación de imágenes que utiliza las
representaciones aprendidas por las redes neuronales convolucionales. Google lo lanzó
por primera vez en el verano de 2015, como una implementación escrita usando la
biblioteca de aprendizaje profundo de Caffe (esto fue varios meses antes del primer
lanzamiento público de TensorFlow).4 Rápidamente se convirtió en una sensación en
Internet gracias a la alucinante imágenes que podría generar (consulte, por ejemplo, la
figura 8.3), llenas de artefactos algorítmicos de pareidolia, plumas de pájaro y ojos de
perro, un subproducto del hecho de que DeepDream convnet se entrenó en ImageNet,
donde las razas de perros y las especies de aves están muy sobrerrepresentadas .

Figura 8.3 Ejemplo de una imagen de salida de DeepDream

El algoritmo DeepDream es casi idéntico a la técnica de visualización de filtro de


convnet presentada en el capítulo 5, que consiste en ejecutar un convnet a la
inversa: haciendo un ascenso de gradiente en la entrada a la convnet para maximizar
la activación de un filtro específico en una capa superior del convnet. DeepDream
utiliza esta misma idea, con algunas diferencias simples:
◾ Con DeepDream, intenta maximizar la activación de capas completas en lugar
de la de un filtro específico, mezclando así visualizaciones de un gran número
de características a la vez.
4 Alexander Mordvintsev, Christopher Olah y Mike Tyka, “DeepDream: A Code Example for Visualizing Neural
Redes,” Google Investigar Blog, Julio 1, 2015,
http://mng.bz/xXlM.

Con licencia para


sueño profundo 281

◾ No se parte de una entrada en blanco y ligeramente ruidosa, sino de una


imagen existente; por lo tanto, los efectos resultantes se adhieren a patrones
visuales preexistentes, distorsionando elementos de la imagen de una manera
un tanto artística.
◾ Las imágenes de entrada se procesan a diferentes escalas (llamadas octavas),
lo que mejora la calidad de las visualizaciones.
Hagamos algunos DeepDreams.

8.2.1 Implementando DeepDream en Keras


Comenzará desde una convnet preentrenada en ImageNet. En Keras, muchas de estas
redes están disponibles: VGG16, VGG19, Xception, ResNet50, etc. Puede implementar
DeepDream con cualquiera de ellos, pero su convnet de elección afectará naturalmente
sus visualizaciones, porque diferentes arquitecturas de convnet resultan en diferentes
características aprendidas. La convnet utilizada en la versión original de DeepDream era
un modelo de Inception y, en la práctica, se sabe que Inception produce DeepDreams
atractivos, por lo que utilizará el modelo Inception V3 que viene con Keras.

Listado 8.8 Cargando el modelo Inception V3 preentrenado

desde keras.applications importar


No estará entrenando el modelo,
inception_v3 desde keras importar backend
por lo que este comando deshabilita
como K todas las operaciones específicas de
K.set_learning_phase(0) entrenamiento.

modelo = inicio_v3.InicioV3(pesos='imagennet', Construye la red Inception V3, sin


include_top=Falso) su base convolucional. El modelo
se cargará con pesos ImageNet
previamente entrenados.

A continuación, calculará la pérdida: la cantidad que buscará maximizar durante el proceso


de ascenso de gradiente. En el capítulo 5, para la visualización de filtros, trató de maximizar
el valor de un filtro específico en una capa específica. Aquí, maximizará simultáneamente la
activación de todos los filtros en varias capas. Específicamente, maximizará una suma
ponderada de la norma L2 de las activaciones de un conjunto de capas de alto nivel. El
conjunto exacto de capas que elija (así como su contribución a la pérdida final) tiene una
gran influencia en las imágenes que podrá producir, por lo que desea que estos parámetros
sean fácilmente configurables. Las capas inferiores dan como resultado patrones
geométricos, mientras que las capas superiores dan como resultado imágenes en las que
puede reconocer algunas clases de ImageNet (por ejemplo, pájaros o perros).

Listado 8.9 Estableciendo la configuración de DeepDream

contribuciones_capa = {
Diccionario que asigna los nombres de las capas a un
'mixed2': 0.2,
coeficiente que cuantifica cuánto contribuye la activación de
'mixto3': 3.,
la capa a la pérdida que buscará maximizar. Tenga en cuenta
'mixto4': 2., que los nombres de las capas están codificados en la
'mixto5': 1.5, aplicación integrada de Inception V3. Puede listar todos los
} nombres de las capas usando model.summary().

Con licencia para


282 CPASADO8Aprendizaje profundo generativo

Ahora, definamos un tensor que contenga la pérdida: la suma ponderada de la norma L2


de las activaciones de las capas del listado 8.9.

Listado 8.10 Definición de la pérdida a maximizar

Crea un diccionario que asigna


nombres de capa a instancias de
capa
layer_dict = dict([(capa.nombre, capa) para capa en modelo.capas])

pérdida = K.variable(0.) Definirá la pérdida agregando


para nombre_capa en contribuciones_capa: contribuciones de capa a esta
coeff = variable escalar.
contribuciones_capa[nombre_capa]
activación = capa_dict[nombre_capa].salida

escalado = K.prod(K.cast(K.shape(activación), 'float32'))


pérdida += coeficiente * K.sum(K.square(activación[:, 2: -2, 2: -2, :])) / escalado

Añade la norma L2 de las características de


Recupera la salida de la una capa a la pérdida. Evita los artefactos de
capa. borde al involucrar solo los píxeles que no
están en el borde en la pérdida.

A continuación, puede configurar el proceso de ascenso de gradiente.

Listado 8.11 Ascenso de gradienteproceso

Este tensor mantiene el


imagen generada: lasueño. Calcula los gradientes de la
soñar con respecto ala pérdida
sueño = modelo.entrada

grads = K.gradients(pérdida, sueño)[0] Normaliza los degradados (truco


importante)
grads /= K.maximum(K.mean(K.abs(grads)), 1e-7)
salidas = [pérdida, grads]
fetch_loss_and_grads = K.function([sueño], salidas) Configura una función de
Keras para recuperar el
def eval_loss_and_grads(x): valor de la pérdida y los
outs = fetch_loss_and_grads([x]) gradientes, dada una
loss_value = outs[0] imagen de entrada
grad_values = outs[1]
devolver loss_value, grad_values
def gradiente_ascenso(x, iteraciones, paso,
max_loss=Ninguno): for i in range(iteraciones):
loss_value, grad_values = eval_loss_and_grads(x) Esta función ejecuta el
si max_loss no es None y loss_value > max_loss: ascenso de gradiente
descanso durante varias
print('...Valor de pérdida en', i, ':', iteraciones.
loss_value) x += paso * grad_values
volver x

Finalmente: el algoritmo real de DeepDream. Primero, define una lista de escalas


(también llamadas octavas) en las que procesar las imágenes. Cada escala sucesiva es
más grande que la anterior por un factor de 1,4 (es un 40% más grande): comienzas
procesando una imagen pequeña y luego la escalas cada vez más (ver figura 8.4).

Con licencia para


sueño profundo 283

reinyecció
reinyec n de
ción de detalle
detalle

Sueño Exclusi SueñoDe LujoSueño


vo

octava 1
octava 2
octava 3

Figura 8.4 El proceso DeepDream: escalas sucesivas de procesamiento espacial (octavas) y reinyección de
detallesal ampliar

Para cada escala sucesiva, desde la más pequeña hasta la más grande, ejecuta un
ascenso de gradiente para maximizar la pérdida que definió previamente, en esa
escala. Después de cada ejecución de ascenso de gradiente, aumenta la imagen
resultante en un 40%.
Para evitar perder muchos detalles de la imagen después de cada ampliación
sucesiva (lo que da como resultado imágenes cada vez más borrosas o pixeladas), puede
usar un truco simple: después de cada ampliación, reinyectará los detalles perdidos en la
imagen, lo que es posible porque sabe cómo debería verse la imagen original a mayor
escala. Dado un tamaño de imagen pequeño S y un tamaño de imagen más grande L,
puede calcular la diferencia entre la imagen original redimensionada a tamaño L y la
original redimensionada a tamaño S; esta diferencia cuantifica los detalles perdidos al
pasar de S a L.

Listado 8.12 Ejecución de ascenso de gradiente sobre diferentes sucesivasescamas

Jugar con estos hiperparámetros te Tamaño de paso de ascenso de gradiente


permitirá lograr nuevos efectos.
Número de escalas en las que
ejecutar el ascenso de gradiente
importar numpy
Relación de tamaño entre escalas
como paso np =
Número de pasos de ascenso a
0.01 correr en cada escala
núm_octava = 3
Si la pérdida es mayor que10, interrumpirá el
escala_octava = 1.4
proceso de ascenso de gradiente para evitar
iteraciones = 20 artefactos desagradables.
max_loss = 10.
Complete esto con la ruta a la imagen que desea usar.
base_image_path = '...'

Con licencia para


img = Carga la imagen base en una matriz
preprocess_image(base_image_path) Numpy (la función se define en el
listado 8.13)

Con licencia para


284 CPASADO8Aprendizaje profundo generativo

forma_original = img.forma[1:3]
formas_sucesivas = [forma_original]
Prepara una lista de tuplas
for i in range(1, num_octave): de forma que definen las
forma = tupla([int(dim / (octave_scale ** i)) diferentes escalas en las
for dim in original_shape]) que ejecutar el ascenso de
formas_sucesivas.append(forma) gradiente
formas_sucesivas = formas_sucesivas[::-1] Invierte la lista de
formas para que
imagen_original = np.copia(imagen) estén en orden
creciente
shrunk_original_img = resize_img(img, formas_sucesivas[0])
Escala
hacia
arriba
el for forma en formas_sucesivas: Cambia el tamaño
sueño print('Procesando forma de imagen', de la matriz
forma) Numpy de la
imagen
imagen img = resize_img(img, forma) a la escala más pequeña
img = degradado_ascenso(img,
iteraciones=iteracione
Aumenta la escala de
Ejecuta la versión más pequeña de
gradienteascen s,paso=paso,
la imagen original: se
so, alteración max_loss=max_loss)
pixelará.
el sueño
upscaled_shrunk_original_img = resize_img(shrunk_original_img, forma)
same_size_original = resize_img(original_img, forma)
Lost_detail = mismo_tamaño_original - upscaled_shrunk_original_img

img += detalle_perdido
shrunk_original_img = resize_img(original_img, forma)
save_img(img, fname='dream_at_scale_' + str(forma) + '.png')

save_img(img, fname='sueño_final.png')
Reinyecta detalles perdidos en el sueño.
Calcula la versión de alta calidad.
de la imagen original en esteTalla La diferencia entre los dos es el
detalle que se perdió al aumentar la
escala.

Tenga en cuenta que este código utiliza las siguientes funciones Numpy auxiliares
sencillas, que hacen lo que sugieren sus nombres. Requieren que tengas SciPy
instalado.

Listado 8.13 Funciones auxiliares

importar scipy
de keras.imagen de importación de preprocesamiento

def resize_img(img,
tamaño): img =
np.copy(img) factores
= (1,
float(tamaño[0]) /
img.forma[1], float(tamaño[1])
/ img.forma[2], 1)
devuelve scipy.ndimage.zoom(img, factores, orden=1)
def save_img(img, fnombre):
pil_img = deprocess_image(np.copy(img)) scipy.misc.imsave(fname,
Con licencia para
pil_img)
Función de utilidad para abrir,
def preprocess_image(image_path): cambiar el tamaño y formatear
img = image.load_img(image_path) imágenes en tensores que
img = image.img_to_array(img) Inception V3 puede procesar

Con licencia para


sueño profundo 285

img = np.expand_dims(img, eje=0)


img = inception_v3.preprocess_input(img)
devolver img
def deprocesar_imagen(x):
Función útil para
if K.image_data_format() == 'channels_first':
convertir un tensor en
x = x.reshape((3, x.shape[2], x.shape[3])) una imagen válida
x = x.transpose((1, 2, 0))
más:
x = x.reforma((x.forma[1], x.forma[2], 3)) x Deshace el preprocesamiento
/= 2. realizado por
x += 0.5 inception_v3.preprocess_
x*= 255. input
x = np.clip(x, 0, 255).astype('uint8')
devuelve x

NOTADebido a que la red Inception V3 original fue entrenada para reconocer


conceptos en imágenes de tamaño 299 × 299, y dado que el proceso implica
reducir las imágenes en un factor razonable, la implementación de DeepDream
produce resultados mucho mejores en imágenes que están en algún lugar entre
300 × 300 y 400 × 400. Independientemente, puede ejecutar el mismo código
en imágenes de cualquier tamaño y cualquier proporción.

Partiendo de una fotografía tomada en las pequeñas colinas entre la Bahía de San
Francisco y el campus de Google, obtuvimos el DeepDream que se muestra en la
figura 8.5.

Figura 8.5 Ejecutando el código de DeepDream en una imagen de ejemplo

Le sugerimos enfáticamente que explore lo que puede hacer ajustando las capas que
usa en su pérdida. Las capas que están más abajo en la red contienen
representaciones más locales y menos abstractas y conducen a patrones de sueños
que parecen más geométricos. Las capas que están más arriba conducen a patrones
visuales más reconocibles basados en los objetos más comunes que se encuentran en
ImageNet, como ojos de perro, plumas de pájaro, etc. Puedes usar

Con licencia para


286 CPASADO8Aprendizaje profundo generativo

generación aleatoriade los parámetros en el diccionario layer_contributions para


explorar rápidamente muchas combinaciones de capas diferentes. La Figura 8.6 muestra
una gama de resultados obtenidos utilizando diferentes configuraciones de capas, a
partir de una imagen de un delicioso pastel casero.

Figura 8.6 Probar una variedad de configuraciones de DeepDream en una imagen de ejemplo

8.2.2 Terminando
◾ DeepDream consiste en ejecutar una convnet a la inversa para generar
entradas basadas en las representaciones aprendidas por la red.
◾ Los resultados producidos son divertidos y algo similares a los artefactos
visuales inducidos en humanos por la interrupción de la corteza visual a
través de psicodélicos.
◾ Tenga en cuenta que el proceso no es específico de los modelos de imagen o
incluso de las redes de conversión. Se puede hacer para voz, música y más.

Con licencia para


Neuraltransferencia de estilo 287

8.3 Transferencia de estilo neuronal


Además de DeepDream, otro avance importante en la modificación de imágenes
impulsada por el aprendizaje profundo es la transferencia de estilo neuronal,
presentada por Leon Gatys et al. en el verano de 2015.5 El algoritmo de
transferencia de estilo neuronal ha sufrido muchos refinamientos y generado
muchas variaciones desde su introducción original, y se ha abierto camino en
muchas aplicaciones de fotos para teléfonos inteligentes. Para simplificar, esta
sección se centra en la formulación descrita en el artículo original.
La transferencia de estilo neuronal consiste en aplicar el estilo de una imagen de
referencia a una imagen de destino conservando el contenido de la imagen de destino.
La Figura 8.7 muestra un ejemplo.

Contenidoimagen de combinación de referencia targetStyle

Figura 8.7 Un ejemplo de transferencia de estilo

En este contexto, estilo significa esencialmente texturas, colores y patrones visuales en


la imagen, en varias escalas espaciales; y el contenido es la macroestructura de nivel
superior de la imagen. Por ejemplo, las pinceladas circulares azules y amarillas se
consideran el estilo de la figura 8.7 (utilizando La noche estrellada de Vincent Van
Gogh), y los edificios de la fotografía de Tübingen se consideran el contenido.
La idea de la transferencia de estilo, que está estrechamente relacionada con la
generación de texturas, ha tenido una larga historia en la comunidad de
procesamiento de imágenes antes del desarrollo de la transferencia de estilo
neuronal en 2015. Pero resulta que la tecnología basada en el aprendizaje profundo
Las implementaciones de la transferencia de estilo ofrecen resultados incomparables
con lo que se había logrado anteriormente con las técnicas clásicas de visión por
computadora, y desencadenaron un renacimiento asombroso en las aplicaciones
creativas de la visión por computadora.
La noción clave detrás de la implementación de la transferencia de estilo es la
misma idea que es fundamental para todos los algoritmos de aprendizaje profundo:
define una función de pérdida para especificar lo que desea lograr y minimiza esta
pérdida. Ya sabes lo que quieres lograr: conservar el contenido de la imagen original
mientras adoptas el estilo de la imagen de referencia. Si fuéramos capaces de definir
matemáticamente el contenido y el estilo, entonces una función de pérdida apropiada
para minimizar sería la siguiente:
pérdida = distancia (estilo (imagen_de referencia) - estilo
(imagen_generada)) + distancia (contenido (imagen_original)
- contenido (imagen_generada))

Con licencia para


5 Leon A. Gatys, Alexander S. Ecker y Matthias Bethge, “A Neural Algorithm of Artistic Style”, arXiv (2015),
https://arxiv.org/abs/1508.06576.

Con licencia para


288 CPASADO8Aprendizaje profundo generativo

Aquí,distanciaes una función norma como la norma L2,contenidoes una función que
toma una imagen y calcula una representación de su contenido, y estiloes una función
que toma una imagen y calcula una representación de su estilo. Minimizar estas causas
de pérdidaestilo (imagen_generada)estar cerca deestilo (referencia_imagen),
ycontenido (imagen_generada)escerca decontenido (imagen_generada),logrando
así la transferencia del estilo tal y como lo definimos.
Una observación fundamental realizada por Gatys et al. era esa profunda neurona
convolucionalLas redes ral ofrecen una manera de definir matemáticamente las funciones
de estilo y contenido. Veamos cómo.

8.3.1 La pérdida de contenido


Como ya sabe, las activaciones de capas anteriores en una red contienen información
local sobre la imagen, mientras que las activaciones de capas superiores contienen
información abstracta cada vez más global. Formulado de manera diferente, las
activaciones de las diferentes capas de una convnet proporcionan una descomposición
del contenido de una imagen en diferentes escalas espaciales. Por lo tanto, esperaría que
el contenido de una imagen, que es más global y abstracto, sea capturado por las
representaciones de las capas superiores en un convnet.
Un buen candidato para la pérdida de contenido es, por lo tanto, la norma L2
entre las activaciones de una capa superior en un convnet preentrenado, calculadas
sobre la imagen de destino, y las activaciones de la misma capa calculadas sobre la
imagen generada. Esto garantiza que, vista desde la capa superior, la imagen
generada se verá similar a la imagen de destino original. Suponiendo que lo que ven
las capas superiores de una convnet es realmente el contenido de sus imágenes de
entrada, esto funciona como una forma de preservar el contenido de la imagen.

8.3.2 La pérdida de estilo


La pérdida de contenido solo utiliza una única capa superior, pero la pérdida de
estilo definida por Gatys et al. utiliza varias capas de una convnet: intenta capturar
la apariencia de la imagen de referencia de estilo en todas las escalas espaciales
extraídas por la convnet, no solo en una sola escala. Para la pérdida de estilo, Gatys
et al. use la matriz de Gram de las activaciones de una capa: el producto interno de
los mapas de características de una capa determinada. Este producto interno puede
entenderse como la representación de un mapa de las correlaciones entre las
características de la capa. Estas correlaciones de características capturan las
estadísticas de los patrones de una escala espacial particular, que corresponden
empíricamente a la apariencia de las texturas que se encuentran en esta escala.
Por lo tanto, la pérdida de estilo tiene como objetivo preservar correlaciones internas
similares dentro de las activaciones de diferentes capas, a través de la imagen de
referencia de estilo y la imagen generada. A su vez, esto garantiza que las texturas
encontradas en diferentes escalas espaciales se vean similares en la imagen de referencia
de estilo y la imagen generada.
En resumen, puede usar un convnet preentrenado para definir una pérdida que hará lo siguiente:
◾ Preserve el contenido manteniendo activaciones de capa de alto nivel similares
entre la imagen de contenido de destino y la imagen generada. El convnet debe

Con licencia para


"ver" que tanto la imagen de destino como la imagen generada contienen las
mismas cosas.

Con licencia para


Neuraltransferencia de estilo 289

◾ Preserve el estilo manteniendo correlaciones similares dentro de las activaciones


tanto para las capas de bajo nivel como para las capas de alto nivel. Las
correlaciones de características capturan texturas: la imagen generada y la imagen
de referencia de estilo deben compartir las mismas texturas en diferentes escalas
espaciales.
Ahora, veamos una implementación de Keras del algoritmo de transferencia de
estilo neuronal original de 2015. Como verá, comparte muchas similitudes con la
implementación de DeepDream desarrollada en la sección anterior.

8.3.3 Transferencia de estilo neuronal en Keras


La transferencia de estilo neuronal se puede implementar utilizando cualquier
convnet preentrenado. Aquí, utilizará la red VGG19 utilizada por Gatys et al.
VGG19 es una variante simple de la red VGG16 presentada en el capítulo 5, con
tres capas convolucionales más.
Este es el proceso general:
1Configure una red que calcule las activaciones de capa VGG19 para la imagen de
referencia de estilo, la imagen de destino y la imagen generada al mismo tiempo.
2Utilice las activaciones de capa calculadas sobre estas tres imágenes para
definir la función de pérdida descrita anteriormente, que minimizará para
lograr la transferencia de estilo.
3Configure un proceso de descenso de gradiente para minimizar esta función de pérdida.

Comencemos definiendo las rutas a la imagen de referencia de estilo y la imagen de


destino. Para asegurarse de que las imágenes procesadas tengan un tamaño similar (los
tamaños muy diferentes dificultan la transferencia de estilo), luego cambiará el tamaño
de todas a una altura compartida de 400 px.

Listado 8.14 Definición de variables iniciales

desde keras.preprocessing.image importar load_img, Ruta a la imagen que desea


img_to_array transformar
target_image_path = 'img/retrato.jpg'
style_reference_image_path = 'img/transfer_style_reference.jpg'
Ruta a la
imagen de
ancho, alto = load_img(target_image_path).tamaño estilo
img_altura = 400 Dimensiones de la imagen
img_width = int(ancho * img_height / generada
altura)

Necesita algunas funciones auxiliares para cargar, preprocesar y posprocesar las


imágenes que entran y salen de la convnet VGG19.

Listado 8.15 Funciones auxiliares

importar numpy como np


de keras.applications importar vgg19
def preprocess_image(image_path):
img = load_img(image_path, target_size=(img_height,
img_width)) img = img_to_array(img)
img = np.expand_dims(img, eje=0)
Con licencia para
img = vgg19.preprocess_input(img)
devolver img

Con licencia para


290 CPASADO8Aprendizaje profundo generativo

def deprocesar_imagen(x):
x[:, :, 0] += 103.939 Centrado en cero mediante la eliminación del valor
x[:, :, 1] += 116.779 de píxel medio de ImageNet. Esto invierte una
x[:, :, 2] += 123,68 transformación realizada por
x = x[:, :, ::-1] vgg19.preprocess_input.
x = np.clip(x, 0, Convierte imágenes de 'BGR' a
255).astype('uint8') devuelve x 'RGB'.Esto también es parte de la
reversión de
vgg.19.preprocess_input.

Configuremos la red VGG19. Toma como entrada un lote de tres imágenes: la imagen
de referencia de estilo, la imagen de destino y un marcador de posición que contendrá la
imagen generada. Un marcador de posición es un tensor simbólico, cuyos valores se
proporcionan externamente a través de matrices Numpy. La referencia de estilo y la
imagen de destino son estáticas y, por lo tanto, se definen mediante K.constant, mientras
que los valores contenidos en el marcador de posición de la imagen generada cambiarán
con el tiempo.

Listado 8.16 Cargando la red VGG19 preentrenada y aplicándola a las tres imágenes

Marcador de posición que


desde keras import backend contendrá la imagen
como K generada

target_image = K.constant(preprocess_image(target_image_path))
style_reference_image =
K.constant(preprocess_image(style_reference_image_path)) combinación_imagen =
K.placeholder((1, img_height, img_width, 3))

input_tensor = K.concatenate([target_image,
imagen_referencia_estilo, Combina las tres
imágenes en un solo
imagen_combinación],
lote.
eje=0)

modelo = Construye el VGG19 red con el


vgg19.VGG19(entrada_tensor=entrada_tensor, lote de tres imágenes como
pesos='imagenet',in entrada. El modelo se cargará
clude_top=Falso) con pesos ImageNet previamente
print('Modelo cargado.') entrenados.

Definamos la pérdida de contenido, que garantizará que la capa superior de la convnet


VGG19 tenga una vista similar de la imagen de destino y la imagen generada.

Listado 8.17 Contenidopérdida

def content_loss(base, combinación):


return K.sum(K.square(combinación - base))

Lo siguiente es la pérdida de estilo. Utiliza una función auxiliar para calcular la


matriz de Gram de una matriz de entrada: un mapa de las correlaciones encontradas
en la matriz de características original.

Listado 8.18 Estilopérdida

Con licencia para


def matriz_gramo(x):
características = K.batch_flatten(K.permute_dimensions(x, (2,
0, 1))) gramo = K.dot(características,
K.transpose(características))
gramo de vuelta

Con licencia para


Neuraltransferencia de estilo 291

def style_loss(estilo,
combinación): S =
gram_matrix(estilo)
C = gram_matrix
(combinación) canales = 3
tamaño = img_alto * img_ancho
return K.sum(K.square(S - C)) / (4. * (canales ** 2) * (tamaño ** 2))

A estos dos componentes de pérdida, se suma un tercero: la pérdida de variación total,


que opera sobre los píxeles de la imagen combinada generada. Fomenta la continuidad
espacial en la imagen generada, evitando así resultados excesivamente pixelados.
Puedes interpretarlo como una pérdida de regularización.

Listado 8.19 Variación totalpérdida

def
pérdida_variación_total(
x): a = K.cuadrado(
x[:, :img_height - 1, :img_width - 1, :] -
x[:, 1:, :img_width - 1, :])
b = K.cuadrado(
x[:, :img_height - 1, :img_width - 1, :] -
x[:, :img_height - 1, 1:, :])
devuelve K.sum(K.pow(a + b,
1.25))

La pérdida que minimiza es un promedio ponderado de estas tres pérdidas. Para calcular
elpérdida de contenido, usa solo una capa superior, la capa block5_conv2, mientras que para
la pérdida de estilo, usa una lista de capas que abarca tanto las capas de bajo nivel como las
de alto nivel. Agrega la pérdida de variación total al final.
Según la imagen de referencia de estilo y la imagen de contenido que esté
utilizando, es probable que desee ajustar el coeficiente content_weight (la contribución
del contenidopérdida a la pérdida total). Un content_weight más alto significa que el
contenido de destino será más reconocible en la imagen generada.

Listado 8.20 Definiendo la pérdida final que minimizarás

Diccionario que asigna nombres


de capas a tensores de
activación
outputs_dict = dict([(layer.name, layer.output) for layer in model.layers])
content_layer = 'block5_conv2'
capas_estilo = peso_estilo = 1.
['bloque1_conv1', contenido_peso = 0.025
'bloque2_conv1'
,
'bloque3_conv1'
,
'bloque4_conv1'
,
'bloque5_conv1'
]
peso_variación_total = 1e-4
Con licencia para
Capa utilizada para la pérdida de contenido

Capas utilizadas para la pérdida de estilo.

Pesos en la media
ponderada de los
componentes de pérdida

Con licencia para


292 CPASADO8Aprendizaje profundo generativo

pérdida = K.variable(0.) Definirá la pérdida


Agre características_capa =
gael agregando todos los
outputs_dict[capa_contenido] componentes a esta variable
conte
nido características_imagen_objetivo = escalar.
pérdida características_capa[0, :, :, :]
características_combinación =
características_capa[2, :, :, :]
pérdida += contenido_peso *
contenido_pérdida(target_image_features,
combinación_características)
Agrega un
para nombre_capa en capas_estilo:
estilocomponent
características_capa = e de pérdida
Agrega el salidas_dict[nombre_capa] para cada capa
estilo_referencia_características = objetivo
capa_características[1, :, :, :]
combinación_características = capa_características[2,
:, :, :]
total sl = pérdida_estilo(características_referencia_estilo,
variación características_combinación) pérdida += (peso_estilo /
pérdid len(capas_estilo)) * sl
a
pérdida += peso_variación_total * pérdida_variación_total(imagen_combinación)

Por último, configurará el proceso de descenso de gradiente. En el original Gatys et


al. paper, la optimización se realiza usando el algoritmo L-BFGS, así que eso es lo
que usará aquí. Esta es una diferencia clave con el ejemplo de DeepDream en la
sección 8.2. El algoritmo L-BFGS viene empaquetado con SciPy, pero existen dos
pequeñas limitaciones con la implementación de SciPy:
◾ Requiere que pase el valor de la función de pérdida y el valor de los
gradientes como dos funciones separadas.
◾ Solo se puede aplicar a vectores planos, mientras que tiene una matriz de imágenes 3D.

Sería ineficiente calcular el valor de la función de pérdida y el valor de los


gradientes de forma independiente, porque hacerlo llevaría a muchos cálculos
redundantes entre los dos; el proceso sería casi el doble de lento que
calcularlosconjuntamente. Para omitir esto, configurará una clase de Python llamada
Evaluator que calcula tanto el valor de pérdida como el valor de los gradientes a la vez,
devuelve el valor de pérdida cuando se llama por primera vez y almacena en caché los
gradientes para la siguiente llamada.

Listado 8.21 Configurando el proceso de descenso de gradiente

grads = K.gradients(pérdida, combinación_imagen)[0]


Obtiene
los fetch_loss_and_grads = K.function([combination_image], [loss, grads])
gradiente
s
del
imagen N
Evaluador de clase (objeto): i
generada
con n
def init (self): g
respecto a
la pérdida self.loss_value = u
Ninguno n
self.grads_values =
Con licencia para
o img_height, img_width, 3)) outs = Función para
fetch_loss_and_grads([x]) obtener los
pérd valores de la
ida Esta clase envuelve pérdida actual y
def( fetch_loss_and_grads de una manera que le la corriente
self permita recuperar las pérdidas y los gradientes a gradientes
, través de dos llamadas de método separadas, lo
x): cual es requerido por el optimizador de SciPy que
a usará.
f
i
r
m
a
r

s
e
l
f
.
l
o
s
s
_
v
a
l
u
e

e
s

N
i
n
g
u
n
o
x

x
.
r
e
s
h
a
p
e
(
(
1
,

Con licencia para


Neuraltransferencia de estilo 293

loss_value = outs[0]
grad_values = outs[1].flatten().astype('float64')
self.loss_value = loss_value
self.grad_values = grad_values
devuelve self.loss_value
def grads(self, x):
afirmar self.loss_value no es Ninguno
grad_values = np.copy(self.grad_values)
self.loss_value = Ninguno
self.grad_values = Ninguno
devolver

grad_values evaluador =

Evaluador()

Finalmente, puede ejecutar el proceso de ascenso de gradiente usando el algoritmo L-


BFGS de SciPy, guardando la imagen generada actual en cada iteración del algoritmo
(aquí, una sola iteración representa 20 pasos de ascenso de gradiente).

Listado 8.22 Bucle de transferencia de estilo

desde scipy.optimize importar


Este es el estado inicial:
fmin_l_bfgs_b desde scipy.misc importar
la imagen de destino.
imsave
tiempo de importación Aplana la imagen porque
scipy.optimize.fmin_l_bfgs_b
result_prefix = 'my_result' solo puede procesar vectores
iteraciones = 20 planos.

x = preprocess_image(target_image_path)
x = x.flatten() Ejecuta la optimización L-
for i in range(iteraciones): BFGS sobre los píxeles de
print('Inicio de iteración', la imagen generada para
i) start_time = time.time() minimizar la pérdida de
x, min_val, info = fmin_l_bfgs_b(evaluador.pérdida,
estilo neuronal. Tenga en
cuenta que debe pasar la
x,
función que calcula la
fprime=evaluador.gradua
pérdida y la función que
dos, maxfun=20) calcula los gradientes
print('Valor de pérdida actual:', min_val) como dos argumentos
img = x.copy().reshape((img_height, img_width, 3)) separados.
img = deprocess_image(img)
fname = result_prefix + '_at_iteration_%d.png' % i
imsave(fname, img) Guarda la imagen
print('Imagen guardada como', generada
fname) end_time = time.time() actualmente.
print('Iteración %d completada en %ds' % (i, end_time - start_time))

La Figura 8.8 muestra lo que obtiene. Tenga en cuenta que lo que logra esta técnica
es simplemente una forma de retexturización de imágenes o transferencia de
texturas. Funciona mejor con imágenes de referencia de estilo que tienen mucha
textura y son muy similares a sí mismas, y con objetivos de contenido que no
requieren altos niveles de detalle para ser reconocibles. Por lo general, no puede
lograr hazañas bastante abstractas, como transferir el estilo de un retrato a otro. El
algoritmo está más cerca del procesamiento de señales clásico que de la IA, ¡así que
Con licencia para
no esperes que funcione como magia!

Con licencia para


294 CPASADO8Aprendizaje profundo generativo

Figura 8.8 Algunosresultados de ejemplo

Con licencia para


Neuraltransferencia de estilo 295

Además, tenga en cuenta que la ejecución de este algoritmo de transferencia de


estilo es lenta. Pero la transformación operada por la configuración es lo
suficientemente simple como para que también pueda ser aprendida por un pequeño
y rápido convnet feedforward, siempre que tenga los datos de entrenamiento
apropiados disponibles. Por lo tanto, se puede lograr una transferencia de estilo
rápida gastando primero una gran cantidad de ciclos de cómputo para generar
ejemplos de entrenamiento de entrada y salida para una imagen de referencia de
estilo fijo, utilizando el método descrito aquí, y luego entrenando una convnet
simple para aprender esta transformación específica de estilo. Una vez hecho esto,
estilizar una imagen dada es instantáneo: es solo un paso hacia adelante de este
pequeño convnet.

8.3.4 Terminando
◾ La transferencia de estilo consiste en crear una nueva imagen que conserva el
contenido de una imagen de destino y al mismo tiempo captura el estilo de una
imagen de referencia.
◾ El contenido puede ser capturado por las activaciones de alto nivel de una convnet.
◾ El estilo puede ser capturado por las correlaciones internas de las activaciones
de diferentes capas de un convnet.
◾ Por lo tanto, el aprendizaje profundo permite que la transferencia de estilos se
formule como un proceso de optimización utilizando una pérdida definida con
una convnet preentrenada.
◾ Partiendo de esta idea básica, son posibles muchas variantes y mejoras.

Con licencia para


296 CPASADO8Aprendizaje profundo generativo

8.4 Generación de imágenes con codificadores automáticos variacionales


El muestreo de un espacio latente de imágenes para crear imágenes completamente
nuevas o editar las existentes es actualmente la aplicación más popular y exitosa de
la IA creativa. En esta sección y la siguiente, revisaremos algunos conceptos de alto
nivel relacionados con la generación de imágenes, junto con detalles de
implementación relativos a las dos técnicas principales en estedominio:
autocodificadores variacionales (VAEs) y redes antagónicas generativas (GAN). Las
técnicas que presentamos aquí no son específicas de las imágenes (podría desarrollar
espacios latentes de sonido, música o incluso texto, utilizando GAN y VAE), pero en la
práctica, los resultados más interesantes se han obtenido con imágenes, y eso es lo que nos
centramos aquí.

8.4.1 Muestreo de espacios latentes de imágenes


La idea clave de la generación de imágenes es desarrollar un espacio latente de
representaciones de baja dimensión (que, naturalmente, es un espacio vectorial) donde
cualquier punto se puede mapear en una imagen de apariencia realista. El módulo capaz
de realizar este mapeo, tomando como entrada un punto latente y emitiendo una imagen
(una cuadrícula de píxeles), se denomina generador (en el caso de GAN) o
decodificador (en el caso de VAE). Una vez que se ha desarrollado un espacio latente de
este tipo, puede muestrear puntos de él, ya sea de forma deliberada o aleatoria, y,
asignándolos al espacio de la imagen, generar imágenes que nunca antes se habían visto
(consulte la figura 8.9).

Datos de entrenamiento

Proceso
?
de
aprendi
zaje

Generador / Decodificador

Vectordel imagen
espacio artificia
Latenteespa
latente l
cio de
imagenes
(un espacio
vectorial)

Figura 8.9 Aprender un espacio vectorial latente de imágenes y usarlo para probar nuevas imágenes

GANs y VAE son dos estrategias diferentes para aprender estos espacios latentes de
representaciones de imágenes, cada una con sus propias características. Los VAE son
excelentes para aprender espacios latentes que están bien estructurados, donde direcciones
específicas codifican un eje significativo de variación en los datos. Las GAN generan
Con licencia para
imágenes que potencialmente pueden ser muy realistas, pero el espacio latente del que
provienen puede no tener tanta estructura ni continuidad.

Con licencia para


Generación de imágenes con variacióncodificadores automáticos 297

Figura 8.10 Un espacio continuode rostros generados por Tom White usando VAE

8.4.2 Vectores conceptuales para la edición de imágenes


Ya insinuamos la idea de un vector conceptual cuando tratamos las incrustaciones de
palabras en el capítulo 6. La idea sigue siendo la misma: dado un espacio latente de
representaciones, o un espacio incrustado, ciertas direcciones en el espacio pueden
codificar interesantes ejes de variación. ación en los datos originales. En un espacio
latente de imágenes de caras, por ejemplo, puede haber un vector de sonrisa s, tal que si
el punto latente z es la representación incrustada de una cara determinada, entonces el
punto latente z + s es la representación incrustada de la misma. cara, sonriendo. Una vez
que haya identificado dicho vector, será posible editar imágenes proyectándolas en el
espacio latente, moviendo su representación de manera significativa y luego
decodificándolas de nuevo al espacio de la imagen. Hay vectores conceptuales para
esencialmente cualquier dimensión independiente de variación en el espacio de la
imagen, en el caso de las caras, puede descubrir vectores para agregar gafas de sol a una
cara, quitarse las gafas, convertir una cara masculina en una cara femenina, etc. La
Figura 8.11 es un ejemplo de un vector de sonrisa, un vector conceptual descubierto por
Tom White de la Escuela de Diseño de la Universidad de Victoria en Nueva Zelanda,
utilizando VAE entrenados en un conjunto de datos de caras de celebridades (el
conjunto de datos CelebA).

Con licencia para


298 CPASADO8Aprendizaje profundo generativo

Figura 8.11 el vector de la sonrisa

8.4.3 Codificadores automáticos variacionales


Los autocodificadores variacionales, descubiertos simultáneamente por Kingma y
Welling en diciembre de 20136 y Rezende, Mohamed y Wierstra en enero de
20147, son un tipo de modelo generativo especialmente apropiado para la tarea de
edición de imágenes mediante vectores conceptuales. Son una versión moderna de
los codificadores automáticos, un tipo de red que tiene como objetivo codificar una
entrada en un espacio latente de baja dimensión y luego volver a decodificarla, que
combina ideas del aprendizaje profundo con la inferencia bayesiana.
Un codificador automático de imágenes clásico toma una imagen, la asigna a un
espacio vectorial latente a través de un módulo codificador y luego la decodifica a
una salida con las mismas dimensiones que la imagen original, a través de un
módulo decodificador (consulte la figura 8.12). Luego se entrena usando como
datos de destino las mismas imágenes que las imágenes de entrada, lo que significa
que el codificador automático aprende a reconstruir las entradas originales. Al
imponer varias restricciones en el código (la salida del codificador), puede hacer
que el codificador automático aprenda representaciones latentes más o menos
interesantes de los datos. Por lo general, restringirá el código para que sea poco
dimensional y escaso (principalmente ceros), en cuyo caso el codificador actúa
como una forma de comprimir los datos de entrada en menos bits de información.

6
Diederik P. Kingma y Max Welling, “Auto-Coding Variational Bayes, arXiv (2013),https://arxiv.org/ abs/1312.6114.
7 Danilo Jimenez Rezende, Shakir Mohamed, and Daan Wierstra, “Stochastic Backpropagation and Approximate
Inferencia enDeep Generativo
Modelos,” arXiv (2014), https://arxiv.org/abs/1401.4082.

Con licencia para


Generación de imágenes con variacióncodificadores automáticos 299

codificador Descifrador

entrada representació Reconstruidoa


original n comprimida porteX
X

Figura8.12 Un codificador automático: mapeo de una entradaXa una representación


comprimiday luego decodificarlo de nuevo comoX'

En la práctica, estos codificadores automáticos clásicos no conducen a espacios


latentes particularmente útiles o bien estructurados. Tampoco son muy buenos en la
compresión. Por estas razones, han pasado de moda en gran medida. Los VAE, sin
embargo, aumentan los codificadores automáticos con un poco de magia estadística
que los obliga a aprender espacios latentes continuos y altamente estructurados. Han
resultado ser una poderosa herramienta para la generación de imágenes. Un VAE, en
lugar de comprimir su imagen de entrada en un código fijo en el espacio latente,
convierte la imagen en los parámetros de una distribución estadística: una media y
una varianza. Esencialmente, esto significa que está asumiendo que la imagen de
entrada ha sido generada por un proceso estadístico, y que la aleatoriedad de este
proceso debe tenerse en cuenta durante la codificación y decodificación. Luego, el
VAE usa la media y los parámetros de varianza para muestrear aleatoriamente un
elemento de la distribución y decodifica ese elemento de vuelta a la entrada original
(consulte la figura 8.13). La estocasticidad de este proceso mejora la robustez y
obliga al espacio latente a codificar representaciones significativas en todas partes:
cada punto muestreado en el espacio latente se decodifica en una salida válida.

Distribución sobre el
espacio latente definido
Imagen de entrada por z_mean y z_log_var

codificador
imagen
reconstrui
da

Descifrador

Puntomuestre
ado
aleatoriamente
de la
distribución

Figura 8.13 Un VAE asigna una imagen a dos vectores,media_zyz_log_sigma, que definen
una distribución de probabilidad sobre el espacio latente, utilizada para muestrear un punto
latente a decodificar.

Con licencia para


300 CPASADO8Aprendizaje profundo generativo

En términos técnicos, así es como funciona un VAE:


1Un módulo codificador convierte las muestras de entrada entrada_imgen dos
parámetros enun espacio latente de representaciones,media_zyz_log_varianza.
2Muestreas aleatoriamente un punto zde la distribución normal latente que se supone que
genera la imagen de entrada, a través dez = z_media + exp(z_log_varianza)
*épsilon, dóndeépsilones un tensor aleatorio de valores pequeños.
3Un módulo decodificador mapea este punto en el espacio latente de vuelta a la
imagen de entrada original.
Debido a que épsilon es aleatorio, el proceso asegura que cada punto que esté cerca de la
ubicación latenteción donde codificó input_img (z-mean) se puede decodificar a algo similar
ainput_img, obligando así al espacio latente a ser continuamente significativo. Cualquiera de
los dos puntos cercanos en el espacio latente se decodificará en imágenes muy similares. La
continuidad, combinada con la baja dimensionalidad del espacio latente, obliga a cada
dirección en el espacio latente a codificar un eje significativo de variación de los datos, lo
que hace que el espacio latente esté muy estructurado y, por lo tanto, sea muy adecuado para
la manipulación a través de vectores conceptuales.
Los parámetros de un VAE se entrenan a través de dos funciones de pérdida: una
pérdida de reconstrucción que obliga a las muestras decodificadas a coincidir con las
entradas iniciales y una pérdida de regularización que ayuda a aprender espacios
latentes bien formados y reduce el sobreajuste de los datos de entrenamiento.
Repasemos rápidamente una implementación Keras de un VAE. Esquemáticamente, se
ve así:

z_mean, z_log_variance = codificador


Codifica la entrada en un
(input_img) z = z_mean + exp parámetro de media y
varianza
Decodifi (z_log_variance) * epsilon reconstruido_img
Dibuja un punto latente
ca z de
= decodificador (z) utilizando un pequeño
nuevo a
épsilon aleatorio
modelo = Modelo (entrada_img,reconstruido_img)
una instanciasel modelo de codificador
imagen automático, que asigna una
imagen de entrada a su
reconstrucción

A continuación, puede entrenar el modelo utilizando la pérdida de reconstrucción y


la pérdida de regularización. La siguiente lista muestra la red de codificador que
usará, asignando imágenes a los parámetros de una distribución de probabilidad
sobre el espacio latente. Es una convnet simple
que mapea la imagen de entradaXa dos vectores,media_zyz_log_var.

Listado 8.23 Red de codificador VAE

importar kera img_forma = (28, 28, 1)


de keras importar capas lote_tamaño = 16
desde keras import backend latent_dim = 2
como K desde keras.models
import Model import numpy as
np

Con licencia para


Dimensionalidad del
espacio latente: un
plano 2D

input_img = keras.Input(forma=img_forma)

Con licencia para


Generación de imágenes con variacióncodificadores automáticos 301

x = capas.Conv2D(32, 3,
padding='igual',
activación='relu')(input_img) x = capas.Conv2D(64, 3,
padding='igual',
activación='relu', zancadas=(2,
2))(x)
x = capas.Conv2D(64, 3,
relleno='igual',
activación='relu')(x) x = capas.Conv2D(64, 3,
relleno='igual',
activación='relu')(x) forma_antes_aplanamiento =
K.int_forma(x)
x = capas.Aplanar()(x)
x = capas.Densa(32, activación='relu')(x)
La imagen de entrada
z_mean = capas.Dense(latent_dim)(x)
termina siendo codificada
z_log_var = capas.Dense(latent_dim)(x) en estos dos parámetros.

El siguiente es el código para usar z_mean y z_log_var, los parámetros de la distribución


estadística que se supone que produjeron input_img, para generar un punto espacial latente
z. Aquí, envuelve un código arbitrario (construido sobre las primitivas de back-end de
Keras) en una capa Lambda. En Keras, todo debe ser una capa, por lo que el código que no
forma parte de una capa integrada debe envolverse en una Lambda (o en una capa
personalizada).

Listado 8.24 Función de muestreo de espacio latente

muestreo de definición (argumentos):


z_mean, z_log_var = argumentos
epsilon = K.random_normal(shape=(K.shape(z_mean)[0], latent_dim),
mean=0., stddev=1.)
devuelve z_mean + K.exp(z_log_var) * epsilon
z = capas.Lambda(muestreo)([z_mean, z_log_var])

La siguiente lista muestra la implementación del decodificador. Remodela el vector z a


las dimensiones de una imagen y luego usa algunas capas de convolución para obtener
una salida de imagen final que tiene las mismas dimensiones que el input_img original.

Listado 8.25 Red decodificadora VAE, mapeo de puntos de espacio latente a imágenes

entrada_decodificador = Entrada donde


capas.Entrada(K.int_shape(z)[1:])

x = alimentará z Aumenta la
capas.Densa(np.prod(forma_antes_aplanamiento[1:]),
activación='relu')(decodificador_ muestra de la entrada

entrada)x = capas. Reformar

(forma_antes_aplanamiento [1:]) (x)

x = capas.Conv2DTranspose(32, 3, 2
padding='igual', )
activación='relu', )
zancadas=(2, (

Con licencia para


x)
x = capas.Conv2D(1, 3, Utiliza una transposición
padding='igual', Conv2Dcapa y capa
activación='sigmoide')(x) Conv2D para decodificar z
en un mapa de
Cambia la forma de z en un mapa de características con la misma características del mismo
forma que el mapa de características justo antes de la última capa tamaño que la entrada de
Flatten en el modelo del codificador imagen original

Con licencia para


302 CPASADO8Aprendizaje profundo generativo

decodificador = Modelo Crea una instancia del modelo del


(entrada_decodificador, x) decodificador, que se convierte en
"decoder_input"
z_decodificado =
Lo aplica a z para en la imagen decodificada
decodificador (z)
recuperar el z
decodificado

La pérdida dual de un VAE no se ajusta a la expectativa tradicional de una función de


muestrade la forma loss(input, target). Por lo tanto, configurará la pérdida escribiendo una
capa personalizada que utilice internamente el método de capa incorporado add_loss para
crear una pérdida arbitraria.

Listado 8.26 Capa personalizada utilizada para calcular el VAEpérdida

clase CustomVariationalLayer(keras.layers.Layer):

def vae_loss(self, x, z_decoded):


x = K.flatten(x)
z_decodificado = K.flatten(z_decodificado)
xent_loss = keras.metrics.binary_crossentropy(x, z_decoded)
kl_loss = -5e-4 * K.mean(
1 + z_log_var - K.square(z_mean) - K.exp(z_log_var), eje=-1)
return K.mean(xent_loss + kl_loss)

def call(self, Implementa capas


No usa esta entradas): x = personalizadas escribiendo un
salida, pero entradas[0] método de llamada.
la capa debe z_decodificado = entradas[1]
devolver pérdida = self.vae_loss(x,
algo. Llama a la capa
z_decoded) self.add_loss(pérdida,
personalizada en la
entradas=entradas) devuelve x entrada y la salida
decodificada para obtener
y = CustomVariationalLayer()([input_img, z_decoded]) la salida del modelo final

Finalmente, está listo para instanciar y entrenar el modelo. Debido a que la pérdida
se soluciona en la capa personalizada, no especifica una pérdida externa en el
momento de la compilación (loss=None), lo que a su vez significa que no pasará
datos de destino durante el entrenamiento (como puede ver,solo pase x_train al
modelo en ajuste).

Listado 8.27 Entrenando alVAE

desde keras.datasets import mnist

vae = Model(input_img, y)
vae.compile(optimizer='rmsprop',
loss=Ninguno) vae.summary()
(x_tren, _), (x_prueba, y_prueba) = mnist.load_data()
x_train = x_train.astype('float32') / 255.
x_train = x_train.reshape(x_train.shape + (1,))
x_test = x_test.astype('float32') / 255.
prueba_x = prueba_x.reforma(prueba_x.forma + (1,))
vae.fit(x=x_tren, y=Ninguno,
barajar=Verdadero,

Con licencia para


épocas=10,
tamaño_lote=tamaño_lot
e,
validación_datos=(x_prueba, Ninguno))

Con licencia para


Generación de imágenes con variacióncodificadores automáticos 303

Una vez que dicho modelo está entrenado, en MNIST, en este caso, puede usar la red
del decodificador para convertir vectores espaciales latentes arbitrarios en imágenes.

Listado 8.28 Muestreando una cuadrícula de puntos del espacio latente 2D y decodificándolos a
imágenes

importar matplotlib.pyplot como


plt desde scipy.stats norma de
Mostrará una cuadrícula de15 ×15
importación dígitos (255 dígitos en total).
n = 15 Transforma linealmente espaciadas
tamaño_dígito = 28
figure = np.zeros((digit_size * n, digit_size * n)) coordenadas usando el SciPyfunción
grid_x = norm.ppf(np.linspace(0.05, 0.95, n)) ppf para producir valores de la
grid_y = norm.ppf(np.linspace(0.05, 0.95, n)) variable latente z (porque el
anterior del espacio latente es
para i, yi en enumerate(grid_x): gaussiano)
para j, xi en
Repite z varias veces para
enumerate(grid_y): formar un lote completo
muestra_z = np.matriz([[xi, yi]])
z_sample = np.tile(z_sample, batch_size).reshape(batch_size, 2)
x_decoded = decoder.predict(z_sample, batch_size=batch_size)
digit = x_decoded[0].reshape(digit_size, digit_size)
figura[i * tamaño_dígito: (i + 1) * tamaño_dígito,
j * tamaño_dígito: (j + 1) * tamaño_dígito] = dígito

plt.figure(figsize=(10, 10)) Cambia la forma del


plt.imshow(figure, cmap='Greys_r') primer dígito del lote de 28
plt.show() × 28 × 1
a 28 × 28
Decodifica el lote
en imágenes de
dígitos

La cuadrícula de dígitos
muestreados (consulte la figura
8.14) muestra una distribución
completamente continua de las
diferentes clases de dígitos, con un
dígito transformándose en otro a
medida que sigue un camino a
través del espacio latente. Las
direcciones específicas en este
espacio tienen un significado: por
ejemplo, hay una dirección para
“cuatro”, “uno”, etc.
En la siguiente sección,
cubriremos en detalle la otra
herramienta principal para generar
imágenes artificiales: las redes Figura 8.14 Cuadrícula de dígitos decodificados de
adversariales generativas (GAN). la latenteespacio

Con licencia para


304 CPASADO8Aprendizaje profundo generativo

8.4.4 Terminando
◾ La generación de imágenes con aprendizaje profundo se realiza mediante el
aprendizaje de espacios latentes que capturan información estadística sobre un
conjunto de datos de imágenes. Al muestrear y decodificar puntos del espacio
latente, puede generar imágenes nunca antes vistas. Hay dos herramientas
principales para hacer esto:VAEarenaGANs.
◾ VAEs dan como resultado representaciones latentes continuas altamente
estructuradas. Por esta razón, funcionan bien para realizar todo tipo de edición de
imágenes en el espacio latente: intercambio de caras, convertir una cara con el
ceño fruncido en una cara sonriente, etc. También funcionan muy bien para hacer
animaciones basadas en el espacio latente, como animar un paseo a lo largo de
una sección transversal del espacio latente, mostrando una imagen inicial que se
transforma lentamente en diferentes imágenes de forma continua.
◾ GANs permiten la generación de imágenes realistas de un solo cuadro, pero
pueden no inducir espacios latentes con estructura sólida y alta continuidad.
La mayoría de las aplicaciones prácticas exitosas que he visto con imágenes se basan en
VAE, pero los GAN son extremadamente populares en el mundo de la investigación
académica, al menos, alrededor de 2016-2017. Descubrirá cómo funcionan y cómo
implementar uno en la siguiente sección.

PROPINAPara seguir jugando con la generación de imágenes, sugiero trabajar


con el conjunto de datos de atributos de rostros de celebridades a gran escala
(CelebA). Es un conjunto de datos de imágenes de descarga gratuita que
contiene más de 200.000 retratos de celebridades. Es excelente para
experimentar con vectores conceptuales en particular: definitivamente supera a
MNIST.

Con licencia para


Introducción al adversario generativoredes 305

8.5 Introducción a las redes antagónicas generativas


Las redes adversariales generativas (GAN), introducidas en 2014 por Goodfellow et
al.8, son una alternativa a las VAE para el aprendizaje de espacios latentes de imágenes.
Permiten la generación de imágenes sintéticas bastante realistas al obligar a las
imágenes generadas a ser estadísticamente casi indistinguibles de las reales.
Una forma intuitiva de entender las GAN es imaginar a un falsificador tratando
de crear una pintura falsa de Picasso. Al principio, el falsificador es bastante malo
en la tarea. Mezcla algunas de sus falsificaciones con obras de Picasso auténticas y
se las muestra todas a un marchante de arte. El marchante de arte hace una
evaluación de autenticidad de cada pintura y le da al falsificador información sobre
lo que hace que un Picasso parezca un Picasso. El falsificador vuelve a su estudio
para preparar nuevas falsificaciones. A medida que pasa el tiempo, el falsificador se
vuelve cada vez más competente para imitar el estilo de Picasso, y el comerciante
de arte se vuelve cada vez más experto en detectar falsificaciones. Al final, tienen
entre manos unos excelentes Picassos falsos.
Eso es lo que es una GAN: una red de falsificadores y una red de expertos, cada una
entrenada para superar a la otra. Como tal, una GAN se compone de dos partes:
◾ Red de generadores: toma como entrada un vector aleatorio (un punto aleatorio
en el espacio latente) y lo decodifica en una imagen sintética
◾ Red discriminadora (o adversario): toma como entrada una imagen (real o sintética)
y predice si la imagen provino del conjunto de entrenamiento o fue creada por la red
del generador.
La red generadora está entrenada para poder engañar a la red discriminadora, y así
evoluciona hacia la generación de imágenes cada vez más realistas a medida que
avanza el entrenamiento: imágenes artificiales que parecen indistinguibles de las
reales, hasta el punto de que es imposible para el discriminador. red para distinguir
los dos (ver figura 8.15). Mientras tanto, el discriminador se adapta constantemente
a las capacidades de mejora gradual del generador, estableciendo un alto nivel de
realismo para las imágenes generadas. Una vez que finaliza el entrenamiento, el
generador es capaz de convertir cualquier punto en su espacio de entrada en una
imagen creíble. A diferencia de los VAE, este espacio latente tiene menos garantías
explícitas de estructura significativa; en particular, no es continua.

8
Ian Goodfellow et al., "Redes antagónicas generativas", arXiv (2014),https://arxiv.org/abs/1406.2661.

Con licencia para


306 CPASADO8Aprendizaje profundo generativo

Aleatoriovector Imagen
de la generada
espacio (descifrad
latente
a)

Generador
(decodificador) Retroali
mentació
n de
entrena
miento

Discriminado "Una verdadera


falsedad"

Mezcla de
imágenes reales
y falsas.

Figura 8.15 Un generador transforma vectores latentes aleatorios en imágenes y un


discriminador busca diferenciar las imágenes reales de las generadas. El generador está
entrenado para engañar al discriminador.

Sorprendentemente, una GAN es un sistema donde el mínimo de optimización no es


fijo, a diferencia de cualquier otra configuración de entrenamiento que haya encontrado
en este libro. Normalmente, el descenso de pendiente consiste en rodar cuesta abajo en
un paisaje de pérdida estática. Pero con una GAN, cada paso cuesta abajo cambia un
poco todo el paisaje. Es un sistema dinámico donde el proceso de optimización no busca
un mínimo, sino un equilibrio entre dos fuerzas. Por esta razón, las GAN son
notoriamente difíciles de entrenar: hacer que una GAN funcione requiere muchos
ajustes cuidadosos de la arquitectura del modelo y los parámetros de entrenamiento.

Figura 8.16 Habitantes del espacio latente. Imágenes generadas por Mike
Tyka usandouna GAN de varias etapas entrenada en un conjunto de
datos de rostros (www.miketyka.com).

Con licencia para


Introducción al adversario generativoredes 307

8.5.1 Una implementación esquemática de GAN


En esta sección, explicaremos cómo implementar una GAN en Keras, en su forma más
básica, debido a que las GAN son avanzadas, profundizar en los detalles técnicos estaría
fuera del alcance de este libro. La implementación específica es una GAN
convolucional profunda (DCGAN): una GAN donde el generador y el discriminador son
conexiones profundas. En particular, utilizauna capa Conv2DTranspose para el muestreo
superior de imágenes en el generador.
Entrenará la GAN con imágenes de CIFAR10, un conjunto de datos de 50 000 32 × 32 RGB
imágenes pertenecientes a10 clases (5.000 imágenes por clase). Para facilitar las
cosas, solo usará imágenes que pertenezcan a la clase "rana".
Esquemáticamente, la GAN se ve así:
1Ageneradormapasde red vectores de forma(latent_dim,)a imágenes de forma
(32, 32, 3).
2Adiscriminadomapas de red imágenes de forma (32, 32, 3)a una puntuación
binaria que estima la probabilidad de que la imagen sea real.
3Una red gan encadena el generador y el discriminador: gan(x) =
discriminador(generador(x)). Por lo tanto, esta red gan asigna vectores espaciales
latentes a la evaluación del discriminador del realismo de estos vectores latentes
tal como los decodifica el generador.
4Entrena al discriminador usando ejemplos de imágenes reales y falsas junto con
etiquetas "reales"/"falsas", tal como entrena cualquier modelo normal de
clasificación de imágenes.
5Para entrenar el generador, utiliza los gradientes de los pesos del generador con
respecto a la pérdida del modelo gan. Esto significa que, en cada paso, mueve
los pesos del generador en una dirección que hace que el discriminador
clasifique como "reales" las imágenes decodificadas por el generador. En
otras palabras, entrenas al generador para engañar al discriminador.

8.5.2 Una bolsa de trucos


El proceso de entrenamiento de GAN y ajuste de implementaciones de GAN es
notoriamente difícil. Hay una serie de trucos conocidos que debes tener en cuenta.
Como la mayoría de las cosas en el aprendizaje profundo, es más alquimia que
ciencia: estos trucos son heurísticas, no pautas respaldadas por teorías. Están
respaldados por un nivel de comprensión intuitiva del fenómeno en cuestión, y se
sabe que funcionan bien empíricamente, aunque no necesariamente en todos los
contextos.
Estos son algunos de los trucos utilizados en la implementación del generador y
discriminador GAN en esta sección. No es una lista exhaustiva de consejos
relacionados con GAN; encontrará muchos más en la literatura de GAN:
◾ Usamosbronceadocomo última activación en el generador, en lugar
desigmoideo, que se encuentra más comúnmente en otros tipos de modelos.
◾ Muestreamos puntos del espacio latente utilizando una distribución normal
(distribución gaussiana), no una distribución uniforme.

Con licencia para


308 CPASADO8Aprendizaje profundo generativo

◾ La estocasticidad es buena para inducir robustez. Porque GANel entrenamiento


da como resultado un equilibrio dinámico,GANes probableatascarse en todo
tipo de formas. Introducir la aleatoriedad durante el entrenamiento ayuda a
prevenir esto. Introducimos la aleatoriedad de dos formas: usando abandono
en el discriminador y agregando ruido aleatorio a las etiquetas para el
discriminador.
◾ Gradientes dispersos pueden dificultar GANcapacitación. En el aprendizaje
profundo, la escasez suele ser una propiedad deseable, pero no en GANs. Dos
cosas pueden inducir la escasez de gradiente: operaciones de agrupación máxima
yReLUactivaciones. En lugar de agrupación máxima, recomendamos usar
convoluciones estriadas para reducir la resolución y recomendamosusando
unLeakyReLUcapa en lugar de unaReLUactivación. es similar aReLU, pero relaja las
restricciones de escasez al permitir pequeños valores de activación negativos.
◾ En las imágenes generadas, es común ver artefactos de tablero de ajedrez
causados por una cobertura desigual del espacio de píxeles en el generador
(consulte la figura 8.17). Para arreglar esto, usamos un tamaño de núcleo que
es divisible por el tamaño de zancada cada vez que usamos unandaba a
zancadasConv2DTransponeroConv2Dtanto en el generador como en el
discriminador.

Figura 8.17 Artefactos de tablero de ajedrez causados por pasos y tamaños de


kernel que no coinciden, lo que da como resultado una cobertura de espacio de
píxeles desigual: una de las muchas trampas de las GAN

8.5.3 El generador
Primero, desarrollemos un modelo generador que convierta un vector (desde el espacio
latente—durante el entrenamiento será muestreado al azar) en una imagen candidata.
Uno de los muchos problemas que suelen surgir con las GAN es que el generador se
atasca con imágenes generadas que parecen ruido. Una posible solución es usar dropout
tanto en el discriminador como en el generador.

Listado 8.29 Red generadora GAN

importar kera
desde keras importar
capas importar numpy
como np
latent_dim = 32
altura = 32

Con licencia para


ancho = 32
canales = 3

Con licencia para


Introducción a las redes antagónicas 309
generativas

entrada_generador =
Transforma la entrada en
keras.Entrada(forma=(latent_dim,)) x = un16 ×161Mapa de
funciones de 28
capas.Densa(128 * 16 * 16)(entrada_generador) canales
x = capas.LeakyReLU()(x)
x = capas. Reformar ((16, 16, 128)) (x)
x = capas.Conv2D(256, 5, relleno='igual')(x)
x = capas.LeakyReLU()(x)
x = capas.Conv2DTranspose(256, 4, zancadas=2, Upsamples
relleno='igual')(x) x = capas.LeakyReLU()(x) a 32 × 32
x = capas.Conv2D(256, 5, relleno='igual')(x)
x = capas.LeakyReLU()(x)
x = capas.Conv2D(256, 5, relleno='igual')(x)
x = capas.LeakyReLU()(x)

x = capas.Conv2D(canales, 7, activación='tanh', relleno='mismo')(x)


generador = keras.models.Model(generator_input, x)
generador.resumen()
Produce un 32 × 321-canalmapa de
Instancia el modelo generador, que mapea la entrada de características (forma de
forma (latent_dim,) en una imagen de forma (32, 32, 3) CIFAR10 imagen)

8.5.4 el discriminador
A continuación, desarrollará un modelo discriminador que toma como entrada una imagen
candidata (real o sintética) y la clasifica en una de dos clases: "imagen generada" o "imagen
real que proviene del conjunto de entrenamiento".

Listado 8.30 La red discriminatoria de GAN

entrada_discriminador = capas.Entrada(forma=(alto, ancho, canales))


x = capas.Conv2D(128, 3)(entrada_discriminador)
x = capas.LeakyReLU()(x)
x = capas.Conv2D(128, 4, zancadas=2)(x)
x = capas.LeakyReLU()(x)
x = capas.Conv2D(128, 4, zancadas=2)(x)
x = capas.LeakyReLU()(x) Una capa de abandono:
x = capas.Conv2D(128, 4, zancadas=2)(x) un truco importante!
x = capas.LeakyReLU()(x)
x = capas.Aplanar()(x) Capa de clasificación
x = capas.Abandono(0.4)(x)
instanciasel modelo
x = capas.Densa(1, activación='sigmoide')(x) discriminador, que convierte
dor,
discriminador = keras.models.Model(discriminator_input, x)
discriminator.summary()
discriminador_optimizador =
keras.optimizadores.RMSprop( lr=0.0008,
valor de
recorte =
1.0,decaimient
o=1e-8)
discriminador.compilar(optimizador=optimizador_discrimina

Con licencia para


y_crossentropy') una entrada (32, 32, 3)
en una decisión de
clasificación binaria
(falsa/real)

Utiliza recorte de
degradado (por valor) en el
optimizador

Estabilizar
entrenamiento, utiliza el
decaimiento de la tasa
de aprendizaje

Con licencia para


310 CPASADO8Aprendizaje profundo generativo

8.5.5 La red contradictoria


Finalmente, configurará la GAN, que encadena el generador y el discriminador.
Cuando se entrena, este modelo moverá el generador en una dirección que mejora
su capacidad para engañar al discriminador. Este modelo convierte los puntos de
espacio latente en una decisión de clasificación, "falsa" o "real", y está destinado a
ser entrenado con etiquetas que siempre son“Estas son imágenes reales.” Por lo tanto, el
gan de entrenamiento actualizará los pesos del generador de una manera que hace que el
discriminador sea más probable que prediga "real" cuando mira imágenes falsas. Es muy
importante tener en cuenta que configura el discriminador para que se congele durante el
entrenamiento (no entrenable): sus pesos no se actualizarán cuando entrene. Si los pesos del
discriminador pudieran actualizarse durante este proceso, entonces estaría entrenando al
discriminador para que siempre prediga "real", ¡que no es lo que quiere!

Listado 8.31 Red adversaria

discriminador.entrenable= Falso
Establece los pesos del
gan_input = keras.Input(shape=(latent_dim,)) discriminador enno
gan_output = entrenable (esto solo se
discriminador(generador(gan_input)) gan = aplicará al modelo gan)
keras.models.Model(gan_input, gan_output)
gan_optimizer = keras.optimizers.RMSprop(lr=0.0004,
clipvalue=1.0,decaimiento=1e-8) gan.compile(optimizador=gan_optimizer,
loss='binary_crossentropy')

8.5.6 Cómo entrenar tu DCGAN


Ahora puedes empezar a entrenar. Para recapitular, así es como se ve esquemáticamente el ciclo de
entrenamiento. Para cada época, haga lo siguiente:
1Dibujar puntos aleatorios en el espacio latente (ruido aleatorio).
2Genera imágenes congeneradorusando este aleatorioruido.

3Mezcla las imágenes generadas con las reales.

4Entrene al discriminador utilizando estas imágenes mixtas, con los objetivos


correspondientes: ya sea "real" (para las imágenes reales) o "falso" (para las
imágenes generadas).
5Dibuja nuevos puntos aleatorios en el espacio latente.

6Entrene a Gan usando estos vectores aleatorios, con objetivos que digan "estas son
imágenes reales". Esto actualiza los pesos del generador (solo porque el
discriminador está congelado dentro de gan) para moverlos hacia que el
discriminador prediga "estas son imágenes reales" para las imágenes generadas:
esto entrena al generador para engañar al discriminador.
Vamos a implementarlo.

Listado 8.32 Implementando el entrenamiento GAN

importar sistema operativo


de keras.imagen de importación de Cargas CIFAR10 datos
preprocesamiento

(x_tren, y_tren), (_, _) = keras.datasets.cifar10.load_data()

Con licencia para


Introducción al adversario generativoredes 311

tren_x = tren_x[tren_y.aplanar() == 6]
Selecciona imágenes de ranas (clase 6)
tren_x = tren_x.reformar(
(tren_x.forma[0],) +
(alto, ancho, canales)).astype('float32') / 255. normaliza datos

iteraciones = 10000
tamaño_lote = 20
guardar_dir ='tu_dir'
Especifica dónde desea
guardar las imágenes
inicio = 0
generadas
para paso en rango (iteraciones): muestras al azar
random_latent_vectors = np.random.normal(size=(batch_size, puntos en el
latente_dim)) espacio latente

Decodifi imágenes_generadas =
ca generador.predecir(vectores_latentes_aleatorios)
a ellos Los combina
fals parada = inicio + tamaño_lote con imágenes
oimág real_images = x_tren[inicio: reales
enes parada]
imágenes_combinadas = np.concatenate([imágenes_generadas, imágenes_reales])
Ensambla etiquetas,
etiquetas = np.concatenate([np.ones((batch_size,
1)),
discriminando imágenes
reales de falsas
np.ceros((tamaño_lote,
1))])
etiquetas += 0.05 *np.random.random(etiquetas.forma)
Agrega ruido
Entrena al d_loss = aleatorio a las
discriminador etiquetas: ¡un
discriminator.train_on_batch(combined_images, etiquetas) truco
importante!
random_latent_vectors = np.random.normal(size=(batch_size,
latent_dim)) Muestrea puntos
aleatorios en el
Ensambla misleading_targets = np.zeros((batch_size, 1)) espacio latente
etiquetas
que dicen a_loss = gan.train_on_batch(random_latent_vectors, Entrena al generador (a través
“todas objetivos engañosos) del modelo gan, donde los pesos
estas son del discriminador están
imágenes inicio += tamaño_lote congelados)
reales”
(¡es
mentira!)
si inicio > len(x_tren) -
lote_tamaño: inicio = 0
Ocasionalmente guarda
y traza (cada100 pasos)
si paso % 100 == 0:
gan.save_weights('gan.h5') Guarda los pesos del
modelo
print('pérdida del discriminador:', salva uno
d_pérdida)
Imprime imagen generada
print('pérdida contradictoria:',
métricas una_pérdida)

img = image.array_to_img(generated_images[0] * 255., scale=False)


img.save(os.path.join(save_dir,
'generated_frog' + str(paso) + '.png'))
img = image.array_to_img(real_images[0] * 255., scale=False)
Con licencia para
img.save(os.path.join(save_dir,
'real_frog' + str(paso) + '.png'))

Guarda una imagen


real para
comparar

Con licencia para


312 CPASADO8Aprendizaje profundo generativo

Durante el entrenamiento, es posible que observe que la pérdida adversaria


comienza a aumentar considerablemente, mientras que la pérdida discriminatoria
tiende a cero: el discriminador puede terminar dominando al generador. Si ese es el
caso, intente reducir la tasa de aprendizaje del discriminador y aumente la tasa de
abandono del discriminador.

Figura 8.18 Juega el discriminador: en cada fila, la GAN imaginó dos imágenes y una imagen
proviene del conjunto de entrenamiento. ¿Puedes diferenciarlos? (Respuestas: el
verdaderolas imágenes en cada columna son medio, superior, inferior, medio.)

8.5.7 Terminando
◾ AGANconsiste en una red generadora acoplada con una red discriminadora.
El discriminador se entrena para diferenciar entre la salida del generador y las
imágenes reales de un conjunto de datos de entrenamiento, y el generador se
entrena para engañar al discriminador. Sorprendentemente, el generador
nunca ve imágenes del conjunto de entrenamiento directamente; la
información que tiene sobre los datos proviene del discriminador.
◾ GANs son difíciles de entrenar, porque entrenar a un GANes un proceso
dinámico en lugar de un simple proceso de descenso de gradiente con un
paisaje de pérdidas fijas. conseguir un GANentrenar correctamente requiere el
uso de una serie de trucos heurísticos, así como una gran cantidad de ajustes.
◾ GANs puede potencialmente producir imágenes altamente realistas. Pero a
diferenciaVAEs, el espacio latente que aprenden no tiene una estructura
continua ordenada y, por lo tanto, puede no ser adecuado para ciertas
aplicaciones prácticas, como la edición de imágenes a través de vectores de
concepto de espacio latente.
Con licencia para
Introducción al adversario generativoredes 313

Resumen del capítulo


◾ Con aplicaciones creativas de aprendizaje profundo, las redes profundas
van más allá de anotar el contenido existente y comienzan a generar el
suyo propio. Aprendiste lo siguiente:
– Cómo generar datos de secuencia, un paso de tiempo a la vez. Esto es
aplicable a la generación de texto y también a la generación de música
nota por nota o cualquier otro tipo de datos de series temporales.
– Cómo funciona DeepDream: maximizando la convnetactivaciones de
capa a través del ascenso de gradiente en el espacio de entrada.
– Cómo realizar el estilotransferencia, donde una imagen de contenido y
una imagen de estilo se combinan para producir resultados interesantes.
– Qué son las GAN y los VAE, cómo se pueden usar para crear nuevas
imágenes y cómo se pueden usar los vectores de concepto de espacio
latente para la edición de imágenes.
◾ Estas pocas técnicas cubren solo los conceptos básicos de este campo en
rápida expansión. Hay mucho más por descubrir: el aprendizaje
profundo generativo merece un libro completo.

Con licencia para


Conclusiones

Este capítulo cubre


◾ Conclusiones importantes de este libro
◾ Las limitaciones del aprendizaje profundo
◾ El futuro del aprendizaje profundo, el
aprendizaje automático,e IA
◾ Recursos para seguir aprendiendo y trabajar
enel campo

Casi has llegado al final de este libro. Este último capítulo resumirá y revisará los
conceptos básicos mientras expande sus horizontes más allá de las nociones
relativamente básicas que ha aprendido hasta ahora. Comprender el aprendizaje
profundo y la IA es un viaje, y terminar este libro es solo el primer paso. Quiero
asegurarme de que se dé cuenta de esto y esté debidamente equipado para dar los
próximos pasos de este viaje por su cuenta.
Comenzaremos con una vista panorámica de lo que debe sacar de este libro. Esto
debería refrescar tu memoria con respecto a algunos de los conceptos que has
aprendido. A continuación, presentaremos una descripción general de algunas
limitaciones clave del aprendizaje profundo. Para usar una herramienta de manera
adecuada, no solo debe comprender lo que puede hacer, sino también ser consciente
de lo que no puede hacer. Finalmente, ofreceré algunos pensamientos especulativos
sobre la evolución futura de los campos del aprendizaje profundo, el aprendizaje
automático y la IA. Esto debería ser especialmente interesante para usted si desea
ingresar a la investigación fundamental. El capítulo finaliza con una breve lista de
recursos y estrategias para aprender más sobre la IA y mantenerse al día con los
nuevos avances.
314
Con licencia para
Llaveconceptos en repaso 315

9.1 Conceptos clave en revisión


Esta sección sintetiza brevemente los puntos clave de este libro. Si alguna vez necesita
un repaso rápido que le ayude a recordar lo que ha aprendido, puede leer estas pocas
páginas.

9.1.1 Diversos enfoques de la IA


En primer lugar, el aprendizaje profundo no es sinónimo de IA ni de aprendizaje
automático. La inteligencia artificial es un campo antiguo y amplio que generalmente se
puede definir como "todos los intentos de automatizar procesos cognitivos", en otras
palabras, la automatización del pensamiento. Esto puede variar desde lo más básico,
como una hoja de cálculo de Excel, hasta lo más avanzado, como un robot humanoide
que puede caminar y hablar.
Aprendizaje automáticoes un subcampo específico de la IA que tiene como objetivo
el desarrollo automático de programas (llamados modelos) únicamente a partir de la
exposición a datos de entrenamiento. Este proceso de convertir datos en un programa se
llama aprendizaje. Aunque el aprendizaje automático existe desde hace mucho tiempo,
solo comenzó a despegar en la década de 1990.
Aprendizaje profundoes una de las muchas ramas del aprendizaje automático,
donde los modelos son largas cadenas de funciones geométricas, aplicadas una tras
otra. Estas operaciones están estructuradas en módulos llamados capas: los modelos
de aprendizaje profundo suelen ser pilas de capas o, de manera más general,
gráficos de capas. Estas capas están parametrizadas por pesos, que son los
parámetros aprendidos durante el entrenamiento. El conocimiento de un modelo se
almacena en sus pesos, y el proceso de aprendizaje consiste en encontrar buenos
valores para estos pesos.
Aunque el aprendizaje profundo es solo uno entre muchos enfoques del
aprendizaje automático, no está en pie de igualdad con los demás. El aprendizaje
profundo es un gran éxito. Este es el por qué.

9.1.2 que haceaprendizaje profundo


especial dentro del campo del
aprendizaje automático
En el lapso de solo unos pocos años, el aprendizaje profundo ha logrado grandes
avances en una amplia gama de tareas que históricamente se han percibido como
extremadamente difíciles para las computadoras, especialmente en el área de la
percepción de la máquina: extraer información útil de imágenes, videos, sonido, y
más. Con suficientes datos de entrenamiento (en particular, datos de entrenamiento
debidamente etiquetados por humanos), es posible extraer de los datos de
percepción casi cualquier cosa que un humano pueda extraer. Por lo tanto, a veces
se dice que el aprendizaje profundo ha resuelto la percepción, aunque eso es cierto
solo para una definición bastante estrecha de percepción.
Debido a sus éxitos técnicos sin precedentes, el aprendizaje profundo ha
provocado por sí solo el tercer y, con mucho, el mayor verano de IA: un período de
intenso interés, inversión y entusiasmo en el campo de la IA. Mientras se escribe
este libro, estamos en el medio. Si este período terminará en un futuro cercano y qué

Con licencia para


sucederá después de que termine, son temas de debate. Una cosa es segura: en
marcado contraste con los veranos anteriores de IA, el aprendizaje profundo ha
proporcionado un enorme valor comercial a varias grandes empresas de tecnología,
permitiendo el reconocimiento de voz a nivel humano, asistentes inteligentes,

Con licencia para


316 CPASADO9Conclusiones

clasificación de imágenes, traducción automática muy mejorada y más. La


exageración puede (y probablemente lo hará) retroceder, pero el impacto económico
y tecnológico sostenido del aprendizaje profundo permanecerá. En ese sentido, el
aprendizaje profundo podría ser análogo a Internet: puede que esté demasiado
promocionado durante algunos años, pero a largo plazo seguirá siendo una gran
revolución que transformará nuestra economía y nuestras vidas.
Soy particularmente optimista sobre el aprendizaje profundo porque incluso si no
hiciéramos más progreso tecnológico en la próxima década, implementar los algoritmos
existentes para cada problema aplicable sería un cambio de juego para la mayoría de las
industrias. El aprendizaje profundo es nada menos que una revolución, y el progreso se
está produciendo actualmente a un ritmo increíblemente rápido, debido a una inversión
exponencial en recursos y personal. Desde mi punto de vista, el futuro parece
prometedor, aunque las expectativas a corto plazo son algo demasiado optimistas;
implementar el aprendizaje profundo en todo su potencial llevará más de una década.

9.1.3 Cómo pensar en el aprendizaje profundo


Lo más sorprendente del aprendizaje profundo es lo simple que es. Hace diez años,
nadie esperaba que lográramos resultados tan sorprendentes en los problemas de
percepción de las máquinas mediante el uso de modelos paramétricos simples
entrenados con descenso de gradiente. Ahora, resulta que todo lo que necesita son
modelos paramétricos suficientemente grandes entrenados con descenso de
gradiente en suficientes ejemplos. Como dijo una vez Feynman sobre el universo:
"No es complicado, es solo mucho".1
En el aprendizaje profundo, todo es un vector: todo es un punto en un espacio
geométrico. Las entradas del modelo (texto, imágenes, etc.) y los objetivos primero se
vectorizan: se convierten en un espacio vectorial de entrada inicial y un espacio
vectorial de destino. Cada capa en un modelo de aprendizaje profundo opera una
transformación geométrica simple en los datos que la atraviesan. Juntas, la cadena de
capas en el modelo forma una transformación geométrica compleja, dividida en una
serie de simples. Esta transformación compleja intenta mapear el espacio de entrada al
espacio de destino, un punto a la vez. Esta transformación está parametrizada por los
pesos de las capas, que se actualizan iterativamente en función del rendimiento actual
del modelo. Una característica clave de esta transformación geométrica es que debe ser
diferenciable, que se requiere para que podamos aprender sus parámetros a través del
descenso de gradiente. Intuitivamente, esto significa que la transformación geométrica
de entradas a salidas debe ser suave y continua, una restricción importante.
Todo el proceso de aplicación de esta compleja transformación geométrica a los
datos de entrada se puede visualizar en 3D imaginando a una persona tratando de
desarrugar una bola de papel: la bola de papel arrugada es la variedad de los datos
de entrada con los que comienza el modelo. Cada movimiento operado por la
persona en la bola de papel es similar a una transformación geométrica simple
operada por una capa. La secuencia completa de gestos de desarrugamiento es la
transformación compleja de todo el modelo. Los modelos de aprendizaje profundo
son máquinas matemáticas para descomponer múltiples complejos de datos de alta
dimensión.

Con licencia para


1 Richard Feynman, entrevista, El mundo desde otro punto de vista, Yorkshire Television, 1972.

Con licencia para


Llaveconceptos en repaso 317

Esa es la magia del aprendizaje profundo: convertir el significado en vectores,


en espacios geométricos, y luego aprender gradualmente transformaciones
geométricas complejas que asignan un espacio a otro. Todo lo que necesita son
espacios de dimensionalidad suficientemente alta para capturar el alcance completo
de las relaciones que se encuentran en los datos originales.
Todo gira en torno a una sola idea central: que el significado se deriva de la relación de
pares entre cosas (entre palabras en un idioma, entre píxeles en una imagen, etc.) y que estas
relaciones pueden ser capturadas por una función de distancia. Pero tenga en cuenta que si el
cerebro implementa el significado a través de espacios geométricos es una cuestión
completamente diferente. Los espacios vectoriales son eficientes para trabajar desde un
punto de vista computacional, pero se pueden visualizar fácilmente diferentes estructuras de
datos para la inteligencia, en particular, gráficos. Las redes neuronales surgieron
inicialmente de la idea de usar gráficos como una forma de codificar el significado, por lo
que se denominan redes neuronales; el campo de investigación circundante solía llamarse
conexionismo. Hoy en día, el nombre de red neuronal existe puramente por razones
históricas: es un nombre extremadamente engañoso porque no son ni redes ni neuronales. En
particular, las redes neuronales apenas tienen nada que ver con el cerebro. Un nombre más
apropiado habría sido aprendizaje de representaciones en capas o aprendizaje de
representaciones jerárquicas, o tal vez incluso modelos diferenciables profundos o
transformaciones geométricas encadenadas, para enfatizar el hecho de que la manipulación
continua del espacio geométrico está en su núcleo.

9.1.4 Tecnologías facilitadoras clave


La revolución tecnológica que se está desarrollando actualmente no comenzó con un
solo invento revolucionario. Más bien, como cualquier otra revolución, es el
producto de una gran acumulación de factores habilitadores, lentamente al principio
y luego repentinamente. En el caso del aprendizaje profundo, podemos señalar los
siguientes factores clave:
◾ Innovaciones algorítmicas incrementales, primero repartidas durante dos
décadas (comenzando con la retropropagación) y luego ocurriendo cada vez
más rápido a medida que se invirtió más esfuerzo de investigación en
aprendizaje profundo después de 2012.
◾ La disponibilidad de grandes cantidades de datos perceptuales, que es un
requisito para darnos cuenta de que modelos suficientemente grandes
entrenados en datos suficientemente grandes son todo lo que necesitamos.
Esto, a su vez, es un subproducto del auge de Internet para consumidores y la
aplicación de la ley de Moore a los medios de almacenamiento.
◾ La disponibilidad de hardware de cómputo rápido y altamente paralelo a bajo
precio, especialmente elGPUes producido porNVIDIA—primer juegoGPUs y
luego chips diseñados desde cero para el aprendizaje profundo.
Temprano,CEO de NVIDIAJensen Huang tomó nota del auge del aprendizaje
profundo y decidió apostar el futuro de la empresa en él.
◾ Una pila compleja de capas de software que hace que este poder computacional
esté disponible para los humanos: el CUDAlenguaje, marcos como TensorFlow
que hacen la diferenciación automática y Keras, que hace que el aprendizaje
Con licencia para
profundo sea accesible para la mayoría de las personas.

Con licencia para


318 CPASADO9Conclusiones

En el futuro, el aprendizaje profundo no solo será utilizado por especialistas


(investigadores, estudiantes de posgrado e ingenieros con un perfil académico), sino que
también será una herramienta en la caja de herramientas de todo desarrollador, al igual
que la tecnología web en la actualidad. Todo el mundo necesita crear aplicaciones
inteligentes: así como todas las empresas hoy en día necesitan un sitio web, cada
producto deberá dar sentido de forma inteligente a los datos generados por los usuarios.
Lograr este futuro requerirá que construyamos herramientas que hagan que el
aprendizaje profundo sea radicalmente fácil de usar y accesible para cualquier persona
con habilidades básicas de codificación. Keras es el primer gran paso en esa dirección.

9.1.5 El flujo de trabajo universal de aprendizaje automático


Tener acceso a una herramienta extremadamente poderosa para crear modelos que
asignan cualquier espacio de entrada a cualquier espacio de destino es excelente,
pero la parte difícil del flujo de trabajo de aprendizaje automático es a menudo todo
lo que viene antes de diseñar y entrenar dichos modelos (y, para la producción).
modelos, lo que viene después, también). Comprender el dominio del problema para
poder determinar qué intentar predecir, según qué datos y cómo medir el éxito, es
un requisito previo para cualquier aplicación exitosa de aprendizaje automático, y
no es algo que herramientas avanzadas como Keras y TensorFlow puede ayudarte.
Como recordatorio, aquí hay un resumen rápido del flujo de trabajo típico de
aprendizaje automático como se describe en el capítulo 4:
1Defina el problema: ¿Qué datos están disponibles y qué está tratando de
predecir? ¿Necesitará recopilar más datos o contratar personas para etiquetar
manualmente un conjunto de datos?
2Identifique una forma de medir de forma fiable el éxito de su objetivo. Para tareas
simples, esto puede ser precisión de predicción, pero en muchos casos requerirá
métricas específicas de dominio sofisticadas.
3Prepare el proceso de validación que utilizará para evaluar sus modelos. En
particular, debe definir un conjunto de entrenamiento, un conjunto de
validación y un conjunto de prueba. Las etiquetas del conjunto de validación
y prueba no deben filtrarse en los datos de entrenamiento: por ejemplo, con la
predicción temporal, los datos de validación y prueba deben ser posteriores a
los datos de entrenamiento.
4Vectorice los datos convirtiéndolos en vectores y preprocesándolos de una
manera que los haga más accesibles para una red neuronal (normalización,
etc.).
5Desarrolle un primer modelo que supere una línea de base trivial de sentido común,
demostrando así que el aprendizaje automático puede funcionar en su problema.
¡Este puede no ser siempre el caso!
6Refina gradualmente la arquitectura de tu modelo ajustando los
hiperparámetros y agregando regularización. Realice cambios basados en el
rendimiento solo en los datos de validación, no en los datos de prueba ni en
los datos de entrenamiento. Recuerde que debe hacer que su modelo se
sobreajuste (identificando así un nivel de capacidad de modelo que sea mayor
de lo que necesita) y solo entonces comience a agregar regularización o
Con licencia para
reducir el tamaño de su modelo.

Con licencia para


Llaveconceptos en repaso 319

7Tenga en cuenta el sobreajuste del conjunto de validación al convertir los


hiperparámetros: el hecho de que sus hiperparámetros pueden terminar
sobreespecializados en el conjunto de validación. ¡Evitar esto es el propósito
de tener un equipo de prueba separado!

9.1.6 Arquitecturas de red clave


Las tres familias de arquitecturas de red con las que debería estar familiarizadoson
densamenteredes conectadas, redes convolucionales y redes recurrentes. Cada tipo de red
está destinado a una modalidad de entrada específica: una arquitectura de red (densa,
convolucional, recurrente) codifica suposiciones sobre la estructura de los datos: un espacio
de hipótesis dentro del cual procederá la búsqueda de un buen modelo. El que una
arquitectura dada funcione en un problema dado depende completamente de la coincidencia
entre la estructura de los datos y las suposiciones de la arquitectura de la red.
Estos diferentes tipos de redes se pueden combinar fácilmente para lograr redes
multimodales más grandes, de la misma manera que se combinan piezas de LEGO.
En cierto modo, las capas de aprendizaje profundo son ladrillos LEGO para el
procesamiento de información. Aquí hay una descripción general rápida de la
asignación entre las modalidades de entrada y las arquitecturas de red apropiadas:
◾ Datos vectoriales—Red densamente conectada (Densocapas).
◾ Datos de imagen—2Dconvenciones
◾ Datos de sonido (por ejemplo, forma de onda)-O1Dconvnets (preferido) oRNNs.
◾ datos de texto-O1Dconvnets (preferido) o RNNs.
◾ Datos de series de tiempo-O RNNs (preferido) o1Dconvenciones
◾ Otros tipos de datos de secuencia-ORNNs o1Dconvenciones PreferirRNNs si el orden
de los datos es muy significativo (por ejemplo, para series de tiempo, pero no para
texto).
◾ datos de vídeo-O3Dconvnets (si necesita capturar efectos de movimiento) o una
combinación de un nivel de cuadro 2Dconvnet para la extracción de
características seguido de unRNNo un1Dconvnet para procesar las secuencias
resultantes.
◾ Datos volumétricos—3Dconvenciones

Ahora, repasemos rápidamente las especificidades de cada arquitectura de red.


DREDES CONECTADAS ENSELY
Una red densamente conectada es una pila de capas densas, destinadas a procesar datos
vectoriales (lotes de vectores). Tales redes no asumen una estructura específica en las
características de entrada:se llaman densamente conectados porque las unidades de una
capa Densa están conectadas con todas las demás unidades. La capa intenta mapear las
relaciones entre dos entidades de entrada cualesquiera; esto es diferente a una capa de
convolución 2D, por ejemplo, que solo analiza las relaciones locales.
Las redes densamente conectadas se usan más comúnmente para datos categóricos
(por ejemplo, donde las características de entrada son listas de atributos), como el
conjunto de datos de precios de la vivienda de Boston que se usó en el capítulo 3.
También se usan como etapa final de clasificación o regresión. de la mayoría de las
redes. Por ejemplo, las redes convencionales cubiertas en el capítulo 5 generalmente
Con licencia para
terminan con una o dos capas densas, al igual que las redes recurrentes en el capítulo 6.

Con licencia para


320 CPASADO9Conclusiones

Recuerde: para realizar una clasificación binaria, termine su pila de capas con
unDensocapacon una sola unidad y unsigmoideoactivación y
usoentropía_cruzada_binariacomo la pérdida. Sus objetivos deben ser 0 o 1:
desde keras importar
modelos desde keras
importar capas
modelo = modelos. Secuencial()
modelo.add(capas.Dense(32, activación='relu',
input_shape=(num_input_features,)))modelo.add(capas.Dense(32,
activación='relu'))
modelo.add(capas.Densa(1,

activación='sigmoide'))modelo.compile(optimizador='rmsprop',

pérdida='binary_crossentropy')

Para realizar una clasificación categórica de una sola etiqueta (donde cada muestra tiene
exactamente una clase, no más), termine su pila de capas con una Densocapa con un
número de unidades igual al número de clases, y un softmaxactivación. Si sus
objetivos están codificados en caliente, utilice categorical_crossentropycomo la
pérdida; si son números enteros, utiliceescasa_categórica_entropía cruzada:
modelo = modelos. Secuencial()
modelo.add(capas.Dense(32, activación='relu',
input_shape=(num_input_features,)))modelo.add(capas.Dense(32,
activación='relu')) modelo.add(capas.Denso(núm_clases, activación='softmax'))

modelo.compile(optimizador='rmsprop', pérdida='categorical_crossentropy')

Para realizar una clasificación categórica multietiqueta (donde cada muestra puede tener
varias clases), termine su pila de capas con una Densocapa con un número de unidades
igual alnúmero declases y unsigmoideoactivación y
usoentropía_cruzada_binariacomo la pérdida. Sus objetivos deben estar codificados
en k-hot:
modelo = modelos. Secuencial()
modelo.add(capas.Dense(32, activación='relu',
input_shape=(num_input_features,)))modelo.add(capas.Dense(32,
activación='relu')) modelo.add(capas.Denso(núm_clases,
activación='sigmoide'))

modelo.compile(optimizador='rmsprop', pérdida='binary_crossentropy')

Para realizar una regresión hacia un vector de valores continuos, termine su pila de
capas con una capa Densa con una cantidad de unidades igual a la cantidad de valores
que está tratando de predecir (a menudo uno solo, como el precio de una casa) y sin
activación. Varioslas pérdidas se pueden usar para la regresión, más comúnmente
mean_squared_error (MSE) y mean_absolute_error (MAE):
modelo = modelos. Secuencial()
modelo.add(capas.Dense(32, activación='relu',
input_shape=(num_input_features,)))modelo.add(capas.Dense(32,
activación='relu')) modelo.add(capas.Dense(núm_valores))

Con licencia para


modelo.compilar(optimizador='rmsprop', pérdida='mse')

Con licencia para


Llaveconceptos en repaso 321

CONVNETS
Las capas de convolución observan patrones espacialmente locales aplicando la
misma transformación geométrica a diferentes ubicaciones espaciales (parches) en
un tensor de entrada. Esto da como resultado representaciones que son invariantes a
la traducción, lo que hace que las capas de convolución sean altamente eficientes y
modulares. Esta idea es aplicable a espacios de cualquier dimensionalidad: 1D
(secuencias), 2D (imágenes), 3D (volúmenes), etc. Puede usar la capa Conv1D para
procesar secuencias (especialmente texto; no funciona tan bien en series de tiempo,
que a menudo no siguen la suposición de invariancia de traducción), la capa
Conv2D para procesarimágenes y las capas Conv3D para procesar volúmenes.
convenciones, o redes convolucionales, consisten en pilas de capas de convolución y
max-pooling. Las capas de agrupación le permiten reducir la muestra espacial de los datos,
lo cual es necesario para mantener los mapas de características en un tamaño razonable a
medida que crece la cantidad de características, y para permitir que las capas de convolución
posteriores "vean" una mayor extensión espacial de las entradas. Convnets a menudo
terminan con una operación Flatten o una capa de agrupación global, convirtiendo los mapas
de características espaciales en vectores, seguidos de capas densas para lograr la
clasificación o la regresión.
Tenga en cuenta que es muy probable que las circunvoluciones regulares pronto
sean reemplazadas en su mayoría (o completamente) por una alternativa equivalente
pero más rápida y eficiente desde el punto de vista de la representación: la convolución
separable en profundidad (capa SeparableConv2D). Esto es verdadero por Entradas 3D, 2D
y 1D. Cuando está construyendo una nueva red desde cero, usando profundidad-las circunvoluciones
separables sabias son definitivamente el camino a seguir. La capa SeparableConv2D se
puede usar como reemplazo directo de Conv2D, lo que da como resultado una red más
pequeña y más rápida que también se desempeña mejor en su tarea.
Aquí hay una red típica de clasificación de imágenes (clasificación categórica, en
este caso):
modelo = modelos.Sequential()
modelo.add(capas.SeparableConv2D(32, 3, activación='relu',
input_shape=(alto, ancho, canales)))
modelo.add(capas.SeparableConv2D(64, 3, activación='relu'))
modelo.add(capas.MaxPooling2D(2))

modelo.add(capas.SeparableConv2D(64, 3, activación='relu'))
modelo.añadir(capas.SeparableConv2D(128, 3,
activación='relu')) modelo.añadir(capas.MaxPooling2D(2))

modelo.add(capas.SeparableConv2D(64, 3, activación='relu'))
modelo.add(capas.SeparableConv2D(128, 3, activación='relu'))
modelo.add(capas.GlobalAveragePooling2D())

modelo.add(capas.Dense(32, activación='relu'))
modelo.add(capas.Denso(núm_clases, activación='softmax'))

modelo.compile(optimizador='rmsprop', pérdida='categorical_crossentropy')

RNNS
Redes neuronales recurrentes(RNN) funcionan procesando secuencias de entradas un paso
de tiempo a la vez y manteniendo un estado en todo momento (un estado suele ser un vector

Con licencia para


o conjunto de vectores:

Con licencia para


322 CPASADO9Conclusiones

un punto en un espacio geométrico de estados). Deben usarse preferentemente sobre


conv-nets 1D en el caso de secuencias donde los patrones de interés no son invariantes
por traducción temporal (por ejemplo, datos de series temporales donde el pasado
reciente es más importante que el pasado lejano).
Hay tres capas RNN disponibles en Keras: SimpleRNN, GRU y LSTM. Para la mayoría
de los propósitos prácticos, debe usar GRU o LSTM. LSTM es el más potente de los dos
pero también es más caro; puede pensar en GRU como una alternativa más simple y
económica.
Para apilar varias capas RNN una encima de la otra, cada capa anterior a la
última capa de la pila debe devolver la secuencia completa de sus salidas (cada paso
de tiempo de entrada corresponderá a un paso de tiempo de salida); si no está
apilando más capas de RNN, entonces es común devolver solo la última salida, que
contiene información sobre la secuencia completa.
A continuación se muestra una sola capa RNN para la clasificación binaria de secuencias
vectoriales:
modelo = modelos. Secuencial()
model.add(layers.LSTM(32, input_shape=(num_timesteps, num_features)))
model.add(layers.Dense(num_classes, activate='sigmoid'))

50model.compile(optimizador='rmsprop', pérdida='binary_crossentropy')

Y esta es una capa RNN apilada para la clasificación binaria de secuencias vectoriales:
modelo = modelos.Sequential()
modelo.add(capas.LSTM(32, return_sequences=True,
input_shape=(num_timesteps, num_features)))
modelo.add(capas.LSTM(32, return_sequences=True))
modelo.add(capas.LSTM(32))
modelo.add(capas.Dense(num_clases, activación='sigmoide'
))

modelo.compile(optimizador='rmsprop', pérdida='binary_crossentropy')

9.1.7 El espacio de las posibilidades


con que vas a construir¿aprendizaje profundo? Recuerde, construir modelos de
aprendizaje profundo es como jugar con ladrillos LEGO: las capas se pueden unir
para mapear esencialmente cualquier cosa con cualquier cosa, siempre que tenga los
datos de entrenamiento apropiados disponibles y que el mapeo se pueda lograr a
través de una transformación geométrica continua de com razonable. - complejidad.
El espacio de posibilidades es infinito. Esta sección ofrece algunos ejemplos para
inspirarlo a pensar más allá de las tareas básicas de clasificación y regresión que
tradicionalmente han sido el pan y la mantequilla del aprendizaje automático.
He ordenado mis aplicaciones sugeridas por modalidades de entrada y salida.
Tenga en cuenta que bastantes de ellos amplían los límites de lo que es posible;
aunque un modelo podría entrenarse en todas estas tareas, en algunos casos dicho
modelo probablemente no generalizaría más allá de sus datos de entrenamiento. Las
secciones 9.2 y 9.3 abordarán cómo se podrían eliminar estas limitaciones en el
futuro.

Con licencia para


Llaveconceptos en repaso 323

◾ Asignación de datos vectoriales a datos vectoriales


– Atención médica predictiva—Asignación de registros médicos de pacientes a
predicciones de resultados de pacientes
– Segmentación por comportamiento—Mapeo de un conjunto de atributos del sitio
web con datos sobre cuánto tiempo pasará un usuario en el sitio web
– control de calidad del producto—Mapeo de un conjunto de atributos relativos a
una instancia de un producto fabricado con la probabilidad de que el producto falle
el próximo año
◾ Asignación de datos de imagen a datos vectoriales
– asistente medico—Mapeo de diapositivas de imágenes médicas con una
predicción sobre la presencia de un tumor
– vehículo autónomo—Asignación de cuadros de video de la cámara del tablero del
automóvil a los comandos de ángulo del volante
– Juego de mesaAI—Asignación de Go y tableros de ajedrez al siguiente movimiento del
jugador
– ayudante de dieta—Asignación de imágenes de un plato a su conteo de calorías
– Predicción de edad—Asignación de selfies a la edad de la persona
◾ Asignación de datos de series temporales a datos vectoriales
– Predicción del tiempo—Mapeo de series temporales de datos meteorológicos
en una cuadrícula de ubicaciones de datos meteorológicos la semana siguiente
en una ubicación específica
– Interfaces cerebro-computadora—Mapeo de series temporales de
magnetoencefalograma (MEG) datos a comandos de computadora
– Segmentación por comportamiento—Mapeo de series temporales de interacciones
de usuarios en un sitio web con la probabilidad de que un usuario compre algo
◾ Asignación de texto a texto
– Respuesta inteligente—Asignación de correos electrónicos a posibles respuestas de una
línea
– Respondiendo preguntas—Asignación de preguntas de conocimiento general a respuestas
– resumen—Asignación de un artículo largo a un breve resumen del artículo
◾ Asignación de imágenes a texto
– subtítulos—Asignación de imágenes a subtítulos breves que describen el
contenido de las imágenes
◾ Asignación de texto a imágenes
– Generación de imagen condicionada—Asignación de una breve descripción de
texto a imágenes que coincidan con la descripción
– Generación/selección de logotipo—Asignación del nombre y la descripción de
una empresa al logotipo de la empresa
◾ Asignación de imágenes a imágenes
– Súper resolución—Asignación de imágenes reducidas a versiones de mayor
resolución de las mismas imágenes
– Detección de profundidad visual—Mapeo de imágenes de ambientes interiores
a mapas de predicciones de profundidad

Con licencia para


324 CPASADO9Conclusiones

◾ Mapeo de imágenes y texto a texto


– Visualcontrol de calidad—Asignación de imágenes y preguntas en lenguaje
natural sobre el contenido de las imágenes a respuestas en lenguaje natural
◾ Mapeo de video y texto a texto
– Videocontrol de calidad —Asignación de videos cortos y preguntas en lenguaje
natural sobre el contenido de los videos a respuestas en lenguaje natural
Casitodo es posible, pero no absolutamente nada. Veamos en la siguiente sección lo que
no podemos hacer con el aprendizaje profundo.

Con licencia para


Las limitaciones deaprendizaje profundo 325

9.2 Las limitaciones del aprendizaje profundo


El espacio de aplicaciones que se pueden implementar con el aprendizaje profundo
es casi infinito. Y, sin embargo, muchas aplicaciones están completamente fuera del
alcance de las técnicas actuales de aprendizaje profundo, incluso con grandes
cantidades de datos anotados por humanos. Digamos, por ejemplo, que podría
ensamblar un conjunto de datos de cientos de miles, incluso millones, de
descripciones en inglés de las características de un producto de software, escrito por
un gerente de producto, así como el código fuente correspondiente desarrollado por
un equipo de ingenieros para cumplir con estos requisitos. Incluso con estos datos,
no podría entrenar un modelo de aprendizaje profundo para leer la descripción de un
producto y generar la base de código adecuada. Ese es solo un ejemplo entre
muchos. En general, cualquier cosa que requiera razonamiento, como programar o
aplicar el método científico, planificación a largo plazo, y la manipulación
algorítmica de datos está fuera del alcance de los modelos de aprendizaje profundo,
sin importar la cantidad de datos que les proporcione. Incluso aprender un algoritmo
de clasificación con una red neuronal profunda es tremendamente difícil.
Esto se debe a que un modelo de aprendizaje profundo es solo una cadena de
transformaciones geométricas simples y continuas que asignan un espacio vectorial a
otro. Todo lo que puede hacer es mapear una variedad de datos X en otra variedad Y,
asumiendo la existencia de una transformación continua aprendible de X a Y. Un
modelo de aprendizaje profundo puede interpretarse como una especie de
programa.gramo; pero, a la inversa, la mayoría de los programas no se pueden expresar
como modelos de aprendizaje profundo: para la mayoría de las tareas, no existe una red
neuronal profunda correspondiente que resuelva la tarea o, incluso si existe, es posible que
no se pueda aprender: la correspondiente geométrica transform puede ser demasiado
complejo, o puede que no haya datos apropiados disponibles para aprenderlo.
Ampliar las técnicas actuales de aprendizaje profundo apilando más capas y
utilizando más datos de entrenamiento solo puede paliar superficialmente algunos
de estos problemas. No resolverá los problemas más fundamentales de que los
modelos de aprendizaje profundo están limitados en lo que pueden representar y que
la mayoría de los programas que desee aprender no se pueden expresar como una
transformación geométrica continua de una variedad de datos.

9.2.1 El riesgo de antropomorfizar los modelos de aprendizaje automático


Un riesgo real de la IA contemporánea es malinterpretar lo que hacen los modelos
de aprendizaje profundo y sobreestimar sus capacidades. Una característica
fundamental de los humanos es nuestra teoría de la mente: nuestra tendencia a
proyectar intenciones, creencias y conocimientos sobre las cosas que nos rodean.
Dibujar una carita sonriente en una roca de repente la hace "feliz" en nuestras
mentes. Aplicado al aprendizaje profundo, esto significa que, por ejemplo, cuando
somos capaces de entrenar con cierto éxito a un modelo para que genere subtítulos
para describir imágenes, se nos hace creer que el modelo "entiende" el contenido de
las imágenes y los subtítulos que genera. Entonces nos sorprendemos cuando
cualquier ligera desviación del tipo de imágenes presentes en los datos de
entrenamiento hace que el modelo genere subtítulos completamente absurdos (ver
Con licencia para
figura 9.1).

Con licencia para


326 CPASADO9Conclusiones

Figura 9.1 Fallo de un pie de fotosistema


basado en aprendizaje profundo
El niño sostiene un bate de béisbol.

En particular, esto se destaca mediante ejemplos contradictorios, que son muestras


alimentadas a una red de aprendizaje profundo que están diseñadas para engañar al
modelo para que las clasifique erróneamente. Ya sabe que, por ejemplo, es posible hacer
un ascenso de gradiente en el espacio de entrada para generar entradas que maximicen
la activación de algún filtro de convnet; esta es la base de la técnica de visualización de
filtro presentada en el capítulo 5, así como la Algoritmo DeepDream en el capítulo 8.
De manera similar, a través del ascenso de gradiente, puede modificar ligeramente una
imagen para maximizar la predicción de clase para una clase determinada. Al tomar una
fotografía de un panda y agregarle un gradiente de gibón, podemos obtener una red
neuronal para clasificar al panda como un gibón (ver figura 9.2).

f(x) f(x)

Panda ¡Gibón!
Gradiente
de clase

Panda Ejemplo adversarial

Gibbon
Figura 9.2 Un ejemplo contradictorio: los cambios imperceptibles en una imagen pueden
cambiar la clasificación de la imagen de un modelo.

Con licencia para


Las limitaciones deaprendizaje profundo 327

En resumen, los modelos de aprendizaje profundo no tienen ninguna comprensión


de su entrada, al menos, no en un sentido humano. Nuestra propia comprensión de
las imágenes, los sonidos y el lenguaje se basa en nuestra experiencia
sensoriomotora como humanos. Los modelos de aprendizaje automático no tienen
acceso a tales experiencias y, por lo tanto, no pueden comprender sus entradas de
una manera identificable por los humanos. Al anotar una gran cantidad de ejemplos
de entrenamiento para alimentar nuestros modelos, logramos que aprendan una
transformación geométrica que asigna datos a conceptos humanos en un conjunto
específico de ejemplos, pero este mapeo es un bosquejo simplista del modelo
original en nuestras mentes. —la desarrollada a partir de nuestra experiencia como
agentes encarnados. Es como una imagen tenue en un espejo (ver figura 9.3).

Datos
Experiencia Resumenconcept etiquetados Modelo de
Mundo real humana os en la mente que aprendizaje
encarnada humana ejemplifican automático
estos
conceptos
f(x)

Puede que no No coincide con el Coincide


siempre se modelo mental con los
transfiera bien humano del que datos de
al mundo real. proviene. entrenamien
to

Figura 9.3 Modelos actuales de aprendizaje automático: como una imagen tenue en un espejo

Como profesional del aprendizaje automático, siempre tenga esto en cuenta y nunca
caiga en la trampa de creer que las redes neuronales entienden la tarea que realizan;
no lo hacen, al menos no de una manera que tenga sentido para nosotros. Fueron
entrenados en una tarea diferente y mucho más limitada que la que queríamos
enseñarles: la de mapear las entradas de entrenamiento a los objetivos de
entrenamiento, punto por punto. Muéstreles cualquier cosa que se desvíe de sus
datos de entrenamiento, y se romperán de manera absurda.

9.2.2 Generalización local versus generalización extrema


Existen diferencias fundamentales entre la transformación geométrica directa de
entrada a salida que hacen los modelos de aprendizaje profundo y la forma en que
los humanos piensan y aprenden. No es solo el hecho de que los humanos aprendan
por sí mismos a partir de la experiencia encarnada en lugar de que se les presenten
ejemplos de entrenamiento explícitos. Además de los diferentes procesos de
aprendizaje, existe una diferencia básica en la naturaleza de las representaciones
subyacentes.
Los humanos son capaces de mucho más que mapear estímulos inmediatos en

Con licencia para


respuestas inmediatas, como lo haría una red profunda, o tal vez un insecto.
Mantenemos modelos complejos y abstractos de nuestra situación actual, de
nosotros mismos y de otras personas, y podemos utilizar estos modelos para
anticipar diferentes futuros posibles y realizar una planificación a largo plazo.
Podemos fusionar conceptos conocidos para representar algo que nunca hemos
experimentado.

Con licencia para


328 CPASADO9Conclusiones

antes, como imaginar a un caballo con jeans, por ejemplo, o imaginar lo que
haríamos si ganáramos la lotería. Esta capacidad para manejar hipótesis, para
expandir el espacio de nuestro modelo mental mucho más allá de lo que podemos
experimentar directamente (para realizar abstracciones y razonamientos) es
posiblemente la característica que define la cognición humana. Yo lo llamo
generalización extrema: la capacidad de adaptarse a situaciones nuevas, nunca antes
experimentadas, utilizando pocos datos o incluso ninguno en absoluto.
Esto contrasta fuertemente con lo que hacen las redes profundas, lo que yo llamo
generalización local (ver figura 9.4). El mapeo de entradas a salidas realizado por una
red profunda rápidamente deja de tener sentido si las nuevas entradas difieren aunque
sea ligeramente de lo que vio la red en el momento del entrenamiento. Considere, por
ejemplo, el problema de aprender los parámetros de lanzamiento apropiados para que un
cohete aterrice en la luna. Si usó una red profunda para esta tarea y la entrenó con
aprendizaje supervisado o aprendizaje por refuerzo, tendría que alimentarla con miles o
incluso millones de pruebas de lanzamiento: tendría que exponerla a una muestra densa
del espacio de entrada, para que aprenda un mapeo confiable del espacio de entrada al
espacio de salida. A diferencia de, como seres humanos, podemos usar nuestro poder de
abstracción para generar modelos físicos (ciencia de cohetes) y derivar una solución
exacta que hará que el cohete aterrice en la luna en una o varias pruebas. De manera
similar, si desarrollara una red profunda que controla un cuerpo humano y quisiera que
aprendiera a navegar con seguridad por una ciudad sin ser atropellado por automóviles,
la red tendría que morir miles de veces en diversas situaciones hasta que pudiera inferir
que los automóviles son peligrosos, y desarrollar comportamientos de evitación
apropiados. Abandonada en una nueva ciudad, la red tendría que volver a aprender la
mayor parte de lo que sabe. Por otro lado, los humanos pueden aprender
comportamientos seguros sin tener que morir ni una sola vez, nuevamente, gracias a
nuestro poder de modelado abstracto de situaciones hipotéticas. y querías que
aprendiera a navegar con seguridad por una ciudad sin ser atropellado por autos, la red
tendría que morir miles de veces en varias situaciones hasta que pudiera inferir que los
autos son peligrosos y desarrollar comportamientos de evasión apropiados. Abandonada
en una nueva ciudad, la red tendría que volver a aprender la mayor parte de lo que sabe.
Por otro lado, los humanos pueden aprender comportamientos seguros sin tener que
morir ni una sola vez, nuevamente, gracias a nuestro poder de modelado abstracto de
situaciones hipotéticas. y querías que aprendiera a navegar con seguridad por una ciudad
sin ser atropellado por autos, la red tendría que morir miles de veces en varias
situaciones hasta que pudiera inferir que los autos son peligrosos y desarrollar
comportamientos de evasión apropiados. Abandonada en una nueva ciudad, la red
tendría que volver a aprender la mayor parte de lo que sabe. Por otro lado, los humanos
pueden aprender comportamientos seguros sin tener que morir ni una sola vez,
nuevamente, gracias a nuestro poder de modelado abstracto de situaciones hipotéticas.

Con licencia para


puntos de
datos
o experiencia

Generalización local: Generalización


poder de extrema: poder de
Figura 9.4 Generalización
generalización del generalización logrado
reconocimiento de a través de la localvs. generalización
patrones abstracción y el extrema
razonamiento.

En resumen, a pesar de nuestro progreso en la percepción de las máquinas, todavía


estamos lejos de la IA a nivel humano. Nuestros modelos solo pueden realizar
generalizaciones locales, adaptándose a nuevas situaciones que deben ser similares
a datos pasados, mientras que la cognición humana es capaz de

Con licencia para


Las limitaciones deaprendizaje profundo 329

generalización extrema, adaptación rápida a situaciones radicalmente nuevas y


planificación para situaciones futuras a largo plazo.

9.2.3 Terminando
Esto es lo que debe recordar: el único éxito real del aprendizaje profundo hasta ahora ha sido
la capacidad de mapear el espacio X al espacio Y usando una transformación geométrica
continua, dada una gran cantidad de datos anotados por humanos. Hacer esto bien es un
cambio de juego para prácticamente todas las industrias, pero todavía está muy lejos de la IA
a nivel humano.
Para eliminar algunas de las limitaciones que hemos discutido y crear IA que
pueda competir con los cerebros humanos, debemos alejarnos de los mapeos
directos de entrada a salida y pasar al razonamiento y la abstracción. Un sustrato
probablemente apropiado para el modelado abstracto de varias situaciones y
conceptos es el de los programas de computadora. Dijimos anteriormente que los
modelos de aprendizaje automático se pueden definir como programas que se
pueden aprender; actualmente sólo podemos aprender programas que pertenecen a
un subconjunto estrecho y específico de todos los programas posibles. Pero, ¿y si
pudiéramos aprender cualquier programa, de forma modular y reutilizable? Veamos
en la siguiente sección cómo puede ser el camino a seguir.

Con licencia para


330 CPASADO9Conclusiones

9.3 El futuro del aprendizaje profundo


Esta es una sección más especulativa destinada a abrir horizontes para las personas
que quieran unirse a un programa de investigación o comenzar a hacer una
investigación independiente. Dado lo que sabemos sobre el funcionamiento de las
redes profundas, sus limitaciones y el estado actual del panorama de la
investigación, ¿podemos predecir hacia dónde se dirigen las cosas a mediano plazo?
Los siguientes son algunos pensamientos puramente personales. Tenga en cuenta
que no tengo una bola de cristal, por lo que mucho de lo que anticipo puede no
convertirse en realidad. Comparto estas predicciones no porque espero que se
demuestre que son completamente correctas en el futuro, sino porque son
interesantes y procesables en el presente.
A un alto nivel, estas son las direcciones principales en las que veo promesa:
◾ Modelos más cercanos a los programas informáticos de propósito general,
construido sobre primitivos mucho más ricos que las capas diferenciables actuales.
Así llegaremos al razonamiento ya la abstracción, cuya carencia es la debilidad
fundamental de los modelos actuales.
◾ Nuevas formas de aprendizaje que hacen posible el punto anterior, lo que permite
que los modelos se alejen de las transformaciones diferenciables.
◾ Modelos que requieren menos participación de ingenieros humanos. No debería ser
tu trabajo afinar las perillas sin parar.
◾ Mayor reutilización sistemática de características y arquitecturas aprendidas
previamente, como meta-sistemas de aprendizaje utilizando subrutinas de programa
modulares y reutilizables.
Además, tenga en cuenta que estas consideraciones no son específicas del tipo de
aprendizaje supervisado que ha sido el pan y la mantequilla del aprendizaje
profundo hasta ahora; más bien, son aplicables a cualquier forma de aprendizaje
automático, incluido el aprendizaje no supervisado, autosupervisado y aprendizaje
reforzado. No es fundamentalmente importante de dónde provienen sus etiquetas o
cómo se ve su ciclo de entrenamiento; estas diferentes ramas del aprendizaje
automático son diferentes facetas de la misma construcción. Sumerjámonos.

9.3.1 Modelos como programas


Como se señaló en la sección anterior, un desarrollo transformador necesario que
podemos esperar en el campo del aprendizaje automático es alejarse de los modelos
que realizanpuramente reconocimiento de patrones y solo puede lograr una generalización
local, hacia modelos capaces de abstracción y razonamiento que pueden lograr una
generalización extrema. Los programas actuales de IA que son capaces de formas básicas de
razonamiento están todos codificados por programadores humanos: por ejemplo, software
que se basa en algoritmos de búsqueda, manipulación de gráficos y lógica formal. En
AlphaGo de DeepMind, por ejemplo, la mayor parte de la inteligencia que se muestra está
diseñada y codificada por programadores expertos (como Monte Carlo Tree Search); el
aprendizaje de los datos ocurre solo en submódulos especializados (redes de valor y redes de
políticas). Pero en el futuro, tales sistemas de IA pueden aprenderse por completo, sin
participación humana.

Con licencia para


¿Qué camino podría hacer que esto suceda? Considere un tipo de red bien conocido:
RNN. Es importante tener en cuenta que las RNN tienen un poco menos de limitaciones
que las redes feedforward. Eso es porque los RNN son un poco más que meras
transformaciones geométricas:

Con licencia para


El futuro de lo profundoaprendizaje 331

son transformaciones geométricas aplicadas repetidamente dentro de un bucle for. El bucle


for temporal está en sí mismo codificado por desarrolladores humanos: es una suposición
integrada de la red. Naturalmente, los RNN todavía están extremadamente limitados en lo
que pueden representar, principalmente porque cada paso que realizan es una transformación
geométrica diferenciable y transportan información de un paso a otro a través de puntos en
un espacio geométrico continuo (vectores de estado). Ahora imagine una red neuronal que se
aumenta de manera similar con primitivas de programación, pero en lugar de un solo bucle
for codificado con memoria geométrica codificada, la red incluye un gran conjunto de
primitivas de programación que el modelo puede manipular libremente para expandir su
procesamiento. función, como ramas if, declaraciones while, creación de variables,
almacenamiento en disco para memoria a largo plazo, operadores de clasificación,
estructuras de datos avanzadas (como listas, gráficos y tablas hash) y muchas más. El
espacio de programas que podría representar dicha red sería mucho más amplio de lo que se
puede representar con los modelos actuales de aprendizaje profundo, y algunos de estos
programas podrían lograr un poder de generalización superior.
Dejaremos de tener, por un lado, inteligencia algorítmica codificada (software
artesanal) y, por otro lado, inteligencia geométrica aprendida (aprendizaje
profundo). En su lugar, tendremos una combinación de módulos algorítmicos
formales que brindan capacidades de razonamiento y abstracción, y módulos
geométricos que brindan intuición informal y capacidades de reconocimiento de
patrones. Todo el sistema se aprenderá con poca o ninguna participación humana.
Un subcampo relacionado de la IA que creo que puede estar a punto de despegar a lo
grande es la síntesis de programas, en particular la síntesis de programas neuronales. La
síntesis de programas consiste en generar automáticamente programas simples mediante
el uso de un algoritmo de búsqueda (posiblemente búsqueda genética, como en la
programación genética) para explorar un gran espacio de posibles programas. La
búsqueda se detiene cuando se encuentra un programa que cumple con las
especificaciones requeridas, a menudo proporcionado como un conjunto de pares de
entrada y salida. Esto recuerda mucho al aprendizaje automático: dados los datos de
entrenamiento proporcionados como pares de entrada y salida, encontramos un
programa que hace coincidir las entradas con las salidas y puede generalizarse a nuevas
entradas. La diferencia es que en lugar de aprender los valores de los parámetros en un
programa codificado (una red neuronal), generamos el código fuente a través de un
proceso de búsqueda discreto.
Definitivamente espero que este subcampo vea una ola de interés renovado en
los próximos años. En particular, espero el surgimiento de un subcampo cruzado
entre el aprendizaje profundo y la síntesis de programas, donde en lugar de generar
programas en un lenguaje de propósito general, generaremos redes neuronales
(flujos de procesamiento de datos geométricos) aumentados con un rico conjunto de
algoritmos. primitivos, como bucles for y muchos otros (ver figura 9.5). Esto
debería ser mucho más manejable y útil que la generación directa de código fuente,
y ampliará drásticamente el alcance de los problemas que se pueden resolver con el
aprendizaje automático: el espacio de programas que podemos generar
automáticamente, dados los datos de entrenamiento apropiados. Los RNN
contemporáneos pueden verse como un ancestro prehistórico de tales modelos
híbridos algorítmico-geométricos.
Con licencia para
332 CPASADO9Conclusiones

Programa modular a nivel


de tarea aprendido sobre
la marcha para resolver Datos
una tarea específica yretroali
Subrutina Subrutina mentació
Tarea #002456
geométric algorítmica n Figura 9.5 Un programa aprendido
a que se basa tanto en primitivas
Subrutina Subrutina geométricas (reconocimiento de
Compor
geométric algorítmica
tamient
patrones, intuición) como
a algorítmicasprimitivas
o
(razonamiento, búsqueda,
memoria)

9.3.2 Más allá de la retropropagación y las capas diferenciables


Si los modelos de aprendizaje automático se vuelven más como programas, en su
mayoría ya no serán diferenciables: estos programas seguirán usando capas geométricas
continuas como subrutinas, que serán diferenciables, pero el modelo en su conjunto no
lo será. Como resultado, el uso de la retropropagación para ajustar los valores de
ponderación en una red fija codificada no puede ser el método elegido para entrenar
modelos en el futuro; al menos, no puede ser la historia completa. Necesitamos
descubrir cómo entrenar sistemas no diferenciables de manera eficiente. Los enfoques
actuales incluyen algoritmos genéticos, estrategias de evolución, ciertos métodos de
aprendizaje por refuerzo y el método de multiplicadores de dirección alterna (ADMM).
Naturalmente, el descenso de gradiente no va a ninguna parte; la información de
gradiente siempre será útil para optimizar funciones paramétricas diferenciables.
Además, la retropropagación es de un extremo a otro, lo cual es excelente para
aprender buenas transformaciones encadenadas, pero es computacionalmente
ineficiente porque no aprovecha completamente la modularidad de las redes
profundas. Para hacer algo más eficiente, existe una receta universal: introducir
modularidad y jerarquía. Entonces podemos hacer que la retropropagación sea más
eficiente introduciendo módulos de entrenamiento desacoplados con un mecanismo
de sincronización entre ellos, organizados de forma jerárquica. Esta estrategia se
refleja de alguna manera en el trabajo reciente de DeepMind sobre gradientes
sintéticos. Espero más en este sentido en un futuro próximo. Puedo imaginar un
futuro en el que los modelos que son globalmente no diferenciables (pero que
presentan partes diferenciables) se entrenan —crecen— usando un proceso de
búsqueda eficiente que no usa gradientes,

9.3.3 Aprendizaje automático automatizado


En el futuro, las arquitecturas modelo se aprenderán en lugar de ser hechas a mano
por ingenieros-artesanos. Las arquitecturas de aprendizaje van de la mano con el
uso de conjuntos más ricos de primitivas y modelos de aprendizaje automático
similares a programas.

Con licencia para


El futuro de lo profundoaprendizaje 333

Actualmente, la mayor parte del trabajo de un ingeniero de aprendizaje profundo


consiste en recopilar datos con secuencias de comandos de Python y luego ajustar la
arquitectura y los hiperparámetros de una red profunda en profundidad para obtener
un modelo que funcione, o incluso para obtener un modelo de última generación.
modelo, si el ingeniero es tan ambicioso. No hace falta decir que esa no es una
configuración óptima. Pero la IA puede ayudar. Desafortunadamente, la parte de
manipulación de datos es difícil de automatizar, porque a menudo requiere
conocimiento del dominio, así como una comprensión clara y de alto nivel de lo que
el ingeniero quiere lograr. Sin embargo, la sintonización de hiperparámetros es un
procedimiento de búsqueda simple; y en ese caso sabemos lo que el ingeniero
quiere lograr: está definido por la función de pérdida de la red que se está
sintonizando. Ya es una práctica común configurar sistemas básicos de AutoML que
se encargan de la mayoría de los ajustes de perillas de modelos. Incluso monté el
mío propio, hace años,
En el nivel más básico, dicho sistema ajustaría la cantidad de capas en una pila,
su orden y la cantidad de unidades o filtros en cada capa. Esto se hace comúnmente
con bibliotecas como Hyperopt, que discutimos en el capítulo 7. Pero también
podemos ser mucho más ambiciosos e intentar aprender una arquitectura apropiada
desde cero, con la menor cantidad de restricciones posible: por ejemplo, a través del
aprendizaje por refuerzo o genética. algoritmos
Otra dirección importante de AutoML implica el aprendizaje de la arquitectura
del modelo junto con los pesos del modelo. Debido a que entrenar un nuevo modelo
desde cero cada vez que probamos una arquitectura ligeramente diferente es
tremendamente ineficiente, un sistema AutoML verdaderamente poderoso haría
evolucionar las arquitecturas al mismo tiempo que las características del modelo se
ajustaban a través de la retropropagación en los datos de entrenamiento. Tales
enfoques están comenzando a surgir mientras escribo estas líneas.
Cuando esto comience a suceder, los trabajos de los ingenieros de aprendizaje
automático no desaparecerán, sino que los ingenieros ascenderán en la cadena de
creación de valor. Comenzarán a esforzarse mucho más en crear funciones de
pérdida complejas que realmente reflejen los objetivos comerciales y comprendan
cómo sus modelos impactan en los ecosistemas digitales en los que se implementan
(por ejemplo, los usuarios que consumen las predicciones del modelo y generan los
datos de entrenamiento del modelo). ), problemas que solo las empresas más
grandes pueden permitirse considerar en la actualidad.

9.3.4 Aprendizaje permanente y reutilización de subrutinas modulares


Si los modelos se vuelven más complejos y se construyen sobre primitivas
algorítmicas más ricas, esta mayor complejidad requerirá una mayor reutilización
entre tareas, en lugar de entrenar un nuevo modelo desde cero cada vez que tenemos
una nueva tarea o un nuevo conjunto de datos. Muchos conjuntos de datos no
contienen suficiente información para que podamos desarrollar un modelo nuevo y
complejo desde cero, y será necesario usar información de conjuntos de datos
encontrados anteriormente (al igual que no aprende inglés desde cero cada vez que
abre un nuevo libro). —eso sería imposible). Entrenar modelos desde cero en cada

Con licencia para


tarea nueva también es ineficiente debido a la gran superposición entre las tareas
actuales y las tareas encontradas anteriormente.

Con licencia para


334 CPASADO9Conclusiones

Una observación notable se ha hecho repetidamente en los últimos años:


entrenar el mismo modelo para realizar varias tareas poco conectadas al mismo
tiempo da como resultado un modelo que es mejor en cada tarea. Por ejemplo,
entrenar el mismo modelo neuronal de traducción automática para realizar la
traducción del inglés al alemán y del francés al italiano dará como resultado un
modelo que es mejor en cada par de idiomas. De manera similar, entrenar un
modelo de clasificación de imágenes junto con un modelo de segmentación de
imágenes, compartiendo la misma base convolucional, da como resultado un
modelo que es mejor en ambas tareas. Esto es bastante intuitivo: siempre hay alguna
superposición de información entre tareas aparentemente desconectadas, y un
modelo conjunto tiene acceso a una mayor cantidad de información sobre cada tarea
individual que un modelo entrenado solo en esa tarea específica.
Actualmente, cuando se trata de la reutilización de modelos entre tareas, usamos
pesos previamente entrenados para modelos que realizan funciones comunes, como la
extracción de características visuales. Usted vio esto en acción en el capítulo 5. En el
futuro, espero que una versión generalizada de esto sea un lugar común: usaremos no
solo características previamente aprendidas (pesos de submodelos), sino también
arquitecturas de modelos y procedimientos de entrenamiento. A medida que los
modelos se parezcan más a los programas, comenzaremos a reutilizar las subrutinas del
programa como las funciones y clases que se encuentran en los lenguajes de
programación humanos.
Piense en el proceso de desarrollo de software actual: una vez que un ingeniero
resuelve un problema específico (consultas HTTP en Python, por ejemplo), lo
empaqueta como una biblioteca abstracta y reutilizable. Los ingenieros que enfrenten un
problema similar en el futuro podrán buscar bibliotecas existentes, descargar una y
usarla en su propio proyecto. De manera similar, en el futuro, los sistemas de
metalaprendizaje podrán ensamblar nuevos programas examinando una biblioteca
global de bloques reutilizables de alto nivel. Cuando el sistema se encuentra
desarrollando subrutinas de programa similares para varias tareas diferentes, puede
generar una versión abstracta y reutilizable de la subrutina y almacenarla en la
biblioteca global (consulte la figura 9.6). Tal proceso implementará la abstracción: un
componente necesario para lograr una generalización extrema. Se puede decir que una
subrutina que es útil en diferentes tareas y dominios abstrae algún aspecto de la
resolución de problemas. Esta definición de abstracción es similar a la noción de
abstracción en ingeniería de software. Estas subrutinas pueden ser geométricas
(módulos de aprendizaje profundo con representaciones previamente entrenadas) o
algorítmicas (más cercanas a las bibliotecas que manipulan los ingenieros de software
contemporáneos).

Con licencia para


El futuro de lo profundoaprendizaje 335

Biblioteca global
de subrutinas Empuje
abstractas subrutinas
reutilizable Metal-aprendiz perpetuo
Subrutina Subrutina Subrutina s
geométric algorítmic algorítmic
capaz de hacer crecer
a a a rápidamente un modelo a
Subrutina Subrutina Subrutina nivel de tarea Tarea #002453
Obtener a través de una variedad
geométric algorítmic algorítmic
a a a
subrutinas de tareas
relevantes Tarea #002454
Subrutina Subrutina Subrutina
geométric algorítmic algorítmic
Opcion Datosy
a a a
es de retroalim
diseño Tarea #002455
Programa modular aentación
nivel
de tarea aprendido sobre
la marcha para resolver Datosy
una tarea específica retroalim
entación
Tarea #002456
GeométricaAlgorítmica
subrutinasubrutina
Comport
amiento
GeométricaAlgorítmica
subrutinasubrutina

Figura 9.6 Un meta-aprendiz capazde desarrollar rápidamente modelos específicos de tareas utilizando
primitivas reutilizables(tanto algorítmico como geométrico), logrando así una generalización
extrema

9.3.5 el largo plazovisión


En resumen, esta es mi visión a largo plazo para el aprendizaje automático:
◾ Los modelos serán más como programas y tendrán capacidades que van mucho
más allá de las continuas transformaciones geométricas de los datos de entrada
con los que trabajamos actualmente. Podría decirse que estos programas estarán
mucho más cerca de los modelos mentales abstractos que los humanos mantienen
sobre su entorno y sobre sí mismos, y serán capaces de una mayor generalización
debido a su rica naturaleza algorítmica.
◾ En particular, los modelos combinarán módulos algorítmicos que brindan
capacidades formales de razonamiento, búsqueda y abstracción con módulos
geométricos que brindan intuición informal y capacidades de reconocimiento de
patrones. AlphaGo (un sistema que requirió mucha ingeniería de software manual
y decisiones de diseño hechas por humanos) proporciona un ejemplo temprano de
cómo podría verse una combinación de IA simbólica y geométrica.
◾ Dichos modelos se desarrollarán automáticamente en lugar de ser codificados por
ingenieros humanos, utilizando partes modulares almacenadas en una biblioteca
global de subrutinas reutilizables, una biblioteca que evolucionó mediante el
aprendizaje de modelos de alto rendimiento en miles de conjuntos de datos y
tareas anteriores. A medida que el sistema de metaaprendizaje identifique
patrones frecuentes de resolución de problemas, se convertirán en subrutinas
reutilizables, al igual que las funciones y clases en ingeniería de software, y se
agregarán a la biblioteca global. Esto logrará la abstracción.
◾ Esta biblioteca global y el sistema de crecimiento de modelos asociado podrán
lograr alguna forma de generalización extrema similar a la humana: dada una

Con licencia para


nueva tarea o situación,

Con licencia para


336 CPASADO9Conclusiones

el sistema podrá ensamblar un nuevo modelo de trabajo apropiado para la tarea


utilizando muy pocos datos, gracias a primitivas similares a programas que se
generalizan bien y una amplia experiencia con tareas similares. De la misma
manera, los humanos pueden aprender rápidamente a jugar un nuevo videojuego
complejo si tienen experiencia con muchos juegos anteriores, porque los modelos
derivados de esta experiencia previa son abstractos y parecidos a programas, en
lugar de un mapeo básico entre estímulos. uli y acción.
◾ Como tal, este sistema de crecimiento de modelos de aprendizaje perpetuo
puede interpretarse como una inteligencia general artificial ( AGI). Pero no
esperes que se produzca ningún apocalipsis robótico singularitario: eso es pura
fantasía, proveniente de una larga serie de profundos malentendidos tanto de la
inteligencia como de la tecnología. Tal crítica, sin embargo, no pertenece a este
libro.

Con licencia para


Mantenerse al día en un mundo en rápido movimientocampo 337

9.4 Mantenerse al día en un campo en rápida evolución


Como palabras finales de despedida, quiero darle algunos consejos sobre cómo
seguir aprendiendo y actualizando sus conocimientos y habilidades después de
haber pasado la última página de este libro. El campo del aprendizaje profundo
moderno, tal como lo conocemos hoy, tiene solo unos pocos años, a pesar de una
prehistoria larga y lenta que se remonta a décadas. Con un aumento exponencial de
los recursos financieros y el personal de investigación desde 2013, el campo en su
conjunto ahora se mueve a un ritmo frenético. Lo que ha aprendido en este libro no
será relevante para siempre, y no es todo lo que necesitará para el resto de su
carrera.
Afortunadamente, hay muchos recursos en línea gratuitos que puede usar para
mantenerse actualizado y expandir sus horizontes. Aquí hay algunos.

9.4.1 Practica en problemas del mundo real usando Kaggle


Una forma efectiva de adquirir experiencia en el mundo real es probar suerte en el
aprendizaje automático. competicioneso norte Kaggle(https://kaggle.com). los
solamentereayo camino a aprender es a través de la práctica y la codificación real: esa es la
filosofía de este libro, y las competencias de Kaggle son la continuación natural de esto. En
Kaggle, encontrará una variedad de competencias de ciencia de datos constantemente renovadas,
muchas de las cuales involucran aprendizaje profundo, preparadas por empresas interesadas en
obtener soluciones novedosas para algunos de sus problemas de aprendizaje automático más
desafiantes. Se ofrecen premios monetarios bastante grandes a los mejores participantes.
La mayoría de las competencias se ganan utilizando la biblioteca XGBoost (para
aprendizaje automático superficial) o Keras (para aprendizaje profundo). ¡Así que
encajarás perfectamente! Al participar en algunas competencias, tal vez como parte
de un equipo, se familiarizará con el lado práctico de algunas de las mejores
prácticas avanzadas descritas en este libro, especialmente el ajuste de
hiperparámetros, evitando el sobreajuste del conjunto de validación y el modelo.
montaje

9.4.2 Lea sobre los últimos desarrollos en arXiv


La investigación de aprendizaje profundo, a diferencia de otros campos científicos, se
lleva a cabo completamente al aire libre. Los documentos se hacen públicos y de libre
acceso tan pronto como están finalizados, y a loteoF relacionado software esaire
librenorte fuente. arXiv(https://arxiv.org)—pronunciado “archivo” (la X significa el
griego chi)—es un servidor de preimpresión de acceso abierto para trabajos de
investigación en física, matemáticas e informática. Se ha convertido en la forma de
facto de mantenerse actualizado sobre la vanguardia del aprendizaje automático y el
aprendizaje profundo. La gran mayoría de los investigadores de aprendizaje profundo
cargan cualquier artículo que escriben en arXiv poco después de su finalización. Esto
les permite plantar una bandera y reclamar un hallazgo específico sin esperar la
aceptación de una conferencia (que lleva meses), lo cual es necesario dado el rápido
ritmo de investigación y la intensa competencia en el campo. También permite que el
campo se mueva extremadamente rápido: todos los nuevos hallazgos están disponibles
de inmediato para que todos los vean y desarrollen.
Con licencia para
Una desventaja importante es que la gran cantidad de documentos nuevos que se
publican todos los días en arXiv hace que sea imposible siquiera hojearlos todos; y el
hecho de que no sean revisados por pares hace que sea difícil identificar aquellos que
son importantes y de alta calidad.

Con licencia para


338 CPASADO9Conclusiones

Es difícil, y cada vez más, encontrar la señal en el ruido. Actualmente, no hay una
buena solución a este problema. Pero algunas herramientas pueden ayudar: un sitio
web auxiliar llamado arXiv Sanity Preserver (http://arxiv-sanidad.com) sirve como
un motor de recomendación para nuevos documentos y puede ayudarlo a realizar un
seguimiento de los nuevos desarrollos dentro de una estrecha vertical específica de
aprendizaje profundo. Además, puede utilizar Google Scholar
(https://erudito.google.com) para realizar un seguimiento de las publicaciones de
sus autores favoritos.

9.4.3 Explora el ecosistema de Keras


Con cerca de 200 000 usuarios a partir de noviembre de 2017 y creciendo
rápidamente, Keras tiene un gran ecosistema de tutoriales, guías y proyectos de
código abierto relacionados:
◾ Su principal referencia para trabajar con Keras es la documentación en línea
enhttps://keras.io. los Keras fuente código pueden serF sonido a
https://github.com/ fchollet/keras.
◾ Puede solicitar ayuda y unirse a debates de aprendizaje profundo en el canal
Keras Slack: https://kerasteam.slack.com.
◾ los Keras Blog, https://blog.keras.io,o ofertas Keras tutoriales y otro artículos
relacionados con el aprendizaje profundo.
◾ Puedes seguirme en Twitter: @fchollet.

Con licencia para


Ultimas palabras 339

9.5 Ultimas palabras


¡Este es el final del aprendizaje profundo con Python! Espero que hayas aprendido una
o dos cosas sobre el aprendizaje automático, el aprendizaje profundo, Keras y tal vez
incluso la cognición en general. El aprendizaje es un viaje que dura toda la vida,
especialmente en el campo de la IA, donde tenemos muchas más incógnitas en nuestras
manos que certezas. Así que sigue aprendiendo, cuestionando e investigando. Nunca
pares. Porque incluso dado el progreso realizado hasta ahora, la mayoría de las
preguntas fundamentales en IA siguen sin respuesta. A muchos ni siquiera se les ha
preguntado correctamente todavía.

Con licencia para


apéndice A
Instalación de Keras y
sus dependencias en
Ubuntu

El proceso de configuración de una estación de trabajo de aprendizaje profundo es


bastante complicado y consta de los siguientes pasos, que este apéndice cubrirá en
detalle:
1Instale la suite científica de Python, Numpy y SciPy, y asegúrese de tener
instalada una biblioteca de subprograma de álgebra lineal básica (BLAS) para
que sus modelos se ejecuten rápidamente en la CPU.
2Instale dos paquetes adicionales que resultan útiles al usar Keras: HDF5
(para guardar archivos grandes de redes neuronales) y Graphviz (para
visualizar arquitecturas de redes neuronales).
3Asegúrese de que su GPU pueda ejecutar código de aprendizaje profundo
instalando controladores CUDA y cuDNN.
4Instale un backend para Keras: TensorFlow, CNTK o Theano.

5Instala Keras.

Puede parecer un proceso desalentador. De hecho, la única parte difícil es


configurar la compatibilidad con GPU; de lo contrario, todo el proceso se puede
realizar con unos pocos comandos y toma solo un par de minutos.
Asumiremos que tiene una instalación nueva de Ubuntu, con una GPU NVIDIA
disponible. Antes de comenzar, asegúrese de tener pip instalado y que su
administrador de paquetes esté actualizado:
$ sudo apt-obtener actualización
$ sudo apt-obtener actualización
$ sudo apt-get install python-pip python-dev

Con licencia para


340

Con licencia para


Instalación de Python Scientificsuite 341

Pitón 2contra Python 3


De manera predeterminada, Ubuntu usa Python 2 cuando instala paquetes de Python
comopitón-pip. Si desea usar Python 3 en su lugar, debe usar elpitón3prefijo en
su lugardepitón. Por ejemplo:
$ sudo apt-get install python3-pip python3-dev

Cuando estás instalando paquetes usandopepita, tenga en cuenta que, de


forma predeterminada, apunta a Python 2. Para apuntar a Python 3, debe
usarpip3:
$ sudo pip3 instalar tensorflow-gpu

A.1 Instalación de la suite científica de Python


Si usa una Mac, le recomendamos que instale la suite científica Python a través de
Anaconda, que puede obtener enwww.continuum.io/descargas.Tenga en cuenta que
esto no incluirá HDF5 y Graphviz, que debe instalar manualmente. Los siguientes
son los pasos para una instalación manual de la suite científica de Python en
Ubuntu:
1Instaleuna biblioteca BLAS (OpenBLAS, en este caso), para asegurarse de que
puede ejecutar operaciones de tensor rápidas en su CPU:
$ sudo apt-get install build-essential cmake git unzip \
pkg-config libopenblas-dev liblapack-dev

2Instale la suite científica de Python: Numpy, SciPy y Matplotlib. Esto es necesario


para realizar cualquier tipo de aprendizaje automático o computación científica en
Python, independientemente de si está realizando un aprendizaje profundo:
$ sudo apt-get install python-numpy python-scipy python-matplotlib
➥python-yaml
3InstaleHDF5. Esta biblioteca, desarrollada originalmente por la NASA, almacena
grandes archivos de datos numéricos en un formato binario eficiente. Le
permitirá guardar sus modelos de Keras en el disco de forma rápida y eficiente:
$ sudo apt-get install libhdf5-serial-dev python-h5py

4InstaleGraphviz y pydot-ng, dos paquetes que le permitirán visualizar modelos


de Keras. No son necesarios para ejecutar Keras, por lo que puede omitir este
paso e instalar estos paquetes cuando los necesite. Aquí están los comandos:
$ sudo apt-get install graphviz
$ sudo pip install pydot-ng

5Instale paquetes adicionales que se utilizan en algunos de nuestros ejemplos de código:


$ sudo apt-get install python-opencv

Con licencia para


342 AAPÉNDICEA Instalación de Keras y sus dependencias en Ubuntu

A.2 Configurar la compatibilidad con GPU


El uso de una GPU no es estrictamente necesario, pero es muy recomendable. Todos los
ejemplos de código que se encuentran en este libro se pueden ejecutar en la CPU de una
computadora portátil, pero a veces es posible que tenga que esperar varias horas para
que un modelo se entrene, en lugar de meros minutos en una buena GPU. Si no tiene
una GPU NVIDIA moderna, puede omitir este paso e ir directamente a la sección A.3.
Para usar su GPU NVIDIA para el aprendizaje profundo, debe instalar dos cosas:
◾ CUDA—Un conjunto de controladores para su GPUque le permite ejecutar un
lenguaje de programación de bajo nivel para computación paralela.
◾ cuDNN—Una biblioteca de primitivas altamente optimizadas para el aprendizaje
profundo. Al usar cuDNNy corriendo en unGPU, normalmente puede aumentar
la velocidad de entrenamiento de sus modelos entre un 50 % y un 100 %.
TensorFlow depende de versiones particulares de CUDA y la biblioteca cuDNN. En
el momento de redactar este documento, utiliza la versión 8 de CUDA y la versión 6
de cuDNN. Consulte el sitio web de TensorFlow para obtener instrucciones
detalladas sobre qué versiones se recomiendan
actualmente:www.tensorflow.org/install/install_linux.
Sigue estos pasos:
1Descargar CUDA. Para Ubuntu (y otras variantes de Linux), NVIDIA
proporciona un paquete listo para usar que puede descargar
desdehttps://desarrollador
.nvidia.com/cuda-descargas:
$ por recibirhttp://developer.download.nvidia.com/compute/cuda/repos/ubuntu1604/
➥x86_64/cuda-repo-ubuntu1604_9.0.176-1_amd64.deb
2Instale CUDA. La forma más fácil de hacerlo es usar apt de Ubuntu en este
paquete.Esto le permitirá instalar fácilmente actualizaciones a través de apt a medida
que estén disponibles:
$ sudo dpkg -i cuda-repo-ubuntu1604_9.0.176-1_amd64.deb
$ sudo apt-key adv --fetch-keys
➥http://developer.download.nvidia.com/compute/cuda/repos/ubuntu1604/
➥x86_64/7fa2af80.pub
$ sudo apt-obtener actualización
$ sudo apt-get install cuda-8-0

3InstalarcuDNN:
aRegístrese para obtener una cuenta gratuita de desarrollador de NVIDIA
(lamentablemente, esto es necesario para obtener acceso a la descarga de
cuDNN) y descargue cuDNN enhttps://desarrollador. NVIDIA.com/cudnn
(Seleccione la versión de cuDNN compatible con TensorFlow). Al igual
que CUDA, NVIDIA proporciona paquetes para diferentes sabores de
Linux; usaremos la versión para Ubuntu 16.04. Tenga en cuenta que si está
trabajando con una instalación EC2, no podrá descargar el archivo cuDNN
directamente a su instancia; en su lugar, descárguelo a su máquina local y
luego cárguelo a su instancia EC2 (a través de scp).
bInstalar cu DNN:
$ sudo dpkg -i dpkg -i libcudnn6*.deb
Con licencia para
Instalación de Keras 343

4InstalarTensorFlow:
aTensorFlow con o sin compatibilidad con GPU se puede instalar desde PyPI
mediante Pip. Aquí está el comando sin soporte de GPU:
$ sudo pip instalar tensorflow

bEste es el comando para instalar TensorFlow con compatibilidad con GPU:


$ sudo pip install tensorflow-gpu

A.3 Instalación de Theano (opcional)


Debido a que ya instaló TensorFlow, no es necesario que instale Theano para ejecutar el
código de Keras. Pero a veces puede ser útil alternar entre TensorFlow y Theano al
crear modelos de Keras.
Theano también se puede instalar desde PyPI:
$ sudo pip install theano

Si está usando una GPU, debe configurar Theano para usar su GPU. Puede crear un
archivo de configuración de Theano con este comando:
nano ~/.theanorc

Luego, complete el archivo con la siguiente configuración:


[global]
floatX =
dispositivo
float32 = gpu0
[nvcc]
matemáticas rápidas = Verdadero

A.4 Instalación de Keras


Puede instalar Keras desde PyPI:
$ sudo pip instalar keras

Alternativamente, puede instalar Keras desde GitHub. Si lo hace, podrá acceder a la


carpeta keras/examples, que contiene muchos scripts de ejemplo de los que puede
aprender:
$ git clonar https://github.com/fchollet/keras
$ cd keras
$ sudo python setup.py instalar

Ahora puede intentar ejecutar un script de Keras, como este ejemplo de MNIST:
ejemplos de python/mnist_cnn.py

Tenga en cuenta que ejecutar este ejemplo hasta su finalización puede llevar unos
minutos, así que siéntase libre de forzar la salida (Ctrl-C) una vez que haya
verificado que funciona normalmente.
Después de ejecutar Keras al menos una vez, el archivo de configuración de Keras se
puede encontrar en
~/.keras/keras.json.yotuCalifornianorteedicióntittoseleccionartelmiretroced
erdesotkerascorrersen:tensorflow, theano o cntk. Su archivo de configuración debería ser
así:
Con licencia para
344 AAPÉNDICEA Instalación de Keras y sus dependencias en Ubuntu

{
"image_data_format": "channels_last",
"epsilon": 1e-07,
"floatx": "float32",
"backend": "tensorflow"
}

Mientras se ejecuta el script de Keras Examples/mnist_cnn.py, puede monitorear la


utilización de la GPU en una ventana de shell diferente:
$ reloj -n 5 NVIDIA-smi -a --display=utilización

¡Estás listo! Felicitaciones, ahora puede comenzar a crear aplicaciones de aprendizaje profundo.

Con licencia para


apéndice
BEjecución de cuadernos
Jupyteren una instancia
de GPU EC2

Este apéndice proporciona un paso a pasoguía para ejecutar cuadernos Jupyter de


aprendizaje profundo en una instancia de GPU de AWS y editar los cuadernos
desde cualquier lugar de su navegador. Esta es la configuración perfecta para la
investigación de aprendizaje profundo si no tiene una GPU en su máquina local.
La versión original (y actualizada) de esta guía se puede fundar a
https://blog.keras.io.

B.1 ¿Qué son los cuadernos Jupyter?


¿Por qué ejecutar cuadernos de Jupyter en GPU de AWS?
Un cuaderno Jupyter es una aplicación web que le permite escribir y anotar código de
Python de forma interactiva. Es una excelente manera de experimentar, investigar y
compartir lo que está trabajando.
Muchas aplicaciones de aprendizaje profundo son muy intensivas desde el punto
de vista computacional y pueden tardar horas o incluso días cuando se ejecutan en los
núcleos de CPU de una computadora portátil. La ejecución en una GPU puede
acelerar el entrenamiento y la inferencia en un factor considerable (a menudo de 5 a
10 veces, cuando se pasa de una CPU moderna a una única GPU moderna). Pero es
posible que no tenga acceso a una GPU en su máquina local. Ejecutar notebooks
Jupyter en AWS le brinda la misma experiencia que ejecutar en su máquina local, al
tiempo que le permite usar una o varias GPU en AWS. Y solo paga por lo que usa, lo
que puede compararse favorablemente con invertir en sus propias GPU si usa el
aprendizaje profundo solo ocasionalmente.

Con licencia para


345

Con licencia para


346 AAPÉNDICEB Ejecución de portátiles Jupyter en una instancia de GPU EC2

B.2 ¿Por qué no querrías usar Jupyter?en


AWS para el aprendizaje profundo?
Las instancias de GPU de AWS pueden volverse costosas rápidamente. El que sugerimos usar
cuesta
$0.90 por hora. Esto está bien para uso ocasional; pero si va a realizar experimentos
durante varias horas al día todos los días, es mejor que construya su propia máquina
de aprendizaje profundo con una TITAN X o GTX 1080 Ti.
En resumen, use la configuración de Jupyter-on-EC2 si no tiene acceso a una GPU
local o si no quiere lidiar con la instalación de dependencias de Keras, en particular,
controladores de GPU. Si tiene acceso a una GPU local, le recomendamos que ejecute
sus modelos localmente. En ese caso, utilice la guía de instalación del apéndice A.

NOTA Necesitará una cuenta de AWS activa. Un poco de familiaridad con


AWS EC2 ayudará, pero no es obligatorio.

B.3 Configuración de una instancia de GPU de AWS


El siguiente proceso de configuración tomará de 5 a 10 minutos:
1 Navegarto la EC2 control panel a https://console.aws.amazon.com/ec2/v2y haga
clic en el vínculo Iniciar instancia (consulte la figura B.1).

Figura B.1 El panel


de control EC2

2Seleccione AWS Marketplace (consulte la figura B.2) y busque "aprendizaje


profundo" en el cuadro de búsqueda. Desplácese hacia abajo hasta encontrar
la AMI llamada Deep Learning AMI Ubuntu Version (ver figura B.3);
seleccionarlo

Figura B.2 El mercado de AMI de EC2

Con licencia para


Configuración de una GPU de AWSinstancia 347

Figura B.3 La AMI de aprendizaje profundo de EC2

3Seleccionela instancia p2.xlarge (ver figura B.4). Este tipo de instancia brinda
acceso a una sola GPU y cuesta $0.90 por hora de uso (a partir de marzo de
2017).

Figura B.4 La instancia p2.xlarge

4Puede mantener la configuración predeterminada para los pasos Configurar


instancia, Agregar almacenamiento y Agregar etiquetas, pero personalizará el
paso Configurar grupo de seguridad. Cree una regla TCP personalizada para
permitir el puerto 8888 (consulte la figura B.5): esta regla se puede permitir
para su IP pública actual (como la de su computadora portátil) o para
cualquier IP(como 0.0.0.0/0) si lo primero no es posible. Tenga en cuenta que si permite el
puerto 8888 para cualquier IP, entonces, literalmente, cualquiera podrá escuchar ese puerto en
su instancia (que es donde ejecutará las computadoras portátiles IPython). Agregará protección
con contraseña a los cuadernos para mitigar el riesgo de que extraños al azar los modifiquen,
pero esa puede ser una protección bastante débil. Si es posible, debería considerar restringir el
acceso a una IP específica. Pero si su dirección IP cambia constantemente, entonces esa no es
una opción práctica. Si va a dejar el acceso abierto a cualquier IP, recuerde no dejar datos
confidenciales en la instancia.

Con licencia para


348 AAPÉNDICEB Ejecución de portátiles Jupyter en una instancia de GPU EC2

Figura B.5 Configure un nuevo grupo de seguridad.

NOTAAl final del proceso de inicio, se le preguntará si desea crear nuevas


claves de conexión o si desea reutilizar las claves existentes. Si nunca antes
ha usado EC2, cree nuevas claves y descárguelas.
5Para conectarse a su instancia, selecciónela en el panel de control de EC2, haga
clic en el botón Conectar y siga las instrucciones (consulte la figura B.6).
Tenga en cuenta que la instancia puede tardar unos minutos en iniciarse. Si no
puede conectarse al principio, espere un poco y vuelva a intentarlo.

Figura B.6 Instrucciones de conexión

6Una vez que haya iniciado sesión en la instancia a través de SSH, cree un
directorio ssl en la raíz de la instancia y haga un cd (no es obligatorio, pero es
más limpio):
$ mkdir ssl
$ cd ssl

Con licencia para


Configuración de una GPU de AWSinstancia 349

7Cree un nuevo certificado SSL usando OpenSSL y cree archivos cert.key y


cert.pem en el directorio ssl actual:
$ openssl req -x509 -nodes -days 365 -newkey rsa:1024 -keyout "cert.key" -out
➥"cert.pem" -lote
2.3.1 configurando Jupyter
Antes de usar Jupyter, debe retocar su configuración predeterminada. Sigue estos
pasos:
1Genere un nuevo archivo de configuración de Jupyter (todavía en la instancia remota):
$ jupyter notebook --generate-config

2Opcionalmente, puede generar una contraseña de Jupyter para sus cuadernos.


Debido a que su instancia puede estar configurada para ser accesible desde
cualquier IP (según la elección que haya realizado al configurar el grupo de
seguridad), es mejor restringir el acceso a Jupyter a través de una contraseña.
Para generar una contraseña, abra un shell IPython (comando ipython) y
ejecute lo siguiente:
desde IPython.lib import
passwd passwd()
salida

3El comando passwd() le pedirá que ingrese y verifique una contraseña. Después de
hacerlo, mostrará un hash de su contraseña. Copie ese hash, lo necesitará pronto. Se
ve algo como esto:
sha1:b592a9cf2ec6:b99edb2fd3d0727e336185a0b0eab561aa533a43

Tenga en cuenta que esto es un hash de la palabra contraseña, que no es una


contraseña que deba usar.
4Use vi (o su editor de texto disponible favorito) para editar el archivo de configuración de
Jupyter:
$ vi ~/.jupyter/jupyter_notebook_config.py

5El archivo de configuración es un archivo de Python con todas las líneas


comentadas. Inserte las siguientes líneas de código Python al principio del
archivo:
Ruta a la clave privada que Sirve los
generó para el certificado cuadernos
localmente
Ruta al certificado que
generó Obtiene el objeto de Figura en línea
configuración cuando se usa
Matplotlib

c =get_config()
c.NotebookApp.certfile = u'/home/ubuntu/ssl/cert.pem'
c.NotebookApp.keyfile = u'/home/ubuntu/ssl/cert.key'
c.IPKernelApp.pylab = 'en línea'
c.NotebookApp.ip = '*'
c.NotebookApp.open_browser = Falso
c.NotebookApp.password =
➥'sha1:b592a9cf2ec6:b99edb2fd3d0727e336185a0b0eab561aa533a43'
Con licencia para
No abra una ventana del Hash de
navegador de forma contraseña que
predeterminada cuando use generó
cuadernos. anteriormente

Con licencia para


350 AAPÉNDICEB Ejecución de portátiles Jupyter en una instancia de GPU EC2

NOTAEn caso de que no esté acostumbrado a usar vi, recuerde que debe
presionar I para comenzar a insertar contenido. Cuando haya terminado,
presione Esc, ingrese :wq y presione Entrar para salir de vi y guardar sus
cambios (:wq significa escribir-salir).

B.4 Instalación de Keras


Ya casi está listo para comenzar a usar Jupyter. Pero primero, debe actualizar Keras.
Hay una versión de Keras preinstalada en la AMI, pero es posible que no esté
necesariamente actualizada. En la instancia remota, ejecute este comando:
$ sudo pip install keras --actualizar

Debido a que probablemente usará Python 3 (los cuadernos provistos con este libro
usan Python 3), también debe actualizar Keras usando pip3:
$ sudo pip3 instalar keras --actualizar

Si hay un archivo de configuración de Keras existente en la instancia (no debería


haberlo, pero la AMI puede haber cambiado desde que escribí esto), debe
eliminarlo, por si acaso. Keras volverá a crear un archivo de configuración estándar
cuando se inicie por primera vez.
Si el siguiente fragmento de código devuelve un error que indica que el archivo
no existe, puede ignorarlo:
$ rm -f ~/.keras/keras.json

B.5 Configurar el reenvío de puerto local


En un shell en su máquina local (no en la instancia remota), comience a reenviar su
puerto local 443 (el HTTPSpuerto) al puerto 8888 de la instancia remota:
$ sudo ssh -i awsKeys.pem -L puerto_local:máquina_local:puerto_remoto máquina_remota

En mi caso, quedaría de la siguiente manera:


$ sudo ssh -i awsKeys.pem -L
➥443:127.0.0.1:8888ubuntu@ec2-54-147-126-214.compute-1.amazonaws.com

B.6 Usando Jupyter desde su navegador local


En la instancia remota, clone el repositorio de GitHub que contiene los cuadernos de
Jupyter asociados con este libro:
$ clon de git https://github.com/fchollet/deep-learning-with-python-
notebooks.gitcd deep-learning-with-python-notebooks

Inicie Jupyter Notebook ejecutando este comando, aún en la instancia remota:


$ libreta jupyter

Luego, en su navegador local, navegue a la dirección local que está reenviando al


control remoto computadora portátil proceso (https://127.0.0.1). Ser Por supuesto
tútuse HTTPS entél dirección, o obtendrá un error de SSL.

Con licencia para


Usando Jupyter desde su localnavegador 351

Debería ver la advertencia de seguridad que se muestra en la figura B.7. Esta


advertencia se debe al hecho de que el certificado SSL que generó no está verificado por
una autoridad de confianza (obviamente, usted generó el suyo propio). Haga clic en
Avanzado y proceda a navegar.

Figura B.7 Una advertencia de seguridadpuede ignorar

Se le pedirá que ingrese su contraseña de Jupyter. A continuación, llegará al panel de


control de Jupyter (consulte la figura B.8).

Figura B.8 El tablero de Jupyter

Elija New > Notebook para comenzar (vea la


figura B.9). Puede utilizar la versión de Python
de su elección. ¡Todo listo!

Figura B.9 Crear un nuevo cuaderno.

Con licencia para


Con licencia para
índice
simbolos arquitectura de redes 319–322 B
convnets 321
* operador 40 redes densamente Babbage, Carlos 4 motor
+ operador 99 conectadas 319–320 de fondo, Keras 62
redes neuronales algoritmo de
recurrentes321–322 retropropagación
numericos patrones de arquitectura de 11,51–52,246
modelos 260–263 pase hacia atrás 49
tensores 0D.Verescalares normalización por lotes bolsa-de-2-gramos 181
circunvoluciones 1D 225– 260–261 bolsa-de-3-gramos 181
227 Agrupación 1D, para separable en profundidad bolsa de palabras 181
secuencia convolución 261–263 Baidu 22
datos 226 conexiones residuales 235– lote eje 35
tensores 236,244–246 normalización por lotes 22
1D.Vervectorestensores flecha del tiempo 100 BatchNormalization capa 260
2D.Vermatricesincrusta inteligencia artificial 3–13, lote_tamaño 211
ciones 3D 253 270 Bengio, Yoshua 17,188,202
expectativas para 13 capas bidireccionales 207
A historia de 12-13 clasificaciones binarias 68–77,
servidor de preimpresión arXiv 96
activación 160 271,337–338 entropía cruzada binaria 60,72
ensamblaje de conjuntos de cajas negras 160
funciones de activación 22
datos 111–112
segmentación de anuncios 12 BLAS (Álgebra Lineal Básica
inteligencia aumentada 270
método add_loss 302 subprogramas)39,340
aumento de datos 138–
ADMM (dirección efectos de borde 125–
142extracción de
alternamétodo de 126 operaciones de
características con
multiplicadores) 332 radiodifusión
149–152
redes antagónicas 310 39–40
extracción de
Ver tambiénaprendizaje navegadores, locales, usando
características sin
profundo generativo; 147–149 Jupyterde 350–351
redes adversarias codificadores
generativas automáticos.VerVAE C
red adversaria 305 (variacióncodificadore
transformaciones afines 72 s automáticos devoluciones de llamada,
Web de opcionales) escritura 251–252CAM
AmazonasServicios.VerAWSA Sistemas AutoML 333 (mapa de activación de
MD 20 conducción autónoma 12 clases)
Motor Analítico 4 AWS (servicios web de 172
anotaciones 94,96 interfaces Amazon) codificación categórica 79
de programas de aplicación. Instancias de GPU categorical_crossentropy
VerAPI funcionales ejecutando Jupyter en función 53,80,83
350configurar 346–350
usando Jupyter en 346

Con licencia para


353

Con licencia para


354 ÍNDICE

datos138–142
CERN 17 visualizando el aprendizaje de convnet 160–
usando
canaleseje 123 176
convenciones
canales-primera convención 36 filtros convnet 167–172 mapas de calor
preentrenadas
canales-última convención 36 de clase
143–159
lenguaje neuronal a nivel de activación 172–176 activaciones
extracción
carácter intermedias
de 160–166
modelo 272
caracterí filtros convennets 160
Ciresan, Dan 17,20
sticas base de convolución 143–144operaciones de
activación de clase,visualizando
143–152 convolución
el calor- mapas de 172– ajuste fino 152–158
176 122–127
clases 27,96 efectos de borde 125–126
clasificación 60 pasos de convolución 127
nube, ejecutando trabajos en remando 125–126
66 agrupamiento 94 pasos de convolución 127 circunvoluciones
CNN.Verconvnets (redes 1D 225–226
neuronales separable en profundidad 261–263
convolucionales) Cortés, Corina 15
CNTK (kit de herramientas entropía cruzada 73
cognitivas de controladores CUDA 20,340,342
Microsoft) 62 biblioteca cuDNN 62,340,342
compilación paso 29 curvatura 48
conceptovectores, para
editar D
imágenes 297–298
datos de acondicionamiento datos
272 Botón de conexión, aumentando 138–142rasgoextracción
control EC2 con
tablero 348 149–152
conexiones,residuo 244–246 extracción de características sin 147–
pérdida de contenido 288 149
Conv1D capa 226 lotes de 34–35 generar datos de
Conv2D capa 120,122,124 secuencia
convenciones(neural 272
convolucional heterogéneo 101
redes) 321 homogéneo 101 representaciones de
1D 226–227 aprendizaje
combinando con de 6–8
recurrenteRedes desaparecido 102
neuronales 228–231 preparando 112–113
resumen 120–129 para generación de texto LSTM a nivel
circunvoluciónoperaci de carácter 274
ones para neural recurrente redes 210–212
122–127 preprocesamiento 101–103,
operaciones de agrupación 135–138
máxima127–129 redundancia 100 representaciones para
procesamiento de secuencias neural
con 225–231 redes 31–37
capacitaciónen pequeños tensores 3D 32
conjuntos de datos lotes de datos 34–35ejemplos de
130–142 datostensores
construyendo redes 35
133–135
Preprocesamiento de datos
135–138
relevancia para datos
pequeños problemas
130–131
utilizando el aumento de
Con licencia para
iónde
de 23
dimens
habilita
iones
ndo
superio
tecnolo
restens
gías
ores 32
317–318
datos de imagen 36–37
futuro de
atributos clave
23–
de los
24,330–
tensores
336
32–33
máquina
manipulando
automati
tensores en
Numpy 34 zada
aprendizaje 332–333
matrices(ten
aprendizaje permanente
sores
333–335
2D)31–
32 visión a
escalares largo plazo
(tensores 0D) 335–336
31datos de modelos
secuencia 35– como
36 programas
datos de series de tiempo 35- 330–332
36 reutilizació
datos vectoriales 35 n de
vectores subrutin
(tensores 1D) as
31datos de modular
vídeo 37 es333–
barajar 98,100 335
dividir 98 interpretación
tokenización 189–190 geométri
transformaciones 10 ca de
44–45
transformando 6
ferretería y 20–21
vectorización 101
inversión en 22–23
aumento de datos 130
destilación de datos 28 limitaciones
de 325–
puntos de datos 27,220
329
representatividad de
generaliz
los datos 100
ación
tensores de datos, local vs.
ejemplos de 35
generali
conjuntos de datos, zación
montaje 111–112 extrema
DCGAN 327–329
(convolucional
profunda
GAN)
resumen 307
entrenamiento 310–312
límites de decisión 15
árboles de decisióndieciséis-17
conexiones profundas 266
aprendizaje profundo 3,6–13
logros de 11–12
logros de 315-316
democratizac

Con licencia para


ÍNDICE 355

aprendizaje profundo, Detención anticipada de operaciones elementales 38–39


limitaciones de devoluciones de llamada incrustando capas, aprendiendo
(continuado) 250 incrustaciones de palabras
riesgo Eck, Douglas 271 con 185–187
deantropomorfizar- edición de imágenes, características de ingeniería 101–103
aprendizaje vectores modelos de ensamblaje 264–266
automático modelos conceptuales por épocas 53,74,76,82
325–327 297–298 épsilon 300
resumen 9–11,316–317 Eigen 62 evaluandomodelos 192–195protocolos
posibles usos de 322–324 de evaluación, eligiendo
motivos de interés en 20–24 100,112
Ver tambiéngenerativo sistemas expertos 4
profundo extremogeneralización, generalización
aprendizaje local vs.
AMI de aprendizaje profundo, 327–329
EC2 66Técnica DeepDream comienzo extremo 244
280–286
resumen 280 F
implementando
enKeras ingeniería de características 16,18
281–286 función de aprendizaje 101–103
Deep Mind, Google 22,95 mapas de características 123,129
Capas densas 28,38,53,69–70, caracteristicas
122,187,213,321 ingeniería 101–103
muestreo denso 328 redes extrayendo 143–152
densamente conectadas con aumento de datos149–152
319–320 sin aumento de datos147–149
en profundidadseparable características eje 35
convolución 321 redes feedforward 196,202
derivados, definidos 47–48 Feynman, Ricardo 316
cuenta de desarrollador, modo_relleno 139
NVIDIA filtrar visualizaciones 172 filtros
342 resumen 124
asistentes digitales convnets, visualizando 167–172
12 sintonia FINA 152–158
dimensión 31 método de ajuste 29
dimensionalidad 31,94 método fit_generator 136
gráficos acíclicos dirigidos Aplanar capa 133
de Flickr21
capas 242–246 flotar32 29,101,173
módulos de inicio 242–244 para bucle 38,197,331
conexiones residuales pase hacia adelante 46
244–246 capas de congelación 150
redes discriminatoriasresumen capas completamente conectadas 58 API
305 funcionales, Keras 234–248
implementar 307–309 gráficos acíclicos dirigidos de capas
función de distancia 288 242–246
operaciones de puntos 40–42 compartir el peso de la capa 246–247
producto escalar 38 modelos como capas 247–248 modelos
descargando de entradas múltiples 238–240
incrustaciones de palabras en modelos multisalida 240–242
guantes 190texto sin procesar
189
Capa de abandono 140
atributo tipod 32–33

mi

Con licencia para


pérdida de
GRAMO estilo 288–
289aprendizaje
Gal, Yarin 216
profundo
GAN (Generative
generativo,
Adversial redes)
Sueño
296,305
Profundo 280–286
capas de unidades recurrentes
generativoredes
cerradas.
recurrentes,
Vercapas
historia de 271
GRUGatys, León
generador de
287
funcion 211,230
Distribución gaussiana 307
redes de
generalización 104,327–329
generadores,
aprendizaje profundo
implementar
generativo
307–308
generación de imágenes
interpretación
con varia-
codificadores geométrica
automáticos de aprendizaje profundo
nacionales 296–304 44–45
vectores de concepto de operaciones
paraimagenedición tensoriales 43–
297–298 44espacio
muestreo de geométrico 316
latente
espacios de
imágenes
296–297
generar texto con LSTM
271–279
generación de datos
de secuencia 272
historia de las redes
recurrentes
generativas 271
implementarpersonaj
e-nivel de texto
LSTM generación
274–279
estrategia de muestreo 272–
274 contradictorio generativo
redes 305–313
redes antagónicas 310
redes discriminatorias
307–309
redes generadoras307–
308
implementación
esquemática de 307
entrenamiento DCGAN
310–312 transferencia de
estilo neural 287–295
pérdida de contenido 288
en Keras 289–295

Con licencia para


356 ÍNDICE

datos heterogéneos 101


GloVe (Vectores globales para Hinton, Geoffrey 17,109
capas ocultas 77
la representación de Hochreiter, septiembre de 202
palabras) unidad oculta 70 validación de retención 98–99
descargar incrustaciones de representación datos homogeneos 101
palabras 190 jerárquica giro_horizontal 139
carga de aprendizaje 8 Formato HSV (valor de saturación de
incrustaciones en tono) 6
modelos 191 Biblioteca Hyperas 264
Buen compañero, Ian 305 hiperóptico 264
GPU (procesamiento de hiperparámetros
gráficos optimizando 263–264
unidades) resumen 98
instalando en AWS 350 Afinación 114–115
instancias, en AWS 346– hiperplanos 15
350 visión general 20 espacio de hipótesis 59,72,319
seleccionando 66–67
apoyo, instalación en yo
Ubuntu 342–343
máquinas de aumento de IDSIA 17
gradiente ILSVRC (ImageNetDesafío de
16–17 reconocimiento visual a gran escala)
descenso de 21
gradiente 167 clasificación de imágenes 11
propagación de gradiente datos de imagen 36–37,319
22 optimización basada en segmentación de imágenes 94
gradientes tarea de clasificación de imágenes 262
46–52 ImageDataGenerator clase 135,
algoritmo de 139,147
retropropagación51– ImageNet clase 17,145,281imágenes
52 ediciónvectores de concepto para297–
derivados, definidos 47–48 298
gradientes 48 volteando 139
estocásticodescenso de generando con variacional codificadores
gradiente48–51 automáticos296–304
gradientes 48 vectores de concepto de imagen
Gram matriz 288 edición 297–298
gráficos, acíclicos dirigidos resumen 296
de capas 242–246 muestreo de espacios latentes de 296–297
grafviz 257,340–341 bloques de inicio 59
Tumbas, Alex 271 Módulos de inicio 235,
muestreo codicioso 272 242–244,281
verdad básica 96 argumento include_top 145
GRU (unidad recurrente cuellos de botella de información 80,84
cerrada)capas 202– destilación de información
204,215 tubería 166
fugas de información 97
estado inicial 196
H datos de entrada 6–7,58,95
argumento input_shape 145
transcripción manuscrita 11 entrada_tensor 237 instalando
hardware 20–21 CUDA 342
colisiones hash 183 cuDNN 342
HDF5 340
mapas de calor
de activación de
clase,visualizante 172–
176
resumen 160
rango de cambio de altura 139
Con licencia para
API de Keras 234–248
Keras 343–344,350
gráficos
AbiertoBLAS 341
acíclicos
OpenCV 341
dirigidos
Paquete científico de capas
de Python en 242–246
Ubuntu 341 explorando 338
TensorFlow API
343 Theano en funcionales
Ubuntu 343 236–
Intel 22 238implement
intermedioactivaciones, ando
visualizando DeepDream
160-166 inversiones en 281–286
en aprendizaje instalando
profundo 343–
22–23 344,350
comando ipython 349 compartir el peso
de la capa 246–
j 247 modelos
como capas 247–
aprendizaje de 248 modelos de
características entradas
conjuntas 18 múltiples 238–
Cuadernos Jupyter 240 modelos
65 multisalida
configurando 349–350 240–242
resumen 345 transfere
ejecutándose en ncia
instancias de de
GPU de AWS estil
instalar Keras o
350 neur
configurando la al
GPU de AWS en
instancias 289
346– –
350configurar 295
puerto local capas
reenvío 350 recurrentes en
usando desde 198–202usando
navegadores devoluciones
locales de llamada
350–351 249–259
usando en AWS 346

k
K80, NVIDIA 21
Plataforma
Kaggleresum
en 16,19,266
práctica en
problemas del
mundo real
usando 337

Con licencia para


ÍNDICE 357

Marco Keras 61–64 Red LeNet 15 historia de 14–19


CNTK 62 LHC (Gran Colisionador de árboles de decisión
desarrollando con 62–64 Hadrones) 17 16–17aumento de
corriendo 66 aprendizaje permanente 333– gradiente
TensorFlow 62 335 máquinas 16–17
Teano 62 transformaciones lineales 72 métodos del núcleo 15-16
Biblioteca Keras 27 generalización local,extremo Redes neuronales 14–15,17
keras.aplicacionesmódulo 145 generalización vs. 327– modelado probabilístico
módulo keras.callbacks 249, 329 14
251 reenvío de puerto bosques aleatorios
keras.preprocesamiento.imagen local,configurando 16-17representaciones
135 350 de aprendizaje
métodos del núcleo 15–16 algoritmo de regresión de datos 6–
truco del núcleo 15 logística 85 8modelos, riesgo de
Validación de K-fold, iterada logreg (logísticaregresión) 14 antropo-
registra el argumento 251 morphing 325–327
con arrastramiento 99-
Parámetro retrospectivo 230 overfitting y underfitting
100
pasos de tiempo retrospectivos 104–110
Kingma, Diederik pág. 298
210 agregando abandono
Krizhevski, Alex 20
función de pérdida 109–110agregando peso
L 10,29,58,60,113 regularización 107–108
meseta de pérdida 250 reduciendo el tamaño de
valor de pérdida 96 la red
104–107
Lovelace, Ada 5 flujo de trabajo de 111–115,
22 LSTM (largo a corto plazo
Regularización L1 107 LeakyReLU capa 308 memoria)58,202–204 generar
Regularización L2 107 LeCun, Yann 15,17 texto con 271–279
etiqueta 27,96 generación de datos de
capa lambda 301 secuencia 272
modelos de lenguaje historia de las redes recurrentes
muestreo de 276–278 generativas 271
entrenamiento 276–278 implementarpersonaje-
última capaactivación generación de texto de
113 espacios latentes nivel 274–279
de imágenes, muestreo de estrategia de muestreo 272–274
296–297 resumen 20,269
resumen 270
compatibilidad de capas 59 METRO
representaciones en capas
aprendizaje 8 aprendizaje
capas automáticoautomatizado3
diferenciable 332 32–333
gráficos acíclicos enfoques básicos 213–215
dirigidos de ramas de 94–96aprendizaje
242–246 reforzado
módulos de inicio 95–96
242–244 aprendizaje autosupervisado 94–
residualconexiones 95
244–246 aprendizaje supervisado 94
congelación 150 aprendizaje no supervisado 94
modelos como 247–248 preprocesamiento de datos 101–103
resumen 8,58–59 aprendizaje profundo frente a 17–18
recurrente evaluación de modelos de 97–100
en Keras 198–202 elección de protocolos de
apilamiento 217–219 evaluación 100
descongelar 154 conjuntos de prueba 97–100
reparto de peso 246–247 conjuntos de entrenamiento 97–
preentrenamiento por capas 100
Con licencia para
conjuntos de validación 318–319
97–100 ensamblaje de
ingeniería de conjuntos de
funciones101–103 datos111–
función de aprendizaje 112
101–103 elección del
protocolo de
evaluación
112 elegir
medidade
éxito 112
definición de
problemas
111–112
desarrollo de
modelos 113–
114
preparandodatos
112–113modelos
de regularización
114–115
ajuste de
hiperparámetro
s114–115
Ver tambiénaprendizaje
no automático
MAE (error absoluto
medio)
87,91,212,32
0
biblioteca Matplotlib
33,74,349 matrices
(tensores 2D) 31–
32operación máxima 40
operaciones de
agrupación
máxima127–
129
MaxPooling1D capa 226,231
MaxPooling2D capa 120,122,
127
error_cuadrado_medio 73
capacidad de memorización 104
métricas 29
métricas, registro 249
Kit de herramientas
cognitivas de
Microsoft.
VerCNTK
Mikolov, Tomás 188

Con licencia para


358 ÍNDICE

mini-lote 96 MSE (error cuadrático medio) datos vectoriales 35


SGD de mini lotes (descenso 77,87,91,241,320 vectores (tensores 1D) 31
de gradiente clasificaciones multiclase 78– datos de vídeo 37
estocástico de mini 84 optimización basada en
lotes) 49 redes multicabezal 59 gradientes46–52
Minsky, Marvin 12 modelos de entradas múltiples retropropagación
conjunto de datos MNIST 238–240 algoritmo 51–52
27,68 clasificación multietiqueta derivados 47–48
modelo de puntos de 78,96, gradientes 48
control 249 320 gradiente
Modelo clase 162 entradas multimodales 234 estocástico
modelo profundidad 8 modelos multisalida 240–242 descenso 48–51
parcela modelo 258
función model.fit() 249 norte
función modelo.fit_generator() Keras 61–64
249 regularizando 114–115 N clases 84
Devoluciones de llamadas entrenamiento
Algoritmo bayesiano ingenuo 14
de 192–195
ingenuo_añadir 39
ModelCheckpoint usando las
Instituto Nacional de Normas y Tecnología.
250 devoluciones de
VerNIST
modelos llamada de
atributo ndim 31
patrones de arquitectura Keras
Sistemas Nervana 22
260–263 249–259
normalización por usando TensorBoard capas neurales 22 Redes neuronales
lotes260–261 249–259subrutinas anatomía de 58–60
separable en modulares, reutilización capas 58–59
profundidad 333–335 funciones de pérdida 60
convolución 261–263 módulos, inicio 242–244 modelos59–60
conexiones impulso 50 optimizadores 60
residuales235– Ley de Moore 21,317 clasificaciones binarias 68–77
236,244–246 avances en 17 preprocesamiento de
como capas 247–248 datos para
como programas 330–332 101–102
definición manejo de valores faltantes 102
191 normalización de valores 101–102
desarrolland vectorización 101 representaciones
o de datos para
lograr poder estadístico 31–37
113–114 tensores 3D 32
determinación de la lotes de datos 34–35ejemplos de
capacidad 114 datostensores
montaje 264–266 35
evaluando 192–195 de dimensiones
optimización de superiorestensores 32
hiperparámetros datos de imagen 36–37
263–264 atributos clave de los tensores32–33
idioma manipulando tensores en Numpy 34
muestreo de 276–278 matrices(tensores 2D)31–32
entrenamiento 276–278 escalares (tensores 0D)31datos de
CARGANDO secuencia 35–36
INTEGRACIONES DE datos de series temporales 35–36
GUANTES
en 191
aprendizaje automático,
riesgo de
antropomorfizando 3
25–327
multientrada 238–240
multisalida 240–242
Con licencia para
CNTK 62 aprendizaj
desarrollando con 62–64 e no
TensorFlow 62 automático
Teano 62 ,
clasificaciones líneas de base 212–
multiclase 213
78–84 problemas no estacionarios
regresión 85– 111
91configurar normalización de lotes260–
estaciones de 261
trabajo normalización de valores 101–
65–67 102
GPU para el matrices numpy 28,31
aprendizaje Biblioteca
profundo numpy
66–67 ,
Cuadernos manipu
Jupyter 65 landote
ejecutar trabajos nsores
en la nube 66 en 34
ejecutando Keras matriz numpy 31
66 Tensores numpy 53
operaciones nvidia
tensoriales 38– 20,66
45
radiodifusi
ón 39–40
punto 40–42
elemento-sabio
38–39
interpretación
geométrica
de 43–44
interpretación
geométrica de
aprendizaje
profundo 44–
45
reorganización 42–43
transferencia de
estilo neural 287–
295pérdida de
contenido 288
en Keras 289–295
pérdida de estilo 288–289
N-gramos 180
NIST
(Nacional
Instituto
de
Estándare
sy
Tecnologí
a) 27
función de no
linealidad72

Con licencia para


ÍNDICE 359

O resumen 135–138 redes neuronales recurrentes


incrustaciones190-191 196–224,319,321–322
detección de objetos 94 convenciones preentrenadas básicoaprendizaje
función objetivo 10,60 143–159 automático
Principio de la navaja de extracción de Acercarse 213–
Occam 107octavas 281–282 características1 4 3 – 215
codificación one-hot 1 5 2 con aumento de datos bidireccional 219–222
de personajes 181–183 combinando con
149–152
de palabras 181–183 convenciones 228–
sin aumento de datos147–
resumen 79,84,101 231primera línea de
documentación en línea, 149
base recurrente
Keras sintonia FINA 152– 215–216
338 158con pequeños generativo, historia de 271
optimización 22,50,104,113, conjuntos de datos 159 Capas GRU 202–204
263–264 redes preentrenadas130,143 capas LSTM202–204
argumento optimizador incrustaciones de palabras aprendizaje no
11,29,58, preentrenadas automático
73 184 líneas de base 212–
optimizadore modelado probabilístico 14 213preparación de datos
s60 distribución de probabilidad 80 para 210–212 capas
producción problemas, definiendo 111– recurrentes en Keras
clases 77 198–202
resumen 95 112procesamiento de
secuencias con apilar capas recurrentes 217–
tensor 237 219
sobreajuste conexiones 225–231
utilizando la deserción
agregando la deserción convolución 1D para
recurrente paralucha
109–110 agregando secuenciadatos 225–
contra el sobreajuste
regularización de peso 226 216–217
107–108 agrupación 1Dpara datos de ReducirLROnPlateau devoluciones de
reduciendo el tamaño secuencia 226 llamada250–251
de la red104– combinando con recurrente regresión 60,85–91,320
107 redes neuronales para pérdida de
utilizando la deserción procesar secuencias regularizaciónfunción
recurrente paralucha largas 228–231 300
216–217 implementando convnets modelos de regularización114–115
1D226–227 aprendizaje por refuerzo 95–
PAGS programa subrutinas 334 96relu (unidad lineal
programa de síntesis 331 rectificada) 71
relleno 125–126 PyCharm 65 representaciones
capas parametrizadas 10 biblioteca pydot 257 extrayendo 28
parámetros visión general 6
ajustando 249 pydot-ng 341
Pitón tensores de remodelación 42–43
resumen 97 conexiones residuales 235
particiones 99 instalar suite científica en
mapa de respuesta 124
contraseña () comando Ubuntu 341
argumento return_sequences
349 PCA (componente resumen 19 198
principal paquete python-pip 341 reutilización 23
análisis) 255
Pichai, domingo 22 q diferenciación de modo
inverso52
Formato RGB (rojo-verde-azul) 6
pipa 350 Optimizador RMSProp 53,73,77,
parcela_modelo 258 135,155,222
código de trazado 156 modelo de preguntas y RNN (neural recurrente
circunvoluciones respuestas 238 red) 196
puntuales243 agrupación 1D, rango_de_rotación 139
para datos de secuencia R
226
método de predicción predicciones 83 datos 101–103,135–138
76,83,147 preparandodatos 112– para redes neuronales101–102
error de predicción 95–96 113 preprocesamiento
Con licencia para
bosques aleatorios 16–17 S
datos aleatorios aleatorios
100aleatoriedad 272 eje de muestras 34
rango 31 muestras
abandono recurrente 207,216 dimensión 34
capas recurrentes, muestreo
bidireccional del
207 idioma
model
os276–
278

Con licencia para


360 ÍNDICE

Función de respuesta
muestreo (continuación) softmax 28,80,84,273,320
inteligente, Google
desde espacios latentes de datos de sonido 319
271
imágenes296–297 sparse_categorical_crossentropy
vector de sonrisa 297
estrategias272– 83–84
274Preservador de cordura, patrones espacialmente jerárquicos123
arXiv 338regresión escalar reconocimiento de voz 11
86,96 directorio ssl 348 apilar capas
tensor escalar 31 recurrentes
escalares (tensores 0D) 31 217–219
implementación poder estadístico, desarrollando modelos con
esquemática, de 113–114
GAN 307 pasos_por_epoch 136
Schmidhuber, Jürgen 202 estocásticodescenso de gradiente.
Scikit-Learn 63 VerEURmuestreo estocástico
ciencia ficción 284,341 272
aprendizaje autosupervisado estocasticidad 272,308
94–95 circunvoluciones zancadas 127
selu función 261 zancadas 125
SeparableConv2D capa 261, función de estilo288
321 pérdida de estilo 288–289 subrutinas,
hiperplano de separación reutilizando modular
15datos de secuencia 333–335
generar 272 aprendizaje supervisado 94
resumen 35–36 SVM (máquina de vectores de soporte) 15
generación de secuencias 94 IA simbólica 4,12
secuencia de predicción 60 diferenciación simbólica 52 predicción del
secuencias, procesamiento con árbol de sintaxis 94 Szegedy, Christian
convnets 225–231 235
convolución 1D para
secuenciadatos 225– T
226
Agrupación 1D para tanh activación 77
datos de secuencia objetivo 95
226 fuga temporal 100
combinando con aprendizaje supervisado temporalmente95
recurrenteRedes Aplicaciones de TensorBoard233,
neuronales 228–231 249–259
implementando convnets Visualización de TensorFlow
1D226–227 marco 252–258
Clase secuencial 63,248 tensores
modelo secuencial dimensiones superiores 32 atributos
150,234SGD (gradiente clave de 32–33
estocástico manipular en Numpy 34operaciones
descenso) 48–51,60 de 38–45
aprendizaje superficial 8 radiodifusión39–40
LSTM compartido 247 punto 40–42
cortante_rango 139 elemento sabio 38–39interpretación
mostrar_formas opción 258 geométrica
barajado, validación iterada de de 43–44
K-fold interpretación geométrica de
ción con 100 Siamés aprendizaje profundo 44–45
LSTM modelo 247 función remodelando 42–43
sigmoidea 71,86,320
Simonian, Karen 143
SimpleRNN capa 198,322
etiqueta única
clasificación categórica 320
clasificación multiclase 78
ventanas correderas 124
Con licencia para
historia de las 133–135
remodelando 42
redes
rebanar 34
recurrentes
Ver
generativas
tambiéntensores
271
de datosequipos
implementando
de prueba 97–
nivel de
100
personaje
validación de
generación
retención 98–99
de texto
validación iterada
274–279
de K-fold
estrategia de muestreo 272–
con barajar 100
274
Validación de plegado en K 99
conversión de
datos de texto
texto a voz 12
180-195,319
Teano
descargando
instalar en
texto sin
Ubuntu 343
procesar
resumen 23,62
188–195
datos de series de tiempo 35-
uno-
36,319
calientecodif
pasos de tiempo 210
icación de
TITAN X, NVIDIA 21
palabrasy
incrustaci
personajes
ón de
181–183
fichas
incrustaciones de palabras 184–
180
195
tokenizaci
definición de
ón de
modelos 191
datos,
descargar GloVe
palabra
word
incrustaci
incrustaciones
ones 189–190
190 aprendizaje
pérdida de
con incrustación
variación total
capas 185–187
291
CARGANDO
TPU (unidad de
INTEGRACIO
procesam
NES DE
iento de
GUANTES EN
MODELOS tensores)
191 21
preprocesamiento 190–191 atributo
preentrenado 188 entrenable
150
tokenización de
capacitaci
datos 189-
ón
190entrenar y
convnets en
evaluar
pequeños
modelos
conjuntos
192–195 texto,
de datos
generando con
130–142
LSTM
constru
271–279
yen
generación de
do
datos de
rede
secuencia
s
272

Con licencia para


ÍNDICE 361

formación, edición 297– incrustaciones de palabras 184–195


convencionesen 298muestreo de definición de modelos 191
pequeñoconjuntos latenteespacios descargar GloVe word
de datos de imágenes 296–297 incrustaciones 190
(continuación) puntuaciones de validación 100 evaluación de modelos
Preprocesamiento conjuntos de validación 97–100 192–195aprendiendo
de datos135– validación de retención 98– incrustar capas
138 99validación iterada de K- 185–187
descargando fold CARGANDO
datos131–133 con barajar 100 INTEGRACIONES DE
relevancia para datos Validación de plegado en K GUANTES EN
pequeños problemas 99 MODELOS 191
130–131 sobreajuste 97 preprocesamientoincrustac
utilizando el aumento de resumen 73 iones190–191
datos138–142 argumento de tokenización de datos 189-190
interrumpir 249 validación_datos 74, modelos de
modelos de lenguaje 276– 137 entrenamiento1 9 2 –
278 argumento de 1 9 5 usando una palabra
modelos 192–195 pasos_validación 137 valores preentrenada
bucle de entrenamiento manejo faltante 102 incrustaciones 188
11,46 normalizando 101- vectores de palabras 184
juegos de entrenamiento 97– 102problema del gradiente Algoritmo Word2vec 188
100 de fuga espacio de incrustación de palabras 185
validación de retención 98– 202 índice_de_palabras 69
99validación iterada de K- Vapnik, Vladímir 15 flujo de trabajo de aprendizaje
fold datos vectoriales 35,319 automático 111–
con barajar 100 regresión vectorial 96 115,318–319
Validación de plegado en K vectorización 101 ensamblaje de conjuntos de
99 datos vectorizados 69 datos 111–112 elección de
variable tren_etiquetas27,68 implementaciones vectorizadas evaluaciónprotocolo
traducción- 38 112
invariantepatrones vectorizar texto 180 elección de la medida del
123,321 vectores (tensores 1D) 31 éxito 112
transposición 43 versatilidad 23 definición de problemas 111–112
Prueba de Turing 5 vi 350 desarrollo de modelos 113–114
Turing, Alan 5 preparando datos 112–113
redes de dos ramas 59
Tyka, Mike 280,306
tu
datos de video modelos de regularización 114–115
37,319
conceptos visuales 160 ajuste de hiperparámetros
ubuntu visualizante 114–115
instalando Keras en 343–344 filtros convnet 167–172 flujos de trabajo 18
instalando python cientifico aprendizaje de convnet estaciones de trabajo,
suite en 341 160–176 mapas de calor de configuración 65–67
instalando Theano en activación de clases Cuadernos Jupyter 65
343configurar el soporte 172–176 ejecutar trabajos en la nube
de GPU activaciones intermedias 66 ejecutando Keras 66
342–343 160–166 selección de GPU 66–67
desajuste 104–110 datos volumétricos 319 escribir devoluciones de
agregando la deserción llamada 251–252
109–110 agregando W
regularización de peso X
107–108
reduciendo el tamaño descongelar capas 154 aprendizaje no supervisado 94
de la red104– Estación de trabajo Unix
107 65
Con licencia para
V pérdida de peso 107 excepción 244,248
regularización de peso, Biblioteca XGBoost 19,337
VAE (autocodificadores agregando 107–
variacionales), 108distribución del peso de
generación de imágenes las capas Y
con 296–304 246–247
vectores de concepto de esquemas de inicialización de operador de rendimiento 136
imagen peso 22
argumento de pesos, VGG16 Z
58,145
pesos, capas 10 Zisserman, Andrés 143
Welling, máximo 298 zoom_rango 139
ancho_desplazamiento rango
139

Con licencia para


TÍTULOS DE MANEJO RELACIONADOS

Aprendizaje automático con TensorFlow


por Nishant Shukla
ISBN: 9781617293870
325 páginas, $44.99
diciembre 2017

El libro rápido de Python, tercera edición


por Noemí Ceder
ISBN: 9781617294037
400 páginas, $39.99
diciembre 2017

R en acción, segunda edición


Análisis de datos y gráficos.con
Rpor Robert I. Kabacoff
ISBN: 9781617291388
608 páginas, $59.99
mayo 2015

Ciencia de datos práctica con R


de Nina Zumel y John Mount
ISBN: 9781617291562
416 páginas, $49.99
Marzo del 2014

Para obtener información sobre pedidos, vaya


awww.manning.com
Con licencia para
PYTHON/APRENDIZAJE AUTOMÁTICO
Para descargar su libro
Aprendizaje profundocon electrónico gratuito en formato
PDF, ePub y Kindle, los

pitón
propietarios de este libro deben
visitarwww.manning.com/bo
oks/deep-learning-with-
François Chollet python

M
El aprendizaje automático ha progresado notablemente
en los últimos años. Pasamos de un reconocimiento de
voz e imagen casi inutilizable a una precisión casi

E
humana. fuimos de
máquinas que no pudieron vencer a un jugador serio de Go,
hasta derrotar a un campeón mundial. Detrás de este
progreso está el aprendizaje profundo, una combinación de

T
avances de ingeniería, mejores prácticas y teoría que permite
una gran cantidad de inteligencia inteligente que antes era
imposible.aplicaciones
Aprendizaje profundo con Pythonpresenta el campo de profundo

R
aprendizaje utilizando el lenguaje Python y la potente biblioteca Keras.
Escrito por el creador de Keras e investigador de IA de Google
FrançoisChollet, este libro construye tu comprensiónmediante
explicaciones intuitivas y ejemplos prácticos. Explorará

O
conceptos desafiantes y practicará con aplicaciones en
visión por computadora, procesamiento de lenguaje natural
y modelos generativos. Cuando termine, tendrá el
conocimiento y las habilidades prácticas para aplicar el
aprendizaje profundo en sus propios proyectos.

Qué hay adentro


● Aprendizaje profundo desde los primeros principios
● Configuración de su propio entorno de aprendizaje
profundo
● Clasificación de imágenesmodelos
● Aprendizaje profundo para texto y secuencias
● Transferencia de estilo neuronal, generación de texto y
generación de imágenes.

Los lectores necesitan habilidades intermedias de Python. No


se requiere experiencia previa con Keras, TensorFlow o
aprendizaje automático.

François Cholletes investigador de inteligencia artificial en Google


Brain Teamy autor de la biblioteca de aprendizaje profundo
de Keras.
“bombo
Cierra la brecha entreel
yun sistema de
VER INSERTAR
funcionamiento. ”
aprendizaje profundo en

—Peter Rabinovitch, Akamai

La explicación más clara de aprendizaje profundo


que he encontrado... fue un placer leerlo.

“ para
El mejor recurso
convertirse en un
—Richard Tobias, Cefasónicos
maestro de
””
Keras y aprendizaje profundo.


Una excelente prácticatítulo introductorio, —Claudio
RodríguezGrupo de
con gran profundidad y amplitud. medios de Cox
—David Blumenthal-BarbyBabel

MANEJO $49.99 / Puede $65.99[INCLUYE EL LIBRO ELECTRÓNICO]

francoisC h o l l e t  
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
MANEJO  
 T
Con licencia para 
<null>
 
Aprendizaje profundo con Python
Con licencia para 
<null>
Con licencia para 
<null>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
Aprendizaje 
profundo 
con Python 
FRANÇOIS CHOLLET
Con licencia para 
<null>
 
Para obtener información en línea y solicitar este y otros libros de Manning, visite 
www.manning
Con licencia para 
<null>
 
 
 
 
 
 
 
 
 
 
 
 
 
  
contenidos 
breves 
PARTE1F
 
FUNDAMENTALES DE PROFUNDIDADAPRENDIZAJE
Con licencia para 
<null>
 
 
 
v
Con licencia para 
<null>
Con licencia para 
<null>
 
 
 
 
 
 
 
 
 
 
 
 
 
contenido 
prefacio xiii 
expresiones de 
gratitudXV sobre este 
libro xv
Con licencia para 
<null>
 
viii

También podría gustarte