© Poornachandra Sarang 2021
P. SarangArtificial Neural Networks with TensorFlow 2https://doi.org/10.1007/978-1-4842-6150-7_6

6. Estimators

Poornachandra Sarang1  
(1)
Mumbai, India
 

Introduction

Any machine learning project consists of many stages that include training, evaluation, prediction, and finally exporting it for serving on a production server. You learned these stages in previous chapters where the classification and regression machine learning projects were discussed. To develop the best performing model, you played around with different ANN architectures. Basically, you experimented with several different prototypes to achieve the desired results. Prior to TF 2.0, this entire experimentation was not so easy as for every change that you make in the code, you were required to build a computational graph and run it in a session. The estimators that you are going to study in this chapter were designed to handle all this plumbing. The entire process of creating graphs and running them in sessions was a time-consuming job and posed lots of challenges in debugging the code.

Additionally, after the model is fully developed, there was a challenge of deploying it to a production environment where you may wish to deploy it in a distributed environment for better performance. Also, you may like to run the model on a CPU, GPU, or a TPU. This necessitated code changes. To help you with all these issues and to bring everything under one umbrella, estimators were introduced, albeit prior to TF 2.0. However, the estimators, which you are going to learn in this chapter and will be using in all your future projects, are capable of taking advantage of the many new facilities introduced in TF 2.x. For example, there is a clear separation between building a data pipeline and the model development. The deployment on a distributed environment too occurs without any code change. The enhanced logging and tracing make debugging easier. In this chapter, you will learn how estimator achieves this.

In particular, you will learn the following:
  • What is an estimator?

  • What are premade estimators?

  • Using a premade estimator for classification problems

  • Using a premade estimator for regression problems

  • Building custom estimators on Keras models

  • Building custom estimators on tfhub modules

Estimator Overview

A TensorFlow estimator is a high-level API that unifies several stages of machine learning development under a single umbrella. It encapsulates the various APIs for training, evaluation, prediction, and exporting your model for production use. It is a high-level API that provides a further abstraction to the existing TensorFlow API stack.

API Stack

After the introduction of estimators, the new API stack for TensorFlow can be depicted as shown in Figure 6-1.
../images/495303_1_En_6_Chapter/495303_1_En_6_Fig1_HTML.jpg
Figure 6-1

TensorFlow API stack

So far, you have mostly used mid-level APIs; the use of low-level APIs becomes a rare necessity when you need a finer control over the model development. Now, after learning the estimator API, you may not even use the mid-level APIs for your model developments. But then what happens to the models which you have already developed – can they benefit from using this API? And if so, how to make them use this API? Fortunately, the TensorFlow team has developed an interface that allows you to migrate the existing models to use the estimator interface. Not only that, they have created a few estimators on their own to get you quickly started. These are called premade estimators. They are not just the start-up points. They are fully developed and tested for you to use in your immediate projects. If at all these do not meet your purpose or if you want to migrate existing models to facilitate the benefits offered by the estimator, you can develop custom estimators using the estimator API. Before you learn how to use premade estimators and to build your own ones, let me discuss its benefits in more detail.

Estimator Benefits

To give you a quick overview of the major benefits offered by an estimator, I am first going to list them here:
  • Providing a unified interface for train/evaluate/predict

  • Handling data input through an Input function

  • Creating checkpoints

  • Creating summary logs

These need not be the only benefits, but are certainly the most important ones. I will now discuss each one in further detail. To understand the discussion, keep the estimator interface depicted in Figure 6-2 in your mind.
../images/495303_1_En_6_Chapter/495303_1_En_6_Fig2_HTML.jpg
Figure 6-2

Estimator interface

As you can see in Figure 6-2, the estimator class provides three interface methods for training, evaluation, and predictions. So, once you develop an estimator object, you will be able to call the train, evaluate, and predict methods on the same object. Note that you need to send different datasets for each. This is achieved with the help of an input function. I have explained the structure of this input function in more detail later in this section. It is sufficient to say at this point that the introduction of the Input function simplifies your experimentation with different datasets.

The checkpoints created during training allow you to roll back to a known state and continue the training from this checkpoint. This would save you lots of training time, especially when the errors occur toward the fag end of an epoch. This also makes the debugging quicker. After the training is over, the summary logs created during evaluation can be visualized on TensorBoard, giving you quick insights on how good the model is trained.

After the model is trained to your full satisfaction, next comes the task of deployment. Deploying a trained model on CPU/GPU/TPU, even mobiles and the Web, and a distributed environment previously required several code changes. If you use an estimator, you will deploy the trained model as is or at the most with minimal changes on any of these platforms.

Having said all these benefits, let us first look at the types of estimators.

Estimator Types

The estimators are classified into two categories:
  • Premade estimators

  • Custom estimators

The classification can be visualized in the diagram shown in Figure 6-3.
../images/495303_1_En_6_Chapter/495303_1_En_6_Fig3_HTML.jpg
Figure 6-3

Estimator classifications

The premade estimators are like a model in a box where the model functionality is already written by the TensorFlow team. On the other hand, in custom estimators, you are supposed to provide this model functionality. In both cases, the estimator object that you create will have a common interface for training, evaluation, and prediction. Both can be exported for serving in a similar way.

The TensorFlow library provides a few premade estimators for your immediate go; if these do not meet your purpose and/or you want to migrate your existing models to get the benefits of estimators, you would create your own estimator class. All estimators are subclasses of the tf.estimator.Estimator base class.

The DNNClassifier, LinearClassifier, and LinearRegressor are the few examples of premade estimators. The DNNClassifier is useful for creating classification models based on dense neural networks, while the LinearRegressor is for handling linear regression problems. You will learn how to use both these classes in the upcoming sections in this chapter.

As part of building a custom estimator, you will be converting an existing Keras model to an estimator. Doing so will enable you to take advantage of the several benefits offered by estimators, which you have seen earlier. You will be building a custom estimator for the wine quality regression model that you developed in the previous chapter. Finally, I will also show you how to build a custom estimator based on tfhub modules.

To work with the estimators, you need to understand two new concepts – Input functions and Feature columns. The input function creates a data pipeline based on tf.data.dataset that feeds the data to the model in batches for both training and evaluation. You may also create a data pipeline for inference. I will show you how to do this in the DNNClassifier project. Feature columns specify how the data is to be interpreted by the estimator. Before I discuss these Input function and Feature column concepts, I will give you an overview of the development of an estimator-based project.

Workflow for Estimator-Based Projects

