聲明
機緣巧合下,如雷貫耳了TensorFlow框架。略覽后欣喜,遂決心深入研究。文章是本人在自研人工智能的道路上,通過閱讀、視頻、博客等形式記錄的所見所聞。介于小白鼠屬性滿格,難免漏洞,請諸位大神不吝賜教,也請其他小白不要糾結。若涉及侵權,煩請告知,必刪;若閱完有點滴心得,定竊喜不枉辛勞。
計算機自發(fā)明以來,一直扮演人類祖先的角色:以自我為中心(計算密集型,涉及CPU計算、GPU計算等,比如TensorFlow),瘋狂攫取外界資源(IO密集型——涉及HTTP請求、磁盤操作等,比如Django、Scrapy)。直至現(xiàn)今,瘋狂到想讓電腦直接變成人腦。哎,技術無罪,有罪的是掌握技術的人。為什么要寫這段呢,因為我也不知道。
TensorFlow簡單三步驟:使用 tensor 表示數(shù)據(jù);使用圖 (graph) 來表示計算任務;在會話(session)中運行圖。TensorFlow字面意思是由Tensor(張量)和Flow(流)組成。實際上還包括:
1、Operation,專門運算的操作節(jié)點;
2、Graph圖,整個程序的結構,包括輸入,輸入的流向,輸出等;
3、Session會話,專門用于運行程序所建立的圖。
TensorFlow分為前端系統(tǒng)和后端系統(tǒng),前端系統(tǒng)(Tensor、Operation、Graph)負責定義程序的圖的結構,后端系統(tǒng)(Session)負責運算圖的結構。TensorFlow程序通常被組織成一個構建階段和一個執(zhí)行階段。在構建階段,op的執(zhí)行步驟被描述成一個圖。在執(zhí)行階段,使用會話執(zhí)行執(zhí)行圖中的op。
Tensor
張量,重要概念。類型是對numpy的ndarray類型的封裝,類似于數(shù)組;階,類似于數(shù)組的維。張量有如下屬性:operation、name、shape(0維表示為(),1維表示為(2),2維表示為(?,2))、graph。在TensorFlow中,有很多操作張量的函數(shù),有生成張量、創(chuàng)建隨機張量、張量類型與形狀變換和張量的切片與運算。
tf.zeros(shape, dtype=tf.float32, name=None)
創(chuàng)建所有元素設置為零的張量。此操作返回一個dtype具有形狀shape和所有元素設置為零的類型的張量。
tf.zeros_like(tensor, dtype=None, name=None)
給tensor定單張量(),此操作返回tensor與所有元素設置為零相同的類型和形狀的張量。
tf.ones(shape, dtype=tf.float32, name=None)
創(chuàng)建一個所有元素設置為1的張量。此操作返回一個類型的張量,dtype形狀shape和所有元素設置為1。
tf.ones_like(tensor, dtype=None, name=None)
給tensor定單張量(),此操作返回tensor與所有元素設置為1 相同的類型和形狀的張量。
tf.fill(dims, value, name=None)
創(chuàng)建一個填充了標量值的張量。此操作創(chuàng)建一個張量的形狀dims并填充它value。
tf.constant(value, dtype=None, shape=None, name='Const')
創(chuàng)建一個常數(shù)張量。
tf.truncated_normal(shape, mean=0.0, stddev=1.0, dtype=tf.float32, seed=None, name=None)
從截斷的正態(tài)分布中輸出隨機值,和 tf.random_normal() 一樣,但是所有數(shù)字都不超過兩個標準差
tf.random_normal(shape, mean=0.0, stddev=1.0, dtype=tf.float32, seed=None, name=None)
從正態(tài)分布中輸出隨機值,由隨機正態(tài)分布的數(shù)字組成的矩陣
tf.random_uniform(shape, minval=0.0, maxval=1.0, dtype=tf.float32, seed=None, name=None)
從均勻分布輸出隨機值。生成的值遵循該范圍內(nèi)的均勻分布 [minval, maxval)。下限minval包含在范圍內(nèi),而maxval排除上限。
tf.random_shuffle(value, seed=None, name=None)
沿其第一維度隨機打亂
tf.set_random_seed(seed)
設置圖級隨機種子
tf.string_to_number(string_tensor, out_type=None, name=None)
將輸入Tensor中的每個字符串轉換為指定的數(shù)字類型。注意,int32溢出導致錯誤,而浮點溢出導致舍入值
tf.shape(input, name=None)
返回張量的形狀
tf.squeeze(input, squeeze_dims=None, name=None)
這個函數(shù)的作用是將input中維度是1的那一維去掉。但是如果你不想把維度是1的全部去掉,那么你可以使用squeeze_dims參數(shù),來指定需要去掉的位置
tf.expand_dims(input, dim, name=None)
該函數(shù)作用與squeeze相反,添加一個指定維度
張量頻繁用到的操作是形狀的改變,即維度的變化(一維變二維,或者兩列變?nèi)校?。涉及靜態(tài)改變形狀和動態(tài)改變形狀。
靜態(tài)形狀的改變指:不改變維度,只改變維度中的行列數(shù);一旦張量形狀固定,不能再次進行修改。
動態(tài)形狀的改變指改變維度。動態(tài)形狀和靜態(tài)形狀的區(qū)別:有沒有生成一個新的張量。兩種形狀的改變都不能改變張量的總大小。
如果你定義了一個沒有標明具體維度的占位符,即用None表示維度,那么當你將值輸入到占位符時,這些無維度就是一個具體的值,并且任何一個依賴這個占位符的變量,都將使用這個值。
注意:
1、轉換靜態(tài)形狀的時候,1-D到1-D,2-D到2-D,不能跨階數(shù)改變形狀;
2、對于已經(jīng)固定或者設置靜態(tài)形狀的張量/變量,不能再次設置靜態(tài)形狀;
3、tf.reshape()動態(tài)創(chuàng)建新張量時,元素個數(shù)不能不匹配;
4、運行時候,動態(tài)獲取張量的形狀值,只能通過tf.shape(tensor)[]。
Operation
只要使用TensorFlow框架的API定義的函數(shù)都是Operation,Tensor也是Operation,指代的是數(shù)據(jù)。
Graph
圖由整個程序構造,可用系統(tǒng)默認的圖,也可自定義。一個Session只能運行一個圖。
Session
相當于中間件,對上解析并運行定義的圖結構,對下分配CPU或者GPU資源進行計算,掌握資源(變量、隊列、線程等)。如果不與圖綁定,那會話使用默認的圖。
Session可能返回錯誤:RuntimeError、TypeError、ValueError。
Feed機制
將某些特殊的操作指定為"feed"操作,標記的方法是使用 tf.placeholder() 為這些操作創(chuàng)建占位符,并且在Session.run方法中增加一個feed_dict參數(shù)。突然感覺滅霸還是個心細的紫叔叔,讓矮人族打造無限手套的時候特意留了六個位置,因為他知道,早晚要用到這六個位置,跟TensorFlow里的占位符簡直異曲同工。如果沒有正確提供feed參數(shù),placeholder() 操作將會產(chǎn)生錯誤。
tf.placeholder(tf.float32, [None, 3])# 行數(shù)不固定,列數(shù)固定
run(fetches, feed_dict = None, graph = None):訓練模型時實時提供數(shù)據(jù)進行訓練,用placeholder占位符和feed_dict結合使用
舉個栗子
import tensorflow as tf
import os
# 忽略不必要的警告信息
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
# 創(chuàng)建一張圖包含Operation和Tensor,兩個圖之間互不干擾
g = tf.Graph()
with g.as_default():
c = tf.constant(11.0)
print(g)
print(c.graph)
# 實現(xiàn)一個加法運算,定義兩個Tensor和一個Operation
a = tf.constant(5.0)
b = tf.constant(6.0)
sum = tf.add(a, b)
# 不是Operation不能運行,但是有重載機制,默認會給運算符重載成op類型(var + a可執(zhí)行)
# var = 2
# 默認的圖,相當于給程序分配內(nèi)存
graph = tf.get_default_graph()
print(graph)
# 一個會話只能運行一個圖,可在會話中指定圖運行
# 上下文管理器with默認會釋放資源
with tf.Session(graph=graph) as sess:
print(sum) # Tensor("Add:0", shape=(), dtype=float32),分別為op名字,張量形狀,張量數(shù)據(jù)類型
print(a.graph)
print(sum.graph)
print(sess.graph)
print(sess.run(sum)) # run()執(zhí)行圖
# 靜態(tài)形狀和動態(tài)形狀
# 對于靜態(tài)形狀而言,一旦張量形狀固定,不能再次進行修改
# 動態(tài)形狀可新增一個,進行修改,但是元素數(shù)量要相同
# 如果需要維度修改,必須用動態(tài)形狀修改
plt = tf.placeholder(tf.float32, [None, 2])
print(plt)
plt.set_shape([3, 2])
print(plt)
# plt.set_shape([4, 2]) # 不能修改
plt_reshape = tf.reshape(plt, [1, 6])
print(plt_reshape)
with tf.Session() as sess:
pass
# 變量op
# 1、變量op可持久化保存,普通張量op不能
# 2、當定義一個變量op時,一定要在會話中取運行初始化
# 3、name參數(shù)在tensorboard中使用顯示,防止沖突
a = tf.constant([1, 2, 3, 4, 5], name="a")
var = tf.Variable(tf.random_normal([1, 2], mean=0, stddev=1.0))
print(a, var)
# 必須做一步顯示的初始化op
init_op = tf.global_variables_initializer()
with tf.Session() as s:
s.run(init_op)
# 把程序的圖結構寫入事件,把指定的圖寫入事件中
filewriter = tf.summary.FileWriter("./summary", graph=s.graph)
print(s.run([a, var]))