Contenido
Cuantización int8 para microcontroladores: cómo funciona
Cuantización int8 para microcontroladores explicada: escalas y puntos cero, pesos por canal, calibración, recuantización y cuándo la PTQ ya no te basta.
El modelo en punto flotante tiene 92 % de exactitud. Después de convertirlo a int8 para el microcontrolador tiene 71 %, y el equipo concluye que el modelo “no se deja cuantizar”. Casi siempre sí se deja. La cuantización int8 para microcontroladores es un mapeo de números reales a 256 niveles enteros, y la exactitud que conserva depende sobre todo de elegir bien el rango de cada tensor. Aquí te explico la aritmética (escalas, puntos cero, pesos por canal y recuantización), te muestro con números calculados dónde se pierde exactitud y resumo lo que dice la investigación sobre la cuantización post-entrenamiento frente al entrenamiento consciente de la cuantización.
Puntos clave
- Cada tensor int8 guarda sus valores reales como (q − punto cero) × escala, así que 256 niveles tienen que cubrir el rango del tensor. La elección del rango decide la precisión.
- Los pesos int8 son cuatro veces más pequeños que los float32 y corren con kernels SIMD enteros, que es lo que hace práctica la inferencia en un microcontrolador.
- Las escalas por canal importan: con una sola escala por tensor, un canal con pesos pequeños puede terminar usando apenas unos cuantos de los 255 niveles.
- Los datos de calibración fijan los rangos de las activaciones. Un solo valor atípico puede estirar el rango y dejar a los valores típicos con muy pocos niveles.
- Con pesos por canal, la cuantización post-entrenamiento quedó a unos 2 % de la exactitud en flotante en las CNN de un estudio de Google, y el entrenamiento consciente de la cuantización a cerca de 1 %.
El problema: “perdió 20 puntos al cuantizarlo”
Las caídas grandes de exactitud después de cuantizar casi siempre tienen unas cuantas causas. El conjunto de calibración eran unas cuantas imágenes al azar, o datos sintéticos, así que los rangos de las activaciones no corresponden a las entradas reales. Una capa tiene unas cuantas activaciones extremas que estiran su rango. Los pesos se cuantizaron con una sola escala para todo el tensor y algunos canales tienen pesos mucho más pequeños que otros. El preprocesamiento de la entrada en el dispositivo es distinto del que se usó para calibrar. O una operación sensible a la precisión, como un softmax final o una suma residual con escalas que no coinciden, se cuantizó sin cuidado.
Cada uno de estos es un problema de rango, y todos se encuentran comparando capa por capa las salidas en flotante y en int8.
Cómo funciona la cuantización int8
Escala y punto cero
El esquema que usan casi todos los runtimes embebidos lo describieron Jacob y sus colegas en su artículo de CVPR 2018 sobre inferencia solo con aritmética entera. Un valor real r se representa con un entero q mediante un mapeo afín: r = S × (q − Z), donde S es una escala real positiva y Z es el punto cero entero, elegido para que el valor real 0 se pueda representar exactamente. La especificación de cuantización de 8 bits de LiteRT (antes TensorFlow Lite), de Google, usa la misma fórmula y las convenciones que siguen las herramientas actuales: las activaciones usan int8 en [−128, 127] con un punto cero libre y una escala por tensor; los pesos usan int8 en [−127, 127] con punto cero 0 (simétricos) y pueden tener una escala por canal de salida; los sesgos son int32 con una escala igual a la escala de entrada por la escala de los pesos.
Un ejemplo calculado. Supón que la calibración muestra que las activaciones de una capa van de −2.5 a 6.0. La escala es (6.0 − (−2.5)) / 255 ≈ 0.0333, y el punto cero que pone −2.5 en −128 es Z = −53. Comprobación: 6.0 se mapea a 6.0 / 0.0333 − 53 = 127, y 0.0 se mapea exactamente a −53. El peor error de redondeo dentro del rango es medio escalón, unos 0.017.
Por qué importan las escalas por canal
Los canales de salida de una convolución pueden tener magnitudes de pesos muy distintas. Con una sola escala simétrica para todo el tensor, la escala la fija el peso más grande. Como ejemplo ilustrativo, si el peso más grande de una capa es 0.42, la escala por tensor es 0.42 / 127 ≈ 0.0033. Un canal cuyos pesos nunca pasan de 0.02 usa entonces solo unos ±6 de los ±127 niveles disponibles, apenas más de 3 bits de precisión. Darle a cada canal su propia escala le devuelve el rango completo a cada uno.
El white paper de Raghuraman Krishnamoorthi de 2018 en Google sobre la cuantización de redes convolucionales midió el efecto: la cuantización post-entrenamiento con pesos por canal y activaciones por capa quedó a unos 2 % de la exactitud en punto flotante en varias arquitecturas CNN, y recomienda justo esa combinación para el hardware.
Calibración y valores atípicos
Los pesos se conocen al terminar el entrenamiento, pero los rangos de las activaciones dependen de los datos. La cuantización post-entrenamiento pasa un conjunto de calibración por el modelo en flotante y registra el rango de cada tensor. Si ese conjunto no se parece a las entradas reales, los rangos salen mal.
Los valores atípicos son la otra trampa. A modo de ilustración, si las activaciones de una capa normalmente están entre 0 y 3 pero una sola muestra de calibración llega a 30, un rango mínimo-máximo da una escala de 30 / 255 ≈ 0.118, y los valores típicos entre 0 y 3 quedan representados por solo unos 25 niveles. Los métodos de calibración que recortan en un percentil de la distribución observada, o que minimizan el error de cuantización, sacrifican un poco de los atípicos raros a cambio de mucha más precisión en los valores comunes.
Recuantización: solo enteros de capa a capa
Dentro de una capa cuantizada, las entradas int8 y los pesos int8 se multiplican y se suman en un acumulador int32. El resultado tiene escala S_in × S_w, y hay que pasarlo a la escala del tensor de salida, S_out, antes de la siguiente capa. Jacob y sus colegas mostraron cómo hacerlo sin punto flotante: la razón M = S_in × S_w / S_out es un número real entre 0 y 1 que se representa como un multiplicador entero de punto fijo normalizado más un corrimiento de bits. En el ejemplo, con una escala de entrada de 0.0333, una de pesos de 0.0033 y una de salida de 0.05, M ≈ 0.0022, que es 0.564 × 2⁻⁸, así que se guarda como 0.564 en punto fijo de 32 bits más un corrimiento a la derecha de 8 bits. Cada capa corre en la ruta entera que aceleran las instrucciones SIMD del microcontrolador.
¿Cuantización post-entrenamiento o entrenamiento consciente de la cuantización?
El white paper de Nagel y sus colegas de 2021 sobre cuantización de redes neuronales resume el compromiso: la cuantización post-entrenamiento (PTQ) no necesita reentrenar ni datos etiquetados, y en la mayoría de los casos basta para cuantizar a 8 bits con una exactitud cercana a la de punto flotante. El entrenamiento consciente de la cuantización (QAT) simula la cuantización durante un ajuste fino para que la red aprenda a tolerarla; necesita el pipeline de entrenamiento y datos etiquetados, pero recupera más exactitud y permite menos bits. Los números de Krishnamoorthi dicen lo mismo: QAT bajó la brecha a 8 bits a cerca de 1 %, y los pesos de 4 bits con QAT perdieron entre 2 y 10 %, más en las redes pequeñas.
Las ganancias de memoria y velocidad vienen del número de bits en ambos casos. El artículo de Krishnamoorthi señala que los pesos de 8 bits reducen cuatro veces el tamaño del modelo aun en hardware sin aritmética de 8 bits, y en los microcontroladores los kernels enteros son lo que hace que la inferencia sea lo bastante rápida para servir.
Opciones de cuantización int8, comparadas
| Decisión | Opción A | Opción B | Efecto en la exactitud | Cuándo elegir B |
|---|---|---|---|---|
| Escala de los pesos | Por tensor | Por canal | B evita dejar sin niveles a los canales pequeños | Casi siempre en convoluciones |
| Simetría de los pesos | Asimétrica | Simétrica (Z = 0) | Poco; B es más simple y rápida | Por defecto en las especificaciones actuales |
| Rango de activaciones | Mínimo-máximo | Percentil o mínimo error | B es mejor con atípicos | Cuando las activaciones tienen colas largas |
| Datos de calibración | Aleatorios o sintéticos | Entradas reales representativas | B da rangos correctos | Siempre |
| Método | Post-entrenamiento (PTQ) | Entrenamiento consciente (QAT) | B recupera más, cerca de 1 % de brecha en un estudio | Cuando PTQ pierde más de lo aceptable |
| Número de bits | 8 bits | 4 bits o mixto | B pierde más (2–10 % con QAT en un estudio) | Solo cuando la memoria lo obliga |
Qué hacer
Compara flotante e int8 capa por capa
Pasa las mismas entradas por el modelo en flotante y por el cuantizado y compara la salida de cada capa. La primera capa donde el error se dispara es donde el rango o el esquema están mal.
Usa pesos por canal y datos de calibración reales
Convierte con cuantización de pesos por canal y unos cientos de entradas reales representativas, preprocesadas exactamente como las va a preprocesar el dispositivo.
Atiende los valores atípicos a propósito
Revisa los histogramas de las activaciones en busca de colas largas. Usa calibración por percentil, o corrige la causa en el modelo (una activación sin límite muchas veces se puede cambiar por una acotada antes de entrenar).
Pasa a QAT solo cuando haga falta
Si la PTQ con buena calibración todavía no llega a la meta de exactitud, haz un ajuste fino con entrenamiento consciente de la cuantización en lugar de abandonar int8.
Verifica en el dispositivo
Corre el modelo cuantizado en el microcontrolador con las features del dispositivo y compara sus salidas con las del modelo cuantizado en la computadora. No se garantiza que coincidan bit a bit entre implementaciones, pero las diferencias deben ser mínimas.
Qué no hacer
No juzgues si un modelo “se deja cuantizar” a partir de una conversión con datos de calibración aleatorios. Y no pases a pesos de 4 bits para ahorrar memoria sin antes revisar a dónde se va la memoria; las activaciones y los buffers muchas veces dominan la RAM.
Cómo ponerlo en práctica
Si tienes una hora
Cuantiza tu modelo dos veces, con pesos por tensor y por canal, usando el mismo conjunto de calibración real, y compara la exactitud. Si por canal recupera casi toda la pérdida, ya encontraste el problema.
Si tienes un sprint
Arma una comparación capa por capa entre el modelo en flotante y el int8 con unos cientos de entradas reales, grafica el error por capa y corrige los rangos de las peores capas. Después corre QAT solo si todavía no llegas a la meta.
Si quieres que dure toda la vida del producto
Guarda el conjunto de calibración, la configuración de cuantización y la exactitud en flotante contra int8 con cada versión del modelo, y renueva el conjunto de calibración cuando cambien el sensor, la instalación o el preprocesamiento.
La pregunta que debes hacerte: “Cuando mi modelo perdió exactitud en int8, ¿encontré qué rango de qué capa la causó, o le eché la culpa al número de bits?”
Preguntas frecuentes
¿Qué es la cuantización int8?
La cuantización int8 representa los pesos y las activaciones de una red neuronal como enteros de 8 bits, cada tensor con una escala y un punto cero que regresan los enteros a valores reales: r = S × (q − Z). Permite correr la red con aritmética entera en la cuarta parte de la memoria que con flotantes de 32 bits.
¿Cuánta exactitud se pierde con la cuantización int8?
Muchas veces muy poca. En un estudio de Google, la cuantización post-entrenamiento con pesos por canal quedó a unos 2 % de la exactitud en flotante en varias CNN, y el entrenamiento consciente de la cuantización a cerca de 1 %. Las pérdidas mayores suelen venir de mala calibración, de valores atípicos o de escalas de pesos por tensor.
¿Cuál es la diferencia entre cuantización por tensor y por canal?
La cuantización por tensor usa una sola escala para todo un tensor de pesos; la por canal usa una escala para cada canal de salida. Por canal evita que los canales con pesos pequeños queden representados con muy pocos niveles enteros, y las especificaciones actuales la soportan para los pesos de las convoluciones.
¿Qué es la calibración en la cuantización post-entrenamiento?
La calibración pasa un conjunto de entradas representativas por el modelo en flotante para medir el rango de cada tensor de activaciones, lo que fija su escala y su punto cero. Si los datos de calibración no se parecen a las entradas reales, los rangos salen mal y baja la exactitud.
¿Cuándo conviene el entrenamiento consciente de la cuantización?
Cuando la cuantización post-entrenamiento con pesos por canal y buena calibración todavía no llega a tu meta de exactitud, o cuando necesitas menos de 8 bits. QAT simula la cuantización durante el ajuste fino para que la red se adapte a ella.
Lecturas relacionadas: inferencia en un Cortex-M, del sensor a la inferencia embebida y cómo medir un demo de IA embebida.
Fuentes
- Jacob, B., Kligys, S., Chen, B., et al. (2018). “Quantization and Training of Neural Networks for Efficient Integer-Arithmetic-Only Inference.” 2018 IEEE/CVF Conference on Computer Vision and Pattern Recognition, 2704–2713. https://doi.org/10.1109/CVPR.2018.00286
- Krishnamoorthi, R. (2018). “Quantizing Deep Convolutional Networks for Efficient Inference: A Whitepaper.” arXiv:1806.08342. https://arxiv.org/abs/1806.08342
- Nagel, M., Fournarakis, M., Amjad, R. A., Bondarenko, Y., van Baalen, M., y Blankevoort, T. (2021). “A White Paper on Neural Network Quantization.” arXiv:2106.08295. https://arxiv.org/abs/2106.08295
- Google AI Edge. “LiteRT 8-bit Quantization Specification.” https://developers.google.com/edge/litert/conversion/tensorflow/quantization/quantization_spec
- Lai, L., Suda, N., y Chandra, V. (2018). “CMSIS-NN: Efficient Neural Network Kernels for Arm Cortex-M CPUs.” arXiv:1801.06601. https://arxiv.org/abs/1801.06601



