2020-6-6 吳恩達-NN&DL-w2 NN基礎(課後編程-Logistic Regression with a Neural Network mindset)

原文鏈接

本練習將使用邏輯迴歸分類來識別貓。

這項作業將指導你如何用NN的思維方式來完成任務,也將培養你對DL的直覺。

請不要在代碼中使用循環(for/while),除非作業明確要求你這樣做。

通過作業你可以學習如何建立學習算法的總體架構,包含

  • 初始化參數
  • 計算成本函數和它的參數
  • 使用優化算法(梯度下降)

1.本文涉及的基本庫

本作業涉及以下幾個python庫

  • numpy :是用Python進行科學計算的基本軟件包。
  • h5py:是與H5文件中存儲的數據集進行交互的常用軟件包。
  • matplotlib:是一個著名的庫,用於在Python中繪製圖表。
  • PIL和scipy:處理圖片。可以使用你自己的圖片來測試你的模型。
  • lr_utils.py :本文包含的代碼文件,包含一個load_dataset()函數,可以用來加載資料中提供的圖像數據。具體如下

2. 訓練集/測試集概況和預處理

import numpy as np
import h5py
    
    
def load_dataset():
    train_dataset = h5py.File('datasets/train_catvnoncat.h5', "r")
    train_set_x_orig = np.array(train_dataset["train_set_x"][:]) # your train set features
    train_set_y_orig = np.array(train_dataset["train_set_y"][:]) # your train set labels

    test_dataset = h5py.File('datasets/test_catvnoncat.h5', "r")
    test_set_x_orig = np.array(test_dataset["test_set_x"][:]) # your test set features
    test_set_y_orig = np.array(test_dataset["test_set_y"][:]) # your test set labels

    classes = np.array(test_dataset["list_classes"][:]) # the list of classes
    
    train_set_y_orig = train_set_y_orig.reshape((1, train_set_y_orig.shape[0]))
    test_set_y_orig = test_set_y_orig.reshape((1, test_set_y_orig.shape[0]))
    
    return train_set_x_orig, train_set_y_orig, test_set_x_orig, test_set_y_orig, classes

說明

  • train_catvnoncat.h5,包含訓練圖片集合,標籤爲cat (y=1) 或者 non-cat (y=0),209張
  • test_catvnoncat.h5,包含測試圖片集合,50張
  • 圖片都是64x64,正方形,3通道 (RGB),高和寬都是num_px
  • train_set_x_orig/test_set_x_orig :訓練/測試集裏面的圖像數據。每一行都是一個表示圖像的數組。
  • train_set_y_orig/test_set_y_orig :訓練/測試集的圖像對應的分類值,0和1
  • classes : bytes類型的兩個字符串數據,數據爲:[b’non-cat’ b’cat’]。

加載數據,調用方法

train_set_x_orig , train_set_y , test_set_x_orig , test_set_y , classes = load_dataset()

1-1.弄清數據集維度

你可以用以下方式查看一下某一張圖像

# Example of a picture
index = 25
plt.imshow(train_set_x_orig[index])
plt.show() #我的代碼必須加這一句才能把plt.imshow()處理後的內容顯示出來
print ("y = " + str(train_set_y[:,index]) + ", it's a '" + classes[np.squeeze(train_set_y[:,index])].decode("utf-8") +  "' picture.")

np.squeeze()函數可以刪除數組形狀中的單維度條目,即把shape中爲1的維度去掉,但是對非單維的維度不起作用。

運行後,圖像顯示如下
在這裏插入圖片描述

控制檯輸出分類,是貓

y = [1], it's a 'cat' picture.

如果是訓練集,index=65
在這裏插入圖片描述

控制檯顯示,不是貓

y = [0], it's a 'non-cat' picture.

注意

DL的許多軟件問題來自於矩陣/向量維度不匹配。如果你能保持你的矩陣/向量的維度是準確的,你將在很大程度上消除許多錯誤。

請嘗試找到以下幾個值,以便了解加載圖像數據集具體情況

  • m_train :訓練集圖片的數量。希望輸出209
  • m_test :測試集圖片的數量。希望輸出50
  • num_px : 訓練/測試集中圖片的高度和寬度。希望輸出64

