diff --git a/CHANGELOG.md b/CHANGELOG.md index 57545d59..5a2313f0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,31 @@ # Changelog +## v0.15.3 + +- [001baa4](/001baa419309edc6c84a4dae1dfa2e99bb3c75b5) - doc(evaluation): add evaluation.md, 2025-10-12 by *Guillaume Chervet* + + +## v0.15.2 + +- [1f4ebf7](/1f4ebf7243d71e42666297bc032251776dd9f911) - doc(evaluation): add evaluation.md, 2025-10-12 by *Guillaume Chervet* + + +## v0.15.1 + +- [b7edb55](/b7edb551645e123b271e11f667439a7ad3edbfe3) - doc(evaluation): add evaluation.md, 2025-10-12 by *Guillaume Chervet* + + +## v0.15.0 + +- [33b1b92](/33b1b929acd5a50d6ef9f7f4c377de34cdd8c234) - Merge branch 'main' of https://www.github.com/guillaume-chervet/MLOpsPython, 2025-09-21 by *Guillaume Chervet* +- [21f73c4](/21f73c48109465fe269583828b3f12e432ca4a6b) - feat(workshop): add library workshop, 2025-09-21 by *Guillaume Chervet* + + +## v0.14.11 + +- [ecfae26](/ecfae26c4f796ee80fbb3f6dfdf7809682667f6a) - fix(workshop): update to make it works in 2025, 2025-09-20 by *Guillaume Chervet* + + ## v0.14.10 - [a0310e2](/a0310e2f8248704ee42c0b776c3dcf16a9b5db7a) - refactore(all): switch to pyttest (#46), 2025-09-08 by *Guillaume Chervet* @@ -268,28 +294,3 @@ - [315e72c](/315e72ca2469df17729820fcd6e1f2ef23091268) - feat(workshop): create microsoft workshop, 2023-11-24 by *Guillaume Chervet* -## v0.3.3 - -- [6de6e5e](/6de6e5e90c8df00578d5883cea64480d38422290) - fix: Using pip instead of poetry to init the project was causing errors (#22), 2023-10-31 by *antoinelrnld* - - -## v0.3.2 - -- [14037bc](/14037bc8cd6b65eb5dca74e00da729272ae43e2e) - fix(train): azure cluster name (#21), 2023-10-21 by *Guillaume Chervet* - - -## v0.3.1 - -- [fb2f4e2](/fb2f4e24ee6ab0c920c94b70d88d4392e7ee9063) - docs(workshop): Update workshop_cloud_nord.md, 2023-10-12 by *Guillaume Chervet* - - -## v0.3.0 - -- [e4c1a89](/e4c1a8948c9772d64526e4f954b3712d130a99fb) - feat(workshop): create cloud nord workshop (#18), 2023-10-11 by *Guillaume Chervet* - - -## v0.2.1 - -- [3997017](/3997017790f048e512b0b012f347138ed6110147) - fix: api requirements.txt doesn't work on MacOs (#19), 2023-10-11 by *Ca.phe* - - diff --git a/evaluation.md b/evaluation.md new file mode 100644 index 00000000..4ce8abf2 --- /dev/null +++ b/evaluation.md @@ -0,0 +1,56 @@ +# Evaluation Notes + +- **Project:** 12 points +- **In-class follow-up:** 8 points + - UV Library Publication → link to PyPI library → 3 points + - Dependency Injection for Inference → link to personal GitHub → 3 points + - MLOps Lab Work → link to personal GitHub → 2 points +--- + +## Startup Project with High Added Value (topic of your choice) + +The project must: + +- Be hosted on a **public open-source Git repository** +- Include **Pull Requests** with **review/validation** between team members +- Contain **Unit Tests**, ideally following a **TDD** (Test-Driven Development) approach +- Include a **public Kanban board** +- Contain a **preprocessing phase**, such as: + - In the MLOps lab, the preprocessing step is the **extraction of images from a PDF** + - It can also be another turnkey AI component (e.g., text detection, OCR, etc.) +- Include a **mandatory AI training phase**: + - The AI can be trained **from scratch** (requires a large dataset) + - Or **fine-tuned** from an existing model (e.g., from **Hugging Face**) +- Use **more than 100 data samples** (images, audio, videos, etc.) **created by you** (not downloaded from the internet) and **annotated manually** +- Be **exposed as a real-time API** +- Optionally include a **web front-end** (not mandatory) + +--- + +## Evaluation Grid (Total: 12 points) + +| Item | Description | Points | +|------|--------------|--------| +| Teamwork, Clean Code, Pull Requests, linked commits and cards | Proper commit history | **1** | +| Unit-tested preprocessing phase | | **2** | +| AI training phase | | **1** | +| Annotation phase | | **2** | +| Real-time API deployed in an environment | | **2** | +| Automated integration tests | | **2** | +| Final Presentation (5 minutes) | | **2** | + +--- + +## Presentation Guidelines + +1. **Purpose:** What is your project’s functional value? What problem does it solve for end users? What makes it innovative? +2. **Demo** +3. **Why are you the best?** + - You may include technical details about **MLOps**, **cost**, and **Time to Market**. +4. **What is missing** — both technically and functionally. + +--- + +### Presentation Format + +Choose the format you believe adds the **most value** to your project presentation! diff --git a/packages/mlopspython-inference/mlopspython_inference/inference_pillow.py b/packages/mlopspython-inference/mlopspython_inference/inference_pillow.py index 63e5a9d3..d347027f 100644 --- a/packages/mlopspython-inference/mlopspython_inference/inference_pillow.py +++ b/packages/mlopspython-inference/mlopspython_inference/inference_pillow.py @@ -23,10 +23,22 @@ def load_image(filename: str|BytesIO): BASE_PATH = Path(__file__).resolve().parent +class IModel(): + def predict(self, img) -> np.ndarray: + pass + +class ModelPillow(IModel): + def __init__(self, model_path: str): + self.model = load_model(model_path) + + def predict(self, img) -> np.ndarray: + return self.model.predict(img) + + class Inference: - def __init__(self, logging, model_path: str): + def __init__(self, logging, model: IModel): self.logger = logging.getLogger(__name__) - self.model = load_model(model_path) + self.model = model def execute(self, filepath:str|BytesIO): img = load_image(filepath) diff --git a/packages/mlopspython-inference/tests/input/model/final_model.h5 b/packages/mlopspython-inference/tests/input/model/final_model.h5 deleted file mode 100644 index 60daa135..00000000 Binary files a/packages/mlopspython-inference/tests/input/model/final_model.h5 and /dev/null differ diff --git a/packages/mlopspython-inference/tests/test_inference.py b/packages/mlopspython-inference/tests/test_inference.py index 27cc7656..0b627880 100644 --- a/packages/mlopspython-inference/tests/test_inference.py +++ b/packages/mlopspython-inference/tests/test_inference.py @@ -1,22 +1,26 @@ import logging from pathlib import Path +from unittest.mock import MagicMock + import pytest +from inference_pillow import IModel from mlopspython_inference.inference_pillow import Inference BASE_PATH = Path(__file__).resolve().parent input_directory = BASE_PATH / "input" -@pytest.mark.skip(reason="Modèle lourd / GPU non requis sur CI. Enlever ce skip si nécessaire.") +#@pytest.mark.skip(reason="Modèle lourd / GPU non requis sur CI. Enlever ce skip si nécessaire.") def test_inference_runs_with_sample_model_and_image(): - model_path = input_directory / "model" / "final_model.h5" image_path = input_directory / "images" / "cat.png" - assert model_path.is_file(), "Modèle de test manquant" assert image_path.is_file(), "Image de test manquante" - inference = Inference(logging, str(model_path)) + model_mock = MagicMock(IModel) + model_mock.execute = MagicMock(return_value=[[1, 0, 0]]) + + inference = Inference(logging, model_mock) result = inference.execute(str(image_path)) assert result["prediction"] in {"Cat", "Dog", "Other"} diff --git a/train/label_split_data/__pycache__/label_split_data.cpython-310.pyc b/train/label_split_data/__pycache__/label_split_data.cpython-310.pyc new file mode 100644 index 00000000..6a7356f6 Binary files /dev/null and b/train/label_split_data/__pycache__/label_split_data.cpython-310.pyc differ diff --git a/workshop_create_library.md b/workshop_create_library.md index ac4fbf50..29c0e109 100644 --- a/workshop_create_library.md +++ b/workshop_create_library.md @@ -3,6 +3,12 @@ uv init --package mon_package cd mon_package +For linux/macos : +source .venv/bin/ + +For windows: +.venv\Scripts\activate + # Runtime dependencies (example) uv add httpx @@ -18,10 +24,10 @@ uv run black . --check uv run black . + # Run tests & code coverage uv run pytest -q -uv run pytest --cov=mon_package --cov-report=term-missing --cov-report=html - +uv run pytest -q uv run pytest --cov=mon_package --cov-report=term-missing --cov-report=html # Build wheel + sdist uv build