AE.py
import torch
import torchvision.datasets as dsets
import torchvision.transforms as transforms
import torchvision
from torch.autograd import Variable
import torch.nn as nn
from time import time
from AE import *
num_epochs = 200 # 迭代完所有训练数据
batch_size = 128 #批量处理的大小,一般为8的倍数,在data_loader变量的初始化中使用到了
hidden_size = 30
'''一个iter训练batchsize张,一个epoch训练次数:总张数/batchsize'''
# MNIST dataset
#这部分是对数据的读取,该程序中使用的是minist数据,可以替换为其他数据
#dset中的totensor使得数据集能够在加载的阶段可以进行映射
dataset = dsets.MNIST(root='../MINIST/MNIST',
train=True,
transform=transforms.ToTensor(),
download=True)
# Data loader
# 加载数据,dataset 是传入的数据集,要求是映射类型的或者可迭代类型的数据集,batchsize 是非空的,
# shuffle set to True to have the data reshuffled at every epoch
data_loader = torch.utils.data.DataLoader(dataset=dataset,
batch_size=batch_size,
shuffle=True)
def to_var(x):
# 判断cuda是不是可以使用
if torch.cuda.is_available():
x = x.cuda()
return Variable(x)
#父类是nn.Module,因为它是所有的网络基类
class Autoencoder(nn.Module):
# def __init__(self, in_dim=784, h_dim=400):
# in_dim是每个输入样本的大小
# h_dim是每个输出样本的大小
def __init__(self, in_dim, h_dim):
super(Autoencoder, self).__init__()
# 编码器,Sequential是一个时序容器
self.encoder = nn.Sequential(
nn.Linear(in_dim, h_dim), # 做线性变换 y = ax + b
nn.ReLU() # 激活函数 max(0, x)
)
# 解码器
self.decoder = nn.Sequential(
nn.Linear(h_dim, in_dim),
nn.Sigmoid() # 激活函数,S型曲线
)
def forward(self, x):
"""
Note: image dimension conversion will be handled by external methods
"""
out = self.encoder(x)
out = self.decoder(out)
return out
# 对自编码类实例化
ae = Autoencoder(in_dim=784, h_dim=hidden_size)
if torch.cuda.is_available():
ae.cuda()
criterion = nn.BCELoss() # 计算输入和目标之间的二进制交叉熵,个人认为也是一个实例化
optimizer = torch.optim.Adam(ae.parameters(), lr=0.001) # 优化方法,lr是步长
iter_per_epoch = len(data_loader) # 数据集中数据的个数
data_iter = iter(data_loader) # 完全训练一次
# save fixed inputs for debugging
fixed_x, _ = next(data_iter)
# 第一个参数是tensor,第二个参数是一个文件或者文件名,目的是将一个张量存储在一张图里
torchvision.utils.save_image(Variable(fixed_x).data.cpu(), './data/real_images.png')
# 函数,将输入放到一个容器里面
fixed_x = to_var(fixed_x.view(fixed_x.size(0), -1))
for epoch in range(num_epochs):
t0 = time() # 返回当前时间戳
for i, (images, _) in enumerate(data_loader):
# flatten the image 使图片单调
images = to_var(images.view(images.size(0), -1))
out = ae(images) # 通过自编码训练
loss = criterion(out, images) # 计算训练结果和原图的损失
# 这三行的主要目的是训练loss,直到loss稳定,而这一点是通过训练梯度做到的,这三行做的事情就是训练梯度
optimizer.zero_grad() # 设置每一个被优化的张量的梯度为0
loss.backward() # 计算损失函数的梯度
optimizer.step() # 重新给梯度
if (i+1) % 100 == 0:
print ('Epoch [%d/%d], Iter [%d/%d] Loss: %.4f Time: %.2fs'
%(epoch+1, num_epochs, i+1, len(dataset)//batch_size, loss.data, time()-t0))
# save the reconstructed images
reconst_images = ae(fixed_x)
reconst_images = reconst_images.view(reconst_images.size(0), 1, 28, 28)
torchvision.utils.save_image(reconst_images.data.cpu(), './data/reconst_images_%d.png' % (epoch+1))
在实际实验中我对数据集进行了替换,这个过程比较痛苦,但是代码搞丢了,主要是替换数据集那部分,同时因为输入的数据是彩色图片,通道数要改,然而我并没有研究全连接处理彩色图片的方法,就不了了之了。
这个代码来自于github,我只是添加注释,仅作学习使用。链接如下:
https://github.com/wanglouis49/pytorch-autoencoders