現(xiàn):MNIST分類課設(shè)全解析)
簡介面向機(jī)器學(xué)習(xí)課程設(shè)計(jì)場景該資源聚焦線性回歸分類與手寫數(shù)字識別兩大核心任務(wù)適合正在完成結(jié)課大作業(yè)、希望參考完整代碼實(shí)現(xiàn)的高校學(xué)生。資源包共11個文件包含7個Python腳本和4個MNIST數(shù)據(jù)集文件壓縮包大小約11MB代碼既有手動設(shè)計(jì)實(shí)現(xiàn)也有直接調(diào)用sklearn庫的版本便于對照學(xué)習(xí)算法細(xì)節(jié)與工程化調(diào)用方法目前已有646人學(xué)習(xí)下載。內(nèi)容涵蓋高斯函數(shù)回歸、冪函數(shù)回歸、手寫數(shù)字識別及KMeans聚類應(yīng)用等涉及數(shù)據(jù)加載、預(yù)處理、模型構(gòu)建、訓(xùn)練評估全流程其中手寫數(shù)字部分包含原始數(shù)據(jù)集與多種實(shí)現(xiàn)回歸部分則通過不同基函數(shù)展示擬合效果。通過自主實(shí)現(xiàn)與調(diào)庫實(shí)現(xiàn)的對比能幫助讀者深入理解線性回歸在分類任務(wù)中的拓展以及不同特征處理方式對識別效果的影響可直接作為課程設(shè)計(jì)代碼庫或?qū)嶒?yàn)報(bào)告素材。1. 一份課設(shè)壓縮包背后的兩條技術(shù)路線接手“線性回歸分類、手寫數(shù)字識別”這類課設(shè)題目時大多數(shù)人的第一反應(yīng)是去找一份能直接跑的現(xiàn)成代碼。但真正拉開分?jǐn)?shù)差距的從來不是代碼能不能跑通而是你有沒有把“設(shè)計(jì)程序”和“調(diào)庫程序”這兩條路線都講清楚。所謂設(shè)計(jì)程序指的是從損失函數(shù)、梯度更新到前向傳播全部手寫實(shí)現(xiàn)不借助 sklearn 或 PyTorch 的現(xiàn)成模型類調(diào)庫程序則是用成熟的機(jī)器學(xué)習(xí)框架在幾行內(nèi)完成同樣的任務(wù)。這兩條路線對應(yīng)著兩種能力前者驗(yàn)證你對算法原理的理解后者驗(yàn)證你對工程工具鏈的熟練度。本文從三個層面展開先建立線性回歸與分類任務(wù)的數(shù)學(xué)對應(yīng)關(guān)系再分別拆解手寫實(shí)現(xiàn)和調(diào)庫實(shí)現(xiàn)的關(guān)鍵代碼最后給出課設(shè)報(bào)告中能拿高分的結(jié)果分析思路。如果你正卡在 MNIST 數(shù)據(jù)讀取、梯度下降不收斂或準(zhǔn)確率上不去這類問題上這篇內(nèi)容正好覆蓋。2. 線性回歸分類從 MSE 到?jīng)Q策邊界的數(shù)學(xué)一跳2.1 線性回歸與分類任務(wù)的關(guān)系澄清線性回歸原本解決連續(xù)值預(yù)測問題標(biāo)簽 y 屬于實(shí)數(shù)域。而分類任務(wù)的標(biāo)簽是離散的類別編號。二者能聯(lián)系起來靠的是“回歸輸出 閾值判斷”這個組合拳。二元分類可以看作在特征空間中尋找一個超平面 w·x b 0樣本落在哪一側(cè)就判為哪一類。這個超平面的參數(shù) w 和 b 正是線性回歸要學(xué)習(xí)的對象。一個常見的理解誤區(qū)是直接拿線性回歸的預(yù)測值當(dāng)作分類置信度。線性回歸的輸出范圍是 (-∞, ∞)當(dāng)真實(shí)標(biāo)簽是 0 和 1 時模型為了逼近極端值會在邊界處產(chǎn)生很大的梯度導(dǎo)致決策邊界被拉扯。更嚴(yán)謹(jǐn)?shù)淖龇ㄊ窃诰€性輸出之后接一個激活函數(shù)比如 Sigmoid 或 Softmax把連續(xù)值壓縮到 (0,1) 區(qū)間內(nèi)作為概率。這就是邏輯回歸Logistic Regression的思路嚴(yán)格意義上它屬于廣義線性模型但從課設(shè)評分角度看“線性回歸 激活函數(shù) 交叉熵?fù)p失”被歸入線性回歸分類的范疇是完全可以接受的。2.2 損失函數(shù)設(shè)計(jì)與梯度推導(dǎo)手寫實(shí)現(xiàn)的第一步不是寫代碼是寫出損失函數(shù)對參數(shù)的偏導(dǎo)。以均方誤差MSE為例模型輸出為 y_hat X·w b損失為L(w,b) (1/2m) · Σ(y_hat_i - y_i)2其中 m 是樣本數(shù)。之所以在標(biāo)準(zhǔn) MSE 基礎(chǔ)上加 1/2 系數(shù)是為了求導(dǎo)后系數(shù)抵消讓梯度表達(dá)式更干凈。對 w 求偏導(dǎo)?L/?w (1/m) · X?·(X·w b - y)對 b 求偏導(dǎo)?L/?b (1/m) · Σ(y_hat_i - y_i)有了這兩個梯度參數(shù)更新就寫成w : w - α · ?L/?w b : b - α · ?L/?bα 是學(xué)習(xí)率。這里有一個更高效的做法如果把偏置 b 吸收進(jìn)權(quán)重向量在特征矩陣 X 左側(cè)拼接一列全 1那么 X 從 (m, n) 變成 (m, n1)w 從 (n,) 變成 (n1,)上面的更新規(guī)則只需要維護(hù)一個參數(shù)向量。調(diào)庫實(shí)現(xiàn)時 sklearn 的 LinearRegression 默認(rèn)使用最小二乘法閉式解 w (X?X)?1X?y它不需要設(shè)置學(xué)習(xí)率也沒有迭代過程。但當(dāng)特征維度很高或矩陣奇異時閉式解的計(jì)算會不穩(wěn)定此時梯度下降反而更可靠。這就是設(shè)計(jì)程序存在的工程意義。2.3 手寫線性回歸分類的最小實(shí)現(xiàn)下面給出一個完整可運(yùn)行的手寫線性回歸分類實(shí)現(xiàn)用梯度下降訓(xùn)練并用 Sigmoid 做概率轉(zhuǎn)換。數(shù)據(jù)集選擇 sklearn 自帶的乳腺癌數(shù)據(jù)集它有 30 個特征、569 個樣本規(guī)模適合課設(shè)演示。import numpy as np from sklearn.datasets import load_breast_cancer from sklearn.preprocessing import StandardScaler from sklearn.model_selection import train_test_split # 加載數(shù)據(jù)并標(biāo)準(zhǔn)化 data load_breast_cancer() X, y data.data, data.target scaler StandardScaler() X scaler.fit_transform(X) # 標(biāo)準(zhǔn)化到均值為0方差為1 # 劃分訓(xùn)練集和測試集 X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.2, random_state42 ) # 在特征矩陣左側(cè)拼接全1列對應(yīng)偏置項(xiàng) X_train_b np.c_[np.ones((X_train.shape[0], 1)), X_train] X_test_b np.c_[np.ones((X_test.shape[0], 1)), X_test] # 初始化權(quán)重 m, n X_train_b.shape w np.random.randn(n, 1) * 0.01 y_train y_train.reshape(-1, 1) y_test y_test.reshape(-1, 1) # 超參數(shù) alpha 0.1 epochs 1000 losses [] for epoch in range(epochs): # 前向線性輸出 sigmoid激活 z X_train_b w y_hat 1 / (1 np.exp(-z)) # 損失交叉熵 loss -np.mean( y_train * np.log(y_hat 1e-8) (1 - y_train) * np.log(1 - y_hat 1e-8) ) losses.append(loss) # 梯度計(jì)算 grad (1 / m) * X_train_b.T (y_hat - y_train) # 參數(shù)更新 w - alpha * grad # 預(yù)測和評估 test_prob 1 / (1 np.exp(-X_test_b w)) test_pred (test_prob 0.5).astype(int) accuracy np.mean(test_pred y_test) print(f測試集準(zhǔn)確率: {accuracy:.4f})代碼邏輯說明標(biāo)準(zhǔn)化放在訓(xùn)練前是因?yàn)樘荻认陆祵μ卣鞯某叨让舾腥绻蛔鰳?biāo)準(zhǔn)化梯度在數(shù)值上會被大尺度特征主導(dǎo)小尺度特征對應(yīng)的權(quán)重更新緩慢。拼接全 1 列后權(quán)重向量的最后一個分量就是偏置。損失函數(shù)使用交叉熵而非 MSE這是分類任務(wù)的推薦選擇因?yàn)?MSE 配合 Sigmoid 會面臨梯度飽和問題在 Sigmoid 輸出接近 0 或 1 時梯度趨近于零訓(xùn)練會卡住。參數(shù)說明學(xué)習(xí)率 α 設(shè)置為 0.1歸一化之后這個數(shù)值通常合適。如果損失曲線下降很慢可以嘗試 0.3如果損失震蕩甚至爆炸降到 0.03 再試。epochs 設(shè) 1000 是因?yàn)?sklearn 的乳腺癌數(shù)據(jù)量不大1000 輪訓(xùn)練在普通 CPU 上只要一兩秒。1e-8加在 log 內(nèi)部是為了防止 y_hat 取到 0 或 1 時出現(xiàn) log(0) 的數(shù)學(xué)錯誤。3. 手寫數(shù)字識別MNIST 的讀取、訓(xùn)練與評估全流程3.1 從 MNIST 原始文件到手寫代碼的環(huán)境準(zhǔn)備手寫數(shù)字識別最常用的數(shù)據(jù)集是 MNIST包含 60000 張訓(xùn)練圖片和 10000 張測試圖片每張圖片是 28×28 像素的灰度圖。原始數(shù)據(jù)以 IDX 文件格式存儲不是常見的圖片文件如 PNG 或 JPG。讀取時要注意文件頭信息前 4 個字節(jié)是魔數(shù)接下來的 4 個字節(jié)是樣本數(shù)量再接下來分別用 4 字節(jié)指定行數(shù)和列數(shù)之后才是像素?cái)?shù)據(jù)。解析時全部使用大端序。設(shè)計(jì)程序和調(diào)庫程序的差別從數(shù)據(jù)讀取階段就開始了。調(diào)庫路線可以用 torchvision 的datasets.MNIST一行加載數(shù)據(jù)設(shè)計(jì)路線需要手工解析二進(jìn)制文件。建議課設(shè)代碼里保留兩種讀取方式手寫解析函數(shù)證明你理解數(shù)據(jù)格式調(diào)用現(xiàn)成 API 證明你熟悉工具。3.2 圖像展平與特征變換的準(zhǔn)備過程MNIST 每張圖片是二維矩陣28×28而線性模型接受的輸入是一維向量。展平操作將每行像素拼接起來得到 784 維向量。這一步看似簡單但有一個信息損失問題需要描述清楚展平破壞了像素之間的空間鄰接關(guān)系。卷積神經(jīng)網(wǎng)絡(luò)正是為保留這種空間結(jié)構(gòu)而設(shè)計(jì)的線性模型則天然不具備這種能力。這就是為什么 MNIST 上線性模型準(zhǔn)確率上限在 92% 左右而簡單 CNN 能輕松超過 98%。除展平外像素值歸一化也值得專門寫一段。MNIST 像素原始范圍是 0 到 255如果直接喂給模型梯度尺度會非常大。常見做法是除以 255 把范圍壓縮到 [0,1]或按 (x - mean) / std 做標(biāo)準(zhǔn)化。對線性模型來說前者足夠后者在數(shù)據(jù)分布偏移明顯的場景下更穩(wěn)。3.3 手寫 Softmax 回歸核心訓(xùn)練代碼MNIST 有 10 個類別二元邏輯回歸需要擴(kuò)展成多分類形式。Softmax 回歸將線性輸出轉(zhuǎn)換為 10 個類別的概率分布每個樣本的損失用交叉熵計(jì)算。下面這段代碼是手寫實(shí)現(xiàn)的核心部分適合直接放入課設(shè)報(bào)告。import numpy as np import struct def load_mnist_images(filename): 解析MNIST圖像文件IDX格式 with open(filename, rb) as f: magic, num, rows, cols struct.unpack(IIII, f.read(16)) # 按大端序解析4個無符號整數(shù) data np.frombuffer(f.read(), dtypenp.uint8) return data.reshape(num, rows * cols) / 255.0 # 展平并歸一化 def load_mnist_labels(filename): 解析MNIST標(biāo)簽文件 with open(filename, rb) as f: magic, num struct.unpack(II, f.read(8)) data np.frombuffer(f.read(), dtypenp.uint8) return data # 加載數(shù)據(jù) X_train load_mnist_images(train-images.idx3-ubyte) y_train load_mnist_labels(train-labels.idx1-ubyte) X_test load_mnist_images(t10k-images.idx3-ubyte) y_test load_mnist_labels(t10k-labels.idx1-ubyte) # one-hot編碼標(biāo)簽 def one_hot(y, num_classes10): return np.eye(num_classes)[y] Y_train one_hot(y_train) num_classes 10 m, n X_train.shape # m60000, n784 # 初始化權(quán)重加1列給偏置 W np.random.randn(n 1, num_classes) * 0.01 X_train_b np.c_[np.ones((m, 1)), X_train] X_test_b np.c_[np.ones((X_test.shape[0], 1)), X_test] # 超參數(shù) alpha 0.5 epochs 500 for epoch in range(epochs): # 前向傳播線性變換 softmax scores X_train_b W # 形狀60000 x 10 exp_scores np.exp(scores - np.max(scores, axis1, keepdimsTrue)) probs exp_scores / np.sum(exp_scores, axis1, keepdimsTrue) # 交叉熵?fù)p失 L2正則 reg_lambda 0.01 loss -np.mean(np.sum(Y_train * np.log(probs 1e-8), axis1)) loss 0.5 * reg_lambda * np.sum(W[1:, :] ** 2) # 正則項(xiàng)不加偏置 # 梯度 grad (1 / m) * X_train_b.T (probs - Y_train) grad[1:, :] reg_lambda * W[1:, :] # 正則項(xiàng)梯度 W - alpha * grad if (epoch 1) % 100 0: print(fEpoch {epoch 1}/{epochs}, Loss: {loss:.4f}) # 評估 test_scores X_test_b W test_pred np.argmax(test_scores, axis1) accuracy np.mean(test_pred y_test) print(f測試集準(zhǔn)確率: {accuracy:.4f})損失函數(shù)里減去np.max(scores)是數(shù)值穩(wěn)定的標(biāo)準(zhǔn)技巧。softmax 中的指數(shù)計(jì)算在 score 很大時會溢出減去每行最大值后再取指數(shù)可以保證 exp 的參數(shù)最大為 0計(jì)算過程完全可控。這個細(xì)節(jié)在報(bào)告的“數(shù)值穩(wěn)定性處理”部分值得單獨(dú)寫一段。L2 正則化對 MNIST 這種高維數(shù)據(jù)很有必要。784 維特征對應(yīng)至少 7840 個參數(shù)加偏置后是 7850模型容量遠(yuǎn)大于任務(wù)需求不加正則很容易讓權(quán)重絕對值偏大。正則系數(shù) reg_lambda 取值 0.001 到 0.1 之間較常見取 0.01 是比較中庸的起點(diǎn)。注意梯度里正則項(xiàng)的更新只作用于 W 除第一行以外的部分因?yàn)榈谝恍袑?yīng)偏置通常不對它施加正則約束。這個手寫實(shí)現(xiàn)在 MNIST 上大約能跑出 91% 到 92% 的準(zhǔn)確率與調(diào)庫的線性模型相當(dāng)。訓(xùn)練時間取決于你的機(jī)器配置標(biāo)壓筆記本上 500 輪大約 30 秒到 1 分鐘。4. 調(diào)庫版本sklearn 與 PyTorch 的工程化實(shí)現(xiàn)對照4.1 sklearn 一行代碼完成線性分類調(diào)庫路線的最簡實(shí)現(xiàn)可以用 sklearn 的 LogisticRegression它內(nèi)部使用 L-BFGS 優(yōu)化算法不需要手動設(shè)置學(xué)習(xí)率。直接看代碼from sklearn.linear_model import LogisticRegression from sklearn.datasets import load_breast_cancer from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler from sklearn.metrics import accuracy_score data load_breast_cancer() X, y data.data, data.target X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.2, random_state42 ) scaler StandardScaler() X_train scaler.fit_transform(X_train) X_test scaler.transform(X_test) model LogisticRegression(C1.0, solverlbfgs, max_iter1000) model.fit(X_train, y_train) y_pred model.predict(X_test) print(f準(zhǔn)確率: {accuracy_score(y_test, y_pred):.4f})注意fit_transform和transform的區(qū)別測試集的均值和方差必須從訓(xùn)練集計(jì)算得出不能在測試集上單獨(dú) fit。如果測試集用了自己的均值方差相當(dāng)于測試集的信息泄漏到預(yù)處理階段評估結(jié)果會略偏樂觀。超參數(shù)C是正則化強(qiáng)度的倒數(shù)C 越小正則越強(qiáng)。課設(shè)報(bào)告中建議做一組 C 的網(wǎng)格搜索用交叉驗(yàn)證選出最優(yōu)參數(shù)這個過程在調(diào)庫路線的描述里會占不少篇幅。可以展示這樣一個參數(shù)調(diào)優(yōu)表格C 值訓(xùn)練集準(zhǔn)確率測試集準(zhǔn)確率備注0.010.9720.965強(qiáng)正則略欠擬合0.10.9820.973較優(yōu)1.00.9880.964存在輕微過擬合10.00.9920.957正則弱過擬合加劇這個表格直觀體現(xiàn)了正則強(qiáng)度與泛化能力的權(quán)衡。4.2 PyTorch 實(shí)現(xiàn) MNIST 分類的訓(xùn)練循環(huán)PyTorch 版本用nn.Linear加CrossEntropyLoss就可以完成線性分類任務(wù)。與手寫版本相比PyTorch 自動處理梯度反向傳播訓(xùn)練循環(huán)的代碼量少很多import torch import torch.nn as nn from torch.utils.data import DataLoader, TensorDataset from torchvision import datasets, transforms # 使用torchvision加載MNIST transform transforms.Compose([ transforms.ToTensor(), # 轉(zhuǎn)Tensor并歸一化到[0,1] transforms.Lambda(lambda x: x.view(-1)) # 展平為784維 ]) train_dataset datasets.MNIST( root./data, trainTrue, downloadTrue, transformtransform ) test_dataset datasets.MNIST( root./data, trainFalse, downloadTrue, transformtransform ) train_loader DataLoader(train_dataset, batch_size64, shuffleTrue) test_loader DataLoader(test_dataset, batch_size256, shuffleFalse) # 定義模型784 - 10 的線性層 model nn.Linear(784, 10) criterion nn.CrossEntropyLoss() optimizer torch.optim.SGD(model.parameters(), lr0.1, momentum0.9) epochs 10 for epoch in range(epochs): for batch_X, batch_y in train_loader: optimizer.zero_grad() outputs model(batch_X) # 前向傳播 loss criterion(outputs, batch_y) loss.backward() # 自動反向傳播 optimizer.step() # 參數(shù)更新 print(fEpoch {epoch1}, Loss: {loss.item():.4f}) # 評估 correct 0 total 0 with torch.no_grad(): for batch_X, batch_y in test_loader: outputs model(batch_X) _, predicted torch.max(outputs, 1) total batch_y.size(0) correct (predicted batch_y).sum().item() print(f準(zhǔn)確率: {correct / total:.4f})nn.CrossEntropyLoss在 PyTorch 里已經(jīng)集成了 Softmax 運(yùn)算所以模型的輸出層不需要再手動加 Softmax 激活。這一點(diǎn)新手容易搞混默認(rèn)情況下模型的最后一層輸出原始 logits損失函數(shù)內(nèi)部負(fù)責(zé)轉(zhuǎn)換。與手寫實(shí)現(xiàn)對比需要注意的數(shù)據(jù)流差異手寫版本用的是全量梯度下降每輪迭代看過全部 60000 個樣本PyTorch 版本用 mini-batch 隨機(jī)梯度下降每個 batch 只有 64 個樣本。batch 大小會影響梯度估計(jì)的噪聲和收斂速度一般 32 到 128 之間是經(jīng)驗(yàn)區(qū)。課設(shè)報(bào)告里寫對比結(jié)論時不建議直接說“PyTorch 準(zhǔn)確率高”因?yàn)橛?xùn)練設(shè)置不同梯度下降方式、epoch 數(shù)、優(yōu)化器都會影響最終結(jié)果要控制變量后再下結(jié)論。4.3 手寫與調(diào)庫程序的差異對照設(shè)計(jì)程序和調(diào)庫程序在代碼行數(shù)、調(diào)試方式、運(yùn)行性能和學(xué)習(xí)價值上有明顯區(qū)別。代碼行數(shù)方面手寫線性回歸至少需要 80 到 120 行才能完整覆蓋數(shù)據(jù)處理、訓(xùn)練循環(huán)、評估指標(biāo)調(diào)庫版本通常 40 行內(nèi)結(jié)束。但這不代表手寫代碼“沒用”它要求你理解梯度公式的每一項(xiàng)從矩陣的哪個維度來理解損失函數(shù)如何驅(qū)動參數(shù)更新。調(diào)試層面手寫實(shí)現(xiàn)一旦出現(xiàn) NaN 或輸出不收斂排查路徑通常是“數(shù)值穩(wěn)定性 → 學(xué)習(xí)率 → 數(shù)據(jù)預(yù)處理”三連擊調(diào)庫版本的報(bào)錯更多是 API 使用問題和數(shù)據(jù)形狀不匹配網(wǎng)上可查的解決方案很多。性能層面設(shè)計(jì)程序的矩陣運(yùn)算基于 NumPy在 CPU 上表現(xiàn)不錯PyTorch 如果啟用 CUDAGPU 加速在大規(guī)模數(shù)據(jù)上優(yōu)勢明顯。MNIST 這種小數(shù)據(jù)集差距不大但如果換到 CIFAR-10 或更大的圖片集差距會拉開。5. 模型診斷與課設(shè)報(bào)告的關(guān)鍵結(jié)果解讀5.1 準(zhǔn)確率之外的四個必看指標(biāo)課設(shè)報(bào)告中如果只寫一個準(zhǔn)確率評分老師會認(rèn)為分析深度不夠。正確率是最直觀的指標(biāo)但分類任務(wù)中類別不平衡時它會有欺騙性。MNIST 的 10 個類別分布相對均勻準(zhǔn)確率問題不大但乳腺癌數(shù)據(jù)集是 357:212 的正負(fù)樣本比只看準(zhǔn)確率會掩蓋模型在少數(shù)類上的表現(xiàn)。建議補(bǔ)上混淆矩陣、精確率Precision、召回率Recall和 F1-Score 四個指標(biāo)。混淆矩陣可以直觀看出哪些數(shù)字容易被混淆比如 4 和 9、3 和 8 是 MNIST 上線性模型的典型混淆對。這些數(shù)字之所以混淆是因?yàn)檎蛊胶蟮?784 維向量丟失了局部形狀信息4 的上半部分和 9 的上半部分在像素分布上高度相似。一個快速實(shí)現(xiàn)混淆矩陣可視化的方法import matplotlib.pyplot as plt from sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay cm confusion_matrix(y_test, test_pred) disp ConfusionMatrixDisplay(confusion_matrixcm) disp.plot(cmapBlues) plt.title(MNIST Confusion Matrix - Linear Model) plt.show()預(yù)測錯誤的樣本值得專門挑出幾幅來展示。遍歷測試集找出模型預(yù)測錯誤的圖片再結(jié)合圖片特征說明錯誤原因這部分內(nèi)容在報(bào)告中視覺沖擊力強(qiáng)也能展示你對模型局限性的理解。5.2 學(xué)習(xí)率與正則系數(shù)的邊界在哪里學(xué)習(xí)率是手寫版本中最難調(diào)的超參數(shù)。取 0.1 時損失下降平穩(wěn)但如果試過 1.0 會發(fā)現(xiàn)損失在某一輪后突然變成 NaN原因是梯度更新步長過大參數(shù)跳出了損失函數(shù)的低谷區(qū)域。一個可靠的快速收斂方法是用學(xué)習(xí)率衰減decay_rate 0.99 decay_step 100 for epoch in range(epochs): if (epoch 1) % decay_step 0: alpha * decay_rate每 100 輪乘以 0.99 的衰減因子效果是讓訓(xùn)練前期大步前進(jìn)、后期小步精調(diào)。這種設(shè)置在課設(shè)報(bào)告中體現(xiàn)為“學(xué)習(xí)率從 0.5 逐漸衰減到約 0.37”能明顯提升末段收斂的穩(wěn)定性。正則系數(shù)與學(xué)習(xí)率是耦合的。正則項(xiàng)會讓梯度的方向不止指向損失下降的方向還附帶“把權(quán)重往原點(diǎn)拉”的分量。正則越大可用的學(xué)習(xí)率窗口越窄。建議課設(shè)中做一組 ablation study消融實(shí)驗(yàn)固定學(xué)習(xí)率分別測試 reg_lambda 等于 0、0.001、0.01、0.1 時的訓(xùn)練損失曲線和測試準(zhǔn)確率用圖表說明正則強(qiáng)度對過擬合的抑制效果。5.3 預(yù)測錯誤的典型模式分析MNIST 線性分類器的典型錯誤集中在兩類筆畫交疊的數(shù)字和變形嚴(yán)重的樣本。將錯誤樣本與預(yù)測概率一起打印可以區(qū)分“低置信度錯誤”和“高置信度錯誤”。前者模型本身不確定概率接近 0.5后者模型很自信卻分錯了這通常意味著特征分布中存在與常見模式?jīng)_突的樣本。# 獲取測試集的預(yù)測概率找出預(yù)測錯誤但置信度最高的樣本 test_scores X_test_b W test_probs np.exp(test_scores - np.max(test_scores, axis1, keepdimsTrue)) test_probs / np.sum(test_probs, axis1, keepdimsTrue) misclassified np.where(test_pred ! y_test)[0] confident_errors sorted( misclassified, keylambda i: np.max(test_probs[i]), reverseTrue ) for idx in confident_errors[:5]: true_label y_test[idx] pred_label test_pred[idx] prob np.max(test_probs[idx]) print(f樣本 {idx}: 真實(shí)標(biāo)簽{true_label}, 預(yù)測{pred_label}, 置信度{prob:.3f})通過置信度排序你可能會發(fā)現(xiàn)有些錯誤樣本在訓(xùn)練集中根本找不到類似的圖像這說明模型的上限受限于訓(xùn)練數(shù)據(jù)的覆蓋范圍。在報(bào)告里寫這樣的觀察比單純說“準(zhǔn)確率 92%”有分量得多它說明你理解什么叫做“數(shù)據(jù)分布決定模型能力邊界”。這部分的最后可以加上一個快速驗(yàn)證技巧從兩個版本各隨機(jī)選 10 個測試樣本對比預(yù)測標(biāo)簽是否一致。如果設(shè)計(jì)程序和調(diào)庫程序在大多數(shù)樣本上同判說明兩個實(shí)現(xiàn)的行為一致課設(shè)代碼中的對照實(shí)驗(yàn)才算閉環(huán)。本文還有配套的精品資源點(diǎn)擊獲取