機器學習筆記5-Tensorflow高級API之tf.estimator

前言

本文接着上一篇繼續來聊Tensorflow的接口,上一篇中用較低層的接口實現了線性模型,本篇中將用更高級的API——tf.estimator來改寫線性模型。python

還記得以前的文章《機器學習筆記2 - sklearn之iris數據集》嗎?本文也將使用tf.estimator改造該示例。算法

本文代碼都是基於API版本r1.4。本文中本地開發環境爲Pycharm,在文中再也不贅述。數組


tf.estimator

內置模型

比起用底層API「較硬」的編碼方式,tf.estimator的在使用時更像是對模型描述(或定義)的過程。Tensorflow訓練評估數據處理等這些過程所有封裝起來,讓開發人員更專一於解決實際問題的建模過程,而不是糾結於代碼實現過程。若是用tf.estimator改造上一篇中的線性模型的話,完整代碼以下:機器學習

本例中使用的庫numpy是一個開源工具,是一個功能很是強大且執行效率很高的庫,主要用做數值處理及矩陣操做等。工具

import numpy as np
import tensorflow as tf

# 定義特性列,線性模型中特性是列是x,shape=[1],所以定義以下:
feature_columns = [tf.feature_column.numeric_column("x", shape=[1])]

# 使用tf.estimator內置的LinearRegressor來完成線性迴歸算法
# tf.estimator提供了不少常規的算法模型以便用戶調用,不須要用戶本身重複造輪子
# 到底爲止,短短兩行代碼咱們的建模工做就已經完成了
estimator = tf.estimator.LinearRegressor(feature_columns=feature_columns)

# 有了模型以後,咱們要使用模型完成訓練->評估->預測這幾個步驟
# 訓練數據依舊是(1.,0.),(2.,-1.),(3.,-2.),(4.,-3.)這幾個點,拆成x和y兩個維度的數組
x_train = np.array([1., 2., 3., 4.])
y_train = np.array([0., -1., -2., -3.])

# 評估數據爲(2.,-1.01),(5.,-4.1),(8.,-7.),(1.,0.)這四個點,一樣拆分紅x和y兩個維度的數組
x_eval = np.array([2., 5., 8., 1.])
y_eval = np.array([-1.01, -4.1, -7., 0.])

# 用tf.estimator.numpy_input_fn方法生成隨機打亂的數據組,每組包含4個數據
input_fn = tf.estimator.inputs.numpy_input_fn({"x": x_train}, y_train, batch_size=4, num_epochs=None, shuffle=True)
# 循環1000次訓練模型
estimator.train(input_fn=input_fn, steps=1000)

# 生成訓練數據,分紅1000組,每組4個數據
train_input_fn = tf.estimator.inputs.numpy_input_fn({"x": x_train}, y_train, batch_size=4, num_epochs=1000, shuffle=False)
# 生成評估數據,分紅1000組,每組4個數據
eval_input_fn = tf.estimator.inputs.numpy_input_fn({"x": x_eval}, y_eval, batch_size=4, num_epochs=1000, shuffle=False)

# 訓練數據在模型上的預測準確率
train_metrics = estimator.evaluate(input_fn=train_input_fn)
# 評估數據在模型上的預測準確率
eval_metrics = estimator.evaluate(input_fn=eval_input_fn)

print("train metrics: %r"% train_metrics)
print("eval metrics: %r"% eval_metrics)

輸出結果以下:學習

train metrics: {'average_loss': 4.4709815e-08, 'loss': 1.7883926e-07, 'global_step': 1000}
eval metrics: {'average_loss': 0.0025470245, 'loss': 0.010188098, 'global_step': 1000}


自定義模型

雖然tf.estimator內置了大量的經常使用模型,但也並不表明咱們必須使用內置模型。若有須要,咱們能夠用底層API實現自定義模型,同時,繼續使用tf.estimator提供的高級特性。如上例中,咱們須要定義本身的線性迴歸模型,僅須要按以下步驟操做:測試

替換estimator

# 下面這行替換了原先的estimator = tf.estimator.LinearRegressor(feature_columns=feature_columns)
estimator = tf.estimator.Estimator(model_fn=model_fn)

定義並實現model_fn方法

