说到 OpenAI发布的 GPT-4o,个人总结有两大亮点:一个是多模态统一,另一个是快。
GPT-4o 能够更快的原因可能有很多,比如
模型参数量减少了
OpenAI的Infra更强了
文本的分词效率提高了
等等
在模型参数量上一如既往还是个谜;Infra更强是有可能的(发布会上Mira Murati有向Nvidia的Nvidia CEO Jensen Huang致谢);分词效率提高在OpenAI的博客上( https://openai.com/index/hello-gpt-4o/)特别强调了一波Language tokenization。
博客中还贴了一张在20种语言上的分词效率提升,其中一个例子是在中文上原来需要34个token才可以表示的两句话,现在只需要24个token就可以表示。这也表明了相比于之前的模型,生成相同的一段文本,需要进行推理的次数能够大幅度减少(大模型推理是逐个token推理的),推理次数少了那自然就更快了。
Q1: 什么是分词,什么是token
分词(Tokenization)是将原始文本分解为更小的单元(即词元,Token)的过程。分词策略有很多,不同策略得到的词元可以是一个词、一个子词,甚至是单个字符。在LLM中,每个词元会被映射到一个唯一的数字ID,然后才能交给模型运算。
举个例子,下面这句话
"你好,我的名字是GPT-4o"
通过GPT-4o的分词器转化词元为
[177519, 40824, 1616, 103582, 3221, 162016, 12, 19, 78]
然后ID序列再送入模型中转为embedding,然后交给transformer。
Q2: 那如何得到分词器?有什么分词策略
从中文的角度,按照“词”的概念,一个词语当作一个词元就是word level分词策略
比如
我爱自然语言处理
分词完得到三个token(假设“自然语言处理”是一个词语)
['我', '爱', '自然语言处理']
不过以“词语”作为词元存在的问题是对于一些新词、专有名词之类的效果不好。
中文里的词、句都是由“字”组成的,那就用“字”的概念来分词是不是可以避免前面提到的处理不好新词、专有名词的问题?这就是Char Level分词策略,还是上面那句话,分词完得到八个token
['我', '爱', '自', '然', '语', '言', '处', '理']
这样分词的问题在于生成的token序列较长,计算开销大;而且语义信息较为分散,不利于捕捉高层次语义(原来一些短语之类的拆成字后丧失了原来的意思)。
为了缓解前面两种方法的问题,一个想法是尽量保留高频词,对低频词进行切分,这样就能得到一个粒度适中且有一定泛化性的词表了。这也是目前的主流方法:Subword Level分词策略。比如前面那句话可能(subworld level中的不同方法、不同参数、不同语料得到的分词器也不一样)的分词结果为
['我', '爱', '自然', '语言', '处理']
Q3: 现在各家大模型的分词器都是用的什么方法
这里从各家大模型的抱抱脸或者代码仓库里截取了他们关于分词器的相关声明
- The LLaMA tokenizer is a BPE model based on sentencepiece.
- Construct a ChatGLM tokenizer. Based on byte-level Byte-Pair-Encoding.
- Qwen-7B uses BPE tokenization on UTF-8 bytes using the tiktoken package.
- Construct a BaiChuan tokenizer. Based on byte-level Byte-Pair-Encoding.
- Construct a InternLM2 tokenizer. Based on byte-level Byte-Pair-Encoding.
- Construct a Gemma tokenizer. Based on byte-level Byte-Pair-Encoding.
- llama3 Tokenizing and encoding/decoding text using the Tiktoken tokenizer.
- Mistral-7B Byte-fallback BPE tokenizer - ensures that characters are never mapped to out of vocabulary tokens.
- Phi Construct a CodeGen tokenizer. Based on byte-level Byte-Pair-Encoding.
- HunYuanTokenizer ByteLevelBPETokenizer
有几个结论
清一色的byte-level BPE
主流的三种分词器训练框架:抱抱脸的tokenizers、openai的tiktoken和谷歌的sentencepiece
llama1-2使用谷歌的sentencepiece,llama3使用Tiktoken
Q4: byte-level BPE和之前提到的方法有什么关系
目前subword level 的tokenizer 方法主要有BPE, WordPiece, Unigram, SentencePiece等
byte-level BPE是BPE的改进
原始BPE的局限性
BPE的结果依赖于输入文本的词汇分布。在不同的文本数据集上训练出的BPE模型可能差异较大。
对于使用非拉丁字母的语言,如中文、日语、韩语等,BPE需要先进行特定的字符处理,否则效果不佳。
BPE有时会生成一些语义上不连贯的子词单位,这可能对下游任务产生负面影响。
Byte-Level BPE 的核心改进在于它将文本数据先转化为字节序列(而非字符序列):
它基于字节而不是字符进行编码,可以更好地处理多语言文本和符号。
因为字节是所有文本文件共有的表示方式,Byte-Level BPE 因此更为语言中立,可以跨语言使用。
由于它减少了对特定语言字符的依赖,因此在处理未见过的字符或新语言时更为稳定。
总的来说,Byte-Level BPE通过使用字节而非字符,使得模型能够无缝处理多语言文本和非标准字符,从而增强了模型的通用性和灵活性。
Q5: 可以讲讲BPE的具体做法吗
BPE本质上是一个迭代合并的过程,这里是一个简易版的流程用于展示思路
Step1. 将语料中每个字符视为一个单独的token
Step2. 统计所有相邻token对的出现频率
Step3. 选择出现频率最高的token对合并为一个新token
Step4. 重复步骤2和3,直到达到预设的token总数或者无法继续合并
举个例子,假如训练语料如下
我爱北京天安门,天安门上太阳升。
第一轮:
词表:['我','爱','北','京','天','安','门',',','上','太','阳','升','。']
token对出现频率: ('天','安'): 2 ('安','门'): 2 ('北','京'): 1 ('京','天'): 1 ('门',','): 1 (',','天'): 1 ('上','太'): 1 ('太','阳'): 1 ('阳','升'): 1 ('升','。'): 1
选择('天','安')合并为'天安',得到新的词表: ['我','爱','北','京','天安','门',',','上','太','阳','升','。']
第二轮:
词表:['我','爱','北','京','天安','门',',','上','太','阳','升','。']
token对出现频率: ('天安','门'): 2 ('北','京'): 1
('京','天安'): 1 ('门',','): 1 (',','天安'): 1 ('上','太'): 1 ('太','阳'): 1 ('阳','升'): 1 ('升','。'): 1
选择('天安','门')合并为'天安门',得到新的词表: ['我','爱','北','京','天安门',',','上','太','阳','升','。']
以此类推。
更进一步,Byte-Level BPE就是把文本先转为bytes,再执行上面操作。对细节和算法的优化感兴趣的同学可以参考下面代码仓库
https://github.com/openai/tiktoken
https://github.com/karpathy/minbpe
Q6: 回到GPT-4o,它的分词器对中文的压缩能力更强体现在哪里
openai的分词器在tiktoken是开源的,我们可以看一下4和4o在词表大小的差距
enc_4o = tiktoken.encoding_for_model("gpt-4o")
enc_4 = tiktoken.encoding_for_model("gpt-4")
print(enc_4o.n_vocab)
print(enc_4.n_vocab)
结果是
200019
100277
词表大小差不多是之前的两倍。
再看一下词表中包含中文字符的token数
token_dict_4o = get_chinese_token(enc_4o)
token_dict_4 = get_chinese_token(enc_4)
values1 = set(token_dict_4o.values())
values2 = set(token_dict_4.values())
intersection = values1 & values2
print(len(token_dict_4o), len(token_dict_4), len(intersection))
可以发现包含中文的token数从原来的800+直接提高到了7000+
7563 868 827
随便找段文本编码一下试试
text = """
腾讯控股5月14日发布2024年第一季度财报,受益于新芽业务快速成长和传统业务聚焦提效,腾讯2024年开局保持高质量增长,毛利劲增23%。
财报显示,2024年第一季度腾讯实现营收1595.01亿元,毛利838.7亿元,经营利润586.19亿元,净利润502.65亿元,毛利、经营利润以及净利润增速均持续跑赢收入增速,盈利质量显著提升。
重点业务板块上,腾讯的广告、企业服务等核心业务找到新打法,视频号、小程序、SaaS等新芽业务集体爆发新能量,共同驱动了业绩增长。一季度腾讯已累计回购达到148亿港元,日均回购金额达8.24亿港元,创历史新高。
腾讯董事会主席兼首席执行官马化腾表示,一季度公司在本土市场和国际市场的数款头部游戏中的团队调整初见成效,游戏总流水实现增长,为未来几个季度游戏收入恢复增长打下基础。公司持续培育高质量的收入来源,包括微信视频号及搜一搜广告、小游戏平台服务费及视频号商家技术服务费,推动了公司毛利和经营盈利增幅超过收入增幅。公司致力于将盈余资本回馈股东,加大回购力度,按计划执行2024年超千亿港元的股份回购,提升股息,同时致力于持续投资于AI技术、提升平台及生产高价值内容。
"""
print(len(enc_4o.encode(text)))
print(len(enc_4.encode(text)))
可以看到原来需要562个token才可以表示这段话,现在只要348个token就可以搞定了,效率确实是显著提高。
348
562
Q7: GPT-4o的中文词表扩了这么多,是好事还是坏事
从速度提升的角度来说是好事,但在一些场景下不一定是好事。
旧版词表按字符串长度降序的前50个token,看着还算正常
[' 生命周期函数', ' 自动生成', ' 生命周期', '微软雅黑', '监听页面', '不能为空', ' 初始化', '無しさん', '删除成功', '管理员', '验证码', ' 删除', '��态', '命周期', ' 参数', '字符串', '用户名', ' 用户', '��加', '手机号', '请输入', '�始化', ' 设置', '初始化', ' 默认', '动生成', '無し�', '软雅黑', ' 是否', ' 数据', ' 若要', ' 返回', ' 更新', '设计器', ' 输入', ' 添加', ' 时间', ' 输出', '不存在', ' 页面', '��取', '��作', '��索', ' 下午', ',默认', ' 如果', ' 修改', '数据库', ' 示例', ' 使用']
再看看新版大词表的前50个token(手动删了几个比较露骨的token),惊!怎么一堆彩票、黄色相关的词?
[' 微信公众号天天中彩票', ' 微信上的天天中彩票', ' 微信里的天天中彩票', ' 天天中彩票大神推荐', 'VIPがお送りします', '给主人留下些什么吧', '无码不卡高清免费v', ' 大发快三开奖结果', ' 天天中彩票一等奖', ' 天天中彩票APP', ' 天天中彩票nba', ' 大发快三大小单双', '大发展有限公司官网', ' 天天中彩票公众号', ' 天天中彩票不中返', ' 天天爱彩票app', ' 天天中彩票双色球', ' 彩神争霸官方下载', ' 中国福利彩票天天', ' 手机版天天中彩票', ' 天天中彩票app', ' 全民彩票天天送钱', ' 手机上天天中彩票', ' 天天中彩票中奖了', ' 天天彩票与你同行', ' 彩神争霸大发快三', '久久免费热在线精品', ' 天天中彩票怎么买', ' 天天中彩票中大奖', ' 天天中彩票是不是', ',最新高清无码专区', ' 天天中彩票为什么', ' qq的天天中彩票', ' 微信的天天中彩票', ' 天天中彩票不能买', ' 天天中彩票官网', ' 大发快三是不是', ' 天天中彩票篮球', '无码一区二区三区', ' 彩神争霸电脑版', ' 天天中彩票不能', ' 彩神争霸大发快', ' 天天中彩票在哪', ' 天天中彩票中了', '精品一区二区三区', ' 海南天天中彩票', ' 天天大奖彩票站', ' 天天中彩票软件']
看来这一波词表的扩充,openai提高了数量但却忽略了质量,其他语种什么情况感兴趣的同学可以自行验证下看看。
Q8: 低质量的token会带来什么问题
我们直接来看看如果给模型输入中存在一些没经过充分训练的低质量token会有什么问题
GPT-4o的回复
GPT4-的回复
可以看到GPT-4o是一个胡说八道的状态,GPT-4则是正常的。原因是“给主人留下些什么吧”在GPT-4o中是一个独立的token,但是却没有得到充分的训练。 感兴趣的同学可以自己再尝试其他情况看看。
Q9: 词表这么脏的原因是什么
最直接的原因就是用于训练分词器的中文语料没有经过较好的清洗,混杂了大量黄色、赌博方面的数据。
不过训练阶段的数据感觉总应该清洗过了吧?但是当我再用了几个奇奇怪怪的token去问模型时,很尴尬地发现训练数据中应该也还是混了一些奇奇怪怪的脏数据的。
不过大多数情况由于训练LLM后续的安全防护还是能兜住的。
Q10: 有什么补救措施吗
一个直接但不保证效果的做法是直接把这个脏token在词典中剔除掉,举个例子
我把“给主人留下些什么吧”这个token在字典中删掉,然后创建一个新的encoder,再用它来编码
del enc_4o._mergeable_ranks[b'\xe7\xbb\x99\xe4\xb8\xbb\xe4\xba\xba\xe7\x95\x99\xe4\xb8\x8b\xe4\xba\x9b\xe4\xbb\x80\xe4\xb9\x88\xe5\x90\xa7']
my_enc = tiktoken.Encoding(name="custom",
pat_str=r"""'s|'t|'re|'ve|'m|'ll|'d| ?[a-z]+| ?[0-9]+| ?[^\s]+| ?\s+""",
mergeable_ranks=enc_4o._mergeable_ranks,
special_tokens={})
my_enc.encode("给主人留下些什么吧")
得到这句话新的表示,由两个token组成
[176738, 140893]
这两个ID对应的是'给主人'和'留下些什么吧',其实还是有点不常见的词语,可以再进一步清洗。
这样简单粗暴地删词表中的token在很多时候可能会出问题的,更加“标准”点的做法还是应该清洗合适的语料、确定合适的词表大小、验证词表质量,再用来训练LLM。
最后有什么想法
GPT-4o确实很强,但在OpenAI没对词表做一些更新之前应该还是要视场景混用GPT-4和4o吧。
另外,用着脏数据训练都能搞出性能这么强的模型,国内大模型和OAI的差距到底在哪?话筒留给大家。
参考资料&扩展阅读
https://openai.com/index/hello-gpt-4o/
https://huggingface.co/docs/transformers/tokenizer_summary
https://huggingface.co/learn/nlp-course/en/chapter6/5?fw=pt
https://arxiv.org/abs/1909.03341
https://arxiv.org/pdf/1508.07909v5
https://leimao.github.io/blog/Byte-Pair-Encoding/
https://github.com/openai/tiktoken
https://github.com/karpathy/minbpe
https://docs.mistral.ai/guides/tokenization/
https://github.com/ymcui/Chinese-LLaMA-Alpaca/blob/main/scripts/merge_tokenizer/merge_tokenizers.py
https://github.com/QwenLM/Qwen/blob/main/tokenization_note.md
关于LitGate
大家好,我是LitGate,一个专注于AI创作的游戏社区。我们的新版官网已经上线✨你可以在里面找到各种AI创作的实操案例,以及已经沉淀的AI游戏创意demo,相信一定能让你大开眼界!
我们还有一个讨论群📣,如果你对AI创作感兴趣,或者有什么问题想要咨询,欢迎加入我们的讨论群,和大家一起交流学习!(PS:目前群内人数较多,为了有一个优质的讨论环境,请各位添加社区管理员企业微信账号邀请入群
更多精彩活动和功能筹备上线中,敬请期待~
关注我们,一起探索AI创作的无限可能吧!
新版官网地址:www.litgate.ai