caffe入门应用方法(一)——网络层参数配置解析

要运行caffe,需要先创建一个模型(model),如比较常用的Lenet,Alex等, 而一个模型由多个层(layer)构成,每一层又由许多参数组成。所有的参数都定义在caffe.proto这个文件中。要熟练使用caffe,最重要的就是学会配置文件(prototxt)的编写。

层有很多种类型,比如Data,Convolution,Pooling等,层之间的数据流动是以Blobs的方式进行。

今天本文主要介绍神经网络中常用的网络层:数据层,卷积层,激活层,全连接层等.

数据层

数据层是每个模型的最底层,是模型的入口,不仅提供数据的输入,也提供数据从Blobs转换成别的格式进行保存输出。通常数据的预处理(如减去均值, 放大缩小, 裁剪和镜像等),也在这一层设置参数实现。

数据来源可以来自高效的数据库(如LevelDB和LMDB),也可以直接来自于内存。如果不是很注重效率的话,数据也可来自磁盘的hdf5文件和图片格式文件。

所有的数据层的都具有的公用参数:先看示例

layer {
  name: "cifar"
  type: "Data"
  top: "data"  #一般用bottom表示输入,top表示输出,多个top代表有多个输出  zhongxinhua
  top: "label"
  include {
    phase: TRAIN #训练网络分为训练阶段和自测试阶段,如果没写include则表示该层即在测试中,又在训练中
  }
  transform_param {
    mean_file: "examples/cifar10/mean.binaryproto" #用一个配置文件来进行均值的操作
    transform_param {
    scale: 0.00390625  # 1/255 guiyihua
    mirror: 1  # 1表示开启镜像,0表示关闭,也可用ture和false来表示
    # 剪裁一个 227*227的图块,在训练阶段随机剪裁,在测试阶段从中间裁剪
    crop_size: 227
  }
  }
  data_param {
    source: "examples/cifar10/cifar10_train_lmdb" #数据库来源
    batch_size: 64 #每次批处理的个数
    backend: LMDB #选用数据的名称
  }
}
  • name: 表示该层的名称,可随意取
  • type: 层类型,如果是Data,表示数据来源于LevelDB或LMDB。根据数据的来源不同,数据层的类型也不同(后面会详细阐述)。一般在练习的时候,我们都是采 用的LevelDB或LMDB数据,因此层类型设置为Data。
  • top或bottom: 每一层用bottom来输入数据,用top来输出数据。如果只有top没有bottom,则此层只有输出,没有输入。反之亦然。如果有多个 top或多个bottom,表示有多个blobs数据的输入和输出。
  • data 与 label: 在数据层中,至少有一个命名为data的top。如果有第二个top,一般命名为label。 这种(data,label)配对是分类模型所必需的。
  • include: 一般训练的时候和测试的时候,模型的层是不一样的。该层(layer)是属于训练阶段的层,还是属于测试阶段的层,需要用include来指定。如果没有include参数,则表示该层既在训练模型中,又在测试模型中。
  • transform_param: 数据的预处理,可以将数据变换到定义的范围内。如设置scale为0.00390625,实际上就是1/255, 即将输入数据由0-255归一化到0-1之间, mean_file参数将所有输入数据减去一个平均值,表示将数据中心化.
  • data_param: 输入数据相关配置,来源方式,批处理大小,数据名称.

使用LMDB源

layer {
  name: "mnist"
  type: "Data"
  top: "data"
  top: "label"
  include {
    phase: TRAIN
  }
  transform_param {
    scale: 0.00390625
  }
  data_param {
    source: "examples/mnist/mnist_train_lmdb"
    batch_size: 64
    backend: LMDB
  }
}

使用HDF5数据源

layer {
  name: "data"
  type: "HDF5Data"
  top: "data"
  top: "label"
  hdf5_data_param {
    source: "examples/hdf5_classification/data/train.txt"
    batch_size: 10
  }
}

