Skip to content
AI & ML

Machine Learning with Python and TensorFlow - Practical Guide

Published on:
·5 min read·Author: MDS Software Solutions Group

Machine Learning with

ai-ml

Machine Learning with Python and TensorFlow - Practical Guide

Machine Learning (ML) is revolutionizing the way we build software. Instead of programming explicit rules, we train models to recognize patterns in data. TensorFlow, created by Google, is one of the most powerful frameworks for building and deploying ML models. In this guide, we will walk through the theoretical foundations, TensorFlow architecture, practical implementations, and production deployment strategies.

Machine Learning Fundamentals#

Before diving into TensorFlow, it is essential to understand the three main paradigms of machine learning.

Supervised Learning#

In supervised learning, a model is trained on pairs of (input data, expected output). Based on these examples, it learns a function that maps inputs to outputs.

Common applications:

  • Classification - image recognition, sentiment analysis, spam detection
  • Regression - price prediction, weather forecasting, delivery time estimation
# Simple example: binary classification
import tensorflow as tf
from tensorflow import keras

# Training data: features and labels
X_train = [[0.1, 0.2], [0.4, 0.6], [0.8, 0.9], [0.3, 0.1]]
y_train = [0, 0, 1, 0]  # 0 = class A, 1 = class B

model = keras.Sequential([
    keras.layers.Dense(16, activation='relu', input_shape=(2,)),
    keras.layers.Dense(1, activation='sigmoid')
])

model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])
model.fit(X_train, y_train, epochs=50, verbose=0)

Unsupervised Learning#

The model analyzes data without labels, searching for hidden patterns and structures.

Common applications:

  • Clustering - customer segmentation, image segmentation
  • Dimensionality reduction - visualizing high-dimensional data (PCA, t-SNE)
  • Anomaly detection - fraud identification, system monitoring
# Autoencoder for anomaly detection
encoder = keras.Sequential([
    keras.layers.Dense(64, activation='relu', input_shape=(100,)),
    keras.layers.Dense(32, activation='relu'),
    keras.layers.Dense(16, activation='relu')  # Bottleneck
])

decoder = keras.Sequential([
    keras.layers.Dense(32, activation='relu', input_shape=(16,)),
    keras.layers.Dense(64, activation='relu'),
    keras.layers.Dense(100, activation='sigmoid')
])

autoencoder_input = keras.layers.Input(shape=(100,))
encoded = encoder(autoencoder_input)
decoded = decoder(encoded)
autoencoder = keras.Model(autoencoder_input, decoded)

autoencoder.compile(optimizer='adam', loss='mse')

Reinforcement Learning#

An agent learns to make decisions in an environment by receiving rewards for good actions and penalties for bad ones. This paradigm is behind the success of AlphaGo, robotics, and autonomous vehicles.

Key concepts:

  • Agent - the decision-making entity
  • Environment - the world in which the agent operates
  • Policy - the agent's decision-making strategy
  • Reward - feedback signal from the environment

TensorFlow and Keras Architecture#

TensorFlow is a comprehensive ecosystem for machine learning. Keras, the high-level API of TensorFlow, significantly simplifies model construction.

Tensors - The Core Data Structure#

A tensor is a multi-dimensional numerical array. The name TensorFlow comes from the flow of tensors through a computational graph.

import tensorflow as tf

# Scalar (0-dimensional tensor)
scalar = tf.constant(42)
print(scalar.shape)  # ()

# Vector (1-dimensional tensor)
vector = tf.constant([1.0, 2.0, 3.0])
print(vector.shape)  # (3,)

# Matrix (2-dimensional tensor)
matrix = tf.constant([[1, 2], [3, 4], [5, 6]])
print(matrix.shape)  # (3, 2)

# 3-dimensional tensor (e.g., batch of RGB images)
images = tf.random.normal([32, 224, 224, 3])
print(images.shape)  # (32, 224, 224, 3)

# Tensor operations
a = tf.constant([[1, 2], [3, 4]])
b = tf.constant([[5, 6], [7, 8]])

print(tf.add(a, b))       # Element-wise addition
print(tf.matmul(a, b))    # Matrix multiplication
print(tf.reduce_mean(a))  # Mean

