『PyTorch』屌絲的PyTorch玩法


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 安裝

  1. 克隆源代碼
git clone https://github.com/NVIDIA/apex

可以先下載到碼雲,再下載到本地

  1. 安裝apex
cd apex
python setup.py install

最好打開PyCharm的終端進行安裝,這樣實在Anaconda的環境里安裝了

  1. 刪除剛剛clone下來的apex文件夾,然后重啟PyCharm

【注意】安裝PyTorch和cuda時注意版本對應,要按照正確流程安裝

  1. 測試安裝成功
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,注意,是不是


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM