朱虎明,羅 政,緱水平,田小林,焦李成,張小華
(西安電子科技大學 電子工程學院,陜西 西安 710071)
劉喜平, 萬常選, 舒 蔚, 駱斯文
(江西財經大學 信息管理學院, 江西 南昌 330013)
Android平臺上基于卷積神經網絡的手寫數字識別實驗
朱虎明,羅 政,緱水平,田小林,焦李成,張小華
(西安電子科技大學 電子工程學院,陜西 西安 710071)
卷積神經網絡算法由于良好的性能已經廣泛使用在自動駕駛、語音識別和圖像分類等領域,為增強學生學習和利用卷積神經網絡算法的能力,文章設計在Android平臺上基于TensorFlow卷積神經網絡的手寫數字識別實驗,并說明實施過程,同時介紹卷積神經網絡算法、Android平臺相關技術原理和實驗過程。
卷積神經網絡; 手寫數字識別;Android; TensorFlow
2006年加拿大多倫多大學的Hinton教授提出了基于“逐層訓練”和“精調”的兩階段策略,解決深度神經網絡中參數訓練的難題,此后紐約大學的LeCun、蒙特利爾大學的Bengio和斯坦福大學的Andrew Ng等人對深度神經網絡展開研究,并提出深度自編碼器(Deep Auto Encoder)、深度置信網(Deep Belief Networks)、卷積神經網絡(Convolutional Neural Networks)等深度模型[1]。深度神經網絡獲得學術界和工業界的廣泛關注,在圍棋和德州撲克等領域獲得突破性進展,而且深度學習的相關課程也逐漸進入高校。在國內,吳立德教授在復旦大學開設了深度學習課程;在國外,一些知名高校也開設了深度學習課程,如斯坦福大學、牛津大學、紐約大學等。目前,深度學習在本科教學中目前涉及的內容還比較少,為幫助學生更好的理解和學習算法,筆者設計在Android平臺上進行深度學習實驗,實驗以卷積神經網絡為例,利用TensorFlow深度學習框架并將其應用于手寫體識別。
卷積神經網絡是近年發展起來并引起廣泛重視的一種高效識別方法。20世紀60年代,Hubel和Wiesel在研究貓腦皮層中的神經元時發現其獨特的網絡結構可以有效地降低反饋神經網絡的復雜性,繼而提出卷積神經網絡。現在,卷積神經網絡已經成為眾多科學領域的研究熱點之一,特別是在模式分類領域,由于卷積神經網絡算法避免了對圖像手工提取特征等步驟,因而得到更為廣泛的應用。
隨著智能終端在全球范圍內的普及,目前主流的智能手機操作系統有谷歌公司的Android系統、蘋果公司的iOS系統和微軟公司的Windows Phone系統,由于Android系統的開源特性,使得華為、三星、小米等廠商的手機都采用了Android操作系統。2017年5月,NetMarketShare數據網站公布了手機操作系統市場份額,其中Android系統的占有率是65.19%,排名居首。鑒于Android系統越來越廣的使用領域,目前高校開設了很多基于Android系統的實驗類課程[23]。
2015年11月9日,Google發布并開源第二代人工智能學習系統TensorFlow[4],其命名源于本身的運行原理。Tensor(張量)意味著N維數組,Flow(流)意味著基于數據流圖的計算,TensorFlow為張量從流圖的一端流動到另一端的計算,TensorFlow是將復雜的數據輸入至人工智能神經網中進行分析和處理過程的系統,它可在小到一部智能手機、大到數千臺數據中心服務器的各種設備上運行。
卷積神經網絡是一種前饋神經網絡[5],其基本結構一般包括兩層:其一為特征提取層,每個神經元的輸入與前一層的局部感受相連,并提取該局部的特征[5],一旦該局部特征被提取后,它與其他特征間的位置關系也隨之確定下來;其二是特征映射層,網絡的每個計算層由多個特征映射組成,每個特征映射是一個平面,平面上所有神經元的權值相等。
卷積神經網絡主要用來識別位移、縮放及扭曲不變性的二維圖像[68]。由于卷積神經網絡的卷積層通過訓練數據進行學習,所以在使用時,避免了顯式的特征提取,而隱式地從訓練數據中進行學習;再者由于同一特征映射面上的神經元權值相同,所以網絡可以并行學習。
本次實驗的卷積神經網絡是由兩個卷積層(conv)、兩個池化層(pool)和兩個全連接層(fc)以及一個softmax組成。第一層卷積層有32個5*5的卷積核,網絡采用了Relu(Recti fi ed Linear Unit 修正線性函數)作為激活函數。第二層是最大池化層,求取特征圖后,用大小為2*2池化窗口對特征圖進行池化操作。第三層中,有64個5*5的卷積核,同樣采用Relu作為激活函數。第四層也是池化窗口為2*2的最大池化層。第五層是全連接層,有1024個神經元。為了減少過擬合,在輸出層之前加入dropout算子。只在訓練過程中啟用dropout。第六層也是全連接層,有10個神經元。最后添加一個softmax層,將網絡輸出值轉換成概率值,網絡結構如圖1所示。
實驗過程分為兩個部分,訓練過程和推理過程。在訓練過程中,首先要建立卷積神經網絡的網絡結構,同時設置訓練過程的一些超參數,如學習率、動力因子、最大迭代次數等,接著使用訓練集對網絡參數進行訓練,但在部分情況下,會把訓練集劃分出一部分作為驗證集用來交叉驗證。推理過程是用測試集對模型進行驗證。實驗流程如圖2所示。

