習(xí)第一課:用線性模型理解神經(jīng)網(wǎng)絡(luò)核心原理)
1. 為什么線性模型值得作為深度學(xué)習(xí)的第一課1.1 它到底在解決什么問(wèn)題作為帶過(guò)不少人入門(mén)的老手我被問(wèn)過(guò)很多次“深度學(xué)習(xí)的第一個(gè)模型該學(xué)什么”。我的回答從來(lái)沒(méi)變過(guò)寫(xiě)一個(gè)最簡(jiǎn)單的線性模型。這個(gè)答案看起來(lái)太樸素甚至有點(diǎn)對(duì)不起“深度學(xué)習(xí)”四個(gè)字但真正做完之后你會(huì)發(fā)現(xiàn)它能幫你把神經(jīng)網(wǎng)絡(luò)的骨架一次性搭清楚。題目標(biāo)題里寫(xiě)的liner我默認(rèn)是linear的筆誤我們聊的就是基于linear線性模型的生成也就是讓模型從數(shù)據(jù)中“生成”出一組能擬合規(guī)律的參數(shù)。線性模型解決的是這樣一類問(wèn)題給定一系列輸入和輸出我們希望找到一個(gè)從輸入到輸出的線性映射關(guān)系。舉個(gè)例子房?jī)r(jià)和面積之間如果近似成正比那么面積每增加一平米房?jī)r(jià)增加多少就是一個(gè)線性關(guān)系。我們不需要一開(kāi)始就上卷積神經(jīng)網(wǎng)絡(luò)只要用一條直線y kx b去擬合數(shù)據(jù)點(diǎn)模型自動(dòng)把k和b學(xué)出來(lái)這就是線性模型最原始的場(chǎng)景。放在深度學(xué)習(xí)語(yǔ)境下線性模型不只是“直線擬合”這么簡(jiǎn)單。它是神經(jīng)網(wǎng)絡(luò)的最小單元。我們常聽(tīng)到的全連接層、稠密層、MLP里的Linear層本質(zhì)上都是線性變換。你在Transformer里看到的Q、K、V矩陣第一步也是線性映射。所以如果能把線性模型的原理吃透后面看任何模型源碼都不會(huì)心虛。1.2 深度學(xué)習(xí)框架里的線性層長(zhǎng)什么樣在PyTorch中torch.nn.Linear(in_features, out_features)就是深度學(xué)習(xí)中最常見(jiàn)的線性層。它內(nèi)部維護(hù)兩個(gè)參數(shù)權(quán)重矩陣W和偏置向量b。前向傳播的計(jì)算公式是y x W.T b。這個(gè)公式和中學(xué)生學(xué)的一次函數(shù)ykxb幾乎沒(méi)有區(qū)別只是從標(biāo)量擴(kuò)展到了向量和矩陣。當(dāng)輸入是一個(gè)批量的樣本時(shí)假設(shè)形狀是[batch_size, in_features]Linear層會(huì)把它映射成[batch_size, out_features]的輸出。每個(gè)輸出神經(jīng)元做的事情就是把輸入向量的每個(gè)維度分別乘以一個(gè)權(quán)重再求和最后加上偏置。整個(gè)過(guò)程中沒(méi)有任何非線性變換這也是它被稱為線性的原因。理解了Linear層你就理解了深度學(xué)習(xí)里大約六成的基礎(chǔ)代碼。因?yàn)闊o(wú)論你怎么堆網(wǎng)絡(luò)最底層的計(jì)算單元依然是線性變換加激活函數(shù)。激活函數(shù)負(fù)責(zé)引入非線性線性變換負(fù)責(zé)特征組合。線性層沒(méi)有激活函數(shù)也能存在但它單獨(dú)使用只能表達(dá)線性關(guān)系。這就是本文要做的核心實(shí)驗(yàn)只用一個(gè)線性層讓模型從數(shù)據(jù)中學(xué)會(huì)生成正確的參數(shù)。1.3 一個(gè)“簡(jiǎn)單”的線性模型也沒(méi)那么簡(jiǎn)單很多人覺(jué)得線性模型太基礎(chǔ)不需要專門(mén)學(xué)。但“會(huì)調(diào)用API”和“理解原理”是兩碼事。我見(jiàn)過(guò)不少同學(xué)能跑通CNN卻說(shuō)不清為什么學(xué)習(xí)率過(guò)大會(huì)導(dǎo)致loss變成NaN也不知道為什么模型參數(shù)不更新時(shí)先查一下梯度是否為0。本質(zhì)上就是對(duì)梯度更新這條鏈路缺乏肌肉記憶。線性模型正好把所有核心概念壓縮到最有辨識(shí)度的小場(chǎng)景里前向傳播、損失函數(shù)、梯度計(jì)算、參數(shù)更新、收斂判斷。這些概念在復(fù)雜模型里被大量代碼和網(wǎng)絡(luò)結(jié)構(gòu)掩蓋但在線性模型里每一個(gè)都可以直接用數(shù)學(xué)公式寫(xiě)出來(lái)。你把這一套流程跑通遇到的坑踩一遍以后再切換到神經(jīng)網(wǎng)絡(luò)遇到的問(wèn)題基本是同一批只是規(guī)模變大而已。用真實(shí)項(xiàng)目心態(tài)來(lái)對(duì)待這個(gè)“玩具模型”很重要。線性模型在生產(chǎn)里依然被廣泛使用比如銷售預(yù)測(cè)、溫度預(yù)測(cè)、廣告點(diǎn)擊率預(yù)估的baseline。它更是你生成式AI實(shí)驗(yàn)的起點(diǎn)。今天這篇文章我們就從數(shù)據(jù)生成開(kāi)始手寫(xiě)一個(gè)線性模型再用PyTorch復(fù)現(xiàn)一遍最后聊聊那些訓(xùn)練中必然會(huì)踩的坑。2. 先把數(shù)學(xué)寫(xiě)明白前向傳播、損失和梯度2.1 前向傳播的矩陣表示要用代碼實(shí)現(xiàn)線性模型第一步是把數(shù)學(xué)公式寫(xiě)清楚。假設(shè)我們有m個(gè)樣本每個(gè)樣本只有一個(gè)特征x那么前向傳播就是y_pred x * w b在批量訓(xùn)練時(shí)可以把所有樣本堆疊成一個(gè)列向量X形狀是[m, 1]。權(quán)重w是標(biāo)量b是標(biāo)量那么y_pred X * w b如果特征不止一個(gè)那么X變成[m, n]w變成[n, 1]輸出仍然是[m, 1]。用矩陣乘法寫(xiě)就是y_pred X w b。這里的 在NumPy和PyTorch中都表示矩陣乘法。為什么需要矩陣形式因?yàn)樯疃葘W(xué)習(xí)訓(xùn)練時(shí)永遠(yuǎn)是一次處理一批數(shù)據(jù)。如果不用矩陣就得寫(xiě)for循環(huán)逐個(gè)樣本計(jì)算效率極低。更重要的是矩陣形式下梯度公式非常優(yōu)雅可以利用線性代數(shù)的性質(zhì)直接推導(dǎo)。你只要記住輸入的形狀是[batch, features]權(quán)重形狀是[features, output_dim]輸出就是[batch, output_dim]。這個(gè)形狀匹配規(guī)則在以后搭建任何線性層時(shí)都不會(huì)變。2.2 損失函數(shù)為什么要用MSE模型輸出的預(yù)測(cè)值和真實(shí)值之間一定有誤差。我們需要一個(gè)數(shù)值指標(biāo)來(lái)衡量誤差有多大這個(gè)指標(biāo)就是損失函數(shù)。線性模型最常用的損失函數(shù)是均方誤差MSE公式為L(zhǎng) (1/m) * Σ (y_pred - y_true)^2為什么用平方而不是絕對(duì)值原因有三個(gè)。第一平方函數(shù)處處可導(dǎo)尤其在誤差接近0的時(shí)候?qū)?shù)也平滑趨近0這非常有利于梯度下降絕對(duì)值函數(shù)在0點(diǎn)不可導(dǎo)雖然也有專門(mén)處理辦法但對(duì)入門(mén)來(lái)說(shuō)沒(méi)必要增加難度。第二平方放大了大誤差的懲罰模型會(huì)更努力去修正那些偏離得離譜的預(yù)測(cè)。第三MSE對(duì)應(yīng)高斯噪聲下的最大似然估計(jì)統(tǒng)計(jì)意義很清晰。當(dāng)然MSE也有缺點(diǎn)它會(huì)對(duì)離群點(diǎn)過(guò)度敏感。一個(gè)極端異常值會(huì)讓模型拼命往那個(gè)點(diǎn)靠攏。但在我們這一篇的線性模型場(chǎng)景中數(shù)據(jù)是自己生成的服從正態(tài)分布噪聲MSE就是最自然的選擇。理解MSE后面再看交叉熵、KL散度都會(huì)有一個(gè)對(duì)照基準(zhǔn)。2.3 梯度的直觀理解有了損失函數(shù)我們要找到一組w和b讓L盡可能小。怎么找梯度下降。梯度是一個(gè)向量它指向損失函數(shù)在當(dāng)前參數(shù)處上升最快的方向。想讓損失下降就要沿著負(fù)梯度方向更新參數(shù)。對(duì)線性模型梯度可以手推出來(lái)。先求出預(yù)測(cè)誤差error y_pred - y_true那么dL/dw (2/m) * X^T errordL/db (2/m) * Σ error這里的關(guān)鍵是誤差error是驅(qū)動(dòng)一切更新的源頭。預(yù)測(cè)偏高了參數(shù)就往下調(diào)預(yù)測(cè)偏低了參數(shù)就往上調(diào)。整個(gè)過(guò)程和“一個(gè)人看自己偏離目標(biāo)多遠(yuǎn)然后往回走”是一樣的。理解這一點(diǎn)后再去看PyTorch里的loss.backward()你就知道它其實(shí)就是在自動(dòng)計(jì)算這一堆導(dǎo)數(shù)沒(méi)有任何玄學(xué)。3. 用NumPy手寫(xiě)一個(gè)可訓(xùn)練的線性模型3.1 準(zhǔn)備數(shù)據(jù)用帶噪聲的線性函數(shù)生成為了驗(yàn)證模型能不能學(xué)會(huì)參數(shù)我們得先造一批“標(biāo)準(zhǔn)答案”。真實(shí)規(guī)律設(shè)定為y 3.2x 0.8然后疊加一些正態(tài)分布噪聲。這樣模型能學(xué)到的參數(shù)不會(huì)和真實(shí)參數(shù)完全一樣但會(huì)非常接近。噪聲的存在讓任務(wù)更真實(shí)也讓我們可以觀察損失最終降到什么程度。數(shù)據(jù)生成代碼如下import numpy as np np.random.seed(42) X np.random.rand(200, 1) * 5 # 生成200個(gè)[0,5]區(qū)間內(nèi)的x true_w 3.2 true_b 0.8 y true_w * X true_b np.random.randn(200, 1) * 0.5這里X的形狀是[200, 1]y的形狀也是[200, 1]。噪聲標(biāo)準(zhǔn)差設(shè)置為0.5所以最終MSE的理論下限大約是0.25也就是噪聲方差0.5的平方。如果你發(fā)現(xiàn)訓(xùn)練后loss低于0.25反而說(shuō)明模型把噪聲也學(xué)進(jìn)去了屬于過(guò)擬合信號(hào)。這一步很多人會(huì)忽略但它其實(shí)是判斷模型是否正常收斂的標(biāo)尺。3.2 前向傳播與損失計(jì)算接下來(lái)定義前向傳播和損失函數(shù)。代碼非常簡(jiǎn)潔def forward(X, w, b): return X w b def mse_loss(y_pred, y_true): return np.mean((y_pred - y_true) ** 2)注意np.mean會(huì)把所有樣本誤差的平方取平均這樣損失就是標(biāo)量。為什么不直接用np.sum因?yàn)槿绻麡颖緮?shù)變成1000損失值會(huì)變大不同batch之間就沒(méi)法比較。除以樣本數(shù)之后損失表示“平均每個(gè)樣本錯(cuò)多少”語(yǔ)義更清晰。初始化參數(shù)時(shí)w一般用隨機(jī)數(shù)b可以初始化為0。這里有個(gè)小技巧w的初始值不要太大。如果初始w是10模型一開(kāi)始預(yù)測(cè)會(huì)非常大誤差和梯度都很大可能直接導(dǎo)致參數(shù)更新震蕩。常見(jiàn)的做法是讓w初始值在0附近比如np.random.randn(1, 1) * 0.1。3.3 梯度下降更新代碼有了前向傳播和損失就可以寫(xiě)訓(xùn)練循環(huán)。這里我選擇手動(dòng)計(jì)算梯度因?yàn)檫@是理解整個(gè)深度學(xué)習(xí)最關(guān)鍵的節(jié)點(diǎn)。w np.random.randn(1, 1) * 0.1 b np.zeros((1, 1)) lr 0.01 epochs 500 for epoch in range(epochs): y_pred forward(X, w, b) loss mse_loss(y_pred, y) error y_pred - y grad_w (2.0 / len(X)) * X.T error grad_b (2.0 / len(X)) * np.sum(error) w w - lr * grad_w b b - lr * grad_b if epoch % 50 0: print(fepoch {epoch}, loss {loss:.4f}, w {w.item():.4f}, b {b.item():.4f})訓(xùn)練過(guò)程中每隔50個(gè)epoch打印一次。你會(huì)發(fā)現(xiàn)loss從某個(gè)初始值逐漸下降w慢慢接近3.2b接近0.8。如果lr設(shè)置合適500輪之后就能收斂到差不多位置。這里的(2.0 / len(X))正是MSE對(duì)w求導(dǎo)的結(jié)果系數(shù)2不能漏否則梯度方向是對(duì)的但每一步的步長(zhǎng)會(huì)錯(cuò)一半導(dǎo)致收斂變慢。3.4 跑起來(lái)看結(jié)果訓(xùn)練完成后把學(xué)到的參數(shù)和真實(shí)參數(shù)對(duì)比你會(huì)看到類似這樣的輸出epoch 450, loss 0.2381, w 3.1894, b 0.8236w和b沒(méi)有完全等于3.2和0.8因?yàn)閿?shù)據(jù)里有噪聲模型只能無(wú)限接近真實(shí)的線性規(guī)律。如果把原始數(shù)據(jù)散點(diǎn)圖和擬合直線畫(huà)在同一張圖里可以看到直線穿過(guò)了點(diǎn)云的中心。這說(shuō)明模型已經(jīng)成功“生成”了一個(gè)線性映射。這一步的意義在于我們用最基礎(chǔ)的工具復(fù)現(xiàn)了深度學(xué)習(xí)的最小閉環(huán)前向傳播計(jì)算預(yù)測(cè)值損失函數(shù)量化誤差反向傳播這里手動(dòng)推導(dǎo)計(jì)算梯度然后用梯度更新參數(shù)。之后所有深度學(xué)習(xí)框架做的都是同一件事。把這個(gè)閉環(huán)刻進(jìn)腦子里你就算真正入門(mén)了。4. 用PyTorch實(shí)現(xiàn)同樣的模型并驗(yàn)證效果4.1 為什么換成PyTorchNumPy版本能讓我們看清每一步的數(shù)學(xué)原理但真實(shí)做深度學(xué)習(xí)時(shí)不會(huì)手動(dòng)算梯度。PyTorch的autograd機(jī)制會(huì)自動(dòng)構(gòu)建計(jì)算圖并計(jì)算梯度我們只需要定義網(wǎng)絡(luò)結(jié)構(gòu)和損失函數(shù)。更重要的是PyTorch的模塊化設(shè)計(jì)讓我們可以從線性模型平滑過(guò)渡到多層神經(jīng)網(wǎng)絡(luò)。很多人一開(kāi)始直接學(xué)PyTorch會(huì)陷入“為什么需要.backward()”的困惑。但在手寫(xiě)了NumPy版本之后你看到loss.backward()就知道它等同于我們手動(dòng)算的grad_w和grad_b看到optimizer.step()就知道它等同于w w - lr * grad_w。有了基礎(chǔ)框架在你眼里就不是魔法而是工具。4.2 搭建模型與訓(xùn)練循環(huán)用PyTorch實(shí)現(xiàn)同樣的線性模型代碼反而更短。但有幾個(gè)細(xì)節(jié)必須注意否則會(huì)踩坑。import torch import torch.nn as nn # 數(shù)據(jù)轉(zhuǎn)換 X_t torch.tensor(X, dtypetorch.float32) y_t torch.tensor(y, dtypetorch.float32) # 定義模型一個(gè)輸入維度為1輸出維度為1的線性層 model nn.Linear(1, 1) # 定義優(yōu)化器和損失函數(shù) optimizer torch.optim.SGD(model.parameters(), lr0.01) loss_fn nn.MSELoss() for epoch in range(500): y_pred model(X_t) loss loss_fn(y_pred, y_t) optimizer.zero_grad() loss.backward() optimizer.step() if epoch % 50 0: print(fepoch {epoch}, loss {loss.item():.4f})這里的model(X_t)會(huì)調(diào)用Linear層的forward自動(dòng)完成x W.T b。訓(xùn)練循環(huán)里有一行很不起眼但極其重要的代碼optimizer.zero_grad()。PyTorch的梯度是累積的如果不清零上一輪的梯度會(huì)加到這一輪上導(dǎo)致參數(shù)更新方向出現(xiàn)偏差訓(xùn)練結(jié)果一團(tuán)糟。新手最容易漏掉的就是這一行。4.3 完整代碼與結(jié)果訓(xùn)練結(jié)束后通過(guò)以下方式取出參數(shù)print(model.weight.item(), model.bias.item())正常情況下輸出會(huì)在3.2和0.8附近。這里有一個(gè)值得注意的現(xiàn)象每次運(yùn)行結(jié)果會(huì)有細(xì)微差別因?yàn)槟P蛥?shù)初始化是隨機(jī)的。但最終都會(huì)收斂到同一片區(qū)域。PyTorch的nn.Linear默認(rèn)會(huì)做合理的參數(shù)初始化所以我們的初始w已經(jīng)接近0不需要額外處理。如果你把優(yōu)化器換成Adam比如torch.optim.Adam(model.parameters(), lr0.05)收斂速度會(huì)明顯加快。這可能讓你產(chǎn)生“Adam比SGD更好”的錯(cuò)覺(jué)。其實(shí)在簡(jiǎn)單凸問(wèn)題上兩者都能收斂只是路徑不同。線性模型最適合先看SGD的表現(xiàn)因?yàn)樗庇^、更容易配合你手動(dòng)計(jì)算的梯度做驗(yàn)證。4.4 從線性模型推廣到多層感知機(jī)學(xué)會(huì)了線性層下一步稍微擴(kuò)展一下就能變成一個(gè)兩層的神經(jīng)網(wǎng)絡(luò)。把模型改成model nn.Sequential( nn.Linear(1, 16), nn.ReLU(), nn.Linear(16, 1) )訓(xùn)練代碼幾乎不用改。這時(shí)候模型不再是直線了而是一條可以彎曲的曲線。因?yàn)橹虚g加了一層ReLU激活函數(shù)給模型注入了非線性表達(dá)能力。你會(huì)發(fā)現(xiàn)對(duì)于同樣的線性數(shù)據(jù)這個(gè)兩層網(wǎng)絡(luò)也能學(xué)會(huì)而且可能比單層線性模型學(xué)得更復(fù)雜。但如果數(shù)據(jù)真的是線性關(guān)系兩層網(wǎng)絡(luò)反而可能過(guò)擬合。這個(gè)實(shí)驗(yàn)的意義在于讓你看清深度學(xué)習(xí)和線性模型不是兩套完全割裂的東西。多層的神經(jīng)網(wǎng)絡(luò)只是在基礎(chǔ)線性變換之間插入了激活函數(shù)整體訓(xùn)練邏輯依然是前向傳播、求loss、反向傳播、更新參數(shù)。你掌握了線性模型就等于把神經(jīng)網(wǎng)絡(luò)中最核心的骨架握在了手里。5. 訓(xùn)練過(guò)程中最常見(jiàn)的坑和調(diào)參建議5.1 學(xué)習(xí)率太大loss爆炸我見(jiàn)過(guò)非常多初學(xué)者在第一個(gè)訓(xùn)練循環(huán)里就把lr設(shè)成1然后眼睜睜看著loss變成NaN。為什么會(huì)這樣回到參數(shù)更新公式w w - lr * grad_w。如果lr太大每次w移動(dòng)的距離超過(guò)真實(shí)需要的范圍就可能越過(guò)最優(yōu)區(qū)域來(lái)到誤差更大的地方。下一輪的梯度也因此更大參數(shù)進(jìn)一步飛出去最終數(shù)值溢出。你可以用相同的數(shù)據(jù)試試lr0.5或lr1。大概幾十輪之后loss就會(huì)變成inf或者nan。這絕不是代碼寫(xiě)錯(cuò)了而是優(yōu)化過(guò)程不穩(wěn)定。處理方式很簡(jiǎn)單把學(xué)習(xí)率調(diào)小比如0.001通常能穩(wěn)定下來(lái)。學(xué)習(xí)率跟模型結(jié)構(gòu)、數(shù)據(jù)尺度都有關(guān)系沒(méi)有通用最優(yōu)值但從小學(xué)習(xí)率開(kāi)始總是對(duì)的。5.2 特征未歸一化梯度震蕩線性模型對(duì)輸入特征的尺度很敏感。如果x的范圍是0到5SGD收斂很快。但如果x的范圍是0到50000損失函數(shù)曲面就會(huì)變成一個(gè)細(xì)長(zhǎng)的碗梯度方向不指向碗底導(dǎo)致收斂極其緩慢甚至來(lái)回震蕩。解決辦法是對(duì)特征做標(biāo)準(zhǔn)化讓每個(gè)維度的均值接近0標(biāo)準(zhǔn)差接近1。標(biāo)準(zhǔn)化代碼很簡(jiǎn)單X_mean X_t.mean() X_std X_t.std() X_norm (X_t - X_mean) / X_std這樣處理后損失函數(shù)的等高線更接近圓形梯度下降路徑會(huì)平緩很多。這在實(shí)際項(xiàng)目中會(huì)比在本文實(shí)驗(yàn)中更重要因?yàn)檎鎸?shí)數(shù)據(jù)的特征尺度往往相差懸殊。記住一條原則深度學(xué)習(xí)模型里輸入的數(shù)值規(guī)模不宜過(guò)大盡量保持在0附近。5.3 怎么判斷模型收斂了很多人只看loss數(shù)值變得很小就認(rèn)為訓(xùn)練結(jié)束。但更可靠的判斷是看參數(shù)是否穩(wěn)定。在你手動(dòng)打印的日志中如果最后幾百個(gè)epoch里w和b幾乎不再變化說(shuō)明已經(jīng)收斂。如果loss還在緩慢下降而參數(shù)已經(jīng)不動(dòng)可能梯度已經(jīng)太小需要加大學(xué)習(xí)率或改用Adam。還有一個(gè)實(shí)用方法畫(huà)出訓(xùn)練過(guò)程中l(wèi)oss曲線。理想曲線是平滑下降最后趨平。如果loss先降后升說(shuō)明學(xué)習(xí)率可能偏大開(kāi)始震蕩了。如果loss全程基本不動(dòng)可能是初始化或?qū)W習(xí)率的問(wèn)題也可能是梯度為零。對(duì)線性模型來(lái)說(shuō)梯度幾乎不會(huì)為零所以更可能是學(xué)習(xí)率太小。5.4 用真實(shí)項(xiàng)目心態(tài)看待“玩具模型”有同學(xué)會(huì)問(wèn)這篇文章里的模型連“深度學(xué)習(xí)”都算不上值得認(rèn)真學(xué)嗎值得。因?yàn)楹芏鄰?fù)雜模型最容易出的問(wèn)題——loss不降、梯度異常、參數(shù)不更新——在線性模型里就能復(fù)現(xiàn)和排查。用最小場(chǎng)景學(xué)會(huì)這些套路比直接抱著一堆預(yù)訓(xùn)練模型瞎調(diào)參有效得多。在生產(chǎn)中線性回歸也是很多業(yè)務(wù)的強(qiáng)基線。你給客戶做的第一個(gè)預(yù)測(cè)系統(tǒng)往往是從線性模型開(kāi)始的。它訓(xùn)練快、解釋性強(qiáng)、不容易過(guò)擬合。先把線性模型做到極致再考慮加網(wǎng)絡(luò)層數(shù)這是一種非常務(wù)實(shí)的路徑。深度學(xué)習(xí)從來(lái)不是“模型越復(fù)雜越好”而是在保證效果的前提下選擇最合適的解決方案。從數(shù)據(jù)生成到手動(dòng)梯度再到PyTorch自動(dòng)求導(dǎo)最后到調(diào)參避坑我們把一個(gè)簡(jiǎn)單的線性模型從里到外過(guò)了一遍。如果你能跟著代碼敲一遍再把學(xué)習(xí)率、初始化值改一改觀察loss和參數(shù)的變化比看十篇理論文章都有用。我個(gè)人帶人的習(xí)慣是只允許學(xué)員在完成手寫(xiě)線性回歸之后再去碰CNN和Transformer。這個(gè)順序幫很多人避開(kāi)了“一看就會(huì)、一跑就廢”的窘境。