如何强制GPT2生成的每个句子都包含指定token?
GPT2强制生成包含指定Token的实现方法
需求说明
输入字符串后输出对应生成token的向量表示,要求所有生成句子必须满足硬性规则:包含预先指定的token,例如必须出现4个逗号、2个单词"to"等。
目前已考虑的两个思路:
- 思路1:是否存在专门的损失项,能强制GPT2生成内容包含指定token?
- 思路2:参考BERT的token掩码机制,不强制模型主动生成指定token,而是提前在序列中放置预定义token,序列格式如下:
[MASK][MASK][specific_token][MASK][MASK][specific_token]
但这个思路存在明显缺陷:[specific_token]前后需要生成/掩码的token数量无法提前定义,每次输入对应的待生成句子总长度也不固定——如果长度固定我直接用BERT就能实现,不需要适配GPT2。
当前已写的基础测试代码:
from transformers import logging from transformers import GPT2Tokenizer, GPT2Model import torch checkpoint = 'gpt2' tokenizer = GPT2Tokenizer.from_pretrained(checkpoint) model = GPT2Model.from_pretrained(checkpoint) num_added_tokens = tokenizer.add_special_tokens({'pad_token': '[CLS]'}) embedding_layer = model.resize_token_embeddings(len(tokenizer)) # 按新词表大小更新模型嵌入层 input_string = 'Architecturally, the school has a Catholic character.' token_ids = tokenizer(input_string, truncation = True, padding=True) output = model(torch.tensor(token_ids['input_ids']))
可行方案
方案1:自定义约束损失项
在原有自回归语言模型损失的基础上,新增一个计数惩罚损失:
- 生成全过程统计每个指定token的实际出现次数
- 生成结束后,对比实际出现次数和要求的次数,差值越大惩罚值越高
- 把惩罚项按合适权重加到原损失上做反向传播,引导模型提升指定token的生成概率
注意权重需要调试:权重过高会破坏生成内容的语义流畅度,权重过低达不到强制约束的效果。
方案2:解码阶段加硬约束(鲁棒性更强,无需重训)
不需要修改模型训练逻辑,直接在解码环节(贪心、波束搜索、核采样都适用)加规则控制,是落地更常用的方案:
- 初始化阶段先记录每个指定token要求出现的总次数
- 每生成一个token,就更新剩余待生成的指定token计数、剩余可生成的最大token长度
- 当剩余可生成长度刚好等于还没凑够的指定token总数时,直接把后续步的候选token范围限定为待生成的指定token,禁止选择其他token
- 常规生成阶段,可以给指定token对应的logits加一个固定偏置,适当提升它被采样到的概率,不会过度破坏生成内容的自然度。
不建议直接套用BERT式固定掩码填充的方案:GPT2是从左到右的自回归生成模型,和BERT的双向预训练目标不匹配,硬套固定位置掩码不仅适配不了可变长度生成需求,还很容易生成语义不通的内容。
内容的提问来源于stack exchange,提问作者Penguin
相关产品推荐
相关产品推荐

