Notatka
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Dotyczy: ✔️ AKS Automatic AKS Standard ✔️
Metodyka MLOps to zestaw praktyk wdrażania, monitorowania i zarządzania modelami uczenia maszynowego w środowiskach produkcyjnych.
Najważniejsze najlepsze rozwiązania dotyczące metodyki MLOps opisane w tym artykule:
- Infrastruktura jako kod (IaC)
- Konteneryzacja
- Zarządzanie modelami i przechowywanie wersji
- Automation
- Skalowalność i zarządzanie zasobami
- Niezawodność długotrwałego zadania wsadowego
- Zabezpieczenia i zgodność
W tym artykule opisano najlepsze rozwiązania i zagadnienia, które należy wziąć pod uwagę podczas korzystania z metodyki MLOps w usłudze AKS. Aby uzyskać więcej informacji na temat metodyki MLOps, zobacz Operacje uczenia maszynowego (MLOps) dla przepływów pracy sztucznej inteligencji i uczenia maszynowego.
Wybierz tryb AKS dla MLOps
Usługa AKS obsługuje dwa tryby klastra: AKS Automatic i AKS Standard. Wybierz AKS Automatic, jeśli chcesz skorzystać z gotowej do użycia w środowisku produkcyjnym konfiguracji bazowej przy mniejszym nakładzie pracy związanej z bieżącym zarządzaniem platformą. Wybierz usługę AKS Standard, jeśli potrzebujesz dokładniejszej kontroli nad infrastrukturą klastra i konfiguracją platformy.
Praktyki MLOps opisane w tym artykule mają zastosowanie w obu trybach. Jednak odpowiedzialność za implementację różni się w zależności od trybu: usługa AKS Automatic zapewnia więcej wstępnie skonfigurowanych ustawień domyślnych, podczas gdy usługa AKS Standard zwykle wymaga bardziej wyraźnej konfiguracji platformy i własności cyklu życia.
| Area | Automatyczne usługi AKS | AKS Standard |
|---|---|---|
| Konfiguracja klastra bazowego | Wstępnie skonfigurowane pule węzłów, sieć i monitorowanie od razu gotowe do użycia | Wymaga ręcznej konfiguracji pul węzłów, interfejsu CNI i stosu możliwości obserwacji |
| Operacje puli węzłów systemowych | Automatyczna aprowizacja węzłów i skalowanie zarządzane przez usługę | Operator musi skonfigurować ustalanie rozmiaru puli węzłów, reguły skalowania i okna obsługi |
| Mechanizmy kontroli punktu odniesienia zabezpieczeń | Zasady sieciowe, standardy zabezpieczeń podów i tożsamość obciążeń domyślnie włączone | Operatorzy muszą jawnie włączyć i skonfigurować zasady sieciowe, zabezpieczenia podów oraz ustawienia tożsamości |
| Punkt odniesienia sieci | Wstępnie skonfigurowany Azure CNI Overlay z domyślnymi wzorcami ruchu wejściowego | Pełna elastyczność wybierania wtyczki CNI, konfigurowania niestandardowych kontrolerów ruchu przychodzącego i definiowania topologii sieci |
| Operacje i uaktualnienia | Automatyczne aktualizacje obrazu węzła i wersji Kubernetes | Operatorzy planują terminy aktualizacji i zarządzają strategią ich wdrażania. |
| Fokus implementacji metodyki MLOps | Weryfikowanie, zarządzanie i dostrajanie wartości domyślnych | Projektowanie i konfigurowanie kontrolek platformy |
| Pojemność i planowanie procesora GPU | Kwalifikująca się pojemność GPU może być automatycznie przydzielana na podstawie żądań zasobów obciążenia roboczego i ograniczeń planowania, z zastrzeżeniem regionalnej dostępności jednostek SKU oraz limitu przydziału w ramach subskrypcji | Operatorzy tworzą pule węzłów GPU oraz zarządzają nimi, a także etykietami, taintami, limitami autoskalera, sterownikami i konfiguracją wtyczki urządzeń |
| Szkolenie rozproszone | Domyślne planowanie w Kubernetes i automatyczna aprowizacja węzłów stanowią punkt wyjścia; operatory treningowe, harmonogramowanie grupowe i dostrajanie topologii pozostają decyzjami zależnymi od konkretnego obciążenia | Operatorzy samodzielnie instalują operatory szkoleniowe i harmonogramisty oraz projektują pule węzłów GPU, sieć, skalowanie i rozmieszczenie dla zadań rozproszonych |
Infrastruktura jako kod (IaC)
Najważniejsze wnioski: Definiowanie i wersje szablonów IaC dla każdego etapu potoku sztucznej inteligencji w celu zapewnienia spójności, efektywności kosztów i szybszych wdrożeń.
Infrastruktura IaC umożliwia spójną i powtarzalną aprowizację infrastruktury i zarządzanie nią dla różnych typów aplikacji. W zależności od sposobu wdrożenia aplikacji implementacja IaC może się zmieniać na różnych etapach potoku AI, ponieważ zapotrzebowanie na moc obliczeniową i zasoby potrzebne do wnioskowania, udostępniania, trenowania i dostrajania modeli może być różne. Definiowanie i przechowywanie wersji szablonów IaC dla zespołów deweloperów sztucznej inteligencji może pomóc zapewnić spójność i efektywność kosztów w różnych typach zadań, jednocześnie wyjaśniając wymagania sprzętowe i przyspieszając proces wdrażania.
W AKS Automatic podejście IaC może w większym stopniu koncentrować się na definicjach obciążeń, mechanizmach ochronnych zasad i spójności środowiska niż na domyślnych ustawieniach platformy. W usłudze AKS Standard usługa IaC często zawiera bardziej jawne ustawienia platformy klastra, takie jak sieć, skalowanie i opcje konfiguracji operacyjnej.
Konteneryzacja
Najważniejszy wniosek: Pakowanie wag modelu, metadanych i konfiguracji w obrazach kontenerowych zapewnia przenośność, upraszcza wersjonowanie i obniża koszty przechowywania.
Zarządzanie wagami modelu, metadanymi i konfiguracją w obrazach kontenerów zapewnia przenośność, uproszczone wersjonowanie oraz obniżenie kosztów przechowywania w dłuższej perspektywie. Dzięki konteneryzacji można wykonywać następujące czynności:
- Używaj istniejących obrazów kontenerowych, zwłaszcza w przypadku dużych modeli językowych (LLM) liczących od milionów do miliardów parametrów oraz modeli Stable Diffusion, przechowywanych w bezpiecznych rejestrach kontenerów.
- Unikaj pojedynczego punktu awarii w potoku przetwarzania, używając wielu lekkich kontenerów zawierających specyficzne zależności dla każdego zadania zamiast utrzymywać jeden duży obraz.
- Przechowuj duże zbiory danych tekstowych i obrazowych poza bazowym obrazem kontenera i odwołuj się do nich w razie potrzeby w czasie działania. Rozpocznij pracę z operatorem łańcucha narzędzi AI platformy Kubernetes (KAITO), aby wdrożyć rozwiązanie LLM w usłudze AKS.
Mechanizmy kontroli łańcucha dostaw kontenerów pozostają niezbędne w obu trybach. Nawet w przypadku wstępnie skonfigurowanych ustawień domyślnych platformy w usłudze AKS Automatyczne, pochodzenie obrazów, skanowanie i wzmacnianie środowiska uruchomieniowego są nadal podstawowymi obowiązkami uczenia maszynowego.
Wzorzec pliku Dockerfile dla obciążeń uczenia maszynowego:
Użyj jawnego tagu obrazu bazowego z obsługą CUDA do obciążeń treningowych GPU (na przykład pytorch/pytorch:2.4.1-cuda12.4-cudnn9-runtime) zamiast nieotagowanego odwołania do obrazu bazowego. Przypnij obraz przez skrót w środowisku produkcyjnym, aby zapewnić powtarzalne kompilacje i przewidywalne zachowanie CUDA/cuDNN. Utrzymuj oddzielne warianty obrazów dla CPU i GPU, aby przydzielanie zadań przez harmonogram i zależności środowiska uruchomieniowego pozostawały jawne.
Zarządzanie modelami i przechowywanie wersji
Kluczowy wniosek: Systematycznie wersjonuj modele, aby zachować spójność między środowiskami i umożliwić szybszą iterację dzięki metodom efektywnego parametrowo dostrajania.
Zarządzanie modelami i przechowywanie wersji są niezbędne do śledzenia zmian w modelach w czasie. Wersjonując modele, można wykonywać następujące czynności:
- Zachowaj spójność w kontenerach modelu, aby ułatwić wdrażanie w różnych środowiskach.
- Stosuj metody efektywnego dostrajania parametrów (PEFT), aby szybciej iterować na podzbiorze wag modelu i utrzymywać nowe wersje w lekkich kontenerach.
W AKS Automatic wstępnie skonfigurowane standardowe konfiguracje platformy mogą ułatwić zachowanie spójności środowisk. W usłudze AKS Standard zespoły często muszą zapewniać spójność w bardziej bezpośredni sposób poprzez konfigurację platformy i wdrożeń.
Automation
Najważniejsze wnioski: automatyzowanie pozyskiwania danych, monitorowanie wydajności modelu i ponowne trenowanie potoków w celu zmniejszenia błędów ręcznych i zapewnienia spójności w całym cyklu życia uczenia maszynowego.
Automatyzacja pomaga zmniejszyć błędy ręczne, zwiększyć wydajność i zapewnić spójność w całym cyklu życia uczenia maszynowego. Automatyzując zadania, można wykonywać następujące czynności:
- Zintegruj narzędzia alertowe, aby uruchamiać proces importu wektorów, gdy nowe dane napływają do aplikacji.
- Ustaw progi wydajności modelu, aby monitorować spadki wydajności i uruchamiać potoki ponownego uczenia.
W obu trybach usługi AKS oprócz wyzwalaczy jakości modelu uwzględnij automatyzację weryfikacji zasad, wykrywanie dryfu konfiguracji i zarządzanie wydaniami.
Skalowalność i zarządzanie zasobami
Najważniejszy wniosek: Optymalizuj wykorzystanie zasobów za pomocą przetwarzania rozproszonego, automatycznego skalowania i planowania odtwarzania po awarii, aby w opłacalny sposób obsługiwać zmienne wymagania potoków AI.
Skalowalność i zarządzanie zasobami mają kluczowe znaczenie dla zapewnienia, że potok sztucznej inteligencji może obsługiwać wymagania aplikacji. Optymalizując użycie zasobów, możesz:
- Integruj narzędzia, które efektywnie korzystają z przydzielonych zasobów procesora CPU, procesora GPU i pamięci za pośrednictwem rozproszonego przetwarzania i wielu poziomów równoległości, takich jak dane, model i równoległość potoków.
- Włącz skalowanie automatyczne w zasobach obliczeniowych, aby obsługiwać duże ilości żądań modelu w godzinach szczytu i skalować w dół w godzinach poza szczytem.
- Zaplanuj odzyskiwanie po awarii, postępując zgodnie z najlepszymi rozwiązaniami dotyczącymi odporności i niezawodności usługi AKS.
Usługa AKS Automatic może zmniejszyć nakład pracy związany z konfiguracją typowych wzorców skalowania i operacji, a usługa AKS Standard zapewnia głębszą kontrolę nad niestandardowymi architekturami skalowania.
Uruchamiać długotrwałe zadania wsadowe
Najważniejszy wniosek: Uruchamiaj zadanie skończone jako obiekt Job w Kubernetes Job, zapisuj postęp poza podem, obsługuj sygnały zakończenia i zakładaj, że zadanie może zostać uruchomione więcej niż raz.
Aktualizacje węzłów, ponowne uruchomienia, zdarzenia skalowania w dół, presja na zasoby, wywłaszczenie i awarie infrastruktury mogą zakłócać długotrwałe zadania wsadowe. Obiekt Kubernetes Job zastępuje zasobnik, który uległ awarii lub został usunięty, ale zastępczy zasobnik jest uruchamiany na innym węźle bez lokalnych plików poprzedniego zasobnika ani pamięci procesu. Zaprojektuj aplikację tak, aby mogła wznowić działanie z trwale zapisanego stanu i bezpiecznie ponawiać operacje.
Stosuj te praktyki w przypadku typowych zadań wsadowych intensywnie wykorzystujących procesor, pamięć lub operacje we/wy. Wskazówki dotyczące gang scheduling i kolejkowania obciążeń mają zastosowanie, gdy obciążenie rozproszone wymaga, aby wiele węzłów roboczych uruchamiało się jednocześnie, lub gdy zespoły potrzebują współdzielonych limitów przydziału zasobów. Jednowątkowe lub niezależnie zrównoleglone zadanie wsadowe zwykle nie wymaga harmonogramowania grupowego.
Konfigurowanie punktów kontrolnych, ponawiania prób i kończenia
Poniższy przykład przetwarza sekwencję elementów roboczych i rejestruje następny element na woluminie trwałym Azure Files. Przywraca punkt kontrolny po zastąpieniu poda i zapisuje postęp, gdy proces otrzyma SIGTERM:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: batch-checkpoints
spec:
accessModes:
- ReadWriteMany
storageClassName: azurefile-csi
resources:
requests:
storage: 10Gi
---
apiVersion: batch/v1
kind: Job
metadata:
name: checkpointed-batch
spec:
backoffLimit: 6
activeDeadlineSeconds: 86400
ttlSecondsAfterFinished: 86400
podFailurePolicy:
rules:
- action: Ignore
onPodConditions:
- type: DisruptionTarget
template:
metadata:
labels:
app: checkpointed-batch
spec:
restartPolicy: Never
terminationGracePeriodSeconds: 120
containers:
- name: worker
image: ubuntu:24.04
command:
- /bin/bash
- -c
- |
set -euo pipefail
CHECKPOINT=/checkpoints/next-item
NEXT_ITEM=1
if [[ -f "${CHECKPOINT}" ]]; then
NEXT_ITEM="$(cat "${CHECKPOINT}")"
echo "Resuming at item ${NEXT_ITEM}."
fi
save_checkpoint() {
printf '%s\n' "${NEXT_ITEM}" > "${CHECKPOINT}.tmp"
mv "${CHECKPOINT}.tmp" "${CHECKPOINT}"
echo "Saved checkpoint for item ${NEXT_ITEM}."
}
terminate() {
echo "Received a termination signal."
save_checkpoint
exit 143
}
trap terminate TERM INT
while (( NEXT_ITEM <= 1000 )); do
echo "Processing item ${NEXT_ITEM}."
sleep 10
NEXT_ITEM=$((NEXT_ITEM + 1))
save_checkpoint
done
echo "Batch completed."
resources:
requests:
cpu: "1"
memory: 1Gi
limits:
cpu: "1"
memory: 1Gi
volumeMounts:
- name: checkpoints
mountPath: /checkpoints
volumes:
- name: checkpoints
persistentVolumeClaim:
claimName: batch-checkpoints
Zastąp przykładową pętlę swoją aplikacją wsadową i wybierz pamięć masową spełniającą wymagania dotyczące przepustowości i odzyskiwania danych. Użyj tożsamości obciążenia roboczego zamiast osadzonych poświadczeń, gdy aplikacja zapisuje punkty kontrolne bezpośrednio w usłudze Azure Blob Storage lub innej usłudze platformy Azure.
Zastosuj te mechanizmy kontroli niezawodności celowo:
-
Punkty kontrolne i idempotentność: Zapisuj postęp w odstępach zgodnych z docelowym punktem odtwarzania (RPO). Przechowuj punkty kontrolne i zatwierdzone dane wyjściowe w trwałej pamięci masowej, a nie w systemie plików kontenera,
emptyDir, ani w lokalnej pamięci masowej węzła. Użyj zapisów atomowych, kluczy idempotencji, wyjścia transakcyjnego lub deduplikacji, ponieważ ten sam program Job może czasami uruchomić się więcej niż raz. -
Zachowanie ponownego uruchamiania: Zadanie dopuszcza
restartPolicy: NeverlubOnFailure. W przypadkuNeverawaria kontenera powoduje niepowodzenie poda, a kontroler zadania tworzy jego zastępstwo. Za pomocąOnFailurekubelet może ponownie uruchomić kontener w tym samym podzie. Użyj poleceniaNever, gdy oddzielne nieudane pody i ich dzienniki ułatwiają diagnostykę oraz zapewniają bezpieczne wznowienie niezależnie od wybranego wariantu. -
Limity ponowień: Ustaw wartość
backoffLimitna podstawie liczby przejściowych błędów, które może tolerować obciążenie robocze. UżyjpodFailurePolicy, aby natychmiast kończyć działanie w przypadku znanych kodów wyjścia, dla których nie należy ponawiać prób, lub — jak w przykładzie — zapobiec temu, by dobrowolne przerwy zużywały limit ponownych prób. Zakłócenia mogą nadal zatrzymywać zasobnik; zasady zmieniają tylko sposób, w jaki zadanie zlicza to niepowodzenie. -
Terminy: ustaw
activeDeadlineSeconds, kiedy zadanie musi zostać zatrzymane po maksymalnym całkowitym czasie wykonywania. Termin obejmuje ponawianie prób i ma pierwszeństwo przedbackoffLimit. Nie ustawiaj limitu czasu krótszego niż przewidywany czas działania plus czas ponawiania prób i odzyskiwania. Zadanie, które zakończyło się niepowodzeniem, nie jest automatycznie uruchamiane ponownie jako nowe zadanie. -
Łagodne zakończenie: obsłuż
SIGTERMw aplikacji i ustawterminationGracePeriodSecondsna wystarczająco długi czas, aby przestać przyjmować nowe zadania, bezpiecznie dokończyć lub porzucić bieżącą jednostkę pracy, opróżnić bufory wyjścia i zapisać punkt kontrolny. Platforma Kubernetes wysyła,SIGKILLjeśli proces przekracza okres prolongaty, dlatego okresowe punkty kontrolne pozostają niezbędne. -
Czyszczenie: ustaw
ttlSecondsAfterFinishedlub skonfiguruj limity historii zadań CronJob, aby zapobiec gromadzeniu się ukończonych zadań i podów. Zachowaj rekordy zadań wystarczająco długo na potrzeby zbierania dzienników i badania zdarzeń.
Planowanie eksmisji i konserwacji węzłów
Nie traktuj blokowania eksmisji jako podstawowej strategii odzyskiwania dla długotrwałego zadania. W przypadku zadania wsadowego z możliwością ponownego uruchomienia zwykle nie należy tworzyć obiektu PDB (PodDisruptionBudget); kontroler zadania wsadowego tworzy zastępczy zasobnik po dobrowolnym zakłóceniu. PDB chroni jedynie przed dobrowolnymi eksmisjami i nie zapewnia ochrony przed awarią węzła, eksmisją spowodowaną presją na zasoby ani wyparciem. PdB, który umożliwia zerowe zakłócenia, może również blokować opróżniania węzłów i opóźniać uaktualnienia usługi AKS.
Używaj PDB tylko wtedy, gdy równoległe zadanie wsadowe musi zachować minimalną liczbę jednocześnie działających procesów roboczych i przetestowano jego zachowanie podczas opróżniania. Podobnie, cluster-autoscaler.kubernetes.io/safe-to-evict: "false" należy używać tylko w przypadku wyjątkowych zadań, których nie można uruchomić ponownie. Adnotacja może zapobiec skalowaniu w dół i zwiększać koszty, ale nie chroni przed awarią węzła ani przed każdym zdarzeniem związanym z konserwacją.
Usługa AKS uaktualnia cordon i opróżnia stare węzły przed ich zastąpieniem. Skonfiguruj planowane okna konserwacji, aby dopasować obsługiwane operacje konserwacyjne AKS do okresów o mniejszym wpływie, ale zadbaj o możliwość ponownego uruchamiania obciążenia, ponieważ harmonogram konserwacji nie eliminuje nieplanowanych zakłóceń. W usłudze AKS Standard uruchamiaj zadania wsadowe w dedykowanej puli węzłów użytkownika, gdy wymagają osobnych rozmiarów maszyn wirtualnych, limitów skalowania, skażeń lub harmonogramu aktualizacji. Unikaj pul węzłów Spot w przypadku zadań, które nie mogą wznowić działania po preempcji. Przed konserwacją węzła sprawdź, czy ostatnie punkty kontrolne mogą być używane i czy inna kwalifikowana pula węzłów ma wystarczający limit przydziału i pojemność do uruchamiania zasobników zastępczych.
Monitorowanie postępu i odzyskiwania zadania
Podczas analizowania długotrwale działającego zadania używaj razem statusu, zdarzeń i dzienników Kubernetes:
kubectl get job checkpointed-batch --watch
kubectl describe job checkpointed-batch
kubectl get pods -l batch.kubernetes.io/job-name=checkpointed-batch
kubectl logs job/checkpointed-batch
Włącz usługę zarządzaną Azure Monitor dla rozwiązania Prometheus i usługi Container Insights, aby przechowywać dzienniki i skorelować stan zadania z ponownymi uruchomieniami zasobników, eksmisjami, czasem oczekiwania, stanem węzła i wykorzystaniem zasobów. Instrumentacja aplikacji za pomocą sygnałów postępu biznesowego, takich jak ukończone elementy, zakończone niepowodzeniem, czas ostatniego pomyślnego punktu kontrolnego, szybkość przetwarzania, liczba ponownych prób i szacowany czas ukończenia. Alert o zadaniu zakończonym niepowodzeniem, zadaniu przekraczającym oczekiwany czas trwania, braku punktu kontrolnego w wymaganym czasie celu punktu odzyskiwania (RPO), powtarzających się wymianach podów, długotrwale oczekujących podach oraz wstrzymanej przepustowości przetwarzania.
Zabezpieczenia i zgodność
Najważniejsze wnioski: zaimplementuj skanowanie CVE, dzienniki inspekcji i mechanizmy kontroli zgodności, aby chronić dane i spełniać wymagania prawne, takie jak SOC 2, HIPAA i RODO.
Zabezpieczenia i zgodność mają kluczowe znaczenie dla ochrony danych i zapewnienia, że potok sztucznej inteligencji spełnia wymagania prawne. Implementując najlepsze rozwiązania w zakresie zabezpieczeń i zgodności, można wykonywać następujące czynności:
- Zintegruj skanowanie pod kątem Common Vulnerabilities and Exposures (CVE), aby wykrywać typowe luki w zabezpieczeniach w obrazach kontenerów modeli open source.
- Użyj Microsoft Defender for Containers do obrazów kontenerów modeli przechowywanych w usłudze Azure Container Registry.
- Zachowaj dziennik inspekcji pozyskanych danych, zmian modelu i metryk, aby zachować zgodność z zasadami organizacji.
- Obsługa standardów zgodności, takich jak SOC 2 (dzięki rejestrowaniu zdarzeń audytowych i mechanizmom kontroli dostępu platformy Azure), HIPAA (za pomocą szyfrowania danych przechowywanych i przesyłanych oraz izolacji sieci) oraz GDPR (dzięki opcjom lokalizacji danych i zasadom zarządzania dostępem).
W usłudze AKS Automatyczne wstępnie skonfigurowane ustawienia zabezpieczeń zwiększają stan punktu odniesienia, ale mechanizmy kontroli zabezpieczeń na poziomie modelu, na poziomie danych i na poziomie potoku pozostają wymagane.
Planowanie obciążeń procesora GPU
Najważniejszy wniosek: udostępniaj procesory GPU za pomocą wtyczki urządzeń NVIDIA, jawnie żądaj procesorów GPU i izoluj kosztowne węzły GPU za pomocą etykiet, taintów i tolerancji.
Platforma Kubernetes planuje procesory GPU jako zasoby rozszerzone. Po zarejestrowaniu układów GPU w węźle przez wtyczkę urządzenia NVIDIA pod żąda GPU, ustawiając nvidia.com/gpu zarówno w resources.requests, jak i w resources.limits. Poniższy pod żąda jednego GPU i jest kierowany do puli węzłów oznaczonej etykietą accelerator=nvidia:
apiVersion: v1
kind: Pod
metadata:
name: gpu-training-pod
labels:
app: gpu-training
spec:
restartPolicy: Never
nodeSelector:
accelerator: nvidia
tolerations:
- key: sku
operator: Equal
value: gpu
effect: NoSchedule
containers:
- name: trainer
image: nvcr.io/nvidia/cuda:12.4.1-runtime-ubuntu22.04
command:
- /bin/bash
- -c
- |
set -e
nvidia-smi
echo "GPU is available to the training container."
resources:
requests:
cpu: "1"
memory: 2Gi
nvidia.com/gpu: 1
limits:
cpu: "1"
memory: 2Gi
nvidia.com/gpu: 1
Rozszerzone zasoby nie są nadmiernie obciążone. Kubernetes traktuje limit GPU jako żądanie GPU, gdy określono tylko limit, ale ustawienie obu pól jednoznacznie określa zamierzenie dotyczące obciążenia i ułatwia walidację zasad.
Aprowizowanie puli węzłów GPU usługi AKS
Dla usługi AKS Standard utwórz dedykowaną pulę węzłów użytkownika z obsługiwanym rozmiarem maszyny wirtualnej NVIDIA GPU VM. Poniższy przykład interfejsu Azure CLI tworzy automatycznie skalowaną pulę węzłów Standard_NC4as_T4_v3, stosuje etykietę używaną przez poprzedni pod i nakłada tainty na węzły, aby odpychać obciążenia, które nie tolerują jawnie węzłów GPU:
RESOURCE_GROUP=myResourceGroup
AKS_CLUSTER=myAKSCluster
az aks nodepool add \
--resource-group "$RESOURCE_GROUP" \
--cluster-name "$AKS_CLUSTER" \
--name gpunp \
--mode User \
--node-vm-size Standard_NC4as_T4_v3 \
--node-count 0 \
--enable-cluster-autoscaler \
--min-count 0 \
--max-count 4 \
--labels accelerator=nvidia workload=training \
--node-taints sku=gpu:NoSchedule
Przed utworzeniem puli węzłów sprawdź, czy SKU maszyny wirtualnej jest dostępne w regionie klastra oraz czy subskrypcja ma wystarczający limit przydziału w regionie i dla rodziny maszyn wirtualnych. Wybierz rozmiar serii NC na podstawie pamięci procesora GPU, liczby procesorów GPU, stosunku procesora CPU do procesora GPU, magazynu lokalnego, sieci i możliwości CUDA wymaganych przez platformę szkoleniową. Na przykład rozmiary NCas T4 v3 są odpowiednie do wielu obciążeń wykorzystujących pojedynczy procesor GPU oraz do mniejszych zadań treningowych, podczas gdy rozmiary NC A100 v4 obsługują większe modele i konfiguracje GPU z wieloma instancjami.
Usługa AKS Automatic może aprowizować kwalifikowaną pojemność procesora GPU w odpowiedzi na oczekujące zasobniki. Obciążenie nadal musi żądać nvidia.com/gpu, a wszelkie selektory węzłów, afinity, tolerancje, ograniczenia topologii, limity subskrypcji oraz dostępność regionalnych jednostek SKU muszą być możliwe do spełnienia. Użyj AKS Standard, jeśli potrzebujesz stałego typu maszyny wirtualnej (SKU), niestandardowego cyklu życia puli węzłów lub precyzyjnej kontroli nad skalowaniem i topologią puli GPU.
Weryfikowanie lub instalowanie wtyczki urządzenia NVIDIA
Konfiguracje GPU w usłudze AKS mogą zapewniać zarządzane sterowniki GPU oraz integrację z wtyczką urządzenia. Przed zainstalowaniem innej wtyczki sprawdź obowiązującą konfigurację:
kubectl get nodes -L accelerator,kubernetes.azure.com/agentpool
kubectl get daemonsets --all-namespaces | grep -i nvidia
kubectl describe node | grep -A5 -E "Capacity:|Allocatable:|nvidia.com/gpu"
Nie uruchamiaj wielu obiektów DaemonSet wtyczki urządzeń NVIDIA na tych samych węzłach. Jeśli konfiguracja AKS nie zarządza tą wtyczką, poniższy samodzielny obiekt DaemonSet rejestruje procesory graficzne NVIDIA w kubelecie. Zainstaluj wersję wtyczki urządzenia obsługiwaną przez sterownik NVIDIA i wersje platformy Kubernetes:
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: nvidia-device-plugin
namespace: kube-system
labels:
app.kubernetes.io/name: nvidia-device-plugin
spec:
selector:
matchLabels:
app.kubernetes.io/name: nvidia-device-plugin
updateStrategy:
type: RollingUpdate
template:
metadata:
labels:
app.kubernetes.io/name: nvidia-device-plugin
spec:
priorityClassName: system-node-critical
nodeSelector:
accelerator: nvidia
tolerations:
- operator: Exists
containers:
- name: nvidia-device-plugin
image: nvcr.io/nvidia/k8s-device-plugin:v0.17.1
args:
- --fail-on-init-error=false
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
volumeMounts:
- name: device-plugin
mountPath: /var/lib/kubelet/device-plugins
volumes:
- name: device-plugin
hostPath:
path: /var/lib/kubelet/device-plugins
type: Directory
Przed przesłaniem zadań szkoleniowych potwierdź, że nvidia.com/gpu widnieje w sekcji przydzielanych zasobów każdego węzła GPU.
Podziel GPU A100 i H100 za pomocą MIG
Technologia NVIDIA Multi-Instance GPU (MIG) może podzielić obsługiwany procesor graficzny A100 lub H100 na izolowane instancje GPU. MIG jest przydatny do dostrajania hiperparametrów i mniejszych zadań dostrajania modelu, które nie wymagają całego fizycznego układu GPU. Używaj pełnych procesorów GPU dla obciążeń, które wymagają całej pamięci procesora GPU, maksymalnej przepustowości połączenia międzyoperacyjnego lub profilu, który nie jest obsługiwany przez zainstalowany procesor GPU.
Użyj operatora NVIDIA GPU i menedżera MIG, jeśli potrzebujesz deklaratywnego zarządzania cyklem życia MIG. Operator powinien zarządzać wtyczką urządzenia i konfiguracją MIG dla węzłów, których to dotyczy; nie należy łączyć go z drugą niezależną wtyczką urządzenia. Dokładne nazwy profilów i liczba wystąpień zależą od modelu procesora GPU i pojemności pamięci. Poniższa konfiguracja tworzy siedem 1g.10gb wystąpień w obsługiwanych konfiguracjach 80 GB A100 lub H100:
apiVersion: v1
kind: Namespace
metadata:
name: gpu-operator
---
apiVersion: v1
kind: ConfigMap
metadata:
name: mig-parted-config
namespace: gpu-operator
data:
config.yaml: |
version: v1
mig-configs:
all-disabled:
- devices: all
mig-enabled: false
hptuning-1g10gb:
- devices: all
mig-enabled: true
mig-devices:
"1g.10gb": 7
---
apiVersion: v1
kind: Namespace
metadata:
name: ml-training
---
apiVersion: batch/v1
kind: Job
metadata:
name: mig-hyperparameter-trial
namespace: ml-training
labels:
workload: hyperparameter-tuning
spec:
backoffLimit: 2
template:
metadata:
labels:
workload: hyperparameter-tuning
spec:
restartPolicy: Never
nodeSelector:
accelerator: nvidia
nvidia.com/mig.config: hptuning-1g10gb
nvidia.com/mig.config.state: success
tolerations:
- key: sku
operator: Equal
value: gpu
effect: NoSchedule
containers:
- name: trial
image: nvcr.io/nvidia/cuda:12.4.1-runtime-ubuntu22.04
command:
- /bin/bash
- -c
- |
set -e
nvidia-smi
echo "Starting one hyperparameter trial on a MIG instance."
sleep 30
resources:
requests:
cpu: "2"
memory: 8Gi
nvidia.com/mig-1g.10gb: 1
limits:
cpu: "2"
memory: 8Gi
nvidia.com/mig-1g.10gb: 1
Skonfiguruj MIG Manager operatora GPU, aby korzystał z obiektu ConfigMap mig-parted-config, używał strategii MIG mixed, gdy obciążenia żądają nazwanych profili MIG, a następnie oznacz węzły docelowe:
kubectl label nodes \
-l accelerator=nvidia \
nvidia.com/mig.config=hptuning-1g10gb \
--overwrite
Zmiana konfiguracji MIG zakłóca zadania, które już korzystają z GPU. Oznacz węzeł docelowy jako niedostępny do planowania i opróżnij go, zastosuj konfigurację podczas okna konserwacyjnego i upewnij się, że żądany profil istnieje w zasobach alokowalnych węzła przed przesłaniem zadań.
Izolowanie obciążeń procesora GPU za pomocą defektów i tolerancji
Skażenie NoSchedule powstrzymuje zwykłe pody aplikacyjne przed trafianiem na drogie węzły GPU. Przykład tworzenia puli węzłów dotyczy sku=gpu:NoSchedule. Następujące kompletne zadanie obejmuje pasującą tolerancję i selektor węzła:
apiVersion: batch/v1
kind: Job
metadata:
name: isolated-gpu-training
spec:
backoffLimit: 3
template:
metadata:
labels:
app: isolated-gpu-training
spec:
restartPolicy: Never
nodeSelector:
accelerator: nvidia
workload: training
tolerations:
- key: sku
operator: Equal
value: gpu
effect: NoSchedule
containers:
- name: trainer
image: nvcr.io/nvidia/cuda:12.4.1-runtime-ubuntu22.04
command:
- /bin/bash
- -c
- |
set -e
nvidia-smi
sleep 60
resources:
requests:
cpu: "4"
memory: 16Gi
nvidia.com/gpu: 1
limits:
cpu: "4"
memory: 16Gi
nvidia.com/gpu: 1
Toleracja umożliwia zaplanowanie, ale nie wymusza umieszczenia poda na węźle z GPU. Połącz tolerancje z żądaniem zasobu GPU oraz selektorem węzłów lub koligacją węzłów. Upewnij się, że wymagane platformowe obiekty DaemonSet, takie jak te odpowiedzialne za sieć, monitorowanie, pamięć masową i wtyczkę urządzeń, tolerują skażenie GPU.
Uruchom rozproszone obciążenia treningowe
Najważniejszy wniosek: użyj operatora trenowania do zarządzania tożsamościami węzłów roboczych i cyklem życia zadań, weryfikowania komunikacji sieciowej między wieloma węzłami oraz mechanizmu jednoczesnego dopuszczania zadań, gdy wszystkie węzły robocze muszą zostać uruchomione jednocześnie.
Trenowanie rozproszone wykorzystuje wiele procesów do podziału danych, stanu modelu lub etapów potoku przetwarzania. Na platformie Kubernetes operator może tworzyć zasobniki robocze, wprowadzać konfigurację odwzorowania, śledzić stan repliki, ponownie uruchamiać procesy robocze, które zakończyły się niepowodzeniem, i czyścić zadanie. Instaluj operatory szkoleniowe i zarządzaj ich wersjami za pomocą mechanizmów IaC oraz procesu wydawniczego platformy, zamiast pozwalać poszczególnym zespołom instalować niezarządzane obiekty CRD obejmujące cały klaster.
Tworzenie przenośnego obrazu szkoleniowego CUDA
Poniższy plik Dockerfile stanowi rozwinięcie wzorca Dockerfile opisanego w sekcji „Konteneryzacja”. Obraz zawiera środowisko uruchomieniowe CUDA oraz biblioteki PyTorch, natomiast zgodny sterownik NVIDIA pozostaje na węźle GPU usługi AKS:
FROM pytorch/pytorch:2.4.1-cuda12.4-cudnn9-runtime
WORKDIR /workspace
COPY requirements.txt .
RUN python -m pip install --no-cache-dir -r requirements.txt
COPY train.py .
ENTRYPOINT ["python", "/workspace/train.py"]
Przypnij obraz bazowy w środowisku produkcyjnym za pomocą niezmiennego identyfikatora digest. Zachowaj zestawy danych i często zmieniaj punkty kontrolne poza obrazem, a następnie skanuj obraz wynikowy przed wypchnięciem go do Azure Container Registry.
Uruchamianie zadania PyTorchJob
Operator Kubeflow do trenowania udostępnia element CRD PyTorchJob. Przed zastosowaniem tego manifestu zainstaluj wersję operatora trenowania zgodną z wersją platformy Kubernetes. Poniższy przykład z dwiema replikami wykonuje operację all-reduce NCCL między jednym węzłem głównym a jednym węzłem roboczym:
apiVersion: v1
kind: Namespace
metadata:
name: ml-training
labels:
purpose: ml-training
---
apiVersion: kubeflow.org/v1
kind: PyTorchJob
metadata:
name: pytorch-nccl-example
namespace: ml-training
spec:
runPolicy:
cleanPodPolicy: None
pytorchReplicaSpecs:
Master:
replicas: 1
restartPolicy: OnFailure
template:
metadata:
labels:
training-job: pytorch-nccl-example
spec:
nodeSelector:
accelerator: nvidia
tolerations:
- key: sku
operator: Equal
value: gpu
effect: NoSchedule
containers:
- name: pytorch
image: pytorch/pytorch:2.4.1-cuda12.4-cudnn9-runtime
command:
- python
- -c
- |
import os
import torch
import torch.distributed as dist
torch.cuda.set_device(0)
dist.init_process_group(backend="nccl")
value = torch.tensor(
[float(dist.get_rank() + 1)],
device="cuda"
)
dist.all_reduce(value)
print(
f"rank={dist.get_rank()} "
f"world_size={dist.get_world_size()} "
f"all_reduce_sum={value.item()}"
)
dist.destroy_process_group()
env:
- name: NCCL_DEBUG
value: INFO
- name: NCCL_SOCKET_IFNAME
value: eth0
- name: NCCL_IB_DISABLE
value: "1"
- name: TORCH_NCCL_ASYNC_ERROR_HANDLING
value: "1"
resources:
requests:
cpu: "4"
memory: 16Gi
nvidia.com/gpu: 1
limits:
cpu: "4"
memory: 16Gi
nvidia.com/gpu: 1
Worker:
replicas: 1
restartPolicy: OnFailure
template:
metadata:
labels:
training-job: pytorch-nccl-example
spec:
nodeSelector:
accelerator: nvidia
tolerations:
- key: sku
operator: Equal
value: gpu
effect: NoSchedule
containers:
- name: pytorch
image: pytorch/pytorch:2.4.1-cuda12.4-cudnn9-runtime
command:
- python
- -c
- |
import os
import torch
import torch.distributed as dist
torch.cuda.set_device(0)
dist.init_process_group(backend="nccl")
value = torch.tensor(
[float(dist.get_rank() + 1)],
device="cuda"
)
dist.all_reduce(value)
print(
f"rank={dist.get_rank()} "
f"world_size={dist.get_world_size()} "
f"all_reduce_sum={value.item()}"
)
dist.destroy_process_group()
env:
- name: NCCL_DEBUG
value: INFO
- name: NCCL_SOCKET_IFNAME
value: eth0
- name: NCCL_IB_DISABLE
value: "1"
- name: TORCH_NCCL_ASYNC_ERROR_HANDLING
value: "1"
resources:
requests:
cpu: "4"
memory: 16Gi
nvidia.com/gpu: 1
limits:
cpu: "4"
memory: 16Gi
nvidia.com/gpu: 1
Na potrzeby treningu produkcyjnego zastąp test wbudowany bezpośrednio w kod swoim wersjonowanym obrazem treningowym i skryptem. Dostosuj liczbę replik do liczby GPU i procesów wymaganych przez framework treningowy.
Uruchom zadanie TFJob
Operator trenowania udostępnia również TFJob CRD. Poniższy przykład uruchamia synchroniczne trenowanie TensorFlow na dwóch procesach roboczych GPU przy użyciu MultiWorkerMirroredStrategy:
apiVersion: v1
kind: Namespace
metadata:
name: ml-training
labels:
purpose: ml-training
---
apiVersion: kubeflow.org/v1
kind: TFJob
metadata:
name: tensorflow-multiworker-example
namespace: ml-training
spec:
runPolicy:
cleanPodPolicy: None
tfReplicaSpecs:
Worker:
replicas: 2
restartPolicy: OnFailure
template:
metadata:
labels:
training-job: tensorflow-multiworker-example
spec:
nodeSelector:
accelerator: nvidia
tolerations:
- key: sku
operator: Equal
value: gpu
effect: NoSchedule
containers:
- name: tensorflow
image: tensorflow/tensorflow:2.16.1-gpu
command:
- python
- -c
- |
import tensorflow as tf
strategy = tf.distribute.MultiWorkerMirroredStrategy()
print("workers:", strategy.num_replicas_in_sync)
with strategy.scope():
model = tf.keras.Sequential([
tf.keras.layers.Input(shape=(32,)),
tf.keras.layers.Dense(64, activation="relu"),
tf.keras.layers.Dense(1)
])
model.compile(
optimizer="adam",
loss="mean_squared_error"
)
features = tf.random.normal([4096, 32])
labels = tf.random.normal([4096, 1])
dataset = (
tf.data.Dataset.from_tensor_slices((features, labels))
.shuffle(4096)
.repeat()
.batch(64)
)
model.fit(dataset, epochs=2, steps_per_epoch=32)
resources:
requests:
cpu: "4"
memory: 16Gi
nvidia.com/gpu: 1
limits:
cpu: "4"
memory: 16Gi
nvidia.com/gpu: 1
W przypadku trenowania z użyciem serwera parametrów zdefiniuj typy replik Chief, Worker i PS zgodnie ze strategią dystrybucji TensorFlow. Przed zwiększeniem liczby replik zmierz wynikające z tego wąskie gardła sieci i serwera parametrów.
Dostrajanie modelu za pomocą interfejsu KAITO
KAITO zapewnia ukierunkowaną na AKS abstrakcję obszaru roboczego do wdrażania i dostrajania modeli. Włącz dodatek KAITO lub zainstaluj zgodną wersję KAITO przed zastosowaniem elementu Workspace. Sprawdź, czy wybrany preset, SKU maszyny wirtualnej i metoda dostrajania są obsługiwane przez zainstalowaną wersję KAITO.
Poniższy obszar roboczy wymaga maszyny wirtualnej z procesorem graficznym A100 i rozpoczyna dostrajanie QLoRA dla obsługiwanego presetu Phi-3 przy użyciu publicznie dostępnego zestawu danych:
apiVersion: kaito.sh/v1beta1
kind: Workspace
metadata:
name: workspace-tuning-phi-3-mini
resource:
instanceType: Standard_NC24ads_A100_v4
labelSelector:
matchLabels:
apps: phi-3-mini-tuning
tuning:
preset:
name: phi-3-mini-4k-instruct
method: qlora
input:
urls:
- https://huggingface.co/datasets/yahma/alpaca-cleaned/resolve/main/alpaca_data_cleaned.json
KAITO może koordynować konfigurację predefiniowanych ustawień modelu oraz infrastrukturę GPU potrzebną dla przestrzeni roboczej. W środowisku produkcyjnym zbiór danych treningowych należy przechowywać na zatwierdzonym koncie usługi Azure Storage, stosować dostęp prywatny i tożsamość obciążenia tam, gdzie są obsługiwane, oraz zapisywać uzyskany model w nadzorowanym rejestrze modeli lub w usłudze Azure Container Registry. Traktuj manifest obszaru roboczego, wersję wejściowego zestawu danych, wersję ustawienia wstępnego, konfigurację adaptera i skrót obrazu wyjściowego jako jeden wersjonowany rekord treningowy.
Konfigurowanie komunikacji NCCL przy użyciu AKS CNI
Biblioteka NVIDIA Collective Communications Library (NCCL) obsługuje operacje zbiorowe, takie jak all-reduce. Aby uzyskać przenośną linię bazową TCP w AKS CNI, użyj interfejsu sieciowego poda, zwykle eth0, i zacznij od NCCL_IB_DISABLE=1. W przypadku obsługiwanych rozmiarów maszyn wirtualnych z obsługą RDMA użyj udokumentowanej konfiguracji RDMA dla platform NVIDIA i Azure i zweryfikuj jej poprawność przed ustawieniem NCCL_IB_DISABLE=0.
Użyj następujących zmiennych środowiskowych punktu odniesienia:
-
NCCL_SOCKET_IFNAME=eth0wybiera interfejs sieciowy poda. -
NCCL_DEBUG=INFOzapewnia diagnostykę podczas walidacji. Zmniejsz poziom rejestrowania po zakończeniu dostrajania. -
NCCL_IB_DISABLE=1wybiera gniazda TCP, gdy funkcja RDMA nie jest skonfigurowana. -
TORCH_NCCL_ASYNC_ERROR_HANDLING=1pomaga PyTorch zakończyć działanie zamiast zawieszać się bez końca po asynchronicznych błędach komunikacji.
Jeśli włączono zasady sieciowe, zezwól na cały wymagany ruch rendezvous i NCCL między replikami. NCCL może negocjować dynamicznie przydzielane porty, więc rygorystyczna polityka stałych portów może powodować zawieszanie się zadań treningowych. Następujące zasady zezwalają na nieograniczoną komunikację między zasobnikami tylko między replikami zadania PyTorch i umożliwiają rozpoznawanie nazw DNS:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-pytorch-nccl
namespace: ml-training
spec:
podSelector:
matchLabels:
training-job: pytorch-nccl-example
policyTypes:
- Ingress
- Egress
ingress:
- from:
- podSelector:
matchLabels:
training-job: pytorch-nccl-example
egress:
- to:
- podSelector:
matchLabels:
training-job: pytorch-nccl-example
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
podSelector:
matchLabels:
k8s-app: kube-dns
ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53
Przetestuj wydajność NCCL niezależnie od treningu modelu przed skalowaniem poziomym. Porównaj przepustowość operacji all-reduce, opóźnienia, wykorzystanie GPU oraz przepustowość treningu dla każdej liczby węzłów roboczych. Więcej procesów roboczych może obniżyć wydajność, gdy komunikacja lub ładowanie danych stają się wąskim gardłem.
Używaj planowania grupowego i kolejek obciążeń
Najważniejszy wniosek: Dopuszczaj rozproszone procesy robocze jako grupę i egzekwuj limity przydziału GPU dla dzierżawców, aby częściowo zaplanowane zadania nie rezerwowały procesorów GPU podczas oczekiwania na pozostałe procesy robocze.
Domyślny harmonogramista Kubernetes przydziela pody indywidualnie. W przypadku zadania rozproszonego, które nie może robić postępów, dopóki wszystkie procesy robocze nie zostaną uruchomione, częściowe przydzielenie może prowadzić do marnowania zasobów GPU. Kueue zapewnia kontrolę dopuszczenia i zarządzanie przydziałami, zanim pody zaczną działać. Volcano udostępnia planistę oraz oparty na PodGroup model planowania „wszystko albo nic”.
Usługa AKS Automatic udostępnia domyślny mechanizm planowania Kubernetes oraz automatyczne aprowizowanie węzłów na początek. Prześlij zwykłe zadania Job lub zadania treningowe zarządzane przez operatora z precyzyjnie określonym zapotrzebowaniem na zasoby i pozwól platformie przydzielić odpowiednie zasoby. To zachowanie nie gwarantuje atomowego dopuszczenia dla każdego workera. Zainstaluj Kueue lub Volcano, jeśli dane obciążenie robocze wymaga grupowego planowania zadań, kolejkowania, limitów zasobów dla zespołów, sprawiedliwego podziału zasobów lub niestandardowych mechanizmów wywłaszczania.
Przydzielanie wielodzierżawnego limitu GPU za pomocą Kueue
Zainstaluj wersję kueue zgodną z wersją rozwiązania Kubernetes i włącz integrację dla używanych typów obciążeń. Poniższy manifest tworzy:
- GPU
ResourceFlavorpowiązany z węzłami oznaczonymi etykietąaccelerator=nvidia. - Zestaw z czterema GPU
ClusterQueuedla zespołu A. - Konfiguracja z dwoma procesorami GPU
ClusterQueuedla zespołu B. - Zakres przestrzeni nazw
LocalQueuedla każdego zespołu. - Zadanie z dwoma procesami roboczymi, które Kueue dopuszcza tylko wtedy, gdy żądane przez nie zasoby są dostępne.
apiVersion: v1
kind: Namespace
metadata:
name: team-a
---
apiVersion: v1
kind: Namespace
metadata:
name: team-b
---
apiVersion: kueue.x-k8s.io/v1beta1
kind: ResourceFlavor
metadata:
name: nvidia-gpu
spec:
nodeLabels:
accelerator: nvidia
---
apiVersion: kueue.x-k8s.io/v1beta1
kind: ClusterQueue
metadata:
name: team-a-gpu
spec:
namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: team-a
queueingStrategy: BestEffortFIFO
resourceGroups:
- flavors:
- name: nvidia-gpu
resources:
- name: cpu
nominalQuota: "64"
- name: memory
nominalQuota: 256Gi
- name: nvidia.com/gpu
nominalQuota: "4"
---
apiVersion: kueue.x-k8s.io/v1beta1
kind: ClusterQueue
metadata:
name: team-b-gpu
spec:
namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: team-b
queueingStrategy: BestEffortFIFO
resourceGroups:
- flavors:
- name: nvidia-gpu
resources:
- name: cpu
nominalQuota: "32"
- name: memory
nominalQuota: 128Gi
- name: nvidia.com/gpu
nominalQuota: "2"
---
apiVersion: kueue.x-k8s.io/v1beta1
kind: LocalQueue
metadata:
name: gpu-queue
namespace: team-a
spec:
clusterQueue: team-a-gpu
---
apiVersion: kueue.x-k8s.io/v1beta1
kind: LocalQueue
metadata:
name: gpu-queue
namespace: team-b
spec:
clusterQueue: team-b-gpu
---
apiVersion: batch/v1
kind: Job
metadata:
name: team-a-two-gpu-training
namespace: team-a
labels:
kueue.x-k8s.io/queue-name: gpu-queue
spec:
suspend: true
completions: 2
parallelism: 2
backoffLimit: 2
template:
metadata:
labels:
app: team-a-two-gpu-training
spec:
restartPolicy: Never
tolerations:
- key: sku
operator: Equal
value: gpu
effect: NoSchedule
containers:
- name: worker
image: nvcr.io/nvidia/cuda:12.4.1-runtime-ubuntu22.04
command:
- /bin/bash
- -c
- |
set -e
nvidia-smi
echo "Kueue admitted this worker."
sleep 120
resources:
requests:
cpu: "4"
memory: 16Gi
nvidia.com/gpu: 1
limits:
cpu: "4"
memory: 16Gi
nvidia.com/gpu: 1
Limit przydziału ClusterQueue to limit przydziału harmonogramowania, a nie limit przydziału subskrypcji platformy Azure. Upewnij się, że klaster AKS może udostępnić bazową pojemność maszyn wirtualnych oraz że limit przydziału procesorów GPU w usłudze Azure jest wystarczający dla łącznego dopuszczonego obciążenia. Korzystaj z kohort i funkcji sprawiedliwego współdzielenia w Kueue, gdy zespoły mogą pożyczać od siebie nawzajem niewykorzystany przydział.
Użyj wulkanu jako alternatywy
Wulkan jest alternatywą, jeśli chcesz dedykowany harmonogram partii z zasadami planowania, kolejek i cyklu życia zadań. Zainstaluj wersję Volcano zgodną z klastrem przed zastosowaniem jego CRD. Następujące zadanie Volcano wymaga, aby oba procesy robocze GPU były dostępne przed uruchomieniem tego zadania:
apiVersion: batch.volcano.sh/v1alpha1
kind: Job
metadata:
name: volcano-gpu-training
namespace: default
spec:
minAvailable: 2
schedulerName: volcano
policies:
- event: PodEvicted
action: RestartJob
- event: PodFailed
action: RestartJob
tasks:
- replicas: 2
name: worker
template:
metadata:
labels:
app: volcano-gpu-training
spec:
restartPolicy: OnFailure
nodeSelector:
accelerator: nvidia
tolerations:
- key: sku
operator: Equal
value: gpu
effect: NoSchedule
containers:
- name: worker
image: nvcr.io/nvidia/cuda:12.4.1-runtime-ubuntu22.04
command:
- /bin/bash
- -c
- |
set -e
nvidia-smi
echo "All Volcano workers were admitted."
sleep 120
resources:
requests:
cpu: "4"
memory: 16Gi
nvidia.com/gpu: 1
limits:
cpu: "4"
memory: 16Gi
nvidia.com/gpu: 1
Stosuj jeden podstawowy system kolejkowania i harmonogramowania grupowego, chyba że masz przetestowany projekt interoperacyjności. W przeciwnym razie wiele kontrolerów dopuszczania lub planistów może utrudniać zrozumienie zachowania związanego ze stanem oczekiwania i wywłaszczaniem.
Konfigurowanie priorytetów trenowania i wnioskowania
Wnioskowanie wrażliwe na opóźnienia zwykle wymaga wyższego priorytetu niż przerywane uczenie wsadowe. Następujące zasoby PriorityClass umożliwiają podom inferencyjnym wywłaszczanie podów o niższym priorytecie, jednocześnie uniemożliwiając podom treningu wsadowego wywłaszczanie innych obciążeń:
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
name: training-batch
value: 10000
globalDefault: false
preemptionPolicy: Never
description: Batch training can wait and can be preempted by higher-priority workloads.
---
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
name: inference-critical
value: 100000
globalDefault: false
preemptionPolicy: PreemptLowerPriority
description: Latency-sensitive production inference can preempt lower-priority workloads.
Przypisz klasę za pomocą spec.priorityClassName w szablonie poda. Priorytet zasobnika Kubernetes i priorytet obciążenia Kueue mają wpływ na różne etapy: usługa Kueue kontroluje wstęp do kolejki, a priorytet kubernetes wpływa na planowanie i wywłaszczanie zasobników po przyjęciu. Koordynuj obie zasady, aby wyrazić ten sam priorytet biznesowy.
Preempcja przerywa działanie podów o niższym priorytecie. Obciążenia treningowe, które mogą zostać przerwane, muszą zapisywać punkty kontrolne w trwałej pamięci masowej, tolerować powielanie pracy i wznawiać działanie bez polegania na plikach lokalnych na węźle.
Konfigurowanie pamięci udostępnionej i zarządzania zasobami
Najważniejszy wniosek: zastąp małe ustawienie domyślne /dev/shmśrodowiska uruchomieniowego kontenera, ustaw żądania zasobów na podstawie obserwowanego wykorzystania i skonfiguruj skalowanie węzłów zgodnie z pełnymi wymaganiami obciążeń GPU.
Zwiększ /dev/shm dla modułów ładowania danych ML
Moduły ładujące dane PyTorch, potoki wejściowe TensorFlow, NCCL oraz moduł multiprocessing w Pythonie mogą korzystać z pamięci współdzielonej POSIX. Domyślna wartość parametru /dev/shm w kontenerze jest często zbyt mała podczas trenowania wieloprocesowego, co może powodować awarie procesów roboczych, błędy magistrali lub pozorne zawieszanie się procesu trenowania.
Zamontuj oparty na pamięci emptyDir pod /dev/shm i ustaw jawny sizeLimit:
apiVersion: batch/v1
kind: Job
metadata:
name: shared-memory-training
spec:
backoffLimit: 2
template:
metadata:
labels:
app: shared-memory-training
spec:
restartPolicy: Never
nodeSelector:
accelerator: nvidia
tolerations:
- key: sku
operator: Equal
value: gpu
effect: NoSchedule
containers:
- name: trainer
image: pytorch/pytorch:2.4.1-cuda12.4-cudnn9-runtime
command:
- /bin/bash
- -c
- |
set -e
df -h /dev/shm
python -c '
import multiprocessing as mp
import torch
def worker(index):
value = torch.ones(1024, 1024)
print(f"worker={index}, sum={value.sum().item()}")
if __name__ == "__main__":
processes = [mp.Process(target=worker, args=(i,)) for i in range(4)]
for process in processes:
process.start()
for process in processes:
process.join()
if process.exitcode != 0:
raise SystemExit(process.exitcode)
'
volumeMounts:
- name: shared-memory
mountPath: /dev/shm
resources:
requests:
cpu: "8"
memory: 16Gi
nvidia.com/gpu: 1
limits:
cpu: "8"
memory: 16Gi
nvidia.com/gpu: 1
volumes:
- name: shared-memory
emptyDir:
medium: Memory
sizeLimit: 8Gi
Użycie pamięci emptyDir wlicza się do zużycia pamięci poda. Uwzględnij maksymalne oczekiwane użycie pamięci udostępnionej podczas ustawiania limitu pamięci kontenera. Jeśli /dev/shm wzrośnie ponad efektywny budżet pamięci, zasobnik może zostać usunięty lub zakończony z powodu przekroczenia limitu pamięci.
Dobierz CPU i pamięć na podstawie obserwowanego wykorzystania
Zacznij od testu porównawczego opartego na reprezentatywnym modelu, rozmiarze partii, długości sekwencji, współbieżności modułu ładującego dane, rozszerzaniu i zachowaniu punktu kontrolnego. Następnie użyj danych monitorowania, aby dostosować:
- Ustaw odpowiednio wysokie żądania zasobów CPU, aby zapewnić stały dopływ danych do potoków wejściowych GPU. Utrzymujące się okresy bezczynności GPU mogą wskazywać na niedobór zasobów procesora CPU lub pamięci masowej.
- Ustaw żądania pamięci na poziomie zbliżonym do stabilnego wykorzystania zestawu roboczego, powiększonego o margines bezpieczeństwa. Uwzględnij
/dev/shm, zachowanie pamięci podręcznej stron, narzut alokatora frameworka oraz szczytowe wartości serializacji punktów kontrolnych. - Ustaw limity pamięci powyżej obserwowanego szczytu. Zbadaj zdarzenia
OOMKilled, zamiast wielokrotnie zwiększać limity bez znalezienia przyczyny. - Oceń dławienie CPU przed użyciem ścisłych limitów CPU. Limity procesora CPU, które są zbyt niskie, mogą zmniejszyć wykorzystanie procesora GPU nawet wtedy, gdy średnie użycie procesora CPU wydaje się akceptowalne.
- Ustaw żądania i limity równe dla przewidywalnych, wysokowartościowych zadań szkoleniowych, gdy gwarantowana jakość usługi jest ważniejsza niż pakowanie węzłów.
- Profiluj każdą istotną zmianę rozmiaru modelu, precyzji, rozmiaru partii, liczby procesów roboczych i potoku przetwarzania danych.
Stosuj percentyle dla pełnych przebiegów treningowych zamiast średniej z krótkiego okresu. Fazy uruchamiania, walidacji, punktu kontrolnego i mieszania danych często mają różne szczyty zasobów.
Skonfiguruj automatyczne skalowanie klastra dla puli węzłów GPU
W przypadku usługi AKS Standard włącz narzędzie do automatycznego skalowania klastra w puli węzłów użytkownika procesora GPU i zdefiniuj minimalną i maksymalną pojemność:
RESOURCE_GROUP=myResourceGroup
AKS_CLUSTER=myAKSCluster
GPU_NODE_POOL=gpunp
az aks nodepool update \
--resource-group "$RESOURCE_GROUP" \
--cluster-name "$AKS_CLUSTER" \
--name "$GPU_NODE_POOL" \
--enable-cluster-autoscaler \
--min-count 0 \
--max-count 8
Obsługiwane ustawienia profilu automatycznego skalowania klastra można dostosować na poziomie klastra. Przetestuj zmiany profilu zarówno na potrzeby trenowania, jak i obsługi obciążeń:
az aks update \
--resource-group "$RESOURCE_GROUP" \
--name "$AKS_CLUSTER" \
--cluster-autoscaler-profile \
scan-interval=20s \
scale-down-unneeded-time=10m \
scale-down-delay-after-add=15m \
max-graceful-termination-sec=120
Oczekujący pod GPU powoduje zwiększenie skali tylko wtedy, gdy jego pełne wymagania harmonogramowania odpowiadają szablonowi puli węzłów. Sprawdź żądanie zasobów GPU, pojemność maszyny wirtualnej, etykiety, skażenia, tolerancje, afinity, ograniczenia topologii, topologię woluminu trwałego, maksymalną liczbę węzłów i limit przydziału w Azure, gdy nie dochodzi do skalowania w górę.
Skalowanie do zera jest odpowiednie dla przerywalnych pul treningowych, ale wprowadza opóźnienia związane z aprowizowaniem maszyn wirtualnych, pobieraniem obrazów, montowaniem zbioru danych i inicjalizacją modelu. Zachowaj minimum niezerowe, gdy opóźnienie uruchamiania ma istotny wpływ na cele usługi. Budżety zakłóceń zasobników, zasobniki niewzmienialne, magazyn lokalny i długie okresy prolongaty zakończenia mogą opóźniać skalowanie w dół.
Usługa AKS Automatic zarządza aprowizowaniem i skalowaniem węzłów w ramach podstawowego zakresu usługi. Skoncentruj się na dokładnych żądaniach zasobników i obsługiwanych ograniczeniach zamiast konfigurowania automatycznego skalowania puli węzłów procesora GPU.
Przechowywanie zestawów danych i punktów kontrolnych
Najważniejszy wniosek: wybieraj pamięć masową w zależności od wzorca dostępu, przepustowości, udostępniania i wymagań dotyczących odtwarzania oraz zapisuj punkty kontrolne poza węzłem, aby można było wznowić trenowanie po wyeksmitowaniu lub przerwaniu.
Nie umieszczaj dużych zestawów danych, artefaktów modelu ani punktów kontrolnych w obrazach kontenerów. Wybierz interfejs pamięci masowej w zależności od obciążenia:
- Użyj Azure Blob Storage w przypadku dużych zestawów danych obiektów, artefaktów modelu i repozytoriów danych o wysokiej pojemności.
- Użyj Azure Files, gdy wiele węzłów roboczych wymaga udostępnionego systemu plików w stylu POSIX.
- Użyj usługi Azure Disk do obciążeń punktów kontrolnych lub pamięci podręcznej o wysokiej wydajności, z odczytem i zapisem na pojedynczym węźle, gdy
ReadWriteOncejest wystarczające. - Używaj lokalnej pamięci efemerycznej węzła tylko na potrzeby pamięci podręcznych, które można odtworzyć, oraz plików tymczasowych.
Uzyskiwanie dostępu do dużych zestawów danych za pomocą sterownika Azure Blob CSI
Włącz sterownik Azure Blob CSI w usłudze AKS Standard, jeśli nie został jeszcze włączony:
RESOURCE_GROUP=myResourceGroup
AKS_CLUSTER=myAKSCluster
az aks update \
--resource-group "$RESOURCE_GROUP" \
--name "$AKS_CLUSTER" \
--enable-blob-driver
Poniższy przykład dynamicznie tworzy kontener obiektów blob Azure w warstwie Premium, udostępniany przez NFS, i montuje go w podzie szkoleniowym. W przypadku istniejącego zarządzanego zestawu danych użyj statycznie zdefiniowanego woluminu lub konfiguracji obiektu BlobFuse z odpowiednimi kontrolkami tożsamości i sieci prywatnej zamiast tworzenia pustego kontenera dynamicznego:
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: ml-azureblob-nfs
provisioner: blob.csi.azure.com
parameters:
protocol: nfs
skuName: Premium_LRS
reclaimPolicy: Delete
allowVolumeExpansion: true
volumeBindingMode: Immediate
mountOptions:
- -o attr_timeout=120
- -o entry_timeout=120
- -o negative_timeout=120
- -o actimeo=120
- -o noresvport
- -o nconnect=4
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: blob-training-dataset
namespace: default
spec:
accessModes:
- ReadWriteMany
storageClassName: ml-azureblob-nfs
resources:
requests:
storage: 1Ti
---
apiVersion: batch/v1
kind: Job
metadata:
name: inspect-blob-dataset
namespace: default
spec:
backoffLimit: 2
template:
metadata:
labels:
app: inspect-blob-dataset
spec:
restartPolicy: Never
containers:
- name: dataset-reader
image: ubuntu:24.04
command:
- /bin/bash
- -c
- |
set -e
echo "Mounted dataset path:"
df -h /mnt/dataset
find /mnt/dataset -maxdepth 2 -type f | head -100
volumeMounts:
- name: dataset
mountPath: /mnt/dataset
volumes:
- name: dataset
persistentVolumeClaim:
claimName: blob-training-dataset
Przeprowadź test porównawczy opcji protokołu i instalacji względem reprezentatywnych rozmiarów fragmentów i wzorców dostępu. Gdy wiele procesów roboczych odczytuje wiele małych plików, wyniki mogą się różnić od tych uzyskiwanych przy sekwencyjnym strumieniowym odczycie dużych fragmentów danych. Rozważ podział zestawów danych na fragmenty o odpowiednim rozmiarze oraz użycie lokalnej dla węzła przestrzeni pamięci podręcznej, jeśli w kolejnych epokach trzeba byłoby ponownie pobierać te same obiekty.
Udostępnij dane treningowe za pomocą usługi Azure Files
Usługa Azure Files obsługuje ReadWriteMany, co umożliwia rozproszonym procesom roboczym na różnych węzłach montowanie tego samego udziału. Usługa Premium Azure Files jest odpowiednia, gdy obciążenie wymaga przewidywalnej wydajności systemu plików, a wybrany region obsługuje wymaganą opcję nadmiarowości.
Poniższy manifest tworzy udział usługi Azure Files w warstwie Premium i montuje go w dwóch równoległych podach roboczych:
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: ml-azurefile-premium
provisioner: file.csi.azure.com
parameters:
skuName: Premium_LRS
reclaimPolicy: Delete
allowVolumeExpansion: true
volumeBindingMode: Immediate
mountOptions:
- dir_mode=0770
- file_mode=0660
- uid=1000
- gid=1000
- mfsymlinks
- cache=strict
- actimeo=30
- nosharesock
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: shared-training-data
namespace: default
spec:
accessModes:
- ReadWriteMany
storageClassName: ml-azurefile-premium
resources:
requests:
storage: 100Gi
---
apiVersion: batch/v1
kind: Job
metadata:
name: shared-data-workers
namespace: default
spec:
completions: 2
parallelism: 2
completionMode: Indexed
backoffLimitPerIndex: 2
template:
metadata:
labels:
app: shared-data-workers
spec:
restartPolicy: Never
securityContext:
runAsUser: 1000
runAsGroup: 1000
fsGroup: 1000
containers:
- name: worker
image: ubuntu:24.04
command:
- /bin/bash
- -c
- |
set -e
WORKER_INDEX="${JOB_COMPLETION_INDEX:-0}"
echo "worker=${WORKER_INDEX}" \
> "/mnt/shared/worker-${WORKER_INDEX}.txt"
ls -la /mnt/shared
volumeMounts:
- name: shared-data
mountPath: /mnt/shared
volumes:
- name: shared-data
persistentVolumeClaim:
claimName: shared-training-data
Unikaj wielokrotnego wyliczania katalogu zawierającego miliony plików. Użyj manifestu lub deterministycznego przydziału shardów, aby każdy proces roboczy wiedział, które obiekty ma odczytać.
Punkt kontrolny do magazynu trwałego
Punkt kontrolny powinien zawierać wystarczającą ilość stanu, aby wznowić działanie prawidłowo, takie jak wagi modelu, stan optymalizatora, stan harmonogramu, stan skalowania, epoka lub numer kroku, stan generatora liczb losowych i pozycja modułu ładującego dane, gdy jest obsługiwana. Zapisuj punkty kontrolne okresowo oraz przed łagodnym zakończeniem.
Poniższe zadanie zapisuje atomowe punkty kontrolne PyTorch w usłudze Azure Files, przywraca najnowszy punkt kontrolny po ponownym uruchomieniu kontenera lub zastąpieniu poda oraz obsługuje SIGTERM, dzięki czemu wywłaszczenie może zachować ostatnie postępy:
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: ml-checkpoints-azurefile
provisioner: file.csi.azure.com
parameters:
skuName: Premium_LRS
reclaimPolicy: Retain
allowVolumeExpansion: true
volumeBindingMode: Immediate
mountOptions:
- dir_mode=0770
- file_mode=0660
- uid=1000
- gid=1000
- mfsymlinks
- cache=strict
- actimeo=30
- nosharesock
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: model-checkpoints
namespace: default
spec:
accessModes:
- ReadWriteMany
storageClassName: ml-checkpoints-azurefile
resources:
requests:
storage: 100Gi
---
apiVersion: batch/v1
kind: Job
metadata:
name: checkpointed-pytorch-training
namespace: default
spec:
backoffLimit: 6
template:
metadata:
labels:
app: checkpointed-pytorch-training
spec:
restartPolicy: OnFailure
terminationGracePeriodSeconds: 120
securityContext:
runAsUser: 1000
runAsGroup: 1000
fsGroup: 1000
containers:
- name: trainer
image: pytorch/pytorch:2.4.1-cuda12.4-cudnn9-runtime
command:
- python
- -c
- |
import os
import signal
import sys
import time
import torch
checkpoint_path = "/checkpoints/latest.pt"
temporary_path = "/checkpoints/latest.pt.tmp"
state = {"epoch": 0, "value": torch.tensor([0.0])}
if os.path.exists(checkpoint_path):
state = torch.load(checkpoint_path, map_location="cpu")
print(f"Restored epoch {state['epoch']}", flush=True)
def save_checkpoint():
torch.save(state, temporary_path)
os.replace(temporary_path, checkpoint_path)
print(f"Saved epoch {state['epoch']}", flush=True)
def terminate(signum, frame):
print(f"Received signal {signum}", flush=True)
save_checkpoint()
sys.exit(143)
signal.signal(signal.SIGTERM, terminate)
signal.signal(signal.SIGINT, terminate)
for epoch in range(state["epoch"] + 1, 21):
state["epoch"] = epoch
state["value"] += 1
time.sleep(10)
if epoch % 2 == 0:
save_checkpoint()
save_checkpoint()
print("Training completed.", flush=True)
volumeMounts:
- name: checkpoints
mountPath: /checkpoints
resources:
requests:
cpu: "1"
memory: 2Gi
limits:
cpu: "1"
memory: 2Gi
volumes:
- name: checkpoints
persistentVolumeClaim:
claimName: model-checkpoints
Użyj Retain zasady odzyskiwania lub niezależnie zarządzanego konta magazynowego dla produkcyjnych punktów kontrolnych, aby usunięcie PVC nie spowodowało niezamierzonego usunięcia jedynego punktu przywracania. W przypadku rozproszonego treningu równoległego względem danych zazwyczaj należy polecić procesowi o randze zero zapisanie globalnego punktu kontrolnego albo użyć obsługiwanego przez framework shardowanego formatu punktu kontrolnego. Zapobiegaj jednoczesnemu zapisaniu tego samego pliku w wielu szeregach.
Przetestuj odzyskiwanie po awarii, celowo usuwając pod roboczy podczas uruchomienia w środowisku nieprodukcyjnym. Sprawdź, czy kontroler ponownie utworzy obciążenie, nowy zasobnik instaluje ten sam trwały wolumin i wznawia trenowanie z oczekiwanego kroku.
Monitorowanie wykorzystania procesora GPU i przepływności trenowania
Kluczowy wniosek: Monitoruj wykorzystanie obliczeniowe GPU, pamięć GPU, przepustowość potoku danych, czas trwania kroku oraz aktywność związaną z punktami kontrolnymi, aby odróżnić nasycenie zasobów obliczeniowych od wąskich gardeł procesora CPU, sieci lub pamięci masowej.
Włącz usługę zarządzaną Azure Monitor dla rozwiązania Prometheus i Container Insights, aby skorelować stan platformy Kubernetes, dzienniki kontenera, kondycję węzła i metryki Rozwiązania Prometheus. Podczas projektowania alertów, przechowywania i operacyjnych pulpitów nawigacyjnych należy stosować najlepsze rozwiązania dotyczące monitorowania usługi AKS .
Zbieranie metryk procesora GPU firmy NVIDIA
Eksporter NVIDIA Data Center GPU Manager (DCGM) udostępnia metryki Prometheusa dla układów GPU NVIDIA. Jeśli operator procesora GPU firmy NVIDIA już wdraża eksportera DCGM, nie wdrażaj zduplikowanego eksportera. Skonfiguruj Azure Monitor zarządzanego rozwiązania Prometheus w celu złomowania istniejącego eksportera.
Poniższy PodMonitor używa zarządzanego przez Azure Monitor zasobu CRD Prometheus i jest przeznaczony dla zasobników DCGM Exporter w przestrzeni nazw gpu-operator. Dostosuj selektor etykiet, aby był zgodny z etykietami używanymi przez zainstalowanego eksportera:
apiVersion: azmonitoring.coreos.com/v1
kind: PodMonitor
metadata:
name: nvidia-dcgm-exporter
namespace: gpu-operator
spec:
selector:
matchLabels:
app: nvidia-dcgm-exporter
podMetricsEndpoints:
- port: metrics
interval: 30s
scrapeTimeout: 10s
Przed zastosowaniem zasobu monitorującego sprawdź nazwę usługi eksportera lub nazwę portu poda. Typowe metryki DCGM obejmują:
| Metric | Purpose |
|---|---|
DCGM_FI_DEV_GPU_UTIL |
Procent czasu aktywnego procesora GPU |
DCGM_FI_DEV_FB_USED |
Używana pamięć buforu ramek |
DCGM_FI_DEV_FB_FREE |
Wolna pamięć buforu ramek |
DCGM_FI_DEV_MEM_COPY_UTIL |
Wykorzystanie aparatu kopiowania pamięci |
DCGM_FI_DEV_POWER_USAGE |
Zużycie energii procesora GPU |
DCGM_FI_DEV_GPU_TEMP |
Temperatura procesora GPU |
DCGM_FI_DEV_XID_ERRORS |
Zdarzenia błędów NVIDIA XID |
Dostępność metryk zależy od wersji procesorów GPU, sterowników, DCGM i eksporterów.
Eksportowanie metryk przepływności trenowania
Wyposaż aplikację szkoleniową w metryki na poziomie obciążenia. Przydatne metryki obejmują:
-
ml_training_samples_totaldla skumulowanych próbek lub przetworzonych tokenów. -
ml_training_steps_totaldla zakończonych kroków optymalizacji. -
ml_training_step_duration_secondsdla opóźnienia kroku. -
ml_training_checkpoint_duration_secondsdla opóźnienia punktu kontrolnego. -
ml_training_data_wait_secondsdla czasu oczekiwania na dane wejściowe. - Utrata specyficzna dla modelu, szybkość uczenia, normy gradientu i metryki walidacji.
Poniższy przykład z możliwością uruchomienia uwidacznia syntetyczne metryki trenowania na porcie 8000. Zastąp symulację metrykami emitowaną przez rzeczywistą pętlę trenowania:
apiVersion: v1
kind: Namespace
metadata:
name: ml-observability
---
apiVersion: v1
kind: ConfigMap
metadata:
name: training-metrics-server
namespace: ml-observability
data:
server.py: |
import http.server
import threading
import time
state = {
"samples": 0,
"steps": 0,
"last_step_duration": 0.0,
}
def train():
while True:
started = time.time()
time.sleep(1)
state["samples"] += 256
state["steps"] += 1
state["last_step_duration"] = time.time() - started
class MetricsHandler(http.server.BaseHTTPRequestHandler):
def do_GET(self):
if self.path != "/metrics":
self.send_response(404)
self.end_headers()
return
body = (
"# HELP ml_training_samples_total Samples processed.\n"
"# TYPE ml_training_samples_total counter\n"
f"ml_training_samples_total{{job_name=\"metrics-demo\"}} "
f"{state['samples']}\n"
"# HELP ml_training_steps_total Training steps completed.\n"
"# TYPE ml_training_steps_total counter\n"
f"ml_training_steps_total{{job_name=\"metrics-demo\"}} "
f"{state['steps']}\n"
"# HELP ml_training_step_duration_seconds "
"Duration of the most recent training step.\n"
"# TYPE ml_training_step_duration_seconds gauge\n"
f"ml_training_step_duration_seconds"
f"{{job_name=\"metrics-demo\"}} "
f"{state['last_step_duration']}\n"
).encode("utf-8")
self.send_response(200)
self.send_header("Content-Type", "text/plain; version=0.0.4")
self.send_header("Content-Length", str(len(body)))
self.end_headers()
self.wfile.write(body)
def log_message(self, format, *args):
return
threading.Thread(target=train, daemon=True).start()
http.server.ThreadingHTTPServer(("0.0.0.0", 8000), MetricsHandler).serve_forever()
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: training-metrics-demo
namespace: ml-observability
spec:
replicas: 1
selector:
matchLabels:
app: training-metrics-demo
template:
metadata:
labels:
app: training-metrics-demo
spec:
containers:
- name: metrics
image: python:3.12-slim
command:
- python
- /app/server.py
ports:
- name: metrics
containerPort: 8000
readinessProbe:
httpGet:
path: /metrics
port: metrics
initialDelaySeconds: 2
periodSeconds: 10
resources:
requests:
cpu: 50m
memory: 64Mi
limits:
cpu: 200m
memory: 128Mi
volumeMounts:
- name: application
mountPath: /app
readOnly: true
volumes:
- name: application
configMap:
name: training-metrics-server
---
apiVersion: azmonitoring.coreos.com/v1
kind: PodMonitor
metadata:
name: training-metrics-demo
namespace: ml-observability
spec:
selector:
matchLabels:
app: training-metrics-demo
podMetricsEndpoints:
- port: metrics
path: /metrics
interval: 30s
scrapeTimeout: 10s
W przypadku rzeczywistego zadania rozproszonego uwzględnij stabilne etykiety, takie jak nazwa modelu, wersja modelu, nazwa zadania, identyfikator uruchomienia, rola repliki i zespół. Nie używaj nieograniczonych etykiet, takich jak identyfikatory próbek, identyfikatory żądań lub surowe ścieżki do zbiorów danych, ponieważ etykiety o wysokiej kardynalności zwiększają koszty monitorowania i opóźnienia zapytań.
Tworzenie pulpitów nawigacyjnych GPU i przepustowości
Użyj zapytań PromQL, takich jak poniższe, jako punktów wyjścia i zweryfikuj etykiety metryk w swoim eksporterze:
avg by (namespace, pod, gpu) (
avg_over_time(DCGM_FI_DEV_GPU_UTIL[5m])
)
Następujące zapytanie oblicza użycie pamięci buforu ramek jako wartość procentową:
100 *
DCGM_FI_DEV_FB_USED
/
(DCGM_FI_DEV_FB_USED + DCGM_FI_DEV_FB_FREE)
Następujące zapytanie oblicza liczbę próbek treningowych przetwarzanych na sekundę:
sum by (job_name) (
rate(ml_training_samples_total[5m])
)
Następujące zapytanie wyświetla średni czas trwania kroku:
avg by (job_name) (
ml_training_step_duration_seconds
)
Zinterpretuj te sygnały razem:
- Niskie wykorzystanie GPU i długi czas oczekiwania na dane zwykle wskazują na problemy z pamięcią masową, siecią, wstępnym przetwarzaniem danych lub niedoborem zasobów CPU.
- Wysokie wykorzystanie procesora GPU z oczekiwaną przepływnością wskazuje, że akcelerator jest skutecznie używany.
- Duża ilość pamięci procesora GPU i powtarzające się błędy braku pamięci wskazują, że rozmiar partii, długość sekwencji, pamięć aktywacji, stan optymalizatora lub fragmentacja wymaga dostosowania.
- Spadająca przepływność przy stabilnym wykorzystaniu procesora GPU może wskazywać na dłuższe sekwencje, obciążenie komunikacji, zachowanie cieplne lub zmianę obliczeń modelu.
- Niskie wykorzystanie GPU na przydzielonych procesorach graficznych wskazuje na niewykorzystane zasoby, które można ograniczyć, inaczej kolejkować lub podzielić za pomocą MIG.
- Długi czas tworzenia punktu kontrolnego może sprawić, że wywłaszczenie będzie kosztowne, i zwiększyć zakres pracy, którą trzeba powtórzyć po przywróceniu.
Twórz alerty dotyczące utrzymującego się niskiego wykorzystania GPU, wykorzystania pamięci GPU bliskiego maksymalnej pojemności, błędów XID, zastoju przepustowości trenowania, awarii procesów roboczych, oczekujących obciążeń planowanych grupowo oraz punktów kontrolnych, które nie zostały ukończone w oczekiwanym czasie wynikającym z docelowego punktu odzyskiwania.
Najczęściej zadawane pytania (FAQ)
Jaka jest różnica między usługą AKS Automatic i AKS Standard for MLOps?
Usługa AKS Automatic udostępnia wstępnie skonfigurowane domyślne ustawienia dla pul węzłów, sieci, zabezpieczeń i aktualizacji, dzięki czemu zespoły MLOps mogą skupić się na definicjach obciążeń i nadzorze. Usługa AKS Standard wymaga ręcznej konfiguracji tych składników platformy, ale zapewnia głębszą kontrolę nad niestandardowymi architekturami i wymaganiami dotyczącymi skalowania.
Jak mogę wersjonować modele uczenia maszynowego w usłudze AKS?
Wersjonuj swoje modele, pakując wagi modeli, metadane i konfiguracje w obrazach kontenerów przy użyciu semantycznych znaczników wersji. Przechowuj te obrazy w usłudze Azure Container Registry i odwołuj się do konkretnych wersji w manifestach wdrożeniowych Kubernetes, aby zapewnić spójność w różnych środowiskach.
Jak zaplanować obciążenia procesora GPU w usłudze AKS?
Upewnij się, że wtyczka urządzeń NVIDIA jest dostępna, aby węzły GPU zgłaszały nvidia.com/gpu. W usłudze AKS Standard utwórz dedykowaną pulę węzłów użytkownika z procesorem GPU, korzystając z obsługiwanego rozmiaru maszyny wirtualnej, takiego jak jednostka SKU serii Standard_NC, i skonfiguruj etykiety węzłów, skażenie NoSchedule oraz limity autoskalera klastra. W każdym podzie treningowym zażądaj nvidia.com/gpu, wybierz kwalifikujący się węzeł GPU i dodaj odpowiadającą tolerancję. AKS Automatic może przydzielać kwalifikujące się zasoby GPU na podstawie żądań zasobników, z zastrzeżeniem obsługiwanych jednostek SKU, dostępności regionalnej, ograniczeń harmonogramowania i limitu przydziału w ramach subskrypcji platformy Azure.
Jak uruchamiać rozproszone zadania szkoleniowe w usłudze AKS?
Zainstaluj operator treningowy Kubeflow i prześlij PyTorchJob lub TFJob, aby zarządzać rozproszonymi replikami, konfiguracją rendezvous, zasadami ponownego uruchamiania i stanem zadania. KAITO zapewnia abstrakcję obszaru roboczego skoncentrowaną na usłudze AKS dla obsługiwanych przepływów pracy dostrajania modeli i może koordynować infrastrukturę GPU z predefiniowanymi ustawieniami modeli. W przypadku wielowęzłowego treningu PyTorch skonfiguruj i przeprowadź testy porównawcze NCCL w sieci podów AKS CNI, zezwól na ruch między węzłami roboczymi za pomocą zasad sieciowych i użyj obsługiwanej konfiguracji RDMA, jeśli wymagają tego wybrany typ maszyny wirtualnej (SKU) i obciążenie.
Jak zarządzać limitem przydziału procesora GPU w wielu zespołach?
Zainstaluj Kueue i zdefiniuj zasoby ClusterQueue z limitami CPU, pamięci i nvidia.com/gpu, a następnie przypisz przestrzeń nazw każdego zespołu do przypisanego mu limitu za pomocą obiektu LocalQueue. Używaj kohort Kueue lub sprawiedliwego współdzielenia, gdy zespoły mogą korzystać z niewykorzystanych zasobów. Volcano jest alternatywą, gdy potrzebujesz mechanizmu harmonogramowania zadań wsadowych z dopuszczaniem workerów na zasadzie „wszystko albo nic”. Skoordynuj priorytet kolejki z zasobami Kubernetes PriorityClass, aby wnioskowanie wrażliwe na opóźnienia mogło mieć pierwszeństwo przed zadaniami treningowymi, które można przerwać, oraz zapewnij, aby zadania treningowe z możliwością wywłaszczenia były wznawiane z punktów kontrolnych zapisanych w trwałej pamięci masowej.
Jakie są najlepsze rozwiązania dotyczące długotrwałych zadań wsadowych w usłudze AKS?
Użyj obiektu Kubernetes Job do zadań jednorazowych, a CronJob do zadań zaplanowanych. Utrwalaj punkty kontrolne i zatwierdzone dane wyjściowe poza podem, zapewnij idempotentność przetwarzania, obsługuj SIGTERM oraz ustaw jawne żądania zasobów, limity ponawiania prób, limity czasu i zasady czyszczenia. Załóż, że konserwacja węzła lub jego awaria mogą spowodować zastąpienie zasobnika, i sprawdź, czy zastępczy zasobnik prawidłowo odtwarza swój punkt kontrolny. Monitoruj stan zadania, zdarzenia podów, dzienniki, wiek punktu kontrolnego, przepustowość i sposób ponawiania prób. Zwykłe zadania, które można ponownie uruchamiać, nie wymagają gang scheduling ani PDB. Używaj tych elementów sterujących tylko wtedy, gdy równoległe procesy muszą uruchamiać się jednocześnie lub utrzymać sprawdzony minimalny poziom współbieżności.
Treści powiązane
Dowiedz się więcej o najlepszych rozwiązaniach w innych obszarach wdrażania i operacji aplikacji w usłudze AKS: