noticias

¡Miles de palabras de temas técnicos! Una guía de cuantificación de lectura obligada para ingenieros de LLM, ilustraciones visuales que revelan cómo comprimir modelos grandes

2024-07-31

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina


Nuevo informe de sabiduría

Editor: Departamento Editorial

[Introducción a la Nueva Sabiduría] Ante la escala de parámetros de LLM que se expande gradualmente, los desarrolladores e investigadores sin H100 han ideado muchas formas de compensarlo, y la tecnología de "cuantificación" es una de ellas. Esta guía visual utiliza varias ilustraciones para resumir exhaustivamente los conceptos básicos y los métodos de rama de "cuantificación".

Los modelos de lenguajes grandes (LLM) suelen ser demasiado grandes para ejecutarse en hardware de consumo. Estos modelos pueden tener más de miles de millones de parámetros y, a menudo, requieren GPU con gran memoria para acelerar el proceso de inferencia.

Por lo tanto, cada vez más investigaciones han comenzado a centrarse en cómo reducir el modelo, como mejorar los métodos de entrenamiento o usar adaptadores. Una de las principales técnicas en este campo se llama cuantificación.

El ingeniero de aprendizaje automático Maarten Grootendorst escribió una publicación de blog que presenta específicamente la tecnología de cuantificación en el contexto del modelado del lenguaje y explora conceptos relacionados uno por uno a través de métodos visuales para ayudarnos a desarrollar una comprensión intuitiva de la tecnología.


En esta publicación de blog, Maarten explora varios métodos, casos de uso y los principios detrás de la cuantificación.

La tabla de contenido y el contenido del artículo se muestran en la figura siguiente. Presenta principalmente los dos métodos de cuantificación posterior al entrenamiento (PTQ) y entrenamiento consciente de la cuantificación (QAT). Se recomienda a los lectores con una base en IA que salten directamente. a la parte de cuantificación simétrica:


Primera parte: El "problema" del LLM

Los "modelos de lenguaje grande" son grandes en términos de la cantidad de parámetros del modelo, y generalmente alcanzan miles de millones en escala (principalmente pesos).

No sólo los costos de almacenamiento de estos parámetros son bastante altos, sino que la cantidad de cálculo en la fase de inferencia también es grande.

Durante la inferencia, el valor de activación es el producto de la entrada y el peso, por lo que cuanto mayor sea el número de pesos, mayor será el valor de activación.


Por lo tanto, queremos representar miles de millones de valores de la manera más eficiente posible, minimizando así el espacio requerido para almacenar parámetros.

Comencemos por el principio y exploremos cómo se representan los valores antes de optimizar.

Cómo representar valores numéricos

Los valores numéricos generalmente se almacenan como números de punto flotante (o simplemente flotantes): un número positivo o negativo con un punto decimal.

Estos valores están representados por dígitos binarios en cada bit.

El estándar IEEE-754 describe cómo los dígitos de cada dígito representan un valor específico. Específicamente, hay tres asignaciones: signo, exponente o decimal (mantisa).


Estas tres partes se pueden combinar para calcular el valor representado en función de un conjunto de valores de bits:


Cuantos más dígitos se utilicen, más preciso será el valor numérico. Por ejemplo, el formulario FP32 puede tener una precisión de más dígitos después del punto decimal que FP16:


limite de memoria

Cuantos más dígitos haya disponibles, no sólo más preciso será el valor, sino también más amplio será el rango de valores que se pueden representar.


Dado un número de bits y una representación, el rango de valores que se pueden representar se llama rango dinámico y la distancia entre dos valores adyacentes se llama precisión.


Una característica interesante de esta representación es que podemos calcular cuánta memoria requiere el dispositivo para almacenar un valor determinado.

Dado que cada byte en la memoria contiene 8 bits, podemos crear una fórmula básica para la mayoría de las formas de números de punto flotante:


En aplicaciones reales, hay muchos más factores que afectan la cantidad de gráficos/memoria necesarios durante la inferencia, como el tamaño del contexto y la arquitectura del modelo.

