随着机器学习和人工智能需求的增长,越来越多的公司开始开发计算机系统和新技术以实现这一目标。人工智能已经成为全球增长最快的技术之一,据估计每天新增机器超过30,000台。目标检测和目标分类是人工智能的一部分,目前也呈现出显著的增长趋势。自动驾驶汽车越来越受欢迎,这些汽车能够实时检测道路上的物体,使用高效的目标检测模型。此外,使用智能驾驶技术检测行人也成为一个流行行业,一些公司如特斯拉正在引领这一潮流。
在本文中,将创建一个使用卷积神经网络的图像分类模型,能够对10个不同类别的图像进行分类。还将讨论训练模型在测试集上的准确度和损失曲线。
CIFAR-10数据集包含60,000张32×32彩色图像,每个类别包含6000张图像,共有十个类别。它由50,000张32×32彩色训练图像组成,跨越十个类别,以及10,000张测试图像。对于CIFAR-FS数据集,训练测试分割也是50000个样本用于训练,10000个用于测试。图像大小为32×32×3。
存在的不同类别包括:['飞机', '汽车', '鸟', '猫', '鹿', '狗', '青蛙', '马', '船', '卡车']。每个测试和训练数据集中不同类别的样本数量如下:
train_dataset class : {'青蛙': 5000, '卡车': 5000, '鹿': 5000, '汽车': 5000, '鸟': 5000,
'马': 5000, '船': 5000, '猫': 5000, '狗': 5000, '飞机': 5000}
test_dataset class : {'猫': 1000, '船': 1000, '飞机': 1000, '青蛙': 1000, '汽车': 1000,
'卡车': 1000, '狗': 1000, '马': 1000, '鹿': 1000, '鸟': 1000}
在这一部分,将看到加载和预处理Cifar-10数据集的代码。首先,将使用torchvision库直接下载数据集,并将数据集分为训练集和测试集。
import torchvision
import torch
from torch.utils.data import DataLoader
from torchvision import transforms
# 设置
torch.manual_seed(42)
# 加载数据集
train_dataset = torchvision.datasets.CIFAR10(root='data/', train=True, download=True, transform=transforms.ToTensor())
test_dataset = torchvision.datasets.CIFAR10(root='data/', download=True, train=False, transform=transforms.ToTensor())
# 分割数据集
my_list = [45000, 5000]
train_ds, val_ds = torch.utils.data.random_split(train_dataset, my_list)
# 配置
configs = {'random_seed': 42, 'val_size': 5000, 'train_size': 45000, 'pin_memory': True, 'optimizer': 'Adam', 'batch_size': 64, 'lr': 0.001}
# 数据加载器
train_data = DataLoader(train_ds, configs['batch_size'], shuffle=True, pin_memory=configs['pin_memory'], num_workers=2)
val_data = DataLoader(val_ds, configs['batch_size'], shuffle=True, pin_memory=configs['pin_memory'], num_workers=2)
将检查系统是否包含专用GPU。GPU可以加速训练过程,因为它包含特殊硬件。
def GPU_IsAvailable():
if torch.cuda.is_available():
temp = torch.device('cuda')
return temp
else:
tmp1 = torch.device('cpu')
return tmp1
下面,编写了一些基本函数,如evaluate,用于评估模型在测试数据上的准确度。另一个名为fit的函数用于拟合CNN模型内的训练数据。
import torch.nn as nn
import torch.optim as optim
channel = 3
num = 28
@torch.no_grad()
def evaluate(model, val_loader, dt_load):
model.eval()
outputs = []
for i in val_loader:
temp = model.val_func(i, num, channel)
outputs.append(temp)
var3 = model.valid_func(outputs, num)
return var3
def fit(epochs, lr, model, train_loader, val_loader):
lst1 = list()
lst2 = list()
opt_func = optim.Adam
optimizer = opt_func(model.parameters(), lr)
for epoch in range(epochs):
lst3 = []
# 训练阶段
model.train()
for batch in train_loader:
loss = model.train_func(batch, num)
lst3.append(loss)
loss.backward()
optimizer.step()
optimizer.zero_grad()
# 验证阶段
result = evaluate(model, val_loader, epoch)
result['train_loss'] = torch.stack(lst3).mean().item()
model.func(epoch, result, channel)
lst1.append(result)
return lst1
CNN模型将包含三层,每层包含一个卷积层和一个最大池化层。
two = 2
one = 1
class CnnModel1_2(nn.Module):
def __init__(self):
super().__init__()
self.network = nn.Sequential(
nn.Conv2d(3, 32, kernel_size=3, stride=1, padding=1),
nn.ReLU(),
nn.MaxPool2d(2, 2),
nn.Conv2d(32, 64, kernel_size=3, stride=1, padding=1),
nn.ReLU(),
nn.MaxPool2d(2, 2),
nn.Conv2d(64, 128, kernel_size=3, stride=1, padding=1),
nn.ReLU(),
nn.MaxPool2d(2, 2),
nn.Flatten(),
nn.Linear(4*4*128, 10)
)
def forward(self, x):
x = self.network(x)
return x
将设置训练周期为20,然后将训练数据输入模型。
model1_2 = CnnModel1_2()
train_data1_2 = DataLoader(GPU_IsAvailable(), train_data)
val_data1_2 = DataLoader(GPU_IsAvailable(), val_data)
GPU_Calculate(model1_2, GPU_IsAvailable())
# 训练20个周期
num_epochs = 20
lr = configs['lr']
history = fit(num_epochs, lr, model1_2, train_data1_2, val_data1_2)
将绘制训练和验证损失随周期数变化的曲线。
import matplotlib.pyplot as plt
train_losses = [x.get('train_loss') for x in history]
val_losses = [x['val_loss'] for x in history]
plt.plot(train_losses, '-bx')
plt.plot(val_losses, '-yx')
plt.xlabel('周期')
plt.ylabel('损失')
plt.legend(['训练', '验证'])
plt.title('损失与周期数')
plt.show()
将绘制训练和验证准确度随周期数变化的曲线。
accuracies = [x['val_acc'] for x in history]
plt.plot(accuracies, '-yx')
plt.xlabel('周期')
plt.ylabel('准确度')
plt.title('准确度与周期数')
plt.show()
改变网络大小如何影响准确度?卷积神经网络由两个主要部分组成,即特征提取和分类。在这些类型的网络中,卷积操作负责特征提取,而全连接层负责分类。观察到,从I到iii的三次实验中改变网络大小,准确度趋于提高,这表明改变网络大小会影响准确度。然而,相反地,观察到在第三种架构中存在两个全连接层。
实验不同的池化大小,并对池化大小对网络的影响进行详细分析。池化是一个用户定义的操作。手头有不同类型的池化,如最大池化、求和池化和平均池化,各有利弊。但通常使用最大池化,因为它在给定的问题陈述上表现更好,因为试图根据它们的重要性提取特征。由于它包含更多的特征提取层,双卷积块(Conv-Conv-Pool-Conv-Conv-Pool)比其他模型表现更好。它的区分能力增强,使其能够更好地工作。还发现,增加一个以上的FC层并不影响性能,这意味着增加额外的FC层并不能保证更好的性能。它更多地依赖于特征提取层。当增加池化大小时,会发生两件事之一,即要么获得更多的泛化能力,要么在更多的收缩发生时丢失一些重要特征。