自学内容网 自学内容网

pytorch显存管理_前向传播中间激活存储(intermediate activation)

一 激活值存储

# pytorch显存管理、前向传播中间激活存储(intermediate activation)和torch.utils.checkpoint
如何理解激活值留在显存中,可以通过以下例子
测试代码

import torch
from torch.utils.checkpoint import checkpoint

class MyModel(torch.nn.Module):
    def __init__(self):
        super(MyModel, self).__init__()
        self.net1 = torch.nn.Linear(3, 300)
        self.net2 = torch.nn.Linear(300, 300)
        self.net3 = torch.nn.Linear(300, 400)
        self.net4 = torch.nn.Linear(400, 300)
        self.net5 = torch.nn.Linear(300, 100)
        self.activation_sum = 0
        self.activation_size = 0

    def forward(self, x):
        x = self.net1(x)
        self.activation_sum += x.nelement()
        self.activation_size += (x.nelement() * x.element_size())
        x = self.net2(x)
        self.activation_sum += x.nelement()
        self.activation_size += (x.nelement() * x.element_size())
        x = self.net3(x)
        self.activation_sum += x.nelement()
        self.activation_size += (x.nelement() * x.element_size())
        x = self.net4(x)
        self.activation_sum += x.nelement()
        self.activation_size += (x.nelement() * x.element_size())
        x = self.net5(x)
        self.activation_sum += x.nelement()
        self.activation_size += (x.nelement() * x.element_size())
        return x
def modelSize(model):
    param_size = 0
    param_sum = 0
    for param in model.parameters():
        param_size += param.nelement() * param.element_size()
        param_sum += param.nelement()
    buffer_size = 0
    buffer_sum = 0
    for buffer in model.buffers():
        buffer_size += buffer.nelement() * buffer.element_size()
        buffer_sum += buffer.nelement()
    all_size = (param_size + buffer_size)
    return all_size

device = torch.device("cuda:0")

input = torch.randn(10, 3).to(device)
label = torch.randn(10, 100).to(device)

torch.cuda.empty_cache()
before = torch.cuda.memory_allocated()
model = MyModel().to("cuda:0")
after = torch.cuda.memory_allocated()
print("建立模型前显存{}".format( before))
print("建立模型后显存{}".format(after ))
print("建立模型后显存变大{}".format(after - before))

print("模型大小为{}".format(modelSize(model)))

loss_fn = torch.nn.MSELoss()
optimizer = torch.optim.SGD(model.parameters(), lr=0.01)
model.train()
optimizer.zero_grad()

before = torch.cuda.memory_allocated()
print("模型前向传播前使用显存为{}".format(before))

output = model(input)  # 前向传播

after = torch.cuda.memory_allocated()
print("模型前向传播后使用显存为{},差值(中间激活)为{}".format(after, after - before))

loss = loss_fn(output, label)
torch.autograd.backward(loss)
optimizer.step()
建立模型前显存4608
建立模型后显存1457152
建立模型后显存变大1452544
模型大小为1449200
模型前向传播前使用显存为1457152
模型前向传播后使用显存为1514496,差值(中间激活)为57344
二 模型存储

其中,关于模型大小的model.parameters()与model.buffer()内容,可以查看
# Pytorch模型中的parameter与buffer
# pytorch中的parameter与buffer
简而言之,反向传播中需要被更新的是model.parameters(),不需要更新的是model.buffer()
比如:Transformer中word embedding需要更新,使用model.parameters(),而 position embedding不需要更新,使用model.buffer()

三 显存分配
  • memory_allocated():表示当前已分配并正在使用的内存。
  • memory_cached():表示已经分配但当前未使用的内存,处于缓存状态,可能会被重用或释放。
import torch

# 设定设备为GPU
device = torch.device('cuda')

# 第一步:模拟内存分配
tensor1 = torch.randn(1024, 1024, device=device)  # 1MB 的数据
tensor2 = torch.randn(2048, 2048, device=device)  # 4MB 的数据

# 打印分配和缓存内存
print("Before empty_cache:")
print(f"Allocated Memory: {torch.cuda.memory_allocated()} bytes")
print(f"Cached Memory: {torch.cuda.memory_reserved()} bytes")

# 第二步:释放 tensor1
del tensor1

# 打印分配和缓存内存(仍然会保留一部分内存)
print("\nAfter deleting tensor1 (without empty_cache):")
print(f"Allocated Memory: {torch.cuda.memory_allocated()} bytes")
print(f"Cached Memory: {torch.cuda.memory_reserved()} bytes")

# 删除 tensor2 以确保没有其他变量占用内存
del tensor2

# 第三步:清理缓存
torch.cuda.empty_cache()

# 打印分配和缓存内存(应该会减少缓存内存)
print("\nAfter calling empty_cache:")
print(f"Allocated Memory: {torch.cuda.memory_allocated()} bytes")
print(f"Cached Memory: {torch.cuda.memory_reserved()} bytes")

结果

Before empty_cache:
Allocated Memory: 20971520 bytes
Cached Memory: 20971520 bytes

After deleting tensor1 (without empty_cache):
Allocated Memory: 16777216 bytes
Cached Memory: 20971520 bytes

After calling empty_cache:
Allocated Memory: 0 bytes
Cached Memory: 0 bytes

没有显式释放内存:虽然你删除了 data,但如果在前向传播中没有做显式的内存释放操作(如 torch.cuda.empty_cache()),GPU 会继续保留内存缓存,系统并不会自动回收未使用的缓存内存。
PyTorch 的内存管理机制:PyTorch 默认不会释放未使用的内存,而是会将其标记为缓存,用于后续的操作。这是为了减少频繁的显存分配与释放的开销,所以即使内存不再被使用,缓存的内存可能仍然会保持不变。

  • 爆显存 是指 memory_allocated() 超过了 GPU 显存的最大容量,这通常会导致程序崩溃或报错(如 “CUDA out of memory”)。
  • memory_cached() 超过显存并不会导致爆显存,因为这部分内存是缓存,可以被框架动态回收或重新分配
四 python中内存管理

python中设置为None并不能清空内存

1 设置为None的作用

将这些变量赋值为 None 只是清除了它们在 Python 内存中的引用,而并不会立即释放显存。仅仅删除 Python 中的引用并不意味着 GPU 显存会立刻被释放。

2 显存无法释放的原因

即使你将变量赋值为 None,如果这些变量在其他地方仍然被引用,或者有其他地方保存了该变量的引用(比如在计算图中或缓存中),显存也不会被释放。在框架中,张量(tensor)通常在计算图中仍然保持引用,直到反向传播或者其他操作完成

举例

import torch

# 设定设备为GPU
device = torch.device('cuda')

# 第一步:模拟内存分配
tensor1 = torch.randn(1024, 1024, device=device)  # 1MB 的数据
tensor2 = torch.randn(2048, 2048, device=device)  # 4MB 的数据

# 打印分配和缓存内存
print("Before empty_cache:")
print(f"Allocated Memory: {torch.cuda.memory_allocated()} bytes")
print(f"Cached Memory: {torch.cuda.memory_reserved()} bytes")

tensor3 =tensor1  # 4MB 的数据
tensor4 =tensor2  # 4MB 的数据
print("Before empty_cache3:")
print(f"Allocated Memory: {torch.cuda.memory_allocated()} bytes")
print(f"Cached Memory: {torch.cuda.memory_reserved()} bytes")

# 第二步:释放 tensor1
del tensor1

# 打印分配和缓存内存(仍然会保留一部分内存)
print("\nAfter deleting tensor1 (without empty_cache):")
print(f"Allocated Memory: {torch.cuda.memory_allocated()} bytes")
print(f"Cached Memory: {torch.cuda.memory_reserved()} bytes")

# 删除 tensor2 以确保没有其他变量占用内存
del tensor2

# 第三步:清理缓存
torch.cuda.empty_cache()

# 打印分配和缓存内存(应该会减少缓存内存)
print("\nAfter calling empty_cache:")
print(f"Allocated Memory: {torch.cuda.memory_allocated()} bytes")
print(f"Cached Memory: {torch.cuda.memory_reserved()} bytes")

打印语句

Before empty_cache:
Allocated Memory: 20971520 bytes
Cached Memory: 20971520 bytes
Before empty_cache3:
Allocated Memory: 20971520 bytes
Cached Memory: 20971520 bytes

After deleting tensor1 (without empty_cache):
Allocated Memory: 20971520 bytes
Cached Memory: 20971520 bytes                                                                                                                                                                                     parallel-size', 

After calling empty_cache:                                                                                                                                                                                        parallel-size', 
Allocated Memory: 20971520 bytes
Cached Memory: 20971520 bytes

其中没有一个显存释放。
只有同时删除

# 第二步:释放 tensor1
del tensor1
del tensor3

或者

tensor1 = None
tensor3 = None

才能清除变量所占用的内存空间


原文地址:https://blog.csdn.net/m0_49448331/article/details/144021865

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!