跳转至

第 30 课 卷积、注意力、Transformer 与时间分块

RNN 把历史压进状态,卷积沿时间寻找反复出现的局部形状,注意力让相隔很远的位置直接比较。本课沿着这三条路线,理解复杂序列模型为何出现。

适合谁已经完成 RNN、LSTM 与 GRU,希望继续理解现代序列模型的读者
前置知识序列、隐藏状态、神经网络训练、按时间验证与交易边界
建议用时180 分钟,建议分两次完成
本课成果手算一次卷积和一次注意力,并为复杂模型设计逐级消融表

同一种三日形状可能出现在任何位置

研究员小周观察一段二十日行情时,常会注意到局部形状。例如,前两天波动逐渐收窄,第三天成交量放大并向上突破。这个三日形状可能出现在窗口开头,也可能出现在第十天附近。普通全连接网络会把“第 1 天、第 2 天、第 3 天”与“第 10 天、第 11 天、第 12 天”当成不同列,需要为不同位置重新学习权重。

我们更希望制作一枚可以沿时间滑动的印章。它每次查看连续三天,用同一套规则打分。无论形状出现在窗口哪里,只要局部排列相似,分数就会相似。这种沿数据移动并重复使用同一组权重的计算叫作卷积。处理一维时间序列时,常称为一维卷积;由多层卷积组成的神经网络通常简称 CNN。

先用五日收益做一次手算。为了方便,表中的 1 表示 1%。我们设计一枚三日过滤器,权重依次为 -0.5、0 和 0.5。它实际上在比较窗口最后一天与第一天。中间一天暂时不影响分数。

五日收益          -1,  2,  1, -1,  1
三日过滤器权重  -0.5,  0,  0.5

窗口 1  [-1,  2,  1]  得分  (-0.5)×(-1) + 0×2 + 0.5×1  =  1.0
窗口 2  [ 2,  1, -1]  得分  (-0.5)×2    + 0×1 + 0.5×(-1) = -1.5
窗口 3  [ 1, -1,  1]  得分  (-0.5)×1    + 0×(-1) + 0.5×1 =  0.0

第一个窗口从 -1 上升到 1,得到正分;第二个窗口从 2 下降到 -1,得到负分;第三个窗口首尾相同,得到零。真实 CNN 会同时训练许多过滤器,每枚过滤器可以观察收益、成交量、振幅等多项输入。过滤器权重由损失函数学习,研究者无需手工指定,不过这个数字例子揭示了卷积最重要的两点。小窗口负责提取局部模式,同一组权重会在不同位置重复使用。

flowchart LR
    accTitle: 三日卷积窗口沿五日序列滑动
    accDescr: 同一组三个权重先作用于第1到第3天,再作用于第2到第4天,最后作用于第3到第5天,三个得分共同形成局部模式序列
    days["五日输入<br/>-1 2 1 -1 1"] --> w1["窗口 1<br/>第 1 至 3 天<br/>得分 1.0"]
    days --> w2["窗口 2<br/>第 2 至 4 天<br/>得分 -1.5"]
    days --> w3["窗口 3<br/>第 3 至 5 天<br/>得分 0.0"]
    w1 --> features["局部特征序列<br/>1.0 -1.5 0.0"]
    w2 --> features
    w3 --> features

三行 Python 怎样复现这枚滑动印章

下面的代码只完成刚才的三次手算。输入是五个收益数字和三个过滤器权重,输出应为 [1.0, -1.5, 0.0]。它没有训练网络,目的是让读者看清“取窗口、逐项相乘、求和、向右移动”四个动作。

returns = [-1, 2, 1, -1, 1]
kernel = [-0.5, 0, 0.5]

scores = []
for start in range(3):
    window = returns[start:start + 3]
    score = sum(x * w for x, w in zip(window, kernel))
    scores.append(score)

print(scores)

range(3) 让起点依次取 0、1、2,因为五日序列中只能放下三个完整的三日窗口。切片语句取出当前三天,zip 把每项输入与对应权重配成一对,sum 再把三个乘积相加。最后把分数放入列表。真实卷积层会一次处理许多样本、特征和过滤器,还会使用自动求导学习权重,基础动作仍可以追溯到这段循环。

卷积后还会接激活函数、归一化或汇总层。多层卷积能把短形状继续组合成长形状。第一层可能识别三日变化,第二层再把相邻的局部结果组合成更长结构。网络越深,能够覆盖的历史范围越大,同时也更容易过拟合,因此仍要与简单移动平均、线性模型和树模型比较。

时间卷积为何必须尊重先后顺序

图像卷积通常可以同时查看一个像素左边和右边,因为整张图在预测时已经可见。时间序列不同。若我们要在第 10 天结束后形成预测,卷积不能偷偷读取第 11 天。只使用当前与过去位置的卷积叫作因果卷积

实现卷积时经常需要在序列边缘补数,这叫作填充。若照搬图像中的对称填充或居中窗口,模型可能让当前位置连接到右侧未来数据。最直接的检查方法,是保存一份早期输出,再在数据末尾添加几行未来数据。若新增未来行改变了早期预测,时间边界很可能存在问题。

时间卷积网络通常简称 TCN。它常把因果卷积与扩张卷积结合。普通三日卷积查看连续三格;扩张距离为 2 时,它查看第 1、3、5 格;距离为 4 时,它查看第 1、5、9 格。随着层数增加,网络不必逐日经过很长链条,就能覆盖更远历史。

TCN 还常使用残差连接。残差连接允许输入绕过若干层,与新计算结果相加,给梯度提供较短通路。它能帮助较深网络训练,却无法纠正未来填充、错误标签和不合理成本。与 RNN 相比,卷积的各个时间位置可以同时计算,通常更容易并行;它如何聚合长期信息,则由窗口大小、扩张距离和层数共同决定。

当今天想直接询问某个遥远日期

RNN 让第 1 天的信息逐步经过第 2、3、4 天,最后到达第 5 天。即使 LSTM 改善了长期通道,信息仍要沿时间顺序传递。注意力提供另一条路线。今天的位置可以直接与窗口里的每个历史位置比较,并按匹配程度取回信息。

可以把这个过程想成一次图书馆检索。今天的研究问题是一张检索单;每个历史日期都有一张索引标签,也保存一段真正的内容。模型先比较检索单与所有索引标签,再决定从每个日期取回多少内容。

注意力把这三类角色分别称为 Query、Key 和 Value,中文常译为查询、键和值。Query 表达当前正在寻找什么,Key 表达每个位置可以用什么线索被找到,Value 保存匹配以后真正汇总的内容。三者通常由同一份输入经过不同权重变换得到。

名称 在计算中的职责 图书馆类比 时间序列中的直觉
Query 提出当前匹配要求 读者的检索问题 今天正在寻找怎样的历史状态
Key 提供每个位置的匹配线索 每本书的索引标签 每个日期有什么可供比较的特征
Value 保存要被取回的内容 书中真正的内容 每个日期准备贡献给当前表示的信息

用四个日期手算一次注意力

假设今天的 Query 与四个历史 Key 比较后,得到匹配分数 1、2、0 和 1。分数越高,表示当前查询与该位置越相似。为了把这些分数转换成非负且总和为 1 的比例,模型常使用 softmax。softmax 会先把较高分数放大,再统一归一化。上面四个分数经过转换后,大约得到 0.20、0.53、0.07 和 0.20。

假设四个位置的 Value 简化为 -1、0.5、2 和 -0.5。注意力输出就是各项 Value 按权重相乘后相加。

第 1 个位置贡献  0.20 × (-1)  = -0.20
第 2 个位置贡献  0.53 × 0.5   =  0.265
第 3 个位置贡献  0.07 × 2     =  0.14
第 4 个位置贡献  0.20 × (-0.5)= -0.10

最终汇总结果约为 0.105

第 2 个位置匹配权重最高,所以它贡献较大。第 3 个位置权重低,但 Value 数值较大,仍产生一定影响。真实模型中的 Query、Key 和 Value 都是向量,匹配通常通过向量点积计算。把第 \(i\) 个查询和全部键放在一起,常见的缩放点积注意力写成下面形式。

\[ \operatorname{Attention}(Q,K,V)=operatorname{softmax}\left(\frac{QK^{\mathsf T}}{\sqrt{d_k}}\right)V \]

公式中的 \(QK^{\mathsf T}\) 计算查询与各个键的匹配分数,\(d_k\) 是键向量的维度。除以平方根用于防止维度较高时分数过大,softmax 再把分数变成权重,最后乘以 \(V\) 完成加权汇总。初学阶段先掌握这条计算路线即可,无需手推矩阵导数。

自注意力让一条序列内部互相比较

当 Query、Key 和 Value 都来自同一条序列时,这种计算叫作自注意力。每个日期都可以形成自己的 Query,并直接查看其他日期的 Key 与 Value。第 60 天回看第 2 天只需要一次匹配,不必让信息连续穿过五十八次状态更新。

直接连接远距离位置带来计算代价。长度为 \(L\) 的序列需要比较大约 \(L\times L\) 对位置。序列从 100 增加到 200,比较数量大约从一万增加到四万。长分钟序列或全市场资产序列会迅速占用显存和时间,这也是后面引入时间分块和稀疏连接的原因之一。

注意力权重也不能直接升级为金融因果解释。某个日期获得高权重,只说明当前网络在这次前向计算中更多使用了它。多层网络、多个注意力头和后续前馈层还会继续改变结果,共同市场状态也可能同时影响两个日期。权重图适合寻找诊断线索,因果主张仍需要替换输入、删除日期、跨期复现和更严格的研究设计。

为什么同时需要多个注意力头

一套 Query、Key 和 Value 只能形成一种比较空间。多头注意力会并行建立多套变换,每一套叫作一个头。某个头可能更常连接邻近日期,另一个头可能更常连接财报附近,第三个头可能关注收益与成交量组合。训练目标不会保证这些分工恰好对应人类概念,因此“这个头就是趋势”仍需额外验证。

多个头的结果会拼接并再次变换,交给后续网络。头数增加会带来更多参数与计算。若四个头已经足够,继续增加到十六个却只让训练损失降低,验证结果没有改善,额外容量很可能只是在记忆噪声。

Transformer 是一组部件的合作

Transformer 经常与注意力放在一起提到,但一个完整编码器还包含前馈网络、残差连接、归一化和位置信息。注意力负责在不同位置之间交换信息,前馈网络负责对每个位置的表示做非线性变换,残差连接帮助原信息与新信息共同传递,归一化帮助数值保持稳定。

注意力只比较内容,本身不知道谁在前、谁在后。若把同一组输入日期完全打乱,又没有加入位置提示,模型很难区分第一天与第六十天。位置编码会把顺序信息加入每个位置。金融数据还要面对周末、节假日、停牌和不等间隔,位置编号应与交易日历和缺失处理一起设计。

flowchart TB
    accTitle: Transformer 编码器的一层数据流
    accDescr: 序列特征先加入位置信息,自注意力负责位置之间交换信息,残差与归一化保留原输入并稳定数值,前馈网络再逐位置变换,最终形成新的序列表示
    input["历史序列特征"] --> pos["加入位置编码<br/>告诉模型先后顺序"]
    pos --> attn["多头自注意力<br/>不同日期直接比较"]
    pos --> add1["第一次残差相加与归一化"]
    attn --> add1
    add1 --> ff["前馈网络<br/>逐位置非线性变换"]
    add1 --> add2["第二次残差相加与归一化"]
    ff --> add2
    add2 --> output["更新后的序列表示"]

用于逐时预测时,还要考虑因果遮罩。遮罩像一块挡板,使第 10 个位置无法读取第 11 个位置。若整个六十日输入窗口都发生在预测时点以前,编码器可以在窗口内部双向比较,因为这些历史在下单时已经可见;标签期仍必须位于窗口之后。模型内部允许双向观察,不会放宽数据与成交边界。

时间分块为何能缩短长序列

假设输入有 240 根日 K 线。标准注意力需要处理 240 个位置并比较大量位置对。若把每 10 天打包成一块,就得到 24 个较大的位置。每块先把十天的开高低收、成交量和其他特征压缩成一个向量,Transformer 再比较这些向量。这种连续分组常叫作 Patch,可以理解为时间片段。

K 线序列被切成片段,再通过注意力进入预测与风险检查

图中左侧是按时间排列的 K 线,中间把相邻 K 线装入多个时间片段,随后由注意力比较片段,右侧才形成预测并进入风险检查。分块首先降低了序列长度,也让每个位置表达一小段局部形状。单日噪声可能在块内得到一定平滑,模型关注的单位从“一根 K 线”变成“十日形状”。

压缩也会损失细节。重大单日跳空若与九个普通日期混在一起,影响可能被稀释。块长度为 5、10 还是 20,步长是否重叠,都会改变模型看到的时间尺度。五日块接近一周交易节奏,二十日块接近一个月,但这种日历解释只能作为提出候选值的理由,最后仍要在验证期比较,并保留不分块与简单滚动统计基线。

时间分块、序列编码和资产间比较可以装进同一个模型,研究时却不宜一次全部加入。先比较局部卷积有没有增加有效信息,再单独检查长距离注意力,随后加入 Patch,最后才考虑资产之间的关系。每一步都保留前一版作为基线,结果变化才能找到来源。

