1.試水:可定製的數據預處理與如此簡單的數據增強(上)

開了專欄後的第一篇文章0.伏筆:圖像讀取方式以及效率對比沒想到反響如此強烈,我分析了一下,一方面是有各位大佬點贊支持,另一方面,大家對於MXNet以及其他大家平時都會用的包會非常感興趣,也願意去剖析它的用處與好處。我也調整了一下思路,之後的文章自己希望以一種初學探討方式和大家進行分享,希望大家多討論,多交流~

上篇文章講了關於圖像讀取的方法和對比,有很多同學也提醒我,很多深度學習框架都開始採用比較高效的讀取方法。的確如此,二進位讀取方式和多線程是標配,不論是熱門的pytorch、Tensorflow、Keras還是冷的不行的CNTK、chainer等,都在數據讀取方面做了相應的優化,今天給大家重點介紹一下,MXNet+Gluon在數據預處理和數據增強方面是如何進行的。

說實話,在我仔細研究了MXNet和Gluon是如何進行數據載入與數據增強的,不得不佩服DMLC真的很良心,提供了如此簡單的介面和又方便又多樣的數據處理工具庫。

在早期,我在學習MXNet的時候,覺得不論是文檔(早期文檔我就不吐槽了)還是官方教程都很奇怪,它的使用基礎介紹主要分為兩部分:一個NDArray的操作,一個是Symbol的介面。實際上從後來大多數Github上的例子中可以看出,大家使用的基本都是通過Symbol進行神經網路圖模型的構建。

但事實上,MXNet不僅僅是一個深度學習神經網路工具箱,它本身設計的初衷是一個科學計算庫,可以大批量通過顯卡進行數學計算,同時又加入了自動求導(話說這不就成了反向傳播BP了么?),使得整個工具庫變得全面,比如DMLC早期想單獨把這一部分剝離開,做成minpy。

好了閑話不說了,我們進入正題。

回憶起初高中學的大多數計算都屬於前向計算方法,最簡單如之類的y=a*b+1可以直接在MXNet實現,具體可以看看NDArray - Imperative tensor operations on CPU/GPU這一部分。

後來我在想,那NDArray中的其他工具是不是也不完全只有神經網路才能用,莫非也可以直接拿來做前向計算?我準備用卷積Convolution運算進行開刀。

了解的同學應該知道,Convolution運算實際上還有個別的名稱:掩膜運算。我是本科自動化,在學信號處理、數字圖像處理的時候,學過所謂的濾波演算法,比如中值濾波、高斯濾波等等,實際上是狹義上的卷積運算。那麼我今天嘗試用MXNet中的NDArray的各種工具,提取一個圖像邊緣輪廓信息。

圖像的知識,大家可以自己搜索,我直接用一個Prewitt運算元對圖像做濾波,實現邊緣信息提取。Prewitt運算元是這樣的一個結構:

$$

begin{matrix}

-1 & 0 & 1

-1 & 0 & 1

-1 & 0 & 1

end{matrix} tag{1}

$$

我們只需要做一次Convolution卷積運算,同時將他的卷積核心設置成上述的Prewitt運算元就好。

我們還是用二進位編碼的方式打開圖像並載入圖像:

from mxnet import imagenimg = image.imdecode(open(../data/train/cats/cat.1234.jpg,rb).read())nimshow(img.asnumpy())n

接下來,我們需要將圖像轉一下格式,因為普通的圖像是(width, height, channel)這樣的格式,而在MXNet通用的格式是(batch_size, channel, width, height),所以我們直接採用MXNet中的nd操作就好。

from mxnet import ndnimg = nd.transpose(img, (2,0,1))/255. # 調整三個維度的順序(c,w,h)nimg = nd.stack(img, axis=0) # 在前面加上一維度(1,c,w,h)nprint("image shape is:", img.shape)n

image shape is: (1, 272, 345, 3)

之後就是重頭戲,我們調用卷積函數Convolution,但是卷積函數需要幾個參量,一個是輸入數據(這個我們有了),權重weight,偏置bias,卷積核大小kernel:

weight = nd.array([[-1,0,1],[-1,0,1],[-1,0,1]]) #採用 Prewitt運算元nweight = weight.broadcast_to((1,3,3,3)) # 廣播成(1,3,3,3)大小的卷積核nbias = nd.zeros((1)) #設置偏置nkernel=(3,3)n

這樣我們就直接調用我們的大玩具了:

out = mx.nd.Convolution(data=img, weight=weight, bias=bias, kernel=kernel, num_filter=1)n

我們看看結果怎麼樣:

sam = out[0][0].asnumpy()nimshow(sam, cmap=gray)n

真的好好玩啊!這就可以了?要是我把整個過程移到顯卡上,是不是就可以批量加速了?!

我再試試其他運算元,這是考慮對角情況的sobel運算元

weight = nd.array([[[-1,-1,-1],[-1,8,-1],[-1,-1,-1]]]) #採用8方向的Sobel運算元n

(如果我換成二階運算元應該也是可以的吧?)

大家不妨把腦洞打開的再大些:如果我從訓練好的模型中,抽取出這些權重,是不是就可以自己寫一個inference了?那麼我就可以各種權重可視化了?中間層可視化?莫非我還可以根據權重大小來做卷積核的裁剪?如果我想在網路中輸入的訓練數據是邊緣輪廓數據,莫非也可以中mx.nd來做預處理?以前老師讓我們做的邊緣提取什麼分析的是不是也可以這麼直接做了?

(這些腦洞和想法,我會在後續的文章中繼續介紹與實踐)

反正MXNet的這些操作可以用顯卡進行加速!!~~

那麼在本篇文章的後半部分,我會詳細說說,我們怎麼在MXNet中定製我們自己的數據增強,並且也會順帶介紹幾種MXNet的數據載入方法,敬請期待~~~


推薦閱讀:

mxnet 加入apache 之後會有哪些影響,未來如發展?
DSSD:Deconvolutional Single Shot Detector 解析與實踐
MXnet初體驗之inception-resnet-v2從Model到Predict
MXNet的動態圖介面Gluon

TAG:mxnet | 深度学习DeepLearning | TensorFlow |