深度学习基础——残差神经网络(ResNet)

news/2024/11/14 7:00:15/

深度学习基础——残差神经网络(ResNet)

1. 定义

残差神经网络(ResNet)是一种深度神经网络结构,由微软研究院的Kaiming He等人于2015年提出。它通过引入残差块(Residual Block)来解决深度神经网络的退化问题,使得网络可以更深地进行训练。ResNet在ImageNet图像识别挑战赛上取得了第一名的成绩,并在许多领域取得了显著的成功应用。

2. 如何计算

ResNet的核心思想是引入残差连接(Residual Connection)。传统的神经网络是通过堆叠一系列的层来逐层提取特征,但随着网络层数的增加,网络往往会遭遇梯度消失(Gradient Vanishing)和梯度爆炸(Gradient Exploding)等问题,导致训练困难。ResNet通过在原始输入和输出之间添加一个跳跃连接,使得网络可以学习残差,从而解决了这些问题。

残差块的计算方式可以表示为:

Output = F ( Input ) + Input \text{Output} = \mathcal{F}(\text{Input}) + \text{Input} Output=F(Input)+Input

其中, F ( ⋅ ) \mathcal{F}(\cdot) F()表示残差学习的映射函数。通过残差块,网络学习到的是残差 F ( Input ) \mathcal{F}(\text{Input}) F(Input),而不是直接学习输出。这种设计使得网络可以更轻松地学习到恒等映射,从而避免了梯度消失和梯度爆炸的问题。

3. 用Python实现(结果可视化)

下面是使用PyTorch实现的一个简单的ResNet模型,并使用CIFAR-10数据集进行训练和测试的示例代码:

import torch
import torch.nn as nn
import torch.optim as optim
import torchvision
import torchvision.transforms as transforms# 定义ResNet残差块
class ResidualBlock(nn.Module):def __init__(self, in_channels, out_channels, stride=1):super(ResidualBlock, self).__init__()self.conv1 = nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=stride, padding=1, bias=False)self.bn1 = nn.BatchNorm2d(out_channels)self.relu = nn.ReLU(inplace=True)self.conv2 = nn.Conv2d(out_channels, out_channels, kernel_size=3, stride=1, padding=1, bias=False)self.bn2 = nn.BatchNorm2d(out_channels)self.downsample = Noneif stride != 1 or in_channels != out_channels:self.downsample = nn.Sequential(nn.Conv2d(in_channels, out_channels, kernel_size=1, stride=stride, bias=False),nn.BatchNorm2d(out_channels))def forward(self, x):residual = xout = self.conv1(x)out = self.bn1(out)out = self.relu(out)out = self.conv2(out)out = self.bn2(out)if self.downsample is not None:residual = self.downsample(residual)out += residualout = self.relu(out)return out# 定义ResNet网络
class ResNet(nn.Module):def __init__(self, block, num_blocks, num_classes=10):super(ResNet, self).__init__()self.in_channels = 64self.conv1 = nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1, bias=False)self.bn1 = nn.BatchNorm2d(64)self.relu = nn.ReLU(inplace=True)self.layer1 = self.make_layer(block, 64, num_blocks[0], stride=1)self.layer2 = self.make_layer(block, 128, num_blocks[1], stride=2)self.layer3 = self.make_layer(block, 256, num_blocks[2], stride=2)self.layer4 = self.make_layer(block, 512, num_blocks[3], stride=2)self.avg_pool = nn.AdaptiveAvgPool2d((1, 1))self.fc = nn.Linear(512, num_classes)def make_layer(self, block, out_channels, num_blocks, stride):layers = []layers.append(block(self.in_channels, out_channels, stride))self.in_channels = out_channelsfor _ in range(1, num_blocks):layers.append(block(out_channels, out_channels, stride=1))return nn.Sequential(*layers)def forward(self, x):out = self.conv1(x)out = self.bn1(out)out = self.relu(out)out = self.layer1(out)out = self.layer2(out)out = self.layer3(out)out = self.layer4(out)out = self.avg_pool(out)out = out.view(out.size(0), -1)out = self.fc(out)return out# 定义数据预处理
transform = transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))
])# 加载CIFAR-10数据集
trainset = torchvision.datasets.CIFAR10(root='./data', train=True, download=True, transform=transform)
trainloader = torch.utils.data.DataLoader(trainset, batch_size=128, shuffle=True, num_workers=2)testset = torchvision.datasets.CIFAR10(root='./data', train=False, download=True, transform=transform)
testloader = torch.utils.data.DataLoader(testset, batch_size=128, shuffle=False, num_workers=2)classes = ('plane', 'car', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck')# 定义设备
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")# 定义ResNet模型
net = ResNet(ResidualBlock, [2, 2, 2, 2]).to(device)# 定义损失函数和优化器
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(), lr=0.1, momentum=0.9, weight_decay=5e-4)# 训练网络
num_epochs = 50
for epoch in range(num_epochs):net.train()running_loss = 0.0for i, data in enumerate(trainloader, 0):inputs, labels = data[0].to(device), data[1].to(device)optimizer.zero_grad()outputs = net(inputs)loss = criterion(outputs, labels)loss.backward()optimizer.step()running_loss += loss.item()print('[%d, %5d] loss: %.3f' % (epoch + 1, i + 1, running_loss / len(trainloader)))print('Finished Training')# 测试网络
net.eval()
correct = 0
total = 0
with torch.no_grad():for data in testloader:images, labels = data[0].to(device), data[1].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))# 保存模型
torch.save(net.state_dict(), 'resnet_model.pth')# 加载模型
net.load_state_dict(torch.load('resnet_model.pth'))# 输出结果可视化
import matplotlib.pyplot as plt
import numpy as np# 输出图像的函数
def imshow(img):img = img / 2 + 0.5     # unnormalizenpimg = img.numpy()plt.imshow(np.transpose(npimg, (1, 2, 0)))plt.show()# 获取随机数据
dataiter = iter(testloader)
images, labels = dataiter.next()# 输出图像
imshow(torchvision.utils.make_grid(images))
print('GroundTruth: ', ' '.join('%5s' % classes[labels[j]] for j in range(4)))# 预测图像
outputs = net(images.to(device))
_, predicted = torch.max(outputs, 1)print('Predicted: ', ' '.join('%5s' % classes[predicted[j]] for j in range(4)))

此示例演示了如何使用PyTorch实现ResNet模型,并使用CIFAR-10数据集对其进行训练和测试。最后,展示了模型对测试图像的分类结果,并可视化了部分图像及其预测结果。


http://www.ppmy.cn/news/1428226.html

相关文章

探索C++的奇妙世界:学习之旅的点点滴滴

在这个信息技术飞速发展的时代,编程语言作为计算机与人类沟通的桥梁,其重要性不言而喻。在众多编程语言中,C以其高效、灵活和强大的特性,吸引了无数编程爱好者的目光。今天,我将与大家分享我学习C的历程和心得&#xf…

Golang插件系统实现

插件可以在解耦的基础上灵活扩展应用功能,本文介绍了如何基于Golang标准库实现插件功能,帮助我们构建更灵活可扩展的应用。原文: Plugins with Go 什么是插件 简单来说,插件就是可以被其他软件加载的软件,通常用于扩展应用程序的功…

java-Spring-入门学习-第二天(单例模式和多例模式)

目录 Bean作用域 单例模式(默认可以不写) Spring下的 AutoWired 依赖注入 JaveEE下的 Resource 依赖注入 多例模式 Bean作用域 ​在Spring框架中,Bean是按照作用域来创建的,常见的作用域有两种:Singleton 和 Prototype。Singleton (单例…

LeetCode———100——相同的树

目录 ​编辑 1.题目 2.解答 1.题目 . - 力扣(LeetCode) 给你两棵二叉树的根节点 p 和 q ,编写一个函数来检验这两棵树是否相同。 如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。 示例 1&…

(vue)el-select选择框加全选/清空/反选

(vue)el-select选择框加全选/清空/反选 <el-form-item label"批次"><el-selectv-model"formInline.processBatch"multiplecollapse-tagsfilterableplaceholder"请选择"style"width: 250px"no-data-text"请先选择企业、日…

Golang学习笔记_RabbitMQ的原理架构和使用

RabbitMQ 简介 实现了高级消息队列协议&#xff08;Advanced Message Queuing Protcol&#xff09;AMQP消息队列中间件的作用&#xff08;Redis实现MQ里面有写过&#xff0c;这里简单带过&#xff09; 解耦削峰异步处理缓存消息通信提高扩展性 RabbitMQ 架构理解 #mermaid-s…

Golang数据类型

文章目录 数据类型的基本介绍基本数据类型整数类型字符类型浮点数类型复数类型布尔类型string类型 常量类型转换基本数据类型相互转换基本数据类型与string的转换 指针类型值类型和引用类型 数据类型的基本介绍 数据类型的基本介绍 Go中的每一种数据都定义了明确的数据类型&…

笔试强训-day01_T1 BC153 [NOIP2010]数字统计

一、题目链接 BC153 [NOIP2010]数字统计 二、题目描述 描述 请统计某个给定范围[L, R]的所有整数中&#xff0c;数字2出现的次数。 比如给定范围[2, 22]&#xff0c;数字2在数2中出现了1次&#xff0c;在数12中出现1次&#xff0c;在数20中出现1次&#xff0c;在数21中出现1次…