◆版權聲明:本文出自胖喵~的博客,轉載必須註明出處。html
轉載請註明出處:http://www.javashuo.com/article/p-qyokzyab-m.html
python
目前機器學習、深度學習在業界使用的愈來愈普遍,作爲一個有着技術追求的it人,我以爲有必要學習和了解一下這塊的知識,今天就從最簡單的單層神經網絡開始介紹。算法
在介紹人工神經網絡以前,首先認知下神經元。spring
不知道你們還有印象這個圖嗎?這個是出如今咱們生物課本中的一幅圖。springboot
一個神經元的組成基本就是上圖這些東西組成。網絡
一般一個神經元具備多個樹突,主要用來接受傳入信息信息,信息經過軸突傳遞進來後通過一系列的計算(細胞核)最終產生一個信號傳遞到軸突,軸突只有一條,軸突尾端有許多軸突末梢能夠給其餘多個神經元傳遞信息。軸突末梢跟其餘神經元的樹突產生鏈接,從而傳遞信號。這個鏈接的位置在生物學上叫作「突觸」。機器學習
也就是說一個神經元接入了多個輸入,最終只變成一個輸出,給到了後面的神經元,那麼基於此,咱們嘗試去構造一個相似的結構。函數
神經元的樹突咱們類比爲多條輸入,而軸突能夠類比爲最終的輸出。學習
這裏咱們構造一個典型的神經元模型,該模型包含有3個輸入,1個輸出,以及中間的計算功能。spa
注意在每個輸入的「鏈接」上,都有一個對應的「權值」。
說個通俗的例子來理解下權值。好比今天你要決定今是否要去看電影,可能要考慮這3個因素: 一、女友有沒有時間,二、有沒有好看的電影,三、今天工做忙不忙; 而這三個因素對於每一個人來講權重都是不一樣的,由於有的人看重工做、有的人看重家人,不一樣的權重最終的結果也會不同。
所以權重的大小是比較關鍵的。而一個神經網絡的訓練算法就是讓權重的值調整到最佳,以便使得整個網絡的預測效果最好。
接下里,咱們用數學的方式來表示一下神經元,咱們定義 w爲權重,x爲輸入
$$ w = \begin{bmatrix} w_{1} \\ ... \\ w_{m} \end{bmatrix} , x = \begin{bmatrix} x_{1} \\ ... \\ x_{m} \end{bmatrix}$$
$$ z = w_{1} * x_{1} + ... + w_{m} * x_{m} $$
z輸入的總和,也就是這兩個矩陣的點乘,也叫內積。這裏補充點數學知識。
$$ z = w_{1} * x_{1} + ... + w_{m} * x_{m} = \sum\limits_{j=1}^{m} w_{j} * w_{j} = w^{T}*x $$
$\phi$(z) = { 1 if z>=θ; -1 otherwise
注意這裏有一個閾值 θ ,閾值的肯定也須要在訓練過程當中進行完成。
那麼如何進行訓練,這裏的咱們須要用到感知器(preceptron)算法,具體過程分爲下面這麼幾個步驟:
一、首先將權重向量w進行初始化,能夠爲0或者是[0,1]之間的隨機數;
二、將訓練樣本輸入感知器(計算內積後輸入激活函數獲得最終結果),最後獲得分類的結果(結果爲1 或 -1);
三、根據分類的結果再次更新權重向量w;
前面提到激活函數是當z值大於必定的閾值 θ 後,才進行激活或者不激活。所以爲了計算方便呢,咱們再多加入一組向量,w0 和 x0 ,w 取 -θ ,x0 取 1;將其放到等式左邊,這樣當 z>0 的時候 激活函數輸出 1,而 z<0 激活函數輸出 -1。
$$ z = w_{0} * x_{0} + w_{1} * x_{1} + ... + w_{m} * x_{m} $$
$\phi$(z) = { 1 if z>=0; -1 otherwise
權重更新
好,前面全部的準備都已經完成,接下來咱們看下剛纔提到的第三步,權重向量的更新,其實也就是神經網絡訓練的過程:
權重的更新每一輪迭代 Wj = Wj+ ▽Wj
而 ▽Wj = η * ( y - y' ) * Xj
上式中 η 叫作學習率,是[0, 1]之間的一個小數,由咱們本身定義;y是真實 的樣本分類,而 y’ 是感知器計算出來的分類。
咱們能夠簡單推導一下,當 y 和 y' 相等,▽Wj 的值爲0,Wj則不會更新。對應的意義就是真實和預測的結果是相同的,所以權重也不須要再更新了。
這裏舉個例子 :
假設初始化 W = [ 0, 0, 0] , X = [1, 2, 3], 假設定義 η = 0.3,y = 1,y' = -1
▽W(1) = 0.3 * (1 - (-1)) * X(1) = 0.3*2*1 = 0.6; W(1) = W(1) + ▽W(1) = 0.6;
▽W(2) = 0.3 * (1 - (-1)) * X(2) = 0.3*2*2 = 1.2; W(1) = W(1) + ▽W(1) = 1.2;
▽W(3) = 0.3 * (1 - (-1)) * X(3) = 0.3*2*3 = 1.8; W(1) = W(1) + ▽W(1) = 1.8;
更新以後的向量 w = [0.6, 1.2, 1.8] 而後接着繼續計算,更新。
閾值更新
前面提到,咱們將閾值通過變換後變成了 w0,再每一輪的迭代訓練過程當中,w0也須要跟着一塊兒更新。
最初w0 也須要初始化爲0,由於x0等於1,所以 ▽W(0) = η * ( y - y' ) ;
這裏不少人可能會和我開始有同樣的疑惑,閾值不是提早定義好的嗎?其實不是的,這裏不斷的迭代,其實就是閥值計算的過程,和權重向量同樣,最終都是經過一輪一輪更新計算出來的,因爲一開始咱們設定的w0 = - θ,因此當最終咱們的閥值更新出來後,-w0 就是咱們學習出來的閥值。
看到上面的過程是否有些暈,從總體上看,其實就是這樣一個過程:
初始化權重向量和閾值,而後計算預測結果和真實結果是否存在偏差,有偏差就根據結果不斷的更新權重,直到權重計算的結果最終達到最佳,權重的值就是咱們學習出的規律。
感知器目前的適用場景爲線性可分的場景,就是用一條直線能夠分割的二分類問題。
用python實現了上述過程,能夠看下:
#-*- coding:utf-8 -*- # 簡單神經網絡 感知器 import numpy as np reload(sys) sys.setdefaultencoding("utf-8") class Perception(object): ''' eta: 學習率 η time: 訓練次數 w_: 權重向量 ''' def __init__(self, eta = 0.01, time=10): self.eta = eta self.time = time pass ''' 輸入訓練數據,X爲輸入樣本向量,y對應樣本分類 X:shape[n_samples, n_features] X:[[1,2,3], [4,5,6]] n_samples : 2 n_features: 3 y:[1, -1] ''' def fit(self, X, y): # 初始化權重向量爲0,加一爲w0,也就是損失函數的閾值 self.w_ = np.zero[1 + X.shape[1]] self.errors_ = [] for _ in range(self.time): errors = 0 # x:[[1,2,3], [4,5,6]] # y:[1, -1] # zip(X,y) = [[1,2,3,1], [4,5,6.-1]] for xi, target in zip(X, y): # update = η * ( y - y' ) update = self.eta * (target - self.predict(xi)) # xi 爲向量, 這裏每一個向量都會乘 self.w_[1:] += update * xi self.w_[0] += update; errors += int(update != 0.0) pass # 損失函數 def predict(self, X): # z = w1*x1+...+wj*xj + w0*1 z = np.dot(X, self.w_[1:]) + self.w_[0] # 損失函數 if z >= 0.0: return 1 else: return -1