代碼如下

m_train = train_set_y.shape[1] #訓練集裏圖片的數量。
m_test = test_set_y.shape[1] #測試集裏圖片的數量。
num_px = train_set_x_orig.shape[1] #訓練、測試集裏面的圖片的寬度和高度(均爲64x64)。

print ("訓練集的數量: m_train = " + str(m_train))
print ("測試集的數量 : m_test = " + str(m_test))
print ("圖片的高和寬 : num_px = " + str(num_px))
print ("圖片的大小 : (" + str(num_px) + ", " + str(num_px) + ", 3)")
print ("訓練集_圖片的維數 : " + str(train_set_x_orig.shape))
print ("訓練集_標籤的維數 : " + str(train_set_y.shape))
print ("測試集_圖片的維數: " + str(test_set_x_orig.shape))
print ("測試集_標籤的維數: " + str(test_set_y.shape))

運行結果

訓練集的數量: m_train = 209
測試集的數量 : m_test = 50
圖片的高和寬 : num_px = 64
圖片的大小 : (64, 64, 3)
訓練集_圖片的維數 : (209, 64, 64, 3)
訓練集_標籤的維數 : (1, 209)
測試集_圖片的維數: (50, 64, 64, 3)
測試集_標籤的維數: (1, 50)

1-2.重構數據集

爲了方便,你需要把維度爲(64,64,3)的圖像重新構造爲(64 x 64 x 3,1)的numpy數組。(乘以3的原因是每張圖片是由64x64像素構成的,而每個像素點由(R,G,B)三原色構成的)。reshape之後,訓練和測試數據集是一個numpy數組,每列代表一個平坦的圖像flattened image。numpy數組會有m_train(m_test)列。

小技巧

當你想將形狀(a,b,c,d)的矩陣X平鋪成形狀(b * c * d,a)的矩陣X_flatten時,可以使用以下代碼

X_flatten = X.reshape(X.shape[0], -1).T      # X.T is the 轉置 of X

將訓練集/測試集重構:降低維度,並轉置。代碼如下

# Reshape the training and test examples

### START CODE HERE ### (≈ 2 lines of code)
train_set_x_flatten = train_set_x_orig.reshape(train_set_x_orig.shape[0], -1).T
test_set_x_flatten = test_set_x_orig.reshape(test_set_x_orig.shape[0], -1).T
### END CODE HERE ###

print ("train_set_x_flatten shape: " + str(train_set_x_flatten.shape))
print ("train_set_y shape: " + str(train_set_y.shape))
print ("test_set_x_flatten shape: " + str(test_set_x_flatten.shape))
print ("test_set_y shape: " + str(test_set_y.shape))

控制檯輸出

train_set_x_flatten shape: (12288, 209)
train_set_y shape: (1, 209)
test_set_x_flatten shape: (12288, 50)
test_set_y shape: (1, 50)

因爲我們已經知道train_set_x_orig.shape=(209, 64, 64, 3),所以train_set_x_flatten.shape結果就是(64643,209)=(12288,209)。

1-3.數據預處理

要表示彩色圖像,必須爲每個像素指定紅色、綠色和藍色通道(RGB),因此像素值實際上是一個由0到255之間的三個數字組成的向量。

DL中一個常見的預處理步驟是將數據集居中並標準化。
這意味着從每個示例中減去整個numpy數組的平均值,然後將每個示例除以整個numpy數組的標準差。但對於圖片數據集來說,它更簡單、更方便,並且幾乎可以將數據集的每一行除以255(像素通道的最大值)。因爲在RGB中不存在比255大的數據,我們可以通過除以255,讓標準化的數據位於[0,1]之間。

標準化預處理圖像代碼如下

train_set_x = train_set_x_flatten / 255.
test_set_x = test_set_x_flatten / 255.

總結

數據集預處理步驟包含

  • 弄清訓練集/測試集的維度,形狀(例如:m_train, m_test, num_px)
  • 重構數據集,把每個示例變爲一個向量,大小爲(num_px * num_px * 3, 1)
  • 標準化數據

3.學習算法的一般結構

現在可以設計一個簡單的算法來區分貓圖片和非貓圖片了。

你將利用NN思維來構築邏輯迴歸。下圖解釋了爲什麼邏輯迴歸實際上是一個非常簡單的神經網絡!
在這裏插入圖片描述

算法的數學表達式如下:
對於一個樣本 x(i)x^{(i)},邏輯迴歸算法前向傳播,每個神經元分兩步完成
步驟1,z(i)=wTx(i)+bz^{(i)}=w^Tx^{(i)}+b
步驟2,y(i)=a(i)=sigmoid(z(i))y^{​(i)}=a^{(i)}=sigmoid(z^{(i)}),激活函數輸出預測值

得到損失函數,預測分類和實際類別偏差
L(a(i),y(i))=y(i)log(a(i))(1y(i))log(1a(i))L(a^{(i)},y^{(i)})=−y^{(i)}log(a^{(i)})−(1−y^{(i)})log(1−a^{(i)})

通過對所有訓練樣本損失求和來計算成本:
J=1mi=1mL(a(i),y(i))J=\frac 1m \sum_{i=1}^m​L(a^{(i)},y^{(i)})

本練習中,需要實現算法的以下關鍵步驟

  • 初始化模型參數
  • 通過最小化成本來學習模型的參數
  • 使用學習好的參數來進行預測(在測試集上)
  • 分析結果,得出結論

4.實現算法

建立NN的主要步驟包含

  • 定義模型結構(例如輸入特徵的數量)
  • 初始化模型的參數
  • 循環
    • 計算當前損失(前向傳播)
    • 計算當前梯度(反向傳播)
    • 更新參數(梯度下降)

通常我們會分別建立上面3步,然後集成到一個函數中–model()。

4.1輔助函數-sigmoid()

實現函數sigmoid()。如上面的圖中所示,最終你需要通過計算sigmoid(wTx+b)sigmoid( w^T x + b)來完成分類預測。

sigmoid()實現代碼如下

# GRADED FUNCTION: sigmoid

def sigmoid(z):
    """
    Compute the sigmoid of z 計算sigmoid(z)

    Arguments:
    x -- A scalar or numpy array of any size. 任意大小的標量或者numpy數組

    Return:
    s -- sigmoid(z)
    """

    ### START CODE HERE ### (≈ 1 line of code)
    s = 1 / (1 + np.exp(-z))
    ### END CODE HERE ###
    
    return s

測試一下

print ("sigmoid(0) = " + str(sigmoid(0)))
print ("sigmoid(9.2) = " + str(sigmoid(9.2)))

運行結果

sigmoid(0) = 0.5
sigmoid(9.2) = 0.999898970806

sigmoid函數圖像如下,結果與其相符合。
在這裏插入圖片描述

4.2初始化參數

你需要把ww初始化爲0向量,可以通過np.zeros()函數來實現。

代碼如下

# GRADED FUNCTION: initialize_with_zeros

def initialize_with_zeros(dim):
    """
    This function creates a vector of zeros of shape (dim, 1) for w and initializes b to 0.
    此函數爲w創建一個維度爲(dim,1)的0向量,並將b初始化爲0。
    
    Argument:
    dim -- size of the w vector we want (or number of parameters in this case)
    我們想要的向量w的大小(或者參數數量)
    
    Returns:
    w -- initialized vector of shape (dim, 1) 維度爲(dim,1)的初始化向量
    b -- initialized scalar (corresponds to the bias) 初始化的標量(對應於偏差)
    """
    
    ### START CODE HERE ### (≈ 1 line of code)
    w = np.zeros(shape=(dim, 1))
    b = 0
    ### END CODE HERE ###

    #使用斷言來確保數據是正確的
    assert(w.shape == (dim, 1))
    assert(isinstance(b, float) or isinstance(b, int))
    
    return w, b

調用方法如下

dim = 2
w, b = initialize_with_zeros(dim)
print ("w = " + str(w))
print ("b = " + str(b))

運行結果

w = [[ 0.]
 [ 0.]]
b = 0

在前面已經提醒過,爲了減少錯誤,需要時時保持你的矩陣/向量的維度是準確的。
本次練習中,對於圖像輸入,ww的維度應該是 (num_px * num_px * 3, 1)。因爲我們在step1-2時候,爲了方便,已經把維度爲(64,64,3)的圖像重新構造爲(64 x 64 x 3,1)的numpy數組。

4.3前向和反向傳播

你已經完成了參數初始化。現在你可以進入前向和反向傳播步驟來學習參數。

實現propagate() 函數來計算成本(前向)和梯度(反向)。

提示

前向傳播

  • 獲得輸入X
  • 計算A=σ(wTX+b)=(a(0),a(1),...,a(m1),a(m))A = \sigma(w^T X + b) = (a^{(0)}, a^{(1)}, ..., a^{(m-1)}, a^{(m)})
  • 計算成本函數 J=1mi=1my(i)log(a(i))(1y(i))log(1a(i))J=-\frac 1m \sum_{i=1}^my^{(i)}log(a^{(i)})−(1−y^{(i)})log(1−a^{(i)})

反向傳播,在這裏有2個公式你會使用到
Jw=1mX(AY)T(7) \frac{\partial J}{\partial w} = \frac{1}{m}X(A-Y)^T\tag{7}Jb=1mi=1m(a(i)y(i))(8) \frac{\partial J}{\partial b} = \frac{1}{m} \sum_{i=1}^m (a^{(i)}-y^{(i)})\tag{8}

實現代碼

# GRADED FUNCTION: propagate

def propagate(w, b, X, Y):
    """
    Implement the cost function and its gradient for the propagation explained above

    Arguments:
    w -- weights, a numpy array of size (num_px * num_px * 3, 1) 
           權重,numpy數組,維度(num_px * num_px * 3,1)
    b -- bias, a scalar 偏差,標量
    X -- data of size (num_px * num_px * 3, number of examples)  
           維度爲(num_px * num_px * 3,訓練數量)
    Y -- true "label" vector (containing 0 if non-cat, 1 if cat) of size (1, number of examples)“標籤”
           矢量(如果非貓則爲0,如果是貓則爲1),維度爲(1,訓練數據數量)

    Return:
    cost -- negative log-likelihood cost for logistic regression 邏輯迴歸的負對數似然成本
    dw -- gradient of the loss with respect to w, thus same shape as w 關於w的損失梯度,與w相同的形狀
    db -- gradient of the loss with respect to b, thus same shape as b 關於b的損失梯度,與b的形狀相同
    
    Tips:
    - Write your code step by step for the propagation
    """
    
    m = X.shape[1]
    
    # FORWARD PROPAGATION (FROM X TO COST) 正向傳播
    ### START CODE HERE ### (≈ 2 lines of code)
    A = sigmoid(np.dot(w.T, X) + b)  # compute activation
    cost = (- 1 / m) * np.sum(Y * np.log(A) + (1 - Y) * (np.log(1 - A)))  # compute cost
    ### END CODE HERE ###
    
    # BACKWARD PROPAGATION (TO FIND GRAD) 反向傳播
    ### START CODE HERE ### (≈ 2 lines of code)
    dw = (1 / m) * np.dot(X, (A - Y).T)
    db = (1 / m) * np.sum(A - Y)
    ### END CODE HERE ###

   #使用斷言確保我的數據是正確的
    assert(dw.shape == w.shape)
    assert(db.dtype == float)
    cost = np.squeeze(cost)
    assert(cost.shape == ())
    
    #創建一個字典,把dw和db保存起來。
    grads = {"dw": dw,
             "db": db}
    
    return grads, cost

測試一下

w, b, X, Y = np.array([[1], [2]]), 2, np.array([[1,2], [3,4]]), np.array([[1, 0]])
grads, cost = propagate(w, b, X, Y)
print ("dw = " + str(grads["dw"]))
print ("db = " + str(grads["db"]))
print ("cost = " + str(cost))

運行結果

dw = [[ 0.99993216]
 [ 1.99980262]]
db = 0.499935230625
cost = 6.00006477319

4.3.1優化

到目前爲止,你已經完成了初始化參數,計算了成本和它的梯度。
現在你需要使用梯度來更新參數。

我們的目標是通過最小化成本函數 JJ 來學習 wwbb 。對於參數 θθ ,更新規則是 θ=θα dθ\theta = \theta - \alpha \text{ } d\theta,其中 αα 是學習率。

# GRADED FUNCTION: optimize

def optimize(w, b, X, Y, num_iterations, learning_rate, print_cost = False):
    """
    This function optimizes w and b by running a gradient descent algorithm
    此函數通過運行梯度下降算法來優化w和b
    
    Arguments:
    w -- weights, a numpy array of size (num_px * num_px * 3, 1)
    b -- bias, a scalar
    X -- data of shape (num_px * num_px * 3, number of examples)
    Y -- true "label" vector (containing 0 if non-cat, 1 if cat), of shape (1, number of examples)
    num_iterations -- number of iterations of the optimization loop 優化循環的迭代次數
    learning_rate -- learning rate of the gradient descent update rule 梯度下降更新規則的學習率
    print_cost -- True to print the loss every 100 steps 每100步打印一次損失值
    
    Returns:
    params -- dictionary containing the weights w and bias b 包含權重w和偏差b的字典
    grads -- dictionary containing the gradients of the weights and bias with respect to the cost function
                  包含權重和偏差相對於成本函數的梯度的字典
    costs -- list of all the costs computed during the optimization, this will be used to plot the learning curve.
                 優化時計算的所有成本列表,將用於繪製學習曲線。

    Tips: 提示
    You basically need to write down two steps and iterate through them:
    你通常需要寫下兩個步驟並遍歷它們:
        1) Calculate the cost and the gradient for the current parameters. Use propagate().
            使用propagate(),計算當前參數的成本和梯度。
        2) Update the parameters using gradient descent rule for w and b.
            使用w和b的梯度下降法則更新參數。
    """
    
    costs = []
    
    for i in range(num_iterations):
        
        
        # Cost and gradient calculation (≈ 1-4 lines of code)
        ### START CODE HERE ### 
        grads, cost = propagate(w, b, X, Y)
        ### END CODE HERE ###
        
        # Retrieve derivatives from grads
        dw = grads["dw"]
        db = grads["db"]
        
        # update rule (≈ 2 lines of code)
        ### START CODE HERE ###
        w = w - learning_rate * dw  # need to broadcast
        b = b - learning_rate * db
        ### END CODE HERE ###
        
        # Record the costs
        if i % 100 == 0:
            costs.append(cost)
        
        # Print the cost every 100 training examples
        if print_cost and i % 100 == 0:
            print ("Cost after iteration %i: %f" % (i, cost))
    
    params = {"w": w,
              "b": b}
    
    grads = {"dw": dw,
             "db": db}
    
    return params, grads, costs

測試一下優化函數

params, grads, costs = optimize(w, b, X, Y, num_iterations= 100, learning_rate = 0.009, print_cost = False)

print ("w = " + str(params["w"]))
print ("b = " + str(params["b"]))
print ("dw = " + str(grads["dw"]))
print ("db = " + str(grads["db"]))

運行結果

w = [[ 0.1124579 ]
 [ 0.23106775]]
b = 1.55930492484
dw = [[ 0.90158428]
 [ 1.76250842]]
db = 0.430462071679

函數迭代了100次,學習率0.009,不打印成本,最終輸出學習好的wwbb

利用wwbb,我們就可以預測數據集X的分類標籤了。

我們構建一個predict()函數來預測。計算預測有2個步驟

  • 計算Y^=A=σ(wTX+b)\hat{Y} = A = \sigma(w^T X + b)
  • 將a的值變爲0(如果激活值<= 0.5)或者爲1(如果激活值> 0.5)。把預測結果保存到向量Y_prediction。你可以通過for循環來實現(當然也有向量化方式可以實現,這裏暫時不用)。

代碼如下

# GRADED FUNCTION: predict

def predict(w, b, X):
    '''
    Predict whether the label is 0 or 1 using learned logistic regression parameters (w, b)
    使用學習好的邏輯迴歸參數(w,b)預測標籤是0還是1,
    
    Arguments:
    w -- weights, a numpy array of size (num_px * num_px * 3, 1)
    b -- bias, a scalar
    X -- data of size (num_px * num_px * 3, number of examples)
    
    Returns:
    Y_prediction -- a numpy array (vector) containing all predictions (0/1) for the examples in X
                             包含X中所有圖片的所有預測結果(0/1) 的一個numpy數組(向量)
    '''
    
    m = X.shape[1] #圖片的數量
    Y_prediction = np.zeros((1, m))
    w = w.reshape(X.shape[0], 1)
    
    # Compute vector "A" predicting the probabilities of a cat being present in the picture
    # 計算預測貓在圖片中出現的概率
    ### START CODE HERE ### (≈ 1 line of code)
    A = sigmoid(np.dot(w.T, X) + b)
    ### END CODE HERE ###
    
    for i in range(A.shape[1]):
        # Convert probabilities a[0,i] to actual predictions p[0,i]
        # #將概率a [0,i]轉換爲實際預測p [0,i]
        ### START CODE HERE ### (≈ 4 lines of code)
        Y_prediction[0, i] = 1 if A[0, i] > 0.5 else 0
        ### END CODE HERE ###
    
    #使用斷言確保數據是正確的
    assert(Y_prediction.shape == (1, m))
    
    return Y_prediction

測試一下

print("predictions = " + str(predict(w, b, X)))

運行結果

predictions = [[ 1.  1.]]

注意,在前面我們已經賦值過了

w, b, X, Y = np.array([[1], [2]]), 2, np.array([[1,2], [3,4]]), np.array([[1, 0]])

輸入矩陣X有2個樣本,每個樣本都有2個特徵,2個樣本的分類標籤分別是1和0。只不過訓練和測試用了同一個矩陣X,測試結果就有偏差了,輸出的預測分類都是1。

5.把所有函數併入模型中

現在你可以按照正確的順序將所有前面部分實現過的函數組合在一起,從而瞭解整個模型的結構。

5.1構建model函數

使用下面符號,構建model函數Implement the model function. Use the following notation:

  • Y_prediction:測試集的預測結果 for your predictions on the test set
  • Y_prediction_train:訓練集的預測結果 for your predictions on the train set
  • w, costs, grads: optimize()函數輸出

代碼如下

# GRADED FUNCTION: model

def model(X_train, Y_train, X_test, Y_test, num_iterations=2000, learning_rate=0.5, print_cost=False):
    """
    Builds the logistic regression model by calling the function you've implemented previously
    通過調用之前實現的函數來構建邏輯迴歸模型
    
    Arguments:
    X_train -- training set represented by a numpy array of shape (num_px * num_px * 3, m_train)
	numpy的數組,維度爲(num_px * num_px * 3,m_train)的訓練集
    Y_train -- training labels represented by a numpy array (vector) of shape (1, m_train)
	numpy的數組,維度爲(1,m_train)(矢量)的訓練標籤集
    X_test -- test set represented by a numpy array of shape (num_px * num_px * 3, m_test)
	numpy的數組,維度爲(num_px * num_px * 3,m_test)的測試集
    Y_test -- test labels represented by a numpy array (vector) of shape (1, m_test)
	numpy的數組,維度爲(1,m_test)的(向量)的測試標籤集
    num_iterations -- hyperparameter representing the number of iterations to optimize the parameters
    	超參,表示用於優化參數的迭代次數
    learning_rate -- hyperparameter representing the learning rate used in the update rule of optimize()
	超參,學習率
    print_cost -- Set to true to print the cost every 100 iterations 每100次迭代打印成本
    
    Returns:
    d -- dictionary containing information about the model. 包含有關模型信息的字典
    """
    
    ### START CODE HERE ###
    # initialize parameters with zeros (≈ 1 line of code)
    w, b = initialize_with_zeros(X_train.shape[0])

    # Gradient descent (≈ 1 line of code)
    parameters, grads, costs = optimize(w, b, X_train, Y_train, num_iterations, learning_rate, print_cost)
    
    # Retrieve parameters w and b from dictionary "parameters"
    # #從“參數”字典中檢索參數w和b
    w = parameters["w"]
    b = parameters["b"]
    
    # Predict test/train set examples (≈ 2 lines of code)
    # 預測測試/訓練集
    Y_prediction_test = predict(w, b, X_test)
    Y_prediction_train = predict(w, b, X_train)

    ### END CODE HERE ###

    # Print train/test Errors
    # 打印訓練後的準確率
    print("train accuracy: {} %".format(100 - np.mean(np.abs(Y_prediction_train - Y_train)) * 100))
    print("test accuracy: {} %".format(100 - np.mean(np.abs(Y_prediction_test - Y_test)) * 100))

    
    d = {"costs": costs,
         "Y_prediction_test": Y_prediction_test, 
         "Y_prediction_train" : Y_prediction_train, 
         "w" : w, 
         "b" : b,
         "learning_rate" : learning_rate,
         "num_iterations": num_iterations}
    
    return d

