人工神經網絡有許多流行的變體,可用於有監督和無監督學習問題。自編碼器也是神經網絡的一個變種,主要用於無監督學習問題。
當它們在體系結構中有多個隱藏層時,它們被稱為深度自編碼器。這些模型可以應用於包括圖像重建在內的各種應用。
在圖像重建中,他們學習輸入圖像模式的表示,並重建與原始輸入圖像模式匹配的新圖像。圖像重建有許多重要的應用,特別是在醫學領域,需要從現有的不完整或有噪聲的圖像中提取解碼後的無噪聲圖像。
在本文中,我們將演示在PyTorch中實現用於重建圖像的深度自編碼器。該深度學習模型將以MNIST手寫數字為訓練對象,在學習輸入圖像的表示後重建數字圖像。
自編碼器
自編碼器是人工神經網絡的變體,通常用於以無監督的方式學習有效的數據編碼。
他們通常在一個表示學習方案中學習,在那裡他們學習一組數據的編碼。網絡通過學習輸入數據的表示,以非常相似的方式重建輸入數據。自編碼器的基本結構如下所示。
該體系結構通常包括輸入層、輸出層和連接輸入和輸出層的一個或多個隱藏層。輸出層與輸入層具有相同數量的節點,因為它要重新構造輸入。
在它的一般形式中,只有一個隱藏層,但在深度自動編碼器的情況下,有多個隱藏層。這種深度的增加減少了表示某些函數的計算成本,也減少了學習某些函數所需的訓練數據量。其應用領域包括異常檢測、圖像處理、信息檢索、藥物發現等。
在PyTorch中實現深度自編碼器
首先,我們將導入所有必需的庫。
import osimport torch import torchvisionimport torch.nn as nnimport torchvision.transforms as transformsimport torch.optim as optimimport matplotlib.pyplot as pltimport torch.nn.functional as Ffrom torchvision import datasetsfrom torch.utils.data import DataLoaderfrom torchvision.utils import save_imagefrom PIL import Image現在,我們將定義超參數的值。
Epochs = 100Lr_Rate = 1e-3Batch_Size = 128以下函數將用於PyTorch模型所需的圖像轉換。
transform = transforms.Compose([ transforms.ToTensor(), transforms.Normalize((0.5,), (0.5,))])使用下面的代碼片段,我們將下載MNIST手寫數字數據集,並為進一步處理做好準備。
train_set = datasets.MNIST(root='./data', train=True, download=True, transform=transform)test_set = datasets.MNIST(root='./data', train=False, download=True, transform=transform)train_loader = DataLoader(train_set, Batch_Size=Batch_Size, shuffle=True)test_loader = DataLoader(test_set, Batch_Size=Batch_Size, shuffle=True)讓我們看看關於訓練數據及其類的一些信息。
print(train_set)
print(train_set.classes)
在下一步中,我們將定義用於定義模型的Autoencoder類。
class Autoencoder(nn.Module): def __init__(self): super(Autoencoder, self).__init__() #編碼器 self.enc1 = nn.Linear(in_features=784, out_features=256) # Input image (28*28 = 784) 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) #解碼器 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) # Output image (28*28 = 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現在,我們將創建Autoencoder模型作為上面定義的Autoencoder類的一個對象。
model = Autoencoder()print(model)
現在,我們將定義損失函數和優化方法。
criterion = nn.MSELoss()optimizer = optim.Adam(net.parameters(), lr=Lr_Rate)以下函數將啟用CUDA環境。
def get_device(): if torch.cuda.is_available(): device = 'cuda:0' else: device = 'cpu' return device下面的函數將創建一個目錄來保存結果。
def make_dir(): image_dir = 'MNIST_Out_Images' if not os.path.exists(image_dir): os.makedirs(image_dir)使用下面的函數,我們將保存模型生成的重建圖像。
def save_decod_img(img, epoch): img = img.view(img.size(0), 1, 28, 28) save_image(img, './MNIST_Out_Images/Autoencoder_image{}.png'.format(epoch))將調用下面的函數來訓練模型。
def training(model, train_loader, Epochs): train_loss = [] for epoch in range(Epochs): running_loss = 0.0 for data in train_loader: img, _ = data img = img.to(device) img = img.view(img.size(0), -1) optimizer.zero_grad() outputs = model(img) loss = criterion(outputs, img) loss.backward() optimizer.step() running_loss += loss.item() loss = running_loss / len(train_loader) train_loss.append(loss) print('Epoch {} of {}, Train Loss: {:.3f}'.format( epoch+1, Epochs, loss)) if epoch % 5 == 0: save_decod_img(outputs.cpu().data, epoch) return train_loss以下函數將對訓練後的模型進行圖像重建測試。
def test_image_reconstruct(model, test_loader): for batch in test_loader: img, _ = batch img = img.to(device) img = img.view(img.size(0), -1) outputs = model(img) outputs = outputs.view(outputs.size(0), 1, 28, 28).cpu().data save_image(outputs, 'MNIST_reconstruction.png') break在訓練之前,模型將被推送到CUDA環境中,並使用上面定義的函數創建目錄來保存結果圖像。
device = get_device()model.to(device)make_dir()現在,將對模型進行訓練。
train_loss = training(model, train_loader, Epochs)
訓練成功後,我們將在訓練中可視化損失。
plt.figure()plt.plot(train_loss)plt.title('Train Loss')plt.xlabel('Epochs')plt.ylabel('Loss')plt.savefig('deep_ae_mnist_loss.png')
我們將可視化訓練期間保存的一些圖像。
Image.open('/content/MNIST_Out_Images/Autoencoder_image0.png')
Image.open('/content/MNIST_Out_Images/Autoencoder_image50.png')
Image.open('/content/MNIST_Out_Images/Autoencoder_image95.png')
在最後一步,我們將測試我們的自編碼器模型來重建圖像。
test_image_reconstruct(model, testloader)Image.open('/content/MNIST_reconstruction.png')
所以,我們可以看到,自訓練過程開始時,自編碼器模型就開始重建圖像。第一個epoch以後,重建的質量不是很好,直到50 epoch後才得到改進。
經過完整的訓練,我們可以看到,在95 epoch以後生成的圖像和測試中,它可以構造出與原始輸入圖像非常匹配的圖像。
我們根據loss值,可以知道epoch可以設置100或200。
經過長時間的訓練,有望獲得更清晰的重建圖像。然而,通過這個演示,我們可以理解如何在PyTorch中實現用於圖像重建的深度自編碼器。
參考文獻:
Sovit Ranjan Rath, 「Implementing Deep Autoencoder in PyTorch」Abien Fred Agarap, 「Implementing an Autoencoder in PyTorch」Reyhane Askari, 「Auto Encoders」