国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

人工智能課程設(shè)計畢業(yè)設(shè)計——基于機(jī)器學(xué)習(xí)的手寫漢字識別系統(tǒng)

這篇具有很好參考價值的文章主要介紹了人工智能課程設(shè)計畢業(yè)設(shè)計——基于機(jī)器學(xué)習(xí)的手寫漢字識別系統(tǒng)。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報違法"按鈕提交疑問。

需要完整代碼和論文私信我

人工智能 手寫字識別,人工智能,課程設(shè)計,機(jī)器學(xué)習(xí)

人工智能 手寫字識別,人工智能,課程設(shè)計,機(jī)器學(xué)習(xí)

人工智能 手寫字識別,人工智能,課程設(shè)計,機(jī)器學(xué)習(xí)

《機(jī)器學(xué)習(xí)》課程設(shè)計實驗報告

題目:基于深度學(xué)習(xí)的手寫漢字識別系統(tǒng)

目錄

基于深度學(xué)習(xí)的手寫漢字識別系統(tǒng)實驗報告

1.緒論............................................................................................................................................................ 1

1.1 研究背景及意義.......................................................................................................................... 1

1.2 國內(nèi)外研究現(xiàn)狀.......................................................................................................................... 1

1.3 研究內(nèi)容....................................................................................................................................... 2

2.相關(guān)技術(shù)概述........................................................................................................................................... 2

3.數(shù)據(jù)準(zhǔn)備.................................................................................................................................................... 2

3.1 數(shù)據(jù)獲取....................................................................................................................................... 2

3.2 數(shù)據(jù)預(yù)處理................................................................................................................................... 3

4.數(shù)據(jù)描述性分析....................................................................................................................................... 5

5.模型選擇、訓(xùn)練與測試........................................................................................................................... 6

5.1深度學(xué)習(xí)與傳統(tǒng)機(jī)器學(xué)習(xí)............................................................................................................ 6

5.2卷積神經(jīng)網(wǎng)絡(luò)................................................................................................................................. 6

5.3模型訓(xùn)練......................................................................................................................................... 8

5.4模型測試....................................................................................................................................... 14

6.模型性能評估與優(yōu)化.............................................................................................................................. 15

6.1模型性能評估.............................................................................................................................. 15

6.2模型優(yōu)化....................................................................................................................................... 16

7.模型部署與使用..................................................................................................................................... 18

7.1模型部署....................................................................................................................................... 18

7.2模型使用....................................................................................................................................... 18

8.總結(jié).......................................................................................................................................................... 20

參考文獻(xiàn)...................................................................................................................................................... 21

附錄.............................................................................................................................................................. 23

(1) 程序清單............................................................................................................................................. 23

(2) 源代碼................................................................................................................................................. 23

基于深度學(xué)習(xí)的手寫漢字識別系統(tǒng)實驗報告

1.緒論

    1. 研究背景及意義

在上世紀(jì)60年代,美國IBM公司開始進(jìn)行了對印刷體漢字的模式識別研究工作;1996年Casey和Nag用模板匹配法成功的識別出了1000個印刷體漢字,在全球范圍內(nèi),基于漢字的識別研究開始展開了。而就在這個時候,研究界對手寫漢字識別也掀起了高潮。日本率先開始研究手寫漢字識別,到了80年代,國內(nèi)開始了對手寫漢字的研究,因為漢語作為我們的母語,漢字主要在我國廣泛使用,對漢字的種類、內(nèi)涵、造字原理國內(nèi)的掌握情況較透徹,所以關(guān)于手寫漢字識別的深入研究主要集中在國內(nèi)。至今,手寫漢字識別已經(jīng)具備了比較成熟的理論基礎(chǔ)和廣闊的運(yùn)用前景,近年來,隨著機(jī)器學(xué)習(xí)和人工智能產(chǎn)業(yè)的高速發(fā)展,手寫文字識別更是被廣泛運(yùn)用。

在實際運(yùn)用中,手寫漢字識別被用于漢字掃描、機(jī)器自動閱卷、票據(jù)識別、證件識別等,提高了漢字的輸入效率,降低了手動輸入漢字的錯誤率,極大便利了人們的工作和生活。手寫體漢字識別是一個具有挑戰(zhàn)性的模式識別和機(jī)器學(xué)習(xí)問題。漢字結(jié)構(gòu)復(fù)雜,相似性大、數(shù)量大、種類多等特點(diǎn)給漢字識別研究帶來很多困難,尤其是手寫漢字識別,不同人具有不同的手寫風(fēng)格,在不同的書寫環(huán)境下容易發(fā)生形變,再加上漢字又分為行書、草書、楷書等多種形式,手寫漢字識別問題的研究一直困擾著字符識別研究學(xué)者的一個關(guān)鍵性難題。

本次機(jī)器學(xué)習(xí)課程設(shè)計項目我們小組基于卷積神經(jīng)網(wǎng)絡(luò)算法設(shè)計了手寫漢字識別系統(tǒng),采用卷積神經(jīng)網(wǎng)絡(luò)實現(xiàn)的低成本和快速高效手寫漢字圖像識別系統(tǒng),將在日常工作和生活中帶來極大的現(xiàn)實意義,同時也有著非常重要的研究意義。

    1. 國內(nèi)外研究現(xiàn)狀

如今在手寫字識別領(lǐng)域,存在的識別方法有多種。手寫漢字識別由于數(shù)據(jù)采集方式不同可以劃分為脫機(jī)手寫體漢字識別和聯(lián)機(jī)手寫體漢字識別兩大類:聯(lián)機(jī)手寫漢字識別所處理的手寫文字是書寫者通過物理設(shè)備(如數(shù)字筆、數(shù)字手寫板或者觸摸屏)在線書寫獲取的文字信號,書寫的軌跡通過定時采樣即時輸入到計算機(jī)中;而脫機(jī)手寫文字識別所處理的手寫文字是通過掃描儀或攝像頭等圖像捕捉設(shè)備采集到的手寫文字二維圖片。目前,比較常用的手寫漢字識別方法有K最近鄰算法、神經(jīng)網(wǎng)絡(luò)、隱馬爾可夫模型、貝葉斯分類器、支持向量機(jī)和改進(jìn)的二次判別函數(shù)等。

特別是最近幾年來隨著深度學(xué)習(xí)理論研究的不斷深入和運(yùn)用場景和不斷擴(kuò)大,深度學(xué)習(xí)理論不斷顛覆了傳統(tǒng)的識別算法,已經(jīng)成為模式識別領(lǐng)域研究熱點(diǎn)之一,也在影響著字符識別的研究,越來越多的深度學(xué)習(xí)算法正在被運(yùn)用在手寫字識別領(lǐng)域。深度學(xué)習(xí)的引入使得手寫單字符識別問題已經(jīng)在某種程度上獲得了較好的解決,但相對單字符識別而言,含序列信息的手寫文本行識別仍然是此領(lǐng)域還未解決的難點(diǎn)問題之一。

目前,在我國,已經(jīng)推出了多字體大字符集簡繁混識的識別核心,能夠識別常見的十幾種字體及其變體,識別字符集包括簡體中文6763字、繁體中文5401字、香港常用字等1萬多字,各種字體的識別率都在99%以上。

    1. 研究內(nèi)容

本次課程設(shè)計主要是針對手寫體漢字識別,通過對比采用不同模型所得到的結(jié)果,進(jìn)行從中擇優(yōu),對其中較好的模型以及其參數(shù)進(jìn)行保留,同時搭建一個簡單的GUI界面,最后用上述訓(xùn)練好的模型進(jìn)行預(yù)測,得到識別結(jié)果。

2.相關(guān)技術(shù)概述

本次課程設(shè)計的相關(guān)代碼都是是基于python編寫的,其中用到的框架和庫有tensorflow、sklearn、OpenCV、numpy等等,而我們此次用到的主要框架也是tensorflow,準(zhǔn)確地說是tensorflow -gpu。

TensorFlow:提供Python語言下的四個不同版本:CPU版本(tensorflow)、包含GPU加速的版本(tensorflow-gpu),以及它們的每日編譯版本(tf-nightly、tf-nightly-gpu)。TensorFlow就好像一個功能強(qiáng)大的機(jī)床,它可以幫助制造出不同的產(chǎn)品(即數(shù)學(xué)模型),用它來處理大量數(shù)據(jù),可以快速建立數(shù)學(xué)模型,而這些模型可以完成智能功能。用tensorflow-gpu會比CPU版本快上好幾十倍以上。

3.數(shù)據(jù)準(zhǔn)備

    1. ?數(shù)據(jù)獲取

本次實驗采用中國科學(xué)院自動化研究所提供的手寫體漢字?jǐn)?shù)據(jù)集CASIA-HWDB1.1進(jìn)行實驗。CASIA-HWDB1.1數(shù)據(jù)集包含了3755個常用的GB2312一級漢字,由300個不同的編寫者書寫,每個漢字的樣本庫包含240個訓(xùn)練樣本和60個測試樣本。

以下分別是訓(xùn)練集和測試集的地址:

http://www.nlpr.ia.ac.cn/databases/download/feature_data/HWDB1.1trn_gnt.zip
http://www.nlpr.ia.ac.cn/databases/download/feature_data/HWDB1.1tst_gnt.zip

將上述文件解壓后可以分別得到HWDB1.1trn_gnt.alz和HWDB1.1tst_gnt.alz ,alz也屬于一種壓縮文件的格式,需要進(jìn)行二次解壓,再次解壓就會得到gnt文件。

    1. ?數(shù)據(jù)預(yù)處理

3.2.1數(shù)據(jù)讀取

分別讀取HWDB1.1trn和HWDB1.1tst兩個文件夾中的數(shù)據(jù),并最終將數(shù)據(jù)存儲在char_dict字典中,計算該字典的長度,共計3755。

圖3-1

3.2.2圖片格式轉(zhuǎn)換

將訓(xùn)練集和測試集中的文件格式由gnt格式轉(zhuǎn)換為png(3通道)格式,并分別統(tǒng)計其中的圖片數(shù)目,得到訓(xùn)練集中有89萬余張圖片,測試集中則有22萬余張圖片。

圖3-2

選擇其中一個文件夾查看一下轉(zhuǎn)換后的效果,如下圖:

圖3-3

3.2.3查看數(shù)據(jù)集標(biāo)簽

讀取并查看訓(xùn)練集的標(biāo)簽,即漢字和對應(yīng)編碼的位置。

圖3-4

3.2.4圖像處理

查看解碼后的圖片,發(fā)現(xiàn)其分辨率不統(tǒng)一,有長有短,所以我們統(tǒng)一把數(shù)據(jù)轉(zhuǎn)成64x64,并做歸一化處理,這里調(diào)用 cv2 庫讀入圖片,并用resize方法統(tǒng)一像素為64x64 。

圖3-5

3.2.5劃分訓(xùn)練集和驗證集

在訓(xùn)練集中取一部分作為驗證集,test_size=0.25,radom_state=7。

圖3-6

4.數(shù)據(jù)描述性分析

數(shù)據(jù)集一共包含3755類手寫漢字,訓(xùn)練集來自240人寫的897758個漢字,測試集來自60人寫的223991個漢字。而且解碼后圖片的規(guī)格大小也完全不同,從30x42規(guī)格到101x54規(guī)格不等。

雖然單張圖片的大小也就不到幾KB,但由于數(shù)據(jù)集數(shù)量龐大,讀取速度就會特別慢,而且通過一層層神經(jīng)網(wǎng)絡(luò)之后數(shù)據(jù)的維度就逐漸放大,讀取的時候就會占用大量內(nèi)存,甚至直接爆滿。普通電腦或筆記本的CPU根本就跑不了這么多類。100個類可以跑,200個類也還行,到了1000個類,直接十幾個小時數(shù)據(jù)都沒讀取完,因為估計CPU已經(jīng)運(yùn)作不起來了,所以一直卡著。因為電腦配置的限制,最終我們只能選擇訓(xùn)練500個類,也就是訓(xùn)練500個漢字,而且還是因為租借了谷歌云服務(wù)器才能最終等到跑完這500個類。

5.模型選擇、訓(xùn)練與測試

5.1深度學(xué)習(xí)與傳統(tǒng)機(jī)器學(xué)習(xí)

我們都知道,傳統(tǒng)的機(jī)器學(xué)習(xí)可以用來做許多的東西,例如模式識別、數(shù)據(jù)挖掘計算機(jī)視覺和語音識別等領(lǐng)域。但傳統(tǒng)的機(jī)器學(xué)習(xí)也有自己的短板方面,例如傳統(tǒng)的機(jī)器學(xué)習(xí)需要人工去提取特征,然而深度學(xué)習(xí)不需要。深度學(xué)習(xí)通常由多個層組成,它們通常將更簡單的模型組合在一起,將數(shù)據(jù)從一層傳遞到另一層來構(gòu)建更復(fù)雜的模型。通過訓(xùn)練大量數(shù)據(jù)自動得出模型,不需要人工特征提取環(huán)節(jié)。這個特點(diǎn)在數(shù)據(jù)規(guī)模比較大的數(shù)據(jù)集上可以很好的體現(xiàn)出來兩者之間的差距,并且深度學(xué)習(xí)的表達(dá)能力仍然要強(qiáng)與傳統(tǒng)的機(jī)器學(xué)習(xí)。

傳統(tǒng)的機(jī)器學(xué)習(xí)與深度學(xué)習(xí)性能差距在數(shù)據(jù)規(guī)模上,我們可以看一組對比圖,可以看到在不同的數(shù)據(jù)規(guī)模,深度學(xué)習(xí)與傳統(tǒng)的機(jī)器學(xué)習(xí)之間的差距就很明顯的體現(xiàn)出來了,如下圖所示。

圖5-1

5.2卷積神經(jīng)網(wǎng)絡(luò)

本次課程設(shè)計項目使用的數(shù)據(jù)是為圖片數(shù)據(jù),圖片數(shù)據(jù)對于普通的數(shù)據(jù)而言,它擁有的數(shù)據(jù)特征數(shù)量都是比較大的,并且數(shù)據(jù)規(guī)模也很大。所以傳統(tǒng)的機(jī)器學(xué)習(xí)模型已經(jīng)滿足不了我們的需求,所以本次課程設(shè)計使用的訓(xùn)練模型是深度學(xué)習(xí)中的卷積神經(jīng)網(wǎng)絡(luò)(CNN)。

CNN由紐約大學(xué)的Yann Lecun于1998年提出,其本質(zhì)是一個多層感知機(jī),它的部分特點(diǎn)在于減少了權(quán)值的數(shù)量使得網(wǎng)絡(luò)易于優(yōu)化,并且還降低了模型的復(fù)雜度,也就是減小了過擬合的風(fēng)險。對于輸入數(shù)據(jù)為圖像數(shù)據(jù)的時候,它的表現(xiàn)的更為明顯,因為圖像可以直接作為網(wǎng)絡(luò)的輸入,避免了傳統(tǒng)識別算法中復(fù)雜的特征提取和數(shù)據(jù)重建的過程,在二維圖像的處理過程中有很大的優(yōu)勢。所以許多的圖像識別分類項目中都被大量使用,其中比較著名的模型有LeNet5 模型、AlexNet 模型、VGG 模型、GoogleNet模型和ResNets模型等,它們都是圖像分類任務(wù)中被大量使用,可以很明顯體現(xiàn)出卷積神經(jīng)網(wǎng)絡(luò)對于圖像分類的優(yōu)勢。

深度神經(jīng)網(wǎng)絡(luò)的基本思想是通過構(gòu)建多層網(wǎng)絡(luò),對目標(biāo)進(jìn)行多層表示,以期通過多層的高層次特征來表示數(shù)據(jù)的抽象語義信息,獲得更好的特征魯棒性。它與普通的神經(jīng)網(wǎng)絡(luò)對比,層數(shù)更加多,結(jié)構(gòu)更加復(fù)雜,下圖是普通的神經(jīng)網(wǎng)絡(luò)結(jié)構(gòu)圖。普通的神經(jīng)網(wǎng)絡(luò)結(jié)構(gòu)包括:輸入層、隱藏層和輸出層,其中隱藏層是可以擁有多層的結(jié)構(gòu)。

圖5-2

卷積神經(jīng)網(wǎng)絡(luò)結(jié)構(gòu)包括:輸入層、卷積層、池化層、全連接層和輸出層等。每一層有多個特征圖,每個特征圖通過一種卷積濾波器提取輸入的一種特征,每個特征圖有多個神經(jīng)元。所以除了輸入層和輸出層,卷積神經(jīng)網(wǎng)絡(luò)的其他層都可以擁有多層的結(jié)構(gòu),與普通神經(jīng)網(wǎng)絡(luò)結(jié)構(gòu)對比,它的結(jié)構(gòu)更加復(fù)雜,層數(shù)更加多,如下圖一個經(jīng)典的汽車識別分類的案例所示。

圖5-3

5.3模型訓(xùn)練

模型的訓(xùn)練環(huán)境、軟硬件如下表:

環(huán)境

版本號、其他信息

筆記本

華碩飛行堡壘7

操作系統(tǒng)

Windows 10專業(yè)版本

編程語言

Python3.7

模型框架

Tensorflow2.4.0、Keras2.5.0

服務(wù)器

Google Colab PRO

GPU

Tesla T100

表5-1

對于已經(jīng)進(jìn)行預(yù)處理的圖片數(shù)據(jù)進(jìn)行隨機(jī)選取的500個類別進(jìn)行模型的訓(xùn)練,初步的模型訓(xùn)練只是用于來選取最佳的模型參數(shù),訓(xùn)練出最佳的卷積神經(jīng)網(wǎng)絡(luò)模型。500個手寫漢字類別,每個類別是240張圖片,一共的訓(xùn)練集是120000張圖片,驗證集一共是30000張圖片。每張圖片經(jīng)過初步的圖像預(yù)處理,使得尺寸統(tǒng)一為64*64,為RGB的三個通道,數(shù)據(jù)規(guī)模非常龐大。

此處需要對圖片進(jìn)行讀取,對圖片數(shù)據(jù)轉(zhuǎn)換為數(shù)字格式,因為計算機(jī)只認(rèn)識數(shù)字類型的數(shù)據(jù)。對于圖片數(shù)據(jù)的讀取,我們使用到了Python的一個OpenCv庫,用于圖像的讀取以及圖像的特征提取,如下圖所示。主要是使用到了Python的numpy庫與opencv庫。由于圖片數(shù)據(jù)規(guī)模較大,基于Tesla T100的GPU,讀取120000張訓(xùn)練圖片的時間需要15分鐘左右,讀取30000張測試圖片需要3分鐘左右。訓(xùn)練數(shù)據(jù)的讀取方式與測試數(shù)據(jù)的讀取方式一致。

圖5-4

接下來是定義一個卷積神經(jīng)網(wǎng)絡(luò)。本次的卷積神經(jīng)網(wǎng)絡(luò)是基于tensorflow的一個框架進(jìn)行定義,如下圖代碼所示。該模型使用了4個卷積層,每個卷積層后添加了一個池化層,池化層的作用是可以把卷積層增加的大量特征進(jìn)行縮小。后面還用到了扁平層,用于把數(shù)據(jù)“拉直”,便于后面的全連接層計算。模型的最后使用了兩層全連接層,最后一層使用了softmax激活函數(shù),該函數(shù)使用與多分類的模型當(dāng)中,其中最后的輸出類別為500個類別。

圖5-5

由于模型的訓(xùn)練結(jié)果需要展示,此處還自定義了一個可以展示模型訓(xùn)練結(jié)果的一個函數(shù),如下圖所示,該函數(shù)主要是使用到了Python的matplotlib庫,可以畫出自定義的卷積神經(jīng)網(wǎng)絡(luò)訓(xùn)練效果圖片。代碼設(shè)計如下圖所示。

圖5-6

使用上面自定義的讀取圖片數(shù)據(jù)的函數(shù),對圖片數(shù)據(jù)進(jìn)行一個讀取且轉(zhuǎn)化成為一個數(shù)值型數(shù)據(jù)。

圖5-7

最后到了模型的訓(xùn)練階段,此處的模型訓(xùn)練我們使用tensorflow模型框架的fit()函數(shù)對數(shù)據(jù)進(jìn)行訓(xùn)練,對于訓(xùn)練結(jié)果,使用自定義的函數(shù)對其進(jìn)行展示,查看模型的訓(xùn)練效果。如下圖所示。對于模型的結(jié)構(gòu)圖,我們使用到了一個keras框架的一個特殊功能進(jìn)行打印,并且需要安裝好Python的兩個graphviz和pydot2模塊才可以進(jìn)行使用。

圖5-8

許多人喜歡使用Tensorflow框架的原因,是因為深度學(xué)習(xí)模型的訓(xùn)練過程中可以輸出模型的詳細(xì)參數(shù)和模型的詳細(xì)訓(xùn)練過程,如下圖所示,展示了自定義的卷積神經(jīng)網(wǎng)絡(luò)的各層的詳細(xì)參數(shù)如下圖所示。

圖5-9

其中最左邊的Layer是模型中的各個層的名稱,中間的Output Shape是指該層輸出的數(shù)據(jù)類型大小,例如(None,64,64,32)是指圖像經(jīng)過第一層的卷積后輸出的數(shù)據(jù)大小。None指的是圖片數(shù)量不進(jìn)行確認(rèn),64、64分別是指圖像經(jīng)過第一層卷積之后圖像的長和寬為64和64。64和64的由來是因為圖片的輸入為(64,64,3),通過計算一下卷積公式計算得來,其中O是輸出尺寸,K是卷積核大小,P是填充,即是參數(shù)padding,S是步長(卷積的移動長度)。該模型的輸入圖像大小為64,步長為1,卷積核大小為5,所以輸出尺寸為(64-5+(5-1)/2)/1+1=64,所以第一層的輸入圖像尺寸為64*64,輸出圖像大小也為64*64。

? ???????P=(K-1)2

???? ???????????(1)

????? O=W-K+2PS+1

? ????????(2)

最后的一個32,指的是該層的神經(jīng)元個數(shù),也可以易懂的理解為卷積之后的圖片層數(shù)(第一層的圖片是RGB三個通道,為三層)。我們可以看到最右邊Param指的是參數(shù)個數(shù),例如第一層的參數(shù)個數(shù)為2432,計算公式如下,其中K指的是卷積核大小,C1指的是前一層的神經(jīng)元個數(shù)(或者是圖片層數(shù),例如一般彩色圖片的輸入為RGB三層),C2是指自身卷積層的神經(jīng)元個數(shù)(圖片層數(shù))。例如第一層,卷積核大小為5,前一層是輸入層,輸入層的層數(shù)為3,該卷積層有32個神經(jīng)元,所以5*5*3*32+32=2432,最后加上的是一個偏置數(shù),有多少層就需要加上多少個偏置數(shù)。其他層的輸出大小和參數(shù)個數(shù)計算與上一致。我們可以查看上圖最后輸出的參數(shù)總和為19907892個,參數(shù)量很大。

