递归神经网络
简单的神经网络由三部分组成:输入,隐藏层,输出
深度神经网络(DNN)一般是增加隐藏层的数量。
递归神经网络(RNN)更加关注的是隐藏层中每个神经元在时间上的成长与进步。
Back Propogation Through Time
在普通的前馈神经网络 (feed-forward nn) 中,我们可以直接应用反向传播来计算梯度并更新权重。但是在 RNN 这种具有时间依赖的网络中,当前的输出不仅依赖于当前输入,还依赖于过去的隐藏状态。这就导致了参数的梯度计算需要沿时间维度进行传播,而 BPTT 正是解决这一问题的方法。 数学推导如下:
(1) 设定符号
- 输入序列:$ X = ${$x_1, x_2, …, x_T$}
- 输出序列:$ Y = ${$y_1, y_2, …, y_T$}
- 隐藏状态:$ h_t $ 表示时间步 $ t $ 的隐藏状态
- 参数:
- $ W_{xh} $:输入到隐藏层的权重
- $ W_{hh} $:隐藏层到隐藏层的权重
- $ W_{hy} $:隐藏层到输出的权重
- 损失函数:$ L(Y, \hat{Y}) $(如 MSE 或交叉熵)
(2) RNN 的前向传播 在 RNN 中,每个时间步的计算如下: $$ h_t = f(W_{hh} h_{t-1} + W_{xh} x_t) $$ $$ \hat{y} _ t = g(W_{hy} h_t) $$ 其中:
- $ f $ 是隐藏状态的激活函数(如 tanh 或 ReLU)
- $ g $ 是输出层的激活函数(如 softmax)
总损失为: $ L = \sum_{t=1}^{T} L_t(y_t, \hat{y}_t) $
(3) 反向传播 Through Time
计算损失对输出的梯度 $ \frac{\partial L}{\partial \hat{y} _ t} = \nabla_{\hat{y}_t} L_t $ 计算损失相对于输出的梯度,这部分和普通 BP 计算类似。
计算损失对隐藏状态的梯度 $ \frac{\partial L}{\partial h_t} = \frac{\partial L_t}{\partial h_t} + \frac{\partial L_{t+1}}{\partial h_t} + \frac{\partial L_{t+2}}{\partial h_t} + \dots $ 由于隐藏状态 $ h_t $ 会影响后续的所有时间步,因此梯度要沿时间方向反向累积。
计算参数的梯度
- 对隐藏状态的权重 $ W_{hh} $: $ \frac{\partial L}{\partial W_{hh}} = \sum_{t=1}^{T} \frac{\partial L}{\partial h_t} \cdot \frac{\partial h_t}{\partial W_{hh}} $
- 对输入权重 $ W_{xh} $: $ \frac{\partial L}{\partial W_{xh}} = \sum_{t=1}^{T} \frac{\partial L}{\partial h_t} \cdot \frac{\partial h_t}{\partial W_{xh}} $
- 对输出权重 $ W_{hy} $: $ \frac{\partial L}{\partial W _ {hy}} = \sum _ {t=1}^{T} \frac{\partial L}{\partial \hat{y} _ t} \cdot \frac{\partial \hat{y} _ t}{\partial W_{hy}} $
反向传播回传梯度
- 计算 梯度传播路径,从损失 $ L $ 反向通过时间步 $ T \to 1 $ 逐步更新参数。
- 使用 梯度下降(SGD, Adam) 来更新权重。
显而易见,BPTT存在两个致命问题:
- 第一个是梯度消失或爆炸:当权重矩阵的范数$||W_{hh}||$小于1时,随着时间步的增加,梯度指数级衰减,导致早期时间步的梯度几乎为 0,无法有效训练;
- 可能的解决方案:使用梯度裁剪(Gradient Clipping) 来限制梯度大小;使用长短时记忆网络(LSTM)或 门控循环单元(GRU) 代替 RNN。
- 第二个问题在于计算开销:BPTT 需要存储所有时间步的隐藏状态,因此当序列很长是,训练效率低。
- 可能的解决方案:Truncated BPTT,仅在固定窗口大小内进行梯度传播,而不回溯整个序列。
BPTT Variation
Truncted BPTT
- 策略:不展开整个时间序列,而是仅在 固定窗口大小 $ k $ 内进行反向传播(如$ k=10 $)。
- 优点:减少计算量,适用于长序列训练。
- 缺点:可能导致长程依赖信息丢失。
Online BPTT
- 计算一个时间步的梯度 立即更新参数(类似在线学习)。
- 适用于 流式数据处理(如语音识别)。
RNN Variation
LSTM 和 GRU 是RNN的两种主要变体,它们被设计用于解决传统RNN的梯度消失和梯度爆炸问题,从而更好地捕捉长程依赖(long-term dependencies)。LSTM和GRU可以通过门控机制(Gates) 控制信息流动,能够选择性保留或遗忘信息,有效缓解梯度消失问题,从而更好地学习长程依赖。
LSTM
(1) 结构
LSTM 主要引入了三个Gates和一个记忆单元(Cell State, $ C_t $):
- 遗忘门(Forget Gate):决定丢弃多少过去的信息。
- 输入门(Input Gate):决定更新多少新信息到记忆单元。
- 输出门(Output Gate):决定输出多少隐藏状态。
完整计算流程: $$ f_t = \sigma(W_f [h_{t-1}, x_t] + b_f) $$ $$ i_t = \sigma(W_i [h_{t-1}, x_t] + b_i) $$ $$ \tilde{C} _ t = \tanh(W_c [h_{t-1}, x_t] + b_c) $$ $$ C _ t = f _ t \odot C _ {t-1} + i _ t \odot \tilde{C} _ t $$ $$ o_t = \sigma(W_o [h_{t-1}, x_t] + b_o) $$ $$ h_t = o_t \odot \tanh(C_t) $$
(2) 详细解释
- 遗忘门 $ f_t $:控制是否遗忘过去的记忆。
- 输入门 $ i_t $:控制是否写入新的信息。
- 候选记忆 $ \tilde{C}_t $:当前时间步的新信息。
- 记忆单元 $ C_t $:更新后的长程记忆,信息可以直接在时间轴上流动,不易丢失。
- 输出门 $ o_t $:决定隐藏状态 $ h_t $ 的输出。
$ C_t $ 直接通过加法连接,使得梯度流动不会因多次乘法而消失。
GRU
GRU 是 LSTM 的简化版本,去掉了独立的记忆单元 $ C_t $,仅使用隐藏状态 $ h_t $ 作为存储信息的介质。
(1) 结构 GRU 主要有两个门:
- 重置门(Reset Gate):控制如何结合新的输入和过去的隐藏状态。
- 更新门(Update Gate):控制多少过去的信息保留,多少新信息加入。
完整计算流程: $$ r_t = \sigma(W_r [h_{t-1}, x_t] + b_r) $$ $$ z_t = \sigma(W_z [h_{t-1}, x_t] + b_z) $$ $$ \tilde{h} _ t = \tanh(W_h [r_t \odot h_{t-1}, x_t] + b_h) $$ $$ h_t = (1 - z_t) \odot h_{t-1} + z_t \odot \tilde{h} _ t $$
(2) 详细解释
- 重置门 $ r_t $:决定是否遗忘过去的隐藏状态。
- 更新门 $ z_t $:决定新旧信息的混合比例,类似 LSTM 的输入门和遗忘门的结合。
- 候选状态 $ \tilde{h}_t $:新的信息。
- 最终隐藏状态 $ h_t $:
- 当 $ z_t $ 逼近 1:当前状态 接近新信息。
- 当 $ z_t $ 逼近 0:当前状态 保留过去的隐藏状态。
GRU 用更新门合并了 LSTM 的输入门和遗忘门,因此计算更简单。
Transformers
虽然 LSTM 和 GRU 仍然被广泛使用,但现代NLP任务大多采用 Transformer(基于自注意力机制),因为:
- Transformer 并行计算 性能更强,而 LSTM/GRU 依赖序列处理,无法并行。
- Transformer 通过 Self-Attention 直接建模长程依赖,而LSTM/GRU仍然有一定信息衰减问题。
但在语音处理、时间序列预测等任务中,LSTM/GRU仍然具有较好的表现。
Self-Attention
The fundamental operation of any transformer architecture is the self-attention operation 1.
自注意力机制是一个从序列到序列的操作,它的输入是一组向量 $x_1, x_2, …, x_t$,对应的输出序列是 $y_1, y_2, …, y_t$。(每个向量都是k维)
每一个 $y_i$ 是怎么计算的?$y_i$是根据当前位置的$x_i$和其他所有位置的$x_j$的相关性计算出来的,具体公式如下 $$y_{\color{red}{i}} = \sum_{\color{blue}{j}} w_{\color{red}{i}\color{blue}{j}} x_{\color{blue}{j}}$$
对于$w_{\color{red}{i}\color{blue}{j}}$, 它是由$x_{\color{red}{i}}, x_{\color{blue}{j}}$的点积函数推导出来的。 $$w_{\color{red}{i}\color{blue}{j}} = \text{softmax}(w^{\prime}_{\color{red}{i}\color{blue}{j}})$$
其中 $$w^{\prime}_{\color{red}{i}\color{blue}{j}} = x^T_ix_j$$
原理可视化如下图所示,值得注意的是,这是整个体系结构中唯一在向量之间传播信息的操作。
为什么self-attention机制如此有效?我们拿电影推荐系统来举例子。假设你经营一家电影租赁公司,你有一些电影和一些用户,你想向你的用户推荐他们可能会喜欢的电影。一种方法是为电影手动创建特征,例如电影中有多少浪漫情节,有多少动作场面,然后为用户设计相应的特征:他们有多喜欢浪漫电影,有多喜欢动作片。如果这样做,两个特征向量之间的点积就会为电影属性与用户喜好的匹配程度打分。如果用户和电影的某个特征的符号相匹配–电影很浪漫,用户喜欢浪漫,或者电影不浪漫,用户讨厌浪漫–那么得到的点积就会得到该特征的正值。如果符号不匹配–电影浪漫而用户讨厌浪漫,则相应项为负值。
当然这样做并不现实,因为这涉及到大量的数据标注工作。一种解决办法是我们将电影特征和用户特征作为模型的参数,让用户选择一些喜欢的电影,然后通过优化算法调整用户特征和电影特征,使它们的点积能够匹配用户的已知喜好。即使我们没有告诉模型这些特征的具体含义,但在训练后,这些特征往往会自发地映射到有意义的电影内容信息。 例如,某个维度可能对应“浪漫”,另一个维度可能对应“动作”或“喜剧”,即使我们事先并未明确这些维度的含义。
这就是self-attention机制。它本质上是一种计算序列内部关系的方法。在处理文本时,我们首先为每个单词分配一个可学习的嵌入向量(embedding vector),例如句子 “the cat walks on the street” 会被映射为向量序列 $ v_{\text{the}}, v_{\text{cat}}, v_{\text{walks}}, v_{\text{on}}, v_{\text{the}}, v_{\text{street}} $。然后,这些向量进入self-attention layer,输出新的向量序列 $ y_{\text{the}}, y_{\text{cat}}, y_{\text{walks}}, y_{\text{on}}, y_{\text{the}}, y_{\text{street}} $。其中,每个 $ y_t $ 都是输入向量的加权和,而权重是根据归一化 (softmax) 的点积(dot product) 计算得到的。点积衡量了单词之间的相关性,如果两个单词在上下文中紧密相关,它们的点积就会较高,从而获得更高的注意力权重。例如,在句子中,“walks” 这个动词需要与“cat”建立联系,所以 $ v_{\text{walks}} $ 和 $ v_{\text{cat}} $ 的点积会较高,而“the” 这样的冠词由于对整体语义影响较小,通常不会与其他词有很大的点积值。
有趣的是,基础的self-attention并不关心输入的顺序,它只关注单词之间的相对关系。如果我们对输入序列进行重新排列,输出的向量序列也会以相同的方式被调整,而不会改变内容本身。这意味着自注意力本质上是一种集合操作(Set Operation),它不会依赖词的前后顺序,而是让模型自己学习哪些单词之间应该有更强的联系。此外,基础的自注意力层没有可训练参数,它的行为完全取决于输入向量,而这些向量来自于嵌入层,而嵌入层是可学习的。在完整的 Transformer 结构中,我们会通过位置编码(Positional Encoding) 让模型感知单词的顺序信息,但在纯自注意力层中,它是完全顺序不敏感的。
Query, Key, Value
当代transformer中使用的self-attention还依赖三个额外的技巧 - Queries, Values, Keys。在 自注意力 计算中,每个输入向量 $ x_i $ 需要在三种不同的角色之间切换:
- 查询(Query,$ q_i $):每个词向量都需要与其他词向量进行比较,以确定它对自己的输出 $ y_i $ 的影响权重。
- 键(Key,$ k_i $):每个词向量也被其他单词用来计算权重,即它对其他单词输出 $ y_j $ 的影响。
- 值(Value,$ v_i $):在计算完权重后,每个单词的最终表示是所有词向量的加权和,其中加权方式由查询和键计算得到的注意力权重决定。
为了更方便计算,我们不会直接使用原始输入向量 $ x_i $,而是对其进行三次不同的 线性变换,得到: $$ q_i = W_q x_i, \quad k_i = W_k x_i, \quad v_i = W_v x_i $$ 其中 $ W_q, W_k, W_v $ 是可训练的 权重矩阵,用于学习适合任务的注意力表示。
接下来,计算两个词之间的相似性(相关性): $$ w’ = q_i^T k_j $$ 然后进行 softmax 归一化 以获得最终的注意力权重: $$ w_{ij} = \text{softmax}(w’) $$ 最后,每个单词的输出向量$ y_i $是所有值向量的加权和: $$ y_i = \sum_j w_{ij} v_j $$ 这个过程让模型能够动态调整单词之间的相互影响,从而更好地理解序列中的语义关系。
点积缩放
刚才我们使用 dot product 计算查询(Query)和键(Key)之间的相似性,并将其输入 Softmax 计算注意力权重。然而,当嵌入维度 $ k $ 较大时,点积的值会变得很大,导致 Softmax 的梯度变得极小,甚至造成梯度消失,影响模型训练。
为了解决这个问题,我们对点积进行缩放 (scaling dot product),即除以 $ \sqrt{k} $: $$ w’_{ij} = \frac{q_i^T k_j}{\sqrt{k}} $$ 从而防止输入值过大,使 softmax 函数输出的梯度保持稳定,提高训练效率。这样缩放的原因在于 高维向量的欧几里得长度随着维度 $ k $ 增大而增大,通过除以 $\sqrt{k}$,可以消除这种放大效应,使不同维度的计算结果保持在合理范围内,从而更稳定地学习注意力权重。
Multi-head Attention
在Self-Attention机制中,每个单词都可以与句子中的其他单词建立关系。然而,在标准的单头注意力(Single-Head Attention)机制下,一个单词只能用一个注意力分布来表示它与所有其他单词的关系。这就导致了一个问题:单个词可能在不同的上下文中承担不同的语义角色,但单头注意力无法区分这些角色。例如Mary gave roses to susan. 在 single-head attention 机制中,所有这些信息都会被简单地加权求和,而不会分别处理不同的语义关系。这意味着,“Mary” 和 “Susan” 都会影响 “gave” 的表示,但它们的影响方式是相同的,无法区分"施事者" 和 “受益者” 的不同语义。
多头注意力如何解决这个问题? 多头注意力(Multi-Head Attention) 通过使用多个独立的注意力头(attention heads) 来提供更高的表达能力。具体来说,每个注意力头(head)具有自己独立的查询、键和值变换矩阵:$W_q^r, W_k^r, W_v^r$,其中$r$表示不同的注意力头。对于输入$x_i$,每个注意力头都会产生一个输出向量$y_i^r$,把这些向量拼接起来,然后通过一个线性变换把维度降到k。
什么是Transformer?
Any architecture designed to process a connected set of units—such as the tokens in a sequence or the pixels in an image—where the only interaction between units is through self-attention.
下面是一个比较基础的架构
BERT
BERT - Bidirectional Embedding Representation Transformer
BERT与GPT架构的区别
Parsing
Decoding with LLMs
One naturally wonders if the problem of translation could conceivably be treated as a problem in cryptography. When I look at an article in Russian, I say: ’This is really written in English, but it has been coded in some strange symbols. I will now proceed to decode.
Terminology: continuation - 补全
我们如何生成the most probable continuation? $$ \arg\max_{w_1, …, w_n} p(w_1, …, w_n | \text{prefix}) $$ 如何求解?
- 遍历所有可能的续写,计算它们的概率,然后选择概率最大的那个。 但在自然语言处理中,可能的序列数量是指数级增长的,所以这种方法通常不可行。
- 另一种策略是逐步生成,即每一步选择当前最优的下一个单词(或 top-k 选项)。这种方法更实用,比如贪心解码(greedy decoding)
Greedy Decoding
下面是greedy decoding的具体流程
这种解码方式的问题:
- 我们只做一次continuation,一旦发生错误无法回溯更改。
Beam Searching Decoding
根据greedy decoding的教训,我们选择保留几个continuation,并且每次都扩展most promising的那个。流程如下图所示
Beam Searching如何实现?
- 用优先队列这样的数据结构来存储每个continuation
- 这个队列中保持最多k个解析
- 当要解码一个单词时,从队列中pop出一个解析,扩展完再push回队列
- 用priority queue这种结构来做,时间复杂度不会超过O(logk),甚至能达到O(1)
队列规模k的影响
- 当k=1,就是greedy decoding。所以当k较小时,我们会出现类似的问题
- 当k很大时,一方面是计算昂贵,一方面是有工作表明较大的k往往导致worse translation 2, 3。
- 而且当k很大时,往往生成的contination都很短,因为较短的continuation一般都是优选
- 因此,选择一个合适的k非常重要
解决方法:
Sampling
与其每次选择概率最大的,不如从输出的概率分布中采样。例如Top-k Sampling和Nucleus sampling
Holtzman et al. 对比了几种方法的效果,如图所示4
除此以外,还有Locally Typical Sampling
Top-k Sampling vs. Nucleus Sampling vs. Locally Typical Sampling
这些都是文本生成任务中用于解码(decoding)的策略,旨在平衡多样性和合理性,特别是在语言模型(如 GPT、LLM)中应用。
它们的核心目标是避免单一确定性输出(如 Greedy Search),让生成文本更加自然和富有变化。
核心思想:
- 选择那些使得模型生成的下一个单词在上下文中最符合“局部典型性”的单词。
- 不只是看单词概率本身,而是看它是否在上下文中“听起来”合理(局部熵最小)。
流程:
- 计算所有单词的概率 $ p(w \mid \text{context}) $。
- 计算这些单词的 信息熵(self-information): $$ s(w) = -\log p(w \mid \text{context}) $$
- 选择信息熵最接近平均信息熵(典型熵) 的一部分单词。
- 在这个子集中进行采样。
优点:
- 避免了 Top-k 和 Nucleus Sampling 的局限,使得输出更加符合上下文,而不是仅仅基于全局概率高低。
- 适用于对局部语境要求高的任务,比如对话生成、摘要等。
缺点:
- 计算复杂度略高,需要额外计算信息熵。
采样的目的就是平衡多样性和合理性。避免语言模型单一确定性的输出。
Neural Parsing
先复习下Encoder-Decoder架构,如下图所示,Encoder作用是将输入序列(如德语句子)编码成一个固定长度的上下文向量(context vector)。
- 输入词(如 “natürlich”, “hat”, “john”, “spaß”)首先被映射成词向量($ x_1, x_2, x_3, x_4 $)。
- 这些词向量依次输入到一个RNN 编码器(通常是 LSTM 或 GRU),产生隐藏状态 $ h_1, h_2, h_3, h_4 $。
- 这些隐藏状态捕捉了句子的信息,最终最后一个隐藏状态(这里是 $ h_4 $)被用作整个输入句子的上下文向量(context vector)。
Decoder接收编码器提供的上下文信息,然后逐步生成目标语言的句子(如英文)。
- 编码器最后的隐藏状态被传入解码器的 RNN 作为初始状态。
- 解码器使用 RNN(LSTM/GRU)逐步生成目标语言的单词:
- 初始状态 $ s_1 $ 依赖于编码器的最后一个隐藏状态。
- 每个时间步,解码器的 RNN 生成一个新的隐藏状态 $ s_t $。
- 通过一个 softmax 层,$ s_t $ 计算当前时间步的输出词 $ y_t $(如 “of”, “course”, “john”, “has”, “fun”)。
- 解码器的输出作为输入传递到下一步,直到生成完整句子。
Parsing is the task of turning a sequence of words
问题来了,句子解析的输入是一个序列,但输出不是,那我们如何用encoder-decoder模型来进行parsing?
我们可以linearize the syntax tree. 这样我们就有一个序列来表示输出了。例如:I saw a man with a telescope的句子解析就是
(S (NP (Pro You ) ) (VP (V saw ) (NP (Det a ) (N man ) (PP (P with ) (Det a ) (N telescope ) ) ) ) )
此外,还需要一些优化
- 添加EOS。使解码器知道何时停止生成,而不会一直无限制地预测单词。
- 反转输入字符串可以带来小幅的性能提升。
- 加深网络层数。例如对encoder和decoder都使用三层LSTM5。
- 添加注意力机制
- 使用word2vec作为输入(预训练的词嵌入)
- 自动生成训练数据,而不需要人工标注。Vinyals et al. (2015) 5 采用 Berkeley Parser(一个已有的句法解析器)来解析大量文本,并用这些解析结果作为训练数据。
可能发生的问题(比例很小,无需担心):比如我们如何确定opening and closing brackets match? 如何对应输入和输出?如何确保模型输出的是整个序列的最优parsing而不是仅仅预测每个time step上的best symbol?
Parsing with Transformers Kitaev等人用transformers进行parsing。
- Use a transformer to encode the input
- This results in a “context aware summary vector” (embedding) for each input word.
- The embedding encodes word, PoS tag, and position information.
- The embedding layers are combined to obtain span scores
- But they also try factored attention heads, which separate position and content information.
什么是span scores? 在NLP中,尤其是命名实体识别(NER)、句法解析(Parsing) 和 信息抽取(IE) 等任务中用于评估模型性能的指标。 Span scores 通常基于 Precision(精确率)、Recall(召回率) 和 F1-score(F1 分数) 来评估模型在 span-level 的表现:
Span scores在Transformer解析任务中的计算方法:计算span相关的向量差值,经过线性变换、归一化(LayerNorm)、非线性激活(ReLU)和再次变换,得到 span scores。最终,这些得分用于 解码(decode the output),即找到最优的解析树。
Unsupervised Parsing
Unsupervised Parsing6主要是从未标记的文本中归纳出语法结构。
Unsupervised Parsing的SOTA的F-score只有60,对比supervised parsing来说很难,supervised parsing的F-score可以达到95以上
LLM前沿研究
Scaling Law
例如,给定固定的计算资源预算,训练Transformer语言模型的最佳模型大小和训练数据集大小是多少?
这类问题就可以用Scaling laws来回答。它提供了Compute Budget(C),size of model(N)以及number of training tokens(D)之间的一种关系。有一个粗略的共识是,它们可以使用power laws或类似的定律(以及它们的组合)来建模。
Power Law
Power Law描述的是变量x和它某些行为之间的关系,公式表示为$f(x) = \alpha x^\mathcal{-K}$
它有一个重要的性质:当$x$乘以一个因子时,$f(x)$也同样作为$κ$的函数乘以一个因子。即: $$ f(cx) = \alpha (cx)^\mathcal{-K} = c^\mathcal{-K}f(x) $$
Kaplan et al. (2020)
Kaplan等人的研究7总结
- 模型的性能很大程度上取决于scale(模型参数的数量,数据集大小,计算预算)而不是网络拓扑(层数,每层的宽度)。
- 数据集大小和模型大小的一起增长是很重要的。
- 性能可以用power law来建模。
还有一点,我们使用floating-point operations per second (FLOPs) 来衡量compute,而不是单纯依赖时间来衡量。
对他们的工作(Kaplan Scaling Law)的主要批判点在于,他们在训练中使用了相同的学习率。
Hoffmann et al. (2020)
以前的scaling law认为,增加计算预算(compute budget)时,优先增加模型大小(model size),其次才增加数据量(data size)。 比如计算预算 ×100 时,模型参数量 ×25,数据量 ×4。因为直觉上更大的模型能更有效地利用数据,所以数据规模的增长不需要太快。 但是,过度增加模型大小可能会导致过拟合或计算资源浪费。
Hoffmann等人2022年的研究提出了一个新的结论8:
计算预算增加时,模型大小和数据量应该同比例增长。 比如计算预算 ×100 时,模型大小 ×10,数据量 ×10。因为之前的策略导致很多大模型在小数据上训练,出现欠训练(undertrained models) 的问题。 Hoffmann 发现,更大模型并不一定能完全利用固定数量的数据,合理增加数据量可以显著提升模型性能。这个发现也影响了后续 LLM 训练策略,例如 GPT-4、Gemini、PaLM 等更关注 数据与模型规模的均衡增长。
如何推导Hoffmann等人提出的Chinchilla’s Scaling Law?
- L: LM average test loss (entropy loss)
- D: dataset size, number of tokens
- N: number of parameters
- C: compute budget, C=C(N, D) 已知一个固定的compute budget C*, 找到 $$ \arg\min_{N, D}L(N, D) = C^* $$ 用power law来建模: $$ L(N, D) = \frac{a}{N^\alpha} + \frac{b}{D^\beta} + c $$ $c$是理想的test loss
因此,Hoffmann等人训练出来了两个模型:
- Gopher: 280 billion parameters, 300 billion tokens, L(N, D) = 1.993
- Chinchilla: 70 billion parameters, 1.4 trillion tokens, L(N, D) = 1.936
Chinchilla 遵循这一策略(较小模型 + 更多数据),结果证明它在test loss和下游任务上表现更优。
增加效率
语言模型的训练中,主要做的计算就是矩阵乘法和求和归一化(Softmax)。用一个公式概括Transformer做的事情就是$\text{Softmax}(QK^T)V$
GPU是并行处理器,结构如下图所示
- 基础的计算单元是线程
- 线程被分组成Block,Block中的所有线程都有唯一的ID,但运行相同的代码
- 这使得GPU可以做极端的并行化
- Grid是一组Block。每个Block可以运行不同的代码段
- GPU有很大的global memory,很大,但是很慢
- 每个Block都有一个共享内存-Block中的所有线程之间共享这个内存,它效率很高,但很小
- 写代码时要尽可能少用全局内存,多用Block的共享内存
Double Descent
Double Descent是深度学习训练过程中出现的一种现象,它描述了模型的test error随着model size或dataset size变化的非单调趋势。 Double Descent 现象表明,在“过拟合区域”之后,继续增加模型规模,test error反而会再次下降,进入“第二次泛化区域”。
因此,传统统计学习理论预测过拟合会导致泛化能力下降,但Double Descent说明在超大模型下,泛化能力反而会回升。
LLMs as Formal Machines
LLM微调
GPT发展历史:
- GPT: 117M parameters, decoder-only model with 12 layers, trained on 4.6GB data
- GPT-2: 1.5B parameters, decoder-only model with 48 layers, trained on 40GB data
- GPT-3: 175B parameters, unkown model structure, trained on 600GB data
介绍下In-context learning, 是指LLM在不进行参数更新的情况下,仅通过输入示例来完成新任务。就是让模型“看例子学套路”而不是“调参数学规则”。但是这会让模型对提示词高度敏感,而且适用范围也受限
指令微调
- Collect examples of instruction-output pairs across several tasks and fine-tune a model, then evaluate on unseen tasks.
如图所示,可以说明:
- Model generation performance is positively correlated with observed tasks and model size.
- Number of examples does not have a big influence.
RLHF
Logic behind learning from human feedback
- Say we had human “rewards” – a score that tells how much a human prefers a completion. Say there is such function called $r(x, y)$ that maps prompt and completion to a reward
- We would want to find an LLM with parameters $\theta$ such that
$$ \theta = \arg \max_{\theta} \mathbb{E} _ {p _ {\theta}(x,y)}[r(x,y)] $$
- This is the model that maximises the expected reward according to humans.
问题来了,怎么更新参数?(怎么计算梯度?),因为reward函数是外部评估器,没办法直接对其求梯度。
首先定义$z = (x, y)$是一个完整的生成序列,那么要求: $$ \nabla_\theta \mathbb{E} _ {p_\theta(z)}[r(z)] = \nabla_\theta \sum_z p _ \theta(z) r(z) $$ 梯度更新$\theta$,$r(z)$与其无关,所以放进去: $$ = \sum_z r(z) \nabla_\theta p _ \theta(z) $$ 然后用log-derivative trick变换: $$ \nabla_\theta p_\theta(z) = p_\theta(z)\nabla_\theta \log p_\theta(z) $$ 所以替换过后就变成了 $$ \sum_z r(z) p_\theta(z)\nabla_\theta \log p_\theta(z) $$ 然后变成期望形式 $$ \mathbb{E} _ {p_\theta(z)}[r(z)\nabla_\theta\log p_\theta(z)] $$
用模型生成一些$(x_i, y_i)$,然后用打分函数得到$r(x_i, y_i)$,再去近似估计上面的期望 $$ \nabla_\theta \mathbb{E}[r(x,y)] \approx \frac{1}{n} \sum_{i=1}^n r(x_i, y_i) \nabla_\theta \log p_\theta(x_i, y_i) $$ 再用这个梯度来更新参数 $$ \theta_t \leftarrow \theta_{t-1} + \frac{\alpha}{n} \sum_{i=1}^n r(x_i, y_i) \nabla_\theta \log p_{\theta_{t-1}}(x_i, y_i) $$ $\alpha$是学习率,梯度更新本质上是用reward加权的log-likelihood梯度来更新。这样做之后,虽然我们不能对reward直接求导,但是可以让reward控制梯度的大小。
RLHF的问题是什么?是人类,人类标注不仅高成本,而且标注结果噪声不小。
Summarising Text
Types of summarisation models:
- Multi-document versus single document
- Extractive versus abstractive
- Generic (unconditioned) versus query-focused (conditioned) or controllable
- Supervised versus unsupervised
- Multi-modal versus single modality
Multi-document summarisation vs Single-document summarisation
- Single document summarisation use a single source, for example, a news article
- Multi document summarisation uses multiple sources or documents for the summary (all sources are related to a theme or topic)
Query-focused summarisation vs Controllable summarisation
- Query-focused: summarise a document based on a specific query
- Controllable: Control parameters such as length, aspect, sentiment
Extractive summarisation vs Abstractive summarisation
- Extractive: use a subset of the sentences from the document as the candidate summary
- Abstractive: synthesise a summary which is not tied to the exact wording in the article
Extractive总结很简单:对于一个有n句话的文档$d=(s_1, s_2, …, s_n)$, 然后做分类,如果这个句子应该放在summarisation中,就是$y_i=1$,否则$y_i=0$。非常简单,但是是许多summarizer的基础模型。
对于二分标签总结,有两个问题
- 从哪里获得训练模型的标签?
- 训练目标是什么?朝什么方向优化?
对于标签,给定一篇文章(含多句子)和它的“参考摘要”。然后计算每句话和参考摘要之间的 ROUGE 分数(ROUGE 测的是和摘要重合的词/短语数量)。选出 得分最高的几个句子,作为模型的正样本(打上 1 标签),其他句子为0。
对于训练目标,现在每个句子都有一个标签(是否该被选进摘要),用 logistic 回归或者其他分类器,目标是最大化这堆标注的 log-likelihood。这就是标准的 binary cross-entropy: $$ \mathcal{L} = -\sum_i \left[ y_i \log p_i + (1 - y_i)\log(1 - p_i) \right] $$
Abstractive总结:这个问题应该被视为文本生成问题,而不是之前的选择问题。使用的是pointer-generator network。
- Base model是一个seq2seq架构(输入文章由encoder编码,输出摘要由decoder逐词生成)。
- 这个base model的问题是标准的seq2seq模型很难生成词表外的词,而且容易错过原文中的关键词
- 解决办法就是pointer-generator network,引入指针机制,这样每一步生成单词$w$的概率就变成了一个混合模型 $$ P(w) = p_{\text{gen}} P_{\text{vocab}}(w) + (1 - p_{\text{gen}}) \sum_{i: w_i = w} a^t_i $$
- 这个公式表示模型可以选择 “从词表中生成” 或 “从原文中复制”,通过$p_{\text{gen}}$来动态切换。
- 还有一个问题是这个模型通常生成重复内容,因此引入coverage vector $c^t = \sum^{t-1}_{t’=0}a^{t’}$
- 这个向量记录了过去decoder在source上的attention积累量,新一轮decoder中把这个vector输入进来可以防止过度关注同一个片段,从而减少重复。
ROUGE分数是什么?如何计算?
- ROUGE是Recall-Oriented Understudy for Gisting Evaluation,值越高越好。 $$ \text{ROUGE-N} = \frac{\sum_{S\in ref}\sum_{\text{gram} _ n\in S}\text{countmatch}(\text{gram} _ n)}{\sum_{S\in ref}\sum_{\text{gram}_n\in S}\text{count}(\text{gram}_n)} $$
- 为什么计算的是召回率而不是精确率?Recall is more important to decide whether the information in the candidate summary captures the information in the reference summary.
还有一种分数不依赖n-grams,用BERT来softly score similarity. 它计算的是语义相似度
- 使用BERT提取每个词的向量表示,再用余弦相似度比较候选摘要和参考摘要之间的每个词是否“语义接近”。
- 给定$C$是candidate sentence,$R$是reference sentence
- 用BERT把C和R中的每个词编码成向量。$C=[c_1, …, c_n], R=[r_1, …, r_m]$
- 每个词对之间都计算余弦相似度,得到一个 n×m 的相似度矩阵
- 每个词从对方句子中找最相似的词作为匹配,得到precision(每个生成词去参考里找最相似的词)和recall(每个参考词去生成中找最相似的词)两个方向的得分。最终的F1 score就是 $$ \text{BERT Score} = \frac{2 \times \text{Precision} \times \text{Recall}}{\text{Precision} + \text{Recall}} $$
PEFT
假设有一个神经网络函数$ f: X \to Y $,可以表示为多个子函数的组合:
$$ f_{\theta_1} \circ \dots \circ f_{\theta_n} $$ 每个子函数$ f_{\theta_i} $有自己的参数$\theta_i$。我们希望通过一个只含有少量参数的模块$ \phi $来对这个网络进行微调(即 PEFT 的目标),而不是更新整个模型的参数$ \theta $。
PEFT分为三类
Parameter composition: $$ g_i(x) = f_{\theta_i \oplus \phi}(x) $$
- 用一个组合操作$ \oplus $将原始参数$ \theta_i $与微调模块参数$ \phi $融合。
- 举例:LoRA就是这种方式,它在原始权重上添加了一个低秩矩阵。
Input composition: $$ g_i(x) = f_{\theta_i}([x, \phi]) $$
- 把 $ \phi $ 拼接在输入$ x $上作为新的输入。
- 举例:Prefix Tuning就是这种方式,它把微调参数作为“前缀”输入到 Transformer 中。
Function composition: $$ g_i(x) = f_{\theta_i} \circ f_{\phi}(x) $$
- 把$ f_\phi $作为前置函数处理输入,再送入原始函数$ f_{\theta_i} $。
- 举例:Adapter 模块可以看作在主模型中插入了一个前置的小网络。
首先介绍三种常见的parameter composition实现方式
- Sparse network
- 让$\phi$具有稀疏结构,即只有一小部分参数是非零的。目标是减少计算和内存开销,同时保留表达能力。
- Structured composition
- 在原始参数$\theta_i$上施加结构化限制,例如只更新某些预定义结构中的参数(比如只调 Transformer 中的 FFN 或某层的 attention)。
- Low rank composition
- 把参数表示成低秩矩阵,比如将全连接层的权重调整部分限制为两个小矩阵相乘(低秩近似)。
Parameter Efficiency | Training Efficiency | Inference Efficiency | Performance | |
---|---|---|---|---|
Parameter Composition | methods require <3% of params | pruning requires re-training iterations | does not increase model size | LoRA achieves strong performance |
Input Composition | only add a small number of params | extend the context’s window | extend the context’s window | require large models to perform well |
Function Composition | adapters depend on hidden size | does not require gradients of frozen params | new functions increase # of operations | mactch or outperform standard fine-tuning |
Evaluating Generation and Machine Translation
Ethics
Evaluation of LLM and Alignment
QA and RAG
Tutorials
Language Models
- Softmax Function
- What is the purpose of Softmax function?
- The softmax converts an arbitrary vector of |v| dimensions into a valid categorical probability distribution over |v| possible outcomes. In particular it ensures that all individual elements (probabilities) are non-negative and sum to one.
- What is the purpose of the expression in the numerator?
- The numerator ensures that all values are positive. Note that this is stronger than needed: the axioms of probability simply require all values to be non-negative. But exponentiation is only zero in the (negative) limit.
- What is the purpose of the expression in the denominator?
- The denominator normalises the distribution so that all individual probabilities sum to one.
- Now consider how a neural language model with a softmax output layer compares with a classic n-gram language model. Typically, we use techniques like smoothing or backoff in conjunction with n-gram models. Does this problem arise in the neural model? Why or why not?
- No—softmax ensures that the model will always return a non-zero probability for any n-gram.
- Feedforward Language Models
- In feedforward language model, the probability $P(w_i\mid w_{i-n+1}, …, w_{i-1}) = \text{softmax}(Vh_2 + b_2)$, where $h_2 = \text{tanh}(Wh_1 + b_1)$, $h_1 = \text{concatenate}(Cw_{i-n+1}, …, Cw_{i-1})$, $w_i = \text{onehot}(w_i)$ for all i. Now consider the number of parameters required to represent this model. This number is determined by the size of the vocabulary (given to you by the data), the order $n$, and the dimension of the two hidden layers, $h_1$ and $h_2$, which we will denote $d_1$ and $d_2$, respectively (Note that the first dimension must be divisible by n − 1, but you can ignore this detail in your calculations). Dimensions $d_1$ and $d_2$ are modeling choices, though the practical consideration is how they impact the model’s accuracy.
- How to express the number of model parameters in terms of $|V|, n, d_1$ and $d_2$?
- For $V$: $d_2|V|$
- For $W$: $d_1d_2$ because $d_1$ is predefined, and will be equal to $(n-1) * \text{embedding}$
- For $C$: $|V|d_1/(n-1)$ because $|\text{embedding}| = \frac{d_1}{n-1}$
- For $b_1$: $d_2$
- For the complete model, add up the aboveL $(1+\frac{d_1}{n-1} + d_2){V} + d_1d_2 + d_2$
- An effective size for the hidden dimension of a neural NLP model is often in the hundreds. For n from 2 to 5, how many parameters would your model have if $\frac{d_1}{n-1} = d_2 = 100$, what if $\frac{d_1}{n-1} = d_2 = 1000$
- The key here is that $(1 + \frac{d_1}{n-1} + d_2)|V|$ dominates, and this is determined by the mapping between the one-hot vocabulary vectors and the hidden dimensions. A reasonable guess for |V| in most neural network language models is 20000 and $\frac{d_1}{n-1} = d_2 = 100$ should give parameters of about 4M parameters. If $\frac{d_1}{n-1} = d_2 = 1000$ then you have about 40M parameters. However if we try to model an open vocabulary in this model we will struggle to fit this in memory on a GPU whose memory is generally far smaller than a CPU machine.
- What do you conclude about the relative memory efficiency of classic n-gram and feedforward neural language models? If you increased n even further, what would happen?
- The number of parameters in the n-gram model is highly sensitive to changes in n, while the number of parameters in the neural model is almost unchanged. Hence, the feedforward model can be easily extended to larger n, which might be advantageous.
- How would you expect the number of parameters in an RNN model to scale with $n$ and $|V|$
- An RNN scales in the same way as the feedforward model: the dominant factor is the vocabulary size. It’s entirely insensitive to n since it (theoretically) models $n = \infty$
- Think of any strategies to substantially reduce the number of parameters?
- For RNN models, the key to reducing the number of parameters is to reduce vocabulary size. This can be done with subword modeling. Notice that this is inappropriate for the n-gram model, since it would be conditioning on less information! Note that the feedforward model has a similar limitation, though it is easier to increase the order $n$ of the feedforward model.
- How to express the number of model parameters in terms of $|V|, n, d_1$ and $d_2$?
- Model Design
- Design a feedforward neural network to model $P(y_i\mid x)$. . Identify any independence assumptions you make. Draw a diagram that illustrates how the model computes probabilities for the tag of the word “with”: What is the input, and how is the output distribution computed from the input? Write out the basic equations of the model, and explain the choice.
- An effective design for the feedforward network is to model $P(y_i \mid x_{i-k}, …, x_{i+k})$ for some fixed window size 2k+1. For example, use something like: $P(y_i \mid x_{i-k}, …, x_{i+k}) = \text{softmax}(Wh+b_2)$, where $h = \text{tanh}(Vx+b_1)$, and $x$ is onehot encoded like $x = \text{onehot}(x_{i-k});…;\text{onehot}(x_{i+k})$. The choice of non-linearity is not important for this question, but since it asks for a feedforward network, you should have a hidden layer. This is about the simplest possible model.
- Design a RNN to model $P(y_i\mid x)$. . Identify any independence assumptions you make. Draw a diagram that illustrates how the model computes probabilities for the tag of the word “with”: What is the input, and how is the output distribution computed from the input? Write out the basic equations of the model, and explain your choices.
- One design for the RNN is to model $P(y_i\mid x_1, …, x_i)$. That is, the RNN reads $x_1$ through $x_i$ one step at a time, and at the ith step produces a distribution for possible tags $y_i$. For simplicity, let’s use RNN to denote a unit that receives an input and a previous hidden state, and produces a new hidden state; it can easily be replaced with an LSTM or other recurrent unit of your choice: $P(y_i\mid x_1, …, x_i) = \text{softmax}(Wh_i+b)$, where $h_i = \text{RNN}(\text{onehot}(x_i), h_{i-1})$.
Transformers
- Transformer’s Efficiency
- Inspect Table 1 in Attention is all you Need with a focus on the “Complexity per Layer” column wherein n is the sequence length and d is the representation dimension, the same parameter as the self-attention projection size from Q1.
- Consider the complexity bounds and your own knowledge of how NLP tasks are constructed – describe when a self-attention network has a lower complexity than other networks.
- As a case study, we can set
d=1024
and compare between these models. For most NLP tasks here we can approximate thatn << d
and therefore the Transformer has lower complexity than the RNN. It might be helpful to name and discuss a few tasks where this is true. Conversely, there might be some cases where the inverse is true (document translation?). In terms of increasingn
, the additional complexity in a Transformer makes sense as we need an additional self attention computation against all prior sequence elements. For the RNN, we only need to compute the RNN cell with the new state and cumulative history.
- As a case study, we can set
- Other than complexity – describe other constraining factors to be considered when planning experiments using neural networks for NLP. There is no right answer here.
- we now want to add in the practical other constraints that exist when running experiments. You could discuss that really this complexity is only a part of choosing models as well as performance and constraints such as GPU Memory, data availability, tunable hyperparameters etc. A typical Transformer is much larger than an RNN and space/speed constraints might arise before complexity can even be considered.
- Consider the complexity bounds and your own knowledge of how NLP tasks are constructed – describe when a self-attention network has a lower complexity than other networks.
- Consider an encoder-decoder RNN model, following up on the question before. Can the computation of the encoder be easily parallelised with respect to the number of tokens (meaning, can you break the input and the computation into chunks such that they run in parallel)? Explain why or why not.
- a
- Consider the Transformer encoder layer. Explain why its computation can be paralleised over tokens per layer. Can computation be easily parallelised across layers?
- a
- Considering Permutations
References
‘Transformers from scratch’ Available: https://peterbloem.nl/blog/transformers ↩︎
Tu, Zhaopeng, et al. “Neural machine translation with reconstruction.” Proceedings of the AAAI Conference on Artificial Intelligence. Vol. 31. No. 1. 2017. ↩︎
Koehn, Philipp, and Rebecca Knowles. “Six challenges for neural machine translation.” arXiv preprint arXiv:1706.03872 (2017). ↩︎
Holtzman, Ari, et al. “The curious case of neural text degeneration.” arXiv preprint arXiv:1904.09751 (2019). ↩︎
Vinyals, Oriol, et al. “Grammar as a foreign language.” Advances in neural information processing systems 28 (2015). ↩︎ ↩︎
Cao, Steven, Nikita Kitaev, and Dan Klein. “Unsupervised parsing via constituency tests.” arXiv preprint arXiv:2010.03146 (2020). ↩︎
Kaplan, Jared, et al. “Scaling laws for neural language models.” arXiv preprint arXiv:2001.08361 (2020). ↩︎
Hoffmann, Jordan, et al. “Training compute-optimal large language models.” arXiv preprint arXiv:2203.15556 (2022). ↩︎