Beginner

Build, Train and Deploy Your First Neural Network with TensorFlow 2

The full ML workflow in TensorFlow 2 and Keras — build, train, monitor and deploy a neural network.

A comprehensive introduction to building, training, and deploying neural networks with TensorFlow 2 and Keras.


Table of Contents

  1. Course Overview
  2. Why Learn TensorFlow?
  3. TensorFlow Environment Setup
  4. AI and Machine Learning Concepts
  5. Applying the ML Workflow with TensorFlow — House Price Prediction
  6. Understanding Neural Networks
  7. Building and Training the First Neural Network
  8. Monitoring and Improving Performance
  9. Deploying the Neural Network
  10. 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

ModuleTopicDuration
1Course Overview1m 35s
2Why Learn TensorFlow?12m 12s
3Environment Setup16m 50s
4AI and Machine Learning Concepts20m
5ML Workflow Application (house prices)29m 35s
6Understanding Neural Networks25m 7s
7Building the First Neural Network22m 11s
8Monitoring and Improving Performance21m 7s
9Deploying the Neural Network10m 53s
10Conclusion7m 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

LanguagePrimary usage
PythonMain language, most popular in the ML community
C++High-performance math libraries, IoT
JavaScriptTensorFlow.js — client-side and server-side
SwiftStrong 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

ConceptDescription
Code CellContains Python code to execute
Text CellMarkdown documentation
ExecutionShift+Enter or click the arrow
Execution numberIndicates the order cells were executed
Run AllExecutes all cells from top to bottom
Restart & Run AllResets 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

AspectTraditional ProgrammingMachine Learning
ApproachExpert manually codes explicit rules (if/else)Model learns rules from data
DataInput for processingLearning source
RulesDefined by the developerLearned automatically
ImprovementManual code modificationRetraining 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:

PropertyDescriptionExample
RankNumber of dimensionsScalar=0, Vector=1, Matrix=2
ShapeSize of each dimension[28, 28] for a 28×28 image
Data typeType of valuesfloat32, 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 SF
  • Gr 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
FunctionEquationRangeTypical 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=1Output 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
LabelClass
0T-shirt/top
1Trouser
2Pullover
3Dress
4Coat
5Sandal
6Shirt
7Sneaker
8Bag
9Ankle 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

  1. Explore other courses on machine learning
  2. Visit TensorFlow.org to stay up to date with the framework
  3. Explore the Keras functional API for more complex architectures
  4. Read research papers on new ML architectures
  5. 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

CommandDescription
%tensorflow_version 2.xEnsures 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

LayerUsage
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

OptimizerDescriptionUsage
'sgd'Stochastic Gradient DescentSimple problems, educational
'adam'Adam (adaptive)Recommended default
'rmsprop'RMSpropRNNs, recurrent networks

Common Loss Functions

LossUsage
'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

Interested in this course?

Contact us to book it or get a custom training plan for your team.