PyTorch 核心三件套:Tensor、Module、Autograd

歡迎來到啾啾的博客🐱。
記錄學習點滴。分享工作思考和實用技巧,偶爾也分享一些雜談💬。
有很多很多不足的地方,歡迎評論交流,感謝您的閱讀和評論😄。

目錄

  • 引言
  • 1 Tensor
    • 1.1 🛠?Tensor 的核心用途(5大場景)
    • 1.2 表示現實世界數據|輸入數據
    • 1.3 表示標簽(Labels / Targets)
    • 1.4 存儲模型參數(Weights & Biases)
    • 1.5 中間計算結果(Forward Pass)
    • 1.6 梯度計算(Backward Pass)
    • 1.7 📚 常用 API 速查表
    • 1.8 💡 Tensor 演示
  • 2 Module
    • 2.1 簡介
    • 2.2 創建Module
    • 2.3 Module 的核心操作
  • 3 Autograd
    • 3.1 簡介
    • 3.2 梯度追蹤
    • 3.3 反向傳播
    • 3.4 禁用梯度計算
  • 4 📌 三件套關系圖解
  • 5 🌟 三件套協同工作流程(完整訓練示例)
    • 5.1 Demo:三件套簡單串聯
    • 5.2 構建一個簡單線性回歸模型 y=wx+b
    • 5.3 Demo:搭建一個簡單的多層感知機
  • 刻意練習

引言

本篇將講述PyTorch的核心“三件套”:Tensor, Module, Autograd。
嘗試以后端崗位工程應用角度來理解、串聯起這個三個概念。

AI使用聲明:本文內容由作者基于對深度學習和PyTorch框架的學習與理解撰寫。在內容整理、結構優化和語言表達的過程中,我使用了人工智能(AI)工具作為輔助。

資料:
《深入淺出PyTorch 第二章節》
《動手學深度學習第四章》

1 Tensor

讓我們思考一個問題,我們要怎么把現實世界的數據變成計算機能處理的數字形式呢?

通過Tensor,張量,它是現代機器學習的基礎。

n維數組,也稱為_張量_(tensor)。

幾何代數中定義的張量是基于向量和矩陣的推廣,比如我們可以將標量視為零階張量,矢量可以視為一階張量,矩陣就是二階張量。

張量維度代表含義示例
0D標量(Scalar)torch.tensor(3.14)
1D向量(Vector)[1, 2, 3]
2D矩陣(Matrix)圖像展平后的特征
3D序列/單圖(C, H, W) 彩色圖像
4D批量圖像(B, C, H, W)

在PyTorch中,?torch.Tensor?是存儲和變換數據的主要工具,比起NumPy更適合深度學習。

1.1 🛠?Tensor 的核心用途(5大場景)

1.2 表示現實世界數據|輸入數據

現實世界常見數據的Tensor示例如下:

數據類型Tensor形狀示例說明
圖像(3, 224, 224)RGB 三通道圖像
批量圖像(64, 3, 224, 224)一次處理64張圖
文本(1, 512)512個詞的編碼序列
音頻(1, 16000)1秒音頻(16kHz采樣)
# 圖像轉 Tensor(使用 torchvision)
from torchvision import transforms
transform = transforms.ToTensor()
image_tensor = transform(pil_image)  # PIL圖像 → Tensor

1.3 表示標簽(Labels / Targets)

可以告訴模型“正確答案”。

# 分類任務:類別標簽
labels = torch.tensor([3, 1, 7, 0])  # 4個樣本的真實類別# 回歸任務:連續值
targets = torch.tensor([1.5, 2.3, 0.8])# 語義分割:每個像素的類別
mask = torch.randint(0, 20, (1, 256, 256))  # (C,H,W)

1.4 存儲模型參數(Weights & Biases)

神經網絡的“記憶”就存在 Tensor 里。

linear = torch.nn.Linear(10, 5)
print(linear.weight.shape)  # torch.Size([5, 10]) ← 這是個 Tensor!
print(linear.bias.shape)    # torch.Size([5])     ← 這也是 Tensor!

這些參數 Tensor 會:

  • 在訓練中不斷更新(梯度下降)
  • 決定模型的預測能力
  • 可以保存和加載(.pth 文件)

1.5 中間計算結果(Forward Pass)

網絡每一層的輸出都是 Tensor 。

x = torch.randn(1, 784)          # 輸入
w = torch.randn(784, 256)        # 權重
b = torch.zeros(256)             # 偏置# 每一步都是 Tensor 運算
z = x @ w + b                    # 線性變換
a = torch.relu(z)                # 激活函數
# a 仍然是 Tensor,傳給下一層

1.6 梯度計算(Backward Pass)

Autograd 用 Tensor 記錄梯度 。

x = torch.tensor(2.0, requires_grad=True)
y = x ** 2
y.backward()  # 計算 dy/dx
print(x.grad)  # tensor(4.) ← 梯度也存在 Tensor 中!

1.7 📚 常用 API 速查表

類別API說明示例
創建torch.tensor()通用創建x = torch.tensor([1,2,3])
torch.randn()隨機正態分布x = torch.randn(2,3)
torch.zeros()全零張量x = torch.zeros(4,4)
轉換.numpy()→ NumPy 數組arr = x.numpy()
torch.from_numpy()← NumPy 數組x = torch.from_numpy(arr)
.to('cuda')→ GPUx_gpu = x.to('cuda')
運算+,-,*,/基礎運算z = x + y
torch.matmul()矩陣乘法z = torch.matmul(x,y)
x.view()形狀變換x_2d = x.view(2,3)
自動求導.requires_grad_()開啟梯度追蹤x.requires_grad_()
.detach()剝離梯度計算x_no_grad = x.detach()

1.8 💡 Tensor 演示

import torch  # 1. 創建張量(開啟梯度追蹤)  
x = torch.tensor([1.0, 2.0, 3.0], requires_grad=True)  
print(f"初始張量: {x} | 是否追蹤梯度: {x.requires_grad}")  # 2. 張量運算(自動構建計算圖)  
y = x * 2 + 3  
z = y.mean()  
print(f"中間結果 y: {y} | 最終結果 z: {z}")  # 3. 自動求導(反向傳播)  
z.backward()  # 計算 dz/dxprint(f"梯度 dz/dx: {x.grad}")  # 輸出: [0.6667, 0.6667, 0.6667]  # 4. GPU 加速演示  
if torch.cuda.is_available():  x_gpu = x.to('cuda')  # 一鍵遷移到GPU  print(f"GPU張量: {x_gpu} | 位于設備: {x_gpu.device}")

2 Module

讓我們思考一個問題,我們要怎么定義一個神經網絡的“結構”和“行為”呢?

通過 nn.Module,它是PyTorch中所有神經網絡模塊的基類。你可以把它想象成一個可以“思考”的容器,它不僅存儲網絡的參數(如權重和偏置),還定義了數據應該如何流動(前向傳播)。

本質:所有神經網絡層的基類,管理參數 + 定義計算流程
核心forward() 方法定義數據流動邏輯

2.1 簡介

在PyTorch中,torch.nn.Module 是構建神經網絡的核心抽象。無論是簡單的線性層 nn.Linear,還是復雜的ResNet模型,它們都是 nn.Module 的子類。通過繼承 nn.Module,我們可以輕松地定義自己的神經網絡。

經過本節的學習,你將收獲:

  • nn.Module 的簡介
  • 如何使用 nn.Sequential 快速構建模型
  • 如何自定義 nn.Module 子類來創建復雜模型
  • nn.Module 的核心操作(參數管理、設備遷移)

2.2 創建Module

在接下來的內容中,我們將介紹幾種常見的創建 Module 的方法。

  • 使用 nn.Sequential 構建模型
    nn.Sequential 是一個有序的容器,它將傳入的模塊按順序組合起來。對于不需要復雜邏輯的“直筒型”網絡,這是最簡單的方法。

    import torch.nn as nn# 定義一個簡單的多層感知機 (MLP)
    model = nn.Sequential(nn.Flatten(),                    # 將圖像展平成一維向量nn.Linear(28*28, 128),           # 全連接層 (輸入784 -> 輸出128)nn.ReLU(),                       # 激活函數nn.Linear(128, 10),              # 輸出層 (輸入128 -> 輸出10類)nn.Softmax(dim=1)                # 輸出概率分布
    )
    print(model)
    
    Sequential((0): Flatten(start_dim=1, end_dim=-1)(1): Linear(in_features=784, out_features=128, bias=True)(2): ReLU()(3): Linear(in_features=128, out_features=10, bias=True)(4): Softmax(dim=1)
    )
    
  • 自定義 nn.Module 子類
    對于更復雜的網絡結構(如包含分支、殘差連接等),我們需要創建自己的類,繼承 nn.Module

    import torch.nn as nnclass SimpleMLP(nn.Module):def __init__(self):super().__init__()# 在 __init__ 中定義網絡層self.flatten = nn.Flatten()self.fc1 = nn.Linear(28*28, 128)self.relu = nn.ReLU()self.fc2 = nn.Linear(128, 10)def forward(self, x):# 在 forward 中定義數據流動的邏輯x = self.flatten(x)x = self.fc1(x)x = self.relu(x)x = self.fc2(x)return x# 實例化模型
    model = SimpleMLP()
    print(model)
    
    SimpleMLP((flatten): Flatten(start_dim=1, end_dim=-1)(fc1): Linear(in_features=784, out_features=128, bias=True)(relu): ReLU()(fc2): Linear(in_features=128, out_features=10, bias=True)
    )
    

一個標準的 nn.Module 子類有兩個必須理解的方法。

  1. __init__ 方法:
    初始化網絡層,并將它們作為類的屬性,在這里定義參數。
  2. forward 方法:
    接收輸入 x(一個Tensor),然后執行一系列計算并返回輸出(也是一個Tensor)。
    不需要手動調用 forward,執行model實例是,PyTorch 會自動調用它的forward方法。

