Přizpůsobení skriptu jazyka R pro spuštění v produkčním prostředí

Tento článek vysvětluje, jak použít existující skript jazyka R a provést příslušné změny pro jeho spuštění jako úlohu ve službě Azure Machine Learning.

Většinu změn popsaných v tomto článku budete muset provést na maximum( pokud ne všechny).

Odebrání interakce uživatele

Skript jazyka R musí být navržený tak, aby běžel bezobslužně a bude proveden příkazem Rscript v rámci kontejneru. Ujistěte se, že ze skriptu odeberete všechny interaktivní vstupy nebo výstupy.

Přidání analýzy

Pokud váš skript vyžaduje libovolný typ vstupního parametru (většina skriptů), předejte vstupy do skriptu prostřednictvím Rscript volání.

Rscript <name-of-r-script>.R
--data_file ${{inputs.<name-of-yaml-input-1>}} 
--brand ${{inputs.<name-of-yaml-input-2>}}

Ve skriptu jazyka R parsujte vstupy a proveďte správné převody typů. Doporučujeme použít optparse balíček.

Následující fragment kódu ukazuje, jak:

  • inicializovat analyzátor
  • přidání všech vstupů jako možností
  • parsování vstupů s příslušnými datovými typy

Můžete také přidat výchozí hodnoty, které jsou užitečné pro testování. Doporučujeme přidat --output parametr s výchozí hodnotou ./outputs , aby byl uložen jakýkoli výstup skriptu.

library(optparse)

parser <- OptionParser()

parser <- add_option(
  parser,
  "--output",
  type = "character",
  action = "store",
  default = "./outputs"
)

parser <- add_option(
  parser,
  "--data_file",
  type = "character",
  action = "store",
  default = "data/myfile.csv"
)

parser <- add_option(
  parser,
  "--brand",
  type = "double",
  action = "store",
  default = 1
)
args <- parse_args(parser)

args je pojmenovaný seznam. Některé z těchto parametrů můžete použít později ve skriptu.

Zdroj pomocného azureml_utils.R skriptu

