)
簡介本資源是一份面向本科及碩士階段教學與自學的Matlab神經(jīng)網(wǎng)絡(luò)基礎(chǔ)實踐材料聚焦多層感知器MLP模型的反向傳播算法原理與工程實現(xiàn)幫助學習者深入理解前饋結(jié)構(gòu)、激活函數(shù)、梯度計算與權(quán)重更新等核心機制。壓縮包共2000個文件主體為4236張訓練過程可視化圖像如螺旋數(shù)據(jù)分類結(jié)果圖fig4600–fig5000、最終決策邊界圖輔以4個關(guān)鍵M文件含網(wǎng)絡(luò)構(gòu)建MLP_NN.m、前向/反向傳播主邏輯、激活函數(shù)及其導數(shù)實現(xiàn)另有4個points數(shù)據(jù)點集支撐實驗復(fù)現(xiàn)整體體積197.48MB結(jié)構(gòu)清晰便于分階段調(diào)試與效果對比。已有1330人下載學習配套代碼完整可運行適配Matlab 2019a包含從數(shù)據(jù)生成、網(wǎng)絡(luò)初始化、迭代訓練到性能評估的全流程腳本特別適合神經(jīng)網(wǎng)絡(luò)入門者動手驗證理論、觀察收斂過程并建立直觀認知。1. 從零開始為什么用Matlab手搓一個MLP如果你正在學習機器學習尤其是神經(jīng)網(wǎng)絡(luò)那么“反向傳播”和“多層感知器”這兩個詞一定如雷貫耳。網(wǎng)上有無數(shù)現(xiàn)成的框架比如TensorFlow、PyTorch幾行代碼就能搭出一個強大的網(wǎng)絡(luò)。那么為什么我們還要費勁地用Matlab從頭實現(xiàn)一個MLP呢這就像學開車自動擋固然方便但真正理解離合、油門和變速箱如何協(xié)同工作才能讓你從“會開”變成“懂車”。手搓一個MLP正是為了讓你徹底搞懂神經(jīng)網(wǎng)絡(luò)內(nèi)部那套“傳動系統(tǒng)”——前向傳播如何計算輸出反向傳播又如何根據(jù)誤差調(diào)整每一個神經(jīng)元的“權(quán)重”和“偏置”。Matlab在這個學習過程中扮演了一個絕佳的角色。它強大的矩陣運算能力讓復(fù)雜的數(shù)學公式可以非常直觀地用幾行代碼表達出來避免了Python中NumPy等庫的底層細節(jié)干擾。你可以清晰地看到每一次迭代中數(shù)據(jù)如何流動參數(shù)如何更新誤差如何下降。這個過程會讓你對梯度下降、鏈式法則這些核心概念有刻骨銘心的理解而不是僅僅停留在調(diào)用model.fit()的層面。當你親手實現(xiàn)并調(diào)試成功一個MLP后再去看那些高級框架的API會有一種“原來如此”的通透感。這篇文章我就帶你從最基礎(chǔ)的數(shù)學原理出發(fā)用Matlab一步步構(gòu)建、訓練并可視化一個完整的MLP過程中遇到的每一個坑和對應(yīng)的填坑技巧我都會毫無保留地分享給你。2. MLP的核心架構(gòu)與數(shù)學原理拆解在動手寫代碼之前我們必須把MLP的“設(shè)計圖紙”和“工作原理”搞清楚。一個典型的多層感知器MLP通常包含一個輸入層、一個或多個隱藏層以及一個輸出層。每一層都由若干個神經(jīng)元或稱為節(jié)點組成層與層之間通過權(quán)重矩陣和偏置向量全連接。2.1 前向傳播信息如何從輸入流向輸出前向傳播的過程就是數(shù)據(jù)從輸入層開始逐層經(jīng)過加權(quán)求和、加上偏置、再通過一個非線性激活函數(shù)最終得到輸出層結(jié)果的過程。我們用數(shù)學公式來精確描述它。假設(shè)我們的網(wǎng)絡(luò)有L層輸入層不計入層數(shù)。我們用上標[l]表示第l層的相關(guān)參數(shù)。W[l]: 第l層的權(quán)重矩陣維度為(n[l], n[l-1])其中n[l]是第l層的神經(jīng)元個數(shù)。W[l]的第i行第j列元素w_{ij}^{[l]}表示第l-1層第j個神經(jīng)元到第l層第i個神經(jīng)元的連接權(quán)重。b[l]: 第l層的偏置向量維度為(n[l], 1)。Z[l]: 第l層的線性計算結(jié)果加權(quán)輸入Z[l] W[l] * A[l-1] b[l]。A[l]: 第l層的激活值輸出A[l] g[l](Z[l])其中g(shù)[l]()是第l層的激活函數(shù)。我們約定A[0]就是輸入數(shù)據(jù)X。以一個簡單的3層網(wǎng)絡(luò)1個隱藏層為例處理單個樣本x列向量時輸入層A[0] x隱藏層Z[1] W[1] * A[0] b[1],A[1] g[1](Z[1])例如g[1]可以是ReLU或Sigmoid輸出層Z[2] W[2] * A[1] b[2],A[2] g[2](Z[2])例如二分類問題g[2]用Sigmoid多分類用Softmax這里的A[2]就是網(wǎng)絡(luò)的最終預(yù)測輸出y_hat。在實際編程中我們通常一次性處理一個批量的樣本比如m個此時輸入X的維度是(n[0], m)每一列是一個樣本。矩陣運算的優(yōu)勢就體現(xiàn)出來了上述公式完全適用只是A[l]和Z[l]的維度變成了(n[l], m)計算過程完全向量化效率極高。2.2 反向傳播誤差如何指導參數(shù)更新前向傳播得到了預(yù)測值y_hat我們通過損失函數(shù)J如均方誤差MSE、交叉熵損失來計算它與真實標簽y之間的誤差。反向傳播的核心任務(wù)就是計算損失函數(shù)J關(guān)于網(wǎng)絡(luò)中每一個參數(shù)W[l]和b[l]的梯度偏導數(shù)即?J/?W[l]和?J/?b[l]。然后我們就可以用梯度下降法來更新參數(shù)使損失減小。反向傳播的精髓是鏈式法則。我們從輸出層開始反向逐層計算梯度。這里我們推導最關(guān)鍵的幾個公式以單個樣本的均方誤差損失為例J 0.5 * (y_hat - y)^2輸出層激活函數(shù)為Sigmoid。首先計算輸出層的誤差δ[L]L是最后一層δ[L] ?J/?Z[L] (A[L] - y) ⊙ g[L](Z[L])其中⊙表示逐元素相乘Hadamard積。對于Sigmoid輸出g(z) g(z)*(1-g(z))所以δ[L] (A[L] - y) ⊙ A[L] ⊙ (1 - A[L])。然后反向傳播這個誤差到前一l層δ[l] (W[l1]^T * δ[l1]) ⊙ g[l](Z[l])這個公式是反向傳播的引擎。W[l1]^T * δ[l1]將后一層的誤差“分配”回本層再乘以本層激活函數(shù)的導數(shù)就得到了本層的誤差δ[l]。最后利用本層的誤差δ[l]和前一層激活值A(chǔ)[l-1]計算參數(shù)的梯度?J/?W[l] δ[l] * A[l-1]^T?J/?b[l] δ[l]注意這里是針對單個樣本的梯度。對于m個樣本的批量梯度是每個樣本梯度的平均值。注意激活函數(shù)導數(shù)的選擇至關(guān)重要。如果你在隱藏層使用Sigmoid其導數(shù)g(z)的最大值只有0.25。當網(wǎng)絡(luò)層數(shù)較深時多個小于1的導數(shù)連乘會導致梯度指數(shù)級減小這就是著名的“梯度消失”問題。因此在現(xiàn)代網(wǎng)絡(luò)中隱藏層更推薦使用ReLURectified Linear Unit或其變體。ReLU的導數(shù)在輸入為正時為1為負時為0能有效緩解梯度消失加速訓練。我們在代碼實現(xiàn)時會重點考慮這一點。3. Matlab實現(xiàn)從初始化到訓練循環(huán)理論鋪墊完畢現(xiàn)在進入實戰(zhàn)環(huán)節(jié)。我們將實現(xiàn)一個具有一個隱藏層的MLP用于解決一個簡單的二分類問題例如異或問題XOR。3.1 網(wǎng)絡(luò)初始化好的開始是成功的一半?yún)?shù)的初始化不能隨意。如果全部初始化為0那么同一層所有神經(jīng)元的梯度會完全一樣導致它們學習不到不同的特征對稱性破壞問題。常見的初始化方法有隨機初始化W randn(n[l], n[l-1]) * 0.01。小的隨機數(shù)打破對稱性乘0.01是為了防止初始值過大導致激活函數(shù)如Sigmoid飽和梯度接近于0。Xavier初始化適用于Sigmoid、Tanh等激活函數(shù)。W randn(n[l], n[l-1]) * sqrt(1/n[l-1])。He初始化專為ReLU及其變體設(shè)計。W randn(n[l], n[l-1]) * sqrt(2/n[l-1])。我們選擇ReLU作為隱藏層激活函數(shù)因此采用He初始化。輸出層用Sigmoid其權(quán)重可以用較小的隨機數(shù)初始化。function [parameters] initialize_parameters(n_x, n_h, n_y) % 初始化網(wǎng)絡(luò)參數(shù) % n_x: 輸入層維度 % n_h: 隱藏層神經(jīng)元數(shù)量 % n_y: 輸出層維度 % 返回包含W1, b1, W2, b2的結(jié)構(gòu)體 rng(1); % 設(shè)置隨機種子確保結(jié)果可復(fù)現(xiàn) W1 randn(n_h, n_x) * sqrt(2.0 / n_x); % He初始化 b1 zeros(n_h, 1); % 偏置初始化為0是常見的做法 W2 randn(n_y, n_h) * 0.01; % 輸出層權(quán)重小隨機初始化 b2 zeros(n_y, 1); parameters struct(); parameters.W1 W1; parameters.b1 b1; parameters.W2 W2; parameters.b2 b2; end3.2 前向與反向傳播的函數(shù)實現(xiàn)接下來我們實現(xiàn)單次前向傳播和反向傳播的函數(shù)。這里我們處理的是批量數(shù)據(jù)。function [A2, cache] forward_propagation(X, parameters) % 前向傳播 % X: 輸入數(shù)據(jù)維度 (n_x, m) % parameters: 包含W1,b1,W2,b2的結(jié)構(gòu)體 % 返回: % A2: 輸出層激活值 (預(yù)測值) % cache: 緩存Z1, A1, Z2, A2用于反向傳播 W1 parameters.W1; b1 parameters.b1; W2 parameters.W2; b2 parameters.b2; % 隱藏層 Z1 W1 * X b1; A1 relu(Z1); % 使用ReLU激活函數(shù) % 輸出層 Z2 W2 * A1 b2; A2 sigmoid(Z2); % 使用Sigmoid激活函數(shù)輸出概率 cache struct(Z1, Z1, A1, A1, Z2, Z2, A2, A2); end function [grads] backward_propagation(parameters, cache, X, Y) % 反向傳播計算梯度 % parameters: 網(wǎng)絡(luò)參數(shù) % cache: 前向傳播緩存 % X: 輸入數(shù)據(jù) % Y: 真實標簽 % 返回: 包含各參數(shù)梯度的結(jié)構(gòu)體 grads m size(X, 2); % 樣本數(shù)量 W2 parameters.W2; A1 cache.A1; A2 cache.A2; % 輸出層誤差 dZ2 dZ2 A2 - Y; % 對于Sigmoid輸出和交叉熵損失這是簡化形式 % 詳細推導J -[y*log(a)(1-y)*log(1-a)], ?J/?Z2 a - y % 輸出層梯度 dW2 (1/m) * (dZ2 * A1); db2 (1/m) * sum(dZ2, 2); % 按行求和 % 隱藏層誤差 dZ1 dA1 W2 * dZ2; dZ1 dA1 .* relu_backward(cache.Z1); % 點乘ReLU的導數(shù) % 隱藏層梯度 dW1 (1/m) * (dZ1 * X); db1 (1/m) * sum(dZ1, 2); grads struct(dW1, dW1, db1, db1, dW2, dW2, db2, db2); end % 激活函數(shù)及其導數(shù) function A relu(Z) A max(0, Z); end function dZ relu_backward(Z) % ReLU的導數(shù)輸入0時為1否則為0 dZ double(Z 0); end function A sigmoid(Z) A 1 ./ (1 exp(-Z)); end實操心得梯度公式的簡化。上面backward_propagation函數(shù)中dZ2 A2 - Y是一個非常重要的簡化。它是由Sigmoid激活函數(shù)和二元交叉熵損失函數(shù)共同作用的結(jié)果。如果你使用其他損失函數(shù)如均方誤差或其他輸出層激活函數(shù)如Softmax這個公式會不同。理解這個簡化的來源能讓你在修改網(wǎng)絡(luò)結(jié)構(gòu)時正確推導梯度而不是死記硬背代碼。3.3 參數(shù)更新與訓練循環(huán)有了梯度我們就可以用梯度下降法更新參數(shù)。我們實現(xiàn)一個基本的批量梯度下降。function [parameters] update_parameters(parameters, grads, learning_rate) % 使用梯度下降更新參數(shù) parameters.W1 parameters.W1 - learning_rate * grads.dW1; parameters.b1 parameters.b1 - learning_rate * grads.db1; parameters.W2 parameters.W2 - learning_rate * grads.dW2; parameters.b2 parameters.b2 - learning_rate * grads.db2; end現(xiàn)在把所有部分組合起來形成完整的訓練循環(huán)。function [parameters, costs] model(X, Y, n_h, learning_rate, num_iterations, print_cost) % 訓練MLP模型 % X, Y: 訓練數(shù)據(jù)和標簽 % n_h: 隱藏層神經(jīng)元數(shù)量 % learning_rate: 學習率 % num_iterations: 迭代次數(shù) % print_cost: 每1000次迭代是否打印損失 % 返回訓練好的參數(shù)和損失歷史 n_x size(X, 1); n_y size(Y, 1); costs []; % 記錄損失 % 1. 初始化參數(shù) parameters initialize_parameters(n_x, n_h, n_y); % 2. 訓練循環(huán) for i 1:num_iterations % 前向傳播 [A2, cache] forward_propagation(X, parameters); % 計算損失二元交叉熵 m size(X, 2); logprobs Y .* log(A2) (1 - Y) .* log(1 - A2); cost - (1/m) * sum(logprobs(:)); cost squeeze(cost); % 確保cost是標量 % 反向傳播 grads backward_propagation(parameters, cache, X, Y); % 更新參數(shù) parameters update_parameters(parameters, grads, learning_rate); % 記錄損失 if mod(i, 100) 0 costs [costs, cost]; end % 打印損失 if print_cost mod(i, 1000) 0 fprintf(迭代次數(shù) %i 損失值 %f \n, i, cost); end end % 繪制損失曲線 if print_cost figure; plot(costs); xlabel(迭代次數(shù) (每100次)); ylabel(損失); title([學習率 num2str(learning_rate)]); grid on; end end4. 實戰(zhàn)測試解決異或問題與關(guān)鍵調(diào)試技巧理論正確不代表代碼能跑通更不代表能有效學習。我們用經(jīng)典的異或XOR問題來測試我們的MLP。XOR問題的輸入輸出如下輸入 (X): [0,0; 0,1; 1,0; 1,1] 輸出 (Y): [0; 1; 1; 0]這是一個簡單的非線性可分問題單層感知機無法解決但帶有一個隱藏層的MLP可以。4.1 數(shù)據(jù)準備與模型訓練% 準備XOR數(shù)據(jù) X [0 0; 0 1; 1 0; 1; 1]; % 維度 (2, 4) Y [0 1 1 0]; % 維度 (1, 4) % 定義超參數(shù) n_h 4; % 隱藏層4個神經(jīng)元 learning_rate 0.1; num_iterations 10000; print_cost true; % 訓練模型 [parameters, costs] model(X, Y, n_h, learning_rate, num_iterations, print_cost);運行后你應(yīng)該能看到損失值隨著迭代次數(shù)增加而穩(wěn)步下降最終趨近于0。繪制出的損失曲線應(yīng)該是單調(diào)遞減的可能會有小幅波動。4.2 模型預(yù)測與決策邊界可視化訓練完成后我們用訓練好的參數(shù)進行預(yù)測并可視化其學到的決策邊界。function [predictions] predict(parameters, X) % 使用訓練好的模型進行預(yù)測 A2, ~ forward_propagation(X, parameters); predictions (A2 0.5); % 以0.5為閾值進行二分類 end % 在訓練集上預(yù)測 predictions_train predict(parameters, X); fprintf(訓練集準確率: %f %%\n, mean(double(predictions_train Y)) * 100); % 可視化決策邊界 function plot_decision_boundary(parameters, X, Y) % 設(shè)置網(wǎng)格范圍 x1 linspace(-0.5, 1.5, 100); x2 linspace(-0.5, 1.5, 100); [X1_grid, X2_grid] meshgrid(x1, x2); % 將網(wǎng)格點展開為輸入格式 X_grid [X1_grid(:); X2_grid(:)]; % 預(yù)測網(wǎng)格上每一點的類別 A2, ~ forward_propagation(X_grid, parameters); Z_grid A2 0.5; Z_grid reshape(Z_grid, length(x2), length(x1)); % 繪制等高線決策邊界 figure; contourf(x1, x2, Z_grid, LineColor, none); colormap([0.9 0.9 1; 1 0.9 0.9]); % 淺藍和淺紅 hold on; % 繪制原始數(shù)據(jù)點 scatter(X(1, Y0), X(2, Y0), 100, b, filled, DisplayName, Class 0); scatter(X(1, Y1), X(2, Y1), 100, r, filled, DisplayName, Class 1); xlabel(x1); ylabel(x2); title(MLP學到的決策邊界 (XOR問題)); legend(Location, best); axis([-0.5 1.5 -0.5 1.5]); hold off; end % 調(diào)用函數(shù)繪圖 plot_decision_boundary(parameters, X, Y);如果一切順利你將看到一張圖其中藍色和紅色點被一條復(fù)雜的非線性邊界完美分開這條邊界能將(0,0)和(1,1)歸為一類藍色(0,1)和(1,0)歸為另一類紅色。這直觀地證明了你的MLP成功學習到了XOR的非線性關(guān)系。4.3 調(diào)試與優(yōu)化當網(wǎng)絡(luò)不學習時該怎么辦在實際操作中你的網(wǎng)絡(luò)可能一開始并不收斂損失值可能居高不下甚至變成NaN。以下是幾個最常見的坑和排查思路損失值為NaN或無限大爆炸檢查學習率這是頭號嫌犯。學習率太大可能導致梯度更新步伐過大參數(shù)在優(yōu)化空間中“跳崖”損失爆炸。嘗試將學習率降低一個數(shù)量級比如從0.1降到0.01或0.001。檢查數(shù)據(jù)輸入數(shù)據(jù)X或標簽Y中是否有異常值極大、極小或NaN確保數(shù)據(jù)是干凈的。檢查激活函數(shù)在Sigmoid函數(shù)中如果Z非常大exp(-Z)可能下溢為0導致計算log(0)產(chǎn)生-Inf。確保前向傳播的值在合理范圍內(nèi)??梢钥紤]在Sigmoid函數(shù)中加入數(shù)值穩(wěn)定處理A 1 ./ (1 exp(-max(min(Z, 50), -50)))。損失值下降非常緩慢或停滯學習率太小與爆炸相反學習率太小會導致收斂極慢??梢試L試適當增大學習率。初始化問題如果權(quán)重初始化值太小可能導致初始激活值非常小對于Sigmoid/Tanh其梯度也接近0學習幾乎停滯。嘗試使用Xavier或He初始化而不是簡單的小隨機數(shù)。激活函數(shù)飽和如果使用Sigmoid/Tanh且輸入絕對值很大梯度會接近0導致“梯度消失”。隱藏層改用ReLU是解決此問題的標準做法。檢查梯度計算是否正確這是最根本的。實現(xiàn)一個梯度檢查函數(shù)。利用導數(shù)的定義對每個參數(shù)進行數(shù)值近似求導與你反向傳播計算的解析梯度進行比較。如果兩者差異很大比如相對誤差大于1e-7說明你的反向傳播代碼有bug。過擬合在復(fù)雜數(shù)據(jù)集上網(wǎng)絡(luò)可能很快在訓練集上達到高精度但在測試集上表現(xiàn)很差。獲取更多數(shù)據(jù)最有效的方法。正則化在損失函數(shù)中加入L2正則化項懲罰大的權(quán)重。這需要在損失計算和梯度計算中都加入正則化項。Dropout在訓練時隨機“丟棄”一部分神經(jīng)元防止神經(jīng)元之間產(chǎn)生復(fù)雜的共適應(yīng)關(guān)系。踩坑實錄梯度檢查的重要性。在我第一次實現(xiàn)時損失一直不降。我花了大量時間調(diào)整學習率、初始化方法都無濟于事。最后我寫了一個梯度檢查函數(shù)發(fā)現(xiàn)db2的解析梯度和數(shù)值梯度差了幾個數(shù)量級。仔細檢查代碼發(fā)現(xiàn)我在計算db2時錯誤地用了mean(dZ2, 1)按列求平均而正確的應(yīng)該是mean(dZ2, 2)按行求平均因為b2是列向量。這個細微的錯誤導致偏置更新方向完全錯誤。教訓是在確信反向傳播正確之前不要盲目調(diào)參梯度檢查是調(diào)試神經(jīng)網(wǎng)絡(luò)代碼的“金標準”。5. 超越基礎(chǔ)擴展功能與性能考量一個能跑通的MLP只是起點。要讓其更實用、更健壯我們還需要考慮一些擴展功能。5.1 實現(xiàn)L2正則化L2正則化通過在損失函數(shù)中增加權(quán)重的平方和項來抑制權(quán)重的大小防止過擬合。修改后的損失函數(shù)為J_reg J (lambda/(2*m)) * sum(W^2)其中l(wèi)ambda是正則化超參數(shù)。我們需要修改前向傳播的損失計算和反向傳播的梯度計算。% 在前向傳播的損失計算中假設(shè)parameters是一個包含所有W的結(jié)構(gòu)體數(shù)組 function cost compute_cost_with_regularization(A2, Y, parameters, lambda) m size(Y, 2); cross_entropy_cost - (1/m) * sum( Y .* log(A2) (1-Y) .* log(1-A2), all); % 計算所有權(quán)重矩陣的L2范數(shù)平方和 L2_cost 0; fields fieldnames(parameters); for i 1:length(fields) field fields{i}; if startsWith(field, W) % 只對權(quán)重矩陣正則化 L2_cost L2_cost sum(parameters.(field).^2, all); end end L2_cost (lambda / (2*m)) * L2_cost; cost cross_entropy_cost L2_cost; end % 在反向傳播的梯度計算中需要加上正則化項的梯度 % 對于dW[l]正則化項的梯度是 (lambda/m) * W[l] % 因此更新后的梯度為dW[l]_reg dW[l] (lambda/m) * W[l] % db的梯度不變5.2 實現(xiàn)不同的優(yōu)化器基礎(chǔ)的梯度下降Batch Gradient Descent每次使用全部數(shù)據(jù)計算梯度對于大數(shù)據(jù)集很慢。更常用的優(yōu)化器是小批量梯度下降每次迭代隨機抽取一小批mini-batch數(shù)據(jù)計算梯度。這需要在訓練循環(huán)中增加數(shù)據(jù)打亂和分批的邏輯。帶動量的梯度下降引入“速度”變量使參數(shù)更新不僅考慮當前梯度還累積之前的梯度方向有助于加速收斂并減少震蕩。Adam結(jié)合了動量和自適應(yīng)學習率的優(yōu)點是目前最常用的優(yōu)化器。以帶動量的梯度下降為例我們需要在更新參數(shù)時維護一個速度變量VV beta * V (1 - beta) * dWW W - learning_rate * V其中beta是動量參數(shù)通常取0.9。5.3 使用向量化操作處理批量數(shù)據(jù)我們的代碼已經(jīng)利用了Matlab的矩陣運算是向量化的。但要處理真正的批量數(shù)據(jù)你需要將數(shù)據(jù)組織成矩陣Xn_x * m和Yn_y * m。前向和反向傳播中的所有操作都應(yīng)該是矩陣運算避免使用for循環(huán)遍歷樣本這是Matlab高效運行的關(guān)鍵。5.4 超參數(shù)調(diào)優(yōu)實戰(zhàn)網(wǎng)絡(luò)性能很大程度上取決于超參數(shù)的選擇。一個簡單的調(diào)優(yōu)流程可以是確定網(wǎng)絡(luò)架構(gòu)先從1-2個隱藏層開始每層神經(jīng)元數(shù)量可以嘗試比如[4, 8, 16, 32]。選擇學習率這是最重要的超參數(shù)。常用策略是進行對數(shù)尺度搜索例如嘗試[0.1, 0.03, 0.01, 0.003, 0.001]。確定迭代次數(shù)觀察損失曲線直到損失收斂或開始過擬合。引入正則化如果出現(xiàn)過擬合訓練損失低驗證損失高嘗試加入L2正則化調(diào)整lambda如[0, 0.01, 0.1, 1]。使用驗證集將數(shù)據(jù)分為訓練集、驗證集和測試集。用驗證集來評估不同超參數(shù)組合的效果選擇在驗證集上性能最好的模型最后用測試集報告最終性能。你可以編寫一個簡單的網(wǎng)格搜索或隨機搜索腳本來自動化這個過程。6. 從Matlab實現(xiàn)到理解現(xiàn)代深度學習框架通過這個手搓MLP的項目我希望你獲得的不僅僅是幾行能運行的Matlab代碼。更重要的是理解背后的“為什么”為什么需要非線性激活函數(shù)沒有它多層網(wǎng)絡(luò)等價于單層線性變換無法解決XOR這類非線性問題。反向傳播的本質(zhì)是什么是鏈式法則的高效應(yīng)用將最終誤差公平地“分攤”給每一個該負責的參數(shù)。初始化、學習率、激活函數(shù)如何影響訓練你通過調(diào)試親身感受到了。當你理解了這些再去使用PyTorch或TensorFlow你會明白nn.Linear,nn.ReLU,optim.SGD,loss.backward()這些語句背后在做什么。你會知道如何選擇初始化方法如何設(shè)置合理的學習率如何診斷梯度消失/爆炸問題。這個從底層實現(xiàn)中獲得的直覺是任何高級框架的教程都無法直接給你的。最后你可以嘗試挑戰(zhàn)自己用Matlab實現(xiàn)一個更深的網(wǎng)絡(luò)比如3個隱藏層在更復(fù)雜的數(shù)據(jù)集如螺旋數(shù)據(jù)集或簡單的圖像分類數(shù)據(jù)集上進行測試并加入Dropout、Batch Normalization等現(xiàn)代技巧。這個過程會充滿挑戰(zhàn)但每解決一個問題你對神經(jīng)網(wǎng)絡(luò)的理解就會加深一層。本文還有配套的精品資源點擊獲取