Неправильные маркеры заполнения в прогнозировании модели HFPython

Программы на Python
Ответить
Anonymous
 Неправильные маркеры заполнения в прогнозировании модели HF

Сообщение Anonymous »

Рассмотрите следующий код:

Код: Выделить всё

from datasets import load_dataset_builder, load_dataset
import numpy as np
import os
import torch
from transformers import AutoModelForSeq2SeqLM, AutoTokenizer, DataCollatorForSeq2Seq, Seq2SeqTrainer, Seq2SeqTrainingArguments

class QGenMetrics:
def __init__(self, tokenizer, ignore_index=-100):
self.tokenizer = tokenizer
self.ignore_index = ignore_index

def clean_labels(self, labels):
labels[labels == self.ignore_index] = self.tokenizer.pad_token_id
return labels

def compute_metrics_validation(self, eval_preds):
predictions = eval_preds.predictions
labels = eval_preds.label_ids

# predictions, labels = eval_preds
#
try:
labels = self.clean_labels(labels)
predictions = self.tokenizer.batch_decode(predictions, skip_special_tokens=True)
labels = self.tokenizer.batch_decode(labels, skip_special_tokens=True)
except Exception as e:
print(e)
print("PREDS")
print(predictions)
print("LABELS")
print(labels)
for i, pred in enumerate(predictions):
if -100 in pred:
print(f"preds[{i}]: {pred}")
assert False

res = {"metric":1.0}
return res

def compute_metrics_test(self, test_preds):
res = {"metric":1.0}
return res
#<

def actual_encoding(examples, tokenizer, max_source_len=None, max_target_len=None, ignore_label=-100):
# no padding and no truncation: a collator will do the job
# prompts_enc = tokenizer(examples["prompt"], padding="max_length", truncation=True, max_length=200)
# targets_enc = tokenizer(text_target=examples["question"], padding="max_length", truncation=True, max_length=200)  # max_length=target_length, padding="max_length", truncation=True, return_tensors="pt")
prompts_enc = tokenizer(examples["question"],
truncation = True if max_source_len else False,
max_length = max_source_len if max_source_len else None,
padding = "max_length" if max_source_len else False,
return_tensors="pt" if max_source_len else None)
targets_enc = tokenizer(examples["text"],
truncation = True if max_target_len else False,
padding = "max_length" if max_target_len else False,
max_length = max_target_len if max_target_len else None,
return_tensors="pt" if max_source_len else None)

print(type(prompts_enc))
examples["input_ids"] = prompts_enc["input_ids"]
examples["attention_mask"] = prompts_enc["attention_mask"]

# unused
# labels = []
# for ex_labels in targets_enc["input_ids"]:
#     proc_labels = [label if label != 0 else ignore_label for label in ex_labels]
#     labels.append(proc_labels)
examples["labels"] = targets_enc["input_ids"]  # labels
return examples
#<  actual_encoding

# download Bilkies/QuestionGeneration from HF hub
# https://huggingface.co/datasets/Bilkies/QuestionGeneration

ds_name = 'Bilkies/QuestionGeneration'
ds_builder = load_dataset_builder(ds_name)
print(ds_builder.info)
dataset = load_dataset(ds_name)
display(dataset)
train_ds = dataset['train']
print("number of original training point", len(train_ds))
# subsample train_ds
train_ds = train_ds.select(range(1000))
print("after sampling", len(train_ds))
test_ds = dataset['validation'].select(range(500))
# split training_ds in 80/20 for training and validation
train_ds = train_ds.train_test_split(test_size=0.2)
valid_ds = train_ds['test']
train_ds = train_ds['train']

model_id = "google/flan-t5-small"
tokenizer = AutoTokenizer.from_pretrained(model_id)

max_source_len = 31
max_target_len = 50

train_ds = train_ds.map(actual_encoding, fn_kwargs={"tokenizer": tokenizer, "max_source_len":max_source_len, "max_target_len":max_target_len}, batched=True, num_proc=2)