圖1 卷積神經網絡網絡結構

圖2 實驗流程
卷積神經網絡訓練過程在計算機上完成,分為3個步驟:①建立卷積神經網絡網絡結構;②利用帶有GPU的計算機訓練模型;③保存模型。
(1)建立卷積神經網絡網絡結構。
TensorFlow深度學習框架提供了python語言的API接口,因此利用python編程語言編寫訓練代碼,建立卷積神經網絡的網絡結構,本次實驗參考TensorFlow官方給出的Deep MNIST for Experts模型訓練卷積神經網絡。
(2)利用帶有GPU的計算機訓練模型。
在建立好網絡結構之后,下一步是訓練模型,訓練模型的時間一般比推理時間長很多,且模型的超參數會影響正確率,所以一般需要多次訓練,一般采用安裝有GPU的計算機進行訓練,由于GPU強大的計算能力,可以大大縮短深度神經網絡的訓練時間。
本次實驗采用的是MNIST數據集,手寫數字MNIST數據庫包含一個訓練樣本集和一個測試樣本集,訓練樣本集包含60,000個樣例,測試樣本集包含10,000個樣例。圖片被歸一化成一張放在中間部位的28*28像素的灰度圖。該數據集包含0~9共10類阿拉伯數字。數據集共包含4個文件,它們分別是訓練樣本數據集、訓練數據樣本標簽集、測試用例數據集和測試用例數據標簽集。MNIST的部分樣例如圖3所示。

圖3 MNIST數據集樣例
本實驗中,訓練優化方法分別采用Adagrad、GradienDescent和Adam,其中GradienDescent優化方法測試了多組參數,對比識別的準確率(見表1)發現,GradientDescent(學習率為0.001)的正確率最高,因此網絡采用GradientDescent(學習率為0.001)的優化算法。
(3)保存模型。
在模型訓練結束后,使用TensorFlow的API函數tf.g fi le.FastGFile()將模型保存為.pb文件,該函數既能保存模型的結構,又能夠保存模型中參數的值。

表1 優化算法對比表
推理過程分為兩個步驟:①搭建Android平臺上的卷積神經網絡系統;②系統性能測試。
(1)搭建Android平臺上的卷積神經網絡。
本次實驗所用到的集成開發軟件為Android工具Android studio IDE,設計開發的Android應用程序分為兩個部分,第一部分是UI界面的設計,第二部分是將采集的測試樣本進行推理。
UI界面設計主要是和用戶進行交互,實驗中使用了兩個Button和一個Bitmap控件。系統界面布局如圖4所示,本次實驗中Android應用通過Bitmap和Canvas操作使得界面自適應屏幕大小。通過Android觸控屏記錄手寫過程的軌跡,并將手寫軌跡存儲為圖像數據即可生成了手寫體數據。執行圖像預處理,即后臺處理生成bitmap,作為模型的輸入。一個Button用作清屏,另一個Button用作觸發推理事件,即調用訓練好的模型進行推理,并且將返回推理結果更新到界面上。

