<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 <a href="https
Step1:  Regression with TensorFlow
We have trained a linear regression model in TensorFlow and used it to predict housing prices. However, the model didn't perform as well as we would have liked it to. In this lab, we will build a neural network to try to tackle the same regression problem and see if we can get better results.
Loading and Preparing the Data
The dataset we'll use for this Colab contains California housing information taken from the 1990 census data. We explored this data in a previous lab, so we won't do an analysis here. As a reminder, the documentation for the dataset can be found on Kaggle.
Upload your kaggle.json file and run the code block below.
Step2:  Once you are done, use the kaggle command to download the file into the lab.
Step3:  We now have a file called california-housing-prices.zip that we can load into a DataFrame.
Step4:  Next we can define which columns are features and which is the target.
We'll also make a separate list of our numeric columns.
Step5:  We also reduced the value of our targets by a factor in the previous lab. This reduction in magnitude was done to help the model train faster. Let's do that again.
Step6:  And we filled in some missing total_bedrooms values.
Step7:  Exercise 1
Step8:  One-Hot Encoding
The ocean_proximity column will not work with the neural network model that we are planning to build. Neural networks expect numeric values, but ocean_proximity contains string values.
Let's remind ourselves which values it contains
Step9:  There are five string values. In our linear regression Colab we told TensorFlow to treat these values as a categorical column. Each string was converted to a whole number that represented their position in a vocabulary list
Step10:  Exercise 2
Step11:  Building the Model
We will build the model using TensorFlow 2. Let's enable it and go ahead and load up TensorFlow.
Step12:  When we built a TensorFlow LinearRegressor in a previous lab, we were using a pre-configured model. For our neural network regressor, we will build the model ourselves using the Keras API of TensorFlow.
We'll build a sequential model where one layer feeds into the next. Each layer will be densely connected, which means every node in one layer connects to every node in the next layer.
A few things are required for our network. We need to have 13 input nodes since that is the number of features that we have (8 original numerical columns, plus the 5 one-hot encoded ocean proximity columns that we added). We also need to have one output node since we are trying to predict a single price value.
Let's see what that would look like
Step13:  Above we have basically recreated our linear regression from an earlier lab. We have all of our inputs directly mapping to a single output. We didn't choose an activation function, and the default activation function for a Dense layer is a linear function $f(x) = x$.
Note that the way we built this model was pretty verbose. You typically see simple models like this built in a more compact manner
Step14:  Also notice that the layers are named dense_1, dense_2, etc.
If you don't supply a name for a layer, TensorFlow will provide a name for you. In small models, this isn't a problem, but you might want to have a meaningful layer name in larger models.
Even in simple models, is dense_2 a good name for the first layer in a model?
Exercise 3
Step15:  Which class did the parameter that you used originate from?
Your answer goes here
Making a Deep Neural Network
Where neural networks really get powerful is when you add hidden layers. These hidden layers can find complex patterns in your data.
Let's create a model with a few hidden layers. We'll add two layers with sixty-four nodes each.
Step16:  We now have a deep neural network model. The model has 13 input nodes. These nodes feed into our first hidden layer of 64 nodes.
The first line of our model summary tells us that we have 64 nodes and 896 parameters. The node count in 'Output Shape' makes sense, but what about the 'Param #' of 896?
Remember that we have 13 input nodes feeding into 64 nodes in our first hidden layer. The layers are densely connected, so each of the 13 input nodes connects to each of the 64 nodes in the next layer. 13 * 64 = 832 connections. Add another 64 for the number of nodes in the layer, and you get the 896 number.
This pattern repeats for the next layer. 64 nodes connecting to 64 nodes
Step17:  Training the Model
We can now train the model using the fit() method. Training is performed for a specified number of epochs. An epoch is a full pass over the training data. In this case, we are asking to train over the full dataset 50 times.
In order to get the data into the model, we don't have to write an input function like we did with the Estimator API. The Keras API provides for a much more direct format.
Step18:  Validating the Model
We can now see how well our model performs on our validation test set. In order to get the model to make predictions, we use the predict method.
Step19:  Notice that the predictions are lists of lists. This is because neural networks can return more than one prediction per input. We set this network up to have a single final node, but could have had more.
Exercise 4
Step20:  Improving the Model
In the exercise above, you likely got a root mean squared error very close to the error we got in the linear regression lab. What's going on? I thought deep learning models were supposed to be really, really good!
Deep learning models can be really good, but they often require a bit of hyperparameter tuning. Aside from the breadth and depth of the hidden layers, the activation function for the model can have a big impact on how a model performs.
Earlier we mentioned that the default activation function for Dense layers is the linear function $f(x) = x$. It turns out that if you stack layers of linear functions, you just get a single linear function, so the network that we built is basically just one big linear regression.
We can change the activation function layer by layer for our model. In order to do that, we just pass an activation argument to our Dense class. Keras has many built-in activations that you can reference by name like
Step21:  Visualizing Training
At this point, we have a pretty solid neural network regression model. It performs better than our linear regression model, though it does take a while to train.
Training time is largely a product of two factors
Step22:  Notice that the history.history contains our model's loss (loss), mean absolute error (mae), mean squared error (mse), validation loss (val_loss), validation mean absolute error (val_mae), and validation mean squared error (val_mse) at each epoch.
It would be useful to plot the error over time. In the next exercise, you will create a visualization that will help us determine when to stop training the model.
Exercise 6
Step23:  Student Solution
Step24:  Interpreting Loss Visualizations
We have now created a visualization that should look something like this
<ASSISTANT_TASK:>
Python Code:
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
Explanation: <a href="https://colab.research.google.com/github/google/applied-machine-learning-intensive/blob/master/content/03_regression/08_regression_with_tensorflow/colab.ipynb" target="_parent"><img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open In Colab"/></a>
Copyright 2020 Google LLC.
End of explanation
! chmod 600 kaggle.json && (ls ~/.kaggle 2>/dev/null || mkdir ~/.kaggle) && mv kaggle.json ~/.kaggle/ && echo 'Done'
Explanation: Regression with TensorFlow
We have trained a linear regression model in TensorFlow and used it to predict housing prices. However, the model didn't perform as well as we would have liked it to. In this lab, we will build a neural network to try to tackle the same regression problem and see if we can get better results.
Loading and Preparing the Data
The dataset we'll use for this Colab contains California housing information taken from the 1990 census data. We explored this data in a previous lab, so we won't do an analysis here. As a reminder, the documentation for the dataset can be found on Kaggle.
Upload your kaggle.json file and run the code block below.
End of explanation
!kaggle datasets download camnugent/california-housing-prices
!ls
Explanation: Once you are done, use the kaggle command to download the file into the lab.
End of explanation
import pandas as pd
housing_df = pd.read_csv('california-housing-prices.zip')
housing_df
Explanation: We now have a file called california-housing-prices.zip that we can load into a DataFrame.
End of explanation
target_column = 'median_house_value'
feature_columns = [c for c in housing_df.columns if c != target_column]
numeric_feature_columns = [c for c in feature_columns if c != 'ocean_proximity']
target_column, feature_columns, numeric_feature_columns
Explanation: Next we can define which columns are features and which is the target.
We'll also make a separate list of our numeric columns.
End of explanation
TARGET_FACTOR = 100000
housing_df[target_column] /= TARGET_FACTOR
housing_df[target_column].describe()
Explanation: We also reduced the value of our targets by a factor in the previous lab. This reduction in magnitude was done to help the model train faster. Let's do that again.
End of explanation
has_all_data = housing_df[~housing_df['total_bedrooms'].isna()]
sums = has_all_data[['total_bedrooms', 'total_rooms']].sum().tolist()
bedrooms_to_total_rooms_ratio = sums[0] / sums[1]
missing_total_bedrooms_idx = housing_df['total_bedrooms'].isna()
housing_df.loc[missing_total_bedrooms_idx, 'total_bedrooms'] = housing_df[
    missing_total_bedrooms_idx]['total_rooms'] * bedrooms_to_total_rooms_ratio
housing_df.describe()
Explanation: And we filled in some missing total_bedrooms values.
End of explanation
# Your Code Goes Here
Explanation: Exercise 1: Standardization
Previously when we worked with this dataset, we normalized the feature data in order to get it ready for the model. Normalization was the process of making all of the data fit between 0.0 and 1.0 by subtracting the minimum of each column from each data point in that column and then dividing by the delta between the maximum and minimum values.
In this exercise you will need to standardize all of the feature columns. Standardization is performed by subtracting the mean value of each column from each data point in that column and then dividing by the standard deviation.
Hint: When you are done call describe() and ensure that the standard deviation for every feature column is 1.0`
Student Solution
End of explanation
sorted(housing_df['ocean_proximity'].unique())
Explanation: One-Hot Encoding
The ocean_proximity column will not work with the neural network model that we are planning to build. Neural networks expect numeric values, but ocean_proximity contains string values.
Let's remind ourselves which values it contains:
End of explanation
for op in sorted(housing_df['ocean_proximity'].unique()):
  op_col = op.lower().replace(' ', '_').replace('<', '')
  housing_df[op_col] = (housing_df['ocean_proximity'] == op).astype(int)
  feature_columns.append(op_col)
feature_columns.remove('ocean_proximity')
housing_df
Explanation: There are five string values. In our linear regression Colab we told TensorFlow to treat these values as a categorical column. Each string was converted to a whole number that represented their position in a vocabulary list: 0, 1, 2, 3, or 4.
For neural networks it is common to see another strategy called one-hot encoding. One-hot encoding is the process of taking a column with a fixed list of string values and turning it into multiple columns containing only zeros and ones.
For instance the column ocean_proximity containing five strings would be converted to five columns containing ones and zeros:
op_sub_hr | op_inland | op_island | op_near_bay | op_near_ocean
----------|-----------|-----------|-------------|--------------
 0        | 0         | 0         | 1           | 0
 0        | 1         | 0         | 0           | 0
 0        | 1         | 0         | 0           | 0
 1        | 0         | 0         | 0           | 0
 0        | 0         | 1         | 0           | 0
 0        | 0         | 0         | 0           | 1
 0        | 0         | 1         | 0           | 0
Notice that in each row, only one column has a value of 1. The rest are all 0. This is the "one-hot" in one-hot encoding.
As you can imagine, it doesn't scale well for columns with many distinct values. In our case, 5 is perfectly reasonable.
Let's manually one-hot encode our data.
End of explanation
# Your Code Goes Here
Explanation: Exercise 2: Split the Data
We want to hold out some of the data for validation. Using standard Python or a library, split the data. Put 20% of the data in a DataFrame called testing_df and the other 80% in a DataFrame called training_df. Be sure to shuffle the data before splitting. Print the number of records in testing_df and training_df in order to check your work.
Student Solution
End of explanation
%tensorflow_version 2.x
import tensorflow as tf
tf.__version__
Explanation: Building the Model
We will build the model using TensorFlow 2. Let's enable it and go ahead and load up TensorFlow.
End of explanation
from tensorflow import keras
from tensorflow.keras import layers
# Create the Sequential model.
model = keras.Sequential()
# Determine the "input shape", which is the number
# of features that we will feed into the model.
input_shape = len(feature_columns)
# Create a layer that accepts our features and outputs
# a single value, the predicted median home price.
layer = layers.Dense(1, input_shape=[input_shape])
# Add the layer to our model.
model.add(layer)
# Print out a model summary.
model.summary()
Explanation: When we built a TensorFlow LinearRegressor in a previous lab, we were using a pre-configured model. For our neural network regressor, we will build the model ourselves using the Keras API of TensorFlow.
We'll build a sequential model where one layer feeds into the next. Each layer will be densely connected, which means every node in one layer connects to every node in the next layer.
A few things are required for our network. We need to have 13 input nodes since that is the number of features that we have (8 original numerical columns, plus the 5 one-hot encoded ocean proximity columns that we added). We also need to have one output node since we are trying to predict a single price value.
Let's see what that would look like:
End of explanation
from tensorflow import keras
from tensorflow.keras import layers
model = keras.Sequential(layers=[
    layers.Dense(1, input_shape=[len(feature_columns)])
])
model.summary()
Explanation: Above we have basically recreated our linear regression from an earlier lab. We have all of our inputs directly mapping to a single output. We didn't choose an activation function, and the default activation function for a Dense layer is a linear function $f(x) = x$.
Note that the way we built this model was pretty verbose. You typically see simple models like this built in a more compact manner:
End of explanation
from tensorflow import keras
from tensorflow.keras import layers
model = keras.Sequential(layers=[
    layers.Dense(
        1,
        input_shape=[len(feature_columns)],
        # Name your layer here
    )
])
model.summary()
Explanation: Also notice that the layers are named dense_1, dense_2, etc.
If you don't supply a name for a layer, TensorFlow will provide a name for you. In small models, this isn't a problem, but you might want to have a meaningful layer name in larger models.
Even in simple models, is dense_2 a good name for the first layer in a model?
Exercise 3: Name Your Layers
The default naming scheme for layers can start to become confusing, especially if you repeatedly run a cell block to iterate on your model design.
In this exercise consult the Dense documentation and find the argument that allows you to name your layer. Use that argument in the code below to name your layer 'the_only_layer'. Note that you might have to consult the documentation for the parent classes of Dense.
Also, don't forget to answer the question below the code block!
Student Solution
End of explanation
from tensorflow import keras
from tensorflow.keras import layers
feature_count = len(feature_columns)
model = keras.Sequential([
  layers.Dense(64, input_shape=[feature_count]),
  layers.Dense(64),
  layers.Dense(1)
])
model.summary()
Explanation: Which class did the parameter that you used originate from?
Your answer goes here
Making a Deep Neural Network
Where neural networks really get powerful is when you add hidden layers. These hidden layers can find complex patterns in your data.
Let's create a model with a few hidden layers. We'll add two layers with sixty-four nodes each.
End of explanation
model.compile(
  loss='mse',
  optimizer='Adam',
  metrics=['mae', 'mse'],
)
model.summary()
Explanation: We now have a deep neural network model. The model has 13 input nodes. These nodes feed into our first hidden layer of 64 nodes.
The first line of our model summary tells us that we have 64 nodes and 896 parameters. The node count in 'Output Shape' makes sense, but what about the 'Param #' of 896?
Remember that we have 13 input nodes feeding into 64 nodes in our first hidden layer. The layers are densely connected, so each of the 13 input nodes connects to each of the 64 nodes in the next layer. 13 * 64 = 832 connections. Add another 64 for the number of nodes in the layer, and you get the 896 number.
This pattern repeats for the next layer. 64 nodes connecting to 64 nodes: 64 * 64 + 64 = 4160.
And finally 64 nodes connect to the final output node: 64 * 1 + 1 = 65.
This makes for a total of 5121 parameters in the model. Even a very small neural network like this can have a lot of trainable parameters inside of it!
Before we start training it, we need to tell TensorFlow how and what to optimize the model for using the compile method. In our example below, we are optimizing for mean squared error using the Adam optimizer.  We'll calculate and report the mean squared error and mean absolute error along the way.
End of explanation
EPOCHS = 50
model.fit(
  training_df[feature_columns],
  training_df[target_column],
  epochs=EPOCHS,
  validation_split=0.2,
)
Explanation: Training the Model
We can now train the model using the fit() method. Training is performed for a specified number of epochs. An epoch is a full pass over the training data. In this case, we are asking to train over the full dataset 50 times.
In order to get the data into the model, we don't have to write an input function like we did with the Estimator API. The Keras API provides for a much more direct format.
End of explanation
predictions = model.predict(testing_df[feature_columns])
predictions
Explanation: Validating the Model
We can now see how well our model performs on our validation test set. In order to get the model to make predictions, we use the predict method.
End of explanation
# Your Code Goes here
Explanation: Notice that the predictions are lists of lists. This is because neural networks can return more than one prediction per input. We set this network up to have a single final node, but could have had more.
Exercise 4: Calculating RMSE
At this point we have the predicted values from our test features and the actual values. In this exercise you are tasked with computing the root-mean squared error of those predictions. Given the predictions stored in predictions above, write code that computes the root mean squared error of those predictions vs. the truth found in testing_df. Print the root mean squared error.
Student Solution
End of explanation
# Your Code Goes Here
Explanation: Improving the Model
In the exercise above, you likely got a root mean squared error very close to the error we got in the linear regression lab. What's going on? I thought deep learning models were supposed to be really, really good!
Deep learning models can be really good, but they often require a bit of hyperparameter tuning. Aside from the breadth and depth of the hidden layers, the activation function for the model can have a big impact on how a model performs.
Earlier we mentioned that the default activation function for Dense layers is the linear function $f(x) = x$. It turns out that if you stack layers of linear functions, you just get a single linear function, so the network that we built is basically just one big linear regression.
We can change the activation function layer by layer for our model. In order to do that, we just pass an activation argument to our Dense class. Keras has many built-in activations that you can reference by name like:
python
  layers.Dense(64, activation='sigmoid')
For activations that aren't built into Keras, you can use the full path to their class:
python
  layers.Dense(64, activation=tf.nn.swish)
The tf.nn namespace is a little crowded, but there are activations functions in there including swish, leaky_relu, and more.
Exercise 5: A Better Activation Function
Experiment with different activation functions and find one that performs better than the linear activation that we used above. You can set the activation function on any or all of the layers in the network. The functions don't have to be the same.
Print out the root mean squared error once you find an acceptable activation function.
Student Solution
End of explanation
model = keras.Sequential([
  layers.Dense(64, input_shape=[feature_count]),
  layers.Dense(64),
  layers.Dense(1)
])
model.compile(
  loss='mse',
  optimizer='Adam',
  metrics=['mae', 'mse'],
)
EPOCHS = 5
history = model.fit(
  training_df[feature_columns],
  training_df[target_column],
  epochs=EPOCHS,
  verbose=0,                     # New parameter to make model training silent
  validation_split=0.2,
)
history.history
Explanation: Visualizing Training
At this point, we have a pretty solid neural network regression model. It performs better than our linear regression model, though it does take a while to train.
Training time is largely a product of two factors:
The size of the model
The number of epochs
Larger models take longer to train. That shouldn't come as a surprise. Remember from above that we calculated the number of parameters in our model. Every layer that is densely connected adds many more parameters that need to be adjusted during training.
Our goal is to find a model that is big enough, but not too big. This, it turns out, is very much an area where experimentation is required.
The second determination of model training time is the number of epochs. We can choose an arbitrary number of epochs from one to infinity. How many do we need?
It turns out that we can be much more scientific about this parameter. As a model begins to converge, there is less and less benefit for each subsequent epoch.
More training does not necessarily mean a better model.
There are a few ways to determine the appropriate number of epochs. One is to plot the error and see when it flattens out.
It turns out that our model actually returns the error values when you fit the model.
End of explanation
model = keras.Sequential([
  layers.Dense(64, input_shape=[feature_count]),
  layers.Dense(64),
  layers.Dense(1)
])
model.compile(
  loss='mse',
  optimizer='Adam',
  metrics=['mae', 'mse'],
)
EPOCHS = 100
history = model.fit(
  training_df[feature_columns],
  training_df[target_column],
  epochs=EPOCHS,
  verbose=0,
  validation_split=0.2,
)
Explanation: Notice that the history.history contains our model's loss (loss), mean absolute error (mae), mean squared error (mse), validation loss (val_loss), validation mean absolute error (val_mae), and validation mean squared error (val_mse) at each epoch.
It would be useful to plot the error over time. In the next exercise, you will create a visualization that will help us determine when to stop training the model.
Exercise 6: Plotting Error
Use matplotlib.pyplot or seaborn to create a line plot that shows the mean squared error and the validation mean squared error per epoch.
In the code block below, we save the errors per epoch in the variable history. Inspect the variable and plot a line plot which has the epoch on the x-axis and the mean squared error on the y-axis. There should be two lines on the visualization: mean absolute error and validation mean absolute error.
Note that we created the model with the default activation function. Use the activation function that you found to be more useful in exercise 5.
The result should be a line plot of epoch and error with two lines similar to:
End of explanation
# Your Code Goes Here
Explanation: Student Solution
End of explanation
model = keras.Sequential([
  layers.Dense(64, input_shape=[feature_count]),
  layers.Dense(64),
  layers.Dense(1)
])
model.compile(
  loss='mse',
  optimizer='Adam',
  metrics=['mae', 'mse'],
)
EPOCHS = 1000
early_stop = keras.callbacks.EarlyStopping(monitor='val_loss', patience=10)
history = model.fit(
  training_df[feature_columns],
  training_df[target_column],
  epochs=EPOCHS,
  validation_split=0.2,
  callbacks=[early_stop],
)
Explanation: Interpreting Loss Visualizations
We have now created a visualization that should look something like this:
But how do we interpret this visualization?
The blue line is the mean squared error for the training data. You can see it plummeting fast as the model quickly learns.
The orange line is the validation data. This is a holdout set of data that the model checks after each epoch. You can see it dropping pretty quickly, too, but then it seems to stabilize somewhat by 20 epochs.
Toward the right side of the graph, you can see that our validation set says volatile but relatively flat, while our training data set keeps getting better and better.
Should we train more or less?
The constantly reducing blue line is actually a signal of overfitting on the training data.
The flat(ish) orange line signals this model is as good as we can get.
For this model we could possibly stop training after even 25 epochs and get similar performance.
But how do you know when to stop?
Luckily there is an early stopping algorithm that allows a model to stop training when validation data isn't improving.
In the example below, we set up a model to train for 1000 epochs; however, we add an early stopping callback. Early stopping stops training when the model isn't progressing upon validation.
If you run the code block below, you'll see far fewer than 1000 epochs run.
End of explanation
<END_TASK>