今天来仔细讲一下卷基层和全连接层训练参数个数如何确定的问题。我们以Mnist为例,首先贴出网络配置文件:

 

  1. name: "LeNet"  
  2. layer {  
  3.   name: "mnist"  
  4.   type: "Data"  
  5.   top: "data"  
  6.   top: "label"  
  7.   data_param {  
  8.     source: "examples/mnist/mnist-train-leveldb"  
  9.     backend: LEVELDB  
  10.     batch_size: 64  
  11.   }  
  12.   transform_param {  
  13.     scale: 0.00390625  
  14.   }  
  15.   include: { phase: TRAIN }  
  16. }  
  17. layer {  
  18.   name: "mnist"  
  19.   type: "Data"  
  20.   top: "data"  
  21.   top: "label"  
  22.   data_param {  
  23.     source: "examples/mnist/mnist-test-leveldb"  
  24.     backend: LEVELDB  
  25.     batch_size: 100  
  26.   }  
  27.   transform_param {  
  28.     scale: 0.00390625  
  29.   }  
  30.   include: { phase: TEST }  
  31. }  
  32. layer {  
  33.   name: "conv1"  
  34.   type: "Convolution"  
  35.   bottom: "data"  
  36.   top: "conv1"  
  37.   param {  
  38.     lr_mult: 1  
  39.   }  
  40.   param {  
  41.     lr_mult: 2  
  42.   }  
  43.   convolution_param {  
  44.     num_output: 20  
  45.     kernel_size: 5  
  46.     stride: 1  
  47.     weight_filler {  
  48.       type: "xavier"  
  49.     }  
  50.     bias_filler {  
  51.       type: "constant"  
  52.     }  
  53.   }  
  54. }  
  55. layer {  
  56.   bottom: "conv1"  
  57.   top: "conv1"  
  58.   name: "bn_conv1"  
  59.   type: "BatchNorm"  
  60.   param {  
  61.     lr_mult: 0  
  62.     decay_mult: 0  
  63.   }   
  64.   param {  
  65.     lr_mult: 0  
  66.     decay_mult: 0  
  67.   }  
  68.   param {  
  69.     lr_mult: 0  
  70.     decay_mult: 0  
  71.   }  
  72. }  
  73. layer {  
  74.   bottom: "conv1"  
  75.   top: "conv1"  
  76.   name: "scale_conv1"  
  77.   type: "Scale"  
  78.   scale_param {  
  79.     bias_term: true  
  80.   }  
  81. }  
  82. layer {  
  83.   name: "pool1"  
  84.   type: "Pooling"  
  85.   bottom: "conv1"  
  86.   top: "pool1"  
  87.   pooling_param {  
  88.     pool: MAX  
  89.     kernel_size: 2  
  90.     stride: 2  
  91.   }  
  92. }  
  93. layer {  
  94.   name: "relu_pool1"  
  95.   type: "ReLU"  
  96.   bottom: "pool1"  
  97.   top: "pool1"  
  98. }  
  99. layer {  
  100.   name: "conv2"  
  101.   type: "Convolution"  
  102.   bottom: "pool1"  
  103.   top: "conv2"  
  104.   param {  
  105.     lr_mult: 1  
  106.   }  
  107.   param {  
  108.     lr_mult: 2  
  109.   }  
  110.   convolution_param {  
  111.     num_output: 50  
  112.     kernel_size: 5  
  113.     stride: 1  
  114.     weight_filler {  
  115.       type: "xavier"  
  116.     }  
  117.     bias_filler {  
  118.       type: "constant"  
  119.     }  
  120.   }  
  121. }  
  122. layer {  
  123.   bottom: "conv2"  
  124.   top: "conv2"  
  125.   name: "bn_conv2"  
  126.   type: "BatchNorm"  
  127.   param {  
  128.     lr_mult: 0  
  129.     decay_mult: 0  
  130.   }   
  131.   param {  
  132.     lr_mult: 0  
  133.     decay_mult: 0  
  134.   }  
  135.   param {  
  136.     lr_mult: 0  
  137.     decay_mult: 0  
  138.   }  
  139. }  
  140. layer {  
  141.   bottom: "conv2"  
  142.   top: "conv2"  
  143.   name: "scale_conv2"  
  144.   type: "Scale"  
  145.   scale_param {  
  146.     bias_term: true  
  147.   }  
  148. }  
  149. layer {  
  150.   name: "pool2"  
  151.   type: "Pooling"  
  152.   bottom: "conv2"  
  153.   top: "pool2"  
  154.   pooling_param {  
  155.     pool: MAX  
  156.     kernel_size: 2  
  157.     stride: 2  
  158.   }  
  159. }  
  160. layer {  
  161.   name: "relu_pool2"  
  162.   type: "ReLU"  
  163.   bottom: "pool2"  
  164.   top: "pool2"  
  165. }  
  166. layer {  
  167.   name: "ip1"  
  168.   type: "InnerProduct"  
  169.   bottom: "pool2"  
  170.   top: "ip1"  
  171.   param {  
  172.     lr_mult: 1  
  173.   }  
  174.   param {  
  175.     lr_mult: 2  
  176.   }  
  177.   inner_product_param {  
  178.     num_output: 500  
  179.     weight_filler {  
  180.       type: "xavier"  
  181.     }  
  182.     bias_filler {  
  183.       type: "constant"  
  184.     }  
  185.   }  
  186. }  
  187. layer {  
  188.   name: "relu1"  
  189.   type: "ReLU"  
  190.   bottom: "ip1"  
  191.   top: "ip1"  
  192. }  
  193. layer {  
  194.   name: "ip2"  
  195.   type: "InnerProduct"  
  196.   bottom: "ip1"  
  197.   top: "ip2"  
  198.   param {  
  199.     lr_mult: 1  
  200.   }  
  201.   param {  
  202.     lr_mult: 2  
  203.   }  
  204.   inner_product_param {  
  205.     num_output: 10  
  206.     weight_filler {  
  207.       type: "xavier"  
  208.     }  
  209.     bias_filler {  
  210.       type: "constant"  
  211.     }  
  212.   }  
  213. }  
  214. layer {  
  215.   name: "accuracy"  
  216.   type: "Accuracy"  
  217.   bottom: "ip2"  
  218.   bottom: "label"  
  219.   top: "accuracy"  
  220.   include {  
  221.     phase: TEST  
  222.   }  
  223. }  
  224. layer {  
  225.   name: "loss"  
  226.   type: "SoftmaxWithLoss"  
  227.   bottom: "ip2"  
  228.   bottom: "label"  
  229.   top: "loss"  
  230. }  

OK,在开始讲解之前我们先说明几个问题:

1、输入的图片大小是28*28,;

2、我们将分三部分讲解,因为三部分计算方式不同;

3、由于偏置量b的个数与卷积核的个数相同,因此我们讲解的主要是权重,偏置量个数加上就可以了。

1、第一个卷积conv1,之所把第一个卷积单独拿出来,是因为他和后面的卷积计算方式不同,他训练参数个数计算并不关心输入,这里的数据就是指data层中batch_size大小。也可以说第一个卷基层并不关心特征组合,只是提取特征。

在每一个卷积层中都以一个参数num_output,这个参数怎么理解呢?两种理解方式1、卷积的种类个数;2、输出特征图的个数,我么可以认为一种卷积核提取一种特征,然后输出一张特征。

由于第一个卷积层只是简单的提取特征,并没有进行特征组合,因此训练参数个数计算只是num_output*kernel_size^2.这里怎么理解呢?(由于我不会画图,需要大家一点想象力)假设我们的输入有5张图,num_output=3,kernel_size=5。没有进行特征组合,只是简单提取特征,指的是一种卷积核对5张图的同一区域使用相同的权重进行卷积计算,这样每幅图使用相同的卷积核就能提取到相同的特征,然后相同的特征组成一张特征图。

2、第二个卷积至全连接层之间的卷积,这些卷积层的训练参数个数和输入特征图的数量有关,因为这些卷积层需要进行特征组合。举个例子:conv1的num_output=20,说明卷积1层输出了20个特征图,那么卷积2层的输入就是20。conv2的num_output=50,kernel_size=5,那么计算公式是20*50*5*5.

为什么这些卷积层的训练个数和输入的特征图的数量有关呢?重点还是在特征组合。输入的20个特征图,每个特征图代表一种特征,如果我们给每种特征不同的权重那是不是就进行了特征组合呢?conv2的卷积核是5*5,对20个特征图进行卷积,那就会有20组(5*5)个连接(每张特征图是一组),如果这20组卷积核的权重相同,那就回到了第一个卷积层的情况,没有对20个特征进行组合,因为权重相同嘛!只能看成简单的相加,如果20组权重不同,是不是就进行了线性相加了呢?所以对于一个卷积核(5*5)我们要学习的参数不是25个,而是25*20个。说到这里我相信你应该已经明白了吧!

3、全连接层,全连接层就是普通的神经网络,全连接层的num_output和卷积层中num_output的理解不同,全连接层的num_output应该看成神经元的个数。

3.1、这里要细分一下,先说IP1也就是第一个全连接层。先讲一下ip1的输入,比如最后一个卷积层的num_output=50,那么IP1的输入是50吗?注意这里不是,要理解这个问题,我们只需将全连接层看成是一些列的普通神经网络就可以。比如IP1的num_output=500,也就是有500个神经元,每个神经元都和输入的每一个像素相连,最后一个卷积层输出了50个特征图,每个特征图大小是4*4(输入图像是28*28)那么每个神经元连接的个数就是50*16=800个,也就有800个参数需要学习。总共有500个神经元,因此对于IP1层共需要学习800*500=400,000个参数。

3.2、对于iP2层,iP2的输入就是IP1的输出了,因为IP1输出的不是图像了(或矩阵)而是500个数字。比如ip2的num_output=10,也就是输出数据500维,输出10维的普通神经网络,那么需要学习的参数就是500*10=5000个。

 

以上,只是我的个人见解,如果有错误,欢迎大家指正!

文章出处: http://blog.csdn.net/sunshine_in_moon/article/details/51434908

 

 

 

卷积中要注意的其他点:

1)尽量使用多层fliter尺寸小的卷积层代替一层filter较大的卷积层。

    因为使用多层filter较小的卷积层所能观察到的区域大小和一层filter较大的卷积层是相同的,但是前者可以看到更加抽象的特征,提取的特征表达性能更佳。

    此外,前者引入的参数规模相比后者更小。比如,使用3层filter为3X3的卷积层代替1层filter为7X7的卷积层,假设输入的volume为C个通道则前者参数

    个数为

 2)为什么使用padding?

     使用padding的好处是使得卷积前后的图像尺寸保持相同,可以保持边界的信息。一般padding的大小为P=(F-1)/2,其中F为filter的尺寸。如果不使用

     paddding,则要仔细跟踪图像尺寸的变化,确保每一层filter和stride正确的被使用。

  3)为什么stride一般设为1?

     stride设为1实际表现效果更好,将下采样的工作全部交给池化层。

   (4)输入层(input layer)尺寸一般应该能被2整除很多次,比如32(CIFAR-10),64,96(STL-10),224(common ImageNet ConvNets),384和512。

   (5)尽量使用filter较小(3x3 or 至多 5x5)的卷积层,如果要使用较大的filter(比如7x7),一般也只在第一个卷积层。

   (6)有时候由于参数太多,内存限制,会在第一个卷积层使用较大filter(7x7)和stride(2)(参考 ZF Net),或者filter(11x11),stride(4)

        (参考 AlexNet)。

 

 
 

1)尽量使用多层fliter尺寸小的卷积层代替一层filter较大的卷积层。

    因为使用多层filter较小的卷积层所能观察到的区域大小和一层filter较大的卷积层是相同的,但是前者可以看到更加抽象的特征,提取的特征表达性能更佳。

    此外,前者引入的参数规模相比后者更小。比如,使用3层filter为3X3的卷积层代替1层filter为7X7的卷积层,假设输入的volume为C个通道则前者参数

    个数为

 2)为什么使用padding?

     使用padding的好处是使得卷积前后的图像尺寸保持相同,可以保持边界的信息。一般padding的大小为P=(F-1)/2,其中F为filter的尺寸。如果不使用

     paddding,则要仔细跟踪图像尺寸的变化,确保每一层filter和stride正确的被使用。

  3)为什么stride一般设为1?

     stride设为1实际表现效果更好,将下采样的工作全部交给池化层。

   (4)输入层(input layer)尺寸一般应该能被2整除很多次,比如32(CIFAR-10),64,96(STL-10),224(common ImageNet ConvNets),384和512。

   (5)尽量使用filter较小(3x3 or 至多 5x5)的卷积层,如果要使用较大的filter(比如7x7),一般也只在第一个卷积层。

   (6)有时候由于参数太多,内存限制,会在第一个卷积层使用较大filter(7x7)和stride(2)(参考 ZF Net),或者filter(11x11),stride(4)

        (参考 AlexNet)。