Quería bajar lo que cuesta pasarle archivos grandes a un modelo. Sonaba fácil: el texto se repite mucho, así que tiene que poderse comprimir.
Estuve probando ideas y midiéndolas. Fueron seis y ninguna funcionó.
Primero, qué es un token
El modelo no lee letras ni palabras.
Lee tokens, que son pedazos de texto que tiene guardados en una lista de 200 mil. Esa lista es pública y la puedes revisar en el repositorio de tiktoken.
Y te cobran por token.
Esta frase, por ejemplo:
la esperanza es lo ultimo que se pierde
Son 8 tokens. Uno por palabra.
La pregunta era esa: ¿cómo hago que cueste menos de 8?
Las seis que no funcionaron
-
Mandarlo en binario.
La palabra
holaes 1 token. En binario,01101000 01101111 01101100 01100001, son 15.Con un archivo entero, 7.721 tokens se volvieron 36.582. Cinco veces peor.
El modelo cobra por token, no por byte, y una tira de ceros y unos no se parece a nada que tenga guardado.
-
Hex y base64.
Lo mismo.
holaen hex es686f6c61, que son 5 tokens.Y en base64 es
aG9sYQ==, que son 7. -
Un diccionario de palabras.
La idea era cambiar
lapor un código corto tipo§0.Pero
laya cuesta 1 token y§0cuesta 2, así que el texto entero salió 62% peor. -
Pegar palabras.
la pelotason 2 tokens.la-pelotason 4.Probé los 109 caracteres que se pueden usar para unirlas y ninguno sale mejor que dejar el espacio de siempre.
-
Buscar un token que traiga dos palabras juntas.
Me recorrí la lista entera del modelo, los 200.019 tokens que tiene guardados. Ninguno lleva un espacio en medio.
Los tokens largos que sí existen son cosas como 112 guiones seguidos, que valen 1 token pero no dicen nada.
-
Traducir a otro idioma.
El cliente aceptó el productoson 6 tokens. En chino,客户接受了产品, son 4.Ahorra, pero para traducir necesitas un modelo, así que pagas antes lo que ibas a ahorrar después.
Hubo una que sí bajó los tokens: comprimir el archivo con gzip, que es lo que usan los .zip de toda la vida. Bajaba 3 veces.
Pero el modelo no puede abrir un zip.
Lo único que sabe hacer con lo que le mandas es leerlo.
Y ese es el problema de fondo: por muy barato que salga, si el modelo no lo entiende, no sirve.
Por qué el lenguaje se repite tanto
Lee esto:
El g_to se sub__ al te__do y no se qu_so ba__r.
Lo entendiste igual.
Le faltan letras y no importó, porque tu cabeza las rellena sola.
Eso es la redundancia del lenguaje, y es la razón por la que nos entendemos.
Es lo que te deja leer con faltas, entender un acento cerrado, o escuchar a alguien en un bar con música.
Claude Shannon, el matemático que sentó las bases de cómo se transmite la información, la midió en 1951 y le puso número: cerca del 75%.
Ahí está la trampa, porque ese 75% es justo lo que yo quería quitar:
- Si lo quitas, el archivo queda en la cuarta parte. Pero ya nadie puede leerlo, porque leer consiste en rellenar esos huecos.
- Si lo dejas, se entiende perfecto. Pero pagas por todo.
Ese relleno que yo veía como desperdicio resulta que es lo que hace posible entender.
Mis seis ideas estaban intentando quitar justo eso, cada una a su manera, y por eso todas chocaban con lo mismo.
Lo que sí funciona es borrar
Si no puedes escribirlo mejor, solo queda decir menos.
Probé LLMLingua-2, de Microsoft, que corre en tu laptop y es gratis.
Lo que hace es ir palabra por palabra decidiendo si la deja o la quita, y te devuelve las que quedaron tal cual estaban, sin resumir ni reescribir nada.
Así se ve. Esto entra:
Of course, by now you and I know that the customer who has accepted and used the BUG products has been trapped into facing the influence of the reciprocity rule.
Y esto sale:
customer accepted BUG products reciprocity rule
De 33 tokens a 7.
Se fueron el of course, el you and I know, el who has, los the. Quedaron las palabras que dicen de qué va la frase, y con esas el modelo se arma el resto.
Para saber si de verdad servía, agarré dos páginas de un libro y anoté todos los datos concretos que traían. Salieron 12, cosas así:
- El 18% de respuesta que tuvo una campaña de donaciones por correo, y el 35% que tuvo la misma campaña al incluir un regalito.
- Que el regalo eran etiquetas con la dirección impresa.
- Que la matanza de Jonestown fue en noviembre de 1978.
- Los nombres: Diane Louie, Jim Jones, el antropólogo Marcel Mauss.
Después comprimí el texto a distintos niveles y fui contando cuántos de esos 12 datos seguían apareciendo:
- Comprimido 2 veces: siguen apareciendo 11 datos de los 12.
- Comprimido 5 veces: siguen apareciendo 11 datos.
- Comprimido 9 veces: siguen apareciendo 10 datos.
- Comprimido 17 veces: siguen apareciendo 8 datos.
El de 5 veces es el que me sorprendió, y ahí están midiéndose dos cosas distintas.
Comprimir 5 veces quiere decir que se fue el 80% de las palabras. De cada cinco palabras del original, quedó una.
Pero de los 12 datos solo desapareció uno.
O sea, se va casi todo el texto y casi ninguna información.
Y lo que borra es más o menos ese relleno que midió Shannon. Está quitando lo predecible y apostando a que el modelo lo reponga, igual que hiciste tú con la frase del gato.
Cómo lo probé
Por si quieres reproducirlo, es poco código.
pip install tiktoken llmlingua
Para contar tokens uso tiktoken, que es el tokenizador de los modelos de OpenAI. Le pasas texto y te devuelve la lista de tokens:
import tiktoken
enc = tiktoken.get_encoding("o200k_base")
enc.encode("la esperanza es lo ultimo que se pierde")
# 8 tokens
[enc.decode([t]) for t in enc.encode("la esperanza es lo ultimo que se pierde")]
# ['la', ' esperanza', ' es', ' lo', ' ultimo', ' que', ' se', ' pierde']
El segundo enseña por dónde parte cada palabra. Ahí se ve que el espacio va pegado al token.
Y para comprimir, LLMLingua-2. El rate es cuánto quieres conservar, así que 0.25 es comprimir 4 veces:
from llmlingua import PromptCompressor
compresor = PromptCompressor(
model_name="microsoft/llmlingua-2-bert-base-multilingual-cased-meetingbank",
use_llmlingua2=True,
device_map="cpu",
)
resultado = compresor.compress_prompt(texto, rate=0.25)
print(resultado["compressed_prompt"])
La primera vez se descarga el modelo, que pesa unos cientos de megas. Después, las dos páginas que usé de ejemplo las procesó en menos de un segundo.
Dos cosas que sí encontré
-
Las tildes cuestan el doble.
ultimoes 1 token,últimoson 2. El tokenizador vio mucho español escrito sin acentos. -
Las notaciones comprimen de verdad. "dos átomos de hidrógeno y uno de oxígeno" es
H2O, cuatro veces menos. Pero solo sirven donde aplican. En un libro casi no hay nada que notar, en un reporte financiero hay muchísimo.
Donde sí queda margen
Todo lo de arriba lo probé sobre texto escrito, o sea frases seguidas: un libro, un correo, un contrato.
Con una hoja de cálculo, un CSV o un export de la base de datos la cosa cambia.
En una tabla de 3.000 filas la misma columna trae el mismo valor una y otra vez, exactamente igual. Eso sí lo puedes escribir una vez y referenciarlo, sin perder nada.
En un texto escrito eso casi no pasa. Las frases se parecen, pero es raro que dos sean idénticas.
Así que la idea del diccionario, la que me falló con la y que, sí sirve. Solo que en una hoja de cálculo, no en un libro.
Qué usar hoy
Yo no construí nada nuevo, pero estas tres ya existen y hacen el trabajo:
- LLMLingua-2 borra palabras. Le dices cuánto quieres comprimir y te devuelve el texto ya recortado.
- Headroom es la versión completa. Detecta qué tipo de contenido es, separa lo que hay que conservar de lo que se puede quitar, y guarda el original por si lo necesitas.
- graphify va por otro lado. Convierte una carpeta en un grafo que puedes navegar, así que en vez de comprimir el texto cambias lo que le mandas.
Lo que me llevo
Lo mejor fue medir antes de programar. Cada idea se caía enseguida.
No construí lo que quería, pero terminé entendiendo el problema un poco mejor.
No encontré una forma válida, pero si se te ocurre algo, bienvenida la idea.