网站服务器报价,英语培训网站模板,公司网页制作h5,新图闻提供的产品和服务计算图与CUDA OOM
在实践过程中多次碰到了CUDA OOM的问题#xff0c;有时候这个问题是很好解决的#xff0c;有时候DEBUG一整天还是头皮发麻。
最近实践对由于计算图积累导致CUDA OOM有一点新的看法#xff0c;写下来记录一下。包括对计算图的一些看法和一个由于计算图引发…计算图与CUDA OOM
在实践过程中多次碰到了CUDA OOM的问题有时候这个问题是很好解决的有时候DEBUG一整天还是头皮发麻。
最近实践对由于计算图积累导致CUDA OOM有一点新的看法写下来记录一下。包括对计算图的一些看法和一个由于计算图引发错误的简化实例记录。
本人能力有限认识片面如果犯了错误希望大家指教
计算图的存储
计算图是pytorch进行梯度反向传播核心计算图是在程序运行过程中动态产生的当tensor变量赋予了requires_gradTrue的属性时torch会自动记录其参与的计算并形成计算图保存在显存中。
敲重点计算图是会吃显存的 本来想截下来描述一下计算图是长什么样的至少是概念的表述一下结果去学习了一圈发现和我想的完全不一样附上学习链接传送门。更关键的是我还没完全看懂学会有没有大大学会了教我一下不甚感激
总的来说一个tensor它内部包含的grad_fn别有洞天首先grad_fn也是作为一个节点在计算图中的其在pytorch的C艹中是Node的子类grad_fn不仅是记录了这个tensor是被什么数学符号计算来的它还暗搓搓记录了这个tensor是是从哪些数字里头窜出来的以及其和其他grad_fn的py友谊还有被包含在其内部context中的信息我偷那个学习链接的一张图展示一下一个计算图的形态借花献佛展示一下grad_fn偷偷摸摸用你的卡干了啥事情。
BTW提几个小知识点
我们常用的detach()方法就是通过把tensor的grad_fn扬了从而把tensor从计算图中剥离出来。 x
tensor([1.], requires_gradTrue)y x1y.grad_fn
AddBackward0 object at 0x7f8306e68b50y.detach().grad_fn is None
True关于*.backward(retain_graphTrue)的问题backward中retain_graph默认是False其含义是经过默认的*.backward()之后计算图会被清空从而释放其占用的显存。和detach不一样的是grad_fn还是那个grad_fn只不过它悄咪咪维持的友谊被杀掉了如下 x
tensor([1.], requires_gradTrue)y x1; y.grad_fn
AddBackward0 object at 0x7f8306e68b50y.backward(retain_graphFalse)y.grad_fn
AddBackward0 object at 0x7f8306e68b50续上面一点的内容但是内容包含我瞎猜的成分我们猜测一下backward杀掉了grad_fn的什么东西。一般的我们认为当retain_graphFalse的时候我们只能backward()一次因为计算图会被清空第二次尝试反向传播会造成错误。但其实不然如下实验例子1的尝试我们连续backwrad并没有报错。AMAZING啊。进一步的我们进行例子2的实验我们只是简单的让前向多了一个乘法计算然后另z反向传播两次这回顺理成章的报错同时报错之后我们再次反传y我们发现反传y又不会报错。我猜测backward()会清楚grad_fn节点和其他grad_fn的联系因此z的grad_fn不能联系到y的grad_fn了于是第二次z.backward()报错但是y直接和叶子x连接不需要其他的grad_fn朋友也能自己和自己玩。
例子1:x
tensor([1.], requires_gradTrue)y x1y.backward(retain_graphFalse);y.backward()
返回没有报错
---------------------------------------------------------------
例子2:x
tensor([1.], requires_gradTrue)yx1;z2*y #前向过程多了一个乘法z.backward(retain_graphFalse)z.backward()
Traceback (most recent call last):File stdin, line 1, in moduleFile /Users/**/opt/anaconda3/lib/python3.8/site-packages/torch/_tensor.py, line 487, in backwardtorch.autograd.backward(File /Users/**/opt/anaconda3/lib/python3.8/site-packages/torch/autograd/__init__.py, line 200, in backwardVariable._execution_engine.run_backward( # Calls into the C engine to run the backward pass
RuntimeError: Trying to backward through the graph a second time (or directly access saved tensors after they have already been freed). Saved intermediate values of the graph are freed when you call .backward() or autograd.grad(). Specify retain_graphTrue if you need to backward through the graph a second time or if you need to access saved tensors after calling backward.
y.backward()
返回没有报错一个由于没处理好计算图导致OOM的例子
import torch,time
l1 torch.nn.Linear(1000,1000).cuda()
l2 torch.nn.Linear(1000,1000).cuda()
memory []for _ in range(10000000):time.sleep(0.01)data_input torch.rand(1000).cuda()output l1(l2(data_input))output.backward(retain_graphTrue) #此行与报错无关 memroy.append(output.cpu()) #memory存储的内容通过.cpu()转移在主存上#但是与output相关联的l1,l2的计算图依旧停留在显存中并在循环中一直积累撑爆显存。...some other operations...这个例子中由于每个output不能被正常清除计算图显存最终导致OOM。
这个例子是某次实践的超级简化版如果只看这个例子的话其实只要把最后一行改写成
memory.append(output.detach().cpu())就会由于output在每次循环后失去引用detach()创建了新的变量从而被回收计算图被自动清空避免OOM。