避坑指南:MMAction2训练自定义数据集时,90%的人都会遇到的5个报错及解决方法
MMAction2实战避坑指南:自定义数据集训练中的五大典型错误与解决方案
当你在深夜的显示器前看到又一个红色报错信息时,那种挫败感我深有体会。作为计算机视觉领域最受欢迎的动作识别框架之一,MMAction2的强大功能背后,隐藏着无数让开发者"折戟沉沙"的陷阱。本文将揭示那些官方文档没有明确警告、但实际项目中必定会遇到的五个"杀手级"错误。
1. 文件路径迷宫:FileNotFoundError的七十二变
"文件不存在"这个看似简单的错误,在MMAction2的复杂目录结构中能演变出十几种变体。最常见的是配置文件、数据路径和标签文件三者之间的路径不匹配。
1.1 相对路径与绝对路径的陷阱
MMAction2的配置文件默认使用相对路径,但当你从不同目录执行脚本时,这个相对路径的基准点会发生变化。比如:
# 在项目根目录执行时 python tools/train.py configs/your_config.py # 在tools目录执行时 python train.py ../configs/your_config.py这两种情况下,配置文件中定义的data_root = 'data/myucf101/rawframes'会产生完全不同的解析结果。最佳实践是:
# 在配置文件中使用绝对路径 import os.path as osp data_root = osp.abspath('data/myucf101/rawframes/')1.2 标签文件路径的隐藏规则
标签文件(trainlist.txt/testlist.txt)中的路径格式有严格约定。假设你的视频存放在data/myucf101/videos/ApplyEyeMakeup/目录下,那么标签文件中应该写:
ApplyEyeMakeup/v_ApplyEyeMakeup_g01_c01.avi而不是:
data/myucf101/videos/ApplyEyeMakeup/v_ApplyEyeMakeup_g01_c01.avi # 错误! v_ApplyEyeMakeup_g01_c01.avi # 同样错误!提示:使用
osp.relpath()生成相对路径可以避免手动输入错误
2. 标签格式的暗礁:KeyError背后的数据对齐问题
当看到KeyError: 'ApplyEyeMakeup'这类错误时,说明你的标签系统存在断层。MMAction2要求三类关键文件必须严格对齐:
| 文件类型 | 示例内容 | 校验要点 |
|---|---|---|
| classInd.txt | 1 ApplyEyeMakeup | 类别名必须完全一致 |
| trainlist.txt | ApplyEyeMakeup/video1.avi | 路径前缀匹配类别名 |
| testlist.txt | ApplyEyeMakeup/video2.avi | 不能出现训练集未包含的类别 |
我曾在一个项目中浪费了6小时,最终发现是classInd.txt中使用了"Makeup"而视频目录名为"MakeUp"(大小写差异)。诊断工具推荐:
from mmengine import Config cfg = Config.fromfile('your_config.py') # 检查类别一致性 class_names = set([line.split()[1] for line in open('data/myucf101/txt/classInd.txt')]) video_dirs = set([d.name for d in Path('data/myucf101/videos').iterdir() if d.is_dir()]) print("仅在classInd.txt中的类别:", class_names - video_dirs) print("仅在视频目录中的类别:", video_dirs - class_names)3. CUDA内存不足(OOM):不只是调batch_size那么简单
遇到RuntimeError: CUDA out of memory时,大多数教程只会告诉你减小batch_size,但这只是冰山一角。通过以下策略可以系统性地解决OOM问题:
3.1 内存消耗的四大来源
输入数据尺寸:
- 原始分辨率(256x256) → 裁剪后(224x224)
- 帧数(clip_len x num_clips)
模型结构:
- TSM的时序位移操作
- 3D CNN的时空卷积核
训练配置:
# config中这些参数影响显存 train_dataloader = dict( batch_size=16, # 直接影响显存 num_workers=4, # 影响数据预加载 persistent_workers=True # 保持worker进程 )中间缓存:
- 梯度累积
- AMP混合精度训练
3.2 实用调优表格
| 调整项 | 配置示例 | 显存影响 | 精度影响 |
|---|---|---|---|
| 分辨率 | scale=(-1, 224)→ 180 | 高 | 中 |
| 帧采样策略 | clip_len=8→ 4 | 高 | 高 |
| 数据增强 | 移除MultiScaleCrop | 中 | 中 |
| 梯度累积 | accumulative_counts=4 | 低 | 无 |
| AMP混合精度 | fp16=dict(loss_scale=512) | 高 | 低 |
# 使用gradient checkpointing技术(需修改模型代码) torch.utils.checkpoint.checkpoint_sequential(model.layers, chunks, input)4. 预训练权重加载警告:类型不匹配的深层原因
看到Unexpected key(s) in state_dict或size mismatch警告时,说明模型结构与权重文件存在断层。常见情况有:
4.1 类别数不匹配
Kinetics预训练模型有400类,而你的数据集可能只有10类。需要在配置文件中明确指定:
model = dict( cls_head=dict( num_classes=10, # 必须与classInd.txt中的类别数一致 in_channels=2048 ) )4.2 输入通道差异
如果原始模型使用光流(2通道)而你的数据是RGB(3通道),需要修改第一层卷积:
# 在自定义模型代码中添加 if pretrained: backbone.conv1 = nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3, bias=False) load_checkpoint(model, pretrained, strict=False) # 非严格加载注意:使用
strict=False时,建议用以下代码检查实际加载情况:missing_keys, unexpected_keys = model.load_state_dict(state_dict, strict=False) print(f"未加载的键:{missing_keys}\n意外的键:{unexpected_keys}")
5. 评估指标全零:AccMetric=0的诊断流程图
当训练loss在下降但验证准确率始终为0时,问题可能出在评估环节。按照以下流程排查:
检查数据流:
# 在配置中启用调试模式 train_dataloader = dict( dataset=dict( pipeline=train_pipeline, test_mode=False # 必须为False ) ) val_dataloader = dict( dataset=dict( pipeline=val_pipeline, test_mode=True # 必须为True ) )验证采样策略:
val_pipeline = [ dict( type='SampleFrames', clip_len=1, frame_interval=1, num_clips=8, test_mode=True # 关键区别 ), ... ]检查标签映射:
# 在val_evaluator中添加debug选项 val_evaluator = dict( type='AccMetric', metric_options=dict( topk=(1, 5), debug=True # 打印预测结果 ) )
实际案例:某次调试发现验证时所有样本都被预测为第0类,原因是classInd.txt中的类别索引从1开始,而模型输出是从0开始,需要做pred_label = pred_label + 1的转换。
终极调试工具包
当所有常规方法都失效时,这套组合拳可能会救你一命:
可视化数据流:
from mmaction.utils import register_all_modules register_all_modules() dataset = build_dataset(cfg.train_dataloader.dataset) for i in range(5): data = dataset[i] visualize(data['inputs'], data['data_samples'])模型预测检查:
with torch.no_grad(): output = model(extract_results(data['inputs'])) print(f"预测分布:{torch.softmax(output, dim=1)}")梯度监控:
# 训练时添加--show-grads参数 python tools/train.py configs/your_config.py --show-grads
记住,在MMAction2的世界里,没有解决不了的bug,只有还没找到的日志信息。当你陷入困境时,不妨回到数据流的起点,逐层验证每个环节的数据形态——这往往是突破瓶颈的关键。
