簡介
不多有程序員不對這裏或者那裏所包含的人工智能編程所吸引,然而,許多對AI感興趣的程序員很快就因其中包含的算法的複雜性而退卻。在本文中,咱們將討論一個能大大簡化這種複雜性的Java開源工程。
Java面向對象的神經網絡(JOONE)是一開源工程,它提供給Java程序員一個高適應性的神經網絡。該JOONE工程源代碼由LGPL所保護。簡言之,這意味着源代碼是可自由使用的並且你不須要支付版稅就可使用JOONE。JOONE能夠從[url]http://joone.sourceforge.net/[/url]處下載。
JOONE能容許你輕易地從一個Java程序中建立神經網絡。JOONE支持許多特徵,如多線程和分佈式處理。這意味着JOONE能利用多處理機計算機和多臺計算機的優點來進行分佈式處理。
神經網絡
JOONE用Java實現了一我的工神經網絡。一我的工神經網絡試圖仿效生物學神經網絡的功能--神經網絡組成今天在地球上幾乎全部高等生命的大腦形式。神經網絡由神經原組成。圖1顯示了一個實際神經原圖。
圖1:一個生物學的神經原
從圖1中你能夠看出,神經起因一個內核細胞和幾個長長的稱爲觸角的鏈接器組成。神經原之間依靠這些觸角進行鏈接。不管是生物學的仍是人工的神經網絡,都經過觸角把信號從一個神經原傳遞到另外一個神經原來工做。
使用JOONE
在這篇文章中,你將看到一個簡單的怎樣使用JOONE的實例。神經網絡題目涉及普遍並覆蓋許多不一樣的應用領域。在本文中,咱們將展現給你怎樣使用JOONE來解決一個很簡單的模式識別問題。模式識別是神經網絡中的最廣泛的應用之一。
模式識別提供給神經網絡一種模式,判斷是否該神經網絡可以識別出該模式。這種模式應該可以在某種程度上被扭曲而該神經網絡仍然可以識別它。這很像人類識 別東西(如一個交通標誌)的能力。人類應該可以識別在下雨天,晴天或者晚上的交通標誌。即便這些圖像看上去可能至關不一樣,但人類的大腦仍可以判斷出它們是 同樣的圖像。
當進行JOONE編程時,你通常要使用兩種類型的對象。你要使用神經原層對象,用於描述一層的一個或多個的具備類似特徵的神經原。神經網絡常常有一層或兩層神經元。這些神經元層經過觸角聯繫在一塊兒。這些觸角把這種待識別的模式,從一個神經元層傳輸到另外一個神經元層。
觸角不只把這種模式從一個神經元層傳輸到另外一個神經元層。觸角還將生成一些指向這種模式的元素的斜線。這些斜線將致使這種模式的某些元素在被傳輸到下一 個神經元層時不如經過其它方式傳遞更有效些。這些斜線一般稱爲權重,它們造成神經網絡的存儲系統。經過調整存儲在觸角中的這些權重,能夠更改神經網絡的行 爲。
觸角在JOONE中還承擔着另一個角色。在JOONE中,能夠把觸角看做是數據導管。正如觸角把模式從一個神經元層傳輸到另外一個神經元層,指定版本的觸角用於把模式傳入和傳出神經網絡。下面將給你展現一個簡單的單層的神經網絡是怎樣被構建並進行模式識別的。
訓練神經網絡
爲實現本文的目的,咱們將指導JOONE去識別一個很簡單的模式。在這種模式中,咱們將考察一個二進制的布爾操做,例如XOR。這個XOR操做的真值表列舉以下:
X
|
Y
|
X XOR Y
|
0 |
0 |
0 |
0 |
1 |
1 |
1 |
0 |
1 |
1 |
1 |
0 |
正如你從上表中看到的,XOR運算的結果是隻有當 X和Y具備不一樣值時,結果才爲真(1)。其它狀況下,XOR運算結果均爲假(0)。默認地,JOONE從存儲在你的系統中的文本文件中取得輸入。這些文本 文件經過使用一種稱爲FileInputSynapse的特殊觸角來讀取。爲了訓練XOR運算問題,你必須創建一個輸入文件-該文件包含上面顯示的數據。 該文件顯示在列表1中。
列表1:爲解決XOR問題的輸入文件的內容
0.0;0.0;0.0
0.0;1.0;1.0
1.0;0.0;1.0
1.0;1.0;0.0
咱們如今分析一個簡單的程序,它指導JOONE來識別XOR運算併產生正確的結果。咱們如今分析訓練該神經網絡必須被處理的過程。訓練過程包括把XOR 問題提交給神經網絡,而後觀察結果。若是這個結果不是所預期的,該訓練算法將調整存儲在觸角中的重量。在神經網絡的實際輸出和預料的輸出之間的差距稱爲誤 差。訓練將繼續到偏差小於一個可接受值爲止。這個級別一般是一個百分數,如10%。咱們如今分析必須用於訓練一個神經網絡的代碼。
訓練過程經過創建神經網絡開始,同時也必須建立隱蔽的輸入層和輸出層。
// 首先,創造這三個層 input = new SigmoidLayer(); hidden = new SigmoidLayer(); output = new SigmoidLayer(); |
每一個層被使用JOONE對象SigmoidLayer建立。Sigmoidlayer基於天然對數生成一個輸出。JOONE還包含另外的層,而不是你可能選擇使用的S形的層類型。
下一步,每一層被賦於一個名字。這些名字將有助於後面在調試期間識別該層。
input.setLayerName("input"); hidden.setLayerName("hidden"); output.setLayerName("output"); |
如今必須定義每一個層。咱們將指定在每一層中的"行"號。該"行"號對應於這一層中的神經原的數目。
input.setRows(2); hidden.setRows(3); output.setRows(1); |
從上面的代碼看出,輸入層有兩個神經原,隱蔽層有三個隱蔽神經原,輸出層包含一個神經原。這對於神經網絡包含兩個輸入神經原和一個輸出神經原是具備重要意義的,由於XOR運算符接收兩個參數而產生一個結果。
爲使用該神經原層,咱們也必須建立觸角。在本例中,咱們要使用多個觸角。這些觸角用下面的代碼實現。
// 輸入-> 隱蔽的鏈接。 FullSynapse synapse_IH = new FullSynapse(); // 隱蔽-> 輸出鏈接。 FullSynapse synapse_HO = new FullSynapse(); |
就象神經原層的狀況同樣,觸角也可能命名以有助於程序的調試。下面的代碼命名新建的觸角。
synapse_IH.setName("IH"); synapse_HO.setName("HO"); |
最後,咱們必須把觸角聯接到適當神經原層。下面的代碼實現這一點。
// 聯接輸入層到隱蔽層 input.addOutputSynapse(synapse_IH); hidden.addInputSynapse(synapse_IH); // 聯接隱蔽層到輸出層 hidden.addOutputSynapse(synapse_HO); output.addInputSynapse(synapse_HO); |
如今既然神經網絡已被建立,咱們必須建立一個用於調節該神經網絡的監視器對象。下面的代碼建立監視器對象。
//建立監視器對象而且設置學習參數 monitor = new Monitor(); monitor.setLearningRate(0.8); monitor.setMomentum(0.3); |
學習速度和動力做爲參數以用於指定訓練的產生方式。JOONE利用backpropagation學習算法。要更多瞭解關於學習速度或者動力的信息,你應該參考backpropagation算法。
這個監視器對象應該被賦值給每個神經原層。下面的代碼實現這一點。
input.setMonitor(monitor); hidden.setMonitor(monitor); output.setMonitor(monitor); |
就象許多
Java對象自己同樣,JOONE監視器容許聽者能夠添加到它上面去。隨着訓練的進行,JOONE將通知聽者有關訓練進程的信息。在這個簡單的例子中,咱們使用:
monitor.addNeuralNetListener(this); |
我 們如今必須創建輸入觸角。如前所述,咱們將使用一個FileInputSynapse來讀取一個磁盤文件。磁盤文件不是JOONE惟一可以接受的輸入種 類。JOONE對於不一樣的輸入源具備很強的靈活性。爲使JOONE可以接收其它輸入類型,你只需建立一個新的觸角來接受輸入。在本例中,咱們將簡單地使用 FileInputSynapse。FileInputSynapse首先被實例化。
inputStream = new FileInputSynapse(); |
而後,必須通知FileInputSynapse要使用哪些列。列表1中顯示的文件使用了輸入數據的前兩列。下面代碼創建起前兩列用於輸入到神經網絡。
// 前兩列包含輸入值 inputStream.setFirstCol(1); inputStream.setLastCol(2); |
而後,咱們必須提供輸入文件的名字,這個名字直接來源於用戶接口。而後,提供一個編輯控件用於收集輸入文件的名字。下面代碼爲FileInputSynapse設置文件名。
// 這是包含輸入數據的文件名 inputStream.setFileName(inputFile.getText()); |
如前所述,一個觸角僅是一個神經原層之間的數據導管。FileInputSynapse正是這裏的數據導管,經過它數據進入到神經網絡。爲了更容易實現這點,咱們必需要把FileInputSynapse加到神經網絡的輸入層。這由下面一行實現。
input.addInputSynapse(inputStream); |
現 在既然已經創建起神經網絡,咱們必須建立一個訓練員和一個監視器。訓練員用於訓練該神經網絡,由於該監視器經過一個事先設置好的訓練重複數來運行這個神經 網絡。對於每一次訓練重複,數據被提供到神經網絡,而後就能夠觀察到結果。該神經網絡的權重(存儲在穿梭在神經原層之間的觸角鏈接中)將根據偏差做適當調 整。隨着訓練的進行,偏差級將降低。下列代碼創建訓練員並把它依附到監視器。
trainer = new TeachingSynapse(); trainer.setMonitor(monitor); |
你會記得列表1中提供的輸入文件包含三個列。到目前爲止,咱們僅僅使用了第1、二列,它們指定了到神經網絡的輸入。第三列包含當提供給神經網絡第一列中 的數字時的期盼的輸出值。咱們必須使得訓練員可以存取該列以便能肯定偏差。該錯誤是神經網絡的實際輸出和期盼的輸出之間的差距。下列代碼建立另一個 FileInputSynapse並做好準備以讀取與前面相同的輸入文件。
// 設置包含指望的響應值的文件,這由FileInputSynapse來提供 samples = new FileInputSynapse(); samples.setFileName(inputFile.getText()); |
這時,咱們想指向在第三列的FileInputSynapse。下列代碼實現了這一點,而後讓訓練員使用這個FileInputSynapse。
//輸出值在文件中的第三列上 samples.setFirstCol(3); samples.setLastCol(3); trainer.setDesired(samples); |
最後,訓練員被連結到神經網絡輸出層,這將使訓練員接收神經網絡的輸出。
// 鏈接訓練員到網絡的最後一層 output.addOutputSynapse(trainer); |
咱們如今已爲全部的層準備好後臺
線程,包括訓練員。
input.start(); hidden.start(); output.start(); trainer.start(); |
最後,咱們爲訓練設置一些參數。咱們指定在輸入文件中共有四行,並且想訓練20,000個週期,並且還在不段學習。若是你設置學習參數爲false,該神經網絡將簡單地處理輸入並不進行學習。咱們將在下一節討論輸入處理。
monitor.setPatterns(4); monitor.setTotCicles(20000); monitor.setLearning(true); |
如今咱們已經爲訓練過程做好準備。調用監視器的Go方法將在後臺啓動訓練過程。
神經網絡如今將要被訓練20,000個週期。當神經網絡訓練完成,偏差層應該在一個合理的低級別上。通常低於10%的偏差級是可接受的。
運行神經網絡
如今,既然神經網絡已經訓練開始,咱們能夠經過提供輸入模式給神經網絡來測試它並 觀察結果。用於運行神經網絡的方法必須首先爲神經網絡處理數據做好準備。目前,該神經網絡處理一種訓練方式中。首先,咱們將從輸出層刪除訓練員。而後,我 們將用FileOutputSynapse替換訓練員,以便於咱們能記錄來自於神經網絡的輸出。下面的代碼實現這一點:
output.removeOutputSynapse(trainer); FileOutputSynapse results = new FileOutputSynapse(); results.setFileName(resultFile.getText()); |
如今咱們必須重置輸入流--咱們將使用與訓練期間同樣的文件輸入流。這將填入在神經網絡訓練期間使用的相同的輸入。
inputStream.resetInput(); samples.resetInput(); results.setMonitor(monitor); output.addOutputSynapse(results); |
而後,咱們必須重啓響應於該神經網絡全部的線程。
input.start(); hidden.start(); output.start(); trainer.start(); |
如今,既然線程已被從新啓動,咱們必須爲下一步的識別設置一些基本配置信息。下面代碼完成這些工做。
monitor.setPatterns(4); monitor.setTotCicles(1); monitor.setLearning(false); |
首先,輸入模式數要置爲4,這是由於咱們想要神經網絡處理全部這四種輸入模式(你之前爲訓練該神經網絡提供的)。最後,置爲學習方式。這些完成後,咱們能夠調用監視器的"Go"方法。
當訓練完成,你將看到輸出文件產生的結果相似列表2。
列表2:來自於神經網絡的輸出
0.012549763955262739
0.9854631848890223
0.9853159647305264
0.01783622084836082
能夠看出,上面列表中的第一行中的數字合理地接近於零。這是很好的,由於輸入訓練文件的第一行,如列表1所示,被預期結果是爲零的。一樣,第二行合理地接近於1,這也很好,由於訓練文件的第二行被預期結果也是爲1的。
結論 JOONE引擎封裝了神經網絡編程中的具備至關多的複雜性,本文的例子顯示了神經網絡使用的基本過程。儘管真實世界中神經網絡的實現將複雜得多,可是其 基本處理過程是同樣的--數據被提供到神經網絡用於訓練,而後生成新的模式用於識別。這裏的例程爲用JOONE進行探索提供了一個良好的開端。