Chainer筆記 -- SRCNN
首先來說一說為什么會來寫chainer, 盡管最近已經(jīng)不打算再繼續(xù)用chainer了, 但是對于剛接觸深度學(xué)習(xí)的人來說, 極簡單的安裝和極簡單的gpu加速使得chainer仍是一個簡單快速上手的深度學(xué)習(xí)庫

什么是SRCNN? ? ? ?論文地址:?https://ieeexplore.ieee.org/document/7115171
SRCNN全稱為Super Resolution?Convolutional Network, 這是第一個使用深度學(xué)習(xí)的超分辨率算法?(超分辨率算法: 從低分辨率圖像得到高分辨率圖像的算法). SRCNN具有極其簡單的結(jié)構(gòu), 甚至比許多分類器簡單很多, 十分適合用來做演示.
SRCNN是在YUV通道的V上進行圖像復(fù)原?(YUV圖像: 使用V(亮度), 和UV(CbCr色度))?, 這比起使用RGB的CNN可以減少很多權(quán)重以加快計算速度并且不會損失細節(jié)
SRCNN一共有3層, 分別為:?提取圖像特征,?非線性映射,?重構(gòu)圖像

ps: 卷積核尺寸為9,1,5的SRCNN也稱SRCNN(9-1-5), 更改卷積核尺寸可以得到SRCNN(9-3-5), SRCNN(9-5-5), 盡管卷積核尺寸越大會提升得到圖像的真實性, 但是這也會大大減慢計算速度, 所以這里使用915作栗子



如何訓(xùn)練SRCNN
SRCNN里的結(jié)構(gòu):? ?
提取圖像特征:?卷積核尺寸9,?輸入通道1, 輸出通道64,?步長1, padding?-, 有bias? ?[ReLU]
非線性映射:? ??卷積核尺寸1, 輸入通道64, 輸出通道32, 步長1, padding 0, 有bias? ? [ReLU]
重構(gòu)圖像:? ? ? ? 卷積核尺寸5, 輸入通道32, 輸出通道1, 步長1, padding -, 有bias
訓(xùn)練 train:? ? ? ? ??以下稱? ?提取圖像特征為conv1, 非線性映射為conv2,?重構(gòu)圖像為conv3
為了加快計算速度, 我們輸入使用33x33處理過的小圖片塊, 并且讓conv1和conv3的padding為0, 那么輸出圖像為21x21, 對應(yīng)的label為圖像塊中央?yún)^(qū)域,? 并且loss使用均方誤差函數(shù)
圖像處理:? 裁出需要的大小為33x33的圖像A, 經(jīng)過雙三次插值縮小后放大得到33x33的圖像B,?圖像B為訓(xùn)練輸入, 而A的從坐標(6,6)到(26,26)則為label
實際使用? ? test:
為了保證輸出輸入大小一致, 我們需要把conv1和conv3的padding設(shè)置為4和2
以下為我使用了450張不知道從哪里扒來的p站圖片作為訓(xùn)練集, 訓(xùn)練了150epoches的結(jié)果, 一般來說應(yīng)該訓(xùn)練幾千甚至幾萬epoches的, 但是我真的沒這個算力


以下是Chainer時間
如何使用Chainer? ? ? ??
Chainer內(nèi)置了大量深度學(xué)習(xí)使用的函數(shù)和連接層, 而且也擁有和其他深度學(xué)習(xí)庫一樣的傻瓜式一鍵反向傳播和一鍵更新權(quán)重? ? ? ? ? ?官方手冊:??https://docs.chainer.org/en/stable/reference/index.html
chainer的特點是可以設(shè)置連接層的輸入為None, 它會在第一次調(diào)用連接層時根據(jù)輸入調(diào)整內(nèi)部結(jié)構(gòu), 并且chainer使用的基本數(shù)據(jù)類Variable的運算是建立在傳入的數(shù)據(jù)類上的(使用Variable.data可以重新訪問傳入的數(shù)據(jù)), 這意味著可以完全使用cupy代替numpy達到GPU加速的效果? ?AMD No!
Chainer的安裝: 無腦pip, 請? ? ?**ps: chainer安裝時會順便帶上cuda, cupy和內(nèi)置的caffe, 但是在安裝時會阻止這些庫的錯誤, 這使得chainer是唯一一個可以在termux(安卓版linux命令行模擬器)安裝成功的深度學(xué)習(xí)庫, 手機端開發(fā)ok
基本使用:

注意1: 有研究指出深度學(xué)習(xí)對精度沒有太高的要求, 所以chainer為了提高計算速度默認是使用float32, 請注意傳入的數(shù)據(jù)需要手動從默認的float64改為float32? ?(當(dāng)然也可以把chainer默認數(shù)據(jù)改為float64, 但是何樂而不為呢)
注意2: chainer里的連接層的輸入, 第一個維度必須是batchsize, 比如說一個vgg16, 默認輸入是(3,224,224), 而在chainer里面則是 (n, 3,224,224), 這是為了一次計算可以計算多個輸入從而提升速度
實例1:? ?通過反向傳播更新輸入? x→[0.75, -1.5, 0]
首先隨機生成一個x, 然后指定target_x=[0.75, -1.5, 0],? ?target_x經(jīng)過一個連接層和sigmoid后得到label,
x經(jīng)過連接層和sigmoid后得到y(tǒng), y與label作均方誤差, 并使用反向傳播更新x, 使得x→target_x


可以看到隨著x的更新會越來越接近target_x

關(guān)于圖片操作
圖片處理的庫我使用的是opencv, 當(dāng)然用pillow也可以實現(xiàn), 所以我這里就不貼代碼了, 只說明我做了哪些圖片處理的函數(shù)
load_img(img_path)?????以RGB形式加載圖片, 返回一個范圍在[0,255], 形狀為(h,w,3)的numpy數(shù)組
save_img(img_path, img)??? 以RGB形式把img數(shù)組保存至img_path里
RGB_2_YUV(img)? ? ??把RGB數(shù)組轉(zhuǎn)換成YUV數(shù)組, 返回?(h,w,3)?的數(shù)組
YUV_2_RGB(img)? ? ??把YUV數(shù)組轉(zhuǎn)換成RGB數(shù)組,?返回?(h,w,3)?的數(shù)組
normaliz_img(img)? ? ?把數(shù)組從[0,255]歸一化為[0,1], 并返回
denormaliz_img(img)? ?把數(shù)組從[0,1]變?yōu)閇0,255], clamp掉<0和>255的數(shù)據(jù), 并返回

實現(xiàn)SRCNN
首先定義全局變量,? 注意訓(xùn)練集最好是風(fēng)格統(tǒng)一的, 否則可能導(dǎo)致學(xué)習(xí)效果不太好??waifu2x在風(fēng)景圖效果不好也是同理

然后定義SRCNN的結(jié)構(gòu)

訓(xùn)練部分:? ?
def train(model, imgs_path, epoches, lr, batchsize=10, scale=3, test_img=None, test_n_train=100)
首先在訓(xùn)練部分里定義兩個必要的函數(shù)

然后訓(xùn)練函數(shù)的主體:

最后使用兩行函數(shù)開始訓(xùn)練模型


源碼下載?盤.白度.com/s/1ENKRnx7nylkAV3zFSKh5ZQ,? ?提取碼8bry
(內(nèi)置彩蛋)
chainer里雖然自帶數(shù)據(jù)集格式, 也知道迭代器和訓(xùn)練器, 但是深度學(xué)習(xí)的樂趣不就是自己魔改訓(xùn)練器嗎