日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【Pytorch神经网络实战案例】13 构建变分自编码神经网络模型生成Fashon-MNST模拟数据

發(fā)布時間:2024/7/5 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【Pytorch神经网络实战案例】13 构建变分自编码神经网络模型生成Fashon-MNST模拟数据 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1 變分自編碼神經網絡生成模擬數據案例說明

變分自編碼里面真正的公式只有一個KL散度。

1.1 變分自編碼神經網絡模型介紹

主要由以下三個部分構成:

1.1.1 編碼器

由兩層全連接神經網絡組成,第一層有784個維度的輸入和256個維度的輸出;第二層并列連接了兩個全連接神經網絡,每個網絡都有兩個維度的輸出,輸出的結果分別代表數據分布的均值與方差。

1.1.2 采樣器

根據編碼器得到的均值與方差計算出數據分布情況,從數據分布情況中采樣取得數據特征z,并將z傳遞到兩節(jié)點為開始的解碼器部分。

1.1.3 解碼器

由兩個全連接神經網絡構成,第一層有兩個維度的輸入和256個維度的輸出;第二層有256個維度的輸入和784哥維度的輸出。

  • 采樣器的左側是編碼器。
  • 圓角方框是采樣器部分,其工作步驟如下。(1)用lg_var.exp()方法算出真正的方差值。(2)用方差值的sqrt0方法執(zhí)行開平方運算得到標準差。(3)在符合標準正態(tài)分布的空間里隨意采樣,得到一個具體的數。(4)將該數乘以標準差,再加上均值,得到符合編碼器輸出的數據分布(均值為mean、方差為sigma)集合中的一個點(sigma是指網絡生成的lg_var經過變換后的值)。
  • 采樣器的右側是解碼器。?經過采樣器之后所合成的點可以輸入解碼器進行模擬樣本的生成。
  • 1.1.4 小總結

    在神經網絡中,可以為模型的輸出值賦于任意一個意義,并通過訓練得到對應的關系。具體做法是:將代表該意義的值代入相應的公式(要求該公式必須能夠支持返向傳播),計算公式的輸出值與目標值的誤差,并將誤差放到優(yōu)化器里,然后通過多次選代的方式進行訓練。

    2 變分自編碼神經網絡模型的反向傳播與KL散度的應用

    變分自編碼神經網絡模型是假設編碼器輸出的數據分布屬于高斯分布,只有在編碼器能夠輸出符合高斯分布數據集的前提上,才可以將一個符合標準高斯分布中的點x通過mean+sigma ×?x的方式進行轉化(mean表示均值、sigma表示標準差),完成在解碼器輸出空間中的采樣功能。

    2.1 變分自編碼神經網絡的損失函數

    變分自編碼神經網絡的損失函數不但需要計算輸出結果與輸入之間的個體差異,而且需要計算輸出分布與高斯分布之間的差異。
    輸出與輸入之間的損失函數可以使用MSE算法來計算,輸出分布與標準高斯分布之損失函數可以使用KL散度距離進行計算。

    2.2 KL散度

    KL散度是相對熵的意思。KL散度在本例中的應用可以理解為在模型的訓練過程中令輸出的數據分布與標準高斯分布之間的差距不斷縮小。

    設P(x)、Q(x)是離散隨機變量集合X中取值x的兩個概率分布函數,它們的結果分別為p和q,則p對q的相對熵如下:

    由式可知,當P(x)和Q(x)兩個概率分布函數相同時,相對熵為0(因為log1=0)并且相對熵具有不對稱性,“Ep”代表期望,期望是指每次可能結果的概率乘以結果的總和。

    將高斯分布的密度函數代入上式中,可以得到:

    為輸出分布與標準高斯分布之間的KL散度距離。它與MSE算法一起構成變分自編碼神經網絡的損失函數。

    3 實例代碼編寫

    3.1 代碼實戰(zhàn):引入模塊并載入樣本----Variational_selfcoding.py(第1部分)

    import torch import torchvision from cv2 import waitKey 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_dataset = DataLoader(val_dataset,batch_size=10,shuffle=False) # 指定設備 device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") print("所使用的設備為:",device)

    3.2 代碼實戰(zhàn):定義變分自編碼神經網絡的正向模型----Variational_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_var

    3.3 代碼實戰(zhàn):損失函數與訓練函數的完善----Variational_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)

    3.4 代碼實戰(zhàn):訓練模型并輸出可視化結果----Variational_selfcoding.py(第4部分)

    # 1.4 訓練模型并輸出可視化結果 if __name__ == '__main__':model = VAE().to(device) # 實例化模型train(model, 50) # 訓練模型test_loader = DataLoader(val_dataset, batch_size=len(val_dataset), shuffle=False) # 獲取全部測試數據# 可視化結果sample = iter(test_loader)images, labels = sample.next()images2 = images.view(images.size(0), -1)with torch.no_grad():pred, mean, lg_var = model(images2.to(device))pred = to_img(pred.cpu().detach())rel = torch.cat([images, pred], axis=0)imshow(torchvision.utils.make_grid(rel, nrow=10))# 上一語句的生成結果中,第1行是原始的樣本圖片,第2行是使用變分自編碼重建后生成的圖片可以看到,生成的樣本并不會與原始的輸入樣本完全一致。這表明模型不是一味地學習樣本個體,而是通過數據分布的方式學習樣本的分布規(guī)則。waitKey(30)

    3.5 代碼實戰(zhàn):提取樣本的低維數據并可視化----Variational_selfcoding.py(第5部分)

    # 1.5 提取樣本的低維特征并可視化: 編寫代碼實現對原始數據的維度進行壓縮,利用解碼器輸出的均值和方差從解碼器輸出的分布空間中取樣,并將其映到直角坐標系中展現出來,具體代碼如下。sample = iter(test_loader)images, labels = sample.next()with torch.no_grad(): # 將數據輸入模型獲得低維度特征:mean, lg_var = model.encode(images.view(images.size(0), -1).to(device))# 將數據輸入模型獲得低維度特征:z = model.reparametrize(mean, lg_var)# 將數據輸入模型獲得低維度特征:在輸出樣本空間中采樣z =z.cpu().detach().numpy()plt.figure(figsize=(6, 6))plt.scatter(z[:, 0], z[:, 1], c=labels) # 在坐標軸中顯示plt.colorbar()plt.show() # 根據結果顯示,數據集中同一類樣本的特征分布還是比較集中的。這說明變分自編碼神經網絡具有降維功能,也可以用于進行分類任務的數據降維預處理。

    3.6 代碼實戰(zhàn):可視化模型的輸出空間----Variational_selfcoding.py(第6部分)

    #1.6 可視化模型的輸出空間n = 15 # 生成15個圖片digit_size = 28figure = np.zeros((digit_size * n, digit_size * n))# norm代表標準高斯分布,ppf代表累積分布函數的反函數。累積積分布的意思是,在一個集合里所有小于指定值出現的概率的和。舉例,x=ppf(0.05)就代表每個小于x的數在集合里出現的概率的總和等于0.05。# norm.ppf()函數的作用是使用百分比從按照大小排列后的標準高斯分布中取值# p.linspace(0.05,0.95,n)的作用是將整個高斯分布數據集從大到小排列,并將其分成100份,再將第5份到第95份之間的數據取出、最后,將取出的數據分成n份,返回每一份最后一個數據的具體數值。grid_x = norm.ppf(np.linspace(0.05, 0.95, n))grid_y = norm.ppf(np.linspace(0.05, 0.95, n))for i, yi in enumerate(grid_x):for j, xi in enumerate(grid_y):z_sample = torch.FloatTensor([[xi, yi]]).reshape([1, 2]).to(device)x_decoded = model.decode(z_sample).cpu().detach().numpy()digit = x_decoded[0].reshape(digit_size, digit_size)figure[i * digit_size: (i + 1) * digit_size,j * digit_size: (j + 1) * digit_size] = digitplt.figure(figsize=(10, 10))plt.imshow(figure, cmap='Greys_r')plt.show()#從上一語句的生成結果中可以清楚地看到鞋子、手提包和服裝商品之間的過渡。變分自編碼神經網絡生成的分布樣本很有規(guī)律性,左下方側重的圖像較寬和較高,右上方側重的圖像較寬和較矮,左上方側重的圖像下方較寬、上方較窄,右下方側重的圖像較窄和較高。

    4 代碼匯總(Variational_selfcoding.py)

    import torch import torchvision from cv2 import waitKey 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_dataset = 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 訓練模型并輸出可視化結果 if __name__ == '__main__':model = VAE().to(device) # 實例化模型train(model, 50) # 訓練模型test_loader = DataLoader(val_dataset, batch_size=len(val_dataset), shuffle=False) # 獲取全部測試數據# 可視化結果sample = iter(test_loader)images, labels = sample.next()images2 = images.view(images.size(0), -1)with torch.no_grad():pred, mean, lg_var = model(images2.to(device))pred = to_img(pred.cpu().detach())rel = torch.cat([images, pred], axis=0)imshow(torchvision.utils.make_grid(rel, nrow=10))# 上一語句的生成結果中,第1行是原始的樣本圖片,第2行是使用變分自編碼重建后生成的圖片可以看到,生成的樣本并不會與原始的輸入樣本完全一致。這表明模型不是一味地學習樣本個體,而是通過數據分布的方式學習樣本的分布規(guī)則。waitKey(30)# 1.5 提取樣本的低維特征并可視化: 編寫代碼實現對原始數據的維度進行壓縮,利用解碼器輸出的均值和方差從解碼器輸出的分布空間中取樣,并將其映到直角坐標系中展現出來,具體代碼如下。sample = iter(test_loader)images, labels = sample.next()with torch.no_grad(): # 將數據輸入模型獲得低維度特征:mean, lg_var = model.encode(images.view(images.size(0), -1).to(device))# 將數據輸入模型獲得低維度特征:z = model.reparametrize(mean, lg_var)# 將數據輸入模型獲得低維度特征:在輸出樣本空間中采樣z =z.cpu().detach().numpy()plt.figure(figsize=(6, 6))plt.scatter(z[:, 0], z[:, 1], c=labels) # 在坐標軸中顯示plt.colorbar()plt.show()# 根據結果顯示,數據集中同一類樣本的特征分布還是比較集中的。這說明變分自編碼神經網絡具有降維功能,也可以用于進行分類任務的數據降維預處理。#1.6 可視化模型的輸出空間n = 15 # 生成15個圖片digit_size = 28figure = np.zeros((digit_size * n, digit_size * n))# norm代表標準高斯分布,ppf代表累積分布函數的反函數。累積積分布的意思是,在一個集合里所有小于指定值出現的概率的和。舉例,x=ppf(0.05)就代表每個小于x的數在集合里出現的概率的總和等于0.05。# norm.ppf()函數的作用是使用百分比從按照大小排列后的標準高斯分布中取值# p.linspace(0.05,0.95,n)的作用是將整個高斯分布數據集從大到小排列,并將其分成100份,再將第5份到第95份之間的數據取出、最后,將取出的數據分成n份,返回每一份最后一個數據的具體數值。grid_x = norm.ppf(np.linspace(0.05, 0.95, n))grid_y = norm.ppf(np.linspace(0.05, 0.95, n))for i, yi in enumerate(grid_x):for j, xi in enumerate(grid_y):z_sample = torch.FloatTensor([[xi, yi]]).reshape([1, 2]).to(device)x_decoded = model.decode(z_sample).cpu().detach().numpy()digit = x_decoded[0].reshape(digit_size, digit_size)figure[i * digit_size: (i + 1) * digit_size,j * digit_size: (j + 1) * digit_size] = digitplt.figure(figsize=(10, 10))plt.imshow(figure, cmap='Greys_r')plt.show()#從上一語句的生成結果中可以清楚地看到鞋子、手提包和服裝商品之間的過渡。變分自編碼神經網絡生成的分布樣本很有規(guī)律性,左下方側重的圖像較寬和較高,右上方側重的圖像較寬和較矮,左上方側重的圖像下方較寬、上方較窄,右下方側重的圖像較窄和較高。

    總結

    以上是生活随笔為你收集整理的【Pytorch神经网络实战案例】13 构建变分自编码神经网络模型生成Fashon-MNST模拟数据的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。