数据直接来源与图片

#/path/to/images/img3423.jpg 2
#/path/to/images/img3424.jpg 13
#/path/to/images/img3425.jpg 8

layer {
  name: "data"
  type: "ImageData" #类型
  top: "data"
  top: "label"
  transform_param {
    mirror: false
    crop_size: 227
    mean_file: "data/ilsvrc12/imagenet_mean.binaryproto"
  }
  image_data_param {
    source: "examples\_temp\file_list.txt"
    batch_size: 50
    new_height: 256 #如果设置就对图片进行resize操作
    new_width: 256
  }
}

数据来自于内存

layer {
  top: "data"
  top: "label"
  name: "memory_data"
  type: "MemoryData"
  memory_data_param{
    batch_size: 2
    height: 100
    width: 100
    channels: 1
  }
  transform_param {
    scale: 0.0078125
    mean_file: "mean.proto"
    mirror: false
  }
}

数据来源于Windows

layer {
  name: "data"
  type: "WindowData"
  top: "data"
  top: "label"
  include {
    phase: TRAIN
  }
  transform_param {
    mirror: true
    crop_size: 227
    mean_file: "data/ilsvrc12/imagenet_mean.binaryproto"
  }
  window_data_param {
    source: "examples/finetune_pascal_detection/window_file_2007_trainval.txt"
    batch_size: 128
    fg_threshold: 0.5
    bg_threshold: 0.5
    fg_fraction: 0.25
    context_pad: 16
    crop_mode: "warp"
  }
}

Reshape层

layer {
    name: "reshape"
    type: "Reshape"
    bottom: "input"
    top: "output"
    reshape_param {
      shape {
        dim: 0  # copy the dimension from below
        dim: 2
        dim: 3
        dim: -1 # infer it from the other dimensions
      }
    }
  }

有一个可选的参数组shape, 用于指定blob数据的各维的值(blob是一个四维的数据:ncw*h)。

  • dim:0 表示维度不变,即输入和输出是相同的维度。
  • dim:2 或 dim:3 将原来的维度变成2或3
  • dim:-1 表示由系统自动计算维度。数据的总量不变,系统会根据blob数据的其它三维来自动计算当前维的维度值 。

假设原数据为:32*3*28*28, 表示32张3通道的28*28的彩色图片
shape {
dim: 0
dim: 0
dim: 14
dim: -1
}
输出数据为:32*3*14*56

卷积层

layer {
  name: "conv1"
  type: "Convolution"
  bottom: "data"
  top: "conv1"
  param {
    lr_mult: 1  #lr_mult: 学习率的系数,最终的学习率是这个数乘以solver.prototxt配置文件中的base_lr。如果有两个lr_mult, 则第一个表示权值的学习率,第二个表示偏置项的学习率。一般偏置项的学习率是权值学习率的两倍。
  }
  param {
    lr_mult: 2
  }
  convolution_param {
    num_output: 20 #卷积核(filter)的个数
    kernel_size: 5 #卷积核的大小
    stride: 1 #卷积核的步长,默认为1
    pad: 0 #扩充边缘,默认为0,不扩充
    weight_filler {
      type: "xavier" #权值初始化。 默认为“constant",值全为0,很多时候我们用"xavier"算法来进行初始化,也可以设置为”gaussian"
    }
    bias_filler {
      type: "constant" #偏置项的初始化。一般设置为"constant",值全为0
    }
  }
}
  • lr_mult: 学习率的系数,最终的学习率是这个数乘以solver.prototxt配置文件中的base_lr。如果有两个lr_mult, 则第一个表示权值的学习率,第二个表示偏置项的学习率。一般偏置项的学习率是权值学习率的两倍。

在后面的convolution_param中,我们可以设定卷积层的特有参数。
必须设置的参数:

  • num_output: 卷积核(filter)的个数
  • kernel_size: 卷积核的大小。如果卷积核的长和宽不等,需要用kernel_h和kernel_w分别设定

其它参数:

  • stride: 卷积核的步长,默认为1。也可以用stride_h和stride_w来设置。
  • pad: 扩充边缘,默认为0,不扩充。 扩充的时候是左右、上下对称的,比如卷积核的大小为5*5,那么pad设置为2,则四个边缘都扩充2个像素,即宽度和高度都扩充了4个像素,这样卷积运算之后的特征图就不会变小。也可以通过pad_h和pad_w来分别设定。
  • weight_filler: 权值初始化。 默认为“constant",值全为0,很多时候我们用"xavier"算法来进行初始化,也可以设置为”gaussian".
  • bias_filler: 偏置项的初始化。一般设置为"constant",值全为0。
  • bias_term: 是否开启偏置项,默认为true, 开启
  • group: 分组,默认为1组。如果大于1,限制卷积的连接操作在一个子集内。如果我们根据图像的通道来分组,那么第i个输出分组只能与第i个输入分组进行连接。

输入:n*c0*w0*h0
输出:n*c1*w1*h1

其中,c1就是参数中的num_output,生成的特征图个数

 w1=(w0+2\*pad-kernel_size)/stride+1;
 h1=(h0+2\*pad-kernel_size)/stride+1;

如果设置stride为1,前后两次卷积部分存在重叠。如果设置pad=(kernel_size-1)/2,则运算后,宽度和高度不变。

Pooling层

也叫池化层,为了减少运算量和数据维度而设置的一种层。

layer {
  name: "pool1"
  type: "Pooling"
  bottom: "conv1"
  top: "pool1"
  pooling_param {
    pool: MAX #池化方法,默认为MAX。目前可用的方法有MAX, AVE
    kernel_size: 3 #池化的核大小
    stride: 2 #池化的步长,默认为1。一般我们设置为2,即不重叠。
  }
}

必须设置的参数:

  • kernel_size: 池化的核大小。也可以用kernel_h和kernel_w分别设定。

其它参数:

  • pool: 池化方法,默认为MAX。目前可用的方法有MAX, AVE, 或STOCHASTIC
  • pad: 和卷积层的pad的一样,进行边缘扩充。默认为0
  • stride: 池化的步长,默认为1。一般我们设置为2,即不重叠。也可以用stride_h和stride_w来设置。

pooling层的运算方法基本是和卷积层是一样的。

输入:ncw0h0
输出:n
cw1h1

和卷积层的区别就是其中的c保持不变

 w1=(w0+2*pad-kernel_size)/stride+1;
 h1=(h0+2*pad-kernel_size)/stride+1;

如果设置stride为2,前后两次卷积部分不重叠。100*100的特征图池化后,变成50*50.

Dropout层

layer {
  name: "drop7"
  type: "Dropout"
  bottom: "fc7-conv"
  top: "fc7-conv"
  dropout_param {
    dropout_ratio: 0.5
  }
}

设置一个dropout_ratio去除层次中参数数量的比率.

Local Response Normalization (LRN)层

此层是对一个输入的局部区域进行归一化,达到“侧抑制”的效果。可去搜索AlexNet或GoogLenet,里面就用到了这个功能.

layers {
  name: "norm1"
  type: LRN
  bottom: "pool1"
  top: "norm1"
  lrn_param {
    local_size: 5
    alpha: 0.0001
    beta: 0.75
  }
}

参数:全部为可选,没有必须

  • local_size: 默认为5。如果是跨通道LRN,则表示求和的通道数;如果是在通道内LRN,则表示求和的正方形区域长度。
  • alpha: 默认为1,归一化公式中的参数。
  • beta: 默认为5,归一化公式中的参数。
  • norm_region: 默认为ACROSS_CHANNELS。有两个选择,ACROSS_CHANNELS表示在相邻的通道间求和归一化。WITHIN_CHANNEL表示在一个通道内部特定的区域内进行求和归一化。与前面的local_size参数对应。

激活层

1.Sigmoid层

layer {
  name: "test"
  bottom: "conv"
  top: "test"
  type: "Sigmoid"
}

2.ReLU层

layer {
  name: "relu1"
  type: "ReLU"
  bottom: "pool1"
  top: "pool1"
}

对每个输入数据,利用sigmoid函数执行操作。这种层设置比较简单,没有额外的参数。ReLU是目前使用最多的激活函数,主要因为其收敛更快,并且能保持同样效果。

全连接层

layer {
  name: "ip1"
  type: "InnerProduct"
  bottom: "pool2"
  top: "ip1"
  param {
    lr_mult: 1
  }
  param {
    lr_mult: 2
  }
  inner_product_param {
    num_output: 500
    weight_filler {
      type: "xavier"
    }
    bias_filler {
      type: "constant"
    }
  }
}

全连接层,把输入当作成一个向量,输出也是一个简单向量(把输入数据blobs的width和height全变为1)。

输入: n*c0*h*w
输出: n*c1*1*1

全连接层实际上也是一种卷积层,只是它的卷积核大小和原数据大小一致。因此它的参数基本和卷积层的参数一样。

lr_mult: 学习率的系数,最终的学习率是这个数乘以solver.prototxt配置文件中的base_lr。如果有两个lr_mult, 则第一个表示权值的学习率,第二个表示偏置项的学习率。一般偏置项的学习率是权值学习率的两倍。

必须设置的参数:

  • num_output: 过滤器(filfter)的个数

其它参数:

  • weight_filler: 权值初始化。 默认为“constant",值全为0,很多时候我们用"xavier"算法来进行初始化,也可以设置为”gaussian"
  • bias_filler: 偏置项的初始化。一般设置为"constant",值全为0。
  • bias_term: 是否开启偏置项,默认为true, 开启
    复制代码

准确率层

layer {
  name: "accuracy"
  type: "Accuracy"
  bottom: "ip2"
  bottom: "label"
  top: "accuracy"
  include {
    phase: TEST
  }
}

输出分类(预测)精确度,只有test阶段才有,因此需要加入include参数。

softmax-loss layer:输出loss值

layer {
  name: "loss"
  type: "SoftmaxWithLoss"
  bottom: "ip1"
  bottom: "label"
  top: "loss"
}

softmax layer: 输出似然值

layers {
  bottom: "cls3_fc"
  top: "prob"
  name: "prob"
  type: “Softmax"
}

softmax-loss层和softmax层计算大致是相同的。softmax是一个分类器,计算的是类别的概率(Likelihood),是Logistic Regression 的一种推广。Logistic Regression 只能用于二分类,而softmax可以用于多分类。

用户可能最终目的就是得到各个类别的概率似然值,这个时候就只需要一个 Softmax层,而不一定要进行softmax-Loss 操作;或者是用户有通过其他什么方式已经得到了某种概率似然值,然后要做最大似然估计,此时则只需要后面的 softmax-Loss 而不需要前面的 Softmax 操作。因此提供两个不同的 Layer 结构比只提供一个合在一起的 Softmax-Loss Layer 要灵活许多。

推荐阅读更多精彩内容

  • CNN on TensorFlow 本文大部分内容均参考于: An Intuitive Explanation o...
    _Randolph_阅读 6,827评论 2 31
  • 声明:本文为个人因方便、共享而对《Node.js,MongoDB and AngularJS》的翻译,若有侵权请及...
    琚致远阅读 63评论 0 1
  • 文丨绿豆侠 这是绿豆侠,自2014年4月23日以来的,第10篇文章 1、《少有人走的路:心智成熟的旅程...
    绿豆侠阅读 178评论 0 1
  • 我们已经慢慢的长大了,成长好像海里无法避免的龙卷风,它将我们带到了一个又一个的漩涡,任我们在里面挣扎起伏.越想挣脱...
    倦々待阅读 50评论 0 0