Вопрос или проблема
Я пытаюсь дообучить Llama-3-8B для задачи регрессии с использованием PEFT, чтобы модель выдавала число с плавающей запятой для “оценки” входных данных. Я попытался адаптировать модель, изменив количество выходных логитов на 1 и изменив функцию потерь на среднеквадратическую ошибку. Я отформатировал свои данные, предоставив инструкцию вместе с входным запросом, токенизировал их и сохранил значение с плавающей запятой в “labels”. Я получаю ошибку:
RuntimeError: The size of tensor a (8) must match the size of tensor b (512) at non-singleton dimension 1
где моя MAX_SEQ_LEN при токенизации входных инструкций и запросов установлена на максимальную длину 512, но как-то это совпадает с моим выходным значением с плавающей запятой? Все ресурсы в интернете для дообучения Llama 3 предназначены для текстовых ответов, а не для задач регрессии, поэтому я не уверен, как это сделать. Ниже приведён мой код:
from datasets import load_dataset, load_metric
from transformers import AutoTokenizer, Trainer, TrainingArguments, EarlyStoppingCallback, AutoModelForSequenceClassification, BitsAndBytesConfig
from peft import LoraConfig, get_peft_model
from trl import SFTTrainer
import numpy as np
import json
from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score
import torch
quant_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_compute_dtype=torch.float16,
bnb_4bit_quant_type="nf4"
)
MAX_SEQ_LEN = 512
device = "cuda" if torch.cuda.is_available() else "cpu"
dataset = load_dataset("json", data_files="datasets/aNLI/train_rationale_cleaned.jsonl", cache_dir="/data/etey916")["train"]
#dataset = load_dataset("json", data_files="datasets/aNLI/train_rationale_output.jsonl", cache_dir="/data/etey916")
model_name = "meta-llama/Meta-Llama-3-8B"
model = AutoModelForSequenceClassification.from_pretrained(model_name, quantization_config=quant_config, problem_type="regression", num_labels=1)
model.config.pad_token_id = model.config.eos_token_id
tokenizer = AutoTokenizer.from_pretrained(model_name)
tokenizer.pad_token = tokenizer.eos_token
def format_dataset(sample):
input_text = sample['prompt'].replace('_', sample['rationale'])
instruction = ("<|begin_of_text|><|start_header_id|>user<|end_header_id|>\n\n"
"Приведите заявление, состоящее из начального контекста, гипотезы, вывода и результата, определите, насколько это правдоподобно, присвоив непрерывный балл от -1 до 1, где -1 означает чрезвычайно неправдоподобно, а 1 означает чрезвычайно правдоподобно.\n"
f"{input_text}<|eot_id|>")
output = float(sample['label'])
tokenized_inputs = tokenizer(instruction, truncation=True, padding="max_length", max_length=MAX_SEQ_LEN)
return {**tokenized_inputs, "labels": output}
def compute_metrics_for_regression(eval_pred):
logits, labels = eval_pred
labels = labels.reshape(-1, 1)
mse = mean_squared_error(labels_logits)
mae = mean_absolute_error(labels, logis)
r2 = r2_score(labels, logits)
sse = ((logits - labels).flatten()**2).tolist()
accuracy = sum([1 for e in sse if e < 0.25]) / len(sse)
return {"mse":mse, "mae":mae, "r2":r2, "accuracy":accuracy}
dataset = dataset.map(
format_dataset,
remove_columns=dataset.column_names
)
lora_config = LoraConfig(
r=8,
lora_alpha=16,
lora_dropout=0.1,
target_modules="all-linear",
bias = "none",
task_type="CAUSAL_LM",
)
peft_model = get_peft_model(model, lora_config)
training_args = TrainingArguments(
output_dir = "./results",
eval_strategy="epoch",
save_strategy="epoch",
learning_rate=5e-5,
per_device_train_batch_size=8,
per_device_eval_batch_size=8,
num_train_epochs=10,
weight_decay=0.01,
logging_dir="./logs",
logging_steps=10,
save_steps=500,
save_total_limit=2,
#metric_for_best_model="eval_loss",
load_best_model_at_end=True,
greater_is_better=False
)
trainer = SFTTrainer(
model=model,
tokenizer=tokenizer,
args=training_args,
peft_config=lora_config,
train_dataset=dataset,
compute_metrics=compute_metrics_for_regression,
)
trainer.train()
trainer.save_model("./finetuned_model")
tokenizer.save_pretrained("./finetuned_model")
Ответ или решение
Чтобы настроить модель Llama 3 для задачи регрессии с использованием PEFT, необходимо учесть несколько нюансов, которые могут помочь устранить возникшую ошибку и улучшить настройку модели. Поскольку вы уже внесли изменения в количество выходных логитов и функцию потерь, сосредоточимся на других аспектах.
Проблема с ошибкой RuntimeError
Ошибка, которую вы получаете:
RuntimeError: The size of tensor a (8) must match the size of tensor b (512) at non-singleton dimension 1
означает, что размеры ваших тензоров не совпадают при вычислении потерь. Это может быть связано с тем, как вы обрабатываете ваши данные в функции format_dataset
и как они передаются в модель и функцию потерь.
Исправление кода
-
Измените форматирование выходных данных:
Убедитесь, что
labels
представляют собой тензор правильного размера. Вместо того чтобы просто возвращатьoutput
, создайте список, который будет содержать только одно значение, и преобразуйте его в тензор.Исправленный
format_dataset
:def format_dataset(sample): input_text = sample['prompt'].replace('_', sample['rationale']) instruction = ("<|begin_of_text|><|start_header_id|>user<|end_header_id|>\n\n" "Give a statement consisting of the initial context, hypothesis, inference, and outcome, determine how plausible it is by assigning a continuous score between -1 and 1 with -1 being extremely implausible and 1 being extremely plausible.\n" f"{input_text}<|eot_id|>") output = float(sample['label']) tokenized_inputs = tokenizer(instruction, truncation=True, padding="max_length", max_length=MAX_SEQ_LEN) tokenized_inputs["labels"] = torch.tensor([output], dtype=torch.float32) # Изменено здесь return tokenized_inputs
-
Измените конфигурацию модели:
Убедитесь, что при инициализации
AutoModelForSequenceClassification
вы правильно указываетеnum_labels=1
для регрессионной задачи.model = AutoModelForSequenceClassification.from_pretrained(model_name, quantization_config=quant_config, num_labels=1)
-
Обновите функцию
compute_metrics_for_regression
:В этой функции убедитесь, что метрики считаются правильно. По всей видимости, у вас есть некоторые опечатки. Измените
labels_logits
наlabels
. Вот исправленная версия:def compute_metrics_for_regression(eval_pred): logits, labels = eval_pred # Убедитесь, что размеры совпадают logits = logits.flatten() labels = labels.flatten() mse = mean_squared_error(labels, logits) mae = mean_absolute_error(labels, logits) r2 = r2_score(labels, logits) sse = ((logits - labels) ** 2).tolist() accuracy = sum([1 for e in sse if e < 0.25]) / len(sse) return {"mse": mse, "mae": mae, "r2": r2, "accuracy": accuracy}
Итоговые шаги
После внесения этих изменений выполните следующие действия:
- Проверьте ваш набор данных: Убедитесь, что все ваши метки для оценки и входные данные корректны и соответствуют ожидаемым значениям.
- Запустите обучение: Протестируйте ваш измененный код и посмотрите, возникают ли еще ошибки.
- Отладка: Если возникают дополнительные ошибки, вы можете использовать
print
для отладки, чтобы увидеть, каково состояние ваших тензоров перед вызовом функции потерь.
Следуя этим шагам, вы сможете решить проблему с ошибкой и успешно настроить Llama 3 для вашей регрессионной задачи. Удачи!