Menu iconMenu icon
Aprendizaje Profundo Generativo Edición Actualizada

Capítulo 8: Proyecto: Generación de Texto con Modelos Autoregresivos

8.4 Evaluación del Modelo

Evaluar el rendimiento de un modelo de generación de texto es crucial para asegurar que genere texto de alta calidad, coherente y contextualmente apropiado. En esta sección, discutiremos varios métodos para evaluar nuestro modelo GPT-2 ajustado, incluyendo tanto métricas cuantitativas como evaluaciones cualitativas. También proporcionaremos códigos de ejemplo para demostrar estas técnicas de evaluación.

8.4.1 Métricas de Evaluación Cuantitativa

Las métricas cuantitativas proporcionan medidas objetivas del rendimiento del modelo. Para la generación de texto, las métricas comunes incluyen Perplejidad, puntuación BLEU y puntuación ROUGE. Estas métricas ayudan a evaluar la fluidez, coherencia y relevancia del texto generado.

Perplejidad

La perplejidad mide qué tan bien una distribución de probabilidad o un modelo de probabilidad predice una muestra. Una perplejidad más baja indica un mejor rendimiento, ya que significa que el modelo asigna mayores probabilidades a los datos reales.

Ejemplo: Cálculo de la Perplejidad

import torch
from transformers import GPT2LMHeadModel, GPT2Tokenizer

# Load the pre-trained GPT-2 model and tokenizer
tokenizer = GPT2Tokenizer.from_pretrained("gpt2")
model = GPT2LMHeadModel.from_pretrained("gpt2")

# Define a function to calculate perplexity
def calculate_perplexity(text):
    input_ids = tokenizer.encode(text, return_tensors='pt')
    with torch.no_grad():
        outputs = model(input_ids, labels=input_ids)
        loss = outputs.loss
        perplexity = torch.exp(loss)
    return perplexity.item()

# Example text for perplexity calculation
text = "The quick brown fox jumps over the lazy dog."
perplexity = calculate_perplexity(text)
print(f"Perplexity: {perplexity}")

Primero, se cargan el modelo GPT-2 preentrenado y su correspondiente tokenizador. El tokenizador se utiliza para convertir el texto de entrada en un formato que el modelo pueda entender, mientras que el propio modelo se utiliza para generar predicciones.

A continuación, se define una función llamada calculate_perplexity, que toma un fragmento de texto como entrada. Dentro de esta función, el texto de entrada se tokeniza y se convierte en tensores de PyTorch utilizando el tokenizador cargado. Estos tensores se alimentan al modelo, que genera predicciones en forma de logits.

La función model se llama con los ids de entrada y las etiquetas (que en este caso también son los ids de entrada), y devuelve la pérdida del modelo. La pérdida es una medida de qué tan bien las predicciones del modelo coinciden con los resultados reales. En el contexto del modelado de lenguaje, una pérdida más baja significa que las probabilidades predichas por el modelo para la secuencia de palabras están más cerca de la secuencia real.

Luego, la pérdida se utiliza para calcular la perplejidad, que es una medida de incertidumbre. Se calcula tomando el exponencial de la pérdida. En el contexto de los modelos de lenguaje, una perplejidad más baja es mejor, ya que significa que el modelo está más seguro de sus predicciones.

Finalmente, se proporciona un texto de ejemplo ("The quick brown fox jumps over the lazy dog.") para demostrar cómo usar la función calculate_perplexity. Luego se imprime la perplejidad calculada. Esto permite a los usuarios ver qué tan bien el modelo predice el texto de ejemplo y da una idea del rendimiento general del modelo.

Puntuación BLEU

La puntuación BLEU (Bilingual Evaluation Understudy) evalúa la calidad del texto que ha sido traducido automáticamente de un idioma a otro. También se utiliza para evaluar modelos de generación de texto comparando el texto generado con textos de referencia.

Ejemplo: Cálculo de la Puntuación BLEU

from nltk.translate.bleu_score import sentence_bleu

# Reference and candidate texts
reference = "The quick brown fox jumps over the lazy dog."
candidate = "The quick brown fox jumps over the lazy dog."

# Calculate BLEU score
bleu_score = sentence_bleu([reference.split()], candidate.split())
print(f"BLEU Score: {bleu_score}")

En este ejemplo, la línea from nltk.translate.bleu_score import sentence_bleu importa la función requerida sentence_bleu de NLTK.

Luego, se definen dos oraciones: la oración 'referencia' y la oración 'candidata'. La oración de referencia es el texto que consideramos la versión correcta, mientras que la oración candidata es el texto generado por máquina que queremos evaluar. En este caso, las oraciones de referencia y candidata son idénticas.

La función sentence_bleu se llama con la oración de referencia y la oración candidata como sus argumentos. La oración de referencia se divide en palabras individuales usando el método split() porque el cálculo de la puntuación BLEU requiere que las oraciones estén tokenizadas (es decir, divididas en palabras individuales).

El resultado de la función, bleu_score, es la puntuación BLEU de la oración candidata en relación con la oración de referencia. La puntuación BLEU es un número entre 0 y 1: una puntuación de 1 significa que la oración candidata coincide perfectamente con la oración de referencia, mientras que una puntuación de 0 significa que no hay coincidencia en absoluto.

En este caso, dado que la oración de referencia y la oración candidata son idénticas, la puntuación BLEU debería ser 1, indicando una coincidencia perfecta.

Finalmente, la puntuación BLEU se imprime con una cadena formateada.

Puntuación ROUGE

ROUGE (Recall-Oriented Understudy for Gisting Evaluation) mide la superposición entre el texto generado y los textos de referencia, centrándose en el recall. Se usa comúnmente para tareas de resumen.

Ejemplo: Cálculo de la Puntuación ROUGE

from rouge_score import rouge_scorer

# Reference and candidate texts
reference = "The quick brown fox jumps over the lazy dog."
candidate = "The quick brown fox leaps over the lazy dog."

# Calculate ROUGE score
scorer = rouge_scorer.RougeScorer(['rouge1', 'rougeL'], use_stemmer=True)
scores = scorer.score(reference, candidate)
print(f"ROUGE-1 Score: {scores['rouge1'].fmeasure}")
print(f"ROUGE-L Score: {scores['rougeL'].fmeasure}")

El primer paso en el código es importar el rouge_scorer del módulo rouge_score. Este scorer es una herramienta para calcular las puntuaciones ROUGE.

A continuación, el código define dos oraciones: la oración 'referencia' y la oración 'candidata'. La oración de referencia es el texto que consideramos la versión correcta, mientras que la oración candidata es el texto generado por máquina que queremos evaluar. Aquí, la referencia es "The quick brown fox jumps over the lazy dog." y la candidata es "The quick brown fox leaps over the lazy dog."

Para calcular la puntuación ROUGE, el código crea una instancia de RougeScorer, que se inicializa con los tipos de puntuaciones ROUGE que queremos calcular. En este caso, se utilizan 'rouge1' y 'rougeL'. 'rouge1' se refiere a la superposición de unigrams (palabras individuales) entre los textos de referencia y candidatos. 'rougeL' utiliza las estadísticas basadas en la subsecuencia común más larga (LCS). LCS se refiere a la secuencia más larga de palabras que son iguales entre los textos de referencia y candidatos, en el mismo orden.

El argumento use_stemmer=True significa que el scorer aplicará stemming a las palabras antes de calcular las puntuaciones. El stemming es un proceso de reducción de palabras a su forma raíz, lo que puede ayudar a emparejar palabras similares.

La línea scorer.score(reference, candidate) es la que realmente calcula las puntuaciones ROUGE. La variable scores resultante es un diccionario que contiene las puntuaciones calculadas para 'rouge1' y 'rougeL'.

Las dos últimas líneas del código imprimen la medida F para 'rouge1' y 'rougeL'. La medida F, o puntuación F1, es la media armónica de la precisión y el recall, proporcionando un equilibrio entre estas dos medidas.

8.4.2 Evaluación Cualitativa

La evaluación cualitativa implica inspeccionar manualmente el texto generado para evaluar su fluidez, coherencia y relevancia. Este método es subjetivo pero proporciona información valiosa sobre el rendimiento del modelo.

Inspección Visual

La inspección visual implica generar un conjunto de textos y examinarlos en busca de corrección gramatical, coherencia y relevancia con respecto al prompt. Esto puede ayudar a identificar problemas evidentes como frases repetitivas, falta de coherencia o contenido inapropiado.

Ejemplo: Inspección Visual

# Define a prompt
prompt = "In the quiet village of Rivendell,"

# Generate text using the fine-tuned GPT-2 model
input_ids = tokenizer.encode(prompt, return_tensors='pt')
output = model.generate(input_ids, max_length=100, num_return_sequences=1, temperature=0.7)
generated_text = tokenizer.decode(output[0], skip_special_tokens=True)

# Print the generated text
print(generated_text)

Este ejemplo comienza con un prompt predefinido: "En el tranquilo pueblo de Rivendel,". El prompt se codifica en tokens adecuados para el modelo, y luego el modelo genera texto hasta una longitud máxima de 100 tokens basado en esta entrada. El texto generado se decodifica de nuevo en texto legible para humanos y se imprime.

Evaluación Humana

La evaluación humana implica pedir a un grupo de personas que califiquen los textos generados en base a criterios como coherencia, fluidez y relevancia. Este método proporciona una evaluación más robusta del rendimiento del modelo, pero puede ser lento y requerir muchos recursos.

Ejemplo: Criterios de Evaluación Humana

  • Coherencia: ¿El texto tiene sentido lógico y fluye naturalmente?
  • Fluidez: ¿El texto es gramaticalmente correcto y fácil de leer?
  • Relevancia: ¿El texto se mantiene en el tema y responde adecuadamente al prompt?

8.4.3 Evaluación de la Diversidad y Creatividad

Para evaluar la diversidad y creatividad del texto generado, podemos analizar la variación en las salidas dadas diferentes prompts o ligeras variaciones del mismo prompt. Esto ayuda a asegurar que el modelo no produzca textos repetitivos o excesivamente similares.

Ejemplo: Evaluación de la Diversidad

# Define a set of similar prompts
prompts = [
    "Once upon a time in a faraway land,",
    "Long ago in a distant kingdom,",
    "In a realm beyond the mountains,",
]

# Generate and print text for each prompt
for i, prompt in enumerate(prompts):
    input_ids = tokenizer.encode(prompt, return_tensors='pt')
    output = model.generate(input_ids, max_length=100, num_return_sequences=1, temperature=0.7)
    generated_text = tokenizer.decode(output[0], skip_special_tokens=True)
    print(f"Prompt {i+1}:\\n{generated_text}\\n")

Este código de ejemplo primero define una lista de prompts, cada uno siendo la oración inicial de una posible historia. Luego utiliza un tokenizador y un modelo preexistentes para generar e imprimir una historia para cada prompt.

La función tokenizer.encode se usa para convertir el prompt en un formato que el modelo pueda entender (es decir, un tensor de IDs enteros). La función model.generate se usa luego para generar una continuación del prompt hasta una longitud de 100 tokens. El parámetro temperature se usa para controlar la aleatoriedad de la salida (con valores más altos que conducen a una salida más aleatoria).

