【中文】【吳恩達課後編程作業】Course 1 - 神經網絡和深度學習 - 第二週作業

【吳恩達課後編程作業】Course 1 - 神經網絡和深度學習 - 第二週作業 - 具有神經網絡思維的Logistic迴歸


上一篇:【課程1 - 第二週測驗】※※※※※ 【回到目錄】※※※※※下一篇:【課程1 - 第三週測驗】

在開始之前,首先聲明本文參考【Kulbear】的github上的文章,本文參考Logistic Regression with a Neural Network mindset,我基於他的文章加以自己的理解發表這篇博客,力求讓大家以最輕鬆的姿態理解吳恩達的視頻,如有不妥的地方歡迎大家指正。


本文所使用的資料已上傳到百度網盤【點擊下載】,提取碼:2u3w ,請在開始之前下載好所需資料,然後將文件解壓到你的代碼文件同一級目錄下,請確保你的代碼那裏有lr_utils.py和datasets文件夾。


【博主使用的python版本:3.6.2】


我們要做的事是搭建一個能夠**【識別貓】** 的簡單的神經網絡,你可以跟隨我的步驟在Jupyter Notebook中一步步地把代碼填進去,也可以直接複製完整代碼,在完整代碼在本文最底部。

在開始之前,我們有需要引入的庫:

  • numpy :是用Python進行科學計算的基本軟件包。
  • h5py:是與H5文件中存儲的數據集進行交互的常用軟件包。
  • matplotlib:是一個著名的庫,用於在Python中繪製圖表。
  • lr_utils :在本文的資料包裏,一個加載資料包裏面的數據的簡單功能的庫。

如果你沒有以上的庫,請自行安裝。

import numpy as np
import matplotlib.pyplot as plt
import h5py
from lr_utils import load_dataset

lr_utils.py代碼如下,你也可以自行打開它查看:

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

解釋以下上面的load_dataset() 返回的值的含義:

  • train_set_x_orig :保存的是訓練集裏面的圖像數據(本訓練集有209張64x64的圖像)。
  • train_set_y_orig :保存的是訓練集的圖像對應的分類值(【0 | 1】,0表示不是貓,1表示是貓)。
  • test_set_x_orig :保存的是測試集裏面的圖像數據(本訓練集有50張64x64的圖像)。
  • test_set_y_orig : 保存的是測試集的圖像對應的分類值(【0 | 1】,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()

我們可以看一下我們加載的文件裏面的圖片都是些什麼樣子的,比如我就查看一下訓練集裏面的第26張圖片,當然你也可以改變index的值查看一下其他的圖片。

index = 25
plt.imshow(train_set_x_orig[index])
#print("train_set_y=" + str(train_set_y)) #你也可以看一下訓練集裏面的標籤是什麼樣的。

運行結果如下:
index_25

現在我們可以結合一下訓練集裏面的數據來看一下我到底都加載了一些什麼東西。

#打印出當前的訓練標籤值
#使用np.squeeze的目的是壓縮維度,【未壓縮】train_set_y[:,index]的值爲[1] , 【壓縮後】np.squeeze(train_set_y[:,index])的值爲1
#print("【使用np.squeeze:" + str(np.squeeze(train_set_y[:,index])) + ",不使用np.squeeze: " + str(train_set_y[:,index]) + "】")
#只有壓縮後的值才能進行解碼操作
print("y=" + str(train_set_y[:,index]) + ", it's a " + classes[np.squeeze(train_set_y[:,index])].decode("utf-8") + "' picture")

打印出的結果是:y=[1], it's a cat' picture,我們進行下一步,我們查看一下我們加載的圖像數據集具體情況,我對以下參數做出解釋:

  • m_train :訓練集裏圖片的數量。
  • m_test :測試集裏圖片的數量。
  • num_px : 訓練、測試集裏面的圖片的寬度和高度(均爲64x64)。

請記住,train_set_x_orig 是一個維度爲(m_​​train,num_px,num_px,3)的數組。

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)

爲了方便,我們要把維度爲(64,64,3)的numpy數組重新構造爲(64 x 64 x 3,1)的數組,要乘以3的原因是每張圖片是由64x64像素構成的,而每個像素點由(R,G,B)三原色構成的,所以要乘以3。在此之後,我們的訓練和測試數據集是一個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是X的轉置
#將訓練集的維度降低並轉置。
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

