TensorFlow学习笔记12----Creating Estimators in tf.contrib.learn

原文教程:tensorflow官方教程

记录关键内容与学习感受。未完待续。。


Creating Estimators in tf.contrib.learn

——tf.contrib.learn框架,通过其高级别的EstimatorAPI,使得构建和训练机器学习模型变得容易。Estimator提供了类,你可以快速的实例化并安装普通的模型类别,如回归器和分类器:

——但是如果tf.contrib.learn预先定义的模型类型中没有可以满足你的需求的怎么办?或许你需要更多对于模型配置的精细控制,例如有能力自定义最优化使用的损失函数,或者是对每一个神经网络层明确不同的激励函数。或许你需要实现一个排名或者推荐系统,这样无论是分类器和回归器都产生预测都不合适。

——这个教程覆盖了如何使用tf.contrib.learn提供的构建模块,来创建你自己的Estimator,这可以基于鲍鱼的身体尺寸,预测他们的年龄。你可以从如下几个方面学习:

  • 实例化一个Estimator。

  • 构建一个自定义模型函数。

  • 使用tf.contrib.layers配置神经网络。

  • 从tf.contrib.losses中选择一个合适的损失函数。

  • 为你的模型定义一个训练操作。

  • 生成并返回预测。

1、Prerequisites

——这个教程假设你已经知道了tf.contrib.learn API的基础知识,例如特征列和fit()操作。如果你之前没有使用过tf.contrib.learn,或者需要补习,你应该首先回顾一下一下教程:

2、An Abalone Age Predictor

——通过贝壳上的圈数,预测鲍鱼(海螺)的年龄是可能的。然而,因为这个任务要求切割、染色,并且在显微镜下观察贝壳,寻找其他可以预测年龄的测量值是比较合适的。

——Abalone Data Set包含鲍鱼的以下特征数据

FeatureDescription
LengthLength of abalone (in longest direction; in mm)
鲍鱼的长度(在最长的方向上,单位毫米)
DiameterDiameter of abalone (measurement perpendicular to length; in mm)
鲍鱼的直径(测量长度的垂线,单位毫米)
HeightHeight of abalone (with its meat inside shell; in mm)
鲍鱼的高度(壳里带肉测量,单位毫米)
Whole WeightWeight of entire abalone (in grams)
整个鲍鱼的重量(单位克)
Shucked WeightWeight of abalone meat only (in grams)
只有鲍鱼肉的重量(单位克)
Viscera WeightGut weight of abalone (in grams), after bleeding
在出血之后,鲍鱼内脏的重量(单位克)
Shell WeightWeight of dried abalone shell (in grams)
干燥的鲍鱼壳的重量(单位克)

.

——预测的标签是圈数,作为鲍鱼年龄的代理。

这里写图片描述

3、Setup

——这篇教程使用了三个数据集。abalone_train.csv包含了有标签的训练数据,共3320个例子。abalone_test.csv包含了有标签的测试数据,共850个例子。abalone_predict包含了7个例子来做出预测。

4、Loading Abalone CSV Data into TensorFlow Datasets

——为了将鲍鱼数据集喂给模型,你需要下载并加载CSVs到tensorflow的Datasets中。首先,添加一些Python和tensorflow的标准导入模块。

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

import tempfile 
import urllib

import numpy as np
import tensorflow as tf

tf.logging.set_verbosity(tf.logging.INFO)

——接着定义flags,允许用户通过命令行,随意的指定CSV文件进行训练、测试和预测数据集,并且使用日志:

flags = tf.app.flags
FLAGS = flags.FLAGS

flags.DEFINE_string(
    "train_data",
    "",
    "Path to the training data"
)
flags.DEFINE_string(
    "test_data",
    "",
    "Path to the test data."
)
flags.DEFINE_string(
    "predict_data",
    "",
    "Path to the prediction data"
)

tf.logging.set_verbosity(tf.logging.INFO)

——然后定义函数来加载CSVs(要么从命令行选项中指定文件,要么从tensorflow.org中下载)。

