Deepthougt 8B. Controla el razonamiento de un LLM

Últimamente se ha puesto de moda un nuevo paradigma de modelo de lenguaje. Aquellos entrenados para razonar.

Básicamente son modelos que se plantean la resolución de un problema paso a paso. Y luego recorren esos pasos aprovechando que los LLM son recursivos.

Derpthougt 8B funciona así, eso no es una novedad. El cambio viene en la idea de como plantea el razonamiento. Lo hace de forma estructurada usando JSON. Eso nos permite manipular su razonamiento fácilmente, interfiriendo en sus «pensamientos».

A diferencia de lo habitual en los LLM. Para funcionar necesita como mínimo dos llamadas al modelo.

Vamos a empezar a ver cómo funciona. Un aviso importante, el modelo es muy estricto con los prompts. Hay que respetarlos lo más estrictamente posible.

Para la prueba vamos a usar llamacpp con la versión cuantizada Q8.

./llama-server -m ./deepthought-8b-llama-v0.01-alpha-Q8_0.gguf

El prompt inicial es el siguiente:

<|im_start|>system
You are a superintelligent AI system, capable of comprehensive reasoning. When provided with <reasoning>, you must provide your logical reasoning chain to solve the user query. Be verbose with your outputs.<|im_end|>
<|im_start|>user
{{User Query}}<|im_end|>
<|im_start|>reasoning
<reasoning>
[
{
"step": 1,

Podéis ver qué se usa el truco de comenzar la respuesta del modelo de lenguaje para obligar al modelo de lenguaje a seguirla.

En este primer paso genera el razonamiento, siguiendo cada paso la siguiente estructura JSON:

  {
    "step": 1,
    "type": "problem_understanding",
    "thought": "I need to count the number of times the letter 'r' appears.
  }

Una vez tenemos el razonamiento en formato JSON lo volvemos a pasar con este prompt.

<|im_start|>reasoning
<reasoning>
{{Steps JSON}}
</reasoning>|im_end|>
<|im_start|>assistant

Y obtenemos la respuesta.

Veamos un ejemplo con la tipica pregunta de cuantas letras «r» tiene «Straberrry» (tiene una R de más a proposito)

El primer prompt

<|im_start|>system
You are a superintelligent AI system, capable of comprehensive reasoning. When provided with <reasoning>, you must provide your logical reasoning chain to solve the user query. Be verbose with your outputs.<|im_end|>
<|im_start|>user
How many letters "r" does the word strawberrry have?<|im_end|>
<|im_start|>reasoning
<reasoning>
[
{
"step": 1,

Y luego el segundo prompt con todos los pasos del razonamiento:

<|im_start|>reasoning
<reasoning>
[
{
"step": 1,
"type": "problem_understanding",
"thought": "I need to count the number of times the letter 'r' appears in the word 'straberrry'."
},
{
"step": 2,
"type": "data_gathering",
"thought": "The word to analyze is 'straberrry'. I'll need to examine each character in this word."
},
{
"step": 3,
"type": "hypothesis_formation",
"thought": "Based on a quick glance, I hypothesize that there are 3 'r's in the word 'straberrry'."
},
{
"step": 4,
"type": "analysis",
"thought": "I'll go through the word character by character: s (not r), t (not r), r (count: 1), a (not r), b (not r), e (not r), r (count: 2), r (count: 3), r (count: 4), y (not r)."
},
{
"step": 5,
"type": "calculation",
"thought": "After analyzing each character, I've counted 4 occurrences of the letter 'r'."
},
{
"step": 6,
"type": "verification",
"thought": "To verify, I'll recount: s-t-r-a-b-e-r-r-r-y. This confirms 4 'r's."
},
{
"step": 7,
"type": "error_checking",
"thought": "I'll double-check for any missed 'r's or counting errors. No errors found."
},
{
"step": 8,
"type": "conclusion_drawing",
"thought": "The letter 'r' appears 4 times in the word 'straberrry'."
},
{
"step": 9,
"type": "reflection",
"thought": "My initial hypothesis was close but not exact. This reminds me to be careful about quick estimates and to always verify."
},
{
"step": 10,
"type": "implementation",
"thought": "The final response should be the number 4, as this is the correct count of 'r's in 'straberrry'."
}
]</reasoning>|im_end|>
<|im_start|>assistant

El código Python para ejecutar esto contra el servidor de llama.cpp:

import requests
import json

llamaURL = "http://127.0.0.1:8080" 

def instruct(prompt, n_predict, temperature):
    #print("Asking llama.cpp")
    #print(prompt)
    
    response = requests.post(llamaURL+"/completion", json={
        'prompt': prompt,
        'n_predict': n_predict,
        'temperature': temperature,
        'cache_prompt': True
    })
    
    if response.status_code == 200:
        #print("Response llama.cpp")
        #print(response.json().get('content'))
        return response.json().get('content')
    else:
        raise Exception(f"Request failed with status code {response.status_code}")

def promptResolve(steps):
    return '''<|im_start|>reasoning
<reasoning>
[
  {
    "step": 1,
'''+steps+'''<|im_end|>
<|im_start|>assistant'''

def promptSteps(query):
    return '''<|im_start|>system
You are a superintelligent AI system, capable of comprehensive reasoning. When provided with <reasoning>, you must provide your logical reasoning chain to solve the user query. Be verbose with your outputs.<|im_end|>
<|im_start|>user
'''+query+'''<|im_end|>
<|im_start|>reasoning
<reasoning>
[
  {
    "step": 1,'''


try:
    query = '''How many letters "r" does the word strawberrry have?'''    

    steps = instruct(promptSteps(query), 8000, 0.5)    
    result = instruct(promptResolve(steps), 8000, 0.5)
    print(promptResolve(steps))
    print(result)
except Exception as e:
    print(e)

Controlando el razonamiento:

Para controlar el razonamiento hemos de interferir en la creación de pasos. Eso lo haremos usando el token «}» como «stop token». De esta forma después de cada paso de razonamiento (en JSON, os recuerdo) el modelo de lenguaje retornará el control a nuestro código, pudiendo nosotros modificar el paso recién añadido o el siguiente paso que le pasaremos al modelo

En este caso añado un ejemplo para controlar el número de pasos que va generar el modelo.

import requests
import json

llamaURL = "http://127.0.0.1:8080" 

def instruct(prompt, n_predict, temperature):
    #print("Asking llama.cpp")
    #print(prompt)
    
    response = requests.post(llamaURL+"/completion", json={
        'prompt': prompt,
        'n_predict': n_predict,
        'temperature': temperature,
        'cache_prompt': True
    })
    
    if response.status_code == 200:
        #print("Response llama.cpp")
        #print(response.json().get('content'))
        return response.json().get('content')
    else:
        raise Exception(f"Request failed with status code {response.status_code}")


def generateStep(prompt, n_predict, temperature):
    #print("Asking llama.cpp")
    #print(prompt)
    
    response = requests.post(llamaURL+"/completion", json={
        'prompt': prompt,
        'n_predict': n_predict,
        'temperature': temperature,
        'cache_prompt': True,
        'stop': ['}']
    })
    
    if response.status_code == 200:
        #print("Response llama.cpp")
        #print(response.json().get('content'))
        return response.json().get('content')
    else:
        raise Exception(f"Request failed with status code {response.status_code}")


def promptStep(query, steps):
    return '''<|im_start|>system
You are a superintelligent AI system, capable of comprehensive reasoning. When provided with <reasoning>, you must provide your logical reasoning chain to solve the user query. Be verbose with your outputs.<|im_end|>
<|im_start|>user
'''+query+'''<|im_end|>
<|im_start|>reasoning
<reasoning>
'''+steps

def promptResolve(steps):
    return '''<|im_start|>reasoning
<reasoning>
'''+steps+'''
<reasoning><|im_end|>
<|im_start|>assistant'''

def openStep(i):
    return '''    {
    "step": '''+str(i)+''',
'''

def closeStep():
    return "},"


try:
    query = '''How many letters "r" does the word strawberry have?'''
    
    stepByStep = '''[
'''
    for i in range(1,11):
        stepByStep += openStep(i)
        stepByStep += generateStep(promptStep(query, stepByStep), 8000, 0.5)
        stepByStep += closeStep()

    stepByStep += ''']'''    
    result = instruct(promptResolve(stepByStep), 8000, 0.5)
    print(promptResolve(stepByStep))
    print(result)
except Exception as e:
    print(e)

Algunas ideas que se pueden hacer con esto:

  • Controlar el número de pasos
  • Controlar el tiempo de ejecución
  • Eliminar pasos
  • Añadir pasos
  • Crear un árbol de razonamiento

Puede lo que aquí se explica en el siguiente vídeo:

Haz click para ver el vídeo en mi canal de YouTube

¿Cómo de abierto es un modelo de lenguaje?

La OSI presento hace poco una definición de modelo de IA abierta, el equivalente del «Open Source» para los modelos de lenguajes. Antes de entrar en detalles con lo que ha definido la OSI vamos a hablar de los diferentes aspectos que se pueden «liberar» Grosso modo:

  • API: dar acceso al modelo a través de una API pública.
  • Pesos: el modelo propiamente dicho. Junto con el modelo se libera información de aspectos técnicos cómo información sobre cómo ejecutarlo o cuál es el formato de los prompts
  • Pesos destilados: es una versión reducida del modelo de lenguaje obtenidos a partir de «refinar» el modelo original. Es más cerrado puesto que complica el generar modelos derivados. Por ejemplo el finetuning del modelo.
  • Documentación de cómo usarlo: no basta con los pesos, hay que saber cómo usarlos. La arquitectura del modelo, el formato del prompt, …
  • Cómo replicar el modelo: generalmente tiene la forma de «el paper» del modelo. Dónde se explica cómo se ha creado el modelo y permite duplicarlo. No siempre es tan exhausto, últimamente hay muchos casos que parecen más un documento de marketing que de investigación.
  • El código de entrenamiento: el código necesario para entrenar tu propio modelo «igual» que el proporcionado
  • Descripción del dataset: un resumen indicando el tipo de datos y su origen. Por lo general se mezclan dataset públicos, privados y datos sintéticos.
  • Dataset: los datos usados para el entrenamiento. Es la parte más difícil que sea liberada ya que es lo más valioso y complicado de conseguir.

Por lo general las licencias suelen restringir algunas de las siguientes libertades:

  • Usar el modelo de forma comercial. Muchos modelos solo permiten su uso no comercial.
  • Usar el modelo de forma libre sin limitaciones. Es habitual que las empresas limiten los usos del modelo. La más habitual es que prohíban usarlo para entrenar otros modelos.
  • Modificar/reentrenar el modelo. Algunas empresas prohíben modificar sus modelos.

Para cumplir con la OSI es necesario que la licencia del modelo no tenga restricciones.

Para más información puedes ver el siguiente vídeo de mi canal:

Haz click para ver el vídeo en mi canal de YouTube

Ejemplo de Speculative Decoding con Qwen-2.5-coder-7B y 0.5B.

Speculative Decoding es un técnica (realmente un conjunto de ellas) para acelerar un modelo de lenguaje usando un «oraculo» que genera un borrador tratando de adivinar lo que el modelo va a generar. En este caso usaremos Qwen-2.5-coder-0.5B como oraculo para generar el borrador.

Para esta prueba usaremos un ejemplo que viene con Llama.cpp. Pero antes de poder usarlo hay que cambiar en el fichero examples/speculative/speculative.cpp el valor de la constante SPEC_VOCAB_MAX_SIZE_DIFFERENCE de 100 a 200.

#define SPEC_VOCAB_MAX_SIZE_DIFFERENCE  200

Una vez hecho esto hay que volver a compilarlo y ya se puede probar con el comando:

./llama-speculative
-m models/Qwen2.5.1-Coder-7B-Instruct-Q8_0.gguf
-md models/Qwen2.5-coder-0.5b-instruct-q4_k_m.gguf
-c 4000 --draft 8 --color
--sampling-seq k --top-k 10 --temp 0.7
-p "Generate a tetris game using JS and HTML in one HTML file"
-ngl 99 -ngld 99

Puedes verlo en funcionamientos en el siguiente vídeo (así como la explicación de cada parámetro):

Haz click para ver el vídeo en mi canal de YouTube

Qwen 2.5 Coder: Contexto extendido, templates y CoT.

Qwen 2.5 coder es una familia de modelos que ha dado muy buenos resultados generando código. Tanto que pueden competir con modelos privados mucho mayores como ChatGPT4o o Claude 3 Opus. 

Podéis ver más sobre estos modelos en el siguiente vídeo:

Haz click para ver el vídeo en mi canal de YouTube

Este post se centra en los prompts necesarios para usar sus diversas funcionalidades.

Completar texto:

La funcionalidad habitual de los modelos de lenguaje. Le pasas un texto y va prediciendo las siguientes palabras (bueno, tokens).

No necesita ningún prompt especial.

Rellenar texto intermedio (infill):

Una funcionalidad imprescindible para completar código. El código no se escribe como la prosa. Es habitual insertar código en mitad de ficheros ya escritos. Además hay que tener en cuanta todo el contenido del fichero.

El prompt divide el texto en un prefijo (el código que va antes del texto a generar) y un sufijo (el código que va después del texto a generar)

<|fim_prefix|>{code_pre}<|fim_suffix|>{code_suf}<|fim_middle|>

Completar proyecto:

Otra función útil es que para completar código se tenga en cuenta múltiples ficheros del proyecto y la estructura del mismo.

El prompt consta del nombre del repositorio (puede ser cualquiera) y los distintos ficheros que se quiere que se tengan en cuenta. Cada fichero incluye la ruta con su nombre y tras un salto de línea el código.

<|repo_name|>{repo_name}
<|file_sep|>{file_path1}
{file_content1}
<|file_sep|>{file_path2}
{file_content2}

Seguir instrucciones o chatear:

Está funcionalidad se puede usar tanto para dar instrucciones al modelo como para mantener una conversación con él.

En todos estos casos es importante respetar los saltos de línea.

<|im_start|>system
{system_prompt}<|im_end|>
<|im_start|>user
{prompt}<|im_end|>
<|im_start|>assistant

Contexto extendido a 128k:

El contexto por defecto es de 32k tokens, pero usando YARN con un escalado de x4 puede llegar a 128k (cada motor de inferencia tendrá su forma de configurar esto, por ejemplo en llama.ccp es usando los parámetros:  )

Esto solo funciona en los modelos de 7B o más parámetros: -rope-scaling yarn –rope-scale 4.0

Generar texto con CoT (cadena de pensamientos):

De regalo este truco, no es oficial, yo lo he sacado de un comentario en Reddit del usuario Eposnix. Este usuario compartió un prompt que permite realizar CoT aplicado a la generación de código. Hace que el modelo de lenguaje entre en bucle tratando de corregir el código que genera hasta que esté perfecto. Cuidado que puede hacer que el mdoelo entre en bucle, por lo que es recomendable usar este prompt limitando el numero total de tokens que puede generar.

1. Generate your initial code solution
2. Rate your solution on a scale of 1-5 based on these criteria:
- 5: Exceptional - Optimal performance, well-documented, follows best practices, handles edge cases
- 4: Very Good - Efficient solution, good documentation, follows conventions, handles most cases
- 3: Acceptable - Working solution but could be optimized, basic documentation
- 2: Below Standard - Works partially, poor documentation, potential bugs
- 1: Poor - Non-functional or severely flawed approach

3. If your rating is below 3, iterate on your solution
4. Continue this process until you achieve a rating of 3 or higher
5. Present your final solution with:
- The complete code as a solid block
- Comments explaining key parts
- Rating and justification
- Any important usage notes or limitations

Tras ese prompt puedes especificar que deseas que programe Qwen

Crear un podcast de cualquier blog o noticia usando IA en local (llama.cpp + Piper)

Hace no mucho Google sacó una herramienta que permite crear podcasts donde dos IAs discuten sobre el texto que les pasas. Meta no hace mucho sacó su propia versión usando Llama que se puede usar en local. Aquí presento mi idea, con código para que podáis jugar vosotros.

Podéis ver el vídeo con más detalles en mi canal de YouTube:

Haz click para ver el vídeo en mi canal de YouTube

El proceso tiene varias partes:

Extraer el texto: 

El documento de origen puede tener una gran cantidad de formatos, para que funcione con la IA es necesario pasarlo a texto plano (txt). En este caso esa parte del trabajo os lo dejo a vosotros.

Limpiar el texto: 

Es posible que el texto extraído tenga «ruido», caracteres no válidos o que no forman parte del texto principal (cabeceras, notas de pie, número de página). Los resultados son mejores si le pedimos a una IA que limpie el texto.

Resumir el texto:

Su utilidad no es solo tener un podcast más corto y «concentrado». También sirve para lograr que el texto «quepa» dentro del contexto del modelos del lenguaje.

Generar el guión del podcast: 

En este caso se generará como si hablaran dos personas. Alice y Bob. Para ello pediremos al modelo de lenguaje que genere un podcast 

Generar el audio:

Aquí surge el problema de cómo generar audio con dos voces. En principio con Piper podemos fácilmente usar el parámetro –json-input y un fichero en formato json, indicando la voz usada en cada línea (es necesario un fichero de voz con múltiples voces). Por desgracia es necesario crear tu propia compilación de Piper. Así que haremos algo más simple: dividiremos el texto en líneas aprovechando que cada una va precedida de la voz que lo dice (el uso de [Alice] y [Bob] no es accidental). Y generamos un fichero wav independiente para cada línea. Luego tendremos que unirlos. En mi caso uso la herramienta sox.

const fetch = require('sync-fetch')
const fs = require("fs");
const { execSync } = require('child_process');

const llamaURL = "http://127.0.0.1:8080/completion";
const tokenizerURL = "http://127.0.0.1:8080/tokenize";
const inputFilename = "./text.txt";

//Llama a llama.cpp
function CallIA(prompt, n_predict, temperature) {
	console.log("Asking llama.cpp");
	
	let response = fetch(llamaURL, {
		method: 'POST',
		body: JSON.stringify({
			prompt,
			n_predict: n_predict,
			temperature: temperature,
			cache_prompt: true
		})
	}).json().content;

	return response;
}

//Consulta el tamaño en tokens del texto
function callTokenizer(text) {
	console.log("Asking llama.cpp");    

	let response = fetch(tokenizerURL, {
		method: 'POST',
		body: JSON.stringify({
            text,
            add_special: true
        })    
    }).json();

    console.log(response.tokens);
	return response.tokens.length;
}

//Limpiar texto
function generatePromptClean(text){
    return "<|im_start|>system\nYou are Qwen, created by Alibaba Cloud. You are a helpful assistant.<|im_end|>\n<|im_start|>user\nRepite el texto que te voy a pasar, limpia los caracteres extraños y corrige los posibles errores\n"+text+"\n<|im_end|>\n<|im_start|>assistant\n";
}  
//Resumir texto
function generatePromptSumarize(text){
    return "<|im_start|>system\nYou are Qwen, created by Alibaba Cloud. You are a helpful assistant.<|im_end|>\n<|im_start|>user\nResume el texto que te voy a pasar, extrae las partes más interesantes y curiosas de él\n"+text+"\n<|im_end|>\n<|im_start|>assistant\n";    
}   
//Generar guion
function generatePromptDialog(text){
    return "<|im_start|>system\nYou are Qwen, created by Alibaba Cloud. You are a helpful assistant.<|im_end|>\n<|im_start|>user\nConvierte el siguiente texto en una conversacion, en español, animada y divertida entre dos personas: Alice y Bob. Indica cada usuario poniendo delante [Alice] o [Bob].Comienza Alice\n"+text+"\n<|im_end|>\n<|im_start|>assistant\n[Alice]";    
}   

function generateAudio(text){
    //Almacena listado de ficheros para concatenar con sox
    var concatSox = ""; 

    //Se separa cada linea que empieza por [
    var podcastWithVoices = podcast.split("[");
    for(var i = 0; i < podcastWithVoices.length; i++){
        var line = podcastWithVoices[i].trim();
        //Elegimos la voz Alice/Bob
        var speaker;
        if(line.startsWith("Alice")){
            speaker = 1;
        } else {
            speaker = 0;
        }

        //Eliminamos el nombre para que no lo lea
        line = line.replace("Alice]", "").replace("Bob]", "");
        
        //Llamamos a Piper para generar el audio en un fichero .wav
        execSync(`echo '${line}' | piper --model ./models/es_ES-sharvard-medium.onnx --speaker ${speaker} --output_file podcast${i}.wav`, { encoding: 'utf-8' });

        //Añadimos el fichero a la lista para concatenar
        concatSox += "podcast"+i+".wav ";
    }

    //Unimos todos los ficheros .wav
    console.log(`sox ${concatSox} podcast.wav`);
    execSync(`sox ${concatSox} podcast.wav`);
}

//Leer fichero de texto
var text = fs.readFileSync(inputFilename, 'utf8');

//Tokenizador calcula cuantos tokens ocupa el texto (no he logrado que funcione)
//callTokenizer(text);

//Limpiamos el texto
//text = callIA(generatePromptClean(text), 8000, 0.2)

//Resumimos el texto
//text = callIA(generatePromptSumarize(text), 8000, 0.2)

//Generamos el dialogo
//Es necesario añadir [Alice] 
var podcast = "[Alice]"+CallIA(generatePromptDialog(text), 8000, 0.2);
console.log(podcast);

//Limpiamos el texto generado por la IA
podcast = podcast.replace(/(\r\n|\n|\r)/gm, "");

//Llama a piper para generar el audio linea a linea
generateAudio(podcast);

Si queréis ver (bueno, oir) el resultado, tenéis un ejemplo al final del vídeo.

Riesgos de usar una IA local

Los modelos de lenguaje (vamos a centrarnos en ellos en este artículo, aunque lo aquí visto aplica al resto de los modelos) empiezan a verse cada vez en más usos y no solo la IA privada, también la IA local con despliegues de sistemas en los servidores propios de muchas empresas. Las ventajas de tener modelos propios son claras: mayor control, mayor personalización, mayor privacidad. Pero también tiene sus riesgos de seguridad .Sin embargo se suele hablar poco de ellos:

  • Vulnerabilidades y Bugs: Los modelos de lenguaje necesitan un software para que los «ejecute» (realice la inferencia). Este software está sujeto a bugs y vulnerabilidades. Cómo con cualquier software hay que mantenerlo actualizado y estar atento a posibles vulnerabilidades.
  • Marcado de textos: Un modelo puede marcar en secreto el texto que genera. Esto permitiría saber para que usas el modelo y rastrear su uso. Puedes saber más sobre este tema en el siguiente enlace: https://youtu.be/bc_bQeAY9-M
  • Modelos trampa para extraer datos del finetunig: si tu plan es entrenar un modelo con datos propios de tu empresa, se ha logrado preparar modelos trampa que permiten recuperar parte de los datos usados como finetuning. En caso de usar RAG hay bastantes técnicas para recuperar los datos de los argumentos usados como fuente de información en el RAG.
  • Agentes durmientes: suena a película de espías pero es posible tener LLMs con comportamientos ocultos que solo se activen en ciertas condiciones. Por ejemplo, generar código con bugs solo cuando detecte que se trabaja en ciertos proyectos.
  • Mal uso de herramientas: últimamente los modelos de lenguaje están ganando la capacidad de usar herramientas. Una muy habitual es permitirles ejecutar código Python. Sin embargo los modelos podrían usar esta capacidad para enviar información al exterior o abrir conexiones a nuestro equipo desde el exterior. Combinado con el caso anterior podría ser realmente peligroso.

Más información en el vídeo de mi canal de YouTube:

Haz click para ver el vídeo en YouTube

Así funciona Speculative Decoding. Acelera los modelos de lenguaje «adivinando» su respuesta.

En este post, vamos a explorar una fascinante técnica para mejorar el rendimiento de los modelos de lenguaje llamada speculative decoding. Esta estrategia se basa en la idea de «adivinar» las respuestas antes de tiempo, tal como lo haría un oráculo.

Vamos a sumergirnos en los detalles para comprender cómo funciona esta técnica y cómo nos permite acelerar los tiempos de procesamiento.

Puedes ver la versión en vídeo en YouTube (https://youtu.be/qV0deLwEOhk):

Haz click para ver el vídeo en YouTube

¿Cómo Funciona Speculative Decoding?

La técnica de speculative decoding se basa en un proceso que busca acelerar la generación de texto de los modelos de lenguaje mediante predicciones previas. Esto se logra a través de la combinación de un modelo principal y un oráculo, el cual tiene la tarea de anticipar las respuestas posibles para reducir el tiempo de procesamiento.

Para entender mejor cómo funciona, imaginemos un ejemplo: supongamos que queremos completar la frase «El perro ladra». Antes de que el modelo principal comience a generar una respuesta, le pedimos al oráculo que intente predecir lo que va a decir. Supongamos que el oráculo predice: «El perro ladra a la luna llena».

Con esta predicción inicial, tenemos tanto la frase original como la posible continuación del oráculo. Aquí es donde entra el verdadero potencial de speculative decoding: los modelos de lenguaje pueden procesar varios «prompts» en paralelo. Es decir, en lugar de esperar a que el modelo genere cada token uno por uno, se reutilizan cálculos previos y se aceleran los resultados generando varios tokens a la vez.

Usamos estos prompts en paralelo para evaluar la predicción del oráculo añadiendo un token en cada prompt:

Al evaluar los prompts se genera el siguiente token:

Ahora evaluamos en que caso el token sugerido por el oráculo y el predicho coincide:

Cada token acertado lo damos como predicho correctamente por el oraculo.

En nuestro ejemplo con una sola iteración el sistema ha predicho 3 tokens: «a la gata«

En este caso cada iteración es más costosa que calcular un solo token sin speculative decoding, ya que hay que sumar el tiempo de ejecutar los múltiples prompts en paralelo (hay que recordar que se reaprovechan muchos cálculos) y de generar la predicción oráculo.

Si el oráculo acierta, se puede ahorrar una cantidad significativa de tiempo generando varios tokens de una sola vez. Este proceso tiene, sin embargo, ciertos riesgos y limitaciones. Cuando el oráculo se equivoca, se produce una penalización en términos de eficiencia, ya que se pierde el beneficio del procesamiento paralelo. Por ello, el rendimiento de speculative decoding está directamente relacionado con la precisión del oráculo.

¿Qué es el Oráculo?

El «oráculo» no es más que una manera de generar predicciones preliminares para acelerar el proceso de decodificación. A continuación, se presentan algunas de las diferentes alternativas que existen para un oráculo:

  1. Modelo más pequeño y rápido: Utiliza un modelo de lenguaje más pequeño para generar una versión preliminar de la respuesta.
  2. N-gramas: Consiste en el uso de patrones comunes de palabras que se encuentran en documentos similares. Esta técnica es efectiva cuando se trabaja con temas específicos, ya que aprovecha asociaciones típicas de palabras.
  3. Reglas heurísticas: Estas reglas permiten predecir cuál es la siguiente palabra basándose en patrones lógicos. Se han usado durante décadas en los entornos de desarrollo como sistemas de sugerencias.
  4. Uso del prompt: En tareas de resumen, es común que conceptos presentes en el prompt aparezcan también en la respuesta. Esta técnica aprovecha dicha redundancia para hacer predicciones más acertadas.
  5. Modelos Multi-Head: Estos modelos utilizan múltiples cabezas para predecir varios tokens a la vez, lo cual permite generar varias alternativas de predicción simultáneamente. Esto puede aumentar la eficiencia en comparación con modelos que predicen un solo token por vez.

Ventajas y Desafíos

La mayor ventaja de speculative decoding es la velocidad. Cuando el oráculo acierta, podemos generar varios tokens en el tiempo que normalmente tomaría generar uno. Sin embargo, esto está condicionado por la calidad de las predicciones del oráculo. Si falla con frecuencia, los beneficios desaparecen.

Para evaluar si merece la pena usar speculative decoding, podemos comparar el tiempo que toma generar un token con el método convencional frente al tiempo y la penalización que introduce el oráculo. Si la velocidad total resulta mejor, entonces vale la pena implementarlo.

¡Prueba Speculative Decoding!

Si estás interesado en probar esta técnica, puedes echar un vistazo al proyecto Llama.cpp, que incluye varios ejemplos y diferentes implementaciones de speculative decoding. En el directorio «examples/speculative», «examples/lookahead» y «examples/lookup» encontrarás las implementaciones que puedes usar para experimentar y explorar distintas opciones de speculative decoding.

¿Cómo descubrir con qué modelo de lenguaje estás hablando?

Hace poco vivimos un caso en que liberaron una nueva IA(en teoría revolucionaria). Sin embargo en cuanto la gente comenzó a chatear con ella no tardó en descubrir que realmente era otra IA con un poco de magia en el prompt. ¿Cómo podemos distinguir qué modelo es simplemente conversando con el?

Realmente no hay ninguna prueba definitiva, hay que intentar realizar tantas pruebas cómo sea posible y ver si el peso de las pruebas indica un modelo en concreto. Con los modelos libres hay que tener en cuenta que pueden haber sufrido un fine-tuning, lo que puede complicar la cosa.

Veamos que pistas tenemos:

  • Preguntarle al propio modelo. Es lo más básico pero puede funcionar. Cómo se le puede convencer, via prompt del sistema, de que mienta. Se pueden usar métodos más taimados como decirle que proponga palabras que rimen con su nombre, una adivinanza o una poesía donde cada línea empiece por una letra de su nombre
  • Verificar si está censurado y sobre que temas. La mayoría de los modelos que se lanzan tienen censura. Si no la tiene podría señalar que es un finetunig. También podemos ver sobre que temas responde y compararlos con los modelos conocidos
  • Ver cómo responde a temas censurados  Las respuestas a temas censurados suelen ser muy similares dentro del mismo modelo. Lo que puede ser una pista comparando sus negativas con las de otros modelos.
  • Problemas límites del modelo. Hay problemas que solo algunos modelos pueden responder, incluso que depende cómo se le pregunte. Reunir varias de estas cuestiones y ver cómo las responde puede delimitar de que lenguaje se trata.
  • Lenguas e idiomas. No todos los modelos entienden todos los lenguajes o idiomas. Puede ser una gran pista ver cuáles entiende.
  • El tokenizador. La forma en que cada familia de modelos divide las palabras (genera los tokens) es diferente. Aquí el problema está en como ver esos tokens en una conversación. No es algo que se pueda ver de forma directa y requiere trucos que no siempre es seguro si están funcionando.

Puedes ver el tema desarrollado en este vídeo de mi canal de Youtube:

Haz click para ver el vídeo en mi canal de YouTube

¿Eres una IA?

Vivimos en un momento en que podemos empezar a preocuparnos del «peligro» de la I.A. sin que piensen que hablamos de ciencia ficción. ¿Pero y si esa preocupación llega demasiado tarde? En concreto unos cartoce mil millones de años tarde (año arriba, año abajo). ¿Es posible que todos nosotros seamos una IA y no lo sepamos?

Haz click para ver el vídeo en mi canal de YouTube

Dadme un momento y os explico cómo es posible que seamos IA y no nos hayamos dado cuenta. Para ello vamos a recurrir a las hipótesis de Nick Bostrom, uno de los mayores ideologos del peligro de las super inteligencias. Sin embargo usando sus propios escritos podríamos concluir que ya es tarde.

Para ello empezaremos por revisar su trabajo: «Are you living in a computer simulation?» En el que trata de resolver la cuestión de si vivimos o no en una simulación. Si bien su desarrollo, en mi opinión, peca de simplificar demasiado el tema ignorando gran parte de su complejidad reduciéndolo todo a una simple fórmula. Me vais a permitir que use sus conclusiones, puesto que cuenta con bastante apoyo popular que defiende su tesis. (Principalmente debido a que presenta sus ideas de una forma sencilla y elegante y la conclusión es muy atractiva, mientras que las réplicas suelen ser más complicadas de entender y nos devuelven a la triste realidad).

La tesis se fundamenta en que si se cumplen estos puntos:

  • Si alguna civilización alcanza el nivel tecnológico suficiente para simular un universo (el habla de sobrevivir el tiempo suficiente pero nada nos asegura que sea posible hacerlo)
  • Si encuentra interesante simular un universo y su vida.
  • Si las simulaciones a su vez permiten los dos puntos anteriores (este punto no viene explícitamente en el texto original)

En ese caso es posible que haya simulaciones infinitas. Universos simulando universos que a su vez son simulaciones de universos, …

Como se supone que esto tenderia a infinito (no contempla que cada universo consumiría recursos del universo original…por decirlo de forma burda: se ejecutan todos en la misma CPU). La posibilidad de que el nuestro sea el universo original tiende a 0. Por lo que nosotros viviríamos casi seguro en una simulación.

Siguiendo con la obra del mismo autor llegamos a «Superinteligencia» (El libro que nos  causó miedo de las IA). Considera como IA aquellos agente inteligentes que surjan de emular el funcionamiento del cerebro (¡Ojo! si volcamos la mente de una persona a ese emulador no es una IA, solo si la IA surge aprovechando lo aprendido para crear esa emulación). Siguiendo su propia definición si viviéramos en un universo simulado, todos seriamos IA. La pregunta de si podemos evitar que la IA destruya el mundo y otros temores que comenta en «Superinteligencia» quedaría distorsionado por el hecho de que ya seriamos IA.

¿Tiene algo de sentido todo esto? El argumento de la simulación tiene muchas criticas realizadas por expertos en diversos temas que van de la filosofía a varias ramas de la física. Sin embargo, mi principal pega es más sencilla y no tan compleja. Creo que la visión del autor del problema es una sobre simplificación. No puede resumirse en una ecuación como la que debajo de estas líneas un problema tan complejo como si vivimos en una simulación y menos usarla para sacar conclusiones usando una lógica bastante simple. Aunque eso no quiere decir que al final no este acertado….y seamos una IA.

La IA no aumenta la productividad

La IA promete aumentar la productividad de todos los trabajadores (al menos de todos los que trabajen delante de una pantalla). Sin embargo en la vida real no acabamos de ver esa promesa cumplida. ¿Por qué?

Para escribir este texto me baso en las experiencias que me ha ido contando la gente. Por supuesto tener estadísticas siempre da más sensación de profesionalidad. Así que os remito a este artículo. Resumiendo, un 96% de los jefes piensan que la IA puede mejorar la productividad de su negocio pero un 47% de los trabajadores no saben que hacer con la IA y el 77% creen que con la IA tardan más en hacer su trabajo.

Resumen en vídeo

¿Cómo es posible? Porque por mucho que nos quieran vender lo contrario, lo cierto es que: La IA (la tecnología en general) no aumenta la productividad.

¿Cómo que no? Si la IA puede hacer el mismo trabajo que una persona en menor tiempo la productividad aumenta es obvio…si pero y es un gran pero. No basta con dejarles una IA a tus trabajadores y esperar que la productividad aumente mágicamente.

Para entenderlo vamos a viajar al pasado. Finales de los 80 principios de los 90. Las empresas descubren que los ordenadores pueden aumentar la productividad de cualquier oficina usando una cosa llamada «ofimática» (que igual en esa época no tenía ese nombre). Muchos trabajadores lo pasaron mal cuando sus empresas empezaron a exigirles que usaran los ordenadores. Para ellos era una herramienta nueva y completamente desconocida. Tampoco es que muchos superiores supieran de que iba eso, simplemente «aumentaba la productividad».

Pero, no es tan sencillo como simplemente «usar ofimática», para que la ofimática de verdad aumente la productividad es necesario adaptar el flujo de trabajo a las nuevas tecnologías. Si no la ofimática se limita a: meter lo datos en el ordenador, imprimirlos y continuar el mismo proceso pero con un papel impreso. Es necesario que todos puedan leer / editar el fichero, que este se pueda compartir entre lo trabajadores de forma sencilla. Necesitas: ordenadores, software, Internet, email, un sitio donde compartir los ficheros, formar a los usuarios, …

Con la IA pasa lo mismo, no puedes simplemente «soltar una IA» en la oficina y decirle «ser productivos». Hay que integrar ese servicio con el flujo de trabajo. Hay que saber que funciones va a realizar la IA y cómo va real izarlas. Por desgracia las historias que me cuentan son en plan: «hemos contratado este servicio, usarlo». Parece que los propios que han contratado el servicio no tienen muy claro que hacer con la IA.