Skip to content

About

DTU group project: BERT text readability classifier with training, API serving, and cloud deployment

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Latest commit

Β 

History

78 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Text Quality Classification - MLOps Project

A machine learning system for classifying English text readability levels (Elementary, Intermediate, Advanced) using a fine-tuned BERT model. This project implements a complete MLOps pipeline including training, evaluation, API serving, and cloud deployment.

Python PyTorch FastAPI License

⚠️ Intel Mac Users: This project uses PyTorch 2.6.0, which doesn't have wheels for Intel Macs with uv. Please see INTEL_MAC_GUIDE.md for Docker-based setup instructions.

Made By

Group 63 - DTU Course 02476 Machine Learning Operations

Student Number
s234869 (Alexander Hougaard) (GitHub: Alexander-bit-boop)
s245176 (William Hyldig) (GitHub: Williamhyldig)
s244742 (Valdemar Stamm) (GitHub: HrStamm)
s245362 (Frederik JΓΈnsson) (GitHub: Trexz14)
s246089 (Gustav Christensen) (GitHub: DonConarch)

Overview

This project was developed as part of the 02476 Machine Learning Operations course at DTU. It builds an end-to-end ML pipeline that predicts text readability levels on a 0-2 scale:

  • 0: Elementary (simple vocabulary and sentence structure)
  • 1: Intermediate (moderate complexity)
  • 2: Advanced (complex vocabulary and sentence structure)

Key Features

  • πŸ€– BERT-based model using the lightweight prajjwal1/bert-mini (11M parameters)
  • πŸ“Š Experiment tracking with Weights & Biases
  • 🐳 Containerized training and API serving with Docker
  • ☁️ Cloud deployment on Google Cloud Platform (Cloud Run)
  • πŸ”„ CI/CD pipelines with GitHub Actions
  • πŸ“¦ Data versioning with DVC and Google Cloud Storage
  • πŸ§ͺ Comprehensive testing with pytest and code coverage
  • πŸ“ˆ API monitoring with Prometheus metrics

Quick Start

For detailed setup instructions, see QUICKSTART.md.

# Clone the repository
git clone https://github.com/Trexz14/ml-ops-assignment.git
cd ml-ops-assignment

# Install dependencies (requires uv)
uv sync

# Authenticate with Google Cloud (for data/model access)
gcloud auth application-default login

# Pull data and models from DVC
uv run dvc pull

# Evaluate the trained model
uv run invoke evaluate --checkpoint models/model_final.pt

# Start the API server
uv run invoke serve-api

Project Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                              Data Pipeline                                   β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                 β”‚
β”‚  β”‚   HuggingFace │────▢│  Tokenizer   │────▢│  Processed   β”‚                 β”‚
β”‚  β”‚    Dataset    β”‚     β”‚  (BERT)      β”‚     β”‚   Dataset    β”‚                 β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                 β”‚
β”‚                                                    β”‚                         β”‚
β”‚                                                    β–Ό                         β”‚
β”‚                              β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”           β”‚
β”‚                              β”‚         DVC + GCS Storage        β”‚           β”‚
β”‚                              β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜           β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                            Training Pipeline                                 β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                 β”‚
β”‚  β”‚   Config     │────▢│   Training   │────▢│    Model     β”‚                 β”‚
β”‚  β”‚   (YAML)     β”‚     β”‚   Script     β”‚     β”‚  Checkpoints β”‚                 β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                 β”‚
β”‚                              β”‚                     β”‚                         β”‚
β”‚                              β–Ό                     β–Ό                         β”‚
β”‚                       β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                  β”‚
β”‚                       β”‚   W&B      β”‚        β”‚    DVC     β”‚                  β”‚
β”‚                       β”‚  Logging   β”‚        β”‚   Storage  β”‚                  β”‚
β”‚                       β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                           Serving Pipeline                                   β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                 β”‚
β”‚  β”‚   FastAPI    │────▢│   Docker     │────▢│  Cloud Run   β”‚                 β”‚
β”‚  β”‚   Server     β”‚     β”‚   Container  β”‚     β”‚  Deployment  β”‚                 β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                 β”‚
β”‚         β”‚                                                                    β”‚
β”‚         β–Ό                                                                    β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                                                           β”‚
β”‚  β”‚  Prometheus  β”‚                                                           β”‚
β”‚  β”‚   Metrics    β”‚                                                           β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                                                           β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                             CI/CD Pipeline                                   β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                 β”‚
β”‚  β”‚   GitHub     │────▢│   GitHub     │────▢│   Cloud      β”‚                 β”‚
β”‚  β”‚   Push       β”‚     β”‚   Actions    β”‚     β”‚   Build      β”‚                 β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                 β”‚
β”‚                              β”‚                     β”‚                         β”‚
β”‚                              β–Ό                     β–Ό                         β”‚
β”‚                       β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                  β”‚
β”‚                       β”‚   Tests    β”‚        β”‚  Artifact  β”‚                  β”‚
β”‚                       β”‚  + Lint    β”‚        β”‚  Registry  β”‚                  β”‚
β”‚                       β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Project Structure

