PyTorch学习笔记:AutoEncoder自编码模型(基于Linear)

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
from sklearn.metrics import classification_report, accuracy_score
import torch
from torch import nn
import torch.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

from AutoEncoder import AutoEncoder

if __name__ == '__main__':
    # 使用手写体数据,准备训练数据集
    # 数据集MNIST被分成两部分:60000行的训练数据集(mnist.train)和10000行的测试数据集(mnist.test)
    train_data = MNIST(
        root="./data/MNIST",  # 数据的路径
        train=True,  # 只使用训练数据集
        transform=transforms.ToTensor(),
        download=False
    )
    # 将图像数据转化为向量数据
    train_data_x = train_data.data.type(torch.FloatTensor) / 255.0
    train_data_x = train_data_x.reshape(train_data_x.shape[0], -1)
    train_data_y = train_data.targets
    # 自编码器是无监督,训练网络不需要标签数据y,只需要特征张量x,故此处不需要将x和y整合到一起作为数据集
    # train_data = Data.TensorDataset(train_data_x, train_data_y)
    # 定义一个数据加载器
    train_loader = Data.DataLoader(
        dataset=train_data_x,  # 使用的数据集※
        batch_size=64,  # 批处理样本大小
        shuffle=True,  # 每次迭代前打乱数据
        num_workers=2,  # 使用两个进程
    )
    test_data = MNIST(
        root="./data/MNIST",
        train=False,  # 使用测试集
        transform=transforms.ToTensor(),
        download=False
    )
    test_data_x = test_data.data.type(torch.FloatTensor) / 255.0
    test_data_x = test_data_x.reshape(test_data_x.shape[0], -1)
    test_data_y = test_data.targets

    print("train_data", train_data_x.shape)
    print("test_data", test_data_x.shape)

    # 可视化训练数据集中一个batch的图像内容
    # for step, b_x in enumerate(train_loader):
    #     if step > 0:
    #         break
    #
    # # 网格化,将多幅图像拼在一起;数据为[batch,channel,height,width]形式
    # im = make_grid(b_x.reshape((-1, 1, 28, 28)))
    # im = im.data.numpy().transpose((1, 2, 0))
    # plt.figure()
    # plt.imshow(im)
    # plt.axis("off")
    # plt.show()

    AEmodel = AutoEncoder()
    print(AEmodel)

    # 自编码网络的训练
    # 使用Adam优化器;损失函数选择MSELoss(均方根误差损失),因为AE需重构出原始的手写体数据,所以看作回归问题,即与原始图像的误差越小越好
    # 定义优化器
    optimizer = torch.optim.Adam(AEmodel.parameters(), lr=0.003)  # 学习率
    loss_func = nn.MSELoss()
    # 记录训练过程的指标
    history1 = hl.History()
    # 使用Canvas进行可视化
    canvas1 = hl.Canvas()
    train_num = 0
    val_num = 0
    # 对模型进行迭代训练,对所有的数据训练epoch轮
    for epoch in range(10):
        train_loss_epoch = 0
        # 对训练数据的加载器进行迭代计算
        for step, b_x in enumerate(train_loader):
            # 使用每个batch进行训练模型
            _, output = AEmodel(b_x)
            # 均方根误差;b_x表示每次网络的输入数据,output表示经过自编码网络的输出内容
            loss = loss_func(output, b_x)
            #
            optimizer.zero_grad()
            loss.backward()
            optimizer.step()
            #
            train_loss_epoch += loss.item() * b_x.size(0)
            train_num = train_num + b_x.size(0)

        # 计算一个epoch的损失
        train_loss = train_loss_epoch / train_num
        print("epoch", epoch)
        print("train_loss", train_loss)
        # 保存每个epoch上的输出loss
        history1.log(epoch, train_loss=train_loss)
        # 可视化网络训练的过程
        # with canvas1:
        #     canvas1.draw_plot(history1["train_loss"])

    # 预测测试集前100张图像的输出
    # AEmodel.eval()  # 将模型设置为验证模式
    # _, test_decoder = AEmodel(test_data_x[0:100, :])
    # # 可视化原始的图像
    # plt.figure(figsize=(6, 6))
    # for ii in range(test_decoder.shape[0]):
    #     plt.subplot(10, 10, ii + 1)
    #     im = test_data_x[ii, :]
    #     im = im.data.numpy().reshape(28, 28)
    #     plt.imshow(im, cmap=plt.cm.gray)
    #     plt.axis("off")
    # plt.show()
    # # 可视化编码后的图像
    # plt.figure(figsize=(6, 6))
    # for ii in range(test_decoder.shape[0]):
    #     plt.subplot(10, 10, ii + 1)
    #     im = test_decoder[ii, :]
    #     im = im.data.numpy().reshape(28, 28)
    #     plt.imshow(im, cmap=plt.cm.gray)
    #     plt.axis("off")
    # plt.show()
    # 自编码网络得到的图像有些模糊,而且针对原始图像中的某些细节并不能很好地重构
    # 这是因为在网络中,自编码器部分最后一层只有3个神经元,将784维的数据压缩到三维,会损失大量的信息
    # 此处降到三维主要为了方便数据可视化,在实际情况中,可以使用较多的神经元,保留更丰富的信息。

    # 自编码后的特征训练集和测试集
    train_ae_x, _ = AEmodel(train_data_x)
    train_ae_x = train_ae_x.data.numpy()
    train_y = train_data_y.data.numpy()
    test_ae_x, _ = AEmodel(test_data_x)
    test_ae_x = test_ae_x.data.numpy()
    test_y = test_data_y.data.numpy()

    # PCA降维获得的训练集和测试集前3个主成分
    pcamodel = PCA(n_components=3, random_state=10)
    train_pca_x = pcamodel.fit_transform(train_data_x.data.numpy())
    test_pca_x = pcamodel.fit_transform(test_data_x.data.numpy())

    print(train_pca_x.shape)

    # 分别针对两种类型的数据使用相同的参数,建立 支持向量机 分类器
    # 先使用训练集对SVM分类器进行训练,然后利用测试集测试SVM的分类精度,并使用accuracy_score()和classification_report()函数输出分类器在测试集上的预测效果

    # 使用自编码数据建立分类器,训练和预测
    ae_svc = SVC(kernel="rbf", random_state=123)
    ae_svc.fit(train_ae_x, train_y)
    ae_svc_pre = ae_svc.predict(test_ae_x)
    print(classification_report(test_y, ae_svc_pre))
    print("AE+SVM模型精度", accuracy_score(test_y, ae_svc_pre))

    # 使用PCA降维数据建立分类器,训练和预测
    pca_svc = SVC(kernel="rbf", random_state=123)
    pca_svc.fit(train_pca_x, train_y)
    pca_svc_pre = pca_svc.predict(test_pca_x)
    print(classification_report(test_y, pca_svc_pre))
    print("PCA+SVM模型精度", accuracy_score(test_y, pca_svc_pre))

你可能感兴趣的:(深度学习,pytorch,网络,深度学习)