Brief 概述
基於對 Tensorflow 大致的瞭解,並理解了流程圖設置的邏輯和運行方法後,我們逐漸的會發現其設計理念與機器學習深遠的匹配性。延續前面一章節最後的代碼,此單元記錄的模型和方法主要也是圍繞 「監督學習」 爲重點展開。構建一個內涵機器學習算法的流程圖後,我們就可以以一個參數作爲輸入,啓動計算流程並等待最終結果,大致的訓練過程如下流程:
- 建構好數學模型指向圖
- 初始化模型參數
- 輸入訓練用的數據集
- 從初始化的參數出發,推斷模型走向
- 和訓練集數據樣本比較,計算差異多寡, 此差異名爲損失
- 根據損失調整參數,重新回到步驟 3. 並不斷循環下去
模型在一次又一次的迭代訓練時,學習效率這個參數需要我們人工調整,只要確保整個學習結果朝向一個正確的方向走就是一個好的參數。一個完整的代碼框架如下演示:
import tensorflow as tf
# initialize variables and arguments in the math model
# define the operations within the training loop
def inference(X):
# calculate the result when substituting data X into the model
pass
def loss(X, Y):
# calculate loss value by substracting model output and training data
pass
def inputs():
# read or generate the training data X and the expected output Y
pass
def train(total_loss):
# adjust the model parameters based on the loss value
pass
def evaluate(sess, X, Y):
# evaluate the performance of a trained model
pass
# here is the routine procedure below
with tf.Session() as sess:
tf.global_variables_initializer().run()
X, Y = inputs()
total_loss = loss(X, Y)
train_op = train(total_loss)
cdr = tf.train.Coordinator()
threads = tf.train.start_queue_runners(sess=sess, coodr=cdr)
for step in range(1000):
sess.run([train_op])
if step % 10 == 0:
print('loss:', sess.run([total_loss]))
evaluate(sess, X, Y)
cdr.request_stop()
cdr.join(threads)
sess.close()
如代碼有些陌生之處,可以點擊此超鏈接閱讀上一篇文章: Tensorflow_01_Overview 全局概述
p.s. 編寫神經網絡代碼的時候,我們會習慣把一些功能集成到自定義的函數中,讓最後的代碼寫出來更易讀。
Functions in The Model 模型中的函數總覽
說到模型,裏面總會有許多 Tensorflow 所包含的類和方法是看着陌生的東西,下面是對於許多示範代碼中提取出來常見的函數列舉與附上代碼的詳細解釋,在理解的過程中可以逐漸對此模塊的構建邏輯有更清晰的認識。
p.s. 點擊 此鏈接 可以查看中文版的 Tensorflow 官方文檔
Tool Box 工具集函數
- tf.equal()
- tf.range()
- tf.stack()
- tf.unstack()
- tf.reshape()
- tf.cast()
- tf.split()
- tf.concat()
- tf.one_hot()
- tf.to_float()
- tf.transpose()
- tf.squeeze()
Calculating Operations 運算操作
Deep Learning 深度學習
- tf.nn.sigmoid()
- tf.nn.relu()
- tf.nn.softmax()
- tf.nn.conv2d()
- tf.nn.max_pool()
- tf.nn.dropout() ?????
- tf.nn.batch_normalization()
Gradient Descent 梯度下降
- tf.train.GradientDescentOptimizer()
- tf.train.MomentumOptimizer()
- tf.train.AdagradOptimizer()
- tf.train.RMSPropOptimizer()
- tf.train.AdamOptimizer()
- apply_gradients()
- compute_gradients()
- get_name()
- get_slot()
- get_slot_name()
- minimize()
- variables()
Tool Box 工具集函數
1. tf.equal(x, y, name=None) / tf.math.equal(x, y, name=None)
- x: 必須是一個張量 (Tensor) ,並且同時定義清楚該張量的數據類型
- y: 必須是一個跟 x 同類型,且維度也一模一樣的張量 (Tensor)
- name: 自定義此節點的名稱,用字符串表示
回傳結果: 一個同樣維度的張量,元素是 x 與 y 匹配結果的布爾值
import tensorflow as tf
a = [1, 2, 3, 3, 4]
b = [2, 2, 3, 4, 5]
sess = tf.Session()
print(sess.run(tf.equal(a, b, name='equal')))
sess.close()
### ----- Result is shown below ----- ###
[False True True False False]
2. tf.range(start, limit, delta=1, dtype=None, name='range')
- start: 一個範圍的起頭,回傳值**包含**此值
- limit: 一個範圍的結束,回傳值**不包含**此值
- delta: 開始結束值中間的取值間隔是多少,會取到最靠近 limit 值的值爲止
- dtype: 此回傳值全部的數據類型
- name: 自定義此節點的名稱,用字符串表示
回傳結果: 一個向量格式的列表數據 (只有一個維度)
import tensorflow as tf
sess = tf.Session()
print(sess.run(tf.range(3, 10, delta=2, dtype=tf.float32)))
sess.close()
### ----- Result is shown below ----- ###
[3. 5. 7. 9.]
3. tf.stack(values, axis=0, name='stack')
- values: 爲一個張量值 (Tensor),最好有明確的數據類型
- axis: 只有 0 與 1 兩個值, 0 表示維持張量的單純橫向元素疊加,增加維度;反之如果是 1 ,則疊加後的結果會被縱向元素堆疊後纔回傳結果
- name: 自定義此節點的名稱,用字符串表示
p.s. 此函數的原本名稱爲: tf.pack()
回傳結果: 是一個元素堆疊過後的總列表 (並不限制堆疊的元素有幾個維度,但是被堆疊在一起的元素必須形狀完全相同)
import tensorflow as tf
a = tf.constant([[1, 2, 3, 4], [2, 3, 4, 5]], dtype=tf.float32)
b = tf.constant([[3, 4, 5, 6], [5, 6, 7, 8]], dtype=tf.float32)
c = tf.constant([[11, 12, 13, 14], [13, 14, 15, 16]], dtype=tf.float32)
sess = tf.Session()
print(sess.run(tf.stack([a, b, c], axis=0, name=None)))
print('----- Separation -----')
print(sess.run(tf.stack([a, b, c], axis=1, name=None)))
sess.close()
### ----- Result is shown below ----- ###
[[[ 1. 2. 3. 4.]
[ 2. 3. 4. 5.]]
[[ 3. 4. 5. 6.]
[ 5. 6. 7. 8.]]
[[11. 12. 13. 14.]
[13. 14. 15. 16.]]]
----- Separation -----
[[[ 1. 2. 3. 4.]
[ 3. 4. 5. 6.]
[11. 12. 13. 14.]]
[[ 2. 3. 4. 5.]
[ 5. 6. 7. 8.]
[13. 14. 15. 16.]]]
4. tf.unstack(value, num=None, axis=0, name='unstack')
- value: 只能放入一個可以被分拆的張量中, 最好有宣告好數據類型
- num: 表示要被分割的段數,但是經過嘗試我們沒辦法把例如四段張量用其公因數切分,還是比需按照原本的總量尺寸逐一切分,因此爲了方便起見我們就填 None ,但是初始值就是 None ,一番折騰後發現有跟沒有是一樣的
- axis: 只有 0 與 1 兩個值, 類似 stack , 0 是橫向拆分,而 1 是縱向拆分
- name: 自定義此節點的名稱,用字符串表示
回傳結果: 是一個拆分後的子張量,並用一個列表的形式回傳
import tensorflow as tf
a = tf.constant([[1, 2, 3, 4], [4, 5, 6, 7], [7, 8, 9, 10]],
dtype=tf.float32)
sess = tf.Session()
print(sess.run(tf.unstack(a, num=3, axis=0, name=None)))
sess.close()
### ----- Result is shown below ----- ###
[array([1., 2., 3., 4.], dtype=float32),
array([4., 5., 6., 7.], dtype=float32),
array([7., 8., 9., 10.], dtype=float32)]
5. tf.reshape(Tensor, shape, name=None)
- Tensor: 給定一個需要被重組的張量值
- shape: 必填,給定一個重組後的張量形狀,描述形狀的數字類型必須是 int32/int64,維度等信息。其中 「-1」 是一個特殊的存在,最多可以填在一個維度上,而 tf 會自動計算該張量變換形狀後填了 -1 的維度值大小
- name: 自定義此節點的名稱,用字符串表示
回傳結果: 是一個改變形態後的新的張量,裏面的元素內容原封不動
import tensorflow as tf
k = tf.constant([1, 2, 3, 4, 5, 6, 7, 8, 9])
h = tf.constant([[[1, 1, 1],
[2, 2, 2]],
[[3, 3, 3],
[4, 4, 4]],
[[5, 5, 5],
[6, 6, 6]]])
sess = tf.Session()
print(sess.run(tf.reshape(k, shape=[3, 3])))
print('----- Separation -----')
print(sess.run(tf.reshape(h, shape=(2, 3, -1))))
sess.close()
### ----- Result is shown below ----- ###
[[1 2 3]
[4 5 6]
[7 8 9]]
----- Separation -----
[[[1 1 1]
[2 2 2]
[3 3 3]]
[[4 4 4]
[5 5 5]
[6 6 6]]]
6. tf.cast(x, dtype, name=None)
- x: 一個張量傳入,抑或一個數字類型的數據
- dtype: 把傳入的數據轉換成這裏指定的數據類型
- name: 自定義此節點的名稱,用字符串表示
回傳結果: 還是原來的函數,只是數據類型變了
import tensorflow as tf
x = tf.constant([1.8, 2.2], dtype=tf.float32)
sess = tf.Session()
print(sess.run(tf.cast(x, tf.int32)))
sess.close()
### ----- Result is shown below ----- ###
[1 2]
7. tf.split(value, num_or_size_splits, axis=0, num=None, name='split')
- value: 一個準備被拆分的張量值
- num_or_size_splits: 可以是一個數字,意味着橫着把輸入的張量批成幾刀,也可以是向量,意味着把一個張量拆成兩個內涵向量中數字多寡之元素的張量,如下代碼
- axis: 只有 0 和 1 的輸入, 0 表示正常形狀切割, 1 表示先轉置過後再切割
- num: 一般不寫,只是用來表明即將要被分成幾塊,如果我們預期的結果與實際上不同,則報錯,是一個讓代碼與邏輯更清晰的工具
- name: 自定義此節點的名稱,用字符串表示
回傳結果: 一個被拆分後的新張量, 使用一個列表數據形態概括拆分後的結果
import tensorflow as tf
p = tf.constant([1, 2, 3, 4, 5, 6], shape=(4, 2), dtype=tf.float32)
sess = tf.Session()
print(sess.run(p))
print('----- Separation -----')
print(sess.run(tf.split(p, 2, axis=0)))
print('----- Separation -----')
print(sess.run(tf.split(p, [1, 3], axis=0, num=2)))
sess.close()
### ----- Result is shown below ----- ###
[[1. 2.]
[3. 4.]
[5. 6.]
[6. 6.]]
----- Separation -----
[array([[1., 2.],
[3., 4.]], dtype=float32), array([[5., 6.],
[6., 6.]], dtype=float32)]
----- Separation -----
[array([[1., 2.]], dtype=float32), array([[3., 4.],
[5., 6.],
[6., 6.]], dtype=float32)]
8. tf.concat(values, axis, name='concat')
- values: 一個即將要被合在一起之列表組成的多個張量,或是單一個張量
- axis: 我們指定沿着哪一個維度來合併兩個要被連在一起的張量, 0 表示 1D, 1 表示 2D, 以此類推
- name: 自定義此節點的名稱,用字符串表示
回傳結果: 回傳一個沿着指定的座標軸疊加了幾個目標張量的張量,用列表方式展示
import tensorflow as tf
T1 = tf.constant([[[1, 1, 1], [2, 2, 2]], [[3, 3, 3], [4, 4, 4]]])
T2 = tf.constant([[[5, 5, 5], [6, 6, 6]], [[7, 7, 7], [8, 8, 8]]])
sess = tf.Session()
print(sess.run(tf.concat([T1, T2], 0)))
print('----- Separation -----')
print(sess.run(tf.concat([T1, T2], 1)))
print('----- Separation -----')
print(sess.run(tf.concat([T1, T2], 2)))
sess.close()
### ----- Result is shown below ----- ###
[[[1 1 1]
[2 2 2]]
[[3 3 3]
[4 4 4]]
[[5 5 5]
[6 6 6]]
[[7 7 7]
[8 8 8]]]
----- Separation -----
[[[1 1 1]
[2 2 2]
[5 5 5]
[6 6 6]]
[[3 3 3]
[4 4 4]
[7 7 7]
[8 8 8]]]
----- Separation -----
[[[1 1 1 5 5 5]
[2 2 2 6 6 6]]
[[3 3 3 7 7 7]
[4 4 4 8 8 8]]]
9. tf.one_hot(indices, depth, on_value=None, off_value=None, axis=None, dtype=None, name=None)
- indices: 一個一維的列表數組,內部只能是數字元素,數字只能是整數類型,數字表示的是生成結果元素在該維度下的 「位置」 信息,意味着列表裏面的數字不能夠大於列表的總長度,不然該位置不存在。函數的結果將以此列表加一個維度的方式展現
- depth: 根據 indices 提供的總位置信息,可以用此參數選擇打印出來的比例,最大值就是該信息列表的總長,函數的結果就是一個方陣
- on_value: 根據選中的位置,統一填上的值在這裏設定,數據類型需要統一
- off_value: 根據選中位置之外的位置,填上的值在這裏設定,數據類型也需要統一
- axis: 要沿着什麼軸打印,默認值是 -1, 0 在這邊反而被轉置過, 1 功能等於 -1
- dtype: 必須跟 indices 的數據類型相同,且只限制整數的數據類型,否則報錯
- name: 自定義此節點的名稱,用字符串表示
回傳結果: 一個比 indices 還要多一個維度的張量,只有兩種元素組成,分別是 on_value 和 off_value,如下代碼
import tensorflow as tf
t = tf.constant([0, 1, 2, 0, 3, 5], dtype=tf.int32)
sess = tf.Session()
print(sess.run(tf.one_hot(t, depth=6, on_value=1, off_value=0,
axis=-1, dtype=tf.int32)))
print('----- Separation -----')
print(sess.run(tf.one_hot(t, depth=6, on_value=9, off_value=1,
axis=0, dtype=tf.int32)))
print('----- Separation -----')
print(sess.run(tf.one_hot(t, depth=4, on_value=1, off_value=0,
axis=1, dtype=tf.int32)))
sess.close()
### ----- Result is shown below ----- ###
[[1 0 0 0 0 0]
[0 1 0 0 0 0]
[0 0 1 0 0 0]
[1 0 0 0 0 0]
[0 0 0 1 0 0]
[0 0 0 0 0 1]]
----- Separation -----
[[9 1 1 9 1 1]
[1 9 1 1 1 1]
[1 1 9 1 1 1]
[1 1 1 1 9 1]
[1 1 1 1 1 1]
[1 1 1 1 1 9]]
----- Separation -----
[[1 0 0 0]
[0 1 0 0]
[0 0 1 0]
[1 0 0 0]
[0 0 0 1]
[0 0 0 0]]
10. tf.to_float(x, name='ToFloat')
- x: 傳入一個要被改成 tf.float32 數據形態的張量
- name: 自定義此節點的名稱,用字符串表示
p.s. 同樣類似的函數方法可以在官網鏈接中查找並使用,如下代碼
回傳結果: 回傳一個外觀和值都一模一樣的張量數據,只是數據類型改成了 tf.float32
import tensorflow as tf
t = tf.constant([1, 2, 3, 4], shape=(2, 2), dtype=tf.int32)
sess = tf.Session()
print(sess.run(t))
print('----- Separation -----')
print(sess.run(tf.to_float(t)))
print('----- Separation -----')
print(sess.run(tf.to_complex64(t)))
print('----- Separation -----')
print(sess.run(tf.to_bfloat16(t)))
sess.close()
### ----- Result is shown below ----- ###
[[1 2]
[3 4]]
----- Separation -----
[[1. 2.]
[3. 4.]]
----- Separation -----
[[1.+0.j 2.+0.j]
[3.+0.j 4.+0.j]]
----- Separation -----
[[bfloat16(1) bfloat16(2)]
[bfloat16(3) bfloat16(4)]]
11. tf.transpose(a, perm=None, name='transpose', conjugate=False)
- a: 一個即將要被轉置的張量
- perm: 默認是 None ,用一個列表表示,內部的元素值代表輸入張量 a 的維度排列位置, 如果 a 是一個三維矩陣,此列表元素值就不能大於 2 ,原始的張量排列就是 0 1 2, 如果要轉置, 就調換 0 1 2 彼此的排列,以此告訴此函數轉制的方向
- name: 自定義此節點的名稱,用字符串表示
- conjugate: 布爾值,是否回傳如果是複數的共軛結果
回傳結果: 即 a 張量沿着我們設定的方向轉置之後的新張量
import tensorflow as tf
x = tf.constant([i+1 for i in range(12)], shape=(2, 3, 2), dtype=tf.complex64)
sess = tf.Session()
print(sess.run(x))
print('----- Separation -----')
print(sess.run(tf.transpose(x, perm=[0, 2, 1], conjugate=True)))
print('----- Separation -----')
print(sess.run(tf.transpose(x, perm=[1, 2, 0], conjugate=False)))
### ----- Result is shown below ----- ###
[[[ 1.+0.j 2.+0.j]
[ 3.+0.j 4.+0.j]
[ 5.+0.j 6.+0.j]]
[[ 7.+0.j 8.+0.j]
[ 9.+0.j 10.+0.j]
[11.+0.j 12.+0.j]]]
----- Separation -----
[[[ 1.-0.j 3.-0.j 5.-0.j]
[ 2.-0.j 4.-0.j 6.-0.j]]
[[ 7.-0.j 9.-0.j 11.-0.j]
[ 8.-0.j 10.-0.j 12.-0.j]]]
----- Separation -----
[[[ 1.+0.j 7.+0.j]
[ 2.+0.j 8.+0.j]]
[[ 3.+0.j 9.+0.j]
[ 4.+0.j 10.+0.j]]
[[ 5.+0.j 11.+0.j]
[ 6.+0.j 12.+0.j]]]
12. tf.squeeze(input, axis=None, name=None)
- input: 一個預計要被壓縮的張量
- axis: 可以讓使用者自定義張量的哪幾個只有一個元素的維度要被壓縮,一般使用列表來表示維度位置
- name: 自定義此節點的名稱,用字符串表示
回傳結果: 一個被壓縮過後的張量,內部的值全部保持不動,是一個單純維度上的調整
import tensorflow as tf
t = tf.constant([i+1 for i in range(12)], shape=(1, 2, 1, 3, 2, 1, 1))
sess = tf.Session()
print(sess.run(tf.squeeze(t)))
print('----- Separation -----')
print(sess.run(tf.squeeze(t, axis=[2, 5])))
# the shape of t would be shape=(1, 2, 3, 2, 1)
### ----- Result is shown below ----- ###
[[[ 1 2]
[ 3 4]
[ 5 6]]
[[ 7 8]
[ 9 10]
[11 12]]]
----- Separation -----
[[[[[ 1]
[ 2]]
[[ 3]
[ 4]]
[[ 5]
[ 6]]]
[[[ 7]
[ 8]]
[[ 9]
[10]]
[[11]
[12]]]]]
Calculating Operations 運算操作
1. tf.matmul(a, b, transpose_a=False, transpose_b=False, adjoint_a=False, adjoint_b=False, a_is_sparse=False, b_is_sparse=False, name=None)
- a, b: 爲兩個同樣尺寸和數據類型的矩陣,兩個預備做內積的矩陣 a*b, 支持的數據類型有 int32, float16/32/64, complex64/128
- transpose: 使用布爾值設置矩陣內積前是否先被轉置
- adjoint: 使用布爾值設置矩陣內積前是否先做伴隨矩陣
- a_is_sparse: 如果相乘的矩陣中有很多 0 元素,則可以把這個布爾值調成 True 加速運算
- name: 自定義此節點的名稱,用字符串表示
回傳結果: 得到兩個矩陣的內積答案,並維持計算完的尺寸和數據類型
import tensorflow as tf
t_1 = tf.constant([1, 2, 3, 4, 5, 6], shape=(2, 3), dtype=tf.float32)
t_2 = tf.constant([6, 7, 8, 0, 0, 0], shape=[3, 2], dtype=tf.float32)
sess = tf.Session()
print(sess.run(t_1), '\n', sess.run(t_2))
print('----- Separation -----')
print(sess.run(tf.matmul(t_1, t_2, b_is_sparse=True)))
sess.close()
### ----- Result is shown below ----- ###
[[1. 2. 3.]
[4. 5. 6.]]
[[6. 7.]
[8. 0.]
[0. 0.]]
----- Separation -----
[[22. 7.]
[64. 28.]]
2-4. tf.reduce_sum(Tensor, axis=None, keepdims=False, name=None, reduction_indices=None)
- Tensor: 一個任意數字類型的張量,不限形狀
- axis: 要沿着哪一個維度縮減,值爲 0 表示橫向, 1 表示縱向,如果是默認值 None 就尺寸都縮減成只有 1
- keepdims: 如果設爲 True, 則保留縮減後原本的維度,不整合成一個
- name: 自定義此節點的名稱,用字符串表示
p.s. 此模塊部分沒有寫出來的參數意義就是一些即將被淘汰的部分,因此不重要。 reduce_mean() 和 reduce_max() 也都是一模一樣的原理
回傳結果:一個被縮減其中某寫維度的張量,縮減的辦法是使用加法把所有的元素加總起來,回傳到一個自定義的張量中,必須限定是數字的數據類型
import tensorflow as tf
e = tf.constant([[1, 2, 3], [4, 5, 6], [7, 8, 9], [0, 0, 0]])
sess = tf.Session()
print(sess.run(tf.reduce_sum(e, axis=1)))
print('----- Separation -----')
print(sess.run(tf.reduce_mean(e, axis=1, keepdims=True)))
print('----- Separation -----')
print(sess.run(tf.reduce_max(e, axis=0, keepdims=True)))
sess.close()
### ----- Result is shown below ----- ###
[ 6 15 24 0]
----- Separation -----
[[2]
[5]
[8]
[0]]
----- Separation -----
[[7 8 9]]
Deep Learning 深度學習
1. tf.nn.sigmoid(x, name=None)
- x: 是一個不限維度的張量值傳入,限制數據類型只能是 float16/32/64, complex64/128
- name: 自定義此節點的名稱,用字符串表示
p.s. tf.nn.sigmoid() == tf.sigmoid() 目前兩者並存
回傳結果: 即 1 / (1 + exp(-x)) 的計算結果,如果張量裏面不止一個數值,則分別帶入計算後,返回同樣尺寸和和數據類型的結果
2. tf.nn.relu(features, name=None)
- features: 是一個不限維度的張量值傳入,限制數據類型不能是複數,詳情點擊上面超鏈接查看官方文檔
- name: 自定義此節點的名稱,用字符串表示
回傳結果: 即 max(features, 0) ,在大於零的情況下維持線性關係,小於零的情況下皆爲零
import tensorflow as tf
m = tf.constant([3, 0.8, 0.2], dtype=tf.float32)
sess = tf.Session()
print(sess.run(tf.nn.sigmoid(m)))
print(sess.run(tf.nn.relu(m)))
# so did the other activation functions
sess.close()
### ----- Result is shown below ----- ###
[0.95257413 0.6899745 0.54983395]
[3. 0.8 0.2]
3. tf.nn.softmax(logits, axis=None, name=None)
- logits: 即一個非空着的張量,其數據類型必須是 tf.float32/64, half
- axis: 可以選擇一個張量其中一個橫排套如此公式,得出的結果
- name: 自定義此節點的名稱,用字符串表示
softmax formula:
- softmax = tf.exp(logits) / tf.reduce_sum(tf.exp(logits), axis)
回傳結果: 一個張量經過 softmax 數學運算後得出來同樣形狀與數據類型的結果
import tensorflow as tf
t = tf.constant([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], shape=(3, 4), dtype=tf.float32)
t2 = tf.constant([1, 5, 9], dtype=tf.float32)
t3 = tf.constant([1, 2, 3, 4], dtype=tf.float32)
sess = tf.Session()
print(sess.run(t))
print('----- Separation -----')
print(sess.run(tf.nn.softmax(t, axis=-1)))
print('----- Separation -----')
print(sess.run(tf.nn.softmax(t, axis=0)))
print('----- Separation -----')
print(sess.run(tf.nn.softmax(t2)))
print('----- Separation -----')
print(sess.run(tf.nn.softmax(t3)))
sess.close()
### ----- Result is shown below ----- ###
[[ 1. 2. 3. 4.]
[ 5. 6. 7. 8.]
[ 9. 10. 11. 12.]]
----- Separation -----
[[0.0320586 0.08714432 0.23688284 0.6439143 ]
[0.0320586 0.08714432 0.23688284 0.6439143 ]
[0.0320586 0.08714432 0.23688284 0.6439143 ]]
----- Separation -----
[[3.2932041e-04 3.2932041e-04 3.2932041e-04 3.2932041e-04]
[1.7980287e-02 1.7980287e-02 1.7980287e-02 1.7980287e-02]
[9.8169035e-01 9.8169035e-01 9.8169035e-01 9.8169035e-01]]
----- Separation -----
[3.2932041e-04 1.7980287e-02 9.8169035e-01]
----- Separation -----
[0.0320586 0.08714432 0.23688284 0.6439143 ]
4. tf.nn.conv2d(input, filter, strides, padding, use_cudnn_on_gpu=True, data_format='NHWC', dilations=[1, 1, 1, 1], name=None)
- input: 爲一個需要做卷積的圖像四維張量數據,數據類型只能都是 tf.float32/64, half, 其中張量中包含了 [batch, in_height, in_width, in_channels], 分別對應的是, 1)每一批次訓練的圖片張數 2)每張圖片的高 3)每張照片的寬 4) 每張照片的顏色通道(照片數據深度)
- filter: 爲一個卷積核,用來跟別人做卷積之同維度的張量數據,張量包含了 [filter_height, filter_width, in_channels, out_channels], 分別對應到的是 1)匹配被掃描數據的高 2)匹配被掃描數據的寬 3)匹配被掃描數據的顏色通道 4)卷積核的個數
- strides: 爲一個內涵四個整數形態元素的一維列表數據,注意只能是整數,該四個整數分別表示卷積核在輸入數據的每個維度上每次移動的距離,參數順序由 data_format 明確定義
- padding: 只有兩組字符串輸入 1)'SAME'表示需添加 0 元素到被掃描數據的邊框,使得卷積核掃描過後的輸出數據尺寸保持保持不變 2)'VALID'則不加 0 元素,讓掃描結果的尺寸自然遞減
- use_cudnn_on_gpu: 輸入必須是布爾值,是一個是否使用 GPU 加速運算的開關
- data_format: 使用字符串表明輸入數據格式, NHWC 是默認值 (batch, height, width, channels), 也可以調成 NCHW (batch, channels, height, width)
- dilations: 爲一個內涵四個整數形態元素的一維列表數據,注意只能是整數,該四個整數分別表示卷積核在輸入數據的每個維度上掃描時跳過了(對應該維度數字 -1 )個數據後得出來的結果,跟感受野的原理同源,參數順序由 data_format 明確定義
- name: 自定義此節點的名稱,用字符串表示
回傳結果: 同樣數據類型的張量,不過經過卷積核的一番掃描和運算,其各個維度的尺寸很可能都會受到影響。需要注意的是,卷積運算時使用的格式是以 「圖片」 在 Python 中的數據形式來展開計算,需要把圖片的數據形態 「側着看」, 使得圖片顏色數據的元素個數用 column 的行數來表示,等所有運算都完成後,我們再使用其他方法把此 「側着」 的列表數據翻成正面方可直觀理解運算結果
import tensorflow as tf
i = tf.constant([[4, 3, 1, 0, 5],
[2, 1, 0, 1, 3],
[1, 2, 4, 1, 4],
[3, 1, 0, 2, 0],
[2, 2, 4, 5, 1]], dtype=tf.float32, name='i')
k = tf.constant([[1, 0, 1],
[2, 1, 0],
[0, 0, 1]], dtype=tf.float32, name='k')
image = tf.reshape(i, [1, 5, 5, 1], name='image')
kernel = tf.reshape(k, [3, 3, 1, 1], name='kernel')
result = tf.nn.conv2d(image, kernel, strides=[1, 1, 1, 1],
padding="VALID", use_cudnn_on_gpu=False,
data_format='NHWC', dilations=[1, 1, 1, 1])
Format = tf.squeeze(result)
sess = tf.Session()
# print(sess.run(image))
# print(sess.run(kernel))
# print(sess.run(result))
print(sess.run(Format))
sess.close()
### ----- Result is shown below ----- ###
[[14. 6. 11.]
[ 6. 12. 12.]
[16. 10. 11.]]
5. tf.nn.max_pool(value, ksize, strides, padding, data_format='NHWC', name=None)
- value: 爲一個需要做縮減的圖像四維張量數據,數據類型只要是數字都可以,其四維的排列順序預設是 batch, height, width, channels ,具體的順序還需要 data_format 給出最終的判斷
- ksize: 爲一個內涵四個整數類型數據的列表, 設定每個維度的縮減單元大小, 預設序列是 batch, height, width, channels, batch 同樣也可以被用來池化
- strides: 爲一個內涵四個整數形態元素的一維列表數據,注意只能是整數,該四個整數分別表示卷積核在輸入數據的每個維度上每次移動的距離,參數順序由 data_format 明確定義
- padding: 只有兩組字符串輸入 1)'SAME'表示需添加 0 元素到被掃描數據的邊框,使得卷積核掃描過後的輸出數據尺寸保持保持不變 2)'VALID'則不加 0 元素,讓掃描結果的尺寸自然遞減
- data_format: 使用字符串表明輸入數據格式, NHWC 是默認值 (batch, height, width, channels), 也可以調成 NCHW (batch, channels, height, width),另一個新的 NCHW_VECT_C 也同樣支持
- name: 自定義此節點的名稱,用字符串表示
p.s. 尚有如 tf.nn.avg_pool() 同類的函數,參數一模一樣,只是運算是取平均
回傳結果: 爲一個同樣維度的張量, 經過池化處理後每個維度上的元素總量都有一定的縮減
import tensorflow as tf
i = tf.constant([[4, 3, 1, 0, 5, 3],
[2, 1, 0, 1, 3, 4],
[1, 2, 4, 1, 4, 2],
[3, 1, 0, 2, 0, 1],
[2, 2, 4, 5, 1, 2],
[3, 4, 2, 4, 1, 2]], dtype=tf.float32)
image = tf.reshape(i, [1, 6, 6, 1])
result = tf.nn.max_pool(image, [1, 2, 2, 1], strides=[1, 1, 1, 1],
padding='VALID', data_format='NHWC')
Format = tf.squeeze(result)
sess = tf.Session()
print(sess.run(Format))
sess.close()
### ----- Result is shown below ----- ###
[[4. 3. 1. 5. 5.]
[2. 4. 4. 4. 4.]
[3. 4. 4. 4. 4.]
[3. 4. 5. 5. 2.]
[4. 4. 5. 5. 2.]]
6. tf.nn.dropout(x, keep_prob, noise_shape=None, seed=None, name=None)
- x: 爲一個隨意尺寸的張量,只要張量內部元素皆可爲浮點數即可
- keep_prob: 每一個元素被保存下來的機率, 用 0.xx 的形式表示,最小不能夠爲 0 ,而最大可以是 1 ,意味着全部元素都被保留下來
- nosie_shape: ?????
- seed: ?????
- name: 定義此節點的名稱,用字符串表示
p.s. 經過 dropout 訓練出來的值需要乘上 (1-p)% ,p 表示在 dropout 中有多少比例的神經單元被丟棄
回傳結果: 一個同樣尺寸的張量,不過其內部元素中依照 keep_prob 的比例被設成了 0 ,造成在後面的函數運算中不起作用
import tensorflow as tf
i = tf.constant([[4, 3, 1, 0, 5, 3],
[2, 1, 0, 1, 3, 4],
[1, 2, 4, 1, 4, 2],
[3, 1, 0, 2, 0, 1],
[2, 2, 4, 5, 1, 2],
[3, 4, 2, 4, 1, 2]], dtype=tf.float32)
c = tf.reshape(i, shape=(1, 3, 3, 4))
Dropout = tf.nn.dropout(i, 0.5, noise_shape=[1, 1, 3, 4])
sess = tf.Session()
print(sess.run(Dropout))
sess.close()
### ----- Result is shown below ----- ###
[[[[0. 0. 0. 0.]
[0. 0. 0. 2.]
[0. 0. 6. 0.]]
[[0. 0. 0. 0.]
[0. 0. 0. 2.]
[0. 0. 0. 0.]]
[[0. 0. 0. 0.]
[0. 0. 0. 8.]
[0. 0. 2. 0.]]]]
7. tf.nn.batch_normalization(x, mean, variance, offset, scale, variance_epsilon, name=None)
- x: 爲一個隨意維度的張量,最好是浮點數形態不容易出錯
- mean: 一個代表平均數的張量
- variance: 一個代表統計中方差的張量
- offset: 表示此公式算法中 beta 的值,也是一個張量
- scale: 表示此公式算法中 gama 的值,也是一個張量
- variance_epsilon: 一個用來避免被 0 所除所造成錯誤的浮點數
- name: 定義此節點的名稱,用字符串表示
p.s. 每個參數都是必填項目,都是公式計算的必須參數 p.s.s. 其他的歸一化方法也都是類似的,都給定一個公式,然後該公式後面依序掛着一個又一個公式必要得參數項,如 tf.nn.local_response_normalization() 也是另一個典型的歸一化方法之一
回傳結果: 爲一個尺寸與 x 一模一樣的張量,不過張量中的每個元素都會被 Batch Normalization 算法套過一遍然後得出來的運算結果取代該元素作爲回傳張量
import tensorflow as tf
x = tf.constant([i+1 for i in range(36)], shape=(3, 4, 3), dtype=tf.float32)
BN = tf.nn.batch_normalization(x, mean=2, variance=1, offset=3,
scale=1, variance_epsilon=0.01)
sess = tf.Session()
print(sess.run(BN))
sess.close()
### ----- Result is shown below ----- ###
[[[ 2.004963 3. 3.995037 ]
[ 4.990074 5.9851117 6.980149 ]
[ 7.975186 8.970222 9.9652605]
[10.960298 11.955335 12.950372 ]]
[[13.945409 14.940446 15.935483 ]
[16.93052 17.925558 18.920595 ]
[19.915632 20.91067 21.905706 ]
[22.900743 23.89578 24.890818 ]]
[[25.885855 26.880892 27.875929 ]
[28.870966 29.866003 30.86104 ]
[31.856077 32.851112 33.846153 ]
[34.84119 35.836227 36.831264 ]]]
Gradient Descent 梯度下降
1-5. tf.train.AdamOptimizer(learning_rate=0.001, beta1=0.9, beta2=0.999, epsilon=1e-08, use_locking=False, name='Adam')
- learning_rate: 一個浮點數張量,或是一個浮點數值
- beta1: 一個浮點數張量,或是一個浮點數值, 第一個函數動量的指數下降率
- beta2: 一個浮點數張量,或是一個浮點數值, 第二個函數動量的指數下降率
- epsilon: 一個很小的常數,用來確保數字的穩定性
- use_locking: 如果是 True ,則使用 locks 在操作子上 ?????
- name: 定義此節點的名稱,用字符串表示
回傳結果: 這些梯度下降的算法都是 「類」 ,意味着他們還可以用來創造示例然後呼叫方法,下面是他們的方法列舉:
- apply_gradients()
- compute_gradients()
- get_name()
- get_slot()
- get_slot_name()
- minimize()
- variables()
等到方法被呼叫後,纔會回傳一個計算好梯度的結果。
下一篇文章: Tensorflow_03_Save and Restore 儲存和載入