Tensorflow 如何两次得到损失函数的梯度

Tensorflow 如何两次得到损失函数的梯度,tensorflow,pytorch,Tensorflow,Pytorch,以下是我试图实现的目标: 我们通常根据F(X)计算损失。但我们也定义了“对抗性损失”,即基于F(X+e)的损失e定义为dF(X)/dX乘以某个常数。损失和对抗性损失都是总损失的反向传播 在tensorflow中,此部分(获取dF(X)/dX)可按如下方式编码: grad, = tf.gradients( loss, X ) grad = tf.stop_gradient(grad) e = constant * grad 下面是我的pytorch代码: class DocReade

以下是我试图实现的目标:

我们通常根据
F(X)
计算损失。但我们也定义了“对抗性损失”,即基于
F(X+e)
的损失
e
定义为
dF(X)/dX
乘以某个常数。损失和对抗性损失都是总损失的反向传播

在tensorflow中,此部分(获取
dF(X)/dX
)可按如下方式编码:

  grad, = tf.gradients( loss, X )
  grad = tf.stop_gradient(grad)
  e = constant * grad
下面是我的pytorch代码:

class DocReaderModel(object):
    def __init__(self, embedding=None, state_dict=None):
        self.train_loss = AverageMeter()
        self.embedding = embedding
        self.network = DNetwork(opt, embedding)
        self.optimizer = optim.SGD(parameters)

    def adversarial_loss(self, batch, loss, embedding, y):
        self.optimizer.zero_grad()
        loss.backward(retain_graph=True)
        grad = embedding.grad
        grad.detach_()

        perturb = F.normalize(grad, p=2)* 0.5
        self.optimizer.zero_grad()
        adv_embedding = embedding + perturb
        network_temp = DNetwork(self.opt, adv_embedding) # This is how to get F(X)
        network_temp.training = False
        network_temp.cuda()
        start, end, _ = network_temp(batch) # This is how to get F(X)
        del network_temp # I even deleted this instance.
        return F.cross_entropy(start, y[0]) + F.cross_entropy(end, y[1])

    def update(self, batch):
        self.network.train()
        start, end, pred = self.network(batch)
        loss = F.cross_entropy(start, y[0]) + F.cross_entropy(end, y[1])
        loss_adv = self.adversarial_loss(batch, loss, self.network.lexicon_encoder.embedding.weight, y) 
        loss_total = loss + loss_adv 

        self.optimizer.zero_grad()
        loss_total.backward()
        self.optimizer.step()
我有几个问题:

1) 我将tf.stop_梯度替换为grad.detach_u()。这是正确的吗

2) 我得到了
“RuntimeError:第二次尝试通过图形反向运行,但缓冲区已被释放。第一次调用backward时指定retain\u graph=True。”
因此我在
loss.backward
处添加了
retain\u graph=True
。那个具体的错误消失了。 然而,现在我在经历了几个时代之后出现了一个内存错误(
RuntimeError:cuda运行时错误(2):在/opt/conda/conda bld/pytorch_1525909934016/work/aten/src/THC/generic/THCStorage.cu:58处内存不足
).我怀疑我没有必要保留图表


有人能告诉我pytorch在这方面的最佳实践吗?任何提示/即使是简短的评论都将受到高度赞赏。

我认为您正在尝试实现生成性对抗网络(GAN),但从代码来看,我不理解,也无法理解您试图实现的目标,因为GAN缺少一些功能。我可以看到有一个鉴别器网络模块,
DNetwork
,但缺少发电机网络模块

如果要猜的话,当你说“损失函数两次”时,我假设你的意思是,你有一个用于鉴别器网络的损失函数,另一个用于发生器网络。如果是这样的话,让我来分享一下我将如何实现一个基本的GAN模型

作为一个例子,让我们来看看这个

我将跳过不太重要的部分,在这里放大重要的部分:

  • 首先,导入PyTorch库并设置

    # Set up batch size, image size, and size of noise vector:
    bs, sz, nz = 64, 64, 100 # nz is the size of the latent z vector for creating some random noise later
    
  • 构建鉴别器模块

    class DCGAN_D(nn.Module):
        def __init__(self):
            ... truncated, the usual neural nets stuffs, layers, etc ...
        def forward(self, input):
            ... truncated, the usual neural nets stuffs, layers, etc ...
    
    class DCGAN_G(nn.Module):
        def __init__(self):
            ... truncated, the usual neural nets stuffs, layers, etc ...
        def forward(self, input):
            ... truncated, the usual neural nets stuffs, layers, etc ...
    
  • 构建一个生成器模块

    class DCGAN_D(nn.Module):
        def __init__(self):
            ... truncated, the usual neural nets stuffs, layers, etc ...
        def forward(self, input):
            ... truncated, the usual neural nets stuffs, layers, etc ...
    
    class DCGAN_G(nn.Module):
        def __init__(self):
            ... truncated, the usual neural nets stuffs, layers, etc ...
        def forward(self, input):
            ... truncated, the usual neural nets stuffs, layers, etc ...
    
  • 把它们放在一起

    netG = DCGAN_G().cuda()
    netD = DCGAN_D().cuda()
    
  • 优化器需要被告知要优化哪些变量。模块自动跟踪其变量

    optimizerD = optim.RMSprop(netD.parameters(), lr = 1e-4)
    optimizerG = optim.RMSprop(netG.parameters(), lr = 1e-4)
    
  • 鉴别器的一个前进步和一个后退步

    在这里,网络可以计算反向过程中的梯度,这取决于此函数的输入。因此,在我的情况下,我有3种类型的损失;发生器损失,分色器真实图像损失,分色器假图像损失。我可以得到三次不同净传递的损失函数梯度

    def step_D(input, init_grad):
        # input can be from generator's generated image data or input image from dataset
        err = netD(input)
        err.backward(init_grad) # backward pass net to calculate gradient
        return err # loss
    
  • 控制可训练参数[重要信息]

    模型中的可训练参数是那些需要梯度的参数

    def make_trainable(net, val):
        for p in net.parameters():
            p.requires_grad = val # note, i.e, this is later set to False below in netG update in the train loop.
    
    在TensorFlow中,该部分可按如下方式编码:
    
    梯度=tf.梯度(损失,X)
    梯度=tf.停止梯度(梯度)
    

    所以,我想这将回答你的第一个问题,“我用grad.detach_u()替换了tf.stop_u梯度。这是正确的吗?”

  • 列车环路

  • 你可以在这里看到3个不同的损失函数是如何被调用的

        def train(niter, first=True):
    
            for epoch in range(niter):
                # Make iterable from PyTorch DataLoader
                data_iter = iter(dataloader)
                i = 0
    
                while i < n:
                    ###########################
                    # (1) Update D network
                    ###########################
                    make_trainable(netD, True)
    
                    # train the discriminator d_iters times
                    d_iters = 100
    
                    j = 0
    
                    while j < d_iters and i < n:
                        j += 1
                        i += 1
    
                        # clamp parameters to a cube
                        for p in netD.parameters():
                            p.data.clamp_(-0.01, 0.01)
    
                        data = next(data_iter)
    
                        ##### train with real #####
                        real_cpu, _ = data
                        real_cpu = real_cpu.cuda()
                        real = Variable( data[0].cuda() )
                        netD.zero_grad()
    
                        # Real image discriminator loss
                        errD_real = step_D(real, one)
    
                        ##### train with fake #####
                        fake = netG(create_noise(real.size()[0]))
                        input.data.resize_(real.size()).copy_(fake.data)
    
                        # Fake image discriminator loss
                        errD_fake = step_D(input, mone)
    
                        # Discriminator loss
                        errD = errD_real - errD_fake
                        optimizerD.step()
    
                    ###########################
                    # (2) Update G network
                    ###########################
                    make_trainable(netD, False)
                    netG.zero_grad()
    
                    # Generator loss
                    errG = step_D(netG(create_noise(bs)), one)
                    optimizerG.step()
    
                    print('[%d/%d][%d/%d] Loss_D: %f Loss_G: %f Loss_D_real: %f Loss_D_fake %f'
                        % (epoch, niter, i, n,
                        errD.data[0], errG.data[0], errD_real.data[0], errD_fake.data[0]))
    
    def序列(niter,first=True):
    对于范围内的历元(niter):
    #从PyTorch数据加载器使其可用
    数据_iter=iter(数据加载器)
    i=0
    而i
    “我得到了”RuntimeError:第二次尝试通过图形反向

    PyTorch具有这种行为;为了减少GPU内存使用,在调用
    .backward()
    期间,所有中间结果(如果您有保存的激活等)都会在不再需要时被删除。因此,如果您尝试调用
    .backward())
    同样,中间结果不存在,无法执行反向传递(并且您会看到错误)

    这取决于您尝试执行的操作。您可以调用
    .backward(retain\u graph=True)
    进行向后传递,该传递不会删除中间结果,因此您可以