1. 程式人生 > >(tensorflow)——tf.estimator自定義估算器使用方法

(tensorflow)——tf.estimator自定義估算器使用方法

文章結構

  • 1.簡介
  • 2.自定義Estimator與pre-made Estimator
  • 3.使用Pre-made Estimator
  • 4.入門 Custom Estimator
    • 4.1 Write an Input function
    • 4.2 Create feature columns
    • 4.3 Write a model function
      • 4.3.1 Define the model
        • Define the input layer
        • Hidden Layers
        • Output Layer
      • 4.3.2 Implement training, evaluation, and prediction
        • Predict
        • Calculate the loss
        • Evaluate
        • Train
  • 5 實戰 Custom Estimator
    • step 1: 初始化一個tf.estimator.Estimator例項
    • step 2: 寫model_fn
    • step 3: Define the model
    • step 4: Implement training, evaluation, and prediction
    • step 5: 開始訓練

1 簡介

在TensorFlow的UG中,他們強烈的建議在寫Tensorflow程式時使用estimator的API,使用後發現的確好用!在github上一些開源程式也已經開始使用estimator,比如

DeeplabV3+,關於DeeplabV3+的程式碼註釋可以參考我的另一篇部落格

官方原話:
We strongly recommend writing TensorFlow programs with the following APIs:
· Estimators, which represent a complete model. The Estimator API provides methods to train the model, to judge the model’s accuracy, and to generate predictions.
· Datasets for Estimators

, which build a data input pipeline. The Dataset API has methods to load and manipulate data, and feed it into your model. The Dataset API meshes well with the Estimators API.

在這裡插入圖片描述

TensorFlow官方文件對Estimator的定義是:High level tools for working with models.
它已經包含了一些內建的機器學習或者深度學習演算法模型(Premade Estimators),比如:
BaselineClassifier
BaselineRegressor
BestExporter
BoostedTreesClassifier
BoostedTreesRegressor
DNNClassifier
DNNLinearCombinedClassifier
DNNLinearCombinedRegressor
DNNRegressor
我們可以直接使用上面的模型進行深度學習演算法的驗證和實現。

2 自定義Estimator與pre-made Estimator

pre-made Estimator是別人寫好的模型(model_fn);自定義estimator需要自己設計模型
首先我們要對pre-made Estimator和custom Estimator的關係有一個清晰的理解:
在這裡插入圖片描述

3 使用Pre-made Estimator

我很少會用到pre-made Estimator,這裡就不做介紹了,感興趣可以參考官方UG

4 入門 Custom Estimator

我的另一篇部落格中介紹了DeeplabV3+,原始碼中就是使用了Custom Estimator,這份原始碼是一個不錯的例項。
此處我們首先另起爐灶,舉一個更加簡單的例子。之後再談論DeeplabV3+這個程式。

4.1 Write an Input function

def train_input_fn(features, labels, batch_size):
    """An input function for training"""
    # Convert the inputs to a Dataset.
    dataset = tf.data.Dataset.from_tensor_slices((dict(features), labels))

    # Shuffle, repeat, and batch the examples.
    dataset = dataset.shuffle(1000).repeat().batch(batch_size)

    # Return the read end of the pipeline.
    return dataset.make_one_shot_iterator().get_next()

這個輸入函式建立了一個input pipline,每次提取batch大小的(features, labels)

4.2 Create feature columns

我們必須定義模型的feature columns來明確我們的模型應該如何使用各個feature

# Feature columns describe how to use the input.
my_feature_columns = []
for key in train_x.keys():
    my_feature_columns.append(tf.feature_column.numeric_column(key=key))

4.3 Write a model function

Custom Estimator應該和DNNClassifier等Pre-made Estimator具有相同的介面:

tf.estimator.Estimator(
    model_fn, #模型函式
    model_dir=None, #儲存目錄,訓練和驗證產生的檔案都會儲存在這個目錄下
    config=None, #設定引數物件,主要針對執行環境的一些設定
    params=None, #超引數,將傳遞給model_fn使用
    warm_start_from=None #熱啟動目錄路徑
)

其中最重要的就是model_fn了,它應該具有以下形式:

