Sunteți pe pagina 1din 33

Antes de comenzar: los

bloques de construcción
matemáticos de redes
neuronales

Este capítulo trata de


 Un primer ejemplo de una red neural
 Tensores y sus operaciones
 Cómo aprender a través de las redes neuronales de
retropropagación y descenso de gradiente

La comprensión profunda de aprendizaje requiere estar familiarizado con muchos


conceptos matemáticos simples: tensores, operaciones tensor, diferenciación, descenso de
gradiente, y así sucesivamente. Nuestro objetivo en este capítulo será construir su intuición
acerca de estas nociones sin conseguir demasiado técnico. En particular, vamos a alejarse
de la notación matemática, que puede ser una experiencia desagradable para las personas
sin ningún tipo de fondo y las matemáticas no es estrictamente necesario explicar bien las
cosas.
Para añadir un poco de contexto para tensores y descenso de gradiente, vamos a
comenzar el capítulo con un ejemplo práctico de una red neuronal. A continuación vamos
a repasar todos los nuevos conceptos

Con licencia para <null>


26 CCAPÍTULO 2Antes de comenzar: los bloques de construcción matemáticos de redes neuronales
25
que se han introducido de punto por punto. Tenga en cuenta que estos conceptos serán
esenciales para que usted entienda los ejemplos prácticos que vendrán en los siguientes
capítulos!
Después de leer este capítulo, usted tendrá una comprensión intuitiva de trabajo de redes
neuronales cómo, y serás capaz de pasar a aplicaciones prácticas -que se iniciará con el
capítulo 3.

Con licencia para <null>


27
Un primer vistazo a una red neuronal

2.1 Un primer vistazo a una red neuronal


Echemos un vistazo a un ejemplo concreto de una red neuronal que utiliza la biblioteca de
Python Keras para aprender a clasificar los dígitos escritos a mano. A menos que ya tenga
experiencia con Keras o bibliotecas similares, que no va a entender todo acerca de este primer
ejemplo de inmediato. Es probable que ni siquiera han instalado Keras todavía; esta bien. En
el siguiente capítulo, vamos a revisar cada elemento en el ejemplo y los explicamos en detalle.
Así que no se preocupe si algunos pasos parecen arbitrarias o aspecto como magia para usted!
Tenemos que empezar por alguna parte.
El problema que estamos tratando de resolver aquí es clasificar las imágenes en escala de
grises de dígitos escritos a mano (28 × 28 píxeles) en sus 10 categorías (0 a 9). Vamos a utilizar
el conjunto de datos MNIST, un clásico en la comunidad de aprendizaje de máquina, que ha
existido casi tanto tiempo como el propio campo y ha sido estudiado intensamente. Es un
conjunto de 60.000 imágenes de entrenamiento, además de 10.000 imágenes de prueba,
reunidos por el Instituto Nacional de Estándares y Tecnología (NIST en MNIST) en la década
de 1980. Se puede pensar en “resolver” MNIST como el “Hello World” de profundo
aprendizaje que es lo que se hace para comprobar que los algoritmos están funcionando como
se esperaba. Como convertirse en un practicante de aprendizaje de máquinas, verá MNIST
llegar una y otra vez, en trabajos científicos, publicaciones de blog, y así sucesivamente. Se
pueden ver algunas muestras MNIST en la figura 2.1.

Nota sobre las clases y etiquetas


En el aprendizaje de máquina, una categoría en un problema de clasificación se llama
una clase. Los puntos de datos se denominan muestras. La clase asociada con una
muestra específica se denomina una etiqueta.

Figura 2.1 los dígitos muestra MNIST

No es necesario tratar de reproducir este ejemplo en su máquina hace un momento. Si se desea,


primero debe configurar Keras, que se cubre en la sección 3.3.
El conjunto de datos MNIST viene precargado en Keras, en la forma de un conjunto de
cuatro arrays NumPy.
Listing 2.1 Cargando el conjunto de datos MNIST en Keras
de keras.datasets mnist importación
(Train_images, train_labels), (test_images, test_labels) = mnist.load_data ()

Con licencia para <null>


28 CCAPÍTULO 2Antes de comenzar: los bloques de construcción matemáticos de redes neuronales
train_images y train_labels forman el conjunto de entrenamiento,
los datos que el modelo va a aprender. El modelo a continuación,
se probó en el aparato de prueba, test_images y test_labels.
Las imágenes se codifican como arrays NumPy, y las etiquetas son una serie de dígitos, que van
de 0 a 9. Las imágenes y etiquetas tienen una correspondencia uno-a-uno.
Echemos un vistazo a los datos de entrenamiento:
>>> train_images.shape
(60000, 28, 28)
>>> len (train_labels)
60000
>>> train_labels
array ([5, 0, 4, ..., 5, 6, 8], dtype = uint8)

Y aquí está la prueba de los datos:


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

El flujo de trabajo será el siguiente: En primer lugar, vamos a alimentar la red neuronal los
datos de entrenamiento, y train_images train_labels. La red será entonces aprender a asociar
imágenes y etiquetas. Por último, vamos a solicitar a la red para producir predicciones para
test_images, y vamos a verificar si estas predicciones coinciden con las etiquetas de
test_labels.
acumulación de permitir que la red de nuevo, recuerda que no se espera que entender todo
acerca de este ejemplo todavía.
Listing 2.2 La arquitectura de red
de Keras importar modelos
de Keras capas de
importación
red = models.Sequential () network.add (layers.Dense (512, la activación
= 'relu', input_shape = (28 * 28,))) network.add (layers.Dense (10,
activación = 'softmax'))

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


procesamiento de datos que se puede considerar como un filtro para los datos. Algunos datos
que entra, y sale en una forma más útil. Específicamente, las capas de extraer las
representaciones de los datos alimentados en ellos-es de esperar, las representaciones que son
más significativo para el problema en cuestión. La mayoría de aprendizaje profundo consiste
en encadenar capas juntas simples que implementarán una forma de destilación de datos
progresiva. Un modelo de profundidad de aprendizaje es como un colador para el
procesamiento de datos, hecho de una sucesión de cada vez más refinados filtros de los datos
capas.

Con licencia para <null>


29
Aquí, nuestra red consiste en una secuencia de dos capas densas, que están conectados
densamente (también llamado totalmente conectados) capas neuronales. El segundo (y último)
capa es una capa softmax 10 vías, lo que significa que devolver una matriz de 10 puntuaciones
de probabilidad (sumadores a 1). Cada puntuación será la probabilidad de que la imagen dígito
actual pertenece a una de nuestras clases de 10 dígitos.
Un primer vistazo a una red neuronal

Para hacer que la red listo para el entrenamiento, tenemos que elegir tres cosas más, como
parte de la etapa de compilación:
 Una función de pérdida-Como la red será capaz de medir su rendimiento en los datos
de entrenamiento, y por lo tanto cómo va a ser capaz de dirigir sí en la dirección
correcta.
 un optimizador-El mecanismo a través del cual la red se actualizará en base a los datos
que ve y su función de pérdida.
 Indicadores para el monitor durante el entrenamiento y las pruebas-Aquí, sólo le
importe por la precisión (la fracción de las imágenes que fueron clasificados
correctamente).
El propósito exacto de la función de pérdida y el optimizador se hará claro a lo largo de los
próximos dos capítulos.
Listing 2.3 El paso de compilación
network.compile (optimizador = 'rmsprop', pérdida =
'categorical_crossentropy', las métricas = [
'exactitud'])

Antes del entrenamiento, vamos a preproceso de los datos mediante la remodelación en la


