作者:chen_h
微訊號 & QQ:862251340
微信公眾號:coderpai
簡書地址:https://www.jianshu.com/p/e3a…
計劃現將 tensorflow 中的 Python API 做一個學習,這樣方便以後的學習。
原文連結
該章介紹有關神經網路構建的API
啟用函式表示
在神經網路中,我們有很多的非線性函式來作為啟用函式,比如連續的平滑非線性函式(sigmoid
,tanh
和softplus
),連續但不平滑的非線性函式(relu
,relu6
和relu_x
)和隨機正則化函式(dropout
)。
所有的啟用函式都是單獨應用在每個元素上面的,並且輸出張量的維度和輸入張量的維度一樣。
tf.nn.relu(features, name = None)
解釋:這個函式的作用是計算啟用函式relu
,即max(features, 0)
。
使用例子:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import tensorflow as tf
a = tf.constant([-1.0, 2.0])
with tf.Session() as sess:
b = tf.nn.relu(a)
print sess.run(b)
輸入引數:
-
features
: 一個Tensor
。資料型別必須是:float32
,float64
,int32
,int64
,uint8
,int16
,int8
。 -
name
: (可選)為這個操作取一個名字。
輸出引數:
- 一個
Tensor
,資料型別和features
相同。
tf.nn.relu6(features, name = None)
解釋:這個函式的作用是計算啟用函式relu6
,即min(max(features, 0), 6)
。
使用例子:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import tensorflow as tf
a = tf.constant([-1.0, 12.0])
with tf.Session() as sess:
b = tf.nn.relu6(a)
print sess.run(b)
輸入引數:
-
features
: 一個Tensor
。資料型別必須是:float
,double
,int32
,int64
,uint8
,int16
或者int8
。 -
name
: (可選)為這個操作取一個名字。
輸出引數:
- 一個
Tensor
,資料型別和features
相同。
tf.nn.softplus(features, name = None)
解釋:這個函式的作用是計算啟用函式softplus
,即log( exp( features ) + 1)
。
使用例子:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import tensorflow as tf
a = tf.constant([-1.0, 12.0])
with tf.Session() as sess:
b = tf.nn.softplus(a)
print sess.run(b)
輸入引數:
-
features
: 一個Tensor
。資料型別必須是:float32
,float64
,int32
,int64
,uint8
,int16
或者int8
。 -
name
: (可選)為這個操作取一個名字。
輸出引數:
- 一個
Tensor
,資料型別和features
相同。
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,要不都還是原來的值。
使用例子:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import tensorflow as tf
a = tf.constant([[-1.0, 2.0, 3.0, 4.0]])
with tf.Session() as sess:
b = tf.nn.dropout(a, 0.5, noise_shape = [1,4])
print sess.run(b)
b = tf.nn.dropout(a, 0.5, noise_shape = [1,1])
print sess.run(b)
輸入引數:
-
x
: 一個Tensor
。 -
keep_prob
: 一個 Python 的 float 型別。表示元素是否放電的概率。 -
noise_shape
: 一個一維的Tensor
,資料型別是int32
。代表元素是否獨立的標誌。 -
seed
: 一個Python的整數型別。設定隨機種子。 -
name
: (可選)為這個操作取一個名字。
輸出引數:
- 一個
Tensor
,資料維度和x
相同。
異常:
-
輸入異常
: 如果keep_prob
不是在(0, 1]
區間,那麼會提示錯誤。
tf.nn.bias_add(value, bias, name = None)
解釋:這個函式的作用是將偏差項 bias
加到 value
上面。
這個操作你可以看做是 tf.add
的一個特例,其中 bias
必須是一維的。該API支援廣播形式,因此 value
可以有任何維度。但是,該API又不像 tf.add
,可以讓 bias
的維度和 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))
輸入引數:
-
value
: 一個Tensor
。資料型別必須是float
,double
,int64
,int32
,uint8
,int16
,int8
或者complex64
。 -
bias
: 一個一維的Tensor
,資料維度和value
的最後一維相同。資料型別必須和value
相同。 -
name
: (可選)為這個操作取一個名字。
輸出引數:
- 一個
Tensor
,資料型別和value
相同。
tf.sigmoid(x, name = None)
解釋:這個函式的作用是計算 x
的 sigmoid 函式。具體計算公式為 y = 1 / (1 + exp(-x))
。
使用例子:
#!/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]])
sess = tf.Session()
print sess.run(tf.sigmoid(a))
輸入引數:
-
x
: 一個Tensor
。資料型別必須是float
,double
,int32
,complex64
,int64
或者qint32
。 -
name
: (可選)為這個操作取一個名字。
輸出引數:
- 一個
Tensor
,如果x.dtype != qint32
,那麼返回的資料型別和x
相同,否則返回的資料型別是quint8
。
tf.tanh(x, name = None)
解釋:這個函式的作用是計算 x
的 tanh 函式。具體計算公式為 ( exp(x) - exp(-x) ) / ( exp(x) + exp(-x) )
。
使用例子:
#!/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]])
sess = tf.Session()
print sess.run(tf.tanh(a))
輸入引數:
-
x
: 一個Tensor
。資料型別必須是float
,double
,int32
,complex64
,int64
或者qint32
。 -
name
: (可選)為這個操作取一個名字。
輸出引數:
- 一個
Tensor
,如果x.dtype != qint32
,那麼返回的資料型別和x
相同,否則返回的資料型別是quint8
。
卷積層
卷積操作是使用一個二維的卷積核在一個批處理的圖片上進行不斷掃描。具體操作是將一個卷積核在每張圖片上按照一個合適的尺寸在每個通道上面進行掃描。為了達到好的卷積效率,需要在不同的通道和不同的卷積核之間進行權衡。
-
conv2d
: 任意的卷積核,能同時在不同的通道上面進行卷積操作。 -
depthwise_conv2d
: 卷積核能相互獨立的在自己的通道上面進行卷積操作。 -
separable_conv2d
: 在縱深卷積depthwise filter
之後進行逐點卷積separable filter
。
注意,雖然這些操作被稱之為“卷積”操作,但是嚴格的說,他們只是互相關,因為卷積核沒有做一個逆向的卷積過程。
卷積核的卷積過程是按照 strides
引數來確定的,比如 strides = [1, 1, 1, 1]
表示卷積核對每個畫素點進行卷積,即在二維螢幕上面,兩個軸方向的步長都是1。strides = [1, 2, 2, 1]
表示卷積核對每隔一個畫素點進行卷積,即在二維螢幕上面,兩個軸方向的步長都是2。
如果我們先暫且不考慮通道這個因素,那麼卷積操作的空間含義定義如下:如果輸入資料是一個四維的 input
,資料維度是 [batch, in_height, in_width, ...]
,卷積核也是一個四維的卷積核,資料維度是 [filter_height, filter_width, ...]
,那麼:
shape(output) = [batch,
(in_height - filter_height + 1) / strides[1],
(in_width - filter_width + 1) / strides[2],
...]
output[b, i, j, :] =
sum_{di, dj} input[b, strides[1] * i + di, strides[2] * j + dj, ...] *
filter[di, dj, ...]
因為,input
資料是一個四維的,每一個通道上面是一個向量 input[b, i, j, :]
。對於 conv2d
,這些向量將會被卷積核 filter[di, dj, :, :]
相乘而產生一個新的向量。對於 depthwise_conv_2d
,每個標量分量 input[b, i, j, k]
將在 k
個通道上面獨立的被卷積核 filter[di, dj, k]
進行卷積操作,然後把所有得到的向量進行連線組合成一個新的向量。
對於輸出資料的維度 shape(output)
,這取決於填充引數 padding
的設定:
-
padding = `SAME`
: 向下取捨,僅適用於全尺寸操作,即輸入資料維度和輸出資料維度相同。 -
padding = `VALID
: 向上取捨,適用於部分視窗,即輸入資料維度和輸出資料維度不同。
tf.nn.conv2d(input, filter, strides, padding, use_cudnn_on_gpu=None, name=None)
解釋:這個函式的作用是對一個四維的輸入資料 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]
。
使用例子:
#!/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, 1), dtype = np.float32)
y = tf.nn.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))
輸入引數:
-
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
相同。
tf.nn.depthwise_conv2d(input, filter, strides, padding, name=None)
解釋:這個函式也是一個卷積操作。
給定一個輸入張量,資料維度是 [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))
輸入引數:
-
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]
。
tf.nn.separable_conv2d(input, depthwise_filter, pointwise_filter, strides, padding, name=None)
解釋:這個函式的作用是利用幾個分離的卷積核去做卷積,可以參考這個解釋。
比如下圖中,常規卷積和分離卷積的區別:
這個卷積是為了避免卷積核在全通道的情況下進行卷積,這樣非常浪費時間。使用這個API,你將應用一個二維的卷積核,在每個通道上,以深度 channel_multiplier
進行卷積。其實如上圖 Separable Convolution
中,就是先利用 depthwise_filter
,將 ID
的通道數對映到 ID * DM
的通道數上面,之後從 ID * DM
的通道數對映到 OD
的通道數上面,這也就是上面說的深度 channel_multiplier
對應於 DM
。
具體公式如下:
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)
pointwise_filter = tf.Variable( np.random.rand(1, 1, 15, 20), dtype = np.float32)
# 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))
輸入引數:
-
input
: 一個Tensor
。資料維度是四維[batch, in_height, in_width, in_channels]
。 -
depthwise_filter
: 一個Tensor
。資料維度是四維[filter_height, filter_width, in_channels, channel_multiplier]
。其中,in_channels
的卷積深度是 1。 -
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
,那麼將報錯。
池化層
池化操作是利用一個矩陣視窗在輸入張量上進行掃描,並且將每個矩陣視窗中的值通過取最大值,平均值或者XXXX來減少元素個數。每個池化操作的矩陣視窗大小是由 ksize
來指定的,並且根據步長引數 strides
來決定移動步長。比如,如果 strides
中的值都是1,那麼每個矩陣視窗都將被使用。如果 strides
中的值都是2,那麼每一維度上的矩陣視窗都是每隔一個被使用。以此類推。
更具體的輸出結果是:
output[i] = reduce( value[ strides * i: strides * i + ksize ] )
輸出資料維度是:
shape(output) = (shape(value) - ksize + 1) / strides
其中,取捨方向取決於引數 padding
:
-
padding = `SAME`
: 向下取捨,僅適用於全尺寸操作,即輸入資料維度和輸出資料維度相同。 -
padding = `VALID
: 向上取捨,適用於部分視窗,即輸入資料維度和輸出資料維度不同。
tf.nn.avg_pool(value, ksize, strides, padding, name=None)
解釋:這個函式的作用是計算池化區域中元素的平均值。
使用例子:
#!/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, 10), dtype = np.float32)
y = tf.nn.conv2d(input_data, filter_data, strides = [1, 1, 1, 1], padding = `SAME`)
output = tf.nn.avg_pool(value = y, ksize = [1, 2, 2, 1], strides = [1, 1, 1, 1], padding = `SAME`)
with tf.Session() as sess:
init = tf.initialize_all_variables()
sess.run(init)
print sess.run(output)
print sess.run(tf.shape(output))
輸入引數:
-
value
: 一個四維的Tensor
。資料維度是[batch, height, width, channels]
。資料型別是float32
,float64
,qint8
,quint8
,qint32
。 -
ksize
: 一個長度不小於4的整型陣列。每一位上面的值對應於輸入資料張量中每一維的視窗對應值。 -
strides
: 一個長度不小於4的整型陣列。該引數指定滑動視窗在輸入資料張量每一維上面的步長。 -
padding
: 一個字串,取值為SAME
或者VALID
。 -
name
: (可選)為這個操作取一個名字。
輸出引數:
- 一個
Tensor
,資料型別和value
相同。
tf.nn.max_pool(value, ksize, strides, padding, name=None)
解釋:這個函式的作用是計算池化區域中元素的最大值。
使用例子:
#!/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, 10), dtype = np.float32)
y = tf.nn.conv2d(input_data, filter_data, strides = [1, 1, 1, 1], padding = `SAME`)
output = tf.nn.max_pool(value = y, ksize = [1, 2, 2, 1], strides = [1, 1, 1, 1], padding = `SAME`)
with tf.Session() as sess:
init = tf.initialize_all_variables()
sess.run(init)
print sess.run(output)
print sess.run(tf.shape(output))
輸入引數:
-
value
: 一個四維的Tensor
。資料維度是[batch, height, width, channels]
。資料型別是float32
,float64
,qint8
,quint8
,qint32
。 -
ksize
: 一個長度不小於4的整型陣列。每一位上面的值對應於輸入資料張量中每一維的視窗對應值。 -
strides
: 一個長度不小於4的整型陣列。該引數指定滑動視窗在輸入資料張量每一維上面的步長。 -
padding
: 一個字串,取值為SAME
或者VALID
。 -
name
: (可選)為這個操作取一個名字。
輸出引數:
- 一個
Tensor
,資料型別和value
相同。
tf.nn.max_pool_with_argmax(input, ksize, strides, padding, Targmax = None, name=None)
解釋:這個函式的作用是計算池化區域中元素的最大值和該最大值所在的位置。
因為在計算位置 argmax
的時候,我們將 input
鋪平了進行計算,所以,如果 input = [b, y, x, c]
,那麼索引位置是 ( ( b * height + y ) * width + x ) * channels + c
。
檢視原始碼,該API只能在GPU環境下使用,所以我沒有測試下面的使用例子,如果你可以測試,請告訴我程式是否可以執行。
原始碼展示:
REGISTER_KERNEL_BUILDER(Name("MaxPoolWithArgmax")
.Device(DEVICE_GPU)
.TypeConstraint<int64>("Targmax")
.TypeConstraint<float>("T"),
MaxPoolingWithArgmaxOp<Eigen::GpuDevice, float>);
REGISTER_KERNEL_BUILDER(Name("MaxPoolWithArgmax")
.Device(DEVICE_GPU)
.TypeConstraint<int64>("Targmax")
.TypeConstraint<Eigen::half>("T"),
MaxPoolingWithArgmaxOp<Eigen::GpuDevice, Eigen::half>);
使用例子:
#!/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 = tf.float32 )
filter_data = tf.Variable( np.random.rand(2, 2, 3, 10), dtype = np.float32)
y = tf.nn.conv2d(input_data, filter_data, strides = [1, 1, 1, 1], padding = `SAME`)
output, argmax = tf.nn.max_pool_with_argmax(input = y, ksize = [1, 2, 2, 1], strides = [1, 1, 1, 1], padding = `SAME`)
with tf.Session() as sess:
init = tf.initialize_all_variables()
sess.run(init)
print sess.run(output)
print sess.run(tf.shape(output))
輸入引數:
-
input
: 一個四維的Tensor
。資料維度是[batch, height, width, channels]
。資料型別是float32
。 -
ksize
: 一個長度不小於4的整型陣列。每一位上面的值對應於輸入資料張量中每一維的視窗對應值。 -
strides
: 一個長度不小於4的整型陣列。該引數指定滑動視窗在輸入資料張量每一維上面的步長。 -
padding
: 一個字串,取值為SAME
或者VALID
。 -
Targmax
: 一個可選的資料型別:tf.int32
或者tf.int64
。預設情況下是tf.int64
。 -
name
: (可選)為這個操作取一個名字。
輸出引數:
一個元祖張量 (output, argmax)
:
-
output
: 一個Tensor
,資料型別是float32
。表示池化區域的最大值。 -
argmax
: 一個Tensor
,資料型別是Targmax
。資料維度是四維的。
標準化
標準化是能防止模型過擬合的好方法。特別是在大資料的情況下。
tf.nn.l2_normalize(x, dim, epsilon=1e-12, name=None)
解釋:這個函式的作用是利用 L2 範數對指定維度 dim
進行標準化。
比如,對於一個一維的張量,指定維度 dim = 0
,那麼計算結果為:
output = x / sqrt( max( sum( x ** 2 ) , epsilon ) )
假設 x
是多維度的,那麼標準化只會獨立的對維度 dim
進行,不會影響到別的維度。
使用例子:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import numpy as np
import tensorflow as tf
input_data = tf.Variable( np.random.rand(2, 3), dtype = tf.float32 )
output = tf.nn.l2_normalize(input_data, dim = 0)
with tf.Session() as sess:
init = tf.initialize_all_variables()
sess.run(init)
print sess.run(output)
print sess.run(tf.shape(output))
輸入引數:
-
x
: 一個Tensor
。 -
dim
: 需要標準化的維度。 -
epsilon
: 一個很小的值,確定標準化的下邊界。如果norm < sqrt(epsilon)
,那麼我們將使用sqrt(epsilon)
進行標準化。 -
name
: (可選)為這個操作取一個名字。
輸出引數:
一個 Tensor
,資料維度和 x
相同。
tf.nn.local_response_normalization(input, depth_radius=None, bias=None, alpha=None, beta=None, name=None)
解釋:這個函式的作用是計算區域性資料標準化。
輸入的資料 input
是一個四維的張量,但該張量被看做是一個一維的向量( input
的最後一維作為向量),向量中的每一個元素都是一個三維的陣列(對應 input
的前三維)。向量的每一個元素都是獨立的被標準化的。具體數學形式如下:
sqr_sum[a, b, c, d] =
sum(input[a, b, c, d - depth_radius : d + depth_radius + 1] ** 2)
output = input / (bias + alpha * sqr_sum ** beta)
如果你想更加了解這種標準化,可以參考這篇論文。
使用例子:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import numpy as np
import tensorflow as tf
input_data = tf.Variable( np.random.rand(1, 2, 3, 4), dtype = tf.float32 )
output = tf.nn.local_response_normalization(input_data)
with tf.Session() as sess:
init = tf.initialize_all_variables()
sess.run(init)
print sess.run(input_data)
print sess.run(output)
print sess.run(tf.shape(output))
輸入引數:
-
input
: 一個Tensor
。資料維度是四維的,資料型別是float32
。 -
depth_radius
: (可選)一個整型,預設情況下是 5 。 -
bias
: (可選)一個浮點型,預設情況下是 1。一個偏移項,為了避免除0,一般情況下我們取正值。 -
alpha
: (可選)一個浮點型,預設情況下是 1。一個比例因子,一般情況下我們取正值。 -
beta
: (可選)一個浮點型,預設情況下是 0.5。一個指數。 -
name
: (可選)為這個操作取一個名字。
輸出引數:
一個 Tensor
,資料型別是 float32
。
tf.nn.moments(x, axes, name=None)
解釋:這個函式的作用是計算 x
的均值和方差。
沿著 axes
維度,計算 x
的均值和方差。如果 x
是一維的,並且 axes = [0]
,那麼就是計算整個向量的均值和方差。
如果,我們取 axes = [0, 1, 2] (batch, height, width)
,那麼我們就是計算卷積的全域性標準化。如果只是計算批處理的標準化,那麼我們取 axes = [0] (batch)
。
使用例子:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import numpy as np
import tensorflow as tf
input_data = tf.Variable( np.random.rand(2, 3), dtype = tf.float32 )
mean, variance = tf.nn.moments(input_data, [0])
with tf.Session() as sess:
init = tf.initialize_all_variables()
sess.run(init)
print sess.run(input_data)
print sess.run(mean)
print sess.run(tf.shape(mean))
輸入引數:
-
x
: 一個Tensor
。 -
axes
: 一個整型的陣列,確定計算均值和方差的維度 。 -
name
: 為這個操作取個名字。
輸出引數:
兩個 Tensor
,分別是均值 mean
和方差 variance
。
誤差值
度量兩個張量或者一個張量和零之間的損失誤差,這個可用於在一個迴歸任務或者用於正則的目的(權重衰減)。
tf.nn.l2_loss(t, name=None)
解釋:這個函式的作用是利用 L2 範數來計算張量的誤差值,但是沒有開方並且只取 L2 範數的值的一半,具體如下:
output = sum(t ** 2) / 2
使用例子:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import numpy as np
import tensorflow as tf
input_data = tf.Variable( np.random.rand(2, 3), dtype = tf.float32 )
output = tf.nn.l2_loss(input_data)
with tf.Session() as sess:
init = tf.initialize_all_variables()
sess.run(init)
print sess.run(input_data)
print sess.run(output)
print sess.run(tf.shape(output))
輸入引數:
-
t
: 一個Tensor
。資料型別必須是一下之一:float32
,float64
,int64
,int32
,uint8
,int16
,int8
,complex64
,qint8
,quint8
,qint32
。雖然一般情況下,資料維度是二維的。但是,資料維度可以取任意維度。 -
name
: 為這個操作取個名字。
輸出引數:
一個 Tensor
,資料型別和 t
相同,是一個標量。
分類操作
Tensorflow提供了操作,能幫助你更好的進行分類操作。
tf.nn.sigmoid_cross_entropy_with_logits(logits, targets, name=None)
解釋:這個函式的作用是計算 logits
經 sigmoid 函式啟用之後的交叉熵。
對於一個不相互獨立的離散分類任務,這個函式作用是去度量概率誤差。比如,比如,在一張圖片中,同時包含多個分類目標(大象和狗),那麼就可以使用這個函式。
為了描述簡潔,我們規定 x = logits
,z = targets
,那麼 Logistic 損失值為:
x - x * z + log( 1 + exp(-x) )
為了確保計算穩定,避免溢位,真實的計算實現如下:
max(x, 0) - x * z + log(1 + exp(-abs(x)) )
logits
和 targets
必須有相同的資料型別和資料維度。
使用例子:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import numpy as np
import tensorflow as tf
input_data = tf.Variable( np.random.rand(1,3), dtype = tf.float32 )
output = tf.nn.sigmoid_cross_entropy_with_logits(input_data, [[1.0,0.0,0.0]])
with tf.Session() as sess:
init = tf.initialize_all_variables()
sess.run(init)
print sess.run(input_data)
print sess.run(output)
print sess.run(tf.shape(output))
輸入引數:
-
logits
: 一個Tensor
。資料型別是以下之一:float32
或者float64
。 -
targets
: 一個Tensor
。資料型別和資料維度都和logits
相同。 -
name
: 為這個操作取個名字。
輸出引數:
一個 Tensor
,資料維度和 logits
相同。
tf.nn.softmax(logits, name=None)
解釋:這個函式的作用是計算 softmax 啟用函式。
對於每個批 i
和 分類 j
,我們可以得到:
softmax[i, j] = exp(logits[i, j]) / sum(exp(logits[i]))
使用例子:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import numpy as np
import tensorflow as tf
input_data = tf.Variable( [[0.2, 0.1, 0.9]] , dtype = tf.float32 )
output = tf.nn.softmax(input_data)
with tf.Session() as sess:
init = tf.initialize_all_variables()
sess.run(init)
print sess.run(input_data)
print sess.run(output)
print sess.run(tf.shape(output))
輸入引數:
-
logits
: 一個Tensor
。資料型別是以下之一:float32
或者float64
。資料維度是二維[batch_size, num_classes]
。 -
name
: 為這個操作取個名字。
輸出引數:
一個 Tensor
,資料維度和資料型別都和 logits
相同。
tf.nn.softmax_cross_entropy_with_logits(logits, labels, name=None)
解釋:這個函式的作用是計算 logits
經 softmax 函式啟用之後的交叉熵。
對於每個獨立的分類任務,這個函式是去度量概率誤差。比如,在 CIFAR-10 資料集上面,每張圖片只有唯一一個分類標籤:一張圖可能是一隻狗或者一輛卡車,但絕對不可能兩者都在一張圖中。(這也是和 `tf.nn.sigmoid_cross_entropy_with_logits(logits, targets, name=None)
`這個API的區別)
警告:輸入API的資料 logits
不能進行縮放,因為在這個API的執行中會進行 softmax 計算,如果 logits
進行了縮放,那麼會影響計算正確率。不要呼叫這個API區計算 softmax 的值,因為這個API最終輸出的結果並不是經過 softmax 函式的值。
logits
和 labels
必須有相同的資料維度 [batch_size, num_classes]
,和相同的資料型別 float32
或者 float64
。
使用例子:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import numpy as np
import tensorflow as tf
input_data = tf.Variable( [[0.2, 0.1, 0.9]] , dtype = tf.float32 )
output = tf.nn.softmax_cross_entropy_with_logits(input_data, [[1,0,0]])
with tf.Session() as sess:
init = tf.initialize_all_variables()
sess.run(init)
print sess.run(input_data)
print sess.run(output)
print sess.run(tf.shape(output))
輸入引數:
-
logits
: 一個沒有縮放的對數張量。 -
labels
: 每一行labels[i]
必須是一個有效的概率分佈值。 -
name
: 為這個操作取個名字。
輸出引數:
一個 Tensor
,資料維度是一維的,長度是 batch_size
,資料型別都和 logits
相同。
嵌入層
Tensorflow 提供了從張量中嵌入查詢的庫。
tf.nn.embedding_lookup(params, ids, name=None)
解釋:這個函式的作用是查詢 params
中索引是 ids
的值。
這個操作是 tf.gather()
的一個泛化,但它可以被平行計算處理,其中 params
被認為是一個大型的張量庫,ids
中的值對應於各個分割槽。
如果 len(params) > 1
,ids
中每個元素 id
對應於 params
中每個分割槽 p
,即 p = id % len(params)
。那麼,我們得到的每個切片是 params[p][id // len(params), ...]
。
最後得到的切片結果被重新連線成一個稠密張量,最後返回的張量維度是 shape(ids) + shape(params)[1: ]
。
使用例子:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import tensorflow as tf
import numpy as np
params = tf.constant(np.random.rand(3,4))
ids = tf.constant([0,2])
output = tf.nn.embedding_lookup(params, ids)
with tf.Session() as sess:
print `params: `, sess.run(params)
print `-------------------------------`
print `輸出第0行和第2行: `, sess.run(output)
輸入引數:
-
params
: 一個擁有相同資料維度和資料型別的張量。 -
ids
: 一個張量,資料型別是int32
。 -
name
: 為這個操作取個名字。
輸出引數:
一個 Tensor
,資料型別和 params
相同。
異常:
-
數值異常
: 如果params
是空的,那麼會丟擲這個異常。
評估操作
評估操作對於測量網路的效能是有用的。 由於它們是不可微分的,所以它們通常只是被用在評估階段。
tf.nn.top_k(input, k, name=None)
解釋:這個函式的作用是返回 input
中每行最大的 k
個數,並且返回它們所在位置的索引。
value(i, j)
表示輸入資料 input(i)
的第 j
大的元素。
indices(i, j)
給出對應元素的列索引,即 input(i, indices(i, j)) = values(i, j)
。如果遇到兩個相等的元素,那麼我們先取索引小的值。
使用例子:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import tensorflow as tf
import numpy as np
input = tf.constant(np.random.rand(3,4))
k = 2
output = tf.nn.top_k(input, k)
with tf.Session() as sess:
print sess.run(input)
print `--------------------`
print sess.run(output)
輸入引數:
-
input
: 一個張量,資料型別必須是以下之一:float32
、float64
、int32
、int64
、uint8
、int16
、int8
。資料維度是batch_size
乘上x
個類別。 -
k
: 一個整型,必須>= 1
。在每行中,查詢最大的k
個值。 -
name
: 為這個操作取個名字。
輸出引數:
一個元組 Tensor
,資料元素是 (values, indices)
,具體如下:
-
values
: 一個張量,資料型別和input
相同。資料維度是batch_size
乘上k
個最大值。 -
indices
: 一個張量,資料型別是int32
。每個最大值在input
中的索引位置。
tf.nn.in_top_k(predictions, targets, k, name=None)
解釋:這個函式的作用是返回一個布林向量,說明目標值是否存在於預測值之中。
輸出資料是一個 batch_size
長度的布林向量,如果目標值存在於預測值之中,那麼 out[i] = true
。
注意:targets
是predictions
中的索引位,並不是 predictions
中具體的值。
使用例子:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import tensorflow as tf
import numpy as np
input = tf.constant(np.random.rand(3,4), tf.float32)
k = 2
output = tf.nn.in_top_k(input, [3,3,3], k)
with tf.Session() as sess:
print sess.run(input)
print `--------------------`
print sess.run(output)
輸入引數:
-
predictions
: 一個張量,資料型別是float32
。資料維度是batch_size
乘上x
個類別。 -
targets
: 一個張量,資料型別是int32
。一個長度是batch_size
的向量,裡面的元素是目標class ID
。 -
k
: 一個整型。在每行中,查詢最大的k
個值。 -
name
: 為這個操作取個名字。
輸出引數:
一個張量,資料型別是 bool
。判斷是否預測正確。
Candidate Sampling
這是一些取樣的函式,由於目前不是很理解,暫且不學習……
作者:chen_h
微訊號 & QQ:862251340
簡書地址:https://www.jianshu.com/p/e3a…
CoderPai 是一個專注於演算法實戰的平臺,從基礎的演算法到人工智慧演算法都有設計。如果你對演算法實戰感興趣,請快快關注我們吧。加入AI實戰微信群,AI實戰QQ群,ACM演算法微信群,ACM演算法QQ群。長按或者掃描如下二維碼,關注 “CoderPai” 微訊號(coderpai)