← 返回论文阅读室正在排版公式与图表…
PAPER ANALYZER · EST · 学术型精读

EST:把微弱表情变化组织成可以学习的时间结构

Expression Snippet Transformer · 论文、源码、采样与实验协议逐项精读

Yuanyuan Liu、Wenbin Wang、Chuanxu Feng、Haoyu Zhang、Zhe Chen、Yibing Zhan · Pattern Recognition 138 (2023), 109368 · 出版信息 · 19 页作者稿全文 · 公开源码,固定版本 f85a0cdcf9

一句话总结

EST 先在五帧片段内提取局部关系,再在七个片段之间建模,并用预测打乱顺序的辅助任务减少对固定峰值位置的依赖。关键学习点是采样、两级注意力、监督与实验协议。

全部论文精读目录 →

交互:打乱片段后,SSOP的标签是什么?

用三个片段和四种固定排列做小型教学示意,原顺序为1、2、3。选择输入排列,查看整条排列对应的类别标签;不是逐位置预测原编号。真实EST为七个片段、十种固定排列。这里仅演示监督标签生成,不训练网络。

先认清任务:从一段人脸视频到一个表情类别

EST 的输入是一段已经裁剪好人脸的视频,输出是整段视频的基本表情类别。DFEW、AFEW 使用七类表情,包含快乐、愤怒、厌恶、恐惧、悲伤、惊讶和中性;另外两个受控数据集使用六类。这里的“细微变化”指同一视频中变化幅度较小的视觉线索,不能直接等同于专门研究短暂微表情的任务,也不能把七类分类当成复合情绪标注。

与前一篇 ALMT 相比,EST 只使用视觉模态;ALMT 主要预测连续情感分数,EST 预测离散表情类别。二者都用注意力,但注意力处理的对象、监督信号和评价指标不同。学习顺序上的连接是:你已经知道注意力怎样按相关性汇总特征,现在把这个机制放到视频内部,观察“局部几帧”和“全视频几段”怎样形成两级时间结构。

一帧中清晰的眉眼形态能帮助分类,但单帧也可能只是说话时张嘴、转头或遮挡。反过来,连续变化能补充证据,例如嘴角逐渐上扬,而不是某一帧偶然相似。难点在于表情运动常常比头部运动更弱。模型把注意力集中到视觉变化最大的帧,并不保证抓住表情线索。

原文 Figure 1(作者稿第 2 页):左侧普通 Transformer 与右侧 EST 的对照用于说明这个动机。黄色标记表示最高注意力位置,并不是人工提供的真实表情发生区间。读这幅图时,应把“模型注意了哪里”和“哪里对正确预测具有因果作用”分开。

EST 的核心做法分成三步:先将长序列组织成七个短片段;片段内用 AA-SFE 汇总五帧;片段之间用编码器与解码器汇总成视频表示,再通过 SSOP 辅助任务约束学习。阅读时最该抓住的两个问题是:一段内部怎样压缩,段与段之间的关系靠什么训练。

原文摘要用 “intra-snippet” 和 “inter-snippet” 区分两种关系;Section 3.3 将辅助任务称为 “shuffled snippet order prediction”。这三个短引文分别对应片段内部、片段之间和排列监督。
flowchart TD
 A[105 normalized face frames] --> B[75 frame temporal crop]
 B --> C[7 windows of 15 frames]
 C --> D[5 sampled frames per window]
 D --> E[ResNet18 frame features]
 E --> F[AA-SFE within each snippet]
 F --> G[7 snippet features]
 G --> H[Shuffle with one of 10 orders]
 H --> I[Transformer encoder and decoder]
 I --> J[Emotion feature T]
 J --> K[7 class expression head]
 H --> L[Detached snippet features]
 L --> M[Add T and concatenate]
 J --> M
 M --> N[10 class order head]
 K --> O[Classification loss]
 N --> P[Order loss times 1 over 7]

第一步:真正进入网络的 35 帧怎样选出来

原文 Section 4.2 先把视频通过插值或裁剪统一到 105 帧,并用 RetinaFace 得到 224×224 的人脸区域。注意:公开数据加载器只读取已经准备好的图片文件夹,不负责完成原始视频的人脸检测和 105 帧标准化。因此“运行 main.py”不等于从原始视频自动完成整条预处理流程。

训练时从第 0 到第 29 个索引中随机选起点 a,取其后的 75 帧。随后构造七个长度为 15 的候选窗口,相邻窗口的起点相差 10 帧,因此相邻窗口重叠五帧。每个窗口再抽五帧,最终形成七个五帧片段。35 是输入位置数量,窗口重叠使同一源帧可能出现在相邻片段里,所以不能保证每次都是 35 张互不重复的源图像。

$$W_i=\{a+10i,\ldots,a+10i+14\},\quad i=0,\ldots,6;\qquad C_i\subset W_i,\ |C_i|=5$$教学重写:对应 Section 4.2

这里 W 表示候选窗口,C 表示实际采样片段,下标 i 是片段序号。最后一个窗口覆盖 a+60 到 a+74,恰好落在 75 帧范围中。例如 a=15 时,第一个窗口是 15~29,第二个是 25~39;两者共享 25~29。这个算式能直接帮助你检查采样代码是否越界。

测试时公开实现默认固定起点 15,在每个 15 帧窗口内使用相对索引 [0,3,6,9,12]。因此测试输入是确定的,分类分支使用正常片段顺序。训练阶段随机采样、测试阶段固定采样的差别必须写进实验记录;换成均匀覆盖整段原始视频就是新的采样协议。

公开源码采样流程;不是论文性能数据
阶段窗口起点窗口内选帧片段排列
训练a 在 0~29 随机取从 15 帧中随机选五帧从固定十种排列中随机取一种
测试分类默认 a=150、3、6、9、12原始顺序
测试顺序头与测试采样相同同上随机选一种排列,仅用于顺序准确率

一个需要复现者核查的差异:论文 Section 4.4.3 明确说片段内部帧序保持不变,但 data/random_shuffle_dataset.py 的 sample() 将随机索引放入 set,再直接 list(s),没有显式排序。set 不提供时间顺序保证。忠实运行当前源码与按论文补上 sorted() 是两种可区分的实验,应分别记录;本文教学采样脚本显式排序,目的是演示时间结构,不冒充原实现的逐位复现。

预备知识:一帧、一个 token、一个片段分别是什么

ResNet-18 是逐帧特征提取器:它把一张 3×224×224 的 RGB 人脸图像变成一个 512 维向量。向量中的每个坐标是学习到的视觉响应,不是预先指定的“嘴角角度”或“恐惧程度”。批量大小为 B 时,原始输入形状为 B×7×5×3×224×224;卷积阶段先把前面三维合并成 B×35 张图,再恢复成 B×7×5×512。

token 在这里指模型作为一个处理单位使用的向量。AA-SFE 内部有五个帧 token;视频 Transformer 接收七个片段 token。把两处的注意力矩阵混起来,就会误读论文:前者计算的是同一小段内帧与帧的关系,后者计算的是整段视频中片段与片段的关系。

$$A(Q,K,V)=\operatorname{softmax}\!\left(\frac{QK^{\mathsf T}}{\sqrt{d}}\right)V$$原文 Eq. (1)

Q 是查询向量组成的矩阵,K 是被比较的键,V 是最后被加权汇总的值,d 是论文写法中的特征维度。直观上,每个查询先给所有键打相关性分数,再通过 softmax 变成一行权重,最后按权重混合值向量。实际多头实现把 512 维拆到四个头,每头 128 维,各头再合并;上式省略了多头拼接、残差和前馈网络,不能把一个式子当成完整 Transformer 层。

自注意力的 Q、K、V 来自同一组对象;交叉注意力的查询来自另一组对象。EST 的视频编码器让七个片段相互交流,解码器使用一个可学习的情绪查询向量,从编码结果里汇总对分类有用的信息。它与 ALMT 的语言查询不同:情绪查询没有对应一个输入句子,而是随训练更新的模型参数。

第二步:AA-SFE 怎样把五帧压成一个片段表示

原文 Figure 3(作者稿第 5 页):AA-SFE 的两级注意力结构:先做帧间关系建模,再用片段整体信息重新加权帧特征。重点不是增加一个名字,而是明确两个阶段分别在比较什么。

第一级先将片段的五个 512 维向量堆成矩阵 I,再做一次帧间自注意力,得到 I′。每个输出帧向量已经包含其他帧的信息,因此后续选择的对象不是原始孤立帧,而是与局部上下文交流后的表示。公开实现还把原始特征加回注意力输出,再做 LayerNorm,这个残差通道使模型不必完全重建原有的逐帧信息。

第二级首先在时间维上做最大池化,得到一个 512 维的整体向量。最大池化是逐坐标选择最大响应:第一维可能来自第 1 帧,第二维可能来自第 4 帧。因此这个整体向量通常不是任何一张真实帧的特征,也不能简单叫作“峰值帧”。它描述这个局部片段中各类强响应的集合。

$$\hat r^{\prime}_k=\max_{j=1,\ldots,J}r^{\prime}_{j,k},\qquad J=5,\quad k=1,\ldots,512$$教学展开:原文 Section 3.2 的 max pooling

这里 j 是帧序号,k 是特征坐标,r′ 是第一级之后的帧向量,带帽子的 r′ 是片段整体向量。这个写法把“最大池化”具体化了:比较发生在五帧之间,结果仍保留 512 个坐标,不是直接把所有数压成一个标量。

$$\alpha_j=\cos(r_j^{\prime},\hat r^{\prime})=\frac{r_j^{\prime}\cdot\hat r^{\prime}}{\|r_j^{\prime}\|_2\,\|\hat r^{\prime}\|_2}$$原文 Eq. (2)

α 是第 j 帧向量与片段整体向量的余弦相似度。点积除以两个向量长度后,主要比较方向而不是数值大小。作者希望偏离整体较大的帧得到较低权重,从而减轻偶发干扰。但是“与整体相似”不自动等于“包含表情”,如果多数帧都被同一类噪声主导,整体向量也可能带偏。

$$R_i=\frac{\sum_{j=1}^{J}\alpha_jr_j^{\prime}}{\sum_{j=1}^{J}\alpha_j}$$原文 Eq. (3)

R 是第 i 个片段最终的 512 维表示。分子把五个向量乘上各自权重后相加,分母控制总权重规模。与简单平均相比,它允许不同帧贡献不同;与直接选一帧相比,它保留多帧的组合信息。该权重来自当前特征的计算,论文没有逐帧噪声标签,也没有监督每个权重应该取多少。

models/Model.py:187–203 · 固定源码版本

        for i in range(self.clips):
            vs_stack = tmp[:,i,:,:]
            vs_stack = vs_stack.permute(1,0,2)
            output,weight = self.attn(vs_stack,vs_stack,vs_stack)
            if self.use_norm:
                output = vs_stack + self.dropout3(output)
                output = self.norm1(output).permute(1,2,0)

            global_feature = self.maxpool2(output).squeeze(dim=2)
            local_feature = output.permute(2,0,1) # 5*b*512
            dis_list = []
            for j in range(self.img_num_per_clip):
                dis = self.cos(local_feature[j],global_feature)
                dis_list.append(dis)
            dis_alpha = torch.stack(dis_list,dim=1).unsqueeze(dim=1)
            dis_alpha = torch.clamp(dis_alpha, min=1e-8)
            output = output.mul(dis_alpha).sum(2).div(dis_alpha.sum(2))

上面 17 行是两级处理的直接对应。vs_stack 的形状是 5×B×512;self.attn 的三个参数相同,对应第一级自注意力;output 经转置成为 B×512×5;maxpool2 汇总时间维;最后 mul、sum、div 对应原文 Eq. (3)。源码在余弦权重上额外使用 clamp(min=1e-8),把负值和过小值截断成正数。论文 Eq. (2) 的余弦理论上可能为负,因此“严格按纸面公式”和“按发布代码”在这个数值细节上有差别。

建议你先用两个二维向量手算余弦,再看五帧的向量运算。若权重是 [1,0.5,0.5,1,1],分母就是 4;如果把所有权重同时乘二,最后的加权平均不变。这个性质说明公式关注相对贡献。源码截断与分母归一化共同避免负权重抵消造成不稳定,不能误讲成对五个余弦值执行 softmax。

第三步:七个片段怎样变成整段视频的预测

原文 Figure 2(作者稿第 4 页):完整训练结构连接了片段采样、AA-SFE、编码器、情绪查询解码器、表情分类头和顺序预测头。图中的两个输出头承担不同监督信号。

七个片段向量组成 R,加入正弦与余弦位置编码后进入视频 Transformer。位置编码让特征携带时间位置身份,否则标准自注意力主要处理一组向量之间的关系,难以单凭相同的内容集合区分先后。原文使用三层编码器和三层解码器,每层四个头,默认隐藏维度为 512;不要使用 Model.py 构造函数里四层的默认形参来断言论文用了四层,因为主程序实际传入 options/base_options.py 的三层配置。

编码器输出七个带上下文的向量 H。解码器使用一个 512 维可学习情绪查询,反复从 H 读取信息,输出单个视频向量 T。随后三层全连接分类器输出类别 logits。logits 是尚未归一化的分数,训练交叉熵直接接收这些分数,推断时可以用 softmax 看概率,最后取最大分数的类别作为预测。

$$T=\operatorname{Decoder}(q_{\rm emotion},H,H),\qquad \hat Y=\operatorname{softmax}(\operatorname{MLP}_{\rm cls}(T))$$教学概括:对应 Section 3.1;不是新增论文公式

q 是情绪查询参数,H 同时提供键与值,MLP 是全连接网络。这个式子强调数据流:查询不是一张挑选出来的人脸图,也不是某一表情的人工原型。公开源码的分类器为 512→128→64→7,最后七维适用于 AFEW、DFEW;如果改做六类数据集,应核实标签映射及输出维度,而不是照搬七类头后直接比较论文结果。

源码还透露了一个经常被解释遗漏的细节:训练片段被排列后,位置编码也按同一排列重排,即原片段的原始时间位置身份跟着它移动。不能将它讲成“打乱后统一重新编号 0 到 6”。比较修改前后的结果时,应把“保留原位置身份”和“采用打乱后位置”当成两种不同实现,并先设计小规模行为检查。

models/Model.py:210–229 · 固定源码版本

        pos = torch.tensor([self.clips] * b)
        pos_enc = self.pos_enc(pos)
        for i in range(b):
            pos_enc[i] = pos_enc[i][per[i]]
        x = ori_video_feature + pos_enc
        x = x.permute(1, 0, 2)
        tgt = self.query_embed.weight
        tgt = tgt.unsqueeze(1).repeat(1,b,1)
        emotion_clip_feature,weight_list = self.transformer(x, tgt) #.permute(1, 2, 0)
        emotion_clip_feature = emotion_clip_feature.permute(1,2,0)

        emotion_clip_feature = emotion_clip_feature.reshape(-1,self.d_model * self.key_clips)


        #####permutation
        ori_video_feature_detach = ori_video_feature.detach()
        per_feature = ori_video_feature_detach + emotion_clip_feature.unsqueeze(dim=1)
        per_output = self.per_branch(per_feature.view(b,-1))

        output = self.classifier(emotion_clip_feature)

pos_enc[i][per[i]] 是位置身份随片段移动的直接证据;query_embed 提供唯一情绪查询;classifier 产生表情分数。这个片段也包含下一节的 SSOP 输入构造,读源码时沿着变量的形状追踪,比只记模块名称更可靠。

第四步:SSOP 预测排列类别,而不是逐帧恢复视频

