Deep Learning; Notas personales Parte 1 Lección 4: Aprendizaje estructurado, Procesamiento del lenguaje natural, Filtrado colaborativo. Dropout, Embeddings, Prop posterior a través del tiempo.

Esta serie de publicaciones de blog se actualizará cuando tenga una segunda visión de las lecciones rápidas de ai . Estas son mis notas personales; un esfuerzo por entender las cosas claramente y explicarlas bien. Nada nuevo, solo viviendo este blog .

Fast.ai adopta el enfoque de “aquí está cómo usar el software para hacer algo y luego mira detrás de escena mirando los detalles”. ”

Omisión

 learn = ConvLearner.pretrained (arch, data, ps = 0.5, precompute = True)

precompute = True precomputa las activaciones que salen de la última capa convolucional. Una activación es un número calculado en base a algunos pesos también conocidos como parámetros que forman un núcleo o filtros que se aplican a la activación de capas previas que de otro modo podrían ser las entradas o resultados de otros cálculos.

Escribiendo el nombre de su alumno Objeto puede ver realmente las capas en él:

 learn
 Sequential (
 (0): BatchNorm1d (1024, eps = 1e-05, momentum = 0.1, affine = True) 
 (1) : Deserción (p = 0.5) 
 (2): Lineal (in_features = 1024, out_features = 512) 
 (3): ReLU () 
 (4): BatchNorm1d (512, eps = 1e-05 , momentum = 0.1, affine = True) 
 (5): Omisión (p = 0.5) 
 (6): Lineal (in_features = 512, out_features = 120) 
 (7): LogSoftmax () 
) 

Lineal (in_features = 1024, out_features = 512) una capa lineal significa un multiplicador de matriz. En este caso, tenemos una matriz con 1024 filas y 512 columnas. Toma en 1024 activaciones y escupe 512 activaciones.

ReLu. Reemplaza los negativos con ceros.

Lineal (in_features = 512, out_features = 120) la segunda capa lineal toma las primeras activaciones de capa lineal 512 activaciones y las pone a través de una nueva matriz multiplica 512 por 120 y las salidas 120 activaciones.

Softmax - Una función de activación que devuelve números que suman 1 y cada uno de ellos está entre 0 y 1. Por razones de menor precisión numérica, resulta mejor tomar el registro de softmax que softmax directamente. Es por eso que cuando obtenemos predicciones de nuestros modelos, tenemos que hacer np.exp (log_preds).

¿Qué hace Dropout (p = 0.5) do?

La ​​aplicación de deserción significa elegir activación en una capa y borrarlos. p es la probabilidad de eliminar una activación. La activación de la salida no cambia mucho.

La eliminación aleatoria de la mitad de las activaciones en una capa tiene un efecto interesante, la fuerza a no sobreabastecerse. Si una activación de activación particular había aprendido exactamente el perro o gato exacto, obliga al modelo a encontrar una representación sin una mitad aleatoria de las activaciones.

Si ha realizado todos los aumentos de datos o ha proporcionado al modelo los datos suficientes que podría, te quedan pocas cosas que podrías hacer, pero en gran medida estás estancado. Geofrey Hinton et al produjeron una deserción que está inspirada por la forma en que funciona el cerebro.

p = 0.01 está desperdiciando el 1% de las activaciones, no cambiará mucho las cosas, por lo tanto, no evitará el sobreajuste, es decir no generalizará.

p = 0.99 tirarás el 99% de las activaciones. Tampoco será demasiado grande para generalizar pero matará tu precisión.

Alto Los valores de p se generalizan bien pero disminuyen tu precisión de entrenamiento, bajo Los valores de p se generalizarán menos pero te darán una mejor precisión.

Al principio del entrenamiento, ¿por qué las pérdidas de validación son mejores que las pérdidas de entrenamiento dado que el conjunto de datos que no ha visto no espera que las pérdidas sean mucho mejores? esto se debe a que cuando miramos el conjunto de validación, suspendemos el abandono. Al hacer inferencias, es decir, predecir que queremos usar el mejor modelo que podamos. La deserción ocurre durante el entrenamiento.

¿Tienes que hacer algo para acomodar el hecho de que estás descartando activaciones? No lo hacemos (fast.ai) Cuando decimos que p = 0.5 detrás de la escena, pytorch tira la mitad de las activaciones y dobla la activación ya existente, por lo tanto, la activación promedio no cambia.

En Fast.ai, puede pasar en ps que es el valor de p para todas las capas agregadas. No cambiará el abandono en la red pre-entrenada ya que debería haber sido entrenado con un nivel apropiado de abandono:

 learn = ConvLearner.pretrained (arch, data,  ps = 0.5 precálculo = Verdadero)

Podemos eliminar la deserción mediante la configuración = 0.Pero después de un par de épocas empezamos a sobredimensionar masivamente. La pérdida de entrenamiento es menor que la pérdida de validación. Con ps = 0, el abandono no se agrega al modelo.

Se habrá dado cuenta de que ha agregado dos capas lineales. No tenemos que hacer eso. Hay un parámetro xtra_fc (capas completamente conectadas) que puede configurar. Puedes pasar una lista de lo grande que quieres que sea cada capa adicional completamente conectada. Necesitas al menos uno que tome la salida de la capa convolucional (1096 en este ejemplo) y la convierta en el número de clases 120 razas de perros, es decir, definida por tu problema:

Si el xtra_fc está vacío significa que no lo haces agregue capas lineales adicionales solo la que tenemos que tener, dándonos un modelo mínimo.

¿Hay un valor p particular que deberíamos usar por defecto? Para la primera capa tenemos p = 0.25 y para la segunda capa tenemos p = 0.5 que parece funcionar para la mayoría de las cosas. Si la encuentra sobreexplotada, siga aumentando, digamos 0.2. Si no lo está, disminuya.

