原文連接: https://debuggercafe.com/implementing-deep-autoencoder-in-pytorch/
本文將簡述pytorch環境下的線性自編碼器的實現:
本文內容:
- autoencoder簡介;
- 方法;
- Pytorch實現(線性層)
- 圖片重構
一、autoencoder簡介
深度學習自編碼器是一種神經網絡類型,可以從潛在code空間中重構圖片;
這里涉及到三個概念:
1)encoder 2)decoder 3) code
下面以圖像為例進行說明:
encoder:是個網絡結構;輸入圖像,輸出code;
decoder:也是個網絡結構;輸入code,輸出圖像;
code:可以理解為圖像潛在特征表示
下面用一張圖來對其進行表示:
二、方法
Deep autoencoder
三、Pytorch實現
數據集: Fashion MNIST
有70000張灰度圖,其中60000作為訓練,10000作為測試集;
包含有10個類別;
代碼實現:
1)導入需要的包
# import packages import os import torch import torchvision import torch.nn as nn import torchvision.transforms as transforms import torch.optim as optim import matplotlib.pyplot as plt import torch.nn.functional as F from torchvision import datasets from torch.utils.data import DataLoader from torchvision.utils import save_image
重要包說明:
- torchvision: 包含許多流行的計算機視覺數據集,深度神經網絡架構,以及圖像處理模塊;我們將使用這個包來下載Fashion MNIST和CIFAR10數據集;
- torch.nn:包含了許多深度學習網絡層,比如Linear()、Conv2d()等;
- transforms:幫助定義圖像變換和正則化;
- optim:包含了深度學習的優化器;
- functional:在本文中的激活函數將用到它;
- Dataloader:使數據成為可迭代的訓練和測試形式;
2)數據准備以及超參數定義
超參數是指,人工預先設定的,不通過網絡學習得到的參數;
主要有, 迭代的次數NUM_EPOCHS,學習率LEARNING_RATE,batch的大小BATCH_SIZE
代碼如下:
# constants NUM_EPOCHS = 50 LEARNING_RATE = 1e-3 BATCH_SIZE = 128 # image transformations transform = transforms.Compose([ transforms.ToTensor(), ])
transforms.Compose([transforms.ToTensor(),])是將pixel的值轉換為tensor;並且將其縮放至[-1,1]范圍;
訓練集和測試的准備:
trainset = datasets.FashionMNIST( root='./data', train=True, download=True, transform=transform ) testset = datasets.FashionMNIST( root='./data', train=False, download=True, transform=transform ) trainloader = DataLoader( trainset, batch_size=BATCH_SIZE, shuffle=True ) testloader = DataLoader( testset, batch_size=BATCH_SIZE, shuffle=True )
這里的trainloader以及testloader中的batchsize大小均為128; data loaders是可迭代的;
trainloader中含有60000/128個batches,testloader中含有10000/128個batches。
3) 實用函數 utility functions
寫這些函數的目的在於:節省時間,避免代碼重復;
本文包含三個實用函數:
a. get_device() 設備判斷函數——返回GPU或者是CPU
b.make_dir()創建一個目錄來存儲訓練中重構的圖片;
c. save_decode_image() 用於存儲自編碼器重構的圖片。
# utility functions def get_device(): if torch.cuda.is_available(): device = 'cuda:0' else: device = 'cpu' return device def make_dir(): image_dir = 'FashionMNIST_Images' if not os.path.exists(image_dir): os.makedirs(image_dir) def save_decoded_image(img, epoch): img = img.view(img.size(0), 1, 28, 28) save_image(img, './FashionMNIST_Images/linear_ae_image{}.png'.format(epoch))
4)定義自編碼-解碼網絡
Autoencoder()具有兩個部分:編碼encoder部分以及解碼decoder部分;
encoder部分:
a. encoder將28*28維的圖像進行展平處理,成為28*28=784維的向量;
b. 定義了5個Linear()層,直到最后一個輸出特征是16;
encoder部分生成了潛在code表示;之后進行decoder用於重構;
decoder:
a. 將code中的16個維度通過線性層逐層遞增;
b. 最后得到輸出的784維的特征;
在forward()函數中,對每層的后面都接了ReLU激活函數,最后將網絡結構進行返回;
net = Autoencoder() 創建了一個Autoencoder()實例,當我們需要使用神經網絡的時候就可以調用它;
實際上,對於Fashion MNIST來說,我們甚至不需要這么大的網絡;即使是兩層網絡也可以很好的捕捉到圖像的重要特征;
class Autoencoder(nn.Module): def __init__(self): super(Autoencoder, self).__init__() # encoder self.enc1 = nn.Linear(in_features=784, out_features=256) self.enc2 = nn.Linear(in_features=256, out_features=128) self.enc3 = nn.Linear(in_features=128, out_features=64) self.enc4 = nn.Linear(in_features=64, out_features=32) self.enc5 = nn.Linear(in_features=32, out_features=16) # decoder self.dec1 = nn.Linear(in_features=16, out_features=32) self.dec2 = nn.Linear(in_features=32, out_features=64) self.dec3 = nn.Linear(in_features=64, out_features=128) self.dec4 = nn.Linear(in_features=128, out_features=256) self.dec5 = nn.Linear(in_features=256, out_features=784) def forward(self, x): x = F.relu(self.enc1(x)) x = F.relu(self.enc2(x)) x = F.relu(self.enc3(x)) x = F.relu(self.enc4(x)) x = F.relu(self.enc5(x)) x = F.relu(self.dec1(x)) x = F.relu(self.dec2(x)) x = F.relu(self.dec3(x)) x = F.relu(self.dec4(x)) x = F.relu(self.dec5(x)) return x net = Autoencoder() print(net)
輸出:
Autoencoder( (enc1): Linear(in_features=784, out_features=256, bias=True) (enc2): Linear(in_features=256, out_features=128, bias=True) (enc3): Linear(in_features=128, out_features=64, bias=True) (enc4): Linear(in_features=64, out_features=32, bias=True) (enc5): Linear(in_features=32, out_features=16, bias=True) (dec1): Linear(in_features=16, out_features=32, bias=True) (dec2): Linear(in_features=32, out_features=64, bias=True) (dec3): Linear(in_features=64, out_features=128, bias=True) (dec4): Linear(in_features=128, out_features=256, bias=True) (dec5): Linear(in_features=256, out_features=784, bias=True) )
5)定義網絡的損失函數和優化器
criterion = nn.MSELoss()
optimizer = optim.Adam(net.parameters(), lr=LEARNING_RATE)
6) 定義使用的train和test函數
train()函數
有一些需要注意的地方:
第6行,只提取了數據,而沒有提取Label;
第8行,將28*28的圖像展成784維的形式;
在每次迭代的時候,我們都將loss值存儲到train_loss中,在函數最后進行返回;
每5次迭代后,我們將存儲重構的圖像;可以直觀可視化神經網絡的變現性能;
test()函數:test_image_reconstruction()
將重構一個batch的圖像;
1 def train(net, trainloader, NUM_EPOCHS): 2 train_loss = [] 3 for epoch in range(NUM_EPOCHS): 4 running_loss = 0.0 5 for data in trainloader: 6 img, _ = data 7 img = img.to(device) 8 img = img.view(img.size(0), -1) 9 optimizer.zero_grad() 10 outputs = net(img) 11 loss = criterion(outputs, img) 12 loss.backward() 13 optimizer.step() 14 running_loss += loss.item() 15 16 loss = running_loss / len(trainloader) 17 train_loss.append(loss) 18 print('Epoch {} of {}, Train Loss: {:.3f}'.format( 19 epoch+1, NUM_EPOCHS, loss)) 20 if epoch % 5 == 0: 21 save_decoded_image(outputs.cpu().data, epoch) 22 return train_loss 23 def test_image_reconstruction(net, testloader): 24 for batch in testloader: 25 img, _ = batch 26 img = img.to(device) 27 img = img.view(img.size(0), -1) 28 outputs = net(img) 29 outputs = outputs.view(outputs.size(0), 1, 28, 28).cpu().data 30 save_image(outputs, 'fashionmnist_reconstruction.png') 31 break
7)訓練自編碼網絡
接下來,接可以調用之前定義的utility函數,訓練和檢驗我們的網絡;
代碼說明:
line 2 得到計算設備 cuda: cpu/gpu
line 5 加載網絡到設備上;
line 6 為重構的圖像建立目錄文件;
line 10 繪制訓練損失;
line 19 對圖像進行重構來檢驗單個batch中的影像;
1 # get the computation device 2 device = get_device() 3 print(device) 4 # load the neural network onto the device 5 net.to(device) 6 make_dir() 7 # train the network 8 train_loss = train(net, trainloader, NUM_EPOCHS) 9 plt.figure() 10 plt.plot(train_loss) 11 plt.title('Train Loss') 12 plt.xlabel('Epochs') 13 plt.ylabel('Loss') 14 plt.savefig('deep_ae_fashionmnist_loss.png') 15 # test the network 16 test_image_reconstruction(net, testloader)
8) 分析損失圖和圖像重構結果
四、重構圖像:
可以看出隨着迭代次數的增加,圖像的質量得到了顯著提升;
總結與結論:
本文是關於Pytorch實現一個簡單的深度自編碼器的研究。
在深度學習中,如果你能夠很清晰的理解一個簡單的概念,那么相關的概念也會較為容易理解的。
我在此希望你已經學到了如何使用Pytorch實現深度自編碼器。
接下來,我們將實現卷積自編碼器。