這一段意思是指把數組變爲209行的矩陣(因爲訓練集裏有209張圖片),但是我懶得算列有多少,於是我就用-1告訴程序你幫我算,最後程序算出來時12288列,我再最後用一個T表示轉置,這就變成了12288行,209列。測試集亦如此。

然後我們看看降維之後的情況是怎麼樣的:

print ("訓練集降維最後的維度: " + str(train_set_x_flatten.shape))
print ("訓練集_標籤的維數 : " + str(train_set_y.shape))
print ("測試集降維之後的維度: " + str(test_set_x_flatten.shape))
print ("測試集_標籤的維數 : " + str(test_set_y.shape))

執行之後的結果爲:

訓練集降維最後的維度: (12288, 209)
訓練集_標籤的維數 : (1, 209)
測試集降維之後的維度: (12288, 50)
測試集_標籤的維數 : (1, 50)

爲了表示彩色圖像,必須爲每個像素指定紅色,綠色和藍色通道(RGB),因此像素值實際上是從0到255範圍內的三個數字的向量。機器學習中一個常見的預處理步驟是對數據集進行居中和標準化,這意味着可以減去每個示例中整個numpy數組的平均值,然後將每個示例除以整個numpy數組的標準偏差。但對於圖片數據集,它更簡單,更方便,幾乎可以將數據集的每一行除以255(像素通道的最大值),因爲在RGB中不存在比255大的數據,所以我們可以放心的除以255,讓標準化的數據位於[0,1]之間,現在標準化我們的數據集:

train_set_x = train_set_x_flatten / 255
test_set_x = test_set_x_flatten / 255

flatten


現在總算是把我們加載的數據弄完了,我們現在開始構建神經網絡。

以下是數學表達式,如果對數學公式不甚理解,請仔細看一下吳恩達的視頻。

對於 x(i)x^{(i)}: z(i)=wTx(i)+b(1)z^{(i)} = w^T x^{(i)} + b \tag{1}y^(i)=a(i)=sigmoid(z(i))(2)\hat{y}^{(i)} = a^{(i)} = sigmoid(z^{(i)})\tag{2}L(a(i),y(i))=y(i)log(a(i))(1y(i))log(1a(i))(3) \mathcal{L}(a^{(i)}, y^{(i)}) = - y^{(i)} \log(a^{(i)}) - (1-y^{(i)} ) \log(1-a^{(i)})\tag{3}

然後通過對所有訓練樣例求和來計算成本: J=1mi=1mL(a(i),y(i))(4) J = \frac{1}{m} \sum_{i=1}^m \mathcal{L}(a^{(i)}, y^{(i)})\tag{4}

建立神經網絡的主要步驟是:

  1. 定義模型結構(例如輸入特徵的數量)

  2. 初始化模型的參數

  3. 循環:

    3.1 計算當前損失(正向傳播)

    3.2 計算當前梯度(反向傳播)

    3.3 更新參數(梯度下降)

現在構建sigmoid(),需要使用 sigmoid(w ^ T x + b) 計算來做出預測。

def sigmoid(z):
    """
    參數:
        z  - 任何大小的標量或numpy數組。
    
    返回:
        s  -  sigmoid(z)
    """
    s = 1 / (1 + np.exp(-z))
    return s

我們可以測試一下sigmoid(),檢查一下是否符合我們所需要的條件。

#測試sigmoid()
print("====================測試sigmoid====================")
print ("sigmoid(0) = " + str(sigmoid(0)))
print ("sigmoid(9.2) = " + str(sigmoid(9.2)))

打印出的結果爲:

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

既然sigmoid測試好了,我們現在就可以初始化我們需要的參數w和b了。

def initialize_with_zeros(dim):
    """
        此函數爲w創建一個維度爲(dim,1)的0向量,並將b初始化爲0。
        
        參數:
            dim  - 我們想要的w矢量的大小(或者這種情況下的參數數量)
        
        返回:
            w  - 維度爲(dim,1)的初始化向量。
            b  - 初始化的標量(對應於偏差)
    """
    w = np.zeros(shape = (dim,1))
    b = 0
    #使用斷言來確保我要的數據是正確的
    assert(w.shape == (dim, 1)) #w的維度是(dim,1)
    assert(isinstance(b, float) or isinstance(b, int)) #b的類型是float或者是int
    
    return (w , b)

初始化參數的函數已經構建好了,現在就可以執行“前向”和“後向”傳播步驟來學習參數。

我們現在要實現一個計算成本函數及其漸變的函數propagate()。

def propagate(w, b, X, Y):
	"""
    實現前向和後向傳播的成本函數及其梯度。
    參數:
        w  - 權重,大小不等的數組(num_px * num_px * 3,1)
        b  - 偏差,一個標量
        X  - 矩陣類型爲(num_px * num_px * 3,訓練數量)
        Y  - 真正的“標籤”矢量(如果非貓則爲0,如果是貓則爲1),矩陣維度爲(1,訓練數據數量)

    返回:
        cost- 邏輯迴歸的負對數似然成本
        dw  - 相對於w的損失梯度,因此與w相同的形狀
        db  - 相對於b的損失梯度,因此與b的形狀相同
    """
	m = X.shape[1]
    
    #正向傳播
    A = sigmoid(np.dot(w.T,X) + b) #計算激活值,請參考公式2。
    cost = (- 1 / m) * np.sum(Y * np.log(A) + (1 - Y) * (np.log(1 - A))) #計算成本,請參考公式3和4。
    
    #反向傳播
    dw = (1 / m) * np.dot(X, (A - Y).T) #請參考視頻中的偏導公式。
    db = (1 / m) * np.sum(A - Y) #請參考視頻中的偏導公式。
	
	#使用斷言確保我的數據是正確的
    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)

寫好之後我們來測試一下。

#測試一下propagate
print("====================測試propagate====================")
#初始化一些參數
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))

測試結果是:

====================測試propagate====================
dw = [[ 0.99993216]
 [ 1.99980262]]
db = 0.499935230625
cost = 6.00006477319

現在,我要使用漸變下降更新參數。

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

def optimize(w , b , X , Y , num_iterations , learning_rate , print_cost = False):
    """
    此函數通過運行梯度下降算法來優化w和b
    
    參數:
        w  - 權重,大小不等的數組(num_px * num_px * 3,1)
        b  - 偏差,一個標量
        X  - 維度爲(num_px * num_px * 3,訓練數據的數量)的數組。
        Y  - 真正的“標籤”矢量(如果非貓則爲0,如果是貓則爲1),矩陣維度爲(1,訓練數據的數量)
        num_iterations  - 優化循環的迭代次數
        learning_rate  - 梯度下降更新規則的學習率
        print_cost  - 每100步打印一次損失值
    
    返回:
        params  - 包含權重w和偏差b的字典
        grads  - 包含權重和偏差相對於成本函數的梯度的字典
        成本 - 優化期間計算的所有成本列表,將用於繪製學習曲線。
    
    提示:
    我們需要寫下兩個步驟並遍歷它們:
        1)計算當前參數的成本和梯度,使用propagate()。
        2)使用w和b的梯度下降法則更新參數。
    """
    
    costs = []
    
    for i in range(num_iterations):
        
        grads, cost = propagate(w, b, X, Y)
        
        dw = grads["dw"]
        db = grads["db"]
        
        w = w - learning_rate * dw
        b = b - learning_rate * db
        
        #記錄成本
        if i % 100 == 0:
            costs.append(cost)
        #打印成本數據
        if (print_cost) and (i % 100 == 0):
            print("迭代的次數: %i , 誤差值: %f" % (i,cost))
        
    params  = {
                "w" : w,
                "b" : b }
    grads = {
            "dw": dw,
            "db": db } 
    return (params , grads , costs)

現在就讓我們來測試一下優化函數:

#測試optimize
print("====================測試optimize====================")
w, b, X, Y = np.array([[1], [2]]), 2, np.array([[1,2], [3,4]]), np.array([[1, 0]])
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"]))

測試結果爲:

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

optimize函數會輸出已學習的w和b的值,我們可以使用w和b來預測數據集X的標籤。

現在我們要實現預測函數predict()。計算預測有兩個步驟:

  1. 計算 Y^=A=σ(wTX+b)\hat{Y} = A = \sigma(w^T X + b)

  2. 將a的值變爲0(如果激活值<= 0.5)或者爲1(如果激活值> 0.5),

然後將預測值存儲在向量Y_prediction中。

def predict(w , b , X ):
    """
    使用學習邏輯迴歸參數logistic (w,b)預測標籤是0還是1,
    
    參數:
        w  - 權重,大小不等的數組(num_px * num_px * 3,1)
        b  - 偏差,一個標量
        X  - 維度爲(num_px * num_px * 3,訓練數據的數量)的數據
    
    返回:
        Y_prediction  - 包含X中所有圖片的所有預測【0 | 1】的一個numpy數組(向量)
    
    """
    
    m  = X.shape[1] #圖片的數量
    Y_prediction = np.zeros((1,m)) 
    w = w.reshape(X.shape[0],1)
    
    #計預測貓在圖片中出現的概率
    A = sigmoid(np.dot(w.T , X) + b)
    for i in range(A.shape[1]):
        #將概率a [0,i]轉換爲實際預測p [0,i]
        Y_prediction[0,i] = 1 if A[0,i] > 0.5 else 0
    #使用斷言
    assert(Y_prediction.shape == (1,m))
    
    return Y_prediction

老規矩,測試一下。

#測試predict
print("====================測試predict====================")
w, b, X, Y = np.array([[1], [2]]), 2, np.array([[1,2], [3,4]]), np.array([[1, 0]])
print("predictions = " + str(predict(w, b, X)))

就目前而言,我們基本上把所有的東西都做完了,現在我們要把這些函數統統整合到一個model()函數中,屆時只需要調用一個model()就基本上完成所有的事了。

def model(X_train , Y_train , X_test , Y_test , num_iterations = 2000 , learning_rate = 0.5 , print_cost = False):
    """
    通過調用之前實現的函數來構建邏輯迴歸模型
    
    參數:
        X_train  - numpy的數組,維度爲(num_px * num_px * 3,m_train)的訓練集
        Y_train  - numpy的數組,維度爲(1,m_train)(矢量)的訓練標籤集
        X_test   - numpy的數組,維度爲(num_px * num_px * 3,m_test)的測試集
        Y_test   - numpy的數組,維度爲(1,m_test)的(向量)的測試標籤集
        num_iterations  - 表示用於優化參數的迭代次數的超參數
        learning_rate  - 表示optimize()更新規則中使用的學習速率的超參數
        print_cost  - 設置爲true以每100次迭代打印成本
    
    返回:
        d  - 包含有關模型信息的字典。
    """
    w , b = initialize_with_zeros(X_train.shape[0])
    
    parameters , grads , costs = optimize(w , b , X_train , Y_train,num_iterations , learning_rate , print_cost)
    
    #從字典“參數”中檢索參數w和b
    w , b = parameters["w"] , parameters["b"]
    
    #預測測試/訓練集的例子
    Y_prediction_test = predict(w , b, X_test)
    Y_prediction_train = predict(w , b, X_train)
    
    #打印訓練後的準確性
    print("訓練集準確性:"  , format(100 - np.mean(np.abs(Y_prediction_train - Y_train)) * 100) ,"%")
    print("測試集準確性:"  , format(100 - np.mean(np.abs(Y_prediction_test - Y_test)) * 100) ,"%")
    
    d = {
            "costs" : costs,
            "Y_prediction_test" : Y_prediction_test,
            "Y_prediciton_train" : Y_prediction_train,
            "w" : w,
            "b" : b,
            "learning_rate" : learning_rate,
            "num_iterations" : num_iterations }
    return d

把整個model構建好之後我們這就算是正式的實際測試了,我們這就來實際跑一下。

print("====================測試model====================")     
#這裏加載的是真實的數據,請參見上面的代碼部分。
d = model(train_set_x, train_set_y, test_set_x, test_set_y, num_iterations = 2000, learning_rate = 0.005, print_cost = True)

執行後的數據:

====================測試model====================
迭代的次數: 0 , 誤差值: 0.693147
迭代的次數: 100 , 誤差值: 0.584508
迭代的次數: 200 , 誤差值: 0.466949
迭代的次數: 300 , 誤差值: 0.376007
迭代的次數: 400 , 誤差值: 0.331463
迭代的次數: 500 , 誤差值: 0.303273
迭代的次數: 600 , 誤差值: 0.279880
迭代的次數: 700 , 誤差值: 0.260042
迭代的次數: 800 , 誤差值: 0.242941
迭代的次數: 900 , 誤差值: 0.228004
迭代的次數: 1000 , 誤差值: 0.214820
迭代的次數: 1100 , 誤差值: 0.203078
迭代的次數: 1200 , 誤差值: 0.192544
迭代的次數: 1300 , 誤差值: 0.183033
迭代的次數: 1400 , 誤差值: 0.174399
迭代的次數: 1500 , 誤差值: 0.166521
迭代的次數: 1600 , 誤差值: 0.159305
迭代的次數: 1700 , 誤差值: 0.152667
迭代的次數: 1800 , 誤差值: 0.146542
迭代的次數: 1900 , 誤差值: 0.140872
訓練集準確性: 99.04306220095694 %
測試集準確性: 70.0 %

我們更改一下學習率和迭代次數,有可能會發現訓練集的準確性可能會提高,但是測試集準確性會下降,這是由於過擬合造成的,但是我們並不需要擔心,我們以後會使用更好的算法來解決這些問題的。


到目前爲止,我們的程序算是完成了,但是,我們可以在後面加一點東西,比如畫點圖什麼的。

#繪製圖
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()

跑一波出來的效果圖是這樣的,可以看到成本下降,它顯示參數正在被學習:
pic

讓我們進一步分析一下,並研究學習率alpha的可能選擇。爲了讓漸變下降起作用,我們必須明智地選擇學習速率。學習率α\alpha 決定了我們更新參數的速度。如果學習率過高,我們可能會“超過”最優值。同樣,如果它太小,我們將需要太多迭代才能收斂到最佳值。這就是爲什麼使用良好調整的學習率至關重要的原因。

我們可以比較一下我們模型的學習曲線和幾種學習速率的選擇。也可以嘗試使用不同於我們初始化的learning_rates變量包含的三個值,並看一下會發生什麼。

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()

跑一下打印出來的結果是:

learning rate is: 0.01
訓練集準確性: 99.52153110047847 %
測試集準確性: 68.0 %

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

learning rate is: 0.001
訓練集準確性: 88.99521531100478 %
測試集準確性: 64.0 %

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

learning rate is: 0.0001
訓練集準確性: 68.42105263157895 %
測試集準確性: 36.0 %

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

pic2


**【完整代碼】: **

# -*- coding: utf-8 -*-
"""
Created on Wed Mar 21 17:25:30 2018

博客地址 :http://blog.csdn.net/u013733326/article/details/79639509

@author: Oscar
"""

import numpy as np
import matplotlib.pyplot as plt
import h5py
from lr_utils import load_dataset

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

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))

#將訓練集的維度降低並轉置。
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

print ("訓練集降維最後的維度: " + str(train_set_x_flatten.shape))
print ("訓練集_標籤的維數 : " + str(train_set_y.shape))
print ("測試集降維之後的維度: " + str(test_set_x_flatten.shape))
print ("測試集_標籤的維數 : " + str(test_set_y.shape))

train_set_x = train_set_x_flatten / 255
test_set_x = test_set_x_flatten / 255

def sigmoid(z):
    """
    參數:
        z  - 任何大小的標量或numpy數組。

    返回:
        s  -  sigmoid(z)
    """
    s = 1 / (1 + np.exp(-z))
    return s

def initialize_with_zeros(dim):
    """
        此函數爲w創建一個維度爲(dim,1)的0向量,並將b初始化爲0。

        參數:
            dim  - 我們想要的w矢量的大小(或者這種情況下的參數數量)

        返回:
            w  - 維度爲(dim,1)的初始化向量。
            b  - 初始化的標量(對應於偏差)
    """
    w = np.zeros(shape = (dim,1))
    b = 0
    #使用斷言來確保我要的數據是正確的
    assert(w.shape == (dim, 1)) #w的維度是(dim,1)
    assert(isinstance(b, float) or isinstance(b, int)) #b的類型是float或者是int

    return (w , b)

def propagate(w, b, X, Y):
    """
    實現前向和後向傳播的成本函數及其梯度。
    參數:
        w  - 權重,大小不等的數組(num_px * num_px * 3,1)
        b  - 偏差,一個標量
        X  - 矩陣類型爲(num_px * num_px * 3,訓練數量)
        Y  - 真正的“標籤”矢量(如果非貓則爲0,如果是貓則爲1),矩陣維度爲(1,訓練數據數量)

    返回:
        cost- 邏輯迴歸的負對數似然成本
        dw  - 相對於w的損失梯度,因此與w相同的形狀
        db  - 相對於b的損失梯度,因此與b的形狀相同
    """
    m = X.shape[1]

    #正向傳播
    A = sigmoid(np.dot(w.T,X) + b) #計算激活值,請參考公式2。
    cost = (- 1 / m) * np.sum(Y * np.log(A) + (1 - Y) * (np.log(1 - A))) #計算成本,請參考公式3和4。

    #反向傳播
    dw = (1 / m) * np.dot(X, (A - Y).T) #請參考視頻中的偏導公式。
    db = (1 / m) * np.sum(A - Y) #請參考視頻中的偏導公式。

    #使用斷言確保我的數據是正確的
    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)

def optimize(w , b , X , Y , num_iterations , learning_rate , print_cost = False):
    """
    此函數通過運行梯度下降算法來優化w和b

    參數:
        w  - 權重,大小不等的數組(num_px * num_px * 3,1)
        b  - 偏差,一個標量
        X  - 維度爲(num_px * num_px * 3,訓練數據的數量)的數組。
        Y  - 真正的“標籤”矢量(如果非貓則爲0,如果是貓則爲1),矩陣維度爲(1,訓練數據的數量)
        num_iterations  - 優化循環的迭代次數
        learning_rate  - 梯度下降更新規則的學習率
        print_cost  - 每100步打印一次損失值

    返回:
        params  - 包含權重w和偏差b的字典
        grads  - 包含權重和偏差相對於成本函數的梯度的字典
        成本 - 優化期間計算的所有成本列表,將用於繪製學習曲線。

    提示:
    我們需要寫下兩個步驟並遍歷它們:
        1)計算當前參數的成本和梯度,使用propagate()。
        2)使用w和b的梯度下降法則更新參數。
    """

    costs = []

    for i in range(num_iterations):

        grads, cost = propagate(w, b, X, Y)

        dw = grads["dw"]
        db = grads["db"]

        w = w - learning_rate * dw
        b = b - learning_rate * db

        #記錄成本
        if i % 100 == 0:
            costs.append(cost)
        #打印成本數據
        if (print_cost) and (i % 100 == 0):
            print("迭代的次數: %i , 誤差值: %f" % (i,cost))

    params  = {
                "w" : w,
                "b" : b }
    grads = {
            "dw": dw,
            "db": db } 
    return (params , grads , costs)

def predict(w , b , X ):
    """
    使用學習邏輯迴歸參數logistic (w,b)預測標籤是0還是1,

    參數:
        w  - 權重,大小不等的數組(num_px * num_px * 3,1)
        b  - 偏差,一個標量
        X  - 維度爲(num_px * num_px * 3,訓練數據的數量)的數據

    返回:
        Y_prediction  - 包含X中所有圖片的所有預測【0 | 1】的一個numpy數組(向量)

    """

    m  = X.shape[1] #圖片的數量
    Y_prediction = np.zeros((1,m)) 
    w = w.reshape(X.shape[0],1)

    #計預測貓在圖片中出現的概率
    A = sigmoid(np.dot(w.T , X) + b)
    for i in range(A.shape[1]):
        #將概率a [0,i]轉換爲實際預測p [0,i]
        Y_prediction[0,i] = 1 if A[0,i] > 0.5 else 0
    #使用斷言
    assert(Y_prediction.shape == (1,m))

    return Y_prediction

def model(X_train , Y_train , X_test , Y_test , num_iterations = 2000 , learning_rate = 0.5 , print_cost = False):
    """
    通過調用之前實現的函數來構建邏輯迴歸模型

    參數:
        X_train  - numpy的數組,維度爲(num_px * num_px * 3,m_train)的訓練集
        Y_train  - numpy的數組,維度爲(1,m_train)(矢量)的訓練標籤集
        X_test   - numpy的數組,維度爲(num_px * num_px * 3,m_test)的測試集
        Y_test   - numpy的數組,維度爲(1,m_test)的(向量)的測試標籤集
        num_iterations  - 表示用於優化參數的迭代次數的超參數
        learning_rate  - 表示optimize()更新規則中使用的學習速率的超參數
        print_cost  - 設置爲true以每100次迭代打印成本

    返回:
        d  - 包含有關模型信息的字典。
    """
    w , b = initialize_with_zeros(X_train.shape[0])

    parameters , grads , costs = optimize(w , b , X_train , Y_train,num_iterations , learning_rate , print_cost)

    #從字典“參數”中檢索參數w和b
    w , b = parameters["w"] , parameters["b"]

    #預測測試/訓練集的例子
    Y_prediction_test = predict(w , b, X_test)
    Y_prediction_train = predict(w , b, X_train)

    #打印訓練後的準確性
    print("訓練集準確性:"  , format(100 - np.mean(np.abs(Y_prediction_train - Y_train)) * 100) ,"%")
    print("測試集準確性:"  , format(100 - np.mean(np.abs(Y_prediction_test - Y_test)) * 100) ,"%")

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

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

#繪製圖
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()
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章