Je nutné vytvořit pomocný skript s názvem azureml_utils.R skript ve stejném pracovním adresáři skriptu jazyka R, který se spustí. Pomocný skript se vyžaduje, aby spuštěný skript R mohl komunikovat se serverem MLflow. Pomocný skript poskytuje metodu pro průběžné načítání ověřovacího tokenu, protože se token rychle mění ve spuštěné úloze. Pomocný skript také umožňuje používat funkce protokolování poskytované v rozhraní API jazyka R MLflow k protokolování modelů, parametrů, značek a obecných artefaktů.

  1. Vytvořte soubor s azureml_utils.Rtímto kódem:

    # Azure ML utility to enable usage of the MLFlow R API for tracking with Azure Machine Learning (Azure ML). This utility does the following::
    # 1. Understands Azure ML MLflow tracking url by extending OSS MLflow R client.
    # 2. Manages Azure ML Token refresh for remote runs (runs that execute in Azure Machine Learning). It uses tcktk2 R libraray to schedule token refresh.
    #    Token refresh interval can be controlled by setting the environment variable MLFLOW_AML_TOKEN_REFRESH_INTERVAL and defaults to 30 seconds.
    
    library(mlflow)
    library(httr)
    library(later)
    library(tcltk2)
    
    new_mlflow_client.mlflow_azureml <- function(tracking_uri) {
      host <- paste("https", tracking_uri$path, sep = "://")
      get_host_creds <- function () {
        mlflow:::new_mlflow_host_creds(
          host = host,
          token = Sys.getenv("MLFLOW_TRACKING_TOKEN"),
          username = Sys.getenv("MLFLOW_TRACKING_USERNAME", NA),
          password = Sys.getenv("MLFLOW_TRACKING_PASSWORD", NA),
          insecure = Sys.getenv("MLFLOW_TRACKING_INSECURE", NA)
        )
      }
      cli_env <- function() {
        creds <- get_host_creds()
        res <- list(
          MLFLOW_TRACKING_USERNAME = creds$username,
          MLFLOW_TRACKING_PASSWORD = creds$password,
          MLFLOW_TRACKING_TOKEN = creds$token,
          MLFLOW_TRACKING_INSECURE = creds$insecure
        )
        res[!is.na(res)]
      }
      mlflow:::new_mlflow_client_impl(get_host_creds, cli_env, class = "mlflow_azureml_client")
    }
    
    get_auth_header <- function() {
        headers <- list()
        auth_token <- Sys.getenv("MLFLOW_TRACKING_TOKEN")
        auth_header <- paste("Bearer", auth_token, sep = " ")
        headers$Authorization <- auth_header
        headers
    }
    
    get_token <- function(host, exp_id, run_id) {
        req_headers <- do.call(httr::add_headers, get_auth_header())
        token_host <- gsub("mlflow/v1.0","history/v1.0", host)
        token_host <- gsub("azureml://","https://", token_host)
        api_url <- paste0(token_host, "/experimentids/", exp_id, "/runs/", run_id, "/token")
        GET( api_url, timeout(getOption("mlflow.rest.timeout", 30)), req_headers)
    }
    
    
    fetch_token_from_aml <- function() {
        message("Refreshing token")
        tracking_uri <- Sys.getenv("MLFLOW_TRACKING_URI")
        exp_id <- Sys.getenv("MLFLOW_EXPERIMENT_ID")
        run_id <- Sys.getenv("MLFLOW_RUN_ID")
        sleep_for <- 1
        time_left <- 30
        response <- get_token(tracking_uri, exp_id, run_id)
        while (response$status_code == 429 && time_left > 0) {
            time_left <- time_left - sleep_for
            warning(paste("Request returned with status code 429 (Rate limit exceeded). Retrying after ",
                        sleep_for, " seconds. Will continue to retry 429s for up to ", time_left,
                        " second.", sep = ""))
            Sys.sleep(sleep_for)
            sleep_for <- min(time_left, sleep_for * 2)
            response <- get_token(tracking_uri, exp_id)
        }
    
        if (response$status_code != 200){
            error_response = paste("Error fetching token will try again after sometime: ", str(response), sep = " ")
            warning(error_response)
        }
    
        if (response$status_code == 200){
            text <- content(response, "text", encoding = "UTF-8")
            json_resp <-jsonlite::fromJSON(text, simplifyVector = FALSE)
            json_resp$token
            Sys.setenv(MLFLOW_TRACKING_TOKEN = json_resp$token)
            message("Refreshing token done")
        }
    }
    
    clean_tracking_uri <- function() {
        tracking_uri <- httr::parse_url(Sys.getenv("MLFLOW_TRACKING_URI"))
        tracking_uri$query = ""
        tracking_uri <-httr::build_url(tracking_uri)
        Sys.setenv(MLFLOW_TRACKING_URI = tracking_uri)
    }
    
    clean_tracking_uri()
    tcltk2::tclTaskSchedule(as.integer(Sys.getenv("MLFLOW_TOKEN_REFRESH_INTERVAL_SECONDS", 30))*1000, fetch_token_from_aml(), id = "fetch_token_from_aml", redo = TRUE)
    
    # Set MLFlow related env vars
    Sys.setenv(MLFLOW_BIN = system("which mlflow", intern = TRUE))
    Sys.setenv(MLFLOW_PYTHON_BIN = system("which python", intern = TRUE))
    
  2. Spusťte skript jazyka R následujícím řádkem:

source("azureml_utils.R")

Čtení datových souborů jako místních souborů

Když spustíte skript jazyka R jako úlohu, Azure Machine Learning převezme data zadaná v odeslání úlohy a připojí je ke spuštěném kontejneru. Proto budete moct číst datové soubory, jako by se jednalo o místní soubory ve spuštěném kontejneru.

  • Ujistěte se, že jsou zdrojová data zaregistrovaná jako datový prostředek.
  • Předání datového assetu podle názvu v parametrech odeslání úlohy
  • Čtení souborů obvyklým způsobem čtení místního souboru

