1、學習率設置策略
Pytorch 已經實現了兩種方法:「torch.optim.lr_scheduler.CyclicLR」和「torch.optim.lr_scheduler.OneCycleLR」。
參考文檔:https://pytorch.org/docs/stable/optim.html
2、dataloader中使用多個worker和頁鎖定內存
當使用 torch.utils.data.DataLoader 時 num_workers > 0 pin_memory=True
worker 數量的經驗法則是將其設置為可用 GPU 數量的四倍,大於或小於這個數都會降低訓練速度。請注意,增加 num_workers 將增加 CPU 內存消耗。
參考文檔:https://pytorch.org/docs/stable/data.html
3、增大batch
batch 調到最大是一個頗有爭議的觀點。一般來說,如果在 GPU 內存允許的范圍內將 batch 調到最大,你的訓練速度會更快。
但是,你也必須調整其他超參數,比如學習率。一個比較好用的經驗是,batch 大小加倍時,學習率也要加倍。
4、換一種優化器
AdamW 是由 fast.ai 推廣的一種具有權重衰減(而不是 L2 正則化)的 Adam,在 PyTorch 中以 torch.optim.AdamW 實現。AdamW 似乎在誤差和訓練時間上都一直優於 Adam。
Adam 和 AdamW 都能與上面提到的 1Cycle 策略很好地搭配。
5、cudnn基准
如果你的模型架構保持不變、輸入大小保持不變,設置 torch.backends.cudnn.benchmark = True
6、小心CPU和GPU之間數據的傳輸
當頻繁地使用 tensor.cpu() 將張量從 GPU 轉到 CPU(或使用 tensor.cuda() 將張量從 CPU 轉到 GPU)時,代價是非常昂貴的。item() 和 .numpy() 也是一樣可以使用. detach() 代替。
如果你創建了一個新的張量,可以使用關鍵字參數 device=torch.device('cuda:0') 將其分配給 GPU。
如果你需要傳輸數據,可以使用. to(non_blocking=True),只要在傳輸之后沒有同步點。
7、使用梯度積累
增加 batch 大小的另一種方法是在調用 optimizer.step() 之前在多個. backward() 傳遞中累積梯度。
Hugging Face 的 Thomas Wolf 的文章《Training Neural Nets on Larger Batches: Practical Tips for 1-GPU, Multi-GPU & Distributed setups》介紹了如何使用梯度累積。梯度累積可以通過如下方式實現:
model.zero_grad()
# Reset gradients tensorsfor i, (inputs, labels) in enumerate(training_set):
predictions = model(inputs)
# Forward passloss = loss_function(predictions, labels)
# Compute loss functionloss = loss / accumulation_steps
# Normalize our loss (if averaged)loss.backward()
# Backward passif (i+1) % accumulation_steps == 0:
# Wait for several backward stepsoptimizer.step()
# Now we can do an optimizer stepmodel.zero_grad()
# Reset gradients tensorsif (i+1) % evaluation_steps == 0:
# Evaluate the model when we...evaluate_model()
# ...have no gradients accumulate
這個方法主要是為了規避 GPU 內存的限制而開發的。
8、分布式數據並行進行多GPU訓練
加速分布式訓練可能有很多方法,但是簡單的方法是使用 torch.nn.DistributedDataParallel 而不是 torch.nn.DataParallel。
這樣一來,每個 GPU 將由一個專用的 CPU 核心驅動,避免了 DataParallel 的 GIL 問題。
分布式訓練文檔地址:https://pytorch.org/tutorials/beginner/dist_overview.html
9、設置梯度為None,而不是0
梯度設置為. zero_grad(set_to_none=True) 而不是 .zero_grad()。
這樣做可以讓內存分配器處理梯度,而不是將它們設置為 0。
正如文檔中所說,將梯度設置為 None 會產生適度的加速,但不要期待奇跡出現。
注意,這樣做也有缺點,詳細信息請查看文檔。
文檔地址:https://pytorch.org/docs/stable/optim.html
10、使用.as_tensor() 而不是.tensor()
torch.tensor() 總是會復制數據。如果你要轉換一個 numpy 數組,使用 torch.as_tensor() 或 torch.from_numpy() 來避免復制數據。
11、驗證期間關閉梯度計算
設置:torch.no_grad()
12、使用輸入和batch歸一化