Layers#

Layers are the fundamental building blocks of models. Each layer performs a transformation on the input data.

# Most common layers in Keras

# Dense - fully connected layer
dense = keras.layers.Dense(128, activation='relu')

# Conv2D - 2D convolutional layer
conv = keras.layers.Conv2D(64, kernel_size=(3, 3), activation='relu', padding='same')

# LSTM - Long Short-Term Memory
lstm = keras.layers.LSTM(256, return_sequences=True)

# Dropout - regularization (prevents overfitting)
dropout = keras.layers.Dropout(0.3)

# BatchNormalization - batch normalization
bn = keras.layers.BatchNormalization()

# Embedding - maps indices to dense vectors
embedding = keras.layers.Embedding(input_dim=10000, output_dim=128)

Models - Sequential vs Functional API#

Keras offers two main approaches to building models.

# 1. Sequential API - simple stack of layers
model_sequential = keras.Sequential([
    keras.layers.Dense(256, activation='relu', input_shape=(784,)),
    keras.layers.Dropout(0.3),
    keras.layers.Dense(128, activation='relu'),
    keras.layers.Dropout(0.2),
    keras.layers.Dense(10, activation='softmax')
])

# 2. Functional API - flexible graphs (multiple inputs/outputs, skip connections)
inputs = keras.layers.Input(shape=(784,))
x = keras.layers.Dense(256, activation='relu')(inputs)
x = keras.layers.Dropout(0.3)(x)

# Skip connection (residual)
skip = keras.layers.Dense(128)(inputs)
x = keras.layers.Dense(128, activation='relu')(x)
x = keras.layers.Add()([x, skip])

x = keras.layers.Dropout(0.2)(x)
outputs = keras.layers.Dense(10, activation='softmax')(x)

model_functional = keras.Model(inputs=inputs, outputs=outputs)

The Training Loop#

The model training process consists of several stages: compilation, training, and evaluation.

# Model compilation
model.compile(
    optimizer=keras.optimizers.Adam(learning_rate=0.001),
    loss='sparse_categorical_crossentropy',
    metrics=['accuracy']
)

# Callbacks - monitoring and controlling training
callbacks = [
    keras.callbacks.EarlyStopping(
        monitor='val_loss',
        patience=5,
        restore_best_weights=True
    ),
    keras.callbacks.ReduceLROnPlateau(
        monitor='val_loss',
        factor=0.5,
        patience=3
    ),
    keras.callbacks.ModelCheckpoint(
        filepath='best_model.keras',
        monitor='val_accuracy',
        save_best_only=True
    ),
    keras.callbacks.TensorBoard(log_dir='./logs')
]

# Training
history = model.fit(
    X_train, y_train,
    epochs=100,
    batch_size=32,
    validation_split=0.2,
    callbacks=callbacks
)

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

Common Neural Network Architectures#

CNN - Convolutional Neural Networks#

Convolutional networks dominate image processing. Convolutional filters automatically learn to detect visual features at different levels of abstraction.

def build_cnn_classifier(input_shape=(224, 224, 3), num_classes=10):
    """Build a CNN image classifier."""
    model = keras.Sequential([
        # Convolutional block 1
        keras.layers.Conv2D(32, (3, 3), activation='relu',
                           padding='same', input_shape=input_shape),
        keras.layers.Conv2D(32, (3, 3), activation='relu', padding='same'),
        keras.layers.MaxPooling2D((2, 2)),
        keras.layers.BatchNormalization(),

        # Convolutional block 2
        keras.layers.Conv2D(64, (3, 3), activation='relu', padding='same'),
        keras.layers.Conv2D(64, (3, 3), activation='relu', padding='same'),
        keras.layers.MaxPooling2D((2, 2)),
        keras.layers.BatchNormalization(),

        # Convolutional block 3
        keras.layers.Conv2D(128, (3, 3), activation='relu', padding='same'),
        keras.layers.Conv2D(128, (3, 3), activation='relu', padding='same'),
        keras.layers.MaxPooling2D((2, 2)),
        keras.layers.BatchNormalization(),
        keras.layers.Dropout(0.3),

        # Classifier head
        keras.layers.GlobalAveragePooling2D(),
        keras.layers.Dense(256, activation='relu'),
        keras.layers.Dropout(0.5),
        keras.layers.Dense(num_classes, activation='softmax')
    ])

    model.compile(
        optimizer='adam',
        loss='sparse_categorical_crossentropy',
        metrics=['accuracy']
    )
    return model

