deeplearning.ai官網(wǎng)地址:https://www.deeplearning.ai/
coursera地址:https://www.coursera.org/specializations/deep-learning
網(wǎng)易視頻地址:https://163.lu/nPtn42
課程一第二周課后作業(yè)1-2
具有神經(jīng)網(wǎng)絡(luò)思維的邏輯回歸算法
本次作業(yè)师崎,將會構(gòu)建一個邏輯回歸分類器用以識別貓荞估, 通過完成這次作業(yè),也能了解一些神經(jīng)網(wǎng)絡(luò)的思維,并且能夠建立一個對神經(jīng)網(wǎng)絡(luò)的基本認(rèn)識贰健。
1. 導(dǎo)入相關(guān)包
首先,導(dǎo)入接剩,本此作業(yè)實(shí)現(xiàn)中所需要的所有相關(guān)包皆警,具體實(shí)現(xiàn)如下:
import numpy as np
import matplotlib.pyplot as plt
import h5py
import scipy
from PIL import Image
from scipy import ndimage
from lr_utils import load_dataset
2.數(shù)據(jù)集的概述
作業(yè)所用到的數(shù)據(jù)集存儲在data.h5
文件中,對于數(shù)據(jù)集溢十,有以下介紹:
- 數(shù)據(jù)集中的訓(xùn)練集
m_train
圖像垮刹,被標(biāo)注為cat (y=1)
和non-cat (y=0)
- 數(shù)據(jù)集中的測試集
m_test
圖像,同樣张弛,被標(biāo)注為cat
和non-cat
- 每一幅圖像的都是
(num_px,num_px,3)
的形式荒典,其中3表示圖像是3通道的RGB形式酪劫,而長和寬都是num_px
和num_px
的正方形圖片。 - 加載數(shù)據(jù)前寺董,可以利用python查看數(shù)據(jù)集的存儲形式覆糟,具體實(shí)現(xiàn)代碼如下所示;
f = h5py.File('dataset/train_catvnoncat.h5','r') #打開h5文件
# 可以查看所有的主鍵
for key in f.keys():
print(f[key].name) #輸出數(shù)據(jù)集標(biāo)簽值,train_set_x,train_set_y
print(f[key].shape) #輸出數(shù)據(jù)集train_set_x,train_set_y的形式
print(f[key].value) #輸出數(shù)據(jù)集trian_set_x和train_set_y的具體值
根據(jù)以上數(shù)據(jù)形式遮咖,編寫loadset()
函數(shù)加載數(shù)據(jù)集的代碼如下所示:
def load_dataset():
train_dataset = h5py.File('datasets/train_catvnoncat.h5', "r")
train_set_x_orig = np.array(train_dataset["train_set_x"][:]) #訓(xùn)練集數(shù)據(jù)特征
train_set_y_orig = np.array(train_dataset["train_set_y"][:]) # 訓(xùn)練集數(shù)據(jù)標(biāo)簽
test_dataset = h5py.File('datasets/test_catvnoncat.h5', "r")
test_set_x_orig = np.array(test_dataset["test_set_x"][:]) # 測試集數(shù)據(jù)特征
test_set_y_orig = np.array(test_dataset["test_set_y"][:]) #測試集數(shù)據(jù)標(biāo)簽
classes = np.array(test_dataset["list_classes"][:]) # 數(shù)據(jù)類別構(gòu)成的列表
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
簡單的測試下加載好的數(shù)據(jù)集滩字,可以看到相關(guān)的輸出信息如下所示:
index = 5
plt.imshow(train_set_x_orig[index])
print ("y = " + str(train_set_y[:, index]) + ", it's a '" + classes[np.squeeze(train_set_y[:, index])].decode("utf-8") + "' picture.")
許多深度學(xué)習(xí)代碼存在bug的原因之一就是矩陣或者向量維數(shù)不匹配,在算法實(shí)現(xiàn)之前御吞,先進(jìn)行數(shù)據(jù)集的維度輸出是一個和明智的做法麦箍,具體實(shí)現(xiàn)算法如下代碼所示:
m_train = train_set_x_orig.shape[0]
m_test = test_set_x_orig.shape[0]
num_px = train_set_x_orig.shape[1]
print ("Number of training examples: m_train = " + str(m_train))
print ("Number of testing examples: m_test = " + str(m_test))
print ("Height/Width of each image: num_px = " + str(num_px))
print ("Each image is of size: (" + str(num_px) + ", " + str(num_px) + ", 3)")
print ("train_set_x shape: " + str(train_set_x_orig.shape))
print ("train_set_y shape: " + str(train_set_y.shape))
print ("test_set_x shape: " + str(test_set_x_orig.shape))
print ("test_set_y shape: " + str(test_set_y.shape))
上述代碼實(shí)現(xiàn)結(jié)果如下所示:
在圖像處理過程中,數(shù)據(jù)集中的圖像數(shù)據(jù)是一個(num_px,num_px,3)的矩陣陶珠,需要將其轉(zhuǎn)換為(num_px×num_px×3,1)的矩陣挟裂,在python
中有一個實(shí)現(xiàn)技巧如下所示,可輕松實(shí)現(xiàn)矩陣形式的轉(zhuǎn)化揍诽。
X_flatten = X.reshape(X.shape[0], -1).T
綜上所述诀蓉,具體實(shí)現(xiàn)代碼可以如下所示:
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 ("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))
print ("sanity check after reshaping: " + str(train_set_x_flatten[0:5,0]))
以上代碼結(jié)果如下所示:
為了表示圖片中的顏色,由RGB通道表示圖片顏色寝姿,即每個像素的值實(shí)際上是由三個0-255的數(shù)組成的向量交排。
機(jī)器學(xué)習(xí)中一種通用的處理數(shù)據(jù)集的方法稱之為標(biāo)準(zhǔn)化,對于圖像數(shù)據(jù)集而言饵筑,一種簡單而又方便的處理數(shù)據(jù)的方法是對每一行數(shù)據(jù)除以255埃篓,即其RGB的最大值。具體實(shí)現(xiàn)可以如以下代碼所示:
train_set_x = train_set_x_flatten/255.
test_set_x = test_set_x_flatten/255.
3. 學(xué)習(xí)算法的一般體系架構(gòu)
有了如上的數(shù)據(jù)預(yù)處理流程根资,是時候構(gòu)建一個具有神經(jīng)網(wǎng)絡(luò)思維的算法了架专,其算法實(shí)現(xiàn)過程基本如下圖所示:
對于一個樣本 :
所有樣本的損失可以由以下公式計算:
實(shí)現(xiàn)這個算法的關(guān)鍵步驟是:
- 初始化模型的學(xué)習(xí)參數(shù)
- 通過最小化損失函數(shù)得到模型的學(xué)習(xí)參數(shù)
- 根據(jù)模型的學(xué)習(xí)參數(shù)做出相關(guān)預(yù)測
- 分析預(yù)測結(jié)果并得出相關(guān)結(jié)論
4. 算法的構(gòu)建過程
構(gòu)建分類算法的主要步驟可以如下步驟所示:
- 構(gòu)建模型架構(gòu),例如特征的個數(shù)
- 初始化模型參數(shù)
- 循環(huán):
- 計算當(dāng)前損失
- 利用反向傳播算法計算當(dāng)前的梯度
- 通過梯度下降更新參數(shù)
4.1 sigmoid函數(shù)
邏輯回歸中的激活函數(shù)是sigmoid函數(shù)玄帕,其實(shí)現(xiàn)方式可以由以下代碼所示:
def sigmoid(z):
s = 1 / (1 + np.exp(-z))
return s
4.2 初始化參數(shù)
初始化權(quán)重參數(shù)并使其為0部脚,參數(shù),具體實(shí)現(xiàn)代碼如下所示:
def initialize_with_zeros(dim):
w = np.zeros((dim, 1))
b = 0
#確保參數(shù)w的維數(shù)和數(shù)據(jù)類型正確
assert(w.shape == (dim, 1))
assert(isinstance(b, float) or isinstance(b, int))
return w, b
4.3 前向和反向傳播算法
初始化參數(shù)之后裤纹,通過傳播算法計算學(xué)習(xí)參數(shù)了委刘,關(guān)于參數(shù)的計算其公式如下是所示:
前向傳播算法:
通過輸入變量計算:
計算損失函數(shù):
可以通過以下兩個公式計算相關(guān)參數(shù):
根據(jù)以上公式,算法實(shí)現(xiàn)的代碼如下所示:
def propagate(w, b, X, Y):
m = X.shape[1]
A = sigmoid(np.dot(w.T, X) + b)
cost = -1 / m * np.sum(Y * np.log(A) + (1 - Y) * np.log(1 - A))
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 == ())
grads = {"dw": dw, "db": db}
return grads, cost
4.4 利用梯度下降優(yōu)化算法
有了前向傳播算法對參數(shù)的計算鹰椒,接下來需要做的就是利用反向傳播算法中的梯度下降算法更新參數(shù)锡移,具體實(shí)現(xiàn)代碼如下所示:
def optimize(w, b, X, Y, num_iterations, learning_rate, print_cost = False):
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 ("Cost after iteration %i: %f" %(i, cost))
params = {"w": w,
"b": b}
grads = {"dw": dw,
"db": db}
return params, grads, costs
有了通過反向傳播算法得到的參數(shù)和,可以根據(jù)公式:
做出預(yù)測了漆际,具體實(shí)現(xiàn)代碼如下所示:
def predict(w, b, X):
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]):
if A[0, i] <= 0.5:
Y_prediction[0, i] = 0
else:
Y_prediction[0, i] = 1
assert(Y_prediction.shape == (1, m))
return Y_prediction
5. 將所有函數(shù)合并在一起搭建模型
通過以上淆珊,已經(jīng)分模塊實(shí)現(xiàn)了算法的所有部分,現(xiàn)在可以通過構(gòu)建一個模型函數(shù)將所有的函數(shù)合并在一起奸汇,用以實(shí)現(xiàn)模型的參數(shù)更新和預(yù)測施符,具體實(shí)現(xiàn)代碼如下所示:
def model(X_train, Y_train, X_test, Y_test, num_iterations = 2000, learning_rate = 0.5, print_cost = False):
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 = parameters["w"]
b = parameters["b"]
Y_prediction_test = predict(w, b, X_test)
Y_prediction_train = predict(w, b, X_train)
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
可以簡單繪制模型訓(xùn)練過程中損失函數(shù)和梯度的變化曲線往声,如下所示:
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()
如上圖所示,可以看到戳吝,隨著迭代次數(shù)的增加浩销,模型的損失正在下降,當(dāng)?shù)虼螖?shù)增加骨坑,將會看到訓(xùn)練集的損失逐漸上升撼嗓,而測試集的損失逐漸下降。
6. 進(jìn)一步的分析
學(xué)習(xí)率的大小對于模型的訓(xùn)練也是至關(guān)重要的欢唾,當(dāng)學(xué)習(xí)率的大小決定著參數(shù)更新的速度且警,當(dāng)學(xué)習(xí)率過大時,模型不容易收斂礁遣,而當(dāng)學(xué)習(xí)率過小時斑芜,模型的需要迭代很多次才能收斂,可以用以下代碼驗(yàn)證學(xué)習(xí)率對模型訓(xùn)練的影響祟霍。
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')
綜上杏头,可以得到如下結(jié)論:
- 不同的學(xué)習(xí)率會得到不同的預(yù)測結(jié)果和損失
- 如果模型的學(xué)習(xí)率過大,可能會導(dǎo)致模型的損失上下振蕩沸呐,如上圖所示醇王,學(xué)習(xí)率取0.001可能是一個不錯的選擇。
- 過小的損失不一定意味著該模型是一個好模型崭添,能做出很好的預(yù)測寓娩,很可能是過擬合原因造成的。這種過擬合情況通常發(fā)生在訓(xùn)練集的精確度比測試集高很多的情況下呼渣。
- 對于深度學(xué)習(xí)棘伴,通常有如下建議:
- 為模型選擇一個合適的學(xué)習(xí)率以得到更好的模型參數(shù)
- 如果模型過擬合,通常要采取其他措施消除這種過擬合屁置,一種行之有效的方法是正則化方法焊夸。