[{"content":" 上一篇笔记建立了 Transformer 的直觉和代码实现，这篇深入每个组件背后的数学原理。每个主题都标注了出处论文或博客，方便查阅原文。\n一、Scaled Dot-Product：为什么除以 √dk？ 出处：Vaswani et al. (2017) \u0026ldquo;Attention Is All You Need\u0026rdquo;, Section 3.2.1\n上一篇笔记里我们知道 Attention 的计算公式是：\n$$\\text{Attention}(Q, K, V) = \\text{softmax}\\left(\\frac{QK^T}{\\sqrt{d_k}}\\right) V$$其中：\n$Q$：Query 矩阵 $K$：Key 矩阵 $V$：Value 矩阵 $d_k$：Key 向量的维度 $\\text{softmax}$：归一化函数（将分数转为概率分布） 但为什么要除以 $\\sqrt{d_k}$？Vaswani et al. 在论文中给出了一句关键解释：\u0026ldquo;We suspect that for large values of $d_k$, the dot products grow large in magnitude, pushing the softmax function into regions where it has extremely small gradients.\u0026rdquo; 下面把这句话拆成严格的数学推导。\n1.1 方差推导 假设 $q$ 和 $k$ 的每个分量都是独立同分布的随机变量，均值为 0，方差为 1。点积 $q^T k = \\sum_{i=1}^{d_k} q_i k_i$。\n每一项 $q_i k_i$ 的期望和方差：\n其中：\n$E[\\cdot]$：期望（均值） $\\text{Var}(\\cdot)$：方差（衡量数据的离散程度） $q_i$：Query 向量的第 $i$ 个分量 $k_i$：Key 向量的第 $i$ 个分量 $$E[q_i k_i] = E[q_i] \\cdot E[k_i] = 0 \\times 0 = 0$$$$\\text{Var}(q_i k_i) = E[q_i^2 k_i^2] - (E[q_i k_i])^2 = E[q_i^2] \\cdot E[k_i^2] = 1 \\times 1 = 1$$因为各分量独立，$d_k$ 项求和后：\n$$E[q^T k] = 0, \\quad \\text{Var}(q^T k) = d_k$$结论：点积的方差随 $d_k$ 线性增长。$d_k = 64$ 时标准差是 8，$d_k = 512$ 时标准差是 $\\approx 22.6$。\n1.2 方差过大的后果 当点积的数值很大时，softmax 的输出会趋近 one-hot 分布：\n假设 3 个 token 的 attention score 为 [a, b, c] 当 score 量级正常（如 [1.0, 0.5, 0.2]）： softmax → [0.49, 0.30, 0.22] ← 平滑分布，梯度正常 当 score 量级过大（如 [20.0, 10.0, 4.0]）： softmax → [≈1.00, ≈0.00, ≈0.00] ← 几乎是 one-hot，梯度趋近 0 softmax 在输入值差距很大时进入饱和区，梯度接近零，参数几乎无法更新。除以 $\\sqrt{d_k}$ 把方差拉回 1，让 softmax 始终工作在梯度有效的区间。\n1.3 为什么是 √dk 而不是 dk？ 因为我们要让缩放后的方差等于 1：\n$$\\text{Var}\\left(\\frac{q^T k}{\\sqrt{d_k}}\\right) = \\frac{\\text{Var}(q^T k)}{d_k} = \\frac{d_k}{d_k} = 1$$如果除以 $d_k$，方差会变成 $1/d_k$，过度压缩了分数的区分度。$\\sqrt{d_k}$ 是恰好让方差归一的选择。\n二、Softmax 与 Boltzmann 分布：为什么 softmax 能当概率用？ 出处：统计力学中的 Boltzmann 分布；Vaswani et al. (2017)\n2.1 Softmax 就是 Boltzmann 分布 统计力学中，一个系统处于能量状态 $e_i$ 的概率由 Boltzmann 分布给出：\n$$P(i) = \\frac{\\exp(-e_i / T)}{\\sum_j \\exp(-e_j / T)}$$其中：\n$P(i)$：系统处于状态 $i$ 的概率 $e_i$：状态 $i$ 的能量 $T$：温度参数 $\\exp(\\cdot)$：指数函数 $e^{(\\cdot)}$ $\\sum_j$：对所有状态 $j$ 求和 其中 $T$ 是温度。如果把 $-e_i$ 替换为 logit $z_i$，令 $T = 1$，就得到 softmax：\n$$\\text{softmax}(z_i) = \\frac{\\exp(z_i)}{\\sum_j \\exp(z_j)}$$两者形式完全一致。Attention 中的 $\\frac{1}{\\sqrt{d_k}}$ 缩放因子，本质上就是在调节温度 $T = \\sqrt{d_k}$。\n2.2 温度对注意力分布的影响 温度控制分布的\u0026quot;锐度\u0026quot;：\nscore = [2.0, 1.0, 0.5] T = 0.5（低温）：softmax(score/0.5) = softmax([4.0, 2.0, 1.0]) → [0.84, 0.11, 0.04] ← 集中在最大值，接近 argmax T = 1.0（标准）：softmax(score/1.0) = softmax([2.0, 1.0, 0.5]) → [0.63, 0.23, 0.14] ← 平滑分布 T = 5.0（高温）：softmax(score/5.0) = softmax([0.4, 0.2, 0.1]) → [0.39, 0.32, 0.29] ← 接近均匀分布 $T \\to 0$：softmax 退化为 argmax（硬注意力），只关注一个 token $T \\to \\infty$：softmax 退化为均匀分布，所有 token 权重相等 $T = \\sqrt{d_k}$：Transformer 的默认选择，保持适度的区分度 这个温度视角在知识蒸馏（Hinton et al., 2015）中也很重要——用高温 softmax 让 teacher 模型输出更平滑的概率分布，传递更多\u0026quot;暗知识\u0026quot;。\n三、Positional Encoding：为什么用 sin/cos 就能编码位置？ 出处：Vaswani et al. (2017) Section 3.5；Kazemnejad, \u0026ldquo;Transformer Architecture: The Positional Encoding\u0026rdquo;（博客）\n3.1 公式 原始 Transformer 的正弦位置编码：\n$$PE(pos, 2i) = \\sin\\left(\\frac{pos}{10000^{2i/d_{model}}}\\right)$$$$PE(pos, 2i+1) = \\cos\\left(\\frac{pos}{10000^{2i/d_{model}}}\\right)$$其中 $pos$ 是 token 在序列中的位置，$i$ 是编码向量的维度索引。每一对 $(2i, 2i+1)$ 维度使用同一个频率的 sin 和 cos。\n3.2 不同维度 = 不同频率 频率由 $\\omega_i = 1 / 10000^{2i/d_{model}}$ 决定：\n维度 i=0: ω = 1/10000^0 = 1 → 周期 = 2π ≈ 6.28 个位置 维度 i=128: ω = 1/10000^(256/512) = 1/100 → 周期 ≈ 628 个位置 维度 i=255: ω = 1/10000^(510/512) ≈ 1/9770 → 周期 ≈ 61400 个位置 低维度变化快（捕捉相邻 token 的位置差异），高维度变化慢（捕捉远距离的位置关系）。Jay Alammar 在 \u0026ldquo;The Illustrated Transformer\u0026rdquo; 中把这比作二进制计数器：最低位每步翻转，高位翻转越来越慢。\n3.3 核心数学性质：相对位置的线性可表达性 这是正弦编码最精妙的设计。Kazemnejad 在博客中给出了完整推导：\n对于任意固定偏移 $k$，$PE(pos + k)$ 可以表示为 $PE(pos)$ 的线性变换：\n$$\\begin{bmatrix} PE(pos+k, 2i) \\\\ PE(pos+k, 2i+1) \\end{bmatrix} = \\begin{bmatrix} \\cos(k\\omega_i) \u0026 \\sin(k\\omega_i) \\\\ -\\sin(k\\omega_i) \u0026 \\cos(k\\omega_i) \\end{bmatrix} \\begin{bmatrix} PE(pos, 2i) \\\\ PE(pos, 2i+1) \\end{bmatrix}$$其中：\n$k$：位置偏移量（两个 token 之间的距离） $\\omega_i$：第 $i$ 个维度对应的频率 推导依赖三角恒等式：\n$$\\sin(a + b) = \\sin a \\cos b + \\cos a \\sin b$$ $$\\cos(a + b) = \\cos a \\cos b - \\sin a \\sin b$$其中 $a = pos \\cdot \\omega_i$，$b = k \\cdot \\omega_i$。\n这意味着什么？ 变换矩阵只依赖偏移量 $k$，不依赖绝对位置 $pos$。模型可以通过学习一个线性变换来捕捉\u0026quot;距离为 $k$ 的两个 token 之间的关系\u0026quot;——这就是相对位置信息。Self-Attention 中的 $Q^T K$ 运算天然包含了这种线性组合，因此模型不需要显式计算相对位置，正弦编码已经把这个信息编进去了。\n3.4 为什么底数是 10000？ Vaswani et al. 没有给出严格的理论推导，这更像是一个工程选择。10000 保证了：\n最低频率的周期（$\\approx 2\\pi \\times 10000 \\approx 62800$ 个位置）远大于训练时的最大序列长度 最高频率的周期（$2\\pi \\approx 6$ 个位置）足以区分相邻 token 频率在对数尺度上均匀分布，覆盖从局部到全局的所有距离 实际上，后续工作提出了不同的位置编码方案，但正弦编码的数学优雅性使它成为理解位置编码的最佳起点。\n3.5 现代扩展：RoPE 和 ALiBi RoPE（Rotary Position Embedding）：不把位置信息加到 token embedding 上，而是在计算 $Q^T K$ 时对 Q 和 K 做旋转变换，使得点积结果自然包含相对位置信息。数学上，RoPE 把正弦编码的\u0026quot;加法\u0026quot;思路改成了\u0026quot;乘法（旋转）\u0026ldquo;思路。 ALiBi（Attention with Linear Biases）：完全不用位置编码，而是在 Attention score 上直接加一个与距离成正比的偏置：$\\text{score}_{ij} = q_i^T k_j - m \\cdot |i - j|$，其中 $m$ 是每个 head 不同的斜率。这是便于理解的简化写法；在实际 causal attention 中，ALiBi 对不同 head 使用不同斜率，并结合相对位置方向构造 bias。 两者都比正弦编码更适合处理超长序列（外推到训练时没见过的长度），是当前大模型的主流选择。\n四、Attention 与核方法：为什么 Attention 的形式不是凭空设计的？ 出处：Tsai et al. (EMNLP 2019) \u0026ldquo;Transformer Dissection: An Unified Understanding for Transformer\u0026rsquo;s Attention via the Lens of Kernel\u0026rdquo;\n这一节揭示了一个很漂亮的联系：Attention 不是凭空设计的，它和经典统计学中的核回归有着精确的数学对应。\n4.1 Nadaraya-Watson 核回归 在非参数统计中，Nadaraya-Watson 估计器用核函数对观测值做加权平均：\n$$\\hat{f}(x) = \\frac{\\sum_{j=1}^{n} \\kappa(x, x_j) \\cdot y_j}{\\sum_{j=1}^{n} \\kappa(x, x_j)}$$其中 $\\kappa(x, x_j)$ 是核函数，衡量 $x$ 和 $x_j$ 的相似度。离 $x$ 越近的观测点，权重越大。\n4.2 Attention 就是核回归 把 Attention 的公式展开到单个 query $q_i$：\n$$\\text{Attn}(q_i) = \\sum_{j=1}^{T} \\frac{\\exp(q_i^T k_j / \\sqrt{d_k})}{\\sum_{l=1}^{T} \\exp(q_i^T k_l / \\sqrt{d_k})} \\cdot v_j$$定义核函数 $\\kappa(q, k) = \\exp(q^T k / \\sqrt{d_k})$，上式变成：\n$$\\text{Attn}(q_i) = \\frac{\\sum_j \\kappa(q_i, k_j) \\cdot v_j}{\\sum_j \\kappa(q_i, k_j)}$$其中：\n$\\kappa(q, k)$：核函数（衡量两个向量相似度的函数） $v_j$：第 $j$ 个 token 的 Value 向量 $T$：序列长度 和 Nadaraya-Watson 估计器形式完全一致。从核方法的视角看，$\\kappa$ 可以理解为一种指数内积核（exponentiated inner product kernel），Attention 的 softmax 归一化对应核回归中自然出现的归一化。\n4.3 这个视角的意义 理解视角：Attention 的形式并非凭空设计——它和经典非参数统计中的核回归有清晰的形式对应，softmax 归一化在核回归框架下是自然的 计算瓶颈的来源：核回归的计算复杂度是 $O(n^2)$（每对样本都要算核函数），这正是 Attention 的 $O(T^2)$ 复杂度的根源 线性 Attention 的动机：Choromanski et al. (2021) 的 Performer 利用核的随机特征分解 $\\kappa(q, k) \\approx \\phi(q)^T \\phi(k)$，把 Attention 从 $O(T^2)$ 降到 $O(T)$ 五、Multi-Head Attention：为什么要分成多个头？ 5.1 维度推导 输入 $X \\in \\mathbb{R}^{T \\times d_{model}}$，通过三个权重矩阵投影：\n$$Q = XW_Q, \\quad K = XW_K, \\quad V = XW_V$$其中：\n$X$：输入序列，$T$ 个 token，每个 $d_{model}$ 维 $W_Q, W_K \\in \\mathbb{R}^{d_{model} \\times d_{model}}$：Query 和 Key 的投影矩阵 $W_V \\in \\mathbb{R}^{d_{model} \\times d_{model}}$：Value 的投影矩阵 Multi-Head 把 $Q, K, V$ 沿特征维度 reshape/split 成 $h$ 个头：\n$$Q \\in \\mathbb{R}^{T \\times d_{model}} \\;\\rightarrow\\; Q^{(1)}, \\ldots, Q^{(h)}, \\quad Q^{(i)} \\in \\mathbb{R}^{T \\times d_k}, \\quad d_k = d_{model} / h$$注意这里是沿特征维度切分（每个头看 $d_k$ 个特征通道），不是沿 token 维度拼接。\n每个头独立做 Attention：\n$$\\text{head}_i = \\text{Attention}(Q^{(i)}, K^{(i)}, V^{(i)}) \\in \\mathbb{R}^{T \\times d_k}$$最后拼接并通过输出投影：\n$$\\text{MultiHead}(Q, K, V) = \\text{Concat}(\\text{head}_1, \\ldots, \\text{head}_h) \\cdot W_O$$其中：\n$h$：头的数量（BERT-base 用 12，GPT-2 用 12） $d_k$：每个头的维度（$d_{model} / h$，如 $768 / 12 = 64$） $W_O \\in \\mathbb{R}^{d_{model} \\times d_{model}}$：输出投影矩阵 5.2 为什么分头不损失表达能力？ 在标准实现中，Q/K/V 线性投影的总输出维度仍为 $d_{model}$，因此 Multi-Head 的投影参数量与单头 Attention 保持同量级。分头的优势不在于增加参数，而在于让不同子空间学习不同的关注模式（语法关系、语义关系、位置关系等），而不是把所有模式压缩到一组 Q/K/V 里。\n六、Mask 的数学形式：如何控制 Attention 的可见范围？ 6.1 统一公式 Mask 通过在 Attention score 上加一个矩阵 $M$ 来实现：\n$$\\text{Attention}(Q, K, V) = \\text{softmax}\\left(\\frac{QK^T + M}{\\sqrt{d_k}}\\right) V$$其中：\n$M \\in \\mathbb{R}^{T \\times T}$：Mask 矩阵 $M_{ij} = 0$：位置 $i$ 可以看到位置 $j$ $M_{ij} = -\\infty$：位置 $i$ 不能看到位置 $j$（$\\exp(-\\infty) = 0$，softmax 后权重为 0） 6.2 Causal Mask（自回归 Mask） Decoder 生成时，每个 token 只能看到自己和前面的 token：\n$$M_{ij} = \\begin{cases} 0 \u0026 \\text{if } i \\geq j \\\\ -\\infty \u0026 \\text{if } i \u003c j \\end{cases}$$这是一个下三角矩阵（对角线及以下为 0，上三角为 $-\\infty$）。GPT 系列全程使用 causal mask。\n6.3 Padding Mask 变长序列需要 padding 到统一长度，padding 位置不应参与 Attention 计算：\n$$M_{ij} = \\begin{cases} 0 \u0026 \\text{if } j \\text{ 不是 padding} \\\\ -\\infty \u0026 \\text{if } j \\text{ 是 padding} \\end{cases}$$实际实现中，两种 mask 可以叠加使用。代码里通常用一个很大的负数（如 $-10^9$ 或 dtype 的最小值）近似 $-\\infty$，而不是真正的无穷大。\n七、FFN：为什么 Attention 之后还需要一个 MLP？ 7.1 数学形式 每个 Transformer Block 中，Attention 之后紧跟一个 Feed-Forward Network：\n$$\\text{FFN}(x) = W_2 \\cdot \\phi(W_1 x + b_1) + b_2$$其中：\n$x \\in \\mathbb{R}^{d_{model}}$：单个 token 的特征向量 $W_1 \\in \\mathbb{R}^{d_{ff} \\times d_{model}}$：升维矩阵（通常 $d_{ff} = 4 \\times d_{model}$） $W_2 \\in \\mathbb{R}^{d_{model} \\times d_{ff}}$：降维矩阵 $\\phi$：激活函数（原始 Transformer 用 ReLU，现代模型常用 GELU） $b_1, b_2$：偏置项 7.2 Attention 和 FFN 的分工 Attention 负责 token 之间的信息交互——\u0026ldquo;哪些 token 和我相关？\u0026rdquo; FFN 负责每个 token 内部的特征变换——\u0026ldquo;拿到相关信息后，怎么处理？\u0026rdquo; FFN 对每个 token 独立作用（不涉及 token 间交互），但所有位置共享同一组 $W_1, W_2, b_1, b_2$ 参数——不是每个 token 一个 MLP，而是同一个 MLP 逐个处理每个 token。可以理解为一个逐 token 的非线性变换：先升维到 $d_{ff}$（扩大表示空间），经过非线性激活，再降维回 $d_{model}$。\n八、复杂度分析：为什么长序列是 Transformer 的瓶颈？ 8.1 Self-Attention 的复杂度 对于序列长度 $T$、模型维度 $d$：\n操作 时间复杂度 空间复杂度 $QK^T$ 计算 $O(T^2 \\cdot d)$ $O(T^2)$（存储 Attention 矩阵） Softmax $O(T^2)$ $O(T^2)$ Attention × V $O(T^2 \\cdot d)$ $O(T \\cdot d)$ 瓶颈在 $O(T^2)$：Attention 矩阵的大小是 $T \\times T$。当 $T = 512$ 时矩阵有 26 万个元素，$T = 4096$ 时有 1600 万个，$T = 32768$ 时有 10 亿个。这就是为什么早期 Transformer 的最大序列长度被限制在 512 或 1024。\nMulti-Head Attention 虽然分成 $h$ 个头，但总复杂度的主阶仍然是 $O(T^2 \\cdot d_{model})$——分头不会把平方复杂度变成线性。\n8.2 FFN 的复杂度 操作 时间复杂度 空间复杂度 $W_1 x$（升维） $O(T \\cdot d \\cdot d_{ff})$ $O(T \\cdot d_{ff})$ $W_2 \\cdot \\phi(\\cdot)$（降维） $O(T \\cdot d_{ff} \\cdot d)$ $O(T \\cdot d)$ FFN 的复杂度是 $O(T \\cdot d \\cdot d_{ff})$，对 $T$ 是线性的。当 $T$ 较小时 FFN 可能是计算瓶颈（因为 $d_{ff} = 4d$ 很大），但当 $T$ 增大后，$O(T^2)$ 的 Attention 会迅速超过 FFN。\n8.3 这就是 Linear Attention 的动机 §4 中提到的 Performer 用核的随机特征分解把 Attention 从 $O(T^2)$ 降到 $O(T)$，代价是近似精度。后续的 Flash Attention 则从另一个角度优化——不改变数学计算，而是通过 IO-aware 的分块算法减少显存访问次数，在保持精确计算的同时大幅提速。\n九、Cross-Attention：两个序列之间怎么交互？ 9.1 与 Self-Attention 的区别 Self-Attention 中 Q、K、V 全部来自同一个输入序列。Cross-Attention 则是 Q 来自一个序列（Decoder），K 和 V 来自另一个序列（Encoder）：\n$$\\text{CrossAttn}(Q_{dec}, K_{enc}, V_{enc}) = \\text{softmax}\\left(\\frac{Q_{dec} K_{enc}^T}{\\sqrt{d_k}}\\right) V_{enc}$$其中：\n$Q_{dec} \\in \\mathbb{R}^{T_{dec} \\times d_k}$：来自 Decoder 当前层的 Query（\u0026ldquo;我需要什么信息？\u0026quot;） $K_{enc} \\in \\mathbb{R}^{T_{enc} \\times d_k}$：来自 Encoder 输出的 Key（\u0026ldquo;源序列有哪些信息？\u0026quot;） $V_{enc} \\in \\mathbb{R}^{T_{enc} \\times d_k}$：来自 Encoder 输出的 Value（\u0026ldquo;源序列的实际内容\u0026rdquo;） $T_{dec}$：目标序列长度，$T_{enc}$：源序列长度（两者可以不同） Attention 矩阵的 shape 是 $T_{dec} \\times T_{enc}$——Decoder 的每个位置对 Encoder 的每个位置计算相关性。\n9.2 三种 Attention 的对比 类型 Q 来源 K/V 来源 典型用途 Self-Attention 同一序列 同一序列 BERT、GPT、ViT Masked Self-Attention 同一序列（加 causal mask） 同一序列 GPT 生成、Decoder Cross-Attention Decoder Encoder 机器翻译、T5、Stable Diffusion 9.3 哪些模型用 Cross-Attention？ Encoder-Decoder 模型（原始 Transformer、T5、BART）：Decoder 每一层都有 Cross-Attention 来\u0026quot;读取\u0026quot;Encoder 的输出 Decoder-only 模型（GPT 系列）：没有 Cross-Attention，因为没有 Encoder 多模态模型（Stable Diffusion）：用 Cross-Attention 让图像生成过程\u0026quot;读取\u0026quot;文本条件 十、残差连接：为什么加一个 $x$ 就能训练几十层？ 出处：He et al. (CVPR 2016) \u0026ldquo;Deep Residual Learning for Image Recognition\u0026rdquo;；He et al. (2016) \u0026ldquo;Identity Mappings in Deep Residual Networks\u0026rdquo;\n10.1 残差连接的数学形式 标准的残差块：\n$$y = F(x, \\{W_i\\}) + x$$其中 $F(x)$ 是残差函数（在 Transformer 中就是 Multi-Head Attention 或 FFN）。网络学习的不是完整映射 $H(x) = y$，而是残差 $F(x) = H(x) - x$。\n10.2 梯度流的关键推导 对 loss $\\mathcal{L}$ 求 $x$ 的梯度：\n$$\\frac{\\partial \\mathcal{L}}{\\partial x} = \\frac{\\partial \\mathcal{L}}{\\partial y} \\cdot \\frac{\\partial y}{\\partial x} = \\frac{\\partial \\mathcal{L}}{\\partial y} \\cdot \\left(\\frac{\\partial F}{\\partial x} + I\\right)$$其中：\n$\\mathcal{L}$：损失函数 $\\frac{\\partial \\mathcal{L}}{\\partial x}$：损失对输入 $x$ 的梯度（参数更新的方向和大小） $F(x)$：残差函数（Attention 或 FFN 的输出） $I$：单位矩阵（恒等变换） 恒等项 $I$ 是关键。不管 $\\frac{\\partial F}{\\partial x}$ 有多小（甚至趋近零），梯度中始终有一个 $\\frac{\\partial \\mathcal{L}}{\\partial y} \\cdot I = \\frac{\\partial \\mathcal{L}}{\\partial y}$ 的分量直接传回。这条\u0026quot;梯度高速公路\u0026quot;保证了深层网络不会出现梯度消失。\n10.3 多层堆叠的效果 对于 $L$ 层残差网络，第 $l$ 层的输出可以递归展开：\n$$x_L = x_l + \\sum_{i=l}^{L-1} F(x_i, W_i)$$梯度：\n$$\\frac{\\partial \\mathcal{L}}{\\partial x_l} = \\frac{\\partial \\mathcal{L}}{\\partial x_L} \\cdot \\left(1 + \\frac{\\partial}{\\partial x_l} \\sum_{i=l}^{L-1} F(x_i, W_i)\\right)$$前面的 $1$ 保证了即使后面的求和项很小，梯度也不会消失。这就是为什么 12 层甚至 96 层的 Transformer 能正常训练。\n10.4 Pre-Norm vs Post-Norm He et al. 在 \u0026ldquo;Identity Mappings\u0026rdquo; 中进一步证明，把 Normalization 放在残差函数内部（Pre-Norm）比放在外部（Post-Norm）梯度流更干净：\nPost-Norm（原始 Transformer）： y = LayerNorm(x + F(x)) ← LayerNorm 在残差连接之后 Pre-Norm（改进版）： y = x + F(LayerNorm(x)) ← LayerNorm 在残差函数内部 Pre-Norm 保证了恒等路径上没有任何非线性变换，梯度高速公路完全畅通。GPT-2 和后续大多数大模型都采用了 Pre-Norm。在深层大模型中，Pre-Norm 通常比 Post-Norm 更稳定，因此现代 LLM（GPT、LLaMA、Gemma 等）基本都使用 Pre-Norm 或其变体。\n十一、LayerNorm vs BatchNorm：为什么 Transformer 选 LayerNorm？ 出处：Ba, Kiros \u0026amp; Hinton (2016) \u0026ldquo;Layer Normalization\u0026rdquo;\n11.1 归一化的通用公式 所有归一化方法的形式都一样：\n$$\\hat{x} = \\gamma \\cdot \\frac{x - \\mu}{\\sqrt{\\text{Var}(x) + \\epsilon}} + \\beta$$其中：\n$x$：输入向量 $\\mu$：$x$ 所有分量的均值 $\\text{Var}(x)$：$x$ 所有分量的方差 $\\epsilon$：防止除零的小常数（如 $10^{-8}$） $\\gamma$：可学习的缩放参数 $\\beta$：可学习的偏移参数 $\\hat{x}$：归一化后的输出 区别在于 $\\mu$ 和 $\\text{Var}(x)$ 沿哪个维度计算。\n11.2 BatchNorm vs LayerNorm 的归一化轴 假设输入张量的 shape 是 $[B, T, D]$（batch, 序列长度, 特征维度）：\nBatchNorm：沿 B 维度归一化 对每个特征维度 d，计算 batch 内所有样本、所有位置的均值和方差 μ_d = mean over (B, T) → 依赖 batch 内其他样本 LayerNorm：沿 D 维度归一化 对每个样本的每个位置，计算该位置所有特征维度的均值和方差 μ_{b,t} = mean over D → 每个样本独立，不依赖 batch 内其他样本 11.3 为什么 BatchNorm 不适合 Transformer 问题一：变长序列和 padding 让 batch 统计量不稳定。 不同样本的序列长度不同，短序列需要 padding，这些 padding token 会污染 batch 统计量，让均值和方差的估计带有噪声。\n问题二：小 batch 和推理时的不稳定性。 BatchNorm 的统计量质量取决于 batch size。Transformer 训练时 batch 往往不大（尤其是长序列场景），推理时 batch=1 更是问题——需要依赖训练时积累的 running statistics，但这些统计量在序列任务中不够可靠。\n问题三：token-wise 表示更自然对应 LayerNorm。 Transformer 的核心操作是 token 级别的：每个 token 有自己的特征向量，Attention 在 token 之间交互。对每个 token 独立归一化（LayerNorm）比跨 batch 归一化（BatchNorm）更符合这种计算范式。\nLayerNorm 对每个 token 独立归一化，完全回避了以上三个问题。\n11.4 LayerNorm 的数学效果 LayerNorm 把每个 token 的特征向量投影到一个标准化的超球面上（均值为 0，方差为 1），然后通过可学习的 $\\gamma$ 和 $\\beta$ 做仿射变换。这有两个好处：\n稳定前向传播：防止特征值在层间累积增长或衰减 稳定反向传播：梯度的尺度不会因为层数增加而剧烈变化 结合残差连接，LayerNorm 是 Transformer 能堆叠到几十甚至上百层的另一个关键保障。\n11.5 现代变体：RMSNorm 现代大模型（如 LLaMA、Gemma）常用 RMSNorm 替代 LayerNorm：\n$$\\text{RMSNorm}(x) = \\gamma \\cdot \\frac{x}{\\sqrt{\\frac{1}{d}\\sum_{i=1}^{d} x_i^2 + \\epsilon}}$$和 LayerNorm 的区别：RMSNorm 去掉了均值中心化（不减 $\\mu$），只做缩放归一化。好处是计算更快（少一次均值计算），实验表明效果和 LayerNorm 相当。\n十二、Cross-Entropy Loss：为什么用交叉熵而不是均方误差？ 出处：Cover \u0026amp; Thomas, \u0026ldquo;Elements of Information Theory\u0026rdquo;；Lei Mao 博客 \u0026ldquo;Cross Entropy, KL Divergence, and Maximum Likelihood Estimation\u0026rdquo;\nTransformer 训练时，Decoder 每个位置的 loss 都是交叉熵。但交叉熵不是一个随意选择的损失函数——它和最大似然估计、KL 散度在数学上完全等价。\n12.1 三者等价链 交叉熵：\n$$H(p, q) = -\\sum_{x} p(x) \\log q(x)$$其中：\n$H(p, q)$：交叉熵 $p(x)$：真实分布（训练标签） $q(x)$：模型预测的概率分布 $\\log$：自然对数 KL 散度：\n$$D_{KL}(p \\| q) = \\sum_{x} p(x) \\log \\frac{p(x)}{q(x)} = H(p, q) - H(p)$$其中：\n$D_{KL}(p \\| q)$：KL 散度（衡量两个概率分布之间的差异） $H(p)$：真实分布的熵（常数，不依赖模型参数） 因为 $H(p)$（真实分布的熵）是常数，不依赖模型参数，所以：\n$$\\arg\\min_\\theta H(p, q_\\theta) = \\arg\\min_\\theta D_{KL}(p \\| q_\\theta)$$最大似然估计：\n给定 $N$ 个样本 $\\{x_1, ..., x_N\\}$，MLE 最大化对数似然：\n$$\\arg\\max_\\theta \\frac{1}{N} \\sum_{i=1}^{N} \\log q_\\theta(x_i) = \\arg\\min_\\theta \\left(-\\frac{1}{N} \\sum_{i=1}^{N} \\log q_\\theta(x_i)\\right)$$右边就是经验分布 $\\hat{p}$ 下的交叉熵 $H(\\hat{p}, q_\\theta)$。\n结论：最小化交叉熵 = 最小化 KL 散度 = 最大似然估计。三条路殊途同归。\n12.2 对 Transformer 的意义 Decoder 训练时，每个位置预测下一个 token 的概率分布 $q_\\theta$，标签是 one-hot 的 $p$。交叉熵退化为：\n$$H(p, q) = -\\log q_\\theta(x_{correct})$$就是正确 token 的负对数概率。模型要做的就是让正确 token 的预测概率尽可能高——这正是最大似然估计。\n十三、Label Smoothing：为什么\u0026quot;故意犯错\u0026quot;反而更好？ 出处：Szegedy et al. (CVPR 2016) \u0026ldquo;Rethinking the Inception Architecture\u0026rdquo;；Vaswani et al. (2017)\n13.1 One-hot 标签的问题 标准交叉熵要求模型对正确类别输出概率 1，对其他类别输出概率 0。但 softmax 只有在 logit 趋向无穷大时才能输出 1：\n$$\\text{softmax}(z_i) \\to 1 \\quad \\text{当且仅当} \\quad z_i - z_j \\to \\infty, \\forall j \\neq i$$这迫使模型不断增大 logit 的绝对值，导致：\n过拟合：模型对训练数据过度自信 泛化差：对分布外的输入缺乏鲁棒性 13.2 Label Smoothing 的数学形式 把 one-hot 标签 $y$ 替换为平滑标签：\n$$y_{smooth} = (1 - \\epsilon) \\cdot y_{onehot} + \\frac{\\epsilon}{K}$$其中：\n$y_{onehot}$：原始 one-hot 标签 $\\epsilon$：平滑系数（原始 Transformer 用 0.1） $K$：类别总数 $y_{smooth}$：平滑后的标签 假设 K=5，正确类别是第 2 类： one-hot: [0, 1, 0, 0, 0] smoothed: [0.02, 0.92, 0.02, 0.02, 0.02] (ε=0.1) 模型不再需要输出 100% 的置信度，只需要输出 92% 就够了。这给了模型一个\u0026quot;不用绝对确定\u0026quot;的许可。\n13.3 Label Smoothing 的正则化效果 从 KL 散度的角度看，label smoothing 等价于在标准交叉熵上加了一个正则项：\n$$L_{smooth} = (1 - \\epsilon) \\cdot H(y, q) + \\epsilon \\cdot H(u, q)$$其中 $u$ 是均匀分布。第二项 $H(u, q)$ 惩罚模型输出偏离均匀分布太远——也就是说，不允许模型对任何类别过度自信。\nVaswani et al. 在论文中报告了一个有趣的现象：\u0026ldquo;Label smoothing hurts perplexity, as the model learns to be more unsure, but improves accuracy and BLEU score.\u0026rdquo; 困惑度变差（因为模型不再 100% 确定），但翻译质量反而提升了。\n十四、Learning Rate Warmup：为什么不能一开始就用大学习率？ 出处：Vaswani et al. (2017) Section 5.3；Ma \u0026amp; Yarats (2024) \u0026ldquo;Why Warmup the Learning Rate?\u0026rdquo;\n14.1 原始 Transformer 的学习率调度 Vaswani et al. 提出了一个两阶段的学习率公式：\n$$lr = d_{model}^{-0.5} \\cdot \\min(step^{-0.5}, \\; step \\cdot warmup\\_steps^{-1.5})$$其中：\n$lr$：学习率 $d_{model}$：模型隐藏层维度 $step$：当前训练步数 $warmup\\_steps$：预热阶段的总步数（原始 Transformer 用 4000） 行为分两段：\n阶段一（step \u0026lt; warmup_steps）： lr ≈ d_model^(-0.5) × step × warmup_steps^(-1.5) → 学习率线性增长 阶段二（step ≥ warmup_steps）： lr ≈ d_model^(-0.5) × step^(-0.5) → 学习率按 1/√step 衰减 原始 Transformer 用 warmup_steps = 4000 14.2 为什么需要 Warmup？ Adam 优化器维护每个参数的一阶矩（梯度均值）和二阶矩（梯度方差）的指数移动平均：\n$$m_t = \\beta_1 m_{t-1} + (1 - \\beta_1) g_t$$ $$v_t = \\beta_2 v_{t-1} + (1 - \\beta_2) g_t^2$$其中：\n$m_t$：第 $t$ 步的一阶矩估计（梯度的指数移动平均） $v_t$：第 $t$ 步的二阶矩估计（梯度平方的指数移动平均） $g_t$：第 $t$ 步的梯度 $\\beta_1, \\beta_2$：衰减系数（通常 $\\beta_1=0.9, \\beta_2=0.999$） 参数更新量为 $\\Delta \\theta \\propto m_t / \\sqrt{v_t}$。\n问题在训练初期：$m_t$ 和 $v_t$ 都初始化为 0，前几步的估计严重偏向 0。虽然 Adam 有偏差校正（$\\hat{m}_t = m_t / (1 - \\beta_1^t)$），但校正后的估计在前几十步仍然不稳定。如果此时学习率很大，不稳定的梯度估计 × 大学习率 = 参数剧烈震荡甚至发散。\nWarmup 的作用就是在 Adam 积累可靠统计量的这段时间里，用小学习率保护训练过程。\n14.3 Warmup 步数的选择 Ma \u0026amp; Yarats (2024) 提出了一个较新的解释视角：warmup 的作用可能在于让网络在训练早期经历一个\u0026quot;渐进锐化\u0026quot;阶段，逐步适应更大的学习率。warmup 步数通常设为总训练步数的 1%-5%。太短则保护不够，太长则浪费了高学习率带来的快速收敛。关于 warmup 为什么有效，目前还没有完全统一的理论解释。\n十五、信息瓶颈：一个理解 Attention 的启发性视角（选读） 出处：Tishby \u0026amp; Schwartz-Ziv (2017) \u0026ldquo;Opening the Black Box of Deep Neural Networks via Information\u0026rdquo;\n这一节提供一个理论视角来思考\u0026quot;为什么 Attention 有效\u0026rdquo;。需要强调的是，这更多是一种启发性的类比，而非针对 Transformer 的严格证明。\n15.1 信息瓶颈原理 给定输入 $X$ 和目标 $Y$，一个好的中间表示 $Z$ 应该满足：\n$$\\max I(Z; Y) \\quad \\text{subject to} \\quad \\min I(Z; X)$$其中：\n$I(\\cdot; \\cdot)$：互信息（衡量两个变量之间共享的信息量） $X$：输入数据 $Y$：预测目标（标签） $Z$：中间表示（模型学到的特征） 即：保留尽可能多的与预测目标相关的信息（$I(Z; Y)$ 大），同时压缩掉与预测无关的输入噪声（$I(Z; X)$ 小）。\n15.2 Attention 与信息瓶颈 Attention 的 softmax 权重可以看作一种信息选择机制：\n高权重的 token：信息被保留（与当前 query 相关） 低权重的 token：信息被压缩（与当前 query 无关） 每一层 Attention 都在做一次\u0026quot;选择性压缩\u0026rdquo;——保留对当前任务有用的信息，丢弃无关的上下文。这和信息瓶颈的目标天然吻合。\n不过需要强调，这是一个启发性的类比，不是严格的数学证明。Tishby 的信息瓶颈理论本身在深度学习中的适用性仍有争议（Saxe et al., 2018 提出了质疑）。把它作为理解 Attention 的一个思考框架是有价值的，但不宜过度解读。\n核心概念速查表 概念 一句话解释 为什么重要 $\\sqrt{d_k}$ 缩放 点积方差随维度线性增长，除以 $\\sqrt{d_k}$ 使方差归一 防止 softmax 饱和导致梯度消失 Softmax 温度 $\\sqrt{d_k}$ 本质上是 Boltzmann 分布的温度参数 控制注意力分布的锐度 正弦位置编码 不同频率的 sin/cos 编码位置，$PE(pos+k)$ 是 $PE(pos)$ 的线性变换 让模型通过线性运算学到相对位置关系 Attention = 核回归 softmax attention 与 Nadaraya-Watson 核回归形式对应 提供理解 Attention 设计的经典统计视角 Multi-Head 分头后每个头独立做 Attention，最后拼接投影 让不同头学习不同的关注模式 Mask 在 $QK^T$ 上加 $M$ 矩阵（$-\\infty$ 屏蔽不可见位置） 实现 causal 生成和 padding 处理 FFN 逐 token 的两层 MLP：升维 → 激活 → 降维 Attention 管 token 间交互，FFN 管 token 内变换 $O(T^2)$ 复杂度 Attention 矩阵大小为 $T \\times T$ 长序列的核心瓶颈，Linear Attention 的动机 Cross-Attention Q 来自 Decoder，K/V 来自 Encoder，连接两个序列 Encoder-Decoder 架构和多模态模型的桥梁 残差连接 $y = F(x) + x$，梯度中恒等项 $I$ 保证梯度直通 深层 Transformer 能训练的核心保障 LayerNorm 沿特征维度归一化，每个样本独立 不受 batch 大小和序列长度影响 交叉熵 = KL 散度 = MLE 三种优化目标在数学上完全等价 理解 Decoder 训练的本质 Label Smoothing 用 $(1-\\epsilon) \\cdot y + \\epsilon/K$ 替代 one-hot 防止过拟合，提升泛化 LR Warmup 前 N 步线性增长学习率，之后衰减 给 Adam 时间积累可靠的梯度统计量 信息瓶颈 好的表示应最大化 $I(Z;Y)$ 同时最小化 $I(Z;X)$ 一个理解 Attention 信息筛选的启发性框架 学习检查清单 能推导为什么点积的方差是 $d_k$，以及为什么除以 $\\sqrt{d_k}$ 能解释 softmax 和 Boltzmann 分布的关系，以及温度参数的作用 能写出正弦位置编码的公式，并解释为什么 $PE(pos+k)$ 可以表示为 $PE(pos)$ 的线性变换 能把 Attention 改写成核回归的形式，并说出核函数是什么 能写出 Multi-Head Attention 的完整维度变化：输入 shape → 分头 → 各头 Attention → 拼接 → 输出 能用 $QK^T + M$ 的统一公式解释 causal mask 和 padding mask 能写出 FFN 的公式，并解释 Attention 和 FFN 的分工 能分析 Self-Attention 的时间和空间复杂度，并解释为什么 $O(T^2)$ 是长序列瓶颈 能写出 Cross-Attention 的公式，并说清 Q/K/V 分别来自哪个序列 能推导残差连接的梯度公式，并解释恒等项 $I$ 的作用 能说出 LayerNorm 和 BatchNorm 的归一化轴区别，以及为什么 Transformer 选 LayerNorm 能证明最小化交叉熵等价于最大似然估计 能写出 Label Smoothing 的公式，并解释它为什么能防止过拟合 能写出原始 Transformer 的学习率公式，并解释 warmup 的必要性 能用信息瓶颈的语言描述 Attention 在做什么（选读） 参考文献 编号 论文/博客 对应章节 [1] Vaswani et al. (2017). \u0026ldquo;Attention Is All You Need.\u0026rdquo; NeurIPS. arXiv:1706.03762 §1, §2, §3, §13, §14 [2] Jay Alammar. \u0026ldquo;The Illustrated Transformer.\u0026rdquo; jalammar.github.io §3 [3] Amirhossein Kazemnejad. \u0026ldquo;Transformer Architecture: The Positional Encoding.\u0026rdquo; kazemnejad.com §3 [4] Tsai et al. (2019). \u0026ldquo;Transformer Dissection: A Unified Understanding for Transformer\u0026rsquo;s Attention via the Lens of Kernel.\u0026rdquo; EMNLP. arXiv:1908.11775 §4 [5] Choromanski et al. (2021). \u0026ldquo;Rethinking Attention with Performers.\u0026rdquo; ICLR. arXiv:2009.14794 §4, §8 [6] He et al. (2016). \u0026ldquo;Deep Residual Learning for Image Recognition.\u0026rdquo; CVPR. arXiv:1512.03385 §10 [7] He et al. (2016). \u0026ldquo;Identity Mappings in Deep Residual Networks.\u0026rdquo; ECCV. arXiv:1603.05027 §10 [8] Ba, Kiros \u0026amp; Hinton (2016). \u0026ldquo;Layer Normalization.\u0026rdquo; arXiv:1607.06450 §11 [9] Cover \u0026amp; Thomas. \u0026ldquo;Elements of Information Theory.\u0026rdquo; Wiley. §12 [10] Lei Mao. \u0026ldquo;Cross Entropy, KL Divergence, and Maximum Likelihood Estimation.\u0026rdquo; leimao.github.io §12 [11] Szegedy et al. (2016). \u0026ldquo;Rethinking the Inception Architecture for Computer Vision.\u0026rdquo; CVPR. arXiv:1512.00567 §13 [12] Ma \u0026amp; Yarats (2024). \u0026ldquo;Why Warmup the Learning Rate?\u0026rdquo; arXiv:2406.09405 §14 [13] Tishby \u0026amp; Schwartz-Ziv (2017). \u0026ldquo;Opening the Black Box of Deep Neural Networks via Information.\u0026rdquo; arXiv:1703.00810 §15 [14] Hinton et al. (2015). \u0026ldquo;Distilling the Knowledge in a Neural Network.\u0026rdquo; arXiv:1503.02531 §2 ","permalink":"https://ardenj.pages.dev/learning/transformer_math/","summary":"\u003cblockquote\u003e\n\u003cp\u003e上一篇笔记建立了 Transformer 的直觉和代码实现，这篇深入每个组件背后的数学原理。每个主题都标注了出处论文或博客，方便查阅原文。\u003c/p\u003e\u003c/blockquote\u003e\n\u003chr\u003e\n\u003ch2 id=\"一scaled-dot-product为什么除以-dk\"\u003e一、Scaled Dot-Product：为什么除以 √dk？\u003c/h2\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003cstrong\u003e出处\u003c/strong\u003e：Vaswani et al. (2017) \u0026ldquo;Attention Is All You Need\u0026rdquo;, Section 3.2.1\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003e上一篇笔记里我们知道 Attention 的计算公式是：\u003c/p\u003e\n$$\\text{Attention}(Q, K, V) = \\text{softmax}\\left(\\frac{QK^T}{\\sqrt{d_k}}\\right) V$$\u003cp\u003e其中：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e$Q$：Query 矩阵\u003c/li\u003e\n\u003cli\u003e$K$：Key 矩阵\u003c/li\u003e\n\u003cli\u003e$V$：Value 矩阵\u003c/li\u003e\n\u003cli\u003e$d_k$：Key 向量的维度\u003c/li\u003e\n\u003cli\u003e$\\text{softmax}$：归一化函数（将分数转为概率分布）\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e但为什么要除以 $\\sqrt{d_k}$？Vaswani et al. 在论文中给出了一句关键解释：\u0026ldquo;We suspect that for large values of $d_k$, the dot products grow large in magnitude, pushing the softmax function into regions where it has extremely small gradients.\u0026rdquo; 下面把这句话拆成严格的数学推导。\u003c/p\u003e\n\u003ch3 id=\"11-方差推导\"\u003e1.1 方差推导\u003c/h3\u003e\n\u003cp\u003e假设 $q$ 和 $k$ 的每个分量都是独立同分布的随机变量，均值为 0，方差为 1。点积 $q^T k = \\sum_{i=1}^{d_k} q_i k_i$。\u003c/p\u003e","title":"Transformer 数学原理"},{"content":"大概的总结 三月份做了的事 申请学校科研项目并开始初步尝试 入门robocup仿真3D足球 coffee talk进展顺利，本月进行了3次 没做好的事 折腾claude 课内进度严重落后 没有找到合适高效的学习方法（就是被手机控制了） 英语学习磕磕绊绊 刷课由于时间紧没有做 方法论的反思 存在的问题 在方法论上的执行度呈现一个递减的趋势，在最开始的一两周大概可以执行70%，但是越到后期执行效率越低。\nopen策略：这个月末拉了一个乐队的朋友一起在工位学习，也和他交流了未来的规划，算是有了一个交心的朋友。然后和班里的一位同学有部分的交流，但是我没有和他交流科研上的事情，以后慢慢来吧。我感觉我自己没有能完全地执行open策略，在遇到一些人和事的时候还是会不自然地掩盖自己在做的事情，也会存在我的进度或视野比你超前的想法，导致open策略受到我自己的限制。这也不是一朝一夕可以改变的，我打算慢慢来。 流式规划：这个方法我在月初的时候还有执行，到后面就完全没有实行下去。有几个原因：经常被手机控制，没有学习到1个半小时就拿手机开始刷；提示词的用处还是有的，但是有的时候会忘记写；最初进行了每日以1.5h一个epoch进行时间规划，但这种细分的规划完全起不到约束的作用。 工程思维：现在存在的一个严重问题是对ai的过分依赖（claude太好用了你懂吗😭）。最开始还会尝试审阅代码，后来就直接使用codex和claude code写代码，这就导致我对于代码没有完整的了解，代码能力也没有任何的提升。 输出：在科研开始的时候进行了一些知识输出，但是后半月就几乎没有了。周记也只写了一篇。 调整策略 open策略：我打算慢慢寻找更多的朋友，在校科协或许可以找到不错的伙伴。那里的同学我也和我目前的学习路径高度相似，我相信可以找到不错的朋友。 流式规划：1.5个小时为一段学习时间的规划，我认为依然是好的。在执行的过程中，我发现用Focus Noodles强制隔离手机的效果不错，这个月需要加强执行。而每日细分epoch的规划就放弃，使用动态的规划形式。 工程思维：这个月需要强制降低ai的使用频率，review自己科研项目的代码和robocup的代码，不能做到无脑使用ai，对ai的改动需要清楚为什么。 输出：这个可以和工程思维的改动一起做，贴一些代码阅读上的反思，和阅读论文的笔记。这个月定一个目标，必须要写出自己当前研究方向的一篇综述。 四月重点 经过上文的一些反思和总结，这个月要做的事大致如下：\n学习大纲 课内知识：这是重中之重，这个月必须要至少学到老师讲到的地方，并且要有足够的刷题。可以考虑一天看课一天刷题。每天必须先学足够的课内课程才可以进行其他学习。 research：快速review完当前实验的状况和改进的点，距离截稿日期还长，可以保持低频的输入和输出，保证每天有进步即可。 robocup ：停止完全的ai代码，把一些重点代码读通，补充这方面的通信知识也是不错的。 Stanford CS106B/X、ECC、汇编：这些课程可以在以上三个方向完成后作为补充知识（大概是不会做的），其中ECC可以作为学习之余解闷的放松，深入强化一下claude code的使用。 总而言之，新的一个月继续加油，少崩溃，多反思，GO！\n","permalink":"https://ardenj.pages.dev/thinking/2026_3_summary/","summary":"\u003ch2 id=\"大概的总结\"\u003e大概的总结\u003c/h2\u003e\n\u003ch3 id=\"三月份做了的事\"\u003e三月份做了的事\u003c/h3\u003e\n\u003col\u003e\n\u003cli\u003e申请学校科研项目并开始初步尝试\u003c/li\u003e\n\u003cli\u003e入门robocup仿真3D足球\u003c/li\u003e\n\u003cli\u003ecoffee talk进展顺利，本月进行了3次\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch3 id=\"没做好的事\"\u003e没做好的事\u003c/h3\u003e\n\u003col\u003e\n\u003cli\u003e折腾claude\u003c/li\u003e\n\u003cli\u003e课内进度严重落后\u003c/li\u003e\n\u003cli\u003e没有找到合适高效的学习方法（就是被手机控制了）\u003c/li\u003e\n\u003cli\u003e英语学习磕磕绊绊\u003c/li\u003e\n\u003cli\u003e刷课由于时间紧没有做\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch2 id=\"方法论的反思\"\u003e方法论的反思\u003c/h2\u003e\n\u003ch3 id=\"存在的问题\"\u003e存在的问题\u003c/h3\u003e\n\u003cp\u003e在方法论上的执行度呈现一个递减的趋势，在最开始的一两周大概可以执行70%，但是越到后期执行效率越低。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eopen策略\u003c/strong\u003e：这个月末拉了一个乐队的朋友一起在工位学习，也和他交流了未来的规划，算是有了一个交心的朋友。然后和班里的一位同学有部分的交流，但是我没有和他交流科研上的事情，以后慢慢来吧。我感觉我自己没有能完全地执行open策略，在遇到一些人和事的时候还是会不自然地掩盖自己在做的事情，也会存在我的进度或视野比你超前的想法，导致open策略受到我自己的限制。这也不是一朝一夕可以改变的，我打算慢慢来。\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e流式规划\u003c/strong\u003e：这个方法我在月初的时候还有执行，到后面就完全没有实行下去。有几个原因：经常被手机控制，没有学习到1个半小时就拿手机开始刷；提示词的用处还是有的，但是有的时候会忘记写；最初进行了每日以1.5h一个epoch进行时间规划，但这种细分的规划完全起不到约束的作用。\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e工程思维\u003c/strong\u003e：现在存在的一个严重问题是对ai的过分依赖（claude太好用了你懂吗😭）。最开始还会尝试审阅代码，后来就直接使用codex和claude code写代码，这就导致我对于代码没有完整的了解，代码能力也没有任何的提升。\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e输出\u003c/strong\u003e：在科研开始的时候进行了一些知识输出，但是后半月就几乎没有了。周记也只写了一篇。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"调整策略\"\u003e调整策略\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eopen策略\u003c/strong\u003e：我打算慢慢寻找更多的朋友，在校科协或许可以找到不错的伙伴。那里的同学我也和我目前的学习路径高度相似，我相信可以找到不错的朋友。\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e流式规划\u003c/strong\u003e：1.5个小时为一段学习时间的规划，我认为依然是好的。在执行的过程中，我发现用Focus Noodles强制隔离手机的效果不错，这个月需要加强执行。而每日细分epoch的规划就放弃，使用动态的规划形式。\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e工程思维\u003c/strong\u003e：这个月需要强制降低ai的使用频率，review自己科研项目的代码和robocup的代码，不能做到无脑使用ai，对ai的改动需要清楚为什么。\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e输出\u003c/strong\u003e：这个可以和工程思维的改动一起做，贴一些代码阅读上的反思，和阅读论文的笔记。这个月定一个目标，必须要写出自己当前研究方向的一篇综述。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"四月重点\"\u003e四月重点\u003c/h2\u003e\n\u003cp\u003e经过上文的一些反思和总结，这个月要做的事大致如下：\u003c/p\u003e\n\u003ch3 id=\"学习大纲\"\u003e学习大纲\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003e课内知识\u003c/strong\u003e：这是重中之重，这个月必须要至少学到老师讲到的地方，并且要有足够的刷题。可以考虑一天看课一天刷题。每天必须先学足够的课内课程才可以进行其他学习。\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eresearch\u003c/strong\u003e：快速review完当前实验的状况和改进的点，距离截稿日期还长，可以保持低频的输入和输出，保证每天有进步即可。\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003erobocup\u003c/strong\u003e ：停止完全的ai代码，把一些重点代码读通，补充这方面的通信知识也是不错的。\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eStanford CS106B/X、ECC、汇编\u003c/strong\u003e：这些课程可以在以上三个方向完成后作为补充知识（\u003cdel\u003e大概是不会做的\u003c/del\u003e），其中ECC可以作为学习之余解闷的放松，深入强化一下claude code的使用。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cblockquote\u003e\n\u003cp\u003e总而言之，新的一个月继续加油，少崩溃，多反思，GO！\u003c/p\u003e\u003c/blockquote\u003e","title":"2026.3小结"},{"content":"简单回顾 本周主线：深入阅读敲定下来的科研方向的文献。 最大推进：阅读了5篇该领域的主要文献。针对transformer不熟悉的问题，学习了transformer的基本架构与实现，了解了CILP的底层架构。 最大问题：每日效率有待提高，有的时候会陷入不断制定计划的虚假的自我满足；对课内学习有所忽视。 主要学习内容 本周主要针对LLM+FedDG方向做了深入的文献阅读，CoOp → PromptFL → DiPrompT → FedTPG → FedDSPG，详细了解了soft prompt在联邦域泛化领域的进展。 下面对每篇论文的内容做简要概述：\n文献一：CoOp（IJCV 2022）\n创新：该文献首次提出了图文模型（CLIP、ViT）在联邦域泛化领域的应用，通过生成soft prompt的形式显著改善了人工提示词工程量大，泛化效果不高的问题。\n问题：但它是单机方法，无法适用于数据分布在多设备上的联邦场景；且学到的 prompt 是静态向量，对训练时没见过的域/类泛化能力有限。\n文献二：PromptFL（IEEE TMC 2023）\n创新：首次将 CoOp 的 Soft Prompt 训练搬进联邦框架，只聚合 prompt 向量而非整个模型参数，通信量压缩约 110 倍，且在 Extreme Non-IID 下仍保持稳定（88% vs 传统 FL 的 29%）。\n问题：所有客户端共享同一个 Global Prompt，不区分域差异；没有评估对未见目标域的泛化能力（即不涉及 Domain Generalization）。\n文献三：DiPrompT（CVPR 2024）\n创新：将 prompt 解耦为 G-Prompt（通用知识）和 D-Prompts（域特有知识），并设计 Q-Prompt 自动查询样本所属域，消除了对域标签的依赖和客户端与域一一对应的限制。\n问题：D-Prompt 池大小固定，需要预设域数量；推理时的协同集成依赖目标样本与源域相似的假设，面对全新域时可能失效。\n文献四：FedTPG（ICLR 2024）\n创新：用轻量级 PromptTranslator 网络根据类名文本 embedding 动态生成 prompt，使模型能泛化到训练时未见过的新类别，解决了固定 prompt 向量无法跨类迁移的问题。\n问题：生成条件仅依赖类名文本，不包含域信息，对跨域泛化的提升有限；PromptTranslator 结构简单（MLP），表达能力不足以捕捉复杂的域间差异。\n文献五：FedDSPG（arXiv 2025）\n创新：设计了包含通用 token 和域特有 token 的 DSP 结构，并用 CcGAN 对抗训练学习从图片特征到 prompt 的映射，在 Office-Home/DomainNet/PACS 上全面达到 SOTA。\n问题：GAN 对抗训练计算量大（实验用 8 张 V100），部署成本远高于 PromptFL/DiPrompT；Generator + Discriminator 的参数需要在联邦中传输，部分抵消了 prompt learning 的通信优势。\n对Idea方向的大致思考： 针对目前阅读的论文，我大致思考了几个可以深入展开的Idea： 当前FedDSPG将 参数化的prompt 改进为 生成式的prompt ，那么在此基础上进行思考：\n生成的对象为什么一定是 text prompt？ 能不能生成 LoRA / adapter / expert routing / classifier head / feature transform？ 生成机制为什么一定由图像或文本单独驱动？能不能由 image + text + client meta-info + uncertainty 共同驱动？ 除了这些问题，我和GPT进行了一些讨论，GPT给出了很专业很细致的指导，有的Idea我甚至看不懂他在说什么，所以现在主要还是要打牢基础。\n方法论执行 这周在方法论的执行上完成度不算好，open策略几乎没有执行，周围人还是更趋向零和博弈，我觉得和我们学校浓厚的竞赛氛围有关，大家都把同学当作竞争对手，目前我 也没想到更合适的open方法。 在于学长的交流上倒是进展迅速，碰到了一个很热心的学长，在科研方面请教了很多问题（阿里嘎多！）。同时这周也和导员进行了很密切的交流，导员也给出了不错的提议，这周打算继续跟进。\n流式规划则执行的不是很好，首先要控制自己在学习时玩手机的冲动，有的时候也没法保证恰好1个半小时学习，而是看着看着就2个小时过去，但是效率也没有那么高。\n知识输出倒是一直在做\n英语的执行简直是一坨，就记了两次日记，下周必须完成至少5篇！\n下周计划 这周其实效率并不高，很多时间还是花在了细化计划和方案，每次做计划的时候就感觉自己好像真的做到了一样，有种虚假的满足感\u0026hellip; \u0026hellip; 还有一个问题是现在看论文的时候越看越觉得自己的基础知识其实不是很扎实，知识面有点太窄，所以下周主要做以下事情：\n看李宏毅机器学习的课，理解强化学习、fussion model等热门架构的原理。 扩展FDG方向的视野，了解域对齐、数据操作、学习策略、聚合优化这四个大类的框架。 追一追课内课程的进度。 碎碎念 一个人在学习确实容易陷入内耗和放弃，好想找个朋友一起学习，互相分享方法论和学到的知识点这些的。。。。emmmmmm再想想吧。\n","permalink":"https://ardenj.pages.dev/thinking/wk_sum1/","summary":"\u003ch2 id=\"简单回顾\"\u003e简单回顾\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e本周主线：深入阅读敲定下来的科研方向的文献。\u003c/li\u003e\n\u003cli\u003e最大推进：阅读了5篇该领域的主要文献。针对transformer不熟悉的问题，学习了transformer的基本架构与实现，了解了CILP的底层架构。\u003c/li\u003e\n\u003cli\u003e最大问题：每日效率有待提高，有的时候会陷入不断制定计划的虚假的自我满足；对课内学习有所忽视。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"主要学习内容\"\u003e主要学习内容\u003c/h2\u003e\n\u003cp\u003e本周主要针对LLM+FedDG方向做了深入的文献阅读，CoOp → PromptFL → DiPrompT → FedTPG → FedDSPG，详细了解了soft prompt在联邦域泛化领域的进展。\n下面对每篇论文的内容做简要概述：\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e文献一：CoOp（IJCV 2022）\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e创新：该文献首次提出了图文模型（CLIP、ViT）在联邦域泛化领域的应用，通过生成soft prompt的形式显著改善了人工提示词工程量大，泛化效果不高的问题。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e问题：但它是单机方法，无法适用于数据分布在多设备上的联邦场景；且学到的 prompt 是静态向量，对训练时没见过的域/类泛化能力有限。\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cstrong\u003e文献二：PromptFL（IEEE TMC 2023）\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e创新：首次将 CoOp 的 Soft Prompt 训练搬进联邦框架，只聚合 prompt 向量而非整个模型参数，通信量压缩约 110 倍，且在 Extreme Non-IID 下仍保持稳定（88% vs 传统 FL 的 29%）。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e问题：所有客户端共享同一个 Global Prompt，不区分域差异；没有评估对未见目标域的泛化能力（即不涉及 Domain Generalization）。\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cstrong\u003e文献三：DiPrompT（CVPR 2024）\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e创新：将 prompt 解耦为 G-Prompt（通用知识）和 D-Prompts（域特有知识），并设计 Q-Prompt 自动查询样本所属域，消除了对域标签的依赖和客户端与域一一对应的限制。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e问题：D-Prompt 池大小固定，需要预设域数量；推理时的协同集成依赖目标样本与源域相似的假设，面对全新域时可能失效。\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cstrong\u003e文献四：FedTPG（ICLR 2024）\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e创新：用轻量级 PromptTranslator 网络根据类名文本 embedding 动态生成 prompt，使模型能泛化到训练时未见过的新类别，解决了固定 prompt 向量无法跨类迁移的问题。\u003c/p\u003e","title":"3.9~3.15周总结"},{"content":" 经过CoOp的阅读，我们了解到了在单机上如何通过机器自己优化“soft prompt”来提高图像的识别，而promptFL则是在此基础上更进一步，将CoOp展现的强大迁移能力应用至联邦学习领域。\n优势 成本：在传统联邦学习中，我们需要将大量的数据参数上传至服务器，而promptFL只需要上传提示词参数，在实验对比中，promptFL取得了惊人的成果： 指标 PromptFL Finetuning FL 差距 每轮上传量 6.3 MB 693 MB 110倍 可训练参数 0.01%~0.1% 100% 训练数据需求 202 张 50500 张 250倍 GPU 训练时间 2444s 7189s ~3倍 Non-IID 下不崩：Table 2 的 Extreme Non-IID 列非常关键：Finetuning FL 在 Non-IID 下准确率从 90% 暴跌到 29%，而 PromptFL 从 90% 只掉到 88%。因为 CLIP 冻结不动，prompt 只是轻微调整方向，不容易被某个客户端的偏置数据带偏。\nFew-shot 有效: 每个客户端只需 2~16 张图就能训练，符合联邦场景下各设备数据量小的现实。\n局限 局限一：所有客户端共享同一个 Global Prompt。 不区分客户端的域差异。比如客户端 A 拍的是白天户外的猫，客户端 B 拍的是夜间室内的猫，它们需要的\u0026quot;最佳开场白\u0026quot;显然不同，但 PromptFL 强制所有人用同一个。\n局限二：没有考虑 Domain Generalization。 PromptFL 只在训练过的域上评估，没有测试\u0026quot;在完全没见过的新域上表现如何\u0026quot;。\n局限三：Prompt Learner 极其简单。 就是 CoOp 的原封不动搬过来，没有任何针对联邦场景的适配。\n以后打算简短记一些笔记，这样读论文的压力比较小，也比较容易坚持，遇到很感兴趣的论文再精记笔记吧。\n","permalink":"https://ardenj.pages.dev/learning/promptfl/","summary":"\u003cblockquote\u003e\n\u003cp\u003e经过CoOp的阅读，我们了解到了在单机上如何通过机器自己优化“soft prompt”来提高图像的识别，而promptFL则是在此基础上更进一步，将CoOp展现的强大迁移能力应用至联邦学习领域。\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch2 id=\"优势\"\u003e优势\u003c/h2\u003e\n\u003col\u003e\n\u003cli\u003e\u003cstrong\u003e成本\u003c/strong\u003e：在传统联邦学习中，我们需要将大量的数据参数上传至服务器，而promptFL只需要上传提示词参数，在实验对比中，promptFL取得了惊人的成果：\u003c/li\u003e\n\u003c/ol\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003e指标\u003c/th\u003e\n          \u003cth\u003ePromptFL\u003c/th\u003e\n          \u003cth\u003eFinetuning FL\u003c/th\u003e\n          \u003cth\u003e差距\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e每轮上传量\u003c/td\u003e\n          \u003ctd\u003e6.3 MB\u003c/td\u003e\n          \u003ctd\u003e693 MB\u003c/td\u003e\n          \u003ctd\u003e\u003cstrong\u003e110倍\u003c/strong\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e可训练参数\u003c/td\u003e\n          \u003ctd\u003e0.01%~0.1%\u003c/td\u003e\n          \u003ctd\u003e100%\u003c/td\u003e\n          \u003ctd\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e训练数据需求\u003c/td\u003e\n          \u003ctd\u003e202 张\u003c/td\u003e\n          \u003ctd\u003e50500 张\u003c/td\u003e\n          \u003ctd\u003e\u003cstrong\u003e250倍\u003c/strong\u003e\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003eGPU 训练时间\u003c/td\u003e\n          \u003ctd\u003e2444s\u003c/td\u003e\n          \u003ctd\u003e7189s\u003c/td\u003e\n          \u003ctd\u003e~3倍\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003col start=\"2\"\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003eNon-IID 下不崩\u003c/strong\u003e：Table 2 的 Extreme Non-IID 列非常关键：Finetuning FL 在 Non-IID 下准确率从 90% 暴跌到 29%，而 PromptFL 从 90% 只掉到 88%。因为 CLIP 冻结不动，prompt 只是轻微调整方向，不容易被某个客户端的偏置数据带偏。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003eFew-shot 有效\u003c/strong\u003e: 每个客户端只需 2~16 张图就能训练，符合联邦场景下各设备数据量小的现实。\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch2 id=\"局限\"\u003e局限\u003c/h2\u003e\n\u003cp\u003e\u003cstrong\u003e局限一：所有客户端共享同一个 Global Prompt。\u003c/strong\u003e 不区分客户端的域差异。比如客户端 A 拍的是白天户外的猫，客户端 B 拍的是夜间室内的猫，它们需要的\u0026quot;最佳开场白\u0026quot;显然不同，但 PromptFL 强制所有人用同一个。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e局限二：没有考虑 Domain Generalization。\u003c/strong\u003e PromptFL 只在训练过的域上评估，没有测试\u0026quot;在完全没见过的新域上表现如何\u0026quot;。\u003c/p\u003e","title":"PromptFL阅读笔记"},{"content":"一、为什么要学 Transformer？ Transformer 是当前深度学习的基础架构。NLP 领域的 BERT、GPT 系列，计算机视觉的 ViT，多模态模型 CLIP、Stable Diffusion——底层全是 Transformer。不理解 Transformer，后续读任何相关论文都会卡在架构细节上。\n学完本笔记后，应该能回答：Q/K/V 怎么算？Multi-Head 为什么有用？Positional Encoding 干什么的？Encoder 和 Decoder 有什么区别？\n二、Self-Attention（自注意力机制） 2.1 核心问题：如何处理变长序列？ 输入可能是一句话（5个词）、一段语音（200帧）、一张图（196个patch），长度不固定。传统 FC 层要求固定输入维度，无法处理这种情况。\n生活类比：你在教室里坐着，老师点名提问。FC 层相当于老师只看你一个人；Self-Attention 相当于老师让全班每个人都互相看一眼，综合所有人的信息后再做判断。\n2.2 Self-Attention 的计算流程 假设输入序列有 T 个 token，每个 token 是一个 d 维向量：\n输入：X = [x₁, x₂, ..., xT]，shape = [T, d] 第1步：生成 Q, K, V（三个\u0026#34;角色\u0026#34;） Q = X @ Wq # Query: \u0026#34;我在找什么？\u0026#34; shape = [T, dk] K = X @ Wk # Key: \u0026#34;我能提供什么？\u0026#34; shape = [T, dk] V = X @ Wv # Value: \u0026#34;我的实际内容\u0026#34; shape = [T, dv] 第2步：算 Attention Score（谁和谁最相关？） Score = Q @ K^T # shape = [T, T]，每对 token 之间的相关性 Score = Score / √dk # 缩放，防止数值过大导致 softmax 梯度消失 第3步：Softmax 归一化 Attention = softmax(Score, dim=-1) # 每行和为1，变成概率分布 第4步：加权求和 Output = Attention @ V # shape = [T, dv] 生活类比：\nQuery（查询）：你走进图书馆，脑子里想着\u0026quot;我要找关于机器人的书\u0026quot; Key（钥匙）：每本书封面上的标签，如\u0026quot;机器人\u0026quot;、\u0026ldquo;烹饪\u0026rdquo;、\u0026ldquo;历史\u0026rdquo; Value（内容）：书的实际内容 Attention Score：你的需求和每本书标签的匹配程度 Output：根据匹配程度，从所有书中加权提取出对你最有用的信息 2.3 PyTorch 伪代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 import torch import torch.nn as nn import torch.nn.functional as F class SelfAttention(nn.Module): def __init__(self, d_model, dk): super().__init__() self.Wq = nn.Linear(d_model, dk) self.Wk = nn.Linear(d_model, dk) self.Wv = nn.Linear(d_model, dk) self.scale = dk ** 0.5 # √dk def forward(self, x): \u0026#34;\u0026#34;\u0026#34; x: [batch, seq_len, d_model] \u0026#34;\u0026#34;\u0026#34; Q = self.Wq(x) # [batch, T, dk] K = self.Wk(x) # [batch, T, dk] V = self.Wv(x) # [batch, T, dk] # Attention Score: Q和K的点积衡量相关性 score = torch.bmm(Q, K.transpose(1, 2)) / self.scale # [batch, T, T] # Softmax: 变成概率分布（每行和为1） attn = F.softmax(score, dim=-1) # [batch, T, T] # 加权求和: 用相关性权重对V求和 output = torch.bmm(attn, V) # [batch, T, dk] return output 2.4 数值例子 假设 3 个 token，dk = 2（极简示例） Q = [[1, 0], K = [[1, 0], V = [[5, 6], [0, 1], [0, 1], [7, 8], [1, 1]] [1, 1]] [9, 10]] Score = Q @ K^T / √2: token1 和 token1: (1×1 + 0×0) / √2 = 0.71 token1 和 token2: (1×0 + 0×1) / √2 = 0.00 token1 和 token3: (1×1 + 0×1) / √2 = 0.71 Score = [[0.71, 0.00, 0.71], [0.00, 0.71, 0.71], [0.71, 0.71, 1.41]] Softmax（对每行归一化）: Attn ≈ [[0.39, 0.22, 0.39], ← token1 主要关注自己和 token3 [0.22, 0.39, 0.39], ← token2 主要关注自己和 token3 [0.24, 0.24, 0.52]] ← token3 最关注自己 Output = Attn @ V: token1 的输出 = 0.39×[5,6] + 0.22×[7,8] + 0.39×[9,10] = [7.0, 8.0] → 每个 token 的输出都融合了其他 token 的信息！ 2.5 为什么叫\u0026quot;Self\u0026quot;-Attention？ 因为 Q、K、V 全部来自同一个输入 X。如果 Q 来自一个序列、K/V 来自另一个序列，就叫 Cross-Attention（交叉注意力）——这在 Transformer Decoder（如机器翻译中 Decoder 查看 Encoder 输出）和多模态模型（如图文对齐）中都会用到。\n2.6 Self-Attention 的信息融合效果 以 BERT 为例，输入 [CLS] I love this movie [SEP]，经过 Self-Attention 后，[CLS] 位置的输出向量融合了整个句子的信息——这就是为什么 BERT 用 [CLS] 的输出做句子级分类。每个 token 的输出都不再只代表自己，而是融合了序列中其他 token 的信息。\n三、Multi-Head Attention（多头注意力） 3.1 为什么需要多头？ 单头 Attention 只学一种\u0026quot;关注模式\u0026quot;。但在自然语言中，一个词和其他词的关系是多维度的：\n\u0026#34;The cat sat on the mat because it was soft\u0026#34; \u0026#34;it\u0026#34; 需要同时关注： - 语法层面：\u0026#34;it\u0026#34; 指代 \u0026#34;mat\u0026#34;（名词替代关系） - 语义层面：\u0026#34;soft\u0026#34; 修饰 \u0026#34;mat\u0026#34;（属性关系） - 位置层面：\u0026#34;it\u0026#34; 和 \u0026#34;mat\u0026#34; 距离较近 单头只能学一种关系，多头可以每个头学一种 3.2 Multi-Head 的计算 不是做一次 Attention，而是做 h 次（h 个 head），每次用不同的 W 矩阵： Head_1 = Attention(X @ Wq1, X @ Wk1, X @ Wv1) Head_2 = Attention(X @ Wq2, X @ Wk2, X @ Wv2) ... Head_h = Attention(X @ Wqh, X @ Wkh, X @ Wvh) 最后拼接 + 线性变换： MultiHead = Concat(Head_1, ..., Head_h) @ Wo 3.3 PyTorch 伪代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 class MultiHeadAttention(nn.Module): def __init__(self, d_model, num_heads): super().__init__() self.num_heads = num_heads self.dk = d_model // num_heads # 每个头的维度 self.Wq = nn.Linear(d_model, d_model) self.Wk = nn.Linear(d_model, d_model) self.Wv = nn.Linear(d_model, d_model) self.Wo = nn.Linear(d_model, d_model) def forward(self, x): B, T, D = x.shape h = self.num_heads # 投影后 reshape 成多头：[B, T, D] → [B, h, T, dk] Q = self.Wq(x).view(B, T, h, self.dk).transpose(1, 2) K = self.Wk(x).view(B, T, h, self.dk).transpose(1, 2) V = self.Wv(x).view(B, T, h, self.dk).transpose(1, 2) # 每个头独立做 Attention score = (Q @ K.transpose(-2, -1)) / (self.dk ** 0.5) attn = F.softmax(score, dim=-1) # [B, h, T, T] out = attn @ V # [B, h, T, dk] # 拼接所有头：[B, h, T, dk] → [B, T, D] out = out.transpose(1, 2).contiguous().view(B, T, D) return self.Wo(out) 3.4 实际模型中的 Multi-Head 主流 Transformer 模型普遍使用 8~16 个 head。比如 BERT-base 用 12 个 head（d_model=768，每个 head 的 dk=64），GPT-2 同样是 12 个 head（d_model=768）。更大的模型如 GPT-3 用了 96 个 head。多头数量的选择需要平衡表达能力和计算开销。\n四、Positional Encoding（位置编码） 4.1 为什么需要位置编码？ Self-Attention 本身是排列不变的（permutation invariant）——打乱输入顺序，输出也只是对应打乱，不会改变每个 token 的值。但语言有顺序：\u0026ldquo;狗咬人\u0026quot;和\u0026quot;人咬狗\u0026quot;意思完全不同。\nSelf-Attention 看到的： {狗, 咬, 人} → 一个无序集合，不知道谁在前谁在后 加了位置编码后： {狗+pos0, 咬+pos1, 人+pos2} → 现在知道顺序了 4.2 常见的位置编码方案 方案一：正弦/余弦固定编码（原始 Transformer 论文）\n用不同频率的正弦和余弦函数为每个位置生成唯一的编码向量。优点是可以外推到训练时没见过的更长序列。\n方案二：可学习的位置编码（GPT、BERT、CLIP 等）\n直接把位置编码当作可训练参数，让模型自己学出最优的位置表示：\n1 2 3 4 5 6 7 8 9 10 # 可学习位置编码（简化版） self.positional_embedding = nn.Parameter( torch.randn(max_seq_len, d_model) # 可学习的，如 shape [512, 768] ) def forward(self, tokens): x = self.token_embedding(tokens) # [T, d_model] x = x + self.positional_embedding[:T] # 加上位置信息 x = self.transformer(x) return x 目前大多数模型使用可学习位置编码，因为它在固定长度输入上效果更好。\n4.3 位置编码为什么重要？ 一个直观的例子：\u0026quot;狗咬人\u0026quot; 和 \u0026quot;人咬狗\u0026quot; 用了完全相同的三个 token，但语义截然不同。没有位置编码，Self-Attention 无法区分这两个句子。\n位置编码还影响模型对特殊 token 的处理。比如 BERT 把 [CLS] 放在位置 0，模型通过位置编码\u0026quot;知道\u0026quot;这个 token 的角色是汇聚全句信息；如果把 [CLS] 挪到中间，模型的行为会完全不同。\n五、Transformer 完整架构 5.1 Encoder Block（编码器块） 这是 Transformer Encoder 的核心单元（BERT、ViT 等模型的基本构件），一个 Encoder Block 包含：\n输入 x ↓ [Multi-Head Attention] → 让每个 token 融合其他 token 的信息 ↓ + x（残差连接） [Layer Normalization] → 稳定训练 ↓ [Feed-Forward Network] → 两层 MLP，增加非线性 ↓ + x（残差连接） [Layer Normalization] ↓ 输出 5.2 两个关键组件详解 残差连接（Residual Connection）：\n1 2 3 4 5 6 # 不加残差：信息逐层丢失 x = attention(x) # 加残差：保留原始信息 + 新信息 x = x + attention(x) # 类比：考试时不仅写新学的，也保留已有知识 Layer Normalization：\n1 2 3 4 5 6 7 8 9 # 对每个样本的特征维度做归一化（注意：不是 Batch Norm） def layer_norm(x): mean = x.mean(dim=-1, keepdim=True) std = x.std(dim=-1, keepdim=True) return (x - mean) / (std + 1e-8) # 为什么用 LayerNorm 而不是 BatchNorm？ # 因为序列长度不固定，BatchNorm（对 batch 维度归一化）不适用 # LayerNorm 对每个样本独立归一化，不受 batch 中其他样本影响 Feed-Forward Network（FFN）：\n1 2 3 4 5 6 7 8 9 10 class FFN(nn.Module): def __init__(self, d_model, d_ff): super().__init__() # 两层 MLP：先升维，再降维 self.fc1 = nn.Linear(d_model, d_ff) # 512 → 2048 self.fc2 = nn.Linear(d_ff, d_model) # 2048 → 512 self.activation = nn.GELU() # 现代 Transformer 常用 GELU 激活 def forward(self, x): return self.fc2(self.activation(self.fc1(x))) 5.3 完整 Transformer Encoder 伪代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 class TransformerEncoderBlock(nn.Module): def __init__(self, d_model=512, num_heads=8, d_ff=2048, dropout=0.1): super().__init__() self.attn = MultiHeadAttention(d_model, num_heads) self.ffn = FFN(d_model, d_ff) self.norm1 = nn.LayerNorm(d_model) self.norm2 = nn.LayerNorm(d_model) self.dropout = nn.Dropout(dropout) def forward(self, x): # Sub-layer 1: Multi-Head Attention + 残差 + LayerNorm attn_out = self.attn(x) x = self.norm1(x + self.dropout(attn_out)) # Sub-layer 2: FFN + 残差 + LayerNorm ffn_out = self.ffn(x) x = self.norm2(x + self.dropout(ffn_out)) return x class TransformerEncoder(nn.Module): def __init__(self, num_layers=12, d_model=512, num_heads=8): super().__init__() self.layers = nn.ModuleList([ TransformerEncoderBlock(d_model, num_heads) for _ in range(num_layers) ]) def forward(self, x): for layer in self.layers: x = layer(x) return x 六、Seq2seq 框架总览（对应 slides p2, p15） Transformer 最初是为 Seq2seq（Sequence-to-sequence） 任务设计的：输入一个序列，输出另一个序列，且输出长度由模型自己决定。\n典型 Seq2seq 应用（slides p2）： 机器翻译：\u0026#34;I love learning\u0026#34; [3词] → \u0026#34;我爱学习\u0026#34; [4字] 输入输出长度不同 文本摘要：一篇 500 字的文章 → 50 字的摘要 对话系统：用户问题 → 系统回答 Seq2seq 的核心架构就是 Encoder + Decoder（slides p15）：\n输入序列 → [Encoder] → 隐层表示 → [Decoder] → 输出序列 Encoder：理解输入（\u0026#34;读题\u0026#34;） Decoder：生成输出（\u0026#34;答题\u0026#34;） 三种主流架构：理解 Encoder 和 Decoder 的区别后，就能理解当前主流模型的架构选择：\nEncoder-only（BERT、ViT）：只用 Encoder，适合理解类任务（分类、特征提取） Decoder-only（GPT 系列）：只用 Decoder（带 Masked Self-Attention），适合生成类任务 Encoder-Decoder（原始 Transformer、T5、BART）：完整架构，适合序列到序列任务（翻译、摘要） 七、Decoder — Autoregressive 生成（对应 slides p23-34） 7.1 什么是 Autoregressive（自回归）？ Decoder 生成输出时是一个一个地生成，每次生成一个 token，然后把这个 token 作为下一步的输入，如此循环（slides p24-25）。\n以机器翻译 \u0026#34;I love learning\u0026#34; → \u0026#34;我爱学习\u0026#34; 为例（slides p24-25）： 第1步：输入 START token → Decoder → 输出概率分布 → argmax → \u0026#34;我\u0026#34; 第2步：输入 START + \u0026#34;我\u0026#34; → Decoder → 输出概率分布 → argmax → \u0026#34;爱\u0026#34; 第3步：输入 START + \u0026#34;我\u0026#34; + \u0026#34;爱\u0026#34; → Decoder → argmax → \u0026#34;学\u0026#34; 第4步：输入 START + \u0026#34;我\u0026#34; + \u0026#34;爱\u0026#34; + \u0026#34;学\u0026#34; → Decoder → argmax → \u0026#34;习\u0026#34; 第5步：输入 START + \u0026#34;我\u0026#34; + \u0026#34;爱\u0026#34; + \u0026#34;学\u0026#34; + \u0026#34;习\u0026#34; → Decoder → argmax → END 输出 END 后停止生成（slides p33-34） 生活类比：Autoregressive 像写作文——你先写第一个字，看了第一个字才写第二个字，看了前两个字才写第三个字。每个字都依赖前面所有已写的字。\n7.2 错误传播问题（slides p30） Autoregressive 有一个致命弱点：如果某一步生成错了，后面所有步都会被带偏。\n正确路径：START → 我 → 爱 → 学 → 习 → END 错误路径：START → 我 → 受（错！）→ 学 → 习 → ... \u0026#34;受\u0026#34;是错的，但 Decoder 会把\u0026#34;受\u0026#34;当成正确输入继续生成 → 一步错，步步错（error propagation） 这也是后面 Teacher Forcing 要解决的问题。\n7.3 如何停下来？— END Token（slides p33-34） Decoder 不知道应该输出多长的序列。解法是在词汇表里加一个特殊 token END（或 \u0026lt;EOS\u0026gt;）。当 Decoder 输出 END 时，生成结束。\n1 2 3 4 5 6 7 8 9 10 # Autoregressive 推理伪代码 def autoregressive_decode(encoder_output, max_len=100): tokens = [START_TOKEN] for _ in range(max_len): logits = decoder(tokens, encoder_output) # 输入已有 tokens next_token = logits[-1].argmax() # 取最后位置的预测 if next_token == END_TOKEN: break tokens.append(next_token) return tokens 7.4 AT vs NAT（slides p36） 类型 全称 生成方式 优缺点 AT Autoregressive 逐个生成，每步依赖前一步 质量高但速度慢 NAT Non-autoregressive 一次性并行生成所有 token 速度快但质量通常较差 CLIP 文本端和 GPT 都是 AT 风格。NAT 了解即可，目前主流生成模型基本都用 AT。\n八、Masked Self-Attention（对应 slides p27-29） 8.1 为什么需要 Mask？ 回顾 Encoder 的 Self-Attention：每个 token 可以看到序列中所有 token（包括后面的）。但 Decoder 在生成时，还没生成的 token 不应该被看到——你写第 2 个字的时候，第 3 个字还没写出来，不可能参考它。\nEncoder Self-Attention（双向，无 mask）： 计算 b2 时：看 a1, a2, a3, a4 全部 Decoder Masked Self-Attention（单向，有 mask）： 计算 b2 时：只看 a1, a2（不能看 a3, a4） 8.2 Mask 是怎么实现的？（slides p29） 在计算 Attention Score 之后、Softmax 之前，把不应该看到的位置设为 负无穷，Softmax 后这些位置的权重就变成 0。\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 def masked_self_attention(Q, K, V, mask): \u0026#34;\u0026#34;\u0026#34; mask: 上三角为 True 的布尔矩阵，True 的位置表示\u0026#34;不能看\u0026#34; \u0026#34;\u0026#34;\u0026#34; score = Q @ K.transpose(-2, -1) / (dk ** 0.5) # [T, T] # 关键一步：把未来位置设为负无穷 score = score.masked_fill(mask, float(\u0026#39;-inf\u0026#39;)) # 未来位置 → -∞ attn = F.softmax(score, dim=-1) # -∞ 经过 softmax → 0 output = attn @ V return output # 生成 causal mask（下三角为 False，上三角为 True） T = 4 mask = torch.triu(torch.ones(T, T), diagonal=1).bool() # mask = [[False, True, True, True ], # [False, False, True, True ], # [False, False, False, True ], # [False, False, False, False]] 8.3 Mask 后的 Attention 矩阵长什么样？ 原始 Attention Score（Softmax 前）： t1 t2 t3 t4 t1 [ 0.8 0.3 0.5 0.1 ] t2 [ 0.2 0.9 0.4 0.6 ] t3 [ 0.3 0.7 0.8 0.2 ] t4 [ 0.1 0.5 0.3 0.9 ] Mask 后（上三角变 -∞）： t1 t2 t3 t4 t1 [ 0.8 -∞ -∞ -∞ ] ← t1 只能看自己 t2 [ 0.2 0.9 -∞ -∞ ] ← t2 看 t1 和自己 t3 [ 0.3 0.7 0.8 -∞ ] ← t3 看 t1, t2, 自己 t4 [ 0.1 0.5 0.3 0.9 ] ← t4 看所有 Softmax 后（-∞ → 0，每行和为 1）： t1 t2 t3 t4 t1 [ 1.0 0.0 0.0 0.0 ] t2 [ 0.33 0.67 0.0 0.0 ] t3 [ 0.19 0.29 0.52 0.0 ] t4 [ 0.11 0.26 0.17 0.46] 8.4 Masked Attention 的实际意义 GPT 系列就用了 Masked Self-Attention。这意味着在文本生成时，模型只能根据已生成的内容预测下一个 token：\n生成句子 \u0026#34;今天天气真好\u0026#34;： 在 Masked Self-Attention 中： \u0026#34;今\u0026#34; 只能看到自己 \u0026#34;天\u0026#34; 能看到 \u0026#34;今\u0026#34; 和自己 \u0026#34;天\u0026#34; 能看到 \u0026#34;今\u0026#34;, \u0026#34;天\u0026#34; 和自己 \u0026#34;气\u0026#34; 能看到 \u0026#34;今\u0026#34;, \u0026#34;天\u0026#34;, \u0026#34;天\u0026#34; 和自己 \u0026#34;真\u0026#34; 能看到前面所有 token \u0026#34;好\u0026#34; 能看到前面所有 token ← 融合了整个句子的信息 所以 Decoder-only 模型（如 GPT）取最后一个 token 的输出做预测 因为只有最后位置融合了前面所有 token 的信息 这也解释了为什么 GPT 风格的模型在生成任务上很强——Masked Attention 天然适配从左到右的自回归生成。而 BERT 用的是双向 Attention（无 mask），更适合理解类任务。\n九、Cross Attention — Encoder-Decoder 的桥梁（对应 slides p39-43） 9.1 Cross Attention 是什么？ Cross Attention 是连接 Encoder 和 Decoder 的机制。在 Decoder 的每一层中，除了 Masked Self-Attention，还有一个 Cross Attention 模块，用来\u0026quot;查看\u0026rdquo; Encoder 的输出。\nDecoder 一层的完整流程（slides p39 架构图）： 输入（已生成的 token） ↓ [Masked Self-Attention] → Decoder 内部的 token 互相交流 ↓ + 残差 + LayerNorm [Cross Attention] → Decoder 向 Encoder \u0026#34;提问\u0026#34; ↓ + 残差 + LayerNorm [FFN] → 非线性变换 ↓ + 残差 + LayerNorm 输出 9.2 Cross Attention 的 Q/K/V 来自哪里？（slides p40-41） 这是 Cross Attention 和 Self-Attention 的关键区别：\nSelf-Attention: Q, K, V 全部来自同一个输入 Cross Attention: Q 来自 Decoder，K 和 V 来自 Encoder 具体来说（slides p40）： Encoder 输出 → 生成 K 和 V（\u0026#34;信息提供方\u0026#34;） Decoder 当前层输出 → 生成 Q（\u0026#34;信息查询方\u0026#34;） q = Decoder_output @ Wq # Decoder 在问：\u0026#34;我现在需要什么信息？\u0026#34; k1, k2, k3 = Encoder_out @ Wk # Encoder 在说：\u0026#34;我这里有这些信息\u0026#34; v1, v2, v3 = Encoder_out @ Wv # Encoder 的实际信息内容 attn_score = q @ [k1, k2, k3]^T # 算 Decoder 和 Encoder 各位置的相关性 output = softmax(attn_score) @ [v1, v2, v3] # 加权提取 Encoder 的信息 9.3 PyTorch 伪代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 class CrossAttention(nn.Module): def __init__(self, d_model, num_heads): super().__init__() self.Wq = nn.Linear(d_model, d_model) # Q 来自 Decoder self.Wk = nn.Linear(d_model, d_model) # K 来自 Encoder self.Wv = nn.Linear(d_model, d_model) # V 来自 Encoder self.Wo = nn.Linear(d_model, d_model) self.dk = d_model // num_heads def forward(self, decoder_hidden, encoder_output): \u0026#34;\u0026#34;\u0026#34; decoder_hidden: Decoder 当前层的输出 [B, T_dec, D] encoder_output: Encoder 最终输出 [B, T_enc, D] \u0026#34;\u0026#34;\u0026#34; Q = self.Wq(decoder_hidden) # [B, T_dec, D] — 来自 Decoder K = self.Wk(encoder_output) # [B, T_enc, D] — 来自 Encoder V = self.Wv(encoder_output) # [B, T_enc, D] — 来自 Encoder # Q 和 K 的维度不同：T_dec × T_enc score = Q @ K.transpose(-2, -1) / (self.dk ** 0.5) # [B, T_dec, T_enc] attn = F.softmax(score, dim=-1) output = attn @ V # [B, T_dec, D] return self.Wo(output) 9.4 生活类比 Cross Attention 就像开卷考试：Encoder 是你的参考资料（课本），Decoder 是你在写答案。每写一个字（Decoder），你都会回头翻参考资料（Encoder），找到和当前最相关的内容，提取出来辅助你写下一个字。\n9.5 Cross Attention 的典型应用 Cross Attention 在以下场景中广泛使用：\n机器翻译：Decoder 生成目标语言时，通过 Cross Attention 查看源语言的 Encoder 输出 文本摘要：Decoder 生成摘要时，回看原文的编码表示 多模态模型：文本和图像之间的信息交互（如 Stable Diffusion 中文本条件引导图像生成） 注意，并非所有 Transformer 模型都有 Cross Attention。Encoder-only 模型（BERT）和 Decoder-only 模型（GPT）都没有 Cross Attention，只有完整的 Encoder-Decoder 架构才需要它。\n十、Training — Teacher Forcing（对应 slides p45-46） 10.1 训练时的一个关键问题 推理时，Decoder 用自己上一步的输出作为下一步的输入（Autoregressive）。但训练时如果也这样做，一旦早期输出错误，后面的训练信号全部被污染。\n10.2 Teacher Forcing 的解法（slides p46） 训练时不用 Decoder 自己的输出，而是**直接喂正确答案（Ground Truth）**作为输入：\n推理时（Autoregressive，用自己的输出）： START → Decoder → \u0026#34;我\u0026#34; → Decoder → \u0026#34;爱\u0026#34; → Decoder → \u0026#34;学\u0026#34; → ... 如果第2步输出了\u0026#34;受\u0026#34;而不是\u0026#34;爱\u0026#34;，后面全部出错 训练时（Teacher Forcing，用 Ground Truth）： 输入：START, 我, 爱, 学 ← 全部是正确答案 目标：我, 爱, 学, 习, END ← 每个位置的监督信号 不管 Decoder 预测对不对，下一步的输入始终是正确的 → 每个位置都能得到准确的梯度信号 10.3 PyTorch 伪代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 def train_step(encoder_output, target_sequence): \u0026#34;\u0026#34;\u0026#34; target_sequence: [我, 爱, 学, 习]（Ground Truth） \u0026#34;\u0026#34;\u0026#34; # 构造 Decoder 输入：在 target 前面加 START decoder_input = torch.cat([START_TOKEN, target_sequence[:-1]]) # decoder_input = [START, 我, 爱, 学] # 构造标签：target 后面加 END labels = torch.cat([target_sequence, END_TOKEN]) # labels = [我, 爱, 学, 习, END] # Decoder 一次性处理所有位置（因为 Mask 保证每个位置只看前面的） logits = decoder(decoder_input, encoder_output) # [T, vocab_size] # 每个位置都算 cross entropy loss = F.cross_entropy(logits, labels) return loss 10.4 Exposure Bias（slides p56） Teacher Forcing 有一个副作用叫 Exposure Bias：训练时 Decoder 总是看到正确的输入，但推理时看到的是自己（可能错误的）输出。训练和推理的\u0026quot;曝光\u0026quot;不一致。\n训练时：Decoder 看到的 = Ground Truth（完美输入） 推理时：Decoder 看到的 = 自己的输出（可能有错） → 模型从未在训练中见过\u0026#34;错误输入\u0026#34;的情况 → 一旦推理时出错，模型不知道如何纠正 解法之一是 Scheduled Sampling（slides p57）：训练时以一定概率用模型自己的输出代替 Ground Truth，让模型逐渐适应\u0026quot;不完美输入\u0026quot;。\n十一、完整 Transformer Decoder Block 11.1 结构（综合 slides p26-27） 一个 Decoder Block 比 Encoder Block 多一层 Cross Attention：\n输入（已生成 token 的 embedding + Positional Encoding） ↓ [Masked Multi-Head Self-Attention] ← 只看已生成的部分 ↓ + 残差 + LayerNorm [Cross Multi-Head Attention] ← Q 来自 Decoder，K/V 来自 Encoder ↓ + 残差 + LayerNorm [Feed-Forward Network] ↓ + 残差 + LayerNorm 输出 11.2 PyTorch 伪代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 class TransformerDecoderBlock(nn.Module): def __init__(self, d_model=512, num_heads=8, d_ff=2048): super().__init__() self.masked_attn = MultiHeadAttention(d_model, num_heads) self.cross_attn = CrossAttention(d_model, num_heads) self.ffn = FFN(d_model, d_ff) self.norm1 = nn.LayerNorm(d_model) self.norm2 = nn.LayerNorm(d_model) self.norm3 = nn.LayerNorm(d_model) def forward(self, x, encoder_output, causal_mask): # Sub-layer 1: Masked Self-Attention（只看前面的 token） attn_out = self.masked_attn(x, mask=causal_mask) x = self.norm1(x + attn_out) # Sub-layer 2: Cross Attention（查看 Encoder 的输出） cross_out = self.cross_attn(decoder_hidden=x, encoder_output=encoder_output) x = self.norm2(x + cross_out) # Sub-layer 3: FFN ffn_out = self.ffn(x) x = self.norm3(x + ffn_out) return x 11.3 Encoder vs Decoder 对比总结 特性 Encoder Decoder Self-Attention 类型 双向（看所有 token） Masked（只看前面的 token） Cross Attention 无 有（Q 来自 Decoder，K/V 来自 Encoder） 生成方式 一次处理所有输入 Autoregressive，逐个生成 训练技巧 标准监督学习 Teacher Forcing 典型用途 BERT、ViT、特征提取 GPT、文本生成 代表模型 BERT、ViT GPT 系列 GPT 的特殊性：GPT 虽然常被称为\u0026quot;语言模型\u0026quot;，但架构上就是 Decoder-only Transformer（有 Masked Self-Attention，没有 Cross Attention）。它不需要 Encoder，因为任务本身就是\u0026quot;根据前文生成下一个 token\u0026quot;。\n完整 Encoder-Decoder（如机器翻译）： Masked Self-Attention → Cross Attention → FFN GPT（Decoder-only）： Masked Self-Attention → FFN （没有 Cross Attention） → 因此 GPT 是\u0026#34;只有 Self-Attention 的 Decoder\u0026#34; 十二、Transformer 变体与实际应用 学完 Encoder 和 Decoder 后，可以理解当前主流模型的架构选择逻辑。\n12.1 Encoder-only：BERT BERT 只用 Encoder（双向 Self-Attention），每个 token 都能看到序列中所有其他 token。这使得 BERT 擅长理解类任务——分类、命名实体识别、问答中的答案抽取。\n输入：[CLS] I love this movie [SEP] 双向 Attention：每个 token 都能看到所有其他 token → [CLS] 位置的输出融合了整个句子的信息 → 用 [CLS] 的输出接一个分类头，就能做情感分类 12.2 Decoder-only：GPT GPT 只用 Decoder（Masked Self-Attention），每个 token 只能看到前面的 token。这天然适配从左到右的文本生成。\n输入：\u0026#34;今天天气\u0026#34; → \u0026#34;今\u0026#34; 只看自己 → \u0026#34;天\u0026#34; 看 \u0026#34;今\u0026#34; 和自己 → \u0026#34;天\u0026#34; 看 \u0026#34;今天\u0026#34; 和自己 → \u0026#34;气\u0026#34; 看 \u0026#34;今天天\u0026#34; 和自己 → 预测下一个 token：\u0026#34;真\u0026#34; GPT 系列从 GPT-1 到 GPT-4 都是这个架构，区别只在模型规模和训练数据。\n12.3 Encoder-Decoder：T5、BART 完整的 Encoder-Decoder 架构适合输入和输出都是序列、且长度不同的任务：翻译、摘要、问答生成。Encoder 负责理解输入，Decoder 通过 Cross Attention 查看 Encoder 的输出来生成目标序列。\nT5 的设计哲学是\u0026quot;把所有 NLP 任务都转化为 text-to-text 格式\u0026quot;，统一用 Encoder-Decoder 处理。\n十三、核心概念速查表 概念 一句话解释 典型应用 / 为什么重要 Self-Attention 序列中每个 token 和所有 token 计算相关性并融合信息 所有 Transformer 模型的核心操作 Q/K/V 查询/钥匙/值，三组线性变换 每层 Transformer 都有 Scaled Dot-Product 除以 √dk 防止梯度消失 保证 softmax 输出不会过于集中 Multi-Head 多组 Q/K/V 并行，捕捉不同关系 BERT/GPT 用 12 个 head，大模型用更多 Positional Encoding 给 token 加上位置信息 没有它 Self-Attention 无法区分词序 Residual Connection 输出 = 原始输入 + 变换后的输入 确保深层 Transformer 能训练 Layer Normalization 对每个样本独立归一化 每个 Block 里有两或三个 FFN 两层 MLP，先升维再降维 提供非线性变换能力 Masked Self-Attention 每个 token 只能看到自己和前面的 token GPT 等生成模型的核心机制 Cross Attention Q 来自 Decoder，K/V 来自 Encoder 机器翻译等 Seq2seq 任务的桥梁 Autoregressive 逐个生成 token，每步依赖前一步 GPT 文本生成、机器翻译的 Decoder Teacher Forcing 训练时用 Ground Truth 而非模型输出作为输入 Decoder 训练的标准做法 Exposure Bias 训练用真实输入 vs 推理用模型输出的不一致 Scheduled Sampling 可缓解 [EOS] / [SEP] Token 序列末尾的特殊 token Decoder-only 模型取最后位置做语义表示 END Token 告诉 Decoder 停止生成的信号 Autoregressive 生成的终止条件 十四、学习检查清单 完成以下问题即代表掌握（新增 Decoder 相关项用 ★ 标注）：\n给定 Q、K、V 矩阵，能手算 Attention 输出 理解为什么要除以 √dk 能解释 Multi-Head 的好处 知道 Positional Encoding 的必要性 能画出一个 Transformer Encoder Block 的结构 ★ 能画出一个 Transformer Decoder Block 的结构（比 Encoder 多了什么？） ★ 能解释 Masked Self-Attention 的 mask 是怎么实现的（负无穷 → softmax → 0） ★ 能区分 Self-Attention 和 Cross Attention 的 Q/K/V 来源 ★ 能解释 Autoregressive 生成的流程和 END token 的作用 ★ 能解释 Teacher Forcing 的目的和 Exposure Bias 问题 能解释 Decoder-only 模型（GPT）为什么取最后位置的输出做预测 能区分 BERT（Encoder-only）和 GPT（Decoder-only）的架构差异及适用场景 十五、推荐学习顺序 先看 Self-Attention（上） → 理解 Q/K/V 和 Attention Score 再看 Self-Attention（下） → 理解 Multi-Head 和位置编码 然后看 Transformer（上） → 理解 Encoder 完整架构 最后看 Transformer（下） → 理解 Decoder、Cross Attention、Teacher Forcing 动手实践：用 Hugging Face Transformers 库跑一个预训练模型（如 BERT 做文本分类），把学到的架构知识和实际代码对应起来 视频链接：\nSelf-Attention（上）：https://youtu.be/hYdO9CscNes Self-Attention（下）：https://youtu.be/gmsMY5kc-zw Transformer（上）：https://youtu.be/n9TlOhRjYoc Transformer（下）：https://youtu.be/N6aRv06iv2g ","permalink":"https://ardenj.pages.dev/learning/transformer/","summary":"\u003ch2 id=\"一为什么要学-transformer\"\u003e一、为什么要学 Transformer？\u003c/h2\u003e\n\u003cp\u003eTransformer 是当前深度学习的基础架构。NLP 领域的 BERT、GPT 系列，计算机视觉的 ViT，多模态模型 CLIP、Stable Diffusion——底层全是 Transformer。不理解 Transformer，后续读任何相关论文都会卡在架构细节上。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e学完本笔记后，应该能回答\u003c/strong\u003e：Q/K/V 怎么算？Multi-Head 为什么有用？Positional Encoding 干什么的？Encoder 和 Decoder 有什么区别？\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"二self-attention自注意力机制\"\u003e二、Self-Attention（自注意力机制）\u003c/h2\u003e\n\u003ch3 id=\"21-核心问题如何处理变长序列\"\u003e2.1 核心问题：如何处理变长序列？\u003c/h3\u003e\n\u003cp\u003e输入可能是一句话（5个词）、一段语音（200帧）、一张图（196个patch），长度不固定。传统 FC 层要求固定输入维度，无法处理这种情况。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e生活类比\u003c/strong\u003e：你在教室里坐着，老师点名提问。FC 层相当于老师只看你一个人；Self-Attention 相当于老师让全班每个人都互相看一眼，综合所有人的信息后再做判断。\u003c/p\u003e\n\u003ch3 id=\"22-self-attention-的计算流程\"\u003e2.2 Self-Attention 的计算流程\u003c/h3\u003e\n\u003cp\u003e假设输入序列有 T 个 token，每个 token 是一个 d 维向量：\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e输入：X = [x₁, x₂, ..., xT]，shape = [T, d]\n\n第1步：生成 Q, K, V（三个\u0026#34;角色\u0026#34;）\n  Q = X @ Wq    # Query: \u0026#34;我在找什么？\u0026#34;    shape = [T, dk]\n  K = X @ Wk    # Key:   \u0026#34;我能提供什么？\u0026#34;  shape = [T, dk]\n  V = X @ Wv    # Value: \u0026#34;我的实际内容\u0026#34;    shape = [T, dv]\n\n第2步：算 Attention Score（谁和谁最相关？）\n  Score = Q @ K^T          # shape = [T, T]，每对 token 之间的相关性\n  Score = Score / √dk      # 缩放，防止数值过大导致 softmax 梯度消失\n\n第3步：Softmax 归一化\n  Attention = softmax(Score, dim=-1)   # 每行和为1，变成概率分布\n\n第4步：加权求和\n  Output = Attention @ V    # shape = [T, dv]\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cstrong\u003e生活类比\u003c/strong\u003e：\u003c/p\u003e","title":"Self-Attention \u0026 Transformer 学习笔记"},{"content":"确定方向后第一篇论文精读笔记，随看随做。\n第一遍 Abstract 在图像识别领域，传统做法是用视觉模型提取图像特征，然后匹配一组随机初始化的固定权重向量（每个类别一个向量），这些权重就代表视觉概念。而这就存在一个缺陷：这些向量只是数字，没有语义信息，如“狗”、“猫”、“飞机”在模型眼中只是01、02、03，而无法意识到狗和猫比狗和飞机在语义上更接近。\n这就引出了作者的一个发现：像 CLIP 这样的大型预训练视觉-语言模型在学习可跨越广泛下游任务迁移的表示方面展现了巨大潜力。每个类别不再是数字编号，而是一段自然语言描述（\u0026ldquo;a photo of a dog\u0026rdquo;）。模型学到的是图像和文本在共享语义空间里的对齐关系。\nCoOp 论文想表达的核心对比：正因为 CLIP 用了语言监督而非离散标签，它学到的表征空间天然更 transferable（可迁移）。但要用好这个能力，你得写对 prompt——这就引出了 CoOp 的研究动机：让机器自己学 prompt，别靠人手写。\nIntroduction 传统视觉模型无法较好泛化，模型将“一只猫”，“一只狗”替换为编号，很大程度上丢失了文本语义信息，使其无法处理新类别，因为学习新分类器需要额外的数据。\n最近，视觉-语言预训练成为有前景的一个方向，但提示词工程要求极其玄学的输入，一个词语的增删都会对结果造成显著影响。实验人员需要广泛的测试提示词，造成效率极其低下。\n所以，作者从提示学习（NLP）中找到灵感，提出一种简单方法：上下文优化（context optimization，简称CoOp）\nconclusion 大致意思就是这个实验方向很新，效果很不错，还有很多地方可以细化展开，我们的文章主要做为一个引入。\n第二遍阅读 CLIP是本文绕不开的一个话题。CLIP是openAI发布的开源模型，关联了图像和文字。我主要介绍两个概念：\n特征空间：对于计算机来说，它是无法真正识别图像和文字的，我们需要将他们转换成一串数字（向量）。特征空间就是一个 512 维的数学坐标系，图像和文字都会被转换成这512维的向量，如果一张图片和一串文字在这个坐标系里算出来的距离很近（点积很大），那就说明他们成功匹配了。有趣的是，人类并不知道这512维每一个维度代表什么，这些都是模型在训练中自己决定的。\n编码器（Encoder）：\n图像编码器：输入一张图片，输出一串512维的向量。 文字编码器：输入一句话，输出一串512维的向量。 在CLIP出来之前，CV和NLP之间有巨大的鸿沟。openAI通过4亿对图片与文字进行对比学习，最后训练出CLIP，完美对齐了视觉和语义。\n具体实验流程不放了，下面进入复现\n复现代码 第一次尝试复现代码，流程实在是繁琐。首先下载代码后需要进行环境配置，环境配置好后，需要下载数据集。数据集需要放入指定文件夹，然后在脚本中修改路径。这两步用copilot可以快速完成。\n太tm难复现了这代码，到此为止。。。（3.12记） ","permalink":"https://ardenj.pages.dev/learning/coop_persual/","summary":"\u003cp\u003e确定方向后第一篇论文精读笔记，随看随做。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"第一遍\"\u003e第一遍\u003c/h2\u003e\n\u003ch3 id=\"abstract\"\u003eAbstract\u003c/h3\u003e\n\u003cp\u003e在图像识别领域，传统做法是用视觉模型提取图像特征，然后匹配一组随机初始化的固定权重向量（每个类别一个向量），这些权重就代表视觉概念。而这就存在一个缺陷：这些向量只是数字，没有语义信息，如“狗”、“猫”、“飞机”在模型眼中只是01、02、03，而无法意识到狗和猫比狗和飞机在语义上更接近。\u003c/p\u003e\n\u003cp\u003e这就引出了作者的一个发现：像 CLIP 这样的大型预训练视觉-语言模型在学习可跨越广泛下游任务迁移的表示方面展现了巨大潜力。每个类别不再是数字编号，而是一段自然语言描述（\u0026ldquo;a photo of a dog\u0026rdquo;）。模型学到的是图像和文本在共享语义空间里的对齐关系。\u003c/p\u003e\n\u003cp\u003eCoOp 论文想表达的核心对比：正因为 CLIP 用了语言监督而非离散标签，它学到的表征空间天然更 transferable（可迁移）。但要用好这个能力，你得写对 prompt——这就引出了 CoOp 的研究动机：让机器自己学 prompt，别靠人手写。\u003c/p\u003e\n\u003ch3 id=\"introduction\"\u003eIntroduction\u003c/h3\u003e\n\u003cp\u003e传统视觉模型无法较好泛化，模型将“一只猫”，“一只狗”替换为编号，很大程度上丢失了文本语义信息，使其无法处理新类别，因为学习新分类器需要额外的数据。\u003c/p\u003e\n\u003cp\u003e最近，视觉-语言预训练成为有前景的一个方向，但提示词工程要求极其玄学的输入，一个词语的增删都会对结果造成显著影响。实验人员需要广泛的测试提示词，造成效率极其低下。\u003c/p\u003e\n\u003cp\u003e所以，作者从提示学习（NLP）中找到灵感，提出一种简单方法：上下文优化（context optimization，简称CoOp）\u003c/p\u003e\n\u003ch3 id=\"conclusion\"\u003econclusion\u003c/h3\u003e\n\u003cp\u003e大致意思就是这个实验方向很新，效果很不错，还有很多地方可以细化展开，我们的文章主要做为一个引入。\u003c/p\u003e\n\u003ch2 id=\"第二遍阅读\"\u003e第二遍阅读\u003c/h2\u003e\n\u003cp\u003eCLIP是本文绕不开的一个话题。CLIP是openAI发布的开源模型，关联了图像和文字。我主要介绍两个概念：\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e特征空间\u003c/strong\u003e：对于计算机来说，它是无法真正识别图像和文字的，我们需要将他们转换成一串数字（向量）。特征空间就是一个 512 维的数学坐标系，图像和文字都会被转换成这512维的向量，如果一张图片和一串文字在这个坐标系里算出来的距离很近（点积很大），那就说明他们成功匹配了。有趣的是，人类并不知道这512维每一个维度代表什么，这些都是模型在训练中自己决定的。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e编码器（Encoder）\u003c/strong\u003e：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e图像编码器：输入一张图片，输出一串512维的向量。\u003c/li\u003e\n\u003cli\u003e文字编码器：输入一句话，输出一串512维的向量。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e在CLIP出来之前，CV和NLP之间有巨大的鸿沟。openAI通过4亿对图片与文字进行对比学习，最后训练出CLIP，完美对齐了视觉和语义。\u003c/p\u003e\n\u003cp\u003e具体实验流程不放了，下面进入复现\u003c/p\u003e\n\u003ch2 id=\"复现代码\"\u003e复现代码\u003c/h2\u003e\n\u003cp\u003e第一次尝试复现代码，流程实在是繁琐。首先下载代码后需要进行环境配置，环境配置好后，需要下载数据集。数据集需要放入指定文件夹，然后在脚本中修改路径。这两步用copilot可以快速完成。\u003c/p\u003e\n\u003ch1 id=\"太tm难复现了这代码到此为止312记\"\u003e太tm难复现了这代码，到此为止。。。（3.12记）\u003c/h1\u003e","title":"FedDG阅读：Learning to Prompt for Vision-Language Models"},{"content":"全局视角：三篇\u0026quot;地基\u0026quot;论文 论文 定位 PromptFL（2023） 方向一的起点 Baseline，\u0026ldquo;联邦 Prompt 学习的 FedAvg\u0026rdquo; FedSR（NeurIPS 2022） 通用 FedDG Baseline，三个方向都必须比较的对象 SHOT（ICML 2020） 方向三的历史根源，Source-Free DA 的奠基之作 这三篇是\u0026quot;祖师爷\u0026quot;级别——必须理解，但后续工作要站在它们肩膀上，不是复现它们。\n方向一：CLIP / LLM + 联邦提示微调 入门论文 CoOp — Prompt Learning for Vision-Language Models 会议：IJCV 2022（原版 ICCV 2021）\n关键词：Soft Prompt, CLIP, Context Optimization\n读这篇是因为 PromptFL 本质上就是\u0026quot;把 CoOp 塞进联邦框架\u0026quot;，不懂 CoOp 就没法理解 PromptFL。\nCLIP 用\u0026quot;a photo of a [CLASS]\u0026ldquo;这样的手工文本做零样本分类，但手工模板很依赖玄学——换一句话描述，准确率可能差 10%。CoOp 的解决方案很直接：别手写模板，让模型自己学出来。\nSoft Prompt 的核心机制\n手工 Prompt（Hard Prompt）： 输入 → \u0026#34;a photo of a [cat]\u0026#34; → CLIP 文本编码 → 分类 Soft Prompt（CoOp 的做法）： 输入 → [v1][v2][v3][v4][cat] → CLIP 文本编码 → 分类 ↑ 这 4 个 [v] 不是文字，是可学习的浮点向量 训练时只更新这 4 个向量，CLIP 的其余参数全部冻结 Soft Prompt 就是在类别词前面拼几个可学习的浮点向量，训练时只更新这几个向量，CLIP 其余参数全部冻结。\n生活类比：CLIP 是一个很聪明但很挑食的翻译官，Soft Prompt 就是你摸索出的一套\u0026quot;最佳开场白\u0026rdquo;，每次跟翻译官说话前先念这串开场白，它就会以最利于你任务的方式工作。\n训练目标（PyTorch 伪代码）：\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 import torch import torch.nn as nn class CoOp(nn.Module): def __init__(self, clip_model, n_ctx=4, ctx_dim=512): super().__init__() # 只有这一个小矩阵是可训练的，其余全部 requires_grad=False self.ctx = nn.Parameter(torch.randn(n_ctx, ctx_dim)) self.clip = clip_model for p in self.clip.parameters(): p.requires_grad = False # CLIP 冻结 def forward(self, image, class_token): # class_token: [num_classes, ctx_dim]（预先编码好的类别词向量） # 把 soft prompt 拼在类别词前面 prompt = torch.cat([self.ctx.expand(len(class_token), -1, -1), class_token.unsqueeze(1)], dim=1) text_features = self.clip.encode_text(prompt) image_features = self.clip.encode_image(image) # 对比学习：让图像特征和对应类别的文本特征最近 logits = image_features @ text_features.T return logits CoOp 证明了 Soft Prompt 在单机场景有效。PromptFL 的核心贡献就是\u0026quot;把这个 ctx 向量的训练过程改成联邦聚合\u0026quot;——理解了这一点，下面这篇就很自然了。\nPromptFL — Let Federated Participants Cooperatively Learn Prompts Instead of Models 期刊：IEEE Transactions on Mobile Computing, 2023\n关键词：Federated Prompt Learning, Communication Efficiency\n读完 CoOp 之后接着读这篇。\n核心问题：标准联邦学习（FedAvg）每轮要同步整个模型的梯度，对 ViT-B/16 这种 86M 参数的大模型来说通信代价极高。PromptFL 的思路很简单：只让客户端训练 Soft Prompt，模型本身变成不动的\u0026quot;公共基础设施\u0026quot;。\n通信量差距有多大？\nFedAvg（同步全模型）： 每轮通信 = ResNet-50 全量参数 ≈ 25M × 32bit = 800MB/客户端/轮 PromptFL（只同步 Prompt）： 每轮通信 = 16 tokens × 512 dim = 8192个浮点数 ≈ 32KB/客户端/轮 压缩比：约 25000:1 联邦训练流程：\n1. 服务器广播：全局 Prompt 向量 ctx_global（极小） 2. 客户端本地： 用 ctx_global 初始化本地 ctx 在本地数据上训练 ctx（CLIP 全程冻结） 上传 ctx_grad（梯度，同样极小） 3. 服务器聚合：FedAvg(ctx_grad_1, ctx_grad_2, ...) → ctx_global 更新 4. 重复 PyTorch 联邦聚合伪代码：\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 # 服务器端 def fedavg_prompts(client_prompts, client_sizes): \u0026#34;\u0026#34;\u0026#34;client_prompts: list of [n_ctx, ctx_dim] tensors\u0026#34;\u0026#34;\u0026#34; total = sum(client_sizes) global_prompt = torch.zeros_like(client_prompts[0]) for prompt, size in zip(client_prompts, client_sizes): global_prompt += prompt * (size / total) return global_prompt # 客户端本地训练（核心只改了一行） optimizer = torch.optim.SGD([ctx], lr=0.002) # 只优化 ctx for x, y in local_dataloader: logits = model(x, ctx) # CLIP 不参与优化 loss = F.cross_entropy(logits, y) loss.backward() optimizer.step() PromptFL 的局限（后续工作要超越的地方）：\n所有客户端学出来的是同一个 Global Prompt，不区分客户端的域差异 没有考虑 Prompt 的跨域泛化性——在训练过的域上好，但遇到新域就不行 2023 年的工作，后续 CVPR/ICML 已经在此基础上叠了很多层 进阶阅读 论文 会议 一句话贡献 和我的关系 DiPrompT CVPR 2024 把 Prompt 解耦成\u0026quot;通用知识\u0026quot;和\u0026quot;域特有风格\u0026quot;两部分 直接 Baseline，需要超越 FedPGP ICML 2024 (arXiv:2405.09771) LoRA 风格个性化 Prompt + CLIP 泛化约束 理解个性化 vs. 泛化的 trade-off FedTPG ICLR 2024 文本驱动的 Prompt Generator，让 Prompt 能泛化到未见类别 Generator 思路可借鉴 FedDSPG arXiv 2025/09 (arXiv:2509.20807) 生成式视角：训练 Generator 为未见域动态生成 Prompt 最新 SOTA，找它的裂缝 FedMVP ICCV 2025 多模态（图像+属性）注入 Prompt，超越纯文本 Prompt 拓展视野用 PromptFL → DiPrompT → FedDSPG，三篇连起来看就能理解这个子方向的进化主线。\n方向二：机器人 Sim-to-Real + FedDG 入门论文 FedSR — A Simple and Effective Domain Generalization Method for Federated Learning 会议：NeurIPS 2022\n作者：A. Tuan Nguyen, Philip Torr, Ser-Nam Lim（牛津 + Meta AI）\n代码：github.com/atuannguyen/FedSR\n这是通用 FedDG Baseline，不是机器人专属——但方向二实验对比中必须出现它。\n核心问题：大多数联邦学习方法只关心在现有客户端上表现好，完全忽视\u0026quot;来了一个从没见过的新客户端（新域）该怎么办\u0026quot;。FedSR 把 Domain Generalization 的目标正式嫁接进联邦框架。\nFedSR 的核心思路：让表示\u0026quot;简单\u0026quot;\n普通深度学习的特征学习： 尽可能学到所有特征，包括域特有特征（光照、背景、噪声） → 在训练域上极好，在新域上灾难性失败 FedSR 的\u0026#34;简单表示\u0026#34;： 用信息瓶颈原则，只保留预测标签必要的特征，丢掉域特有噪声 → 泛化能力更强（因为学到的是本质特征） 两个核心正则化项：\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 def fesr_loss(z, y, z_dist, lambda_l2r=0.01, lambda_cmi=0.001): \u0026#34;\u0026#34;\u0026#34; z: 特征向量（encoder 输出） y: 标签 z_dist: 特征的概率分布（变分推断） \u0026#34;\u0026#34;\u0026#34; # 主损失：标准分类 ce_loss = F.cross_entropy(classifier(z), y) # 正则化1：L2 范数正则（让表示空间紧凑） l2r_loss = torch.norm(z, p=2, dim=1).mean() # 正则化2：条件互信息最小化（让特征只保留与 y 相关的信息） # I(X; Z | Y) → 最小化，用 ELBO 近似 cmi_loss = -z_dist.log_prob(z).mean() # KL 散度近似 total = ce_loss + lambda_l2r * l2r_loss + lambda_cmi * cmi_loss return total 生活类比：FedSR 就像考前只记最核心的知识点，不背偏题。每个学生（客户端）用自己的笔记学习，但大家都遵循\u0026quot;只记主干，不记杂枝\u0026quot;的原则，最后合并的全局模型在任何新考场（新域）都有基础分保底。\n为什么方向二必须用 FedSR 做 Baseline：它是学术界公认的 FedDG 通用 Baseline。论文如果不包含 FedSR 的比较结果，审稿人大概率会要求补充。它有官方开源代码，在 PACS/VLCS/Office-Home/DomainNet 上都有报告数字，可以直接拿来对比。\nSim-to-Real Transfer via Language（非联邦版原型） 会议：RSS 2024（Robotics: Science and Systems）\n关键词：CLIP semantic anchor, Sim-to-Real, Domain-invariant representation\n这篇是方向二 idea 的直接前身——无联邦版本的 CLIP 语义锚对齐。\n核心思路：仿真图和真实图长得完全不同，但它们描述的是同一个物理概念（\u0026ldquo;一个红色积木\u0026rdquo;）。CLIP 的文字端天然理解这些概念，因此可以作为\u0026quot;跨域语义锚点\u0026quot;。\n不用 CLIP： 仿真图特征 → [ResNet] → 向量 A ← 这两个向量差异极大 真实图特征 → [ResNet] → 向量 B ← 无法对齐 用 CLIP 文字锚： 仿真图特征 → [CLIP Image Enc] → 向量 A ─┐ ├─→ 都靠近\u0026#34;a red cube\u0026#34; 的文本向量 真实图特征 → [CLIP Image Enc] → 向量 B ─┘ 文字锚点 → [CLIP Text Enc] → 向量 T（\u0026#34;a red cube on a table\u0026#34;） 这篇论文的\u0026quot;裂缝\u0026quot;：它完全没有考虑联邦场景。多台机器人的数据如果放到同一台机器上做对齐，就违反了数据隐私原则。如何在各客户端数据不能共享的情况下，用 CLIP 文字端做分布式的语义锚对齐？——这就是方向二 idea 的切入点。\n进阶阅读 论文 会议 一句话贡献 和我的关系 gPerXAN CVPR 2024 个性化重组 BN 层过滤域偏见，论文直接提机器人应用 方向二专属 Baseline FedDG（Liu et al.） CVPR 2021 FedDG 开山之作：频域风格迁移生成跨域样本 理解数据操作分支的奠基逻辑 StableFDG NeurIPS 2023 风格+注意力双路联合联邦域泛化 参考数据增强策略 FedADG arXiv 2021 对抗联邦域对齐，用参考分布做分布匹配 理解域对齐分支的基本方法 VisDA-2017 数据集论文 arXiv 2017 152K 仿真 + 55K 真实，Sim-to-Real 标准 Benchmark 方向二的首选数据集 FedSR → gPerXAN → Sim2Real with Language，再看 FedDG (CVPR 2021) 了解数据操作分支的历史。\n方向三：Source-Free FedDG + 不确定性感知聚合（蔡老师主场） 入门论文 SHOT — Do We Really Need to Access the Source Data? 会议：ICML 2020\n作者：Liang et al.\n关键词：Source-Free DA, Pseudo-label, Information Maximization\nSource-Free Domain Adaptation 领域的开山之作，也是蔡老师方向的\u0026quot;祖师爷\u0026quot;。\n核心问题：传统域自适应（DA）假设源域数据和目标域数据同时可访问，但现实中源域数据往往因为隐私或版权被销毁。SHOT 首次提出：只用预训练好的源域模型 + 无标注目标域数据，能否完成自适应？\nSHOT 的两个核心 loss：\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 def shot_loss(features, pseudo_labels, predictions): \u0026#34;\u0026#34;\u0026#34; features: 目标域样本的特征向量 pseudo_labels: 模型自己预测出来的标签（高置信度样本才用） predictions: softmax 输出概率 \u0026#34;\u0026#34;\u0026#34; # 刀一：信息最大化（IM Loss） # 让模型预测：每个样本要确定（熵最小化） # 同时各类别要均匀（避免模型对所有样本都预测同一类） # 熵最小化：让每个样本的预测\u0026#34;集中\u0026#34;在一个类别 entropy_loss = -(predictions * torch.log(predictions + 1e-8)).sum(dim=1).mean() # 多样性最大化：让不同样本的预测类别尽量分散 mean_pred = predictions.mean(dim=0) # 批次内的平均预测分布 diversity_loss = (mean_pred * torch.log(mean_pred + 1e-8)).sum() # 最大化边际熵的负值 im_loss = entropy_loss + diversity_loss # 刀二：自监督伪标签（只用高置信度样本） pseudo_loss = F.cross_entropy(predictions, pseudo_labels) return im_loss + pseudo_loss 生活类比：SHOT 就像一个\u0026quot;只带毕业证书（模型）、没带过去卷子（源数据）\u0026ldquo;被调往新城市的医生。他的自适应策略是：先给所有病人快速诊断（生成伪标签），只相信自己最有把握的判断（高置信度），用这些判断来调整诊断风格（模型微调），同时确保诊断结果不会退化成\u0026quot;所有人都是感冒\u0026rdquo;（多样性约束）。\nSHOT 的历史地位：它是蔡老师研究链的\u0026quot;源头\u0026quot;。后续工作（如 UCon-SFDA）是在 SHOT 基础上，用更精确的不确定性建模来改进\u0026quot;如何判断哪些伪标签值得信任\u0026quot;这个核心问题。\n关键局限：SHOT 是单机版本，源数据销毁发生在单台机器上。如何把这个框架推广到多客户端的联邦设置？——这就是方向三的研究动机。\nFedWCA — Federated Source-Free Domain Adaptation via Weighted Cluster Aggregation 会议：WACV 2025\narXiv：arXiv:2412.13757\n关键词：Source-Free, Federated, Weighted Aggregation, Pseudo-label\n目前最接近方向三 idea 的前驱论文，也是最直接的超越对象。\nFedWCA 把 Source-Free DA 真正搬进了联邦框架，并提出了第一个有理论支撑的联邦加权聚合方法。\n三阶段流程：\n阶段一：各客户端私有聚类 每个客户端对本地特征做 K-means 聚类 → 得到 K 个簇，每个簇代表一种\u0026#34;局部数据模式\u0026#34; → 注意：聚类结果不上传，只上传簇的统计量（保护隐私） 阶段二：加权簇聚合（WCA） 服务器收到各客户端的簇统计量 计算各客户端模型与全局模型的\u0026#34;特征对齐程度\u0026#34;作为权重 对齐好（特征分布接近全局）→ 权重高 对齐差（特征分布偏离全局）→ 权重低 加权平均 → 全局模型更新 阶段三：Mixup 伪标签自训练 用全局模型生成伪标签 用 Mixup 数据增强 + 伪标签做自监督微调 PyTorch 加权聚合伪代码：\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 def weighted_cluster_aggregation(client_models, client_features, global_model): \u0026#34;\u0026#34;\u0026#34; client_models: 各客户端上传的本地模型参数 client_features: 各客户端的特征统计量（均值/方差，不是原始数据） global_model: 当前全局模型 \u0026#34;\u0026#34;\u0026#34; weights = [] for features in client_features: # 用特征和全局模型的对齐程度作为权重 # 对齐程度 = 特征质心与全局分类器权重的余弦相似度 global_weights = global_model.classifier.weight # [num_classes, feat_dim] alignment = F.cosine_similarity( features.mean(dim=0, keepdim=True), # [1, feat_dim] global_weights.mean(dim=0, keepdim=True) ) weights.append(alignment.item()) # 归一化权重 weights = torch.softmax(torch.tensor(weights), dim=0) # 加权聚合 new_state = {} for key in client_models[0].keys(): new_state[key] = sum(w * m[key] for w, m in zip(weights, client_models)) return new_state FedWCA 的致命裂缝（也是 idea 入口）：\n权重是静态的。 对齐程度一旦计算完毕，在整个聚合过程中就固定了。但真实场景中，同一个客户端的数据里同时存在\u0026quot;高置信度样本\u0026quot;（白天光线充足）和\u0026quot;低置信度样本\u0026quot;（夜间、遮挡），静态权重无法区分这两类样本。把动态不确定性估计引入聚合权重计算，就是填补 FedWCA 最大裂缝的方向。\nUCon-SFDA — Revisiting Source-Free Domain Adaptation: Uncertainty Control Perspective 会议：ICLR 2025\nOpenReview ID：nx9Z5Kva96\n关键词：DRO, Uncertainty Control, Partial Label, Source-Free\n蔡老师研究方向的最新代表作，方向三 idea 的技术提供方。\nUCon-SFDA 用 Distributionally Robust Optimization（DRO）理论来精确建模哪些样本是\u0026quot;不确定的\u0026quot;，并为不确定样本设计专门的\u0026quot;宽松监督\u0026quot;策略。\n不确定性的三个来源：\nUCon-SFDA 把不确定性分成三类： 1. 数据固有模糊性（本来就难分的样本，如边界类别） 2. 域偏移导致的不确定性（从源域到目标域的分布变化） 3. 模型容量导致的不确定性（模型本身的预测置信度） 对不同来源的不确定性，分别设计不同的监督信号强度。 关键创新：Partial Label（偏标签）——对高置信度样本用 hard pseudo-label 强监督，对低置信度样本只要求 top-K 个最可能的类别都算对，不强迫选一个。\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 def uncertainty_aware_loss(predictions, uncertainty_scores, threshold=0.3): \u0026#34;\u0026#34;\u0026#34; predictions: 模型 softmax 输出，shape [B, C] uncertainty_scores: 每个样本的不确定性分数，shape [B] threshold: 高/低不确定性分界线 \u0026#34;\u0026#34;\u0026#34; high_conf_mask = uncertainty_scores \u0026lt; threshold # 低不确定性 = 高置信度 low_conf_mask = uncertainty_scores \u0026gt;= threshold # 高不确定性 = 低置信度 # 高置信度样本：用 Hard Pseudo-label 强监督 hard_labels = predictions[high_conf_mask].argmax(dim=1) hard_loss = F.cross_entropy(predictions[high_conf_mask], hard_labels) # 低置信度样本：用 Partial Label 宽松监督 # Top-K 个最可能的类别都算对（不强迫选一个） topk_mask = torch.zeros_like(predictions[low_conf_mask]) topk_idx = predictions[low_conf_mask].topk(k=3, dim=1).indices topk_mask.scatter_(1, topk_idx, 1.0) partial_loss = -(topk_mask * torch.log(predictions[low_conf_mask] + 1e-8)).sum(dim=1).mean() return hard_loss + 0.5 * partial_loss UCon-SFDA 的裂缝：这是单机版本，假设只有一台机器，没有联邦多客户端场景。它无法处理\u0026quot;如何在不共享数据的情况下，让多个客户端的不确定性信息指导服务器聚合\u0026quot;。\n核心 Idea：两篇论文的\u0026quot;乐高拼接\u0026quot; UCon-SFDA（ICLR 2025） FedWCA（WACV 2025） ↓ ↓ 动态不确定性估计 联邦 Source-Free 加权聚合 精确的样本级不确定性建模 但权重是静态的 单机版本（无联邦场景） 无动态不确定性感知 ↓ Idea： Dynamic Uncertainty-Aware Federated Aggregation （动态不确定性感知联邦聚合） 进阶阅读 论文 会议 一句话贡献 和我的关系 SHOT++ TPAMI 2023 SHOT 的增强版，加入目标域类别均衡约束 理解 SHOT 系列演化 NRC NeurIPS 2021 利用近邻关系图做 Source-Free DA 邻域一致性思路 AaD NeurIPS 2022 对抗式 Source-Free DA，无需源域数据做域对齐 另一类 SFDA 方法视角 FedBN ICLR 2021 保留本地 BN 层不聚合，处理客户端间分布偏移 联邦个性化经典工作 SCAFFOLD ICML 2020 用控制变量纠正 client drift，FedAvg 的重要改进 方向三实验的联邦优化 Baseline 阅读建议：SHOT → FedWCA（arXiv:2412.13757）→ UCon-SFDA（ICLR 2025）。三篇连起来就是方向三的完整故事线。\n三方向论文全局索引 论文简称 全名关键词 会议/期刊 可查找方式 方向归属 CoOp Context Optimization for Vision-Language Models IJCV 2022 搜 \u0026ldquo;CoOp CLIP prompt learning\u0026rdquo; 方向一地基 PromptFL Let Federated Participants Learn Prompts IEEE TMC 2023 搜 \u0026ldquo;PromptFL Guo 2023\u0026rdquo; 方向一入门 DiPrompT Disentangled Prompt Tuning for FedDG CVPR 2024 搜 \u0026ldquo;DiPrompT CVPR 2024\u0026rdquo; 方向一进阶 FedPGP Federated Personalized Generalization Prompts ICML 2024 arXiv:2405.09771 方向一进阶 FedTPG Federated Text-driven Prompt Generation ICLR 2024 搜 \u0026ldquo;FedTPG Qiu 2024\u0026rdquo; 方向一进阶 FedDSPG Federated DG with Domain-Specific Soft Prompts arXiv 2025 arXiv:2509.20807 方向一前沿 FedMVP Federated Multimodal Visual Prompt Tuning ICCV 2025 搜 \u0026ldquo;FedMVP ICCV 2025\u0026rdquo; 方向一前沿 FedSR Simple Effective Domain Generalization for FL NeurIPS 2022 github: atuannguyen/FedSR 方向二/三通用 Baseline gPerXAN Assemble Normalization for FedDG CVPR 2024 搜 \u0026ldquo;gPerXAN CVPR 2024\u0026rdquo; 方向二专属 Baseline FedDG (Liu) Episodic Learning Continuous Frequency Space CVPR 2021 搜 \u0026ldquo;FedDG CVPR 2021 medical\u0026rdquo; 方向二历史根源 SHOT Source Hypothesis Transfer Unsupervised DA ICML 2020 搜 \u0026ldquo;SHOT ICML 2020 Liang\u0026rdquo; 方向三地基 FedWCA Federated Source-Free DA Weighted Cluster Agg WACV 2025 arXiv:2412.13757 方向三核心前驱 UCon-SFDA Uncertainty Control SFDA ICLR 2025 OpenReview: nx9Z5Kva96 方向三核心前驱 阅读优先级建议 方向三（推荐）：\n优先：SHOT → FedWCA → UCon-SFDA（理解 idea 的来龙去脉） 之后：FedSR（实验对比 Baseline），FedBN、SCAFFOLD（联邦优化基础） 有余力：NRC、AaD（丰富 Related Work） 方向一：\n优先：CoOp → PromptFL → DiPrompT → FedDSPG 之后：FedSR（对比 Baseline），FedTPG（Generator 思路参考） 有余力：FedMVP（最新 SOTA） 方向二：\n优先：FedSR → gPerXAN → Sim2Real with Language 之后：FedDG (CVPR 2021)（了解数据操作分支），FedADG（域对齐分支） 有余力：VisDA-2017 数据集论文，GraspNet-1Billion 整理者：Arden 江 | NJUPT 机器人工程 2025 级\n","permalink":"https://ardenj.pages.dev/learning/feddg/","summary":"\u003ch2 id=\"全局视角三篇地基论文\"\u003e全局视角：三篇\u0026quot;地基\u0026quot;论文\u003c/h2\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth\u003e论文\u003c/th\u003e\n          \u003cth\u003e定位\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003ePromptFL\u003c/strong\u003e（2023）\u003c/td\u003e\n          \u003ctd\u003e方向一的起点 Baseline，\u0026ldquo;联邦 Prompt 学习的 FedAvg\u0026rdquo;\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003eFedSR\u003c/strong\u003e（NeurIPS 2022）\u003c/td\u003e\n          \u003ctd\u003e通用 FedDG Baseline，三个方向都必须比较的对象\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd\u003e\u003cstrong\u003eSHOT\u003c/strong\u003e（ICML 2020）\u003c/td\u003e\n          \u003ctd\u003e方向三的历史根源，Source-Free DA 的奠基之作\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003e这三篇是\u0026quot;祖师爷\u0026quot;级别——必须理解，但后续工作要站在它们肩膀上，不是复现它们。\u003c/p\u003e\n\u003chr\u003e\n\u003ch1 id=\"方向一clip--llm--联邦提示微调\"\u003e方向一：CLIP / LLM + 联邦提示微调\u003c/h1\u003e\n\u003ch2 id=\"入门论文\"\u003e入门论文\u003c/h2\u003e\n\u003ch3 id=\"coop--prompt-learning-for-vision-language-models\"\u003eCoOp — Prompt Learning for Vision-Language Models\u003c/h3\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003cstrong\u003e会议\u003c/strong\u003e：IJCV 2022（原版 ICCV 2021）\u003cbr\u003e\n\u003cstrong\u003e关键词\u003c/strong\u003e：Soft Prompt, CLIP, Context Optimization\u003cbr\u003e\n读这篇是因为 PromptFL 本质上就是\u0026quot;把 CoOp 塞进联邦框架\u0026quot;，不懂 CoOp 就没法理解 PromptFL。\u003c/p\u003e\u003c/blockquote\u003e\n\u003cp\u003eCLIP 用\u0026quot;a photo of a [CLASS]\u0026ldquo;这样的手工文本做零样本分类，但手工模板很依赖玄学——换一句话描述，准确率可能差 10%。CoOp 的解决方案很直接：\u003cstrong\u003e别手写模板，让模型自己学出来\u003c/strong\u003e。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eSoft Prompt 的核心机制\u003c/strong\u003e\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e手工 Prompt（Hard Prompt）：\n  输入 → \u0026#34;a photo of a [cat]\u0026#34; → CLIP 文本编码 → 分类\n\nSoft Prompt（CoOp 的做法）：\n  输入 → [v1][v2][v3][v4][cat] → CLIP 文本编码 → 分类\n            ↑\n        这 4 个 [v] 不是文字，是可学习的浮点向量\n        训练时只更新这 4 个向量，CLIP 的其余参数全部冻结\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cstrong\u003eSoft Prompt 就是在类别词前面拼几个可学习的浮点向量\u003c/strong\u003e，训练时只更新这几个向量，CLIP 其余参数全部冻结。\u003c/p\u003e","title":"FedDG 论文导读"},{"content":"前言 经过基础知识的学习，我需要将视角放到更宏大的范围来寻找科研方向，了解整体风向，因此本篇笔记记录一些我摘录的当前学科架构的情况和我对于后续科研方向的一些探索。\n人工智能领域结构 在了解到联邦域泛化（FedDG）后，我回顾了之前的学习历程，发现我对于人工智能领域的全景缺乏理解，所以我让Claude帮我进行快速回顾：\n1 2 3 4 5 6 7 8 9 10 11 12 13 人工智能 (Artificial Intelligence) ├── 机器学习 (Machine Learning) │ ├── 监督学习 (Supervised Learning) │ ├── 无监督学习 (Unsupervised Learning) │ ├── 强化学习 (Reinforcement Learning) │ └── 深度学习 (Deep Learning) ← 当前主流 │ ├── CV（计算机视觉） │ ├── NLP（自然语言处理）← LLM 在这 │ ├── 多模态 (Multimodal) ← CLIP 在这 │ └── 图神经网络 (GNN) ├── 知识表示 \u0026amp; 推理 (符号主义，老派) ├── 搜索与规划 └── 专家系统（已衰落） 而在所有的方向中，强化学习和深度学习无疑是最热门的方向，这里列出它们的内部结构：\n深度学习 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 深度学习 ├── 模型架构 │ ├── CNN（图像） │ ├── RNN/LSTM（序列，已被 Transformer 替代） │ ├── Transformer ← 当代核心架构，LLM/CLIP/ViT 都用它 │ ├── GAN（生成对抗网络） │ └── Diffusion Model（扩散模型，DALL·E、Stable Diffusion） │ ├── 训练范式 │ ├── 标准训练（i.i.d 假设，数据独立同分布） │ ├── 迁移学习 Transfer Learning │ │ ├── Fine-tuning（微调预训练模型） │ │ ├── Domain Adaptation（DA） │ │ ├── Domain Generalization（DG）← 我的方向 │ │ └── Prompt Tuning（提示微调）← CLIP 方向 │ ├── 自监督学习 Self-Supervised Learning（SSL） │ │ └── 对比学习（SimCLR、MoCo） │ ├── 元学习 Meta-Learning（\u0026#34;学会学习\u0026#34;） │ │ └── MAML 等，FedDG 常借用 │ └── 联邦学习 Federated Learning │ └── FedDG = 联邦学习 + 域泛化 ← 我的方向！ │ └── 应用方向 ├── CV：分类、检测、分割、深度估计 ├── NLP：问答、翻译、摘要 ├── 多模态：图文对齐、VQA └── 机器人：感知、规划、控制 一些英文缩写的含义： 强化学习 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 强化学习 (Reinforcement Learning) │ ├── 按\u0026#34;有没有环境模型\u0026#34;分 │ ├── 无模型 Model-Free RL ← 主流，不需要理解环境规律 │ │ ├── 基于值函数 Value-Based │ │ │ ├── Q-Learning（表格版，入门必学） │ │ │ ├── DQN（Deep Q-Network，深度版） │ │ │ └── Rainbow（DQN 的各种改进合集） │ │ │ │ │ ├── 基于策略 Policy-Based │ │ │ ├── REINFORCE（最基础的策略梯度） │ │ │ └── PPO（Proximal Policy Optimization）← 工业界最常用 │ │ │ │ │ └── 演员-评论家 Actor-Critic（值+策略结合） │ │ ├── A3C / A2C │ │ ├── SAC（Soft Actor-Critic）← 机器人连续控制首选 │ │ └── TD3（Twin Delayed DDPG） │ │ │ └── 基于模型 Model-Based RL ← 样本效率高，但难建模 │ ├── Dyna（边学模型边用模型） │ ├── MuZero（AlphaGo 的进化版） │ └── Dreamer（在\u0026#34;梦境\u0026#34;里训练） │ ├── 按\u0026#34;动作空间\u0026#34;分 │ ├── 离散动作（上下左右跳）→ DQN 系列 │ └── 连续动作（关节角度）→ SAC / TD3 / PPO ← 机器人在这 │ ├── 特殊范式 │ ├── 多智能体 MARL（Multi-Agent RL）← 和联邦学习有交叉！ │ │ ├── 合作型（机器人团队协作） │ │ └── 对抗型（博弈、竞技） │ │ │ ├── 离线强化学习 Offline RL ← 和 Source-Free 有类比！ │ │ └── 只用历史数据，不和环境交互（IQL、CQL） │ │ │ ├── 模仿学习 Imitation Learning │ │ ├── 行为克隆 BC（监督学习模仿专家） │ │ └── GAIL（对抗式模仿，用 GAN 思想） │ │ │ └── 逆强化学习 IRL（从行为反推奖励函数） │ └── RLHF 就是它的变体！← LLM 训练用的 │ └── 深度强化学习 Deep RL（RL + 神经网络） └── 以上所有现代方法几乎都是 Deep RL 在真实的机器人场景中，RL面临这许多问题：\n摔倒可能损坏硬件 真实世界 1:1 时间 一些物理描述（如“抓稳了”）怎么描述 传感器有噪声 基于这些问题，我让Claude给出解决方案概览：\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 问题：样本效率低（真实机器人跑不起百万次） ↓ 解法 ├── Model-Based RL（建模环境，减少真实交互） ├── Offline RL（用已有数据集，不再交互） └── Sim-to-Real（仿真里练好，迁移到真实）← 和你的方向直接相关！ 问题：连续动作空间（关节角度是连续值） ↓ 解法 └── SAC / TD3 / PPO（天然支持连续动作） 问题：奖励稀疏（只有\u0026#34;任务完成\u0026#34;才有奖励） ↓ 解法 ├── 好奇心驱动探索（Intrinsic Curiosity Module） ├── 分层 RL（Hierarchical RL，大目标拆小目标） └── 模仿学习（先模仿人类示范，再 RL 精调） 方向探索 在了解完大致结构后，一些兴趣方向也大致锁定。目前我主要在思考三个方向：\nLLM领域 + FedDG（兴趣较大） 机器人领域 + FedDG（契合专业） 无源域适应（导师研究方向） 我主要针对方向一进行了细化：\n结合LLM的FedDG 核心逻辑：利用大模型（主要是 CLIP 这种视觉-语言大模型）的强大泛化能力，来辅助联邦学习中的小模型去适应不同环境。\n需要注意的是，LLM是大语言模型，与其说是LLM+FedDG，不如说是CLIP + FedDG。\nCLIP（Contrastive Language-Image Pretraining）是 OpenAI 用40亿张图文对训练出来的大模型。它最核心的能力是： 把图片和文字映射到同一个特征空间里。 比如，一张猫的照片和\u0026quot;a photo of a cat\u0026quot;这句话，经过 CLIP 处理后，它们的特征向量会非常接近。\n我让Gemini帮我分析了切入点：\n切入点 A：联邦提示微调 (Federated Prompt Tuning)\n故事：以前 FedDG 是在传模型的参数（Weight）。现在我们利用 CLIP，不调模型参数，而是学一个“通用的提示词（Prompt）”。 优势：参数量极小（通信成本低），利用了 CLIP 见过几十亿张图的先验知识，泛化能力天然就很强。 关键词：Vision-Language Models, CLIP, Federated Prompt Learning, Text-guided DG. 切入点 B：LLM 生成数据增强 (Generative Data Augmentation)\n故事：各个医院数据太少？我让 LLM 写 Prompt，指挥 Stable Diffusion 生成一堆“假的但很逼真”的医学图像，扩充本地数据。 优势：简单粗暴有效，故事好听（AIGC for Science）。 关键词：Synthetic Data, Diffusion Models, Data Generation. 在这个方向我通过和Claude的多次对话和提问总结了一份完整的论文导读，在这里不再赘述。\n结语 在整理这篇笔记的过程中，我本来想将三个方向都进行细化整理，但是在重新阅读原始材料的过程中，我发现我对LLM领域有很大的兴趣，以至于第二遍阅读都没怎么看剩下两个方向。所以笔记整理就到第一个方向结束，但论文导读因为有Claude的帮助，完整总结了三个方向从入门到地基再到可优化的点，供未来的我参考。总的来说，总结过程中，未来努力的方向也越来越清晰，或许真的可以在科研中找到学习的乐趣吧。\n","permalink":"https://ardenj.pages.dev/learning/domain_adaptation2/","summary":"\u003ch2 id=\"前言\"\u003e前言\u003c/h2\u003e\n\u003cp\u003e经过基础知识的学习，我需要将视角放到更宏大的范围来寻找科研方向，了解整体风向，因此本篇笔记记录一些我摘录的当前学科架构的情况和我对于后续科研方向的一些探索。\u003c/p\u003e\n\u003ch2 id=\"人工智能领域结构\"\u003e人工智能领域结构\u003c/h2\u003e\n\u003cp\u003e在了解到联邦域泛化（FedDG）后，我回顾了之前的学习历程，发现我对于人工智能领域的全景缺乏理解，所以我让Claude帮我进行快速回顾：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cdiv class=\"chroma\"\u003e\n\u003ctable class=\"lntable\"\u003e\u003ctr\u003e\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"lnt\"\u003e 1\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 2\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 3\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 4\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 5\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 6\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 7\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 8\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 9\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e10\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e11\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e12\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e13\n\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\n\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-text\" data-lang=\"text\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e人工智能 (Artificial Intelligence)\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e├── 机器学习 (Machine Learning)\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e│   ├── 监督学习 (Supervised Learning)\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e│   ├── 无监督学习 (Unsupervised Learning)\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e│   ├── 强化学习 (Reinforcement Learning)\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e│   └── 深度学习 (Deep Learning) ← 当前主流\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e│       ├── CV（计算机视觉）\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e│       ├── NLP（自然语言处理）← LLM 在这\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e│       ├── 多模态 (Multimodal)  ← CLIP 在这\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e│       └── 图神经网络 (GNN)\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e├── 知识表示 \u0026amp; 推理 (符号主义，老派)\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e├── 搜索与规划\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e└── 专家系统（已衰落）\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\n\u003c/div\u003e\n\u003c/div\u003e\u003cp\u003e而在所有的方向中，强化学习和深度学习无疑是最热门的方向，这里列出它们的内部结构：\u003c/p\u003e","title":"Domain adaptation学习笔记（2.选择篇）"},{"content":" 本文为我入门域适应的一些随手记，按照时间顺序进行排序，包含了一些思考和反馈。 摘录我阅读的文章原文部分使用斜体，关于思考总结的部分使用正常字体。 第一次阅读 阅读材料：迁移学习入门之一：域适应的背景，理论与方法\n在机器学习中，Domain Shift是一个很常见的问题，即在训练数据与真实场景来自于不同的分布。 如在医学深度学习模型中，用A医院的数据(Source Domain)训练的模型往往在B医院(Target Domain)预测不准。在摄像头行人重识别(Re-ID)问题中，多个摄像头捕捉的场景分布完全不一致，导致单个行人在多个摄像头中的\u0026quot;重识别\u0026quot;变得较为困难。在联邦学习中，不同客户的数据分布不一致（non-iid）也是最常见的全局模型训练问题。\n而domain adaptation即是对于domain shift的一种解决方案。与其他流派（如迁移学习和微调）不同的点在于，domain adaptation保留了在source domain上的高精度， 并通过一些方法缩小表示空间（将数据从原始输入形式“如图像、文本”转换后得到的特征向量所在的抽象空间，在当前语境下，它是源域与目标域数据通过特征提取层映射后的空间）上Source与target模型特征的距离。\n在了解大方向后，文章给出了一些数学推导，我感觉有点难以理解，这里先记录一些定义和简单的公式：\n文章定义一个domain由两个部分组成：$D,f$ $D$（分布函数）:可以理解为“画风“或数据长什么样。比如源域$D_S$是高清图，目标域$D_T$是高斯模糊图。 $f$（标签函数）:是数据的标签，如在二分类问题中输入一张图$x$,它到底是猫还是狗（0或1）。 在 Domain Adaptation 中，我们通常假设物体的本质不变，只是画风变了。 也就是说，一张猫的图片，无论变多模糊，它依然是猫。也就是: $f_S \\approx f_T$, 但是 $D_s \\neq D_T$\n什么是误差？ 公式 ： $$ \\epsilon(h, f; \\mathcal{D}) = \\mathbf{E}_{\\mathbf{x} \\sim \\mathcal{D}}|h(\\mathbf{x}) - f(\\mathbf{x})| $$ $h$ (hypothesis，假设)：学习函数，就是我们训练的模型网络。 $f$：真实标签。 $\\epsilon$ (error)：误差。 这个公式大概是代码里写的 Loss 函数（或者说测试集上的错误率）。 它表示：在某种画风 $\\mathcal{D}$ 下，你的模型 $h$ 预测的结果，和真实答案 $f$ 之间相差多少。\n$\\epsilon_S(h)$：模型在源域（清晰图）上的错误率。 $\\epsilon_T(h)$：模型在目标域（模糊图）上的错误率。 我们手里只有源域的标签，所以我们只能把 $\\epsilon_S(h)$ 训练得很小。但我们真正想要的是，$\\epsilon_T(h)$ 也很小。\n关键公式：泛化误差上界 $$ \\epsilon_T(h) \\le \\epsilon_S(h) + d_1(\\mathcal{D}_S, \\mathcal{D}_T) + \\text{常量} $$我们把这个公式拆成三块来看： 你要想让目标域错误率 $\\epsilon_T(h)$ 很小（等号左边），你必须让等号右边的三项都很小：\n$\\epsilon_S(h)$：源域的错误率。 代码体现：将源域的Loss 降到最低。 $d_1(\\mathcal{D}_S, \\mathcal{D}_T)$：源域和目标域的距离（画风差异）。 所有DA重点关注的模块。既然清晰图和模糊图有代沟，我们就在网络里加个模块，把他们的特征“拉近”，让这个距离 $d_1$ 变小。 $\\min\\{...\\}$ 项：两个域标签函数的差异。 我们通常假设猫就是猫，不管清不清晰，所以这部分是个很小的常数，通常被忽略。 如何衡量距离？从$d_1$ 到 $\\mathcal{H}$-distance ： $\\mathcal{H}$-距离（公式4） $$ d_{\\mathcal{H}}(\\mathcal{D}_S, \\mathcal{D}_T) = 2 \\sup_{h \\in \\mathcal{H}} |\\Pr_{\\mathcal{D}_S}(I(h)) - \\Pr_{\\mathcal{D}_T}(I(h))| $$ 这个公式有些复杂，所以我让Gemini帮我生成了详细的解释：\n1. $I(h)$ 是什么？—— “VIP 准入名单” 文献里的原话：$I(h) = \\{\\mathbf{x} : h(\\mathbf{x}) = 1, \\mathbf{x} \\in \\mathcal{X}\\}$ 【破壁机翻译】： 假设你的模型 $h$ 是一个“保安”（二分类器），它的任务是判断来的人是不是 VIP（输出 1 是 VIP，输出 0 不是）。 那么，$I(h)$ 就是所有被这个保安放行（判定为 1）的人的集合。 💻 代码体现： 就相当于你在 PyTorch 里写了一句： vip_group = x[model(x) == 1] 2. $\\Pr$ 是什么？—— “放行概率（命中率）” 符号含义：$\\Pr$ 就是 Probability（概率）。底下的下标 $\\mathcal{D}_S$ 或 $\\mathcal{D}_T$ 代表你是在哪个数据集里抓人。 【破壁机翻译】： $\\Pr_{\\mathcal{D}_S}(I(h))$：你在源域（比如：白天拍的照片）里闭着眼睛瞎抓一张，这张照片被模型判为 1 的概率是多少？（假设是 30%） $\\Pr_{\\mathcal{D}_T}(I(h))$：你在目标域（比如：黑夜拍的照片）里闭着眼睛瞎抓一张，这张照片被模型判为 1 的概率是多少？（假设是 80%） $|\\Pr_{\\mathcal{D}_S} - \\Pr_{\\mathcal{D}_T}|$：取个绝对值，算出概率差（$|30\\% - 80\\%| = 50\\%$）。 这个“差值”说明了什么？ 如果同一个保安 $h$，对白天的人放行率是 30%，对黑夜的人放行率是 80%，差值很大，说明这个保安（模型）对环境变化非常敏感（歧视严重）。说明这两个数据集在保安眼里差距很大。 3. $\\sup$ 是什么？—— “找茬大王（找最大值）” 符号含义：sup 全称是 Supremum（上确界）。你可以简单粗暴地把它等同于 $\\max$（求最大值）。 底下的 $h \\in \\mathcal{H}$：$\\mathcal{H}$ 代表你的“模型家族”（比如所有参数组合下的 ResNet18 模型）。 【破壁机翻译】： 现在，你手下有一万个保安（代表所有可能的模型参数组合 $h$）。 sup 的意思就是：作为老板，你要对这一万个保安挨个进行测试，专门挑出那个“双标最严重”、“对源域和目标域态度差异最大”的保安。 把这个“最能找茬的保安”找出的概率差，定义为这两个数据集的最终距离。 💡 连起来理解：什么是 $\\mathcal{H}$-distance？ 现在我们把整个公式连起来读：\n两个数据集的 $\\mathcal{H}$ 距离，就是我们在所有的模型（$\\sup_{h \\in \\mathcal{H}}$）中，找到那个最能把这两个数据集区分开来的模型，它所表现出的“双标程度（概率差）”。\n为什么要这么定义？（高能预警，这联系到了深度学习的本质！）\n你回想一下公式 (2) 的 $d_1$ 距离，那个距离是站在“上帝视角”找不同，太苛刻了。 而公式 (4) 聪明就聪明在：它把距离和模型绑定在了一起。\n如果两个数据集（清晰图和模糊图），在物理像素上肯定不一样（上帝视角看距离很大）。 **但是！如果我们穷尽了所有的神经网络 $h$，连那个“最会找茬的神经网络（sup）”**都发现： “哎？我怎么觉得清晰图里有 30% 是猫，模糊图里也有 30% 是猫？我完全感觉不到差别啊！”\n那就意味着：在神经网络的视角下，这两个数据集的距离为 0！\n👨‍💻 最终落地：这在代码里怎么实现？（诞生了对抗域适应） 理论家写出了 $\\sup$（找最大差异），工程师怎么把它变成代码？\n答案是：训练一个“域分类器（Domain Discriminator）”。\n我们写一个网络，专门去预测图片是来自源域（0）还是目标域（1）。 我们在训练这个分类器时，让它的 Loss 尽可能小（也就是让它尽可能把两边区分开，这就对应了数学上的 $\\sup$ 操作！）。 同时，我们让前面的 Encoder 特征提取器拼命去骗它，让域分类器的 Loss 尽可能大。 这就是著名的 GRL（Gradient Reversal Layer，梯度反转层） 算法，也就是对抗域适应的核心思想。\n接下来文章进入了严谨的公式推导，我实在有些不想看，刚好Gemini最后提到了代码实现的问题，还挺有意思的，那么我们就继续沿着这条线探索。\n第二次阅读 阅读材料：与Gemini的对话。\n在第一次阅读最后，我们从数学公式的定义转向具体的代码，现在我们通过和Gemini对话来深入。\nDANN（Domain-Adversarial Training of Neural Networks） 根据上文的笔记，我们知道域适应的主要数据集分为两种：源域（source）和目标域（target）。 基于此，DANN网络将结构分为三个模块：\n特征提取器（Encoder）：主要用于提取两个域的特征。 标签分类器（Label Classifier）：基于提取的特征进行分类。 域分类器 (Domain Discriminator)：基于提取的特征判断输入的图片属于哪个域。 冲突来了：\n域分类器的目标是高效识别两个域（也就是算出了那个最大的 H-distance） 而Encoder的目标则是模糊两个域的特征让域分类器无法识别。 如何提高Encoder“欺骗”的效率？这就引出了GRL。\nGRL（Gradient Reversal Layer） 在正常的神经网络中，反向传播（Backward）传回来的梯度（Gradient）是向着loss减小的方向进行的。 在DANN中，域分类器遵循这个规则，但对与Encoder则不一样。\nEncoder目标是混淆两个域的区别，增大loss，而传统的反向传播会使loss减小，所以我们需要在loss前乘上一个负号， 于是，Encoder 拿着相反的梯度更新了参数，成功实现了让 Loss 最大化的目的。这就是GRL在网络中的作用。\n代码实现(Gemini代写)： 第一步：写出 GRL 的底层逻辑：\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 import torch import torch.nn as nn from torch.autograd import Function # 自定义一个带反向求导规则的层 class GradientReversalLayer(Function): @staticmethod def forward(ctx, x, alpha): # 顺向传播：记住这个 alpha (反转系数，通常是 1)，然后原封不动地返回 x ctx.alpha = alpha return x.view_as(x) @staticmethod def backward(ctx, grad_output): # 反向传播：叛徒出现了！把传回来的梯度乘上负的 alpha output = grad_output.neg() * ctx.alpha # 第二个返回值是 None，因为 forward 里的 alpha 不需要求导 return output, None # 把这个魔法封装成一个普通的 nn.Module，方便我们像搭积木一样使用 class GRL(nn.Module): def __init__(self, alpha=1.0): super(GRL, self).__init__() self.alpha = alpha def forward(self, x): return GradientReversalLayer.apply(x, self.alpha) 第二步：搭建 DANN 网络:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 class DANN(nn.Module): def __init__(self): super(DANN, self).__init__() # 1. 伪造大师 (特征提取器 Shared Encoder) self.encoder = nn.Sequential( nn.Conv2d(3, 64, 3, padding=1), nn.ReLU(), nn.MaxPool2d(2) ) # 2. 动物专家 (任务分类头 Task Head) self.label_classifier = nn.Sequential( nn.Linear(64 * 16 * 16, 128), nn.ReLU(), nn.Linear(128, 10) # 假设分 10 类动物 ) # 3. 海关警察 (域分类头 Domain Head) self.domain_classifier = nn.Sequential( nn.Linear(64 * 16 * 16, 64), nn.ReLU(), nn.Linear(64, 2) # 只分 2 类：0是源域(高清)，1是目标域(简笔画) ) # 加入叛徒翻译官！ self.grl = GRL(alpha=1.0) def forward(self, x): # 共同提取特征 features = self.encoder(x) features_flat = features.view(features.size(0), -1) # 路线 A：正常去做分类任务 class_preds = self.label_classifier(features_flat) # 路线 B：特征经过 GRL，再交给域分类器 reversed_features = self.grl(features_flat) domain_preds = self.domain_classifier(reversed_features) return class_preds, domain_preds 训练逻辑：\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 # 假设我们有清晰图数据 (Source) 和 模糊图数据 (Target) criterion = nn.CrossEntropyLoss() for (img_S, label_S), (img_T, _) in zip(source_loader, target_loader): # 把源域打上域标签 0，目标域打上域标签 1 domain_label_S = torch.zeros(img_S.size(0), dtype=torch.long) domain_label_T = torch.ones(img_T.size(0), dtype=torch.long) # --------------------------- # 1. 训练源域 (Source) # --------------------------- class_preds_S, domain_preds_S = model(img_S) # 源域能算分类 Loss（因为有真实标签） loss_class = criterion(class_preds_S, label_S) # 源域算域 Loss（警察要认出这是 0） loss_domain_S = criterion(domain_preds_S, domain_label_S) # --------------------------- # 2. 训练目标域 (Target) # --------------------------- class_preds_T, domain_preds_T = model(img_T) # 注意：目标域没有类别标签，所以不能算分类 Loss！ # 目标域只能算域 Loss（警察要认出这是 1） loss_domain_T = criterion(domain_preds_T, domain_label_T) # --------------------------- # 3. 联合优化！ # --------------------------- # 总 Loss = 分类误差 + (警察认出源域的误差 + 警察认出目标域的误差) total_loss = loss_class + (loss_domain_S + loss_domain_T) optimizer.zero_grad() total_loss.backward() optimizer.step() 当 total_loss.backward() 执行时，魔法发生了：\n对于 domain_classifier（警察）：由于它在 GRL 之后，梯度正常流入，它会努力更新自己，让自己更聪明，把 Source 和 Target 分得更清。 对于 encoder（伪造大师）：当警察的梯度穿过 GRL 层传给它时，乘上了负号！于是 Encoder 努力更新自己，使得提取出来的特征，让警察猜不出来！ 训练到最后的结果： 警察彻底疯了，它看所有特征都觉得是 50% 源域，50% 目标域。 这就意味着，Encoder 成功剔除了“画风（清晰还是模糊）”这个无关特征，只保留了“物体的本质”。 此时，拿目标域（模糊图）去给 label_classifier 预测，准确率就会暴涨！\n反思 DANN作为一个经典网络，必然也会有它的短板：\n全局对齐导致的负迁移 (Negative Transfer)：DANN 只对齐了边缘分布 $P(X)$，忽略了条件分布 $P(Y|X)$。 矫枉过正，Encoder会丢弃大量信息来模糊源域和目标域，导致分类效果直线下滑。 数据需求量大，DANN需要源域和目标域的数据，但现实中往往缺乏目标域的数据。 因此，后来的论文基于这三点进行改进，衍生出了四大方向：\n带条件的对抗域适应 (CDAN, NIPS 2018) 伪标签技术 (Pseudo-labeling / Self-training) 熵最小化 (Entropy Minimization) 无源域适应 (Source-Free DA, SFDA) 这些方向基于三个问题点中的1～2个进行了深入研究和优化，具体深入就要通过读对应的论文了，入门笔记就到这里啦。\n","permalink":"https://ardenj.pages.dev/learning/domain_adaptation/","summary":"\u003cblockquote\u003e\n\u003cul\u003e\n\u003cli\u003e本文为我入门域适应的一些随手记，按照时间顺序进行排序，包含了一些思考和反馈。\u003c/li\u003e\n\u003cli\u003e摘录我阅读的文章原文部分使用\u003cem\u003e斜体\u003c/em\u003e，关于思考总结的部分使用正常字体。\u003c/li\u003e\n\u003c/ul\u003e\u003c/blockquote\u003e\n\u003ch2 id=\"第一次阅读\"\u003e第一次阅读\u003c/h2\u003e\n\u003cp\u003e阅读材料：\u003ca href=\"https://zhuanlan.zhihu.com/p/439560708\"\u003e迁移学习入门之一：域适应的背景，理论与方法\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e在机器学习中，Domain Shift是一个很常见的问题，即在训练数据与真实场景来自于不同的分布。\n\u003cem\u003e如在医学深度学习模型中，用A医院的数据(Source Domain)训练的模型往往在B医院(Target Domain)预测不准。在摄像头行人重识别(Re-ID)问题中，多个摄像头捕捉的场景分布完全不一致，导致单个行人在多个摄像头中的\u0026quot;重识别\u0026quot;变得较为困难。在联邦学习中，不同客户的数据分布不一致（non-iid）也是最常见的全局模型训练问题。\u003c/em\u003e\u003c/p\u003e\n\u003cp\u003e而domain adaptation即是对于domain shift的一种解决方案。与其他流派（如迁移学习和微调）不同的点在于，domain adaptation保留了在source domain上的高精度，\n并通过一些方法缩小表示空间（将数据从原始输入形式“如图像、文本”转换后得到的特征向量所在的抽象空间，在当前语境下，它是源域与目标域数据通过特征提取层映射后的空间）上Source与target模型特征的距离。\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"具体图像\" loading=\"lazy\" src=\"/learning/domain_adaptation/v2-551104354ea5639291e857744282a7d4_1440w.png\"\u003e\u003c/p\u003e\n\u003cp\u003e在了解大方向后，文章给出了一些数学推导，我感觉有点难以理解，这里先记录一些定义和简单的公式：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003ch3 id=\"文章定义一个domain由两个部分组成\"\u003e文章定义一个domain由两个部分组成：$D,f$\u003c/h3\u003e\n\u003col\u003e\n\u003cli\u003e\u003cstrong\u003e$D$（分布函数）\u003c/strong\u003e:可以理解为“画风“或数据长什么样。比如源域$D_S$是高清图，目标域$D_T$是高斯模糊图。\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e$f$（标签函数）\u003c/strong\u003e:是数据的标签，如在二分类问题中输入一张图$x$,它到底是猫还是狗（0或1）。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e在 Domain Adaptation 中，我们通常假设\u003cstrong\u003e物体的本质不变，只是画风变了\u003c/strong\u003e。\n也就是说，一张猫的图片，无论变多模糊，它依然是猫。也就是:\n$f_S \\approx f_T$, 但是 $D_s \\neq D_T$\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ch3 id=\"什么是误差\"\u003e什么是误差？\u003c/h3\u003e\n\u003cp\u003e公式 ：\n\u003c/p\u003e\n$$ \\epsilon(h, f; \\mathcal{D}) = \\mathbf{E}_{\\mathbf{x} \\sim \\mathcal{D}}|h(\\mathbf{x}) - f(\\mathbf{x})| $$\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003e$h$ (hypothesis，假设)\u003c/strong\u003e：学习函数，就是我们训练的模型网络。\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e$f$\u003c/strong\u003e：真实标签。\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e$\\epsilon$ (error)\u003c/strong\u003e：误差。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e这个公式大概是代码里写的 \u003cstrong\u003eLoss 函数（或者说测试集上的错误率）\u003c/strong\u003e。\n它表示：在某种画风 $\\mathcal{D}$ 下，你的模型 $h$ 预测的结果，和真实答案 $f$ 之间相差多少。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e$\\epsilon_S(h)$：模型在源域（清晰图）上的错误率。\u003c/li\u003e\n\u003cli\u003e$\\epsilon_T(h)$：模型在目标域（模糊图）上的错误率。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cblockquote\u003e\n\u003cp\u003e我们手里只有源域的标签，所以我们只能把 $\\epsilon_S(h)$ 训练得很小。但我们\u003cstrong\u003e真正想要的是，$\\epsilon_T(h)$ 也很小\u003c/strong\u003e。\u003c/p\u003e\u003c/blockquote\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ch3 id=\"关键公式泛化误差上界\"\u003e关键公式：泛化误差上界\u003c/h3\u003e\n$$ \\epsilon_T(h) \\le \\epsilon_S(h) + d_1(\\mathcal{D}_S, \\mathcal{D}_T) + \\text{常量} $$\u003cp\u003e我们把这个公式拆成三块来看：\n你要想让\u003cstrong\u003e目标域错误率 $\\epsilon_T(h)$ 很小\u003c/strong\u003e（等号左边），你必须让等号右边的三项都很小：\u003c/p\u003e","title":"Domain adaptation入门笔记（1.超基础知识篇）"},{"content":"前言 该文章是基于我校 校科学技术协会 woc-python组题目个人解答过程的系统性回顾。\n项目代码：NJUPT-SAST-Python-WoC-2025\n本文主要记录学习和方法迭代的过程，详细代码实现请查阅代码库。\n题目简介： 任务背景与目标\n本项目旨在探索多任务学习 (Multi-Task Learning) 在计算机视觉中的应用。核心目标是通过联合网络的设计，实现底层视觉（图像重构）与高层视觉（语义理解）两个任务的相互促进 (Mutual Promotion)。\n基础任务定义 (Single-Task Baselines)\n网络需从零开始搭建与训练,完成以下两个独立任务：\n1 2 3 4 5 6 7 Task 1：底层图像恢复 (Low-level Vision) 任务内容：任选一种退化图像修复场景（包括但不限于超分辨率、去噪、去雾、低光增强等）。 评估指标：PSNR 与 SSIM，需在验证集上具有合理表现。 Task 2：高层图像分类 (High-level Vision) 任务内容：基于 CIFAR 数据集的图像分类。 评估指标：Accuracy（最低要求界定为 60%）。 多任务联合优化约束 (Multi-Task Constraints)\n在跑通单任务 Baseline 后，需构建多任务联合网络（例如 Task 1 辅助 Task 2，或反之），且必须满足以下硬性约束：\n1 2 3 4 1.架构轻量化与一致性：多任务分支需与单任务网络结构保持高度一致，禁止大幅增加参数量。 2.鼓励采用参数共享 (Parameter Sharing) 或引入轻量的交互通信模块。 3.微调策略 (Fine-tuning)：在单任务预训练的基础上，通过微调分支头或特征层来实现融合。 4.损失函数创新：鼓励设计具有创新性的互促损失函数 (Mutual-promoting Loss) 来平衡两个任务的梯度。 最终效果： 在 低清图直接分类 和经过多任务学习后 超分-\u0026gt;分类 的结果对比中，后者正确率达到81.01%，而前者只有47.26%，多任务学习将图像分类的正确率提升约0.7倍！ 让我们回到一切的开始，详细聊聊从无到有的过程吧。\n一、破冰与镇痛 时间回到2025年的12月底，那时的我正处在迷茫与焦虑之中：大一的第一学期即将收官，但是自己仍未找到深耕的学习方向。在咨询班主任和高强度上网冲浪后 ，我决定先入门人工智能，再以此为基础学习现代的机器人算法。与此同时，我一直期待的校科协WOC（Winter of Code）也即将举行，我便打算以此作为我入门人工智能的第一个项目。\n在课题公布的最开始，我从未了解过pytorch，也从未使用过Jupyter，甚至对于机器学习、深度学习、神经网络等概念之间的从属关系也傻傻分不清。 于是，当务之急就是恶补这些基础知识。当时我正在通过CS61A(一门很好的计算机语言入门课程，墙裂推荐！)学习python语法， 由于时间紧迫，就囫囵吞枣地把后面关于类(class)的课时刷了一遍（现在来看不扎实的基础知识更加拖慢了后面学习的效率）。 刷完语法，我就开始物色课时短，又好评如潮的深度学习课程，最后，我决定在b站看《pytorch深度学习实践》。这门视频课系列完整地从全连接神经网络讲到现代的卷积和循环神经网络模型，注重代码实践的风格也帮我更快的理解和上手实践。唯一的缺点就是没有教transformer架构，这可能也是为什么课时短的原因吧:)\n不得不提的是，神经网络的学习让我第一次对代码到底如何从计算实现一个大功能有了真实的体验，Thanks~\n二、task1/task2的探索 折腾完基础知识的学习，时间也已经来到了一月底。 可惜的是，假期的开始并没有让我有许多时间投入深度学习的学习（读起来好怪hhh）, 我被拉入了托福课的泥潭，每天自己学习的时间只有晚上可怜的两三个小时。幸亏有gemini和claude，可以直接vibe coding。\ntask2初试 对于一个初学者，task2相比task1可以更好上手。所以我决定先写一个最基础的二层卷积-\u0026gt;下采样-\u0026gt;三层全连接的网络，跑通一遍再说！\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 #定义模型 class Net(nn.Module): def __init__(self): super(Net, self).__init__() # CIFAR10 输入: (batch, 3, 32, 32) self.conv1 = nn.Conv2d(3, 16, kernel_size=5) self.conv2 = nn.Conv2d(16, 32, kernel_size=5) self.pool = nn.MaxPool2d(2, 2) self.fc1 = nn.Linear(32 * 5 * 5, 120) self.fc2 = nn.Linear(120, 84) self.fc3 = nn.Linear(84, 10) def forward(self, x): x = self.pool(F.relu(self.conv1(x))) x = self.pool(F.relu(self.conv2(x))) x = x.view(-1, 32 * 5 * 5) # 展平 x = F.relu(self.fc1(x)) x = F.relu(self.fc2(x)) x = self.fc3(x) return x #损失函数和优化器 criterion = nn.CrossEntropyLoss() optimizer = optim.SGD(model.parameters(), lr=learning_rate, momentum=momentum) 这套我在minst识别中就使用的方案居然在cifar10上跑出了60+%的准确率，已经达到了课题的要求!\n当然，这套方案存在一些缺点：\n1. 卷积层太少、kernel太大，特征提取能力太差（正确率只有60+的核心问题） 2. 非常容易过拟合，上限锁死 不过秉持着‘先跑通一遍’的原则，我决定先把优化的事放一放，先进入task1的学习。\ntask1初试 课题中给了很多task1的选择方向（超分辨率、去噪、去雾、低光增强等），经过gemini（哈基米老师真的很好）的介绍和推荐，我决定搭建超分辨率(Super-Resolution)架构。\n关于数据集\n对于task1需要的数据集，训练数据集我选择了DIV2K，测试数据集选择了Set14。DIV2K包含800张2k超清摄影图，很好的适配了超分辨率的训练需求。Set14是14张不同风格的图片（有摄影，也有海报等），图片数量少，测试快；种类多，也能测试模型的泛化能力。准备好数据集，我们就可以进入模型搭建环节啦！\n超分辨率，或是说这种底层视觉任务，超出了我之前的学习范围，同时又因为每天学习时间碎片化，一些基础知识忘的差不多了，我需要先停下代码进度，回去复习。\n复习的时候，我遇到了另一个非常全面的入门资料：由李沐老师编写的动手学深度学习。复习期间我浏览了其中现代卷积神经网络部分，其中VGG,ResNet对我后续优化起了很大的帮助。\n由于超分辨率是一个细分的分支，市面上并没有一个全面的入门教材，阅读综述就成了入门的唯一方式。在浏览完一个大概的入门综述（综述地址）后，我决定以SRCNN（论文地址）作为我的基础骨架。\n关于SRCNN\nSRCNN作为超分辨率的开山之作,在今天来看其技术架构非常简单易懂，适合入门和个性化改进，其主要有以下几个问题需要改进：\n它只能对相同倍数的图像进行超分，需要重新调整网络参数并训练来实现不同尺寸的超分。 采用的插值方法将LR图像转换到HR图像空间，再利用神经网络重建，这增加了网络计算量。 网络浅，提取特征能力不强。 确定好了基础架构和先先需要改进的问题，第一版模型也就应运而生：\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 class Net(nn.Module): def __init__(self, *args, **kwargs) -\u0026gt; None: super().__init__(*args, **kwargs) #Encoder self.encoder = nn.Sequential( nn.Conv2d(3, 64, kernel_size=9, padding=4), nn.ReLU(inplace=True), nn.Conv2d(64, 32, kernel_size=5, padding=2), nn.ReLU(inplace=True), nn.Conv2d(32, 32, kernel_size=3, padding=1), nn.ReLU(inplace=True) ) #上采样部分 self.upsample = nn.Sequential( nn.Conv2d(32, 32*4, kernel_size=3, padding=1), nn.PixelShuffle(upscale_factor=2), nn.Conv2d(32, 3, kernel_size=3, padding=1), nn.Sigmoid() ) def forward(self, x): x = self.encoder(x) x = self.upsample(x) return x criterion = nn.MSELoss() optimizer = optim.Adam(model.parameters(), lr=lr) 该模型的主要改进：\n增加深度（SRCNN的3层卷积-\u0026gt;5层卷积） 动态调整卷积核的大小（9-\u0026gt;5-\u0026gt;3） 将SRCNN中采用的插值方法改为Pixelshuffle亚像素卷积放大，简化计算流程 优化器采用流行的Adam架构 需要补充的是，受限于设备，训练时每一张图片只能取一小块喂给模型，这样才能保证每个batch的数据量足够多。 具体表现在Dataset之中：\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 class DIV2KDataset(Dataset): def __init__(self, root_dir, crop_size=128, scale_factor=2) -\u0026gt; None: super().__init__() self.root_dir = root_dir self.image_files= [f for f in os.listdir(root_dir)] self.crop_size = crop_size #裁剪为crop_size**2大小的图像 self.scale_factor = scale_factor #缩小scale_factor倍 #处理高清图片 self.transforms_HR = transforms.Compose([ transforms.RandomCrop(crop_size), transforms.ToTensor(), ]) #生成低清图片 self.transforms_LR = transforms.Resize( size=(crop_size // scale_factor, crop_size // scale_factor), interpolation=transforms.InterpolationMode.BICUBIC #双三次插值 ) def __len__(self): return len(self.image_files) def __getitem__(self, idx): #拼出图片路径并打开 img_path = os.path.join(self.root_dir, self.image_files[idx]) image = Image.open(img_path).convert(\u0026#39;RGB\u0026#39;) #制作训练样本 img_HR = self.transform_HR(image) img_LR = self.transform_LR(img_HR) return img_LR, img_HR Dataset类在转换图片为张量的基础上，额外增加了切片制作训练样本的过程。 灵感来源：gemini💁\n最终第一版的模型的跑分为：\nPSNR：26.93 SSIM：0.8303 这一版模型能力还是比较高的（在设备的限制下），也达到了课题验收的要求。但是在之前简单的复习后，一些新的架构和想法在我脑中跃跃欲试，于是，我很快进入优化阶段：\n三、独立模型的优化 task2 还是按照时间顺序，先说task2。在刚开始优化的时候，我尝试过增加模型的深度， 包括增加卷积和全连接层、调整卷积核大小，但越是改动，一个问题就越来越明显：过拟合。一味增加深度不仅拉长了一次训练的时间，而且模型过度记忆训练集的特征，正确率进入了难以突破的瓶颈：训练集达到80%的准确率，但测试集正确率却险些跌破60%。\n过拟合是在模型深度增加时难免遇到的问题，得益于李沐老师的书，我找到了一个简单有效的方法：Dropout。 Dropout方法通过在训练过程中随机丢弃一些神经元，从而预防了模型过度记忆训练集的特征，提高模型的泛化能力。 有了Dropout，模型适当的深度增加所带来的正反馈也得到了加强。\n于是，最终的 CIFAR10分类模型 就完成了：\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 #encoder class Encoder(nn.Module): def __init__(self): super().__init__() self.features = nn.Sequential( nn.Conv2d(3, 64, kernel_size=3, padding=1), nn.ReLU(inplace=True), ) def forward(self, x): return self.features(x) # Task2: 分类网络 class Net(nn.Module): def __init__(self): super(Net, self).__init__() self.encoder = Encoder() self.conv2 = nn.Conv2d(64, 64, kernel_size=3, padding=1) self.conv3 = nn.Conv2d(64, 64, kernel_size=3, padding=1) self.conv4 = nn.Conv2d(64, 64, kernel_size=3, padding=1) self.conv5 = nn.Conv2d(64, 128, kernel_size=3, padding=1) self.conv6 = nn.Conv2d(128, 128, kernel_size=3, padding=1) self.pool = nn.MaxPool2d(2, 2) self.fc1 = nn.Linear(128 * 4 * 4, 256) self.fc2 = nn.Linear(256, 128) self.fc3 = nn.Linear(128, 10) self.dropout_conv = nn.Dropout(0.25) self.dropout_fc = nn.Dropout(0.5) def forward(self, x): x = self.encoder(x) x = F.relu(self.conv2(x)) x = self.pool(x) x = self.dropout_conv(x) x = F.relu(self.conv3(x)) x = F.relu(self.conv4(x)) x = self.pool(x) x = self.dropout_conv(x) x = F.relu(self.conv5(x)) x = F.relu(self.conv6(x)) x = self.pool(x) x = self.dropout_conv(x) x = x.view(-1, 128 * 4 * 4) x = F.relu(self.fc1(x)) x = self.dropout_fc(x) x = F.relu(self.fc2(x)) x = self.dropout_fc(x) x = self.fc3(x) return x criterion = nn.CrossEntropyLoss() optimizer = optim.SGD(model.parameters(), lr=lr, momentum=momentum) 经过优化的模型在测试集和训练集的准确率相当，最终跑分：\n训练集：89%（有几次越过90%） 测试集：85% 这是在清晰的图片下的训练结果，这个测试的准确率也决定了模型在多任务学习中准确率的上限（毕竟我的超分辨率模型怎么优化也超不过原图的清晰度（悲））。\ntask1 SRNet的改动相对来说就复杂许多，首先我想到的改进就是引入残差块(Res_blocks)。\n这个架构可以说是在计算机视觉中家喻户晓的存在。Residual-block通过跳跃连接的方式解决了梯度消失的问题，保证了初始特征在多轮训练中的稳定。简要示意图如下（图片来源）：\n以下为修改后的模型代码：\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 #Encoder class Encoder(nn.Module): def __init__(self): super().__init__() self.features = nn.Sequential( nn.Conv2d(3, 64, kernel_size=3, padding=1), nn.ReLU(inplace=True), ) def forward(self, x): return self.features(x) #定义模型 class Net(nn.Module): def __init__(self, num_channels=128, num_residual_blocks=8) -\u0026gt; None: super().__init__() self.encoder = Encoder() self.transition = nn.Sequential( nn.Conv2d(64, num_channels, kernel_size=3, padding=1), nn.ReLU(inplace=True), ) res_blocks = [] for _ in range(num_residual_blocks): res_blocks.append(nn.Sequential( nn.Conv2d(num_channels, num_channels, kernel_size=3, padding=1), nn.ReLU(inplace=True), nn.Conv2d(num_channels, num_channels, kernel_size=3, padding=1), )) self.res_blocks = nn.ModuleList(res_blocks) self.res_relu = nn.ReLU(inplace=True) #特征压缩 self.tail = nn.Sequential( nn.Conv2d(num_channels, 64, kernel_size=3, padding=1), nn.ReLU(inplace=True), ) #上采样部分 self.upsample = nn.Sequential( nn.Conv2d(64, 64*4, kernel_size=3, padding=1), nn.PixelShuffle(upscale_factor=2), nn.Conv2d(64, 3, kernel_size=3, padding=1), nn.Sigmoid() ) def forward(self, x): x = self.encoder(x) x = self.transition(x) for block in self.res_blocks: x = self.res_relu(x + block(x)) x = self.tail(x) x = self.upsample(x) return x 除残差块外，模型还进行了以下修改：\n将Encoder独立：这里的Encoder和task2的分类网络共享了同一个结构（Conv2d(3, 64, 3, padding=1)），这是为了适应多任务学习部分的参数共享而做出的调整。 引入transition层：将Encoder输出的64通道扩展到128通道，为残差块提供更宽的特征空间。 8个残差块：每个残差块由两层卷积组成，通过跳跃连接（x + block(x)）保持梯度稳定。8个残差块意味着网络的主干深度达到了16层卷积，特征提取能力远超第一版。 特征压缩（tail）：残差块输出后通过tail层将128通道压缩回64通道，再送入上采样模块，保持了PixelShuffle部分的计算效率。 统一卷积核为3×3：抛弃了第一版中9→5→3的递减策略，全部使用3×3小卷积核，通过深度来弥补感受野，这也是VGG论文中的经典结论。 除了架构上的改动，训练策略也做了调整：\n1 2 3 criterion = nn.L1Loss() optimizer = optim.Adam(model.parameters(), lr=0.001) scheduler = optim.lr_scheduler.StepLR(optimizer, step_size=25, gamma=0.7) L1Loss替代MSELoss：MSE对大误差的惩罚过重，容易让模型生成过于平滑的图像。L1Loss对误差的处理更加均匀，生成的图像细节更锐利。 学习率调度器（StepLR）：每25个epoch将学习率乘以0.7，在训练后期自动降低学习率帮助模型更精细地收敛，避免在最优解附近来回震荡。 最终版SRNet在Set14上的跑分：\nPSNR：28.15 SSIM：0.8912 如果但从分数上看，模型的提升相对task2没有那么明显，或许是调整过重，或许是发力错了方向，我个人对于调整过后的分数并不是那么满意。不过作为一个底层视觉优化的模型，一点小的提升相信对与分类器来说也是很不错的加持了。\n四、多任务学习 经过两个独立模型的提升优化，是时候进行联合训练环节了！\n设计思路 回顾课题要求：多任务网络需要让底层视觉（超分辨率）和高层视觉（分类）两个任务相互促进。我的设计思路是：先用超分辨率网络将模糊图像修复，再将修复后的清晰图像送入分类网络进行分类。直觉上来说，分类网络面对一张经过超分增强的图片，理应比面对一张糊成一团的低分辨率图片表现更好。\n整体流程可以概括为：模糊图片 → SR修复 → 归一化 → 分类\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 class MultiTaskNet(nn.Module): def __init__(self): super().__init__() self.sr = SRNet() self.classifier = ClassifyNet() self.normalize = transforms.Normalize( (0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010) ) def forward(self, x): sr_out = self.sr(x) sr_norm = self.normalize(sr_out) cls_out = self.classifier(sr_norm) return sr_out, cls_out 网络结构非常简洁——SRNet和ClassifyNet前后串联，中间加了一层CIFAR10的归一化（因为分类网络是在归一化后的数据上训练的，加上归一化才能串联两个网络的进出口）。\n参数共享 SRNet和ClassifyNet共享了相同结构的Encoder（Conv2d(3, 64, 3, padding=1) + ReLU）。两个任务的第一层特征提取是通用的，无论是用于超分辨率还是分类，初始的浅层特征（如边缘、纹理）都是共通的。\n这种设计也意味着在联合微调时，Encoder的梯度会同时来自两个任务的损失函数，相当于两个任务在底层特征上\u0026quot;协商\u0026quot;出一个对双方都更好的表示。\n联合微调 1 2 3 4 # 训练损失 sr_criterion = nn.L1Loss() cls_criterion = nn.CrossEntropyLoss() loss = lambda_sr * loss_sr + lambda_cls * loss_cls 损失函数采用了最直接的加权求和策略：超分辨率的L1Loss和分类的CrossEntropyLoss各乘以权重系数后相加。两个lambda都设为1.0，让两个任务的损失在同一个量级上竞争。虽然课题鼓励设计\u0026quot;互促损失函数\u0026quot;，但在实践中我发现这种简单的加权组合已经能取得不错的效果了（其实是调参太累）。\n最终效果 搭建完微调框架后，多任务学习的成果可以说非常喜人：\n1 2 3 清晰图直接分类: 85.XX% (上限) 低分辨率图直接分类: 47.26% (下限) 低分辨率图 → 超分 → 分类: 81.01% (多任务) 结果非常有意思：\n直接用模糊图分类，准确率只有47% 经过多任务学习的 超分→分类，准确率提升到了81%，提升约0.7倍，直逼清晰图分类的85%上限。 这说明超分辨率网络确实在帮助分类网络\u0026quot;看清\u0026quot;图片中的关键特征，两个任务之间的互促效应是非常直观的。\n五、回顾与感想 从12月的一无所知到2月份交出一个完整的多任务学习作业，这大概两个月的时间是我大一上成长最快的一段经历。\n回顾整个过程，几个比较深的感触：\n迭代的思想。对于两个独立的task，先搭一个最简单的baseline跑出结果，确认流程没问题后再逐步迭代。如果一开始就追求完美的架构，所耗费的时间是不可想象的。 不必\u0026quot;完全准备好\u0026quot;。很多知识是在实践中才真正理解的。ResNet论文看两遍不懂不如自己写一遍残差块。 善用AI工具。gemini和claude在学习过程中帮了很大的忙。尤其是优化了命名规范，提升了代码可读性（至少简化了我20%的代码）。 我很庆幸在入门阶段经历了如此愉快的编译时光，再次感谢校科协的学长们🙏\n","permalink":"https://ardenj.pages.dev/projects/multi-learning/","summary":"\u003ch2 id=\"前言\"\u003e前言\u003c/h2\u003e\n\u003cp\u003e该文章是基于我校 校科学技术协会 woc-python组题目个人解答过程的系统性回顾。\u003c/p\u003e\n\u003cp\u003e项目代码：\u003ca href=\"https://github.com/tianye-J/NJUPT-SAST-Python-WoC-2025.git\"\u003eNJUPT-SAST-Python-WoC-2025\u003c/a\u003e\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e本文主要记录学习和方法迭代的过程，详细代码实现请查阅代码库。\u003c/p\u003e\u003c/blockquote\u003e\n\u003ch3 id=\"题目简介\"\u003e题目简介：\u003c/h3\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003e任务背景与目标\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e本项目旨在探索多任务学习 (Multi-Task Learning) 在计算机视觉中的应用。核心目标是通过联合网络的设计，实现底层视觉（图像重构）与高层视觉（语义理解）两个任务的相互促进 (Mutual Promotion)。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003e基础任务定义 (Single-Task Baselines)\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e网络需从零开始搭建与训练,完成以下两个独立任务：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cdiv class=\"chroma\"\u003e\n\u003ctable class=\"lntable\"\u003e\u003ctr\u003e\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"lnt\"\u003e1\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e2\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e3\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e4\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e5\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e6\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e7\n\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\n\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-text\" data-lang=\"text\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    Task 1：底层图像恢复 (Low-level Vision)\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    任务内容：任选一种退化图像修复场景（包括但不限于超分辨率、去噪、去雾、低光增强等）。\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    评估指标：PSNR 与 SSIM，需在验证集上具有合理表现。\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    Task 2：高层图像分类 (High-level Vision)\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    任务内容：基于 CIFAR 数据集的图像分类。\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    评估指标：Accuracy（最低要求界定为 60%）。\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\n\u003c/div\u003e\n\u003c/div\u003e\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003e多任务联合优化约束 (Multi-Task Constraints)\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e在跑通单任务 Baseline 后，需构建多任务联合网络（例如 Task 1 辅助 Task 2，或反之），且必须满足以下硬性约束：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cdiv class=\"chroma\"\u003e\n\u003ctable class=\"lntable\"\u003e\u003ctr\u003e\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"lnt\"\u003e1\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e2\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e3\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e4\n\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\n\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-text\" data-lang=\"text\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e1.架构轻量化与一致性：多任务分支需与单任务网络结构保持高度一致，禁止大幅增加参数量。\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e2.鼓励采用参数共享 (Parameter Sharing) 或引入轻量的交互通信模块。\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e3.微调策略 (Fine-tuning)：在单任务预训练的基础上，通过微调分支头或特征层来实现融合。\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e4.损失函数创新：鼓励设计具有创新性的互促损失函数 (Mutual-promoting Loss) 来平衡两个任务的梯度。\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\n\u003c/div\u003e\n\u003c/div\u003e\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch3 id=\"最终效果\"\u003e最终效果：\u003c/h3\u003e\n\u003cp\u003e\u003cimg alt=\"对比图\" loading=\"lazy\" src=\"/projects/multi-learning/judgement.png\"\u003e\u003c/p\u003e","title":"深度学习入门：PyTorch零基础到多任务联合微调"},{"content":" Photo taken in real life :)\nAbout Me Hi, I\u0026rsquo;m Jiang Jinghang (Arden), a Robotics Engineering student at NJUPT (Nanjing University of Posts and Telecommunications).\nI\u0026rsquo;m currently focused on Federated Learning and Domain Adaptation / Domain Generalization, exploring how models can generalize across heterogeneous data distributions and unseen domains.\nAreas of Interest Current Focus — Federated Learning, Domain Adaptation / Generalization Future Interests — Reinforcement Learning, Interpretability, Multimodal Real-time Generation, World Models Contact GitHub: tianye-J Email: jjh2444972201@gmail.com, jjh2444972201@163.com ","permalink":"https://ardenj.pages.dev/about/","summary":"\u003cdiv class=\"about-illustration\" aria-hidden=\"true\"\u003e\n  \u003cimg src=\"/images/portrait.png\" alt=\"\" loading=\"lazy\" draggable=\"false\"\u003e\n\u003c/div\u003e\n\u003cdiv class=\"page-epigraph\"\u003e\n  \u003cp class=\"epigraph-text\"\u003ePhoto taken in real life :)\u003c/p\u003e\n  \u003cp class=\"epigraph-source\"\u003e\u003c/p\u003e\n\u003c/div\u003e\n\u003ch2 id=\"about-me\"\u003eAbout Me\u003c/h2\u003e\n\u003cp\u003eHi, I\u0026rsquo;m \u003cstrong\u003eJiang Jinghang (Arden)\u003c/strong\u003e, a Robotics Engineering student at NJUPT (Nanjing University of Posts and Telecommunications).\u003c/p\u003e\n\u003cp\u003eI\u0026rsquo;m currently focused on Federated Learning and Domain Adaptation / Domain Generalization, exploring how models can generalize across heterogeneous data distributions and unseen domains.\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"areas-of-interest\"\u003eAreas of Interest\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eCurrent Focus\u003c/strong\u003e — Federated Learning, Domain Adaptation / Generalization\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eFuture Interests\u003c/strong\u003e — Reinforcement Learning, Interpretability, Multimodal Real-time Generation, World Models\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch2 id=\"contact\"\u003eContact\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003eGitHub: \u003ca href=\"https://github.com/tianye-J\"\u003etianye-J\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003eEmail: \u003ca href=\"mailto:jjh2444972201@gmail.com\"\u003ejjh2444972201@gmail.com\u003c/a\u003e, \u003ca href=\"mailto:jjh2444972201@163.com\"\u003ejjh2444972201@163.com\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e","title":"About"}]