my_model(
  features, #This is batch_features from input_fn
  labels, #This is batch_labels from input_fn
  mode, #An instance of tf.estimator.ModeKeys, train、evaluate或predict
  params #超引數,對應上面Estimator傳來的引數
)

4.3.1 Define the model

上面的4.3只是寫了一個函式介面,我們還要進一步詳細的定義模型。

  • An input layer
  • One or more hidden layers
  • An output layer
    在這裡插入圖片描述

4.3.1.1 Define the input layer

model_fn的第一行就應該呼叫 tf.feature_column.input_layer ,把feature dictionary和feature_columes匯入模型中:

    # Use `input_layer` to apply the feature columns.
    net = tf.feature_column.input_layer(features, params['feature_columns'])

這句話建立了模型input layer並完成了feature columns中定義的轉換
在這裡插入圖片描述

4.3.1.2 Hidden Layers

hidden layers不用多說,建立之後網路呈現如下結構
在這裡插入圖片描述

4.3.1.3 Output Layer

注意,activation=None;
units = params[‘n_classes’],這個實在構造estimator時就已經設定好了

我們把outlayer中的logits傳入softmax,就可以輸出概率分佈。

    # Compute logits (1 per class).
    logits = tf.layers.dense(net, params['n_classes'], activation=None)

在這裡插入圖片描述

4.3.2 Implement training, evaluation, and prediction

到此為止,模型已經定義好了,我們要著手實現模型的training,evaluation,prediction等功能。

4.3.2.1 Predict

# Compute predictions.
predicted_classes = tf.argmax(logits, 1)
if mode == tf.estimator.ModeKeys.PREDICT:
    predictions = {
        'class_ids': predicted_classes[:, tf.newaxis],
        'probabilities': tf.nn.softmax(logits),
        'logits': logits,
    }
    return tf.estimator.EstimatorSpec(mode, predictions=predictions)

4.3.2.2 Calculate the loss

this is the object that will be optimized !!!
train和evaluate都需要使用它

# Compute loss.
loss = tf.losses.sparse_softmax_cross_entropy(labels=labels, logits=logits)

4.3.2.3 Evaluate

tensorflow提供API去評價一個model的效能,比如tf.metrics

# Compute evaluation metrics.
accuracy = tf.metrics.accuracy(labels=labels,
                               predictions=predicted_classes,
                               name='acc_op')

如果我們還需要看其他的評價指標,比如roi等,可以把roi加入metrics字典中去。以下為完整寫法。

metrics = {'accuracy': accuracy}
tf.summary.scalar('accuracy', accuracy[1])

if mode == tf.estimator.ModeKeys.EVAL:
    return tf.estimator.EstimatorSpec(
        mode, loss=loss, eval_metric_ops=metrics)

4.3.2.4 Train

  • 首先制定優化器
optimizer = tf.train.AdagradOptimizer(learning_rate=0.1)
  • 然後確定train_op
train_op = optimizer.minimize(loss, global_step=tf.train.get_global_step())
  • 最後返回
return tf.estimator.EstimatorSpec(mode, loss=loss, train_op=train_op)

5 實戰 Custom Estimator

step 1: 初始化一個tf.estimator.Estimator例項

  # Set up a RunConfig to only save checkpoints once per training cycle.
  run_config = tf.estimator.RunConfig().replace(save_checkpoints_secs=1e9)
  model = tf.estimator.Estimator(
      model_fn=deeplab_model.deeplabv3_plus_model_fn,
      model_dir=FLAGS.model_dir,
      config=run_config,
      params={
          'output_stride': FLAGS.output_stride,
          'batch_size': FLAGS.batch_size,
          'base_architecture': FLAGS.base_architecture,
          'pre_trained_model': FLAGS.pre_trained_model,
          'batch_norm_decay': _BATCH_NORM_DECAY,
          'num_classes': _NUM_CLASSES,
          'tensorboard_images_max_outputs': FLAGS.tensorboard_images_max_outputs,
          'weight_decay': FLAGS.weight_decay,
          'learning_rate_policy': FLAGS.learning_rate_policy,
          'num_train': _NUM_IMAGES['train'],
          'initial_learning_rate': FLAGS.initial_learning_rate,
          'max_iter': FLAGS.max_iter,
          'end_learning_rate': FLAGS.end_learning_rate,
          'power': _POWER,
          'momentum': _MOMENTUM,
          'freeze_batch_norm': FLAGS.freeze_batch_norm,
          'initial_global_step': FLAGS.initial_global_step
      })