Definujte vstupní parametr, jak je znázorněno v části parametrů. Pomocí parametru data-file, zadejte celou cestu, abyste mohli použít read_csv(args$data_file) ke čtení datového assetu.

Ukládání artefaktů úloh (obrázky, data atd.)

Důležité

Tato část se nevztahuje na modely. Pokyny k ukládání a protokolování pro konkrétní model najdete v následujících dvou částech.

Můžete ukládat libovolné výstupy skriptu, jako jsou datové soubory, obrázky, serializované objekty R atd., které jsou generovány skriptem R ve službě Azure Machine Learning. Vytvořte ./outputs adresář pro uložení všech vygenerovaných artefaktů (obrázky, modely, data atd.) Všechny soubory uložené ./outputs do spuštění se automaticky zahrnou do spuštění a nahrají se do experimentu na konci spuštění. Vzhledem k tomu, že jste do oddílu vstupních parametrů přidali výchozí hodnotu parametru--output, zahrňte do skriptu jazyka R následující fragment kódu, který vytvoří output adresář.

if (!dir.exists(args$output)) {
  dir.create(args$output)
}

Po vytvoření adresáře uložte artefakty do daného adresáře. Příklad:

# create and save a plot
library(ggplot2)

myplot <- ggplot(...)

ggsave(myplot, 
       filename = file.path(args$output,"forecast-plot.png"))


# save an rds serialized object
saveRDS(myobject, file = file.path(args$output,"myobject.rds"))

cratevaše modely s balíčkem carrier

Dokumentace k rozhraní API R MLflow určuje, že vaše modely R musí být variantou crate modelu.

  • Pokud skript R trénuje model a vytváříte objekt modelu, budete ho muset crate později nasadit pomocí služby Azure Machine Learning.
  • Při použití crate funkce použijte explicitní obory názvů při volání jakékoli funkce balíčku, kterou potřebujete.

Řekněme, že máte objekt modelu timeseries, který se nazývá my_ts_model vytvořený s balíčkem fable . Pokud chcete, aby byl tento model při nasazení volatelný, vytvořte crate místo, kde předáte objekt modelu a horizont prognózy v počtu období:

library(carrier)
crated_model <- crate(function(x)
{
  fabletools::forecast(!!my_ts_model, h = x)
})

Objekt crated_model je objekt, který zapíšete.

Modely protokolů, parametry, značky nebo jiné artefakty s využitím rozhraní API MLflow jazyka R

Kromě ukládání všech vygenerovaných artefaktů můžete také protokolovat modely, značky a parametry pro každé spuštění. K tomu použijte rozhraní API R MLflow.

Při protokolování modelu zaznamenáte jmenovitý model , který jste vytvořili, jak je popsáno v předchozí části.

Poznámka:

Při protokolování modelu se také uloží a přidá do artefaktů spuštění. Model není nutné explicitně ukládat, pokud jste ho nezapíšete.

Protokolování modelu a/nebo parametru:

  1. Spuštění spuštění pomocí mlflow_start_run()
  2. Protokolovat artefakty pomocí mlflow_log_model, mlflow_log_paramnebo mlflow_log_batch
  3. Ukončete spuštění s mlflow_end_run(). Přeskočte toto volání, protože aktuálně způsobuje chybu.

Pokud chcete například objekt protokolovat crated_model tak, jak byl vytvořen v předchozí části, zahrnuli byste do skriptu jazyka R následující kód:

Tip

Tato hodnota se používá models jako hodnota pro artifact_path protokolování modelu, což je osvědčený postup (i když ho můžete pojmenovat jinak.)

mlflow_start_run()

mlflow_log_model(
  model = crated_model, # the crate model object
  artifact_path = "models" # a path to save the model object to
  )

mlflow_log_param(<key-name>, <value>)

# mlflow_end_run() - causes an error, do not include mlflow_end_run()

Struktura skriptů a příklad

Tyto fragmenty kódu použijte jako vodítko ke strukturování skriptu jazyka R podle všech změn popsaných v tomto článku.

# BEGIN R SCRIPT

# source the azureml_utils.R script which is needed to use the MLflow back end
# with R
source("azureml_utils.R")

# load your packages here. Make sure that they are installed in the container.
library(...)

# parse the command line arguments.
library(optparse)

parser <- OptionParser()

parser <- add_option(
  parser,
  "--output",
  type = "character",
  action = "store",
  default = "./outputs"
)

parser <- add_option(
  parser,
  "--data_file",
  type = "character",
  action = "store",
  default = "data/myfile.csv"
)

parser <- add_option(
  parser,
  "--brand",
  type = "double",
  action = "store",
  default = 1
)
args <- parse_args(parser)

# your own R code goes here
# - model building/training
# - visualizations
# - etc.

# create the ./outputs directory
if (!dir.exists(args$output)) {
  dir.create(args$output)
}

# log models and parameters to MLflow
mlflow_start_run()

mlflow_log_model(
  model = crated_model, # the crate model object
  artifact_path = "models" # a path to save the model object to
  )

mlflow_log_param(<key-name>, <value>)

# mlflow_end_run() - causes an error, do not include mlflow_end_run()
## END OF R SCRIPT

Vytvořit prostředí

Ke spuštění skriptu R použijete ml rozšíření pro Azure CLI, označované také jako CLI v2. Příkaz ml používá soubor definic úloh YAML. Další informace o odesílání úloh pomocí az mltématu Trénování modelů pomocí rozhraní příkazového řádku služby Azure Machine Learning.

Soubor úlohy YAML určuje prostředí. Před spuštěním úlohy budete muset toto prostředí vytvořit ve svém pracovním prostoru.

Prostředí můžete vytvořit v studio Azure Machine Learning nebo pomocí Azure CLI.

Bez ohledu na to, kterou metodu použijete, použijete soubor Dockerfile. Aby bylo možné pracovat se službou Azure Machine Learning, musí mít všechny soubory kontextu Dockeru pro prostředí R následující specifikaci:

FROM rocker/tidyverse:latest

# Install python
RUN apt-get update -qq && \
 apt-get install -y python3-pip tcl tk libz-dev libpng-dev

RUN ln -f /usr/bin/python3 /usr/bin/python
RUN ln -f /usr/bin/pip3 /usr/bin/pip
RUN pip install -U pip

# Install azureml-MLflow
RUN pip install azureml-MLflow
RUN pip install MLflow

# Create link for python
RUN ln -f /usr/bin/python3 /usr/bin/python

# Install R packages required for logging with MLflow (these are necessary)
RUN R -e "install.packages('mlflow', dependencies = TRUE, repos = 'https://cloud.r-project.org/')"
RUN R -e "install.packages('carrier', dependencies = TRUE, repos = 'https://cloud.r-project.org/')"
RUN R -e "install.packages('optparse', dependencies = TRUE, repos = 'https://cloud.r-project.org/')"
RUN R -e "install.packages('tcltk2', dependencies = TRUE, repos = 'https://cloud.r-project.org/')"

Základní image je rocker/tidyverse:latest, která má mnoho balíčků R a jejich závislosti jsou již nainstalovány.

Důležité

Musíte nainstalovat všechny balíčky jazyka R, které váš skript bude muset spustit předem. Podle potřeby přidejte do kontextového souboru Dockeru další řádky.

RUN R -e "install.packages('<package-to-install>', dependencies = TRUE, repos = 'https://cloud.r-project.org/')"

Další návrhy

Můžete zvážit několik dalších návrhů:

  • Použití funkce R tryCatch pro zpracování výjimek a chyb
  • Přidání explicitního protokolování pro řešení potíží a ladění

Další kroky