南京大学LLM开发基础(四)MoE, LoRA, 数的精度 + MLP层实验

作者:nju_spy日期:2025/10/30

https://njudeepengine.github.io/llm-course-lecture/2025/lecture8.html#1

目录

1. Mixture-of-experts (MoE)

1.1 优势

1.2 结构

1.3 训练

2. Low-rank adaptation (LoRA)

3. 数的精度 -- 混合精度 + 量化操作

Task1:DenseMLPWithLoRA

一、任务背景

二、任务要求

Task2:Sparse MLP


1. Mixture-of-experts (MoE)

通过gating model/network 选择最适合的专家。

Switch Transformers 将Transformers中的 FFN替换为MoE 结构。

1.1 优势

1. 推理阶段的效率提升:

每次只用一部分专家的参数;条件计算动态资源分配

门控网络会根据输入样本的难度和类型动态地选择最合适的专家。

处理简单任务时: 模型可能会路由到一些相对“简单”或计算量较小的专家,从而更快地给出响应。

处理复杂任务时: 模型会调用**更“专业”**的专家,虽然计算量稍大,但能保证输出质量。

2. 以恒定计算成本,实现模型参数规模的巨量提升。

  • 传统模型(稠密模型): 增加参数意味着每一层、每一个输入都要经过所有这些参数的计算。模型变大,计算成本(FLOPS)和时间几乎线性增长。
  • MoE 模型(稀疏模型): 模型总参数量可以变得极其巨大(例如万亿参数),但对于每个具体的输入,只有一小部分“专家”(通常是1个或2个)被激活并参与计算。这意味着:
    • 总参数量巨大:模型拥有海量的知识和能力储备。
    • 激活参数量固定:无论总参数是千亿还是万亿,处理一个 token 实际使用的参数数量是基本不变的,因此计算成本得以保持在一个可接受的水平。

3. 预训练速度显著加快:

相同的计算资源(如相同的GPU数量和训练时间)下,MoE 模型能获得比稠密模型更好的性能

1.2 结构

topk 得到前 k 名,对分数 softmax 得到每个export权重。

1class TopKGating(nn.Module):
2    def __init__(self, hidden_dim, num_experts, k=2):
3        super().__init__()
4        self.router = nn.Linear(hidden_dim, num_experts, bias=False)  # 路由网络
5        self.k = k  # 选择专家数量
6    def forward(self, x):
7        # 1. 计算专家得分
8        scores = self.router(x)  # [batch, experts]
9        # 输入x: [batch_size, hidden_dim]
10        # 输出scores: [batch_size, num_experts]
11        # 每个样本对每个专家得到一个得分
12        
13        # 2. 选择Top-K专家
14        topk_scores, topk_idx = torch.topk(scores, self.k, dim=-1)
15        # topk_scores: [batch_size, k] - 前k个最高得分
16        # topk_idx: [batch_size, k] - 对应的专家索引
17        
18        # 3. 计算选择概率
19        probs = torch.softmax(topk_scores, dim=-1)
20        # 对选中的k个专家得分做softmax,得到归一化的权重
21        
22        # 4. 构建门控矩阵
23        gate = torch.zeros_like(scores)  # 创建全零矩阵 [batch_size, num_experts]
24        gate.scatter_(-1, topk_idx, probs)  # 将概率值填充到对应位置
25        # 结果gate: [batch_size, num_experts],每行只有k个非零值

1.3 训练

训练不稳定性问题:

  • 强者恒强:某些专家训练得快,获得更高权重,被选择更多
  • 弱者淘汰:其他专家得不到充分训练,逐渐被边缘化
  • 模式坍塌:最终只有少数专家被使用

下面三个解决方案:

1. Auxiliary Loss 辅助损失:均衡各个专家的选择概率

  • 计算每个专家被选择的概率分布
  • 计算批次中实际选择每个专家的频率分布
  • 惩罚这两个分布之间的差异,鼓励均匀分布

2. Capacity Factor 容量因子

预先计算每个专家的"容量" 处理token数量上限。多余的强制给别的expert。

3. Shared Experts 共享专家机制

设计专家架构时(不同损失函数)就将专家分为"通用型"和"专用型"。

  • 共享专家:处理通用模式和基础特征,保证基本利用率
  • 专用专家:学习特定领域或复杂模式,允许一定程度的专业化

2. Low-rank adaptation (LoRA)

https://arxiv.org/abs/2106.09685

随着预训练的模型规模不断扩大,对所有模型参数进行全量微调(full fine-tuning)不可行。

冻结预训练模型的权重,并在 Transformer 架构的每一层中注入可训练的低秩分解矩阵

从而大幅减少下游任务所需的可训练参数数量

LoRALayer 求更新的变化值。 A = [ in, rank] B = [ rank, out ]