def maybe_download():
    '''maybe downloads training data and returns train and test file names'''
    if FLAGS.train_data:
        train_file_name=FLAGS.train_data
    else:
        train_file=tempfile.NamedTemporaryFile(delete=False)
        urllib.urlretrieve("http://download.tensorflow.org/data/abalone_train.csv",train_file.name)
        train_file_name=train_file.name
        train_file.close()
        print("Training data is download to %s"%train_file.name)

    if FLAGS.test_data:
        test_file=tempfile.NamedTemporaryFile(delete=False)
        urllib.urlretrieve("http://download.tensorflow.org/data/abalone_test.csv",test_file.name)
        test_file_name=test_file.name
        test_file.close()
        print("Test data is downloaded to %s"%test_file_name)

    if FLAGS.predict_data:
        predict_file_name=FLAGS.predict_data
    else:
        predict_file=tempfile.NamedTemporaryFile(delete=False)
        urllib.urlretrieve("http://download.tensorflow.org/data/abalone_predict.csv",predict_file.name)
        predict_file_name=predict_file.name        
        predict_file.close()
        print("Prediction data is downloaded to %s"%predict_file_name)

    return train_file_name,test_file_name,predict_file_name

——最终,创建一个main()函数,并且加载鲍鱼csv文件到Datasets:

def main(unused_argv):
    # load datasets
    abalone_train,abalone_test,abalone_predict=maybe_download()

    # training examples
    training_set=tf.contrib.learn.datasets.base.load_csv_without_header(
        filename=abalone_train,
        target_dtype=op.int,
        features_dtype=np.float64
    )

    # test examples
    test_set=tf.contrib.learn.datasets.base.load_csv_without_header(
        filename=abalone_test,
        target_dtype=np.int,
        features_dtype=np.float64
    )

    # set of 7 examples for which to predict abalone ages
    prediction_set=tf.contrib.learn.datasets.base.load_csv_without_header(
        filename=abalone_predict,
        target_dtype=np.int,
        features_dtype=np.float64
    )

if __name__ == "__main__":
    tf.app.run()

5、Instantiating an Estimator

——当使用tf.contrib.learn提供的类中的一个类来定义模型的时候,如DNNClassifier,你需要在构建器中提供所有正确的配置参数,如:

my_nn = tf.contrib.learn.DNNClassifier(
    feature_columns=[age,height,weight],
    hidden_units=[10,10,10],
    activation_fn=tf.nn.relu,
    dropout=0.2,
    n_classes=3,
    optimizer="Adam"
)

——你不需要写进一步的代码来知道tensorflow如何训练模型、计算损失或者返回预测值,逻辑已经在DNNClassifier中写好了。

——相比之下,当你从零开始创建你自己的estimator时,constructor对于模型配置只接收两个高级别的参数,model_fn和params。

nn = tf.contrib.learn.Estimator(
    model_fn=model_fn,
    params=model_params
)
  • model_fn:一个函数对象,包含了上面所有提到的支持训练、验证和预测的逻辑。你要负责实现这个功能,在下一节中,Constructing the model_fn涵盖了创建一个模型函数的细节。

  • params:一个可选字典,包含了超参数(例如,learning rate, dropout),传递给model_fn。

——注意,就像tf.contrib.learn预定义的回归器和分类器一样,Estimator初始化程序也需要接收一般的配置参数model_dir和config。

——对于鲍鱼年龄预测器,模型将会接收一个超参数:learning rate。在你的代码最开始的地方,日志配置的后面,定义LEARNING_RATE作为一个常数(下面用粗体标出)。

tf.logging.set_verbosity(tf.logging.INFO)

# Learning rate for the model
LEARNING_RATE = 0.001

——注意:这里LEARNING_RATE设置为0.001,但是你可以在模型训练中,根据需要调整这个值以实现最好的结果。

——接着添加以下的代码到main()函数中,创建包含学习速率的字典model_params,并实例化Estimator:

# set model params
model_params = {"learning_rate":LEARNING_RATE}

# build 2 layer fully connected DNN with 10,10 units respectively
m = tf.contrib.learn.Estimator(
    model_fn=model_fn,
    params=model_params
)

6、Constructing the model_fn

——对于一个EstimatorAPI模型函数基本的骨架差不多是这样的:

def model_fn(features, targets, mode, params):
    # logic to do the following:
    # 1. configure the model via tensorflow operations
    # 2. define the loss function for training/evaluation
    # 3. define the training operation/optimizer
    # 4. generate predictions
    return predictions,loss,train_op

——model_fn必须接收三个参数:

  • features:一个字典,包含了通过fit(),,evaluate()或者predict()操作传递给模型的特征。

  • targets:一个Tensor,包含了通过fit(),,evaluate()或者predict()操作传递给模型的标签。对于predict()调用,可能是空的。因为这些是模型推算出来的值。

  • mode:以下ModeKeys字符串值中的一个,表明 model_fn是在哪个文本被调用的。

    • tf.contrib.learn.ModeKeys.TRAIN:在训练模式下,model_fn被调用,如fit()调用。
    • tf.contrib.learn.ModeKeys.EVAL:在验证模式下,model_fn被调用,如evaluate()调用。
    • tf.contrib.learn.ModeKeys.INFER:在训预测模式下,model_fn被调用,如predict()调用。

