文章目錄
- 1 損失函數
- 1.1 L1Loss
- 1.2 MSELoss
- 1.3 CrossEntropyLoss
- 2 反向傳播
本文環境:
- Pycharm 2025.1
- Python 3.12.9
- Pytorch 2.6.0+cu124
1 損失函數
? 損失函數 (loss function) 是將隨機事件或其有關隨機變量的取值映射為非負實數以表示該隨機事件的"風險"或"損失"的函數。在機器學習中,損失函數通常作為學習準則與優化問題相聯系,通過最小化損失函數來求解和評估模型。
? 損失函數主要分為兩類:
- 回歸問題:常用 L1 損失函數 (MAE) 和 L2 損失函數 (MSE)。
- 分類問題:常用 0-1 損失函數及其代理損失 (如交叉熵損失、鉸鏈損失等)。
1.1 L1Loss

? L1Loss 計算輸入 ( x x x) 和目標 ( y y y) 之間的平均絕對誤差 (MAE)。數學公式如下:
l n = ∣ x n ? y n ∣ l_n=|x_n-y_n| ln?=∣xn??yn?∣
參數 | 類型 | 說明 |
---|---|---|
size_average | (bool, 可選) | 已棄用(請使用reduction)。默認情況下,損失會對批中每個損失元素求平均。注意對于某些損失,每個樣本可能有多個元素。如果設為False,則對每個minibatch的損失求和。當reduce為False時被忽略。默認: True |
reduce | (bool, 可選) | 已棄用(請使用reduction)。默認情況下,根據size_average對每個minibatch的觀測值求平均或求和。當reduce為False時,返回每個批元素的損失并忽略size_average。默認: True |
reduction | (str, 可選) | 指定應用于輸出的縮減方式: ‘none’|‘mean’|‘sum’。 - ‘none’: 不應用縮減, - ‘mean’: 輸出總和除以元素數量, - ‘sum’: 輸出求和。 注意: size_average和reduce正在被棄用,目前指定這兩個參數中的任何一個都會覆蓋reduction。默認: ‘mean’ |
? 依據reduction
的不同,輸出結果也不同:
? ( x , y ) = { 1 N ∑ n = 1 N l n , if?reduction = ’mean’ . ∑ n = 1 N l n , if?reduction = ’sum’ . \ell(x,y)= \begin{cases} \displaystyle\frac{1}{N}\sum_{n=1}^N l_n,&\text{if reduction}=\text{'mean'}.\\\\ \displaystyle\sum_{n=1}^N l_n,&\text{ if reduction}=\text{'sum'}. \end{cases} ?(x,y)=? ? ??N1?n=1∑N?ln?,n=1∑N?ln?,?if?reduction=’mean’.?if?reduction=’sum’.?
? 其中, N N N 為每個批次的數量。
- 輸入: (?), 其中 ? 表示任意維數。
- 目標: (?), 與輸入形狀相同。
- 輸出: 標量。如果reduction為’none’,則形狀與輸入相同(?)。
import torch
from torch import nninputs = torch.tensor([1., 2, 3])
targets = torch.tensor([1, 2, 5])loss = nn.L1Loss()
result = loss(inputs, targets) # 計算平均絕對誤差
print(result) # tensor(0.6667) 計算:(0 + 0 + 2)/3 = 0.6667
特點:
- 對異常值不敏感,具有較好的魯棒性。
- 梯度恒定(±1),在接近最優解時可能導致震蕩。
- 適用于對異常值敏感的場景。
1.2 MSELoss

? MSELoss 計算輸入 ( x x x) 和目標 ( y y y) 之間的均方誤差 (MSE)。
l n = ( x n ? y n ) 2 l_n=(x_n-y_n)^2 ln?=(xn??yn?)2
參數 | 類型 | 說明 |
---|---|---|
size_average | (bool, 可選) | 已棄用(請使用reduction)。默認對批中每個損失元素求平均。設為False則對每個minibatch的損失求和。當reduce為False時被忽略。默認: True |
reduce | (bool, 可選) | 已棄用(請使用reduction)。默認根據size_average對觀測值求平均或求和。當reduce為False時,返回每個批元素的損失。默認: True |
reduction | (str, 可選) | 指定輸出縮減方式: ‘none’|‘mean’|‘sum’。 - ‘none’: 不縮減, - ‘mean’: 輸出總和除以元素數量, - ‘sum’: 輸出求和。 注意: size_average和reduce將被棄用。默認: ‘mean’ |
? 依據reduction
的不同,輸出結果也不同:
? ( x , y ) = { 1 N ∑ n = 1 N l n , if?reduction = ’mean’ . ∑ n = 1 N l n , if?reduction = ’sum’ . \ell(x,y)= \begin{cases} \displaystyle\frac{1}{N}\sum_{n=1}^N l_n,&\text{if reduction}=\text{'mean'}.\\\\ \displaystyle\sum_{n=1}^N l_n,&\text{ if reduction}=\text{'sum'}. \end{cases} ?(x,y)=? ? ??N1?n=1∑N?ln?,n=1∑N?ln?,?if?reduction=’mean’.?if?reduction=’sum’.?
? 其中, N N N 為每個批次的數量。
- 輸入: (?), 其中 ? 表示任意維數
- 目標: (?), 與輸入形狀相同
- 輸出: 標量。如果reduction為’none’,則形狀與輸入相同(?)
解釋import torch
from torch import nninputs = torch.tensor([1., 2, 3])
targets = torch.tensor([1, 2, 5])loss_mse = nn.MSELoss()
result_mse = loss_mse(inputs, targets)
print(result_mse) # tensor(1.3333) 計算:(0 + 0 + 4)/3 = 1.3333
特點:
- 對較大誤差懲罰更重(平方放大效應)。
- 對異常值敏感。
- 梯度隨誤差減小而減小,收斂速度較快。
- 適用于數據質量較好的場景。
1.3 CrossEntropyLoss

l n = ? ∑ c = 1 C w c log ? exp ? ( x n , c ) ∑ i = 1 C exp ? ( x n , i ) y n , c l_n=-\sum_{c=1}^Cw_c\log\frac{\exp(x_{n,c})}{\sum_{i=1}^C\exp(x_{n,i})}y_{n,c} ln?=?c=1∑C?wc?log∑i=1C?exp(xn,i?)exp(xn,c?)?yn,c?
? 其中 w w w 為權重, C C C 為類別數。
參數 | 類型 | 說明 |
---|---|---|
weight | (Tensor, 可選) | 為每個類別分配權重的一維張量,用于處理類別不平衡問題 |
ignore_index | (int, 可選) | 指定要忽略的目標值,不參與梯度計算 |
reduction | (str, 可選) | 指定輸出縮減方式: ‘none’|‘mean’|‘sum’。默認: ‘mean’ |
label_smoothing | (float, 可選) | 標簽平滑系數,范圍[0.0,1.0]。0.0表示無平滑 |
? 依據reduction
的不同,輸出結果也不同:
? ( x , y ) = { 1 N ∑ n = 1 N l n , if?reduction = ’mean’ . ∑ n = 1 N l n , if?reduction = ’sum’ . \ell(x,y)= \begin{cases} \displaystyle\frac{1}{N}\sum_{n=1}^N l_n,&\text{if reduction}=\text{'mean'}.\\\\ \displaystyle\sum_{n=1}^N l_n,&\text{ if reduction}=\text{'sum'}. \end{cases} ?(x,y)=? ? ??N1?n=1∑N?ln?,n=1∑N?ln?,?if?reduction=’mean’.?if?reduction=’sum’.?
? 其中, N N N 為每個批次的數量。
輸入形狀:
- 無批處理: ( C ) (C) (C)。
- 批處理: ( N , C ) (N, C) (N,C) 或 ( N , C , d 1 , d 2 , . . . , d K ) , K ≥ 1 (N, C, d?, d?,...,d_K), K≥1 (N,C,d1?,d2?,...,dK?),K≥1。
目標形狀:
- 類別索引: ( ) , ( N ) (), (N) (),(N) 或 ( N , d 1 , d 2 , . . . , d K ) (N, d?, d?,...,d_K) (N,d1?,d2?,...,dK?)。
- 類別概率: 必須與輸入形狀相同。
from torch import nnx = torch.tensor([0.1, 0.2, 0.3]) # 預測值(未歸一化)
y = torch.tensor([1]) # 真實類別索引
x = x.reshape(1, -1) # 調整為(batch_size, num_classes)loss_cross = nn.CrossEntropyLoss()
result_cross = loss_cross(x, y)
print(result_cross) # tensor(1.1019)
計算過程:
- 對 x 應用 softmax 得到概率分布:[0.3006,0.3322,0.3672]。
- 取真實類別 (1) 的概率:0.3322。
- 計算負對數: ? l o g ( 0.3322 ) ≈ 1.1019 -log(0.3322)\approx1.1019 ?log(0.3322)≈1.1019。
特點:
- 結合了 Softmax 和負對數似然。
- 梯度計算高效,適合多分類問題。
- 對預測概率與真實標簽的差異敏感。
2 反向傳播
? 反向傳播(Backpropagation)是神經網絡訓練的核心算法,通過鏈式法則計算損失函數對網絡參數的梯度。關鍵步驟:
- 前向傳播:計算網絡輸出和損失值。
- 反向傳播:
- 計算損失函數對輸出的梯度。
- 逐層傳播梯度到各參數。
- 應用鏈式法則計算參數梯度。
- 參數更新:使用優化器根據梯度更新參數。
? 以 CIFAR10 網絡為例:
from collections import OrderedDictimport torch
import torchvision
from torch import nnfrom torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter
from torchvision import transforms# 加載CIFAR10數據集
dataset = torchvision.datasets.CIFAR10(root='./dataset', # 數據集存放路徑train=False, # 是否為訓練集download=True, # 是否下載數據集transform=transforms.ToTensor() # 數據預處理
)# 加載數據集
dataloader = DataLoader(dataset, batch_size=1)class MyModel(nn.Module):def __init__(self):super(MyModel, self).__init__()self.model1 = nn.Sequential(OrderedDict([('conv1', nn.Conv2d(3, 32, 5, padding=2)),('maxpool1', nn.MaxPool2d(2)),('conv2', nn.Conv2d(32, 32, 5, padding=2)),('maxpool2', nn.MaxPool2d(2)),('conv3', nn.Conv2d(32, 64, 5, padding=2)),('maxpool3', nn.MaxPool2d(2)),('flatten', nn.Flatten()),('linear1', nn.Linear(64 * 4 * 4, 64)),('linear2', nn.Linear(64, 10))]))def forward(self, x):x = self.model1(x)return xloss = nn.CrossEntropyLoss()model = MyModel()
for data in dataloader:imgs, targets = dataoutputs = model(imgs)result_loss = loss(outputs, targets)result_loss.backward() # 使用反向傳播print(result_loss)
? 在 Pycharm 中,將第 48 行注釋,點擊調試。

? 依次在變量窗口中展開“model”-》“model1”-》“conv1”,可看到 conv1 層中的權重參數 weight。

? 展開“weight”,其 grad 屬性此時為 None。

? 點擊“步過”按鈕,運行 48 行,“weight”的 grad 屬性被賦值。此值即為本次迭代的梯度數據。
