當前位置:
首頁 > 知識 > Tensorflow_01_運算符與張量值

Tensorflow_01_運算符與張量值

本文為作者Kuo_Jun_Lin的TensorFlow技術分享系列第1篇,更多內容可訪問他在AI研習社的博客(http://www.gair.link/page/center/myPage/5104751),也歡迎在他的研習社博文留言互動。


Brief 概述

機器學習與人工智慧其實可以被歸類為一個有歷史的學科領域,在上世紀的六零年代就已經有第一批的科學家先祖們在這個領域投入精力,但是礙於當時的硬體科技發展限制,沒有辦法實現大規模的運算,甚至也沒有單位能夠提供規模龐大的同類型數據給到科學家們,因此這個領域一直沉寂著直到現今爆炸性的成長開了一片絢麗的故事。

不過這樣的發展歷程也意味著非常豐富的知識和方法累計在這門學科中,應對迅速到來的時代,我們需要的不是死磕,而是需要迅速掌控該門類的知識並有效率的參與其中,而 Tensorflow 模塊有效的把許多知識背後的代碼整合到了各種類與函數中,我們作為一個使用者,如果藉助了這個模塊的力量,需要的就只是適時的呼叫函數。

Tensorflow 模塊是由 Google 公司在 2015 年 11 月份公開的深度學習模塊,為了就是整合深度學習中那些常被用到,同時又具有一定深度遇難度的函數原理,因此作為一個使用者只需要了解其中的原理的使用場景和運算背後的大致邏輯即可,大致上分類有下面幾個環節提供我們理解的方向:

TensorBoard

Low Level APIs

High Level APIs

Estimators

Accelerators

Links:Tensorflow Official Website,Tensorflow GitHub,Tensorflow Models

Tensorflow 使用 C++ 和 CUDA 語言編寫而成,其支持語言種類有 Python, C++, Go, Java, JavaScript 等,根據編寫該模塊的語言特性,它可以在眾多系統上移植功能,從電腦到手機,再到大規模的 GPU 調用都可以辦到。

該模塊中實現計算的方法是經由搭建以操作符為樞紐的節點,從設置的參數出發,讓節點與參數之間彼此連成線後,根據操作符的指示開始讓參數之間做運算的過程,而全部的過程我們都可以在一個指向圖中一覽無疑,而節點又可以被視為是一種示例(instance),流竄在節點與線之間的數字則被稱為張量(tensor),Tensorflow 因而得其名。


Setup 安裝

Tensorflow 是一個整合了軟硬體的模塊包,提供一個良好的途徑讓我們能夠更為便捷的建構屬於自己的神經網路,並且有效的部署在自己的電腦中,它幫我們處理好了緩存部署與算力分配的問題,但也因為如此,安裝方法的排列組合增加了一個維度,通常我們安裝需要檢視下面幾點條件:

作業系統: windows, macOS, Ubuntu, or Raspbian

GPU 或者 CPU 版本

其他語言支援包

全部流程包含了比較多繁瑣的步驟,點擊此處前往官方提供安裝 Tensorflow 的介紹文檔。


Content 內容

根據 Tensorflow 官方技術文檔說明,我們需要了解的內容主題順序如下:

Operators 運算符

Tensor Values 張量值的含義

Graph and Board 圖表和畫板

Variables 變數

Training 訓練

使用這個模塊在創建數學模型的時候有兩個最原始的元素參與其中: 1. 節點(node); 2. 邊(edge)。 每個節點裡面會被賦予一個任務需要執行,參數作為一個參與者到了這個節並做完任務後,就會沿著箭頭所代表的邊被送到下一個節點完成另一個任務,直到最後需要做完的任務被輸出為止,如下圖描述:

但是需要注意的是,創建了節點這件事情本身,實際上並沒有執行的動作,創建僅僅是創建,如果需要執行代碼,還需要我們使用一個函數 .Session() 把整個模型描述成一個繪話後,才能執行我們想要執行的運算,上圖的簡易模型如下代碼。

每當節點在創建的時候,其實 Tensorflow 背後還幫我們在指向圖中同樣創建了一個流程圖節點共我們審視數學框架的完整性和邏輯合理性,這個流程圖即為 TensorBoard。我們一般不會在代碼中看到流程圖的定義的過程,原因是有一個預設的流程圖已經為我們自動添加了描述的節點和邊之間的關係,後面會更為詳盡的介紹該圖的功能和使用方法,其中包含了自定義多個流程圖。

在實際上運行代碼,指定節點輸出一個運算結果的時候,節點之間的因果關係(依賴關係)是我們需要非常注意的重點。如上圖,如果我們需要運行 e 節點,那麼前面所有的運算都將稱為運行 e 節點的時候必須提前做完的事情, Tensorflow 也會自動的運行它所需要的那些有因果關係的依賴節點,並只會運行那些節點。同理,如果運行的是 c 節點,那麼跟 c 無關的節點就不會被運行到,如下面代碼演示。

前面提到真正開始執行計算行為的時候,我們需要使用 .Session() 函數先創造一個繪話示例,然後用該示例執行節點內容,過程有了圖之後變得非常直觀,但每個繪話之間的獨立性只有下面的範例可以看出不同,從這個角度來看,流程圖就是一個主體,分發給了很多個經過 .Session() 創建的示例一個運算框架,至於發出去之後,每個示例裡面發生了什麼事情,都是彼此獨立的個體互不影響,如下面代碼演示。

p.s. feed_dict 方法會在下面內容深入提及。

import tensorflowastf

a=tf.constant(5, name="input_a")

b=tf.constant(3, name="input_b")

c=tf.multiply(a,b, name="input_c")

d =tf.add(a,b, name="add_d")

e=tf.add(c, d, name="add_e")

sess_1 =tf.Session()

sess_2 =tf.Session()

print(sess_1.run(e))

print(sess_2.run(c, feed_dict={a:15}))

23

45


1. Operators 操作符

操作符是節點的主角,挑明了數據們一旦來到了這個站點(節點)之後,要做的事情是什麼,是一種行為的描述。一般而言,指向圖中的參數值會隨者訓練的次數增多而不斷刷新,而只有含有狀態的運算操作(如 Variable)才有保存下值的機會。下面是操作符的大致種類:

標量運算: add, subtract, multiply, div, exp, log, greater, less, equal

向量運算: Concat, Slice, Split, Constant, Rank, Shape, Shuffle

矩陣運算: MatMul, MatrixInverse, MatrixDeterminant

含狀態的運算: Variable, Assign, AssignAdd

神經網路組件: SoftMax, Sigmoid, ReLU, Convolution2D, MaxPooling

儲存與恢復: Save, Restore

隊列與同步運算: Enqueue, Dequeue, MutexAcquire, MutexRelease

控制流: Merge, Switch, Enter, Leave, NextIteration

p.s. 點擊官方鏈接可以一覽所有操作符,且操作符不限於運算行為,還可以是其他很多的動作, 例如創建一個占著位置的「東西」等著一個時刻去 feed_dict。


2. Tensor Values 張量值

它是一個 Tensorflow 用來描述數值的一種主要手段,我們創建節點,並組織流程圖的目的就是為了能夠讓這些張量值在裡面流竄,Tensorflow 因而得名,上面的例子中我們使用的是 constant 常量,創建了兩個輸入節點,然後才對其運算。然而,多個節點表示需要更多的精力去管理他們,而張量思維就是一個為我們省去這類多個輸入節點麻煩的方法。

張量可以看作是一個矩陣的別名,常量換句話說就是一個只有一個元素的一維矩陣,因此我們可以使用多維度,且多個元素的矩陣作為一個總體的輸入,然後讓操作符根據裡面元素的值進行運算,得到同樣的結果,下面是對上面代碼的修改:

import tensorflowastf

ab=tf.constant([5,3], name="input_ab")

c=tf.reduce_prod(ab, name="prod_c")

d =tf.reduce_sum(ab, name="sum_d")

e=tf.add(c, d, name="add_e")

sess =tf.Session()

sess.run(e)

23

張量的維度對應到我們熟悉的數學專有名詞如下:

1D: array 向量

2D: matrix 矩陣

3D: 3 Dimensional Tensor 三維張量 (三維以上則用維度表示)

Data Types 數據類型

說到張量值裡面的數據類型,種類非常豐富,完整詳情可以參考官方網頁,主要對數字默認皆為 32 位元的類型,並且 Tensorflow 的數據類型完美且緊密的和 Numpy 模塊整合到了一起,緊密到了鍵入 tf.int32 == np.int32 回傳的值是 True!

雖然說 Tensorflow 與 numpy 非常兼容,在 Tensorflow 的 Operators 中可以放入 numpy 的整數,浮點數,字元串,布爾值,列表與元組等,卻需要注意如整數在 np 中只有 int32 類型,而到了 tf 中卻有 16, 32, 64 等種類,如果不提前聲明好的話,就不得不讓模塊去猜我們的心思,造成不必要的錯誤。

而有個函數 .string() 則是那個例外,我們可以非常順利地把 np.string() 帶入 tf 之中,但是卻不能在 np 模塊中找到任何一個能跟 tf.string() 完美匹配的方法,需要特別注意。


Definition of Tensor『s Shape 張量的形狀定義

定義一個張量的大小可以使用元組 (3, 4) 或是列表 [3, 4] 的形式操作,存在幾個元素就表示幾個維度,元素的值是多少,則表示該維度有幾個值,如果填入的值是 None 則表示該維度的值個數不限定幾個,這個設置一般放在 operator 裡面的參數部位。

code: shape=(3, 4, None) # One of the argument in an operator


feed_dict 方法

它不止是一個方法,同時還是一個觀念,讓我們可以更加明確的了解到節點創立的時候,並不包含了讓節點執行動作的過程,也因為 Tensorflow 這樣的特性,我們可以讓流程先創立好,最後等到要運算真正開始執行的時候,再放入數字即可,就好比先打造出一個遊樂園,等著人進來玩遊戲,詳情如下簡單代碼:

import tensorflowastf

m=tf.add(5,3)

n =tf.multiply(a,3)

sess =tf.Session()

sess.run(n, feed_dict={a:15})

45


3. Graph and Board 圖表和畫板

如上面 「內容」 章節提及的內容,每當一個節點被創建的時候,有一個默認的 TensorBoard 板上會同樣添加一個對應的節點,但是如果需要手動設置節點到我們喜歡的不同板上, Graph 對象就成了一個關鍵的源頭方法,它可以讓我們自由的創建圖例,下面是對應的操作代碼:

import tensorflowastf

# Thisaddnodeisputin the default TensorBoard graph

in_default_graph =tf.add(5,3)

# We create another graphtoload another node

g =tf.Graph()

with g.as_default():

a=tf.add(3,4)

# If we wanttohave nodes created in default graph, hereisthe methodtohelpus

default_graph =tf.get_default_graph()

大多數情況下,用一個默認的數據流圖表就可以了,如果是要定義多個相互之間彼此獨立的模型,則下面三種代碼的寫法適合參考:

import tensorflowastf

#1. createanewgraphandignore the default graph

g1 =tf.Graph()

g2 =tf.Graph()

with g1.as_default():

a=tf.add(3,4, name="add_a")

# define some nodes heretog1 graph

with g2.as_default():

b=tf.subtract(5,2, name="sub_b")

# define some nodes heretog2 graph

#2.getthe default graphandappoint the graphtoanobject

g11 =tf.get_default_graph()

g12 =tf.Graph()

with g11.as_default():

c=tf.add(3,4, name="add_c")

# define some nodes heretog11 graph

with g12.as_default():

d =tf.subtract(5,2, name="sub_d")

# define some nodes heretog21 graph

#3. the default graph can alsobeapplied along with the other graph

g21 =tf.Graph()

e=tf.add(3,4, name="add_e")

# define some nodes here in the default graph

with g21.as_default():

f=tf.subtract(5,2, name="sub_f")

# define some nodes heretog21 graph

sess =tf.Session()

writer =tf.summary.FileWriter("./my_graph")

writer.add_graph(g21)

#orwe canwritethe code in onelinebelow

# writer =tf.summary.FileWriter("./my_graph", graph=g11)

# by the way, sess.graph ==tf.get_default_graph()isTrue!!

sess.close()

writer.close()

等到我們已經確定添加好所有節點到圖表上之後,如果我們要把設置的結果可視化,開啟 TensorBoard 的方法如上面代碼最後一行,兩個參數位置分別如下解釋:

路徑字元串: 根據我們命名的路徑, tf 會自動創建一個文件夾,裡面放著一個圖表的描述檔案,文件夾的路徑則放置在我們代碼啟動的同一個路徑下。

指明一個要被畫上去的物件,可以是繪話裡面的一個方法,讓我們指定要被顯示的繪話是什麼,也可以後面使用 .add_graph() 方法添加要畫上的物件。

如果一個項目比較大,圖中的節點比較多,我們可能會需要使用一個大框框來涵蓋所有的節點,並在圖裡只簡單顯示輸入端和輸出端,使得該大框框成為一個類似黑箱的存在,這時候我們需要使用到下面函數:

tf.name_scope("give_a_name_here")

搭配 with 使用的話,就會變成: with tf.name_scope(): ...indention # the belonged nodes is constructed below.

每個節點參數部分都有一個 name 標籤,是用來為該節點取名字,讓我們能夠更為明了的在 TensorBoard 上面看出哪一個節點對應到的作用是什麼,同時如果這些節點是一個佔位節點,如 Variable, Constant, placeholder 等,我們還可以直接呼叫該節點的名字得到該佔位節點裡面值的復用。

等代碼運行完畢後,找到文件夾路徑,然後從命令提示資源開啟該路徑並鍵入:

tensorboard --logdir="./the_name"

我們會得到一個本地網址,複製該網址到瀏覽器裡面打開即可。

最後,等到所有事情做完了,如果有一個 .close() 的動作,可以避免一些不必要的錯誤,或是我們使用 with 的方法,也可以順利關閉代碼的行為。


4. Variables 變數

繼上面張量小節提到的內容,我們除了 .Constant() 可以用之外,還有兩個也非常適合拿來描述變數,甚至卡位用的函數:

.placeholder()

.Variable()

有別於直接鍵入數字,使用這些函數的好處是我們可以非常精確的聲明該數值的屬性和各種細節,進而免去所有因為數據類型不同造成的錯誤和麻煩。完整的聲明也有助於我們在構建數學模型的時候提升思路的清晰度。


.placeholder() method

前面示範代碼中我們都使用了單一不變的數值作為輸入,但是這樣造成建構好一個模型後沒辦法重複使用,因為數值是一樣的。這個問題被 placeholder 給解開了,它白話文的意思是: 這邊有一個變數,但我還沒決定好它是什麼,不過我可以先對其輪廓給一個定義,例如數據類型,張量大小,該變數在圖表中的名稱等等。

這樣模糊的狀態會持續到即將運行計算環節之前,我們會使用 feed_dict 參數以字典的模式導入數值到該位置,使其最終順利運行,如下面代碼:

importnumpyasnp

importtensorflowastf

""" dtype is a necessity that we should announce in parameter.

shape is optional argument with a default None value on the other hand."""

a = tf.placeholder(dtype=tf.int32, shape=[2], name="my_input")

b = tf.reduce_prod(a, name="prod_b")

c = tf.reduce_sum(a, name="sum_c")

d = tf.add(b, c, name="add_d")

sess = tf.Session()

the_dict =

sess.run(d, feed_dict=the_dict)

23


.Variable() method

它可以用來承載任意的數值,數字,向量,矩陣,多維張量等等都囊括其中,而為了讓它更方便的被使用, tf 有許多創建變數的方法,常見使用的方法如下面列舉:

tf.zeros(shape=(None, None, ...), dtype=np.int32)

tf.ones(shape=(None, None, ...), dtype=np.int32)

tf.random_normal(shape=(None, None, ...), mean=0.0, stddev=2.0)

tf.truncated_normal(shape=(None, None, ...), mean=0.0, stddev=1.0)

tf.random_uniform(shape=(None, None, ...), minval=0, maxval=10)

Official website for more details

因為 .Variable() 方法的好用和普遍性,我們在創建好節點後並在執行運算前,需要對它們做初始化,可以是個別的也可以是全部一起的,代碼如下:

individual: tf.initialize_variables([var], name="init_var")

overall: tf.global_variables_initializer()

如果代碼執行過程中希望「取代」該變數原本的值,那麼有另一個方法可以使用:

.assign()

下面是上面列舉方法的示範代碼:

import numpyasnp

import tensorflowastf

a=tf.Variable(tf.ones(shape=[1], dtype=np.float32))

b=tf.Variable(tf.random_normal(shape=[1], dtype=np.float32,

mean=0.0, stddev=2.0))

c=a.assign(a*2)

d =tf.add(b,c, name="add_d")

init =tf.global_variables_initializer()

sess =tf.Session()

sess.run(init)

fori inrange(3):

print(sess.run(d))

sess.run(tf.assign_add(a, np.array([3], dtype=np.float32)))

[2.0879781]

[4.0879784]

[8.087978]

array([11.], dtype=float32)

如果對於某些參數我們不樂見上面示例般一輪一輪的迭代數值,可以在 .Variable() 中添加如下代碼:

tf.Variable(0, trainable=False)

如此一來就可以鎖定變數值。


5. Training 訓練

根據上面我們描述的內容和觀念,接著我們可以開始嘗試編造一個模型,並且用神經網路原理訓練該模型的結果逼近到我們所預期的答案上,以下是代碼的邏輯步驟:

引入我們需要使用的模塊包,並原地創建需要的數據和方程式

使用神經網路的線性模型 y = wx + b,並用 tf 創建變數的方法創建需要的節點

計算隨機給出的數字和我們的方程式相差大小

使用 tf 裡面的梯度下降其中一個方法,並設置學習效率

開始使用該方法尋找方程式的最小值

初始化完了所有的 tf 的變數後,開啟 100 次循環,表示訓練次數

列印出結果結束

詳細代碼如下展示:

import numpyasnp

import tensorflowastf

x_data = np.random.rand(100).astype(np.float32)

y_data = x_data *0.1+0.3

weight =tf.Variable(tf.random_uniform(shape=[1], minval=-1.0, maxval=1.0))

bias =tf.Variable(tf.zeros(shape=[1]))

y= weight * x_data + bias

loss =tf.reduce_mean(tf.square(y- y_data))

optimizer =tf.train.GradientDescentOptimizer(0.5)

training = optimizer.minimize(loss)

sess =tf.Session()

init =tf.global_variables_initializer()

sess.run(init)

forstep inrange(101):

sess.run(training)

ifstep %10==:

print("Round {}, weight: {}, bias: {}"

.format(step, sess.run(weight[]), sess.run(bias[])))

Round, weight:-0.02453458309173584, bias:0.49208229780197144

Round10, weight:0.010933060199022293, bias:0.34626200795173645

Round20, weight:0.055091626942157745, bias:0.32332566380500793

Round30, weight:0.07735679298639297, bias:0.3117610216140747

Round40, weight:0.08858311176300049, bias:0.3059300184249878

Round50, weight:0.09424349665641785, bias:0.3029899597167969

Round60, weight:0.09709753841161728, bias:0.3015075623989105

Round70, weight:0.09853656589984894, bias:0.3007601201534271

Round80, weight:0.09926214069128036, bias:0.3003832697868347

Round90, weight:0.09962794929742813, bias:0.30019325017929077

Round100, weight:0.09981241822242737, bias:0.30009743571281433

以及我的AI研習社博客:

http://www.gair.link/page/center/myPage/5104751


喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 AI研習社 的精彩文章:

猶他州空氣質量分析-從EPA的空氣質量服務站API中抓取數據
想要訓練專屬人臉識別模型?先掌握構建人臉數據集的三種絕招

TAG:AI研習社 |