...
def model_fn(features, labels, mode):
    # 用底層API構建線性模型
    W = tf.get_variable("W", [1], dtype=tf.float64)
    b = tf.get_variable("b", [1], dtype=tf.float64)
    y = W * features['x'] + b

    loss = tf.reduce_sum(tf.square(y - labels))

    # 獲取訓練全局參數step
    global_step = tf.train.get_global_step()
    # 梯度降低算法,學習率是0.01
    optimizer = tf.train.GradientDescentOptimizer(0.01)
    # 將優化器和全局step的累加方法打包成一個方法組,至關於把若干個方法打包成事務執行的模式
    train = tf.group(optimizer.minimize(loss), tf.assign_add(global_step, 1))

    # 將全部內容封裝成符合tf.estimator.Estimator規範的對象
    return tf.estimator.EstimatorSpec(
        mode=mode,
        predictions=y,
        loss=loss,
        train_op=train)
...


生成並啓動TensorBoard

tf.estimator中,生成TensorBoard的方法也被集成在了底層,咱們要作的,僅僅是傳入參數model_dir而已:優化

在LinearRegressor例中代碼以下:google

...
estimator = tf.estimator.LinearRegressor(feature_columns=feature_columns, model_dir='d1')
...
...
estimator = tf.estimator.Estimator(model_fn=model_fn, model_dir='d2')
...

TensorBoard的啓動和上一篇文章中同樣,在Pycharm的控制檯中執行:阿里雲

# 以LinearRegressor的代碼爲例
tensorboard --logdir=d1

啓動TensorBoard大體效果以下:


IRIS數據集

如今咱們來改造以前用sklearn實現的IRIS數據集。以前用了決策樹鄰近算法兩種算法來實現,此次用的是Tensorflow提供的深度學習模型DNNClassifier,完整代碼以下(代碼是官網提供的Demo代碼,僅僅將DNNClassifier中參數model_dir改成了當前目錄下iris_model目錄):

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import os
from six.moves.urllib.request import urlopen

import numpy as np
import tensorflow as tf

# 數據集
IRIS_TRAINING = "iris_training.csv"
IRIS_TRAINING_URL = "http://download.tensorflow.org/data/iris_training.csv"

IRIS_TEST = "iris_test.csv"
IRIS_TEST_URL = "http://download.tensorflow.org/data/iris_test.csv"


def main():
    # 先將數據集保存到本地
    if not os.path.exists(IRIS_TRAINING):
        raw = urlopen(IRIS_TRAINING_URL).read()
        with open(IRIS_TRAINING, "wb") as f:
            f.write(raw)

    if not os.path.exists(IRIS_TEST):
        raw = urlopen(IRIS_TEST_URL).read()
        with open(IRIS_TEST, "wb") as f:
            f.write(raw)

    # 讀取數據集
    training_set = tf.contrib.learn.datasets.base.load_csv_with_header(
        filename=IRIS_TRAINING,
        target_dtype=np.int,
        features_dtype=np.float32)
    test_set = tf.contrib.learn.datasets.base.load_csv_with_header(
        filename=IRIS_TEST,
        target_dtype=np.int,
        features_dtype=np.float32)

    feature_columns = [tf.feature_column.numeric_column("x", shape=[4])]

    # 建立一個三層的DNN深度學習分類器,三層分別有十、20、10個神經元
    classifier = tf.estimator.DNNClassifier(feature_columns=feature_columns,
                                            hidden_units=[10, 20, 10],
                                            n_classes=3,
                                            model_dir="iris_model")

    # 定義訓練用的數據集輸入
    train_input_fn = tf.estimator.inputs.numpy_input_fn(
        x={"x": np.array(training_set.data)},
        y=np.array(training_set.target),
        num_epochs=None,
        shuffle=True)

    # 訓練模型
    classifier.train(input_fn=train_input_fn, steps=2000)

    # 定義測試用的數據集輸入
    test_input_fn = tf.estimator.inputs.numpy_input_fn(
        x={"x": np.array(test_set.data)},
        y=np.array(test_set.target),
        num_epochs=1,
        shuffle=False)

    # 評估準確率
    accuracy_score = classifier.evaluate(input_fn=test_input_fn)["accuracy"]

    print("\nTest Accuracy: {0:f}\n".format(accuracy_score))

    # 預測兩個新樣本
    new_samples = np.array(
        [[6.4, 3.2, 4.5, 1.5],
         [5.8, 3.1, 5.0, 1.7]], dtype=np.float32)
    predict_input_fn = tf.estimator.inputs.numpy_input_fn(
        x={"x": new_samples},
        num_epochs=1,
        shuffle=False)

    predictions = list(classifier.predict(input_fn=predict_input_fn))

    predicted_classes = [p["classes"] for p in predictions]

    print(
        "New Samples, Class Predictions:    {}\n"
            .format(predicted_classes))


if __name__ == "__main__":
    main()

運行結果:

Test Accuracy: 0.966667

New Samples, Class Predictions:    [array([b'1'], dtype=object), array([b'2'], dtype=object)]


Process finished with exit code 0

能夠看到,用tf.estimator提供的DNNClassifier,僅須要以下代碼便可實現一個三層的DNN,並將模型保存在本地的iris_model文件夾下:

classifier = tf.estimator.DNNClassifier(feature_columns=feature_columns,
                                            hidden_units=[10, 20, 10],
                                            n_classes=3,
                                            model_dir="iris_model")


啓動TensorBoard,看到的效果以下:


Run on ML Engine of Google Cloud Platform

前面幾篇文章中,我在本地運行代碼的以後,同時在阿里雲PAI上執行了一次代碼。原本我也是想在PAI上再進行本文中的示例代碼的,不過我花了一天多的時間,最後仍是失敗了,主要緣由以下:

  • PAI目前只支持到Tensorflow 1.2,而官方目前已經出到Tensorflow 1.4(立刻要出1.5了),而Tensorflow 1.2是不支持tf.estimator.DNNClassifier的(代碼中須要用到)

  • PAI雖然是可視化拖拽,可是代碼仍是須要按照PAI的要求進行少許改造,不便於本地代碼直接放到雲端執行

  • PAI的相關文檔太少,遇到問題很難解決,就算提交工單技術支持也比較敷衍,這讓我這樣的初學者感到很是大的挫折感

說來也好笑,個人代碼不管如何調整在PAI中運行都會報錯,在PAI官方的技術QQ羣裏尋求幫助,半天沒人搭理,而後有一個羣友說PAI確實很差用,建議我用Google Cloud Platform。備受挫折的我就註冊了一個Google Cloud Platform,果真,即使是全英文的文檔,也讓我在不到2小時的時間裏,從註冊帳號到執行代碼成功。這真不是我崇洋媚外或者故意黑阿里,我僅僅敘述了我本身的親身經歷而已。相比PAIGoogle Cloud PlatformML Engine就是一個虛擬雲主機(Linux),能夠直接用Google的Web版遠程控制檯進行操做,就跟操做一臺真實的Linux同樣的體驗。所以本地代碼也能夠直接拷貝過去就能執行,不須要任何修改。運行速度上,我以爲比PAI快不少(沒有數據,只是感受)。

使用Google Cloud PlatformML Engine,須要一些前提條件:

  • 收費,須要綁定信用卡(VISA或MASTER),不過註冊帳號是送300美金體驗1年(也就是一年內不超過300美金的消費是免費的),官方承諾,免費體驗額度用完,若是要產生後續扣信用卡費用的行爲,須要用戶確認以後纔會繼續扣款

  • 較好的英文閱讀能力(能基本看懂英文技術、幫助文檔)

  • FQ(你懂的)

  • 會操做Linux系統

如下就是我在Google Cloud PlatformML Engine的Web控制檯中操做的動圖(註冊過程略):

注意:

  • 我事先作過了實驗,因此代碼已經放在文件~/cloudml-samples-master/mymltest/tensorflowdemo3/code.py中,動圖中僅僅是複製了一份代碼到新的執行目錄下。

  • Google Cloud Platform的幫助文檔我放在了最後的參考文檔中。


參考文檔

官方文檔:

https://www.tensorflow.org/get_started/get_started

https://www.tensorflow.org/get_started/estimator

ML Engine幫助文檔:

https://cloud.google.com/ml-engine/docs/getting-started-training-prediction



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

相關文章
相關標籤/搜索