筆者本次選擇復現的是湯曉鷗組 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 目前是在進行版本更替,本人看到很多函式有重複和不相容的,略感迷茫。
(小道訊息:版本更替大動作即將現身)