Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
b70a0ea
Migrate fine-tuning-with-orpo to MLflow models-from-code approach
NickyJhames Aug 12, 2025
7f6c8dc
feat: Refactor model registration to use FineTuningService
NickyJhames Aug 12, 2025
ea16725
Merge branch 'main' of https://github.com/HPInc/AI-Blueprints into fe…
NickyJhames Sep 2, 2025
2d58fa8
Merge branch 'main' into feat/mlflow-models-from-code-migration-fine-…
ata-turhan Sep 4, 2025
ced47a7
Merge branch 'main' of https://github.com/HPInc/AI-Blueprints into fe…
Oct 14, 2025
022474b
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Oct 14, 2025
c91ce3b
refactor: standardize to universal src/mlflow structure
Oct 14, 2025
2aced77
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Oct 14, 2025
e1e2b8c
refactor: standardize temp artifact dir to "model_artifacts" and tidy…
Oct 14, 2025
bd84743
Merge branch 'feat/mlflow-models-from-code-migration-fine-tuning-with…
Oct 14, 2025
e521a53
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Oct 14, 2025
661c788
feat: adding cell outputs
Oct 14, 2025
584c4c9
Merge branch 'feat/mlflow-models-from-code-migration-fine-tuning-with…
Oct 14, 2025
4b11576
feat: adding cell outputs for register model
Oct 14, 2025
d5da680
deat: adding cell output for run workflow
Oct 14, 2025
7c243c4
Merge branch 'main' into feat/mlflow-models-from-code-migration-fine-…
njhames Nov 3, 2025
535fdb1
Merge branch 'v2.0.0' into feat/mlflow-models-from-code-migration-fin…
njhames Nov 3, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions generative-ai/fine-tuning-with-orpo/configs/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
# model_source can be one of the following: local, hugging-face-cloud, or hugging-face-local
model_source: "local"

# Path to the local model file (used when model_source is "local")
model_path: "/home/jovyan/datafabric/meta-llama3.1-8b-Q8/Meta-Llama-3.1-8B-Instruct-Q8_0.gguf"

# Proxy is used to set the HTTPS_PROXY environment variable when necessary.
# For example, if you need to access external services from a restricted network,
# you should specify the proxy in this config.yaml file.
Expand Down
3 changes: 3 additions & 0 deletions generative-ai/fine-tuning-with-orpo/core/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
"""
Core package for AI Studio Templates.
"""
188 changes: 60 additions & 128 deletions generative-ai/fine-tuning-with-orpo/notebooks/register-model.ipynb

Large diffs are not rendered by default.

1,019 changes: 124 additions & 895 deletions generative-ai/fine-tuning-with-orpo/notebooks/run-workflow.ipynb

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion generative-ai/fine-tuning-with-orpo/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@ deepspeed==0.16.7
transformers==4.53.0
tf-keras==2.19.0
tabulate==0.9.0
mlflow==3.1.0 #TODO: remove me when you finish
torch==2.8.0
mlflow==2.21.2
pandas
17 changes: 17 additions & 0 deletions generative-ai/fine-tuning-with-orpo/src/mlflow/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
"""
MLflow package for fine-tuning models
"""

__all__ = ["Model", "Logger"]


def __getattr__(name):
if name == "Model":
from .model import Model

return Model
if name == "Logger":
from .logger import Logger

return Logger
raise AttributeError(f"module '{__name__}' has no attribute '{name}'")
114 changes: 114 additions & 0 deletions generative-ai/fine-tuning-with-orpo/src/mlflow/loader.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
"""
MLflow models-from-code loader module.
This module provides the _load_pyfunc function required by MLflow's models-from-code approach.
"""

import os
import logging
from typing import Dict, Any, Optional
from pathlib import Path

# Set up logger
logger = logging.getLogger(__name__)


def _load_pyfunc(data_path: str):
"""
MLflow models-from-code loader function.
Called by MLflow to load the model from artifacts.

Args:
data_path: Path to model artifacts directory containing:
- config.yaml: Model configuration
- model_no_finetuning/: Base model directory or HF ID file
- finetuned_model/: Fine-tuned model directory or HF ID file
- secrets.yaml: Secrets (optional)
- demo/: Demo folder with UI components (optional)

Returns:
Model: Initialized model instance ready for prediction
"""
from src.mlflow.model import Model

logger.info(f"Loading Model from artifacts at: {data_path}")

# Helper function to load config
def load_config(config_path: str) -> dict:
"""Load configuration from YAML file."""
import yaml

with open(config_path, "r") as file:
return yaml.safe_load(file)

# Helper function to load secrets if available
def load_secrets_if_available(secrets_path: str) -> Optional[dict]:
"""Load secrets if file exists."""
if os.path.exists(secrets_path):
import yaml

with open(secrets_path, "r") as file:
secrets = yaml.safe_load(file)

# Load secrets into environment
for key, value in secrets.items():
os.environ[key] = str(value)

logger.info("Secrets loaded into environment")
return secrets
return None

# Load configuration
config_path = os.path.join(data_path, "config.yaml")
if not os.path.exists(config_path):
raise FileNotFoundError(f"Configuration file not found at: {config_path}")

config = load_config(config_path)
logger.info("Configuration loaded successfully")

# Load secrets if available
secrets_path = os.path.join(data_path, "secrets.yaml")
secrets = load_secrets_if_available(secrets_path)

# Resolve model paths
base_model_artifact = os.path.join(data_path, "model_no_finetuning")
finetuned_model_artifact = os.path.join(data_path, "finetuned_model")

def resolve_model_path(artifact_path: str) -> str:
"""Resolve model path from artifact, handling both directories and HF ID files."""
if os.path.isdir(artifact_path):
# It's a directory containing the model
return artifact_path
elif os.path.isfile(artifact_path):
# It might be a file containing a HuggingFace model ID
try:
with open(artifact_path, "r") as f:
content = f.read().strip()
if content:
logger.info(f"Using HuggingFace model ID from file: {content}")
return content
except Exception as e:
logger.warning(
f"Failed to read model ID from file {artifact_path}: {e}"
)

# Fallback: return the path as-is (might be a HF model ID)
return artifact_path

base_model_path = resolve_model_path(base_model_artifact)
finetuned_model_path = resolve_model_path(finetuned_model_artifact)

logger.info(f"Resolved base model path: {base_model_path}")
logger.info(f"Resolved fine-tuned model path: {finetuned_model_path}")

# Initialize Model
try:
model = Model(
config=config,
base_model_path=base_model_path,
finetuned_model_path=finetuned_model_path,
)
logger.info("Model initialized successfully")
return model
except Exception as e:
logger.error(f"Failed to initialize Model: {str(e)}")
raise RuntimeError(f"Model loading failed: {str(e)}") from e
Loading