Finalmente, la función tokenizer.decode se usa para convertir la salida del modelo de nuevo en texto legible para humanos, y este texto se imprime en la consola.

8.4 Evaluación del Modelo

Evaluar el rendimiento de un modelo de generación de texto es crucial para asegurar que genere texto de alta calidad, coherente y contextualmente apropiado. En esta sección, discutiremos varios métodos para evaluar nuestro modelo GPT-2 ajustado, incluyendo tanto métricas cuantitativas como evaluaciones cualitativas. También proporcionaremos códigos de ejemplo para demostrar estas técnicas de evaluación.

8.4.1 Métricas de Evaluación Cuantitativa

Las métricas cuantitativas proporcionan medidas objetivas del rendimiento del modelo. Para la generación de texto, las métricas comunes incluyen Perplejidad, puntuación BLEU y puntuación ROUGE. Estas métricas ayudan a evaluar la fluidez, coherencia y relevancia del texto generado.

Perplejidad

La perplejidad mide qué tan bien una distribución de probabilidad o un modelo de probabilidad predice una muestra. Una perplejidad más baja indica un mejor rendimiento, ya que significa que el modelo asigna mayores probabilidades a los datos reales.

Ejemplo: Cálculo de la Perplejidad

import torch
from transformers import GPT2LMHeadModel, GPT2Tokenizer

# Load the pre-trained GPT-2 model and tokenizer
tokenizer = GPT2Tokenizer.from_pretrained("gpt2")
model = GPT2LMHeadModel.from_pretrained("gpt2")

# Define a function to calculate perplexity
def calculate_perplexity(text):
    input_ids = tokenizer.encode(text, return_tensors='pt')
    with torch.no_grad():
        outputs = model(input_ids, labels=input_ids)
        loss = outputs.loss
        perplexity = torch.exp(loss)
    return perplexity.item()

# Example text for perplexity calculation
text = "The quick brown fox jumps over the lazy dog."
perplexity = calculate_perplexity(text)
print(f"Perplexity: {perplexity}")

Primero, se cargan el modelo GPT-2 preentrenado y su correspondiente tokenizador. El tokenizador se utiliza para convertir el texto de entrada en un formato que el modelo pueda entender, mientras que el propio modelo se utiliza para generar predicciones.

A continuación, se define una función llamada calculate_perplexity, que toma un fragmento de texto como entrada. Dentro de esta función, el texto de entrada se tokeniza y se convierte en tensores de PyTorch utilizando el tokenizador cargado. Estos tensores se alimentan al modelo, que genera predicciones en forma de logits.

La función model se llama con los ids de entrada y las etiquetas (que en este caso también son los ids de entrada), y devuelve la pérdida del modelo. La pérdida es una medida de qué tan bien las predicciones del modelo coinciden con los resultados reales. En el contexto del modelado de lenguaje, una pérdida más baja significa que las probabilidades predichas por el modelo para la secuencia de palabras están más cerca de la secuencia real.

Luego, la pérdida se utiliza para calcular la perplejidad, que es una medida de incertidumbre. Se calcula tomando el exponencial de la pérdida. En el contexto de los modelos de lenguaje, una perplejidad más baja es mejor, ya que significa que el modelo está más seguro de sus predicciones.

Finalmente, se proporciona un texto de ejemplo ("The quick brown fox jumps over the lazy dog.") para demostrar cómo usar la función calculate_perplexity. Luego se imprime la perplejidad calculada. Esto permite a los usuarios ver qué tan bien el modelo predice el texto de ejemplo y da una idea del rendimiento general del modelo.

Puntuación BLEU

La puntuación BLEU (Bilingual Evaluation Understudy) evalúa la calidad del texto que ha sido traducido automáticamente de un idioma a otro. También se utiliza para evaluar modelos de generación de texto comparando el texto generado con textos de referencia.

Ejemplo: Cálculo de la Puntuación BLEU

from nltk.translate.bleu_score import sentence_bleu

# Reference and candidate texts
reference = "The quick brown fox jumps over the lazy dog."
candidate = "The quick brown fox jumps over the lazy dog."

# Calculate BLEU score
bleu_score = sentence_bleu([reference.split()], candidate.split())
print(f"BLEU Score: {bleu_score}")

En este ejemplo, la línea from nltk.translate.bleu_score import sentence_bleu importa la función requerida sentence_bleu de NLTK.

Luego, se definen dos oraciones: la oración 'referencia' y la oración 'candidata'. La oración de referencia es el texto que consideramos la versión correcta, mientras que la oración candidata es el texto generado por máquina que queremos evaluar. En este caso, las oraciones de referencia y candidata son idénticas.

La función sentence_bleu se llama con la oración de referencia y la oración candidata como sus argumentos. La oración de referencia se divide en palabras individuales usando el método split() porque el cálculo de la puntuación BLEU requiere que las oraciones estén tokenizadas (es decir, divididas en palabras individuales).

El resultado de la función, bleu_score, es la puntuación BLEU de la oración candidata en relación con la oración de referencia. La puntuación BLEU es un número entre 0 y 1: una puntuación de 1 significa que la oración candidata coincide perfectamente con la oración de referencia, mientras que una puntuación de 0 significa que no hay coincidencia en absoluto.

En este caso, dado que la oración de referencia y la oración candidata son idénticas, la puntuación BLEU debería ser 1, indicando una coincidencia perfecta.

Finalmente, la puntuación BLEU se imprime con una cadena formateada.

Puntuación ROUGE

ROUGE (Recall-Oriented Understudy for Gisting Evaluation) mide la superposición entre el texto generado y los textos de referencia, centrándose en el recall. Se usa comúnmente para tareas de resumen.

Ejemplo: Cálculo de la Puntuación ROUGE

