首页 > 编程知识 正文

pytorch softmax,crossentropyloss pytorch

时间:2023-05-04 15:25:13 阅读:175228 作者:4923

关于Pytorch网络连接中的loss.backward的问题情况一情况二情况三情况四总结

情况1

情况描述:

两个神经网络net1和net2、net1的输出是net2的输入,net1和net2的输出具有truth。 需要对这两个网络进行培训。

应用背景:

端对端仿真读写基本3 dobjectdetection的核心模块。

相关代码:

importtorchfromtorchimportnnx=torch.ones (2,3 ) *0.2net1=nn.linear ) 3,3 ) net2=nn.linear ) 3, 3 ) TGT1=TG 3 ) loss _ fun=torch.nn.MSE loss (opt1=torch.optim.Adam ) net1.parameters, 0.002 ) opt2=torch.optim 0.002 ) forIinrange(1000 ) :tmp=net1(x ) loss1=loss_fun ) tmp, tgt1 ) output=net2) tmp ) loss2=loss_fung tgt2) tol _ loss=loss2loss1opt1. zero _ grad )、tgt2.zero_grad ) output1=net1(x ) output2=net2) output1) print(f'output1:(n ) output1) ) (打印) f ) output13360 ) n ) ououout1)

两个网络都完成了成功的训练,tol_loss.backward ()实现了这个目标。

案例实验结果:

根据情况1来考虑,能否使用tol_loss.backward (为loss1.backward )和loss2.backward )来实现目标

情况描述:

importtorchfromtorchimportnnx=torch.ones (2,3 ) *0.2net1=nn.linear ) 3,3 ) net2=nn.linear ) 3, 3 ) TGT1=TG 3 ) loss _ fun=torch.nn.MSE loss (opt1=torch.optim.Adam ) net1.parameters, 0.002 ) opt2=torch.optim 0.002 ) forIinrange(1000 ) :tmp=net1(x ) loss1=loss_fun ) tmp, tgt1 ) output=net2) tmp ) loss2=loss_fung tgt2) opt1.zero_grad(opt2.zero_grad ) loss1.backward ) loss 2 loss2={loss2} ' ) output1=net1(x ) output2=net2) output1) print(f'output1:(n ) output1) ) ) print )

tryingtobackwardthroughthegraphasecondtime,butthebuffershavealreadybeenfreed.specify retain _ graph=truewhencallingbackwabackwed

这涉及到pytorch的计算图。 pytorch使用动态计算图、树的结构,我们想要优化的参数是叶节点,在forward的过程中被制作,在loss.backward () )之后被释放。 因此,如果使用loss1.backward (),net1的计算图将在free中丢失,loss2.backward ()将无法正常运行。

相关代码:

办法:
loss1.backward()改为loss1.backward(retain_graph=True),将计算图保留下来,不被清除掉就好了。但是,还是建议使用tol_loss.backward()进行反向梯度的计算。

【注意】:
这从一个方面说明了net1和net2的计算图是建立在一起的,不是分开的!!!记住这句话,对下面的情况三出现的问题才能理解。

情况三

情况描述:
在情况一的基础上,我们对net1的输出需要做一些数据的计。

应用背景: 数据增强等等

相关代码:

import torchfrom torch import nnx = torch.ones(2, 3)*0.2net1 = nn.Linear(3, 3)net2 = nn.Linear(3, 3)tgt1 = torch.ones(2, 3)*0.5tgt2 = torch.ones(2, 3)loss_fun = torch.nn.MSELoss()opt1 = torch.optim.Adam(net1.parameters(), 0.002)opt2 = torch.optim.Adam(net2.parameters(), 0.002)for i in range(3000): tmp = net1(x) loss1=loss_fun(tmp, tgt1) tmp=tmp*0.5 output = net2(tmp) loss2 = loss_fun(output, tgt2) tol_loss= loss2+loss1 opt1.zero_grad() opt2.zero_grad() tol_loss.backward() opt1.step() opt2.step() print(f'EPOCH:{i}, loss={loss1}, loss2={loss2}')output1 = net1(x)output1=output1*0.5output2 = net2(output1)print(f'output1:n {output1}')print(f'output2n {output2}')

