pytorch多个反向传播

pytorch多个反向传播

标签: pytorch


之前我的一篇文章pytorch 计算图以及backward,讲了一些pytorch中基本的反向传播,理清了梯度是如何计算以及下降的,建议先看懂那个,然后再看这个。

从一个错误说起:RuntimeError: Trying to backward through the graph a second time, but the buffers have already been freed

在深度学习中,有些场景需要进行两次反向,比如Gan网络,需要对D进行一次,还要对G进行一次,很多人都会遇到上面这个错误,这个错误的意思就是尝试对一个计算图进行第二次反向,但是计算图已经释放了。其实看简单点和我们之前的backward一样,当图进行了一次梯度更新,就会把一些梯度的缓存给清空,为了避免下次叠加,但在Gan这种情形下,我们必须要二次更新,那怎么办呢。有两种方案:

方案一:

这是网上大多数给出的解决方案,在第一次反向时候加入一个l2.backward(),这样就能避免释放掉了。

方案二:

上面的方案虽然解决了问题,但是并不优美,因为我们用Gan的时候,D和G两者的更新并无联系,二者的联系仅仅是D里面用到了G的输出,而这个输出一般我们都是直接拿来用的,而问题就出现在这里。下面给一个模拟:

data = torch.randn(4,10)

model1 = torch.nn.Linear(10,2)
model2 = torch.nn.Linear(2,2)

optimizer1 = torch.optim.Adam(model1.parameters(), lr=0.001,betas=(0.5, 0.999))
optimizer2 = torch.optim.Adam(model2.parameters(), lr=0.001,betas=(0.5, 0.999))

loss = torch.nn.CrossEntropyLoss()
data = torch.randn(4,10)
label = torch.Tensor([0,1,1,0]).long()
for i in range(20):
    a = model1(data)
    b = model2(a)
    l1 = loss(a,label)
    l2 = loss(b,label)
    optimizer2.zero_grad()
    l2.backward()
    optimizer2.step()

    optimizer1.zero_grad()
    l1.backward()
    optimizer1.step()

上面定义了两个模型,而model2的输入是model1的输出,而更新的时候,二者都是各自更新自己的参数,并无联系,但是上面的代码会报一个RuntimeError: Trying to backward through the graph a second time, but the buffers have already been freed 这样的错,解决方案可以是l2.backward(retain_graph=True)。除此之外我们还可以是b = model2(a.detach()),这个就优美一点,a.detach()a的区别你可以打印出来看一下,其实a.detach()是没有梯度的,所以相当于一个单纯的数字,和model1就脱离了联系,这样model2和model1就是完全分离开来的两个图,但是如果用的是a则model2和model1则仍然公用一个图,所以导致了错误。可以看下面示意图(这个是我猜测,帮助理解):

2019-11-26_101938.jpg

左边相当于直接用a而右边则用a.detach(),类似的在Gan网络里面D的输入可以改为G的输出y_fake.detach()

但有一点需要注意的是,两个网络一定没有需要共同更新的 ,假如上面的optimizer2 = torch.optim.Adam(itertools.chain(model1.parameters(),model2.parameters()), lr=0.001,betas=(0.5, 0.999)),则还是用retain_graph=True保险,因为.detach则model2反向不会传播到model1,导致不对model1里面参数更新。

关于PyTorch反向传播不起作用的问题,可能有几个常见的原因。请确保您的代码中包含以下几个步骤: 1. 定义模型:首先,您需要定义一个模型,包括网络结构和参数。 2. 定义损失函数:根据您的任务类型,选择适当的损失函数(例如交叉熵损失函数)。 3. 定义优化器:选择一个合适的优化器(如SGD或Adam),用于更新模型的参数。 4. 前向传播:将输入数据通过模型,计算预测输出。 5. 计算损失:使用预测输出和真实标签计算损失值。 6. 反向传播:调用`loss.backward()`方法,计算梯度。 7. 更新参数:调用优化器的`optimizer.step()`方法,根据梯度更新模型的参数。 如果您按照上述步骤进行操作,但仍然无法使PyTorch反向传播起作用,请尝试检查以下几个可能的问题: 1. 确保您的模型参数需要梯度:在定义模型时,确保将`requires_grad=True`设置为所有需要计算梯度的参数。 2. 确保将模型和数据移至正确的设备:如果您使用GPU进行训练,请将模型和数据移至GPU设备上,使用`.to(device)`方法。 3. 检查损失函数的输入和标签的维度匹配:确保您的损失函数接收正确的输入和标签,并且它们的维度是匹配的。 4. 检查学习率和其他优化器参数:如果学习率设置过高或过低,可能会影响梯度更新的效果。您可以尝试调整学习率和其他优化器参数来优化训练过程。 如果您仍然遇到问题,请提供更多的代码和错误信息,以便我们更好地帮助您解决问题。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值