¿Dos horas más tarde y sigue funcionando? Cómo mantener tu sklearn.fit bajo control.

Escrito por Gabriel Lerner y Nathan Toubiana

Todo lo que quería hacer era probar su código, pero dos horas más tarde, su ajuste de Scikit-learn no muestra signos de terminar. Scitime es un paquete que predice el tiempo de ejecución de los algoritmos de aprendizaje automático para que un ajuste interminable no lo pille desprevenido.

Ya sea que esté en el proceso de crear un modelo de aprendizaje automático o implementar su código en producción, el conocimiento de cuánto tardará su algoritmo en adaptarse es clave para optimizar su flujo de trabajo. Con Scitime, podrá estimar en cuestión de segundos cuánto tiempo debe llevar el ajuste para los algoritmos de Scikit Learn más utilizados.

Se han publicado un par de artículos de investigación (como este) sobre ese tema. Sin embargo, hasta donde sabemos, no existe una implementación práctica. El objetivo aquí no es predecir el tiempo de ejecución exacto del algoritmo, sino más bien dar una aproximación aproximada.

¿Qué es Scitime?

Scitime es un paquete de Python que requiere al menos Python 3.6 con dependencias de pandas, scikit-learn, psutil y joblib. Encontrará el repositorio Scitime aquí.

La función principal de este paquete se llama " tiempo ". Dado un vector de matriz X, el vector estimado Y junto con el modelo de Scikit Learn de su elección, el tiempo generará tanto el tiempo estimado como su intervalo de confianza. Actualmente, el paquete admite los siguientes algoritmos de Scikit Learn con planes de agregar más en un futuro próximo:

  • KMeans
  • AleatorioBosqueRegresor
  • SVC
  • RandomForestClassifier

Inicio rápido

Instalemos el paquete y ejecutemos lo básico.

Primero cree un nuevo virtualenv (¡esto es opcional, para evitar conflictos de versiones!)

❱ virtualenv env❱ source env/bin/activate

y luego ejecuta:

❱ (env) pip install scitime

o con conda:

❱ (env) conda install -c conda-forge scitime

Una vez que la instalación se haya realizado correctamente, estará listo para estimar el tiempo de su primer algoritmo.

Supongamos que quiere entrenar un clúster de kmeans, por ejemplo. Primero necesitaría importar el paquete scikit-learn, establecer los parámetros kmeans y también elegir las entradas (también conocidas como X) , aquí generadas aleatoriamente por simplicidad.

Ejecutar esto antes de hacer el ajuste real daría una aproximación del tiempo de ejecución:

Como puede ver, ¡puede obtener esta información solo en una línea adicional de código! Las entradas de la función de tiempo son exactamente lo que se necesita para ejecutar el ajuste (es decir, el algoritmo en sí y X), lo que lo hace aún más fácil de usar.

Mirando más de cerca la última línea del código anterior, la primera salida ( estimación: 15 segundos en este caso) es el tiempo de ejecución previsto que está buscando. Scitime también lo generará con un intervalo de confianza ( límite inferior y límite superior: 10 y 30 segundos en este caso). Siempre puede compararlo con el tiempo de entrenamiento real ejecutando:

En este caso, en nuestra máquina local, la estimación es de 15 segundos, mientras que el tiempo de entrenamiento real es de 20 segundos (pero es posible que no obtenga los mismos resultados, como explicaremos más adelante).

Como guía de uso rápido:

Clase de estimador (meta_algo, detallado, de confianza):

  • meta_algo : el estimador utilizado para predecir el tiempo, ya sea 'RF' o 'NN' (ver detalles en el siguiente párrafo) - por defecto es 'RF'
  • detallado : control de la cantidad de salida de registro (0, 1, 2 o 3); el valor predeterminado es 0
  • Confianza : Confianza para los intervalos - predeterminado al 95%

Función estimator.time (algo, X, y):

  • algo : algo cuyo tiempo de ejecución el usuario quiere predecir
  • X : gran variedad de entradas a entrenar
  • y : una gran variedad de salidas a entrenar (establecido en Ninguno si el algoritmo no está supervisado)

