1. 程式人生 > >吳恩達學習-深層神經網路

吳恩達學習-深層神經網路

深度學習是指神經網路包含了很多層的隱層,比如說10層20層這樣,有些問題用淺層神經網路不能得到很好的優化,只能通過深層神經網路優化,這是因為深層神經網路有其獨特的優勢,下面我們就先介紹深層神經網路的優勢。

1.深層神經網路的優勢

1.深層神經網路的一大優勢就是優化演算法的區域性最優解問題

這裡寫圖片描述

之前訓練淺層神經網路時,經常會陷入區域性最優解,而無法找到全域性最優解,如下圖所示(圖來自吳恩達老師講義)。

這裡寫圖片描述

這種問題出現在深度學習網路的概率非常小,我們假設深度神經網路中有n個引數,每個引數在某點取得極小值的概率為p,則所有引數在同一點取得極小值的概率為p的n次方,這個概率是相當小的。在深度學習裡,會經常出現的是鞍點,如下圖所示(圖來自吳恩達老師講義):

這裡寫圖片描述

鞍點處的梯度為0,所有在鞍點時,同樣會被困住。但是困在鞍點並不容易發生,只是存在一定的概率。可怕的是在處於馬鞍面上時,梯度接近於0,這時候下降速度將會非常緩慢。所幸的是已經有很多方法加快收斂速度(比如mini-batch、momentum、Adam等),從而避免這種情況的發生。所以,在深度學習中,不很在意區域性最優解問題,而會在意加快收斂速度問題。

2.深度學習為什麼會奏效
吳老師給了一個直觀的解釋,如下圖(圖來自吳恩達老師講義),用深度學習做人臉時,第一層節點可能就是做簡單的邊緣檢測,第二層將第一層的結果組合,出來簡單的器官,比如眼睛、眉毛等,第三層再將這些器官組合,一直到最後一層。每走一層,都會更加複雜,最後組合出人臉的樣子。

這裡寫圖片描述

2.前向傳播

深度學習前向傳播與淺層神經網路前向傳播一樣,假設有L層,則前向傳播如下:

這裡寫圖片描述

3.成本函式

深度學習的成本函式和淺層神經網路的成本函式形式相同,不同的是深度學習的成本函式包含更多的引數。

深度學習的損失函式:

這裡寫圖片描述

對於多個樣本,成本函式為:

這裡寫圖片描述

4.反向傳播

深度學習的反向傳播與淺層神經網路的反向傳播相同,都是反向優化引數,不同的是深度學習的反向傳播有多層引數優化,需要逐層逐層的優化,反向傳播的公式如下(推導過程略):
對於單個樣本而言,反向傳播如下

這裡寫圖片描述

對於多個樣本而言,反向傳播如下

這裡寫圖片描述

5.初始化引數

在深度學習中初始化引數極為重要,在Logistic Regression中可以將W和b都初始化為0。但是在深度學習中,如果將W初始化為0,則每層節點的輸出都是相同的,假設某層節點有10個,則10個節點只能當一個用,這就無法發揮出深度學習的優勢。深度學習中,將隨機生成W。當然在隨機生成W時,為了防止梯度爆炸或消失,還需要一定的技巧,這在優化引數時再講。

6.Python原始碼

將以上過程寫成Python程式碼如下,在寫反向傳播時隱藏了一個bug,調了整整兩天,才找到bug,其實就是一個很小的錯誤,但影響是很大的,所以還是要多加細心啊☺!

import numpy as np
import matplotlib.pyplot as plt
from testCases import *
import sklearn
import sklearn.datasets
import sklearn.learning_curve
from planar_utils import plot_decision_boundary, sigmoid, load_planar_dataset, load_extra_datasets
%matplotlib inline
np.random.seed(1)

def layer_sizes(X, Y, n_h):
    n_x = X.shape[0]
    n_y = Y.shape[0]
    n_h.insert(0, n_x)
    n_h.append(n_y)
    return n_h

def initialize_parameters(n_h):
    np.random.seed(2)
    W = []
    b = []
    layer_size = np.shape(n_h)[0]
    for i in range(layer_size - 1):
        W_i = np.random.randn(n_h[i + 1], n_h[i]) / np.sqrt(n_h[i] / 2)
        b_i = np.zeros((n_h[i + 1], 1))
        W.append(W_i)
        b.append(b_i)
    assert(np.shape(W)[0] == layer_size - 1)
    assert(np.shape(b)[0] == layer_size - 1)
    paramters = {"W":W,
                 "b":b}
    return paramters

def forword_propagation(X, parameters):
    W = parameters["W"]
    b = parameters["b"]
    n_size = np.shape(W)[0]
    Z = []
    A = [X]
    A_i_former = X
    for i in range(n_size):
        W_i = W[i]
        b_i = b[i]
        Z_i = np.dot(W_i, A_i_former) + b_i
        A_i = np.zeros((W_i.shape[0], A_i_former.shape[1]))
        if(i == n_size - 1):
            A_i = sigmoid(Z_i)
        else:
            A_i = np.tanh(Z_i)
            #A_i = np.maximum(Z_i, 0)
        Z.append(Z_i)
        A.append(A_i)
        A_i_former = A_i
    A_final = A[np.shape(A)[0] - 1]
    cache = {"A": A,
             "Z": Z}
    return A_final, cache

def compute_cost(A_final, Y):
    m = float(Y.shape[1])
    loss = np.dot(Y, np.log(A_final).T) + np.dot(1 - Y, np.log(1 - A_final).T)
    cost = -1 / m * np.sum(loss)
    cost = np.squeeze(cost)
    assert(isinstance(cost, float))
    return cost

def backword_propagation(Y, parameters, cache):
    W = parameters["W"]
    b = parameters["b"]
    Z = cache["Z"]
    A = cache["A"]
    n = np.shape(A)[0]
    m = float(Y.shape[1])
    dW_n = np.shape(W)[0]
    db_n = np.shape(b)[0]
    dW = range(dW_n)
    db = range(db_n)
    dZ_final = A[n - 1] - Y
    dW_final = 1 / m * np.dot(dZ_final, A[n - 2].T)
    db_final = 1 / m * np.sum(dZ_final, axis=1, keepdims=True)
    dW[dW_n - 1] = dW_final
    db[dW_n - 1] = db_final
    dZ_last = dZ_final 
    i = dW_n - 2
    while i >= 0:
        #print "dZ_last" + str(dZ_last)
        dW_last = dW[i + 1]
        dZ_i = np.dot(W[i + 1].T, dZ_last) * (1 - np.power(A[i + 1], 2))
        #dZ_i = np.dot(W[i + 1].T, dZ_last) * np.int64(A[i + 1] > 0)
        dW_i = 1 / m * np.dot(dZ_i, A[i].T)
        db_i = 1 / m * np.sum(dZ_i, axis=1, keepdims=True)
        dZ_last = dZ_i
        dW[i] = dW_i
        db[i] = db_i
        i = i - 1
        #print "dZ_i" + str(dZ_i)
        #print "dW_last" + str(dW_last)
        #print "A" + str(A[1])
    grads = {"dW":dW,
             "db":db}
    return grads

def update_parameters(parameters, grads, learning_rate = 1.2):
    W = parameters["W"]
    b = parameters["b"]
    dW = grads["dW"]
    db = grads["db"]
    for i in range(np.shape(W)[0]):
        W[i] = W[i] - learning_rate * dW[i]
        b[i] = b[i] - learning_rate * db[i]
    parameters = {"W": W,
                  "b": b}
    return parameters

def deep_learning_model(X, Y, n_h, iteration_num = 10000, learning_rate = 1.2, show_cost = True):
    np.random.seed(3)
    n_h = layer_sizes(X, Y, n_h)
    parameters = initialize_parameters(n_h)
    for i in range(iteration_num):
        A_final, cache = forword_propagation(X, parameters)
        #print A_final, cache
        cost = compute_cost(A_final, Y)
        #print cost
        grads = backword_propagation(Y, parameters, cache)
        #print grads
        parameters = update_parameters(parameters, grads, learning_rate)
        #print parameters
        if show_cost and i % 1000 == 0:
            print cost
    return parameters

def predict(X, parameters):
    A_final, cache = forword_propagation(X, parameters)
    predictions = (A_final >= 0.5)
    return predictions