網站首頁 編程語言 正文
前言
訓練模型時,一般我們會把模型model,數據data和標簽label放到GPU顯存中進行加速。
但有的時候GPU Memory會增加,有的時候會保持不變,以及我們要怎么清理掉一些用完的變量呢?
下面讓我們一起來探究下原理吧!
一、pytorch訓練模型
只要你把任何東西(無論是多小的tensor)放到GPU顯存中,那么你至少會棧1000MiB左右的顯存(根據cuda版本,會略有不同)。這部分顯存是cuda running時固有配件必須要占掉的顯存,你先訓練過程匯總也是無法釋放的。
import torch
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
# 把一個很小的tensor加到GPU顯存中(大約2MiB)
x = torch.randn((2, 3), device=device)
現在我再放入一個比較大的tensor,GPU顯存升到了1919MiB
y = torch.randn((200, 300, 200, 20), device=device)
也就是說當你有個新的東西加進去時,GPU顯存會不斷擴大。
二、batch訓練模型時,GPU顯存的容量會保持不變?
但是為什么我們像下面這樣拿出一個個batch訓練模型時,GPU顯存的容量會保持不變的呢?
batch_loss = []
for epoch in range(self.epoch):
pbar = enumerate(tqdm(self.train_dataloader, desc="Training Bar"), 0)
for i, (inputs, labels) in pbar:
inputs = inputs.to(self.device) # 放到GPU顯存中
labels = labels.to(self.device) # 放到GPU顯存中
optimizer.zero_grad()
outputs = model(inputs)
loss = criterion(outputs, labels)
batch_loss.append(loss)
loss.backward()
optimizer.step()
這實際上跟cuda的內存管理有關,但你的一塊內存不再由引用它的變量時,他就不再是Active memory。他會殘留在一個隊列中,如果下一次有新的東西進來,那就會把他擠出隊列(FIFO),當然如果新進來的東西和你那部分空間的大小差不多,那么出去一塊空間,又進來一塊空間,那么看上去你的GPU顯存就不會有增加,看上去是一直不變。這就解釋了一個個batch訓練模型時GPU顯存不變的原因。
當然如果新加進來的東西很多,就是那些unactivate的memory全部被擠出還是放不下新的東西,那GPU的顯存就會增加了。(有點類似C++中的capacity增加的情況)
實際運行中,我們會發現這個隊列capacity會有個閾值(這個閾值好像不是固定的),當你還沒到達這個閾值時不會觸發垃圾回收機制(即清理unactivate memeory的空間)
也就是說我不斷運行下面代碼
y = torch.randn((200, 300, 200, 20), device=device)
GPU顯存會增加到9247MiB
這時再加入y,容量不再增加,會把原來unactivate的memory擠掉。
三、如何釋放GPU顯存空間
那么我們要怎么樣釋放掉空間呢
我們上面很多空間原來是被y指向的,后來y指向新的地方,那這些空間都是殘留的,我們可以用下面命令繼續釋放(如果你想釋放的話)
torch.cuda.empty_cache()
上述命令可能要運行多次才會釋放空間,我運行了大概5次吧
殘留內存成功被釋放
現在這里面GPU顯存 = 基礎配置(1001MiB) + y(918MiB) + x(忽略不計)
最后我們再來把y這部分釋放掉
令 y = 2
,那么原來y所指的那部分顯存空間就會變成unactivate,我們可以使用torch.cuda.empty_cache()
把這部分空間釋放掉
最終只剩下基礎配置的GPU顯存占用(這部分已經無法釋放了)
四、torch.cuda.memory_summary()查看顯存信息
使用print(torch.cuda.memory_summary())
可以看到更多關于cuda顯存的信息
五、寫在最后
經過上面的摸索,我感覺這部分內容跟操作系統的內存管理有點像,所以說計算機的那幾門基礎課真的很重要,大家都要好好學一學!
當然實際中cuda的顯存管理肯定沒有那么簡單,有興趣的同學可以繼續探究下。
原文鏈接:https://blog.csdn.net/qq_43827595/article/details/115722953
相關推薦
- 2023-03-01 Android使用AndroidUtilCode實現多語言_Android
- 2024-03-03 layui 表格select下拉不顯示全的問題
- 2022-05-13 Django-Cookies && Session
- 2022-08-17 Win2008系統搭建DHCP服務器_win服務器
- 2022-10-21 React封裝全屏彈框的方法_React
- 2022-04-04 切換路由時如何關閉上一個頁面的所有請求-axios cancelToken
- 2022-12-24 Android自定義View實現繪制水波浪溫度刻度表_Android
- 2022-06-16 Beego中ORM操作各類數據庫連接方式詳細示例_Golang
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支