Creación avanzada de scripts de entrada

SE APLICA A:SDK de Python azureml v1

En este artículo se explica cómo escribir scripts de entrada para casos de uso especializados.

Requisitos previos

En este artículo se da por supuesto que ya tiene un modelo de aprendizaje automático entrenado que planea implementar con Azure Machine Learning. Para más información sobre la implementación de modelos, consulte Implementación de modelos de Machine Learning en Azure.

Generación automática de un esquema de Swagger

Para generar automáticamente un esquema para el servicio web, proporcione un ejemplo de la entrada y salida del constructor de uno de los objetos de tipo definidos. El tipo y ejemplo se usan para crear automáticamente el esquema. A continuación, Azure Machine Learning crea una especificación OpenAPI (anteriormente, especificación de Swagger) para el servicio web durante la implementación.

Advertencia

No debe usar datos confidenciales o privados para la entrada o salida de ejemplo. La página de Swagger para la inferencia hospedada en AML expone los datos de ejemplo.

Actualmente se admiten estos tipos:

  • pandas
  • numpy
  • pyspark
  • Objeto estándar de Python

Para usar la generación de esquemas, incluya el paquete inference-schema de código abierto, versión 1.1.0 o superior, en el archivo de dependencias. Para obtener más información sobre este paquete, consulte InferenceSchema en GitHub. Para generar el consumo de servicios web automatizados compatible con Swagger, la función run() del script de puntuación debe tener la forma de API de:

  • Primer parámetro de tipo StandardPythonParameterType, denominado Entradas y anidados
  • Un segundo parámetro opcional de tipo StandardPythonParameterType, denominado GlobalParameters
  • Devuelve un diccionario de tipo StandardPythonParameterType, denominado Results y anidado

Defina los formatos de ejemplo de entrada y salida de las variables input_sample y output_sample, que representan los formatos de solicitud y respuesta del servicio web. Use estos ejemplos en los decoradores de entrada y salida de la función run(). El siguiente ejemplo de Scikit-learn usa generación de esquemas.

Punto de conexión compatible con Power BI

En el ejemplo siguiente se muestra cómo definir la forma de la API según las instrucciones anteriores. Este método se admite para consumir el servicio Web implementado desde Power BI.

import json
import pickle
import numpy as np
import pandas as pd
import azureml.train.automl
from sklearn.externals import joblib
from sklearn.linear_model import Ridge

from inference_schema.schema_decorators import input_schema, output_schema
from inference_schema.parameter_types.standard_py_parameter_type import StandardPythonParameterType
from inference_schema.parameter_types.numpy_parameter_type import NumpyParameterType
from inference_schema.parameter_types.pandas_parameter_type import PandasParameterType


def init():
    global model
    # Replace filename if needed.
    model_path = os.path.join(os.getenv('AZUREML_MODEL_DIR'), 'sklearn_regression_model.pkl')
    # Deserialize the model file back into a sklearn model.
    model = joblib.load(model_path)


# providing 3 sample inputs for schema generation
numpy_sample_input = NumpyParameterType(np.array([[1,2,3,4,5,6,7,8,9,10],[10,9,8,7,6,5,4,3,2,1]],dtype='float64'))
pandas_sample_input = PandasParameterType(pd.DataFrame({'name': ['Sarah', 'John'], 'age': [25, 26]}))
standard_sample_input = StandardPythonParameterType(0.0)

# This is a nested input sample, any item wrapped by `ParameterType` will be described by schema
sample_input = StandardPythonParameterType({'input1': numpy_sample_input, 
                                        'input2': pandas_sample_input, 
                                        'input3': standard_sample_input})

sample_global_parameters = StandardPythonParameterType(1.0) # this is optional
sample_output = StandardPythonParameterType([1.0, 1.0])
outputs = StandardPythonParameterType({'Results':sample_output}) # 'Results' is case sensitive

@input_schema('Inputs', sample_input) 
# 'Inputs' is case sensitive

@input_schema('GlobalParameters', sample_global_parameters) 
# this is optional, 'GlobalParameters' is case sensitive

@output_schema(outputs)

def run(Inputs, GlobalParameters): 
    # the parameters here have to match those in decorator, both 'Inputs' and 
    # 'GlobalParameters' here are case sensitive
    try:
        data = Inputs['input1']
        # data will be convert to target format
        assert isinstance(data, np.ndarray)
        result = model.predict(data)
        return result.tolist()
    except Exception as e:
        error = str(e)
        return error

Sugerencia

El valor devuelto del script puede ser cualquier objeto de Python que sea serializable para JSON. Por ejemplo, si el modelo devuelve una trama de datos de Pandas que contiene varias columnas, puede usar un decorador de salida similar al código siguiente:

output_sample = pd.DataFrame(data=[{"a1": 5, "a2": 6}])
@output_schema(PandasParameterType(output_sample))
...
result = model.predict(data)
return result

Datos binarios (es decir, imagen)

Si el modelo acepta datos binarios, como una imagen, debe modificar el archivo score.py usado para la implementación para aceptar solicitudes HTTP sin procesar. Para aceptar los datos sin procesar, use la clase AMLRequest en el script de entrada y agregue el elemento decorador @rawhttp a la función run().

Este es un ejemplo de score.py que acepta datos binarios:

from azureml.contrib.services.aml_request import AMLRequest, rawhttp
from azureml.contrib.services.aml_response import AMLResponse
from PIL import Image
import json


def init():
    print("This is init()")
    

@rawhttp
def run(request):
    print("This is run()")
    
    if request.method == 'GET':
        # For this example, just return the URL for GETs.
        respBody = str.encode(request.full_path)
        return AMLResponse(respBody, 200)
    elif request.method == 'POST':
        file_bytes = request.files["image"]
        image = Image.open(file_bytes).convert('RGB')
        # For a real-world solution, you would load the data from reqBody
        # and send it to the model. Then return the response.

        # For demonstration purposes, this example just returns the size of the image as the response.
        return AMLResponse(json.dumps(image.size), 200)
    else:
        return AMLResponse("bad request", 500)

Importante

La clase AMLRequest está en el espacio de nombres azureml.contrib. Las entidades de este espacio de nombres cambian con frecuencia mientras trabajamos para mejorar el servicio. Todo el contenido de este espacio de nombres debe considerarse una versión preliminar que no es completamente compatible con Microsoft.

Si necesita probar esto en su entorno de desarrollo local, puede instalar los componentes mediante el comando siguiente:

pip install azureml-contrib-services

Nota

No se recomienda500 como código de estado personalizado, como en azureml-fe, el código de estado se volverá a escribir en 502.

  • El código de estado se pasa a través de azureml-fe y, a continuación, se enviará al cliente.
  • Azureml-fe solo vuelve a escribir el código 500 devuelto del lado del modelo para que sea 502 y el cliente recibe un código 502.
  • Pero si el propio azureml-fe devuelve un código 500, el lado cliente seguirá recibiendo este código.

La clase AMLRequest solo permite acceder a los datos publicados sin procesar en el archivo score.py, no hay ningún componente del lado cliente. Desde un cliente, los datos se publican de la forma habitual. Por ejemplo, el siguiente código de Python lee un archivo de imagen y envía los datos:

import requests

uri = service.scoring_uri
image_path = 'test.jpg'
files = {'image': open(image_path, 'rb').read()}
response = requests.post(uri, files=files)

print(response.json)

Uso compartido de recursos entre orígenes (CORS)

El uso compartido de recursos entre orígenes es una manera de permitir que los recursos de una página web se soliciten desde otro dominio. CORS funciona a través de los encabezados HTTP enviados con la solicitud del cliente y se devuelven con la respuesta del servicio. Para más información sobre CORS y los encabezados válidos, consulte Intercambio de recursos de origen cruzado en Wikipedia.

Para configurar la implementación del modelo para que admita CORS, use la clase AMLResponse en el script de entrada. Esta clase permite establecer los encabezados en el objeto de respuesta.

En el ejemplo siguiente se establece el encabezado Access-Control-Allow-Origin para la respuesta desde el script de entrada:

from azureml.contrib.services.aml_request import AMLRequest, rawhttp
from azureml.contrib.services.aml_response import AMLResponse


def init():
    print("This is init()")

@rawhttp
def run(request):
    print("This is run()")
    print("Request: [{0}]".format(request))
    if request.method == 'GET':
        # For this example, just return the URL for GET.
        # For a real-world solution, you would load the data from URL params or headers
        # and send it to the model. Then return the response.
        respBody = str.encode(request.full_path)
        resp = AMLResponse(respBody, 200)
        resp.headers["Allow"] = "OPTIONS, GET, POST"
        resp.headers["Access-Control-Allow-Methods"] = "OPTIONS, GET, POST"
        resp.headers['Access-Control-Allow-Origin'] = "http://www.example.com"
        resp.headers['Access-Control-Allow-Headers'] = "*"
        return resp
    elif request.method == 'POST':
        reqBody = request.get_data(False)
        # For a real-world solution, you would load the data from reqBody
        # and send it to the model. Then return the response.
        resp = AMLResponse(reqBody, 200)
        resp.headers["Allow"] = "OPTIONS, GET, POST"
        resp.headers["Access-Control-Allow-Methods"] = "OPTIONS, GET, POST"
        resp.headers['Access-Control-Allow-Origin'] = "http://www.example.com"
        resp.headers['Access-Control-Allow-Headers'] = "*"
        return resp
    elif request.method == 'OPTIONS':
        resp = AMLResponse("", 200)
        resp.headers["Allow"] = "OPTIONS, GET, POST"
        resp.headers["Access-Control-Allow-Methods"] = "OPTIONS, GET, POST"
        resp.headers['Access-Control-Allow-Origin'] = "http://www.example.com"
        resp.headers['Access-Control-Allow-Headers'] = "*"
        return resp
    else:
        return AMLResponse("bad request", 400)

Importante

La clase AMLResponse está en el espacio de nombres azureml.contrib. Las entidades de este espacio de nombres cambian con frecuencia mientras trabajamos para mejorar el servicio. Todo el contenido de este espacio de nombres debe considerarse una versión preliminar que no es completamente compatible con Microsoft.

Si necesita probar esto en su entorno de desarrollo local, puede instalar los componentes mediante el comando siguiente:

pip install azureml-contrib-services

Advertencia

Azure Machine Learning solo enruta las solicitudes POST y GET a los contenedores que ejecutan el servicio de puntuación. Esto puede producir errores porque los exploradores usan solicitudes OPTIONS para preparar solicitudes CORS.

Carga de los modelos registrados

Hay dos maneras de buscar modelos en el script de entrada:

  • AZUREML_MODEL_DIR: variable de entorno que contiene la ruta de acceso a la ubicación del modelo
  • Model.get_model_path: API que devuelve la ruta de acceso al archivo de modelo mediante el nombre del modelo registrado

AZUREML_MODEL_DIR

AZUREML_MODEL_DIR es una variable de entorno que se crea durante la implementación del servicio. Puede usar esta variable de entorno para buscar la ubicación de los modelos implementados.

En la tabla siguiente se describe el valor de AZUREML_MODEL_DIR en función del número de modelos implementados:

Implementación Valor de la variable de entorno
Modelo único Ruta de acceso a la carpeta que contiene el modelo.
Varios modelos Ruta de acceso a la carpeta que contiene todos los modelos. Los modelos se encuentran por nombre y versión en esta carpeta ($MODEL_NAME/$VERSION).

Durante el registro y la implementación de un modelo, este se coloca en la ruta de acceso AZUREML_MODEL_DIR y se conserva su nombre de archivo original.

Para obtener la ruta de acceso a un archivo de modelo en el script de entrada, combine la variable de entorno con la ruta de acceso al archivo que busca.

Ejemplo de modelo único

# Example when the model is a file
model_path = os.path.join(os.getenv('AZUREML_MODEL_DIR'), 'sklearn_regression_model.pkl')

# Example when the model is a folder containing a file
file_path = os.path.join(os.getenv('AZUREML_MODEL_DIR'), 'my_model_folder', 'sklearn_regression_model.pkl')

Ejemplo de varios modelos

En este escenario, se registran dos modelos con el área de trabajo:

  • my_first_model: contiene un archivo (my_first_model.pkl) y solo existe una versión, 1
  • my_second_model: contiene un archivo (my_second_model.pkl) y hay dos versiones, 1 y 2

Cuando se implementó el servicio, ambos modelos se proporcionan en la operación de implementación:

first_model = Model(ws, name="my_first_model", version=1)
second_model = Model(ws, name="my_second_model", version=2)
service = Model.deploy(ws, "myservice", [first_model, second_model], inference_config, deployment_config)

En la imagen de Docker que hospeda el servicio, la variable de entorno AZUREML_MODEL_DIR contiene el directorio donde se encuentran los modelos. En este directorio, cada uno de los modelos se encuentra en una ruta de acceso al directorio de MODEL_NAME/VERSION. Donde MODEL_NAME es el nombre del modelo registrado y VERSION es la versión del modelo. Los archivos que componen el modelo registrado se almacenan en estos directorios.

En este ejemplo, las rutas de acceso serían $AZUREML_MODEL_DIR/my_first_model/1/my_first_model.pkl y $AZUREML_MODEL_DIR/my_second_model/2/my_second_model.pkl.

# Example when the model is a file, and the deployment contains multiple models
first_model_name = 'my_first_model'
first_model_version = '1'
first_model_path = os.path.join(os.getenv('AZUREML_MODEL_DIR'), first_model_name, first_model_version, 'my_first_model.pkl')
second_model_name = 'my_second_model'
second_model_version = '2'
second_model_path = os.path.join(os.getenv('AZUREML_MODEL_DIR'), second_model_name, second_model_version, 'my_second_model.pkl')

get_model_path

Cuando registra un modelo, puede proporcionar un nombre de modelo que se usa para administrar este en el registro. Usará este nombre con el método Model.get_model_path() para recuperar la ruta de acceso del archivo del modelo en el sistema de archivos local. Si registra una carpeta o una colección de archivos, esta API devolverá la ruta de acceso del directorio que contiene esos archivos.

Al registrar un modelo, se le asigna un nombre. El nombre se corresponde con la ubicación donde se coloque el modelo, ya sea localmente o durante la implementación del servicio.

Ejemplos específicos del marco

Consulte los artículos siguientes para obtener más ejemplos de scripts de entrada para casos de uso específicos de aprendizaje automático: