手把手带你训练 CVPR2022 视频超分模型

简介: RealBasicVSR 小课堂继续开课啦!上一期文章中我们解读了真实视频超分的文章 RealBasicVSR,今天我们将手把手带大家一起使用 MMEditing 训练 RealBasicVSR。这一次我们会重点关注数据处理,希望大家看完这一期的内容后能更了解 RealBasicVSR 的训练方式和 MMEditing 的数据处理流程。

RealBasicVSR 小课堂继续开课啦!上一期文章中我们解读了真实视频超分的文章 RealBasicVSR,今天我们将手把手带大家一起使用 MMEditing 训练 RealBasicVSR。这一次我们会重点关注数据处理,希望大家看完这一期的内容后能更了解 RealBasicVSR 的训练方式和 MMEditing 的数据处理流程。


RealBasicVSR 训练方式



让我们来先了解一下 RealBasicVSR 是如何训练的。RealBasicVSR 是通过大量生成退化(例如Gaussian blur, Poisson noise, JPEG compression)的不同组合用作监督训练。通过不同退化的组合,RealBasicVSR 在一定程度上可以泛化到真实场景当中。RealBasicVSR 使用的是 Real-ESRGAN 的二阶退化模型,下图是 Real-ESRGAN 原文中的图解:

640.png

上图的二阶退化模型仅使用了 Blur, resize, noise 等等生成退化。因此,我们可以在训练中很容易获得相应的退化,在作用到高清图片中得到低清图片。RealBasicVSR 的退化大致跟上图一样。唯一不同的是为了针对视频退化,我们在 JPEG 压缩后加上视频压缩。


定义 Model 和 Backbone



我们要先在配置文件中定义 Model 和 Backbone,如下:

# model settings
model = dict(
    type='RealBasicVSR',
    generator=dict(
        type='RealBasicVSRNet',
        mid_channels=64,
        num_propagation_blocks=20,
        num_cleaning_blocks=20,
        dynamic_refine_thres=255,  # change to 1.5 for test
        spynet_pretrained='https://download.openmmlab.com/mmediting/restorers/'
        'basicvsr/spynet_20210409-c6c1bd09.pth',
        is_fix_cleaning=False,
        is_sequential_cleaning=False),
    pixel_loss=dict(type='L1Loss', loss_weight=1.0, reduction='mean'),
    cleaning_loss=dict(type='L1Loss', loss_weight=1.0, reduction='mean'),
    is_use_sharpened_gt_in_pixel=True,
    is_use_ema=True,
)


定义数据处理流程



早期的超分辨率模型假设退化是固定的(例如 bicubic 下采样),因为不需要考虑泛他性的问题,我们只需要对于高清图片作出对应的退化得到低清图片然后保存,再在训练期间直接读取高清和低清的图片对。


但是使用二阶退化模型时,为了提高泛化性,退化的参数是随机选取的。因此,我们不能先生成图片对再直接读取。所以,我们要对数据处理作出修改:只读取高清图片,再加上随机退化得到低清图片。我们再来看看配置文件。从 52 行到 195 行都是我们的随机退化,我们接下来看看不同退化的设置。


RandomBlur


dict(
    type='RandomBlur',
    params=dict(
        kernel_size=[7, 9, 11, 13, 15, 17, 19, 21],
        kernel_list=[
            'iso', 'aniso', 'generalized_iso', 'generalized_aniso',
            'plateau_iso', 'plateau_aniso', 'sinc'
        ],
        kernel_prob=[0.405, 0.225, 0.108, 0.027, 0.108, 0.027, 0.1],
        sigma_x=[0.2, 3],
        sigma_y=[0.2, 3],
        rotate_angle=[-3.1416, 3.1416],
        beta_gaussian=[0.5, 4],
        beta_plateau=[1, 2],
        sigma_x_step=0.02,
        sigma_y_step=0.02,
        rotate_angle_step=0.31416,
        beta_gaussian_step=0.05,
        beta_plateau_step=0.1,
        omega_step=0.0628),
    keys=['lq'],
),

首先我们会对图片加上模糊。MMEditing 支持不同的模糊,例如 isotropic gaussian, anisotropic gaussian 等等。在使用的时候我们可以在 kernel_list 标明想使用的 kernel。另外,我们需要设置不同模糊的参数,例如 kernel_size 和各个模糊被选取的概率等等。


值得注意的是, RealBasicVSR 提出了 stochastic degradation scheme。大概意思就是每一帧之间的退化参数都会有区别。所以我们在上述代码中可以看到 xxx_step 的设置,而 xxx_step 就是定义参数区别的大小。以 sigma_x_step 作为例子,如果现在的 sigma_x 是 0.5, 在 sigma_x_step 是 0.02 的情况下, sigma_x 在下一帧就会在 0.48 和 0.52 之间随机选取。


RandomResize


dict(
    type='RandomResize',
    params=dict(
        resize_mode_prob=[0.2, 0.7, 0.1],  # up, down, keep
        resize_scale=[0.15, 1.5],
        resize_opt=['bilinear', 'area', 'bicubic'],
        resize_prob=[1 / 3.0, 1 / 3.0, 1 / 3.0],
        resize_step=0.015,
        is_size_even=True),
    keys=['lq'],
),

接着就是随机更改图片大小。上述代码中看到的 resize_mode_prob 就是图片被上采样、下采样,和保持大小的概率。以 resize_scale=[0.15, 1.5] 为例子,上述代码中的设定就是一个图片会有 0.2 的概率上采样到 1x-1.5x 的大小,0.7 的概率下采样的 0.15x-1x 的大小,和有 0.1 的概率维持现有的大小。值得注意的是,这里的 scale 是随机选取的。接着 resize_opt 就是使用什么 resize 的操作。现在 MMEditing 支持 cv2 里的 “bilinear”, “area” 和 “bicubic”。而 resize_step 的意思和 Blur 的 xxx_step 意思一样,在一定范围内改变下一帧的 resize_scale 。我们还提供了 is_size_even 的参数,因为在作用视频压缩时,图片的大小要求是偶数。如果需要使用视频压缩时,我们需要把 is_size_even 置为 True。


RandomNoise

dict(
    type='RandomNoise',
    params=dict(
        noise_type=['gaussian', 'poisson'],
        noise_prob=[0.5, 0.5],
        gaussian_sigma=[1, 30],
        gaussian_gray_noise_prob=0.4,
        poisson_scale=[0.05, 3],
        poisson_gray_noise_prob=0.4,
        gaussian_sigma_step=0.1,
        poisson_scale_step=0.005),
    keys=['lq'],
),

然后就是加上噪声。MMEditing 现在支持 Gaussian 和 Poisson 两种噪声。参数的设置和之前大同小异。


RandomJPEGCompression

dict(
    type='RandomJPEGCompression',
    params=dict(quality=[30, 95], quality_step=3),
    keys=['lq'],
),


RandomVideoCompression

dict(
    type='RandomVideoCompression',
    params=dict(
        codec=['libx264', 'h264', 'mpeg4'],
        codec_prob=[1 / 3., 1 / 3., 1 / 3.],
        bitrate=[1e4, 1e5]),
    keys=['lq'],
),

除了上面的图像退化外,我们在训练 RealBasicVSR 时也加上了视频压缩。MMEditing 提供了 libx264,h264 和 mpeg4 的压缩,用户只需要注明 bit rate 就可以。


DegradationsWithShuffle

dict(
    type='DegradationsWithShuffle',
    degradations=[
        dict(
            type='RandomVideoCompression',
            params=dict(
                codec=['libx264', 'h264', 'mpeg4'],
                codec_prob=[1 / 3., 1 / 3., 1 / 3.],
                bitrate=[1e4, 1e5]),
            keys=['lq'],
        ),
        [
            dict(
                type='RandomResize',
                params=dict(
                    target_size=(64, 64),
                    resize_opt=['bilinear', 'area', 'bicubic'],
                    resize_prob=[1 / 3., 1 / 3., 1 / 3.]),
            ),
            dict(
                type='RandomBlur',
                params=dict(
                    prob=0.8,
                    kernel_size=[7, 9, 11, 13, 15, 17, 19, 21],
                    kernel_list=['sinc'],
                    kernel_prob=[1],
                    omega=[3.1416 / 3, 3.1416],
                    omega_step=0.0628),
            ),
        ]
    ],
    keys=['lq'],
),

最后要介绍的是随机改变退化顺序的操作。在BSRGAN 这个工作中,退化的顺序就是随机组合,从而提高退化的多样性。MMEditing 当然也支持这个操作。我们只需要使用 DegradationsWithShuffle ,里面的 degradations 参数就是你希望使用的退化,与个别的退化定义是一样的。在有一些情况中,你可能想保留个别退化的顺序,这时候你只需要把对应的退化放在一个 list 里就可以。例如上述代码中的 RandomResize 和 RandomBlur,因为它们在一个 list 里面,他们的顺序是保持不变的,即是永远都是先 resize 然后 blur。

定义训练和测试配置



data = dict(
    workers_per_gpu=10,
    train_dataloader=dict(
        samples_per_gpu=2, drop_last=True, persistent_workers=False),
    val_dataloader=dict(samples_per_gpu=1, persistent_workers=False),
    test_dataloader=dict(samples_per_gpu=1, workers_per_gpu=1),
    # train
    train=dict(
        type='RepeatDataset',
        times=150,
        dataset=dict(
            type=train_dataset_type,
            lq_folder='data/REDS/train_sharp_sub',
            gt_folder='data/REDS/train_sharp_sub',
            num_input_frames=15,
            pipeline=train_pipeline,
            scale=4,
            test_mode=False)),
    # val
    val=dict(
        type=val_dataset_type,
        lq_folder='data/UDM10/BIx4',
        gt_folder='data/UDM10/GT',
        pipeline=val_pipeline,
        scale=4,
        test_mode=True),
    # test
    test=dict(
        type=val_dataset_type,
        lq_folder='data/VideoLQ',
        gt_folder='data/VideoLQ',
        pipeline=test_pipeline,
        scale=4,
        test_mode=True),
)
# optimizer
optimizers = dict(generator=dict(type='Adam', lr=1e-4, betas=(0.9, 0.99)))
# learning policy
total_iters = 300000
lr_config = dict(policy='Step', by_epoch=False, step=[400000], gamma=1)
checkpoint_config = dict(interval=5000, save_optimizer=True, by_epoch=False)
# remove gpu_collect=True in non distributed training
evaluation = dict(interval=5000, save_image=False, gpu_collect=True)
log_config = dict(
    interval=100,
    hooks=[
        dict(type='TextLoggerHook', by_epoch=False),
        dict(type='TensorboardLoggerHook'),
    ])
visual_config = None
# custom hook
custom_hooks = [
    dict(
        type='ExponentialMovingAverageHook',
        module_keys=('generator_ema', ),
        interval=1,
        interp_cfg=dict(momentum=0.999),
    )
]

最后就是定义训练和测试时的 batch size,数据路径,优化器等等的配置。在 custom_hooks 里我们看到 ExponentialMovingAverageHook,这是对于 RealBasicVSR 的 weights 做一个 moving average,这个设计可以让表现稳定一点,大家可以留意一下。


训练过程



当把数据准备好后,我们就可以开始训练和测试。训练的时候只需要输入:

./tools/dist_train.sh configs/restorers/real_basicvsr/realbasicvsr_wogan_c64b20_2x30x8_lr1e-4_300k_reds.py 8


训练完毕后可以用相同指令加上 adversarial loss 和 perceptual loss 训练:

./tools/dist_train.sh configs/restorers/real_basicvsr/realbasicvsr_c64b20_1x30x8_lr5e-5_150k_reds.py 8

要留意的是需要在第二阶段的配置文件中的 load_from 更改成第一阶段训练的模型路径。


结语



MMEditing 提供了最前沿的真实图像和视频超分训练模式。我们的模块化设计也可以让大家方便的增加或减少各种退化。当你需要新的退化时,只需要写出对应的代码和修改配置文入件,不用重新写一个新的 dataloader。欢迎大家来试试,享受一下高清的快感


文章来源:【OpenMMLab

 2022-04-18 18:05

相关实践学习
基于阿里云DeepGPU实例,用AI画唯美国风少女
本实验基于阿里云DeepGPU实例,使用aiacctorch加速stable-diffusion-webui,用AI画唯美国风少女,可提升性能至高至原性能的2.6倍。
目录
相关文章
|
2天前
Halcon 学习笔记九:mlp训练学习实战颜色识别
Halcon 学习笔记九:mlp训练学习实战颜色识别
61 0
|
2天前
|
机器学习/深度学习 人工智能 自然语言处理
【EMNLP 2023】基于大语言模型的复杂任务认知推理算法CogTree
近日,阿里云人工智能平台PAI与华东师范大学张伟教授团队合作在自然语言处理顶级会议EMNLP2023上发表了基于认知理论所衍生的CogTree认知树生成式语言模型。通过两个系统:直觉系统和反思系统来模仿人类产生认知的过程。直觉系统负责产生原始问题的多个分解假设,反思系统对直觉系统产生的假设进行验证,并选择更有可能的假设进行后续生成,直到达到最终结果。通过上述双系统的迭代式生成,可以提升大模型的解题准确度。
|
10月前
|
机器学习/深度学习 人工智能 计算机视觉
【YOLOv8】实战一:手把手教你使用YOLOv8实现实时目标检测
【YOLOv8】实战一:手把手教你使用YOLOv8实现实时目标检测
10603 0
【YOLOv8】实战一:手把手教你使用YOLOv8实现实时目标检测
|
12月前
|
机器学习/深度学习
CVPR2021 GAN详细解读 | AdaConv自适应卷积让你的GAN比AdaIN更看重细节(附论文下载)(二)
CVPR2021 GAN详细解读 | AdaConv自适应卷积让你的GAN比AdaIN更看重细节(附论文下载)(二)
81 0
|
12月前
|
机器学习/深度学习 编解码 计算机视觉
CVPR2021 GAN详细解读 | AdaConv自适应卷积让你的GAN比AdaIN更看重细节(附论文下载)(一)
CVPR2021 GAN详细解读 | AdaConv自适应卷积让你的GAN比AdaIN更看重细节(附论文下载)(一)
347 0
|
12月前
|
机器学习/深度学习 自然语言处理 固态存储
CVPR2021全新Backbone | ReXNet在CV全任务以超低FLOPs达到SOTA水平(文末下载论文和源码)(二)
CVPR2021全新Backbone | ReXNet在CV全任务以超低FLOPs达到SOTA水平(文末下载论文和源码)(二)
105 0
CVPR2021全新Backbone | ReXNet在CV全任务以超低FLOPs达到SOTA水平(文末下载论文和源码)(二)
|
12月前
|
机器学习/深度学习 PyTorch 文件存储
CVPR2021全新Backbone | ReXNet在CV全任务以超低FLOPs达到SOTA水平(文末下载论文和源码)(一)
CVPR2021全新Backbone | ReXNet在CV全任务以超低FLOPs达到SOTA水平(文末下载论文和源码)(一)
64 0
|
机器学习/深度学习 人工智能 自然语言处理
深度学习与CV教程(15) | 视觉模型可视化与可解释性
本文讲解了一些理解 CNN 可视化的方法(特征、滤波器可视化),以及一些有趣的应用,如DeepDream、图像神经风格迁移(特征反演 + 纹理生成)等【对应 CS231n Lecture 12】
18840 1
深度学习与CV教程(15) | 视觉模型可视化与可解释性
|
机器学习/深度学习 计算机视觉
【论文速递】CVPR2021 - 用于目标检测的通用实例蒸馏
【论文速递】CVPR2021 - 用于目标检测的通用实例蒸馏
110 0
【论文速递】CVPR2021 - 用于目标检测的通用实例蒸馏
|
机器学习/深度学习 计算机视觉 Python
手把手带你调参Yolo v5 (v6.2)(推理)(一)
手把手带你调参Yolo v5 (v6.2)(推理)
手把手带你调参Yolo v5 (v6.2)(推理)(一)