В процессе работы RLHF я создал модель вознаграждения, используя набор данных из пар строк chosen
и rejected
. Он очень похож на пример в официальной библиотеке TRL — Моделирование вознаграждения
Я использовал модель LLaMA 2 7b (пробовал как чатовую, так и не чатовую версию - поведение одинаковое). Теперь мне хотелось бы передать входные данные и увидеть выходные данные модели вознаграждения. Однако я не могу понять, что выводит модель вознаграждения.
Например: я попытался ввести данные следующим образом:
chosen = "This is the chosen text."
rejected = "This is the rejected text."
test = {"chosen": chosen, "rejected": rejected}
Тогда я попробую -
import torch
import torch.nn as nn
from transformers import AutoModelForSequenceClassification, AutoTokenizer, AutoModelForCausalLM
base_model_id = "./llama2models/Llama-2-7b-chat-hf"
model_id = "./reward_models/Llama-2-7b-chat-hf_rm_inference/checkpoint-500"
model = AutoModelForSequenceClassification.from_pretrained(
model_id,
# num_labels=1, #gives an error since the model always outputs a tensor of [2, 4096]
)
tokenizer = AutoTokenizer.from_pretrained(base_model_id)
rewards_chosen = model(
**tokenizer(chosen, return_tensors='pt')
).logits
print('reward chosen is ', rewards_chosen)
rewards_rejected = model(
**tokenizer(rejected, return_tensors='pt')
).logits
print('reward rejected is ', rewards_rejected)
loss = -nn.functional.logsigmoid(rewards_chosen - rewards_rejected).mean()
print(loss)
И результат выглядит примерно так:
reward chosen is tensor([[ 2.1758, -8.8359]], dtype=torch.float16)
reward rejected is tensor([[ 1.0908, -2.2168]], dtype=torch.float16)
tensor(0.0044)
Потеря печати не помогла. Я имею в виду, что я не вижу какой-либо тенденции (например, положительный убыток становится отрицательным), даже если я поменяю rewards_chosen
и rewards_rejected
в формуле.
Кроме того, результаты не дали никакой информации. Я не понимаю, как понимать rewards_chosen
и rewards_rejected
. Почему они представляют собой тензор с двумя элементами вместо одного?
Я пробовал rewards_chosen > rewards_rejected
, но это тоже бесполезно, так как выводит tensor([[ True, False]])
Когда я пробую какую-нибудь модель публичного вознаграждения (она занимает всего несколько мегабайт, поскольку это всего лишь адаптер — https://huggingface.co/vincentmin/llama-2-13b-reward-oasst1), я получаю результаты, которые имеют больше смысла. поскольку он выводит тензор одного элемента -
Код -
import torch
import torch.nn as nn
from peft import PeftModel, PeftConfig
from transformers import AutoModelForSequenceClassification, AutoTokenizer, AutoModelForCausalLM
peft_model_id = "./llama-2-13b-reward-oasst1"
base_model_id = "/cluster/work/lawecon/Work/raj/llama2models/13b-chat-hf"
config = PeftConfig.from_pretrained(peft_model_id)
model = AutoModelForSequenceClassification.from_pretrained(
base_model_id,
num_labels=1,
# torch_dtype=torch.float16,
)
model = PeftModel.from_pretrained(model, peft_model_id)
tokenizer = AutoTokenizer.from_pretrained(base_model_id)
chosen = "prompter: What is your purpose? assistant: My purpose is to assist you."
rejected = "prompter: What is your purpose? assistant: I do not understand you."
test = {"chosen": chosen, "rejected": rejected}
model.eval()
with torch.no_grad():
rewards_chosen = model(
**tokenizer(chosen, return_tensors='pt')
).logits
print('reward chosen is ', rewards_chosen)
rewards_rejected = model(
**tokenizer(rejected, return_tensors='pt')
).logits
print('reward rejected is ', rewards_rejected)
loss = -nn.functional.logsigmoid(rewards_chosen - rewards_rejected).mean()
print(loss)
Выход -
reward chosen is tensor([[0.6876]])
reward rejected is tensor([[-0.9243]])
tensor(0.1819)
Этот вывод имеет для меня больше смысла. Но почему в моей модели вознаграждения я получаю выходные данные с двумя значениями?
Я сам столкнулся с той же проблемой, следуя тому же примеру в библиотеке TRL! Я думаю, что в этом примере есть ошибка; модели вознаграждения должны выводить одноэлементные тензоры, как вы предлагаете, а не двухэлементные тензоры.
Я считаю, что установка num_labels=1
при звонке AutoModelForSequenceClassification.from_pretrained
— это решение. Это создает экземпляр модели с одноэлементным выходом.
Я вижу, что вы прокомментировали это в своем примере, сказав, что это «выдает ошибку, поскольку модель всегда выводит тензор [2, 4096]». У меня такой ошибки нет, поэтому я не уверен, что у вас там происходит.
Да вы правы. В конце концов я это понял. Никогда не было времени вернуться к нему и ответить на него.