for batch_idx, sample in enumerate(self.data_loader):
        self.writer.set_step((epoch - 1) * len(self.data_loader) + batch_idx)

        # get data and send them to GPU
        blurred = sample['blurred'].to(self.device)
        sharp = sample['sharp'].to(self.device)

        # get G's output
        deblurred = self.generator(blurred)

        # denormalize
        with torch.no_grad():
            denormalized_blurred = denormalize(blurred)
            denormalized_sharp = denormalize(sharp)
            denormalized_deblurred = denormalize(deblurred)

        if batch_idx % 100 == 0:
            # save blurred, sharp and deblurred image
            self.writer.add_image('blurred', make_grid(denormalized_blurred.cpu()))
            self.writer.add_image('sharp', make_grid(denormalized_sharp.cpu()))
            self.writer.add_image('deblurred', make_grid(denormalized_deblurred.cpu()))

        # get D's output
        sharp_discriminator_out = self.discriminator(sharp)
        # deblurred_discriminator_out = self.discriminator(deblurred)
        deblurred_discriminator_out = self.discriminator(deblurred.detach())

        # set critic_updates
        if self.config['loss']['adversarial'] == 'wgan_gp_loss':
            critic_updates = 5
        else:
            critic_updates = 1

        # train discriminator
        discriminator_loss = 0
        for i in range(critic_updates):
            self.discriminator_optimizer.zero_grad()
           
            # train discriminator on real and fake
            if self.config['loss']['adversarial'] == 'wgan_gp_loss':
                gp_lambda = self.config['others']['gp_lambda']
                alpha = random.random()
                interpolates = alpha * sharp + (1 - alpha) * deblurred
                interpolates_discriminator_out = self.discriminator(interpolates)
                kwargs = {
                    'gp_lambda': gp_lambda,
                    'interpolates': interpolates,
                    'interpolates_discriminator_out': interpolates_discriminator_out,
                    'sharp_discriminator_out': sharp_discriminator_out,
                    'deblurred_discriminator_out': deblurred_discriminator_out
                }
                wgan_loss_d, gp_d = self.adversarial_loss('D', **kwargs)
              
                discriminator_loss_per_update = wgan_loss_d + gp_d

                self.writer.add_scalar('wgan_loss_d', wgan_loss_d.item())
                self.writer.add_scalar('gp_d', gp_d.item())
            elif self.config['loss']['adversarial'] == 'gan_loss':
                kwargs = {
                    'sharp_discriminator_out': sharp_discriminator_out,
                    'deblurred_discriminator_out': deblurred_discriminator_out
                }
                gan_loss_d = self.adversarial_loss('D', **kwargs)
                discriminator_loss_per_update = gan_loss_d

                self.writer.add_scalar('gan_loss_d', gan_loss_d.item())
            else:

                raise NotImplementedError
         
            discriminator_loss_per_update.backward(retain_graph=True)
            discriminator_loss += discriminator_loss_per_update.item()
            self.discriminator_optimizer.step()


        discriminator_loss /= critic_updates