061、自定义数据集训练:如何将自己的图像和视频数据用于超分模型

📅 2026/7/6 5:51:55 👁️ 阅读次数 📝 编程学习
061、自定义数据集训练:如何将自己的图像和视频数据用于超分模型

061、自定义数据集训练:如何将自己的图像和视频数据用于超分模型

上周帮一个做遥感图像的朋友调试超分模型,他兴冲冲地拿来一堆卫星图,结果训练到一半loss直接炸了——NaN满天飞。我一看数据,好家伙,16位TIFF直接喂给模型,像素值范围0-65535,模型压根没见过这种阵仗。这种坑我踩过不止一次,今天就把自定义数据集训练超分模型的完整流程掰开揉碎讲清楚。

数据准备:别让格式坑了你

先说说图像数据。很多人以为超分训练就是拿一堆高清图扔进去,然后模型自动学会放大。天真了。超分训练的核心是构造低分辨率-高分辨率对,模型学的是从低到高的映射关系,不是凭空变出细节。

你手头的图像,不管是从相机拍的、网上爬的还是专业设备采集的,第一步要做的是统一格式。我习惯把所有图像转成PNG或BMP,避免JPEG压缩带来的块效应污染训练数据。如果你非要用JPEG,至少保证质量因子在95以上,不然模型学到的全是压缩伪影的修复技巧,不是真正的超分能力。

这里有个血泪教训:别用8位图像训练超分模型然后指望输出16位结果。模型输出的位深和输入是一致的,你想做HDR超分,训练数据就得是HDR格式。我见过有人拿普通8位图训练,然后要求模型输出16位,结果就是颜色断层严重,跟水彩画似的。

数据预处理:双三次下采样不是唯一选择

构造LR-HR对时,最常用的方法是双三次下采样。但如果你做的是真实场景超分,比如监控图像、老照片修复,双三次下采样出来的LR图像和真实低分辨率图像差距很大。真实低分辨率图像包含传感器噪声、光学模糊、压缩失真等多种退化,单纯的双三次下采样太干净了。

我自己的做法是:根据应用场景设计退化模型。做遥感超分,我会加入高斯模糊和泊松噪声;做视频超分,我会考虑运动模糊和压缩伪影。代码实现时,可以用OpenCV的退化函数组合,也可以直接用BasicSR框架里的退化模块,后者封装得比较完善。

# 这里踩过坑:直接用cv2.resize做下采样,然后发现模型在真实低分辨率图上效果很差# 后来改成模拟真实退化importcv2importnumpyasnpdefdegrade_image(hr_img,scale=4,noise_level=0.05):# 先加模糊模拟光学退化kernel_size=int(scale*2)+1blurred=cv2.GaussianBlur(hr_img,(kernel_size,kernel_size),0)# 下采样lr=cv2.resize(blurred,(hr_img.shape[1]//scale,hr_img.shape[0]//scale),interpolation=cv2.INTER_CUBIC)# 加噪声模拟传感器噪声noise=np.random.randn(*lr.shape)*noise_level*255lr=np.clip(lr+noise,0,255).astype(np.uint8)returnlr

别这样写:直接把HR图resize成小尺寸就当LR用,除非你确定你的应用场景就是理想退化。

视频数据的特殊处理

视频超分和图像超分最大的区别在于时序一致性。你单独对每一帧做超分,然后拼回去,会发现画面闪烁、抖动,因为模型对每一帧的处理不一致。

处理视频数据时,我通常先做关键帧提取。不是所有帧都需要,相邻帧之间信息冗余太大。一般每秒取10-15帧就够了,动作快的场景可以多取一些。然后以关键帧为中心,前后各取2-3帧构成一个clip,作为训练样本。

# 视频帧提取,别用opencv的默认参数,它会把帧读成BGR# 超分模型一般用RGB,记得转换cap=cv2.VideoCapture('input_video.mp4')fps=cap.get(cv2.CAP_PROP_FPS)frame_interval=max(1,int(fps/12))# 每秒取12帧frames=[]count=0whileTrue:ret,frame=cap.read()ifnotret:breakifcount%frame_interval==0:frame_rgb=cv2.cvtColor(frame,cv2.COLOR_BGR2RGB)frames.append(frame_rgb)count+=1

视频超分训练时,clip的长度很关键。太短了学不到时序信息,太长了显存放不下。我一般用5帧,前2后2加中间帧。训练时随机从视频中截取clip,而不是固定位置,这样数据多样性更好。

数据增强:别只做水平翻转

