現(xiàn))
簡(jiǎn)介本資源是一份面向本科及碩士階段教研學(xué)習(xí)的Matlab神經(jīng)網(wǎng)絡(luò)基礎(chǔ)教程完整實(shí)現(xiàn)反向傳播算法驅(qū)動(dòng)的多層感知器MLP建模與訓(xùn)練流程適用于機(jī)器學(xué)習(xí)入門(mén)、神經(jīng)網(wǎng)絡(luò)原理教學(xué)及課程實(shí)驗(yàn)驗(yàn)證。壓縮包共2000個(gè)文件主體為4236張訓(xùn)練過(guò)程可視化圖像如螺旋數(shù)據(jù)分類(lèi)結(jié)果fig4600–fig5000.png等輔以4個(gè)核心Matlab函數(shù)文件含網(wǎng)絡(luò)前向傳播、激活函數(shù)及其導(dǎo)數(shù)計(jì)算、模型評(píng)估等模塊另有4個(gè)points數(shù)據(jù)點(diǎn)文件支撐實(shí)驗(yàn)復(fù)現(xiàn)整體容量197.48MB結(jié)構(gòu)清晰、模塊解耦便于逐層理解BP機(jī)制與梯度更新邏輯。已有1330人下載學(xué)習(xí)配套代碼可直接運(yùn)行于Matlab 2019a環(huán)境包含從初始化、誤差反傳、權(quán)值迭代到最終分類(lèi)效果展示的全流程實(shí)現(xiàn)特別適合夯實(shí)神經(jīng)網(wǎng)絡(luò)底層原理認(rèn)知與動(dòng)手調(diào)試能力。1. 項(xiàng)目概述為什么用Matlab手搓一個(gè)MLP在機(jī)器學(xué)習(xí)和人工智能的浪潮里神經(jīng)網(wǎng)絡(luò)無(wú)疑是那顆最耀眼的明星。但當(dāng)你打開(kāi)TensorFlow或PyTorch的文檔面對(duì)動(dòng)輒幾十行的API調(diào)用和復(fù)雜的自動(dòng)微分機(jī)制時(shí)有沒(méi)有那么一瞬間感覺(jué)自己和這個(gè)“黑箱”之間隔著一層厚厚的毛玻璃你只知道輸入數(shù)據(jù)、調(diào)整參數(shù)、得到結(jié)果但對(duì)數(shù)據(jù)如何在層間流動(dòng)、誤差如何精確地反向修正每一個(gè)權(quán)重總有種霧里看花的感覺(jué)。這正是我決定用Matlab從頭實(shí)現(xiàn)一個(gè)基于反向傳播Backpropagation的多層感知器MLP的原因。Matlab這個(gè)在工程和科研領(lǐng)域深耕多年的老將以其強(qiáng)大的矩陣運(yùn)算能力和直觀的編程環(huán)境成為了理解算法本質(zhì)的絕佳“手術(shù)刀”。它沒(méi)有深度學(xué)習(xí)框架那些為了極致效率而封裝起來(lái)的復(fù)雜抽象迫使你必須親手定義每一個(gè)矩陣的維度親手計(jì)算每一次前向傳播的輸出和反向傳播的梯度。這個(gè)過(guò)程就像親手拆卸并組裝一臺(tái)精密的機(jī)械鐘表每一個(gè)齒輪神經(jīng)元的咬合每一根發(fā)條權(quán)重的張力你都了然于胸。這個(gè)項(xiàng)目解決的不僅僅是“用Matlab實(shí)現(xiàn)一個(gè)神經(jīng)網(wǎng)絡(luò)”的技術(shù)問(wèn)題它更深層的價(jià)值在于“祛魅”。通過(guò)這個(gè)實(shí)踐你將徹底理解前向傳播數(shù)據(jù)如何像流水線(xiàn)一樣經(jīng)過(guò)加權(quán)求和、激活函數(shù)一層層變換最終形成預(yù)測(cè)。反向傳播預(yù)測(cè)出錯(cuò)后誤差信號(hào)如何沿著網(wǎng)絡(luò)逆向傳播并利用鏈?zhǔn)椒▌t精確計(jì)算出每個(gè)權(quán)重需要調(diào)整的“量”和“方向”。梯度下降如何利用計(jì)算出的梯度以“小步快跑”的方式讓網(wǎng)絡(luò)權(quán)重朝著損失減少的方向迭代更新。無(wú)論你是剛接觸神經(jīng)網(wǎng)絡(luò)的學(xué)生希望夯實(shí)基礎(chǔ)還是有一定經(jīng)驗(yàn)的工程師想深入理解模型訓(xùn)練的底層邏輯亦或是科研人員需要為一個(gè)特定問(wèn)題定制簡(jiǎn)單的神經(jīng)網(wǎng)絡(luò)模塊這個(gè)手搓MLP的過(guò)程都將是一次極具價(jià)值的“思想實(shí)驗(yàn)”和技能錘煉。接下來(lái)我們就拋開(kāi)框架的“拐杖”用Matlab的矩陣語(yǔ)言一步步搭建并訓(xùn)練我們自己的神經(jīng)網(wǎng)絡(luò)大腦。2. 核心原理拆解前向傳播、損失函數(shù)與反向傳播的三角關(guān)系要親手實(shí)現(xiàn)一個(gè)MLP絕不能停留在“調(diào)用fit函數(shù)”的層面。我們必須深入其最核心的數(shù)學(xué)引擎理解前向傳播Forward Propagation、損失函數(shù)Loss Function和反向傳播Backpropagation這三者如何精密協(xié)作驅(qū)動(dòng)網(wǎng)絡(luò)學(xué)習(xí)。它們構(gòu)成了一個(gè)完整的閉環(huán)前向傳播負(fù)責(zé)“做出猜測(cè)”損失函數(shù)負(fù)責(zé)“評(píng)價(jià)猜測(cè)有多糟糕”反向傳播則負(fù)責(zé)“找出誰(shuí)該為這個(gè)糟糕的猜測(cè)負(fù)責(zé)并糾正它”。2.1 前向傳播從輸入到預(yù)測(cè)的線(xiàn)性與非線(xiàn)性之旅前向傳播是網(wǎng)絡(luò)進(jìn)行推理或預(yù)測(cè)的過(guò)程。對(duì)于一個(gè)具有L層的MLP輸入層不算作一層其第l層l1,2,...,L的操作可以統(tǒng)一表示為Z[l] W[l] * A[l-1] b[l]A[l] g l這里W[l]是第l層的權(quán)重矩陣維度為(當(dāng)前層神經(jīng)元數(shù) 上一層神經(jīng)元數(shù))。這是網(wǎng)絡(luò)需要學(xué)習(xí)的核心參數(shù)。A[l-1]是上一層的激活值輸出對(duì)于第一層A[0]就是輸入數(shù)據(jù)X。b[l]是偏置向量維度為(當(dāng)前層神經(jīng)元數(shù) 1)。Z[l]是加權(quán)輸入或稱(chēng)為凈輸入。g[l]是第l層的激活函數(shù)它為網(wǎng)絡(luò)引入了非線(xiàn)性使其能夠擬合復(fù)雜的模式。常見(jiàn)的激活函數(shù)包括Sigmoid、Tanh和ReLU。為什么是矩陣乘法這是Matlab實(shí)現(xiàn)的關(guān)鍵優(yōu)勢(shì)。假設(shè)我們有一個(gè)批次Batch的100個(gè)樣本每個(gè)樣本有10個(gè)特征即X的維度是10×100。如果使用for循環(huán)逐個(gè)樣本計(jì)算效率極低。而利用矩陣乘法W[1]假設(shè)第一隱藏層有20個(gè)神經(jīng)元維度20×10乘以X10×100一次性就得到了所有100個(gè)樣本在第一層的Z[1]20×100。這種“向量化”操作是Matlab的強(qiáng)項(xiàng)也是實(shí)現(xiàn)高效訓(xùn)練的基礎(chǔ)。激活函數(shù)的選擇考量在隱藏層我強(qiáng)烈推薦使用ReLURectified Linear Unit或其變種如Leaky ReLU。原因很簡(jiǎn)單計(jì)算速度快無(wú)需指數(shù)運(yùn)算且能有效緩解梯度消失問(wèn)題Sigmoid和Tanh在輸入值很大或很小時(shí)梯度接近0導(dǎo)致深層網(wǎng)絡(luò)權(quán)重更新緩慢。在輸出層則需要根據(jù)任務(wù)選擇二分類(lèi)用Sigmoid輸出介于0-1可視為概率多分類(lèi)用Softmax回歸問(wèn)題用線(xiàn)性函數(shù)或無(wú)激活函數(shù)。2.2 損失函數(shù)量化“錯(cuò)誤”的標(biāo)尺網(wǎng)絡(luò)做出了預(yù)測(cè)A[L]我們需要一個(gè)客觀的標(biāo)尺來(lái)衡量它與真實(shí)標(biāo)簽Y的差距這就是損失函數(shù)J。它是所有參數(shù)W, b的函數(shù)。對(duì)于二分類(lèi)常用二元交叉熵?fù)p失。J -1/m * sum( Y .* log(A[L]) (1-Y) .* log(1-A[L]) )其中m是樣本數(shù).*表示逐元素乘法。對(duì)于多分類(lèi)常用分類(lèi)交叉熵?fù)p失。J -1/m * sum( sum( Y .* log(A[L]) ) )這里Y通常是one-hot編碼形式。對(duì)于回歸常用均方誤差損失。J 1/(2m) * sum( (A[L] - Y).^2 )損失函數(shù)的意義它提供了一個(gè)單一的、可微的標(biāo)量值。我們的終極目標(biāo)就是通過(guò)調(diào)整W和b使J最小化。你可以把它想象成網(wǎng)絡(luò)所處的一個(gè)“誤差地形圖”我們的目標(biāo)是找到其中的最低點(diǎn)全局最小或局部最小。2.3 反向傳播誤差的逆向溯源與梯度計(jì)算這是整個(gè)MLP學(xué)習(xí)的“靈魂”。反向傳播的核心是鏈?zhǔn)椒▌t。它的目標(biāo)是計(jì)算損失函數(shù)J相對(duì)于網(wǎng)絡(luò)中每一個(gè)參數(shù)W[l]和b[l]的偏導(dǎo)數(shù)即梯度dW[l]和db[l]。其過(guò)程是從輸出層開(kāi)始反向逐層遞推輸出層誤差首先計(jì)算輸出層激活值的誤差dZ[L]。對(duì)于交叉熵?fù)p失Sigmoid/Softmax輸出有一個(gè)非常簡(jiǎn)潔的形式dZ[L] A[L] - Y。這個(gè)公式非常優(yōu)美它直接就是預(yù)測(cè)值與真實(shí)值的差值。反向傳播誤差已知第l1層的誤差dZ[l1]可以計(jì)算第l層的誤差dZ[l]dZ[l] (W[l1]的轉(zhuǎn)置 * dZ[l1]) .* g[l](Z[l])這里.*是逐元素乘法g[l]是第l層激活函數(shù)的導(dǎo)數(shù)。這一步是誤差從深層向淺層傳播的關(guān)鍵。計(jì)算參數(shù)梯度利用本層的誤差dZ[l]和上一層的激活值A(chǔ)[l-1]可以計(jì)算出本層參數(shù)的梯度dW[l] 1/m * (dZ[l] * A[l-1]的轉(zhuǎn)置)db[l] 1/m * sum(dZ[l], 維度2)對(duì)樣本維度求和為什么這樣設(shè)計(jì)dW[l]的計(jì)算公式dZ[l] * A[l-1]^T揭示了梯度的來(lái)源它由“本層神經(jīng)元傳遞過(guò)來(lái)的誤差信號(hào)”dZ[l]和“前一層神經(jīng)元當(dāng)時(shí)的激活狀態(tài)”A[l-1]共同決定。這非常符合直覺(jué)如果前一個(gè)神經(jīng)元激活值很高(A[l-1]很大)那么它與當(dāng)前神經(jīng)元連接的權(quán)重(W)對(duì)最終誤差的“貢獻(xiàn)”或“責(zé)任”就更大因此其梯度(dW)也理應(yīng)更大。注意矩陣維度校驗(yàn)。這是手寫(xiě)反向傳播時(shí)最容易出錯(cuò)的地方。一個(gè)黃金法則是每次計(jì)算完dW和db后立即用Matlab的size()函數(shù)檢查其維度是否與W和b的原始維度完全一致。例如W[l]的維度是(n[l], n[l-1])那么dW[l]也必須是(n[l], n[l-1])。維度不一致幾乎必然導(dǎo)致后續(xù)更新或計(jì)算錯(cuò)誤。3. Matlab實(shí)現(xiàn)詳析從矩陣初始化到迭代訓(xùn)練理解了原理我們就可以用Matlab將其轉(zhuǎn)化為具體的代碼。我們將遵循“初始化 - 前向傳播 - 計(jì)算損失 - 反向傳播 - 更新參數(shù)”的循環(huán)構(gòu)建完整的訓(xùn)練流程。3.1 網(wǎng)絡(luò)初始化打破對(duì)稱(chēng)性與尺度控制權(quán)重的初始值不能簡(jiǎn)單地設(shè)為0或相同的隨機(jī)數(shù)。如果所有權(quán)重相同那么在反向傳播時(shí)同一層內(nèi)所有神經(jīng)元將獲得完全相同的梯度并進(jìn)行相同的更新這會(huì)使網(wǎng)絡(luò)失去學(xué)習(xí)不同特征的能力。因此我們需要“打破對(duì)稱(chēng)性”。常用的初始化方法小型隨機(jī)數(shù)例如W randn(n[l], n[l-1]) * 0.01。randn生成標(biāo)準(zhǔn)正態(tài)分布隨機(jī)數(shù)乘以一個(gè)很小的系數(shù)如0.01是為了防止初始激活值過(guò)大導(dǎo)致像Sigmoid/Tanh這樣的激活函數(shù)飽和梯度接近0。Xavier/Glorot初始化更推薦用于Sigmoid/Tanh激活函數(shù)。它根據(jù)輸入和輸出的神經(jīng)元數(shù)量來(lái)調(diào)整隨機(jī)數(shù)的尺度W randn(n[l], n[l-1]) * sqrt(1/n[l-1])。He初始化專(zhuān)為ReLU激活函數(shù)設(shè)計(jì)能更好地保持信號(hào)在前向和反向傳播中的方差W randn(n[l], n[l-1]) * sqrt(2/n[l-1])。偏置b通常初始化為0即可。function parameters initialize_parameters(layer_dims) % layer_dims: 一個(gè)數(shù)組例如 [input_size, hidden1_size, hidden2_size, ..., output_size] parameters struct(); L length(layer_dims); for l 2:L % 使用He初始化假設(shè)隱藏層使用ReLU parameters.([W, num2str(l-1)]) randn(layer_dims(l), layer_dims(l-1)) * sqrt(2/layer_dims(l-1)); parameters.([b, num2str(l-1)]) zeros(layer_dims(l), 1); end end3.2 單次迭代的前向與反向傳播實(shí)現(xiàn)一次完整的迭代包含前向傳播、損失計(jì)算和反向傳播。前向傳播實(shí)現(xiàn) 我們需要緩存每一層的線(xiàn)性輸出Z和激活輸出A供反向傳播使用。function [AL, caches] forward_propagation(X, parameters, activation_functions) % X: 輸入數(shù)據(jù) (n_x, m) % parameters: 包含W1,b1,W2,b2,...的結(jié)構(gòu)體 % activation_functions: 元胞數(shù)組例如 {relu, relu, sigmoid} A X; caches {}; % 用于緩存 (Z, A_prev, W, b, activation) L length(fieldnames(parameters)) / 2; % 總層數(shù) for l 1:L-1 A_prev A; W parameters.([W, num2str(l)]); b parameters.([b, num2str(l)]); Z W * A_prev b; A relu(Z); % 假設(shè)隱藏層用ReLU caches{l} {Z, A_prev, W, b, relu}; end % 輸出層 W parameters.([W, num2str(L)]); b parameters.([b, num2str(L)]); Z W * A b; AL sigmoid(Z); % 假設(shè)二分類(lèi)輸出層用Sigmoid caches{L} {Z, A, W, b, sigmoid}; end反向傳播實(shí)現(xiàn) 這是最需要細(xì)心的一步務(wù)必對(duì)照公式和維度。function grads backward_propagation(AL, Y, caches) % AL: 前向傳播的輸出 (n_y, m) % Y: 真實(shí)標(biāo)簽 (n_y, m) % caches: 前向傳播緩存列表 grads struct(); m size(Y, 2); L length(caches); % 初始化反向傳播 dAL - (Y ./ AL - (1 - Y) ./ (1 - AL)); % 交叉熵?fù)p失對(duì)AL的導(dǎo)數(shù)通用形式 % 但對(duì)于Sigmoid輸出層結(jié)合交叉熵?fù)p失可以直接得到更簡(jiǎn)單的dZ[L] current_cache caches{L}; [Z, A_prev, W, b, activation] current_cache{:}; if strcmp(activation, sigmoid) dZ AL - Y; % 簡(jiǎn)化形式 else % 如果是其他激活函數(shù)需按通用公式計(jì)算 dZ dAL .* activation_derivative(Z) dZ dAL .* sigmoid_derivative(Z); end dW (1/m) * dZ * A_prev; db (1/m) * sum(dZ, 2); grads.([dW, num2str(L)]) dW; grads.([b, num2str(L)]) db; % 循環(huán)反向傳播至第一層 for l L-1:-1:1 current_cache caches{l}; [Z, A_prev, W, b, activation] current_cache{:}; % 從下一層獲取誤差 dZ_next grads.([dZ, num2str(l1)]); % 需要在前一步緩存dZ % 計(jì)算本層dZ if strcmp(activation, relu) dZ (W * dZ_next) .* relu_derivative(Z); end % 計(jì)算本層梯度 dW (1/m) * dZ * A_prev; db (1/m) * sum(dZ, 2); grads.([dW, num2str(l)]) dW; grads.([b, num2str(l)]) db; % 為上一層傳播準(zhǔn)備如果需要 grads.([dZ, num2str(l)]) dZ; end end3.3 參數(shù)更新與梯度下降優(yōu)化拿到梯度dW和db后我們使用梯度下降法更新參數(shù)W W - learning_rate * dWb b - learning_rate * db學(xué)習(xí)率learning_rate是一個(gè)超參數(shù)控制著每次更新的步長(zhǎng)。步長(zhǎng)太大可能越過(guò)最優(yōu)點(diǎn)甚至發(fā)散步長(zhǎng)太小則學(xué)習(xí)速度緩慢。function parameters update_parameters(parameters, grads, learning_rate) L length(fieldnames(parameters)) / 2; for l 1:L parameters.([W, num2str(l)]) parameters.([W, num2str(l)]) - learning_rate * grads.([dW, num2str(l)]); parameters.([b, num2str(l)]) parameters.([b, num2str(l)]) - learning_rate * grads.([b, num2str(l)]); end end將以上所有部分組合起來(lái)就構(gòu)成了核心的訓(xùn)練循環(huán)function [parameters, costs] model(X, Y, layers_dims, learning_rate, num_iterations) parameters initialize_parameters(layers_dims); costs []; for i 1:num_iterations % 前向傳播 [AL, caches] forward_propagation(X, parameters, {relu, sigmoid}); % 計(jì)算成本 cost compute_cost(AL, Y); costs [costs, cost]; % 反向傳播 grads backward_propagation(AL, Y, caches); % 更新參數(shù) parameters update_parameters(parameters, grads, learning_rate); % 每100次迭代打印一次成本 if mod(i, 100) 0 fprintf(迭代次數(shù) %i 成本值 %f\n, i, cost); end end end4. 關(guān)鍵技巧、調(diào)試與性能優(yōu)化實(shí)戰(zhàn)實(shí)現(xiàn)基礎(chǔ)版本只是第一步。要讓這個(gè)手搓的MLP真正可靠、高效還需要一系列的技巧和調(diào)試方法。4.1 梯度檢查確保反向傳播的正確性反向傳播的推導(dǎo)和實(shí)現(xiàn)極其復(fù)雜極易出錯(cuò)。梯度檢查Gradient Checking是驗(yàn)證其正確性的“金標(biāo)準(zhǔn)”。它的原理是利用導(dǎo)數(shù)的定義來(lái)近似計(jì)算梯度并與我們反向傳播計(jì)算出的梯度進(jìn)行對(duì)比。數(shù)值梯度近似公式dW_approx[i] (J(W[i] epsilon) - J(W[i] - epsilon)) / (2*epsilon)操作步驟將所有權(quán)重和偏置展開(kāi)并連接成一個(gè)巨大的向量theta。對(duì)于theta中的每一個(gè)元素i計(jì)算加上和減去一個(gè)極小值epsilon如1e-7后的損失J用上述公式計(jì)算該位置梯度的近似值dtheta_approx[i]。通過(guò)反向傳播計(jì)算得到梯度向量dtheta。計(jì)算dtheta_approx和dtheta之間的相對(duì)差異diff norm(dtheta_approx - dtheta) / norm(dtheta_approx dtheta)。如果diff在1e-7量級(jí)通常認(rèn)為反向傳播實(shí)現(xiàn)正確如果大于1e-5則很可能存在錯(cuò)誤。重要提示梯度檢查計(jì)算量巨大需要對(duì)每個(gè)參數(shù)計(jì)算兩次前向傳播因此僅用于調(diào)試。一旦確認(rèn)反向傳播正確在正式訓(xùn)練時(shí)必須關(guān)閉梯度檢查否則訓(xùn)練速度將無(wú)法接受。4.2 超參數(shù)調(diào)優(yōu)學(xué)習(xí)率、網(wǎng)絡(luò)結(jié)構(gòu)與正則化學(xué)習(xí)率Learning Rate這是最重要的超參數(shù)??梢詮囊粋€(gè)較大的值如0.1開(kāi)始嘗試如果成本曲線(xiàn)震蕩劇烈甚至上升說(shuō)明學(xué)習(xí)率太大應(yīng)減小如0.01 0.001。如果成本下降極其緩慢則可以適當(dāng)增大。更高級(jí)的方法是使用學(xué)習(xí)率衰減如每N輪迭代將學(xué)習(xí)率乘以一個(gè)衰減因子或自適應(yīng)優(yōu)化器如Adam雖然需要額外實(shí)現(xiàn)動(dòng)量等概念但能顯著提升收斂速度。網(wǎng)絡(luò)架構(gòu)層數(shù)和每層神經(jīng)元數(shù)沒(méi)有固定公式。對(duì)于簡(jiǎn)單問(wèn)題如異或XOR一個(gè)隱藏層2個(gè)神經(jīng)元就足夠了。對(duì)于更復(fù)雜的問(wèn)題可以嘗試增加層深深度和寬度神經(jīng)元數(shù)。一個(gè)實(shí)用的起點(diǎn)是1-2個(gè)隱藏層每層神經(jīng)元數(shù)相同或遞減。過(guò)寬過(guò)深的網(wǎng)絡(luò)在小數(shù)據(jù)集上極易過(guò)擬合。正則化Regularization為了防止過(guò)擬合可以在損失函數(shù)中加入L2正則化項(xiàng)。這相當(dāng)于對(duì)大的權(quán)重值施加懲罰鼓勵(lì)網(wǎng)絡(luò)學(xué)習(xí)更簡(jiǎn)單、更平滑的函數(shù)。L2正則化后的損失函數(shù)為J_reg J (lambda/(2*m)) * sum(W^2)。反向傳播時(shí)梯度也需要相應(yīng)加上(lambda/m) * W。lambda是正則化強(qiáng)度超參數(shù)需要調(diào)整。4.3 訓(xùn)練過(guò)程監(jiān)控與可視化訓(xùn)練時(shí)不能只等最終結(jié)果必須實(shí)時(shí)監(jiān)控。繪制成本曲線(xiàn)將每次迭代的成本J記錄下來(lái)并繪圖。一個(gè)健康的訓(xùn)練過(guò)程成本曲線(xiàn)應(yīng)該隨著迭代平滑下降最終趨于平緩。如果曲線(xiàn)出現(xiàn)劇烈震蕩可能是學(xué)習(xí)率過(guò)高如果幾乎不下降可能是學(xué)習(xí)率過(guò)低或網(wǎng)絡(luò)架構(gòu)/初始化有問(wèn)題。在簡(jiǎn)單數(shù)據(jù)集上驗(yàn)證在嘗試復(fù)雜數(shù)據(jù)前先在一個(gè)人工構(gòu)造的、完全線(xiàn)性可分或簡(jiǎn)單非線(xiàn)性的小數(shù)據(jù)集如月亮形數(shù)據(jù)集make_moons或圓形數(shù)據(jù)集上測(cè)試你的模型。確保它能快速達(dá)到接近100%的訓(xùn)練準(zhǔn)確率。這是驗(yàn)證整個(gè)訓(xùn)練流程包括數(shù)據(jù)預(yù)處理、模型、損失函數(shù)是否正確的最快方法。檢查激活值分布在訓(xùn)練初期可以查看各層激活值A(chǔ)的分布。如果很多值都是0使用ReLU時(shí)這可能意味著“神經(jīng)元死亡”學(xué)習(xí)率可能需要調(diào)整或者考慮使用Leaky ReLU。4.4 常見(jiàn)問(wèn)題排查與解決實(shí)錄在實(shí)際編碼中你幾乎一定會(huì)遇到下面這些問(wèn)題成本Loss為NaN或無(wú)限大Inf首要嫌疑犯學(xué)習(xí)率過(guò)高。這是最常見(jiàn)的原因立即嘗試將學(xué)習(xí)率降低一個(gè)數(shù)量級(jí)例如從0.01降到0.001。檢查數(shù)據(jù)輸入數(shù)據(jù)X或標(biāo)簽Y中是否存在NaN或異常大/小的值進(jìn)行歸一化或標(biāo)準(zhǔn)化處理如縮放到[0,1]或均值為0方差為1通常能解決此問(wèn)題。檢查數(shù)學(xué)運(yùn)算在計(jì)算log(AL)時(shí)AL是否可能為0可以加一個(gè)極小的epsilon防止數(shù)值下溢log(max(AL, eps))。成本下降一段時(shí)間后停滯不變學(xué)習(xí)率可能太小導(dǎo)致更新步長(zhǎng)不足以跳出當(dāng)前的平坦區(qū)域。可能陷入了局部最優(yōu)點(diǎn)或鞍點(diǎn)。雖然理論上神經(jīng)網(wǎng)絡(luò)有很多局部最優(yōu)但實(shí)踐表明很多局部最優(yōu)的解質(zhì)量也差不多??梢試L試隨機(jī)初始化幾次看是否都能收斂到相似的成本值。檢查梯度是否消失Vanishing Gradient如果使用Sigmoid/Tanh在深層網(wǎng)絡(luò)中梯度可能變得極小。改用ReLU及其變種是標(biāo)準(zhǔn)解決方案。訓(xùn)練準(zhǔn)確率高但驗(yàn)證/測(cè)試準(zhǔn)確率低過(guò)擬合獲取更多訓(xùn)練數(shù)據(jù)是最有效的方法但通常不現(xiàn)實(shí)。應(yīng)用正則化增加L2正則化的lambda值。使用Dropout在訓(xùn)練時(shí)以一定概率隨機(jī)將一部分神經(jīng)元的激活值置零可以防止神經(jīng)元之間產(chǎn)生復(fù)雜的共適應(yīng)關(guān)系是一種強(qiáng)大的正則化手段。實(shí)現(xiàn)時(shí)在前向傳播中引入Dropout掩碼在反向傳播時(shí)對(duì)應(yīng)梯度的路徑也應(yīng)被屏蔽。簡(jiǎn)化模型減少網(wǎng)絡(luò)層數(shù)或每層的神經(jīng)元數(shù)量。訓(xùn)練速度極慢確保使用了向量化實(shí)現(xiàn)。使用for循環(huán)遍歷樣本的代碼在Matlab中會(huì)慢得令人絕望。反復(fù)檢查你的W * A等操作是否一次性處理了所有樣本m列。預(yù)分配數(shù)組在循環(huán)中不斷costs [costs, new_cost]會(huì)動(dòng)態(tài)擴(kuò)展數(shù)組影響速度??梢灶A(yù)先分配costs zeros(1, num_iterations)。使用性能分析工具M(jìn)atlab的profile工具可以幫助你找到代碼中的性能瓶頸。5. 超越基礎(chǔ)擴(kuò)展功能與進(jìn)階思考實(shí)現(xiàn)一個(gè)基礎(chǔ)的MLP后你可以在此基礎(chǔ)上添加更多現(xiàn)代深度學(xué)習(xí)中的組件使其更強(qiáng)大、更實(shí)用。5.1 實(shí)現(xiàn)Mini-Batch梯度下降我們目前實(shí)現(xiàn)的是批量梯度下降Batch Gradient Descent即每次迭代使用全部訓(xùn)練數(shù)據(jù)計(jì)算梯度。這對(duì)于大型數(shù)據(jù)集來(lái)說(shuō)單次迭代的計(jì)算開(kāi)銷(xiāo)和內(nèi)存占用都很大。隨機(jī)梯度下降SGD每次只用一個(gè)樣本更新參數(shù)波動(dòng)大可能難以收斂到精確最優(yōu)點(diǎn)。小批量梯度下降Mini-Batch GD折中方案。每次迭代隨機(jī)抽取一小批如64 128 256數(shù)據(jù)進(jìn)行計(jì)算。這既能利用向量化計(jì)算的效率又能引入一定的隨機(jī)性有助于跳出局部最優(yōu)。實(shí)現(xiàn)時(shí)你需要在訓(xùn)練循環(huán)外層增加一個(gè)對(duì)數(shù)據(jù)批次進(jìn)行隨機(jī)打亂和分組的邏輯。5.2 集成自適應(yīng)優(yōu)化器以Adam為例基礎(chǔ)的梯度下降法對(duì)所有參數(shù)使用相同的、固定的學(xué)習(xí)率。自適應(yīng)優(yōu)化器如Adam、RMSprop會(huì)為每個(gè)參數(shù)計(jì)算自適應(yīng)的學(xué)習(xí)率。Adam優(yōu)化器結(jié)合了動(dòng)量Momentum和RMSprop的思想它大致的工作流程是計(jì)算梯度的一階矩估計(jì)有偏和二階矩估計(jì)有偏。對(duì)一階和二階矩估計(jì)進(jìn)行偏差校正。用校正后的估計(jì)更新參數(shù)。雖然實(shí)現(xiàn)起來(lái)比基礎(chǔ)SGD復(fù)雜但它能自動(dòng)調(diào)整學(xué)習(xí)率對(duì)超參數(shù)特別是初始學(xué)習(xí)率不那么敏感通常能帶來(lái)更快的收斂速度。你可以嘗試將其作為update_parameters函數(shù)的一個(gè)高級(jí)替代選項(xiàng)。5.3 構(gòu)建一個(gè)簡(jiǎn)單的模型API為了讓你的MLP更易用可以將其封裝成一個(gè)簡(jiǎn)單的類(lèi)或結(jié)構(gòu)體提供類(lèi)似model.fit(X_train, Y_train)和model.predict(X_test)的接口。fit函數(shù)整合初始化、訓(xùn)練循環(huán)、成本記錄等功能。predict函數(shù)只進(jìn)行前向傳播返回預(yù)測(cè)結(jié)果。對(duì)于分類(lèi)問(wèn)題在輸出層之后需要對(duì)Sigmoid輸出進(jìn)行閾值判斷如0.5為1否則為0或?qū)oftmax輸出取argmax。還可以加入save_weights和load_weights函數(shù)用于保存和加載訓(xùn)練好的模型參數(shù)。手搓MLP的過(guò)程是一個(gè)從“知其然”到“知其所以然”的深刻旅程。它剝開(kāi)了深度學(xué)習(xí)框架的魔法外衣讓你直面最核心的數(shù)學(xué)和算法。當(dāng)你看到自己編寫(xiě)的幾行矩陣運(yùn)算代碼在經(jīng)過(guò)迭代后真的從雜亂的數(shù)據(jù)中學(xué)習(xí)到了規(guī)律那種成就感是調(diào)用現(xiàn)成API無(wú)法比擬的。這份對(duì)底層原理的透徹理解將成為你后續(xù)駕馭更復(fù)雜模型、進(jìn)行模型調(diào)試和創(chuàng)新的堅(jiān)實(shí)基石。無(wú)論未來(lái)你使用多么高級(jí)的框架這段親手構(gòu)建的體驗(yàn)都會(huì)讓你對(duì)神經(jīng)網(wǎng)絡(luò)內(nèi)部發(fā)生的一切保持一份清晰的洞察力。本文還有配套的精品資源點(diǎn)擊獲取