ResNet34 tiene menos parámetros, por lo que no se sobrecarga tanto, pero para una arquitectura más grande como ResNet50, a menudo necesita aumentar el abandono.

¿Hay alguna manera particular en la que pueda determinar si está sobreajustado? Sí, puede ver que la pérdida de entrenamiento es mucho menor que la pérdida de validación. No puede decir si también está sobreajustado. El overfitting cero generalmente no es óptimo. Lo único que intenta hacer es reducir la pérdida de validación, por lo que necesita jugar con algunas cosas y ver qué hace que la pérdida de validación sea baja.

¿Por qué es importante la activación promedio? Si eliminamos la mitad de las activaciones, la siguiente activación que las toma como entrada también se reducirá a la mitad, y todo después de eso. Por ejemplo, las orejas esponjosas son esponjosas si la activación es mayor que 0.6, y ahora solo es esponjosa si es mayor que 0.3, lo que cambia el significado. El objetivo aquí es eliminar activaciones sin cambiar el significado.

¿Podemos tener diferentes niveles de abandono por capa? Sí, es por eso que se llama ps y podríamos pasar una matriz: ps = [0.1,0.2]

No existe una regla de oro para cuando las capas anteriores o posteriores deben tener diferentes cantidades de desertores aún. Si tiene dudas, use la misma puntera para cada capa completamente conectada. A menudo, las personas solo ponen la deserción en la última capa lineal.

¿Por qué controlar la pérdida y la falta de precisión? La pérdida es lo único que podemos ver tanto para el conjunto de validación como para el conjunto de entrenamiento y podemos compararlos. Como veremos más adelante, la pérdida es lo que realmente estamos optimizando, por lo que es más fácil monitorear y entender lo que eso significa.

Al agregar el abandono parece que estamos agregando un ruido aleatorio y eso significa que no lo hacemos Aprendimos mucho, ¿necesitamos ajustar la tasa de aprendizaje? No parece afectar la velocidad de aprendizaje suficiente para darse cuenta. En teoría, podría pero no lo suficiente afectarnos.

Datos Estructurados y de Series Temporales

Los dos tipos de columnas en los datos son:

Categóricos: tiene una cantidad de “nivel”, p. StoreType, surtido

Continuo: tiene un número donde la diferencia o proporción de ese número tiene algún tipo de significado. por ejemplo, CompetitionDistance

No cubriremos la limpieza de datos y la ingeniería de características, supondremos que se ha hecho. Necesitamos convertir a la entrada compatible con una red neuronal.

Esto incluye la conversión de variables categóricas en enteros contiguos o codificaciones en caliente, normalización de las funciones continuas para normal normal, etc …

Números como año, mes y día aunque podría tratarlos como continuo, no es necesario. Cuando decidimos hacer algo categórico, le estamos diciendo a la red neuronal que trate cada nivel de manera diferente. Pero, cuando decimos que es continuo, le decimos que cree una función suave para ajustarlos.

Muy a menudo, las cosas que son continuas pero no tienen muchos niveles distintos (por ejemplo, Año, Día de la semana), a menudo funcionan mejor para tratarlos como categóricos. Como cada día puede comportarse de manera cualitativa diferente

Decidimos qué variables son categóricas y cuáles son continuas, esta es una decisión de modelado que tiene que tomar.

Si algo está codificado en sus datos como “a, b” , c “tiene que llamarlo como categórico, si comienza como continuo, debe elegir si tratar eso como categórico o continuo.

Tenga en cuenta que las variables continuas son números reales de coma flotante. Los números flotantes tienen muchos niveles, es decir, tiene una cardinalidad alta p. la cardinalidad de DayOfWeek es 7.

¿Alguna vez has bin variables continuas? No por el momento, pero una cosa que podríamos hacer, digamos Max_Temperature, es agrupar en 0-10, 10-20, 20-30, y llame a eso categórico. Un grupo de investigadores descubrió que a veces el binning puede ser útil.

Si usa el año como una categoría, ¿qué sucede cuando un modelo se encuentra con un año que nunca antes había visto? Será tratado como un categoría desconocida Pandas tiene una categoría especial llamada desconocida y si ve una categoría que no ha visto antes, se trata como desconocida.

Si nuestro conjunto de datos de entrenamiento no tiene categorías sino prueba, no se sabe qué hará el modelo , ¿va a predecir? Formará parte de la categoría desconocida, todavía va a predecir que procesará el valor 0 detrás de lo visto, si hay desconocidos en el conjunto de entrenamiento habrá aprendido a predecir con ellos si no lo ha hecho. un vector al azar.

 n = len (unido); n 
 844338

Tenemos 844338 filas que son las fechas en cada tienda.

Pasa por cat_vars y convierte las columnas de marco de datos aplicables en columnas categóricas.

Pasa por contin_vars y establécelas como float32 (32 bit punto flotante) porque eso es lo que PyTorch espera. por ejemplo Promo, SchoolHoliday

Comience con una muestra

Tendemos a comenzar con una pequeña muestra del conjunto de datos. Para las imágenes que significarían cambiar el tamaño de la imagen a 64 x 64 o 128 x 128. Pero con los datos estructurados comenzamos con una muestra aleatoria de filas.

Así nos da 150000 filas de datos para comenzar.

Mirando los datos:

Aunque configuramos algunas de las columnas como “categoría”, por ejemplo ‘StoreType’, ‘Año’. Eso se guardó internamente, los pandas aún se muestran como una cadena en el cuaderno.

proc_df (marco de datos de proceso) es una función rápida de ai que:

Toma un marco de datos indica cuál es tu variable dependiente, la coloca en una variable separada y lo borra del marco de datos original. En otras palabras, df no tiene columna Sales, y y contiene la columna Sales.

do_scale A las redes neuronales les gusta realmente que los datos de entrada estén en algún lugar alrededor de cero con una desviación estándar de alrededor de 1. Para que esto suceda, tome nuestros datos, reste la media y divídala por la desviación estándar. Devuelve un mapeador de objetos especial que realiza un seguimiento de qué media y desviación estándar utilizó para esa normalización, por lo que puede hacer lo mismo con el conjunto de pruebas más adelante.

nas También maneja valores perdidos, para la variable categórica, se convierte en ID: 0 y otras categorías se convierten en 1, 2, 3, y así sucesivamente. Para la variable continua, reemplaza el valor perdido con la mediana y crea una nueva columna que es booleana que dice si faltaba o no.

Antes del preprocesamiento
Después del preprocesamiento

El año 2014, por ejemplo, se convierte en 2 ya que categórico las variables se han reemplazado con enteros contiguos comenzando en cero. El motivo es que los vamos a colocar en una matriz más adelante, y no queremos que la matriz tenga 2014 filas, cuando podrían ser solo dos filas.

ahora tenemos un marco de datos que no contiene la variable dependiente y donde todo es un número. Ahí es donde tenemos que hacer un Deep Learning.

En este caso, debemos predecir las próximas dos semanas de ventas, por lo tanto, debemos crear un conjunto de validación que sea las últimas dos semanas de nuestro conjunto de capacitación. [19659008] En los datos de series temporales, la validación cruzada no es aleatoria. En cambio, nuestros datos de retención generalmente son los datos más recientes, como lo serían en una aplicación real. Este problema se discute en detalle aquí . Un enfoque es tomar el último 25% de las filas (ordenadas por fecha) como nuestro conjunto de validación.

Al unir nuestro modelo

es importante que tenga una sólida comprensión de su métrica, es decir, cómo va a ser. juzgado. En esta competencia se nos juzgará en Root Mean Square Percentage Error (RMSPE).

Esto significa que tomamos la venta real menos el valor predicho de una predicción única para encontrar su porcentaje y luego encontrar el promedio.

Cuando toma el registro de los datos, obtener el error medio cuadrático de la raíz realmente le conseguirá el error de porcentaje cuadrático medio:

Podemos crear un objeto ModelData directamente desde el marco de datos de salida:

 md =  ColumnarModelData.from_data_frame  (RUTA, val_idx, df, 
 yl.astype (np.float32), cat_flds = cat_vars, bs = 128, 
 test_df = df_test)

Lo haremos comience por crear el modelo de objeto de datos md que tiene un conjunto de validación, un conjunto de entrenamiento y un conjunto de pruebas opcional integrado. A partir de eso, obtendremos un aprendiz, luego opcionalmente llamaremos a lr_find, luego llamaremos a learn.fit y demás.

La diferencia aquí es que no estamos usando ImageClassifierData.from_csv o from_paths, necesitamos un tipo diferente de datos del modelo llamados ColumnarModelData y llamamos from_data_frame.

La ruta especifica dónde almacenar el archivo de modelo, etc.

val_idx lista de índices de filas que pondremos en el conjunto de validación.

df el marco de datos de las variables independientes.

yl variable dependiente que es el log de y devuelto por proc_df ie yl = np.log (y)

cat_flds especifica qué cosas quiere que se traten como categóricas. Todo se convirtió en un número a menos que especifiquemos, los tratará a todos como continuos. pase la lista de nombres cat_vars

bs tamaño de lote

Ahora tenemos un objeto de datos de modelo estándar que contiene train_dl, val_dl, train_ds, val_ds, etc.

Creando un alumno adecuado para nuestros datos modelo:

 m = md.get_learner (emb_szs, len (df.columns) -len (cat_vars), 
 0.04, 1, [1000,500][0.001,0.01]
 y_range = y_range)
  • 0.04: cuánto abandono para usar desde el principio
  • [1000,500]: cuántas activaciones se deben tener en cada capa
  • [0.001,0.01]: cuántas interrupciones usar en capas posteriores
  • emb_szs incrustaciones

Incrustar

vamos a mantener las variables categóricas por un momento y mira las variables continuas:

Nunca deseas poner ReLU en la última capa porque softmax necesita negativos para crear bajas probabilidades.

Vista simple de una capa completamente conectada:

Toma una entrada como rango un tensor lo puso a través de una capa lineal (producto matriz), a través de un activador on (ReLu), capa lineal otra vez luego softmax y finalmente una salida. Podemos agregar capas o abandonos más lineales.

Omita el softmax para problemas de regresión.

Variables categóricas

Creamos una nueva matriz de 7 filas y tantas columnas como elijamos 4, por ejemplo, y lo llenamos con números flotantes. Para agregar “Domingo” a nuestro tensor de rango 1 con variables continuas, observamos esta matriz, que devolverá 4 números flotantes, y los usaremos como “Domingo”.

Inicialmente, estos números son aleatorios. Pero podemos ponerlos a través de una red neuronal y actualizarlos usando el descenso de gradiente de una manera que reduzca la pérdida. Esta matriz es solo otro grupo de pesos en nuestra red neuronal llamada matriz de inclusión

Una matriz de inclusión es algo donde comenzamos con un número entero entre cero y el número máximo de niveles de esa categoría. Indexamos en la matriz para encontrar una fila en particular, y la adjuntamos a todas nuestras variables continuas, y todo después de eso es exactamente igual a la anterior (lineal → ReLU → lineal, etc.).

¿Qué hacen esos ¿4 números representan? Son solo parámetros que estamos aprendiendo que terminan por darnos una buena pérdida. Más adelante descubriremos que estos parámetros particulares a menudo son interpretables por humanos y bastante interesantes, pero que son un efecto secundario. Son un conjunto de 4 números aleatorios que estamos aprendiendo.

¿Tiene una buena heurística para la dimensionalidad de la matriz de inserción? Usamos la cardinalidad de cada variable (es decir, su número de valores únicos) para decidir qué tan grande hacer sus incrustaciones .

Arriba hay una lista de cada variable categórica y su cardinalidad.

Tenemos 7 días de la semana, pero al observar la cardinalidad de DayOfWeek es 8, la cardinalidad adicional se agrega solo en caso de que exista un desconocido en el conjunto de prueba, divida eso por 2, por lo tanto, los 4 números aleatorios . Incluso si no hubiera valores perdidos en los datos originales, aún debe reservar uno para desconocido por si acaso. Los años también son 3 pero agregamos uno para lo desconocido, etc.

La regla de oro para determinar el tamaño de incrustación es el tamaño de cardinalidad dividido por 2, pero no más grande que 50.

Mirando la tienda lo haremos tenemos 1116 tiendas para buscar que devuelven un rango de un tensor de longitud 50. Tenemos que construir una matriz de inclusión para cada variable categórica.

Luego pasamos los tamaños de inserción emb_szs a get_learner, que le dice al alumno que para cada variable categórica que incrustación para usar para esa variable.

 m = md.get_learner (emb_szs, len (df.columns) -len (cat_vars), 
 0.04, 1, [1000,500][0.001,0.01]y_range = y_range) 
 m.summary ()

¿Hay alguna manera de inicializar matrices de incrustación además de aleatorio? La idea básica es que si alguien más en Rossmann ya había entrenado una red neuronal para predecir las ventas de queso, también podría comenzar con su matriz de incrustación de tiendas para predecir las ventas de licores. Esto es lo que sucede, por ejemplo, en Pinterest e Instacart. Instacart usa esta técnica para enrutar a sus compradores, y Pinterest la usa para decidir qué mostrar en una página web. Tienen matrices integradas de productos / tiendas que se comparten en la organización para que las personas no tengan que entrenar nuevas.

¿Cuál es la ventaja de usar matrices de incrustación sobre una codificación en caliente? Para el día de la semana ejemplo anterior, en lugar de los 4 números, podríamos haber pasado fácilmente 7 números, por ejemplo [0, 1, 0, 0, 0, 0, 0] para el domingo. Esa también es una lista de carrozas y funcionaría totalmente y así es como, en términos generales, las variables categóricas se han utilizado en las estadísticas durante muchos años llamadas “variables ficticias”. El problema con eso es que el concepto de domingo solo puede asociarse con un solo número de coma flotante. Entonces tiene este tipo de comportamiento lineal, dice que el domingo es más o menos de una sola cosa. Con incrustaciones, el domingo es un concepto en un espacio de cuatro dimensiones. Lo que sucede es que estos vectores de inserción tienden a obtener estos ricos conceptos semánticos. Por ejemplo, si los fines de semana tienen un comportamiento diferente, tienden a ver que los sábados y domingos tendrán un número particular más alto o, por ejemplo, ciertos días de la semana tienden a asociarse con mayores ventas, por ejemplo, la compra de licor el viernes.

Al tener un vector de mayor dimensionalidad en lugar de solo un número, le da a la red de Deep Learning la oportunidad de aprender estas representaciones ricas.

La idea de una incrustación es lo que se llama una “representación distribuida”: la más fundamental concepto de redes neuronales. Esta es la idea de que un concepto en la red neuronal tiene una alta representación dimensional que puede ser difícil de interpretar. Estos números en este vector ni siquiera tienen que tener un solo significado. Podría significar una cosa si es baja y si una es alta, y otra cosa si esa es alta y esa es baja porque está pasando por esta rica función no lineal. Es esta rica representación lo que le permite aprender relaciones tan interesantes.

¿Las incrustaciones son adecuadas para ciertos tipos de variables? La incrustación es adecuada para cualquier variable categórica. Lo único que no puede funcionar bien sería algo con una cardinalidad demasiado alta. Si tenía 600,000 filas y una variable tenía 600,000 niveles, esa no es una variable categórica útil. Pero en general, el tercer ganador en esta competencia realmente decidió que todo lo que no era demasiada cardinalidad, los puso a todos como categóricos. La buena regla empírica es que, si puede hacer una variable categórica, también puede hacerlo porque de esa manera puede aprender esta rica representación distribuida; en otro caso, si lo deja como continuo, lo máximo que puede hacer es tratar de encontrar una sola forma funcional que se ajuste bien.

Cómo funciona el álgebra matricial detrás de la escena:

Hacer una búsqueda es idéntico a hacer una producto de la matriz entre un vector codificado en caliente y la matriz de inclusión.

Después de multiplicar le queda un solo vector. Las bibliotecas modernas implementan esto como tomar un número entero y buscar en una matriz.

¿Podría tocar el uso de fechas y horas como categóricas y cómo eso afecta la estacionalidad? A continuación, se extraen los campos de fecha particulares de una fecha de tiempo completa con el fin de construir categoricals. Debería siempre considerar este paso de extracción de características cuando se trabaja con fecha y hora. Sin ampliar su fecha y hora en estos campos adicionales, no puede capturar ningún comportamiento tendencial / cíclico como una función del tiempo en ninguna de estas granularidades. Añadiremos a cada tabla con un campo de fecha.

la función add_datepart toma un marco de datos y un nombre de columna. Opcionalmente, quita la columna del marco de datos y la reemplaza con muchas columnas que representan toda la información útil acerca de esa fecha, como el día de la semana, el día del mes, el mes del año, es el inicio del quater, el final del quater, etc. terminamos con una lista de nuestras características:

Por ejemplo, DayOfWeek ahora se convierte en ocho filas por cuatro columnas que incorporan la matriz. Conceptualmente, esto permite a nuestro modelo crear algunos modelos interesantes de series de tiempo. Si hay algo que tiene un ciclo de siete días que sube los lunes y los miércoles pero solo a diario y solo en Berlín, puede hacer eso totalmente, tiene toda la información que necesita.

