【Pytorch神经网络实战案例】15 WGAN-gp模型生成Fashon-MNST模拟数据
1 WGAN-gp模型生成模擬數(shù)據(jù)案例說明
使用WGAN-gp模型模擬Fashion-MNIST數(shù)據(jù)的生成,會使用到WGAN-gp模型、深度卷積GAN(DeepConvolutional GAN,DCGAN)模型、實例歸一化技術(shù)。
1.1 DCGAN中的全卷積
WGAN-gp模型側(cè)重于GAN模型的訓練部分,而DCGAN是指使用卷積神經(jīng)網(wǎng)絡(luò)的GAN,它側(cè)重于GAN模型的結(jié)構(gòu)部分,重點介紹在DCGAN中使用全卷積進行重構(gòu)的技術(shù)。
1.1.1 DCGAN的原理與實現(xiàn)
DCGAN的原理和GAN類似,只是把CNN卷積技術(shù)用在GAN模式的網(wǎng)絡(luò)里。生成器G在生成數(shù)據(jù)時,使用反卷積的重構(gòu)技術(shù)來重構(gòu)原始圖片,判別器D使用卷積技術(shù)來識別圖片特征,進而做出判別。同時,DCGAN中的卷積神經(jīng)網(wǎng)絡(luò)對結(jié)構(gòu)進行改變,提高樣本質(zhì)量與收斂速度。
DCGAN模型可以更好地學到對輸入圖像層次化的表示,尤其在生成器部分會有更好的模擬效果,在訓練中,會使用Adam優(yōu)化算法。
1.1.2 全卷積的實現(xiàn)
在PyTorch中,全卷積是通過轉(zhuǎn)置卷積接口ConvTranspose2d()來實現(xiàn)的。該接口的參數(shù)與卷積函數(shù)參數(shù)的含義相同,還有1D和3D的轉(zhuǎn)置卷積實現(xiàn)。
convTranspose2d (in_channels,out_channels,kernel_size,stride=1,padding=0,output_padding=0,groups=1,bias=τrue,dilation=1,padding_mode='zeros')先對卷積核進行轉(zhuǎn)置,再實現(xiàn)全卷積處理,輸出的尺寸與卷積操作所輸出的尺寸互逆。
1.2 上采樣與下采樣?
1.2.1 上下采樣的簡述
- 上采樣是將圖像放大。
- 下采樣是將圖像縮小。
上采樣與下采樣操作并不能給圖片帶來更多的信息,但會對圖像質(zhì)量產(chǎn)生影響。
在深度卷積網(wǎng)絡(luò)模型的運算中,通過上采樣與下采樣操作可實現(xiàn)本層數(shù)據(jù)與上下層的維度匹配。
1.2.2 上下采樣的作用
神經(jīng)網(wǎng)絡(luò)模型常使用窄卷積或池化對模型進行下采樣,
神經(jīng)網(wǎng)絡(luò)模型使用轉(zhuǎn)置卷積對模型進行上采樣。
1.2.3 通過卷積和全卷積函數(shù)實現(xiàn)下采樣方式處理再上采樣的方式進行還原操作。
from torch import nn import torch# 定義輸入數(shù)據(jù),3通道,尺寸為[12,12] input = torch.randn(1,3,12,12) # 輸入和輸出通道為3,卷積核為3,步長為2,進行下采樣 downsample = nn.Conv2d(3,3,3,stride=2,padding=1) h = downsample(input) print(h.size()) # 輸出結(jié)果:torch.SizeC[1,3,6,6]),尺寸變?yōu)閇6,6]# 輸入和輸出通道為3,卷積核為3,步長為2,進行上采樣還原 upsample = nn.ConvTranspose2d(3,3,3,stride=2,padding=1) output = upsample(h,output_size=input.size()) print(output.size()) # 輸出結(jié)果:torch.Size([1,3,12,12]),尺寸變回[12,12]1.3 實例歸一化
批量歸一化是對一個批次圖片中的所有像素求均值和標準差,
實例歸一化是對單一圖片進行歸一化處理,即對單個圖片的所有像素求均值和標準差
1.3.1?實例歸一化的使用場景
在對抗神經(jīng)網(wǎng)絡(luò)模型、風格轉(zhuǎn)換這類生成式任務(wù)中,常用實例歸一化取代批量歸一化,因為生成式任務(wù)的本質(zhì)是將生成樣本的特征分布與目標樣本的特征分布進行匹配。生成式任務(wù)的每個樣本都有獨立的風格,不應(yīng)該與批次中其他樣本產(chǎn)生太多聯(lián)系。因此,實例歸一化適合解決這種基于個體的樣本分布問題。
1.3.2?實例歸一化的使用
PyTorch中實例歸一化的實現(xiàn)接口是nn模塊下的InstanceNorm2d(),還有1D、3D實例歸一化,與該接口類似。
Instanceormd(num_features,eps=1e-5,momentum=0.1,affine=False,track_running_stats=False)僅關(guān)注參數(shù)num_features,該參數(shù)是需要傳入輸入數(shù)據(jù)的通道數(shù),其他參數(shù)與批量歸一化BatchNorm2d()中參數(shù)的含義一致,該接口會按照通道對單個數(shù)據(jù)進行歸一化,其返回的形狀與輸入形狀相同。
2?實例代碼編寫
2.1 代碼實戰(zhàn):引入模塊并載入樣本----WGAN-gp-228.py(第1部分)
import torch import torchvision from torchvision import transforms from torch.utils.data import DataLoader from torch import nn import torch.autograd as autograd import matplotlib.pyplot as plt import numpy as np import matplotlib import os os.environ["KMP_DUPLICATE_LIB_OK"]="TRUE"# 1.1 引入模塊并載入樣本:定義基本函數(shù),加載FashionMNIST數(shù)據(jù)集 def to_img(x):x = 0.5 * (x+1)x = x.clamp(0,1)x = x.view(x.size(0),1,28,28)return xdef imshow(img,filename = None):npimg = img.numpy()plt.axis('off')array = np.transpose(npimg,(1,2,0))if filename != None:matplotlib.image.imsave(filename,array)else:plt.imshow(array)# plt.savefig(filename) # 保存圖片 注釋掉,因為會報錯,暫時不知道什么原因 2022.3.26 15:20plt.show()img_transform = transforms.Compose([transforms.ToTensor(),transforms.Normalize(mean=[0.5],std=[0.5])] )data_dir = './fashion_mnist'train_dataset = torchvision.datasets.FashionMNIST(data_dir,train=True,transform=img_transform,download=True) train_loader = DataLoader(train_dataset,batch_size=1024,shuffle=True) # 測試數(shù)據(jù)集 val_dataset = torchvision.datasets.FashionMNIST(data_dir,train=False,transform=img_transform) test_loader = DataLoader(val_dataset,batch_size=10,shuffle=False) # 指定設(shè)備 device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") print(device)2.2 代碼實戰(zhàn):實現(xiàn)生成器和判別器----WGAN-gp-228.py(第2部分)
# 1.2 實現(xiàn)生成器和判別器 :因為復雜部分都放在loss值的計算方面了,所以生成器和判別器就會簡單一些。 # 生成器和判別器各自有兩個卷積和兩個全連接層。生成器最終輸出與輸入圖片相同維度的數(shù)據(jù)作為模擬樣本。 # 判別器的輸出不需要有激活函數(shù),并且輸出維度為1的數(shù)值用來表示結(jié)果。 # 在GAN模型中,因判別器的輸入則是具體的樣本數(shù)據(jù),要區(qū)分每個數(shù)據(jù)的分布特征,所以判別器使用實例歸一化, class WGAN_D(nn.Module): # 定義判別器類D :有兩個卷積和兩個全連接層def __init__(self,inputch=1):super(WGAN_D, self).__init__()self.conv1 = nn.Sequential(nn.Conv2d(inputch,64,4,2,1), # 輸出形狀為[batch,64,28,28]nn.LeakyReLU(0.2,True),nn.InstanceNorm2d(64,affine=True))self.conv2 = nn.Sequential(nn.Conv2d(64,128,4,2,1),# 輸出形狀為[batch,64,14,14]nn.LeakyReLU(0.2,True),nn.InstanceNorm2d(128,affine=True))self.fc = nn.Sequential(nn.Linear(128*7*7,1024),nn.LeakyReLU(0.2,True))self.fc2 = nn.Sequential(nn.InstanceNorm1d(1,affine=True),nn.Flatten(),nn.Linear(1024,1))def forward(self,x,*arg): # 正向傳播x = self.conv1(x)x = self.conv2(x)x = x.view(x.size(0),-1)x = self.fc(x)x = x.reshape(x.size(0),1,-1)x = self.fc2(x)return x.view(-1,1).squeeze(1)# 在GAN模型中,因生成器的初始輸入是隨機值,所以生成器使用批量歸一化。 class WGAN_G(nn.Module): # 定義生成器類G:有兩個卷積和兩個全連接層def __init__(self,input_size,input_n=1):super(WGAN_G, self).__init__()self.fc1 = nn.Sequential(nn.Linear(input_size * input_n,1024),nn.ReLU(True),nn.BatchNorm1d(1024))self.fc2 = nn.Sequential(nn.Linear(1024,7*7*128),nn.ReLU(True),nn.BatchNorm1d(7*7*128))self.upsample1 = nn.Sequential(nn.ConvTranspose2d(128,64,4,2,padding=1,bias=False), # 輸出形狀為[batch,64,14,14]nn.ReLU(True),nn.BatchNorm2d(64))self.upsample2 = nn.Sequential(nn.ConvTranspose2d(64,1,4,2,padding=1,bias=False), # 輸出形狀為[batch,64,28,28]nn.Tanh())def forward(self,x,*arg): # 正向傳播x = self.fc1(x)x = self.fc2(x)x = x.view(x.size(0),128,7,7)x = self.upsample1(x)img = self.upsample2(x)return img2.3?代碼實戰(zhàn):定義函數(shù)完成梯度懲罰項----WGAN-gp-228.py(第3部分)
# 1.3 定義函數(shù)compute_gradient_penalty()完成梯度懲罰項 # 懲罰項的樣本X_inter由一部分Pg分布和一部分Pr分布組成,同時對D(X_inter)求梯度,并計算梯度與1的平方差,最終得到gradient_penalties lambda_gp = 10 # 計算梯度懲罰項 def compute_gradient_penalty(D,real_samples,fake_samples,y_one_hot):# 獲取一個隨機數(shù),作為真假樣本的采樣比例eps = torch.FloatTensor(real_samples.size(0),1,1,1).uniform_(0,1).to(device)# 按照eps比例生成真假樣本采樣值X_interX_inter = (eps * real_samples + ((1-eps)*fake_samples)).requires_grad_(True)d_interpolates = D(X_inter,y_one_hot)fake = torch.full((real_samples.size(0),),1,device=device) # 計算梯度輸出的掩碼,在本例中需要對所有梯度進行計算,故需要按照樣本個數(shù)生成全為1的張量。# 求梯度gradients = autograd.grad(outputs=d_interpolates, # 輸出值outputs,傳入計算過的張量結(jié)果inputs=X_inter,# 待求梯度的輸入值inputs,傳入可導的張量,即requires_grad=Truegrad_outputs=fake, # 傳出梯度的掩碼grad_outputs,使用1和0組成的掩碼,在計算梯度之后,會將求導結(jié)果與該掩碼進行相乘得到最終結(jié)果。create_graph=True,retain_graph=True,only_inputs=True)[0]gradients = gradients.view(gradients.size(0),-1)gradient_penaltys = ((gradients.norm(2, dim=1) - 1) ** 2).mean() * lambda_gpreturn gradient_penaltys2.4?代碼實戰(zhàn):定義模型的訓練函數(shù)----WGAN-gp-228.py(第4部分)
# 1.4 定義模型的訓練函數(shù) # 定義函數(shù)train(),實現(xiàn)模型的訓練過程。 # 在函數(shù)train()中,按照對抗神經(jīng)網(wǎng)絡(luò)專題(一)中的式(8-24)實現(xiàn)模型的損失函數(shù)。 # 判別器的loss為D(fake_samples)-D(real_samples)再加上聯(lián)合分布樣本的梯度懲罰項gradient_penalties,其中fake_samples為生成的模擬數(shù)據(jù),real_Samples為真實數(shù)據(jù), # 生成器的loss為-D(fake_samples)。 def train(D,G,outdir,z_dimension,num_epochs=30):d_optimizer = torch.optim.Adam(D.parameters(),lr=0.001) # 定義優(yōu)化器g_optimizer = torch.optim.Adam(G.parameters(),lr=0.001)os.makedirs(outdir,exist_ok=True) # 創(chuàng)建輸出文件夾# 在函數(shù)train()中,判別器和生成器是分開訓練的。讓判別器學習的次數(shù)多一些,判別器每訓練5次,生成器優(yōu)化1次。# WGAN_gp不會因為判別器準確率太高而引起生成器梯度消失的問題,所以好的判別器會讓生成器有更好的模擬效果。for epoch in range(num_epochs):for i,(img,lab) in enumerate(train_loader):num_img = img.size(0)# 訓練判別器real_img = img.to(device)y_one_hot = torch.zeros(lab.shape[0],10).scatter_(1,lab.view(lab.shape[0],1),1).to(device)for ii in range(5): # 循環(huán)訓練5次d_optimizer.zero_grad() # 梯度清零# 對real_img進行判別real_out = D(real_img,y_one_hot)# 生成隨機值z = torch.randn(num_img,z_dimension).to(device)fake_img = G(z,y_one_hot) # 生成fake_imgfake_out = D(fake_img,y_one_hot) # 對fake_img進行判別# 計算梯度懲罰項gradient_penalty = compute_gradient_penalty(D,real_img.data,fake_img.data,y_one_hot)# 計算判別器的lossd_loss = -torch.mean(real_out)+torch.mean(fake_out)+gradient_penaltyd_loss.backward()d_optimizer.step()# 訓練生成器for ii in range(1): # 訓練一次g_optimizer.zero_grad() # 梯度清0z = torch.randn(num_img,z_dimension).to(device)fake_img = G(z,y_one_hot)fake_out = D(fake_img,y_one_hot)g_loss = -torch.mean(fake_out)g_loss.backward()g_optimizer.step()# 輸出可視化結(jié)果,并將生成的結(jié)果以圖片的形式存儲在硬盤中fake_images = to_img(fake_img.cpu().data)real_images = to_img(real_img.cpu().data)rel = torch.cat([to_img(real_images[:10]), fake_images[:10]], axis=0)imshow(torchvision.utils.make_grid(rel, nrow=10),os.path.join(outdir, 'fake_images-{}.png'.format(epoch + 1)))# 輸出訓練結(jié)果print('Epoch [{}/{}], d_loss: {:.6f}, g_loss: {:.6f} ''D real: {:.6f}, D fake: {:.6f}'.format(epoch, num_epochs, d_loss.data, g_loss.data,real_out.data.mean(), fake_out.data.mean()))# 保存訓練模型torch.save(G.state_dict(), os.path.join(outdir, 'generator.pth'))torch.save(D.state_dict(), os.path.join(outdir, 'discriminator.pth'))2.5?代碼實戰(zhàn):現(xiàn)可視化模型結(jié)果----WGAN-gp-228.py(第5部分)
# 1.5 定義函數(shù),實現(xiàn)可視化模型結(jié)果:獲取一部分測試數(shù)據(jù),顯示由模型生成的模擬數(shù)據(jù)。 def displayAndTest(D,G,z_dimension): # 可視化結(jié)果sample = iter(test_loader)images, labels = sample.next()y_one_hot = torch.zeros(labels.shape[0], 10).scatter_(1,labels.view(labels.shape[0], 1), 1).to(device)num_img = images.size(0) # 獲取樣本個數(shù)with torch.no_grad():z = torch.randn(num_img, z_dimension).to(device) # 生成隨機數(shù)fake_img = G(z, y_one_hot)fake_images = to_img(fake_img.cpu().data) # 生成模擬樣本rel = torch.cat([to_img(images[:10]), fake_images[:10]], axis=0)imshow(torchvision.utils.make_grid(rel, nrow=10))print(labels[:10])2.6?代碼實戰(zhàn):調(diào)用函數(shù)并訓練模型----WGAN-gp-228.py(第6部分)
# 1.6 調(diào)用函數(shù)并訓練模型:實例化判別器和生成器模型,并調(diào)用函數(shù)進行訓練 if __name__ == '__main__':z_dimension = 40 # 設(shè)置輸入隨機數(shù)的維度D = WGAN_D().to(device) # 實例化判別器G = WGAN_G(z_dimension).to(device) # 實例化生成器train(D, G, './w_img', z_dimension) # 訓練模型displayAndTest(D, G, z_dimension) # 輸出可視化可以看到g_loss的絕對值在逐漸變小,d_loss的絕對值在逐漸變大。這表明生成的橫擬樣本質(zhì)量越來越高。在本地路徑的w_img文件夾下,可以看到30張圖片,這里列出3張。
顯示訓練過程中的3張圖片(每兩行為一張),它們分別是第1次、第18次和第30次迭代訓練后的輸出結(jié)果。每張圖片的第1行為樣本數(shù)據(jù),第2行為生成的模擬數(shù)據(jù)。
得出結(jié)論:在WGAN-gp的判別器嚴格要求下,生成器生成的模擬數(shù)據(jù)越來越逼真。從生成的結(jié)果中可以看出,樣本數(shù)據(jù)與生成的模擬數(shù)據(jù)類別并不對應(yīng),這是因為我們沒有對其加入生成類別的信息。使用條件GAN可實現(xiàn)類別對應(yīng)的效果。
?
?3??代碼匯總(WGAN-gp-228.py)
import torch import torchvision from torchvision import transforms from torch.utils.data import DataLoader from torch import nn import torch.autograd as autograd import matplotlib.pyplot as plt import numpy as np import matplotlib import os os.environ["KMP_DUPLICATE_LIB_OK"]="TRUE"# 1.1 引入模塊并載入樣本:定義基本函數(shù),加載FashionMNIST數(shù)據(jù)集 def to_img(x):x = 0.5 * (x+1)x = x.clamp(0,1)x = x.view(x.size(0),1,28,28)return xdef imshow(img,filename = None):npimg = img.numpy()plt.axis('off')array = np.transpose(npimg,(1,2,0))if filename != None:matplotlib.image.imsave(filename,array)else:plt.imshow(array)# plt.savefig(filename) # 保存圖片 注釋掉,因為會報錯,暫時不知道什么原因 2022.3.26 15:20plt.show()img_transform = transforms.Compose([transforms.ToTensor(),transforms.Normalize(mean=[0.5],std=[0.5])] )data_dir = './fashion_mnist'train_dataset = torchvision.datasets.FashionMNIST(data_dir,train=True,transform=img_transform,download=True) train_loader = DataLoader(train_dataset,batch_size=1024,shuffle=True) # 測試數(shù)據(jù)集 val_dataset = torchvision.datasets.FashionMNIST(data_dir,train=False,transform=img_transform) test_loader = DataLoader(val_dataset,batch_size=10,shuffle=False) # 指定設(shè)備 device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") print(device)# 1.2 實現(xiàn)生成器和判別器 :因為復雜部分都放在loss值的計算方面了,所以生成器和判別器就會簡單一些。 # 生成器和判別器各自有兩個卷積和兩個全連接層。生成器最終輸出與輸入圖片相同維度的數(shù)據(jù)作為模擬樣本。 # 判別器的輸出不需要有激活函數(shù),并且輸出維度為1的數(shù)值用來表示結(jié)果。 # 在GAN模型中,因判別器的輸入則是具體的樣本數(shù)據(jù),要區(qū)分每個數(shù)據(jù)的分布特征,所以判別器使用實例歸一化, class WGAN_D(nn.Module): # 定義判別器類D :有兩個卷積和兩個全連接層def __init__(self,inputch=1):super(WGAN_D, self).__init__()self.conv1 = nn.Sequential(nn.Conv2d(inputch,64,4,2,1), # 輸出形狀為[batch,64,28,28]nn.LeakyReLU(0.2,True),nn.InstanceNorm2d(64,affine=True))self.conv2 = nn.Sequential(nn.Conv2d(64,128,4,2,1),# 輸出形狀為[batch,64,14,14]nn.LeakyReLU(0.2,True),nn.InstanceNorm2d(128,affine=True))self.fc = nn.Sequential(nn.Linear(128*7*7,1024),nn.LeakyReLU(0.2,True))self.fc2 = nn.Sequential(nn.InstanceNorm1d(1,affine=True),nn.Flatten(),nn.Linear(1024,1))def forward(self,x,*arg): # 正向傳播x = self.conv1(x)x = self.conv2(x)x = x.view(x.size(0),-1)x = self.fc(x)x = x.reshape(x.size(0),1,-1)x = self.fc2(x)return x.view(-1,1).squeeze(1)# 在GAN模型中,因生成器的初始輸入是隨機值,所以生成器使用批量歸一化。 class WGAN_G(nn.Module): # 定義生成器類G:有兩個卷積和兩個全連接層def __init__(self,input_size,input_n=1):super(WGAN_G, self).__init__()self.fc1 = nn.Sequential(nn.Linear(input_size * input_n,1024),nn.ReLU(True),nn.BatchNorm1d(1024))self.fc2 = nn.Sequential(nn.Linear(1024,7*7*128),nn.ReLU(True),nn.BatchNorm1d(7*7*128))self.upsample1 = nn.Sequential(nn.ConvTranspose2d(128,64,4,2,padding=1,bias=False), # 輸出形狀為[batch,64,14,14]nn.ReLU(True),nn.BatchNorm2d(64))self.upsample2 = nn.Sequential(nn.ConvTranspose2d(64,1,4,2,padding=1,bias=False), # 輸出形狀為[batch,64,28,28]nn.Tanh())def forward(self,x,*arg): # 正向傳播x = self.fc1(x)x = self.fc2(x)x = x.view(x.size(0),128,7,7)x = self.upsample1(x)img = self.upsample2(x)return img# 1.3 定義函數(shù)compute_gradient_penalty()完成梯度懲罰項 # 懲罰項的樣本X_inter由一部分Pg分布和一部分Pr分布組成,同時對D(X_inter)求梯度,并計算梯度與1的平方差,最終得到gradient_penalties lambda_gp = 10 # 計算梯度懲罰項 def compute_gradient_penalty(D,real_samples,fake_samples,y_one_hot):# 獲取一個隨機數(shù),作為真假樣本的采樣比例eps = torch.FloatTensor(real_samples.size(0),1,1,1).uniform_(0,1).to(device)# 按照eps比例生成真假樣本采樣值X_interX_inter = (eps * real_samples + ((1-eps)*fake_samples)).requires_grad_(True)d_interpolates = D(X_inter,y_one_hot)fake = torch.full((real_samples.size(0),),1,device=device) # 計算梯度輸出的掩碼,在本例中需要對所有梯度進行計算,故需要按照樣本個數(shù)生成全為1的張量。# 求梯度gradients = autograd.grad(outputs=d_interpolates, # 輸出值outputs,傳入計算過的張量結(jié)果inputs=X_inter,# 待求梯度的輸入值inputs,傳入可導的張量,即requires_grad=Truegrad_outputs=fake, # 傳出梯度的掩碼grad_outputs,使用1和0組成的掩碼,在計算梯度之后,會將求導結(jié)果與該掩碼進行相乘得到最終結(jié)果。create_graph=True,retain_graph=True,only_inputs=True)[0]gradients = gradients.view(gradients.size(0),-1)gradient_penaltys = ((gradients.norm(2, dim=1) - 1) ** 2).mean() * lambda_gpreturn gradient_penaltys# 1.4 定義模型的訓練函數(shù) # 定義函數(shù)train(),實現(xiàn)模型的訓練過程。 # 在函數(shù)train()中,按照對抗神經(jīng)網(wǎng)絡(luò)專題(一)中的式(8-24)實現(xiàn)模型的損失函數(shù)。 # 判別器的loss為D(fake_samples)-D(real_samples)再加上聯(lián)合分布樣本的梯度懲罰項gradient_penalties,其中fake_samples為生成的模擬數(shù)據(jù),real_Samples為真實數(shù)據(jù), # 生成器的loss為-D(fake_samples)。 def train(D,G,outdir,z_dimension,num_epochs=30):d_optimizer = torch.optim.Adam(D.parameters(),lr=0.001) # 定義優(yōu)化器g_optimizer = torch.optim.Adam(G.parameters(),lr=0.001)os.makedirs(outdir,exist_ok=True) # 創(chuàng)建輸出文件夾# 在函數(shù)train()中,判別器和生成器是分開訓練的。讓判別器學習的次數(shù)多一些,判別器每訓練5次,生成器優(yōu)化1次。# WGAN_gp不會因為判別器準確率太高而引起生成器梯度消失的問題,所以好的判別器會讓生成器有更好的模擬效果。for epoch in range(num_epochs):for i,(img,lab) in enumerate(train_loader):num_img = img.size(0)# 訓練判別器real_img = img.to(device)y_one_hot = torch.zeros(lab.shape[0],10).scatter_(1,lab.view(lab.shape[0],1),1).to(device)for ii in range(5): # 循環(huán)訓練5次d_optimizer.zero_grad() # 梯度清零# 對real_img進行判別real_out = D(real_img,y_one_hot)# 生成隨機值z = torch.randn(num_img,z_dimension).to(device)fake_img = G(z,y_one_hot) # 生成fake_imgfake_out = D(fake_img,y_one_hot) # 對fake_img進行判別# 計算梯度懲罰項gradient_penalty = compute_gradient_penalty(D,real_img.data,fake_img.data,y_one_hot)# 計算判別器的lossd_loss = -torch.mean(real_out)+torch.mean(fake_out)+gradient_penaltyd_loss.backward()d_optimizer.step()# 訓練生成器for ii in range(1): # 訓練一次g_optimizer.zero_grad() # 梯度清0z = torch.randn(num_img,z_dimension).to(device)fake_img = G(z,y_one_hot)fake_out = D(fake_img,y_one_hot)g_loss = -torch.mean(fake_out)g_loss.backward()g_optimizer.step()# 輸出可視化結(jié)果,并將生成的結(jié)果以圖片的形式存儲在硬盤中fake_images = to_img(fake_img.cpu().data)real_images = to_img(real_img.cpu().data)rel = torch.cat([to_img(real_images[:10]), fake_images[:10]], axis=0)imshow(torchvision.utils.make_grid(rel, nrow=10),os.path.join(outdir, 'fake_images-{}.png'.format(epoch + 1)))# 輸出訓練結(jié)果print('Epoch [{}/{}], d_loss: {:.6f}, g_loss: {:.6f} ''D real: {:.6f}, D fake: {:.6f}'.format(epoch, num_epochs, d_loss.data, g_loss.data,real_out.data.mean(), fake_out.data.mean()))# 保存訓練模型torch.save(G.state_dict(), os.path.join(outdir, 'generator.pth'))torch.save(D.state_dict(), os.path.join(outdir, 'discriminator.pth'))# 1.5 定義函數(shù),實現(xiàn)可視化模型結(jié)果:獲取一部分測試數(shù)據(jù),顯示由模型生成的模擬數(shù)據(jù)。 def displayAndTest(D,G,z_dimension): # 可視化結(jié)果sample = iter(test_loader)images, labels = sample.next()y_one_hot = torch.zeros(labels.shape[0], 10).scatter_(1,labels.view(labels.shape[0], 1), 1).to(device)num_img = images.size(0) # 獲取樣本個數(shù)with torch.no_grad():z = torch.randn(num_img, z_dimension).to(device) # 生成隨機數(shù)fake_img = G(z, y_one_hot)fake_images = to_img(fake_img.cpu().data) # 生成模擬樣本rel = torch.cat([to_img(images[:10]), fake_images[:10]], axis=0)imshow(torchvision.utils.make_grid(rel, nrow=10))print(labels[:10])# 1.6 調(diào)用函數(shù)并訓練模型:實例化判別器和生成器模型,并調(diào)用函數(shù)進行訓練 if __name__ == '__main__':z_dimension = 40 # 設(shè)置輸入隨機數(shù)的維度D = WGAN_D().to(device) # 實例化判別器G = WGAN_G(z_dimension).to(device) # 實例化生成器train(D, G, './w_img', z_dimension) # 訓練模型displayAndTest(D, G, z_dimension) # 輸出可視化 創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅持創(chuàng)作打卡瓜分現(xiàn)金大獎總結(jié)
以上是生活随笔為你收集整理的【Pytorch神经网络实战案例】15 WGAN-gp模型生成Fashon-MNST模拟数据的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: pycharm 2020 版取消鼠标悬停
- 下一篇: 智慧交通day04-特定目标车辆追踪03