Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

TensorFlow and Keras

🎯 Goal

After reading this chapter:

  • You will know the difference between TensorFlow/Keras and PyTorch
  • You will build models with Keras Sequential and Functional APIs
  • You will know the TensorFlow ecosystem (TF Serving, TF Lite, TF.js)
  • You will consciously choose your main framework

**Note:**Your main framework will be PyTorch(industry default). We learn TF/Keras just for familiarity, because:

  • Still present in legacy projects
  • Google Cloud (Vertex AI) integration
  • TF Lite — mobile/edge deployment

What to learn

  • TensorFlow 2.x — eager execution, tf.function
  • Keras Sequential API — adding layers in sequence
  • Keras Functional API — complex architectures
  • Model.compile, fit, predict — high-level API
  • Callbacks — EarlyStopping, ModelCheckpoint, TensorBoard
  • tf.data.Dataset — efficient data pipeline
  • TF Serving — production deployment
  • TF Lite — mobile/edge inference
  • TF.js — inference in the browser

Libraries

pip install tensorflow
# or
pip install tensorflow-macos tensorflow-metal  # For Mac M-chip

Version: TensorFlow 2.15+(2.x only).

PyTorch vs TensorFlow/Keras

AspectPyTorchTF/Keras
API stylePythonic, imperativeDeclarative (Keras), imperative (TF 2)
BoilerplateMore (training loop)Less (.fit())
DebuggingEasy (Python)Sometimes hard (in graph mode)
ResearchDominantDeclining
ProductionGrowingHistorically strong
MobilePyTorch MobileTF Lite (better)
BrowserONNX.jsTF.js (good)
Industry adoption⬆️ (LLM era)⬇️ (outside Google)

**Recommendation:**Learn PyTorch as core knowledge, and TF/Keras at a “familiarity level”.

Code examples

Sequential API — the simplest

import tensorflow as tf
from tensorflow.keras import layers, models

model = models.Sequential([
    layers.Input(shape=(784,)),
    layers.Dense(256, activation="relu"),
    layers.Dropout(0.3),
    layers.Dense(128, activation="relu"),
    layers.Dropout(0.3),
    layers.Dense(10, activation="softmax"),
])

model.compile(
    optimizer=tf.keras.optimizers.Adam(learning_rate=1e-3),
    loss="sparse_categorical_crossentropy",
    metrics=["accuracy"],
)

model.summary()

Training (fit API)

from tensorflow.keras.datasets import mnist

(X_train, y_train), (X_test, y_test) = mnist.load_data()
X_train = X_train.reshape(-1, 784) / 255.0
X_test = X_test.reshape(-1, 784) / 255.0

history = model.fit(
    X_train, y_train,
    epochs=10,
    batch_size=128,
    validation_split=0.1,
    verbose=1,
)

# Evaluation
test_loss, test_acc = model.evaluate(X_test, y_test, verbose=0)
print(f"Test accuracy:{test_acc:.4f}")

Functional API — more complex

inputs = layers.Input(shape=(784,))
x = layers.Dense(256, activation="relu")(inputs)
x = layers.Dropout(0.3)(x)

# Branching (the advantage of Functional API)
branch_a = layers.Dense(64, activation="relu")(x)
branch_b = layers.Dense(64, activation="relu")(x)
merged = layers.Concatenate()([branch_a, branch_b])

outputs = layers.Dense(10, activation="softmax")(merged)
model = models.Model(inputs=inputs, outputs=outputs)

Callbacks

from tensorflow.keras.callbacks import EarlyStopping, ModelCheckpoint, TensorBoard

callbacks = [
    EarlyStopping(monitor="val_loss", patience=5, restore_best_weights=True),
    ModelCheckpoint("best_model.keras", monitor="val_accuracy", save_best_only=True),
    TensorBoard(log_dir="./logs"),
]

model.fit(X_train, y_train, epochs=50, callbacks=callbacks, validation_split=0.1)
# TensorBoard: $ tensorboard --logdir=./logs

Custom training loop (PyTorch-like)

optimizer = tf.keras.optimizers.Adam()
loss_fn = tf.keras.losses.SparseCategoricalCrossentropy()
acc_metric = tf.keras.metrics.SparseCategoricalAccuracy()

@tf.function  # graph mode (faster)
def train_step(X, y):
    with tf.GradientTape() as tape:
        logits = model(X, training=True)
        loss = loss_fn(y, logits)
    grads = tape.gradient(loss, model.trainable_weights)
    optimizer.apply_gradients(zip(grads, model.trainable_weights))
    acc_metric.update_state(y, logits)
    return loss

