『壹』 uvos任務經典數據集有哪些
1、MNIST:一個手寫數字分類數據集,包含訓練集旅槐孫和測試集,每個數據樣本由圖像數據和標簽構成。
2、IMDB:一個電影評論分類數據集,可以用來訓練文本分類器拆鏈。
3、CIFAR-10:一個圖像分類數據集,共有10個類別,每個類別包含6000張32*32像素的彩色圖像。
4、KITTI:一個自動駕駛數據集,包含高清圖像和3D點雲數據。
5、SQuAD:一個自然語言問答數據集,用於訓練自然語言處明肆理系統。
『貳』 什麼是深度學習與機器視覺
深度學習框架,尤其是基於人工神經網路的框架可以追溯到1980年福島邦彥提出的新認知機[2],而人工神經網路的歷史更為久遠。1989年,燕樂存(Yann LeCun)等人開始將1974年提出的標准反向傳播演算法[3]應用於深度神經網路,這一網路被用於手寫郵政編碼識別。盡管演算法可以成功執行,但計算代價非常巨大,神經網路的訓練時間達到了3天,因而無法投入實際使用[4]。許多因素導致了這一緩慢的訓練過程,其中一種是由於爾根·施密德胡伯(Jürgen Schmidhuber)的學生賽普·霍克賴特(Sepp Hochreiter)於1991年提出的梯度消失問題[5][6]。與此同時,神經網路也受到了其他更加簡單模型的挑戰,支持向量機等模型在20世紀90年代到21世紀初成為更加流行的機器學習演算法。
「深度學習」這一概念從2007年前後開始受到關注。當時,傑弗里·辛頓(Geoffrey Hinton)和魯斯蘭·薩拉赫丁諾夫(Ruslan Salakhutdinov)提出了一種在前饋神經網路中進行有效訓練的演算法。這一演算法將網路中的每一層視為無監督的受限玻爾茲曼機,再使用有監督的反向傳播演算法進行調優[7]。在此之前的1992年,在更為普遍的情形下,施密德胡伯也曾在遞歸神經網路上提出一種類似的訓練方法,並在實驗中證明這一訓練方法能夠有效提高有監督學習的執行速度[8][9].
自深度學習出現以來,它已成為很多領域,尤其是在計算機視覺和語音識別中,成為各種領先系統的一部分。在通用的用於檢驗的數據集,例如語音識別中的TIMIT和圖像識別中的ImageNet, Cifar10上的實驗證明,深度學習能夠提高識別的精度。
硬體的進步也是深度學習重新獲得關注的重要因素。高性能圖形處理器的出現極大地提高了數值和矩陣運算的速度,使得機器學習演算法的運行時間得到了顯著的縮短[10][11]。
基本概念[編輯]
深度學習的基礎是機器學習中的分散表示(distributed representation)。分散表示假定觀測值是由不同因子相互作用生成。在此基礎上,深度學習進一步假定這一相互作用的過程可分為多個層次,代表對觀測值的多層抽象。不同的層數和層的規模可用於不同程度的抽象[1]。
深度學習運用了這分層次抽象的思想,更高層次的概念從低層次的概念學習得到。這一分層結構常常使用貪婪演算法逐層構建而成,並從中選取有助於機器學習的更有效的特徵[1].
不少深度學習演算法都以無監督學習的形式出現,因而這些演算法能被應用於其他演算法無法企及的無標簽數據,這一類數據比有標簽數據更豐富,也更容易獲得。這一點也為深度學習贏得了重要的優勢[1]。
人工神經網路下的深度學習[編輯]
一部分最成功的深度學習方法涉及到對人工神經網路的運用。人工神經網路受到了1959年由諾貝爾獎得主大衛·休伯爾(David H. Hubel)和托斯坦·威澤爾(Torsten Wiesel)提出的理論啟發。休伯爾和威澤爾發現,在大腦的初級視覺皮層中存在兩種細胞:簡單細胞和復雜細胞,這兩種細胞承擔不同層次的視覺感知功能。受此啟發,許多神經網路模型也被設計為不同節點之間的分層模型[12]。
福島邦彥提出的新認知機引入了使用無監督學習訓練的卷積神經網路。燕樂存將有監督的反向傳播演算法應用於這一架構[13]。事實上,從反向傳播演算法自20世紀70年代提出以來,不少研究者都曾試圖將其應用於訓練有監督的深度神經網路,但最初的嘗試大都失敗。賽普·霍克賴特(Sepp Hochreiter)在其博士論文中將失敗的原因歸結為梯度消失,這一現象同時在深度前饋神經網路和遞歸神經網路中出現,後者的訓練過程類似深度網路。在分層訓練的過程中,本應用於修正模型參數的誤差隨著層數的增加指數遞減,這導致了模型訓練的效率低下[14][15]。
為了解決這一問題,研究者們提出了一些不同的方法。於爾根·施密德胡伯(Jürgen Schmidhuber)於1992年提出多層級網路,利用無監督學習訓練深度神經網路的每一層,再使用反向傳播演算法進行調優。在這一模型中,神經網路中的每一層都代表觀測變數的一種壓縮表示,這一表示也被傳遞到下一層網路[8]。
另一種方法是賽普·霍克賴特和於爾根·施密德胡伯提出的長短期記憶神經網路(long short term memory,LSTM)[16]。2009年,在ICDAR 2009舉辦的連筆手寫識別競賽中,在沒有任何先驗知識的情況下,深度多維長短期記憶神經網路取得了其中三場比賽的勝利[17][18]。
斯文·貝克提出了在訓練時只依賴梯度符號的神經抽象金字塔模型,用以解決圖像重建和人臉定位的問題[19]。
其他方法同樣採用了無監督預訓練來構建神經網路,用以發現有效的特徵,此後再採用有監督的反向傳播以區分有標簽數據。辛頓等人於2006年提出的深度模型提出了使用多層隱變數學習高層表示的方法。這一方法使用斯摩棱斯基於1986年提出的受限玻爾茲曼機[20]對每一個包含高層特徵的層進行建模。模型保證了數據的對數似然下界隨著層數的提升而遞增。當足夠多的層數被學習完畢,這一深層結構成為一個生成模型,可以通過自上而下的采樣重構整個數據集[21]。辛頓聲稱這一模型在高維結構化數據上能夠有效低提取特徵[22]。
吳恩達和傑夫·迪恩(Jeff Dean)領導的谷歌大腦(英語:Google Brain)團隊創建了一個僅通過YouTube視頻學習高層概念(例如貓)的神經網路[23] [24]。
其他方法依賴了現代電子計算機的強大計算能力,尤其是GPU。2010年,在於爾根·施密德胡伯位於瑞士人工智慧實驗室IDSIA的研究組中,丹·奇雷尚(Dan Ciresan)和他的同事展示了利用GPU直接執行反向傳播演算法而忽視梯度消失問題的存在。這一方法在燕樂存等人給出的手寫識別MNIST數據集上戰勝了已有的其他方法[10]。
截止2011年,前饋神經網路深度學習中最新的方法是交替使用卷積層(convolutional layers)和最大值池化層(max-pooling layers)並加入單純的分類層作為頂端。訓練過程也無需引入無監督的預訓練[25][26]。從2011年起,這一方法的GPU實現[25]多次贏得了各類模式識別競賽的勝利,包括IJCNN 2011交通標志識別競賽[27]和其他比賽。
這些深度學習演算法也是最先在某些識別任務上達到和人類表現具備同等競爭力的演算法[28]。
深度學習結構[編輯]
深度神經網路是一種具備至少一個隱層的神經網路。與淺層神經網路類似,深度神經網路也能夠為復雜非線性系統提供建模,但多出的層次為模型提供了更高的抽象層次,因而提高了模型的能力。深度神經網路通常都是前饋神經網路,但也有語言建模等方面的研究將其拓展到遞歸神經網路[29]。卷積深度神經網路(Covolutional Neuron Networks, CNN)在計算機視覺領域得到了成功的應用[30]。此後,卷積神經網路也作為聽覺模型被使用在自動語音識別領域,較以往的方法獲得了更優的結果[31]。
深度神經網路[編輯]
深度神經網路(deep neuron networks, DNN)是一種判別模型,可以使用反向傳播演算法進行訓練。權重更新可以使用下式進行隨機梯度下降求解:
其中,為學習率,為代價函數。這一函數的選擇與學習的類型(例如監督學習、無監督學習、增強學習)以及激活函數相關。例如,為了在一個多分類問題上進行監督學習,通常的選擇是使用Softmax函數作為激活函數,而使用交叉熵作為代價函數。Softmax函數定義為,其中代表類別的概率,而和分別代表對單元和的輸入。交叉熵定義為,其中代表輸出單元的目標概率,代表應用了激活函數後對單元的概率輸出[32]。
深度神經網路的問題[編輯]
與其他神經網路模型類似,如果僅僅是簡單地訓練,深度神經網路可能會存在很多問題。常見的兩類問題是過擬合和過長的運算時間。
深度神經網路很容易產生過擬合現象,因為增加的抽象層使得模型能夠對訓練數據中較為罕見的依賴關系進行建模。對此,權重遞減(正規化)或者稀疏(-正規化)等方法可以利用在訓練過程中以減小過擬合現象[33]。另一種較晚用於深度神經網路訓練的正規化方法是丟棄法("dropout" regularization),即在訓練中隨機丟棄一部分隱層單元來避免對較為罕見的依賴進行建模[34]。
反向傳播演算法和梯度下降法由於其實現簡單,與其他方法相比能夠收斂到更好的局部最優值而成為神經網路訓練的通行方法。但是,這些方法的計算代價很高,尤其是在訓練深度神經網路時,因為深度神經網路的規模(即層數和每層的節點數)、學習率、初始權重等眾多參數都需要考慮。掃描所有參數由於時間代價的原因並不可行,因而小批量訓練(mini-batching),即將多個訓練樣本組合進行訓練而不是每次只使用一個樣本進行訓練,被用於加速模型訓練[35]。而最顯著地速度提升來自GPU,因為矩陣和向量計算非常適合使用GPU實現。但使用大規模集群進行深度神經網路訓練仍然存在困難,因而深度神經網路在訓練並行化方面仍有提升的空間。
深度信念網路[編輯]
一個包含完全連接可見層和隱層的受限玻爾茲曼機(RBM)。注意到可見層單元和隱層單元內部彼此不相連。
深度信念網路(deep belief networks,DBN)是一種包含多層隱單元的概率生成模型,可被視為多層簡單學習模型組合而成的復合模型[36]。
深度信念網路可以作為深度神經網路的預訓練部分,並為網路提供初始權重,再使用反向傳播或者其他判定演算法作為調優的手段。這在訓練數據較為缺乏時很有價值,因為不恰當的初始化權重會顯著影響最終模型的性能,而預訓練獲得的權重在權值空間中比隨機權重更接近最優的權重。這不僅提升了模型的性能,也加快了調優階段的收斂速度[37]。
深度信念網路中的每一層都是典型的受限玻爾茲曼機(restricted Boltzmann machine,RBM),可以使用高效的無監督逐層訓練方法進行訓練。受限玻爾茲曼機是一種無向的基於能量的生成模型,包含一個輸入層和一個隱層。圖中對的邊僅在輸入層和隱層之間存在,而輸入層節點內部和隱層節點內部則不存在邊。單層RBM的訓練方法最初由傑弗里·辛頓在訓練「專家乘積」中提出,被稱為對比分歧(contrast divergence, CD)。對比分歧提供了一種對最大似然的近似,被理想地用於學習受限玻爾茲曼機的權重[35]。當單層RBM被訓練完畢後,另一層RBM可被堆疊在已經訓練完成的RBM上,形成一個多層模型。每次堆疊時,原有的多層網路輸入層被初始化為訓練樣本,權重為先前訓練得到的權重,該網路的輸出作為新增RBM的輸入,新的RBM重復先前的單層訓練過程,整個過程可以持續進行,直到達到某個期望中的終止條件[38]。
盡管對比分歧對最大似然的近似十分粗略(對比分歧並不在任何函數的梯度方向上),但經驗結果證實該方法是訓練深度結構的一種有效的方法[35]。
卷積神經網路[編輯]
主條目:卷積神經網路
卷積神經網路(convolutional neuron networks,CNN)由一個或多個卷積層和頂端的全連通層(對應經典的神經網路)組成,同時也包括關聯權重和池化層(pooling layer)。這一結構使得卷積神經網路能夠利用輸入數據的二維結構。與其他深度學習結構相比,卷積神經網路在圖像和語音識別方面能夠給出更優的結果。這一模型也可以使用反向傳播演算法進行訓練。相比較其他深度、前饋神經網路,卷積神經網路需要估計的參數更少,使之成為一種頗具吸引力的深度學習結構[39]。
卷積深度信念網路[編輯]
卷積深度信念網路(convolutional deep belief networks,CDBN)是深度學習領域較新的分支。在結構上,卷積深度信念網路與卷積神經網路在結構上相似。因此,與卷積神經網路類似,卷積深度信念網路也具備利用圖像二維結構的能力,與此同時,卷積深度信念網路也擁有深度信念網路的預訓練優勢。卷積深度信念網路提供了一種能被用於信號和圖像處理任務的通用結構,也能夠使用類似深度信念網路的訓練方法進行訓練[40]。
結果[編輯]
語音識別[編輯]
下表中的結果展示了深度學習在通行的TIMIT數據集上的結果。TIMIT包含630人的語音數據,這些人持八種常見的美式英語口音,每人閱讀10句話。這一數據在深度學習發展之初常被用於驗證深度學習結構[41]。TIMIT數據集較小,使得研究者可以在其上實驗不同的模型配置。
方法
聲音誤差率 (PER, %)
隨機初始化RNN 26.1
貝葉斯三音子GMM-HMM 25.6
單音子重復初始化DNN 23.4
單音子DBN-DNN 22.4
帶BMMI訓練的三音子GMM-HMM 21.7
共享池上的單音子DBN-DNN 20.7
卷積DNN 20.0
圖像分類[編輯]
圖像分類領域中一個公認的評判數據集是MNIST數據集。MNIST由手寫阿拉伯數字組成,包含60,000個訓練樣本和10,000個測試樣本。與TIMIT類似,它的數據規模較小,因而能夠很容易地在不同的模型配置下測試。Yann LeCun的網站給出了多種方法得到的實驗結果[42]。截至2012年,最好的判別結果由Ciresan等人在當年給出,這一結果的錯誤率達到了0.23%[43]。
深度學習與神經科學[編輯]
計算機領域中的深度學習與20世紀90年代由認知神經科學研究者提出的大腦發育理論(尤其是皮層發育理論)密切相關[44]。對這一理論最容易理解的是傑弗里·艾爾曼(Jeffrey Elman)於1996年出版的專著《對天賦的再思考》(Rethinking Innateness)[45](參見斯拉格和約翰遜[46]以及奎茲和賽傑諾維斯基[47]的表述)。由於這些理論給出了實際的神經計算模型,因而它們是純計算驅動的深度學習模型的技術先驅。這些理論指出,大腦中的神經元組成了不同的層次,這些層次相互連接,形成一個過濾體系。在這些層次中,每層神經元在其所處的環境中獲取一部分信息,經過處理後向更深的層級傳遞。這與後來的單純與計算相關的深度神經網路模型相似。這一過程的結果是一個與環境相協調的自組織的堆棧式的轉換器。正如1995年在《紐約時報》上刊登的那樣,「……嬰兒的大腦似乎受到所謂『營養因素』的影響而進行著自我組織……大腦的不同區域依次相連,不同層次的腦組織依照一定的先後順序發育成熟,直至整個大腦發育成熟。」[48]
深度結構在人類認知演化和發展中的重要性也在認知神經學家的關注之中。發育時間的改變被認為是人類和其他靈長類動物之間智力發展差異的一個方面[49]。在靈長類中,人類的大腦在出生後的很長時間都具備可塑性,但其他靈長類動物的大腦則在出生時就幾乎完全定型。因而,人類在大腦發育最具可塑性的階段能夠接觸到更加復雜的外部場景,這可能幫助人類的大腦進行調節以適應快速變化的環境,而不是像其他動物的大腦那樣更多地受到遺傳結構的限制。這樣的發育時間差異也在大腦皮層的發育時間和大腦早期自組織中從刺激環境中獲取信息的改變得到體現。當然,伴隨著這一可塑性的是更長的兒童期,在此期間人需要依靠撫養者和社會群體的支持和訓練。因而這一理論也揭示了人類演化中文化和意識共同進化的現象[50]。
公眾視野中的深度學習[編輯]
深度學習常常被看作是通向真正人工智慧的重要一步[51],因而許多機構對深度學習的實際應用抱有濃厚的興趣。2013年12月,Facebook宣布僱用燕樂存為其新建的人工智慧實驗室的主管,這一實驗室將在加州、倫敦和紐約設立分支機構,幫助Facebook研究利用深度學習演算法進行類似自動標記照片中用戶姓名這樣的任務[52]。
2013年3月,傑弗里·辛頓和他的兩位研究生亞歷克斯·克里澤夫斯基和伊利婭·蘇特斯科娃被谷歌公司僱用,以提升現有的機器學習產品並協助處理谷歌日益增長的數據。谷歌同時並購了辛頓創辦的公司DNNresearch[53]。
批評[編輯]
對深度學習的主要批評是許多方法缺乏理論支撐。大多數深度結構僅僅是梯度下降的某些變式。盡管梯度下降已經被充分地研究,但理論涉及的其他演算法,例如對比分歧演算法,並沒有獲得充分的研究,其收斂性等問題仍不明確。深度學習方法常常被視為黑盒,大多數的結論確認都由經驗而非理論來確定。
也有學者認為,深度學習應當被視為通向真正人工智慧的一條途徑,而不是一種包羅萬象的解決方案。盡管深度學習的能力很強,但和真正的人工智慧相比,仍然缺乏諸多重要的能力。理論心理學家加里·馬庫斯(Gary Marcus)指出:
就現實而言,深度學習只是建造智能機器這一更大挑戰中的一部分。這些技術缺乏表達因果關系的手段……缺乏進行邏輯推理的方法,而且遠沒有具備集成抽象知識,例如物品屬性、代表和典型用途的信息。最為強大的人工智慧系統,例如IBM的人工智慧系統沃森,僅僅把深度學習作為一個包含從貝葉斯推理和演繹推理等技術的復雜技術集合中的組成部分[54]。
『叄』 CNN之Lenet5
LeNet誕生於 1994 年,是最早的卷積神經網路之一,並且推動了深度學習領域的發展。
LeNet-5是Yann LeCun等人在多次研究後提出的最終卷積神經網路結構,主要用於手寫數字識別
LeNet5的網路結構如下所示:
LeNet-5包含七層,不包括輸入,每一層都包含可訓練參數(權重),當時使用的輸入數據是32*32像素的圖像。下面逐層介紹LeNet-5的結構,並且,卷積層將用Cx表示,子采樣層則被標記為Sx,全連接層被標記為Fx,其中x是層索引。
該層使用了6個卷積核,每個卷積核的大小為5×5,這樣就得到了6個feature map(特徵圖)。
每個卷積核(5×5)與原始的輸入圖像(32×32)進行卷積,這樣得到的feature map(特徵圖)大小為(32-5+1)×(32-5+1)= 28×28
卷積核與輸入圖像按卷積核大小逐個區域進行匹配計算,匹配後原始輸入圖像的尺寸將變小,因為邊緣部分卷積核無法越出界,只能匹配一次,匹配計算後的尺寸變為Cr×Cc=(Ir-Kr+1)×(Ic-Kc+1),其中Cr、Cc,Ir、Ic,Kr、Kc分別表示卷積後結果圖像、輸入圖像、卷積核的行列大小。
由於參數(權值)共享的原因,對於同個卷積核每個神經元均使用相同的參數,因此,參數個數為(5×5+1)×6= 156,其中5×5為卷積核參數,1為偏置參數
卷積後的圖像大小為28×28,因此每個特徵圖有28×28個神經元,每個卷積核參數為(5×5+1)×6,因此,該層的連接數為(5×5+1)×6×28×28=122304
這一層主要是做池化或者特徵映射(特徵降維),池化單元為2×2,因此,6個特徵圖的大小經池化後即變為14×14。池化單元之間沒有重疊,在池化區域內進行聚合統計後得到新的特徵值,因此經2×2池化後,每兩行兩列重新算出一個特徵值出來,相當於圖像大小減半,因此卷積後的28×28圖像經2×2池化後就變為14×14。
這一層的計算過程是:2×2 單元里的值相加,然後再乘以訓練參數w,再加上一個偏置參數b(每一個特徵圖共享相同的w和b),然後取sigmoid值(S函數:0-1區間),作為對應的該單元的值。卷積操作與池化的示意圖如下:
S2層由於每個特徵圖都共享相同的w和b這兩個參數,因此需要2×6=12個參數
下采樣之後的圖像大小為14×14,因此S2層的每個特徵圖有14×14個神經元,每個池化單元連接數為2×2+1(1為偏置量),因此,該層的連接數為(2×2+1)×14×14×6 = 5880
C3層有16個卷積核,卷積模板大小為5×5。
與C1層的分析類似,C3層的特徵圖大小為(14-5+1)×(14-5+1)= 10×10
需要注意的是,C3與S2並不是全連接而是部分連接,有些是C3連接到S2三層、有些四層、甚至達到6層,通過這種方式提取更多特徵,連接的規則如下表所示:
例如第一列表示C3層的第0個特徵圖(feature map)只跟S2層的第0、1和2這三個feature maps相連接,計算過程為:用3個卷積模板分別與S2層的3個feature maps進行卷積,然後將卷積的結果相加求和,再加上一個偏置,再取sigmoid得出卷積後對應的feature map了。其它列也是類似(有些是3個卷積模板,有些是4個,有些是6個)。因此,C3層的參數數目為(5×5×3+1)×6 +(5×5×4+1)×9 +5×5×6+1 = 1516
卷積後的特徵圖大小為10×10,參數數量為1516,因此連接數為1516×10×10= 151600
與S2的分析類似,池化單元大小為2×2,因此,該層與C3一樣共有16個特徵圖,每個特徵圖的大小為5×5。
與S2的計算類似,所需要參數個數為16×2 = 32
連接數為(2×2+1)×5×5×16 = 2000
該層有120個卷積核,每個卷積核的大小仍為5×5,因此有120個特徵圖。由於S4層的大小為5×5,而該層的卷積核大小也是5×5,因此特徵圖大小為(5-5+1)×(5-5+1)= 1×1。這樣該層就剛好變成了全連接,這只是巧合,如果原始輸入的圖像比較大,則該層就不是全連接了。
與前面的分析類似,本層的參數數目為120×(5×5×16+1) = 48120
由於該層的特徵圖大小剛好為1×1,因此連接數為48120×1×1=48120
F6層有84個單元,之所以選這個數字的原因是來自於輸出層的設計,對應於一個7×12的比特圖,如下圖所示,-1表示白色,1表示黑色,這樣每個符號的比特圖的黑白色就對應於一個編碼。
該層有84個特徵圖,特徵圖大小與C5一樣都是1×1,與C5層全連接。
由於是全連接,參數數量為(120+1)×84=10164。跟經典神經網路一樣,F6層計算輸入向量和權重向量之間的點積,再加上一個偏置,然後將其傳遞給sigmoid函數得出結果。
由於是全連接,連接數與參數數量一樣,也是10164。
Output層也是全連接層,共有10個節點,分別代表數字0到9。如果第i個節點的值為0,則表示網路識別的結果是數字i。
該層採用徑向基函數(RBF)的網路連接方式,假設x是上一層的輸入,y是RBF的輸出,則RBF輸出的計算方式是:
上式中的Wij的值由i的比特圖編碼確定,i從0到9,j取值從0到7×12-1。RBF輸出的值越接近於0,表示當前網路輸入的識別結果與字元i越接近。
由於是全連接,參數個數為84×10=840
由於是全連接,連接數與參數個數一樣,也是840
from skimage import io,transform
import os
import glob
import numpy as np
import tensorflow as tf
#將所有的圖片重新設置尺寸為32*32
w = 32
h = 32
c = 1
#mnist數據集中訓練數據和測試數據保存地址
train_path = "E:/data/datasets/mnist/train/"
test_path = "E:/data/datasets/mnist/test/"
#讀取圖片及其標簽函數
'''os.listdir()返回指定的文件夾包含的文件或文件夾的名字,存放於一個列表中;os.path.isdir()判斷某一路徑是否為目錄
enumerate()將一個可遍歷的數據對象(如列表、元組或字元串)組合為一個索引序列,數據下標和相應數據'''
def read_image(path):
label_dir = [path+x for x in os.listdir(path) if os.path.isdir(path+x)]
images = []
labels = []
for index,folder in enumerate(label_dir):
for img in glob.glob(folder+'/*.png'):
print("reading the image:%s"%img)
image = io.imread(img)
image = transform.resize(image,(w,h,c))
images.append(image)
labels.append(index)
return np.asarray(images,dtype=np.float32),np.asarray(labels,dtype=np.int32)
#讀取訓練數據及測試數據
train_data,train_label = read_image(train_path)
test_data,test_label = read_image(test_path)
#打亂訓練數據及測試數據 np.arange()返回一個有終點和起點的固定步長的排列,
train_image_num = len(train_data)
train_image_index = np.arange(train_image_num) ##起始點0,結束點train_image_num,步長1,返回類型array,一維
np.random.shuffle(train_image_index)
train_data = train_data[train_image_index]
train_label = train_label[train_image_index]
test_image_num = len(test_data)
test_image_index = np.arange(test_image_num)
np.random.shuffle(test_image_index)
test_data = test_data[test_image_index]
test_label = test_label[test_image_index]
#搭建CNN 此函數可以理解為形參,用於定義過程,在執行的時候再賦具體的值,形參名X,y_
x = tf.placeholder(tf.float32,[None,w,h,c],name='x')
y_ = tf.placeholder(tf.int32,[None],name='y_')
def inference(input_tensor,train,regularizer):
#第一層:卷積層,過濾器的尺寸為5×5,深度為6,不使用全0補充,步長為1。
#尺寸變化:32×32×1->28×28×6
'''參數的初始化:tf.truncated_normal_initializer()或者簡寫為tf.TruncatedNormal()、tf.RandomNormal() 去掉_initializer,大寫首字母即可
生成截斷正態分布的隨機數,這個初始化方法好像在tf中用得比較多mean=0.0, stddev=1.0 正態分布
http://www.mamicode.com/info-detail-1835147.html'''
with tf.variable_scope('layer1-conv1'):
conv1_weights = tf.get_variable('weight',[5,5,c,6],initializer=tf.truncated_normal_initializer(stddev=0.1))
conv1_biases = tf.get_variable('bias',[6],initializer=tf.constant_initializer(0.0))
conv1 = tf.nn.conv2d(input_tensor,conv1_weights,strides=[1,1,1,1],padding='VALID')
relu1 = tf.nn.relu(tf.nn.bias_add(conv1,conv1_biases))
#第二層:池化層,過濾器的尺寸為2×2,使用全0補充,步長為2。
#尺寸變化:28×28×6->14×14×6
with tf.name_scope('layer2-pool1'):
pool1 = tf.nn.max_pool(relu1,ksize=[1,2,2,1],strides=[1,2,2,1],padding='SAME')
#第三層:卷積層,過濾器的尺寸為5×5,深度為16,不使用全0補充,步長為1。
#尺寸變化:14×14×6->10×10×16
with tf.variable_scope('layer3-conv2'):
conv2_weights = tf.get_variable('weight',[5,5,6,16],initializer=tf.truncated_normal_initializer(stddev=0.1))
conv2_biases = tf.get_variable('bias',[16],initializer=tf.constant_initializer(0.0))
conv2 = tf.nn.conv2d(pool1,conv2_weights,strides=[1,1,1,1],padding='VALID')
relu2 = tf.nn.relu(tf.nn.bias_add(conv2,conv2_biases))
#第四層:池化層,過濾器的尺寸為2×2,使用全0補充,步長為2。
#尺寸變化:10×10×6->5×5×16
with tf.variable_scope('layer4-pool2'):
pool2 = tf.nn.max_pool(relu2,ksize=[1,2,2,1],strides=[1,2,2,1],padding='SAME')
#將第四層池化層的輸出轉化為第五層全連接層的輸入格式。第四層的輸出為5×5×16的矩陣,然而第五層全連接層需要的輸入格式
#為向量,所以我們需要把代表每張圖片的尺寸為5×5×16的矩陣拉直成一個長度為5×5×16的向量。
#舉例說,每次訓練64張圖片,那麼第四層池化層的輸出的size為(64,5,5,16),拉直為向量,nodes=5×5×16=400,尺寸size變為(64,400)
pool_shape = pool2.get_shape().as_list()
nodes = pool_shape[1]*pool_shape[2]*pool_shape[3]
reshaped = tf.reshape(pool2,[-1,nodes])
#第五層:全連接層,nodes=5×5×16=400,400->120的全連接
#尺寸變化:比如一組訓練樣本為64,那麼尺寸變化為64×400->64×120
#訓練時,引入dropout,dropout在訓練時會隨機將部分節點的輸出改為0,dropout可以避免過擬合問題。
#這和模型越簡單越不容易過擬合思想一致,和正則化限制權重的大小,使得模型不能任意擬合訓練數據中的隨機雜訊,以此達到避免過擬合思想一致。
#本文最後訓練時沒有採用dropout,dropout項傳入參數設置成了False,因為訓練和測試寫在了一起沒有分離,不過大家可以嘗試。
'''tf.matmul()這個函數是專門矩陣或者tensor乘法,而不是矩陣元素對應元素相乘
tf.multiply()兩個矩陣中對應元素各自相乘
tf.nn.dropout(x, keep_prob):TensorFlow裡面為了防止或減輕過擬合而使用的函數,它一般用在全連接層,
x:指輸入;keep_prob: 設置神經元被選中的概率,使輸入tensor中某些元素變為0,其它沒變0的元素變為原來的1/keep_prob大小,可以想像下,比如某些元素棄用
在初始化時keep_prob是一個佔位符,keep_prob = tf.placeholder(tf.float32).
tensorflow在run時設置keep_prob具體的值,例如keep_prob: 0.5,train的時候才是dropout起作用的時候
keep_prob: A scalar Tensor with the same type as x. The probability that each element is kept.'''
with tf.variable_scope('layer5-fc1'):
fc1_weights = tf.get_variable('weight',[nodes,120],initializer=tf.truncated_normal_initializer(stddev=0.1))
if regularizer != None:
tf.add_to_collection('losses',regularizer(fc1_weights))
fc1_biases = tf.get_variable('bias',[120],initializer=tf.constant_initializer(0.1))
fc1 = tf.nn.relu(tf.matmul(reshaped,fc1_weights) + fc1_biases)
if train:
fc1 = tf.nn.dropout(fc1,0.5)
#第六層:全連接層,120->84的全連接
#尺寸變化:比如一組訓練樣本為64,那麼尺寸變化為64×120->64×84
'''tf.add_to_collection:把變數放入一個集合,把很多變數變成一個列表
tf.get_collection:從一個結合中取出全部變數,是一個列表
tf.add_n:把一個列表的東西都依次加起來'''
with tf.variable_scope('layer6-fc2'):
fc2_weights = tf.get_variable('weight',[120,84],initializer=tf.truncated_normal_initializer(stddev=0.1))
if regularizer != None:
tf.add_to_collection('losses',regularizer(fc2_weights))
fc2_biases = tf.get_variable('bias',[84],initializer=tf.truncated_normal_initializer(stddev=0.1))
fc2 = tf.nn.relu(tf.matmul(fc1,fc2_weights) + fc2_biases)
if train:
fc2 = tf.nn.dropout(fc2,0.5)
#第七層:全連接層(近似表示),84->10的全連接
#尺寸變化:比如一組訓練樣本為64,那麼尺寸變化為64×84->64×10。最後,64×10的矩陣經過softmax之後就得出了64張圖片分類於每種數字的概率,
#即得到最後的分類結果。
with tf.variable_scope('layer7-fc3'):
fc3_weights = tf.get_variable('weight',[84,10],initializer=tf.truncated_normal_initializer(stddev=0.1))
if regularizer != None:
tf.add_to_collection('losses',regularizer(fc3_weights))
fc3_biases = tf.get_variable('bias',[10],initializer=tf.truncated_normal_initializer(stddev=0.1))
logit = tf.matmul(fc2,fc3_weights) + fc3_biases
return logit
#正則化,交叉熵,平均交叉熵,損失函數,最小化損失函數,預測和實際equal比較,tf.equal函數會得到True或False,
#accuracy首先將tf.equal比較得到的布爾值轉為float型,即True轉為1.,False轉為0,最後求平均值,即一組樣本的正確率。
#比如:一組5個樣本,tf.equal比較為[True False True False False],轉化為float型為[1. 0 1. 0 0],准確率為2./5=40%。
'''規則化可以幫助防止過度配合,提高模型的適用性。(讓模型無法完美匹配所有的訓練項。)(使用規則來使用盡量少的變數去擬合數據)
規則化就是說給需要訓練的目標函數加上一些規則(限制),讓他們不要自我膨脹。
TensorFlow會將L2的正則化損失值除以2使得求導得到的結果更加簡潔
如tf.contrib.layers.apply_regularization/l1_regularizer/l2_regularizer/sum_regularizer
https://blog.csdn.net/liushui94/article/details/73481112
sparse_softmax_cross_entropy_with_logits()是將softmax和cross_entropy放在一起計算
https://blog.csdn.net/ZJRN1027/article/details/80199248'''
regularizer = tf.contrib.layers.l2_regularizer(0.001)
y = inference(x,False,regularizer)
cross_entropy = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=y,labels=y_)
cross_entropy_mean = tf.rece_mean(cross_entropy)
loss = cross_entropy_mean + tf.add_n(tf.get_collection('losses'))
train_op = tf.train.AdamOptimizer(0.001).minimize(loss)
correct_prediction = tf.equal(tf.cast(tf.argmax(y,1),tf.int32),y_)
accuracy = tf.rece_mean(tf.cast(correct_prediction,tf.float32))
#每次獲取batch_size個樣本進行訓練或測試
def get_batch(data,label,batch_size):
for start_index in range(0,len(data)-batch_size+1,batch_size):
slice_index = slice(start_index,start_index+batch_size)
yield data[slice_index],label[slice_index]
#創建Session會話
with tf.Session() as sess:
#初始化所有變數(權值,偏置等)
sess.run(tf.global_variables_initializer())
#將所有樣本訓練10次,每次訓練中以64個為一組訓練完所有樣本。
#train_num可以設置大一些。
train_num = 10
batch_size = 64
for i in range(train_num):
train_loss,train_acc,batch_num = 0, 0, 0
for train_data_batch,train_label_batch in get_batch(train_data,train_label,batch_size):
_,err,acc = sess.run([train_op,loss,accuracy],feed_dict={x:train_data_batch,y_:train_label_batch})
train_loss+=err;train_acc+=acc;batch_num+=1
print("train loss:",train_loss/batch_num)
print("train acc:",train_acc/batch_num)
test_loss,test_acc,batch_num = 0, 0, 0
for test_data_batch,test_label_batch in get_batch(test_data,test_label,batch_size):
err,acc = sess.run([loss,accuracy],feed_dict={x:test_data_batch,y_:test_label_batch})
test_loss+=err;test_acc+=acc;batch_num+=1
print("test loss:",test_loss/batch_num)
print("test acc:",test_acc/batch_num)
『肆』 sklearn 神經網路 MLPClassifier簡單應用與參數說明
MLPClassifier是一個監督學習演算法,下圖是只有1個隱藏層的MLP模型 ,左側是輸入層,右側是輸出層。
上圖的整體結構可以簡單的理解為下圖所示:
MLP又名多層感知機,也叫人工神經網路(ANN,Artificial Neural Network),除了輸入輸出層,它中間可以有多個隱藏層,如果沒有隱藏層即可解決線性可劃分的數據問題。最簡單的MLP模型只包含一個隱藏層,即三層的結構,如上圖。
從上圖可以看到,多層感知機的層與層之間是全連接的(全連接的意思就是:上一層的任何一個神經元與下一層的所有神經元都有連接)。多層感知機最底層是輸入層,中間是隱藏層,最後是輸出層。
輸入層沒什麼好說,你輸入什麼就是什麼,比如輸入是一個n維向量,就有n個神經元。
隱藏層的神經元怎麼得來?首先它與輸入層是全連接的,假設輸入層用向量X表示,則隱藏層的輸出就是
f(W1X+b1),W1是權重(也叫連接系數),b1是偏置,函數f 可以是常用的sigmoid函數或者tanh函數:
最後就是輸出層,輸出層與隱藏層是什麼關系?其實隱藏層到輸出層可以看成是一個多類別的邏輯回歸,也即softmax回歸,所以輸出層的輸出就是softmax(W2X1+b2),X1表示隱藏層的輸出f(W1X+b1)。
MLP整個模型就是這樣子的,上面說的這個三層的MLP用公式總結起來就是,函數G是softmax
因此,MLP所有的參數就是各個層之間的連接權重以及偏置,包括W1、b1、W2、b2。對於一個具體的問題,怎麼確定這些參數?求解最佳的參數是一個最優化問題,解決最優化問題,最簡單的就是梯度下降法了(sgd):首先隨機初始化所有參數,然後迭代地訓練,不斷地計算梯度和更新參數,直到滿足某個條件為止(比如誤差足夠小、迭代次數足夠多時)。這個過程涉及到代價函數、規則化(Regularization)、學習速率(learning rate)、梯度計算等。
下面寫了一個超級簡單的實例,訓練和測試數據是mnist手寫識別數據集:
from sklearn.neural_network import MLPClassifier
import gzip
import pickle
with gzip.open('./mnist.pkl.gz') as f_gz:
train_data,valid_data,test_data = pickle.load(f_gz)
clf = MLPClassifier(solver='sgd',activation = 'identity',max_iter = 10,alpha = 1e-5,hidden_layer_sizes = (100,50),random_state = 1,verbose = True)
clf.fit(train_data[0][:10000],train_data[1][:10000])
print clf.predict(test_data[0][:10])
print(clf.score(test_data[0][:100],test_data[1][:100]))
print(clf.predict_proba(test_data[0][:10]))
參數說明:
參數說明:
1. hidden_layer_sizes :例如hidden_layer_sizes=(50, 50),表示有兩層隱藏層,第一層隱藏層有50個神經元,第二層也有50個神經元。
2. activation :激活函數,{『identity』, 『logistic』, 『tanh』, 『relu』}, 默認relu
- identity:f(x) = x
- logistic:其實就是sigmod,f(x) = 1 / (1 + exp(-x)).
- tanh:f(x) = tanh(x).
- relu:f(x) = max(0, x)
3. solver: {『lbfgs』, 『sgd』, 『adam』}, 默認adam,用來優化權重
- lbfgs:quasi-Newton方法的優化器
- sgd:隨機梯度下降
- adam: Kingma, Diederik, and Jimmy Ba提出的機遇隨機梯度的優化器
注意:默認solver 『adam』在相對較大的數據集上效果比較好(幾千個樣本或者更多),對小數據集來說,lbfgs收斂更快效果也更好。
4. alpha :float,可選的,默認0.0001,正則化項參數
5. batch_size : int , 可選的,默認』auto』,隨機優化的minibatches的大小batch_size=min(200,n_samples),如果solver是』lbfgs』,分類器將不使用minibatch
6. learning_rate :學習率,用於權重更新,只有當solver為』sgd』時使用,{『constant』,』invscaling』, 『adaptive』},默認constant
- 『constant』: 有』learning_rate_init』給定的恆定學習率
- 『incscaling』:隨著時間t使用』power_t』的逆標度指數不斷降低學習率learning_rate_ ,effective_learning_rate = learning_rate_init / pow(t, power_t)
- 『adaptive』:只要訓練損耗在下降,就保持學習率為』learning_rate_init』不變,當連續兩次不能降低訓練損耗或驗證分數停止升高至少tol時,將當前學習率除以5.
7. power_t: double, 可選, default 0.5,只有solver=』sgd』時使用,是逆擴展學習率的指數.當learning_rate=』invscaling』,用來更新有效學習率。
8. max_iter: int,可選,默認200,最大迭代次數。
9. random_state:int 或RandomState,可選,默認None,隨機數生成器的狀態或種子。
10. shuffle: bool,可選,默認True,只有當solver=』sgd』或者『adam』時使用,判斷是否在每次迭代時對樣本進行清洗。
11. tol:float, 可選,默認1e-4,優化的容忍度
12. learning_rate_int:double,可選,默認0.001,初始學習率,控制更新權重的補償,只有當solver=』sgd』 或』adam』時使用。
14. verbose : bool, 可選, 默認False,是否將過程列印到stdout
15. warm_start : bool, 可選, 默認False,當設置成True,使用之前的解決方法作為初始擬合,否則釋放之前的解決方法。
16. momentum : float, 默認 0.9,動量梯度下降更新,設置的范圍應該0.0-1.0. 只有solver=』sgd』時使用.
17. nesterovs_momentum : boolean, 默認True, Whether to use Nesterov』s momentum. 只有solver=』sgd』並且momentum > 0使用.
18. early_stopping : bool, 默認False,只有solver=』sgd』或者』adam』時有效,判斷當驗證效果不再改善的時候是否終止訓練,當為True時,自動選出10%的訓練數據用於驗證並在兩步連續迭代改善,低於tol時終止訓練。
19. validation_fraction : float, 可選, 默認 0.1,用作早期停止驗證的預留訓練數據集的比例,早0-1之間,只當early_stopping=True有用
20. beta_1 : float, 可選, 默認0.9,只有solver=』adam』時使用,估計一階矩向量的指數衰減速率,[0,1)之間
21. beta_2 : float, 可選, 默認0.999,只有solver=』adam』時使用估計二階矩向量的指數衰減速率[0,1)之間
22. epsilon : float, 可選, 默認1e-8,只有solver=』adam』時使用數值穩定值。
屬性說明:
- classes_:每個輸出的類標簽
- loss_:損失函數計算出來的當前損失值
- coefs_:列表中的第i個元素表示i層的權重矩陣
- intercepts_:列表中第i個元素代表i+1層的偏差向量
- n_iter_ :迭代次數
- n_layers_:層數
- n_outputs_:輸出的個數
- out_activation_:輸出激活函數的名稱。
方法說明:
- fit(X,y):擬合
- get_params([deep]):獲取參數
- predict(X):使用MLP進行預測
- predic_log_proba(X):返回對數概率估計
- predic_proba(X):概率估計
- score(X,y[,sample_weight]):返回給定測試數據和標簽上的平均准確度
-set_params(**params):設置參數。
『伍』 如何製作像mnist,CIFAR-10格式的數據集
MNIST 數據集
混合的國家標准和技術 (簡稱 MNIST) 由紅外研究員,作為基準來比較不同的紅外演算法創建數據集。 其基本思想是如果你有你想要測試紅外的演算法或軟體的系統,可以運行您的演算法或系統針對 MNIST 的數據集和比較您的結果與其他系統以前發布成果。
數據集包含的共 70,000 圖像 ; 60,000 訓練圖像 (用於創建紅外模型) 和 10,000 測試圖像 (用於評估模型的精度)。 每個 MNIST 圖像是一個單一的手寫的數字字元的數字化的圖片。 每個圖像是 28 x 28 像素大小。 每個像素值是 0,表示白色,至 255,表示黑。 中間像素值表示的灰度級。 圖 2 顯示了訓練集的前八位的圖像。 對應於每個圖像的實際數字是顯然對人,但確定數字是非常困難的挑戰的計算機。
圖 2 首八 MNIST 訓練圖像
奇怪的是,訓練數據和測試數據均存儲在兩個文件中,而不是在單個文件中。 其中一個文件包含圖像的像素值和,另一個包含圖像的標簽信息 (0 到 9)。 每個的四個文件還包含標頭信息,和所有的四個文件都存儲在已經使用 gzip 格式壓縮的二進制格式。
注意在圖 1,該演示程序使用僅 60,000 項目訓練集。 測試集的格式是相同的訓練集。 MNIST 文件的主存儲庫是目前位於 yann.lecun.com/exdb/mnist。 培訓的像素數據存儲在文件火車-圖像-idx3-ubyte.gz 和培訓標簽數據存儲在文件火車-標簽-idx1-ubyte.gz。 若要運行該演示程序,您需要轉到 MNIST 的存儲庫站點,下載並解壓的兩個培訓數據文件。 將文件解壓縮,我用的免費的開源 7-Zip 實用程序。
創建 MNIST 查看器
若要創建 MNIST 演示程序,我發起了 Visual Studio,創建一個名為 MnistViewer 的新 C# Windows 窗體項目。 演示有沒有重大的.NET 版本依賴關系,因此,任何版本的 Visual Studio 應該工作。
模板代碼載入到 Visual Studio 編輯器後,我設置的 UI 控制項。 我添加了兩個 TextBox 控制項 (textBox1,textBox2) 要堅持兩個解壓後的培訓文件的路徑。 我添加一個按鈕控制項 (button1),並給了它一個標簽載入圖像。 我添加了兩個多個 TextBox 控制項 (textBox3,textBox4) 以保存當前圖像索引和下一個圖像索引的值。 我使用 Visual Studio 設計器,分別設置"NA"和"0,"這些控制項的初始值。
我添加了一個 ComboBox 控制項 (comboBox1) 的圖像放大倍數值。 使用設計器,我去到該控制項的項集合,添加字元串"1"到"10"。我添加了第二個按鈕控制項 (button2),並給了它一個標簽的顯示下一次。 我添加了 PictureBox 控制項 (pictureBox1),將其背景色屬性設置為 ControlDark,以便看到控制項的輪廓。 我將圖片框大小設置為 280 x 280 允許最多 10 倍的放大倍率 (回顧 MNIST 圖像是 28 x 28 像素為單位)。 我添加了第五個 (textBox5) 文本框以顯示十六進制值的圖像,然後將其多行屬性設置為 True 和其字體屬性設置為 8.25 磅 Courier New 和擴大其大小到 606 x 412。 而且,最後,我添加了一個列表框控制項 (listBox1) 的日誌記錄消息。
後放置 UI 控制項拖到 Windows 窗體,添加三個類范圍欄位:
public partial class Form1 : Form
{
private string pixelFile =
@"C:\MnistViewer\train-images.idx3-ubyte";
private string labelFile =
@"C:\MnistViewer\train-labels.idx1-ubyte";
private DigitImage[] trainImages = null;
...
第一次兩個字元串指向解壓後的培訓數據文件的位置。 你會需要編輯這些要運行演示的兩個字元串。 第三個欄位是一個程序定義 DigitImage 對象的數組。
我編輯窗體的構造函數略成 textBox1 和 textBox2 地點的文件路徑,並給予放大倍數初始值 6:
public Form1()
{
InitializeComponent();
textBox1.Text = pixelFile;
textBox2.Text = labelFile;
comboBox1.SelectedItem = "6";
this.ActiveControl = button1;
}
我用的 ActiveControl 屬性來設置初始焦點到 button1 控制項,只是為了方便。