——model_fn也接收params参数,是一个包含训练中使用的超参数的字典(如上述骨架中所展示的那样)。

——函数体执行了以下的任务(细节部分将在后面章节详细描述):

  • 配置模型,这里对于鲍鱼预测器来说,是一个神经网络。

  • 定义损失函数,用来评估模型的预测值与目标值有多匹配。

  • 定义训练的操作,指定optimizer算法来最小化损失函数得到的损失值。

——最终,依赖于model_fn运行的哪个mode,返回以下三个值中的一个或多个:

  • predictions(在INFER和EVAL模式下需要):一个字典,将你选择的key name映射到包含模型预测值的tensor中。例如(下面的代码):

    • 三个在INFER模式下,在model_fn返回的字典会接着被predict()返回,所以你可以用你喜欢的格式在构建它。
    • 在EVAL模式下,字典被metric functions用来计算度量。任何传递给evaluate()的metrics参数的MetricSpec必须有一个prediction_key,这个prediction_key在predictions()中匹配与之相关的预测的key name。
predictions = {"results":tensor_of_predictions}
  • loss(在EVAL和TRAIN模式下需要):一个Tensor,包含了标量损失值:模型的损失函数计算的所有输入样本的损失输出(将会在Defining loss for the model部分进行更深一步的讨论)。用在TRAIN模式下,为了错误处理和日志记录。在EVAL模式下自动的包括在一个度量中。

  • train_op(只在TRAIN模式下需要):一个运行训练每一步的操作。

6.1 Configuring a neural network with tf.contrib.layers

——构建neural network需要创建和连接输入层,隐藏层和输出层。

——输入层是一些列节点(模型中的每一个特征),接收在features参数下传递给model_fn的特征数据。如果features包含了所有特征数据的(这种情况,x和y数据集直接传递给fit(),evaluate()和predict()操作)n维tensor,然后其可以作为输入层。如果features通过输入函数,包含了传递给模型的feature columns字典,你可以使用tf.contrib.layers的input_from_feature_columns()函数,将其转换为一个输入层的tensor。

input_layer = tf.contrib.layers.imput_from_feature_columns(
    columns_to_tensors=features,
    feature_columns=[age,height,weight]
)

——如上所示,input_from_feature_columns()需要两个参数:

  • columns_to_tensors:一个模型的FeatureColumns到包含了与之相关的特征数据的Tensors的映射。这就是实际在features参数上传递给model_fn的值 。

  • feature_columns:模型中所有FeatureColumns的列表,在以上例子中是年龄、高度和宽度。

——神经网络的输入层必须通过一个激励函数(将前一层的数据做一个非线性转换),连接一个或多个隐藏层。隐藏层连接到输出层,即模型的最后一层。tf.contrib.layers对于构建全连接层,提供以下方便的函数:

hidden_layer = tf.contrib.layers.relu(inputs=input_layer,num_outputs=10)
  • relu6(inputs, num_outputs):创建一个num_outputs节点个数的层,使用ReLu 6激励函数(tf.nn.relu6),全连接于前一层hidden_layer。
second_hidden_layer = tf.contrib.layers.rulu6(inputs=hidden_layer,num_outputs=20)
  • linear(inputs, num_outputs):创建一个num_outputs节点个数的层,不使用激励函数,只是一个线性转换,直接全连接于前一层second_hidden_layer。
output_layer = tf.contrib.layers.linear(inputs=second_hidden_layer,num_outputs=3)

——所有这些函数都是更一般化函数fully_connected()一部分,也可以使用其他激励函数添加到全连接层中,如:

output_layer = tf.contrib.layers.fully_connected(
    inputs=second_hidden_layer,
    num_outputs=10,
    activation_fn=tf.sigmoid
)

——以上代码创建了一个神经网络层output_layer,使用sigmoid激励函数(tf.sigmoid)全连接于second_hidden_layer层。对于tensorflow中预先定义的可用的激励函数,可以参见API docs

将它们所有放在一起,以下代码构建了一个完整的鲍鱼预测器的神经网络。

def model_fn(features,targets,mode,params):
    # model function for estimator

    # connect the first hidden layer to input layer(features)
    # with relu activation
    first_hidden_layer = tf.contrib.layers.relu(features,10)

    # connect the second hidden layer to first hidden layer with relu
    second_hidden_layer = tf.contrib.layers.relu(first_hidden_layer,10)

    # connect the output layer to second hidden layer(no activation fn)
    output_layer = tf.contrib.layers.linear(second_hidden_layer,1)

    # reshape output layer to 1-dim tensor to return predictions
    predictions = tf.reshape(output_layer,[-1])
    predictions_dict = {"age":predictions}

