大语言模型中一个调皮的EOS token

背景

最近需要做一个微调的培训,所以不可避免地需要上手一下相关的微调,而受限于机器资源,暂时没法做全参数微调,所以就尝试了目前比较火的两种高效微调方式,分别是PTuning和LoRA。模型选择得自然是现在中文做的比较好的ChatGLM2-6B。

微调的代码分别用的是

PTuning

LoRA

在分别尝试了两个结果后,发现LoRA微调出来的结果有点抽风,喜欢疯狂输出,而它就是咱们今天的主角:ChatGLM2-6B的Tokenizer所使用的EOS(end-of-sequence) token。

EOS token 介绍

其实从名字就可以看出来,EOS的作用就是标记一个序列的结束,这样模型就可以知道这个序列已经结束了,不需要再继续输出了。 如果以为例,一般模型在推理的时候,觉得可以结束一句话了,就会输出,但是模型的脑子里肯定没有的概念呀,它只能输出数字,所以我们需要把转换成数字,这个数字就是EOS token ID。在ChatGLM2-6B的Tokenizer中,EOS token ID是2,而模型输出的时候,输出的也是2,而不是

分析BUG

既然模型会输出文字版的,那是不是模型的输入中,给它喂进去了不合适的语料呢?

进一步查找发现所使用的LoRA库中是这么添加EOS的:

medicalGPT

尝试一下直接用喂给tokenizer,看看tokenizer会怎么处理。

tokenize_s

看到这原因的就很明显了,因为这个EOS添加的是字符,而不是token_id,所以tokenizer有时候会把当成了分开的token,比如</和s和>,模型就把这3它当成了三个token,而不是一个token,所以在推理的时候,遇到结尾,有时候就会输出</+s+>。而transformers的库在推理看一个句子是否以EOS结尾,看的是token_id而不是token。就会认为生成还没有结束,就继续生成了,直到某一次推理,模型想起来预训练时的记忆,在遇到结尾的时候输出了2的token id(也就是),transformers库才会认为生成结束,停止生成。

transformers

既然知道了问题的原因,那么就需要解决这个问题,解决的方法也很简单,就是把EOS token_id添加到输入中,而不是字符。具体代码就是按照PTuning的方式,把EOS token_id添加到输入中。

refactor

改完之后重新train一遍LoRA,模型不再疯狂输出了。

尾声

要改这个bug,其实需要挺多tokenization的知识的,最近没有时间好好研究,之后有时间再来补充一下。

相关推荐
织码weavecodes1 小时前
织码在线教育系统--主观题 AI 智能阅卷:批量初评与教师复核如何协同
人工智能
Shockang7 小时前
llama.cpp 本地运行 9B 模型:部署、工具调用与微调数据
人工智能
Shockang7 小时前
n8n 智能体工作流实战:触发、工具、记忆与发布护栏
人工智能
冬奇Lab9 小时前
开源项目第241期:YuE2 —— 用符号乐谱当“白盒“接口的开源音乐生成模型,SongBench 超越 Suno v5/v6
人工智能
鶴哥只手遮天10 小时前
Spring AI 2.0.1 深度解析-第 14 章 MCP 服务端(上):注解式实现与工具来源
java·人工智能·开源
鶴哥只手遮天10 小时前
Spring AI 2.0.1 深度解析-第 15 章 MCP 服务端(下):三种协议形态、Streamable 传输与状态管理
java·人工智能·开源
鶴哥只手遮天10 小时前
Spring AI 2.0.1 深度解析-第 16 章 向量存储(上):`VectorStore` 接口体系、`BatchingStrategy`
java·人工智能·开源
鶴哥只手遮天10 小时前
Spring AI 2.0.1 深度解析-第 12 章 工具循环的流式形态、Usage 累加与扩展体系
java·人工智能·开源
鶴哥只手遮天10 小时前
Spring AI 2.0.1 深度解析-第 23 章 模型供应商实现:从 `OpenAiSetup` 到 Bedrock
java·人工智能·开源