[深度学习网络从入门到入土]
残差网络ResNet
个人导航
知乎:https://www.zhihu.com/people/byzh_rc
CSDN:https://blog.csdn.net/qq_54636039
注:本文仅对所述内容做了框架性引导,具体细节可查询其余相关资料or源码
参考文章:各方资料
文章目录
- [深度学习网络从入门到入土]
残差网络ResNet
- 个人导航
- 参考资料
- 背景
- 架构(公式)
- 1.
==BasicBlock(ResNet18/34)==
- 2.
==Bottleneck(ResNet50/101/152)==
- 3.
==Shortcut
类型==
- 1.
- 创新点
- 1.
==残差连接==(Skip
结构简洁但极强
- 1.
- 为什么
ResNet
层
- 代码实现
- 项目实例
参考资料
Deep
Residual
Recognition.
背景
在
2014–2015
进入“越深越好”的阶段:
- AlexNet:8
层
问题来了:当网络超过
层后,训练误差反而上升
这不是过拟合,而是优化困难(degradation
problem)
resnet横空出世:让网络学习“残差”,而不是直接学习映射
传统网络:
=
H(x)=F(x)
style="margin-right:
0.0813em;">H
(x)=style="margin-right:
0.1389em;">F
(x)/>ResNet:
0.0813em;">H(x)=
style="margin-right:
0.1389em;">F
(x)+x
架构(公式)
/>
1.BasicBlock(ResNet18/34)
ConvReLU
ReLU
y
=
0.0359em;">y=ReLU( 0.1389em;">F 0.1389em;">F 0.1389em;">W 0.05em;">2 0.15em;"> 0.0359em;">σ 0.1389em;">W 0.05em;">1 0.15em;">style="margin-right:
style="margin-right:
style="margin-right:
style="height:
style="height:
style="margin-right:
style="margin-right:
style="height:
style="height:
2.Bottleneck(ResNet50/101/152)
当网络变得非常深时,使用瓶颈结构:
1×1(降维)3×3(提取特征)
1×1(升维)
F
=
0.1389em;">F(x)= 0.1389em;">W 0.05em;">3 0.15em;"> 0.0359em;">σ 0.1389em;">W 0.05em;">2 0.15em;"> 0.0359em;">σ 0.1389em;">W 0.05em;">1 0.15em;">style="margin-right:
style="height:
style="height:
style="margin-right:
style="margin-right:
style="height:
style="height:
style="margin-right:
style="margin-right:
style="height:
style="height:
3.Shortcut类型
情况1:尺寸相同
=
0.0359em;">y= 0.1389em;">Fstyle="margin-right:
/>情况2:尺寸不同(下采样)
=
0.0359em;">y= 0.1389em;">F 0.1389em;">W 0.05em;">s 0.15em;"> purple;">W purple;">s 0.15em;"> purple;">Convstyle="margin-right:
style="margin-right:
style="height:
style="height:
style="color:
style="height:
style="height:
style="color:
/>
创新点
1.残差连接(Skip
Connection)
允许梯度直接传播
2.层首次成功训练3.
3.
结构简洁但极强
成为后续几乎所有视觉网络的基础(DenseNet,
U-Net)为什么
1 0.0556em;">∂ 0.0359em;">y 0.686em;"> 0.0556em;">∂ 0.1389em;">F 0.686em;">style="height:
style="top:
style="height:
style="height:
style="top:
style="height:
/>即梯度中始终存在
项:
- 梯度不会消失
- 网络可以直接传递恒等映射
代码实现
/>
importtorchimporttorch.nnasnnimporttorch.nn.functionalasFfrombyzh.ai.Butilsimportb_get_paramsclassBasicBlock(nn.Module):"""ResNet18/34
"""
expansion=1def__init__(self,in_ch,out_ch,stride=1):super().__init__()self.conv1=nn.Conv2d(in_ch,out_ch,3,stride,1,bias=False)self.bn1=nn.BatchNorm2d(out_ch)self.conv2=nn.Conv2d(out_ch,out_ch,3,1,1,bias=False)self.bn2=nn.BatchNorm2d(out_ch)self.shortcut=nn.Sequential()ifstride!=1orin_ch!=out_ch:self.shortcut=nn.Sequential(nn.Conv2d(in_ch,out_ch,1,stride,bias=False),nn.BatchNorm2d(out_ch))defforward(self,x):out=torch.relu(self.bn1(self.conv1(x)))out=self.bn2(self.conv2(out))out+=self.shortcut(x)out=torch.relu(out)returnoutclassBottleneck(nn.Module):"""ResNet50/101/152
"""
expansion=4#=
4
def__init__(self,in_ch,out_ch,stride=1):super().__init__()#1x1
降维
self.conv1=nn.Conv2d(in_ch,out_ch,kernel_size=1,bias=False)self.bn1=nn.BatchNorm2d(out_ch)#3x3
下采样)
self.conv2=nn.Conv2d(out_ch,out_ch,kernel_size=3,stride=stride,padding=1,bias=False)self.bn2=nn.BatchNorm2d(out_ch)#1x1
升维
self.conv3=nn.Conv2d(out_ch,out_ch*self.expansion,kernel_size=1,bias=False)self.bn3=nn.BatchNorm2d(out_ch*self.expansion)self.shortcut=nn.Sequential()ifstride!=1orin_ch!=out_ch*self.expansion:self.shortcut=nn.Sequential(nn.Conv2d(in_ch,out_ch*self.expansion,kernel_size=1,stride=stride,bias=False),nn.BatchNorm2d(out_ch*self.expansion))defforward(self,x):out=torch.relu(self.bn1(self.conv1(x)))out=torch.relu(self.bn2(self.conv2(out)))out=self.bn3(self.conv3(out))out+=self.shortcut(x)out=torch.relu(out)returnoutclassResNet(nn.Module):"""input
"""
def__init__(self,block,layers,num_classes=1000):super().__init__()self.in_ch=64self.conv1=nn.Conv2d(3,64,7,2,3,bias=False)self.bn1=nn.BatchNorm2d(64)self.maxpool=nn.MaxPool2d(3,2,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_ch,blocks,stride=1):layers=[]layers.append(block(self.in_ch,out_ch,stride))self.in_ch=out_ch*block.expansionfor_inrange(1,blocks):layers.append(block(self.in_ch,out_ch))returnnn.Sequential(*layers)defforward(self,x):x=torch.relu(self.bn1(self.conv1(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)returnxclassB_ResNet18_Paper(ResNet):"""input
"""
def__init__(self,num_classes=1000):block=BasicBlocklayers=[2,2,2,2]super().__init__(block=block,layers=layers,num_classes=num_classes)classB_ResNet34_Paper(ResNet):"""
input
"""def__init__(self,num_classes=1000):block=BasicBlock
layers=[3,4,6,3]super().__init__(block=block,layers=layers,num_classes=num_classes)classB_ResNet50_Paper(ResNet):"""
input
"""def__init__(self,num_classes=1000):block=Bottleneck
layers=[3,4,6,3]super().__init__(block=block,layers=layers,num_classes=num_classes)classB_ResNet101_Paper(ResNet):"""
input
"""def__init__(self,num_classes=1000):block=Bottleneck
layers=[3,4,23,3]super().__init__(block=block,layers=layers,num_classes=num_classes)classB_ResNet152_Paper(ResNet):"""
input
"""def__init__(self,num_classes=1000):block=Bottleneck
layers=[3,8,36,3]super().__init__(block=block,layers=layers,num_classes=num_classes)if__name__=='__main__':#
ResNet18net=B_ResNet18_Paper(num_classes=1000)a=torch.randn(50,3,224,224)result=net(a)print(result.shape)print(f"参数量:{b_get_params(net)}")#
ResNet34net=B_ResNet34_Paper(num_classes=1000)a=torch.randn(50,3,224,224)result=net(a)print(result.shape)print(f"参数量:{b_get_params(net)}")#
ResNet50net=B_ResNet50_Paper(num_classes=1000)a=torch.randn(50,3,224,224)result=net(a)print(result.shape)print(f"参数量:{b_get_params(net)}")#
ResNet101net=B_ResNet101_Paper(num_classes=1000)a=torch.randn(50,3,224,224)result=net(a)print(result.shape)print(f"参数量:{b_get_params(net)}")#
ResNet152net=B_ResNet152_Paper(num_classes=1000)a=torch.randn(50,3,224,224)result=net(a)print(result.shape)print(f"参数量:{b_get_params(net)}")#
60_192_808
项目实例
库环境:
numpy==1.26.4...
ResNet18训练MNIST数据集:
#copy
run
importtorchimporttorch.nn.functionalasFfromuploadToPypi_ai.byzh.ai.Bdataimportb_stratified_indicesfrombyzh.ai.BtrainerimportB_Classification_Trainerfrombyzh.ai.BdataimportB_Download_MNIST,b_get_dataloader_from_tensor#from
uploadToPypi_ai.byzh.ai.Bmodel.study_cnn
import
B_ResNet18_Paper
frombyzh.ai.Bmodel.study_cnnimportB_ResNet18_Paperfrombyzh.ai.Butilsimportb_get_device#####hyper
#####
epochs=10lr=1e-3batch_size=32device=b_get_device(use_idle_gpu=True)#####data
#####
downloader=B_Download_MNIST(save_dir='D:/study_cnn/datasets/MNIST')data_dict=downloader.get_data()X_train=data_dict['X_train_standard']y_train=data_dict['y_train']X_test=data_dict['X_test_standard']y_test=data_dict['y_test']num_classes=data_dict['num_classes']num_samples=data_dict['num_samples']indices=b_stratified_indices(y_train,num_samples//5)X_train=X_train[indices]X_train=F.interpolate(X_train,size=(224,224),mode='bilinear')X_train=X_train.repeat(1,3,1,1)y_train=y_train[indices]indices=b_stratified_indices(y_test,num_samples//5)X_test=X_test[indices]X_test=F.interpolate(X_test,size=(224,224),mode='bilinear')X_test=X_test.repeat(1,3,1,1)y_test=y_test[indices]train_dataloader,val_dataloader=b_get_dataloader_from_tensor(X_train,y_train,X_test,y_test,batch_size=batch_size)#####model
#####
model=B_ResNet18_Paper(num_classes=num_classes)#####else
#####
optimizer=torch.optim.Adam(model.parameters(),lr=lr)criterion=torch.nn.CrossEntropyLoss()#####trainer
#####
trainer=B_Classification_Trainer(model=model,optimizer=optimizer,criterion=criterion,train_loader=train_dataloader,val_loader=val_dataloader,device=device)trainer.set_writer1('./runs/resnet18/log.txt')#####run
#####
trainer.train_eval_s(epochs=epochs)#####calculate
#####
trainer.draw_loss_acc('./runs/resnet18/loss_acc.png',y_lim=False)trainer.save_best_checkpoint('./runs/resnet18/best_checkpoint.pth')trainer.calculate_model()