——这里,因为你直接将鲍鱼数据集,通过x,y参数,传递给fit(),,evaluate()和predict()操作,输入层是features Tensor传递给model_fn。网络包含了两层隐藏层,每层10个节点,使用了RelU激励函数。输出层没有使用激励函数,并且reshaped为一个一维tensor来捕捉模型的预测,并存储在predictions_dict中。

6.2 Defining loss for the model

——model_fn 必须返回一个tensor,包含loss值,这量化了在训练和验证期间,模型对于目标值预测的好坏程度。tf.contrib.losses模块提供了方便的函数,可以使用不同的度量来计算损失值。

  • absolute_difference(predictions, targets):使用absolute-difference
    formula
    (也称之为L1 loss)计算损失。

  • log_loss(predictions, targets):使用logistic loss forumula(通常用于逻辑回归)计算损失。

  • mean_squared_error(predictions, targets):使用mean
    squared error
    (均方误差,也称之为 L2 loss)计算损失。

——-以下对loss的定义,使用mean_squared_error(),添加到鲍鱼model_fn中:

# calculate loss using mean squared error
    loss = tf.contrib.losses.mean_squared_error(predictions,targets) 

——对于tf.contrib.loss更多损失函数和细节参见API docs

6.3 Defining the training op for the model

——训练操作定义了,在模型拟合训练数据时,tensorflow将使用的优化算法。特别是在训练时,目标是最小化损失。tf.contrib.layers API提供了optimize_loss函数,只需返回一个训练操作就可以。optimize_loss需要四个参数:

——注意:optimize_loss函数提供额外的可选参数来进一步地设置优化器,例如实现decay。查看API docs获取更多信息。

——以下代码对鲍鱼model_fn,使用Defining Loss for the Model的损失值,定义了一个训练操作,学习速率使用params参数传递给函数,使用SGD优化器。对于global_step,在tf.contrib.framework中比较方便的函数get_global_step()负责生成一个整型变量。

train_op = tf.contrib.layers.optimize_loss(
        loss=loss,
        global_step=tf.contrib.framework.get_global_step(),
        learning_rate=params['learning_rate'],
        optimizer="SGD"
    )

6.4 The complete abalone model_fn

——最后,来完整鲍鱼年龄预测器的model_fn。以下代码配置了神经网络,定义了损失和训练操作,并且返回predictions_dict,loss和 train_op。

def model_fn(features,targets,mode,params):
    # model function for estimator

    # connect the first hidden layer to input layer(features)
    # with relu activation
    first_hidden_layer = tf.contrib.layers.relu(features,10)

    # connect the second hidden layer to first hidden layer with relu
    second_hidden_layer = tf.contrib.layers.relu(first_hidden_layer,10)

    # connect the output layer to second hidden layer(no activation fn)
    output_layer = tf.contrib.layers.linear(second_hidden_layer,1)

    # reshape output layer to 1-dim tensor to return predictions
    predictions = tf.reshape(output_layer,[-1])
    predictions_dict = {"age":predictions}

    # calculate loss using mean squared error
    loss = tf.contrib.losses.mean_squared_error(predictions,targets)

    train_op = tf.contrib.layers.optimize_loss(
        loss=loss,
        global_step=tf.contrib.framework.get_global_step(),
        learning_rate=params['learning_rate'],
        optimizer="SGD"
    )

    return predictions_dict, loss, train_op

7、Running the Abalone Model

——你已经对鲍鱼预测器实例化了Estimator,并在model_fn定义了它的行为,剩下的就是训练,验证和预测了。

——以下代码添加在main()函数的最后,神经网络拟合数据并验证准确度。

# fit
nn.fit(x=training_set.data,y=trainging_set.target,steps=5000)

# score accuracy
ev = nn.evaluate(x=test_set.data,y=test_set.target,steps=1)
loss_score = ev["loss"]
print("loss: %s" % loss_score)

——运行代码,你将看到以下结果。

这里写图片描述

这里写图片描述

——上面的loss分数是,当在ABALONE_TEST数据集上运行时,model_fn 返回的均方误差。

——为了在ABALONE_PREDICT数据集上预测年龄,添加以下代码到main()函数中:

# print out predictions
predictions = m.predict(
    x=prediction_set.data,
    as_iterable=True
)
for i,p in enumerate(predictions):
    print("Prediction %s: %s" % (i+1,p["ages"]))

——这里,predict()函数返回的结果在predictions 作为一个迭代,for循环enumerates,并且打印结果。重新运行代码,你将看到如下额外的输出:

这里写图片描述

——最后,完整代码如下:

# step 1 import standard module
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import tempfile 
import urllib

import numpy as np
import tensorflow as tf

tf.logging.set_verbosity(tf.logging.INFO)

# learning rate for the model
LEARNING_RATE = 0.001

# step 2 define flag, specfied csv files
flags = tf.app.flags
FLAGS = flags.FLAGS

flags.DEFINE_string(
    "train_data",
    "",
    "Path to the training data"
)
flags.DEFINE_string(
    "test_data",
    "",
    "Path to the test data."
)
flags.DEFINE_string(
    "predict_data",
    "",
    "Path to the prediction data"
)

# step 3 define function to download csv files
def maybe_download():
    '''maybe downloads training data and returns train and test file names'''
    if FLAGS.train_data:
        train_file_name=FLAGS.train_data
    else:
        train_file=tempfile.NamedTemporaryFile(delete=False)
        urllib.urlretrieve("http://download.tensorflow.org/data/abalone_train.csv",train_file.name)
        train_file_name=train_file.name
        train_file.close()
        print("Training data is download to %s"%train_file.name)

    if FLAGS.test_data:
        test_file_name=FLAGS.test_data
    else:
        test_file=tempfile.NamedTemporaryFile(delete=False)
        urllib.urlretrieve("http://download.tensorflow.org/data/abalone_test.csv",test_file.name)
        test_file_name=test_file.name
        test_file.close()
        print("Test data is downloaded to %s"%test_file_name)

    if FLAGS.predict_data:
        predict_file_name=FLAGS.predict_data
    else:
        predict_file=tempfile.NamedTemporaryFile(delete=False)
        urllib.urlretrieve("http://download.tensorflow.org/data/abalone_predict.csv",predict_file.name)
        predict_file_name=predict_file.name        
        predict_file.close()
        print("Prediction data is downloaded to %s"%predict_file_name)

    return train_file_name,test_file_name,predict_file_name


def model_fn(features,targets,mode,params):
    # model function for estimator

    # connect the first hidden layer to input layer(features)
    # with relu activation
    first_hidden_layer = tf.contrib.layers.relu(features,10)

    # connect the second hidden layer to first hidden layer with relu
    second_hidden_layer = tf.contrib.layers.relu(first_hidden_layer,10)

    # connect the output layer to second hidden layer(no activation fn)
    output_layer = tf.contrib.layers.linear(second_hidden_layer,1)

    # reshape output layer to 1-dim tensor to return predictions
    predictions = tf.reshape(output_layer,[-1])
    predictions_dict = {"ages":predictions}

    # calculate loss using mean squared error
    loss = tf.contrib.losses.mean_squared_error(predictions,targets)

    train_op = tf.contrib.layers.optimize_loss(
        loss=loss,
        global_step=tf.contrib.framework.get_global_step(),
        learning_rate=params['learning_rate'],
        optimizer="SGD"
    )

    return predictions_dict, loss, train_op

# step 4 define main
def main(unused_argv):
    # load datasets
    abalone_train,abalone_test,abalone_predict=maybe_download()

    # training examples
    training_set=tf.contrib.learn.datasets.base.load_csv_without_header(
        filename=abalone_train,
        target_dtype=np.int,
        features_dtype=np.float64
    )

    # test examples
    test_set=tf.contrib.learn.datasets.base.load_csv_without_header(
        filename=abalone_test,
        target_dtype=np.int,
        features_dtype=np.float64
    )

    # set of 7 examples for which to predict abalone ages
    prediction_set=tf.contrib.learn.datasets.base.load_csv_without_header(
        filename=abalone_predict,
        target_dtype=np.int,
        features_dtype=np.float64
    )

    # set model params
    model_params = {"learning_rate":LEARNING_RATE}

    # build 2 layer fully connected DNN with 10,10 units respectively
    m = tf.contrib.learn.Estimator(model_fn=model_fn,params=model_params)

    # fit
    m.fit(x=training_set.data,y=training_set.target,steps=5000)

    # score accuracy
    ev = m.evaluate(x=test_set.data,y=test_set.target,steps=1)
    loss_score = ev["loss"]
    print("loss: %s" % loss_score)

    # print out predictions
    predictions = m.predict(x=prediction_set.data,as_iterable=True)
    for i,p in enumerate(predictions):
        print("Prediction %s: %s" % (i+1,p["ages"]))

if __name__ == "__main__":
    tf.app.run()

8、Additional Resources

——对于建立Estimators一些额外的信息,参见以下API docs:


——以上,结束。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值