The various steps required in the development of an estimator-based project are listed here:
  • Loading data

  • Data preprocessing

  • Defining Features columns

  • Defining the Input function

  • Model instantiation

  • Model training

  • Model evaluation

  • Judging a model’s performance on TensorBoard

  • Using a model for predictions

As part of the learning that you have done in all previous chapters, you are definitely familiar with many steps in the preceding workflow. What needs attention is defining Features columns and the Input function. I will now describe these requirements.

Features Column

Features column provide a bridge between raw data and an estimator. It transforms a diverse range of raw data into formats that estimators need. You use the tf.feature_column module to build a list of Feature columns. This then becomes an input to the estimator constructor. The estimator object uses this list while interpreting the data coming from the Input function. The whole process can be visualized as shown in Figure 6-4.
../images/495303_1_En_6_Chapter/495303_1_En_6_Fig4_HTML.jpg
Figure 6-4

How Features columns are used

As seen in the central block of Figure 6-4, the list of Feature columns is as follows:
  • Fixed acidity (numeric)

  • Volatile acidity (numeric)

  • Citric acid (numeric)

These are the features of our wine quality model that you developed in the previous chapter. Each element in the list is of type tf.feature_column.numeric_column. The following code snippet tells you how to build such a list:
# build numeric features array
numeric_feature = []
for col in numeric_columns:
 numeric_feature.append
    (tf.feature_column.numeric_column(key=col))
Sometimes, your dataset may contain categorical fields which you want to use as the features in your model building. The following code snippet tells you how to build a Features column for such categorical fields:
categorical_features = []
for col in categorical_columns:
 vocabulary = data[col].unique()
 cate = tf.feature_column.
        categorical_column_with_vocabulary_list
            (col, vocabulary)
 categorical_features.append
        (tf.feature_column.indicator_column(cate))

Note we first obtain the vocabulary by calling the categorical_column_with_vocabulary_list method and then append the indicator columns to the list.

This list is passed as a parameter to the estimator constructor, as seen in Figure 6-4. If your model requires both numerical and categorical features, you will need to append both to your destination Features column.

The left block in Figure 6-4 shows data which is actually built by an Input function. This data will be input to the estimator’s train/evaluate/predict method calls.

Next, I will describe how to write the Input function.

Input Function

The purpose of the Input function is to return the following two objects for the use of our estimator model object:
  • A dictionary of feature names (keys) and Tensors or Sparse Tensors (values) containing the corresponding feature data

  • A Tensor containing one or more labels

The basic skeleton looks like this:
def input_fn (dataset):
    # create dictionary with feature names
    # and Tensors with corresponding data
    # create Tensor for label data
    return dictionary, label

You may write separate functions based on this prototype for training/evaluation/inferencing.

I will now present you the practical implementation of the Input function taken from the example that is later discussed in this chapter. This would further clarify the concepts behind the Input function in your minds.

The input function is a Python function with the following prototype:
def input_fn(features, labels, training =
              True, batch_size = 32):
Here the features and labels arguments represent tensors containing the features and the labels data. Within the function, the data is converted into tensor by calling the function from_tensor_slices of the tf.data.Dataset module.
#converts inputs to a dataset
Dataset = tf.data.Dataset.from_tensor_slices
            ((dict(features),labels))
The input parameter to the function is a Python dictionary of features and the corresponding labels. Finally, the function returns this data to the caller in batches by using the batch method of tf.data.Dataset.
return dataset.batch(batch_size)
The function structure is visualized in Figure 6-5 for further understanding.
../images/495303_1_En_6_Chapter/495303_1_En_6_Fig5_HTML.jpg
Figure 6-5

The Input function structure

The whole matter may look quite complicated; a practical example will help in clarifying the entire implementation, and that is what I am going to do next.

Premade Estimators

I will be discussing two types of premade estimators – one for classification and the other for a regression type of problems. First, I will describe a project for classification. We will use the premade DNNClassifier for this project. The DNNClassifier defines a deep neural network and classifies its input into several classes. You will be using the MNIST database for classifying the handwritten digits into ten numeric digits. The second project that I am going to describe uses the premade estimator called LinearRegressor. The project uses the Airbnb database for the Boston region. The database consists of several houses listed on Airbnb. For each listed house, several features are captured, and the price at which the house is sold/saleable is listed. Using this information, you will develop a regression model to predict the price at which a newly listed house would probably be sold.

The use of these two different models will give you a good insight into how to use the premade estimators on your own model development problems. So let us start with a classification model first.

DNNClassifier for Classification

Create a new Colab project and rename it to DNNClassifier-estimator. As usual, import the TensorFlow using the following statement:
import tensorflow as tf

We will use the MNIST database for this project. The dataset is available in the sklearn kit. It is the database of the handwritten digits. Our task is to use the premade classifier to recognize the digits embedded in these images. The output consists of ten classes, pertaining to the ten digits.

Loading Data

To load the MNIST data from the sklearn, you use the following code:
from sklearn import datasets
digits = datasets.load_digits()
You can examine the contents of the loaded data by plotting a few images. The following code will display the first four images:
#plotting sample image
import matplotlib.pyplot as plt
plt.figure(figsize=(1,1))
fig, ax = plt.subplots(1,4)
ax[0].imshow(digits.images[0])
ax[1].imshow(digits.images[1])
ax[2].imshow(digits.images[2])
ax[3].imshow(digits.images[3])
plt.show()
You will see the output shown in Figure 6-6.
../images/495303_1_En_6_Chapter/495303_1_En_6_Fig6_HTML.jpg
Figure 6-6

Sample images

Each image is of size 8 by 8 pixels.

Preparing Data

All images are color images. We do not need the color component to identify the digit. The grayscale images would be fine for our needs. So, we remove the color component by reshaping the images:
n_samples = len(digits.images)
data = digits.images.reshape((n_samples, -1))

If you check the shape of data, you would notice that there are 1797 images, each consisting of totally 64 pixel values.

We split the data into training and testing using the following code:
from sklearn.model_selection
               import train_test_split
X_train, X_test, y_train, y_test =
                   train_test_split(
    data, digits.target, test_size =
                   0.05, shuffle=False)

At this point, we are now ready to define our input function for the estimator.

Estimator Input Function

As you have seen earlier, the input function requires data in a particular format. We need to specify a list of columns followed by the actual data as an input to the estimator. The image data consists of 64 pixels. Each pixel will be represented as a numeric column during the model training. So, to create a tensor consisting of this pixel data, first we create names for our pixel columns:
 # create column names for our model input function
 columns = ['p_'+ str(i) for i in range(1,65)]
The column names would be simply p_1, p_2, and so on. We will now construct our Features columns by appending a numeric_column type from the tf.feature_column class into an array called feature_columns.
feature_columns = []
for col in columns:
 feature_columns.append
    (tf.feature_column.numeric_column(key = col))
We define the Input function as follows:
def input_fn(features, labels, training =
                True, batch_size = 32):

The first parameter defines the features data, the second defines the target values, and the third parameter specifies whether the data is to be used for training or evaluation. The data is processed in batches – the batch size is decided by the last parameter.

We now convert this data into a tensor dataset for more efficient processing by the estimator.
#converts inputs to a dataset
 dataset = tf.data.Dataset.from_tensor_slices
                ((dict(features),labels))

The data is converted into tensors by calling the from_tensor_slices method. The method takes an input consisting of the dictionary of features and the corresponding labels.

If the input data is to be used for training, we shuffle the dataset.
#shuffle and repeat in a training mode
 if training:
   dataset=dataset.shuffle(1000).repeat()

The shuffle method shuffles the dataset. We specify the buffer size of 1000 for shuffling. To handle datasets that are too large to fit in memory, the shuffling is done in batches of data. If the buffer size is greater than the number of data points in the dataset, you get a uniform shuffle. If it is 1, you get no shuffling at all.

Finally, we return the batches of data:
#giving inputs in batches for training
 return dataset.batch(batch_size)

Now comes the time to create an estimator instance.

Creating Estimator Instance

We use the premade DNNClassifier estimator for our purpose. The instance is created using the following statement:
classifier = tf.estimator.DNNClassifier
               (hidden_units = [256, 128, 64],
                feature_columns = feature_columns,
                          optimizer = 'Adagrad',
                          n_classes = 10,
                          model_dir = 'classifier')

The constructor takes five parameters. The first parameter defines the network architecture. Here, we have defined three hidden layers in our architecture; the first layer contains 256 neurons, the second layer contains 128, and the third layer contains 64. The second parameter specifies the list of features that the data will have. Note that we have earlier created the feature_columns vector, so this is set as a default parameter. The third parameter specifies the optimizer to be used, set to Adagrad by default here. Adagrad is an algorithm for gradient-based optimization that does just this: It adapts the learning rate to the parameters, performing smaller updates. The n_classes parameter defines the number of output classes. In our case, it is 10, which is the number of digits 0 through 9. The last parameter model_dir specifies the directory name where the logs will be maintained.

Next comes the important part of model training.

Model Training

The estimator model that we created will be trained with our usual train method. Before we start the training, we need to create the input dataset for training. For this, we create a pandas dataframe consisting of the training data and the list of features using the following statement:
# create dataframes for training
import pandas as pd
dftrain = pd.DataFrame(X_train, columns = columns)
We start the training by calling the train method on the classifier object that we created earlier:
classifier.train(input_fn = lambda:input_fn
                               (dftrain,
                            y_train,
                            training = True),
                            steps = 2000)

The method takes our input_fn as the parameter. The input_fn itself takes the features and labels data as the first two parameters. The training parameter is set to True so that the data will be shuffled. The number of steps is defined to be 2000. Let me explain what this means. In machine learning, an epoch means one pass over the entire training set. A step corresponds to one forward pass and back again. If you do not create batches in your dataset, a step would correspond to exactly one epoch. However, if you have split the dataset into batches, an epoch will contain many steps – note that a step is an iteration over a single batch of data. You can compute the total number of epochs executed during the full training cycle with the formula:

Number_of_epochs = (batch_size * number_of_steps) / (number_of_training_samples)

In our current example, the batch size is 32, the number of steps is 2000, and the number of training samples is 1707. Thus, it will take (32 * 2000) / 1707, that is, 38 epochs, to complete the training.

Model Evaluation

To evaluate the model’s performance, you will create a dataframe as before, but this time with the testing data as the input:
dftest = pd.DataFrame(X_test, columns = columns)
The evaluation is performed by calling the evaluate method on the classifier.
eval_result = classifier.evaluate(
   input_fn = lambda:input_fn(dftest, y_test,
                               training = False)
)
Note that the training parameter is set to false. You can print the evaluation result by simply printing the value of eval_result. The output is shown in the screenshot given in Figure 6-7.
../images/495303_1_En_6_Chapter/495303_1_En_6_Fig7_HTML.jpg
Figure 6-7

Model evaluation results

After the evaluation is done, you can check out the various parameters in TensorBoard by loading the logs in the folder that you had specified as a value to the model_dir parameter of the DNNClassifier constructor.
%load_ext tensorboard
%tensorboard --logdir ./classifier
A sample loss plot from the logs is shown in Figure 6-8.
../images/495303_1_En_6_Chapter/495303_1_En_6_Fig8_HTML.jpg
Figure 6-8

Sample evaluation metric

Next, you will learn how to predict an unseen data using our trained estimator.

Predicting Unseen Data

To predict an unseen data, first we will create an input function called pred_input_fn as follows:
# An input function for prediction
def pred_input_fn(features, batch_size = 32):
   # Convert the inputs to a Dataset without labels.
   return tf.data.Dataset.from_tensor_slices
(dict(features)).batch(batch_size)
The function returns tensor batches of data consisting of only the features and not the labels. We will create two data points for testing the prediction functionality by picking up the items from the dftest dataset as follows:
test = dftest.iloc[:2,:]
We will pick up the target values for these two data items from the y_test dataset:
expected = y_test[:2].tolist()
We do the actual prediction by calling the predict method on the estimator object:
pred = list(classifier.predict(
   input_fn =  lambda:pred_input_fn(test))
)

The input function uses the test data that we create for testing the two unseen data items.

Finally, we print the predicted class for these two items, along with the probability of prediction and the actual target value, using the following loop:
for pred_dict, expec in zip(pred, expected):
   class_id = pred_dict['class_ids'][0]
   probability = pred_dict['probabilities']
                    [class_id]
   print('predicted class {} ,
            probability of prediction {} ,
                expected label {}'.format
                (class_id,probability,expec))
The output of the execution of the preceding statement is given here:
predicted class 8 , probability of prediction 0.9607188701629639 , expected label 8
predicted class 4 , probability of prediction 0.9926437735557556 , expected label 4

Experimenting Different ANN Architectures

It is very easy to experiment with different ANN architectures in evaluating a model's performance. For example, you can add one more layer to the previous architecture by changing the value of the hidden_units parameter in the estimator constructor. I tried the following configuration in our existing code:
hidden_units = [256, 128, 64, 32],
The execution produced the evaluation results shown in Figure 6-9.
../images/495303_1_En_6_Chapter/495303_1_En_6_Fig9_HTML.jpg
Figure 6-9

Evaluation results for more dense network

Not only the number of hidden layers and the neurons in it, you may also add the dropouts by adding a parameter in the estimator instantiation code as shown here:
classifier = tf.estimator.DNNClassifier
            (hidden_units = [256, 128, 64, 32],
             feature_columns = feature_columns,
                       optimizer='Adagrad',
                       n_classes=10,
                       dropout = 0.2,
                       model_dir='classifier')
The evaluation results for this configuration are shown in Figure 6-10.
../images/495303_1_En_6_Chapter/495303_1_En_6_Fig10_HTML.jpg
Figure 6-10

Evaluation metrics after adding dropout

Thus, you can easily experiment with several model architectures. You may also experiment with different datasets – for example, by changing the number of features included in the Features column list. Once satisfied with the model’s performance, you can save it to a file and then take the saved file straightaway to the production server for everybody’s use.

Project Source

The full code for the project is given in Listing 6-1 for your quick reference.
import tensorflow as tf
from sklearn import datasets
digits = datasets.load_digits()
#plotting sample image
import matplotlib.pyplot as plt
plt.figure(figsize=(1,1))
fig, ax = plt.subplots(1,4)
ax[0].imshow(digits.images[0])
ax[1].imshow(digits.images[1])
ax[2].imshow(digits.images[2])
ax[3].imshow(digits.images[3])
plt.show()
# reshape the data to two dimensions
n_samples = len(digits.images)
data = digits.images.reshape((n_samples, -1))
data.shape
# split into training/testing
from sklearn.model_selection
    import train_test_split
        X_train, X_test, y_train, y_test =
            train_test_split(
        data, digits.target, test_size = 0.05,
                shuffle=False)
# create column names for our model input function
  columns = ['p_'+ str(i) for i in range(1,65)]
feature_columns = []
for col in columns:
 feature_columns.append
    (tf.feature_column.numeric_column(key=col))
def input_fn(features, labels,
            training = True, batch_size = 32):
  #converts inputs to a dataset
  dataset = tf.data.Dataset.from_tensor_slices(
               (dict(features),labels))
  #shuffle and repeat in a training mode
  if training:
    dataset=dataset.shuffle(1000).repeat()
  #giving inputs in batches for training
  return dataset.batch(batch_size)
classifier = tf.estimator.DNNClassifier
             (hidden_units = [256, 128, 64],
              feature_columns = feature_columns,
                        optimizer = 'Adagrad',
                        n_classes = 10,
                        model_dir = 'classifier')
# create dataframes for training
import pandas as pd
dftrain = pd.DataFrame
            (X_train, columns = columns)
classifier.train(input_fn =
           lambda:input_fn(dftrain,
                           y_train,
                           training = True),
                           steps = 2000)
# create dataframe for evaluation
dftest = pd.DataFrame(X_test, columns = columns)
eval_result = classifier.evaluate(
    input_fn = lambda:input_fn
               (dftest, y_test, training = False)
)
eval_result
%load_ext tensorboard
%tensorboard --logdir ./classifier
# An input function for prediction
def pred_input_fn(features, batch_size = 32):
# Convert the inputs to a Dataset without labels.
    return tf.data.Dataset.from_tensor_slices
             (dict(features)).batch(batch_size)
test = dftest.iloc[:2,:]
#1st two data points for predictions
expected = y_test[:2].tolist()
#expected labels
pred = list(classifier.predict(
    input_fn =  lambda:pred_input_fn(test))
)
for pred_dict, expec in zip(pred, expected):
    class_id = pred_dict['class_ids'][0]
    probability = pred_dict['probabilities'][class_id]
    print('predicted class {} ,
       probability of prediction {} ,
       expected label {}'.
       format(class_id,probability,expec))
Listing 6-1

DNNClassifier-Estimator full source

Now, as you have seen how to use a dense neural network classification estimator, I will show you how to use a premade classifier for regression problems.

LinearRegressor for Regression

As I mentioned in the previous chapter, neural networks can be used to solve regression problems. To support this claim, we also see a premade estimator in the TF libraries for supporting regression model development. I am going to discuss how to use this estimator in this section.

Project Description

The regression problem that we are trying to solve in this project is to determine the estimated selling price of a house in Boston. We will use the Airbnb dataset for Boston (www.kaggle.com/airbnb/boston) for this purpose. The dataset is multicolumnar and the various columns must be examined carefully for their suitableness as a feature in model development. Thus, for the regression model development, you would need to have a stringent preprocessing of data so that we sufficiently reduce the number of features and yet achieve a great amount of accuracy in predicting the house’s price.

Creating Project

As usual, create a Colab project and rename it to DNNRegressor-Estimator. Import the following libraries:
import tensorflow as tf
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np

Loading Data

You can download the data into your project using the URL specified in the following code:
url = 'https://raw.githubusercontent.com/Apress/artificial-neural-networks-with-tensorflow-2/main/ch06/listings.csv' data = pd.read_csv(url)

The data is read into a pandas dataframe. You may check the data size by calling its shape method. You will know that there are 3585 rows and whopping 95 columns. Finding out a regression relationship between these 95 columns is not an easy task even for a highly skilled data analyst. That’s where once again you will realize that neural networks can come to your aid.

Out of the 95 columns that we have in the database, obviously not all will be of use to us in training our model. So, we need some data cleansing to remove the unwanted columns and standardize the remaining. We now do the data preprocessing as described further.

Features Selection

The first thing that we do is to list out all columns, which we do by calling the columns method on the data. When you do this, you will see the output in Figure 6-11.
../images/495303_1_En_6_Chapter/495303_1_En_6_Fig11_HTML.jpg
Figure 6-11

List of columns

If you prefer, you may use data.info() to get a better understanding of the data structure. You can easily notice that there are many fields that may be irrelevant to us. To get a better idea on what columns can be eliminated, get the data description by calling the describe method. The screen output is shown in Figure 6-12.
../images/495303_1_En_6_Chapter/495303_1_En_6_Fig12_HTML.jpg
Figure 6-12

Data description

