End-to-end computer vision classification pipeline that turns raw pixel data into a trained CNN model, evaluation artifacts, and a FastAPI inference service.
This repository is built as a recruiter-grade machine learning engineering case study. The dataset is intentionally simple, but the work is framed like a production workflow: define the problem, prepare raw image tensors, train and compare models, evaluate failure patterns, package inference, and expose predictions through an API.
Project Link: github.com/mutassimalzeem/vision-classification-pipeline
- Executive Summary
- Business Problem
- Project Results
- Visual Evidence
- System Architecture
- Inference API
- Repository Structure
- Built With
- Getting Started
- Usage
- Evaluation Strategy
- Roadmap
- Portfolio Highlights
- Acknowledgments
Many real-world vision systems begin with a narrow recognition task: identify a mark, symbol, number, product state, form entry, or visual defect. This project uses handwritten digit recognition as a controlled environment for demonstrating the complete ML delivery lifecycle.
The core objective is not just "train a digit classifier." The objective is to show how a model moves from raw pixel data to an inference-ready product component.
| Area | Implementation |
|---|---|
| Problem type | Supervised multi-class image classification |
| Dataset | Kaggle Digit Recognizer, 28x28 grayscale digit images |
| Model family | TensorFlow/Keras CNN |
| Best validation result | 99.51% accuracy on an 8,400-image validation split |
| API | FastAPI POST /predict image upload endpoint |
| Output | Predicted digit, confidence score, class probabilities |
| Portfolio focus | ML lifecycle, evaluation, inference design, documentation |
Organizations often need lightweight image classification systems that can convert visual inputs into structured decisions. Examples include scanned forms, handwritten identifiers, simple quality-control marks, and digitized operational workflows.
This project models that pattern through a handwritten digit classifier:
- Input: raw image pixels or uploaded digit images
- Processing: normalization, reshaping, digit extraction, CNN inference
- Output: structured prediction response suitable for downstream applications
- Business value: faster conversion of visual input into machine-readable labels
| Requirement | Why It Matters |
|---|---|
| Accurate digit classification | Proves the model learns useful visual structure |
| Consistent preprocessing | Prevents training-serving skew |
| Confusion matrix and error review | Shows where the model fails, not only where it succeeds |
| API contract | Makes the model usable outside a notebook |
| Reproducible documentation | Makes the project understandable to technical and non-technical reviewers |
| Metric | Value |
|---|---|
| Validation images | 8,400 |
| Correct validation predictions | 8,359 |
| Validation errors | 41 |
| Validation accuracy | 99.51% |
| API test image prediction | Digit 9 |
| API test confidence | 99.98% |
The saved CNN model performs strongly on the validation split and has been tested through the live FastAPI endpoint using a custom uploaded image.
The final CNN converges cleanly, with validation accuracy stabilizing near the top of the range and validation loss remaining low.
The confusion matrix shows a strong diagonal, which means the model is correctly separating most digit classes. Remaining errors are concentrated in visually similar handwriting patterns.
The training data consists of grayscale 28x28 digit images represented as flattened pixel values in the original CSV dataset.
The API returns a structured prediction response with a digit label, confidence score, and full probability distribution.
flowchart TD
A["Raw CSV Pixels<br/>784 values per image"] --> B["Data Understanding<br/>labels, pixel ranges, class balance"]
B --> C["Preprocessing<br/>normalize, reshape to 28x28x1"]
C --> D["Train Validation Split<br/>stratified 80/20"]
D --> E["Baseline Model<br/>dense neural network"]
D --> F["CNN Model<br/>convolution, pooling, dense layers"]
F --> G["Regularization and Augmentation<br/>rotation, shift, zoom, dropout"]
G --> H["Evaluation<br/>accuracy, loss, confusion matrix"]
H --> I["Error Analysis<br/>ambiguous digits and class confusions"]
I --> J["Model Artifact<br/>digit_model.h5"]
J --> K["FastAPI Service<br/>POST /predict"]
K --> L["Structured Response<br/>digit, confidence, probabilities"]
sequenceDiagram
participant Client
participant API as FastAPI Endpoint
participant Prep as Image Preprocessor
participant Model as Keras CNN
Client->>API: POST /predict with PNG/JPG image
API->>Prep: Read uploaded bytes
Prep->>Prep: EXIF transpose and grayscale conversion
Prep->>Prep: Detect light background and invert if needed
Prep->>Prep: Crop foreground digit and remove edge artifacts
Prep->>Prep: Resize and center on 28x28 canvas
Prep->>Model: Tensor shape 1x28x28x1
Model-->>API: Class probabilities
API-->>Client: predicted_digit, confidence, probabilities
flowchart LR
subgraph Research["Research Layer"]
N["notebooks/analysis.ipynb"]
D["docs/"]
R["reports/"]
end
subgraph Artifact["Artifact Layer"]
M["digit-api/model/digit_model.h5"]
F["assets/figures/"]
end
subgraph Service["Service Layer"]
A["digit-api/main.py"]
P["preprocess_digit_image"]
E["POST /predict"]
end
N --> M
N --> F
D --> A
M --> A
A --> P
P --> E
The project includes a FastAPI service that loads the saved Keras model and exposes prediction through an image upload endpoint.
POST /predict
curl -X POST "http://127.0.0.1:8000/predict" \
-H "accept: application/json" \
-H "Content-Type: multipart/form-data" \
-F "file=@digit.png;type=image/png"{
"filename": "digit.png",
"predicted_digit": 9,
"confidence": 0.9998,
"probabilities": {
"0": 0.0000,
"1": 0.0000,
"2": 0.0000,
"3": 0.0001,
"4": 0.0000,
"5": 0.0000,
"6": 0.0000,
"7": 0.0000,
"8": 0.0000,
"9": 0.9998
}
}The API preprocessing handles more than a naive resize:
- Converts uploaded images to grayscale
- Handles transparent images by compositing on white
- Detects light backgrounds and inverts to MNIST-like polarity
- Removes edge artifacts from screenshots
- Crops the visible digit instead of the whole canvas
- Resizes proportionally and centers on a 28x28 canvas
- Returns clear
400errors for unreadable or blank inputs
vision-classification-pipeline/
|
|-- README.md
|-- PROJECT_CHARTER.md
|-- ROADMAP.md
|-- requirements.txt
|
|-- digit-api/
| |-- main.py
| |-- requirements.txt
| `-- model/
| |-- main.py
| `-- digit_model.h5
|
|-- src/
| |-- train.csv
| |-- test.csv
| `-- sample_submission.csv
|
|-- notebooks/
| |-- analysis.ipynb
| `-- model.png
|
|-- assets/
| |-- figures/
| | |-- training-history.png
| | |-- confusion-matrix.png
| | `-- sample-digits.png
| `-- screenshots/
| |-- prediction-demo.png
| |-- swagger-ui.png
| `-- test_image.png
|
|-- docs/
| |-- 01_problem_framing/
| |-- 02_data_understanding/
| |-- 03_experiment_design/
| |-- 04_modeling_strategy/
| |-- 05_evaluation/
| |-- 06_inference_api/
| |-- 07_deployment/
| `-- 08_portfolio_case_study/
|
`-- reports/
|-- experiment_logs/
`-- model_cards/
| Folder | Purpose |
|---|---|
digit-api/ |
Deployable inference service and saved model artifact |
src/ |
Raw Kaggle Digit Recognizer CSV files |
notebooks/ |
Experimentation, model training, and analysis |
docs/ |
ML planning, evaluation, deployment, and portfolio documentation |
assets/ |
Visual evidence for reviewers and recruiters |
reports/ |
Model-card and experiment-log templates |
- Python 3.10 or newer
- Git
- Recommended: virtual environment
- Clone the repository.
git clone https://github.com/mutassimalzeem/vision-classification-pipeline.git
cd vision-classification-pipeline- Create and activate a virtual environment.
python -m venv .venv
.venv\Scripts\activate- Install dependencies.
pip install -r requirements.txt
pip install -r digit-api/requirements.txt- Confirm the model artifact exists.
digit-api/model/digit_model.h5
cd digit-api
python -m uvicorn main:app --host 127.0.0.1 --port 8000Open the interactive API documentation:
http://127.0.0.1:8000/docs
curl -X POST "http://127.0.0.1:8000/predict" \
-H "accept: application/json" \
-H "Content-Type: multipart/form-data" \
-F "file=@path/to/digit.png;type=image/png"Open the notebook:
notebooks/analysis.ipynb
The notebook covers data loading, preprocessing, train-validation split, model training, evaluation, confusion matrix generation, and final model export.
This project evaluates model quality beyond one accuracy number.
flowchart TD
A["Validation Accuracy"] --> E["Model Quality Review"]
B["Training and Validation Loss"] --> E
C["Confusion Matrix"] --> E
D["Misclassified Samples"] --> E
E --> F["Failure Pattern Notes"]
F --> G["Inference Risk Awareness"]
- Whether validation accuracy improved across model iterations
- Whether training and validation curves suggested overfitting
- Which digit pairs were confused most often
- Whether errors came from ambiguous handwriting or preprocessing mismatch
- Whether real uploaded images matched the model's expected training format
The most important deployment lesson was training-serving consistency. The original API used a simple grayscale resize, which caused custom colored images to be misread. The endpoint now uses digit extraction, polarity normalization, edge cleanup, and centered 28x28 formatting to better match the training distribution.
- Define business-style ML problem framing
- Prepare raw pixel data for CNN modeling
- Train baseline and improved CNN models
- Generate training-history and confusion-matrix visuals
- Package saved Keras model
- Build FastAPI prediction endpoint
- Add preprocessing for custom uploaded images
- Add automated API tests
- Add model version metadata to API responses
- Add confidence threshold warnings
- Deploy the API to a cloud service
- Add a lightweight drawing-canvas frontend
This repository demonstrates practical ML engineering skills that transfer beyond digit recognition:
- Problem framing: explains why a simple dataset can still demonstrate a real ML workflow
- Data preparation: converts flattened pixel columns into model-ready image tensors
- Modeling: compares baseline, CNN, augmented, and improved approaches
- Evaluation: uses visual and quantitative diagnostics
- Inference engineering: turns a notebook-trained model into an API service
- Debugging: fixes real custom-image prediction failures caused by preprocessing mismatch
- Documentation: presents the project as a business-relevant case study
- Kaggle Digit Recognizer dataset for the raw digit classification problem
- Best-README-Template for README organization inspiration
- TensorFlow/Keras and FastAPI documentation for model and API implementation patterns