step 2: 寫model_fn

從上面estimator的初始化中:

 model_fn=deeplab_model.deeplabv3_plus_model_fn

在deeplab_model.py中定義了該函式,可以看出該函式保持了model_fn應該有的介面

def deeplabv3_plus_model_fn(features, labels, mode, params):
  """Model function for PASCAL VOC."""
  # features 是傳進來用於訓練網路的影象
  if isinstance(features, dict):
    features = features['feature']
  #對影象的各通道進行減去平均值,屬於預處理的一部分
  images = tf.cast(
      tf.map_fn(preprocessing.mean_image_addition, features),
      tf.uint8)

step3 Define the model

定義模型同樣在model_fn中

  #使用generator函式生成網路
  network = deeplab_v3_plus_generator(params['num_classes'],
                                      params['output_stride'],
                                      params['base_architecture'],
                                      params['pre_trained_model'],
                                      params['batch_norm_decay'])
  #mode == tf.estimator.ModeKeys.TRAIN
  #在train模式下網路的輸出
  logits = network(features, mode == tf.estimator.ModeKeys.TRAIN)
  #根據logits得出各畫素點屬於的類別
  pred_classes = tf.expand_dims(tf.argmax(logits, axis=3, output_type=tf.int32), axis=3)

network使用deeplab_v3_plus_generator函式生成

def deeplab_v3_plus_generator(num_classes,
                              output_stride,
                              base_architecture,
                              pre_trained_model,
                              batch_norm_decay,
                              data_format='channels_last'):
  """Generator for DeepLab v3 plus models.

  Args:
    num_classes: The number of possible classes for image classification.
    output_stride: The ResNet unit's stride. Determines the rates for atrous convolution.
      the rates are (6, 12, 18) when the stride is 16, and doubled when 8.
    base_architecture: The architecture of base Resnet building block.
    pre_trained_model: The path to the directory that contains pre-trained models.
    batch_norm_decay: The moving average decay when estimating layer activation
      statistics in batch normalization.
    data_format: The input format ('channels_last', 'channels_first', or None).
      If set to None, the format is dependent on whether a GPU is available.
      Only 'channels_last' is supported currently.

  Returns:
    The model function that takes in `inputs` and `is_training` and
    returns the output tensor of the DeepLab v3 model.
  """
  if data_format is None:
    # data_format = (
    #     'channels_first' if tf.test.is_built_with_cuda() else 'channels_last')
    pass

  if batch_norm_decay is None:
    batch_norm_decay = _BATCH_NORM_DECAY

  if base_architecture not in ['resnet_v2_50', 'resnet_v2_101']:
    raise ValueError("'base_architrecture' must be either 'resnet_v2_50' or 'resnet_v2_101'.")
  #確定模型的主體網路是resnet50還是resnet101,這裡使用的是 from tensorflow.contrib.slim.nets import resnet_v2
  #原始碼檢視網址:https://github.com/tensorflow/tensorflow/blob/master/tensorflow/contrib/slim/python/slim/nets/resnet_v2.py
  if base_architecture == 'resnet_v2_50':
    base_model = resnet_v2.resnet_v2_50
  else:
    base_model = resnet_v2.resnet_v2_101

  def model(inputs, is_training):
    """Constructs the ResNet model given the inputs."""
    if data_format == 'channels_first':
      # Convert the inputs from channels_last (NHWC) to channels_first (NCHW).
      # This provides a large performance boost on GPU. See
      # https://www.tensorflow.org/performance/performance_guide#data_formats
      inputs = tf.transpose(inputs, [0, 3, 1, 2])

    # tf.logging.info('net shape: {}'.format(inputs.shape))
    # encoder
    with tf.contrib.slim.arg_scope(resnet_v2.resnet_arg_scope(batch_norm_decay=batch_norm_decay)):
      #resnet_v2的返回值是net, end_points
      #其中net是 A rank-4 tensor of size [batch, height_out, width_out, channels_out].
      #end_points中記錄了網路中不同功能的元件,以字典形式
      #對於deeplabv3+,這裡的logits也就是net,是不需要的,因為我們還需要對這個網路進行變形,得到正確的輸出
      logits, end_points = base_model(inputs,
                                      num_classes=None,
                                      is_training=is_training,
                                      global_pool=False,
                                      output_stride=output_stride)

    if is_training:
      #實際上我們不需要base_model的logits節點,所以這部分設定為不恢復
      #可以參考部落格《使用slim從ckpt裡匯出指定層的引數》:https://www.jianshu.com/p/160620fb2580
      exclude = [base_architecture + '/logits', 'global_step']
      variables_to_restore = tf.contrib.slim.get_variables_to_restore(exclude=exclude)
      #pre_trained_model是存放預訓練模型的路徑,引數用來fine-tune
      tf.train.init_from_checkpoint(pre_trained_model,
                                    {v.name.split(':')[0]: v for v in variables_to_restore})

    inputs_size = tf.shape(inputs)[1:3]
    #去除resnet的block4的輸出,也就是最後一個卷積層的輸出
    net = end_points[base_architecture + '/block4']
    #使用 空洞空間金字塔池化
    encoder_output = atrous_spatial_pyramid_pooling(net, output_stride, batch_norm_decay, is_training)
    #設計 decoder解碼器
    with tf.variable_scope("decoder"):
      with tf.contrib.slim.arg_scope(resnet_v2.resnet_arg_scope(batch_norm_decay=batch_norm_decay)):
        with arg_scope([layers.batch_norm], is_training=is_training):
          with tf.variable_scope("low_level_features"):
            low_level_features = end_points[base_architecture + '/block1/unit_3/bottleneck_v2/conv1']
            low_level_features = layers_lib.conv2d(low_level_features, 48,
                                                   [1, 1], stride=1, scope='conv_1x1')
            low_level_features_size = tf.shape(low_level_features)[1:3]

          with tf.variable_scope("upsampling_logits"):
            net = tf.image.resize_bilinear(encoder_output, low_level_features_size, name='upsample_1')
            net = tf.concat([net, low_level_features], axis=3, name='concat')
            net = layers_lib.conv2d(net, 256, [3, 3], stride=1, scope='conv_3x3_1')
            net = layers_lib.conv2d(net, 256, [3, 3], stride=1, scope='conv_3x3_2')
            net = layers_lib.conv2d(net, num_classes, [1, 1], activation_fn=None, normalizer_fn=None, scope='conv_1x1')
            logits = tf.image.resize_bilinear(net, inputs_size, name='upsample_2')

    return logits
 return model

