[Python人工智慧] 三.theano實現分類神經網路及機器學習基礎

Eastmount發表於2018-05-24

從本篇文章開始,作者正式開始研究Python深度學習、神經網路及人工智慧相關知識。前兩篇文章講解了神經網路基礎概念、Theano庫的安裝過程及基礎用法、theano實現迴歸神經網路,這篇文章主要講解機器學習的基礎知識,再通過theano實現分類神經網路,主要是學習"莫煩大神" 網易雲視訊的線上筆記,後面隨著深入會講解具體的專案及應用。基礎性文章,希望對您有所幫助,也建議大家一步步跟著學習,同時文章中存在錯誤或不足之處,還請海涵~

"莫煩大神" 網易雲視訊地址:http://study.163.com/provider/1111519/course.html

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

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

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

前文參考:
[Python人工智慧] 一.神經網路入門及theano基礎程式碼講解
[Python人工智慧] 二.theano實現迴歸神經網路分析




一.機器學習基礎

首先第一部分也是莫煩老師的線上學習筆記,個人感覺挺好的基礎知識,推薦給大家學習。對機器學習進行分類,包括:
    1.監督學習:通過資料和標籤進行學習,比如從海量圖片中學習模型來判斷是狗還是貓,包括分類、迴歸、神經網路等演算法;

    2.無監督學習:只有資料沒有類標,根據資料特徵的相似性形成規律,比如不知道類標的情況進行分類貓或狗,常見的聚類演算法(物以類聚);

    3.半監督學習:綜合了監督學習和無監督學習,通過少量有標籤樣本和大量沒有標籤樣本進行訓練和分類,有效提升了兩者效果;
    4.強化學習:常用於規劃機器人行為準則,把計算機置於陌生環境去完成一項未知任務,比如投籃,它會自己總結失敗經驗和投籃命中的經驗,進而懲罰或獎勵機器人從而提升命中率,比如阿爾法狗;

    5.遺傳演算法:和強化學習類似,通過淘汰機制去選擇最優模型,比如自己玩超級馬里奧,淘汰前面幾代差的,基於強者的"遺傳和變異",適者生存,弱者淘汰的原理。



二.神經網路基礎

神經網路也稱為人工神經網路ANN(Artifical Neural Network),是80年代非常流行的機器學習演算法,在90年代衰退,現在隨著"深度學習"和"人工智慧"之勢重新歸來,成為最強大的機器學習演算法之一。

神經網路是模擬生物神經網路結構和功能的計算模型,由很多神經層組成,每一層存在著很多神經元,這些神經元是識別事物的關鍵。神經網路通過這些神經元進行計算學習,每個神經元有相關的激勵函式(sigmoid、Softmax、tanh等),包括輸入層、隱藏層(可多層或無)和輸出層,當神經元計算結果大於某個閾值時會產生積極作用(輸出1),相反產生抑制作用(輸出0),常見的型別包括迴歸神經網路(畫線擬合一堆散點)和分類神經網路(影象識別分類)。

例如下面的示例,通過海量圖片學習來判斷一張圖片是狗還是貓,通過提取圖片特徵轉換為數學形式來判斷,如果判斷是狗則會反向傳遞這些錯誤資訊(預測值與真實值差值)回神經網路,並修改神經元權重,通過反覆學習來優化識別。

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




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



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




三. theano實現分類神經網路

下面講解分類神經網路的實現:

1.定義函式計算正確率

正確率為預測正確的數目佔真實樣本數的百分比,程式碼如下:

#coding:utf-8
#參考:http://study.163.com/course/courseLearn.htm?courseId=1003215006
import numpy as np
import theano.tensor as T
import theano
from theano import function

#正確率函式:預測正確數佔真實值數的百分比
def computer_accuracy(y_target, y_predict):
    correct_prediction = np.equal(y_predict, y_target)
    accuracy = np.sum(correct_prediction)/len(correct_prediction)
    return accuracy

2.隨機生成資料
訓練樣本為N,400個樣本;輸入特徵數為feats,784個特徵;隨機生成資料,D = (input_values, target_class),包括輸入資料和類標,其中:
  (1) rng.randn(N, feats)生成400行,每行784個特徵的標註正態分佈資料;
  (2) rng.randint(size=N, low=0, high=2)隨機生成兩個類別比如0和1,0代表一個類,1代表另一個類,比如貓和狗。
然後進行訓練,神經網路辨別哪些是狗哪些是對應的貓。接下來編輯神經網路,用D放到圖片中進行訓練。

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

#定義分類:預測正確數佔真實值數的百分比
def computer_accuracy(y_target, y_predict):
    correct_prediction = np.equal(y_predict, y_target)
    accuracy = np.sum(correct_prediction)/len(correct_prediction)
    return accuracy

#生成虛擬的data
rng = np.random

#訓練數量:400個學習樣本
N = 400
#輸入特徵數
feats = 784
#generate a datasets: D = (input_values, target_class)
D = (rng.randn(N, feats), rng.randint(size=N, low=0, high=2))
print(D)
輸出的資料如下圖所示:
(array([[-1.03486767,  0.09141203, -2.14011897, ...,  0.24325359,
        -1.07465997,  0.74784503],
       [ 1.09143969,  1.5014381 , -0.12580536, ..., -1.63516987,
         0.51615268,  1.51542425],
       [ 1.26905541, -0.54147591, -0.23159387, ...,  0.22647348,
        -0.93035893,  1.19128709],
       ...,
       [-0.53222844,  0.05877263, -1.05092742, ..., -1.07296129,
         1.11237909,  0.86891936],
       [-2.91024609,  0.09091794, -2.34392907, ..., -1.09686952,
         1.08838878,  0.79766499],
       [ 0.12949081, -0.0893665 , -0.43766707, ..., -0.66029383,
         0.03997112,  1.05149843]]), 
array([1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1,
       1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1,
       1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0,
       0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1,
       1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1,
       0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1,
       0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0,
       1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1,
       1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1,
       0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0,
       0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1,
       1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0,
       0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0,
       1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1,
       0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1,
       1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1,
       0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1,
       1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0,
       0, 1, 0, 1]))

3.定義變數和初始化權重
定義Theano變數,其中x為T.dmatrix型別,y因為輸出只是一個型別型別0或1,故使用dvector,也可以使用dmatrix。同時初始化權重和bias,這裡不新增神經網路層,直接使用輸入層和輸出層,讀者可以結合上節課程自己定義。

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

#定義分類:預測正確數佔真實值數的百分比
def computer_accuracy(y_target, y_predict):
    correct_prediction = np.equal(y_predict, y_target)
    accuracy = np.sum(correct_prediction)/len(correct_prediction)
    return accuracy

#生成虛擬的data
rng = np.random

#訓練數量:400個學習樣本
N = 400
#輸入特徵數
feats = 784
#generate a datasets: D = (input_values, target_class)
#target_class: 隨機分成兩個類別,隨機生成0和1
D = (rng.randn(N, feats), rng.randint(size=N, low=0, high=2))
print(D)


#Declare Theano symbolic variables
x = T.dmatrix('x')
y = T.dvector('y')
print(x,y)

#initialize the weights and bias
#初始化權重和bias
W = theano.shared(rng.randn(feats), name='w') #生成feats個的隨機權重W,並且給個名字w
b =  theano.shared(0.1, name='b')
print(W)
print(b)
輸出結果如下圖所示:

4.定義計算誤差
p_1 = T.nnet.sigmoid(T.dot(x,W) + b) 
sigmoid激勵函式(activation function)用來求概率的,如果輸入的數越小,概率越接近0,輸入越大,概率越接近1。這裡將x與W乘積加b(T.dot(x,W) + b)放到激勵函式中去。

prediction = p_1 > 0.5

定義預測值,當值大於0.5時讓它等於True。

xent = -y*T.log(p_1)-(1-y)*T.log(1-p_1)
定義Cross-entropy loss function,它可以理解為cost誤差,前面cost使用是平方差和,這裡使用的是上述公式。

cost = xent.mean()  + 0.01 * (W**2).sum()
由於xent是針對每一個樣本的cost,需要求平均值變成單獨的一個cost,對於整批資料的cost,故cost = xent.mean()求平均值。同時,為了克服Overfitted,在計算cost時增加 一個值(下節課補充),即0.01 * (W**2).sum()。

gW, gb = T.grad(cost, [W,b])
計算cost的梯度,這裡理解為整個視窗的小控制元件。

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

#定義分類:預測正確數佔真實值數的百分比
def computer_accuracy(y_target, y_predict):
    correct_prediction = np.equal(y_predict, y_target)
    accuracy = np.sum(correct_prediction)/len(correct_prediction)
    return accuracy

#生成虛擬的data
rng = np.random

#訓練數量:400個學習樣本
N = 400
#輸入特徵數
feats = 784
#generate a datasets: D = (input_values, target_class)
#target_class: 隨機分成兩個類別,隨機生成0和1
D = (rng.randn(N, feats), rng.randint(size=N, low=0, high=2))
print(D)


#Declare Theano symbolic variables
x = T.dmatrix('x')
y = T.dvector('y')
print(x,y)

#initialize the weights and bias
#初始化權重和bias
W = theano.shared(rng.randn(feats), name='w') #生成feats個的隨機權重W,並且給個名字w
b =  theano.shared(0.1, name='b')
print(W)
print(b)


#Construct Theano expression graph
#定義計算誤差,激勵函式sigmoid: 如果輸入的數越小,概率越接近0,輸入越大,概率越接近1
p_1 = T.nnet.sigmoid(T.dot(x,W) + b)
print(p_1)
#輸入的數是神經網路加工後的值T.dot(x,W) + b), 然後再將這個放到激勵函式中去

#大於0.1的值讓它等於True
prediction = p_1 > 0.5

#梯度下降,可以理解為cost(誤差)
#Cross-entropy loss function
xent = -y*T.log(p_1)-(1-y)*T.log(1-p_1)
print(xent)

cost = xent.mean() #平均值
#The cost to minimize
cost = xent.mean()  + 0.01 * (W**2).sum() #l2:為了克服Overfitted,在計算cost時加上值
print(cost)

#Compute the gradient of the cost
gW, gb = T.grad(cost, [W,b])
print(gW,gb)
輸出值如下:
p_1 => sigmoid.0
xent => Elemwise{sub,no_inplace}.0
cost => Elemwise{add,no_inplace}.0
gW,gb => Elemwise{add,no_inplace}.0 InplaceDimShuffle{}.0

5.編輯函式和編譯模型
呼叫theano.function函式編譯模型,兩個輸出即預測值和xent平均值,然後更新權重和bias,將學習的W-learning_rate*gW更新為W和b。同時,定義預測值。

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

#定義分類:預測正確數佔真實值數的百分比
def computer_accuracy(y_target, y_predict):
    correct_prediction = np.equal(y_predict, y_target)
    accuracy = np.sum(correct_prediction)/len(correct_prediction)
    return accuracy

#生成虛擬的data
rng = np.random

#訓練數量:400個學習樣本
N = 400
#輸入特徵數
feats = 784
#generate a datasets: D = (input_values, target_class)
#target_class: 隨機分成兩個類別,隨機生成0和1
D = (rng.randn(N, feats), rng.randint(size=N, low=0, high=2))
print(D)


#Declare Theano symbolic variables
x = T.dmatrix('x')
y = T.dvector('y')
print(x,y)

#initialize the weights and bias
#初始化權重和bias
W = theano.shared(rng.randn(feats), name='w') #生成feats個的隨機權重W,並且給個名字w
b =  theano.shared(0.1, name='b')
print(W)
print(b)


#Construct Theano expression graph
#定義計算誤差,激勵函式sigmoid: 如果輸入的數越小,概率越接近0,輸入越大,概率越接近1
p_1 = T.nnet.sigmoid(T.dot(x,W) + b)
print(p_1)
#輸入的數是神經網路加工後的值T.dot(x,W) + b), 然後再將這個放到激勵函式中去

#大於0.1的值讓它等於True
prediction = p_1 > 0.5

#梯度下降,可以理解為cost(誤差)
#Cross-entropy loss function
xent = -y*T.log(p_1)-(1-y)*T.log(1-p_1)
print(xent)

cost = xent.mean() #平均值
#The cost to minimize
cost = xent.mean()  + 0.01 * (W**2).sum() #l2:為了克服Overfitted,在計算cost時加上值
print(cost)

#Compute the gradient of the cost
gW, gb = T.grad(cost, [W,b])
print(gW,gb)


#compile
#編輯函式
learning_rate = 0.1 #學習率
train = theano.function(
    inputs=[x,y],
    outputs=[prediction, xent.mean()],
    updates=((W, W-learning_rate*gW),
             (b, b-learning_rate*gb))
    ) #兩個輸出,更新兩個資料

#定義預測 預測值為x
predict = theano.function(inputs=[x], outputs=prediction)
6.訓練和預測
接下來通過for迴圈輸出結果,其中呼叫train(D[0],D[1])進行訓練。
  D[0]:D = (input_values, target_class)的第一個值,即輸入變數;
  D[1]:D = (input_values, target_class)的第二個值,即類標;
然後每隔50步輸出結果,並檢視預測正確率,函式如下:
computer_accuracy(D[1], predict(D[0]))
其中D[1]為真實的類標值,predict(D[0])是對資料預測的類標值,並計算正確率,最後輸出結果。

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

#定義分類:預測正確數佔真實值數的百分比
def computer_accuracy(y_target, y_predict):
    correct_prediction = np.equal(y_predict, y_target)
    accuracy = np.sum(correct_prediction)/len(correct_prediction)
    return accuracy

#生成虛擬的data
rng = np.random

#訓練數量:400個學習樣本
N = 400
#輸入特徵數
feats = 784
#generate a datasets: D = (input_values, target_class)
#target_class: 隨機分成兩個類別,隨機生成0和1
D = (rng.randn(N, feats), rng.randint(size=N, low=0, high=2))
print(D)


#Declare Theano symbolic variables
x = T.dmatrix('x')
y = T.dvector('y')
print(x,y)

#initialize the weights and bias
#初始化權重和bias
W = theano.shared(rng.randn(feats), name='w') #生成feats個的隨機權重W,並且給個名字w
b =  theano.shared(0.1, name='b')
print(W)
print(b)


#Construct Theano expression graph
#定義計算誤差,激勵函式sigmoid: 如果輸入的數越小,概率越接近0,輸入越大,概率越接近1
p_1 = T.nnet.sigmoid(T.dot(x,W) + b)
print(p_1)
#輸入的數是神經網路加工後的值T.dot(x,W) + b), 然後再將這個放到激勵函式中去

#大於0.1的值讓它等於True
prediction = p_1 > 0.5

#梯度下降,可以理解為cost(誤差)
#Cross-entropy loss function
xent = -y*T.log(p_1)-(1-y)*T.log(1-p_1)
print(xent)

cost = xent.mean() #平均值
#The cost to minimize
cost = xent.mean()  + 0.01 * (W**2).sum() #l2:為了克服Overfitted,在計算cost時加上值
print(cost)

#Compute the gradient of the cost
gW, gb = T.grad(cost, [W,b])
print(gW,gb)


#compile
#編輯函式
learning_rate = 0.1 #學習率
train = theano.function(
    inputs=[x,y],
    outputs=[prediction, xent.mean()],
    updates=((W, W-learning_rate*gW),
             (b, b-learning_rate*gb))
    ) #兩個輸出,更新兩個資料

#定義預測 預測值為x
predict = theano.function(inputs=[x], outputs=prediction)

#Training
for i in range(500):
    #輸入和輸入標籤 D = (input_values, target_class)
    pred, err = train(D[0],D[1])
    if i % 50 == 0:
        #每50步輸出結果,檢視多少預測正確
        print('cost:', err)
        #計算正確性 computer_accuracy(y_target, y_predict)
        print('accuracy:', computer_accuracy(D[1], predict(D[0])))


#對比兩個結果,看預測是否正確
print("target values for D:")
print(D[1])
print("prediction on D:")
print(predict(D[0]))
輸出結果如下所示,可以看到誤差在不斷減小,其預測正確率也是不斷增加,最後到100%。
cost: 9.907479693928224
accuracy: 0.505
cost: 4.954027420378552
accuracy: 0.6525
cost: 2.1977148473835193
accuracy: 0.75
cost: 0.9396763739879143
accuracy: 0.875
cost: 0.40360223854133126
accuracy: 0.9575
cost: 0.17876663279172963
accuracy: 0.9825
cost: 0.0822797979378536
accuracy: 0.9925
cost: 0.048794195343816946
accuracy: 1.0
cost: 0.04187510776189411
accuracy: 1.0
cost: 0.03908366728475624
accuracy: 1.0

總結:

1.theano構建神經網路一般需要經歷以下步驟:
    (1) 預處理資料
    generate a dataset: D = (input_values, target_class)
    (2) 定義變數
    Declare Theano symbolic variables
    (3) 構建模型
    Construct Theano expression graph
    (4) 編譯模型
    theano.function()
    train = theano.function(inputs=[x,y],outputs=[],updates=((W, W-learning_rate*gW)) 
    predict = theano.function(inputs=[x], outputs=prediction)
    (5) 訓練模型
    train(D[0],D[1])
    (6) 預測新資料
    print(predict(D[0]))
    
2.分類神經網路不同於迴歸神經網路(前一篇文章)之處:
    (1) 激勵函式為T.nnet.sigmoid(T.dot(x,W) + b),會用到求概率的激勵函式;
    (2) 它計算cost規則不同於前面平方差誤差的方法,它用的是xent = -y*T.log(p_1)-(1-y)*T.log(1-p_1)。



推薦資料:
https://blog.csdn.net/zm714981790/article/details/51251759(鳶尾花分類——神經網路詳解)


基礎性文章,希望對您有所幫助,推薦大家閱讀莫煩大神的學習視訊,也建議大家一步步跟著學習。後面作者會結合神經網路分析實際的資料集,並增加隱藏層,希望您喜歡,同時文章中存在錯誤或不足之處,還請海涵~
(By:Eastmount 2018-05-24 晚上12點
  http://blog.csdn.net/eastmount/ )


相關文章