from rouge_score import rouge_scorer

# Reference and candidate texts
reference = "The quick brown fox jumps over the lazy dog."
candidate = "The quick brown fox leaps over the lazy dog."

# Calculate ROUGE score
scorer = rouge_scorer.RougeScorer(['rouge1', 'rougeL'], use_stemmer=True)
scores = scorer.score(reference, candidate)
print(f"ROUGE-1 Score: {scores['rouge1'].fmeasure}")
print(f"ROUGE-L Score: {scores['rougeL'].fmeasure}")

El primer paso en el código es importar el rouge_scorer del módulo rouge_score. Este scorer es una herramienta para calcular las puntuaciones ROUGE.

A continuación, el código define dos oraciones: la oración 'referencia' y la oración 'candidata'. La oración de referencia es el texto que consideramos la versión correcta, mientras que la oración candidata es el texto generado por máquina que queremos evaluar. Aquí, la referencia es "The quick brown fox jumps over the lazy dog." y la candidata es "The quick brown fox leaps over the lazy dog."

Para calcular la puntuación ROUGE, el código crea una instancia de RougeScorer, que se inicializa con los tipos de puntuaciones ROUGE que queremos calcular. En este caso, se utilizan 'rouge1' y 'rougeL'. 'rouge1' se refiere a la superposición de unigrams (palabras individuales) entre los textos de referencia y candidatos. 'rougeL' utiliza las estadísticas basadas en la subsecuencia común más larga (LCS). LCS se refiere a la secuencia más larga de palabras que son iguales entre los textos de referencia y candidatos, en el mismo orden.

El argumento use_stemmer=True significa que el scorer aplicará stemming a las palabras antes de calcular las puntuaciones. El stemming es un proceso de reducción de palabras a su forma raíz, lo que puede ayudar a emparejar palabras similares.

La línea scorer.score(reference, candidate) es la que realmente calcula las puntuaciones ROUGE. La variable scores resultante es un diccionario que contiene las puntuaciones calculadas para 'rouge1' y 'rougeL'.

Las dos últimas líneas del código imprimen la medida F para 'rouge1' y 'rougeL'. La medida F, o puntuación F1, es la media armónica de la precisión y el recall, proporcionando un equilibrio entre estas dos medidas.

8.4.2 Evaluación Cualitativa

La evaluación cualitativa implica inspeccionar manualmente el texto generado para evaluar su fluidez, coherencia y relevancia. Este método es subjetivo pero proporciona información valiosa sobre el rendimiento del modelo.

Inspección Visual

La inspección visual implica generar un conjunto de textos y examinarlos en busca de corrección gramatical, coherencia y relevancia con respecto al prompt. Esto puede ayudar a identificar problemas evidentes como frases repetitivas, falta de coherencia o contenido inapropiado.

Ejemplo: Inspección Visual

# Define a prompt
prompt = "In the quiet village of Rivendell,"

# Generate text using the fine-tuned GPT-2 model
input_ids = tokenizer.encode(prompt, return_tensors='pt')
output = model.generate(input_ids, max_length=100, num_return_sequences=1, temperature=0.7)
generated_text = tokenizer.decode(output[0], skip_special_tokens=True)

# Print the generated text
print(generated_text)

Este ejemplo comienza con un prompt predefinido: "En el tranquilo pueblo de Rivendel,". El prompt se codifica en tokens adecuados para el modelo, y luego el modelo genera texto hasta una longitud máxima de 100 tokens basado en esta entrada. El texto generado se decodifica de nuevo en texto legible para humanos y se imprime.

Evaluación Humana

La evaluación humana implica pedir a un grupo de personas que califiquen los textos generados en base a criterios como coherencia, fluidez y relevancia. Este método proporciona una evaluación más robusta del rendimiento del modelo, pero puede ser lento y requerir muchos recursos.

Ejemplo: Criterios de Evaluación Humana

  • Coherencia: ¿El texto tiene sentido lógico y fluye naturalmente?
  • Fluidez: ¿El texto es gramaticalmente correcto y fácil de leer?
  • Relevancia: ¿El texto se mantiene en el tema y responde adecuadamente al prompt?

8.4.3 Evaluación de la Diversidad y Creatividad

Para evaluar la diversidad y creatividad del texto generado, podemos analizar la variación en las salidas dadas diferentes prompts o ligeras variaciones del mismo prompt. Esto ayuda a asegurar que el modelo no produzca textos repetitivos o excesivamente similares.

Ejemplo: Evaluación de la Diversidad

# Define a set of similar prompts
prompts = [
    "Once upon a time in a faraway land,",
    "Long ago in a distant kingdom,",
    "In a realm beyond the mountains,",
]

# Generate and print text for each prompt
for i, prompt in enumerate(prompts):
    input_ids = tokenizer.encode(prompt, return_tensors='pt')
    output = model.generate(input_ids, max_length=100, num_return_sequences=1, temperature=0.7)
    generated_text = tokenizer.decode(output[0], skip_special_tokens=True)
    print(f"Prompt {i+1}:\\n{generated_text}\\n")

Este código de ejemplo primero define una lista de prompts, cada uno siendo la oración inicial de una posible historia. Luego utiliza un tokenizador y un modelo preexistentes para generar e imprimir una historia para cada prompt.

La función tokenizer.encode se usa para convertir el prompt en un formato que el modelo pueda entender (es decir, un tensor de IDs enteros). La función model.generate se usa luego para generar una continuación del prompt hasta una longitud de 100 tokens. El parámetro temperature se usa para controlar la aleatoriedad de la salida (con valores más altos que conducen a una salida más aleatoria).

