卷积神经网络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激活函数;

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

相关推荐
机器之心4 小时前
谷歌放出Nano Banana六大正宗Prompt玩法,手残党速来
人工智能·openai
艾醒4 小时前
大模型面试题剖析:大模型微调数据集构建
人工智能·算法·程序员
慧都小项4 小时前
构建安全的自动驾驶:软件测试中的编码规范与AI验证
人工智能·测试工具·安全·自动驾驶·parasoft
GEO_JYB4 小时前
车载卫星通信:让自动驾驶“永不掉线”?
人工智能
用户5191495848454 小时前
Azure MCP Server:连接AI与Azure服务的智能桥梁
人工智能·aigc
技术小黑4 小时前
NLP学习系列 | Transformer代码简单实现
人工智能·自然语言处理
overstarry4 小时前
zed 配置 acp-claude-code 使用 Claude Code
人工智能·claude
yangshuo12814 小时前
Augmentcode免费额度AI开发WordPress商城实战
人工智能
JAMES费4 小时前
分布式AI算力系统番外篇-----超体的现实《星核》
人工智能·分布式