问题描述
我正在跟踪一个PyTorch tutorial,它使用了Huggingface Transformers库中的BERT NLP模型(特征提取器)。我不了解渐变更新的两个相互关联的代码。
(1)torch.no_grad()
本教程有一个类,其中forward()
函数在对BERT特征提取器的调用周围创建一个torch.no_grad()
块,如下所示:
bert = BertModel.from_pretrained('bert-base-uncased')
class BERTGRUSentiment(nn.Module):
def __init__(self,bert):
super().__init__()
self.bert = bert
def forward(self,text):
with torch.no_grad():
embedded = self.bert(text)[0]
(2)param.requires_grad = False
同一教程中还有另外一部分冻结了BERT参数。
for name,param in model.named_parameters():
if name.startswith('bert'):
param.requires_grad = False
我什么时候需要(1)和/或(2)?
- 如果我想使用冻结的BERT进行训练,是否需要同时启用两者?
- 如果我想培训以更新BERT,我是否需要同时禁用这两者?
此外,我运行了所有四个组合并发现:
with torch.no_grad requires_grad = False Parameters Ran
------------------ --------------------- ---------- ---
a. Yes Yes 3M Successfully
b. Yes No 112M Successfully
c. No Yes 3M Successfully
d. No No 112M CUDA out of memory
有人可以解释发生了什么事吗?为什么我为(d)而不是(b)得到CUDA out of memory
?两者都有112M可学习的参数。
解决方法
这是一个较老的讨论,多年来已经发生了一些变化(主要是由于with torch.no_grad()
是一种模式的目的。一个很好的答案,也可以找到您的问题的答案{{3} }。
但是,由于原始问题有很大的不同,所以我将避免标记为重复,尤其是由于第二部分涉及内存。
on Stackoverflow already给出了no_grad
的初始说明:
另一方面,使用了
with torch.no_grad()
是上下文管理器,用于防止计算梯度[...]。
requires_grad
冻结模型的一部分并训练其余的模型。
再次来源here。
本质上,使用requires_grad
只是禁用了网络的一部分,而no_grad
根本不会存储任何任何渐变,因为您可能会将其用于推理而不是训练。
要分析参数组合的行为,让我们调查正在发生的事情:
-
a)
和b)
根本不存储任何渐变,这意味着无论参数有多少,您都拥有更多的可用内存,因为您没有将它们保留给用户使用。潜在的向后通过。 -
c)
必须存储正向通过,以用于以后的反向传播,但是,仅存储了有限数量的参数(300万个),这仍然是可管理的。
然而, -
d)
需要存储所有1.12亿个参数的正向传递 ,这将导致内存不足。