Dziękujemy za zapoznanie się z Google I/O. Zobacz wszystkie sesje na żądanie Oglądaj na żądanie

Zoptymalizuj wydajność TensorFlow za pomocą Profilera

Ten przewodnik pokazuje, jak używać narzędzi dostępnych z TensorFlow Profiler do śledzenia wydajności modeli TensorFlow. Dowiesz się, jak zrozumieć, jak Twój model działa na hoście (CPU), urządzeniu (GPU) lub na kombinacji hosta i urządzenia (urządzeń).

Profilowanie pomaga zrozumieć zużycie zasobów sprzętowych (czas i pamięć) różnych operacji TensorFlow (ops) w modelu i rozwiązać wąskie gardła wydajności, a ostatecznie przyspieszyć wykonanie modelu.

Ten przewodnik poprowadzi Cię przez sposób instalowania programu Profiler, różne dostępne narzędzia, różne tryby zbierania danych dotyczących wydajności przez program Profiler oraz kilka zalecanych najlepszych praktyk w celu optymalizacji wydajności modelu.

Jeśli chcesz profilować wydajność swojego modelu w Cloud TPU, zapoznaj się z przewodnikiem dotyczącym Cloud TPU .

Zainstaluj wymagania wstępne programu Profiler i GPU

Zainstaluj wtyczkę Profiler dla TensorBoard za pomocą pip. Zauważ, że Profiler wymaga najnowszych wersji TensorFlow i TensorBoard (>=2,2).

pip install -U tensorboard_plugin_profile

Aby profilować na GPU, musisz:

  1. Spełnij wymagania sterowników NVIDIA® GPU i CUDA® Toolkit wymienione w wymaganiach oprogramowania obsługi GPU TensorFlow .
  2. Upewnij się, że na ścieżce znajduje się interfejs NVIDIA® CUDA® Profiling Tools Interface (CUPTI):

    /sbin/ldconfig -N -v $(sed 's/:/ /g' <<< $LD_LIBRARY_PATH) | \
    grep libcupti
    

Jeśli nie masz CUPTI w ścieżce, dodaj jego katalog instalacyjny do zmiennej środowiskowej $LD_LIBRARY_PATH , uruchamiając:

export LD_LIBRARY_PATH=/usr/local/cuda/extras/CUPTI/lib64:$LD_LIBRARY_PATH

Następnie ponownie uruchom powyższe polecenie ldconfig , aby sprawdzić, czy znaleziono bibliotekę CUPTI.

Rozwiąż problemy z uprawnieniami

Po uruchomieniu profilowania za pomocą CUDA® Toolkit w środowisku Docker lub w systemie Linux mogą wystąpić problemy związane z niewystarczającymi uprawnieniami CUPTI ( CUPTI_ERROR_INSUFFICIENT_PRIVILEGES ). Przejdź do NVIDIA Developer Docs , aby dowiedzieć się więcej o rozwiązywaniu tych problemów w systemie Linux.

Aby rozwiązać problemy z uprawnieniami CUPTI w środowisku Docker, uruchom

docker run option '--privileged=true'

Narzędzia profilujące

Uzyskaj dostęp do Profilera z zakładki Profil w TensorBoard, która pojawia się dopiero po przechwyceniu niektórych danych modelu.

Profiler posiada zestaw narzędzi pomagających w analizie wydajności:

  • Strona Przegląd
  • Analizator rurociągu wejściowego
  • Statystyki TensorFlow
  • Przeglądarka śledzenia
  • Statystyki jądra GPU
  • Narzędzie profilu pamięci
  • Podgląd podów

Strona Przegląd

Strona przeglądu zapewnia widok najwyższego poziomu, w jaki sposób model działał podczas uruchamiania profilu. Strona zawiera zagregowaną stronę przeglądu hosta i wszystkich urządzeń oraz kilka zaleceń dotyczących poprawy wydajności uczenia modelu. Możesz także wybrać poszczególnych hostów w menu rozwijanym Host.

Strona przeglądu wyświetla dane w następujący sposób:

obraz

  • Podsumowanie wydajności : wyświetla ogólne podsumowanie wydajności modelu. Podsumowanie wyników składa się z dwóch części:

    1. Podział czasu krokowego: dzieli średni czas kroku na wiele kategorii, w których spędza się czas:

      • Kompilacja: Czas spędzony na kompilacji jąder.
      • Wejście: Czas spędzony na czytaniu danych wejściowych.
      • Output: Czas spędzony na czytaniu danych wyjściowych.
      • Uruchamianie jądra: czas poświęcony przez hosta na uruchomienie jąder
      • Czas obliczeniowy hosta...
      • Czas komunikacji urządzenie-urządzenie.
      • Czas obliczeniowy na urządzeniu.
      • Wszystkie inne, w tym obciążenie Pythona.
    2. Precyzja obliczeń urządzenia — podaje procent czasu obliczeń urządzenia przy użyciu obliczeń 16- i 32-bitowych.

  • Wykres czasu kroku : Wyświetla wykres czasu kroku urządzenia (w milisekundach) na wszystkich próbkowanych krokach. Każdy krok jest podzielony na wiele kategorii (w różnych kolorach), w których spędza się czas. Czerwony obszar odpowiada części czasu, w którym urządzenia były bezczynne, czekając na dane wejściowe z hosta. Zielony obszar pokazuje, jak długo urządzenie faktycznie działało.

  • Top 10 operacji TensorFlow na urządzeniu (np. GPU) : Wyświetla operacje na urządzeniu, które trwały najdłużej.

    Każdy wiersz wyświetla czas własny operacji (jako procent czasu zajętego przez wszystkie operacje), łączny czas, kategorię i nazwę.

  • Środowisko uruchomieniowe : Wyświetla ogólne podsumowanie środowiska uruchomieniowego modelu, w tym:

    • Liczba używanych hostów.
    • Typ urządzenia (GPU/TPU).
    • Liczba rdzeni urządzenia.
  • Zalecenie dotyczące następnego kroku : raportuje, gdy model jest powiązany z danymi wejściowymi, i zaleca narzędzia, których można użyć do zlokalizowania i rozwiązania wąskich gardeł wydajności modelu.

Analizator rurociągów wejściowych

Kiedy program TensorFlow odczytuje dane z pliku, zaczyna się na górze wykresu TensorFlow w sposób potokowy. Proces odczytu podzielony jest na wiele etapów przetwarzania danych połączonych szeregowo, gdzie wyjście jednego etapu jest wejściem do następnego. Ten system odczytu danych nazywany jest potokiem wejściowym .

Typowy potok odczytu rekordów z plików ma następujące etapy:

  1. Czytanie plików.
  2. Wstępne przetwarzanie plików (opcjonalnie).
  3. Transfer plików z hosta na urządzenie.

Niewydajny potok wejściowy może poważnie spowolnić działanie aplikacji. Aplikacja jest uważana za powiązaną z danymi wejściowymi, gdy spędza znaczną część czasu w potoku wejściowym. Użyj informacji uzyskanych z analizatora potoku wejściowego, aby zrozumieć, gdzie potok wejściowy jest nieefektywny.

Analizator potoku wejściowego natychmiast informuje, czy program jest powiązany z danymi wejściowymi, i przeprowadza użytkownika przez analizę po stronie urządzenia i hosta w celu debugowania wąskich gardeł wydajności na dowolnym etapie potoku wejściowego.

Zapoznaj się ze wskazówkami dotyczącymi wydajności potoków wejściowych, aby uzyskać zalecane najlepsze rozwiązania dotyczące optymalizacji potoków wejściowych danych.

Pulpit nawigacyjny potoku wejściowego

Aby otworzyć wejściowy analizator potoku, wybierz Profil , a następnie wybierz input_pipeline_analyzer z listy rozwijanej Narzędzia .

obraz

Pulpit nawigacyjny zawiera trzy sekcje:

  1. Podsumowanie : podsumowuje ogólny potok wejściowy z informacjami o tym, czy aplikacja jest powiązana z danymi wejściowymi, a jeśli tak, o ile.
  2. Analiza po stronie urządzenia : wyświetla szczegółowe wyniki analizy po stronie urządzenia, w tym czas wykonania kroku urządzenia i zakres czasu spędzonego przez urządzenie na oczekiwaniu na dane wejściowe w rdzeniach na każdym kroku.
  3. Analiza po stronie hosta : pokazuje szczegółową analizę po stronie hosta, w tym podział czasu przetwarzania danych wejściowych na hoście.

Podsumowanie potoku wejściowego

Podsumowanie informuje, czy program jest powiązany z danymi wejściowymi, przedstawiając procent czasu urządzenia spędzonego na oczekiwaniu na dane wejściowe z hosta. Jeśli używasz standardowego potoku wejściowego, który został oprzyrządowany, narzędzie raportuje, gdzie spędza się większość czasu przetwarzania danych wejściowych.

Analiza po stronie urządzenia

Analiza po stronie urządzenia zapewnia wgląd w czas spędzony na urządzeniu w porównaniu z hostem oraz ile czasu urządzenie spędziło w oczekiwaniu na dane wejściowe z hosta.

  1. Czas kroku wykreślony względem numeru kroku : Wyświetla wykres czasu kroku urządzenia (w milisekundach) we wszystkich próbkowanych krokach. Każdy krok jest podzielony na wiele kategorii (w różnych kolorach), w których spędza się czas. Czerwony obszar odpowiada części czasu, w którym urządzenia były bezczynne, czekając na dane wejściowe z hosta. Zielony obszar pokazuje, jak długo urządzenie faktycznie działało.
  2. Statystyka czasu kroku : Podaje średnią, odchylenie standardowe i zakres ([minimum, maksimum]) czasu kroku urządzenia.

Analiza po stronie hosta

Analiza po stronie hosta raportuje podział czasu przetwarzania danych wejściowych (czas spędzony na operacjach API tf.data ) na hoście na kilka kategorii:

  • Odczytywanie danych z plików na żądanie : czas poświęcony na odczytywanie danych z plików bez buforowania, wstępnego pobierania i przeplatania.
  • Odczytywanie danych z plików z wyprzedzeniem : czas poświęcony na czytanie plików, w tym buforowanie, pobieranie z wyprzedzeniem i przeplatanie.
  • Wstępne przetwarzanie danych : czas poświęcony na wstępne przetwarzanie operacji, takie jak dekompresja obrazu.
  • Kolejkowanie danych do przesłania do urządzenia : czas spędzony na umieszczaniu danych w kolejce wejściowej przed przesłaniem danych do urządzenia.

Rozwiń Statystyki operacji wejściowych , aby sprawdzić statystyki poszczególnych operacji wejściowych i ich kategorie w rozbiciu na czas wykonania.

obraz

Z każdym wpisem pojawi się tabela danych źródłowych zawierająca następujące informacje:

  1. Input Op : Pokazuje nazwę operacji TensorFlow operacji wejściowej.
  2. Count : pokazuje łączną liczbę wystąpień wykonania operacji w okresie profilowania.
  3. Całkowity czas (w ms) : pokazuje skumulowaną sumę czasu spędzonego na każdym z tych wystąpień.
  4. Całkowity czas % : pokazuje całkowity czas spędzony na operacji jako ułamek całkowitego czasu spędzonego na przetwarzaniu danych wejściowych.
  5. Całkowity czas własny (w ms) : pokazuje skumulowaną sumę czasu własnego spędzonego w każdym z tych wystąpień. W tym przypadku self-time mierzy czas spędzony w treści funkcji, z wyłączeniem czasu spędzonego w wywołanej funkcji.
  6. Całkowity czas własny % . Pokazuje całkowity czas własny jako ułamek całkowitego czasu poświęconego na przetwarzanie danych wejściowych.
  7. Kategoria . Pokazuje kategorię przetwarzania wejścia op.

Statystyki TensorFlow

Narzędzie TensorFlow Stats wyświetla wydajność każdej operacji TensorFlow wykonywanej na hoście lub urządzeniu podczas sesji profilowania.

obraz

Narzędzie wyświetla informacje o wydajności w dwóch panelach:

  • W górnym okienku wyświetlane są do czterech wykresów kołowych:

    1. Rozkład czasu samodzielnego wykonania każdej operacji na hoście.
    2. Rozkład czasu samowykonania każdego typu operacji na hoście.
    3. Rozkład czasu samowykonania każdej operacji na urządzeniu.
    4. Rozkład czasu samowykonania każdego typu operacji na urządzeniu.
  • Dolny panel pokazuje tabelę, która raportuje dane o operacjach TensorFlow z jednym wierszem dla każdej operacji i jedną kolumną dla każdego typu danych (sortuj kolumny, klikając nagłówek kolumny). Kliknij przycisk Eksportuj jako CSV po prawej stronie górnego panelu, aby wyeksportować dane z tej tabeli jako plik CSV.

    Zwróć uwagę, że:

    • Jeśli jakieś operacje mają operacje podrzędne:

      • Całkowity „zakumulowany” czas operacji obejmuje czas spędzony w operacjach podrzędnych.
      • Całkowity czas „własny” operacji nie obejmuje czasu spędzonego w ramach operacji potomnych.
    • Jeśli na hoście wykonywana jest operacja:

      • Procent całkowitego czasu samodzielnego na urządzeniu poniesiony przez opcję wyniesie 0.
      • Skumulowany procent całkowitego czasu samodzielnego korzystania z urządzenia do tej operacji włącznie wyniesie 0.
    • Jeśli operacja jest wykonywana na urządzeniu:

      • Procent całkowitego czasu samodzielnego na hoście poniesiony przez tę operację wyniesie 0.
      • Skumulowany procent całkowitego czasu samodzielnego na hoście do tej operacji włącznie wyniesie 0.

Możesz włączyć lub wyłączyć czas bezczynności na wykresach kołowych i w tabeli.

Przeglądarka śledzenia

Przeglądarka śledzenia wyświetla oś czasu, która pokazuje:

  • Czasy trwania operacji, które zostały wykonane przez Twój model TensorFlow
  • Która część systemu (host lub urządzenie) wykonała operację. Zazwyczaj host wykonuje operacje wejściowe, wstępnie przetwarza dane szkoleniowe i przesyła je do urządzenia, podczas gdy urządzenie wykonuje rzeczywiste szkolenie modelu

Przeglądarka śledzenia umożliwia identyfikowanie problemów z wydajnością w modelu, a następnie podejmowanie kroków w celu ich rozwiązania. Na przykład na wysokim poziomie można określić, czy trenowanie danych wejściowych lub modeli zajmuje większość czasu. Przechodząc do szczegółów, możesz określić, które operacje trwają najdłużej. Należy pamiętać, że przeglądarka śledzenia jest ograniczona do 1 miliona zdarzeń na urządzenie.

Interfejs przeglądarki śledzenia

Gdy otworzysz przeglądarkę śladów, pojawi się Twój ostatni bieg:

obraz

Ten ekran zawiera następujące główne elementy:

  1. Okienko osi czasu : pokazuje operacje wykonywane przez urządzenie i hosta w czasie.
  2. Okienko szczegółów : pokazuje dodatkowe informacje o operacjach wybranych w okienku osi czasu.

Panel Oś czasu zawiera następujące elementy:

  1. Górny pasek : zawiera różne pomocnicze elementy sterujące.
  2. Oś czasu : Pokazuje czas w stosunku do początku śladu.
  3. Etykiety sekcji i ścieżek : każda sekcja zawiera wiele ścieżek i ma po lewej stronie trójkąt, który możesz kliknąć, aby rozwinąć lub zwinąć sekcję. Dla każdego elementu przetwarzającego w systemie jest jedna sekcja.
  4. Selektor narzędzi : zawiera różne narzędzia do interakcji z przeglądarką śledzenia, takie jak Zoom, Panoramowanie, Zaznaczanie i Chronometraż. Użyj narzędzia Pomiar czasu, aby oznaczyć przedział czasu.
  5. Zdarzenia : pokazują czas wykonania operacji lub czas trwania meta-zdarzeń, takich jak etapy szkolenia.
Sekcje i tory

Przeglądarka śledzenia zawiera następujące sekcje:

  • Jedna sekcja dla każdego węzła urządzenia , oznaczona numerem układu urządzenia i węzłem urządzenia w układzie (na przykład /device:GPU:0 (pid 0) ). Każda sekcja węzła urządzenia zawiera następujące ścieżki:
    • Krok : Pokazuje czas trwania kroków treningowych uruchomionych na urządzeniu
    • TensorFlow Ops : Pokazuje operacje wykonywane na urządzeniu
    • XLA Ops : Pokazuje operacje XLA (ops), które działały na urządzeniu, jeśli XLA jest używanym kompilatorem (każda operacja TensorFlow jest tłumaczona na jedną lub kilka operacji XLA. Kompilator XLA tłumaczy operacje XLA na kod, który działa na urządzeniu).
  • Jedna sekcja dla wątków działających na procesorze hosta, oznaczona jako „Wątki hosta” . Sekcja zawiera jedną ścieżkę dla każdego wątku procesora. Pamiętaj, że możesz zignorować informacje wyświetlane obok etykiet sekcji.
Wydarzenia

Wydarzenia na osi czasu są wyświetlane w różnych kolorach; same kolory nie mają konkretnego znaczenia.

Przeglądarka śladów może również wyświetlać ślady wywołań funkcji Pythona w twoim programie TensorFlow. Jeśli używasz interfejsu API tf.profiler.experimental.start , możesz włączyć śledzenie w języku Python przy użyciu ProfilerOptions namedtuple podczas uruchamiania profilowania. Alternatywnie, jeśli używasz trybu próbkowania do profilowania, możesz wybrać poziom śledzenia za pomocą opcji rozwijanych w oknie dialogowym Capture Profile .

obraz

Statystyki jądra GPU

To narzędzie pokazuje statystyki wydajności i początkową operację dla każdego jądra akcelerowanego przez GPU.

obraz

Narzędzie wyświetla informacje w dwóch panelach:

  • W górnym okienku wyświetlany jest wykres kołowy, który pokazuje jądra CUDA, które mają najwyższy łączny czas, jaki upłynął.

  • W dolnym okienku wyświetlana jest tabela z następującymi danymi dla każdej unikalnej pary operacji jądra:

    • Pozycja w porządku malejącym całkowitego czasu trwania GPU, pogrupowana według pary kernel-op.
    • Nazwa uruchomionego jądra.
    • Liczba rejestrów GPU używanych przez jądro.
    • Całkowity rozmiar pamięci współdzielonej (statycznej + dynamicznej współdzielonej) używanej w bajtach.
    • Wymiar bloku wyrażony jako blockDim.x, blockDim.y, blockDim.z .
    • Wymiary siatki wyrażone jako gridDim.x, gridDim.y, gridDim.z .
    • Czy operator kwalifikuje się do korzystania z rdzeni tensorowych .
    • Czy jądro zawiera instrukcje Tensor Core.
    • Nazwa operacji, która uruchomiła to jądro.
    • Liczba wystąpień tej pary kernel-op.
    • Całkowity upływający czas GPU w mikrosekundach.
    • Średni czas GPU, który upłynął w mikrosekundach.
    • Minimalny czas GPU, który upłynął w mikrosekundach.
    • Maksymalny czas GPU, jaki upłynął w mikrosekundach.

Narzędzie profilu pamięci

Narzędzie Profil pamięci monitoruje użycie pamięci urządzenia w okresie profilowania. Możesz użyć tego narzędzia do:

  • Debuguj problemy z brakiem pamięci (OOM), wskazując szczytowe użycie pamięci i odpowiednią alokację pamięci do operacji TensorFlow. Można również debugować problemy związane z OOM, które mogą wystąpić podczas uruchamiania wnioskowania o wielu dzierżawcach .
  • Debuguj problemy z fragmentacją pamięci.

Narzędzie profilu pamięci wyświetla dane w trzech sekcjach:

  1. Podsumowanie profilu pamięci
  2. Wykres osi czasu pamięci
  3. Tabela podziału pamięci

Podsumowanie profilu pamięci

Ta sekcja wyświetla ogólne podsumowanie profilu pamięci Twojego programu TensorFlow, jak pokazano poniżej:

Podsumowanie profilu pamięci składa się z sześciu pól:

  1. Identyfikator pamięci : lista rozwijana z listą wszystkich dostępnych systemów pamięci urządzenia. Wybierz system pamięci, który chcesz wyświetlić z listy rozwijanej.
  2. #Allocation : liczba alokacji pamięci dokonanych w okresie profilowania.
  3. #Deallocation : Liczba cofnięć alokacji pamięci w interwale profilowania
  4. Pojemność pamięci : Całkowita pojemność (w GiB) wybranego systemu pamięci.
  5. Szczytowe użycie sterty : szczytowe użycie pamięci (w GiB) od momentu uruchomienia modelu.
  6. Szczytowe użycie pamięci : szczytowe użycie pamięci (w GiB) w interwale profilowania. To pole zawiera następujące podpola:
    1. Sygnatura czasowa : sygnatura czasowa wystąpienia szczytowego użycia pamięci na wykresie osi czasu.
    2. Rezerwacja stosu : ilość pamięci zarezerwowanej na stosie (w GiB).
    3. Heap Allocation : ilość pamięci przydzielonej na stercie (w GiB).
    4. Wolna pamięć : ilość wolnej pamięci (w GiB). Pojemność pamięci to suma rezerwacji stosu, alokacji sterty i wolnej pamięci.
    5. Fragmentacja : Procent fragmentacji (im mniej tym lepiej). Jest obliczany jako procent (1 - Size of the largest chunk of free memory / Total free memory) .

Wykres osi czasu pamięci

Ta sekcja wyświetla wykres użycia pamięci (w GiB) i procent fragmentacji w funkcji czasu (w ms).

obraz

Oś X przedstawia oś czasu (w ms) interwału profilowania. Oś Y po lewej stronie reprezentuje użycie pamięci (w GiB), a oś Y po prawej reprezentuje procent fragmentacji. W każdym momencie na osi X całkowita pamięć jest podzielona na trzy kategorie: stos (na czerwono), sterta (na pomarańczowo) i wolna (na zielono). Najedź kursorem na określoną sygnaturę czasową, aby wyświetlić szczegółowe informacje o zdarzeniach alokacji/dealokacji pamięci w tym momencie, jak poniżej:

obraz

Wyskakujące okienko wyświetla następujące informacje:

  • timestamp(ms) : Lokalizacja wybranego wydarzenia na osi czasu.
  • zdarzenie : typ zdarzenia (alokacja lub cofnięcie alokacji).
  • request_size(GiBs) : Żądana ilość pamięci. Będzie to liczba ujemna dla zdarzeń cofnięcia alokacji.
  • alokacja_rozmiar(GiBs) : Rzeczywista ilość przydzielonej pamięci. Będzie to liczba ujemna dla zdarzeń cofnięcia alokacji.
  • tf_op : Operacja TensorFlow żądająca alokacji/zwolnienia.
  • step_id : etap szkolenia, w którym wystąpiło to zdarzenie.
  • region_type : typ jednostki danych, dla której jest przydzielona pamięć. Możliwe wartości to temp dla tymczasowych, output dla aktywacji i gradientów oraz persist / dynamic dla wag i stałych.
  • data_type : typ elementu tensorowego (np. uint8 dla 8-bitowej liczby całkowitej bez znaku).
  • tensor_shape : kształt tensora, który jest alokowany/cofany.
  • memory_in_use(GiBs) : Całkowita pamięć używana w tym momencie.

Tabela podziału pamięci

W tej tabeli przedstawiono aktywne alokacje pamięci w momencie szczytowego użycia pamięci w interwale profilowania.

obraz

Dla każdego TensorFlow Op istnieje jeden wiersz, a każdy wiersz zawiera następujące kolumny:

  • Nazwa operacji : Nazwa operacji TensorFlow.
  • Rozmiar alokacji (GiBs) : Całkowita ilość pamięci przydzielonej do tej operacji.
  • Żądany rozmiar (GiBs) : Całkowita ilość pamięci wymaganej dla tej operacji.
  • Zdarzenia : Liczba przydziałów dla tego op.
  • Typ regionu : typ jednostki danych, dla której jest przeznaczona ta przydzielona pamięć. Możliwe wartości to temp dla tymczasowych, output dla aktywacji i gradientów oraz persist / dynamic dla wag i stałych.
  • Typ danych : typ elementu tensora.
  • Shape : kształt przydzielonych tensorów.

Przeglądarka podów

Narzędzie Pod Viewer pokazuje podział etapu szkolenia dla wszystkich pracowników.

obraz

  • W górnym okienku znajduje się suwak do wybierania numeru kroku.
  • W dolnym okienku wyświetlany jest skumulowany wykres kolumnowy. Jest to widok wysokiego poziomu rozbitych kategorii krokowych umieszczonych jedna na drugiej. Każda ułożona kolumna reprezentuje unikalnego pracownika.
  • Gdy najedziesz kursorem na skumulowaną kolumnę, karta po lewej stronie pokaże więcej szczegółów na temat podziału kroków.

analiza wąskiego gardła tf.data

Narzędzie do analizy wąskich gardeł tf.data automatycznie wykrywa wąskie gardła w potokach wejściowych tf.data w programie i udostępnia zalecenia dotyczące ich naprawienia. Działa z dowolnym programem korzystającym z tf.data niezależnie od platformy (CPU/GPU/TPU). Jego analiza i zalecenia oparte są na tym przewodniku .

Wykrywa wąskie gardło, wykonując następujące kroki:

  1. Znajdź hosta, który jest najczęściej powiązany z danymi wejściowymi.
  2. Znajdź najwolniejsze wykonanie potoku wejściowego tf.data .
  3. Zrekonstruuj wykres potoku wejściowego ze śladu profilera.
  4. Znajdź ścieżkę krytyczną na grafie potoku wejściowego.
  5. Zidentyfikuj najwolniejszą transformację na ścieżce krytycznej jako wąskie gardło.

Interfejs użytkownika jest podzielony na trzy sekcje: Podsumowanie analizy wydajności , Podsumowanie wszystkich potoków wejściowych i Wykres potoków wejściowych .

Podsumowanie analizy wydajności

obraz

Ta sekcja zawiera podsumowanie analizy. Informuje o wolnych potokach wejściowych tf.data wykrytych w profilu. W tej sekcji przedstawiono również najbardziej powiązany z danymi wejściowymi host i jego najwolniejszy potok wejściowy z maksymalnym opóźnieniem. Co najważniejsze, identyfikuje, która część potoku wejściowego jest wąskim gardłem i jak to naprawić. Informacje o wąskim gardle są dostarczane z typem iteratora i jego długą nazwą.

Jak odczytać długą nazwę iteratora tf.data?

Długa nazwa jest sformatowana jako Iterator::<Dataset_1>::...::<Dataset_n> . W długiej nazwie <Dataset_n> pasuje do typu iteratora, a inne zestawy danych w długiej nazwie reprezentują przekształcenia w dół.

Rozważmy na przykład następujący wejściowy zestaw danych potoku:

dataset = tf.data.Dataset.range(10).map(lambda x: x).repeat(2).batch(5)

Długie nazwy iteratorów z powyższego zbioru danych będą następujące:

Typ iteratora Długie imię
Zasięg Iterator::Partia::Powtórz::Mapa::Zakres
Mapa Iterator::Partia::Powtórz::Mapa
Powtarzać Iterator::Partia::Powtórz
Partia Iterator::Partia

Podsumowanie wszystkich potoków wejściowych

obraz

Ta sekcja zawiera podsumowanie wszystkich potoków wejściowych na wszystkich hostach. Zazwyczaj istnieje jeden potok wejściowy. W przypadku korzystania ze strategii dystrybucji istnieje jeden potok wejściowy hosta, na którym działa kod tf.data programu i wiele potoków wejściowych urządzenia pobierających dane z potoku wejściowego hosta i przesyłających je do urządzeń.

Dla każdego potoku wejściowego pokazuje statystyki czasu jego wykonania. Połączenie jest liczone jako wolne, jeśli trwa dłużej niż 50 μs.

Wykres potoku wejściowego

obraz

W tej sekcji przedstawiono wykres potoku wejściowego z informacjami o czasie wykonania. Możesz użyć "Host" i "Potoku wejściowego", aby wybrać hosta i potok wejściowy do wyświetlenia. Wykonania potoku wejściowego są sortowane według czasu wykonania w kolejności malejącej, którą można wybrać za pomocą listy rozwijanej Ranga .

obraz

Węzły na ścieżce krytycznej mają pogrubione kontury. Węzeł wąskiego gardła, który jest węzłem o najdłuższym czasie własnym na ścieżce krytycznej, ma czerwony kontur. Pozostałe niekrytyczne węzły mają szare, przerywane kontury.

W każdym węźle Start Time wskazuje czas rozpoczęcia wykonania. Ten sam węzeł może być wykonywany wiele razy, na przykład jeśli w potoku wejściowym znajduje się Batch . Jeśli jest wykonywany wiele razy, jest to czas rozpoczęcia pierwszego wykonania.

Całkowity czas trwania to czas trwania egzekucji. Jeśli jest wykonywany wiele razy, jest to suma czasów muru wszystkich egzekucji.

Czas własny to czas całkowity bez nakładania się czasu z jego bezpośrednimi węzłami podrzędnymi.

„# Calls” to liczba wykonywanych potoków wejściowych.

Zbieraj dane o wydajności

TensorFlow Profiler zbiera aktywności hosta i ślady GPU Twojego modelu TensorFlow. Profiler można skonfigurować tak, aby zbierał dane o wydajności w trybie programistycznym lub w trybie próbkowania.

Profilowanie API

Do profilowania można użyć następujących interfejsów API.

  • Tryb programistyczny przy użyciu funkcji TensorBoard Keras Callback ( tf.keras.callbacks.TensorBoard )

    # Profile from batches 10 to 15
    tb_callback = tf.keras.callbacks.TensorBoard(log_dir=log_dir,
                                                 profile_batch='10, 15')
    
    # Train the model and use the TensorBoard Keras callback to collect
    # performance profiling data
    model.fit(train_data,
              steps_per_epoch=20,
              epochs=5,
              callbacks=[tb_callback])
    
  • Tryb programistyczny przy użyciu funkcji API tf.profiler

    tf.profiler.experimental.start('logdir')
    # Train the model here
    tf.profiler.experimental.stop()
    
  • Tryb programistyczny przy użyciu menedżera kontekstu

    with tf.profiler.experimental.Profile('logdir'):
        # Train the model here
        pass
    

  • Tryb próbkowania: Wykonaj profilowanie na żądanie przy użyciu tf.profiler.experimental.server.start , aby uruchomić serwer gRPC z uruchomieniem modelu TensorFlow. Po uruchomieniu serwera gRPC i uruchomieniu modelu, możesz przechwycić profil za pomocą przycisku Przechwyć profil we wtyczce profilu TensorBoard. Użyj skryptu w sekcji Install profiler powyżej, aby uruchomić instancję TensorBoard, jeśli nie jest jeszcze uruchomiona.

    Jako przykład,

    # Start a profiler server before your model runs.
    tf.profiler.experimental.server.start(6009)
    # (Model code goes here).
    #  Send a request to the profiler server to collect a trace of your model.
    tf.profiler.experimental.client.trace('grpc://localhost:6009',
                                          'gs://your_tb_logdir', 2000)
    

    Przykład profilowania wielu pracowników:

    # E.g. your worker IP addresses are 10.0.0.2, 10.0.0.3, 10.0.0.4, and you
    # would like to profile for a duration of 2 seconds.
    tf.profiler.experimental.client.trace(
        'grpc://10.0.0.2:8466,grpc://10.0.0.3:8466,grpc://10.0.0.4:8466',
        'gs://your_tb_logdir',
        2000)
    

Użyj okna dialogowego Profil przechwytywania , aby określić:

  • Rozdzielana przecinkami lista adresów URL usług profilu lub nazw TPU.
  • Czas trwania profilowania.
  • Poziom śledzenia wywołań funkcji urządzenia, hosta i funkcji Pythona.
  • Ile razy Profiler ma ponawiać próby przechwycenia profili, jeśli początkowo nie powiedzie się.

Profilowanie własnych pętli treningowych

Aby profilować niestandardowe pętle treningowe w kodzie TensorFlow, oprzyj pętlę treningową za pomocą interfejsu API tf.profiler.experimental.Trace , aby oznaczyć granice kroków dla Profilera.

Argument name jest używany jako prefiks nazw kroków, argument słowa kluczowego step_num jest dołączany do nazw kroków, a argument słowa kluczowego _r powoduje, że to zdarzenie śledzenia jest przetwarzane jako zdarzenie kroku przez Profiler.

Jako przykład,

for step in range(NUM_STEPS):
    with tf.profiler.experimental.Trace('train', step_num=step, _r=1):
        train_data = next(dataset)
        train_step(train_data)

Umożliwi to analizę wydajności opartą na krokach programu Profiler i spowoduje, że zdarzenia kroków będą wyświetlane w przeglądarce śledzenia.

Upewnij się, że iterator zestawu danych jest uwzględniony w kontekście tf.profiler.experimental.Trace w celu dokładnej analizy potoku wejściowego.

Poniższy fragment kodu jest antywzorcem:

for step, train_data in enumerate(dataset):
    with tf.profiler.experimental.Trace('train', step_num=step, _r=1):
        train_step(train_data)

Profilowanie przypadków użycia

Profiler obejmuje szereg przypadków użycia wzdłuż czterech różnych osi. Niektóre kombinacje są obecnie obsługiwane, a inne zostaną dodane w przyszłości. Niektóre przypadki użycia to:

  • Profilowanie lokalne a zdalne : są to dwa typowe sposoby konfigurowania środowiska profilowania. W profilowaniu lokalnym interfejs API profilowania jest wywoływany na tej samej maszynie, którą wykonuje model, na przykład lokalna stacja robocza z procesorami GPU. W przypadku profilowania zdalnego interfejs API profilowania jest wywoływany na innym komputerze niż ten, na którym wykonywany jest model, na przykład w Cloud TPU.
  • Profilowanie wielu pracowników : możesz profilować wiele komputerów, korzystając z funkcji szkolenia rozproszonego TensorFlow.
  • Platforma sprzętowa : Profile CPU, GPU i TPU.