实验结果:
发现能够完成正常的训练,但是提出一个疑问,现在net1和net2的计算图还是联系在一起的吗?

测试:
我们将tol_loss.backward()换成los1.backward()和loss2.backward()

结果:
出现同样的报错,说明此时两者的计算图还是一个。

情况四

情况描述:
如果此时改变tmp的数据类型,从tensor改为np的array类型,进行计算后在改回tensor,又会是怎样的情况?

相关代码:

import torchfrom torch import nnx = torch.ones(2, 3)*0.2net1 = nn.Linear(3, 3)net2 = nn.Linear(3, 3)tgt1 = torch.ones(2, 3)*0.5tgt2 = torch.ones(2, 3)loss_fun = torch.nn.MSELoss()opt1 = torch.optim.Adam(net1.parameters(), 0.002)opt2 = torch.optim.Adam(net2.parameters(), 0.002)for i in range(3000): tmp = net1(x) loss1=loss_fun(tmp, tgt1) tmp=tmp.detach().numpy() tmp=tmp*0.5 tmp=torch.from_numpy(tmp) tmp.requires_grad_(True) output = net2(tmp) loss2 = loss_fun(output, tgt2) opt1.zero_grad() opt2.zero_grad() loss1.backward() loss2.backward() opt1.step() opt2.step() print(f'EPOCH:{i}, loss={loss1}, loss2={loss2}')output1 = net1(x)output1=output1*0.5output2 = net2(output1)print(f'output1:n {output1}')print(f'output2n {output2}')

实验结果:
居然可以正常运行,这就说明了一个问题,现在这两个net的计算图已经是分开的了,就是说,虽然把tmp.requires_grad设置为了True,但是没有什么用,net2的梯度无法传播到net1了。(其实在这里,不设置tmp.requires_grad为True也不影响net2的更新。)我们可以做个简单的验证。

验证代码:

import torchfrom torch import nnx = torch.ones(2, 3)*0.2net1 = nn.Linear(3, 3)raw_output1=net1(x)raw_output1=raw_output1*0.5net2 = nn.Linear(3, 3)tgt1 = torch.ones(2, 3)*0.5tgt2 = torch.ones(2, 3)loss_fun = torch.nn.MSELoss()opt1 = torch.optim.Adam(net1.parameters(), 0.002)opt2 = torch.optim.Adam(net2.parameters(), 0.002)for i in range(3000): tmp = net1(x) loss1=loss_fun(tmp, tgt1) tmp=tmp.detach().numpy() tmp=tmp*0.5 tmp=torch.from_numpy(tmp) tmp.requires_grad_(True) output = net2(tmp) loss2 = loss_fun(output, tgt2) opt1.zero_grad() opt2.zero_grad() loss2.backward() opt1.step() opt2.step() print(f'EPOCH:{i}, loss={loss1}, loss2={loss2}')output1 = net1(x)output1=output1*0.5output2 = net2(output1)print(f'raw_output1:n {row_output1}')print(f'output1:n {output1}')print(f'output2n {output2}')

验证结果:

raw_output1: tensor([[ 0.0029, -0.1812, -0.0505], [ 0.0029, -0.1812, -0.0505]], grad_fn=<MulBackward0>)output1: tensor([[ 0.0029, -0.1812, -0.0505], [ 0.0029, -0.1812, -0.0505]], grad_fn=<MulBackward0>)output2 tensor([[1.0000, 1.0000, 1.0000], [1.0000, 1.0000, 1.0000]], grad_fn=<AddmmBackward>)

验证结果分析:
发现在没有进行梯度更新前的输出raw_output1和进行loss2.backward()后毫无变化,说明net2没有办法传播到net1中。

总结

网络的串联,在进行forward的所创建的动态计算图是同一个。如果不改变数据的类型,在网络串联之间做一些数据的计算是没有什么问题的。但是如果把tensor张量改成了np.array类型,就不可行了,因为这个时候,前面的计算图会和后面的计算图断开。后面网络梯度无法传播到前面的网络之中。这也就失去了cor的意义。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。