模型合并技术_SLERP_TIES_Merge_DARE

文章目录

    • [1. 先把问题讲清楚:模型能力不能像插件一样相加](#1. 先把问题讲清楚:模型能力不能像插件一样相加)
    • [2. 合并前提:不是所有模型都能合](#2. 合并前提:不是所有模型都能合)
    • [3. 权重平均:最简单也最粗糙](#3. 权重平均:最简单也最粗糙)
    • [4. Task Arithmetic:合并相对 base 的变化](#4. Task Arithmetic:合并相对 base 的变化)
    • [5. 方向冲突:为什么简单相加会出问题](#5. 方向冲突:为什么简单相加会出问题)
    • [6. SLERP:在球面上做平滑插值](#6. SLERP:在球面上做平滑插值)
    • [7. TIES-Merge:先处理符号冲突](#7. TIES-Merge:先处理符号冲突)
    • [8. DARE:随机丢弃 delta 再缩放](#8. DARE:随机丢弃 delta 再缩放)
    • [9. LoRA/adapter 合并与全模型合并](#9. LoRA/adapter 合并与全模型合并)
    • [10. 合并实验怎么做](#10. 合并实验怎么做)
    • [11. 常见失败模式](#11. 常见失败模式)
    • [12. 常见误区](#12. 常见误区)
    • [13. 小结](#13. 小结)
    • 大模型视角
    • 下一篇

摘要:模型合并试图把多个同源模型或 adapter 的能力组合起来,减少重新训练成本。它不是"把代码能力模型 + 客服能力模型 = 全能模型"的魔法,而是在权重空间里做有约束的实验。本文会从最简单的权重平均讲起,解释 task vector、delta、SLERP 球面插值、TIES-Merge 的符号冲突处理、DARE 的随机丢弃和缩放,并给出可运行的小代码帮助你理解这些方法的直觉。最后会重点讨论模型合并的前提条件、评估清单和常见失败模式。

  • 前置知识:专栏一的向量、矩阵、线性插值、低秩分解;专栏二 SFT/LoRA 可配合阅读
  • 阅读时间:50-60 分钟
  • 代码环境:Python 3.10+,示例只依赖标准库
  • 读完目标:能解释为什么同源模型才适合合并,能理解 delta/task vector 的意义,能知道 SLERP、TIES、DARE 分别想缓解什么问题

1. 先把问题讲清楚:模型能力不能像插件一样相加

假设你有一个基础模型 Base,又基于它微调了两个模型:

text 复制代码
Code-Model:更擅长代码解释和修复
Customer-Model:更擅长客服话术和业务问答

你可能会问:能不能不重新训练,直接把两个模型合成一个,同时保留代码和客服能力?这就是模型合并想探索的问题。

但权重不是插件市场。模型参数是高维空间里的连续数值,能力分布在大量层和矩阵中。两个微调模型在某些权重方向上可能互相增强,也可能互相冲突。合并结果可能更好,也可能两个能力都下降。

模型合并的价值在于:

价值 说明
成本低 不需要完整重新训练
实验快 可以快速比较多个合并权重
适配 adapter 多个 LoRA/adapter 可以尝试组合
可探索 帮助观察任务变化在权重空间里的关系

它的风险也很明显:

风险 说明
能力冲突 两个任务对同一权重方向要求相反
格式错乱 chat template 或对齐行为被破坏
安全退化 拒答边界和偏好优化结果被冲淡
不可解释 单个 prompt 看似好,整体评估下降
前提严格 架构、tokenizer、base 不一致通常不能直接合并

所以本文的核心态度是:模型合并可以做低成本实验,但必须建立前提检查和评估闭环。


2. 合并前提:不是所有模型都能合

开始讲算法前,先讲更重要的前提。直接合并通常要求:

text 复制代码
1. 架构完全一致;
2. 参数形状完全一致;
3. tokenizer 完全一致;
4. 最好来自同一个 base model;
5. chat template 和特殊 token 一致;
6. 微调方法和目标不要严重冲突;
7. 有独立评估集验证合并结果。

如果两个模型一个来自 LLaMA 基座,一个来自 Qwen 基座,直接按权重平均没有意义。即使参数形状碰巧一样,权重空间和 tokenizer 语义也不对齐。

最适合合并的情况通常是:

text 复制代码
Base -> FineTune A
Base -> FineTune B
Base -> FineTune C

也就是多个模型都从同一个 Base 出发,只是在不同任务或数据上微调。这样它们的权重差异可以被解释为"相对同一个基座的任务变化"。


3. 权重平均:最简单也最粗糙

最简单的合并是加权平均:

W m e r g e = α W A + ( 1 − α ) W B W_{merge} = \alpha W_A + (1 - \alpha) W_B Wmerge=αWA+(1−α)WB

先用大白话解释:把两个模型同名参数逐元素平均, α \alpha α 控制更偏向哪个模型。

逐项解释:

  • W A W_A WA:模型 A 的某个权重张量;
  • W B W_B WB:模型 B 的对应权重张量;
  • α \alpha α:合并权重,越大越偏向 A;
  • W m e r g e W_{merge} Wmerge:合并后的权重。

用列表模拟:

python 复制代码
# Python 3.10+

def weighted_average(a, b, alpha):
    return [alpha * x + (1 - alpha) * y for x, y in zip(a, b)]

w_a = [1.0, 2.0, 3.0]
w_b = [1.4, 1.8, 2.6]
for alpha in [0.25, 0.5, 0.75]:
    print(alpha, weighted_average(w_a, w_b, alpha))

权重平均的优点是简单。缺点是它完全不知道哪些参数变化重要、哪些方向冲突、哪些层更敏感。它适合做 baseline,不适合作为无需评估的最终答案。


4. Task Arithmetic:合并相对 base 的变化

如果多个模型来自同一个 base,更常见的思路是先计算相对 base 的变化量,也叫 task vector 或 delta。

对于任务 A:

Δ A = W A − W 0 \Delta_A = W_A - W_0 ΔA=WA−W0

对于任务 B:

Δ B = W B − W 0 \Delta_B = W_B - W_0 ΔB=WB−W0

合并时写成:

W m e r g e = W 0 + λ A Δ A + λ B Δ B W_{merge} = W_0 + \lambda_A \Delta_A + \lambda_B \Delta_B Wmerge=W0+λAΔA+λBΔB

逐项解释:

  • W 0 W_0 W0:基础模型权重;
  • W A , W B W_A, W_B WA,WB:两个微调模型权重;
  • Δ A , Δ B \Delta_A, \Delta_B ΔA,ΔB:微调相对 base 改了什么;
  • λ A , λ B \lambda_A, \lambda_B λA,λB:每个任务变化的缩放系数。

直觉上,delta 比完整权重更有意义。完整权重里绝大部分是基础能力,两个模型大部分相同;delta 才是任务微调带来的变化。

代码模拟:

python 复制代码
# Python 3.10+

def sub(a, b):
    return [x - y for x, y in zip(a, b)]


def add(a, b):
    return [x + y for x, y in zip(a, b)]


def scale(a, s):
    return [x * s for x in a]

base = [1.0, 1.0, 1.0, 1.0]
model_a = [1.2, 0.9, 1.0, 1.1]
model_b = [0.9, 1.3, 1.0, 0.8]

delta_a = sub(model_a, base)
delta_b = sub(model_b, base)
merged = add(base, add(scale(delta_a, 0.7), scale(delta_b, 0.5)))
print("delta_a", delta_a)
print("delta_b", delta_b)
print("merged", merged)

这段代码告诉我们:模型合并关注的是"每个任务把 base 往哪个方向推"。如果两个任务在同一位置方向相反,就会产生冲突。


5. 方向冲突:为什么简单相加会出问题

看一个 toy 例子:

text 复制代码
base 权重某位置 = 1.0
代码微调希望变成 1.3,delta = +0.3
客服微调希望变成 0.7,delta = -0.3

如果直接相加,两个 delta 抵消,回到 base;如果权重设置不当,还可能偏向某一方,损害另一方能力。

在真实模型中,这种冲突发生在高维权重空间里。它不一定对应单个可解释参数,但会影响层的表示、注意力投影、FFN 方向和输出风格。

方向冲突常见于:

冲突来源 例子
任务目标不同 一个模型鼓励详细解释,另一个鼓励短答
安全边界不同 一个模型拒答更强,另一个更开放
数据风格不同 代码模型和客服模型输出习惯差异大
chat template 不同 特殊 token 和角色格式不一致
微调强度不同 一个 delta 很大,主导合并结果

TIES-Merge 和 DARE 等方法,部分就是为了缓解这些冲突。


6. SLERP:在球面上做平滑插值

SLERP(Spherical Linear Interpolation,球面线性插值)原本常用于在两个向量方向之间平滑插值。与普通线性插值不同,SLERP 更关注方向和范数的平滑变化。

普通线性插值是:

( 1 − t ) A + t B (1-t)A + tB (1−t)A+tB

SLERP 可以写成:

slerp ( A , B , t ) = sin ⁡ ( ( 1 − t ) θ ) sin ⁡ θ A + sin ⁡ ( t θ ) sin ⁡ θ B \text{slerp}(A,B,t) = \frac{\sin((1-t)\theta)}{\sin\theta}A + \frac{\sin(t\theta)}{\sin\theta}B slerp(A,B,t)=sinθsin((1−t)θ)A+sinθsin(tθ)B

其中 θ \theta θ 是向量 A A A 和 B B B 的夹角。

不用被公式吓到。它想做的事是:如果两个权重向量可以看成高维空间里的方向,普通插值走直线,SLERP 在球面上沿角度平滑过渡。

可运行代码:

python 复制代码
# Python 3.10+
import math


def dot(a, b):
    return sum(x * y for x, y in zip(a, b))


def norm(a):
    return math.sqrt(dot(a, a))


def slerp(a, b, t):
    na = norm(a)
    nb = norm(b)
    if na == 0 or nb == 0:
        return [(1 - t) * x + t * y for x, y in zip(a, b)]

    cos_theta = dot(a, b) / (na * nb)
    cos_theta = max(-1.0, min(1.0, cos_theta))
    theta = math.acos(cos_theta)

    if abs(theta) < 1e-8:
        return a[:]

    sin_theta = math.sin(theta)
    left = math.sin((1 - t) * theta) / sin_theta
    right = math.sin(t * theta) / sin_theta
    return [left * x + right * y for x, y in zip(a, b)]

print(slerp([1.0, 0.0], [0.0, 1.0], 0.5))

SLERP 常用于两个模型之间的平滑合并,尤其是希望保持权重方向性质时。但它也不是万能:如果两个模型本身能力冲突严重,平滑插值仍然可能得到中庸甚至退化结果。


7. TIES-Merge:先处理符号冲突

TIES-Merge 的直觉是:多个 task vector 合并时,不应该把所有 delta 直接相加。很多小变化可能是噪声;同一位置方向相反的变化可能会互相破坏。

可以把它简化成三步:

text 复制代码
Trim:只保留重要 delta,裁掉小幅变化;
Elect Sign:为每个位置选择主导符号;
Merge:只合并与主导符号一致的变化。

下面写一个非常简化的 toy 版本。它不是论文级实现,只用来解释直觉:

python 复制代码
# Python 3.10+

def sign(x):
    return 1 if x > 0 else (-1 if x < 0 else 0)


def ties_merge(deltas, threshold=0.05):
    merged = []
    width = len(deltas[0])

    for j in range(width):
        values = [d[j] if abs(d[j]) >= threshold else 0.0 for d in deltas]
        sign_score = sum(sign(v) for v in values)
        elected = sign(sign_score)

        if elected == 0:
            merged.append(0.0)
            continue

        aligned = [v for v in values if sign(v) == elected]
        merged.append(sum(aligned) / max(len(aligned), 1))

    return merged

delta_code = [0.20, -0.10, 0.02, 0.30]
delta_chat = [0.15, 0.12, -0.03, -0.25]
print(ties_merge([delta_code, delta_chat], threshold=0.05))

这个例子里,小于阈值的变化被裁掉;符号冲突的位置会选主导方向;最后只合并方向一致的 delta。

TIES 的核心不是"符号投票一定正确",而是提醒我们:模型合并要处理冲突,不能无脑相加。


8. DARE:随机丢弃 delta 再缩放

DARE 的直觉是:微调 delta 中有很多变化可能是冗余的。随机丢弃一部分 delta,再对保留部分做缩放,有时可以在保留任务能力的同时减少冲突。

一个简化公式可以理解为:

text 复制代码
以概率 p 丢弃 delta 中的元素;
保留的元素除以 (1-p),保持期望幅度不变。

代码模拟:

python 复制代码
# Python 3.10+
import random


def dare(delta, drop_rate, seed=0):
    random.seed(seed)
    keep_prob = 1.0 - drop_rate
    result = []
    for x in delta:
        if random.random() < keep_prob:
            result.append(x / keep_prob)
        else:
            result.append(0.0)
    return result

print(dare([0.1, -0.2, 0.05, 0.3, -0.4], drop_rate=0.4, seed=42))

为什么丢弃后还要缩放?因为如果只丢弃不缩放,delta 的整体幅度会变小。除以保留概率,可以让保留下来的元素在期望上维持原来的总强度。

DARE 不意味着随机就一定更好。它是一种降低冗余和冲突的策略,实际效果依赖模型、任务、drop rate 和评估。


9. LoRA/adapter 合并与全模型合并

合并不一定发生在完整模型权重上,也可以发生在 LoRA adapter 上。

LoRA 微调后,基础模型不变,任务变化主要在 adapter 权重里。多个 adapter 如果来自同一个 base 和相近训练设置,可以尝试:

text 复制代码
1. 合并 adapter delta;
2. 调整每个 adapter 权重系数;
3. 将 adapter merge 回 base 后再评估;
4. 保留多 adapter 动态路由,而不是强行合成一个。

全模型合并与 adapter 合并的取舍:

方式 优点 风险
全模型合并 推理时单模型,部署简单 权重冲突和回滚成本高
Adapter 合并 成本低,易实验 仍可能冲突,需要同基座
多 adapter 路由 可按任务选择能力 推理系统更复杂

如果任务边界清晰,比如代码任务用代码 adapter、客服任务用客服 adapter,动态选择 adapter 可能比强行合并更稳。


10. 合并实验怎么做

模型合并应该像实验,而不是像发布流程。推荐步骤:

text 复制代码
1. 确认 base、tokenizer、架构、chat template 一致;
2. 准备模型 A、B、C 的单独评估结果;
3. 选择合并方法:平均、task arithmetic、SLERP、TIES、DARE;
4. 设置少量合并权重网格,例如 0.2/0.5/0.8;
5. 生成多个候选合并模型;
6. 跑自动评估和人工样例;
7. 检查安全边界和格式;
8. 与原模型和单任务模型对比;
9. 只保留有明确收益的合并结果。

不要只试一个 prompt。模型合并非常容易出现"演示样例很好,系统评估变差"的情况。

评估表可以这样设计:

评估项 目的
Base 通用能力 是否损害基础能力
任务 A 能力 是否保留模型 A 优势
任务 B 能力 是否保留模型 B 优势
格式遵循 JSON、Markdown、工具调用是否稳定
安全拒答 是否破坏对齐边界
长上下文 是否出现位置或记忆退化
人工样例 是否有明显风格混乱和幻觉

如果合并后每项都比单任务模型差一点,整体可能并不值得发布。


11. 常见失败模式

模型合并常见失败包括:

失败模式 表现 可能原因
能力互相抵消 两个任务都没保住 delta 方向冲突
输出风格混乱 有时像代码模型,有时像客服模型 数据风格差异大
安全边界变弱 更容易回答高风险问题 对齐模型被未对齐 delta 冲淡
过度拒答 正常问题也拒答 安全模型权重过高
格式错乱 chat template、JSON、工具调用不稳定 模板或微调目标不一致
长文本退化 长上下文任务变差 合并影响注意力或位置相关能力

出现失败时,不要只调合并系数。要回到前提检查:是否同基座、同 tokenizer、同模板、评估是否覆盖冲突任务、微调强度是否差异太大。


12. 常见误区

误区一:模型合并等于能力相加。 合并可能增强,也可能互相干扰。能力是否保留必须靠评估验证。

误区二:不同基座只要参数形状一样也能合。 权重空间和 tokenizer 语义不对齐时,直接合并通常没有意义。

误区三:SLERP/TIES/DARE 是万能高级方法。 它们只是缓解某些合并问题,无法解决任务本身冲突和数据质量问题。

误区四:合并可以替代训练。 合并适合低成本探索,不等于系统性训练和对齐。

误区五:只看几个 prompt 就能判断成功。 合并后的安全、格式、通用能力和各任务能力都要重新评估。


13. 小结

模型合并是在权重空间里组合能力的工程实验。权重平均简单但粗糙;Task Arithmetic 关注相对 base 的任务变化;SLERP 用球面插值让两个权重方向平滑过渡;TIES-Merge 尝试处理符号冲突;DARE 通过随机丢弃和缩放减少冗余 delta。它们都建立在重要前提上:最好同基座、同架构、同 tokenizer、同模板,并且必须有完整评估。

对开发者来说,最重要的不是记住每个方法名字,而是理解模型合并的边界:它能快速试验,不保证能力叠加;它能降低训练成本,不替代数据、训练和对齐;它能生成候选模型,但能不能上线要靠评估说话。

大模型视角

从大模型技术主线看,模型合并代表了"在权重空间做工程"的思路:不重新训练,而是把已有的能力向量组合复用。开源社区大量合并模型出自这种思路,它便宜、快速,但也提醒我们:没有数据和训练支撑的组合,能力上限是有限的。

下一篇

下一篇进入 SFT。有监督微调是把基础模型调成可用助手的关键步骤,也是后续 LoRA、QLoRA、DPO 和 RLHF 的基础。

相关推荐
xixiaoyunya1 小时前
网页状态实时提醒:把故障从“事后处理”变成“即时响应”
1024程序员节
Be for thing1 小时前
PyCharm安装与PyTorch项目配置|Jupyter Notebook与PyCharm使用对比
pytorch·学习·1024程序员节
weixin_440401691 小时前
大数据技术-人工智能编程题
大数据·人工智能·python·1024程序员节
代码不停1 小时前
分布式链路追踪 SkyWalking介绍
skywalking·1024程序员节
AIyy8661 小时前
学习资料分类整理的知识库工具使用思路:从统一入口到本地沉淀
1024程序员节
重生之小比特1 小时前
【算法拾光】二分查找|有序数组中的单一元素 + 寻找两个正序数组的中位数
1024程序员节
只是甲1 小时前
本体工程十五讲 | 第 2 篇:知识表示的载体谱系——从三元组到 YAML 字段
nl2sql·1024程序员节·ai agent·智能问数·本体建模
Yuzhiyuxia1 小时前
【AI Agent面试系列】AI Agent基础知识
1024程序员节
虚无的纽扣1 小时前
【Linux】线程同步:条件不满足时,线程该怎么等
linux·服务器·1024程序员节