最後返回的是logits,至此網路就設計好了。

step4 Implement training, evaluation, and prediction

重新回到model_fn函式中,我們還需要實現training, evaluation, prediction功能

  • For mode == ModeKeys.TRAIN: required fields are loss and train_op.
  • For mode == ModeKeys.EVAL: required field is loss.
  • For mode == ModeKeys.PREDICT: required fields are predictions.
    *1、Prediction
  #解碼預測得到的labels,即pred_classes
  #得到RGB影象,每個類別不同顏色
  pred_decoded_labels = tf.py_func(preprocessing.decode_labels,
                                   [pred_classes, params['batch_size'], params['num_classes']],
                                   tf.uint8)
  # 首先 定義predictions供predict模式使用
  predictions = {
      'classes': pred_classes,
      'probabilities': tf.nn.softmax(logits, name='softmax_tensor'),
      'decoded_labels': pred_decoded_labels
  }

  if mode == tf.estimator.ModeKeys.PREDICT:
    # Delete 'decoded_labels' from predictions because custom functions produce error when used with saved_model
    predictions_without_decoded_labels = predictions.copy()
    del predictions_without_decoded_labels['decoded_labels']

    return tf.estimator.EstimatorSpec(
        mode=mode,
        predictions=predictions,
        export_outputs={
            'preds': tf.estimator.export.PredictOutput(
                predictions_without_decoded_labels)
        })