β”œβ”€β”€ .github/                  # GitHub Actions workflows
β”‚   └── workflows/
β”‚       β”œβ”€β”€ tests.yaml        # Run tests on push/PR
β”‚       β”œβ”€β”€ linting.yaml      # Code linting with ruff
β”‚       └── docker-build.yaml # Build and push Docker images
β”œβ”€β”€ configs/                  # Experiment configuration files
β”‚   └── experiments/
β”‚       └── default.yaml      # Default training config
β”œβ”€β”€ data/                     # Data directory (DVC tracked)
β”‚   └── processed/            # Tokenized dataset
β”œβ”€β”€ dockerfiles/              # Docker configurations
β”‚   β”œβ”€β”€ api.dockerfile        # API server image
β”‚   β”œβ”€β”€ train.dockerfile      # Training image
β”‚   └── evaluate.dockerfile   # Evaluation image
β”œβ”€β”€ docs/                     # MkDocs documentation
β”‚   └── source/
β”œβ”€β”€ models/                   # Trained model checkpoints (DVC tracked)
β”œβ”€β”€ reports/                  # Exam report and figures
β”œβ”€β”€ src/ml_ops_assignment/    # Source code
β”‚   β”œβ”€β”€ api.py                # FastAPI application
β”‚   β”œβ”€β”€ data.py               # Data loading and preprocessing
β”‚   β”œβ”€β”€ evaluate.py           # Model evaluation script
β”‚   β”œβ”€β”€ model.py              # Model definition and training logic
β”‚   β”œβ”€β”€ train.py              # Training entry point
β”‚   └── visualize.py          # Visualization utilities
β”œβ”€β”€ tests/                    # Unit tests
β”‚   β”œβ”€β”€ test_api.py           # API tests
β”‚   β”œβ”€β”€ test_data.py          # Data pipeline tests
β”‚   └── test_model.py         # Model tests
β”œβ”€β”€ cloudbuild.yaml           # Google Cloud Build configuration
β”œβ”€β”€ pyproject.toml            # Project dependencies (uv)
β”œβ”€β”€ tasks.py                  # Invoke tasks for common commands
└── README.md                 # This file

Usage

Training

# Preprocess data (if starting from scratch)
uv run invoke preprocess-data

# Train the model
uv run invoke train

# Train with Docker
uv run invoke docker-train

Evaluation

# Evaluate on test set
uv run invoke evaluate --checkpoint models/model_final.pt

# Evaluate on validation set
uv run invoke evaluate --checkpoint models/model_final.pt --split validation

API

# Start the API server locally
uv run invoke serve-api

# Make a prediction
curl -X 'POST' \
  'http://127.0.0.1:8000/predict' \
  -H 'Content-Type: application/json' \
  -d '{"text": "The quick brown fox jumps over the lazy dog."}'

Testing

# Run all tests
uv run pytest tests/ -v

# Run tests with coverage
uv run pytest tests/ --cov=ml_ops_assignment --cov-report=term-missing

Code Quality

# Format code
uv run ruff format .

# Lint code
uv run ruff check . --fix

# Run all pre-commit hooks
uv run pre-commit run --all-files

Technology Stack

Category Tools
ML Framework PyTorch 2.6.0, Transformers
Model BERT-mini (prajjwal1/bert-mini)
Data HuggingFace Datasets, DVC
API FastAPI, Uvicorn, Pydantic
Monitoring Prometheus, Weights & Biases
Infrastructure Docker, Google Cloud Run, Cloud Build
CI/CD GitHub Actions
Code Quality Ruff, Mypy, Pre-commit
Testing Pytest, Coverage
Package Management uv

Dataset

The project uses the OneStop English dataset from HuggingFace, which contains English texts at three readability levels. The dataset is automatically split into:

  • Training: 80% of the data
  • Validation: 10% of the data
  • Test: 10% of the data

Acknowledgments

License

This project is licensed under the MIT License - see the LICENSE file for details.

About

DTU group project: BERT text readability classifier with training, API serving, and cloud deployment

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages