第一次接触微表情识别,是因为一个很具体的问题:普通表情识别已经在公开数据集上做到非常高的准确率了,为什么还要单独研究一个“微表情”?我当时以为,无非是把检测阈值调得更灵敏、把特征算得更细一点,本质上还是同一件事。直到认真读完一篇微表情识别的综述,才意识到这两个方向从数据采集、任务定义到评测方式,几乎没有一环是重叠的。这篇笔记就是我在读综述过程中整理出来的框架,主要围绕微表情识别到底在做什么、数据集是怎么来的、方法如何演进、检测和识别为什么要分开看,以及复现实验时容易踩的评估这些环节。如果你准备入门微表情识别,或者只是好奇它为什么不像普通表情识别那样“大力出奇迹”,这篇笔记应该能让你少翻不少文献。我会尽量不预设你已经具备很强的视觉基础,把综述里那些容易被一句话带过、但对建立整体认知很关键的地方都展开讲。
1. 微表情识别到底在识别什么:任务定义和容易混淆的概念
1.1 微表情不是“弱化版的表情识别”
综述里对微表情的标准描述,一般会落在三个特征上:持续时间短、运动幅度小、只发生在局部区域。心理学上通常把微表情的持续时间定义在0.04秒到0.2秒左右,也有说法是不到瞬间就结束。这个时长有多夸张呢?普通表情通常能持续0.5秒甚至好几秒,你可以在对话中明确观察到对方的嘴角上扬或眉毛紧锁。而微表情是一闪而过的局部动作,比如嘴角只微微抽动一下就恢复,或者眉毛中间肌肉极短促地收缩,动作幅度小到容易被认为是面部抽搐或光线抖动。
正因为如此,微表情识别从来不是“把表情识别模型的灵敏度调高一点”就能解决的问题。普通表情帧与帧之间的状态差异明显,特征表达相对稳定;微表情则需要在很短的时间和很小的空间范围内捕捉到精细的运动模式,这对数据采集设备、标注粒度和算法都能处理细节信息的能力都有完全不同的要求。
1.2 检测与识别是两个不同层级的任务
我在读综述时最容易混淆的一个点,就是“检测”和“识别”。很多入门文章把两个词混着用,但综述里从头到尾都在强调它们是完全分开的任务。
微表情检测(spotting/temporal localization)解决的是“微表情在视频里哪个时间段出现了”。它本质上是时序事件定位,非常像一个警报系统:在几十秒甚至几分钟的视频里,绝大部分时间都是无表情或普通表情,只有极少数片段发生了微表情。你要做的就是把这段区间找出来。
微表情识别(recognition)解决的是“给定一段已经确定的微表情片段,它表达的是什么情绪类别”。它更像分类问题:输入已经知道是微表情的视频片段,输出是高兴、惊讶、厌恶、压抑、紧张等类别。
综述里的常见做法是先讲检测再讲识别,不是因为它们只是顺序关系,而是因为它们的难度来源完全不同。检测难在“正负样本极度不均衡”,识别难在“类别之间差异太小”。实际落地时两个任务要串联起来,但学术研究和实验设计上,必须分开建模和评估。这是我读完综述后印象最深的一点。
1.3 为什么微表情识别长期没有爆发式进展
普通表情识别能依赖大规模数据集,微表情识别则长期受制于几个结构性困难。
第一是数据规模极小。目前最常用的自发微表情数据集,样本量也就一两百个片段,这和普通表情数据集动辄几万几十万张图片完全不在一个量级。深度学习是数据饥渴型的,喂不饱模型,性能自然上不去。
第二是标注成本高。微表情需要标注的不是“这张图是什么表情”,而是要标出动作发生的起始帧、峰值帧、结束帧,还要标注动作单元和情绪类别。这些标注需要受过训练的心理学专业人员参与,而且不同标注者之间的一致性很难保证。对同一段视频,可能有人觉得是厌恶,有人觉得是困惑,这会直接限制监督学习的上限。
第三是类间差异小。微表情的几个类别在纹理和运动模式上高度相似,比如“压抑的愤怒”和“紧张”在局部肌肉运动上可能就是毫米级别的差异。对人眼来说都很困难,对计算机来说自然更不轻松。
理解了这三点,再看后面的数据集和方法设计,很多决策逻辑就顺理成章了。
2. 第一个拦路虎是数据:主流数据集与刺激范式的门道
2.1 常见数据集与它们的关键差异
微表情识别绕不开数据。综述里反复出现的就是几个名字:SMIC、CASME、CASME II、SAMM。我整理了一个简表,方便对照看:
| 数据集 | 被试人数(约) | 微表情片段数(约) | 帧率 | 主要特点 |
|---|---|---|---|---|
| SMIC | 16 | 164 | 100 fps | 最早被广泛使用的自发微表情数据集之一 |
| CASME | 35 | 200左右 | 低于200 fps | 情绪类别以抑制情绪为主,与日常生活接近 |
| CASME II | 26 | 247 | 200 fps | 分辨率高,标注精细,后来绝大多数论文都在它上面测试 |
| SAMM | 32 | 159 | 200 fps | 被试多元化,标注动作单元较细 |
不要小看帧率这个参数。普通视频30 fps,每两帧之间的间隔约33毫秒,而微表情可能只有0.2秒,也就是六帧左右;如果动作更短,甚至只有两三帧。在30 fps下,微表情很容易被完全吞掉。而200 fps下,0.2秒的微表情能记录到40帧左右,算法才有机会捕捉到完整的运动过程。这也是为什么CASME II和SAMM成为主流基准数据集的硬件原因——它们的高帧率决定了能捕捉到足够多的时序细节。
2.2 微表情数据是怎么“诱发”出来的
读综述时我最好奇的部分,是这些微表情片段到底怎么采集的。普通表情数据集里让被试对着摄像头做表情就行,但自发性微表情的最大特征是“被试自己都不知道自己暴露了情绪”,这就必须通过特定的实验范式去诱发。
主流做法有两种。一种是高唤醒视频刺激:给被试播放能引发强烈情绪的影片片段,同时要求他们尽量保持面无表情。人在刻意压抑真实情绪时,面部会出现短暂的微表情泄漏。另一种是访谈/欺骗范式:设计一个需要被试说谎或者掩盖真实反应的任务,利用心理学上的认知负荷诱导微表情。
这两种范式都强调“自发性”而不是“扮演”。扮演出来的微表情往往肌肉配合得更完整、持续时间更长,和真实情境下的微表情分布不一样。这一点直接影响了模型的泛化能力:在扮演数据上训练出来的系统,拿到真实场景里通常表现会下降得很明显。
2.3 标注为什么这么贵且难
微表情数据集的标注比普通表情复杂得多。标注人员需要逐帧观看200 fps的视频帧,确认微表情从哪一帧开始出现、哪一帧肌肉运动达到峰值、哪一帧结束,并记录对应的面部动作单元。动作单元是基于面部动作编码系统定义的,比如“内眉上扬”对应AU1,“嘴角上扬”对应AU12。一个30秒的片段逐帧标下来,可能要花一两个小时,而且多人标注后还要做一致性检验。
这也是我在读综述时产生的一个具体体会:微表情识别的问题瓶颈,可能很长一段时间内都不只是模型结构,而是高质量标注数据的生产能力。深度学习再强,没有可靠的标签也是无米下锅。
3. 方法是怎么从“特征工程”一步步走到“端到端”的
3.1 手工特征时代:从时空纹理到光流统计
综述里对早期方法的梳理,主线是从时空特征到运动特征的演变。早期研究者把微表情当作一个三维时空体来处理,x和y是空间坐标,t是时间轴。最经典的特征是LBP-TOP,它在三个正交平面上分别提取局部二值模式,再把三个方向的直方图拼起来描述时空纹理。
另一条线是光流特征。微表情虽然幅度小,但本质上是一种局部运动,而光流法天生就是用来估计像素运动的,于是很自然地成了微表情识别的重要工具。常见做法是在微表情片段内先计算光流场,再用方向直方图的方式聚合光流信息,得到紧凑的特征描述。这种特征强调“运动方向”而不是“静态纹理”,对微弱运动更敏感。
拿到特征之后,早期分类器以SVM和极限学习机为主。现在回头看在CASME II这类小数据集上,手工特征配合SVM的表现并没有被早期深度学习方法碾压多少,在某些协议下甚至互有胜负。这不是说手工特征更强,而是说明在数据规模极小的情况下,精心设计的特征确实能弥补模型容量的不足。
3.2 深度学习时代:从“空间编码+时序建模”到“时空一体”
综述的后面部分集中在深度学习方法。最直观的思路是把视频当作图片序列,对每一帧先做空间编码,再用循环神经网络建模时序,也就是CNN+LSTM的组合。这种思路容易理解,但在微表情场景下有一个明显问题:微表情的判别信息集中在细微运动里,如果单帧空间编码丢失了运动幅度信息,后面用LSTM也救不回来。
第二种思路是直接用3D-CNN。把连续帧堆叠成三维输入,卷积核在空间和时间两个维度同时滑动,理论上能够同时捕捉空间外观和时序运动。不过3D卷积参数量大,在小数据集上很容易过拟合,所以后来的工作要么从预训练权重初始化,要么在光流序列上做3D卷积,用光流把“微弱运动”这个信息显式地提供给网络。
第三种思路是注意力机制和Transformer。空间注意力可以提示网络该看脸部的哪一块,时序注意力可以告诉网络该在哪几帧集中注意力。对微表情来说这个方向天然合理:不是每一帧都贡献相同的信息,峰值帧附近的运动信息最丰富,注意力机制正好学这种权重分配。
3.3 光流在深度学习方法里的地位依然重要
读综述时我注意到一个反复出现的细节:即便在端到端深度学习时代,光流依然没被抛弃。有些方法把光流作为网络输入,有些方法把光流作为多任务学习的辅助监督信号,还有一些跨数据集的迁移工作,就是靠光流图而不是原始RGB图做适配,因为光流图剥离了一部分人种、肤色、光照的差异,更接近“纯粹的运动模式”。
这一点对我启发很大。微表情识别的难点不是“看清脸”,而是“看清脸上的变化”。RGB帧里的眼睛鼻子眉毛是静态外观,模型很容易依赖这些信息去猜情绪,反而忽略了真正的运动线索。光流相当于告诉模型:别看它长什么样,看它在动什么。在当前数据规模下,这个归纳偏置比模型单纯堆容量更管用。
4. 检测与识别是两件事:任务拆解和评测设计
4.1 微表情检测:在长视频里找到转瞬即逝的信号
微表情检测之所以难,首先是数据极不均衡。一段对话视频里可能只有几帧是微表情,剩下都是普通面部活动或静止状态。检测模型如果犯懒,把所有片段都判定为“非微表情”,准确率可能已经很高,但实际没有任何用处。所以检测工作不能只看整体准确率,通常要看在特定时间窗口内的定位精确率和召回率,以及F1分数。
另一个难点是“微表情”和“普通表情”之间存在过渡区。人类面部动作本身是连续变化的,一个正常的微笑可能包含和微表情非常相似的运动单元,只是持续更长、幅度更大。检测算法需要学习的是“这个短暂的隆起是不是真正的情绪泄漏”,这对时序上下文的要求很高,只看局部几帧很难判断。
综述里介绍的检测方法大体可以分成两类。一类是滑动窗口加分类器,对窗口内片段判“有/无微表情”,简单但计算量大、窗口长度选择敏感。另一类是把检测当作时序分割任务,在整段视频上学习逐帧概率,再用后处理合并相邻帧输出区间。后者的思路更接近现在的主流,但对帧级标签的要求更高。
4.2 微表情识别:给定片段,判断情绪类别
识别任务相对单纯,输入是已经裁好的微表情片段,输出是情绪类别。这里同样有一个协议细节:识别时到底该不该包含微表情出现前后的中性帧。有人习惯只截取从起始帧到结束帧的区间,也有人截取前后各几帧中性帧作为上下文。两种方式会显著影响结果,因为中性帧提供了“动作是从什么状态开始变化”的参考坐标。综述里会反复提醒读者,比较不同方法时必须确认协议一致,不然数字对不上是常态。
4.3 两个任务串联的工程链条
实际系统里,检测和识别是串联的:摄像头或视频流输入,先由检测模块定位微表情片段,再把片段送入识别模块分类。这两个模块的错误会相互放大——检测漏掉一个片段,识别再好也无济于事;检测把普通表情误判成微表情,识别模块就会在无意义的数据上瞎猜。
这个工程链条也解释了为什么微表情识别实际落地比论文里难:论文里往往假设测试数据已经标注好了微表情区间,识别模块只需要做分类;而现实场景中检测本身就已经是巨大的挑战。读完综述,我印象最深的结论之一就是:“识别性能重要,检测性能同样重要,甚至更重要。”
5. 复现综述实验时我踩过的评估坑
5.1 身份泄漏:看起来漂亮的结果很可能无效
微表情数据集样本少,稍不注意就会引入身份泄漏。最简单也是最常见的错误,是随机把片段划分到训练集和测试集。如果同一个被试的多个片段既出现在训练集又出现在测试集,模型实际上是在识别“这个人”而不是“这种微表情”。由于微表情和个人面部特征强相关,这个泄漏会让性能虚高不少。
正确做法是按被试划分。常见协议是留一被试出测试法(Leave-One-Subject-Out,LOSO),也就是每次拿一个被试的所有片段做测试,用其余被试的片段训练,最后把所有被试的结果汇总。这样测试时模型面对的是完全没见过的人,评估结果才更接近真实泛化能力。复现论文时,我给自己定的规矩是:先看代码或者论文里怎么写划分的,如果发现随意随机切分,结果再好看也要打问号。
5.2 准确率会骗人:UAR和UF1才是靠谱的指标
微表情识别类别极不平衡,有些类别在数据集中只有十几个样本,准确率很容易被多数类主导。假设一个数据集里有40%的“平静”样本,模型把一切都预测成“平静”,整体准确率可能也有40%,看起来不是完全没用,但实际对少数类一窍不通。
综述里通常更看重两个指标:未加权平均召回率(UAR)和未加权平均F1分数(UF1)。UAR是每个类别的召回率先取平均,再对各类做平均,这样每个类别的权重一样,不会因为某个类样本多就主导结果。UF1则是每个类别的F1取平均,同时兼顾精确率和召回率。复现实验后,不能只盯着整体准确率,还要输出按类别的混淆矩阵,看看少数类到底是不是被牺牲了。
5.3 小数据集上的“多次运行标准差”一定要写
微表情数据集小,随机初始化参数和训练数据划分会对结果造成明显波动。我复现时发现,同一个模型在相同协议下多跑几次,准确率可能差出5个百分点以上。如果论文只给一次运行的结果,这个数字很可能是最好的一次,甚至是运气最好的一次。
更稳妥的做法是每种实验配置重复5到10次,报告平均数和标准差。标准差大说明模型不稳定,也说明结论不宜过度解读。这一点在读综述时不明显,真正动手复现才体会得到。还有一个小细节:微表情数据集的样本量小到做大型预训练不现实,但很多方法会使用在普通表情或ImageNet上预训练的网络。这时候要检查预训练数据是否包含测试集中的身份或相似尺度的面部图像。如果预训练数据集和测试数据集存在重叠,指标就会虚高,这种泄漏比划分泄漏更隐蔽。
6. 读完综述后的延伸思考:应用方向与值得继续挖的选题
6.1 微表情识别的现实应用:为什么大家执着于它
微表情识别的价值很直接:因为它难以伪装,所以特别适合那些“对方有动机隐藏真实情绪”的场景。比如心理咨询中,求访者嘴上说“我没事”,但医生可以从微表情里捕捉到更多信息;再比如安防和审讯场景,微表情可以作为测谎的辅助信号;在人机交互里,机器如果能感知用户压抑的不满,就能在服务变成投诉之前做出调整。
这些场景听起来很强,但综述里也花了篇幅讨论一个现实问题:实验室条件到真实场景的鸿沟。实验室数据是被试坐在固定光源下对着摄像头,背景干净、头部基本固定;真实场景有头部姿态变化、遮挡、光照不均,还有很多复杂的自然交互。模型在数据集上表现再好,也不能直接等同于实际效果。这也是我读综述后对“落地”保持审慎态度的原因——方向是对的,但中间还隔着大量工程问题。
6.2 小数据困境下的几个可行方向
综述读到最后,我最感兴趣的是如何破解“数据太少”的问题。一个方向是自监督预训练,在无标注的普通人脸视频上让模型学会“面部运动变化”的通用表征,再在微表情小数据集上微调。这个思路在图像领域已经比较成熟,应用到微表情上的核心是设计合适的时间维度预训练任务,而不是简单套用图像自监督。
另一个方向是跨数据集迁移。不同数据集的被试、采集设备、诱发范式都不一样,直接用A数据集训练的模型在B数据集上测试往往掉点明显。如果把多个数据集放到一起训练,同时做风格归一化或者特征对齐,模型见过的数据分布更丰富,泛化性会更好。综述里这部分还提到,利用光流图而不是原始RGB图做跨数据集迁移,效果通常更稳定。
第三个方向是和心理学的动作单元标注做结合。动作单元本身就是跨数据集的通用标签,如果先让模型学会预测动作单元,再基于动作单元组合判断情绪类别,就相当于把“表情分类”这个玄学问题,拆成了“哪些肌肉动了”这个相对客观的中间任务。这一点我认为很适合对微表情识别感兴趣的入门者作为研究切入点。
6.3 如果要从零复现一篇微表情论文,我会怎么做
我自己的建议是先不要一上来就跑深度学习大模型。第一步先把数据处理流程跑通:把某个数据集的原始视频解帧成图片序列,提取每一帧的面部区域,计算光流图,确保数据增广和样本划分是可复现的。第二步用LBP-TOP加SVM搭一个简单基线,运行一次LOSO交叉验证,记录UAR和UF1。第三步再去复现一篇深度学习方法,重点关注它的输入形态、划分协议和预处理方案。这样一步步下来,中间任何一步出了问题,你都能定位到是数据处理的问题还是模型的问题,而不是最后拿着一个莫名其妙的错误数字无从下手。
我自己在复现过程中最常踩的坑是帧率不一致:有的数据采集设备是100fps,有的是200fps,如果不把时间轴换算清楚,起步帧、峰值帧和结束帧的对齐就会出错,输入给模型的片段长度也会对不上。另一个坑是面部对齐的标准,不同的面部关键点检测工具输出的人脸裁剪尺寸和位置不一样,导致同样的模型在不同的预处理管线下结果差异巨大。所以复现任何微表情识别论文,第一件事就是确认它的预处理细节,那些在论文附录里不起眼的描述,往往才是决定成败的地方。
最后再分享一点个人体会。微表情识别是一个很容易让人产生“我马上就能读心”的错觉的领域,但实际上它比大多数视觉任务都更依赖对领域本质的理解:对微表情心理学定义的把握、对数据标注过程的认识、对评测协议的敬畏,这些甚至比刷榜技巧更重要。我读这套综述时最大的收获不是记住了某个SOTA模型的名称,而是理解了为什么这个方向进展慢、卡在哪里、哪些习惯性做法是错的。对刚入门的人来说,先建立这种对问题本质的感知,比立刻追新模型有用得多。后面我还会继续整理这个系列的第二篇笔记,重点写光流处理和深度模型复现的代码细节。