1. 引言
前文封装的模型评测脚本evaluate.py在使用时一直有一个问题,每次评估耗时很长,如下所示,两千条数据需要将近20分钟。
progress: 100%|██████████| 2348/2348 [19:12<00:00, 2.04it/s]
但是根据模型训练时的batch_size设置,模型是支持批量预测的,所以我们有必要根据此特性对评测脚本做一次改造,以支持批量预测,提高每次评测的效率。
2. 初始化
%run evaluate.py
testdata_path = '/data2/anti_fraud/dataset/eval0819.jsonl'
model_path = '/data2/anti_fraud/models/modelscope/hub/Qwen/Qwen2-1___5B-Instruct'
checkpoint_path = '/data2/anti_fraud/models/Qwen2-1___5B-Instruct_ft_0826/checkpoint-900'
device = 'cuda'
加载模型:
model, tokenizer = load_model(model_path, checkpoint_path, device)
加载数据集,并构造用于测试的小批量数据(8条)。
dataset = load_jsonl(testdata_path)
batch_data = dataset[0: 8]
contents = [item['input'] for item in batch_data]
3. 调试可行性
封装一个方法用于构造提示词。
def build_prompt(content):
prompt = f"下面是一段对话文本, 请分析对话内容是否有诈骗风险,只以json格式输出你的判断结果(is_fraud: true/false)。\n\n{
content}"
return [{
"role": "user", "content": prompt}]
按照模型要求的格式将提示词应用到模板,主要是添加特殊token。
注:单条使用apply_chat_template时直接指定了
tokenize=True
和return_tensors="pt"
参数完成了序列化和张量转换。但批量时则需要使用tokenizer来进行序列化,内部会做一些针对批量的特殊处理(例如填充长度),因此不能指定这两个参数。
prompts = [build_prompt(content) for content in contents]
tokenized = tokenizer.apply_chat_template(prompts, add_generation_prompt=True, tokenize=False)
print(f"apply_chat_complete:{
type(tokenized)}, len: {
len(tokenized)}, tokenized[0]:{
tokenized[0]}")
apply_chat_complete:<class 'list'>, len: 8, tokenized[0]:<|im_start|>system
You are a helpful assistant.<|im_end|>
<|im_start|>user
下面是一段对话文本, 请分析对话内容是否有诈骗风险,只以json格式输出你的判断结果(is_fraud: true/false)。
发言人3: 如果投资一个亿就能回收,并且后面全全都是他的那个效益。<|im_end|>
<|im_start|>assistant
可以看到,应用模板后的提示词,每个角色的内容都由特殊token
<|im_start|>
和<|im_end|>
包裹,最后的<|im_start|>assistant
就是在提示模型在此之后生成和补全序列。
将应用模板后的提示词序列化为数字化的token,return_tensors="pt"表示返回pytorch类型的张量(torch.Tensor)。
inputs = tokenizer(tokenized, padding=True, return_tensors="pt").to(device)
print