041、数据增强的艺术:超分任务中的退化模拟、裁剪策略与数据预处理

📅 2026/7/4 7:20:50
041、数据增强的艺术:超分任务中的退化模拟、裁剪策略与数据预处理
041、数据增强的艺术超分任务中的退化模拟、裁剪策略与数据预处理去年有个项目让我记忆犹新。团队用EDSR在DIV2K上训得好好的PSNR飙到34.5一上真实监控视频直接崩到28。放大四倍后人脸糊成一团边缘全是锯齿。我们当时第一反应是模型不够强换RCAN、换SAN甚至上了SwinIR效果有提升但远不如预期。后来排查了三天发现是数据预处理环节出了问题——训练时用的双三次下采样而真实场景的退化是压缩噪声运动模糊传感器噪声的复合体。从那以后我养成了一个习惯先看数据再看模型。退化模拟别让模型活在理想国超分任务最容易被忽视的坑就是“退化假设”。大多数论文默认用双三次插值下采样生成LR-HR对但真实世界的退化过程远比这复杂。我见过太多人直接拿MATLAB的imresize或者OpenCV的resize做下采样然后抱怨模型泛化差。退化模型应该怎么搭我的做法是构建一个退化池包含多种退化操作# 这里踩过坑别只用一个退化函数defbuild_degradation_pool():pool[]# 模糊核高斯、运动、散焦pool.append(lambdax:gaussian_blur(x,sigmanp.random.uniform(0.5,3.0)))pool.append(lambdax:motion_blur(x,anglenp.random.uniform(0,360),sizenp.random.randint(3,15)))# 噪声高斯、泊松、椒盐pool.append(lambdax:add_gaussian_noise(x,stdnp.random.uniform(0,25)))pool.append(lambdax:add_poisson_noise(x,scalenp.random.uniform(0.1,1.0)))# JPEG压缩模拟有损压缩pool.append(lambdax:jpeg_compress(x,qualitynp.random.randint(30,95)))returnpool关键点在于随机组合。每次训练时从池中随机选2-3个退化操作按随机顺序应用。顺序很重要——先模糊再下采样和先下采样再模糊结果完全不同。我一般先做模糊再做下采样最后加噪声和压缩这样更接近真实成像管线的物理顺序。别这样写固定退化参数。比如sigma固定为1.5那模型学到的只是特定模糊程度的逆映射换个场景就失效。应该让sigma在合理范围内均匀采样甚至可以用截断高斯分布来模拟更真实的退化分布。还有一个容易被忽略的点尺度因子随机化。不要只训2倍、3倍、4倍可以训1.5倍、2.7倍这种非整数倍。做法很简单下采样时用随机缩放因子然后通过插值或裁剪对齐到固定尺寸。这能让模型学到尺度不变性对实际应用中的任意缩放需求特别有用。裁剪策略别让模型只看到局部数据裁剪看起来简单但里面的门道不少。很多人直接随机裁剪96x96的patch然后扔进模型训练。这样做的问题在于模型只看到了局部纹理学不到全局结构。多尺度裁剪是我常用的策略。训练时同时裁剪不同尺度的patch# 这里踩过坑别只用固定尺寸defmulti_scale_crop(hr,lr,scale,patch_sizes[48,64,96,128]):# 随机选一个patch sizepatch_sizenp.random.choice(patch_sizes)# 根据scale计算LR侧patch sizelr_patch_sizepatch_size//scale# 随机裁剪位置h,whr.shape[:2]xnp.random.randint(0,h-patch_size1)ynp.random.randint(0,w-patch_size1)hr_patchhr[x:xpatch_size,y:ypatch_size]lr_patchlr[x//scale:x//scalelr_patch_size,y//scale:y//scalelr_patch_size]returnhr_patch,lr_patch小patch让模型关注高频细节大patch让模型理解结构上下文。混合使用能让模型既会“画细节”又会“搭骨架”。别这样写固定裁剪位置。比如只在图像中心裁剪或者只裁剪固定区域。这样模型会学到位置偏置测试时遇到不同构图的图像就崩了。应该让裁剪位置完全随机甚至可以加上一些边界padding来避免边缘效应。还有一个进阶技巧困难样本挖掘。训练过程中记录每个patch的lossloss高的patch说明模型当前处理不好下次训练时多采样这些区域。实现起来很简单维护一个loss队列每次裁剪时以一定概率比如30%从高loss区域采样。这能加速收敛尤其对纹理复杂区域效果明显。数据预处理细节决定成败预处理环节的坑比想象中多。我见过最离谱的是有人直接用uint8数据训练结果模型输出全是255。也见过有人归一化时用错了均值和标准差导致训练不收敛。归一化策略超分任务和分类任务不同不需要ImageNet的均值和标准差。我一般用两种方式简单归一化直接除以255把像素值映射到[0,1]区间。简单有效适合大多数场景。零均值归一化减去数据集均值再除以标准差。这种方式能让模型更快收敛但需要提前统计数据集统计量。# 这里踩过坑别直接用ImageNet的归一化参数defnormalize_sr(hr,lr):# 简单归一化hrhr.astype(np.float32)/255.0lrlr.astype(np.float32)/255.0# 或者零均值归一化需要提前计算# hr_mean, hr_std compute_dataset_stats(hr_dataset)# hr (hr - hr_mean) / (hr_std 1e-8)returnhr,lr数据增强除了退化模拟常规的数据增强也不能少。但要注意超分任务的增强和分类任务不同不能随意改变图像内容。几何增强随机翻转水平、垂直、随机旋转90度倍数。这些操作不会改变图像内容适合超分任务。颜色增强轻微调整亮度、对比度、饱和度。幅度要小否则会引入伪影。别这样写随机裁剪后直接resize到固定尺寸。这会破坏LR-HR的对应关系导致模型学到错误的映射。边界处理下采样时LR和HR的边界对齐是个问题。如果HR尺寸不能被scale整除LR会多出一些像素。我一般用两种方式中心裁剪先下采样然后从LR和HR的中心各裁剪一个对齐的区域。反射填充在边界处用反射填充保证下采样后尺寸匹配。实战经验这些坑我替你踩过了退化模拟的强度要适中。太强会让模型学不到有效信息太弱又起不到泛化作用。我一般把退化参数控制在“人眼能看出退化但还能辨认内容”的程度。数据预处理和模型训练要解耦。不要在训练循环里做预处理应该提前把数据准备好存成numpy数组或HDF5格式。这样能节省大量IO时间。验证集要用真实退化。不要用和训练集相同的退化方式做验证否则PSNR虚高。我一般准备一个真实场景的验证集比如手机拍摄的照片或监控视频帧。数据增强要在线做。每次训练时随机应用增强而不是提前增强后存起来。这样能产生无限多的训练样本避免过拟合。记录退化参数。训练时把每次应用的退化参数记录下来方便后期分析模型对不同退化的敏感度。我一般用wandb或tensorboard记录这些信息。别迷信大patch。patch不是越大越好大patch会降低batch size影响训练效率。我一般用64x64或96x96的patch配合多尺度策略效果更好。数据预处理要可复现。设置随机种子保证每次实验的预处理流程一致。这样调试时才能定位问题出在模型还是数据。最后说一句数据预处理花的时间会在模型训练和测试时十倍百倍地回报你。别急着调模型先把数据搞明白。