A comprehensive introduction to building, training, and deploying neural networks with TensorFlow 2 and Keras.
Table of Contents
- Course Overview
- Why Learn TensorFlow?
- TensorFlow Environment Setup
- AI and Machine Learning Concepts
- Applying the ML Workflow with TensorFlow — House Price Prediction
- Understanding Neural Networks
- Building and Training the First Neural Network
- Monitoring and Improving Performance
- Deploying the Neural Network
- Conclusion and Next Steps
1. Course Overview
This course covers the complete journey to build, train, and deploy a neural network with TensorFlow 2. Here are the main steps:
Getting Started with TensorFlow
↓
Understanding AI and Machine Learning Concepts
↓
Build a Simple Model (house price prediction)
↓
Build a Neural Network (Fashion-MNIST image classification)
↓
Monitor and Improve Performance with TensorBoard
↓
Deploy the Model as a Web Service
Course Content
| Module | Topic | Duration |
|---|---|---|
| 1 | Course Overview | 1m 35s |
| 2 | Why Learn TensorFlow? | 12m 12s |
| 3 | Environment Setup | 16m 50s |
| 4 | AI and Machine Learning Concepts | 20m |
| 5 | ML Workflow Application (house prices) | 29m 35s |
| 6 | Understanding Neural Networks | 25m 7s |
| 7 | Building the First Neural Network | 22m 11s |
| 8 | Monitoring and Improving Performance | 21m 7s |
| 9 | Deploying the Neural Network | 10m 53s |
| 10 | Conclusion | 7m 40s |
2. Why Learn TensorFlow?
What is TensorFlow?
TensorFlow is an open-source machine learning framework accessible to everyone.
TensorFlow is used at the core of many modern AI solutions:
- Voice assistants: Google Home understands context and responds to queries
- Facial recognition: automatic identification of people in images
- Autonomous vehicles: models trained to understand direction changes and analyze sensor data
Why Choose TensorFlow?
mindmap
root((TensorFlow))
Development ease
Intuitive Keras interface
Model creation in a few lines
Connect layers like Lego bricks
Scalability
Local experimentation
Production deployment
Global enterprises
Multi-platform
Cloud data centers
Personal computers
Mobile and IoT devices
Open Source
Source code published daily
Active community
Contributions welcome
The TensorFlow Ecosystem
graph TB
TF_CORE["🧠 TensorFlow Core\n(ML Model Creation)"]
TFX["🏭 TensorFlow Extended (TFX)\n(Production pipelines)"]
TF_JS["🌐 TensorFlow.js\n(Machine Learning in JavaScript)"]
TF_LITE["📱 TensorFlow Lite\n(Mobile and IoT devices)"]
TF_CORE --> TFX
TF_CORE --> TF_JS
TF_CORE --> TF_LITE
style TF_CORE fill:#FF6F00,color:#fff
style TFX fill:#1565C0,color:#fff
style TF_JS fill:#2E7D32,color:#fff
style TF_LITE fill:#6A1B9A,color:#fff
Supported Languages
| Language | Primary usage |
|---|---|
| Python | Main language, most popular in the ML community |
| C++ | High-performance math libraries, IoT |
| JavaScript | TensorFlow.js — client-side and server-side |
| Swift | Strong typing, high performance, safety by design |
Required Skills
What is NOT required:
- Prior experience with TensorFlow
- Advanced Python proficiency
- Advanced math or statistics knowledge
What IS required:
- Basic programming experience (Python, C, C#, Java, etc.)
- Familiarity with data and tables (columns, rows, lists)
- Basic math: sum, mean, median, basic algebra
3. TensorFlow Environment Setup
Development Environment Options
graph LR
A[Developer] --> B{Environment choice}
B --> C[Local installation\nTensorFlow on your machine]
B --> D[Google Colaboratory\nColab - Recommended]
C --> C1[Requires Nvidia GPU configuration]
C --> C2[See tensorflow.org/install]
D --> D1[✅ Free]
D --> D2[✅ No installation required]
D --> D3[✅ GPU/TPU included]
D --> D4[✅ Pre-configured Python + TensorFlow]
D --> D5[✅ Only requirement: Google account]
style D fill:#34A853,color:#fff
style D1 fill:#34A853,color:#fff
style D2 fill:#34A853,color:#fff
style D3 fill:#34A853,color:#fff
style D4 fill:#34A853,color:#fff
style D5 fill:#34A853,color:#fff
What is Google Colaboratory (Colab)?
Google Colab is Google’s enhanced version of the popular Python development environment Jupyter Notebook, running on Google’s servers. It allows you to create hybrid documents containing:
- Executable Python code
- Visualizations
- Text and documentation (Markdown cells)
To get started: colab.research.google.com
Key Jupyter Notebook Concepts
| Concept | Description |
|---|---|
| Code Cell | Contains Python code to execute |
| Text Cell | Markdown documentation |
| Execution | Shift+Enter or click the arrow |
| Execution number | Indicates the order cells were executed |
| Run All | Executes all cells from top to bottom |
| Restart & Run All | Resets state and executes everything |
⚠️ Important: Execution in Jupyter is not necessarily top-to-bottom. The order is determined by which cells were sent to the server, not their position in the notebook.
Importing TensorFlow
# Ensure the correct version of TensorFlow is installed (Colab only)
try:
%tensorflow_version 2.x
except Exception:
pass
# Import essential libraries
import tensorflow as tf # The main framework
import numpy as np # N-dimensional arrays and numerical operations
# Verify versions
print("TensorFlow version:", tf.__version__)
print("NumPy version:", np.__version__)
Setup Summary
1. Create a Google account (free)
2. Go to colab.research.google.com
3. Create a new Python 3 notebook
4. Import TensorFlow and NumPy
5. Verify versions
4. AI and Machine Learning Concepts
Relationship Between AI and ML
graph TD
AI["🤖 Artificial Intelligence\n(Simulation of intelligent behavior)"]
ML["📊 Machine Learning\n(Learning from data)"]
ES["📋 Expert Systems\n(Manually coded rules)"]
NN["🧠 Neural Networks\n(Our focus in this course)"]
AI --> ML
AI --> ES
ML --> NN
style AI fill:#1565C0,color:#fff
style ML fill:#2E7D32,color:#fff
style NN fill:#FF6F00,color:#fff
Machine Learning vs Traditional Programming
| Aspect | Traditional Programming | Machine Learning |
|---|---|---|
| Approach | Expert manually codes explicit rules (if/else) | Model learns rules from data |
| Data | Input for processing | Learning source |
| Rules | Defined by the developer | Learned automatically |
| Improvement | Manual code modification | Retraining with new data |
Definition: Machine Learning is a technique where programs learn from data and improve through experience, without being explicitly programmed.
The Machine Learning Workflow
flowchart TD
A["1️⃣ Define the problem\n'Predict house price\nbased on square footage'"] --> B
B["2️⃣ Obtain data\n(Ames Housing Dataset)"] --> C
C["3️⃣ Prepare data\n• Handle missing values\n• Normalize values\n• Create new columns"] --> D
D["4️⃣ Create the model\n(Network architecture)"] --> E
E["5️⃣ Train the model\n(Training data 70-80%)"] --> F
F["6️⃣ Evaluate the model\n(Test data 20-30%)"] --> G{Acceptable\nperformance?}
G -->|No| C
G -->|Yes| H["✅ Model ready\nfor production"]
style A fill:#1565C0,color:#fff
style B fill:#1565C0,color:#fff
style C fill:#1565C0,color:#fff
style D fill:#2E7D32,color:#fff
style E fill:#2E7D32,color:#fff
style F fill:#FF6F00,color:#fff
style H fill:#34A853,color:#fff
Measuring Loss
Loss is the difference between what the model predicts and the actual value. The goal of training is to minimize this loss.
Mean Squared Error (MSE):
$$\text{MSE} = \frac{1}{n} \sum_{i=1}^{n} (y_i - \hat{y}_i)^2$$
Where:
- $y_i$ = actual value
- $\hat{y}_i$ = predicted value
- $n$ = number of examples
Reducing Loss: Gradient Descent
flowchart LR
A["Initialize weights\n(random values)"] --> B
B["Select a\nrandom mini-batch"] --> C
C["Make predictions\nwith the current model"] --> D
D["Calculate loss\n(MSE, Cross-Entropy...)"] --> E
E["Calculate gradient\n(descent direction)"] --> F
F["Update weights\naccording to learning rate"] --> G{Loss\nconverged?}
G -->|No| B
G -->|Yes| H["✅ Model trained"]
style H fill:#34A853,color:#fff
Mini-batch gradient descent: A variant where the gradient is computed on a small random subset (batch) of training data at each step, rather than the entire dataset.
Tensors
A tensor is an N-dimensional data structure used to represent data in TensorFlow. This is why the library is called TensorFlow — tensors flow through models.
graph LR
R0["Rank 0\nScalar\nShape: []\nEx: 42"]
R1["Rank 1\nVector\nShape: [5]\nEx: [1,2,3,4,5]"]
R2["Rank 2\nMatrix\nShape: [2,3]\nEx: data table"]
R3["Rank 3\n3D Tensor\nShape: [2,2,3]\nEx: data cube"]
R0 --> R1 --> R2 --> R3
Tensor properties:
| Property | Description | Example |
|---|---|---|
| Rank | Number of dimensions | Scalar=0, Vector=1, Matrix=2 |
| Shape | Size of each dimension | [28, 28] for a 28×28 image |
| Data type | Type of values | float32, int64, string |
5. Applying the ML Workflow with TensorFlow — House Price Prediction
Problem Statement
“Using sample data, develop a model that predicts house price based on square footage.”
Dataset used: Ames Housing Dataset (Dean De Cock) — subset from May 2010 (AmesHousing-05-2010.csv)
Step 1 — Obtain and Explore the Data
# Import libraries
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
# Load CSV file (in Google Colab)
from google.colab import files
uploaded = files.upload()
csvHouseFile = next(iter(uploaded.keys()))
print('Uploaded file "{name}" with {length} bytes'.format(
name=csvHouseFile, length=len(uploaded[csvHouseFile])))
# Load into a pandas DataFrame
housingDf = pd.read_csv(csvHouseFile)
# Display first rows
pd.set_option('display.max_columns', None)
housingDf.head(5)
Step 2 — Prepare the Data
Key columns for total square footage:
Total Bsmt SF= BsmtFin SF 1 + BsmtFin SF 2 + Bsmt Unf SFGr Liv Area= 1st Flr SF + 2nd Flr SF- New column:
Total SF= Total Bsmt SF + Gr Liv Area
# Check for missing values
housingDf[['Total Bsmt SF', 'Gr Liv Area']].isnull().values.any()
# >> False (no missing values)
# Create the total square footage column
housingDf['Total SF'] = housingDf['Total Bsmt SF'] + housingDf['Gr Liv Area']
# Verify
print(housingDf[['Total Bsmt SF', 'Gr Liv Area', 'Total SF', 'SalePrice']].head(5))
Data normalization: Square footage ranges from 800–4200 and prices from 80,000 to 400,000. Both need to be scaled to the same range (0.0 to 1.0) to facilitate learning.
from sklearn.preprocessing import MinMaxScaler
# Normalize square footage
sfScaler = MinMaxScaler()
sfScaled = sfScaler.fit_transform(
housingDf['Total SF'].values.reshape(-1,1).astype(np.float64))
# Normalize prices
priceScaler = MinMaxScaler()
priceScaled = priceScaler.fit_transform(
housingDf['SalePrice'].values.reshape(-1,1).astype(np.float64))
Visualizing the area/price relationship:
def visualize_data(x_vals, y_vals, addn_x_vals=None, addn_y_vals=None,
add_addn_reg_line=False):
f, ax = plt.subplots(figsize=(8,8))
plt.plot(x_vals, y_vals, 'ro') # Red points for each data point
if addn_x_vals is not None:
plt.plot(addn_x_vals, addn_y_vals, 'g^') # Green triangles
plt.tick_params(axis='both', which='major', labelsize=14)
plt.show()
# Plot square footage vs price
visualize_data(housingDf['Total SF'], housingDf['SalePrice'])
The visualization shows a linear relationship between square footage and price. This suggests a linear regression model: y = wx + bias
Step 3 — Create the Model
graph LR
INPUT["Input\nSquare footage (x)"] --> NEURON
subgraph NEURON["Single Neuron"]
W["w (weight/slope)"]
B["+ bias"]
EQ["y = wx + bias"]
end
NEURON --> OUTPUT["Output\nPredicted price (y)"]
style INPUT fill:#1565C0,color:#fff
style OUTPUT fill:#2E7D32,color:#fff
# Create the model with Keras — single neuron
model = tf.keras.Sequential()
model.add(tf.keras.layers.Dense(
units=1, # 1 output neuron
activation='linear', # Linear activation (y = wx + b)
input_shape=(1,), # 1 input (square footage)
kernel_initializer='random_uniform', # Random initialization of weight w
bias_initializer='zeros' # Initialize bias to 0
))
Step 4 — Compile the Model
# Compile the model
model.compile(
loss='mean_squared_error', # Loss measure: MSE
optimizer='sgd' # Optimizer: Stochastic Gradient Descent
)
Step 5 — Train the Model
from sklearn.model_selection import train_test_split
# Split data: 70% training, 30% test
sfTrain, sfTest, priceTrain, priceTest = \
train_test_split(sfScaled, priceScaled, test_size=0.3, random_state=42)
# Initial training (8 epochs)
initialEpochs = 8
batchSize = 10
trainHist = model.fit(
sfTrain, priceTrain,
epochs=initialEpochs,
batch_size=batchSize,
verbose=1
)
Loss visualization:
def plot_loss(hist):
plt.title('Loss History')
plt.plot(hist.history['loss'])
plt.ylabel('Loss')
plt.xlabel('Epoch')
plt.show()
plot_loss(trainHist)
# >> Loss is still high → train longer!
Additional training (convergence):
# Train for 1200 additional epochs
addnEpochs = 1200
trainHistAddn = model.fit(
sfTrain, priceTrain,
epochs=addnEpochs, verbose=1)
# Merge histories
trainHist.history['loss'].extend(trainHistAddn.history['loss'])
plot_loss(trainHist)
# >> Loss converges around ~1000 epochs
Step 6 — Evaluate the Model
# Predict on TEST data (never seen during training)
priceTestPredScaled = model.predict(sfTest)
# Calculate MSE on test data
from sklearn.metrics import mean_squared_error
print("Prediction MSE:",
mean_squared_error(priceTest, priceTestPredScaled))
# Visualization: actual data (red) vs predictions (green)
visualize_data(
sfScaler.inverse_transform(sfTest),
priceScaler.inverse_transform(priceTest),
sfScaler.inverse_transform(sfTest),
priceScaler.inverse_transform(priceTestPredScaled)
)
What We Learned
✅ ML = learning relationships in data (vs manually coding rules)
✅ A single neuron can learn the slope and offset of a line
✅ Keras simplifies model creation, training, and evaluation
✅ Data must pass through the model enough times (epochs) for loss to converge
✅ Always evaluate on test data kept separate from training data
6. Understanding Neural Networks
Biological Inspiration
Artificial neural networks are inspired by biological neurons in the brain:
- The human brain contains ~86 billion interconnected neurons
- Neurons receive input signals, process them, and transmit the result
Architecture of an Artificial Neuron
graph LR
I1["x₁"] -->|"w₁"| SUM
I2["x₂"] -->|"w₂"| SUM
I3["x₃"] -->|"w₃"| SUM
IN["..."] -->|"wₙ"| SUM
BIAS["bias"] --> SUM
subgraph NEURON["Neuron"]
SUM["Σ(xᵢ·wᵢ) + bias"]
AF["Activation function\nf(z)"]
SUM --> AF
end
AF --> OUTPUT["Output y"]
style SUM fill:#1565C0,color:#fff
style AF fill:#FF6F00,color:#fff
style OUTPUT fill:#2E7D32,color:#fff
Neuron equation:
$$y = f\left(\sum_{i} x_i \cdot w_i + \text{bias}\right)$$
Where:
- $x_i$ = input values (pixels, features…)
- $w_i$ = learnable weights (the importance of each input)
- $\text{bias}$ = learned offset
- $f$ = activation function
Role of weights:
- $w = 0$ → the input has no effect
- Large $w$ → the input has a significant effect
- Negative $w$ → the input has a negative effect on the output
Activation Functions
Activation functions enable non-linear modeling.
graph TD
AF["Activation Functions"]
SIGMOID["Sigmoid\nσ(x) = 1/(1+e^(-x))\nOutput: [0, 1]"]
TANH["Tanh\ntanh(x)\nOutput: [-1, 1]"]
RELU["ReLU\nf(x) = max(0, x)\nOutput: [0, +∞)"]
SOFTMAX["Softmax\nProbabilities (sum = 1)\nUsage: multi-class classification"]
AF --> SIGMOID
AF --> TANH
AF --> RELU
AF --> SOFTMAX
style RELU fill:#2E7D32,color:#fff
style SOFTMAX fill:#1565C0,color:#fff
| Function | Equation | Range | Typical usage |
|---|---|---|---|
| Linear | $f(x) = x$ | $(-\infty, +\infty)$ | Output layer (regression) |
| Sigmoid | $\sigma(x) = \frac{1}{1+e^{-x}}$ | $[0, 1]$ | Binary classification |
| Tanh | $\tanh(x)$ | $[-1, 1]$ | Hidden layers |
| ReLU | $f(x) = \max(0, x)$ | $[0, +\infty)$ | Hidden layers (go-to) |
| Softmax | $\frac{e^{x_i}}{\sum_j e^{x_j}}$ | $[0, 1]$, sum=1 | Output layer (classification) |
ReLU (Rectified Linear Unit) is the default activation function for hidden layers because it is fast to compute, avoids the vanishing gradient problem, and works well in practice.
Neural Network Architecture
graph LR
subgraph INPUT["Input Layer"]
I1["Pixel 1"]
I2["Pixel 2"]
I3["..."]
I4["Pixel 784"]
end
subgraph HIDDEN["Hidden Layer(s)"]
H1["Neuron 1"]
H2["Neuron 2"]
H3["..."]
H4["Neuron 128"]
end
subgraph OUTPUT["Output Layer"]
O1["Class 0\nT-shirt"]
O2["Class 1\nTrouser"]
O3["..."]
O4["Class 9\nAnkle boot"]
end
I1 & I2 & I3 & I4 --> H1 & H2 & H3 & H4
H1 & H2 & H3 & H4 --> O1 & O2 & O3 & O4
style INPUT fill:#1565C0,color:#fff
style HIDDEN fill:#FF6F00,color:#fff
style OUTPUT fill:#2E7D32,color:#fff
Networks with 2 or more hidden layers are called deep neural networks and their training is called deep learning.
Forward Propagation and Backpropagation
sequenceDiagram
participant DATA as Input Data
participant FORWARD as Forward Propagation
participant LOSS as Loss Calculation
participant BACK as Backpropagation
participant WEIGHTS as Weight Update
DATA->>FORWARD: Images (pixels)
FORWARD->>LOSS: Predictions (probabilities)
Note over LOSS: Compare prediction<br/>vs true class<br/>(Cross-entropy)
LOSS->>BACK: Loss gradient
BACK->>WEIGHTS: Adjust w and bias<br/>for each neuron
WEIGHTS->>FORWARD: New iteration (epoch)
Loss function for multi-class classification:
$$\mathcal{L} = -\sum_{c=1}^{C} y_c \log(\hat{y}_c)$$
Categorical Cross-Entropy: Measures the difference between predicted probabilities and the true class. The lower the value, the better the model predicts.
The Adam Optimizer
Adam (Adaptive Moment Estimation) is a popular variant of mini-batch gradient descent:
- Fast and efficient
- Easy to implement
- Adapts the learning rate for each parameter
- Default choice for most problems
7. Building and Training the First Neural Network
The Fashion-MNIST Dataset
Fashion-MNIST was created by Zalando Research as a replacement for the MNIST dataset (handwritten digits):
- 70,000 images total: 60,000 training + 10,000 test
- Grayscale images: 28×28 pixels
- 10 clothing classes
| Label | Class |
|---|---|
| 0 | T-shirt/top |
| 1 | Trouser |
| 2 | Pullover |
| 3 | Dress |
| 4 | Coat |
| 5 | Sandal |
| 6 | Shirt |
| 7 | Sneaker |
| 8 | Bag |
| 9 | Ankle boot |
Step 1 — Import Libraries and Load Data
# Import libraries
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
print(tf.__version__)
# Class names for display
classNames = ['T-shirt/top', 'Trouser', 'Pullover', 'Dress', 'Coat',
'Sandal', 'Shirt', 'Sneaker', 'Bag', 'Ankle boot']
# Load the Fashion-MNIST dataset via Keras
fashionMnist = tf.keras.datasets.fashion_mnist
(trainImages, trainLabels), (testImages, testLabels) = fashionMnist.load_data()
# Check dimensions
print('Training data:', trainImages.shape, trainLabels.shape)
# >> (60000, 28, 28) (60000,)
print('Test data:', testImages.shape, testLabels.shape)
# >> (10000, 28, 28) (10000,)
Step 2 — Explore and Visualize the Data
def show_training_image(index):
imgLabel = str(trainLabels[index]) + ' (' + classNames[trainLabels[index]] + ')'
plt.figure()
plt.title('Label: ' + imgLabel)
plt.imshow(trainImages[index], cmap='gray')
plt.colorbar()
plt.show()
show_training_image(100)
Step 3 — Prepare Data (Normalization)
Pixels have values from 0 to 255. Normalize them to between 0.0 and 1.0:
# Normalize: divide by 255 to scale to [0, 1]
trainImages = trainImages / 255.0
testImages = testImages / 255.0
Step 4 — Create the Model
graph TD
subgraph MODEL["Keras Sequential Model"]
FLATTEN["Flatten(28×28)\n→ vector of 784 pixels\n(no neurons)"]
DENSE128["Dense(128, activation='relu')\n128 neurons × 784 inputs\n= 100,352 weights + 128 biases\n= 100,480 parameters"]
DENSE10["Dense(10, activation='softmax')\n10 neurons (1 per class)\n128×10 + 10 = 1,290 parameters"]
end
INPUT["28×28 Image\n(784 pixels)"] --> FLATTEN
FLATTEN --> DENSE128
DENSE128 --> DENSE10
DENSE10 --> OUTPUT["Vector of 10 probabilities\n[0.01, 0.05, ..., 0.60]"]
style FLATTEN fill:#1565C0,color:#fff
style DENSE128 fill:#FF6F00,color:#fff
style DENSE10 fill:#2E7D32,color:#fff
# Create the model
model = tf.keras.models.Sequential()
# Flatten layer: converts 28×28 image to a vector of 784 values
model.add(tf.keras.layers.Flatten(input_shape=(28, 28)))
# Hidden Dense layer: 128 neurons with ReLU activation
model.add(tf.keras.layers.Dense(128, activation='relu', name='dense-128-relu'))
# Output layer: 10 neurons (1 per class) with Softmax
model.add(tf.keras.layers.Dense(10, activation='softmax', name='dense-10-softmax'))
# Architecture summary
print('Input data shape:', trainImages.shape)
print(model.summary())
model.summary() output:
Model: "sequential"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
flatten (Flatten) (None, 784) 0
dense-128-relu (Dense) (None, 128) 100480
dense-10-softmax (Dense)(None, 10) 1290
=================================================================
Total params: 101,770
Trainable params: 101,770
Non-trainable params: 0
More than 101,000 weights and biases to adjust during training!
Step 5 — Compile the Model
model.compile(
optimizer='adam', # Adam optimizer
loss='sparse_categorical_crossentropy', # Loss for multi-class classification
metrics=['accuracy'] # Tracking metric: accuracy
)
Why sparse_categorical_crossentropy?
- Labels are simple integers (0–9), not one-hot vectors
- This function finds the class with the highest predicted probability
- It evaluates whether that class matches the true class
Step 6 — Train the Model
# Train for 40 epochs
trainHist = model.fit(trainImages, trainLabels, epochs=40)
Training visualization:
def plot_acc(hist):
plt.title('Accuracy History')
plt.plot(hist.history['accuracy'])
plt.ylabel('Accuracy')
plt.xlabel('Epoch')
plt.show()
def plot_loss(hist):
plt.title('Loss History')
plt.plot(hist.history['loss'])
plt.ylabel('Loss')
plt.xlabel('Epoch')
plt.show()
plot_loss(trainHist)
plot_acc(trainHist)
Step 7 — Evaluate the Model
testLoss, testAcc = model.evaluate(testImages, testLabels, verbose=0)
print('Max accuracy (training):', max(trainHist.history['accuracy']))
print('Accuracy (test):', testAcc)
# >> Training accuracy: ~96%
# >> Test accuracy: ~88%
⚠️ Problem detected: Overfitting! A 10% gap between training (96%) and test (88%) is a classic sign that the model has overfit the training data.
8. Monitoring and Improving Performance
Understanding Overfitting and Underfitting
graph LR
subgraph UNDER["Underfitting"]
U1["The model does not\ncapture enough patterns"]
U2["Low accuracy\ntraining AND test"]
end
subgraph GOOD["Good Balance"]
G1["The model generalizes\nwell on new data"]
G2["Good accuracy\ntraining AND test similar"]
end
subgraph OVER["Overfitting"]
O1["The model has memorized\nthe training data"]
O2["High training accuracy\nLow test accuracy"]
end
UNDER -->|"More\nneurons/epochs"| GOOD
GOOD -->|"Too many\nneurons/epochs"| OVER
style UNDER fill:#d32f2f,color:#fff
style GOOD fill:#2E7D32,color:#fff
style OVER fill:#d32f2f,color:#fff
Solution: Find the right balance where the model generalizes well without memorizing.
TensorBoard: Performance Monitoring
TensorBoard is a visualization tool included in TensorFlow that allows you to:
- Visualize metrics (loss and accuracy)
- Compare training and validation metrics
- Visualize the model graph
- Display histograms of weights and biases
import datetime
# Load the TensorBoard extension
%reload_ext tensorboard
# Remove old logs
!rm -rf ./logs/
# Recreate the baseline model
model = tf.keras.models.Sequential()
model.add(tf.keras.layers.Flatten(input_shape=(28, 28)))
model.add(tf.keras.layers.Dense(128, activation='relu', name='dense-128-relu'))
model.add(tf.keras.layers.Dense(10, activation='softmax', name='dense-10-softmax'))
model.compile(optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])
# Configure TensorBoard callback
logDir = 'logs/fit/' + datetime.datetime.now().strftime('%Y%m%d-%H%M%S')
tensorboardCallback = tf.keras.callbacks.TensorBoard(log_dir=logDir, histogram_freq=1)
# Train with validation data AND TensorBoard callback
trainHist = model.fit(
trainImages, trainLabels,
epochs=40,
validation_data=(testImages, testLabels), # Validation data
callbacks=[tensorboardCallback]
)
# Launch TensorBoard in Colab
%tensorboard --logdir logs/fit
Technique 1 — Reduce Model Complexity
Reduce the number of neurons in the hidden layer (from 128 to 64):
%reload_ext tensorboard
!rm -rf ./logs/
# Simplified model: 64 neurons instead of 128
model = tf.keras.models.Sequential()
model.add(tf.keras.layers.Flatten(input_shape=(28, 28)))
model.add(tf.keras.layers.Dense(64, activation='relu', name='dense-64-relu')) # ← reduced
model.add(tf.keras.layers.Dense(10, activation='softmax', name='dense-10-softmax'))
model.compile(optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])
logDir = 'logs/fit/' + datetime.datetime.now().strftime('%Y%m%d-%H%M%S')
tensorboardCallback = tf.keras.callbacks.TensorBoard(log_dir=logDir, histogram_freq=1)
trainHist = model.fit(
trainImages, trainLabels, epochs=40,
validation_data=(testImages, testLabels),
callbacks=[tensorboardCallback]
)
%tensorboard --logdir logs/fit
Technique 2 — Dropout (Random Neuron Deactivation)
Dropout randomly deactivates a percentage of neurons at each epoch, simulating multiple different models and reducing overfitting.
%reload_ext tensorboard
!rm -rf ./logs/
# Model with Dropout
model = tf.keras.models.Sequential()
model.add(tf.keras.layers.Flatten(input_shape=(28, 28)))
model.add(tf.keras.layers.Dense(128, activation='relu', name='dense-128-relu'))
model.add(tf.keras.layers.Dropout(0.2)) # ← Randomly deactivates 20% of outputs
model.add(tf.keras.layers.Dense(10, activation='softmax', name='dense-10-softmax'))
model.compile(optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])
logDir = 'logs/fit/' + datetime.datetime.now().strftime('%Y%m%d-%H%M%S')
tensorboardCallback = tf.keras.callbacks.TensorBoard(log_dir=logDir, histogram_freq=1)
model.fit(
x=trainImages,
y=trainLabels,
epochs=40,
validation_data=(testImages, testLabels),
callbacks=[tensorboardCallback]
)
%tensorboard --logdir logs/fit
Technique 3 — Early Stopping
Early Stopping automatically halts training when the validation loss stops improving, preventing overfitting.
%reload_ext tensorboard
!rm -rf ./logs/
# Base model
model = tf.keras.models.Sequential()
model.add(tf.keras.layers.Flatten(input_shape=(28, 28)))
model.add(tf.keras.layers.Dense(128, activation='relu', name='dense-128-relu'))
model.add(tf.keras.layers.Dense(10, activation='softmax', name='dense-10-softmax'))
model.compile(optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])
logDir = 'logs/fit/' + datetime.datetime.now().strftime('%Y%m%d-%H%M%S')
tensorboardCallback = tf.keras.callbacks.TensorBoard(log_dir=logDir, histogram_freq=1)
# Early Stopping callback
earlyStoppingCallback = tf.keras.callbacks.EarlyStopping(
monitor='val_loss', # Monitor validation loss
patience=4 # Wait 4 epochs without improvement before stopping
)
# Train with both callbacks
model.fit(
x=trainImages,
y=trainLabels,
epochs=40, # Maximum 40, but stops earlier if needed
validation_data=(testImages, testLabels),
callbacks=[tensorboardCallback, earlyStoppingCallback] # ← Both callbacks
)
%tensorboard --logdir logs/fit
Result: Training stopped automatically after ~11 epochs instead of 40, preventing overfitting!
Technique Comparison
graph TD
PROBLEM["Problem: Overfitting\n(96% training / 88% test)"]
PROBLEM --> T1["Technique 1:\nReduce complexity\n(128→64 neurons)"]
PROBLEM --> T2["Technique 2:\nDropout 20%\n(Dropout(0.2))"]
PROBLEM --> T3["Technique 3:\nEarly Stopping\n(patience=4)"]
T1 --> R1["✅ Less overfitting\nbut slightly reduced accuracy"]
T2 --> R2["✅ Moderate improvement\ntrain/val gap reduced"]
T3 --> R3["✅ Best result!\nOptimal stop ~11 epochs"]
style PROBLEM fill:#d32f2f,color:#fff
style R3 fill:#2E7D32,color:#fff
Saving the Trained Model
import tempfile
import os
# Define the save path with versioning
MODEL_DIR = tempfile.gettempdir()
version = 1
exportPath = os.path.join(MODEL_DIR, str(version))
print('Saving model to: {}\n'.format(exportPath))
# Remove existing version if it exists
if os.path.isdir(exportPath):
print('\nPrevious version found, removing...\n')
!rm -r {exportPath}
# Save the model (architecture + weights + biases)
tf.saved_model.save(model, exportPath)
print('Model saved successfully!')
The save preserves:
- The model architecture (layers, neurons)
- All learned weights and biases (>101,000 values!)
9. Deploying the Neural Network
What Does Deploying a Neural Network Mean?
Deploying a neural network = making the trained network available to applications for making predictions.
graph LR
APP["Client\nApplication"] -->|"Image (pixels)"| SERVICE
subgraph SERVICE["TensorFlow ModelServer"]
INTERFACE["REST Interface"]
MODEL["Trained Model\nFashion-MNIST"]
INTERFACE --> MODEL
end
SERVICE -->|"Probabilities [0.01, ..., 0.60]"| APP
style APP fill:#1565C0,color:#fff
style INTERFACE fill:#FF6F00,color:#fff
style MODEL fill:#2E7D32,color:#fff
Deployment Forms
graph TD
TF_SERVING["TensorFlow Serving"]
LOCAL["Local deployment\n(this course)\nTest on Colab"]
SERVER["Local server\nAccessible to a team"]
CLOUD["Global cloud\nMillions of users"]
TF_SERVING --> LOCAL
TF_SERVING --> SERVER
TF_SERVING --> CLOUD
style LOCAL fill:#2E7D32,color:#fff
style SERVER fill:#FF6F00,color:#fff
style CLOUD fill:#1565C0,color:#fff
Step 1 — Install TensorFlow ModelServer
# Add the APT key for TensorFlow Serving
!echo 'deb http://storage.googleapis.com/tensorflow-serving-apt stable \
tensorflow-model-server tensorflow-model-server-universal' | \
tee /etc/apt/sources.list.d/tensorflow-serving.list && \
curl https://storage.googleapis.com/tensorflow-serving-apt/tensorflow-serving.release.pub.gpg | \
apt-key add -
# Update the APT database
!apt update
# Install TensorFlow ModelServer
!apt-get install tensorflow-model-server
Step 2 — Start the Server
# Configure environment variables
os.environ['MODEL_DIR'] = MODEL_DIR # Path to the saved model
REST_PORT = '8501'
os.environ['REST_PORT'] = REST_PORT # REST access port
MODEL_NAME = 'fashion_mnist'
os.environ['MODEL_NAME'] = MODEL_NAME # Model name (used in the URL)
# Start the server in the background
%%bash --bg
nohup tensorflow_model_server \
--rest_api_port="${REST_PORT}" \
--model_name="${MODEL_NAME}" \
--model_base_path="${MODEL_DIR}" > server.log 2>&1
# Verify the server started correctly
!tail server.log
Step 3 — Send a Prediction Request
REST request architecture:
URL: http://localhost:8501/v1/models/fashion_mnist:predict
Method: POST
Headers: {'content-type': 'application/json'}
Body: {
"signature_name": "serving_default",
"instances": [[[pixel_values]]] // 4D tensor: [-1, 28, 28, 1]
}
# Install the requests library
!pip install -q requests
import requests
import random
import json
# Select a random test image
imageIndex = random.randint(0, len(testImages) - 1)
# Reshape the image: (28,28) → (-1, 28, 28, 1)
# The server expects a list of images (4D tensor)
checkImages = np.reshape(testImages[imageIndex], (-1, 28, 28, 1))
# Build the JSON payload
payload = json.dumps({
'signature_name': 'serving_default',
'instances': checkImages.tolist()
})
# Send the HTTP POST request
headers = {'content-type': 'application/json'}
predictServiceUrl = f'http://localhost:{REST_PORT}/v1/models/{MODEL_NAME}:predict'
jsonResponse = requests.post(predictServiceUrl, data=payload, headers=headers)
# Process the response
predictions = json.loads(jsonResponse.text)['predictions']
# predictions[0] = list of 10 probabilities, e.g. [0.01, 0.05, ..., 0.60]
# Predicted class = index of the maximum probability
predictedClass = np.argmax(predictions[0])
# Display result
def show_image(index, title, show_colorbar=False):
plt.figure()
plt.title('\n\n{}'.format(title), fontdict={'size': 16})
plt.imshow(testImages[index].reshape(28, 28), cmap='gray')
if show_colorbar:
plt.colorbar()
plt.axis('off')
plt.show()
show_image(
imageIndex,
f'Predicted class: {classNames[predictedClass]} (class {predictedClass})\n'
f'True class: {classNames[testLabels[imageIndex]]} (class {testLabels[imageIndex]})'
)
Complete Deployment Flow
sequenceDiagram
participant CLIENT as Client Application
participant SERVER as TensorFlow ModelServer
participant MODEL as Fashion-MNIST Model
CLIENT->>CLIENT: Select a random image
CLIENT->>CLIENT: Reshape to 4D tensor [-1,28,28,1]
CLIENT->>CLIENT: Build JSON payload
CLIENT->>SERVER: POST /v1/models/fashion_mnist:predict
SERVER->>MODEL: Forward pixels
MODEL->>MODEL: Forward propagation
MODEL->>SERVER: Probabilities [0.01, 0.05, ..., 0.60]
SERVER->>CLIENT: JSON response with probabilities
CLIENT->>CLIENT: argmax(probabilities) → predicted class
CLIENT->>CLIENT: Display predicted vs true class
10. Conclusion and Next Steps
Full Journey Summary
flowchart TD
A["🚀 TensorFlow 2\nOpen source ML framework"] --> B
B["🛠️ Google Colab\nFree environment\nPython + GPU/TPU"] --> C
C["📊 ML Workflow\nDefine → Data → Prepare\n→ Model → Train → Evaluate"] --> D
D["🏠 Simple model\nHouse price prediction\n(1 neuron, linear regression)"] --> E
E["🧠 Neural Network\nFashion-MNIST\n(101,770 parameters, 10 classes)"] --> F
F["📈 TensorBoard\nPerformance monitoring\nOverfitting detection"] --> G
G["🔧 Improvement techniques\nReduce complexity\nDropout\nEarly Stopping"] --> H
H["🌐 Deployment\nTensorFlow ModelServer\nREST API for predictions"] --> I
I["✅ Result\nImage classification service\naccessible via HTTP"]
style A fill:#FF6F00,color:#fff
style I fill:#2E7D32,color:#fff
Key Takeaways
✅ TensorFlow is a multi-platform open source ML framework
✅ Google Colab = free development environment, no installation required
✅ ML workflow = Define → Data → Prepare → Model → Train → Evaluate
✅ A neuron = Σ(inputs × weights) + bias → activation function
✅ ReLU for hidden layers, Softmax for multi-class classification
✅ Adam = popular optimizer (mini-batch gradient descent variant)
✅ Loss = categorical cross-entropy for multi-class classification
✅ Overfitting = memorizing training data → poor generalization
✅ TensorBoard allows visualizing and comparing metrics
✅ Early Stopping = effective solution against overfitting
✅ TensorFlow ModelServer deploys a model as a REST service
Final Architecture: Fashion-MNIST Model Summary
Input (28×28 pixels)
│
▼
Flatten → [784 values]
│
▼
Dense(128, ReLU)
• 784 × 128 = 100,352 weights
• 128 biases
• 100,480 parameters
│
▼
[Optional: Dropout(0.2)]
│
▼
Dense(10, Softmax)
• 128 × 10 = 1,280 weights
• 10 biases
• 1,290 parameters
│
▼
Output: [0.01, 0.05, 0.04, 0.06, 0.50, ...]
↑ probability for each of the 10 classes
Total: 101,770 trainable parameters!
Next Steps
- Explore other courses on machine learning
- Visit TensorFlow.org to stay up to date with the framework
- Explore the Keras functional API for more complex architectures
- Read research papers on new ML architectures
- Build your own models — practice is essential!
graph LR
NOW["What you know now"]
NOW --> A["Keras Sequential\nLinear models\nImage classification"]
NEXT["Next steps"]
A --> NEXT
NEXT --> B["Keras Functional API\nComplex architectures\n(ResNet, Inception...)"]
NEXT --> C["Transfer Learning\nReuse pre-trained\nmodels"]
NEXT --> D["TFX\nProduction pipelines\nat scale"]
NEXT --> E["Advanced architectures\nCNN, RNN, Transformers..."]
style NOW fill:#1565C0,color:#fff
style NEXT fill:#FF6F00,color:#fff
Appendix — Key Commands and API Reference
Essential Commands
| Command | Description |
|---|---|
%tensorflow_version 2.x | Ensures TF 2.x in Colab |
tf.__version__ | Displays TensorFlow version |
model.summary() | Displays model architecture |
model.compile(...) | Configures loss, optimizer, metrics |
model.fit(...) | Trains the model |
model.evaluate(...) | Evaluates on test data |
model.predict(...) | Makes predictions |
tf.saved_model.save(model, path) | Saves the model |
Most Used Keras Layers
| Layer | Usage |
|---|---|
tf.keras.layers.Dense(n, activation) | Dense layer (fully connected) |
tf.keras.layers.Flatten(input_shape) | Flattens dimensions |
tf.keras.layers.Dropout(rate) | Dropout for regularization |
Common Optimizers
| Optimizer | Description | Usage |
|---|---|---|
'sgd' | Stochastic Gradient Descent | Simple problems, educational |
'adam' | Adam (adaptive) | Recommended default |
'rmsprop' | RMSprop | RNNs, recurrent networks |
Common Loss Functions
| Loss | Usage |
|---|---|
'mean_squared_error' | Regression (prices, continuous values) |
'sparse_categorical_crossentropy' | Multi-class classification (integer labels) |
'categorical_crossentropy' | Multi-class classification (one-hot labels) |
'binary_crossentropy' | Binary classification |
Useful Callbacks
# TensorBoard: metric visualization
tf.keras.callbacks.TensorBoard(log_dir=logDir, histogram_freq=1)
# Early Stopping: stop training early
tf.keras.callbacks.EarlyStopping(monitor='val_loss', patience=4)
# Model Checkpoint: automatically save best weights
tf.keras.callbacks.ModelCheckpoint(filepath='best_model', save_best_only=True)
Reference document generated from course audio, Jupyter notebooks, and course slides.
Search Terms
train · deploy · neural · network · tensorflow · deep · networks · machine · data · science · model · technique · architecture · loss · commands · compile · concepts · deploying · deployment · environment · evaluate · explore · fashion-mnist · functions