-
Notifications
You must be signed in to change notification settings - Fork 60
Changed multi model metadata storage. #1112
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
402db52
3dc9977
a524924
b321d5c
f9a3064
740bf3d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -24,6 +24,7 @@ | |
| from ads.aqua import logger | ||
| from ads.aqua.app import AquaApp | ||
| from ads.aqua.common import utils | ||
| from ads.aqua.common.entities import AquaMultiModelRef | ||
| from ads.aqua.common.enums import ( | ||
| DataScienceResource, | ||
| Resource, | ||
|
|
@@ -97,6 +98,7 @@ | |
| from ads.model.model_metadata import ( | ||
| MetadataTaxonomyKeys, | ||
| ModelCustomMetadata, | ||
| ModelCustomMetadataItem, | ||
| ModelProvenanceMetadata, | ||
| ModelTaxonomyMetadata, | ||
| ) | ||
|
|
@@ -578,6 +580,7 @@ def validate_model_name( | |
|
|
||
| This function verifies that: | ||
| - The model group is not empty. | ||
| - The model multi metadata is present in the DataScienceModel metadata. | ||
| - The user provided a non-empty model name. | ||
| - The provided model name exists in the DataScienceModel metadata. | ||
| - The deployment configuration contains core metadata required for validation. | ||
|
|
@@ -636,10 +639,39 @@ def validate_model_name( | |
| f"'{create_aqua_evaluation_details.evaluation_source_id}' does not contain any information about deployed models." | ||
| ) | ||
|
|
||
| multi_model_metadata_value = custom_metadata_list.get( | ||
| ModelCustomMetadataFields.MULTIMODEL_METADATA, | ||
| ModelCustomMetadataItem(key=ModelCustomMetadataFields.MULTIMODEL_METADATA), | ||
| ).value | ||
|
|
||
| if not multi_model_metadata_value: | ||
| error_message = ( | ||
| f"Required model metadata is missing for evaluation source ID: {evaluation_source.id}. " | ||
| f"A valid multi-model deployment requires {ModelCustomMetadataFields.MULTIMODEL_METADATA}. " | ||
| "Please recreate the model deployment and retry the evaluation, as an issue occurred during the initialization of the model group." | ||
| ) | ||
| logger.debug(error_message) | ||
| raise AquaRuntimeError(error_message) | ||
|
|
||
| try: | ||
| multi_model_metadata = json.loads( | ||
| evaluation_source.dsc_model.get_custom_metadata_artifact( | ||
| metadata_key_name=ModelCustomMetadataFields.MULTIMODEL_METADATA | ||
| ).decode("utf-8") | ||
| ) | ||
| except Exception as ex: | ||
| error_message = ( | ||
| f"Error fetching {ModelCustomMetadataFields.MULTIMODEL_METADATA} " | ||
| f"from custom metadata for evaluation source ID '{evaluation_source.id}'. " | ||
| f"Details: {ex}" | ||
| ) | ||
| logger.error(error_message) | ||
| raise AquaRuntimeError(error_message) | ||
|
|
||
| # Build the list of valid model names from custom metadata. | ||
| model_names = [ | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should load metadata back to the
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Updated |
||
| custom_metadata_list.get(f"model-name-{idx}").value | ||
| for idx in range(model_group_count) | ||
| AquaMultiModelRef(**metadata).model_name | ||
| for metadata in multi_model_metadata | ||
| ] | ||
|
|
||
| # Check if the provided model name is among the valid names. | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,7 @@ | ||
| #!/usr/bin/env python | ||
| # Copyright (c) 2024, 2025 Oracle and/or its affiliates. | ||
| # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ | ||
| import json | ||
| import os | ||
| import pathlib | ||
| from datetime import datetime, timedelta | ||
|
|
@@ -93,6 +94,7 @@ | |
| TENANCY_OCID, | ||
| ) | ||
| from ads.model import DataScienceModel | ||
| from ads.model.common.utils import MetadataArtifactPathType | ||
| from ads.model.model_metadata import ( | ||
| MetadataCustomCategory, | ||
| ModelCustomMetadata, | ||
|
|
@@ -279,9 +281,10 @@ def create_multi( | |
| selected_models_deployment_containers = set() | ||
|
|
||
| # Process each model | ||
| for idx, model in enumerate(models): | ||
| for model in models: | ||
| source_model = DataScienceModel.from_id(model.model_id) | ||
| display_name = source_model.display_name | ||
| # Update model name in user's input model | ||
| model.model_name = model.model_name or display_name | ||
|
|
||
| # TODO Uncomment the section below, if only service models should be allowed for multi-model deployment | ||
|
|
@@ -310,6 +313,9 @@ def create_multi( | |
| "Please register the model first." | ||
| ) | ||
|
|
||
| # Update model artifact location in user's input model | ||
| model.artifact_location = model_artifact_path | ||
|
|
||
| artifact_list.append(model_artifact_path) | ||
|
|
||
| # Validate deployment container consistency | ||
|
|
@@ -328,47 +334,6 @@ def create_multi( | |
|
|
||
| selected_models_deployment_containers.add(deployment_container) | ||
|
|
||
| # Add model-specific metadata | ||
| model_custom_metadata.add( | ||
| key=f"model-id-{idx}", | ||
| value=source_model.id, | ||
| description=f"ID of '{display_name}' in the multimodel group.", | ||
| category="Other", | ||
| ) | ||
| model_custom_metadata.add( | ||
| key=f"model-name-{idx}", | ||
| value=display_name, | ||
| description=f"Name of '{display_name}' in the multimodel group.", | ||
| category="Other", | ||
| ) | ||
| if model.gpu_count: | ||
| model_custom_metadata.add( | ||
| key=f"model-gpu-count-{idx}", | ||
| value=model.gpu_count, | ||
| description=f"GPU count of '{display_name}' in the multimodel group.", | ||
| category="Other", | ||
| ) | ||
| user_params = ( | ||
| " ".join( | ||
| f"{name} {value}" for name, value in model.env_var.items() | ||
| ).strip() | ||
| if model.env_var | ||
| else UNKNOWN | ||
| ) | ||
| if user_params: | ||
| model_custom_metadata.add( | ||
| key=f"model-user-params-{idx}", | ||
| value=user_params, | ||
| description=f"User params of '{display_name}' in the multimodel group.", | ||
| category="Other", | ||
| ) | ||
| model_custom_metadata.add( | ||
| key=f"{ModelCustomMetadataFields.ARTIFACT_LOCATION}-{idx}", | ||
| value=model_artifact_path, | ||
| description=f"Artifact path for '{display_name}' in the multimodel group.", | ||
| category="Other", | ||
| ) | ||
|
|
||
| # Check if the all models in the group shares same container family | ||
| if len(selected_models_deployment_containers) > 1: | ||
| raise AquaValueError( | ||
|
|
@@ -430,6 +395,19 @@ def create_multi( | |
| f"Aqua Model '{custom_model.id}' created with models: {', '.join(display_name_list)}." | ||
| ) | ||
|
|
||
| # Create custom metadata for multi model metadata | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. let's add more debug statements here
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Updated |
||
| custom_model.create_custom_metadata_artifact( | ||
| metadata_key_name=ModelCustomMetadataFields.MULTIMODEL_METADATA, | ||
| artifact_path_or_content=json.dumps( | ||
| [model.model_dump() for model in models] | ||
| ), | ||
| path_type=MetadataArtifactPathType.CONTENT, | ||
| ) | ||
|
|
||
| logger.debug( | ||
| f"Multi model metadata uploaded for Aqua model: {custom_model.id}." | ||
| ) | ||
|
|
||
| # Track telemetry event | ||
| self.telemetry.record_event_async( | ||
| category="aqua/multimodel", | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -549,7 +549,7 @@ def _create_multi( | |
|
|
||
| container_params = container_spec.get(ContainerSpec.CLI_PARM, UNKNOWN).strip() | ||
|
|
||
| for idx, model in enumerate(create_deployment_details.models): | ||
| for model in create_deployment_details.models: | ||
| user_params = build_params_string(model.env_var) | ||
| if user_params: | ||
| restricted_params = self._find_restricted_params( | ||
|
|
@@ -588,22 +588,13 @@ def _create_multi( | |
| params = f"{params} {get_combined_params(config_parameters, user_params)}".strip() | ||
| break | ||
|
|
||
| artifact_location_key = ( | ||
| f"{ModelCustomMetadataFields.ARTIFACT_LOCATION}-{idx}" | ||
| ) | ||
| artifact_path_prefix = aqua_model.custom_metadata_list.get( | ||
| artifact_location_key | ||
| ).value.rstrip("/") | ||
| artifact_path_prefix = model.artifact_location.rstrip("/") | ||
| if ObjectStorageDetails.is_oci_path(artifact_path_prefix): | ||
| os_path = ObjectStorageDetails.from_path(artifact_path_prefix) | ||
| artifact_path_prefix = os_path.filepath.rstrip("/") | ||
|
|
||
| model_config.append({"params": params, "model_path": artifact_path_prefix}) | ||
|
|
||
| model_name_key = f"model-name-{idx}" | ||
| model_name_list.append( | ||
| aqua_model.custom_metadata_list.get(model_name_key).value | ||
| ) | ||
| model_name_list.append(model.model_name) | ||
|
|
||
| env_var.update({AQUA_MULTI_MODEL_CONFIG: json.dumps({"models": model_config})}) | ||
|
|
||
|
|
@@ -959,28 +950,24 @@ def get(self, model_deployment_id: str, **kwargs) -> "AquaDeploymentDetail": | |
| ) | ||
| aqua_model = DataScienceModel.from_id(aqua_model_id) | ||
| custom_metadata_list = aqua_model.custom_metadata_list | ||
| model_group_count = int( | ||
| custom_metadata_list.get( | ||
| ModelCustomMetadataFields.MULTIMODEL_GROUP_COUNT | ||
| ).value | ||
| multi_model_metadata_value = custom_metadata_list.get( | ||
| ModelCustomMetadataFields.MULTIMODEL_METADATA, | ||
| ModelCustomMetadataItem( | ||
| key=ModelCustomMetadataFields.MULTIMODEL_METADATA | ||
| ), | ||
| ).value | ||
| if not multi_model_metadata_value: | ||
| raise AquaRuntimeError( | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Updated |
||
| f"Invalid multi-model deployment: {model_deployment_id}. " | ||
| f"Ensure that the required custom metadata `{ModelCustomMetadataFields.MULTIMODEL_METADATA}` is added to the AQUA multi-model `{aqua_model.display_name}` ({aqua_model.id})." | ||
| ) | ||
| multi_model_metadata = json.loads( | ||
| aqua_model.dsc_model.get_custom_metadata_artifact( | ||
| metadata_key_name=ModelCustomMetadataFields.MULTIMODEL_METADATA | ||
| ).decode("utf-8") | ||
| ) | ||
| aqua_deployment.models = [ | ||
| AquaMultiModelRef( | ||
| model_id=custom_metadata_list.get(f"model-id-{idx}").value, | ||
| model_name=custom_metadata_list.get(f"model-name-{idx}").value, | ||
| gpu_count=custom_metadata_list.get( | ||
| f"model-gpu-count-{idx}", | ||
| ModelCustomMetadataItem(key=f"model-gpu-count-{idx}"), | ||
| ).value, | ||
| env_var=get_params_dict( | ||
| custom_metadata_list.get( | ||
| f"model-user-params-{idx}", | ||
| ModelCustomMetadataItem(key=f"model-user-params-{idx}"), | ||
| ).value | ||
| or UNKNOWN | ||
| ), | ||
| ) | ||
| for idx in range(model_group_count) | ||
| AquaMultiModelRef(**metadata) for metadata in multi_model_metadata | ||
| ] | ||
|
|
||
| return AquaDeploymentDetail( | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated