我正在尝试实现一个CGAN。我明白在卷积生成器和判别器模型中,通过增加代表标签的深度来增加输入的体积。因此,如果你的数据中有10个类别,那么你的生成器和判别器的输入体积都将是基础深度加上10。
然而,我在网上查看了各种实现方式,但似乎找不到他们实际获取标签的地方。CGAN肯定不能是无监督的,因为你需要获取标签来输入。例如,在cifar10中,如果你在训练判别器处理一只青蛙的真实图像,你需要’青蛙’的注释。
这是我正在研究的一段代码:
class CGAN(object):def __init__(self, args): # parameters self.epoch = args.epoch self.batch_size = args.batch_size self.save_dir = args.save_dir self.result_dir = args.result_dir self.dataset = args.dataset self.log_dir = args.log_dir self.gpu_mode = args.gpu_mode self.model_name = args.gan_type self.input_size = args.input_size self.z_dim = 62 self.class_num = 10 self.sample_num = self.class_num ** 2 # load dataset self.data_loader = dataloader(self.dataset, self.input_size, self.batch_size) data = self.data_loader.__iter__().__next__()[0] # networks init self.G = generator(input_dim=self.z_dim, output_dim=data.shape[1], input_size=self.input_size, class_num=self.class_num) self.D = discriminator(input_dim=data.shape[1], output_dim=1, input_size=self.input_size, class_num=self.class_num) self.G_optimizer = optim.Adam(self.G.parameters(), lr=args.lrG, betas=(args.beta1, args.beta2)) self.D_optimizer = optim.Adam(self.D.parameters(), lr=args.lrD, betas=(args.beta1, args.beta2)) if self.gpu_mode: self.G.cuda() self.D.cuda() self.BCE_loss = nn.BCELoss().cuda() else: self.BCE_loss = nn.BCELoss() print('---------- Networks architecture -------------') utils.print_network(self.G) utils.print_network(self.D) print('-----------------------------------------------') # fixed noise & condition self.sample_z_ = torch.zeros((self.sample_num, self.z_dim)) for i in range(self.class_num): self.sample_z_[i*self.class_num] = torch.rand(1, self.z_dim) for j in range(1, self.class_num): self.sample_z_[i*self.class_num + j] = self.sample_z_[i*self.class_num] temp = torch.zeros((self.class_num, 1)) for i in range(self.class_num): temp[i, 0] = i temp_y = torch.zeros((self.sample_num, 1)) for i in range(self.class_num): temp_y[i*self.class_num: (i+1)*self.class_num] = temp self.sample_y_ = torch.zeros((self.sample_num, self.class_num)).scatter_(1, temp_y.type(torch.LongTensor), 1) if self.gpu_mode: self.sample_z_, self.sample_y_ = self.sample_z_.cuda(), self.sample_y_.cuda()def train(self): self.train_hist = {} self.train_hist['D_loss'] = [] self.train_hist['G_loss'] = [] self.train_hist['per_epoch_time'] = [] self.train_hist['total_time'] = [] self.y_real_, self.y_fake_ = torch.ones(self.batch_size, 1), torch.zeros(self.batch_size, 1) if self.gpu_mode: self.y_real_, self.y_fake_ = self.y_real_.cuda(), self.y_fake_.cuda() self.D.train() print('training start!!') start_time = time.time() for epoch in range(self.epoch): self.G.train() epoch_start_time = time.time() for iter, (x_, y_) in enumerate(self.data_loader): if iter == self.data_loader.dataset.__len__() // self.batch_size: break z_ = torch.rand((self.batch_size, self.z_dim)) y_vec_ = torch.zeros((self.batch_size, self.class_num)).scatter_(1, y_.type(torch.LongTensor).unsqueeze(1), 1) y_fill_ = y_vec_.unsqueeze(2).unsqueeze(3).expand(self.batch_size, self.class_num, self.input_size, self.input_size) if self.gpu_mode: x_, z_, y_vec_, y_fill_ = x_.cuda(), z_.cuda(), y_vec_.cuda(), y_fill_.cuda() # update D network self.D_optimizer.zero_grad() D_real = self.D(x_, y_fill_) D_real_loss = self.BCE_loss(D_real, self.y_real_) G_ = self.G(z_, y_vec_) D_fake = self.D(G_, y_fill_) D_fake_loss = self.BCE_loss(D_fake, self.y_fake_) D_loss = D_real_loss + D_fake_loss self.train_hist['D_loss'].append(D_loss.item()) D_loss.backward() self.D_optimizer.step() # update G network self.G_optimizer.zero_grad() G_ = self.G(z_, y_vec_) D_fake = self.D(G_, y_fill_) G_loss = self.BCE_loss(D_fake, self.y_real_) self.train_hist['G_loss'].append(G_loss.item()) G_loss.backward() self.G_optimizer.step()
看起来y_vec_
和y_fill_
是图像的标签,但在y_fill_
的实例中,它用于给判别器标记真实图像,等于y_fill_ = y_vec_.unsqueeze(2).unsqueeze(3).expand(self.batch_size, self.class_num, self.input_size, self.input_size)
似乎它没有从数据集中获取任何关于标签的信息?它是如何给判别器提供正确的标签的?
谢谢!
回答:
y_fill_
基于y_vec_
,而y_vec_
基于y_
,所以它们是从小批量中读取标签信息的,这是正确的。你可能会对scatter
操作感到困惑,基本上代码所做的是将标签转换为独热编码