文章标签数据语言模型强化学习文章分类jQuery前端开发阅读数254
Reward Modelling(RM)and Reinforcement Learning from Human Feedback(RLHF)for Large language models(LLM)技术初探
OpenAI 推出的 ChatGPT 对话模型掀起了新的 AI 热潮,它面对多种多样的问题对答如流,似乎已经打破了机器和人的边界。这一工作的背后是大型语言模型 (Large Language Model,LLM) 生成领域的新训练范式:RLHF (Reinforcement Learning from Human Feedback) ,即以强化学习方式依据人类反馈优化语言模型。
过去几年里各种 LLM 根据人类输入提示 (prompt) 生成多样化文本的能力令人印象深刻。然而,对生成结果的评估是主观和依赖上下文的,例如,
这些结果难以用现有的基于规则的文本生成指标 (如 BLEU 和 ROUGE) 来衡量。
除了评估指标,现有的模型通常以预测下一个单词的方式和简单的损失函数 (如交叉熵) 来建模,没有显式地引入人的偏好和主观意见。
为了解决上述问题,如果我们 用生成文本的人工反馈作为性能衡量标准,或者更进一步用该反馈作为损失来优化模型,那不是更好吗?这就是 RLHF 的思想:使用强化学习的方式直接优化带有人类反馈的语言模型。
RLHF 使得在一般文本数据语料库上训练的语言模型能和复杂的人类价值观对齐。
RLHF 是一项涉及多个模型和不同训练阶段的复杂概念,根据OpenAI的思路,RLHF分为三步:
参考链接:
https://zhuanlan.zhihu.com/p/591474085
https://zhuanlan.zhihu.com/p/613315873?utm_id=0
可用于收集人类反馈的模型主要有两类:
对于上述模型产生的结果,由专门的研究人员 labeler 去进行相对好坏的的评价,最终得到”prompt-completions pairs by human feedback“。接下来可以使用经典的微调方法训练一个sft语言模型。对这一步的模型,
这里可以用额外的文本或者条件对这个 LM 进行微调,例如
注意,这个sft-llm的训练只是一个起点,之后我们要训练一个 RM奖励模型,然后用RM奖励模型继续训练这个sft-llm。
当RM奖励模型参与到SFT训练中,会将RM中包含的人类倾向经验注入到SFT反馈中,最终我们得目标是得到一个高质量的 RLHF-LLM。
接下来,我们会基于 sft-llm 来生成训练 奖励模型 (RM,也叫偏好模型) 的数据(prompt对应的completions),并在这一步引入人类的偏好信息(打分和排名)。
下图展示当前GPT技术面向特定任务应用的开发范式,
在一般情况下,SFT已经可以满足大多数场景下的需求(我们要做的主要是数据提纯和数据蒸馏),但如果对模型生成质量有更高的需求,则需要采用基于人类反馈的强化学习(RLHF)。
当SFT Model已经可以较好地生成多种不同风格的响应回答,但出于法律、道德、人类价值观、特定领域任务要求等原因,我们需要引导SFT Model选择某种特定风格的回答。因此,我们需要一种向 LLM 提供反馈的方法,以帮助他们了解什么是有用的,什么是无用的,以便我们可以将其输出与公认的人类价值观(例如诚实、乐于助人和无害)保持一致。
综上,出于以下几种原因,我们需要训练一个RM Model:
以上正是 LLM 对齐中奖励模型的目标。
RM 的训练是 RLHF 区别于旧范式的开端。这一模型接收一系列文本(prompt-completions pairs)并返回一个标量奖励(scores),数值上对应人的偏好。
关于模型选择方面,
例如 Anthropic 提出了一种特殊的预训练方式,即用偏好模型预训练 (Preference Model Pretraining,PMP) 来替换一般预训练后的微调过程。因为前者被认为对样本数据的利用率更高。但对于哪种 RM 更好尚无定论。
关于训练文本方面,RM 的提示(prompt) - 生成(completions)对(prompt-completions pairs)文本是经过人工打标后的包含completions打分或者completions pair排序的增强文。例如下图所示
关于训练奖励数值方面,这里需要人工对 SFT-LM 生成的回答进行打分,
关于刻画文本质量的标量数字,用公式表示如下:
奖励模型接收一系列文本(good or bad prompt-completions pair)并返回一个标量奖励(scores),数值上对应人的偏好。
这个过程中一个有趣的产物是目前成功的 RLHF 系统使用了和生成模型具有 不同 大小的 LM,例如
一种直觉是,偏好模型和生成模型需要具有类似的能力来理解提供给它们的文本,即裁判的能力和运动员要大差不差,才能准确无误地对运动员的表现进行评判。
首先将初始语言模型的微调任务建模为强化学习(RL)问题,因此需要定义策略(policy)、动作空间(action space)和奖励函数(reward function)等基本要素。
整个过程如下所示:
而对于强化学习的算法,常见的可行方案是使用策略梯度强化学习 (Policy Gradient RL) 算法、近端策略优化 (Proximal Policy Optimization,PPO) 微调初始 LM 的部分或全部参数。
1、语言模型的强化学习建模
设词表为
,语言模型为,那么对于长度为 n 的序列的概率分布可表示为
对于输入
可能长度为1000的prompt,
可能是长度为100的completions。
那么由prompt x 生成completions y 的的概率可表示为:
初始化策略
,然后使用PPO算法更新策略π,奖励函数定义为 r,则奖励的期望值可表示为:
接下来,PPO 算法优化奖励函数计算步骤如下:
最后根据 PPO 算法,我们按当前批次数据的奖励指标进行优化 (来自 PPO 算法 on-policy 的特性) 。PPO 算法是一种信赖域优化 (Trust Region Optimization,TRO) 算法,它使用梯度约束确保更新步骤不会破坏学习过程的稳定性,另外也可以使用 A2C (synchronous advantage actor-critic) 算法来优化梯度。
参考链接:
https://karpathy.ai/stateofgpt.pdf
https://zhuanlan.zhihu.com/p/616708590
https://openreview.net/forum?id=10uNUgI5Kl
https://huggingface.co/blog/zh/rlhf
https://huggingface.co/datasets/CarperAI/openai_summarize_comparisons/viewer/CarperAI--openai_summarize_comparisons/train?row=0
https://zhuanlan.zhihu.com/p/450690041
选择WebGPT数据集作为reward model的语料集,如下所示,每一个prompt都对应了一个completions列表。
(
'The USA entered World War I because Germany attempted to enlist Mexico as an ally, and for what other reason?',
[
"The United States entered World War I because of Germany's use of submarine warfare against ships in the Atlantic Ocean, which was hurting American exports to Europe. Additionally, Germany tried to enlist Mexico as an ally against the United States, an event which convinced American businessmen and industrialists that the United States should enter the war.",
'The USA entered World War I because Germany attempted to enlist Mexico as an ally and for the Zimmerman Telegram.'
]
)
人类反馈强化后的数据集如下:
从数据集中选出人类反馈的最佳回答的 处理逻辑如下:
class WebGPT:
name = "openai/webgpt_comparisons"
def __init__(self, split: str = "train"):
super().__init__()
self.split = split
dataset = load_dataset(self.name, split=self.split)
self.dataset_dict = defaultdict(dict)
for item in dataset:
post_id = item["question"]["id"]
if post_id not in self.dataset_dict.keys():
self.dataset_dict[post_id] = {
"full_text": item["question"]["full_text"],
"answers": [],
}
if item["score_0"] > 0:
answers = [item["answer_0"], item["answer_1"]]
elif item["score_0"] < 0:
answers = [item["answer_1"], item["answer_0"]]
else:
answers = []
answers = [re.sub(r"\[\d+\]", "", answer) for answer in answers]
answers = [
".".join([sent.strip() for sent in answer.split(".")])
for answer in answers
]
if answers:
self.dataset_dict[post_id]["answers"].extend(answers)
else:
_ = self.dataset_dict.pop(post_id)
self.post_ids = list(self.dataset_dict.keys())
def __len__(self):
return len(self.post_ids)
def __getitem__(self, idx):
question, answers = self.dataset_dict[self.post_ids[idx]].values()
return question, answers
然后,在将数据输入模型之前,使用整理功能进行额外的数据准备,例如标记化和填充。 根据数据集,每个提示的完成次数可能会有所不同,因此我将维护一个额外的变量 batch_k_lens 以指示批次中每个提示的可用完成次数。 这将帮助我们计算损失。
@dataclass
class RMDataCollator:
tokenizer: PreTrainedTokenizer
max_length: int = 512
def format_example(self, example, eos, prompt=False):
sp_token = SPECIAL_TOKENS["prompter"] if prompt else SPECIAL_TOKENS["assistant"]
return "{}{}{}".format(sp_token, example, eos)
def process_example(self, example):
trunc_len = 0
eos = self.tokenizer.eos_token
prefix, outputs = example
prefix = self.format_example(example, eos, prompt=True)
outputs = [self.format_example(output, eos) for output in outputs]
prefix_tokens = self.tokenizer.encode(prefix)
input_ids, attention_masks = [], []
for output in outputs:
out_tokens = self.tokenizer.encode(
output,
)
if len(prefix_tokens) + len(out_tokens) > self.max_length:
trunc_len = max(
0, len(prefix_tokens) + len(out_tokens) - self.max_length
)
prefix_tokens = prefix_tokens[trunc_len:]
out_tokens = prefix_tokens + out_tokens
out_tokens = out_tokens[: self.max_length]
pad_len = self.max_length - len(out_tokens)
attn_masks = [1] * len(out_tokens) + [0] * pad_len
out_tokens += [self.tokenizer.pad_token_id] * pad_len
input_ids.append(out_tokens)
attention_masks.append(attn_masks)
return input_ids, attention_masks
def __call__(self, examples):
batch_k_lens = [0]
input_ids, attention_masks = [], []
for i, example in enumerate(examples):
inp_ids, attn_masks = self.process_example(example)
input_ids.extend(inp_ids)
attention_masks.extend(attn_masks)
batch_k_lens.append(batch_k_lens[i] + len(inp_ids))
return {
"input_ids": torch.tensor(input_ids),
"attention_mask": torch.tensor(attention_masks),
"k_lens": batch_k_lens,
}
对于reward model模型架构,有两种选择:
我现在选择 GPTNeoXModel,我将对最后一个隐藏层进行平均池化,并添加顶部的自定义头部以生成标量输出。
@dataclass
class GPTNeoxRMOuptput(ModelOutput):
"""
Reward Model Output
"""
logits: torch.FloatTensor = None
class GPTNeoXRM(GPTNeoXPreTrainedModel):
""" """
def __init__(
self,
config,
):
super().__init__(config)
self.gpt_neox = GPTNeoXModel(config)
self.out_layer = nn.Linear(config.hidden_size, 1)
def forward(
self,
input_ids,
attention_mask,
**kwargs,
):
return_dict = (
kwargs.get("return_dict")
if kwargs.get("return_dict") is not None
else self.config.use_return_dict
)
outputs = self.gpt_neox(
input_ids,
attention_mask,
return_dict=return_dict,
**kwargs,
)
hidden_states = outputs[0]
if attention_mask is None:
hidden_states = hidden_states.mean(dim=1)
else:
hidden_states = (hidden_states * attention_mask.unsqueeze(-1)).sum(
dim=1
) / attention_mask.sum(dim=1).unsqueeze(-1)
lm_logits = self.out_layer(hidden_states)
if not return_dict:
return (lm_logits,) + outputs[1:]
return GPTNeoxRMOuptput(logits=lm_logits)
对于损失函数,我将使用额外的 L2 归一化因子,以防止过度拟合。 对于每个提示prompt的k个响应回答completions,存在
个两两比较。
损失是针对每个提示单独计算的,并取平均值以获得批量平均损失。
class RMLoss(nn.Module):
""" """
def __init__(
self,
reduction=None,
beta=0.001,
):
super().__init__()
self.reduction = reduction
self.beta = beta
def forward(
self,
logits,
k_lens=None,
):
total_loss = []
indices = list(zip(k_lens[:-1], k_lens[1:]))
for start, end in indices:
combinations = torch.combinations(
torch.arange(start, end, device=logits.device), 2
)
positive = logits[combinations[:, 0]]
negative = logits[combinations[:, 1]]
l2 = 0.5 * (positive**2 + negative**2)
loss = (
-1 * nn.functional.logsigmoid(positive - negative) + self.beta * l2
).mean()
total_loss.append(loss)
total_loss = torch.stack(total_loss)
if self.reduction == "mean":
total_loss = total_loss.mean()
return total_loss
view raw
最后,我们会将所有这些连同训练参数一起传递给自定义训练器来训练和评估我们的模型。
记住!我们最终的目标是训练出一个”裁判“,这个”裁判“代表了人类反馈的倾向,它可以对prompt的completions进行打分和排序(本质上是实现训练集蒸馏)。
一旦训练出一个好的”裁判“,LLM SFT的开发就可以进入一个正向循环,一个整体的开发流程如下:
参考链接:
https://explodinggradients.com/reward-modeling-for-large-language-models-with-code
https://huggingface.co/datasets/openai/summarize_from_feedback/viewer/axis/test?row=0
以trlx的 rlhf案例 为例,深入了解整个过程。
对于大多数特定领域任务LLM的开发来说,项目的初期基本都是从零样本冷启动开始的。因此,task-LLM的第一步就是数据准备工作。
我们分两种情况讨论零样本启动流程。
1、基础大模型能力相对目标任务领域有泛化能力较差
当处于这种情况时,我们需要分别采取prompt engining、样本提纯蒸馏等过程,循环迭代不断扩展我们的基础样本。
2、基础大模型能力能够生成基本符合相对目标任务领域的样本
当处于这种情况时,sample distillation(样本蒸馏/提纯)这一步可以基本省略,其他步骤保持不变。
基础大模型生成的completions基本都满足目标任务领域的最低质量要求,重点的工作就要放在强化奖励模型的开发和RLHF微调训练上。
我们使用” CarperAI/openai_summarize_tldr“,基于” EleutherAI/gpt-j-6B“进行SFT,
# 单GPU
cd sft/ && CUDA_VISIBLE_DEVICES=0 python3 train_gptj_summarize.py
# 多GPU
cd sft/ && deepspeed train_gptj_summarize.py
通过sft,得到了一个和summarize任务对齐了的sft-llm。
1、数据集准备工作(completions打分、排名)
在一般的项目开发中,我们需要雇佣数据承包商或者外包人员,对base-llm、sft-llm、人工等方式生成的completions进行排序(rank)。这一步非常消耗时间,但对最终模型的效果来说又非常重要。
这里我们使用hugeface上开源的” CarperAI/openai_summarize_comparisons“进行演示。
2、hugface数据集(已完成rank排序的completions数据集)加载与预处理
使用开源 数据集,创建一个由字典的组成的列表,每一个字典有3个key,
def create_comparison_dataset(path="CarperAI/openai_summarize_comparisons", split="train"):
dataset = load_dataset(path, split=split)
pairs = []
for sample in tqdm(dataset):
pair = {}
prompt = sample["prompt"]
chosen_summary = sample["chosen"]
rejected_summary = sample["rejected"]
if chosen_summary == rejected_summary:
continue
if len(chosen_summary.split()) < 5 or len(rejected_summary.split()) < 5:
continue
pair["chosen"] = prompt + "\n" + chosen_summary
pair["rejected"] = prompt + "\n" + rejected_summary
pairs.append(pair)
return pairs
拼接prompt-completions pair对,
针对处理完的 pair 对,进行分词处理,并构造成可供训练的数据集形式
class PairwiseDataset(Dataset):
def __init__(self, pairs, tokenizer, max_length):
self.chosen_input_ids = []
self.chosen_attn_masks = []
self.rejected_input_ids = []
self.rejected_attn_masks = []
for pair in tqdm(pairs):
chosen, rejected = pair["chosen"], pair["rejected"]
chosen_encodings_dict = tokenizer(
"<|startoftext|>" + chosen + "<|endoftext|>",
truncation=True,
max_length=max_length,
padding="max_length",
return_tensors="pt",
)
rejected_encodings_dict = tokenizer(
"<|startoftext|>" + rejected + "<|endoftext|>",
truncation=True,
max_length=max_length,
padding="max_length",
return_tensors="pt",
)
self.chosen_input_ids.append(chosen_encodings_dict["input_ids"])
self.chosen_attn_masks.append(chosen_encodings_dict["attention_mask"])
self.rejected_input_ids.append(rejected_encodings_dict["input_ids"])
self.rejected_attn_masks.append(rejected_encodings_dict["attention_mask"])
def __len__(self):
return len(self.chosen_input_ids)
def __getitem__(self, idx):
return (
self.chosen_input_ids[idx],
self.chosen_attn_masks[idx],
self.rejected_input_ids[idx],
self.rejected_attn_masks[idx],
)
上述数据不便于同时输入模型进行训练,需要进一步整理数据,构造成如下形式:
需要说明的是,经过上述处理,batch size 变为原来的2倍
class DataCollatorReward:
def __call__(self, data):
batch = {}
batch["input_ids"] = torch.cat([f[0] for f in data] + [f[2] for f in data])
batch["attention_mask"] = torch.cat([f[1] for f in data] + [f[3] for f in data])
batch["labels"] = torch.tensor([0] * len(data) + [1] * len(data))
return batch
3、构建奖励模型
RM 的结构相对简单,即 transformer 结构+线性分类头。
定义loss公式,
class GPTRewardModel(nn.Module):
def __init__(self, model_path):
super().__init__()
model = AutoModelForCausalLM.from_pretrained(model_path)
self.config = model.config
# `gpt-neo(x)` models use `hidden_size` attribute names instead of `n_embd``
self.config.n_embd = self.config.hidden_size if hasattr(self.config, "hidden_size") else self.config.n_embd
self.transformer = model.transformer
self.v_head = nn.Linear(self.config.n_embd, 1, bias=False)
self.tokenizer = AutoTokenizer.from_pretrained("EleutherAI/gpt-j-6B")
self.tokenizer.pad_token = self.tokenizer.eos_token
self.PAD_ID = self.tokenizer(self.tokenizer.pad_token)["input_ids"][0]
def forward(
self,
input_ids=None,
past_key_values=None,
attention_mask=None,
token_type_ids=None,
position_ids=None,
head_mask=None,
inputs_embeds=None,
mc_token_ids=None,
labels=None,
return_dict=False,
output_attentions=False,
output_hidden_states=False,
):
loss = None
transformer_outputs = self.transformer(
input_ids,
past_key_values=past_key_values,
attention_mask=attention_mask,
token_type_ids=token_type_ids,
position_ids=position_ids,
head_mask=head_mask,
inputs_embeds=inputs_embeds,
)
hidden_states = transformer_outputs[0]
rewards = self.v_head(hidden_states).squeeze(-1)
chosen_end_scores = []
rejected_end_scores = []
# Split the inputs and rewards into two parts, chosen and rejected
assert len(input_ids.shape) == 2
bs = input_ids.shape[0] // 2
chosen = input_ids[:bs]
rejected = input_ids[bs:]
chosen_rewards = rewards[:bs]
rejected_rewards = rewards[bs:]
loss = 0
inference = False
for i in range(bs):
if torch.all(torch.eq(chosen[i], rejected[i])).item():
c_inds = (chosen[i] == self.PAD_ID).nonzero()
c_ind = c_inds[0].item() if len(c_inds) > 0 else chosen.shape[1]
chosen_end_scores.append(chosen_rewards[i, c_ind - 1])
inference = True
continue
# Check if there is any padding otherwise take length of sequence
c_inds = (chosen[i] == self.PAD_ID).nonzero()
c_ind = c_inds[0].item() if len(c_inds) > 0 else chosen.shape[1]
r_inds = (rejected[i] == self.PAD_ID).nonzero()
r_ind = r_inds[0].item() if len(r_inds) > 0 else rejected.shape[1]
end_ind = max(c_ind, r_ind)
# Retrieve first index where trajectories diverge
divergence_ind = (chosen[i] != rejected[i]).nonzero()[0]
assert divergence_ind > 0
# Index into the correct rewards
c_truncated_reward = chosen_rewards[i][divergence_ind:end_ind]
r_truncated_reward = rejected_rewards[i][divergence_ind:end_ind]
# Append the last rewards to the list of end scores
chosen_end_scores.append(c_truncated_reward[-1])
rejected_end_scores.append(r_truncated_reward[-1])
# Compute loss based on truncated rewards (ignore padding)
loss += -torch.log(torch.sigmoid(c_truncated_reward - r_truncated_reward)).mean()
loss = loss / bs
if not inference:
chosen_end_scores = torch.stack(chosen_end_scores)
rejected_end_scores = torch.stack(rejected_end_scores)
if inference:
chosen_end_scores = torch.stack(chosen_end_scores)
return {"chosen_end_scores": chosen_end_scores}
return {
"loss": loss,
"chosen_end_scores": chosen_end_scores,
"rejected_end_scores": rejected_end_scores,
}
将以上部分组合起来,即可以训练RM
# Initialize the reward model from the (supervised) fine-tuned GPT-J
model = GPTRewardModel("CarperAI/openai_summarize_tldr_sft")
# Freeze the first 70% of the hidden layers of the reward model backbone
layers = model.transformer.h
num_layers = len(layers)
num_unfrozen = int(0.3 * num_layers)
for layer in layers[:-num_unfrozen]:
layer.requires_grad_(False)
# Create the comparisons datasets
data_path = "CarperAI/openai_summarize_comparisons"
train_pairs = create_comparison_dataset(data_path, "train")
val_pairs = create_comparison_dataset(data_path, "test")
# Make pairwise datasets for training
max_length = 550
train_dataset = PairwiseDataset(train_pairs, tokenizer, max_length=max_length)
val_dataset = PairwiseDataset(val_pairs, tokenizer, max_length=max_length)
# Create the collator to gather batches of pairwise comparisons
data_collator = DataCollatorReward()
Trainer(
model=model,
args=training_args,
train_dataset=train_dataset,
compute_metrics=compute_metrics,
eval_dataset=val_dataset,
data_collator=data_collator,
).train()
4、启动BP训练
cd reward_model/ && deepspeed train_reward_model_gptj.py
如果想要加快时间,也可以直接下载hugeface上已经开源的训练好的reward model,
mkdir reward_model/rm_checkpoint
wget https://huggingface.co/CarperAI/openai_summarize_tldr_rm_checkpoint/resolve/main/pytorch_model.bin -O reward_model/rm_checkpoint/pytorch_model.bin
由于PPO算法的值函数可以是一个深度学习模型,在本例中则是一个 transformer 模型,策略梯度方法的基本思想将值函数表示为策略参数的某个函数,然后可以根据RM的反馈值进行更新。
1、标准化(Normalization)
由于 reward scores 方差较大,因此需要根据人为结果做差以实现标准化,即
其中
分别表示模型得分和人为得分。代码实现如下:
def reward_fn(samples: List[str]):
# get humans summarizes
posts = [sample.split('TL;DR')] for sample in samples]
ref_samples = [post + 'TL;DR' + post_summ_dict[post] for post in post]
samples_encodings = reward_tokenizer(samples)
samples_scores = reward_model(**samples_encodings) # get scores from reward model for samples
ref_samples_encodings = reward_tokenizer(ref_samples) # get scores from reward model corresponding references samples
ref_samples_scores = reward_model(**ref_samples_encodings)
norms_rewards = samples_scores - ref_samples_scores
return norms_rewards
2、KL 散度(KL Divergence)
当使用 PPO 做 fine-tuning 的时候,summary 由策略(LLM)生成。生成的 summary传到奖励模型生成奖励分,进而更新策略。 由于上述操作是 batch-wise 的,同时由于 RL 训练的噪声很大,特别是在初始阶段,这些可能会导致策略偏移过大。为防止这个问题,引进KL散度作为惩罚项,以避免策略模型偏差过大。
其中
表示奖励模型的输出分数,
表示系数,
表示策略模型,
表示监督模型。
3、启动PPO训练
accelerate launch --config_file configs/default_accelerate_config.yaml trlx_gptj_text_summarization.py
SFT vs PPO
Model |
Rouge-1 |
Rouge-2 |
Rouge-L |
Average |
SFT |
0.334 |
0.125 |
0.261 |
0.240 |
PPO |
0.323 |
0.109 |
0.238 |
0.223 |
ROUGE scores
Model |
Average Reward |
Reward Δ |
SFT |
2.729 |
-0.181 |
PPO |
3.291 |
+0.411 |
Reward scores
参考链接:
https://huggingface.co/datasets/CarperAI/openai_summarize_comparisons/viewer/CarperAI--openai_summarize_comparisons/train?row=0
https://link.zhihu.com/?target=https%3A//github.com/CarperAI/trlx/tree/main/examples/summarize_rlhf
https://github.com/CarperAI/trlx
https://github.com/CarperAI/trlx/tree/main/examples/summarize_rlhf
参考资料:
https://github.com/allenai/RL4LMs
RM总共有两种作用场景:
如果场景1,其实还可以有另一种范式,即通过构造prompt template实现一个“prompt-completions pair文本质量推理链”,prompt template包含如下几个元素:
一个例如如下:
登录后复制
You are a fair AI assistant for checking the quality of the answers of other two AI assistants.
[Question]
{data['query']}
[The Start of Assistant 1's Answer]
llama chains: {data['llama_chains']}
llama answer: {data['llama_answer']}
[The End of Assistant 1's Answer]
[The Start of Assistant 2's Answer]
chatgpt chains: {data['chatgpt_chains']}
chatgpt answer: {data['chatgpt_answer']}
[The End of Assistant 2's Answer]
We would like to request your feedback on the performance of two AI assistants in response to the user question displayed above.
Please first judge if the answer is correct based on the question, if an assistant gives a wrong answer, the score should be low.
Please rate the quality, correctness, helpfulness of their responses based on the question.
Each assistant receives an overall score on a scale of 1 to 10, where a higher score indicates better overall performance, your scores should be supported by reasonable reasons.
Please first output a single line containing only two values indicating the scores for Assistant 1 and 2, respectively.
The two scores are separated by a space. In the subsequent line, please provide a comprehensive explanation of your evaluation, avoiding any potential bias, and the order in which the responses were presented does not affect your judgement.
If the two assistants perform equally well, please output the same score for both of them.
回放中丨2023北京智源大会
https://2023.baai.ac.cn/schedule
智源「悟道3.0」大模型系列问世
https://baai.org/l/27398
Hinton:放弃永生的凡人计算 (附视频)
https://baai.org/l/27397
Yann LeCun:LLM推理能力有限,需要被重新训练
https://baai.org/l/27396
Sam Altman:AI 安全始于足下
https://baai.org/l/27385
David Holz:AI将彻底改变学习、创意和组织
https://baai.org/l/27399