0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

pythonでGANの勉強1 オートエンコーダ

Posted at

pythonでGANの勉強をしていきたいと思います。

自分の勉強のメモとなります。
コードが見づらかったり、正しくない場合があるかもしれません。

まずは、オートエンコーダについて勉強していきます。
「はじめてのディープラーニング」をもとにkerasやpytorchでも実装してみるという流れとなります。

オートエンコーダ

オートエンコーダはエンコーダとデコーダの2つの部分からなります。

  1. エンコーダ
     訓練済みのエンコーダを使って、最初のデータ表現、例えば画像$x$を入力とすれば、その次元を$\tilde{y}$ を$\tilde{z}$ に減らす
  2. 潜在空間($z$)
     ネットワークを訓練するにあたって、潜在空間に何らかの意味が形成される
     通常は入力より小さな次元で、中間ステップとして動作
  3. デコーダ
     元の表現と同じものを、元の次元で再構築する
     このステップにより$z$は$x^*$に変換される

オートエンコーダの訓練は以下のように行われる。

  1. 画像$x$を取り出しオートエンコーダに入力する
  2. $x^*$ が出力される。これは再構成された画像である。
  3. 再構成誤差を計算する。これは$x$と$x^*$の差である。
     これは$x$と$x^*$ の距離(例えばMAE)として計算され、明示的な目的関数($|x-x^*|$)が定義され、勾配降下法により最適化可能となる

実装

まずはnumpyだけでの実装です。
一番下にのせた参考書をもとに作成します。

まず、各層の実装です。
中間層と出力層のみとなります。

import numpy as np

class BaseLayer:
    def update(self, eta):
        self.w -= eta * self.grad_w
        self.b -= eta * self.grad_b

class MiddleLayer(BaseLayer):
    def __init__(self, n_upper, n):
        self.w = np.random.randn(n_upper, n) * np.sqrt(2/n_upper)
        self.b = np.zeros(n)
    
    def forward(self, x):
        self.x = x
        self.u = np.dot(x, self.w) + self.b
        self.y = np.where(self.u <= 0, 0, self.u) # ReLU
    
    def backward(self,grad_y):
        delta = grad_y * np.where(self.u <=0 , 0, 1)
        
        self.grad_w = np.dot(self.x.T, delta)
        self.grad_b = np.sum(delta, axis=0)
        self.grad_x = np.dot(delta, self.w.T)

class OutputLayer(BaseLayer):
    def __init__(self, n_upper, n):
        self.w = np.random.randn(n_upper, n) * np.sqrt(2/n_upper)
        self.b = np.zeros(n)
    
    def forward(self, x):
        self.x = x
        u = np.dot(x, self.w) + self.b
        self.y = 1/(1+np.exp(-u))
    
    def backward(self, t):
        delta = (self.y-t) * self.y * (1-self.y)
        
        self.grad_w = np.dot(self.x.T, delta)
        self.grad_b = np.sum(delta, axis=0)
        self.grad_x = np.dot(delta, self.w.T)

次に、順伝搬と逆伝播、パラメータ更新の定義をします。

def forward_propagation(x_mb):
    middle_layer.forward(x_mb)
    output_layer.forward(middle_layer.y)

def backpropagation(t_mb):
    output_layer.backward(t_mb)
    middle_layer.backward(output_layer.grad_x)

def update_params():
    output_layer.update(eta)
    middle_layer.update(eta)

学習を行います。

import matplotlib.pyplot as plt
from sklearn import datasets

digits_data = datasets.load_digits()
x_train = np.asarray(digits_data.data)
x_train /= 15

def get_error(y, t):
    return 1.0/2.0*np.sum(np.square(y - t))

img_size = 8
n_in_out = img_size * img_size
n_mid = 16

eta = 0.01
epochs = 41
batch_size = 32
interval = 4

middle_layer = MiddleLayer(n_in_out, n_mid)
output_layer = OutputLayer(n_mid, n_in_out)

error_record = []
n_batch = len(x_train) // batch_size
for i in range(epochs):
    
    index_random = np.arange(len(x_train))
    np.random.shuffle(index_random)
    for j in range(n_batch):
        mb_index = index_random[j*batch_size : (j+1)*batch_size]
        x_mb = x_train[mb_index, :]
        
        forward_propagation(x_mb)
        backpropagation(x_mb)
        
        update_params()
    
    forward_propagation(x_train)
    error = get_error(output_layer.y, x_train)
    error_record.append(error)
    
    if i%interval == 0:
        print("Epoch:"+str(i+1)+'/'+str(epochs), "Error:"+str(error))

plt.plot(range(1, len(error_record)+1), error_record)
plt.xlabel("Epochs")
plt.ylabel("Error")
plt.show()

image.png

結果の確認をします。
上の行は入力画像、真ん中の行は潜在空間、一番下の行が出力結果です。

n_img = 10
middle_layer.forward(x_train[:n_img])
output_layer.forward(middle_layer.y)

plt.figure(figsize=(10, 3))
for i in range(n_img):
    
    ax = plt.subplot(3, n_img, i+1)
    plt.imshow(x_train[i].reshape(img_size, -1).tolist(), cmap="Greys_r")
    
    ax.get_xaxis().set_visible(False)
    ax.get_yaxis().set_visible(False)
    
    ax = plt.subplot(3, n_img, i+1+n_img)
    plt.imshow(middle_layer.y[i].reshape(4, -1).tolist(), cmap="Greys_r")
    ax.get_xaxis().set_visible(False)
    ax.get_yaxis().set_visible(False)
    
    ax = plt.subplot(3, n_img, i+1+2*n_img)
    plt.imshow(output_layer.y[i].reshape(img_size, -1).tolist(), cmap="Greys_r")
    ax.get_xaxis().set_visible(False)
    ax.get_yaxis().set_visible(False)

image.png

入力画像が再現され散ることがわかります。

pytorch

同じことをpytorchで実装してみたいと思います。

まず必要なライブラリのインポートをします。

import torch
import torch.nn as nn
import torch.optim as optimizers
from torch.utils.data import Dataset, DataLoader, TensorDataset

データの準備ですが、さきほどと同じデータを使用します。

digits_data = datasets.load_digits()
x_train = np.asarray(digits_data.data)
x_train /= 15
x_train = x_train.reshape(-1, 1, 64)
y = digits_data.target

x_train = torch.tensor(x_train, dtype=torch.float32)
y_train = torch.tensor(y, dtype=torch.float64)

train = TensorDataset(x_train, y_train)
train_dataloader = DataLoader(train, batch_size=32, shuffle=True)

オートエンコーダを定義します。

class AutoEncoder(nn.Module):
    def __init__(self, device='cpu'):
        super().__init__()
        self.device = device
        self.l1 = nn.Linear(64, 16)
        self.l2 = nn.Linear(16, 64)
    
    def forward(self, x):
        h = self.l1(x)
        h = torch.relu(h)
        h = self.l2(h)
        y = torch.sigmoid(h)
        
        return y

モデルの設定を行います。

device = None

model = AutoEncoder(device=device).to(device)
criterion = nn.BCELoss()
optimizer = optimizers.Adam(model.parameters())

学習を実行します。

epochs = 40
train_loss_record = []
for epoch in range(epochs):
    train_loss = 0.
    for (x, _) in train_dataloader:
        x = x.to(device)
        model.train()
        preds = model(x)
        loss = criterion(preds, x)
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        train_loss += loss.item()
    
    train_loss /= len(train_dataloader)
    train_loss_record.append(train_loss)
    
    if epoch%4 == 0:
        print("Epoch: {}, Loss: {:3f}".format(epoch+1, train_loss))

学習の様子を可視化します。

plt.plot(range(1, len(train_loss_record)+1), train_loss_record)
plt.xlabel("Epochs")
plt.ylabel("Error")
plt.show()

image.png

入力画像と出力画像の比較を行います。

n_img = 10

x = x_train[:n_img]
mid_out = model.l1(x)
out = model(x)

plt.figure(figsize=(10, 3))
for i in range(n_img):
    
    ax = plt.subplot(3, n_img, i+1)
    plt.imshow(x_train[i].reshape(img_size, -1).tolist(), cmap="Greys_r")
    
    ax.get_xaxis().set_visible(False)
    ax.get_yaxis().set_visible(False)
    
    ax = plt.subplot(3, n_img, i+1+n_img)
    plt.imshow(mid_out[i].reshape(4, -1).tolist(), cmap="Greys_r")
    ax.get_xaxis().set_visible(False)
    ax.get_yaxis().set_visible(False)
    
    ax = plt.subplot(3, n_img, i+1+2*n_img)
    plt.imshow(out[i].reshape(img_size, -1).tolist(), cmap="Greys_r")
    ax.get_xaxis().set_visible(False)
    ax.get_yaxis().set_visible(False)

image.png

keras

kerasで同じものを実装します。

まず必要なライブラリのインポートをします。

from tensorflow.keras.models import Sequential, Model
from tensorflow.keras.layers import Input, Activation, Dense

データは他のものと同様のものもを使用します。

digits_data = datasets.load_digits()
x_train = np.asarray(digits_data.data)
x_train /= 15
y = digits_data.target

モデルの作成をします。Sequential()を使用します。

input_shape=x_train.shape[1:]
model = Sequential()
model.add(Dense(16, activation='relu', input_shape=input_shape, name='fc1'))
model.add(Dense(64, activation='softmax', name='fc2'))

モデルをコンパイルします。

model.compile(optimizer='adam',
              loss='binary_crossentropy')

学習を実行します。

history = model.fit(x_train, x_train,
                    epochs=100,
                    batch_size=32,
                    shuffle=True,
                    validation_data=(x_train, x_train))

学習の様子を可視化します。

plt.plot(range(1, len(history.history['loss'])+1), history.history['loss'])
plt.xlabel("Epochs")
plt.ylabel("Error")
plt.show()

image.png

入力画像と出力画像を比較します。

n_img = 10

x = np.float64(x_train[:n_img])
mid_out = np.array(model.layers[0](x))
out = np.array(model(x))

plt.figure(figsize=(10, 3))
for i in range(n_img):
    
    ax = plt.subplot(3, n_img, i+1)
    plt.imshow(x_train[i].reshape(img_size, -1).tolist(), cmap="Greys_r")
    
    ax.get_xaxis().set_visible(False)
    ax.get_yaxis().set_visible(False)
    
    ax = plt.subplot(3, n_img, i+1+n_img)
    plt.imshow(mid_out[i].reshape(4, -1).tolist(), cmap="Greys_r")
    ax.get_xaxis().set_visible(False)
    ax.get_yaxis().set_visible(False)
    
    ax = plt.subplot(3, n_img, i+1+2*n_img)
    plt.imshow(out[i].reshape(img_size, -1).tolist(), cmap="Greys_r")
    ax.get_xaxis().set_visible(False)
    ax.get_yaxis().set_visible(False)

image.png

参考文献

0
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?