圖4 系統界面布局
接下來是將TensorFlow移植到Android平臺上,首先編譯在Android平臺上調用TensorFlow模型需要的jar包和so文件;接著將訓練好的模型pb文件放入項目中app/src/main/assets位置,添加jar包和so文件;接下來是創建接口和實現調用,分為四步:導入jar包、導入so文件、Tensor fl ow 接口初始化和模型的調用。


然后接下來的主要工作就是安卓項目的編譯以及將編譯完的apk文件安裝到手機,這部分內容與一般的安卓項目沒有區別。
(2)系統性能測試。
基于卷積神經網絡的手寫數字識別APP設計完成且安裝到Android設備后,在運行時,利用Android的觸屏功能記錄軌跡,手寫完成后,單擊測試按鈕,調用模型,進行識別,并輸出結果到用戶界面。在測試完成后,單擊清除按鈕,會將繪圖區域內生成的手寫數字以及識別結果清除。
本次實驗結果如圖5、圖6所示,由圖5可知,在Android上實現的手寫數字識別算法取得了較好的識別效果。圖6則是無法正確識別的實例,比如當字符比較小的時候或者字符出現在Bitmap的邊緣的時候,識別效果不太理想。
筆者下一步將著重從圖像預處理方面改善因字符太小和書寫位置偏離中心位置等原因造成手寫數字識別度不高的問題。

圖5 手寫數字識別圖—識別正確

