Pytorch訓練時GPU占用率低0%


問題描述

最近在做畢業設計的論文,訓練CNN的時候用nvidia-smi命令查看顯卡占用率的時候發現一個事:
顯存占用上去了,但是GPU利用率一直為0%或者頻繁跳動(圖來自網絡)

數據集用的1萬張圖,7000左右拿來訓練,用resnet-18網絡,圖resize成112*112的灰度圖,GPU-A4000。訓練一個epoch大概30S......

dataloader部分的解決方法

  1. 增加dataloader的num_num_workers數量(這個函數應放在main函數里執行,不然會報錯)。一般設置為與CPU核心數相同的(這條建議我是從租GPU的網站看到的),不過設置過高並沒有用反而性能降低。可以從2,4,6....這樣的逐步增加,看看多少合適
  train_loader = data.DataLoader(dataset=train_dataset,
                                 batch_size=512,
                                 shuffle=False, num_workers=6)

2.修改dataloader的prefetch_factor(pytorch版本1.7以上的新特性,我用的Pytorch-1.8.1可以使用),default=2,表示有2 * num_workers樣本會被提前取出

    train_loader = data.DataLoader(dataset=train_dataset,batch_size=512,
                                 num_workers=6,prefetch_factor=4)
                                   

3.設置dataloader的persistent_workers。如果為True表示dataset被使用后進程不會被關閉,會一直保持

train_loader = data.DataLoader(dataset=train_dataset,batch_size=512,
                                 num_workers=6,prefetch_factor=4,
                                 persistent_workers=True
)

上述部分的解釋可能與pytorch官方文檔有一些出入,詳細可以見:https://pytorch.org/docs/stable/data.html

從數據集本身

一般的數據讀取方法

  1. 從csv等等文件讀取注釋信息。以分類任務為例:有圖片的路徑,和要分類的結果。(img:/root/path/蘋果.jpg label:'apple'這樣的格式)
  2. 根據注釋的path用cv2,PIL等庫對圖片讀取。以PIL讀取為例
from PIL import Image
Image.open(img_path).convert("L")

3.在dataset里使用的時候,讀取注釋path,轉換label為數字

    def __getitem__(self, index):
        'Generates one sample of data'
        img_path = 根據index從csv文件獲取路徑
        label = 根據index從csv文件獲取標簽
        X = Image.open(img_path).convert("L")
        y = torch.tensor(label)

        return X, y

==========》這樣寫是很普遍的用法,如果用SSD讀取還好,SSD的速度很快。但是!!我租GPU的網站硬盤是機械的,這就導致我大量的時間都耗費在IO上了
但是租GPU的網站有個好處-------->大內存,那么就可以考慮先把所有圖片加載到內存中,然后直接映射讀取,這樣就解決了IO問題

解決方法

1.根據csv讀取img_path,label信息
2.把圖片和標簽存入一個文件,這里我存入npy文件
3.在dataset初始化時直接讀取npy文件,就加載到內存中------>后續從npy文件獲取數據即可
4.npy文件的shape為[1000, 2] 1000行2列的矩陣
對於每一行元素 npy[i, 0]第一列表示img(注意是img,而不是img_path),npy[i, 1]第二列表示label
部分代碼如下

ls = []
for line_index, line in df.iterrows():
    img_path = line.path
    val = line.cell_type_idx
    img_path = line.path
    # 讀圖片 灰度處理 方法縮小
    temp_img = Image.open(img_path).convert("L")
    temp_img = temp_img.resize([conf.IMAGE_WIDTH, conf.IMAGE_HEIGHT])
    temp_img = np.array(temp_img)
    # 存入npy
    ls.append([temp_img, val])
    
npy_file = np.array(ls)
np.save("/root/test.npy" (這個參數是你要存npy文件的地方), arr=npy_file (這個參數是需要保存的npy是什么))

在dataset中,初始化時就讀取這個npy文件

class MyDataset(data.Dataset):
    'Characterizes a dataset for PyTorch'
    def __init__(self, train_type):
        'Initialization'
        train_npy ="/root/test.npy"
        train_npy = np.load(train_npy,allow_pickle=True)
        self.df = train_npy
        def __len__(self):
        'Denotes the total number of samples'
        return self.df.shape[0]

    def __getitem__(self, index):
        'Generates one sample of data'
        X = self.df[index, 0]
        X = np.array(X)
        y = torch.tensor(int(self.df[index, 1]))
        return X, y

最終效果

最初一個epoch:30s 現在一個epoch5s (進步巨大)

同時GPU占用也上去了

最后再加一個小技巧

讓遠程服務器的Nvidia-smi命令自動刷新結果 就不用每次都輸入命令手動查看了

進入tmux等
nvidia-smi -l


免責聲明!

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



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