Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

7 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

ml-06-serving

Workflow Guide Python 3.14 MIT

Professional Python project: deploying and serving machine learning models.

Publishing Predictive Engines

A machine learning model learns patterns from data. But, once trained, the model might just sit on a single computer.

Serving a model means wrapping it in a small web service so anyone can send it a data request over the internet and get a prediction back.

The example project trains a model that identifies penguin species from physical measurements, then deploys it so you can ask it what species a set of measurements belongs to.

My custom project serves two models for medical insurance charges from a single request. Sending age, BMI, number of children, and smoking status returns a cost tier, the probability of each of the four tiers, and a predicted dollar amount. The tier says which bracket a person falls in and how strongly the forest agreed on it; the dollar amount says how much, with nothing attached about agreement. Returning both shows what each one cannot tell you.

Project Description

This project focuses on learning to deploy a trained model so others can use it.

We learn to:

  • save and load a trained model
  • wrap a model in a simple API or script
  • validate inputs and handle errors gracefully
  • think about drift, versioning, and monitoring

My custom project applies this to medical insurance charges. Two models are trained on the same 1,338 rows and served from one endpoint: a random forest that predicts a cost tier and a linear regression that predicts a dollar amount. Both are saved as pipelines, so the engineered features are built inside the artifact rather than by the server.

The classifier reaches 0.8582 accuracy on 268 held-out rows. The regressor reaches R-squared 0.8609 with RMSE 4,607.9 dollars using six terms, close to the forty-four term polynomial I built in Module 4. Both models miss the same group: non-smokers whose charges are far higher than age, BMI, children, and smoking can explain.

See docs/index.md for the full write-up.

Project Dependencies

This project needs additional dependencies

    "fastapi[standard]", # for serving - a web framework for building APIs
    "uvicorn",           # for serving - ASGI server for FastAPI
    "joblib",            # for model serialization (saving and loading models)

Project Process

A .joblib file is a serialized Python object that holds the trained model frozen to disk.

The package joblib converts the in-memory RandomForestClassifier (with all its learned decision trees and their weights) into bytes and writes them to a file.

Loading it back gives us the same trained model without having to retrain.

This is how serving a trained model works: train once, save once, load once at startup, then predict on every incoming request.

Example Notebook + Your Notebook

Keep the example notebook as it is. Either copy it or use it to build a new notebook that ends in _yourname. See docs/your-files.md for more.

Links:

Working Files

You'll work with these areas:

  • data/raw - raw data for exploration (only if you add a dataset)
  • docs/ - project narrative and documentation
  • src/mlstudio/ - the app is an example; run only (no need to modify)
  • notebooks/ - interactive analysis
  • pyproject.toml - update authorship & links
  • zensical.toml - update authorship & links

Command Reference

Show command reference

In a machine terminal (open in your Repos folder)

After you get a copy of this repo in your own GitHub account, open a machine terminal in your Repos folder:

# Replace username with YOUR GitHub username.
git clone https://github.com/gracecode42/ml-06-serving

cd ml-06-serving
code .

In a VS Code terminal

These are listed for convenience. For best results, follow the detailed instructions in pro-analytics-02 guide.

uv self update
uv python pin 3.14
uv lock --upgrade
uv sync --extra dev --extra docs --upgrade

uvx pre-commit install
uvx pre-commit autoupdate

git add -A
uvx pre-commit run --all-files
# repeat if changes were made
uvx pre-commit run --all-files

# run the example module to verify the environment (.venv/)
uv run python -m mlstudio.app_case

# TASK 1: train the example model and save it to artifacts/model.joblib.
uv run python -m mlstudio.model_builder_case

# CUSTOM: train both custom models and save them to artifacts/
# Writes model_gracecode42_classifier.joblib and model_gracecode42_regressor.joblib
uv run python -m mlstudio.model_builder_gracecode42_project

# run common chores
uv run ruff format .
uv run ruff check . --fix
uv run python -m pyright
uv run python -m pytest
uv run python -m zensical build

# save progress
git add -A
git commit -m "update"
git push -u origin main

Terminal 2: Right-click and Rename "server"

Open a second terminal. Right-click to rename this terminal "server".

Run:

# Task 2. Start the example server
uv run fastapi dev src/mlstudio/serve_case.py

# CUSTOM: start the insurance server instead
# Returns a cost tier with probabilities and a dollar estimate from one request
uv run fastapi dev src/mlstudio/serve_gracecode42_project.py

Keep this terminal open. You should see the following which means it is ready to receive requests:


   FastAPI   Starting development server πŸš€

             Searching for package file structure from directories with __init__.py files
| INFO | M06 | === RUN START ===
| INFO | M06 | project=M06
| INFO | M06 | repo_dir=ml-06-serving
| INFO | M06 | python=3.14.0
| INFO | M06 | os=Windows 11
| INFO | M06 | shell=powershell
| INFO | M06 | cwd=.
| INFO | M06 | github_actions=False
| INFO | M06 | Loading model from: artifacts\model.joblib
| INFO | M06 | Model loaded successfully
             Importing from C:\Repos\ml\ml-06-serving\src

    module   πŸ“ mlstudio
             β”œβ”€β”€ 🐍 __init__.py
             └── 🐍 serve_case.py

      code   Importing the FastAPI app object from the module with the following code:

             from mlstudio.serve_case import app

       app   Using import string: mlstudio.serve_case:app

    server   Server started at http://127.0.0.1:8000
    server   Documentation at http://127.0.0.1:8000/docs

       tip   Running in development mode, for production use: fastapi run

             Logs:

      INFO   Will watch for changes in these directories: ['C:\\Repos\\ml\\ml-06-serving']
      INFO   Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
      INFO   Started reloader process [31516] using WatchFiles
| INFO | M06 | === RUN START ===
| INFO | M06 | project=M06
| INFO | M06 | repo_dir=ml-06-serving
| INFO | M06 | python=3.14.0
| INFO | M06 | os=Windows 11
| INFO | M06 | shell=powershell
| INFO | M06 | cwd=.
| INFO | M06 | github_actions=False
| INFO | M06 | Loading model from: artifacts\model.joblib
| INFO | M06 | Model loaded successfully
      INFO   Started server process [10012]
      INFO   Waiting for application startup.
      INFO   Application startup complete.

Terminal 3: Right-click and Rename "client"

Open a third terminal. Right-click and rename it "client".

Use this terminal to send a request to the server.

We are making a request to the "/predict" endpoint.

Provide information about a penguin and ask for the predicted species.

Line continuation characters for long commands are different by operating system.

  • PowerShell uses a backtick.
  • Bash and zsh use a back slash

The curl command means "check url".

  • X defines the type of request
  • H provides the requested response format (json data)
  • d provides a json object (a penguin where we want to get the species)

Windows PowerShell

# Task 3. Send a request to the server

curl -X POST http://127.0.0.1:8000/predict `
     -H "Content-Type: application/json" `
     -d '{"bill_length_mm": 39.1, "bill_depth_mm": 18.7, "flipper_length_mm": 181, "body_mass_g": 3750}'

# CUSTOM: send a request to the insurance server
# Returns the cost tier, the probability of each tier, and a dollar estimate

curl -X POST http://127.0.0.1:8000/predict `
     -H "Content-Type: application/json" `
     -d '{"age": 45, "bmi": 33.0, "children": 2, "smoker": "yes"}'

macOS / Linux

# Task 3. Send a request to the server

curl -X POST http://127.0.0.1:8000/predict \
     -H "Content-Type: application/json" \
     -d '{"bill_length_mm": 39.1, "bill_depth_mm": 18.7, "flipper_length_mm": 181, "body_mass_g": 3750}'

Should return the predicted result as JSON data:

{ "prediction": "Adelie" }

Try sending some slightly different data - does it change the prediction? Study the data. Try to create a request that will answer with each of three different species (Adelie, Chinstrap, Gentoo)

Try a Web-based ML Penguin Predictor on Render

Render hosts your ML model for free. It is easy to set up, but they require a credit card (even for the free options). The machines sleep so it can take a minute to wake up and answer. See the docs/ for more.

Customize the request to see what species is predicted:

# PowerShell
curl -X POST https://ml-penguin-predictor.onrender.com/predict `
     -H "Content-Type: application/json" `
     -d '{"bill_length_mm": 39.1, "bill_depth_mm": 18.7, "flipper_length_mm": 181, "body_mass_g": 3750}'

# macOS / Linux
curl -X POST https://ml-penguin-predictor.onrender.com/predict \
     -H "Content-Type: application/json" \
     -d '{"bill_length_mm": 39.1, "bill_depth_mm": 18.7, "flipper_length_mm": 181, "body_mass_g": 3750}'

Try a Web-based ML Penguin Predictor on HuggingFace

HuggingFace also hosts your ML model for free. It is a bit harder to set up (they use their own repo and we upload files via the browser). No credit card is required. See the docs/ for more.

Customize the request to see what species is predicted:

# PowerShell
curl -X POST https://denisecase-ml-penguin-predictor.hf.space/predict `
     -H "Content-Type: application/json" `
     -d '{"bill_length_mm": 39.1, "bill_depth_mm": 18.7, "flipper_length_mm": 181, "body_mass_g": 3750}'

# macOS / Linux
curl -X POST https://denisecase-ml-penguin-predictor.hf.space/predict \
     -H "Content-Type: application/json" \
     -d '{"bill_length_mm": 39.1, "bill_depth_mm": 18.7, "flipper_length_mm": 181, "body_mass_g": 3750}'

Findings and Visuals

Model Metric Test result
Cost tier classifier Accuracy 0.8582
Cost tier classifier Weighted F1 0.8556
Cost tier classifier Recall, very high tier 0.7164
Charges regressor R-squared 0.8609
Charges regressor RMSE $4,607.90

Plain linear regression split its errors into two flat bands: smokers under BMI 30 at a median of negative 9,716 dollars, smokers at BMI 30 or above at positive 7,587. One smoker coefficient had to cover both groups. Flat bands mean the premium jumps at a threshold rather than rising with BMI, so I added a step term rather than raising the polynomial degree. RMSE fell from 6,198 to 4,608 dollars.

Residuals for plain linear regression

Residuals for the served regressor

The bands are gone in the second plot. What remains is a group of non-smokers predicted in the low thousands whose charges run ten to twenty thousand dollars higher, with almost nothing below the line. The classifier misses the same people, placing eight top-tier cases in the lowest tier.

Project Documentation

Additional project instructions, terms, and notes:

docs/index.md

Citation

CITATION.cff

License

MIT

About

Applied Machine Learning - Serving

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Contributors

Languages