我的环境

  • 语言环境:Python 3.12
  • 编译器:Jupyter Lab
  • 深度学习环境:Pytorch 2.4.1 Torchvision 0.19.1
  • 数据集:鸟类分类数据库(和之前的几周一样)

📌 本周任务:
●2.了解并研究 DenseNet与ResNetV 的区别
●3.改进思路是否可以迁移到其他地方呢(自由探索,虽然不强求但是请认真对待这个哦)

一、前言

在计算机视觉领域,卷积神经网络(CNN)已经成为最主流的方法,比如GoogLenet,VGG-16,Incepetion等模型。CNN史上的一个里程碑事件是ResNet模型的出现,ResNet可以训练出更深的CNN模型,从而实现更高的准确度。ResNet模型的核心是通过建立前面层与后面层之间的“短路连接”(shortcuts,skip connection),进而训练出更深的CNN网络。

今天我们要介绍的是DenseNet模型,它的基本思路与ResNet一致,但是它建立的是前面所有层与后面层的密集连接(dense connection),它的名称也是由此而来。DenseNet的另一大特色是通过特征在channel上的连接来实现特征重用(feature reuse)。这些特点让DenseNet在参数和计算成本更少的情形下实现比ResNet更优的性能,DenseNet也因此斩获CVPR 2017的最佳论文奖。

DenseNet(Densely Connected Convolutional Network)是一种深度神经网络架构,于2017年由Gao Huang等人提出。它是深度学习中经典的卷积神经网络模型之一,在图像分类、目标检测等领域表现优异。DenseNet通过高效的信息流传递和参数复用,实现了更高的性能和更少的参数量。
在这里插入图片描述

以下是对DenseNet的核心思想、结构和优点的详细介绍:


核心思想

DenseNet的关键思想是通过密集连接(Dense Connectivity),实现特征的高效利用。具体来说:

  • 在传统的卷积网络中,层与层之间是线性连接的,数据从上一层流向下一层。而在DenseNet中,每一层都与之前所有层直接相连。
  • 每一层的输出不仅作为下一层的输入,还会被直接传递给所有后续层。这样可以更好地保留前面层提取的特征,并减轻梯度消失问题。

网络结构

DenseNet的基本构成可以分为以下几个部分:

  1. Dense Block

    • 在一个Dense Block中,每一层都接收所有前面层的特征图作为输入,并将自己的输出传递给后续所有层。
    • 对于第( l )层,其输入是所有之前层的特征的级联,公式为:
      x l = H l ( [ x 0 , x 1 , … , x l − 1 ] ) x_l = H_l([x_0, x_1, \ldots, x_{l-1}]) xl​=Hl​([x0​,x1​,…,xl−1​])
      其中, H l H_l Hl​表示第 l l l层的非线性变换(如卷积、ReLU等), [ x 0 , x 1 , … , x l − 1 ] [x_0, x_1, \ldots, x_{l-1}] [x0​,x1​,…,xl−1​]表示特征级联。
  2. Transition Layer

    • 在Dense Blocks之间插入Transition Layer,用于降维和控制模型复杂度。
    • Transition Layer通常由一个 1 × 1 1\times1 1×1卷积层和一个平均池化层(Average Pooling)组成。
  3. Growth Rate

    • DenseNet的一个重要超参数是增长率(Growth Rate, ( k )),表示每一层新增的特征图数量。
    • Growth Rate较小时,模型更轻量化;较大时,模型更有表达能力。
  4. 全局池化和分类层

    • 最终通过全局平均池化层(Global Average Pooling)和全连接层实现分类。

优点

  1. 参数高效

    • DenseNet通过特征复用显著减少了参数量,因为不需要重复计算冗余特征。
  2. 缓解梯度消失

    • DenseNet的直接连接机制使得梯度可以从后层更轻松地传递到前面层,改善了深度网络的训练。
  3. 特征复用

    • 每一层的特征都会被后续层反复利用,显著提高了模型的表达能力。
  4. 更深的网络

    • DenseNet的架构支持更深的网络,而不会带来过高的计算开销。

DenseNet的变体

DenseNet有多个变体,适应不同的任务和场景:

  1. DenseNet-121、DenseNet-169、DenseNet-201、DenseNet-264

    • 基于层数的不同,适用于从轻量级到更复杂的任务。
  2. DenseNet在语义分割、目标检测中的扩展

    • 如在DenseASPP等模型中,与空洞卷积结合,用于语义分割任务。

应用场景

  • 图像分类:如ImageNet、CIFAR-10等数据集上表现优异。
  • 目标检测:DenseNet作为特征提取器,广泛应用于Faster R-CNN等模型中。
  • 医学影像分析:DenseNet因其高效的特征表达能力,常用于CT图像分类、病灶检测等任务。

DenseNet与ResNet的比较

特性DenseNetResNet
连接方式每层与之前所有层连接仅与前一层的输出相加
参数量更少较多
特征复用高效较低
梯度流动更顺畅较好
适用场景更深、更复杂的网络多种场景,适用性广泛

二、设计理念

相比ResNet,DenseNet提出了一种更为激进的密集链接机制:即互相连接所有的层,具体来说就是每个层都会接受前面所有层作为其额外的输入。

图1展示了ResNet的残差连接机制,作为对比,后面图2为DenseNet的密集连接机制。可以看到,ResNet是每个层与前面的某层短路连接在一起,连接方式是元素相加,而DenseNet中,每个层都会与前面所有层在channel维度上concat在一起,元素叠加,并作为下一层的输入。
图一图1
在这里插入图片描述图2

三、网络结构

CNN网络一般要经过Pooling或者Stride > 1的Conv来降低特征图的大小,而DenseNet的密集连接方式需要特征图大小保持一致。为了解决这个问题,DenseNet网络中使用DenseBlock + Transition的结构,其中DenseBlock是包含很多层的模块,每个层的特征图大小相同,层与层之间采用密集连接方式,Transition层是链接两个相邻的DenseBlock,通过Pooling使特征图的大小降低。

在这里插入图片描述

四、网络构建

1、Denselayer的构建

import torch
import torch.nn as nn
import torch.nn.functional as F
from torch.utils import model_zoo


class _DenseLayer(nn.Sequential):
    def __init__(self,num_input_features, growth_rate, bn_size, drop_rate):
        super(_DenseLayer,self).__init__()
        self.add_module('norm1',nn.BatchNorm2d(num_input_features))
        self.add_module('relu1',nn.ReLU(inplace=True))
        self.add_module('conv1',nn.Conv2d(num_input_features, bn_size*growth_rate, kernel_size=1, stride=1,bias = False))
        self.add_module('norm2',nn.BatchNorm2d(bn_size*growth_rate))
        self.add_module('relu2',nn.ReLU(inplace=True))
        self.add_module('conv2',nn.Conv2d(bn_size*growth_rate, growth_rate, kernel_size=3, stride=1,padding=1, bias = False))
        self.drop_rate = drop_rate
        
    def forward(self,x):
        new_features = super(_DenseLayer, self).forward(x)
        if self.drop_rate > 0:
            new_features = F.dropout(new_features, p=self.drop_rate, training=self.training)
            
        return torch.cat([x, new_features],1)

2、Denseblock的构建

class _DenseBlock(nn.Sequential):
    def __init__(self, num_layers, num_input_features, bn_size, growth_rate, drop_rate):
        super(_DenseBlock,self).__init__()
        for i in range(num_layers):
            layer = _DenseLayer(num_input_features+i*growth_rate, growth_rate, bn_size, drop_rate)
            self.add_module('denselayer%d'%(i+1,),layer)

3、Transition的构建

class _Transition(nn.Sequential):
    def __init__(self, num_input_features, num_output_features):
        super(_Transition,self).__init__()
        self.add_module('norm',nn.BatchNorm2d(num_input_features))
        self.add_module('relu',nn.ReLU(inplace=True))
        self.add_module('conv',nn.Conv2d(num_input_features, num_output_features, kernel_size=1,stride=1, bias=False))
        self.add_module('pool',nn.AvgPool2d(2, stride=2))

4、完整网络构建

from collections import OrderedDict

class DenseNet(nn.Module):
    def __init__(self, growth_rate = 32, block_config =(6, 12, 24, 16), num_init_features=64, bn_size = 4, compression_rate = 0.5, drop_rate = 0, num_classes = 1000):
        
        super(DenseNet, self).__init__()
        self.features = nn.Sequential(OrderedDict([
            ('conv0', nn.Conv2d(3, num_init_features, kernel_size=7, stride=2, padding=3, bias=False)),
            ('norm0', nn.BatchNorm2d(num_init_features)),
            ('relu0', nn.ReLU(inplace=True)),
            ('pool0', nn.MaxPool2d(3, stride=2, padding=1))
        ]))
        
        num_features = num_init_features
        for i, num_layers in enumerate(block_config):
            block = _DenseBlock(num_layers, num_features, bn_size, growth_rate, drop_rate)
            self.features.add_module('denseblock%d' % (i + 1), block)
            num_features += num_layers * growth_rate
            if i != len(block_config) - 1:
                transition = _Transition(num_features, int(num_features * compression_rate))
                self.features.add_module('transition%d' % (i + 1), transition)
                num_features = int(num_features * compression_rate)
                
        self.features.add_module('norm5', nn.BatchNorm2d(num_features))
        self.features.add_module('relu5', nn.ReLU(inplace=True))
        
        self.classifier = nn.Linear(num_features, num_classes)
        
        for m in self.modules():
            if isinstance(m, nn.Conv2d):
                nn.init.kaiming_normal_(m.weight)
            elif isinstance(m, nn.BatchNorm2d):
                nn.init.constant_(m.bias, 0)
                nn.init.constant_(m.weight,1)
            elif isinstance(m, nn.Linear):
                nn.init.constant_(m.bias,0)
        
    
    def forward(self, x):
        features = self.features(x)
        out = F.avg_pool2d(features, kernel_size=features.size()[2:]).view(features.size(0), -1)
        out = self.classifier(out)
        return out

使用densenet121:

import re
from torch.utils import model_zoo

model_urls = {
    'densenet121': 'https://download.pytorch.org/models/densenet121-a639ec97.pth',
}

def densenet121(pretrained=False, **kwargs):
    model = DenseNet(num_init_features = 64, growth_rate = 32, block_config = (6, 12, 24, 16), **kwargs)
    
    if pretrained:
        pattern = re.compile(r'^(.*denselayer\d+\.(?:norm|relu|conv))\.((?:[12])\.(?:weight|bias|running_mean|running_var))$')
        state_dict = model_zoo.load_url(model_urls['densenet121'])
        for key in list(state_dict.keys()):
            res = pattern.match(key)
            if res:
                new_key = res.group(1)+res.group(2)
                state_dict[new_key] = state_dict[key]
                del state_dict[key]
        
        model.load_state_dict(state_dict)
        return model

我们可以查看网络:

import torchsummary
model = densenet121(pretrained=True).cuda()
x = (3, 224, 224)

torchsummary.summary(model,x)

代码输出:

----------------------------------------------------------------
        Layer (type)               Output Shape         Param #
================================================================
            Conv2d-1         [-1, 64, 112, 112]           9,408
       BatchNorm2d-2         [-1, 64, 112, 112]             128
              ReLU-3         [-1, 64, 112, 112]               0
         MaxPool2d-4           [-1, 64, 56, 56]               0
       BatchNorm2d-5           [-1, 64, 56, 56]             128
              ReLU-6           [-1, 64, 56, 56]               0
            Conv2d-7          [-1, 128, 56, 56]           8,192
       BatchNorm2d-8          [-1, 128, 56, 56]             256
              ReLU-9          [-1, 128, 56, 56]               0
           Conv2d-10           [-1, 32, 56, 56]          36,864
      BatchNorm2d-11           [-1, 96, 56, 56]             192
             ReLU-12           [-1, 96, 56, 56]               0
           Conv2d-13          [-1, 128, 56, 56]          12,288
      BatchNorm2d-14          [-1, 128, 56, 56]             256
             ReLU-15          [-1, 128, 56, 56]               0
           Conv2d-16           [-1, 32, 56, 56]          36,864
      BatchNorm2d-17          [-1, 128, 56, 56]             256
             ReLU-18          [-1, 128, 56, 56]               0
           Conv2d-19          [-1, 128, 56, 56]          16,384
      BatchNorm2d-20          [-1, 128, 56, 56]             256
             ReLU-21          [-1, 128, 56, 56]               0
           Conv2d-22           [-1, 32, 56, 56]          36,864
      BatchNorm2d-23          [-1, 160, 56, 56]             320
             ReLU-24          [-1, 160, 56, 56]               0
           Conv2d-25          [-1, 128, 56, 56]          20,480
      BatchNorm2d-26          [-1, 128, 56, 56]             256
             ReLU-27          [-1, 128, 56, 56]               0
           Conv2d-28           [-1, 32, 56, 56]          36,864
      BatchNorm2d-29          [-1, 192, 56, 56]             384
             ReLU-30          [-1, 192, 56, 56]               0
           Conv2d-31          [-1, 128, 56, 56]          24,576
      BatchNorm2d-32          [-1, 128, 56, 56]             256
             ReLU-33          [-1, 128, 56, 56]               0
           Conv2d-34           [-1, 32, 56, 56]          36,864
      BatchNorm2d-35          [-1, 224, 56, 56]             448
             ReLU-36          [-1, 224, 56, 56]               0
           Conv2d-37          [-1, 128, 56, 56]          28,672
      BatchNorm2d-38          [-1, 128, 56, 56]             256
             ReLU-39          [-1, 128, 56, 56]               0
           Conv2d-40           [-1, 32, 56, 56]          36,864
      BatchNorm2d-41          [-1, 256, 56, 56]             512
             ReLU-42          [-1, 256, 56, 56]               0
           Conv2d-43          [-1, 128, 56, 56]          32,768
        AvgPool2d-44          [-1, 128, 28, 28]               0
      BatchNorm2d-45          [-1, 128, 28, 28]             256
             ReLU-46          [-1, 128, 28, 28]               0
           Conv2d-47          [-1, 128, 28, 28]          16,384
      BatchNorm2d-48          [-1, 128, 28, 28]             256
             ReLU-49          [-1, 128, 28, 28]               0
           Conv2d-50           [-1, 32, 28, 28]          36,864
      BatchNorm2d-51          [-1, 160, 28, 28]             320
             ReLU-52          [-1, 160, 28, 28]               0
           Conv2d-53          [-1, 128, 28, 28]          20,480
      BatchNorm2d-54          [-1, 128, 28, 28]             256
             ReLU-55          [-1, 128, 28, 28]               0
           Conv2d-56           [-1, 32, 28, 28]          36,864
      BatchNorm2d-57          [-1, 192, 28, 28]             384
             ReLU-58          [-1, 192, 28, 28]               0
           Conv2d-59          [-1, 128, 28, 28]          24,576
      BatchNorm2d-60          [-1, 128, 28, 28]             256
             ReLU-61          [-1, 128, 28, 28]               0
           Conv2d-62           [-1, 32, 28, 28]          36,864
      BatchNorm2d-63          [-1, 224, 28, 28]             448
             ReLU-64          [-1, 224, 28, 28]               0
           Conv2d-65          [-1, 128, 28, 28]          28,672
      BatchNorm2d-66          [-1, 128, 28, 28]             256
             ReLU-67          [-1, 128, 28, 28]               0
           Conv2d-68           [-1, 32, 28, 28]          36,864
      BatchNorm2d-69          [-1, 256, 28, 28]             512
             ReLU-70          [-1, 256, 28, 28]               0
           Conv2d-71          [-1, 128, 28, 28]          32,768
      BatchNorm2d-72          [-1, 128, 28, 28]             256
             ReLU-73          [-1, 128, 28, 28]               0
           Conv2d-74           [-1, 32, 28, 28]          36,864
      BatchNorm2d-75          [-1, 288, 28, 28]             576
             ReLU-76          [-1, 288, 28, 28]               0
           Conv2d-77          [-1, 128, 28, 28]          36,864
      BatchNorm2d-78          [-1, 128, 28, 28]             256
             ReLU-79          [-1, 128, 28, 28]               0
           Conv2d-80           [-1, 32, 28, 28]          36,864
      BatchNorm2d-81          [-1, 320, 28, 28]             640
             ReLU-82          [-1, 320, 28, 28]               0
           Conv2d-83          [-1, 128, 28, 28]          40,960
      BatchNorm2d-84          [-1, 128, 28, 28]             256
             ReLU-85          [-1, 128, 28, 28]               0
           Conv2d-86           [-1, 32, 28, 28]          36,864
      BatchNorm2d-87          [-1, 352, 28, 28]             704
             ReLU-88          [-1, 352, 28, 28]               0
           Conv2d-89          [-1, 128, 28, 28]          45,056
      BatchNorm2d-90          [-1, 128, 28, 28]             256
             ReLU-91          [-1, 128, 28, 28]               0
           Conv2d-92           [-1, 32, 28, 28]          36,864
      BatchNorm2d-93          [-1, 384, 28, 28]             768
             ReLU-94          [-1, 384, 28, 28]               0
           Conv2d-95          [-1, 128, 28, 28]          49,152
      BatchNorm2d-96          [-1, 128, 28, 28]             256
             ReLU-97          [-1, 128, 28, 28]               0
           Conv2d-98           [-1, 32, 28, 28]          36,864
      BatchNorm2d-99          [-1, 416, 28, 28]             832
            ReLU-100          [-1, 416, 28, 28]               0
          Conv2d-101          [-1, 128, 28, 28]          53,248
     BatchNorm2d-102          [-1, 128, 28, 28]             256
            ReLU-103          [-1, 128, 28, 28]               0
          Conv2d-104           [-1, 32, 28, 28]          36,864
     BatchNorm2d-105          [-1, 448, 28, 28]             896
            ReLU-106          [-1, 448, 28, 28]               0
          Conv2d-107          [-1, 128, 28, 28]          57,344
     BatchNorm2d-108          [-1, 128, 28, 28]             256
            ReLU-109          [-1, 128, 28, 28]               0
          Conv2d-110           [-1, 32, 28, 28]          36,864
     BatchNorm2d-111          [-1, 480, 28, 28]             960
            ReLU-112          [-1, 480, 28, 28]               0
          Conv2d-113          [-1, 128, 28, 28]          61,440
     BatchNorm2d-114          [-1, 128, 28, 28]             256
            ReLU-115          [-1, 128, 28, 28]               0
          Conv2d-116           [-1, 32, 28, 28]          36,864
     BatchNorm2d-117          [-1, 512, 28, 28]           1,024
            ReLU-118          [-1, 512, 28, 28]               0
          Conv2d-119          [-1, 256, 28, 28]         131,072
       AvgPool2d-120          [-1, 256, 14, 14]               0
     BatchNorm2d-121          [-1, 256, 14, 14]             512
            ReLU-122          [-1, 256, 14, 14]               0
          Conv2d-123          [-1, 128, 14, 14]          32,768
     BatchNorm2d-124          [-1, 128, 14, 14]             256
            ReLU-125          [-1, 128, 14, 14]               0
          Conv2d-126           [-1, 32, 14, 14]          36,864
     BatchNorm2d-127          [-1, 288, 14, 14]             576
            ReLU-128          [-1, 288, 14, 14]               0
          Conv2d-129          [-1, 128, 14, 14]          36,864
     BatchNorm2d-130          [-1, 128, 14, 14]             256
            ReLU-131          [-1, 128, 14, 14]               0
          Conv2d-132           [-1, 32, 14, 14]          36,864
     BatchNorm2d-133          [-1, 320, 14, 14]             640
            ReLU-134          [-1, 320, 14, 14]               0
          Conv2d-135          [-1, 128, 14, 14]          40,960
     BatchNorm2d-136          [-1, 128, 14, 14]             256
            ReLU-137          [-1, 128, 14, 14]               0
          Conv2d-138           [-1, 32, 14, 14]          36,864
     BatchNorm2d-139          [-1, 352, 14, 14]             704
            ReLU-140          [-1, 352, 14, 14]               0
          Conv2d-141          [-1, 128, 14, 14]          45,056
     BatchNorm2d-142          [-1, 128, 14, 14]             256
            ReLU-143          [-1, 128, 14, 14]               0
          Conv2d-144           [-1, 32, 14, 14]          36,864
     BatchNorm2d-145          [-1, 384, 14, 14]             768
            ReLU-146          [-1, 384, 14, 14]               0
          Conv2d-147          [-1, 128, 14, 14]          49,152
     BatchNorm2d-148          [-1, 128, 14, 14]             256
            ReLU-149          [-1, 128, 14, 14]               0
          Conv2d-150           [-1, 32, 14, 14]          36,864
     BatchNorm2d-151          [-1, 416, 14, 14]             832
            ReLU-152          [-1, 416, 14, 14]               0
          Conv2d-153          [-1, 128, 14, 14]          53,248
     BatchNorm2d-154          [-1, 128, 14, 14]             256
            ReLU-155          [-1, 128, 14, 14]               0
          Conv2d-156           [-1, 32, 14, 14]          36,864
     BatchNorm2d-157          [-1, 448, 14, 14]             896
            ReLU-158          [-1, 448, 14, 14]               0
          Conv2d-159          [-1, 128, 14, 14]          57,344
     BatchNorm2d-160          [-1, 128, 14, 14]             256
            ReLU-161          [-1, 128, 14, 14]               0
          Conv2d-162           [-1, 32, 14, 14]          36,864
     BatchNorm2d-163          [-1, 480, 14, 14]             960
            ReLU-164          [-1, 480, 14, 14]               0
          Conv2d-165          [-1, 128, 14, 14]          61,440
     BatchNorm2d-166          [-1, 128, 14, 14]             256
            ReLU-167          [-1, 128, 14, 14]               0
          Conv2d-168           [-1, 32, 14, 14]          36,864
     BatchNorm2d-169          [-1, 512, 14, 14]           1,024
            ReLU-170          [-1, 512, 14, 14]               0
          Conv2d-171          [-1, 128, 14, 14]          65,536
     BatchNorm2d-172          [-1, 128, 14, 14]             256
            ReLU-173          [-1, 128, 14, 14]               0
          Conv2d-174           [-1, 32, 14, 14]          36,864
     BatchNorm2d-175          [-1, 544, 14, 14]           1,088
            ReLU-176          [-1, 544, 14, 14]               0
          Conv2d-177          [-1, 128, 14, 14]          69,632
     BatchNorm2d-178          [-1, 128, 14, 14]             256
            ReLU-179          [-1, 128, 14, 14]               0
          Conv2d-180           [-1, 32, 14, 14]          36,864
     BatchNorm2d-181          [-1, 576, 14, 14]           1,152
            ReLU-182          [-1, 576, 14, 14]               0
          Conv2d-183          [-1, 128, 14, 14]          73,728
     BatchNorm2d-184          [-1, 128, 14, 14]             256
            ReLU-185          [-1, 128, 14, 14]               0
          Conv2d-186           [-1, 32, 14, 14]          36,864
     BatchNorm2d-187          [-1, 608, 14, 14]           1,216
            ReLU-188          [-1, 608, 14, 14]               0
          Conv2d-189          [-1, 128, 14, 14]          77,824
     BatchNorm2d-190          [-1, 128, 14, 14]             256
            ReLU-191          [-1, 128, 14, 14]               0
          Conv2d-192           [-1, 32, 14, 14]          36,864
     BatchNorm2d-193          [-1, 640, 14, 14]           1,280
            ReLU-194          [-1, 640, 14, 14]               0
          Conv2d-195          [-1, 128, 14, 14]          81,920
     BatchNorm2d-196          [-1, 128, 14, 14]             256
            ReLU-197          [-1, 128, 14, 14]               0
          Conv2d-198           [-1, 32, 14, 14]          36,864
     BatchNorm2d-199          [-1, 672, 14, 14]           1,344
            ReLU-200          [-1, 672, 14, 14]               0
          Conv2d-201          [-1, 128, 14, 14]          86,016
     BatchNorm2d-202          [-1, 128, 14, 14]             256
            ReLU-203          [-1, 128, 14, 14]               0
          Conv2d-204           [-1, 32, 14, 14]          36,864
     BatchNorm2d-205          [-1, 704, 14, 14]           1,408
            ReLU-206          [-1, 704, 14, 14]               0
          Conv2d-207          [-1, 128, 14, 14]          90,112
     BatchNorm2d-208          [-1, 128, 14, 14]             256
            ReLU-209          [-1, 128, 14, 14]               0
          Conv2d-210           [-1, 32, 14, 14]          36,864
     BatchNorm2d-211          [-1, 736, 14, 14]           1,472
            ReLU-212          [-1, 736, 14, 14]               0
          Conv2d-213          [-1, 128, 14, 14]          94,208
     BatchNorm2d-214          [-1, 128, 14, 14]             256
            ReLU-215          [-1, 128, 14, 14]               0
          Conv2d-216           [-1, 32, 14, 14]          36,864
     BatchNorm2d-217          [-1, 768, 14, 14]           1,536
            ReLU-218          [-1, 768, 14, 14]               0
          Conv2d-219          [-1, 128, 14, 14]          98,304
     BatchNorm2d-220          [-1, 128, 14, 14]             256
            ReLU-221          [-1, 128, 14, 14]               0
          Conv2d-222           [-1, 32, 14, 14]          36,864
     BatchNorm2d-223          [-1, 800, 14, 14]           1,600
            ReLU-224          [-1, 800, 14, 14]               0
          Conv2d-225          [-1, 128, 14, 14]         102,400
     BatchNorm2d-226          [-1, 128, 14, 14]             256
            ReLU-227          [-1, 128, 14, 14]               0
          Conv2d-228           [-1, 32, 14, 14]          36,864
     BatchNorm2d-229          [-1, 832, 14, 14]           1,664
            ReLU-230          [-1, 832, 14, 14]               0
          Conv2d-231          [-1, 128, 14, 14]         106,496
     BatchNorm2d-232          [-1, 128, 14, 14]             256
            ReLU-233          [-1, 128, 14, 14]               0
          Conv2d-234           [-1, 32, 14, 14]          36,864
     BatchNorm2d-235          [-1, 864, 14, 14]           1,728
            ReLU-236          [-1, 864, 14, 14]               0
          Conv2d-237          [-1, 128, 14, 14]         110,592
     BatchNorm2d-238          [-1, 128, 14, 14]             256
            ReLU-239          [-1, 128, 14, 14]               0
          Conv2d-240           [-1, 32, 14, 14]          36,864
     BatchNorm2d-241          [-1, 896, 14, 14]           1,792
            ReLU-242          [-1, 896, 14, 14]               0
          Conv2d-243          [-1, 128, 14, 14]         114,688
     BatchNorm2d-244          [-1, 128, 14, 14]             256
            ReLU-245          [-1, 128, 14, 14]               0
          Conv2d-246           [-1, 32, 14, 14]          36,864
     BatchNorm2d-247          [-1, 928, 14, 14]           1,856
            ReLU-248          [-1, 928, 14, 14]               0
          Conv2d-249          [-1, 128, 14, 14]         118,784
     BatchNorm2d-250          [-1, 128, 14, 14]             256
            ReLU-251          [-1, 128, 14, 14]               0
          Conv2d-252           [-1, 32, 14, 14]          36,864
     BatchNorm2d-253          [-1, 960, 14, 14]           1,920
            ReLU-254          [-1, 960, 14, 14]               0
          Conv2d-255          [-1, 128, 14, 14]         122,880
     BatchNorm2d-256          [-1, 128, 14, 14]             256
            ReLU-257          [-1, 128, 14, 14]               0
          Conv2d-258           [-1, 32, 14, 14]          36,864
     BatchNorm2d-259          [-1, 992, 14, 14]           1,984
            ReLU-260          [-1, 992, 14, 14]               0
          Conv2d-261          [-1, 128, 14, 14]         126,976
     BatchNorm2d-262          [-1, 128, 14, 14]             256
            ReLU-263          [-1, 128, 14, 14]               0
          Conv2d-264           [-1, 32, 14, 14]          36,864
     BatchNorm2d-265         [-1, 1024, 14, 14]           2,048
            ReLU-266         [-1, 1024, 14, 14]               0
          Conv2d-267          [-1, 512, 14, 14]         524,288
       AvgPool2d-268            [-1, 512, 7, 7]               0
     BatchNorm2d-269            [-1, 512, 7, 7]           1,024
            ReLU-270            [-1, 512, 7, 7]               0
          Conv2d-271            [-1, 128, 7, 7]          65,536
     BatchNorm2d-272            [-1, 128, 7, 7]             256
            ReLU-273            [-1, 128, 7, 7]               0
          Conv2d-274             [-1, 32, 7, 7]          36,864
     BatchNorm2d-275            [-1, 544, 7, 7]           1,088
            ReLU-276            [-1, 544, 7, 7]               0
          Conv2d-277            [-1, 128, 7, 7]          69,632
     BatchNorm2d-278            [-1, 128, 7, 7]             256
            ReLU-279            [-1, 128, 7, 7]               0
          Conv2d-280             [-1, 32, 7, 7]          36,864
     BatchNorm2d-281            [-1, 576, 7, 7]           1,152
            ReLU-282            [-1, 576, 7, 7]               0
          Conv2d-283            [-1, 128, 7, 7]          73,728
     BatchNorm2d-284            [-1, 128, 7, 7]             256
            ReLU-285            [-1, 128, 7, 7]               0
          Conv2d-286             [-1, 32, 7, 7]          36,864
     BatchNorm2d-287            [-1, 608, 7, 7]           1,216
            ReLU-288            [-1, 608, 7, 7]               0
          Conv2d-289            [-1, 128, 7, 7]          77,824
     BatchNorm2d-290            [-1, 128, 7, 7]             256
            ReLU-291            [-1, 128, 7, 7]               0
          Conv2d-292             [-1, 32, 7, 7]          36,864
     BatchNorm2d-293            [-1, 640, 7, 7]           1,280
            ReLU-294            [-1, 640, 7, 7]               0
          Conv2d-295            [-1, 128, 7, 7]          81,920
     BatchNorm2d-296            [-1, 128, 7, 7]             256
            ReLU-297            [-1, 128, 7, 7]               0
          Conv2d-298             [-1, 32, 7, 7]          36,864
     BatchNorm2d-299            [-1, 672, 7, 7]           1,344
            ReLU-300            [-1, 672, 7, 7]               0
          Conv2d-301            [-1, 128, 7, 7]          86,016
     BatchNorm2d-302            [-1, 128, 7, 7]             256
            ReLU-303            [-1, 128, 7, 7]               0
          Conv2d-304             [-1, 32, 7, 7]          36,864
     BatchNorm2d-305            [-1, 704, 7, 7]           1,408
            ReLU-306            [-1, 704, 7, 7]               0
          Conv2d-307            [-1, 128, 7, 7]          90,112
     BatchNorm2d-308            [-1, 128, 7, 7]             256
            ReLU-309            [-1, 128, 7, 7]               0
          Conv2d-310             [-1, 32, 7, 7]          36,864
     BatchNorm2d-311            [-1, 736, 7, 7]           1,472
            ReLU-312            [-1, 736, 7, 7]               0
          Conv2d-313            [-1, 128, 7, 7]          94,208
     BatchNorm2d-314            [-1, 128, 7, 7]             256
            ReLU-315            [-1, 128, 7, 7]               0
          Conv2d-316             [-1, 32, 7, 7]          36,864
     BatchNorm2d-317            [-1, 768, 7, 7]           1,536
            ReLU-318            [-1, 768, 7, 7]               0
          Conv2d-319            [-1, 128, 7, 7]          98,304
     BatchNorm2d-320            [-1, 128, 7, 7]             256
            ReLU-321            [-1, 128, 7, 7]               0
          Conv2d-322             [-1, 32, 7, 7]          36,864
     BatchNorm2d-323            [-1, 800, 7, 7]           1,600
            ReLU-324            [-1, 800, 7, 7]               0
          Conv2d-325            [-1, 128, 7, 7]         102,400
     BatchNorm2d-326            [-1, 128, 7, 7]             256
            ReLU-327            [-1, 128, 7, 7]               0
          Conv2d-328             [-1, 32, 7, 7]          36,864
     BatchNorm2d-329            [-1, 832, 7, 7]           1,664
            ReLU-330            [-1, 832, 7, 7]               0
          Conv2d-331            [-1, 128, 7, 7]         106,496
     BatchNorm2d-332            [-1, 128, 7, 7]             256
            ReLU-333            [-1, 128, 7, 7]               0
          Conv2d-334             [-1, 32, 7, 7]          36,864
     BatchNorm2d-335            [-1, 864, 7, 7]           1,728
            ReLU-336            [-1, 864, 7, 7]               0
          Conv2d-337            [-1, 128, 7, 7]         110,592
     BatchNorm2d-338            [-1, 128, 7, 7]             256
            ReLU-339            [-1, 128, 7, 7]               0
          Conv2d-340             [-1, 32, 7, 7]          36,864
     BatchNorm2d-341            [-1, 896, 7, 7]           1,792
            ReLU-342            [-1, 896, 7, 7]               0
          Conv2d-343            [-1, 128, 7, 7]         114,688
     BatchNorm2d-344            [-1, 128, 7, 7]             256
            ReLU-345            [-1, 128, 7, 7]               0
          Conv2d-346             [-1, 32, 7, 7]          36,864
     BatchNorm2d-347            [-1, 928, 7, 7]           1,856
            ReLU-348            [-1, 928, 7, 7]               0
          Conv2d-349            [-1, 128, 7, 7]         118,784
     BatchNorm2d-350            [-1, 128, 7, 7]             256
            ReLU-351            [-1, 128, 7, 7]               0
          Conv2d-352             [-1, 32, 7, 7]          36,864
     BatchNorm2d-353            [-1, 960, 7, 7]           1,920
            ReLU-354            [-1, 960, 7, 7]               0
          Conv2d-355            [-1, 128, 7, 7]         122,880
     BatchNorm2d-356            [-1, 128, 7, 7]             256
            ReLU-357            [-1, 128, 7, 7]               0
          Conv2d-358             [-1, 32, 7, 7]          36,864
     BatchNorm2d-359            [-1, 992, 7, 7]           1,984
            ReLU-360            [-1, 992, 7, 7]               0
          Conv2d-361            [-1, 128, 7, 7]         126,976
     BatchNorm2d-362            [-1, 128, 7, 7]             256
            ReLU-363            [-1, 128, 7, 7]               0
          Conv2d-364             [-1, 32, 7, 7]          36,864
     BatchNorm2d-365           [-1, 1024, 7, 7]           2,048
            ReLU-366           [-1, 1024, 7, 7]               0
          Linear-367                 [-1, 1000]       1,025,000
================================================================
Total params: 7,978,856
Trainable params: 7,978,856
Non-trainable params: 0
----------------------------------------------------------------
Input size (MB): 0.57
Forward/backward pass size (MB): 294.58
Params size (MB): 30.44
Estimated Total Size (MB): 325.59
----------------------------------------------------------------

剩下的和之前一样我们用于鸟类分类问题:

import os, PIL, pathlib
from torchvision import transforms, datasets

data_dir = './data/第十一周/bird_photos/'
data_dir = pathlib.Path(data_dir)

data_paths = list(data_dir.glob('*'))
classNames = [path.name for path in data_paths]
classNames

代码输出:

['Bananaquit', 'Black Skimmer', 'Black Throated Bushtiti', 'Cockatoo']

接下来是transform:

train_transforms = transforms.Compose([
    transforms.RandomResizedCrop(224),  # 随机裁剪到 224x224
    transforms.RandomHorizontalFlip(), # 随机水平翻转
    transforms.ToTensor(),             # 转为 Tensor
    transforms.Normalize(
        mean=[0.485, 0.456, 0.406], 
        std=[0.229, 0.224, 0.225])  # 标准化
])

total_data = datasets.ImageFolder('./data/第十一周/bird_photos/', transform = train_transforms)
total_data

代码输出:

