SparseCore to specjalistyczny procesor kafelkowy zaprojektowany z myślą o wysokiej wydajności przyspieszania zadań, które obejmują nieregularny, rzadki dostęp do pamięci i obliczenia, zwłaszcza w przypadku dużych zbiorów danych przechowywanych w pamięci o wysokiej przepustowości (HBM). Sprawdza się doskonale w przypadku zadań takich jak wyszukiwanie osadzeń, ale jego możliwości obejmują też przyspieszanie różnych innych dynamicznych i rzadkich zbiorów zadań.
1. Wprowadzenie do SparseCore
Najważniejsze cechy architektury:
- Architektura kafelkowa: obejmuje wiele kafelków obliczeniowych (każdy kafelek to kompletna jednostka przepływu danych z własną pamięcią lokalną i jednostką przetwarzania), co umożliwia przetwarzanie równoległe.
- Dynamiczne wykonywanie: natywnie obsługuje przepływ sterowania zależny od danych i dostęp do pamięci, co ma kluczowe znaczenie w przypadku danych rzadkich.
- Przetwarzanie wektorowe: wykorzystuje zadania z małymi wektorami (8-elementowymi lub 16-elementowymi w zależności od wersji sprzętu) do wydajnego obliczania.
- Centralne sterowanie: jeden sekwencer SparseCore koordynuje zadania na wszystkich kafelkach, zapewniając zsynchronizowane działanie.
- Obsługa podsumowywania danych: obejmuje specjalistyczne operacje międzyścieżkowe przydatne w przypadku zadań takich jak sortowanie, filtrowanie i sumy prefiksów.
- Hierarchia pamięci: strategicznie wykorzystuje pamięć HBM do przechowywania dużych zbiorów danych i lokalną pamięć podręczną (SPMEM) do przechowywania często używanych danych, co znacznie zmniejsza opóźnienie HBM.
Specyfikacja w skrócie:
| Atrybut | TPU v4 | TPU v5p | Trillium |
|---|---|---|---|
| SparseCores/Chip | 4 | 4 | 2 |
| Tiles/SparseCore | 16 | 16 | 16 |
| Szerokość SIMD | 8 | 8 | 8 (F32) 16 (BF16) |
| Pojemność pamięci HBM | 32 GiB | 96 GiB | 32 GiB |
2. Przetwarzanie wstępne hosta SparseCore
Skuteczne przygotowanie danych ma kluczowe znaczenie dla wydajności SparseCore, dlatego wstępne przetwarzanie na hoście odgrywa tak ważną rolę. Obejmuje kilka kluczowych funkcji:
- Transformacja danych:
- Zastosuj niezbędne przekształcenia do nieprzetworzonych danych wejściowych.
- zarządzać przekształceniami identyfikatorów, co jest szczególnie ważne w przypadku łączenia cech lub tabel.
- Przekonwertuj dane wejściowe na format rzadki COO (Coordinate), który został szczegółowo opisany w następnej sekcji.
- Podziel dane, aby efektywnie rozprowadzić je między różnymi rdzeniami SparseCore dostępnymi na chipie.
- Weryfikacja limitu:
- Sprawdź, czy charakterystyka danych wejściowych (np. liczba identyfikatorów) jest zgodna z wstępnie zdefiniowanymi limitami operacyjnymi SparseCore, takimi jak
max_ids_per_partitionimax_unique_ids_per_partition. - Jeśli dane wejściowe przekraczają te limity, warstwa wstępnego przetwarzania na hoście może spróbować podzielić dane na mniejsze mini-partie, które mieszczą się w tych ograniczeniach.
- Sprawdź, czy charakterystyka danych wejściowych (np. liczba identyfikatorów) jest zgodna z wstępnie zdefiniowanymi limitami operacyjnymi SparseCore, takimi jak
- Przenoszenie danych:
- Skutecznie kopiuje przetworzone i zweryfikowane dane do pamięci HBM (High Bandwidth Memory) jednostki TPU, aby przygotować je do wykonania przez SparseCore.
Informacje o układaniu tabel:
Łączenie tabel to ważna technika optymalizacji, w której wiele tabel z wektorami jest logicznie łączonych w celu zwiększenia wydajności wyszukiwania wektorów. Ten proces jest zwykle obsługiwany automatycznie przez bazową platformę ML.
- Nakładanie się funkcji: występuje, gdy kilka różnych funkcji korzysta z tej samej tabeli zagnieżdżania. Typowym przykładem jest używanie jednego słownika osadzania do różnych cech kategorialnych, takich jak kody pocztowe z różnych kontekstów.
- Łączenie tabel: w tym scenariuszu łączy się ze sobą kilka różnych tabel z osadzonymi elementami. Tabele, które mają ten sam wymiar przestrzeni wektorów dystrybucyjnych i konfigurację optymalizatora, są często grupowane.
Główną zaletą łączenia tabel jest tworzenie większego efektywnego rozmiaru partii dla operacji na tych połączonych tabelach. Zmniejsza to obciążenie obliczeniowe i może skutecznie ukrywać opóźnienia w komunikacji między układami (ICI). Aby uzyskać optymalną wydajność, zalecamy umiarkowaną liczbę tabel ułożonych jedna na drugiej (zwykle od 5 do 100).
3. Konwersja na tensory COO
Zanim dane będą mogły być przetwarzane przez SparseCore, są zwykle przekształcane w format rzadkiej macierzy współrzędnych (COO). Format COO to sposób na efektywne przedstawianie macierzy rzadkich, zwykle za pomocą 3 tablic:
row_ids: tablica zawierająca indeksy wierszy dla każdego elementu o wartości różnej od zera. W kontekście przetwarzania wsadowego często odpowiada to wymiarowi partii.col_ids: tablica zawierająca indeksy kolumn dla każdego elementu o wartości różnej od zera. W przypadku osadzania są to często wartości funkcji lub identyfikatora.values(opcjonalnie): tablica zawierająca rzeczywiste wartości niezerowych elementów na odpowiednich współrzędnych (row,col). W przypadku obliczeń limitów (omówionych później) związanych z liczbą identyfikatorów te wartości (wzrosty) często nie są brane pod uwagę.
Przykład:
Rozważmy rzadką macierz wejściową reprezentującą partie identyfikatorów:
[
[id_A], // Sample 0
[id_A, id_B, id_C], // Sample 1
[id_B, id_B, id_D], // Sample 2 (note duplicate id_B)
]
Po przekształceniu do formatu COO (i ewentualnym usunięciu zduplikowanych identyfikatorów w ramach tej samej próbki):
row_ids = [0, 1, 1, 1, 2, 2]
col_ids = [id_A, id_A, id_B, id_C, id_B, id_D]
Ta konwersja ma kluczowe znaczenie dla sposobu przetwarzania i dystrybucji pracy przez SparseCore.
W szczególności col_ids mają kluczowe znaczenie dla określania, do której partycji SparseCore należy identyfikator, co umożliwia wydajne dzielenie i wyszukiwanie.
4. SparsecoreConfig: interfejs API wysokiego poziomu
Interfejsy API do osadzania specyficzne dla platformy:
- JAX https://github.com/jax-ml/jax-tpu-embedding
- TensorFlow https://www.tensorflow.org/recommenders/api_docs/python/tfrs/layers/embedding/TPUEmbedding
- Keras https://keras.io/keras_rs/api/embedding_layers/distributed_embedding
Właściwość SparsecoreConfig lub równoważne mechanizmy, takie jak flagi XLA, służy jako interfejs wysokiego poziomu do kontrolowania szerokiego zakresu zachowań SparseCore. Dokładne zrozumienie tych parametrów jest niezbędne do skutecznego dostrajania wydajności i zapewnienia prawidłowego działania modeli.
disable_table_stacking: bool = False- Wyjaśnienie: ta flaga określa, czy automatyczne układanie tabel jest zapobiegać układaniu tabel przez platformę, co może prowadzić do obniżenia wydajności z powodu zwiększonego obciążenia i mniejszej możliwości ukrywania opóźnienia połączenia między układami (ICI).
- Domyślne:
False(co oznacza, że układanie tabel jest domyślnie włączone tam, gdzie obsługuje to platforma).
max_ids_per_chip_per_sample: int = 64- Wyjaśnienie: ten parametr określa globalny górny limit łącznej liczby identyfikatorów osadzania, które pojedynczy układ może przetworzyć z jednej próbki w partii wejściowej, po zsumowaniu we wszystkich tabelach. Jest to mechanizm zarządzania zasobami na poziomie układu scalonego, zanim zostaną uwzględnione bardziej szczegółowe limity dotyczące poszczególnych tabel lub partycji. Dostosowanie tej wartości zależy zwykle od konkretnych cech modelu i ogólnej pojemności systemu.
- Domyślny:
64.
max_ids_per_table: Optional[Dict[str, int]] = None- Wyjaśnienie: ten parametr określa maksymalną liczbę identyfikatorów osadzania (które mogą zawierać duplikaty), które mogą być przetwarzane dla każdej tabeli logicznej, z uwzględnieniem wszystkich jej partycji we wszystkich rdzeniach SparseCore. Jest to szerszy limit niż
max_ids_per_partition. Jeśli tabelaTjest podzielona naPpartycji, ten limit dotyczy sumy identyfikatorów kierowanych do wszystkich partycji P. Często jest to związane zmax_ids_per_partition_per_samplei ogólną wielkością partii. - Ustawienie: zwykle konfigurowane za pomocą pliku limitów (np. za pomocą flagi
xla_sparse_core_max_ids_file), w którym zdefiniowanomax_ids_per_partition. To pojęcie na poziomie tabeli jest metodą ustawiania limitów na poziomie partycji (max_idsimax_uniques). - Domyślna:
None(wartość może być wywnioskowana z limitów poszczególnych partycji lub innych konfiguracji, jeśli nie została podana wprost).
- Wyjaśnienie: ten parametr określa maksymalną liczbę identyfikatorów osadzania (które mogą zawierać duplikaty), które mogą być przetwarzane dla każdej tabeli logicznej, z uwzględnieniem wszystkich jej partycji we wszystkich rdzeniach SparseCore. Jest to szerszy limit niż
max_unique_ids_per_table: Optional[Dict[str, int]] = None- Wyjaśnienie: analogiczny do parametru
max_ids_per_table, ale ten parametr określa maksymalną liczbę unikalnych identyfikatorów dla każdej tabeli logicznej. Jest to kluczowe ustawienie, które pozwala odpowiednio określić rozmiar buforów na urządzeniu używanych podczas przetwarzania unikalnych identyfikatorów i kolejnych operacji na wektorach. - Ustawienie: zwykle zdefiniowane w pliku limitów lub pochodzące z
max_unique_ids_per_partition_per_sample. - Domyślny:
None.
- Wyjaśnienie: analogiczny do parametru
allow_id_dropping: bool = False- Wyjaśnienie: ta wartość logiczna steruje usuwaniem identyfikatorów, gdy liczba identyfikatorów napotkanych w danych wejściowych (obserwowane limity) przekracza limity ustawione podczas kompilacji (np.
max_ids_per_partition).- Jeśli
True: identyfikatory, które spowodowałyby przekroczenie limitów, są cicho odrzucane. Zwykle identyfikatory w partycji są przetwarzane w kolejności posortowanej, a każdy identyfikator, który spowodowałby przekroczenie limitu dla wyznaczonej mini-partii, jest odrzucany. Umożliwia to dalsze wykonywanie programu, ale może mieć negatywny wpływ na dokładność modelu. - Jeśli
False: wystąpi błąd, a proces prawdopodobnie zakończy się, jeśli zaobserwowane limity przekroczą skompilowane limity. Takie podejście zapewnia przetwarzanie wszystkich danych, ale wymaga bardziej konserwatywnego skonfigurowania limitów.
- Jeśli
- Domyślne:
False(powoduje błąd przepełnienia zamiast cichego usuwania danych).
- Wyjaśnienie: ta wartość logiczna steruje usuwaniem identyfikatorów, gdy liczba identyfikatorów napotkanych w danych wejściowych (obserwowane limity) przekracza limity ustawione podczas kompilacji (np.
initialize_tables_on_host: bool = True- Wyjaśnienie: ta flaga określa, czy tabele osadzania są inicjowane na procesorze hosta przed przeniesieniem ich do pamięci o wysokiej przepustowości (HBM) procesora TPU. Standardową praktyką jest inicjowanie tabel na hoście. Ustawienie tej wartości na
Truejest zgodne z tą konwencją. Jeśli wartość tego parametru toFalse, oznacza to mechanizm inicjowania na urządzeniu, który może mieć inne konsekwencje dla wydajności lub określone wymagania wstępne dotyczące inicjowania.
- Wyjaśnienie: ta flaga określa, czy tabele osadzania są inicjowane na procesorze hosta przed przeniesieniem ich do pamięci o wysokiej przepustowości (HBM) procesora TPU. Standardową praktyką jest inicjowanie tabel na hoście. Ustawienie tej wartości na
enable_fast_table_initialization: bool = False- Wyjaśnienie: inicjuje tabele bezpośrednio na TPU. Może to skrócić czas uruchamiania modelu.
5. Potokowe przetwarzanie danych w celu zwiększenia wydajności
Potokowanie to technika optymalizacji wydajności, która umożliwia jednoczesne wykonywanie operacji na rdzeniu TensorCore (TC) i rdzeniu SparseCore (SC). Dzięki nakładaniu się tych obliczeń ogólna przepustowość może się znacznie zwiększyć.
- Mechanizm: w standardowym kroku trenowania, który obejmuje wyszukiwanie rzadkich wektorów osadzania (obsługiwane przez SC) i obliczenia warstw gęstych (obsługiwane przez TC), potokowe przetwarzanie umożliwia SC wykonywanie swojej części kroku
i(np. przejścia w przód lub w tył), podczas gdy TC jednocześnie przetwarza inną część tego samego krokui, a nawet części sąsiednich kroków, takich jaki-1lubi+1. - Wpływ na gradienty: SparseCore może działać na „nieaktualnych” gradientach.
Na przykład gradienty obliczone podczas fazy propagacji wstecznej kroku
imogą nie być w pełni zaktualizowane i widoczne dla SC aż do krokui+2. - Kompromis między wydajnością a wartościami liczbowymi: to nakładające się na siebie wykonywanie może znacznie przyspieszyć działanie, potencjalnie nawet 2-krotnie skracając czas kroku urządzenia. Jednak niewielkie zmiany w wartościach liczbowych (embedding_weights) wynikające z użycia nieaktualnych gradientów mogą wpływać na zachowanie zbieżności modelu lub ostateczną osiągniętą dokładność. Akceptowalność tego kompromisu w dużym stopniu zależy od modelu i często wymaga weryfikacji empirycznej.
- Flaga sterująca: potokowaniem można sterować za pomocą parametru
tf_xla_disable_full_embedding_pipelining. Ustawienie tej flagi natruewyłącza pełne przetwarzanie potokowe (nakładające się obliczenia TensorCore i SparseCore), a ustawienie jej nafalse(lub jeśli semantyka flagi implikuje włączenie, gdy wartość to false) aktywuje je.
Koncepcyjny przepływ potokowy:
Bez potokowania (uproszczony przepływ sekwencyjny):
Loop: SC/F_i -> TC/F_i -> TC/B_i -> SC/B_iZ potokowym przetwarzaniem (uproszczony przepływ nakładający się na siebie):
Time -> Step i: SC/F_i | TC/F_i | TC/B_i | SC/B_i Step i+1: SC/F_i+1| TC/F_i+1| TC/B_i+1| SC/B_i+1Uwaga: rzeczywiste etapy potokowego przetwarzania danych zaimplementowane w sprzęcie i kompilatorze mogą być bardziej złożone i często obejmują pętle wstępne, główne pętle wykonywania i pętle końcowe, które zarządzają zależnościami danych i zapewniają poprawność.
6. Rola XLA
XLA (Accelerated Linear Algebra) to kompilator specjalizowany, który tłumaczy wykresy obliczeniowe wysokiego poziomu, zwykle z platform takich jak TensorFlow, na wysoce zoptymalizowany kod maszynowy dostosowany do jednostek TPU. Obejmuje to generowanie instrukcji dla operacji przeznaczonych dla SparseCore.
Kluczowe funkcje w kontekście SparseCore:
- Kompilacja operacji rzadkich: XLA odpowiada za kompilowanie operacji wyszukiwania osadzania (takich jak
SparseDenseMatmulOp) i innych obliczeń rzadkich do programów SparseCore niskiego poziomu, które można wykonywać. - Integracja limitów: wykorzystuje skonfigurowane limity operacyjne (np.
max_ids_per_partition,max_unique_ids_per_partition, często podawane w pliku limitów określonym przez flagi takie jakxla_sparse_core_max_ids_file), aby statycznie określać rozmiary buforów pamięci na urządzeniu i przydzielać je, zwłaszcza w ramach SPMEM. - Ukierunkowane optymalizacje: XLA przeprowadza zestaw optymalizacji zaprojektowanych specjalnie z myślą o architekturze SparseCore. Mogą one obejmować planowanie instrukcji, przekształcenia układu pamięci i łączenie operacji w celu maksymalizacji wydajności.
- Sterowanie za pomocą flag: wiele aspektów działania SparseCore, parametrów dostrajania i strategii optymalizacji jest udostępnianych i kontrolowanych za pomocą flag XLA (np.
xla_sparse_core_estimate_max_idsdo szacowania limitów lubxla_sc_detect_nando debugowania).
Stan open source:
Obecnie implementacja Sparsecore jest wewnętrzna i obsługiwana za pomocą libtpu.so.
Raportowanie błędów i diagnostyka:
Błędy kompilacji związane z konfiguracjami SparseCore lub ograniczeniami zasobów często objawiają się jako XLA:TPU błędy kompilacji. Te komunikaty o błędach mogą dostarczać cennych informacji o problemach, takich jak zbyt wysokie limity w stosunku do dostępnej pamięci SPMEM lub używanie nieobsługiwanych konfiguracji.
7. Jak limity przekładają się na tabele w SparseCore
W przypadku SparseCore „limity” to podstawowe parametry konfiguracji, które odnoszą się głównie do 2 ustawień na partycję dla każdej tabeli, która jest podzielona (rozproszona) między dostępne rdzenie SparseCore:
max_ids_per_partition: określa maksymalną liczbę wszystkich identyfikatorów (w tym duplikatów), które pojedynczy SparseCore ma wysyłać do określonej partycji danej tabeli lub przetwarzać w jej przypadku w ramach jednego kroku obliczeniowego.max_unique_ids_per_partition: określa maksymalną liczbę unikalnych identyfikatorów, które pojedynczy SparseCore ma wysyłać do lub przetwarzać na potrzeby
Przekształcanie w fizyczny układ tabeli i przetwarzanie:
- Strategia dzielenia tabeli na fragmenty: tabele z osadzaniem są zwykle dzielone na fragmenty za pomocą operacji modulo we wszystkich rdzeniach SparseCore w systemie. Oznacza to, że każdy SparseCore odpowiada za odrębny podzbiór słownictwa (wierszy) każdej tabeli. Identyfikator
jjest zwykle przypisywany doSparseCore_kna podstawie formuły, np.k = j % num_total_sparse_cores. - Definicja „partycji”: w tym kontekście „partycja” odnosi się do konkretnego segmentu tabeli osadzania, w którym wyszukiwaniem zajmuje się pojedynczy SparseCore.
- Alokacja bufora SPMEM: te limity są używane przez kompilator XLA do statycznego określania rozmiaru i alokowania buforów w pamięci podręcznej na urządzeniu (SPMEM). Bufory są wymiarowane w taki sposób, aby wszystkie niezbędne dane związane z identyfikatorami w danej partycji (do określonych limitów
max_idsimax_unique_ids) można było załadować do pamięci SPMEM w celu przetworzenia. Jest to szczególnie ważne w przypadku obliczeń nieelementowych, takich jak redukcja zduplikowanych identyfikatorów w partycji (np. podczas tworzenia skompresowanej reprezentacji wiersza rzadkiego (CSR)), gdzie cały odpowiedni zbiór danych dla identyfikatorów tej partycji musi być łatwo dostępny w pamięci podręcznej. Limity skompilowane a obserwowane:
- Obserwowane limity: rzeczywista liczba identyfikatorów napotkanych w każdej partycji w czasie działania programu na podstawie przetwarzanych danych wejściowych.
- Jeśli zaobserwowane limity przekroczą skompilowane limity, może to spowodować utratę identyfikatora (jeśli włączona jest funkcja
allow_id_dropping) lub błędy.
Obliczanie limitów: proces określania odpowiednich limitów obejmuje dokładną analizę rozkładu danych wejściowych. W przypadku dowolnej tabeli (nazwijmy ją
T1, która może być częścią większej tabeli warstwowejT):- Partia danych wejściowych (np. 2D
SparseTensoro kształcie[BatchSize, MaxSequenceLength]) jest początkowo dzielona między dostępne rdzenie SparseCore. Jeśli na przykład rdzeń TensorCore jest połączony z 2 rdzeniami SparseCore, każdy z nich może otrzymać podgrupę o kształcie[BatchSize/2, MaxSequenceLength]. - Ta podpartia jest następnie przekształcana w format COO, co daje
row_idsicol_ids. - Zduplikowane identyfikatory w tej samej próbce (czyli wpisy z tymi samymi wartościami
row_idicol_id) są usuwane. - W przypadku każdego pozostałego unikalnego identyfikatora
col_id(w próbce) docelowy SparseCore odpowiedzialny za ten identyfikator jest określany za pomocą reguły dzielenia modulo:target_sc_id = col_id % num_total_sparse_cores. - Prowadzona jest łączna liczba identyfikatorów (
ids_per_sparse_core[target_sc_id]++) i liczba unikalnych identyfikatorów (unique_ids_per_sparse_core[target_sc_id]++po zapewnieniu niepowtarzalności w przypadku konkretnegotarget_sc_id), które są przeznaczone dla każdegotarget_sc_id. - Wartość
max_ids_per_partitionw tabeliT1zostanie ustawiona namax(ids_per_sparse_core_array). - Podobnie
max_unique_ids_per_partitionw przypadku tabeliT1jest ustawiona namax(unique_ids_per_sparse_core_array). - Jeśli tabela
T1jest komponentem tabeli warstwowej, przed zsumowaniem statystyk ze wszystkich tabel składowych do rozkładów identyfikatorów mogą być stosowane dodatkowe przekształcenia, takie jak rotacje lub przesunięcia. Pomaga to w równoważeniu obciążenia między chipami.
- Partia danych wejściowych (np. 2D
Prawidłowe ustawienie tych limitów wymaga zachowania równowagi: niższe limity mogą potencjalnie prowadzić do większej wydajności (ponieważ na każdym etapie trzeba przetwarzać mniej danych, a obciążenie SPMEM jest mniejsze), ale jeśli zostaną ustawione zbyt nisko, mogą powodować nadmierne dzielenie na mini-partie lub niepożądane usuwanie identyfikatorów.
8. Sposób komunikacji poszczególnych rdzeni SparseCore
Komunikacja SparseCore, zwłaszcza w kontekście przetwarzania listy identyfikatorów na potrzeby wyszukiwania wektorów, opiera się na kilku skoordynowanych mechanizmach:
- Dzielenie modulo i niejawne kierowanie:
- Tabele osadzania są dzielone na fragmenty w ramach wszystkich rdzeni SparseCore w systemie.
- Gdy host dostarcza partię danych wejściowych (które są następnie wstępnie przetwarzane do formatu COO, w tym
col_ids), wartośćcol_idjest używana do określenia, który SparseCore jest odpowiedzialny za ten konkretny identyfikator:target_sc_id = col_id % num_total_sparse_cores. - Każdy SparseCore skutecznie otrzymuje i przetwarza tylko podzbiór identyfikatorów, które są mapowane na przypisane do niego partycje słownika. Etap wstępnego przetwarzania na hoście ma kluczowe znaczenie dla przygotowania danych w taki sposób, aby każdy rdzeń SparseCore mógł łatwo identyfikować odpowiednie identyfikatory i na nich działać.
- Dystrybucja danych według hosta:
- Logika wstępnego przetwarzania na hoście dzieli ogólną partię danych wejściowych i rozdziela odpowiednie części
row_idsicol_ids(wraz z powiązanymi cechami lub wagami, jeśli ma to zastosowanie) do pamięci (HBM) bezpośrednio dostępnej dla każdego rdzenia SparseCore lub do wspólnej pamięci HBM, z której rdzenie SparseCore będą pobierać wymagane dane.
- Logika wstępnego przetwarzania na hoście dzieli ogólną partię danych wejściowych i rozdziela odpowiednie części
- Przetwarzanie wewnątrz SparseCore:
- Gdy SparseCore otrzyma wyznaczony zestaw identyfikatorów dla danego podziału tabeli, wykonuje operacje takie jak usuwanie duplikatów tych identyfikatorów i zbieranie odpowiednich wektorów osadzania. Są to głównie obliczenia lokalne wykonywane w obrębie własnych kafelków SparseCore i wykorzystujące lokalną pamięć SPMEM.
- Komunikacja między SparseCore (wszystko do wszystkich):
- Po początkowej fazie przetwarzania (np. wyszukiwaniu osadzeń) można użyć wzorca komunikacji „wszystko do wszystkich”, aby połączyć lub ponownie rozdzielić wyniki między rdzenie SparseCore (np. przed przekazaniem aktywacji do warstwy TensorCore, która oczekuje danych wejściowych odpowiadających wszystkim pierwotnym pozycjom próbki). Jest to niezbędne do odtworzenia pełnego zestawu aktywacji, jeśli pierwotna partia danych wejściowych została rozdzielona na potrzeby przetwarzania równoległego.
- Komunikacja z rdzeniami TensorCore:
- Rdzenie SparseCores komunikują się z rdzeniami TensorCores, aby wysyłać aktywacje osadzania (podczas przejścia w przód) i otrzymywać gradienty (podczas przejścia wstecz). Ta interakcja jest koordynowana przez program skompilowany w XLA i często wykorzystuje HBM jako bufor pośredni. Strategia potokowa (omówiona wcześniej) ma duży wpływ na czas i synchronizację tej komunikacji między SC a TC.
Początkowa „dystrybucja” identyfikatorów do odpowiednich obiektów SparseCore jest w dużej mierze obsługiwana przez schemat dzielenia na fragmenty i kroki wstępnego przetwarzania hosta. Dalsza komunikacja obejmuje działanie SparseCores na danych lokalnych, a potem ewentualnie operacje komunikacji zbiorowej, takie jak all-to-all, jeśli dane muszą być wymieniane globalnie lub zmieniane w kolejności między SparseCores przed dalszym przetwarzaniem przez TensorCores.
9. Zarządzanie pamięcią SparseCore
Każdy rdzeń SparseCore wydajnie zarządza kilkoma różnymi typami pamięci, aby wykonywać obliczenia:
- Pamięć podręczna (SPMEM):
- Nature: stosunkowo mała, ale bardzo szybka lokalna pamięć SRAM, która jest dostępna wyłącznie dla każdego rdzenia SparseCore. Pamiętaj, że SPMEM nie jest pamięcią podręczną. Jej użycie jest wyraźnie zarządzane i koordynowane przez kompilator XLA.
- Cel: SPMEM służy do „okazjonalnego przechowywania danych”. Obejmuje to dane wejściowe, wyjściowe i pośrednie, które są wymagane do ciągłych obliczeń SC. Przechowywanie danych w pamięci SPMEM znacznie zmniejsza duże opóźnienia zwykle związane z dostępem do pamięci HBM.
- Rozmiar: jak wspomnieliśmy w sekcji „Limity”, bufory SPMEM mają statyczny rozmiar określany w czasie kompilacji. Rozmiar jest określany na podstawie parametrów takich jak
max_ids_per_partitionimax_unique_ids_per_partition. To statyczne przydzielanie zapewnia, że w przypadku dowolnej operacji na partycji tabeli (np. zmniejszenia CSR) wszystkie niezbędne dane dotyczące identyfikatorów tej partycji (do określonych limitów) mogą zmieścić się w pamięci SPMEM. - Optymalizacje kompilatora: kompilator XLA zawiera zaawansowane optymalizacje, które pozwalają dokładnie określić, ile danych i które konkretne elementy danych należy umieścić w pamięci SPMEM, aby skutecznie ukryć opóźnienie HBM i zmaksymalizować wydajność.
- Ograniczenie dynamicznej alokacji: kompilator SparseCore nie obsługuje obecnie dynamicznej alokacji pamięci podręcznej. Podkreśla to kluczowe znaczenie statycznego określania rozmiaru przez staranne skonfigurowanie limitów.
- Pamięć o wysokiej przepustowości (HBM):
- Nature: duży, współdzielony zasób pamięci dostępny dla wszystkich rdzeni SparseCore, TensorCore i systemu hosta. Główne tabele z osadzaniem są przechowywane w pamięci HBM.
- Wykorzystanie pamięci stosu: operacje SparseCore często wymagają tymczasowego przechowywania w pamięci HBM wyników pośrednich, które nie mieszczą się w ograniczonej pamięci SPMEM lub muszą być przekazywane między większymi etapami potoku przetwarzania. Wykorzystanie stosu HBM podczas przejść w przód i w tył można oszacować w ten sposób:
- Stos HBM w przypadku przejścia w przód (jedna tabela) ≈ (2 *
feature_width+ 1) *max_unique_nz_per_row*logical_replica_count* 4 bajty - Stos HBM w przypadku propagacji wstecznej (jedna tabela) ≈ 3 *
feature_width*max_unique_nz_per_row*logical_replica_count* 4 bajty
- Stos HBM w przypadku przejścia w przód (jedna tabela) ≈ (2 *
- Wykorzystanie sterty: HBM obsługuje też stertę, którą zarządza host. Stos przechowuje dane takie jak wagi warstw gęstych, stałe używane przez model i wstępnie pobrane dane wejściowe. Wykorzystanie sterty zwykle rośnie wraz z liczbą kroków, dla których host pobiera dane z wyprzedzeniem (kontrolowaną przez flagę
maximum_parallel_iterations). Większe wyprzedzające pobieranie może zwiększyć wydajność, ponieważ nakłada na siebie transfery z hosta na urządzenie i obliczenia na urządzeniu, ale zużywa też więcej pamięci HBM. - Serializacja na potrzeby optymalizacji HBM: flaga
xla_sc_num_serialized_tables_to_optimize_hbmumożliwia kontrolowanie, ile danych z tabel jest przechowywanych w pamięci stosu HBM w danym momencie. Zwiększenie tej liczby powoduje szeregowanie przetwarzania większej liczby tabel, co może zmniejszyć szczytowe wykorzystanie stosu HBM, ale może odbywać się kosztem wydajności ze względu na zmniejszoną równoległość.
- Pamięć wektorowa (VMEM):
- VMEM to lokalna pamięć robocza używana wyłącznie przez rdzenie Tensor. Pamięć VMEM nie jest zarządzana bezpośrednio przez SparseCore, ale jest integralną częścią ekosystemu pamięci, z którym SC wchodzi w interakcje, głównie za pośrednictwem TensorCore.
Ogólna strategia zarządzania pamięcią:
Podstawowa strategia zarządzania pamięcią w SparseCore polega na używaniu małej i szybkiej pamięci SPMEM do przechowywania „gorących” danych, które są aktywnie przetwarzane przez blok SparseCore. Dzięki temu minimalizuje się dostęp do wolniejszej pamięci HBM. Skonfigurowane limity są głównym mechanizmem zapobiegającym przepełnieniu pamięci SPMEM. Pamięć HBM służy do przechowywania dużych tabel z osadzaniem i danych tymczasowych, które przekraczają pojemność pamięci SPMEM lub muszą być udostępniane różnym jednostkom przetwarzającym lub etapom potoku. Kompilator XLA odpowiada za koordynowanie całego przesyłania danych i przydzielania buforów na podstawie tych zasad architektury i skonfigurowanych przez użytkownika limitów.
10. Wąskie gardła wydajności i pamięci
Aby osiągnąć optymalną wydajność SparseCore, musisz dobrze rozumieć potencjalne wąskie gardła i wiedzieć, jak je eliminować. Mogą one wystąpić na hoście, w samym SparseCore lub w jego interakcji z TensorCore.
Typowe wąskie gardła wydajności:
- Wąskie gardło hosta:
- Problem: procesor hosta może nie być w stanie wystarczająco szybko wstępnie przetwarzać danych i przekazywać ich do TPU, co prowadzi do niewystarczającego wykorzystania rdzeni SparseCore i TensorCore. Jest to częste ograniczenie wydajności.
- Środki zaradcze: monitoruj wykorzystanie procesora hosta i wskaźniki potoku wejściowego. Zoptymalizuj procedury wczytywania i wstępnego przetwarzania danych po stronie hosta (zapoznaj się ze wskazówkami dotyczącymi konwersji COO). Dostosuj flagę
maximum_parallel_iterations, aby precyzyjnie dostroić wstępne pobieranie danych.
- Suboptimal TC/SC synchronization (lack of pipelining):
- Problem: jeśli potokowe przetwarzanie danych między rdzeniami TensorCore i SparseCore jest wyłączone lub nie działa wydajnie, jeden z rdzeni może spędzać dużo czasu na oczekiwaniu na drugi, co zmniejsza ogólną przepustowość systemu.
- Ograniczanie skutków: upewnij się, że potokowanie jest włączone (np.
tf_xla_disable_full_embedding_pipelining = falselub jego odpowiednik).
- Wąskie gardła spowodowane limitami:
- Problem:
- Zbyt niskie limity: mogą powodować nadmierne dzielenie na mini-partie (dzielenie partii wejściowych na liczne mniejsze podpartie, aby spełnić rygorystyczne limity). Chociaż zapewnia to poprawność, każdy mini-batch wprowadza pewien narzut przetwarzania, co może spowolnić ogólne wykonanie. Jeśli wartość
allow_id_droppingto „true”, zbyt niskie limity mogą też prowadzić do utraty identyfikatorów, co wpływa na dokładność modelu. - Zbyt wysokie limity (ale nadal mieszczące się w zakresie): bardzo wysokie limity mogą uniemożliwiać przetwarzanie mini-partii, ale mogą niepotrzebnie zwiększać obciążenie pamięci SPMEM, jeśli rzeczywiste charakterystyki danych rzadko zbliżają się do tych wartości szczytowych. Mogą też prowadzić do większego wykorzystania stosu HBM niż jest to konieczne.
- Błędy kompilacji: jeśli skonfigurowane limity wymagają więcej pamięci SPMEM lub HBM niż dostępna pamięć fizyczna, kompilacja się nie powiedzie.
- Zbyt niskie limity: mogą powodować nadmierne dzielenie na mini-partie (dzielenie partii wejściowych na liczne mniejsze podpartie, aby spełnić rygorystyczne limity). Chociaż zapewnia to poprawność, każdy mini-batch wprowadza pewien narzut przetwarzania, co może spowolnić ogólne wykonanie. Jeśli wartość
- Środki zaradcze: sprawdź, czy limity są prawidłowo ustawione.
- Problem:
- Nierównomierny rozkład danych:
- Problem: jeśli niektóre partycje SparseCore stale otrzymują nieproporcjonalnie większą liczbę identyfikatorów w porównaniu z innymi (co wskazuje na słabą dystrybucję identyfikatorów), te przeciążone partycje SparseCore staną się wąskim gardłem wydajności.
- Ograniczanie problemu: losowe mieszanie identyfikatorów podczas przetwarzania małych partii może pomóc w przypadku tabel warstwowych, zwłaszcza tych z „gorącymi” tabelami użytkowników. Dokładnie przeanalizuj rozkłady identyfikatorów, aby ustawić odpowiednie i zrównoważone limity dla poszczególnych tabel.
- Problemy z nakładaniem się tabel:
- Problem:
- Zbyt mało tabel w stosie: może nie wystarczyć do skutecznego ukrycia opóźnienia ICI ani do odpowiedniego zmniejszenia obciążenia przetwarzania.
- Zbyt wiele tabel ułożonych jedna na drugiej: może spowodować utworzenie bardzo dużych tabel logicznych, którymi trudno zarządzać lub które mogą przekraczać dostępne limity zasobów.
- Środki zaradcze:
- Zapewnij optymalną liczbę tabel do układania w stos. Ogólna wskazówka dotycząca układania w stos sugeruje, że optymalna liczba tabel to 5–100.
- Problem:
- Nieefektywne wartości liczbowe lub kwantyzacja:
- Problem: używanie pełnej precyzji FP32, gdy wystarczyłyby formaty o mniejszej precyzji, takie jak BF16 lub skwantowane liczby całkowite (które zapewniają szybsze obliczenia), może być wąskim gardłem wydajności.
- Środki zaradcze: wypróbuj opcje o mniejszej precyzji. Pamiętaj jednak, że kwantyzacja wiąże się z pewnym narzutem i może wymagać starannego dostrojenia parametrów, aby zachować dokładność modelu.
- Nasycenie przepustowości HBM:
- Problem: nadmierne przesyłanie danych do i z pamięci HBM, potencjalnie spowodowane bardzo małymi szerokościami cech (co prowadzi do dużego narzutu związanego z wypełnianiem), nieefektywnymi wzorcami dostępu do pamięci lub bardzo dużą liczbą wyszukiwań, może powodować nasycenie dostępnej przepustowości pamięci HBM.
- Środki zaradcze: zwiększenie liczby TPU może pomóc w przypadku nasycenia przepustowości HBM.
Typowe wąskie gardła pamięci:
- Przepełnienie pamięci SPMEM (błąd kompilacji):
- Problem: jeśli wartości
max_ids_per_partitionimax_unique_ids_per_partitionsą zbyt wysokie, kompilator XLA może nie być w stanie przydzielić wystarczającej ilości pamięci SPMEM, co może powodować błędy kompilacji, np."Fixed size allocations (...) do not fit in TileSpmem (...)". Jeśli dodatkowo termin(sample_count * feature_width) / kNumTiles(gdziekNumTilesto liczba kafelków na SC) jest zbyt duży, aby można było przygotować operandy w pamięci SPMEM kafelka, mogą wystąpić błędy, np."Gather operand too large...". - Środki zaradcze: zmniejsz rozmiar partii lub zwiększ liczbę układów używanych do przetwarzania.
- Problem: jeśli wartości
- Przepełnienie stosu HBM (w czasie działania lub kompilacji):
- Problem: jeśli kombinacja wartości
feature_width,max_unique_nz_per_rowilogical_replica_countprowadzi do wymagań dotyczących pamięci stosu HBM, które przekraczają dostępną pamięć HBM, może to spowodować błędy braku pamięci (OOM) w czasie działania lub podczas kompilacji. - Środki zaradcze: dostosuj flagę
xla_sc_num_serialized_tables_to_optimize_hbm, aby zmniejszyć wykorzystanie stosu HBM przez serializację przetwarzania tabel (zwykle wiąże się to z obniżeniem wydajności).
- Problem: jeśli kombinacja wartości
- Wykorzystanie całej pamięci HBM:
- Problem: spowodowany głównie przez bardzo duże wagi gęstej warstwy, liczne stałe przechowywane w pamięci lub zbyt agresywne wstępne pobieranie danych wejściowych (wysoka wartość
maximum_parallel_iterations). - Środki zaradcze: monitoruj wykorzystanie sterty za pomocą narzędzi takich jak XProf Memory Viewer.
- Problem: spowodowany głównie przez bardzo duże wagi gęstej warstwy, liczne stałe przechowywane w pamięci lub zbyt agresywne wstępne pobieranie danych wejściowych (wysoka wartość
- Dodatkowy margines:
- Problem: tabele wektorów dystrybucyjnych są uzupełniane do rozmiaru 32 bajtów (co odpowiada 8 liczbom zmiennoprzecinkowym) w wymiarze cechy. W konsekwencji małe szerokości cech (np. 1 liczba zmiennoprzecinkowa) powodują znaczny narzut związany z wypełnieniem (np. 7/8 przydzielonego miejsca w buforze to wypełnienie), co prowadzi do marnowania pamięci HBM. Wymiar słownictwa tabel jest również uzupełniany, aby był wielokrotnością liczby rdzeni SparseCore w systemie. W przypadku tabel o odpowiednio dużej liczbie słów ma to jednak zwykle znikomy wpływ.
Ogólne czynniki wpływające na wydajność i pamięć:
- Topologia: liczba dostępnych układów i architektura ich połączeń.
- Rozmiar partii: ma bezpośredni wpływ na
sample_countna SparseCore, co z kolei wpływa na zużycie pamięci i obciążenie obliczeniowe. - Formatowanie danych: zapewnienie wydajnego układu danych na urządzeniu ma kluczowe znaczenie dla optymalnej wydajności.
11. Analizowanie profilu SparseCore
Analiza profilu wydajności to kluczowy krok w identyfikowaniu wąskich gardeł i odkrywaniu możliwości optymalizacji w przypadku zbiorów zadań SparseCore.
- Uzyskiwanie śladu:
- Używaj narzędzi do profilowania, takich jak XProf, aby rejestrować szczegółowe ślady wykonania podczas trenowania modelu lub wnioskowania. Ten ślad będzie zawierać oś czasu operacji wykonywanych na hoście, rdzeniach TensorCore i rdzeniach SparseCore.
- Sprawdź przeglądarkę śladów (np. w XProf lub TensorBoard):
- Aktywność gospodarza: sprawdź aktywność gospodarza. Czy w aktywności TPU występują znaczące luki? Takie luki mogą wskazywać, że host jest wąskim gardłem, ponieważ nie dostarcza danych wystarczająco szybko. Analizowanie skuteczności potoku danych wejściowych.
- Aktywność rdzeni TensorCore (TC) i SparseCore (SC):
- Sprawdź osie czasu wykonania zarówno w przypadku TC, jak i SC. Czy działają równolegle, co wskazuje na efektywne przetwarzanie potokowe? Czy zdarzają się dłuższe okresy, w których jedno urządzenie jest bezczynne, czekając na drugie?
- Określ operacje, które zajmują najwięcej czasu (najdłużej trwające operacje) zarówno na SC, jak i na TC.
- Wizualne dane śledzenia (często przedstawiające kolorowe bloki reprezentujące różne operacje w czasie, np.
TPU:0 SparseCore 1 (pid 1005)) są nieocenione przy wizualnym identyfikowaniu dominujących operacji i okresów bezczynności.
- Analiza czasu kroku: obserwuj ogólny czas kroku i sprawdzaj, jak jest on rozłożony lub podzielony między przetwarzanie na hoście, obliczenia SC i obliczenia TC.
- Analiza pamięci (XProf Memory Viewer):
- Wykorzystanie sterty: użyj narzędzi takich jak karta „Memory Viewer” w XProf, aby sprawdzić wykorzystanie sterty HBM. Może to pomóc określić, czy duże wagi modelu, stałe lub zbyt agresywne wstępne pobieranie danych wejściowych nie zużywają nadmiernej ilości pamięci HBM. Włączenie flag takich jak
--vmodule=best_fit_allocator=1może zapewnić dzienniki szczytowego wykorzystania sterty. - Wykorzystanie stosu (pośrednie): bezpośrednie profilowanie stosu HBM może być skomplikowane, ale jeśli napotkasz błędy braku pamięci, a wykorzystanie sterty wydaje się rozsądne, to wyczerpanie stosu HBM (często z powodu zbyt dużych limitów lub szerokości funkcji) jest bardzo prawdopodobne. Pomocne w tym mogą być podane wzory dotyczące wykorzystania stosu HBM.
- Wykorzystanie sterty: użyj narzędzi takich jak karta „Memory Viewer” w XProf, aby sprawdzić wykorzystanie sterty HBM. Może to pomóc określić, czy duże wagi modelu, stałe lub zbyt agresywne wstępne pobieranie danych wejściowych nie zużywają nadmiernej ilości pamięci HBM. Włączenie flag takich jak
- Szukaj konkretnych wzorców:
- Mini-batching: jeśli limity są często przekraczane, w śladzie możesz zauważyć dowody na mini-batching (np. większą niż oczekiwana liczbę mniejszych operacji SC w przypadku globalnego rozmiaru pakietu). Można to często wywnioskować z logów lub obserwując liczbę wywołań określonych operacji.
- Usuwanie identyfikatorów: jeśli usuwanie identyfikatorów jest włączone i występuje, dzienniki systemowe mogą zawierać informacje na ten temat. Byłby to też wyraźny sygnał, że skonfigurowane limity są zbyt restrykcyjne w stosunku do danych wejściowych.
- Czas kompilacji: wydłużony czas ponownej kompilacji, zwłaszcza jeśli włączona jest optymalizacja na podstawie opinii (FDO) i często dostosowuje limity, może znacznie wydłużyć ogólny czas trenowania.
- Korelacja z flagami i konfiguracją:
- Powiąż zaobserwowane w profilu zachowanie z konfiguracjami SparseCore (ustawienia w plikach limitów, flagi XLA). Jeśli np. wartość
xla_sc_num_serialized_tables_to_optimize_hbmjest wysoka, możesz się spodziewać wolniejszej wydajności SC, ale mniejszego zużycia pamięci HBM.
- Powiąż zaobserwowane w profilu zachowanie z konfiguracjami SparseCore (ustawienia w plikach limitów, flagi XLA). Jeśli np. wartość
- Proces iteracyjny:
- Profilowanie jest często iteracyjnym procesem ulepszania. Wprowadź konkretną zmianę (dostosuj limit, włącz lub wyłącz funkcję), utwórz nowy profil, a następnie porównaj go z poprzednim, aby zobaczyć wpływ wprowadzonej modyfikacji.
12. Ogólne flagi debugowania
Możesz włączyć kilka flag, które pomogą w debugowaniu problemów związanych z wykonywaniem SparseCore. Warto pamiętać, że włączenie tych kontroli często wiąże się z obniżeniem wydajności, dlatego zwykle należy je wyłączać w przypadku uruchomień produkcyjnych.
- Weryfikacja tożsamości (poza zakresem):
- Flaga:
xla_sparse_core_enable_id_bound_check = true - Cel: umożliwia sprawdzanie systemu hosta pod kątem identyfikatorów osadzania w danych wejściowych, które wykraczają poza zakres prawidłowego słownictwa zdefiniowany dla danej tabeli osadzania. Pomaga to wykrywać problemy związane z nieprawidłowymi lub uszkodzonymi danymi wejściowymi.
- Flaga:
- Sprawdzanie wartości NaN:
- Flaga:
xla_sc_detect_nan = true - Cel: umożliwia wykrywanie wartości NaN (Not a Number) w danych zmiennoprzecinkowych przetwarzanych na SparseCore. Jeśli w danych wejściowych lub wyjściowych różnych etapów kompilacji zostanie wykryta wartość NaN, ta flaga spowoduje zgłoszenie błędu. Takie błędy zwykle zawierają informacje o tym, gdzie wystąpiła wartość NaN.
- Flaga:
- Sprawdzanie granic (dostępu do pamięci):
- Flaga:
xla_sc_assert_level=bounds - Cel: ta flaga włącza narzędzie w stylu ASAN (AddressSanitizer), które przepisuje instrukcje dostępu do pamięci (takie jak wczytywanie/zapisywanie VMEM i operacje DMA), aby uwzględniać dynamiczne sprawdzanie. Te kontrole sprawdzają, czy dostęp do pamięci mieści się w przydzielonych granicach docelowego regionu pamięci.
- Działanie: jeśli zostanie wykryty dostęp do pamięci poza zakresem, wykonanie zakończy się niepowodzeniem.
- Uwaga: ten moduł sprawdzający może generować fałszywe alarmy, np. z powodu złożonych wzorców dostępu z krokiem, które nie są w pełni przez niego rozumiane. To przekształcenie jest stosowane na późnym etapie procesu kompilacji backendu.
- Flaga:
- Sprawdzanie bufora (uszkodzenie pamięci):
- Flagi:
xla_tpu_buffer_contents_sanitizer_config='cores_to_sanitize: [TC, SC_SCS, SC_TILE], sanitizer_mode: LOCAL_ONLY'xla_tpu_verify_launch_id_across_cores=true
- Cel: te flagi pomagają zapobiegać przypadkowemu uszkodzeniu lub nadpisaniu buforów pamięci przez niezwiązane z nimi operacje. Sanitizer bufora sprawdza zawartość buforów, aby upewnić się, że nie zmieniają się w nieoczekiwany sposób.
- Flagi:
13. Obsługa kwantyzacji
Funkcja SparseDenseMatmulOp w SparseCore została zaprojektowana do obsługi operacji na tabelach zagnieżdżania z użyciem 32-bitowych liczb zmiennoprzecinkowych (FP32) i liczb całkowitych. Chociaż trenowanie modelu zwykle odbywa się z użyciem precyzji FP32 w przypadku tabel osadzania, można zastosować kwantyzację po trenowaniu (PTQ). PTQ umożliwia używanie do wnioskowania typów danych o niższej precyzji (np. 8-bitowych liczb całkowitych), co może zwiększyć wydajność i zmniejszyć zużycie pamięci.
Symulowana kwantyzacja:
SparseDenseMatmulOp można skonfigurować tak, aby wykonywał „symulowaną kwantyzację”. W tym trybie działania wektory dystrybucyjne są najpierw kwantyzowane do niższej precyzji, a następnie dekwantyzowane z powrotem do wyższej precyzji (np. FP32), zanim zostaną użyte w dalszych obliczeniach. Ta technika umożliwia trenowanie modeli z uwzględnieniem wpływu szumu kwantyzacji. Trenowanie z symulowaną kwantyzacją może zwiększyć dokładność końcowego modelu, gdy zostanie on w pełni skwantyzowany na potrzeby wnioskowania.
Atrybuty konfiguracji dla SparseDenseMatmulOp (na potrzeby kwantyzacji):
quantization_config_num_buckets = 256- Ten atrybut określa liczbę odrębnych zasobników lub poziomów, na które zostanie skwantyzowana 32-bitowa liczba zmiennoprzecinkowa. Na przykład podczas kwantyzacji do 8-bitowych liczb całkowitych zwykle określa się 2^8 =256 zasobników.
quantization_config_low = -X.X- Ten atrybut określa minimalną wartość zmiennoprzecinkową w zakresie kwantyzacji. Wszystkie wartości wejściowe poniżej określonego minimum zostaną podczas kwantyzacji przycięte do tej wartości.
quantization_config_high = Y.Y- Ten atrybut określa maksymalną wartość zmiennoprzecinkową w zakresie kwantyzacji. Wszystkie wartości wejściowe powyżej określonego maksimum zostaną podczas kwantyzacji przycięte do tej wartości.
Interakcja z wartościami liczbowymi i potokami:
Zachowanie numeryczne modelu może się zmieniać w zależności od tego, czy potokowe przetwarzanie danych między rdzeniami TensorCore i SparseCore jest włączone. Jeśli potokowe przetwarzanie danych jest aktywne, gradienty przetwarzane przez SparseCore mogą być „nieaktualne” (pochodzić z poprzedniej iteracji). Może to wpływać na proces kwantyzacji i potencjalnie na dynamikę trenowania modelu lub jego ostateczną dokładność.
14. Nadchodzące funkcje i ostatnie ulepszenia
Ekosystem SparseCore jest stale rozwijany i ulepszany.
Mapa:
- Mini-batching w wymiarze próbki:
- Jest to planowana funkcja uzupełniająca dotychczasowe możliwości tworzenia mini-batchy o wymiarze słownictwa.
- Umożliwiłoby to dalsze dzielenie danych wejściowych osadzania wzdłuż wymiaru próbki. Można to osiągnąć, wprowadzając pętle na urządzeniu, które mogą filtrować i przetwarzać wyszukiwania z podzbioru próbek naraz. Ta funkcja może być przydatna do zarządzania bardzo dużą liczbą identyfikatorów próbek lub do poprawy równoważenia obciążenia między jednostkami przetwarzania.
- Ulepszona obsługa osadzania z mniej niż 8 liczbami całkowitymi w wierszu (małe szerokości cech):
- Obecna struktura często wykorzystuje znaczne dopełnienie w przypadku szerokości funkcji osadzania mniejszych niż 8 liczb zmiennoprzecinkowych (co odpowiada 32 bajtów). To dopełnienie może prowadzić do marnowania pamięci HBM i potencjalnego niewykorzystania zasobów obliczeniowych. Przyszłe ulepszenia mają na celu zmniejszenie tej nieefektywności w przypadku tabel o małych wymiarach funkcji.
Najnowsze ulepszenia:
- Przenoszenie operandów operacji zbierania do pamięci HBM:
- Ta optymalizacja pomaga zmniejszyć obciążenie wspólnej pamięci podręcznej (SPMEM), ponieważ umożliwia przechowywanie niektórych danych wejściowych lub wyjściowych operacji zbierania w większej pamięci HBM.
- Zmniejszenie wykorzystania pamięci stosu:
- Wprowadziliśmy ulepszenia, które mają na celu zmniejszenie zużycia pamięci stosu HBM podczas operacji SparseCore, najlepiej bez negatywnego wpływu na ogólną wydajność lub przepustowość.
Te ulepszenia mają na celu zwiększenie wydajności, efektywności pamięci i elastyczności operacyjnej SparseCore w przypadku jeszcze szerszego zakresu zadań wymagających rzadkich danych.