forma de las Espera de red y la ampliación de tal manera que todos los valores están en el
intervalo [0, 1]. Anteriormente, nuestras imágenes de entrenamiento, por ejemplo, se
almacenan en una matriz de forma (60 000, 28, 28) de tipo uint8 con valores en el intervalo
[0, 255]. Nos transformamos en una matriz float32 de forma (60000, 28 * 28) con valores
entre 0 y 1.
Añadir 2,4 Preparación de los datos de imagen
train_images = train_images.reshape ((60000, 28 * 28))
train_images = train_images.astype ( 'float32') / 255
test_images = test_images.reshape ((10000, 28 * 28))
test_images = test_images.astype ( 'float32') / 255

También tenemos que codificar categóricamente las etiquetas, de un paso que explican en el
capítulo 3.
Añadir 2,5 Preparación de las etiquetas
de keras.utils to_categorical importación

train_labels = to_categorical (train_labels)


test_labels = to_categorical (test_labels)

Con licencia para <null>


30 CCAPÍTULO 2Antes de comenzar: los bloques de construcción matemáticos de redes neuronales
Ahora estamos listos para entrenar la red, que a su Keras se realiza a través de una llamada a
la red del ajuste método que se ajustan al modelo de sus datos de entrenamiento:
>>> network.fit (train_images, train_labels, épocas = 5, batch_size = 128)
época 1/5
60000/60000 [==============================] - 9s - pérdida: 0.2524 - 0.9273
ACC:
época 2/5
51328/60000 [========================> .....] - ETA: 1s - pérdida: 0,1035 -
ACC: 0,9692
Dos cantidades se muestran durante la formación: la pérdida de la red a través de los datos de
entrenamiento, y la exactitud de la red a través de los datos de entrenamiento.
Nos llegar rápidamente a una precisión de 0,989 (98.9%) en los datos de entrenamiento.
Ahora vamos a ver que realiza el modelo bien en la prueba, también:
>>> test_loss, test_acc = network.evaluate (test_images, test_labels)
>>> print ( 'test_acc:', test_acc)
test_acc: 0,9785

La exactitud de la prueba-conjunto resulta ser 97,8% -que es un poco más baja que la exactitud
conjunto de entrenamiento. Esta brecha entre la precisión y la exactitud de la prueba de
entrenamiento es un ejemplo de un ajuste por exceso: el hecho de que los modelos de
máquinas de aprendizaje tienden a rendir menos en los nuevos datos que en sus datos de
entrenamiento. Sobreajuste es un tema central en el capítulo 3.
Con esto concluye nuestro primer ejemplo que acaba de ver cómo se puede construir y
entrenar una red neuronal para clasificar los dígitos escritos a mano en menos de 20 líneas de
código Python. En el siguiente capítulo, voy a entrar en detalles sobre cada pieza en
movimiento que acabamos de vista previa y aclarar lo que está pasando detrás de las escenas.
Usted aprenderá acerca de los tensores, los datos que almacenan los objetos que entran en la
red; operaciones tensor, que las capas están hechas de; y descenso de gradiente, lo que permite
a la red para aprender de sus ejemplos de entrenamiento.

Con licencia para <null>


representaciones de datos para las redes neuronales 31

2.2representaciones de datos para las redes neuronales


En el ejemplo anterior, se partió de los datos almacenados en las matrices multidimensionales
numpy, también llamados tensores. En general, todos los sistemas actuales de aprendizaje de
máquinas utilizan tensores como su estructura de datos básica. Los tensores son fundamentales
para el campo tan fundamental que TensorFlow de Google fue nombrado después de ellos.
Entonces, ¿qué es un tensor?
En su esencia, un tensor es un contenedor de datos numéricos datos desde casi siempre. Por
lo tanto, es un contenedor para los números. Usted puede ser ya están familiarizados con
matrices, que son tensores 2D: tensores son una generalización de matrices a un número
arbitrario de dimensiones (nota que en el contexto de los tensores, una dimensión a menudo
se llama un eje).

2.2.1 Escalares (tensores 0D)


Un tensor que contiene solamente un número se llama un escalar (o tensor escalar, o tensor 0-
dimensional, o tensor 0D). En Numpy, un float32 o número float64 es un tensor escalar (o
matriz escalar). Se puede visualizar el número de ejes de un tensor Numpy a través del atributo
Ndim; un tensor escalar tiene 0 ejes (Ndim == 0). El número de ejes de un tensor también se
llama su rango. Aquí está un escalar Numpy:
>>> numpy importación, como NP
>>> x = np.array (12)
>>> x
array (12)
>>> x.ndim
0

2.2.2 Vectores (tensores 1D)


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

Este vector tiene cinco entradas y así se llama un vector de 5 dimensiones. No se debe
confundir un vector 5D con un tensor 5D! A 5D vector sólo tiene 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). 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 (tales como un tensor 5D), que puede ser confuso a veces. En
este último caso, es técnicamente 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 5D tensor es común
independientemente.

Con licencia para <null>


32 CCAPÍTULO 2Antes de comenzar: los bloques de construcción matemáticos de redes neuronales

2.2.3 Matrices (tensores 2D)


Un conjunto de vectores es una matriz, o tensor 2D. Una matriz tiene dos ejes (a menudo se
refiere a las filas y columnas). Se puede interpretar visualmente una matriz como una
cuadrícula rectangular de números. Esta es una matriz Numpy:
>>> x = np.array ([[5, 78, 2, 34, 0],
[6, 79, 3, 35, 1],
[7, 80, 4, 36, 2]])
>>> x.ndim
2

Las entradas desde el primer eje se llaman las filas, y las entradas desde el segundo eje se
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.4tensores y tensores 3D de dimensiones superiores


Si empaca tales matrices en una nueva matriz, se obtiene un tensor 3D, que se puede interpretar
visualmente como un cubo de números. A continuación se presenta un tensor Numpy 3D:
>>> x = np.array ([[[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 comprimir 3D tensores en una matriz, se puede crear un tensor de 4D, y así sucesivamente.
En el aprendizaje profundo, podrás manipular general tensores que son 0D a 4D, aunque es
posible subir a 5D si procesa los datos de vídeo.

2.2.5 Atributos claves


Un tensor está definida por tres atributos clave:
 Número de ejes (ranking)-Para ejemplo, un tensor 3D tiene tres ejes, y una matriz tiene
dos ejes. Esto también se llama Ndim del tensor en Python librerías 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 el
ejemplo tensor 3D tiene forma (3, 3, 5). Un vector tiene una forma con un solo
elemento, tal como (5,), mientras que un escalar tiene una forma vacía, ().
 Tipo de datos(Normalmente llamado dtype en las bibliotecas de Python): es el tipo de
los datos contenidos en el tensor; por ejemplo, el tipo de un tensor podría ser float32,
uint8, float64, y así sucesivamente. En raras ocasiones, es posible que aparezca un

Con licencia para <null>


representaciones de datos para las redes neuronales 33

tensor carbón. Tenga en cuenta que los tensores de cadena no existen en Numpy (o en
la mayoría de otras bibliotecas), porque los tensores viven en preasignados, segmentos
de memoria contiguas: la mayor, siendo de longitud variable, impediría el uso de esta
aplicación.
Para que esto sea más concreto, vamos a mirar hacia atrás en los datos que procesa en el ejemplo
MNIST. En primer lugar, cargamos el conjunto de datos MNIST:
de keras.datasets mnist importación

(Train_images, train_labels), (test_images, test_labels) = mnist.load_data ()

A continuación, se muestra el número de ejes de los train_images tensor, el atributo Ndim:


>>> print (train_images.ndim)
3

Aquí está su forma:


>>> print (train_images.shape) (60000, 28,
28)

Y este es su tipo de datos, el atributo dtype:


>>> print (train_images.dtype) uint8

Así que lo que tenemos aquí es un tensor 3D de enteros de 8 bits. Más precisamente, es una matriz de
60.000 matrices de 28 × 8 números enteros. Cada uno de tales matriz es una imagen en escala de grises,
con coeficientes entre 0 y 255.
Vamos a mostrar el cuarto dígito en este tensor 3D, usando la biblioteca Matplotlib (parte del
conjunto de Python científica estándar); véase la figura 2.2.
Añadir 2,6 Viendo el cuarto dígito
dígito = train_images [4]
matplotlib.pyplot importación como plt.imshow plt
(dígitos, CMAP = plt.cm.binary) plt.show ()

Figura 2.2La cuarta muestra en nuestro conjunto de datos

Con licencia para <null>


34 CCAPÍTULO 2Antes de comenzar: los bloques de construcción matemáticos de redes neuronales

2.2.6La manipulación de tensores en Numpy


En el ejemplo anterior, se seleccionaron un dígito específico junto con el primer eje utilizando
los train_images sintaxis [i]. Selección de elementos específicos en un tensor se llama tensor
de corte. Echemos un vistazo a las operaciones de tensor sobre el tramo se puede hacer en
matrices numpy.
Los siguientes selecciona ejemplo dígitos # 10 a # 100 (# 100 no está incluido) y los pone
en una matriz de forma (90, 28, 28):
>>> my_slice = train_images [10: 100]
>>> print (my_slice.shape)
(90, 28, 28)

Es equivalente a esta notación más detallada, que especifica un índice inicial y el índice de
parada para el corte a lo largo de cada eje tensor. Tenga en cuenta que: es equivalente a
seleccionar todo el eje:
Equivalente a la
>>> my_slice = train_images [10: 100,:,:] ejemplo anterior
>>> my_slice.shape
(90, 28, 28)También equivalente a la
>>> my_slice = train_images [10: 100, 0:28, 0:28] ejemplo anterior
>>> my_slice.shape
(90, 28, 28)

En general, es posible seleccionar entre dos índices a lo largo de cada eje tensor. Por ejemplo,
con el fin de seleccionar 14 × 14 píxeles en la esquina inferior derecha de todas las imágenes,
hacer esto:
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 con respecto al extremo del eje actual. Con el fin de recortar
las imágenes a los parches de 14 × 14 píxeles centrada en el medio, esto se hace: my_slice =
train_images [:, 7: -7, 7: -7]

2.2.7 los noción de lotes de datos


En general, el primer eje (eje 0, debido a la indexación comienza en 0) en todos los tensores
de datos que van a venir a través de un aprendizaje profundo será el eje de las muestras (a
veces llamada la dimensión de las muestras). En el ejemplo MNIST, las muestras son
imágenes de dígitos.
Además, los modelos de aprendizaje profundo no procesan un conjunto de datos completo
de una vez; más bien, se rompen los datos en pequeños lotes. Concretamente, aquí hay un lote
de nuestros dígitos MNIST, con un tamaño de lote de 128:
lotes = [train_images: 128] Y
aquí está el siguiente lote:

Con licencia para <null>


representaciones de datos para las redes neuronales 35

lote = train_images [128: 256]


y el lote de orden n:
lotes = train_images [128 * n: 128 * (n + 1)]
Al considerar tal tensor un lote, el primer eje (eje 0) se llama eje lote o dimensión del lote.
Este es un término que se encontrará con frecuencia cuando se utilicen Keras y otras
bibliotecas profundas-aprendizaje.

2.2.8Ejemplos del mundo real de los tensores de datos


Vamos a tensores de datos de forma más concreta con unos pocos ejemplos similares a lo que
te vas a encontrar más adelante. Los datos que se va a manipular casi siempre caerá en una de
las siguientes categorías:
 Los datos vectorialestensores -2D de forma (muestras, características)
 TimeSeries datos o datos de la secuenciatensores -3D de forma (muestras, timesteps,
características)
 imágenestensores -4D de forma (muestras, altura, anchura, canales) o (muestras,
canales, altura, anchura)
 Vídeotensores -5D de forma (muestras, marcos, altura, anchura, canales) o
(Muestras, marcos, canales, altura, anchura)

2.2.9Los datos vectoriales


Este es el caso más común. En tal un conjunto de datos, cada punto de datos único puede ser
codificada como un vector, y por lo tanto un lote de datos se codifica como un tensor 2D (es
decir, un conjunto de vectores), donde el primer eje es las muestras de eje y el segundo eje es
el eje características. Vamos a echar un vistazo a dos ejemplos:
 Un conjunto de datos actuarial de personas, donde se cuenta la edad de cada persona,
código postal, y los ingresos. Cada persona puede ser caracterizado como un vector de
3 valores, y por lo tanto un conjunto de datos entero de 100.000 personas se puede
almacenar en un tensor 2D de forma
(100 000, 3).
 Un conjunto de datos de documentos de texto, en el que representamos cada documento
por los cargos de cuántas veces aparece cada palabra en ella (de un diccionario de
20.000 palabras comunes). Cada documento se puede codificar como un vector de
20.000 valores (un cargo por palabra en el diccionario), y por lo tanto todo un conjunto
de datos de 500 documentos se puede almacenar en un tensor de forma (500, 20 000).

2.2.10 Series Temporales de datos o de datos de secuencias


Siempre que el tiempo es importante en sus datos (o la noción de orden de secuencia), que
tiene sentido para almacenarlo en un tensor 3D con un eje de tiempo explícito. Cada muestra
puede ser codificado como una secuencia de vectores (un tensor 2D), y por lo tanto un lote de
datos se codifica como un tensor 3D (véase la figura 2.3).

Con licencia para <null>


36 CCAPÍTULO 2Antes de comenzar: los bloques de construcción matemáticos de redes neuronales

Caracteristi
cas
Las
muestras
timesteps Figura 2.3 Un tensor de datos 3D TimeSeries
El eje de tiempo es siempre el segundo eje (eje de índice 1), por convención. Echemos un
vistazo a algunos ejemplos:
 Un conjunto de datos de precios de las acciones. Cada minuto, almacenamos el precio
actual de la acción, el precio más alto en el pasado minutos, y el precio más bajo en el
pasado minutos. Así, cada minuto se codifica como un vector 3D, todo un día de
operaciones se codifica como un tensor 2D de forma (390, 3) (hay 390 minutos en un
día de la operación), y el valor de datos de 250 días se puede almacenar en un tensor
3D de forma (250, 390, 3). A continuación, cada muestra tendría un valor de los datos
de un día.
 Un conjunto de datos de tweets, en las que codifican cada tweet como una secuencia
de 280 caracteres de un alfabeto de 128 caracteres únicos. En esta configuración, cada
carácter puede ser codificada como un vector binario de tamaño 128 (un vector de todos
ceros excepto para una entrada de 1 en el índice correspondiente al carácter). Entonces
cada tweet puede ser codificada como un tensor 2D de forma (280, 128), y un conjunto
de datos de 1 millones de tweets se pueden almacenar en un tensor de forma (1000000,
280, 128).

2.2.11 Los datos de imagen


Imágenes típicamente tienen tres dimensiones: altura, anchura, y profundidad de color.
Aunque las imágenes en escala de grises (como nuestro dígitos MNIST) tienen un solo canal
de color y por lo tanto podrían ser almacenados en 2D tensores, por convención imagen
tensores están siempre en 3D, con un canal de color unidimensional para imágenes en escala
de grises. Un lote de 128 imágenes en escala de grises de tamaño 256 × 256 por lo tanto podría
ser almacenado en un tensor de forma (128, 256, 256, 1), y un lote de 128 imágenes en color
se podría almacenar en un tensor de forma (128, 256, 256, 3) (véase la figura 2.4).

Los canales de
color

Altura

Las
muestras
Figura 2.4A los datos de imagen 4D
Anchura tensor (convención canales-primeros)

Con licencia para <null>


representaciones de datos para las redes neuronales 37

Hay dos formas de convenciones para imágenes tensores: la Convención canales-last


(utilizado por TensorFlow) y la Convención canales y uno (utilizado por Teano). El marco de
aprendizaje de máquinas TensorFlow, de Google, coloca el eje de profundidad de color al
final: (muestras, altura, anchura, color_depth). Mientras tanto, Theano coloca el eje derecho
profundidad de color después de la eje lote: (muestras, color_depth, altura, anchura). Con la
convención Theano, los ejemplos anteriores se convertirían en (128, 1, 256, 256) y (128, 3,
256, 256). El marco Keras proporciona soporte para ambos formatos.

2.2.12 Los datos de vídeo


Los datos de vídeo es uno de los pocos tipos de datos del mundo real para el que necesitará
tensores 5D. Un video puede ser entendido como una secuencia de tramas, cada trama de ser
una imagen en color.
Debido a que cada marco puede ser almacenado en un tensor 3D (altura, anchura,
color_depth), una secuencia de tramas se puede almacenar en un tensor 4D (marcos, altura,
anchura, profundidad color_), y por lo tanto un lote de diferentes vídeos se puede almacenar
en un tensor 5D de la forma
(Muestras, marcos, altura, anchura, color_depth).
Por ejemplo, un clip de vídeo de YouTube de 60 segundos, 144 × 256 muestreado a 4
imágenes por segundo tendría 240 cuadros. Un lote de cuatro de tales clips de vídeo se
almacena en un tensor de forma (4, 240, 144, 256, 3). Eso es un total de 106,168,320 valores!
Si el dtype del tensor era float32, a continuación, cada valor se almacena en 32 bits, por lo que
el tensor representaría 405 MB. ¡Pesado! Vídeos que encontrar en la vida real son mucho más
ligeros, ya que no se almacenan en float32, y por lo general están comprimidas por un factor
grande (como en el formato MPEG).

Con licencia para <null>


38 CCAPÍTULO 2Antes de comenzar: los bloques de construcción matemáticos de redes neuronales

2.3Los engranajes de redes neuronales: las operaciones tensor


Tanto como cualquier programa de ordenador puede ser en última instancia, reduce a un
pequeño conjunto de operaciones binarias en las entradas binarias (AND, OR, NOR, etc.),
todas las transformaciones aprendidas por las redes neuronales profundas pueden ser
reducidos a un puñado de operaciones tensor aplicado a los tensores de datos numéricos. Por
ejemplo, es posible añadir tensores, los tensores se multiplican, y así sucesivamente.
En nuestro ejemplo inicial, estábamos construyendo nuestra red apilando capas densas en

la parte superior de uno al otro. A Keras miradas de instancia capa como esta:

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 2D tensor-una nueva representación para el tensor de entrada. Específicamente,
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, de entrada) + b)

Vamos a descomprimir esto. Tenemos tres operaciones tensor aquí: un producto de punto
(punto) entre el tensor de entrada y un tensor de nombre W; una adición (+) entre el tensor 2D
resultante y un vector b; y, por último, una operación relu. relu (x) es max (x, 0).

NOTA Aunque esta sección se ocupa en su totalidad con las expresiones de álgebra
lineal, que no encontrará en cualquier notación matemática aquí. Me he dado cuenta
que los conceptos matemáticos pueden ser más fácilmente dominado por los
programadores sin conocimientos matemáticos si están expresados como Python
corta de fragmentos en lugar de ecuaciones matemáticas. Así que vamos a utilizar
código Numpy largo.

2.3.1operaciones elemento a elemento


La operación relu y además son operaciones elemento a elemento: las operaciones que se
aplican de forma independiente para cada entrada en los tensores se está considerando. Este
medio de estas operaciones son altamente susceptibles a paralelo de forma masiva
implementaciones (implementaciones vectorized, un término que proviene de la arquitectura
superordenador procesador de vector desde el periodo 1970-1990). Si desea escribir una
implementación de Python ingenua de una operación de elemento a elemento, se utiliza un
bucle, como en esta aplicación ingenua de una operación relu elemento a elemento: def
naive_relu (x):
assert len (x.shape) == 2 x es un tensor 2D Numpy. x =
x.copy ()Evitar sobrescribir el tensor de entrada.
para i en el rango (x.shape [0]):
para j en el rango (x.shape [1]):
x [i, j] = máx (x [i, j], 0)

Con licencia para <null>


representaciones de datos para las redes neuronales 39

return x

Con licencia para <null>


40 CCAPÍTULO 2Antes de comenzar: los bloques de construcción matemáticos de redes
neuronales

Que haga lo mismo para la adición: x e y son tensores 2D


def naive_add (x, y): assert len
NumPy.
(x.shape) == 2 aserción x.shape ==
y.shape
Evitar sobrescribir el
x = x.copy () para i en el rango tensor de entrada.
(x.shape [0]):
para j en el rango (x.shape [1]): x [i,
j] + = y [i, j] retorno x
Según el mismo principio, se puede hacer elemento a elemento de multiplicación, resta, y así
sucesivamente.
En la práctica, cuando se trata de matrices numpy, estas operaciones están disponibles
como welloptimized funciones integradas de numpy, que a su vez delegar el trabajo pesado a
una básicas de álgebra lineal subprogramas (Blas) aplicación si tiene uno instalado (que
debería). BLAS son de bajo nivel, eficientes rutinas altamente paralelas, tensor de
manipulación que se implementan típicamente en Fortran o C.
Así, en Numpy, se puede realizar la siguiente operación elemento a elemento, y será rápida
ardiente:
importar numpy como NP

z = x + y Además Element-sabia

z = np.maximum (z, 0.) En cuanto al elemento relu

2.3.2 Radiodifusión
Nuestra aplicación anterior ingenua de naive_add sólo es compatible con la adición de los
tensores 2D con formas idénticas. Pero en la capa densa introdujo anteriormente, hemos
añadido un tensor con un vector 2D. ¿Qué ocurre con la adición cuando las formas de los dos
tensores que se añade difieren?
Cuando sea posible, y si no hay ambigüedad, el tensor más pequeña será transmitido para
que coincida con la forma del tensor de mayor tamaño. Radiodifusión consta de dos pasos:
1 Ejes (llamados ejes de transmisión) se añaden al tensor más pequeña para que coincida
con el Ndim del tensor más grande.
2 El tensor más pequeña se repite junto a estos nuevos ejes para que coincida con la
forma completa del tensor más grande.
Echemos un vistazo a un ejemplo concreto. Considere X con forma (32, 10) e Y con forma
(10,). En primer lugar, añadimos un primer eje vacío ay, cuya forma se convierte en (1, 10).
Luego, repetimos y 32 veces al lado de este nuevo eje, de modo que nos encontramos con un
tensor Y con forma de

Con licencia para <null>


Los engranajes de redes neuronales: las operaciones tensor 41
(32, 10), donde Y [i,:] == y para i en el rango (0, 32). En este
punto, podemos proceder a añadir X e Y, debido a que tienen la
misma forma.
En términos de implementación, no se crea un nuevo tensor de 2D, porque eso sería
terriblemente ineficiente. La operación de repetición es completamente virtual: se da a nivel
algorítmico en lugar de en el nivel de memoria. Pero el pensamiento del vector que se repite
10 veces junto a un nuevo eje es un modelo mental útil. Esto es lo que una aplicación ingenua
se vería así: naive_add_matrix_and_vector def (x, y):x es un tensor 2D Numpy. assert len
(x.shape) == 2 aserción len (y.shape) == 1 y es un vector Numpy.
assert x.shape [1] == y.shape
[0] x = x.copy ()

evitar sobrescribir
para i en el rango (x.shape
[0]):
el tensor de entrada.
para j en el rango (x.shape [1]):
x [i, j] + = y [j]
return x

Con la radiodifusión, generalmente puede aplicar operaciones elemento a elemento de dos


tensores si uno tensor tiene la forma (a, b, ... n, n + 1, ... m) y el otro tiene la forma (n, n + 1,
... m). La radiodifusión será entonces sucederá de forma automática para los ejes a través de
n - 1.
El siguiente ejemplo se aplica el funcionamiento máximo elemento en cuanto a dos
tensores de diferentes formas a través de la difusión:
importar numpy como NP
x es un tensor aleatoria con
x = np.random.random ((64, 3, 32, 10))de forma (64,
3, 32, 10). y = np.random.random ((32, 10))
y es un tensor azar
z = np.maximum (x, y)con forma (32, 10).
El z de salida tiene forma (64, 3,
32, 10) como x.
2.3.3 tensor de puntos
La operación de punto, también llamado un producto tensor (que no debe confundirse con un
producto elementwise) es el más común, la operación más útil tensor. Contrariamente a las
operaciones elemento a elemento, que combina las entradas de los tensores de entrada.
Un producto de elemento a elemento se hace con el operador * en Numpy, Keras, Teano,
y TensorFlow. dot utiliza una sintaxis diferente en TensorFlow, pero en ambos Numpy y Keras
se hace usando el operador punto estándar:

Con licencia para <null>


42 CCAPÍTULO 2Antes de comenzar: los bloques de construcción matemáticos de redes neuronales

numpy importación

como np z = np.dot

(x, y)

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


z = x. y

Matemáticamente, ¿qué hace la operación de puntos? Vamos a empezar con el producto


escalar de dos vectores x e y. Se calcula de la siguiente manera:
def naive_vector_dot (x, y): assert len
(x.shape) == 1 x e y son vectores NumPy.
assert len (y.shape) == 1
aserción x.shape [0] == y.shape
[0] z = 0. Para i en el rango
(x.shape [0]):
z + = x [i] * y [i]
z retorno

Usted habrá notado que el producto escalar entre dos vectores es un escalar y que los únicos
vectores con el mismo número de elementos son compatibles para un producto escalar.
También puede tomar el producto escalar entre una matriz x y un vector y, que devuelve
un vector donde los coeficientes son los productos de puntos entre Y y las filas de x. Se
implementa de la siguiente manera:

importar numpy como NP X es una matriz Numpy.


def naive_matrix_vector_dot (x, y): assert len (x.shape)
== 2 y es un vector Numpy.
assert len (y.shape) == 1
aserción x.shape [1] ==
y.shape [0]
La primera dimensión de x debe ser el
z = np.zeros (x.shape [0])misma que la dimensión de 0º y! para i en el
rango (x.shape [0]):
para j en el rango (x.shape [1]):Esta operación devuelve un vector
de z [i] + = x [i, j] * y [j] 0s con la misma forma como y.
z retorno

También se podría reutilizar el código que escribimos anteriormente, que pone de relieve 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)
z retorno

Con licencia para <null>


Los engranajes de redes neuronales: las operaciones tensor 43

Tenga en cuenta que tan pronto como uno de los dos tensores tiene una mayor Ndim de 1,
punto ya no es simétrica, lo que quiere decir que punto (x, y) no es el mismo que el punto (y,
x).
Por supuesto, un producto de punto 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 sólo 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 aplicación
ingenua:def naive_matrix_dot (x, y):

Xy Yassert len (x.shape) == 2 La primera dimensión de x debe ser el


sonassert len (y.shape) == 2 misma que la dimensión de 0º y!
numpyassert x.shape [1] == y.shape [0]
Esta operación devuelve una matrices de
matriz. z = np.zeros ((x.shape [0], y.shape [1])) de 0s con una forma específica. para i
en el rango (x.shape [0]): Repite las filas de x ... para j en el rango (y.shape [1]): ...

y sobre las columnas de y.


row_x = x [i,:] column_y = y [:, j] z [i,
j] = naive_vector_dot (row_x, column_y)
z retorno
Para entender la compatibilidad forma de punto-producto, que ayuda a visualizar los tensores
de entrada y salida mediante la alineación de ellos como se muestra en la figura 2.5.
C

y.shape:
(ante)
X.y=z s de

si Columna de y

si

x.shape: z.shape:
(a, b) (a, c)
u
n z [i, j] Figura 2.5 Matriz de puntos
Fila de x diagrama de subproducto
cajas

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 sigue que el ancho de x debe coincidir
con la altura de y. Si vas en el desarrollo de nuevos algoritmos

Con licencia para <null>


44 CCAPÍTULO 2Antes de comenzar: los bloques de construcción matemáticos de redes neuronales

de aprendizaje automático, es probable que vaya a dibujar diagramas


tales frecuencia.
De manera más general, se puede tomar el producto escalar entre los tensores de
dimensiones superiores, siguiendo las mismas reglas para la compatibilidad de la forma como
se describe 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 tensor de remodelación


Un tercer tipo de tensor de operación que es esencial para entender es tensor de remodelación.
A pesar de que no se utilizó en las capas densas en nuestro primer ejemplo de redes neuronales,
lo usamos cuando nos preprocesado de los datos de los dígitos antes de introducirlo en nuestra
red: train_images = train_images.reshape ((60000, 28 * 28))

Remodelación de un medio tensor reordenación de sus filas y columnas para que coincida con
una forma deseada. Naturalmente, el tensor reconfigurado tiene el mismo número total de
coeficientes como el tensor inicial. Remodelación se entiende mejor a través de ejemplos
simples:
>>> x = np.array ([[0., 1.],
[2., 3.],
[4., 5.]])
>>> print (x.shape)
(3, 2)
>>> x = x.reshape ((6, 1))
>>> x array
([[0.], [1.],
[2.],
[3.],
[4.],
[5.]])

>>> x = x.reshape ((2, 3))


>>> x array ([[0., 1.,
2.],
[3., 4., 5.]])

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


transposición de un medio de matriz que intercambian sus filas y sus columnas, de modo que
x [i,:] se convierte en x [:, i]:
>>> x = np.zeros ((300, 20))

Con licencia para <null>


Los engranajes de redes neuronales: las operaciones tensor 45

Crea una matriz de todos los ceros de forma (300, 20)


>>> x = np.transpose (x)
>>> print (x.shape)
(20, 300)

2.3.5Interpretación geométrica de las operaciones del tensor


Debido a que los contenidos de los tensores manipulados por tensor de operaciones pueden
ser interpretadas como coordenadas de puntos en algún espacio geométrico, todas las
operaciones de tensor tienen una interpretación geométrica. Por ejemplo, consideremos
adición. Vamos a empezar con el siguiente vector:
A = [0,5, 1]

Es un punto en un espacio 2D (véase la figura 2.6). Es común a la imagen un vector como una
flecha que une el origen hasta el punto, como se muestra en la figura 2.7.

1 U [0.5, 1] 1 U [0.5, 1]
N N

1 1

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


representado como una flecha

Vamos a considerar un nuevo punto, B = [1, 0,25], lo que vamos a añadir a la anterior. Esto
se hace geométricamente por el encadenamiento de juntas las flechas de vectores, con la
ubicación que resulta ser el vector que representa la suma de los dos vectores anteriores
(véase la figura 2.8).

A+B

1 U
N

si
1 Figura 2.8 Interpretación
geométrica de la suma de dos vectores

Con licencia para <null>


46 CCAPÍTULO 2Antes de comenzar: los bloques de construcción matemáticos de redes neuronales

En, operaciones geométricas elementales generales, tales como transformaciones afines,


rotaciones, escalado, y así sucesivamente se puede expresar como operaciones tensor. Por
ejemplo, una rotación de un vector 2D por un ángulo theta se puede lograr a través de un
producto de punto con un 2 × 2 matriz R = [u, v], donde u y v son ambos vectores del plano:
u = [cos ( theta),
sen (theta)] y v = [-sen (theta), cos (theta)].

2.3.6Una interpretación geométrica de aprendizaje profundo


Que acaba de aprender que las redes neurales consisten enteramente en cadenas de tensor de
operaciones y que todas estas operaciones tensores son simplemente transformaciones
geométricas de los datos de entrada. De ello se desprende que se puede interpretar una red
neuronal como muy compleja transformación geométrica en un espacio de alta dimensión,
implementado a través de una larga serie de pasos simples.
En 3D, la siguiente imagen mental puede resultar útil. Imaginemos dos hojas de papel de
colores: uno rojo y otro azul. Poner una encima de la otra. Ahora les arrugue juntos en una
pequeña bola. Esa bola de papel arrugado es los datos de entrada, y cada hoja de papel es una
clase de datos en un problema de clasificación. Lo que una red neuronal (o cualquier otro
modelo de aprendizaje automático) está destinado a hacer es encontrar una transformación de
la bola de papel que uncrumple que, a fin de hacer las dos clases limpiamente separables de
nuevo. Con el aprendizaje profundo, esto se implementa como una serie de transformaciones
simples del espacio 3D, como las que se podría aplicar en la bola de papel con los dedos, un
movimiento a la vez.

Figura 2.9 un Uncrumpling


complicado colector de datos

Uncrumpling bolas de papel es lo que la máquina de aprendizaje es acerca de: la búsqueda de


representaciones aseado para complejos, colectores de datos altamente plegadas. En este punto, usted
debe tener una muy buena intuición para sobresale de aprendizaje por qué profundidad en esto: se toma
el enfoque de descomponer de forma incremental una transformación geométrica complicada en una
larga cadena de los elementales, que es más o menos la estrategia de un ser humano seguiría hasta una
bola de papel uncrumple. Cada capa en una red profunda se aplica una transformación que desenreda
los datos un poco y una profunda pila de capas marcas tratable un proceso de desenmarañado
extremadamente complicado.

Con licencia para <null>


Los engranajes de redes neuronales: las operaciones tensor 47

2.4 El motor de las redes neuronales:


optimización basada en gradiente
Como se 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, de entrada) + b)

En esta expresión, W y b son tensores que son atributos de la capa. Se llaman los pesos o
parámetros entrenables de la capa (el Kernel y el sesgo de atributos, respectivamente). Estos
pesos contienen la información obtenida por la red de la exposición a los datos de
entrenamiento.
Inicialmente, estas matrices de peso se llenan con valores aleatorios pequeños (un paso
llamado inicialización aleatorio). Por supuesto, no hay razón para esperar que relu (punto (W,
de entrada) + b), cuando W y b son al azar, se dió ningún representaciones útiles. Las
representaciones resultantes no tienen sentido, pero son un punto de partida. Lo que sigue es
el ajuste gradual de estos pesos, en base a una señal de realimentación. Este ajuste gradual,
también llamado entrenamiento, es básicamente el aprendizaje que el aprendizaje automático
se trata.
Esto sucede dentro de lo que se llama un bucle de formación, que funciona de la siguiente
manera. Repita estos pasos en un bucle, mientras sea necesario:
1 Dibuje un lote de la formación de x muestras y los objetivos y correspondiente.
2 Ejecutar la red de a x (un paso llamado el pase hacia adelante) para obtener
predicciones y_pred.
3 Calcular la pérdida de la red en el lote, una medida de la falta de coincidencia entre
y_pred e y.
4 Actualizar todos los pesos de la red de una manera que reduce ligeramente la pérdida
en este lote.
Que finalmente va a terminar con una red que tiene una pérdida muy baja de sus datos de
entrenamiento: una falta de coincidencia entre las predicciones de baja y_pred y objetivos
previstos y. La red ha “aprendido” para mapear sus entradas a los objetivos correctos. Desde
lejos, puede parecer que la magia, pero cuando se reduce a pasos elementales, que resulta ser
simple.
Paso bastante-1 solo sonidos fáciles código de E / S. Los pasos 2 y 3 son meramente la
aplicación de un puñado de operaciones tensor, por lo que podría poner en práctica estos pasos
sólo a partir de lo que aprendió en la sección anterior. La parte difícil es el paso 4: actualización
de los pesos de la red. Teniendo en cuenta un coeficiente de peso individual en la red, ¿cómo
se puede calcular si el coeficiente debe ser aumentado o disminuido, y por cuánto?
Una solución ingenua sería congelar todos los pesos de la red, excepto el coeficiente escalar
uno está considerando, y probar diferentes valores de este coeficiente. Digamos que el valor
inicial del coeficiente es 0,3. Después de que el pase hacia adelante en un lote de datos, la
pérdida de la red en el lote es de 0,5. Si cambia el valor del coeficiente de 0,35 y vuelva a
ejecutar el paso hacia adelante, la pérdida aumenta a 0,6. Pero si se baja el coeficiente de

