Pytorch :线性⾃编码⽹络降维(对⽐PCA )
Pytorch: 图像⾃编码器-线性⾃编码⽹络降维与SVM, PCA 降维与SVM
Copyright: Jingmin Wei, Pattern Recognition and Intelligent System, School of Artificial and Intelligence, Huazhong University of Science and Technology
⽂章⽬录
本教程不商⽤,仅供学习和参考交流使⽤,如需转载,请联系本⼈。
Reference
概念
⾃编码器⽹络,实际上是⼀种⾃监督学习。 它主要分为编码层和解码层,和语义分割⽹络的结构⾮常类似。和普通的⽹络不同,在计算损失以及优化时,不是拿标签和⽹络输出的分类之间进⾏损失计算,⽽是拿原数据(图像)和编码⽹络输出的数据(图像)之间计算损失。⾃编码器主要应⽤于两个⽅⾯,第⼀是对数据降维,或者降维后对数据进⾏可视化;第⼆是对数据进⾏去噪,尤其是图像数据去噪。最初的⾃编码器是⼀个三层⽹络结构,即输⼊层、中间隐藏层和输出层,其中输⼊层和输出层的神经元个数相同,且中间隐藏层的神经元个数会较少,从⽽达到降维的⽬的。其⽹络结构如图所⽰。
深度⾃编码器是将⾃编码器堆积起来,可以包含多个中间隐藏层。由于其可以有更多的中间隐藏层,所以对数据的表⽰和编码能⼒更强,⽽且在实际应⽤中也更加常⽤。
稀疏⾃编码器,是在原有⾃编码器的基础上,对隐层单元施加稀疏性约束,这样会得到对输⼊数据更加紧凑的表⽰,在⽹络中仅有⼩部分神经元会被激活,常⽤的稀疏约束是使⽤ 范数约束,⽬的是让不重要的神经元的权重为 。
卷积⾃编码器是使⽤卷积层搭建获得的⾃编码⽹络。当输⼊数据为图像时,由于卷积操作可以从图像数据中获取更丰富的信息,所以使⽤卷积层作为⾃编码器隐藏层,通常可以对图像数据进⾏更好的表⽰。在实际应⽤中,⽤于处理图像的⾃动编码器的隐藏层⼏乎都是基于卷积的⾃动编码器。在卷积⾃编码器的编码器部分,通常可以通过池化层负责对数据进⾏下采样,卷积层负责对数据进⾏表⽰,⽽解码器通常使⽤可以对特征映射进⾏上采样的操作来完成。
基于线性层的⾃编码模型
类似于全连接神经⽹络的⾃编码模型,即⽹络中编码层和解码层都使⽤线性层包含不同数量的神经元来表⽰。针对⼿写字体数据集,利⽤⾃编码模型对数据降维和重构。
在⾃编码⽹络中,输⼊层和输出层都有 个神经元,对应着⼀张⼿写图⽚的 个像素数,即在使⽤图像
时将 的图像转化为 的向量。在进⾏编码的过程中,神经元的数量逐渐从 个减少到 个,主要是便于降维后数据分布情况的可视化,并分析⼿写字体经过编码后在空间中的分布规律。在解码器中神经元的数量逐渐增加,会从特征编码中重构原始图像。
针对⾃编码模型主要介绍三个相关的应⽤。
1. 使⽤⾃编码模型对⼿写字体图像进⾏重构
2. 可视化测试样本通过⽹络得到的特征编码,将其在三维空间中进⾏数据可视化,观察数据的分布规律。
3. 使⽤⾃编码⽹络降维后的数据特征和 SVM 分类器结合,将⼿写字体数据建⽴分类器,并将分类结果和使⽤ PCA 降维后建⽴的 SVM 分类器进⾏对⽐。
l 1078478428×281×7845123
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D # 三维数据可视化import hiddenlayer as hl
from sklearn.manifold import TSNE
from sklearn.svm import SVC
from sklearn.decomposition import PCA
ics import classification_report, accuracy_score
import torch
as nn
functional as F
import torch.utils.data as Data
import torch.optim as optim
from torchvision import transforms
from torchvision.datasets import MNIST
from torchvision.utils import make_grid
# 模型加载选择GPU
device = torch.device("cuda"if torch.cuda.is_available()else"cpu") # device = torch.device('cpu')
print(device)
print(torch.cuda.device_count())
print(_device_name(0))
cuda
1
GeForce MX250
⾃编码⽹络数据准备
# 使⽤⼿写体数据,准备训练数据集
train_data = MNIST(
root ='./data/MNIST',
train =True,# 只使⽤训练数据集
transform = transforms.ToTensor(),
download =False
)
# 将图像数据转为向量数据
train_data_x = train_pe(torch.FloatTensor)/255.0 train_data_x = train_shape(train_data_x.shape[0],-1) train_data_y = train_data.targets
# 定义⼀个数据加载器
train_loader = Data.DataLoader(
dataset = train_data_x,
batch_size =64,
shuffle =True,
num_workers =2# Windows需要设置为0
)
# 对测试数据集导⼊
test_data = MNIST(
root ='./data/MNIST',
train =False,# 不使⽤训练数据集
transform = transforms.ToTensor(),
download =False
)
# 为测试数据添加⼀个通道维度,获取测试数据的X和Y
test_data_x = test_pe(torch.FloatTensor)/255.0
test_data_x = test_shape(test_data_x.shape[0],-1)
test_data_y = test_data.targets
print('训练数据集:', train_data_x.shape)
print('测试数据集:', test_data_x.shape)
训练数据集: torch.Size([60000, 784])
测试数据集: torch.Size([10000, 784])
此处并没有包含对应的类别标签,是因为上述⾃编码⽹络训练时不需要图像的类别标签数据。可视化训练数据集中⼀个 batch 的图像内容,以观察⼿写体图像的情况
# 可视化训练数据集中⼀个batch的图像内容,以观察⼿写体图像的情况,程序如下:
for step, b_x in enumerate(train_loader):
if step >0:
break
# 可视化⼀个batch
# make_grid将[batch, channel, height, width]形式的batch图像转为图像矩阵,便于对多张图像的可视化im = make_grid(shape((-1,1,28,28)))
im = im.data.numpy().transpose((1,2,0))
plt.figure()
plt.imshow(im)
plt.axis('off')
plt.show()
⾃编码⽹络的构建
class EnDecoder(nn.Module):
def__init__(self):
super(EnDecoder, self).__init__()
# 定义Encoder
self.Encoder = nn.Sequential(
nn.Linear(784,512),
nn.Tanh(),
nn.Linear(512,256),
nn.Tanh(),
nn.Linear(256,128),
nn.Tanh(),
nn.Linear(128,3),
nn.Tanh(),
)
# 定义Decoder
self.Decoder = nn.Sequential(
nn.Linear(3,128),
nn.Tanh(),
nn.Linear(128,256),
nn.Tanh(),
nn.Linear(256,512),
nn.Tanh(),
nn.Linear(512,784),
nn.Sigmoid(),
)
def forward(self, x):
encoder = self.Encoder(x)
decoder = self.Decoder(encoder) return encoder, decoder
# 定义⾃编码⽹络edmodel
myedmodel = EnDecoder().to(device)
from torchsummary import summary summary(myedmodel, input_size=(1,784))
----------------------------------------------------------------
Layer (type) Output Shape Param #
================================================================
Linear-1 [-1, 1, 512] 401,920
Tanh-2 [-1, 1, 512] 0
Linear-3 [-1, 1, 256] 131,328
Tanh-4 [-1, 1, 256] 0
Linear-5 [-1, 1, 128] 32,896
Tanh-6 [-1, 1, 128] 0
Linear-7 [-1, 1, 3] 387
Tanh-8 [-1, 1, 3] 0
Linear-9 [-1, 1, 128] 512
Tanh-10 [-1, 1, 128] 0
Linear-11 [-1, 1, 256] 33,024
Tanh-12 [-1, 1, 256] 0
Linear-13 [-1, 1, 512] 131,584
Tanh-14 [-1, 1, 512] 0
Linear-15 [-1, 1, 784] 402,192
Sigmoid-16 [-1, 1, 784] 0
================================================================
Total params: 1,133,843
Trainable params: 1,133,843
Non-trainable params: 0
-
---------------------------------------------------------------
Input size (MB): 0.00
Forward/backward pass size (MB): 0.04
Params size (MB): 4.33
Estimated Total Size (MB): 4.37
----------------------------------------------------------------
# 输出⽹络结构
from torchviz import make_dot
x = torch.randn(1,1,784).requires_grad_(True)
y = (device))
myEDNet_vis = make_dot(y, params=dict(list(myedmodel.named_parameters())+[('x', x)]))
decoder
myEDNet_vis
⾃编码⽹络的训练
使⽤ Adam 优化器,和均⽅根误差损失(因为⾃编码⽹络需要重构出原始的⼿写体数据,所以看作回归问题,即与原始图像的误差越⼩越好,使⽤均⽅根误差作为损失函数较合适,也可以使⽤绝对值误差作为损失函数)
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论