Linear Regression Tutorial with TensorFlow [Examples]

โšก Smart Summary

Linear Regression in TensorFlow models the relationship between numeric features and a continuous target value. This walkthrough trains a Boston housing price predictor three separate ways, using Pandas, NumPy, and native TensorFlow input pipelines with the LinearRegressor estimator.

  • ๐Ÿ”˜ Model form: A linear regression fits y = bias + weight ร— x, extended with more covariates for multivariate problems.
  • โ˜‘๏ธ Training loop: Gradient descent adjusts the weights each iteration until the Mean Square Error stops falling.
  • โœ… Estimator API: LinearRegressor needs only feature columns, a model directory, and an input function.
  • ๐Ÿงช Three pipelines: Pandas, NumPy, and native TensorFlow datasets feed the same model and return identical predictions.
  • ๐Ÿ› ๏ธ Worked example: Nine Boston features predict median house value and reach a test loss of 3215.
  • โš ๏ธ Version reality: Estimators were deprecated in TensorFlow 2.12 and removed in 2.16, so port new work to Keras.

Linear Regression with TensorFlow

What is Linear Regression?

Linear Regression is an approach in statistics for modelling relationships between two variables. This modelling is done between a scalar response and one or more explanatory variables. The relationship with one explanatory variable is called simple linear regression, and with more than one explanatory variable it is called multiple linear regression.

TensorFlow provides tools to have full control of the computations. This is done with the low-level API. On top of that, TensorFlow is equipped with a vast array of APIs to perform many machine learning algorithms. This is the high-level API, and TensorFlow calls them estimators.

  • Low-level API: Build the architecture and the optimization of the model from scratch. It is complicated for a beginner.
  • High-level API: Define the algorithm. It is user-friendly. TensorFlow provides a toolbox called estimator to construct, train, evaluate and make a prediction.

In this tutorial, you will use the estimators only. The computations are faster and are easier to implement. The first part explains how to use the gradient descent optimizer to train a linear regression in TensorFlow. In a second part, you will use the Boston dataset to predict the price of a house using a TensorFlow estimator.

Download Boston DataSet

How to train a linear regression model

Before we begin to train the model, let us have a look at what a linear regression actually is.

Imagine you have two variables, x and y, and your task is to predict the value of y knowing the value of x. If you plot the data, you can see a positive relationship between your independent variable, x, and your dependent variable, y, as the scatter plot below shows.

Scatter plot of x against y showing a positive linear relationship

You may observe that if x=1, y will roughly be equal to 6, and if x=2, y will be around 8.5.

This is not a very accurate method and is prone to error, especially with a dataset containing hundreds of thousands of points.

A linear regression is evaluated with an equation. The variable y is explained by one or many covariates. In your example, there is only one dependent variable. If you have to write this equation, it will be:

Simple linear regression equation with a bias, a weight and an error term

With:

  • Bias coefficient symbol is the bias. That is, if x=0, y=Bias coefficient value when x equals zero
  • Weight coefficient symbol associated with x is the weight associated with x
  • Residual error term symbol is the residual, or the error of the model. It includes what the model cannot learn from the data

Imagine you fit the model and you find the following solution for:

  • Fitted bias coefficient equal to 3.8 = 3.8
  • Fitted weight coefficient equal to 2.78 = 2.78

You can substitute those numbers in the equation and it becomes:

y= 3.8 + 2.78x

You now have a better way to find the values for y. That is, you can replace x with any value you want in order to predict y. In the image below, we have replaced x in the equation with all the values in the dataset and plotted the result.

Fitted regression line drawn in red through the plotted data points

The red line represents the fitted value, that is the values of y for each value of x. You do not need to see the value of x to predict y; for each x there is a value which belongs to the red line. You can also predict for values of x higher than 2.

If you want to extend the linear regression to more covariates, you can do so by adding more variables to the model. The difference between traditional analysis and linear regression is that linear regression looks at how y will react for each variable x taken independently.

Let us see an example. Imagine you want to predict the sales of an ice cream shop. The dataset contains different information such as the weather (rainy, sunny, cloudy) and customer information (salary, gender, marital status).

Traditional analysis will try to predict the sale by, let us say, computing the average for each variable and trying to estimate the sale for different scenarios. It will lead to poor predictions and restrict the analysis to the chosen scenario.

If you use linear regression, you can write this equation:

Multiple linear regression equation combining several weighted covariates

The algorithm will find the best solution for the weights; it means it will try to minimize the cost, which is the difference between the fitted line and the data points.

How the algorithm works

The diagram below summarises the loop the algorithm repeats: pick weights, predict y, measure the error, and correct the weights.

Flow diagram of the linear regression training loop from random weights to minimised error

The algorithm will choose a random number for each Randomly initialised bias coefficient and Randomly initialised weight coefficient and replace the value of x to get the predicted value of y. If the dataset has 100 observations, the algorithm computes 100 predicted values.

We can compute the error, noted Model error term used in the loss calculation, of the model, which is the difference between the predicted value and the real value. A positive error means the model underestimates the prediction of y, and a negative error means the model overestimates the prediction of y.

Squared error minimisation objective written in mathematical notation