Finalmente, la función tokenizer.decode se usa para convertir la salida del modelo de nuevo en texto legible para humanos, y este texto se imprime en la consola.

8.4 Evaluación del Modelo

Evaluar el rendimiento de un modelo de generación de texto es crucial para asegurar que genere texto de alta calidad, coherente y contextualmente apropiado. En esta sección, discutiremos varios métodos para evaluar nuestro modelo GPT-2 ajustado, incluyendo tanto métricas cuantitativas como evaluaciones cualitativas. También proporcionaremos códigos de ejemplo para demostrar estas técnicas de evaluación.

8.4.1 Métricas de Evaluación Cuantitativa

Las métricas cuantitativas proporcionan medidas objetivas del rendimiento del modelo. Para la generación de texto, las métricas comunes incluyen Perplejidad, puntuación BLEU y puntuación ROUGE. Estas métricas ayudan a evaluar la fluidez, coherencia y relevancia del texto generado.

Perplejidad

La perplejidad mide qué tan bien una distribución de probabilidad o un modelo de probabilidad predice una muestra. Una perplejidad más baja indica un mejor rendimiento, ya que significa que el modelo asigna mayores probabilidades a los datos reales.

Ejemplo: Cálculo de la Perplejidad

import torch
from transformers import GPT2LMHeadModel, GPT2Tokenizer

# Load the pre-trained GPT-2 model and tokenizer
tokenizer = GPT2Tokenizer.from_pretrained("gpt2")
model = GPT2LMHeadModel.from_pretrained("gpt2")

# Define a function to calculate perplexity
def calculate_perplexity(text):
    input_ids = tokenizer.encode(text, return_tensors='pt')
    with torch.no_grad():
        outputs = model(input_ids, labels=input_ids)
        loss = outputs.loss
        perplexity = torch.exp(loss)
    return perplexity.item()

# Example text for perplexity calculation
text = "The quick brown fox jumps over the lazy dog."
perplexity = calculate_perplexity(text)
print(f"Perplexity: {perplexity}")

Primero, se cargan el modelo GPT-2 preentrenado y su correspondiente tokenizador. El tokenizador se utiliza para convertir el texto de entrada en un formato que el modelo pueda entender, mientras que el propio modelo se utiliza para generar predicciones.

A continuación, se define una función llamada calculate_perplexity, que toma un fragmento de texto como entrada. Dentro de esta función, el texto de entrada se tokeniza y se convierte en tensores de PyTorch utilizando el tokenizador cargado. Estos tensores se alimentan al modelo, que genera predicciones en forma de logits.

La función model se llama con los ids de entrada y las etiquetas (que en este caso también son los ids de entrada), y devuelve la pérdida del modelo. La pérdida es una medida de qué tan bien las predicciones del modelo coinciden con los resultados reales. En el contexto del modelado de lenguaje, una pérdida más baja significa que las probabilidades predichas por el modelo para la secuencia de palabras están más cerca de la secuencia real.

Luego, la pérdida se utiliza para calcular la perplejidad, que es una medida de incertidumbre. Se calcula tomando el exponencial de la pérdida. En el contexto de los modelos de lenguaje, una perplejidad más baja es mejor, ya que significa que el modelo está más seguro de sus predicciones.

Finalmente, se proporciona un texto de ejemplo ("The quick brown fox jumps over the lazy dog.") para demostrar cómo usar la función calculate_perplexity. Luego se imprime la perplejidad calculada. Esto permite a los usuarios ver qué tan bien el modelo predice el texto de ejemplo y da una idea del rendimiento general del modelo.

Puntuación BLEU

La puntuación BLEU (Bilingual Evaluation Understudy) evalúa la calidad del texto que ha sido traducido automáticamente de un idioma a otro. También se utiliza para evaluar modelos de generación de texto comparando el texto generado con textos de referencia.

Ejemplo: Cálculo de la Puntuación BLEU

from nltk.translate.bleu_score import sentence_bleu

# Reference and candidate texts
reference = "The quick brown fox jumps over the lazy dog."
candidate = "The quick brown fox jumps over the lazy dog."

# Calculate BLEU score
bleu_score = sentence_bleu([reference.split()], candidate.split())
print(f"BLEU Score: {bleu_score}")

En este ejemplo, la línea from nltk.translate.bleu_score import sentence_bleu importa la función requerida sentence_bleu de NLTK.

Luego, se definen dos oraciones: la oración 'referencia' y la oración 'candidata'. La oración de referencia es el texto que consideramos la versión correcta, mientras que la oración candidata es el texto generado por máquina que queremos evaluar. En este caso, las oraciones de referencia y candidata son idénticas.

La función sentence_bleu se llama con la oración de referencia y la oración candidata como sus argumentos. La oración de referencia se divide en palabras individuales usando el método split() porque el cálculo de la puntuación BLEU requiere que las oraciones estén tokenizadas (es decir, divididas en palabras individuales).

El resultado de la función, bleu_score, es la puntuación BLEU de la oración candidata en relación con la oración de referencia. La puntuación BLEU es un número entre 0 y 1: una puntuación de 1 significa que la oración candidata coincide perfectamente con la oración de referencia, mientras que una puntuación de 0 significa que no hay coincidencia en absoluto.

En este caso, dado que la oración de referencia y la oración candidata son idénticas, la puntuación BLEU debería ser 1, indicando una coincidencia perfecta.

Finalmente, la puntuación BLEU se imprime con una cadena formateada.

Puntuación ROUGE

ROUGE (Recall-Oriented Understudy for Gisting Evaluation) mide la superposición entre el texto generado y los textos de referencia, centrándose en el recall. Se usa comúnmente para tareas de resumen.

Ejemplo: Cálculo de la Puntuación ROUGE

from rouge_score import rouge_scorer

# Reference and candidate texts
reference = "The quick brown fox jumps over the lazy dog."
candidate = "The quick brown fox leaps over the lazy dog."

# Calculate ROUGE score
scorer = rouge_scorer.RougeScorer(['rouge1', 'rougeL'], use_stemmer=True)
scores = scorer.score(reference, candidate)
print(f"ROUGE-1 Score: {scores['rouge1'].fmeasure}")
print(f"ROUGE-L Score: {scores['rougeL'].fmeasure}")

El primer paso en el código es importar el rouge_scorer del módulo rouge_score. Este scorer es una herramienta para calcular las puntuaciones ROUGE.

A continuación, el código define dos oraciones: la oración 'referencia' y la oración 'candidata'. La oración de referencia es el texto que consideramos la versión correcta, mientras que la oración candidata es el texto generado por máquina que queremos evaluar. Aquí, la referencia es "The quick brown fox jumps over the lazy dog." y la candidata es "The quick brown fox leaps over the lazy dog."

Para calcular la puntuación ROUGE, el código crea una instancia de RougeScorer, que se inicializa con los tipos de puntuaciones ROUGE que queremos calcular. En este caso, se utilizan 'rouge1' y 'rougeL'. 'rouge1' se refiere a la superposición de unigrams (palabras individuales) entre los textos de referencia y candidatos. 'rougeL' utiliza las estadísticas basadas en la subsecuencia común más larga (LCS). LCS se refiere a la secuencia más larga de palabras que son iguales entre los textos de referencia y candidatos, en el mismo orden.

El argumento use_stemmer=True significa que el scorer aplicará stemming a las palabras antes de calcular las puntuaciones. El stemming es un proceso de reducción de palabras a su forma raíz, lo que puede ayudar a emparejar palabras similares.

La línea scorer.score(reference, candidate) es la que realmente calcula las puntuaciones ROUGE. La variable scores resultante es un diccionario que contiene las puntuaciones calculadas para 'rouge1' y 'rougeL'.

Las dos últimas líneas del código imprimen la medida F para 'rouge1' y 'rougeL'. La medida F, o puntuación F1, es la media armónica de la precisión y el recall, proporcionando un equilibrio entre estas dos medidas.

8.4.2 Evaluación Cualitativa

La evaluación cualitativa implica inspeccionar manualmente el texto generado para evaluar su fluidez, coherencia y relevancia. Este método es subjetivo pero proporciona información valiosa sobre el rendimiento del modelo.

Inspección Visual

La inspección visual implica generar un conjunto de textos y examinarlos en busca de corrección gramatical, coherencia y relevancia con respecto al prompt. Esto puede ayudar a identificar problemas evidentes como frases repetitivas, falta de coherencia o contenido inapropiado.

Ejemplo: Inspección Visual

# Define a prompt
prompt = "In the quiet village of Rivendell,"

# Generate text using the fine-tuned GPT-2 model
input_ids = tokenizer.encode(prompt, return_tensors='pt')
output = model.generate(input_ids, max_length=100, num_return_sequences=1, temperature=0.7)
generated_text = tokenizer.decode(output[0], skip_special_tokens=True)

# Print the generated text
print(generated_text)

Este ejemplo comienza con un prompt predefinido: "En el tranquilo pueblo de Rivendel,". El prompt se codifica en tokens adecuados para el modelo, y luego el modelo genera texto hasta una longitud máxima de 100 tokens basado en esta entrada. El texto generado se decodifica de nuevo en texto legible para humanos y se imprime.

Evaluación Humana

La evaluación humana implica pedir a un grupo de personas que califiquen los textos generados en base a criterios como coherencia, fluidez y relevancia. Este método proporciona una evaluación más robusta del rendimiento del modelo, pero puede ser lento y requerir muchos recursos.

Ejemplo: Criterios de Evaluación Humana

  • Coherencia: ¿El texto tiene sentido lógico y fluye naturalmente?
  • Fluidez: ¿El texto es gramaticalmente correcto y fácil de leer?
  • Relevancia: ¿El texto se mantiene en el tema y responde adecuadamente al prompt?

8.4.3 Evaluación de la Diversidad y Creatividad

Para evaluar la diversidad y creatividad del texto generado, podemos analizar la variación en las salidas dadas diferentes prompts o ligeras variaciones del mismo prompt. Esto ayuda a asegurar que el modelo no produzca textos repetitivos o excesivamente similares.

Ejemplo: Evaluación de la Diversidad

# Define a set of similar prompts
prompts = [
    "Once upon a time in a faraway land,",
    "Long ago in a distant kingdom,",
    "In a realm beyond the mountains,",
]

# Generate and print text for each prompt
for i, prompt in enumerate(prompts):
    input_ids = tokenizer.encode(prompt, return_tensors='pt')
    output = model.generate(input_ids, max_length=100, num_return_sequences=1, temperature=0.7)
    generated_text = tokenizer.decode(output[0], skip_special_tokens=True)
    print(f"Prompt {i+1}:\\n{generated_text}\\n")

Este código de ejemplo primero define una lista de prompts, cada uno siendo la oración inicial de una posible historia. Luego utiliza un tokenizador y un modelo preexistentes para generar e imprimir una historia para cada prompt.

La función tokenizer.encode se usa para convertir el prompt en un formato que el modelo pueda entender (es decir, un tensor de IDs enteros). La función model.generate se usa luego para generar una continuación del prompt hasta una longitud de 100 tokens. El parámetro temperature se usa para controlar la aleatoriedad de la salida (con valores más altos que conducen a una salida más aleatoria).

Finalmente, la función tokenizer.decode se usa para convertir la salida del modelo de nuevo en texto legible para humanos, y este texto se imprime en la consola.

8.4 Evaluación del Modelo

Evaluar el rendimiento de un modelo de generación de texto es crucial para asegurar que genere texto de alta calidad, coherente y contextualmente apropiado. En esta sección, discutiremos varios métodos para evaluar nuestro modelo GPT-2 ajustado, incluyendo tanto métricas cuantitativas como evaluaciones cualitativas. También proporcionaremos códigos de ejemplo para demostrar estas técnicas de evaluación.

8.4.1 Métricas de Evaluación Cuantitativa

Las métricas cuantitativas proporcionan medidas objetivas del rendimiento del modelo. Para la generación de texto, las métricas comunes incluyen Perplejidad, puntuación BLEU y puntuación ROUGE. Estas métricas ayudan a evaluar la fluidez, coherencia y relevancia del texto generado.

Perplejidad

La perplejidad mide qué tan bien una distribución de probabilidad o un modelo de probabilidad predice una muestra. Una perplejidad más baja indica un mejor rendimiento, ya que significa que el modelo asigna mayores probabilidades a los datos reales.

Ejemplo: Cálculo de la Perplejidad

import torch
from transformers import GPT2LMHeadModel, GPT2Tokenizer

# Load the pre-trained GPT-2 model and tokenizer
tokenizer = GPT2Tokenizer.from_pretrained("gpt2")
model = GPT2LMHeadModel.from_pretrained("gpt2")

# Define a function to calculate perplexity
def calculate_perplexity(text):
    input_ids = tokenizer.encode(text, return_tensors='pt')
    with torch.no_grad():
        outputs = model(input_ids, labels=input_ids)
        loss = outputs.loss
        perplexity = torch.exp(loss)
    return perplexity.item()

# Example text for perplexity calculation
text = "The quick brown fox jumps over the lazy dog."
perplexity = calculate_perplexity(text)
print(f"Perplexity: {perplexity}")

Primero, se cargan el modelo GPT-2 preentrenado y su correspondiente tokenizador. El tokenizador se utiliza para convertir el texto de entrada en un formato que el modelo pueda entender, mientras que el propio modelo se utiliza para generar predicciones.

A continuación, se define una función llamada calculate_perplexity, que toma un fragmento de texto como entrada. Dentro de esta función, el texto de entrada se tokeniza y se convierte en tensores de PyTorch utilizando el tokenizador cargado. Estos tensores se alimentan al modelo, que genera predicciones en forma de logits.

La función model se llama con los ids de entrada y las etiquetas (que en este caso también son los ids de entrada), y devuelve la pérdida del modelo. La pérdida es una medida de qué tan bien las predicciones del modelo coinciden con los resultados reales. En el contexto del modelado de lenguaje, una pérdida más baja significa que las probabilidades predichas por el modelo para la secuencia de palabras están más cerca de la secuencia real.

Luego, la pérdida se utiliza para calcular la perplejidad, que es una medida de incertidumbre. Se calcula tomando el exponencial de la pérdida. En el contexto de los modelos de lenguaje, una perplejidad más baja es mejor, ya que significa que el modelo está más seguro de sus predicciones.

Finalmente, se proporciona un texto de ejemplo ("The quick brown fox jumps over the lazy dog.") para demostrar cómo usar la función calculate_perplexity. Luego se imprime la perplejidad calculada. Esto permite a los usuarios ver qué tan bien el modelo predice el texto de ejemplo y da una idea del rendimiento general del modelo.

Puntuación BLEU

La puntuación BLEU (Bilingual Evaluation Understudy) evalúa la calidad del texto que ha sido traducido automáticamente de un idioma a otro. También se utiliza para evaluar modelos de generación de texto comparando el texto generado con textos de referencia.

Ejemplo: Cálculo de la Puntuación BLEU

from nltk.translate.bleu_score import sentence_bleu

# Reference and candidate texts
reference = "The quick brown fox jumps over the lazy dog."
candidate = "The quick brown fox jumps over the lazy dog."

# Calculate BLEU score
bleu_score = sentence_bleu([reference.split()], candidate.split())
print(f"BLEU Score: {bleu_score}")

En este ejemplo, la línea from nltk.translate.bleu_score import sentence_bleu importa la función requerida sentence_bleu de NLTK.

Luego, se definen dos oraciones: la oración 'referencia' y la oración 'candidata'. La oración de referencia es el texto que consideramos la versión correcta, mientras que la oración candidata es el texto generado por máquina que queremos evaluar. En este caso, las oraciones de referencia y candidata son idénticas.

La función sentence_bleu se llama con la oración de referencia y la oración candidata como sus argumentos. La oración de referencia se divide en palabras individuales usando el método split() porque el cálculo de la puntuación BLEU requiere que las oraciones estén tokenizadas (es decir, divididas en palabras individuales).

El resultado de la función, bleu_score, es la puntuación BLEU de la oración candidata en relación con la oración de referencia. La puntuación BLEU es un número entre 0 y 1: una puntuación de 1 significa que la oración candidata coincide perfectamente con la oración de referencia, mientras que una puntuación de 0 significa que no hay coincidencia en absoluto.

En este caso, dado que la oración de referencia y la oración candidata son idénticas, la puntuación BLEU debería ser 1, indicando una coincidencia perfecta.

Finalmente, la puntuación BLEU se imprime con una cadena formateada.

Puntuación ROUGE

ROUGE (Recall-Oriented Understudy for Gisting Evaluation) mide la superposición entre el texto generado y los textos de referencia, centrándose en el recall. Se usa comúnmente para tareas de resumen.

Ejemplo: Cálculo de la Puntuación ROUGE

from rouge_score import rouge_scorer

# Reference and candidate texts
reference = "The quick brown fox jumps over the lazy dog."
candidate = "The quick brown fox leaps over the lazy dog."

# Calculate ROUGE score
scorer = rouge_scorer.RougeScorer(['rouge1', 'rougeL'], use_stemmer=True)
scores = scorer.score(reference, candidate)
print(f"ROUGE-1 Score: {scores['rouge1'].fmeasure}")
print(f"ROUGE-L Score: {scores['rougeL'].fmeasure}")

El primer paso en el código es importar el rouge_scorer del módulo rouge_score. Este scorer es una herramienta para calcular las puntuaciones ROUGE.

A continuación, el código define dos oraciones: la oración 'referencia' y la oración 'candidata'. La oración de referencia es el texto que consideramos la versión correcta, mientras que la oración candidata es el texto generado por máquina que queremos evaluar. Aquí, la referencia es "The quick brown fox jumps over the lazy dog." y la candidata es "The quick brown fox leaps over the lazy dog."

Para calcular la puntuación ROUGE, el código crea una instancia de RougeScorer, que se inicializa con los tipos de puntuaciones ROUGE que queremos calcular. En este caso, se utilizan 'rouge1' y 'rougeL'. 'rouge1' se refiere a la superposición de unigrams (palabras individuales) entre los textos de referencia y candidatos. 'rougeL' utiliza las estadísticas basadas en la subsecuencia común más larga (LCS). LCS se refiere a la secuencia más larga de palabras que son iguales entre los textos de referencia y candidatos, en el mismo orden.

El argumento use_stemmer=True significa que el scorer aplicará stemming a las palabras antes de calcular las puntuaciones. El stemming es un proceso de reducción de palabras a su forma raíz, lo que puede ayudar a emparejar palabras similares.

La línea scorer.score(reference, candidate) es la que realmente calcula las puntuaciones ROUGE. La variable scores resultante es un diccionario que contiene las puntuaciones calculadas para 'rouge1' y 'rougeL'.

Las dos últimas líneas del código imprimen la medida F para 'rouge1' y 'rougeL'. La medida F, o puntuación F1, es la media armónica de la precisión y el recall, proporcionando un equilibrio entre estas dos medidas.

8.4.2 Evaluación Cualitativa

La evaluación cualitativa implica inspeccionar manualmente el texto generado para evaluar su fluidez, coherencia y relevancia. Este método es subjetivo pero proporciona información valiosa sobre el rendimiento del modelo.

Inspección Visual

La inspección visual implica generar un conjunto de textos y examinarlos en busca de corrección gramatical, coherencia y relevancia con respecto al prompt. Esto puede ayudar a identificar problemas evidentes como frases repetitivas, falta de coherencia o contenido inapropiado.

Ejemplo: Inspección Visual

# Define a prompt
prompt = "In the quiet village of Rivendell,"

# Generate text using the fine-tuned GPT-2 model
input_ids = tokenizer.encode(prompt, return_tensors='pt')
output = model.generate(input_ids, max_length=100, num_return_sequences=1, temperature=0.7)
generated_text = tokenizer.decode(output[0], skip_special_tokens=True)

# Print the generated text
print(generated_text)

Este ejemplo comienza con un prompt predefinido: "En el tranquilo pueblo de Rivendel,". El prompt se codifica en tokens adecuados para el modelo, y luego el modelo genera texto hasta una longitud máxima de 100 tokens basado en esta entrada. El texto generado se decodifica de nuevo en texto legible para humanos y se imprime.

Evaluación Humana

La evaluación humana implica pedir a un grupo de personas que califiquen los textos generados en base a criterios como coherencia, fluidez y relevancia. Este método proporciona una evaluación más robusta del rendimiento del modelo, pero puede ser lento y requerir muchos recursos.

Ejemplo: Criterios de Evaluación Humana

  • Coherencia: ¿El texto tiene sentido lógico y fluye naturalmente?
  • Fluidez: ¿El texto es gramaticalmente correcto y fácil de leer?
  • Relevancia: ¿El texto se mantiene en el tema y responde adecuadamente al prompt?

8.4.3 Evaluación de la Diversidad y Creatividad

Para evaluar la diversidad y creatividad del texto generado, podemos analizar la variación en las salidas dadas diferentes prompts o ligeras variaciones del mismo prompt. Esto ayuda a asegurar que el modelo no produzca textos repetitivos o excesivamente similares.

Ejemplo: Evaluación de la Diversidad

# Define a set of similar prompts
prompts = [
    "Once upon a time in a faraway land,",
    "Long ago in a distant kingdom,",
    "In a realm beyond the mountains,",
]

# Generate and print text for each prompt
for i, prompt in enumerate(prompts):
    input_ids = tokenizer.encode(prompt, return_tensors='pt')
    output = model.generate(input_ids, max_length=100, num_return_sequences=1, temperature=0.7)
    generated_text = tokenizer.decode(output[0], skip_special_tokens=True)
    print(f"Prompt {i+1}:\\n{generated_text}\\n")

Este código de ejemplo primero define una lista de prompts, cada uno siendo la oración inicial de una posible historia. Luego utiliza un tokenizador y un modelo preexistentes para generar e imprimir una historia para cada prompt.

La función tokenizer.encode se usa para convertir el prompt en un formato que el modelo pueda entender (es decir, un tensor de IDs enteros). La función model.generate se usa luego para generar una continuación del prompt hasta una longitud de 100 tokens. El parámetro temperature se usa para controlar la aleatoriedad de la salida (con valores más altos que conducen a una salida más aleatoria).

Finalmente, la función tokenizer.decode se usa para convertir la salida del modelo de nuevo en texto legible para humanos, y este texto se imprime en la consola.