想象你是一间超大阶梯教室里的一名学生,全班坐着 40 个同学。老师布置了一道讨论题,标准注意力的做法是:每个人都举着纸条跑遍全班,和每一位同学交换意见——这确实不漏掉任何信息,但纸条总次数是 40×40=1600 次。而滑动窗口注意力的想法朴素得多:你只需要和前后左右的几位邻居传纸条,远处的消息会通过“同桌传给同桌的接力链”慢慢传到你耳中。于是纸条总数降到 40×5=200 次,省下了八成的功夫。当然,接力传递有延迟,边界上的同学也可能被孤立,所以我们还需要“换队形”(窗口移位)和“偶尔全班广播”(全局注意力融合)来补救。这篇文章就借这场“传纸条”的游戏,带你完整体验滑动窗口注意力从原理到落地的一整套思路。
对从业者而言,滑动窗口注意力是长文本模型和视觉大模型里做“降本增效”的基石:听懂它,你就理解了 Swin Transformer、Longformer 等主流架构为什么能既跑得动、又看得远。
目录
可视化演示
展示滑动窗口注意力的局部感受野机制、窗口移位跨层信息传递,以及复杂度从O(n²)降至O(n×w)的效率优势。
本节配有交互动效(进入视口后自动加载,约 3KB)。
滑动窗口注意力 每个Token只关注窗口大小w内的邻近位置,注意力矩阵从n×n缩小为n×w带状矩阵 窗口移位机制让相邻层窗口错位,实现跨窗口信息传递 复杂度从O(n²)降至O(n×w),w为常数不随序列长度增长 Complexity: O(n×w) vs O(n²) 常用窗口大小为256-512个token。
局部感受野:先照顾身边的同学
上课铃响,老师让大家传纸条讨论问题。你有没有想过,为什么我们不跟全班每个人都传一遍?因为绝大多数有用的信息来自身边的同学——同桌能看到你草稿纸上的符号,前后排能补上你漏听的话,而坐在教室另一角的人,你连他的名字都未必知道。这个直觉,就是滑动窗口注意力的出发点:在信息处理中,距离近的 Token 之间往往有更强的关联,这就是“信息局部性先验”。
在 Transformer 里,每一个 Token(可以理解为一个词或一个图像块)都带着三个角色:Query(负责发问)、Key(负责回应)、Value(负责提供内容)。标准注意力让“每个 Token 问遍所有人”,而滑动窗口注意力规定:我只问前后距离不超过 $w/2$ 个位置的邻居。这个“只问邻居”的规则,并不会改变 QKV 的计算方式,只需要额外加一张“允许通信”的名单——掩码矩阵 $M$。
掩码矩阵 $M$ 的大小是 $n \times n$,第 $i$ 行第 $j$ 列的数字表示 Token $i$ 是否能与 Token $j$ 说话:距离在窗口内记 1,窗口外记 0。注意力分数在 softmax 之前先与掩码逐元素相乘,窗口外的分数变成负无穷,softmax 之后权重自然归零。这样,每个 Token 的输出就只由窗口内的邻居加权求和而来。
回到教室里,掩码矩阵 $M$ 就是那张“座位距离表”——它告诉你哪些同学在传纸条半径内。有了这张表,全班 40 人的广播式交流,就变成了每个同学只跟前后左右几个人低声细语。这正是滑动窗口注意力最核心的一步棋。
- 查询与键的点积计算“当前的 Token 提问($Q$)”和“候选 Token 应答($K$)”之间的相似度分数。
- 缩放因子除以维度 $d$ 的平方根,防止内积过大导致 softmax 输出走向极端。
- 掩码矩阵$M$ 是 0/1 矩阵,窗口内为 1,窗口外为 0。
- 逐元素相乘窗口外的分数被压成负无穷,softmax 后权重为 0。
- 加权聚合只把窗口内 Token 的值向量 $V$ 加权求和。
复杂度下降:从全班广播到邻里闲聊
我们不妨算一笔账:全班 40 人,每人跟其他 39 人传纸条,总次数约 40×39≈1600 张。标准注意力一模一样——$n$ 个 Token 两两打分,需要 $n^2$ 次交互。当 $n$ 上升到 1 万(一篇长文章),$n^2$ 就是一亿次交互,GPU 直接冒烟。这就是“二次复杂度问题”:序列长度翻倍,计算量翻四倍。
滑动窗口把规则改成了“每人只跟左右 $w$ 人传”。假设 $w=7$,每人只需写 7 张纸条,总数是 $n \times w$;对一万 Token 的序列,只有 7 万次交互,比一亿少了三个数量级。用大 O 记号表达,标准注意力是 $O(n^2 d)$,滑动窗口是 $O(n w d)$。由于 $w$ 和 $d$ 都是固定常数,复杂度只随序列长度 $n$ 一次方增长——这就是“线性复杂度”。
传纸条从 1600 张降到 280 张,省下的是真金白银的算力。而这一切只因为你加了一条规则:只看身边的同学。这也是滑动窗口能支撑十万 Token 长文本的根本原因——省下来的钱,足够让你处理更长的文章。
- 标准注意力的次数$n$ 个 Token 两两组合,共 $n^2$ 个分数对。
- 窗口注意力的次数每个 Token 只和 $w$ 个邻居打分。
- 两者之比窗口方案省下的倍数等于 $n / w$。
- 线性化的前提$w$ 是常数(通常 7~64),$n$ 增长时计算量只呈线性增长。
窗口大小权衡:把传纸条半径调到多大合适
现在要回答一个很实际的问题:传纸条的“半径”(窗口大小 $w$)到底定多少?半径定成 3,消息传得近但轻松;半径定成全班,信息完整但累趴。$w$ 就是这条传纸条半径,它同时决定了两件事:每个 Token 能感知的上下文范围,以及总计算量 $n \times w$。两者是一对天然的矛盾。
窗口太小,每个 Token 只见得着身边一两个位置。长句子里主语和谓语动词隔着十几个词,光靠窗口根本联不上,语言建模就变成“盲猜”。窗口太大,$w$ 逼近序列长度 $n$,每个 Token 几乎能看到全文,复杂度又退回平方级,省力效果完全消失。定义覆盖比例 $r = w/n$,可以清楚地看到这个退化过程:
实践中,语言模型常用 $w=7$ 或 $16$,视觉模型常用 $7 \times 7$ 的 patch 窗口。挑选原则叫做“语义粒度匹配”:窗口要能覆盖一个完整的语义单元——一个短语、一个物体的一部分。就像传纸条的半径,得让一次传话刚好覆盖一个“完整的小话题”,而不是大半个教室。
- 覆盖比例$r$ 表示窗口覆盖全文的比例,越接近 0 越“局部”。
- 窗口过大的退化$w$ 接近 $n$ 时,掩码几乎全为 1,计算量回到平方级。
- 窗口过小的失联$w=1$ 时每个 Token 只看得见自己,上下文全部丢失。
窗口移位机制:隔一层换一次队形
固定窗口传纸条有个尴尬:如果把全班按 5 人一组切块,1~5 号互相认识,6~10 号互相认识,但 5 号和 6 号之间隔着一堵看不见的墙——边界同学完全孤立。消息传到最后,永远跨不过每组的边界。这就是固定窗口的“信息孤岛”问题:窗口边界上的 Token 无法和隔壁窗口交流。
Swin Transformer 的解法非常巧妙:在第奇数层,把窗口整体偏移 $\lfloor w/2 \rfloor$ 个位置。原本在窗口边界的 Token,移位后落在新窗口的中央,就能和隔壁组的 Token 交流了。偏移量写成公式,偶数层不偏移,奇数层偏移半个窗口:
这就像做广播操整队:第一遍按 1~5 排手拉手,第二遍整体错开半步,5 号就能牵到 6 号的手。队形没变,边界却被打通了。窗口移位让“跨窗口信息流”得以建立,是局部注意力架构里必不可少的一环。
- 层数记号$t$ 表示当前是第几层 Transformer 编码器。
- 偏移量偶数层偏移 0,奇数层偏移 $\lfloor w/2 \rfloor$。
- 窗口起点第 $i$ 个窗口的起点在偏移后右移 $\delta_t$ 个位置。
- 宽度不变移位只改位置、不改变窗口大小,因此计算量保持不变。
多层堆叠作用:接力棒传遍全班
单靠一次传话,消息只能走一小段。但如果你传给同桌、同桌再传给她的同桌,消息就能穿过整间教室。Transformer 的多层堆叠正是这个接力过程:每一层都做一次窗口注意力,信息就在序列上“向前多走一段”。
设窗口大小为 $w$,堆叠 $L$ 层。第 1 层的输出已经“看”过窗口内 $w$ 个位置的输入;第 2 层再基于这些输出看新的窗口,等效感知范围向两边各扩展 $w-1$ 个位置。递推下去,第 $L$ 层的等效感受野是:
以 $w=7$ 为例,堆到 12 层感受野就是 $1 + 12 \times 6 = 73$,堆到 24 层接近 145。这解释了为什么局部窗口模型也能处理长距离依赖:传纸条接力不需要每个人都认识全班,只要路线通畅,消息早晚传遍整间教室——而“路线通畅”的前提,是模型层数足够深、每层窗口足够合理。
- 基座不考虑任何层时,Token 只能感知自己这 1 个位置。
- 每层扩展每叠一层,感受野向两边各扩展 $w-1$ 个位置。
- 递推求和$L$ 层累加后得到闭合解。
全局注意力融合:给全班广播留一条通道
接力传话虽好,但要是老师临时通知“下课时间提前 10 分钟”,靠一张纸条接力传完,估计已经上课了。这时候最有效的做法是站起来吼一嗓子,让全班都听见。信息处理也一样:局部交流负责日常的细碎关系,但有些信息必须“一键直达”。
纯窗口注意力缺少任意两点之间的直达路径。比如指代消解——“2019 年诺贝尔物理学奖得主……他”——那个“他”和前面的描述可能隔着几百个 Token,单纯靠接力传话容易在中途失真。这就是“纯局部局限”。主流架构的解法是混合注意力设计:在局部窗口之外,额外引入一个全局分支,对稀疏采样的 $s$ 个 Token($s \ll n$)做全交互,两路输出相加:
另一种常见做法是“阶段式融合”:每隔 $K$ 层插入一层完整的全局注意力,其余层全部用窗口注意力。无论哪种方式,本质上都是“传纸条讲效率,广播兜底”——窗口注意力负责日常细碎交流,全局注意力负责关键时刻的直达通道,两者配合才能既省力又不误事。
- 局部分支用窗口 $w$ 计算常规的滑动窗口注意力。
- 全局采样只选 $s$ 个代表性 Token 作为全局锚点,$s$ 远小于 $n$。
- 全局分支每个 Token 与这 $s$ 个锚点做标准注意力。
- 融合相加两路输出相加,再经过投影与残差连接。
AI 应用场景
超长文档问答与摘要
阶段:模型推理优化
解决的问题:传统注意力处理 10 万 Token 的法律合同或学术论文时,需要百亿次交互,GPU 显存和延迟都扛不住。滑动窗口把交互降到线性规模,配合稀疏全局锚点,让长文档处理真正落地。
具体案例:某法律科技公司的合同审查工具,输入整本合同后用窗口注意力逐段编码,每 4 层插入一次全局注意力,单张 A100 即可处理完整卷宗,审查耗时从分钟级降到秒级。
高分辨率视觉模型中的 Swin Transformer
阶段:模型架构设计
解决的问题:图像是像素点阵,整图自注意力的复杂度随像素数平方增长,高清大图完全算不动。滑动窗口把注意力限制在局部 patch 内,配合窗口移位打通跨窗口信息流。
具体案例:在医学影像分割任务中,Swin 将 1024×1024 的 CT 切片切成 7×7 的 patch 窗口逐块建模,再通过移位窗口让相邻区域的信息互相渗透,显存占用下降约 40%,分割精度反而更高。
流式语音识别
阶段:在线服务部署
解决的问题:实时语音助手要求“边说边识别”,不能等整句话说完再用全局注意力。滑动窗口天然只依赖历史与当前片段,满足因果性约束,实现低延迟逐字输出。
具体案例:某智能客服系统在流式解码时使用窗口大小为 64 的因果注意力,每识别一个字只需计算最近 64 帧,首字延迟降低到 300ms 以内,同时保持接近全局模型的准确率。
Python 演示
import numpy as np def softmax(x, axis=-1): e = np.exp(x - x.max(axis=axis, keepdims=True)) return e / e.sum(axis=axis, keepdims=True) def standard_attention(Q, K, V): """标准注意力: 每个 Token 与全部 Token 交互, 复杂度 O(n^2 d)""" d = Q.shape[-1] scores = Q @ K.transpose(0, 1, 3, 2) / np.sqrt(d) return softmax(scores) @ V def window_attention(Q, K, V, window_size): """滑动窗口注意力: 用掩码把窗口外的相似度分数置为负无穷""" n = Q.shape[-2] half = window_size // 2 dist = np.abs(np.arange(n)[:, None] - np.arange(n)[None, :]) mask = (dist <= half).astype(np.float32) scores = Q @ K.transpose(0, 1, 3, 2) / np.sqrt(d) scores = scores * mask - 1e9 * (1 - mask) return softmax(scores) @ V def receptive_field(num_layers, window_size): """L 层堆叠后, 一个 Token 能间接感知的最远距离""" return 1 + num_layers * (window_size - 1) if __name__ == '__main__': np.random.seed(0) n, d = 64, 16 Q = np.random.randn(1, 4, n, d) K = np.random.randn(1, 4, n, d) V = np.random.randn(1, 4, n, d) out_full = standard_attention(Q, K, V) out_win = window_attention(Q, K, V, window_size=n) print('window_size = n 时退化一致:', np.allclose(out_full, out_win, atol=1e-6)) for L in (1, 2, 4, 8, 12): print(f'L={L:2d} 层, w=7, 等效感受野 = {receptive_field(L, 7)} 个 Token')
dist = np.abs(np.arange(n)[:, None] - np.arange(n)[None, :])构造 n×n 的“座位距离表”,第 i 行第 j 列是 Token i 和 Token j 的距离。mask = (dist <= half).astype(np.float32)距离在窗口内记为 1,窗口外记为 0,形成掩码矩阵。scores = scores * mask - 1e9 * (1 - mask)窗口外分数变成负无穷,softmax 后权重归零,等价于“不给窗外同学传纸条”。return 1 + num_layers * (window_size - 1)等效感受野公式 $\mathrm{RF}_L = 1 + L(w-1)$ 的实现。for L in (1, 2, 4, 8, 12):直观展示层数翻倍时感受野的线性增长。
常见误区
误区窗口设成 3 甚至 1 最好,因为等效感受野公式告诉我,层数够多总能覆盖很远,窗口小又省算力,何乐不为?
正解窗口过小时,每层能聚合的上下文质量严重下降,信息逐层传递的损耗和偏差都会被放大。等效感受野只表示“能追溯到的范围”,不等于“高质量地用上了这些信息”。就像传纸条只传给同桌,虽然接力也能传遍全班,但消息被几十个人转述后,最后往往面目全非。实践中窗口通常取 7~64,过小的窗口需要更多层才能补回来,可能反而更贵。
为何常见:看到 $\mathrm{RF}_L = 1 + L(w-1)$ 就觉得窗口小也能靠深层补救,忽略了每层都要靠有限邻居压缩信息、层层传递会有信息损失。
误区滑动窗口是 O(n) 复杂度,那我是不是可以把输入序列拉到百万 token 而不增加任何成本?
正解O(n) 只是注意力交互次数。实际部署还受显存、KV Cache、前馈网络、激活值等因素限制。窗口注意力只是把“平方级瓶颈”缓解为“线性瓶颈”,线性增长的斜率(w×d)依然不小:序列从 1 万到 2 万,计算量近似翻倍。传纸条从 40 人传到 80 人,总数确实只翻倍而不是翻四倍,但你还是得写 80×5=400 张纸条,不可能零成本。
为何常见:把“复杂度降为线性”误读成“成本可忽略”,忽略了线性增长本身仍然随序列长度增加而增加。
误区Swin 的窗口移位不就是把序列整体平移几个位置再切一遍吗?这有什么难的?
正解直接移位切块后,序列边缘会产生不完整的窗口。Swin 的实际做法是“循环移位 + 注意力掩码”:把右端多余块搬到左端拼成完整窗口,同时用掩码阻止原本不相邻的区域互相看见。这一步很关键但容易被忽略——就像整队换排头,队伍末尾的人被挪到最前面,队列虽然整齐,但中间被迫挨着的人其实互相不认识,得拉个帘子隔开。
为何常见:只看了“窗口偏移”的示意图,没深入了解底层实现还要处理边缘拼接与注意力掩码。
误区既然滑动窗口加多层堆叠能覆盖很远的范围,那干脆全用局部窗口,彻底放弃全局注意力。
正解纯窗口注意力缺少“任意两点直达”的路径。需要精确全局配对的任务(如机器翻译的源-目标对齐、跨越超长文本的指代消解),纯局部方案会力不从心。主流做法是混合:每隔几层插一个全局注意力,或用稀疏全局采样。接力传话能传遍全班,但老师要点名提问某个远处同学时,还是得直接喊一嗓子——全局通道该留还是得留。
为何常见:过度关注“省算力”的好处,忽略了局部窗口在长距离精确对齐上的结构性不足。
面试题
Q1. 滑动窗口注意力相比标准注意力的最大改进是什么?
- A.提升每个Token特征维度
- B.降低计算复杂度为线性← 正确答案
- C.消除所有池化层结构
- D.显著增加编码器层数
答案:B。滑动窗口的核心改进是把 “每个 Token 与所有 Token 交互” 换成 “只与窗口内邻居交互”,复杂度从 O(n²) 降到 O(n·w)。A 是维度设计问题,C 与层结构无关,D 是堆深度的手段,都不是滑动窗口的本质。
Q2. 在滑动窗口注意力中,窗口外 Token 的相似度分数会被设置成什么?
- A.固定为数字零
- B.固定为数字一
- C.置为负无穷大← 正确答案
- D.原样保留不变
答案:C。掩码机制把窗口外的分数置为负无穷,经过 softmax 后权重自然为 0。如果设成 0,softmax 后仍会分到权重;设成 1 会干扰归一化;原样保留则窗口形同虚设。就像传纸条名单上没你的名字,消息根本到不了你手里。
Q3. 设窗口大小 $w=7$,堆叠 $L=8$ 层,等效感受野能覆盖多少个位置?
- A.四十九个位置← 正确答案
- B.七个左右位置
- C.五十六个位置
- D.六十四个位置
答案:A。代入感受野公式 $\mathrm{RF}_L = 1 + L \times (w-1)$,即 $1 + 8 \times 6 = 49$。B 是单层窗口的范围,C 是 8×7 的错误乘法,D 是 64 也是误算。8 层接力下来,一个 Token 能间接“看见”49 个位置。
Q4. Swin Transformer 引入窗口移位(shifted window)的主要动机是什么?
- A.大幅度减少模型参数
- B.打破窗口间信息壁垒← 正确答案
- C.加快整体训练速度
- D.避免网络过拟合
答案:B。固定窗口把序列切成分隔的块,边界 Token 无法跨窗口交流,形成信息孤岛。窗口移位让边界 Token 在下一层落入窗口中央,打通跨窗口信息流。它不是减参数、加速或防过拟合的手段。
Q5. 下列哪项不是滑动窗口注意力带来的挑战?
- A.窗口边界信息被隔离
- B.长距离依赖建模受限
- C.计算量随窗口大小升
- D.免除位置编码依赖← 正确答案
答案:D。窗口注意力天然引入边界隔离、长距离建模受限、计算量随 w 线性增加等问题。但它并没有免除位置编码——位置信息是独立注入的机制,与注意力窗口无关,因此 D 不是它带来的挑战。
Q6. 以下哪些做法可以缓解纯局部窗口的视野局限?
- A.堆叠多层编码器层← 正确答案
- B.交替使用移位窗口← 正确答案
- C.间隔K层插入全局← 正确答案
- D.固定使用最大窗口512
答案:ABC。堆叠多层可以通过感受野公式扩大等效视野;移位窗口打破固定边界;每隔 K 层插全局注意力提供直达通道,这三种都是主流方案。D 直接固定一个超大窗口既不现实,也违背了局部注意力的初衷。
Q7. 序列长度 $n=10000$、窗口 $w=16$ 时,标准注意力的计算量约是滑动窗口的多少倍?
- A.约六百二十五倍← 正确答案
- B.约六千二百五十倍
- C.约一百二十八倍
- D.约一万零二百倍
答案:A。标准注意力是 $O(n^2)$,滑动窗口是 $O(n w)$,倍数 $= n/w = 10000/16 = 625$。也就是同样的序列,标准方案要做约 625 倍于窗口方案的计算量。这就是滑动窗口在大规模序列上极具吸引力的原因。
Q8. 在混合注意力设计中,全局分支通常采用什么策略来控制成本?
- A.与全部Token交互
- B.用多个小窗口拼接
- C.稀疏采样部分Token← 正确答案
- D.把窗口规模缩小到三
答案:C。混合注意力的全局分支如果与全部 Token 交互,复杂度又会回到平方级。主流做法是只选 $s$ 个代表性 Token(如 CLS、特殊任务 Token)做全局锚点,$s \ll n$,从而在保留全局通道的同时控制开销。
Q9. 滑动窗口注意力适用的真实场景有哪些?
- A.高分辨率图像分割← 正确答案
- B.超长文档的摘要← 正确答案
- C.流式语音识别← 正确答案
- D.逐词翻译的对齐
答案:ABC。高分辨率图像像素多、超长文档 Token 多、流式语音要求只看历史窗口,都适合滑动窗口。D 逐词机器翻译需要每一步都与源语言全句精确对齐,纯窗口容易漏掉远距离对应关系,应使用全局或混合注意力。
Q10. 设窗口大小 $w=9$,堆叠 $L=6$ 层,等效感受野是多少?
- A.四十九个位置← 正确答案
- B.七个左右位置
- C.五十六个位置
- D.六十四个位置
答案:A。代入公式 $\mathrm{RF}_L = 1 + L \times (w-1)$,即 $1 + 6 \times 8 = 49$。B 是单层窗口的理解误差,C 是 $7 \times 8$ 的误算,D 是按 $w=8, L=8$ 的错误组合。感受野随层数线性扩展,6 层就能覆盖 49 个位置。