自动编码器与GAN
自动编码器
自动编码器是一种人工神经网络,不需要任何监督就可以学习输入数据的密集特征,称为潜在表征/编码。有的自动编码器是生成模型,能够随机生成看起来与训练数据非常相似的数据。但看起来效果并不好。相比之下,生成式对抗网络(GAN)生成的人脸就真实很多。
GAN(生成式对抗网络)
最近比较火的一个网站:https://thispersondoesnotexist.com/,这个网站会随机展示一张人脸,这张人脸就是GAN随机生成的,在现实世界中并不存在。
PS:这个网站的作者把模型开源了,可以下载运行试试!
https://github.com/NVlabs/stylegan2
目前GAN广泛用于:
- 超分辨率(提高图像分别率)
- 着色,编辑图像,比如替换背景
- 预测视频的下一帧图像
- 扩充数据集
两者的关联
这两个模型都是非监督的,都可以作为生成模型。
两者的区别
这两种技术的工作方式不一样。
自动编码器:查看输入 → 将输入转换为有效的潜在表征 → 通过潜在表征输出非常接近输入的东西,通常包括两部分:
- 将输入转换为潜在表征的编码器/识别网络
- 将内部表征转换为输出的编码器/生成网络
GAN是由两个神经网络组成的,
- 一个用来生成跟训练数据相似的数据,叫生成器。
- 另一个用来从虚假数据中分辨出真实数据,叫判别器。
使用不完整的线性自动编码器执行PCA
因为内部表征的维度比输入数据的维度要低(输入为3D,输出为2D),所以自动编码器是不完整的。不完整的自动编码器无法将输入简单复制到编码中,所以需要找到一种输出其输入副本的方法,让它被迫学习输入数据中最重要的特征。
如果自动编码器仅使用线性激活,且成本函数是均方误差,则最后执行的是主成分分析。
先构建一个简单的线性自动编码器,用来对3D的数据集进行PCA降维,投影到2D。
- 自动编码器分为两个子部件,编码器和解码器。这两个部件都是用单一Dense层的常规Sequential模型,自动解码器就是包含编码器和解码器的Sequential模型,换句话说,其实就是一个模型作为了另一个模型的一个层。
- 解码器神经元个数为3,因为输出为3维,自动编码器的输出数量要和输入的数量相等(指的是降维前的输入数量!)。
- 神经元不使用任何激活函数,因为神经元都是线性的,成本函数是MSE,只需要指定一个优化器就可以了。
代码如下:
# 先生成一个3D的数据集作为输入
np.random.seed(4)
# m为一维的长度,w1和w2为权重,noise为噪声扰动
def generate_3d_data(m, w1=0.1, w2=0.3, noise=0.1):
angles = np.random.rand(m) * 3 * np.pi / 2 - 0.5
data = np.empty((m, 3))
data[:, 0] = np.cos(angles) + np.sin(angles)/2 + noise * np.random.randn(m) / 2
data[:, 1] = np.sin(angles) * 0.7 + noise * np.random.randn(m) / 2
data[:, 2] = data[:, 0] * w1 + data[:, 1] * w2 + noise * np.random.randn(m)
return data
X_train = generate_3d_data(60)
X_train = X_train - X_train.mean(axis=0, keepdims=0)
# 然后建立自动编码器
np.random.seed(42)
tf.random.set_seed(42)
encoder = keras.models.Sequential([keras.layers.Dense(2, input_shape=[3])]) # 编码器有2个神经元
decoder = keras.models.Sequential([keras.layers.Dense(3, input_shape=[2])]) # 解码器有3个神经元
autoencoder = keras.models.Sequential([encoder, decoder])
# 优化函数使用SGD,学习率调的高一些,这样能训练的快一些
autoencoder.compile(loss="mse", optimizer=keras.optimizers.SGD(learning_rate=1.5))
# 开始训练
history = autoencoder.fit(X_train, X_train, epochs=20)
这里训练完全可以放心大胆的跑,训练很快,因为数据集的规模一共才60*3,而且学习率还高到1.5,20轮训练一秒就结束

训练完成后用模型对该数据集进行编码
codings = encoder.predict(X_train)
然后绘制生成的数据:
# 设置中文不乱码
plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['axes.unicode_minus']=False
fig = plt.figure(figsize=(4,3))
plt.plot(codings[:,0], codings[:, 1], "b.")
plt.xlabel("$z_1$", fontsize=18)
plt.ylabel("$z_2$", fontsize=18, rotation=0)
plt.grid(True)
plt.title("数据集生成的2D投影")
save_fig("2D投影")
plt.show()
顺带生成一下原始的3D数据:
# 设置中文不乱码
plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['axes.unicode_minus']=False
ax = plt.subplot(projection = '3d') # 创建1个3维的绘图工程
ax.set_title("3D数据集原始图像")
ax.scatter(X_train[:,0], X_train[:, 1], X_train[:, 2],"b")
ax.set_xlabel("$x_1$")
ax.set_ylabel("$x_2$")
ax.set_zlabel("$x_3$")
生成图像如下:

上图为数据集原始图像

上图为数据集生成的2D投影图像
注意,自动编码器找到的这个2D投影并不是$x_1x_2$平面,而是3D图像中斜向的一个最佳2D平面,尽可能的保留了数据中的方差(因为我们的损失函数用的就是MSE)。
Comments | NOTHING