PyTorch 訓練目前已經是 num_workers = 0 了 CPU占用還是高
如果 num_workers=0 後 CPU 占用還是很高,問題主要在於模型運算本身。以下是幾個有效的解決方案:
1. 限制 PyTorch 的 CPU 執行緒數 (最有效)
在 training.py 最前面加入:
import torch import os # === 在所有 import 之後,主程式之前加入 === # 限制 PyTorch 使用的 CPU 執行緒數 torch.set_num_threads(2) # 限制為 2 個執行緒 torch.set_num_interop_threads(2) # 限制 inter-op 執行緒 # 限制底層數學庫的執行緒數 os.environ['OMP_NUM_THREADS'] = '2' os.environ['MKL_NUM_THREADS'] = '2' os.environ['NUMEXPR_NUM_THREADS'] = '2' os.environ['OPENBLAS_NUM_THREADS'] = '2'
2. 在 CONFIG 中加入可配置的執行緒控制
修改 training.py 的 main 函數開頭:
def main():
# === 在最開始加入執行緒控制 ===
cpu_threads = CONFIG.get('cpu_threads', 2)
torch.set_num_threads(cpu_threads)
torch.set_num_interop_threads(cpu_threads)
os.environ['OMP_NUM_THREADS'] = str(cpu_threads)
os.environ['MKL_NUM_THREADS'] = str(cpu_threads)
os.environ['NUMEXPR_NUM_THREADS'] = str(cpu_threads)
os.environ['OPENBLAS_NUM_THREADS'] = str(cpu_threads)
print(f"? 限制 CPU 使用 {cpu_threads} 個執行緒")
print("="*70)
print("影像分類訓練系統")
# ... 其餘程式碼
在 CONFIG 設定中加入:
CONFIG = {
# ... 其他設定 ...
'cpu_threads': config.get('cpu_threads', 2), # 新增這行
}
3. 在 settings/training.yaml 加入設定
# CPU 執行緒控制 cpu_threads: 2 # 可調整為 1, 2, 4 等 num_workers: 0
4. 減小 batch_size (如果記憶體夠用)
較小的 batch_size 會降低每次運算的負擔:
batch_size: 16 # 從 32 改為 16 (或更小)
5. 加入訓練間隔休息 (可選)
在 train_epoch 函數中加入小延遲:
def train_epoch(model, dataloader, criterion, optimizer, device):
model.train()
running_loss = 0.0
total_batches = len(dataloader)
for batch_idx, (inputs, labels) in enumerate(dataloader, 1):
inputs, labels = inputs.to(device), labels.float().to(device)
optimizer.zero_grad()
outputs = model(inputs).squeeze(1)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
running_loss += loss.item() * inputs.size(0)
# 計算當前平均 loss
current_avg_loss = running_loss / (batch_idx * inputs.size(0))
# 顯示訓練進度
progress = batch_idx / total_batches * 100
print(f"\r Training: [{batch_idx}/{total_batches}] {progress:.1f}% | Loss: {current_avg_loss:.4f}", end='')
# === 每 N 個 batch 休息一下 (可選) ===
if batch_idx % 10 == 0:
import time
time.sleep(0.01) # 休息 10ms
epoch_loss = running_loss / len(dataloader.dataset)
print()
return epoch_loss
6. 使用更輕量的模型
目前使用 efficientnet_v2_s,可以改為更小的模型:
model: mobilenet_v3_small # 參數量只有 2.5M,比 efficientnet_v2_s (21M) 小很多
完整修改建議:
在 if __name__ == '__main__': 之前加入:
if __name__ == '__main__':
import torch
import os
# === 必須在最開始設定,否則無效 ===
torch.set_num_threads(2)
torch.set_num_interop_threads(2)
os.environ['OMP_NUM_THREADS'] = '2'
os.environ['MKL_NUM_THREADS'] = '2'
os.environ['NUMEXPR_NUM_THREADS'] = '2'
os.environ['OPENBLAS_NUM_THREADS'] = '2'
warnings.filterwarnings('ignore')
# 載入設定檔
config_path = 'settings/training.yaml'
# ... 其餘程式碼
在 settings/training.yaml:
# 效能調整 cpu_threads: 2 # CPU 執行緒數 (1-4) num_workers: 0 # DataLoader 工作執行緒 batch_size: 16 # 減小 batch size model: mobilenet_v3_small # 使用更輕量的模型
效果預期:
torch.set_num_threads(2): 可降低 50-70% 的 CPU 占用
改用 mobilenet_v3_small: 可再降低 20-30% 的運算量
減小 batch_size: 可降低瞬間峰值,但訓練時間會拉長
建議優先嘗試第 1 點,這是最有效且最簡單的方法!
後記:
# 限制 PyTorch 使用的 CPU 執行緒數
torch.set_num_threads(2)
torch.set_num_interop_threads(2)
os.environ['OMP_NUM_THREADS'] = '2'
os.environ['MKL_NUM_THREADS'] = '2'
os.environ['NUMEXPR_NUM_THREADS'] = '2'
os.environ['OPENBLAS_NUM_THREADS'] = '2'
實測有效!![]()

留言板
歡迎留下建議與分享!希望一起交流!感恩!