Técnica Jedi para reducir redes convolucionales: poda

Técnica Jedi para reducir redes convolucionales: poda

Te enfrentas de nuevo a la tarea de detección de objetos. La prioridad es la velocidad con una precisión aceptable. Tomas la arquitectura YOLOv3 y la reentrenas. La precisión (mAp75) es superior a 0.95. Pero el tiempo de ejecución sigue siendo lento. ¡Maldición!

Hoy omitiremos la cuantización. Pero a continuación veremos... Poda modelo — Eliminar las partes redundantes de la red para acelerar la inferencia sin perder precisión. Esto muestra claramente dónde, cuánto y cómo eliminar. Veremos cómo hacerlo manualmente y dónde se puede automatizar. Al final se incluye un repositorio de Keras.

introducción

En mi anterior trabajo, Macroscop en Perm, desarrollé la costumbre de monitorizar constantemente los tiempos de ejecución de los algoritmos. Los tiempos de ejecución de la red siempre se verifican mediante un filtro de suficiencia. Los datos de última generación en producción normalmente no superan este filtro, lo que me llevó a la poda.

La poda es un tema antiguo que se ha discutido en Conferencias de Stanford En 2017. La idea básica es reducir el tamaño de una red neuronal entrenada sin perder precisión mediante la eliminación de varios nodos. Suena interesante, pero rara vez oigo hablar de su uso. Quizás no haya suficientes implementaciones, no existan artículos en ruso o, simplemente, todo el mundo considera la poda un conocimiento especializado y prefiere no compartirlo.
Pero es difícil de averiguar.

Una mirada a la biología

Me encanta cuando las ideas de la biología se incorporan al aprendizaje profundo. Al igual que la evolución, son fiables (¿sabías que ReLU es muy similar a Función de activación neuronal en el cerebro?)

El proceso de poda de modelos también guarda cierta similitud con la biología. La respuesta de la red en este caso puede compararse con la plasticidad cerebral. El libro incluye un par de ejemplos interesantes. Norman Doidge:

  1. El cerebro de una mujer nacida con solo la mitad del cuerpo se ha reprogramado para realizar las funciones de la mitad faltante.
  2. El hombre se voló la parte del cerebro responsable de la visión. Con el tiempo, otras partes del cerebro asumieron estas funciones. (No intentaremos repetirlo).

De igual forma, puedes eliminar algunos de los haces más débiles de tu modelo. En caso de necesidad, los haces restantes pueden usarse para reemplazar los que se eliminaron.

¿Te encanta el aprendizaje por transferencia o estás aprendiendo desde cero?

Opción número uno. Estás utilizando aprendizaje por transferencia en YOLOv3, Retina, Mask-RCNN o U-Net. Sin embargo, lo más frecuente es que no necesitemos reconocer 80 clases de objetos, como en COCO. En mi experiencia, suele bastar con 1 o 2 clases. Podría parecer que una arquitectura para 80 clases es excesiva, lo que sugiere que es necesario reducirla. Además, nos gustaría hacerlo sin perder los pesos preentrenados existentes.

Opción número dos. Quizás tengas muchos datos y recursos informáticos, o simplemente necesites una arquitectura súper personalizada. No importa. Pero estás entrenando la red desde cero. El procedimiento habitual consiste en analizar la estructura de los datos, elegir una arquitectura muy potente e implementar dropout para evitar el sobreajuste. He visto valores de dropout de 0.6, Karl.

En ambos casos, la red se puede reducir. Me has motivado. Ahora veamos qué es la poda.

Algoritmo general

Decidimos que podíamos quitar los pliegues. Parece bastante sencillo:

Técnica Jedi para reducir redes convolucionales: poda

Eliminar cualquier convolución sobrecarga la red, lo que suele provocar un ligero aumento del error. Por un lado, este aumento indica la eficacia de la eliminación de convoluciones (por ejemplo, un aumento considerable indica un error). Sin embargo, un pequeño aumento del error es perfectamente aceptable y a menudo se puede corregir con un reentrenamiento ligero posterior con una tasa de aprendizaje baja. Añadamos un paso de reentrenamiento:

Técnica Jedi para reducir redes convolucionales: poda

Ahora debemos determinar cuándo queremos detener nuestro ciclo de Aprendizaje-Poda. Pueden darse casos excepcionales, como cuando necesitamos reducir la escala de la red a un tamaño y una frecuencia de ejecución específicos (por ejemplo, para dispositivos móviles). Sin embargo, lo más común es continuar el ciclo hasta que el error supere un valor aceptable. Añadamos la condición:

Técnica Jedi para reducir redes convolucionales: poda

El algoritmo está claro. Ahora veamos cómo determinar qué convoluciones eliminar.

Buscar pliegues eliminables

Necesitamos eliminar algunos paquetes. Eliminarlos todos a la ligera es una mala idea, aunque funcione. Pero si tienes algo de criterio, puedes pensarlo bien e intentar identificar los paquetes más vulnerables para eliminarlos. Hay varias opciones:

  1. Medida L1 más baja o poda de baja magnitudLa idea de que las convoluciones con valores de peso pequeños contribuyen poco a la decisión final
  2. La puntuación L1 más baja, dada la media y la desviación estándar. Complementada con una estimación de la naturaleza de la distribución.
  3. Enmascaramiento por convolución y exclusión de aquellos que tienen el menor impacto en la precisión finalDetección más precisa de pliegues insignificantes, pero requiere mucho tiempo y recursos.
  4. Otros

Cada opción tiene sus propias consideraciones de viabilidad e implementación. Aquí, consideraremos la opción con la puntuación L1 más baja.

Proceso manual para YOLOv3

La arquitectura original contiene bloques residuales. Si bien son muy útiles para redes profundas, resultan un tanto engorrosos. La dificultad radica en que no podemos eliminar las comparaciones con diferentes índices en estas capas.

Técnica Jedi para reducir redes convolucionales: poda

Por lo tanto, seleccionemos las capas de las que podemos eliminar libremente las reconciliaciones:

Técnica Jedi para reducir redes convolucionales: poda

Ahora vamos a crear un ciclo de trabajo:

  1. Descarga de activaciones
  2. Vamos a averiguar cuánto recortar.
  3. Cortamos
  4. Estudiamos 10 épocas con LR=1e-4
  5. Prueba

El desdoblamiento de pliegues es útil para evaluar cuánto se puede eliminar en un paso determinado. Ejemplos de desdoblamiento:

Técnica Jedi para reducir redes convolucionales: poda

Observamos que, prácticamente en todos los casos, el 5 % de las convoluciones tienen una norma L1 muy baja, por lo que podemos eliminarlas. En cada paso, se repitió esta eliminación y se evaluó qué capas y cuántas se podían eliminar.

Todo el proceso constó de cuatro pasos (los números que se muestran aquí y en todas partes corresponden a la RTX 2060 Super):

PasomAp75Número de parámetros, millonesTamaño de la red, MBDel original, %Tiempo de ejecución, mscondición de circuncisión
00.965660241100180-
10.962255218911755% de todos
20.962550197831685% de todos
30.9633391556415515% para capas con más de 400 convoluciones
40.9555311245114610% para capas con más de 100 convoluciones

El paso 2 agregó un efecto positivo: el tamaño del lote 4 se ajustó a la memoria, lo que aceleró significativamente el proceso de reentrenamiento.
En el paso 4, el proceso se detuvo, ya que incluso un entrenamiento adicional a largo plazo no elevó mAp75 a los valores anteriores.
Como resultado, logramos acelerar la inferencia. un 15%reducir tamaño por un 35% y no perder precisión.

Automatización para arquitecturas más simples

Para arquitecturas de red más simples (sin bloques de suma condicional, concatenación y residuales), es muy posible centrarse en procesar todas las capas convolucionales y automatizar el proceso de eliminación de convoluciones.

Implementé esta opción. aquí.
Es sencillo: todo lo que necesitas es una función de pérdida, un optimizador y generadores de lotes:

import pruning
from keras.optimizers import Adam
from keras.utils import Sequence

train_batch_generator = BatchGenerator...
score_batch_generator = BatchGenerator...

opt = Adam(lr=1e-4)
pruner = pruning.Pruner("config.json", "categorical_crossentropy", opt)

pruner.prune(train_batch, valid_batch)

Si es necesario, puede cambiar los parámetros de configuración:

{
    "input_model_path": "model.h5",
    "output_model_path": "model_pruned.h5",
    "finetuning_epochs": 10, # the number of epochs for train between pruning steps
    "stop_loss": 0.1, # loss for stopping process
    "pruning_percent_step": 0.05, # part of convs for delete on every pruning step
    "pruning_standart_deviation_part": 0.2 # shift for limit pruning part
}

Además, se ha implementado una restricción basada en la desviación estándar. El objetivo es limitar la porción de datos que se eliminará, excluyendo las convoluciones con medidas L1 ya "suficientes":

Técnica Jedi para reducir redes convolucionales: poda

De esta forma, solo permitimos que se eliminen las convoluciones débiles de distribuciones similares a la de la derecha, sin afectar la eliminación de las distribuciones similares a la de la izquierda:

Técnica Jedi para reducir redes convolucionales: poda

Cuando la distribución se aproxima a la normalidad, el coeficiente pruning_standard_deviation_part se puede seleccionar de:

Técnica Jedi para reducir redes convolucionales: poda
Recomiendo una tolerancia de 2 sigmas. Como alternativa, puede ignorar esta característica y dejar el valor < 1.0.

La salida es un gráfico del tamaño de la red, la pérdida y el tiempo de ejecución de la red para toda la prueba, normalizados a 1.0. Por ejemplo, aquí el tamaño de la red se redujo casi a la mitad sin ninguna pérdida de calidad (una pequeña red convolucional con 100.000 pesos):

Técnica Jedi para reducir redes convolucionales: poda

La velocidad de carrera está sujeta a fluctuaciones normales y se ha mantenido prácticamente sin cambios. Esto tiene una explicación:

  1. El número de convoluciones cambia de valores convenientes (32, 64, 128) a valores no tan convenientes para las tarjetas de vídeo: 27, 51, etc. Podría estar equivocado, pero lo más probable es que esto tenga un efecto.
  2. La arquitectura no es ancha, pero sí consistente. Al reducir el ancho, mantenemos la profundidad intacta. Esto reduce la carga sin afectar la velocidad.

Por lo tanto, la mejora resultó en una reducción del 20-30% en la carga de CUDA durante la ejecución, pero no en una reducción en el tiempo de ejecución.

resultados

Reflexionemos. Consideramos dos opciones de poda: una para YOLOv3 (que requiere procesamiento manual) y otra para redes con arquitecturas más simples. Es evidente que, en ambos casos, se puede reducir el tamaño de la red y acelerar el proceso sin sacrificar la precisión. Resultados:

  • Reduciendo el tamaño
  • Ejecución de aceleración
  • Reducción de la carga CUDA
  • Como resultado, se optimiza el uso futuro de los recursos informáticos, fomentando la sostenibilidad (en algún lugar, uno se siente satisfecho). Greta Tunberg)

Apéndice

  • Tras el paso de poda, también puedes ajustar la cuantización (por ejemplo, con TensorRT).
  • TensorFlow proporciona capacidades para poda de baja magnitud. Obras.
  • repositorio Quiero desarrollarme y agradecería recibir ayuda.

Fuente: habr.com

Compre alojamiento confiable para sitios con protección DDoS, servidores VPS VDS 🔥 Compra alojamiento web fiable con protección DDoS, servidores VPS VDS | ProHoster