2.3 Module 的核心操作

在接下來的內容中,我們將介紹 Module 的幾個關鍵操作。

  • 參數管理
    nn.Module 會自動將 nn.Parameter 或任何 nn.Module 子類的實例注冊為模型的參數。我們可以使用以下方法訪問它們。

    # 獲取模型的所有參數
    for param in model.parameters():print(param.shape)# 獲取模型的命名參數
    for name, param in model.named_parameters():print(f"{name}: {param.shape}")
    
    flatten._parameters: {} # Flatten層無參數
    fc1.weight: torch.Size([128, 784])
    fc1.bias: torch.Size([128])
    fc2.weight: torch.Size([10, 128])
    fc2.bias: torch.Size([10])
    
  • 設備遷移
    為了利用GPU加速,我們可以使用 .to(device) 方法將整個模型(包括其所有參數和子模塊)遷移到指定設備。

    device = 'cuda' if torch.cuda.is_available() else 'cpu'
    model = model.to(device)  # 一鍵遷移到GPU
    print(f"模型設備: {next(model.parameters()).device}")
    
  • 狀態保存與加載
    我們可以使用 state_dict() 來獲取模型參數的字典,這非常適合保存和加載訓練好的模型。

    # 保存模型
    torch.save(model.state_dict(), 'simple_mlp.pth')# 加載模型 (需要先創建相同結構的模型)
    new_model = SimpleMLP()
    new_model.load_state_dict(torch.load('simple_mlp.pth'))
    new_model.eval() # 切換到評估模式
    
  • 訓練/評估模式切換
    一些層(如 Dropout, BatchNorm)在訓練和評估時的行為不同。我們可以使用 model.train()model.eval() 來切換模式。

    model.train()  # 啟用Dropout等訓練專用操作
    # ... 訓練代碼 ...model.eval()   # 禁用Dropout,使用BatchNorm的統計值
    # ... 推理代碼 ...
    with torch.no_grad():  # 通常與 no_grad() 一起使用output = model(input_tensor)
    

3 Autograd

讓我們思考一個問題,我們要怎么讓模型“學會”調整自己的參數呢?

通過 autograd,它是PyTorch的自動微分引擎。它會默默地記錄我們對張量進行的所有操作,構建一個“計算圖”,然后在需要時自動計算梯度,使得反向傳播變得極其簡單。

3.1 簡介

在深度學習中,我們通過反向傳播算法來更新模型參數。手動計算梯度不僅繁瑣而且容易出錯。PyTorch的 autograd 包可以自動完成這一過程。

autograd 的核心是 torch.Tensortorch.Function
Tensorrequires_grad 屬性為 True 時,autograd 會追蹤所有作用于該張量的操作
。一旦計算完成,調用 .backward() 方法,autograd 就會自動計算所有梯度,并將它們累積到 .grad 屬性中。

經過本節的學習,你將收獲:

  • autograd 的工作原理
  • 如何使用 requires_grad 控制梯度追蹤
  • 如何執行反向傳播并查看梯度
  • 如何使用 torch.no_grad() 上下文管理器

3.2 梯度追蹤

  • 開啟梯度追蹤
    通過設置 requires_grad=True,我們可以告訴 autograd 需要追蹤對這個張量的所有操作。

    import torch# 方法1: 創建時指定
    x = torch.tensor([1., 2., 3.], requires_grad=True)
    print(f"x.requires_grad: {x.requires_grad}")# 方法2: 對已有張量啟用
    y = torch.tensor([4., 5., 6.])
    y.requires_grad_(True) # 注意是方法,帶下劃線
    print(f"y.requires_grad: {y.requires_grad}")
    
  • 構建計算圖
    一旦開啟了梯度追蹤,后續的運算都會被記錄下來。

    z = x * y + 2
    print(f"z.grad_fn: {z.grad_fn}")  # <AddBackward0 object>
    print(f"z's creator: {z.grad_fn}") 
    

3.3 反向傳播

  • 執行反向傳播
    調用 .backward() 方法來觸發反向傳播。如果 loss 是一個標量(0維張量),可以直接調用 loss.backward()

    loss = z.sum() # loss 是一個標量
    print(f"loss: {loss}") # tensor(27., grad_fn=<SumBackward0>)loss.backward() # 計算梯度
    print(f"dx/dloss: {x.grad}") # tensor([4., 5., 6.])
    print(f"dy/dloss: {y.grad}") # tensor([1., 2., 3.])
    

    注意.backward()累積梯度。在下一次迭代前,務必使用 optimizer.zero_grad() 或手動清零 x.grad.zero_()

  • 非標量輸出
    如果要對非標量張量調用 .backward(),需要傳入一個 gradient 參數(形狀與該張量相同),作為外部梯度。

    v = torch.tensor([0.1, 1.0, 0.0001], dtype=torch.float)
    z.backward(gradient=v) # 這里會累加梯度
    # x.grad 會增加 v * y 的值
    

3.4 禁用梯度計算

在模型推理(inference)或某些不需要梯度的計算中,我們可以使用 torch.no_grad() 上下文管理器來臨時禁用梯度計算,這可以節省內存并加快計算速度。

print(f"Before no_grad, x.requires_grad: {x.requires_grad}")with torch.no_grad():a = x * 2print(f"Inside no_grad, a.requires_grad: {a.requires_grad}") # Falseprint(f"After no_grad, x.requires_grad: {x.requires_grad}") # 仍然是 True# 另一種方式:使用 .detach()
b = x.detach() * 3
print(f"b.requires_grad: {b.requires_grad}") # False

4 📌 三件套關系圖解

  ┌─────────────┐      ┌───────────┐      ┌─────────────┐│             │      │           │      │             ││   Tensor    │─────?│  Module   │─────?│   Autograd  ││ (數據載體)  │?─────│ (計算邏輯)│?─────│ (梯度引擎)  │└─────────────┘      └───────────┘      └─────────────┘▲                      │                   ││                      ▼                   ▼┌─────┴──────┐        ┌─────────────┐     ┌─────────────┐│ 數據加載   │        │ 模型定義    │     │ 反向傳播    ││ DataLoader │        │ forward()   │     │ loss.backward() └────────────┘        └─────────────┘     └─────────────┘

? 關鍵口訣
“Tensor 存數據,Module 定流程,Autograd 算梯度,三件套合訓練成”

5 🌟 三件套協同工作流程(完整訓練示例)

資料:https://zh-v2.d2l.ai/chapter_multilayer-perceptrons/mlp-scratch.html

5.1 Demo:三件套簡單串聯

import torch
import torch.nn as nn
import torch.optim as optim# 1. Tensor:準備數據
x = torch.randn(64, 1, 28, 28)  # 64張28x28灰度圖
y_true = torch.randint(0, 10, (64,))  # 10分類標簽# 2. Module:創建模型
model = nn.Sequential(nn.Flatten(),nn.Linear(28*28, 128),nn.ReLU(),nn.Linear(128, 10)
)# 3. Autograd:訓練循環
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=0.01)# 前向傳播 → 計算損失 → 反向傳播 → 更新參數
optimizer.zero_grad()         # 清零梯度(Autograd)
logits = model(x)             # 前向傳播(Module)
loss = criterion(logits, y_true)  # 計算損失(Tensor)
loss.backward()               # 反向傳播(Autograd)
optimizer.step()              # 更新參數(Tensor)print(f"訓練完成!損失值: {loss.item():.4f}")

5.2 構建一個簡單線性回歸模型 y=wx+b

我們將構建一個簡單的線性回歸模型 y = wx + b,并模擬一個真實的訓練過程。

  1. 創建一個簡單的線性模型(nn.Module)。
  2. 使用真實數據和模型預測來手動計算損失(均方誤差)。
  3. 調用 loss.backward() 觸發自動微分。
  4. 觀察模型參數(權重 w 和偏置 b)的 .grad 屬性,看到梯度的產生。
