Vetiver

Vetiver is a framework for MLOps tasks in Python and R. The goal of vetiver is to provide fluent tooling to version, share, deploy, and monitor a trained model. Functions handle both recording and checking the model’s input data prototype, and predicting from a remote API endpoint.

Vetiver integrates with pins in Python and pins in R to support model versioning. When you write a vetiver model to a board, the binary model object is stored together with necessary metadata, including its version, the packages needed to make a prediction, and the model’s input data prototype for checking new data at prediction time.

Deploy

To deploy a vetiver API to Connect, we recommend that users first pin their model to a board, possibly board_rsconnect() in R or in Python. From the pin info, the vetiver package can deploy the API.

library(vetiver)

vetiver_deploy_rsconnect(
    board = board, 
    name = "my.username/pin_name",
    predict_args = list(debug = TRUE),
    account = "my.username"
)

The username for the pin and the account deploying the model API do not have to be the same.

To deploy a vetiver API for a model trained in Python to Connect, users need a deployable app file as well as a file to capture dependencies. Vetiver offers functionality to build deployable files via vetiver.write_app(). Dependencies can be captured with a requirements.txt in Python.

from vetiver import vetiver_write_app
from rsconnect.actions import deploy_python_fastapi

app_file = vetiver_write_app(
     board = board,
     pin_name = "my.username/pin_name",
     file = "app.py"
)

deploy_python_fastapi(
    connect_server=connect_server,
    directory=".",
    extra_files=None,
    excludes=None,
    entry_point = "app:api",
    new=True,
    app_id=None,
    title="vetiver api",
    python=None,
    conda_mode=False,
    force_generate=False,
    log_callback=None,
)

When deploying a vetiver API in Python, ensure that you specify the correct entrypoint for the specific app you are deploying. The example above has its source code in a file named app.py, and within that file, the Vetiver API application object is named api, making the entrypoint app:api. See the documentation on entrypoints for more information.

Predict from your model endpoint

A model deployed via vetiver can be treated as a special vetiver_endpoint() object. If the API is only accessible to specified people, use an API Key for authorization. You can use predict() to make predictions from your remote endpoint with your new data.

endpoint <- vetiver_endpoint(
  "https://connect.example.com/content/$APP_ID/predict")
apiKey <- Sys.getenv("CONNECT_API_KEY")

predict(
  endpoint,
  new_data,
  httr::add_headers(Authorization = paste("Key", apiKey)))
from vetiver.server import predict, vetiver_endpoint

endpoint = vetiver_endpoint(
    f"https://connect.example.com/content/{APP_ID}/predict")

h = { 'Authorization': f'Key {api_key}' }
response = predict(endpoint = endpoint, data = new_data, headers=h)

Example

To run this example, you must have your Connect URL and API key loaded in your environment.

library(vetiver)
library(pins)

cars_lm <- lm(mpg ~ ., data = mtcars)
v <- vetiver_model(cars_lm, "cars_mpg")
b <- board_rsconnect()
vetiver_pin_write(b, v)

vetiver_deploy_rsconnect( 
     b, 
     "my.username/cars_mpg", 
     predict_args = list(debug = TRUE), 
     account = "my.username" 
)
import pins
import vetiver
from vetiver.data import mtcars

from rsconnect.api import RSConnectServer
from rsconnect.actions import deploy_python_fastapi

from sklearn import linear_model

connect_server = RSConnectServer(url = rsc_url, api_key = api_key)
board = pins.board_rsconnect(server_url = rsc_url, api_key=api_key, allow_pickle_read=True)

cars_lm = linear_model.LinearRegression().fit(mtcars, mtcars["mpg"])
v = vetiver.VetiverModel(cars_lm, model_name = "user.name/cars_mpg", 
     save_ptype = True, ptype_data = mtcars)

vetiver.vetiver_pin_write(board, v)
vetiver.vetiver_write_app(board, "user.name/cars_mpg")

deploy_python_fastapi(
    connect_server=connect_server,
    directory=".",
    extra_files=None,
    excludes=None,
    entry_point = "app:api",
    new=True,
    app_id=None,
    title="mtcars linear regression",
    python=None,
    conda_mode=False,
    force_generate=False,
    log_callback=None,
)