提前说明一下,GAN生成的图像数据估计是各大博主做的不好。我只是发表我的理解和我的步骤。大家加油,找个好的博客,试着去了解一下。文末有完整代码。最好看代码,用思路解释一下饭。GAN生成对抗网络,经典理论主要由生成器和判别器两部分组成,生成器生成一张与数据集相似的新图片,让判别器区分这张图片是真实图片还是生成图片。两者相互对立,提高了判别器的判别能力,促使生成器生成更接近真实图片的图片;生成器生成更多“真实”图片后,提示鉴别器提高识别能力。当然,我们想要的往往是一个生成新图片(或其他数据)的生成器。自己训练的时候要注意:生成器和判别器必须“势均力敌”才能得到好的生成器。可以适当调整两者的学习进度,比如在真实图片中加入噪声干扰判别器的学习,调整两者的学习率,调整训练次数(比如Train1discriminatortotrain5台发电机)等。实现思路准备导入包,image_size为28×28,后面会用到,我直接把一张图片处理成[1,28×28]向量。然后一个工具类,为了查看dataloader中的数据,其实没什么用,可以自己写版本。importtorchimporttorch.utils.dataimporttorch.nnasnnimportmatplotlib.pyplotaspltimporttorchvision.transformsastransformsimporttorchvisionDEVICE='cuda'iftorch.cuda.is_available()else'cpu'BATCH_SIZE=128IMAGE_SIZE=28*28eslengthaswelldefShowDataLoader(dataloader,num):i=0forimgs,dataloader中的labs:print("imgs",imgs.shape)print("labs",labs.shape)i+=1ifi==num:Breakreturnloadsthe数据集并加载图片。自然要先对图片进行预处理。Torchvision提供了很多功能帮助。Transform先变成tensor,再对其进行正则化。由于不想用到那么多数据,所以对数据进行了划分,只取出了32*1500条数据。如果limi的MNIST中没有数据集,可以直接下载,设置download=True即可。然后加载pytrochdataloader,基本操作pytorch。如果__name__=='__main__':transform=transforms.Compose([transforms.ToTensor(),transforms.Normalize(mean=[0.5],std=[0.5])])#loadmnistmnist=torchvision.datasets.MNIST(root="./data-source",train=True,transform=transform)#splitdatasetwhole_length=len(mnist)#数据长度应该是能被bath_size整除的数sub_length=32*1500sub_minist1,sub_minist2=torch.utils.data.random_split(mnist,[sub_length,whole_length-sub_length])#加载数据集dataloader=torch.utils.data.DataLoader(dataset=sub_minist1,batch_size=BATCH_SIZE,shuffle=True)#plt.imshow(next(iter(dataloader))[0][0][0])#plt.show()方便使用sequential创建判别器和生成器等,声明两个网络。选择BCELoss作为损失函数,优化器也可以使用其他的,两个网络,每人一个优化器。判别器的输入好说,不管是真还是假,都是一批batch的图片。生成器输入的经典论文推荐了一个latentvector,其实就是一个随机生成的向量。生成器更改后,生成成一批图像数据。学习率也是可调的,取决于训练情况。鉴别器=nn.Sequential(nn.Linear(IMAGE_SIZE,300),nn.LeakyReLU(0.2),nn.Linear(300,150),nn.LeakyReLU(0.2),nn.Linear(150,1),nn.Sigmoid())Discriminator=Discriminator.to(DEVICE)latent_size=64Generator=nn.Sequential(nn.Linear(latent_size,150),nn.ReLU(True),nn.Linear(150,300),nn.ReLU(True),nn.Linear(300,IMAGE_SIZE),nn.Tanh()#将其改为(-1,1))Generator=Generator.to(DEVICE)loss_fn=nn.BCELoss()d_optimizer=torch.optim.SGD(Discriminator.parameters(),lr=0.002)g_optimizer=torch.optim.Adam(Generator.parameters(),lr=0.002)training训练代码格式,经典的pytorch写法我就不用多解释了。实现的时候,我有这样的想法:通过矩阵变换,变成一张图片和一个向量,维度为[1,28*28]。首先计算判别器的损失,它来自两部分,一部分是真实数据,另一部分是生成器产生的数据。由于我们的标签不是MNIST的标签,而是应该标明图片真实性的标签,所以我们需要自己制作标签。两部分损失向后后,判别器的训练就完成了。如果生成器生成的图片被鉴别器判断为假的,它就会失败,所以它希望它生成的图片的标签应该是“真”。所以loss就是判别器的结果与全真值向量相比的BCEloss。loader_len=len(dataloader)EPOCH=30G_EPOCH=1forepochinrange(EPOCH):fori,(images,_)inenumerate(dataloader):images=images.reshape(images.shape[0],IMAGE_SIZE)。to(DEVICE)#噪音干扰#noise=torch.randn(images.shape[0],IMAGE_SIZE)#images=noise+images#makelabelsfortraininglabel_real_pic=torch.ones(BATCH_SIZE,1).to(DEVICE)label_fake_pic=torch.zeros(BATCH_SIZE,1).to(DEVICE)#查看真实图像ifi%100==0:plt.title('real')data=images.view(BATCH_SIZE,28,28).data.cpu().numpy()plt.imshow(data[0])plt.pause(1)#计算“真实部分”的损失res_real=Discriminitor(images)d_loss_real=loss_fn(res_real,label_real_pic)#calculateloss的“假部分”#generatefakeimagez=torch.randn(BATCH_SIZE,latent_size).to(DEVICE)fake_imgs=Generator(z)res_fake=Discriminitor(fake_imgs.detach())#detach表示固定参数。d_loss_fake=loss_fn(res_fake,label_fake_pic)d_loss=d_loss_fake+d_loss_real#updatediscriminatormodeld_optimizer.zero_grad()d_loss.backward()d_optimizer.step()#changeG_EPOCH修改鉴别器在范围内的epoch(G_EPOCH):tt=torch.randn(BATCH_SIZE,latent_size).to(DEVICE)fake1=Generator(tt)res_fake2=Discriminitor(fake1)g_loss=loss_fn(res_fake2,label_real_pic)g_optimizer.zero_grad()g_loss.backward()g_optimizer.step()如果我%50==0:print("纪元[{}/{}],步骤[{}/{}],d_loss:{:.4f},g_loss:{:.4f},".format(epoch,EPOCH,i,loader_len,d_loss.item(),g_loss.item()))#看一下generator目前怎么样temp=torch.randn(BATCH_SIZE,latent_size).to(DEVICE)fake_temp=Generator(temp)ff=fake_temp.view(BATCH_SIZE,28,28).data.cpu().numpy()plt.title('生成')plt.imshow(ff[0])plt.pause(1)的效果我的程序会在一段时间后显示当前的一个trainingbatches,既有realdata也有generateddata,代表当前的情况。generateddata可以看做是当前generator可以生成到什么程度,当然你也可以看到双方的损失,在console中可以看到。完整代码importtorchimporttorch.utils.dataimporttorch.nnasnnimportmatplotlib.pyplotaspltimporttorchvision.transformsastransformsimporttorchvisionDEVICE='cuda'iftorch.cuda.is_available()else'cpu'BATCH_SIZE=128IMAGE_SIZE=28*28#it将向量长度表示为welldefShowDataLoader(dataloader,num):i=0forimgs,dataloader中的labs:print("imgs",imgs.shape)print("labs",labs.shape)i+=1ifi==num:breakreturnif__name__=='__main__':transform=transforms.Compose([transforms.ToTensor(),transforms.Normalize(mean=[0.5],std=[0.5])])#loadmnistmnist=torchvision.datasets数据集.MNIST(root="./data-source",train=True,transform=transform)#拆分数据集whole_length=len(mnist)#数据长度应该是能被bath_size整除的数sub_length=32*1500sub_minist1,sub_minist2=torch.utils.data.random_split(mnist,[sub_length,whole_length-sub_length])#load数据集dataloader=torch.utils.data.DataLoader(dataset=sub_minist1,batch_size=BATCH_SIZE,shuffle=True)#plt.imshow(next(iter(dataloader))[0][0][0])#plt.show()Discriminitor=nn.Sequential(nn.Linear(IMAGE_SIZE,300),nn.LeakyReLU(0.2),nn.Linear(300,150),nn.LeakyReLU(0.2),nn.Linear(150,1),nn.Sigmoid())Discriminitor=Discriminitor.to(DEVICE)latent_size=64Generator=nn.Sequential(nn.Linear(latent_size,150),nn.ReLU(True),nn.Linear(150,300),nn.ReLU(True),nn.Linear(300,IMAGE_SIZE),nn.Tanh()#将其更改为(-1,1))Generator=Generator.to(DEVICE)loss_fn=nn.BCELoss()d_optimizer=torch.optim.SGD(Discriminitor.parameters(),lr=0.002)g_optimizer=torch.optim.Adam(Generator.parameters(),lr=0.002)loader_len=len(dataloader)EPOCH=30G_EPOCH=1forepochinrange(EPOCH):对于我,(图像,_)在enumerate(dataloader):images=images.reshape(images.shape[0],IMAGE_SIZE).to(DEVICE)#noise=torch.randn(images.shape[0],IMAGE_SIZE)#images=noise+imageslabel_real_pic=火炬.ones(BATCH_SIZE,1).to(DEVICE)label_fake_pic=torch.zeros(BATCH_SIZE,1).to(DEVICE)如果i%100==0:plt.title('real')data=images.view(BATCH_SIZE,28,28).data.cpu().numpy()plt.imshow(data[0])plt.pause(1)res_real=Discriminitor(images)d_loss_real=loss_fn(res_real,label_real_pic)#generatefakeimagez=torch.randn(BATCH_SIZE,latent_size).to(DEVICE)fake_imgs=Generator(z)res_fake=Discriminitor(fake_imgs.detach())#detach表示固定参数。d_loss_fake=loss_fn(res_fake,label_fake_pic)d_loss=d_loss_fake+d_loss_reald_optimizer.zero_grad()d_loss.backward()d_optimizer.step()forjinrange(G_EPOCH):tt=torch.randn(BATCH_SIZE,latent_size).to(DEVICE)fake1=Generator(tt)res_fake2=Discriminitor(fake1)g_loss=loss_fn(res_fake2,label_real_pic)g_optimizer.zero_grad()g_loss.backward()g_optimizer.step()ifi%50==0:print("Epoch[{}/{}],Step[{}/{}],d_loss:{:.4f},g_loss:{:.4f},".format(epoch,EPOCH,i,loader_len,d_loss.item(),g_loss.item()))temp=torch.randn(BATCH_SIZE,latent_size).to(DEVICE)fake_temp=Generator(temp)ff=fake_temp.view(BATCH_SIZE,28,28).data.cpu().numpy()plt.title('generated')plt.imshow(ff[0])plt.暂停(1)