Nota rápida: para evitar confusiones, vale la pena resaltar que algo y meta_algo son dos cosas diferentes aquí: algo es el algoritmo cuyo tiempo de ejecución queremos estimar, meta_algo es el algoritmo que utiliza Scitime para predecir el tiempo de ejecución.

Cómo funciona Scitime

Podemos predecir el tiempo de ejecución para que se ajuste utilizando nuestro propio estimador, lo llamamos meta algoritmo ( meta_algo ), cuyos pesos se almacenan en un archivo pickle dedicado en los metadatos del paquete. Para cada modelo de Scikit Learn, encontrará un archivo de pickle metaalgo correspondiente en la base de código de Scitime.

Podrías estar pensando:

¿Por qué no estimar manualmente la complejidad del tiempo con notaciones O grandes?

Ese es un buen punto. Es una forma válida de abordar el problema y algo en lo que pensamos al principio del proyecto. Sin embargo, una cosa es que necesitaríamos formular la complejidad explícitamente para cada algoritmo y conjunto de parámetros, lo cual es bastante desafiante en algunos casos, dada la cantidad de factores que juegan un papel en el tiempo de ejecución. El meta_algo básicamente hace todo el trabajo por ti, y te explicaremos cómo.

Se han entrenado dos tipos de metaalgos para estimar el tiempo de adaptación (ambos de Scikit Learn):

  • El metaalgo de RF , un estimador RandomForestRegressor.
  • El metaalgo NN , un estimador MLPRegressor básico.

Estos metaalgos estiman el tiempo de adaptación utilizando una serie de características 'meta'. A continuación, se muestra un resumen de cómo creamos estas funciones:

En primer lugar, buscamos la forma de su matriz de entrada X y el vector de salida y. En segundo lugar, los parámetros que ingresa al modelo de Scikit Learn se tienen en cuenta, ya que también afectarán el tiempo de capacitación. Por último, también se considera su hardware específico, exclusivo de su máquina, como la memoria disponible y los recuentos de cpu.

Como se mostró anteriormente, también proporcionamos intervalos de confianza en la predicción de tiempo. La forma en que se calculan depende del metaalgo elegido:

  • Para RF , dado que cualquier regresor forestal aleatorio es una combinación de varios árboles (también llamados estimadores ), el intervalo de confianza se basará en la distribución del conjunto de predicciones calculadas por cada estimador.
  • Para NN , el proceso es un poco menos sencillo: primero calculamos un conjunto de MSE junto con el número de observaciones en un conjunto de prueba, agrupadas por intervalos de duración prevista (es decir, de 0 a 1 segundo, de 1 a 5 segundos, y así) on), y luego calculamos un t-stat para obtener los límites inferior y superior de la estimación. Como no tenemos muchos datos para modelos muy largos, el intervalo de confianza para dichos datos puede volverse muy amplio.

Como lo construimos

Podrías estar pensando:

¿Cómo obtuviste suficientes datos sobre el tiempo de entrenamiento de todos estos ajustes de sciki-learn en varios parámetros y configuraciones de hardware?

La respuesta (poco glamorosa) es que nosotros mismos generamos los datos usando una combinación de computadoras y hardware de VM para simular cuál sería el tiempo de entrenamiento en los diferentes sistemas. Luego, ajustamos nuestros metaalgos en estos puntos de datos generados aleatoriamente para construir un estimador destinado a ser confiable independientemente de su sistema.

Mientras que el archivo estimado.py maneja la predicción del tiempo de ejecución, el archivo _model.py nos ayudó a generar datos para entrenar nuestros metaalgos, usando nuestra clase de modelo dedicada. Aquí hay una muestra de código correspondiente, para kmeans:

Tenga en cuenta que también puede usar el archivo _data.py directamente con la línea de comando para generar datos o entrenar un nuevo modelo. Las instrucciones relacionadas se pueden encontrar en el archivo Readme del repositorio.

Al generar puntos de datos, puede editar los parámetros de los modelos de Scikit Learn en los que desea entrenar. Puede dirigirse a scitime / _config.json y editar los parámetros de los modelos, así como el número de filas y columnas con las que le gustaría entrenar.

Usamos una función itertool para recorrer todas las combinaciones posibles, junto con una tasa de caída establecida entre 0 y 1 para controlar la rapidez con que el bucle saltará a través de las diferentes iteraciones posibles.

¿Qué precisión tiene Scitime?

A continuación, destacamos cómo funcionan nuestras predicciones para el caso específico de kmeans. Nuestro conjunto de datos generado contiene ~ 100k puntos de datos, que dividimos en un tren y conjuntos de prueba (75% - 25%).

Agrupamos los tiempos predichos de entrenamiento por diferentes intervalos de tiempo y calculamos el MAPE y el RMSE en cada uno de esos intervalos para todos nuestros estimadores utilizando el meta-algoritmo de RF y el meta-algoritmo NN.

Tenga en cuenta que estos resultados se realizaron en un conjunto de datos restringido, por lo que pueden ser diferentes en puntos de datos inexplorados (como otros sistemas / valores extremos de ciertos parámetros del modelo). Para este conjunto de entrenamiento específico, el R cuadrado es de alrededor del 80% para NN y del 90% para RF.

Como podemos ver, no es sorprendente que la precisión sea consistentemente mayor en el tren que en la prueba, tanto para NN como para RF. También vemos que RF parece funcionar mucho mejor que NN en general. El MAPE para RF es de alrededor del 20% en el tren y del 40% en el de prueba. El NN MAPE es sorprendentemente muy alto.

Cortemos el MAPE (en el conjunto de prueba) por el número de segundos predichos:

Una cosa importante a tener en cuenta es que, en algunos casos, la predicción del tiempo es sensible al metaalgo elegido (RF o NN). En nuestra experiencia, RF se ha desempeñado muy bien dentro de los rangos de entrada del conjunto de datos, como se muestra arriba. Sin embargo, para puntos fuera de rango, NN podría funcionar mejor, como se sugiere al final del gráfico anterior. Esto explicaría por qué NN MAPE es bastante alto mientras que el RMSE es decente: se desempeña mal en valores pequeños.

Por ejemplo, si intenta predecir el tiempo de ejecución de un kmeans con parámetros predeterminados y con una matriz de entrada de unos pocos miles de líneas, el metaalgo de RF será preciso porque nuestro conjunto de datos de entrenamiento contiene puntos de datos similares. Sin embargo, para predecir parámetros muy específicos (por ejemplo, un número muy alto de clústeres), NN podría funcionar mejor porque se extrapola del conjunto de entrenamiento, mientras que RF no lo hace. NN se comporta peor en los gráficos anteriores porque estos gráficos solo se basan en datos cercanos al conjunto de entradas de los datos de entrenamiento.

Sin embargo, como se muestra en este gráfico, los valores fuera de rango (líneas finas) son extrapolados por el estimador NN, mientras que el estimador RF predice la salida por pasos.

Ahora veamos las características 'meta' más importantes para el ejemplo de kmeans:

Como podemos ver, solo 6 características representan más del 80% de la variación del modelo. Entre ellos, el más importante es un parámetro de la propia clase scikit-learn kmeans (número de clústeres), pero muchos factores externos tienen una gran influencia en el tiempo de ejecución, como el número de filas / columnas y la memoria disponible.

Limitaciones

Como se mencionó anteriormente, la primera limitación está relacionada con los intervalos de confianza: pueden ser muy amplios, especialmente para NN, y para modelos pesados ​​(eso tomaría al menos una hora).

Además, el NN podría funcionar mal en predicciones pequeñas o medianas. A veces, durante pequeñas duraciones, la NN puede incluso predecir una duración negativa, en cuyo caso cambiamos automáticamente a RF.

Otra limitación del estimador surge cuando se utilizan valores de parámetros de algoritmos "especiales". Por ejemplo, en un escenario de RandomForest, cuando max_depth se establece en None , la profundidad podría tomar cualquier valor. Esto podría resultar en un tiempo de ajuste mucho más largo, lo que es más difícil de captar para el meta algo, aunque hicimos todo lo posible para tener en cuenta.

Al ejecutar estimator.time (algo, X, y) , requerimos que el usuario ingrese el vector X e y real, lo que parece innecesario, ya que simplemente podríamos solicitar la forma de los datos para estimar el tiempo de entrenamiento. La razón de esto es que en realidad intentamos ajustar el modelo antes de predecir el tiempo de ejecución, para generar errores instantáneos. Corremos algo.fit (x, y) en un subproceso durante un segundo para comprobar si hay cualquier error ajuste hasta después de lo cual se pasa a la parte predicción. Sin embargo, hay ocasiones en las que el algoritmo (y / o la matriz de entrada) son tan grandes que ejecutar algo.fit (X, y) generará un error de memoria eventualmente, que no podemos explicar.

Mejoras futuras

La forma más efectiva y obvia de mejorar el rendimiento de nuestras predicciones actuales sería generar más puntos de datos en diferentes sistemas para soportar mejor una amplia gama de hardware / parámetros.

En un futuro próximo, buscaremos agregar más algoritmos de Scikit Learn compatibles. También podríamos implementar otros algos como lightGBM o xgboost. ¡No dude en contactarnos si hay un algoritmo que le gustaría que implementemos en las próximas iteraciones de Scitime!

Otras vías interesantes para mejorar el rendimiento del estimador serían incluir información más granular sobre la matriz de entrada, como la varianza o la correlación con la salida. Actualmente, generamos datos de forma completamente aleatoria, por lo que el tiempo de ajuste puede ser mayor que para los conjuntos de datos del mundo real. Entonces, en algunos casos, podría sobreestimar el tiempo de entrenamiento.

Además, podríamos rastrear información específica de hardware más fina, como la frecuencia de la CPU o el uso actual de la CPU.

Idealmente, dado que el algoritmo podría cambiar de una versión de scikit-learn a otra y, por lo tanto, tener un impacto en el tiempo de ejecución, también lo tendríamos en cuenta, por ejemplo, utilizando la versión como una función 'meta'.

A medida que adquirimos más datos para adaptarlos a nuestros metaalgos, podríamos pensar en utilizar metaalgos más complejos, como redes neuronales sofisticadas (utilizando técnicas de regularización como la deserción o la normalización por lotes). Incluso podríamos considerar el uso de tensorflow para ajustar el meta algoritmo (y agregarlo como opcional): no solo nos ayudaría a obtener una mejor precisión, sino que también construiría intervalos de confianza más robustos usando el abandono.

Contribuir a Scitime y enviarnos sus comentarios

Primero, cualquier tipo de retroalimentación, especialmente sobre el desempeño de las predicciones y sobre ideas para mejorar este proceso de generación de datos, es muy apreciado.

Como se mencionó anteriormente, puede usar nuestro repositorio para generar sus propios puntos de datos para entrenar su propio meta algoritmo. Al hacerlo, puede ayudar a mejorar Scitime compartiendo los puntos de datos que se encuentran en el resultado csv ( ~ / scitime / scitime / [algo] _results.csv ) para que podamos integrarlo a nuestro modelo.

Para generar sus propios datos, puede ejecutar un comando similar a este (desde la fuente del repositorio de paquetes):

❱ python _data.py --verbose 3 --algo KMeans --drop_rate 0.99

Nota: si se ejecuta directamente usando el código fuente (con la clase Model ), no olvide establecer write_csv en verdadero, de lo contrario, los puntos de datos generados no se guardarán.

Usamos problemas de GitHub para rastrear todos los errores y solicitudes de funciones. No dude en abrir un problema si ha encontrado un error o desea ver una nueva función implementada. Se puede encontrar más información sobre cómo contribuir en el repositorio Scitime.

Para problemas con las predicciones del tiempo de entrenamiento, al enviar comentarios, puede ser útil incluir el diccionario completo de parámetros que está ajustando en su modelo, para que podamos diagnosticar por qué el rendimiento es insatisfactorio para su caso de uso específico. Para hacerlo, simplemente configure el parámetro detallado en 3 y copie y pegue el registro del parámetro dic en la descripción del problema.

Encuentra la fuente del código

Encuentra la documentación

Créditos

  • Gabriel Lerner y Nathan Toubiana son los principales contribuyentes de este paquete y coautores de este artículo.
  • Un agradecimiento especial a Philippe Mizrahi por ayudarnos en el camino.
  • Gracias por toda la ayuda que recibimos de las primeras revisiones / pruebas beta