自编码器微调_自编码(AutoEncoder)模型及几种扩展之三——SDAE

5、 SDAE模型

SDAE(stacked denoised autoencoder ,堆栈去噪自编码器)是vincent大神提出的无监督的神经网络模型,论文:Stacked Denoising Autoencoders: Learning Useful Representations ina Deep Network with a Local Denoising Criterion,原文作者从不同角度解释了模型架构设计理念,非常值得一读。原文请戳:http://www.jmlr.org/papers/volume11/vincent10a/vincent10a.pdf

sDAE的思想就是将多个DAE堆叠在一起形成一个深度的架构. 需要注意的是, 只有在训练的时候才会对输入进行腐蚀(加噪), 一旦训练完成, 就不需要在进行腐蚀, 如下图所示

自编码器微调_自编码(AutoEncoder)模型及几种扩展之三——SDAE_第1张图片

SDAE只是一个特征提取器,并不具有分类功能。为了使SDAE具有分类功能,需在其顶层添加分类器,如SVM、softmax等,并使用带标签的数据对SDAE进行有监督训练,最后使用利用BP算法对整个网络参数进行微调,便得到具有分类功能的SDAE。

具体步骤如下:

  • Step1 初始化SDAE网络参数;
  • Step2 训练第一层DAE,将其隐含层作为第2个DAE的输入,并进行同样的训练,直到第n层DAE训练完成;
  • Step3 将训练好的n层DAE进行堆叠形成SDAE,向SDAE网络顶层添加输出层;
  • Step4 利用样本数据和标签对整个网络进行有监督的微调。

来自李宏毅的PPT的图可能更清楚理解其训练过程:

自编码器微调_自编码(AutoEncoder)模型及几种扩展之三——SDAE_第2张图片

逐层贪婪训练:每层自编码层都单独进行非监督训练,以最小化输入(输入为前一层的隐层输出)与重构结果之间的误差为训练目标。前K层训练好了,就可以训练K+1层,因为已经前向传播求出K层的输出,再用K层的输出当作K+1的输入训练K+1层。

一旦SDAE训练完成, 其高层的特征就可以用做传统的监督算法的输入。当然,也可以在最顶层添加一层logistic regression layer(softmax层),然后使用带label的数据来进一步对网络进行微调(fine-tuning),即用样本进行有监督训练(如上图中最上层是10类分类)。

看代码吧:

##### 设置网络参数 #####
epochs_layer = 10 #每一层DAE训练迭代次数,100
epochs_whole = 20 #SDAE训练迭代次数,200
batch_size = 256
origin_dim = 784  #输入维数
h_dim1 = 256   # SDAE第1隐层的神经元数量
h_dim2 = 64    #

准备数据:

(x_train, _), (x_test, _) = mnist.load_data()

#.....

# 给数据添加噪声
noise_factor = 0.2
x_train_noisy = x_train + noise_factor * np.random.normal(loc = 0.0, scale = 1.0, size = x_train.shape)
x_test_noisy = x_test + noise_factor * np.random.normal(loc = 0.0, scale = 1.0, size = x_test.shape)

单个DAE模型:

##### 构建单个DAE #####
class AutoEncoderLayer():
    def __init__(self, input_dim, output_dim):
        self.input_dim = input_dim
        self.output_dim = output_dim
        self.build()

    def build(self):
        self.input = Input(shape=(self.input_dim,))
        self.encode_layer = Dense(self.output_dim, activation='relu')  #或者sigmoid
        self.encoded = self.encode_layer(self.input)

        # 编码器部分
        self.encoder = Model(self.input, self.encoded)  

        self.decode_layer = Dense(self.input_dim, activation='sigmoid')
        self.decoded = self.decode_layer(self.encoded)

        #DAE模型
        self.autoencoder = Model(self.input, self.decoded)

SDAE模型设计(巧)

注意: SDAE是 E-E-D-D的形式,用DAE的编码结果组合而成,最后再fine-tuning

# 构建堆栈去噪自编码模型-SDAE
class StackedAutoEncoder():
    def __init__(self, layer_list): #参数是一组DAE
        self.layer_list = layer_list
        self.build()

    def build(self):
        out = self.layer_list[0].encoded
        for i in range(1, num_layers ): #堆栈过程:用DAE的编码器部分实现
            out = self.layer_list[i].encode_layer(out)
            
        self.model = Model(self.layer_list[0].input, out)

SDAE每一层的训练函数,也即,DAE的训练:

# 预训练每一层的DAE
def train_layers(encoder_list=None, layer=None, epochs=None, batch_size=None):
    '''
    预训练:逐层训练,当训练第layer个ae时,使用前(layer-1)个ae训练好的encoder的参数
    :param encoder_list:
    :param layer:
    :param epochs:
    :param batch_size:
    :return:
    '''
    # 对前(layer-1)层用已经训练好的参数进行前向计算,ps:第0层没有前置层
    out = x_train_noisy
    origin = x_train
    if layer != 0:
        for i in range(layer):
            # print("encoder weight", str(i), ":", encoder_list[i].encoder.get_weights()[0])
            out = encoder_list[i].encoder.predict(out)

    encoder_list[layer].autoencoder.summary()
    encoder_list[layer].autoencoder.compile(optimizer='adadelta', loss='binary_crossentropy')

    # 训练第layer个DAE
    encoder_list[layer].autoencoder.fit(
        out,
        origin if layer == 0 else out,
        epochs=epochs,
        batch_size=batch_size,
        shuffle=True,
        verbose=2
    )

SDAE的fine_tuning函数:

#fine-tuning SDAE是用的函数
def train_whole(sae=None, epochs=None, batch_size=None):
    '''
    用预训练好的参数初始化stacked ae的参数,然后进行全局训练优化
    :param model:
    :param epochs:
    :param batch_size:
    :return:
    '''

    sae.model.summary()
    sae.model.compile(optimizer='adadelta', loss='binary_crossentropy')
    sae.model.fit(
        x_train,
        x_train,
        epochs=epochs,
        batch_size=batch_size,
        shuffle=True,
        validation_data=(x_test_noisy, x_test),
        verbose=2
    )

DAE的预训练:

# 训练过程
# 4层的stacked ae,实例化4个DAE
num_layers = 4
encoder_1 = AutoEncoderLayer(origin_dim, h_dim1)
encoder_2 = AutoEncoderLayer(h_dim1, h_dim2)
decoder_3 = AutoEncoderLayer(h_dim1, h_dim2)
decoder_4 = AutoEncoderLayer(h_dim1, origin_dim)
autoencoder_list = [encoder_1, encoder_2, decoder_3, decoder_4]

# DAE预训练:按照顺序对每一层进行预训练
print("Pre training:")
for level in range(num_layers - 1):
    print("level:", level)
    train_layers(encoder_list=autoencoder_list, layer=level, epochs=epochs_layer, batch_size=batch_size)

SDAE的fine-tuning训练:

# 用训练好的4个ae构建stacked dae
stacked_ae = StackedAutoEncoder(autoencoder_list)
print("Whole training:")
# 进行全局训练优化
train_whole(sae=stacked_ae, epochs=epochs_whole, batch_size=batch_size)

结果显示:

##### 显示stacked dae重构后的效果 #####
decoded_imgs = stacked_ae.model.predict(x_test_noisy)
n = 10
plt.figure(figsize=(20, 4))
for i in range(1, n):
    # 展示原始图像
    ax = plt.subplot(2, n, i)
    plt.imshow(x_test_noisy[i].reshape(28, 28))
    plt.gray()
    ax.get_xaxis().set_visible(False)
    ax.get_yaxis().set_visible(False)
    # 展示自编码器重构后的图像
    ax = plt.subplot(2, n, i + n)
    plt.imshow(decoded_imgs[i].reshape(28, 28))
    plt.gray()
    ax.get_xaxis().set_visible(False)
    ax.get_yaxis().set_visible(False)

plt.show()

看看mnist上的结果吧:

第1个DAE结构:

自编码器微调_自编码(AutoEncoder)模型及几种扩展之三——SDAE_第3张图片

SDAE结构:

自编码器微调_自编码(AutoEncoder)模型及几种扩展之三——SDAE_第4张图片

复原字符图像(建议增大迭代次数)

自编码器微调_自编码(AutoEncoder)模型及几种扩展之三——SDAE_第5张图片

补,epoch=100, 效果还不错

自编码器微调_自编码(AutoEncoder)模型及几种扩展之三——SDAE_第6张图片

SDAE编码结果:

自编码器微调_自编码(AutoEncoder)模型及几种扩展之三——SDAE_第7张图片

SDAE真的这么神吗,还有什么用?.......欢迎大神交流......

(待续)

参考文献:

  1. [自编码器:理论+代码]:自编码器、栈式自编码器、欠完备自编码器、稀疏自编码器、去噪自编码器、卷积自编码器_小太阳~-CSDN博客_欠完备自编码器

2 堆叠式降噪自动编码器(SDA)_Mr_Researcher 的博客-CSDN博客_堆叠降噪自编码器代码

3 https://github.com/MadhumitaSushil/SDAE

你可能感兴趣的:(自编码器微调)