wuvin
Always take risks!
Toggle navigation
wuvin
主页
实验室的搬砖生活
机器学习
公开的学术内容
公开的其他内容
About Me
归档
标签
友情链接
ZYQN
ihopenot
enigma_aw
hzwer
杨宗翰
AlexNet框架及Pytorch源码
2019-09-17 21:04:53
1220
0
0
wuvin
看了看2012年里程碑式的AlexNet,发现还是挺不错的,我以前意味就只有简单几层CNN积一下就完了,发现trick还是不少(原来这些trick这么早就有了啊,看来那时候我在玩泥巴)。 # 框架 ## 图片版框架 ![AlexNet](https://leanote.com/api/file/getImage?fileId=5d7f4db8ab644142100065ee) * 为什么长这么奇怪呢?因为图之大,一卡装不下。当时只有可怜的3G的GTX580,所以需要两张卡。 * 下面这个图就清爽很多。 ![这有一个清爽很多的图](https://leanote.com/api/file/getImage?fileId=5d7f4e34ab64414210006608) * 第一层:卷积-->ReLU-->池化-->归一化 * 第二层:卷积-->ReLU-->池化-->归一化 * 第三层:卷积-->ReLU * 第四层:卷积-->ReLU * 第五层:卷积-->ReLU-->池化 * 第六层:卷积(全连接)-->ReLU-->Dropout * 第七层:全连接-->ReLU-->Dropout * 第八层:全连接 * 有个奇怪的问题是,为什么前两层卷积后加了Local Contrast Norm 后面就没有了呢?估计是测试了发现图太小后效果不行。 ## 使用的所有Tricks: * ReLU: ReLU首次出现,并且收敛速度远快于Sigmoid。需要注意权重初始化问题。 * 重叠Pooling: 池化运算的尺寸为3×3,步长为2。听说这样可以减少overfitting,提高精度。 * 局部归一化LRN:被激活的神经元抑制相邻神经元,这东西到底有没有道理可能有待商讨(看了看知乎,都说没用,这个生物学特征可能和能量供给不足有关?)。![title](https://leanote.com/api/file/getImage?fileId=5d7f5069ab64414210006683) * Dropout:Dropout原来是在这里出现的,只出现在第6、7层。 * Data augmentation: 随机裁剪,对256×256的图片进行随机裁剪到224×224,然后进行水平翻转,相当于将样本数量增加了2048倍。测试的时候,对左上、右上、左下、右下、中间分别做了5次裁剪,然后翻转,共10个裁剪,之后对结果求平均。作者说,如果不做随机裁剪,大网络基本上都过拟合;对RGB空间做PCA,然后对主成分做一个(0,0.1)的高斯扰动,也就是对颜色、光照作变换,结果使错误率又下降了1%。 # Pytorch代码 * LRN和模型 ```python import torch import torch.nn as nn from torch.nn import functional as F from torch.autograd import Variable # (N,D,H,W) 直接把一张图的RGB当成三层Depth class LRN(nn.Module): def __init__(self, local_size=1, alpha=1.0, beta=0.75, ACROSS_CHANNELS=False): super(LRN, self).__init__() self.ACROSS_CHANNELS = ACROSS_CHANNELS if self.ACROSS_CHANNELS: #竖着一条 self.average=nn.AvgPool3d(kernel_size=(local_size, 1, 1), stride=1, padding=(int((local_size-1.0)/2), 0, 0) # 这里padding(x) 表示上下左右各添加x行 # padding(H,W) 表示上下H左右W(H' = H + padding[0]) # padding(D,H,W) depth也是上下D ) else: # 在一个面上 self.average=nn.AvgPool2d(kernel_size=local_size, stride=1, padding=int((local_size-1.0)/2)) self.alpha = alpha self.beta = beta def forward(self, x): if self.ACROSS_CHANNELS: div = x.pow(2).unsqueeze(1) div = self.average(div).squeeze(1) div = div.mul(self.alpha).add(2.0).pow(self.beta)#这里的2.0即为bias else: div = x.pow(2) div = self.average(div) div = div.mul(self.alpha).add(2.0).pow(self.beta) x = x.div(div) return x class AlexNet(nn.Module): def __init__(self, num_classes = 1000):#imagenet数量 super().__init__() self.layer1 = nn.Sequential( nn.Conv2d(in_channels=3, out_channels=96, kernel_size=11, stride=4), nn.ReLU(inplace=True), nn.MaxPool2d(kernel_size=3, stride=2), LRN(local_size=5, alpha=1e-4, beta=0.75, ACROSS_CHANNELS=True) ) self.layer2 = nn.Sequential( nn.Conv2d(in_channels=96, out_channels=256, kernel_size=5, groups=2, padding=2), nn.ReLU(inplace=True), nn.MaxPool2d(kernel_size=3, stride=2), LRN(local_size=5, alpha=1e-4, beta=0.75, ACROSS_CHANNELS=True) ) self.layer3 = nn.Sequential( nn.Conv2d(in_channels=256, out_channels=384, padding=1, kernel_size=3), nn.ReLU(inplace=True) ) self.layer4 = nn.Sequential( nn.Conv2d(in_channels=384, out_channels=384, kernel_size=3, padding=1), nn.ReLU(inplace=True) ) self.layer5 = nn.Sequential( nn.Conv2d(in_channels=384, out_channels=256, kernel_size=3, padding=1), nn.ReLU(inplace=True), nn.MaxPool2d(kernel_size=3, stride=2) ) #需要针对上一层改变view self.layer6 = nn.Sequential( nn.Linear(in_features=6*6*256, out_features=4096), nn.ReLU(inplace=True), nn.Dropout() ) self.layer7 = nn.Sequential( nn.Linear(in_features=4096, out_features=4096), nn.ReLU(inplace=True), nn.Dropout() ) self.layer8 = nn.Linear(in_features=4096, out_features=num_classes) def forward(self, x): x = self.layer5(self.layer4(self.layer3(self.layer2(self.layer1(x))))) x = x.view(-1, 6*6*256) x = self.layer8(self.layer7(self.layer6(x))) return x ``` * 数据读入部分 ```python import pandas as pd import numpy as np import torch.utils.data import torchvision.transforms as transforms import torchvision.datasets as datasets normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) train_dataset = datasets.ImageFolder('./data/ILSVRC/Data/CLS-LOC/train/', transforms.Compose([ transforms.RandomSizedCrop(227), #AlexNet输入 transforms.RandomHorizontalFlip(), transforms.ToTensor(), normalize ])) batch_size = 256 train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=batch_size, num_workers=2, pin_memory=True, sampler=sampler ) def weight_init(m): # 使用isinstance来判断m属于什么类型 if isinstance(m, nn.Conv2d): import math n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels m.weight.data.normal_(0, math.sqrt(2. / n)) elif isinstance(m, nn.BatchNorm2d): # m中的weight,bias其实都是Variable,为了能学习参数以及后向传播 m.weight.data.fill_(1) m.bias.data.zero_() model = AlexNet(len(train_dataset.classes)) model.apply(weight_init) use_gpu = torch.cuda.is_available() if use_gpu: model = model.cuda() print('USE GPU') else: print('USE CPU') ``` * 训练部分 ```python criterion = nn.CrossEntropyLoss(size_average=False) # optimizer = torch.optim.SGD(model.parameters(), lr=0.001) optimizer = torch.optim.Adam(model.parameters(), lr=1e-3, betas=(0.9, 0.99)) def train(epoch): model.train() for batch_idx, (data, target) in enumerate(train_loader): if use_gpu: data, target = data.cuda(), target.cuda() data, target = Variable(data), Variable(target) optimizer.zero_grad() output = model(data) loss = criterion(output, target) loss.backward() optimizer.step() if batch_idx % 100 == 0: print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format( epoch, batch_idx * len(data), len(train_loader.dataset), 100. * batch_idx / len(train_loader), loss.data[0])) for epoch in range(1, 5): train(epoch) #未加入测试过程 ```
上一篇:
炼丹杂事
下一篇:
VGG及其pytorch实现
0
赞
1220 人读过
新浪微博
微信
腾讯微博
QQ空间
人人网
提交评论
立即登录
, 发表评论.
没有帐号?
立即注册
0
条评论
More...
文档导航
没有帐号? 立即注册