Poniższa tabela zawiera krótki przegląd wspomnianych powyżej przypadków użycia obsługiwanych przez TensorFlow:

Profilowanie API Lokalny Zdalny Wielu pracowników Platformy sprzętowe
TensorBoard Keras Callback Utrzymany Nieobsługiwany Nieobsługiwany CPU, GPU
tf.profiler.experimental start/stop API Utrzymany Nieobsługiwany Nieobsługiwany CPU, GPU
tf.profiler.experimental client.trace API Utrzymany Utrzymany Utrzymany Procesor, GPU, TPU
Interfejs API menedżera kontekstu Utrzymany Nieobsługiwany Nieobsługiwany CPU, GPU

Najlepsze praktyki dla optymalnej wydajności modelu

Skorzystaj z poniższych zaleceń, jeśli mają zastosowanie do modeli TensorFlow, aby osiągnąć optymalną wydajność.

Ogólnie rzecz biorąc, wykonuj wszystkie przekształcenia na urządzeniu i upewnij się, że korzystasz z najnowszej zgodnej wersji bibliotek, takich jak cuDNN i Intel MKL dla swojej platformy.

Zoptymalizuj potok danych wejściowych

Użyj danych z [#input_pipeline_analyzer], aby zoptymalizować potok wprowadzania danych. Wydajny potok wprowadzania danych może znacznie zwiększyć szybkość wykonywania modelu, skracając czas bezczynności urządzenia. Spróbuj zastosować najlepsze rozwiązania opisane w artykule Lepsza wydajność z przewodnikiem interfejsu API tf.data i poniżej, aby zwiększyć wydajność potoku wprowadzania danych.

  • Ogólnie rzecz biorąc, zrównoleglenie dowolnych operacji, które nie muszą być wykonywane sekwencyjnie, może znacznie zoptymalizować potok wprowadzania danych.

  • W wielu przypadkach pomaga zmienić kolejność niektórych wywołań lub dostroić argumenty tak, aby działały najlepiej dla twojego modelu. Podczas optymalizacji potoku danych wejściowych porównaj tylko program ładujący dane bez kroków uczenia i propagacji wstecznej, aby niezależnie określić ilościowo wpływ optymalizacji.

  • Spróbuj uruchomić model z danymi syntetycznymi, aby sprawdzić, czy potok wejściowy jest wąskim gardłem wydajności.

  • Użyj tf.data.Dataset.shard do trenowania z użyciem wielu procesorów graficznych. Upewnij się, że fragmentujesz bardzo wcześnie w pętli wejściowej, aby zapobiec zmniejszeniu przepustowości. Podczas pracy z TFRecords, upewnij się, że dzielisz listę TFRecords, a nie zawartość TFRecords.

  • Zrównolegle kilka operacji, dynamicznie ustawiając wartość num_parallel_calls przy użyciu tf.data.AUTOTUNE .

  • Rozważ ograniczenie użycia tf.data.Dataset.from_generator , ponieważ jest wolniejszy w porównaniu z czystymi operacjami TensorFlow.

  • Rozważ ograniczenie użycia tf.py_function , ponieważ nie można go serializować i nie można go uruchomić w rozproszonym TensorFlow.

  • Użyj tf.data.Options , aby kontrolować statyczne optymalizacje potoku wejściowego.

Przeczytaj także przewodnik analizy wydajności tf.data , aby uzyskać więcej wskazówek dotyczących optymalizacji potoku wejściowego.

Zoptymalizuj powiększanie danych

Podczas pracy z danymi obrazu zwiększ wydajność powiększania danych , przesyłając do różnych typów danych po zastosowaniu przekształceń przestrzennych, takich jak odwracanie, przycinanie, obracanie itp.

Użyj NVIDIA® DALI

W niektórych przypadkach, na przykład w przypadku systemu z wysokim stosunkiem GPU do CPU, wszystkie powyższe optymalizacje mogą nie wystarczyć do wyeliminowania wąskich gardeł w programie ładującym dane spowodowanych ograniczeniami cykli procesora.

Jeśli używasz procesorów graficznych NVIDIA® do zastosowań związanych z widzeniem komputerowym i dźwiękiem do głębokiego uczenia się, rozważ użycie biblioteki ładowania danych ( DALI ) w celu przyspieszenia potoku danych.

Zapoznaj się z dokumentacją NVIDIA® DALI: Operations , aby uzyskać listę obsługiwanych operacji DALI.

Użyj wątków i wykonywania równoległego

Uruchamiaj operacje na wielu wątkach procesora za pomocą interfejsu API tf.config.threading , aby wykonywać je szybciej.

TensorFlow domyślnie automatycznie ustawia liczbę wątków równoległości. Pula wątków dostępna do uruchamiania operacji TensorFlow zależy od liczby dostępnych wątków procesora.

Kontroluj maksymalne przyspieszenie równoległe dla pojedynczej operacji za pomocą tf.config.threading.set_intra_op_parallelism_threads . Zauważ, że jeśli uruchomisz wiele operacji równolegle, wszystkie będą współdzielić dostępną pulę wątków.

Jeśli masz niezależne operacje nieblokujące (operacje bez skierowanej ścieżki między nimi na grafie), użyj tf.config.threading.set_inter_op_parallelism_threads , aby uruchomić je jednocześnie, korzystając z dostępnej puli wątków.

Różnorodny

Pracując z mniejszymi modelami na procesorach graficznych NVIDIA®, możesz ustawić tf.compat.v1.ConfigProto.force_gpu_compatible=True , aby wymusić alokację wszystkich tensorów procesora za pomocą pamięci przypiętej CUDA, aby znacząco zwiększyć wydajność modelu. Należy jednak zachować ostrożność podczas korzystania z tej opcji w przypadku nieznanych/bardzo dużych modeli, ponieważ może to negatywnie wpłynąć na wydajność hosta (procesora).

Popraw wydajność urządzenia

Postępuj zgodnie z najlepszymi praktykami opisanymi tutaj oraz w przewodniku optymalizacji wydajności GPU, aby zoptymalizować wydajność modelu TensorFlow na urządzeniu.

Jeśli korzystasz z procesorów graficznych NVIDIA, zarejestruj wykorzystanie procesora GPU i pamięci w pliku CSV, uruchamiając:

nvidia-smi
--query-gpu=utilization.gpu,utilization.memory,memory.total,
memory.free,memory.used --format=csv

Skonfiguruj układ danych

Podczas pracy z danymi, które zawierają informacje o kanale (np. obrazy), zoptymalizuj format układu danych, aby preferować kanały jako ostatnie (NHWC nad NCHW).

Formaty danych ostatniego kanału poprawiają wykorzystanie rdzenia Tensor i zapewniają znaczną poprawę wydajności, szczególnie w modelach splotowych w połączeniu z AMP. Układy danych NCHW mogą nadal być obsługiwane przez rdzenie Tensor, ale wprowadzają dodatkowe obciążenie ze względu na automatyczne operacje transpozycji.

Możesz zoptymalizować układ danych, aby preferować układy NHWC, ustawiając data_format="channels_last" dla warstw, takich jak tf.keras.layers.Conv2D , tf.keras.layers.Conv3D i tf.keras.layers.RandomRotation .

Użyj tf.keras.backend.set_image_data_format , aby ustawić domyślny format układu danych dla interfejsu API zaplecza Keras.

Zmaksymalizuj pamięć podręczną L2

When working with NVIDIA® GPUs, execute the code snippet below before the training loop to max out the L2 fetch granularity to 128 bytes.

import ctypes

_libcudart = ctypes.CDLL('libcudart.so')
# Set device limit on the current device
# cudaLimitMaxL2FetchGranularity = 0x05
pValue = ctypes.cast((ctypes.c_int*1)(), ctypes.POINTER(ctypes.c_int))
_libcudart.cudaDeviceSetLimit(ctypes.c_int(0x05), ctypes.c_int(128))
_libcudart.cudaDeviceGetLimit(pValue, ctypes.c_int(0x05))
assert pValue.contents.value == 128

Configure GPU thread usage

The GPU thread mode decides how GPU threads are used.

Set the thread mode to gpu_private to make sure that preprocessing does not steal all the GPU threads. This will reduce the kernel launch delay during training. You can also set the number of threads per GPU. Set these values using environment variables.

import os

os.environ['TF_GPU_THREAD_MODE']='gpu_private'
os.environ['TF_GPU_THREAD_COUNT']='1'

Configure GPU memory options

In general, increase the batch size and scale the model to better utilize GPUs and get higher throughput. Note that increasing the batch size will change the model's accuracy so the model needs to be scaled by tuning hyperparameters like the learning rate to meet the target accuracy.

Also, use tf.config.experimental.set_memory_growth to allow GPU memory to grow to prevent all the available memory from being fully allocated to ops that require only a fraction of the memory. This allows other processes which consume GPU memory to run on the same device.

To learn more, check out the Limiting GPU memory growth guidance in the GPU guide to learn more.

Miscellaneous

  • Increase the training mini-batch size (number of training samples used per device in one iteration of the training loop) to the maximum amount that fits without an out of memory (OOM) error on the GPU. Increasing the batch size impacts the model's accuracy—so make sure you scale the model by tuning hyperparameters to meet the target accuracy.

  • Disable reporting OOM errors during tensor allocation in production code. Set report_tensor_allocations_upon_oom=False in tf.compat.v1.RunOptions .

  • For models with convolution layers, remove bias addition if using batch normalization. Batch normalization shifts values by their mean and this removes the need to have a constant bias term.

  • Use TF Stats to find out how efficiently on-device ops run.

  • Use tf.function to perform computations and optionally, enable the jit_compile=True flag ( tf.function(jit_compile=True ). To learn more, go to Use XLA tf.function .

  • Minimize host Python operations between steps and reduce callbacks. Calculate metrics every few steps instead of at every step.

  • Keep the device compute units busy.

  • Send data to multiple devices in parallel.

  • Consider using 16-bit numerical representations , such as fp16 —the half-precision floating point format specified by IEEE—or the Brain floating-point bfloat16 format.

Additional resources

Known limitations

Profiling multiple GPUs on TensorFlow 2.2 and TensorFlow 2.3

TensorFlow 2.2 and 2.3 support multiple GPU profiling for single host systems only; multiple GPU profiling for multi-host systems is not supported. To profile multi-worker GPU configurations, each worker has to be profiled independently. From TensorFlow 2.4 multiple workers can be profiled using the tf.profiler.experimental.client.trace API.

CUDA® Toolkit 10.2 or later is required to profile multiple GPUs. As TensorFlow 2.2 and 2.3 support CUDA® Toolkit versions only up to 10.1, you need to create symbolic links to libcudart.so.10.1 and libcupti.so.10.1 :

sudo ln -s /usr/local/cuda/lib64/libcudart.so.10.2 /usr/local/cuda/lib64/libcudart.so.10.1
sudo ln -s /usr/local/cuda/extras/CUPTI/lib64/libcupti.so.10.2 /usr/local/cuda/extras/CUPTI/lib64/libcupti.so.10.1