Esto es fantástico forma de lidiar con series de tiempo. Solo necesita asegurarse de que el indicador de ciclo en su serie temporal exista como una columna. Si no tuviera una columna llamada día de la semana, sería muy difícil para la red neuronal aprender a dividir el módulo siete y buscar en una matriz de incrustación. No es imposible, pero realmente difícil.

Por ejemplo, si predice ventas de bebidas en San Francisco, es probable que desee una lista de cuándo está listo el juego de pelota en el parque AT & T porque eso afectará a la cantidad de personas bebiendo cerveza en SoMa. Así que debe asegurarse de que los indicadores básicos o la periodicidad estén en sus datos, y mientras estén allí, la red neuronal aprenderá a usarlos.

Aprendiz

 m = md.get_learner (emb_szs, len (df.columns) -len (cat_vars), 
 0.04, 1, [1000,500][0.001,0.01]y_range = y_range) 
 m.summary ()

emb_szs incrustación tamaño

len (df.columns) -len (cat_vars) número de variables continuas en el marco de datos.

0.04 matriz de incrustación tiene su propia deserción y esta es la tasa de deserción.

1 cuántos productos queremos para crear, es decir, la salida de la última capa lineal que es ventas.

[1000, 500] número de activaciones en la primera capa lineal, y la segunda capa lineal.

[0.001,0.01] dropout en la primera capa lineal y la segunda capa lineal.

Tenemos una velocidad más baja, encontremos la velocidad de aprendizaje (lr = 1e-3):

Ajuste

comience con datos de muestra:

métricas esta es una métrica personalizada que especifica una función exp_rmspe que se llama al final de cada época e imprime un resultado.

ajusta todos los datos:

 m.fit (lr, 1, métricas = [exp_rmspe]) cycle_len = 1)
 [ 0.       0.00676  0.01041  0.09711] 

Al usar todos los datos de entrenamiento, obtenemos un RMSPE de 0.09711. Esto nos hubiera llevado al mejor% de la clasificación.

Así que esta es una técnica para tratar con series de tiempo y datos estructurados. Curiosamente, en comparación con el grupo que utilizó esta técnica Embebidos de Entidades de Variables Categóricas el ganador del segundo lugar hizo mucho más ingeniería de características. Los ganadores de esta competencia eran en realidad expertos en materia de previsión de ventas de logística, por lo que tenían su propio código para crear montones y montones de características.

Las personas en Pinterest que construyen un modelo muy similar para recomendaciones también dijeron que cuando cambiaron de las máquinas impulsoras de gradiente al Deep Learning, hicieron menos ingeniería de características y fue un modelo mucho más simple que requiere menos mantenimiento. Este es uno de los grandes beneficios de utilizar este enfoque para el Deep Learning, puedes obtener resultados de última generación pero con mucho menos trabajo.

¿Estamos usando alguna serie de tiempo en cualquiera de estos? Indirectamente, sí. Como acabamos de ver, tenemos un DayOfWeek, MonthOfYear, etc. en nuestras columnas y la mayoría de ellos se tratan como categorías, por lo que estamos creando una representación distribuida de enero, domingo, etc. No estamos utilizando ninguna de las técnicas clásicas de series de tiempo, todo lo que estamos haciendo son dos capas totalmente conectadas en una red neuronal. La matriz de inserción es capaz de manejar cosas como la periodicidad del día de la semana de una manera más rica que cualquier técnica de serie temporal estándar.

¿Cuál es la diferencia entre los modelos de imagen y este modelo? Hay una diferencia en la forma en que llamamos get_learner. En las imágenes solo hicimos Learner.trained y pasamos los datos:

 learn = ConvLearner.pretrained (arch, data, ps = 0., Precompute = True)

Para este tipo de modelos, de hecho para muchos los modelos, el modelo que construimos depende de los datos. En este caso, necesitamos saber qué matrices de incrustación tenemos. Entonces, en este caso, los objetos de datos crean el aprendiz:

 m = md.get_learner (emb_szs, len (df.columns) -len (cat_vars), 0.04, 1, 
                   [1000,500][0.001,0.01]y_range = y_range )

Pasos

