# Deploy a custom model with Pulumi
URL: https://docs.datarobot.com/en/docs/api/dev-learning/python/py-code-examples/pulumi-examples/deploy_custom_inference_model.html

# Deploy a custom model with Pulumi

This notebook outlines how to use Pulumi to deploy a scikit learn classifier in two easy stages.

## Initialize the environment

```
import os

import datarobot as dr

os.environ["PULUMI_CONFIG_PASSPHRASE"] = "default"

assert (
    "DATAROBOT_API_TOKEN" in os.environ
), "Please set the DATAROBOT_API_TOKEN environment variable"
assert "DATAROBOT_ENDPOINT" in os.environ, "Please set the DATAROBOT_ENDPOINT environment variable"

dr.Client()
```

## Set up a project

Configure the functions below to create and build or destroy the Pulumi stack.

```
from pulumi import automation as auto


def stack_up(project_name: str, stack_name: str, program: callable) -> auto.Stack:
    # create (or select if one already exists) a stack that uses our inline program
    stack = auto.create_or_select_stack(
        stack_name=stack_name, project_name=project_name, program=program
    )

    stack.refresh(on_output=print)

    stack.up(on_output=print)
    return stack


def destroy_project(stack: auto.Stack):
    """Destroy pulumi project"""
    stack_name = stack.name
    stack.destroy(on_output=print)

    stack.workspace.remove_stack(stack_name)
    print(f"stack {stack_name} in project removed")
```

## Declarative custom model deployment

To deploy a custom model, you have to put your source code onto DataRobot, register the model, and then initialize the deployment. The `make_custom_deployment` function below shows the declarative way to do this.

```
import pulumi
import pulumi_datarobot as datarobot


def make_custom_inference_deployment():
    """
    Deploy a trained model onto DataRobot's prediction environment.

    Upload source code to create a custom model version.
    Then create a registered model and deploy it to a prediction environment.
    """

    # ID for Python 3.9 Scikit learn drop in environment
    base_environment_id = "5e8c889607389fe0f466c72d"

    # ID for the default prediction server
    default_prediction_server_id = "5dd7fa2274a35f003102f60d"

    custom_model_name = "App Template Minis - Readmitted Custom Model"
    registered_model_name = "App Template Minis - Readmitted Registered Model"
    deployment_name = "App Template Minis - Readmitted Deployed Model"

    deployment_files = [
        ("./model_package/requirements.txt", "requirements.txt"),
        ("./model_package/custom.py", "custom.py"),
        ("./model_package/model.pkl", "model.pkl"),
    ]

    custom_model = datarobot.CustomModel(
        resource_name=custom_model_name,
        files=deployment_files,
        base_environment_id=base_environment_id,
        language="python",
        target_type="Binary",
        target_name="readmitted",
    )

    registered_model = datarobot.RegisteredModel(
        resource_name=registered_model_name,
        custom_model_version_id=custom_model.version_id,
    )

    deployment = datarobot.Deployment(
        resource_name=deployment_name,
        label=deployment_name,
        registered_model_version_id=registered_model.version_id,
        prediction_environment_id=default_prediction_server_id,
    )

    pulumi.export("custom_model_id", custom_model.id)
    pulumi.export("registered_model_id", registered_model.id)
    pulumi.export("deployment_id", deployment.id)
```

## Run the stack

Running the stack takes the files that are in the `model_package` directory, puts them onto DataRobot as a custom model, registers that model, and deploys the result.

```
project_name = "AppTemplateMinis-CustomInferenceModels"
stack_name = "MarshallsCustomReadmissionsPredictor"

stack = stack_up(project_name, stack_name, program=make_custom_inference_deployment)
```

### Interact with outputs

```
from datarobot_predict.deployment import predict
import pandas as pd

df = pd.read_csv("https://s3.amazonaws.com/datarobot_public_datasets/10k_diabetes.csv").tail(100)


deployment_id = stack.outputs().get("deployment_id").value
deployment = dr.Deployment.get(deployment_id)

predict(deployment, data_frame=df).dataframe.head(10).iloc[:, :2]
```

## Clear your work

Use the following cell to shut down the stack, thereby deleting any assets created in DataRobot.

```
destroy_project(stack)
```

### How does scoring code work?

The following cell contains code used to upload so that DataRobot knows how to interact with our model. Deploying a custom inference model with minimal transformation only requires two hooks to be defined, but you could add [others too](https://docs.datarobot.com/en/docs/mlops/deployment/custom-models/custom-model-assembly/custom-model-components.html).

Since the model is a standard scikit-learn binary classifier, DataRobot is smart enough to figure out how to interact with it without you defining any hooks. Since most model artifacts require some custom scoring logic though, you can make a `custom.py` file anyway.

```
from IPython.display import Code

Code(filename="./model_package/custom.py", language="python")
```

### What did I deploy?

If you're curious how you got the fitted model in the first place, `fit_custom_model.py` shows the dataset and model fitting code. The following cell displays the code used to train and pickle the model. It's not important for running the template.

```
from IPython.display import Code

Code(filename="./fit_custom_model.py", language="python")
```

---
