zoukankan      html  css  js  c++  java
  • 收缩自编码器(CAE)

    自编码器是一种很好的降维技术,它可以学习到数据中非常有用的信息。而收缩自编码器作为正则自编码器的一种,其非线性降维效果非常好,并且它的过程可以通过流形知识来解释。

    基础知识

    1、自编码器

    自编码器是一种降维的技术,由编码器和解码器两部分组成,架构图如下。编码器 (f) 用来输出降维后的表示 (h),而解码器 (g) 则通过最小化代价函数从编码器的输出 (h) 来重构原始的输入 (x),输出 (r)。

    编码器 (f) 和解码器 (g) 的内部结构是一个仿射函数(线性组合)再加一个(线性或非线性)激活函数,形式如下:

    [h=fleft( x ight) =s _{f}left( Wx+b _{h} ight), ]

    [r=gleft( h ight) =s _{g}left( W'h+b _{r} ight). ]

    其中,(s) 是激活函数,(W) 是权重矩阵,(b) 是偏置向量。为了防止自编码器学习到整体收缩再放大的无用映射,一般 (W'=W ^{T})。

    详细的自编码器介绍可以参考Introduction to autoencoders.

    2、流形切平面

    流形的一个重要特征是切平面的集合。(d) 维流形上的一点 (x),切平面由能张成流形上允许变动的局部方向的 (d) 维基向量给出。这是《Deep Learning》上的定义,其实切平面就是切线、切面拓展到高维的情况,类似于超平面的概念。

    3、Keras

    Keras 是一个用 Python 编写的高级神经网络 API,它能够以 TensorFlow、CNTK 或者 Theano 作为后端运行。Keras 的开发重点是支持快速的实验。能够以最小的时延把你的想法转换为实验结果,是做好研究的关键。

    使用 Keras 前一定要安装 TensorFlow、CNTK 和 Theano 三个框架中的任一一个,并且要注意每个框架适用的 Python 版本,提前配置好相应的环境。

    收缩自编码器(CAE)

    1、定义

    为了提高对训练集数据点周围小扰动的鲁棒性,收缩自编码器在基础自编码器上添加了正则项,其形式为编码器的映射 (f) 关于输入 (x) 的 (Jacobian) 矩阵的 (Frobenius) 范数(具体形式如下),目的是迫使其学习在训练样本上有更强收缩作用的映射。

    [left| J _{f}left( x ight) ight| ^{2} _{F}=sum _{ij}left( dfrac {partial h _{j}left( x ight) }{partial x _{i}} ight) ^{2}. ]

    假设训练集为 (D _{n}),我们通过最小化重构误差以及对梯度的惩罚来学习自编码器的参数,完整的代价函数如下:

    [J _{CAE}left( heta ight) =sum _{xin D _{n}}left( L(x,g(f(x)))+lambda left| J _{f}left( x ight) ight| ^{2} _{F} ight). ]

    其中 (L) 是重构误差,形式为平方误差(线性自编码器)或者交叉熵损失(非线性误差),而(lambda ) 则是控制正则化强度的超参数。

    2、解释

    从代价函数来看,收缩自编码器通过两种相反的推动力学习有用信息--重构误差和收缩惩罚(正则项)。收缩惩罚迫使自编码器学习到的所有映射对于输入的梯度都很小,即把输入都降维到一个很小的区域(点附近),而重构误差迫使自编码器学习一个恒等映射,保留完整的信息。两种推动力冲击下,使得大部分映射对于输入的梯度都很小,而只有少部分的大梯度。这样在输入具有小扰动时,小梯度会减小这些扰动,达到增加自编码器对输入附近小扰动的鲁棒性。

    3、学习流形

    学习流形的介绍可以看我以前的博客“学习流形”的初认识

    从流行角度来进一步探索,训练数据是位于一个低维流形上的。数据中的变化对应于流形上的局部变化(沿着切平面的方向),而数据中的不变方向是对应于正交于流形的方向。只要我们学习到数据中的变化和不变方向,那么流形的结构也就被捕捉到了。

    回头再看收缩自编码器学习的两种推动力,收缩惩罚想要使学习到的特征在所有方向上不变(对所有方向都有收缩作用),而重构误差则想要能将学习到的特征重构回输入。所以在学习的过程中,重构误差的推动力使数据中的变化方向(即流形切平面的方向)能够抵抗收缩作用,体现在其对应的 (Jacobian) 矩阵中的奇异值很大;而抵抗不了收缩作用的方向则对应于数据中不变的方向(正交于流形的方向),其在 (Jacobian) 矩阵中的梯度则会变得很小。

    由此可以看出收缩自编码器可以很好地捕捉流形结构。

    代码实现

    下面收缩自编码器的实现是基于 Keras 框架的。

    导入数据:

    from tensorflow.examples.tutorials.mnist import input_data
    from keras.layers import Input, Dense
    from keras.models import Model
    
    import numpy as np
    import matplotlib.pyplot as plt
    import keras.backend as K
    

    导入 MNISR 数据:

    mnist = input_data.read_data_sets('../data/MNIST_data', one_hot=True)
    
    X_train, y_train = mnist.train.images, mnist.train.labels
    X_val, y_val = mnist.validation.images, mnist.validation.labels
    X_test, y_test = mnist.test.images, mnist.test.labels
    

    定义收缩自编码器:

    def contractive_autoencoder(X, lam=1e-3):
        X = X.reshape(X.shape[0], -1)
        M, N = X.shape
        N_hidden = 64
        N_batch = 100
    
        inputs = Input(shape=(N,))
        encoded = Dense(N_hidden, activation='sigmoid', name='encoded')(inputs)
        outputs = Dense(N, activation='linear')(encoded)
    
        model = Model(input=inputs, output=outputs)
    
        def contractive_loss(y_pred, y_true):
            mse = K.mean(K.square(y_true - y_pred), axis=1)
    
            W = K.variable(value=model.get_layer('encoded').get_weights()[0])  # N x N_hidden
            W = K.transpose(W)  # N_hidden x N
            h = model.get_layer('encoded').output
            dh = h * (1 - h)  # N_batch x N_hidden
    
            # N_batch x N_hidden * N_hidden x 1 = N_batch x 1
            contractive = lam * K.sum(dh**2 * K.sum(W**2, axis=1), axis=1)
    
            return mse + contractive
    
        model.compile(optimizer='adam', loss=contractive_loss)
        model.fit(X, X, batch_size=N_batch, nb_epoch=3)
    
        return model, Model(input=inputs, output=encoded)
    

    训练模型并测试,画出重构后的图形:

    model, representation = contractive_autoencoder(X_train)
    
    idxs = np.random.randint(0, X_test.shape[0], size=5)
    X_recons = model.predict(X_test[idxs])
    
    for X_recon in X_recons:
        plt.imshow(X_recon.reshape(28, 28), cmap='Greys_r')
        plt.show()
    

    代码主要参考了Deriving Contractive Autoencoder and Implementing it in Keras,其中还详细推导了收缩正则项的计算形式,有兴趣的可以看一下。

    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.
  • 相关阅读:
    php cookie名不能使用点号(句号)
    jquery:iframe里面的元素怎样触发父窗口元素的事件?
    __destruct与register_shutdown_function执行的先后顺序问题
    curl: (60) SSL certificate problem: unable to get local issuer certificate 错误
    js与as3交互的问题
    启动smaba后nginx 11 resource temporarily unavailable[转载]
    PHP错误: Exception thrown without a stack frame in Unknown on line 0[转载]
    Discuz x2.5的注册后返回第三方应用
    laravel-admin select关联
    laravel-admin 自动生成模块
  • 原文地址:https://www.cnblogs.com/woaiml/p/DL1.html
Copyright © 2011-2022 走看看