El mismo modelo, una respuesta diferente
Un sensor inteligente instalado en una máquina transforma unas señales en una puntuación. En el ordenador de desarrollo parece correcta, pero al portar el modelo al microcontrolador algunos valores difieren en una unidad entera. ¿Es ruido inocuo o un error? Depende de lo que represente ese entero. Cerca de un umbral, un paso de la representación puede cambiar una decisión. Antes de modificar la red conviene entender cómo una suma amplia vuelve al pequeño formato de salida.
Estudiamos la recuantización: cambiar de escala, redondear y limitar al intervalo representable. Derivaremos una neurona de tres entradas, calcularemos con fracciones exactas y construiremos contraejemplos para valores intermedios, negativos y saturados. El objetivo no es demostrar que INT8 sea poco fiable, sino explicitar el contrato numérico que deben compartir dos implementaciones. No usamos una placa, medimos latencia ni evaluamos una red completa; el código es una referencia didáctica, no un emulador exacto de un runtime comercial.
Un entero es una etiqueta en una escala
INT8 es un entero de ocho bits con signo: en complemento a dos representa de −128 a 127. En una red cuantizada ese número no tiene por qué coincidir con el valor matemático. Hacen falta una escala positiva s y un punto cero z. La escala indica cuánto vale un paso; z identifica el entero correspondiente al cero real. Es como numerar marcas de una regla desplazada: el número de la marca no basta para conocer la longitud. La analogía explica la conversión, no el funcionamiento de la red.
q es el entero almacenado y r el valor reconstruido. En el ejemplo todas las señales están normalizadas y no tienen unidades físicas: no convertimos directamente voltios ni grados. Con s = 0,1 y z = 10, q = 13 significa r = 0,3; q = 10 significa cero; q = 0 significa −1. Esto importa al añadir bordes nulos a una imagen: el cero matemático se codifica con z, no necesariamente con el byte de valor numérico cero.
Construyamos el cálculo completo antes de redondear
La neurona suma tres productos y añade un sesgo, una constante que desplaza el resultado. Las entradas enteras [13, 9, 12], con sₓ = 0,1 y zₓ = 10, representan [0,3; −0,1; 0,2]. Los pesos [2, −3, 1], con s𝑤 = 0,2 y z𝑤 = 0, representan [0,4; −0,6; 0,2]. El sesgo real es 0,02. Elegimos números representables exactamente en sus rejillas para aislar el redondeo final sin mezclarlo con errores previos de cuantización de entradas.
El cálculo real da 0,3 × 0,4 + (−0,1) × (−0,6) + 0,2 × 0,2 + 0,02 = 0,24. Para obtenerlo con enteros restamos primero el punto cero de entrada. Los productos son 3 × 2, (−1) × (−3) y 2 × 1: 6, 3 y 2. Cada unidad de la suma vale sₓs𝑤 = 0,02. El sesgo debe usar la misma escala: bq = 0,02/0,02 = 1. Sumando 6 + 3 + 2 + 1 obtenemos A = 12, que reconstruye 12 × 0,02 = 0,24.
La relación supone pesos con punto cero nulo y un sesgo representable en la escala del producto; de lo contrario el sesgo necesita su propio redondeo especificado. A es entero: normalmente se acumula en INT32 para disponer de más rango que los operandos INT8. Aquí suponemos que no hay desbordamiento en la acumulación. Reservar suficientes bits es necesario, pero no resuelve el cambio de escala posterior.
De la suma al byte de salida
La salida usa sᵧ = 0,08 y zᵧ = −7, una regla diferente. Para expresar A en pasos de salida dividimos su valor real por sᵧ. La razón M = sₓs𝑤/sᵧ = 1/4 convierte las escalas. R significa redondear al más cercano, alejando de cero los empates exactos. clamp limita entre −128 y 127. Nuestro contrato, en ese orden, es:
Para A = 12, MA = 3 ya es entero. Añadimos −7 y almacenamos qy = −4. Ese byte negativo representa un resultado positivo: ŷ = 0,08 × (−4 + 7) = 0,24. El signo del código no es el signo de la magnitud. Añadir el sesgo directamente en la escala de salida tampoco sería equivalente en general: aquí pertenece al acumulador antes de convertir.
Entre dos valores: hace falta una regla completa
Cambiemos solo A a 10. Antes de redondear, MA = 2,5. Los enteros 2 y 3 están igual de cerca. Nuestra regla elige 3, mientras que el empate al par elige 2 porque es par. Añadiendo zᵧ obtenemos −4 y −5, que reconstruyen 0,24 y 0,16. Antes de recuantizar el valor era 0,20: ambos distan 0,04, pero no son el mismo resultado.
Si una decisión hipotética se activa con ŷ ≥ 0,20, la primera versión la activa y la segunda no. No medimos pérdida de precisión en un dataset: el contraejemplo demuestra por qué importa un código de diferencia. Ninguna regla es universalmente mejor para todas las redes. El problema de compatibilidad es validar con una regla distinta a la del dispositivo o ignorar la tolerancia necesaria para decidir.
También importa el orden. Con nuestra regla, R(2,5) − 7 = −4, pero R(2,5 − 7) = R(−4,5) = −5. Mover la suma del punto cero antes del redondeo parece una transformación inocua del álgebra real, pero cambia el empate respecto a cero. La fórmula debe indicar dónde se redondea. Si un runtime adopta otra convención, la referencia debe reproducirla; no afirmamos que todos utilicen R.
Números negativos, truncamiento y distorsión
Eliminar la parte decimal no siempre equivale a redondear al más cercano. Con A = −11, MA = −2,75: el más cercano es −3, truncar hacia cero da −2 y redondear hacia menos infinito da −3. Con A = 11, truncar y redondear hacia menos infinito dan 2, mientras el más cercano es 3. Las diferencias no son simétricas en todas las reglas. La tabla muestra códigos finales tras añadir zᵧ = −7; para interpretarlos hay que restar zᵧ y multiplicar por 0,08.
| A | MA | R: empates lejos | Empate al par | Truncamiento | Hacia −∞ |
|---|---|---|---|---|---|
| -11 | −2.75 | -10 | -10 | -9 | -10 |
| -10 | −2.5 | -10 | -9 | -9 | -10 |
| 0 | 0 | -7 | -7 | -7 | -7 |
| 10 | 2.5 | -4 | -5 | -5 | -5 |
| 11 | 2.75 | -4 | -4 | -5 | -5 |
El gráfico evalúa todos los enteros A entre −16 y 16, sin saturación, y muestra ŷ − y. Las líneas entre puntos facilitan la lectura; no son pruebas con entradas continuas. Truncar empuja los valores hacia el cero real; redondear hacia menos infinito produce errores no positivos. En esta rejilla simétrica el error medio de R y del truncamiento es cero, pero sus errores individuales difieren y no demuestra ausencia de sesgo con datos reales asimétricos.

Dos pasos algebraicamente exactos, dos redondeos distintos
Un dispositivo puede implementar un factor fraccionario mediante multiplicaciones enteras y desplazamientos de bits. Para entender el riesgo no necesitamos emular un procesador concreto. Tomemos M = 3/8 y dos algoritmos: uno redondea solo al final; el otro calcula 3A/4, redondea, divide entre dos y vuelve a redondear. Sin redondeo, 3/8 y (3/4)/2 son idénticos. Con A = 1, el primero da R(0,375) = 0; el segundo R(R(0,75)/2) = R(0,5) = 1.
No denunciamos un defecto de una biblioteca: hemos construido dos contratos numéricos distintos. Algunas implementaciones usan intencionadamente pasos intermedios diferentes y validados. Para comparar hay que conocer multiplicador, desplazamiento, anchura intermedia y regla de redondeo de cada paso. Comprobar solo el factor real final M no basta. El paquete evalúa ambos algoritmos para todos los A entre −16 y 16, incluidos negativos.
¿Qué error podemos acotar?
Con un solo redondeo al más cercano, multiplicador exacto y sin saturación, la distancia entre R(MA) y MA no supera medio entero. Multiplicar por la escala de salida da una cota local del valor reconstruido:
La prueba corresponde a este paso, no al error respecto al modelo original en coma flotante: pesos, entradas y sesgos anteriores pueden estar aproximados. Tampoco garantiza la decisión final de muchas capas. Operaciones posteriores pueden amplificar el medio paso; cerca del umbral puede bastar para cruzarlo. Analizar toda la red exige la secuencia completa y datos representativos.
Si el dispositivo usa un multiplicador aproximado M̂ sin otros redondeos intermedios, la desigualdad triangular separa dos contribuciones: |ŷ − y| ≤ sᵧ(1/2 + |A|·|M̂ − M|), todavía sin recorte. La primera es el redondeo final; la segunda, el error del multiplicador amplificado por el acumulador. Un pequeño error relativo de la constante no permite ignorar el rango de A. La cota excluye desbordamientos y redondeos ocultos adicionales.
La saturación rompe la garantía del medio paso
Aumentemos A hasta 600 manteniendo las escalas iniciales. El valor real es 12, MA = 150 y el código previo al límite es 150 − 7 = 143. INT8 no puede contenerlo: clamp devuelve 127. Se reconstruye 0,08 × (127 + 7) = 10,72, con error −1,28. No es error de redondeo: alcanzamos el borde de la representación. La garantía de 0,04 no se aplica porque se incumple la ausencia de saturación.
Cambiar sᵧ para ampliar el rango también separa más los valores consecutivos. Rango y resolución deben elegirse juntos con datos adecuados al uso previsto. Una activación puede restringir más el intervalo: en ReLU, que anula valores negativos, el código del límite cero es zᵧ, aquí −7, no necesariamente 0. Saturación numérica y activación son conceptos distintos aunque el kernel los fusione.
De las fuentes a la verificación en el dispositivo
Jacob y colaboradores describen el esquema afín, la escala del sesgo y la cadena entera en su trabajo de 2018, del que leímos las secciones 2 y 4. Sus comparaciones MobileNet corresponden a hardware Snapdragon y protocolos declarados: no trasladamos esos resultados a un microcontrolador. gemmlowp explica la conversión del acumulador y LiteRT distingue tipos, rangos y puntos cero. Son referencias del mecanismo; nuestros ejemplos están separados de sus benchmarks y no certifican compatibilidad con una versión específica.
En Python usamos Fraction para mantener exactos 1/10, 1/5 y 2/25: incluso escribir 0,1 como float puede introducir una aproximación binaria, innecesaria aquí. away redondea el valor absoluto con aritmética entera y recupera el signo; requant aplica multiplicador, redondeo, punto cero y saturación en ese orden. Las aserciones verifican el ejemplo, empates, doble redondeo y la cota de medio paso en toda la rejilla. Los datos son deterministas, sin semilla.
Para L entradas, el producto escalar requiere O(L) operaciones; convertir N acumuladores disponibles requiere O(N) pasos. La memoria del script crece con las filas guardadas, pero no mide el pico RAM del firmware. Python usa enteros de precisión arbitraria: una implementación embedded debe definir anchuras intermedias, desplazamientos válidos, saturaciones y conversiones. Traducir el código línea por línea no demuestra que el compilador preserve todas las propiedades.
La verificación propuesta empieza con vectores compartidos: cero real, negativos, puntos medios, límites de saturación y canales con escalas distintas. Se registran modelo convertido, versión del convertidor, runtime, kernel, compilador y opciones. Si no se espera igualdad exacta, se documenta tolerancia por operador y se evalúa aparte el impacto en decisiones. Después se miden latencia media y percentiles, pico RAM, potencia y energía por inferencia con protocolo explícito. Esas pruebas no se han ejecutado: nuestro cálculo no produce tales mediciones.
La respuesta: comprobar qué significa el byte
Una suma INT32 correcta no garantiza por sí sola una salida INT8 equivalente entre sistemas. Hay que conservar escalas y puntos cero, precisar empates, respetar el orden y distinguir redondeo de saturación. El acumulador 10 reconstruye 0,24 o 0,16 según la regla; con 600, el límite del formato introduce un error mucho mayor. La lección práctica para IA en dispositivos pequeños es verificar qué operación numérica ejecuta realmente el modelo antes de preguntar a qué velocidad funciona.
Fuentes y reproducibilidad
Google gemmlowp, Building a quantization paradigm from first principles.
Google LiteRT, 8-bit quantization specification.
from fractions import Fraction
from experiment import requant, run
print(requant(10), requant(10, rounder=round))
print(requant(600))
print(next(r for r in run()['double_rounding'] if r['a'] == 1))
Código, datos e instrucciones · JSON. Cálculos didácticos ejecutados con Python 3.14.0; figuras con Matplotlib 3.11.2. Análisis asistido por IA, sin afirmar revisión por pares ni humana. Portada original ImageGen ilustrativa: no documenta personas, sedes ni instalaciones de EL-AI. Fuentes consultadas el 4 de octubre de 2026.

