Skip to content

Real-Time What-If Analysis with Model Catalog and Model Deployment Integration #1041

New issue

Have a question about this project? Sign up for a free account to open an issue and contact its maintainers and the community.

By clicking “Sign up for ”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on ? Sign in to your account

Merged
merged 15 commits into from
Jan 30, 2025

Conversation

prasankh
Copy link
Member

This PR introduces real-time "What-If" analysis which includes functionality for saving models to the model catalog and automatically creating a model deployment server when the what_if_analysis section and additional_data is provided in the input YAML.

The forecast operator's input YAML now supports the following configuration:

what_if_analysis:
    project_id: ocid1.datascienceproject.oc1.p1xx
    compartment_id: ocid1.compartment.oc1..c1xx
    model_display_name: model_DD_MM_YYYY
    model_deployment:
        model_deployment_id: "ocid1.modeldeployment.oc1..md1xx"
        display_name: customerX
        model_display_name: customerX
        initial_shape: "VM.Standard2.1"
        description: "simple-description"
        log_id: "ocid1.log.oc1.iad.xx"
        log_group: "ocid1.loggroup.oc1.iad.yy"
        auto_scaling: 
            minimum_instance: 1
            maximum_instance: 10
            cool_down_in_seconds: 600
            scaling_metric: "CPU_UTILIZATION"
            scale_in_threshold: 20
            scale_out_threshold: 70`

If project_id and compartment_id are optional, if not provided, the session's environment variables will be used.

  • Model Catalog Integration:
    • Saving forecasting models to a model catalog for reuse during inference call.
  • Model Deployment :
    • Automatically create MD if existing model deployment ID is not provided.
    • If a model deployment ID is provided in the future, the newly created model will be attached to the specified MD, which will function as a multi-model inference server.
    • Supports autoscaling and logging configuration
  • A new output file deployment_info.json contains deployment metadata such as the Model Catalog ID, Model Deployment ID, Model Deployment Endpoint, and the Series IDs for which the model is applicable.

@prasankhprasankh requested a review from codeloop January 16, 2025 13:28
@oracle-contributor-agreementoracle-contributor-agreement bot added the OCA VerifiedAll contributors have signed the Oracle Contributor Agreement.label Jan 16, 2025
self.test_mode = os.environ.get("TEST_MODE", False)
self.deployment_info = {}

def _satiny_test(self):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo sanity

@prasankhprasankh requested a review from codeloop January 27, 2025 05:28
codeloop
codeloop previously approved these changes Jan 28, 2025
Copy link
Member

@ahosler ahosler left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome work! I have a few comments I just need clarity on.

@@ -168,6 +168,7 @@ def get_data_multi_indexed(self):
self.additional_data.data,
],
axis=1,
join='inner'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What triggered this change? If I have an additional data column with a lot of missing data, won't this delete rows from the historical dataset?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for flagging. I've reverted this change and tested the new development with it.

required: false
meta: "If model_deployment_id is not specified, a new model deployment is created; otherwise, the model is linked to the specified model deployment."
schema:
model_deployment_id:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could probably simplify this to "id" since it's already under "model_deployment".
Or we could move it up a level

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, changed to id

"""
Function perform sanity test for saved artifact
"""
sys.path.insert(0, f"{self.path_to_artifact}")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we undo this command later?
We should save a copy of the original sys.path and restore it.
How do we think about concurrency issues?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In a single operator run, this code will execute only once and restoring sys.path now

Inference script. This script is used for prediction by scoring server when schema is known.
"""

AUTOTS = "autots"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we pull these in from the const.py file? Now that we're importing ads anyways

logger_pred = logging.getLogger('model-prediction')
logger_pred.setLevel(logging.INFO)
logger_feat = logging.getLogger('input-features')
logger_feat.setLevel(logging.INFO)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting logger categories... Maybe we should do this throughout the Operator.

data_type[col['name']] = col['dtype']
else:
print(
"input_schema has to be passed in in order to recover the same data type. pass `X_sample` in `ads.model.framework.sklearn_model.SklearnModel.prepare` function to generate the input_schema. Otherwise, the data type might be changed after serialization/deserialization.")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to keep this error msg? Or change to something operator specific?
If we can re-use the version from score.py-jinja2, then lets just pull it directly

)
return forecast[target_column].tolist()
else:
raise Exception(f"Invalid model object type: {type(model_object).__name__}.")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome work here! Very easy to read and debug

ahosler
ahosler previously approved these changes Jan 29, 2025
@prasankhprasankh merged commit 21ba00b into main Jan 30, 2025
10 checks passed
Sign up for free to join this conversation on . Already have an account? Sign in to comment
Labels
OCA VerifiedAll contributors have signed the Oracle Contributor Agreement.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants