Wdrażanie modeli językowych w punktach końcowych wsadowych

DOTYCZY: Rozszerzenie interfejsu wiersza polecenia platformy Azure w wersji 2 (current)Zestaw PYTHON SDK azure-ai-ml v2 (bieżąca)

Punkty końcowe usługi Batch mogą służyć do wdrażania kosztownych modeli, takich jak modele językowe, za pośrednictwem danych tekstowych. Z tego samouczka dowiesz się, jak wdrożyć model, który może wykonywać podsumowania tekstu długie sekwencje tekstu przy użyciu modelu z aplikacji HuggingFace. Pokazano również, jak przeprowadzić optymalizację wnioskowania przy użyciu bibliotek HuggingFace i accelerate HuggingFaceoptimum.

Informacje o tym przykładzie

Model, z który będziemy pracować, został utworzony przy użyciu popularnych transformatorów biblioteki z HuggingFace wraz ze wstępnie wytrenowanym modelem z Facebooka z architekturą BART. Został on wprowadzony w artykule BART: Denoising Sequence-to-Sequence Pre-training for Natural Language Generation (Denoising Sequence-to-Sequence Pre-training for Natural Language Generation). Ten model ma następujące ograniczenia, które są ważne, aby pamiętać o wdrożeniu:

  • Może działać z sekwencjami do 1024 tokenów.
  • Jest on szkolony do podsumowywania tekstu w języku angielskim.
  • Będziemy używać Torch jako zaplecza.

Przykład w tym artykule jest oparty na przykładach kodu zawartych w repozytorium azureml-examples . Aby uruchomić polecenia lokalnie bez konieczności kopiowania/wklejania kodu YAML i innych plików, najpierw sklonuj repozytorium, a następnie zmień katalogi na folder:

git clone https://github.com/Azure/azureml-examples --depth 1
cd azureml-examples/cli

Pliki dla tego przykładu znajdują się w następujących elementach:

cd endpoints/batch/deploy-models/huggingface-text-summarization

Postępuj zgodnie z instrukcjami w notesach Jupyter Notebook

Możesz skorzystać z tego przykładu w notesie Jupyter Notebook. W sklonowanym repozytorium otwórz notes: text-summarization-batch.ipynb.

Wymagania wstępne

Przed wykonaniem kroków opisanych w tym artykule upewnij się, że masz następujące wymagania wstępne:

  • Subskrypcja platformy Azure. Jeśli nie masz subskrypcji platformy Azure, przed rozpoczęciem utwórz bezpłatne konto. Wypróbuj bezpłatną lub płatną wersję usługi Azure Machine Edukacja.

  • Obszar roboczy usługi Azure Machine Learning. Jeśli go nie masz, wykonaj kroki opisane w artykule Manage Azure Machine Edukacja workspaces (Zarządzanie obszarami roboczymi usługi Azure Machine Edukacja), aby je utworzyć.

  • Upewnij się, że masz następujące uprawnienia w obszarze roboczym:

    • Tworzenie punktów końcowych i wdrożeń wsadowych lub zarządzanie nimi: użyj roli właściciela, współautora lub niestandardowej, która zezwala na Microsoft.MachineLearningServices/workspaces/batchEndpoints/*usługę .

    • Tworzenie wdrożeń usługi ARM w grupie zasobów obszaru roboczego: użyj roli Właściciel, Współautor lub Niestandardowy, która umożliwia Microsoft.Resources/deployments/write korzystanie z grupy zasobów, w której wdrożono obszar roboczy.

  • Aby pracować z usługą Azure Machine Edukacja, należy zainstalować następujące oprogramowanie:

    Interfejs wiersza polecenia platformy mlAzure i rozszerzenie usługi Azure Machine Edukacja.

    az extension add -n ml
    

    Uwaga

    Wdrożenia składników potoku dla punktów końcowych usługi Batch zostały wprowadzone w wersji 2.7 rozszerzenia dla interfejsu ml wiersza polecenia platformy Azure. Użyj az extension update --name ml polecenia , aby pobrać ostatnią wersję.

Nawiązywanie połączenia z obszarem roboczym

Obszar roboczy jest zasobem najwyższego poziomu dla usługi Azure Machine Learning, który udostępnia scentralizowane miejsce do pracy z wszystkimi tworzonymi podczas korzystania usługi Azure Machine Learning artefaktami. W tej sekcji połączymy się z obszarem roboczym, w którym wykonasz zadania wdrażania.

Przekaż wartości identyfikatora subskrypcji, obszaru roboczego, lokalizacji i grupy zasobów w następującym kodzie:

az account set --subscription <subscription>
az configure --defaults workspace=<workspace> group=<resource-group> location=<location>

Rejestrowanie modelu

Ze względu na rozmiar modelu nie został on uwzględniony w tym repozytorium. Zamiast tego możesz pobrać kopię z centrum modelu HuggingFace. Potrzebne są pakiety transformers i torch zainstalowane w używanym środowisku.

%pip install transformers torch

Użyj następującego kodu, aby pobrać model do folderu model:

from transformers import pipeline

model = pipeline("summarization", model="facebook/bart-large-cnn")
model_local_path = 'model'
summarizer.save_pretrained(model_local_path)

Teraz możemy zarejestrować ten model w rejestrze usługi Azure Machine Edukacja:

MODEL_NAME='bart-text-summarization'
az ml model create --name $MODEL_NAME --path "model"

Tworzenie punktu końcowego

Utworzymy punkt końcowy partii o nazwie text-summarization-batch gdzie wdrożyć model HuggingFace w celu uruchomienia podsumowania tekstu w plikach tekstowych w języku angielskim.

  1. Zdecyduj o nazwie punktu końcowego. Nazwa punktu końcowego kończy się identyfikatorem URI skojarzonym z punktem końcowym. W związku z tym nazwy punktów końcowych partii muszą być unikatowe w regionie świadczenia usługi Azure. Na przykład może istnieć tylko jeden punkt końcowy wsadowy o nazwie mybatchendpoint w pliku westus2.

    W takim przypadku umieśćmy nazwę punktu końcowego w zmiennej, abyśmy mogli ją łatwo odwołać później.

    ENDPOINT_NAME="text-summarization-batch"
    
  2. Konfigurowanie punktu końcowego wsadowego

    Następujący plik YAML definiuje punkt końcowy partii:

    endpoint.yml

    $schema: https://azuremlschemas.azureedge.net/latest/batchEndpoint.schema.json
    name: text-summarization-batch
    description: A batch endpoint for summarizing text using a HuggingFace transformer model.
    auth_mode: aad_token
    
  3. Utwórz punkt końcowy:

    az ml batch-endpoint create --file endpoint.yml  --name $ENDPOINT_NAME
    

Tworzenie wdrożenia

Utwórzmy wdrożenie hostujące model:

  1. Musimy utworzyć skrypt oceniania, który może odczytywać pliki CSV dostarczone przez wdrożenie wsadowe i zwracać wyniki modelu z podsumowaniem. Poniższy skrypt wykonuje następujące akcje:

    • Wskazuje funkcję, która wykrywa konfigurację init sprzętu (procesor CPU i procesor GPU) i odpowiednio ładuje model. Zarówno model, jak i tokenizer są ładowane w zmiennych globalnych. Nie używamy pipeline obiektu z funkcji HuggingFace, aby uwzględnić ograniczenie w sekwencji aktualnie używanego modelu.
    • Zwróć uwagę, że przeprowadzamy optymalizacje modelu w celu zwiększenia wydajności przy użyciu optimum bibliotek i accelerate . Jeśli model lub sprzęt nie obsługuje go, uruchomimy wdrożenie bez takich optymalizacji.
    • run Wskazuje funkcję, która jest wykonywana dla każdej mini-partii zapewnia wdrożenie wsadowe.
    • Funkcja run odczytuje całą partię datasets przy użyciu biblioteki. Tekst, który musimy podsumować, znajduje się w kolumnie text.
    • Metoda run iteruje poszczególne wiersze tekstu i uruchamia przewidywanie. Ponieważ jest to bardzo kosztowny model, uruchomienie przewidywania dla całych plików spowoduje wyjątek braku pamięci. Zwróć uwagę, że model nie jest wykonywany z obiektem pipeline .transformers Jest to wykonywane w celu uwzględnienia długich sekwencji tekstu i ograniczenia 1024 tokenów w używanym modelu bazowym.
    • Zwraca podsumowanie podanego tekstu.

    kod/batch_driver.py

    import os
    import time
    import torch
    import subprocess
    import mlflow
    from pprint import pprint
    from transformers import AutoTokenizer, BartForConditionalGeneration
    from optimum.bettertransformer import BetterTransformer
    from datasets import load_dataset
    
    
    def init():
        global model
        global tokenizer
        global device
    
        cuda_available = torch.cuda.is_available()
        device = "cuda" if cuda_available else "cpu"
    
        if cuda_available:
            print(f"[INFO] CUDA version: {torch.version.cuda}")
            print(f"[INFO] ID of current CUDA device: {torch.cuda.current_device()}")
            print("[INFO] nvidia-smi output:")
            pprint(
                subprocess.run(["nvidia-smi"], stdout=subprocess.PIPE).stdout.decode(
                    "utf-8"
                )
            )
        else:
            print(
                "[WARN] CUDA acceleration is not available. This model takes hours to run on medium size data."
            )
    
        # AZUREML_MODEL_DIR is an environment variable created during deployment
        model_path = os.path.join(os.environ["AZUREML_MODEL_DIR"], "model")
    
        # load the tokenizer
        tokenizer = AutoTokenizer.from_pretrained(
            model_path, truncation=True, max_length=1024
        )
    
        # Load the model
        try:
            model = BartForConditionalGeneration.from_pretrained(
                model_path, device_map="auto"
            )
        except Exception as e:
            print(
                f"[ERROR] Error happened when loading the model on GPU or the default device. Error: {e}"
            )
            print("[INFO] Trying on CPU.")
            model = BartForConditionalGeneration.from_pretrained(model_path)
            device = "cpu"
    
        # Optimize the model
        if device != "cpu":
            try:
                model = BetterTransformer.transform(model, keep_original_model=False)
                print("[INFO] BetterTransformer loaded.")
            except Exception as e:
                print(
                    f"[ERROR] Error when converting to BetterTransformer. An unoptimized version of the model will be used.\n\t> {e}"
                )
    
        mlflow.log_param("device", device)
        mlflow.log_param("model", type(model).__name__)
    
    
    def run(mini_batch):
        resultList = []
    
        print(f"[INFO] Reading new mini-batch of {len(mini_batch)} file(s).")
        ds = load_dataset("csv", data_files={"score": mini_batch})
    
        start_time = time.perf_counter()
        for idx, text in enumerate(ds["score"]["text"]):
            # perform inference
            inputs = tokenizer.batch_encode_plus(
                [text], truncation=True, padding=True, max_length=1024, return_tensors="pt"
            )
            input_ids = inputs["input_ids"].to(device)
            summary_ids = model.generate(
                input_ids, max_length=130, min_length=30, do_sample=False
            )
            summaries = tokenizer.batch_decode(
                summary_ids, skip_special_tokens=True, clean_up_tokenization_spaces=False
            )
    
            # Get results:
            resultList.append(summaries[0])
            rps = idx / (time.perf_counter() - start_time + 00000.1)
            print("Rows per second:", rps)
    
        mlflow.log_metric("rows_per_second", rps)
        return resultList
    

    Napiwek

    Mimo że pliki są udostępniane w minisadach przez wdrożenie, ten skrypt oceniania przetwarza jeden wiersz naraz. Jest to typowy wzorzec podczas pracy z kosztownymi modelami (takimi jak transformatory), gdy próbuje załadować całą partię i wysłać ją naraz do modelu, może spowodować wysokie wykorzystanie pamięci na funkcji wykonawczej partii (exeptions OOM).

  2. Musimy wskazać, w którym środowisku będziemy uruchamiać wdrożenie. W naszym przypadku nasz model jest uruchamiany i Torch wymaga bibliotek transformers, acceleratei optimum z narzędzia HuggingFace. Usługa Azure Machine Edukacja ma już środowisko z obsługą platformy Torch i procesora GPU. Dodamy tylko kilka zależności w conda.yaml pliku.

    environment/torch200-conda.yaml

    name: huggingface-env
    channels:
      - conda-forge
    dependencies:
      - python=3.8.5
      - pip
      - pip:
        - torch==2.0
        - transformers
        - accelerate
        - optimum
        - datasets
        - mlflow
        - azureml-mlflow
        - azureml-core
        - azureml-dataset-runtime[fuse]
    
  3. Możemy użyć wymienionego wcześniej pliku conda w następujący sposób:

    Definicja środowiska jest zawarta w pliku wdrożenia.

    deployment.yml

    compute: azureml:gpu-cluster
    environment:
      name: torch200-transformers-gpu
      image: mcr.microsoft.com/azureml/openmpi4.1.0-cuda11.8-cudnn8-ubuntu22.04:latest
    

    Ważne

    Utworzone środowisko torch200-transformers-gpu wymaga zgodnego urządzenia sprzętowego CUDA 11.8 do uruchamiania platformy Torch 2.0 i Ubuntu 20.04. Jeśli urządzenie z procesorem GPU nie obsługuje tej wersji cuda, możesz sprawdzić alternatywne torch113-conda.yaml środowisko Conda (dostępne również w repozytorium), które uruchamia torch 1.3 w systemie Ubuntu 18.04 z cudA 10.1. Jednak przyspieszenie przy użyciu optimum bibliotek i accelerate nie będzie obsługiwane w tej konfiguracji.

  4. Każde wdrożenie jest uruchamiane w klastrach obliczeniowych. Obsługują one zarówno klastry usługi Azure Machine Edukacja Compute (AmlCompute) czy Kubernetes. W tym przykładzie nasz model może korzystać z przyspieszania procesora GPU, dlatego używamy klastra gpu.

    az ml compute create -n gpu-cluster --type amlcompute --size STANDARD_NV6 --min-instances 0 --max-instances 2
    

    Uwaga

    W tym momencie nie są naliczane opłaty za zasoby obliczeniowe, ponieważ klaster pozostaje w 0 węzłach do momentu wywołania punktu końcowego wsadowego i przesłania zadania oceniania wsadowego. Dowiedz się więcej na temat zarządzania kosztami i optymalizowania pod kątem usługi AmlCompute.

  5. Teraz utwórzmy wdrożenie.

    Aby utworzyć nowe wdrożenie w ramach utworzonego punktu końcowego, utwórz konfigurację podobną YAML do poniższej. Możesz sprawdzić pełny schemat YAML punktu końcowego wsadowego pod kątem dodatkowych właściwości.

    deployment.yml

    $schema: https://azuremlschemas.azureedge.net/latest/modelBatchDeployment.schema.json
    endpoint_name: text-summarization-batch
    name: text-summarization-optimum
    description: A text summarization deployment implemented with HuggingFace and BART architecture with GPU optimization using Optimum.
    type: model
    model: azureml:bart-text-summarization@latest
    compute: azureml:gpu-cluster
    environment:
      name: torch200-transformers-gpu
      image: mcr.microsoft.com/azureml/openmpi4.1.0-cuda11.8-cudnn8-ubuntu22.04:latest
      conda_file: environment/torch200-conda.yaml
    code_configuration:
      code: code
      scoring_script: batch_driver.py
    resources:
      instance_count: 2
    settings:
      max_concurrency_per_instance: 1
      mini_batch_size: 1
      output_action: append_row
      output_file_name: predictions.csv
      retry_settings:
        max_retries: 1
        timeout: 3000
      error_threshold: -1
      logging_level: info
    

    Następnie utwórz wdrożenie za pomocą następującego polecenia:

    az ml batch-deployment create --file deployment.yml --endpoint-name $ENDPOINT_NAME --set-default
    

    Ważne

    W tym wdrożeniu zauważysz wysoką wartość w timeout parametrze retry_settings. Przyczyną jest charakter uruchomionego modelu. Jest to bardzo kosztowny model i wnioskowanie w jednym wierszu może potrwać do 60 sekund. Parametry timeout kontrolują czas oczekiwania na zakończenie przetwarzania każdego minisadowego skryptu oceniania. Ponieważ nasz model uruchamia wiersz przewidywania według wiersza, przetwarzanie długiego pliku może zająć trochę czasu. Zwróć również uwagę, że liczba plików na partię jest ustawiona na 1 (mini_batch_size=1). Jest to ponownie związane z naturą wykonywanej pracy. Przetwarzanie jednego pliku naraz na partię jest wystarczająco kosztowne, aby go uzasadnić. Zauważysz, że jest to wzorzec przetwarzania NLP.

  6. Chociaż można wywołać określone wdrożenie wewnątrz punktu końcowego, zazwyczaj chcesz wywołać sam punkt końcowy i pozwolić punktowi końcowemu zdecydować, które wdrożenie ma być używane. Takie wdrożenie nosi nazwę "domyślnego" wdrożenia. Daje to możliwość zmiany wdrożenia domyślnego, a tym samym zmiany modelu obsługującego wdrożenie bez zmiany umowy z użytkownikiem wywołującym punkt końcowy. Aby zaktualizować wdrożenie domyślne, użyj następującej instrukcji:

    DEPLOYMENT_NAME="text-summarization-hfbart"
    az ml batch-endpoint update --name $ENDPOINT_NAME --set defaults.deployment_name=$DEPLOYMENT_NAME
    
  7. W tym momencie nasz punkt końcowy wsadowy jest gotowy do użycia.

Testowanie wdrożenia

W celu przetestowania naszego punktu końcowego użyjemy próbki zestawu danych BillSum: Corpus for Automatic Summarization of US Legislation (Podsumowanie automatyczne przepisów amerykańskich). Ten przykład znajduje się w repozytorium w folderze data. Zwróć uwagę, że format danych to CSV, a zawartość do podsumowania znajduje się w kolumnie text, zgodnie z oczekiwaniami modelu.

  1. Wywołajmy punkt końcowy:

    JOB_NAME=$(az ml batch-endpoint invoke --name $ENDPOINT_NAME --input data --input-type uri_folder --query name -o tsv)
    

    Uwaga

    jq Narzędzie może nie być zainstalowane w każdej instalacji. Możesz uzyskać instrukcje w tym linku.

    Napiwek

    Zwróć uwagę, że wskazując ścieżkę lokalną jako dane wejściowe, dane są przekazywane do usługi Azure Machine Edukacja domyślnego konta magazynu.

  2. Zadanie wsadowe jest uruchamiane natychmiast po powrocie polecenia. Stan zadania można monitorować do momentu jego zakończenia:

    az ml job show -n $JOB_NAME --web
    
  3. Po zakończeniu wdrażania możemy pobrać przewidywania:

    Aby pobrać przewidywania, użyj następującego polecenia:

    az ml job download --name $JOB_NAME --output-name score --download-path .
    

Zagadnienia dotyczące wdrażania modeli, które przetwarzają tekst

Jak wspomniano w niektórych notatkach w tym samouczku, przetwarzanie tekstu może mieć pewne osobliwości, które wymagają określonej konfiguracji dla wdrożeń wsadowych. Podczas projektowania wdrożenia wsadowego należy wziąć pod uwagę następujące kwestie:

  • Niektóre modele NLP mogą być bardzo kosztowne pod względem pamięci i czasu obliczeniowego. Jeśli tak jest, rozważ zmniejszenie liczby plików uwzględnionych w każdej minisadowej partii. W powyższym przykładzie liczba została pobrana do minimalnej, 1 pliku na partię. Chociaż może to nie być Twój przypadek, należy wziąć pod uwagę liczbę plików, które model może oceniać za każdym razem. Należy pamiętać, że relacja między rozmiarem danych wejściowych i pamięcią modelu może nie być liniowa dla modeli uczenia głębokiego.
  • Jeśli model nie może nawet obsłużyć jednego pliku naraz (na przykład w tym przykładzie), rozważ odczytanie danych wejściowych w wierszach/fragmentach. Zaimplementuj przetwarzanie wsadowe na poziomie wiersza, jeśli chcesz osiągnąć większą przepływność lub wykorzystanie sprzętu.
  • timeout Ustaw wartość wdrożenia odpowiednio na kosztowny model i ilość danych, które mają być przetwarzane. Należy pamiętać, że parametr timeout wskazuje czas oczekiwania wdrożenia wsadowego na uruchomienie skryptu oceniania dla danej partii. Jeśli w partii istnieje wiele plików lub plików z wieloma wierszami, ma to wpływ na właściwą wartość tego parametru.

Zagadnienia dotyczące modeli MLflow, które przetwarzają tekst

Te same zagadnienia, o których wspomniano powyżej, dotyczą modeli MLflow. Jednak ponieważ nie jest wymagane podanie skryptu oceniania dla wdrożenia modelu MLflow, niektóre wymienione zalecenia mogą wymagać innego podejścia.

  • Modele MLflow w punktach końcowych usługi Batch obsługują odczytywanie danych tabelarycznych jako danych wejściowych, które mogą zawierać długie sekwencje tekstu. Zobacz Obsługa typów plików, aby uzyskać szczegółowe informacje o obsługiwanych typach plików.
  • Wdrożenia wsadowe wywołuje funkcję predict modelu MLflow z zawartością całego pliku w ramce danych biblioteki Pandas. Jeśli dane wejściowe zawierają wiele wierszy, prawdopodobieństwo uruchomienia złożonego modelu (na przykład przedstawionego w tym samouczku) powoduje wyjątek braku pamięci. Jeśli tak jest, możesz rozważyć następujące kwestie:
    • Dostosuj sposób uruchamiania przewidywań modelu i implementowanie przetwarzania wsadowego. Aby dowiedzieć się, jak dostosować wnioskowanie modelu MLflow, zobacz Rejestrowanie modeli niestandardowych.
    • Utwórz skrypt oceniania i załaduj model przy użyciu polecenia mlflow.<flavor>.load_model(). Aby uzyskać szczegółowe informacje, zobacz Używanie modeli MLflow ze skryptem oceniania.