基于自编码网络AutoEncoder完成数据降维并且提取数据的本质特征

colorknight 2019-03-26

什么是数据的降维?

一维数据我们可以认为它是一个点,二维数据是一条线,三维数据是一个面,但四维数据我们就想象不到了,但这并不意味着不存在。对于深度学习的数据来说,数据的维度往往远远大于四维,四维我们都想象不到,那么远超四维的数据我们就更加难以预料了,为了解决这个问题,我们可以使用机器学习中的数据降维技术,简单的来说就是将高维的数据降低到两维或者三维,也就是人类可以想象到的数据表示形式,这样我们就可以看到这些数据的本质特征了,这样大大降低了计算的复杂程度,减少了冗余信息所造成的识别误差,提高了识别的精度,我们对降维数据进行可视化的操作可以方便我们对这些数据的理解。

基于自编码网络AutoEncoder完成数据降维并且提取数据的本质特征

由三维降低到二维

但是数据的降维不是随意的,我们要保证一点数据降维之后仍然能够最大程度的表示原有的数据特点,也就是最大程度的保留原有数据的特征,使得数据不损失原始数据的主要特征,那么这个就是数据降维的关键点所在,在深度学习领域常用的数据降维的方式是使用自编码网络AutoEncoder来完成这个任务。

AutoEncoder的原理

如下图所示,自编码网络Autoencoder 简单来说就是将原有高维特征的数据x进行压缩成z,之后再进行解压为x撇的过程,得到的最终结果x撇与原始数据x进行比较,从而对此进行非监督学习。

基于自编码网络AutoEncoder完成数据降维并且提取数据的本质特征

encode和decode过程

AutoEncoder进行end-to-end的训练,不断提高其准确率,而通过设计encode和decode过程使输入和输出越来越接近,是一种无监督学习过程。它类似于机器学习中的PCA算法,AutoEncoder的主要功能是将数据压缩之后得到的降维的特征值,这一中间结果正类似于PCA的结果,这也正是原始数据的最本质特征。

基于自编码网络AutoEncoder完成数据降维并且提取数据的本质特征

原始数据的最本质特征

AutoEncoder的可视化

现在我们已经知道了AutoEncoder关键点在于将原始数据降维,而降维的数据就是原始数据的最本质特征,我们可以使用这个降维的数据来表示原有的高维数据。然后我们还可以应用这个降维的数据进行升维操作,从而恢复到原始数据。

基于自编码网络AutoEncoder完成数据降维并且提取数据的本质特征

降维和升维

如图所示,就是AutoEncoder的可视化过程,这个过程分为两个部分,encoder和decoder。encoder完成了数据的降维操作,decoder完成数据的升维操作,通过可视化我们可以看到,输出一张图片2的数据,降维之后我们并不知道变成了什么,但是降维之后的数据却可以恢复为原始的数据2,这就是AutoEncoder的可视化过程。

Autoencoder的实现

class AutoEncoder(nn.Module):
 def __init__(self):
 super(AutoEncoder, self).__init__()
 # 降维
 self.encoder = nn.Sequential(
 nn.Linear(28*28, 128),
 nn.Tanh(),
 nn.Linear(128, 64),
 nn.Tanh(),
 nn.Linear(64, 12),
 nn.Tanh(),
 nn.Linear(12, 3), 
 )
 # 升维
 self.decoder = nn.Sequential(
 nn.Linear(3, 12),
 nn.Tanh(),
 nn.Linear(12, 64),
 nn.Tanh(),
 nn.Linear(64, 128),
 nn.Tanh(),
 nn.Linear(128, 28*28),
 nn.Sigmoid(), # 激励函数让输出值在 (0, 1),因为原始数据transform到了(0,1)
 )
 def forward(self, x):
 encoded = self.encoder(x)
 decoded = self.decoder(encoded)
 return encoded, decoded #返回编码结果和解码结果
autoencoder = AutoEncoder()
optimizer = torch.optim.Adam(autoencoder.parameters(), lr=0.1)
loss_func = nn.MSELoss()
for epoch in range(EPOCH):
 for step, (x, b_label) in enumerate(train_loader):
 b_x = x.view(-1, 28*28) #原始数据
 b_y = x.view(-1, 28*28) #原始数据
 encoded, decoded = autoencoder(b_x)#原始数据放到网络中
 loss = loss_func(decoded, b_y) #计算损失
 optimizer.zero_grad() 
 loss.backward() 
 optimizer.step()

神经网络是很神奇的,如果给定一个神经网络,我们假设其输出与输入是相同的,然后训练调整其网络参数,从而得到每一层中的权重。对于每一层权重,我们可以任务它们是输入x的几种不同表示,这些表示就是特征。