# Usage
cnn_model = build_cnn_classifier(num_classes=10)
cnn_model.summary()

Key CNN layers:

  • Conv2D - detects local features (edges, textures, shapes)
  • MaxPooling2D - reduces spatial dimensions, increases receptive field
  • GlobalAveragePooling2D - aggregates feature maps into a vector
  • BatchNormalization - stabilizes training, faster convergence

RNN - Recurrent Neural Networks#

Recurrent networks process sequential data such as text, time series, and audio. LSTM and GRU architectures solve the vanishing gradient problem.

def build_text_classifier(vocab_size=20000, max_length=200, num_classes=5):
    """Text classifier with bidirectional LSTM."""
    model = keras.Sequential([
        keras.layers.Embedding(vocab_size, 128, input_length=max_length),
        keras.layers.Bidirectional(
            keras.layers.LSTM(64, return_sequences=True)
        ),
        keras.layers.Bidirectional(keras.layers.LSTM(32)),
        keras.layers.Dense(64, activation='relu'),
        keras.layers.Dropout(0.5),
        keras.layers.Dense(num_classes, activation='softmax')
    ])

    model.compile(
        optimizer='adam',
        loss='sparse_categorical_crossentropy',
        metrics=['accuracy']
    )
    return model

# Text generation with RNN
def build_text_generator(vocab_size, seq_length):
    """Character-level text generation model."""
    model = keras.Sequential([
        keras.layers.Embedding(vocab_size, 256, input_length=seq_length),
        keras.layers.LSTM(512, return_sequences=True),
        keras.layers.LSTM(512),
        keras.layers.Dense(256, activation='relu'),
        keras.layers.Dense(vocab_size, activation='softmax')
    ])
    model.compile(optimizer='adam', loss='sparse_categorical_crossentropy')
    return model

Transformer - A Revolution in NLP and Beyond#

The Transformer architecture, based on the self-attention mechanism, has revolutionized NLP and is increasingly being adopted in computer vision as well.

class TransformerBlock(keras.layers.Layer):
    """Transformer block with Multi-Head Attention."""

    def __init__(self, embed_dim, num_heads, ff_dim, dropout_rate=0.1):
        super().__init__()
        self.attention = keras.layers.MultiHeadAttention(
            num_heads=num_heads,
            key_dim=embed_dim // num_heads
        )
        self.ffn = keras.Sequential([
            keras.layers.Dense(ff_dim, activation='gelu'),
            keras.layers.Dense(embed_dim)
        ])
        self.layernorm1 = keras.layers.LayerNormalization(epsilon=1e-6)
        self.layernorm2 = keras.layers.LayerNormalization(epsilon=1e-6)
        self.dropout1 = keras.layers.Dropout(dropout_rate)
        self.dropout2 = keras.layers.Dropout(dropout_rate)

    def call(self, inputs, training=False):
        # Multi-Head Self-Attention + Residual
        attn_output = self.attention(inputs, inputs)
        attn_output = self.dropout1(attn_output, training=training)
        out1 = self.layernorm1(inputs + attn_output)

        # Feed-Forward Network + Residual
        ffn_output = self.ffn(out1)
        ffn_output = self.dropout2(ffn_output, training=training)
        return self.layernorm2(out1 + ffn_output)


def build_transformer_classifier(
    vocab_size=20000, max_length=200, embed_dim=128,
    num_heads=4, ff_dim=256, num_blocks=2, num_classes=5
):
    """Transformer-based text classifier."""
    inputs = keras.layers.Input(shape=(max_length,))
    x = keras.layers.Embedding(vocab_size, embed_dim)(inputs)

    # Positional encoding (simple - learned)
    positions = keras.layers.Embedding(max_length, embed_dim)(
        tf.range(max_length)
    )
    x = x + positions

    for _ in range(num_blocks):
        x = TransformerBlock(embed_dim, num_heads, ff_dim)(x)

    x = keras.layers.GlobalAveragePooling1D()(x)
    x = keras.layers.Dense(64, activation='relu')(x)
    x = keras.layers.Dropout(0.3)(x)
    outputs = keras.layers.Dense(num_classes, activation='softmax')(x)

    model = keras.Model(inputs=inputs, outputs=outputs)
    model.compile(
        optimizer=keras.optimizers.Adam(learning_rate=1e-4),
        loss='sparse_categorical_crossentropy',
        metrics=['accuracy']
    )
    return model

Transfer Learning - The Power of Pretrained Models#

Transfer learning allows you to leverage knowledge from models trained on massive datasets. Instead of training from scratch, you fine-tune a pretrained model for your specific task.

def build_transfer_learning_model(num_classes, fine_tune_at=100):
    """
    Image classifier with transfer learning (EfficientNetV2).
    Only the top layers are trained while the base is frozen.
    """
    # Pretrained model as feature extractor
    base_model = keras.applications.EfficientNetV2B0(
        weights='imagenet',
        include_top=False,
        input_shape=(224, 224, 3)
    )

    # Freeze base layers
    base_model.trainable = False

    # Build model
    model = keras.Sequential([
        base_model,
        keras.layers.GlobalAveragePooling2D(),
        keras.layers.Dense(256, activation='relu'),
        keras.layers.Dropout(0.3),
        keras.layers.Dense(num_classes, activation='softmax')
    ])

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


def fine_tune_model(model, base_model, fine_tune_at=100):
    """
    Stage 2: Fine-tuning - unfreeze top layers of the base model.
    Use a lower learning rate to avoid destroying pretrained weights.
    """
    base_model.trainable = True
    for layer in base_model.layers[:fine_tune_at]:
        layer.trainable = False

    model.compile(
        optimizer=keras.optimizers.Adam(learning_rate=1e-5),
        loss='sparse_categorical_crossentropy',
        metrics=['accuracy']
    )
    return model


# Usage
model, base_model = build_transfer_learning_model(num_classes=5)

# Stage 1: Train classifier (frozen base)
model.fit(train_ds, epochs=10, validation_data=val_ds)

# Stage 2: Fine-tuning (unfrozen top layers)
model = fine_tune_model(model, base_model, fine_tune_at=100)
model.fit(train_ds, epochs=10, validation_data=val_ds)

Popular pretrained models in TensorFlow:

  • EfficientNetV2 - best accuracy-efficiency trade-off for images
  • ResNet50/101 - classic architecture with residual connections
  • MobileNetV3 - optimized for mobile devices
  • BERT/DistilBERT - pretrained language models (via TF Hub or Hugging Face)

Practical Example: Image Classification#

Let us build a complete image classification pipeline with data augmentation and transfer learning.

import tensorflow as tf
from tensorflow import keras
import matplotlib.pyplot as plt

# 1. Loading and preparing data
BATCH_SIZE = 32
IMG_SIZE = (224, 224)

train_ds = keras.utils.image_dataset_from_directory(
    'dataset/train',
    image_size=IMG_SIZE,
    batch_size=BATCH_SIZE,
    label_mode='int',
    shuffle=True,
    seed=42
)

val_ds = keras.utils.image_dataset_from_directory(
    'dataset/validation',
    image_size=IMG_SIZE,
    batch_size=BATCH_SIZE,
    label_mode='int'
)

class_names = train_ds.class_names
num_classes = len(class_names)

# 2. Data augmentation
data_augmentation = keras.Sequential([
    keras.layers.RandomFlip('horizontal'),
    keras.layers.RandomRotation(0.2),
    keras.layers.RandomZoom(0.2),
    keras.layers.RandomContrast(0.2),
    keras.layers.RandomTranslation(0.1, 0.1)
])

# 3. Data pipeline optimization
AUTOTUNE = tf.data.AUTOTUNE
train_ds = train_ds.cache().shuffle(1000).prefetch(buffer_size=AUTOTUNE)
val_ds = val_ds.cache().prefetch(buffer_size=AUTOTUNE)

