靳 濤,張永愛
(福州大學 物理與信息工程學院,福建 福州 350116)
深度學習是機器學習中的一個分支,其通過多個隱藏層對輸入數(shù)據(jù)的處理進行特征抽象,進而理解輸入的數(shù)據(jù)[1]。近年來,深度學習非?;馃?,在圖像處理、語音處理、文本理解等眾多領域的應用越來越多,技術也越來越成熟[2-3]。2016年,谷歌AlphaGo戰(zhàn)勝了李世石引起了社會廣泛關注;科大訊飛的智能語音、百度識圖、谷歌的機器翻譯等技術都應用到了現(xiàn)實生活中,給人們的生活帶來了極大的方便。
目前主流的開源深度學習框架主要有谷歌的TensorFlow、微軟的CNTK、FaceBook的Torch、賈揚清主導開發(fā)的Caffe和蒙特利爾大學Lisa Lab團隊開發(fā)的Theano[4-5]。TensorFlow框架自2015年被谷歌開源后,就受到了極大的關注,用戶數(shù)量大幅上升[6]。TensorFlow是相對高階的機器學習庫,其核心代碼用C++編寫,上層接口除了C++語言外,還可以用Python或者Java編寫。用戶不必親自編寫底層核心的C++代碼就可容易地搭建神經網(wǎng)絡結構,極大降低了深度學習的門檻。同時,TensorFlow的另外一個優(yōu)點是它靈活的移植性,模型的訓練和最終的部署可以運行在有CPU或GPU的PC、服務器或者移動設備上。隨著計算機技術的飛速發(fā)展以及計算能力的大幅提升,普通的計算機也能在TensorFlow平臺上構建深度學習模型,降低了學習深度學習的成本,更易驗證自己的算法。
卷積神經網(wǎng)絡是含有多個處理層的神經網(wǎng)絡[7-8]。典型的卷積神經網(wǎng)絡主要由輸入層、卷積層、下采樣層、全連接層和輸出層組成[9]。其主要包括前向傳播和反向傳播兩個過程,前向傳播通過網(wǎng)絡結構預測結果,反向傳播根據(jù)預測結果與理想結果的差值進行參數(shù)調整。輸入層一般為需要處理的圖像。卷積層即采用規(guī)模小的矩陣與上一層的圖像進行卷積,矩陣相當于特征過濾器,通過移動小矩陣去處理圖像的每一塊,將圖像中的特征提取出來,其原理如式(1)所示:
(1)
下采樣層也叫池化層,可看做特殊的卷積過程,一般有兩種形式:最大值采樣和平均值采樣。下采樣層對特征圖進行降維,原理如式(2)所示:
(2)
卷積神經網(wǎng)絡反向傳播常用的優(yōu)化方法是梯度下降法。殘差通過梯度下降進行反向傳播,逐層更新卷積神經網(wǎng)絡的各個層的參數(shù)值。
(3)
(4)
圖1是卷積神經網(wǎng)絡結構示意圖。主要包括輸入層、兩層卷積層、兩層下采樣層、全連接層和輸出層。其中,卷積層是通過一個或多個可訓練的卷積核對上一層的圖片進行卷積,加上偏置的值,然后應用激活函數(shù),得到卷積層的特征圖;下采樣層是對上一層特征圖中每個22的鄰域求最大值得到下采樣層的一個值,因此下采樣層的特征圖在各個維度都為上一層特征圖的一半;全連接層是將最后一層下采樣層的64張?zhí)卣鲌D展開成一個向量。在全連接層和輸出層之間加入了Dropout層,可以防止模型過擬合,降低神經元之間的依賴,提高模型的泛化能力。最后通過softmax回歸模型進行分類輸出。
圖1 卷積神經網(wǎng)絡結構示意圖
TensorFlow,也就是張量(Tensor)和流(Flow),意味著張量和流是TensorFlow的基礎[10]。TensorFlow中所有數(shù)據(jù)用張量數(shù)據(jù)結構來表示,流意味著數(shù)據(jù)的流動和計算。TensorFlow的結構由會話(session)、圖(graph)、節(jié)點(operation)和邊(tensor)組成。TensorFlow程序開發(fā)流程如圖2所示,分為構建圖和執(zhí)行圖兩個階段。在構建圖階段,節(jié)點的執(zhí)行步驟被描述成一個圖,用來表示計算任務。在執(zhí)行階段,第一步是創(chuàng)建一個會話對象,然后圖在會話的上下文中執(zhí)行,更新變量的狀態(tài),最后用feed或fetch賦值或者獲取數(shù)據(jù)。
圖2 TensorFlow程序開發(fā)流程圖
TensorBoard是TensorFlow自帶的一款可視化工具,可顯示標量、輸入圖像、模型結構、訓練過程中各層參數(shù)的變化情況,更加方便代碼的理解、調試。TensorBoard 通過讀取 TensorFlow 的事件文件來運行。TensorFlow 的事件文件包括TensorFlow 運行中涉及的主要數(shù)據(jù),例如可以向節(jié)點添加scalar_summary操作來輸出學習速度和期望誤差,可以附加 histogram_summary 運算來收集權重變量和梯度輸出。
MNIST是一個手寫數(shù)字數(shù)據(jù)庫,它有60 000個訓練樣本集和10 000個測試樣本集。MNIST數(shù)據(jù)庫含有4個文件:訓練集圖像、訓練集標簽、測試集圖像和測試集標簽。每個樣本圖像都是2828像素大小,每個像素值的范圍是0~255。標簽值為0~9十個不同的數(shù)字。圖3所示為用TensorBoard工具顯示MNIST數(shù)據(jù)庫中的手寫數(shù)字。
圖3 MNIST手寫數(shù)字
圖4是通過TensorBoard可視化工具顯示的整個模型結構,包含了兩個卷積層conv1和conv2、兩個池化層pool1和pool2、一個全連接層fc1、一個輸出層fc2。在兩個輸出層之間添加了Dropout,防止數(shù)據(jù)過擬合。accuracy表示模型訓練或測試時預測結果與標簽吻合的準確度,loss表示模型預測結果與圖像標簽的差值。
圖4 模型結構示意圖
初始化:模型識別率高低的一個重要因素是參數(shù)值的確定,訓練的過程就是找到最優(yōu)的參數(shù)值。卷積神經網(wǎng)絡需要確定權重和偏置值。初始化時需要設置參數(shù)為非0值,以避免輸出恒為零值的情況。代碼中用標準差為0.1的正態(tài)分布生成隨機值賦給權重,用0.1常數(shù)初始化偏置,shape變量為維度值,在調用的時候再定義。
def weight_variable(shape):
initial=tf.truncated_normal(shape, stddev=0.1)
return tf.Variable(initial)
def bias_variable(shape):
initial = tf.constant(0.1, shape=shape)
return tf.Variable(initial)
reshape將調整輸入圖像的行數(shù)、列數(shù)及維度。MNIST數(shù)據(jù)集的一張圖片有28×28共784個像素,按行順序存儲,需要將連續(xù)讀取的784個數(shù)值調整為28行乘以28列的圖片。x為輸入的數(shù)據(jù)集,將它變?yōu)閇-1,28,28,1]四維向量,第一維的-1表示圖片的數(shù)量;第二、三維的28代表圖片的寬和高;第四維表示圖片顏色的通道,由于MNIST數(shù)據(jù)集是灰度圖,因此這里是1。
x_image = tf.reshape(x, [-1,28,28,1])
conv1是模型第一層,即卷積層。將輸入圖片(x_image)和權重(W_conv1)進行卷積,加上偏置(b_conv1)的值,最后應用ReLU激活函數(shù)。權重的張量是[5,5,1,32],前兩個維度表示卷積核的大?。坏谌S是輸入的通道數(shù)目,這里輸入的是原始圖片,通道數(shù)為1;最后一維是輸出的通道數(shù)目,這里是32,即卷積后生成32張?zhí)卣鲌D。對應的偏置數(shù)為32。
W_conv1 = weight_variable([5, 5, 1, 32])
b_conv1 = bias_variable([32])
h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1)
TensorFlow進行卷積計算時對邊界的處理有兩種模式:SAME和VALID。SAME采用0邊距來保證輸出和輸入的圖片是同樣的大小,VALID沒有0邊距,輸出的圖片比輸入的小。strides表示卷積核移動的步長,四個維度上的步長都為1。輸入的圖片經過第一層的卷積后,輸出32張28×28的特征圖。
def conv2d(x, W):
return tf.nn.conv2d(x, W, strides=[1, 1, 1, 1], padding=′SAME′)
pool1是池化層。池化一般有最大值池化和平均值池化,最大值池化是取池化窗口中的最大值,平均值池化是取池化窗口中所有數(shù)的平均值。這里采用最大值池化。x為第一層卷積層輸出的32張?zhí)卣鲌D,ksize表示池化窗口的大小為2×2,strides與卷積層一樣,表示步長,這里對特征圖的水平和垂直方向的移動步長設置為2。經過池化層的處理,輸出32張14×14的特征圖。
def max_pool_2x2(x):
return tf.nn.max_pool(x, ksize=[1, 2, 2, 1],strides=[1, 2, 2, 1], padding=′SAME′)
conv2是第二層卷積層,在池化層的后面。與第一層卷積層類似,卷積核的大小還是5×5,輸入的通道變成了32,輸出通道為64,相應的偏置數(shù)變成了64。經過這層的卷積處理,輸出64張14×14大小的特征圖。
W_conv2 = weight_variable([5, 5, 32, 64])
b_conv2 = bias_variable([64])
h_conv2 = tf.nn.relu(conv2d(h_pool1, W_conv2) + b_conv2)
pool2為池化層,對特征圖進行采樣,降低數(shù)據(jù)量。池化窗口大小為2×2,步長為2。池化處理后,輸出64張7×7大小的特征圖。
fc1是全連接層。經過前面四層的處理,圖片尺寸已經縮小為7×7,接著加入一層全連接層,用于處理整張圖片。全連接層將pool2層輸出的64張?zhí)卣鲌D調整為含有1 024個神經元的行向量,然后與權重矩陣相乘,加上偏置,最后對其使用ReLU激活函數(shù)。
W_fc1 = weight_variable([7 * 7 * 64, 1024])
b_fc1 = bias_variable([1024])
h_pool2_flat = tf.reshape(h_pool2, [-1, 7*7*64])
h_fc1 = tf.nn.relu(tf.matmul(h_pool2_flat, W_fc1) + b_fc1)
為了減少過擬合,在輸出層之前加入Dropout。Dropout就是在訓練過程中以一定的概率讓部分神經元輸出為0,但是其當前的權重值保持不變,下次訓練的過程中,又恢復它的權重。keep_prob用來定義訓練過程中神經元的輸出為0的概率。
sep_prob = tf.placeholder("float")
h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)
fc2為輸出層,采用softmax回歸模型對圖片進行分類,它可以解決多分類的問題,在識別10個不同的單個數(shù)字方面具有很大用處。
W_fc2 = weight_variable([1024, 10])
b_fc2 = bias_variable([10])
y_conv=tf.nn.softmax(tf.matmul(h_fc1_drop, W_fc2) + b_fc2)
loss是模型的輸出值與圖片對應標簽的差值。accuracy是模型預測輸出的準確度。adam_optimizer是Adam優(yōu)化算法,其為一個尋找全局最優(yōu)點的優(yōu)化算法,引入了二次方梯度校正。
MNIST有60 000訓練集和10 000測試集,隨機從訓練集中抽取一組圖片進行訓練,當訓練到10 000次后,用測試集對模型進行檢測。圖5展示了卷積神經網(wǎng)絡結構的訓練次數(shù)與訓練識別率之間的關系。圖5是TensorFlow自帶的可視化工具TensorBoard導出的,其中,橫坐標表示訓練的次數(shù),一共訓練了10 000次,每訓練100次測試一次識別率??v坐標顯示的是識別率的大小。從圖中可以看出,隨著訓練次數(shù)的增加,訓練識別率逐漸升高,最后趨于穩(wěn)定。當訓練到300次以后,識別率就上升到了90%;當訓練到6 000次后,識別率就接近100%了。圖6展示了卷積神經網(wǎng)絡結構的訓練次數(shù)與損失值之間的關系,與識別率正好相反。當訓練的次數(shù)達到6 000次后,誤差就接近于零了。圖7是最終用測試集測試的結果示意圖,測試識別率高達99%。
圖5 訓練次數(shù)與識別率的關系圖
圖6 訓練次數(shù)與損失值的關系圖
圖7 測試結果
圖8是從識別錯誤的測試集中挑選出來的圖片。其中圖8(a)對應標簽為4,模型的識別結果為6,圖8(b)對應標簽為2,模型的識別結果為8。圖8(a)由于書寫的不規(guī)范而具有了數(shù)字6的特征,圖8(b)具有數(shù)字8的特征,這種因書寫不規(guī)范而具有其他數(shù)字特征的圖片的識別錯誤率較高。除了書寫不規(guī)范外,模型的過擬合是識別率低的重要原因。模型過擬合后,訓練時識別率較高,但測試時識別率較低。增加訓練的數(shù)據(jù)集,模型中加入Dropout層可以有效降低模型的過擬合程度。
圖8 識別錯誤的圖片
本文通過谷歌開源的軟件庫TensorFlow快速地搭建了一個深度卷積神經網(wǎng)絡,采用MNIST數(shù)據(jù)集對模型進行訓練及測試,用TensorBoard可視化工具顯示測試結果及模型各層的參數(shù)值,驗證了TensorFlow工具的簡單易用性。同時在經典卷積神經網(wǎng)絡的基礎上,增加了卷積核的數(shù)量,在第二次卷積處理后,特征圖從12張增加到64張,便于提取更加豐富的特征。最終測試達到了99%的識別率。
參考文獻
[1] 尹寶才, 王文通, 王立春. 深度學習研究綜述[J]. 北京工業(yè)大學學報, 2015, 41(1): 48-59.
[2] 余凱, 賈磊, 陳雨強, 等. 深度學習的昨天、今天和明天[J]. 計算機研究與發(fā)展, 2013, 50(9): 1799-1804.
[3] AFFONSO C, ROSSI A L D, VIEIRA F H A, et al. Deep learning for biological image classification[J]. Expert Systems with Applications, 2017, 85: 114-122.
[4] ERICKSON B J, KORFIATIS P, AKKUS Z, et al. Toolkits and libraries for deep learning[J]. Journal of Digital Imaging, 2017, 30(4): 400-405.
[5] 王茜,張海仙. 深度學習框架Caffe在圖像分類中的應用[J]. 現(xiàn)代計算機,2016(5):72-75,80.
[6] WONGSUPHASAWAT K, SMILKOV D, WEXLER J, et al. Visualizing dataflow graphs of deep learning models in TensorFlow[J]. IEEE Transactions on Visualization and Computer Graphics, 2017(99): 1-7.
[7] KRIZHEVSKY A,SUTSKEVER I,HINTON G. Image net classifi-cation with deep convolutional neural networks[C]. Advances in Neural Information Processing Systems(NIPS 2012), 2012: 1106-1114.
[8] 李彥冬, 郝宗波, 雷航. 卷積神經網(wǎng)絡研究綜述[J]. 計算機應用, 2016, 36(9): 2508-2515.
[9] LECUN Y, BOTTOU L, BENGIO Y, et al. Gradient-based learning applied to document recognition[J]. Proceedings of the IEEE, 1998, 86(11): 2278-2324.
[10] 李河偉. 一種移動式TensorFlow平臺的卷積神經網(wǎng)絡設計方法[J]. 電腦知識與技術, 2017, 13(22): 179-182.