基本步驟如下

  • 先初始化參數wwbb,initialize_with_zeros
  • 然後學習,獲得學習好的wwbb,optimize
  • 預測訓練和測試集,predict
  • 打印準確率,預測結果和實際標籤的誤差

測試一下

d = model(train_set_x, train_set_y, test_set_x, test_set_y, num_iterations = 2000, learning_rate = 0.005, print_cost = True)

迭代2000次,學習率0.005
運行結果

Cost after iteration 0: 0.693147
Cost after iteration 100: 0.584508
Cost after iteration 200: 0.466949
Cost after iteration 300: 0.376007
Cost after iteration 400: 0.331463
Cost after iteration 500: 0.303273
Cost after iteration 600: 0.279880
Cost after iteration 700: 0.260042
Cost after iteration 800: 0.242941
Cost after iteration 900: 0.228004
Cost after iteration 1000: 0.214820
Cost after iteration 1100: 0.203078
Cost after iteration 1200: 0.192544
Cost after iteration 1300: 0.183033
Cost after iteration 1400: 0.174399
Cost after iteration 1500: 0.166521
Cost after iteration 1600: 0.159305
Cost after iteration 1700: 0.152667
Cost after iteration 1800: 0.146542
Cost after iteration 1900: 0.140872
train accuracy: 99.04306220095694 %
test accuracy: 70.0 %

迭代2000次後,成本下降並收斂。
最終訓練集準確率99%,測試集正曲率70%。

訓練集正確率接近100%。你的模型正在工作,並且具有足夠高的容量來適應訓練數據。
測試誤差爲70%。慮到我們使用的數據集很小,而且邏輯迴歸是一個線性分類器,所以對於這個簡單的模型來說,這並不壞。

此外,你還可以看到,該模型顯然過度擬合了訓練數據。後面的課程會學習如何減少過度擬合,例如使用正則化。

5.2測試集圖片預測

使用下面的代碼(更改索引變量),你可以查看測試集圖片上的預測。

index = 5
plt.imshow(test_set_x[:,index].reshape((num_px, num_px, 3)))
plt.show() #我的代碼必須加這一句才能把plt.imshow()處理後的函數顯示出來
print ("y = " + str(test_set_y[0, index]) + ", you predicted that it is a \"" + classes[d["Y_prediction_test"][0, index]].decode("utf-8") +  "\" picture.")

運行結果

y = 0, you predicted that it is a "cat" picture.

標籤是0,但是預測結果是貓。顯然,是錯誤的預測。你可以看一下圖片,雖然有點模糊,不過看上去象是蝴蝶。

在這裏插入圖片描述

5.3繪製成本函數

optimize函數輸出了學習過程中的成本,我們可以把它們繪製出來。

繪製成本,代碼如下

costs = np.squeeze(d['costs'])
plt.plot(costs)
plt.ylabel('cost')
plt.xlabel('iterations (per hundreds)')
plt.title("Learning rate =" + str(d["learning_rate"]))
plt.show()

運行後,成本曲線繪製圖形如下

在這裏插入圖片描述

觀察上圖。
你可以看到成本在下降。這表明參數正在學習中。但是,你也明白,你可以在訓練集上訓練更多次的模型。嘗試增迭代次數(例如:3000次)並運行,你可能會看到訓練集的準確性上升,但測試集的準確性下降,這被稱爲過擬合

6.進階分析

我們已經完成了第一個圖像分類器模型。讓我們進一步分析一下,並研究學習率α\alpha的可能選擇。

爲了讓梯度下降起作用,我們必須聰明的選擇學習速率。

學習率α\alpha 決定了我們更新參數的速度。如果學習率過高,我們可能會“超過”最優值。同樣,如果它太小,我們將需要太多迭代才能收斂到最佳值。這就是爲什麼使用良好調整的學習率至關重要的原因。

讓我們在模型中嘗試3個不同的學習率,看看結果會怎麼樣。

代碼如下

learning_rates = [0.01, 0.001, 0.0001]
models = {}
for i in learning_rates:
    print ("learning rate is: " + str(i))
    models[str(i)] = model(train_set_x, train_set_y, test_set_x, test_set_y, num_iterations = 1500, learning_rate = i, print_cost = False)
    print ('\n' + "-------------------------------------------------------" + '\n')

for i in learning_rates:
    plt.plot(np.squeeze(models[str(i)]["costs"]), label= str(models[str(i)]["learning_rate"]))

plt.ylabel('cost')
plt.xlabel('iterations')

legend = plt.legend(loc='upper center', shadow=True)
frame = legend.get_frame()
frame.set_facecolor('0.90')
plt.show()

學習率分別是0.01, 0.001, 0.0001,運行結果如下

learning rate is: 0.01
train accuracy: 99.52153110047847 %
test accuracy: 68.0 %

-------------------------------------------------------

learning rate is: 0.001
train accuracy: 88.99521531100478 %
test accuracy: 64.0 %

-------------------------------------------------------

learning rate is: 0.0001
train accuracy: 68.42105263157895 %
test accuracy: 36.0 %

-------------------------------------------------------

在這裏插入圖片描述

說明:

  • 不同的學習率,成本和預測結果都不一樣
  • 如果學習率太大(0.01),則成本可能上下波動。它甚至可能會發散(儘管在本例中,使用0.01最終還是會得到很好的成本值)。
  • 低成本並不意味着更好的模式。你得檢查一下是否有過擬合可能。當訓練準確率遠高於測試準確率時就會發生這種情況。
  • DL中,通常推薦你
    • 選擇能更好最小化成本的學習率
    • 如果模型過擬合了,請嘗試用其他技術減少過擬合(後面課程介紹)

7.用你自己的圖像測試預測效果

你可以嘗試用你自己的圖片來測試預測效果。

我在網上隨便找了一張貓咪圖片。
在這裏插入圖片描述

測試代碼如下

# We preprocess the image to fit your algorithm.
fname = "images/" + my_image

#image = np.array(ndimage.imread(fname, flatten=False))
image = np.array(imageio.imread(fname))

#my_image = scipy.misc.imresize(image, size=(num_px, num_px)).reshape((1, num_px * num_px * 3)).T
my_image = np.array(Image.fromarray(image).resize((num_px, num_px),Image.ANTIALIAS)) #ANTIALIAS表示保留圖片所有像素,不丟失原有像素
my_image = my_image.reshape((1, num_px * num_px * 3)).T

my_predicted_image = predict(d["w"], d["b"], my_image)

plt.imshow(image)
plt.show()
print("y = " + str(np.squeeze(my_predicted_image)) + ", your algorithm predicts a \"" + classes[int(np.squeeze(my_predicted_image)),].decode("utf-8") +  "\" picture.")

注意,這裏代碼和原文有改變。原因參見鏈接。主要是scipy庫發生了變化。

運行原文代碼,報錯信息如下

NameError: name 'ndimage' is not defined
AttributeError: module 'scipy' has no attribute 'misc'

修改後的代碼需要引入2個庫

import imageio   
from PIL import Image     

運行代碼後,結果如下

y = 1.0, your algorithm predicts a "cat" picture.

可以識別出是貓咪
在這裏插入圖片描述

8.完整代碼

全部代碼下載鏈接

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章