Ahora imaginemos que tenemos un modelo con 70 mil millones de parámetros. La mayoría de los modelos se representan mediante números de coma flotante de 32 bits (a menudo llamados precisión total), lo que requiere 280 GB de memoria para cargar el modelo.


Pero si todos los parámetros se pueden expresar como números de coma flotante de 16 bits, el tamaño de memoria requerido se puede reducir directamente una vez.

Por tanto, resulta muy atractivo minimizar el número de representaciones de los parámetros del modelo (no sólo para inferencia sino también para entrenamiento).

Sin embargo, este enfoque tiene un costo. La precisión del modelo normalmente disminuye a medida que disminuye el número de bits de representación, lo que da como resultado una precisión menor.

Queremos reducir la cantidad de dígitos utilizados para representar un valor manteniendo la precisión... aquí es donde las técnicas de cuantificación resultan útiles.

Parte 2: Introducción a la cuantificación

Ahora sabemos que el propósito de la cuantificación es reducir la precisión de los parámetros del modelo desde anchos de bits más altos (como números de coma flotante de 32 bits) a anchos de bits más bajos (como números enteros de 8 bits).


Al reducir el número de bits que representan los parámetros originales, suele haber una pérdida de cierta precisión (granularidad).

Para que este efecto sea más intuitivo, podemos utilizar los colores de las fotografías como analogía. Por ejemplo, seleccione cualquier imagen (izquierda), pero use solo 8 colores (derecha):


Tenga en cuenta que la cookie ampliada parece más "granulada" que la original.

De manera similar, el objetivo principal de la cuantificación es reducir la cantidad de bits (colores) necesarios para representar los parámetros originales manteniendo la mayor precisión posible.

Tipos de datos comunes

Primero, veamos los tipos de datos comunes y el impacto de usarlos en lugar de la representación de 32 bits (llamada precisión total o FP32).

FP16

El primero es un ejemplo de cómo pasar de punto flotante de 32 bits a 16 bits (llamado media precisión o FP16):


El rango de valores posibles para FP16 es mucho menor que el de FP32.

BF16

Para obtener un rango numérico similar al FP32 original, se introdujo bfloat 16 como un tipo "FP32 truncado":


BF16 usa la misma cantidad de bits que FP16, pero agrega un bit exponencial, por lo que puede obtener una gama más amplia de valores y se usa a menudo en el campo del aprendizaje profundo.

INT8

A medida que se reduce aún más el número de bits, la representación se acerca más a un número entero que a un número de punto flotante. Por ejemplo, pasando de FP32 a INT8 que solo tiene 8 bits, solo 1/4 del número original de bits:


Cada vez que se reduce el número de bits, se realiza un mapeo para "comprimir" la representación original del FP32 en menos bits.

Pero en la operación real, no necesitamos mapear todo el rango FP32 [-3.4e38, 3.4e38] en INT8. Solo necesitamos encontrar una manera de asignar el rango de datos de los parámetros del modelo real a INT8.

Los métodos comunes de compresión/mapeo incluyen la cuantificación simétrica y la cuantificación asimétrica, las cuales son mapeo lineal.

Lo que discutiremos a continuación es el método de cuantificación de FP32 a INT8.

Cuantización simétrica

En la cuantificación simétrica, el rango del valor de punto flotante original se asigna a un rango simétrico centrado en cero en el espacio de cuantificación, con cero como punto medio del rango antes y después de la cuantificación.

Esto significa que el cero original en el espacio de coma flotante es exactamente cero después de ser asignado al espacio cuantificado.


Un ejemplo típico de cuantificación simétrica es la cuantificación máxima absoluta (absmax).

Dada una lista de valores, tomamos el valor absoluto más alto (α) como rango para realizar el mapeo lineal.


[-127, 127] representa el rango restringido y el rango no restringido es [-128, 127], dependiendo del método de cuantificación.