Con licencia para <null>


48 CCAPÍTULO 2Antes de comenzar: los bloques de construcción matemáticos de redes neuronales

0,25, la pérdida cae a 0,4. En este caso, parece que la actualización del coeficiente de -0.05

Con licencia para <null>


El motor de las redes neuronales: optimización basada en gradiente 49

contribuiría a minimizar la pérdida. Esto tendría que ser repetido para todos los coeficientes en
la red.
Sin embargo, este enfoque sería terriblemente ineficiente, ya que había necesidad de
computar dos pasos hacia adelante (que son caros) para cada coeficiente individuales (de los
cuales hay muchos, por lo general los miles ya veces hasta millones). Un mejor enfoque es tomar
ventaja del hecho de que todas las operaciones utilizadas en la red son diferenciables, y calcular
la pendiente de la pérdida con respecto a los coeficientes de la red. A continuación, puede mover
los coeficientes en la dirección opuesta a partir del gradiente, disminuyendo así la pérdida.
Si ya sabe lo que significa diferenciables y lo que es un gradiente, puede saltar a la sección
2.4.3. De lo contrario, las dos secciones siguientes le ayudarán a entender estos conceptos.

2.4.1 Lo que es un derivado?


Considere un continuo, liso función f (x) = y, la asignación de 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 sólo puede llevar
a un pequeño cambio en y-esa es la intuición detrás de continuidad. Digamos que aumenta x
por un pequeño factor de epsilon_x: esto da lugar a un pequeño cambio a epsilon_y y:
f (x + epsilon_x) = y + epsilon_y

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

