1. 程式人生 > 實用技巧 >基於飛槳PaddlePaddle實現的Sub-Pixel影象超解析度

基於飛槳PaddlePaddle實現的Sub-Pixel影象超解析度

此文轉載自:https://my.oschina.net/u/4067628/blog/4766302
大咖揭祕Java人都栽在了哪?點選免費領取《大廠面試清單》,攻克面試難關~>>>

基於飛槳PaddlePaddle實現的Sub-Pixel影象超解析度

1.專案介紹

本文則參考論文:Real-Time Single Image and Video Super-Resolution Using an Efficient Sub-Pixel Convolutional Neural Network ,使用飛槳最新的分支版本,實現了一個輕量級影象的超解析度模型,旨在帶領各位小夥伴快速瞭解飛槳框架2.0,也可以在此基礎上修改、優化模型,實現自己的超解析度演算法。

飛槳PaddlePaddle

最近迎來了重大更新,進入了2. 0時代。AI Studio也同步上線了最新版本得線上程式設計環境,又送免費GPU算力,這波羊毛不薅都對不起自己啊(手動狗頭)。飛槳框架2.0新添加了許多常用的API,豐富的API介面給開發帶來了便利,能夠比較輕鬆的完成模型搭建及訓練。如果小夥伴們對本專案感興趣,歡迎來AI Studio Fork 執行嘗試。

下載安裝命令

## CPU版本安裝命令
pip install -f https://paddlepaddle.org.cn/pip/oschina/cpu paddlepaddle

## GPU版本安裝命令
pip install -f https:
//paddlepaddle.org.cn/pip/oschina/gpu paddlepaddle-gpu

AI Studio專案地址:
https://aistudio.baidu.com/aistudio/projectdetail/1109418

2.前言

影象和視訊通常包含著大量的視覺資訊,且視覺資訊本身具有直觀高效的描述能力,所以隨著資訊科技的高速發展,影象和視訊的應用逐漸遍佈人類社會的各個領域。近些年來,在計算機影象處理,計算機視覺和機器學習等領域中,來自工業界和學術界的許多學者和專家都持續關注著視訊影象的超解析度技術這個基礎熱點問題。

影象超解析度的英文名稱是 Image Super Resolution。它指的是從低解析度影象中恢復高解析度影象的過程。

這項技術在現實世界中有廣泛的應用,最常見的應用場景就是圖片的壓縮傳輸:為了在同等頻寬下獲得更高的影象質量,超解析度演算法適用於低頻寬時低質量影象上的增強。除了提升影象感知的品質,也有助於提升其他計算機視覺任務,例如遙感領域、醫學成像領域。傳統的超解析度方法有:基於預測的方法、基於邊緣的方法、基於統計的方法、基於修補的方法、以及稀疏表示方法等。

近些年深度學習技術的快速發展,使得基於深度學習的超解析度模型效能優異,大量深度學習方法被應用於解決超解析度任務,早期的代表作有SRCNN和SRGAN,近期CVPR2020上也有不少相關的論文,例如:DRN和USRNet。總的來說,深度學習超解析度演算法之間各不相同,主要是由於下面幾個主要的方向:不同型別的網路結構、不同型別的損失函式、不同型別的學習原則和策略等。

SRCNN:

SRGAN:

DRN:

USRNet:

3.專案背景

3.1摘要:

近年來,基於深度神經網路的單影象超解析度重建模型在重建精度和計算效能方面都有了很大的進展。但是這些演算法都太複雜了,效率很低。在本文中,我們提出了一種新的CNN架構,可以有效地降低計算的複雜度。在公開資料集上的評估結果表明,該方法的效能明顯優於之前基於CNN的方法(影象為+0.15dB),並且比其他基於CNN的方法快了一個數量級。

3.2 網路結構:

與以往的工作不同,此專案在網路的末端才將解析度從LR提高到HR,並從LR特徵圖中超解析度地解析HR資料。這樣就不需要在更大的HR解析度下執行大部分超解析度SR操作。為此,我們提出了一種有效的亞畫素卷積層來學習影象和視訊超解析度的上尺度運算。這樣做有兩個優點:
每個LR影象被直接送入網路,通過LR空間中的非線性卷積進行特徵提取。由於輸入解析度降低,我們可以有效地使用較小的過濾器大小來整合相同的資訊,同時保持給定的上下文區域。解析度和濾波器尺寸的減小,大大降低了計算量和記憶體的開銷,但是足以實時實現超解析度。
對於一個有圖層的網路,我們學習了特徵對映的上尺度過濾器,而不是輸入影象的一個上尺度過濾器。此外,不使用顯式插值濾波器意味著網路隱式地學習SR所需的處理。因此,與在第一層向上擴充套件單個固定濾波器相比,網路能夠學習更好和更復雜的LR到HR對映,這使得模型重建精度的有額外提高。

3.3 基於Paddle的程式碼:

這裡僅展示了部分關鍵程式碼,詳細實現請參考AI Studio專案:
https://aistudio.baidu.com/aistudio/projectdetail/1109418

3.3.1 資料預處理

飛槳框架2.0 為我們封裝好了Dataset類,我們定義資料讀取器類時只需要繼承自它並實現__getitem__返回讀取的內容和__len__方法返回資料的樣本數。這裡,我們需要資料讀取器返回一張縮小後的圖片和一張沒有縮放的圖片,這兩張圖片都只有Ycbcr通道中的Y通道,因為大量的研究表表明人眼對亮度更敏感,所以我們這裡只對亮度通道Y進行取樣。

class BSD_data(Dataset):

    def __init__(self,
                 mode='train',
                 image_path="data/data55873/images/"
                ):
        super(BSD_data, self).__init__()

        self.mode = mode.lower()
        if self.mode == 'train':
            self.image_path = os.path.join(image_path,'train')
        elif self.mode == 'val':
            self.image_path = os.path.join(image_path,'val')            
        else:
            raise ValueError('mode must be "train" or "val"')

        # 原始影象的縮放大小
        self.crop_size = 300
        # 縮放倍率
        self.upscale_factor = 3
        # 縮小後送入神經網路的大小
        self.input_size = self.crop_size // self.upscale_factor
        # numpy隨機數種子
        self.seed=1337
        # 圖片集合
        self.temp_images = []
        # 載入資料
        self._parse_dataset()

    def transforms(self, img):
        """
        影象預處理工具,用於將升維(100, 100) => (100, 100,1),
        並進行維度轉換 H W C => C H W
        """
        if len(img.shape) == 2:
            img = np.expand_dims(img, axis=2)
        return img.transpose((2, 0, 1))

    def __getitem__(self, idx):
        """
        返回 縮小3倍後的圖片 和 原始圖片
        """
        # 載入原始影象
        img = self._load_img(self.temp_images[idx])
        # 將原始影象縮放到(3, 300, 300)
        img = img.resize(
          [self.crop_size,self.crop_size], 
          Image.BICUBIC
        )

        #轉換為YCbCr影象
        ycbcr = img.convert("YCbCr")

        # 因為人眼對亮度敏感,所以只取Y通道
        y, cb, cr = ycbcr.split()
        y = np.asarray(y,dtype='float32')
        y = y / 255.0

        # 縮放後的影象和前面採取一樣的操作
        img_ = img.resize(
          [self.input_size,self.input_size], 
          Image.BICUBIC
        )
        ycbcr_ = img_.convert("YCbCr")
        y_, cb_, cr_ = ycbcr_.split()
        y_ = np.asarray(y_,dtype='float32')
        y_ = y_ / 255.0

        # 升維並將HWC轉換為CHW
        img_s = self.transforms(y)
        img_l = self.transforms(y_)

        # img_s 為縮小3倍後的圖片(1, 100, 100) 
        # img_l 是原始圖片(1, 300, 300)
        return img_s , img_l


    def __len__(self):
        """
        實現__len__方法,返回資料集總數目
        """
        return len(self.temp_images)

    def _sort_images(self, img_dir):
        """
        對資料夾內的影象進行按照檔名排序
        """
        files = []

        for item in os.listdir(img_dir):
            if item.split('.')[-1].lower() in ["jpg",'jpeg','png']:
                files.append(os.path.join(img_dir, item))
        return sorted(files)

    def _parse_dataset(self):
        """
        處理資料集
        """
        self.temp_images = self._sort_images(self.image_path)
        random.Random(self.seed).shuffle(self.temp_images)

    def _load_img(self, path):
        """
        從磁碟讀取圖片
        """
        with open(path, 'rb') as f:
            img = Image.open(io.BytesIO(f.read()))
            img = img.convert('RGB')
            return img

