Spaces:
Sleeping
Sleeping
Deploy KidneyDL CT Scan Classifier
Browse files
README.md
CHANGED
|
@@ -9,54 +9,72 @@ pinned: true
|
|
| 9 |
license: mit
|
| 10 |
---
|
| 11 |
|
| 12 |
-
##
|
| 13 |
|
| 14 |
-
[](https://www.tensorflow.org/)
|
| 16 |
[](https://dvc.org/)
|
| 17 |
[](https://mlflow.org/)
|
| 18 |
[](https://dagshub.com/)
|
| 19 |
[](https://flask.palletsprojects.com/)
|
| 20 |
[](https://www.docker.com/)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 21 |
|
| 22 |
---
|
| 23 |
|
| 24 |
## What This Project Is
|
| 25 |
|
| 26 |
-
This is a production-style, end-to-end machine learning project that classifies kidney CT scan images as either **Normal** or **Tumor**.
|
| 27 |
|
| 28 |
-
It was built to demonstrate what a
|
| 29 |
|
| 30 |
---
|
| 31 |
|
| 32 |
## The Problem
|
| 33 |
|
| 34 |
-
Kidney disease is among the leading causes of death globally, and it often goes undetected until its later stages when treatment options become limited. Radiologists
|
| 35 |
|
| 36 |
-
This project builds a binary image classifier that
|
| 37 |
|
| 38 |
---
|
| 39 |
|
| 40 |
-
## Why VGG16
|
| 41 |
|
| 42 |
-
VGG16 was selected deliberately
|
| 43 |
|
| 44 |
-
|
| 45 |
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
It is also a stable, well-understood architecture. In a medical context, that matters. The behaviour of the model is predictable, and the features it learns can be interpreted through tools like Grad-CAM.
|
| 49 |
|
| 50 |
---
|
| 51 |
|
| 52 |
## Model Performance
|
| 53 |
|
| 54 |
-
| Metric
|
| 55 |
-
|---
|
| 56 |
-
| Accuracy | 89.9%
|
| 57 |
-
| Loss
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 58 |
|
| 59 |
-
|
| 60 |
|
| 61 |
---
|
| 62 |
|
|
@@ -65,6 +83,10 @@ Metrics are logged automatically to MLflow after every pipeline run. You can vie
|
|
| 65 |
```text
|
| 66 |
Kidney_classification_Using_MLOPS_and_DVC/
|
| 67 |
│
|
|
|
|
|
|
|
|
|
|
|
|
|
| 68 |
├── config/
|
| 69 |
│ └── config.yaml Central path and artifact configuration
|
| 70 |
│
|
|
@@ -74,6 +96,7 @@ Kidney_classification_Using_MLOPS_and_DVC/
|
|
| 74 |
├── main.py Runs all pipeline stages sequentially
|
| 75 |
├── app.py Flask web application
|
| 76 |
├── Dockerfile Container definition for the prediction server
|
|
|
|
| 77 |
├── requirements.txt Python dependencies
|
| 78 |
├── setup.py Installable package definition
|
| 79 |
├── scores.json Latest evaluation metrics
|
|
@@ -100,41 +123,60 @@ Kidney_classification_Using_MLOPS_and_DVC/
|
|
| 100 |
│ └── prediction.py Prediction pipeline used by the Flask app
|
| 101 |
│
|
| 102 |
├── research/
|
| 103 |
-
│ ├── 01_data_ingestion.ipynb
|
| 104 |
│ ├── 02_prepare_base_model.ipynb
|
| 105 |
│ ├── 03_model_trainer.ipynb
|
| 106 |
-
│ └── 04_model_evaluation.ipynb
|
| 107 |
│
|
| 108 |
└── templates/
|
| 109 |
-
└── index.html Web UI
|
| 110 |
```
|
| 111 |
|
| 112 |
---
|
| 113 |
|
| 114 |
## The ML Pipeline
|
| 115 |
|
| 116 |
-
The pipeline has four stages, each defined in `dvc.yaml` and executed in order by DVC.
|
| 117 |
|
| 118 |
```text
|
| 119 |
-
Stage 1
|
| 120 |
-
Data
|
|
|
|
|
|
|
| 121 |
```
|
| 122 |
|
| 123 |
### Stage 1: Data Ingestion
|
| 124 |
|
| 125 |
-
Downloads the kidney CT scan dataset from Google Drive using `gdown`, extracts the zip archive, and places the images into
|
| 126 |
|
| 127 |
### Stage 2: Base Model Preparation
|
| 128 |
|
| 129 |
-
Loads VGG16 with ImageNet weights
|
| 130 |
|
| 131 |
### Stage 3: Model Training
|
| 132 |
|
| 133 |
-
Loads the prepared base model
|
| 134 |
|
| 135 |
### Stage 4: Model Evaluation
|
| 136 |
|
| 137 |
-
Loads the trained model and evaluates it
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 138 |
|
| 139 |
---
|
| 140 |
|
|
@@ -145,9 +187,9 @@ All runs are tracked remotely on DagsHub, which acts as the MLflow tracking serv
|
|
| 145 |
- All hyperparameters from `params.yaml`
|
| 146 |
- Validation loss and accuracy
|
| 147 |
- The trained model as an MLflow artifact
|
| 148 |
-
- A registered model version in the MLflow Model Registry
|
| 149 |
|
| 150 |
-
|
| 151 |
[https://dagshub.com/sentongo-web/Kidney_classification_Using_MLOPS_and_DVC_Data-version-control.mlflow](https://dagshub.com/sentongo-web/Kidney_classification_Using_MLOPS_and_DVC_Data-version-control.mlflow)
|
| 152 |
|
| 153 |
---
|
|
@@ -156,7 +198,7 @@ You can view the experiment runs at:
|
|
| 156 |
|
| 157 |
Everything is driven by two YAML files. There are no hardcoded paths or hyperparameters anywhere in the source code.
|
| 158 |
|
| 159 |
-
|
| 160 |
|
| 161 |
```yaml
|
| 162 |
artifacts_root: artifacts
|
|
@@ -180,18 +222,9 @@ evaluation:
|
|
| 180 |
path_of_model: artifacts/training/model.h5
|
| 181 |
training_data: artifacts/data_ingestion/kidney-ct-scan-image
|
| 182 |
mlflow_uri: "https://dagshub.com/sentongo-web/Kidney_classification_Using_MLOPS_and_DVC_Data-version-control.mlflow"
|
| 183 |
-
all_params:
|
| 184 |
-
AUGMENTATION: True
|
| 185 |
-
IMAGE_SIZE: [224, 224, 3]
|
| 186 |
-
BATCH_SIZE: 16
|
| 187 |
-
INCLUDE_TOP: False
|
| 188 |
-
EPOCHS: 5
|
| 189 |
-
CLASSES: 2
|
| 190 |
-
WEIGHTS: imagenet
|
| 191 |
-
LEARNING_RATE: 0.01
|
| 192 |
```
|
| 193 |
|
| 194 |
-
|
| 195 |
|
| 196 |
```yaml
|
| 197 |
AUGMENTATION: True
|
|
@@ -218,7 +251,7 @@ cd Kidney_classification_Using_MLOPS_and_DVC_Data-version-control
|
|
| 218 |
### 2. Create and activate a Conda environment
|
| 219 |
|
| 220 |
```bash
|
| 221 |
-
conda create -n kidney python=3.
|
| 222 |
conda activate kidney
|
| 223 |
```
|
| 224 |
|
|
@@ -229,9 +262,9 @@ pip install -r requirements.txt
|
|
| 229 |
pip install -e .
|
| 230 |
```
|
| 231 |
|
| 232 |
-
### 4. Set up
|
| 233 |
|
| 234 |
-
Create a `.env` file in the project root
|
| 235 |
|
| 236 |
```env
|
| 237 |
MLFLOW_TRACKING_USERNAME=your_dagshub_username
|
|
@@ -246,7 +279,7 @@ This file is gitignored and will never be committed.
|
|
| 246 |
dvc repro
|
| 247 |
```
|
| 248 |
|
| 249 |
-
DVC
|
| 250 |
|
| 251 |
### 6. Launch the web application
|
| 252 |
|
|
@@ -254,15 +287,15 @@ DVC will execute all four stages in order. If any stage has already run and its
|
|
| 254 |
python app.py
|
| 255 |
```
|
| 256 |
|
| 257 |
-
Open
|
| 258 |
|
| 259 |
-
### 7. View experiment runs
|
| 260 |
|
| 261 |
```bash
|
| 262 |
mlflow ui
|
| 263 |
```
|
| 264 |
|
| 265 |
-
Open `http://localhost:5000` to browse all local experiment runs, or visit the DagsHub MLflow URL above
|
| 266 |
|
| 267 |
---
|
| 268 |
|
|
@@ -270,10 +303,10 @@ Open `http://localhost:5000` to browse all local experiment runs, or visit the D
|
|
| 270 |
|
| 271 |
```bash
|
| 272 |
docker build -t kidney-classifier .
|
| 273 |
-
docker run -p
|
| 274 |
```
|
| 275 |
|
| 276 |
-
Open `http://localhost:
|
| 277 |
|
| 278 |
---
|
| 279 |
|
|
@@ -281,13 +314,13 @@ Open `http://localhost:8080` in your browser.
|
|
| 281 |
|
| 282 |
The Flask app exposes three routes:
|
| 283 |
|
| 284 |
-
| Route
|
| 285 |
-
|
|
| 286 |
-
| `/`
|
| 287 |
-
| `/predict`| POST | Accepts an image file and returns the classification result as JSON
|
| 288 |
-
| `/train`
|
| 289 |
|
| 290 |
-
The prediction endpoint returns
|
| 291 |
|
| 292 |
```json
|
| 293 |
[{"image": "Normal"}]
|
|
@@ -299,49 +332,85 @@ or
|
|
| 299 |
[{"image": "Tumor"}]
|
| 300 |
```
|
| 301 |
|
| 302 |
-
The UI supports drag and drop, shows a live preview of the uploaded scan, displays the result with a confidence bar, and works in both light and dark mode with automatic
|
| 303 |
|
| 304 |
---
|
| 305 |
|
| 306 |
## Tech Stack
|
| 307 |
|
| 308 |
-
| Area | Tools
|
| 309 |
-
|
|
| 310 |
-
| Deep Learning | TensorFlow and Keras with VGG16 transfer learning
|
| 311 |
-
| Data Versioning | DVC
|
| 312 |
-
| Experiment Tracking | MLflow hosted on DagsHub
|
| 313 |
-
| Web Framework | Flask with Flask-CORS
|
| 314 |
-
| Data Processing | NumPy, Pandas, scikit-learn
|
| 315 |
-
| Configuration | PyYAML and python-box
|
| 316 |
-
| Package Management | setuptools with src layout, editable install
|
| 317 |
-
| Containerisation | Docker
|
| 318 |
-
|
|
|
|
|
|
|
|
| 319 |
|
| 320 |
---
|
| 321 |
|
| 322 |
## MLOps Concepts Demonstrated
|
| 323 |
|
| 324 |
-
| Concept
|
| 325 |
-
| ---
|
| 326 |
-
| Data versioning
|
| 327 |
-
| Pipeline as code
|
| 328 |
-
| Incremental execution
|
| 329 |
-
| Experiment tracking
|
| 330 |
-
| Model registry
|
| 331 |
-
| Configuration management | All paths and hyperparameters live in YAML files with no hardcoded values
|
| 332 |
-
| Modular ML package
|
| 333 |
-
| Reproducibility
|
| 334 |
-
| Containerisation
|
| 335 |
-
| REST API serving
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 336 |
|
| 337 |
---
|
| 338 |
|
| 339 |
## About the Author
|
| 340 |
|
| 341 |
-
**Paul Sentongo** is a data scientist and applied AI researcher with a Master's degree in Data Science. He is passionate about building machine learning systems that go beyond the notebook: reproducible, traceable, and deployable. His research interests include deep learning for medical imaging, MLOps infrastructure, and the practical challenges of making AI work
|
| 342 |
|
| 343 |
Paul is currently open to research positions and industry roles where he can contribute to meaningful AI projects and grow alongside motivated teams.
|
| 344 |
|
| 345 |
- GitHub: [github.com/sentongo-web](https://github.com/sentongo-web)
|
| 346 |
- LinkedIn: [linkedin.com/in/paul-sentongo-885041284](https://www.linkedin.com/in/paul-sentongo-885041284/)
|
| 347 |
-
- Email: sentongogray1992@gmail.com
|
|
|
|
| 9 |
license: mit
|
| 10 |
---
|
| 11 |
|
| 12 |
+
## KidneyDL: End-to-End Kidney CT Scan Classification with MLOps
|
| 13 |
|
| 14 |
+
[](https://www.python.org/)
|
| 15 |
[](https://www.tensorflow.org/)
|
| 16 |
[](https://dvc.org/)
|
| 17 |
[](https://mlflow.org/)
|
| 18 |
[](https://dagshub.com/)
|
| 19 |
[](https://flask.palletsprojects.com/)
|
| 20 |
[](https://www.docker.com/)
|
| 21 |
+
[](https://huggingface.co/spaces/Sentoz/kidney-classifier)
|
| 22 |
+
[](https://opensource.org/licenses/MIT)
|
| 23 |
+
|
| 24 |
+
---
|
| 25 |
+
|
| 26 |
+
## Live Demo
|
| 27 |
+
|
| 28 |
+
The application is deployed and publicly accessible at:
|
| 29 |
+
|
| 30 |
+
**[https://huggingface.co/spaces/Sentoz/kidney-classifier](https://huggingface.co/spaces/Sentoz/kidney-classifier)**
|
| 31 |
+
|
| 32 |
+
Upload a kidney CT scan image and receive an instant classification — Normal or Tumor — directly in your browser. No setup required.
|
| 33 |
|
| 34 |
---
|
| 35 |
|
| 36 |
## What This Project Is
|
| 37 |
|
| 38 |
+
This is a production-style, end-to-end machine learning project that classifies kidney CT scan images as either **Normal** or **Tumor**. The model is only one piece of the story. The real focus is everything surrounding it: a fully reproducible DVC pipeline, experiment tracking with MLflow and DagsHub, a configuration-driven codebase, a Flask web application, Docker containerisation, and live deployment on Hugging Face Spaces with GitHub Actions CI/CD.
|
| 39 |
|
| 40 |
+
It was built to demonstrate what a genuine MLOps workflow looks like in practice — not just the notebook that produces a metric, but the entire system that allows a model to be trained, evaluated, versioned, and served reliably.
|
| 41 |
|
| 42 |
---
|
| 43 |
|
| 44 |
## The Problem
|
| 45 |
|
| 46 |
+
Kidney disease is among the leading causes of death globally, and it often goes undetected until its later stages when treatment options become severely limited. Radiologists reviewing CT scans are under enormous pressure, and any tool that reliably flags suspicious scans for closer attention has genuine clinical value.
|
| 47 |
|
| 48 |
+
This project builds a binary image classifier that examines a kidney CT scan and determines, within seconds, whether the kidney appears normal or shows signs of a tumour. Trained on a labelled CT scan dataset and fine-tuned from VGG16, the model achieves approximately **89.9% validation accuracy**.
|
| 49 |
|
| 50 |
---
|
| 51 |
|
| 52 |
+
## Why VGG16
|
| 53 |
|
| 54 |
+
VGG16 was selected deliberately. Its architecture is built from uniform 3x3 convolutional layers stacked into increasing depth — a design that is especially strong at learning fine-grained local textures. This matters in medical imaging because the difference between healthy and abnormal tissue often comes down to subtle structural patterns, not large-scale shape differences.
|
| 55 |
|
| 56 |
+
Pre-trained on ImageNet, VGG16 already knows how to see. Its lower layers encode general-purpose feature detectors for edges, corners, and textures. Those weights do not need to be learned from scratch. Only the top classification layers need to be adapted to the kidney scan domain, which means the model achieves strong performance with far less labelled data than training from scratch would require.
|
| 57 |
|
| 58 |
+
It is also a stable, well-understood architecture. In a medical context that matters: the behaviour of the model is predictable, its performance is reproducible, and its features can be interpreted through tools like Grad-CAM if needed.
|
|
|
|
|
|
|
| 59 |
|
| 60 |
---
|
| 61 |
|
| 62 |
## Model Performance
|
| 63 |
|
| 64 |
+
| Metric | Value |
|
| 65 |
+
| --- | --- |
|
| 66 |
+
| Accuracy | 89.9% |
|
| 67 |
+
| Loss | 1.26 |
|
| 68 |
+
| Architecture | VGG16 (fine-tuned) |
|
| 69 |
+
| Model Version | v1 — registered in MLflow Model Registry as `VGG16Model` |
|
| 70 |
+
| Training Epochs | 5 |
|
| 71 |
+
| Optimiser | SGD (learning rate 0.01) |
|
| 72 |
+
| Input Size | 224 x 224 x 3 |
|
| 73 |
+
| Classes | Normal, Tumor |
|
| 74 |
+
|
| 75 |
+
Metrics are logged automatically to MLflow after every pipeline run. All experiment runs, parameters, and model artifacts are tracked remotely on DagsHub:
|
| 76 |
|
| 77 |
+
[https://dagshub.com/sentongo-web/Kidney_classification_Using_MLOPS_and_DVC_Data-version-control.mlflow](https://dagshub.com/sentongo-web/Kidney_classification_Using_MLOPS_and_DVC_Data-version-control.mlflow)
|
| 78 |
|
| 79 |
---
|
| 80 |
|
|
|
|
| 83 |
```text
|
| 84 |
Kidney_classification_Using_MLOPS_and_DVC/
|
| 85 |
│
|
| 86 |
+
├── .github/
|
| 87 |
+
│ └── workflows/
|
| 88 |
+
│ └── cd.yml GitHub Actions CD pipeline (deploys to HF Spaces on push)
|
| 89 |
+
│
|
| 90 |
├── config/
|
| 91 |
│ └── config.yaml Central path and artifact configuration
|
| 92 |
│
|
|
|
|
| 96 |
├── main.py Runs all pipeline stages sequentially
|
| 97 |
├── app.py Flask web application
|
| 98 |
├── Dockerfile Container definition for the prediction server
|
| 99 |
+
├── deploy_to_hf.py One-command deployment script for Hugging Face Spaces
|
| 100 |
├── requirements.txt Python dependencies
|
| 101 |
├── setup.py Installable package definition
|
| 102 |
├── scores.json Latest evaluation metrics
|
|
|
|
| 123 |
│ └── prediction.py Prediction pipeline used by the Flask app
|
| 124 |
│
|
| 125 |
├── research/
|
| 126 |
+
│ ├── 01_data_ingestion.ipynb Stage prototyped and validated here first
|
| 127 |
│ ├── 02_prepare_base_model.ipynb
|
| 128 |
│ ├── 03_model_trainer.ipynb
|
| 129 |
+
│ └── 04_model_evaluation.ipynb
|
| 130 |
│
|
| 131 |
└── templates/
|
| 132 |
+
└── index.html Web UI: dark/light mode, drag-and-drop, confidence bar
|
| 133 |
```
|
| 134 |
|
| 135 |
---
|
| 136 |
|
| 137 |
## The ML Pipeline
|
| 138 |
|
| 139 |
+
The pipeline has four stages, each defined in `dvc.yaml` and executed in order by DVC. Every stage declares its dependencies and outputs explicitly, so DVC knows exactly which stages to skip and which to rerun when something changes.
|
| 140 |
|
| 141 |
```text
|
| 142 |
+
Stage 1 → Stage 2 → Stage 3 → Stage 4
|
| 143 |
+
Data Base Model Model
|
| 144 |
+
Ingestion Model Training Evaluation
|
| 145 |
+
Prep
|
| 146 |
```
|
| 147 |
|
| 148 |
### Stage 1: Data Ingestion
|
| 149 |
|
| 150 |
+
Downloads the kidney CT scan dataset from Google Drive using `gdown`, extracts the zip archive, and places the images into `artifacts/data_ingestion/`. DVC tracks the output so this stage is skipped entirely if the data already exists and nothing has changed.
|
| 151 |
|
| 152 |
### Stage 2: Base Model Preparation
|
| 153 |
|
| 154 |
+
Loads VGG16 with ImageNet weights, removes its original classification head, and adds a custom head: global average pooling followed by a dense softmax output layer for two classes (Normal, Tumor). All base VGG16 layers are frozen. Both the base model and the updated model are saved to disk.
|
| 155 |
|
| 156 |
### Stage 3: Model Training
|
| 157 |
|
| 158 |
+
Loads the prepared base model and recompiles it with an SGD optimiser. Trains on the kidney CT images with optional data augmentation (horizontal flip, zoom, shear). The trained model is saved to `artifacts/training/model.h5`.
|
| 159 |
|
| 160 |
### Stage 4: Model Evaluation
|
| 161 |
|
| 162 |
+
Loads the trained model and evaluates it on the 30 percent validation split. Loss and accuracy are written to `scores.json` and logged to MLflow. The model is also registered in the MLflow Model Registry under the name `VGG16Model` for versioning and downstream use.
|
| 163 |
+
|
| 164 |
+
---
|
| 165 |
+
|
| 166 |
+
## CI/CD Pipeline
|
| 167 |
+
|
| 168 |
+
Every push to `main` on GitHub triggers the GitHub Actions CD workflow defined in `.github/workflows/cd.yml`. The workflow:
|
| 169 |
+
|
| 170 |
+
1. Checks out the repository with full history and LFS support
|
| 171 |
+
2. Pushes the codebase to Hugging Face Spaces via git
|
| 172 |
+
|
| 173 |
+
Hugging Face then detects the `Dockerfile` and automatically builds and deploys the updated container. The deployment is fully automated after initial setup.
|
| 174 |
+
|
| 175 |
+
For the initial deployment or when the trained model needs to be included (since it is gitignored), the `deploy_to_hf.py` script uses the Hugging Face Hub Python API to upload all necessary files including the model artifact:
|
| 176 |
+
|
| 177 |
+
```bash
|
| 178 |
+
python deploy_to_hf.py
|
| 179 |
+
```
|
| 180 |
|
| 181 |
---
|
| 182 |
|
|
|
|
| 187 |
- All hyperparameters from `params.yaml`
|
| 188 |
- Validation loss and accuracy
|
| 189 |
- The trained model as an MLflow artifact
|
| 190 |
+
- A registered model version in the MLflow Model Registry under `VGG16Model`
|
| 191 |
|
| 192 |
+
View all experiment runs at:
|
| 193 |
[https://dagshub.com/sentongo-web/Kidney_classification_Using_MLOPS_and_DVC_Data-version-control.mlflow](https://dagshub.com/sentongo-web/Kidney_classification_Using_MLOPS_and_DVC_Data-version-control.mlflow)
|
| 194 |
|
| 195 |
---
|
|
|
|
| 198 |
|
| 199 |
Everything is driven by two YAML files. There are no hardcoded paths or hyperparameters anywhere in the source code.
|
| 200 |
|
| 201 |
+
`config/config.yaml` manages all file paths and artifact locations:
|
| 202 |
|
| 203 |
```yaml
|
| 204 |
artifacts_root: artifacts
|
|
|
|
| 222 |
path_of_model: artifacts/training/model.h5
|
| 223 |
training_data: artifacts/data_ingestion/kidney-ct-scan-image
|
| 224 |
mlflow_uri: "https://dagshub.com/sentongo-web/Kidney_classification_Using_MLOPS_and_DVC_Data-version-control.mlflow"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 225 |
```
|
| 226 |
|
| 227 |
+
`params.yaml` is where all model hyperparameters live:
|
| 228 |
|
| 229 |
```yaml
|
| 230 |
AUGMENTATION: True
|
|
|
|
| 251 |
### 2. Create and activate a Conda environment
|
| 252 |
|
| 253 |
```bash
|
| 254 |
+
conda create -n kidney python=3.10 -y
|
| 255 |
conda activate kidney
|
| 256 |
```
|
| 257 |
|
|
|
|
| 262 |
pip install -e .
|
| 263 |
```
|
| 264 |
|
| 265 |
+
### 4. Set up MLflow credentials
|
| 266 |
|
| 267 |
+
Create a `.env` file in the project root:
|
| 268 |
|
| 269 |
```env
|
| 270 |
MLFLOW_TRACKING_USERNAME=your_dagshub_username
|
|
|
|
| 279 |
dvc repro
|
| 280 |
```
|
| 281 |
|
| 282 |
+
DVC executes all four stages in order. Stages whose inputs have not changed are skipped automatically. After the pipeline completes, `scores.json` contains the latest evaluation metrics.
|
| 283 |
|
| 284 |
### 6. Launch the web application
|
| 285 |
|
|
|
|
| 287 |
python app.py
|
| 288 |
```
|
| 289 |
|
| 290 |
+
Open `http://localhost:7860` in your browser. Upload a kidney CT scan image and get a classification result instantly.
|
| 291 |
|
| 292 |
+
### 7. View experiment runs locally
|
| 293 |
|
| 294 |
```bash
|
| 295 |
mlflow ui
|
| 296 |
```
|
| 297 |
|
| 298 |
+
Open `http://localhost:5000` to browse all local experiment runs, or visit the DagsHub MLflow URL above for all remotely tracked runs.
|
| 299 |
|
| 300 |
---
|
| 301 |
|
|
|
|
| 303 |
|
| 304 |
```bash
|
| 305 |
docker build -t kidney-classifier .
|
| 306 |
+
docker run -p 7860:7860 kidney-classifier
|
| 307 |
```
|
| 308 |
|
| 309 |
+
Open `http://localhost:7860` in your browser.
|
| 310 |
|
| 311 |
---
|
| 312 |
|
|
|
|
| 314 |
|
| 315 |
The Flask app exposes three routes:
|
| 316 |
|
| 317 |
+
| Route | Method | Description |
|
| 318 |
+
|------------|--------|----------------------------------------------------------------------|
|
| 319 |
+
| `/` | GET | Serves the prediction web UI |
|
| 320 |
+
| `/predict` | POST | Accepts an image file and returns the classification result as JSON |
|
| 321 |
+
| `/train` | GET | Reruns `main.py` to retrain the model from scratch |
|
| 322 |
|
| 323 |
+
The prediction endpoint returns:
|
| 324 |
|
| 325 |
```json
|
| 326 |
[{"image": "Normal"}]
|
|
|
|
| 332 |
[{"image": "Tumor"}]
|
| 333 |
```
|
| 334 |
|
| 335 |
+
The UI supports drag and drop, shows a live preview of the uploaded scan, displays the result with a confidence bar, and works in both light and dark mode with automatic system preference detection.
|
| 336 |
|
| 337 |
---
|
| 338 |
|
| 339 |
## Tech Stack
|
| 340 |
|
| 341 |
+
| Area | Tools |
|
| 342 |
+
|---------------------|------------------------------------------------------|
|
| 343 |
+
| Deep Learning | TensorFlow and Keras with VGG16 transfer learning |
|
| 344 |
+
| Data Versioning | DVC |
|
| 345 |
+
| Experiment Tracking | MLflow hosted on DagsHub |
|
| 346 |
+
| Web Framework | Flask with Flask-CORS |
|
| 347 |
+
| Data Processing | NumPy, Pandas, scikit-learn |
|
| 348 |
+
| Configuration | PyYAML and python-box |
|
| 349 |
+
| Package Management | setuptools with src layout, editable install |
|
| 350 |
+
| Containerisation | Docker |
|
| 351 |
+
| Deployment | Hugging Face Spaces (Docker SDK) |
|
| 352 |
+
| CI/CD | GitHub Actions |
|
| 353 |
+
| Environment | Conda with pip |
|
| 354 |
|
| 355 |
---
|
| 356 |
|
| 357 |
## MLOps Concepts Demonstrated
|
| 358 |
|
| 359 |
+
| Concept | Implementation |
|
| 360 |
+
| --- | --- |
|
| 361 |
+
| Data versioning | DVC tracks the dataset and all model artifacts |
|
| 362 |
+
| Pipeline as code | `dvc.yaml` defines every stage, its dependencies, and its outputs |
|
| 363 |
+
| Incremental execution | DVC only reruns stages whose inputs have changed |
|
| 364 |
+
| Experiment tracking | MLflow logs parameters, metrics, and model artifacts on every run |
|
| 365 |
+
| Model registry | Trained models are registered and versioned in the MLflow Model Registry |
|
| 366 |
+
| Configuration management | All paths and hyperparameters live in YAML files with no hardcoded values |
|
| 367 |
+
| Modular ML package | Source code is structured as an installable Python package with a clean src layout |
|
| 368 |
+
| Reproducibility | Any contributor can clone the repo and run `dvc repro` to get identical results |
|
| 369 |
+
| Containerisation | Dockerfile ensures the app runs consistently across all environments |
|
| 370 |
+
| REST API serving | Flask wraps the prediction pipeline and exposes it over HTTP |
|
| 371 |
+
| Automated deployment | GitHub Actions pushes to Hugging Face Spaces on every merge to main |
|
| 372 |
+
| Notebook-to-production | Each pipeline stage was prototyped in a Jupyter notebook before being productionised |
|
| 373 |
+
|
| 374 |
+
---
|
| 375 |
+
|
| 376 |
+
## Future Work
|
| 377 |
+
|
| 378 |
+
The current system is a solid, working foundation. These are the planned improvements for future versions:
|
| 379 |
+
|
| 380 |
+
### Model Improvements
|
| 381 |
+
|
| 382 |
+
- Extend to a multi-class classifier covering cysts, stones, and tumours in addition to normal scans
|
| 383 |
+
- Experiment with EfficientNetV2 and Vision Transformers for potentially higher accuracy
|
| 384 |
+
- Implement Grad-CAM visualisations in the web UI to show which regions of the scan influenced the prediction
|
| 385 |
+
- Increase training epochs and experiment with learning rate schedules and early stopping
|
| 386 |
+
|
| 387 |
+
### MLOps Infrastructure
|
| 388 |
+
|
| 389 |
+
- Add a model monitoring layer to detect data drift and prediction degradation in production
|
| 390 |
+
- Implement automated retraining triggers when model performance drops below a defined threshold
|
| 391 |
+
- Add a full test suite covering unit tests for pipeline components and integration tests for the API
|
| 392 |
+
- Set up a staging environment on HF Spaces to validate model changes before pushing to production
|
| 393 |
+
|
| 394 |
+
### Application
|
| 395 |
+
|
| 396 |
+
- Add a confidence score to the prediction response and display it numerically alongside the confidence bar
|
| 397 |
+
- Support batch prediction: accept multiple scans in a single request
|
| 398 |
+
- Add an admin dashboard showing prediction history, volume, and accuracy trends
|
| 399 |
+
- Implement user authentication for the `/train` endpoint to prevent unauthorised retraining
|
| 400 |
+
|
| 401 |
+
### Deployment
|
| 402 |
+
|
| 403 |
+
- Explore deployment on a GPU-backed inference endpoint for sub-second response times on large batches
|
| 404 |
+
- Package the prediction service as a standalone REST API with OpenAPI documentation
|
| 405 |
|
| 406 |
---
|
| 407 |
|
| 408 |
## About the Author
|
| 409 |
|
| 410 |
+
**Paul Sentongo** is a data scientist and applied AI researcher with a Master's degree in Data Science. He is passionate about building machine learning systems that go beyond the notebook: reproducible, traceable, and deployable in the real world. His research interests include deep learning for medical imaging, MLOps infrastructure, and the practical challenges of making AI work reliably at scale.
|
| 411 |
|
| 412 |
Paul is currently open to research positions and industry roles where he can contribute to meaningful AI projects and grow alongside motivated teams.
|
| 413 |
|
| 414 |
- GitHub: [github.com/sentongo-web](https://github.com/sentongo-web)
|
| 415 |
- LinkedIn: [linkedin.com/in/paul-sentongo-885041284](https://www.linkedin.com/in/paul-sentongo-885041284/)
|
| 416 |
+
- Email: [sentongogray1992@gmail.com](mailto:sentongogray1992@gmail.com)
|