Param=K*K*C1*C2+C2*1

????? (3)

Tensorflow框架還可以在模型的訓(xùn)練過程中輸出模型的訓(xùn)練過程,如下圖所示,Tensorflow框架不僅僅可以輸出每一個批次的訓(xùn)練過程的進(jìn)度條和訓(xùn)練時間,還可以輸出每一個訓(xùn)練批次的訓(xùn)練結(jié)果,例如訓(xùn)練集的訓(xùn)練損失、驗證集的訓(xùn)練損失,還有訓(xùn)練集和驗證集的每一個批次的準(zhǔn)確率。

圖5-10

在此次的模型訓(xùn)練中,除了上述的卷積神經(jīng)網(wǎng)絡(luò),此處還使用了兩個傳統(tǒng)機(jī)器學(xué)習(xí)模型進(jìn)行對比,用來對比深度學(xué)習(xí)與傳統(tǒng)的機(jī)器學(xué)習(xí)對于在大規(guī)模數(shù)據(jù)的模型訓(xùn)練效果的差異,如下表和圖所示。

模型

訓(xùn)練集準(zhǔn)確率

驗證集準(zhǔn)確率

KNN

56.69%

49.83%

SVM

68.67%

52.23%

自定義CNN1

92.77%

79.34%

自定義CNN2

97.89%

82.12%

自定義CNN3

96.58%

85.56%

表5-2

由于傳統(tǒng)的機(jī)器學(xué)習(xí)模型訓(xùn)練的效果不佳,此處不展示兩個傳統(tǒng)機(jī)器學(xué)習(xí)模型的訓(xùn)練結(jié)果,直接展示自定義的三個卷積神經(jīng)網(wǎng)絡(luò)的模型訓(xùn)練結(jié)果圖,CNN1、CNN2和CNN3的訓(xùn)練結(jié)果圖依次往下所示。我們很直觀的發(fā)現(xiàn),自定義的卷積神經(jīng)網(wǎng)絡(luò)訓(xùn)練集的準(zhǔn)確率都達(dá)到了92%以上,驗證集的準(zhǔn)確率都達(dá)到了79%以上,可以很明顯發(fā)現(xiàn)在大規(guī)模數(shù)據(jù)下,使用深度學(xué)習(xí)的效果要明顯好于傳統(tǒng)的機(jī)器學(xué)習(xí)模型。

圖5-11 自定義CNN1????????????????????????????? 圖5-12 自定義CNN2

圖5-13 自定義CNN3

5.4模型測試

由于在本次的項目中,傳統(tǒng)的機(jī)器學(xué)習(xí)模型的訓(xùn)練效果不佳,所以不對傳統(tǒng)的機(jī)器學(xué)習(xí)模型進(jìn)行測試。對于上述三個自定義的卷積神經(jīng)網(wǎng)絡(luò),使用訓(xùn)練好的模型,對測試集30000張手寫漢字圖像數(shù)據(jù)進(jìn)行預(yù)測,得到的測試結(jié)果如下圖所示。我們可以發(fā)現(xiàn)目前最高的模型測試結(jié)果已經(jīng)達(dá)到了82.48%,但是結(jié)果還達(dá)不到我們的期望,還需要對模型進(jìn)行優(yōu)化。

圖5-14

6.模型性能評估與優(yōu)化

6.1模型性能評估

對于自定義的三個卷積神經(jīng)網(wǎng)絡(luò)模型,我們可以發(fā)現(xiàn)模型的訓(xùn)練效果較好,訓(xùn)練集的準(zhǔn)確率最高達(dá)到了97.89%,驗證集的準(zhǔn)確率最高為85.56%,但是兩個數(shù)據(jù)集合的最高準(zhǔn)確率都不在同一個訓(xùn)練模型中,所以我們需要對自定義的卷積神經(jīng)網(wǎng)絡(luò)模型繼續(xù)修改參數(shù)進(jìn)行優(yōu)化,使得性能達(dá)到我們期望的效果。

圖6-1

6.2模型優(yōu)化

由于卷積神經(jīng)網(wǎng)絡(luò)的參數(shù)量很大,并且訓(xùn)練時間較長,所以對參數(shù)的調(diào)整也是一個本次項目中的一個難點(diǎn)。本次項目的參數(shù)調(diào)整為人為調(diào)整,憑借著自己的模型訓(xùn)練經(jīng)驗和當(dāng)前的訓(xùn)練結(jié)果對模型的參數(shù)進(jìn)行修改。

查看了許多優(yōu)秀的卷積神經(jīng)網(wǎng)絡(luò)的項目,里面給出了基于Tensorfolw框架大量有價值需要調(diào)整的參數(shù),例如在卷積層當(dāng)中,可以修改卷積核大小,每層的神經(jīng)元個數(shù),每層卷積的填充值大小,還有每層卷積的步長(滑動步長)和激活函數(shù)等。經(jīng)過多次的訓(xùn)練對比,訓(xùn)練得出500種手寫漢字的卷積神經(jīng)網(wǎng)絡(luò)最佳參數(shù)如下表所示。

參數(shù)名稱

參數(shù)大小、其他

卷積層

4

卷積核

(5,5)

每層卷積的神經(jīng)元個數(shù)

32,64,128256

填充值

2

滑動步長

1

激活函數(shù)(除最后一層)

relu

激活函數(shù)(最后一層)

softmax

優(yōu)化算法

隨機(jī)梯度下降(Stochastic Gradient Descent,SGD)

Dropout layer

0.2

batch-size

64

epochs

18

表6-1

最優(yōu)卷積神經(jīng)網(wǎng)絡(luò)模型結(jié)構(gòu)圖如下所示(從左往右),詳細(xì)展示了各層的輸入和輸出參數(shù)大小。

圖6-2

最終得到的最優(yōu)模型訓(xùn)練和測試的結(jié)果如下圖所示。

圖6-3

模型的最優(yōu)訓(xùn)練效果如下圖所示,我們可以發(fā)現(xiàn)模型的收斂性較好,訓(xùn)練集與驗證集之間的損失數(shù)大小相差不大。最終的模型,無論是在訓(xùn)練集的準(zhǔn)確率、驗證集的準(zhǔn)確率還是測試集的準(zhǔn)確率都是最高的,并且從模型的訓(xùn)練效果中可以看出模型的收斂性較好。

? 圖6-4

7.模型部署與使用

7.1模型部署

在模型訓(xùn)練的時候已經(jīng)把模型的相關(guān)訓(xùn)練權(quán)重保存為h5文件,可直接通過tf.keras.models.load_model()直接讀取該模型,再通過model()方法預(yù)測結(jié)果。

圖4-1

7.2模型使用

這里我們調(diào)用PyQt5庫,簡單地做了一個GUI界面,設(shè)置了一個畫板來繪畫并保存圖片,以及將預(yù)測結(jié)果的方法包裝成組件,最后通過點(diǎn)擊組件按鈕對畫板傳輸過來的圖片進(jìn)行識別,將結(jié)果打印在控制臺上。運(yùn)行效果如下:

圖7-2

在畫板上寫字,并點(diǎn)擊“開始識別”,得到結(jié)果如下:

圖7-3

點(diǎn)擊“清空畫板”,再重新寫字和識別,如下圖:

圖7-4

圖7-5

圖7-6

圖677

從上述測試結(jié)果可以看出,當(dāng)字體居中而且特征明顯時,識別結(jié)果的可能概率近乎于1;而當(dāng)字體沒有很明顯的指向某個字的特征時,識別結(jié)果的可能概率就會很低。

8.總結(jié)

在本次的機(jī)器學(xué)習(xí)課程設(shè)計中,我們組實現(xiàn)了手寫漢字識別系統(tǒng),其中包括對深度學(xué)習(xí)的卷積神經(jīng)網(wǎng)絡(luò)模型的訓(xùn)練還有系統(tǒng)GUI界面的設(shè)計。本次課程設(shè)計的手寫漢字?jǐn)?shù)據(jù)來源于中國科學(xué)院自動化研究所提供的手寫體漢字?jǐn)?shù)據(jù)集CASIA-HWDB1.1的前500種手寫漢字,每個類別的訓(xùn)練數(shù)據(jù)為240張手寫漢字圖片,每一類的測試數(shù)據(jù)為60張手寫漢字圖片,數(shù)據(jù)量是非常的龐大,對電腦硬件上有很大的要求。

我們自定義的卷積神經(jīng)網(wǎng)絡(luò)進(jìn)行參數(shù)的修改和其他方面的改變,最終最優(yōu)的卷積神經(jīng)網(wǎng)絡(luò)在500種手寫漢字的識別任務(wù)上訓(xùn)練集的準(zhǔn)確率達(dá)到了98.9%,驗證集的最高準(zhǔn)確率達(dá)到了88.14%,測試集的準(zhǔn)確率也達(dá)到了87.3%,模型的訓(xùn)練效果非常可觀。

在本次課程設(shè)計當(dāng)中,我們第一次使用到了深度學(xué)習(xí)的模型和使用GPU來訓(xùn)練大規(guī)模的數(shù)據(jù)。我們發(fā)現(xiàn)在大規(guī)模數(shù)據(jù)上,無論是模型的訓(xùn)練效果上還是模型的訓(xùn)練時間,深度學(xué)習(xí)模型要比傳統(tǒng)的機(jī)器學(xué)習(xí)模型的效果好許多。例如在同一個環(huán)境中,傳統(tǒng)的機(jī)器學(xué)習(xí)KNN,訓(xùn)練一個模型和預(yù)測測試數(shù)據(jù)需要49分鐘左右,而自定義卷積神經(jīng)網(wǎng)絡(luò)訓(xùn)練和預(yù)測測試數(shù)據(jù)只需要8分鐘左右。

由于本次課程設(shè)計選擇的數(shù)據(jù)量很大,僅訓(xùn)練圖片就有120000多張,本地筆記本電腦無法實現(xiàn)對數(shù)據(jù)的讀取和模型的訓(xùn)練,所以本次課程設(shè)計我們還是用到了Google的一個服務(wù)器,利用提供的GPU對數(shù)據(jù)進(jìn)行一個讀取和模型的訓(xùn)練。我們發(fā)現(xiàn)利用GPU對于數(shù)據(jù)的讀取和模型的訓(xùn)練速度是非??欤魶]有GPU,對于大量數(shù)據(jù)的網(wǎng)絡(luò)訓(xùn)練會非常的耗時。在某種意義上來講,訓(xùn)練深度網(wǎng)絡(luò)時,GPU比CPU快40倍左右。CPU適合復(fù)雜的邏輯運(yùn)算,GPU適合矩陣運(yùn)算,深度學(xué)習(xí)大部分的模型訓(xùn)練的算法運(yùn)算都采用了矩陣運(yùn)算,而且CPU的核心數(shù)要比GPU少,模型訓(xùn)練需要很多并行的矩陣運(yùn)算,GPU在深度學(xué)習(xí)模型的訓(xùn)練上顯得非常的出色。

經(jīng)過上學(xué)期的機(jī)器學(xué)習(xí)課程的學(xué)習(xí),和本次課程設(shè)計的實踐,我們組成員學(xué)到了如何利用GPU來訓(xùn)練大規(guī)模數(shù)據(jù)的深度學(xué)習(xí)模型,并且理解了許多深度學(xué)習(xí)模型的參數(shù)含義,并且可以自己設(shè)計自定義的深度學(xué)習(xí)模型和設(shè)計模型識別系統(tǒng)的GUI界面,使得我們對機(jī)器學(xué)習(xí)的認(rèn)識更進(jìn)一步。

參考文獻(xiàn)

[1]薛炳如,楊靜宇,胡鐘山,等. 小類別數(shù)手寫漢字識別[J]. 計算機(jī)研究與發(fā)展,2000,37(4):483-492.

[2]李璐璐. 基于彈性網(wǎng)格的手寫體識別二級分類器的研究[D]. 廣東:華南理工大學(xué),2008. DOI:10.7666/d.Y1384676.

[3]瞿海金. 手寫體數(shù)字識別方法的研究與實現(xiàn)[D]. 江蘇:南京理工大學(xué),2005. DOI:10.7666/d.y763434.

[4]金連文,鐘卓耀,楊釗,等. 深度學(xué)習(xí)在手寫漢字識別中的應(yīng)用綜述[J]. 自動化學(xué)報,2016,42(8):1125-1141. DOI:10.16383/j.aas.2016.c150725.

[5]高學(xué),王有旺. 基于CNN和隨機(jī)彈性形變的相似手寫漢字識別[J]. 華南理工大學(xué)學(xué)報(自然科學(xué)版),2014(1):72-76,83. DOI:10.3969/j.issn.1000-565X.2014.01.013.

[6]周甲甲. 基于深度學(xué)習(xí)的漢字識別方法研究[D]. 湖北:華中師范大學(xué),2019.

附錄

  1. 程序清單

CNN_1 .ipynb和CNN_2 .ipynb和CNN.ipynb這三個文件主要在模型結(jié)構(gòu)有差異,其它地方類似,所以代碼的完整的注釋在CNN.ipynb中,而Machine learning.ipynb是傳統(tǒng)的機(jī)器學(xué)習(xí)模型,ImageChange.ipynb則是圖片格式轉(zhuǎn)換,GuiMain.ipynb則是最終運(yùn)行界面。

(2) 源代碼

CNN.ipynb

#對訓(xùn)練數(shù)據(jù)進(jìn)行加載并且轉(zhuǎn)換

import os

import cv2

import numpy as np

import matplotlib.image as mi

from sklearn.model_selection import train_test_split

dataset1 = []? # 數(shù)據(jù)集列表

labels1 = []? # 標(biāo)簽列表

label1 = 0? # 第一個標(biāo)簽

def load_data1(filepath):

??? # 遍歷filepath下所有文件,包括子目錄

??? files = os.listdir(filepath)

??? for fi in files:

??????? fi_d = os.path.join(filepath, fi+'/')

??????? if os.path.isdir(fi_d):

??????????? global label1

??????????? load_data1(fi_d)

??????????? label1 += 1?????????????? #圖像類別的標(biāo)簽

??????? else:

??????????? labels1.append(label1)

??????????? img = mi.imread(fi_d[:-1])??????? #對圖像數(shù)據(jù)進(jìn)行讀取???

??????????? img2 = cv2.resize(img, (64, 64))? # 對圖像數(shù)據(jù)進(jìn)行轉(zhuǎn)換,大小為(64,64,3)

??????????? dataset1.append(img2)??????????? #把讀取得到的一個圖像數(shù)據(jù)添加到數(shù)組內(nèi)

??? # 在訓(xùn)練集中取一部分作為驗證集

??? train_image, val_image, train_label, val_label = train_test_split(?????????????

??????? np.array(dataset1), np.array(labels1), random_state=7)

return train_image, val_image, train_label, val_label?????? #返回讀取得到的圖像數(shù)據(jù)和圖像標(biāo)簽

#對測試數(shù)據(jù)進(jìn)行加載并且轉(zhuǎn)換

import os

import cv2

import numpy as np

import matplotlib.image as mi

dataset2 = []? # 數(shù)據(jù)集列表

labels2 = []? # 標(biāo)簽列表

label2 = 0? # 第一個標(biāo)簽

def load_data2(filepath):

??? # 遍歷filepath下所有文件,包括子目錄

??? files = os.listdir(filepath)

??? for fi in files:

??????? fi_d = os.path.join(filepath, fi+'/')

??????? if os.path.isdir(fi_d):

??????????? global label2

??????????? load_data2(fi_d)

??????????? label2 += 1

??????? else:

??????????? labels2.append(label2)

??????????? img = mi.imread(fi_d[:-1])

??????????? img2 = cv2.resize(img, (64, 64))? # (64,64,3)

??????????? dataset2.append(img2)

??? return np.array(dataset2), np.array(labels2)

#使用tensorflow框架對自定義對卷積神經(jīng)網(wǎng)絡(luò)模型結(jié)構(gòu)進(jìn)行定義

import tensorflow.keras.backend as k

from tensorflow.keras.models import Sequential

from tensorflow.keras.layers import Dropout, Flatten, Dense

from tensorflow.keras.layers import Conv2D, MaxPooling2D

def get_model():

??? k.clear_session()

??? # 創(chuàng)建一個新模型,使用的是keras框架下的一個Sequential模型

??? model = Sequential()

??? model.add(Conv2D(32, (5,5), padding='same', activation='relu', input_shape=(64, 64, 3))) #設(shè)計第一個卷積層,卷積核為5*5,32個神經(jīng)元,激活函數(shù)為relu函數(shù),輸入圖像大小為64*64*3

??? model.add(MaxPooling2D(pool_size=(2, 2)))??????????????????????????? #設(shè)計一個池化層,對卷積之后的數(shù)據(jù)進(jìn)行最大池化處理,池化大小為2*2

??? model.add(Conv2D(64, (5,5), padding='same', activation='relu'))?????? #第二個卷積層,卷積核一樣為5*5,64個神經(jīng)元,激活函數(shù)為relu

??? model.add(MaxPooling2D(pool_size=(2, 2)))??????????????????? #第二個池化層,池化大小為2*2

??? model.add(Conv2D(128, (5,5), padding='same', activation='relu'))?????? #與上類似

??? model.add(MaxPooling2D(pool_size=(2, 2)))

??? model.add(Conv2D(256, (5,5), padding='same', activation='relu'))

??? model.add(MaxPooling2D(pool_size=(2, 2)))

??? model.add(Flatten())??????????????????????????????? #扁平層,類似于把數(shù)據(jù)“拉直”

???

??? model.add(Dropout(0.2))????????????????????????????? #防止數(shù)據(jù)過擬合

??? model.add(Dense(4096, activation='relu'))??????????????????? #全連接層,大小為4096,激活函數(shù)為relu

??? model.add(Dropout(0.2))

??? model.add(Dense(500, activation='softmax'))?????????????????? #最后一個全連接層,也為輸出層,激活函數(shù)選擇了softmax函數(shù),輸出類別為500個

??? model.summary()????????????????????????????????? #模型可視化

??? # 選擇優(yōu)化器和損失函數(shù)

??? model.compile(optimizer='sgd',??????????

????????????????? loss='sparse_categorical_crossentropy',#categorical_crossentropy,獨(dú)熱編碼才用的交叉熵

????????????????? metrics=['accuracy'])

??? return model

#也是自定義模型,遇上一致

import tensorflow.keras.backend as k

from tensorflow.keras.models import Sequential

from tensorflow.keras.layers import Dropout, Flatten, Dense

from tensorflow.keras.layers import Conv2D, MaxPooling2D

def get_model():

??? k.clear_session()

??? # 創(chuàng)建一個新模型

??? model = Sequential()

??? model.add(Conv2D(64, (3,3), padding='same', activation='relu', input_shape=(64, 64, 3)))? # 64 64 3

??? model.add(MaxPooling2D(pool_size=(2, 2)))

??? model.add(Conv2D(128, (3,3), padding='same', activation='relu'))

??? model.add(MaxPooling2D(pool_size=(2, 2)))

??? model.add(Conv2D(256, (3,3), padding='same', activation='relu'))

??? model.add(MaxPooling2D(pool_size=(2, 2)))

??? model.add(Conv2D(512, (3,3), padding='same', activation='relu'))

??? model.add(MaxPooling2D(pool_size=(2, 2)))

??? # model.add(Conv2D(512, (3,3), padding='same', activation='relu'))

??? # model.add(MaxPooling2D(pool_size=(2, 2)))

??? model.add(Flatten())

???

??? model.add(Dropout(0.2))

??? model.add(Dense(4096, activation='relu'))

??? model.add(Dropout(0.2))

??? model.add(Dense(500, activation='softmax'))

??? model.summary()

??? # 選擇優(yōu)化器和損失函數(shù)

??? model.compile(optimizer='sgd',

????????????????? loss='sparse_categorical_crossentropy',#categorical_crossentropy,獨(dú)熱編碼才用的交叉熵

????????????????? metrics=['accuracy'])

??? return model

#自定義的模型訓(xùn)練效果繪畫函數(shù)

import matplotlib.pyplot as plt

def show(epochs_range, train_loss, val_loss, train_accuracy, val_accuracy, name):

??? plt.subplot(1, 2, 1)

??? plt.plot(epochs_range, train_loss, label='Training Loss')

??? plt.plot(epochs_range, val_loss, label='Validation Loss')

??? plt.legend(loc='upper right')

??? plt.title('Training and Validation Loss')

??? plt.subplot(1, 2, 2)

??? plt.plot(epochs_range, train_accuracy, label='Training Accuracy')

??? plt.plot(epochs_range, val_accuracy, label='Validation Accuracy')

??? plt.legend(loc='lower right')

??? plt.title('Training and Validation Accuracy')

??? plt.savefig(name)

??? plt.show()

#以下代碼都是讀取數(shù)據(jù)和對模型進(jìn)行訓(xùn)練

from keras.utils.vis_utils import plot_model

model = get_model()? # 選擇模型

epochs = 18? # 選擇批次

# 訓(xùn)練, fit方法自帶shuffle隨機(jī)讀取

history = model.fit(

??? train_image, train_label, batch_size=64,epochs=epochs, validation_data=(val_image, val_label))

# 測試, 單用evaluate方法不會自動輸出數(shù)值,需要手動輸出他返回的兩個數(shù)值

test_scores = model.evaluate(test_image, test_label)

#取出模型的訓(xùn)練結(jié)果值,如準(zhǔn)確率和損失值,用于繪圖

epochs_range = range(1, epochs+1)

train_loss = history.history['loss']

val_loss = history.history['val_loss']

test_loss = test_scores[0]

train_acc = history.history['accuracy']

val_acc = history.history['val_accuracy']

test_acc = test_scores[1]

#使用Python的一個庫,畫出模型的結(jié)構(gòu)圖

plot_model(model, to_file="model11.png",show_shapes=True);

print("model's photo has done!")

# 將模型保存為 HDF5 文件

model.save('./Chinese_recognition_model11.h5')

print("save model: Chinese_recognition_model11.h5")

# 繪制圖表

show(epochs_range, train_loss, val_loss, train_acc, val_acc, 'Model_score_v111')

#? 打印得分

print('')

print('train loss:', train_loss[-1], '?? ', 'train accuracy:', train_acc[-1])

print('val loss:', val_loss[-1], '?? ', 'val accuracy:', val_acc[-1])

print('test loss:', test_loss, '?? ', 'test accuracy:', test_acc)

print('')

CNN_1.ipynb

#加載Google云盤

import os

from google.colab import drive

drive.mount('/content/drive')

# path = "/content/drive/My Drive"

path = "/content/"

os.chdir(path)

os.listdir(path)

#獲取訓(xùn)練數(shù)據(jù)

import os

import cv2

import numpy as np

import matplotlib.image as mi

from sklearn.model_selection import train_test_split

dataset1 = []? # 數(shù)據(jù)集列表

labels1 = []? # 標(biāo)簽列表

label1 = 0? # 第一個標(biāo)簽

def load_data1(filepath):

??? # 遍歷filepath下所有文件,包括子目錄

??? files = os.listdir(filepath)

??? for fi in files:

??????? fi_d = os.path.join(filepath, fi+'/')

??????? if os.path.isdir(fi_d):

??????????? global label1

??????????? load_data1(fi_d)

??????????? label1 += 1

??????? else:

??????????? labels1.append(label1)

??????????? img = mi.imread(fi_d[:-1])

??????????? img2 = cv2.resize(img, (64, 64))? # (64,64,3)

??????????? dataset1.append(img2)

??? # 在訓(xùn)練集中取一部分作為驗證集

??? train_image, val_image, train_label, val_label = train_test_split(

??????? np.array(dataset1), np.array(labels1), random_state=7)

??? return train_image, val_image, train_label, val_label

#獲取測試數(shù)據(jù)

import os

import cv2

import numpy as np

import matplotlib.image as mi

dataset2 = []? # 數(shù)據(jù)集列表

labels2 = []? # 標(biāo)簽列表

label2 = 0? # 第一個標(biāo)簽

def load_data2(filepath):

??? # 遍歷filepath下所有文件,包括子目錄

??? files = os.listdir(filepath)

??? for fi in files:

??????? fi_d = os.path.join(filepath, fi+'/')

??????? if os.path.isdir(fi_d):

??????????? global label2

??????????? load_data2(fi_d)

??????????? label2 += 1

??????? else:

??????????? labels2.append(label2)

??????????? img = mi.imread(fi_d[:-1])

??????????? img2 = cv2.resize(img, (64, 64))? # (64,64,3)

??????????? dataset2.append(img2)

??? return np.array(dataset2), np.array(labels2)

#定義卷積神經(jīng)網(wǎng)絡(luò)架構(gòu)

import tensorflow.keras.backend as k

from tensorflow.keras.models import Sequential

from tensorflow.keras.layers import Dropout, Flatten, Dense

from tensorflow.keras.layers import Conv2D, MaxPooling2D

def get_model():

??? k.clear_session()

??? # 創(chuàng)建一個新模型

??? model = Sequential()

??? model.add(Conv2D(32, (5,5), padding='same', activation='relu', input_shape=(64, 64, 3)))? # 64 64 3

??? model.add(MaxPooling2D(pool_size=(2, 2)))

??? model.add(Conv2D(64, (5,5), padding='same', activation='relu'))

??? model.add(MaxPooling2D(pool_size=(2, 2)))

??? model.add(Conv2D(128, (5,5), padding='same', activation='relu'))

??? model.add(MaxPooling2D(pool_size=(2, 2)))

??? model.add(Conv2D(256, (5,5), padding='same', activation='relu'))

??? model.add(MaxPooling2D(pool_size=(2, 2)))

??? # model.add(Conv2D(512, (3,3), padding='same', activation='relu'))

??? # model.add(MaxPooling2D(pool_size=(2, 2)))

??? model.add(Flatten())

???

??? model.add(Dropout(0.2))

??? model.add(Dense(4096, activation='relu'))

??? model.add(Dropout(0.2))

??? model.add(Dense(500, activation='softmax'))

??? model.summary()

??? # 選擇優(yōu)化器和損失函數(shù)

??? model.compile(optimizer='sgd',

????????????????? loss='sparse_categorical_crossentropy',#categorical_crossentropy,獨(dú)熱編碼才用的交叉熵

????????????????? metrics=['accuracy'])

??? return model

#定義繪圖函數(shù)

import matplotlib.pyplot as plt

def show(epochs_range, train_loss, val_loss, train_accuracy, val_accuracy, name):

??? plt.subplot(1, 2, 1)

??? plt.plot(epochs_range, train_loss, label='Training Loss')

??? plt.plot(epochs_range, val_loss, label='Validation Loss')

??? plt.legend(loc='upper right')

??? plt.title('Training and Validation Loss')

??? plt.subplot(1, 2, 2)

??? plt.plot(epochs_range, train_accuracy, label='Training Accuracy')

??? plt.plot(epochs_range, val_accuracy, label='Validation Accuracy')

??? plt.legend(loc='lower right')

??? plt.title('Training and Validation Accuracy')

??? plt.savefig(name)

??? plt.show()

import tensorflow as tf

tf.compat.v1.disable_eager_execution()

# 加載訓(xùn)練數(shù)據(jù)和測試數(shù)據(jù)

(train_image, val_image, train_label, val_label) = load_data1('train1/')

(test_image, test_label) = load_data2('test1/')

print("數(shù)據(jù)全部加載完畢?。。?-----------------------------------------------------------------------")

#模型訓(xùn)練數(shù)據(jù)

from keras.utils.vis_utils import plot_model

model = get_model()? # 選擇模型

epochs = 18? # 選擇批次

# 訓(xùn)練, fit方法自帶shuffle隨機(jī)讀取

history = model.fit(

??? train_image, train_label, batch_size=64,epochs=epochs, validation_data=(val_image, val_label))

# 測試, 單用evaluate方法不會自動輸出數(shù)值,需要手動輸出他返回的兩個數(shù)值

test_scores = model.evaluate(test_image, test_label)

epochs_range = range(1, epochs+1)

train_loss = history.history['loss']

val_loss = history.history['val_loss']

test_loss = test_scores[0]

train_acc = history.history['accuracy']

val_acc = history.history['val_accuracy']

test_acc = test_scores[1]

plot_model(model, to_file="model11.png",show_shapes=True);

print("model's photo has done!")

# 將模型保存為 HDF5 文件

model.save('./Chinese_recognition_model11.h5')

print("save model: Chinese_recognition_model11.h5")

# 繪制圖表

show(epochs_range, train_loss, val_loss, train_acc, val_acc, 'Model_score_v111')

#? 打印得分

print('')

print('train loss:', train_loss[-1], '?? ', 'train accuracy:', train_acc[-1])

print('val loss:', val_loss[-1], '?? ', 'val accuracy:', val_acc[-1])

print('test loss:', test_loss, '?? ', 'test accuracy:', test_acc)

print('')

CNN_2.ipynb

#!/usr/bin/env python

# coding: utf-8

# In[ ]:

import os

from google.colab import drive

drive.mount('/content/drive')

# path = "/content/drive/My Drive"

path = "/content/"

os.chdir(path)

os.listdir(path)

# In[ ]:

# import shutil

# shutil.rmtree("/content/drive/MyDrive/Chinese/train1")

# In[ ]:

import os

import cv2

import random

from tqdm import tqdm

import matplotlib.pyplot as plt

import matplotlib.image as mi

import numpy as np

from sklearn.model_selection import train_test_split

a=[]

tr_data=[]

dirth='train1/'

for root, dirs, files in os.walk('train1/'):

??? a.append(dirs)

for i in a[0]:

??? path=os.path.join(dirth,i)

??? label=a[0].index(i)+1

??? for j in tqdm(os.listdir(path)):

??????? # try:

????? img=cv2.imread(os.path.join(path,j))

????? img=cv2.resize(img,(64,64))

????? tr_data.append([img,label])

??????? # except Exception as e:

??????? #???? pass

random.shuffle(tr_data)

X_tr=[]

Y_tr=[]

for x,y in tr_data:

??? X_tr.append(x)

??? Y_tr.append(y)

X_tr=np.array(X_tr)

X_tr=X_tr/255.0

Y_tr=np.array(Y_tr)

print("--------------------------------------------------------數(shù)據(jù)讀取完成----------------------------------------------------------------")

# In[ ]:

import os

import cv2

import random

from tqdm import tqdm

import matplotlib.pyplot as plt

import numpy as np

b=[]

te_data=[]

dirth='test1/'

for root, dirs, files in os.walk('test1/'):

??? b.append(dirs)

for i in b[0]:

??? path=os.path.join(dirth,i)

??? label=b[0].index(i)+1

??? for j in tqdm(os.listdir(path)):

??????? try:

??????????? img=cv2.imread(os.path.join(path,j))

??????????? img=cv2.resize(img,(64,64))

??????????? te_data.append([img,label])

??????? except Exception as e:

??????????? pass

random.shuffle(te_data)

X_te=[]

Y_te=[]

for x,y in te_data:

??? X_te.append(x)

??? Y_te.append(y)

X_te=np.array(X_te)

X_te=X_te/255.0

Y_te=np.array(Y_te)

print("--------------------------------------------------------數(shù)據(jù)讀取完成----------------------------------------------------------------")

# In[ ]:

# import tensorflow.keras.backend as k

# from tensorflow.keras.models import Sequential

# from tensorflow.keras.layers import Dropout, Flatten, Dense

# from tensorflow.keras.layers import Conv2D, MaxPooling2D,ZeroPadding2D

# def get_model():

#?? k.clear_session()

#?? # 創(chuàng)建一個新模型

#?? model = Sequential()

#?? # model.add(ZeroPadding2D(1,1),input_shape=(64,64,3))

#?? model.add(Conv2D(64, (3,3), padding='same', activation='relu',input_shape=(64,64,3)))? # 64 64 3

#?? model.add(ZeroPadding2D(1,1))

#?? model.add(Conv2D(64, (3,3), padding='same', activation='relu'))

#?? model.add(ZeroPadding2D(1,1))

#?? model.add(MaxPooling2D(pool_size=(2, 2),strides=(2,2)))

#?? model.add(ZeroPadding2D(1,1))

#?? model.add(Conv2D(128, (3,3), padding='same', activation='relu'))

#?? model.add(ZeroPadding2D(1,1))

#?? model.add(Conv2D(128, (3,3), padding='same', activation='relu'))

#?? model.add(ZeroPadding2D(1,1))

#?? model.add(MaxPooling2D(pool_size=(2, 2),strides=(2,2)))

#?? model.add(ZeroPadding2D(1,1))

#?? model.add(Conv2D(256, (3,3), padding='same', activation='relu'))

#?? model.add(ZeroPadding2D(1,1))

#?? model.add(Conv2D(256, (3,3), padding='same', activation='relu'))

#?? model.add(ZeroPadding2D(1,1))

#?? model.add(Conv2D(256, (3,3), padding='same', activation='relu'))

#?? model.add(MaxPooling2D(pool_size=(2, 2),strides=(2,2)))

#?? model.add(ZeroPadding2D(1,1))

#?? model.add(Conv2D(512, (3,3), padding='same', activation='relu'))

#?? model.add(ZeroPadding2D(1,1))

#?? model.add(Conv2D(512, (3,3), padding='same', activation='relu'))

#?? model.add(ZeroPadding2D(1,1))

#?? model.add(Conv2D(512, (3,3), padding='same', activation='relu'))

#?? model.add(MaxPooling2D(pool_size=(2, 2),strides=(2,2)))

#?? model.add(ZeroPadding2D(1,1))

#?? model.add(Conv2D(512, (3,3), padding='same', activation='relu'))

#?? model.add(ZeroPadding2D(1,1))

#?? model.add(Conv2D(512, (3,3), padding='same', activation='relu'))