import torch
import torch.nn as nn# ----------------------------------------
# 第一步:準備虛擬數據 (y = 3x + 2)
# ----------------------------------------
# 我們假設真實的世界關系是 y = 3x + 2
# 我們生成一些帶點“噪聲”的數據來模擬真實情況# 創建輸入 x (形狀: [5, 1])
x = torch.tensor([[1.0], [2.0], [3.0], [4.0], [5.0]])  # 5個樣本
print("輸入 x:")
print(x)# 創建真實標簽 y_true (形狀: [5, 1])
true_w = 3.0
true_b = 2.0
y_true = true_w * x + true_b + torch.randn_like(x) * 0.1  # 加點小噪聲
print("\n真實標簽 y_true (y ≈ 3x + 2):")
print(y_true)# ----------------------------------------
# 第二步:定義模型 (nn.Module)
# ----------------------------------------
# 我們創建一個非常簡單的模型,它就是一個線性層class SimpleLinear(nn.Module):def __init__(self):super().__init__()# nn.Linear(in_features, out_features) -> y = Wx + b# 因為我們只有一個輸入和一個輸出,所以是 Linear(1, 1)self.linear = nn.Linear(1, 1)def forward(self, x):return self.linear(x)# 實例化模型
model = SimpleLinear()
print("\n模型結構:")
print(model)# 打印初始參數 (模型剛開始是“瞎猜”的)
print("\n訓練前的模型參數:")
print(f"權重 w: {model.linear.weight.item():.3f}")  # .item() 取出單個數值
print(f"偏置 b: {model.linear.bias.item():.3f}")
# 你會發現初始的 w 和 b 是隨機的,和 3.0, 2.0 差很遠# ----------------------------------------
# 第三步:前向傳播 (Forward Pass)
# ----------------------------------------
# 讓模型對輸入 x 進行預測model.train()  # 確保模型在訓練模式
y_pred = model(x)  # 調用 forward 方法print("\n模型預測 y_pred (訓練前):")
print(y_pred)# ----------------------------------------
# 第四步:手動計算損失 (Loss)
# ----------------------------------------
# 我們使用最簡單的均方誤差 (MSE) 損失
# loss = (1/N) * Σ (y_true - y_pred)2# 手動計算損失
loss = torch.mean((y_true - y_pred) ** 2)print(f"\n訓練前的損失 (MSE): {loss.item():.4f}")# ----------------------------------------
# 第五步:反向傳播 (Backward Pass) 和 觀察梯度
# ----------------------------------------
# 這是最關鍵的一步!
# 在反向傳播之前,必須先將梯度清零,否則梯度會累積
model.zero_grad()  # 等價于 optimizer.zero_grad()# 執行反向傳播
loss.backward()# 🔥 現在,我們來“親眼”看看梯度產生了!
print("\n" + "="*50)
print("調用 loss.backward() 后,模型參數的梯度:")
print("="*50)# 查看權重 w 的梯度
w_grad = model.linear.weight.grad
print(f"權重 w 的梯度 (.grad): {w_grad.item():.4f}")
# 這個梯度告訴我們:為了減小損失,w 應該增加還是減少?# 查看偏置 b 的梯度
b_grad = model.linear.bias.grad
print(f"偏置 b 的梯度 (.grad): {b_grad.item():.4f}")
# 同理,這個梯度指導 b 如何更新# ----------------------------------------
# 第六步:(可選)更新參數
# ----------------------------------------
# 雖然練習目標不包括更新,但我們可以手動模擬一下
# 這就是優化器(如SGD)做的事情:參數 = 參數 - 學習率 * 梯度learning_rate = 0.01# 手動更新權重
with torch.no_grad():  # 更新參數時不需要記錄梯度model.linear.weight -= learning_rate * w_gradmodel.linear.bias -= learning_rate * b_gradprint("\n" + "="*50)
print("一次梯度下降更新后的模型參數:")
print("="*50)
print(f"更新后的權重 w: {model.linear.weight.item():.3f}")
print(f"更新后的偏置 b: {model.linear.bias.item():.3f}")
print("現在參數更接近真實的 3.0 和 2.0 了嗎?")

在這個Demo中,三大件協作如下:

          (數據)↓┌─────────────┐│    Tensor   │ ← 存放 x, y, w, b 這些數字└─────────────┘↓ (輸入)┌─────────────┐│   Module    │ ← 定義 y = w*x + b 這個計算公式└─────────────┘↓ (輸出預測 y_pred)┌─────────────┐│  計算損失    │ ← 比較 y_pred 和 真實 y 的差距└─────────────┘↓ (標量 loss)┌─────────────┐│  Autograd   │ ← 調用 loss.backward(),自動算出 w 和 b 的梯度└─────────────┘↓ (梯度 dw, db)┌─────────────┐│  優化器     │ ← 用梯度更新 w 和 b,讓它們更接近真實值└─────────────┘

5.3 Demo:搭建一個簡單的多層感知機

Transformer模型中的“前饋網絡(Feed-Forward Network)”部分,其本質就是一個多層感知機(MLP)。
讓我們仿照教程,搭建搭建一個簡單的多層感知機:手寫數字分類MLP。

