本文是基于b站费曼学徒冬瓜老师视频,结合自己问AI的思考,的笔记。
词袋模型
考虑词语在句子里面的出现频率(考虑句子长度,term frequency),词语在所有文档中的出现次数(稀有性inverse document frequency)
word2vec
然后word2vec, 考虑同义词语应该有类似的上下文,并且开始向量表示。
CBOW
word2vec中有方法CBOW,Continuous Bag of Words,最大化在给定上下文 $C$ 的条件下,中心词 $w_c$ 的概率 $P(w_c | C)$。$$P(w_c | C) = \frac{\exp(v_{w_c}^T \cdot h)}{\sum_{w’ \in V} \exp(v_{w’}^T \cdot h)}$$其中 $h$ 是上下文词向量的平均或者和(在 Skip-gram 中 $h$ 就是中心词 $w_c$ 的输入词向量), $v_{w_c}$ 是输出词向量。$v_{w_c}$: 输出词向量 (Output Vector) for $w_c$,在标准的 Word2Vec 模型中,这个向量是词汇表矩阵 $\mathbf{W}’$(隐藏层到输出层)中对应 $w_c$ 的行向量。$V$: 整个词汇表 (Vocabulary)。所有训练文本中出现过的、模型要处理的唯一词汇的集合。
分母需要对整个词汇表 $V$ (通常是数万到数十万) 进行求和,优化时计算梯度非常慢。可以使用层次Softmax,改写对中心词的表示。这里利用目前词表中所有词的词频来构建一个哈夫曼树(Huffman Tree),构建一次,全程使用。
负采样
word2vec也有负采样,将多分类转化为一系列二分类问题,用 $\text{sigmoid}$ 函数替代 Softmax,极大地提高了训练速度,是 Word2Vec 最常用的实现方式。
具体形式:正样本: 窗口内的中心词 $w_c$ 和上下文 $C$ 构成一个正样本对 $\langle C, w_c \rangle$。负样本: 从词汇表 $V$ 中随机抽取 $k$ 个与 $w_c$ 不在同一窗口的词 $w_k$,构成 $k$ 个负样本对 $\langle C, w_k \rangle$。模型的优化目标是:最大化中心词 $w_c$ 的概率,同时最小化负样本 $w_k$ 的概率。损失函数(二元交叉熵形式):$$\text{L} = - \left[ \log \sigma (v_{w_c}^T \cdot h) + \sum_{k=1}^K \mathbb{E}{w_k \sim P_n(w)} \left[ \log \sigma (-v{w_k}^T \cdot h) \right] \right]$$其中:$\sigma(x) = 1 / (1 + e^{-x})$ 是 $\text{sigmoid}$ 函数。
$\sum_{k=1}^K \mathbb{E}{w_k \sim P_n(w)} \left[ \log \sigma (-v{w_k}^T \cdot h) \right]$ 代表了负样本项的期望总和。$k=1$ 到 $K$: 表示我们选择了 $K$ 个负样本。$\mathbb{E}_{w_k \sim P_n(w)}$: 期望 (Expectation)。这意味着负样本 $w_k$ 是从一个特定的噪声分布 $P_n(w)$ 中随机采样得到的。$P_n(w)$ 是噪声分布,通常基于词汇在语料库中的频率,但经过调整(例如,使用 $\text{word_freq}^{3/4}$)以增加低频词被选为负样本的几率。在实际训练中,这个期望通常通过蒙特卡洛采样(即直接采样 $K$ 个词 $w_k$)来近似。
GloVe
(Global Vectors for Word Representation)
GloVe 由斯坦福大学在 2014 年提出,结合 Word2Vec 的局部窗口思想和 LSA(Latent Semantic Analysis)的全局矩阵分解思想。
GloVe 认为,词向量应该编码词语的含义,而两个词的语义关系可以通过它们与其他词的共现概率比值来更好地体现。假设我们有两个目标词 $i$ 和 $j$,以及一个探测词 $k$。$P_{ik}$:词语 $i$ 和词语 $k$ 共现的概率。$P_{jk}$:词语 $j$ 和词语 $k$ 共现的概率。$Ratio = \frac{P_{ik}}{P_{jk}}$:这个比值能够区分相关性。
全局共现矩阵(Global Co-occurrence Matrix):首先构建一个巨大的词语-词语共现矩阵,矩阵中的元素 $X_{ij}$ 表示词语 $i$ 和词语 $j$ 在语料库中同时出现的次数。然后,模型通过最小化一个加权平方误差来分解这个矩阵,从而获得词向量。
词向量的点积应该与它们在全局共现矩阵中的对数共现频率成比例$$w_i^T w_j \approx \log(X_{ij})$$
GloVe 的目标是:训练出的词向量的差异(点积)应该能够表示这个共现概率的比值。
GloVe 的损失函数 $\mathcal{L}$ 定义为:$$\mathcal{L} = \sum_{i, j=1}^{V} f\left(X_{i j}\right)\left(w_{i}^{T} \tilde{w}{j}+b{i}+\tilde{b}{j}-\log \left(X{i j}\right)\right)^{2}$$其中:$V$: 词汇表大小。$X_{ij}$: 巨大的词语-词语共现矩阵中,词语 $i$ 和词语 $j$ 在语料库中共现的次数(或频率)。$w_i$ 和 $\tilde{w}j$: 待训练的词向量。GloVe 为每个词 $i$ 训练两个独立的向量:一个作为中心词向量 $w_i$,一个作为上下文词向量 $\tilde{w}j$。最终使用的词向量通常是两者之和或平均。$b_i$ 和 $\tilde{b}j$: 词语 $i$ 和词语 $j$ 的偏置项(Bias Terms)。$\log(X{ij})$: 目标值。模型希望 $w_i^{T} \tilde{w}{j}$ 能够近似 $\log(X{ij})$。$f(X_{ij})$: 权重函数。它是一个非递减函数,旨在降低出现频率极低或出现频率极高的共现对损失的贡献,从而防止模型被噪声或停用词主导。
transformer架构进行词嵌入
transformer模型通过添加注意力层,实现了考虑上下文语意的词嵌入,从而可以用于理解和生成类任务。一般分为encoder decoder层,bert只有encoder(双向注意力),GPT只有decoder(自注意力,不能偷看下文), 需要执行序列2序列任务的(如机器翻译、文本生成、摘要生成等),例如T5,同时有encoder+decoder(decoder接受的输入包含encoder的输出)。
bert
以只有encoder层的bert为例。BERT 的 Transformer 架构是通过训练其内部的 嵌入层 (Embedding Layer) 来获得静态词向量的:嵌入层 ($\text{nn.Embedding}$): 这是一个巨大的查找表,形状是 $(\text{Vocab Size}, \text{Model Dim})$。
一旦有了这个训练好的词嵌入,数据进入 Transformer 架构后,就会由于encoder decoder层的注意力机制发生上下文融合,得到上下文嵌入 (Contextual Embedding),输出张量形状是 $(\text{Batch Size}, \text{SeqLen}, \text{ModelDim})$。
序列分类任务时,只有 [CLS] (classsification)对应的 $\text{SeqLen}_{\text{out}}$ 维度上的输出(即第一个 Token 的输出)直接用于分类。命名实体识别(NER)、词性标注(POS)不止使用CLS,[CLS] 只是 BERT 提供的一个聚合信息的出口。是否使用它,完全取决于你的下游任务需要整个句子的概括还是每个词元的细节。
嵌入层和输出层的权重共享
bert嵌入层的训练:用静态词向量+encoder层的注意力机制 得到的上下文嵌入 来执行预测任务,得到loss之后反向传播。这样可以更新静态词向量的嵌入层,以及注意力层的参数。
Masked Language Model (MLM) 任务的目标是预测被 [MASK] 遮盖的词元。这是一个典型的多分类问题,分类的类别数就是词汇表的大小($\text{Vocab Size}$).
有一个常见的优化技巧是 权重共享 (Weight Sharing):输入嵌入层 ($\mathbf{W}_{\text{embed}}$) 的权重MLM 任务的输出层(用于预测被 $\text{[MASK]}$ 词元的分类器)的权重这两者通常是共享的。
在 PyTorch 的 Autograd 系统中,梯度计算图能够完美地捕捉这种共享关系,并通过 梯度累加 (Gradient Accumulation) 来处理。在一次前向传播和反向传播中,会产生两个独立的梯度流:嵌入路径的梯度 ($\nabla L_{\text{embed}}$):梯度从编码器输入流回 $\mathbf{W}{\text{embed}}$。这是 $\mathbf{W}{\text{embed}}$ 作为查找表对损失的贡献。输出路径的梯度 ($\nabla L_{\text{output}}$):梯度从 MLM 损失 流入 $\mathbf{W}{\text{output}}$(如果共享,则流入 $\mathbf{W}{\text{embed}}^T$)。这是 $\mathbf{W}{\text{output}}$ 作为分类器对损失的贡献。当这两个独立的梯度流在反向传播过程中都到达共享的底层参数 $\mathbf{W}{\text{embed}}$ 时,Autograd 系统不会覆盖任何一个梯度,而是会将它们加起来。
GPT
对于只有decoder的GPT,也需要有静态词向量和注意力层的权重的训练过程,训练好了之后才开始evaluate。这个过程就是pretrain。
seq2seq模型,交叉注意力
如果是既有encoder又有decoder的seq2seq模型,例如英译中模型:编码器词嵌入负责将英文单词(或子词)ID 转换成向量,解码器词嵌入负责将中文单词(或子词)ID 转换成向量;由于两种语言通常使用不同的词汇表(不同的字符集、不同的分词方式),它们的查找表矩阵 ($\mathbf{W}_{\text{embed}}$) 是独立的,并且行数($\text{Vocab Size}$)也可能不同。
在统一模型或相同语言任务中,例如 T5(Text-to-Text Transfer Transformer),它将所有 NLP 任务都转换为 Seq2Seq 格式。在 T5 中,源和目标通常是同一种语言(例如,文本摘要:输入和输出都是英文),此时可以共享这个巨大的嵌入矩阵,从而大幅减少模型的参数量。
连接decoder和encoder的是交叉注意力层(而非只有decoder的GPT的自注意力),交叉注意力层的$\mathbf{Q}、\mathbf{K}、\mathbf{V}$ 的来源是不同的。以下cross_attn= MultiHeadAttention(d_model, num_heads),调用时候的参数是q,k,v,mask,attn_output = self.cross_attn(x, enc_output, enc_output, src_mask), x = self.norm2(x + self.dropout(attn_output)) # 残差连接和层归一化
对比学习,RAG
对于 Sentence Embedding Model(如 BGE/SimCSE), 对比学习 可以直接作为 Pretrain 任务,因为它对模型的 精确语义区分能力 具有极大的帮助。对比学习是指,包含锚点样本,和正样本,和很多负样本的学习样本,增大(降低)和正(负)样本的相似度,涉及e指数和log。然后反向传播,前向传播。
Sentence Embedding Model可以在Retrieval-Augmented Generation(RAG)中起作用,在这个模型词嵌入的结果中找相关文本,并且给GPT模型生成回复,Sentence Embedding Model间接提高了生成式语言模型的回答质量和准确性。