# 4. Building the model with transfer learning
base_model = keras.applications.EfficientNetV2B0(
    weights='imagenet', include_top=False, input_shape=(*IMG_SIZE, 3)
)
base_model.trainable = False

inputs = keras.layers.Input(shape=(*IMG_SIZE, 3))
x = data_augmentation(inputs)
x = keras.applications.efficientnet_v2.preprocess_input(x)
x = base_model(x, training=False)
x = keras.layers.GlobalAveragePooling2D()(x)
x = keras.layers.Dense(256, activation='relu')(x)
x = keras.layers.Dropout(0.3)(x)
outputs = keras.layers.Dense(num_classes, activation='softmax')(x)

model = keras.Model(inputs, outputs)

# 5. Training
model.compile(
    optimizer=keras.optimizers.Adam(1e-3),
    loss='sparse_categorical_crossentropy',
    metrics=['accuracy']
)

history = model.fit(
    train_ds, epochs=20, validation_data=val_ds,
    callbacks=[
        keras.callbacks.EarlyStopping(patience=5, restore_best_weights=True),
        keras.callbacks.ReduceLROnPlateau(patience=3, factor=0.5)
    ]
)

# 6. Visualizing results
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 4))
ax1.plot(history.history['accuracy'], label='Train')
ax1.plot(history.history['val_accuracy'], label='Val')
ax1.set_title('Accuracy')
ax1.legend()

ax2.plot(history.history['loss'], label='Train')
ax2.plot(history.history['val_loss'], label='Val')
ax2.set_title('Loss')
ax2.legend()
plt.savefig('training_history.png', dpi=150)
plt.show()

Practical Example: Sentiment Analysis (NLP)#

import tensorflow as tf
from tensorflow import keras
import tensorflow_datasets as tfds

# 1. Loading the IMDB Reviews dataset
(train_data, test_data), info = tfds.load(
    'imdb_reviews',
    split=['train', 'test'],
    as_supervised=True,
    with_info=True
)

# 2. Tokenization and data preparation
VOCAB_SIZE = 20000
MAX_LENGTH = 300

# TextVectorization - built-in tokenization layer
text_vectorizer = keras.layers.TextVectorization(
    max_tokens=VOCAB_SIZE,
    output_mode='int',
    output_sequence_length=MAX_LENGTH
)

# Adapt to training data
train_texts = train_data.map(lambda text, label: text)
text_vectorizer.adapt(train_texts)

# 3. Preparing datasets
def preprocess(text, label):
    text = text_vectorizer(tf.expand_dims(text, -1))
    text = tf.squeeze(text, axis=0)
    return text, label

BATCH_SIZE = 64
AUTOTUNE = tf.data.AUTOTUNE

train_ds = (train_data
    .map(preprocess, num_parallel_calls=AUTOTUNE)
    .shuffle(10000)
    .batch(BATCH_SIZE)
    .prefetch(AUTOTUNE))

test_ds = (test_data
    .map(preprocess, num_parallel_calls=AUTOTUNE)
    .batch(BATCH_SIZE)
    .prefetch(AUTOTUNE))

# 4. Model: 1D CNN + Bidirectional LSTM
model = keras.Sequential([
    keras.layers.Embedding(VOCAB_SIZE, 128, input_length=MAX_LENGTH),
    keras.layers.Conv1D(128, 5, activation='relu', padding='same'),
    keras.layers.MaxPooling1D(2),
    keras.layers.Bidirectional(keras.layers.LSTM(64)),
    keras.layers.Dense(64, activation='relu'),
    keras.layers.Dropout(0.5),
    keras.layers.Dense(1, activation='sigmoid')
])

model.compile(
    optimizer='adam',
    loss='binary_crossentropy',
    metrics=['accuracy']
)

# 5. Training
history = model.fit(
    train_ds, epochs=10, validation_data=test_ds,
    callbacks=[keras.callbacks.EarlyStopping(patience=3)]
)

# 6. Prediction
def predict_sentiment(texts):
    """Predict sentiment for a list of texts."""
    vectorized = text_vectorizer(tf.constant(texts))
    predictions = model.predict(vectorized)
    for text, pred in zip(texts, predictions):
        sentiment = "Positive" if pred[0] > 0.5 else "Negative"
        print(f"{sentiment} ({pred[0]:.2%}): {text[:80]}...")