for epoch in range(10):
    for X_batch, y_batch in train_dataset:
        loss = train_step(X_batch, y_batch)
    print(f"Epoch{epoch+1}: loss={loss:.4f}, acc={acc_metric.result():.4f}")
    acc_metric.reset_state()

tf.data.Dataset — efficient pipeline

import tensorflow as tf

dataset = tf.data.Dataset.from_tensor_slices((X_train, y_train))
dataset = (dataset
    .shuffle(buffer_size=10000)
    .batch(128)
    .prefetch(tf.data.AUTOTUNE))

for X_batch, y_batch in dataset.take(1):
    print(X_batch.shape, y_batch.shape)

Saving and loading

# Save (Keras format — new standard)
model.save("model.keras")

# Load
loaded = tf.keras.models.load_model("model.keras")

# Weights only
model.save_weights("weights.h5")
new_model.load_weights("weights.h5")

# SavedModel format (for TF Serving)
model.export("saved_model_dir/")

TFLite — mobile/edge

converter = tf.lite.TFLiteConverter.from_keras_model(model)
converter.optimizations = [tf.lite.Optimize.DEFAULT]
tflite_model = converter.convert()

with open("model.tflite", "wb") as f:
    f.write(tflite_model)

# Loading (mobile)
interpreter = tf.lite.Interpreter(model_path="model.tflite")
interpreter.allocate_tensors()

Backend integration

# With Docker
docker run -p 8501:8501 \
  --mount type=bind,source=$(pwd)/saved_model_dir,target=/models/my_model \
  -e MODEL_NAME=my_model \
  tensorflow/serving

# REST API
curl -X POST http://localhost:8501/v1/models/my_model:predict \
  -d '{"instances": [[1.0, 2.0, 3.0, ...]]}'

FastAPI proxy to TF Serving

import httpx
from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()
TF_SERVING_URL = "http://localhost:8501/v1/models/my_model:predict"

class Input(BaseModel):
    features: list[float]

@app.post("/predict")
async def predict(data: Input):
    async with httpx.AsyncClient() as client:
        response = await client.post(
            TF_SERVING_URL,
            json={"instances": [data.features]},
        )
    return response.json()

Keras model directly in FastAPI

import tensorflow as tf
from contextlib import asynccontextmanager

@asynccontextmanager
async def lifespan(app):
    app.state.model = tf.keras.models.load_model("model.keras")
    yield

app = FastAPI(lifespan=lifespan)

@app.post("/predict")
def predict(data: Input):
    X = tf.constant([data.features])
    logits = app.state.model(X, training=False).numpy()
    return {"prediction": int(logits.argmax()), "confidence": float(logits.max())}

Resources

  • TensorFlow tutorialstensorflow.org/tutorials
  • Keras docskeras.io
  • “Deep Learning with Python” — François Chollet (creator of Keras, 2nd ed.)
  • Andrew Ng — TensorFlow Professional Certificate(Coursera)
  • TensorFlow YouTube channel — official tutorials

🏋️ Exercises

🟢 Easy

  1. Create a 3-layer MLP with the Sequential API and train it on MNIST.
  2. Interpret the number of parameters shown by model.summary().
  3. Stop training automatically with an EarlyStopping callback.

🟡 Medium

  1. Custom callback: Write a custom callback that prints loss/acc every 5 epochs.
  2. Functional API: Create a model with 2 inputs (numeric + categorical).
  3. Same model, two frameworks: Write the same MLP in PyTorch and Keras, compare accuracy and training time.

🔴 Hard

  1. TF Serving deployment: Deploy the MNIST model with TF Serving in Docker, predict via REST API.
  2. TF Lite mobile: Export the model to .tflite, run inference in Python or on Android emulator.

Capstone

notebooks/month-03/03_keras_mnist.ipynb:

  • Create models on MNIST with Keras Sequential and Functional API
  • Write logs to TensorBoard
  • EarlyStopping + ModelCheckpoint with callbacks
  • Export to TF Lite
  • Compare with PyTorch capstone

✅ Checklist

  • I know the difference between Sequential and Functional API
  • I know the model.compile / fit / evaluate workflow
  • I use callbacks (EarlyStopping, ModelCheckpoint)
  • I can create a tf.data.Dataset pipeline
  • I can save models in .keras, SavedModel, TFLite formats
  • I have an understanding of TF Serving
  • I can justify the choice between PyTorch and TF/Keras

Moving on to Training techniques — back to focus on PyTorch.