# Deploy a custom model with Pulumi
URL: https://docs.datarobot.com/en/docs/wb-apps/app-templates/pulumi-tasks/deploy-custom-model.html

# Deploy a custom model with Pulumi

This notebook outlines how to use Pulumi to deploy a Scikit-learn classifier. Before proceeding, [download the necessary assets](https://datarobot-doc-assets.s3.us-east-1.amazonaws.com/deploy_custom_model.zip) to execute the tasks in this notebook.

## Initialize the environment

Start the environment and import the DataRobot library.

```
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

Set up functions to create and build or destroy your 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")
```

## Create a declarative custom model deployment

Use this cell to create a custom model deployment. Add your source code to DataRobot, register the model, and then initialize the deployment. The `make_custom_deployment` function below shows how to declaratively do this. You'll see some variant of this across all application templates.

```
import pulumi_datarobot as datarobot
import pulumi


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 Pulumi stack

You can now run the Pulumi stack. Doing so takes the files in the `model_package` directory from the downloaded assets, puts them into 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

You may not be interested in keeping the custom model. Use this cell to shut down the stack, deleting any assets created in DataRobot.

```
destroy_project(stack)
```

## Appendix

### How does scoring code work?

The code below shows what you upload so that DataRobot knows how to interact with the custom model. Since you are deploying a custom inference model with minimal transformations, it only defines two hooks to interact with the model, but you could add [others too](https://docs.datarobot.com/en/docs/mlops/deployment/custom-models/drum/custom-model-components.html). Since the example model is a standard Scikit-learn binary classifier, DataRobot can figure out how to interact with it without you defining any hooks. However, most model artifacts require some custom scoring logic, so the example includes 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. This example trains a random forest binary classifier using the 10K diabetes dataset. The code below is 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")
```

---
