自动编码器(pytorch)


参考《深度学习入门之Pytorch》

介绍

在这里插入图片描述
自动编码器最开始是作为一种数据压缩方法,同时还可以在卷积网络中进行逐层预训练,但是随后更多结构复杂的网络,比如 resnet 的出现使得我们能够训练任意深度的网络,自动编码器就不再使用在这个方面,下面我们讲一讲自动编码器的一个新的应用,这是随着生成对抗模型而出现的,就是使用自动编码器生成数据。
由上面的图片,我们能够看到,第一部分是编码器(encoder),第二部分是解码器(decoder),编码器和解码器都可以是任意的模型,通常我们可以使用神经网络作为我们的编码器和解码器,输入的数据经过神经网络降维到一个编码,然后又通过另外一个神经网络解码得到一个与原始数据一模一样的生成数据,通过比较原始数据和生成数据,希望他们尽可能接近,所以最小化他们之间的差异来训练网络中编码器和解码器的参数。
当训练完成之后,我们如何生成数据呢?非常简单,我们只需要拿出解码器的部分,然后随机传入 code,就可以通过解码器生成各种各样的数据。

代码

import os
import torch
from torch.autograd import Variable
from torch import nn
from torch.utils.data import DataLoader

from torchvision.datasets import MNIST
from torchvision import transforms as tfs
from torchvision.utils import save_image

#数据预处理方法
im_tfs = tfs.Compose([
    tfs.ToTensor(),
    tfs.Normalize([0.5], [0.5]) # 标准化
])

train_set = MNIST('./mnist', transform=im_tfs)
train_data = DataLoader(train_set, batch_size=128, shuffle=True)

# 定义网络
class autoencoder(nn.Module):
    def __init__(self):
        super(autoencoder, self).__init__()
        #编码器
        self.encoder = nn.Sequential(
            nn.Linear(28*28, 128),
            nn.ReLU(True),
            nn.Linear(128, 64),
            nn.ReLU(True),
            nn.Linear(64, 12),
            nn.ReLU(True),
            nn.Linear(12, 3) # 输出的 code 是 3 维,便于可视化
        )
        #解码器
        self.decoder = nn.Sequential(
            nn.Linear(3, 12),
            nn.ReLU(True),
            nn.Linear(12, 64),
            nn.ReLU(True),
            nn.Linear(64, 128),
            nn.ReLU(True),
            nn.Linear(128, 28*28),
            nn.Tanh()  #使输出范围在-1~1
        )

    def forward(self, x):
        encode = self.encoder(x)
        decode = self.decoder(encode)
        return encode, decode
        
net = autoencoder()

criterion = nn.MSELoss(size_average=False)
optimizer = torch.optim.Adam(net.parameters(), lr=1e-3)

def to_img(x):
    '''
    定义一个函数将最后的结果转换回图片
    '''
    x = 0.5 * (x + 1.)
    x = x.clamp(0, 1)
    x = x.view(x.shape[0], 1, 28, 28)
    return x
    
# 开始训练自动编码器
for e in range(100):
    for im, _ in train_data:
        im = im.view(im.shape[0], -1)
        im = Variable(im)
        # 前向传播
        _, output = net(im)
        loss = criterion(output, im) / im.shape[0] # 平均
        # 反向传播
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
    
    if (e+1) % 20 == 0: # 每 20 次,将生成的图片保存一下
        print('epoch: {}, Loss: {:.4f}'.format(e + 1, loss.data))
        pic = to_img(output.cpu().data)
        if not os.path.exists('./simple_autoencoder'):
            os.mkdir('./simple_autoencoder')
        save_image(pic, './simple_autoencoder/image_{}.png'.format(e + 1))

在这里插入图片描述

import matplotlib.pyplot as plt
from matplotlib import cm
from mpl_toolkits.mplot3d import Axes3D
%matplotlib inline

# 可视化结果
view_data = Variable((train_set.train_data[:200].type(torch.FloatTensor).view(-1, 28*28) / 255. - 0.5) / 0.5)
encode, _ = net(view_data)    # 提取压缩的特征值
fig = plt.figure(2)
ax = Axes3D(fig)    # 3D 图
# x, y, z 的数据值
X = encode.data[:, 0].numpy()
Y = encode.data[:, 1].numpy()
Z = encode.data[:, 2].numpy()
values = train_set.train_labels[:200].numpy()  # 标签值
for x, y, z, s in zip(X, Y, Z, values):
    c = cm.rainbow(int(255*s/9))    # 上色
    ax.text(x, y, z, s, backgroundcolor=c)  # 标位子
ax.set_xlim(X.min(), X.max())
ax.set_ylim(Y.min(), Y.max())
ax.set_zlim(Z.min(), Z.max())
plt.show()

在这里插入图片描述
可以看到,不同种类的图片进入自动编码器之后会被编码得不同,而相同类型的图片经过自动编码之后的编码在几何示意图上距离较近,在训练好自动编码器之后,我们可以给一个随机的 code,通过 decoder 生成图片。

code = Variable(torch.FloatTensor([[1.19, -3.36, 2.06]])) # 给一个 code 是 (1.19, -3.36, 2.06)
decode = net.decoder(code)
decode_img = to_img(decode).squeeze()
decode_img = decode_img.data.numpy() * 255
plt.imshow(decode_img.astype('uint8'), cmap='gray') # 生成图片 3

在这里插入图片描述

卷积自动编码器

class conv_autoencoder(nn.Module):
    def __init__(self):
        super(conv_autoencoder, self).__init__()
        
        self.encoder = nn.Sequential(
            nn.Conv2d(1, 16, 3, stride=3, padding=1),  # (b, 16, 10, 10)
            nn.ReLU(True),
            nn.MaxPool2d(2, stride=2),  # (b, 16, 5, 5)
            nn.Conv2d(16, 8, 3, stride=2, padding=1),  # (b, 8, 3, 3)
            nn.ReLU(True),
            nn.MaxPool2d(2, stride=1)  # (b, 8, 2, 2)
        )
        
        self.decoder = nn.Sequential(
            nn.ConvTranspose2d(8, 16, 3, stride=2),  # (b, 16, 5, 5)
            nn.ReLU(True),
            nn.ConvTranspose2d(16, 8, 5, stride=3, padding=1),  # (b, 8, 15, 15)
            nn.ReLU(True),
            nn.ConvTranspose2d(8, 1, 2, stride=2, padding=1),  # (b, 1, 28, 28)
            nn.Tanh()
        )

    def forward(self, x):
        encode = self.encoder(x)
        decode = self.decoder(encode)
        return encode, decode

conv_net = conv_autoencoder()
if torch.cuda.is_available():
    conv_net = conv_net.cuda()
optimizer = torch.optim.Adam(conv_net.parameters(), lr=1e-3, weight_decay=1e-5)

# 开始训练自动编码器
for e in range(40):
    for im, _ in train_data:
        if torch.cuda.is_available():
            im = im.cuda()
        im = Variable(im)
        # 前向传播
        _, output = conv_net(im)
        loss = criterion(output, im) / im.shape[0] # 平均
        # 反向传播
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
    
    if (e+1) % 20 == 0: # 每 20 次,将生成的图片保存一下
        print('epoch: {}, Loss: {:.4f}'.format(e+1, loss.data))
        pic = to_img(output.cpu().data)
        if not os.path.exists('./conv_autoencoder'):
            os.mkdir('./conv_autoencoder')
        save_image(pic, './conv_autoencoder/image_{}.png'.format(e+1))
  • 4
    点赞
  • 44
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
自动编码器 (Autoencoder) 是一种无监督学习算法,可以用于降维。在 PyTorch 中实现一个自动编码器进行降维可以分为以下几个步骤: 1. 导入必要的库和模块: ```python import torch import torch.nn as nn import torch.optim as optim ``` 2. 定义自动编码器的网络结构: ```python class Autoencoder(nn.Module): def __init__(self, input_dim, encoding_dim): super(Autoencoder, self).__init__() self.encoder = nn.Sequential( nn.Linear(input_dim, encoding_dim), nn.ReLU() ) self.decoder = nn.Sequential( nn.Linear(encoding_dim, input_dim), nn.Sigmoid() ) def forward(self, x): encoded = self.encoder(x) decoded = self.decoder(encoded) return decoded ``` 在这个例子中,我们使用了一个简单的全连接神经网络作为编码器和解码器,中间的隐藏层 `encoding_dim` 就起到了降维的作用。 3. 准备数据并定义损失函数和优化器: ```python # 假设你已经有了训练数据 X_train # 初始化自动编码器 input_dim = X_train.shape[1] encoding_dim = 10 # 降维后的维度 autoencoder = Autoencoder(input_dim, encoding_dim) # 定义损失函数和优化器 criterion = nn.MSELoss() optimizer = optim.Adam(autoencoder.parameters(), lr=0.001) ``` 4. 训练自动编码器: ```python num_epochs = 100 batch_size = 32 for epoch in range(num_epochs): # 随机打乱训练数据 permutation = torch.randperm(X_train.size()[0]) for i in range(0, X_train.size()[0], batch_size): indices = permutation[i:i+batch_size] batch_x = X_train[indices] # 前向传播和计算损失 output = autoencoder(batch_x) loss = criterion(output, batch_x) # 反向传播和优化 optimizer.zero_grad() loss.backward() optimizer.step() # 每个 epoch 打印一次损失 print('Epoch [{}/{}], Loss: {:.4f}'.format(epoch+1, num_epochs, loss.item())) ``` 5. 使用训练好的自动编码器进行降维: ```python # 假设你有测试数据 X_test encoded_data = autoencoder.encoder(X_test) ``` 通过以上步骤,你可以使用 PyTorch 实现一个简单的自动编码器来进行降维。请注意,这只是一个基本示例,实际应用中可能需要根据具体问题进行调整和修改。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值