1. 程式人生 > >『TensorFlow』網絡操作API

『TensorFlow』網絡操作API

ima Y軸 features -s 給定 odi info .cn 進行

簡書翻譯原文

卷積層

卷積操作是使用一個二維的卷積核在一個批處理的圖片上進行不斷掃描。具體操作是將一個卷積核在每張圖片上按照一個合適的尺寸在每個通道上面進行掃描。為了達到好的卷積效率,需要在不同的通道和不同的卷積核之間進行權衡。

三個卷積函數

  • conv2d: 任意的卷積核,能同時在不同的通道上面進行卷積操作。
  • depthwise_conv2d: 卷積核能相互獨立的在自己的通道上面進行卷積操作。
  • separable_conv2d: 在縱深卷積 depthwise filter 之後進行逐點卷積 separable filter。

卷積步長:

strides ,比如 strides = [1, 1, 1, 1]

表示卷積核對每個像素點進行卷積,即在二維屏幕上面,兩個軸方向的步長都是1。strides = [1, 2, 2, 1] 表示卷積核對每隔一個像素點進行卷積,即在二維屏幕上面,兩個軸方向的步長都是2。

輸出shape:

  • padding = ‘SAME‘: 向下取舍,僅適用於全尺寸操作,即輸入數據維度和輸出數據維度相同。
  • padding = ‘VALID: 向上取舍,適用於部分窗口,即輸入數據維度和輸出數據維度不同,輸出維度如下。
shape(output) = [batch,
                (in_height - filter_height + 1) / strides[1],
                (in_width - filter_width + 1) / strides[2],
                ...]

conv2d

tf.nn.conv2d(input, filter, strides, padding, use_cudnn_on_gpu=None, name=None)

輸入參數:

  • input: 一個Tensor。數據類型必須是float32或者float64
  • filter: 一個Tensor。數據類型必須是input相同。
  • strides: 一個長度是4的一維整數類型數組,每一維度對應的是 input 中每一維的對應移動步數,比如,strides[1] 對應 input[1] 的移動步數。
  • padding: 一個字符串,取值為 SAME 或者 VALID
  • use_cudnn_on_gpu
    : 一個可選布爾值,默認情況下是 True
  • name: (可選)為這個操作取一個名字。

輸出參數:

  • 一個Tensor,數據類型是 input 相同。

解釋:這個函數的作用是對一個四維的輸入數據 input 和四維的卷積核 filter 進行操作,然後對輸入數據進行一個二維的卷積操作,最後得到卷積之後的結果。

給定的輸入張量的維度是 [batch, in_height, in_width, in_channels] ,卷積核張量的維度是 [filter_height, filter_width, in_channels, out_channels] ,具體卷積操作如下:

  • 將卷積核的維度轉換成一個二維的矩陣形狀 [filter_height * filter_width * in_channels, output_channels]
  • 對於每個批處理的圖片,我們將輸入張量轉換成一個臨時的數據維度 [batch, out_height, out_width, filter_height * filter_width * in_channels]
  • 對於每個批處理的圖片,我們右乘以卷積核,得到最後的輸出結果。

更加具體的表示細節為:

output[b, i, j, k] = sum_{di, dj, q} 
  input[b, strides[1] * i + di, strides[2] * j + dj, q] * filter[di, dj, q, k]

註意,必須有 strides[0] = strides[3] = 1。在大部分處理過程中,卷積核的水平移動步數和垂直移動步數是相同的,strides = [1, stride, stride, 1]

depthwise_conv2d

tf.nn.depthwise_conv2d(input, filter, strides, padding, name=None)

輸入參數:

  • input: 一個Tensor。數據維度是四維 [batch, in_height, in_width, in_channels]
  • filter: 一個Tensor。數據維度是四維 [filter_height, filter_width, in_channels, channel_multiplier]
  • strides: 一個長度是4的一維整數類型數組,每一維度對應的是 input 中每一維的對應移動步數,比如,strides[1] 對應 input[1] 的移動步數。
  • padding: 一個字符串,取值為 SAME 或者 VALID
  • use_cudnn_on_gpu: 一個可選布爾值,默認情況下是 True
  • name: (可選)為這個操作取一個名字。

輸出參數:

  • 一個四維的Tensor,數據維度為 [batch, out_height, out_width, in_channels * channel_multiplier]

解釋:這個函數也是一個卷積操作。

給定一個輸入張量,數據維度是 [batch, in_height, in_width, in_channels] ,一個卷積核的維度是 [filter_height, filter_width, in_channels, channel_multiplier] ,在通道 in_channels 上面的卷積深度是 1 (我的理解是在每個通道上單獨進行卷積),depthwise_conv2d 函數將不同的卷積核獨立的應用在 in_channels 的每個通道上(從通道 1 到通道 channel_multiplier ),然後把所有的結果進行匯總。最後輸出通道的總數是 in_channels * channel_multiplier

更加具體公式如下:

output[b, i, j, k * channel_multiplier + q] =
    sum_{di, dj} input[b, strides[1] * i + di, strides[2] * j + dj, k] * 
                  filter[di, dj, k, q]

註意,必須有 strides[0] = strides[3] = 1。在大部分處理過程中,卷積核的水平移動步數和垂直移動步數是相同的,strides = [1, stride, stride,1]

使用例子:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import numpy as np
import tensorflow as tf

input_data = tf.Variable( np.random.rand(10, 6, 6, 3), dtype = np.float32 )
filter_data = tf.Variable( np.random.rand(2, 2, 3, 5), dtype = np.float32)

y = tf.nn.depthwise_conv2d(input_data, filter_data, strides = [1, 1, 1, 1], padding = ‘SAME‘)

with tf.Session() as sess:
    init = tf.initialize_all_variables()
    sess.run(init)
    print sess.run(y)
    print sess.run(tf.shape(y))

separable_conv2d

tf.nn.separable_conv2d(input, depthwise_filter, pointwise_filter, strides, padding, name=None)

輸入參數:

  • input: 一個Tensor。數據維度是四維 [batch, in_height, in_width, in_channels]
  • depthwise_filter: 一個Tensor。數據維度是四維 [filter_height, filter_width, in_channels, channel_multiplier]。其中,in_channels 的卷積深度等於input的in_channels。
  • pointwise_filter: 一個Tensor。數據維度是四維 [1, 1, channel_multiplier * in_channels, out_channels]。其中,pointwise_filter 是在 depthwise_filter 卷積之後的混合卷積。
  • strides: 一個長度是4的一維整數類型數組,每一維度對應的是 input 中每一維的對應移動步數,比如,strides[1] 對應 input[1] 的移動步數。
  • padding: 一個字符串,取值為 SAME 或者 VALID
  • name: (可選)為這個操作取一個名字。

輸出參數:

  • 一個四維的Tensor,數據維度為 [batch, out_height, out_width, out_channels]

異常:

  • 數值異常: 如果 channel_multiplier * in_channels > out_channels ,那麽將報錯。

解釋:這個函數的作用是利用幾個分離的卷積核去做卷積,可以參考這個解釋。

比如下圖中,常規卷積和分離卷積的區別:

技術分享

技術分享

首先使用一個二維的卷積核,在每個通道上,以深度 channel_multiplier 進行卷積。也就是先使用 depthwise_conv2d ,將 ID 的通道數映射到 ID * DM 的通道數上面,之後從 ID * DM 的通道數映射到 OD 的通道數上面,這也就是又進行了一次常規卷積

具體公式如下:

output[b, i, j, k] = sum_{di, dj, q, r}
    input[b, strides[1] * i + di, strides[2] * j + dj, q] *
    depthwise_filter[di, dj, q, r] *
    pointwise_filter[0, 0, q * channel_multiplier + r, k]  

strides 只是僅僅控制 depthwise convolution 的卷積步長,因為 pointwise convolution 的卷積步長是確定的 [1, 1, 1, 1] 。註意,必須有 strides[0] = strides[3] = 1。在大部分處理過程中,卷積核的水平移動步數和垂直移動步數是相同的,strides = [1, stride, stride, 1]

使用例子:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import numpy as np
import tensorflow as tf

input_data = tf.Variable( np.random.rand(10, 6, 6, 3), dtype = np.float32 )
depthwise_filter = tf.Variable( np.random.rand(2, 2, 3, 5), dtype = np.float32)    # 輸入通道等於input的通道
pointwise_filter = tf.Variable( np.random.rand(1, 1, 15, 20), dtype = np.float32)  # 卷積核兩項必須是1
# out_channels >= channel_multiplier * in_channels
y = tf.nn.separable_conv2d(input_data, depthwise_filter,
    pointwise_filter, strides = [1, 1, 1, 1], padding = ‘SAME‘)
with tf.Session() as sess:
    init = tf.initialize_all_variables()
    sess.run(init)
    print sess.run(y)
    print sess.run(tf.shape(y))

池化層

最大匯聚效果優於平均匯聚

池化操作是利用一個矩陣窗口在輸入張量上進行掃描,並且將每個矩陣窗口中的值通過取最大值,平均值或者XXXX來減少元素個數。每個池化操作的矩陣窗口大小是由 ksize 來指定的,並且根據步長參數 strides 來決定移動步長。比如,如果 strides 中的值都是1,那麽每個矩陣窗口都將被使用。如果 strides 中的值都是2,那麽每一維度上的矩陣窗口都是每隔一個被使用。以此類推。

