The End of the World

勉強したことのメモが中心。たまに日々の雑感。

PytorchによるAutoEncoder Familyの実装

はじめに

AutoEncoderとはニューラルネットワークによる次元削減の手法で、日本語では自己符号化器と呼ばれています。DeepLearningの手法の中では使い道がよくわからないこともあり比較的不人気な気がします。(個人的には教師なしで抽象的な情報を取り出すのはとても面白そうだと思います。)

今回は自分の勉強のためにPyTorchでAutoEncoderを実装します。コードはこちら

AutoEncoder

まずは3層MLPの一番簡単な奴。ネットワーク定義はこんな感じ。

class AutoEncoder(nn.Module):
    def __init__(self, input_size, embedding_dimension):
        # initialization of class
        super(AutoEncoder, self).__init__()

        # define the network
        self.layer1 = nn.Linear(input_size, 32)
        self.layer2 = nn.Linear(32, input_size)
        self.encoder = nn.Sequential(
                        self.layer1,
                        nn.ReLU()
                        )
        self.decoder = nn.Sequential(
                        self.layer2,
                        nn.Sigmoid()
                        )

    def forward(self, x):
        encoded = self.encoder(x)
        decoded = self.decoder(encoded)

        return encoded, decoded

    def initialization(self, mean=0, std=0.01):
        nn.init.normal(self.layer1.weight, mean, std)
        nn.init.normal(self.layer2.weight, mean, std)

シンプルですね。中間層の前にReLUを入れてしまっているのがちょっと微妙かも。パラメータの初期化は平均0標準偏差0.01の正規分布にしてます。実験では中間層のノードの数は10にしています。

再構成の結果はこんな感じ。

f:id:dl-kento:20180222195026p:plain

Deep AutoEncoder

今度は層の数を増やし、10層のNNを学習してみます。画像を見るとうまく学習できていないことがわかります。DeepなNNの学習の難しさが見て取れますね。

f:id:dl-kento:20180222195554p:plain

Stacked AutoEncoder

単に層を深くするだけでは学習がうまく行かないので工夫を加えます。層ごとに事前学習をしていくのですが、方法が2つあります。ひとつは入力に近い層から1層ずつ学習する方法。ふたつ目は両端の層から中心の層に向かって学習していく方法です。(下図参照)今回はJ. Xieらの論文*1を参考にして後者の方法で学習をします。初期化方法や学習率も論文に合わせています.論文を読み直したら普通に入力に近い層から1層ずつ学習していました...すみません.

f:id:dl-kento:20180225141350j:plain:w500

実装は、クラスの中で層を積み上げる数に応じてアトリビュートを作成しています(ここが動的にできると良い?)また、学習時にはoptimizerを定義するときに学習するレイヤーを指定しています。かなり見苦しいコードになってしまったので早く修正したいところではあります。

結果はこちら。層が深くなっても学習できています。見栄えも良くなった気がします。

f:id:dl-kento:20180222200132p:plain

Convolutional AutoEncoder

CNNによるAutoEncoderです。画像の潜在表現を取り出す方法としてはこちらのほうが理にかなっている気はします。下の画像はCAEのネットワーク構造になります。*2

f:id:dl-kento:20180226161649p:plain

モデル定義はこのようになりました。kerasのようにpadding='same'とできないので少しブサイクな実装になっています。

class Convolutional_AutoEncoder(nn.Module):
    def  __init__(self, embedding_dimension):
        super(Convolutional_AutoEncoder, self).__init__()

        # define the network
        # encoder
        self.conv1 = nn.Sequential(nn.ZeroPad2d((1,2,1,2)),
                              nn.Conv2d(1, 32, kernel_size=5, stride=2),
                              nn.ReLU())
        self.conv2 = nn.Sequential(nn.ZeroPad2d((1,2,1,2)),
                              nn.Conv2d(32, 64, kernel_size=5, stride=2),
                              nn.ReLU())
        self.conv3 = nn.Sequential(nn.Conv2d(64, 128, kernel_size=3, stride=2, padding=0),
                              nn.ReLU())
        self.fc1 = nn.Conv2d(128, 10, kernel_size=3)

        # decoder
        self.fc2 = nn.Sequential(nn.ConvTranspose2d(10, 128, kernel_size=3),
                            nn.ReLU())
        self.conv3d = nn.Sequential(nn.ConvTranspose2d(128, 64, kernel_size=3, stride=2, padding=0),
                               nn.ReLU())
        self.conv2d = nn.Sequential(nn.ConvTranspose2d(64, 32, kernel_size=5, stride=2),
                               nn.ReLU())
        self.conv1d = nn.ConvTranspose2d(32, 1, kernel_size=5, stride=2)

    def forward(self, x):
        encoded = self.fc1(self.conv3(self.conv2(self.conv1(x))))

        decoded = self.fc2(encoded)
        decoded = self.conv3d(decoded)
        decoded = self.conv2d(decoded)[:,:,1:-2,1:-2]
        decoded = self.conv1d(decoded)[:,:,1:-2,1:-2]
        decoded = nn.Sigmoid()(decoded)

return encoded, decoded

再構成の結果はこちらです。きれいですね。

f:id:dl-kento:20180226162931p:plain

まとめ

今回はAE, SAE, CAEを実装しました。また新しく実装したものがあれば追記したいと思います。

*1:Xie, Junyuan et al. “Unsupervised Deep Embedding for Clustering Analysis.” ICML (2016). https://arxiv.org/abs/1511.06335

*2:Xifeng Guo, Xinwang Liu, En Zhu, Jianping Yin. Deep Clustering with Convolutional Autoencoders. ICONIP 2017. https://link.springer.com/chapter/10.1007/978-3-319-70096-0_39