二元分類模型範例
以下示範使用 PyTorch 建立一個簡單的二元分類模型:
- 輸入特徵:標準化後的身高、體重
- 輸出標籤:男生為 `1`,女生為 `0`
- 模型:兩個線性層,中間使用 ReLU
- 損失函數:`BCEWithLogitsLoss`
---
## 1. 安裝 PyTorch
```bash
pip install torch numpy
```
---
## 2. 準備資料
假設身高與體重已經標準化,也就是大致符合平均值為 0、標準差為 1。
```python
import numpy as np
import torch
from torch.utils.data import TensorDataset, DataLoader, random_split
```
以下資料僅作為示範:
```python
# 每一列依序為:[標準化身高, 標準化體重]
X = np.array([
[-1.2, -1.0],
[-0.8, -0.7],
[-0.5, -0.6],
[-0.3, -0.4],
[ 0.2, 0.1],
[ 0.4, 0.3],
[ 0.8, 0.7],
[ 1.0, 1.1],
[ 1.2, 0.9],
[-0.7, -0.2],
[ 0.6, 0.5],
[-0.4, -0.8],
], dtype=np.float32)
# 男生為 1,女生為 0
y = np.array([
0, 0, 0, 0,
1, 1, 1, 1,
1, 0, 1, 0
], dtype=np.float32)
# 轉換為 PyTorch Tensor
X_tensor = torch.tensor(X, dtype=torch.float32)
y_tensor = torch.tensor(y, dtype=torch.float32).reshape(-1, 1)
dataset = TensorDataset(X_tensor, y_tensor)
# 切分訓練集與測試集
train_size = int(0.8 * len(dataset))
test_size = len(dataset) - train_size
train_dataset, test_dataset = random_split(
dataset,
[train_size, test_size],
generator=torch.Generator().manual_seed(42)
)
train_loader = DataLoader(train_dataset, batch_size=4, shuffle=True)
test_loader = DataLoader(test_dataset, batch_size=4, shuffle=False)
```
---
## 3. 建立模型
使用兩個線性層:
```text
身高、體重
↓
Linear(2, 8)
↓
ReLU
↓
Linear(8, 1)
↓
輸出 logit
```
```python
import torch.nn as nn
class GenderClassifier(nn.Module):
def __init__(self):
super().__init__()
self.network = nn.Sequential(
nn.Linear(2, 8), # 2 個輸入特徵,8 個隱藏神經元
nn.ReLU(),
nn.Linear(8, 1) # 輸出一個 logit
)
def forward(self, x):
return self.network(x)
model = GenderClassifier()
print(model)
```
輸出的模型結構大致如下:
```text
GenderClassifier(
(network): Sequential(
(0): Linear(in_features=2, out_features=8, bias=True)
(1): ReLU()
(2): Linear(in_features=8, out_features=1, bias=True)
)
)
```
### 為什麼最後不直接使用 Sigmoid?
因為使用:
```python
nn.BCEWithLogitsLoss()
```
時,損失函數已經內含 Sigmoid,數值上通常比自行先使用 Sigmoid 更穩定。
---
## 4. 設定損失函數與最佳化器
```python
loss_function = nn.BCEWithLogitsLoss()
optimizer = torch.optim.Adam(
model.parameters(),
lr=0.01
)
```
主要設定:
- `BCEWithLogitsLoss`:適合二元分類
- `Adam`:常用且容易使用的最佳化器
- `lr=0.01`:學習率,控制每次更新的幅度
---
## 5. 訓練模型
```python
num_epochs = 100
for epoch in range(num_epochs):
model.train()
total_loss = 0.0
for inputs, labels in train_loader:
# 前向傳播
logits = model(inputs)
# 計算損失
loss = loss_function(logits, labels)
# 清除上一輪的梯度
optimizer.zero_grad()
# 反向傳播
loss.backward()
# 更新模型參數
optimizer.step()
total_loss += loss.item() * inputs.size(0)
average_loss = total_loss / len(train_loader.dataset)
if (epoch + 1) % 10 == 0:
print(
f"Epoch [{epoch + 1}/{num_epochs}], "
f"Loss: {average_loss:.4f}"
)
```
每一輪訓練的主要流程是:
1. 將輸入資料送入模型
2. 計算預測值與正確答案之間的損失
3. 清除舊梯度
4. 反向傳播計算梯度
5. 使用最佳化器更新權重
---
## 6. 評估模型準確率
模型最後輸出的是 `logit`,需要先使用 Sigmoid 轉換成機率:
```python
model.eval()
correct = 0
total = 0
with torch.no_grad():
for inputs, labels in test_loader:
logits = model(inputs)
# 將 logit 轉換為機率
probabilities = torch.sigmoid(logits)
# 機率 >= 0.5 判定為男生 1,否則為女生 0
predictions = (probabilities >= 0.5).float()
correct += (predictions == labels).sum().item()
total += labels.numel()
accuracy = correct / total
print(f"Test Accuracy: {accuracy:.2%}")
```
判斷方式:
```python
probability >= 0.5 -> 男生,1
probability < 0.5 -> 女生,0
```
---
## 7. 預測新資料
假設新資料的身高與體重也已經使用相同方式標準化:
```python
# 一筆新資料:[標準化身高, 標準化體重]
new_person = torch.tensor([[0.7, 0.6]], dtype=torch.float32)
model.eval()
with torch.no_grad():
logit = model(new_person)
probability = torch.sigmoid(logit).item()
prediction = 1 if probability >= 0.5 else 0
print(f"男生機率: {probability:.4f}")
print(f"預測結果: {'男生' if prediction == 1 else '女生'}")
```
---
## 重要設定與注意事項
### 1. 輸入形狀
每筆資料有兩個特徵:
```text
[身高, 體重]
```
因此第一層必須設定為:
```python
nn.Linear(2, 8)
```
其中:
- `2`:輸入特徵數量
- `8`:隱藏層神經元數量,可自行調整
### 2. 輸出形狀
二元分類通常只需要輸出一個數值:
```python
nn.Linear(8, 1)
```
這個數值稱為 `logit`,再透過 Sigmoid 轉換成 0 到 1 之間的機率。
### 3. 標籤格式
因為使用 `BCEWithLogitsLoss`,標籤應為浮點數:
```python
0.0 或 1.0
```
而不是整數類別索引。
### 4. 標準化資料
如果原始資料尚未標準化,可以使用:
```python
X_standardized = (X - mean) / std
```
實務上應該只用訓練集計算 `mean` 和 `std`,再套用到驗證集、測試集及新資料,避免資料洩漏。
### 5. 性別預測的實務限制
身高和體重未必能可靠判斷個人性別,實際資料可能存在大量重疊。因此此範例主要用來示範 PyTorch 的模型建置與訓練流程,不代表這是一個適合實務使用的性別分類方法。
相關學習地圖、教學課程
Python 人工智慧