时空融合的癫痫异常放电检测
头皮脑电这条线依托神经信息教育部重点实验室(与成都脑科学临床研究院、 中国医学科学院神经信息单元 2019RU035 协同)做的,主方向是癫痫样放电自动检测。 它给了一个很少见的训练:输入是噪声很大、标注很贵、错一次后果很重的信号。
这套模型叫 TSG-Transformer(Temporal–Spatial Graph Transformer), 做头皮脑电里的癫痫样放电(IED)检测。它在 TUEV v2.0.1 官方评估集上拿到 accuracy 93.58%、specificity 94.91%、sensitivity 92.14%、F1 93.26%、AUC 98.29%, 和六条基线放在同一套预处理与评估协议下比,accuracy、specificity、F1、AUC 四项点位最高。
它真正想解决的不是「把波形认得更准」——人眼看过两次棘慢复合波就认得出来, 真正麻烦的是一条放电是怎么从电极之间铺开来的,以及真正说话的其实只有几个导联。 论文里那三个任务特性(多尺度波形、沿通路传播、通道稀疏)直接对应三段结构: 多尺度时间编码器、PLV 引导的多跳注意力、自适应局部-全局图池化。这一页就按这条线讲一遍。
这条线由两半组成,谁也不是另一半的附属品。模型侧是上面这套结构; 工程侧是配套的 PyQt 检测客户端,EDF 解析、切片、推理、复核、统计这条链路上没有一步是买来的。 数据用 Temple University Hospital EEG Corpus(TUEV v2.0.1), 官方评估集 159 名受试,训练与评估在受试层面不重叠。
波形不难,难的是电极之间怎么连
任务是在长程脑电里找癫痫样放电。放电埋在几十分钟甚至几小时的记录里,人工标注慢、贵, 不同阅片人之间的差异也不小:八位专家给 13,262 个候选放电打分,两两一致率只有 72.4%, Gwet κ 48.7%,只到 fair。所以自动检测要抢的先不是精度,是人力。
训练与评估用 Temple University Hospital EEG Corpus(TUEV v2.0.1):官方划分训练 359 名受试、 评估 159 名,两个划分的受试互不重叠。预处理之后切成 13,044 个 1 秒片段, 其中阳性 6,191、阴性 6,853,接近平衡。
导联取标准 22 导 TCP 双极 montage 去掉含耳电极的 A1–T3 与 T4–A2,留下 20 条双极导联, 采样率 250 Hz,每个片段 250 个采样点。标签侧把棘慢复合波、广泛周期性放电、 偏侧周期性放电并为正类,把眼动、伪迹、背景并为负类。
六步预处理是一条流水:单极转 TCP 双极,四阶零相位 Butterworth 做 0.5–49 Hz 带通,
按标注切不重叠的 1 秒片段,逐片段逐通道 z-score。
之后用复 Morlet 小波做连续小波变换(cmor2.0–2.0,32 个频点铺满 0.5–49 Hz,
其中 12 个集中在 10–30 Hz 提高分辨率),最后在 10–30 Hz 上算通道间的 PLV。
尖波和慢波压根不是一个时间尺度
IED 是几十到几百毫秒的瞬态事件:棘成分的上升沿只有几毫秒,跟在后面的慢波却能拖几十到几百毫秒。 一条一维卷积只有一个感受野,想在一秒片段里同时装下「几毫秒的陡」和「几百毫秒的缓」,做不到。
所以第一段是多尺度时间编码器,思路来自 InceptionTime: 三条并行一维卷积分支,kernel 取 8 / 16 / 32,分别抓短、中、长三种尺度; 每条分支是卷积、BatchNorm、激活。 激活选 LeakyReLU(负斜率 0.2)是有意的——放电的负相在双极导联上往往比正相更有定位意义, ReLU 会把负半轴直接砍成零,等于丢掉一半判别信息。
再给三条同样核大的并行 max-pool 提供互补表示:保留各尺度的峰值响应, 而不是把所有位置压成一个均值。均值会把「这个时刻正好有个尖波」直接抹平。 三条分支沿时间维拼起来之后线性投影到 d_model。
这里还有一条贯穿全网的约束:每条通道共用同一个编码器,参数不按通道复制; 后面的掩码注意力、两个 GIN、Top-K 选择和全局池化头都对通道索引保持置换等变或置换不变, 也没有用任何位置编码或电极嵌入。这一条在后面解释「为什么它挑出来的导联有意思」时会回来。
相位锁住的才算通路,隔着头皮远近不算
放电不是每个电极各自响一下,而是沿着致痫网络的功能通路扩散。 于是「一起抖」有两种含义:振幅大,或者相位锁定。前者只看能量就够了,后者才是连接关系。 拓扑不是事后画出来给人看的图,是从信号本身的相位关系里算出来的。
20 个导联两两配对,在 10–30 Hz 带内取复小波系数的瞬时相位,对每个通道对算 PLV(相位锁定值):
PLV(i,j) = | (1/N) · Σ exp( j · ( φ_i(n) − φ_j(n) ) ) |, N = 250
完全随机的相位关系趋于 0,完全锁相趋于 1。得到的是一张 20×20 的加权邻接,边权就是 PLV 值—— 不是「相关所以相似」,而是「这两个导联的相位真的锁住了」。 20 个导联两两配对,去掉自环后是 190 条候选边。
但 PLV 只量到了直接耦合。真实通路常常是 A 到 B 再到 C,B 是个中继, 只看一跳就会漏掉隔着一个中继的 C。所以还要两步才成图。 第一步是按每段保留最强的一批边做二值化,阈值 τ = 40% 是扫出来的最优: 从 10% 到 90% 全扫过,非单调,40% 处 accuracy 和 AUC 同时到顶。
M(i,j) = 1 if rank↓( PLV(i,j) ) / N_E ≤ τ, 否则 0
第二步是把这张二值矩阵做矩阵幂扩展,递归地把多跳连通关系也显式建出来:
M⁽ˡ⁾ = 𝟙[ ( M⁽ˡ⁻¹⁾ · M ) > 0 ], l = 2, …, n, M⁽¹⁾ = M
取 n = 2,每张 M⁽ˡ⁾ 对角线归零排除自环, 于是 M⁽ˡ⁾(i,j) = 1 就表示 i 与 j 之间存在一条长度为 l 的功能通路。 这一步是「神经通路」四个字里最关键的处理:一跳是直接耦合, 二跳是「经由一个中继通道连上」,把中继这个中间环节补上了。
注意力只往算出来的通路上流
有了多跳拓扑,就把它压进自注意力的掩码里。对时间编码后的特征算 Q / K / V, 对每个跳数 l 造一个加法掩码 E⁽ˡ⁾:M⁽ˡ⁾(i,j) = 1 的位置掩码取 0(可看),否则取 −∞:
Attention⁽ˡ⁾ = softmax( ( Q·Kᵀ / √d_k ) + E⁽ˡ⁾ ) · V
掩码加在 softmax之前,这一点很关键:未连通的位置在归一化之前就被遮住, 不会靠随机初始化偷来一点权重,注意力只沿着 PLV 撑起来的通路流动。跨跳合并时取平均:
Attention_MH = (1/n) · Σ Attention⁽ˡ⁾, l = 1, …, n
取平均而不是拼接,是有意的取舍。两个跳数覆盖的东西不一样: 一跳抓的是紧邻的直接同步电极,也就是 PLV 直接给出的证据;二跳抓的是经由中继的远端。
直接拼接会让二阶信息压过一跳,而一跳恰恰是整个拓扑的证据来源;取平均等于让两条跳各占一半话语权。 合并之后走残差与 LayerNorm,再过一个 GELU 前馈层收尾。
这一步和已有做法的区别值得说清楚。EEG-GCNN 那类脑电图网络只在一跳邻域上聚合, 中继通道这个中间环节被跳过了;BIOT 那类跨域生物信号 Transformer 的注意力完全不带拓扑掩码, 通道之间该不该交换信息是靠学出来的。
V2IED 是表里唯一专门为 IED 设计的,它的空间分支用固定的三维通道拓扑嵌入,对所有导联一视同仁。 本模型把「该不该交换」从「学」换成了「先算出来再约束」: 直接耦合和经由中继的耦合,都在注意力开合之前就被拓扑矩阵定好了。
收益在消融里被单独切出来验证过:把 PLV 多跳注意力换成普通自注意力,AUC 掉 2.22 个点。 这 2.22 个点全部来自「拓扑先验」和「中继通路」这两件事本身。
真正说话的只有几个导联
通道稀疏这个特性决定了一件取舍:放电主要集中在致痫区上方或邻近的少数导联, 其余大片通道装的都是背景活动和伪迹。把所有通道一视同仁地送进分类器,等于稀释判别信号; 但只挑几个通道又会丢掉整张图的上下文。最后一段做成局部-全局双路图池化, 两条路并行再融合。
第一路是局部特征池化。用 GIN 当节点重要性函数,对节点特征和 PLV 加权邻接给出每个通道一个标量分数, 按局部保留比 r₁ = 0.3 选出 K₁ = 6 个通道:
s = GIN(X, A), X_ch1 = X_idx ⊙ s_idx, A_ch1 = A_(idx,idx)
第二路是全局拓扑池化,保整张图的统计。用一个可微的 soft assignment 矩阵 P = softmax( GIN(X,A) ) 把 20 个节点软映射到 k₂ = 4 个粗化社区节点, 社区表示 X_coarse = PᵀX,社区邻接 A_coarse = PᵀAP。
融合这一下才是双路的意义所在。P 里与那 6 个保留通道对应的行单独拎出来, 就是连接「细粒度通道」和「粗粒度社区」的跨路矩阵 A_cross, 它把全局社区信息搬回每个被保留下来的通道,再一起过一个可学习投影:
X_fused = σ( [ X_ch1 + A_cross · X_coarse ] · W_V ), σ 为 GELU
于是每个留下来的导联都带着「它所在社区的全局上下文」,而不是孤立地代表自己。 全量保留会稀释关键导联,只做社区粗化又丢掉具体哪个导联在放电, 局部选通道、全局保拓扑、跨路搬运,两头都占。 双路骨架接在分层图池化那条线上(DiffPool / SAGPool / Graph U-Nets), 局部与全局并行的结构则来自 FC-HGNN;差别在于这里的社区分配矩阵和通道打分矩阵都吃 每段自己的 PLV 邻接,不是全库共用一个空间图,也不是硬聚类式的不可导分配。
分类头把 X_fused 沿通道做并行全局最大池化和全局平均池化拼起来: 最大池化抓尖波峰值这种最显著的瞬态,平均池化留整体通道间的协同模式。 两者拼起来再过两层 MLP,出该片段的放电概率。
局部池化那一路还顺手产出了一样比指标更耐用的东西:每个通道的重要性分数。 统计全部 IED 片段里每个通道进 Top-5 的频率,排在最前面的五条是 F7–T3、C4–T4、Fp2–F8、T3–T5、C3–Cz。
这五条全是双极链上的相邻电极对,结构上高度一致,落点集中在颞区与额颞交界, 正是临床看 IED 时最先扫的那片区域。特别值得说的是:整套模型没有给任何电极身份, 也没有电极位置编码,网络对 20 个导联的重排是不变的。 也就是说这个偏好没有任何空间先验能造出来, 它是从这些导联自身的信号和连通性统计里学出来的——不是人告诉模型的,是模型自己挑的。
这套偏好合适的落点是预筛和复核优先级的排序,不是定侧定灶。 放在这个位置上,它给临床的是「先看这几条导联」的提示,让一屏一屏翻的过程有个顺序。
摆在同一套协议上比,才知道涨在哪
对比选了六条代表性方法,全部在同一套预处理和评估协议下复现, 深度学习基线一律用原论文默认超参、不做任务内调参。 它们分别是 SVM 加手工特征(每通道 23 维时频特征,20 通道拼成 460 维)、EEGNet、CNN–LSTM、 EEG-Conformer、BIOT,以及 V2IED——形态学分支加三维通道拓扑嵌入加决策级融合, 是表里唯一专门为 IED 设计的那条。
TUEV v2.0.1 官方评估集上,TSG-Transformer 的 accuracy 93.58、specificity 94.91、 sensitivity 92.14、F1 93.26、AUC 98.29。 这四项都点位最高,相对各自最强的基线分别高 2.55、2.28、2.55 和 1.00 个百分点。
有几处值得单独点出来。sensitivity 92.14 并不是全场最高,EEGNet 有 93.71, 但它的 specificity 只有 79.81,比本模型低了 15.1 个点: 单看召回会得出完全相反的结论,这也是五项指标必须一起摆的原因。 另一处是 SVM 那条线:specificity 92.04 不算差,sensitivity 却只有 54.37, 手工特征路线能撑住特异性,几乎抓不住放电本体, 说明这条线缺的不是更强的分类器,而是把放电的空间传播结构显式建出来。
τ 那条曲线也值得单独看一遍。从 10% 扫到 90% 是非单调的,40% 处 accuracy 和 AUC 同时到顶: 阈值太低,弱连接噪声会累积;太高,有价值的功能连接又被删掉。 40% 是「召回和特异性都不亏」的那个平衡,不是单点冲高。
还有一个数字能给这套架构一个外部尺度上的参照:已有研究里, Persyst 13 放电检测器在长时脑电上与三位熟练判读者标记棘波的表现相当。 同期三家全自动算法用在 20 分钟常规记录上时,特异性不足以直接上临床; 而把检测聚类后交给专家复核,准确率接近常规人工阅片,复核负担还更低。 本模型做的事正互补:它判的是已经切好、已标注的 1 秒片段, 在那种流水线里更像一个二级分类器,而不是终端产品。
从评估集走进院里,最先变的不是准确率
公开库能给出一条漂亮的曲线,临床上没人会因为曲线好看就信它。 这条线现在已经在和临床配合做预实验,落点是一个很朴素的两段式结构:采集端和计算端分开。
采集端在医院侧。脑电由院内采集设备引出,视频脑电或动态脑电视场景而定, 按临床自己的记录习惯走导联方式,原始数据直接以标准 EDF 导出。 片段切分沿用同一套标注:医师在阅片时标出的放电段,就是这批数据的标签来源。 这一端只负责把真实世界的数据原样拿出来,不碰模型、不做任何二次加工—— 一旦采集侧做了预处理,后面就分不清是模型学得好还是上游洗得干净。
计算端放院内本地算。三层原因:数据不出院,合规上先过审; 医师要在一块屏幕上同时看波形和模型判定,回传路径越短,复核时的上下文越接得上; 预实验阶段样本小、迭代快,本地改一次参数就能重跑一批。
两端之间就是一段 EDF 加一份标注。计算端产出逐片段的放电概率、判定, 以及它选中了哪几个导联,回传后由临床医师逐条确认或否决。
模型只出概率,阈值固定,最后由人拍板,医师否决掉的样本回流进下一轮训练。 流程上还压着两条硬规矩:伦理审批与知情同意先走完、原始身份不出院, 以及标签始终来自临床医师、模型不给基准。
配套的 PyQt 检测客户端要回答的是另外几个问题:这个片段为什么被判成放电、判得对不对、 攒起来能不能统计。EDF 解析、单极转 20 导双极、0.5–49 Hz 零相位带通、 按标注切 1 秒片段、逐段标准化,这条预处理和模型侧完全同构,不存在训练一套、上线另一套。 界面上多导联波形同步绘制、时间轴对齐到片段,能看到尖波和慢波长什么样, 也看得到模型盯了哪些通道——那张通道重要性分数直接画在上面。 批量推理给出每个片段的放电概率与判定,人工确认与否决的结果落盘形成可以回流的样本, 正负片段数、逐导联命中分布、逐受试统计一屏看完。
进院之后最容易变的不是准确率,而是阈值和导联习惯: 院里常见的 montage 和 TUEV 不完全一致,PLV 那边按 20 导搭出来的通路,换一套导联就得重新算边。 预实验真正要验的就是这种东西,而不是又刷一遍公开集的分数。
什么才算把一条线做完
三条任务特性直接换来三段结构,不能反过来。 先想「尖波和慢波不是一个尺度」才有多尺度编码器,先想「头皮距离描述不了通路」才有 PLV 多跳注意力, 先想「关键导联只有几个」才有局部-全局双路池化。 反过来先画架构再编理由,模块之间就散,消融也跑不出清晰的因果。
拓扑先验要算出来,不要画出来,也要能调稀疏度。 PLV 那一步看着很「分析」、离模型很远,但它把「哪些电极连成一片」变成了可直接当输入、 也可直接扫描的结构约束。τ 从 10% 扫到 90% 全摆出来,40% 最优; 换成普通自注意力 AUC 掉 2.22,这 2.22 个点就是「拓扑」本身的价。
选通道和保上下文不是二选一,是用跨路矩阵把两者接上。 只粗化到 4 个社区,全局分布有了、具体导联没了;只做 Top-6 选通道, 关键导联有了、整体模式没了。跨路矩阵那一步把社区信息搬回保留通道, 融合之后每个导联都带着自己所在社区的上下文。
证据这个词在两边长得不一样,标准却是一致的:能回溯到原始材料、能被第三方推翻、 三个月后有人翻出来还能撑住。脑电这边,一份证据是一个 1 秒片段的波形、 模型给出的概率、它选中的那几条导联,外加医师的确认或否决。
一条线做完的标志不是指标停在某个数上,而是它开始接受外部约束: 公开的划分、医师的否决、另一家医院不完全一致的导联习惯。 指标是在这些约束之前的东西,过了这一关它才说明得了什么。
顺带说一句:这几条在 Agent 侧也成立
这条线本来和 Agent 没什么关系,做完回头看,两边撞的是同一批约束。 一边是几十微伏的头皮电位,一边是模型的自然语言输出, 共同点是都能给出看起来很像答案的东西,都不能自己证明它对。
处理办法在两边也是同一套:主指标要配一个盯另一头的副指标, 每条输出留一个能否决的口子,每个数字要能归因到具体设计。 这几条在 Multi-Agent 编排运行时 里是准入和验收的一部分。
能力有多强是模型的事,能不能被验证、能不能被推翻,是工程的事。 把后面这件事做实,前面那件事才有被讨论的资格。