1. prefetch_generator
使用 prefetch_generator
庫 在后台加載下一batch的數據,原本PyTorch默認的DataLoader
會創建一些worker
線程來預讀取新的數據,但是除非這些線程的數據全部都被清空,這些線程才會讀下一批數據。使用prefetch_generator
,我們可以保證線程不會等待,每個線程都總有至少一個數據在加載。
-
安裝
pip install prefetch_generator
-
使用
之前加載數據集的正確方式是使用torch.utils.data.DataLoader
,現在我們只要利用這個庫,新建個DataLoaderX
類繼承DataLoader
並重寫__iter__
方法即可from torch.utils.data import DataLoader from prefetch_generator import BackgroundGenerator class DataLoaderX(DataLoader): def __iter__(self): return BackgroundGenerator(super().__iter__())
之后這樣用:
train_dataset = MyDataset(".........") train_loader = DataLoaderX(dataset=train_dataset, batch_size=batch_size, num_workers=4, shuffle=shuffle)
2. Apex
2.1 安裝
- 克隆源代碼
git clone https://github.com/NVIDIA/apex
可以先下載到碼雲,再下載到本地
- 安裝apex
cd apex
python setup.py install
最好打開PyCharm的終端進行安裝,這樣實在Anaconda的環境里安裝了
- 刪除剛剛clone下來的apex文件夾,然后重啟PyCharm
【注意】安裝PyTorch和cuda時注意版本對應,要按照正確流程安裝
- 測試安裝成功
from apex import amp
如果導入不報錯說明安裝成功
2.2 使用
from apex import amp # 這個必須的,其他的導包省略了
train_dataset = MyDataset("......")
train_loader = DataLoader(dataset=train_dataset, batch_size=2, num_workers=4, shuffle=True)
model = MyNet().to(device) # 創建模型
criterion = nn.MSELoss() # 定義損失函數
optimizer = optim.Adam(net.parameters(), lr=learning_rate, weight_decay=0.00001) # 優化器
net, optimizer = amp.initialize(net, optimizer, opt_level="O1") # 這一步很重要
# 學習率衰減
scheduler = optim.lr_scheduler.ReduceLROnPlateau(
optimizer=optimizer, mode="min",factor=0.1, patience=3,
verbose=False,cooldown=0, min_lr=0.0, eps=1e-7)
for epoch in range(epochs):
net.train() # 訓練模式
train_loss_epoch = [] # 記錄一個epoch內的訓練集每個batch的loss
test_loss_epoch = [] # 記錄一個epoch內測試集的每個batch的loss
for i, data in enumerate(train_loader):
# forward
x, y = data
x = x.to(device)
y = y.to(device)
outputs = net(x)
# backward
optimizer.zero_grad()
loss = criterion(outputs, labels)
# 這一步也很重要
with amp.scale_loss(loss, optimizer) as scaled_loss:
scaled_loss.backward()
# 更新權重
optimizer.step()
scheduler.step(1) # 更新學習率。每1步更新一次
- 主要是添加了三行代碼
- scaled_loss 是將原loss放大了,所以要保存loss應該保存之前的值,這種放大防止梯度消失
考察amp.initialize(net, optimizer, opt_level="O1")
的opt_level
參數
-
opt_level=O0
(base)
表示的是當前執行FP32訓練,即正常的訓練 -
opt_level=O1
(推薦)
表示的是當前使用部分FP16混合訓練 -
opt_level=O2
表示的是除了BN層的權重外,其他層的權重都使用FP16執行訓練
-
opt_level=O3
表示的是默認所有的層都使用FP16執行計算,當keep_batch norm_fp32=True
,則會使用cudnn執行BN層的計算,該優化等級能夠獲得最快的速度,但是精度可能會有一些較大的損失
一般我們用
O1
級別就行,最多O2
,注意,是歐
不是零