<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>FSDP | Twinkle</title><link>https://modelscope.github.io/twinkle-web/zh/tags/fsdp/</link><atom:link href="https://modelscope.github.io/twinkle-web/zh/tags/fsdp/index.xml" rel="self" type="application/rss+xml"/><description>FSDP</description><generator>HugoBlox Kit (https://hugoblox.com)</generator><language>zh-Hans</language><lastBuildDate>Mon, 01 Jun 2026 00:00:00 +0000</lastBuildDate><image><url>https://modelscope.github.io/twinkle-web/media/logo_hu_fedc6a0bfe689b18.png</url><title>FSDP</title><link>https://modelscope.github.io/twinkle-web/zh/tags/fsdp/</link></image><item><title>Multi-LoRA：共享 GPU 上的多租户并行训练</title><link>https://modelscope.github.io/twinkle-web/zh/blog/multi-lora/</link><pubDate>Mon, 01 Jun 2026 00:00:00 +0000</pubDate><guid>https://modelscope.github.io/twinkle-web/zh/blog/multi-lora/</guid><description>&lt;p&gt;Twinkle 的 Multi-LoRA 架构支持多个租户在&lt;strong&gt;同一份共享模型&lt;/strong&gt;上同时训练各自独立的 LoRA 适配器。本文介绍其技术方案，涵盖 Transformers 和 Megatron 两种后端。&lt;/p&gt;
&lt;h2 id="为什么需要-multi-lora"&gt;为什么需要 Multi-LoRA？&lt;/h2&gt;
&lt;p&gt;传统 LoRA 训练中，每个用户都要加载一份完整的基座模型。对于 70B 模型，这意味着每个租户占用 ~140 GB 显存——当所有用户的冻结基座权重完全相同时，这是巨大的浪费。Multi-LoRA 的解决思路：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;共享基座模型&lt;/strong&gt;：所有租户共享一份冻结的基座权重。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;预分配适配器槽位&lt;/strong&gt;：初始化时分配固定的 LoRA 适配器槽位池（&lt;code&gt;max_loras × max_r&lt;/code&gt;），避免运行时内存碎片化。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;动态租户切换&lt;/strong&gt;：租户可以即时获取/释放适配器，上下文切换开销接近零。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="架构概览"&gt;架构概览&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;┌──────────────────────────────────────────┐
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ 共享基座模型 │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ (冻结权重，仅加载一次) │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├──────────────────────────────────────────┤
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ MultiLora 管理器 │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ ┌────────┐ ┌────────┐ ┌────────┐ │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ │ 槽位 0 │ │ 槽位 1 │ │ 槽位 2 │ ... │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ │ 租户 A │ │ 租户 B │ │ 空闲 │ │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ └────────┘ └────────┘ └────────┘ │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├──────────────────────────────────────────┤
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ 每租户独立：优化器、学习率调度器、 │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ 模板、梯度累积 │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;└──────────────────────────────────────────┘
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;MultiLora&lt;/code&gt; 类管理完整生命周期：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;patch(model)&lt;/code&gt;&lt;/strong&gt; — 为每个 &lt;code&gt;LoLayer&lt;/code&gt; 的 forward 方法打补丁，使其遍历所有活跃适配器并施加 LoRA 权重。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;acquire_lora(tenant, config)&lt;/code&gt;&lt;/strong&gt; — 从预分配池中为租户分配一个槽位。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;adapter(name)&lt;/code&gt;&lt;/strong&gt; — 上下文管理器，在 forward/backward 期间激活指定适配器。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;release_lora(tenant)&lt;/code&gt;&lt;/strong&gt; — 恢复初始权重，将槽位归还空闲池。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="transformers-后端"&gt;Transformers 后端&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;MultiLoraTransformersModel&lt;/code&gt; 在标准 &lt;code&gt;TransformersModel&lt;/code&gt; 之上实现了逐适配器隔离：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MultiLoraTransformersModel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Qwen/Qwen3.5-72B&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_loras&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 租户 A 注册适配器&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_adapter_to_model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;tenant_a&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;LoraConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;target_modules&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;all-linear&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_optimizer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;optimizer_cls&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Adam&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lr&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;1e-4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;adapter_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;tenant_a&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 租户 B 独立注册&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_adapter_to_model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;tenant_b&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;LoraConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;target_modules&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;all-linear&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_optimizer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;optimizer_cls&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Adam&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lr&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;2e-4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;adapter_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;tenant_b&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 各租户独立训练——梯度隔离&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;forward_backward&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inputs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;batch_a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;adapter_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;tenant_a&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;clip_grad_and_step&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;adapter_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;tenant_a&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;核心设计：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;优化器组&lt;/strong&gt;：每个适配器拥有独立的优化器、学习率调度器和梯度累积配置，存储在 &lt;code&gt;OptimizerGroup&lt;/code&gt; 中。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;上下文切换 forward&lt;/strong&gt;：所有 &lt;code&gt;forward_backward&lt;/code&gt;、&lt;code&gt;step&lt;/code&gt;、&lt;code&gt;zero_grad&lt;/code&gt; 调用都被 &lt;code&gt;self.multi_adapter.adapter(name)&lt;/code&gt; 包裹，确保梯度隔离。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;独立 checkpoint&lt;/strong&gt;：&lt;code&gt;save()&lt;/code&gt; 仅提取当前活跃适配器的状态字典，租户之间互不可见。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="megatron-后端"&gt;Megatron 后端&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;MultiLoraMegatronModel&lt;/code&gt; 在 Megatron 张量/流水线并行训练的基础上支持多租户。核心挑战在于 Megatron 使用&lt;strong&gt;分布式优化器&lt;/strong&gt;，它能看到所有参数——但我们需要按适配器隔离梯度。&lt;/p&gt;
&lt;p&gt;解决方案：&lt;strong&gt;&lt;code&gt;optimizer_context&lt;/code&gt; 上下文管理器&lt;/strong&gt;，临时替换每个流水线并行模块上的 &lt;code&gt;named_parameters()&lt;/code&gt;，使其仅返回匹配当前活跃适配器正则模式的参数：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nd"&gt;@contextmanager&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;optimizer_context&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;adapter_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;pattern&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;compile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;rf&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;\.lora_\w+\.&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;escape&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;adapter_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s1"&gt;\.&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;module&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;orig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;named_parameters&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;named_parameters&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;make_filtered&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;orig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pattern&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;yield&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# 恢复原始 named_parameters&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这确保了即使在 TP/PP 分片的分布式环境中，优化器也只更新目标适配器的 LoRA 权重。&lt;/p&gt;
&lt;p&gt;Megatron 特有功能：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;按 rank 保存优化器状态&lt;/strong&gt;：每个 rank 独立保存优化器状态，高效支持多 GPU 恢复。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;HF + Megatron 双格式导出&lt;/strong&gt;：支持以 HuggingFace PEFT 格式或原生 Megatron 格式保存适配器。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;RNG 状态隔离&lt;/strong&gt;：加载租户 checkpoint 时，全局 RNG 故意&lt;em&gt;不&lt;/em&gt;恢复，以避免影响其他活跃租户的 dropout 行为。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="性能对比"&gt;性能对比&lt;/h2&gt;
&lt;p&gt;通过跨租户共享基座模型权重，Multi-LoRA 按比例降低显存使用：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;租户数&lt;/th&gt;
&lt;th&gt;传统方式（N × 完整模型）&lt;/th&gt;
&lt;th&gt;Multi-LoRA（1 模型 + N 适配器）&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;140 GB&lt;/td&gt;
&lt;td&gt;140 GB + 0.1 GB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;700 GB&lt;/td&gt;
&lt;td&gt;140 GB + 0.5 GB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;1400 GB&lt;/td&gt;
&lt;td&gt;140 GB + 1.0 GB&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;em&gt;基于 70B 模型、LoRA r=16 的估算。&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="快速开始"&gt;快速开始&lt;/h2&gt;
&lt;p&gt;完整示例请参考
。&lt;/p&gt;</description></item></channel></rss>