Your goal is to minimize the square of the error. The algorithm computes the mean of the square error. This step is called minimization of the error. For linear regression, this is the Mean Square Error, also called MSE. Mathematically, it is:

Mean Square Error formula written in matrix notation

Where:

  • Weight vector symbol used in the MSE formula is the weights, so Predicted value notation used in the MSE formula refers to the predicted value
  • y is the real values
  • m is the number of observations

Note that Transposed weight matrix notation means it uses the transpose of the matrices. The Summation and mean notation used in the MSE formula is the mathematical notation of the mean.

The goal is to find the best Optimal weight symbol that minimises the MSE that minimizes the MSE.

If the average error is large, it means the model performs poorly and the weights are not chosen properly. To correct the weights, you need to use an optimizer. The traditional optimizer is called Gradient Descent.

The gradient descent takes the derivative and decreases or increases the weight. If the derivative is positive, the weight is decreased. If the derivative is negative, the weight increases. The model will update the weights and recompute the error. This process is repeated until the error does not change anymore. Each pass is called an iteration. Besides, the gradients are multiplied by a learning rate, which indicates the speed of the learning.

If the learning rate is too small, it will take a very long time for the algorithm to converge, because it requires many more iterations. If the learning rate is too high, the algorithm might never converge. The loss curve below plots the error against the iteration count for this dataset.

Loss curve showing the error falling and stabilising after about twenty iterations

You can see from the picture above that the model repeats the process about 20 times before finding a stable value for the weights, therefore reaching the lowest error.

Note that the error is not equal to zero but stabilizes around 5. It means the model makes a typical error of 5. If you want to reduce the error, you need to add more information to the model, such as more variables, or use different estimators.

You remember the first equation:

Final fitted linear regression equation with the solved weights

The final weights are 3.8 and 2.78. The video below shows you how the gradient descent optimizes the loss function to find these weights.

How to train a Linear Regression with TensorFlow

Now that you have a better understanding of what is happening behind the hood, you are ready to use the estimator API provided by TensorFlow to train your first linear regression using TensorFlow.

Version note: the estimator workflow shown below was written against TensorFlow 1.x and the early 2.x releases. TensorFlow marked the tf.estimator and tf.feature_column APIs fully deprecated in version 2.12 and dropped Estimators in version 2.16. On a current install, run this code inside a TensorFlow 1.15 or 2.x-with-tf.compat.v1 environment, or port it to Keras, where tf.keras.layers.Dense(1) plus preprocessing layers replace the LinearRegressor and the feature columns. The concepts โ€” features, labels, batches, epochs, MSE and gradient descent โ€” carry over unchanged.

You will use the Boston Dataset, which includes the following variables.

Variable Description
crim per capita crime rate by town
zn proportion of residential land zoned for lots over 25,000 sq.ft.
indus proportion of non-retail business acres per town.
nox nitric oxides concentration
rm average number of rooms per dwelling
age proportion of owner-occupied units built before 1940
dis weighted distances to five Boston employment centers
tax full-value property-tax rate per dollars 10,000
ptratio pupil-teacher ratio by town
medv Median value of owner-occupied homes in thousand dollars

You will create three different datasets:

dataset objective shape
Training Train the model and obtain the weights 400, 10
Evaluation Evaluate the performance of the model on unseen data 100, 10
Predict Use the model to predict house value on new data 6, 10

The objective is to use the features of the dataset to predict the value of the house.

During the second part of the tutorial, you will learn how to use TensorFlow with three different ways to import the data:

  • With Pandas
  • With NumPy
  • Only TensorFlow

Note that all three options provide the same results.

You will learn how to use the high-level API to build, train and evaluate a TensorFlow linear regression model. If you were using the low-level API, you would have to define by hand the:

  • Loss function
  • Optimizer: gradient descent
  • Matrix multiplication
  • Graph and tensor

This is tedious and more complicated for a beginner.

Pandas Solution

You need to import the necessary libraries to train the model.

import pandas as pd
from sklearn import datasets
import tensorflow as tf
import itertools

Step 1) Import the data with Pandas.

You define the column names and store them in COLUMNS. You can use pd.read_csv() to import the data.

COLUMNS = ["crim", "zn", "indus", "nox", "rm", "age",
           "dis", "tax", "ptratio", "medv"]

Point each call at the CSV files you downloaded earlier.

training_set = pd.read_csv("E:/boston_train.csv", skipinitialspace=True,skiprows=1, names=COLUMNS)
test_set = pd.read_csv("E:/boston_test.csv", skipinitialspace=True,skiprows=1, names=COLUMNS)
prediction_set = pd.read_csv("E:/boston_predict.csv", skipinitialspace=True,skiprows=1, names=COLUMNS)

You can print the shape of the data.

print(training_set.shape, test_set.shape, prediction_set.shape)

Output

(400, 10) (100, 10) (6, 10)

Note that the label, that is your y, is included in the dataset. So you need to define two other lists: one containing only the features, and one with the name of the label only. These two lists will tell your estimator what the features in the dataset are and which column name is the label.

It is done with the code below.

