惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

人人都是产品经理
人人都是产品经理
博客园_首页
博客园 - 三生石上(FineUI控件)
V
Visual Studio Blog
Hugging Face - Blog
Hugging Face - Blog
美团技术团队
小众软件
小众软件
T
Tailwind CSS Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
月光博客
月光博客
有赞技术团队
有赞技术团队
WordPress大学
WordPress大学
博客园 - 【当耐特】
Apple Machine Learning Research
Apple Machine Learning Research
罗磊的独立博客
V
V2EX
酷 壳 – CoolShell
酷 壳 – CoolShell
IT之家
IT之家
量子位
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Recent Announcements
Recent Announcements
M
MIT News - Artificial intelligence
阮一峰的网络日志
阮一峰的网络日志
The GitHub Blog
The GitHub Blog

Longlong's Blog

从PPO到DPO的数学推导以及实现 - Longlong's Blog RLHF中的PPO算法——TRL库的PPOTrainer源码分析 - Longlong's Blog 从0强化学习基础到理解PPO - Longlong's Blog llava源码精读 - Longlong's Blog MHA、MQA、GQA小结 - Longlong's Blog 从 LayerNorm 到 RMSNorm:为什么可以去掉均值? - Longlong's Blog CLIP、SigLIP、SigLIP2小结 - Longlong's Blog 熵、交叉熵、KL散度的区别 - Longlong's Blog 由Sinusoidal位置编码到RoPE - Longlong's Blog LoRA小结 - Longlong's Blog GPT3与ChatGPT有什么不同?——RLHF技术小结 - Longlong's Blog Bert源码解读(HuggingFace Transformers源码) - Longlong's Blog The Annotated Transformer学习笔记(Transformer的pytorch实现)(下) - Longlong's Blog The Annotated Transformer学习笔记(Transformer的pytorch实现)(上) - Longlong's Blog Transformer小结 - Longlong's Blog 基于encoder-decoder架构的注意力机制 - Longlong's Blog Seq2Seq模型与encoder-decoder架构(附代码实现一个小小demo) - Longlong's Blog LSTM小结 - Longlong's Blog
RELU到SwiGLU:LLM中FFN层的演变 - Longlong's Blog
Longlong · 2026-08-20 · via Longlong's Blog

原始transformer的FFN层

原始transformerFFN层非常简单,就是一个升维+降维的操作,中间套一个RELU激活函数:

FFN层的作用是增加模型的非线性能力,升维再降维的操作也是老传统了,之前学从感知机到多层感知机就明白,一个低的维度的特征终归是有限,但是高的维度,能够组合更多的特征,学到更多的东西。
相关研究(Transformer Feed-Forward Layers Build Predictions by Promoting Concepts in the Vocabulary Space)发现 Transformer FFN 会编码词汇和概念信息,可以说FFN层是存储着世界知识。

在传统深度学习中,就有老生常谈的"死亡ReLu"问题。当x<0的时候,Relu是输出是0,梯度为0,这个神经元就可以看作"死亡了",这在大规模的LLM训练中,这个问题更严重。

GLEU

后续很多基于transformer架构的模型,例如Bert、GPT1都是采用了GELU(Gaussian Error Linear Units)这个激活函数

其中:

表示标准正态分布的累积分布函数。
GELU相比ReLU改进在哪里?
GELU的核心思想是:不要像ReLU一样进行简单的二值化筛选,而是根据输入值的重要程度进行平滑地保留信息

可以看作一个动态权重,决定当前输入应该保留多少。

时:,
此时

信息基本保留。

当:时:

此时

信息被抑制。

  • ReLU 是硬门控(Hard Gate),直接判断保留或丢弃;
  • GELU 是软门控(Soft Gate),通过连续函数平滑控制信息流。
    这使得GELU在大规模Transformer训练中通常比ReLU更加稳定。

GLU——引入显式门控机制

虽然GELU可以根据输入调整激活程度,但是它仍然只有一条信息路径。输入特征既负责提供信息,又负责决定自己是否被保留。
门控机制很早就有了。2020年google的一项研究将他引入了transformer的FFN层:
GLU Variants Improve Transformer

其中:

  • :信息分支,负责产生特征;
  • :门控分支,负责控制信息是否通过;
  • :逐元素乘法。

他的思想就是将信息提取和信息筛选分开。模型可以学习一个专门的门控函数,动态控制不同特征的重要程度。
论文中还研究了各种门控函数的变体

20260820173738


20260820173745

最后效果比较好的就是SwiGLU了

GLU变体的胜出者:SwiGLU

门控的思想我们已经掌握了,就是将信息提取和信息筛选分开,模型可以学习一个专门的门控函数,动态控制不同特征的重要程度。各种变体无非就是这个门控函数的激活函数不同。

SwiGLU用的激活函数为:Swish(也叫 SiLU,Sigmoid Linear Unit):

可以看到Siwsh就是x乘以一个函数,只是比原始的GLU的激活函数多乘了一个
这会带来什么优势?

原始的GLU的门控范围为0~1,这意味着只能对通过的信息进行缩小或者不变,没法放大,当较大时,可以保留甚至增强正向信息;当为负值时,仍然保留部分负方向信息,而不是像ReLU一样直接截断。Swish相比sigmoid具有更加灵活的信息调节能力,既负责开关,又负责调节幅度

实现

以下摘自modeling_llama.py(已删除无关内容以及分支)

class LlamaMLP(nn.Module):
    def __init__(self, config):
        super().__init__()
        self.config = config
        self.hidden_size = config.hidden_size
        self.intermediate_size = config.intermediate_size
        self.gate_proj = nn.Linear(self.hidden_size, self.intermediate_size, bias=False)
        self.up_proj = nn.Linear(self.hidden_size, self.intermediate_size, bias=False)
        self.down_proj = nn.Linear(self.intermediate_size, self.hidden_size, bias=False)
        self.act_fn = ACT2FN[config.hidden_act]#hidden_act="silu",

 def forward(self, x):
    down_proj = self.down_proj(self.act_fn(self.gate_proj(x)) * self.up_proj(x))

代码很简单,这里不再阐述