卷积层输出矩阵大小
padding = “SAME”
padding = “VALID”
池化层的输出大小公式也与卷积层一样,由于没有进行填充,所以p=0,可以简化为
通过减少卷积层之间的连接,降低运算复杂程度
一个卷积核对应一个feature map
卷积层
试图将神经网络中的每一小块进行更深入的分析从而得到抽象程度更高的特征,一般来说经过卷积层的处理节点矩阵会变得更深.
左侧小矩阵的尺寸为过滤器的尺寸,而右侧单位矩阵的深度为过滤器的深度
- 为了避免尺寸的变化可以在当前层的矩阵的边界加入全0填充(zero-padding).否则中间的像素会多次进入卷积野而边上的进入次数少
- 还可以通过设置过滤器移动步长调整结果矩阵的大小
# 前两个维度代表了过滤器的尺寸,
# 第三个维度是当前层的深度,卷积层过滤器处理的矩阵深度和当前层神经网络节点矩阵的深度是一致的
# 第四个维度是过滤器的深度,输出单位节点矩阵的深度.
conv1_weights = tf.get_variable(
"weight",
[CONV1_SIZE, CONV1_SIZE, NUM_CHANNELS, CONV1_DEEP],
initializer=tf.truncated_normal_initializer(stddev=0.1))
conv1_biases = tf.get_variable(
"bias",
[CONV1_DEEP],
initializer=tf.constant_initializer(0.0))
# 第一个参数为当前层的节点矩阵;该矩阵为四维,第一维是输入batch,后三维是一个节点矩阵
# 第二个参数为卷积层权重
# 第三个参数为不同维度上的步长;长度为4的数组,第一维和最后一维一定是1,因为步长只对长和宽有效
# 最后一个参数为填充方法;SAME全0填充VALLID不填充
conv1 = tf.nn.conv2d(
input_tensor,
conv1_weights,
strides=[1, 1, 1, 1],
padding='SAME')
relu1 = tf.nn.relu(tf.nn.bias_add(conv1, conv1_biases))
池化层
不会改变三维矩阵的深度,可以缩小矩阵的大小.(将高分辨率转为低分辨率)可进一步缩小最后全连接层中节点的个数.
# ksize为过滤器尺寸,strides为步长,padding为填充
pool1 = tf.nn.max_pool(relu1, ksize = [1,2,2,1],strides=[1,2,2,1],padding="SAME")
池化函数使用某一位置的相邻输出的总体统计特征来代替网络在该位置的输出。
池化具有局部平移不变性,由于最后局部的像素会聚集,所以图像微小的平移有时并不会对池化的结果产生影响。通常当我们只关心某些特征是否出现而不关心其出现在何位置时池化显得非常有用。因为池化过后存储需求又进一步降低了,计算效率再次提升。卷积和池化可以理解为两个无限强的先验。卷积是这样的先验:该层应该学得的函数只包含局部连接关系且对平移具有等变性。池化则是这样的先验:每一个单元都具有对少量平移的不变性。
pooling的结果是使得特征减少,参数减少,但pooling的目的并不仅在于此。pooling目的是为了保持某种不变性(旋转、平移、伸缩等)。并且pooling是在不同的通道上分开执行的,即池化操作不改变通道数目,且不需要参数控制。再根据窗口大小进行相应的操作。常见max pooling、average polling等。
卷积运算的定义、动机
卷积提取底层特征减少神经网络中参数个数 、池化防止过拟合并将数据维度减小
参数增多除导致计算速度减慢,还很容易导致过拟合问题
卷积可减少神经网络中参数个数
池化层的作用
(1)下采样
(2)降维、去除冗余信息、对特征进行压缩、简化网络复杂度、减小计算量、减小内存消耗
(3)实现非线性
(4)扩大感知野
(5)实现不变性,(平移不变性、旋转不变性和尺度不变性)
池化种类
(1)一般池化(General Pooling)
其中最常见的池化操作有平均池化、最大池化
平均池化(average pooling):计算图像区域的平均值作为该区域池化后的值
最大池化(max pooling):选图像区域的最大值作为该区域池化后的值
(2)重叠池化(Overlapping Pooling)
相邻池化窗口之间有重叠区域,此时一般sizeX > stride
(3)空间金字塔池化(Spatial Pyramid Pooling)
空间金字塔池化的思想院子Spatial Pyramid Model,它将一个Pooling变成了多个scale的Pooling。用不同大小池化窗口作用于上层的卷积特征。也就是说spatial pyramid pooling layer就是把前一卷积层的feature maps的每一个图片上进行了3个卷积操作,并把结果输出给全连接层。其中每一个pool操作可以看成是一个空间金字塔的一层
空间金字塔池化可以把任意尺度的图像的卷积特征转化成相同维度,使得CNN可以处理任意尺度的数据,还可以避免cropping和warping操作造成的信息的丢失。
全连接层
卷积层和池化层提取完图像的特征后使用全连接层完成分类
稀疏权重
传统的神经网络使用全连接(矩阵运算),进行输入数据和输出数据之间的连接。其中,参数矩阵中每一个单独的参数都描述了一个输入单元和一个输出单元之间的链接,假设输入单元的数目为 mm,输出单元的数目为nn,则进行转换的参数矩阵数目为m∗nm∗n。当mm和nn非常大的时候,必然带来一个非常大的内存开销。
但是卷积神经网络核函数的存在,我们只需要检测当前时刻核函数所覆盖的范围内,假设核函数的宽度为kk,输出单元的宽度为nn,则需要的参数矩阵数目为k∗nk∗n,一般情况下,核函数的宽度要远小于输入函数的宽度,这不仅减少了模型参数存储的需求,还增快了统计效率。
参数共享
参数共享是指在一个模型的多个函数中使用相同的参数。在传统的神经网络中,每一个参数仅仅使用一次,对应着固定的输入和输出神经元,比如参数wi,jwi,j表示第ii个输入神经元和第jj个输出神经元之间的连接权重。而卷积神经网络中的参数共享保证了我们只需要学习到一个卷积核函数,而不是像全连接神经网络一样在每个位置都学习一个卷积核函数。这虽然没有改变前向传播的计算时间,但是它显著的减少了参数的数目。
等变表示
指的是,图像中某一元素/成分的移动,在上层神经元中也表现为一定的移动。这是由参数共享直接带来的,因为移动过程中卷积核的参数不变。这种等变表示使得图像的平移不会对分类预测结果产生太大的影响,使得学习算法能够对相同内容不同位置的图像较为准确的识别。
优化
轻量化模型、改进卷积层结构、改进卷积算法本身、压缩权重、压缩精度、模型剪枝
两个33代替一个55
参数量减少,非线性变换增多
假设输入的图片大小为1001003,卷积操作不改变大小(padding=same)。先看用128个773的核进行卷积操作,需要100100773128次乘法操作然后我们用3层33卷积代替上面的77卷积,每层仍取128个核,需要1001003331283次乘法操作,约掉相同部分,分别剩下77=49和333=27.显然,用三层33代替一层77可以减少近一半的计算量。
1*1卷积跨通道交流信息、降维升维
加速卷积运算
im2col
FFT(不常用)
一维卷积运算和二维卷积运算。
一维卷积
LeNet-5实现
import tensorflow as tf
# 1. 设定神经网络的参数
INPUT_NODE = 784
OUTPUT_NODE = 10
IMAGE_SIZE = 28
NUM_CHANNELS = 1
NUM_LABELS = 10
CONV1_DEEP = 32
CONV1_SIZE = 5
CONV2_DEEP = 64
CONV2_SIZE = 5
FC_SIZE = 512
# 2. 定义前向传播的过程
def inference(input_tensor, train, regularizer):
with tf.variable_scope('layer1-conv1'):
conv1_weights = tf.get_variable(
"weight", [CONV1_SIZE, CONV1_SIZE, NUM_CHANNELS, CONV1_DEEP],
initializer=tf.truncated_normal_initializer(stddev=0.1))
conv1_biases = tf.get_variable("bias", [CONV1_DEEP], initializer=tf.constant_initializer(0.0))
conv1 = tf.nn.conv2d(input_tensor, conv1_weights, strides=[1, 1, 1, 1], padding='SAME')
relu1 = tf.nn.relu(tf.nn.bias_add(conv1, conv1_biases))
with tf.name_scope("layer2-pool1"):
pool1 = tf.nn.max_pool(relu1, ksize = [1,2,2,1],strides=[1,2,2,1],padding="SAME")
with tf.variable_scope("layer3-conv2"):
conv2_weights = tf.get_variable(
"weight", [CONV2_SIZE, CONV2_SIZE, CONV1_DEEP, CONV2_DEEP],
initializer=tf.truncated_normal_initializer(stddev=0.1))
conv2_biases = tf.get_variable("bias", [CONV2_DEEP], initializer=tf.constant_initializer(0.0))
conv2 = tf.nn.conv2d(pool1, conv2_weights, strides=[1, 1, 1, 1], padding='SAME')
relu2 = tf.nn.relu(tf.nn.bias_add(conv2, conv2_biases))
with tf.name_scope("layer4-pool2"):
pool2 = tf.nn.max_pool(relu2, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')
pool_shape = pool2.get_shape().as_list()
nodes = pool_shape[1] * pool_shape[2] * pool_shape[3]
reshaped = tf.reshape(pool2, [pool_shape[0], nodes])
with tf.variable_scope('layer5-fc1'):
fc1_weights = tf.get_variable("weight", [nodes, FC_SIZE],
initializer=tf.truncated_normal_initializer(stddev=0.1))
if regularizer != None: tf.add_to_collection('losses', regularizer(fc1_weights))
fc1_biases = tf.get_variable("bias", [FC_SIZE], initializer=tf.constant_initializer(0.1))
fc1 = tf.nn.relu(tf.matmul(reshaped, fc1_weights) + fc1_biases)
if train: fc1 = tf.nn.dropout(fc1, 0.5)
with tf.variable_scope('layer6-fc2'):
fc2_weights = tf.get_variable("weight", [FC_SIZE, NUM_LABELS],
initializer=tf.truncated_normal_initializer(stddev=0.1))
if regularizer != None: tf.add_to_collection('losses', regularizer(fc2_weights))
fc2_biases = tf.get_variable("bias", [NUM_LABELS], initializer=tf.constant_initializer(0.1))
logit = tf.matmul(fc1, fc2_weights) + fc2_biases
return logit
Text-CNN的原理。
利用Text-CNN模型来进行文本分类。
https://blog.csdn.net/yanyiting666/article/details/88547000