From 1809c514ca9801b018b5b758c1843ea06d986c90 Mon Sep 17 00:00:00 2001 From: Nathalie Jonathan Date: Tue, 17 Dec 2024 14:42:53 -0800 Subject: [PATCH] Added ML Model APIs (load, upload, create metadata). Signed-off-by: Nathalie Jonathan --- CHANGELOG.md | 2 +- spec/namespaces/ml.yaml | 159 ++++++++++++++++++++++++++ tests/plugins/ml/models/load.yaml | 79 +++++++++++++ tests/plugins/ml/models/metadata.yaml | 75 ++++++++++++ tests/plugins/ml/models/upload.yaml | 56 +++++++++ 5 files changed, 370 insertions(+), 1 deletion(-) create mode 100644 tests/plugins/ml/models/load.yaml create mode 100644 tests/plugins/ml/models/metadata.yaml create mode 100644 tests/plugins/ml/models/upload.yaml diff --git a/CHANGELOG.md b/CHANGELOG.md index 8a53a266..89f69361 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,7 +34,7 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) - Added response schema for `GET /_plugins/_knn/warmup/{index}` ([#717](https://github.com/opensearch-project/opensearch-api-specification/pull/717)) - Added support for multiple test verbs ([#724](https://github.com/opensearch-project/opensearch-api-specification/pull/724)) - Added support for using a certificate and key in tests ([#731](https://github.com/opensearch-project/opensearch-api-specification/pull/731)) -- Added `GET /_plugins/_ml/models/{model_id}`, `POST /_plugins/_ml/models/_search`, `PUT /_plugins/_ml/models/{model_id}`, `POST /_plugins/_ml/models/{model_id}/_unload`, `POST /_plugins/_ml/models/_unload`, and `POST /_plugins/_ml/models/_undeploy` ([#733](https://github.com/opensearch-project/opensearch-api-specification/pull/733)) +- Added `GET /_plugins/_ml/models/{model_id}`, `POST /_plugins/_ml/models/_search`, `PUT /_plugins/_ml/models/{model_id}`, `POST /_plugins/_ml/models/{model_id}/_unload`, `POST /_plugins/_ml/models/_unload`, `POST /_plugins/_ml/models/_undeploy`, `POST /_plugins/_ml/models/_upload`,`POST /_plugins/_ml/models/{model_id}/_load`, and `POST /_plugins/_ml/models/meta` ([#733](https://github.com/opensearch-project/opensearch-api-specification/pull/733)) ### Removed - Removed unsupported `_common.mapping:SourceField`'s `mode` field and associated `_common.mapping:SourceFieldMode` enum ([#652](https://github.com/opensearch-project/opensearch-api-specification/pull/652)) diff --git a/spec/namespaces/ml.yaml b/spec/namespaces/ml.yaml index d65c5eb9..8cecd7c8 100644 --- a/spec/namespaces/ml.yaml +++ b/spec/namespaces/ml.yaml @@ -43,6 +43,29 @@ paths: responses: '200': $ref: '#/components/responses/ml.register_model@200' + /_plugins/_ml/models/meta: + post: + operationId: ml.create_model_meta.0 + x-operation-group: ml.create_model_meta + description: Creates a model metadata. + requestBody: + $ref: '#/components/requestBodies/ml.create_model_meta' + responses: + '200': + $ref: '#/components/responses/ml.create_model_meta@200' + /_plugins/_ml/models/_upload: + post: + operationId: ml.upload_model.0 + x-operation-group: ml.upload_model + deprecated: true + x-version-deprecated: 2.7.0 + x-deprecation-message: Use `register_model` instead. + description: Registers a model. + requestBody: + $ref: '#/components/requestBodies/ml.upload_model' + responses: + '200': + $ref: '#/components/responses/ml.upload_model@200' /_plugins/_ml/models/{model_id}: get: operationId: ml.get_model.0 @@ -83,6 +106,19 @@ paths: responses: '200': $ref: '#/components/responses/ml.deploy_model@200' + /_plugins/_ml/models/{model_id}/_load: + post: + operationId: ml.load_model.0 + x-operation-group: ml.load_model + deprecated: true + x-version-deprecated: 2.7.0 + x-deprecation-message: Use `deploy_model` instead. + description: Deploys a model. + parameters: + - $ref: '#/components/parameters/ml.load_model::path.model_id' + responses: + '200': + $ref: '#/components/responses/ml.load_model@200' /_plugins/_ml/models/{model_id}/_undeploy: post: operationId: ml.undeploy_model.0 @@ -264,6 +300,72 @@ components: required: - name - version + ml.create_model_meta: + content: + application/json: + schema: + type: object + properties: + name: + type: string + description: The model name. + version: + type: string + description: The model version. + model_format: + type: string + description: The portable format of the model file. + enum: [ONNX, TORCH_SCRIPT] + model_group_id: + type: string + description: The ID of the model group to which to register the model. + model_content_hash_value: + type: string + description: The model content hash value. + model_config: + $ref: '../schemas/ml._common.yaml#/components/schemas/ModelConfig' + total_chunks: + type: integer + format: int64 + description: The total chunks. + url: + type: string + description: The model URL. + description: + type: string + description: The model description. + required: + - model_config + - model_content_hash_value + - model_format + - name + - total_chunks + - version + ml.upload_model: + content: + application/json: + schema: + type: object + properties: + name: + type: string + description: The model name. + version: + type: string + description: The model version. + model_format: + type: string + description: The portable format of the model file. + enum: [ONNX, TORCH_SCRIPT] + description: + type: string + description: The model description. + model_group_id: + type: string + description: The ID of the model group to which to register the model. + required: + - name + - version ml.search_models: content: application/json: @@ -430,6 +532,32 @@ components: required: - status - task_id + ml.create_model_meta@200: + content: + application/json: + schema: + type: object + properties: + status: + type: string + model_id: + type: string + required: + - model_id + - status + ml.upload_model@200: + content: + application/json: + schema: + type: object + properties: + status: + type: string + task_id: + type: string + required: + - status + - task_id ml.deploy_model@200: content: application/json: @@ -445,6 +573,31 @@ components: required: - status - task_id + ml.load_model@200: + content: + application/json: + schema: + type: object + properties: + status: + type: string + task_id: + type: string + task_type: + type: string + enum: + - BATCH_INGEST + - BATCH_PREDICTION + - DEPLOY_MODEL + - EXECUTION + - PREDICTION + - REGISTER_MODEL + - TRAINING + - TRAINING_AND_PREDICTION + required: + - status + - task_id + - task_type ml.undeploy_model@200: content: application/json: @@ -548,6 +701,12 @@ components: required: true schema: type: string + ml.load_model::path.model_id: + name: model_id + in: path + required: true + schema: + type: string ml.undeploy_model::path.model_id: name: model_id in: path diff --git a/tests/plugins/ml/models/load.yaml b/tests/plugins/ml/models/load.yaml new file mode 100644 index 00000000..c560e906 --- /dev/null +++ b/tests/plugins/ml/models/load.yaml @@ -0,0 +1,79 @@ +$schema: ../../../../json_schemas/test_story.schema.yaml + +description: Test the deployment of a model using load API (deprecated). +distributions: + excluded: + - amazon-managed + - amazon-serverless +warnings: + multiple-paths-detected: false +prologues: + - path: /_plugins/_ml/models/_register + id: register_model + method: POST + request: + payload: + name: huggingface/sentence-transformers/msmarco-distilbert-base-tas-b + version: 1.0.1 + model_format: TORCH_SCRIPT + output: + task_id: payload.task_id +epilogues: + - path: /_plugins/_ml/models/{model_id}/_undeploy + method: POST + parameters: + model_id: ${get_completed_register_model_task.model_id} + status: [200, 404] + - path: /_plugins/_ml/models/{model_id} + parameters: + model_id: ${get_completed_register_model_task.model_id} + method: DELETE + status: [200, 404] +chapters: + - synopsis: Wait to get completed task. + id: get_completed_register_model_task + path: /_plugins/_ml/tasks/{task_id} + method: GET + parameters: + task_id: ${register_model.task_id} + response: + status: 200 + payload: + state: COMPLETED + output: + model_id: payload.model_id + retry: + count: 3 + wait: 10000 + - synopsis: Deploy a model. + id: load_model + path: /_plugins/_ml/models/{model_id}/_load + method: POST + parameters: + model_id: ${get_completed_register_model_task.model_id} + output: + task_id: payload.task_id + response: + status: 200 + - synopsis: Wait to get completed task. + id: get_completed_load_model_task + path: /_plugins/_ml/tasks/{task_id} + method: GET + parameters: + task_id: ${load_model.task_id} + response: + status: 200 + payload: + state: COMPLETED + output: + model_id: payload.model_id + retry: + count: 3 + wait: 10000 + - synopsis: Undeploy a model. + path: /_plugins/_ml/models/{model_id}/_undeploy + method: POST + parameters: + model_id: ${get_completed_register_model_task.model_id} + response: + status: 200 diff --git a/tests/plugins/ml/models/metadata.yaml b/tests/plugins/ml/models/metadata.yaml new file mode 100644 index 00000000..49062cf6 --- /dev/null +++ b/tests/plugins/ml/models/metadata.yaml @@ -0,0 +1,75 @@ +$schema: ../../../../json_schemas/test_story.schema.yaml + +description: Test the creation of model metadata. +distributions: + excluded: + - amazon-managed + - amazon-serverless +version: '>= 2.11' +warnings: + multiple-paths-detected: false +prologues: + - path: /_plugins/_ml/models/_register + id: register_model + method: POST + request: + payload: + name: huggingface/sentence-transformers/msmarco-distilbert-base-tas-b + version: 1.0.1 + model_format: TORCH_SCRIPT + output: + task_id: payload.task_id +epilogues: + - path: /_plugins/_ml/models/{model_id} + parameters: + model_id: ${get_completed_task.model_id} + method: DELETE + status: [200, 404] +chapters: + - synopsis: Create model metadata. + id: model_metadata + path: /_plugins/_ml/models/meta + method: POST + request: + payload: + name: huggingface/sentence-transformers/msmarco-distilbert-base-tas-b + version: 1.0.1 + model_format: TORCH_SCRIPT + model_content_hash_value: 123abc + total_chunks: 1 + model_config: + all_config: path + model_type: bert + embedding_dimension: 384 + framework_type: sentence_transformers + response: + status: 200 + output: + model_id: payload.model_id + - synopsis: Wait to get completed task. + id: get_completed_task + path: /_plugins/_ml/tasks/{task_id} + method: GET + parameters: + task_id: ${register_model.task_id} + response: + status: 200 + payload: + state: COMPLETED + output: + model_id: payload.model_id + retry: + count: 5 + wait: 30000 + - synopsis: Get model. + path: /_plugins/_ml/models/{model_id} + method: GET + parameters: + model_id: ${get_completed_task.model_id} + response: + status: 200 + - synopsis: Delete model. + path: /_plugins/_ml/models/{model_id} + parameters: + model_id: ${get_completed_task.model_id} + method: DELETE diff --git a/tests/plugins/ml/models/upload.yaml b/tests/plugins/ml/models/upload.yaml new file mode 100644 index 00000000..6efafdb4 --- /dev/null +++ b/tests/plugins/ml/models/upload.yaml @@ -0,0 +1,56 @@ +$schema: ../../../../json_schemas/test_story.schema.yaml + +description: Test the creation of models using upload API (deprecated). +distributions: + excluded: + - amazon-managed + - amazon-serverless +warnings: + multiple-paths-detected: false +epilogues: + - path: /_plugins/_ml/models/{model_id} + method: DELETE + status: [200, 404] + parameters: + model_id: ${get_completed_task.model_id} +chapters: + - synopsis: Register model. + id: upload_model + path: /_plugins/_ml/models/_upload + method: POST + request: + payload: + name: huggingface/sentence-transformers/msmarco-distilbert-base-tas-b + version: 1.0.1 + model_format: TORCH_SCRIPT + response: + status: 200 + output: + task_id: payload.task_id + - synopsis: Wait to get completed task. + id: get_completed_task + path: /_plugins/_ml/tasks/{task_id} + method: GET + parameters: + task_id: ${upload_model.task_id} + response: + status: 200 + payload: + state: COMPLETED + output: + model_id: payload.model_id + retry: + count: 5 + wait: 30000 + - synopsis: Get model. + path: /_plugins/_ml/models/{model_id} + method: GET + parameters: + model_id: ${get_completed_task.model_id} + response: + status: 200 + - synopsis: Delete model. + path: /_plugins/_ml/models/{model_id} + parameters: + model_id: ${get_completed_task.model_id} + method: DELETE