#?? model.add(ZeroPadding2D(1,1))

#?? model.add(Conv2D(512, (3,3), padding='same', activation='relu'))

#?? model.add(MaxPooling2D(pool_size=(2, 2),strides=(2,2)))

#?? model.add(Flatten())

#?? # model.add(Dropout(0.2))

#?? model.add(Dense(4096, activation='relu'))

#?? model.add(Dropout(0.5))

#?? model.add(Dense(4096, activation='relu'))

#?? model.add(Dropout(0.5))

#?? model.add(Dense(500, activation='softmax'))

#?? model.summary()

#?? # 選擇優(yōu)化器和損失函數(shù)

#?? model.compile(optimizer='sgd',

#???????????????? loss='sparse_categorical_crossentropy',#categorical_crossentropy,獨(dú)熱編碼才用的交叉熵

#???????????????? metrics=['accuracy'])

#?? return model

# In[ ]:

import tensorflow.keras.backend as k

from tensorflow.keras.models import Sequential

from tensorflow.keras.layers import Dropout, Flatten, Dense

from tensorflow.keras.layers import Conv2D, MaxPooling2D

def get_model():

??? k.clear_session()

??? # 創(chuàng)建一個新模型

??? model = Sequential()

??? model.add(Conv2D(32, (5,5), padding='same', activation='relu', input_shape=(64, 64, 3)))? # 64 64 3

??? model.add(MaxPooling2D(pool_size=(2, 2)))

??? model.add(Conv2D(64, (5,5), padding='same', activation='relu'))

??? model.add(MaxPooling2D(pool_size=(2, 2)))

??? model.add(Conv2D(128, (5,5), padding='same', activation='relu'))

??? model.add(MaxPooling2D(pool_size=(2, 2)))

??? model.add(Conv2D(256, (5,5), padding='same', activation='relu'))

??? model.add(MaxPooling2D(pool_size=(2, 2)))

??? model.add(Flatten())

???

??? model.add(Dropout(0.2))

??? model.add(Dense(4096, activation='relu'))

??? model.add(Dropout(0.2))

??? model.add(Dense(500,activation='softmax'))

??? model.summary()

??? # 選擇優(yōu)化器和損失函數(shù)

??? model.compile(optimizer='sgd',

????????????????? loss='sparse_categorical_crossentropy',#categorical_crossentropy,獨(dú)熱編碼才用的交叉熵

????????????????? metrics=['accuracy'])

# tf.optimizers.SGD(learning_rate=0.01)

??? return model

# In[ ]:

import matplotlib.pyplot as plt

def show(epochs_range, train_loss, val_loss, train_accuracy, val_accuracy, name):

??? plt.subplot(1, 2, 1)

??? plt.plot(epochs_range, train_loss, label='Training Loss')

??? plt.plot(epochs_range, val_loss, label='Validation Loss')

??? plt.legend(loc='upper right')

??? plt.title('Training and Validation Loss')

??? plt.subplot(1, 2, 2)

??? plt.plot(epochs_range, train_accuracy, label='Training Accuracy')

??? plt.plot(epochs_range, val_accuracy, label='Validation Accuracy')

??? plt.legend(loc='lower right')

??? plt.title('Training and Validation Accuracy')

??? plt.savefig(name)

??? plt.show()

# In[ ]:

from keras.utils.vis_utils import plot_model

import tensorflow as tf

tf.compat.v1.disable_eager_execution()

model=get_model()? # 選擇模型

epochs = 10? # 選擇批次

# 訓(xùn)練, fit方法自帶shuffle隨機(jī)讀取

history = model.fit(

??? X_tr,Y_tr, batch_size=64,epochs=epochs,validation_split=0.3)

# 測試, 單用evaluate方法不會自動輸出數(shù)值,需要手動輸出他返回的兩個數(shù)值

test_scores = model.evaluate(X_te,Y_te)

epochs_range = range(1, epochs+1)

train_loss = history.history['loss']

val_loss = history.history['val_loss']

test_loss = test_scores[0]

train_acc = history.history['accuracy']

val_acc = history.history['val_accuracy']

test_acc = test_scores[1]

plot_model(model, to_file="model_1.png",show_shapes=True);

print("model's photo has done!")

# 將模型保存為 HDF5 文件

model.save('./Chinese_recognition_model_1.h5')

print("save model: Chinese_recognition_model_1.h5")

# 繪制圖表

show(epochs_range, train_loss, val_loss, train_acc, val_acc, 'Model_score_v1_1')

#? 打印得分

print('')

print('train loss:', train_loss[-1], '?? ', 'train accuracy:', train_acc[-1])

print('val loss:', val_loss[-1], '?? ', 'val accuracy:', val_acc[-1])

print('test loss:', test_loss, '?? ', 'test accuracy:', test_acc)

print('')

# In[ ]:

# 拷貝文件到 /content

import shutil

shutil.copyfile('/content/drive/MyDrive/Chinese/test1.zip','/content/test1.zip')

# In[ ]:

# 解壓縮文件

import zipfile

file_dir = '/content/test1.zip'? # 你的壓縮包路徑

zipFile = zipfile.ZipFile(file_dir)

for file in zipFile.namelist():

??? zipFile.extract(file, '/content/')? # 解壓路徑

zipFile.close()

# In[ ]:

import tensorflow as tf

from tensorflow.python.client import device_lib

print(device_lib.list_local_devices())

Machine learning.ipynb

import os

from google.colab import drive

drive.mount('/content/drive')

# path = "/content/drive/My Drive"

path = "/content/"

os.chdir(path)

os.listdir(path)

from google.colab import drive

drive.mount('/content/drive')

import os

import cv2

import numpy as np

import matplotlib.image as mi

from sklearn.model_selection import train_test_split

dataset1 = []? # 數(shù)據(jù)集列表

labels1 = []? # 標(biāo)簽列表

label1 = 0? # 第一個標(biāo)簽

def load_data1(filepath):

??? # 遍歷filepath下所有文件,包括子目錄

??? files = os.listdir(filepath)

??? for fi in files:

??????? fi_d = os.path.join(filepath, fi+'/')

??????? if os.path.isdir(fi_d):

??????????? global label1

??????????? load_data1(fi_d)

??????????? label1 += 1

??????? else:

??????????? labels1.append(label1)

??????????? img = mi.imread(fi_d[:-1])

??????????? img2 = cv2.resize(img, (64, 64))? # (64,64,3)

??????????? img2 = img2.reshape(-1,)

??????????? dataset1.append(img2)

??? # 在訓(xùn)練集中取一部分作為驗證集

??? train_image, val_image, train_label, val_label = train_test_split(

??????? np.array(dataset1), np.array(labels1), random_state=7)

??? return train_image, val_image, train_label, val_label

import os

import cv2

import numpy as np

import matplotlib.image as mi

dataset2 = []? # 數(shù)據(jù)集列表

labels2 = []? # 標(biāo)簽列表

label2 = 0? # 第一個標(biāo)簽

def load_data2(filepath):

??? # 遍歷filepath下所有文件,包括子目錄

??? files = os.listdir(filepath)

??? for fi in files:

??????? fi_d = os.path.join(filepath, fi+'/')

??????? if os.path.isdir(fi_d):

??????????? global label2

??????????? load_data2(fi_d)

??????????? label2 += 1

??????? else:

??????????? labels2.append(label2)

??????????? img = mi.imread(fi_d[:-1])

??????????? img2 = cv2.resize(img, (64, 64))? # (64,64,3)

??????????? img2 = img2.reshape(-1,)

??????????? dataset2.append(img2)

??? return np.array(dataset2), np.array(labels2)

# 加載訓(xùn)練數(shù)據(jù)和測試數(shù)據(jù)

(train_image, val_image, train_label, val_label) = load_data1('train2/')

(test_image, test_label) = load_data2('test2/')

print("數(shù)據(jù)全部加載完畢!?。?-----------------------------------------------------------------------")

#KNN模型的訓(xùn)練和預(yù)測

# 導(dǎo)入第三方模塊

from sklearn import metrics

from sklearn import neighbors

knn_class = neighbors.KNeighborsClassifier(n_neighbors = 8, weights = 'uniform')

# 模型擬合

knn_class.fit(train_image,train_label)

predict1 = knn_class.predict(train_image)

predict2 = knn_class.predict(val_image)

print('模型的訓(xùn)練集準(zhǔn)確率為:\n',metrics.accuracy_score(train_label, predict1))

print('模型的驗證集準(zhǔn)確率為:\n',metrics.accuracy_score(val_label, predict2))

#決策是模型的訓(xùn)練和預(yù)測

# 導(dǎo)入第三方模塊

from sklearn import metrics

from sklearn import tree

# 構(gòu)建分類決策樹

CART_Class = tree.DecisionTreeClassifier(max_depth=6, min_samples_leaf = 4, min_samples_split=6)

CART_Class.fit(train_image,train_label)

predict1 = CART_Class.predict(train_image)

predict2 = CART_Class.predict(val_image)

print('模型的訓(xùn)練集準(zhǔn)確率為:\n',metrics.accuracy_score(train_label, predict1))

print('模型的驗證集準(zhǔn)確率為:\n',metrics.accuracy_score(val_label, predict2))

#非線性的SVM模型訓(xùn)練和預(yù)測

from sklearn import model_selection

from sklearn import svm

# 選擇非線性SVM模型,徑向基核函數(shù)

nolinear_svc = svm.SVC(C=1.0,kernel='rbf')

nolinear_svc.fit(train_image,train_label)

predict1 = nolinear_svc.predict(train_image)

predict2 = nolinear_svc.predict(val_image)

print('模型的訓(xùn)練集準(zhǔn)確率為:\n',metrics.accuracy_score(train_label, predict1))

print('模型的驗證集準(zhǔn)確率為:\n',metrics.accuracy_score(val_label, predict2))

# 選擇非線性SVM模型,多項式核函數(shù)

nolinear_svc = svm.SVC(C=1.0,kernel='poly',degree=2)

# 模型在訓(xùn)練數(shù)據(jù)集上的擬合

nolinear_svc.fit(train_image,train_label)

predict1 = nolinear_svc.predict(train_image)

predict2 = nolinear_svc.predict(val_image)

print('模型的訓(xùn)練集準(zhǔn)確率為:\n',metrics.accuracy_score(train_label, predict1))

print('模型的驗證集準(zhǔn)確率為:\n',metrics.accuracy_score(val_label, predict2))

ImageChange.ipynb

#!/usr/bin/env python

# coding: utf-8

# In[1]:

import os

import numpy as np

import struct

from PIL import Image

data_dir = '/Users/apple/'

train_data_dir = os.path.join(data_dir, 'HWDB1.1trn_gnt')

test_data_dir = os.path.join(data_dir, 'HWDB1.1tst_gnt')

def read_from_gnt_dir(gnt_dir=train_data_dir):

??? def one_file(f):

??????? header_size = 10

??????? while True:

??????????? header = np.fromfile(f, dtype='uint8', count=header_size)

??????????? if not header.size: break

??????????? sample_size = header[0] + (header[1]<<8) + (header[2]<<16) + (header[3]<<24)

??????????? tagcode = header[5] + (header[4]<<8)

??????????? width = header[6] + (header[7]<<8)

??????????? height = header[8] + (header[9]<<8)

??????????? if header_size + width*height != sample_size:

??????????????? break

??????????? try:

??????????????? image = np.fromfile(f, dtype='uint8', count=width*height).reshape((height, width))

??????????? except:

