网站的设计理念,专业网站制作需要多少钱,网站怎么添加友情链接,苏州建网站收费引言
在上一篇文章中#xff0c;我们详细介绍了ResNet与GoogLeNet的网络结构、设计理念及其在图像分类中的应用。本文将继续深入探讨如何在实际项目中应用这些模型#xff0c;特别是如何保存训练好的模型、加载模型以及使用模型进行新图像的预测。通过这些步骤#xff0c;读…引言
在上一篇文章中我们详细介绍了ResNet与GoogLeNet的网络结构、设计理念及其在图像分类中的应用。本文将继续深入探讨如何在实际项目中应用这些模型特别是如何保存训练好的模型、加载模型以及使用模型进行新图像的预测。通过这些步骤读者将能够完整地掌握从模型训练到部署的全过程。
ps:数据集已经发布
目录 ResNet简介 ResNet的网络结构 残差块 ResNet模型架构 GoogLeNet简介 GoogLeNet的网络结构 Inception模块 GoogLeNet模型架构 ResNet与GoogLeNet的对比 实际应用利用ResNet进行图像分类 数据准备与预处理 模型实例化与参数设置 模型训练与评估 模型保存与加载 新图像预测 完整代码实现详解 总结与展望 参考文献 ResNet简介
随着深度神经网络层数的增加模型的表达能力显著提升。然而网络越深训练过程中面临的梯度消失、梯度爆炸等问题也愈加严重导致模型性能难以进一步提升。2015年何凯明等人提出了残差网络ResNet通过引入“跳跃连接”Shortcut Connections有效缓解了深层网络训练中的退化问题使得训练超过百层的深度网络成为可能。ResNet在2015年的ImageNet图像识别挑战赛中取得了显著成绩极大地影响了后续深度神经网络的设计。 ResNet的网络结构
残差块
在传统的深层神经网络中随着网络深度的增加模型的训练误差往往呈现上升趋势这被称为“退化问题”。ResNet通过引入残差块Residual Block解决了这一问题。
这种结构被称为“跳跃连接”Shortcut Connection它允许梯度直接在网络中传播缓解了梯度消失的问题。基础残差块
输入 x|Conv3x3|BatchNorm|ReLU|Conv3x3|BatchNorm|-----| |x || |-----|ReLU|输出 H(x) F(x) x
瓶颈残差块
输入 x|Conv1x1|BatchNorm|ReLU|Conv3x3|BatchNorm|ReLU|Conv1x1|BatchNorm|-----| |x || |-----|ReLU|输出 H(x) F(x) x
ResNet模型架构
ResNet的整体架构由多个残差块堆叠而成不同的ResNet版本如ResNet-18、ResNet-34、ResNet-50、ResNet-101、ResNet-152主要区别在于残差块的类型及其数量。以ResNet-50为例其结构如下
图2ResNet-34架构图 来源
下图ResNet 的常见版本架构
GoogLeNet简介
GoogLeNet又称为Inception v1是Google在2014年提出的一种深度卷积神经网络模型。与ResNet不同GoogLeNet主要通过Inception模块的设计实现了网络结构的深度和宽度的有效扩展同时控制了计算复杂度。GoogLeNet在2014年的ImageNet挑战赛中取得了优异成绩显著降低了参数数量。
图3GoogLeNet架构图 来源
GoogLeNet的网络结构 Inception模块
Inception模块是GoogLeNet的核心创新通过在同一层次上并行应用不同尺寸的卷积核和池化操作捕捉多尺度的特征信息。具体来说一个Inception模块通常包括以下几部分 1x1卷积用于减少维度降低计算量。 3x3卷积处理空间信息。 5x5卷积处理更大范围的空间信息。 3x3最大池化用于下采样后接1x1卷积。
通过这些并行的操作Inception模块能够同时捕捉到不同尺度的特征提高了模型的表达能力。
GoogLeNet模型架构
图4Inception模块示意图 来源
ResNet与GoogLeNet的对比
特性ResNetGoogLeNet核心创新残差学习Residual LearningInception模块网络深度可扩展至超过100层22层后续版本如Inception v2、v3更深参数数量随层数增加显著通过Inception模块有效控制参数数量训练难度残差块设计缓解深层网络的训练难题多路径结构复杂需精心设计和训练应用场景图像分类、目标检测、语义分割等多种任务主要用于图像分类后续版本扩展至其他任务计算效率残差块结构相对简单计算效率高Inception模块复杂但通过1x1卷积降低计算量
实际应用利用ResNet进行图像分类
本文将以ResNet-18为例演示如何在PyTorch框架下构建、训练和评估一个图像分类模型。以鲜花种类识别为案例读者可以通过本文的步骤掌握从数据准备到模型训练、保存、加载及预测的完整流程。
数据准备与预处理
首先确保已下载并整理好鲜花数据集。数据集通常分为训练集和测试集分别存放在不同的文件夹中。为了适应ResNet-18的输入要求需要将图像尺寸调整为224x224。 from torchvision import transforms
from torch.utils.data import DataLoader
from torchvision.datasets import ImageFolder
# 指定批次大小
batch_size 16
# 指定数据集路径
flower_train_path ./dataset/flower_datas/train/
flower_test_path ./dataset/flower_datas/val/
# 数据预处理调整图像大小并转换为Tensor
dataset_transform transforms.Compose([transforms.Resize((224, 224)), # 调整图像大小为224x224transforms.ToTensor() # 将图像转换为Tensor
])
# 加载训练集和测试集
flower_train ImageFolder(flower_train_path, transformdataset_transform)
flower_test ImageFolder(flower_test_path, transformdataset_transform)
# 创建数据加载器
train_loader DataLoader(datasetflower_train, batch_sizebatch_size, shuffleTrue)
test_loader DataLoader(datasetflower_test, batch_sizebatch_size, shuffleFalse) 说明 使用transforms.Resize将图像调整为224x224以匹配ResNet的输入要求。 使用ImageFolder加载数据集确保数据集目录结构符合PyTorch的要求每个类别一个文件夹。 使用DataLoader创建训练和测试数据加载器设置批次大小和是否打乱数据。
模型实例化与参数设置
使用PyTorch内置的ResNet-18模型并根据任务需要调整输出类别数。 import torch
import torchvision.models as models
# 实例化ResNet-18模型调整输出类别数为5
model models.resnet18(num_classes5)
# 设置训练设备为GPU如果可用否则为CPU
device torch.device(cuda if torch.cuda.is_available() else cpu)
model model.to(device)
# 定义优化器Adam和损失函数交叉熵损失
learning_rate 1e-3
num_epochs 25
optimizer torch.optim.Adam(model.parameters(), lrlearning_rate)
loss_fn torch.nn.CrossEntropyLoss() 说明 models.resnet18(num_classes5)加载ResNet-18模型并将最后的全连接层调整为输出5个类别。 device自动检测是否有GPU可用并将模型移动到对应设备以加速训练。 optimizer选择Adam优化器并设置学习率。 loss_fn使用交叉熵损失函数适用于多分类任务。
模型训练与评估
定义训练和评估函数逐步训练模型并监控其性能。 import matplotlib.pyplot as plt
# 评估模型准确率
def evaluate_accuracy(data_iter, model):model.eval() # 设置模型为评估模式correct 0total 0with torch.no_grad(): # 不计算梯度for images, labels in data_iter:images, labels images.to(device), labels.to(device)outputs model(images)_, predicted torch.max(outputs.data, 1)total labels.size(0)correct (predicted labels).sum().item()return correct / total
# 训练模型
def train_model(model, train_loader, test_loader, optimizer, loss_fn, num_epochs):train_losses []train_accuracies []test_accuracies []for epoch in range(num_epochs):model.train() # 设置模型为训练模式running_loss 0.0correct 0total 0for images, labels in train_loader:images, labels images.to(device), labels.to(device)# 前向传播outputs model(images)loss loss_fn(outputs, labels)# 反向传播和优化optimizer.zero_grad() # 清除之前的梯度loss.backward() # 反向传播计算梯度optimizer.step() # 更新参数# 统计损失和准确率running_loss loss.item()_, predicted torch.max(outputs.data, 1)total labels.size(0)correct (predicted labels).sum().item()# 计算平均损失和准确率epoch_loss running_loss / len(train_loader)epoch_acc correct / totaltest_acc evaluate_accuracy(test_loader, model)train_losses.append(epoch_loss)train_accuracies.append(epoch_acc)test_accuracies.append(test_acc)print(fEpoch [{epoch1}/{num_epochs}], Loss: {epoch_loss:.4f}, fTrain Acc: {epoch_acc:.3f}, Test Acc: {test_acc:.3f})print(训练完成)# 绘制损失和准确率曲线epochs range(1, num_epochs1)plt.figure(figsize(12,5))# 绘制训练损失曲线plt.subplot(1,2,1)plt.plot(epochs, train_losses, r, label训练损失)plt.xlabel(Epoch)plt.ylabel(Loss)plt.title(训练损失曲线)plt.legend()# 绘制训练和测试准确率曲线plt.subplot(1,2,2)plt.plot(epochs, train_accuracies, g, label训练准确率)plt.plot(epochs, test_accuracies, b, label测试准确率)plt.xlabel(Epoch)plt.ylabel(Accuracy)plt.title(准确率曲线)plt.legend()plt.show() 说明 evaluate_accuracy函数用于评估模型在测试集上的准确率设置模型为评估模式避免梯度计算。 train_model函数负责整个训练过程包括前向传播、计算损失、反向传播、优化参数以及记录和绘制损失与准确率曲线。 在每个epoch结束后输出当前epoch的损失、训练准确率和测试准确率。
输出
模型保存与加载
在完成模型训练后保存训练好的模型是非常重要的步骤。保存模型不仅可以避免重复训练还可以在需要时加载模型进行预测或进一步训练。
1. 保存模型
使用PyTorch的torch.save函数可以方便地保存模型的参数state_dict或整个模型。
# 保存模型参数torch.save(model.state_dict(), resnet18_flower.pth)
print(模型已保存为 resnet18_flower.pth) 说明 model.state_dict()获取模型的所有参数。 torch.save将参数保存到指定路径。 推荐保存模型的参数而不是整个模型因为保存参数更加灵活适用于不同的应用场景。
2. 加载模型
在需要使用保存的模型时可以通过加载模型参数来恢复模型。 # 实例化模型结构
model_loaded models.resnet18(num_classes5)
# 加载模型参数
model_loaded.load_state_dict(torch.load(resnet18_flower.pth))
# 设置模型为评估模式
model_loaded.eval()
# 将模型移动到对应设备
model_loaded model_loaded.to(device)
print(模型已加载并准备就绪) 说明 实例化与保存时相同结构的模型。 使用load_state_dict加载保存的参数。 设置模型为评估模式避免在推理时启用训练模式的行为如Dropout。 将模型移动到相应设备GPU或CPU。
新图像预测
完成模型的加载后可以使用模型对新图像进行预测。以下步骤展示了如何加载新图像、进行预处理、并使用模型进行预测。 from PIL import Image
import numpy as np
# 定义类别标签根据实际数据集调整
class_names [daisy, dandelion, roses, sunflowers, tulips]
# 图像预处理函数
def preprocess_image(image_path):# 定义与训练时相同的预处理步骤transform transforms.Compose([transforms.Resize((224, 224)),transforms.ToTensor()])# 打开图像image Image.open(image_path).convert(RGB)# 应用预处理image transform(image)# 增加批次维度image image.unsqueeze(0)return image
# 预测函数
def predict(image_path, model, class_names):# 预处理图像image preprocess_image(image_path)image image.to(device)# 进行预测model.eval()with torch.no_grad():outputs model(image)_, predicted torch.max(outputs.data, 1)# 获取预测结果predicted_class class_names[predicted.item()]return predicted_class
# 示例预测新图像
new_image_path ./dataset/flower_datas/test/daisy/daisy_001.jpg # 替换为实际图像路径
predicted_label predict(new_image_path, model_loaded, class_names)
print(f预测结果{predicted_label}) 说明 preprocess_image函数加载并预处理新图像使其符合模型输入要求。 predict函数加载预处理后的图像使用模型进行前向传播获取预测结果。 class_names根据实际数据集定义类别标签。 示例中替换new_image_path为实际需要预测的图像路径。
完整代码实现详解
以下是完整的代码实现包括数据准备、模型定义、训练、保存、加载及新图像预测。代码中包含详细注释帮助您理解每一步的具体操作。 # 导入相关的工具包
import torch
import torchvision.models as models
from torchvision import transforms
from torch.utils.data import DataLoader
from torchvision.datasets import ImageFolder
import matplotlib.pyplot as plt
from PIL import Image
import numpy as np
# 指定批次大小
batch_size 16
# 指定数据集路径
flower_train_path ./dataset/flower_datas/train/
flower_test_path ./dataset/flower_datas/val/
# 数据预处理调整图像大小并转换为Tensor
dataset_transform transforms.Compose([transforms.Resize((224, 224)), # 调整图像大小为224x224transforms.ToTensor() # 将图像转换为Tensor
])
# 加载训练集和测试集
flower_train ImageFolder(flower_train_path, transformdataset_transform)
flower_test ImageFolder(flower_test_path, transformdataset_transform)
# 创建数据加载器
train_loader DataLoader(datasetflower_train, batch_sizebatch_size, shuffleTrue)
test_loader DataLoader(datasetflower_test, batch_sizebatch_size, shuffleFalse)
# 实例化ResNet-18模型调整输出类别数为5
model models.resnet18(num_classes5)
# 设置训练设备为GPU如果可用否则为CPU
device torch.device(cuda if torch.cuda.is_available() else cpu)
model model.to(device)
# 定义优化器Adam和损失函数交叉熵损失
learning_rate 1e-3
num_epochs 25
optimizer torch.optim.Adam(model.parameters(), lrlearning_rate)
loss_fn torch.nn.CrossEntropyLoss()
# 评估模型准确率
def evaluate_accuracy(data_iter, model):model.eval() # 设置模型为评估模式correct 0total 0with torch.no_grad(): # 不计算梯度for images, labels in data_iter:images, labels images.to(device), labels.to(device)outputs model(images)_, predicted torch.max(outputs.data, 1)total labels.size(0)correct (predicted labels).sum().item()return correct / total
# 训练模型
def train_model(model, train_loader, test_loader, optimizer, loss_fn, num_epochs):train_losses []train_accuracies []test_accuracies []for epoch in range(num_epochs):model.train() # 设置模型为训练模式running_loss 0.0correct 0total 0for images, labels in train_loader:images, labels images.to(device), labels.to(device)# 前向传播outputs model(images)loss loss_fn(outputs, labels)# 反向传播和优化optimizer.zero_grad() # 清除之前的梯度loss.backward() # 反向传播计算梯度optimizer.step() # 更新参数# 统计损失和准确率running_loss loss.item()_, predicted torch.max(outputs.data, 1)total labels.size(0)correct (predicted labels).sum().item()# 计算平均损失和准确率epoch_loss running_loss / len(train_loader)epoch_acc correct / totaltest_acc evaluate_accuracy(test_loader, model)train_losses.append(epoch_loss)train_accuracies.append(epoch_acc)test_accuracies.append(test_acc)print(fEpoch [{epoch1}/{num_epochs}], Loss: {epoch_loss:.4f}, fTrain Acc: {epoch_acc:.3f}, Test Acc: {test_acc:.3f})print(训练完成)# 绘制损失和准确率曲线epochs range(1, num_epochs1)plt.figure(figsize(12,5))# 绘制训练损失曲线plt.subplot(1,2,1)plt.plot(epochs, train_losses, r, label训练损失)plt.xlabel(Epoch)plt.ylabel(Loss)plt.title(训练损失曲线)plt.legend()# 绘制训练和测试准确率曲线plt.subplot(1,2,2)plt.plot(epochs, train_accuracies, g, label训练准确率)plt.plot(epochs, test_accuracies, b, label测试准确率)plt.xlabel(Epoch)plt.ylabel(Accuracy)plt.title(准确率曲线)plt.legend()plt.show()
# 保存模型参数
def save_model(model, pathresnet18_flower.pth):torch.save(model.state_dict(), path)print(f模型已保存为 {path})
# 加载模型参数
def load_model(pathresnet18_flower.pth):model_loaded models.resnet18(num_classes5)model_loaded.load_state_dict(torch.load(path))model_loaded model_loaded.to(device)model_loaded.eval()print(模型已加载并准备就绪)return model_loaded
# 图像预处理函数
def preprocess_image(image_path):# 定义与训练时相同的预处理步骤transform transforms.Compose([transforms.Resize((224, 224)),transforms.ToTensor()])# 打开图像image Image.open(image_path).convert(RGB)# 应用预处理image transform(image)# 增加批次维度image image.unsqueeze(0)return image
# 预测函数
def predict(image_path, model, class_names):# 预处理图像image preprocess_image(image_path)image image.to(device)# 进行预测model.eval()with torch.no_grad():outputs model(image)_, predicted torch.max(outputs.data, 1)# 获取预测结果predicted_class class_names[predicted.item()]return predicted_class
# 定义类别标签根据实际数据集调整
class_names [daisy, dandelion, roses, sunflowers, tulips]
# 开始训练
train_model(model, train_loader, test_loader, optimizer, loss_fn, num_epochs)
# 保存训练好的模型
save_model(model, resnet18_flower.pth)
# 加载保存的模型
model_loaded load_model(resnet18_flower.pth)
# 示例预测新图像
new_image_path ./dataset/flower_datas/test/daisy/daisy_001.jpg # 替换为实际图像路径
predicted_label predict(new_image_path, model_loaded, class_names)
print(f预测结果{predicted_label}) 代码注释详解 数据准备 使用transforms.Resize将图像调整为224x224以匹配ResNet的输入要求。 使用ImageFolder加载数据集确保每个类别的图像存放在单独的文件夹中。 使用DataLoader创建训练和测试数据加载器设置批次大小和是否打乱数据。 模型实例化与参数设置 使用models.resnet18加载ResNet-18模型并将最后的全连接层调整为5个输出类别。 检测是否有GPU可用并将模型移动到对应设备以加速训练。 定义优化器Adam和损失函数交叉熵损失设置学习率和训练轮数。 训练与评估 定义evaluate_accuracy函数用于在测试集上评估模型的准确率设置模型为评估模式避免梯度计算。 定义 train_model 函数包含整个训练过程 设置模型为训练模式。 遍历每个epoch和每个batch进行前向传播、计算损失、反向传播和优化参数。 记录每个epoch的损失和准确率。 在每个epoch结束后评估模型在测试集上的准确率。 绘制训练损失和准确率曲线直观展示模型的训练过程。 模型保存与加载 定义save_model函数使用torch.save将模型的参数保存到指定路径。 定义load_model函数实例化相同结构的模型并使用load_state_dict加载保存的参数。设置模型为评估模式并移动到对应设备。 新图像预测 定义preprocess_image函数加载并预处理新图像使其符合模型输入要求。 定义predict函数加载预处理后的图像使用模型进行前向传播获取预测结果。 示例中替换new_image_path为实际需要预测的图像路径打印预测结果。
完整流程说明 数据准备加载并预处理数据集包括图像尺寸调整和格式转换。 模型定义与参数设置实例化ResNet-18模型定义优化器和损失函数并将模型移动到训练设备。 模型训练与评估通过训练函数迭代训练模型并在每个epoch后评估模型性能。 模型保存训练完成后使用torch.save保存模型的参数。 模型加载在需要使用模型时实例化相同结构的模型并加载保存的参数。 新图像预测加载并预处理新图像使用加载的模型进行预测输出预测结果。
示例运行结果
训练过程的输出如下
Epoch [1/25], Loss: 1.3775, Train Acc: 0.442, Test Acc: 0.516
Epoch [2/25], Loss: 1.1998, Train Acc: 0.528, Test Acc: 0.552
...
Epoch [25/25], Loss: 0.7376, Train Acc: 0.730, Test Acc: 0.684
训练完成
模型已保存为 resnet18_flower.pth
模型已加载并准备就绪
预测结果daisy 通过绘制的损失和准确率曲线可以直观地观察模型的训练过程和性能提升情况。
总结与展望
本文详细介绍了ResNet与GoogLeNet两种经典深度卷积神经网络的结构与设计理念并通过实际案例演示了如何在PyTorch框架下应用ResNet进行图像分类任务。特别是通过增加模型保存、加载和新图像预测的步骤展示了完整的从训练到部署的流程。
关键总结 ResNet通过引入残差块有效解决了深层网络的训练难题使得训练超过100层的深度网络成为可能。 GoogLeNet通过Inception模块实现了网络深度和宽度的有效扩展同时控制了计算复杂度适用于计算资源有限的场景。 实际应用中选择适当的网络结构和参数设置对于提升模型性能至关重要。 模型的保存与加载是深度学习项目中重要的步骤确保训练成果能够被复用和部署。
未来展望
随着深度学习技术的不断发展更多高效的网络架构不断涌现如DenseNet、EfficientNet等。结合更先进的优化算法和硬件加速技术深度神经网络将在计算机视觉、自然语言处理等领域发挥更大的作用。此外模型压缩与加速技术的发展也将推动深度学习模型在移动设备和边缘计算中的广泛应用。
参考文献 He, K., Zhang, X., Ren, S., Sun, J. (2016). Deep Residual Learning for Image Recognition. arXiv preprint arXiv:1512.03385. Szegedy, C., Liu, W., Jia, Y., Sermanet, P., Reed, S., Anguelov, D., ... Rabinovich, A. (2015). Going deeper with convolutions. Proceedings of the IEEE conference on computer vision and pattern recognition. He, K., Zhang, X., Ren, S., Sun, J. (2016). Identity Mappings in Deep Residual Networks. European Conference on Computer Vision (ECCV). Ioffe, S., Szegedy, C. (2015). Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift. International Conference on Machine Learning (ICML). 本文内容结合了公开的学术论文与实践经验旨在为读者提供清晰、系统的ResNet与GoogLeNet解析。如有任何问题或建议欢迎在评论区交流讨论。