[Python人工智慧] 一.神經網路入門及theano基礎程式碼講解

Eastmount發表於2018-05-18

從本篇文章開始,作者正式開始研究Python深度學習、神經網路及人工智慧相關知識。第一篇文章主要講解神經網路基礎概念,同時講解Theano庫的安裝過程及基礎用法,主要結合 "莫煩大神" 的視訊介紹,後面隨著深入會講解具體的專案及應用。基礎性文章,希望對您有所幫助,也建議大家一步步跟著學習,同時文章中存在錯誤或不足之處,還請海涵~

同時推薦前面作者另外三個Python系列文章。

從2014年開始,作者主要寫了三個Python系列文章,分別是基礎知識、網路爬蟲和資料分析。

這裡寫圖片描述 這裡寫圖片描述 這裡寫圖片描述


一. 神經網路入門

該部分主要通過白話文的方式講述神經網路,其中主要轉載吳老的文章。連結:
    吳祖增前輩:神經網路入門(連載之一)
    吳祖增前輩:神經網路入門(連載之二)
    史丹佛機器學習視訊NG教授 https://class.coursera.org/ml/class/index
    書籍《遊戲開發中的人工智慧》、《遊戲程式設計中的人工智慧技術》
    神經網路和機器學習基礎入門分享 - eastmount


神經網路(也稱人工神經網路,ANN)演算法是80年代機器學習界非常流行的演算法,不過在90年代中途衰落。現在,攜著“深度學習”之勢,神經網路重灌歸來,重新成為最強大的機器學習演算法之一。

人工神經網路(Artificial Neural Network,縮寫ANN),是一種模仿生物神經網路的結構和功能的數學模型或計算模型。神經網路由大量的人工神經元聯結進行計算。其來源於生物,故吳老先先講述了生物神經網路的基礎知識,從而進行引入。



神經細胞通過軸突將訊號傳遞給其他的神經細胞,通過樹突向各個方向接受訊號。
神經細胞利用電-化學過程交換訊號。輸入訊號來自另一些神經細胞。這些神經細胞的軸突末梢(也就是終端)和本神經細胞的樹突相遇形成突觸(synapse),訊號就從樹突上的突觸進入本細胞。
訊號在大腦中實際怎樣傳輸是一個相當複雜的過程,但就我們而言,重要的是把它看成和現代的計算機一樣,利用一系列的0和1來進行操作。就是說,大腦的神經細胞也只有兩種狀態:興奮(fire)和不興奮(即抑制)。


    
神經細胞利用一種我們還不知道的方法,把所有從樹突突觸上進來的訊號進行相加,如果全部訊號的總和超過某個閥值,就會激發神經細胞進入興奮(fire)狀態,這時就會有一個電訊號通過軸突傳送出去給其他神經細胞。如果訊號總和沒有達到閥值,神經細胞就不會興奮起來。這樣的解釋有點過分簡單化,但已能滿足我們的目的。


由於人腦具有一下幾個特點:
    1.能實現無監督的學習
    大腦能夠自己進行學習,而不需要導師的監督教導。如果一個神經細胞在一段時間內受到高頻率的刺激,則它和輸入訊號的神經細胞之間的連線強度就會按某種過程改變,使得該神經細胞下一次受到激勵時更容易興奮。
    2.對損傷有冗餘性(tolerance)
    大腦即使有很大一部分受到了損傷, 它仍然能夠執行復雜的工作。
    3.處理資訊的效率極高
    神經細胞之間電-化學訊號的傳遞,與一臺數字計算機中CPU的資料傳輸相比,速度是非常慢的,但因神經細胞採用了並行的工作方式,使得大腦能夠同時處理大量的資料。例如,大腦視覺皮層在處理通過我們的視網膜輸入的一幅圖象訊號時,大約只要100ms的時間就能完成,眼睛併發執行。
    4.善於歸納推廣
    大腦和數字計算機不同,它極擅長的事情之一就是模式識別,並能根據已熟悉資訊進行歸納推廣(generlize)。例如,我們能夠閱讀他人所寫的手稿上的文字,即使我們以前從來沒見過他所寫的東西。 
    5.它是有意識的


如下圖所示,它表示的是一個人工神經細胞。其中:
輸入(Input);權重(Weight):左邊五個灰色圓底字母w代表浮點數;激勵函式(Activation Function):大圓,所有經過權重調整後的輸入加起來,形成單個的激勵值;輸出(Output):神經細胞的輸出。


進入人工神經細胞的每一個input(輸入)都與一個權重w相聯絡,正是這些權重將決定神經網路的整體活躍性。假設權重為-1和1之間的一個隨機數,權重可正可負(激發和抑制作用)。當輸入訊號進入神經細胞時,它們的值將與它們對應的權重相乘,作為圖中大圓的輸入。如果激勵值超過某個閥值(假設閥值為1.0),就會產生一個值為1的訊號輸出;如果激勵值小於閥值1.0,則輸出一個0。這是人工神經細胞激勵函式的一種最簡單的型別。涉及的數學知識如下圖所示:


如果最後計算的結果激勵值大於閾值1.0,則神經細胞就輸出1;如果激勵值小於閾值則輸出0。這和一個生物神經細胞的興奮狀態或抑制狀態是等價的。下面圖是通過神經網路實現邏輯表示式與運算:(參考NG史丹佛機器學習講義)


可以看到x1和x2變數作為神經網路的輸入,當它們取不同的0或1值時,其結果通過sigmod函式計算的值是不同的。它模擬了整個AND運算。


該圖中神經網路共有三層 ( 注輸入層不是神經細胞,神經細胞只有兩層 ):
輸入層中的每個輸入都饋送到了隱藏層,作為該層每一個神經細胞的輸入;然後,從隱藏層的每個神經細胞的輸出都連到了它下一層(即輸出層)的每一個神經細胞。
注意:
1.圖中僅僅畫了一個隱藏層,作為前饋網路,一般地可以有任意多個隱藏層。但在對付你將處理的大多數問題時一層通常是足夠的。
2.事實上,有一些問題甚至根本不需要任何隱藏單元,你只要把那些輸入直接連結到輸出神經細胞就行了。
3.每一層實際都可以有任何數目的神經細胞,這完全取決於要解決的問題的複雜性。但神經細胞數目愈多,網路的工作速度也就愈低,網路的規模總是要求保持儘可能的小。



神經網路體系建立成功後,它必須接受訓練來認出數字4,方法:
1.先把神經網路的所有權重初始化為任意值;
2.再給他一系列輸入代表皮膚不同配置的輸入,對每種輸入配置,檢查它的輸出是什麼,並調整相應權重;
3.如果我們送給網路的輸入模式不是4,則我們知道網路應該輸出一個0。因此每個非4字元時,網路權重應進行調整,使得它的輸出趨向於0;當代表4的模式輸送給網路時,則應把權重調整到使其輸出趨向於1;
4.我們可以進一步識別0到9的所有數字或字母,其本質是手寫識別的工作原理。
5.最後,網路不單能認識已經訓練的筆跡,還顯示了它有顯著的歸納和推廣能力。

正是這種歸納推廣能力,使得神經網路已經成為能夠用於無數應用的一種無價的工具,從人臉識別、醫學診斷,直到跑馬賽的預測,另外還有電腦遊戲中的bot(作為遊戲角色的機器人)的導航,或者硬體的robot(真正的機器人)的導航。


