ResNet(残差网络)是一种重要的深度学习架构,由微软研究院的Kaiming He等人在2015年提出。ResNet通过引入残差连接(Residual Connections)解决了随着网络深度增加而导致的训练困难问题,使得网络能够成功训练上百甚至上千层的深度。
算法原理
ResNet的核心思想是残差学习(Residual Learning)。在一个深层网络中,如果一个层的输入和输出之间的映射关系是恒等映射(Identity Mapping),那么这个层就不会对网络的性能产生负面影响。基于这个思想,ResNet通过添加跳过一层或多层的直接连接(称为残差连接),允许网络学习输入和输出之间的残差(即差异),而不是直接学习映射关系。
具体来说,ResNet中的每个残差块(Residual Block)包含两个或更多的卷积层,这些卷积层的输出会与输入相加,然后进行非线性激活函数处理。如果输入和输出的维度不一致,通常会使用卷积层或全连接层进行调整。
数学推导解释
假设H(x)是期望的映射关系,F(x)是残差映射(即H(x) - x),那么残差块的目标就是学习F(x)。对于一个简单的残差块,其数学表达式可以写成:
y = F(x) + x
其中,y是残差块的输出,F(x)是经过卷积层的残差映射,x是输入。如果H(x)是一个恒等映射,那么F(x)将接近于0,网络学习的就是输入和输出之间的微小差异,这使得网络更容易学习到有用的特征。
Python代码实现
以下是使用PyTorch实现的ResNet的一个简化版:
import torch
import torch.nn as nn
import torch.nn.functional as F
class BasicBlock(nn.Module):
expansion = 1
def __init__(self, in_planes, planes, stride=1, downsample=None):
super(BasicBlock, self).__init__()
self.conv1 = nn.Conv2d(in_planes, planes, kernel_size=3, stride=stride, padding=1, bias=False)
self.bn1 = nn.BatchNorm2d(planes)
self.relu = nn.ReLU(inplace=True)
self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=1, padding=1, bias=False)
self.bn2 = nn.BatchNorm2d(planes)
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)
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_planes = 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, planes, blocks, stride=1):
downsample = None
if stride != 1 or self.in_planes != planes * block.expansion:
downsample = nn.Sequential(
nn.Conv2d(self.in_planes, planes * block.expansion, kernel_size=1, stride=stride, bias=False),
nn.BatchNorm2d(planes * block.expansion),
)
layers = []
layers.append(block(self.in_planes, planes, stride, downsample))
self.in_planes = planes * block.expansion
for _ in range(1, blocks):
layers.append(block(self.in_planes, planes))
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 = torch.flatten(x, 1)
x = self.fc(x)
return x
# 示例:创建一个ResNet-50网络
resnet50 = ResNet(BasicBlock, [3, 4, 6, 3])
# 假设输入特征图的大小为(1, 3, 224, 224)
input_tensor = torch.randn(1, 3, 224, 224)
# 前向传播
output = resnet50(input_tensor)
print(output.size()) # 应该输出 (1, 1000)
在这个例子中,我们定义了一个简化版的ResNet-50网络,它使用BasicBlock作为残差块,并且包含4个残差层级。我们创建了一个输入张量,并通过了ResNet网络来获取输出。这个简化的ResNet网络可以作为一个构建更深层次ResNet网络的组件。
本文暂时没有评论,来添加一个吧(●'◡'●)