Paso 1 . Enumere los nombres de las variables categóricas y enumere los nombres de las variables continuas y colóquelos en un marco de datos de Pandas:

 cat_vars = ['Tienda''Díadelasemana''Año''Mes''Día''Vacacionesestatales''Competición&minutos  
 & # 039; Promo2 semanas & # 039 ;, & # 039; StoreType & # 039 ;, & # 039; Surtido & # 039 ;, & # 039; PromoInterval & # 039 ;, & # 039; CompetitionOpenSinceYear & # 039 ;, & # 039; Promo2SinceYear & # 039;, 
 & # 039; Estado & # 039 ;, & # 039; Semana & # 039 ;, & # 039; Eventos & # 039 ;, & # 039; Promo_fw & # 039 ;, & # 039; Promo_bw & # 039 ;, & # 039; EstadoDiscusión_fw & # 039 ;, & # 039; StateHoliday_bw & # 039;, 
 & # 039; SchoolHoliday_fw & # 039 ;, & # 039; SchoolHoliday_bw & # 039;]
 contin_vars = ['CompetitionDistance''Temperatura_máxC''Temperatura_de_temperaturaC''Temperatura_mínimaC'
 & # 039; Infortunidad máxima & # 039 ;, & # 039; Incertidumbre_de_medio & # 039 ;, & # 039; Min_Humedad & # 039 ;, & # 039; Max_Wind_SpeedKm_h & # 039 ;, 
 & # 039; Mea n_Wind_SpeedKm_h & # 039 ;, & # 039; CloudCover & # 039 ;, & # 039; trend & # 039 ;, & # 039; trend_DE & # 039;, 
 & # 039; AfterStateHoliday & # 039 ;, & # 039; BeforeStateHoliday & # 039 ;, & # 039; Promo & # 039 ;, & # 039; SchoolHoliday & # 039;]

Paso 2 . Cree una lista de los índices de fila que desea en su conjunto de validación:

 val_idx = np.flatnonzero (
 (df.index  = datetime.datetime (2014,8,1)))

Paso 3 . Llame a esta línea exacta de código:

md = ColumnarModelData.from_data_frame (RUTA, val_idx, df, 
 yl.astype (np.float32), cat_flds = cat_vars, bs = 128, 
 test_df = df_test) [19659007]  Paso 4 . Cree una lista de qué tamaño desea que tenga cada matriz de inserción:
emb_szs = [(c, min(50, (c+1)//2)) for _,c in cat_sz]
 emb_szs 
 [(111650)
 (8, 4), 
 (4, 2) , 
 (13, 7), 
 (32, 16), 
 (3, 2), 
 (26, 13), 
 (27, 14), 
 ( 5, 3), 
 (4, 2), 
 (4, 2), 
 (24, 12), 
 (9, 5), 
 (13, 7), 
 (53, 27), 
 (22, 11), 
 (7, 4), 
 (7, 4), 
 (4, 2), ... [19659007]  Paso 5 . Llame a get_learner: puede usar estos parámetros exactos para empezar, si usa overfits, puede jugar con ellos.
 m = md.get_learner (emb_szs, len (df.columns) -len (cat_vars), 0.04, 1, 
                   [1000,500][0.001,0.01]y_range = y_range)

Paso 6 . Llamar a m.fit

 m.fit (lr, 3, metrics = [exp_rmspe])

Cómo usar el aumento de datos para este tipo de datos, y cómo funciona el abandono? No tengo idea. Puede ser que tenga que ser específico del dominio, pero él (Jeremy) nunca ha visto ningún periódico ni a nadie en la industria que haga un aumento de datos con datos estructurados y Deep Learning. Él piensa que se puede hacer, pero no lo ha visto hecho. Lo que está haciendo el abandono es arrojar la mitad de la activación de un tensor de rango uno. Lo cual también se aplica a la matriz de inclusión.

¿Cuál es la desventaja? Casi nadie está usando esto. Por qué no? Básicamente, la respuesta es que nadie en la academia está trabajando en esto porque no es algo en lo que la gente publique. As a result, there have not been really great examples people could look at and say “oh here is a technique that works well so let’s have our company implement it”. But perhaps equally importantly, until now with this Fast.ai library, there has not been any way to do it conveniently. If you wanted to implement one of these models, you had to write all the custom code yourself. Now it is 6 step process. There are a lot of big commercial and scientific opportunity to use this and solve problems that previously haven’t been solved very well.

Natural Language Processing

This is the most most up-and-coming area of deep learning and it is two or three years behind computer vision. The state of software and some of the concepts is much less mature than it is for computer vision.

One of the things you find in NLP is there are particular problems you can solve and they have particular names. There is a particular kind of problem in NLP called “language modeling” — it means building a model given a few words of a sentence, to predict what the next word is going to be.

For example when typing and you press space and the next word is suggested that is a language model.

For this exercise we downloaded 18 months papers from arXiv.org

Data:

— category of the paper. CSNI is Computer Science and Networking.

— abstract of the paper.

Let’s look at the output of a trained language model we pass the category in this case csni (computer science and networking) and some priming text:

The model learned by reading arXiv papers that somebody who is writing about computer networking would talk like this. Remember, it started out not knowing English at all. It started out with an embedding matrix for every word in English that was random. By reading lots of arXiv papers, it learned what kind of words followed others.

The model not only learned how to write English pretty well, but also after you say something like “convolutional neural network” it use parenthesis to specify an acronym “(CNN)”.

We will try to create a pre-trained model which is used to do some other tasks. For example, given IMDB movie reviews, we will figure out whether they are positive or negative. Which is a classification problem.

We would like to use a pre-trained network which at least knows how to read English. So we will train a model that predicts the next word of a sentence i.e. language model, and just like in computer vision, stick some new layers on the end and ask it to predict whether something is positive or negative.

Basically, create a language model and make it the pre-trained model for a classification model.

Why would doing directly what you want to do doesn’t work better? It just turns out it doesn’t perform well empirically. There are several reasons. First of all, we know fine-tuning a pre-trained network is really powerful. So if we can get it to learn some related tasks first, then we can use all that information to try and help it on the second task. The other reason is IMDB movie reviews are up to a 1000 words long. So after reading a 1000 words(integers) knowing nothing about how English is structured or the concept of a word or punctuation is, all you get is a 1 or a 0 (positive or negative). Trying to learn the entire structure of English and then how it expresses positive and negative sentiments from a single number is just too much to expect. By building a language model first we build a neural net that understand the English language of movie review then we hope that the things it learns will be helpful in deciding if a review is positive or negative.

Is this similar to Char-RNN by Karpathy? This is somewhat similar to Char-RNN which predicts the next letter given a number of previous letters. Language model generally work at a word level but they do not have to, and we will focus on word level modeling.

To what extent are these generated words and sentences actual copies of what it found in the training dataset? The words are definitely words it has seen before because it is not at character level so it can only give us the words it has seen before. The Sentences, there are several rigorous ways of doing it but the easiest way would be by looking at examples like above, Where it creates two categories and looking at them it creates similar concepts.

Most importantly, when we train the language model, we will have a validation set so that we are trying to predict the next word of something that has never seen before.

Examples of text classification:

  1. Hedge fund, might identify things in articles or Twitter that caused massive market drops in the past.
  2. Recognising customer service queries which tend to be associated with people who cancel their subscriptions in the next month.
  3. Classifying if documents into whether they are part of legal discovery or not.

IMDB

Imports

torchtext PyTorch’s NLP library.

Data

The large movie view dataset contains a collection of 50,000 reviews from IMDB. The dataset contains an even number of positive and negative reviews. The authors considered only highly polarized reviews. A negative review has a score ≤ 4 out of 10, and a positive review has a score ≥ 7 out of 10. Neutral reviews are not included in the dataset. The dataset is divided into training and test sets. The training set is the same 25,000 labeled reviews.

The sentiment classification task consists of predicting the polarity (positive or negative) of a given text.

However, before we try to classify sentimentwe will simply try to create a language model; that is, a model that can predict the next word in a sentence. ¿Por qué? Because our model first needs to understand the structure of English, before we can expect it to recognize positive vs negative sentiment.

So our plan of attack is the same as we used for Dogs v Cats: pretrain a model to do one thing (predict the next word), and fine tune it to do something else (classify sentiment).

Unfortunately, there are no good pre-trained language models available to download, so we need to create our own.

We do not have separate test and validation in this case. The training directory has bunch of files in it representing movie reviews:

Checking out an example of a movie review:

let’s check how many words are in the training dataset and test dataset respectively:

Before we can analyze text, we must first tokenize it. This refers to the process of splitting a sentence into an array of words or more generally, into an array of tokens.

A good tokenizer will do a good job of recognizing pieces in your sentence. Each separated piece of punctuation will be separated, and each part of multi-part word will be separated as appropriate below is an example of a tokenization:

We use Pytorch’s torchtext library to preprocess our data, telling it to use the spacy library to handle tokenization.

Create a field

First, we create a torchtext fieldwhich describes how to preprocess a piece of text — in this case, we tell torchtext to make everything lowercase, and tokenize it with spacy.

TEXT = data.Field(lower=True, tokenize="spacy")

lower=True — lowercase the text

tokenize=spacy_tok — tokenize with spacy_tok

We create a ModelData object for language modeling by taking advantage of LanguageModelData, passing it our torchtext field object, and the paths to our training, test, and validation sets. In this case, we don’t have a separate test set, so we’ll just use VAL_PATH for that too.

bs=64; bptt=70
FILES = dict(train=TRN_PATH, validation=VAL_PATH, test=VAL_PATH)
md = LanguageModelData.from_text_files(PATH, TEXT, **FILES, bs=bs, bptt=bptt, min_freq=10)

PATH where the data is, where to save models e.t.c

TEXT torchtext’s Field definition of how to preprocess text.

**FILES list of all of the files we have: training, validation, and test

bs batch size

bptt Back Prop Through Time. It means how long a sentence we will stick on the GPU at once

min_freq=10 : In a moment, we are going to be replacing words with integers i.e a unique index for every word. If there are any words that occur less than 10 times, just call them unknown.

After building our ModelData object, it automatically fills the TEXT object with a very important attribute: TEXT.vocab. This is a vocabularywhich stores which words (or tokens) have been seen in the text, and how each word will be mapped to a unique integer id. We’ll need to use this information again later, so we save it.

(Technical note: python’s standard Pickle library can’t handle this correctly, so at the top of this notebook we used the dill library instead and imported it as pickle).

This is the start of the mapping from integer IDs to unique tokens:

vocab let’s us take a word and match it to an integer and an integer to a word. We will work using integers.

Is it common to do any stemming or lemma-tizing? Not really, no. Generally tokenization is what we want. To keep it as general as possible, we want to know what is coming next so whether it is future tense or past tense or plural or singular, we don’t really know which things are going to be interesting and which are not, so it seems that it is generally best to leave it alone as much as possible.

When dealing with natural language, isn’t context important? Why are we tokenizing and looking at individual word? No, we are not looking at individual word — they are still in order. Just because we replaced I with a number 12, they are still in that order.

There is a different way of dealing with natural language called “bag of words” and they do throw away the order and context. In the Machine Learning course, we will be learning about working with bag of words representations but they are no longer useful or in the verge of becoming no longer useful. We are starting to learn how to use deep learning to use context properly.

Batch size and Back Prop Through Time (BPTT)

What happens in a language model is even though we have lots of movie reviews, they all get concatenated together into one big block of text. So we predict the next word in this huge long thing which is all of the IMDB movie reviews concatenated together.

We start with a big block of text with for example 64 million words. We split up the concatenated reviews into batches. In this case, we will split it to 64 sections. We then move each section underneath the previous one, and transpose it. We end up with a matrix which is 1 million by 64. We then grab a little chunk at time and those chunk lengths are approximately equal to BPTT(this changes with every epoch). We grab a little 70 long section and that is the first thing we chuck into our GPU i.e. the batch.

Our LanguageModelData object will create batches with 64 columns (that’s our batch size), and varying sequence lengths of around 80 tokens (that’s our bptt parameter - backprop through time).

Each batch also contains the exact same data as labels, but one word later in the text — since we’re trying to always predict the next word. The labels are flattened into a 1d array.

We grab our first training batch by wrapping the data loader(md.trn_dl) with iter then calling next

We get back a 77 by 64 tensor which is approximately 70 rows but not exactly.

Torchtext randomly change the bptt number every time so each epoch it gets slightly different bits of text — similar to shuffling images in computer vision. We cannot randomly shuffle the words because they need to be in the right order, so instead, we randomly move their breakpoints a little bit.

77 represents the first 77 words of the first movie review.

Why not split by a sentence? Not really. Remember, we are using columns. So each of our column is of length about 1 million, so although it is true that those columns are not always exactly finishing on a full stop, they are so long we do not care. Each column contains multiple sentences.

Creating a model

Now that we have a model data object that can feed us batches, we can create a model. First, we are going to create an embedding matrix.

4602 number of batches

34945 number of unique tokens in the vocab (unique words have to appear at least 10 times min_freq=10 otherwise they will be replased with Unk)

1 length of the dataset i.e the whole corpus

20621966 number of words in the corpus .

34945 is used to create an embedding matrix:

Each word gets an embedding vector. This is a categorical variable it is just a very high cardinality categorical variable. It is 34945 categorical variable that is why we create an embedding matrix for it.

We have a number of parameters to set:

em_sz = 200  # size of each embedding vector
nh = 500     # number of hidden activations per layer
nl = 3       # number of layers

The embedding size is 200 which is much bigger than our previous embedding vectors. Not surprising because a word has a lot more nuance to it than the concept of Sunday.

Generally, an embedding size for a word will be somewhere between 50 and 600.

Researchers have found that large amounts of momentum don’t work well with these kinds of RNN (Recurrent neural networks) models, so we create a version of the Adam optimizer with less momentum than it’s default of 0.9.

opt_fn = partial(optim.Adam, betas=(0.7, 0.99))

Fastai uses a variant of the state of the art AWD LSTM Language Model developed by Stephen Merity. A key feature of this model is that it provides excellent regularization through Dropout. There is no simple way known (yet!) to find the best values of the dropout parameters below — you just have to experiment…

However, the other parameters (alpha, beta, and clip) shouldn’t generally need tuning

If you try to build an NLP model and you are under-fitting, then decrease all these dropouts, if overfitting, then increase all these dropouts in roughly this ratio.

There are other kind of ways we can avoid overfitting. For now, learner.reg_fn = partial(seq2seq_reg, alpha=2, beta=1) works reliably so all of your NLP models probably want this particular line.

learner.clip=0.3 when you look at your gradients and you multiply them by the learning rate and decide how much to update your weights by, this will not let them be more than 0.3. Prevents us from taking too big steps (high learning rate).

There are word embedding out there such as Word2vec or GloVe. How are they different from this? And why not initialize the weights with those initially? People have pre-trained these embedding matrices before to do various other tasks. They are not called pre-trained models; they are just a pre-trained embedding matrix and you can download them. There is no reason we could not download them. Building a whole pre-trained model in this way did not seem to benefit much if at all from using pre-trained word vectors; where else using a whole pre-trained language model made a much bigger difference. Maybe we can combine both to make them a little better still.

What is the architecture of the model? It is a recurrent neural network using something called LSTM (Long Short Term Memory).

Fitting the model

learner.fit(3e-3, 4, wds=1e-6, cycle_len=1, cycle_mult=2)
learner.save_encoder('adam1_enc')
learner.load_encoder('adam1_enc')
learner.fit(3e-3, 1, wds=1e-6, cycle_len=10)

In the sentiment analysis section, we’ll just need half of the language model — the encoderso we save that part:

learner.save_encoder('adam3_10_enc')
learner.load_encoder('adam3_10_enc')

Language modeling accuracy is generally measured using the metric perplexitywhich is simply exp() of the loss function we used.

math.exp(4.165)
64.39268 24434624
pickle.dump(TEXT, open(f'{PATH}models/TEXT.pkl','wb'))

Testing

We can play around with our language model a bit to check it seems to be working OK. First, let’s create a short bit of text to ‘prime’ a set of predictions. We’ll use our torchtext field to numericalize it so we can feed it to our language model.

We haven’t yet added methods to make it easy to test a language model, so we’ll need to manually go through the steps:

Let’s see what the top 10 predictions were for the next word after our short text:

Let’s see if our model can generate a bit more text all by itself:

Sentiment Analysis

We have a pre-trained language model and now we want to fine-tune it to do sentiment classification.We’ll need the saved vocab from the language model, since we need to ensure the same words map to the same IDs.

TEXT = pickle.load(open(f'{PATH}models/TEXT.pkl','rb'))

sequential=False tells torchtext that a text field should be tokenized (in this case, we just want to store the ‘positive’ or ‘negative’ single label).

We need to not treat the whole thing as one big piece of text but every review is separate because each one has a different sentiment attached to it.

splits is a torchtext method that creates train, test, and validation sets. The IMDB dataset is built into torchtext, so we can take advantage of that. Take a look at lang_model-arxiv.ipynb to see how to define your own fastai/torchtext datasets.

Splits allows us to look at a single label t.label and some of the text t.text

fastai can create a ModelData object directly from torchtext splits that we can train on md2:

get_model gets us our learner, then we can load into it the pre-trained language model m3.load_encoder(f’adam3_10_enc’).

Because we’re fine-tuning a pre-trained model, we’ll use differential learning rates, and also increase the max gradient for clipping, to allow the SGDR to work better.

We make sure all except the last layer is frozen. Then we train a bit, unfreeze it, train it a bit. The nice thing is once you have got a pre-trained language model, it actually trains really fast.

A recent paper from Bradbury et al, Learned in translation: contextualized word vectorshas a handy summary of the latest academic research in solving this IMDB sentiment analysis problem. Many of the latest algorithms shown are tuned for this specific problem.

As you see, we just got a new state of the art result in sentiment analysis, decreasing the error from 5.9% to 5.5%! You should be able to get similarly world-class results on other NLP classification problems using the same basic steps.

There are many opportunities to further improve this:

For example we could start training language models that look at lots of medical journals and then make a downloadable medical language model that then anybody could use to fine-tune on a prostate cancer subset of medical literature.

We could also combine this with pre-trained word vectors.

We could have pre-trained a Wikipedia corpus language model and then fine-tuned it into an IMDB language model, and then fine-tune that into an IMDB sentiment analysis model and we would have gotten something better than this.

Collaborative Filtering

Data:

Movie lens data

http://files.grouplens.org/datasets/movielens/ml-latest-small.zip

path='data/ml-latest-small/'

It contains a userId the movie movieId r ating and timestamp

Our goal will be for some user-movie combination we have not seen before, we have to predict if they will like it. This is how recommendation engines are built.

Let’s read the movie names too:

We will create(in the next lesson) a kind of cross tab of users by movies:

Thanks for reading! follow @itsmuriuki.

Back to learning!


Deep Learning; Personal Notes Part 1 Lesson 4: Structured learning, Natural language Processing… was originally published in Towards Data Science on Medium, where people are continuing the conversation by highlighting and responding to this story.