機器學習筆記4-Tensorflow線性模型示例及TensorBoard的使用

前言

在上一篇中,我簡單介紹了一下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


數值型

Constant

常量是一種沒有輸入,只有一個輸出值的節點,常量在定義的時候就將其值存儲在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)))


Placeholder

佔位符也是數值型節點的一種定義方式,佔位符是一種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.}))


Variable

比起佔位符,變量就更靈活了,能夠隨時賦值,這樣就能夠將某些節點的輸出值賦值到指定的變量中,以便後續節點使用。這種模式在機器學習中是很是必要的,由於機器學習就是一個調參的過程,在運行的時候就但願能隨時改變某些值以達到預期。

變量在使用的時候須要注意的是,在執行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,這裏就不贅述了。


TensorBoard

這裏再簡單介紹下Tensorflow自帶的很是強大的可視化工具TensorBoardTensorBoard徹底能夠單獨寫一篇博文,本文先拋磚引玉,主要是爲了直觀的展現上述代碼產生的圖。

最簡單的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),咱們須要推導出表明紅色直線的係數Wb(公式爲y = Wx + b),固然這個例子很簡單,用肉眼看一下就知道W=-1b=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上運行

本系列教程我儘可能在阿里雲的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



本文在個人博客園個人我的博客上同步發佈,做者保留版權,轉載請註明來源。

相關文章
相關標籤/搜索