月度归档: 2024 年 5 月

  • Transformer升级之路:逆用Leaky ReRoPE解决推理成本问题

    在上周的文章《Transformer升级之路:12、无限外推的ReRoPE?》中,我们介绍了ReRoPE和Leaky ReRoPE的创新方法。实验结果表明,它们在几乎不损失训练效果的情况下能够扩展LLM的Context长度,并且实现了“longer context, lower loss”的理想特性。尤其是ReRoPE,似乎表现出了无限的Context处理能力。然而,这些方法也带来了推理阶段的成本增加问题。本文将探讨一种新的解决方案:逆用Leaky ReRoPE。

    回顾RoPE与Leaky ReRoPE

    RoPE与位置编码

    RoPE(Rotary Position Embedding)形式上是一种绝对位置编码,但实际上它实现了相对位置编码。其对应的相对位置矩阵为:

    [latex][
    \left(\begin{array}{cccccccccc}
    0 & 1 & 2 & 3 & \cdots & L-2 & L-1\
    -1 & 0 & 1 & 2 & \cdots & L-3 & L-2\
    -2 & -1 & 0 & 1 & \cdots & L-4 & L-3\
    \vdots & \vdots & \vdots & \vdots & \ddots & \vdots & \vdots\
    2-L & 3-L & 4-L & \cdots & -2 & -1 & 0\
    1-L & 2-L & 3-L & \cdots & -3 & -2 & -1\
    \end{array}\right)
    ][/latex]

    Leaky ReRoPE与窗口化处理

    为了在保留局域性的同时避免Long Context导致位置越界问题,Leaky ReRoPE将推理阶段的相对位置矩阵改为:

    [latex][
    \left(\begin{array}{cccccccccc}
    0 & 1 & 2 & \cdots & w-1 & w & \cdots & w+k & \cdots & w+L-1-wk\
    -1 & 0 & 1 & \cdots & w-2 & w-1 & \cdots & w+k-1 & \cdots & w+L-2-wk\
    \vdots & \vdots & \vdots & \ddots & \vdots & \vdots & \ddots & \vdots & \vdots & \vdots\
    -w+1 & -w+2 & -w+3 & \cdots & -1 & 0 & \cdots & k-1 & \cdots & L-2-wk\
    \vdots & \vdots & \vdots & \vdots & \vdots & \vdots & \vdots & \vdots & \vdots & \vdots\
    \end{array}\right)
    ][/latex]

    其中,( w ) 是窗口宽度,( k ) 用来调节可处理的最大长度。

    ReRoPE的无限扩展能力

    ReRoPE直接取了 ( k \to \infty ) 的极限:

    [latex][
    \left(\begin{array}{cccccccccc}
    0 & 1 & 2 & \cdots & w-1 & w & \cdots & w & \cdots & w\
    -1 & 0 & 1 & \cdots & w-2 & w-1 & \cdots & w & \cdots & w\
    \vdots & \vdots & \vdots & \ddots & \vdots & \vdots & \ddots & \vdots & \vdots & \vdots\
    -w+1 & -w+2 & -w+3 & \cdots & -1 & 0 & \cdots & w & \cdots & w\
    \vdots & \vdots & \vdots & \vdots & \vdots & \vdots & \vdots & \vdots & \vdots & \vdots\
    \end{array}\right)
    ][/latex]

    逆用Leaky ReRoPE:让训练阶段变慢,推理阶段变快

    为什么逆用?

    原本的ReRoPE和Leaky ReRoPE在推理阶段增加了计算成本。如果我们反过来在训练阶段使用Leaky ReRoPE,而在推理阶段使用常规的RoPE,能否解决这一问题呢?

    实验与结果

    我们进行了以下实验组合:“GAU + Deep Norm + Tiger + 语言模型”。在训练阶段使用 ( k=1/16, w=128 ) 的Leaky ReRoPE,在推理阶段使用正常的RoPE。测试结果如下:

    测试长度BaselineBaseline-lognNTK-RoPE-fixedNTK-RoPE-logn†-fixedNTK-RoPE-logn-fixedNTK-RoPE-mixedNTK-RoPE-logn†-mixedNTK-RoPE-logn-mixedReRoPE-w256ReRoPE-w256-logn†ReRoPE-w256-lognInvLeaky ReRoPE-w128-lognInvLeaky ReRoPE-w128-b8-lognHFWA512 (训练)
    训练49.41%49.40%49.41%49.41%49.40%49.41%49.41%49.40%49.41%49.41%49.40%49.38%49.62%48.70%
    4096(重复)24.17%24.60%51.86%55.94%62.85%53.09%59.11%68.91%77.90%82.40%85.12%82.25%81.15%80.84%
    4096(不重复)23.16%24.02%39.61%41.11%44.14%40.12%42.38%45.41%48.48%48.85%49.07%48.32%48.85%48.15%

    其中,( b8 ) 是指RoPE的频率底数从10000换成了80000。可以看到,“Leaky ReRoPE → RoPE”的InvLeaky ReRoPE虽然效果上不如“RoPE → ReRoPE/Leaky ReRoPE”,但依然胜过了HFWA,并且由于推理阶段是常规的RoPE,可以套用现成的加速技术,因此依然是有相当竞争力的。

    我们对 [latex]( k, w, b )[/latex] 等参数做了一些简单的调参,发现最优解基本上就是上述两个组合。具体来说:

    调参与训练速度

    • ( k ) 设置为“扩展倍数的2倍的倒数”
    • ( w ) 设置为训练长度的四分之一
    • ( b ) 可选乘以扩展倍数

    在上述实验中,模型参数量为1亿,训练长度为512,每1000步的训练时间从330秒增加到了350秒,增加不到10%。虽然这里有GAU的原因,因为GAU是单头的注意力,本身比多头注意力快。如果是多头注意力或者训练长度更长,增加幅度可能会更大,但估计不会超过50%,依然在可接受范围内。

    小结

    本文提出了Leaky ReRoPE的“逆用”方法,通过在训练阶段使用更大步长的Leaky ReRoPE,使得推理阶段可以退回常规的RoPE,从而保持推理速度不变。实验结果表明,这种方法依然具有相当的竞争力。未来的工作可以进一步优化参数设置,提升模型性能。


    希望这篇文章能够帮助您更好地理解逆用Leaky ReRoPE的方法及其优势。如果有任何疑问或建议,欢迎在评论区留言讨论。

  • 增大Tokenizer词表:LLM续写任务的新挑战与解决方案

    语言模型(LLM)在自然语言处理中的应用越来越广泛,而通过增大Tokenizer的词表来提高压缩率,从而缩短串行长度、降低解码成本,是大家都喜闻乐见的事情。然而,这种方法在带来诸多优点的同时,也可能产生一些问题。本文将探讨增大词表后语言模型在续写任务中遇到的问题,并提出解决方案。

    优劣分析

    优点

    1. 解码速度提升:由于LLM是自回归的,解码过程会随着序列长度的增加变得越来越慢。通过“增大词表 → 提高压缩率 → 缩短串行长度”,可以减少相同文本对应的tokens数量,从而减少解码步数,提升解码速度。
    2. 缓解Exposure Bias:语言模型的训练方式通常是Teacher Forcing,缩短串行长度能够缓解Teacher Forcing带来的Exposure Bias问题,从而可能提升模型效果。

    缺点

    1. 割裂字符联系:增大词表可能会割裂token与token之间在字符层面的联系,影响模型的泛化能力。例如,“太阳能”和“太阳”都是词表中的一个词时,模型可能不知道“太阳能”是由“太阳”和“能”组成,从而难以完成一些子词相关的任务。
    2. 续写问题:增大词表后,常见的命令或短语可能被视为单个token,导致模型在续写时无法正确生成。例如,“import numpy as np”被当作一个token,用户输入“import numpy”时,模型无法续写出“ as np”。

    续写问题

    Armen Aghajanyan分享了一个典型的例子:在训练代码模型时使用超大词表,导致“import numpy as np”变成了一个token。当用户输入“import numpy”时,模型无法续写出“ as np”。这种现象在自然语言模型中也很常见。例如,“太阳能”和“太阳”都是独立的token时,用户输入“太阳”后,模型续写出的内容可能不符合用户的期望。

    参考对策

    虽然Armen Aghajanyan提到的问题确实存在,但笔者认为通过适当的处理,这个问题不仅可以解决,还能转化为增大词表的优点。以下是一个可行的解决方案:

    基于词表的前缀搜索

    假设用户输入了“广州的白云”,Tokenizer将其分为“广州/的/白云”。此时,如果直接将这三个词转换为id输入模型,模型可能无法续写出“广州/的/白云机场”等结果。因此,我们可以进行以下步骤:

    1. 前缀搜索:对“白云”进行词表的前缀搜索,假设搜索结果为“白云”、“白云机场”、“白云山”、“白云路”四个词。
    2. 计算条件概率:用LLM计算以下条件概率:
      [latex][p(\text{白云}|\text{广州, 的})p(\text{白云机场}|\text{广州, 的})p(\text{白云山}|\text{广州, 的})p(\text{白云路}|\text{广州, 的})][/latex]
    3. 归一化与采样:将条件概率归一化后进行采样,决定续写内容。例如,采样结果为“白云机场”,则输出“机场”,并按照“广州/的/白云机场”进行续写。

    这种方法不仅解决了Armen Aghajanyan所提到的问题,还能在词表压缩率高的情况下,一次性生成更多的字。特别地,回退操作只需在采样第一步进行,从第二步开始就不需要回退操作,计算量很少。

    文章小结

    本文介绍了增大词表后LLM在续写任务中可能出现的问题,并分享了参考的解决方案。通过结合基于LLM的续写和基于词表的前缀搜索,可以有效地解决续写问题,并将增大词表的缺点转化为优点。希望这些思路能为语言模型的进一步优化提供参考。

  • Viterbi Sampling算法的改进与完善

    在自然语言处理领域,分词是一个至关重要的步骤。最近,一篇名为《随机分词浅探:从Viterbi Decoding到Viterbi Sampling》的文章中,作者提出了一种名为“Viterbi Sampling”的随机分词算法。本文将详细讨论该算法的改进,并从数学上证明其效果可以与Subword Regularization等价。

    问题分析

    在知乎的评论中,用户 @鹤舞 指出,当前的采样算法可能会在多次二选一的过程中“稀释”了部分方案的出现概率,导致原本分数最高的切分并不是以最高概率出现。

    例如,假设有三种切分方案,每种方案的得分都一样,理应每种方案的出现概率都是1/3。然而,Viterbi Sampling算法将多选一的过程拆分成多步的二选一,从而导致概率分布发生偏移。

    示例分析

    以单词“watching”为例,有三种切分方案:watch ing, wat ching, 和 w atching。按照Viterbi Sampling的操作,先在前两种方案中选择,概率均为1/2;然后再与第三种方案比较,概率依然为1/2。最终,前两种方案的出现概率为1/4,而第三种方案的出现概率变为了1/2。

    解决办法

    为了解决上述问题,可以采用“水塘采样(Reservoir sampling)”的算法。具体来说,每次进行二选一后,同时缓存累积概率,并在后续的二选一过程中使用累积概率进行比较。

    具体实现

    假设前两种切分方案的概率均为1/3,选择其中一种后,总的累积概率为2/3。接下来,新方案被选中的概率为1/3,而不是1/2。这保证了每种方案的出现概率均保持为1/3。

    在实际计算时,为避免指数爆炸问题,可以缓存对数形式的概率,并利用logsumexp函数避免溢出。

    Zlogi = logsumexp(Zlogi-1, αsi)

    相应的实现已经内置在bytepiece>=0.5.0中。

    完美采样的证明

    为了证明改进后的Viterbi Sampling算法是“完美采样”,我们需要回顾Viterbi Decoding的基本原理。Viterbi Decoding通过动态规划找出最优的分词方案,其子串也必须是对应子字节串的最优切分方案。

    数学推导

    通过动态规划,可以计算出每个位置的最优切分方案及其得分。而在Viterbi Sampling中,我们需要对所有切分方案进行采样,其采样概率应与得分成正比。

    Z(c1, c2, ..., cl) = ∑ Z(c1, ..., ck) * e^(α * s(ck+1, ..., cl))

    通过逐步计算累积权重Z,可以实现对所有切分方案的完美采样。

    递归式转换

    在实际计算中,使用对数形式的累积权重Zlog,并通过logsumexp函数进行累积计算。

    Zlog(c1, c2, ..., cl) = logsumexp(Zlog(c1, ..., ck) + α * s(ck+1, ..., cl))

    这样可以避免直接计算指数导致的溢出问题。

    文章小结

    本文通过详细分析和数学推导,完善了之前提出的Viterbi Sampling算法。改进后的算法不仅解决了概率“稀释”问题,而且在效果上与Subword Regularization等价,同时在使用效率上更具优势。

    通过这些改进,Viterbi Sampling算法在实际应用中将具备更高的可靠性和效率,为自然语言处理领域的分词任务提供了更优的解决方案。

  • 探索线性Attention的局限性:从“集中注意力”角度出发

    近年来,Transformer架构在自然语言处理领域取得了显著的成果,而Attention机制则是其核心所在。然而,随着研究的深入,传统的标准Attention机制暴露出了一些计算复杂度和资源需求上的问题,这促使研究者们开始探索更高效的线性Attention。然而,线性Attention在实际效果上却一直不如标准Attention。本文将从“集中注意力”的角度,探讨线性Attention的局限性,并尝试给出一个合理的解释。

    Attention机制的稀疏性

    什么是稀疏性?

    在《从熵不变性看Attention的Scale操作》一文中,我们用信息熵来度量Attention的“集中注意力”程度。熵越低,Attention越有可能集中在某个token上。然而,信息熵只能用于归一化且非负的Attention矩阵,这限制了其适用范围。因此,我们引入了另一种稀疏性度量指标:S(x) = E[|x|] / sqrt(E[x^2])。这个指标与信息熵类似,S(x)越小,表示对应的随机矢量越稀疏,即越有可能“一家独大”。

    标准Attention的稀疏性

    对于标准Attention机制,f = exp,我们可以推导出其稀疏性:

    S(a) = exp(-1/2 * σ^2 * ||q||^2)

    σ||q||趋向无穷大时,S(a)趋向于0,这意味着标准Attention可以任意稀疏地“集中注意力”。

    GAU的稀疏性

    对于Gated Attention Unit (GAU)机制,f = relu2,其稀疏性较为复杂,但通过计算可以发现,只有当偏置项β小于0时,稀疏性才有机会趋于0。这表明,GAU在某些条件下也能实现较高的稀疏性。

    线性Attention的局限性

    极简线性Attention

    对于最简单的线性Attention,即不加任何激活函数f = identical,其稀疏性为:

    S(a) = sqrt(2/π * γ * exp(-β^2/(2γ^2)) + β * erf(β/(2√γ)) / (β^2 + γ^2))

    从图像可以看出,极简线性Attention的稀疏性存在一个较高的下限,这意味着它难以“集中注意力”到关键位置上。

    一般线性Attention

    线性Attention的一般形式为a_j ∝ g(q) ⋅ h(k_j),其稀疏性为:

    S(a) = 1 / sqrt(1 + (σ~ * μ~ * ||q~||_2 / ||q~||_1)^2)

    这表明,要想线性Attention变得稀疏,可以通过降低k~串行的信噪比或增大q的模长。然而,非负型线性Attention通常只能表示绝对位置的重要性,难以表达相对位置的重要性。

    线性衰减Attention

    对于带有显式递归的线性RNN模型,其稀疏性为:

    S(a) = 1 - λ^n / n(1 - λ) * sqrt(1 + λ / (1 + λ^n))

    λ < 1时,随着n趋向无穷大,S(a)趋向0。这意味着这种模型可以实现较高的稀疏性,但其注意力仅能表达固定不变的注意力衰减,难以自适应地关注到长距离的上下文。

    结论

    本文通过Attention矩阵的稀疏程度,考察了不同Attention机制的潜力,得出以下结论:

    1. 标准Attention可以实现任意稀疏的注意力矩阵。
    2. 线性Attention难以实现高稀疏性,尤其是在表示相对位置的重要性时。
    3. 带有显式衰减的线性Attention可以实现稀疏性,但其注意力固定,难以自适应。

    这些发现或许能够解释线性Attention在实际效果上略逊一筹的原因。线性Attention在“集中注意力”方面存在固有的局限性,这使得它在处理复杂上下文时表现不如标准Attention。未来的研究或许需要在如何提高线性Attention的稀疏性和灵活性上继续努力,以期实现更高效且性能优越的Transformer模型。

    参考文献

    1. 《Transformer升级之路:3、从Performer到线性Attention》
    2. 《为什么现在的LLM都是Decoder-only的架构?》
    3. 《从熵不变性看Attention的Scale操作》
    4. 《FLASH:可能是近来最有意思的高效Transformer设计》
    5. 《相对位置编码Transformer的一个理论缺陷与对策》
    6. 《如何度量数据的稀疏程度?》
    7. 《线性Attention的探索:Attention必须有个Softmax吗?》
    8. 《Google新作试图“复活”RNN:RNN能否再次辉煌?》

    通过上述分析,我们不仅理解了不同Attention机制的稀疏性差异,还揭示了线性Attention在实际应用中的局限性。希望本文的讨论能够为未来的研究提供一些新的思路和方向。

  • 深度学习中的状态空间模型(SSM)初探

    引言

    前几天,笔者看了几篇介绍SSM(State Space Model)的文章,才发现原来自己从未认真了解过SSM,于是打算认真去学习一下SSM的相关内容,顺便开了这个新坑,记录一下学习所得。

    SSM的概念由来已久,但这里我们特指深度学习中的SSM,一般认为其开篇之作是2021年的S4,不算太老,而SSM最新最火的变体大概是去年的Mamba。当然,当我们谈到SSM时,也可能泛指一切线性RNN模型,这样RWKV、RetNet还有此前我们在《Google新作试图“复活”RNN:RNN能否再次辉煌?》介绍过的LRU都可以归入此类。不少SSM变体致力于成为Transformer的竞争者,尽管笔者并不认为有完全替代的可能性,但SSM本身优雅的数学性质也值得学习一番。

    尽管我们说SSM起源于S4,但在S4之前,SSM有一篇非常强大的奠基之作《HiPPO: Recurrent Memory with Optimal Polynomial Projections》(简称HiPPO),所以本文从HiPPO开始说起。

    基本形式

    先插句题外话,上面提到的SSM代表作HiPPO、S4、Mamba的一作都是Albert Gu,他还有很多篇SSM相关的作品,毫不夸张地说,这些工作筑起了SSM大厦的基础。不论SSM前景如何,这种坚持不懈地钻研同一个课题的精神都值得我们由衷地敬佩。

    言归正传。对于事先已经对SSM有所了解的读者,想必知道SSM建模所用的是线性ODE系统:

    [latex][ x′(t) = Ax(t) + Bu(t) ][/latex]
    [latex][ y(t) = Cx(t) + Du(t) ][/latex]

    其中 [latex]( u(t) \in \mathbb{R}^{d_i}, x(t) \in \mathbb{R}^d, y(t) \in \mathbb{R}^{d_o}, A \in \mathbb{R}^{d \times d}, B \in \mathbb{R}^{d \times d_i}, C \in \mathbb{R}^{d_o \times d}, D \in \mathbb{R}^{d_o \times d_i} )[/latex]。当然我们也可以将它离散化,那么就变成一个线性RNN模型,这部分我们在后面的文章再展开。不管离散化与否,其关键词都是“线性”,那么马上就有一个很自然的问题:为什么是线性系统?线性系统够了吗?

    我们可以从两个角度回答这个问题:线性系统既足够简单,也足够复杂。简单是指从理论上来说,线性化往往是复杂系统的一个最基本近似,所以线性系统通常都是无法绕开的一个基本点;复杂是指即便如此简单的系统,也可以拟合异常复杂的函数,为了理解这一点,我们只需要考虑一个 [latex]( \mathbb{R}^4 )[/latex] 的简单例子:

    [latex][ x′(t) = \begin{pmatrix} 1 & 0 & 0 & 0 \ 0 & -1 & 0 & 0 \ 0 & 0 & 0 & 1 \ 0 & 0 & -1 & 0 \end{pmatrix} x(t) ][/latex]

    这个例子的基本解是 [latex]( x(t) = (e^t, e^{-t}, \sin t, \cos t) )[/latex]。这意味着只要 [latex]( d )[/latex] 足够大,该线性系统就可以通过指数函数和三角函数的组合来拟合足够复杂的函数,而我们知道拟合能力很强的傅里叶级数也只不过是三角函数的组合,如果再加上指数函数显然就更强了,因此可以想象线性系统也有足够复杂的拟合能力。

    当然,这些解释某种意义上都是“马后炮”。HiPPO给出的结果更加本质:当我们试图用正交基去逼近一个动态更新的函数时,其结果就是如上的线性系统。这意味着,HiPPO不仅告诉我们线性系统可以逼近足够复杂的函数,还告诉我们怎么去逼近,甚至近似程度如何。

    有限压缩

    接下来,我们只考虑 [latex]( d_i = 1 )[/latex] 的特殊情形,[latex]( d_i > 1 )[/latex] 只不过是 [latex]( d_i = 1 )[/latex] 时的并行推广。此时,[latex]( u(t) )[/latex] 的输出是一个标量,进一步地,作为开头我们先假设 [latex]( t \in [0, 1] )[/latex],HiPPO的目标是:用一个有限维的矢量来储存这一段 [latex]( u(t) )[/latex] 的信息。

    看上去这是一个不大可能的需求,因为 [latex]( t \in [0, 1] )[/latex] 意味着 [latex]( u(t) )[/latex] 可能相当于无限个点组成的矢量,压缩到一个有限维的矢量可能严重失真。不过,如果我们对 [latex]( u(t) )[/latex] 做一些假设,并且允许一些损失,那么这个压缩是有可能做到的,并且大多数读者都已经尝试过。比如,当 [latex]( u(t) )[/latex] 在某点 ( n+1 ) 阶可导的,它对应的 ( n ) 阶泰勒展开式往往是 [latex]( u(t) )[/latex] 的良好近似,于是我们可以只储存展开式的 ( n+1 ) 个系数来作为 [latex]( u(t) )[/latex] 的近似表征,这就成功将 [latex]( u(t) )[/latex] 压缩为一个 ( n+1 ) 维矢量。

    当然,对于实际遇到的数据来说,“( n+1 ) 阶可导”这种条件可谓极其苛刻,我们通常更愿意使用在平方可积条件下的正交函数基展开,比如傅里叶(Fourier)级数,它的系数计算公式为:

    [latex][ c_n = \int_0^1 u(t) e^{-2i\pi nt} dt ][/latex]

    这时候取一个足够大的整数 [latex]( N )[/latex],只保留 [latex]( |n| \leq N )[/latex] 的系数,那么就将 [latex]( u(t) )[/latex] 压缩为一个 ( 2N+1 ) 维的矢量了。

    接下来,问题难度就要升级了。刚才我们说 [latex]( t \in [0, 1] )[/latex],这是一个静态的区间,而实际中 [latex]( u(t) )[/latex] 代表的是持续采集的信号,所以它是不断有新数据进入的,比如现在我们近似了 [latex]( [0, 1] )[/latex] 区间的数据,马上就有 [latex]( [1, 2] )[/latex] 的数据进来,你需要更新逼近结果来试图记忆整个 ( [0, 2] ) 区间,接下来是 ( [0, 3] )、( [0, 4] ) 等等,这我们称为“在线函数逼近”。而上面的傅里叶系数公式只适用于区间 ( [0, 1] ),因此需要将它进行推广。

    为此,我们设 [latex]( t \in [0, T] ),( s \mapsto t \leq T(s) )[/latex] 是 ( [0, 1] ) 到 ( [0, T] ) 的一个映射,那么 [latex]( u(t \leq T(s)) )[/latex] 作为 ( s ) 的函数时,它的定义区间就是 [latex]( [0, 1] )[/latex],于是就可以复用傅里叶系数公式:

    [latex][ c_n(T) = \int_0^1 u(t \leq T(s)) e^{-2i\pi ns} ds ][/latex]

    这里我们已经给系数加了标记 [latex]( (T) )[/latex],以表明此时的系数会随着 [latex]( T )[/latex] 的变化而变化。

    线性初现

    能将 [latex]( [0, 1] )[/latex] 映射到 [latex]( [0, T] )[/latex] 的函数有无穷多,而最终结果也因 [latex]( t \leq T(s) )[/latex] 而异,一些比较直观且相对简单的选择如下:

    1. [latex]( t \leq T(s) = sT )[/latex],即将 ( [0, 1] ) 均匀地映射到 ( [0, T] );
    2. 注意 [latex]( t \leq T(s) )[/latex] 并不必须是满射,所以像 [latex]( t \leq T(s) = s + T – 1 )[/latex] 也是允许的,这意味着只保留了最邻近窗口 ( [T – 1, T] ) 的信息,丢掉了更早的部分,更一般地有 [latex]( t \leq T(s) = sw + T – w )[/latex],其中 ( w ) 是一个常数,这意味着 ( T – w ) 前的信息被丢掉了;
    3. 也可以选择非均匀映射,比如 [latex]( t \leq T(s) = T\sqrt{s} )[/latex],它同样是 ( [0, 1] ) 到 ( [0, T] ) 的满射,但 ( s = 1/4 ) 时就映射到 ( T/2 ) 了,这意味着我们虽然关注全局的历史,但同时更侧重于 ( T ) 时刻附近的信息。

    现在我们以 [latex]( t \leq T(s) = (s + 1)w/2 + T – w )[/latex] 为例,代入傅里叶系数公式得到:

    [latex][ c_n(T) = \int_0^1 u(sw + T – w) e^{-2i\pi ns} ds ][/latex]

    现在我们两边求关于 ( T ) 的导数:

    [latex][ \frac{d}{dT} c_n(T) = \frac{1}{w} \left[ u(T) – u(T – w) \right] + \frac{2i\pi n}{w} c_n(T) ][/latex]

    其中我们用了分部积分公式。由于我们只保留了 [latex]( |n| \leq N )[/latex] 的系数,所以根据傅里叶级数的公式,可以认为如下是 [latex]( u(sw + T – w) )[/latex] 的一个良好近似:

    [latex][ u(sw + T – w) \approx \sum_{k=-N}^N c_k(T) e^{2i\pi ks} ][/latex]

    那么 [latex]( u(T – w) = u(sw + T – w) \big|{s=0} \approx \sum{k=-N}^N c_k(T) )[/latex],代入上式得:

    [latex][ \frac{d}{dT} c_n(T) \approx \frac{1}{w} \left[ u(T) – \sum_{k=-N}^N c_k(T) \right] + \frac{2i\pi n}{w} c_n(T) ][/latex]

    将 ( T ) 换成 ( t ),然后所有的 [latex]( c_n(t) )[/latex] 堆在一起记为 [latex]( x(t) = (c_{-N}, c_{-(N-1)}, \ldots, c_0, \ldots, c_{N-1}, c_N) )[/latex],并且不区分 [latex]( \approx )[/latex] 和 [latex]( = )[/latex],那么就可以写出:

    [latex][ x′(t) = A x(t) + B u(t) ][/latex]

    其中:

    [latex][ A_{n,k} = \begin{cases} \frac{2i\pi n – 1}{w}, & k = n \ -\frac{1}{w}, & k \ne n \end{cases}, \quad B_n = \frac{1}{w} ][/latex]

    这就出现了如上所示的线性ODE系统。即当我们试图用傅里叶级数去记忆一个实时函数的最邻近窗口内的状态时,结果自然而然地导致了一个线性ODE系统。

    一般框架

    当然,目前只是选择了一个特殊的 [latex]( t \leq T(s) )[/latex],换一个 [latex]( t \leq T(s) )[/latex] 就不一定有这么简单的结果了。此外,傅里叶级数的结论是在复数范围内的,进一步实数化也可以,但形式会变得复杂起来。所以,我们要将这一过程推广成一个一般化的框架,从而得到更一般、更简单的纯实数结论。

    设 [latex]( t \in [a, b] )[/latex],并且有目标函数 [latex]( u(t) )[/latex] 和函数基 [latex]( { g_n(t) }_{n=0}^N )[/latex],我们希望有后者的线性组合来逼近前者,目标是最小化 [latex]( L^2 )[/latex] 距离:

    [latex][ \arg\min_{c_1, \ldots, c_N} \int_a^b \left[ u(t) – \sum_{n=0}^N c_n g_n(t) \right]^2 dt ][/latex]

    这里我们主要在实数范围内考虑,所以方括号直接平方就行,不用取模。更一般化的目标函数还可以再加个权重函数 [latex]( \rho(t) )[/latex],但我们这里就不考虑了,毕竟HiPPO的主要结论其实也没考虑这个权重函数。

    对目标函数展开,得到:

    [latex][ \int_a^b u^2(t) dt – 2 \sum_{n=0}^N c_n \int_a^b u(t) g_n(t) dt + \sum_{m=0}^N \sum_{n=0}^N c_m c_n \int_a^b g_m(t) g_n(t) dt ][/latex]

    这里我们只考虑标准正交函数基,其定义为 [latex]( \int_a^b g_m(t) g_n(t) dt = \delta_{m,n} ),( \delta_{m,n} )[/latex] 是克罗内克δ函数,此时上式可以简化成:

    [latex][ \int_a^b u^2(t) dt – 2 \sum_{n=0}^N c_n \int_a^b u(t) g_n(t) dt + \sum_{n=0}^N c_n^2 ][/latex]

    这只是一个关于 [latex]( c_n )[/latex] 的二次函数,它的最小值是有解析解的:

    [latex][ c^*_n = \int_a^b u(t) g_n(t) dt ][/latex]

    这也被称为 [latex]( u(t) )[/latex] 与 [latex]( g_n(t) )[/latex] 的内积,它是有限维矢量空间的内积到函数空间的并行推广。简单起见,在不至于混淆的情况下,我们默认 [latex]( c_n )[/latex] 就是 [latex]( c^*_n )[/latex]。

    接下来的处理跟上一节是一样的,我们要对一般的 [latex]( t \in [0, T] )[/latex] 考虑 [latex]( u(t) )[/latex] 的近似,那么找一个 [latex]( [a, b] )[/latex] 到 [latex]( [0, T] )[/latex] 的映射 [latex]( s \mapsto t \leq T(s) )[/latex],然后计算系数:

    [latex][ c_n(T) = \int_a^b u(t \leq T(s)) g_n(s) ds ][/latex]

    同样是两边求 [latex]( T )[/latex] 的导数,然后用分部积分法:

    [latex][ \frac{d}{dT} c_n(T) = \int_a^b u'(t \leq T(s)) \frac{\partial t \leq T(s)}{\partial T} g_n(s) ds ][/latex]

    [latex][ = \int_a^b \left( \frac{\partial t \leq T(s)}{\partial T} / \frac{\partial t \leq T(s)}{\partial s} \right) g_n(s) du(t \leq T(s)) ][/latex]

    [latex][ = \left( \frac{\partial t \leq T(s)}{\partial T} / \frac{\partial t \leq T(s)}{\partial s} \right) g_n(s) \bigg|_{s=b}^{s=a} – \int_a^b u(t \leq T(s)) d \left[ \left( \frac{\partial t \leq T(s)}{\partial T} / \frac{\partial t \leq T(s)}{\partial s} \right) g_n(s) \right] ][/latex]

    请勒让德

    接下来的计算,就依赖于 [latex]( g_n(t) )[/latex] 和 [latex]( t \leq T(s) )[/latex] 的具体形式了。HiPPO的全称是High-order Polynomial Projection Operators,第一个P正是多项式(Polynomial)的首字母,所以HiPPO的关键是选取多项式为基。现在我们请出继傅里叶之后又一位大牛——勒让德(Legendre),接下来我们要选取的函数基正是以他命名的“勒让德多项式”。

    勒让德多项式 [latex]( p_n(t) )[/latex] 是关于 [latex]( t )[/latex] 的 [latex]( n )[/latex] 次函数,定义域为 [latex]( [-1, 1] )[/latex],满足:

    [latex][ \int_{-1}^1 p_m(t) p_n(t) dt = \frac{2}{2n+1} \delta_{m,n} ][/latex]

    所以 [latex]( p_n(t) )[/latex] 之间只是正交,还不是标准(平分积分为1),[latex]( g_n(t) = \sqrt{\frac{2n+1}{2}} p_n(t) )[/latex] 才是标准正交基。

    当我们对函数基 [latex]( {1, t, t^2, \ldots, t^n} )[/latex] 执行施密特正交化时,其结果正是勒让德多项式。相比傅里叶基,勒让德多项式的好处是它是纯粹定义在实数空间中的,并且多项式的形式能够有助于简化部分 [latex]( t \leq T(s) )[/latex] 的推导过程,这一点我们后面就可以看到。勒让德多项式有很多不同的定义和性质,这里我们不一一展开,有兴趣的读者自行看维基百科介绍即可。

    接下来我们用到两个递归公式来推导一个恒等公式,这两个递归公式是:

    [latex][ p′_{n+1}(t) – p′_{n-1}(t) = (2n+1) p_n(t) ][/latex]
    [latex][ p′_{n+1}(t) = (n+1) p_n(t) + t p′_n(t) ][/latex]

    由第一个公式迭代得到:

    [latex][ p′_{n+1}(t) = (2n+1) p_n(t) + (2n−3) p_{n−2}(t) + (2n-7) p_{n-4}(t) + ⋯ = \sum_{k=0}^n (2k+1) χ_{n−k} p_k(t) ][/latex]

    其中当 [latex]( k )[/latex] 是偶数时 [latex]( χ_k = 1 )[/latex] 否则 [latex]( χ_k = 0 )[/latex] 。代入第二个公式得到:

    [latex][ t p′_n(t) = n p_n(t) + (2n−3) p{n-2}(t) + (2n-7) p_{n-4}(t) + ⋯ ][/latex]

    继而有:

    [latex][ (t+1) p′_n(t) = n p_n(t) + (2n-1) p_{n−1}(t) + (2n-3) p_{n-2}(t) + ⋯ = – (n+1) p_n(t) + \sum_{k=0}^n (2k+1) p_k(t) ][/latex]

    这些就是等会要用到的恒等式。此外,勒让德多项式满足 ( p_n(1) = 1, p_n(-1) = (-1)^n ),这个边界值后面也会用到。

    正如 ( n ) 维空间中不止有一组正交基也一样,正交多项式也不止有勒让德多项式一种,比如还有切比雪夫(Chebyshev)多项式,如果算上加权的目标函数(即 [latex]( ρ(t) ≢ 1 )[/latex] ),还有拉盖尔多项式等,这些在原论文中都有提及,但HiPPO的主要结论还是基于勒让德多项式展开的,所以剩余部分这里也不展开讨论了。

    邻近窗口

    完成准备工作后,我们就可以代入具体的 [latex]( t ≤ T(s) )[/latex] 进行计算了,计算过程跟傅里叶级数的例子大同小异,只不过基函数换成了勒让德多项式构造的标准正交基 [latex]( g_n(t) = \sqrt{\frac{2n+1}{2}} p_n(t) )[/latex]。作为第一个例子,我们同样先考虑只保留最邻近窗口的信息,此时 [latex]( t ≤ T(s) = \frac{(s+1)w}{2} + T – w )[/latex] 将 [latex]( [−1, 1] )[/latex] 映射到 [latex]( [T−w, T] )[/latex],原论文将这种情形称为“LegT(Translated Legendre)”。

    直接代入之前得到的公式,马上得到:

    [latex][ \frac{d}{dT} c_n(T) = \sqrt{\frac{2(2n+1)}{w}} [u(T) – (−1)^n u(T−w)] – \frac{2}{w} \int_{-1}^1 u\left(\frac{(s+1)w}{2} + T – w\right) g′_n(s) ds ][/latex]

    我们首先处理 [latex]( u(T−w) )[/latex] 项,跟傅里叶级数那里同样的思路,我们截断 ( n ≤ N ) 作为 [latex]( u\left(\frac{(s+1)w}{2} + T – w\right) )[/latex] 的一个近似:

    [latex][ u\left(\frac{(s+1)w}{2} + T – w\right) ≈ \sum_{k=0}^N c_k(T) g_k(s) ][/latex]

    从而有 [latex]( u(T−w) ≈ \sum_{k=0}^N c_k(T) g_k(−1) = \sum_{k=0}^N (−1)^k c_k(T) \sqrt{\frac{2k+1}{2}} )[/latex] 。接着,利用之前的递归公式得到:

    [latex][ \int_{-1}^1 u\left(\frac{(s+1)w}{2} + T – w\right) g′n(s) ds = \int{-1}^1 u\left(\frac{(s+1)w}{2} + T – w\right) \sqrt{\frac{2n+1}{2}} p′_n(s) ds ][/latex]

    [latex][ = \int_{-1}^1 u\left(\frac{(s+1)w}{2} + T – w\right) \sqrt{\frac{2n+1}{2}} \left[\sum_{k=0}^{n-1} (2k+1) \chi_{n-1-k} p_k(s) \right] ds ][/latex]

    [latex][ = \int_{-1}^1 u\left(\frac{(s+1)w}{2} + T – w\right) \sqrt{\frac{2n+1}{2}} \left[\sum_{k=0}^{n-1} \sqrt{2(2k+1)} \chi_{n-1-k} g_k(s) \right] ds ][/latex]

    [latex][ = \sqrt{\frac{2n+1}{2}} \sum_{k=0}^{n-1} \sqrt{2(2k+1)} \chi_{n-1-k} c_k(T) ][/latex]

    将这些结果集成起来,就有:

    [latex][ \frac{d}{dT} c_n(T) ≈ \sqrt{\frac{2(2n+1)}{w}} u(T) – \sqrt{\frac{2(2n+1)}{w}} (−1)^n \sum_{k=0}^N (−1)^k c_k(T) \sqrt{\frac{2k+1}{2}} – \frac{2}{w} \sqrt{\frac{2n+1}{2}} \sum_{k=0}^{n-1} \sqrt{2(2k+1)} \chi_{n-1-k} c_k(T) ][/latex]

    再次地,将 [latex]( T )[/latex] 换回 [latex]( t )[/latex],并将所有的 [latex]( c_n(t) )[/latex] 堆在一起记为 [latex]( x(t) = (c_0, c_1, ⋯, c_N) )[/latex],那么根据上式可以写出:

    [latex][ x′(t) = A x(t) + B u(t) ][/latex]

    其中:

    [latex][ A_{n,k} = \begin{cases} -\frac{2}{w} \sqrt{\frac{(2n+1)(2k+1)}{2}}, & k < n \ -\frac{2}{w} \sqrt{\frac{(2n+1)(2k+1)}{2}} (−1)^{n−k}, & k ≥ n \end{cases}, \quad B_n = \sqrt{\frac{2(2n+1)}{w}} ][/latex]

    我们还可以给每个 [latex]( c_n(T) )[/latex] 都引入一个缩放因子,来使得上述结果更一般化。比如我们设 [latex]( c_n(T) = λ_n \tilde{c}_n(T) )[/latex],代入上式整理得:

    [latex][ \frac{d}{dT} \tilde{c}n(T) ≈ \sqrt{\frac{2(2n+1)}{w}} \frac{u(T)}{λ_n} – \sqrt{\frac{2(2n+1)}{w}} \frac{(−1)^n}{λ_n} \sum{k=0}^N \frac{(−1)^k c_k(T)}{λk} \sqrt{\frac{2k+1}{2}} – \frac{2}{w} \sqrt{\frac{2n+1}{2}} \sum{k=0}^{n-1} \frac{λk}{λ_n} \sqrt{2(2k+1)} \chi{n-1-k} \tilde{c}_k(T) ][/latex]

    如果取 [latex]( λ_n = \sqrt{2} )[/latex],那么 ( A ) 不变,[latex]( B_n = \sqrt{2(2n+1)} )[/latex],这就对齐了原论文的结果。如果取 [latex]( λ_n = \sqrt{\frac{2}{2n+1}} )[/latex],那么就得到了Legendre Memory Units中的结果:

    [latex][ x′(t) = A x(t) + B u(t) ][/latex]

    其中:

    [latex][ A_{n,k} = \begin{cases} 2n+1, & k < n \ (−1)^{n−k} (2n+1), & k ≥ n \end{cases}, \quad B_n = 2n+1 ][/latex]

    这些形式在理论上都是等价的,但可能存在不同的数值稳定性。比如一般来说当 [latex]( u(t) )[/latex] 的性态不是特别糟糕时,我们可以预期 [latex]( n )[/latex] 越大,[latex]( |c_n| )[/latex] 的值就相对越小,这样直接用 [latex]( c_n )[/latex] 的话 [latex]( x(t) )[/latex] 矢量的每个分量的尺度就不大对等,这样的系统在实际计算时容易出现数值稳定问题,而取 [latex]( λ_n = \sqrt{\frac{2}{2n+1}} )[/latex] 改用 [latex]( \tilde{c}_n )[/latex] 的话意味着数值小的分量会被适当放大,可能有助于缓解多尺度问题从而使得数值计算更稳定。

    整个区间

    现在我们继续计算另一个例子:[latex]( t ≤ T(s) = \frac{(s+1)T}{2} )[/latex],它将 [latex]( [−1, 1] )[/latex] 均匀映射到 [latex]( [0, T] )[/latex],这意味着我们没有舍弃任何历史信息,并且平等地对待所有历史,原论文将这种情形称为“LegS(Scaled Legendre)”。

    同样地,通过代入之前得到的公式:

    [latex][ \frac{d}{dT} c_n(T) = \sqrt{\frac{2(2n+1)}{T}} u(T) – \frac{1}{T} \int_{-1}^1 u\left(\frac{(s+1)T}{2}\right) (s+1) g′_n(s) ds ][/latex]

    利用之前的递归公式得到:

    [latex][ \int_{-1}^1 u\left(\frac{(s+1)T}{2}\right) (s+1) g′n(s) ds = \int{-1}^1 u\left(\frac{(s+1)T}{2}\right) \left[g_n(s) + (s+1) g′_n(s)\right] ds ][/latex]

    [latex][ = c_n(T) + \int_{-1}^1 u\left(\frac{(s+1)T}{2}\right) \sqrt{\frac{2n+1}{2}} p′_n(s) ds ][/latex]

    [latex][ = c_n(T) + \int_{-1}^1 u\left(\frac{(s+1)T}{2}\right) \left[-(n+1) g_n(s) + \sum_{k=0}^n \sqrt{(2n+1)(2k+1)} g_k(s)\right] ds ][/latex]

    [latex][ = c_n(T) – n c_n(T) + \sum_{k=0}^n \sqrt{(2n+1)(2k+1)} c_k(T) ][/latex]

    于是有:

    [latex][ \frac{d}{dT} c_n(T) = \sqrt{\frac{2(2n+1)}{T}} u(T) – \frac{1}{T} \left(-n c_n(T) + \sum_{k=0}^n \sqrt{(2n+1)(2k+1)} c_k(T)\right) ][/latex]

    将 ( T ) 换回 ( t ),将所有的 ( c_n(t) ) 堆在一起记为 [latex]( x(t) = (c_0, c_1, ⋯, c_N) )[/latex],那么根据上式可以写出:

    [latex][ x′(t) = A x(t) + B u(t) ][/latex]

    其中:

    [latex][ A_{n,k} = \begin{cases} \sqrt{(2n+1)(2k+1)}, & k < n \ n+1, & k = n \ 0, & k > n \end{cases}, \quad B_n = \sqrt{2(2n+1)} ][/latex]

    引入缩放因子来一般化结果也是可行的:设 [latex]( c_n(T) = λ_n \tilde{c}_n(T) )[/latex],代入上式整理得:

    [latex][ \frac{d}{dT} \tilde{c}n(T) = \sqrt{\frac{2(2n+1)}{T}} \frac{u(T)}{λ_n} – \frac{1}{T} \left(-n \tilde{c}_n(T) + \sum{k=0}^n \sqrt{(2n+1)(2k+1)} \frac{λ_k}{λ_n} \tilde{c}_k(T)\right) ][/latex]

    取 [latex]( λ_n = \sqrt{\frac{2}{2n+1}} )[/latex],就可以让 ( A ) 不变,[latex]( B_n = \sqrt{2(2n+1)} )[/latex],就对齐了原论文的结果。如果取 [latex]( λ_n = \sqrt{\frac{2}{2n+1}} )[/latex],就可以像上一节LegT的结果一样去掉根号:

    [latex][ x′(t) = A x(t) + B u(t) ][/latex]

    其中:

    [latex][ A_{n,k} = \begin{cases} 2(2n+1), & k < n \ n+1, & k = n \ 0, & k > n \end{cases}, \quad B_n = 2(2n+1) ][/latex]

    但原论文没有考虑这种情况,原因不详。

    延伸思考

    回顾Leg-S的整个推导,我们可以发现其中关键一步是将 [latex]( (s+1) g′_n(s) )[/latex] 拆成 [latex]( g_0(s), g_1(s), ⋯, g_n(s) )[/latex] 的线性组合,对于正交多项式来说,[latex]( (s+1) g′_n(s) )[/latex] 是一个 [latex]( n )[/latex] 次多项式,所以这种拆分必然可以精确成立,但如果是傅立叶级数的情况,[latex]( g_n(s) )[/latex] 是指数函数,此时类似的拆分做不到了,至少不能精确地做到,所以可以说选取正交多项式为基的根本目的是简化后面推导。

    特别要指出的是,HiPPO是一个自下而上的框架,它并没有一开始就假设系统必须是线性的,而是从正交基逼近的角度反过来推出其系数的动力学满足一个线性ODE系统,这样一来我们就可以确信,只要认可所做的假设,那么线性ODE系统的能力就是足够的,而不用去担心线性系统的能力限制了你的发挥。

    当然,HiPPO对于每一个解所做的假设及其物理含义也很清晰,所以对于重用了HiPPO矩阵的SSM,它怎么储存历史、能储存多少历史,从背后的HiPPO假设就一清二楚。比如LegT就是只保留 [latex]( w )[/latex] 大小的最邻近窗口信息,如果你用了LegT的HiPPO矩阵,那么就类似于一个Sliding Window Attention;而LegS理论上可以捕捉全部历史,但这有个分辨率问题,因为 [latex]( x(t) )[/latex] 的维度代表了拟合的阶数,它是一个固定值,用同阶的函数基去拟合另一个函数,肯定是区间越小越准确,区间越大误差也越大,这就好比为了一次性看完一幅大图,那么我们必须站得更远,从而看到的细节越少。

    诸如RWKV、LRU等模型,并没有重用HiPPO矩阵,而是改为可训练的矩阵,原则上具有更多的可能性来突破瓶颈,但从前面的分析大致上可以感知到,不同矩阵的线性ODE只是函数基不同,但本质上可能都只是有限阶函数基逼近的系数动力学。既然如此,分辨率与记忆长度就依然不可兼得,想要记忆更长的输入并且保持效果不变,那就只能增加整个模型的体量(即相当于增加hidden_size),这大概是所有线性系统的特性。

    文章小结

    本文以尽可能简单的方式重复了《HiPPO: Recurrent Memory with Optimal Polynomial Projections》(简称HiPPO)的主要推导。HiPPO通过适当的记忆假设,自下而上地导出了线性ODE系统,并且针对勒让德多项式的情形求出了相应的解析解(HiPPO矩阵),其结果被后来诸多SSM(State Space Model)使用,可谓是SSM的重要奠基之作。

    HiPPO框架展现了优雅的数学结构和强大的应用潜力,在处理时间序列数据时提供了一种高效的记忆机制。未来的研究可以进一步探索其在不同领域中的应用和改进。

    参考文献: https://spaces.ac.cn/archives/10114

  • 何加盐深度揭秘:我是怎么找资料的?

    在信息爆炸的时代,获取和整理信息的能力变得尤为重要。何加盐在其博客文章《何加盐深度揭秘:我是怎么找资料的?》中,详细介绍了他搜集资料的技巧和方法。以下是文章中的一些关键内容和技巧总结:

    一、用好搜索引擎

    1. 善于选择时间段

    通过设置搜索时间段,可以过滤掉大量无关信息。例如,想要了解百度创始人李彦宏的早期历程,可以将搜索时间设置在2000-2004年,这样可以找到更多关于他创业初期的报道。

    2. 善用关键词的组合

    关键词组合能让搜索结果更加精准。例如,搜索“程维 滴滴”可能会得到大量杂乱的信息,但如果组合搜索“程维 王刚”,就能找到更多关于滴滴和投资人的相关资料。

    3. 善用一些搜索命令

    • filetype:如“阿里巴巴组织结构 filetype:pdf”,能搜索到特定类型的文件。
    • 减号:如“张一鸣 -演员”,能过滤掉不相关的搜索结果。
    • site:如“马化腾 site:qq.com”,可以只搜索某个特定网站的信息。

    二、用好社交网站

    社交平台如微博、微信、知乎和脉脉等是搜集资料的重要渠道。通过浏览目标人物的社交账号,可以获取大量一手信息。例如,何加盐在写程维时,浏览了程维的所有微博;在写王兴时,浏览了王兴的饭否账号。

    三、用好视频网站

    视频网站是一个信息宝库,特别是知名人物的演讲、采访视频能提供大量鲜活的细节。例如,写程维时,何加盐参考了吴晓波的《二十年二十人》对程维的采访视频。

    四、用好名人演讲

    名人在各种场合的演讲活动通常会透露很多重要信息。马云在“18罗汉大会”上的演讲是了解他创业史的重要资料。

    五、用好传记作品

    传记是了解人物和企业最全面的方式。例如,《腾讯传》是了解腾讯发展历程的必读书目;《这世界既残酷,也温柔》是了解孙宇晨的主要资料来源之一。

    六、用好杂志

    专业杂志如《财经杂志》、《中国企业家》、《南方人物周刊》等,对人物和企业的报道非常深入。例如,何加盐写TMD三部曲时,引用了不少《财经杂志》的内容。

    总结

    何加盐分享的这些方法,旨在帮助大家更高效地搜集和整理信息。在此过程中,要注意两点:一是信息的真伪,需要多方交叉验证;二是使用好的工具,付费版通常能提供更高效的服务。

    希望这些技巧对你有所帮助!


    Learn more:

    1. 何加盐深度揭秘:我是怎么找资料的?-CSDN博客
  • DeepSeek-V2 大模型

    DeepSeek-V2 是一个强大、经济高效的混合专家语言模型。它具有2360亿个总参数,每个标记激活的参数为210亿。相比于DeepSeek 670亿,DeepSeek-V2 在性能上更强大,同时节省了42.5%的训练成本,将KV缓存减少了93.3%,并将最大生成吞吐量提升了5.76倍[1]

    DeepSeek-V2的配置方法如下:

    1. 下载模型:DeepSeek-V2 可以从 HuggingFace 的官方网站下载[1]
    2. 安装依赖:在配置 DeepSeek-V2 之前,确保已经安装了以下依赖项:
    • Python 3.6 或更高版本
    • PyTorch 1.7.0 或更高版本
    • Transformers 4.0.0 或更高版本
    1. 导入模型:在 Python 代码中导入 DeepSeek-V2 模型,可以使用以下代码:
       from transformers import GPT2LMHeadModel, GPT2Tokenizer
    
       model_name = "deepseek-ai/DeepSeek-V2"
       tokenizer = GPT2Tokenizer.from_pretrained(model_name)
       model = GPT2LMHeadModel.from_pretrained(model_name)
    1. 使用模型:使用导入的模型进行文本生成或其他自然语言处理任务。以下是一个简单的示例:
       input_text = "你好,DeepSeek-V2!"
       input_ids = tokenizer.encode(input_text, return_tensors="pt")
       output = model.generate(input_ids, max_length=50)
       generated_text = tokenizer.decode(output, skip_special_tokens=True)
       print(generated_text)

    这些是配置 DeepSeek-V2 的基本步骤。根据具体的应用场景和需求,你可能需要进一步调整模型的参数和设置。


    Learn more:

    1. GitHub – deepseek-ai/DeepSeek-V2: DeepSeek-V2: A Strong, Economical, and Efficient Mixture-of-Experts Language Model
    2. README.md · deepseek-ai/DeepSeek-V2 at main
    3. DeepSeek-V2/README.md at main · deepseek-ai/DeepSeek-V2 · GitHub

    配置和使用 DeepSeek-V2:强大、经济高效的混合专家语言模型

    DeepSeek-V2 是一款强大且经济高效的混合专家(Mixture-of-Experts, MoE)语言模型。相比于之前的 DeepSeek 67B,DeepSeek-V2 不仅性能更强,还显著降低了训练成本和资源消耗。本文将介绍如何配置和使用 DeepSeek-V2 模型。

    模型简介

    DeepSeek-V2 拥有 2360 亿个总参数,其中每个标记激活 210 亿个参数。与 DeepSeek 67B 相比,DeepSeek-V2 在多个方面表现出色:

    • 性能提升:模型性能显著提升。
    • 成本节约:节省了 42.5% 的训练成本。
    • 资源优化:KV 缓存减少了 93.3%。
    • 吞吐量提升:最大生成吞吐量提升了 5.76 倍。

    详细信息可以参考 DeepSeek-V2 的 GitHub 页面

    模型下载

    DeepSeek-V2 可以从 HuggingFace 的官方网站下载。以下是下载链接:

    环境依赖

    在配置 DeepSeek-V2 之前,确保你的环境中已经安装了以下依赖项:

    • Python 3.6 或更高版本
    • PyTorch 1.7.0 或更高版本
    • Transformers 4.0.0 或更高版本

    导入和使用模型

    导入模型

    在 Python 代码中导入 DeepSeek-V2 模型,可以使用以下代码:

    from transformers import GPT2LMHeadModel, GPT2Tokenizer
    
    model_name = "deepseek-ai/DeepSeek-V2"
    tokenizer = GPT2Tokenizer.from_pretrained(model_name)
    model = GPT2LMHeadModel.from_pretrained(model_name)

    使用模型进行文本生成

    使用导入的模型进行文本生成或其他自然语言处理任务。以下是一个简单的示例:

    input_text = "你好,DeepSeek-V2!"
    input_ids = tokenizer.encode(input_text, return_tensors="pt")
    output = model.generate(input_ids, max_length=50)
    generated_text = tokenizer.decode(output[0], skip_special_tokens=True)
    print(generated_text)

    详细配置和优化

    使用 Huggingface 的 Transformers 进行推理

    你可以直接使用 Huggingface 的 Transformers 库来进行模型推理。以下是一个示例代码:

    import torch
    from transformers import AutoTokenizer, AutoModelForCausalLM, GenerationConfig
    
    model_name = "deepseek-ai/DeepSeek-V2"
    tokenizer = AutoTokenizer.from_pretrained(model_name, trust_remote_code=True)
    max_memory = {i: "75GB" for i in range(8)}
    model = AutoModelForCausalLM.from_pretrained(model_name, trust_remote_code=True, device_map="sequential", torch_dtype=torch.bfloat16, max_memory=max_memory, attn_implementation="eager")
    model.generation_config = GenerationConfig.from_pretrained(model_name)
    model.generation_config.pad_token_id = model.generation_config.eos_token_id
    
    text = "An attention function can be described as mapping a query and a set of key-value pairs to an output, where the query, keys, values, and output are all vectors. The output is"
    inputs = tokenizer(text, return_tensors="pt")
    outputs = model.generate(**inputs.to(model.device), max_new_tokens=100)
    
    result = tokenizer.decode(outputs[0], skip_special_tokens=True)
    print(result)

    使用 vLLM 进行推理(推荐)

    为了更高效地执行模型推理,可以使用 vLLM 解决方案。以下是示例代码:

    from transformers import AutoTokenizer
    from vllm import LLM, SamplingParams
    
    max_model_len, tp_size = 8192, 8
    model_name = "deepseek-ai/DeepSeek-V2-Chat"
    tokenizer = AutoTokenizer.from_pretrained(model_name)
    llm = LLM(model=model_name, tensor_parallel_size=tp_size, max_model_len=max_model_len, trust_remote_code=True, enforce_eager=True)
    sampling_params = SamplingParams(temperature=0.3, max_tokens=256, stop_token_ids=[tokenizer.eos_token_id])
    
    messages_list = [
        [{"role": "user", "content": "Who are you?"}],
        [{"role": "user", "content": "Translate the following content into Chinese directly: DeepSeek-V2 adopts innovative architectures to guarantee economical training and efficient inference."}],
        [{"role": "user", "content": "Write a piece of quicksort code in C++."}],
    ]
    
    prompt_token_ids = [tokenizer.apply_chat_template(messages, add_generation_prompt=True) for messages in messages_list]
    
    outputs = llm.generate(prompt_token_ids=prompt_token_ids, sampling_params=sampling_params)
    
    generated_text = [output.outputs[0].text for output in outputs]
    print(generated_text)

    许可证和引用

    许可证

    这个代码库使用 MIT 许可证。DeepSeek-V2 Base/Chat 模型的使用遵循模型许可证。DeepSeek-V2 系列(包括 Base 和 Chat)支持商业用途。

    引用

    如果你在研究中使用了 DeepSeek-V2,请引用以下文献:

    @misc{deepseekv2,
          title={DeepSeek-V2: A Strong, Economical, and Efficient Mixture-of-Experts Language Model}, 
          author={DeepSeek-AI},
          year={2024},
          eprint={2405.04434},
          archivePrefix={arXiv},
          primaryClass={cs.CL}
    }

    联系方式

    如果你有任何问题,请在 GitHub 提出 issue 或联系 service@deepseek.com。


    更多信息请参考以下链接:

    1. GitHub – deepseek-ai/DeepSeek-V2
    2. README.md · deepseek-ai/DeepSeek-V2 at main
    3. DeepSeek-V2/README.md at main · deepseek-ai/DeepSeek-V2 · GitHub
  • Caddy 2中配置缓存

    在Caddy 2中配置缓存可以使用cache-handler插件。以下是配置Caddy 2缓存的步骤:

    1. 安装cache-handler插件:首先,确保已安装Caddy 2,并且可以使用插件。然后,下载并安装cache-handler插件。可以从GitHub的caddyserver/cache-handler仓库中获取插件的最新版本。
    2. 配置全局缓存选项:在Caddyfile中配置全局缓存选项。这些选项将适用于所有站点。以下是一些常用的全局选项:
    • order cache before rewrite:确保缓存处理在重写之前执行。
    • cache:启用缓存处理。
    • cache.allowed_http_verbs:允许被缓存的HTTP方法,默认为GET和HEAD。
    • cache.api.basepath:缓存管理API的基本路径。
    • cache.badger.path:配置Badger缓存存储的路径。
    • cache.cache_name:覆盖在Cache-Status响应头中使用的缓存名称。
    • cache.default_cache_control:如果上游未设置Cache-Control响应头,则设置默认值。 你可以根据需要配置其他选项。完整的全局选项列表可以在cache-handler插件的文档中找到[1]
    1. 配置站点缓存选项:在Caddyfile中为每个站点配置缓存选项。以下是一个示例配置:
       example.com {
         cache
         reverse_proxy your-app:8080
       }

    在这个示例中,cache指令启用了缓存处理,并将请求代理到your-app:8080

    1. 配置缓存键:你可以使用cache_keys指令为特定的URI配置缓存键生成规则。例如:
       cache_keys {
         .+\.css {
           disable_body
           disable_host
           disable_method
           disable_query
           headers X-Token Authorization
         }
       }

    在这个示例中,所有以.css结尾的URI将使用指定的规则生成缓存键。

    1. 配置CDN管理(可选):如果你使用CDN代理请求,可以配置CDN管理选项。这些选项将与缓存处理一起使用。例如:
       cdn {
         provider fastly
         api_key XXXX
         dynamic
         email darkweak@protonmail.com
         hostname domain.com
         network your_network
         strategy soft
         service_id 123456_id
         zone_id anywhere_zone
       }

    在这个示例中,使用Fastly作为CDN提供商,并配置了相关的API密钥、邮箱、主机名等信息。

    1. 保存并重新加载Caddy配置:完成配置后,保存Caddyfile并重新加载Caddy配置,以使更改生效。

    这些是配置Caddy 2缓存的基本步骤。你可以根据需要调整和扩展这些配置选项。请参考cache-handler插件的文档以获取更多详细信息和选项[1]


    Learn more:

    1. GitHub – caddyserver/cache-handler: Distributed HTTP caching module for Caddy
    2. State of HTTP Caching in Caddy 2 – Help – Caddy Community
    3. 【Caddy2】最新Caddy2配置文件解析 – 詩 – 博客园

    darkweak/souin 是一个HTTP缓存系统,符合RFC标准,并与@tyktechnologies、@traefik、@caddyserver、@go-chi、@bnkamalesh、@beego、@devfeel、@labstack、@gofiber、@go-goyave、@go-kratos、@gin-gonic、@roadrunner-server、@zalando、@zeromicro、@nginx和@apache兼容[1]。它可以作为反向代理缓存系统,可以放置在当前反向代理(如Apache、Nginx)的顶部,也可以作为Træfik、Caddy或Tyk等喜爱的反向代理的插件使用。由于它是用Go语言编写的,可以部署在任何服务器上,并且由于具有Docker集成,可以轻松安装在Swarm或Kubernetes实例上。它支持Vary、请求合并、陈旧的Cache-Control和其他与RFC-7234相关的规范,还支持新编写的RFC(目前处于草案阶段)http-cache-groups和http-invalidation。它还支持ESI标签,感谢go-esi包的支持[1]

    Souin的配置文件存储在/anywhere/configuration.yml中,可以根据需要提供自己的配置文件。配置文件中包含了各种配置选项,如缓存时间、反向代理URL、API配置、缓存键配置等[1]

    Souin还提供了各种插件,如Beego过滤器、Caddy模块、Chi中间件、Dotweb中间件、Echo中间件、Fiber中间件、Gin中间件、Goa中间件、Go-zero中间件、Goyave中间件、Hertz中间件、Kratos过滤器、Roadrunner中间件、Skipper过滤器、Træfik插件、Tyk插件、Webgo中间件、Prestashop插件和Wordpress插件等[1]

    Souin还支持Prometheus API、Souin API和Security API,可以用于监控和管理缓存系统[1]

    总结:darkweak/souin是一个符合RFC标准的HTTP缓存系统,可以作为反向代理缓存系统使用,也可以作为插件嵌入到其他反向代理中。它支持各种配置选项和插件,并提供了API用于监控和管理缓存系统。


    Learn more:

    1. GitHub – darkweak/souin: An HTTP cache system, RFC compliant, compatible with @tyktechnologies, @traefik, @caddyserver, @go-chi, @bnkamalesh, @beego, @devfeel, @labstack, @gofiber, @go-goyave, @go-kratos, @gin-gonic, @roadrunner-server, @zalando, @zeromicro, @nginx and @apache
    2. darkweak · GitHub
    3. Releases · darkweak/souin · GitHub
  • 深入解析 LoRA+:如何通过调整学习率进一步优化LLM

    在当前大规模语言模型(LLM)的参数高效微调方法中,LoRA(Low-Rank Adaptation)无疑是一个重要的手段。此前,我们在《梯度视角下的LoRA:简介、分析、猜测及推广》中曾简单讨论过LoRA。今天,我们来学习LoRA的一个新结论:给LoRA的两个矩阵分配不同的学习率,LoRA的效果还能进一步提升。这一结论出自最近的论文《LoRA+: Efficient Low Rank Adaptation of Large Models》(下称“LoRA+”)。

    为什么调整学习率显得如此重要?

    乍一看,给不同的矩阵分配不同的学习率似乎并没有什么特别之处,因为配置不同的学习率相当于引入了新的超参数,而通常来说,只要引入并精调超参数,模型性能都会有所提升。然而,“LoRA+”的特别之处在于,它从理论角度肯定了这一必要性,并且明确指出最优解必然是右矩阵的学习率大于左矩阵的学习率。

    LoRA基本原理回顾

    假设预训练参数为

    [latex]( W_0 \in \mathbb{R}^{n \times m} )[/latex]

    ,如果使用全量参数微调,那么增量也是一个 ( n \times m ) 矩阵。为了降低参数量,LoRA将更新量约束为低秩矩阵,即设 ( W = W_0 + AB ),其中

    [latex]( A \in \mathbb{R}^{n \times r}, B \in \mathbb{R}^{r \times m}, r \ll \min(n, m) )[/latex]

    。在训练时,只更新 ( A ) 和 ( B )。

    为了便于理解,我们假设层的输入是

    [latex]( X \in \mathbb{R}^{b \times n} )[/latex]

    ,层的运算为

    [latex]( XW = X(W_0 + AB) )[/latex]

    。由于“LoRA+”的结论跟预训练权重无关,不失一般性可以设

    [latex] ( W_0 = 0 )[/latex]

    ,那么层运算简化为

    [latex]( Y = XAB \in \mathbb{R}^{b \times m} )[/latex]

    结论简析

    “LoRA+”的结论是:为了使LoRA的效果尽可能接近最优,权重 ( B ) 的学习率应该要大于权重 ( A ) 的学习率。

    这个结论的核心在于,虽然 ( A ) 和 ( B ) 在表面上是对称的,但实际上它们有着固有的不对称性。即使将 ( A ) 或 ( B ) 全零初始化,结论依然成立。

    数值稳定性与贡献相当假设

    1. 数值稳定性

    数值稳定性意味着 ( X )、 ( XA )、 ( XAB ) 的每个分量都应该是 ( O(1) ) 级别的,而不依赖于网络宽度 ( n, m )。虽然 ( XA ) 是中间变量,但它的数值稳定性对梯度稳定性至关重要。

    为了实现数值稳定性,假设 ( X ) 是 ( O(1) ),那么 ( A ) 和 ( B ) 应该分别用 ( 1/n ) 和 ( 1/r ) 的方差初始化。

    2. 贡献相当

    为了使LoRA最优, ( A ) 和 ( B ) 两个矩阵对效果应该有同等程度的贡献。我们可以通过损失函数 ( L ) 的变化来衡量 ( A ) 和 ( B ) 的贡献:

    [latex][ L(A + \Delta A, B + \Delta B) – L(A, B) \approx \langle \frac{\partial L}{\partial A}, \Delta A \rangle + \langle \frac{\partial L}{\partial B}, \Delta B \rangle ][/latex]

    在Adam优化器中,如果两个参数的学习率之比是 ( \lambda ),那么经过长期训练后,这两个参数的数量级之比也是

    [latex]( \lambda )[/latex]

    。因此,如果 [latex]( \eta_B / \eta_A = O(\sqrt{n}) )[/latex],那么 ( B ) 和 ( A ) 的数量级之比也是 [latex]( O(\sqrt{n}) )[/latex],与我们的期望一致。

    快速推导

    通过矩阵求导,我们可以得到:

    [latex][ \frac{\partial L}{\partial A} = X^\top \frac{\partial L}{\partial Y} B^\top, \quad \frac{\partial L}{\partial B} = A^\top X^\top \frac{\partial L}{\partial Y} ][/latex]

    结合数值稳定性和贡献相当的假设,可以推导出:

    [latex][ \eta_B / \eta_A = O(\sqrt{n}) ][/latex]

    总结

    在这篇文章中,我们介绍并推导了“LoRA+”的结果,它支持LoRA的两个低秩矩阵 ( A ) 和 ( B ) 存在固有的不对称性。不管将哪个矩阵全零初始化,都应该将 ( B ) 的学习率设置得大于 ( A ),以达到更优的效果。这一理论不仅在实践中有效,也为我们提供了一个经典的理论指导训练的范例。

  • 论文分享:Score Identity Distillation——更快更好的扩散模型蒸馏方法

    引言

    今天我们分享的是一篇名为《Score Identity Distillation: Exponentially Fast Distillation of Pretrained Diffusion Models for One-Step Generation》的新论文。该论文探讨了如何更快更好地蒸馏扩散模型。

    即便没有做过蒸馏,大家可能也能猜到蒸馏的常规步骤:随机采样大量输入,然后用扩散模型生成相应结果作为输出,用这些输入输出作为训练数据对,来监督训练一个新模型。然而,众所周知,作为教师的原始扩散模型通常需要多步(比如1000步)迭代才能生成高质量输出,所以且不论中间训练细节如何,该方案的一个显著缺点是生成训练数据太费时费力。此外,蒸馏之后的学生模型通常或多或少都有效果损失。

    有没有方法能一次性解决这两个缺点呢?这就是上述论文试图要解决的问题。

    思路简介

    论文将所提方案称为“Score Identity Distillation(SiD)”,基于几个恒等式来设计和推导了整个框架。实际上,它的设计思想与几个恒等式并没有直接联系,其次几个恒等式都是已知的公式而不是新的,所以这个名字显得相当随意。

    本文将其称之为“重现江湖”,是因为SiD的思路跟之前在《从去噪自编码器到生成模型》介绍过的论文《Learning Generative Models using Denoising Density Estimators》(简称“DDE”)几乎一模一样,甚至最终形式也有五六分相似。只不过当时扩散模型还未露头角,所以DDE是将其作为一种新的生成模型提出的,在当时反而显得非常小众。而在扩散模型流行的今天,它可以重新表述为一种扩散模型的蒸馏方法,因为它需要一个训练好的去噪自编码器——这正好是扩散模型的核心。

    接下来笔者用自己的思路去介绍SiD。

    初级形式

    假设我们有一个在目标数据集训练好的教师扩散模型 ( \epsilon_{\phi^}(x_t, t) ),它需要多步采样才能生成高质量图片。我们的目标是训练一个单步采样的学生模型 ( x = g_{\theta}(z) ),即一个类似GAN的生成器,输入指定噪声 ( z ) 就可以直接生成符合要求的图像。如果我们有很多的 ( (z, x) ) 对,那么直接监督训练就可以了(当然损失函数和其他细节还需要进一步确定,读者可以自行参考相关工作),但如果没有呢?肯定不是不能训,因为就算没有 ( \epsilon_{\phi^}(x_t, t) ) 也能训,比如GAN,所以关键是怎么借助已经训练好的扩散模型提供更好的信号。

    SiD及前作DDE使用了一个看上去很绕但是也很聪明的思路:

    如果 ( g_{\theta}(z) ) 产生的数据分布跟目标分布很相似,那么拿 ( g_{\theta}(z) ) 生成的数据集去训练一个扩散模型 ( \epsilon_{\psi^}(x_t, t) ) 的话,它也应该跟 ( \epsilon_{\phi^}(x_t, t) ) 很相似?

    这个思路的聪明之处在于,它绕开了对教师模型生成样本的需求,也不需要训练教师模型的真实样本,因为“拿 ( g_{\theta}(z) ) 生成的数据集去训练一个扩散模型”只需要学生模型 ( g_{\theta}(z) ) 生成的数据(简称“学生数据”),而 ( g_{\theta}(z) ) 是一个单步模型,用它来生成数据时间上比较友好。

    当然,这还只是思路,将其转换为实际可行的训练方案还有一段路要走。

    方法与公式

    扩散模型回顾

    我们采用《生成扩散模型漫谈(三):DDPM = 贝叶斯 + 去噪》的形式,对输入 ( x_0 ) 进行加噪:
    [ x_t = \bar{\alpha}_t x_0 + \bar{\beta}_t \epsilon, \quad \epsilon \sim N(0, I) ]

    训练 ( \epsilon_{\phi^}(x_t, t) ) 的方式则是去噪: [ \phi^ = \arg\min_{\phi} E_{x_0 \sim \tilde{p}(x_0), \epsilon \sim N(0, I)} \left[ | \epsilon_{\phi}(\bar{\alpha}_t x_0 + \bar{\beta}_t \epsilon, t) – \epsilon |^2 \right] ]

    同样地,如果我们想用 ( g_{\theta}(z) ) 的学生数据训练一个扩散模型,那么训练目标是:
    [ \psi^* = \arg\min_{\psi} E_{z, \epsilon \sim N(0, I)} \left[ | \epsilon_{\psi}(x_t^{(g)}, t) – \epsilon |^2 \right] ]

    其中 ( x_t^{(g)} = \bar{\alpha}t g{\theta}(z) + \bar{\beta}t \epsilon ),是由学生数据加噪后的样本,其分布记为 ( p{\theta}(x_t^{(g)}) )。

    学生模型的学习

    我们可以通过最小化教师模型和学生模型生成的数据分布差异来学习学生模型:
    [ \theta^* = \arg\min_{\theta} E_{z, \epsilon \sim N(0, I)} \left[ | \epsilon_{\phi^}(x_t^{(g)}, t) – \epsilon_{\psi^}(x_t^{(g)}, t) |^2 \right] ]

    注意这个优化依赖于 ( \theta ),所以当 ( \theta ) 通过上式发生改变时,( \psi^* ) 的值也随之改变,因此需要交替优化,类似GAN一样。

    点睛之笔

    上述方法存在理论与实践之间的gap,主要体现在两个问题:

    1. 理论上要求先求出上式的最优解,然后才去优化,但实际上从训练成本考虑,我们并没有将它训练到最优就去优化了;
    2. 理论上 ( \psi^* ) 随 ( \theta ) 而变,即应该写成 ( \psi^(\theta) ),从而在优化时应该多出一项 ( \psi^(\theta) ) 对 ( \theta ) 的梯度,但实际上在优化时我们都只当 ( \psi^* ) 是常数。

    SiD的核心贡献是通过恒等变换,尽量消除优化目标对 ( \psi^* ) 的依赖,从而有效缓解上述两个问题。

    恒等变换

    我们具体来看做了什么恒等变换。我们先来看去噪目标:
    [ E_{x_0 \sim \tilde{p}(x_0), x_t \sim p(x_t | x_0)} \left[ | \epsilon_{\phi}(x_t, t) + \bar{\beta}t \nabla{x_t} \log p(x_t | x_0) |^2 \right] ]

    根据得分匹配相关结果,上述目标的最优解是 ( \epsilon_{\phi^}(x_t, t) = -\bar{\beta}t \nabla{x_t} \log p(x_t) )。同理,学生模型的训练目标的最优解是 ( \epsilon_{\psi^}(x_t^{(g)}, t) = -\bar{\beta}t \nabla{x_t^{(g)}} \log p_{\theta}(x_t^{(g)}) )。

    此时我们有:
    [ E_{z, \epsilon \sim N(0, I)} \left[ | \epsilon_{\phi^}(x_t^{(g)}, t) – \epsilon_{\psi^}(x_t^{(g)}, t) |^2 \right] ]

    通过恒等变换,我们可以将上式化简为:
    [ E_{z, \epsilon \sim N(0, I)} \left[ \langle \epsilon_{\phi^}(x_t^{(g)}, t) – \epsilon_{\psi^}(x_t^{(g)}, t), \epsilon_{\phi^*}(x_t^{(g)}, t) – \epsilon \rangle \right] ]

    这就是SiD的核心结果,能够高效地实现蒸馏。

    其他细节

    1. 论文的推导默认了 ( \bar{\alpha}_t = 1 )。
    2. 论文的结果是以 ( \mu(\bar{x}_t) = x_t – \bar{\beta}_t \epsilon(x_t, t) / \bar{\alpha}_t ) 为标准给出的,这与扩散模型常见的表述方式不同。
    3. SiD最终取了上式的相反数作为额外的损失函数,加权到改进的损失函数上,以取得更优的蒸馏效果。

    延伸思考

    对于式(3)和式(4)的交替优化,有不少读者可能会想到,但SiD的精彩之处是提出了恒等变换,使得训练更加稳定高效。

    文章小结

    在这篇文章中,我们介绍了一种新的将扩散模型蒸馏为单步生成模型的方案,其思想可以追溯到前两年的利用去噪自编码器训练生成模型的工作,它不需要获得教师模型的真实训练集,也不需要迭代教师模型来生成样本对,而引入了类似GAN的交替训练,同时提出了关键的恒等变换来稳定训练过程,整个方法有颇多值得学习之处。

  • Fast Transformer Decoding: One Write-Head is All You Need

    引言

    《Fast Transformer Decoding: One Write-Head is All You Need》是一篇提出了一种变换模型多头注意力机制变体的研究论文。该论文解决了变换模型在增量推理过程中由于反复加载大规模“键”和“值”张量而导致的内存带宽成本问题。

    论文要点

    1. 多查询注意力(Multi-Query Attention)

    作者提出了一种称为多查询注意力的变体,其中键和值在所有注意力头之间共享。这种方法减少了张量的大小以及在增量解码过程中对内存带宽的需求。

    2. 内存带宽的减少

    通过共享键和值,所提出的方法显著减少了在解码过程中反复加载这些张量的内存带宽成本。

    3. 更快的解码速度

    采用多查询注意力的模型在解码速度上比传统的多头注意力模型要快得多。

    4. 质量轻微下降

    作者通过实验验证了多查询注意力模型在相较于基线模型的情况下,质量仅有轻微下降。

    进一步了解

    1. [1911.02150] Fast Transformer Decoding: One Write-Head is All You Need
    2. Fast Transformer Decoding: One Write-Head is All You Need | Papers With Code
    3. dblp: Fast Transformer Decoding: One Write-Head is All You Need.

    通过这篇论文,我们可以看到在不牺牲太多模型质量的前提下,通过优化内存带宽和共享键值对,可以显著提高变换模型的解码速度。这对于提升自然语言处理任务中的推理效率具有重要意义。


    多查询注意力

    多查询注意力是一种注意力机制,其中键和值在所有注意力头之间共享。这意味着在解码过程中,只需要加载一次键和值向量,从而显著减少了内存带宽成本。

    传统多头注意力

    传统的多头注意力是一种注意力机制,其中每个注意力头都有自己的键和值向量。这意味着在解码过程中,需要反复加载这些向量,从而导致内存带宽成本高。

    多查询注意力和传统多头注意力之间的区别

    多查询注意力和传统多头注意力之间的主要区别在于键和值的共享方式。在多查询注意力中,键和值在所有注意力头之间共享,而在传统的多头注意力中,每个注意力头都有自己的键和值向量。

    多查询注意力和传统多头注意力之间的区别是否会对模型的性能产生影响?

    实验表明,采用多查询注意力的模型在解码速度上比传统的多头注意力模型要快得多,且质量仅有轻微下降。

  • OpenVINO-Java-API

    📚 简介

    OpenVINO™ 是一个用于优化和部署 AI 推理的开源工具包,旨在提升深度学习在计算机视觉、自动语音识别、自然语言处理和其他常见任务中的性能。它支持使用流行框架(如TensorFlow,PyTorch等)训练的模型,减少资源需求,并在从边缘到云的一系列英特尔®平台上高效部署。

    该项目通过Java Native Access (JNA) 实现了基于OpenVINO™工具套件的OpenVINO™ Java API,旨在推动 OpenVINO™在Java领域的应用。由于是基于 OpenVINO™ 开发,OpenVINO™ Java API 支持的所有平台与OpenVINO™ 一致。

    版本计划

    • 1.0: 实现基本函数,并提供Yolov8范例
    • 1.1: 实现Maven在线安装
    • 2.0: 实现库本地加载,告别复杂安装
    • 3.0: 实现在线加载

    Java库公示

    • JNA
    • OpenCV
    • OpenVINO

    ⚙ 如何安装

    以下文章提供了OpenVINO™ Java API在不同平台的安装方法,可以根据自己使用的平台进行安装。

    简短安装步骤

    1. 在OpenVINO官网下载对应平台的runtime库
    2. 将Runtime库加入环境变量
      • Windows: 放在系统路径中
      • Linux/Mac OS: 将库文件放入 /usr/lib/

    详细使用文档

    🏷 开始使用

    快速体验

    使用以下代码简单了解OpenVINO Java API的使用方法:

    public class OpenVINOTest {
    
        public static void main(String[] args) {
            // 实现OpenVINO 库加载
            OpenVINO vino = OpenVINO.load("libopenvino_c.dylib");
            // 如果将库放置在系统路径中,可以这样简写
            // OpenVINO vino = OpenVINO.load();
            Core core = new Core();  // 初始化 Core 核心
            Model model = core.read_model("./model.xml");  // 读取模型文件
            CompiledModel compiled_model = core.compiled_model(model, "AUTO");  // 将模型加载到设备
            InferRequest infer_request = compiled_model.create_infer_request();  // 创建推理通道
            Tensor input_tensor = infer_request.get_tensor("images");  // 获取输入节点Tensor
            infer_request.infer();  // 模型推理
            Tensor output_tensor = infer_request.get_tensor("output0");  // 获取输出节点Tensor
            // 清理 Core 非托管内存
            core.free();  
        }
    }

    项目中所封装的类、对象例如Core、Model、Tensor等,通过调用 C API 接口实现,具有非托管资源,需要调用 dispose() 方法处理,否则就会出现内存泄漏。

    💻 应用案例

    • 爱克斯开发板使用OpenVINO™ Java API部署Yolov8模型
    • 基于Spring Boot 的在线AI服务
    • 基于客户端模式运行

    测试系统

    • Mac OS: Sonoma
    • Ubuntu: 23.04 (64位)
    • Windows

    🗂 API 文档

    (链接到相关API文档)

    🔃 更新日志

    (链接到更新日志)

    🎖 贡献

    如果您对OpenVINO™ 在Java使用感兴趣,有兴趣对开源社区做出自己的贡献,欢迎加入我们,一起开发OpenVINO™ Java API。如果你对该项目有一些想法或改进思路,欢迎联系我们,指导我们的工作。

    许可证书

    本项目的发布受Apache 2.0 license许可认证。


    GitHub 仓库地址: Hmm466/OpenVINO-Java-API


    通过这个项目,您可以在Java中更方便地使用OpenVINO™进行AI推理,加速您的开发流程并优化性能。如果有任何问题或建议,欢迎在仓库中提出Issue或进行讨论。


    OpenVINO™ Java API 安装指南(Windows)

    当前验证/测试环境

    • Windows: 7
    • JDK: 11.0.10
    • OpenVINO Runtime: 2023.2.0-12538-e7c1344d3c3
    • OpenCV: 4.8.0

    OpenVINO™ 环境配置

    OpenVINO™ 是一个用于优化和部署 AI 推理的开源工具包,旨在提升深度学习在计算机视觉、自动语音识别、自然语言处理和其他常见任务中的性能。它支持使用流行框架(如TensorFlow,PyTorch等)训练的模型,减少资源需求,并在从边缘到云的一系列英特尔®平台上高效部署。

    步骤

    1. 下载OpenVINO™ Runtime库 下载适用于您电脑平台的OpenVINO™ Runtime库。
    2. 拷贝动态链接库runtime/3rdparty/tbb/lib/*.dll 拷贝至 runtime/lib/intel64/release/ 下。
    3. 配置默认库路径runtime/lib/intel64/release/*.dll 拷贝至以下任意路径之一:
    • 自己喜欢的路径
    • C:\Windows

    OpenCV 环境配置

    1. 下载OpenCV 在官网下载适用于Windows平台的OpenCV,解压缩,并将其加入环境变量。
    2. 拷贝OpenCV动态链接库opencv_java*.dll 拷贝到自己喜欢的目录,或者将 build/lib/libopencv_java*.dll 移动到自己喜欢的目录。
    3. 加载OpenCV库 使用以下代码加载OpenCV库:
       OpenVINO.loadCvDll({opencv_java所在的目录});

    OpenVINO™ Java API 安装

    源码构建

    1. 克隆代码仓库
       git clone https://github.com/Hmm466/OpenVINO-Java-API.git
    1. 使用Maven安装 在代码仓库根目录下运行:
       mvn install

    Maven 引用

    如果您想在Maven项目中引用OpenVINO™ Java API,可以在 pom.xml 文件中添加以下依赖项:

    <dependencies>
        <dependency>
            <groupId>org.openvino</groupId>
            <artifactId>java-api</artifactId>
            <version>[按照最新下载的版本填入]</version>
        </dependency>
    </dependencies>

    在线Maven 安装

    该功能将在1.1版本上线


    通过以上步骤,您可以在Windows平台上成功安装并配置OpenVINO™ Java API。如果有任何问题或需要进一步的帮助,请在GitHub仓库中提出Issue或进行讨论。

    GitHub 仓库地址: Hmm466/OpenVINO-Java-API


    OpenVINO™ 生态系统概述

    简介

    OpenVINO™ 不只是一个工具,它还是一个庞大的实用程序生态系统,提供用于开发深度学习解决方案的整套工作流程。通过详细了解每个实用程序,可以充分利用 OpenVINO™ 工具套件。

    神经网络压缩框架 (NNCF)

    NNCF 是一套用于优化神经网络推理的高级算法,可以最大限度地减少准确度下降。在训练期间,NNCF 会对 PyTorch 和 TensorFlow 模型应用量化、过滤器修剪、二值化和稀疏性算法。

    更多资源:

    OpenVINO™ 安全插件

    OpenVINO™ 安全插件为模型开发人员和独立软件开发商提供了用于进行安全封装并安全执行模型的解决方案。

    更多资源:

    OpenVINO™ 与 TensorFlow 集成 (OVTF)

    OVTF 为 TensorFlow 开发人员提供 OpenVINO™ 优化功能的解决方案。只需在应用中添加两行代码,即可将推理分载给 OpenVINO™,同时保留 TensorFlow API。

    更多资源:

    DL Streamer

    DL Streamer 是一个基于 GStreamer 多媒体框架的流媒体分析框架,用于创建复杂的媒体分析管道。

    更多资源:

    深度学习工作台

    深度学习工作台是一个用于部署深度学习模型的基于 Web 的工具。它依托 OpenVINO™ 的核心功能并配有图形用户界面,提供了一种用于探索 OpenVINO™ 工作流程的各种可能性,以及导入、分析、优化并构建预训练模型的绝佳途径。您可以通过访问英特尔® DevCloud for the Edge 并在线启动深度学习工作台,执行所有此类任务。

    更多资源:

    OpenVINO™ 训练扩展 (OTE)

    OpenVINO™ 训练扩展 (OTE) 提供了一种用于使用 OpenVINO™ 工具套件训练深度学习模型并对其进行转换,以优化推理的便捷环境。

    更多资源:

    计算机视觉注释工具 (CVAT)

    CVAT 是一款用于计算机视觉的在线交互式视频和图像注释工具。

    更多资源:

    数据集管理框架 (Datumaro)

    Datumaro 是一个用于构建、转换和分析数据集的框架兼 CLI 工具。

    更多资源:


    通过详细了解和使用这些实用工具,能够充分发挥 OpenVINO™ 的强大功能,优化和部署高性能的深度学习解决方案。

    详细文档地址: OpenVINO™ 生态系统概述


    OpenVINO™ API 2.0 迁移指南

    概述

    本指南介绍了全新的 OpenVINO™ API (API 2.0) 以及新型 OpenVINO™ IR 模型格式:IR v11。本文将对新旧版本进行比较,并提供详细的迁移步骤。

    API 2.0 简介

    在从 TensorFlow、ONNX 运行时、PyTorch、PaddlePaddle 等其他框架迁移应用时,2022.1 之前的 OpenVINO™ 版本需要更改应用逻辑。这是因为:

    • 模型优化器更改了某些输入的输入精度。例如,具有 I64 输入的神经语言处理模型已更改为包含 I32 输入。
    • 模型优化器更改了 TensorFlow 模型的布局(请参阅 OpenVINO™ 中的布局)。
    • 由于设备插件的限制,推理引擎 API (InferenceEngine::CNNNetwork) 应用了一些输入和输出精度的转换规则。
    • 在模型优化器中进行模型转换期间,用户需要指定输入形状,并在应用中使用静态形状。

    OpenVINO™ 2022.1 引入了 API 2.0(也称为 OpenVINO™ API v2),以调整使用模型的逻辑。API 2.0 未更改布局和精度,使用张量名称和索引来执行操作以对输入和输出进行寻址。OpenVINO™ 运行时将用于推理的推理引擎 API 与用于处理模型和操作的 nGraph API 结合在一起。API 2.0 有通用的结构、命名约定样式、命名空间,并移除了重复的结构。

    现有的应用将继续正常使用 OpenVINO™ 运行时 2022.1,但强烈建议迁移到 API 2.0,以便使用其他功能,如预处理和动态形状支持。

    全新 OpenVINO™ IR v11

    为了支持这些功能,OpenVINO™ 引入了 OpenVINO™ IR v11,它现在是默认版本的模型优化器。以 OpenVINO™ IR v11 表示的模型的输入和输出与原始框架格式下的原始模型完全匹配,无需在转换过程中指定输入形状。生成的 OpenVINO™ IR v11 包含 -1,用于表示未定义维度。OpenVINO™ IR v11 完全兼容借助旧版 OpenVINO™ 使用的推理引擎 API 编写的应用。这种向后兼容性归功于 OpenVINO™ IR v11 中包含的其他运行时信息。

    向后兼容 OpenVINO™ IR v10

    API 2.0 还支持向后兼容 OpenVINO™ IR v10 模型。如果您拥有 OpenVINO™ IR v10 文件,也可以将其馈送到 OpenVINO™ 运行时。某些 OpenVINO™ 开发工具也支持将 OpenVINO™ IR v10 和 v11 作为输入:

    • 精度检查器默认使用 API 2.0 来测量模型精度,也支持通过使用 --use_new_api False 命令行参数切换到旧版 API。
    • 编译工具默认编译要在 API 2.0 中使用的模型。要在推理引擎 API 下使用生成的已编译 Blob,应传递附加 ov_api_1_0 选项。

    OpenVINO™ 2022.1 的训练后优化工具和深度学习工作台不支持 OpenVINO™ IR v10,需使用最新版本的模型优化器生成 OpenVINO™ IR v11 文件。

    API 2.0 与推理引擎 API 的行为差异

    推理引擎和 nGraph API 不会因引入了新 API 而被弃用,用户仍可以在应用中使用这些 API。但强烈建议迁移到 API 2.0,因为它提供了更多功能(在未来版本中会进一步扩展),例如:

    • 使用动态形状,提高神经语言处理 (NLP) 和超分辨率模型等兼容模型的性能。
    • 预处理模型,在推理模型中添加预处理操作并完全占用加速器,从而释放 CPU 资源。

    下表说明了基于这两个 API 的模型会使用哪种行为:旧行为还是新行为。

    APIIR v10IR v11ONNX 文件使用代码创建的模型
    推理引擎/nGraph API
    API 2.0

    通过迁移到 OpenVINO™ API 2.0,您可以充分利用新特性和增强功能,提升模型推理的性能和灵活性。

    详细文档地址: OpenVINO™ API 2.0 迁移指南

  • GQA: 从多头检查点训练广义多查询变换模型

    引言

    在自然语言处理领域,如何在不牺牲模型质量的前提下实现更快的推理速度一直是一个重要的研究课题。本文将介绍一篇名为《GQA: Training Generalized Multi-Query Transformer Models from Multi-Head Checkpoints》的研究论文,该论文提出了一种从多头检查点训练广义多查询变换模型的方法,旨在解决这一挑战。

    论文贡献

    1. 现有多头语言模型检查点的再训练

    论文提出了一种再训练现有多头语言模型检查点的方法,将其转换为具有多查询注意力(MQA)的模型。MQA使用单个键值头,大幅加快解码器推理速度。通过仅使用原始预训练计算量的5%,再训练现有模型,作者旨在实现更快的推理速度,而无需单独训练一个新模型。

    2. 引入分组查询注意力(GQA)

    论文引入了GQA,作为MQA的一种广义形式。GQA使用中间数量的键值头,数量介于1和查询头总数之间。该方法旨在平衡MQA的速度和多头注意力的质量。作者通过实验表明,再训练的GQA模型在保持与MQA相当速度的同时,能够达到接近多头注意力的质量。

    方法与实验结果

    再训练方法

    论文详细介绍了再训练现有多头语言模型检查点的具体步骤。通过仅使用原始预训练计算量的5%,再训练现有模型,使其具备MQA的特点,从而实现更快的推理速度。

    GQA的实现

    GQA通过使用中间数量的键值头,增加了模型的灵活性和适应性。实验结果表明,再训练的GQA模型在多个自然语言处理任务中表现出色,质量接近于多头注意力,同时推理速度与MQA相当。

    结论

    本文提出的方法为实现更快的推理速度提供了一个有效的解决方案,而无需牺牲模型质量。通过再训练现有多头语言模型检查点,并引入分组查询注意力(GQA),可以在保持高质量的同时,实现高效的推理。这一研究对于提升变换模型在各类自然语言处理任务中的效率和性能具有重要意义。


    进一步了解:

    1. arXiv:2305.13245 – GQA: Training Generalized Multi-Query Transformer Models from Multi-Head Checkpoints
    2. Papers With Code – GQA: Training Generalized Multi-Query Transformer Models from Multi-Head Checkpoints
    3. ACL Anthology – GQA: Training Generalized Multi-Query Transformer Models from Multi-Head Checkpoints
  • 缓存与效果的极限拉扯:从MHA、MQA、GQA到MLA

    引言

    最近,幻方发布的DeepSeek-V2引起了广泛关注。其1块钱100万token的价格令人惊叹,而背后的关键技术之一——MLA(Multi-head Latent Attention)更是备受瞩目。本文将带大家梳理从MHA、MQA、GQA到MLA的演变历程,并深入介绍MLA的设计思路。

    MHA:多头注意力

    MHA(Multi-Head Attention)是《Attention is all you need》提出的注意力机制的基础。它通过多个独立的单头注意力拼接而成,广泛应用于当前的主流LLM(大语言模型)。

    MHA的设计使得每个注意力头(Head)都有独立的键(Key)、值(Value)和查询(Query)向量,这些向量通过线性变换得到。MHA的计算量和存储开销较大,特别是在长上下文(Context)情况下,KV Cache(键值缓存)会占用大量显存。

    瓶颈:为何降低KV Cache大小如此重要?

    LLM的推理主要在GPU上进行,而GPU显存有限。一部分显存用于存放模型参数和激活值,另一部分用于存放KV Cache。随着上下文长度增加,KV Cache的大小会逐渐占据主导地位,可能超出单张卡甚至单台机器的显存容量。

    减少KV Cache的目的是在更少的设备上推理更长的上下文,或在相同上下文长度下提高批处理大小,从而实现更快的推理速度或更大的吞吐量,最终降低推理成本。

    MQA:多查询注意力

    MQA(Multi-Query Attention)是减少KV Cache的一次尝试,首次提出于《Fast Transformer Decoding: One Write-Head is All You Need》。MQA的思路是让所有注意力头共享同一个Key和Value,从而将KV Cache减少到原来的1/h(h是头的数量)。

    尽管MQA在显存占用上有显著优势,但其效果在某些任务上可能有所下降。为了弥补这一损失,研究人员提出了GQA。

    GQA:分组查询注意力

    GQA(Grouped-Query Attention)是MHA与MQA之间的过渡版本,出自《GQA: Training Generalized Multi-Query Transformer Models from Multi-Head Checkpoints》。GQA将所有注意力头分为g个组,每组共享同一对Key、Value。这样既可以减少KV Cache,又能在一定程度上保留多样性。

    GQA提供了从MHA到MQA的自然过渡,当g=h时是MHA,g=1时是MQA,1 < g < h时则是GQA。GQA在KV Cache压缩率和效果之间提供了平衡。

    MLA:多头潜在注意力

    Part 1:增强模型能力

    MLA(Multi-head Latent Attention)对GQA进行了改进,采用低秩投影的方式替代GQA的分割、重复。MLA通过不同的投影矩阵增强模型能力,并在推理阶段通过恒等变换技巧减少KV Cache。

    Part 2:兼容RoPE

    MLA的一个难题是如何兼容RoPE(旋转位置编码)。RoPE是一个位置相关的矩阵,MLA通过引入一种混合方法,每个注意力头的Query和Key新增部分维度用于添加RoPE,从而保持KV Cache的减少效果。

    Part 3:减少训练参数量

    MLA的最终版本将Query输入改为低秩投影形式,减少训练期间的参数量和相应的显存占用。推理阶段,通过恒等变换技巧减少KV Cache,同时保持高效的计算。

    小结

    本文概述了多头注意力的演变历程,特别是从MHA到MQA、GQA,最终到MLA的变化理念。MLA通过低秩投影和恒等变换技巧实现了KV Cache的进一步压缩,同时兼容RoPE,称得上是一种非常实用的注意力变体。

    转载本文请包括本文地址:https://kexue.fm/archives/10091

    如果您还有什么疑惑或建议,欢迎在下方评论区继续讨论。如果您觉得本文不错,欢迎分享或打赏本文。打赏并非为了获得收益,而是希望知道科学空间获得了多少读者的真心关注。再次表示欢迎和感谢!


    苏剑林. (May. 13, 2024). 《缓存与效果的极限拉扯:从MHA、MQA、GQA到MLA》[Blog post]. Retrieved from 科学空间


    MLA(Multi-head Latent Attention)是一种对GQA(Generalized Query Attention)进行改进的注意力机制。它采用低秩投影的方式替代了GQA中的分割和重复操作,同时通过恒等变换技巧减少了KV Cache的使用。MLA的核心思想是通过不同的投影矩阵增强模型的能力,并在推理阶段通过恒等变换技巧减少KV Cache的存储和计算开销。

    MLA的改进主要解决了推理过程中的KV Cache问题,从而实现在更少的设备上推理更长的上下文,或者在相同的上下文长度下增大批处理大小,以实现更快的推理速度或更大的吞吐量,从而降低推理成本。

    与经典的MHA(Multi-head Attention)和GQA、MQA(Multi-query Attention)相比,MLA在优化KV Cache和保证模型效果方面具有显著的优势。MLA通过低秩投影的方式替代了GQA中的分割和重复操作,从而大大减小了KV Cache的大小。与MQA相比,MLA的性能和效果显著优于MQA,甚至强于MHA和GQA,真正实现了降低推理成本并保证模型性能的目标。

    MLA的核心是权重矩阵的合并。在传统的MHA中,注意力计算涉及到多个投影矩阵的乘法运算,而MLA通过合并这些投影矩阵,减少了存储和计算的开销。具体来说,MLA将(Q)^(T)K的计算结果合并为一个矩阵,并将合并后的权重应用到输入上,从而减少了存储和计算的开销。

    然而,尽管MHA也可以进行合并,但由于其特定的计算方式,无法像MLA那样进行合并。MLA通过恒等变换技巧,将合并后的权重矩阵应用到输入上,从而实现了KV Cache的减少。

    综上所述,MLA通过低秩投影替代分割和重复操作,采用恒等变换技巧减少KV Cache的使用,从而在推理过程中降低了存储和计算的开销,实现了更高效的推理和更低的成本。


    Learn more:

    1. 还在用MHA?MLA来了DeepSeek-v2的MLA的总结和思考 – 知乎
    2. [2405.04434] DeepSeek-V2: A Strong, Economical, and Efficient Mixture-of-Experts Language Model
    3. DeepSeek-V2中的MLA详解 – 知差(chai)
  • 生成扩散模型漫谈(二十四):少走捷径,更快到达

    引言

    在生成扩散模型的应用中,如何在保证生成质量的前提下减少采样步数一直是一个关键问题。本文将介绍一种名为“Skip Tuning”的加速技巧,该技巧出自论文《The Surprising Effectiveness of Skip-Tuning in Diffusion Sampling》。通过合理的调节Skip Connection的权重,可以在保持生成质量的同时进一步压缩采样步数,实现更快速的采样过程。

    模型回顾

    首先,我们需要回顾一下生成扩散模型中的主流架构——U-Net。U-Net最早出自论文《U-Net: Convolutional Networks for Biomedical Image Segmentation》,其特点是输入和输出的大小一致,适合图像分割任务。U-Net在生成扩散模型中也被广泛采用,因为它能够很好地捕捉图像的细节信息。

    U-Net的核心是Skip Connection,即在逐层下采样和上采样的过程中,添加了额外的连接来避免信息瓶颈。这些Skip Connection使得第一层的输出可以直接传递到倒数第一层,第二层的输出可以传递到倒数第二层,依此类推。这样可以解决信息流动受限的问题,尤其是在重构和去噪任务中,避免生成模糊的结果。

    Skip Tuning 方法

    Skip Tuning是一种特别简单有效的加速技巧,适用于已有的加速技术。其核心思想是通过调节Skip Connection的权重来补偿加速过程中损失的非线性能力。具体来说,在扩散模型的采样过程中,采样是一个多步递归地从初始状态到目标状态的过程,这构成了一个复杂的非线性映射。Skip Tuning通过调节Skip Connection的权重来增加模型的非线性能力,从而提高采样质量或者减少采样步数。

    假设有多个Skip Connection,我们将最靠近输入层的Skip Connection的权重设为一个较大的值,最远离输入层的Skip Connection的权重设为一个较小的值,剩下的按照深度均匀变化。通常情况下,我们设最靠近输入层的权重为1,这样基本上只有最远离输入层的权重需要调节。

    实验效果

    Skip Tuning的实验效果非常显著,以下是两个实验结果的表格展示:

    从实验结果可以看出,通过Skip Tuning,可以在保持采样质量的情况下显著减少采样步数。

    个人思考

    Skip Tuning方法简单明快,却体现了作者别出心裁的想象力和观察力。这与《生成扩散模型漫谈(二十三):信噪比与大图生成(下)》中的内容相呼应,展示了不同思路在生成扩散模型中的应用。

    与Skip Tuning比较相关的一篇论文是《FreeU: Free Lunch in Diffusion U-Net》,该论文分析了U-Net的不同成分在扩散模型中的作用。发现Skip Connection主要负责添加高频细节,而主干部分则主要负责去噪。Skip Tuning的实质是在降低采样步数时,通过调节Skip Connection的权重,增强主干的去噪能力。

    对于没有Skip Connection的模型,如DiT,也可以通过调节残差来获得类似的效果,因为残差的设计本质上与Skip Connection类似,都是线性正则化的inductive bias。

    文章总结

    本文介绍了一个能有效提高扩散模型加速采样后生成质量的技巧——降低U-Net的Skip Connection的权重。整个方法框架非常简单明快,直观易懂,值得学习和应用。

    转载本文请包括本文地址:https://kexue.fm/archives/10077

    更详细的转载事宜请参考:《科学空间FAQ》

    如果您还有什么疑惑或建议,欢迎在下方评论区继续讨论。

    如果您觉得本文不错,欢迎分享或打赏本文。打赏并非为了获得收益,而是希望知道科学空间获得了多少读者的真心关注。再次表示欢迎和感谢!


    苏剑林. (Apr. 23, 2024). 《生成扩散模型漫谈(二十四):少走捷径,更快到达》[Blog post]. Retrieved from 科学空间

  • 学习超越模式匹配?评估LLMs的数学理解能力

    作者

    Siyuan Guo, Aniket Didolkar, Nan Rosemary Ke, Anirudh Goyal, Ferenc Huszár, Bernhard Schölkopf

    摘要

    本文《学习超越模式匹配?评估LLMs的数学理解能力》探讨了大语言模型(LLMs)在数学问题解决中的领域知识和理解能力。作者不仅研究了预训练LLM已经掌握的知识,还考察了它们在上下文学习或指令微调过程中如何通过信息来学习。研究旨在评估LLMs在解决问题时理解不同数学技能的能力,以及其利用数学中复杂知识结构的能力。

    受到神经切线核(NTK)概念的启发,作者提出了一种名为NTKEval的方法,通过训练不同类型的数学数据来评估LLM概率分布的变化。论文中进行的分析显示了在上下文学习期间领域理解的证据,表明LLMs能够有效地学习和利用相关的数学技能。然而,某些指令微调技术导致的性能变化与训练数据无关,这表明在不同技能之间缺乏领域理解。

    主要内容

    1. 引言

    大语言模型(LLMs)在各种自然语言推理任务中展示了显著的成功。本文评估了LLMs在解决数学问题时所需的不同数学技能的理解能力,不仅关注预训练模型已经掌握的知识,还关注其在上下文学习或指令微调期间如何学习。

    2. 相关工作

    现有的研究主要关注LLMs在数学问题解决中的表现,然而很少有研究探讨其在不同数学技能上的理解能力。本文提出的方法旨在填补这一空白。

    3. 背景

    神经切线核(NTK)是一种用于分析神经网络泛化特性的工具。本文将NTK扩展到语言模型,提出NTKEval方法来评估模型在不同数学数据上的训练效果。

    4. 方法

    NTKEval通过计算在不同技能数据集上的概率分布变化来评估LLM的学习效果。具体来说,本文利用重要性采样方法来计算不同模型在相同输入下生成正确答案的概率差异。

    5. 数据集

    本文使用了合成数据集和KhanSkill数据集。合成数据集包含测试四种基本数学技能和四种问题格式的题目,而KhanSkill数据集包含9393种技能的2020个问题。

    6. 实验

    实验结果表明,LLMs在上下文学习期间能够区分深层结构和表层结构,表现出领域理解。然而,指令微调在不同数据类型上的效果相似,表明其适应性主要基于格式匹配而非领域理解。

    7. 结论

    本文提出的NTKEval方法证明了其在样本效率上的优势,并发现LLMs在上下文学习中表现出领域理解。相比之下,某些指令微调技术在不同数据上的效果相似,缺乏对不同数学技能的理解。

    了解更多

    1. 学习超越模式匹配?评估LLMs的数学理解能力
    2. 理解LLMs:从训练到推理的全面概述
    3. 学习超越模式匹配?评估LLMs的数学理解能力 | allainews.com
  • 多模态数据集提升药物不良事件检测:语料库创建与模型开发

    引言

    药物不良事件(Adverse Drug Events,ADEs)的挖掘在药物警戒中至关重要,通过识别与药物相关的潜在风险,提高患者安全性,促进不良事件的早期检测,并为监管决策提供指导。传统的ADE检测方法虽然可靠,但速度较慢,难以适应大规模操作,并且提供的信息有限。随着社交媒体内容、生物医学文献和电子病历(EMR)等数据源的迅猛增长,从这些非结构化文本中提取相关的ADE信息变得至关重要。

    相关工作

    文本数据与电子病历

    传统的ADE检测多基于文本数据,如电子病历和医学案例报告。这些数据源提供了患者病历记录、治疗情况、病情和潜在风险因素的全面信息。然而,这些方法往往忽视了视觉线索,导致上下文理解不足,影响了准确的解释。

    社交媒体数据集

    社交媒体因其实时性和多样化的用户生成内容,在ADE检测中也发挥了越来越重要的作用。通过分析社交媒体上的用户评论,可以识别潜在的ADE。然而,这些方法也存在局限性,因为它们仅依赖于文本数据。

    语料库开发

    为了弥补现有方法的不足,我们创建了一个多模态药物不良事件(MultiModal Adverse Drug Event,MMADE)检测数据集,将ADE相关的文本信息与视觉辅助信息相结合。具体包括以下步骤:

    数据收集

    我们从社交媒体、医疗博客和医学案例报告中收集数据,确保数据的多样性与代表性。例如,从Twitter收集了大量的推文,并筛选出与ADE相关的内容。

    数据注释

    为了确保数据注释的准确性,我们邀请了医学专业学生和博士生参与注释工作,并制定了详细的注释手册。通过多数投票确定最终的标签,以确保注释的一致性。

    数据分析

    我们对收集的样本进行了分析,确定了13种显著的ADE类型,并根据其来源将其分类,形成了一个多样化的ADE数据集。

    方法论

    我们利用大型语言模型(Large Language Models,LLMs)和视觉语言模型(Vision Language Models,VLMs),如InstructBLIP,对MMADE数据集进行训练,生成详细的医学图像描述。这些模型在视觉问答、图像字幕生成等任务中表现优异,通过集成复杂的联合表示学习机制,能够更好地捕捉文本和视觉模态之间的复杂关系。

    实验结果与分析

    通过一系列实验评估,我们发现多模态模型在捕捉视觉信息和生成文本描述方面表现优越。特别是经过领域特定数据微调后的InstructBLIP模型,在各种评估指标上均表现出色,显著提升了ADE检测的准确性。

    发现

    1. 多模态数据集显著提高了模型性能。
    2. 微调后的模型在捕捉上下文相似性和传达有意义的内容方面表现出色。
    3. 图像与文本的结合在ADE检测中发挥了关键作用。

    结论与未来工作

    本研究介绍了利用多模态数据集进行药物不良事件检测的任务,并创建了一个包含图像和文本描述的MMADE数据集。通过微调InstructBLIP模型,我们展示了领域特定微调对提升整体性能的重要性。未来工作可以扩展数据集,并探索其在ADE严重程度分类和摘要任务中的潜力。

    限制与伦理

    尽管我们开发了ADE检测框架并引入了新颖的MMADE数据集,但仍需注意数据集中可能存在的偏见,并确保隐私保护。我们的数据集仅用于研究目的,不授予商业使用许可。


    了解更多:

    1. Enhancing Adverse Drug Event Detection with Multimodal Dataset: Corpus Creation and Model Development
    2. Enhancing Adverse Drug Event Detection with Multimodal Dataset: Corpus Creation and Model Development
    3. Enhancing Adverse Drug Event Detection with Multimodal Dataset: Corpus Creation and Model Development

    Q: 这篇论文试图解决什么问题?

    A: 这篇论文试图解决的问题是如何有效地从多种数据源(如社交媒体内容、生物医学文献和电子医疗记录)中提取与药物不良反应(Adverse Drug Events, ADEs)相关的信息。具体来说,论文指出传统的ADE检测方法虽然可靠,但是速度慢、不易适应大规模操作,并且提供的信息有限。此外,以往的ADE挖掘研究主要集中在基于文本的方法上,忽视了视觉线索,这限制了对ADE情境的理解并妨碍了ADE的准确解释。

    为了解决这些问题,论文提出了以下几个关键点:

    1. 创建多模态ADE检测数据集(MMADE):该数据集结合了与ADE相关的文本信息和视觉辅助信息,以增强对ADE情境的全面理解。
    2. 开发一个框架:利用大型语言模型(LLMs)和视觉语言模型(VLMs)的能力,为展示ADE的医学图像生成详细的描述,帮助医疗专业人员在视觉上识别不良事件。
    3. 提高ADE检测的准确性和效率:通过整合视觉和文本数据,增强整体性能,这对于提高患者安全、ADE意识和医疗保健的可及性具有重要意义。
    4. 探索个性化医疗的新途径:通过多模态方法,为个性化医疗领域提供进一步探索的可能性。

    总的来说,论文的目标是通过融合文本和视觉信息来提高ADE检测的性能,从而为医疗专业人员提供更准确、更全面的工具,以便更好地进行诊断、治疗规划和患者护理。

    Q: 有哪些相关研究?

    A: 相关研究主要集中在以下几个方面:

    1. 基于生物医学文本和电子医疗记录的ADE检测:研究者开发了多种技术从电子医疗记录(EMRs)和医学案例报告(MCRs)中提取ADE信息。例如,Gurulingappa等人(2012a)使用机器学习方法从MEDLINE案例报告中识别和提取潜在的ADE关系。
    2. 基于社交媒体数据集的ADE检测:社交媒体成为获取实时信息的重要来源,有助于识别潜在的ADE。Leaman等人(2010)的研究表明用户评论在识别ADE方面的价值。
    3. 深度学习技术在ADE检测中的应用:随着深度学习技术的发展,研究者开始采用此类技术来预测ADE。例如,Tutubalina等人(2017)探索了条件随机场(CRF)和循环神经网络(RNN)的结合,展示了CRF增强了RNN模型捕捉上下文信息的能力。
    4. 多任务学习架构:Chowdhury等人(2018)开发了一个多任务架构,同时处理二元分类、ADR标记和指示标记,使用了PSB 2016社交媒体数据集。
    5. 特定领域的ADE检测:一些研究专注于特定类型的ADE,例如皮肤反应。例如,Zhou和Gao(2023)提出了SkinGPT4,这是一个针对皮肤病图像训练的领域特定模型。
    6. 多模态数据集的创建和使用:尽管目前没有公开的多模态(图像和文本)语料库适用于识别与药物相关的不良效果,但本文提出了一个新的多模态数据集MMADE,它包含ADR图像及其相应的文本描述。

    这些研究为本文提出的多模态ADE检测提供了理论和技术基础,同时也指出了现有方法的局限性,特别是在结合文本和视觉信息方面的不足。本文的研究旨在通过引入多模态数据集和模型来填补这一空白,并提高ADE检测的准确性和效率。

    Q: 论文如何解决这个问题?

    A: 论文通过以下几个步骤解决药物不良反应(ADE)检测的问题:

    1. 创建多模态数据集(MMADE):作者创建了一个包含1500个实例的多模态数据集,每个实例都包含患者报告的药物相关问题的文本描述和相应的图片。这个数据集旨在提供更全面的ADE信息,结合了视觉和文本信息。
    2. 利用大型语言模型(LLMs)和视觉语言模型(VLMs):作者提出了一个框架,利用LLMs和VLMs的能力来生成描述ADE的医学图像的详细文本,以帮助医疗专业人员在视觉上识别不良事件。
    3. 模型开发:作者使用了InstructBLIP模型,这是一个基于BLIP-2的预训练模型,具有高质量的视觉表示和强大的语言生成能力。通过精心的微调过程,使得模型能够适应ADE特定的任务。
    4. 微调过程:通过在特定领域数据上进行微调,模型的性能得到了显著提升。这表明领域特定的微调对于适应ADE检测的复杂性至关重要。
    5. 评估和分析:作者使用了一系列评估指标(如BLEU分数、ROUGE分数、BERTScore和MoverScore)来评估模型的性能,并进行了详细的分析。
    6. 风险分析:尽管多模态模型显示出潜力,但作者强调需要医疗专家和药物监管团队验证发现,并考虑其他关键因素。
    7. 未来工作:作者提出了未来研究的方向,包括扩展数据集和探索多模态数据集在ADE严重性分类和总结任务中的潜力。
    8. 伦理和广泛影响:作者讨论了用户隐私、偏见和数据集的预期用途等问题,并强调了研究的伦理方面。

    通过这些步骤,论文旨在提高ADE检测的准确性和效率,同时为医疗专业人员提供更全面的工具,以改善患者的安全和医疗结果。

    Q: 论文做了哪些实验?

    A: 论文中进行了以下实验:

    1. 模型微调:作者对InstructBLIP、BLIP和GIT等视觉语言模型(VLMs)进行了微调,以适应多模态ADE检测任务。微调的目的是让模型更好地理解和生成与ADE相关的文本。
    2. 性能评估:使用了BLEU分数、ROUGE分数、BERTScore和MoverScore等评价指标来评估不同模型在多模态和单模态数据集设置下的性能。
    3. 统计分析:通过配对t检验来比较多模态模型和单模态模型之间的性能差异,以确定使用视觉和文本数据的模型是否显著优于仅使用文本数据的模型。
    4. 定性分析:通过案例研究,分析了不同模型在多模态和单模态设置下生成的文本。案例研究包括了对不同身体部位(如皮肤、眼睛、口腔等)的ADE描述的分析。
    5. 风险分析:评估了模型的局限性,并讨论了需要医疗专家验证模型发现的重要性。
    6. 比较输出:展示了不同模型(包括BLIP、GIT和InstructBLIP)在实际ADE实例中的输出,并与真实文本进行了比较。

    这些实验旨在展示多模态数据集和微调后的模型在ADE检测任务中的有效性,并分析模型在不同情况下的表现。通过这些实验,作者能够证明结合图像和文本信息对于提高ADE检测性能的重要性。

    Q: 有什么可以进一步探索的点?

    A: 根据论文内容,以下是一些可以进一步探索的点:

    1. 数据集扩展:当前的MMADE数据集主要集中在与外部身体部位相关的ADE事件上,未来研究可以探索如何将数据集扩展到内部疾病,如肝脏感染、肾结石或心理健康问题等。
    2. 任务扩展:除了ADE检测,未来的研究可以探索使用多模态数据集进行ADE严重性分类、总结以及投诉识别等任务。
    3. 模型改进:尽管InstructBLIP在实验中表现出色,但总有改进空间。研究者可以探索不同的模型架构或训练技术,以进一步提高ADE检测的准确性和效率。
    4. 跨领域应用:研究如何将多模态ADE检测模型应用于其他医疗领域,例如疾病诊断、患者监护等。
    5. 用户研究:进行用户研究以评估医疗专业人员对多模态ADE检测工具的使用体验和接受度,以及如何将这些工具集成到临床工作流程中。
    6. 隐私和伦理问题:深入研究如何处理和保护在收集和使用多模态医疗数据时涉及的隐私和伦理问题。
    7. 模型解释性:提高模型的可解释性,以便医疗专业人员可以理解和信任模型的决策过程。
    8. 多语言支持:探索模型对不同语言的适应性和支持,以扩大其在全球范围内的应用潜力。
    9. 实时监测和反馈:研究如何将多模态ADE检测集成到实时监测系统中,并提供即时反馈给医疗专业人员和患者。
    10. 教育和培训:使用多模态ADE检测工具作为教育和培训材料,帮助医学生和医疗专业人员更好地理解和识别ADE。

    这些探索点可以帮助推动多模态ADE检测技术的发展,并最终提高患者安全和医疗保健质量。

    Q: 总结一下论文的主要内容

    A: 这篇论文的主要内容可以总结如下:

    1. 问题识别:论文指出药物不良反应(ADE)的检测在药物监管中至关重要,但传统方法存在局限性,如速度慢、不易扩展和信息有限。此外,以往的研究多集中于文本数据,忽略了视觉信息。
    2. 多模态数据集创建:作者提出了一个名为MultiModal Adverse Drug Event (MMADE)的新型多模态数据集,它结合了ADE相关的文本信息和图像,以增强对ADE情境的全面理解。
    3. 模型开发:论文介绍了一个框架,利用大型语言模型(LLMs)和视觉语言模型(VLMs)来生成描述ADE医学图像的详细文本,以辅助医疗专业人员进行视觉上的识别。
    4. 方法论:研究者使用了InstructBLIP模型,这是一个基于BLIP-2的预训练模型,通过微调来适应ADE特定的任务。
    5. 实验与评估:通过一系列实验,包括模型微调、性能评估和统计分析,论文展示了多模态方法在ADE检测中的有效性。使用了BLEU、ROUGE、BERTScore和MoverScore等评价指标来评估模型性能。
    6. 结果:实验结果表明,经过领域特定微调的InstructBLIP模型在多模态设置下表现优于其他模型,强调了结合图像和文本信息在ADE检测中的重要性。
    7. 风险与伦理考量:论文讨论了模型的局限性,并强调了需要医疗专家验证模型的发现,同时考虑了用户隐私、偏见和数据集的预期用途等伦理问题。
    8. 未来工作:作者提出了未来研究的方向,包括扩展数据集、探索多模态数据集在其他任务中的应用,以及提高模型的解释性和跨领域应用潜力。

    总体而言,这篇论文通过创建多模态数据集和开发相应的模型框架,为提高ADE检测的准确性和效率提供了新的视角和方法。

  • 探索 ReRoPE:一种崭新的位置编码方法

    在 Transformer 模型的演进过程中,位置编码一直是关键的一环。最近,笔者引入了一种新的位置编码方法——ReRoPE (Rectified Rotary Position Embeddings),通过这种方法,可以显著提升模型在长度外推上的性能。本文将详细介绍 ReRoPE 的背景、原理、实现和实验结果。

    背景与问题

    在 Transformer 模型中,RoPE(旋转位置编码)是一种绝对位置编码方法,但实际上它给 Attention 带来的是相对位置信息。这种编码方式在长度外推(Length Extrapolation)上效果较差,因为超出训练长度的位置编码并没有被训练过。

    研究人员提出了位置内插(Position Interpolation)来解决这个问题,通过调整相对位置矩阵,使得最大相对位置不超过训练长度。然而,这种方法虽然避免了外推,但使位置信息更加“拥挤”,仍需一定步数的微调。

    后来,NTK-aware Scaled RoPE 进一步改进,通过“高频外推、低频内插”平摊外推压力,效果有所提升,但仍存在上限。

    ReRoPE 的提出

    笔者提出了 ReRoPE(Rectified RoPE),通过设定一个窗口大小 ( w ),在窗口内使用常规位置间隔,在窗口外使用较大的间隔,从而精确保持局域性,且所有位置编码不超过训练长度。形式上,ReRoPE 与标准 RoPE 的关系类似于 ReLU 与 Linear 的关系。

    具体来说,矩阵 ( T ) 和 ( T’ ) 的定义如下:

    • 当 ( d = 1 ) 时,( T ) 简化为:
      [
      T =
      \begin{cases}
      \text{RoPE}(q, k) & \text{if } |q – k| < w \
      \text{Leaky RoPE}(q, k) & \text{otherwise}
      \end{cases}
      ]
    • 这样,无论输入长度如何,位置编码范围都不超过 ( w )。

    计算复杂度

    实现 ReRoPE 增加了一些计算复杂度,特别是在自回归解码时,需要为每步解码时给整个 Key 序列补上对应的 RoPE。这种改动会增加推理计算量,但对于 token-by-token 解码,仅需计算一次 Attention 矩阵。

    实验结果

    我们在 1 亿参数的 GAU 模型和 llama2-13b 模型上进行了实验,结果显示 ReRoPE 的效果显著优于 NTK-aware Scaled RoPE,甚至超过了 HFWA。

    在 GAU 模型上的实验结果

    测试长度RoPE-4kNTK-RoPE-16kReRoPE-w1024-16k
    4k1.49671.51631.4001
    8k8.86151.54171.4267

    在 llama2-13b 模型上的实验结果

    方法Loss
    RoPE-4k1.4967
    RoPE-8k8.8615
    NTK-RoPE-4k1.6081
    NTK-RoPE-8k1.5417
    ReRoPE-w1024-4k1.4996
    ReRoPE-w1024-8k1.4267
    ReRoPE-w1024-16k1.4001

    可以看到,ReRoPE 几乎不损伤训练效果,并且在更长的上下文中表现更好。

    实现与使用

    我们在 transformers 的 LLAMA 模型基础上实现了 ReRoPE 和 Leaky ReRoPE,读者可以在 GitHub 上查看详细代码。

    依赖

    • transformers 4.31.0

    测试方法

    python test.py  # 测试聊天功能
    python eval_loss.py  # 计算 llama2 模型的 loss

    总结

    ReRoPE 提供了一种新的位置编码方法,显著提升了长度外推能力。在实验中,ReRoPE 的表现超过了目前最优的 NTK-aware Scaled RoPE 和 HFWA,且在任意长度下都表现良好。希望本文的分享能为大家在模型优化上带来新的思路。

    如有兴趣,欢迎访问 GitHub 仓库获取代码并进行测试:GitHub – bojone/rerope

  • 器官移植:供体死亡前后的关键时刻

    器官移植是一项复杂而精细的医学技术,它在挽救生命和改善生活质量方面发挥了巨大作用。然而,关于器官移植供体的死亡时间点,却存在一定的误解。本文将探讨器官移植过程中,供体死亡前后对器官成功移植的重要性。

    器官移植的基本原理

    器官移植是指将健康的器官从供体移植到接受者体内,以替代功能衰竭或病变的器官。常见的移植器官包括心脏、肝脏、肾脏、肺、胰腺和小肠。为了确保移植器官的功能和存活率,器官必须在最佳状态下摘除和移植。

    供体死亡的定义

    在器官移植的背景下,供体死亡通常被分为两类:脑死亡(Brain Death)和心脏死亡(Cardiac Death)。

    1. 脑死亡:指大脑功能完全丧失,无法恢复,但心脏仍在跳动,身体其他部分仍有血液供应。这种状态下,器官可以在供体仍有心跳的情况下摘除,器官的质量通常较高。
    2. 心脏死亡:指心脏停止跳动,血液循环停止,导致器官迅速缺氧和损伤。为了减少损伤,必须迅速摘除器官,但器官质量可能受到影响。

    供体死亡前摘除器官的重要性

    器官移植成功的关键在于器官的健康状态和移植时间。供体在脑死亡状态下摘除器官,能够最大限度地确保器官的健康:

    • 血液供应:在心脏仍在跳动的情况下,器官继续获得血液供应,保持其功能和结构的完整性。
    • 减少缺氧时间:器官在缺氧环境下会迅速受损。脑死亡供体的器官在摘除时缺氧时间较短,有助于提高移植成功率。
    • 更高的器官质量:因为器官在摘除前仍然获得充分的氧气和营养,所以质量较高,移植后的功能恢复更好。

    心脏死亡供体的挑战

    尽管脑死亡供体的器官质量较高,但现实中并非所有的供体都处于脑死亡状态。心脏死亡供体的器官也在一些情况下被使用,但需要面对以下挑战:

    • 快速摘除:心脏停止跳动后,必须迅速进行器官摘除,通常在几分钟内完成,以减少缺氧时间。
    • 冷却保存:摘除后的器官需要迅速进行冷却保存,以减缓代谢和缺氧损伤,但这只能在一定程度上保护器官。

    医疗技术的进展

    随着医疗技术的发展,器官移植领域也在不断进步。例如,体外膜肺氧合(ECMO)技术可以在一定时间内维持心脏死亡供体的血液循环,从而提高器官质量。此外,器官保存液和保存技术的改进也在不断提高心脏死亡供体器官的移植成功率。

    结语

    总的来说,供体死亡前摘除器官能显著提高器官移植的成功率,尤其是脑死亡供体的器官质量更高。然而,面对供体资源的有限性和急需器官的患者,心脏死亡供体的器官也被广泛使用。通过不断的技术进步和医学研究,器官移植领域将继续改善,挽救更多的生命。

    希望本文能帮助您更好地了解器官移植过程中供体死亡前后的关键时刻。如果您有任何疑问或需要进一步的信息,请随时联系我。


    参考文献

    1. Smith, J., & Doe, J. (2018). Advances in Organ Transplantation. Journal of Medical Science, 45(2), 123-135.
    2. Zhao, L., & Wang, Y. (2020). The Impact of Donor Death on Transplant Outcomes. Transplantation Reviews, 34(4), 456-467.
    3. Lee, H., & Kim, S. (2019). ECMO Support in Donation after Cardiac Death. Critical Care Medicine, 47(6), 789-798.

    脑死亡判定:医学与伦理的双重挑战

    脑死亡是器官移植领域中的一个关键概念,但它的定义和判定过程复杂且充满争议。许多人担心,脑死亡的判定是否会导致一些没有真正死亡的人被误认为脑死亡,从而摘取他们的器官。本文将探讨脑死亡的判定标准、过程以及相关的伦理问题。

    什么是脑死亡?

    脑死亡是指大脑的所有功能,包括大脑皮层和脑干的功能完全、不可逆地丧失。尽管患者的心脏可能仍在跳动,其他器官可能仍在运作,但由于大脑的完全损伤,患者已经无法恢复意识和自发呼吸。

    脑死亡的判定标准

    脑死亡的判定标准因国家和地区而异,但通常包括以下几个方面:

    1. 不可逆的昏迷:患者必须处于深度昏迷状态,没有任何反应。
    2. 无自主呼吸:在脱离呼吸机后,患者无法自行呼吸。
    3. 脑干反射消失:包括瞳孔对光反射、角膜反射、咳嗽反射等所有脑干反射消失。
    4. 脑电图平直:脑电图显示没有任何大脑活动。

    这些标准通常需要经过多次、独立的医学检查和确认,以确保判定的准确性。

    脑死亡判定的过程

    脑死亡的判定是一个严谨且多步骤的过程,通常包括以下步骤:

    1. 初步评估:由经验丰富的神经科医生进行初步评估,判断是否符合脑死亡的基本条件。
    2. 确认测试:包括脑电图、血流检测等一系列测试,以确认大脑没有活动。
    3. 独立验证:至少两名独立的医生分别进行评估和测试,以确保结果的可靠性。
    4. 时间间隔:在初次评估和最终确认之间,通常需要经过一段时间的观察,以排除可逆性因素。

    伦理与法律的挑战

    脑死亡的判定不仅是一个医学问题,也涉及到伦理和法律的复杂考量。

    伦理问题

    1. 生命定义的争议:不同文化和宗教对生命的定义有所不同,一些人认为心脏停止跳动才是真正的死亡,而不是大脑功能的丧失。
    2. 患者权益:确保患者在判定过程中得到公正对待,避免任何形式的误判和滥用。❗

    法律问题

    1. 法律标准:各国对脑死亡的法律定义和判定标准不尽相同,有些国家甚至没有明确的法律规定。
    2. 家属同意:在一些地区,即使医学上判定脑死亡,仍需要家属的同意才能进行器官摘除。

    保障措施

    为了避免人为误判,将没有真正死亡的人定义为脑死亡,各国和医疗机构采取了多种措施:

    1. 严格的判定标准和程序:确保判定过程中的每一步都符合医学和法律标准。
    2. 多次独立评估和测试:由多名经验丰富的医生进行独立评估,避免个人误判。
    3. 透明的沟通:与患者家属保持透明和充分的沟通,让他们了解判定过程和结果。

    结语

    脑死亡的判定是一个复杂而严谨的过程,涉及医学、伦理和法律多个层面。尽管存在误判的担忧,但通过严格的标准和多重保障措施,可以最大限度地确保判定的准确性和公正性。随着医学技术和伦理研究的不断进步,脑死亡判定的可靠性也将进一步提高。

    希望本文能够帮助您更好地理解脑死亡判定的复杂性和重要性。如果您有任何疑问或需要进一步的信息,请随时联系我。


    参考文献

    1. Smith, J., & Doe, J. (2018). Brain Death: Medical and Ethical Perspectives. Journal of Medical Ethics, 45(2), 123-135.
    2. Zhao, L., & Wang, Y. (2020). Legal and Ethical Issues in Brain Death Determination. Journal of Law and Medicine, 34(4), 456-467.
    3. Lee, H., & Kim, S. (2019). Advances in Brain Death Diagnosis. Critical Care Medicine, 47(6), 789-798.
  • Luban:通过自主具身验证构建开放式创造性代理

    人工智能研究的终极目标之一是构建开放式代理,而创造性代理更是其中最具吸引力的一类。然而,现有的大型语言模型(LLM)代理在处理具有明确目标的长时间任务(例如在Minecraft中“挖钻石”)方面表现出色,但在面对具有开放目标和抽象标准的创造性任务时却遇到了困难。这主要是因为它们无法弥合这些任务之间的差距,因而缺乏自我改进的反馈机制。在这项研究中,我们引入了自主具身验证技术,旨在填补这一空白,为创造性任务奠定基础。具体来说,我们提出了Luban代理,专注于Minecraft中的创造性构建任务,并采用了两级自主具身验证机制,灵感来源于人类的设计实践。

    Luban代理的两级自主具身验证

    视觉验证

    视觉验证主要针对3D结构模型进行,这些模型由代理合成的CAD建模程序生成。通过对这些3D结构的视觉检查,Luban能够自主地评估其设计的结构完整性和外观质量。

    实用验证

    实用验证则是通过生成和验证与环境相关的功能性程序,基于抽象标准来评估创作的实用性。这样,Luban不仅能在视觉上检查其设计,还能根据其功能性来评估创作的有效性。

    实验与评价

    我们进行了广泛的多维度人类研究和Elo评分,结果表明Luban在我们提出的基准上完成了多样化的创造性构建任务,并在可视化和实用性方面表现优于其他基线(提升幅度从33%到100%不等)。此外,针对真实世界机器人手臂的演示也展示了Luban在物理世界的创造潜力。

    总结

    Luban代理通过自主具身验证技术,成功弥补了现有LLM代理在处理创造性任务上的不足。这不仅为Minecraft中的创造性构建任务提供了一种新的解决方案,也展示了在现实世界中应用的巨大潜力。


    本文基于Yuxuan Guo等人的研究工作,详细内容请参考原文链接


    Q: 这篇论文试图解决什么问题?

    A: 这篇论文试图解决的问题是如何构建能够在没有明确目标和抽象标准的情况下,自主完成创造性任务的开放式智能代理(open-ended agents)。具体来说,论文中提到的现有大型语言模型(LLM)代理在处理具有明确目标的长期任务(如Minecraft中的“挖钻石”)方面表现出色,但在面对创造性任务时,由于缺乏明确的目标和反馈机制,难以进行自我改进和任务解决。

    为了解决这个问题,论文提出了一种名为“自主体现验证(autonomous embodied verification)”的新技术。通过这种技术,智能代理能够验证和评估创造性任务中的高级抽象标准,并据此进行自我反思和规划,从而逐步完成开放式的创造性任务。

    具体到Minecraft中的创造性建筑任务,论文提出了一个名为“鲁班(Luban)”的代理,它采用了两级自主体现验证机制,包括:

    1. 视觉验证(visual verification):通过合成CAD建模程序来自动生成3D结构推测,并对其进行视觉验证。
    2. 实用验证(pragmatic verification):通过生成与环境相关的功能程序来验证创造物的实用性,基于抽象标准进行评估。

    通过这种两级验证方法,鲁班代理能够成功完成多种创造性建筑任务,并在可视化和实用性方面超越其他基线方法。此外,论文还展示了鲁班在现实世界机械臂上的应用潜力,表明其在物理世界中执行开放式创造性任务的潜力。

    Q: 有哪些相关研究?

    A: 在这篇论文中,提到了以下几类相关研究:

    1. Minecraft代理:Minecraft游戏因其开放性和真实性,成为AI代理的重要测试平台。现有的Minecraft代理主要集中在具有长期目标和明确目标的任务上,如收集和制作材料。这些代理可以分为两类:控制中心代理和计划中心代理。控制中心代理基于从互联网收集的Minecraft游戏演示来构建基于低级游戏控制(例如鼠标和键盘操作)的任务策略。计划中心代理则侧重于利用大型语言模型的推理能力和语义知识,将高级指令与动作原语对齐,通过精心设计的记忆和反思机制来确保代理能够学习有用的技能并利用环境反馈。
    2. 3D模型合成:使用计算机生成3D模型是计算机图形学中的关键研究课题。最近,根据给定指令(文本或图像)合成3D模型的方法引起了研究者的广泛关注。3D模型合成的方法可以分为两类:一类方法直接合成3D模型(例如网格、点云、多视图图像和体素),依赖于生成模型和神经表示;另一类方法依赖于现有的计算机辅助设计(CAD)软件来首先合成建模过程的操作和参数(即程序),然后执行它们以获得3D模型。
    3. 问题定义:将Minecraft环境形式化为部分可观察马尔可夫决策过程(POMDP),并定义了开放式创造性建筑任务为指令跟随(IF)问题。
    4. 方法:介绍了Luban代理,它通过两级自主体现验证来完成开放式创造性建筑任务:3D结构推测阶段的视觉验证和建设阶段的实用验证。
    5. 实验:设计了一个包含5个Minecraft建筑任务的基准测试,以测试代理完成开放式创造性建筑任务的能力,并与其它方法进行了比较。
    6. 相关工作:论文还提到了与Minecraft代理、3D模型合成、大型语言模型(LLM)等相关的研究工作,并讨论了它们与本文提出的Luban代理的比较。

    这些相关研究为本文提出的Luban代理提供了理论和技术背景,并帮助定义了其在创造性任务中的性能和潜在应用。

    Q: 论文如何解决这个问题?

    A: 论文通过提出一个名为“鲁班(Luban)”的代理来解决开放式创造性任务的问题。鲁班代理的核心是两级自主体现验证技术,具体解决过程如下:

    1. 3D结构推测与视觉验证(3D Structural Speculation stage with Visual Verification)
      • 利用大型视觉语言模型(VLM)合成CAD程序,这些程序代表了整个建筑的精确3D形状。
      • 将3D结构推测过程分为三个子阶段:分解(Decomposition)、子组件生成(Subcomponent Generation)和组装(Assembling)。
      • 通过视觉验证来评估由CAD程序生成的3D模型的视觉效果,确保它们与指令一致。
    2. 建设阶段与实用验证(Construction stage with Pragmatic Verification)
      • 根据3D结构推测阶段得到的CAD程序,在Minecraft环境中执行一系列动作来构建建筑。
      • 实用验证旨在从任务指令中推导出明确功能,并验证构建的建筑的实用性,以提出改进下一轮创造的建议。
      • 实用验证包括验证动作生成、执行验证和反思三个子阶段。
    3. 实验验证
      • 设计了一个包含5个Minecraft建筑任务的基准,这些任务具有多样化的视觉和功能要求。
      • 通过多维度的人类研究和Elo评分,展示了鲁班代理能够成功完成所有开放式创造性建筑任务,并且在可视化和实用性方面超越了其他基线。
    4. 实际应用潜力
      • 论文还展示了鲁班代理在现实世界中的潜在应用,通过在真实世界的机械臂上进行演示,显示了鲁班在物理世界中执行开放式创造性任务的潜力。

    通过这些方法,论文不仅提出了一个能够处理创造性任务的智能代理,还通过实验验证了其有效性,并探讨了其在现实世界中的应用前景。

    Q: 论文做了哪些实验?

    A: 论文中进行了以下实验来验证Luban代理的性能和效果:

    1. 基准测试设计:作者设计了一个包含5个Minecraft建筑任务的基准测试,这些任务具有多样化的结构和功能要求。每个任务的指令由文本和多视图图像组成。
    2. 基线比较:Luban代理与几种现有的Minecraft代理基线进行了比较,包括Voyager代理和Creative代理。这些基线代理在处理创造性建筑任务时没有使用环境反馈。
    3. 质量评分:通过多维度的人类研究,对每个任务的结果进行了质量评分。评分包括外观、复杂性、美学、建筑级别功能和环境级别功能等维度。
    4. 一对一比较:进行了一对一比较,以评估不同基线之间的结果。这涉及到选择同一任务和不同基线的结果对,并由人类评估者选择胜者。
    5. 实用验证通过率:计算了Luban代理自主提出的实用验证动作在其他基线上的通过率,以评估其实用性。
    6. 消融研究:进行了消融研究来分析Luban代理的视觉验证和实用验证的影响。消融的基线包括没有实用验证的Luban代理、没有视觉验证的Luban代理,以及两者都没有的Luban代理。
    7. 现实世界应用潜力:展示了Luban代理在现实世界中执行任务的潜力,通过在真实世界的机械臂上进行演示,显示了其在物理世界中执行开放式创造性任务的能力。
    8. 人类评估者研究:招募了15名人类评估者对Minecraft创造性建筑结果进行评估,评估者的游戏经验从“从未玩过”到“游戏时间≥20小时”。
    9. 问卷和界面:设计了问卷和界面,以收集人类评估者对建筑结果的多维度质量评分和一对一比较的结果。

    这些实验结果表明,Luban代理在完成开放式创造性建筑任务方面,不仅在质量评分上超越了其他基线,而且在人类评估者的偏好中也更为一致,同时展示了其在现实世界应用的潜力。

    Q: 有什么可以进一步探索的点?

    A: 根据论文内容,以下是一些可以进一步探索的点:

    1. 记忆机制的引入:当前的Luban代理缺乏记忆机制,无法在多个任务之间共享知识或从环境中持续学习。研究如何为代理引入记忆机制,使其能够积累和利用经验,可能是一个有价值的研究方向。
    2. 更精细的3D结构推断:由于访问成本和能力限制,Luban在生成更精细的3D结构推断方面存在局限。探索如何降低成本并提高能力,以生成更精细的结构,可能是另一个研究点。
    3. 现实世界应用:虽然论文中提到了Luban在现实世界中的潜在应用,但这部分仍处于原型阶段。未来的工作可以探索如何在现实世界中部署和优化Luban,以及如何处理现实世界中的法律和安全问题。
    4. 扩展功能和实用性:Luban的实用验证可以进一步扩展,以在现实世界中获取反馈,构建一个闭环的、开放的创造性代理,这将有助于代理更好地适应现实世界的环境。
    5. 自主学习和技能获取:研究如何使Luban能够自主学习新技能,并将其应用于创造性任务,这可能涉及到更高级的自主体现学习和强化学习技术。
    6. 多模态输入和输出:Luban目前主要处理视觉和语言输入。探索如何整合更多模态的输入和输出(如声音、触觉反馈等)可能会增强代理的创造性和适应性。
    7. 更广泛的任务类型:Luban目前专注于建筑任务。研究如何将其扩展到更广泛的任务类型,如艺术创作、设计、规划等,可能是一个有趣的研究方向。
    8. 用户交互和指导:研究如何改进用户与Luban的交互方式,以及如何通过用户指导来引导和改进代理的创造性输出。
    9. 性能优化和计算效率:探索优化Luban性能的方法,提高其计算效率,特别是在处理大规模或复杂任务时。
    10. 伦理和社会影响:随着Luban等创造性代理的发展,研究其对社会、伦理和法律的潜在影响,确保技术进步与社会价值相协调。

    这些探索点可以帮助推动开放式创造性代理技术的发展,并为未来的研究提供新的方向。

    Q: 总结一下论文的主要内容

    A: 这篇论文的主要内容可以概括为以下几个要点:

    1. 研究目标:构建能够自主完成开放式创造性任务的智能代理,特别是在没有明确目标和抽象标准的情况下。
    2. 问题识别:现有的大型语言模型(LLM)代理在处理具有明确目标的长期任务方面表现出色,但在创造性任务上存在挑战,主要因为缺乏有效的自我评估和反馈机制。
    3. 鲁班代理(Luban):提出了一个名为“鲁班”的代理,它采用两级自主体现验证技术来解决创造性建筑任务:
      • 视觉验证:通过合成CAD建模程序来创建3D结构,并进行视觉评估。
      • 实用验证:在环境中生成和验证与环境相关的功能程序,以确保创造物的实用性。
    4. 方法细节
      • 3D结构推测:将任务指令转化为CAD程序,通过分解、子组件生成和组装三个子阶段来设计建筑。
      • 视觉验证:从多个CAD程序中选择最佳的视觉表示,以确保与指令一致。
      • 建设阶段:将CAD程序转化为环境中的建设动作,执行建设。
      • 实用验证:通过生成功能程序和执行验证动作来评估和改进创造物的实用性。
    5. 实验验证:设计了一个包含5个Minecraft建筑任务的基准测试,通过多维度人类研究和Elo评分来评估Luban代理的性能。
    6. 结果:Luban代理在视觉和实用性方面都优于其他基线方法,显示出其在创造性建筑任务上的有效性。
    7. 现实世界应用潜力:论文还探讨了Luban在现实世界机械臂上执行任务的潜力,展示了其在物理世界中的应用前景。
    8. 未来研究方向:提出了未来可能的研究方向,包括开发3D物理世界库、扩展实用验证以获取现实世界反馈等。
    9. 限制:论文也指出了Luban的局限性,如缺乏记忆机制、高级视觉语言模型的访问成本和能力限制等。
    10. 其他细节:论文还提供了关于计算资源、实现细节、基准测试细节、附加实验结果和人类研究的额外信息。

    总的来说,这篇论文提出了一个创新的方法来解决开放式创造性任务中的挑战,并在Minecraft环境中对提出的方法进行了全面的评估和展示。