輸出數據維度是:

shape(output) = (shape(value) - ksize + 1) / strides

  • padding = ‘SAME‘: 向下取舍,僅適用於全尺寸操作,即輸入數據維度和輸出數據維度相同。
  • padding = ‘VALID: 向上取舍,適用於部分窗口,即輸入數據維度和輸出數據維度不同,輸出維度如上。

avg_pool

tf.nn.avg_pool(value, ksize, strides, padding, name=None)

解釋:這個函數的作用是計算池化區域中元素的平均值。

輸入參數:

  • value: 一個四維的Tensor。數據維度是 [batch, height, width, channels]。數據類型是float32float64qint8quint8qint32
  • ksize: 一個長度不小於4的整型數組。每一位上面的值對應於輸入數據張量中每一維的窗口對應值。
  • strides: 一個長度不小於4的整型數組。該參數指定滑動窗口在輸入數據張量每一維上面的步長。
  • padding: 一個字符串,取值為 SAME 或者 VALID
  • name: (可選)為這個操作取一個名字。

輸出參數:

  • 一個Tensor,數據類型和value相同。

max_pool

tf.nn.max_pool(value, ksize, strides, padding, name=None)解釋:這個函數的作用是計算池化區域中元素的最大值。

輸入參數:

  • value: 一個四維的Tensor。數據維度是 [batch, height, width, channels]。數據類型是float32float64qint8quint8qint32
  • ksize: 一個長度不小於4的整型數組。每一位上面的值對應於輸入數據張量中每一維的窗口對應值。
  • strides: 一個長度不小於4的整型數組。該參數指定滑動窗口在輸入數據張量每一維上面的步長。
  • padding: 一個字符串,取值為 SAME 或者 VALID
  • name: (可選)為這個操作取一個名字。

輸出參數:

  • 一個Tensor,數據類型和value相同。

激活函數

在神經網絡中,我們有很多的非線性函數來作為激活函數,比如連續的平滑非線性函數(sigmoidtanhsoftplus),連續但不平滑的非線性函數(relurelu6relu_x)和隨機正則化函數(dropout)。

所有的激活函數都是單獨應用在每個元素上面的,並且輸出張量的維度和輸入張量的維

分類:

平滑非線性(sigmoid,tanh,elu,softplus,softsign)

連續但不是處處可導(relu,relu6,crelu,relu_x)

隨機正則化(dropout)

技術分享

技術分享

relu

tf.nn.relu(features, name = None)

解釋:這個函數的作用是計算激活函數relu,即max(features, 0)

輸入參數:

  • features: 一個Tensor。數據類型必須是:float32float64int32int64uint8int16int8
  • name: (可選)為這個操作取一個名字。

輸出參數:

  • 一個Tensor,數據類型和features相同。

技術分享

relu6

tf.nn.relu6(features, name = None)

解釋:這個函數的作用是計算激活函數relu6,即min(max(features, 0), 6)

輸入參數:

  • features: 一個Tensor。數據類型必須是:floatdoubleint32int64uint8int16或者int8
  • name: (可選)為這個操作取一個名字。

輸出參數:

  • 一個Tensor,數據類型和features相同。

技術分享

crelu

tf.nn.crelu(features, name = None)

解釋:這個函數會倍增通道,一個是relu,一個是relu關於y軸對稱的形狀。

輸入參數:

  • features: 一個Tensor。數據類型必須是:float32float64int32int64uint8int16int8
  • name: (可選)為這個操作取一個名字。

輸出參數:

  • 一個Tensor,數據類型和features相同,通道加倍。

elu

tf.nn.elu(features, name = None)

解釋:x小於0時,y = a*(exp(x)-1),x大於0時同relu。

  • features: 一個Tensor。數據類型必須是:float32float64int32int64uint8int16int8
  • name: (可選)為這個操作取一個名字。

輸出參數:

  • 一個Tensor,數據類型和features相同。

技術分享

softplus

tf.nn.softplus(features, name = None)

解釋:這個函數的作用是計算激活函數softplus,即log( exp( features ) + 1)

輸入參數:

  • features: 一個Tensor。數據類型必須是:float32float64int32int64uint8int16或者int8
  • name: (可選)為這個操作取一個名字。

輸出參數:

  • 一個Tensor,數據類型和features相同。

技術分享

softsign

tf.nn.softsign(features, name = None)