??????????????? print(struct.pack('>H', tagcode).decode('gb2312'))

??????????? #print(image, tagcode)

??????????? #image = image.reshape()

??????????? yield image, tagcode

??? for file_name in os.listdir(gnt_dir):

??????? if file_name.endswith('.gnt'):

??????????? file_path = os.path.join(gnt_dir, file_name)

??????????? with open(file_path, 'rb') as f:

??????????????? for image, tagcode in one_file(f):

??????????????????? yield image, tagcode

char_set = set()

for _, tagcode in read_from_gnt_dir(gnt_dir=train_data_dir):

??? tagcode_unicode = struct.pack('>H', tagcode).decode('gb2312')

??? char_set.add(tagcode_unicode)

#save char list

char_list = list(char_set)

char_dict = dict(zip(sorted(char_list), range(len(char_list))))

print("總共有",len(char_dict),"個漢字")

# In[2]:

import pickle

f = open('char_dict', 'wb')

pickle.dump(char_dict, f)

f.close()

train_counter = 0

test_counter = 0

print('-----開始提取訓(xùn)練數(shù)據(jù)-----')

for image, tagcode in read_from_gnt_dir(gnt_dir=train_data_dir):

??? tagcode_unicode = struct.pack('>H', tagcode).decode('gb2312')

??? im = Image.fromarray(image)

??? dir_name = './data/train/' + '%0.5d'%char_dict[tagcode_unicode]

??? if not os.path.exists(dir_name):

??????? os.makedirs(dir_name)

??? im.convert('RGB').save(dir_name+'/' + str(train_counter) + '.png')

??? train_counter += 1

print("一共",int(train_counter),"張漢字圖片")

print('-----開始提取測試數(shù)據(jù)-----')

for image, tagcode in read_from_gnt_dir(gnt_dir=test_data_dir):

??? tagcode_unicode = struct.pack('>H', tagcode).decode('gb2312')

??? im = Image.fromarray(image)

??? dir_name = './data/test/' + '%0.5d'%char_dict[tagcode_unicode]

??? if not os.path.exists(dir_name):

??????? os.makedirs(dir_name)

??? im.convert('RGB').save(dir_name+'/' + str(test_counter) + '.png')

??? test_counter += 1

print("一共",int(test_counter),"張漢字圖片")

# In[3]:

#讀取lable,即漢字和對應(yīng)編碼的dict

import pickle

f = open('char_dict','br')

dict = pickle.load(f)

print(dict)

GuiMain.ipynb

#!/usr/bin/env python

# coding: utf-8

# In[1]:

from PyQt5.QtWidgets import QWidget

from PyQt5.Qt import QPixmap, QPainter, QPoint, QPaintEvent, QMouseEvent, QPen, QColor, QSize

from PyQt5.QtCore import Qt

import cv2

import numpy as np

from PyQt5.QtGui import QPixmap,QImage,QColor

from PIL import Image

#畫板類

class PaintBoard(QWidget):

??? def __init__(self, Parent=None):

??????? super().__init__(Parent)

??????? self.__InitData() #先初始化數(shù)據(jù),再初始化界面

??????? self.__InitView()

??? def __InitData(self):

???????

??????? #self.__size = QSize(480,460)

??????? self.__size = QSize(240,240)? #畫板大小

???????

??????? #新建QPixmap作為畫板,尺寸為__size

??????? self.__board = QPixmap(self.__size)

??????? self.__board.fill(Qt.white) #用白色填充畫板

???????

??????? self.__IsEmpty = True #默認(rèn)為空畫板

??????? self.EraserMode = False #默認(rèn)為禁用橡皮擦模式

???????

??????? self.__lastPos = QPoint(0,0)#上一次鼠標(biāo)位置

??????? self.__currentPos = QPoint(0,0)#當(dāng)前的鼠標(biāo)位置

???????

??????? self.__painter = QPainter()#新建繪圖工具

???????

??????? self.__thickness = 8?????? #默認(rèn)畫筆粗細(xì)為8px

??????? self.__penColor = QColor("black")#設(shè)置默認(rèn)畫筆顏色為黑色

??????? self.__colorList = QColor.colorNames() #獲取顏色列表

??? def __InitView(self):

??????? #設(shè)置界面的尺寸為__size

??????? self.setFixedSize(self.__size)

??? def Clear(self):

??????? #清空畫板

??????? self.__board.fill(Qt.white)

??????? self.update()

??????? self.__IsEmpty = True

???????

??? def ChangePenColor(self, color="black"):

??????? #改變畫筆顏色

??????? self.__penColor = QColor(color)

???????

??? def ChangePenThickness(self, thickness=8):

??????? #改變畫筆粗細(xì)

??????? self.__thickness = thickness

???????

??? def IsEmpty(self):

??????? #返回畫板是否為空

??????? return self.__IsEmpty

???

??? def GetContentAsQImage(self):

??????? #獲取畫板內(nèi)容(返回QImage)

??????? image = self.__board.toImage()

???????

??????? return image

???????

??? def paintEvent(self, paintEvent):

??????? #繪圖事件

??????? #繪圖時必須使用QPainter的實例,此處為__painter

??????? #繪圖在begin()函數(shù)與end()函數(shù)間進(jìn)行

??????? #begin(param)的參數(shù)要指定繪圖設(shè)備,即把圖畫在哪里

??????? #drawPixmap用于繪制QPixmap類型的對象

??????? self.__painter.begin(self)

??????? # 0,0為繪圖的左上角起點(diǎn)的坐標(biāo),__board即要繪制的圖

??????? self.__painter.drawPixmap(0,0,self.__board)

??????? self.__painter.end()

???????

??? def mousePressEvent(self, mouseEvent):

??????? #鼠標(biāo)按下時,獲取鼠標(biāo)的當(dāng)前位置保存為上一次位置

??????? self.__currentPos =? mouseEvent.pos()

??????? self.__lastPos = self.__currentPos

???????

???????

??? def mouseMoveEvent(self, mouseEvent):

??????? #鼠標(biāo)移動時,更新當(dāng)前位置,并在上一個位置和當(dāng)前位置間畫線

??????? self.__currentPos =? mouseEvent.pos()

??????? self.__painter.begin(self.__board)

???????

??????? if self.EraserMode == False:

??????????? #非橡皮擦模式

??????????? self.__painter.setPen(QPen(self.__penColor,self.__thickness)) #設(shè)置畫筆顏色,粗細(xì)

??????? else:

??????????? #橡皮擦模式下畫筆為純白色,粗細(xì)為10

??????????? self.__painter.setPen(QPen(Qt.white,15))

???????????

??????? #畫線???

??????? self.__painter.drawLine(self.__lastPos, self.__currentPos)

??????? self.__painter.end()

??????? self.__lastPos = self.__currentPos

???????????????

??????? self.update() #更新顯示

???????

??? def mouseReleaseEvent(self, mouseEvent):

??????? self.__IsEmpty = False #畫板不再為空

???????

???????

# In[2]:

from PyQt5.Qt import QWidget, QColor, QPixmap, QIcon, QSize, QCheckBox

from PyQt5.QtWidgets import QHBoxLayout, QVBoxLayout, QPushButton, QSplitter,??? QComboBox, QLabel, QSpinBox, QFileDialog

import cv2

import matplotlib.image as mpimg

import tensorflow as tf

import numpy as np

try:

??? import tensorflow.python.keras as keras

except:

??? import tensorflow.keras as keras

???

class MainWidget(QWidget):

??? def __init__(self, Parent=None):

??????? '''

??????? Constructor

??????? '''

??????? super().__init__(Parent)

???????

??????? self.__InitData() #先初始化數(shù)據(jù),再初始化界面

??????? self.__InitView()

???

??? def __InitData(self):

??????? '''

????????????????? 初始化成員變量

??????? '''

??????? self.__paintBoard = PaintBoard(self)

??????? #self.__picture = Picture(self)

??????? #獲取顏色列表(字符串類型)

??????? self.__colorList = QColor.colorNames()

???????

???????

??? def __InitView(self):

??????? '''

????????????????? 初始化界面

??????? '''

??????? self.setFixedSize(600,330)

??????? self.setWindowTitle("手寫漢字識別")

??

??????? #新建一個水平布局作為本窗體的主布局

??????? main_layout = QHBoxLayout(self)

??????? #設(shè)置主布局內(nèi)邊距以及控件間距為10px

??????? main_layout.setSpacing(10)

???

??????? #在主界面左側(cè)放置畫板

??????? main_layout.addWidget(self.__paintBoard)

???????

??????? #新建垂直子布局用于放置按鍵

??????? sub_layout = QVBoxLayout()

???????

??????? #設(shè)置此子布局和內(nèi)部控件的間距為5px

??????? sub_layout.setContentsMargins(10, 10, 10, 10)

???????

??????? splitter = QSplitter(self) #占位符

??????? sub_layout.addWidget(splitter)

??????? self.__btn_Recognize = QPushButton("開始識別")

??????? self.__btn_Recognize.setParent(self)

??????? self.__btn_Recognize.clicked.connect(self.on_btn_Recognize_Clicked)

??????? sub_layout.addWidget(self.__btn_Recognize)

???????

??????? self.__btn_Clear = QPushButton("清空畫板")

??????? self.__btn_Clear.setParent(self) #設(shè)置父對象為本界面

??????

??????? #將按鍵按下信號與畫板清空函數(shù)相關(guān)聯(lián)

??????? self.__btn_Clear.clicked.connect(self.__paintBoard.Clear)

??????? sub_layout.addWidget(self.__btn_Clear)

???????

??????? self.__btn_Quit = QPushButton("退出")

??????? self.__btn_Quit.setParent(self) #設(shè)置父對象為本界面

??????? self.__btn_Quit.clicked.connect(self.Quit)

??????? sub_layout.addWidget(self.__btn_Quit)

???????

??????? self.__btn_Save = QPushButton("保存")

??????? self.__btn_Save.setParent(self)

??????? self.__btn_Save.clicked.connect(self.on_btn_Save_Clicked)

??????? sub_layout.addWidget(self.__btn_Save)

???????

??????? self.__cbtn_Eraser = QCheckBox("橡皮擦")

??????? self.__cbtn_Eraser.setParent(self)

??????? self.__cbtn_Eraser.clicked.connect(self.on_cbtn_Eraser_clicked)

??????? sub_layout.addWidget(self.__cbtn_Eraser)

???????

???????

??????? self.__label_penThickness = QLabel(self)

??????? self.__label_penThickness.setText("畫筆粗細(xì)")

??????? self.__label_penThickness.setFixedHeight(20)

??????? sub_layout.addWidget(self.__label_penThickness)

???????

??????? self.__spinBox_penThickness = QSpinBox(self)

??????? self.__spinBox_penThickness.setMaximum(20)

??????? self.__spinBox_penThickness.setMinimum(2)

??????? self.__spinBox_penThickness.setValue(8) #默認(rèn)粗細(xì)為4

??????? self.__spinBox_penThickness.setSingleStep(2) #最小變化值為2

??????? self.__spinBox_penThickness.valueChanged.connect(self.on_PenThicknessChange)#關(guān)聯(lián)spinBox值變化信號和函數(shù)on_PenThicknessChange

??????? sub_layout.addWidget(self.__spinBox_penThickness)

???????

??????? self.__label_penColor = QLabel(self)

??????? self.__label_penColor.setText("畫筆顏色")

??????? self.__label_penColor.setFixedHeight(20)

??????? sub_layout.addWidget(self.__label_penColor)

