1. 程式人生 > >CNN中卷積層的計算細節

CNN中卷積層的計算細節

原文連結: https://zhuanlan.zhihu.com/p/29119239






卷積層尺寸的計算原理

  • 輸入矩陣格式:四個維度,依次為:樣本數、影象高度、影象寬度、影象通道數
  • 輸出矩陣格式:與輸出矩陣的維度順序和含義相同,但是後三個維度(影象高度、影象寬度、影象通道數)的尺寸發生變化。
  • 權重矩陣(卷積核)格式:同樣是四個維度,但維度的含義與上面兩者都不同,為:卷積核高度、卷積核寬度、輸入通道數、輸出通道數(卷積核個數)
  • 輸入矩陣、權重矩陣、輸出矩陣這三者之間的相互決定關係
    • 卷積核的輸入通道數(in depth)由輸入矩陣的通道數所決定。(紅色標註)
    • 輸出矩陣的通道數(out depth)由卷積核的輸出通道數所決定。(綠色標註)
    • 輸出矩陣的高度和寬度(height, width)這兩個維度的尺寸由輸入矩陣、卷積核、掃描方式所共同決定。計算公式如下。(藍色標註)

\begin{cases} height_{out} &= (height_{in} - height_{kernel} + 2 * padding) ~ / ~ stride + 1\\[2ex] width_{out} &= (width_{in} - width_{kernel} + 2 * padding) ~ / ~ stride + 1 \end{cases}


* 注:以下計算演示均省略掉了 Bias ,嚴格來說其實每個卷積核都還有一個 Bias 引數。


標準卷積計算舉例

以 AlexNet 模型的第一個卷積層為例,
- 輸入圖片的尺寸統一為 227 x 227 x 3 (高度 x 寬度 x 顏色通道數),
- 本層一共具有96個卷積核,
- 每個卷積核的尺寸都是 11 x 11 x 3。
- 已知 stride = 4, padding = 0,
- 假設 batch_size = 256,
- 則輸出矩陣的高度/寬度為 (227 - 11) / 4 + 1 = 55

\begin{matrix} & \mathbf{Batch} & \mathbf{Height} && \mathbf{Width} && \mathbf{In~Depth} && \mathbf{Out~Depth}\\[2ex] \mathbf{Input} & \quad\quad 256 \quad\quad \times & \color{blue}{227} & \times & \color{blue}{227} & \times & \color{red}{3} \\[2ex] \mathbf{Kernel} &\quad\quad\quad\quad\quad & \color{blue}{11} & \times & \color{blue}{11} & \times & \color{red}{3} & \times & \color{green}{96} \\[2ex] \mathbf{Output} & \quad\quad 256 \quad\quad \times & \color{blue}{55} & \times & \color{blue}{55} &&& \times & \color{green}{96} \end{matrix}


1 x 1 卷積計算舉例

後期 GoogLeNet、ResNet 等經典模型中普遍使用一個畫素大小的卷積核作為降低引數複雜度的手段。
從下面的運算可以看到,其實 1 x 1 卷積沒有什麼神祕的,其作用就是將輸入矩陣的通道數量縮減後輸出(512 降為 32),並保持它在寬度和高度維度上的尺寸(227 x 227)。

\begin{matrix} & \mathbf{Batch} & \mathbf{Height} && \mathbf{Width} && \mathbf{In~Depth} && \mathbf{Out~Depth}\\[2ex] \mathbf{Input} & \quad\quad 256 \quad\quad \times & \color{blue}{227} & \times & \color{blue}{227} & \times & \color{red}{512} \\[2ex] \mathbf{Kernel} &\quad\quad\quad\quad\quad & \color{blue}{1} & \times & \color{blue}{1} & \times & \color{red}{512} & \times & \color{green}{32} \\[2ex] \mathbf{Output} & \quad\quad 256 \quad\quad \times & \color{blue}{227} & \times & \color{blue}{227} &&& \times & \color{green}{32} \end{matrix}


全連線層計算舉例

實際上,全連線層也可以被視為是一種極端情況的卷積層,其卷積核尺寸就是輸入矩陣尺寸,因此輸出矩陣的高度和寬度尺寸都是1。

\begin{matrix} & \mathbf{Batch} & \mathbf{Height} && \mathbf{Width} && \mathbf{In~Depth} && \mathbf{Out~Depth}\\[2ex] \mathbf{Input} & \quad \quad 256 \quad \quad \times & \color{blue}{32} & \times & \color{blue}{32} & \times & \color{red}{512} \\[2ex] \mathbf{Kernel} &\quad\quad\quad\quad\quad & \color{blue}{32} & \times & \color{blue}{32} & \times & \color{red}{512} & \times & \color{green}{4096} \\[2ex] \mathbf{Output} & \quad \quad 256 \quad \quad \times & \color{blue}{1} & \times & \color{blue}{1} &&& \times & \color{green}{4096} \end{matrix}


總結下來,其實只需要認識到,雖然輸入的每一張影象本身具有三個維度,但是對於卷積核來講依然只是一個一維向量。卷積核做的,其實就是與感受野範圍內的畫素點進行點積(而不是矩陣乘法)。


附:TensorFlow 中卷積層的簡單實現

def conv_layer(x, out_channel, k_size, stride, padding):
    in_channel = x.shape[3].value
    w = tf.Variable(tf.truncated_normal([k_size, k_size, in_channel, out_channel], mean=0, stddev=stddev))
    b = tf.Variable(tf.zeros(out_channel))
    y = tf.nn.conv2d(x, filter=w, strides=[1, stride, stride, 1], padding=padding)
    y = tf.nn.bias_add(y, b)
    y = tf.nn.relu(y)
    return x
  • 輸入 x:[batch, height, width, in_channel]
  • 權重 w:[height, width, in_channel, out_channel]
  • 輸出 y:[batch, height, width, out_channel]

原文連結: https://zhuanlan.zhihu.com/p/29119239






卷積層尺寸的計算原理

  • 輸入矩陣格式:四個維度,依次為:樣本數、影象高度、影象寬度、影象通道數
  • 輸出矩陣格式:與輸出矩陣的維度順序和含義相同,但是後三個維度(影象高度、影象寬度、影象通道數)的尺寸發生變化。
  • 權重矩陣(卷積核)格式:同樣是四個維度,但維度的含義與上面兩者都不同,為:卷積核高度、卷積核寬度、輸入通道數、輸出通道數(卷積核個數)
  • 輸入矩陣、權重矩陣、輸出矩陣這三者之間的相互決定關係
    • 卷積核的輸入通道數(in depth)由輸入矩陣的通道數所決定。(紅色標註)
    • 輸出矩陣的通道數(out depth)由卷積核的輸出通道數所決定。(綠色標註)
    • 輸出矩陣的高度和寬度(height, width)這兩個維度的尺寸由輸入矩陣、卷積核、掃描方式所共同決定。計算公式如下。(藍色標註)

\begin{cases} height_{out} &= (height_{in} - height_{kernel} + 2 * padding) ~ / ~ stride + 1\\[2ex] width_{out} &= (width_{in} - width_{kernel} + 2 * padding) ~ / ~ stride + 1 \end{cases}


* 注:以下計算演示均省略掉了 Bias ,嚴格來說其實每個卷積核都還有一個 Bias 引數。


標準卷積計算舉例

以 AlexNet 模型的第一個卷積層為例,
- 輸入圖片的尺寸統一為 227 x 227 x 3 (高度 x 寬度 x 顏色通道數),
- 本層一共具有96個卷積核,
- 每個卷積核的尺寸都是 11 x 11 x 3。
- 已知 stride = 4, padding = 0,
- 假設 batch_size = 256,
- 則輸出矩陣的高度/寬度為 (227 - 11) / 4 + 1 = 55

\begin{matrix} & \mathbf{Batch} & \mathbf{Height} && \mathbf{Width} && \mathbf{In~Depth} && \mathbf{Out~Depth}\\[2ex] \mathbf{Input} & \quad\quad 256 \quad\quad \times & \color{blue}{227} & \times & \color{blue}{227} & \times & \color{red}{3} \\[2ex] \mathbf{Kernel} &\quad\quad\quad\quad\quad & \color{blue}{11} & \times & \color{blue}{11} & \times & \color{red}{3} & \times & \color{green}{96} \\[2ex] \mathbf{Output} & \quad\quad 256 \quad\quad \times & \color{blue}{55} & \times & \color{blue}{55} &&& \times & \color{green}{96} \end{matrix}


1 x 1 卷積計算舉例

後期 GoogLeNet、ResNet 等經典模型中普遍使用一個畫素大小的卷積核作為降低引數複雜度的手段。
從下面的運算可以看到,其實 1 x 1 卷積沒有什麼神祕的,其作用就是將輸入矩陣的通道數量縮減後輸出(512 降為 32),並保持它在寬度和高度維度上的尺寸(227 x 227)。

\begin{matrix} & \mathbf{Batch} & \mathbf{Height} && \mathbf{Width} && \mathbf{In~Depth} && \mathbf{Out~Depth}\\[2ex] \mathbf{Input} & \quad\quad 256 \quad\quad \times & \color{blue}{227} & \times & \color{blue}{227} & \times & \color{red}{512} \\[2ex] \mathbf{Kernel} &\quad\quad\quad\quad\quad & \color{blue}{1} & \times & \color{blue}{1} & \times & \color{red}{512} & \times & \color{green}{32} \\[2ex] \mathbf{Output} & \quad\quad 256 \quad\quad \times & \color{blue}{227} & \times & \color{blue}{227} &&& \times & \color{green}{32} \end{matrix}


全連線層計算舉例

實際上,全連線層也可以被視為是一種極端情況的卷積層,其卷積核尺寸就是輸入矩陣尺寸,因此輸出矩陣的高度和寬度尺寸都是1。

\begin{matrix} & \mathbf{Batch} & \mathbf{Height} && \mathbf{Width} && \mathbf{In~Depth} && \mathbf{Out~Depth}\\[2ex] \mathbf{Input} & \quad \quad 256 \quad \quad \times & \color{blue}{32} & \times & \color{blue}{32} & \times & \color{red}{512} \\[2ex] \mathbf{Kernel} &\quad\quad\quad\quad\quad & \color{blue}{32} & \times & \color{blue}{32} & \times & \color{red}{512} & \times & \color{green}{4096} \\[2ex] \mathbf{Output} & \quad \quad 256 \quad \quad \times & \color{blue}{1} & \times & \color{blue}{1} &&& \times & \color{green}{4096} \end{matrix}


總結下來,其實只需要認識到,雖然輸入的每一張影象本身具有三個維度,但是對於卷積核來講依然只是一個一維向量。卷積核做的,其實就是與感受野範圍內的畫素點進行點積(而不是矩陣乘法)。


附:TensorFlow 中卷積層的簡單實現

def conv_layer(x, out_channel, k_size, stride, padding):
    in_channel = x.shape[3].value
    w = tf.Variable(tf.truncated_normal([k_size, k_size, in_channel, out_channel], mean=0, stddev=stddev))
    b = tf.Variable(tf.zeros(out_channel))
    y = tf.nn.conv2d(x, filter=w, strides=[1, stride, stride, 1], padding=padding)
    y = tf.nn.bias_add(y, b)
    y = tf.nn.relu(y)
    return x
  • 輸入 x:[batch, height, width, in_channel]
  • 權重 w:[height, width, in_channel, out_channel]
  • 輸出 y:[batch, height, width, out_channel]