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.
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.
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.
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.
Utwórz plik ,
azureml_utils.R
przy 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))
Uruchom skrypt języka R z następującym wierszem:
source("azureml_utils.R")
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-file
aby określić całą ścieżkę, aby można read_csv(args$data_file)
było odczytać zasób danych.
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"))
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ć.
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:
- Uruchom przebieg za pomocą polecenia
mlflow_start_run()
- Artefakty dziennika za pomocą elementu
mlflow_log_model
,mlflow_log_param
lubmlflow_log_batch
- 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()
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
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 ml
programu , 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/')"
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