前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >alexnet论文复现

alexnet论文复现

原创
作者头像
用户7680342
修改2020-11-09 10:42:55
7520
修改2020-11-09 10:42:55
举报
文章被收录于专栏:人工智能基础人工智能基础

今天复现一篇cv方面基础的论文,也可以说是计算机视觉,需要读的第一篇论文:

alexnet(当然还有很多cv方面奠基的文章,但是因为alexnet是第一个将卷积神经网络应用到大规模图片识别,并且取得很好的效果:ImageNet LSVRC-2010 取得top-1和top-5错误率为37.5%和17.0%的效果, ImageNet LSVRC-2012中,取得了top-5错误率为15.3%)。

论文主要贡献:

1> 训练了一个基于imagenet数据集的大型卷积神经网络,并且效果不错。

2> 实现了一个基于两块gpu的2d卷积网络实现,包含一些提高性能和减少训练时长的特性。

3> 为了避免过拟合,alexnet使用relu,数据增强的方法,有效的解决了过拟合问题。

4> alexnet发现和证明了,网络深度对神经网络的性能,至关重要。

可以看出,网络从左到右包含五个卷积层,三个全连接,最终输出1000个softmax,共八层。

下面就根据该图,从输入开始详细介绍:

输入层:

alexnet需要固定的图片大小,所以imagenet数据集中的图片需要进行下采样到统一的256 * 256.

方法是: 首先对图片矩形进行缩放,使得较短的变长变成256 长。之后对缩放后的数据进行裁剪得到256 * 256的正方形。

图片中每个像素在训练之前都会减去训练集均值,所以alexnet的训练。

从网络结构中输入层看到,输入数据是224 * 224.不禁生疑,输入图像不是256 * 256的吗?

原来,在输入图片上,alexnet还需要进行224 *224的随机裁剪。这样可以大大增加训练集的大小(2048倍 2 * 32 * 32),

论文中提到,如果没有这一步,整个网络的效果会差很多。

第一层:

根据输入3 * 224 * 224, 使用11 * 11 * 3 * 96 步长为4 padding为2的操作,,根据公式(224 - 11 + 2 * 2)/4 + 1 = 55 ,得到55 * 55 * 96的特征图

(网上有一种说法,说是论文错了,网络输入层应该是227 * 227 , 根据公式,(227 - 11 + 2*0)/4 + 1 = 55,这里笔者没有深入讨论是否论文错了)

值得注意的是,第二层开始,所有的特征图分为两部分,分布在两块显卡上,每个显卡的对应第二层有48个特征图。

第一层卷积之后经过一个maxpooling , 得到第二层输入,维度为 27 * 27 * 96 ,同样池化后的数据经过卷积依然分别存在两块显卡上,每个显卡48个特征图。

第二层:

上一次的输出27 * 27 * 96 经过这一层首先经过5 * 5 * 96 * 256 的卷积操作,padding为2 步长为1,根据公式 (27 +4 - 5)/1 + 1 = 27 , 则最终输出

27 * 27 * 256的特征图。然后经过步长为2 的3*3池化 (27/2) = 13 ,即第二层最终输出为 13 * 13 * 256

第三层:

这一层开始不会做池化操作了,并且从网络架构图中可以看出,这层里,不同网卡中的数据进行了融合(论文里面没有特别提到这点,这里也不做详细介绍)

所以当前层使用 3 * 3 * 256 * 192 的卷积操作(步长为1 ,padding 为1),得到 13 * 13 * 192的 输出。

第四层:

第四层和第三层类似,只使用 3 * 3 * 192*192的卷积操作(步长为1,padding为1)这样的操作下, 输出和输出维度一致 , 依然为 13 * 13 * 192.

第五层:

这里使用 3 * 3 * 192 * 256 的卷积操作(步长为1, padding为1),输出 为 13 * 13 * 256,之后经过一个max pooling, (13/2)= 6 得到 6 * 6 * 256的特征图。

第六层:

全连接层: 这里将特征图拉长为一个向量,经过 6 * 6 * 256 * 4096的矩阵相乘得到4096的向量输出。

第七层:

依旧是一个全连接: 权重矩阵为 4096 * 4096,这里后面加一个dropout,会以0.5 的概率冻结部分全连接的输出。(最终当前轮 对应神经元的权重不会更新)

第八层: 全连接并最终softmax输出到1000个分类。

代码语言:javascript
复制
paddle paddle的实现如下: 
import paddle
import paddle.fluid as fluid
import numpy as np
from paddle.fluid.dygraph.nn import Conv2D, Pool2D, Linear
from paddle.fluid.dygraph import Dropout

# 定义 AlexNet 网络结构
class AlexNet(fluid.dygraph.Layer):
    def __init__(self, num_classes=10):
        super(AlexNet, self).__init__()
        ##### alexnet main structure

        #data = fluid.data(name='data', shape=[None, 3, 224, 224], dtype='float32')

        # output[96, 55, 55] , (224+2*2-11)/4+1) = int(55.25)  = 55
        self.conv1 = Conv2D(num_channels=3, num_filters=96, filter_size=11,stride=4, padding=2, act="relu")

        # output[96, 27], ((55-3)/2+1) = 27
        self.pool1 = Pool2D( pool_type='max',pool_stride=2, pool_size=3)

        # output [256, 27, 27] ((27+4-5)/1 +1) = 27
        self.conv2 = Conv2D(num_channels=96, num_filters=256, filter_size=5, padding=2, act = "relu")

        # output [256, 13, 13] ((27-3)/2 + 1) = 13
        self.pool2 = Pool2D( pool_type='max', pool_size=3, pool_stride=2)

        # output[192, 13, 13] ((13+2 - 3)/1 + 1)
        self.conv3 = Conv2D(num_channels=256, num_filters=192, filter_size=3, padding=1, act="relu")

        # output[192, 13, 13] ((13+2-3)/1 + 1)
        self.conv4 = Conv2D(num_channels=192, num_filters=192, filter_size=3, padding=1, act="relu")
        
        # output[256, 13, 13]
        self.conv5 = Conv2D(num_channels = 192, num_filters=256, filter_size=3, padding=1, act="relu")

        # output[256, 6, 6 ] ((13 -3)/2 + 1)
        self.pool5 = Pool2D( pool_type='max', pool_size=3, pool_stride=2)

        # input = 6 * 6 * 256
        self.fc6 = Linear(input_dim=6*6*256, output_dim=4096, act='relu')
        
        self.drop6 =  Dropout(p=0.5) #fluid.layers.dropout(fc6,dropout_prob=0.5)
        
        self.fc7 = Linear(input_dim=4096, output_dim=4096, act = "relu")#fluid.layers.fc(drop6, size=4096, act='relu')
        self.drop7  = Dropout(p=0.5)
        self.fc8 = Linear(input_dim=4096, output_dim=num_classes)#fluid.layers.fc(fc7, size=n_classes)
        ##### alexnet structure end.

        
    # 网络的前向计算过程
    def forward(self, x):
        x = self.conv1(x)
        x = self.pool1(x)
        x = self.conv2(x)
        x = self.pool2(x)
        x = self.conv3(x)
        x = self.conv4(x)
        x = self.conv5(x)
        x = self.pool5(x)
        x = fluid.layers.reshape(x, [x.shape[0], -1])

        x = self.fc6(x)
        x = self.drop6(x)
        x = self.fc7(x)
        x = self.drop7(x)
        x = self.fc8(x)
        return x


x = np.random.randn(*[3,3,224,224])
print(x.shape)
x = x.astype('float32')
with fluid.dygraph.guard():
    
    # 创建LeNet类的实例,指定模型名称和分类的类别数目
    m = AlexNet(num_classes=10)
    # 通过调用LeNet从基类继承的sublayers()函数,
    # 查看LeNet中所包含的子层
    #print(m.sublayers())
    x = fluid.dygraph.to_variable(x)
    for item in m.sublayers():
        # item是LeNet类中的一个子层
        # 查看经过子层之后的输出数据形状
        try:
            x = item(x)
        except:
            x = fluid.layers.reshape(x, [x.shape[0], -1])
            x = item(x)
        if len(item.parameters())==2:
            # 查看卷积和全连接层的数据和参数的形状,
            # 其中item.parameters()[0]是权重参数w,item.parameters()[1]是偏置参数b
            print(item.full_name(), x.shape, item.parameters()[0].shape, item.parameters()[1].shape)
        else:
            # 池化层没有参数
            print(item.full_name(), x.shape)
            
            
            
    上述代码输出为:
代码语言:javascript
复制
conv2d_0 [3, 96, 55, 55] [96, 3, 11, 11] [96]
pool2d_0 [3, 96, 27, 27]
conv2d_1 [3, 256, 27, 27] [256, 96, 5, 5] [256]
pool2d_1 [3, 256, 13, 13]
conv2d_2 [3, 192, 13, 13] [192, 256, 3, 3] [192]
conv2d_3 [3, 192, 13, 13] [192, 192, 3, 3] [192]
conv2d_4 [3, 256, 13, 13] [256, 192, 3, 3] [256]
pool2d_2 [3, 256, 6, 6]
linear_0 [3, 4096] [9216, 4096] [4096]
dropout_0 [3, 4096]
linear_1 [3, 4096] [4096, 4096] [4096]
dropout_1 [3, 4096]
linear_2 [3, 10] [4096, 10] [10]

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 论文主要贡献:
  • 输入层:
  • 第一层:
  • 第二层:
  • 第三层:
  • 第四层:
  • 第五层:
  • 第六层:
  • 第七层:
  • 第八层: 全连接并最终softmax输出到1000个分类。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档