PyTorch 損失函式
## 一、損失函式的用途
損失函式(Loss Function)用來衡量:
> 模型的預測結果(prediction)與真實答案或期待值(target)之間有多大的差異。
損失值通常是數值,且一般希望越小越好。訓練神經網路時,模型會透過損失值了解目前預測的好壞,再配合反向傳遞與最佳化器更新參數。
簡化流程如下:
```text
輸入資料
↓
神經網路模型
↓
模型預測值 prediction
↓
損失函式(prediction, target)
↓
損失值 loss
```
本題只示範如何計算損失,不進行後續的反向傳遞,例如不呼叫:
```python
loss.backward()
optimizer.step()
```
---
## 二、常見的損失函式
### 1. 均方誤差:MSELoss
常用於迴歸問題,例如:
- 房價預測
- 溫度預測
- 銷售量預測
PyTorch 使用方式:
```python
nn.MSELoss()
```
預測誤差越大,平方後對損失的影響越明顯。
---
### 2. 平均絕對誤差:L1Loss
同樣常用於迴歸問題:
PyTorch 使用方式:
```python
nn.L1Loss()
```
相比 MSE,L1Loss 對異常值通常比較不敏感。
---
### 3. 交叉熵損失:CrossEntropyLoss
常用於多分類問題,例如:
- 判斷圖片是貓、狗或鳥
- 判斷新聞類別
- 手寫數字辨識
PyTorch 的 `CrossEntropyLoss` 通常結合了:
1. `Softmax`
2. 負對數概似損失(Negative Log Likelihood Loss)
因此,模型輸出應該是**未經 Softmax 的 logits**,而目標值應該是類別索引。
```python
nn.CrossEntropyLoss()
```
例如:
```text
類別 0:貓
類別 1:狗
類別 2:鳥
```
真實標籤可以使用:
```python
target = tensor([1])
```
代表答案是類別 1。
---
### 4. 二元交叉熵損失:BCEWithLogitsLoss
常用於二元分類,例如:
- 垃圾郵件或正常郵件
- 有病或無病
- 是或否
```python
nn.BCEWithLogitsLoss()
```
它會自動將 logits 結合 Sigmoid 計算,因此模型輸出不需要先手動套用 `Sigmoid`。
---
## 三、PyTorch 範例一:迴歸模型使用 MSELoss
以下建立一個簡單的神經網路,根據 3 個輸入特徵預測一個連續數值。
```python
import torch
import torch.nn as nn
# 建立一個簡單的迴歸神經網路
class RegressionModel(nn.Module):
def __init__(self):
super().__init__()
self.network = nn.Sequential(
nn.Linear(3, 8), # 3 個輸入特徵
nn.ReLU(),
nn.Linear(8, 1) # 輸出 1 個連續數值
)
def forward(self, x):
return self.network(x)
# 建立模型
model = RegressionModel()
# 假設有 2 筆資料,每筆資料有 3 個特徵
x = torch.tensor([
[1.0, 2.0, 3.0],
[2.0, 1.0, 0.5]
])
# 真實答案,形狀為 [2, 1]
target = torch.tensor([
[10.0],
[5.0]
])
# 前向傳遞,取得模型預測值
prediction = model(x)
# 建立均方誤差損失函式
loss_function = nn.MSELoss()
# 計算預測值與真實值之間的誤差
loss = loss_function(prediction, target)
print("模型預測值:")
print(prediction)
print("真實值:")
print(target)
print("MSE 損失:")
print(loss.item())
```
### 程式說明
```python
prediction = model(x)
```
這一步是前向傳遞,模型根據輸入資料產生預測值。
```python
loss = loss_function(prediction, target)
```
這一步比較:
- `prediction`:模型預測值
- `target`:真實值
並計算平均平方誤差。
此範例沒有執行:
```python
loss.backward()
```
因此不會計算梯度,也不會更新模型參數。
---
## 四、PyTorch 範例二:多分類模型使用 CrossEntropyLoss
以下建立一個簡單的多分類神經網路。假設輸入有 4 個特徵,分類為 3 個類別。
```python
import torch
import torch.nn as nn
# 建立一個簡單的分類神經網路
class ClassificationModel(nn.Module):
def __init__(self):
super().__init__()
self.network = nn.Sequential(
nn.Linear(4, 10), # 4 個輸入特徵
nn.ReLU(),
nn.Linear(10, 3) # 3 個分類,輸出 3 個 logits
)
def forward(self, x):
return self.network(x)
# 建立模型
model = ClassificationModel()
# 假設有 3 筆資料,每筆資料有 4 個特徵
x = torch.tensor([
[1.0, 0.5, 2.0, 1.5],
[2.0, 1.0, 0.2, 0.8],
[0.1, 1.5, 2.5, 0.3]
])
# 真實類別標籤
# 假設共有 3 個類別:0、1、2
target = torch.tensor([0, 2, 1])
# 前向傳遞,取得 logits
logits = model(x)
# 建立交叉熵損失函式
loss_function = nn.CrossEntropyLoss()
# 計算分類損失
loss = loss_function(logits, target)
print("模型輸出的 logits:")
print(logits)
print("真實類別:")
print(target)
print("Cross Entropy 損失:")
print(loss.item())
```
### 程式說明
模型輸出:
```python
logits = model(x)
```
其形狀為:
```text
[資料筆數, 類別數]
```
本例中形狀為:
```text
[3, 3]
```
表示有 3 筆資料,每筆資料對應 3 個類別分數。
`CrossEntropyLoss` 的輸入格式如下:
```python
loss = loss_function(logits, target)
```
其中:
- `logits`:模型輸出,尚未套用 Softmax
- `target`:整數類別索引,例如 `0`、`1`、`2`
- `target` 不應該是 One-hot 向量
例如:
```python
target = torch.tensor([0, 2, 1])
```
代表三筆資料的正確分類分別是:
```text
第 1 筆資料 → 類別 0
第 2 筆資料 → 類別 2
第 3 筆資料 → 類別 1
```
如果想查看模型預測的類別,可以使用:
```python
predicted_class = torch.argmax(logits, dim=1)
print(predicted_class)
```
但計算 `CrossEntropyLoss` 時,應直接將 `logits` 傳入,不需要先呼叫:
```python
torch.softmax(logits, dim=1)
```
---
## 五、重點整理
| 問題類型 | 常見損失函式 | PyTorch 類別 |
|---|---|---|
| 迴歸 | 均方誤差 | `nn.MSELoss()` |
| 迴歸 | 平均絕對誤差 | `nn.L1Loss()` |
| 多分類 | 交叉熵 | `nn.CrossEntropyLoss()` |
| 二元分類 | 二元交叉熵 | `nn.BCEWithLogitsLoss()` |
PyTorch 中計算損失的基本模式為:
```python
prediction = model(input_data)
loss = loss_function(prediction, target)
```
本範例到計算 `loss` 為止,沒有進行:
```python
loss.backward()
optimizer.step()
```
因此只會得到目前模型預測與期待值之間的誤差,不會更新模型參數。
相關學習地圖、教學課程
Python 人工智慧