Accurate Image Super-Resolution Using Very Deep Convolutional Networks論文分析

論文地址

簡介

我們提出一個高精確度的單張圖像超分辨率重建方法。我們的方法由VGG-net啓發。
網絡的深度對於超分精確度有着十分重要的的影響,最終網絡模型爲20層。通過許多小尺寸的卷積層相連,有效的利用了圖像中的上下文信息,面對深度網絡難以訓練的問題,我們使用學習residuals,使用大的學習率、梯度剪裁來解決這個問題。最後,實驗證明我們提出的方法十分有效。

指出SRCNN的不足指出:
1.It relies on the context of small image regions;
2.Second, training converges too slowly;
3.Third, the network only works for a single scale。

解決方法:
1.增加了感受野,在處理大圖像上有優勢,由SRCNN的(1313)變爲(4141)。
2.採用殘差圖像進行訓練,增大學習率,收斂速度變快,因爲殘差圖像更加稀疏,更加容易收斂(換種理解就是LR攜帶低頻信息,這些信息依然被訓練到HR圖像,然而HR圖像和LR圖像的低頻信息相近,這部分花費了大量時間進行訓練),相當於只對LR和HR的差值進行modelling。
3.考慮多個尺度,一個卷積網絡可以處理多尺度問題。

模型圖

在這裏插入圖片描述

補充說明

1.該論文利用殘差網絡,加深網絡結構(20層),在圖像的超分辨率上取得了較好的效果,感受野大小(2D+1)X(2D+1)
2.作者採取了殘差學習,提高學習率來爲梯度傳輸排除障礙,節省時間
3.輸入圖片的大小不一致,使得網絡可以針對不同倍數的超分辨率操作,
4.卷積後補0使得圖像大小保持一致.

卷積可以提高較大的感受野,感受野就是視野的意思,圖片預測,如果利用一個像素點去推斷一個像素點,那麼是做不好的,所以就要用卷積,卷積使得可以根據NXN個像素去推斷目標像素值,圖像處理中大家普遍認爲像素之間是有相關性的,所以根據更多的像素數據去推斷目標像素,也是認爲是一個提高效果的操作

一個5X5的圖片利用3X3的卷積核,卷積2次,輸出爲1個1X1的像素,則這個輸出結果考慮到了5X5的像素信息,也就是感受野爲5X5。

但是傳統的卷積操作會使圖片通過逐步卷積,圖像大小也越來越小,一個很小的圖,首先不適合一個很深的網絡(這會要求輸入圖片的size很大),

其次,如果採取傳統的卷積操作,邊界像素會因考慮的區域少,感受野小而導致結果較差,於是傳統的做法是對卷積結果做一個裁剪,剪去邊界區域,隨之產生一個新的問題,裁剪後的圖像(卷積後本來就很小了)變的更小,用論文原話來說就是:After cropping,the final image is too small to be visually pleasing.
於是對於邊界問題,作者提出一個新的策略,就是每次卷積後,圖像的size變小,但是,在下一次卷積前,對圖像進行補0操作,恢復到原來大小,這樣不僅解決了網絡深度的問題,同時,實驗證明對邊界像素的預測結果也得到了提升。

模型框架

訓練的策略:

1.採用殘差的方式進行訓練,避免訓練過長的時間。
2.使用大的學習進行訓練。
3.自適應梯度裁剪,將梯度限制在某一個範圍,本文采用自適應梯度方法,將梯度限制在在這裏插入圖片描述 ,其中γ是學習率。
4.多尺度,多種尺度樣本一起訓練可以提高大尺度的準確率。

在這裏插入圖片描述
在這裏插入圖片描述

殘差學習Residual-Learning

1.殘差圖像定義爲HR圖像減去LR圖像
2.損失函數定義爲殘差圖像與預測值的均方誤差
3.損失層接受的輸入爲殘差估計,網絡輸入LR和真值HR
4.損失通過計算重構圖像和真值圖像的歐氏距離得到
5.採用小批量梯度下降法來進行訓練
在這裏插入圖片描述

Pytorch代碼實現

model.py

import torch
import torch.nn as nn
from math import sqrt


class Conv_ReLU_Block(nn.Module):
    def __init__(self):
        super(Conv_ReLU_Block, self).__init__()
        self.conv = nn.Conv2d(in_channels=64, out_channels=64, kernel_size=3, stride=1, padding=1, bias=False)
        self.relu = nn.ReLU(inplace=True)

    def forward(self, x):
        return self.relu(self.conv(x))


class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.residual_layer = self.make_layer(Conv_ReLU_Block, 18)  # 一共20層,除了第一層和最後一層,中間的18層
        self.input = nn.Conv2d(in_channels=1, out_channels=64, kernel_size=3, stride=1, padding=1, bias=False)
        self.output = nn.Conv2d(in_channels=64, out_channels=1, kernel_size=3, stride=1, padding=1, bias=False)
        self.relu = nn.ReLU(inplace=True)

        for m in self.modules():
            if isinstance(m, nn.Conv2d):  # 如果是卷積層
                n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels
                m.weight.data.normal_(0, sqrt(2. / n))  # 權重初始化

    def make_layer(self, block, num_of_layer):
        layers = []  # 定義一個空列表,存放創建的每一層結構
        for _ in range(num_of_layer):
            layers.append(block())  # 從Net第三行可以看出,傳入block對應的參數是Conv_ReLU_Block(),即一個拼接的Conv2d層和一個ReLU層
        return nn.Sequential(*layers)  # layers前面的*代表將列表通過非關鍵字參數的形式傳入

    def forward(self, x):
        residual = x
        out = self.relu(self.input(x))  # 首先通過第一層input layer
        out = self.residual_layer(out)  # 再通過18層相同的卷積層
        out = self.output(out)  # 最後通過最後一層output layer
        out = torch.add(out, residual)
        return out

11

1

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章