<jupyter_start><jupyter_text>コンペティション課題5  課題変分オートエンコーダ（VAE）により, FashionMNISTの画像を生成してみましょう。  目標値ELBO (周辺尤度下界): -240以上 (大きいほど良い)  ルール- 「修正しないでください」とあるセルを、修正しないでください。- 基本的なアーキテクチャはVAEとしてください。内部のアーキテクチャは自由です。- 以下のセル内の`x_train`以外の学習データは使わないでください。  提出方法- 1つのファイルを提出していただきます。  1. テストデータ`x_test`に対する予測ラベルを`submission5_gen.csv`として保存・ダウンロードしてください。  2. Homeworkタブから**Day5 Pred (.csv)**を選択して提出してください。  3. それとは別に、最終提出に対応するノートブックを[Final Submission]などと命名しわかるようにiLect System上に置いておいてください。- 成績優秀者には、次回講義にて取り組みの発表をお願いいたします。 LeaderBoard- コンペティション期間中のLeaderBoardは提出されたcsvファイルのうち50%を使って計算されます。- コンペティション終了時には提出されたcsvファイルのうち、コンペティション期間中のLeaderBoard計算に使われなかったもう半分のデータがスコア計算に使用されます。- このため、コンペ中の順位とコンペ終了後にLeaderBoardが更新された後の順位やスコアが食い違うことがあります。  評価方法- 評価は生成画像のテストデータに対するELBOで行います.  $\sum_{i=1}^D x_i\log \hat{x}_i + (1-x_i)\log (1-\hat{x}_i) - KL\ divergence$- このスコアが大きいほど、良いモデルとなっています。  データの読み込み- このセルは修正しないでください。- 誤って修正した場合は、元ファイルをコピーし直してください。<jupyter_code>import numpy as np
import csv
from sklearn.model_selection import train_test_split

import torch
import torch.nn as nn
import torch.nn.functional as F


def kl_divergence(mean, var):
    return -0.5*(1 + np.log(var) - mean**2 - var).sum(axis=1)


def clip_log(x):
    return torch.log(torch.clamp(x, 1e-10, None))


### データとイテレータの準備 ###

class train_dataset(torch.utils.data.Dataset):
    def __init__(self, x_train, transform=None):
        self.x_train = x_train.reshape(-1, 1, 28, 28).astype('float32') / 255
        self.transform = transform

    def __len__(self):
        return self.x_train.shape[0]

    def __getitem__(self, idx):
        data = torch.tensor(self.x_train[idx], dtype=torch.float)
        if self.transform:
            data = self.transform(data)
        return data


class test_dataset(torch.utils.data.Dataset):
    def __init__(self, x_test, transform=None):
        self.x_test = x_test.reshape(-1, 1, 28, 28).astype('float32') / 255
        self.transform = transform

    def __len__(self):
        return self.x_test.shape[0]

    def __getitem__(self, idx):
        data = torch.tensor(self.x_test[idx], dtype=torch.float)
        if self.transform:
            data = self.transform(data)
        return data


# 学習データ
x_train = np.load('/root/userspace/public/day5/homework5/data/x_train.npy')
# テストデータ
x_test = np.load('/root/userspace/public/day5/homework5/data/x_test.npy')
    
train_data = train_dataset(x_train)
test_data = test_dataset(x_test)

batch_size = 32
test_size = 50

dataloader_train = torch.utils.data.DataLoader(
    train_data,
    batch_size=batch_size,
    shuffle=True
)

dataloader_test = torch.utils.data.DataLoader(
    test_data,
    batch_size=test_size,
    shuffle=False
)<jupyter_output><empty_output><jupyter_text>VAEの実装<jupyter_code>rng = np.random.RandomState(1234)
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')


class VAE(nn.Module):
    def __init__(self, input_size=784, hidden_size=400, z_dim=10):
        super(VAE, self).__init__()
        # encoder
        self.h1 = nn.Linear(input_size, hidden_size)
        self.batchnorm1 = nn.BatchNorm1d(400)
        self.h2 = nn.Linear(hidden_size, hidden_size)
        self.mean = nn.Linear(hidden_size, z_dim)
        self.var = nn.Linear(hidden_size, z_dim)
        # decoder
        self.h3 = nn.Linear(z_dim, hidden_size)
        self.batchnorm2 = nn.BatchNorm1d(400)
        self.h4 = nn.Linear(hidden_size, hidden_size)
        self.out = nn.Linear(hidden_size, input_size)
    def encode(self, x):
        h1 = F.relu(self.h1(x))
        h1 = self.batchnorm1(h1)
        h2 = F.relu(self.h2(h1))
        mean = self.mean(h2)
        var = F.softplus(self.var(h2))
        return mean, var
    
    def sampling_z(self, mean, var):
        epsilon = torch.randn(mean.shape).to(device)
        z = mean + torch.sqrt(var) * epsilon
        return z
    
    def decode(self, z): 
        h3 = F.relu(self.h3(z))
        h3 = self.batchnorm2(h3) 
        h4 = F.relu(self.h4(h3))
        
        y = torch.sigmoid(self.out(h4))
        return y
        
    def lower_bound(self, x):
        # encode
        mean, var = self.encode(x)
        KL = -0.5 * torch.mean(torch.sum(1+clip_log(var) - mean**2 - var, dim=1))
        
        # z
        z = self.sampling_z(mean, var)

        # decode
        y = self.decode(z)
        reconstruction = torch.mean(torch.sum(x*clip_log(y) + (1-x) * clip_log(1-y), dim=1))
        
        return reconstruction, KL # lower_bound


model = VAE().to(device)
optimizer = torch.optim.Adam(model.parameters(),lr=0.0003)


num_epochs=100
for epoch in range(num_epochs):
    for i, x in enumerate(dataloader_train):
        x = x.to(device).view(-1, 784)
        reconst_loss, kl_div  = model.lower_bound(x)
        loss =  - (reconst_loss - kl_div)
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        
        if (i+1)%100 == 0:
            print(f"Epoch:{epoch+1}/{num_epochs}, Step:{i+1}/{len(dataloader_train)}, Lower Bound:{-loss.item():.2f}, Reconst:{reconst_loss.item():.2f}, KL:{-kl_div.item():.2f}")
            

# Encode
for x in dataloader_test:
    x = x.to(device)
    mean, var = model.encode(x.reshape(-1, 784))
sample_z = mean

# Decode
sample_x = model.decode(sample_z)

mean = mean.cpu().detach().numpy()
var = var.cpu().detach().numpy()
sample_x = sample_x.cpu().detach().numpy()

kl = kl_divergence(mean, var)
result = np.concatenate([sample_x.reshape(-1, 28*28), kl.reshape(-1, 1)], 1).tolist()
with open('/root/userspace/submission5_gen240.csv', 'w') as file:
    writer = csv.writer(file, lineterminator='\n')
    writer.writerows(result)<jupyter_output>Epoch:1/100, Step:100/2186, Lower Bound:-286.40, Reconst:-275.89, KL:-10.51
Epoch:1/100, Step:200/2186, Lower Bound:-279.81, Reconst:-267.94, KL:-11.87
Epoch:1/100, Step:300/2186, Lower Bound:-259.85, Reconst:-247.61, KL:-12.24
Epoch:1/100, Step:400/2186, Lower Bound:-263.59, Reconst:-251.60, KL:-11.99
Epoch:1/100, Step:500/2186, Lower Bound:-243.00, Reconst:-231.56, KL:-11.45
Epoch:1/100, Step:600/2186, Lower Bound:-278.39, Reconst:-265.86, KL:-12.53
Epoch:1/100, Step:700/2186, Lower Bound:-247.98, Reconst:-235.80, KL:-12.18
Epoch:1/100, Step:800/2186, Lower Bound:-262.83, Reconst:-249.83, KL:-13.00
Epoch:1/100, Step:900/2186, Lower Bound:-264.67, Reconst:-251.66, KL:-13.01
Epoch:1/100, Step:1000/2186, Lower Bound:-243.71, Reconst:-231.10, KL:-12.62
Epoch:1/100, Step:1100/2186, Lower Bound:-262.75, Reconst:-250.18, KL:-12.57
Epoch:1/100, Step:1200/2186, Lower Bound:-279.50, Reconst:-265.79, KL:-13.71
Epoch:1/100, Step:1300/2186, Lower Bound:-255.30, Reconst:-241.50, KL:-13.81
Epoch:1/[...]
{'fraction_non_alphanumeric': 0.14993972272453285, 'fraction_numerical': 0.07172995780590717, 'mean_word_length': 3.401193633952255, 'pattern_counts': {'":': 0, '<': 8, '<?xml version=': 0, '>': 8, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '2', 'dir': 'jupyter-structured-clean-dedup', 'id': '628561', 'license': 'MIT', 'n_tokens_mistral': 3273, 'n_tokens_neox': 2948, 'n_words': 426, 'path': 'homework5-Final.ipynb', 'repo_name': 'Leozyc-waseda/DeepLearning_Course_Homework', 'size': '6636'}