用pytorch實現Autoencoder


原文連接: 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實現深度自編碼器。

接下來,我們將實現卷積自編碼器。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM