This project is an end-to-end machine learning workflow for the red wine quality dataset. It covers:
- data ingestion
- data validation
- train/test split
- model training with
ElasticNet - model evaluation
- experiment tracking with DagsHub-hosted MLflow
- model registration in MLflow Model Registry
- a Flask web app for training and prediction
- containerized execution with Docker and Docker Compose
The repository is structured so that configuration, pipeline orchestration, component logic, tracking, artifacts, and serving are separated cleanly.
The goal of the project is to take a tabular dataset from source to a trained and tracked model in a reproducible way.
At a high level, the project does this:
- Download the dataset
- Validate the schema
- Split the data into train and test sets
- Train an
ElasticNetmodel - Evaluate the model
- Log metrics and parameters to MLflow on DagsHub
- Register the model in MLflow as
ElasticnetModel - Serve a simple UI for training and prediction
The execution flow is:
config.yaml + params.yaml + schema.yaml
|
v
ConfigurationManager
|
v
Pipeline classes in src/datascience/pipeline/
|
v
Component classes in src/datascience/components/
|
v
data/ + artifacts/ + logs/ + MLflow/DagsHub
|
v
Flask app and prediction UI
This separation is important:
- configuration files describe what to run
- entity classes define the structure of that configuration
- component classes do the real work
- pipeline classes orchestrate component execution
main.pyruns the whole training workflowapp.pyexposes browser routes for training and prediction
datascienceproject/
|-- app.py
|-- main.py
|-- data/
| |-- raw.dvc
| |-- processed.dvc
| |-- raw/
| `-- processed/
|-- .dvc/
|-- Dockerfile
|-- docker-compose.yml
|-- .dockerignore
|-- .env.example
|-- requirements.txt
|-- pyproject.toml
|-- params.yaml
|-- schema.yaml
|-- config/
| `-- config.yaml
|-- templates/
| |-- index.html
| `-- results.html
|-- research/
| `-- notebooks for stage-by-stage experimentation
`-- src/
`-- datascience/
|-- __init__.py
|-- components/
|-- config/
|-- constants/
|-- entity/
|-- pipeline/
`-- utils/
This is the main runtime configuration file.
It defines:
- where DVC-tracked raw data goes
- where DVC-tracked processed data goes
- where the trained model is saved
- where evaluation output is saved
- which MLflow tracking URI to use
- which registered model name to use
Current model registration name:
registered_model_name: ElasticnetModelThis file stores model hyperparameters.
Current parameters:
ElasticNet:
alpha: 0.2
l1_ratio: 0.1These are read during model training and evaluation.
This file defines the expected dataset columns and target column.
It is used by the validation and training flow to make sure the pipeline is operating on the expected data structure.
Current target column:
TARGET_COLUMN:
name: qualityThis file defines dataclasses such as:
DataIngestionConfigDataValidationConfigDataTransformationConfigModelTrainerConfigModelEvaluationConfig
These classes turn raw YAML values into typed Python objects.
This is the configuration manager.
It reads:
config.yamlparams.yamlschema.yaml
Then it creates stage-specific config objects for every pipeline stage.
This folder contains the actual business logic.
Current implemented components:
data_ingestion.pyDownloads the wine quality ZIP file and extracts it.data_validation.pyChecks whether dataset columns match the expected schema.data_transformation.pySplits the dataset into train and test CSV files.model_trainer.pyTrains anElasticNetmodel and savesmodel.joblib.model_evaluation.pyLoads the trained model, evaluates it, savesmetrics.json, logs metrics to MLflow, and registers the model on DagsHub MLflow.
This folder wraps each component into a pipeline runner.
It keeps orchestration separate from logic.
Examples:
data_ingestion_pipeline.pymodel_trainer_pipeline.pymodel_evaluation_pipeline.pyprediction_pipeline.py
This is the end-to-end training entrypoint.
It runs all stages in order:
- Data Ingestion
- Data Validation
- Data Transformation
- Model Trainer
- Model Evaluation
If you want to run the full ML pipeline from code or terminal, main.py is the main file.
This is the Flask application.
Routes:
/Loads the home page/trainStarts training in the background/train/statusShows whether background training is running or idle/predictAccepts form values and returns a model prediction
The important design point is that /train does not block the web request anymore. It starts main.py in a background process and returns immediately.
This folder is generated by the pipeline.
Typical contents:
- trained model file
- evaluation metrics JSON
Raw and processed datasets now live under the DVC-tracked data/ directory:
data/raw/data/processed/
This folder stores runtime logs.
Important files:
logs/logging.logMain application logslogs/training.logBackground training log when/trainis used
This project trains an ElasticNet regressor on wine quality data.
During evaluation, the project logs:
- parameters from
params.yaml - metrics such as
rmse,mae, andr2 - the trained model artifact
- a registered model in DagsHub-hosted MLflow
The registered model name is:
ElasticnetModel
The evaluation flow also tags the registered model version with metric values so the model registry is more informative.
Before running the project, make sure you have:
- Python 3.11 or compatible
- Git
- Docker Desktop and Docker Compose
- DVC CLI available locally (installed by
pip install -r requirements.txt) - a DagsHub account
- access to the DagsHub repository used for MLflow logging
PowerShell:
python -m venv .venv
.venv\Scripts\Activate.ps1Git Bash:
python -m venv .venv
source .venv/Scripts/activatepip install -r requirements.txtCreate a file named .env in the project root.
Example:
MLFLOW_TRACKING_USERNAME=your-dagshub-username
MLFLOW_TRACKING_PASSWORD=your-dagshub-tokenThis file is ignored by Git and should not be committed.
This repository now tracks dataset directories with DVC:
data/raw.dvcdata/processed.dvc
Commit these DVC metadata files:
data/raw.dvcdata/processed.dvcdata/.gitignore.dvc/config.dvc/.gitignore.dvcignore
Do not commit:
.dvc/config.local.env- actual files inside
data/raw/ - actual files inside
data/processed/
If your DVC remote is already configured, pull the tracked data with:
dvc pullIf no DVC remote is configured yet, the pipeline can still recreate the local dataset by running python main.py. That command recreates:
data/raw/data/processed/
Those files will remain local until you configure a DVC remote and push them.
You have two common options.
Option 1: connect an existing GitHub repository from the DagsHub UI.
- Open DagsHub
- Create a new repository or connect an existing one
- Follow the "Connect an Existing Repository" flow
Reference:
Option 2: add DagsHub as a Git remote to the current repository.
Example:
git remote add dagshub https://dagshub.com/<username>/<repo-name>.git
git push dagshub mainIf the remote already exists, inspect it first:
git remote -vFor this project, the MLflow URI currently points to:
https://dagshub.com/faizulkhan56/datascienceproject.mlflow
So the matching DagsHub Git repository is typically:
https://dagshub.com/faizulkhan56/datascienceproject.git
Practical sequence for an existing GitHub project:
- Create or open the matching repository in DagsHub.
- Use DagsHub's "connect existing repository" flow or add DagsHub as an additional Git remote from your local clone.
- Confirm your code is visible in DagsHub after a normal Git push.
- Configure
.envlocally for MLflow credentials. - Run
python main.pyand verify experiment runs appear in DagsHub MLflow. - Configure the DVC remote and push tracked data if you also want dataset versioning visible in DagsHub.
The MLflow tracking URI is set in config/config.yaml.
The application loads credentials from .env, then model_evaluation.py uses them when sending experiment data to DagsHub-hosted MLflow.
Use a DagsHub access token.
The DagsHub docs recommend:
MLFLOW_TRACKING_USERNAME= your DagsHub usernameMLFLOW_TRACKING_PASSWORD= your DagsHub password, or preferably an access token
Reference:
- Experiment tracking docs: https://dagshub.com/docs/feature_guide/experiment_tracking/
In practice, use an access token instead of your account password.
Typical flow:
- Sign in to DagsHub
- Open user settings
- Open the tokens page
- Create or copy an access token
- Put that token into
.envasMLFLOW_TRACKING_PASSWORD
The token settings page is:
https://dagshub.com/user/settings/tokens
You must be signed in to access it.
After training completes successfully, you should see:
- a new experiment run in DagsHub MLflow
- a registered model named
ElasticnetModel - a new model version
- metrics such as
rmse,mae, andr2
Experiment tracking and DVC data versioning are separate.
This project now stores datasets under DVC-tracked paths:
data/raw/data/processed/
To make those datasets visible in DagsHub's data area, you still need to do the account-specific remote setup on your side:
- Configure a DVC remote that points to your chosen storage backend or DagsHub-supported storage workflow.
- Authenticate that remote from your machine.
- Run
dvc push. - Commit and push the generated DVC metadata files.
After that, collaborators can use dvc pull after cloning the repo.
After your Git repository is already connected to DagsHub and MLflow tracking is working, configure the DVC remote in this order.
Browser steps:
- Open your DagsHub repository homepage.
- Find the repository storage / remote / data-connection area.
- Open the data-storage instructions for
DVC. - Copy the repository-specific setup values shown there.
Terminal steps:
./.venv/Scripts/dvc.exe remote add -d dagshub s3://dvc
./.venv/Scripts/dvc.exe remote modify dagshub endpointurl https://dagshub.com/<username>/<repo>.s3
./.venv/Scripts/dvc.exe remote modify --local dagshub access_key_id <token>
./.venv/Scripts/dvc.exe remote modify --local dagshub secret_access_key <token>Notes:
dagshubis the DVC remote name and is intentionally separate from Gitorigin-dmakes it the default DVC remote--localstores credentials in.dvc/config.local, which must not be committed
Verify the remote:
./.venv/Scripts/dvc.exe remote listPush the tracked dataset:
./.venv/Scripts/dvc.exe push -r dagshubOr, because it is the default:
./.venv/Scripts/dvc.exe pushVerify after push:
./.venv/Scripts/dvc.exe status
git statusExpected outcome:
- DVC status is up to date
- Git status remains clean or only shows intentional tracked config changes
.dvc/config.localstays untracked- actual files under
data/raw/anddata/processed/stay out of Git
Then refresh the DagsHub repository page and check the data-related view again.
python main.pyWhat this does:
- downloads or reuses the dataset
- stores raw data under
data/raw/ - validates columns
- writes train/test splits to
data/processed/ - trains the model
- evaluates the model
- writes model and metrics artifacts
- logs to DagsHub MLflow
python app.pyThen open:
http://localhost:8080/
http://localhost:8080/Home pagehttp://localhost:8080/trainStarts training in the backgroundhttp://localhost:8080/train/statusReturnsrunningoridle
Docker makes the project easier to run in a consistent environment.
It packages:
- Python runtime
- project code
- dependencies
- Gunicorn
Docker Compose adds:
- port mapping
- environment file loading
- mounted
data/for DVC-tracked datasets - mounted artifacts and logs
- healthcheck
Purpose:
- builds the runtime image
- installs system and Python dependencies
- copies the project into
/app - exposes port
8080 - runs the Flask app with Gunicorn
Purpose:
- builds the image from the local
Dockerfile - loads values from
.env - maps
${APP_HOST_PORT:-8080}on the host to container port8080 - mounts
data/ - mounts
artifacts/andlogs/ - defines a container healthcheck
Purpose:
- keeps the build context smaller
- excludes local virtual environments
- excludes local DVC-tracked data payloads
- excludes local logs and artifacts
- excludes
.env
docker compose build --no-cache
docker compose up -ddocker compose psExpected state:
- service
web - status
Up - ideally
(healthy)
docker compose logs -f webhttp://localhost:8080/http://localhost:8080/trainhttp://localhost:8080/train/status
If port 8080 is already used on your machine, override it:
PowerShell:
$env:APP_HOST_PORT="8082"
docker compose up -dGit Bash:
APP_HOST_PORT=8082 docker compose up -dThen use:
http://localhost:8082/
docker compose downRecommended sequence for a fresh user:
- Clone the repository
- Create
.env - Install dependencies or use Docker
- If a DVC remote already exists, run
dvc pull; otherwise runpython main.pyto recreatedata/raw/anddata/processed/ - Configure DVC remote access if you want shared dataset versioning on DagsHub
- Check
config/config.yaml - Start the application with
docker compose up -dorpython app.py - Confirm
data/andartifacts/are present - Confirm MLflow logs appear in DagsHub
- Use the browser app for prediction and training
After a successful training run, verify:
data/raw/data.zipdata/raw/winequality-red.csvdata/processed/train.csvdata/processed/test.csvartifacts/model_trainer/model.joblibartifacts/model_evaluation/metrics.jsondata/raw.dvcdata/processed.dvc
Main logs:
Get-Content .\logs\logging.log -WaitBackground training logs:
Get-Content .\logs\training.log -WaitQuick tail:
Get-Content .\logs\training.log -Tail 50After the run, the training logs usually print:
- the MLflow run URL
- the experiment URL
You can also open the repository on DagsHub and then:
- Open the project page
- Open the MLflow or Experiments area
- Open the latest run
- Inspect metrics, parameters, and artifacts
- Open the registered model
- Open the latest model version
What to verify on the run page:
rmsemaer2- run parameters from
params.yaml - model artifact
What to verify in the model registry:
- registered model
ElasticnetModel - latest version number
- model version created from the run
The usual flow is:
- Open your DagsHub repository
- Navigate to the experiment tracking / MLflow area
- Open the latest run
- Review:
- metrics
- parameters
- artifacts
- source run information
- Open the model registry entry
- Open the latest version of
ElasticnetModel
If the training log prints a direct link such as:
View run https://dagshub.com/<user>/<repo>.mlflow/#/experiments/0/runs/<run-id>
you can open that link directly.
Testing this project is mostly operational and integration-oriented.
Syntax check:
python -m py_compile app.py
python -m py_compile main.pypython main.pySuccess criteria:
- no exception raised
data/raw/anddata/processed/created or reused- metrics JSON written
- model saved
- DagsHub MLflow run created
Start app:
python app.pyThen verify:
/loads/trainstarts background training/train/statuschanges torunningand later returns toidle/predictreturns a prediction when the form is submitted
docker compose build --no-cache
docker compose up -d
docker compose ps
docker compose logs -f webSuccess criteria:
- container starts
- healthcheck passes
- Gunicorn is running
/trainworks without blocking the browser
Browser:
http://localhost:8080/train/status
Expected:
runningduring active trainingidleafter training completes
Look for the final stage completion lines in logs/training.log, especially:
Model Evaluation stage completed- the MLflow run URL
- the registered model version creation line
dir artifacts\model_trainerExpected:
model.joblib
dir data\raw
dir data\processedOptional DVC check:
dvc statustype artifacts\model_evaluation\metrics.jsonCause:
- old behavior blocked the web request while training ran
Current solution:
/trainnow starts background training withsubprocess.Popen
Action:
- rebuild Docker if needed
- call
/train - monitor
logs/training.log
Cause:
- stale image or old server configuration
- connection-level stalls
Action:
docker compose down
docker compose build --no-cache
docker compose up -dCheck:
.envexistsMLFLOW_TRACKING_USERNAMEis correctMLFLOW_TRACKING_PASSWORDcontains a valid DagsHub tokenconfig/config.yamlhas the correctmlflow_uri
Understand the separation:
- metrics are primarily logged to the MLflow run
- the registered model links to the run
- this project also tags model versions with metrics, but the run page is still the main place to inspect experiment metrics
This is not fatal.
MLflow tries to infer environment metadata using uv, then falls back automatically if uv is unavailable.
The Docker image now installs git, and GIT_PYTHON_REFRESH=quiet is set to reduce noisy warnings.
A successful run usually includes:
- all five pipeline stages completing
- raw data under
data/raw/ - processed data under
data/processed/ metrics.jsonbeing saved- a new MLflow run URL in the logs
- a new
ElasticnetModelversion created /train/statuseventually returningidle
For normal development:
- Pull latest code
- Update config or parameters if needed
- Start Docker or local environment
- Trigger training
- Monitor logs
- Check DagsHub MLflow results
- Test prediction UI
- Commit only intended changes
Install:
pip install -r requirements.txtOptional DVC pull:
dvc pullDVC remote setup with DagsHub Storage:
./.venv/Scripts/dvc.exe remote add -d dagshub s3://dvc
./.venv/Scripts/dvc.exe remote modify dagshub endpointurl https://dagshub.com/<username>/<repo>.s3
./.venv/Scripts/dvc.exe remote modify --local dagshub access_key_id <token>
./.venv/Scripts/dvc.exe remote modify --local dagshub secret_access_key <token>
./.venv/Scripts/dvc.exe remote list
./.venv/Scripts/dvc.exe push -r dagshubRun pipeline:
python main.pyRun app:
python app.pyDocker build:
docker compose build --no-cacheDocker start:
docker compose up -dDocker logs:
docker compose logs -f webDocker stop:
docker compose downTraining log tail:
Get-Content .\logs\training.log -WaitTraining status:
http://localhost:8080/train/status
- DagsHub experiment tracking docs: https://dagshub.com/docs/feature_guide/experiment_tracking/
- DagsHub track ML experiments guide: https://dagshub.com/docs/use_cases/track_ml_experiments/
- DagsHub connect existing repository guide: https://dagshub.com/docs/quick_start/connect_existing_project/
- MLflow docs: https://mlflow.org/docs/latest/
This repository is now structured so that a new user can:
- set up credentials
- run the training flow
- inspect generated artifacts
- inspect MLflow results in DagsHub
- use Docker for a repeatable environment
- test the browser-based training and prediction flow
If you keep .env local, rebuild Docker after runtime changes, and monitor logs/training.log plus DagsHub MLflow, the project is straightforward to operate end-to-end.
Minimal rebuild path from zero:
- Clone the repository
- Create
.env - Install dependencies with
pip install -r requirements.txt - Run
dvc pullif the DVC remote is already configured; otherwise runpython main.py - Start with
docker compose up -dorpython app.py