CNN神經網絡之一維卷積、二維卷積詳解


作者:凌逆戰

地址:https://www.cnblogs.com/LXP-Never/p/10763804.html


 

在看這兩個函數之前,我們需要先了解一維卷積(conv1d)二維卷積(conv2d),二維卷積是將一個特征圖在width和height兩個方向進行滑動窗口操作,對應位置進行相乘求和;而一維卷積則只是在width或者height方向上進行滑動窗口並相乘求和。

一維卷積:tf.layers.conv1d()

一維卷積常用於序列數據,如自然語言處理領域。

tf.layers.conv1d(
    inputs,
    filters,
    kernel_size,
    strides=1,
    padding='valid',
    data_format='channels_last',
    dilation_rate=1,
    activation=None,
    use_bias=True,
    kernel_initializer=None,
    bias_initializer=tf.zeros_initializer(),
    kernel_regularizer=None,
    bias_regularizer=None,
    activity_regularizer=None,
    kernel_constraint=None,
    bias_constraint=None,
    trainable=True,
    name=None,
    reuse=None
)

參數:[1]

  • inputs:張量數據輸入,一般是[batch, width, length]
  • filters:整數,輸出空間的維度,可以理解為卷積核(濾波器)的個數
  • kernel_size:單個整數或元組/列表,指定1D(一維,一行或者一列)卷積窗口的長度。
  • strides:單個整數或元組/列表,指定卷積的步長,默認為1
  • padding:"SAME" or "VALID" (不區分大小寫)是否用0填充,
      • SAME用0填充;
      • VALID不使用0填充,舍去不匹配的多余項。
  • activation:激活函數
  • ues_bias:該層是否使用偏差
  • kernel_initializer:卷積核的初始化
  • bias_initializer:偏置向量的初始化器
  • kernel_regularizer:卷積核的正則化項
  • bias_regularizer:偏置的正則化項
  • activity_regularizer:輸出的正則化函數
  • reuse:Boolean,是否使用相同名稱重用前一層的權重
  • trainable:Boolean,如果True,將變量添加到圖collection中
  • data_format:一個字符串,一個channels_last(默認)或channels_first。輸入中維度的排序。
      • channels_last:對應於形狀的輸入(batch, length, channels)
      • channels_first:對應於形狀輸入(batch, channels, length)
  • name = 取一個名字

返回值

  一維卷積后的張量,

例子

import tensorflow as tf 

x = tf.get_variable(name="x", shape=[32, 512, 1024], initializer=tf.zeros_initializer)
x = tf.layers.conv1d(
    x,
    filters=1,                    # 輸出的第三個通道是1
    kernel_size=512,            # 不用管它是多大,都不影響輸出的shape
    strides=1,
    padding='same',
    data_format='channels_last',
    dilation_rate=1,
    use_bias=True,
    bias_initializer=tf.zeros_initializer())

print(x)            # Tensor("conv1d/BiasAdd:0", shape=(32, 512, 1), dtype=float32)

解析

  1. 輸入數據的維度為[batch, data_length, data_width]=[32, 512, 1024],一般輸入數據input第一維為batch_size,此處為32,意味着有32個樣本,第二維度和第三維度分別表示輸入的長和寬(512,1024)
  2. 一維卷積核是二維的,也有長和寬,長為卷積核的數量kernel_size=512,因為卷積核的數量只有一個,所以寬為輸入數據的寬度data_width=1024,所以一維卷積核的shape為[512,1024]
  3. filteres是卷積核的個數,即輸出數據的第三維度。filteres=1,第三維度為1
  4. 所以卷積后的輸出數據大小為[32, 512, 1]

二維卷積:tf.layers.conv2d()

二維卷積常用於計算機視覺、圖像處理領域

tf.layers.conv2d(
    inputs,
    filters,
    kernel_size,
    strides=(1, 1),
    padding='valid',
    data_format='channels_last',
    dilation_rate=(1, 1),
    activation=None,
    use_bias=True,
    kernel_initializer=None,
    bias_initializer=tf.zeros_initializer(),
    kernel_regularizer=None,
    bias_regularizer=None,
    activity_regularizer=None,
    kernel_constraint=None,
    bias_constraint=None,
    trainable=True,
    name=None,
    reuse=None
)

參數:[4]

  • inputs:張量輸入。一般是[batch, width, length,channel]
  • filters:整數,輸出空間的維度,可以理解為卷積核(濾波器)的個數
  • kernel_size:2個整數或元組/列表,指定2D卷積窗口的高度和寬度。可以是單個整數,以指定所有空間維度的相同值。
  • strides:2個整數或元組/列表,指定卷積沿高度和寬度方向的步幅。可以是單個整數,以指定所有空間維度的相同值。
  • padding:"SAME" or "VALID" (不區分大小寫)是否用0填充,
      • SAME用0填充;
      • VALID不使用0填充,舍去不匹配的多余項。
  • data_format:字符串,"channels_last"(默認)或"channels_first"。輸入中維度的排序。
      • channels_last:對應於具有形狀的輸入,(batch, height, width, channels)
      • channels_first:對應於具有形狀的輸入(batch, channels, height, width)
  • activation:激活函數
  • use_bias:Boolean, 該層是否使用偏差項
  • kernel_initializer:卷積核的初始化
  • bias_initializer:  偏置向量的初始化。如果為None,將使用默認初始值設定項
  • kernel_regularizer:卷積核的正則化項
  • bias_regularizer:  偏置矢量的正則化項
  • activity_regularizer:輸出的正則化函數
  • trainable:Boolean,如果True,將變量添加到圖collection中
  • name:圖層的name
  • reuse:Boolean,是否使用相同名稱重用前一層的權重

返回:

  二維卷積后的張量

例子:

import tensorflow as tf 

x = tf.get_variable(name="x", shape=[1, 3, 3, 5], initializer=tf.zeros_initializer)
x = tf.layers.conv2d(
    x,
    filters=1,                    # 結果的第三個通道是1
    kernel_size=[1, 1],            # 不用管它是多大,都不影響輸出的shape
    strides=[1, 1],
    padding='same',
    data_format='channels_last',
    use_bias=True,
    bias_initializer=tf.zeros_initializer())

print(x)            # shape=(1, 3, 3, 1)

解析:

  1. input輸入是1張 3*3 大小的圖片,圖像通道數是5,輸入shape=(batch, data_length, data_width, data_channel)
  2. kernel_size卷積核shape是 1*1,數量filters是1strides步長是[1,1],第一維和第二維分別為長度方向和寬度方向的步長 = 1。
  3. 最后輸出的shape為[1,3,3,1] 的張量,即得到一個3*3的feature map(batch,長,寬,輸出通道數)
  4. 長和寬只和strides有關,最后一個維度 = filters。

卷積層中的輸出大小計算

  設輸入圖片大小W,Filter大小F*F,步長為S,padding為P,輸出圖片的大小為N:

$$N=\frac{W-F+2P}{S}+1$$

  向下取整后再加1。

在Tensoflow中,Padding有2個選型,'SAME'和'VALID' ,下面舉例說明差別:

如果 Padding='SAME',輸出尺寸為: W / S(向上取整)

import tensorflow as tf

input_image = tf.get_variable(shape=[64, 32, 32, 3], dtype=tf.float32, name="input", initializer=tf.zeros_initializer)
conv0 = tf.layers.conv2d(input_image, 64, kernel_size=[3, 3], strides=[2, 2], padding='same')  # 32/2=16
conv1 = tf.layers.conv2d(input_image, 64, kernel_size=[5, 5], strides=[2, 2], padding='same')  
# kernel_szie不影響輸出尺寸
print(conv0)      # shape=(64, 16, 16, 64)
print(conv1)      # shape=(64, 16, 16, 64)

如果 Padding='VALID',輸出尺寸為:(W - F + 1) / S

import tensorflow as tf

input_image = tf.get_variable(shape=[64, 32, 32, 3], dtype=tf.float32, name="input", initializer=tf.zeros_initializer)
conv0 = tf.layers.conv2d(input_image, 64, kernel_size=[3, 3], strides=[2, 2], padding='valid')  # (32-3+1)/2=15
conv1 = tf.layers.conv2d(input_image, 64, kernel_size=[5, 5], strides=[2, 2], padding='valid')  # (32-5+1)/2=14
print(conv0)      # shape=(64, 15, 15, 64)
print(conv1)      # shape=(64, 14, 14, 64)

 1x1卷積核的作用,加深一層網絡,提取更深特征,數據變維,

有效卷積(valid)、同維卷積(same)、完全卷積(full)

a = [1 2 3 4 5]   原數組
b = [8 7 6]    卷積核數組 kernel

使用b作為卷積核對a數組做一維卷積運算的過程如下:

原數組:   0  0  1  2  3  4  5  0  0
卷積數組: 6  7  8
            6  7  8
               6  7  8
                  6  7  8
                     6  7  8
                        6  7  8
                           6  7  8
-------------------------------------
結果:        44 65  86         有效卷積 (valid)
          23 44 65  86 59      同維卷積 (same)
      8   23 44 65  86 59 30   完全卷積 (full)

 

參考文獻:

[1] tensorflow官方API tf.layers.conv1d

[2] tf.layers.conv1d函數解析(一維卷積)

[3] tf.layer.conv1d、conv2d、conv3d

[4] tensorflow官方API tf.layers.conv2d

import tensorflow as tf

# case 2
input = tf.Variable(tf.random_normal([1, 3, 3, 5]))
filter = tf.Variable(tf.random_normal([1, 1, 5, 1]))
op2 = tf.nn.conv2d(input, filter, strides=[1, 1, 1, 1], padding='VALID')  # (1, 3, 3, 1)
# case 3
input = tf.Variable(tf.random_normal([1, 3, 3, 5]))
filter = tf.Variable(tf.random_normal([3, 3, 5, 1]))
op3 = tf.nn.conv2d(input, filter, strides=[1, 1, 1, 1], padding='VALID')  # (1, 1, 1, 1)
# case 4
input = tf.Variable(tf.random_normal([1, 5, 5, 5]))
filter = tf.Variable(tf.random_normal([3, 3, 5, 1]))
op4 = tf.nn.conv2d(input, filter, strides=[1, 1, 1, 1], padding='VALID')  # (1, 3, 3, 1)
# case 5
input = tf.Variable(tf.random_normal([1, 5, 5, 5]))
filter = tf.Variable(tf.random_normal([3, 3, 5, 1]))
op5 = tf.nn.conv2d(input, filter, strides=[1, 1, 1, 1], padding='SAME')  # (1, 5, 5, 1)
# case 6
input = tf.Variable(tf.random_normal([1, 5, 5, 5]))
filter = tf.Variable(tf.random_normal([3, 3, 5, 7]))
op6 = tf.nn.conv2d(input, filter, strides=[1, 1, 1, 1], padding='SAME')  # (1, 5, 5, 7)
# case 7
input = tf.Variable(tf.random_normal([1, 5, 5, 5]))
filter = tf.Variable(tf.random_normal([3, 3, 5, 7]))
op7 = tf.nn.conv2d(input, filter, strides=[1, 2, 2, 1], padding='SAME')  # (1, 3, 3, 7)
# case 8
input = tf.Variable(tf.random_normal([10, 5, 5, 5]))
filter = tf.Variable(tf.random_normal([3, 3, 5, 7]))
op8 = tf.nn.conv2d(input, filter, strides=[1, 2, 2, 1], padding='SAME')  # (10, 3, 3, 7)

init = tf.global_variables_initializer()
with tf.Session() as sess:
    sess.run(init)
    print("case 2")
    print(sess.run(op2).shape)  # (1, 3, 3, 1)
    print("case 3")
    print(sess.run(op3).shape)  # (1, 1, 1, 1)
    print("case 4")
    print(sess.run(op4).shape)  # (1, 3, 3, 1)
    print("case 5")
    print(sess.run(op5).shape)  # (1, 5, 5, 1)
    print("case 6")
    print(sess.run(op6).shape)  # (1, 5, 5, 7)
    print("case 7")
    print(sess.run(op7).shape)  # (1, 3, 3, 7)
    print("case 8")
    print(sess.run(op8).shape)  # (10, 3, 3, 7)
View Code

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM