经典论文复现 | 基于深度卷积网络的图像超分辨率算法

栏目: 编程工具 · 发布时间: 7年前

内容简介:笔者本次选择复现的是汤晓鸥教授和何恺明团队发表于 2015 年的经典论文——论文复现代码:

笔者本次选择复现的是汤晓鸥教授和何恺明团队发表于 2015 年的经典论文—— SRCNN 。 超分辨率技术(Super-Resolution)是指从观测到的低分辨率图像重建出相应的高分辨率图像,在监控设备、卫星图像和医学影像等领域都有重要的应用价值。在深度卷积网络的浪潮下, 本文 首次提出了基于深度卷积网络的端到端超分辨率算法。

经典论文复现 | 基于深度卷积网络的图像超分辨率算法

论文复现代码: http://aistudio.baidu.com/aistudio/#/projectdetail/24446

SRCNN流程

经典论文复现 | 基于深度卷积网络的图像超分辨率算法 ▲ SRCNN算法框架

SRCNN 将深度学习与传统稀疏编码之间的关系作为依据,将 3 层网络划分为 图像块提取 (Patch extraction and representation)、 非线性映射 (Non-linear mapping)以及最终的 重建 (Reconstruction)。

SRCNN 具体流程如下:

1. 先将低分辨率图像使用双三次差值放大至目标尺寸(如放大至 2 倍、3 倍、4 倍),此时仍然称放大至目标尺寸后的图像为低分辨率图像(Low-resolution image),即图中的输入(input);

2. 将低分辨率图像输入三层 卷积神经网络 。举例:在论文其中一个实验相关设置,对 YCrCb 颜色空间中的 Y 通道进行重建,网络形式为 (conv1+relu1)—(conv2+relu2)—(conv3+relu3);第一层卷积:卷积核尺寸 9×9 (f1×f1),卷积核数目 64 (n1),输出 64 张特征图;第二层卷积:卷积核尺寸 1×1 (f2×f2),卷积核数目 32 (n2),输出 32 张特征图;第三层卷积:卷积核尺寸 5×5 (f3×f3),卷积核数目 1 (n3),输出 1 张特征图即为最终重建高分辨率图像。

经典论文复现 | 基于深度卷积网络的图像超分辨率算法

训练

训练数据集

论文中某一实验采用 91 张自然图像作为训练数据集,对训练集中的图像先使用双三次差值缩小到低分辨率尺寸,再将其放大到目标放大尺寸,最后切割成诸多 33 × 33 图像块作为训练数据,作为标签数据的则为图像中心的 21 × 21 图像块(与卷积层细节设置相关)。

损失函数

采用 MSE 函数作为 卷积神经网络 损失函数。

经典论文复现 | 基于深度卷积网络的图像超分辨率算法

卷积层细节设置

第一层卷积核 9 × 9,得到特征图尺寸为 (33-9)/1+1=25,第二层卷积核 1 × 1,得到特征图尺寸不变,第三层卷积核 5 × 5,得到特征图尺寸为 (25-5)/1+1=21。训练时得到的尺寸为 21 × 21,因此图像中心的 21 × 21 图像块作为标签数据(卷积训练时不进行 padding)。

# 查看个人持久化工作区文件
!ls /home/aistudio/work/
# coding=utf-8
import os
import paddle.fluid as fluid
import paddle.v2 as paddle
from PIL import Image
import numpy as np
import scipy.misc
import scipy.ndimage
import h5py
import glob

FLAGS={"epoch": 10,"batch_size": 128,"image_size": 33,"label_size": 21,
      "learning_rate": 1e-4,"c_dim": 1,"scale": 3,"stride": 14,
      "checkpoint_dir": "checkpoint","sample_dir": "sample","is_train": True}

#utils
def read_data(path):
    with h5py.File(path, 'r') as hf:
        data = np.array(hf.get('data'))
        label = np.array(hf.get('label'))
        return data, label

def preprocess(path, scale=3):

    image = imread(path, is_grayscale=True)
    label_ = modcrop(image, scale)

    label_ = label_ / 255.
    input_ = scipy.ndimage.interpolation.zoom(label_, zoom=(1. / scale), prefilter=False)  # 一次
    input_ = scipy.ndimage.interpolation.zoom(input_, zoom=(scale / 1.), prefilter=False)  # 二次,bicubic

    return input_, label_

def prepare_data(dataset):
    if FLAGS['is_train']:
        data_dir = os.path.join(os.getcwd(), dataset)
        data = glob.glob(os.path.join(data_dir, "*.bmp"))
    else:
        data_dir = os.path.join(os.sep, (os.path.join(os.getcwd(), dataset)), "Set5")
        data = glob.glob(os.path.join(data_dir, "*.bmp"))

    return data

def make_data(data, label):
    if not os.path.exists('data/checkpoint'):
        os.makedirs('data/checkpoint')
    if FLAGS['is_train']:
        savepath = os.path.join(os.getcwd(), 'data/checkpoint/train.h5')
    # else:
    #     savepath = os.path.join(os.getcwd(), 'data/checkpoint/test.h5')

    with h5py.File(savepath, 'w') as hf:
        hf.create_dataset('data', data=data)
        hf.create_dataset('label', data=label)

def imread(path, is_grayscale=True):
    if is_grayscale:
        return scipy.misc.imread(path, flatten=True, mode='YCbCr').astype(np.float)  # 将图像转灰度
    else:
        return scipy.misc.imread(path, mode='YCbCr').astype(np.float)  # 默认为false

def modcrop(image, scale=3):

    if len(image.shape) == 3:  # 彩色 800*600*3
        h, w, _ = image.shape
        h = h - np.mod(h, scale)
        w = w - np.mod(w, scale)
        image = image[0:h, 0:w, :]
    else:  # 灰度 800*600
        h, w = image.shape
        h = h - np.mod(h, scale)
        w = w - np.mod(w, scale)
        image = image[0:h, 0:w]
    return image

def input_setup(config):
    if config['is_train']:
        data = prepare_data(dataset="data/data899/Train.zip_files/Train")
    else:
        data = prepare_data(dataset="Test")

    sub_input_sequence = []
    sub_label_sequence = []
    padding = abs(config['image_size'] - config['label_size']) // 2  # 6 填充

    if config['is_train']:
        for i in range(len(data)):
            input_, label_ = preprocess(data[i], config['scale'])  # data[i]为数据目录

            if len(input_.shape) == 3:
                h, w, _ = input_.shape
            else:
                h, w = input_.shape
            for x in range(0, h - config['image_size'] + 1, config['stride']):
                for y in range(0, w - config['image_size'] + 1, config['stride']):
                    sub_input = input_[x:x + config['image_size'], y:y + config['image_size']]  # [33 x 33]
                    sub_label = label_[x + padding:x + padding + config['label_size'],
                                y + padding:y + padding + config['label_size']]  # [21 x 21]

                    # Make channel value,颜色通道1
                    sub_input = sub_input.reshape([config['image_size'], config['image_size'], 1])
                    sub_label = sub_label.reshape([config['label_size'], config['label_size'], 1])

                    sub_input_sequence.append(sub_input)
                    sub_label_sequence.append(sub_label)
        arrdata = np.asarray(sub_input_sequence)  # [?, 33, 33, 1]
        arrlabel = np.asarray(sub_label_sequence)  # [?, 21, 21, 1]

        make_data(arrdata, arrlabel)  # 把处理好的数据进行存储,路径为checkpoint/..
    else:
        input_, label_ = preprocess(data[4], config['scale'])

        if len(input_.shape) == 3:
            h, w, _ = input_.shape
        else:
            h, w = input_.shape
        input = input_.reshape([h, w, 1])

        label = label_[6:h - 6, 6:w - 6]
        label = label.reshape([h - 12, w - 12, 1])

        sub_input_sequence.append(input)
        sub_label_sequence.append(label)

        input1 = np.asarray(sub_input_sequence)
        label1 = np.asarray(sub_label_sequence)
        return input1, label1, h, w

def imsave(image, path):
    return scipy.misc.imsave(path, image)
#train
def reader_creator_image_and_label():
    input_setup(FLAGS)
    data_dir= os.path.join('./data/{}'.format(FLAGS['checkpoint_dir']), "train.h5")
    images,labels=read_data(data_dir)
    def reader():
        for i in range(len(images)):
            yield images, labels
    return reader