很多人做数据增强就是水平翻转、垂直翻转、旋转90度,完事。对于超分任务,这些远远不够。超分模型对纹理细节敏感,你需要让模型见过各种尺度和方向的纹理。

我常用的增强策略:

  • 随机裁剪:从HR图上随机裁patch,然后生成对应的LR patch。patch大小根据模型感受野定,EDSR这类大模型需要96x96以上,轻量模型64x64就够了。
  • 随机旋转:0, 90, 180, 270度,加上随机翻转。注意旋转后要同步处理LR和HR,别只转一个。
  • 颜色抖动:轻微调整亮度、对比度、饱和度。别调太狠,不然模型学的是颜色映射不是超分。
  • 混合分辨率:同一个batch里混入不同下采样倍数的样本,让模型学会处理多种尺度。这个技巧在真实场景超分中特别有用。
# 这里踩过坑:颜色抖动参数设太大,模型输出颜色漂移# 现在只用很小的幅度fromtorchvisionimporttransforms color_jitter=transforms.ColorJitter(brightness=0.1,# 别超过0.2contrast=0.1,saturation=0.05,hue=0.02)

训练策略:学习率调度是门玄学

自定义数据集训练超分模型,最怕的就是过拟合。你的数据集可能只有几百张图,而模型参数量动辄几百万。这时候需要一些trick。

先用预训练权重初始化。不管你的数据多特殊,先在DIV2K或Flickr2K上预训练过的权重基础上微调,效果远好于从头训练。我试过用EDSR在遥感图像上从头训练,跑了三天PSNR还不如预训练模型微调两小时。

学习率要小。微调时初始学习率设1e-4,每10个epoch衰减0.5。如果loss震荡,说明学习率大了,降到5e-5试试。别用固定学习率,超分模型训练后期需要精细调整。

验证集要模拟真实场景。不要用双三次下采样的验证集,那会给你虚假的自信。用真实的低分辨率图像验证,或者用你设计的退化模型生成验证集。我习惯在验证集上同时看PSNR和SSIM,但更看重主观效果——PSNR高但图像模糊的情况太常见了。

数据加载:别让IO成为瓶颈

很多人训练超分模型时,GPU利用率只有30-40%,一看CPU和磁盘IO已经100%了。这是因为超分训练需要频繁读取大尺寸图像,而且每次都要做下采样、裁剪等预处理。

解决方案:

  • 预处理成patch:把HR图像预先裁成小patch,存成npy或h5文件。训练时直接读取patch,省去实时裁剪的开销。
  • 使用LMDB数据库:把图像序列化存入LMDB,读取速度比文件系统快一个数量级。BasicSR框架默认支持LMDB格式。
  • 多进程数据加载:PyTorch的DataLoader设置num_workers=4或8,但别超过CPU核心数。我试过设成16,结果系统卡死。
# 别这样写:每次训练都从原始大图裁剪,IO开销巨大# 应该预处理成patchimporth5pydefpreprocess_to_patches(hr_dir,lr_dir,patch_size=96,scale=4):# 遍历所有HR图像,裁成patch并保存# 同时生成对应的LR patch# 保存为h5文件,训练时直接读取pass# 具体实现略,思路最重要

个人经验性建议

  1. 数据质量比数量重要。100张高质量、多样性的图像,效果远好于1000张重复、模糊的图像。我见过有人从视频里抽了10000帧训练,结果模型学到的全是相同场景的不同角度,泛化能力极差。

  2. 别迷信PSNR。PSNR高不代表超分效果好,尤其是自定义数据集上。我做过一个实验,用GAN训练的超分模型PSNR比ESRGAN低0.5dB,但人眼看起来细节更真实。如果做应用,建议同时用NIQE、PIQE等无参考评价指标。

  3. 视频超分先做对齐。如果你的视频有运动,帧与帧之间没有对齐,直接训练时序模型会学到运动模糊。建议先用光流法或特征匹配做帧对齐,再送入模型。EDVR和BasicVSR都内置了对齐模块,但需要你提供对齐后的数据。

  4. 混合精度训练要小心。超分模型对精度敏感,混合精度训练容易导致梯度消失或爆炸。我一般先用FP32训练几个epoch,确认loss稳定后再切到AMP。如果发现loss异常,立刻切回FP32。

  5. 保存中间结果。每训练一个epoch,在验证集上跑一次,保存超分结果。肉眼观察比看loss曲线更直观。我经常发现loss在下降,但超分结果越来越模糊——这是过拟合的征兆。

最后说一句,自定义数据集训练超分模型,80%的时间花在数据准备上,10%花在调参,只有10%是真正的训练。别急着跑模型,先把数据搞清楚,后面会省很多事。