WeHelp
PyTorch 可以應用在迴歸預測模型、分類預測模型、影像辨識、物件偵測、生成式模型等等領域。
  1. 房屋價格預測
  2. 乳癌良性 / 惡性分類
  3. 紅酒產地分類
  4. CNN 影像辨識
  5. R-CNN 物件偵測
  6. GAN 生成對抗網路
房屋價格預測
以下以「**根據房屋坪數、屋齡、房間數與距離市中心距離,預測房屋價格**」為例,使用 PyTorch 建立一個多層感知器(MLP)迴歸模型。 --- ## 一、問題定義 假設每筆房屋資料包含以下特徵: | 特徵 | 說明 | |---|---| | `area` | 房屋面積 | | `age` | 屋齡 | | `rooms` | 房間數 | | `distance` | 距離市中心距離 | 模型輸出: - `price`:房屋價格 這是一個典型的監督式學習迴歸問題,損失函數可以使用均方誤差(MSE)。 --- ## 二、完整實作程式碼 ### 1. 匯入套件與建立資料 以下使用 `make_regression` 建立一組模擬房價資料。實務上可以將這段替換成讀取 CSV 或資料庫的程式。 ```python import copy import numpy as np import torch import torch.nn as nn from torch.utils.data import TensorDataset, DataLoader from sklearn.datasets import make_regression from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score ``` ```python # 固定亂數,讓結果容易重現 np.random.seed(42) torch.manual_seed(42) # 建立模擬房價資料 # 4 個特徵:坪數、屋齡、房間數、距離市中心距離 X, y = make_regression( n_samples=1000, n_features=4, n_informative=4, noise=12, random_state=42 ) # 將房價設定為二維陣列,方便後續標準化 y = y.reshape(-1, 1) print("X shape:", X.shape) print("y shape:", y.shape) ``` --- ### 2. 切分訓練集、驗證集與測試集 資料切分方式如下: - 訓練集:70% - 驗證集:15% - 測試集:15% ```python # 先切分出 70% 訓練集與 30% 暫存集 X_train, X_temp, y_train, y_temp = train_test_split( X, y, test_size=0.30, random_state=42 ) # 再將暫存集切成驗證集與測試集,各佔 15% X_val, X_test, y_val, y_test = train_test_split( X_temp, y_temp, test_size=0.50, random_state=42 ) print("Train:", X_train.shape) print("Validation:", X_val.shape) print("Test:", X_test.shape) ``` --- ### 3. 特徵標準化 神經網路通常對特徵尺度較敏感,因此將輸入特徵標準化為平均值 0、標準差 1。 需要注意: > `StandardScaler` 只能使用訓練集進行 `fit`,不能使用全部資料,避免資料洩漏。 同時也將目標值進行標準化,使模型訓練更加穩定。 ```python x_scaler = StandardScaler() y_scaler = StandardScaler() # 只使用訓練集 fit X_train_scaled = x_scaler.fit_transform(X_train) X_val_scaled = x_scaler.transform(X_val) X_test_scaled = x_scaler.transform(X_test) y_train_scaled = y_scaler.fit_transform(y_train) y_val_scaled = y_scaler.transform(y_val) y_test_scaled = y_scaler.transform(y_test) ``` --- ### 4. 轉換成 PyTorch Tensor 與 DataLoader ```python # 轉為 float32,適合 PyTorch 模型 X_train_tensor = torch.tensor(X_train_scaled, dtype=torch.float32) y_train_tensor = torch.tensor(y_train_scaled, dtype=torch.float32) X_val_tensor = torch.tensor(X_val_scaled, dtype=torch.float32) y_val_tensor = torch.tensor(y_val_scaled, dtype=torch.float32) X_test_tensor = torch.tensor(X_test_scaled, dtype=torch.float32) y_test_tensor = torch.tensor(y_test_scaled, dtype=torch.float32) # 建立 Dataset train_dataset = TensorDataset(X_train_tensor, y_train_tensor) val_dataset = TensorDataset(X_val_tensor, y_val_tensor) test_dataset = TensorDataset(X_test_tensor, y_test_tensor) # 建立 DataLoader train_loader = DataLoader( train_dataset, batch_size=32, shuffle=True ) val_loader = DataLoader( val_dataset, batch_size=32, shuffle=False ) test_loader = DataLoader( test_dataset, batch_size=32, shuffle=False ) ``` --- ## 三、建立迴歸模型 這裡建立一個簡單的多層感知器: ```text 輸入層:4 個特徵 ↓ Linear(4 → 64) ↓ ReLU ↓ Linear(64 → 32) ↓ ReLU ↓ Linear(32 → 1) ↓ 預測價格 ``` 迴歸問題的輸出層通常不使用 Sigmoid 或 Softmax,直接輸出連續數值即可。 ```python class HousePriceRegressor(nn.Module): def __init__(self, input_dim): super().__init__() self.network = nn.Sequential( nn.Linear(input_dim, 64), nn.ReLU(), nn.Linear(64, 32), nn.ReLU(), nn.Linear(32, 1) ) def forward(self, x): return self.network(x) model = HousePriceRegressor(input_dim=4) print(model) ``` --- ## 四、設定損失函數與最佳化器 ```python # 迴歸常用損失函數 criterion = nn.MSELoss() # Adam 通常適合用於快速建立基準模型 optimizer = torch.optim.Adam( model.parameters(), lr=0.001, weight_decay=1e-4 ) ``` 主要設定說明: | 設定 | 說明 | |---|---| | `MSELoss` | 衡量預測值與真實值平方差 | | `Adam` | 常用且穩定的最佳化器 | | `lr=0.001` | 學習率 | | `weight_decay=1e-4` | L2 正則化,降低過擬合 | --- ## 五、模型訓練 訓練時需要進行以下步驟: 1. 從 DataLoader 取得一批資料 2. 將資料送入模型 3. 計算預測值與損失 4. 反向傳播 5. 更新模型參數 6. 使用驗證集評估模型 ```python num_epochs = 500 train_losses = [] val_losses = [] best_val_loss = float("inf") best_model_state = None for epoch in range(num_epochs): # ------------------------- # Training # ------------------------- model.train() total_train_loss = 0.0 for batch_X, batch_y in train_loader: # 清除上一批資料的梯度 optimizer.zero_grad() # 前向傳播 predictions = model(batch_X) # 計算損失 loss = criterion(predictions, batch_y) # 反向傳播 loss.backward() # 更新參數 optimizer.step() total_train_loss += loss.item() * batch_X.size(0) avg_train_loss = total_train_loss / len(train_loader.dataset) # ------------------------- # Validation # ------------------------- model.eval() total_val_loss = 0.0 with torch.no_grad(): for batch_X, batch_y in val_loader: predictions = model(batch_X) loss = criterion(predictions, batch_y) total_val_loss += loss.item() * batch_X.size(0) avg_val_loss = total_val_loss / len(val_loader.dataset) train_losses.append(avg_train_loss) val_losses.append(avg_val_loss) # 保存驗證集表現最好的模型 if avg_val_loss < best_val_loss: best_val_loss = avg_val_loss best_model_state = copy.deepcopy(model.state_dict()) if (epoch + 1) % 50 == 0: print( f"Epoch [{epoch + 1:3d}/{num_epochs}] " f"Train Loss: {avg_train_loss:.4f}, " f"Val Loss: {avg_val_loss:.4f}" ) # 載入驗證集表現最好的模型 model.load_state_dict(best_model_state) ``` --- ## 六、使用測試集評估模型 因為訓練時對 `y` 做了標準化,因此模型輸出也是標準化後的價格。評估時要先轉回原始價格尺度,再計算指標。 ```python model.eval() with torch.no_grad(): test_predictions_scaled = model(X_test_tensor).numpy() # 還原成原本的價格尺度 test_predictions = y_scaler.inverse_transform( test_predictions_scaled ) test_actual = y_scaler.inverse_transform( y_test_scaled ) # 計算評估指標 mse = mean_squared_error(test_actual, test_predictions) rmse = np.sqrt(mse) mae = mean_absolute_error(test_actual, test_predictions) r2 = r2_score(test_actual, test_predictions) print("\nTest Results") print(f"MSE : {mse:.4f}") print(f"RMSE: {rmse:.4f}") print(f"MAE : {mae:.4f}") print(f"R2 : {r2:.4f}") ``` ### 評估指標說明 #### MSE 對較大的預測誤差懲罰較重。 #### RMSE 與目標值使用相同單位,較容易解讀。 #### MAE 表示平均預測誤差的大小,對離群值較不敏感。 #### \(R^2\) 表示模型解釋資料變異的能力: - 越接近 1,通常代表模型越好 - 等於 0,代表和直接預測平均值差不多 - 小於 0,代表模型表現不佳 --- ## 七、查看實際預測結果 ```python for i in range(10): print( f"實際價格: {test_actual[i][0]:8.2f}, " f"預測價格: {test_predictions[i][0]:8.2f}" ) ``` --- ## 八、繪製訓練曲線 訓練曲線可以觀察模型是否過擬合。 ```python import matplotlib.pyplot as plt plt.figure(figsize=(8, 5)) plt.plot(train_losses, label="Training Loss") plt.plot(val_losses, label="Validation Loss") plt.xlabel("Epoch") plt.ylabel("MSE Loss") plt.title("Training and Validation Loss") plt.legend() plt.grid() plt.show() ``` 判斷方式: - 訓練損失與驗證損失都下降:模型正在學習 - 訓練損失持續下降,但驗證損失上升:可能過擬合 - 兩者都很高且不下降:可能模型太簡單、學習率不適當,或資料本身噪聲太大 --- ## 九、若使用真實 CSV 資料 假設資料檔案名稱為 `house_prices.csv`,欄位如下: ```text area,age,rooms,distance,price ``` 可以將資料建立部分改成: ```python import pandas as pd df = pd.read_csv("house_prices.csv") X = df[["area", "age", "rooms", "distance"]].values y = df[["price"]].values ``` 後續的資料切分、標準化、Tensor 建立與模型訓練程式可以維持不變。 --- ## 十、關鍵步驟總結 1. **準備資料** - 找出輸入特徵與預測目標 - 處理缺失值與異常值 2. **切分資料** - 訓練集用於更新模型參數 - 驗證集用於選擇模型與調整超參數 - 測試集只能在最後使用 3. **標準化資料** - 只用訓練集估計平均值與標準差 - 驗證集、測試集只能使用相同轉換方式 4. **建立模型** - 使用 `nn.Linear` 建立全連接層 - 使用 `ReLU` 增加非線性表達能力 - 迴歸輸出層通常輸出一個連續數值 5. **設定訓練方法** - 損失函數:`MSELoss` - 最佳化器:`Adam` - 適當設定學習率、批次大小與訓練回合數 6. **模型評估** - 使用 RMSE、MAE、\(R^2\) - 評估前將標準化後的預測值轉回原始單位 7. **避免過擬合** - 使用驗證集 - 保存最佳模型 - 使用 `weight_decay` - 必要時加入 Dropout 或 Early Stopping 這個模型適合作為房價、銷售量、能源消耗量或產品需求量等連續數值預測問題的基礎 PyTorch 實作。
相關學習地圖、教學課程
Python 人工智慧
建議完成「Python 資料工程」教程後,繼續學習以下課程。