Pytorchは0から1の変分エンコーダから--(10)


冒頭


今回はエンコーダから変分することについてお話しします.変分エンコーダも一般的なネットワーク構造である.その役割はGANと似ていて、私たちのために「偽乱真」の画像を生成しています.しかし、VAEはGANとは異なり、ジェネレータと区別器を区別する必要はなく、ネットワークでプロセス全体を完了しています.私たちはまず画像を入力して、彼を符号化して、それから私たちのネットワーク構造を通じて符号化の分散と平均値を生成して、それから生成画像を復号して、ここで最も重要なのはこの分散と平均値の生成です.自分はちょうど1回再現して、ここはやはりとても多く理解して掌握する地方を必要とすると感じて、しかも1種の悪くない設計の構想です.詳細については、VAEを参考にご紹介します.ここではコードだけを話します.

VAE変分セルフエンコーダ


ライブラリの導入
import os
import torch.nn as nn
import torchvision
import torch.nn.functional as F
from torchvision import transforms
import torch
from torchvision.utils import save_image

デバイスの設定と画像を保存するアドレスの設定
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
sample_dir = 'sample_dir'
if not os.path.exists(sample_dir):
    os.makedirs(sample_dir)

スーパーパラメータの定義
image_size = 784
h_dim = 400
z_dim = 20
num_epochs = 15
batch_size = 128
learning_rate = 1e-3

ここで説明する、h_dimとは、最初の非表示レイヤ、すなわち、画像を入力した後に最初に通過する非表示レイヤの出力特徴寸法を指す.z_dimは予測分散と平均値のネットワーク層の出力特徴寸法を表し,我々の平均値と分散の寸法寸法寸法であると理解できる.データの準備とロード
data = torchvision.datasets.MNIST(root = '../../data/',
                                  download = True,
                                  train = True,
                                  transform = transforms.ToTensor())

data_loader = torch.utils.data.DataLoader(dataset = data,
                                          shuffle = True,
                                          batch_size = batch_size)

VAEモデルの構築
class VAE(nn.Module):
    def __init__(self,image_size,h_dim = 400,z_dim = 20):
        super(VAE, self).__init__()
        self.fc1 = nn.Linear(image_size,h_dim)
        self.fc2 = nn.Linear(h_dim,z_dim)
        self.fc3 = nn.Linear(h_dim,z_dim)
        self.fc4 = nn.Linear(z_dim,h_dim)
        self.fc5 = nn.Linear(h_dim,image_size)
    def encode(self,x):
        h = F.relu(self.fc1(x))
        return self.fc2(h),self.fc3(h)
    def reparameterize(self,mu,log_var):
        std = torch.exp(log_var / 2)
        ep = torch.randn_like(std)
        return mu + ep * std

    def decode(self,z):
        h = F.relu(self.fc4(z))
        return F.relu(self.fc5(h))
    def forward(self, x):
        mu,log_var = self.encode(x)
        z = self.reparameterize(mu,log_var)
        x_reconst = self.decode(z)
        return x_reconst,mu,log_var

Encode操作は,平均値と分散を計算し,それをreparameterize関数に転送し,分散と平均値をステップ処理し,分散と平均値からなる式を得,decode関数に伝達して復号してピクチャを得る.モデルとオプティマイザの定義
model = VAE().to(device)
optimizer = torch.optim.Adam(model.parameters(),lr = learning_rate)

トレーニングモデル
for epoch in range(num_epochs):
    for i,(images,_) in enumerate(data_loader):
        x = images.to(device).view(-1,image_size)
        x_reconst,mu,log_var = model(x)
        loss_reconst = F.binary_cross_entropy(x_reconst,x,size_average=True)
        kl_div = -0.5 * torch.sum(1 + log_var - mu.pow(2) - log_var.exp())
        loss = x_reconst + kl_div
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        if (i + 1) % 10 == 0:
            print("Epoch[{}/{}], Step [{}/{}], Reconst Loss: {:.4f}, KL Div: {:.4f}"
                  .format(epoch + 1, num_epochs, i + 1, len(data_loader), loss_reconst.item(), kl_div.item()))

我々の損失は,我々が再生成したピクチャと既存の実ピクチャの二分交差エントロピー損失のみならず,KL分散から構成されているが,この式は上で共有したリンクを参照することができ,内部で詳細な説明がある.両者の加算は我々の損失を得,その後損失を逆伝搬し最適化し,すなわち訓練を完了した.モデルのテスト
with torch.no_grad():
    # Save the sampled images
    #  
    z = torch.randn(batch_size, z_dim).to(device)
    out = model.decode(z).view(-1, 1, 28, 28)
    save_image(out, os.path.join(sample_dir, 'sampled-{}.png'.format(epoch + 1)))

    # Save the reconstructed
    out, _, _ = model(x)
    x_concat = torch.cat([x.view(-1, 1, 28, 28), out.view(-1, 1, 28, 28)], dim=3)
    save_image(x_concat, os.path.join(sample_dir, 'reconst-{}.png'.format(epoch + 1)))

ランダムに正規分布の数のセットを生成し、平均値は0、分散は1である.その後、この符号化を私たちのモデルに与え、生成された画像を記憶し、実際の画像をモデルに与え、両者を接続して比較しやすいようにします.また真実を預ける.

まとめ


VAEはGAN機能によく似たネットワーク構造であり,主に損失関数の由来と計算分散と平均値の意味を明らかにするためにGANの理解を借りてVAEをよく理解することができる.