¿Cómo calcular el impacto de la memoria de mini lotes al entrenar modelos de aprendizaje profundo?

17

Estoy tratando de calcular la cantidad de memoria que necesita una GPU para entrenar mi modelo en base a estas notas de Andrej Karphaty: http://cs231n.github.io/convolutional-networks/#computational-considerations

Mi red tiene 532,752 activaciones y 19,072,984 parámetros (pesos y sesgos). Todos estos son valores flotantes de 32 bits, por lo que cada uno ocupa 4 bytes en la memoria.

Mi imagen de entrada es 180x50x1 (ancho x alto x profundidad) = 9,000 valores flotantes 32. No uso el aumento de imagen, por lo que creo que la memoria miscelánea solo estaría relacionada con el tamaño del mini lote. Estoy usando un tamaño de mini lote de 128 imágenes.

Según la recomendación de Andrej, obtengo los siguientes tamaños de memoria:

Activaciones: 532,752 * 4 / (1024 ^ 2) = 2.03 MB

Parámetros: 19,072,984 * 4 / (1024 ^ 2) * 3 = 218.27 MB

Varios: 128 * 9,000 * 4 / (1024 ^ 2) = 4.39 MB

Entonces, la memoria total para entrenar esta red sería de 224,69 MB .

Estoy usando TensorFlow y creo que me falta algo. Todavía no he realizado el entrenamiento, pero estoy bastante seguro (en base a experiencias pasadas) de que la memoria en uso será mucho mayor de lo que he calculado.

Si para cada imagen en el mini lote, TensorFlow mantiene sus gradientes para que pueda normalizarlos más tarde para un solo paso de actualización de pesos / sesgos, entonces creo que la memoria debería tener en cuenta otros 532,752 * 128 valores (gradientes para cada imagen en el mini-lote) Si ese es el caso, necesitaría más 260.13 MB para entrenar este modelo con 128 imágenes / mini-lote.

¿Me pueden ayudar a comprender las consideraciones de memoria para entrenar mi modelo de aprendizaje profundo? ¿Son correctas las consideraciones anteriores?

barbolo
fuente
Vea mi respuesta (propuesta) a su pregunta aquí .
Adam Hendry

Respuestas:

5

Creo que estás en el camino correcto.

Sí, necesitará almacenar las derivadas de las activaciones y de los parámetros para la retropropagación.

Además, su elección de optimización puede ser importante. ¿Estás entrenando con SGD, o Adam, o Adagrad? Todos estos tendrán diferentes requisitos de memoria. Por ejemplo, tendrá que almacenar la memoria caché de tamaño de paso para un método basado en el impulso, aunque eso debería ser secundario en comparación con las otras consideraciones de memoria que menciona.

Así que, en general, parece haber calculado los requisitos de memoria para un pase hacia adelante. Andrej Karpathy menciona que el pase hacia atrás podría tomar hasta 3 veces la memoria del pase hacia adelante, por lo que esta podría ser la razón por la que ve tanta diferencia (desplácese hacia abajo hasta 'Estudios de casos' en el sitio web para ver un ejemplo de VGGNet).

EstadísticasSorceress
fuente
5

@StatsSorceress TL; DR:

Estoy realizando esta actividad para ver si puedo calcular la memoria requerida por mí mismo:

Activaciones: 532,752 * 2 * 4 / (1024 ^ 2) = 4.06 MB

Parámetros: 19,072,984 * 4 / (1024 ^ 2) * 3 = 218.27 MB

Varios: 128 * 9,000 * 4 / (1024 ^ 2) = 4.39 MB

Memoria total: (4.06 * 128 ) + 218.27 + 4.39 = 742.34 MB

( Alguien corríjame en esto si me equivoco. Para su información, ya multiplicó misceláneas por 128, por eso no lo multipliqué por 128 arriba )


Le señalaría este artículo y el video correspondiente . Me ayudaron a entender lo que está sucediendo mucho mejor.

NOTA: La memoria requerida para usar una red para las predicciones es mucho menor que la requerida para el entrenamiento por dos razones:

  • Al predecir, solo enviamos una imagen hacia adelante a través de la red y no hacia atrás (por lo que no multiplicamos la memoria X 3; ver más abajo)
  • Hay una predicción por imagen (por lo que no necesitamos multiplicar la memoria requerida para una imagen por un tamaño de lote porque no usamos lotes en la predicción).

Proceso (memoria para entrenar)

  1. Calcule la memoria requerida para entrenar en una imagen
  2. Multiplique este número por el número de imágenes en su lote

( RECUERDE: Mini-batching dice que tomamos un subconjunto de nuestros datos, calculamos los gradientes y errores para cada imagen en el subconjunto, luego promedia estos y avanza en la dirección del promedio. Para las redes de comunicación, se comparten pesos y sesgos, pero la cantidad de activaciones se multiplica por la cantidad de imágenes en el lote ).

PASO 1: Memoria para 1 imagen

Para entrenar una imagen, debe reservar memoria para:

  • Parámetros del modelo:

    Los pesos y sesgos en cada capa, sus gradientes y sus variables de impulso (si se utilizan optimizadores Adam, Adagrad, RMSProp, etc.)

    Para aproximar la memoria para esto, calcule la memoria requerida para almacenar los pesos y sesgos y multiplíquelo por 3 (es decir, "por 3" porque estamos diciendo que la cantidad de memoria necesaria para almacenar los pesos y sesgos es (aproximadamente) igual a necesario para los gradientes y para las variables de impulso)

    ECUACIONES

    Convoluciones

    pesos (n) = profundidad (n) * (kernel_width * kernel_height) * profundidad (n-1)

    sesgos (n) = profundidad (n)

    Capas completamente conectadas (densas):

    pesos (n) = salidas (n) * entradas (n)

    sesgos (n) = salidas (n)

donde n es la capa actual y n-1 es la capa anterior, y las salidas son el número de salidas de la capa FC y las entradas son el número de entradas a la capa FC (si la capa anterior no es una capa completamente conectada, el número de entradas es igual al tamaño de esa capa aplanada).

NOTA: La memoria solo para los pesos y los sesgos, más la memoria para las activaciones de una imagen (ver a continuación), es la cantidad total de memoria que necesita para las predicciones (excluyendo algunos gastos generales para la memoria para convoluciones y otras cosas).

  • Activaciones (estos son "Blobs" en Caffe):

(Estoy usando términos sueltos aquí, tengan paciencia conmigo)

Cada convolución en una capa de convolución produce activaciones de " número de píxeles en la imagen " (es decir, si pasa una imagen a través de una sola convolución, obtiene un mapa de características único que consiste en activaciones " m ", donde " m " es el número de píxeles de su imagen / entrada).

Para capas completamente conectadas, el número de activaciones que produce es igual al tamaño de su salida.

Convoluciones

activaciones (n) = image_width * image_height * image_num_channels

Capas completamente conectadas (densas):

activaciones (n) = salidas (n)

Tenga en cuenta que su entrada es realmente solo una imagen al comienzo de la red. Después de las circunvoluciones, se convierte en algo más (mapas de características). Así que realmente reemplace "image_width", "image_height" e "image_num_channels" con "input_width", "input_height" y "layer_depth" para ser más precisos. (Es más fácil para mí pensar en este concepto en términos de imágenes).

Dado que también necesitamos almacenar el error para las activaciones en cada capa (utilizado en el paso hacia atrás), multiplicamos el número de activaciones por 2 para obtener el número total de entidades que necesitamos para dejar espacio en nuestro espacio de almacenamiento. El número de activaciones aumenta con el número de imágenes en el lote, por lo que multiplica este número por el tamaño del lote.

PASO 2: Memoria para entrenar por lotes

Suma el número de pesos y sesgos (por 3) y el número de activaciones (por 2 veces el tamaño del lote). Multiplique esto por 4 y obtendrá la cantidad de bytes necesarios para entrenar el lote. Puede dividir entre 1024 ^ 2 para obtener la respuesta en GB.

Adam Hendry
fuente
¿Por qué dices "no usamos lotes en la predicción"? Si un usuario necesita hacer predicciones en una gran cantidad de imágenes, entonces puede tener sentido usar lotes en las predicciones.
user3731622
1

Alternativamente, creo que puede usar cualquier biblioteca de perfiles para analizar la memoria y el uso de la CPU por su programa. Hay muchas bibliotecas de Python que pueden proporcionarle una instantánea de la memoria y el uso de la CPU por un subproceso o proceso particular en un intervalo de milisegundos.

Puede ejecutar la parte de su programa que desea monitorear en un subproceso diferente usando popen y monitorear su memoria y uso de CPU usando su PID.

psutil me parece bueno para ese trabajo. Aunque hay muchos otros.

Espero que esto sea de ayuda.

EngineeredBrain
fuente
3
Gracias por la respuesta, @Anwar. Estoy buscando un cálculo analítico en lugar de una observación empírica.
barbolo