吳恩達深度學習課程第一課 — 神經網絡與深度學習1,2

第二週

邏輯迴歸是一個用於二分類(binary classification)的算法。

sigmoid函數

在梯度下降法中,會得到局部最優解,不能得到全局最優解

在邏輯迴歸中,使用的損失函數:

損失函數是在單個訓練樣本中定義的,它衡量的是算法在單個訓練樣本中表現如何,爲了衡量算法在全部訓練樣本上的表現如何。

我們需要定義一個算法的代價函數,算法的代價函數是對m個樣本的損失函數求和然後除以m:

 

損失函數只適用於像這樣的單個訓練樣本,而代價函數是參數的總代價,所以在訓練邏輯迴歸模型時候,我們需要找到合適的w和b,來讓代價函數J 的總代價降到最低。

 

所以這裏有很多細節,但讓我們把這些裝進一個具體的算法。同時你需要一起應用的就是邏輯迴歸和梯度下降。

我們初始化

代碼流程:

J=0;dw1=0;dw2=0;db=0;
for i = 1 to m
    z(i) = wx(i)+b;
    a(i) = sigmoid(z(i));
    J += -[y(i)log(a(i))+(1-y(i))log(1-a(i));
    dz(i) = a(i)-y(i);
    dw1 += x1(i)dz(i);
    dw2 += x2(i)dz(i);
    db += dz(i);
J/= m;
dw1/= m;
dw2/= m;
db/= m;
w=w-alpha*dw
b=b-alpha*db

 

使用向量化替代顯示for循環

 

此處b是一個實數,自動擴展成1*m的行向量(broadcasting廣播)

 

梯度下降的一次迭代:

上面可被下面替換

列相加

 

axis=1 水平相加

python的廣播機制

 

 

一個向量的具體緯度

神經元節點先計算線性函數(z = Wx + b),再計算激活。

神經元的輸出是a = g(Wx + b),其中g是激活函數(sigmoid,tanh,ReLU,…)。

第二章編程作業-識別貓

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

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()
index=25
plt.imshow(train_set_x_orig[index])
#查看訓練集的標籤
print("train_set_y="+str(train_set_y))

結合一下訓練集裏面的數據來看一下都加載了一些什麼東西。

#打印出當前的訓練標籤值
#使用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")
  • m_train :訓練集裏圖片的數量。
  • m_test :測試集裏圖片的數量。
  • num_px : 訓練、測試集裏面的圖片的寬度和高度(均爲64x64)。

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

爲了方便,我們要把維度爲(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列。測試集亦如此。

爲了表示彩色圖像,必須爲每個像素指定紅色,綠色和藍色通道(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

開始構建神經網絡


然後通過對所有訓練樣例求和來計算成本:

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

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

  2. 初始化模型的參數

  3. 循環:

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

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

    3.3 更新參數(梯度下降)

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

初始化我們需要的參數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))

使用漸變下降更新參數。

 

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

整合

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

繪圖

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

成本下降,它顯示參數正在被學習

爲了讓漸變下降起作用,我們必須明智地選擇學習速率。學習率α \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()

 

 

 

 

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