在深度学习的模型开发流程中,模型测试与网络结构优化是至关重要的环节。结合实际代码与操作,总结模型测试的方法以及全局平均池化在网络中的应用。

一、模型测试:评估网络性能

(一)整体准确率测试

要评估模型在测试集上的整体表现,我们可以通过计算预测正确的样本数与总样本数的比例来得到整体准确率。以下是实现代码:

python

运行

correct = 0
total = 0
with torch.no_grad():
    for data in testloader:
        images, labels = data
        images, labels = images.to(device), labels.to(device)
        outputs = net(images)
        _, predicted = torch.max(outputs.data, 1)
        total += labels.size(0)
        correct += (predicted == labels).sum().item()

print('Accuracy of the network on the 10000 test images: %d %%' % (
    100 * correct / total))

这里需要注意,在使用testloader前,要确保已经正确创建了测试数据加载器。通常通过torch.utils.data.DataLoader结合相应的数据集(如 CIFAR10)来创建,代码如下:

python

运行

from torch.utils.data import DataLoader
from torchvision import datasets, transforms

transform = transforms.Compose([
    transforms.ToTensor(),
    transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))
])

testset = datasets.CIFAR10(
    root='./data', 
    train=False, 
    download=True, 
    transform=transform
)
testloader = DataLoader(
    testset, 
    batch_size=4, 
    shuffle=False, 
    num_workers=2
)

同时,要定义好device(指定计算设备是 CPU 还是 GPU)以及网络模型net,并将网络移动到指定设备上:

python

运行

import torch
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
# 假设net是已经定义好的网络模型
net = net.to(device)

(二)按类别准确率测试

除了整体准确率,有时我们还需要了解模型在每个类别上的表现,这就需要按类别计算准确率。代码实现如下:

python

运行

class_correct = list(0. for i in range(10))
class_total = list(0. for i in range(10))
with torch.no_grad():
    for data in testloader:
        images, labels = data
        images, labels = images.to(device), labels.to(device)
        outputs = net(images)
        _, predicted = torch.max(outputs, 1)
        c = (predicted == labels).squeeze()
        for i in range(4):
            label = labels[i]
            class_correct[label] += c[i].item()
            class_total[label] += 1

classes = ('plane', 'car', 'bird', 'cat', 'deer', 
           'dog', 'frog', 'horse', 'ship', 'truck')
for i in range(10):
    print('Accuracy of %5s : %2d %%' % (
        classes[i], 100 * class_correct[i] / class_total[i]))

通过这种方式,我们可以清晰地看到模型在各个类别上的优势与不足,为后续的模型优化提供方向。

二、全局平均池化:优化网络结构

在卷积神经网络(CNN)的结构设计中,池化层用于减小特征图尺寸、降低计算量并增强网络的平移不变性等。全局平均池化(Global Average Pooling,GAP)作为一种特殊的池化方式,具有诸多优势。

(一)全局平均池化的原理

对于形状为\(H\times W\times C\)(H为高度,W为宽度,C为通道数)的特征图,全局平均池化会对每个通道的所有元素求平均,最终得到形状为\(1\times 1\times C\)的输出。它将每个通道的空间信息压缩为一个数值,既保留了通道的特征信息,又极大地简化了后续计算。

(二)代码实现

以下是一个采用全局平均池化的网络结构代码示例:

python

运行

import torch.nn as nn
import torch.nn.functional as F
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")

class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = nn.Conv2d(3, 16, 5)
        self.pool1 = nn.MaxPool2d(2, 2)
        self.conv2 = nn.Conv2d(16, 36, 5)
        self.aap = nn.AdaptiveAvgPool2d(1)
        self.fc3 = nn.Linear(36, 10)

    def forward(self, x):
        x = self.pool1(F.relu(self.conv1(x)))
        x = self.pool2(F.relu(self.conv2(x)))
        x = self.aap(x)
        x = x.view(x.shape[0], -1)
        x = self.fc3(x)
        return x

net = Net()
net = net.to(device)

print("net_gvp have {} parameters in total".format(sum(x.numel() for x in net.parameters())))

在这个网络中,先通过卷积和最大池化提取特征,然后使用AdaptiveAvgPool2d(1)实现全局平均池化,将每个通道的特征图压缩为单个值,最后通过全连接层完成分类等任务。

(三)全局平均池化的优势

  1. 减少参数量:与传统全连接层相比,全局平均池化几乎不引入额外参数,能有效缓解过拟合,使网络更易于训练和泛化。
  2. 保留空间相关性:基于整个特征图进行平均,能更好地保留特征图的空间相关性信息,相比局部池化(如最大池化、平均池化),可捕获更全局的特征。
  3. 增强解释性:每个通道经过全局平均池化后的输出,可看作是该通道对最终任务的重要性指标,有助于理解网络学习到的特征。
  4. 简化网络结构:避免了复杂的全连接层设计,使网络结构更加简洁,也减少了计算过程中的内存占用。

三、总结

模型测试是评估网络性能的关键步骤,通过整体准确率和按类别准确率测试,能全面了解模型的表现。而全局平均池化作为一种高效的池化方式,在现代卷积神经网络设计中优势明显,能帮助我们构建更高效、更具泛化能力的神经网络模型。在实际的深度学习任务中,合理运用这些技术,将助力我们更好地完成模型开发与优化工作。

Logo

码道开发者社区,聚焦华为云码道 CodeArts 代码智能体,沉淀 Agent、Skill、鸿蒙开发实战内容,供开发者查阅资料、交流技术、分享工程实践

更多推荐