Adaptar o script R para executá-lo em produção
Este artigo explica como usar um script R existente e fazer as alterações apropriadas para executá-lo como um trabalho no Azure Machine Learning.
Você precisará aproveitar ao máximo, se não todas, as alterações descritas em detalhes neste artigo.
Remover interação do usuário
O script R precisa ser projetado para ser executado de maneira autônoma e será executado por meio do comando Rscript
no contêiner. Remova todas as entradas ou saídas interativas do script.
Adicionar análise
Se o script exigir qualquer tipo de parâmetro de entrada (a maioria dos scripts exige), transmita as entradas para o script por meio da chamada Rscript
.
Rscript <name-of-r-script>.R
--data_file ${{inputs.<name-of-yaml-input-1>}}
--brand ${{inputs.<name-of-yaml-input-2>}}
No script R, analise as entradas e faça as conversões de tipo adequadas. Recomendamos que você use o pacote optparse
.
O seguinte snippet mostra como:
- iniciar o analisador
- adicionar todas as entradas como opções
- analisar as entradas com os tipos de dados apropriados
Você também pode adicionar padrões, que são úteis para teste. Recomendamos que você adicione um parâmetro --output
com um valor padrão igual a ./outputs
para que qualquer saída do script seja armazenada.
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
é uma lista nomeada. Você pode usar um desses parâmetros posteriormente no script.
Gerar o script auxiliar azureml_utils.R
Você precisa gerar um script auxiliar chamado azureml_utils.R
no mesmo diretório de trabalho do script R que será executado. O script auxiliar é necessário para que o script R em execução possa se comunicar com o servidor do MLflow. O script auxiliar fornece um método para recuperar continuamente o token de autenticação, pois o token é alterado rapidamente em um trabalho em execução. O script auxiliar também permite que você use as funções de log fornecidas na API do R para MLflow para registrar em log modelos, parâmetros, marcas e artefatos gerais.
Crie o arquivo,
azureml_utils.R
, com este código:# 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))
Inicie o script R com a seguinte linha:
source("azureml_utils.R")
Ler arquivos de dados como arquivos locais
Quando você executa um script R como um trabalho, o Azure Machine Learning usa os dados especificados no envio do trabalho e os monta no contêiner em execução. Portanto, você poderá ler os arquivos de dados como se eles fossem arquivos locais no contêiner em execução.
- Verifique se os dados de origem estão registrados como um ativo de dados
- Transmita o ativo de dados pelo nome nos parâmetros de envio do trabalho
- Leia os arquivos como você normalmente leria um arquivo local
Defina o parâmetro de entrada conforme mostrado na seção de parâmetros. Use o parâmetro data-file
para especificar um caminho inteiro, de modo que você possa usar read_csv(args$data_file)
para ler o ativo de dados.
Salvar artefatos de trabalho (imagens, dados etc.)
Importante
Esta seção não se aplica aos modelos. Confira as duas seções a seguir para obter instruções de salvamento e log específicas do modelo.
Você pode armazenar saídas de script arbitrárias, como arquivos de dados, imagens, objetos R serializados etc. que são gerados pelo script R no Azure Machine Learning. Crie um diretório ./outputs
para armazenar os artefatos gerados (imagens, modelos, dados etc.). Todos os arquivos salvos em ./outputs
serão incluídos automaticamente na execução e carregados no experimento no final da execução. Como você adicionou um valor padrão para o parâmetro --output
na seção parâmetros de entrada, inclua o snippet de código a seguir no script R para criar o diretório output
.
if (!dir.exists(args$output)) {
dir.create(args$output)
}
Depois de criar o diretório, salve os artefatos nesse diretório. Por exemplo:
# 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"))
Execute crate
nos modelos com o pacote carrier
A documentação da API R MLflowespecifica que seus modelos R precisam ser do tipo crate
modelo.
- Se o script R treinar um modelo e você produzir um objeto de modelo, será necessário executar
crate
nele para que ele possa implantá-lo posteriormente com o Azure Machine Learning. - Ao usar a função
crate
, use namespaces explícitos ao chamar qualquer função de pacote necessária.
Digamos que você tenha um objeto de modelo de série temporal chamado my_ts_model
, criado com o pacote fable
. Para fazer com que esse modelo possa ser chamado quando for implantado, crie um crate
em que você transmitirá o objeto de modelo e um horizonte de previsão em número de períodos:
library(carrier)
crated_model <- crate(function(x)
{
fabletools::forecast(!!my_ts_model, h = x)
})
O objeto crated_model
é aquele que você registrará em log.
Registrar em log modelos, parâmetros, marcas ou outros artefatos com a API do R para MLflow
Além de salvar os artefatos gerados, você também pode registrar em log modelos, marcas e parâmetros para cada execução. Use a API do R para MLflow para fazer isso.
Ao registrar um modelo em log, você registra o modelo em contêiner criado conforme descrito na seção anterior.
Observação
Quando você registra um modelo em log, o modelo também é salvo e adicionado aos artefatos de execução. Não é necessário salvar explicitamente um modelo, a menos que você não o tenha registrado em log.
Para registrar um modelo e/ou um parâmetro:
- Inicie a execução com
mlflow_start_run()
- Registre os artefatos em log com
mlflow_log_model
,mlflow_log_param
oumlflow_log_batch
- Não termine a execução com
mlflow_end_run()
. Ignore essa chamada, pois, atualmente, ela causa um erro.
Por exemplo, para registrar em log o objeto crated_model
conforme criado na seção anterior, inclua o seguinte código no script R:
Dica
Use models
como valor para artifact_path
ao registrar um modelo em log. Essa é uma melhor prática (mesmo que você possa dar outro nome a ele).
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()
Estrutura de script e exemplo
Use estes snippets de código como um guia para estruturar o script R, seguindo todas as alterações descritas neste artigo.
# 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
Criar um ambiente
Para executar o script R, você usará a extensão ml
para a CLI do Azure, também conhecida como CLI v2. O comando ml
usa um arquivo de definições de trabalho YAML. Para obter mais informações sobre como enviar trabalhos com o az ml
, confira Treinar modelos com a CLI do Azure Machine Learning.
O arquivo de trabalho YAML especifica um ambiente. Você precisará criar esse ambiente no seu workspace para executar o trabalho.
Você pode criar o ambiente no Estúdio do Azure Machine Learning ou com a CLI do Azure.
Seja qual for o método usado, você usará um Dockerfile. Todos os arquivos de contexto do Docker para ambientes do R precisam ter a seguinte especificação para funcionarem no 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/')"
A imagem base é rocker/tidyverse:latest
, que tem vários pacotes R e as respectivas dependências já instaladas.
Importante
Você precisa instalar todos os pacotes do R que o script precisará executar com antecedência. Adicione mais linhas ao arquivo de contexto do Docker conforme necessário.
RUN R -e "install.packages('<package-to-install>', dependencies = TRUE, repos = 'https://cloud.r-project.org/')"
Outras sugestões
Algumas outras sugestões que talvez você queira considerar:
- Usar a função
tryCatch
do R para tratamento de exceção e erro - Adicionar um log explícito para solução de problemas e depuração