上圖會演示神經網路在影象識別領域的一個著名應用,這個程式叫做LeNet,是一個基於多個隱層構建的神經網路。通過LeNet可以識別多種手寫數字,並且達到很高的識別精度與擁有較好的魯棒性。LeNet的發明人是機器學習的大牛Yann LeCun(目前google)。
右下方的方形中顯示的是輸入計算機的影象,方形上方的紅色字樣“answer”後面顯示的是計算機的輸出。左邊的三條豎直的影象列顯示的是神經網路中三個隱藏層的輸出,可以看出,隨著層次的不斷深入,越深的層次處理的細節越低,例如層3基本處理的都已經是線的細節了。
        
這種型別的訓練稱作有監督的學習(supervised learnig),用來訓練的資料稱為訓練集(training set)。調整權重可以採用許多不同的方法。對本類問題最常用的方法就是反向傳播(backpropagation,簡稱backprop或BP)方法,即BP神經網路。
你自己可以去學習另外的一種訓練方式,即根本不需要任何導師來監督的訓練,或稱無監督學習(unsupervised learnig)。下圖是神經網路的簡單回顧與總結:

最後給大家看一個利用神經網路對圖片進行分類的例子:過程就不詳細論述了,圖片很清晰,對人、汽車、摩托車、卡車進行圖片識別,而具體的隱藏層函式需要大家去深入研究,我自己研究得也很淺顯,抱歉~



下面簡單講解"莫煩大神"網易雲課程的一個示例。假設存在千萬張圖片,現在需要通過神經網路識別出某一張圖片是狗還是貓,如下圖所示共包括輸入層、隱藏層(3層)和輸出層




計算機通過訓練或強化學習判斷貓,將獲取的特徵轉換為數學的形式。首先得到一堆數字,通過判斷處理得到另一堆資料,最終判斷其是狗還是貓。比如第一次正確識別的只有10%,下面那隻貓被識別成狗,它會將識別錯誤的資訊(與真實答案的差別)反向傳遞迴神經網路,並修改神經元權重,為下次更好地識別。



每一個神經元都有一個激勵函式,被激勵的神經元傳遞的資訊最有價值,它也決定最後的輸出結果,經過海量資料的訓練,最終神經網路將可以用於識別貓或狗。



參考資料包括NG教授的課程講義和CSDN一位很厲害的女博主Rachel-Zhang:

Stanford機器學習---第五講. 神經網路的學習 Neural Networks learning





二. theano安裝及入門

1.基礎知識

Theano在深度學習框架中是祖師級的存在。它的開發始於2007,早期開發者包括傳奇人物Yoshua Bengio和Ian Goodfellow。Theano基於Python,是一個擅長處理多維陣列的庫(這方面它類似於 NumPy)。當與其他深度學習庫結合起來,它十分適合資料探索。它為執行深度學習中大規模神經網路演算法的運算所設計。其實,它可以被更好地理解為一個數學表示式的編譯器:用符號式語言定義你想要的結果,該框架會對你的程式進行編譯,來高效執行於GPU或CPU。 

它與後來出現的Tensorflow功能十分相似(或者應該說,Tensorflow 類似 Theano ),因而兩者常常被放在一起比較。它們本身都偏底層,同樣的,Theano 像是一個研究平臺多過是一個深度學習庫。你需要從底層開始做許多工作,來建立你需要的模型。比方說,Theano 沒有神經網路的分級。


下面開始講解Theano的安裝過程,主要呼叫 "pip install theano" 安裝,如下圖所示:



安裝成功之後,下面給出基礎性的程式碼。這也是學習莫煩大神的雲課程筆記,希望對您有所幫助。
莫煩大神地址:
http://study.163.com/course/courseLearn.htm?courseId=1003215006

2.存量變數使用

首先匯入相關包,然後定義存量x和y,再進行相加計算。由於theano需要用到cpu或gpu,所以其function定義比較特殊,核心程式碼為f = function([x,y],z)。

#coding:utf-8
import numpy as np
import theano.tensor as T
from theano import function

#存量相加
x = T.dscalar('x')
y = T.dscalar('y')
z = x + y

#輸入[x,y]列表 輸出結果z
f = function([x,y],z) 

