CNN中卷积层和池化的作用和理解

承接上文对CNN的介绍[学习笔记P20-CNN],下面来看看一些细节梳理:

CNN框架:

池化层(pooling layer)也叫做子采样层(subsampling layer),其作用是进行特征选择,降低特征数量,并从而减少参数数量。

为什么conv-layer之后需要加pooling_layer?

卷积层【局部连接和权重共享】虽然可以显著减少网络中连接的数量,但特征映射组中的神经元个数并没有显著减少。如果后面接一个分类器,分类器的输入维数依然很高,很容易过拟合。为了解决这个问题,可以再卷积层之后加上一个pooling layer,从而降低特征维数,避免过拟合。

Pooling是指对每个区域进行下采样(Down Sampling)得到一个之,作为这个区域的概括。常用的pooling 函数有两种:

1)最大池化(Max Pooling):一般是取一个区域内所有神经元的最大值。

2)平均池化(Mean Pooling):一般是取区域内所有神经元的平均值。

上图给出了采样max pooling进行子采样操作的示例。可以看出,汇聚层不但 可以有效地减少神经元的数量,还可以使得网络对

一些小的局部形态改变保持 不变性,并拥有更大的感受野。
 
注意:过大的采样区域会急剧减少神经元的数量,会造成过多的信息损失。
 

如果只有conv-layer会怎么样?

1)过于执着局部特征学习,忽视全局

      经过3层conv-layer 3X3filter后,相当于只用了1层conv-layer7X7filter来扫描原图(28-7+1=22);对原图整体状态信息学习很少;从底层细小局部简单的特征到高层复杂全局性更高的特征,推进速度太慢。

2)计算量仍然很大

为什么使用pooling layer?

1)大幅降低parameters,降低计算量

2)通过多层conv-layer间接用更大的filter扫描原图

为什么Max pooling要优于strided convolution和average pooling?

1)strided convolution的弊端

跳格平移,容易overlook,忽视或者丢失细节数据。

2)average pooling的弊端

取均值,容易造成稀释特征程度的效果问题。

最佳downsampling的方法组合:

1)unstrided convolution

2)max pooling

  • 7
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
好的,我可以帮你回答这个问题。首先,手写数字识别的卷积神经网络(CNN)通常由卷积层池化层组成。以下是用C++实现卷积层池化层的基本步骤: 卷积层: 1. 定义卷积核的大小和数量 2. 定义输入和输出张量的大小 3. 对于每个卷积核,遍历输入张量,按照卷积核大小计算每个位置的输出 4. 将输出张量传递给下一层网络 池化层: 1. 定义池化的类型(最大池化或平均池化)和池化核大小 2. 定义输入和输出张量的大小 3. 对于每个池化核,遍历输入张量,按照池化核大小计算每个位置的输出 4. 将输出张量传递给下一层网络 下面是一个卷积层和一个最大池化层的C++代码实现示例: ```c++ //卷积层实现 void conv_layer(float* input, float* output, float* weight, float* bias, int in_h, int in_w, int in_c, int out_h, int out_w, int out_c, int ksize, int stride, int padding) { int in_size = in_h * in_w * in_c; int out_size = out_h * out_w * out_c; int kernel_size = ksize * ksize; //遍历每个输出通道 for (int oc = 0; oc < out_c; oc++) { int out_idx = oc * out_h * out_w; for (int oh = 0; oh < out_h; oh++) { for (int ow = 0; ow < out_w; ow++) { int in_idx = 0; //遍历每个输入通道 for (int ic = 0; ic < in_c; ic++) { int kernel_idx = oc * in_c * kernel_size + ic * kernel_size; //遍历卷积核大小 for (int kh = 0; kh < ksize; kh++) { for (int kw = 0; kw < ksize; kw++) { int ih = oh * stride + kh - padding; int iw = ow * stride + kw - padding; if (ih >= 0 && ih < in_h && iw >= 0 && iw < in_w) { int in_pix_idx = ic * in_h * in_w + ih * in_w + iw; int kernel_pix_idx = kh * ksize + kw; in_idx += input[in_pix_idx] * weight[kernel_idx + kernel_pix_idx]; } } } } //加上偏置项 output[out_idx++] = in_idx + bias[oc]; } } } } //最大池化层实现 void maxpool_layer(float* input, float* output, int in_h, int in_w, int in_c, int out_h, int out_w, int ksize, int stride) { int in_size = in_h * in_w * in_c; int out_size = out_h * out_w * in_c; //遍历每个输入通道 for (int ic = 0; ic < in_c; ic++) { int out_idx = ic * out_h * out_w; for (int oh = 0; oh < out_h; oh++) { for (int ow = 0; ow < out_w; ow++) { int in_idx = ic * in_h * in_w + oh * stride * in_w + ow * stride; float max_val = input[in_idx]; //遍历池化核大小 for (int kh = 0; kh < ksize; kh++) { for (int kw = 0; kw < ksize; kw++) { int cur_idx = in_idx + kh * in_w + kw; if (cur_idx < in_size && input[cur_idx] > max_val) { max_val = input[cur_idx]; } } } output[out_idx++] = max_val; } } } } ``` 希望这个示例可以帮助你理解如何用C++实现卷积层池化层。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值