Deep Learning学习: CIFAR10彩色图片识别

一,前言(引用)

>- **🍨 本文为[🔗365天深度学习训练营](https://mp.weixin.qq.com/s/Z9yL_wt7L8aPOr9Lqb1K3w) 中的学习记录博客**
>- **🍖 原作者:[K同学啊](https://mtyjkh.blog.csdn.net/)**

二,训练准备

1.训练环境

  • Framework: Pytorch, matplotlib,numpy
  • Compiler:Jupyter Lab
  • Cpu: AMD Ryzen 5600H

三,训练过程

初始化:
import torch
import torch.nn as nn
import matplotlib.pyplot as plt
import torchvision
import numpy as np
from torchinfo import summary

device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
device(type='cpu')
数据集:

使用dataset下载CIFAR10数据集,并划分好训练集与测试集 iter(train_dl): train_dl 是一个 DataLoader 对象,它是一个可迭代对象,包含了训练数据。 iter(train_dl) 将 DataLoader 转换为一个迭代器,这样我们就可以逐批次地获取数据。 next(iter(train_dl)): next() 函数从迭代器中获取下一个批次的数据。在这个例子中,它会返回一个包含图像和标签的元组 (imgs, labels)。

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

train_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)

示例:

imgs, labels = next(iter(train_dl))
imgs.shape
torch.Size([32, 3, 32, 32])
labels
tensor([1, 6, 3, 1, 8, 2, 2, 6, 3, 1, 2, 7, 8, 4, 9, 1, 5, 5, 6, 9, 0, 1, 4, 5,
        9, 3, 5, 8, 6, 0, 7, 9])

transpose((1, 2, 0))详解:

● 作用是对NumPy数组进行轴变换,transpose函数的参数是一个元组,定义了新轴的顺序。原始PyTorch张量通常是以(C, H, W)的格式存储的,其中: ○ C是通道数(例如,RGB图像有3个通道)。 ○ H是图像的高度。 ○ W是图像的宽度。

● transpose((1, 2, 0))将轴的顺序从(C, H, W)转换为(H, W, C),这使得数据格式更适合可视化和处理。

plt.figure(figsize=(30, 5)) 
for i, imgs in enumerate(imgs[:30]):
    
    npimg = imgs.numpy().transpose((1, 2, 0))
    
    plt.subplot(3, 10, i+1)
    plt.imshow(npimg, cmap=plt.cm.binary)
    plt.axis('off')

cmap=plt.cm.binary 参数指定了颜色映射(colormap),在这里使用的是 binary,这意味着图像将以黑白两色显示123。

设计卷积网络和池化层:

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 ( int ) – 输入图像中的通道数 ● out_channels ( int ) – 卷积产生的通道数 ● kernel_size ( int or tuple ) – 卷积核的大小 ● stride ( int or tuple , optional ) -- 卷积的步幅。默认值:1 ● padding ( int , tuple或str , optional ) – 添加到输入的所有四个边的填充。默认值:0 ● dilation (int or tuple, optional) - 扩张操作:控制kernel点(卷积核点)的间距,默认值:1。 ● groups(int,可选):将输入通道分组成多个子组,每个子组使用一组卷积核来处理。默认值为 1,表示不进行分组卷积。 ● padding_mode (字符串,可选) – 'zeros', 'reflect', 'replicate'或'circular'. 默认:'zeros'

2. torch.nn.Linear()

函数原型:

torch.nn.Linear(in_features, out_features, bias=True, device=None, dtype=None)

关键参数说明:

● in_features:每个输入样本的大小 ● out_features:每个输出样本的大小

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:控制窗口中元素步幅的参数

4. 关于卷积层、池化层的计算:

下面的网络数据shape变化过程为:

3, 32, 32(输入数据) -> 64, 30, 30(经过卷积层1)-> 64, 15, 15(经过池化层1) -> 64, 13, 13(经过卷积层2)-> 64, 6, 6(经过池化层2) -> 128, 4, 4(经过卷积层3) -> 128, 2, 2(经过池化层3) -> 512 -> 256 -> num_classes(10)

import torch.nn.functional as F

num_classes = 10  

class Model(nn.Module):
     def __init__(self):
        super().__init__()
         # feature extraction
        self.conv1 = nn.Conv2d(3, 64, kernel_size=3)   # conv kern of 3*3
        self.pool1 = nn.MaxPool2d(kernel_size=2)       # pooling kern of 2*2
        self.conv2 = nn.Conv2d(64, 64, kernel_size=3)  # conv kern of 3*3   
        self.pool2 = nn.MaxPool2d(kernel_size=2)       # pooling kern of 2*2
        self.conv3 = nn.Conv2d(64, 128, kernel_size=3) # conv kern of 3*3   
        self.pool3 = nn.MaxPool2d(kernel_size=2)       # pooling kern of 2*2
                                      
        # classification 
        self.fc1 = nn.Linear(512, 256)          
        self.fc2 = nn.Linear(256, num_classes)
     # forward network
     def forward(self, x):   #3, 32, 32
        x = self.pool1(F.relu(self.conv1(x)))   # 64, 30, 30-> 64, 15, 15
        x = self.pool2(F.relu(self.conv2(x)))   #64, 13, 13-> 64, 6, 6
        x = self.pool3(F.relu(self.conv3(x)))   #128, 4, 4 -> 128, 2, 2
        
        x = torch.flatten(x, start_dim=1) #512

        x = F.relu(self.fc1(x))  #256
        x = self.fc2(x)          #256
       
        return x

模型细节:

=================================================================

Layer (type:depth-idx) Param # =================================================================

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 2,570 ================================================================= Total params: 246,474 Trainable params: 246,474 Non-trainable params: 0 =================================================================

训练方法:
损失函数用CrossEntropy,优化方法SGD
loss_fn    = nn.CrossEntropyLoss() # loss
learn_rate = 1e-2 # lr
opt        = torch.optim.SGD(model.parameters(),lr=learn_rate)
设计训练函数和测试函数
# Train
def train(dataloader, model, loss_fn, optimizer):
    size = len(dataloader.dataset)  # 60000 pictures
    num_batches = len(dataloader)   # Batch size 1875(60000/32)

    train_loss, train_acc = 0, 0  
    
    for X, y in dataloader:  
        X, y = X.to(device), y.to(device)
        
        # calculate the loss
        pred = model(X)          
        loss = loss_fn(pred, y)  
        
        # backward
        optimizer.zero_grad()  
        loss.backward()        
        optimizer.step()       
        
        # acc&loss
        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
def test (dataloader, model, loss_fn):
    size        = len(dataloader.dataset)  # 10000 Pictures
    num_batches = len(dataloader)          # batch size,313(10000/32=312.5)
    test_loss, test_acc = 0, 0
    
    
    with torch.no_grad():
        for imgs, target in dataloader:
            imgs, target = imgs.to(device), target.to(device)
            
            # loss
            target_pred = model(imgs)
            loss        = loss_fn(target_pred, target)
            
            test_loss += loss.item()
            test_acc  += (target_pred.argmax(1) == target).type(torch.float).sum().item()

    test_acc  /= size
    test_loss /= num_batches

    return test_acc, test_loss

1. model.train()

model.train()的作用是启用 Batch Normalization 和 Dropout。

如果模型中有BN层(Batch Normalization)和Dropout,需要在训练时添加model.train()。model.train()是保证BN层能够用到每一批数据的均值和方差。对于Dropout,model.train()是随机取一部分网络连接来训练更新参数。

2. model.eval()

model.eval()的作用是不启用 Batch Normalization 和 Dropout。

如果模型中有BN层(Batch Normalization)和Dropout,在测试时添加model.eval()。model.eval()是保证BN层能够用全部训练数据的均值和方差,即测试过程中要保证BN层的均值和方差不变。对于Dropout,model.eval()是利用到了所有网络连接,即不进行随机舍弃神经元。

训练完train样本后,生成的模型model要用来测试样本。在model(test)之前,需要加上model.eval(),否则的话,有输入数据,即使不训练,它也会改变权值。这是model中含有BN层和Dropout所带来的的性质。

epochs     = 10
train_loss = []
train_acc  = []
test_loss  = []
test_acc   = []

for epoch in range(epochs):
    model.train()
    epoch_train_acc, epoch_train_loss = train(train_dl, model, loss_fn, opt)
    
    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)
    
    template = ('Epoch:{:2d}, Train_acc:{:.1f}%, Train_loss:{:.3f}, Test_acc:{:.1f}%,Test_loss:{:.3f}')
    print(template.format(epoch+1, epoch_train_acc*100, epoch_train_loss, epoch_test_acc*100, epoch_test_loss))
print('Done')

Epoch: 1, Train_acc:12.0%, Train_loss:2.297, Test_acc:16.0%,Test_loss:2.275 Epoch: 2, Train_acc:22.0%, Train_loss:2.100, Test_acc:20.2%,Test_loss:2.125 Epoch: 3, Train_acc:30.2%, Train_loss:1.899, Test_acc:37.4%,Test_loss:1.742 Epoch: 4, Train_acc:38.8%, Train_loss:1.682, Test_acc:41.1%,Test_loss:1.621 Epoch: 5, Train_acc:43.7%, Train_loss:1.552, Test_acc:44.8%,Test_loss:1.515 Epoch: 6, Train_acc:47.2%, Train_loss:1.460, Test_acc:46.8%,Test_loss:1.466 Epoch: 7, Train_acc:50.7%, Train_loss:1.374, Test_acc:49.7%,Test_loss:1.416 Epoch: 8, Train_acc:53.7%, Train_loss:1.300, Test_acc:49.2%,Test_loss:1.405 Epoch: 9, Train_acc:56.3%, Train_loss:1.235, Test_acc:55.0%,Test_loss:1.258 Epoch:10, Train_acc:58.5%, Train_loss:1.181, Test_acc:57.1%,Test_loss:1.210 Done

结果:
import warnings
warnings.filterwarnings("ignore")               
plt.rcParams['font.sans-serif']    = ['SimHei'] 
plt.rcParams['axes.unicode_minus'] = False      #minus
plt.rcParams['figure.dpi']         = 100        

epochs_range = range(epochs)

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='Test 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='Test Loss')
plt.legend(loc='upper right')
plt.title('Training and Validation Loss')
plt.show()

四、总结

在本次学习中,学习了如何使用PyTorch框架进行图像分类任务。学到了如何使用torchvision加载和处理CIFAR-10数据集,使用DataLoader对象批次读取数据,并通过matplotlib进行数据的可视化与转换。掌握了卷积神经网络(CNN)的构建模块,包括Conv2d卷积层、MaxPool2d池化层和Linear全连接层,理解了各层的参数及其作用。通过定义forward方法实现前向传播,使用torchinfo查看模型结构,设计了训练和测试函数,并使用model.train()model.eval()来管理Batch Normalization和Dropout层。模型训练过程中使用了CrossEntropy损失函数和SGD优化器,通过绘制训练与测试的准确率和损失曲线分析模型性能。整个学习过程使我深入理解了深度学习模型的构建、训练和优化流程,为进一步研究和应用深度学习奠定了基础。

  • 数据集的使用与处理

    • 了解了如何使用torchvision下载和加载CIFAR-10数据集,并进行数据的预处理和划分(训练集与测试集)。
    • 学习了如何使用DataLoader对象来迭代数据集,批次地读取数据,提升了对大规模数据的处理能力。
  • 数据可视化与转换

    • 使用matplotlib进行数据可视化,使用transpose函数调整数组的维度,以适应可视化要求。
    • 熟悉了不同颜色映射的使用(如cmap=plt.cm.binary)来展示数据。
  • 神经网络的设计与实现

    • 掌握了卷积神经网络(CNN)的基本构建模块,如Conv2d卷积层、MaxPool2d池化层、Linear全连接层等,理解了各层的关键参数及其作用。
    • 学习了如何搭建一个包含多层卷积和池化的神经网络模型,并在特征提取和分类部分分别使用卷积和全连接层。
  • 前向传播与模型细节展示

    • 通过定义forward方法实现了模型的前向传播过程,掌握了从输入数据到输出预测的流程。
    • 使用torchinfo库中的summary函数查看模型的详细结构信息,帮助理解各层的输出形状及参数量。
  • 训练和测试函数的设计与实现

    • 掌握了如何设计训练函数和测试函数,分别计算模型的损失和准确度。
    • 学习了如何使用model.train()model.eval()来启用和关闭Batch Normalization和Dropout层,确保模型在训练和测试时的行为一致性。
  • 模型训练过程与结果分析

    • 学习了如何使用CrossEntropy作为损失函数,SGD作为优化器,并在不同的epoch中迭代优化模型。
    • 通过绘制训练和测试过程中的准确率和损失曲线,直观地分析模型的性能,观察到随着epoch的增加,训练和测试的准确率逐步提高,损失逐步下降,表明模型在不断学习和优化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值