valid_ds = valid_ds.map(actual_encoding, fn_kwargs={"tokenizer": tokenizer, "max_source_len": max_source_len, "max_target_len": max_target_len}, batched=True, num_proc=2)

test_ds = test_ds.map(actual_encoding, fn_kwargs={"tokenizer": tokenizer, "max_source_len": max_source_len, "max_target_len": max_target_len}, batched=True, num_proc=2)

for ds in [train_ds, valid_ds, test_ds]:
ds_in_lens = [len(ex["input_ids"]) for ex in ds.iter(batch_size=1)]
ds_lab_lens = [len(ex["labels"]) for ex in ds.iter(batch_size=1)]
check = np.array([l == ds_in_lens[0] for l in ds_in_lens[1:]]).all() and np.array([l == ds_lab_lens[0] for l in ds_lab_lens[1:]]).all()
assert check, "check lengths in {ds}"

model = AutoModelForSeq2SeqLM.from_pretrained(model_id)
model = model.to(torch.device("cuda:0"))

bs = 1

data_collator = DataCollatorForSeq2Seq(tokenizer=tokenizer, model=model, padding="longest", label_pad_token_id=-100)
evaluator = QGenMetrics(tokenizer)
trainer = Seq2SeqTrainer(
model=model,
train_dataset=train_ds,
eval_dataset=valid_ds,
data_collator=data_collator,
compute_metrics=evaluator.compute_metrics_validation,
args=Seq2SeqTrainingArguments(
output_dir="./_remove",
gradient_accumulation_steps=1,
per_device_train_batch_size=per_dev_bs,
per_device_eval_batch_size=per_dev_bs,
num_train_epochs=1,
seed = 3,
data_seed = 4,
predict_with_generate=True,
eval_strategy="epoch",
report_to="none"
) #< training args
) #< trainer

trainer.train()
Что я объясняю здесь:

Код: Выделить всё

# download Bilkies/QuestionGeneration from HF hub
# https://huggingface.co/datasets/Bilkies/QuestionGeneration

ds_name = 'Bilkies/QuestionGeneration'
ds_builder = load_dataset_builder(ds_name)
print(ds_builder.info)
dataset = load_dataset(ds_name)
display(dataset)
train_ds = dataset['train']
print("number of original training point", len(train_ds))
# subsample train_ds
train_ds = train_ds.select(range(1000))
print("after sampling", len(train_ds))
test_ds = dataset['validation'].select(range(500))
# split training_ds in 80/20 for training and validation
train_ds = train_ds.train_test_split(test_size=0.2)
valid_ds = train_ds['test']
train_ds = train_ds['train']
После загрузки набора данных Bilkies/QuestionGeneration я сохраняю только первые 1000 примеров в целях «скорости». Я создаю три раздела данных:
  • набор тестовых данных test_ds, который соответствует допустимому разделу набора данных HF

    Код: Выделить всё

    train_ds
    и valid_ds, которые соответствуют 80 % и 20 % обучающих данных соответственно.

Код: Выделить всё

model_id = "google/flan-t5-small"
tokenizer = AutoTokenizer.from_pretrained(model_id)

max_source_len = 31
max_target_len = 50

train_ds = train_ds.map(actual_encoding, fn_kwargs={"tokenizer": tokenizer, "max_source_len":max_source_len, "max_target_len":max_target_len}, batched=True, num_proc=2)

valid_ds = valid_ds.map(actual_encoding, fn_kwargs={"tokenizer": tokenizer, "max_source_len": max_source_len, "max_target_len": max_target_len}, batched=True, num_proc=2)

test_ds = test_ds.map(actual_encoding, fn_kwargs={"tokenizer": tokenizer, "max_source_len": max_source_len, "max_target_len": max_target_len}, batched=True, num_proc=2)

for ds in [train_ds, valid_ds, test_ds]:
ds_in_lens = [len(ex["input_ids"]) for ex in ds.iter(batch_size=1)]
ds_lab_lens = [len(ex["labels"]) for ex in ds.iter(batch_size=1)]
check = np.array([l == ds_in_lens[0] for l in ds_in_lens[1:]]).all() and np.array([l == ds_lab_lens[0] for l in ds_lab_lens[1:]]).all()
assert check, "check lengths in {ds}"
Я загружаю модель и связанный с ней токенизатор, затем токенизирую три набора данных с помощью fact_encoding с заранее определенной максимальной длиной для input_ids и меток. Цикл for в конце проверяет, что все поля, используемые при обучении, имеют одинаковую длину.
Затем я обучаю модель, выполняя этап проверки в конце каждого обучения. эпоха. Проверка основана на сгенерированных token_id, а не на логитах (

Код: Выделить всё

predict_with_generate=True
)

Код: Выделить всё

bs = 1

data_collator = DataCollatorForSeq2Seq(tokenizer=tokenizer, model=model, padding="longest", label_pad_token_id=-100)
evaluator = QGenMetrics(tokenizer)
trainer = Seq2SeqTrainer(
model=model,
train_dataset=train_ds,
eval_dataset=valid_ds,
data_collator=data_collator,
compute_metrics=evaluator.compute_metrics_validation,
args=Seq2SeqTrainingArguments(
output_dir="./_remove",
gradient_accumulation_steps=1,
per_device_train_batch_size=bs,
per_device_eval_batch_size=bs,
num_train_epochs=1,
seed = 3,
data_seed = 4,
predict_with_generate=True,
eval_strategy="epoch",
report_to="none"
) #< training args
) #< trainer

trainer.train()
Модель оценивается с помощью QGenMetrics, в частности, с помощью метода Compute_metrics_validation:

Код: Выделить всё

def compute_metrics_validation(self, eval_preds):
predictions = eval_preds.predictions
labels = eval_preds.label_ids

try:
labels = self.clean_labels(labels)
predictions = self.tokenizer.batch_decode(predictions, skip_special_tokens=True)
labels = self.tokenizer.batch_decode(labels, skip_special_tokens=True)
except Exception as e:
print(e)
print("PREDS")
print(predictions)
print("LABELS")
print(labels)
for i, pred in enumerate(predictions):
if -100 in pred:
print(f"preds[{i}]: {pred}")
assert False

res = {"metric":1.0}
return res
Метки очищаются, а их значение заполнения -100 заменяется токеном заполнения, предоставленным токенизатором. Затем токенизатор декодирует и предсказания, и метки.
Проблема в том, что токенизатор находит значение -100 в предсказанных токенах:

Код: Выделить всё

Trainer.tokenizer is now deprecated.  You should use Trainer.processing_class instead.
[[repeated for every validation sample]]

out of range integral type conversion attempted

[...]
preds[0]: [    0     3     9 28376     1     0     0     0     0     0     0     0
0     0     0     0     0     0     0     0  -100]
[...]
preds[199]: [   0  328 1944    3    9  467   13    3 2951    7   16    8    3 2951
7 5892    5    1    0    0 -100]

Как вы можете видеть:
  • Trainer.tokenizer используется, но я не вижу, где, потому что я явно вызывать токенизатор, когда мне это нужно.
  • Каждый прогноз проверки имеет конечное значение -100, которого там быть не должно.
Я уверен, что ошибка вызвано очень глупым шагом, который я сделал в своем коде, но я не могу понять, какой именно.
Кто-нибудь может мне помочь?
Я подготовил блокнот в Colab, но не уверен, что он работает нормально, так как не могу получить доступ к среде выполнения с графическим процессором.
https://colab.research.google.com/drive ... sp=sharing

Подробнее здесь: https://stackoverflow.com/questions/792 ... prediction
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Python»