
简介CK人脸表情数据集由Cohn-Kanade数据集扩展而来是人脸表情识别领域广泛使用的标准资源主要面向计算机视觉研究者、深度学习开发者和相关专业学生。该资源可用于七类基本表情识别模型的训练与评估帮助解决表情动态变化建模、特征提取和自动化标注等关键问题。压缩包共包含928个文件以920张PNG序列图像为主体记录了中性、快乐、悲伤、惊讶、愤怒、厌恶、恐惧表情从起始到峰值的连续变化同时附带C语言数据整理脚本、PDF参考论文及使用说明文档便于图像预处理、标注规范查阅和算法复现整包大小约139.77MB。目前已有2523人学习使用可应用于学术算法验证、情感计算、人机交互、心理学研究等场景。该数据集提供多帧表情序列、关键点定位、表情强度评分与情感标签等丰富标注能直接支撑深度学习模型训练、特征提取方法对比及表情识别系统开发对推动表情识别技术的研究与落地具有重要价值。 从入行做计算机视觉到现在我见过太多数据集“你方唱罢我登场”但有一个老面孔始终没从论文和开源项目里消失——CK人脸表情数据集。十多年过去了新模型、新榜单层出不穷但一提“标准benchmark”“基线对比”还是绕不开它。甚至在一些日常沟通里同行说到表情识别第一句就是“你在CK上跑多少”。这个数据集的独特之处在于它不算大动辄上万的现代数据集比比皆是但它贵在“干净”和“标注质量极高”。论文里做对比实验用CK的人远多于用其他野榜数据的人面试算法岗时聊到表情识别面试官也常拿“你在CK上怎么调”来起手。如果你要入门人脸表情识别或者要给论文补一个通用基准CK几乎是绕不开的第一步。不过越是老牌数据集资料越分散很多细节藏在一封封邮件和零散的readme里。这篇文章就把CK从申请下载、目录结构、标注格式到训练模型时最容易被忽略的暗坑完整串一遍最后聊一聊它和现代真实场景数据之间的边界在哪里。无论你是第一次接触这个数据集的初学者还是已经跑过但觉得“哪里不对”的进阶老手应该都能有些收获。1. 这个“老古董”为什么至今还是默认基准1.1 一个反直觉的现象小数据集反而更能说明问题很多刚接触的人会困惑现在表情识别数据集不是有AffectNet、RAF-DB这些几万、几十万样本的“大块头”吗为什么做算法对比时大家还要回头在CK上再跑一遍我记得早年在组里做表情识别导师的第一句话说“先别急着上大模型把CK跑通你看看能不能到90%以上。”当时不理解测精度不应该是数据集越大越有说服力吗后来才琢磨明白这里面的道理。大数据集虽然样本多但很多是互联网采集标签噪声不小光照、姿态、遮挡干扰很大。模型在这些数据上的分数既可能是学到了真东西也可能是在“死记硬背”某些场景模式很难完全理性地归因。而CK是受控实验室环境下采集的人脸位置、光照、姿态都比较规整表情是从中性到峰值的连续帧标签是经过训练的编码员逐帧标注的。你在它上面提一个点大概率是算法本身真的有效而不是恰好适配了某种数据分布。所以CVPR、ICCV这些顶会论文里做表情识别或面部动作单元分析的几乎都要在CK上报一个数本质上是给审稿人一个“这方法在公认的干净基准上没崩”的信号。这个作用是大数据集替代不了的。1.2 CK与原始CK的差异扩展版到底扩展了什么CK的全称是Extended Cohn-Kanade Dataset由卡内基梅隆大学和匹兹堡大学联合发布。它前面还有个CK原始版本现在基本已经没人用了但不妨碍我们把历史脉络理清楚。原始CK发布于2000年左右包含大约100多人的表情视频序列侧重在FACS面部动作编码系统编码上。而CK的扩展主要在三块序列数量从原本的几百增加到593个覆盖了123个受试者增加了七类基本表情的标签愤怒、轻蔑、厌恶、恐惧、快乐、悲伤、惊讶提供了更完善的68点面部关键点坐标landmarks方便做人脸对齐和形状特征提取。这些看起来只是“多一点数据、多几个标签文件”但对做研究的人来说最关键的是表情标签终于可以用了。因为原始CK里面很多序列只有FACS标签没有对应的离散情绪标签没法直接用于表情分类任务。CK把这个问题解决了这也是它成了默认基准的硬条件之一。还有一个容易被忽略的点CK里每个样本不是一张静态图而是一个图像序列通常从中性脸开始逐步过渡到表情峰值。这意味着它天然适合做成“时序表情识别”的研究也是后来很多论文说“我们用CK的峰值帧”这个说法的由来。2. 数据集的目录结构与标注逻辑2.1 目录组织与样本命名规律刚拿到CK压缩包的时候如果不看readme可能会被文件夹层级弄得有点晕。它的目录结构大致如下cohn-kanade-images/ S010/ 001/ S010_001_00000001.png S010_001_00000002.png ... S010_001_00000012.png 002/ ... S011/ ... FACS_labels/ landmarks/ Emotion_labels/四类文件的含义分别是cohn-kanade-images原始图像序列灰度PNG图分辨率通常是640x490或640x480FACS_labels每帧对应的面部动作单元编码文件A/B/C三种强度示例文本格式landmarks每帧对应的68点面部关键点坐标文本格式顺序对应dlib等库输出的索引Emotion_labels序列级别的表情标签文件每个序列包含两个文本文件一个固定为0表示第一帧中性另一个是对应峰值帧的表情编号。命名规律其实是有信息量的。以S010_001_00000012.png为例S010是受试者编号001是序列编号后面的数字是帧序号。注意不同受试者、不同序列的帧数不固定所以看到有些序列只有10帧有些有20多帧都是正常的。遍历文件夹时不要假设所有序列长度一致。2.2 标签文件与7类1类表情的编码约定关于Emotion_labels代码里写的时候要特别小心。它的标签不是全序列都标每个序列文件夹下通常只有两个txtS010_001_00000001_emotion.txt内容是0标记中性帧S010_001_00000012_emotion.txt内容是具体编号比如5表示高兴中间那些帧没有表情标签文件只有图像。这种做法对训练来说意味着一个视频序列往往只能提取出“中性帧峰值帧”两个可用分类样本。这也解释了为什么CK给人感觉“很大”但真正能当单帧分类用的样本数其实不多。标签数值的对应关系是固定的写代码时最好直接定义成常量别用魔法数字EMOTION_MAP { 0: neutral, 1: anger, 2: contempt, 3: disgust, 4: fear, 5: happy, 6: sadness, 7: surprise }这里有个容易踩的坑很多人写分类代码时以为表情类别是1到7把中性帧扔掉有人则反过来把0也当成一类训练。这都没错取决于你要做什么任务。但如果要和论文里的数字对齐就得先看清对比论文是“7类”不含中性还是“8类”含中性。CK官方论文里常用的是7类基本表情因为中性本身不是基本表情但实际做模型时很多人会把中性单列一类因为应用场景里总需要识别“没表情”。FACS标签的格式更复杂一点它是用类似1425这样的组合代表多个动作单元同时激活。做AU检测的人才会用到这里不展开。但值得注意的是FACS文件是按帧可用的每个视频帧都有对应的AU编码文件所以做“动作单元强度回归”的人更喜欢用CK因为它是少见的帧级能对上AU标注的数据集。3. 获取授权与落地前的预处理3.1 申请下载流程中的几个要点CK不是直接注册就能下载的公共数据集它需要向发布方申请。这个流程经常被论文复现的人忽略结果卡在“没有数据集”这一步。申请需要访问卡内基梅隆大学相关页面的数据集申请表填写姓名、机构、邮箱、使用目的等信息。有些高校或公司的公共邮箱会被拦截此类邮件建议用机构域名邮箱并在垃圾邮件箱里翻一翻。审核周期不等快的一两天慢的一两周申请主要用于科研用途商业用途基本会被拒绝。我个人的经验是申请邮件里把你的研究方向、具体要做什么任务写清楚并说明会遵循数据使用条款通过的效率会高一些。另外下载链接有时会用压缩包分卷的形式给下载后要仔细比对校验文件。如果发现某个分卷损坏不要用浏览器续传直接重新下载那个分卷否则解压时会报“unexpected end of data”。拿到压缩包后建议先解压到一个稳定路径因为后面所有预处理脚本都会依赖这个路径结构。如果换了机器、换了目录一堆硬编码路径的脚本就会全挂。3.2 图像帧选取从视频序列到静态样本的取舍CK原始数据是序列帧但绝大多数表情识别模型输入是静态图像。所以“从序列中取哪一帧作为训练样本”是一个从一开始就要想清楚的决策。三种常见做法只取峰值帧每个序列最后一帧就是表情最明显的帧用这一帧对应一个表情标签。这样每个有表情标签的序列只贡献1个样本样本量最小但标签最干净。取中性帧峰值帧中性帧作为“负样本”峰值帧作为“正样本”相当于把每个序列变成两个样本。这是很多论文的做法也是我推荐的做法因为模型可以学到“从平静到激动”的对比。取中间所有帧数据量最大但中间帧的表情强度参差不齐标签存在模糊性。有些帧你可能看不出是什么表情但被强行标成了某个类。第一种和第二种比较常用第三种一般配合“自监督预训练”或者“标签分布学习”使用。我后来回头看发现很多排行榜上虚高的数字其实是用第一种取完峰值帧后、又做了随机裁剪等增强刷出来的泛化性经不起考验。所以在写复现说明时一定要标明“本文取峰值帧”还是“取中性峰值帧”。预处理中的另一步是人脸对齐。CK自带landmarks只是文本文件不是图片标注框。常见操作是读取68个关键点然后用标准模板做相似变换把眼睛对准同一个位置再裁剪到224x224输入网络。这里要注意某些landmarks文件的坐标值不是整数分辨率而是浮点型读取时别顺手转int否则对齐完会发现头部角度偏了。4. 用CK训练一个表情识别模型的全流程4.1 数据划分与类别平衡处理CK一共593个序列但不是所有序列都有表情标签。按官方统计只有327个序列带七类基本表情标签其余序列要么只有FACS编码要么未标定情绪类别。所以如果你打算做基本表情分类实际可用的序列数量约327个。这327个序列中类别分布也不均匀。粗略来看快乐和惊讶样本比较多轻蔑很少恐惧也不算多。如果用简单的随机划分很容易出现某一类在验证集中只有一两个样本的情况评估结果方差很大。我推荐两条划分策略按受试者划分把同一个人的所有序列放进同一个fold避免同一个人同时出现在训练集和验证集中否则模型会因为“见过这人”而虚高几个百分点。这一点很多人会忽略但论文审稿人越来越看重。采用交叉验证或多组随机划分因为数据量小一次性划分的运气成分很大。我习惯跑5次不同种子的划分取平均值和标准差来报告。如果你的任务类别数实在太少比如蔑视类只有几十个样本有几个补救办法将蔑视类合并到邻近类别变成6类做数据增强水平翻转、轻微旋转、亮度抖动但尽量在训练时做别在提前扩到磁盘上否则验证集里可能出现增强后的样本泄漏使用类别加权损失函数让少数类的loss贡献更大。我自己最终用的方案是6类分类砍掉蔑视加上中性帧一共7类。因为蔑视这个类别本身在训练和测试中都极其不稳定丢掉之后模型稳定性反而更好。4.2 模型选型与训练实录CK是灰度图单通道分辨率不高。不需要一上来就上Swin Transformer或者ViT-Huge我记得第一次用ResNet18做实验就能跑到接近95%的准确率。真正拉开差距的不是模型大小而是输入预处理和对齐质量。一个可复现的baseline配置如下import torch from torchvision.models import resnet18, ResNet18_Weights model resnet18(weightsResNet18_Weights.IMAGENET1K_V1) model.conv1 torch.nn.Conv2d(1, 64, kernel_size7, stride2, padding3, biasFalse) num_features model.fc.in_features model.fc torch.nn.Linear(num_features, 7)这里有个细节ImageNet预训练模型输入是3通道而CK是灰度图。直接把灰度图复制成三通道再输入是最省事的做法也能用上预训练权重但如果你想从第一层开始重新调灰度特征就把conv1改成1通道输入。实测下来前者收敛更快后者最终精度略高一点点但差距通常在1%以内。可以按算力预算选。训练时的超参数我有几个实践经验输入尺寸224x224够用不需要更大优化器Adam初始学习率1e-4或1e-3都行加一个StepLR或者余弦退火Batch size32或64数据量小bn层一定不要dropout开太大Epoch30-50个epoch之间就够太久了会明显过拟合。CK数据量小loss下降很快但val准确率容易停在95%附近波动。如果训练过程中发现训练集准确率已经99%而验证集只有80%多那就是过拟合了。除了加正则化和数据增强还有一种很有效的方式做人脸关键点对齐后的crop不要丢整张图进去。因为原始图像中背景占比高模型很容易学到“背景不同→表情不同”这种虚假关联。4.3 评估指标与过拟合判断在CK上做表情分类最常见的评估指标就是Overall Accuracy和混淆矩阵。一个成熟的实验除了给平均准确率还应该看每个类别的recall和precision。因为类别不平衡准确率高并不代表个别类不崩。比如很多论文报CK的平均准确率在98%以上但只要看混淆矩阵就会发现恐惧和悲伤经常互相混惊讶和快乐相对容易区分。如果你的验证集里恰好恐惧类样本少准确率会显得非常好看。我自己测试时会打印每个epoch里验证集每一类的recall并观察训练集和验证集的loss曲线。CK上有一个典型现象训练集loss和验证集loss在前几个epoch同步下降但10个epoch后验证集loss开始反弹这就是过拟合的明确信号。此时不要盲目加epoch而是考虑降低学习率增加数据增强强度缩小模型容量提前停止。还有一点值得单独说不要只用一组固定划分的结果就下结论。CK太小单次划分的验证集可能只有30-40张图一个样本的预测翻转都可能造成2-3个百分点的波动。所以正式汇报时最好跑多个随机种子取均值用标准差作为误差棒这比单次结果可信得多。5. CK的边界在哪里实验室数据与真实场景的鸿沟5.1 为什么在CK上表现良好的模型落地会翻车在CK上练出来的模型拿去做校园课堂专注度分析、车载驾驶员状态监测常常会出现“实验室精度97%现场表现惨不忍睹”的情况。这不是模型没调好而是CK本身的分布和现实世界存在系统性差异。这背后有几条很扎实的原因采集环境是实验室光线均匀背景单一正面朝向无遮挡。真实场景里逆光、低头、侧脸、戴口罩、手机遮挡随便一个条件都可能让模型失效样本以欧美面孔为主肤色、五官比例比较同质。换到东亚人群跨域性能明显下降表情是表演或引导出来的具有明显的“峰值形态”而真实表情往往强度低、混杂、持续时间短。CK里“平静的伤心”和“强颜欢笑”几乎不存在图像是灰度且在受控分辨率下采集和手机拍摄的彩色、压缩、低光照图像差异巨大。所以如果你要在真实产品里做表情识别我的建议是不要只用CK训练而是把它作为“模型是否学到基本表情能力”的一个离散指标再混入AffectNet、RAF-DB等真实场景数据做联合训练或者领域自适应。5.2 面向真实场景的多数据集混合策略我实践过比较可行的方案是用CK做模型的“初始化校准”再用真实场景数据做迁移微调。具体来说第一步在CK上做预实验快速验证网络结构、增强策略、超参数是否正常工作。CK数据量小训练一轮快的几分钟能迅速暴露代码bug和方向错误。第二步把训练好的模型在RAF-DB或AffectNet这些真实场景数据上继续微调。预训练权重有了一个“表情语义”的初始化点收敛比完全从头训快很多。RAF-DB包含真实世界的人脸表情样本背景复杂、姿态多样非常适合跨域迁移。第三步如果目标场景非常特定比如“驾驶员疲劳检测”还要用自己的业务数据做最后一层的fine-tune甚至做伪标注联合训练。这样做的效果我实测过比单独用CK训练或单独用RAF-DB从零训练都要好。原因也不复杂CK虽然量少但标注质量极高等于给模型输入了“什么是一个标准表情”的先验真实数据量大但噪声多模型在两者之间取了一个平衡。还有一个细节由于CK是灰度图如果你全程用CK预训练模型第一个卷积层的通道数是1迁移到彩色数据时要先复制通道或者改回3通道。建议预训练阶段就用3通道输入灰度图复制三次这样后续迁移不用改动网络结构。5.3 给新手的配套工具箱如果你正打算复现CK上的表情识别实验下面这些小工具和经验可以省不少时间人脸检测与对齐可以用OpenCV的DNN人脸检测器或者MediaPipe检测人脸并提取68点关键点然后做相似变换对齐。如果不做检测直接整图训练可能会被背景干扰数据读取脚本建议写一个Dataset类按受试者分组划分索引避免后续代码越写越乱存储格式小规模实验直接用文件夹命名规则就行不必转成LMDB或TFRecord反而增加调试成本可视化工具用matplotlib把每个序列的中性帧和峰值帧并排打印出来检查标签对齐是否准确。这一步看似简单但能避免大量“标签对错帧”的隐蔽bug。我记得有一次跑实验怎么调准确率都上不去后来把所有峰值帧打印出来一看发现脚本里frame序号取错了取成了中性帧。这种错误只有可视化才能快速暴露。结尾用CK这么多年我的体会是它不像那些新兴的大规模数据集那样能让你“大力出奇迹”但它是一块极好的试金石逼着你在数据预处理、标签对齐、训练策略这些基础细节上下硬功夫。谁能在这么小的数据上稳定刷出高分数谁才敢说自己是真把表情识别这件事理解了。最后再分享一个小技巧如果你决定用CK做论文实验记得在论文中写明“we use the final frame of each sequence for evaluation”并注明是否包含中性类。这两个注释能省去审稿人反复猜疑的麻烦也能让复现的人少走很多弯路。本文还有配套的精品资源点击获取