From dabd92aafe916071904c28adec890738a0865c10 Mon Sep 17 00:00:00 2001 From: Alvaro Lopez Garcia Date: Fri, 15 Mar 2024 13:16:17 +0100 Subject: [PATCH] feat: add option to allow to load a single module Since we are deprecating loading several models (#128, #129, #132) we need to ensure that users are able to load only a single module, even if several are present. --- deepaas/cmd/cli.py | 9 ++--- deepaas/cmd/execute.py | 11 ------ deepaas/config.py | 14 ++++++++ deepaas/exceptions.py | 19 ++++++++++ deepaas/model/loading.py | 24 +++++++++++++ deepaas/model/v2/__init__.py | 24 +++++++++++-- doc/source/cli/deepaas-cli.rst | 36 ++++++++++++------- doc/source/cli/deepaas-predict.rst | 25 ++++++------- doc/source/cli/deepaas-run.rst | 10 ++++++ doc/source/user/v2-api.rst | 6 ++++ ...te-old-model-loading-27aa4485b2132da7.yaml | 4 ++- 11 files changed, 139 insertions(+), 43 deletions(-) create mode 100644 deepaas/exceptions.py diff --git a/deepaas/cmd/cli.py b/deepaas/cmd/cli.py index 012ef721..7ff9d8bb 100644 --- a/deepaas/cmd/cli.py +++ b/deepaas/cmd/cli.py @@ -34,9 +34,11 @@ from oslo_log import log # from deepaas import config +from deepass import config from deepaas.model import loading from deepaas.model.v2 import wrapper as v2_wrapper +CONF = config.CONF debug_cli = False @@ -152,15 +154,14 @@ def _get_model_name(model_name=None): sys.stderr.write( "[ERROR]: There are several models available ({}).\n" "You have to choose one and set it in the DEEPAAS_V2_MODEL " - "environment setting.\n".format(list(models.keys())) + "environment variable or using the --mode-name option" + ".\n".format(list(models.keys())) ) sys.exit(1) # Get the model name -model_name = None -if "DEEPAAS_V2_MODEL" in os.environ: - model_name = os.environ["DEEPAAS_V2_MODEL"] +model_name = CONF.model_name model_name, model_obj = _get_model_name(model_name) diff --git a/deepaas/cmd/execute.py b/deepaas/cmd/execute.py index 224751db..7ae12326 100644 --- a/deepaas/cmd/execute.py +++ b/deepaas/cmd/execute.py @@ -26,17 +26,6 @@ from deepaas.model.v2.wrapper import UploadedFile cli_opts = [ - cfg.StrOpt( - "model-name", - help=""" -Add the name of the model from which you want -to obtain the prediction. -If there are multiple models installed and youd don't -specify the name of the one you want to use the program will fail. -If there is only one model installed, that will be used -to make the prediction. -""", - ), cfg.StrOpt( "input-file", short="i", diff --git a/deepaas/config.py b/deepaas/config.py index f87a2c18..6d85997b 100644 --- a/deepaas/config.py +++ b/deepaas/config.py @@ -15,6 +15,7 @@ # under the License. import logging +import os import warnings from oslo_config import cfg @@ -85,6 +86,19 @@ Pre-warm the modules (eg. load models, do preliminary checks, etc). You might want to disable this option if DEEPaaS is loading more than one module because you risk getting out of memory errors. +""", + ), + cfg.StrOpt( + "model-name", + default=os.environ.get("DEEPAAS_V2_MODEL", ""), + help=""" +Specify the model to be used. If not specified, DEEPaaS will serve all the models that +are available. If specified, DEEPaaS will serve only the specified model. You can also +use the DEEPAAS_V2_MODEL environment variable. + +WARNING: Serving multiple models is deprecated and will be removed in the future, + therefore it is strongly suggested that you specify the model you want to + or that you ensure that only one model is available. """, ), ] diff --git a/deepaas/exceptions.py b/deepaas/exceptions.py new file mode 100644 index 00000000..2f15fb3b --- /dev/null +++ b/deepaas/exceptions.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- + +# Copyright 2018 Spanish National Research Council (CSIC) +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + + +class ModuleNotFoundError(Exception): + """Module not found error.""" diff --git a/deepaas/model/loading.py b/deepaas/model/loading.py index 62f351b8..55441870 100644 --- a/deepaas/model/loading.py +++ b/deepaas/model/loading.py @@ -14,6 +14,8 @@ # License for the specific language governing permissions and limitations # under the License. +from deepaas import exceptions + import stevedore NAMESPACES = { @@ -21,6 +23,28 @@ } +def get_model_by_name(name, version): + """Get a model by its name. + + :param name: The name of the model. + :type name: str + :param version: The version of the model. + :type version: str + + :returns: The model. + :rtype: object + """ + mgr = stevedore.NamedExtensionManager( + namespace=NAMESPACES.get(version), + names=[name], + ) + if name not in mgr.names(): + raise exceptions.ModuleNotFoundError( + "Model '%s' not found in namespace '%s'" % (name, NAMESPACES.get(version)) + ) + return mgr[name].plugin + + def get_available_model_names(version): """Get the names of all the models that are available on the system. diff --git a/deepaas/model/v2/__init__.py b/deepaas/model/v2/__init__.py index 987b893e..920cc01b 100644 --- a/deepaas/model/v2/__init__.py +++ b/deepaas/model/v2/__init__.py @@ -18,12 +18,16 @@ from oslo_log import log +from deepaas import config +from deepaas import exceptions from deepaas.model import loading from deepaas.model.v2 import test from deepaas.model.v2 import wrapper LOG = log.getLogger(__name__) +CONF = config.CONF + # Model registry MODELS = {} MODELS_LOADED = False @@ -37,10 +41,26 @@ def register_models(app): return try: - for name, model in loading.get_available_models("v2").items(): - MODELS[name] = wrapper.ModelWrapper(name, model, app) + if CONF.model_name: + MODELS[CONF.model_name] = wrapper.ModelWrapper( + CONF.model_name, + loading.get_model_by_name(CONF.model_name, "v2"), + app, + ) + else: + for name, model in loading.get_available_models("v2").items(): + MODELS[name] = wrapper.ModelWrapper(name, model, app) + except exceptions.ModuleNotFoundError: + LOG.error("Model not found: %s", CONF.model_name) + raise except Exception as e: + # We do not raise here, as we have not yet removed the deprecated loading of the + # test module... but we should remove it as soon as the code below is deprecated LOG.warning("Error loading models: %s", e) + warnings.warn( + "Error loading models, using test model. This will be deprecated soon.", + DeprecationWarning, + ) if MODELS: if len(MODELS) > 1: diff --git a/doc/source/cli/deepaas-cli.rst b/doc/source/cli/deepaas-cli.rst index b86dcd03..b194e79f 100644 --- a/doc/source/cli/deepaas-cli.rst +++ b/doc/source/cli/deepaas-cli.rst @@ -10,20 +10,20 @@ Synopsis Description =========== -:program:`deepaas-cli` Command line interface (CLI) to DEEPaaS models +:program:`deepaas-cli` Command line interface (CLI) to DEEPaaS models that are loaded through the ``deepaas.v2.models`` entrypoint API. - One gets access to the same get_metadata, warm, predict, and train + One gets access to the same get_metadata, warm, predict, and train methods with all corresponding options as with DEEPaaS REST API. - To get available for the method options, one has to call + To get available for the method options, one has to call ``deepaas-cli --help``. Additional parameters are provided: - ``--deepaas_method_output`` is to store the output in a pre-defined - by a user file; - ``--deepaas_with_multiprocessing`` is to activate multiprocessing + ``--deepaas_method_output`` is to store the output in a pre-defined + by a user file; + ``--deepaas_with_multiprocessing`` is to activate multiprocessing support, default is True. - oslo_log package is used for logging information, which provides + oslo_log package is used for logging information, which provides additional options for the script. - If several models are available for loading, one has to provide + If several models are available for loading, one has to provide which one to load via DEEPAAS_V2_MODEL environment setting. Options @@ -42,21 +42,31 @@ Options Calls predict() method. The output can be stored via --deepaas_method_output. - + .. option:: train Calls train() method. The output can be stored via --deepaas_method_output. -.. option:: --deepaas_method_output +.. option:: --deepaas_method_output - To save the results to a local file, if needed. Available for + To save the results to a local file, if needed. Available for get_metadata, predict, train methods. -.. option:: --deepaas_with_multiprocessing +.. option:: --deepaas_with_multiprocessing To activate multiprocessing support, default is True. - + +.. option:: --model-name MODEL_NAME + + Specify the model to be used. If not specified, DEEPaaS will serve all the models + that are available. If specified, DEEPaaS will serve only the specified model. You + can also use the DEEPAAS_V2_MODEL environment variable. + + WARNING: Serving multiple models is deprecated and will be removed in the future, + therefore it is strongly suggested that you specify the model you want to or that + you ensure that only one model is available. + Files ===== diff --git a/doc/source/cli/deepaas-predict.rst b/doc/source/cli/deepaas-predict.rst index 53dee532..469395d3 100644 --- a/doc/source/cli/deepaas-predict.rst +++ b/doc/source/cli/deepaas-predict.rst @@ -10,8 +10,8 @@ Synopsis Description =========== -:program:`deepaas-predict` It is a command that allows you to obtain, - through the command line, the prediction of a file or the url of +:program:`deepaas-predict` It is a command that allows you to obtain, + through the command line, the prediction of a file or the url of a file, of the models that are loaded through the ``deepaas.v2.models`` entrypoint API. @@ -28,23 +28,24 @@ Options option must be available in the model used. (by default application/json). -.. option:: --model-name CONTENT_TYPE, -c CONTENT_TYPE +.. option:: --model-name MODEL_NAME + + Specify the model to be used. If not specified, DEEPaaS will serve all the models + that are available. If specified, DEEPaaS will serve only the specified model. You + can also use the DEEPAAS_V2_MODEL environment variable. + + WARNING: Serving multiple models is deprecated and will be removed in the future, + therefore it is strongly suggested that you specify the model you want to or that + you ensure that only one model is available. - Add the name of the model from which you want - to obtain the prediction. - If there are multiple models installed and youd don't - specify the name of the one you want to use the program will fail. - If there is only one model installed, that will be used - to make the prediction. - .. option:: --output OUTPUT_DIR, -o OUTPUT_DIR Save the result to a local file. This option is required. -.. option:: --url, -u +.. option:: --url, -u If set to true, the input file is the url o a file to predict. - + Files ===== diff --git a/doc/source/cli/deepaas-run.rst b/doc/source/cli/deepaas-run.rst index 421d4d48..9ce3043c 100644 --- a/doc/source/cli/deepaas-run.rst +++ b/doc/source/cli/deepaas-run.rst @@ -16,6 +16,16 @@ Description Options ======= +.. option:: --model-name MODEL_NAME + + Specify the model to be used. If not specified, DEEPaaS will serve all the models + that are available. If specified, DEEPaaS will serve only the specified model. You + can also use the DEEPAAS_V2_MODEL environment variable. + + WARNING: Serving multiple models is deprecated and will be removed in the future, + therefore it is strongly suggested that you specify the model you want to or that + you ensure that only one model is available. + .. option:: --debug, -d If set to true, the logging level will be set to DEBUG instead of the diff --git a/doc/source/user/v2-api.rst b/doc/source/user/v2-api.rst index d16575e7..22ffc278 100644 --- a/doc/source/user/v2-api.rst +++ b/doc/source/user/v2-api.rst @@ -15,6 +15,12 @@ loaded to offer the model functionality through the API. This allows you to offer several models using a single DEEPaaS instance, by defining different entry points for the different models. +.. warning:: + Serving multiple models is marked as deprecated, and will be removed in a + future major version of the API. Please ensure that you start using the `model-name` + configuration option in your configuration file or the `--model-name` command line + option as soon as possible. + .. _Setuptools: https://setuptools.readthedocs.io/en/latest/setuptools.html When the DEEPaaS API is spawned it will look for the ``deepaas.v2.model`` diff --git a/releasenotes/notes/deprecate-old-model-loading-27aa4485b2132da7.yaml b/releasenotes/notes/deprecate-old-model-loading-27aa4485b2132da7.yaml index 62410d74..221d3863 100644 --- a/releasenotes/notes/deprecate-old-model-loading-27aa4485b2132da7.yaml +++ b/releasenotes/notes/deprecate-old-model-loading-27aa4485b2132da7.yaml @@ -5,4 +5,6 @@ prelude: > deprecations: - Loading the default deepaas-test model if no models are available is now marked as deprecated and will be removed in the next major version. - - Loading several models is now marked as deprecated. + - Loading several models is now marked as deprecated. If you have several models + installed, please use the `model-name` configuration option or the + `--model-name` CLI option.