tensorflow学习笔记(六):TF.contrib.learn大杂烩

  这一节介绍一个常用的高级API:tf.contrib_learn。这个API使配置、训练和计算变得更简单。现在依然是依照官方教程进行一些学习和补充。而且程序依然会放在github里。而且从这里开始一直是按照最新的tensorflow版本(目前是r1.2)来进行。这个API的内容因为太高级了,也不准备多介绍了,因为比它好用的高级API还是有一些的,只不过这个API在自己创建Estimator上的灵活度还是很高的

一、API简略浏览

  在写程序之前依然先看一下API中的类、函数和方法
  这里 有???的是因为实在基础太差有的没有接触过,希望有人能够指教

1、Estimator

  Estimator中包含了各种机器学习和深度学习的类,我们可以直接使用这些高阶类(当然也可以我们自己在此基础上创建自己的子类)。

大致介绍
tf.contrib.learn.BaseEstimator基类但是一般不用,而是用Estimator
tf.contrib.learn.Estimator这个给了我们自定义模型的机会,非常重要后面总结
tf.contrib.learn.Trainable是Estimator的一部分内容
tf.contrib.learn.Evaluable和上面同理
tf.contrib.learn.KMeansClustering一个用于K-means的Estimator
tf.contrib.learn.ModeKeys??
tf.contrib.learn.MetricSpec??
tf.contrib.learn.PredictionKey???
tf.contrib.learn.DNNClassifier创建一个DNN模型分类器,API中有例子
tf.contrib.learn.DNNRegressor创建一个DNN回归模型
tf.contrib.learn.DNNLinearCombinedRegressor创建一个线性和DNN的联合回归模型
tf.contrib.learn.DNNLinearCombinedClassifier创建一个线性和DNN的联合分类模型
tf.contrib.learn.LinearClassifier创建一个线性和DNN的联合分类模型
tf.contrib.learn.LinearRegressor线性回归模型
tf.contrib.learn.LogisticRegressor逻辑回归模型
tf.contrib.learn.SVM用于二分类的SVM

2、Distributed training utilities

用于分布式训练的实用程序。因为对分布式不了解所以这个先跳过吧。

大致介绍
tf.contrib.learn.Experiment简单的建立模型试验的类,包括建模所需的所有信息
tf.contrib.learn.ExportStrategy可以输出一系列的模型??
tf.contrib.learn.TaskType???

3、Graph actions

这部分用于在图中执行多样的训练、评估和推断活动。

大致介绍
tf.contrib.learn.RunConfig用于管理Estimator运行的控制信息
tf.contrib.learn.evaluate评估从检查点加载的模型(弃用了)
tf.contrib.learn.infer从检查点中恢复图(弃用)
tf.contrib.learn.run_feeds弃用
tf.contrib.learn.run_n弃用
tf.contrib.learn.train弃用

上面几个弃用的方程可以用tf.train.* utilities来代替。

3、Input processing

队列和读取批量的输入数据。这个在上一节中有提及一点。

大致介绍
tf.contrib.learn.extract_dask_data从dask*(dask.Series or dask.DataFrame)中读取数据
tf.contrib.learn.extract_dask_labels同理只不过是读取标签
tf.contrib.learn.extract_pandas_data从 pandas.DataFrame读取数据用于预测
tf.contrib.learn.extract_pandas_labels从 pandas.DataFrame读取标签
tf.contrib.learn.extract_pandas_matrix从 pandas.DataFrame读取数据
tf.contrib.learn.infer_real_valued_columns_from_input把实值矩阵转为FeatureColumn对象
tf.contrib.learn.infer_real_valued_columns_from_input_fn把返回元组的输入函数作为参数转为FeatureColumn对象
tf.contrib.learn.read_batch_examplesAdds operations to read, queue, batch Example protos
tf.contrib.learn.read_batch_featuresAdds operations to read, queue, batch and parse Example protos.
tf.contrib.learn.read_batch_record_featuresReads TFRecord, queues, batches and parses Example proto

上面三个英文的都涉及到了proto这种文件格式,这是google常用的,暂时还不是很懂是什么,不过caffe也用到了。
*dask是分布式的dataframe用到的。

4、Export utilities

输出实例

大致介绍
tf.contrib.learn.build_parsing_serving_input_fn???
tf.contrib.learn.ProblemType???

二、tf.contrib.learn Quickstart


  这部分来自官方教程。用到了上面提到的的Estimator中的内容,有助于帮助我们简单理解现有的Estimator,为后面自定义Estimator做准备。可以学到的东西有:     
* 如何读取CSV数据转为TensorFlow所用数据
* 如何利用tf.contrib.learn构建简单的神经网络分类器
* 如何利用模型测试新数据
完整的程序如下,数据集是Iris:

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

import os
import urllib

import numpy as np
import tensorflow as tf

# Data sets
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 the training and test sets aren't stored locally, download them.
  # 下面这部分是看数据存不存在,不存在就下载
  if not os.path.exists(IRIS_TRAINING):
    raw = urllib.urlopen(IRIS_TRAINING_URL).read()
    with open(IRIS_TRAINING, "w") as f:
      f.write(raw)

  if not os.path.exists(IRIS_TEST):
    raw = urllib.urlopen(IRIS_TEST_URL).read()
    with open(IRIS_TEST, "w") as f:
      f.write(raw)
'''
Load datasets.用learn封装好的方法读取数据,很奇怪我没有在API上找到这个方法,后来在https://www.tensorflow.org/versions/master/api_docs/python/tf/contrib/learn/datasets找到了,进去看了下源码https://github.com/tensorflow/tensorflow/blob/master/tensorflow/contrib/learn/python/learn/datasets/base.py 发现这个是单纯用python的函数在读取整个数据,怪不得没有写在API里,因为还是针对一些常用的样例数据集写的。
返回值是一个元组,分别是(data,target)

'''
  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)

  # Specify that all features have real-value data
  # 指定数据的形式,下面的意思是形成一个4维度,列名为"",数据格式为float32(默认)的形式。
  feature_columns = [tf.contrib.layers.real_valued_column("", dimension=4)]

  # Build 3 layer DNN with 10, 20, 10 units respectively.
  classifier = tf.contrib.learn.DNNClassifier(feature_columns=feature_columns,
                                              hidden_units=[10, 20, 10],
                                              n_classes=3,
                                              model_dir="/tmp/iris_model")
  # Define the training inputs
  def get_train_inputs():
    x = tf.constant(training_set.data)
    y = tf.constant(training_set.target)

    return x, y

  # Fit model.
  classifier.fit(input_fn=get_train_inputs, steps=2000)

  # Define the test inputs
  def get_test_inputs():
    x = tf.constant(test_set.data)
    y = tf.constant(test_set.target)

    return x, y

  # Evaluate accuracy.
  #返回的是一个字典,取准确度
  accuracy_score = classifier.evaluate(input_fn=get_test_inputs,
                                       steps=1)["accuracy"]

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

  # Classify two new flower samples.
  # predict参数函数只要返回一个数据矩阵即可
  def new_samples():
    return np.array(
      [[6.4, 3.2, 4.5, 1.5],
       [5.8, 3.1, 5.0, 1.7]], dtype=np.float32)

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

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

if __name__ == "__main__":
    main()

三、Building Input Functions with tf.contrib.learn

前面我们用的输入函数使用的Python一次性读入所有数据,现在我们要换一个更好的方式,使用input_fn来预处理数据,并将数据feed给我们的模型。现在介绍使用input_fn封装数据输入的流程。

(1)基本形式

其基本的形式为:

def my_input_fn():
    # Preprocess your data here...预处理数据如归一化等,进行数据清洗

    # ...then return 1) a mapping of feature columns to Tensors with
    # the corresponding feature data, and 2) a Tensor containing labels
    # 返回两个tensor,feature_cols为一个键值对对应特征名和特征的数值,labels为标签值
    return feature_cols, labels

(2)转换特征数据为Tensors

如果输入数据为panda或arrays在input_fn返回之前需要转换为Tensor。

  • 对于连续数据可以用constant来转换:
feature_column_data = [1, 2.4, 0, 9.9, 3, 120]
feature_tensor = tf.constant(feature_column_data)
  • 对于sparse, categorical data(大部分数据都是0)需要转为一个SparseTensor,SparseTensor由三个部分组成:
    • dense_shape尺寸:和我们平时说的shape一样
    • indices索引:用于指示非零值的位置
    • values值:可以由索引得到所需要的值
      下面这个对应了一个3行5列的二维SparseTensor,坐标[0,1]处值为6、[2,4]处为0.5
sparse_tensor = tf.SparseTensor(indices=[[0,1], [2,4]],
                                values=[6, 0.5],
                                dense_shape=[3, 5])

[[0, 6, 0, 0, 0]
 [0, 0, 0, 0, 0]
 [0, 0, 0, 0, 0.5]]

(3)将转换后的Tensor输入到模型中

