吴恩达深度学习课程第二章第一周编程作业
文章目錄
- 聲明
- 一、任務描述
- 二、編程實現
- 1.數據
- 2.參數初始化
- 2.1 初始化參數為0
- 2.2 參數隨機初始化
- 2.3 抑梯度異常初始化
- 2.4 主控函數
- 2.5 測試結果對比
- 2.5.1 初始化為0
- 2.5.2 隨機初始化參數
- 2.5.3抑梯度異常初始化
- 3.模型正則化
- 3.1 未使用正則化
- 3.2 L2正則化
- 3.3 dropout正則化
- 總結
聲明
??本博客只是記錄一下本人在深度學習過程中的學習筆記和編程經驗,大部分代碼是參考了【中文】【吳恩達課后編程作業】Course 2 - 改善深層神經網絡 - 第一周作業(1&2&3)這篇博客,對其代碼實現了復現,代碼或文字表述中還存在一些問題,請見諒,之前的博客也是主要參考這個大佬。
一、任務描述
??這次作業我們的主要任務是以下三個:
1.初始化參數:0初始化,隨機初始化,使用抑梯度異常初始化參數。 2.正則化:L2正則化,dropout正則化。 3.梯度校驗 :對模型使用梯度校驗,檢測它是否在梯度下降的過程中出現誤差過大的情況。??本次作業的重點是在參數初始化,正則化和梯度檢驗上,因此對于神經網絡的相關實現進行過多描述。三個知識點對于神經網絡的要求并不完全相同,在正向和反向傳播上存在差異,分別創建對應的 init_utils.py ,reg_utils.py 和 gc_utils.py 文件,封裝神經網絡的相關操作,神經網絡統一為兩層結構,即一個輸入層,一個隱藏層和一個輸出層。
二、編程實現
1.數據
??本次作業提供了一份數據,用matplotlib繪制:
??本次作業中要處理的問題也是一個二分類問題。
2.參數初始化
??根據課程知識,我們可以分別對三種初始化的情形編程。
2.1 初始化參數為0
def initialize_zeros(layers_dims):"""將參數都設置成0:param layers_dims:列表,各層的神經元個數:return:"""parameters = {}for i in range(1, len(layers_dims)):parameters["W" + str(i)] = np.zeros((layers_dims[i], layers_dims[i - 1]))parameters["b" + str(i)] = np.zeros((layers_dims[i], 1))assert(parameters["W" + str(i)].shape == (layers_dims[i], layers_dims[i - 1]))assert (parameters["b" + str(i)].shape == (layers_dims[i], 1))return parameters2.2 參數隨機初始化
def initialize_random(layers_dims):"""將W隨機初始化,b依舊初始化為0:param layers_dims:列表,各層的神經元個數:return:"""np.random.seed(3)parameters = {}for i in range(1, len(layers_dims)):parameters["W" + str(i)] = np.random.randn(layers_dims[i], layers_dims[i - 1])*10parameters["b" + str(i)] = np.zeros((layers_dims[i], 1))assert (parameters["W" + str(i)].shape == (layers_dims[i], layers_dims[i - 1]))assert (parameters["b" + str(i)].shape == (layers_dims[i], 1))return parameters2.3 抑梯度異常初始化
??抑梯度異常初始化需要在隨機初始化W矩陣的基礎上乘上系數(1/n[L-1])^(1/2),即上層神經元個數(也就是當前神經元的輸入個數)的倒數取平方根。
def initialize_random_he(layers_dims):"""將W隨機初始化,b依舊初始化為0:param layers_dims:列表,各層的神經元個數:return:"""np.random.seed(3)parameters = {}for i in range(1, len(layers_dims)):parameters["W" + str(i)] = np.random.randn(layers_dims[i], layers_dims[i - 1])*np.sqrt(2 / layers_dims[i - 1])parameters["b" + str(i)] = np.zeros((layers_dims[i], 1))assert (parameters["W" + str(i)].shape == (layers_dims[i], layers_dims[i - 1]))assert (parameters["b" + str(i)].shape == (layers_dims[i], 1))return parameters2.4 主控函數
def model(X, Y, learning_rate=0.01, num_iterations=15000, print_cost=True, initialization="he", is_plot=True):"""實現一個三層(雙層隱藏層一層輸出層)神經網絡:RELU,RELU,SIGMOID:param X: 輸入數據:param Y: 輸入數據標簽:param learning_rate:學習率:param num_iterations: 迭代次數:param print_cost: 是否打印損失值:param initialization: 參數初始化類型:param is_plot: 是否繪制梯度下降曲線:return:"""grads = {}costs = []layers_dim = [X.shape[0], 10, 5, 1]sample_num = X.shape[1]# 隨機初始化神經網絡參數if initialization == "zeros":parameters = initialize_zeros(layers_dim)elif initialization == "random":parameters = initialize_random(layers_dim)elif initialization == "random_he":parameters = initialize_random_he(layers_dim)else:print("傳參錯誤")for i in range(0, num_iterations):a3, cache = init_utils.forward_propagation(X, parameters)cost = init_utils.compute_loss(a3, Y)grads = init_utils.backward_propagation(X, Y, cache)parameters = init_utils.update_parameters(parameters, grads, learning_rate)if i % 1000 == 0:costs.append(cost)if print_cost:print("第" + str(i) + "次迭代,成本值為:" + str(cost))if is_plot:plt.plot(costs)plt.ylabel('cost')plt.xlabel('iterations (per hundreds)')plt.title("Learning rate =" + str(learning_rate))plt.show()return parameters2.5 測試結果對比
2.5.1 初始化為0
??初始化參數為0時的損失函數曲線:
??用matplotlib繪制初始化參數為0時的決策邊界:
??得到的模型在訓練集和測試集上的表現效果:
??可以看出,初始化參數為0時,模型的表現效果非常差,預測的每個結果都為0。用0初始化神經網絡參數無法打破網絡的對稱性。
2.5.2 隨機初始化參數
??繪制隨機初始化損失曲線如下:
??用matplotlib繪制決策邊界:
??得到的模型在訓練集和測試集上的表現效果:
??從結果可以看出,隨機初始化的效果比初始化為0的效果好的多,但是隨機初始化存在一些問題,上次作業中我提到過,如果權重矩陣隨機初始化為較大的值會導致梯度消失和梯度爆炸,之前的解決方案是直接在初始化權重矩陣時乘上系數0.01,這里將嘗試采用抑梯度異常初始化的方式來對權重矩陣的初始化進行控制。
2.5.3抑梯度異常初始化
??繪制損失曲線如下:
??用matplotlib繪制決策邊界:
??得到的模型在訓練集和測試集上的表現效果:
??從結果可以看出,抑梯度異常初始化的方法得到的模型表現效果特別好。
3.模型正則化
??吳恩達老師的視頻中主要講述了兩種正則化的方法:L2正則化和dropout正則化。這次我們需要使用到的數據分布如下:
??我們還是以兩層神經網絡為基礎編寫代碼,主控函數代碼如下:
??主控函數model需要傳入參數 lambd 和 keep_drop 分別是L2正則化和dropout正則化需要的超參數。當lambd>0時,L2正則化才起作用。當keep_drop<1時,dropout正則化才起作用。接下來分別對這兩種正則化方法進行編程。
3.1 未使用正則化
??當我們往model中傳入的參數lambd=0,keep_drop=1時表示不使用正則化。
if __name__ == "__main__":train_X, train_Y, test_X, test_Y = reg_utils.load_2D_dataset(is_plot=True)parameters = model(train_X, train_Y, is_plot=True)print("訓練集:")predictions_train = reg_utils.predict(train_X, train_Y, parameters)print("測試集:")predictions_test = reg_utils.predict(test_X, test_Y, parameters)plt.title("Model without regularization")axes = plt.gca()axes.set_xlim([-0.75, 0.40])axes.set_ylim([-0.75, 0.65])??繪制損失曲線如下:
??繪制決策邊界:
??模型在訓練集和測試集上的表現:
??可以看到訓練集上的準確率高于測試集上的準確率,可以視為過擬合現象,接下來通過L2正則化降低過擬合現象。
3.2 L2正則化
??L2正則化是在損失函數的基礎上加了正則項,這樣其實并不會影響神經網絡的正向傳播,只需要對神經網絡的反向傳播代碼和損失函數計算代碼進行調整。
def backward_propagation_with_regularization(X, Y, cache, lambd):"""實現正則化后的反向傳播:param X: 輸入數據:param Y: 實際標簽值:param cache: forward的cache:param lambd: 正則化參數:return:"""m = X.shape[1](Z1, A1, W1, b1, Z2, A2, W2, b2, Z3, A3, W3, b3) = cachedZ3 = A3 - YdW3 = (1 / m) * np.dot(dZ3, A2.T) + ((lambd * W3) / m)db3 = (1 / m) * np.sum(dZ3, axis=1, keepdims=True)dA2 = np.dot(W3.T, dZ3)dZ2 = np.multiply(dA2, np.int64(A2 > 0))dW2 = (1 / m) * np.dot(dZ2, A1.T) + ((lambd / W2) / m)db2 = (1 / m) * np.sum(dZ2, axis=1, keepdims=True)dA1 = np.dot(W2.T, dZ2)dZ1 = np.multiply(dA1, np.int64(A1 > 0))dW1 = (1 / m) * np.dot(dZ1, X.T) + ((lambd * W1) / m)db1 = (1 / m) * np.sum(dZ1, axis=1, keepdims=True)gradients = {"dZ3": dZ3, "dW3": dW3, "db3": db3, "dA2": dA2,"dZ2": dZ2, "dW2": dW2, "db2": db2, "dA1": dA1,"dZ1": dZ1, "dW1": dW1, "db1": db1}return gradients??損失函數計算代碼:
def compute_cost_with_regularization(A3, Y, parameters, lambd):"""實現L2正則化的損失函數計算:param A3: 輸出層的輸出值:param Y: 實際標簽值:param parameters:神經網絡參數:param lambd: 正則化參數:return:"""cost_part1 = compute_cost(A3, Y)m = Y.shape[1]W1 = parameters["W1"]W2 = parameters["W2"]W3 = parameters["W3"]L2_regularization_cost = lambd * (np.sum(np.square(W1)) + np.sum(np.square(W2)) + np.sum(np.square(W3))) / (2 * m)cost = cost_part1 + L2_regularization_costreturn cost??設置超參數lambd=0.7,損失曲線繪制如下:
??決策邊界繪制如下:
??模型在訓練集和測試集上的表現:
??從結果可以看出,使用L2正則化的后,模型在訓練集和測試集上的表現效果十分接近,有效的解決了過擬合。
3.3 dropout正則化
??dropout正則化會影響常規的正向傳播和反向傳播,損失函數的計算沒有影響。正向傳播代碼如下:
"""dropout正則化前向傳播:RELU+DROPOUT,RELU+DROPOUT,SIGMOID:param X:輸入數據:param parameters:神經網絡參數:param keep_prob: dropout參數:return:"""np.random.seed(1)W1 = parameters["W1"]b1 = parameters["b1"]W2 = parameters["W2"]b2 = parameters["b2"]W3 = parameters["W3"]b3 = parameters["b3"]Z1 = np.dot(W1, X) + b1A1 = relu(Z1)D1 = np.random.rand(A1.shape[0], A1.shape[1])D1 = D1 < keep_probA1 = A1 * D1A1 = A1 / keep_probZ2 = np.dot(W2, A1) + b2A2 = relu(Z2)D2 = np.random.rand(A2.shape[0], A2.shape[1])D2 = D2 < keep_probA2 = A2 * D2A2 = A2 / keep_probZ3 = np.dot(W3, A2) + b3A3 = sigmoid(Z3)cache = (Z1, D1, A1, W1, b1, Z2, D2, A2, W2, b2, Z3, A3, W3, b3)return A3, cache??反向傳播代碼如下:
def backward_propagation_with_dropout(X, Y, cache, keep_prob):"""實現dropout正則化后的反向傳播:param X: 輸入數據:param Y: 標簽值:param cache: 正向傳播的緩存:param keep_prob: dropout正則化參數:return:"""m = X.shape[1](Z1, D1, A1, W1, b1, Z2, D2, A2, W2, b2, Z3, A3, W3, b3) = cachedZ3 = A3 - YdW3 = (1 / m) * np.dot(dZ3, A2.T)db3 = (1 / m) * np.sum(dZ3, axis=1, keepdims=True)dA2 = np.dot(W3.T, dZ3)dA2 = dA2 * D2dA2 = dA2 / keep_probdZ2 = np.multiply(dA2, np.int64(A2 > 0))dW2 = (1. / m) * np.dot(dZ2, A1.T)db2 = (1. / m) * np.sum(dZ2, axis=1, keepdims=True)dA1 = np.dot(W2.T, dZ2)dA1 = dA1 * D1dA1 = dA1 / keep_probdZ1 = np.multiply(dA1, np.int64(A1 > 0))dW1 = (1. / m) * np.dot(dZ1, X.T)db1 = (1. / m) * np.sum(dZ1, axis=1, keepdims=True)gradients = {"dZ3": dZ3, "dW3": dW3, "db3": db3, "dA2": dA2,"dZ2": dZ2, "dW2": dW2, "db2": db2, "dA1": dA1,"dZ1": dZ1, "dW1": dW1, "db1": db1}return gradients??將主控函數中的keep_drop的值設為0.86,繪制損失曲線如下:
??繪制決策邊界:
??模型在訓練集和測試集上的表現效果:
??dropout正則化降低了模型在訓練集上的準確率,提高了模型在測試集上的準確率,成功地解決了過擬合現象。另外,在寫代碼的過程中,初始化矩陣D時,使用了randn函數而不是rand函數,導致結果偏低。
??rand和randn都是numpy庫中生成的隨機數的函數,但是rand是生成一個數組,并在數組中加入在[0,1]之間均勻分布的隨機樣本。randn則是創建一個數組,數組中的元素符合正態分布。很明顯在dropout正則化中,我們需要初始化數組D中的數據在[0,1]之間均與分布,這樣就可以保證D中小于keep_drop的元素占比為keep_drop。
總結
??再次聲明,本博客的主要代碼參考來源為【中文】【吳恩達課后編程作業】Course 2 - 改善深層神經網絡 - 第一周作業(1&2&3) - 初始化、正則化、梯度校驗,原博客講述更加詳細。本人的代碼已上傳到百度網盤中,提取碼:uu35。
總結
以上是生活随笔為你收集整理的吴恩达深度学习课程第二章第一周编程作业的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 鸿蒙系统桌面天气如何设置,怎么设置桌面时
- 下一篇: 吴恩达深度学习课程第二章第三周编程作业(