predict_sentiment([
    "This movie was absolutely fantastic! Great acting and storyline.",
    "Terrible film. Waste of time. The plot made no sense at all."
])

TensorFlow.js - Machine Learning in the Browser#

TensorFlow.js allows you to run ML models directly in the browser or in Node.js, enabling client-side inference without server communication.

// Installation: npm install @tensorflow/tfjs

import * as tf from '@tensorflow/tfjs';

// Loading a pretrained image classification model
async function classifyImage(imageElement) {
    // Load MobileNet model
    const model = await tf.loadGraphModel(
        'https://tfhub.dev/google/tfjs-model/imagenet/mobilenet_v3_small_100_224/classification/5/default/1',
        { fromTFHub: true }
    );

    // Process image into a tensor
    const tensor = tf.browser.fromPixels(imageElement)
        .resizeBilinear([224, 224])
        .expandDims(0)
        .div(255.0);

    // Inference
    const predictions = model.predict(tensor);
    const topK = tf.topk(predictions, 5);

    const indices = await topK.indices.data();
    const values = await topK.values.data();

    // Free memory
    tensor.dispose();
    predictions.dispose();

    return indices.map((idx, i) => ({
        classIndex: idx,
        confidence: values[i]
    }));
}

// Converting a Keras model to TensorFlow.js
// In Python:
// import tensorflowjs as tfjs
// tfjs.converters.save_keras_model(model, 'tfjs_model/')

Advantages of TensorFlow.js:

  • Privacy - data never leaves the user's device
  • Low latency - no round-trip to the server
  • Offline - the model works without internet
  • Scaling - inference on user devices instead of expensive GPU servers

Production Model Deployment#

TensorFlow Serving#

TensorFlow Serving is a high-performance system for serving models in production.

# Save model in SavedModel format
model.save('saved_model/image_classifier/1')

# Directory structure:
# saved_model/
#   image_classifier/
#     1/                    <- model version
#       saved_model.pb
#       variables/
# docker-compose.yml - TensorFlow Serving
version: "3.8"
services:
  tf-serving:
    image: tensorflow/serving:latest
    ports:
      - "8501:8501"  # REST API
      - "8500:8500"  # gRPC
    volumes:
      - ./saved_model:/models
    environment:
      MODEL_NAME: image_classifier
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              count: 1
              capabilities: [gpu]
# Calling the REST API
import requests
import numpy as np
import json

def predict_via_serving(image_array):
    """Send a prediction request to TensorFlow Serving."""
    url = "http://localhost:8501/v1/models/image_classifier:predict"
    payload = {
        "instances": image_array.tolist()
    }
    response = requests.post(url, json=payload)
    predictions = response.json()['predictions']
    return np.array(predictions)

# Batch prediction
images = np.random.rand(8, 224, 224, 3).astype(np.float32)
results = predict_via_serving(images)
print(f"Predictions shape: {results.shape}")

Exporting to ONNX#

ONNX (Open Neural Network Exchange) is an open format that allows running models across different runtimes.

# TensorFlow -> ONNX conversion
# pip install tf2onnx

import tf2onnx
import onnxruntime as ort

# Conversion
spec = (tf.TensorSpec((None, 224, 224, 3), tf.float32, name="input"),)
model_proto, _ = tf2onnx.convert.from_keras(
    model, input_signature=spec, output_path="model.onnx"
)

# Inference with ONNX Runtime (faster than TF for CPU)
session = ort.InferenceSession("model.onnx")
input_name = session.get_inputs()[0].name
output_name = session.get_outputs()[0].name

result = session.run(
    [output_name],
    {input_name: np.random.rand(1, 224, 224, 3).astype(np.float32)}
)
print(f"ONNX prediction: {result[0]}")

TensorFlow Lite - Models on Mobile Devices#

# Conversion to TFLite with quantization
converter = tf.lite.TFLiteConverter.from_saved_model('saved_model/image_classifier/1')

# Post-training quantization (reduces model size by 4x)
converter.optimizations = [tf.lite.Optimize.DEFAULT]

# Optional: full int8 quantization (requires calibration)
def representative_dataset():
    for i in range(100):
        yield [np.random.rand(1, 224, 224, 3).astype(np.float32)]

converter.representative_dataset = representative_dataset
converter.target_spec.supported_types = [tf.float16]

tflite_model = converter.convert()

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

print(f"TFLite model size: {len(tflite_model) / 1024 / 1024:.2f} MB")

TensorFlow vs PyTorch - Comparison#

The choice of framework depends on the project context. Here are the key differences:

| Aspect | TensorFlow | PyTorch | |--------|-----------|---------| | Execution mode | Eager + Graph (tf.function) | Eager by default, TorchScript for graph | | High-level API | Keras (built-in) | torch.nn (built-in), Lightning | | Deployment | TF Serving, TFLite, TF.js | TorchServe, ONNX, ExecuTorch | | Mobile/Edge | TFLite (mature) | ExecuTorch (newer) | | Browser | TensorFlow.js (mature) | ONNX.js / Transformers.js | | Ecosystem | TFX, TF Hub, TF Data | Hugging Face, PyTorch Ecosystem | | Research popularity | Declining | Dominant | | Production popularity | Still strong | Growing | | Debugging | Harder (graph mode) | Easier (Pythonic) | | Documentation | Extensive but scattered | Consistent, well-organized |

When to choose TensorFlow:

  • Multi-platform deployment (web, mobile, embedded)
  • Existing TFX infrastructure in the organization
  • Need for TensorFlow.js for browser inference
  • Production projects requiring TF Serving

When to choose PyTorch:

  • Scientific research and prototyping
  • Working with Hugging Face models
  • Preference for Pythonic API and easy debugging
  • Projects requiring latest architectures from research papers

Best Practices in ML Projects#

1. Experiment Management#

import mlflow

# Logging experiments with MLflow
mlflow.set_experiment("image-classification")

with mlflow.start_run(run_name="efficientnet-v2-finetune"):
    # Log hyperparameters
    mlflow.log_params({
        "learning_rate": 1e-3,
        "batch_size": 32,
        "epochs": 20,
        "model": "EfficientNetV2B0",
        "fine_tune_layers": 50
    })

    # Training
    history = model.fit(train_ds, epochs=20, validation_data=val_ds)

    # Log metrics
    mlflow.log_metrics({
        "final_accuracy": history.history['accuracy'][-1],
        "final_val_accuracy": history.history['val_accuracy'][-1],
        "final_loss": history.history['loss'][-1]
    })

    # Log model
    mlflow.keras.log_model(model, "model")

2. Data Versioning#

# DVC (Data Version Control) - tracking data changes
# dvc init
# dvc add dataset/
# git add dataset.dvc .gitignore
# git commit -m "Add training dataset v1"
# dvc push

3. Reproducibility#

import random
import numpy as np

def set_seeds(seed=42):
    """Set seeds for reproducibility."""
    random.seed(seed)
    np.random.seed(seed)
    tf.random.set_seed(seed)
    # Deterministic operations (slower but reproducible)
    tf.config.experimental.enable_op_determinism()

set_seeds(42)

Conclusion#

TensorFlow combined with Keras provides a complete ecosystem for building, training, and deploying Machine Learning models. From simple Dense networks, through advanced CNN, RNN, and Transformer architectures, to deployment on servers, mobile devices, and in browsers, TensorFlow delivers tools at every stage of the ML model lifecycle.

Key takeaways:

  • Start with transfer learning - pretrained models deliver excellent results with minimal data
  • Optimize data pipelines - tf.data with prefetch and cache significantly accelerates training
  • Track experiments - MLflow or TensorBoard is a necessity in serious projects
  • Test deployment early - TF Serving, TFLite, and TF.js each have different constraints

Need to integrate Machine Learning into your application? The MDS Software Solutions Group team specializes in building intelligent solutions powered by AI and ML. From image classification, through text analysis, to recommendation systems - we will help you go from prototype to production. Contact us and let's discuss your project!

Author
MDS Software Solutions Group

Team of programming experts specializing in modern web technologies.

Machine Learning with Python and TensorFlow - Practical Guide | MDS Software Solutions Group | MDS Software Solutions Group