After the careful examination of the data, I decided to use only 17 columns for our analytics. In practice, you would use any of the known feature selection techniques – just to say univariate selection or correlation matrix with heatmap. These columns are selected by explicitly typing out their names as in the following statement:
# Selecting only few columns as our features
data = data[['property_type','room_type',
         'bathrooms','bedrooms','beds','bed_type',
         'accommodates','host_total_listings_count',
         'number_of_reviews','review_scores_value',
         'neighbourhood_cleansed','cleaning_fee',
         'minimum_nights','security_deposit',
         'host_is_superhost','instant_bookable',
         'price']]

After selecting our features, we need to ensure that the data it contains is clean.

Data Cleansing

We first check if the data contains any null values. You do this by using the isnull function and taking the sum on its output. The screenshot in Figure 6-13 shows the columns containing null values.
../images/495303_1_En_6_Chapter/495303_1_En_6_Fig13_HTML.jpg
Figure 6-13

Checking null values

As you can see in Figure 6-13, seven columns have null values, where the sum does not equal to zero. As the security_deposit column has 2243 nulls out of 3585 records, a very large percentage, we will eliminate this column in our analysis.
data = data.drop('security_deposit' , axis = 1)
We can examine the data by printing a few records. The command and its output are shown in Figure 6-14.
data.head()
../images/495303_1_En_6_Chapter/495303_1_En_6_Fig14_HTML.jpg
Figure 6-14

Examining data

When you examine this data, you will notice that the property_type field is categorical. We will deal with it separately during our cleansing operation. You also notice that the cleaning_fee, security_deposit, and price columns also contain a $ sign. These values must be converted into a floating-point number after stripping the $ symbol. Also, notice that the amount fields also contain a comma in between the digits. This also needs to be stripped. For cleaning up the values in these three columns, we write a transform function as shown here:
# function to remove $ and , characters
def transform(x):
 x = str(x)
 x = x.replace('$','')
 x = x.replace(",","")
 return float(x)
We now apply this transformation on the three fields in a for loop:
for col in ["cleaning_fee","price"]:
  data[col] = data[col].apply(transform)
  #filling nan with mean value
  data[col].fillna(data[col].mean(),inplace = True)

In the loop, we also replace the null values with the field’s mean value.

For the rest of the columns, we just replace null values with the column’s mean using the following code:
#filling nan values with mean value
for feature in ["bathrooms","bedrooms","beds",
                "review_scores_value"]:
 data[feature].fillna(data[feature].mean(),
               inplace = True)
Next, we look into the categorical column – property_type. As this is a categorical column, we cannot simply replace null values with a mean. We need to find an appropriate value for the replacement of the null fields. For this, let us check what the unique values are in this column. The unique values can be seen in Figure 6-15.
../images/495303_1_En_6_Chapter/495303_1_En_6_Fig15_HTML.jpg
Figure 6-15

Unique values in categorical columns

We can check the frequency of each value by calling the value_counts method. This is shown in Figure 6-16.
../images/495303_1_En_6_Chapter/495303_1_En_6_Fig16_HTML.jpg
Figure 6-16

Frequency distribution for property_type values

As the Apartment word occurs most frequently, we will use this as a replacement text to our null values in this column. We do this replacement using the following code statement:
# replacing nan with Apartment
data['property_type'].fillna('Apartment',
                             inplace = True)

Creating Datasets

Now, we are ready to extract features and labels from the preprocessed data. We do this using the following two statements:
feature = data.drop('price', axis = 1)
#input data
target = data['price']
There is one last thing that I would like to show you as a part of data preprocessing. We want to predict the price for a newly signed up apartment. So, let us look at the price distribution in our database. You can plot the histogram of the prices using the following code:
# price value histogram
data['price'].plot(kind='hist',grid = True)
plt.title('price distribution')
plt.xlabel('price')
The histogram is shown in Figure 6-17.
../images/495303_1_En_6_Chapter/495303_1_En_6_Fig17_HTML.jpg
Figure 6-17

Original price distribution

As you can see in Figure 6-17, most of the price values are in the lower range of the price spectrum. For better learning, these prices should have a better distribution rather than the skewed distribution that they have now. This is done by taking the logarithm of the price as shown in the following code:
target = np.log(data.price) #output data
target.hist()
plt.title
    ('price distribution after log transformation')
After the transformation, the distribution looks like the one shown in Figure 6-18.
../images/495303_1_En_6_Chapter/495303_1_En_6_Fig18_HTML.jpg
Figure 6-18

Price distribution after transformations

At this point, your data processing is complete. We now create the training and testing datasets.

To create the training and testing datasets, we use the train_test_split method of sklearn.
#splitting input and output data for training and testing
from sklearn.model_selection import train_test_split
xtrain,xtest,ytrain,ytest=train_test_split
    (feature, target, test_size = 0.2,
     random_state = 42)

We reserve 20% of our data for testing. The last thing that we need to do before building our estimator is to create Feature columns, which we do next.

Building Feature Columns

In the previous application, you created a Features column as a simple list of feature names. All the columns in that list were numeric. The current dataset has both numeric and categorical features. First, we build the list of numeric columns:
# selecting numerical feature columns
numeric_columns = feature.select_dtypes
      (include = np.number).columns.tolist()
numeric_columns
We include all columns with type np.number from our feature list and create a new list called numeric_columns. When you print this list, you would see the output shown in Figure 6-19.
../images/495303_1_En_6_Chapter/495303_1_En_6_Fig19_HTML.jpg
Figure 6-19

Numeric features array

Note the names of all numeric columns from our feature list are added to the new list. Next, we will convert this array into a format required by our input function for the estimator. The input function requires that the list of features with their data types (tf.feature_column) should be included in the list. We build this list using a for loop as follows:
# build numeric features array
numeric_feature = []
for col in numeric_columns:
 numeric_feature.append
    (tf.feature_column.numeric_column(key=col))
numeric_feature
If we print this list, you would see the output shown in Figure 6-20.
../images/495303_1_En_6_Chapter/495303_1_En_6_Fig20_HTML.jpg
Figure 6-20

Features column

Likewise, we will create a list of categorical columns present in our feature list. We select and build the list of column names having categorical attributes as follows:
#selecting categorical feature columns
categorical_columns = feature.select_dtypes
          (exclude=np.number).columns.tolist()
categorical_columns
When you print this list, you will see the output shown in Figure 6-21.
../images/495303_1_En_6_Chapter/495303_1_En_6_Fig21_HTML.jpg
Figure 6-21

Categorical columns list

Note that there are six columns having categorical values. Now, we build the Features column having these categorical fields with the following for loop:
categorical_features = []
for col in categorical_columns:
 vocabulary = data[col].unique()
 cate = tf.feature_column.
          categorical_column_with_vocabulary_list
          (col, vocabulary)
 categorical_features.append
          (tf.feature_column.indicator_column(cate))
We first extracted the unique values in the categorical column, then built the vocabulary list, and finally added it to the categorical_features list. If you print this list, you would see the output shown in Figure 6-22.
../images/495303_1_En_6_Chapter/495303_1_En_6_Fig22_HTML.jpg
Figure 6-22

Features column for categorical columns

Finally, we combine both numeric and categorical features into a single list for inputting as a parameter to our input function that is defined next.
# combining both features as our final features list
features = categorical_features +
            numeric_feature

Defining Input Function

The input function is defined as follows:
# An input function for training and evaluation
def input_fn(features,labels,training = True,batch_size = 32):
 #converts inputs to a dataset
 dataset=tf.data.Dataset.from_tensor_slices
            ((dict(features), labels))
 #shuffle and repeat in a training mode
 if training:
   dataset=dataset.shuffle(10000).repeat()
 # return batches of data
 return dataset.batch(batch_size)

As seen in the previous project, the function takes features and labels as the first two parameters. The training parameter determines whether the data is to be used for training; if so, the data is shuffled. The from_tensor_slices function call creates a tensor for the data pipeline to our model. The function returns the data in batches.

Creating Estimator Instance

We now create the instance of a premade estimator using the following statement:
linear_regressor = tf.estimator.LinearRegressor(
   feature_columns = features,
   model_dir = "linear_regressor")

Note we use the LinearRegressor class as a premade estimator for regression. The first parameter is the Features columns, which specify the combined numerical and categorical columns list. The second parameter is the name of the directory where the logs would be maintained.

Model Training

We train the model by calling the train method:
 linear_regressor.train(input_fn = lambda:input_fn(xtrain,
                      ytrain,
                      training = True),
                      steps = 2000)

The input function takes the features data in the xtrain dataset and the target values in the ytrain dataset. The training parameter is set to true that enables data shuffling. The number of steps would decide the number of epochs in the training phase.

Model Evaluation

We evaluate the model by calling the evaluate method:
linear_regressor.evaluate(
   input_fn = lambda:input_fn
             (xtest, ytest, training = False)
)
This time, the input function uses xtest and ytest datasets for evaluation purposes. A typical evaluation output would be as follows:
{'average_loss': 0.18083459,
 'global_step': 2000,
 'label/mean': 4.9370537,
 'loss': 0.1811692,
 'prediction/mean': 4.956979}
After the evaluation completes, we can see the various metrics by loading the TensorBoard.
%load_ext tensorboard
%tensorboard --logdir ./linear_regressor
A loss curve displayed on the TensorBoard is shown in Figure 6-23.
../images/495303_1_En_6_Chapter/495303_1_En_6_Fig23_HTML.jpg
Figure 6-23

Loss metrics

Project Source

The full code for the project is given in Listing 6-2 for your quick reference.
import tensorflow as tf
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
url = 'https://raw.githubusercontent.com/Apress/artificial-neural-networks-with-tensorflow-2/main/ch06/listings.csv'
data = pd.read_csv(url)
# listing column names
data.columns
# understanding data
data.describe()
# Selecting only few columns as our features
data = data[['property_type','room_type',
          'bathrooms','bedrooms','beds','bed_type',
          'accommodates','host_total_listings_count',
          'number_of_reviews','review_scores_value',
          'neighbourhood_cleansed','cleaning_fee',
          'minimum_nights','security_deposit',
          'host_is_superhost','instant_bookable',
          'price']]
data.isnull().sum() #nan values
data.head()
# function to remove $ and , characters
def transform(x):
  x = str(x)
  x = x.replace('$','')
  x = x.replace(",","")
  return float(x)
for col in ["cleaning_fee","security_deposit","price"]:
   data[col] = data[col].apply(transform)
# apply function
   #filling nan with mean value
   data[col].fillna(data[col].mean(),inplace = True)
#filling nan values with mean value
for feature in ["bathrooms","bedrooms","beds",
                "review_scores_value"]:
  data[feature].fillna(data[feature].mean(),
                inplace = True)
data['property_type'].unique()
# get frequency of all unique values
data['property_type'].value_counts()
# replacing nan with Apartment
data['property_type'].fillna
           ('Apartment', inplace = True)
feature = data.drop('price', axis = 1)
#input data
target = data['price']
# price value histogram
data['price'].plot(kind='hist',grid = True)
plt.title('price distribution')
plt.xlabel('price')
# make a log transformation to remove skew.
target = np.log(data.price) #output data
target.hist()
plt.title('price distribution after log transformation')
#splitting input and output data for training and testing
from sklearn.model_selection
             import train_test_split
             xtrain,xtest,ytrain,ytest =
             train_test_split
             (feature, target, test_size = 0.2,
             random_state = 42)
# selecting numerical feature columns
numeric_columns = feature.select_dtypes
           (include = np.number).columns.tolist()
numeric_columns
# build numeric features array
numeric_feature = []
for col in numeric_columns:
  numeric_feature.append
        (tf.feature_column.numeric_column(key=col))
numeric_feature
#selecting categorical feature columns
categorical_columns = feature.select_dtypes
      (exclude=np.number).columns.tolist()
categorical_columns
categorical_features = []
for col in categorical_columns:
  vocabulary = data[col].unique()
  cate = tf.feature_column.
            categorical_column_with_vocabulary_list
            (col, vocabulary)
  categorical_features.append
         (tf.feature_column.indicator_column(cate))
categorical_features
# combining both features as our final features list
features = categorical_features +
           numeric_feature
# An input function for training and evaluation
def input_fn(features,labels,training = True,batch_size = 32):
  #converts inputs to a dataset
  dataset=tf.data.Dataset.from_tensor_slices(
                 (dict(features), labels))
  #shuffle and repeat in a training mode
  if training:
    dataset=dataset.shuffle(10000).repeat()
  # return batches of data
  return dataset.batch(batch_size)
linear_regressor = tf.estimator.LinearRegressor(
    feature_columns = features,
    model_dir = "linear_regressor")
linear_regressor.train(input_fn = lambda:input_fn(xtrain,
                ytrain,
                training = True),
                steps = 2000)
linear_regressor.evaluate(
    input_fn = lambda:input_fn
            (xtest, ytest, training = False)
)
%load_ext  tensorboard
%tensorboard --logdir ./linear_regressor
Listing 6-2

