上一次CNN的作业,供大家参考
```python
'''
-*- coding: utf-8 -*-
@Time : 2021/7/26 11:47
@Author : Small_Volcano
@File : fashion_mnist-cnn.py.py
'''
import copy
import time
import torch
import torch.nn as nn
import torch.utils.data as Data
from torch.optim import Adam
from torchvision import transforms
from torchvision.datasets import FashionMNIST
from sklearn.metrics import accuracy_score
import pandas as pd
import matplotlib.pyplot as plt
#使用FashionMNIST数据,准备训练数据集
train_data = FashionMNIST(root="../resourses/datasets/",
train=True,
transform=transforms.ToTensor(), #转换为tensor类型
download=False)
#对测试集进行处理
test_data = FashionMNIST(root="../resourses/datasets/",
train=False,
download=False)
#定义一个数据加载器
train_loader = Data.DataLoader(dataset=train_data,
batch_size=64, #每小批量64
shuffle=False, #是否打乱
num_workers=0) #是否多进程
#为数据添加一个通道维度,并且取值范围缩放到0-1之间 为测试准备
test_data_x = test_data.data.type(torch.FloatTensor) / 255.0
test_data_x = torch.unsqueeze(test_data_x,dim=1)
test_data_y = test_data.targets #测试集的标签
#搭建卷积神经网络
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
#定义第一个卷积层
self.conv1 = nn.Sequential(
nn.Conv2d(in_channels=1, #2d代表二维的 输入层数为1
out_channels=16, #输出高度16 16个卷积核
kernel_size=3, #卷积核尺寸3*3
stride=1, #步长为1
padding=1), #卷积后:(1*28*28)->(16*28*28)
nn.ReLU(),
nn.MaxPool2d(kernel_size=2,stride=2) #池化后:(16*28*28)->(16*14*14)
)
#定义第二个卷积层
self.conv2 = nn.Sequential(
nn.Conv2d(in_channels=16,out_channels=32,kernel_size=3,stride=1,padding=0),#卷积后:(16*14*14)->(32*12*12)
nn.ReLU(),
nn.MaxPool2d(kernel_size=2,stride=2) #池化后:(32*12*12)->(32*6*6)
)
#定义全连接层
self.classifier = nn.Sequential(
nn.Linear(32*6*6,256), #长方体变平面
nn.ReLU(),
nn.Linear(256,128),
nn.ReLU(),
nn.Linear(128,10) #分为10类
)
#定义网络的前向传播路径
def forward(self,x):
x = self.conv1(x)
x = self.conv2(x)
x = x.view(x.size(0),-1) #展平多维的卷积图层
output = self.classifier(x)
return output
#输出网络结构
net = Net() #创建实例
print(net)
#定义网络的训练过程函数
def train_model(model,traindataloader,train_rate,criterion,optimizer,num_epochs=25):
#train_rate:训练集中训练数量的百分比
#计算训练使用的batch数量
batch_num = len(traindataloader)
train_batch_num = round(batch_num * train_rate) #前train_rate(80%)的batch进行训练
#复制最好模型的参数
best_model_wts = copy.deepcopy(model.state_dict())
best_acc = 0.0
train_loss_all = []
train_acc_all = []
val_loss_all = []
val_acc_all = []
since = time.time()
for epoch in range(num_epochs):
print('Epoch {}/{}'.format(epoch,num_epochs-1)) #格式化字符串
print('-' * 10)
#每个epoch有两个训练阶段
train_loss = 0.0
train_corrects = 0
train_num = 0
val_loss = 0.0
val_corrects = 0
val_num = 0
for step,(b_x,b_y) in enumerate(traindataloader): #取标签和样本
if step < train_batch_num: #前train_rate(80%)的batch进行训练
model.train() #设置模型为训练模式,对Droopou有用
output = model(b_x) #取得模型预测结果
pre_lab = torch.argmax(output,1) #横向获得最大值位置
loss = criterion(output,b_y) #loss是一个batch的loss,每个样本的loss均值?
optimizer.zero_grad() #梯度清零
loss.backward() #计算梯度 对loss的反向传播
optimizer.step() #修改权值
train_loss += loss.item() * b_x.size(0) #此处的b_x.size(0)=batch_size。此处相当于一个batch的loss?计算的是整体训练的loss
train_corrects += torch.sum(pre_lab == b_y.data) #训练正确个数
train_num += b_x.size(0)
else:
model.eval() #设置模型为验证模式
output = model(b_x)
pre_lab = torch.argmax(output,1)
loss = criterion(output,b_y)
val_loss += loss.item() * b_x.size(0)
val_corrects += torch.sum(pre_lab == b_y.data)
val_num += b_x.size(0)
#计算训练集和验证集上的损失和精度
train_loss_all.append(train_loss / train_num) #一个epoch上的loss
train_acc_all.append(train_corrects.double().item() / train_num)
val_loss_all.append(val_loss / val_num)
val_acc_all.append(val_corrects.double().item() / val_num)
print('{} Train Loss: {:.4f} Train Acc: {:.4f}'.format(epoch,train_loss_all[-1],train_acc_all[-1])) #此处-1没搞明白
print('{} Val Loss: {:.4f} Val Acc: {:.4f}'.format(epoch,val_loss_all[-1],val_acc_all[-1]))
#拷贝模型最高精度下的参数
if val_acc_all[-1] > best_acc:
best_acc = val_acc_all[-1]
best_model_wts = copy.deepcopy(model.state_dict())
time_use = time.time() - since
print("Train and val complete in {:.0f}m {:.0f}s".format(time_use // 60,time_use % 60)) #训练用时
#使用最好模型的参数
model.load_state_dict(best_model_wts)
#组成数据表格train_process打印
train_process = pd.DataFrame(data={"epoch":range(num_epochs),
"train_loss_all":train_loss_all,
"val_loss_all":val_loss_all,
"train_acc_all":train_acc_all,
"val_acc_all":val_acc_all})
return model,train_process
#对模型进行训练
optimizer = Adam(net.parameters(),lr=0.0003) #优化器
criterion = nn.CrossEntropyLoss() #使用交叉熵作为损失函数
net,train_process = train_model(net,train_loader,0.8, #使用训练集的20%作为验证
criterion,optimizer,num_epochs=25)
#可视化模型训练过程中
plt.figure(figsize=(12,4))
plt.subplot(1,2,1)
plt.plot(train_process.epoch,train_process.train_loss_all,"ro-",label="Train loss")
plt.plot(train_process.epoch,train_process.val_loss_all,"bs-",label="Val loss")
plt.legend()
plt.xlabel("epoch")
plt.ylabel("Loss")
plt.subplot(1,2,2)
plt.plot(train_process.epoch,train_process.train_acc_all,"ro-",label="Train acc")
plt.plot(train_process.epoch,train_process.val_acc_all,"bs-",label="Val acc")
plt.xlabel("epoch")
plt.ylabel("acc")
plt.legend()
plt.show()
#对测试集进行预测,并可视化预测结果。计算模型的泛化能力
net.eval()
output = net(test_data_x)
pre_lab = torch.argmax(output,1)
acc = accuracy_score(test_data_y,pre_lab)
print("在测试集上的预测精度为:",acc)
'''Net(
(conv1): Sequential(
(0): Conv2d(1, 16, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(1): ReLU()
(2): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
)
(conv2): Sequential(
(0): Conv2d(16, 32, kernel_size=(3, 3), stride=(1, 1))
(1): ReLU()
(2): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
)
(classifier): Sequential(
(0): Linear(in_features=1152, out_features=256, bias=True)
(1): ReLU()
(2): Linear(in_features=256, out_features=128, bias=True)
(3): ReLU()
(4): Linear(in_features=128, out_features=10, bias=True)
)
)
Epoch 0/24
----------
0 Train Loss: 0.7203 Train Acc: 0.7342
0 Val Loss: 0.4867 Val Acc: 0.8244
Train and val complete in 0m 45s
Epoch 1/24
----------
1 Train Loss: 0.4360 Train Acc: 0.8426
1 Val Loss: 0.3962 Val Acc: 0.8585
Train and val complete in 1m 34s
Epoch 2/24
----------
2 Train Loss: 0.3676 Train Acc: 0.8693
2 Val Loss: 0.3573 Val Acc: 0.8717
Train and val complete in 2m 26s
Epoch 3/24
----------
3 Train Loss: 0.3308 Train Acc: 0.8815
3 Val Loss: 0.3362 Val Acc: 0.8798
Train and val complete in 3m 9s
Epoch 4/24
----------
4 Train Loss: 0.3049 Train Acc: 0.8899
4 Val Loss: 0.3226 Val Acc: 0.8844
Train and val complete in 3m 56s
Epoch 5/24
----------
5 Train Loss: 0.2848 Train Acc: 0.8968
5 Val Loss: 0.3138 Val Acc: 0.8865
Train and val complete in 4m 39s
Epoch 6/24
----------
6 Train Loss: 0.2679 Train Acc: 0.9030
6 Val Loss: 0.3027 Val Acc: 0.8920
Train and val complete in 5m 20s
Epoch 7/24
----------
7 Train Loss: 0.2535 Train Acc: 0.9085
7 Val Loss: 0.2963 Val Acc: 0.8955
Train and val complete in 6m 6s
Epoch 8/24
----------
8 Train Loss: 0.2404 Train Acc: 0.9134
8 Val Loss: 0.2873 Val Acc: 0.8986
Train and val complete in 6m 47s
Epoch 9/24
----------
9 Train Loss: 0.2285 Train Acc: 0.9176
9 Val Loss: 0.2781 Val Acc: 0.9025
Train and val complete in 7m 33s
Epoch 10/24
----------
10 Train Loss: 0.2172 Train Acc: 0.9222
10 Val Loss: 0.2716 Val Acc: 0.9039
Train and val complete in 8m 15s
Epoch 11/24
----------
11 Train Loss: 0.2063 Train Acc: 0.9262
11 Val Loss: 0.2640 Val Acc: 0.9074
Train and val complete in 8m 55s
Epoch 12/24
----------
12 Train Loss: 0.1960 Train Acc: 0.9292
12 Val Loss: 0.2590 Val Acc: 0.9091
Train and val complete in 9m 35s
Epoch 13/24
----------
13 Train Loss: 0.1862 Train Acc: 0.9328
13 Val Loss: 0.2563 Val Acc: 0.9113
Train and val complete in 10m 15s
Epoch 14/24
----------
14 Train Loss: 0.1768 Train Acc: 0.9366
14 Val Loss: 0.2525 Val Acc: 0.9123
Train and val complete in 10m 56s
Epoch 15/24
----------
15 Train Loss: 0.1676 Train Acc: 0.9401
15 Val Loss: 0.2510 Val Acc: 0.9135
Train and val complete in 11m 36s
Epoch 16/24
----------
16 Train Loss: 0.1584 Train Acc: 0.9439
16 Val Loss: 0.2502 Val Acc: 0.9146
Train and val complete in 12m 17s
Epoch 17/24
----------
17 Train Loss: 0.1504 Train Acc: 0.9473
17 Val Loss: 0.2517 Val Acc: 0.9135
Train and val complete in 12m 58s
Epoch 18/24
----------
18 Train Loss: 0.1420 Train Acc: 0.9505
18 Val Loss: 0.2571 Val Acc: 0.9136
Train and val complete in 13m 39s
Epoch 19/24
----------
19 Train Loss: 0.1337 Train Acc: 0.9527
19 Val Loss: 0.2606 Val Acc: 0.9124
Train and val complete in 14m 20s
Epoch 20/24
----------
20 Train Loss: 0.1258 Train Acc: 0.9561
20 Val Loss: 0.2673 Val Acc: 0.9123
Train and val complete in 15m 1s
Epoch 21/24
----------
21 Train Loss: 0.1185 Train Acc: 0.9584
21 Val Loss: 0.2773 Val Acc: 0.9097
Train and val complete in 15m 43s
Epoch 22/24
----------
22 Train Loss: 0.1109 Train Acc: 0.9615
22 Val Loss: 0.2915 Val Acc: 0.9077
Train and val complete in 16m 24s
Epoch 23/24
----------
23 Train Loss: 0.1043 Train Acc: 0.9640
23 Val Loss: 0.3015 Val Acc: 0.9071
Train and val complete in 17m 5s
Epoch 24/24
----------
24 Train Loss: 0.0973 Train Acc: 0.9666
24 Val Loss: 0.3209 Val Acc: 0.9044
Train and val complete in 17m 44s
在测试集上的预测精度为: 0.9112
'''