Como se trata de un mapa lineal centrado en cero, la fórmula es simple.

Primero calcule los factores de escala usando la siguiente fórmula:

- b es el número de bytes que queremos cuantificar en (8)

- α es el valor absoluto más alto

Luego usamos s para cuantizar la entrada x:


Como se muestra en la figura anterior, el valor absoluto máximo α es 10,8. Al asignar FP32 a INT8, se obtiene la siguiente fórmula:


Si desea restaurar los valores originales del FP32, también puede utilizar los factores de escala calculados previamente para la cuantización inversa.


Primero cuantice y luego decuantifique para restaurar el valor original. Todo el proceso es el siguiente:


Puede ver que algunos valores, como 3,08 y 3,02, son ambos 36 cuando se cuantifican en INT8. Entonces, cuando se descuantifican a FP32, pierden algo de precisión y ya no son distinguibles.

Esta diferencia entre el valor original y el valor cuantificado inverso se denomina error de cuantificación. Generalmente cuantos menos bits tenga el resultado de la cuantificación, mayor será el error.


cuantificación asimétrica

A diferencia de la cuantificación simétrica, la cuantificación asimétrica no es una simetría centrada en cero. En cambio, asigna los valores mínimo (β) y máximo (α) del rango de coma flotante a los valores mínimo y máximo del rango cuantificado, respectivamente.

El método que exploramos aquí se llama cuantificación de punto cero.


Observe cómo se ha movido la posición de 0. Por eso se llama cuantificación asimétrica. En el rango [-7,59, 10,8], los valores máximo y mínimo están a diferentes distancias de 0.

Debido al desplazamiento de la posición del punto cero, tenemos que calcular el punto cero en el rango INT8 para realizar el mapeo lineal. Como antes, también tenemos que calcular el o los factores de escala, pero usando la diferencia en el rango INT8 [-128, 127].


Esto es un poco complicado ya que el punto cero (z) debe calcularse en el rango INT8 para mover los pesos.

Como antes, completemos la fórmula:


Para descuantizar el valor cuantificado de INT8 a FP32, necesitamos usar los factores de escala y el punto cero (z) calculados previamente.

De lo contrario, la descuantización es sencilla:


Cuando ponemos la cuantificación simétrica y asimétrica una al lado de la otra, podemos ver rápidamente la diferencia entre los dos métodos:


En la imagen de arriba, podemos ver la característica de centro cero de la cuantificación simétrica y el desplazamiento de la cuantificación asimétrica.

Mapeo y recorte de rango (Recorte)

En el ejemplo anterior, exploramos cómo asignar un rango de valores en un vector determinado a una representación de bits bajos. Si bien esto puede mapear todo el rango de valores vectoriales, tiene un inconveniente importante: los valores atípicos.

Imagina que tienes un vector que contiene los siguientes valores:


Un valor que es mucho mayor que todos los demás puede considerarse un valor atípico. Si asignamos toda la gama de vectores, todos los valores pequeños se asignarán a la misma representación de orden inferior y perderán su carácter distintivo:


Este es el método absmax utilizado antes.Lo mismo ocurre con la cuantificación asimétrica sin recorte.

En su lugar, podemos optar por recortar ciertos valores. El recorte se refiere a establecer un rango dinámico diferente de los valores originales para que todos los valores atípicos se establezcan en el mismo valor.

En el siguiente ejemplo, configuramos manualmente el rango dinámico en [-5, 5] y todos los valores fuera de este rango se asignarán a -127 o 127, independientemente de su valor real:


La principal ventaja de este enfoque es que el error de cuantificación de los valores no atípicos se reduce significativamente. Sin embargo, dará lugar a un mayor error de cuantificación de los valores atípicos.

Calibración

En el ejemplo anterior, configuramos aleatoriamente el rango dinámico en [-5, 5], pero la decisión debe tomarse mediante un proceso de "calibración" para encontrar un rango apropiado que abarque tantos valores como sea posible y al mismo tiempo minimice el error de cuantificación.

La ejecución específica de los pasos de calibración es diferente para diferentes tipos de parámetros.

Pesos (y sesgos)

Podemos considerar los pesos y sesgos de un modelo de lenguaje grande (LLM) como valores estáticos porque se conocen antes de ejecutar el modelo. Por ejemplo, el archivo de ~20 GB de Llama 3 se compone principalmente de pesos y sesgos.

Dado que el número de variables de sesgo (millones) es significativamente menor que los pesos (miles de millones), los sesgos generalmente mantienen una mayor precisión (como INT16), mientras que el trabajo principal sobre cuantificación se centra en los pesos.

Para pesos estáticos conocidos, las técnicas de calibración para seleccionar el rango incluyen:

- Seleccionar manualmente percentiles del rango de entrada

- Optimice el error cuadrático medio (MSE) entre pesos originales y pesos cuantificados

- Minimizar la entropía entre el valor original y el valor cuantificado (divergencia KL)


Elegir un percentil, por ejemplo, da como resultado un comportamiento de recorte similar al que vimos anteriormente.

valor de activación

Las entradas que se actualizan constantemente en un modelo de lenguaje grande a menudo se denominan activaciones.


Se llaman valores de activación porque normalmente pasan por alguna función de activación, como sigmoide o relu.

A diferencia de los pesos, las activaciones cambian con los datos de entrada durante la inferencia y, por lo tanto, son difíciles de cuantificar con precisión.

Dado que estos valores se actualizan después de cada capa oculta, sus valores específicos no se conocen durante la fase de inferencia hasta que los datos de entrada pasan por el modelo.


En general, existen dos métodos para calibrar pesos y activaciones, aplicados en diferentes etapas del modelo:

- Cuantización post-entrenamiento (PTQ)

- Como sugiere el nombre, es una cuantificación después del entrenamiento.

- Entrenamiento consciente de la cuantificación (QAT)

- Cuantización durante el entrenamiento/ajuste

Parte 3: Cuantificación post-entrenamiento (PTQ)

La cuantización post-entrenamiento (PTQ) es una de las técnicas de cuantización más populares. Cuantifica los parámetros del modelo (incluidos pesos y valores de activación) una vez completado el entrenamiento del modelo.

La cuantificación de pesos puede utilizar cuantificación simétrica o cuantificación asimétrica.

Sin embargo, la cuantificación de los valores de activación requiere de una etapa de inferencia para obtener su distribución subyacente, ya que no conocemos su rango de antemano.

Existen dos formas de cuantificación de los valores de activación:

- cuantificación dinámica

- cuantificación estática

cuantificación dinámica

Después de que los datos pasan por la capa oculta, se recopilan sus valores de activación y se comparan el valor máximo (α) y el valor mínimo (β) de cada capa:


La distribución de estas activaciones se utiliza luego para calcular los valores del punto cero (z) y del factor (es) de escala necesarios para la salida cuantificada:


Este proceso se repite cada vez que los datos pasan a través de una nueva capa de red. Por lo tanto, cada capa tiene sus propios valores z y s independientes, utilizando así un esquema de cuantificación diferente.

cuantificación estática

A diferencia de la cuantificación dinámica, la cuantificación estática no calcula el punto cero (z) y los factores de escala durante la inferencia, sino que calcula estos valores antes de la inferencia.

Para encontrar estos valores, utilizamos un conjunto de datos de calibración y lo introducimos en el modelo para recopilar estas distribuciones subyacentes de los valores de activación.


Una vez recopiladas estas distribuciones, se pueden calcular los valores s y z necesarios para la cuantificación durante la inferencia.

En el momento de la inferencia real, los valores s y z no se recalculan, sino que se utilizan globalmente en todas las activaciones para cuantificarlos.

En general, la cuantificación dinámica, que calcula los valores s y z para cada capa oculta, tiende a ser más precisa. Sin embargo, esto puede aumentar el tiempo de cálculo, ya que estos valores deben calcularse en cada momento de inferencia.

