Sentoz commited on
Commit
6241d3b
·
verified ·
1 Parent(s): 3e93e14

Deploy KidneyDL CT Scan Classifier

Browse files
Files changed (1) hide show
  1. README.md +150 -81
README.md CHANGED
@@ -9,54 +9,72 @@ pinned: true
9
  license: mit
10
  ---
11
 
12
- ## KidneyAI: End-to-End Kidney CT Scan Classification with MLOps
13
 
14
- [![Python](https://img.shields.io/badge/Python-3.13-blue?logo=python&logoColor=white)](https://www.python.org/)
15
  [![TensorFlow](https://img.shields.io/badge/TensorFlow-2.x-orange?logo=tensorflow&logoColor=white)](https://www.tensorflow.org/)
16
  [![DVC](https://img.shields.io/badge/DVC-Pipeline%20Versioning-945DD6?logo=dvc&logoColor=white)](https://dvc.org/)
17
  [![MLflow](https://img.shields.io/badge/MLflow-Experiment%20Tracking-0194E2?logo=mlflow&logoColor=white)](https://mlflow.org/)
18
  [![DagsHub](https://img.shields.io/badge/DagsHub-Remote%20Tracking-FF6B35?logoColor=white)](https://dagshub.com/)
19
  [![Flask](https://img.shields.io/badge/Flask-Web%20App-000000?logo=flask&logoColor=white)](https://flask.palletsprojects.com/)
20
  [![Docker](https://img.shields.io/badge/Docker-Containerised-2496ED?logo=docker&logoColor=white)](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**. But the model itself is only one piece of the story. The real focus of this project is everything that surrounds it: a fully reproducible DVC pipeline, experiment tracking with MLflow and DagsHub, a clean configuration-driven codebase, a Flask web application, and a Dockerised deployment setup.
27
 
28
- It was built to demonstrate what a real 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.
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 manually reviewing CT scans are under enormous pressure, and any tool that can reliably flag suspicious scans for closer attention has genuine clinical value.
35
 
36
- This project builds a binary image classifier that can look at a kidney CT scan and tell you, within seconds, whether the kidney appears normal or shows signs of a tumor. It is trained on a labelled CT scan dataset and achieves approximately **89.9% validation accuracy** using a fine-tuned VGG16 network.
37
 
38
  ---
39
 
40
- ## Why VGG16?
41
 
42
- VGG16 was selected deliberately, not arbitrarily. Here is the reasoning:
43
 
44
- Its architecture is built from uniform 3x3 convolutional layers stacked into increasing depth. This design is especially good at learning fine-grained local textures, which is critical in medical imaging where the difference between healthy and abnormal tissue often comes down to subtle structural patterns rather than large-scale shape differences.
45
 
46
- 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 can achieve strong performance with far less labelled data than training from scratch would require.
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 | Value |
55
- |----------|--------|
56
- | Accuracy | 89.9% |
57
- | Loss | 1.26 |
 
 
 
 
 
 
 
 
58
 
59
- Metrics are logged automatically to MLflow after every pipeline run. You can view all experiment runs, compare parameters, and download model artifacts directly from the DagsHub MLflow UI.
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 Each stage was prototyped here first
107
 
108
  └── templates/
109
- └── index.html Web UI for the prediction app
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 Stage 2 Stage 3 Stage 4
120
- Data Ingestion Base Model Preparation Model Training Model Evaluation
 
 
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 the `artifacts/data_ingestion/` directory. DVC tracks the output so this stage is skipped if the data already exists and nothing has changed.
126
 
127
  ### Stage 2: Base Model Preparation
128
 
129
- Loads VGG16 with ImageNet weights and without its top classification layers. Adds a custom head: a global average pooling layer followed by a dense output layer with softmax activation for the two classes, Normal and Tumor. The base VGG16 layers are frozen. The resulting model is saved to disk so the training stage can pick it up.
130
 
131
  ### Stage 3: Model Training
132
 
133
- Loads the prepared base model, recompiles it with an SGD optimiser, and trains it on the kidney CT images. Supports data augmentation (horizontal flip, zoom, shear) to improve generalisation. The trained model is saved as `artifacts/training/model.h5`.
134
 
135
  ### Stage 4: Model Evaluation
136
 
137
- Loads the trained model and evaluates it against the 30 percent validation split. Loss and accuracy are saved to `scores.json` and logged to MLflow. The model is also registered in the MLflow Model Registry under the name `VGG16Model`.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
- You can view the experiment runs at:
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
- **`config/config.yaml`** manages all file paths and artifact locations:
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
- **`params.yaml`** is where all model hyperparameters live:
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.13 -y
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 your MLflow credentials
233
 
234
- Create a `.env` file in the project root with your DagsHub token:
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 will execute all four stages in order. If any stage has already run and its inputs have not changed, it will be skipped automatically. After the pipeline finishes, `scores.json` will contain the latest evaluation metrics.
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 your browser and go to `http://localhost:8080`. You can upload a kidney CT scan image and get a classification result instantly.
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 to see all remotely tracked runs.
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 8080:8080 kidney-classifier
274
  ```
275
 
276
- Open `http://localhost:8080` in your browser.
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 | Method | Description |
285
- | --------- | ------ | ------------------------------------------------------------------- |
286
- | `/` | GET | Serves the prediction web UI |
287
- | `/predict`| POST | Accepts an image file and returns the classification result as JSON |
288
- | `/train` | GET | Reruns `main.py` to retrain the model from scratch |
289
 
290
- The prediction endpoint returns a response like this:
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 detection of your system preference.
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
- | Environment | Conda with pip |
 
 
319
 
320
  ---
321
 
322
  ## MLOps Concepts Demonstrated
323
 
324
- | Concept | How it is implemented |
325
- | ------------------------ | ------------------------------------------------------------------------------- |
326
- | Data versioning | DVC tracks the dataset and all model artifacts |
327
- | Pipeline as code | `dvc.yaml` defines every stage and its dependencies |
328
- | Incremental execution | DVC only reruns stages whose inputs have changed |
329
- | Experiment tracking | MLflow logs parameters, metrics, and model artifacts on every run |
330
- | Model registry | Trained models are registered and versioned in the MLflow Model Registry |
331
- | Configuration management | All paths and hyperparameters live in YAML files with no hardcoded values |
332
- | Modular ML package | Source code is structured as an installable Python package |
333
- | Reproducibility | Any contributor can clone the repo and run `dvc repro` to get identical results |
334
- | Containerisation | Dockerfile ensures the app runs consistently in any environment |
335
- | REST API serving | Flask wraps the prediction pipeline and exposes it over HTTP |
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 in the real world.
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
+ [![Python](https://img.shields.io/badge/Python-3.10-blue?logo=python&logoColor=white)](https://www.python.org/)
15
  [![TensorFlow](https://img.shields.io/badge/TensorFlow-2.x-orange?logo=tensorflow&logoColor=white)](https://www.tensorflow.org/)
16
  [![DVC](https://img.shields.io/badge/DVC-Pipeline%20Versioning-945DD6?logo=dvc&logoColor=white)](https://dvc.org/)
17
  [![MLflow](https://img.shields.io/badge/MLflow-Experiment%20Tracking-0194E2?logo=mlflow&logoColor=white)](https://mlflow.org/)
18
  [![DagsHub](https://img.shields.io/badge/DagsHub-Remote%20Tracking-FF6B35?logoColor=white)](https://dagshub.com/)
19
  [![Flask](https://img.shields.io/badge/Flask-Web%20App-000000?logo=flask&logoColor=white)](https://flask.palletsprojects.com/)
20
  [![Docker](https://img.shields.io/badge/Docker-Containerised-2496ED?logo=docker&logoColor=white)](https://www.docker.com/)
21
+ [![HuggingFace](https://img.shields.io/badge/HuggingFace-Deployed-FFD21E?logo=huggingface&logoColor=black)](https://huggingface.co/spaces/Sentoz/kidney-classifier)
22
+ [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](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 1Stage 2Stage 3Stage 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)