只有视频类别标签时,网络可能靠最容易辨认的某一段就完成训练,不必理解整段变化。作者观察到模型常依赖中间片段,于是增加一个不需要人工标注的任务:从预先选定的十种排列中随机挑一种,重排七个片段,然后预测本次用了哪一种。监督标签是采样程序自己知道的排列编号,所以这是辅助自监督信号;整套 EST 仍同时使用人工表情标签,不能称为完全无监督训练。

七个片段理论上共有 7!=5040 种排列,EST 训练的输出空间只有十种预选排列。模型不是预测 5040 类,不是给每一帧恢复时间戳,也不是生成一个排好序的新视频。公开仓库 datasets/permutation_10.npy 保存这十种排列;复现时必须固定该文件版本,临时重新生成会改变辅助任务。

$$O_i=R_i+T,\qquad O=\operatorname{Concat}(O_1,\ldots,O_n),\qquad \hat S=\operatorname{softmax}(\operatorname{MLP}_{\rm order}(O))$$原文 Algorithm 1 的 O 构造;预测式为教学展开

T 在七个片段位置上广播相加;每个 O 都保留局部片段信息并加入视频情绪信息,再拼成 7×512=3584 维,输入顺序分类器。论文解释,仅使用压缩后的 T 难保留足够细的顺序信息,所以用片段表示补充。顺序头不是放在视频解码器里的一串七个输出 token,而是另一个接收拼接向量的全连接分支。

$$\mathcal L_{\rm cls}=-\mathbb E[Y_C\log\hat Y_C],\qquad \mathcal L_S=-\mathbb E[S_C\log\hat S_C]$$原文 Eq. (5) 与 Eq. (6)

C 索引视频,Y 是真实表情的 one-hot 向量,Ŷ 是预测概率,S 是真实排列类别,Ŝ 是顺序预测概率,期望表示对训练样本求平均。对于单个样本,交叉熵就是负对数真实类别概率:正确类别概率越小,损失越大。PyTorch 的 CrossEntropyLoss 内部处理 log-softmax,因此训练前不必手工再给 logits 加 softmax。

$$\mathcal L=\mathcal L_{\rm cls}+\frac{1}{n}\mathcal L_S,\qquad n=7$$原文 Eq. (7)

损失系数 1/7 用于减轻辅助任务的影响;公开配置使用 0.1428 近似它。训练循环分别算两个交叉熵后相加,再做一次反向传播。分类标签和排列标签监督不同的目标,因此辅助损失下降不代表表情一定更准确,仍需观察独立验证集上的 WAR 与 UAR。

源码与纸面还存在梯度路径的差别:ori_video_feature.detach() 让 SSOP 中直接相加的 R 分支不接收梯度,但 T 路径仍可把 SSOP 梯度传回 Transformer 和特征提取器。准确讲法是“阻断局部旁路的直接梯度”,不是“骨干被冻结”,也不是“SSOP 没有参与学习”。这一点适合做梯度检查练习,不能在写报告时省略。

原文 Figure 7(作者稿第 12 页):直方图比较最高注意力落在哪个片段,显示加入 SSOP 后分布更分散。它支持“减少对固定中间位置的依赖”的解释,但没有证明每个片段被同等理解。更分散的注意力也可能只是变平,需要结合准确率和干预实验判断。

实验怎么读:先看相同基线,再看不平衡类别

原文使用 BU-3DFE、MMI 的被试独立十折验证,AFEW 的训练/验证划分,以及 DFEW 五折评估。公开作者稿第 8 页 BU-3DFE 的文字统计存在数据集名称与序列来源容易混淆的问题;新实验应根据你实际获得的官方授权数据、分割文件和被试编号进行核验,不应仅凭本文转述重新构造分割。AFEW 数据集虽然介绍了独立测试集,主要结果段落采用 Train/Val 评估;跨库 Section 4.4.7 又称 AFEW testing set,发布代码未在 README 中给出这部分可直接重建的分割说明,必须保留这一可核验性限制。

$$\operatorname{UAR}=\frac{1}{K}\sum_{k=1}^{K}\frac{TP_k}{N_k},\qquad \operatorname{WAR}=\frac{\sum_{k=1}^{K}TP_k}{\sum_{k=1}^{K}N_k}$$评价指标教学定义;对应原文 Section 4.2

K 是类别数,N 是该类真实样本数,TP 是该类预测正确的数量。UAR 先算每个类别召回率,再给各类相同权重;WAR 按样本数加权,在单标签分类中等于整体准确率。例如大类 10 个样本答对 8 个,小类 2 个答对 1 个,WAR=9/12=75%,UAR=(80%+50%)/2=65%。这说明大类占优时,只看 WAR 容易忽略少数类。

论文 Table 2–5:与作者自身 Transformer 基线比较;本页未重新训练
数据集Transformer 基线 WAR / UAR (%)EST WAR / UAR (%)WAR 增益(百分点)
BU-3DFE85.60 / 85.6088.17 / 88.172.57
MMI90.50 / 90.0392.50 / 90.312.00
AFEW 8.049.72 / 43.9554.26 / 49.574.54
DFEW63.85 / 50.3965.85 / 53.942.00

最直接的证据是与作者自身 Transformer 基线比较,因为任务、主干与训练设置较接近。在 AFEW 上 WAR 从 49.72 到 54.26,是 4.54 个百分点,相对于基线的相对增幅约为 9.13%。正文把这项变化称为 8.37% 相对提高,数值更接近除以最终值后的比例;本页采用表格数值自行计算百分点,避免把不同口径混用。

对 DFEW 还要降低表述强度:与 Former-DFER 相比,EST 的 WAR 65.85 对 65.70 只多 0.15 个百分点,UAR 53.94 对 53.69 多 0.25 个百分点。原文称取得提升,但没有在这些表格中提供多随机种子的标准差或显著性检验,所以不能依据小差值断言稳定领先。与自身基线的两点 WAR 提升和跨方法的零点一五点提升,是两条证据。

少数类问题仍然明显。作者报告 DFEW 厌恶类准确率仅 5.52%,快乐类可达 86.87%,并把它与长尾分布及类别间细微差别联系起来。总体 WAR 提升并未解决细粒度混淆;这恰好解释为什么后续学习路线应研究区分困难类别、局部区域、动作单元或类别结构,而不是只追求更大的整体准确率。

论文 Table 6:逐步加入组件的消融实验
组件参数量 MMACs GBU-3DFE WAR/UAR (%)
Transformer34.3763.8585.60
Transformer + AA-SFE34.3763.8887.12
Transformer + AA-SFE + SSOP42.7863.8988.17

AA-SFE 带来 1.52 个百分点,随后 SSOP 再带来 1.05 个百分点。这个逐步消融支持两个模块在该组合设置下有效,但不是完整 2×2 因子实验:缺少“只加 SSOP、不加 AA-SFE”这一行,所以不能从该表独立估计交互作用。参数量增加主要出现在顺序预测头,计算量变化却很小,因为相对逐帧卷积,大型全连接辅助头的运算量占比低;不能把“小 MACs 增量”讲成“没有参数代价”。

原文 Table 7 中层级注意力 88.17 优于单自注意力 87.63、SE-like 注意力 87.46;Table 9 中把视频中间帧置零后,带 SSOP 的 WAR 为 87.5,不带 SSOP 为 82.5。后一个实验比单纯注意力图更接近行为干预,但仍只针对一种人工遮断条件和特定数据集,不能推导出对所有遮挡、所有场景都稳健。

从 EST 怎样走向细粒度与跨场景研究

论文 Table 11:作者报告的跨数据库实验,目标集不微调;具体分割可核验性见正文
训练 → 评估Transformer WAR (%)EST WAR (%)差值(百分点)
DFEW → AFEW48.8651.142.28
BU-3DFE → AFEW19.6625.175.51

跨场景意味着训练与评估的数据分布不同,例如摄影条件、影片风格、人群或表演方式改变。Table 11 比同库评估更贴近这个问题,但 EST 本身没有专门的域对齐损失,也没有学习一个显式场景不变分解;它是把同一模型迁移评估,不能称为已经解决域泛化。由受控数据到 AFEW 的 25.17% 仍很低,也不能与同库 54.26% 当成条件一致的优劣对照。

细粒度方向的第一个可执行问题是:当恐惧被判成愤怒、厌恶被判成中性时,错误来自关键局部变化没有被编码,还是标签、低分辨率与类别不平衡?先从每一类各抽取一组独立验证样本,记录脸部清晰度、姿态、遮挡、时间位置和预测变化。这个错误表比“设计一个更强模块”的空泛起点更有用,且不应先用测试集筛选最适合新方法的例子。

跨场景方向的第一个问题是:是否在新场景里误把背景或姿态当成情绪?把源域划分为训练与验证,目标域保留完整评估集合,统一七类标签映射及人脸预处理;先跑源域模型直接迁移的基线。若训练时使用无标签目标域样本,应明确称为无监督域适应;若训练时完全不看目标域,则更接近域泛化或直接跨库评估。这几种协议不能混成同一个成绩。

适合从 EST 起步的改动应一次只动一个因素,例如比较 AA-SFE 加权与简单平均,或者比较正常采样与严格保持片段内顺序。先验证改动确实改变了预期行为,再讨论类别结构或域不变学习。使用多个数据集做独立同库训练,只能说明方法在多个数据集上适用,不能自动算跨场景泛化实验。

局限与复现风险:区分作者结论和阅读者判断

作者自述。Section 4.3.5 与结论指出:极细微的视觉差别仍难捕获,长尾分布导致少数类学习不足,厌恶/中性、恐惧/愤怒等混淆仍存在。作者计划进一步利用自监督机制与无标签数据。应将这些写进读书报告,而不能只摘抄摘要中“鲁棒”和“最先进”的表达。

独立判断一:自监督目标可能利用捷径。排列类别可以从局部外观强弱、裁剪变化、视频开头结尾差异中得到线索。顺序准确率高并不证明网络理解了表情运动的语义顺序。可以把时间反转、重复帧、同视频片段替换作为后续受控检验,要求表情表现与辅助任务表现一起变化;这些是本文建议的实验,尚未执行。

独立判断二:可视化的解释范围有限。Figure 7 的注意力分布与 Figure 12 的 t-SNE 可以展示模型行为与表示结构,但不能单独证明因果机制或泛化。t-SNE 的降维超参数和抽样会影响图形,看起来分开的点团不能替代独立测试集准确率、类别召回率和误差条。

独立判断三:当前源码的实验选择需要澄清。main.py 每轮使用 test_list_root 对应列表评估,并按其整体准确率保存最好模型。若该文件就是正式测试折,就存在依据测试表现选轮次的问题;若它是验证划分,则需要另设最终测试。新实验应在训练部分划出验证集确定轮次,再做一次最终测试,并说明协议与原文不同;不能靠变量名“validate”判定实际数据角色。

工程上,README 标注 Python 3.7.9,requirements 锁定较旧的 PyTorch/torchvision;源码还直接调用 .cuda(),所以参数帮助里写“gpu_ids=-1 可用 CPU”不代表整条代码实际能在 CPU 跑通。显存不足时可以先减 batch,但那会影响 BatchNorm 与优化设置,不能预先承诺成绩等同。本文没有运行 EST 长训练,也没有把作者 RTX 3090 上的 fps 当成你的 RTX 4070 Laptop 的实际速度。

发表信息使用出版者元数据:Pattern Recognition 138(2023),109368,DOI 10.1016/j.patcog.2023.109368。本文方法和数值逐项取自作者网站的 19 页稿件,页面标注日期为 2023-02-10;它与出版排版版的页码体系不同,本文引用 Figure/Table 编号并注明作者稿页码,避免把阅读版本混淆。

把阅读变成可交付练习:每一步都有验收标准

练习一,30~45 分钟:只复现采样索引。下载本页配套 est_sampling_probe.py,在一个空目录运行下面命令。脚本只用 Python 标准库,完全不需要数据集、GPU 或预训练权重。这不是 EST 训练,而是检查你是否掌握 105→75→7×5 的时间结构。

python est_sampling_probe.py --seed 8 --start 15
python est_sampling_probe.py --seed 21 --start 15

验收标准:两次输出的 frame_slots 都等于 35;test_indices 两次完全相同;train_indices 随 seed 改变;每个片段有五个递增索引;所有索引在 0~104 内;assertions 为 passed。最后一段测试索引应是 [75,78,81,84,87]。将两个 JSON 输出保存下来,并手画相邻窗口的五帧重叠区域。脚本使用显式排序,是与论文叙述一致的教学版本。

练习二,45~60 分钟:形状追踪。不训练网络,沿 Model.py 在纸上写出六个形状:输入 B×7×5×3×224×224、卷积展开 B×35×3×224×224、帧特征 B×7×5×512、片段序列 B×7×512、情绪向量 B×512、顺序头输入 B×3584。验收标准:能解释每次 reshape 或 permute 只改变组织方式,注意力和池化才改变信息内容;能指出顺序头十类与表情头七类的区别。

练习三,60~90 分钟:验证梯度路径。在已能导入模型的兼容环境中,用一个至少含两条视频的合成 batch 做一次前向和只含顺序损失的反向。给 detach 前的 R 与 T 保留梯度,再比较局部旁路与 T 路径;如果要 isolating 旁路,需要显式分离两条路径,不能把“R.grad 非零”误解为 detach 没生效,因为 R 还通过 Transformer 影响 T。验收是画出两条路径并解释哪条被切断,先于训练真实数据。

练习四,半天内的准备工作:数据与协议清单。选择一个已有合法访问权限的数据集和一个固定官方 fold,检查文件夹帧数、文件名排序、标签范围、训练/验证/测试 ID 交集。输出 split_audit.json、采样可视化和一批输入形状。验收标准是三个集合不重叠、标签映射明确、至少十段视频都能无越界读出 7×5 帧;没有通过时不启动 160 轮训练。

练习五,先测 100 步,再估算整程。只有依赖、预训练权重和数据审计完成后,才做短训练,记录每步耗时、GPU 峰值显存、损失是否有限、验证预测是否覆盖合理类别。以实测每步时间乘每轮步数估计训练时长,并单列验证和图片读取开销。验收不是“loss 下降一次”,而是完整保存一次可重新加载的 checkpoint,并用同一输入得到一致的评估预测。这个阶段才有依据回答完整消融需要多久。

读完本篇应留下三份可检查的产物:一张注明形状的数据流图、一份“论文描述—源码实现—潜在差异”的对应表,以及一份固定划分的实验计划。能用这三份东西解释 AA-SFE 与 SSOP 分别处理哪种问题,再进入后续细粒度和跨场景论文,学习重点会从记名字转成比较机制与证据。

自测:SSOP 准确率只有约 50%,是否意味着它没用?

不能这样判断。十分类随机猜测约 10%,论文 Table 8 报告 45.0%~55.4% 的排列准确率;辅助任务的最终价值仍取决于独立的表情识别效果与消融证据。顺序预测不是最终任务,也不需要达到接近 100% 才可能产生训练作用。

自测:五个余弦权重加起来是否天然等于 1?

不是。源码先截断,再通过 Eq. (3) 的分母归一化。只有归一化后的相对权重和为 1,且这里不是 softmax。

自测:将 DFEW 和 AFEW 分别训练出好结果,算跨场景吗?

这属于两个数据集上的同库验证。跨场景证据需要说明用哪个域训练、在哪个未参与模型选择的域评估,以及目标域数据是否在训练中出现。

来源与核查

  1. 作者公开全文(19 页,本文图表与公式编号依据)
  2. Pattern Recognition 正式出版记录与 DOI
  3. 官方公开源码固定提交 f85a0cdcf974630648d2a60188d086ad85a0347a
  4. 数据加载器:采样与排列实现
  5. 实验参数与默认值
  6. 训练、测试与最好模型选择逻辑

下载 EST 片段采样与排列学习脚本(只用Python标准库)