Skip to content

Commit f06a732

Browse files
authored
Merge pull request #77 from fuzzylabs/SD-163-Easy-Run
[SD-163] Run without MLflow / DAGsHub download
2 parents 4f50c85 + fb8df02 commit f06a732

File tree

4 files changed

+65
-33
lines changed

4 files changed

+65
-33
lines changed

ecoml/pyproject.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,8 @@ torch = [
4444
[build-system]
4545
requires = ["hatchling"]
4646
build-backend = "hatchling.build"
47+
48+
[tool.poetry]
49+
include = [
50+
"src/ecoml/ecoml_models/**"
51+
]

ecoml/src/ecoml/.DS_Store

0 Bytes
Binary file not shown.
Lines changed: 42 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
1-
"""Load inference model from Mlflow registry."""
1+
"""Load inference model from MLflow registry."""
22

33
import os
44
from pathlib import Path
5-
from typing import Any, Literal, Optional
6-
5+
from typing import Any, Literal
76
import dagshub
87
import mlflow
98
import pandas as pd
10-
from rich import print
119
from loguru import logger
1210

1311
from ecoml.data_preparation.features import (
@@ -16,63 +14,78 @@
1614
get_pooling_features,
1715
)
1816
from ecoml.data_preparation.pytorch_utils import PytorchLayer
17+
import importlib.resources as pkg_resources
18+
import ecoml
1919

2020
ALLOWED_LAYER_TYPES = Literal["convolutional", "pooling", "dense"]
2121

2222

2323
class InferenceModel:
2424
"""Inference Model.
2525
26-
It downloads model from MLFlow Registry on DagsHub, if not present on the first run.
26+
Downloads model from MLflow Registry on DagsHub if not already present.
2727
"""
2828

2929
def __init__(
3030
self,
3131
layer_type: ALLOWED_LAYER_TYPES,
3232
model_version: int,
3333
verbose: bool = False,
34-
dagshub_repo_owner: Optional[str] = "fuzzylabs",
35-
dagshub_repo_name: Optional[str] = "edge-vision-power-estimation",
34+
dagshub_repo_owner: str = "fuzzylabs",
35+
dagshub_repo_name: str = "edge-vision-power-estimation",
36+
use_packaged_models: bool = False,
3637
):
3738
self.layer_type = layer_type
3839
self.model_version = model_version
3940
self.verbose = verbose
4041
self.repo_name = dagshub_repo_name
4142
self.repo_owner = dagshub_repo_owner
42-
self.base_model_dir = Path.cwd() / "ecoml_models" / self.layer_type
43-
# Download model from MLFlow Registry if not present on first run
43+
self.use_packaged_models = use_packaged_models
44+
45+
if not self.use_packaged_models:
46+
self.base_model_dir = Path.cwd() / "ecoml_models" / self.layer_type
47+
else:
48+
self.base_model_dir = pkg_resources.files(ecoml).joinpath("ecoml_models", self.layer_type)
49+
4450
self.runtime_model = self.load_model(model_type="runtime")
45-
4651

47-
def _download_model(self, model_uri: str, dst_path: str) -> None:
52+
def _download_model(self, model_uri: str, dst_path: Path) -> None:
4853
"""Download model from MLflow registry to local filesystem.
4954
5055
Args:
5156
model_uri: URI pointing to model artifact.
52-
dst_path: Path of the local filesystem destination directory
53-
to which to download the specified artifacts.
57+
dst_path: Destination directory path.
5458
"""
5559
if self.verbose:
56-
logger.info(f"Downloading model to {dst_path} folder")
60+
logger.info(f"Downloading model to {dst_path}")
5761
dagshub.init(repo_name=self.repo_name, repo_owner=self.repo_owner, mlflow=True)
5862
mlflow.artifacts.download_artifacts(artifact_uri=model_uri, dst_path=str(dst_path))
5963

6064
def load_model(self, model_type: str) -> Any:
61-
"""Download and load power or runtime model from MLflow Registry.
62-
63-
Download is skipped if model exists in the local filesystem.
65+
"""Download and load runtime or power model from MLflow Registry.
6466
6567
Returns:
66-
Power or runtime model from MLflow Registry.
68+
Loaded runtime or power model.
6769
"""
70+
if self.use_packaged_models:
71+
model_path = self.base_model_dir / model_type / "model.pkl"
72+
if not model_path.exists():
73+
raise FileNotFoundError(
74+
f"Packaged model file not found: {model_path}. "
75+
"Ensure ecoml_models are packaged correctly."
76+
)
77+
model_dir = model_path.parent
78+
if self.verbose:
79+
logger.info(f"Loading packaged {model_type} model from {model_dir}")
80+
return mlflow.pyfunc.load_model(str(model_dir))
81+
82+
# Using DagsHub / MLFlow remote model
6883
model_name = f"{self.layer_type}_{model_type}_model"
6984
model_uri = f"models:/{model_name}/{self.model_version}"
7085
dst_path = self.base_model_dir / model_type
71-
# TODO: Tighter check to see if current model version is present
72-
# instead of checking only if directory exists
7386
version_file = dst_path / "version.txt"
74-
need_download = True
7587

88+
need_download = True
7689
if version_file.exists():
7790
local_version = version_file.read_text().strip()
7891
if local_version == str(self.model_version):
@@ -83,23 +96,21 @@ def load_model(self, model_type: str) -> Any:
8396
version_file.write_text(str(self.model_version))
8497
else:
8598
if self.verbose:
86-
logger.info("Model already downloaded")
99+
logger.info(f"{model_type.capitalize()} model version {self.model_version} already downloaded.")
87100

88101
if self.verbose:
89-
logger.info(f"Loading the {model_type} trained model from {dst_path} folder")
90-
logger.info(f"Loading {model_type} model from {dst_path}")
102+
logger.info(f"Loading {model_type} model from {dst_path}")
91103

92-
def get_features(self, layer_info: PytorchLayer) -> pd.DataFrame:
93-
"""Get features for the model to run prediction.
104+
return mlflow.pyfunc.load_model(str(dst_path))
94105

95-
Each layer type creates input features required by
96-
power and runtime models using Pytorch model summary file.
106+
def get_features(self, layer_info: PytorchLayer) -> pd.DataFrame:
107+
"""Get features for prediction based on layer type.
97108
98109
Args:
99-
layer_info: Pydantic class containing all layer information.
110+
layer_info: Layer details.
100111
101112
Returns:
102-
Pandas dataframe containing input features.
113+
DataFrame containing features.
103114
"""
104115
if self.layer_type == "convolutional":
105116
features = get_convolutional_features(layer_info)
@@ -108,6 +119,4 @@ def get_features(self, layer_info: PytorchLayer) -> pd.DataFrame:
108119
elif self.layer_type == "dense":
109120
features = get_dense_features(layer_info)
110121
else:
111-
raise ValueError(f"Unsupported layer type: {self.layer_type}")
112-
113-
return pd.DataFrame([features])
122+

ecoml/src/ecoml/model_summary/test.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import torch
2+
import json
3+
4+
# Load PyTorch quantized model
5+
pt_model = torch.load("sample_data/resnet18_quantised.pt", map_location="cpu")
6+
7+
# Load JSON model summary
8+
with open("sample_data/resnet18_quantized.json", "r") as f:
9+
json_model = json.load(f)
10+
11+
# Print PyTorch model state dictionary keys
12+
print("\n--- PyTorch Model State Dict Keys ---")
13+
print(pt_model.state_dict().keys()) # This should list all layer names
14+
15+
# Print first layer in JSON model for comparison
16+
print("\n--- JSON Model First Layer ---")
17+
first_layer_name = list(json_model.keys())[0]
18+
print(first_layer_name, "->", json_model[first_layer_name])

0 commit comments

Comments
 (0)