???????

??????? self.__comboBox_penColor = QComboBox(self)

??????? self.__fillColorList(self.__comboBox_penColor) #用各種顏色填充下拉列表

??????? self.__comboBox_penColor.currentIndexChanged.connect(self.on_PenColorChange) #關(guān)聯(lián)下拉列表的當(dāng)前索引變更信號與函數(shù)on_PenColorChange

??????? sub_layout.addWidget(self.__comboBox_penColor)

??????? main_layout.addLayout(sub_layout) #將子布局加入主布局

??? def __fillColorList(self, comboBox):

??????? index_black = 0

??????? index = 0

??????? for color in self.__colorList:

??????????? if color == "black":

??????????????? index_black = index

??????????? index += 1

??????????? pix = QPixmap(70,20)

??????????? pix.fill(QColor(color))

??????????? comboBox.addItem(QIcon(pix),None)

??????????? comboBox.setIconSize(QSize(70,20))

??????????? comboBox.setSizeAdjustPolicy(QComboBox.AdjustToContents)

??????? comboBox.setCurrentIndex(index_black)

???????

???????

??? #畫筆顏色???

??? def on_PenColorChange(self):

??????? color_index = self.__comboBox_penColor.currentIndex()

??????? color_str = self.__colorList[color_index]

??????? self.__paintBoard.ChangePenColor(color_str)

???

??? #畫筆粗細(xì)

??? def on_PenThicknessChange(self):

??????? penThickness = self.__spinBox_penThickness.value()

??????? self.__paintBoard.ChangePenThickness(penThickness)

???

??? #圖片儲存

??? def on_btn_Save_Clicked(self):

??????? savePath = QFileDialog.getSaveFileName(self, 'Save Your Paint', '.\\', '*.png')

??????? print(savePath)

??????? if savePath[0] == "":

??????????? print("Save cancel")

??????????? return

??????? image = self.__paintBoard.GetContentAsQImage()

??????? image.save(savePath[0])

??????? print(savePath[0])

???

??? #橡皮擦

??? def on_cbtn_Eraser_clicked(self):

??????? if self.__cbtn_Eraser.isChecked():

??????????? self.__paintBoard.EraserMode = True #進(jìn)入橡皮擦模式

??????? else:

??????????? self.__paintBoard.EraserMode = False #退出橡皮擦模式

???

??? #識別預(yù)測

??? def on_btn_Recognize_Clicked(self):

???????

??????? image = self.__paintBoard.GetContentAsQImage()

??????? savePath = "/Users/apple/text.png"

??????? image.save(savePath,"PNG",100)

??????? img = mpimg.imread('/Users/apple/text.png')

??????? img2 = cv2.resize(img, (64, 64))

??????? img3 = np.zeros((1, img2.shape[0], img2.shape[1], img2.shape[2]))? # (1, 64, 64, 3)

??????? img3[0, :] = img2

??????? model = tf.keras.models.load_model('/Users/apple/Chinese_recognition_model11.h5')

??????? #pre = model.predict(img3)

??????? pre = model(img3)

???????

??????? predicted_label1 = np.argmax(pre[0])

??????? class_names = ['臥', '典',?? '俄',?? '畝',?? '刺',?? '舉',?? '卑', ?'佬',? '儒',? '五',? '勤',?

??????????????????? '仆',?? '吃',?? '半',?? '侄',?? '伯',?? '冒',?? '劈',? '仗',? '司',? '亨',

??????????????????? '住',?? '中',?? '俏',?? '協(xié)',?? '廁',?? '化',?? '具',? '書',? '單',? '兼',???

??????????????????? '鑿',?? '倍',?? '依',?? '伏',?? '剩',?? '凱',?? '丸',? '變',? '親',? '亢',???

??????????????????? '刃',?? '加',?? '憑',?? '右',?? '嚴(yán)',?? '凌',?? '冬',? '偽',? '偵',? '傭',???

??????????????????? '蘭',?? '乒',?? '冷',?? '上',?? '黨',?? '兆',?? '副',? '侗',? '冠',? '免',???

??????????????????? '充',?? '剁',?? '召',?? '凍',?? '判',?? '個',?? '叁',? '允',? '俘',? '事',???

??????????????????? '卻',?? '卓',?? '井',?? '削',?? '兇',?? '豐',?? '與',? '發(fā)',? '傷',? '使',???

??????????????????? '凄',?? '付',?? '勻',?? '壓',?? '則',?? '僅',?? '亞',? '虧',? '低',? '今',???

??????????????????? '匈',?? '偶',?? '業(yè)',?? '偷',?? '伎',?? '寫',?? '危',? '你',? '仕',? '券',???

??????????????????? '丘',?? '人',?? '只',?? '動',?? '丟',?? '卸',?? '募',? '涼',? '傈',? '九',???

??????????????????? '傀',?? '歷',?? '伙',?? '于',?? '側(cè)',?? '倪',?? '勉',? '利',? '眾',? '衛(wèi)',???

??????????????????? '倒',?? '臺',?? '份',?? '興',?? '厄',?? '冕',?? '介',? '卞',? '便',? '亭',???

??????????????????? '健',?? '冊',?? '佐',?? '刑',?? '佩',?? '俯',?? '倉',? '亥',? '交',? '三',???

??????????????????? '卯',?? '受',?? '劣',?? '之',?? '傅',?? '兵',?? '再',? '儲',? '價',? '侖',???

??????????????????? '傻',?? '兜',?? '也',?? '凈',?? '倘',?? '丙',?? '為',? '催',? '借',? '關(guān)',??

??????????????????? '嗎',?? '號',?? '華',?? '侯',?? '刨',?? '且',?? '似',? '保',? '促',? '主',???

??????????????????? '馮',?? '仔',?? '乓',?? '匪',?? '廠',?? '刁',?? '鹵',? '凰',? '即',? '疊',

??????????????????? '各',?? '取',?? '助',?? '另',?? '勾',?? '印',?? '又',? '專',? '傘',? '減',

??????????????????? '絲',?? '二',?? '去',?? '全',?? '僵',?? '僚',?? '匣',? '決',? '侶',? '修',

??????????????????? '厲',?? '佛',?? '乞',?? '冗',?? '下',?? '億',?? '俐',? '乖',? '串',? '冶',

??????????????????? '凳',?? '刮',?? '辦',?? '匝',?? '體',?? '優(yōu)',?? '合',? '葉',? '僻',? '勛',

??????????????????? '佃',?? '值',?? '倡',?? '乾',?? '凡',?? '匆',?? '東',? '一',? '鄉(xiāng)',? '列',

??????????????????? '產(chǎn)',?? '余',?? '叭',?? '傳',?? '偏',?? '兄',?? '剔',? '習(xí)',? '么',? '湊',

??????????????????? '嚇',?? '勵',?? '茲',?? '丑',?? '劇',?? '醫(yī)',?? '出',? '佑',? '償',? '克',

??????????????????? '力',?? '俠',?? '名',?? '軍',?? '古',?? '冕',?? '剛',? '叔',? '萬',? '冉',

??????????????????? '京',?? '任',?? '部',?? '卵',?? '義',?? '劫',?? '卉',? '兌',? '勁',? '及',

??????????????????? '會',?? '伍',?? '企',?? '乘',?? '買',?? '包',?? '仰',? '原',? '獸',? '區(qū)',

??????????????????? '侈',?? '別',?? '分',?? '刊',?? '麗',?? '儡',?? '僥',? '八',? '別',? '佰',

??????????????????? '擊',?? '云',?? '倔',?? '卡',?? '兢',?? '敘',?? '丫',? '叉',? '叛',? '刻',

??????????????????? '呂',?? '后',?? '向',?? '什',?? '喪',?? '吏',?? '互',? '伐',? '爭',? '丁',

??????????????????? '剪',?? '升',?? '剿',?? '何',?? '劍',?? '仟',?? '厚',? '傣',? '傍',? '反',

??????????????????? '初',?? '其',?? '像',?? '卜',?? '光',?? '千',?? '令',? '乏',? '久',? '廚',

??????????????????? '伴',?? '停',?? '叢',?? '匡',?? '侵',?? '農(nóng)',?? '休',? '可',? '俗',? '卒',

??????????????????? '丈',?? '吁',?? '亂',?? '仲',?? '佳',?? '南',?? '樂',? '臨',? '劃',? '仇',

??????????????????? '做',?? '伊',?? '雙',?? '厘',?? '凸',?? '勇',?? '喬',? '幾',? '六',? '佯',

??????????????????? '勢',?? '丹',?? '代',?? '冰',?? '凜',?? '伶',?? '僑',? '劑',? '位',? '匠',

??????????????????? '僧',?? '兩',?? '倚',?? '他',?? '嘆',?? '匿',?? '創(chuàng)',? '切',? '僳',? '賣',

??????????????????? '乃',?? '勿',?? '件',?? '勃',?? '刪',?? '偉',?? '刷',? '伸',? '盧',? '函',

??????????????????? '劊',?? '卿',?? '厭',?? '候',?? '廈',?? '匹',?? '準(zhǔn)',? '亡',? '仁',? '仿',

??????????????????? '凹',?? '剎',?? '但',?? '侮',?? '例',?? '北',?? '凋',? '世',? '參',? '勘',

??????????????????? '同',?? '勒',?? '倆',?? '兔',?? '叫',?? '倫',?? '俺',? '廂',? '乎',? '債',

??????????????????? '匙',?? '叨',?? '卷',?? '儉',?? '割',?? '侍',?? '勸',? '公',? '養(yǎng)',? '吐',

??????????????????? '從',?? '友',?? '剃',?? '們',?? '勞',?? '口',?? '凝',? '乍',? '乳',? '供',

??????????????????? '沖',?? '了',?? '冀',?? '伺',?? '烏',?? '廄',?? '內(nèi)',? '劉',? '不',? '到',

??????????????????? '況',?? '岡',?? '吉',?? '儈',?? '些',?? '假',?? '入',? '努',? '亦',? '享',

??????????????????? '仍',?? '剝',?? '信',?? '倶',?? '先',?? '縣',?? '制',? '元',? '七',? '儀',

??????????????????? '亮',?? '俊',?? '作',?? '乙',?? '傾',?? '占',?? '前',? '吊',? '史',? '句',

??????????????????? '功',?? '俞',?? '十',?? '鳳',?? '估',?? '午',?? '傲',? '勺',? '以',? '仙',

??????????????????? '共',?? '博',?? '予',?? '倦',?? '務(wù)',?? '廳',?? '兒',? '叮',? '刀']

???????

??????? print("識別結(jié)果:",class_names[predicted_label1],"\n可能概率:",1*np.max(pre[0]),"\n")

???

??? #關(guān)閉

??? def Quit(self):

??????? self.close()

???????

???????

???????

# In[3]:

#from MainWidget import MainWidget

from PyQt5.QtWidgets import QApplication

import sys

def main():

??? app = QApplication(sys.argv)

???

??? mainWidget = MainWidget() #新建一個主界面

??? mainWidget.show()??? #顯示主界面

???

??? exit(app.exec_()) #進(jìn)入消息循環(huán)

???

???

if __name__ == '__main__':

??? main()文章來源地址http://www.zghlxwxcb.cn/news/detail-828999.html

到了這里,關(guān)于人工智能課程設(shè)計畢業(yè)設(shè)計——基于機(jī)器學(xué)習(xí)的手寫漢字識別系統(tǒng)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點(diǎn)擊違法舉報進(jìn)行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包