1import torch.nn as nn
2
3class LoRALayer(nn.Module):
4    def __init__(self, in_dim, out_dim, rank, alpha):
5        super().__init__()
6        std_dev = 1 / torch.sqrt(torch.tensor(rank).float())
7        self.A = nn.Parameter(torch.randn(in_dim, rank) * std_dev)
8        self.B = nn.Parameter(torch.zeros(rank, out_dim))
9        self.alpha = alpha
10
11    def forward(self, x):
12        x = self.alpha * (x @ self.A @ self.B)
13        return x

线性层 + LoRA 层,参数更新

1class LinearWithLoRA(nn.Module):
2
3    def __init__(self, linear, rank, alpha):
4        super().__init__()
5        self.linear = linear
6        self.lora = LoRALayer(
7            linear.in_features, linear.out_features, rank, alpha
8        )
9
10    def forward(self, x):
11        return self.linear(x) + self.lora(x)

3. 数的精度 -- 混合精度 + 量化操作

浮点数 -- 双精度: FP64 单精度: FP32 半精度: FP16

通过 exp和fraction 不同的范围与精度。

混合精度是指在模型训练过程中,同时使用不同数值精度的格式。

量化是指将模型中的浮点参数(如 FP32)转换为低比特整数(如 INT8、INT4,甚至 INT2/INT1)或定点数**,通过减少每个参数的存储位数来压缩模型。**

对模型训练的帮助

  1. 减少内存占用
  2. 加速计算速度
  3. 降低能源消耗

https://njudeepengine.github.io/LLM-Blog/2025/06/29/A3-modeling-mlp/

Task1:DenseMLPWithLoRA

Dense 的 MLP 模块 :先将 hidden_statesh 维上投影(up-project)到更高的 ffh 维,

再通过 gating 机制下投影(down-project)回原始维度。

一、任务背景

MLP 模块中的参数通常占据了 LLMs 中超过 90% 的可训练参数,

因此采用全量线性参数监督微调(supervised fine-tuning, SFT)的方式效率非常低。

LoRA 的核心基本假设是: δ W 是一个低秩且稀疏的矩阵,其可以通过低秩分解表示为:

二、任务要求

对三个投影矩阵 W 进行初始化,初始化方式为从正态分布中采样。

  • 如果 activation_type 使用 MLPActivationType.SIGMOIDMLPActivationType.BILINEAR,则使用 Xavier Initialization
  • 否则,对于其余 ReLU-family 的激活函数,则使用 Kaiming Initialization
  • 标准差 std = sqrt ( 2/ fan_in )

LoRA 低秩分解矩阵 A、B初始化:均匀分布 seed = lora_init_base_seed +1 / +2

对 lora_gate\up\down_A\B 的 seed 分别设置 offset 偏移量。

1. 若 lora_rank = 0,你应跳过任何与 LoRA 有关的逻辑

2. 参数 lora_alpha 是一个正缩放因子,默认为 None 时,表示应设置 = lora_rank(不缩放)

3. Dropout 层有 lora_dropout_seedlora_dropout_rate 参数

Task2:Sparse MLP

类似多头注意力,将投影矩阵的 ffh 维度划分为 ne 个大小相等的 shard(分片)对应一个专家。

hidden states 的每个 token 通过一个机制,映射到对应的 k 个 experts。

最终,每个 token 的最终输出是来自这 k 个 experts 子输出的加权和。

从而:降低高维计算开销;通过并行学习,提高潜在模式的多样性。

下文实现方式 Mixtral 方法:

1. 训练一个 (h, ne) 的网络 G;把 h 维的输入,转换为 ne 个专家分别的概率。

2. 只取前 k 名的 P,用 P / SUM 分配权重。将这几个 experts 的输出结果加权。

3. 每一个小专家 相当于一个 DenseMLP,调用上一问。


南京大学LLM开发基础(四)MoE, LoRA, 数的精度 + MLP层实验》 是转载文章,点击查看原文


相关推荐


【C++list】底层结构、迭代器核心原理与常用接口实现全解析
m0_748233642025/10/27

一、官方源码的探究 在实现list的底层前,我们先看下官方的核心成员变量,link_type node,其中link_type是list_node*,也就是说是节点的指针 在这里插入图片描述 下面我们看下其的初始化,在空初始化中,链表为空并不是把节点的指针给成空,而是给了个节点,让其的前驱指针和后继指针均指向自己,在C语言阶段的数据结构中我们便知道这个节点是哨兵位头节点 注意: 这里创捷新的节点不是new的,而是使用get_node出来的,这里是由于内存池的原因,后续再介绍


从复杂到高效:QtitanNavigation助力金融系统界面优化升级
Aevget2025/10/24

QtitanNavigation 组件模拟Microsoft Dynamics CRM-2016 / Office 365导航界面和一组控件,来改善Qt.C ++应用程序的用户体验。QtitanNavigation结合用户界面构建“Ribbon UI”和“Side Bar”的各种示例,可以更好地在您的应用程序中导航,使用户更直观地访问应用程序的某些部分。因此,它允许同时显示更多的信息,并让您高效地查看所有实体(工作区域,网格或其他项目),滚动次数更少,点击次数更少。与我们的其他解决方案一样,Qt


Rust 与 Go – 比较以及每个如何满足您的需求
std78792025/10/22

Rust 和 Go 是新的编程语言。每个都解决了以前编程语言(例如 C 和 C++)固有的问题。 如果您不确定哪一个适合您的项目,请查看这篇比较文章,我们将在其中更深入地研究 Rust 与 Go。 在比较结束时,您将清楚地了解 Rust 和 Go 提供的功能。我们将介绍它们的主要特点、优缺点、异同,并根据您的要求讨论正确的选择。 除此之外,我们还将争辩说,大多数团队可能能够同时使用这两种语言来支持他们的应用程序,并且比只坚持使用一种编程语言获得好处。 那么,为什么还要等呢?让我们


node.js上传图片接口
郏国上2025/10/21

node.js需要使用koa-multer库来实现上传图片接口。 实际上先通过koa-multer下载到本地指定目录,然后上传到阿里云(部分格式图片需要转换成网络格式图片jgp再上传)。 首先在系统启动文件引入注册路由: app.use(BodyParser({ 'formLimit':'3mb', 'jsonLimit':'3mb', 'textLimit':'3mb' })); // 注意顺序,必须body parser在前, router在后 app.use(rou


SpringBoot的学习
ʚ希希ɞ ྀ2025/10/20

学习目标: 1.掌握基于SpringBoot框架的程序开发步骤 2.熟练使用SpringBoot配置信息修改服务器配置 3.基于SpringBoot的完成SSM整合项目开发 下图创建一个Spring模块: 下图是一个SpringBoot程序最基本的架子: 如下一个SpringBoot程序就开发好了。 SpringBoot程序之所以好用是因为pom文件中的继承和一个dependency: 最后运行Application类: Spring程序和S


小杰深度学习(sixteen)——视觉-经典神经网络——MobileNetV2
jie*2025/10/19

7.MobileNetV2 1. 网络的背景 MobileNetV1 还不够轻量和高性能,为了让移动设备有更好的体验,Google 团队提出了 MobileNetV2 架构 MobileNetV2网络是由谷歌团队在2018年提出的,它相对于MobileNetV1而言,有着更高的准确率和更小的网络模型。 论文地址:https://arxiv.org/abs/1801.04381 Inverted Residuals and Linear Bottlenecks.pdf 2. 网络的


C#:函数默认参数
曹牧2025/10/17

C#函数默认参数允许在方法定义时为参数指定默认值,当调用时未提供该参数值则自动使用默认值:    ‌1、基本语法‌     在方法声明中通过参数名=默认值形式定义,例如void Print(string msg="default")。调用时可省略有默认值的参数Print(),此时msg取值为"default"。    ‌2、使用规则‌         默认参数必须从右向左连续定义,即某个参数有默认值后,其右侧所有参数必须都有默认值        默认值必须是编译时常量,不支持运行时动态赋值


【项目实战 Day12】springboot + vue 苍穹外卖系统(Apache POI + 工作台模块 + Excel表格导出 完结)
Roye_ack2025/10/16

目录 一、工作台模块 1、查询今日运营数据 - GET接口 (1)需求分析 (2)代码开发 2、查询今日运营数据 - GET接口 (1)需求分析 (2)代码开发 3、查询菜品总览 - GET接口 (1)需求分析 (2)代码开发 4、查询套餐总览 - GET接口 (1)需求分析 (2)代码开发 二、Excel表格导出 1、Apache POI (1)入门案例 2、导出Excel表格模块 (1)需求分析 (2)代码开发 【1】导入excel模板文件 【2】c


【HarmonyOS Bug踩坑】主窗口调用的接口,UI在子窗口异常显示
GeorgeGcs2025/10/15

【HarmonyOS Bug踩坑】主窗口调用的UI表现在子窗口异常显示 一、问题现象: 这个问题的标题略显抽象,毕竟涉及到的异常表现形式太多,标题是临时拟定的。 说白了,这个问题是鸿蒙里经典的上下文指定问题。 异常的业务场景是,在主窗口之上,添加一个子窗口。当在主窗口里调用某些UI表现,例如:气泡,弹窗,模态窗口,自定义安全键盘,自定义loading等,你会发现,有时候都异常加载到子窗口中了,并没有在主窗口显示。如下图所示: import { window } from '@kit.ArkUI


k8s-pod的启动
Code Rhythm2025/10/13

k8s-pod的启动 一、命令行启动nginx的pod创建deployment访问节点中的nginx查看部署控制器和副本控制器模拟高可用,将k8s-3关机手动触发重建删除rs会重新启新的rs删除deploy,所管理的rs也会被删除 二、yaml文件启podkubectl apply 启动podkubectl apply 使用部署控制器启动pod 三、pod的启动流程四、pod的终止过程 官方文档:https://kubernetes.io/zh-cn/docs/concept

首页编辑器站点地图

Copyright © 2025 聚合阅读

License: CC BY-SA 4.0