Tensorflow基于CNN的AutoEncoder

Tensorflow基于CNN的AutoEncoder

完整代码:https://github.com/SongDark/cnn_autoencoder_mnist

一、概述

AutoEncoder属于无监督学习,由一个编码器Encoder和一个解码器Decoder组成,是一个Encoder-Decoder结构,它学习的目标是还原输入,不需要提供标签。

1.1 AutoEncoder和PCA的关系

AutoEncoder和PCA有点像,PCA是对标准化的输入,用SVD的方式计算一个矩阵 W W W,对输入进行线性变换,AutoEncoder是非线性的。理论上,AutoEncoder的Reconstruct loss会比PCA的更低,因为它非线性,信息丢失会更少。

1.2 AutoEncoder恢复的一定不模糊吗

不一定,根据我的经验,一般的AE恢复出来的图像很糊。De-Noising AutoEncoder能稍微缓解,它在输入加噪,要求Decoder恢复出加噪前的输入,强迫AE具有去噪功能。

1.3 AutoEncoder可以用来做什么

  1. 压缩。图像、词向量等高维流型,压缩成低维。
  2. 预训练。用不带标签的样本,对分类器逐层用AE做预训练,作为分类器的初始参数,然后再fine-tune。

二、数据源

使用Mnist作为训练数据,Mnist的获取可以参考这篇博客:
获取MNIST数据的几种方法


三、Encoder和Decoder结构

Encoder输入图片输出编码,Decoder输入编码输出图片,因此用多层卷积结构实现Encoder,用多层解卷积结构实现Decoder。下面代码实现的结构,支持任意指定编码维度(output_dim)。

class CNN_Encoder(BasicBlock):
    def __init__(self, output_dim, sn=False, name=None):
        super(CNN_Encoder, self).__init__(None, name or "CNN_Encoder")
        self.output_dim = output_dim
        self.sn = sn # spectral norm
    
    def __call__(self, x, sn=False, is_training=True, reuse=False):
        with tf.variable_scope(self.name, reuse=reuse):
            net = lrelu(conv2d(x, 64, 4, 4, 2, 2, sn=self.sn, padding="SAME", name="conv1"), name="l1")
            net = lrelu(bn(conv2d(net, 128, 4, 4, 2, 2, sn=self.sn, padding="SAME", name="conv2"), is_training, name="bn2"), name="l2")
            net = lrelu(bn(conv2d(net, 256, 4, 4, 2, 2, sn=self.sn, padding="SAME", name="conv3"), is_training, name="bn3"), name="l3")
            net = tf.reshape(net, [-1, 4*4*256])
            net = lrelu(bn(dense(net, 1024, sn=self.sn, name="fc4"), is_training, name="bn4"), name="l4")
            out = dense(net, self.output_dim, sn=self.sn, name="fc5")
        return out

class CNN_Decoder(BasicBlock):
    def __init__(self, sn=False, name=None):
        super(CNN_Decoder, self).__init__(None, name or "CNN_Decoder")
        self.sn = sn
    
    def __call__(self, x, is_training=True, reuse=False):
        with tf.variable_scope(self.name, reuse=reuse):
            net = tf.nn.relu(dense(x, 1024, name='fc1'))
            net = tf.nn.relu(bn(dense(net, 256*4*4, name='fc2'), is_training, name='bn2'))
            net = tf.reshape(net, [-1, 4, 4, 256])
            net = tf.nn.relu(bn(deconv2d(net, 128, 4, 4, 1, 1, padding="VALID", name='dc3'), is_training, name='bn3'))
            net = tf.nn.relu(bn(deconv2d(net, 64, 4, 4, 2, 2, padding="SAME", name='dc4'), is_training, name='bn4'))
            out = tf.nn.sigmoid(deconv2d(net, 1, 4, 4, 2, 2, padding="SAME", name="dc5"))
        return out

四、AutoEncoder实现

核心代码

# 核心代码
def build_placeholder(self):
    self.source = tf.placeholder(shape=(self.batch_size, 28, 28, 1), dtype=tf.float32)
    self.target = tf.placeholder(shape=(self.batch_size, 28, 28, 1), dtype=tf.float32)
    
def build_network(self):
    self.embedding = self.encoder(self.source, is_training=True, reuse=False)
    self.pred = self.decoder(self.embedding, is_training=True, reuse=False)

def build_optimizer(self):
    self.loss = mse(self.pred, self.target, self.batch_size)
    self.solver = tf.train.AdamOptimizer(learning_rate=2e-4, beta1=0.5).minimize(self.loss, var_list=self.encoder.vars + self.decoder.vars)

五、恢复效果

经过试验,用上面的Encoder和Decoder,需要将编码维度至少设为8以上,才能有比较好的恢复效果。原本想尝试压缩成2维,但是基本无法还原。
下图是编码长度为10的结果,每一行4附图,奇数位为Encoder输入的原图,偶数位为Decoder恢复图。

Tensorflow基于CNN的AutoEncoder_第1张图片

六、编码可视化

用t-sne将10维的编码降维至2维,以在平面直角坐标系中可视化。

# 核心代码
from sklearn.manifold import TSNE 

model = TSNE(n_components=2, random_state=0)
embs = model.fit_transform(embs)
plt.scatter(embs[:, 0], embs[:, 1], c=labels)
plt.colorbar() 

t-sne只是对Encoder的编码做了降维,可以看到降维后,数字0(深蓝)、6(黄)、9(红)靠得很近,因为它们比较相似,编码效果与我的直观感受是一致的。

Tensorflow基于CNN的AutoEncoder_第2张图片

七、有监督的Auto-Encoder

  AutoEncoder是无监督的,它最大的问题就是,你无法控制模型学到什么东西。模型的工作原理就是一个压缩-解压的过程,你无法要求编码的某一位代表特定的意义。现在我们引入样本标签,实现这个功能。
  具体来说,将中间的编码分成两部分:标签部分+噪声部分。一方面,重构损失要求编码器将图像信息压缩进整个编码,解码器从整个编码解压图像;另一方面,引入分类损失,要求编码的前十位在Softmax后与样本标签一致。
  最终达到的效果是:整段编码压缩了输入图像的信息,单独取出编码的前十位做Softmax能得到输入图像的类别。

Tensorflow基于CNN的AutoEncoder_第3张图片

我将编码结果的前十位的Softmax分类结果写在下图第2和第4列的小标题处,可以看到预测的标签都正确。

Tensorflow基于CNN的AutoEncoder_第4张图片

完整代码

https://github.com/SongDark/cnn_autoencoder_mnist


参考资料

sklearn.manifold.TSNE
matplotlib.pyplot.scatter
Hinton在Science上的论文 “Reducing the Dimensionality of Data with Neural Networks”
Denoising Auto-Encoder “Extracting and Composing Robust Features with Denoising Autoencoders”
李宏毅机器学习-Unsupervised Learning - Auto-encoder

你可能感兴趣的:(机器学习,深度学习)