3.3.2 定義網路結構:

通過2.2節網路結構圖,可以很容易的看出來:圖片經過三層CNN取樣後得到R的平方個特徵通道,再通過Sub-Pixel層還原成channel個通道(這裡是1通道)影象。

from paddle.nn import Layer, Conv2D
class Sub_Pixel_CNN(Layer):

   def __init__(self, upscale_factor=3, channels=1):
       super(Sub_Pixel_CNN, self).__init__()
       self.conv1 = Conv2D(channels,64,5,stride=1, padding=2)

       self.conv2 = Conv2D(64,32,3,stride=1, padding=1)
       self.conv3 = Conv2D(32,channels * (upscale_factor ** 2),3,stride=1, padding=1)

   def forward(self, x):
       x = self.conv1(x)
       x = self.conv2(x)
       x = self.conv3(x)
       x = paddle.fluid.layers.pixel_shuffle(x,3)
       return x

模型封裝及模型視覺化

3.3.3 模型封裝

model = paddle.Model(Sub_Pixel_CNN())

3.3.4 模型視覺化

model.summary((1, 1, 100, 100))

3.3.5 模型訓練準備

損失函式選用:
這裡選擇了常用的的均方差損失函式:MSELoss,其表示式如下圖所示:

有興趣的小夥伴可以嘗試一下使用PSMR作為損失函式,可能效果會更好。

model.prepare(
  paddle.optimizer.Adam(
    learning_rate=0.001,
    parameters=model.parameters()
    ),
  paddle.nn.MSELoss()
  )

3.3.6 模型訓練:

# 啟動模型訓練,指定訓練資料集、訓練輪數、批次大小、日誌格式
model.fit(train_dataset,
          epochs=1,
          batch_size=16,
          verbose=1)

3.3.7 結果視覺化

從我們的預測資料集中抽1個張圖片來看看預測的效果,其中lowers是縮放的圖片,prediction是lowers經過卷積超解析度之後的結果。

psmr_low: 30.381882136539197 psmr_pre: 29.4920122281961

4 .思考與總結

這篇論文發表之前,CNN網路在超解析度重建上就取得了非常好的效果,但是網路結構複雜,不適合在移動端部署。這篇論文使用了一個結構十分簡單的網路結構,可以在視訊上實現實時超解析度,給輕量級的超解析度演算法提供了一個很好的思路。因為時間關係,本專案還沒有實現對視訊的實時處理。別急,下一個專案一定會有的!

最後,感謝飛槳和AI Studio深度學習開源平臺提供的支援。本專案全程使用AI Studio完成開發,簡直是窮學生黨的福音啊,V100是真的香!

下載安裝命令

## CPU版本安裝命令
pip install -f https://paddlepaddle.org.cn/pip/oschina/cpu paddlepaddle

## GPU版本安裝命令
pip install -f https://paddlepaddle.org.cn/pip/oschina/gpu paddlepaddle-gpu

>>訪問 PaddlePaddle 官網瞭解更多相關內容

郵箱:(歡迎騷擾,一起探討學習)
[email protected]
近期目標:拿到墨大AI方向研究生的offer(好像有點難度)
愛好倒騰,喜歡航模、航拍,夢想有朝一日實現財富自由,帶著我的小飛機自駕拍遍全國。疫情原因暫時還在國內,歡迎南京的小夥伴找我面基。

如在使用過程中有問題,可加入飛槳官方QQ群進行交流:1108045677。

如果您想詳細瞭解更多飛槳的相關內容,請參閱以下文件。

飛槳PaddlePaddle專案地址:

GitHub:
https://github.com/PaddlePaddle/PaddlePaddle
Gitee:
https://Gitee.com/PaddlePaddle/PaddlePaddle

飛槳官網地址:

https://www.paddlepaddle.org.cn/

本文分享 CSDN - Ralph Lu。
如有侵權,請聯絡 [email protected] 刪除。
本文參與“OSC源創計劃”,歡迎正在閱讀的你也加入,一起分享。