Obviamente, esta aproximación lineal es válida sólo cuando x es lo suficientemente cerca de p.


La pendiente a se llama la derivada de f en p. Si a es negativa, significa que un cambio
pequeño 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 se traducirá en un aumento de f (x). Además,
el valor absoluto de un (la magnitud de la derivada) le indica la rapidez con este aumento o
disminución sucederán.

lineal local
aproximación de f,
con pendiente
una

F
Figura 2.10 Derivado de F en pags

Para cada función (medios diferenciables “se pueden derivar”: por ejemplo, liso, funciones
continuas se pueden derivar) f diferenciable (x), existe una función derivada f '(x) que mapea los

Con licencia para <null>


50 CCAPÍTULO 2Antes de comenzar: los bloques de construcción matemáticos de redes neuronales

valores de x para la pendiente de la locales aproximación lineal de f en esos puntos. Por ejemplo,
el derivado de cos (x) es -sen (x), la derivada de f (x) = a * x es f '(x) = A, y así sucesivamente.
Si usted está tratando de actualización de x por un factor de epsilon_x con el fin de minimizar
f (x), y usted sabe que la derivada de f, entonces su trabajo está hecho: la derivada describe por
completo la forma f (x) evoluciona a medida que cambian x. Si desea reducir el valor de f (x),
sólo tiene que mover x un poco en la dirección opuesta a la derivada.

