如何仿制一个网站,石家庄酒店网站建设,适合做网页的主题,平面设计要什么学历Pytorch | 从零构建GoogleNet对CIFAR10进行分类 CIFAR10数据集GoogleNet网络结构特点网络整体架构应用与影响Inceptionv1到Inceptionv2 GoogleNet结构代码详解结构代码代码详解Inception 类初始化方法前向传播 forward GoogleNet 类初始化方法前向传播 forward 训练过程和测试结… Pytorch | 从零构建GoogleNet对CIFAR10进行分类 CIFAR10数据集GoogleNet网络结构特点网络整体架构应用与影响Inceptionv1到Inceptionv2 GoogleNet结构代码详解结构代码代码详解Inception 类初始化方法前向传播 forward GoogleNet 类初始化方法前向传播 forward 训练过程和测试结果代码汇总googlenet.pytrain.pytest.py 前面文章我们构建了AlexNet、Vgg对CIFAR10进行分类 Pytorch | 从零构建AlexNet对CIFAR10进行分类 Pytorch | 从零构建Vgg对CIFAR10进行分类 这篇文章我们来构建GoogleNet或称GoogleNet-BN, Inception v2.
CIFAR10数据集
CIFAR-10数据集是由加拿大高级研究所CIFAR收集整理的用于图像识别研究的常用数据集基本信息如下
数据规模该数据集包含60,000张彩色图像分为10个不同的类别每个类别有6,000张图像。通常将其中50,000张作为训练集用于模型的训练10,000张作为测试集用于评估模型的性能。图像尺寸所有图像的尺寸均为32×32像素这相对较小的尺寸使得模型在处理该数据集时能够相对快速地进行训练和推理但也增加了图像分类的难度。类别内容涵盖了飞机plane、汽车car、鸟bird、猫cat、鹿deer、狗dog、青蛙frog、马horse、船ship、卡车truck这10个不同的类别这些类别都是现实世界中常见的物体具有一定的代表性。
下面是一些示例样本
GoogleNet
GoogleNet是由Google团队在2014年提出的一种深度卷积神经网络架构以下是对它的详细介绍
网络结构特点
Inception模块这是GoogleNet的核心创新点。Inception模块通过并行使用不同大小的卷积核如1×1、3×3、5×5和池化操作然后将它们的结果在通道维度上进行拼接从而可以同时提取不同尺度的特征。例如1×1卷积核可以用于在不改变特征图尺寸的情况下进行降维或升维减少计算量3×3和5×5卷积核则可以捕捉不同感受野的特征。深度和宽度GoogleNet网络很深共有22层但它的参数量却比同层次的一些网络少很多这得益于Inception模块的高效设计。同时网络的宽度也较大能够学习到丰富的特征表示。辅助分类器为了缓解梯度消失问题GoogleNet在网络中间层添加了两个辅助分类器。这些辅助分类器在训练过程中与主分类器一起进行反向传播帮助梯度更好地传播到浅层网络加快训练速度并提高模型的泛化能力。在测试时辅助分类器的结果会被加权融合到主分类器的结果中。
网络整体架构 输入层接收大小为 H × W × 3 H×W×3 H×W×3的图像数据其中 H H H和 W W W表示图像的高度和宽度3表示图像的RGB通道数。 卷积层和池化层网络的前面几层主要由卷积层和池化层组成用于提取图像的基本特征。这些层逐渐降低图像的分辨率同时增加特征图的通道数。 Inception模块组网络的主体部分由多个Inception模块组构成每个模块组包含多个Inception模块。随着网络的深入Inception模块的输出通道数逐渐增加以学习更高级的特征。 池化层和全连接层在Inception模块组之后网络通过一个平均池化层将特征图的尺寸缩小到1×1然后将其展平并连接到一个全连接层最后通过一个Softmax层输出分类结果。
应用与影响
图像分类GoogleNet在图像分类任务上取得了非常好的效果在ILSVRC 2014图像分类竞赛中获得了冠军。它能够准确地识别各种自然图像中的物体类别如猫、狗、汽车、飞机等。目标检测GoogleNet也可以应用于目标检测任务通过在网络中添加一些额外的检测层和算法可以实现对图像中物体的定位和检测。后续研究基础GoogleNet的成功推动了深度学习领域的发展其Inception模块的设计思想为后来的许多网络架构提供了灵感如Inception系列的后续版本以及其他一些基于多分支结构的网络。
Inceptionv1到Inceptionv2
上面所提到的 Inception 模块组我们称之为 Inception v1而后谷歌又对其进行优化体现在本文的代码中的即
引入了Batch Normalization (BN)层Inception v1 没有 BN 层而 Inception v2 在每个卷积层之后引入了 BN 层。这有助于解决深层网络中的梯度消失问题使每一层的输入更加稳定从而加快训练过程并提高模型的收敛速度.优化卷积核组合Inception v1 中使用 1x1、3x3、5x5 的卷积核和 3x3 的池化操作并行组合。Inception v2 学习 VGG 网络的做法用两个 3x3 的卷积核替代 Inception 模块中的 5x5 卷积核减少了参数数量同时增加了网络的非线性表达能力
GoogleNet结构代码详解
结构代码
import torch
import torch.nn as nnclass Inception(nn.Module):def __init__(self, in_channels, ch1x1, ch3x3reduc, ch3x3, ch5x5reduc, ch5x5, pool_proj):super().__init__()self.branch1x1 nn.Sequential(nn.Conv2d(in_channels, ch1x1, kernel_size1),nn.BatchNorm2d(ch1x1),nn.ReLU(inplaceTrue))self.branch3x3 nn.Sequential(nn.Conv2d(in_channels, ch3x3reduc, kernel_size1),nn.BatchNorm2d(ch3x3reduc),nn.ReLU(inplaceTrue),nn.Conv2d(ch3x3reduc, ch3x3, kernel_size3, padding1),nn.ReLU(inplaceTrue))self.branch5x5 nn.Sequential(nn.Conv2d(in_channels, ch5x5reduc, kernel_size1),nn.BatchNorm2d(ch5x5reduc),nn.ReLU(inplaceTrue),nn.Conv2d(ch5x5reduc, ch5x5, kernel_size3, padding1),nn.BatchNorm2d(ch5x5),nn.ReLU(inplaceTrue),nn.Conv2d(ch5x5, ch5x5, kernel_size3, padding1),nn.BatchNorm2d(ch5x5),nn.ReLU(inplaceTrue))self.branch_pool nn.Sequential(nn.MaxPool2d(kernel_size3, stride1, padding1),nn.Conv2d(in_channels, pool_proj, kernel_size1),nn.BatchNorm2d(pool_proj),nn.ReLU(inplaceTrue))def forward(self, x):branch1x1 self.branch1x1(x)branch3x3 self.branch3x3(x)branch5x5 self.branch5x5(x)branch_pool self.branch_pool(x)return torch.cat([branch1x1, branch3x3, branch5x5, branch_pool], 1)class GoogleNet(nn.Module):def __init__(self, num_classes):super(GoogleNet, self).__init__()self.prelayers nn.Sequential(nn.Conv2d(3, 64, kernel_size3, padding1),nn.BatchNorm2d(64),nn.ReLU(inplaceTrue),nn.Conv2d(64, 64, kernel_size3, padding1),nn.BatchNorm2d(64),nn.ReLU(inplaceTrue),nn.Conv2d(64, 192, kernel_size3, padding1),nn.BatchNorm2d(192),nn.ReLU(inplaceTrue))self.maxpool2 nn.MaxPool2d(kernel_size3, stride2, padding1)self.inception3a Inception(192, 64, 96, 128, 16, 32, 32)self.inception3b Inception(256, 128, 128, 192, 32, 96, 64)self.maxpool3 nn.MaxPool2d(kernel_size3, stride2, padding1)self.inception4a Inception(480, 192, 96, 208, 16, 48, 64)self.inception4b Inception(512, 160, 112, 224, 24, 64, 64)self.inception4c Inception(512, 128, 128, 256, 24, 64, 64)self.inception4d Inception(512, 112, 144, 288, 32, 64, 64)self.inception4e Inception(528, 256, 160, 320, 32, 128, 128)self.maxpool4 nn.MaxPool2d(kernel_size3, stride2, padding1)self.inception5a Inception(832, 256, 160, 320, 32, 128, 128)self.inception5b Inception(832, 384, 192, 384, 48, 128, 128)self.avgpool nn.AdaptiveAvgPool2d((1, 1))self.dropout nn.Dropout(0.4)self.fc nn.Linear(1024, num_classes)def forward(self, x):x self.prelayers(x)x self.maxpool2(x)x self.inception3a(x)x self.inception3b(x)x self.maxpool3(x)x self.inception4a(x)x self.inception4b(x)x self.inception4c(x)x self.inception4d(x)x self.inception4e(x)x self.maxpool4(x)x self.inception5a(x)x self.inception5b(x)x self.avgpool(x)x self.dropout(x)x x.view(x.size()[0], -1)x self.fc(x)return x代码详解
以下是对上述代码的详细解释这段Python代码使用PyTorch库构建了经典的GoogleNetInception v1网络结构用于图像分类任务以下从不同部分展开介绍
Inception 类
这个类定义了GoogleNet中的Inception模块它的作用是通过不同尺寸的卷积核等操作来并行提取特征然后将这些特征在通道维度上进行拼接。
初始化方法
参数说明 in_channels输入特征图的通道数即输入数据的深度维度。ch1x1、ch3x3reduc、ch3x3、ch5x5reduc、ch5x5、pool_proj分别对应不同分支中卷积操作涉及的通道数等参数用于配置每个分支的结构。 网络结构构建 self.branch1x1构建了一个包含1×1卷积、批归一化BatchNorm和ReLU激活函数的顺序结构。1×1卷积用于在不改变特征图尺寸的情况下调整通道数批归一化有助于加速训练和提高模型稳定性ReLU激活函数引入非线性变换。self.branch3x3先是一个1×1卷积进行通道数的降维减少计算量接着经过批归一化和ReLU激活然后是一个3×3卷积通过padding1保证特征图尺寸不变最后再接ReLU激活。self.branch5x5结构相对更复杂些先是1×1卷积和批归一化、ReLU激活然后连续两个3×3卷积都通过合适的padding保证尺寸不变中间穿插批归一化和ReLU激活用于提取更复杂的特征。self.branch_pool先进行最大池化MaxPool2d通过特定参数设置保证尺寸基本不变然后接1×1卷积来调整通道数再进行批归一化和ReLU激活。
前向传播 forward
接收输入张量x分别将其传入上述四个分支结构中得到四个分支的输出branch1x1、branch3x3、branch5x5、branch_pool。最后通过torch.cat函数沿着通道维度维度1即参数中的1将这四个分支的输出特征图拼接在一起作为整个Inception模块的输出。
GoogleNet 类
这是整个网络的主体类将多个Inception模块以及其他必要的层组合起来构建完整的GoogleNet架构。
初始化方法
参数说明 num_classes表示分类任务的类别数量用于最终全连接层输出对应数量的类别预测结果。 网络结构构建 self.prelayers由一系列的卷积、批归一化和ReLU激活函数组成的顺序结构用于对输入图像进行初步的特征提取逐步将输入的3通道对应RGB图像特征图转换为192通道的特征图。self.maxpool2一个最大池化层用于下采样减小特征图尺寸同时增大感受野步长为2按一定的padding设置来控制输出尺寸。接下来依次定义了多个Inception模块如self.inception3a、self.inception3b等它们的输入通道数和各分支的配置参数不同随着网络的深入逐渐提取更高级、更复杂的特征并且中间穿插了几个最大池化层self.maxpool3、self.maxpool4等进行下采样操作。self.avgpool自适应平均池化层将不同尺寸的特征图转换为固定大小这里是1×1的特征图方便后续的全连接层处理。self.dropout引入Dropout层概率设置为0.4在训练过程中随机丢弃部分神经元连接防止过拟合。self.fc全连接层将经过前面处理后的特征映射到指定的num_classes个类别上用于最终的分类预测。
前向传播 forward
首先将输入x传入self.prelayers进行初步特征提取然后经过self.maxpool2下采样。接着依次将特征图传入各个Inception模块并穿插经过最大池化层进行下采样不断提取和整合特征。经过最后的Inception模块后特征图通过self.avgpool进行平均池化再经过self.dropout进行随机失活处理然后通过x.view函数将特征图展平成一维向量方便全连接层处理最后传入self.fc全连接层得到最终的分类预测结果并返回。
训练过程和测试结果
训练过程损失函数变化曲线
训练过程准确率变化曲线
测试结果
代码汇总
项目github地址 项目结构
|--data
|--models|--__init__.py|--googlenet.py|--...
|--results
|--weights
|--train.py
|--test.pygooglenet.py
import torch
import torch.nn as nnclass Inception(nn.Module):def __init__(self, in_channels, ch1x1, ch3x3reduc, ch3x3, ch5x5reduc, ch5x5, pool_proj):super().__init__()self.branch1x1 nn.Sequential(nn.Conv2d(in_channels, ch1x1, kernel_size1),nn.BatchNorm2d(ch1x1),nn.ReLU(inplaceTrue))self.branch3x3 nn.Sequential(nn.Conv2d(in_channels, ch3x3reduc, kernel_size1),nn.BatchNorm2d(ch3x3reduc),nn.ReLU(inplaceTrue),nn.Conv2d(ch3x3reduc, ch3x3, kernel_size3, padding1),nn.ReLU(inplaceTrue))self.branch5x5 nn.Sequential(nn.Conv2d(in_channels, ch5x5reduc, kernel_size1),nn.BatchNorm2d(ch5x5reduc),nn.ReLU(inplaceTrue),nn.Conv2d(ch5x5reduc, ch5x5, kernel_size3, padding1),nn.BatchNorm2d(ch5x5),nn.ReLU(inplaceTrue),nn.Conv2d(ch5x5, ch5x5, kernel_size3, padding1),nn.BatchNorm2d(ch5x5),nn.ReLU(inplaceTrue))self.branch_pool nn.Sequential(nn.MaxPool2d(kernel_size3, stride1, padding1),nn.Conv2d(in_channels, pool_proj, kernel_size1),nn.BatchNorm2d(pool_proj),nn.ReLU(inplaceTrue))def forward(self, x):branch1x1 self.branch1x1(x)branch3x3 self.branch3x3(x)branch5x5 self.branch5x5(x)branch_pool self.branch_pool(x)return torch.cat([branch1x1, branch3x3, branch5x5, branch_pool], 1)class GoogleNet(nn.Module):def __init__(self, num_classes):super(GoogleNet, self).__init__()self.prelayers nn.Sequential(nn.Conv2d(3, 64, kernel_size3, padding1),nn.BatchNorm2d(64),nn.ReLU(inplaceTrue),nn.Conv2d(64, 64, kernel_size3, padding1),nn.BatchNorm2d(64),nn.ReLU(inplaceTrue),nn.Conv2d(64, 192, kernel_size3, padding1),nn.BatchNorm2d(192),nn.ReLU(inplaceTrue))self.maxpool2 nn.MaxPool2d(kernel_size3, stride2, padding1)self.inception3a Inception(192, 64, 96, 128, 16, 32, 32)self.inception3b Inception(256, 128, 128, 192, 32, 96, 64)self.maxpool3 nn.MaxPool2d(kernel_size3, stride2, padding1)self.inception4a Inception(480, 192, 96, 208, 16, 48, 64)self.inception4b Inception(512, 160, 112, 224, 24, 64, 64)self.inception4c Inception(512, 128, 128, 256, 24, 64, 64)self.inception4d Inception(512, 112, 144, 288, 32, 64, 64)self.inception4e Inception(528, 256, 160, 320, 32, 128, 128)self.maxpool4 nn.MaxPool2d(kernel_size3, stride2, padding1)self.inception5a Inception(832, 256, 160, 320, 32, 128, 128)self.inception5b Inception(832, 384, 192, 384, 48, 128, 128)self.avgpool nn.AdaptiveAvgPool2d((1, 1))self.dropout nn.Dropout(0.4)self.fc nn.Linear(1024, num_classes)def forward(self, x):x self.prelayers(x)x self.maxpool2(x)x self.inception3a(x)x self.inception3b(x)x self.maxpool3(x)x self.inception4a(x)x self.inception4b(x)x self.inception4c(x)x self.inception4d(x)x self.inception4e(x)x self.maxpool4(x)x self.inception5a(x)x self.inception5b(x)x self.avgpool(x)x self.dropout(x)x x.view(x.size()[0], -1)x self.fc(x)return xtrain.py
import torch
import torch.nn as nn
import torch.optim as optim
import torchvision
import torchvision.transforms as transforms
from models import *
import matplotlib.pyplot as pltimport ssl
ssl._create_default_https_context ssl._create_unverified_context# 定义数据预处理操作
transform transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.491, 0.482, 0.446), (0.247, 0.243, 0.261))])# 加载CIFAR10训练集
trainset torchvision.datasets.CIFAR10(root./data, trainTrue,downloadFalse, transformtransform)
trainloader torch.utils.data.DataLoader(trainset, batch_size128,shuffleTrue, num_workers2)# 定义设备GPU优先若可用
device torch.device(cuda if torch.cuda.is_available() else cpu)# 实例化模型
model_name GoogleNet
if model_name AlexNet:model AlexNet(num_classes10).to(device)
elif model_name Vgg_A:model Vgg(cfg_vggA, num_classes10).to(device)
elif model_name Vgg_A-LRN:model Vgg(cfg_vggA-LRN, num_classes10).to(device)
elif model_name Vgg_B:model Vgg(cfg_vggB, num_classes10).to(device)
elif model_name Vgg_C:model Vgg(cfg_vggC, num_classes10).to(device)
elif model_name Vgg_D:model Vgg(cfg_vggD, num_classes10).to(device)
elif model_name Vgg_E:model Vgg(cfg_vggE, num_classes10).to(device)
elif model_name GoogleNet:model GoogleNet(num_classes10).to(device)criterion nn.CrossEntropyLoss()
optimizer optim.Adam(model.parameters(), lr0.001)# 训练轮次
epochs 15def train(model, trainloader, criterion, optimizer, device):model.train()running_loss 0.0correct 0total 0for i, data in enumerate(trainloader, 0):inputs, labels data[0].to(device), data[1].to(device)optimizer.zero_grad()outputs model(inputs)loss criterion(outputs, labels)loss.backward()optimizer.step()running_loss loss.item()_, predicted outputs.max(1)total labels.size(0)correct predicted.eq(labels).sum().item()epoch_loss running_loss / len(trainloader)epoch_acc 100. * correct / totalreturn epoch_loss, epoch_accif __name__ __main__:loss_history, acc_history [], []for epoch in range(epochs):train_loss, train_acc train(model, trainloader, criterion, optimizer, device)print(fEpoch {epoch 1}: Train Loss: {train_loss:.4f}, Train Acc: {train_acc:.2f}%)loss_history.append(train_loss)acc_history.append(train_acc)# 保存模型权重每5轮次保存到weights文件夹下if (epoch 1) % 5 0:torch.save(model.state_dict(), fweights/{model_name}_epoch_{epoch 1}.pth)# 绘制损失曲线plt.plot(range(1, epochs1), loss_history, labelLoss, markero)plt.xlabel(Epoch)plt.ylabel(Loss)plt.title(Training Loss Curve)plt.legend()plt.savefig(fresults\\{model_name}_train_loss_curve.png)plt.close()# 绘制准确率曲线plt.plot(range(1, epochs1), acc_history, labelAccuracy, markero)plt.xlabel(Epoch)plt.ylabel(Accuracy (%))plt.title(Training Accuracy Curve)plt.legend()plt.savefig(fresults\\{model_name}_train_acc_curve.png)plt.close()test.py
import torch
import torch.nn as nn
import torchvision
import torchvision.transforms as transforms
from models import *import ssl
ssl._create_default_https_context ssl._create_unverified_context
# 定义数据预处理操作
transform transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.491, 0.482, 0.446), (0.247, 0.243, 0.261))])# 加载CIFAR10测试集
testset torchvision.datasets.CIFAR10(root./data, trainFalse,downloadFalse, transformtransform)
testloader torch.utils.data.DataLoader(testset, batch_size128,shuffleFalse, num_workers2)# 定义设备GPU优先若可用
device torch.device(cuda if torch.cuda.is_available() else cpu)# 实例化模型
model_name GoogleNet
if model_name AlexNet:model AlexNet(num_classes10).to(device)
elif model_name Vgg_A:model Vgg(cfg_vggA, num_classes10).to(device)
elif model_name Vgg_A-LRN:model Vgg(cfg_vggA-LRN, num_classes10).to(device)
elif model_name Vgg_B:model Vgg(cfg_vggB, num_classes10).to(device)
elif model_name Vgg_C:model Vgg(cfg_vggC, num_classes10).to(device)
elif model_name Vgg_D:model Vgg(cfg_vggD, num_classes10).to(device)
elif model_name Vgg_E:model Vgg(cfg_vggE, num_classes10).to(device)
elif model_name GoogleNet:model GoogleNet(num_classes10).to(device)criterion nn.CrossEntropyLoss()# 加载模型权重
weights_path fweights/{model_name}_epoch_15.pth
model.load_state_dict(torch.load(weights_path, map_locationdevice))def test(model, testloader, criterion, device):model.eval()running_loss 0.0correct 0total 0with torch.no_grad():for data in testloader:inputs, labels data[0].to(device), data[1].to(device)outputs model(inputs)loss criterion(outputs, labels)running_loss loss.item()_, predicted outputs.max(1)total labels.size(0)correct predicted.eq(labels).sum().item()epoch_loss running_loss / len(testloader)epoch_acc 100. * correct / totalreturn epoch_loss, epoch_accif __name__ __main__:test_loss, test_acc test(model, testloader, criterion, device)print(f{model_name} Test)print(fLoad Model Weights From: {weights_path})print(fTest Loss: {test_loss:.4f}, Test Acc: {test_acc:.2f}%)