GoolgeNet实战

📅 2026/7/8 13:47:20
GoolgeNet实战
1.GoolgeNet代码分析1.1Inception模块class Inception(nn.Module): def __init__(self, in_channels, c1, c2, c3, c4): super(Inception, self).__init__() self.ReLU nn.ReLU() # 路线1单1×1卷积层 self.p1_1 nn.Conv2d(in_channelsin_channels, out_channelsc1, kernel_size1) # 路线21×1卷积层, 3×3的卷积 self.p2_1 nn.Conv2d(in_channelsin_channels, out_channelsc2[0], kernel_size1) self.p2_2 nn.Conv2d(in_channelsc2[0], out_channelsc2[1], kernel_size3, padding1) # 路线31×1卷积层, 5×5的卷积 self.p3_1 nn.Conv2d(in_channelsin_channels, out_channelsc3[0], kernel_size1) self.p3_2 nn.Conv2d(in_channelsc3[0], out_channelsc3[1], kernel_size5, padding2) # 路线43×3的最大池化, 1×1的卷积 self.p4_1 nn.MaxPool2d(kernel_size3, padding1, stride1) self.p4_2 nn.Conv2d(in_channelsin_channels, out_channelsc4, kernel_size1) def forward(self, x): p1 self.ReLU(self.p1_1(x)) p2 self.ReLU(self.p2_2(self.ReLU(self.p2_1(x)))) p3 self.ReLU(self.p3_2(self.ReLU(self.p3_1(x)))) p4 self.ReLU(self.p4_2(self.p4_1(x))) return torch.cat((p1, p2, p3, p4), dim1)这里Inception模块包含四条并行路径路径11×1卷积 (降维)路径21×1卷积 → 3×3卷积 (提取中等特征)路径31×1卷积 → 5×5卷积 (提取大范围特征)路径43×3最大池化 → 1×1卷积 (保留空间信息)1.2GoogLeNet主体结构class GoogLeNet(nn.Module): def __init__(self, Inception): super(GoogLeNet, self).__init__() self.b1 nn.Sequential( nn.Conv2d(in_channels1, out_channels64, kernel_size7, stride2, padding3), nn.ReLU(), nn.MaxPool2d(kernel_size3, stride2, padding1)) self.b2 nn.Sequential( nn.Conv2d(in_channels64, out_channels64, kernel_size1), nn.ReLU(), nn.Conv2d(in_channels64, out_channels192, kernel_size3, padding1), nn.ReLU(), nn.MaxPool2d(kernel_size3, stride2, padding1)) self.b3 nn.Sequential( Inception(192, 64, (96, 128), (16, 32), 32), Inception(256, 128, (128, 192), (32, 96), 64), nn.MaxPool2d(kernel_size3, stride2, padding1)) self.b4 nn.Sequential( Inception(480, 192, (96, 208), (16, 48), 64), Inception(512, 160, (112, 224), (24, 64), 64), Inception(512, 128, (128, 256), (24, 64), 64), Inception(512, 112, (128, 288), (32, 64), 64), Inception(528, 256, (160, 320), (32, 128), 128), nn.MaxPool2d(kernel_size3, stride2, padding1)) self.b5 nn.Sequential( Inception(832, 256, (160, 320), (32, 128), 128), Inception(832, 384, (192, 384), (48, 128), 128), nn.AdaptiveAvgPool2d((1, 1)), nn.Flatten(), nn.Linear(1024, 10)) for m in self.modules(): if isinstance(m, nn.Conv2d): nn.init.kaiming_normal_(m.weight, modefan_out, nonlinearityrelu) if m.bias is not None: nn.init.constant_(m.bias, 0) elif isinstance(m, nn.Linear): nn.init.normal_(m.weight, 0, 0.01) if m.bias is not None: nn.init.constant_(m.bias, 0) def forward(self, x): x self.b1(x) x self.b2(x) x self.b3(x) x self.b4(x) x self.b5(x) return x其中这段是网络的参数初始化代码for m in self.modules(): if isinstance(m, nn.Conv2d): nn.init.kaiming_normal_(m.weight, modefan_out, nonlinearityrelu) if m.bias is not None: nn.init.constant_(m.bias, 0) elif isinstance(m, nn.Linear): nn.init.normal_(m.weight, 0, 0.01) if m.bias is not None: nn.init.constant_(m.bias, 0)这段代码就是遍历所有模块判断是卷积层还是全连接层然后进行相应的操作。代码保证了卷积层使用适合ReLU的Kaiming初始化所有偏置置于0全连接层使用小标准差的正态分布初始化。2.代码#model import torch from torch import nn from torchsummary import summary class Inception(nn.Module): def __init__(self, in_channels, c1, c2, c3, c4): super(Inception, self).__init__() self.ReLU nn.ReLU() # 路线1单1×1卷积层 self.p1_1 nn.Conv2d(in_channelsin_channels, out_channelsc1, kernel_size1) # 路线21×1卷积层, 3×3的卷积 self.p2_1 nn.Conv2d(in_channelsin_channels, out_channelsc2[0], kernel_size1) self.p2_2 nn.Conv2d(in_channelsc2[0], out_channelsc2[1], kernel_size3, padding1) # 路线31×1卷积层, 5×5的卷积 self.p3_1 nn.Conv2d(in_channelsin_channels, out_channelsc3[0], kernel_size1) self.p3_2 nn.Conv2d(in_channelsc3[0], out_channelsc3[1], kernel_size5, padding2) # 路线43×3的最大池化, 1×1的卷积 self.p4_1 nn.MaxPool2d(kernel_size3, padding1, stride1) self.p4_2 nn.Conv2d(in_channelsin_channels, out_channelsc4, kernel_size1) def forward(self, x): p1 self.ReLU(self.p1_1(x)) p2 self.ReLU(self.p2_2(self.ReLU(self.p2_1(x)))) p3 self.ReLU(self.p3_2(self.ReLU(self.p3_1(x)))) p4 self.ReLU(self.p4_2(self.p4_1(x))) return torch.cat((p1, p2, p3, p4), dim1) class GoogLeNet(nn.Module): def __init__(self, Inception): super(GoogLeNet, self).__init__() self.b1 nn.Sequential( nn.Conv2d(in_channels1, out_channels64, kernel_size7, stride2, padding3), nn.ReLU(), nn.MaxPool2d(kernel_size3, stride2, padding1)) self.b2 nn.Sequential( nn.Conv2d(in_channels64, out_channels64, kernel_size1), nn.ReLU(), nn.Conv2d(in_channels64, out_channels192, kernel_size3, padding1), nn.ReLU(), nn.MaxPool2d(kernel_size3, stride2, padding1)) self.b3 nn.Sequential( Inception(192, 64, (96, 128), (16, 32), 32), Inception(256, 128, (128, 192), (32, 96), 64), nn.MaxPool2d(kernel_size3, stride2, padding1)) self.b4 nn.Sequential( Inception(480, 192, (96, 208), (16, 48), 64), Inception(512, 160, (112, 224), (24, 64), 64), Inception(512, 128, (128, 256), (24, 64), 64), Inception(512, 112, (128, 288), (32, 64), 64), Inception(528, 256, (160, 320), (32, 128), 128), nn.MaxPool2d(kernel_size3, stride2, padding1)) self.b5 nn.Sequential( Inception(832, 256, (160, 320), (32, 128), 128), Inception(832, 384, (192, 384), (48, 128), 128), nn.AdaptiveAvgPool2d((1, 1)), nn.Flatten(), nn.Linear(1024, 10)) for m in self.modules(): if isinstance(m, nn.Conv2d): nn.init.kaiming_normal_(m.weight, modefan_out, nonlinearityrelu) if m.bias is not None: nn.init.constant_(m.bias, 0) elif isinstance(m, nn.Linear): nn.init.normal_(m.weight, 0, 0.01) if m.bias is not None: nn.init.constant_(m.bias, 0) def forward(self, x): x self.b1(x) x self.b2(x) x self.b3(x) x self.b4(x) x self.b5(x) return x if __name__ __main__: device torch.device(cuda if torch.cuda.is_available() else cpu) model GoogLeNet(Inception).to(device) print(summary(model, (1, 224, 224)))#model-train import copy import time import torch from torchvision.datasets import FashionMNIST from torchvision import transforms import torch.utils.data as Data import numpy as np import matplotlib.pyplot as plt from model import GoogLeNet, Inception import torch.nn as nn import pandas as pd def train_val_data_process(): train_data FashionMNIST(root./data, trainTrue, transformtransforms.Compose([transforms.Resize(size224), transforms.ToTensor()]), downloadTrue) train_data, val_data Data.random_split(train_data, [round(0.8*len(train_data)), round(0.2*len(train_data))]) train_dataloader Data.DataLoader(datasettrain_data, batch_size32, shuffleTrue, num_workers2) val_dataloader Data.DataLoader(datasetval_data, batch_size32, shuffleTrue, num_workers2) return train_dataloader, val_dataloader def train_model_process(model, train_dataloader, val_dataloader, num_epochs): # 设定训练所用到的设备有GPU用GPU没有GPU用CPU device torch.device(cuda if torch.cuda.is_available() else cpu) # 使用Adam优化器学习率为0.001 optimizer torch.optim.Adam(model.parameters(), lr0.001) # 损失函数为交叉熵函数 criterion nn.CrossEntropyLoss() # 将模型放入到训练设备中 model model.to(device) # 复制当前模型的参数 best_model_wts copy.deepcopy(model.state_dict()) # 初始化参数 # 最高准确度 best_acc 0.0 # 训练集损失列表 train_loss_all [] # 验证集损失列表 val_loss_all [] # 训练集准确度列表 train_acc_all [] # 验证集准确度列表 val_acc_all [] # 当前时间 since time.time() for epoch in range(num_epochs): print(Epoch {}/{}.format(epoch, num_epochs-1)) print(-*10) # 初始化参数 # 训练集损失函数 train_loss 0.0 # 训练集准确度 train_corrects 0 # 验证集损失函数 val_loss 0.0 # 验证集准确度 val_corrects 0 # 训练集样本数量 train_num 0 # 验证集样本数量 val_num 0 # 对每一个mini-batch训练和计算 for step, (b_x, b_y) in enumerate(train_dataloader): # 将特征放入到训练设备中 b_x b_x.to(device) # 将标签放入到训练设备中 b_y b_y.to(device) # 设置模型为训练模式 model.train() # 前向传播过程输入为一个batch输出为一个batch中对应的预测 output model(b_x) # 查找每一行中最大值对应的行标 pre_lab torch.argmax(output, dim1) # 计算每一个batch的损失函数 loss criterion(output, b_y) # 将梯度初始化为0 optimizer.zero_grad() # 反向传播计算 loss.backward() # 根据网络反向传播的梯度信息来更新网络的参数以起到降低loss函数计算值的作用 optimizer.step() # 对损失函数进行累加 train_loss loss.item() * b_x.size(0) # 如果预测正确则准确度train_corrects加1 train_corrects torch.sum(pre_lab b_y.data) # 当前用于训练的样本数量 train_num b_x.size(0) for step, (b_x, b_y) in enumerate(val_dataloader): # 将特征放入到验证设备中 b_x b_x.to(device) # 将标签放入到验证设备中 b_y b_y.to(device) # 设置模型为评估模式 model.eval() # 前向传播过程输入为一个batch输出为一个batch中对应的预测 output model(b_x) # 查找每一行中最大值对应的行标 pre_lab torch.argmax(output, dim1) # 计算每一个batch的损失函数 loss criterion(output, b_y) # 对损失函数进行累加 val_loss loss.item() * b_x.size(0) # 如果预测正确则准确度train_corrects加1 val_corrects torch.sum(pre_lab b_y.data) # 当前用于验证的样本数量 val_num b_x.size(0) # 计算并保存每一次迭代的loss值和准确率 # 计算并保存训练集的loss值 train_loss_all.append(train_loss / train_num) # 计算并保存训练集的准确率 train_acc_all.append(train_corrects.double().item() / train_num) # 计算并保存验证集的loss值 val_loss_all.append(val_loss / val_num) # 计算并保存验证集的准确率 val_acc_all.append(val_corrects.double().item() / val_num) print({} train loss:{:.4f} train acc: {:.4f}.format(epoch, train_loss_all[-1], train_acc_all[-1])) print({} val loss:{:.4f} val acc: {:.4f}.format(epoch, val_loss_all[-1], val_acc_all[-1])) if val_acc_all[-1] best_acc: # 保存当前最高准确度 best_acc val_acc_all[-1] # 保存当前最高准确度的模型参数 best_model_wts copy.deepcopy(model.state_dict()) # 计算训练和验证的耗时 time_use time.time() - since print(训练和验证耗费的时间{:.0f}m{:.0f}s.format(time_use//60, time_use%60)) # 选择最优参数保存最优参数的模型 model.load_state_dict(best_model_wts) # torch.save(model.load_state_dict(best_model_wts), C:/Users/86159/Desktop/LeNet/best_model.pth) torch.save(best_model_wts, C:/Users/12072/Desktop/TEST/GoogLeNet/best_model.pth) train_process pd.DataFrame(data{epoch:range(num_epochs), train_loss_all:train_loss_all, val_loss_all:val_loss_all, train_acc_all:train_acc_all, val_acc_all:val_acc_all,}) return train_process def matplot_acc_loss(train_process): # 显示每一次迭代后的训练集和验证集的损失函数和准确率 plt.figure(figsize(12, 4)) plt.subplot(1, 2, 1) plt.plot(train_process[epoch], train_process.train_loss_all, ro-, labelTrain loss) plt.plot(train_process[epoch], train_process.val_loss_all, bs-, labelVal loss) plt.legend() plt.xlabel(epoch) plt.ylabel(Loss) plt.subplot(1, 2, 2) plt.plot(train_process[epoch], train_process.train_acc_all, ro-, labelTrain acc) plt.plot(train_process[epoch], train_process.val_acc_all, bs-, labelVal acc) plt.xlabel(epoch) plt.ylabel(acc) plt.legend() plt.show() if __name__ __main__: # 加载需要的模型 GoogLeNet GoogLeNet(Inception) # 加载数据集 train_data, val_data train_val_data_process() # 利用现有的模型进行模型的训练 train_process train_model_process(GoogLeNet, train_data, val_data, num_epochs20) matplot_acc_loss(train_process)#model-test import torch import torch.utils.data as Data from torchvision import transforms from torchvision.datasets import FashionMNIST from model import GoogLeNet, Inception def test_data_process(): test_data FashionMNIST(root./data, trainFalse, transformtransforms.Compose([transforms.Resize(size224), transforms.ToTensor()]), downloadTrue) test_dataloader Data.DataLoader(datasettest_data, batch_size1, shuffleTrue, num_workers0) return test_dataloader def test_model_process(model, test_dataloader): # 设定测试所用到的设备有GPU用GPU没有GPU用CPU device cuda if torch.cuda.is_available() else cpu # 讲模型放入到训练设备中 model model.to(device) # 初始化参数 test_corrects 0.0 test_num 0 # 只进行前向传播计算不计算梯度从而节省内存加快运行速度 with torch.no_grad(): for test_data_x, test_data_y in test_dataloader: # 将特征放入到测试设备中 test_data_x test_data_x.to(device) # 将标签放入到测试设备中 test_data_y test_data_y.to(device) # 设置模型为评估模式 model.eval() # 前向传播过程输入为测试数据集输出为对每个样本的预测值 output model(test_data_x) # 查找每一行中最大值对应的行标 pre_lab torch.argmax(output, dim1) # 如果预测正确则准确度test_corrects加1 test_corrects torch.sum(pre_lab test_data_y.data) # 将所有的测试样本进行累加 test_num test_data_x.size(0) # 计算测试准确率 test_acc test_corrects.double().item() / test_num print(测试的准确率为, test_acc) if __name__ __main__: # 加载模型 model GoogLeNet(Inception) model.load_state_dict(torch.load(best_model.pth)) # # 利用现有的模型进行模型的测试 test_dataloader test_data_process() test_model_process(model, test_dataloader) # 设定测试所用到的设备有GPU用GPU没有GPU用CPU device cuda if torch.cuda.is_available() else cpu model model.to(device) classes [T-shirt/top, Trouser, Pullover, Dress, Coat, Sandal, Shirt, Sneaker, Bag, Ankle boot] with torch.no_grad(): for b_x, b_y in test_dataloader: b_x b_x.to(device) b_y b_y.to(device) # 设置模型为验证模型 model.eval() output model(b_x) pre_lab torch.argmax(output, dim1) result pre_lab.item() label b_y.item() print(预测值, classes[result], ------, 真实值, classes[label])3.结果展示model-train运行结果model-test运行结果