卷积神经网络CNN-part2-简单的CNN

卷积神经网络CNN-part1-组成和构建-CSDN博客

摘要:本文介绍了经典的卷积神经网络LeNet及其实现。LeNet由Yann LeCun于1989年提出,是最早的CNN之一,主要用于手写数字识别。其结构包含两个卷积块(每个含卷积层、Sigmoid激活和平均池化)和三个全连接层。文中详细展示了PyTorch实现代码,并演示了28x28输入图像在各层的维度变化。同时提供了模型训练方法,包括数据加载、评估函数和GPU训练过程。最后介绍了一个3D可视化工具,可交互式观察LeNet-5各层处理过程,包括输入填充、卷积、池化及全连接层的具体参数变化。该可视化直观展示了CNN。

1.简单的CNN-LeNet

1.1结构解析

LeNet是最早发布的卷积神经网络之一,因其在计算机视觉任务中的高性能表现收到关注。LeNet是AT&T贝尔实验室的Yann LeCun在1989年发布的,目的是识别图像中的手写数字。LeNet被广泛应用在ATM机上。

LeNet有以下两个部分组成:

卷积编码器:由两个卷积层。

全连接层稠密块:由3个全连接层组成。

结构如下图所示(来自网络)。

每个卷积块都包含了一个卷积层,一个激活函数和一个池化层。第一个卷积层由6个通道,第二个卷积层由16个通道。池化层具有2x2的窗口和2的步距,通过空间采样将维数减少4倍。稠密块有3个全连接层,分别是120、84、10。

1.2构建

实现程序:

python 复制代码
#模型
net=nn.Sequential(
    #卷积层1,输入1转6通道,核函数5x5,填充2,激活函数Sigmoid
    nn.Conv2d(1,6,kernel_size=5,padding=2),nn.Sigmoid(),
    #池化层1,平均池化,窗口2x2,步幅2
    nn.AvgPool2d(kernel_size=2,stride=2),
    #卷积层2,6通道变16通道,核函数5x5,激活函数Sigmoid
    nn.Conv2d(6,16,kernel_size=5),nn.Sigmoid(),
    #池化层2,平均池化,窗口2x2,步幅2
    nn.AvgPool2d(kernel_size=2,stride=2),    
    nn.Flatten(),
    #全连接层1,输出120,激活函数Sigmoid
    nn.Linear(16*5*5,120),nn.Sigmoid(),
    #全连接层2,输出84,激活函数Sigmoid
    nn.Linear(120,84),nn.Sigmoid(),
    #全连接层3,输出10
    nn.Linear(84,10))

输入时28x28像素的单通道图像通过LeNet做前向计算。我们查看下每一层的数据。

python 复制代码
X=torch.rand(size=(1,1,28,28),dtype=torch.float32)
for layer in net:
    X=layer(X)
    print(layer.__class__.__name__,'output shape:\t',X.shape)

结果:

Conv2d output shape: torch.Size([1, 6, 28, 28])

Sigmoid output shape: torch.Size([1, 6, 28, 28])

AvgPool2d output shape: torch.Size([1, 6, 14, 14])

Conv2d output shape: torch.Size([1, 16, 10, 10])

Sigmoid output shape: torch.Size([1, 16, 10, 10])

AvgPool2d output shape: torch.Size([1, 16, 5, 5])

Flatten output shape: torch.Size([1, 400])

Linear output shape: torch.Size([1, 120])

Sigmoid output shape: torch.Size([1, 120])

Linear output shape: torch.Size([1, 84])

Sigmoid output shape: torch.Size([1, 84])

Linear output shape: torch.Size([1, 10])

2. 模型训练

加载数据集

python 复制代码
#模型训练
batch_size=256
train_iter,test_iter=d2l.load_data_fashion_mnist(batch_size=batch_size)

评估准确率函数

python 复制代码
def evalute_accuracy_gpu(net,data_iter,device=None):#@save
    """使用GPU计算模型在数据集上的精度"""
    if isinstance(net,nn.Module):
        net.eval() #设置为评估模式
        if not device:
            device=next(iter(net.parameters())).device
    #正确预测的数量,总预测的数量
    metric=d2l.Accumulator(2)
    with torch.no_grad():
        for X,y in data_iter:
            if isinstance(X,list):
                #BERT微调所需的
                X=[x.to(device) for x in X]
            else:
                X=X.to(device)
            y=y.to(device)
            metric.add(d2l.accuracy(net(X),y),y.numel())
    return metric[0]/metric[1]

训练函数

