Dela via


Anpassa R-skriptet så att det körs i produktion

Den här artikeln beskriver hur du tar ett befintligt R-skript och gör lämpliga ändringar för att köra det som ett jobb i Azure Mašinsko učenje.

Du måste göra det mesta av, om inte alla, av de ändringar som beskrivs i detalj i den här artikeln.

Ta bort användarinteraktion

R-skriptet måste vara utformat för att köras obevakat och köras via Rscript kommandot i containern. Se till att du tar bort interaktiva indata eller utdata från skriptet.

Lägg till parsning

Om skriptet kräver någon typ av indataparameter (de flesta skript gör det) skickar du indata till skriptet via anropet Rscript .

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

I R-skriptet parsar du indata och gör rätt typkonverteringar. Vi rekommenderar att du använder paketet optparse .

Följande kodfragment visar hur du:

  • initiera parsern
  • lägg till alla dina indata som alternativ
  • parsa indata med lämpliga datatyper

Du kan också lägga till standardvärden som är praktiska för testning. Vi rekommenderar att du lägger till en --output parameter med standardvärdet ./outputs så att alla utdata från skriptet lagras.

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 är en namngiven lista. Du kan använda någon av dessa parametrar senare i skriptet.

Hämta hjälpskriptet azureml_utils.R

Du måste hämta ett hjälpskript med namnet azureml_utils.R script i samma arbetskatalog för R-skriptet som ska köras. Hjälpskriptet krävs för att R-skriptet som körs ska kunna kommunicera med MLflow-servern. Hjälpskriptet tillhandahåller en metod för att kontinuerligt hämta autentiseringstoken, eftersom token ändras snabbt i ett jobb som körs. Med hjälpskriptet kan du också använda loggningsfunktionerna i R MLflow-API:et för att logga modeller, parametrar, taggar och allmänna artefakter.

  1. Skapa filen , azureml_utils.Rmed den här koden:

    # 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. Starta R-skriptet med följande rad:

source("azureml_utils.R")

Läsa datafiler som lokala filer

När du kör ett R-skript som ett jobb tar Azure Mašinsko učenje de data som du anger i jobböverföringen och monterar dem på containern som körs. Därför kan du läsa datafilerna som om de vore lokala filer i containern som körs.

  • Kontrollera att dina källdata är registrerade som en datatillgång
  • Skicka datatillgången efter namn i parametrarna för jobböverföring
  • Läsa filerna som du normalt skulle läsa en lokal fil

Definiera indataparametern enligt beskrivningen i avsnittet parametrar. Använd parametern , data-fileför att ange en hel sökväg så att du kan använda read_csv(args$data_file) för att läsa datatillgången.

Spara jobbartefakter (bilder, data osv.)

Viktigt!

Det här avsnittet gäller inte för modeller. Se följande två avsnitt för modellspecifika instruktioner för sparande och loggning.

Du kan lagra godtyckliga skriptutdata som datafiler, bilder, serialiserade R-objekt osv. som genereras av R-skriptet i Azure Mašinsko učenje. Skapa en ./outputs katalog för att lagra alla genererade artefakter (bilder, modeller, data osv.) Alla filer som sparas i ./outputs inkluderas automatiskt i körningen och laddas upp till experimentet i slutet av körningen. Eftersom du har lagt till ett standardvärde för parametern --output i avsnittet indataparametrar ska du ta med följande kodfragment i R-skriptet för att skapa output katalogen.

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

När du har skapat katalogen sparar du artefakterna i katalogen. Till exempel:

# 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"))

crate dina modeller med carrier paketet

Dokumentationen för R MLflow API anger att dina R-modeller måste vara av modellsmakencrate.

  • Om ditt R-skript tränar en modell och du skapar ett modellobjekt måste crate du kunna distribuera det vid ett senare tillfälle med Azure Mašinsko učenje.
  • När du använder crate funktionen använder du explicita namnområden när du anropar alla paketfunktioner som du behöver.

Anta att du har ett tidsseriemodellobjekt som heter my_ts_model skapad med fable paketet. För att göra den här modellen anropsbar när den distribueras skapar du en crate plats där du skickar in modellobjektet och en prognoshorisont i antal perioder:

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

Objektet crated_model är det som du loggar.

Loggmodeller, parametrar, taggar eller andra artefakter med R MLflow-API:et

Förutom att spara alla genererade artefakter kan du även logga modeller, taggar och parametrar för varje körning. Använd R MLflow-API:et för att göra det.

När du loggar en modell loggar du den crated-modell som du skapade enligt beskrivningen i föregående avsnitt.

Kommentar

När du loggar en modell sparas även modellen och läggs till i körningsartefakterna. Du behöver inte spara en modell uttryckligen om du inte har loggat den.

Så här loggar du en modell och/eller parameter:

  1. Starta körningen med mlflow_start_run()
  2. Logga artefakter med mlflow_log_model, mlflow_log_parameller mlflow_log_batch
  3. Avsluta inte körningen med mlflow_end_run(). Hoppa över det här anropet eftersom det för närvarande orsakar ett fel.

Om du till exempel vill logga crated_model objektet som det skapades i föregående avsnitt skulle du inkludera följande kod i R-skriptet:

Dricks

Använd models som värde för artifact_path när du loggar en modell, det här är en bra idé (även om du kan ge den ett annat namn.)

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()

Skriptstruktur och exempel

Använd dessa kodfragment som en guide för att strukturera R-skriptet genom att följa alla ändringar som beskrivs i den här artikeln.

# 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

Skapa en miljö

Om du vill köra R-skriptet ml använder du tillägget för Azure CLI, även kallat CLI v2. Kommandot ml använder en YAML-jobbdefinitionsfil. Mer information om hur du skickar jobb med az mlfinns i Träna modeller med Azure Mašinsko učenje CLI.

YAML-jobbfilen anger en miljö. Du måste skapa den här miljön på din arbetsyta innan du kan köra jobbet.

Du kan skapa miljön i Azure Mašinsko učenje Studio eller med Azure CLI.

Oavsett vilken metod du använder använder du en Dockerfile. Alla Docker-kontextfiler för R-miljöer måste ha följande specifikation för att kunna arbeta med Azure Mašinsko učenje:

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/')"

Basavbildningen är rocker/tidyverse:latest, som redan har många R-paket och deras beroenden installerade.

Viktigt!

Du måste installera alla R-paket som skriptet måste köra i förväg. Lägg till fler rader i Docker-kontextfilen efter behov.

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

Ytterligare förslag

Några ytterligare förslag som du kanske vill överväga:

  • Använd R:s funktion för undantags tryCatch - och felhantering
  • Lägga till explicit loggning för felsökning och felsökning

Nästa steg