美文网首页
Caffe源代码学习 — AlexNet(Caffenet.py

Caffe源代码学习 — AlexNet(Caffenet.py

作者: 江南竹影 | 来源:发表于2018-03-08 15:47 被阅读0次

    欢迎访问我的个人Blog: zengzeyu.com

    导言


    源码位置:caffe/examples/pycaffe/caffenet.py
    该文件源代码是经典模型AlexNet的Caffe实现,有兴趣的小伙伴去拜读一下论文: ImageNet Classification with Deep Convolutional Neural Networks.

    源码解读


    1. 导入模块


    from __future__ import print_function
    from caffe import layers as L, params as P, to_proto
    from caffe.proto import caffe_pb2
    

    2. 定义Layer函数


    包括: 卷积层(Convolution Layer)、全连接层(Full Connected Layer)和池化层(Pooling Layer)

    2.1 卷积层(Convolution Layer)函数

    def conv_relu(bottom, ks, nout, stride=1, pad=0, group=1):
        conv = L.Convolution(bottom, kernel_size=ks, stride=stride,
                                    num_output=nout, pad=pad, group=group)
        return conv, L.ReLU(conv, in_place=True)
    

    1. 函数输入

    • bottom - 输入节点(blob)名
    • ks - 卷积核尺寸(kernel size
    • nout - 输出深度尺寸(number output
    • stride - 卷积核滑窗距离
    • pad - 图像边缘添加尺寸,即在图像周围一周添加尺寸为pad的空白像素
    • group - 将数据进行分开训练堆数目

    2. 调用Caffe卷基层生成函数

    • conv = L.Convolution(bottom, kernel_size=ks, stride=stride,num_output=nout, pad=pad, group=group)

    3. 返回参数

    • conv - 卷积层配置
    • L.ReLU(conv, in_place=True) - 卷积后的数据经过ReLU激活函数得到的数据

    2.2 全连接层(Full Connected Layer)

    def fc_relu(bottom, nout):
        fc = L.InnerProduct(bottom, num_output=nout)
        return fc, L.ReLU(fc, in_place=True)
    

    1. 调用Caffe内积函数

    • fc = L.InnerProduct(bottom, num_output=nout)

    2. 返回参数

    • fc, L.ReLU(fc, in_place=True) - 全连接分类之后数据通过ReLU函数

    2.3 池化层(Pooling Layer)

    def max_pool(bottom, ks, stride=1):
        return L.Pooling(bottom, pool=P.Pooling.MAX, kernel_size=ks, stride=stride)
    

    调用Caffe池化层生成函数

    • L.Pooling)()
    • pool=P.Pooling.MAX - 池化类型选择MAX,即取模板内最大值输出

    3. 定义网络结构


    data, label = L.Data(source=lmdb, backend=P.Data.LMDB, batch_size=batch_size, ntop=2,
            transform_param=dict(crop_size=227, mean_value=[104, 117, 123], mirror=True))
    
             # the net itself
        conv1, relu1 = conv_relu(data, 11, 96, stride=4)
        pool1 = max_pool(relu1, 3, stride=2)
        norm1 = L.LRN(pool1, local_size=5, alpha=1e-4, beta=0.75)
        conv2, relu2 = conv_relu(norm1, 5, 256, pad=2, group=2)
        pool2 = max_pool(relu2, 3, stride=2)
        norm2 = L.LRN(pool2, local_size=5, alpha=1e-4, beta=0.75)
        conv3, relu3 = conv_relu(norm2, 3, 384, pad=1)
        conv4, relu4 = conv_relu(relu3, 3, 384, pad=1, group=2)
        conv5, relu5 = conv_relu(relu4, 3, 256, pad=1, group=2)
        pool5 = max_pool(relu5, 3, stride=2)
        fc6, relu6 = fc_relu(pool5, 4096)
        drop6 = L.Dropout(relu6, in_place=True)
        fc7, relu7 = fc_relu(drop6, 4096)
        drop7 = L.Dropout(relu7, in_place=True)
        fc8 = L.InnerProduct(drop7, num_output=1000)
        loss = L.SoftmaxWithLoss(fc8, label)
    
        if include_acc:
            acc = L.Accuracy(fc8, label)
            return to_proto(loss, acc)
        else:
            return to_proto(loss)
    

    1. 函数输入

    • lmdb - 文件名
    • batch_size - 每次训练输入样本数目
    • include_acc - 加速?

    2. 调用Caffe数据层输入函数(Data)
    L.Data(source=lmdb, backend=P.Data.LMDB, batch_size=batch_size, ntop=2, transform_param=dict(crop_size=227, mean_value=[104, 117, 123], mirror=True))

    • backend - 数据类型
    • ntop - 输出blob数目,因为数据层处理数据输出data和label,所以值为 2
    • transform_param - 对单个图片处理: crop_size图片剪裁大小,mean_valueRGB图像需要减去的值(目的是更好突出特征)和mirror镜像处理。
    Layer Operation Output
    Data crop_size:227, mean_value: [104, 117, 123], mirror: true data: 227x227x3; label: 227x227x1
    1 conv1 -> relu1 -> pool1 -> norm1 27x27x96
    2 conv2 -> relu2 -> pool2 -> norm2 13x13x256
    3 conv3 -> relu3 11x11x384
    4 conv4 -> relu4 11x11x384
    5 conv5 -> relu5 -> pool5 6x6x256
    6 fc6 -> relu6 -> drop6 4096
    7 fc7 -> relu7 -> drop7 4096
    8 fc8 -> loss 1000

    3. 网络结构
    此博客绘制了AlexNet网络结构图和数据流动图,方便直观理解网络结构,可移步:深度学习之图像分类模型AlexNet解读
    第1-5层为卷积层,如下表所示:

    Layer Operation Output
    Data crop_size:227, mean_value: [104, 117, 123], mirror: true data: 227x227x3; label: 227x227x1
    1 conv1 -> relu1 -> pool1 -> norm1 27x27x96
    2 conv2 -> relu2 -> pool2 -> norm2 13x13x256
    3 conv3 -> relu3 11x11x384
    4 conv4 -> relu4 11x11x384
    5 conv5 -> relu5 -> pool5 6x6x256
    6 fc6 -> relu6 -> drop6 4096
    7 fc7 -> relu7 -> drop7 4096
    8 fc8 -> loss 1000

    以第1层代码为例进行分析:

    1. 第1层 = 卷积层(conv1+relu1) + 池化层(pool1) + 归一化(norm1)

    (1). 第1层 - 卷积层(conv1+relu1)
    作用:提取局部特征,使用ReLU作为CNN的激活函数,并验证其效果在较深的网络超过了Sigmoid,成功解决了Sigmoid在网络较深时的梯度弥散问题。
    conv1, relu1 = conv_relu(data, 11, 96, stride=4)

    • 数据:数据层输出data数据
    • 卷积核大小: 11
    • 输出节点深度: 96
    • 滑窗距离: 4

    (2). 第1层 - 池化层(pool1)
    作用:提取最大值,避免平均池化的模糊化效果。在AlexNet中提出让步长比池化核的尺寸小,这样池化层的输出之间会有重叠和覆盖,提升了特征的丰富性。
    pool1 = max_pool(relu1, 3, stride=2)

    • 数据: relu1
    • 模板核大小: 3
    • 滑窗距离: 2

    (3). 第1层 - 局部响应归一化(Local Response Normalize)(norm1)
    作用:对局部神经元的活动创建竞争机制,使得其中响应比较大的值变得相对更大,并抑制其他反馈较小的神经元,增强了模型的泛化能力
    norm1 = L.LRN(pool1, local_size=5, alpha=1e-4, beta=0.75)

    • 数据: pool1
    • 取值模板尺寸: 5
    • alpha: 0.0001
    • beta: 0.75

    4. 输出网络结构文件(.prototxt)


    def make_net():
        with open('train.prototxt', 'w') as f:
            print(caffenet('/path/to/caffe-train-lmdb'), file=f)
    
        with open('test.prototxt', 'w') as f:
            print(caffenet('/path/to/caffe-val-lmdb', batch_size=50, include_acc=True), file=f)
    

    5. 运行


    if __name__ == '__main__':
        make_net()
    

    总结


    Caffene.py是入门Caffe较好的源代码,结合原论文看,同时能加深对网络结构的理解,补充理论知识。下面根据这个example形式构建自己的网络结构,其中第一步,也是学习深度学习最重要的一步,编写自己的数据类型接口层程序。

    以上。

    附:

    1. AlexNet网络总结
    2. 深度学习之图像分类模型AlexNet解读

    相关文章

      网友评论

          本文标题:Caffe源代码学习 — AlexNet(Caffenet.py

          本文链接:https://www.haomeiwen.com/subject/eanefftx.html