>- **🍨 本文为[🔗365天深度学习训练营](https://mp.weixin.qq.com/s/AtyZUu_j2k_ScNH6e732ow) 中的学习记录博客**
>- **🍦 参考文章:[365天深度学习训练营-第P2周:彩色识别](https://mp.weixin.qq.com/s/BKsTrlOtu32bQzgORaMLEw)**
>- **🍖 原作者:[K同学啊](https://mtyjkh.blog.csdn.net/)**
目录
一、前期准备
1.1 设置GPU
import torch
import torch.nn as nn
import torchvision.transforms as transforms
import torchvision
import tqdm as tqdm
from torchvision import datasets, models, transforms
import os,PIL,pathlib
import torch.nn.functional as F
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
device
device(type='cuda')
1.2 导入数据
使用dataset下载CIFAR10数据集,并划分好训练集与测试集,使用dataloader加载数据。
train_ds = torchvision.datasets.CIFAR10('data',
train=True,
transform=torchvision.transforms.ToTensor(),
download=True)
test_ds = torchvision.datasets.CIFAR10('data',
train=False,
transform=torchvision.transforms.ToTensor(),
download=True)
batch_size = 32
trian_dl = torch.utils.data.DataLoader(train_ds, batch_size=batch_size, shuffle=True)
test_dl = torch.utils.data.DataLoader(test_ds, batch_size=batch_size, shuffle=False)
imgs ,labels = next(iter(trian_dl))
1.3 数据可视化
plt.figure(figsize=(20,5))
for i , imgs in enumerate(imgs[:20]):
npimg = imgs.numpy().transpose((1,2,0))
plt.subplot(2,10,i+1)
plt.imshow(npimg,cmap=plt.cm.binary)
plt.axis('off')
二、构建简单的CNN网络
2.1 torch.nn.Conv2d()
torch.nn.Conv2d(in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=True, padding_mode='zeros', device=None, dtype=None)
参数说明:
in_channels – 输入图像中的通道数
out_channels – 卷积产生的通道数
kernel_size – 卷积核的大小
stride – 卷积的步幅。默认值:1
padding – 添加到输入的所有四个边的填充。默认值:0
dilation - 扩张操作:控制kernel点(卷积核点)的间距,默认值:1。
padding_mode – 'zeros', 'reflect', 'replicate'或'circular'. 默认:'zeros'
2.2 torch.nn.Linear()
torch.nn.Linear(in_features, out_features, bias=True, device=None, dtype=None)
2.3 torch.nn.MaxPool2d()
torch.nn.MaxPool2d(kernel_size, stride=None, padding=0, dilation=1, return_indices=False, ceil_mode=False)
kernel_size:最大的窗口大小
stride:窗口的步幅,默认值为kernel_size
padding:填充值,默认为0
dilation:控制窗口中元素步幅的参数
2.4 构建模型
num_classes = 10
class Model(nn.Module):
def __init__(self):
super().__init__()
self.conv1 = nn.Conv2d(3, 64, kernel_size=3)
self.pool1 = nn.MaxPool2d(kernel_size=2)
self.conv2 = nn.Conv2d(64, 64, kernel_size=3)
self.pool2 = nn.MaxPool2d(kernel_size=2)
self.conv3 = nn.Conv2d(64, 128, kernel_size=3)
self.pool3 = nn.MaxPool2d(kernel_size=2)
self.fc1 = nn.Linear(128*2*2, 256)
self.fc2 = nn.Linear(256, 128)
self.fc3 = nn.Linear(128, num_classes)
def forward(self, x):
x = self.pool1(F.relu(self.conv1(x)))
x = self.pool2(F.relu(self.conv2(x)))
x = self.pool3(F.relu(self.conv3(x)))
x = torch.flatten(x,start_dim=1)
x = F.relu(self.fc1(x))
x = F.relu(self.fc2(x))
x = self.fc3(x)
return x
2.5 打印模型参数
from torchinfo import summary
model = Model().to(device)
summary(model)
Model --
├─Conv2d: 1-1 1,792
├─MaxPool2d: 1-2 --
├─Conv2d: 1-3 36,928
├─MaxPool2d: 1-4 --
├─Conv2d: 1-5 73,856
├─MaxPool2d: 1-6 --
├─Linear: 1-7 131,328
├─Linear: 1-8 32,896
├─Linear: 1-9 1,290
=================================================================
Total params: 278,090
Trainable params: 278,090
Non-trainable params: 0
=================================================================
三、训练模型
3.1 设置超参数
import tqdm as tqdm
loss_fn = nn.CrossEntropyLoss()
learning_rate = 0.001
optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)
3.2 编写训练函数
def train(dataloader, model ,loss_fn,optimizer):
size = len(dataloader.dataset)
num_batches = len(dataloader)
train_loss = 0.0
train_acc = 0.0
par = tqdm.tqdm(dataloader)
for x, y in par:
x, y = x.to(device), y.to(device)
pred = model(x)
loss = loss_fn(pred, y)
optimizer.zero_grad()
loss.backward()
optimizer.step()
train_acc += (pred.argmax(1) == y).type(torch.float).sum().item()
train_loss += loss.item()
train_acc /= size
train_loss /= num_batches
return train_acc, train_loss
3.3 编写测试函数
def test(dataloader, model, loss_fn):
size = len(dataloader.dataset)
num_batches = len(dataloader)
test_loss = 0.0
test_acc = 0.0
par = tqdm.tqdm(dataloader)
with torch.no_grad():
for imgs, target in par:
imgs, target = imgs.to(device), target.to(device)
pred = model(imgs)
loss = loss_fn(pred, target)
test_acc += (pred.argmax(1) == target).type(torch.float).sum().item()
test_loss += loss.item()
test_acc /= size
test_loss /= num_batches
par.set_description(desc=f'loss={test_loss:.4f} acc={test_acc:.4f}')
return test_acc, test_loss
3.4 训练
epochs = 10
train_loss = []
train_acc = []
test_loss = []
test_acc = []
for epoch in range(epochs):
model.train()
epoch_train_acc , epoch_train_loss = train(trian_dl, model, loss_fn, optimizer)
model.eval()
epoch_test_acc, epoch_test_loss = test(test_dl, model, loss_fn)
train_acc.append(epoch_train_acc)
train_loss.append(epoch_train_loss)
test_acc.append(epoch_test_acc)
test_loss.append(epoch_test_loss)
tmp = ('Epoch: {:2d}, Train Loss: {:.4f}, Train Acc: {:.4f}%, Test Loss: {:.4f}, Test Acc: {:.4f}%')
print(tmp.format(epoch+1, epoch_train_loss, epoch_train_acc*100, epoch_test_loss,epoch_test_acc*100))
Epoch: 1, Train Loss: 1.6013, Train Acc: 40.4180%, Test Loss: 1.3290, Test Acc:51.2500%
Epoch: 2, Train Loss: 1.2079, Train Acc: 56.6840%, Test Loss: 1.1471, Test Acc: 58.6500%
Epoch: 3, Train Loss: 1.0413, Train Acc: 63.1600%, Test Loss: 0.9907, Test Acc: 64.8000%
Epoch: 4, Train Loss: 0.9288, Train Acc: 67.3680%, Test Loss: 0.9407, Test Acc: 66.8700%
Epoch: 5, Train Loss: 0.8405, Train Acc: 70.4920%, Test Loss: 0.9245, Test Acc: 67.6900%
Epoch: 6, Train Loss: 0.7689, Train Acc: 72.8200%, Test Loss: 0.8776, Test Acc: 69.6500%
Epoch: 7, Train Loss: 0.7106, Train Acc: 74.9640%, Test Loss: 0.8722, Test Acc: 70.3700%
Epoch: 8, Train Loss: 0.6574, Train Acc: 76.7360%, Test Loss: 0.9029, Test Acc: 69.3400%
Epoch: 9, Train Loss: 0.6136, Train Acc: 78.2980%, Test Loss: 0.9080, Test Acc: 69.7000%
Epoch: 10, Train Loss: 0.5699, Train Acc: 79.8440%, Test Loss: 0.8913, Test Acc:71.0000%
四、结果可视化
plt.figure(dpi=600)
epochs_range = range(1, epochs+1)
plt.figure(figsize=(12, 3))
plt.subplot(1, 2, 1)
plt.plot(epochs_range, train_acc, label='Training Accuracy')
plt.plot(epochs_range, test_acc, label='Validation Accuracy')
plt.legend(loc='lower right')
plt.title('Training and Validation Accuracy')
plt.subplot(1, 2, 2)
plt.plot(epochs_range, train_loss, label='Training Loss')
plt.plot(epochs_range, test_loss, label='Validation Loss')
plt.legend(loc='upper right')
plt.title('Training and Validation Loss')
plt.show()