Por el contrario, la cuantificación estática, aunque no es tan precisa como la cuantificación dinámica, es más rápida porque ya conoce de antemano los valores s y z utilizados para la cuantificación.

campo cuantitativo de 4 bits

La cuantificación por debajo de 8 bits siempre ha sido un desafío porque el error de cuantificación aumenta con cada bit perdido. Afortunadamente, existen varias formas inteligentes de reducir la cantidad de bits a 6, 4 o incluso 2 bits (aunque generalmente no se recomienda reducir la cantidad de bits por debajo de 4 bits).

Exploraremos dos métodos comunes en HuggingFace:

- GPTQ (el modelo completo se ejecuta en GPU)

- GGUF (posiblemente descarga capas a la CPU)

GPTQ

Se puede decir que GPTQ es uno de los métodos de cuantificación de 4 bits más famosos en aplicaciones prácticas.

Utiliza cuantificación asimétrica y la procesa capa por capa, procesando cada capa de forma independiente antes de pasar a la siguiente capa:


En este proceso de cuantificación capa por capa, primero convierte los pesos de las capas en matrices de Hesse inversas. La matriz de Hesse inversa es la segunda derivada de la función de pérdida del modelo y representa la sensibilidad de la salida del modelo a cada cambio de peso.

En pocas palabras, esencialmente muestra la importancia (importancia inversa) de los pesos en cada capa.

Las ponderaciones de valores más pequeños en la matriz de Hesse son más importantes porque pequeños cambios en estas ponderaciones pueden provocar cambios significativos en el rendimiento del modelo.


En la matriz de Hesse inversa, los valores más bajos representan pesos más "importantes"

A continuación, cuantificamos y descuantizamos la primera fila de la matriz de pesos:


Este proceso nos permite calcular el error de cuantificación (q), que podemos ponderar utilizando el valor hessiano inverso previamente calculado (h_1).

Básicamente, estamos creando un error cuantificado ponderado basado en la importancia de los pesos:


A continuación, redistribuimos este error de cuantificación ponderado a los otros pesos de la fila. Esto ayuda a mantener la funcionalidad general y el rendimiento de la red.

Por ejemplo, si hacemos esto para el segundo peso (es decir, x_2=0,3), multiplicamos el error de cuantificación (q) por el hessiano inverso del segundo peso (h_2) y le sumamos:


A continuación, continúa la misma operación para el tercer peso de una fila determinada:


Este proceso de redistribución del error de cuantificación ponderado q se repite hasta que se hayan cuantificado todos los valores.

Este método funciona porque los pesos suelen estar relacionados entre sí. Por lo tanto, cuando un peso tiene un error de cuantificación, el peso relacionado se actualizará en consecuencia mediante el hessiano inverso.

GUF-G

Aunque GPTQ es un buen método de cuantificación para ejecutar todo el modelo de lenguaje grande (LLM) en la GPU, si no existen las condiciones de hardware correspondientes, cualquier capa del LLM también se puede descargar a la CPU a través de GGUF.

Equivale a ejecutar el modelo en la CPU y GPU al mismo tiempo para compensar la falta de memoria de vídeo (VRAM).

El método de cuantificación GGUF se actualiza con frecuencia y depende del número específico de bits de cuantificación, pero el principio básico es el siguiente.

Primero, los pesos de una capa determinada se dividen en "superbloques", cada uno de los cuales contiene un conjunto de "subbloques". A partir de estos "subbloques" calculamos el (los) factor(es) de escala y el valor alfa:


Para cuantificar un "subbloque" determinado, puede utilizar la cuantificación absmax mencionada anteriormente, multiplicando el peso dado por el factor de escala (s_sub):


El factor de escala s_sub se calcula utilizando la información del "subbloque", pero se cuantifica utilizando la información s_super del "superbloque":


En resumen, esta cuantificación bloque por bloque utiliza el factor de escala del "superbloque" (s_super) para cuantificar el factor de escala del "subbloque" (s_sub).

El nivel de cuantificación de cada factor de escala puede ser diferente, y los factores de escala de "superbloque" generalmente tienen mayor precisión que los factores de escala de "subbloque".

Para ilustrar esto, exploremos varios niveles de cuantificación (2 bits, 4 bits y 6 bits):


Dependiendo del tipo de cuantificación, también se requiere un valor mínimo adicional (m) para ajustar el punto cero, estos se cuantifican al igual que el (los) factor(es) de escala.

Parte 4: Capacitación en conciencia cuantitativa (QAT)

La tercera parte describe cómo cuantificar el modelo después del entrenamiento. La desventaja de este método es que no tiene en cuenta el proceso de formación real.

Aquí es donde resulta útil el Entrenamiento de Conciencia Cuantitativa (QAT). A diferencia de la cuantificación posterior al entrenamiento (PTQ), el objetivo de QAT es aprender el proceso de cuantificación durante el entrenamiento.


QAT tiende a ser más preciso que PTQ porque la cuantificación ya se tiene en cuenta durante el proceso de formación. Así es como funciona:

Durante el proceso de entrenamiento se introduce la denominada cuantificación "falsa". Por ejemplo, primero cuantice los pesos en INT4 y luego descuantícelos nuevamente en FP32:


Este proceso permite que el modelo tenga en cuenta el error de cuantificación al calcular las pérdidas y actualizar los pesos durante la fase de entrenamiento.

Como se muestra en la figura siguiente, QAT intenta explorar el valor de pérdida en el caso de mínimos "amplios" para reducir los errores de cuantificación, porque los mínimos "estrechos" a menudo conducen a errores de cuantificación mayores.


Suponiendo que la cuantificación no se considera durante la retropropagación, el proceso de descenso de gradiente seleccionará el peso con el valor de pérdida más pequeño. Sin embargo, si está en un mínimo "estrecho", se introducirán errores de cuantificación mayores.

Por el contrario, si consideramos la cuantificación, se elegirá un peso de actualización diferente en los mínimos "anchos", con un error de cuantificación mucho menor.


Por lo tanto, aunque el método PTQ tiene un valor de pérdida bajo con alta precisión (por ejemplo, FP32), QAT también tiene un valor de pérdida bajo con baja precisión (por ejemplo, INT4), que es lo que estamos persiguiendo.

Era de 1 bit: BitNet

Vimos antes que reducir la precisión de la cuantificación a 4 bits ya es bastante pequeño, pero ¿qué pasa si la reducimos aún más?

Aquí es donde entra BitNet, representa los pesos de un modelo como un solo bit, ya sea -1 o 1, y lo hace inyectando el proceso de cuantificación directamente en la arquitectura Transformer.

La arquitectura Transformer es la base de la mayoría de los LLM y consta de cálculos que involucran capas lineales:


Estas capas lineales normalmente se representan con mayor precisión, como FP16, y es donde se encuentran la mayoría de los pesos.

BitNet reemplaza estas capas lineales con capas BitLinear:


Las capas BitLinear funcionan igual que las capas lineales normales, multiplicando los pesos por los valores de activación para calcular la salida.

Pero la diferencia es que la capa BitLinear solo usa 1 bit para representar el peso del modelo y usa INT8 para representar el valor de activación:


Las capas BitLinear, como el entrenamiento con reconocimiento de cuantificación (QAT), realizan una especie de cuantificación "falsa" durante el entrenamiento para analizar el efecto de cuantificación de los pesos y activaciones:


Entendamos BitLinear paso a paso.

cuantificacion de peso

Durante el entrenamiento, los pesos se almacenan como INT8 y luego se cuantifican a 1 bit mediante una estrategia básica llamada función signum.

Básicamente, mueve la distribución de pesos para que se centre en 0, luego asigna todos los valores menores de 0 a -1 y todos los valores mayores de 0 a 1:


Además, realiza un seguimiento de un valor β (valor absoluto medio), que usaremos más adelante en el proceso de cuantificación inversa.

Cuantización de activación

Para cuantificar activaciones, BitLinear habilita el método de valor máximo absoluto (absmax) para convertir activaciones de FP16 a INT8 ya que requieren la multiplicación de matrices (×) con mayor precisión.


Además, realiza un seguimiento de un valor α (valor absoluto máximo), que utilizaremos más adelante en el proceso de descuantización.

cuantificación inversa

Realizamos un seguimiento de α (el valor absoluto máximo de las activaciones) y β (el valor absoluto promedio de las ponderaciones), lo que nos ayudará a descuantificar las activaciones hasta el FP16.

Las activaciones de salida se reescalan usando {α, γ} para descuantificarlas con la precisión original:


Este proceso es relativamente simple y permite representar el modelo con solo dos valores, -1 o 1.

Con este enfoque, los autores observaron que a medida que crece el tamaño del modelo, la brecha de rendimiento entre el entrenamiento de 1 bit y el entrenamiento FP16 se vuelve cada vez más pequeña.

Sin embargo, esto sólo se aplica a los modelos más grandes (>30B parámetros), la brecha entre los modelos más pequeños sigue siendo grande.

Todos los LLM son de 1,58 bits.

Para mejorar los problemas de escalabilidad mencionados anteriormente, se introdujo BitNet 1.58b.

En este nuevo enfoque, cada peso del modelo no sólo puede ser -1 o 1, sino que también puede tomar 0, haciendo que cada variable sea ternaria.

Curiosamente, simplemente agregar 0 es una operación simple que mejora enormemente BitNet y acelera el proceso de cálculo.

0 poder

¿Por qué agregar 0 es una mejora significativa?

¡Esto tiene que ver con la multiplicación de matrices!

Primero, exploremos el funcionamiento básico de la multiplicación de matrices.

Al calcular la salida, multiplicamos la matriz de peso por el vector de entrada. A continuación se muestra una visualización de la multiplicación de la primera fila de la primera capa de la matriz de pesos:


Esta multiplicación implica dos acciones, multiplicar un solo peso con la entrada y luego sumarlos todos.

Por el contrario, BitNet 1.58b logra evitar el acto de multiplicación, ya que los pesos de tres valores esencialmente le dicen lo siguiente:

- 1: quiero agregar este valor

- 0: no quiero este valor

- -1: quiero restar este valor

Entonces, si sus pesos están cuantificados a 1,58 bits, solo necesita realizar la suma:


Esto no sólo acelera significativamente los cálculos, sino que también permite el filtrado de funciones.

Establecer un peso determinado en 0 equivale a ignorar la entrada, en lugar de sumar o restar el valor de entrada como si fuera 1 bit.

Cuantificar

Para realizar la cuantificación de peso, BitNet 1.58b utiliza la cuantificación de valor absoluto medio (absmean), una variante de la cuantificación de valor absoluto máximo (absmax) que hemos visto antes.

Simplemente comprime la distribución de pesos y utiliza la media absoluta (α) para cuantificar los valores. Luego redondealos a -1, 0 o 1:


En comparación con BitNet, la cuantificación de activación es la misma excepto por un aspecto: en lugar de escalar las activaciones al rango [0, 2ᵇ⁻¹], utilizamos el método de valor absoluto máximo para escalar a [-2ᵇ⁻¹, 2ᵇ⁻¹].

En resumen, la cuantificación de 1,58 bits implica principalmente dos técnicas:

- Agregue 0 para crear una representación de tres valores [-1, 0, 1]

- Cuantificación media absoluta de pesos.

El documento de BitNet llega a esta conclusión: "13B BitNet b1.58 es más eficiente que 3B FP16 LLM en términos de latencia, uso de memoria y consumo de energía".


Dirección del artículo: https://arxiv.org/abs/2402.17764

Con sólo 1,58 bits computacionalmente eficientes, obtenemos un modelo liviano.

Referencias:

https://newsletter.maartengrootendorst.com/p/a-visual-guide-to-quantization