Datawhale 大模型基础与量化微调 task0:Tokenizer
此博客为Datawhale 组队学习打卡笔记
分词技术
基于规制与词典
假设一个分词路径由一个词语序列组成,将其表示为 w 1 , w 2 , . . . , w n w_1, w_2, ..., w_n w1,w2,...,wn,其中 w i w_i wi 代表序列中的第 i 个词。那么这条路径的概率可以近似为:
P ( w 1 , w 2 , . . . , w n ) ≈ P ( w 1 ) × P ( w 2 ) × . . . × P ( w n ) P(w_1, w_2, ..., w_n) \approx P(w_1) \times P(w_2) \times ... \times P(w_n) P(w1,w2,...,wn)≈P(w1)×P(w2)×...×P(wn)
其中,每个词 w i w_i wi 的概率 P ( w i ) P(w_i) P(wi) 可以通过其在词典(语料库)中的频率来估算:
P ( w i ) = 词 w i 的词频 词典中所有词的总词频 P(w_i) = \frac{\text{词 } w_i \text{ 的词频}}{\text{词典中所有词的总词频}} P(wi)=词典中所有词的总词频词 wi 的词频
jieba的目标就是找到一条路径,使得这个累乘的概率值最大。
python
import jieba
# 未加载词典前的错误分词
text = "九头虫让奔波儿灞把唐僧师徒除掉"
print(f"精准模式: {jieba.lcut(text, cut_all=False)}")
# 加载自定义词典
jieba.load_userdict("./user_dict.txt")
print(f"加载词典后: {jieba.lcut(text, cut_all=False)}")
text
九头虫
奔波儿灞
精准模式: ['九头', '虫', '让', '奔波', '儿', '灞', '把', '唐僧', '师徒', '除掉']
加载词典后: ['九头虫', '让', '奔波儿灞', '把', '唐僧', '师徒', '除掉']
统计学习时代的方法
为了解决对人工词典的过度依赖, jieba 就利用了HMM来识别词典中不存在的 OOV
python
text = "我在Boss直聘找工作"
# 开启HMM(默认)
seg_list_hmm = jieba.lcut(text, HMM=True)
print(f"HMM开启: {seg_list_hmm}")
# 关闭HMM
seg_list_no_hmm = jieba.lcut(text, HMM=False)
print(f"HMM关闭: {seg_list_no_hmm}")
bash
HMM开启: ['我', '在', 'Boss', '直聘', '找', '工作']
HMM关闭: ['我', '在', 'Boss', '直', '聘', '找', '工作']
在这个例子中,当HMM开启时,__cut_DAG 方法将动态规划产生的 ['直', '聘'] 序列在缓冲区内拼接成 "直聘",然后交由HMM模型(finalseg.cut)处理,最终HMM通过其学到的统计规律,"猜"出这两个字是一个完整的词语,从而弥补了词典法的不足。
词性标注
除了分词,jieba 还提供了词性标注功能
在词典中设置词频和词性
text
九 10000000 n
头 1000000 n
奔波儿灞 nr
从"分词"到"分块"
字粒度分词(Character-level): BERT 在处理中文时,直接将每个汉字视为一个独立的Token。有效解决了 OOV 问题, 但丢失词汇语义,输入序列更长。
子词分词(Subword):(当前标准方案)
- GPT 采用 BPE算法,在原始的字符语料库上,迭代地将高频的相邻字节对(或字符对)合并成一个新的、更大的单元,并将其加入词表。
- 例如,对于语料中频繁出现的 "deeper",BPE可能会先学习到 "er",然后是 "deep",最终可能将 "deeper" 作为一个整体或"deep"+"er" 的组合加入词表。
- 基于统计频率,语言学可解释性不强;对训练语料的强依赖性
词向量表示
离散表示
独热编码(One-Hot Encoding)
词袋模型(Bag-of-Words, BoW)
- 表示整个句子或文档, 可以理解为:将文档中所有词的独热向量相加,得到一个最终的向量。这个向量的维度等于词典大小,每一维的值代表了对应词语在文档中的出现频次。
- 通过计算两个向量的距离, 可判断文档相似性
- 丢失词序;未考虑词的重要性:像"的"、"是"这类在所有文档中都频繁出现的停用词,会获得很高的频次,但它们对区分文档主题几乎没有贡献,反而会形成干扰
词袋模型向量中每一维的值,可以根据不同策略来确定:
- 频数: 直接使用单词在文档中出现的次数。这是最简单直接的方式,但会受到文章长度影响,长文章的计数值会普遍偏高。
- 频率: 使用单词在文档中出现的次数除以文档的总词数,即词频(TF)。这在一定程度上缓解了文档长度不同带来的问题。
- 二进制 : 只关心单词是否出现,出现即为
1,不出现为0,不关心出现的次数。
N-gram 模型
通过统计连续词组的方式弥补词序信息丢失,但是组合指数级爆炸,数据稀疏绝大多数词的组合(如"大象 驾驶 飞机")在语料中永远不会出现
常见的 N-gram 模型包括:
- Unigram (1-gram): 即词袋模型。假设每个词都是独立的,完全不看前面。
- Bigram (2-gram) : 只看前 1 个词。例如看到"喜欢",预测下一个词是"玩"的概率。
- Trigram (3-gram) : 看前 2 个词。例如看到"喜欢 玩",预测下一个词是"GTA6"的概率。
TF-IDF
- 提升文档在向量空间中的区分度,解决"常见词权重过高"导致文档混淆的问题
- 一个词的重要性,与其在当前文档中出现的次数 成正比,与其在整个语料库中出现的频率成反比。一个词在当前文档里越常见,但在其他文档里越罕见,其权重就越高。
序号化表示
只把文本转换成最基础的整数 ID 序列 ,然后把"学习词语的含义和重要性"这个更复杂的任务,交给模型自己去完成。
从主题模型到 Word2Vec
分布式表示(Distributed Representation) :将词语映射到一个低维、稠密、且蕴含丰富语义信息的连续向量空间中
主题模型
- 通过SVD 矩阵分解,将词降维聚类到K个主题维度
- 计算代价高昂:对一个大型语料库进行SVD分解,计算量和内存开销都极大
- 依赖全局统计
Word2Vec
- 语言学中的分布式假设,即一个词的含义,由其上下文中的词语所决定
- 如果两个词的上下文经常是相似的,那么这两个词的语义就是相近的
- 最终目标:获取一个高质量的 词向量查询表。这本质上是一个巨大的矩阵 W i n W_{in} Win, 矩阵的每一行就是对应单词的稠密向量。
- Word2Vec 包含 CBOW 和 Skip-gram 两种具体的实现模型。
CBOW 模型: 根据上下文预测中心词
Skip-gram 模型: 根据中心词预测上下文
Word2Vec的局限性
- 上下文无关; 无法解决一词多义;
- 静态词向量, 训练完成后,这个表就固定下来了
参考
1\] [https://datawhalechina.github.io/base-llm](https://datawhalechina.github.io/base-llm/#/)