import torch  
import torch.nn.functional as F  
from torchvision import datasets, transforms  
from torch.utils.data import DataLoader  
import numpy as np  # =============================================================================  
# 1. Tensor:數據的容器  
# =============================================================================  
"""  
Tensor 是 PyTorch 中存儲和操作數據的核心結構。  
它不僅是多維數組,還能追蹤梯度,是深度學習的“通用貨幣”。  
"""  # 演示:Tensor 的基本用途  
print("=== 1. Tensor 演示 ===")  # 創建一個需要梯度追蹤的張量  
x = torch.tensor([1.0, 2.0, 3.0], requires_grad=True)  
print(f"初始張量: {x} | 追蹤梯度: {x.requires_grad}")  # 執行運算(構建計算圖)  
y = x * 2 + 3  
z = y.mean()  
print(f"中間結果 y: {y} | 最終標量 z: {z}")  # 反向傳播  
z.backward()  
print(f"梯度 dz/dx: {x.grad}")  # 應為 [2/3, 2/3, 2/3]  
# GPU 加速(如果可用)  
if torch.cuda.is_available():  x_gpu = x.to('cuda')  print(f"GPU張量: {x_gpu} | 設備: {x_gpu.device}")  
else:  print("GPU不可用,使用CPU")  # =============================================================================  
# 2. Module:計算邏輯的藍圖(手動實現)  
# =============================================================================  
"""  
我們不使用 nn.Module 和 nn.Linear,  
而是手動創建權重和偏置,并定義前向傳播函數。  
"""  print("\n=== 2. 手動實現 MLP(無 nn.Module / nn.Linear)===")  # 超參數  
input_size = 784   # 28x28 圖像展平  
hidden_size = 128  # 隱藏層大小
output_size = 10   # MNIST 10 類  
learning_rate = 0.01  # 學習率
num_epochs = 3  # 訓練輪數# 手動初始化參數(替代 nn.Linear)  
torch.manual_seed(42)  
W1 = torch.randn(input_size, hidden_size) * 0.01  
b1 = torch.zeros(hidden_size)  
W2 = torch.randn(hidden_size, output_size) * 0.01  
b2 = torch.zeros(output_size)  # 開啟梯度追蹤  
W1.requires_grad_(True)  
b1.requires_grad_(True)  
W2.requires_grad_(True)  
b2.requires_grad_(True)  print(f"W1: {W1.shape}, b1: {b1.shape}")  
print(f"W2: {W2.shape}, b2: {b2.shape}")  # 定義前向傳播函數(替代 forward)  
def forward(x):  """  手動實現前向傳播  :param x: 輸入張量 (B, 784)    :return: logits (B, 10)    """    z1 = x @ W1 + b1      # 第一層線性變換  a1 = F.relu(z1)       # 激活函數  z2 = a1 @ W2 + b2     # 第二層線性變換  return z2  # =============================================================================  
# 3. Autograd:自動微分引擎  
# =============================================================================  
"""  
Autograd 會自動追蹤所有操作,調用 loss.backward() 即可計算梯度。  
我們手動實現訓練循環,替代 optimizer.step() 和 optimizer.zero_grad()"""  print("\n=== 3. 數據加載與訓練 ===")  # 數據預處理  
transform = transforms.ToTensor()  # 加載 MNIST 數據集  
train_dataset = datasets.MNIST(root='./data', train=True, download=True, transform=transform)  
test_dataset = datasets.MNIST(root='./data', train=False, transform=transform)  train_loader = DataLoader(train_dataset, batch_size=64, shuffle=True)  
test_loader = DataLoader(test_dataset, batch_size=1000, shuffle=False)  print(f"訓練集大小: {len(train_dataset)}")  
print(f"測試集大小: {len(test_dataset)}")  # 訓練循環  
train_losses = []  for epoch in range(num_epochs):  epoch_loss = 0.0  count = 0  for x_batch, y_batch in train_loader:  # 展平圖像: (B, 1, 28, 28) -> (B, 784)  x_batch = x_batch.view(x_batch.size(0), -1)  # 前向傳播  logits = forward(x_batch)  loss = F.cross_entropy(logits, y_batch)  # 使用函數式 API  # 反向傳播  loss.backward()  # 手動更新參數(替代 optimizer.step())  with torch.no_grad():  W1 -= learning_rate * W1.grad  b1 -= learning_rate * b1.grad  W2 -= learning_rate * W2.grad  b2 -= learning_rate * b2.grad  # 清零梯度(替代 optimizer.zero_grad())  W1.grad.zero_()  b1.grad.zero_()  W2.grad.zero_()  b2.grad.zero_()  epoch_loss += loss.item()  count += 1  avg_loss = epoch_loss / count  train_losses.append(avg_loss)  print(f"Epoch [{epoch+1}/{num_epochs}], Loss: {avg_loss:.4f}")  # =============================================================================  
# 4. 模型評估  
# =============================================================================  
print("\n=== 4. 模型評估 ===")  correct = 0  
total = 0  
with torch.no_grad():  # 推理時關閉梯度  for x_batch, y_batch in test_loader:  x_batch = x_batch.view(x_batch.size(0), -1)  logits = forward(x_batch)  _, predicted = torch.max(logits, 1)  total += y_batch.size(0)  correct += (predicted == y_batch).sum().item()  accuracy = 100 * correct / total  
print(f"測試準確率: {accuracy:.2f}%")  # =============================================================================  
# 5. Demo:線性回歸(觀察梯度生成過程)  
# =============================================================================  
print("\n=== 5. 線性回歸 Demo:觀察梯度如何生成 ===")  # 生成虛擬數據:y = 3x + 2 + noise  
x_reg = torch.tensor([[1.0], [2.0], [3.0], [4.0], [5.0]])  
true_w, true_b = 3.0, 2.0  
y_true = true_w * x_reg + true_b + torch.randn_like(x_reg) * 0.1  # 初始化參數  
w = torch.randn(1, 1, requires_grad=True)  
b = torch.zeros(1, requires_grad=True)  print(f"真實參數: w={true_w}, b={true_b}")  
print(f"初始參數: w={w.item():.3f}, b={b.item():.3f}")  # 前向傳播  
y_pred = x_reg @ w + b  
loss = F.mse_loss(y_pred, y_true)  # 反向傳播  
loss.backward()  print(f"\n調用 loss.backward() 后:")  
print(f"權重 w 的梯度: {w.grad.item():.4f}")  
print(f"偏置 b 的梯度: {b.grad.item():.4f}")  print("\n梯度方向正確:w 的梯度為正,說明當前 w 偏小,應增大")  # =============================================================================  
# 6. 總結口訣  
# =============================================================================  
print("\n" + "="*60)  
print("🎯 PyTorch 三件套核心口訣")  
print("="*60)  
print("Tensor 存數據,Module 定流程,Autograd 算梯度")  
print("三件套合訓練成,手動實現才真懂!")  
print("="*60)

概念補充:

  • 超參數:一般指一些模型的配置參數,想當于模型的學習規則。
超參數說明為什么重要
學習率 (Learning Rate,?lr)每次更新參數時的“步長”太大:學得快但可能錯過最優解
太小:學得慢,可能卡住
批次大小 (Batch Size)一次訓練使用的樣本數量太大:內存壓力大,泛化可能差
太小:訓練不穩定
訓練輪數 (Epochs)整個數據集被完整遍歷的次數太少:欠擬合
太多:過擬合(死記硬背)
隱藏層大小 (Hidden Size)神經網絡中隱藏層的神經元數量決定了模型的“容量”
太大:容易過擬合
太小:無法學習復雜模式
網絡層數 (Number of Layers)有多少個隱藏層層數多 → “深度網絡”,能學更復雜特征,但也更難訓練
優化器類型使用 SGD、Adam 還是 RMSprop不同優化器收斂速度和穩定性不同
正則化參數如 Dropout 概率、L2 權重衰減用于防止過擬合

刻意練習

Q:如何給MLP增加一個隱藏層?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/94685.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/94685.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/94685.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

python源碼是如何運行起來的

為什么要了解底層原理 寫出高質量代碼 問題定位 滿足好奇心 機械通感 開始 當我們編寫并運行一行 print(Hello, World!) 時&#xff0c;背后究竟發生了什么&#xff1f;Python 代碼是如何從我們可讀的文本&#xff0c;變成計算機可以執行的指令的呢&#xff1f; 很多人將…

MacOS Docker 安裝指南

MacOS Docker 安裝指南 引言 Docker 是一個開源的應用容器引擎,它允許開發者打包他們的應用以及應用的依賴包到一個可移植的容器中,然后發布到任何流行的 Linux 機器上,也可以實現虛擬化。容器是完全使用沙箱機制,相互之間不會有任何接口(類似 iPhone 的 app)。Docker …

Cisco 3750X交換機更新到IOS 15.2后無法啟動 提示:Boot process failed...

背景及故障現象 一臺新購入的二手Cisco 3750X-48P&#xff0c;原機自帶IOS軟件版本為12.x&#xff0c;可以正常工作。 但將IOS版本升級到15.2之后&#xff0c;在啟動過程中卡住。 第一次加載IOS軟件時是正常的&#xff0c;提示&#xff1a; Loading "flash:/c3750e-uni…

Redis Redis 常見數據類型

Redis 提供了 5 種數據結構&#xff0c;理解每種數據結構的特點對于 Redis 開發運維非常重要&#xff0c;同時掌握每種數據結構的常見命令&#xff0c;會在使用 Redis 的時候做到游刃有余。 一、預備知識 官方文檔&#xff1a;Commands | Docs (redis.io) 1、最核心的兩個命令…

金融風控實戰:Spring Boot + LightGBM 貸款預測模型服務化(超詳細版)

金融風控實戰&#xff1a;Spring Boot LightGBM 貸款預測模型服務化&#xff08;超詳細版&#xff09;一、整體架構設計二、模型訓練與優化1. 特征工程&#xff08;Python&#xff09;2. 模型評估與優化三、Spring Boot 服務實現1. 項目結構2. ONNX 模型服務3. 特征工程服務4.…

前端學習 7:EDA 工具

目錄 EDA 工具 Design Ware Synopsys CoreTools 套件 VCS verdi Design Compiler EDA 工具 常用的EDA工具主要來自三家公司&#xff1a;Synopsys、Cadence和Mentor&#xff08;已被Siemens收購&#xff09;。EDA&#xff0c;全稱電子設計自動化&#xff08;Electronics …

windows有一個企業微信安裝包,腳本執行并安裝到d盤。

以下是將本地已有的企業微信安裝包安裝到D盤的完整PowerShell腳本&#xff0c;包含詳細的錯誤處理和進度反饋&#xff1a; <# .SYNOPSIS使用本地企業微信安裝包安裝到D盤 .DESCRIPTION自動檢測本地安裝包&#xff0c;靜默安裝到指定目錄支持.exe和.msi格式安裝包 #># 強制…

[LVGL] 布局系統 lv_flex, lv_grid | 輸入設備 lv_indev | union

第五章&#xff1a;布局系統&#xff08;lv_flex, lv_grid&#xff09; 歡迎回來&#xff01; 在第四章&#xff1a;樣式&#xff08;lv_style&#xff09;中&#xff0c;我們掌握了如何通過色彩、字體和圓角等特性美化部件。當界面元素具備視覺吸引力后&#xff0c;如何優雅…

Linux中的mkdir命令

基本語法mkdir 命令的基本語法如下&#xff1a;mkdir [選項] 目錄名創建單個目錄要創建一個新目錄&#xff0c;只需在 mkdir 后跟上目錄名稱。例如&#xff1a;mkdir new_folder這會在當前工作目錄下創建一個名為 new_folder 的目錄。創建多個目錄可以一次性創建多個目錄&#…

基于大數據的美食視頻播放數據可視化系統 Python+Django+Vue.js

本文項目編號 25003 &#xff0c;文末自助獲取源碼 \color{red}{25003&#xff0c;文末自助獲取源碼} 25003&#xff0c;文末自助獲取源碼 目錄 一、系統介紹二、系統錄屏三、啟動教程四、功能截圖五、文案資料5.1 選題背景5.2 國內外研究現狀 六、核心代碼6.1 查詢數據6.2 新…

微信小程序精品項目-基于springboot+Android的計算機精品課程學習系統(源碼+LW+部署文檔+全bao+遠程調試+代碼講解等)

博主介紹&#xff1a;??碼農一枚 &#xff0c;專注于大學生項目實戰開發、講解和畢業&#x1f6a2;文撰寫修改等。全棧領域優質創作者&#xff0c;博客之星、掘金/華為云/阿里云/InfoQ等平臺優質作者、專注于Java、小程序技術領域和畢業項目實戰 ??技術范圍&#xff1a;&am…

(五)系統可靠性設計

2024年博主考軟考高級系統架構師沒通過&#xff0c;于是決定集中精力認真學習系統架構的每一個環節&#xff0c;并在2025年軟考中取得了不錯的成績&#xff0c;雖然做信息安全的考架構師很難&#xff0c;但找對方法&#xff0c;問題就不大&#xff01; 本文主要是博主在學習過程…

Shuffle SOAR使用學習經驗

Shuffle SOAR 1. 基礎操作與配置1.1 環境搭建與系統要求1.1.1 硬件與操作系統要求Shuffle SOAR 平臺作為一款開源的安全編排、自動化與響應&#xff08;SOAR&#xff09;工具&#xff0c;其部署方式靈活&#xff0c;支持云端和自托管兩種模式。對于自托管部署&#xff0c;官方推…

騰訊云 EdgeOne 產品分析與免費套餐體驗指南

本文圍繞騰訊云 EdgeOne 展開&#xff0c;全方位介紹它的核心能力、免費套餐內容&#xff0c;以及如何快速上手、監控和排查常見問題&#xff0c;幫助個人開發者和中小企業在不產生額外成本的前提下體驗高性能的邊緣加速與安全防護。 一、產品概述 EdgeOne 定位 一體化云服務平…

npm ERR! Unsupported URL Type “workspace:“: workspace:./lib

如下 npm install npm ERR! code EUNSUPPORTEDPROTOCOL npm ERR! Unsupported URL Type "workspace:": workspace:./libnpm ERR! A complete log of this run can be found in: D:\IDEA\nodejs\node_cache\_logs\2025-08-06T08_21_32_592Z-debug-0.log原因及解決 pac…

微積分: 變化與累積

微積分,這門研究變化與累積的數學分支,其核心思想竟與東方哲學中"易"的概念不謀而合。《易經》有云:“易有太極,是生兩儀”,而微積分正是通過"微分"與"積分"這對辯證統一的操作,揭示了世間萬物變化與永恒的奧秘。 #mermaid-svg-UjO6qqMm0h…

web-vue工作流程

接續bmcweb流程。 當登錄openbmc web頁面后,瀏覽器會根據index.html中的js文件中的routes信息,自動獲取信息,比如當前的網絡設置信息、Datetime時區時間信息等。 以獲取網絡配置信息為例: 瀏覽器從app.js獲取到settins->network的route:”/settings/network”,加載對應…

全球化2.0 | 泰國IT服務商攜手云軸科技ZStack重塑云租賃新生態

在全球數字化轉型不斷加速的今天&#xff0c;泰國企業對于高質量云服務的需求日益旺盛。作為深耕本地市場逾二十年的行業領先IT服務商&#xff0c;泰國IT服務商不僅覆蓋了IT系統、軟件、硬件及網絡等多個領域&#xff0c;還持續引領當地技術服務創新。近期&#xff0c;該泰國IT…

一文搞懂Hive臨時表操作秘籍

Hive 臨時表&#xff1a;數據處理的得力助手 在大數據處理的廣闊領域中&#xff0c;Hive 憑借其強大的數據倉庫功能&#xff0c;成為了眾多數據分析師和開發者的得力工具。Hive 提供了類似 SQL 的查詢語言 HiveQL&#xff0c;讓我們能夠方便地對存儲在 Hadoop 分布式文件系統&a…

瞬態吸收光譜儀的基本原理

目錄 1. 基態與激發態 2. 時間上的動力學信息 3. pump-probe探測技術 4. 時間延遲和同一光源 5. 延時線和OPA 6. 差分信號 7. 斬波器 原視頻鏈接&#xff1a;瞬態吸收光譜儀的基本原理_嗶哩嗶哩_bilibili 1. 基態與激發態 當光照射在物質上時&#xff0c;組成物質的微觀…