2.4.2 Derivado de una operación de tensor: el gradiente


Un gradiente es la derivada de una operación de tensor. Es la generalización del concepto de
derivados para funciones de las entradas multidimensionales: es decir, a las funciones que toman
como entradas tensores.
Considérese un vector de entrada x, una matriz W, un objetivo y, y una pérdida de función de
pérdida. Se puede utilizar para calcular W candidato objetivo y_pred, y calcular la pérdida o
falta de coincidencia, entre el candidato de destino y el objetivo y_pred y:
y_pred = punto (W, x)
loss_value = pérdida (y_pred,
y)

Si x e y se congelan las entradas de datos, entonces esto se puede interpretar como un archivo
de valores de correlación de funciones de W a valores de pérdida:
loss_value = f (W)

Digamos que el valor actual de W es W0. Entonces la derivada de f en el punto W0 es un


gradiente tensor (f) (W0) con la misma forma que W, donde cada gradiente coeficiente (f) (W0)
[i, j] indica la dirección y la magnitud del cambio en loss_value se observa cuando se modifica
W0 [i, j]. Eso gradiente tensor (f) (W0) es el gradiente de la función f (W) = loss_value en W0.
Usted vio anteriormente que la derivada de una función f (x) de un único coeficiente puede
ser interpretado como la pendiente de la curva de f. Del mismo modo, gradiente (f) (W0) puede
interpretarse como el tensor de describir la curvatura de f (W) alrededor de W0.
Por esta razón, casi de la misma manera que, para una función f (x), puede reducir el valor de
f (x) moviendo poco xa en la dirección opuesta a la derivada, con una función f (W) de una
tensor, puede reducir f (W) moviendo W en la dirección opuesta a partir del gradiente: por
ejemplo, W1 = W0 - paso * gradiente (f) (W0) (donde el paso es un pequeño factor de escala).
Eso significa ir en contra de la curvatura, que intuitivamente debe poner a bajar en la curva.
Tenga en cuenta que se necesita el paso factor de escala debido a gradiente (f) (W0) sólo se
aproxima a la curvatura cuando se está cerca de W0, por lo que no quiere estar demasiado lejos
de W0.

2.4.3 descenso de gradiente estocástico


Dada una función diferenciable, es teóricamente posible encontrar su mínimo analítica: se sabe
que el mínimo de una función es un punto donde la derivada es 0, por lo que todo lo que tiene

Con licencia para <null>


El motor de las redes neuronales: optimización basada en gradiente 51

que hacer es encontrar todos los puntos donde la derivada va a 0 y el cheque por el cual de estos
puntos de la función tiene el valor más bajo.
Aplicada a una red neuronal, que 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 mediante la resolución de
la gradiente de la ecuación (f) (W) = 0 para W. Esta es una ecuación polinómica de n variables, donde N
es el número de coeficientes en la red. Aunque sería posible resolver esta ecuación para N = 2 ó N = 3,
hacerlo es insuperable para las redes neuronales reales, donde el número de parámetros nunca es menor
que unos pocos miles y, a menudo puede ser de varias decenas de millones.
En su lugar, puede utilizar el algoritmo de cuatro etapas que se describe al principio de esta sección:
modificar los parámetros poco a poco en función del valor actual pérdida de un lote aleatorio de datos.
Debido a que usted está tratando con una función diferenciable, se puede calcular su gradiente, lo que le
proporciona una manera eficiente para implementar el paso 4. Si actualiza los pesos en la dirección
opuesta a la pendiente, la pérdida será un poco menos cada vez que:
1 Dibuje un lote de la formación de x muestras y los objetivos y correspondiente.
2 Ejecutar la red de x para obtener predicciones y_pred.
3 Calcular la pérdida de la red en el lote, una medida de la falta de coincidencia entre y_pred e y.
4 Calcular el gradiente de la pérdida con respecto a los parámetros de la red (un pase hacia atrás).
5 Mover los parámetros de un poco en la dirección opuesta a la W gradiente, por ejemplo - = paso
* reducir gradiente-así la pérdida en el lote un poco.
¡Suficientemente fácil! Lo que acabo de describir se llama minibatch estocástico pendiente de descenso
(minibatch SGD). El término estocástico refiere al hecho de que cada lote de datos se extrae al azar
(estocástico es un sinónimo científico de azar). La figura 2.11 ilustra lo que sucede en 1D, cuando la red
tiene un solo parámetro y tiene sólo una muestra de entrenamiento.

Pérdi Paso, también llamada tasa de


valor
da aprendizaje
Comenza
punto (t = 0)
ndo

t=
1
t=
2 t=
3

Parámetro Figura 2.11 SGD por una


pérdida de 1D valor curva (un parámetro learnable)

Como se puede ver, de manera intuitiva que es importante escoger un valor razonable para el factor de
paso. Si es demasiado pequeño, el descenso por la curva tendrá muchas iteraciones, y podría quedar
atascado en un mínimo local. Si el paso es demasiado grande, las actualizaciones pueden terminar que
le llevará a lugares completamente al azar en la curva.

Con licencia para <null>


52 CCAPÍTULO 2Antes de comenzar: los bloques de construcción matemáticos de redes neuronales

Tenga en cuenta que una variante del algoritmo SGD mini-lotes sería elaborar una sola muestra y el
objetivo en cada iteración, en lugar de dibujar una serie de datos. Esto sería cierto SGD (en contraposición
a SGD mini-lotes). Alternativamente, yendo al extremo opuesto, podría ejecutar cada paso en todos los
datos disponibles, que se llama SGD por lotes. Cada actualización sería entonces más preciso, pero mucho
más caro. El compromiso eficaz entre estos dos extremos es el uso de 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
va a utilizar 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 o incluso millones de
ellos. Para ayudar a construir intuición sobre superficies de pérdida, podrá también ascendencia
Visualizar gradiente a lo largo de una superficie pérdida 2D, como se muestra en la figura 2.12. Pero
usted no puede visualizar lo que el proceso real de la formación de una red neural se ve como-usted no
puede representar un espacio 1.000.000 dimensiones de una manera que tenga sentido para los seres
humanos. Como tal, es bueno tener en cuenta que las intuiciones que se desarrollan a través de estas
representaciones de baja dimensión no siempre es exacta en la práctica. Esto ha sido históricamente una
fuente de problemas en el mundo de la investigación profunda de aprendizaje.

Punto de partida

45
40
35
30
25
20
15
10
5
Figura 2.12 descenso de gradiente abajo de una
superficie pérdida 2D (dos parámetros se pueden
Punto final aprender)

Además, existen múltiples variantes de SGD que difieren teniendo en cuenta las anteriores
actualizaciones de peso cuando se calcula la próxima actualización de peso, en lugar de sólo mirar el
valor actual de los gradientes. Hay, por ejemplo, SGD con el impulso, así como Adagrad, RMSProp, y
varios otros. Tales variantes se conocen como métodos de optimización o 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 2.13, que muestra la curva de una pérdida como una función de un parámetro de red.

Con licencia para <null>


El motor de las redes neuronales: optimización basada en gradiente 53

Pérdi
valor
da

Local
mínimo

Global
mínimo

Parámetro Figura 2.13 un mínimo local valor y


un mínimo global

Como se puede ver, en torno a un determinado valor del parámetro, hay un mínimo local:
alrededor de ese punto, moviéndose de izquierda resultaría en la pérdida cada vez mayor, pero
también lo sería moverse a la derecha. Si el parámetro bajo consideración se está optimizando a
través de SGD con una tasa de aprendizaje pequeña, entonces el proceso de optimización podría
atascarse en el mínimo local en lugar de hacer su camino hacia el mínimo global.
Puede evitar estos problemas mediante el uso de un 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 rodando
por la curva de pérdida. Si tiene suficiente impulso, la pelota no se queda bloqueado en un
barranco y terminará en el mínimo global. Momentum se implementa moviendo la bola en cada
paso basado no sólo en el valor actual de la pendiente (la aceleración actual) sino también de la
velocidad de la corriente (como resultado de la aceleración pasado). En la práctica, esto significa
actualizar el parámetro w basan no sólo en el valor del gradiente actual, sino también en la
actualización de parámetros anterior, como en esta implementación ingenua:
past_velocity = 0. factor de impulso
constante impulso = 0,1
bucle de optimización
mientras que la pérdida> 0,01:
w, pérdida, gradiente = get_current_parameters ()
velocidad = past_velocity * impulso + learning_rate * gradiente
de w = w + impulso * velocidad - learning_rate * gradient
past_velocity = velocidad update_parameter (w)

2.4.4Encadenamiento de derivados: el algoritmo de retropropagación


En el algoritmo anterior, asumimos que casualmente porque una función es diferenciable,
podemos calcular explícitamente su derivado. En la práctica, una función de red neural consta
de muchas operaciones tensor encadenados juntos, cada uno de los cuales tiene una simple,
conocido derivado. Por ejemplo, este es un f red compuesta de tres operaciones de tensor, a, b,
y c, con el peso matrices de W1, W2, W3 y:
f (W1, W2, W3) = a (W1, b (W2, c (W3)))

Con licencia para <null>


54 CCAPÍTULO 2Antes de comenzar: los bloques de construcción matemáticos de redes neuronales

Cálculo nos dice que una cadena de funciones puede derivarse usando la siguiente identidad,
llamada la regla de la cadena: f (g (x)) = f '(g (x)) * g' (x). Aplicando la regla de la cadena para
el cálculo de los valores de gradiente de una red neuronal da lugar a un algoritmo llamado
retropropagación (también llamado a veces inversa modo diferenciación). Propagación hacia
atrás comienza con el valor de pérdida final y trabaja hacia atrás desde las capas superiores a las
capas inferiores, aplicando la regla de la cadena para calcular la contribución que cada parámetro
tenía en el valor de pérdida.
Hoy en día, y en los próximos años, la gente va a implementar redes en los marcos modernos que son
capaces de diferenciación simbólica, como TensorFlow. Esto significa que, dada una cadena de
operaciones con un conocido derivado, se puede calcular una función de gradiente para la cadena
(mediante la aplicación de la regla de la cadena) que asigna valores de los parámetros de red a los valores
de gradiente. Cuando se tiene acceso a la función de este tipo a, el pase hacia atrás se reduce a una llamada
a esta función del gradiente. Gracias a la diferenciación simbólica, que nunca tendrá que aplicar el
algoritmo de retropropagación con la mano. Por esta razón, no vamos a perder su tiempo y su enfoque en
derivar la formulación exacta del algoritmo de retropropagación en estas páginas. Todo lo que necesita
es una buena comprensión de cómo funciona la optimización basada en el gradiente.

Con licencia para <null>


55
Mirando hacia atrás en nuestro primer ejemplo

2.5Mirando hacia atrás en nuestro primer ejemplo


Usted ha llegado al final de este capítulo, y que ahora debe tener un conocimiento general de
lo que está pasando detrás de las escenas en una red neuronal. Volvamos al primer ejemplo y
revisar cada parte de ella a la luz de lo que ha aprendido en las tres secciones anteriores.
Esto era los datos de entrada:
(Train_images, train_labels), (test_images, test_labels) = mnist.load_data ()
train_images = train_images.reshape ((60000, 28 * 28))
train_images = train_images.astype ( 'float32') / 255
test_images = test_images.reshape ((10000, 28 * 28))
test_images = test_images.astype ( 'float32') / 255

Ahora usted entiende que las imágenes de entrada se almacenan en los tensores numpy, que
están formateados como Float32 tensores de forma (60000, 784) (datos de entrenamiento) y
(10000, 784) (datos de prueba), respectivamente. Esta fue nuestra red:
red = models.Sequential () network.add (layers.Dense (512, la activación
= 'relu', input_shape = (28 * 28,))) network.add (layers.Dense (10,
activación = 'softmax'))

Ahora usted entiende que esta red consiste en una cadena de dos capas densas, que cada capa
se aplica unas pocas operaciones simples con tensores a los datos de entrada, y que estas
operaciones implican tensores de peso. tensores de peso, que son atributos de las capas, son
donde el conocimiento de las persiste la red.
Este fue el paso de la red-compilación:
network.compile (optimizador = 'rmsprop', pérdida =
'categorical_crossentropy', las métricas = [
'exactitud'])

Ahora usted entiende que categorical_crossentropy es la función de pérdida que se utiliza


como señal de realimentación para el aprendizaje de los tensores de peso y que la fase de
entrenamiento intentará reducir al mínimo. También sabe que esta reducción de la pérdida que
ocurre a través de descenso de gradiente estocástico minibatch. Las reglas exactas que rigen
un uso específico de descenso de gradiente se definen por el optimizador rmsprop pasado
como primer argumento. Por último, este fue el bucle de formación: network.fit (train_images,
train_labels, épocas = 5, batch_size = 128)

Ahora usted entiende lo que sucede cuando se llama ajuste: la red comenzará a iterar sobre los
datos de entrenamiento en mini-lotes de 128 muestras, 5 veces más (cada iteración sobre todos
los datos de entrenamiento se llama una época). En cada iteración, la red calcular los
gradientes de los pesos con respecto a la pérdida del lote, y actualizar los pesos en
consecuencia. Después de estos 5 épocas, la red habrá realizado 2.345 cambios de gradiente

Con licencia para <null>


56 CCAPÍTULO 2Antes de comenzar: los bloques de construcción matemáticos de redes neuronales
(469 por época), y la pérdida de la red será suficientemente baja para que la red será capaz de
clasificar dígitos escritos a mano con alta precisión.
En este punto, usted ya sabe la mayoría de lo que hay que saber acerca de las redes neuronales.

Con licencia para <null>


57
Mirando hacia atrás en nuestro primer ejemplo

men del capítulo


Aprendizaje significa encontrar una combinación de los parámetros del modelo
que minimiza una función de pérdida para un determinado conjunto de muestras
de datos de entrenamiento y sus objetivos correspondientes.
El aprendizaje ocurre mediante la elaboración lotes al azar 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. Los parámetros de red se mueven entonces un bit (la
magnitud del movimiento se define por la tasa de aprendizaje) en la dirección
opuesta a la del gradiente.
Todo el proceso de aprendizaje se hace posible por el hecho de que las redes
neuronales son cadenas de operaciones tensores diferenciables, y por lo tanto es
posible aplicar la regla de la cadena de derivación para hallar la función gradiente
de mapeo de los parámetros actuales y lote actual de datos a un valor de gradiente.
Dos conceptos clave que verá con frecuencia en capítulos futuros son la pérdida
y optimizadores. Estas son las dos cosas que hay que definir antes de comenzar
la alimentación de datos en una red.
La pérdida es la cantidad que va a intentar minimizar durante el entrenamiento,
por lo que debe representar una medida del éxito de la tarea que estamos tratando
de resolver.
Los optimizador especifica la manera exacta en la que se utilizará el gradiente de
la pérdida de parámetros de actualización: por ejemplo, podría ser el optimizador
RMSProp, SGD con ímpetu, y así sucesivamente.

Con licencia para <null>

S-ar putea să vă placă și