在上一篇中,我簡單介紹了一下Tensorflow
以及在本機及阿里雲的PAI
平臺上跑通第一個示例的步驟。在本篇中我將稍微講解一下幾個基本概念以及Tensorflow
的基礎語法。node
本文代碼都是基於API版本r1.4
。本文中本地開發環境爲Pycharm
,在文中再也不贅述。python
和不少開發語言設計同樣,Tensorflow
提供了多個級別的客戶端API,其中最底層叫Tensorflow Core
,使用這一層API能夠徹底控制Tensorflow
,可是使用難度上也相對較大。在Tensorflow Core
之上建立的更高級別的API,對開發者更友好,更易於使用、學習起來也更簡單。web
Tensorflow
中該數據的核心單位是張量(Tensor)
,張量
就是將一組基礎數值,組織成形態(Shape)
爲一個任意維度的數組,張量
的階(Rank)
就是維度的數量。概念仍是挺拗口的,舉個例子就很是明瞭了:算法
[1., 2., 3.] # Rank=1, Shape=[3] [[1., 2., 3.], [4., 5., 6.]] # Rank=2; Shape=[2, 3]: 表明第一層數組裏包含2個子數組,每一個子數組裏包含3個值 [[[1., 2., 3.]], [[7., 8., 9.]]] # Rank=3; Shape=[2, 1, 3] : 表明第一層數組裏包含2個數組,每一個子數組裏又包含1個子數組,子數組裏包含3個元素
Tensorflow
其實就是針對張量
的計算圖,計算圖中的每一個節點(Node)
之間是有向鏈接的,看起來像張量
的流動圖(即從輸入開始,流過一系列的節點,最終輸出結果),Tensorflow
也由此得名。官方原話是:編程
What is a Data Flow Graph? Data flow graphs describe mathematical computation with a directed graph of nodes & edges. Nodes typically implement mathematical operations, but can also represent endpoints to feed in data, push out results, or read/write persistent variables. Edges describe the input/output relationships between nodes. These data edges carry dynamically-sized multidimensional data arrays, or tensors. The flow of tensors through the graph is where TensorFlow gets its name. Nodes are assigned to computational devices and execute asynchronously and in parallel once all the tensors on their incoming edges becomes available.
Tensorflow Core
編程,有點像畫設計稿(構建流圖)
->按圖施工(執行流圖)
這樣的過程,執行流圖必須使用tf.run()
方法。計算圖中的節點
將接受0-N個張量
做爲輸入值併產生一個輸出值。在個人理解中,節點
能夠分爲數值型
和運算型
兩種。api
常量是一種沒有輸入,只有一個輸出值的節點,常量在定義的時候就將其值存儲在Tensorflow
內部了,一旦定義則沒法修改其值。數組
示例代碼:瀏覽器
# 定義常量c1,並將其數值類型定義爲tf.float32,默認值爲1.0 c1 = tf.constant(1., dtype=tf.float32) # 定義常量c2,並將其數值類型定義爲tf.float32,默認值爲2.0 c2 = tf.constant(2., dtype=tf.float32) # 執行流圖: c1 + c2 with tf.Session() as sess: print(sess.run(tf.add(c1, c2)))
佔位符也是數值型節點的一種定義方式,佔位符是一種Promise
,就是承諾在執行tf.run()
的時候必定會在參數feed_dict
中提供其值。相比常量,佔位符更像是一種參數,使用起來更靈活。app
用佔位符改寫上面的示例代碼以下:機器學習
# 定義佔位值p1,並將其數值類型定義爲tf.float32 p1 = tf.placeholder(tf.float32) # 定義佔位值p2,並將其數值類型定義爲tf.float32 p2 = tf.placeholder(tf.float32) # 執行流圖: p1 + p2 with tf.Session() as sess: # 既然承諾過,所以在run的時候必須提供p1,p2的值,不然代碼將報錯 print(sess.run(tf.add(p1, p2), {p1: 1., p2: 2.}))
比起佔位符,變量就更靈活了,能夠隨時賦值,這樣就能夠將某些節點的輸出值賦值到指定的變量中,以便後續節點使用。這種模式在機器學習中是很是必要的,由於機器學習就是一個調參的過程,在運行的時候就但願能隨時改變某些值以達到預期。
變量在使用的時候須要注意的是,在執行tf.run()
方法以前,必須將變量進行初始化,初始化語句是:
init = tf.global_variables_initializer() sess.run(init)
依舊是上述代碼用變量改寫:
# 定義變量v1,並將其數值類型定義爲tf.float32,默認值爲1.0 v1 = tf.Variable(1., tf.float32) # 定義變量v2,並將其數值類型定義爲tf.float32,默認值爲1.0 v2 = tf.Variable(2., tf.float32) with tf.Session() as sess: init = tf.global_variables_initializer() sess.run(init) print(sess.run(tf.add(v1, v2)))
其實上面的代碼中已經用到了加法tf.add()
方法,減法是tf.subtract()
,乘法是tf.multiply()
,除法是tf.divide()
等等。全部的方法能夠在官方API文檔中找到:https://www.tensorflow.org/api_docs/python/tf,這裏就不贅述了。
這裏再簡單介紹下Tensorflow
自帶的很是強大的可視化工具TensorBoard
,TensorBoard
徹底能夠單獨寫一篇博文,本文先拋磚引玉,主要是爲了直觀的展現上述代碼產生的圖。
最簡單的TensorBoard
的使用方法以下:
# 保存計算圖 with tf.summary.FileWriter(logdir='logs', graph=tf.get_default_graph()) as writer: writer.flush()
執行上述代碼以後,Tensorflow
會將生成圖所需的數據序列化到本地文件中,我指定了生成到當前同級目錄logs
中,生成成功以後,能夠在PyCharm
的控制檯(使用快捷鍵ALT+F12可調出)中輸入:
tensorboard --logdir=logs
等待幾秒鐘以後,控制檯輸出相似於以下內容則表示TensorBoard
已經啓動成功:
TensorBoard 0.4.0rc3 at http://localhost:6006 (Press CTRL+C to quit)
在本地瀏覽器(推薦使用Chrome)地址欄中,輸入http://localhost:6006
打開TensorBoard
,大體效果以下:
真正的機器學習過程當中,咱們固然是不知道變量的,咱們真正的目的就是去習得
這些變量,以達到模型可以儘量準確預測樣本的指望,也就是所謂的損失(loss)
最小化。Tensorflow
提供了優化器(optimizers)
來作這個工做。最簡單的優化器
算法叫梯度降低
,這是在線性模型中最經常使用的一種優化算法。優化器
底層會調用Tensorflow Core
中的tf.gradients
方法來實現梯度降低
。
如上圖所示,假設如今已知4個藍色的點(1,0),(2,-1),(3,-2),(4,-3),咱們須要推導出表明紅色直線的係數W
和b
(公式爲y = Wx + b
),固然這個例子很簡單,用肉眼看一下就知道W=-1
,b=1
,用Tensorflow
實現的完整代碼以下:
import tensorflow as tf # y = Wx + b, 初始化的時候隨便定義一個初始值 W = tf.Variable([.3], dtype=tf.float32) b = tf.Variable([-.3], dtype=tf.float32) # 輸入值 x, 定義爲佔位符, 便於在學習過程當中換成不一樣的值 x = tf.placeholder(tf.float32) # 定義線性模型 linear_model = W*x + b # 輸出值 y, 定義爲佔位符, 便於在學習過程當中換成不一樣的值 y = tf.placeholder(tf.float32) # 損失loss,線性模型中以歐式距離來衡量損失值 loss = tf.reduce_sum(tf.square(linear_model - y)) # 定義優化器optimizer optimizer = tf.train.GradientDescentOptimizer(0.01) train = optimizer.minimize(loss) # 4個藍色點的訓練數據,分解成x和y的數組爲 x_train = [1, 2, 3, 4] y_train = [0, -1, -2, -3] # 初始化Session init = tf.global_variables_initializer() sess = tf.Session() sess.run(init) # 循環1000次,訓練模型 for i in range(1000): sess.run(train, {x: x_train, y: y_train}) # 評估準確率 curr_W, curr_b, curr_loss = sess.run([W, b, loss], {x: x_train, y: y_train}) print("W: %s b: %s loss: %s"%(curr_W, curr_b, curr_loss)) # 保存計算圖 with tf.summary.FileWriter(logdir='logs_linear_regression', graph=tf.get_default_graph()) as writer: writer.flush()
我本機的輸出結果爲:
W: [-0.9999969] b: [ 0.99999082] loss: 5.69997e-11
W
的值無限接近-1,b
的值無限接近1,而loss
無限接近0,這個就是咱們設計的函數y=-x+1
。
在TensorBoard
中查看結果如圖所示:
這個圖就看起來就比較像這麼回事了。
本系列教程我儘可能在阿里雲的PAI
平臺上也運行一次,雖然目前公測階段仍是有不少問題,可是也是讓不少人對機器學習變得觸手可及的一種很是好的方案。
上一篇中,我用web版的OSS管理工具上傳了源代碼文件,本用例將使用OSS Browser
客戶端上傳和管理文件,下載地址在阿里雲後臺以下位置:
下載客戶端的同時,能夠開通阿里雲的Access Key
(用來登陸OSS Browser
),開通位置以下:
開通以後,在管理界面看到以下內容:
打開並解壓縮剛纔下載的OSS Browser
,雙擊打開oss-browser.exe
文件,使用剛纔開通的Access Key
登陸:
我依舊在上一篇相同的目錄oss://danielfu-oss-tf-test/tensorflowtest/
下,建立了一個放summary
文件夾,並上傳了代碼文件tensorflow-demo2.py
:
在阿里雲上使用Tensorflow
須要將上述的demo示例代碼進行少許的改造,格式基本也都是固定的,改造完以後的完整代碼以下:
# 指定文件的編碼格式,這個不加在PAI裏運行會報錯 #!/usr/bin/python # -*-coding:utf-8 -*- from __future__ import absolute_import from __future__ import division from __future__ import print_function import sys import argparse import tensorflow as tf # 定義FLAGS用來傳遞全局參數 FLAGS = None def main(_): # y = Wx + b, 初始化的時候隨便定義一個初始值 W = tf.Variable([.3], dtype=tf.float32) b = tf.Variable([-.3], dtype=tf.float32) # 輸入值 x, 定義爲佔位符, 便於在學習過程當中換成不一樣的值 x = tf.placeholder(tf.float32) # 定義線性模型 linear_model = tf.multiply(W, x) + b # 輸出值 y, 定義爲佔位符, 便於在學習過程當中換成不一樣的值 y = tf.placeholder(tf.float32) # 損失loss,線性模型中以歐式距離來衡量損失值 loss = tf.reduce_sum(tf.square(linear_model - y)) # 定義優化器optimizer optimizer = tf.train.GradientDescentOptimizer(0.01) train = optimizer.minimize(loss) # 4個藍色點的訓練數據,分解成x和y的數組爲 x_train = [1, 2, 3, 4] y_train = [0, -1, -2, -3] # 初始化Session init = tf.global_variables_initializer() with tf.Session() as sess: sess.run(init) # 循環1000次,訓練模型 for i in range(1000): sess.run(train, {x: x_train, y: y_train}) # 評估準確率 curr_W, curr_b, curr_loss = sess.run([W, b, loss], {x: x_train, y: y_train}) print("W: %s b: %s loss: %s" % (curr_W, curr_b, curr_loss)) # 保存計算圖 with tf.summary.FileWriter(FLAGS.summaryDir + 'train', sess.graph) as writer: writer.flush() # 在運行main程序的時候,將參數傳入執行代碼中 # 本例中就指定了summaryDir參數 if __name__ == '__main__': parser = argparse.ArgumentParser() parser.add_argument('--summaryDir', type=str, default='', help='Summaries log directory') FLAGS, unparsed = parser.parse_known_args() tf.app.run(main=main)
在PAI
中,下圖中1
的位置指定爲tensorflow-demo2.py
文件,2
的位置指定爲summary
目錄,而後點擊3
處的按鈕:
多是PAI的BUG,該示例在執行的時候,輸出結果永遠是報錯,可是在OSS中,summary
文件也已經成功生成,並且若是點擊查看Tensorblaord
按鈕,實際上是能夠啓動TensorBoard
的:
如上圖所示,能夠成功運行PAI
端的TensorBoard
(URL是阿里雲的,不是本機localhost的)。並且生成的圖和本地運行生成的圖也是如出一轍的(廢話)。
官方文檔:https://www.tensorflow.org/get_started/get_started