pytorch利用变分自编码器进行MNIST实战

自编码器是一种无监督学习

它的作用:
1、降维
2、预处理
3、可视化
4、利用无监督的数据
5、压缩(有损)、降噪、超分辨率

原理

一句话概括,自己训练自己。

怎么训练

在这里插入图片描述

PCA和Auto-Encoders的区别

PCA的线性变换对特征维度的类型有限制,AE可以是非线性变换。

降噪AE

在这里插入图片描述

KL散度

KL计算公式:
在这里插入图片描述
通过这样的技巧,在反向传播中就可以顺利通过了。
在这里插入图片描述
在这里插入图片描述
可以理解为这样:
在这里插入图片描述
main.py代码为:

import torch
from torch.utils.data import DataLoader
from torch import nn, optim
from torchvision import transforms, datasets
# from ae import AE
from vae import VAE
import visdom


def main():
    mnist_train = datasets.MNIST('mnist', True, transform=transforms.Compose([
        transforms.ToTensor()
    ]), download=True)
    mnist_train = DataLoader(mnist_train, batch_size=256, shuffle=True)

    mnist_test = datasets.MNIST('mnist', False, transform=transforms.Compose([
        transforms.ToTensor()
    ]), download=True)
    mnist_test = DataLoader(mnist_test, batch_size=256, shuffle=True)

    x, _ = iter(mnist_train).next()
    print("x:", x.shape)

    device = torch.device('cuda')
    # model = AE().cuda()
    model = VAE().cuda()
    criteon = nn.MSELoss()
    optimizer = optim.Adam(model.parameters(), lr=1e-3)
    print(model)

    viz = visdom.Visdom()

    for epoch in range(1000):
        for batchidx, (x, _) in enumerate(mnist_train):
            # [b, 1, 28, 28]
            x = x.cuda()

            x_hat, kld = model(x)
            loss = criteon(x_hat, x)

            if kld is not None:
                elbo = -loss - 1.0 * kld
                loss = - elbo

            # backprop
            optimizer.zero_grad()  # 梯度清零
            loss.backward()
            optimizer.step()  # 更新梯度

        print(epoch, 'loss:', loss.item(), 'kld', kld.item())

        x, _ = iter(mnist_test).next()
        x = x.cuda()
        with torch.no_grad():
            x_hat, kld = model(x)
        viz.images(x, nrow=8, win='x', opts=dict(title='x'))
        viz.images(x_hat, nrow=8, win='x_hat', opts=dict(title='x_hat'))


if __name__ == '__main__':
    main()

vae.py代码为:

import torch
from torch import nn


class VAE(nn.Module):
    """

    """

    def __init__(self):
        """

        """
        super(VAE, self).__init__()

        # [b, 784] => [b, 20]
        # u均值: [b, 10]
        # sigma标准差: [b, 10]
        self.encoder = nn.Sequential(
            nn.Linear(784, 256),
            nn.ReLU(),
            nn.Linear(256, 64),
            nn.ReLU(),
            nn.Linear(64, 20),
            nn.ReLU()
        )

        # [b, 10] => [b, 784]
        self.decoder = nn.Sequential(
            nn.Linear(10, 64),
            nn.ReLU(),
            nn.Linear(64, 256),
            nn.ReLU(),
            nn.Linear(256, 784),
            nn.Sigmoid()  # 压缩像素为0到1
        )

    def forward(self, x):
        """

        :param x: [b, 1, 28, 28]
        :return:
        """
        batchsz = x.shape[0]
        # flatten
        x = x.view(batchsz, 784)
        # encoder
        # [b, 784] => [b, 20],包括均值和方差
        h_ = self.encoder(x)
        # [b, 20] => [b, 10] 和 [b, 10]
        mu, sigma = h_.chunk(2, dim=1)
        # 重新参数化技巧,epison ~ N(0,1),变为可导的操作
        h = mu + sigma * torch.randn_like(sigma)
        # torch.pow():幂次运算
        kld = 0.5 * torch.sum(
            torch.pow(mu, 2) +
            torch.pow(sigma, 2) -
            torch.log(1e-8 + torch.pow(sigma, 2)) - 1
        ) / (batchsz * 28 * 28)

        # decoder
        # [b, 10] => [b, 784]
        x_hat = self.decoder(h)
        # reshape, [b, 784] => [b, 1, 28, 28]
        x_hat = x_hat.view(batchsz, 1, 28, 28)

        return x_hat, kld


def main():
    x = torch.randn(256, 1, 28, 28)
    model = VAE()
    out1, out2 = model(x)
    print('x_hat:', out1.shape)
    print('kld:', out2)

    # 查看模型结构
    print(model)


if __name__ == '__main__':
    main()

ae.py代码为:

import torch
from torch import nn


class AE(nn.Module):
    """

    """

    def __init__(self):
        """

        """
        super(AE, self).__init__()

        # [b, 784] => [b, 20]
        self.encoder = nn.Sequential(
            nn.Linear(784, 256),
            nn.ReLU(),
            nn.Linear(256, 64),
            nn.ReLU(),
            nn.Linear(64, 20),
            nn.ReLU()
        )

        # [b, 20] => [b, 784]
        self.decoder = nn.Sequential(
            nn.Linear(20, 64),
            nn.ReLU(),
            nn.Linear(64, 256),
            nn.ReLU(),
            nn.Linear(256, 784),
            nn.Sigmoid()  # 压缩像素为0到1
        )

    def forward(self, x):
        """

        :param x: [b, 1, 28, 28]
        :return:
        """
        batchsz = x.shape[0]
        # flatten,打平数据,[b, 1, 28, 28] => [b, 784]
        x = x.view(batchsz, 784)
        # encoder
        x = self.encoder(x)
        # decoder
        x = self.decoder(x)
        # reshape, [b, 784] => [b, 1, 28, 28]
        x = x.view(batchsz, 1, 28, 28)

        return x


def main():
    x = torch.randn(256, 1, 28, 28)
    model = AE()
    out = model(x)
    print('x:', out.shape)

    # 查看模型结构
    print(model)


if __name__ == '__main__':
    main()

运行时打开visdom可视化界面,代码为:

python -m visdom.server

在网页中输入:

localhost:8097

在这里插入图片描述
虽然有点模糊,是因为训练次数比较少,次数多后,后面会原来越来越清晰。

有用请点个赞!!
本站所有文章均为原创,欢迎转载,请注明文章出处:https://blog.csdn.net/weixin_45092662。百度和各类采集站皆不可信,搜索请谨慎鉴别。技术类文章一般都有时效性,本人习惯不定期对自己的博文进行修正和更新,因此请访问出处以查看本文的最新版本。

  • 2
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是使用PyTorch实现变分自动编码器的步骤: 1.导入所需的库和模块,包括torch、torch.nn、torch.nn.functional、torchvision等。 2.定义设备配置,判断是否有可用的GPU,如果有则使用GPU,否则使用CPU。 3.定义变分自动编码器的编码器和解码器。编码器由两个全连接层和一个输出层组成,解码器由一个全连接层和一个输出层组成。 4.定义变分自动编码器的前向传播函数forward(),其中包括编码器和解码器的前向传播过程。 5.定义变分自动编码器的损失函数,包括重构误差和KL散度。 6.定义优化器,使用Adam优化器。 7.训练模型,包括前向传播、计算损失、反向传播和优化器更新参数。 8.保存模型和生成样本图片。 下面是完整的代码实现: ```python import os import torch import torch.nn as nn import torch.nn.functional as F import torchvision from torchvision import transforms from torchvision.utils import save_image import matplotlib.pyplot as plt # 设备配置 device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') # 定义变分自动编码器的编码器和解码器 class VAE(nn.Module): def __init__(self): super(VAE, self).__init__() self.fc1 = nn.Linear(784, 400) self.fc21 = nn.Linear(400, 20) self.fc22 = nn.Linear(400, 20) self.fc3 = nn.Linear(20, 400) self.fc4 = nn.Linear(400, 784) def encode(self, x): h1 = F.relu(self.fc1(x)) return self.fc21(h1), self.fc22(h1) def reparameterize(self, mu, logvar): std = torch.exp(0.5*logvar) eps = torch.randn_like(std) return mu + eps*std def decode(self, z): h3 = F.relu(self.fc3(z)) return torch.sigmoid(self.fc4(h3)) def forward(self, x): mu, logvar = self.encode(x.view(-1, 784)) z = self.reparameterize(mu, logvar) return self.decode(z), mu, logvar # 定义变分自动编码器的损失函数 def loss_function(recon_x, x, mu, logvar): BCE = F.binary_cross_entropy(recon_x, x.view(-1, 784), reduction='sum') KLD = -0.5 * torch.sum(1 + logvar - mu.pow(2) - logvar.exp()) return BCE + KLD # 定义优化器 vae = VAE().to(device) optimizer = torch.optim.Adam(vae.parameters(), lr=1e-3) # 训练模型 def train(epoch): vae.train() train_loss = 0 for batch_idx, (data, _) in enumerate(train_loader): data = data.to(device) optimizer.zero_grad() recon_batch, mu, logvar = vae(data) loss = loss_function(recon_batch, data, mu, logvar) loss.backward() train_loss += loss.item() optimizer.step() if batch_idx % 100 == 0: print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format( epoch, batch_idx * len(data), len(train_loader.dataset), 100. * batch_idx / len(train_loader), loss.item() / len(data))) print('====> Epoch: {} Average loss: {:.4f}'.format( epoch, train_loss / len(train_loader.dataset))) # 保存模型和生成样本图片 if not os.path.exists('./vae_samples'): os.mkdir('./vae_samples') def save_samples(epoch): with torch.no_grad(): sample = torch.randn(64, 20).to(device) sample = vae.decode(sample).cpu() save_image(sample.view(64, 1, 28, 28), './vae_samples/sample_' + str(epoch) + '.png') # 加载MNIST数据集 batch_size = 128 transform = transforms.Compose([ transforms.ToTensor(), transforms.Normalize((0.1307,), (0.3081,)) ]) train_dataset = torchvision.datasets.MNIST(root='./data', train=True, transform=transform, download=True) train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=batch_size, shuffle=True) # 训练模型并保存样本图片 for epoch in range(1, 21): train(epoch) save_samples(epoch) ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值