首頁 > 軟體

pytorch訓練時的視訊記憶體佔用遞增的問題解決

2023-01-16 14:01:29

遇到的問題:

在pytorch訓練過程中突然out of memory。

解決方法:

1. 測試的時候爆視訊記憶體有可能是忘記設定no_grad

加入 with torch.no_grad()

model.eval()
with torch.no_grad():
        for idx, (data, target) in enumerate(data_loader):
            if args.gpu != -1:
                data, target = data.to(args.device), target.to(args.device)
            log_probs = net_g(data)
            probs.append(log_probs)
            
            # sum up batch loss
            test_loss += F.cross_entropy(log_probs, target, reduction='sum').item()
            # get the index of the max log-probability
            y_pred = log_probs.data.max(1, keepdim=True)[1]
            correct += y_pred.eq(target.data.view_as(y_pred)).long().cpu().sum()

2. loss.item()

寫成loss_train = loss_train + loss.item(),不能直接寫loss_train = loss_train + loss

3. 在程式碼中新增以下兩行:

torch.backends.cudnn.enabled = True
torch.backends.cudnn.benchmark = True

4. del操作後再加上torch.cuda.empty_cache()

單獨使用del、torch.cuda.empty_cache()效果都不明顯,因為empty_cache()不會釋放還被佔用的記憶體。
所以這裡使用了del讓對應資料成為“沒標籤”的垃圾,之後這些垃圾所佔的空間就會被empty_cache()回收。

"""新增了最後兩行,img和segm是影象和標籤輸入,很明顯通過.cuda()已經是被存在在視訊記憶體裡了;
   outputs是模型的輸出,模型在視訊記憶體裡當然其輸出也在視訊記憶體裡;loss是通過在視訊記憶體裡的segm和
   outputs算出來的,其也在視訊記憶體裡。這4個物件都是一次性的,使用後應及時把其從視訊記憶體中清除
   (當然如果你視訊記憶體夠大也可以忽略)。"""
 
def train(model, data_loader, batch_size, optimizer):
    model.train()
    total_loss = 0
    accumulated_steps = 32 // batch_size
    optimizer.zero_grad()
    for idx, (img, segm) in enumerate(tqdm(data_loader)):
        img = img.cuda()
        segm = segm.cuda()
        outputs = model(img)
        loss = criterion(outputs, segm)
        (loss/accumulated_steps).backward()
        if (idx + 1 ) % accumulated_steps == 0:
            optimizer.step() 
            optimizer.zero_grad()
        total_loss += loss.item()
        
        # delete caches
        del img, segm, outputs, loss
        torch.cuda.empty_cache()

補充:Pytorch視訊記憶體不斷增長問題的解決思路

思路很簡單,就是在程式碼的執行階段輸出視訊記憶體佔用量,觀察在哪一塊存在視訊記憶體劇烈增加或者視訊記憶體異常變化的情況。
但是在這個過程中要分級確認問題點,也即如果存在三個檔案main.py、train.py、model.py。
在此種思路下,應該先在main.py中確定問題點,然後,從main.py中進入到train.py中,再次輸出視訊記憶體佔用量,確定問題點在哪。
隨後,再從train.py中的問題點,進入到model.py中,再次確認。
如果還有更深層次的呼叫,可以繼續追溯下去。

例如:

main.py

def train(model,epochs,data):
    for e in range(epochs):
        print("1:{}".format(torch.cuda.memory_allocated(0)))
        train_epoch(model,data)
        print("2:{}".format(torch.cuda.memory_allocated(0)))
        eval(model,data)
        print("3:{}".format(torch.cuda.memory_allocated(0)))

若1與2之間視訊記憶體增加極為劇烈,說明問題出在train_epoch中,進一步進入到train.py中。

train.py

def train_epoch(model,data):
    model.train()
    optim=torch.optimizer()
    for batch_data in data:
        print("1:{}".format(torch.cuda.memory_allocated(0)))
        output=model(batch_data)
        print("2:{}".format(torch.cuda.memory_allocated(0)))
        loss=loss(output,data.target)
        print("3:{}".format(torch.cuda.memory_allocated(0)))
        optim.zero_grad()
        print("4:{}".format(torch.cuda.memory_allocated(0)))
        loss.backward()
        print("5:{}".format(torch.cuda.memory_allocated(0)))
        utils.func(model)
        print("6:{}".format(torch.cuda.memory_allocated(0)))

如果在1,2之間,5,6之間同時出現視訊記憶體增加異常的情況。此時需要使用控制變數法,例如我們先讓5,6之間的程式碼失效,然後執行,觀察是否仍然存在視訊記憶體爆炸。如果沒有,說明問題就出在5,6之間下一級的程式碼中。進入到下一級程式碼,進行偵錯:

utils.py

def func(model):
    print("1:{}".format(torch.cuda.memory_allocated(0)))
    a=f1(model)
    print("2:{}".format(torch.cuda.memory_allocated(0)))
    b=f2(a)
    print("3:{}".format(torch.cuda.memory_allocated(0)))
    c=f3(b)
    print("4:{}".format(torch.cuda.memory_allocated(0)))
    d=f4(c)
    print("5:{}".format(torch.cuda.memory_allocated(0)))

此時我們再展示另一種偵錯思路,先註釋第5行之後的程式碼,觀察視訊記憶體是否存在先訓爆炸,如果沒有,則註釋掉第7行之後的,直至確定哪一行的程式碼出現導致了視訊記憶體爆炸。假設第9行起作用後,程式碼出現視訊記憶體爆炸,說明問題出在第九行,視訊記憶體爆炸的問題鎖定。

參考連結:
http://www.zzvips.com/article/196059.html
https://blog.csdn.net/fish_like_apple/article/details/101448551

到此這篇關於pytorch訓練時的視訊記憶體佔用遞增的問題解決的文章就介紹到這了,更多相關pytorch 視訊記憶體佔用遞增內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com