Udostępnij za pośrednictwem


Dostosowywanie skryptu języka R do uruchamiania w środowisku produkcyjnym

W tym artykule wyjaśniono, jak podjąć istniejący skrypt języka R i wprowadzić odpowiednie zmiany w celu uruchomienia go jako zadania w usłudze Azure Machine Learning.

Musisz w większości, jeśli nie wszystkie, wprowadzić większość zmian opisanych szczegółowo w tym artykule.

Usuwanie interakcji użytkownika

Skrypt języka R musi być zaprojektowany do uruchamiania nienadzorowanego i zostanie wykonany za pomocą Rscript polecenia w kontenerze. Upewnij się, że usunięto wszystkie interaktywne dane wejściowe lub wyjściowe ze skryptu.

Dodawanie analizowania

Jeśli skrypt wymaga jakiegokolwiek parametru wejściowego (większość skryptów wykonuje), przekaż dane wejściowe do skryptu za pośrednictwem wywołania Rscript .

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

W skrytecie języka R przeanalizuj dane wejściowe i dokonaj odpowiednich konwersji typów. Zalecamy użycie optparse pakietu.

Poniższy fragment kodu pokazuje, jak:

  • inicjowanie analizatora
  • dodaj wszystkie dane wejściowe jako opcje
  • Analizowanie danych wejściowych przy użyciu odpowiednich typów danych

Możesz również dodać wartości domyślne, które są przydatne do testowania. Zalecamy dodanie parametru --output z wartością ./outputs domyślną , aby wszystkie dane wyjściowe skryptu będą przechowywane.

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 jest nazwaną listą. W dalszej części skryptu możesz użyć dowolnego z tych parametrów.

Źródło skryptu azureml_utils.R pomocnika

Musisz uruchomić skrypt pomocnika o nazwie azureml_utils.R script w tym samym katalogu roboczym skryptu języka R. Skrypt pomocnika jest wymagany, aby uruchomiony skrypt języka R mógł komunikować się z serwerem MLflow. Skrypt pomocnika udostępnia metodę ciągłego pobierania tokenu uwierzytelniania, ponieważ token szybko zmienia się w uruchomionym zadaniu. Skrypt pomocnika umożliwia również używanie funkcji rejestrowania dostępnych w interfejsie API języka R MLflow do rejestrowania modeli, parametrów, tagów i ogólnych artefaktów.

  1. Utwórz plik , azureml_utils.Rprzy użyciu następującego kodu:

    # 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. Uruchom skrypt języka R z następującym wierszem:

source("azureml_utils.R")

Odczytywanie plików danych jako plików lokalnych

Po uruchomieniu skryptu języka R jako zadania usługa Azure Machine Learning pobiera dane określone w przesłaniu zadania i instaluje je w uruchomionym kontenerze. W związku z tym będzie można odczytywać pliki danych tak, jakby były plikami lokalnymi w uruchomionym kontenerze.

  • Upewnij się, że dane źródłowe są zarejestrowane jako zasób danych
  • Przekazywanie zasobu danych według nazwy w parametrach przesyłania zadania
  • Odczytywanie plików w zwykły sposób odczytuje plik lokalny

Zdefiniuj parametr wejściowy, jak pokazano w sekcji parametrów. Użyj parametru , data-fileaby określić całą ścieżkę, aby można read_csv(args$data_file) było odczytać zasób danych.

Zapisywanie artefaktów zadań (obrazy, dane itp.)

Ważne

Ta sekcja nie dotyczy modeli. Zapoznaj się z następującymi dwoma sekcjami, aby uzyskać instrukcje dotyczące zapisywania i rejestrowania określonego modelu.

Możesz przechowywać dowolne dane wyjściowe skryptu, takie jak pliki danych, obrazy, serializowane obiekty języka R itp., które są generowane przez skrypt języka R w usłudze Azure Machine Learning. Utwórz ./outputs katalog do przechowywania wszelkich wygenerowanych artefaktów (obrazów, modeli, danych itp.) Wszystkie pliki zapisane w ./outputs programie zostaną automatycznie dołączone do przebiegu i przekazane do eksperymentu na końcu przebiegu. Ponieważ dodano wartość domyślną parametru --output w sekcji parametrów wejściowych, dołącz następujący fragment kodu w skrypcie języka R, aby utworzyć output katalog.

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

Po utworzeniu katalogu zapisz artefakty w tym katalogu. Na przykład:

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

cratemodele z pakietem carrier

Dokumentacja interfejsu API języka R MLflow określa, że modele języka R muszą być w crate wersji modelu.

  • Jeśli skrypt języka R trenuje model i tworzysz obiekt modelu, musisz crate go wdrożyć w późniejszym czasie za pomocą usługi Azure Machine Learning.
  • W przypadku korzystania z crate funkcji użyj jawnych przestrzeni nazw podczas wywoływania dowolnej potrzebnej funkcji pakietu.

Załóżmy, że masz obiekt modelu timeseries o nazwie my_ts_model utworzony za pomocą fable pakietu. Aby ten model był wywoływany podczas wdrażania, utwórz crate miejsce, w którym przekażesz obiekt modelu i horyzont prognozowania w liczbie okresów:

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

Obiekt crated_model jest obiektem, który będziesz rejestrować.

Modele dzienników, parametry, tagi lub inne artefakty za pomocą interfejsu API języka R MLflow

Oprócz zapisywania wszelkich wygenerowanych artefaktów można również rejestrować modele, tagi i parametry dla każdego przebiegu. Użyj interfejsu API języka R MLflow, aby to zrobić.

Podczas rejestrowania modelu rejestrujesz utworzony model zgodnie z opisem w poprzedniej sekcji.

Uwaga

Podczas rejestrowania modelu model jest również zapisywany i dodawany do artefaktów uruchamiania. Nie ma potrzeby jawnego zapisywania modelu, chyba że nie został on zapisany.

Aby zarejestrować model i/lub parametr:

  1. Uruchom przebieg za pomocą polecenia mlflow_start_run()
  2. Artefakty dziennika za pomocą elementu mlflow_log_model, mlflow_log_paramlub mlflow_log_batch
  3. Nie kończ przebiegu za pomocą polecenia mlflow_end_run(). Pomiń to wywołanie, ponieważ obecnie powoduje błąd.

Na przykład aby zarejestrować crated_model obiekt utworzony w poprzedniej sekcji, należy uwzględnić następujący kod w skrycie języka R:

Napiwek

Użyj models wartości jako wartości artifact_path podczas rejestrowania modelu, jest to najlepsze rozwiązanie (mimo że można nazwać go czymś innym).

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 skryptu i przykład

Użyj tych fragmentów kodu jako przewodnika po strukturze skryptu języka R, postępując zgodnie ze wszystkimi zmianami opisanymi w tym artykule.

# 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

Utwórz środowisko

Aby uruchomić skrypt języka R, użyjesz rozszerzenia dla interfejsu ml wiersza polecenia platformy Azure, nazywanego również interfejsem wiersza polecenia w wersji 2. Polecenie ml używa pliku definicji zadań YAML. Aby uzyskać więcej informacji na temat przesyłania zadań za pomocą az mlprogramu , zobacz Trenowanie modeli za pomocą interfejsu wiersza polecenia usługi Azure Machine Learning.

Plik zadania YAML określa środowisko. Przed uruchomieniem zadania należy utworzyć to środowisko w obszarze roboczym.

Środowisko można utworzyć w usłudze Azure Machine Learning Studio lub za pomocą interfejsu wiersza polecenia platformy Azure.

Niezależnie od używanej metody użyjesz pliku Dockerfile. Wszystkie pliki kontekstowe platformy Docker dla środowisk języka R muszą mieć następującą specyfikację, aby można było pracować w usłudze Azure Machine Learning:

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

Obraz podstawowy to rocker/tidyverse:latest, który zawiera wiele pakietów języka R i ich zależności, które zostały już zainstalowane.

Ważne

Należy zainstalować wszystkie pakiety języka R, które skrypt będzie musiał uruchomić z wyprzedzeniem. Dodaj więcej wierszy do pliku kontekstu platformy Docker zgodnie z potrzebami.

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

Dodatkowe sugestie

Niektóre dodatkowe sugestie, które warto wziąć pod uwagę:

  • Używanie funkcji języka R tryCatch do obsługi wyjątków i błędów
  • Dodawanie jawnego rejestrowania na potrzeby rozwiązywania problemów i debugowania

Następne kroki