上面我们用过了模型fit的函数,这里更细致的讲一下。注意fit的输入为:

classifier.fit(input_fn=my_input_fn, steps=2000)

可以看到input_fn的参数为input_fn 函数 而不是返回值,也就是说下面这种情况是不允许的:

classifier.fit(input_fn=my_input_fn(training_set), steps=2000)

那么如何用参数化的函数来初始化呢?

  • 可以用下面这种形式:
def my_input_function_training_set():
  return my_input_function(training_set)

classifier.fit(input_fn=my_input_fn_training_set, steps=2000)
  • 或者使用Python的functools.partial:
classifier.fit(input_fn=functools.partial(my_input_function,
                                          data_set=training_set), steps=2000)
  • 或者使用lambda来进行函数封装:
classifier.fit(input_fn=lambda: my_input_fn(training_set), steps=2000)

这样进行参数化的函数封装有一个很大的好处,可以用同样的函数来处理evaluate 和 predict操作:

classifier.evaluate(input_fn=lambda: my_input_fn(test_set), steps=2000)

(4)例子讲解

下面用一个神经网络来预测房价,数据来自于UCI Housing Data Set,特征内容如下:

FeatureDescription
CRIMCrime rate per capita
ZNFraction of residential land zoned to permit 25,000+ sq ft lots
INDUSFraction of land that is non-retail business
NOXConcentration of nitric oxides in parts per 10 million
RMAverage Rooms per dwelling
AGEFraction of owner-occupied residences built before 1940
DISDistance to Boston-area employment centers
TAXProperty tax rate per $10,000
PTRATIOStudent-teacher ratio

输入数据可以在这里下载:boston_train.csv, boston_test.csv, and boston_predict.csv

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

import itertools

import pandas as pd
import tensorflow as tf

tf.logging.set_verbosity(tf.logging.INFO)
#数据内容
COLUMNS = ["crim", "zn", "indus", "nox", "rm", "age",
           "dis", "tax", "ptratio", "medv"]
FEATURES = ["crim", "zn", "indus", "nox", "rm",
            "age", "dis", "tax", "ptratio"]
LABEL = "medv"

#定义输入函数处理程序
def input_fn(data_set):
  feature_cols = {k: tf.constant(data_set[k].values) for k in FEATURES}
  labels = tf.constant(data_set[LABEL].values)
  return feature_cols, labels


def main(unused_argv):
  # Load datasets
  # 用pandas读取输入数据
  training_set = pd.read_csv("boston_train.csv", skipinitialspace=True,
                             skiprows=1, names=COLUMNS)
  test_set = pd.read_csv("boston_test.csv", skipinitialspace=True,
                         skiprows=1, names=COLUMNS)

  # Set of 6 examples for which to predict median house values
  prediction_set = pd.read_csv("boston_predict.csv", skipinitialspace=True,
                               skiprows=1, names=COLUMNS)

  # Feature cols
  # 产生特征列的形式
  feature_cols = [tf.contrib.layers.real_valued_column(k)
                  for k in FEATURES]

  # Build 2 layer fully connected DNN with 10, 10 units respectively.
  regressor = tf.contrib.learn.DNNRegressor(feature_columns=feature_cols,
                                            hidden_units=[10, 10],
                                            model_dir="/tmp/boston_model")

  # Fit
  # 和前面说的一样用lambda来fit参数化的函数
  regressor.fit(input_fn=lambda: input_fn(training_set), steps=5000)

  # Score accuracy
  ev = regressor.evaluate(input_fn=lambda: input_fn(test_set), steps=1)
  loss_score = ev["loss"]
  print("Loss: {0:f}".format(loss_score))

  # Print out predictions
  y = regressor.predict(input_fn=lambda: input_fn(prediction_set))
  # .predict() returns an iterator; convert to a list and print predictions
  # islice(y,6)是只看前6个结果
  predictions = list(itertools.islice(y, 6))
  print("Predictions: {}".format(str(predictions)))

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

四、Logging and Monitoring Basics with tf.contrib.learn

  这部分主要是模型训练的监控,主要利用TensorFlow的 logging capabilities(记录功能)和Monitor API 。例子程序建立在tf.contrib.learn Quickstart的基础之上。如果没有过程记录,其实整个算法就和黑盒子一样什么都看不到,比如有的时候可能模型在很早就已经收敛了或者看看模型是不是early stopping了是很必要的。
  一种解决方法是多次使用fit来一步一步评估模型,但是这明显很慢所以并不建议使用,所以 tf.contrib.learn提供了Monitor API帮助我们在训练过程中评估模型,下面内容主要有三个过程:

  • 如何进行记录
  • 如何设置一个ValidationMonitor进行流式的监控
  • 在TensorBoard上进行可视化

(1)Logging with TensorFlow记录

Tensorflow记录有5个等级DEBUG, INFO, WARN, ERROR, and FATAL(严重程度升序),比如我设计记录等级是INFO,那么我就屏蔽了Debug的内容但是保留高等级的记录信息。默认配置的记录等级是WARN也就是我们平时看到的,因为我们平时并没有看到INFO和DEBUG的信息。但是现在,因为我们要进行模型评估所以调整记录等级为INFO
方法是在import后面加上:

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

这时候运行代码的时候就会看到:

INFO:tensorflow:loss = 1.18812, step = 1
INFO:tensorflow:loss = 0.210323, step = 101
INFO:tensorflow:loss = 0.109025, step = 201

而且tf.contrib.learn会自动的每100个step输出训练损失评估指标到stderr。

(2)ValidationMonitor进行流式监控

tf.contrib.learn提供了一些高级的Monitor帮助我们在fit的时候进一步进行更细微的监控

Monitor描述
CaptureVariable每n个step保存一个特殊的变量值
PrintTensor每n个step记录一个特殊的tensor值
SummarySaver每n个step用tf.summary.FileWriter保存给定的tensor到tf.Summary protocol buffers
ValidationMonitor每n个step记录一个特定的评估指标集合,而且可以满足条件情况下设置早停止

  我们如果想要在训练的同时评估测试集的结果,就可以使用ValidationMonitor作用在测试数据上。默认的every_n_steps为100,这里我们设置every_n_steps为50,并把下面的程序放到classifier的后面 :

validation_monitor = tf.contrib.learn.monitors.ValidationMonitor(
    test_set.data,
    test_set.target,
    every_n_steps=50)

  因为ValidationMonitor依赖于保存当前的checkpoint进行评估操作,所以我们需要在classifier中加入tf.contrib.learn.RunConfig(包含save_checkpoints_secs这个记录着保存两次checkpoint的时间差),因为iris训练数据少,所以可以设置save_checkpoints_secs为1

#model_dir保存着checkpoint是可以断点再训练的关键
classifier = tf.contrib.learn.DNNClassifier(
    feature_columns=feature_columns,
    hidden_units=[10, 20, 10],
    n_classes=3,
    model_dir="/tmp/iris_model",
    config=tf.contrib.learn.RunConfig(save_checkpoints_secs=1))

最终在fit的时候要附上validation_monitor,注意需要一个列表封装,因为可以同时有几种monitor存在:

classifier.fit(x=training_set.data,
               y=training_set.target,
               steps=2000,
               monitors=[validation_monitor])

最终得到的结果应该类似于:

INFO:tensorflow:Validation (step 50): loss = 1.71139, global_step = 0, accuracy = 0.266667
...
INFO:tensorflow:Validation (step 300): loss = 0.0714158, global_step = 268, accuracy = 0.966667
...
INFO:tensorflow:Validation (step 1750): loss = 0.0574449, global_step = 1729, accuracy = 0.966667

流式监控进阶内容
  1.自定义度量:
  可以看到ValidationMonitor会记录loss和accuracy,但是我们同样可以自定义度量方法。可以在ValidationMonitor的构造函数上加入metrics参数,其参数是一个键值对,键为想要记录的度量的名称,值为相应的MetricSpec对象。
MetricSpec对象可以接收下面几个参数(这里不是很明白):

  • metric_fn:计算并返回度量值的函数,可以使用现有的tf.contrib.metrics.streaming_precision或tf.contrib.metrics.streaming_recall也可以定制自己的函数
  • prediction_key:可以看成是预测结果的类别,包括:CLASSES、LOGISTIC、PROBABILITIES、SCORES、TOP_K等
  • label_key:这个在input_fn使用的时候才用
  • weights_key:
    下面的代码就定义了三种度量方法:
validation_metrics = {
    "accuracy":
        tf.contrib.learn.MetricSpec(
            metric_fn=tf.contrib.metrics.streaming_accuracy,
            prediction_key=tf.contrib.learn.PredictionKey.CLASSES),
    "precision":
        tf.contrib.learn.MetricSpec(
            metric_fn=tf.contrib.metrics.streaming_precision,
            prediction_key=tf.contrib.learn.PredictionKey.CLASSES),
    "recall":
        tf.contrib.learn.MetricSpec(
            metric_fn=tf.contrib.metrics.streaming_recall,
            prediction_key=tf.contrib.learn.PredictionKey.CLASSES)
}

把这个字典放入validation_monitor的metrics参数中,即metrics=validation_metrics,得到的结果如下:

INFO:tensorflow:Validation (step 50): recall = 0.0, loss = 1.20626, global_step = 1, precision = 0.0, accuracy = 0.266667
...
INFO:tensorflow:Validation (step 600): recall = 1.0, loss = 0.0530696, global_step = 571, precision = 1.0, accuracy = 0.966667
...
INFO:tensorflow:Validation (step 1500): recall = 1.0, loss = 0.0617403, global_step = 1452, precision = 1.0, accuracy = 0.966667

  2.早停止:
  我们可以设置早停止选项在需要停止的时候停止训练:

参数描述
early_stopping_metric早停止指标如loss或者accuracy
early_stopping_metric_minimizeTrue代表希望最小化上面的指标,False希望最大化上面的指标
early_stopping_rounds默认是None也就是不会早停止,如果是n就代表指标在n轮都不变那就停止
validation_monitor = tf.contrib.learn.monitors.ValidationMonitor(
    test_set.data,
    test_set.target,
    every_n_steps=50,
    metrics=validation_metrics,
    early_stopping_metric="loss",
    early_stopping_metric_minimize=True,
    early_stopping_rounds=200)

结果是:

...
INFO:tensorflow:Validation (step 1150): recall = 1.0, loss = 0.056436, global_step = 1119, precision = 1.0, accuracy = 0.966667
INFO:tensorflow:Stopping. Best step: 800 with loss = 0.048313818872.

接着就可以直接在TensorBoard上看结果了,注意logdir的地址:

$ tensorboard --logdir=/tmp/iris_model/
Starting TensorBoard 39 on port 6006

(3)全部程序

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

import os

import numpy as np
import tensorflow as tf

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

# Data sets
IRIS_TRAINING = os.path.join(os.path.dirname(__file__), "iris_training.csv")
IRIS_TEST = os.path.join(os.path.dirname(__file__), "iris_test.csv")


def main(unused_argv):
  # Load datasets.
  training_set = tf.contrib.learn.datasets.base.load_csv_with_header(
      filename=IRIS_TRAINING, target_dtype=np.int, features_dtype=np.float)
  test_set = tf.contrib.learn.datasets.base.load_csv_with_header(
      filename=IRIS_TEST, target_dtype=np.int, features_dtype=np.float)

  validation_metrics = {
      "accuracy":
          tf.contrib.learn.MetricSpec(
              metric_fn=tf.contrib.metrics.streaming_accuracy,
              prediction_key="classes"),
      "precision":
          tf.contrib.learn.MetricSpec(
              metric_fn=tf.contrib.metrics.streaming_precision,
              prediction_key="classes"),
      "recall":
          tf.contrib.learn.MetricSpec(
              metric_fn=tf.contrib.metrics.streaming_recall,
              prediction_key="classes")
  }
  validation_monitor = tf.contrib.learn.monitors.ValidationMonitor(
      test_set.data,
      test_set.target,
      every_n_steps=50,
      metrics=validation_metrics,
      early_stopping_metric="loss",
      early_stopping_metric_minimize=True,
      early_stopping_rounds=200)

  # Specify that all features have real-value data
  feature_columns = [tf.contrib.layers.real_valued_column("", dimension=4)]

  # Build 3 layer DNN with 10, 20, 10 units respectively.
  classifier = tf.contrib.learn.DNNClassifier(
      feature_columns=feature_columns,
      hidden_units=[10, 20, 10],
      n_classes=3,
      model_dir="/tmp/iris_model",
      config=tf.contrib.learn.RunConfig(save_checkpoints_secs=1))

  # Fit model.
  classifier.fit(x=training_set.data,
                 y=training_set.target,
                 steps=2000,
                 monitors=[validation_monitor])

  # Evaluate accuracy.
  accuracy_score = classifier.evaluate(
      x=test_set.data, y=test_set.target)["accuracy"]
  print("Accuracy: {0:f}".format(accuracy_score))

  # Classify two new flower samples.
  new_samples = np.array(
      [[6.4, 3.2, 4.5, 1.5], [5.8, 3.1, 5.0, 1.7]], dtype=float)
  y = list(classifier.predict(new_samples))
  print("Predictions: {}".format(str(y)))


if __name__ == "__main__":
  tf.app.run()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值