Dataset ImageFolder
    Number of datapoints: 565
    Root location: ./data/第十一周/bird_photos/
    StandardTransform
Transform: Compose(
               RandomResizedCrop(size=(224, 224), scale=(0.08, 1.0), ratio=(0.75, 1.3333), interpolation=bilinear, antialias=True)
               RandomHorizontalFlip(p=0.5)
               ToTensor()
               Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
           )
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
device

代码输出:

device(type='cuda')

接下来划分数据集:

train_size = int(0.7 * len(total_data)) #训练集的大小为总数据的70%
remain_size  = len(total_data) - train_size  #剩下的为测试集
train_dataset, remain_dataset = torch.utils.data.random_split(total_data, [train_size, remain_size]) #随机分配数据
test_size = int(0.6 * len(remain_dataset))
validate_size = len(remain_dataset) - test_size
test_dataset, validate_dataset = torch.utils.data.random_split(remain_dataset, [test_size, validate_size]) #随机分配数据
train_dataset, test_dataset, validate_dataset

代码输出:

(<torch.utils.data.dataset.Subset at 0x1aaa5696390>,
 <torch.utils.data.dataset.Subset at 0x1aaa5694380>,
 <torch.utils.data.dataset.Subset at 0x1aaa5696840>)
batch_size = 16
train_dl = torch.utils.data.DataLoader(
    train_dataset,
    batch_size = batch_size,
    shuffle = True,
    num_workers = 4
)

test_dl = torch.utils.data.DataLoader(
    test_dataset,
    batch_size = batch_size,
    shuffle = False,
    num_workers = 4
)

validate_dl = torch.utils.data.DataLoader(
    validate_dataset,
    batch_size = batch_size,
    shuffle = False,
    num_workers = 4
)

for x, y in test_dl:
    print('shape of x[N, C, H, W]:', x.shape)
    print('shape of y:',y.shape)
    break

代码输出:

shape of x[N, C, H, W]: torch.Size([16, 3, 224, 224])
shape of y: torch.Size([16])

查看数据情况:

import numpy as np
import matplotlib.pyplot as plt
# 定义反归一化函数
def unnormalize(img, mean, std):
    mean = np.array(mean)
    std = np.array(std)
    img = img * std + mean  # 反归一化
    return np.clip(img, 0, 1)  # 限制值范围到 [0, 1]

plt.figure(figsize=(10, 5))
mean = [0.485, 0.456, 0.406]
std = [0.229, 0.224, 0.225]

for images, labels in test_dl:  # 从 DataLoader 中获取一个批次
    for i in range(8):  # 显示前 8 张图片
        ax = plt.subplot(2, 4, i + 1)  # 创建 2 行 4 列的子图
        
        # 反归一化并转换为 (H, W, C)
        img = images[i].permute(1, 2, 0).numpy()  # (C, H, W) -> (H, W, C)
        img = unnormalize(img, mean, std)  # 反归一化
        
        # 显示图像
        plt.imshow(img)  # 显示图像,值范围应为 [0, 1]
        plt.title(classNames[labels[i].item()])  # 使用类别名称作为标题
        plt.axis("off")  # 关闭坐标轴
    break  # 仅显示第一个批次

代码输出:
在这里插入图片描述
接下来正式训练:

def train(dataloader, model, loss_fn, optimizer):
    size = len(dataloader.dataset)
    num_batches = len(dataloader)

    train_loss, train_acc = 0, 0

    for x, y in dataloader:
        x, y = x.to(device), y.to(device)

        pred = model(x)
        loss = loss_fn(pred, y)

        #backward
        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

def test(dataloader, model, loss_fn):
    size = len(dataloader.dataset)
    num_batches = len(dataloader)

    test_loss, test_acc = 0, 0

    for x, y in dataloader:
        x, y = x.to(device), y.to(device)

        pred = model(x)
        loss = loss_fn(pred, y)

        test_acc += (pred.argmax(1) == y).type(torch.float).sum().item()
        test_loss += loss.item()

    test_acc /= size
    test_loss /= num_batches

    return test_acc, test_loss
#%%
import copy
from torch.optim.lr_scheduler import ReduceLROnPlateau

opt = torch.optim.Adam(model.parameters(), lr= 1e-4)
scheduler = ReduceLROnPlateau(opt, mode='min', factor=0.1, patience=5, verbose=True) # 当指标(如损失)连续 5 次没有改善时,将学习率乘以 0.1
loss_fn = nn.CrossEntropyLoss() # 交叉熵

epochs = 32

train_loss = []
train_acc  = []
test_loss  = []
test_acc   = []

best_acc = 0    # 设置一个最佳准确率,作为最佳模型的判别指标

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)
    scheduler.step(epoch_test_loss)
    
    if epoch_test_acc > best_acc:
        best_acc = epoch_test_acc
        best_model = copy.deepcopy(model)

    train_acc.append(epoch_train_acc)
    train_loss.append(epoch_train_loss)
    test_acc.append(epoch_test_acc)
    test_loss.append(epoch_test_loss)

     # 获取当前的学习率
    lr = opt.state_dict()['param_groups'][0]['lr']
    
    template = ('Epoch:{:2d}, Train_acc:{:.1f}%, Train_loss:{:.3f}, Test_acc:{:.1f}%, Test_loss:{:.3f}, Lr:{:.2E}')
    print(template.format(epoch+1, epoch_train_acc*100, epoch_train_loss, 
                          epoch_test_acc*100, epoch_test_loss, lr))
    
# 保存最佳模型到文件中
PATH = './best_model.pth'  # 保存的参数文件名
torch.save(best_model.state_dict(), PATH)

print('Done')

代码输出:

Epoch: 1, Train_acc:98.2%, Train_loss:0.072, Test_acc:99.0%, Test_loss:0.114, Lr:1.00E-04
Epoch: 2, Train_acc:98.2%, Train_loss:0.050, Test_acc:99.0%, Test_loss:0.026, Lr:1.00E-04
Epoch: 3, Train_acc:98.7%, Train_loss:0.038, Test_acc:99.0%, Test_loss:0.019, Lr:1.00E-04
Epoch: 4, Train_acc:98.0%, Train_loss:0.087, Test_acc:98.0%, Test_loss:0.068, Lr:1.00E-04
Epoch: 5, Train_acc:96.7%, Train_loss:0.078, Test_acc:100.0%, Test_loss:0.014, Lr:1.00E-04
Epoch: 6, Train_acc:99.0%, Train_loss:0.022, Test_acc:98.0%, Test_loss:0.022, Lr:1.00E-04
Epoch: 7, Train_acc:99.0%, Train_loss:0.030, Test_acc:100.0%, Test_loss:0.003, Lr:1.00E-04
Epoch: 8, Train_acc:99.0%, Train_loss:0.031, Test_acc:98.0%, Test_loss:0.034, Lr:1.00E-04
Epoch: 9, Train_acc:98.2%, Train_loss:0.043, Test_acc:99.0%, Test_loss:0.033, Lr:1.00E-04
Epoch:10, Train_acc:99.0%, Train_loss:0.033, Test_acc:97.1%, Test_loss:0.065, Lr:1.00E-04
Epoch:11, Train_acc:99.2%, Train_loss:0.040, Test_acc:98.0%, Test_loss:0.038, Lr:1.00E-04
Epoch:12, Train_acc:97.7%, Train_loss:0.064, Test_acc:97.1%, Test_loss:0.107, Lr:1.00E-04
Epoch:13, Train_acc:98.2%, Train_loss:0.055, Test_acc:100.0%, Test_loss:0.018, Lr:1.00E-05
Epoch:14, Train_acc:98.7%, Train_loss:0.029, Test_acc:99.0%, Test_loss:0.012, Lr:1.00E-05
Epoch:15, Train_acc:97.5%, Train_loss:0.074, Test_acc:99.0%, Test_loss:0.017, Lr:1.00E-05
Epoch:16, Train_acc:99.7%, Train_loss:0.010, Test_acc:99.0%, Test_loss:0.023, Lr:1.00E-05
Epoch:17, Train_acc:98.2%, Train_loss:0.042, Test_acc:99.0%, Test_loss:0.010, Lr:1.00E-05
Epoch:18, Train_acc:99.2%, Train_loss:0.023, Test_acc:96.1%, Test_loss:0.042, Lr:1.00E-05
Epoch:19, Train_acc:99.2%, Train_loss:0.028, Test_acc:99.0%, Test_loss:0.028, Lr:1.00E-06
Epoch:20, Train_acc:98.7%, Train_loss:0.025, Test_acc:100.0%, Test_loss:0.011, Lr:1.00E-06
Epoch:21, Train_acc:99.0%, Train_loss:0.020, Test_acc:97.1%, Test_loss:0.066, Lr:1.00E-06
Epoch:22, Train_acc:99.5%, Train_loss:0.021, Test_acc:98.0%, Test_loss:0.094, Lr:1.00E-06
Epoch:23, Train_acc:99.2%, Train_loss:0.028, Test_acc:100.0%, Test_loss:0.004, Lr:1.00E-06
Epoch:24, Train_acc:98.7%, Train_loss:0.031, Test_acc:98.0%, Test_loss:0.031, Lr:1.00E-06
Epoch:25, Train_acc:99.2%, Train_loss:0.025, Test_acc:95.1%, Test_loss:0.079, Lr:1.00E-07
Epoch:26, Train_acc:99.7%, Train_loss:0.012, Test_acc:98.0%, Test_loss:0.023, Lr:1.00E-07
Epoch:27, Train_acc:99.5%, Train_loss:0.021, Test_acc:98.0%, Test_loss:0.050, Lr:1.00E-07
Epoch:28, Train_acc:99.7%, Train_loss:0.021, Test_acc:99.0%, Test_loss:0.011, Lr:1.00E-07
Epoch:29, Train_acc:99.5%, Train_loss:0.019, Test_acc:99.0%, Test_loss:0.015, Lr:1.00E-07
Epoch:30, Train_acc:99.0%, Train_loss:0.034, Test_acc:99.0%, Test_loss:0.024, Lr:1.00E-07
Epoch:31, Train_acc:99.7%, Train_loss:0.012, Test_acc:99.0%, Test_loss:0.014, Lr:1.00E-08
Epoch:32, Train_acc:99.5%, Train_loss:0.018, Test_acc:99.0%, Test_loss:0.032, Lr:1.00E-08
Done

数据可视化:

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

代码输出:
在这里插入图片描述
对验证集的准确性预测:

plt.figure(figsize=(10, 5))  

# 遍历验证数据集,取第一个批次
for images, labels in test_dl:
    for i in range(8):  # 只显示前 8 张图片
        ax = plt.subplot(2, 4, i + 1)

        # 显示图片
        img = images[i].permute(1, 2, 0).numpy()  # 转换为 (H, W, C)
        img = unnormalize(img, mean, std)  # 反归一化
        plt.imshow(img)  # 显示图像,值范围为 [0, 1]

        # 增加一个维度用于模型预测
        img_tensor = images[i].unsqueeze(0).to("cuda" if torch.cuda.is_available() else "cpu")

        # 使用模型预测类别
        best_model.eval()  # 切换到评估模式
        with torch.no_grad():  # 禁用梯度计算
            predictions = best_model(img_tensor)  # 预测结果
            predicted_class_index = predictions.argmax(dim=1).item()  # 获取预测类别索引
            predicted_class = classNames[predicted_class_index]  # 获取预测类别名称

        # 获取真实类别名称
        true_class = classNames[labels[i].item()]

        # 设置标题为真实类别和预测类别
        plt.title(f"T: {true_class}\nP: {predicted_class}")
        plt.axis("off")  # 隐藏坐标轴

        # 打印真实类别和预测类别
        print(f"Image {i+1}: True Label = {true_class}, Predicted Label = {predicted_class}")

    break  # 只处理第一个批次

代码输出:

Image 1: True Label = Black Skimmer, Predicted Label = Black Skimmer
Image 2: True Label = Cockatoo, Predicted Label = Cockatoo
Image 3: True Label = Black Skimmer, Predicted Label = Black Skimmer
Image 4: True Label = Cockatoo, Predicted Label = Cockatoo
Image 5: True Label = Black Skimmer, Predicted Label = Black Skimmer
Image 6: True Label = Cockatoo, Predicted Label = Cockatoo
Image 7: True Label = Bananaquit, Predicted Label = Bananaquit
Image 8: True Label = Bananaquit, Predicted Label = Bananaquit

在这里插入图片描述
验证集的总体正确率:

def validate(dataloader, model):
    model.eval()
    size = len(dataloader.dataset)
    num_batches = len(dataloader)

    validate_acc = 0

    for x, y in dataloader:
        x, y = x.to(device), y.to(device)

        pred = model(x)

        validate_acc += (pred.argmax(1) == y).type(torch.float).sum().item()

    validate_acc /= size

    return validate_acc


# 计算验证集准确率
validate_acc = validate(validate_dl, best_model)
print(f"Validation Accuracy: {validate_acc:.2%}")

代码输出:

Validation Accuracy: 92.65%

验证集的准确性达到92.65%

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