FastAI Machine Learning (Lección 1)
Uno de los cursos que se dan en AI Saturdays Guayaquil, como también en los capítulos de otras ciudades alrededor del mundo, es el mooc de “Introduction to Machine Learning for Coders” de FastAI. Este curso es gratuito y cualquiera lo puede seguir. Para ayudar a cualquier persona a seguir este curso a solucionar cualquiera de los problemas que se pueden encontrar y aclarar dudas, decidí escribir mis notas acerca de los vídeos de la primera Lección “Introducción a Random Forest”.
La Lección 1 te mostrará cómo crear un “bosque aleatorio” (Random Forest), quizás el modelo de aprendizaje automático más aplicable, para crear una solución para la competencia Kaggle de “Bull Book for Bulldozers”, que te llevará al 25% superior en la tabla de líderes. Aprenderás cómo usar un cuaderno Jupyter para crear y analizar modelos, cómo descargar datos y otras habilidades básicas que necesita para comenzar a practicar el aprendizaje automático en la práctica.
Paso 1: Configurar el entorno con las bibliotecas requeridas
Hay varias opciones de plataformas para poder seguir este curso, entre las que están:
- Google Colab (gratuita).
- Jupyter Notebook en tu propio ordenador (gratuito).
- Crestle (GPU $0.59/hora).
- Paperspace (GPU $0.51/hora).
- Etc.
Les mostrare como ejecutar la lección 1 en las dos plataformas gratuitas (Google Colab y Jupyter Notebook).
Configuración de Jupyer Notebook (en tu propio ordenador)
Si bien Windows no es oficialmente compatible con Fastai o con las lecciones en esta etapa, parece que está funcionando ahora. Aquí les dejo instrucciones para comenzar a correr las leciones en una GPU y en una CPU en Windows:
GPU
1- Debes tener una GPU de Nvidia y haber instalado los controladores de Nvidia más recientes.
2- Instala Anaconda (Python 3.7) utilizando el instalador gráfico de 64 bits. Elije la opción de instalación para “solo este usuario”. Te puede ser útil la guía “Empezando a usar Jupyter Notebook para Python (Parte 1 — Instalación)”.
3- Instala Git para windows.
4- Ejecuta el “Anaconda Prompt” desde el menú de inicio y escribe:
git clone https://github.com/fastai/fastai.git
Este comando te clonara el repositorio del curso de Fastai en tu ordenador.
5- Cuando el repositorio este clonado, estas listo para configurar Fastai:
cd fastai
conda env update
5- Activa tu nuevo entorno (debes ejecutar este comando siempre que vayas a trabajar con Fastai).
activate fastai
6- Instala widgets ipython en jupyter:
jupyter nbextension enable --py widgetsnbextension --sys-prefix
7- Reemplaza el enlace simbólico de Linux por uno de Windows (ten en cuenta que esto requiere un símbolo de sistema ejecutado como administrador si no tienes una versión completamente actualizada de Windows 10):
cd courses\ml1
del fastai
mklink /d fastai ..\..\old\fastai
cd ..\..
8- ¡Eso es! Debería estar listo para escribir
jupyter notebook
Se abrirá el entorno de Jupyter. Busca la carpeta de los cursos y abre el cuaderno “lesson1-rf”.
CPU
1- Repite los pasos de configuración para GPU hasta el paso 4 (Ejecuta el “Anaconda Prompt” desde el menú de inicio y escribe:).
2- Cuando el repositorio este clonado, estas listo para configurar Fastai:
conda env update -f environment-cpu.yml
Importante: usamos el archivo environment-cpu.yml, porque vamos a usar una CPU, no una GPU.
3- Activa tu nuevo entorno (debes ejecutar este comando siempre que vayas a trabajar con Fastai).
conda activate fastai-cpu
4- Instala widgets ipython en jupyter:
jupyter nbextension enable --py widgetsnbextension --sys-prefix
5- Reemplaza el enlace simbólico de Linux por uno de Windows (ten en cuenta que esto requiere un símbolo de sistema ejecutado como administrador si no tienes una versión completamente actualizada de Windows 10):
cd courses\ml1
del fastai
mklink /d fastai ..\..\old\fastai
cd ..\..
6- ¡Eso es! Debería estar listo para escribir
jupyter notebook
Se abrirá el entorno de Jupyter. Busca la carpeta de los cursos y abre el cuaderno “lesson1-rf”.
Configuración usando Google Colab
Paso 1: Acceder a Colab
1- En primer lugar, debe iniciar sesión en tu cuenta de Google si no has iniciado sesión de forma predeterminada. Debe realizar este paso antes de abrir Colab, de lo contrario, los cuadernos no funcionarán. Puedes iniciar sesión aquí.
2- A continuación, dirígete a la página de bienvenida de Colab y has clic en “Github”. En el ‘Ingresa una URL de GitHub o busca por organización o usuario’ ingresa ‘fastai/’. En repositorio selecciona fastai/fastai y veras los cuadernos de los cursos de ml1, dl1 y dl2. Selecciona la lección “lesson1-rf.ipynb”.
Deberías ver tu cuaderno ahora. Antes de ejecutar cualquier cosa, debe decirle a Colab que estas interesado en utilizar una GPU. Puedes hacerlo haciendo clic en la pestaña “Tiempo de ejecución” y seleccionando “Cambiar tipo de tiempo de ejecución”. Se abrirá una ventana emergente con un menú desplegable. Seleccione ‘GPU’ en el menú y has clic en ‘Guardar’.
Paso 2: Guarda tu trabajo
Si abriste una libreta de Github, deberás guardar tu trabajo en Google Drive. Puedes hacer esto haciendo clic en “Archivo” y luego en “Guardar”. Deberías ver una ventana emergente con el siguiente mensaje:
Paso 3: Configurar tu instancia
Antes de comenzar a utilizar tu cuaderno, debes instalar los paquetes necesarios. Puedes hacer esto creando una celda de código y ejecutando:
!pip install fastai==0.7.0
Lección 1 (Blue Book for Bulldozers)
Este es el primer proyecto de Kaggle que Jeremy analizó en la serie “Introduction to Machine Learning for Coders”. El objetivo de este proyecto es predecir el “precio de venta”, que es la variable dependiente del valor continuo. Este proyecto tiene datos que se han recopilado durante muchos años. El algoritmo que se utiliza en la tarea es “Random Forest”. Jeremy enseguida salta al punto en que “Random Forest” puede usarse para desarrollar un modelo predictivo exitoso.
Random Forest también conocidos en castellano como ‘“Bosques Aleatorios”’ es una combinación de árboles predictores tal que cada árbol depende de los valores de un vector aleatorio probado independientemente y con la misma distribución para cada uno de estos. Es una modificación sustancial de bagging que construye una larga colección de árboles no correlacionados y luego los promedia.
Aquí hay una breve introducción de las palabras de Jeremy Howard:
- El bosque aleatorio es un tipo de técnica de aprendizaje automático universal.
- Se puede utilizar para problemas de regresión (el objetivo es una variable continua) o la clasificación (el objetivo es una variable categórica).
- También funciona con columnas de cualquier tipo, como valores de píxeles, códigos postales, ingresos, etc.
- En general, el bosque aleatorio no se sobre ajusta (overfit)(es muy fácil evitar que se sobre ajuste demasiado).
- No necesita un conjunto de validación separado en general. Puede indicarle qué tan bien se generaliza incluso si solo tiene un conjunto de datos.
- Tiene pocas (si alguna) suposiciones estadísticas (no asume que los datos se distribuyen normalmente, los datos son lineales o que necesita especificar las interacciones).
- Requiere muy pocas características tácticas de ingeniería, por lo que es un excelente lugar para comenzar.
Suena como una técnica Fascinante, ¿verdad?
Pues empecemos.
Importar librerías
Vas encontrar la siguiente celda:
%load_ext autoreload
%autoreload 2%matplotlib inline
El comando “autoreload” te ayuda a cargar automáticamente los módulos antes de ingresar a la ejecución, “autoreload 2” recarga todos los módulos (excepto los excluidos por %aimport) cada vez antes de ejecutar el código Python escrito (más información aquí) y “matplotlib” es un paquete de trazado que ayuda a visualizar tus datos de la manera más fácil posible.
Ahora debes importar las librerías:
from fastai.imports import *
from fastai.structured import *from pandas_summary import DataFrameSummary
from sklearn.ensemble import RandomForestRegressor, RandomForestClassifier
from IPython.display import displayfrom sklearn import metrics
Si estas usando un cuaderno de Jupyter en tu ordenador puede que necesites instalar ciertas librerías que necesita Fastai y no las tienes en tu entorno. Posibles problemas y soluciones, aquí.
Obteniendo los datos
Kaggle: Problemas del mundo real publicados por una empresa / instituto.
Estos están realmente cerca de los problemas del mundo real, te permite medirte contra otros competidores y es perfecto para comprobar tus habilidades.
Jeremy: “He aprendido más de las competiciones Kaggle que cualquier otra cosa que haya hecho en toda mi vida”
Para descargar los datos de entrenamiento desde Kaggle debes tener creada una cuenta. Ingresar a la página de la competición de Blue Book for Bulldozers y aceptar los términos y condiciones.
Para descargar los datos de entrenamiento tienes tres maneras de hacerlo y va depender de si estas usando Colab o tu ordenador (Jupyter Notebook).
1- Google Colab: Debes instalar el paquete kaggle-cli (parece que dejo de funcionar), creando una línea de código y escribiendo:
!pip install kaggle-cli
# always use ! to run bash commands from Notebook
Y obtienes los datos escribiendo:
!kg download -u <<Kaggle UserName>> -p <<Kaggle Password>> -c bluebook-for-bulldozers -f Train.zip
Una vez que hayamos descargado los datos, vamos a extraer y organizar los datos para el trabajo.
!mkdir -p data/bulldozers/
!mv Train.zip data/bulldozers/
!unzip data/bulldozers/Train.zip -d data/bulldozers/
2-Google Colab: Usamos !wget para descargar el archivo desde un repositorio y !tar para descomprimirlo (usa este método hasta que vuelva a funcionar la librería kaggle-cli).
!wget https://raw.githubusercontent.com/Giffy/Personal_dataset_repository/master/train.tar.gz
!tar xvf train.tar.gz
3- Jupyter Notebook: y en la pestaña de datos (en el concurso de Kaggle)descargar el archivo Train.zip. Descomprime este archivo en una carpeta llamada “data/bulldozers/” (debes crearla).
Veamos los datos
a) Primero ponemos los datos en la memoria:
Se establece la ruta en nuestro código:
PATH = “data/bulldozers/”
Leemos el archivo de datos utilizando Pandas para permitirnos analizar y procesar previamente los datos. Pandas es la mejor librería para trabajar con datos tabulares y te permite leer archivos CSV.
df_raw = pd.read_csv(f'{PATH}Train.csv', low_memory=False,
parse_dates=["saledate"])
low_memory=False (permite cargar más detalles a la memoria).
b) Revisamos los datos y obtenemos información de alto nivel para tener una idea de lo que estamos tratando.
df_raw.info()
La salida es la siguiente:
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 401125 entries, 0 to 401124
Data columns (total 53 columns):
SalesID 401125 non-null int64
SalePrice 401125 non-null int64
MachineID 401125 non-null int64
ModelID 401125 non-null int64
datasource 401125 non-null int64
auctioneerID 380989 non-null float64
YearMade 401125 non-null int64
MachineHoursCurrentMeter 142765 non-null float64
UsageBand 69639 non-null object
saledate 401125 non-null datetime64[ns]
fiModelDesc 401125 non-null object
fiBaseModel 401125 non-null object
fiSecondaryDesc 263934 non-null object
fiModelSeries 56908 non-null object
fiModelDescriptor 71919 non-null object
ProductSize 190350 non-null object
fiProductClassDesc 401125 non-null object
state 401125 non-null object
ProductGroup 401125 non-null object
ProductGroupDesc 401125 non-null object
Drive_System 104361 non-null object
Enclosure 400800 non-null object
Forks 192077 non-null object
Pad_Type 79134 non-null object
Ride_Control 148606 non-null object
Stick 79134 non-null object
Transmission 183230 non-null object
Turbocharged 79134 non-null object
Blade_Extension 25219 non-null object
Blade_Width 25219 non-null object
Enclosure_Type 25219 non-null object
Engine_Horsepower 25219 non-null object
Hydraulics 320570 non-null object
Pushblock 25219 non-null object
Ripper 104137 non-null object
Scarifier 25230 non-null object
Tip_Control 25219 non-null object
Tire_Size 94718 non-null object
Coupler 213952 non-null object
Coupler_System 43458 non-null object
Grouser_Tracks 43362 non-null object
Hydraulics_Flow 43362 non-null object
Track_Type 99153 non-null object
Undercarriage_Pad_Width 99872 non-null object
Stick_Length 99218 non-null object
Thumb 99288 non-null object
Pattern_Changer 99218 non-null object
Grouser_Type 99153 non-null object
Backhoe_Mounting 78672 non-null object
Blade_Type 79833 non-null object
Travel_Controls 79834 non-null object
Differential_Type 69411 non-null object
Steering_Controls 69369 non-null object
dtypes: datetime64[ns](1), float64(2), int64(6), object(44)
memory usage: 162.2+ MB
Podemos ver que tenemos 401125 elementos de datos con información distribuida en 53 columnas y tipos de datos divididos: datetime64[ns](1), float64(2), int64(6), object(44).
Pre-procesamiento de los datos
a) Convertir la variable dependiente usando la métrica RMSLE
Es importante tener en cuenta qué métrica se está utilizando para un proyecto. En general, la selección de la métrica (s) es una parte importante de la configuración del proyecto. Sin embargo, en este caso, Kaggle nos dice qué métrica usar: RMSLE (Error logarítmico medio cuadrático) entre los precios de subasta reales y previstos. Por lo tanto, tomamos el registro de los precios para que RMSE nos brinde lo que necesitamos.
df_raw.SalePrice = np.log(df_raw.SalePrice)
b) Extraer información adicional del campo de fecha
Antes de realizar cualquier manipulación / procesamiento de datos, debemos comprender la declaración del problema. De la descripción dada en Kaggle, entendemos que nuestro modelo debe aprender sobre los precios del historial de ventas y predecir el precio de venta futuro. Por lo tanto, cualquier fecha / período de ventas de la información podría ser uno de los factores importantes y deberíamos intentar extraer la mayor cantidad de información posible a partir de la fecha.
Fastai tiene una función incorporada que extrae información de la fecha como día de la semana, día del año, fin de mes, inicio de mes, fin de año, fin de año, etc. La función add_datepart de Fastai toma un campo de fecha como entrada y extrae esta información variada de eso.
add_datepart(df_raw, 'saledate')
Podemos observar las nuevas columnas creadas escribiendo
df_raw.columns
c) Trabajar con Strings
Random Forest espera datos numéricos. Así que necesitamos convertir datos de objetos, etc. a números. Pandas y Scikit disponen de varios métodos para preprocesar los datos, pero aquí usaremos Fastai, que proporciona algunos métodos de envoltura sorprendentes para realizar el preprocesamiento que cubre la mayoría de las acciones de preprocesamiento de forma predeterminada.
train_cats(df_raw)
Esta función toma campos no numéricos (/ no datetime) y los transforma al tipo de datos Categoría. Como se ve a continuación, todos los campos de objetos se transformaron en datos categóricos.
d) Ordenar las categorías
Al ejecutar
df_raw.UsageBand.cat.categories
veremos la salida
Index(['High', 'Low', 'Medium'], dtype='object')
Y podemos observar que la organización de las categorías no es la adecuada por lo que podemos re ordenarla escribiendo
df_raw.UsageBand.cat.set_categories(['High', 'Medium', 'Low'], ordered=True, inplace=True)
inplace=True, modifica el DataFrame actual en lugar de crear uno nuevo.
e) Reparando los datos faltantes “missing values (valores continuos) y convirtiendo todos los datos de tipo de categoría a tipo de datos numéricos
Usamos la función proc_df de Fastai para dividir los datos en datos de la variable dependiente (y) y los datos transformados a totalmente numéricos (x).
Primero corrige los datos faltantes al actualizarlos por la mediana de los campos numéricos y luego reemplazar los datos categóricos por sus códigos numéricos. Ten en cuenta que no tomamos ninguna medida para que falten datos categóricos, ya que cuando convertimos los datos de Categoría a su código, los datos que faltan se reemplazan por -1.
Aquí proporcionamos 2 entradas para proc_df. Primero, el marco de datos de entrada cuyos datos se cambiarán a numérico y se cargarán en df_processed y segundo el nombre del campo de destino que se dividirá del marco de datos y se guardará por separado (df_target).
df, y, nas = proc_df(df_raw, 'SalePrice')
Construimos el modelo
Con los datos modificados para poder usados por los algoritmos de ML, ajustamos los datos para Random Forest en este caso como un Regresor, ya que necesitamos predecir el precio (variable continua).
m = RandomForestRegressor(n_jobs=-1)
m.fit(df, y)
m.score(df,y)
Aquí ejecutamos el entrenamiento en procesos separaos para todos los núcleos de CPU disponibles definiendo n_jobs = -1.
Podemos observar que obtenemos un resultado del
0.9830970922936578
WOOOOOOOOWW un 98% sin hacer mucho(1 es el mejor y 0 el peor)!!
Revisar Modelo
Pues sí, pero ahora debemos de ver si nuestro modelo no esta sobre entrenado (overfitting), es decir que no generaliza a nuevos datos.
Para esto podemos crear un set de validación ordenado por fecha. Las 12000 fechas más recientes serán el conjunto de validación.
def split_vals(a,n): return a[:n].copy(), a[n:].copy()n_valid = 12000 # same as Kaggle's test set size
n_trn = len(df)-n_valid
raw_train, raw_valid = split_vals(df_raw, n_trn)
X_train, X_valid = split_vals(df, n_trn)
y_train, y_valid = split_vals(y, n_trn)X_train.shape, y_train.shape, X_valid.shape
RESULTADO FINAL
Probemos de nuevo nuestro modelo, esta vez con conjuntos de validación y entrenamiento separados.
Creamos nuestra función para poder trabajar con la métrica RMSLE
def rmse(x,y): return math.sqrt(((x-y)**2).mean())def print_score(m):
res = [rmse(m.predict(X_train), y_train),
rmse(m.predict(X_valid), y_valid),
m.score(X_train, y_train), m.score(X_valid,
y_valid)]
if hasattr(m, 'oob_score_'): res.append(m.oob_score_)
print(res)
Volvemos a ejecutar el entrenamiento con Random Forest
m = RandomForestRegressor(n_jobs=-1)
%time m.fit(X_train, y_train)
print_score(m)
Obteniendo
[0.09044244804386327, 0.2508166961122146, 0.98290459302099709, 0.88765316048270615]
El segundo valor mostrado es el RMSLE entre los datos de validación.
Con 0.25 nos coloca en el Top 25% del concurso de Kaggle.
Gracias a Fastai, ahora podemos configurar un entorno desde cero, procesar datos y entrenar un modelo de aprendizaje automático con resultados muy buenos con pocas líneas de código.
Antes de la siguiente clase
Por favor, repite este proceso para resolver la mayor cantidad posible de competiciones Kaggle. Lo que probablemente sucederá es que te sorprenderá muchísimo. Nos vemos en la siguiente lección…