第一次接触TSM(Temporal Shift Module)是在去年做一个智能家居项目的时候。当时需要识别老人日常生活中的跌倒动作,试过几种3D卷积网络,但我的GTX 1080显卡根本跑不动。直到发现了TSM这个神器——它通过时间位移操作捕捉视频时序特征,性能接近3D CNN,但计算量只有2D CNN的水平。
TSM的核心创新点在于"时间位移"机制。想象你在看一部电影时,大脑会自动关联前后帧的内容来理解动作。TSM也是这样,它在2D卷积网络中插入特殊模块,让网络能够"偷看"前后几帧的特征。这种设计使得我的旧显卡也能流畅训练视频模型,实测在UCF101数据集上能达到74%的准确率。
相比其他视频模型,TSM有三大优势:
去年在Windows 10上配置环境时,我遇到了几个坑。首先是PyTorch版本问题,官方代码要求1.10.0,但直接pip install会装最新版。后来发现可以用这个命令指定版本:
bash复制pip install torch==1.10.0+cu113 torchvision==0.11.1+cu113 -f https://download.pytorch.org/whl/torch_stable.html
FFmpeg的安装更是个大坑。虽然官网下载了二进制文件,但Python死活找不到。后来发现需要手动添加环境变量,还要在代码里指定路径:
python复制# 在vid2img_ucf101.py中添加
os.environ["PATH"] += os.pathsep + 'C:/ffmpeg/bin'
建议直接用conda创建虚拟环境,这是我验证过的配置清单:
去年为养老院项目制作跌倒检测数据集时,我总结了一套标准化流程。首先要规划好目录结构,建议完全复现UCF101的格式:
code复制MyDataset/
├── videos/
│ ├── Falling/
│ │ ├── v_Falling_g01_c01.avi
│ │ └── v_Falling_g01_c02.avi
│ └── Walking/
│ ├── v_Walking_g01_c01.avi
│ └── v_Walking_g01_c02.avi
└── splits/
├── trainlist01.txt
└── testlist01.txt
视频命名规则要注意:
g01表示第1组拍摄c01表示该组第1个片段我用Premiere Pro剪辑原始视频,导出时选择H.264编码,分辨率统一为320x240。实测发现大于640x480的视频会显著增加训练时间,但对准确率提升有限。
运行vid2img_ucf101.py时最容易出问题的就是帧提取环节。我的经验是:
python复制# 修改这个参数控制抽帧间隔
frame_rate = 10 # 每秒提取10帧
提取后的帧会按这样的结构存放:
code复制frames/
├── Falling/
│ ├── v_Falling_g01_c01/
│ │ ├── img_00001.jpg
│ │ └── img_00002.jpg
└── Walking/
└── v_Walking_g01_c01/
├── img_00001.jpg
└── img_00002.jpg
曾遇到图片命名格式不匹配的问题,解决方案是修改dataset_config.py中的filename_tmpl参数:
python复制# 根据实际图片名前缀修改
'filename_tmpl': 'img_{:05d}.jpg', # 或改为image_{:05d}.jpg
标签生成是最容易出错的一环。我建议先用小批量数据测试,确认生成的标签文件格式正确。关键是要保证classInd.txt和训练/测试列表的一致性:
code复制# classInd.txt格式
1 Falling
2 Walking
# trainlist01.txt格式
Falling/v_Falling_g01_c01 1
Walking/v_Walking_g01_c01 2
我写了个自动检查脚本,可以验证标签是否正确:
python复制import os
for root, _, files in os.walk('frames'):
for file in files:
if not file.endswith('.jpg'):
continue
path = os.path.join(root, file)
# 检查图片是否能正常打开
try:
Image.open(path).verify()
except:
print(f"损坏文件: {path}")
在GTX 1060上训练时,我调整了这些关键参数:
bash复制python main.py mydataset RGB \
--arch resnet50 \
--num_segments 8 \ # 根据GPU内存调整
--batch-size 32 \ # 显存不足时减小
--lr 0.01 \ # 初始学习率
--epochs 50 \ # 小数据集可减少
--dropout 0.5
几个实用技巧:
--eval-freq 5每5个epoch验证一次--tensorboard可视化训练过程num_segments和batch-size训练过程中要监控这些指标:
训练完成后,我用Flask搭建了一个简单的演示系统。核心推理代码如下:
python复制def predict(video_path):
# 1. 抽帧处理
frames = extract_frames(video_path)
# 2. 数据预处理
transform = transforms.Compose([
transforms.Resize(256),
transforms.CenterCrop(224),
transforms.ToTensor(),
transforms.Normalize(mean=[0.485, 0.456, 0.406],
std=[0.229, 0.224, 0.225])
])
# 3. 模型推理
with torch.no_grad():
inputs = torch.stack([transform(f) for f in frames])
outputs = model(inputs.unsqueeze(0))
_, pred = torch.max(outputs.data, 1)
return classes[pred.item()]
在实际部署时发现两个性能瓶颈:
torch.jit.trace将模型转为TorchScript格式Q1: 训练时出现CUDA out of memory
Q2: 验证集准确率波动大
--lr 0.001--wd 1e-4权重衰减Q3: 预测结果全部相同
Q4: 帧提取时卡住
记得训练前先跑通UCF101示例,确保环境配置正确。我在第一次运行时花了三天排查各种环境问题,后来总结了一套环境检查脚本,可以快速验证各组件是否正常工作。