def train(use_cuda, num_passes,BATCH_SIZE = 128, model_save_dir='../models'):
    if FLAGS['is_train']:
      images = fluid.layers.data(name='images', shape=[1, FLAGS['image_size'], FLAGS['image_size']], dtype='float32')
      labels = fluid.layers.data(name='labels', shape=[1, FLAGS['label_size'], FLAGS['label_size']], dtype='float32')
    else:
      _,_,FLAGS['image_size'],FLAGS['label_size']=input_setup(FLAGS)
      images = fluid.layers.data(name='images', shape=[1, FLAGS['image_size'], FLAGS['label_size']], dtype='float32')
      labels = fluid.layers.data(name='labels', shape=[1, FLAGS['image_size']-12, FLAGS['label_size']-12], dtype='float32')

    #feed_order=['images','labels']
    # 获取<mark data-type="technologies" data-id="72b0bcc0-d8f9-4edd-919f-fa7c2560388c">神经网络</mark>的训练结果
    predict = model(images)
    # 获取<mark data-type="technologies" data-id="4c38563a-2d9b-439e-bfb4-21d209eeff3e">损失函数</mark>
    cost = fluid.layers.square_error_cost(input=predict, label=labels)
    # 定义平均<mark data-type="technologies" data-id="4c38563a-2d9b-439e-bfb4-21d209eeff3e">损失函数</mark>
    avg_cost = fluid.layers.mean(cost)
    # 定义优化方法
    optimizer = fluid.optimizer.Momentum(learning_rate=1e-4,momentum=0.9)
    opts =optimizer.minimize(avg_cost)

    # 是否使用GPU
    place = fluid.CUDAPlace(0) if use_cuda else fluid.CPUPlace()

    # 初始化执行器
    exe=fluid.Executor(place)
    exe.run(fluid.default_startup_program())
    # 获取训练数据
    train_reader = paddle.batch(
        reader_creator_image_and_label(), batch_size=BATCH_SIZE)
    # 获取测试数据
    # test_reader = paddle.batch(
    #     read_data(), batch_size=BATCH_SIZE)
    #print(len(next(train_reader())))
    feeder = fluid.DataFeeder(place=place, feed_list=[images, labels])
    for pass_id in range(num_passes):
        for batch_id, data in enumerate(train_reader()):
            avg_cost_value = exe.run(fluid.default_main_program(),
                                    feed=feeder.feed(data),
                                    fetch_list=[avg_cost])

            if batch_id%100 == 0:
                print("loss="+avg_cost_value[0])

def model(images):
    conv1=fluid.layers.conv2d(input=images, num_filters=64, filter_size=9, act='relu')
    conv2=fluid.layers.conv2d(input=conv1, num_filters=32, filter_size=1,act='relu')
    conv3=fluid.layers.conv2d(input=conv2, num_filters=1, filter_size=5)
    return conv3

if __name__ == '__main__':
    # 开始训练
    train(use_cuda=False, num_passes=10)

测试

全卷积网络

所用网络为全卷积网络,因此作为实际测试时,直接输入完整图像即可。

Padding

训练时得到的实际上是除去四周 (33-21)/2=6 像素外的图像,若直接采用训练时的设置(无 padding),得到的图像最后会减少四周各 6 像素(如插值放大后输入 512 × 512,输出 500 × 500)。

因此在测试时每一层卷积都进行了 padding(卷积核尺寸为 1 × 1的不需要进 行 padding),这样保证插值放大后输入与输出尺寸的一致性。

重建结果

客观评价指标 PSNR 与 SSIM:相比其他传统方法,SRCNN 取得更好的重建效果。

经典论文复现 | 基于深度卷积网络的图像超分辨率算法

主观效果:相比其他传统方法,SRCNN 重建效果更具优势。

经典论文复现 | 基于深度卷积网络的图像超分辨率算法


以上所述就是小编给大家介绍的《经典论文复现 | 基于深度卷积网络的图像超分辨率算法》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Code Reading

Code Reading

Diomidis Spinellis / Addison-Wesley Professional / 2003-06-06 / USD 64.99

This book is a unique and essential reference that focuses upon the reading and comprehension of existing software code. While code reading is an important task faced by the vast majority of students,......一起来看看 《Code Reading》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具