LinearRegressor-Estimator full source

This project has demonstrated how to use a premade LinearRegressor for solving the linear regression problems. Next, I will describe how to build a custom estimator of your own.

Custom Estimators

In the previous chapter, you developed a wine quality classifier. You used three different architectures – small, medium, and large – to compare their results. I will now show you how to convert these existing Keras models to a custom estimator to take advantage of the facilities provided by the estimator.

Creating Project

Create a new Colab project and rename it to ModelToEstimator. Add the following imports to the project:
import tensorflow as tf
import pandas as pd
from sklearn.model_selection
             import train_test_split
from sklearn.preprocessing
             import StandardScaler

Loading Data

We will use the white wine quality that you have used previously. The data is downloaded to your project from the UCI Machine Learning Repository using the following code:
data_url='https://raw.githubusercontent.com/Apress/artificial-neural-networks-with-tensorflow-2/main/Ch05/winequality-white.csv'
data=pd.read_csv(data_url,delimiter=';')

As you are already familiar with the data, I am not going to describe it again. I will not also include any data preprocessing here. I will straightaway move on to features selection.

Creating Datasets

As you know from the previous chapter, the quality field in the database is used as a target label, and the rest of the fields are used as features. To separate out features and the target label, we used the following code:
x = data.iloc[:,:-1]
y = data.iloc[:,-1]
All selected features, which are numeric, must now be scaled to a normal distribution.
sc = StandardScaler()
x = sc.fit_transform(x)
We now create the training/testing datasets by using the train_test_split method.
xtrain, xtest, ytrain, ytest =
      train_test_split(x, y, test_size =
                       0.3,random_state = 20)
We capture the shape of xtrain in a variable; this is required while defining the Keras sequential model.
input_shape = xtrain.shape[1]

Defining Model

We use the small model definition from our previous example. The model definition is given here:
small_model = tf.keras.models.Sequential([
             tf.keras.layers.Dense
                (64,activation = 'relu',
                input_shape = (input_shape,)),
             tf.keras.layers.Dense(1)
])

The output consists of a single neuron which emits a float value for the wine quality. Note that we are treating this problem as a regression problem like the wine quality problem discussed in the previous chapter.

We compile the model by calling its compile method:
small_model.compile
            (loss = 'mse', optimizer = 'adam')

We consider this as a regression problem and thus use mse for our loss function. We will use this compiled model in the estimator instantiation. Before that, we define the input function.

Defining Input Function

The input function like in the preceding example is defined as follows:
def input_fn(features, labels,
           training = True, batch_size = 32):
 #converts inputs to a dataset
 dataset = tf.data.Dataset.from_tensor_slices
           (({'dense_input':features},labels))
  #shuffle and repeat in a training mode
 if training:
   dataset = dataset.shuffle(1000).repeat()
 #giving inputs in batch for training
 return dataset.batch(batch_size)

The function definition is identical to the earlier example and does not need any further explanation.

Now, it is time for us to convert our model to the estimator.

Model to Estimator

To convert the existing Keras models to an estimator instance, the TF libraries provide a function called model_to_estimator. The function call is shown in the following code statement:
keras_small_estimator = tf.keras.estimator.model_to_estimator(
   keras_model = small_model,
        model_dir = 'keras_small_classifier')

The function takes two arguments; the first argument specifies the previously existing compiled Keras model, and the second argument specifies the folder name where the logs would be maintained during the training. The function call returns an estimator instance which you would use like in the earlier example to train, evaluate, and predict.

Model Training

We train the model by calling the train method on the estimator instance like what we did in the earlier example.
keras_small_estimator.train
            (input_fn = lambda:input_fn
            (xtrain, ytrain), steps = 2000)

For training, the input function takes the features data in xtrain and the labels in ytrain. The number of steps is set to 2000, which decides the number of training epochs. The mode set by the training argument takes the default value of True.

Evaluation

After the training completes, you can evaluate the model’s performance by calling the evaluate method on the estimator instance.
eval_small_result =
            keras_small_estimator.evaluate(
   input_fn = lambda:input_fn
           (xtest, ytest, training = False),
                steps=1000)
print('Eval result: {}'.format
           (eval_small_result))
The input function this time specifies the value for the training argument which is set to False. The testing data created earlier is used for evaluation. After the evaluation, the results are printed on the console. You may check out the various metrics generated by the evaluation using TensorBoard.
%load_ext tensorboard
%tensorboard --logdir ./keras_small_classifier

Note that we pick up the metrics from the earlier specified logs folder.

Project Source

The full code for the project is given in Listing 6-3 for your quick reference.
import tensorflow as tf
import pandas as pd
from sklearn.model_selection
        import train_test_split
from sklearn.preprocessing
        import StandardScaler
data_url='https://raw.githubusercontent.com/Apress/artificial-neural-networks-with-tensorflow-2/main/Ch05/winequality-white.csv'
data=pd.read_csv(data_url,delimiter=';')
x = data.iloc[:,:-1]
y = data.iloc[:,-1]
sc = StandardScaler()
x = sc.fit_transform(x)
xtrain, xtest, ytrain,
        ytest = train_test_split
        (x, y, test_size = 0.3,random_state = 20)
input_shape = xtrain.shape[1]
small_model = tf.keras.models.Sequential([
              tf.keras.layers.Dense
                 (64,activation = 'relu',
                  input_shape = (input_shape,)),
              tf.keras.layers.Dense(1)
])
small_model.compile
        (loss = 'mse', optimizer = 'adam')
def input_fn(features, labels, training =
             True, batch_size = 32):
  #converts inputs to a dataset
  dataset = tf.data.Dataset.from_tensor_slices
         (({'dense_input':features},labels))
  #shuffle and repeat in a training mode
  if training:
    dataset = dataset.shuffle(1000).repeat()
  #giving inputs in batch for training
  return dataset.batch(batch_size)
keras_small_estimator = tf.keras.estimator.model_to_estimator(
    keras_model = small_model, model_dir =
                  'keras_small_classifier')
keras_small_estimator.train
    (input_fn = lambda:input_fn
                (xtrain, ytrain), steps = 2000)
eval_small_result =
         keras_small_estimator.evaluate(
    input_fn = lambda:input_fn
               (xtest, ytest, training = False),
                    steps=1000)
print('Eval result: {}'.format
        (eval_small_result))
%load_ext tensorboard
%tensorboard --logdir ./keras_small_classifier
Listing 6-3

ModelToEstimator full source

Custom Estimators for Pre-trained Models

In Chapter 4, you saw the use of pre-trained models from TF Hub. You have seen how to reuse these models in your own model definitions. It is also possible to convert these models into an estimator while extending their architecture. The following code shows you how to extend the VGG16 model and create a custom estimator on the extended model. VGG16 is a state-of-the-art deep learning which is trained to classify an image into 1000 categories. Suppose you just want to classify your datasets into just two categories – cats and dogs. So, we need just a binary classification. For this, we will need to change the output from categorical to binary. This example shows you how to replace the existing output layer of VGG16 with a single neuron Dense layer.

Creating Project

Create a new Colab project and rename it to tfhub-custom-estimator. Import TensorFlow as usual.
import tensorflow as tf

Importing VGG16

Import the VGG16 trained model into your project with the following statement:
keras_Vgg16 = tf.keras.applications.VGG16(
   input_shape=(160, 160, 3), include_top=False)
The input shape to the model is set as per the original model specification. The include_top parameter specifies that the top layer of the model be eliminated. Obviously, we do not want to regenerate the weights for this already trained model. So, we set the trainable parameter to false:
keras_Vgg16.trainable = False

Building Your Model

We will now build our model on top of the loaded VGG16 model:
estimator_model = tf.keras.Sequential([
   keras_Vgg16,
   tf.keras.layers.GlobalAveragePooling2D(),
   tf.keras.layers.Dense(256),
   tf.keras.layers.Dense(1)
])

We build a sequential model by taking the VGG16 as the base layer. On top of this, we add a pooling layer, followed by two Dense layers. The last layer is a binary output layer.

You may print the summaries of the two models to see the changes you have made.

The original model summary is printed with the following statement:
keras_Vgg16.summary()
The output is shown in Figure 6-24.
../images/495303_1_En_6_Chapter/495303_1_En_6_Fig24_HTML.jpg
Figure 6-24

Model summary for VGG16

As you can see in Figure 6-24, the VGG16 models have several hidden layers, and the total number of trainable parameters equals more than 14 million. You can imagine the time and resources it would have taken to train this model. Obviously, in your application, when you use this model, you will never think of retraining this model.

You can now print the summary of your newly built model.
estimator_model.summary()
The output is shown in Figure 6-25.
../images/495303_1_En_6_Chapter/495303_1_En_6_Fig25_HTML.jpg
Figure 6-25

Model summary for the extended model

In your model, you have only about 100,000 trainable parameters.

Compiling Model

The model is compiled as usual, with the desired optimizer, loss function, and metrics:
# Compile the model
estimator_model.compile(
   optimizer = 'adam',
   loss=tf.keras.losses.BinaryCrossentropy
            (from_logits = True),
   metrics = ['accuracy'])

Creating Estimator

You create an estimator using the model_to_estimator method:
est_vgg16 = tf.keras.estimator.model_to_estimator
            (keras_model = estimator_model)

Before you train the estimator, you need to process your images.

Processing Data

The model requires images of size 160x160 pixels. We preprocess the image by using the following preprocess function given in TF samples:
IMG_SIZE = 160
import tensorflow_datasets as tfds
def preprocess(image, label):
 image = tf.cast(image, tf.float32)
 image = tf.image.resize
            (image, (IMG_SIZE, IMG_SIZE))
 return image, label
The following Input function will define the data pipeline for the dogs and cats training data, which is available in the TensorFlow built-in datasets:
def train_input_fn(batch_size):
 data = tfds.load('cats_vs_dogs',
          as_supervised=True)
 train_data = data['train']
 train_data = train_data.map(preprocess).shuffle(500).batch
                      (batch_size)
 return train_data

Training/Evaluation

You train the estimator by calling its train method.
est_vgg16.train(input_fn =
       lambda: train_input_fn(32), steps = 500)
After the model is trained, you can evaluate the model’s performance:
est_vgg16.evaluate(input_fn = lambda: train_input_fn(32), steps=10)

Note that I have used the same training dataset with a different step size for model evaluation, as no separate testing dataset is available for the purpose.

The evaluation produces the following results:
{'accuracy': 0.96875, 'global_step': 500, 'loss': 0.27651623}

Project Source

The full project source is given in Listing 6-4 .
import tensorflow as tf
keras_Vgg16 = tf.keras.applications.VGG16(
   input_shape=(160, 160, 3), include_top=False)
keras_Vgg16.trainable = False
estimator_model = tf.keras.Sequential([
   keras_Vgg16,
   tf.keras.layers.GlobalAveragePooling2D(),
   tf.keras.layers.Dense(256),
   tf.keras.layers.Dense(1)
])
keras_Vgg16.summary()
estimator_model.summary()
# Compile the model
estimator_model.compile(
   optimizer = 'adam',
   loss=tf.keras.losses.BinaryCrossentropy
           (from_logits = True),
   metrics = ['accuracy'])
est_vgg16 = tf.keras.estimator.model_to_estimator
              (keras_model = estimator_model)
IMG_SIZE = 160
import tensorflow_datasets as tfds
def preprocess(image, label):
 image = tf.cast(image, tf.float32)
 image = tf.image.resize
            (image, (IMG_SIZE, IMG_SIZE))
 return image, label
def train_input_fn(batch_size):
 data = tfds.load('cats_vs_dogs',
          as_supervised = True)
 train_data = data['train']
 train_data = train_data.map(preprocess).shuffle(500).batch
          (batch_size)
 return train_data
est_vgg16.train(input_fn = lambda: train_input_fn(32), steps=500)
est_vgg16.evaluate(input_fn = lambda: train_input_fn(32), steps=10)
Listing 6-4

VGG16-custom-estimator full source

This trivial example has demonstrated how you can use well-trained models into your own models.

Summary

The estimators facilitate model development by providing a unified interface for training, evaluation, and prediction. They provide a separation of data pipeline from the model development, thus allowing you to experiment with different datasets easily. The estimators are classified as premade and custom. In this chapter, you learned to use the premade estimators for both classification and regression types of problems. The custom estimators are used for migrating the existing models to the estimator interface to take advantage of the benefits offered by estimators. An estimator-based model can be trained on a distributed environment or even on a CPU/GPU/TPU. Once you develop your model using the estimator, it can be deployed easily even on a distributed environment without any code changes. You also learned to use a well-trained model like VGG16 in your own model building. It is recommended that you use the pre-trained model wherever possible. If it does not meet your purpose, then think of creating custom estimators.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.22.242.141