Beispiel #1
0
def docker_example_base_image():
    mlflow_home = os.environ.get("MLFLOW_HOME", None)
    if not mlflow_home:
        raise Exception(
            "MLFLOW_HOME environment variable is not set. Please set the variable to "
            "point to your mlflow dev root.")
    with TempDir() as tmp:
        cwd = tmp.path()
        mlflow_dir = _copy_project(src_path=mlflow_home, dst_path=cwd)
        import shutil

        shutil.copy(os.path.join(TEST_DOCKER_PROJECT_DIR, "Dockerfile"),
                    tmp.path("Dockerfile"))
        with open(tmp.path("Dockerfile"), "a") as f:
            f.write(("COPY {mlflow_dir} /opt/mlflow\n"
                     "RUN pip install -U -e /opt/mlflow\n").format(
                         mlflow_dir=mlflow_dir))

        client = docker.from_env()
        try:
            client.images.build(
                tag="mlflow-docker-example",
                forcerm=True,
                nocache=True,
                dockerfile="Dockerfile",
                path=cwd,
            )
        except BuildError as build_error:
            for chunk in build_error.build_log:
                print(chunk)
            raise build_error
        except APIError as api_error:
            print(api_error.explanation)
            raise api_error
Beispiel #2
0
def build_image(name=DEFAULT_IMAGE_NAME, mlflow_home=None):
    """
    This function builds an MLflow Docker image.
    The image is built locally and it requires Docker to run.

    :param name: image name
    """
    with TempDir() as tmp:
        install_mlflow = "RUN pip install mlflow=={version}".format(version=mlflow.version.VERSION)
        cwd = tmp.path()
        if mlflow_home:
            mlflow_dir = _copy_project(src_path=mlflow_home, dst_path=tmp.path())
            install_mlflow = "COPY {mlflow_dir} /opt/mlflow\n RUN pip install /opt/mlflow\n"
            install_mlflow = install_mlflow.format(mlflow_dir=mlflow_dir)

        with open(os.path.join(cwd, "Dockerfile"), "w") as f:
            f.write(_DOCKERFILE_TEMPLATE % install_mlflow)
        eprint("building docker image")
        os.system('find {cwd}/'.format(cwd=cwd))
        proc = Popen(["docker", "build", "-t", name, "-f", "Dockerfile", "."],
                     cwd=cwd,
                     stdout=PIPE,
                     stderr=STDOUT,
                     universal_newlines=True)
        for x in iter(proc.stdout.readline, ""):
            eprint(x, end='')
Beispiel #3
0
def _get_mlflow_install_step(dockerfile_context_dir, mlflow_home):
    """
    Get docker build commands for installing MLflow given a Docker context dir and optional source
    directory
    """
    if mlflow_home:
        mlflow_dir = _copy_project(src_path=mlflow_home,
                                   dst_path=dockerfile_context_dir)
        return (
            "COPY {mlflow_dir} /opt/mlflow\n"
            "RUN pip install /opt/mlflow\n"
            "RUN cd /opt/mlflow/mlflow/java/scoring && "
            "mvn --batch-mode package -DskipTests && "
            "mkdir -p /opt/java/jars && "
            "mv /opt/mlflow/mlflow/java/scoring/target/"
            "mlflow-scoring-*-with-dependencies.jar /opt/java/jars\n").format(
                mlflow_dir=mlflow_dir)
    else:
        return (
            "RUN pip install mlflow=={version}\n"
            "RUN mvn "
            " --batch-mode dependency:copy"
            " -Dartifact=org.mlflow:mlflow-scoring:{version}:pom"
            " -DoutputDirectory=/opt/java\n"
            "RUN mvn "
            " --batch-mode dependency:copy"
            " -Dartifact=org.mlflow:mlflow-scoring:{version}:jar"
            " -DoutputDirectory=/opt/java/jars\n"
            "RUN cp /opt/java/mlflow-scoring-{version}.pom /opt/java/pom.xml\n"
            "RUN cd /opt/java && mvn "
            "--batch-mode dependency:copy-dependencies -DoutputDirectory=/opt/java/jars\n"
        ).format(version=mlflow.version.VERSION)
Beispiel #4
0
def build_image(name=DEFAULT_IMAGE_NAME, mlflow_home=None):
    """
    This function builds an MLflow Docker image.
    The image is built locally and it requires Docker to run.

    :param name: image name
    """
    with TempDir() as tmp:
        install_mlflow = "RUN pip install mlflow=={version}".format(
            version=mlflow.version.VERSION)
        cwd = tmp.path()
        if mlflow_home:
            mlflow_dir = _copy_project(src_path=mlflow_home,
                                       dst_path=tmp.path())
            install_mlflow = ("COPY {mlflow_dir} /opt/mlflow\n"
                              "RUN cd /opt/mlflow/mlflow/java/scoring &&"
                              " mvn --batch-mode package -DskipTests \n"
                              "RUN pip install /opt/mlflow\n")
            install_mlflow = install_mlflow.format(mlflow_dir=mlflow_dir)
        else:
            eprint("`mlflow_home` was not specified. The image will install"
                   " MLflow from pip instead. As a result, the container will"
                   " not support the MLeap flavor.")

        with open(os.path.join(cwd, "Dockerfile"), "w") as f:
            f.write(_DOCKERFILE_TEMPLATE % install_mlflow)
        eprint("building docker image")
        os.system('find {cwd}/'.format(cwd=cwd))
        proc = Popen(["docker", "build", "-t", name, "-f", "Dockerfile", "."],
                     cwd=cwd,
                     stdout=PIPE,
                     stderr=STDOUT,
                     universal_newlines=True)
        for x in iter(proc.stdout.readline, ""):
            eprint(x, end='')
Beispiel #5
0
def build_image(name=DEFAULT_IMAGE_NAME, mlflow_home=None):
    """
    Build an MLflow Docker image.
    The image is built locally and it requires Docker to run.

    :param name: Docker image name.
    :param mlflow_home: (Optional) Path to a local copy of the MLflow GitHub repository.
                        If specified, the image will install MLflow from this directory.
                        If None, it will install MLflow from pip.
    """
    with TempDir() as tmp:
        cwd = tmp.path()
        if mlflow_home:
            mlflow_dir = _copy_project(
                src_path=mlflow_home, dst_path=cwd)
            install_mlflow = (
                "COPY {mlflow_dir} /opt/mlflow\n"
                "RUN pip install /opt/mlflow\n"
                "RUN cd /opt/mlflow/mlflow/java/scoring &&"
                " mvn --batch-mode package -DskipTests &&"
                " mkdir -p /opt/java/jars &&"
                " mv /opt/mlflow/mlflow/java/scoring/target/"
                "mlflow-scoring-*-with-dependencies.jar /opt/java/jars\n"
            ).format(mlflow_dir=mlflow_dir)
        else:
            install_mlflow = (
                "RUN pip install mlflow=={version}\n"
                "RUN mvn --batch-mode dependency:copy"
                " -Dartifact=org.mlflow:mlflow-scoring:{version}:pom"
                " -DoutputDirectory=/opt/java\n"
                "RUN mvn --batch-mode dependency:copy"
                " -Dartifact=org.mlflow:mlflow-scoring:{version}:jar"
                " -DoutputDirectory=/opt/java/jars\n"
                "RUN cd /opt/java && mv mlflow-scoring-{version}.pom pom.xml &&"
                " mvn --batch-mode dependency:copy-dependencies -DoutputDirectory=/opt/java/jars\n"
                "RUN rm /opt/java/pom.xml\n"
            ).format(version=mlflow.version.VERSION)

        with open(os.path.join(cwd, "Dockerfile"), "w") as f:
            f.write(_DOCKERFILE_TEMPLATE % install_mlflow)
        _logger.info("building docker image")
        os.system('find {cwd}/'.format(cwd=cwd))
        proc = Popen(["docker", "build", "-t", name, "-f", "Dockerfile", "."],
                     cwd=cwd,
                     stdout=PIPE,
                     stderr=STDOUT,
                     universal_newlines=True)
        for x in iter(proc.stdout.readline, ""):
            eprint(x, end='')
Beispiel #6
0
def build_image(model_uri,
                workspace,
                image_name=None,
                model_name=None,
                mlflow_home=None,
                description=None,
                tags=None,
                synchronous=True):
    """
    Register an MLflow model with Azure ML and build an Azure ML ContainerImage for deployment.
    The resulting image can be deployed as a web service to Azure Container Instances (ACI) or
    Azure Kubernetes Service (AKS).

    The resulting Azure ML ContainerImage will contain a webserver that processes model queries.
    For information about the input data formats accepted by this webserver, see the
    :ref:`MLflow deployment tools documentation <azureml_deployment>`.

    :param model_uri: The location, in URI format, of the MLflow model for which to build an Azure
                      ML deployment image, for example:

                      - ``/Users/me/path/to/local/model``
                      - ``relative/path/to/local/model``
                      - ``s3://my_bucket/path/to/model``
                      - ``runs:/<mlflow_run_id>/run-relative/path/to/model``

                      For more information about supported URI schemes, see the
                      `Artifacts Documentation <https://www.mlflow.org/docs/latest/tracking.html#
                      supported-artifact-stores>`_.

    :param image_name: The name to assign the Azure Container Image that will be created. If
                       unspecified, a unique image name will be generated.
    :param model_name: The name to assign the Azure Model will be created. If unspecified,
                       a unique model name will be generated.
    :param workspace: The AzureML workspace in which to build the image. This is a
                      `azureml.core.Workspace` object.
    :param mlflow_home: Path to a local copy of the MLflow GitHub repository. If specified, the
                        image will install MLflow from this directory. Otherwise, it will install
                        MLflow from pip.
    :param description: A string description to associate with the Azure Container Image and the
                        Azure Model that will be created. For more information, see
                        `<https://docs.microsoft.com/en-us/python/api/azureml-core/
                        azureml.core.image.container.containerimageconfig>`_ and
                        `<https://docs.microsoft.com/en-us/python/api/azureml-core/
                        azureml.core.model.model?view=azure-ml-py#register>`_.
    :param tags: A collection of tags, represented as a dictionary of string key-value pairs, to
                 associate with the Azure Container Image and the Azure Model that will be created.
                 These tags will be added to a set of default tags that include the model path,
                 the model run id (if specified), and more. For more information, see
                 `<https://docs.microsoft.com/en-us/python/api/azureml-core/
                 azureml.core.image.container.containerimageconfig>`_ and
                 `<https://docs.microsoft.com/en-us/python/api/azureml-core/
                 azureml.core.model.model?view=azure-ml-py#register>`_.
    :param synchronous: If `True`, this method will block until the image creation procedure
                        terminates before returning. If `False`, the method will return immediately,
                        but the returned image will not be available until the asynchronous
                        creation process completes. The `azureml.core.Image.wait_for_creation()`
                        function can be used to wait for the creation process to complete.
    :return: A tuple containing the following elements in order:
             - An `azureml.core.image.ContainerImage` object containing metadata for the new image.
             - An `azureml.core.model.Model` object containing metadata for the new model.

    >>> import mlflow.azureml
    >>> from azureml.core import Workspace
    >>> from azureml.core.webservice import AciWebservice, Webservice
    >>>
    >>> # Load or create an Azure ML Workspace
    >>> workspace_name = "<Name of your Azure ML workspace>"
    >>> subscription_id = "<Your Azure subscription ID>"
    >>> resource_group = "<Name of the Azure resource group in which to create Azure ML resources>"
    >>> location = "<Name of the Azure location (region) in which to create Azure ML resources>"
    >>> azure_workspace = Workspace.create(name=workspace_name,
    >>>                                    subscription_id=subscription_id,
    >>>                                    resource_group=resource_group,
    >>>                                    location=location,
    >>>                                    create_resource_group=True,
    >>>                                    exist_okay=True)
    >>>
    >>> # Build an Azure ML Container Image for an MLflow model
    >>> azure_image, azure_model = mlflow.azureml.build_image(
    >>>                                 model_path="<model_path>",
    >>>                                 workspace=azure_workspace,
    >>>                                 synchronous=True)
    >>> # If your image build failed, you can access build logs at the following URI:
    >>> print("Access the following URI for build logs: {}".format(azure_image.image_build_log_uri))
    >>>
    >>> # Deploy the image to Azure Container Instances (ACI) for real-time serving
    >>> webservice_deployment_config = AciWebservice.deploy_configuration()
    >>> webservice = Webservice.deploy_from_image(
    >>>                    image=azure_image, workspace=azure_workspace, name="<deployment-name>")
    >>> webservice.wait_for_deployment()
    """
    # The Azure ML SDK is only compatible with Python 3. However, the `mlflow.azureml` module should
    # still be accessible for import from Python 2. Therefore, we will only import from the SDK
    # upon method invocation.
    # pylint: disable=import-error
    from azureml.core.image import ContainerImage
    from azureml.core.model import Model as AzureModel

    absolute_model_path = _download_artifact_from_uri(model_uri)

    model_pyfunc_conf = _load_pyfunc_conf(model_path=absolute_model_path)
    model_python_version = model_pyfunc_conf.get(pyfunc.PY_VERSION, None)
    if model_python_version is not None and\
            StrictVersion(model_python_version) < StrictVersion("3.0.0"):
        raise MlflowException(message=(
            "Azure ML can only deploy models trained in Python 3 or above! Please see"
            " the following MLflow GitHub issue for a thorough explanation of this"
            " limitation and a workaround to enable support for deploying models"
            " trained in Python 2: https://github.com/mlflow/mlflow/issues/668"
        ),
                              error_code=INVALID_PARAMETER_VALUE)

    tags = _build_tags(model_uri=model_uri,
                       model_python_version=model_python_version,
                       user_tags=tags)

    if image_name is None:
        image_name = _get_mlflow_azure_resource_name()
    if model_name is None:
        model_name = _get_mlflow_azure_resource_name()

    with TempDir(chdr=True) as tmp:
        model_directory_path = tmp.path("model")
        tmp_model_path = os.path.join(
            model_directory_path,
            _copy_file_or_tree(src=absolute_model_path,
                               dst=model_directory_path))

        registered_model = AzureModel.register(workspace=workspace,
                                               model_path=tmp_model_path,
                                               model_name=model_name,
                                               tags=tags,
                                               description=description)
        _logger.info(
            "Registered an Azure Model with name: `%s` and version: `%s`",
            registered_model.name, registered_model.version)

        # Create an execution script (entry point) for the image's model server. Azure ML requires
        # the container's execution script to be located in the current working directory during
        # image creation, so we create the execution script as a temporary file in the current
        # working directory.
        execution_script_path = tmp.path("execution_script.py")
        _create_execution_script(output_path=execution_script_path,
                                 azure_model=registered_model)
        # Azure ML copies the execution script into the image's application root directory by
        # prepending "/var/azureml-app" to the specified script path. The script is then executed
        # by referencing its path relative to the "/var/azureml-app" directory. Unfortunately,
        # if the script path is an absolute path, Azure ML attempts to reference it directly,
        # resulting in a failure. To circumvent this problem, we provide Azure ML with the relative
        # script path. Because the execution script was created in the current working directory,
        # this relative path is the script path's base name.
        execution_script_path = os.path.basename(execution_script_path)

        if mlflow_home is not None:
            _logger.info(
                "Copying the specified mlflow_home directory: `%s` to a temporary location for"
                " container creation", mlflow_home)
            mlflow_home = os.path.join(
                tmp.path(),
                _copy_project(src_path=mlflow_home, dst_path=tmp.path()))
            image_file_dependencies = [mlflow_home]
        else:
            image_file_dependencies = None
        dockerfile_path = tmp.path("Dockerfile")
        _create_dockerfile(output_path=dockerfile_path,
                           mlflow_path=mlflow_home)

        conda_env_path = None
        if pyfunc.ENV in model_pyfunc_conf:
            conda_env_path = os.path.join(tmp_model_path,
                                          model_pyfunc_conf[pyfunc.ENV])

        image_configuration = ContainerImage.image_configuration(
            execution_script=execution_script_path,
            runtime="python",
            docker_file=dockerfile_path,
            dependencies=image_file_dependencies,
            conda_file=conda_env_path,
            description=description,
            tags=tags,
        )
        image = ContainerImage.create(workspace=workspace,
                                      name=image_name,
                                      image_config=image_configuration,
                                      models=[registered_model])
        _logger.info(
            "Building an Azure Container Image with name: `%s` and version: `%s`",
            image.name, image.version)
        if synchronous:
            image.wait_for_creation(show_output=True)
        return image, registered_model