FEATURES = ["crim", "zn", "indus", "nox", "rm",
                 "age", "dis", "tax", "ptratio"]
LABEL = "medv"

Step 2) Convert the data

You need to convert the numeric variables into the proper format. TensorFlow provides a method to convert a continuous variable: tf.feature_column.numeric_column().

In the previous step, you defined a list of features you want to include in the model. Now you can use this list to convert them into numeric data. If you want to exclude features from your model, feel free to drop one or more variables from the list FEATURES before you construct feature_cols.

Note that you will use a Python list comprehension with the list FEATURES to create a new list named feature_cols. It helps you avoid writing tf.feature_column.numeric_column() nine times. A list comprehension is a faster and cleaner way to create new lists.

feature_cols = [tf.feature_column.numeric_column(k) for k in FEATURES]

Step 3) Define the estimator

In this step, you need to define the estimator. TensorFlow provides six pre-built canned estimators, three for classification tasks and three for TensorFlow regression tasks:

  • Regressor
    • DNNRegressor
    • LinearRegressor
    • DNNLinearCombinedRegressor
  • Classifier
    • DNNClassifier
    • LinearClassifier
    • DNNLinearCombinedClassifier

In this tutorial, you will use the Linear Regressor. To access this function, you need to use tf.estimator.

The function needs two arguments:

  • feature_columns: contains the variables to include in the model
  • model_dir: path to store the graph, save the model parameters, and so on

TensorFlow will automatically create a folder named train in your working directory. You need to use this path to access TensorBoard, as shown in the TensorFlow regression example below.

estimator = tf.estimator.LinearRegressor(
        feature_columns=feature_cols,
        model_dir="train")

Output

INFO:tensorflow:Using default config.
INFO:tensorflow:Using config: {'_model_dir': 'train', '_tf_random_seed': None, '_save_summary_steps': 100, '_save_checkpoints_steps': None, '_save_checkpoints_secs': 600, '_session_config': None, '_keep_checkpoint_max': 5, '_keep_checkpoint_every_n_hours': 10000, '_log_step_count_steps': 100, '_train_distribute': None, '_service': None, '_cluster_spec': <tensorflow.python.training.server_lib.ClusterSpec object at 0x1a215dc550>, '_task_type': 'worker', '_task_id': 0, '_global_id_in_cluster': 0, '_master': '', '_evaluation_master': '', '_is_chief': True, '_num_ps_replicas': 0, '_num_worker_replicas': 1}

The tricky part with TensorFlow is the way to feed the model. TensorFlow is designed to work with parallel computing and very large datasets. Due to the limitation of the machine resources, it is impossible to feed the model with all the data at once. For that, you need to feed a batch of data each time. Note that we are talking about huge datasets with millions or more records. If you do not add a batch, you will end up with a memory error.

For instance, if your data contains 100 observations and you define a batch size of 10, it means the model will see 10 observations for each iteration (10*10).

When the model has seen all the data, it finishes one epoch. An epoch defines how many times you want the model to see the data. It is better to set this step to none and let the model perform a set number of iterations.

A second piece of information to add is whether you want to shuffle the data before each iteration. During the training, it is important to shuffle the data so that the model does not learn a specific pattern of the dataset. If the model learns the details of the underlying pattern of the data, it will have difficulty generalizing the prediction for unseen data. This is called overfitting. The model performs well on the training data but cannot predict correctly for unseen data.

TensorFlow makes these two steps easy to do. When the data goes to the pipeline, it knows how many observations it needs (batch) and whether it has to shuffle the data.

To instruct TensorFlow how to feed the model, you can use pandas_input_fn. This object needs five parameters:

  • x: feature data
  • y: label data
  • batch_size: batch. By default 128
  • num_epoch: number of epochs, by default 1
  • shuffle: shuffle the data or not. By default, None

You need to feed the model many times, so you define a function to repeat this process. Call this function get_input_fn.

def get_input_fn(data_set, num_epochs=None, n_batch = 128, shuffle=True):
         return tf.estimator.inputs.pandas_input_fn(
         x=pd.DataFrame({k: data_set[k].values for k in FEATURES}),
         y = pd.Series(data_set[LABEL].values),
         batch_size=n_batch,
         num_epochs=num_epochs,
         shuffle=shuffle)

The usual method to evaluate the performance of a model is to:

  • Train the model
  • Evaluate the model on a different dataset
  • Make a prediction

The TensorFlow estimator provides three different functions to carry out these three steps easily.

Step 4) Train the model

You can use the estimator train method to fit the model. The train estimator needs an input_fn and a number of steps. You can use the function you created above to feed the model. Then you instruct the model to iterate 1000 times. Note that you do not specify the number of epochs; you let the model iterate 1000 times. If you set the number of epochs to 1, then the model will iterate four times, because there are 400 records in the training set and the batch size is 128:

  1. 128 rows
  2. 128 rows
  3. 128 rows
  4. 16 rows

Therefore, it is easier to set the number of epochs to none and define the number of iterations, as shown in the TensorFlow classification example below.

estimator.train(input_fn=get_input_fn(training_set,
                                           num_epochs=None,
                                           n_batch = 128,
                                           shuffle=False),
                                           steps=1000)

