機器學習演算法mini版

Inside_Zhang發表於2015-11-26

深度神經網路

  • 預訓練(pre-training)的本質是引數(權值&&偏置)的初始化(careful initialization)。

  • 自動編碼(autoencoder)的數學意義是尋找approximate identity functiong(x)=x

    g(x)=x

    dW1ijd~W1jid
    d\stackrel{W_{ij}^1}{\longrightarrow}\tilde{d}\stackrel{W_{ji}^1}{\longrightarrow}d

判斷學習的過程是否過慢

以神經網路、以梯度下降學習演算法為例:
判斷學習過程的變化情況,就是判斷代價函式對模型所要學習的量,比如權重CwLjk

\frac{\partial\,C}{\partial\,w_{jk}^L}
的變化情況。

logistic regression

logistic regression是一個基於概率的(probabilistic ),線性分類器(classifier),注意邏輯斯特迴歸是一個分類模型,而不是迴歸模型。

tanh or sigmoid

用作激勵函式的函式是選擇tanh

\tanh
還是sigmoid
sigmoid

tanh(a)=eaeaea+easigmoid(a)=11+ea
\tanh(a)=\frac{e^{a}-e^{-a}}{e^{a}+e^{-a}}\\ sigmoid(a)=\frac{1}{1+e^{-a}}

一般選擇tanh

\tanh
,因為更容易產生更快的學習效率(it typically yields to faster training and sometimes also to better local minima)

SGD(stochastic gradient descent)

SGD=S+GD
\mathrm{SGD=S+GD}

SGD要點有二:

  • 隨機

    S:Stochastic

    \mathrm{S:Stochastic}
    的實現——shuffle
    \mathrm{shuffle}

    np.random.shuffle(training_data)

    或者先隨機地獲得一次排列組合,再進行shuffle:

    r = np.random.permutation(training_data.shape[0])
    training_data[r, :]
  • 分塊(batch)

    mini_batches = [training_data[k:k+mini_batch_size] for k in range(0, n, mini_batch_size)]

back propagation

backprog(x, y)

反向傳播演算法(監督學習)接收每一筆(單筆單筆接收)輸入((x,y)

(x, y)
),根據目前的weights以及biases進行對特徵向量的預測(a=σ(wa+b)
a=\sigma(w\cdot a+b)
),也即y_pred = feedforward(x),最終根據真實值與預測值之間的誤差(cost_derivative=y_predy
\mathrm{cost\_derivative=y\_pred-y}
)進行對權值及偏置的更新,這中間是一系列相對麻煩的過程,也是反向傳播演算法的精髓所在。也即,反向傳播的最終目的是通過真實值與預測值的誤差進行對權值以及偏置的更新。

wk=wkηmj=1Cxjwkmbl=blηmj=1Cxjblm
w_k^{'}=w_k-\eta\cdot\frac{\sum_{j=1}^{m}\frac {\partial\, C_{x_j}}{\partial\, w_k}}{m}\\ b_l^{'}=b_l-\eta \cdot\frac{\sum_{j=1}^m\frac{\partial\,{C_{x_j}}}{\partial\, b_l}}{m}

以上的梯度下降(GD:GradientDescent

\mathrm{GD:\,Gradient\,Descent}
)公式中的,Cxjwj
\frac{\partial\,C_{x_j}}{\partial\,w_j}
正是反向傳播演算法的工作。

mj=1Cxjwkm

\frac{\sum_{j=1}^m\frac{\partial\, C_{x_j}}{\partial\,w_k}}{m}
表達的是塊的概念,將某一塊當做一個整體進行權值以及偏置的更新,否則每傳遞進來一個樣本都要進行一次前向進行預測,後向進行更新,會增大計算量。

物件導向版BP神經網路

神經網路的步驟:

  • 初始化全部權值和偏置

    這一步自然放在Network的建構函式的內部進行(一般的做法是使用np.random.randn())。因為初始化動作以及類的建構函式一樣,只進行一次,也自然,Network類持有整個神經網路的全部權值以及偏置。

    class Network(object):
        def __init__(self, topology):
            self.topology = topology
            self.num_layers = len(topology)
            self.biases = [np.random.randn((y, 1)) for y in topology[1:]]
            self.weights = [np.random.randn(y, x) for (x, y) in zip(topology[1:], topology[:-1])]

    注意這裡每兩層權重矩陣的size,W(j×i)

    W_{(j\times i)}
    j
    j
    表示後一層(layer)的神經元(neuron)個數,i
    i
    表示前一層(layer)的神經元(neuron)個數,這樣做的目的是為了後面計算內積的方便,也即W(j×i)x(i×1)
    W_{(j\times i)}\cdot x_{(i\times 1)}
    ,而前一層向後一層的偏置為b(j×1)
    b_{(j\times 1)}
    ,這樣根據前向(forward)計算(稱之為鏈式計算吧),可獲得下一層的輸入也即:W(j×i)x(i×1)+b(j×1)
    W_{(j\times i)}\cdot x_{(i\times 1)}+b_{(j\times 1)}

  • 根據輸入(單樣本,但特徵向量),前向計算獲得樣本的預測類別

def feedword(self, a):
    for w, b in zip(self.weights, self.biases):
        a = sigmoid(np.dot(w, a)+b)
    return a
  • 遍歷訓練集,對每一個(x,y)

    (x, y)
    ,進行backpropagation
    \mathrm{back\,propagation}
    ,更新全部權值及偏置:

    1. 計算各層各個神經元的輸入(zs
      \mathrm{zs}
      )與輸出(activations
      \mathrm{activations}

      sll=iWljixl1ixlj=σ(slj)
      s_l^l=\sum_iW_{ji}^lx_i^{l-1}\\ x_j^l=\sigma(s_j^l)
    2. 根據(cost_derivative
      \mathrm{cost\_derivative}
      也即output_activationy
      \mathrm{output\_activation - y}
      )計算末尾一層的δ
      \delta

      ensLi=(xLiy)xLisLi=(xLiy)σ(sLi)enWLji=ensLisLiWLji=ensLixL1i
      \frac {\partial e_n}{\partial s_i^L} = (x_i^L-y)\frac{\partial x_i^L}{\partial s_i^L}=(x_i^L-y)\cdot\sigma '(s_i^L)\\ \frac{\partial e_n}{\partial W_{ji}^L} = \frac {\partial e_n}{\partial s_i^L} \cdot \frac{\partial s_i^L}{\partial W_{ji}^L}= \frac {\partial e_n}{\partial s_i^L} x_i^{L-1}
    3. 後向計算每一層的權值更新

enWlji=enslisliWljiensli=k
\frac{\partial e_n}{\partial W_{ji}^l} = \frac {\partial e_n}{\partial s_i^l} \cdot \frac{\partial s_i^l}{\partial W_{ji}^l}\\ \frac {\partial e_n}{\partial s_i^l} =\sum_k
def backprog(self, x, y):
    nabla_b = [np.zeros(b.shape) for b in self.biases] 
    nabla_w = [np.zeros(w.shape) for w in self.weights]
    activation = x
    activations = [x]
    zs = []

    # step 1
    for w, b in zip(self.weights, self.biases):
        z = np.dot(w, activation) + b
        zs.append(z)
        activation = sigmoid(z)
        activations.append(activation)

    # step 2
    delta = (activations[-1]-y)*sigmoid_prime(zs[-1])
    nabla_b[-1] = delta
    nabla_w[-1] = np.dot(delta, activations[-2].transpose())
                    # 因為是兩層之間的權值矩陣,delta表示的後一層的列
                    # activations[-2]表示的前一層的列,作一轉置

    # step 3
    for l  in range(2, self.num_layers):
        z = zs[-l]
        sp = sigmoid_prime(z)
        delta = np.dot(self.wights[-l+1].transpose(), delta)*sp
        nabla_b[-l] = delta
        nabla_w[-l] = np.dot(delta, activations[-l-1].transpose())

sigmoid_prime是對sigmoid函式的導數:

def sigmoid_prime(z):
    return sigmoid(z)*(1-sigmoid(z))

相關文章