只能说“钞能力”真伟大,openai 直接请了一群人,给 GPT 生成的多个回答进行排序打分,然后再根据这个打分训练一个奖励模型(GPT 生成的结果越好,得分越高),有了这样一个模型后,就可以用来指导 GPT 生成尽可能高分的回答了。
没钱也没精力,但不妨碍我们学习如何训练一个奖励模型,奖励模型的学习本质就是一个句子分类或者回归的任务。
这里找一个数据集来展示一下整个流程,比如 IMDB 影评数据集,常用于情感分析,也就是给文本的情感打分,输入就是影评,输出就是得分(积极或消极对应 1 或 0),那就能训练一个奖励模型了(比如可以用来指导 GPT 生成得分越高,也就是更加积极的文本)。
首先导入一下数据集(下载链接:https://ai.stanford.edu/~amaas/data/sentiment/)
def read_imdb_split(split_dir):
split_dir = Path(split_dir)
texts = []
labels = []
for label_dir in ["pos", "neg"]:
for text_file in (split_dir/label_dir).iterdir():
texts.append(text_file.read_text(encoding='utf-8'))
labels.append(0 if label_dir is "neg" else 1)
return texts, labels
train_texts, train_labels = read_imdb_split("./DataSmall/aclImdb/train")
test_texts, test_labels = read_imdb_split("./DataSmall/aclImdb/test")
看一眼数据就是长这样,一段文本对应一个标签:
同样的我们需要对其进行分词,转为一串 id,定义分词器,并构造数据集:
print("Tokenizing train, validate, test text ")
tokenizer = DistilBertTokenizerFast.from_pretrained('distilbert-base-uncased')
train_encodings = tokenizer(train_texts, truncation=True, padding=True)
test_encodings = tokenizer(test_texts, truncation=True, padding=True)
class IMDbDataset(torch.utils.data.Dataset):
def __init__(self, encodings, labels):
self.encodings = encodings
self.labels = labels
def __getitem__(self, idx):
item = {key: torch.tensor(val[idx]) for key, val in self.encodings.items()}
item['labels'] = torch.tensor(self.labels[idx])
return item
def __len__(self):
return len(self.labels)
print("Loading tokenized text into Pytorch Datasets ")
train_dataset = IMDbDataset(train_encodings, train_labels)
test_dataset = IMDbDataset(test_encodings, test_labels)
train_loader = DataLoader(train_dataset, batch_size=10, shuffle=True)
接下来定义一个用于预测得分的模型,以及优化器:
print("Loading pre-trained DistilBERT model ")
model = DistilBertForSequenceClassification.from_pretrained('distilbert-base-uncased')
model.to(device)
model.train()
optim = AdamW(model.parameters(), lr=5e-5)
接下来就可以开始模型的训练了:
for epoch in range(3):
for (b_ix, batch) in enumerate(train_loader):
optim.zero_grad()
input_ids = batch['input_ids'].to(device)
attention_mask = batch['attention_mask'].to(device)
labels = batch['labels'].to(device)
outputs = model(input_ids, attention_mask=attention_mask, labels=labels)
loss = outputs[0]
loss.backward()
optim.step()
训练完模型后,我们就可以对任意文本来进行情感的打分了,比如:
显然这是一句很 positive 的话,模型的打分为:
本章的完整代码可以参考 James D. McCaffrey 的博客:
https://jamesmccaffrey.wordpress.com/author/jamesdmccaffrey/
PS:模型的选择问题,这里作为演示采样了一个 distilbert 作为奖励模型,但实际上 ChatGPT 用的奖励模型的规模应该是和生成模型差不多大小的模型。
到目前为止,我们已经能够训练一个能够生成文本的 GPT,一个能够对文本打分的奖励模型,接下来就需要考虑如果用奖励模型来教会 GPT 生成高分文本了。考虑到很多同学可能没有强化学习的基础,这里将插入一章强化学习的介绍。
(深度)强化学习简介强化学习的内容其实很多,背后涉及的数学也挺多,身边很多人在入门过程就被劝退,为了让大家更易于接受,这里主要介绍一些必备的基础知识,以及从策略梯度方法到 PPO 算法的演进。
强化术语在强化学习中,智能体和环境进行交互并基于一定的奖励机制来提高自身的水平;智能体的决策,一般称为策略(policy)决定了在当前环境状态下智能体应该去实施什么动作;实施完动作后,智能体会随着环境进入下一个状态,并获得相应的奖励或惩罚。这里附上两页 slides 帮助大家理解(图片来源为 wangshusen 老师的强化课程)。