2、training

  gt_decoded_labels = tf.py_func(preprocessing.decode_labels,
                                 [labels, params['batch_size'], params['num_classes']], tf.uint8)

  labels = tf.squeeze(labels, axis=3)  # reduce the channel dimension.

  logits_by_num_classes = tf.reshape(logits, [-1, params['num_classes']])
  labels_flat = tf.reshape(labels, [-1, ])

  valid_indices = tf.to_int32(labels_flat <= params['num_classes'] - 1)
  valid_logits = tf.dynamic_partition(logits_by_num_classes, valid_indices, num_partitions=2)[1]
  valid_labels = tf.dynamic_partition(labels_flat, valid_indices, num_partitions=2)[1]

  preds_flat = tf.reshape(pred_classes, [-1, ])
  valid_preds = tf.dynamic_partition(preds_flat, valid_indices, num_partitions=2)[1]
  confusion_matrix = tf.confusion_matrix(valid_labels, valid_preds, num_classes=params['num_classes'])

  predictions['valid_preds'] = valid_preds
  predictions['valid_labels'] = valid_labels
  predictions['confusion_matrix'] = confusion_matrix

  cross_entropy = tf.losses.sparse_softmax_cross_entropy(
      logits=valid_logits, labels=valid_labels)

  # Create a tensor named cross_entropy for logging purposes.
  tf.identity(cross_entropy, name='cross_entropy')
  tf.summary.scalar('cross_entropy', cross_entropy)

  if not params['freeze_batch_norm']:
    train_var_list = [v for v in tf.trainable_variables()]
  else:
    train_var_list = [v for v in tf.trainable_variables()
                      if 'beta' not in v.name and 'gamma' not in v.name]

  # Add weight decay to the loss.
  with tf.variable_scope("total_loss"):
    loss = cross_entropy + params.get('weight_decay', _WEIGHT_DECAY) * tf.add_n(
        [tf.nn.l2_loss(v) for v in train_var_list])
  # loss = tf.losses.get_total_loss()  # obtain the regularization losses as well

  if mode == tf.estimator.ModeKeys.TRAIN:
    tf.summary.image('images',
                     tf.concat(axis=2, values=[images, gt_decoded_labels, pred_decoded_labels]),
                     max_outputs=params['tensorboard_images_max_outputs'])  # Concatenate row-wise.

    global_step = tf.train.get_or_create_global_step()

    if params['learning_rate_policy'] == 'piecewise':
      # Scale the learning rate linearly with the batch size. When the batch size
      # is 128, the learning rate should be 0.1.
      initial_learning_rate = 0.1 * params['batch_size'] / 128
      batches_per_epoch = params['num_train'] / params['batch_size']
      # Multiply the learning rate by 0.1 at 100, 150, and 200 epochs.
      boundaries = [int(batches_per_epoch * epoch) for epoch in [100, 150, 200]]
      values = [initial_learning_rate * decay for decay in [1, 0.1, 0.01, 0.001]]
      learning_rate = tf.train.piecewise_constant(
          tf.cast(global_step, tf.int32), boundaries, values)
    elif params['learning_rate_policy'] == 'poly':
      learning_rate = tf.train.polynomial_decay(
          params['initial_learning_rate'],
          tf.cast(global_step, tf.int32) - params['initial_global_step'],
          params[
            
           

相關推薦

(tensorflow)——tf.estimator定義估算使用方法

文章結構 1.簡介 2.自定義Estimator與pre-made Estimator 3.使用Pre-made Estimator 4.入門 Custom Estimator 4.1 Write an Input function 4.2 Create

在struts2中配置定義攔截放行多個方法

return med ttr limit ring req tac cat invoke 源碼: 自定義的攔截器類: //自定義攔截器類:LoginInterceptor ; package com.java.action.interceptor; import j

9.12 URL控制器之path方法--內建轉換定義轉換

兩個用法一致: django 1.0 :  url django2.0 : re_path     基於以下2個需求,django2.0 又加了path方法: 一、使用內建轉換器 內建轉換器有:   二、自定義轉換器: 1.

SpringMVC同時使用<mvc:resources … />和裝配定義轉換Converter時出現問題的解決方法

一、問題由來 在學習SpringMVC的過程中,對於URL的攔截,使用了RESTful形式,因為使用了RESTful所以,在將Servlet作為Controller中的時候,web.xml中配置攔截的url-pattern就寫成了 / ,如下所示: <servlet> <

利用List的sort方法定義比較對類屬性進行排序

JDK1.8之後,List新增了sort方法,使用Comparator作為引數,呼叫者可自定義比較規則。 User user1 = new User(12, "張三"); User use

tensorflow中RNNcell原始碼分析以及定義RNNCell的方法

我們在模擬一些論文的時候經常會遇到一些模型,對RNN或者LSTM進行了少許的修改,或者自己定義了一種RNN的結構等情況,比如前面介紹的幾篇memory networks的論文,往往都需要按照自己定義的方法來構造RNN網路。所以本篇部落格就主要總結一下RNNcel

Django入門學習(7)——定義管理和模型類的建立方法

自定義管理器的目的1:更改查詢集# -*- coding:utf-8 -*- from django.db import models class BookInfoManager(models.Manager): def get_queryset(self):

Java中的equals方法定義比較

class Student { private String name; private int age; Student(String name,int age) { this.name = name; this.age = age; } public S

淺談JavaScript--Array陣列sort()排序方法定義比較的使用

陣列的排序的重要性不必多說,到處可見,現在來說說sort()方法的使用與自定義比較器 sort()方法:預設將陣列中的所有元素轉為字串後再排列(預設是升序),用來排列字串型別的元素 比如一個數組:

kindeditor編輯新增定義外掛的方法

KindEditor是一套開源的HTML視覺化編輯器,主要用於讓使用者在網站上獲得所見即所得編輯效果。說實話在使用這個編輯器以前,我也使用過別的編輯器,最後不是因為使用麻煩,就是因為程式太臃腫,而放棄使用,可是KindEditor不同,不僅結構小巧,而且功能強大,最主要的是

struts2定義攔截註解配置方法

自定義攔截器: package com.penjing.interceptor; import javax.servlet.http.HttpServletRequest; import net.sf.json.JSONObject; import

定義攔截 includeMethods和excludeMethods無效 解決方法

首先, includeMethods和excludeMethods都是需要自定義攔截器類繼承MethodFilterInterceptor,因為只有繼承這個類的自定義攔截器才有 setIncludeMethods和setExcludeMethods方法,這個我是網上找到的,但

Collections之sort的兩個方法(自然排序和定義比較排序)

Collections是個服務於Collection的工具類(靜態的),它裡面定義了一些集合可以用到的方法。 本文演示了Collections類裡sort()的兩個方法。第一種只需傳入被排序的集合,便會為它自然排序。但有時我們需要自定義排序的方式,這是我們就得定義一個比較器

vivado設定定義編輯與notepad++設定高亮方法

vivado2015.03下tools->option->general->text editor -> 選擇custom editor, 右邊的 ... 瀏覽按鈕,如下圖

SpringMVC 定義轉換

del 轉化 string sna 問題 print request package type 實踐SpringMVC轉化器是遇到的問題:表單提交沒有經過自定義轉換器(解決:表單用post方式提交) 自定義轉化器代碼 package cn.liangqinghai.

JAVAEE——struts2_04:定義攔截、struts2標簽、登陸功能和校驗登陸攔截的實現

strac htm logs transacti 標識 area 返回 ftw jsp 一、自定義攔截器   1.架構      2.攔截器創建 //攔截器:第一種創建方式 //攔截器生命周期:隨項目的啟動而創建,隨項目關閉而銷毀 public class MyInt

struts2學習(6)定義攔截-登錄驗證攔截

back tps class res urn fff .com space war 需求:對登錄進行驗證,用戶名cy 密碼123456才能登錄進去;   登錄進去後,將用戶存在session中; 其他鏈接要來訪問(除了登錄鏈接),首先驗證

手機影音第六天 定義播放頁面的實現(按鈕暫時未監聽)

手機影音第六天 自定義播放器布局以及橫豎屏切換播放器時的問題解決 目前進度的項目源代碼托管在裏碼雲上,地址如下: https://git.oschina.net/joy_yuan/MobilePlayer 感興趣的可以去下載看看,多多支持

定義攔截判斷用戶是否有權限訪問

indexof mon com source ora extend ide isa att 1、關於權限系統,對於用戶是否有權限對系統進行訪問,設置自定義攔截器,來攔截用戶的請求 1 package org.slsale.interceptor; 2 3 impo

Swift 定義打印方法

orm rom -m http mat cti nbsp 使用 span Swift 自定義打印方法 #代碼如下 // MARK:- 自定義打印方法 func MLLog<T>(_ message : T, file : String = #file, fun