码农知识堂 - 1000bd
  •   Python
  •   PHP
  •   JS/TS
  •   JAVA
  •   C/C++
  •   C#
  •   GO
  •   Kotlin
  •   Swift
  • 深度学习进阶(二十七)现代 LLM 的核心架构设计其二:SwiGLU


    合集 - 深度学习进阶(31)
    1.深度学习进阶(一)从注意力到自注意力03-312.深度学习进阶(二)多头自注意力机制(Multi-Head Attention)04-023.深度学习进阶(三)Transformer Block04-044.深度学习进阶(四)Transformer 整体结构04-065.深度学习进阶(五)Vision Transformer04-086.深度学习进阶(六)归纳偏置与蒸馏04-107.深度学习进阶(七)Data-efficient Image Transformer04-138.深度学习进阶(八)Swin Transformer04-159.深度学习进阶(九)池化技术的初步改进:RoI Pooling04-1910.深度学习进阶(十) RoI Align04-2111.深度学习进阶(十一)Position-Sensitive RoI Pooling04-2412.深度学习进阶(十二)可变形池化 deformable RS RoI Pooling04-2713.深度学习进阶(十三)可变形卷积 DCN04-2914.深度学习进阶(十四)ConvNeXt04-3015.深度学习进阶(十五)通道注意力 SE05-0316.深度学习进阶(十六) 混合注意力 CBAM05-0417.深度学习进阶(十七)高效通道注意力 ECA05-0518.深度学习进阶(十八)坐标注意力 CA05-0619.深度学习进阶(十九)相对位置编码 RPE05-0920.深度学习进阶(二十)Transformer-XL05-1121.深度学习进阶(二十一)跨窗口的 RPE05-1322.深度学习进阶(二十二)T5:NLP任务的首次大一统05-1523.深度学习进阶(二十三)偏置型 RPE05-1824.深度学习进阶(二十四)Swin 的二维 RPE05-2025.深度学习进阶(二十五)RoPE:现代 NLP 的位置编码范式05-2926.深度学习进阶(二十六)现代 LLM 的核心架构设计其一:RMSNorm06-01
    27.深度学习进阶(二十七)现代 LLM 的核心架构设计其二:SwiGLU06-04
    28.深度学习进阶(二十八)现代 LLM 的核心架构设计其三:Decoder-Only 下的 KV Cache06-0829.深度学习进阶(二十九)现代 LLM 的核心架构设计其四:GQA06-0930.深度学习进阶(三十)从 Transformer 到 LLaMA:现代 LLM 架构总览06-1631.深度学习进阶(三十一)FlashAttention:IO 感知的精确注意力06-19
    收起

    上一篇我们看了现代大模型对归一化的改造。
    RMSNorm 去掉了均值中心化,只保留均方根缩放:一个沿用多年的标准组件,拆开一看,其中一部分工作在现代整体架构中已经有些多余了。

    本篇来看第二个改动:Transformer 架构中的 FFN (MLP) 层的重构,而其具体内容,需要先从激活函数说起。

    1. 激活函数的发展历程#

    很早之前,我们就展开过激活函数的相关内容:激活函数。其本质是给神经网络引入非线性。 这里再简单复述一遍:
    Sigmoid 是最早被广泛使用的激活函数:

    σ(x)=11+e−x

    sigmoid.png

    Sigmoid 将任意实数压缩到 (0,1) 区间,在隐藏层可以理解为"激活概率",但现在更常见在分类头等输出层最后表示概率。
    但它有两个问题:

    1. 输出不是零中心的,会导致后一层接收的输入始终为正,导致反向传播时权重梯度容易同号,梯度更新效率低。
    2. 两端饱和严重,x 较大或较小时梯度几乎为零,深层网络中容易梯度消失。

    Tanh 缓解了第一个问题:

    tanh⁡(x)=ex−e−xex+e−x

    tanh.png

    很明显它把输出范围压缩到 (−1,1),实现了零中心化。但梯度饱和的问题仍然存在,在 x 绝对值较大的区域梯度依然趋近于零。

    真正的转折点是 2012 年前后 ReLU(Rectified Linear Unit) 的普及:

    ReLU(x)=max(0,x)

    relu.png

    ReLU 的形式极简:正半轴保持梯度为 1,负半轴直接归零。
    但这种看似不合理的设计却在隐藏层传播中带来了极大优势:正半轴梯度恒为 1,梯度消失问题被大幅缓解,同时计算更是简单到只需要一个比较操作。
    ReLU 对训练深层网络起到积极贡献(此外还有残差网络),因此也是很长一段时间里的默认选择。

    但 ReLU 也有自己的问题:负半轴完全归零会导致死神经元:当某个神经元对所有训练样本都输出负值时,其梯度将始终为 0,参数无法继续更新,从而永久停留在负半区。

    因此:出现了一批试图修复这个问题的变体:

    1. Leaky ReLU:max(αx,x),负半轴改为一个小斜率 α(比如 0.01),让信息仍然可以流动。
    2. PReLU:把 α 变成可学习的参数。
    3. ELU:负半轴用指数曲线,让输出均值接近零。
      activation_comparison.png
      这些变体各自有一些效果,但都没有真正取代 ReLU 的主流地位。

    再往后就来到了 16 年的 Gaussian Error Linear Units(GELU):

    GELU(x)=x⋅Φ(x)

    gelu.png

    我们在之前的 ConvNeXt中也简单展开过它, Φ(x) 是标准正态分布的累积分布函数。
    GELU 在 ReLU 的基础上做了平滑,负半轴有一个非零的"尾巴",在 x=0 附近也是光滑可导的。
    它在 NLP 领域很受欢迎,BERT 和 GPT 系列都用了它,它也逐渐成为 Transformer 系列中 FFN 的默认激活函数。

    此外,17 年 Google 在 Searching for Activation Functions 提出了 Swish 激活函数,它看起来和 GELU 十分相似:

    Swish(x)=x⋅σ(x)

    swish_vs_gelu.png

    Swish 是 Google 实验室在同一个网络中进行只换激活函数的大规模 A/B Test 得到的,并没有从理论推导,而是纯粹实验发现的优解。

    从函数形状上看,Swish 与 GELU 几乎等价,二者性能差距通常很小。
    历史上 NLP 社区由于 BERT 的成功更偏向 GELU,而 CV 领域曾广泛采用实现更简单的 Swish。
    这种难分伯仲的情况也让研究者开始跳出 “用哪种激活函数” 去发现其他逻辑,这也是下部分的内容:

    2. 标准 FFN 的结构局限#

    简单过了过激活函数后,现在我们再来看 Transformer Block 中的 FFN 层:

    FFN(x)=W2⋅σ(W1x+b1)+b2

    其中 σ 是激活函数,原版 Transformer 使用 ReLU,后续则大多换成了 GELU。
    这条信息流路径非常直接:

    输入升维激活降维输出输入升维激活降维输出输入→升维→激活→降维→输出

    原理也很清晰:FFN 可以学习特征的重要性,在训练过程中,权重矩阵 W1 和 W2 会不断调整,从而让网络自动学会哪些模式更值得关注。

    但以事后诸葛亮的视角来看,它仍然存在一个隐含的限制:

    完成训练后,FFN 学到的是固定的重要性,而不是针对当前输入的动态重要性。

    也就是完成训练后,某个隐藏神经元在训练过程中学会了识别某种特征,那么无论输入什么样本,它都会使用同一套权重进行计算。

    这与注意力机制形成了鲜明对比,在 Attention 逻辑中,不同输入会产生不同的注意力分布,因此模型能够动态决定哪些信息应该被重点关注、哪些信息应该被弱化甚至忽略。

    这种根据当前样本实时调整权重的能力,我们称之为动态门控思想。

    既然 Attention 可以动态选择重要信息,那么 FFN 能否也拥有类似的能力?

    而答案正是后来逐渐流行起来的门控机制,我们之前在 RNN 中介绍过,例如 GRU 和 LSTM都利用门控控制信息流动。
    不久前的 通道注意力系列等其实也是这种门控思想的应用。

    那么如何实现在 FFN 中实现门控逻辑?就是本篇的主角:

    3. SwiGLU#

    3.1 GLU:门控线性单元#

    GLU(Gated Linear Unit) 来自 17 年的论文 Language Modeling with Gated Convolutional Networks。它在标准全连接基础上增加了一个分支:

    GLU(x)=(xW+b)⊙σ(xV+c)

    其中:

    • 左边的是 Value 分支。
    • 右边是 Gate 分支,使用 Sigmoid 函数激活。

    5fd20f50-3554-4c82-b53e-807e708235da.png

    其实逻辑和之前的SE是十分相似的,将输入同步聚合为一组权重再作用在输出上,实现门控逻辑。

    这便是最基础的 GLU 逻辑。

    3.2 SwiGLU#

    Sigmoid 门控本身是很符合我们的现实逻辑的,但在后续的实践中,研究者们却发现它其实不一定是最优选择。
    20 年,论文 GLU Variants Improve Transformer 中做了一个系统的实验:把标准 FFN 替换成各种 GLU 变体,看门控激活函数选哪个最好,而 SwiGLU 表现最好,也由此在后续的实践中逐渐发扬光大。

    SwiGLU 其实就是把 GLU 中的 Sigmoid 激活函数更换为了 Swish 函数:(DL 论文里经常忽略偏置,Transformer 架构里偏置甚至经常在实现中被直接删除。)

    SwiGLU(x)=(xW)⊙Swish(xV)

    而对于为什么使用 Swish 要强于 sigmoid 比较主流的认知主要集中在两点:

    1. sigmoid 的 0-1 取值范围只能实现抑制和保留,而 Swish 却不受限于 0-1,可以实现放大。
    2. sigmoid 在网络传播中的梯度问题仍然存在,Swish 更好优化。

    3.3 一个应用 SwiGLU 的 FFN 子层#

    最终,Transformer block 在引入 SwiGLU 后,原本的 FFN 子层本的升维层被拆成了两条并行分支:

    SwiGLU(x)=(xWv)⊙Swish(xWg)

    随后再正常通过原本的降维层,整体表示如下:

    FFNSwiGLU(x)=Wo((xWv)⊙Swish(xWg))

    9540b336-4a61-41fd-81da-a39535614359.png

    显然,其改进就在于利用额外的门控分支实现输入相关的动态调制。
    这样,整个 Transformer block 就都拥有了动态调制输入的能力。

    如今的开源大语言模型中,SwiGLU 也已经基本成为 FFN 模块的默认选择。

    4. SwiGLU 的参数问题#

    在具体实现中,一个需要展开的点是 SwiGLU 的参数问题。

    很明显的是,标准 FFN 用了 2 个权重矩阵,而 SwiGLU 由于门控分支增加到了 3 个。凭空多出一个矩阵,参数量必然上涨。

    于是,为了保持参数量持平,LLaMA 将中间维度,也就是升维维度从 4d 压缩到了 83d≈2.67d。

    对比一下:

    1. 标准 FFN:

    Params=2×(d×4d)=8d2

    1. SwiGLU FFN:

    Params=d×83d+d×83d+83d×d=3×83d2=8d2

    刚好相等。这是刻意的参数预算分配。
    因此,SwiGLU 的性能提升并不能简单归因于堆参数,而是在相同参数预算下,通过重新分配容量获得了更好的效果。

    简单看几个例子:

    模型 dmodel dff(标准 4×) dff(SwiGLU 的 8/3×)
    LLaMA 7B 4096 16384 11008
    LLaMA 13B 5120 20480 13824
    LLaMA 70B 8192 32768 28672

    从 dff 实际取值来看,LLaMA 选择了比 83d 更规整的实际数字(通常取 8 的倍数),接近但不完全等于理论值。

    作者:哥布林学者

    出处:https://www.cnblogs.com/Goblinscholar/p/20309898

    版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

    给自己一些时间。

  • 相关阅读:
    SpringBoot和MybatisPlus的多数据源配置及两者的区别
    Java设计模式之模板方法模式
    Java IO学习笔记(二):字节流与字符流
    JAVA便利店库存管理计算机毕业设计Mybatis+系统+数据库+调试部署
    【C语言】-动态内存管理
    向量数据库的分类概况
    React类组件和函数组件对比-Hooks的介绍及初体验
    一篇万字博文带你入坑爬虫这条不归路 【万字图文】
    Python教程——最后一波来喽
    classification_report分类报告的含义
  • 原文地址:https://www.cnblogs.com/Goblinscholar/p/20309898
  • 最新文章
  • 沪漂五周年了:我越来越迷茫了
    Agentic Skill Routing 实战:别再把所有 Skill 塞进 AI Agent 上下文
    MySQL-Seconds_behind_master的精度误差
    [MAF预定义ChatClient中间件-03]CachingChatClient——利用缓存省钱省时间
    AI的至暗历史:从万众期待到被政府撤资,AI的两次死亡徘徊
    Agent OS :五种驯服不确定性的范式
    PortSwigger SQL注入LAB11
    数据库即时编译JIT
    [Begin]AI Learn Data Day 0
    深度学习进阶(二十七)现代 LLM 的核心架构设计其二:SwiGLU
  • 热门文章
  • 十款代码表白小特效 一个比一个浪漫 赶紧收藏起来吧!!!
    奉劝各位学弟学妹们,该打造你的技术影响力了!
    五年了,我在 CSDN 的两个一百万。
    Java俄罗斯方块,老程序员花了一个周末,连接中学年代!
    面试官都震惊,你这网络基础可以啊!
    你真的会用百度吗?我不信 — 那些不为人知的搜索引擎语法
    心情不好的时候,用 Python 画棵樱花树送给自己吧
    通宵一晚做出来的一款类似CS的第一人称射击游戏Demo!原来做游戏也不是很难,连憨憨学妹都学会了!
    13 万字 C 语言从入门到精通保姆级教程2021 年版
    10行代码集2000张美女图,Python爬虫120例,再上征途
小工具 小游戏
Copyright © 2022 侵权请联系2656653265@qq.com    京ICP备2022015340号-1

京公网安备 11010502049817号