Output

INFO:tensorflow:Calling model_fn.
INFO:tensorflow:Done calling model_fn.
INFO:tensorflow:Create CheckpointSaverHook.
INFO:tensorflow:Graph was finalized.
INFO:tensorflow:Running local_init_op.
INFO:tensorflow:Done running local_init_op.
INFO:tensorflow:Saving checkpoints for 1 into train/model.ckpt.
INFO:tensorflow:loss = 83729.64, step = 1
INFO:tensorflow:global_step/sec: 238.616
INFO:tensorflow:loss = 13909.657, step = 101 (0.420 sec)
INFO:tensorflow:global_step/sec: 314.293
INFO:tensorflow:loss = 12881.449, step = 201 (0.320 sec)
INFO:tensorflow:global_step/sec: 303.863
INFO:tensorflow:loss = 12391.541, step = 301 (0.327 sec)
INFO:tensorflow:global_step/sec: 308.782
INFO:tensorflow:loss = 12050.5625, step = 401 (0.326 sec)
INFO:tensorflow:global_step/sec: 244.969
INFO:tensorflow:loss = 11766.134, step = 501 (0.407 sec)
INFO:tensorflow:global_step/sec: 155.966
INFO:tensorflow:loss = 11509.922, step = 601 (0.641 sec)
INFO:tensorflow:global_step/sec: 263.256
INFO:tensorflow:loss = 11272.889, step = 701 (0.379 sec)
INFO:tensorflow:global_step/sec: 254.112
INFO:tensorflow:loss = 11051.9795, step = 801 (0.396 sec)
INFO:tensorflow:global_step/sec: 292.405
INFO:tensorflow:loss = 10845.855, step = 901 (0.341 sec)
INFO:tensorflow:Saving checkpoints for 1000 into train/model.ckpt.
INFO:tensorflow:Loss for final step: 5925.9873.

You can check TensorBoard with the following command:

activate hello-tf
# For MacOS
tensorboard --logdir=./train
# For Windows
tensorboard --logdir=train

Step 5) Evaluate your model

You can evaluate the fit of your model on the test set with the code below:

ev = estimator.evaluate(
          input_fn=get_input_fn(test_set,
          num_epochs=1,
          n_batch = 128,
          shuffle=False))

Output

INFO:tensorflow:Calling model_fn.
INFO:tensorflow:Done calling model_fn.
INFO:tensorflow:Starting evaluation at 2018-05-13-01:43:13
INFO:tensorflow:Graph was finalized.
INFO:tensorflow:Restoring parameters from train/model.ckpt-1000
INFO:tensorflow:Running local_init_op.
INFO:tensorflow:Done running local_init_op.
INFO:tensorflow:Finished evaluation at 2018-05-13-01:43:13
INFO:tensorflow:Saving dict for global step 1000: average_loss = 32.15896, global_step = 1000, loss = 3215.896

You can print the loss with the code below:

loss_score = ev["loss"]
print("Loss: {0:f}".format(loss_score))

Output

Loss: 3215.895996

The model has a loss of 3215. You can check the summary statistics to get an idea of how big the error is.

training_set['medv'].describe()

Output

count    400.000000
mean      22.625500
std        9.572593
min        5.000000
25%       16.600000
50%       21.400000
75%       25.025000
max       50.000000
Name: medv, dtype: float64

From the summary statistic above, you know that the average price for a house is 22 thousand, with a minimum price of 5 thousand and a maximum of 50 thousand. Because the reported loss is the mean squared error, the typical error in the original units is roughly the square root of 32.16, which is about 5.7 thousand dollars.

Step 6) Make the prediction

Finally, you can use the estimator TensorFlow predict method to estimate the value of six Boston houses.

y = estimator.predict(
         input_fn=get_input_fn(prediction_set,
         num_epochs=1,
         n_batch = 128,
         shuffle=False))

To print the estimated values, you can use this code:

predictions = list(p["predictions"] for p in itertools.islice(y, 6))
print("Predictions: {}".format(str(predictions)))

Output

INFO:tensorflow:Calling model_fn.
INFO:tensorflow:Done calling model_fn.
INFO:tensorflow:Graph was finalized.
INFO:tensorflow:Restoring parameters from train/model.ckpt-1000
INFO:tensorflow:Running local_init_op.
INFO:tensorflow:Done running local_init_op.
Predictions: [array([32.297546], dtype=float32), array([18.96125], dtype=float32), array([27.270979], dtype=float32), array([29.299236], dtype=float32), array([16.436684], dtype=float32), array([21.460876], dtype=float32)]

The model forecasts the following values:

House Prediction
1 32.29
2 18.96
3 27.27
4 29.29
5 16.43
6 21.46

Note that we do not know the true value of these six houses. In the deep learning tutorial, you will try to beat the linear model.

NumPy Solution

This section explains how to train the model using a NumPy estimator to feed the data. The method is the same, except that you will use the numpy_input_fn estimator.

Read the same three CSV files, but keep only the raw NumPy arrays with .values.

training_set_n = pd.read_csv("E:/boston_train.csv").values
test_set_n = pd.read_csv("E:/boston_test.csv").values
prediction_set_n = pd.read_csv("E:/boston_predict.csv").values