圖6 手寫數字識別圖—識別錯誤
[1] Hinton G E, Salakhutdinov R R. Reducing the dimensionality of data with neural networks[J]. Science, 2006(5786): 504-507
[2] 劉春.以Android應用為案例的軟件工程教學[J]. 計算機教育,2015(11):75-77.
[3] 劉成明,李瑋瑋. Android手機開發課程的案例教學法[J]. 計算機教育, 2015(14): 37-40.
[4] Abadi M, Agarwal A, Barham P, et al. TensorFlow: Large-Scale machine learning on heterogeneous distributed systems[EB/OL].(2016-03-14)[2017-04-05]. http://download. tensor fl ow.ong/paper/white paper 2015.pdf.
[5] 吳岸城. 神經網絡與深度學習[M]. 北京: 電子工業出版社. 2016.
[6] 周飛燕, 金林鵬, 董軍. 卷積神經網絡研究綜述[J]. 計算機學報, 2017(7): 1-23.
[7] 余濱, 李紹滋, 徐素霞, 等. 深度學習: 開啟大數據時代的鑰匙[J]. 工程研究——跨學科視野中的工程, 2014(3): 234-235.
[8] 焦李成, 楊淑媛, 劉芳, 等. 神經網絡七十年: 回顧與展望[J]. 計算機學報, 2016(8): 1697-1716.
1672-5913(2017)11-0159-04
G642
西安電子科技大學新實驗開發與新實驗設備研制及實驗教學改革(SY1408)。
朱虎明,男,副教授,研究方向為高性能計算及其應用,zhuhum@mail.xidian.edu.cn。
(編輯:史志偉)
教材建設
劉喜平, 萬常選, 舒 蔚, 駱斯文
(江西財經大學 信息管理學院, 江西 南昌 330013)
文章編號:1672-5913(2017)11-0163-04
中圖分類號:G642
摘 要:介紹編程能力培養的3個層次:器—術—道,分析這3個層次對能力的要求,然后探討《C程序設計:方法與實踐》教材在夯實編程之器、提煉編程之術、引導編程之道3個方面中的做法。
關鍵詞:程序設計; 教材; C語言; 器—術—道
基金項目:江西省2013年度普通本科高校卓越工程師教育培養計劃項目(贛教高字[2013]78 號);江西省高等學校省級教改立項重點項目(JXJG-16-4-6);江西財經大學“3+7+x”專業主干課程建設項目(教務通知字[2017]33號)。
作者簡介:劉喜平,男,副教授,研究方向為數據庫和數據挖掘,lewislxp@gmail.com;
萬常選(通信作者),男,教授,研究方向為信息檢索和數據挖掘,wanchangxuan@263.net。
程序設計的境界有3種:器—術—道。在程序設計能力培養方面,一般由“器”入門,通過熟悉“術”,最終達到“道”的境界。在編寫程序設計教材的時候,要注意這3個層次的內容安排,并注意它們之間的過渡。
《易經》曰“形而下者謂之器”,說得通俗一些,“器”就是具體工具。在編程中,“器”首先指編程語言,如Java、C/C++。“器”的另一層意思是具體特性。要學好一門語言,首先要掌握語言的基本特性,如選擇、循環、函數等;其次要掌握好這門語言的獨特特性,如指針操作之于C。“器”的第三層意思是具體的開發和調試工具。學任何語言的時候,初學者都要熟練掌握一種開發和調試工具,如C/C++編程,在Linux下要學會使用GDB調試,在Windows下,要會使用Visual Studio或者其他工具開發。
“術”是中國古人對技藝、技巧、技能的一個稱謂,比如武術。“術”強調的是應用,是對“器”非常熟練基礎上的靈活運用。
在編程中,“術”對應套路、思路和算法。比如,在C文件編程中,要把一個二進制文件中的某些記錄刪除,直觀的做法是:逐個記錄掃描,如果記錄需要刪除,則將后面的記錄往前挪動。兩種常見的套路是:①創建一個新的文件,將需要保留的數據復制到新文件中,需要刪除的記錄則跳過,最后將舊文件刪除,將新文件重命名為舊文件,這種刪除套路稱為硬刪除;②軟刪除,不真正地刪除記錄,而是標上記號。這兩種套路各有優缺點,需要靈活選用。再比如,在一個應用中如果需要將商品按照銷量排序,那么需要用到某種排序算法;如果經常需要排序的話,需要考慮用某種數據結構,如B樹、堆等。
《易經》說“形而上者謂之道”,也就是說,“道”是對事物蘊含思想、哲理的反思。掌握了編程之“道”的人,看透了編程工具和語言背后的差別,不再執著于某種工具和語言,通常談論的是架構、設計模式、框架、抽象、分解等概念。如果要用一個簡單的詞語概括編程中的“道”,那就是常說的“計算思維”[1]。
舉兩個簡單的例子說明“道”和“術”在編程上的區別。對于二分查找算法,得“術”者看到的是這個算法的運用前提(數據存儲在線性表中且有序)、算法的基本思路等,而得“道”者看到的是這個算法背后的分治思想;當應用某一種框架的時候,得“術”者看到的是這個框架的組成、交互方式等,得“道”者看到的是這個框架背后的思維,如模型、視圖和控制相分離的原則。
面向初學者的程序設計課程的目標,是讓學生掌握“器”,熟悉“術”,并引導他們感悟“道”。
C程序設計是一門非常基礎的課程,在“器”這個層面上,必須要掌握兩部分:一是C語言的知識點;二是C語言的開發和調試工具。
大部分教材介紹C語言知識點的時候,把這些知識點分割成若干個條塊。一種常見的知識點劃分見圖1,其中虛線框部分可以并列,其先后順序比較隨意。

圖1 C語言知識點條塊結構圖
這種條塊式結構的優點是:結構清晰,方便教學。學校的教學實踐,初期也采取這種教學模式,但是在實踐中發現,這種條塊式結構存在以下不足:
(1)知識點之間的滲透不夠。
(2)教學初期的例子比較簡單、單調。
(3)學生的綜合訓練比較少。
考慮到這些問題,筆者采取一種新的層級式結構:先介紹C語言的內核,再系統地介紹C語言知識點,這個內核包含的內容如下。
· C程序的構成;
· 最常見的數據類型:int、 fl oat和 double、char 4種基本數據類型;
· 輸入輸出:printf和scanf函數(只介紹常用的格式控制符);
· 常量和變量的概念;
· 運算符與表達式:算術運算符、關系運算符、邏輯運算符、賦值運算符;
· 語句:簡單語句、語句塊、if語句、for語句、while語句;
· 函數調用。
在此基礎上,系統地介紹C語言的知識點。按照順序分別是:數據類型與輸入輸出、運算符與表達式、分支結構、循環結構、函數、指針與數組、C程序運行原理、結構體、文件和其他。在這些章節中,有幾個部分值得特別介紹。
(1)數據類型與輸入輸出。這一部分與其他教材差別很大。除了基本數據類型及其輸入和輸出,也介紹了:
· 數組、字符串及其輸入輸出。這里介紹了數組是如何創建、初始化和遍歷的(用for、while語句),還介紹了puts、gets等常見的字符串輸入和輸出函數,但沒有直接引入指針的概念。
· 文本文件輸入輸出,包括fscanf和fprintf兩個格式化輸入輸出函數。
(2)循環結構。在介紹循環結構的時候,引入了選擇排序、冒泡排序、楊輝三角、字符串單詞統計、文本文件字符統計等例子,一方面讓學生更好地掌握復雜的循環結構,另一方面加強了知識點的融合,擴大了知識面。
(3)C程序運行原理。這一章包含了所有系統底層的介紹,包括計算機的存儲器體系結構、程序的內存布局、變量的存儲類型等。這一章的目的是更好地培養學生的系統觀。
(4)文件。由于在前面章節中已經對文本文件的讀寫操作進行了很多演練,因此這一章主要圍繞二進制文件的讀寫進行。特別地介紹了二進制文件記錄的讀、寫、刪、查等操作場景。通過這些例子,可以讓學生更熟悉文件操作,也更側重實際應用。
通過這樣的安排,不僅加強了知識點之間的融合,而且大大提高了例題的多樣性,還可以在教學過程中安排更多的綜合訓練,比如文本文件處理。
另一方面,“器”還強調對工具的使用,這里最主要的是調試工具。筆者在教材中安排一章介紹常見開發環境的使用(介紹了Visual Studio Community和Code::Blocks),可以幫助初學者掌握調試技巧。
程序設計中的“術”就是應用基本的程序設計知識點解決問題的模式[2]、套路和算法。因此,它是知識點的綜合應用,是一些解決問題的有效思路。為了讓學生盡快熟悉編程之術,在教材中采取了以下策略。
(1)精選例題,從例題中引申出編程之術。筆者安排了綜合性、有代表性的例子,例如在循環結構這一章,介紹了選擇排序和冒泡排序兩種排序算法;在函數這一章,安排了輸出日歷以及簡單四則運算的例子,通過分析這些問題,學生可以學習到程序分解的過程以及關于日期的操作;在結構體這一章,介紹了基于鏈表的學生學籍信息管理實例,讓學生掌握與記錄操作相關的套路;在文件這一章,展示了如何從二進制文件中刪除滿足某些條件的記錄的思路。
(2)注重總結,提煉出編程之術。初學者往往不善于總結,因此教材中加入了大量的總結和提煉。首先,每一章結束后都有本章小結,對本章的知識點、常見套路和算法進行了總結。其次,在一些代表性的例題后面,對例題中的關鍵算法進行了總結。第三,介紹一些知識點的時候,順便介紹該知識點相關的常見套路。例如介紹了字符之后,總結大小寫字符之間的轉換等;在介紹浮點數的時候,提醒浮點數比較的注意事項;在介紹循環結構的時候,提煉窮舉算法的思想和注意事項;在講解遞歸函數調用的時候,總結遞歸這一技巧應用的要點。
(3)及時訓練,鞏固編程之術。在習題和實驗中,設計了相關題目,要求學生及時應用學到的套路和算法。
在編程實踐中,還有大量與編程風格和編程效率有關的經驗和技巧,這些也屬于“術”的范疇。這些內容在教材中的8個“編程實踐”章節中有所涉及,如代碼風格、命名、程序計時、軟件測試、實用字符串處理、程序設計與操作系統、中文處理等。這8個章節的內容可以擴大學生的知識面,激發學生的興趣。在實際教學中,這8個章節不一定由教師講授,完全可以讓學生自學。
對初學者來說,編程之“道”,或者說計算思維,往往比較抽象,難以理解。因此,需要對學生加以引導和點化。本教材中,很多地方都點出了程序背后的“道”。
(1)專門開辟了一個章節“復雜問題的求解算法”,介紹了很多面向問題求解的思想,如分治、貪心、動態規劃和回溯。對于每種思想,描述了其思維模式,指出其應用范圍和優缺點,并給出多個例子演示其應用。這樣,對于這些抽象思想,學生就有了比較感性的認識。
(2)在介紹知識點的時候適時點化。比如,緩存的思想在計算機硬件和軟件中經常用到。教材在介紹計算機存儲體系的時候,不是直接介紹這些存儲器,而是把內存看作CPU和磁盤之間的緩存,L2 cache看作CPU和內存之間的緩存,L1 cache又是CPU和L2 cache之間的高速緩存。最后,指出其中存在緩存思路的反復應用:為了彌補高速處理器和低速存儲器之間的速度差異,可以在它們之間插入一個更小但更快的存儲器,換句話說,中間存儲器是低速存儲器的高速緩存。
類似這樣的例子還有很多。通過這些例子,點出一些典型的計算思維,也許學生不一定馬上就能夠應用這些思維解決問題,但是可以引導學生從一個更高的角度看待問題,這對學生理解程序設計的本質和計算機系統無疑是有巨大幫助的。
當然,真正讓學生感悟這些“道”,還需要教師在教學過程中的引導。
教材《C程序設計:方法與實踐》[3](以下簡稱本教材)的前身是2009年出版的《C語言與程序設計方法》第1版[4]和第2版[5]。在本教材正式出版之前,初稿于2015—2016年在本校試用了兩年,并根據反饋意見進行了修改、定稿,最后由清華大學出版社于2017年5月出版。
本教材的章節目錄和內容見表1。
與現有教材相比,本教材在結構上有所突破,在內容組織上有所創新,精選了例題,并強調工程化和規范化的開發,這些在前面都已提到,此處不再重復。

