基於深度學習的影象超解析度重建

PaperWeekly發表於2018-09-27

筆者本次選擇復現的是湯曉鷗組 Chao Dong 的作品,這篇論文也是深度學習應用在超解析度重構上的開山之作

基於深度學習的影象超解析度重建

論文復現程式碼: 

http://aistudio.baidu.com/#/projectdetail/23978

超解析度重構

單影象超解析度重構(SR)可以從一張較小的影象生成一張高解析度的影象。顯然,這種恢復的結果是不唯一的。可以這樣直觀地理解:遠遠看到一個模糊的身影,看不清臉,既可以認為對面走來的是個男生,也可以認為這是個女生。那麼,當我想象對面人的長相時,會如何腦補呢?

這就依賴於我們的先驗知識假如我認為,一個穿著裙子的人肯定是個女生,而對面那個人穿著裙子,所以我認為那是個女生,腦補了一張女神臉。然而,如果我知道穿裙子的人不一定是女生,還可能是女裝大佬。迎面走來那個人瘦瘦高高,所以我認為十有八九是個男孩子,就會腦補一個……

也就是說,不同的先驗知識,會指向不同的結果。我們的任務,就是學習這些先驗知識目前效果最好的辦法都是基於樣本的(example-based)。

基於深度學習的影象超解析度重建

▲ 超解析度重構的結果。SRCNN所示為論文提出的模型的結果,可以看出,邊緣更加清晰。

論文提出一種有趣的視角:CNN 所構造的模型和稀疏編碼方法(sparse coding based)是等價的。稀疏編碼方法的流程如下: 

1. 從原始圖片中切割出一個個小塊,並進行預處理(歸一化)。這種切割是密集的,也就是塊與塊之間有重疊;

2. 使用低維詞典(low-resolution dictionary)編碼,得到一個稀疏引數

3. 使用高維詞典(high-resolution dictionary)結合稀疏引數進行重建(換了個密碼本);

4. 將多個小塊拼接起來,重合部分使用加權和拼接。

基於深度學習的影象超解析度重建

上圖是卷積神經網路對應於稀疏編碼的結構。對於一個低解析度影象 Y,第一個卷積層提取 feature maps。第二個卷積層將 feature maps 進行非線性變換,變換為高解析度影象的表示。最後一層恢復出高解析度影象。 

相比於稀疏編碼,論文提出的模型是 end-to-end 的,便於優化。並且,不需要求最小二乘的解,運算速度更快。

模型構造和訓練

模型的結構 

這是一個 base-line 模型。如下圖,f1=9,f2=1,f3=5,n1=64,n2=32,前兩層使用 relu 作為啟用函式。輸入為影象的 Y 通道。

基於深度學習的影象超解析度重建

為了減輕邊界帶來的影響,論文使用 valid 方式處理卷積的邊界。所以模型輸出的結果是比輸入要小一點點的。 顯然,這是一個 FCN 的網路。我們使用影象的一個個 patch 進行訓練,在測試時輸入為一整張圖片。由於沒有全連線層,輸入影象的大小可以是任意的。 

訓練資料 

為了使模型更好地收斂,我們在原始的訓練資料集上面切出一系列 33 X 33 大小的影象進行訓練,切割的步長為 14。也就是說,我們使用的訓練集影象,是有互相重合的部分的。

我們使用的是 timofte 資料集,共 91 張圖片。論文中進行對比試驗的時候,使用的都是 ImageNet 資料集。相比於 timofte,ImageNet 資料集可以提供更豐富的樣本,得到更好的訓練結果。但是 91 張圖片給出的樣本已經很豐富了,並且模型本身引數也不多,還不至於過擬合。所以使用 ImageNet 對結果的提升比較有限。

我們進行論文復現的時候,考慮到計算資源限制,使用 timofte 資料集,可以得到相似的結果。 我們使用 set5 作為驗證集,使用 set14 可以得到類似的結論。

    def read_data(self, data_path):
        def data_reader():
            for image in os.listdir(data_path):
                if image.endswith('.bmp'):
                    img = cv2.imread(os.path.join(data_path, image))
                    yuv = cv2.cvtColor(img, cv2.COLOR_BGR2YCrCb)
                    img_y, img_u, img_v = cv2.split(yuv)
                    # 下面是切圖的步驟
                    j = 0
                    count = 0
                    while j+33 < len(img_y):
                        i = 0
                        while i+33 < len(img_y[0]):
                            img_patch = img_y[j:j+33, i:i+33]
                            img_gth = img_patch[6:27, 6:27].copy()
                            img_blur = cv2.GaussianBlur(img_patch, (5, 5), 0)
                            img_sumsample = cv2.resize(img_blur, (11, 11))
                            img_input = cv2.resize(img_blur, (33, 33), interpolation=cv2.INTER_CUBIC)
                            yield img_input, img_gth
                            i+=14
                        j+= 14
        return data_reader

▲ 資料讀取程式碼展示

損失函式和模型評估

我們使用 MSE 作為損失函式,即:

基於深度學習的影象超解析度重建

其中,是模型中的所有引數。 如上文所述,我們使用 valid 方式處理邊界,所以輸出的影象比輸入影象略小。計算損失值時,只使用輸入影象中間和輸出影象對應位置的部分進行計算。 

由於超解析度重建的結果是不唯一的,所以其結果的評估往往比較困難。論文使用峰值訊雜比(PSNR)作為模型的評價指標。它和人眼的感受並不完全一致。可能會出現指標很高,但是人眼感受不太好的情況。但是,它仍然是廣為接受的指標。 PSNR 的計算公式如下:

基於深度學習的影象超解析度重建

其中,n 為每畫素的位元數,一般取 8。

模型訓練結果

基於深度學習的影象超解析度重建

當訓練的 backprops 數達到基於深度學習的影象超解析度重建時,模型 PSNR 值達到 32.39dB。而同樣的迭代次數,如果使用 ImageNet 資料集,可以達到 32.52dB。也就是說,使用更大的資料集,可以取得更好的結果。

使用更大的模型

論文從卷積核個數、卷積核大小、卷積層數三個方面增大模型的複雜度,在 ImageNet 上面對比可以看出,更加複雜的模型,可以取得更優的結果。

基於深度學習的影象超解析度重建

彩色影象上的實驗 

在前面的實驗中,論文使用影象的 Y 通道進行重建,其它通道使用雙三次插值(bicubic)得到。下面進行彩色影象上的探索,包括:baseline(只使用 Y 通道),bicubic,YCbCr 格式的三通道直接輸入,預訓練 Y 再三個通道一起訓練,預訓練 CbCr 再三個通道一起訓練,RGB 格式的三通道直接輸入。對比這些實驗,得到了一些非常有意思的結論。

基於深度學習的影象超解析度重建

最令人矚目的結論就是,直接把 YCbCr 格式的三通道影象輸入模型,結果竟然連 Bicubic 都不如。作者認為這是由於 Y 和 CbCr 的特徵差別較大,導致模型陷入區域性最小值。

另外,使用預訓練的結果繼續訓練,結果會比直接訓練 YCbCr 三個通道好些,但是還是不如只用 Y 的。最好的結果出現在使用 RGB 的。也比較好理解,因為 RGB 三個通道影象相關性比較高。 需要注意的一點是,加上 CbCr 的結果只比只用 Y 通道的結果好一點點,可見色相和飽和度兩個通道對超解析度重建的幫助不大。

論文總結

論文提出了一種 FCN 模型,並指出它和基於稀疏編碼的超解析度重構方法是等價的,並進行了一些改進,對比結果。 

但是筆者認為,有一些分析是比較牽強的。例如彩色影象的超解析度重構,其 PSNR 除了直接使用 YCbCr 訓練效果很差之外,其它相差都在 0.1 左右,甚至小於 0.1。這麼小的差距,在 set5 驗證集上面沒有太多的說服力(set5 只有 5 張圖片,而且這個結果是用 timofte 資料集訓練的,也是一個比較小的資料集)。

論文的主要意義其實還是在於開拓了一個新的方法,構造了一個新的超解析度重構的框架。