python 复制代码
def train_ch6(net,train_iter,test_iter,num_epochs,lr,device):
    """用GPU训练模型"""
    def init_weights(m):
        if type(m) == nn.Linear or type(m) == nn.Conv2d:
            nn.init.xavier_uniform_(m.weight)
    net.apply(init_weights)
    print('training on',device)
    net.to(device)
    #优化函数选择了SGD,损失函数选择交叉熵
    optimizer=torch.optim.SGD(net.parameters(),lr=lr)
    loss=nn.CrossEntropyLoss()
    animator=d2l.Animator(xlabel='epoch',xlim=[1,num_epochs],legend=['train loss','train acc','test acc'])
    timer,num_batches=d2l.Timer(),len(train_iter)
    for epoch in range(num_epochs):
        """训练损失之和,训练准确率之和,样本数"""
        metric=d2l.Accumulator(3)
        net.train()
        for i,(X,y) in enumerate(train_iter):
            timer.start()    #计时器开始
            optimizer.zero_grad()    #优化函数初始化
            X,y=X.to(device),y.to(device)
            y_hat=net(X)        
            l=loss(y_hat,y)   #计算损失
            l.backward()       #计算反向梯度
            optimizer.step()    #优化函数计算
            with torch.no_grad():
                metric.add(l*X.shape[0],d2l.accuracy(y_hat,y),X.shape[0])
            timer.stop()        #计时器停止
            train_l=metric[0]/metric[2]            
            train_acc=metric[1]/metric[2]
            if (i+1)%(num_batches//5)==0 or i==num_batches-1:
                animator.add(epoch+(i+1)/num_batches,(train_l,train_acc,None))
        test_acc=evalute_accuracy_gpu(net,test_iter)
        animator.add(epoch+1,(None,None,test_acc))
    print(f'loss {train_l:.3f},train acc {train_acc:.3f},' f'test acc {test_acc:.3f}')
    print(f'{metric[2]*num_epochs/timer.sum():.1f} examples/sec' f'on{str(device)}')

训练模型

python 复制代码
lr,num_epochs=0.9,10
train_ch6(net,train_iter,test_iter,num_epochs,lr,d2l.try_gpu())

3.CNN可视化

在资料查找中发现一个网址:3D Visualization of a Convolutional Neural Network

该网站提供了一个训练好的CNN网络,和基本的LeNet-5的结果类似。左上角可以用鼠标拖动输入数字,右侧控制每一层的的显示与否,中部是每一层每个像素的具体参数。该页面是在三维中开发,可通过不同视觉观察。CNN的具体配置如下:

输入:28x28,但是四周填充了2列,共32x32=1024个单元;

卷积层1:6通道,28x28=784个单元,tanh激活函数;

池化层1:6通道,14x14=196单元,最大池化;

卷积层2:16通道,10x10=100单元,tanh激活函数;

池化层2:16通道,5x5=25单元,最大池化;

稠密层1:120单元,tanh激活函数;

稠密层2:100单元,tanh激活函数;

稠密层3:10单元,tanh激活函数;

最终输出第一结果和第二结果。

相关推荐
编程武士15 小时前
从50ms到30ms:YOLOv10部署中图像预处理的性能优化实践
人工智能·python·yolo·性能优化
max50060015 小时前
基于Meta Llama的二语习得学习者行为预测计算模型
人工智能·算法·机器学习·分类·数据挖掘·llama
月疯16 小时前
OPENCV摄像头读取视频
人工智能·opencv·音视频
极客天成ScaleFlash16 小时前
极客天成让统一存储从云原生‘进化’到 AI 原生: 不是版本升级,而是基因重组
人工智能·云原生
王哥儿聊AI16 小时前
Lynx:新一代个性化视频生成模型,单图即可生成视频,重新定义身份一致性与视觉质量
人工智能·算法·安全·机器学习·音视频·软件工程
_pinnacle_17 小时前
打开神经网络的黑箱(三) 卷积神经网络(CNN)的模型逻辑
人工智能·神经网络·cnn·黑箱·卷积网络
Ada's17 小时前
深度学习在自动驾驶上应用(二)
人工智能·深度学习·自动驾驶
张较瘦_17 小时前
[论文阅读] 人工智能 + 软件工程 | 从“人工扒日志”到“AI自动诊断”:LogCoT框架的3大核心创新
论文阅读·人工智能·软件工程
lisw0517 小时前
连接蓝牙时“无媒体信号”怎么办?
人工智能·机器学习·微服务
扫地的小何尚17 小时前
深度解析 CUDA-QX 0.4 加速 QEC 与求解器库
人工智能·语言模型·llm·gpu·量子计算·nvidia·cuda