#呼叫函式 
print(f(2,3))

#to pretty-print the function
##檢視z函式原型,輸出(x+y)
from theano import pp
print(pp(z))

輸出結果如下所示:

5.0
(x + y)


3.矩陣變數使用

定義兩個矩陣x和y,均為3行4列,其中x通過np.arange(12).reshape((3,4))程式碼定義,為0-11數字;y通過10*np.ones((3,4))程式碼定義,全部為10。

#coding:utf-8
import numpy as np
import theano.tensor as T
from theano import function

#定義矩陣 matrix
x = T.dmatrix('x')
y = T.dmatrix('y')
z = x + y

#矩陣的加法
f = function([x,y],z)

#3行4列矩陣 y全部為10 x從0-11
print(u"輸入矩陣")
print(np.arange(12).reshape((3,4)))
print(10*np.ones((3,4)))
print(u"輸出結果")
print(f(np.arange(12).reshape((3,4)),
        10*np.ones((3,4))
        ))

計算結果如下圖所示:



如果需要實現乘法,則使用z = T.dot(x,y) 程式碼實現。


三. theano函式

theano運用CPU、GPU加速和平行計算,會自己定義function,下面詳細講解其函式功能。

1.激勵函式
神經網路中的神經元中都有激勵函式(activation function),這裡我們定義邏輯迴歸的激勵函式,常見的激勵函式參考維基百科:
https://en.wikipedia.org/wiki/Activation_function

然後對一個2*2的矩陣進行計算,程式碼如下:
#coding:utf-8
import numpy as np
import theano.tensor as T
import theano
from theano import function

#1.激勵函式
#activation function example
x = T.dmatrix('x')
#計算概率 logistic or soft step
s = 1/(1+T.exp(-x)) #np.exp() 這裡用的theano中的T.exp()
#輸入x 輸出s
logistic =theano.function([x],s)
#兩行兩列矩陣
print(logistic([[0,1],[2,3]]))
#wikipedia: Activation function
#輸入0 輸出s=1/(1+e0次方)=0.5

輸出結果如下所示,比如當數值為0時,其結果為s=1/(1+e的0次方)=0.5。

[[0.5        0.73105858]
 [0.88079708 0.95257413]]

2.返回多個值
輸入為a和b變數,輸出為差值、差值絕對值、差值平法和。核心程式碼如下:
f = theano.function([a,b],[diff,abs_diff,diff_squared])

#coding:utf-8
import numpy as np
import theano.tensor as T
import theano
from theano import function

#2.返回多個值或結果
#multiply outputs for a function
a,b = T.dmatrices('a','b')
#定義兩個的差的絕對值和平方
diff = a - b
abs_diff = abs(diff)   #差值絕對值
diff_squared = diff*2  
f = theano.function([a,b],[diff,abs_diff,diff_squared])

#[1,1,1,1] [0,1,2,3]
x1,x2,x3 = f(np.ones((2,2)),
        np.arange(4).reshape((2,2)))
print(x1)
print(x2)
print(x3)

輸出結果如下所示:

[[ 1.  0.]
 [-1. -2.]]
[[1. 0.]
 [1. 2.]]
[[ 2.  0.]
 [-2. -4.]]


3.函式賦初值

#coding:utf-8
import numpy as np
import theano.tensor as T
import theano
from theano import function

#3.如何運用function名字更加方便
#name for a function
#定義存量
x,y,w = T.dscalars('x','y','w')
z = (x+y)*w
#定義預設值和名字
f = theano.function([x,theano.In(y,value=1),
                     theano.In(w, value=2, name='weight')],
                    z)
print(f(23,2))
#(23+2)*2=50
print(f(23,2,weight=4))
#(23+2)*4=100

輸出結果如下所示:

50.0
100.0

(By:Eastmount 2018-05-18 下午4點
  http://blog.csdn.net/eastmount/ )


相關文章