我使用循环在我的模型中向前和向后传播。但是,我在第二个循环期间遇到错误通知,并显示以下消息:
运行时错误:尝试第二次向后浏览图表(或者在释放张量后直接访问保存的张量)。当您调用 .backward() 或 autograd.grad() 时,保存的图表中间值将被释放。如果您需要第二次向后浏览图表或者需要在向后调用后访问保存的张量,请指定retain_graph=True。
我探索了网络上可用的各种方法,确保我不会在一个循环中使用反向传播两次。看来没有必要放图了
我已尽力检查错误,但仍然没有解决办法。这是我第一次来S.O.如果描述有不清楚的地方请见谅。
有问题的代码如下(未全部显示,因为我认为没有必要)
criterion = torch.nn.MSELoss().type(data_type)
optimizer = torch.optim.Adam(net.parameters(), lr=learning_rate)
image_queue = queue.Queue()
# a separate thread for calculating a value that is used by a main thread
denoise_thread = Thread(target=lambda q, f, p: q.put(f(*p)), # q -> queue, f -> func, p -> params
args=(image_queue, non_local_means,
[benchmark_image.clone().squeeze().cpu().detach().numpy(), 3]))
denoise_thread.start()
temp_benchmark = benchmark_image.clone() # copy of the benchmark for intermediate calculations
for i in range(num_iter + 1):
optimizer.zero_grad()
out = net(net_input)
temp = benchmark_image - lagrange_multiplier
loss_net = criterion(out, decrease_image) # this loss backward normally
loss_red = criterion(out, temp) # this is where things go wrong
total_loss = loss_net + mu * loss_red
total_loss.backward() # FAIL backward!!!
# updates the benchmark value every iteration a certain number of times
if i % 30 == 0:
denoise_thread.join()
temp_benchmark = image_queue.get()
temp_benchmark = torch.from_numpy(temp_benchmark)[None, :].cuda()
temp_benchmark.requires_grad_()
# as before, it is used to update values that will be used by the main thread
denoise_thread = Thread(target=lambda q, f, p: q.put(f(*p)),
args=(image_queue, non_local_means,
[benchmark_image.clone().squeeze().cpu().detach().numpy(), 3]))
denoise_thread.start()
benchmark_image = 1 / (beta + mu) * (beta * temp_benchmark + mu * (out + lagrange_multiplier))
lagrange_multiplier = lagrange_multiplier + out - benchmark_image
optimizer.step()
if denoise_thread.is_alive():
denoise_thread.join()
我已经解决这个问题好几天了,如果我的描述中有任何不清楚的部分,请告诉我。非常感谢您的帮助! ;-)
我认为问题是由于将
out
添加到 lagrange_multiplier
并开启渐变而产生的。
这样,当您在包含
loss.backward()
的计算上调用 lagrange_multiplier
时,pytorch 将尝试再次计算模型输出的梯度,这解释了 Trying to backward through the graph a second time
的错误。
我不熟悉你的问题以及这是否是预期的行为,但一个简单的解决方法是在更新
lagrange_multiplier
时关闭渐变:
with torch.no_grad():
lagrange_multiplier = lagrange_multiplier + out - benchmark_image