ResNet网络详解
ResNet
ResNet在2015年由微软实验室提出,斩获当年lmageNet竞赛中分类任务第一名,目标检测第一名。获得coco数据集中目标检测第一名,图像分割第一名。
ResNet亮点
1.超深的网络结构(突破1000层)
2.提出residual模块
3.使用Batch Normalization加速训练(丢弃dropout)
网络一定是越深越好吗?
一般来说,网络越深,咱们能获取的信息越多,而且特征也越丰富。我们思考一个问题,我们一直加深我们的网络,取得的效果一定越好吗?
看到这两幅图我们看到,网络并不是深度越深效果越好,那么是什么原因导致的呢?在ResNet论文中,提出了两个问题,一个是随着网络深度的增加,梯度消失或梯度爆炸问题;另一个是退化问题。为了让更深的网络也能训练出好的效果,何恺明提出了ResNet网络。
残差结构
左边的残差结构用于ResNet-34,右边的残差结构用于ResNet-50/101/152。残差结构可以用表达式F(x)=f(x)+x表示。左边的残差结构很简单,主线f(x)是两个3x3的卷积,最后与x合并。右边多了两个1x1的卷积,用来降维和升维(减少参数量)。
ResNet网络结构
我们着重分析一下ResNet-34结构,可以看到是由多个残差结构堆叠而成:
为什么会有实线和虚线之分呢?从网络参数图上可以看到,经过一个类型的第一个残差结构后,图像的大小为原来的一半,我们拿第一条虚线举例:输入图像为56x56x64,输出为28x28x128,所以分支需要一个1x1卷积来将输入图处理成输出大小。
右侧虚线残差结构的主分支上第一个1x1卷积层的步距是2,第二个3x3卷积层步距是1。但在pytorch官方实现过程中是第一个1x1卷积层的步距是1,第二个3x3卷积层步距是2,这样能够在imagenet的top1上提升大概0.5%的准确率。
Batch Normalization
Batch Normalization是google团队在2015年论文《Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift》提出的。通过该方法能够加速网络的收敛并提升准确率。我们在图像预处理过程中通常会对图像进行标准化处理,这样能够加速网络的收敛,假设对于Conv1来说输入的就是满足某一分布的特征矩阵,但对于Conv2而言经过Conv1卷积后输入的feature map就不一定满足某一分布规律了。而我们Batch Normalization的目的就是使我们的feature map满足均值为0,方差为1的分布规律。下图是一个示例:
我们需要知道的是将bn层放在卷积层(Conv)和激活层(例如Relu)之间,且卷积层不要使用偏置bias,如图所示:
ResNet实现
1.建立模型:
import torch.nn as nn
import torchclass BasicBlock(nn.Module):expansion = 1def __init__(self, in_channel, out_channel, stride=1, downsample=None, **kwargs):super(BasicBlock, self).__init__()self.conv1 = nn.Conv2d(in_channels=in_channel, out_channels=out_channel,kernel_size=3, stride=stride, padding=1, bias=False)self.bn1 = nn.BatchNorm2d(out_channel)self.relu = nn.ReLU()self.conv2 = nn.Conv2d(in_channels=out_channel, out_channels=out_channel,kernel_size=3, stride=1, padding=1, bias=False)self.bn2 = nn.BatchNorm2d(out_channel)self.downsample = downsampledef forward(self, x):identity = xif self.downsample is not None:identity = self.downsample(x)out = self.conv1(x)out = self.bn1(out)out = self.relu(out)out = self.conv2(out)out = self.bn2(out)out += identityout = self.relu(out)return outclass Bottleneck(nn.Module):expansion = 4def __init__(self, in_channel, out_channel, stride=1, downsample=None,groups=1, width_per_group=64):super(Bottleneck, self).__init__()width = int(out_channel * (width_per_group / 64.)) * groupsself.conv1 = nn.Conv2d(in_channels=in_channel, out_channels=width,kernel_size=1, stride=1, bias=False) # squeeze channelsself.bn1 = nn.BatchNorm2d(width)# -----------------------------------------self.conv2 = nn.Conv2d(in_channels=width, out_channels=width, groups=groups,kernel_size=3, stride=stride, bias=False, padding=1)self.bn2 = nn.BatchNorm2d(width)# -----------------------------------------self.conv3 = nn.Conv2d(in_channels=width, out_channels=out_channel*self.expansion,kernel_size=1, stride=1, bias=False) # unsqueeze channelsself.bn3 = nn.BatchNorm2d(out_channel*self.expansion)self.relu = nn.ReLU(inplace=True)self.downsample = downsampledef forward(self, x):identity = xif self.downsample is not None:identity = self.downsample(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)out += identityout = self.relu(out)return outclass ResNet(nn.Module):def __init__(self,block,blocks_num,num_classes=1000,include_top=True,groups=1,width_per_group=64):super(ResNet, self).__init__()self.include_top = include_topself.in_channel = 64self.groups = groupsself.width_per_group = width_per_groupself.conv1 = nn.Conv2d(3, self.in_channel, kernel_size=7, stride=2,padding=3, bias=False)self.bn1 = nn.BatchNorm2d(self.in_channel)self.relu = nn.ReLU(inplace=True)self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)self.layer1 = self._make_layer(block, 64, blocks_num[0])self.layer2 = self._make_layer(block, 128, blocks_num[1], stride=2)self.layer3 = self._make_layer(block, 256, blocks_num[2], stride=2)self.layer4 = self._make_layer(block, 512, blocks_num[3], stride=2)if self.include_top:self.avgpool = nn.AdaptiveAvgPool2d((1, 1)) # output size = (1, 1)self.fc = nn.Linear(512 * block.expansion, num_classes)for m in self.modules():if isinstance(m, nn.Conv2d):nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')def _make_layer(self, block, channel, block_num, stride=1):downsample = Noneif stride != 1 or self.in_channel != channel * block.expansion:downsample = nn.Sequential(nn.Conv2d(self.in_channel, channel * block.expansion, kernel_size=1, stride=stride, bias=False),nn.BatchNorm2d(channel * block.expansion))layers = []layers.append(block(self.in_channel,channel,downsample=downsample,stride=stride,groups=self.groups,width_per_group=self.width_per_group))self.in_channel = channel * block.expansionfor _ in range(1, block_num):layers.append(block(self.in_channel,channel,groups=self.groups,width_per_group=self.width_per_group))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)if self.include_top:x = self.avgpool(x)x = torch.flatten(x, 1)x = self.fc(x)return xdef resnet34(num_classes=1000, include_top=True):# https://download.pytorch.org/models/resnet34-333f7ec4.pthreturn ResNet(BasicBlock, [3, 4, 6, 3], num_classes=num_classes, include_top=include_top)def resnet50(num_classes=1000, include_top=True):# https://download.pytorch.org/models/resnet50-19c8e357.pthreturn ResNet(Bottleneck, [3, 4, 6, 3], num_classes=num_classes, include_top=include_top)def resnet101(num_classes=1000, include_top=True):# https://download.pytorch.org/models/resnet101-5d3b4d8f.pthreturn ResNet(Bottleneck, [3, 4, 23, 3], num_classes=num_classes, include_top=include_top)def resnext50_32x4d(num_classes=1000, include_top=True):# https://download.pytorch.org/models/resnext50_32x4d-7cdf4587.pthgroups = 32width_per_group = 4return ResNet(Bottleneck, [3, 4, 6, 3],num_classes=num_classes,include_top=include_top,groups=groups,width_per_group=width_per_group)def resnext101_32x8d(num_classes=1000, include_top=True):# https://download.pytorch.org/models/resnext101_32x8d-8ba56ff5.pthgroups = 32width_per_group = 8return ResNet(Bottleneck, [3, 4, 23, 3],num_classes=num_classes,include_top=include_top,groups=groups,width_per_group=width_per_group)
2.训练模型:
import os
import sys
import jsonimport torch
import torch.nn as nn
import torch.optim as optim
from torchvision import transforms, datasets
from tqdm import tqdmfrom model import resnet34def main():device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")print("using {} device.".format(device))data_transform = {"train": transforms.Compose([transforms.RandomResizedCrop(224),transforms.RandomHorizontalFlip(),transforms.ToTensor(),transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])# transforms.ConvertImageDtype('RGB')]),"val": transforms.Compose([transforms.Resize(256),transforms.CenterCrop(224),transforms.ToTensor(),transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])])}train_dataset = datasets.ImageFolder(root='./train',transform=data_transform["train"])train_num = len(train_dataset)flower_list = train_dataset.class_to_idxcla_dict = dict((val, key) for key, val in flower_list.items())json_str = json.dumps(cla_dict, indent=4)with open('class_indices.json', 'w') as json_file:json_file.write(json_str)batch_size = 16nw = min([os.cpu_count(), batch_size if batch_size > 1 else 0, 8]) # number of workersprint('Using {} dataloader workers every process'.format(nw))train_loader = torch.utils.data.DataLoader(train_dataset,batch_size=batch_size, shuffle=True,num_workers=nw)validate_dataset = datasets.ImageFolder(root='./val',transform=data_transform["val"])val_num = len(validate_dataset)validate_loader = torch.utils.data.DataLoader(validate_dataset,batch_size=batch_size, shuffle=False,num_workers=nw)print("using {} images for training, {} images for validation.".format(train_num, val_num))net = resnet34(num_classes=36)net.to(device)# define loss functionloss_function = nn.CrossEntropyLoss()# construct an optimizerparams = [p for p in net.parameters() if p.requires_grad]optimizer = optim.Adam(params, lr=0.0001)epochs = 15best_acc = 0.0save_path = './resNet34.pth'train_steps = len(train_loader)for epoch in range(epochs):# trainnet.train()running_loss = 0.0train_bar = tqdm(train_loader, file=sys.stdout)for step, data in enumerate(train_bar):images, labels = dataoptimizer.zero_grad()logits = net(images.to(device))loss = loss_function(logits, labels.to(device))loss.backward()optimizer.step()# print statisticsrunning_loss += loss.item()train_bar.desc = "train epoch[{}/{}] loss:{:.3f}".format(epoch + 1,epochs,loss)# validatenet.eval()acc = 0.0 # accumulate accurate number / epochwith torch.no_grad():val_bar = tqdm(validate_loader, file=sys.stdout)for val_data in val_bar:val_images, val_labels = val_dataoutputs = net(val_images.to(device))# loss = loss_function(outputs, test_labels)predict_y = torch.max(outputs, dim=1)[1]acc += torch.eq(predict_y, val_labels.to(device)).sum().item()val_bar.desc = "valid epoch[{}/{}]".format(epoch + 1,epochs)val_accurate = acc / val_numprint('[epoch %d] train_loss: %.3f val_accuracy: %.3f' %(epoch + 1, running_loss / train_steps, val_accurate))if val_accurate > best_acc:best_acc = val_accuratetorch.save(net.state_dict(), save_path)print('Finished Training')if __name__ == '__main__':main()
ResNet网络详解相关推荐
- ResNet网络详解与keras实现
ResNet网络详解与keras实现 ResNet网络详解与keras实现 Resnet网络的概览 Pascal_VOC数据集 第一层目录 第二层目录 第三层目录 梯度退化 Residual Lear ...
- ResNet网络详解并使用pytorch搭建模型、并基于迁移学习训练
1.ResNet网络详解 网络中的创新点: (1)超深的网络结构(突破1000层) (2)提出residual模块 (3)使用Batch Normalization加速训练(丢弃dropout) (1 ...
- 1. Resnet网络详解
一.ResNet网络介绍 ResNet是2015年有微软实验室提出的,题目: 作者是何凯明等,这四个都是华人. 当年ResNet斩获了当年各种第一名.基本上只要它参加的比赛,全都是第一名. 我们来看一 ...
- 【深度学习】ResNet网络详解
文章目录 ResNet 参考 结构概况 conv1与池化层 残差结构 Batch Normalization 总结 ResNet 参考 ResNet论文: https://arxiv.org/abs/ ...
- ResNet、ResNeXt网络详解及复现
网络详解: ResNet网络详解 ResNeXt网络详解 torch复现: import torch.nn as nn import torch''' 对应着18层和34层的残差结构 既要拥有实现部分 ...
- 第十六章 ConvNeXt网络详解
系列文章目录 第一章 AlexNet网络详解 第二章 VGG网络详解 第三章 GoogLeNet网络详解 第四章 ResNet网络详解 第五章 ResNeXt网络详解 第六章 MobileNetv1网 ...
- 深度残差网络(ResNet)详解与实现(tensorflow2.x)
深度残差网络(ResNet)详解与实现(tensorflow2.x) ResNet原理 ResNet实现 模型创建 数据加载 模型编译 模型训练 测试模型 训练过程 ResNet原理 深层网络在学习任 ...
- GoogleNet网络详解与keras实现
GoogleNet网络详解与keras实现 GoogleNet网络详解与keras实现 GoogleNet系列网络的概览 Pascal_VOC数据集 第一层目录 第二层目录 第三层目录 Incepti ...
- EfficientNetV2网络详解
原论文名称:EfficientNetV2: Smaller Models and Faster Training 论文下载地址:https://arxiv.org/abs/2104.00298 原论文 ...
最新文章
- Flask API TypeError: Object of type 'Response' is not JSON serializable
- scrapy爬虫,爬取图片
- android 系统状态栏的隐藏和显示
- Python学习笔记——os模块【文件、目录方法】
- 7.java.lang.IllegalAccessException
- 网络服务器费信息技术服务费,中山大学网络与信息技术中心网费在线系统
- Makefile语法总结
- IT运维管理必备工具大全,看完还敢称自己是高手吗?
- c# 获取excel单元格公式结果_EXCEL公式解析:单元格中数字去重排序思路及公式详解...
- C语言中强制转换问题
- C++中使用初始化列表比在构造函数中对成员变量赋值更高效
- VB6.0基于ADO连接access踩坑之数据库不显示数据
- 魔鬼作坊端游脱机封包辅助制作
- (二)Latex编译与xelatex编译
- 修改后的取得汉字首字母的lazarus函数,可以自己增加疑难汉字,这个应该比较理想了
- 读书印记 - 《星船伞兵》
- Jboss RichFaces + Skin的简单运用示例代码
- 2019年3月最新windwows101809教育版激活密钥及其下载地址
- 台式计算机怎么加一个硬盘,台式机加装一个机械硬盘图解 但建议直接在windows下...
- 【架构风格】架构风格演进和领域架构分类
热门文章
- Nginx 之实现原理
- c语言定义未知长度一维数组,c++ 如何定义未知元素个数的数组
- 星舰到底要实现什么壮志?火星移民,月球旅行,亦是地球轨道运输
- Windows环境下安装RabbitMQ(官方文档中文版)
- 2021安全范儿高校挑战赛ByteCTF线上赛部分Writeup
- xmlHttp.send(null)与xmlHttp.send…
- 无法安装驱动程序 此计算机上不存在英特尔适配器,win10系统提示无法安装驱动程序,此计算机中没有Intel适配器怎么办...
- Object.assign与vue $set
- Echarts地图 绘制自定义区域 - geojson.io使用方法
- 头插法和尾插法建立单链表