論文復現結果

Baseline模型復現結果 

考慮到算力限制,使用 timofte 資料集進行訓練。Scale Factor 為 3 。為了加快收斂速度,我們使用 AdamOptimizer,前兩層學習率基於深度學習的影象超解析度重建, 最後一層為基於深度學習的影象超解析度重建。相比於 SGD,AdamOptimizer 收斂到一個更好的結果。

這裡有一個 trick,就是最後一層的學習率和前兩層不同。這個設定是非常重要的,在實際測試中發現,使用這樣的設定,模型收斂更加穩定。而所有層使用相同的學習率時,很容易出現 model collapse。

基於深度學習的影象超解析度重建

圖中橫軸是反向傳播次數(batchsize * batchnum)。縱軸是 PSNR 值(dB)。可見,收斂速度比論文中快了很多,效果也更好。經過 150 個 epoch 的迭代,最終在 set5 測試集上 PSNR 達到了 35.25dB。 看一下恢復出來的圖片是什麼樣的。Y 通道使用 SRCNN 恢復,Cr,Cb 通道使用 bicubic 插值。

基於深度學習的影象超解析度重建

基於深度學習的影象超解析度重建

基於深度學習的影象超解析度重建

基於深度學習的影象超解析度重建

另一張圖片:

基於深度學習的影象超解析度重建

基於深度學習的影象超解析度重建

對比一下高頻細節,可見重構的效果還是不錯的:上圖為輸入,下圖為輸出。

基於深度學習的影象超解析度重建

基於深度學習的影象超解析度重建

構造更深的網路模型 

論文給出來的結果大同小異,結論是類似的。我們這裡復現 filter size 改變的結果。

基於深度學習的影象超解析度重建

PSNR 曲線為:

基於深度學習的影象超解析度重建

使用 9-3-1 的模型結構,150 個 epoch 之後的 PSNR 值為 35.82。我們做一個對比圖片,可以看出,雖然收斂速度、最終收斂結果不同(因為用的是不同的 Optimizor),但是得到的結論是一致的。

基於深度學習的影象超解析度重建

論文中的結果為:

基於深度學習的影象超解析度重建

三通道 RGB 訓練結果 

輸入影象為 RGB 三個通道。

基於深度學習的影象超解析度重建

模型訓練比較困難,很容易出現 model collapse 。使用單通道的引數作為預訓練引數,再此基礎上進行訓練。經過更長的迭代次數(200 個 epoch),PSNR 達到了 35.92。 

看一下 3 個通道訓練結果:

基於深度學習的影象超解析度重建

基於深度學習的影象超解析度重建

基於深度學習的影象超解析度重建

對比一下高頻細節,左圖是輸入,右圖是輸出:

基於深度學習的影象超解析度重建

總結

SRCNN 網路是 CNN 應用在超解析度重建領域的開山之作。雖然論文嘗試了更深的網路,但是相比於後來的神經網路,如 DRCN 中的網路,算是很小的模型了。受限於模型的表達能力,最終訓練的結果還有很大的提升空間。 

另外,雖然相比於 sparse coding 方法,SRCNN 可以算是 end to end 方法了。但是仍然需要將圖片進行 bicubic 差值到同樣大小。此後的 ESPCN 使用 sub-pixel convolutional layer,減少了卷積的運算量,大大提高了超解析度重建的速度。 

在復現的過程中,筆者發現 SGD 收斂速度相當慢,論文中曲線橫軸都是數量級。使用 Adam 優化器收斂速度更快,並且幾個模型的 PSNR 值更高。說明使用 SGD 訓練時候,很容易陷入區域性最優了。

關於PaddlePaddle

筆者目前只用到 PaddlePaddle 一些較為基礎的功能,看介紹說 program 是特色但是本人在復現過程中並沒有用到。

整體使用感受跟 TensorFlow 較為相似,資料讀取那個部分較之 TensorFlow 更為方便好用,超讚!另外,可能 PaddlePaddle 目前是在進行版本更替,本人看到很多函式有重複和不相容的,略感迷茫。

(小道訊息:版本更替大動作即將現身)

相關文章