1289 字
6 分钟
大模型词表

引言#

在文本输入 embedding 层之前,以中文文本为例,首先对文本进行分词并进行 one-hot 编码,分词肯定是根据词表来进行分词,那构建一个合适的词表就显得至关重要,过大或者过小都会对后续模型的训练效果产生影响。所以这里介绍当前各个大模型的词表构建方法。

基础#

我们首先了解一下什么是分词器 (Tokenizer),简单来说就是把字符序列转换为数字序列,对应模型的输入,一般有三种粒度/char/subword

  • word: 按照词进行分词,如 today is Tuesday, 那么分为三个词.词表大,稀有词学不好,可能超出表外,无法理解单词形态关系和词缀,比如 cat 和 cats
  • char: 没什么好说的,词表小,对于中文比较合理,但是英文无法承载丰富语义,序列长度长
  • subword: 把 Today is Tuesday 分为 to day,is,s,un,day,平衡了上述两种方案,是目前大模型的分词方案 目前大模型大部分适用 sentencepiece 库中的 BBPE 分词算法来构建词表。

SentencePiece:SentencePiece 它是谷歌推出的子词开源工具包,它是把一个句子看作一个整体,再拆成片段,而没有保留天然的词语的概念。一般地,它把空格也当作一种特殊字符来处理,再用 BPE 或者 Unigram 算法来构造词汇表。SentencePiece 除了集成了 BPE、ULM 子词算法之外,SentencePiece 还能支持字符和词级别的分词。

如何扩充词表#

在开源大模型中,LLaMA 是 best,但是对中文的支持不太理想,原版的 LLaMA 模型词表为 32K,而多语言模型的词表大小为 250K,这导致了 LLaMA 的 tokenizer 中包含的中文字符少,一个中文字符往往被切分为多个 token 降低编码水平,预训练中也没有出现过或者出现的很少的语言训练的不充分

因此我们需要对 LLaMA 原生的 tokenizer 词表进行扩充.比如在中文语料库上训练一个中文 tokenizer 模型,然后吧中文的 tokenzier 和原生的进行合并,最后的到一个新的 tokenizer 模型

词表的特殊标记#

这里我们使用库 SentencePiece 库来进行实现

self.sp_model = SentencePieceProcessor(model_file=model_path)
# BOS / EOS token IDs
self.n_words: int = self.sp_model.vocab_size()  # 这里是一些基本信息,比如词表大小
self.bos_id: int = self.sp_model.bos_id()  # bos开始id
self.eos_id: int = self.sp_model.eos_id()  # 结束id
self.pad_id: int = self.sp_model.pad_id()  # 填充符id
<SOS>,<BOS>,<GO>一个序列的开始
<EOS>序列的结束
<MASK>遮盖一些单词
<UNK>未知单词
<SEP>分割两个数据句子
<CLS>放在句子首位,表示句子开始,就是 classification 的意思
<PAD>补全字符,比如要把句子扩充到特定的长度就需要补<PAD>

Embedding#

我们来看 embedding 的参数: nn.Embedding(num_embeddings,embedding_dim)

其中 num_embedding 是词典大小,比如训练的时候的词有 5k 个,那么就等于 5k,儿 embedding_dim 是嵌入向量的维度,也就是多少来表示一个符号。

首先来看 one_hot,one_hot 使用一个长度为 5 的 01 向量来表示 我是中国人,这样的方法很简单,但是词典的字多的时候会导致稀疏性,不便于计算,而且无法处理原来的序列信息,==比如“我是人”这句话中,“我”和“人”的距离与“我”和“是”的距离一样,==这显然是不合理的。

embedding 就是为了解决这个问题。首先我们准备一本字典,把句子中的每个词映射到更低维度上去。对 5k 字的字典,one-hot 需要 5k 长度的 vector,儿 embedding 只需要指定一个 embedding_dim,这个 dim 可以小于 5k。也就是对于一句话来说,本来我们需要 (length,5k) 的矩阵,现在我们只需要 (length,dim) 的矩阵就可以了

也就是说,当整个输入数据 X 只有一句话时 X(1, max_length, num_embeddings) 字典为(num_embeddings, embedding_dim) 则经过翻译之后,这句话变成(1,max_length,embedding_dim)

因果语言模型和序列到序列模型的区别#

seq2seq的模型专指 encoder-decoder 架构,一定有一个编码过程,典型任务比如机器翻译和图像生成文字,因为这俩任务都需要一个 encoder 来处理输入把他处理为一个序列。因为 seq2seq 的建模下,输入输出的数据并不在一个空间里面,因此 encoder 是需要的. 而casual LM中,有人说中文和英文也可以都健在一个空间里面,比如都建模在世界文本数据集上,只需要使用合适的 prompt 就可以比如“translate chinese to english:…”这个模型就会帮你翻译。这个 idea 在 gpt2 中被提出,关键是建模方法的不同,大模型通常才用 decoder-only 的方法。现在一般来说,decoder-only自回归因果语言模型这三个词基本上是等价的。一句话来说:根据之前的序列,生成后续的序列。

大模型词表
https://fuwari.vercel.app/posts/machinelearning/nlp/大模型词表/
作者
FlyingWhite
发布于
2024-10-22
许可协议
CC BY-NC-SA 4.0