同一天的不同资产也可以互相比较

前面的注意力沿时间连接不同日期。另一种做法是在同一个交易日连接不同资产,通常称为横截面注意力。例如,模型处理某只汽车股时,可以同时参考当日行业内其他股票、市场指数和供应链公司表示。它试图学习资产之间的相对关系。

若每天包含 500 只股票,两两比较会产生约 25 万个位置对。股票数量还会随上市、退市、停牌和股票池规则变化。历史输入必须使用当时真实可见的股票集合,不能拿今天仍存续的公司名单回填过去,否则会造成幸存者偏差。

模型也可能把行业或市值暴露当作容易利用的捷径。加入横截面注意力以后,应检查行业集中度、市值分布、市场方向暴露和股票池变化。分行业计算、稀疏连接或先聚合行业表示可以降低成本,不过每种简化都会改变假设,需要单独消融。

消融实验怎样回答“复杂部件是否真的有用”

消融实验是逐项拿掉或加入一个组件,观察研究结论怎样变化。它像检修一台由多块零件组成的机器。若同时更换发动机、轮胎和燃料,即使速度提高,也无法知道哪一项起作用。复杂模型研究应一次只改变一个主要部件,并保持数据、标签、时间切分、训练预算、随机种子与交易规则一致。

版本 与上一版相比唯一的主要变化 它要回答的问题
A 线性或树模型基线 复杂序列结构是否有必要
B 加入一维 CNN 可重复的局部形状是否提供增量
C 用 TCN 扩大历史范围 更长的卷积观察范围是否有帮助
D 使用简单自注意力 远距离直接连接是否提供增量
E 在 D 上加入 Patch 分块是否改善效率、稳定性或泛化
F 在 E 上加入横截面注意力 资产之间的关系是否提供额外样本外信息

每一级都应记录参数量、训练时间、预测指标、多个随机种子的变化范围、扣费后组合、换手、风险暴露与故障次数。如果 E 只在一个种子或一个 Patch 长度上领先,邻近长度全部失效,这个部件仍然脆弱。消融的价值在于允许研究者得出“这个复杂部件没有稳定增量”的结论,而不是强迫每一级都胜出。

一张选择表帮助定位起点

模型 主要能力 计算特点 常见风险 适合先问的问题
CNN 用共享过滤器寻找局部形状 易并行,参数相对节省 观察范围受窗口和层数限制 局部 K 线或成交量形状是否重复出现
TCN 用因果扩张卷积覆盖更长历史 易并行,梯度路径较短 填充方向可能泄漏未来 长期信息能否通过卷积层级提取
RNN、LSTM 逐步更新内部状态 符合顺序阅读直觉 长序列较慢,状态可能成为瓶颈 过去信息是否需要持续更新与遗忘
Transformer 让不同位置直接比较 并行度高,长序列成本大 数据需求高,注意力图易被误读 遥远日期之间是否存在可重复联系
Patch Transformer 先压缩局部块,再进行注意力 位置数减少,可整合局部形状 细节损失,块长度敏感 长序列是否能按自然时间尺度分组

这张表用于选择实验起点,不负责给出答案。数据规模很小、特征主要是结构化因子时,线性和树模型可能更可靠;高频长序列、局部形状明确时,卷积值得优先尝试;需要远距离比较且样本充足时,注意力才有更充分理由。最终选择仍要回到相同时间验证与交易约束。

复杂模型最低限度要报告什么

复杂结构的预测指标略有改善,还不足以结束研究。报告至少需要包含简单规则、线性模型、树模型和一个轻量序列基线;所有模型使用相同特征截止时间、标签、验证窗口、费用和风险限制。参数更多的模型应运行多个预先确定的随机种子,展示平均、范围与失败次数。

训练资源也要记录。一个模型每次重训需要多少时间,线上预测延迟多长,显存不足时会怎样失败,依赖库升级后是否还能复现,都会影响实际可用性。如果预测优势很小,却带来十倍换手、十倍计算和更难排查的故障,简单模型可能给出更好的整体方案。

还要专门做时间截断测试。删除预测时点之后的全部数据,早期特征与预测应保持不变;改变窗口末尾以后,过去已经生成的样本不应被重新标准化;因果卷积和遮罩应通过小型人工数组验证。越复杂的网络,越需要用简单数字构造单元测试。

容易弄错的地方

容易出现的做法 为什么会误导 更稳妥的检查
把图像卷积直接搬到行情 对称窗口可能读取右侧未来位置 使用因果卷积,并做新增未来行测试
把高注意力权重解释为因果 权重只描述当前网络中的信息使用 配合输入扰动、删除日期和样本外检验
只报告最好的 Patch 长度 多次尝试后挑最佳会放大选择偏差 预先给出范围,展示邻近长度与无 Patch 基线
同时加入 Patch、新特征和横截面注意力 结果变化无法归因到单一部件 一次只改变一项,建立完整消融阶梯
Transformer 使用更多数据和训练时间 比较条件不同,优势可能来自额外资源 统一数据与预算,并单独报告规模效应
只看最佳随机种子 偶然初始化会被误写成模型能力 预先运行多个种子并报告分布
预测指标提高就直接上线 换手、费用、风险和故障可能吞掉增量 回到账本、压力测试与模拟盘检查

一分钟自测

长度 120 的序列,每 10 天组成一个不重叠 Patch,会得到多少个位置?如果某个注意力位置权重最高,能否据此宣布该日期导致了未来收益?

查看答案 会得到 12 个 Patch 位置。注意力权重高只说明该位置在当前模型计算中被使用得较多,无法单独排除共同原因和其他替代解释,因此不能直接宣布因果关系。

本课术语

词语 先这样理解
卷积 用同一组小窗口权重沿序列寻找局部模式
CNN 由一层或多层卷积组成的神经网络
因果卷积 预测当前位置时只连接当前与过去的卷积
扩张卷积 按一定间隔取样,以较少层数扩大观察范围
注意力 按查询与键的匹配程度加权汇总值
自注意力 Query、Key 和 Value 都来自同一条序列的注意力
Transformer 由注意力、前馈层、残差、归一化和位置信息组成的结构
位置编码 向模型补充序列先后位置的信息
Patch 把连续若干时间位置打包成一个较大单元
消融实验 一次改变一个组件,用来检查它是否提供独立增量

机器学习阶段综合作业

回到你一直使用的毕业研究问题,为它安排三级对照。第一级使用简单规则或线性模型,第二级使用树模型,第三级从 RNN、CNN、TCN 或 Transformer 中选择一个。为每一级写清输入形状、标签时点、训练窗口、验证窗口、测试窗口和可执行成交时点。

随后制作一张消融表。每一行只改变一个组件,并提前写好这个组件值得保留的最低证据,例如多个滚动窗口平均改善、邻近参数仍然稳定、扣费后增量为正、多个种子大部分成功。也要允许最终结论停在简单基线。这张表会直接进入第 33 课毕业报告的模型选择部分。

课后练习

  1. 卷积计算。 五日序列使用三日窗口、步长为 1、不填充,共有几个窗口?若序列长度改成八日,窗口数量又是多少?

    提示与答案五日序列有第 1 至 3、第 2 至 4、第 3 至 5 三个窗口。八日序列共有 `8 - 3 + 1 = 6` 个完整窗口。

  2. 注意力计算。 三个位置的权重为 0.2、0.5 和 0.3,对应 Value 为 -1、2 和 0.5。请计算加权结果。

    提示与答案逐项相乘后相加,结果为 `0.2 × (-1) + 0.5 × 2 + 0.3 × 0.5 = 0.95`。

  3. 时间排错。 一维卷积在生成第 10 天预测时使用了第 11 天输入。最可能的问题是什么,怎样构造测试?

    提示与答案卷积窗口或填充方向没有遵守因果顺序。可以在第 11 天以后替换成极端数值,检查第 10 天及以前输出是否改变。

  4. 设计消融。 研究者同时加入 Patch、横截面注意力和一组新特征后,模型表现提高。请把它拆成能够定位原因的实验顺序。

    提示与答案先固定原特征比较无 Patch 与 Patch,再在胜出结构上单独加入横截面注意力,最后把新特征作为独立版本。所有版本保持时间切分、训练预算和交易规则相同。

  5. 研究判断。 Patch Transformer 在最佳种子上超过线性模型,所有种子的平均结果没有优势,扣费后更差。你会怎样写结论?

    评价要点当前证据不足以支持保留复杂模型。应完整报告种子分布与费用结果,检查实现和参数敏感性,并让简单基线继续作为主要方案。只有新的独立数据提供稳定增量,才有理由重新评估。

离开本页前
五日数字已经把几种复杂结构落回可检查的动作。卷积沿时间重复一组权重,注意力让当前位置直接比较历史位置,Transformer 再加入位置、残差和前馈层,Patch 用细节换取更短的序列。每增加一个组件,都回到消融表中单独比较,复杂度才有明确来路。