表1 教材目錄和章節內容
為了配合這本教材的使用,筆者在書中安排了9個實驗,其中每個實驗包含了若干個實驗項目。每個實驗經過精心設計,題目類型多樣,可以有效地鞏固所學內容。
另外,為了方便教師教學,教材編寫組精心準備了前13章的教學課件,該教學課件是作者教學中使用并若干次修改和增補而來,內容非常豐富,可以直接用于教學。
在本教材出版之前,筆者在教學實踐中一直在思考和嘗試,進行了一系列的教學改革。本教材的出版是筆者的教學成果之一。跟本教材配套,筆者在教學方法上進行了一系列的調整,如實施了翻轉教學、加大了實踐訓練的力度等。實踐證明,圍繞這一教材展開的教學改革有明顯成效,學生的學習興趣明顯提升,實踐動手能力有大的改進。
參考文獻:
[1] Wing J M. Computational thinking [J]. Communications of the ACM, 2006, 49(3): 33-35.
[2] 張俊, 張彥鐸. 模式在程序設計教學中的應用[J]. 計算機教育, 2010(3): 108-111.
[3] 劉喜平, 萬常選, 舒蔚. C程序設計: 方法與實踐[M]. 北京: 清華大學出版社, 2017.
[4] 萬常選, 舒蔚, 駱斯文. C語言與程序設計方法[M]. 北京: 科學出版社, 2005.
[5] 萬常選, 舒蔚, 駱斯文. C語言與程序設計方法[M]. 2版. 北京:科學出版社, 2009.
(編輯:孫怡銘)