pt第8章 基于线性层的自编码网络
导入库
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
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
数据准备
# 使用手写体数据,准备训练数据集
train_data = MNIST(root="./data/MNIST",
train=True,
transform=transforms.ToTensor(),
download=True
)
# 将图像数据转化为向量数据
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
# 定义一个数据加载器
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=True
)
# 为测试数据添加一个通道纬度,获取测试数据的X和Y
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_x.shape)
print("测试数据集 :", test_data_x.shape)
训练数据集: torch.Size([60000, 784])
测试数据集 : torch.Size([10000, 784])
for step, b_x in enumerate(train_loader):
if step > 0:
break
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()
模型定义
自编码器
class EnDecoder(nn.Module):
def __init__(self):
super(EnDecoder, self).__init__()
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 = EnDecoder()
edmodel
EnDecoder(
(Encoder): Sequential(
(0): Linear(in_features=784, out_features=512, bias=True)
(1): Tanh()
(2): Linear(in_features=512, out_features=256, bias=True)
(3): Tanh()
(4): Linear(in_features=256, out_features=128, bias=True)
(5): Tanh()
(6): Linear(in_features=128, out_features=3, bias=True)
(7): Tanh()
)
(Decoder): Sequential(
(0): Linear(in_features=3, out_features=128, bias=True)
(1): Tanh()
(2): Linear(in_features=128, out_features=256, bias=True)
(3): Tanh()
(4): Linear(in_features=256, out_features=512, bias=True)
(5): Tanh()
(6): Linear(in_features=512, out_features=784, bias=True)
(7): Sigmoid()
)
)
训练过程
import hiddenlayer as hl
optimizer = torch.optim.Adam(edmodel.parameters(), lr=0.003)
loss_func = nn.MSELoss()
# 记录
history1 = hl.History()
# 使用 Canvas 进行可视化
canvas = hl.Canvas()
train_num = 0
val_num = 0
# 对模型进行迭代训练
for epoch in range(10):
train_loss_epoch = 0
# 对训练数据的加载器进行迭代计算
for step, b_x in enumerate(train_loader):
_,output = edmodel(b_x)
loss = loss_func(output, b_x)
optimizer.zero_grad()
loss.backward()
optimizer.step()
train_loss_epoch += loss.item() * b_x.size(0)
train_num += b_x.size(0)
# 计算一个epoch 的损失
train_loss = train_loss_epoch / train_num
# 保存每个 epoch 上的输出 loss
history1.log(epoch, train_loss=train_loss)
# 可视网络训练的过程
with canvas:
canvas.draw_plot(history1["train_loss"])
可视化一个批次的图像
edmodel.eval() # 将模型设置为评估模式
_, test_decoder_output = edmodel(test_data_x[0:100, :]) ##预测前一百章
# 可视化原始的图像
plt.figure(figsize=(6, 6))
for ii in range(test_decoder_output.shape[0]):
plt.subplot(10, 10, ii + 1)
im = test_data_x[ii, :] #使用原始图像数据
im = im.numpy().reshape(28, 28) #将图像数据转换为 numpy 数组并重塑为 28x28
plt.imshow(im)
plt.axis("off") #不显示坐标轴
plt.show()
#可视化编码后的图像
plt.figure(figsize=(6, 6))
for ii in range(test_decoder_output.shape[0]):
plt.subplot(10, 10, ii + 1)
im = test_decoder_output[ii, :] #使用编码后的图像数据
im = im.data.numpy().reshape(28, 28)
plt.imshow(im)
plt.axis("off")
plt.show()
edmodel.eval() # 将模型设置为评估模式
# 获取前500个样本的自编码后的特征
TEST_num = 500
test_encoder, _ = edmodel(test_data_x[0:TEST_num, :])
# 打印编码后的特征的形状
print("test_encoder_output.shape:", test_encoder.shape)
test_encoder_output.shape: torch.Size([500, 3])
3D可视化自编码特征
from mpl_toolkits.mplot3d import Axes3D
## 将 3 个维度的特征进行可视化
test_encoder_arr = test_encoder.data.numpy()
print(test_encoder_arr)
# 创建图形和轴对象用于3D可视化
fig = plt.figure(figsize=(12, 8))
ax1 = fig.add_axes(Axes3D(fig))
# 从编码的特征中提取每个维度的数据
X = test_encoder_arr[:, 0]
Y = test_encoder_arr[:, 1]
Z = test_encoder_arr[:, 2]
# 设置坐标轴的范围
ax1.set_xlim([min(X), max(X)])
ax1.set_ylim([min(Y), max(Y)])
ax1.set_zlim([min(Z), max(Z)])
# 在每个点的位置上添加标签文本
for ii in range(test_encoder.shape[0]):
text = test_data_y.data.numpy()[ii]
ax1.text(X[ii], Y[ii], Z[ii], str(text),
fontsize=10,
bbox=dict(boxstyle="round",
facecolor=plt.cm.Set1(text),
alpha=0.7)
)
plt.show()
[[ 0.31008023 0.49149397 -0.95673186]
[-0.9799462 -0.10318345 0.78829974]
[-0.79156405 0.91067296 -0.41046414]
...
[ 0.37451348 -0.18652499 -0.5412912 ]
[ 0.71749717 -0.57455105 0.60234135]
[ 0.7848706 -0.30445015 0.17963228]]
使用自编码特征
# 自编码后的特征训练集和测试集
train_ed_x,_ = edmodel(train_data_x)
train_ed_x = train_ed_x.data.numpy()
train_y = train_data_y.data.numpy()
test_ed_x,_ = edmodel(test_data_x)
test_ed_x = test_ed_x.data.numpy()
test_y = test_data_y.data.numpy()
使用PCA降维特征
# 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.transform(test_data_x.data.numpy())
print(train_pca_x.shape)
(60000, 3)
# 使用自编码数据建立分类器,训练和预测
encodersvc = SVC(kernel="rbf", random_state=123)
encodersvc.fit(train_ed_x, train_y)
edsvc_pred = encodersvc.predict(test_ed_x)
print(classification_report(test_y, edsvc_pred))
print("模型精度", accuracy_score(test_y, edsvc_pred))
precision recall f1-score support
0 0.93 0.97 0.95 980
1 0.98 0.98 0.98 1135
2 0.95 0.90 0.92 1032
3 0.89 0.86 0.87 1010
4 0.79 0.74 0.77 982
5 0.81 0.89 0.85 892
6 0.94 0.94 0.94 958
7 0.93 0.90 0.91 1028
8 0.84 0.83 0.83 974
9 0.70 0.76 0.73 1009
accuracy 0.88 10000
macro avg 0.88 0.88 0.88 10000
weighted avg 0.88 0.88 0.88 10000
模型精度 0.8772
# 使用 PCA 降维数据建立分类器,训练和预测
pcasvc = SVC(kernel="rbf", random_state=123)
pcasvc.fit(train_pca_x, train_y)
# 进行预测
pcasvc_pred = pcasvc.predict(test_pca_x)
# 打印分类报告和模型精度
print(classification_report(test_y, pcasvc_pred))
print("模型精度", accuracy_score(test_y, pcasvc_pred))
precision recall f1-score support
0 0.68 0.74 0.71 980
1 0.93 0.95 0.94 1135
2 0.51 0.49 0.50 1032
3 0.65 0.64 0.64 1010
4 0.41 0.55 0.47 982
5 0.42 0.31 0.36 892
6 0.38 0.60 0.47 958
7 0.52 0.51 0.52 1028
8 0.41 0.26 0.32 974
9 0.44 0.30 0.36 1009
accuracy 0.54 10000
macro avg 0.54 0.54 0.53 10000
weighted avg 0.54 0.54 0.54 10000
模型精度 0.5427