解釋:這個函數的作用是計算激活函數softsign,即features / (abs(features) + 1)

輸入參數:

  • features: 一個Tensor。數據類型必須是:float32float64int32int64uint8int16或者int8
  • name: (可選)為這個操作取一個名字。

輸出參數:

  • 一個Tensor,數據類型和features相同。

技術分享

sigmoid

tf.sigmoid(x, name = None)

解釋:這個函數的作用是計算 x 的 sigmoid 函數。具體計算公式為 y = 1 / (1 + exp(-x))

輸入參數:

  • x: 一個Tensor。數據類型必須是floatdoubleint32complex64int64或者qint32
  • name: (可選)為這個操作取一個名字。

輸出參數:

  • 一個Tensor,如果 x.dtype != qint32 ,那麽返回的數據類型和x相同,否則返回的數據類型是 quint8

sigmoid輸出恒大於零,相當於加了偏置分量。

技術分享

tanh

tf.tanh(x, name = None)

解釋:這個函數的作用是計算 x 的 tanh 函數。具體計算公式為 ( exp(x) - exp(-x) ) / ( exp(x) + exp(-x) )

  • x: 一個Tensor。數據類型必須是floatdoubleint32complex64int64或者qint32
  • name: (可選)為這個操作取一個名字。

輸出參數:

  • 一個Tensor,如果 x.dtype != qint32 ,那麽返回的數據類型和x相同,否則返回的數據類型是 quint8

[-2,2]之間tanh最敏感

[-8,-2]之間tanh不敏感

技術分享

dropout

tf.nn.dropout(x, keep_prob, noise_shape = None, seed = None, name = None)

解釋:這個函數的作用是計算神經網絡層的dropout

一個神經元將以概率keep_prob決定是否放電,如果不放電,那麽該神經元的輸出將是0,如果該神經元放電,那麽該神經元的輸出值將被放大到原來的1/keep_prob。這裏的放大操作是為了保持神經元輸出總個數不變。比如,神經元的值為[1, 2]keep_prob的值是0.5,並且是第一個神經元是放電的,第二個神經元不放電,那麽神經元輸出的結果是[2, 0],也就是相當於,第一個神經元被當做了1/keep_prob個輸出,即2個。這樣保證了總和2個神經元保持不變。

默認情況下,每個神經元是否放電是相互獨立的。但是,如果noise_shape被修改了,那麽他對於變量x就是一個廣播形式,而且當且僅當 noise_shape[i] == shape(x)[i]x中的元素是相互獨立的。比如,如果 shape(x) = [k, l, m, n], noise_shape = [k, 1, 1, n] ,那麽每個批和通道都是相互獨立的,但是每行和每列的數據都是關聯的,即要不都為0,要不都還是原來的值。

輸入參數:

  • x: 一個Tensor
  • keep_prob: 一個 Python 的 float 類型。表示元素是否放電的概率。
  • noise_shape: 一個一維的Tensor,數據類型是int32。代表元素是否獨立的標誌。
  • seed: 一個Python的整數類型。設置隨機種子。
  • name: (可選)為這個操作取一個名字。

輸出參數:

  • 一個Tensor,數據維度和x相同。

異常:

  • 輸入異常: 如果 keep_prob 不是在 (0, 1]區間,那麽會提示錯誤。

bias_add

tf.nn.bias_add(value, bias, name = None)

解釋:這個函數的作用是將偏差項 bias 加到 value 上面。

這個操作你可以看做是 tf.add 的一個特例,其中 bias 必須是一維的。該API支持廣播形式,因此 value 可以有任何維度。但是,該API又不像 tf.add 可以讓 bias 的維度和 value 的最後一維不同,tf.nn.bias_add中bias的維度和value最後一維必須相同。

輸入參數:

  • value: 一個Tensor。數據類型必須是floatdoubleint64int32uint8int16int8或者complex64
  • bias: 一個一維的Tensor,數據維度和 value 的最後一維相同。數據類型必須和value相同。
  • name: (可選)為這個操作取一個名字。

輸出參數:

  • 一個Tensor,數據類型和value相同。

範例:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import tensorflow as tf 

a = tf.constant([[1.0, 2.0],[1.0, 2.0],[1.0, 2.0]]) 
b = tf.constant([2.0,1.0])  
c = tf.constant([1.0])
sess = tf.Session()
print sess.run(tf.nn.bias_add(a, b))
# 因為 a 最後一維的維度是 2 ,但是 c 的維度是 1,所以以下語句將發生錯誤
print sess.run(tf.nn.bias_add(a, c))
# 但是 tf.add() 可以正確運行
print sess.run(tf.add(a, c))

『TensorFlow』網絡操作API