CNN基础
通过shape修改liner层的输入参数
手写数字 卷积模型训练
import torch
import pandas as pd
import matplotlib.pyplot as plt
import pylab
import numpy as np
import torch.utils.data
import torchvision
from torch import nn
import torch.nn.functional as F
from sklearn.model_selection import train_test_split
from torch.utils.data import TensorDataset
from torch.utils.data import DataLoader
from torchvision import datasets, transforms # transforms 是转换数据集的方法
transformation = transforms.Compose(
[transforms.ToTensor()]
)
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
# 这一步定义使用到的转换方法。transforms.ToTensor() 转换为tensor,将数据归一化。transforms.Normalize() 做标准化。
train_ds = datasets.MNIST('dataa/', # 存放位置
train=True, # 是否为训练集
transform=transformation, # 采用的转换方法
download=True
)
test_ds = datasets.MNIST('dataa/', # 存放位置
train=False, # 是否为训练集
transform=transformation, # 采用的转换方法
download=True
)
train_dl = torch.utils.data.DataLoader(train_ds, batch_size=64, shuffle=True)
test_dl = torch.utils.data.DataLoader(test_ds, batch_size=256)
imgs, labels = next(iter(train_dl))
# imgs.shape # torch.Size([64, 1, 28, 28])
# 表示有64张[1,28,28]图片数据, 对应 通道, hight,wight,经过ToTensor后,channel是放在长宽前的
# img = imgs[0]
# img = img.numpy() # 转换成ndarray
# img = np.squeeze(img)
# plt.imshow(img)
# pylab.show()
# print(labels[:10])
def imshow(img):
npimg = img.numpy()
npimg = np.squeeze(npimg)
plt.imshow(npimg)
pylab.show()
plt.figure(figsize=(10, 1)) # 创建画布
# for i, img in enumerate(imgs[: 10]):
# plt.subplot(1, 10, i+1)
# imshow(img)
class Model(nn.Module):
# 定义一个类,从nn.Module中继承
def __init__(self): # 初始化
super().__init__() # 继承父类中所有属性
self.conv1 = nn.Conv2d(1, 6, 5)
# 输入的channels,输出的channels(使用的卷积核数),卷积核大小,是否跨像素 1表示不跨,填充的像素数
self.pool = nn.MaxPool2d((2, 2))
self.conv2 = nn.Conv2d(6, 16, 5)
self.liner_1 = nn.Linear(16*4*4, 256) # 输入为图片像素数
self.liner_2 = nn.Linear(256, 10)
def forward(self, input):
x = F.relu(self.conv1(input))
x = self.pool(x)
x = F.relu(self.conv2(x))
x = self.pool(x)
# print(x.size())
# x = x.view(x.size(0), -1)
# 把图片展平 x.size(0) = 64 就是batch,batch是不变的,只将后面的channel wight hight三个维度展平
x = x.view(-1, 16*4*4) # -1表示不改变batch
# 在forward中使用上面的层,参数为self,对input进行处理
x = F.relu(self.liner_1(x)) # 第一层调用,直接用F调用relu
x = self.liner_2(x)
return x
model = Model()
# print(model)
# Model(
# (liner_1): Linear(in_features=784, out_features=120, bias=True)
# (liner_2): Linear(in_features=120, out_features=84, bias=True)
# (liner_3): Linear(in_features=84, out_features=10, bias=True)
# )
model.to(device)
loss_fn = torch.nn.CrossEntropyLoss()
optim = torch.optim.Adam(model.parameters(), lr=0.0001)
def fit(epoch, model, trainloader, testloater):
correct = 0 # correct预测成功数
total = 0 # total训练总样本数
running_loss = 0
for x, y in trainloader:
x, y = x.to(device), y.to(device)
y_pred = model(x)
loss = loss_fn(y_pred.to(torch.float32), y.to(torch.int64))
optim.zero_grad()
loss.backward()
optim.step() # 优化
with torch.no_grad():
y_pred = torch.argmax(y_pred, dim=1) # argmax dim=1返回y_pred每一行最大数值对应的列号
correct += (y_pred == y).sum().item() # 累加正确样本个数
total += y.size(0) # 总样本数
running_loss += loss.item() # 表示每一个batch的loss
epoch_acc = correct / total
epoch_loss = running_loss / len(trainloader.dataset) # 平均loss trainloader.dataset 返回对应的ds
test_correct = 0 # correct预测成功数
test_total = 0 # total训练总样本数
test_running_loss = 0
with torch.no_grad():
for x, y in testloater:
x, y = x.to(device), y.to(device)
y_pred = model(x)
loss = loss_fn(y_pred.to(torch.float32), y.to(torch.int64))
y_pred = torch.argmax(y_pred, dim=1) # argmax dim=1返回y_pred每一行最大数值对应的列号
test_correct += (y_pred == y).sum().item() # 累加正确样本个数
test_total += y.size(0) # 总样本数
test_running_loss += loss.item() # 表示每一个batch的loss
epoch_test_loss = test_running_loss / len(testloater.dataset)
epoch_test_acc = test_correct / test_total
print('epoch', epoch,
'loss: ', round(epoch_loss, 3),
'accuracy:', round(epoch_acc, 3),
'test_loss: ', round(epoch_test_loss, 3),
'test_accuracy:', round(epoch_test_acc, 3)
)
return epoch_loss, epoch_acc, epoch_test_loss, epoch_test_acc
train_loss = []
train_acc = []
test_loss = []
test_acc = []
epochs = 20
for epoch in range(epochs):
epoch_loss, epoch_acc, epoch_test_loss, epoch_test_acc = fit(epoch, model, train_dl, test_dl)
train_loss.append(epoch_loss)
train_acc.append(epoch_acc)
test_loss.append(epoch_test_loss)
test_acc.append(epoch_test_acc)