Step 1) Import the data

First of all, you need to differentiate the feature variables from the label. You need to do this for the training data and the evaluation data. It is faster to define a function to split the data.

def prepare_data(df):
        X_train = df[:, :-3]
        y_train = df[:,-3]
        return X_train, y_train

You can use the function to split the label from the features of the train and evaluate datasets.

X_train, y_train = prepare_data(training_set_n)
X_test, y_test = prepare_data(test_set_n)

You need to exclude the last column of the prediction dataset because it contains only NaN.

x_predict = prediction_set_n[:, :-2]

Confirm the shape of the array. Note that the label should not have a second dimension, which means (400,).

print(X_train.shape, y_train.shape, x_predict.shape)

Output

(400, 9) (400,) (6, 9)

You can construct the feature columns as follows:

feature_columns = [      tf.feature_column.numeric_column('x', shape=X_train.shape[1:])]

The estimator is defined as before: you specify the feature columns and where to save the graph.

estimator = tf.estimator.LinearRegressor(
         feature_columns=feature_columns,
         model_dir="train1")

Output

INFO:tensorflow:Using default config.
INFO:tensorflow:Using config: {'_model_dir': 'train1', '_tf_random_seed': None, '_save_summary_steps': 100, '_save_checkpoints_steps': None, '_save_checkpoints_secs': 600, '_session_config': None, '_keep_checkpoint_max': 5, '_keep_checkpoint_every_n_hours': 10000, '_log_step_count_steps': 100, '_train_distribute': None, '_service': None, '_cluster_spec': <tensorflow.python.training.server_lib.ClusterSpec object at 0x1a218d8f28>, '_task_type': 'worker', '_task_id': 0, '_global_id_in_cluster': 0, '_master': '', '_evaluation_master': '', '_is_chief': True, '_num_ps_replicas': 0, '_num_worker_replicas': 1}

You can use the NumPy estimator to feed the data to the model and then train the model. Note that we define the input_fn function beforehand to ease readability.

# Train the estimator
train_input = tf.estimator.inputs.numpy_input_fn(
           x={"x": X_train},
           y=y_train,
           batch_size=128,
           shuffle=False,
           num_epochs=None)
estimator.train(input_fn = train_input,steps=5000)

Output

INFO:tensorflow:Calling model_fn.
INFO:tensorflow:Done calling model_fn.
INFO:tensorflow:Create CheckpointSaverHook.
INFO:tensorflow:Graph was finalized.
INFO:tensorflow:Running local_init_op.
INFO:tensorflow:Done running local_init_op.
INFO:tensorflow:Saving checkpoints for 1 into train1/model.ckpt.
INFO:tensorflow:loss = 83729.64, step = 1
INFO:tensorflow:global_step/sec: 490.057
INFO:tensorflow:loss = 13909.656, step = 101 (0.206 sec)
INFO:tensorflow:global_step/sec: 788.986
INFO:tensorflow:loss = 12881.45, step = 201 (0.126 sec)
INFO:tensorflow:global_step/sec: 736.339
INFO:tensorflow:loss = 12391.541, step = 301 (0.136 sec)
INFO:tensorflow:global_step/sec: 383.305
INFO:tensorflow:loss = 12050.561, step = 401 (0.260 sec)
INFO:tensorflow:global_step/sec: 859.832
INFO:tensorflow:loss = 11766.133, step = 501 (0.117 sec)
INFO:tensorflow:global_step/sec: 804.394
INFO:tensorflow:loss = 11509.918, step = 601 (0.125 sec)
INFO:tensorflow:global_step/sec: 753.059
INFO:tensorflow:loss = 11272.891, step = 701 (0.134 sec)
INFO:tensorflow:global_step/sec: 402.165
INFO:tensorflow:loss = 11051.979, step = 801 (0.248 sec)
INFO:tensorflow:global_step/sec: 344.022
INFO:tensorflow:loss = 10845.854, step = 901 (0.288 sec)
INFO:tensorflow:Saving checkpoints for 1000 into train1/model.ckpt.
INFO:tensorflow:Loss for final step: 5925.985.
Out[23]:
<tensorflow.python.estimator.canned.linear.LinearRegressor at 0x1a1b6ea860>

You replicate the same step with a different input function to evaluate your model.

eval_input = tf.estimator.inputs.numpy_input_fn(
       x={"x": X_test},
       y=y_test,
       shuffle=False,
       batch_size=128,
       num_epochs=1)
   estimator.evaluate(eval_input,steps=None)

Output

INFO:tensorflow:Calling model_fn.
INFO:tensorflow:Done calling model_fn.
INFO:tensorflow:Starting evaluation at 2018-05-13-01:44:00
INFO:tensorflow:Graph was finalized.
INFO:tensorflow:Restoring parameters from train1/model.ckpt-1000
INFO:tensorflow:Running local_init_op.
INFO:tensorflow:Done running local_init_op.
INFO:tensorflow:Finished evaluation at 2018-05-13-01:44:00
INFO:tensorflow:Saving dict for global step 1000: average_loss = 32.158947, global_step = 1000, loss = 3215.8945
Out[24]:
{'average_loss': 32.158947, 'global_step': 1000, 'loss': 3215.8945}

Finally, you can compute the prediction. It should be similar to the Pandas result.

test_input = tf.estimator.inputs.numpy_input_fn(
        x={"x": x_predict},
        batch_size=128,
        num_epochs=1,
        shuffle=False)
        y = estimator.predict(test_input)

predictions = list(p["predictions"] for p in itertools.islice(y, 6))
print("Predictions: {}".format(str(predictions)))

Output

INFO:tensorflow:Calling model_fn.
INFO:tensorflow:Done calling model_fn.
INFO:tensorflow:Graph was finalized.
INFO:tensorflow:Restoring parameters from train1/model.ckpt-1000
INFO:tensorflow:Running local_init_op.
INFO:tensorflow:Done running local_init_op.
Predictions: [array([32.297546], dtype=float32), array([18.961248], dtype=float32), array([27.270979], dtype=float32), array([29.299242], dtype=float32), array([16.43668], dtype=float32), array([21.460878], dtype=float32)]

TensorFlow Solution

The last section is dedicated to a pure TensorFlow solution. This method is slightly more complicated than the other two.

Note that if you use a Jupyter notebook, you need to restart and clear the kernel to run this session.

TensorFlow has built a great tool to pass the data into the pipeline. In this section, you will build the input_fn function by yourself.

Step 1) Define the path and the format of the data

First of all, you declare two variables with the path of the CSV files. Note that you have two files, one for the training set and one for the testing set.

import tensorflow as tf
df_train = "E:/boston_train.csv"
df_eval = "E:/boston_test.csv"

Then you need to define the columns you want to use from the CSV file. We will use all of them. After that, you need to declare the type of each variable.

Float variables are defined by [0.]

COLUMNS = ["crim", "zn", "indus", "nox", "rm", "age",
                "dis", "tax", "ptratio", "medv"]
RECORDS_ALL = [[0.0], [0.0], [0.0], [0.0],[0.0],[0.0],[0.0],[0.0],[0.0],[0.0]]

Step 2) Define the input_fn function

The function can be broken into three parts:

  1. Import the data
  2. Create the iterator
  3. Consume the data

Below is the overall code to define the function. The code will be explained afterwards.

def input_fn(data_file, batch_size, num_epoch = None):
       # Step 1
          def parse_csv(value):
          columns = tf.decode_csv(value, record_defaults= RECORDS_ALL)
          features = dict(zip(COLUMNS, columns))
          #labels = features.pop('median_house_value')
          labels =  features.pop('medv')
          return features, labels

          # Extract lines from input files using the Dataset API.
          dataset = (tf.data.TextLineDataset(data_file) # Read text file
          .skip(1) # Skip header row
          .map(parse_csv))

          dataset = dataset.repeat(num_epoch)
          dataset = dataset.batch(batch_size)
          # Step 3
          iterator = dataset.make_one_shot_iterator()
          features, labels = iterator.get_next()
          return features, labels

Import the data

For a CSV file, the dataset method reads one line at a time. To build the dataset, you need to use the object TextLineDataset. Your dataset has a header, so you need to use skip(1) to skip the first line. At this point, you only read the data and exclude the header in the pipeline. To feed the model, you need to separate the features from the label. The method used to apply any transformation to the data is map.

This method calls a function that you will create in order to instruct how to transform the data. In a nutshell, you need to pass the data into the TextLineDataset object, exclude the header, and apply a transformation which is instructed by a function.

Code explanation

  • tf.data.TextLineDataset(data_file): this line reads the CSV file
  • .skip(1): skips the header
  • .map(parse_csv)): parses the records into the tensors

You need to define a function to instruct the map object. You can call this function parse_csv.

This function parses the CSV file with the method tf.decode_csv and declares the features and the label. The features can be declared as a dictionary or a tuple. You use the dictionary method because it is more convenient.

Code explanation

  • tf.decode_csv(value, record_defaults= RECORDS_ALL): the method decode_csv uses the output of the TextLineDataset to read the CSV file. record_defaults instructs TensorFlow about the column types. In TensorFlow 2.x this symbol lives at tf.io.decode_csv.
  • dict(zip(COLUMNS, columns)): populates the dictionary with all the columns extracted during this data processing
  • features.pop(‘medv’): excludes the target variable from the feature variables and creates a label variable

The Dataset needs further elements to iteratively feed the tensors. Indeed, you need to add the method repeat to allow the dataset to continue indefinitely to feed the model. If you do not add the method, the model will iterate only one time and then throw an error because no more data is fed into the pipeline.

After that, you can control the batch size with the batch method. It means you tell the dataset how much data you want to pass into the pipeline for each iteration. If you set a big batch size, the model will be slow.

Step 3) Create the iterator

Now you are ready for the second step: create an iterator to return the elements in the dataset.

The simplest way of creating an operator is with the method make_one_shot_iterator.

After that, you can create the features and labels from the iterator.

Step 4) Consume the data

You can check what happens with the input_fn function. You need to call the function in a session to consume the data. You try with a batch size equal to 1.

Note that it prints the features in a dictionary and the label as an array.

It will show the first line of the CSV file. You can try to run this code many times with different batch sizes.

next_batch = input_fn(df_train, batch_size = 1, num_epoch = None)
with tf.Session() as sess:
     first_batch  = sess.run(next_batch)
     print(first_batch)

Output

({'crim': array([2.3004], dtype=float32), 'zn': array([0.], dtype=float32), 'indus': array([19.58], dtype=float32), 'nox': array([0.605], dtype=float32), 'rm': array([6.319], dtype=float32), 'age': array([96.1], dtype=float32), 'dis': array([2.1], dtype=float32), 'tax': array([403.], dtype=float32), 'ptratio': array([14.7], dtype=float32)}, array([23.8], dtype=float32))

Step 5) Define the feature column

You need to define the numeric columns as follows:

X1= tf.feature_column.numeric_column('crim')
X2= tf.feature_column.numeric_column('zn')
X3= tf.feature_column.numeric_column('indus')
X4= tf.feature_column.numeric_column('nox')
X5= tf.feature_column.numeric_column('rm')
X6= tf.feature_column.numeric_column('age')
X7= tf.feature_column.numeric_column('dis')
X8= tf.feature_column.numeric_column('tax')
X9= tf.feature_column.numeric_column('ptratio')

Note that you need to combine all the variables in a bucket.

base_columns = [X1, X2, X3,X4, X5, X6,X7, X8, X9]

Step 6) Build the model

You can train the model with the estimator LinearRegressor.

model = tf.estimator.LinearRegressor(feature_columns=base_columns, model_dir='train3')

Output

INFO:tensorflow:Using default config. INFO:tensorflow:Using config: {'_model_dir': 'train3', '_tf_random_seed': None, '_save_summary_steps': 100, '_save_checkpoints_steps': None, '_save_checkpoints_secs': 600, '_session_config': None, '_keep_checkpoint_max': 5, '_keep_checkpoint_every_n_hours': 10000, '_log_step_count_steps': 100, '_train_distribute': None, '_service': None, '_cluster_spec': <tensorflow.python.training.server_lib.ClusterSpec object at 0x1820a010f0>, '_task_type': 'worker', '_task_id': 0, '_global_id_in_cluster': 0, '_master': '', '_evaluation_master': '', '_is_chief': True, '_num_ps_replicas': 0, '_num_worker_replicas': 1}

You need to use a lambda function to allow you to write the arguments for the function input_fn. If you do not use a lambda function, you cannot train the model.

# Train the estimator
model.train(steps =1000,
          input_fn= lambda : input_fn(df_train,batch_size=128, num_epoch = None))

Output

INFO:tensorflow:Calling model_fn.
INFO:tensorflow:Done calling model_fn.
INFO:tensorflow:Create CheckpointSaverHook.
INFO:tensorflow:Graph was finalized.
INFO:tensorflow:Running local_init_op.
INFO:tensorflow:Done running local_init_op.
INFO:tensorflow:Saving checkpoints for 1 into train3/model.ckpt.
INFO:tensorflow:loss = 83729.64, step = 1
INFO:tensorflow:global_step/sec: 72.5646
INFO:tensorflow:loss = 13909.657, step = 101 (1.380 sec)
INFO:tensorflow:global_step/sec: 101.355
INFO:tensorflow:loss = 12881.449, step = 201 (0.986 sec)
INFO:tensorflow:global_step/sec: 109.293
INFO:tensorflow:loss = 12391.541, step = 301 (0.915 sec)
INFO:tensorflow:global_step/sec: 102.235
INFO:tensorflow:loss = 12050.5625, step = 401 (0.978 sec)
INFO:tensorflow:global_step/sec: 104.656
INFO:tensorflow:loss = 11766.134, step = 501 (0.956 sec)
INFO:tensorflow:global_step/sec: 106.697
INFO:tensorflow:loss = 11509.922, step = 601 (0.938 sec)
INFO:tensorflow:global_step/sec: 118.454
INFO:tensorflow:loss = 11272.889, step = 701 (0.844 sec)
INFO:tensorflow:global_step/sec: 114.947
INFO:tensorflow:loss = 11051.9795, step = 801 (0.870 sec)
INFO:tensorflow:global_step/sec: 111.484
INFO:tensorflow:loss = 10845.855, step = 901 (0.897 sec)
INFO:tensorflow:Saving checkpoints for 1000 into train3/model.ckpt.
INFO:tensorflow:Loss for final step: 5925.9873.
Out[8]:
<tensorflow.python.estimator.canned.linear.LinearRegressor at 0x18225eb8d0>

You can evaluate the fit of your model on the test set with the code below:

results = model.evaluate(steps =None,input_fn=lambda: input_fn(df_eval, batch_size =128, num_epoch = 1))
for key in results:
print("   {}, was: {}".format(key, results[key]))

Output

INFO:tensorflow:Calling model_fn.
INFO:tensorflow:Done calling model_fn.
INFO:tensorflow:Starting evaluation at 2018-05-13-02:06:02
INFO:tensorflow:Graph was finalized.
INFO:tensorflow:Restoring parameters from train3/model.ckpt-1000
INFO:tensorflow:Running local_init_op.
INFO:tensorflow:Done running local_init_op.
INFO:tensorflow:Finished evaluation at 2018-05-13-02:06:02
INFO:tensorflow:Saving dict for global step 1000: average_loss = 32.15896, global_step = 1000, loss = 3215.896
   average_loss, was: 32.158958435058594
   loss, was: 3215.89599609375
   global_step, was: 1000

The last step is predicting the value of the target based on the value of the feature matrix. You can write a dictionary with the values you want to predict. Your model has nine features, so you need to provide a value for each. The model will provide a prediction for each of them.

In the code below, you write the values of each feature that is contained in the df_predict CSV file.

You need to write a new input_fn function because there is no label in the dataset. You can use the from_tensors API from the Dataset object.

prediction_input = {
          'crim': [0.03359,5.09017,0.12650,0.05515,8.15174,0.24522],
          'zn': [75.0,0.0,25.0,33.0,0.0,0.0],
          'indus': [2.95,18.10,5.13,2.18,18.10,9.90],
          'nox': [0.428,0.713,0.453,0.472,0.700,0.544],
          'rm': [7.024,6.297,6.762,7.236,5.390,5.782],
          'age': [15.8,91.8,43.4,41.1,98.9,71.7],
          'dis': [5.4011,2.3682,7.9809,4.0220,1.7281,4.0317],
          'tax': [252,666,284,222,666,304],
          'ptratio': [18.3,20.2,19.7,18.4,20.2,18.4]
     }
     def test_input_fn():
     dataset = tf.data.Dataset.from_tensors(prediction_input)
     return dataset

     # Predict all our prediction_input
     pred_results = model.predict(input_fn=test_input_fn)

Finally, you print the predictions.

for pred in enumerate(pred_results):
print(pred)

Output

INFO:tensorflow:Calling model_fn.
INFO:tensorflow:Done calling model_fn.
INFO:tensorflow:Graph was finalized.
INFO:tensorflow:Restoring parameters from train3/model.ckpt-1000
INFO:tensorflow:Running local_init_op.
INFO:tensorflow:Done running local_init_op.
(0, {'predictions': array([32.297546], dtype=float32)})
(1, {'predictions': array([18.96125], dtype=float32)})
(2, {'predictions': array([27.270979], dtype=float32)})
(3, {'predictions': array([29.299236], dtype=float32)})
(4, {'predictions': array([16.436684], dtype=float32)})
(5, {'predictions': array([21.460876], dtype=float32)})

INFO:tensorflow:Calling model_fn. INFO:tensorflow:Done calling model_fn. INFO:tensorflow:Graph was finalized. INFO:tensorflow:Restoring parameters from train3/model.ckpt-5000 INFO:tensorflow:Running local_init_op. INFO:tensorflow:Done running local_init_op. (0, {'predictions': array([35.60663], dtype=float32)}) (1, {'predictions': array([22.298521], dtype=float32)}) (2, {'predictions': array([25.74533], dtype=float32)}) (3, {'predictions': array([35.126694], dtype=float32)}) (4, {'predictions': array([17.94416], dtype=float32)}) (5, {'predictions': array([22.606628], dtype=float32)})

All three pipelines return the same six predictions, which confirms that the choice between Pandas, NumPy and a native TensorFlow dataset is a matter of convenience, not of accuracy.

FAQs

No. TensorFlow marked Estimators and feature columns fully deprecated in release 2.12 and dropped them in 2.16. Pin TensorFlow 1.15 or 2.15 to run this code unchanged, or rewrite the model with Keras layers, which the TensorFlow team now recommends.

Load the CSV files with Pandas, scale the nine features with a Normalization layer, then stack a single Dense(1) unit. Compile with an optimizer and mean_squared_error loss, then call fit. One Dense unit without activation is a linear regression.

Start around 0.01 and adjust by factors of ten. A rate that is too small needs far more iterations to converge, while a rate that is too large makes the loss oscillate. Plot the loss curve and keep the largest rate that still falls smoothly.

scikit-learn removed load_boston in version 1.2 over ethical concerns about an engineered racial variable. This tutorial reads plain CSV files, so the download link still works, but new projects should use the California housing or Ames housing datasets instead.

Root Mean Square Error restores the original units, Mean Absolute Error resists outliers, and R-squared reports the share of variance explained. Report an absolute-error metric alongside R-squared, because a high R-squared can still hide large individual prediction errors.

Linear regression predicts a continuous number, such as a house price. A linear classifier predicts a discrete class label. Both fit a weighted sum of the features, but the classifier passes that sum through a decision threshold.

Automated pipelines score features with Lasso regularisation, mutual information, or permutation importance, then drop the weakest ones. AutoML tools search preprocessing and model options together, so you spend less time hand-picking which columns belong in feature_cols.

Copilot drafts boilerplate quickly, including input functions, feature-column lists, and evaluation loops. Treat every suggestion as a draft, because it frequently emits deprecated Estimator calls. Check each generated symbol against the current TensorFlow API before you run it.

Summarize this post with: