【周末AI课堂】简单的自编码器(代码篇)| 机器学习你会遇到的“坑”
AI课堂开讲,就差你了!
很多人说,看了再多的文章,可是没有人手把手地教授,还是很难真正地入门AI。为了将AI知识体系以最简单的方式呈现给你,从这个星期开始,芯君邀请AI专业人士开设“周末学习课堂”——每周就AI学习中的一个重点问题进行深度分析,课程会分为理论篇和代码篇,理论与实操,一个都不能少!
来,退出让你废寝忘食的游戏页面,取消只有胡吃海塞的周末聚会吧。未来你与同龄人的差异,也许就从每周末的这堂AI课开启了!
读芯术读者交流群,请加小编微信号:zhizhizhuji。等你。后台回复“周末AI课堂”,查阅相关源代码。
全文共2187字,预计学习时长4分钟
理论回顾
我们在上一节分别介绍了三种自编码器:
? 不加正则项的欠完备自编码器,其中的bottle layer是我们想要的低维表示。
? 加上KL散度项或者使用L1正则化的过完备自编码器,可以在高维隐层中实现稀疏编码。
? 对输入图像添加噪声或者使用梯度正则项的自编码器,整体作为一个去噪声的模型。
在熟练掌握理论的前提下,自编码器的具体实践就会变得非常简单,去噪自编码器可以看作收缩自编码器(CAE)的一种,同时在实践中会涉及到deconvolution和unpooling等技术,所以在这篇文章中,我们着重解决以下两个对初学者更为友好的问题:
? 如何在keras中构建自编码器?
? 假如我们的目的是获得一个低维表示,稀疏自编码器(SAE)和普通的欠完备自编码器,哪一个效果会更好?
自编码器的baseline
在keras中实现自编码器是非常简单的,我们可以利用函数式模型来定义:
from keras.models import Model
from keras import optimizers
from keras.layers import Input,Dense
def autoencoder(dim,act):
input_tensor= Input(shape=(28*28,))
encoder=Dense(dim,activation=act,name='encode')(input_tensor)
decoder = Dense(28*28, activation='sigmoid',name='decode')(encoder)
model = Model(input_tensor,decoder)
model.compile(optimizer=optimizers.Adam(), loss='binary_crossentropy')
return model
我们将模型定义在一个函数中,总共有三层,隐层的维度和激活函数的类型是函数的参数。特别值得注意的是,我们这里使用binary_crossentropy就是二分类的交叉熵,因为我们的损失函数只需要度量输出与输入的相似度(距离)。
定义好模型之后,我们可以很方便的导入数据:
from keras.datasets import mnist
from sklearn.preprocessing import StandardScaler
(X_train,y_train), (X_test, y_test) = mnist.load_data()
X_train = X_train.reshape(60000,28*28)
X_train = X_train.astype('float32') /255
X_test = X_test.reshape(10000, 28*28)
X_test = X_test.astype('float32') /255
scale=StandardScaler().fit(X_train)
X_train=scale.transform(X_train)
X_test =scale.transform(X_test)
这里的特征缩放有着直接的意义,其一,我们的输出单元是sigmoid,它的输出介于(0,1),缩放到这样尺度下对损失函数更友好;其二,PCA需要对数据作归一化,否则我们样本的协方差矩阵就不是一个对角矩阵。
接下来,我们直接开始训练它,并且保存到his变量中(不保存也可以,因为我们不会使用它,但这是个好习惯):
AE=autoencoder(32,'relu')
his=AE.fit(X_train,X_train,batch_size=256,verbose=1,epochs=10)
在训练完成之后,我们还需要做一步,那就获得encode层的输出,在keras中,我们简单可以定义一个新的模型,输入与原模型相同,输出设置为encode层。定义完成之后,就直接可以使用predict方法来获取任意输入的encode层的输出,代码如下:
model = Model(inputs=AE.input,\
outputs=AE.get_layer('encode').output)
model_out=model.predict(X_test)#对任意数据获取输出
此时,我们得到了两个模型,一个叫做AE,是我们训练而来的自编码器,另一个叫做model,是我们用来获取encode输出的模型。
最后我们使用t-SNE来我们上文中获取的表示做一个简单的可视化,我们对整个测试集总共1w个样本做降维,然后再将其放入到t-SNE中,可以得到:
from sklearn import manifold
import matplotlib.pyplot as plt
tsne =manifold.TSNE(n_components=2, init='random', random_state=0)
X_tsne =tsne.fit_transform(model_out)
plt.figure(figsize=(15,10))
for i inrange(10):
plt.scatter(X_tsne[y_test==i,0],X_tsne[y_test==i,1],s=20,label='%d'%i)
plt.title('simple AE')
plt.legend()
plt.show()
更深的自编码器
如果把网络加到合适的深,自编码器可能会获得更好的表示。为了简单的阐释加深的好处,我们将不使用t-SNE步骤,取而代之的是,我们直接将bottle layer的维数设置为2,然后直接利用这个表示做可视化。
首先,我们训练只有一个隐层的自编码器,只需要将上述的函数维数参数改为2即可:
AE_H1=autoencoder(32,'relu')
his=AE_H1.fit(X_train,X_train,batch_size=256,verbose=1,epochs=10)
直接做可视化就可得:
我们在深层的模型中取得了较好的表示,从图中可以看出1和0都是几乎被完全分开的,比起浅层模型已经好了太多。因为我们使用了ReLU激活单元,所以在图中没有出现负轴。
总体看来与不使用稀疏的32维自编码器没有太大差别,但很容易看清楚,集群变得更加紧凑,集群之间的距离略微增大,尤其是2与3、8分的更开了,8的弥散程度减轻。
留言 点赞 发个朋友圈
我们一起分享AI学习与发展的干货
作者:唐僧不用海飞丝
如需转载,请后台留言,遵守转载规范