卷积神经网络(CNN)

卷积层输出矩阵大小

padding = “SAME”n_{\text {output}}=\left[\frac{n_{\text {input}}}{S}\right]
padding = “VALID”n_{\text {output}}=\left[\frac{n_{\text {input}}-f+1}{s}\right]

池化层的输出大小公式也与卷积层一样,由于没有进行填充,所以p=0,可以简化为 \frac{n-f}{s} +1

通过减少卷积层之间的连接,降低运算复杂程度


一个卷积核对应一个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

image.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,128评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,316评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,737评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,283评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,384评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,458评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,467评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,251评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,688评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,980评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,155评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,818评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,492评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,142评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,382评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,020评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,044评论 2 352

推荐阅读更多精彩内容