AutoEncoder
自编码器是输入神经元数等于输出神经元数的神经网络。自编码器由两部分组成:
1.编码器:从输入层到隐层, 它可以用一个编码函数表示;
2.解码器:从隐层到输出层,重构输入。 它可以用解码函数表示。
完整的自编码器为:
如果隐层神经元数小于输入层神经元数,这样的自编码器称为欠完备或不完备自编码器。
自编码器的应用
1)自编码器可用于降维;
2)自编码器可作为强大的特征检测器(feature detectors),应用于深度神经网络的预训练;
3)自编码器还可以随机生成与训练数据类似的数据,这被称作生成模型(generative model);
4)数据压缩
普通自编码器(3层)
普通自编码器是具有一个隐藏层的三层网络,输入和输出神经元数是相同的,用于学习如何重构输入,例如使用adam优化器和均方误差损失函数。
在这里,我们看到我们有一个欠完备自编码器,因为隐藏层维(64)小于输入(784)。 这个约束将强加我们的神经网络来学习压缩的数据表示。
input_size = 784
hidden_size = 64
output_size = 784
x = Input(shape=(input_size,))
# Encoder
h = Dense(hidden_size, activation='relu')(x)
# Decoder
r = Dense(output_size, activation='sigmoid')(h)
autoencoder = Model(input=x, output=r)
autoencoder.compile(optimizer='adam', loss='mse')
多层自编码器
也称为栈式自编码器(Stacked Autoencoders)或深度自编码器。如果一个隐藏层不够用,我们显然可以将自编码器扩展到更多的隐藏层。 任何隐藏层都可以作为特征表示,但我们将使网络结构对称并使用最中间的隐藏层。
input_size = 784
hidden_size = 128
code_size = 64
x = Input(shape=(input_size,))
# Encoder
hidden_1 = Dense(hidden_size, activation='relu')(x)
h = Dense(code_size, activation='relu')(hidden_1)
# Decoder
hidden_2 = Dense(hidden_size, activation='relu')(h)
r = Dense(input_size, activation='sigmoid')(hidden_2)
autoencoder = Model(input=x, output=r)
autoencoder.compile(optimizer='adam', loss='mse')
卷积自编码器
我们也可能会问自己:自编码器可以用于卷积层而不是全连接层吗?
答案是肯定的,原理是一样的,但使用图像(3D矢量)而不是平坦的1维矢量。 对输入图像进行下采样以提供较小尺寸的隐藏表示并强制自编码器学习图像的压缩版本。
x = Input(shape=(28, 28,1))
# Encoder
conv1_1 = Conv2D(16, (3, 3), activation='relu', padding='same')(x)
pool1 = MaxPooling2D((2, 2), padding='same')(conv1_1)
conv1_2 = Conv2D(8, (3, 3), activation='relu', padding='same')(pool1)
pool2 = MaxPooling2D((2, 2), padding='same')(conv1_2)
conv1_3 = Conv2D(8, (3, 3), activation='relu', padding='same')(pool2)
h = MaxPooling2D((2, 2), padding='same')(conv1_3)
# Decoder
conv2_1 = Conv2D(8, (3, 3), activation='relu', padding='same')(h)
up1 = UpSampling2D((2, 2))(conv2_1)
conv2_2 = Conv2D(8, (3, 3), activation='relu', padding='same')(up1)
up2 = UpSampling2D((2, 2))(conv2_2)
conv2_3 = Conv2D(16, (3, 3), activation='relu')(up2)
up3 = UpSampling2D((2, 2))(conv2_3)
r = Conv2D(1, (3, 3), activation='sigmoid', padding='same')(up3)
autoencoder = Model(input=x, output=r)
autoencoder.compile(optimizer='adam', loss='mse')
正则化的自编码器
还有其他一些方法可以限制自编码器的重构,而不是简单地强加一个维度比输入小的隐藏层。 正规化自编码器不是通过调整编码器和解码从而限制模型容量,而是使用损失函数,鼓励模型学习除了将输入复制到其输出之外的其他属性。 在实践中,我们通常会发现两种正规化自编码器:稀疏自编码器和去噪自编码器。
稀疏自编码器:稀疏自编码器通常用于学习分类等其他任务的特征。 稀疏自编码器必须响应数据集独特的统计特征,而不仅仅是作为标识函数。 通过这种方式,用稀疏性惩罚来执行复制任务的训练可以产生有用的特征模型。
我们可以限制自编码器重构的另一种方式是对损失函数施加约束。 例如,我们可以在损失函数中添加一个修正术语。 这样做会使我们的自编码器学习数据的稀疏表示
注意在我们的正则项中,我们添加了一个l1激活函数正则器,它将在优化阶段对损失函数应用一个惩罚。 在结果上,与正常普通自编码器相比,该表示现在更稀松。
input_size = 784
hidden_size = 64
output_size = 784
x = Input(shape=(input_size,))
# Encoder
h = Dense(hidden_size, activation='relu', activity_regularizer=regularizers.l1(10e-5))(x)
# Decoder
r = Dense(output_size, activation='sigmoid')(h)
autoencoder = Model(input=x, output=r)
autoencoder.compile(optimizer='adam', loss='mse')
去噪自编码器
我们可以获得一个自编码器,通过改变损失函数的重构误差项来学习一些有用的东西,而不是对损失函数加以惩罚。 这可以通过给输入图像添加一些噪声并使自编码器学会移除噪声从而来进行训练。 通过这种方式,编码器将提取最重要的特征并学习数据的更鲁棒的表示。
x = Input(shape=(28, 28, 1))
# Encoder
conv1_1 = Conv2D(32, (3, 3), activation='relu', padding='same')(x)
pool1 = MaxPooling2D((2, 2), padding='same')(conv1_1)
conv1_2 = Conv2D(32, (3, 3), activation='relu', padding='same')(pool1)
h = MaxPooling2D((2, 2), padding='same')(conv1_2)
# Decoder
conv2_1 = Conv2D(32, (3, 3), activation='relu', padding='same')(h)
up1 = UpSampling2D((2, 2))(conv2_1)
conv2_2 = Conv2D(32, (3, 3), activation='relu', padding='same')(up1)
up2 = UpSampling2D((2, 2))(conv2_2)
r = Conv2D(1, (3, 3), activation='sigmoid', padding='same')(up2)
autoencoder = Model(input=x, output=r)
autoencoder.compile(optimizer='adam', loss='mse')