【Pytorch神经网络实战案例】14 构建条件变分自编码神经网络模型生成可控Fashon-MNST模拟数据
生活随笔
收集整理的這篇文章主要介紹了
【Pytorch神经网络实战案例】14 构建条件变分自编码神经网络模型生成可控Fashon-MNST模拟数据
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
1 條件變分自編碼神經網絡生成模擬數據案例說明
在實際應用中,條件變分自編碼神經網絡的應用會更為廣泛一些,因為它使得模型輸出的模擬數據可控,即可以指定模型輸出鞋子或者上衣。
1.1 案例描述
在變分自編碼神經網絡模型的技術上構建條件變分自編碼神經網絡模型,實現向模型輸入標簽,并使其生成與標簽類別對應的模擬數據的功能。
1.2 條件變分自編碼神經網絡的實現條件
變分自編碼神經網絡在變分自編碼神經網絡基礎之上,增加指導性條件。在編碼階段的輸入端添加了與標簽對應的特征,在解碼階段同樣添加標簽特征。這樣,最終得到的模型將會把輸入的標簽特征當成原始數據的一部分,實現通過標簽來生成可控模擬數據的效果。
在輸入端添加標簽時,一般是通過一個全連接層的變換將得到的結果連接到原始輸入。
在解碼階段也將標簽作為樣本輸入,與高斯分布的隨機值一并運算,生成模擬樣本。
1.2.1 條件變分自編碼神經網絡結構
2 實例代碼編寫
2.1 代碼實戰:引入模塊并載入樣本----Variational_cond_selfcoding.py(第1部分)
import torch import torchvision from torch import nn import torch.nn.functional as F from torch.utils.data import DataLoader from torchvision import transforms import numpy as np from scipy.stats import norm # 在模型可視化時使用該庫的norm接口從標準的高斯分布中獲取數值 import matplotlib.pylab as plt import os os.environ['KMP_DUPLICATE_LIB_OK'] = 'True' # 可能是由于是MacOS系統的原因# 1.1 引入模塊并載入樣本:定義基礎函數,并且加載FashionMNIST數據集 # 定義樣本預處理接口 img_transform = transforms.Compose([transforms.ToTensor()])def to_img(x): # 將張量轉化為圖片x = 0.5 * (x + 1)x = x.clamp(0,1)x = x.reshape(x.size(0),1,28,28)return xdef imshow(img): # 顯示圖片npimg = img.numpy()plt.axis('off')plt.imshow(np.transpose(npimg,(1,2,0)))plt.show()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=128,shuffle=True) # 獲取測試數據集 val_dataset = torchvision.datasets.FashionMNIST(data_dir,train=False,transform=img_transform) test_loader = DataLoader(val_dataset,batch_size=10,shuffle=False) # 指定設備 device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") print("所使用的設備為:",device)2.2 代碼實戰:定義變分自編碼神經網絡的正向模型----Variational_cond_selfcoding.py(第2部分)
# 1.2 定義變分自編碼神經網絡模型的正向結構 class VAE(nn.Module):def __init__(self,hidden_1=256,hidden_2=256,in_decode_dim=2,hidden_3=256):super(VAE, self).__init__()self.fc1 = nn.Linear(784, hidden_1)self.fc21 = nn.Linear(hidden_2, 2)self.fc22 = nn.Linear(hidden_2, 2)self.fc3 = nn.Linear(in_decode_dim, hidden_3)self.fc4 = nn.Linear(hidden_3, 784)def encode(self,x): # 編碼器方法:使用兩層全連接網絡將輸入的圖片進行壓縮,對第二層中兩個神經網絡的輸出結果代表均值(mean)與取對數(log)以后的方差(lg_var)。h1 = F.relu(self.fc1(x))return self.fc21(h1),self.fc22(h1)def reparametrize(self,mean,lg_var): # 采樣器方法:對方差(lg_var)進行還原,并從高斯分布中采樣,將采樣數值映射到編碼器輸出的數據分布中。std = lg_var.exp().sqrt()# torch.FloatTensor(std.size())的作用是,生成一個與std形狀一樣的張量。然后,調用該張量的normal_()方法,系統會對該張量中的每個元素在標準高斯空間(均值為0、方差為1)中進行采樣。eps = torch.FloatTensor(std.size()).normal_().to(device) # 隨機張量方法normal_(),完成高斯空間的采樣過程。return eps.mul(std).add_(mean)# 在torch.FloatTensor()# 函數中,傳入Tensor的size類型,返回的是一個同樣為size的張量。假如std的size為[batch,dim],則返回形狀為[batch,dim]的未初始化張量,等同于torch.FloatTensor(# batch,dim),但不等同于torchFloatTensor([batch,dim),這是值得注意的地方。def decode(self,z): # 解碼器方法:輸入映射后的采樣值,用兩層神經網絡還原出原始圖片。h3 = F.relu(self.fc3(z))return self.fc4(h3)def forward(self,x,*arg): # 正向傳播方法:將編碼器,采樣器,解碼器串聯起來,根據輸入的原始圖片生成模擬圖片mean,lg_var = self.encode(x)z = self.reparametrize(mean=mean,lg_var=lg_var)return self.decode(z),mean,lg_var2.3 代碼實戰:損失函數與訓練函數的完善----Variational_cond_selfcoding.py(第3部分)
# 1.3 完成損失函數和訓練函數 reconstruction_function = nn.MSELoss(size_average=False)def loss_function(recon_x,x,mean,lg_var): # 損失函數:將MSE的損失縮小到一半,再與KL散度相加,目的在于使得輸出的模擬樣本可以有更靈活的變化空間。MSEloss = reconstruction_function(recon_x,x) # MSE損失KLD = -0.5 * torch.sum(1 + lg_var - mean.pow(2) - lg_var.exp())return 0.5 * MSEloss + KLDdef train(model,num_epochs = 50): # 訓練函數optimizer = torch.optim.Adam(model.parameters(),lr=1e-3)display_step = 5for epoch in range(num_epochs):model.train()train_loss = 0for batch_idx, data in enumerate(train_loader):img,label = dataimg = img.view(img.size(0),-1).to(device)y_one_hot = torch.zeros(label.shape[0],10).scatter_(1,label.view(label.shape[0],1),1).to(device)optimizer.zero_grad()recon_batch, mean, lg_var = model(img, y_one_hot)loss = loss_function(recon_batch, img, mean, lg_var)loss.backward()train_loss += loss.dataoptimizer.step()if epoch % display_step == 0:print("Epoch:", '%04d' % (epoch + 1), "cost=", "{:.9f}".format(loss.data))print("完成訓練 cost=",loss.data)2.4?代碼實戰:定義條件變分自編碼神經網絡模型----Variational_cond_selfcoding.py(第3部分)
# 1.4 定義條件變分自編碼神經網絡模型 class CondVAE(VAE): # 繼承VAE類,實現條件變分自編碼神經網絡模型的正向結構。def __init__(self, hidden_1=256, hidden_2=512,in_decode_dim=2 + 10, hidden_3=256):super(CondVAE, self).__init__(hidden_1, hidden_2, in_decode_dim, hidden_3)self.labfc1 = nn.Linear(10, hidden_1)def encode(self, x, lab):h1 = F.relu(self.fc1(x))lab1 = F.relu(self.labfc1(lab))h1 = torch.cat([h1, lab1], axis=1)return self.fc21(h1), self.fc22(h1)def decode(self, z, lab):h3 = F.relu(self.fc3(torch.cat([z, lab], axis=1)))return self.fc4(h3)def forward(self, x, lab):mean, lg_var = self.encode(x, lab)z = self.reparametrize(mean, lg_var)return self.decode(z, lab), mean, lg_var2.5?代碼實戰:訓練模型并輸出可視化結果----Variational_cond_selfcoding.py(第4部分)
# 1.5 訓練模型并輸出可視化結果 if __name__ == '__main__':model = CondVAE().to(device) # 實例化模型train(model, 50)# 將指定的one_hot標簽輸入模型,便可得到對應的模擬數據sample = iter(test_loader) # 取出10個樣本,用于測試images, labels = sample.next()# 將標簽轉化為one_hot編碼,取10個測試樣本與標簽。y_one_hots = torch.zeros(labels.shape[0], 10).scatter_(1, labels.view(labels.shape[0], 1), 1)# 將標簽輸入模型,生成模擬數據images2 = images.view(images.size(0), -1)with torch.no_grad():pred, mean, lg_var = model(images2.to(device), y_one_hots.to(device))pred = to_img(pred.cpu().detach()) # 將生成的模擬數據轉化為圖片print("標簽值:", labels) # 輸出標簽# 標簽值: tensor([9, 2, 1, 1, 6, 1, 4, 6, 5, 7])# 輸出可視化結果z_sample = torch.randn(10, 2).to(device)x_decoded = model.decode(z_sample, y_one_hots.to(device)) # 將取得的10個標簽與隨機的高斯分布采樣值z_sample一起輸入模型,得到與標簽相對應的模擬數據。rel = torch.cat([images, pred, to_img(x_decoded.cpu().detach())], axis=0)imshow(torchvision.utils.make_grid(rel, nrow=10))plt.show()# 根據標簽生成模擬數據一共有3行圖片,第1行是原始圖片,第2行是將原始圖片輸入模型后所得到的模擬圖片,第3行是將原始標簽輸入模型后生成的模擬圖片。# 比較第2行和第3行圖片可以看出,使用原始圖片生成的模擬圖片還會帶有一些原來的樣子,而使用標簽生成的模擬圖片已經學會了數據的分布規則,并能生成截然不同卻帶有相同意義的數據。?3??代碼匯總(Variational_cond_selfcoding.py)
import torch import torchvision from torch import nn import torch.nn.functional as F from torch.utils.data import DataLoader from torchvision import transforms import numpy as np from scipy.stats import norm # 在模型可視化時使用該庫的norm接口從標準的高斯分布中獲取數值 import matplotlib.pylab as plt import os os.environ['KMP_DUPLICATE_LIB_OK'] = 'True' # 可能是由于是MacOS系統的原因# 1.1 引入模塊并載入樣本:定義基礎函數,并且加載FashionMNIST數據集 # 定義樣本預處理接口 img_transform = transforms.Compose([transforms.ToTensor()])def to_img(x): # 將張量轉化為圖片x = 0.5 * (x + 1)x = x.clamp(0,1)x = x.reshape(x.size(0),1,28,28)return xdef imshow(img): # 顯示圖片npimg = img.numpy()plt.axis('off')plt.imshow(np.transpose(npimg,(1,2,0)))plt.show()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=128,shuffle=True) # 獲取測試數據集 val_dataset = torchvision.datasets.FashionMNIST(data_dir,train=False,transform=img_transform) test_loader = DataLoader(val_dataset,batch_size=10,shuffle=False) # 指定設備 device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") print("所使用的設備為:",device)# 1.2 定義變分自編碼神經網絡模型的正向結構 class VAE(nn.Module):def __init__(self,hidden_1=256,hidden_2=256,in_decode_dim=2,hidden_3=256):super(VAE, self).__init__()self.fc1 = nn.Linear(784, hidden_1)self.fc21 = nn.Linear(hidden_2, 2)self.fc22 = nn.Linear(hidden_2, 2)self.fc3 = nn.Linear(in_decode_dim, hidden_3)self.fc4 = nn.Linear(hidden_3, 784)def encode(self,x): # 編碼器方法:使用兩層全連接網絡將輸入的圖片進行壓縮,對第二層中兩個神經網絡的輸出結果代表均值(mean)與取對數(log)以后的方差(lg_var)。h1 = F.relu(self.fc1(x))return self.fc21(h1),self.fc22(h1)def reparametrize(self,mean,lg_var): # 采樣器方法:對方差(lg_var)進行還原,并從高斯分布中采樣,將采樣數值映射到編碼器輸出的數據分布中。std = lg_var.exp().sqrt()# torch.FloatTensor(std.size())的作用是,生成一個與std形狀一樣的張量。然后,調用該張量的normal_()方法,系統會對該張量中的每個元素在標準高斯空間(均值為0、方差為1)中進行采樣。eps = torch.FloatTensor(std.size()).normal_().to(device) # 隨機張量方法normal_(),完成高斯空間的采樣過程。return eps.mul(std).add_(mean)# 在torch.FloatTensor()# 函數中,傳入Tensor的size類型,返回的是一個同樣為size的張量。假如std的size為[batch,dim],則返回形狀為[batch,dim]的未初始化張量,等同于torch.FloatTensor(# batch,dim),但不等同于torchFloatTensor([batch,dim),這是值得注意的地方。def decode(self,z): # 解碼器方法:輸入映射后的采樣值,用兩層神經網絡還原出原始圖片。h3 = F.relu(self.fc3(z))return self.fc4(h3)def forward(self,x,*arg): # 正向傳播方法:將編碼器,采樣器,解碼器串聯起來,根據輸入的原始圖片生成模擬圖片mean,lg_var = self.encode(x)z = self.reparametrize(mean=mean,lg_var=lg_var)return self.decode(z),mean,lg_var# 1.3 完成損失函數和訓練函數 reconstruction_function = nn.MSELoss(size_average=False)def loss_function(recon_x,x,mean,lg_var): # 損失函數:將MSE的損失縮小到一半,再與KL散度相加,目的在于使得輸出的模擬樣本可以有更靈活的變化空間。MSEloss = reconstruction_function(recon_x,x) # MSE損失KLD = -0.5 * torch.sum(1 + lg_var - mean.pow(2) - lg_var.exp())return 0.5 * MSEloss + KLDdef train(model,num_epochs = 50): # 訓練函數optimizer = torch.optim.Adam(model.parameters(),lr=1e-3)display_step = 5for epoch in range(num_epochs):model.train()train_loss = 0for batch_idx, data in enumerate(train_loader):img,label = dataimg = img.view(img.size(0),-1).to(device)y_one_hot = torch.zeros(label.shape[0],10).scatter_(1,label.view(label.shape[0],1),1).to(device)optimizer.zero_grad()recon_batch, mean, lg_var = model(img, y_one_hot)loss = loss_function(recon_batch, img, mean, lg_var)loss.backward()train_loss += loss.dataoptimizer.step()if epoch % display_step == 0:print("Epoch:", '%04d' % (epoch + 1), "cost=", "{:.9f}".format(loss.data))print("完成訓練 cost=",loss.data)# 1.4 定義條件變分自編碼神經網絡模型 class CondVAE(VAE): # 繼承VAE類,實現條件變分自編碼神經網絡模型的正向結構。def __init__(self, hidden_1=256, hidden_2=512,in_decode_dim=2 + 10, hidden_3=256):super(CondVAE, self).__init__(hidden_1, hidden_2, in_decode_dim, hidden_3)self.labfc1 = nn.Linear(10, hidden_1)def encode(self, x, lab):h1 = F.relu(self.fc1(x))lab1 = F.relu(self.labfc1(lab))h1 = torch.cat([h1, lab1], axis=1)return self.fc21(h1), self.fc22(h1)def decode(self, z, lab):h3 = F.relu(self.fc3(torch.cat([z, lab], axis=1)))return self.fc4(h3)def forward(self, x, lab):mean, lg_var = self.encode(x, lab)z = self.reparametrize(mean, lg_var)return self.decode(z, lab), mean, lg_var# 1.5 訓練模型并輸出可視化結果 if __name__ == '__main__':model = CondVAE().to(device) # 實例化模型train(model, 50)# 將指定的one_hot標簽輸入模型,便可得到對應的模擬數據sample = iter(test_loader) # 取出10個樣本,用于測試images, labels = sample.next()# 將標簽轉化為one_hot編碼,取10個測試樣本與標簽。y_one_hots = torch.zeros(labels.shape[0], 10).scatter_(1, labels.view(labels.shape[0], 1), 1)# 將標簽輸入模型,生成模擬數據images2 = images.view(images.size(0), -1)with torch.no_grad():pred, mean, lg_var = model(images2.to(device), y_one_hots.to(device))pred = to_img(pred.cpu().detach()) # 將生成的模擬數據轉化為圖片print("標簽值:", labels) # 輸出標簽# 標簽值: tensor([9, 2, 1, 1, 6, 1, 4, 6, 5, 7])# 輸出可視化結果z_sample = torch.randn(10, 2).to(device)x_decoded = model.decode(z_sample, y_one_hots.to(device)) # 將取得的10個標簽與隨機的高斯分布采樣值z_sample一起輸入模型,得到與標簽相對應的模擬數據。rel = torch.cat([images, pred, to_img(x_decoded.cpu().detach())], axis=0)imshow(torchvision.utils.make_grid(rel, nrow=10))plt.show()# 根據標簽生成模擬數據一共有3行圖片,第1行是原始圖片,第2行是將原始圖片輸入模型后所得到的模擬圖片,第3行是將原始標簽輸入模型后生成的模擬圖片。# 比較第2行和第3行圖片可以看出,使用原始圖片生成的模擬圖片還會帶有一些原來的樣子,而使用標簽生成的模擬圖片已經學會了數據的分布規則,并能生成截然不同卻帶有相同意義的數據。總結
以上是生活随笔為你收集整理的【Pytorch神经网络实战案例】14 构建条件变分自编码神经网络模型生成可控Fashon-MNST模拟数据的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java安装后在哪里打开_冷却塔声屏障安
- 下一篇: 【Pytorch神经网络理论篇】 37