度学习中的ResNet模型:原理、特点与应用

简介: 【10月更文挑战第4天】

深度学习技术在过去十年中取得了飞速的发展,其中卷积神经网络(Convolutional Neural Networks, CNNs)在图像识别、目标检测等任务中表现尤为突出。然而,随着网络深度的增加,模型容易出现梯度消失和梯度爆炸的问题,导致训练困难。为了解决这一问题,2015年微软研究院提出了残差网络(Residual Network,简称ResNet)。ResNet通过引入残差块(Residual Block)有效地缓解了深层网络的训练难题,显著提升了模型的性能。
ResNet模型介绍
基本架构
ResNet的核心思想是在网络中引入残差块,通过跳跃连接(Skip Connection)将输入直接传递到后续层,从而缓解梯度消失和梯度爆炸的问题。具体来说,残差块的结构如下:

  1. 残差块(Residual Block):
    • 卷积层:通常包含两个或三个卷积层,每个卷积层后面跟着一个批量归一化(Batch Normalization)层和一个ReLU激活函数。
    • 跳跃连接:将输入直接加到卷积层的输出上,形成残差输出。
    数学上,残差块可以表示为:
    [
    y = F(x, W_i) + x
    ]
    其中,(F(x, W_i)) 表示卷积层的输出,(x) 是输入,(y) 是残差块的输出。1. 整体架构:
    • 输入层:将输入图像转换为特征图。
    • 卷积层:多个残差块组成的卷积层,逐步提取高层次的特征。
    • 池化层:通过最大池化或平均池化降低特征图的维度。
    • 全连接层:将特征图展平后通过全连接层进行分类。
    残差块的变体
    • Bottleneck Block:在ResNet-50及更深的网络中,残差块通常采用Bottleneck结构,包含三个卷积层,分别是1x1、3x3和1x1的卷积层。1x1卷积层用于减少和恢复通道数,3x3卷积层用于提取特征。
    特点
  2. 缓解梯度消失和梯度爆炸:通过跳跃连接,残差块可以直接将输入传递到后续层,避免了梯度在深层网络中的消失或爆炸问题。
  3. 易于训练:残差块的设计使得网络更容易训练,即使在网络深度增加时,性能也不会显著下降。
  4. 灵活性强:ResNet可以很容易地扩展到不同的深度,适用于各种任务和数据集。
  5. 性能优越:ResNet在多个基准数据集上取得了优异的性能,特别是在ImageNet图像分类任务中,ResNet-152模型达到了当时的最佳性能。
    应用
    图像识别
  6. 图像分类:ResNet在ImageNet等大型图像分类数据集上表现出色,显著提升了分类精度。
  7. 目标检测:通过结合Faster R-CNN等目标检测框架,ResNet可以用于精确地检测和定位图像中的多个目标。
  8. 语义分割:ResNet可以作为骨干网络,用于提取图像的高层次特征,应用于语义分割任务,如Cityscapes数据集。
    医疗影像分析
  9. 疾病诊断:ResNet可以用于分析医学影像,如X光片、CT扫描和MRI图像,辅助医生进行疾病诊断。
  10. 病理学分析:通过训练ResNet模型,可以自动识别病理切片中的异常细胞,提高病理学分析的效率和准确性。
    视频分析
  11. 动作识别:ResNet可以用于提取视频帧的特征,结合时间信息进行动作识别,如UCF-101数据集。
  12. 视频分类:通过将ResNet应用于视频帧,可以实现视频内容的分类和标签生成。
    用法
    使用PyTorch实现ResNet
    以下是一个简单的示例,展示如何使用PyTorch库实现一个基本的ResNet模型:
    import torch
    import torch.nn as nn
    import torch.optim as optim
    from torchvision import datasets, transforms

class BasicBlock(nn.Module):
expansion = 1

def __init__(self, in_channels, out_channels, stride=1, downsample=None):
    super(BasicBlock, self).__见代码补全错误

def forward(self, x):
    identity = x

    out = 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:
        identity = self.downsample(x)

    out += identity
    out = self.relu(out)

    return out

class Bottleneck(nn.Module):
expansion = 4

def __init__(self, in_channels, out_channels, stride=1, downsample=None):
    super(Bottleneck, self).__init__()
    self.conv1 = nn.Conv2d(in_channels, out_channels, kernel_size=1, stride=1, bias=False)
    self.bn1 = nn.BatchNorm2d(out_channels)
    self.conv2 = nn.Conv2d(out_channels, out_channels, kernel_size=3, stride=stride, padding=1, bias=False)
    self.bn2 = nn.BatchNorm2d(out_channels)
    self.conv3 = nn.Conv2d(out_channels, out_channels * self.expansion, kernel_size=1, stride=1, bias=False)
    self.bn3 = nn.BatchNorm2d(out_channels * self.expansion)
    self.relu = nn.ReLU(inplace=True)
    self.downsample = downsample

def forward(self, x):
    identity = x

    out = self.conv1(x)
    out = self.bn1(out)
    out = self.relu(out)

    out = self.conv2(out)
    out = self.bn2(out)
    out = self.relu(out)

    out = self.conv3(out)
    out = self.bn3(out)

    if self.downsample is not None:
        identity = self.downsample(x)

    out += identity
    out = self.relu(out)

    return out

class ResNet(nn.Module):
def init(self, block, layers, num_classes=1000):
super(ResNet, self).init()
self.in_channels = 64
self.conv1 = nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3, bias=False)
self.bn1 = nn.BatchNorm2d(64)
self.relu = nn.ReLU(inplace=True)
self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
self.layer1 = self._make_layer(block, 64, layers[0])
self.layer2 = self._make_layer(block, 128, layers[1], stride=2)
self.layer3 = self._make_layer(block, 256, layers[2], stride=2)
self.layer4 = self._make_layer(block, 512, layers[3], stride=2)
self.avgpool = nn.AdaptiveAvgPool2d((1, 1))
self.fc = nn.Linear(512 * block.expansion, num_classes)

def _make_layer(self, block, out_channels, blocks, stride=1):
    downsample = None
    if stride != 1 or self.in_channels != out_channels * block.expansion:
        downsample = nn.Sequential(
            nn.Conv2d(self.in_channels, out_channels * block.expansion, kernel_size=1, stride=stride, bias=False),
            nn.BatchNorm2d(out_channels * block.expansion),
        )

    layers = []
    layers.append(block(self.in_channels, out_channels, stride, downsample))
    self.in_channels = out_channels * block.expansion
    for _ in range(1, blocks):
        layers.append(block(self.in_channels, out_channels))

    return nn.Sequential(*layers)

def forward(self, x):
    x = self.conv1(x)
    x = self.bn1(x)
    x = self.relu(x)
    x = self.maxpool(x)

    x = self.layer1(x)
    x = self.layer2(x)
    x = self.layer3(x)
    x = self.layer4(x)

    x = self.avgpool(x)
    x = x.view(x.size(0), -1)
    x = self.fc(x)

    return x

def ResNet18():
return ResNet(BasicBlock, [2, 2, 2, 2])

def ResNet50():
return ResNet(Bottleneck, [3, 4, 6, 3])

数据加载

transform = transforms.Compose([
transforms.RandomResizedCrop(224),
transforms.RandomHorizontalFlip(),
transforms.ToTensor(),
transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
])

train_dataset = datasets.ImageFolder(root='path/to/train', transform=transform)
train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=32, shuffle=True, num_workers=4)

test_dataset = datasets.ImageFolder(root='path/to/test', transform=transform)
test_loader = torch.utils.data.DataLoader(test_dataset, batch_size=32, shuffle=False, num_workers=4)

模型定义

model = ResNet18()

损失函数和优化器

criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=0.001, momentum=0.9)

训练模型

num_epochs = 10
for epoch in range(num_epochs):
model.train()
running_loss = 0.0
for inputs, labels in train_loader:
optimizer.zero_grad()
outputs = model(inputs)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
running_loss += loss.item()

print(f'Epoch {epoch+1}/{num_epochs}, Loss: {running_loss/len(train_loader)}')

评估模型

model.eval()
correct = 0
total = 0
with torch.no_grad():
for inputs, labels in testloader:
outputs = model(inputs)
, predicted = torch.max(outputs.data, 1)
total += labels.size(0)
correct += (predicted == labels).sum().item()

print(f'Accuracy of the network on the test images: {100 * correct / total}%')结论
ResNet通过引入残差块和跳跃连接,有效地解决了深层网络的训练难题,显著提升了模型的性能。ResNet在图像识别、医疗影像分析和视频分析等多个领域得到了广泛应用,成为深度学习领域的重要模型之一。随着研究的不断深入,ResNet及其变体将继续在更多任务中发挥重要作用。

相关文章
|
3月前
|
机器学习/深度学习 人工智能 算法
鸟类识别系统Python+卷积神经网络算法+深度学习+人工智能+TensorFlow+ResNet50算法模型+图像识别
鸟类识别系统。本系统采用Python作为主要开发语言,通过使用加利福利亚大学开源的200种鸟类图像作为数据集。使用TensorFlow搭建ResNet50卷积神经网络算法模型,然后进行模型的迭代训练,得到一个识别精度较高的模型,然后在保存为本地的H5格式文件。在使用Django开发Web网页端操作界面,实现用户上传一张鸟类图像,识别其名称。
119 12
鸟类识别系统Python+卷积神经网络算法+深度学习+人工智能+TensorFlow+ResNet50算法模型+图像识别
|
机器学习/深度学习 TensorFlow 算法框架/工具
ResNet18详细原理(含tensorflow版源码)
ResNet18详细原理(含tensorflow版源码)
1102 0
ResNet18详细原理(含tensorflow版源码)
|
算法 PyTorch 调度
ResNet 高精度预训练模型在 MMDetection 中的最佳实践
作为最常见的骨干网络,ResNet 在目标检测算法中起到了至关重要的作用。许多目标检测经典算法,如 RetinaNet 、Faster R-CNN 和 Mask R-CNN 等都是以 ResNet 为骨干网络,并在此基础上进行调优。同时,大部分后续改进算法都会以 RetinaNet 、Faster R-CNN 和 Mask R-CNN 为 baseline 进行公平对比。
921 0
ResNet 高精度预训练模型在 MMDetection 中的最佳实践
|
机器学习/深度学习 数据库
【MATLAB第49期】基于MATLAB的深度学习ResNet-18网络不平衡图像数据分类识别模型
【MATLAB第49期】基于MATLAB的深度学习ResNet-18网络不平衡图像数据分类识别模型
|
机器学习/深度学习 存储 人工智能
模型推理加速系列 | 03:Pytorch模型量化实践并以ResNet18模型量化为例(附代码)
本文主要简要介绍Pytorch模型量化相关,并以ResNet18模型为例进行量化实践。
|
编解码 数据库
详细分析ResNet | 用CarNet教你如何一步一步设计轻量化模型(二)
详细分析ResNet | 用CarNet教你如何一步一步设计轻量化模型(二)
264 0
|
机器学习/深度学习 编解码 数据库
详细分析ResNet | 用CarNet教你如何一步一步设计轻量化模型(一)
详细分析ResNet | 用CarNet教你如何一步一步设计轻量化模型(一)
441 0
|
机器学习/深度学习 人工智能 算法
部署教程 | ResNet原理+PyTorch复现+ONNX+TensorRT int8量化部署
部署教程 | ResNet原理+PyTorch复现+ONNX+TensorRT int8量化部署
317 0
|
计算机视觉
【前沿经典模型】ResNet最强改进之ResNeSt(附源码)(二)
【前沿经典模型】ResNet最强改进之ResNeSt(附源码)(二)
539 0
|
机器学习/深度学习 计算机视觉 网络架构
【前沿经典模型】ResNet最强改进之ResNeSt(附源码)(一)
【前沿经典模型】ResNet最强改进之ResNeSt(附源码)(一)
2246 0

热门文章

最新文章

下一篇
DataWorks