Aufmerksamkeit – chatgpz.de – KI-Tools & Praxiswissen https://chatgpz.de Unabhängige Tests, Anleitungen und Hintergründe zu KI-Tools. Wed, 17 Jun 2026 03:07:24 +0000 de-DE hourly 1 https://wordpress.org/?v=6.4.2 234900186 So erstellen Sie speichereffiziente Transformer mit xFormers unter Verwendung gepackter Sequenzen, GQA, ALiBi, SwiGLU und kausaler Aufmerksamkeit https://chatgpz.de/artificial-intelligence/so-erstellen-sie-speichereffiziente-transformer-mit-xformers-unter-verwendung-gepackter-sequenzen-gqa-alibi-swiglu-und-kausaler-aufmerksamkeit/ https://chatgpz.de/artificial-intelligence/so-erstellen-sie-speichereffiziente-transformer-mit-xformers-unter-verwendung-gepackter-sequenzen-gqa-alibi-swiglu-und-kausaler-aufmerksamkeit/#respond Wed, 17 Jun 2026 03:07:24 +0000 https://chatgpz.de/artificial-intelligence/so-erstellen-sie-speichereffiziente-transformer-mit-xformers-unter-verwendung-gepackter-sequenzen-gqa-alibi-swiglu-und-kausaler-aufmerksamkeit/ [ad_1]

print("n" + "="*70 + "n4. Variable-length packed batch — no padding wasten" + "="*70)
seqlens = (37, 120, 8, 200)
whole = sum(seqlens)
H, Ok = 8, 64
q = torch.randn(1, whole, H, Ok, machine=machine, dtype=torch.float16)
okay = torch.randn(1, whole, H, Ok, machine=machine, dtype=torch.float16)
v = torch.randn(1, whole, H, Ok, machine=machine, dtype=torch.float16)
attempt:
   bias = ab.BlockDiagonalMask.from_seqlens(seqlens)
   out_packed = xops.memory_efficient_attention(q, okay, v, attn_bias=bias)
   s0 = seqlens(0)
   ref0 = vanilla_attention(q(:, :s0), okay(:, :s0), v(:, :s0)).half()
   print("packed form         :", tuple(out_packed.form), "(all", whole, "tokens, no pad)")
   print("segment-0 max diff   : {:.2e}".format((out_packed(:, :s0) - ref0).abs().max().merchandise()))
   cbias = ab.BlockDiagonalCausalMask.from_seqlens(seqlens)
   _ = xops.memory_efficient_attention(q, okay, v, attn_bias=cbias)
   print("-> additionally did a packed CAUSAL move. That is how vLLM-style engines")
   print("   batch requests of various lengths with zero padding overhead.")
   splits = bias.cut up(out_packed)
   print("recovered segments   :", (tuple(t.form) for t in splits))
besides Exception as e:
   print("BlockDiagonalMask path skipped on this model/backend:", repr(e))
print("n" + "="*70 + "n5. Grouped-query consideration (5-D BMGHK format)n" + "="*70)
B, M, Ok = 2, 256, 64
n_q_heads, n_kv_heads = 8, 2
G, Hq = n_kv_heads, n_q_heads // n_kv_heads
attempt:
   qg = torch.randn(B, M, G, Hq, Ok, machine=machine, dtype=torch.float16)
   kg = torch.randn(B, M, G, 1,  Ok, machine=machine, dtype=torch.float16)
   vg = torch.randn(B, M, G, 1,  Ok, machine=machine, dtype=torch.float16)
   out_gqa = xops.memory_efficient_attention(qg, kg, vg)
   print("GQA output form     :", tuple(out_gqa.form), "= (B, M, G, Hq, Ok)")
   print(f"-> {n_q_heads} question heads, solely {n_kv_heads} KV heads: smaller KV-cache,")
   print("   which is strictly what Llama-/Mistral-class fashions use at inference.")
besides Exception as e:
   print("GQA 5-D path skipped on this model/backend:", repr(e))

[ad_2]

]]>
https://chatgpz.de/artificial-intelligence/so-erstellen-sie-speichereffiziente-transformer-mit-xformers-unter-verwendung-gepackter-sequenzen-gqa-alibi-swiglu-und-kausaler-aufmerksamkeit/feed/ 0 19317
Ausgelagerte Aufmerksamkeit in LLMs für große Sprachmodelle https://chatgpz.de/artificial-intelligence/ausgelagerte-aufmerksamkeit-in-llms-fuer-grosse-sprachmodelle/ https://chatgpz.de/artificial-intelligence/ausgelagerte-aufmerksamkeit-in-llms-fuer-grosse-sprachmodelle/#respond Tue, 24 Mar 2026 22:12:32 +0000 https://chatgpz.de/artificial-intelligence/ausgelagerte-aufmerksamkeit-in-llms-fuer-grosse-sprachmodelle/ [ad_1]

Bei der Ausführung von LLMs im großen Maßstab liegt die eigentliche Einschränkung eher im GPU-Speicher als in der Rechenleistung, hauptsächlich weil für jede Anfrage ein KV-Cache zum Speichern von Daten auf Token-Ebene erforderlich ist. In herkömmlichen Setups wird professional Anfrage ein großer fester Speicherblock basierend auf der maximalen Sequenzlänge reserviert, was zu erheblich ungenutztem Speicherplatz führt und die Parallelität einschränkt. Paged Consideration verbessert dies, indem der KV-Cache in kleinere, versatile Blöcke aufgeteilt wird, die nur bei Bedarf zugewiesen werden, ähnlich wie der virtuelle Speicher funktioniert. Es ermöglicht auch mehreren Anfragen mit derselben Startaufforderung, den Speicher gemeinsam zu nutzen und ihn nur zu duplizieren, wenn ihre Ausgaben beginnen, sich zu unterscheiden. Dieser Ansatz verbessert die Speichereffizienz erheblich und ermöglicht einen deutlich höheren Durchsatz bei sehr geringem Overhead.

In diesem Artikel simulieren wir den naiven KV-Cache-Allokator, erstellen eine funktionierende Paged Consideration-Implementierung mit einer Blocktabelle und Copy-on-Write-Präfixfreigabe und messen die Auslastungslücke über Stapelgrößen von 10 bis 200 gleichzeitigen Anforderungen.

import math
import random
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
from collections import defaultdict
 
random.seed(42)
np.random.seed(42)

Bevor wir etwas simulieren, müssen wir wissen, wie viel GPU-Speicher ein einzelner Token tatsächlich kostet. Dies hängt vollständig von der Architektur des Modells ab. Wir verwenden eine Konfiguration im GPT-Stil – 32 Ebenen, 32 Aufmerksamkeitsköpfe, 128 Dimensionen professional Kopf, gespeichert in fp16. Der Faktor 2 vorne berücksichtigt sowohl die Schlüssel- als auch die Wertprojektion (es gibt keinen Q-Cache – Abfragen werden bei jedem Schritt neu berechnet). Wenn wir diese multiplizieren, erhalten wir 524.288 Bytes oder 512 KB professional Token. Dies ist die grundlegende Einheit, auf der alles andere aufbaut – Vorbelegungsgrößen, Seitenanzahlen und verschwendeter Speicher skalieren alle direkt von dieser Zahl.

NUM_LAYERS  = 32
NUM_HEADS   = 32
HEAD_DIM    = 128
BYTES_FP16  = 2
PAGE_SIZE   = 16    # tokens per web page (vLLM default)
MAX_SEQ_LEN = 2048
 
KV_BYTES_PER_TOKEN = 2 * NUM_LAYERS * NUM_HEADS * HEAD_DIM * BYTES_FP16
KV_MB_PER_TOKEN    = KV_BYTES_PER_TOKEN / 1024 / 1024

Der naive Ansatz ist einfach: Wenn eine Anfrage eintrifft, wird ein zusammenhängender Block GPU-Speicher mit der Größe der maximalen Sequenzlänge zugewiesen – in diesem Fall 2048 Token. Dies liegt daran, dass die Antwortlänge im Voraus unbekannt ist und daher der schlimmste Fall vorbehalten bleibt.

AVG_RESPONSE ist auf 500 eingestellt, was ein realistischer Durchschnitt für einen Produktions-Chatbot ist. Die Multiplikation mit KV_MB_PER_TOKEN ergibt, was tatsächlich geschrieben wurde und was gesperrt battle. Die Lücke ist die Verschwendung.

Die Zahlen machen das Downside konkret. Jede Anfrage weist 1024 MB vorab zu, nutzt aber nur 250 MB – 24,4 % Auslastung. Die restlichen 774 MB bleiben für die gesamte Dauer der Anfrage reserviert und stehen keiner anderen Anfrage zur Verfügung. Bei 100 gleichzeitigen Benutzern bedeutet das, dass 75 GB GPU-Speicher nichts bewirken. Dies ist kein Randfall – es ist das Standardverhalten jedes Programs, das keine Seitenzuweisung implementiert, und genau das ist der Grund, warum naive Bereitstellungssysteme lange bevor die GPU rechentechnisch ausgelastet ist, an eine OOM-Wand stoßen.

print("=" * 60)
print("SECTION 1 -- Naive KV Cache: The Waste Downside")
print("=" * 60)
 
AVG_RESPONSE = 500   # reasonable common tokens generated
 
pre_allocated_mb = MAX_SEQ_LEN  * KV_MB_PER_TOKEN
actually_used_mb = AVG_RESPONSE * KV_MB_PER_TOKEN
 
print(f"nKV cache per token    : {KV_BYTES_PER_TOKEN:,} bytes")
print(f"Pre-allocated/request : {pre_allocated_mb:.2f} MB  ({MAX_SEQ_LEN} tokens)")
print(f"Really used/request : {actually_used_mb:.2f} MB  ({AVG_RESPONSE} tokens)")
print(f"Utilisation           : {actually_used_mb / pre_allocated_mb * 100:.1f}%")
print(f"Wasted per request    : {pre_allocated_mb - actually_used_mb:.2f} MB")
 
NUM_USERS = 100
wasted_gb = (pre_allocated_mb - actually_used_mb) * NUM_USERS / 1024
print(f"nAcross {NUM_USERS} concurrent customers → {wasted_gb:.2f} GB wasted")
print("n→ Naive programs utilise solely 20-38% of allotted KV cache reminiscence")
print("  (supply: unique Paged Consideration / vLLM paper)")

Hier werden zwei Klassen vorgestellt, um zu simulieren, wie Paged Consideration tatsächlich auf der Speicherverwaltungsebene funktioniert.

PagePool stellt den physischen GPU-Speicherpool dar – ein flaches Array gleich großer Seiten, die jeweils 16 Token enthalten. Es verwaltet eine kostenlose Liste und eine Referenzanzahl professional Seite. Wenn die Ref-Anzahl einer Seite auf Null sinkt, wird sie sofort wieder in die Liste der freien Seiten aufgenommen und steht für jede neue Anfrage zur Verfügung. Dies ist der Hauptunterschied zur naiven Zuweisung – es gibt keine reservierten Lücken, keine Fragmentierung und keinen an eine abgeschlossene Anfrage gebundenen Speicher.

PagedRequest stellt eine einzelne Inferenzanforderung dar. Es enthält eine block_table – eine Liste, die logische Seitenindizes physischen Seiten-IDs im Pool zuordnet. Jedes Mal, wenn „generate_token()“ aufgerufen wird und der Token-Zähler eine Seitengrenze überschreitet, wird eine neue physische Seite aus dem Pool beansprucht. Keine Erinnerung wird berührt, bevor sie benötigt wird.

Es werden fünf Anfragen mit einer Tokenanzahl von 320, 48, 160, 96 und 272 ausgeführt. Die Ausgabe zeigt die Seiten an, die proportional zur tatsächlichen Nutzung zugewiesen sind – req-1 mit 48 Token erhält 3 Seiten, req-0 mit 320 Token erhält 20. Wenn req-1 freigegeben wird, gehen seine 3 Seiten direkt zurück in den Pool und sind sofort wiederverwendbar. Die Poolauslastung von 10,9 % scheint nur deshalb niedrig zu sein, weil 512 Seiten für 5 kleine Anfragen bereitgestellt wurden – in einem voll ausgelasteten Produktionspool würde sie in der Nähe des in Abschnitt 4 gezeigten Bereichs von 98 % liegen. Die „0 verschwendeten Token“ in der Spalte „Letzte Seite“ sind ein Startartefakt – alle fünf Token-Zählungen sind zufällig exakte Vielfache von 16. In der Praxis beträgt die durchschnittliche Verschwendung der letzten Seite PAGE_SIZE / 2 = 8 Token professional Anfrage.

print("n" + "=" * 60)
print("SECTION 2 -- Paged Consideration: Pages + Block Desk")
print("=" * 60)
 
"""
As a substitute of 1 giant contiguous block per request:
  - KV cache is cut up into fixed-size pages (PAGE_SIZE tokens every)
  - Pages are allotted on demand, can dwell wherever in GPU reminiscence
  - Every request retains a block_table: logical index → bodily web page id
"""
 
class PagePool:
    def __init__(self, total_pages):
        self.free      = listing(vary(total_pages))
        self.complete     = total_pages
        self.ref_count = defaultdict(int)
 
    def allocate(self):
        if not self.free:
            elevate MemoryError("OOM -- no free pages")
        pid = self.free.pop(0)
        self.ref_count(pid) = 1
        return pid
 
    def launch(self, pid):
        self.ref_count(pid) -= 1
        if self.ref_count(pid) <= 0:
            self.free.append(pid)
            del self.ref_count(pid)
 
    def share(self, pid):
        """Increment ref rely -- one other request is sharing this web page."""
        self.ref_count(pid) += 1
 
    def cow_copy(self, pid):
        """CoW: allocate a brand new web page, decrement ref on the previous one."""
        new_pid = self.allocate()
        self.launch(pid)
        return new_pid
 
    @property
    def utilisation(self):
        return (self.complete - len(self.free)) / self.complete * 100
 
 
class PagedRequest:
    def __init__(self, req_id, pool: PagePool):
        self.id          = req_id
        self.pool        = pool
        self.block_table = ()   # logical index → bodily web page id
        self.tokens      = 0
 
    def generate_token(self):
        if self.tokens % PAGE_SIZE == 0:   # web page boundary → allocate new web page
            self.block_table.append(self.pool.allocate())
        self.tokens += 1
 
    def free(self):
        for pid in self.block_table:
            self.pool.launch(pid)
        self.block_table.clear()
 
 
pool = PagePool(total_pages=512)
requests = (PagedRequest(f"req-{i}", pool) for i in vary(5))
token_counts = (320, 48, 160, 96, 272)
 
for req, n in zip(requests, token_counts):
    for _ in vary(n):
        req.generate_token()
 
print("nRequest state after technology:")
print(f"  {'ID':<10} {'Tokens':>8} {'Pages':>7} {'Final-page waste':>16}")
for req in requests:
    waste = req.tokens % PAGE_SIZE
    waste = PAGE_SIZE - waste if waste else 0
    print(f"  {req.id:<10} {req.tokens:>8} {len(req.block_table):>7} {waste:>16} tokens")
 
print(f"nPool utilisation : {pool.utilisation:.1f}%")
requests(1).free()
print(f"After releasing req-1 → utilisation: {pool.utilisation:.1f}%  (pages instantly reusable)")

In der Produktion enthält nahezu jede Anfrage an ein bereitgestelltes LLM dieselbe Systemaufforderung – die Anweisungen, die das Verhalten des Modells definieren. Bei der naiven Zuordnung speichert jede dieser Anforderungen eine eigene vollständige Kopie des KV-Cache der Systemeingabeaufforderung. Bei 10 gleichzeitigen Anforderungen und einer Systemaufforderung mit 200 Token bedeutet dies, dass 10 identische Kopien derselben Daten separate Speicherbereiche belegen.

Hier wird derselbe PagePool aus Abschnitt 2 wiederverwendet, erweitert um zwei Methoden: share() erhöht die Ref-Anzahl einer Seite, ohne etwas Neues zuzuweisen, und cow_copy() weist eine neue Seite zu und verringert die Ref-Anzahl des Originals. Ein neuer Pool wird instanziiert und die Systemeingabeaufforderung wird in 13 Seiten codiert – math.ceil(200/16). Jede der 10 Benutzeranfragen ruft dann share() auf allen 13 Seiten auf und verweist ihre Blocktabellen auf denselben physischen Speicher. Es werden keine neuen Seiten zugewiesen. Die Ref-Anzahl auf jeder geteilten Seite steigt einfach auf 11.

Die Einsparungen sind sofort spürbar: Eine naive Zuordnung würde 130 Seiten für 10 Anfragen erfordern. Bei CoW existieren nur 13 physische Seiten. Das sind 936 MB, die durch ein einzelnes gemeinsames Präfix eingespart werden.

Wenn req-3 sein erstes eindeutiges Token generiert, wird cow_copy() auf seiner letzten freigegebenen Seite aufgerufen – Seite 12. Eine neue Seite 13 wird als personal Kopie von req-3 zugewiesen und die Referenzanzahl auf Seite 12 sinkt um eins. Die anderen 9 Anfragen verweisen weiterhin völlig unbeeinflusst auf Seite 12. Dies ist der CoW-Vertrag: geteilt bis zur Divergenz, privat nur bei Bedarf.

print("n" + "=" * 60)
print("SECTION 3 -- Copy-on-Write: Shared System Prompts")
print("=" * 60)
 
"""
If N requests share a system immediate, naive allocation shops N copies.
With CoW, all requests level to the SAME bodily pages.
A personal copy is made solely when a request writes a diverging token.
"""
 
cow_pool    = PagePool(total_pages=512)
SYSTEM_TOKENS = 200
system_pages  = math.ceil(SYSTEM_TOKENS / PAGE_SIZE)
shared_pids   = (cow_pool.allocate() for _ in vary(system_pages))
print(f"nSystem immediate → {system_pages} shared pages: {shared_pids}")
 
N = 10
user_tables = ()
for i in vary(N):
    desk = listing(shared_pids)
    for pid in shared_pids:
        cow_pool.share(pid)     # ref rely up -- no bodily copy
    user_tables.append(desk)
 
saved_mb = (system_pages * N - system_pages) * PAGE_SIZE * KV_MB_PER_TOKEN
print(f"nStoring system immediate for {N} requests:")
print(f"  Naive : {system_pages * N} pages  ({system_pages * N * PAGE_SIZE * KV_MB_PER_TOKEN:.1f} MB)")
print(f"  CoW   : {system_pages} pages   ({system_pages * PAGE_SIZE * KV_MB_PER_TOKEN:.1f} MB)")
print(f"  Saved : {saved_mb:.1f} MB")
 
old_pid                 = user_tables(3)(-1)
new_pid                 = cow_pool.cow_copy(old_pid)
user_tables(3)(-1)      = new_pid
print(f"nReq-3 diverges → CoW: previous web page {old_pid} → new web page {new_pid}")
print(f"All different {N-1} requests nonetheless share web page {old_pid} unaffected")

Es werden zwei Funktionen definiert, um die Auslastung bei jedem Ansatz über verschiedene Chargengrößen hinweg zu messen.

naive_utilisation bezieht die Token-Anzahl aus einer Normalverteilung mit avg=500 und std=200, begrenzt auf (200, 2048). Dies spiegelt eine realistische Produktionsverteilung wider – die meisten Antworten liegen zwischen 200 und 800 Token, gelegentlich gibt es auch längere. Für jede Anfrage wird unabhängig davon der gesamte 2048-Slot-Block vorab zugewiesen. Die Auslastung beträgt dann „actual_tokens_sum / (2048 × n)“ – das Verhältnis zwischen dem, was geschrieben wurde, und dem, was reserviert wurde.

paged_utilisation verwendet die gleichen tatsächlichen Token-Zählungen, berechnet aber, wie viele Seiten jede Anfrage benötigen würde – ceil(tokens / 16). Der einzige Abfall ist der nicht ausgefüllte Schwanz der letzten Seite jeder Anfrage, der durchschnittlich 8 Token ausmacht. Die Auslastung beträgt „actual_tokens_sum“ / (pages_allocated × 16).

Die Ergebnisse werden auf Chargengrößen von 10, 25, 50, 100 und 200 angewendet. Die naive Auslastung liegt bei etwa 24 % über alle Chargengrößen hinweg – mit einer gewissen Abweichung bei kleineren Chargen aufgrund von Stichprobenrauschen –, was genau avg / max_seq = 500 / 2048 entspricht. Es verbessert sich nicht mit der Skalierung, da der Abfall strukturell und nicht statistisch ist.

Die Seitenauslastung liegt unabhängig von der Stapelgröße konstant bei etwa 98,5 %, da der Abfall professional Anfrage durch eine einzelne Teilseite begrenzt ist und überhaupt nicht mit max_seq_len skaliert. Die Lücke zwischen den beiden Zahlen – etwa 74 Prozentpunkte – ist direkt dafür verantwortlich, dass vLLM zwei- bis viermal mehr gleichzeitige Anforderungen in denselben GPU-Speicher unterbringen kann.

print("n" + "=" * 60)
print("SECTION 4 -- Utilisation: Naive vs Paged")
print("=" * 60)
 
def naive_utilisation(n, max_seq=2048, avg=500, std=200):
    precise = np.clip(np.random.regular(avg, std, n).astype(int), 200, max_seq)
    return precise.sum() / (max_seq * n) * 100, precise
 
def paged_utilisation(actual_tokens, page_size=PAGE_SIZE):
    pages = np.ceil(actual_tokens / page_size).astype(int)
    return actual_tokens.sum() / (pages * page_size).sum() * 100
 
batch_sizes = (10, 25, 50, 100, 200)
naive_u, paged_u = (), ()
 
print(f"n  {'Batch':>6}   {'Naive':>8}   {'Paged':>8}")
for bs in batch_sizes:
    nu, precise = naive_utilisation(bs)
    pu = paged_utilisation(precise)
    naive_u.append(nu)
    paged_u.append(pu)
    print(f"  {bs:>6}   {nu:>7.1f}%   {pu:>7.1f}%")

Schauen Sie sich das an Vollständiges Notizbuch hier. Sie können uns auch gerne weiter folgen Twitter und vergessen Sie nicht, bei uns mitzumachen 120.000+ ML SubReddit und Abonnieren Unser E-newsletter. Warten! Bist du im Telegram? Jetzt können Sie uns auch per Telegram kontaktieren.


Ich habe einen Abschluss im Bauingenieurwesen (2022) von Jamia Millia Islamia, Neu-Delhi, und interessiere mich sehr für Datenwissenschaft, insbesondere für neuronale Netze und deren Anwendung in verschiedenen Bereichen.

[ad_2]

]]>
https://chatgpz.de/artificial-intelligence/ausgelagerte-aufmerksamkeit-in-llms-fuer-grosse-sprachmodelle/feed/ 0 17317
Transformatoren (und Aufmerksamkeit) sind nur ausgefallene Zusatzmaschinen https://chatgpz.de/machine-learning/transformatoren-und-aufmerksamkeit-sind-nur-ausgefallene-zusatzmaschinen/ https://chatgpz.de/machine-learning/transformatoren-und-aufmerksamkeit-sind-nur-ausgefallene-zusatzmaschinen/#respond Thu, 24 Jul 2025 11:13:55 +0000 http://chatgpz.de/machine-learning/transformatoren-und-aufmerksamkeit-sind-nur-ausgefallene-zusatzmaschinen/ [ad_1]

ist ein relativ neues Unterfeld in der KI, das sich darauf konzentriert, zu verstehen, wie neuronale Netze funktionieren, indem sie ihre internen Mechanismen und Darstellungen umgekehrt und darauf abzielen, sie in menschlich verständliche Algorithmen und Konzepte zu übersetzen. Dies steht im Gegensatz zu und weiter als herkömmliche Erklärungstechniken wie Kind und Kalk.

Shap steht für ShApley Additive ExPLanationen. Es berechnet den Beitrag jeder Funktion zur Vorhersage des Modells lokal und international, dh sowohl für ein einzelnes Beispiel als auch für den gesamten Datensatz. Auf diese Weise kann Shap verwendet werden, um die Merkmals Bedeutung im Allgemeinen für den Anwendungsfall zu bestimmen. Lime arbeitet in der Zwischenzeit an einem einzigen Beispielvorhersagepaar, in dem sie die Beispieleingabe stört und die Störungen und seine Ausgänge verwendet, um einen einfacheren Ersatz des Black-Field-Modells zu approximieren. Als solche arbeiten beide auf Merkmalsebene und geben uns eine Erklärung und heuristisch, um zu beurteilen, wie sich jede Eingabe in das Modell auf seine Vorhersage oder Ausgabe auswirkt.

Andererseits versteht die mechanistische Interpretation die Dinge auf einer detaillierteren Ebene, da sie in der Lage ist, einen Weg zu bieten, wie das genannte Merkmal von verschiedenen Neuronen in verschiedenen Schichten im neuronalen Netzwerk gelernt wird und wie sich das Lernen über den Schichten im Netzwerk entwickelt. Dies macht es geschickt, Pfade im Netzwerk für eine bestimmte Funktion zu verfolgen und Auch Zu sehen, wie sich diese Funktion auf das Ergebnis auswirkt.

Kind und Kalk beantworten Sie die Frage additionally „Welche Funktion trägt am meisten zum Ergebnis bei?“ während die mechanistische Interpretation die Frage beantwortet “Welche Neuronen aktivieren für welche Funktion und wie entwickelt sich diese Funktion und wirkt sich auf das Ergebnis des Netzwerks aus?“

Da die Erklärung im Allgemeinen ein Downside mit tieferen Netzwerken ist, arbeitet dies hauptsächlich mit tieferen Modellen wie den Transformatoren. Es gibt einige Orte, an denen die mechanistische Interpretierbarkeit Transformatoren unterschiedlich betrachtet Multi-Head-Aufmerksamkeit. Wie wir sehen werden, besteht dieser Unterschied darin, die Multiplikations- und Verkettungsvorgänge wie in der „Aufmerksamkeit ist alles, was Sie brauchen“ Papier als Additionsvorgänge, die eine ganze Reihe neuer Möglichkeiten eröffnen.

Aber zuerst eine Zusammenfassung der Transformatorarchitektur.

Transformatorarchitektur

Bild von Autor: Transformator Architektur

Dies sind die Größen, mit denen wir arbeiten:

  • batch_size b = 1;
  • Sequenzlänge S = 20;
  • vocab_size v = 50.000;
  • Hidden_dims d = 512;
  • Köpfe H = 8

Dies bedeutet, dass die Anzahl der Dimensionen im Q, Okay, V -Vektoren 512/8 (l) = 64 beträgt. (Falls Sie sich nicht erinnern, eine Analogie zum Verständnis von Abfrage, Schlüssel und Wert: Die Idee ist, dass wir für ein Token an einer bestimmten Place (ok) basierend auf seinem Kontext (q) die Ausrichtung (erneut mit der Wiederaufnahme) an die Positionen erhalten möchten, die für (v) related sind.)

Dies sind die Schritte bis zur Aufmerksamkeitsberechnung in einem Transformator. (Die Kind der Tensoren wird als Beispiel für ein besseres Verständnis angenommen. Zahlen in Kursiv stellen die Dimension dar, entlang der die Matrix multipliziert wird.)

Schritt Betrieb Eingabe 1 Dims (Kind) Eingabe 2 Dims (Kind) Ausgangsdunkeln (Kind)
1 N / A B x s x v
(1 x 20 x 50.000)
N / A B x s x v
(1 x 20 x 50.000)
2 Holen Sie sich Einbettung B x s x v
(1 x 20 x 50.000)
V x d
(50.000 x 512)
B x s x d
(1 x 20 x 512)
3 Positionsbettendings hinzufügen B x s x d
(1 x 20 x 512)
N / A B x s x d
(1 x 20 x 512)
4 Kopiereinbettungen nach Q, ok, v B x s x d
(1 x 20 x 512)
N / A B x s x d
(1 x 20 x 512)
5 Lineare Transformation Für jeden Kopf H = 8 B x s x d
(1 x 20 x 512)
D x l
(512 X 64)
Bxhxsxl
(1 x 1 x 20 x 64)
6 Skaled Dot -Produkt (Q@ok ‚) in jedem Kopf Bxhxsxl
(1 x 1 x 20 x 64)
(Lxsxhxb)
(64 x 20 x 1 x 1)
BXHXSXS
(1 x 1 x 20 x 20)
7 Skaliertes Punktprodukt (Aufmerksamkeitsberechnung) q@ok’v in jedem Kopf BXHXSXS
(1 x 1 x 20 x 20)
Bxhxsxl
(1 x 1 x 20 x 64)
Bxhxsxl
(1 x 1 x 20 x 64)
8 Beschimpfen über alle Köpfe H = 8 Bxhxsxl
(1 x 1 x 20 x 64)
N / A B x s x d
(1 x 20 x 512)
9 Lineare Projektion B x s x d
(1 x 20 x 512)
D x d
(512 x 512)
B x s x d
(1 x 20 x 512)
Tabellarische Ansicht der Formtransformationen zur Aufmerksamkeitsberechnung im Transformator

Die Tabelle erklärte sich ausführlich:

  1. Wir beginnen mit einem Eingangssatz einer Sequenzlänge von 20, die einhot codiert ist, um Wörter im in der Sequenz vorhandenen Vokabular darzustellen. Kind (b x s x v): (1 x 20 x 50.000)
  2. Wir multiplizieren diesen Eingang mit der lernbaren Einbettungsmatrix wₑ Kind (V x D), um die Einbettungen zu erhalten. Kind (b x s x d): (1 x 20 x 512)
  3. Nächst
  4. Die resultierenden Einbettungen werden dann in die Matrizen Q, Okay und V. Q, Okay und V kopiert, die jeweils auf dem geteilt und umgestaltet werden D Dimension. Kind (b x s x d): (1 x 20 x 512)
  5. Die Matrizen für Q, Okay und V werden jeweils einer linearen Transformationsschicht gespeist, die sie mit lernbarer Gewichtsmatrizen multipliziert. (Eine Kopie für jedes der H = 8 Köpfe). Kind (b x h x s x l): (1 x 1 x 20 x 64) wobei H = 1, da dies die resultierende Kind für ist Jeder Kopf.
  6. Als nächstes berechnen wir die Aufmerksamkeit mit skalierten Punktproduktaufmerksamkeit Jeder Kopf. Kind (b x h x s x l) x (l x s x h x b) → (b x h x s x s): (1 x 1 x 20 x 20).
  7. Als nächstes gibt es einen Skalierungs- und Maskierungsschritt, den ich übersprungen habe, da dies nicht wichtig ist, um zu verstehen, was die unterschiedliche Artwork des Betrachtens von MHA ist. Additionally, als nächstes multiplizieren wir Qk mit V Für jeden Kopf. Kind (b x h x s x s) x (b x h x s x l) → (b x h x s x l): (1 x 1 x 20 x 64)
  8. Concat: Hier verkettet wir die Aufmerksamkeitsergebnisse aus allen Köpfen in der L -Dimension, um eine Kind von (b x s x d) → (1 x 20 x 512) zurückzubekommen.
  9. Diese Ausgabe wird mit einer weiteren Lerngewichtsmatrix wₒ Kind (d x d) noch einmal linear projiziert. Endgültige Kind enden wir mit (b x s x d): (1 x 20 x 512)

Multi-Head-Aufmerksamkeit neu interpretieren

Bild des Autors: Aufmerksamkeit der Mehrköpfe neu interpretieren

Lassen Sie uns nun sehen, wie das Feld der mechanistischen Interpretation dies betrachtet, und wir werden auch sehen, warum es mathematisch gleichwertig ist. Rechts im Bild oben sehen Sie das Modul, das die Aufmerksamkeit der Mehrköpfe neu interpretiert.

Anstatt die Aufmerksamkeitsausgabe zu verkettet, gehen wir mit der Multiplikation fort „innen“ Die Köpfe selbst, wo jetzt die Kind von Wₒ (l x d) ist und sich mit qk’v der Kind (b x h x s x l) multiplizieren, um das Ergebnis der Kind (b x s x h x d) zu erhalten: (1 x 20 x 1 x 512). Dann summieren wir die H -Dimension, um wieder mit der Kind (b x s x d) zu enden: (1 x 20 x 512).

Aus der obigen Tabelle sind die letzten beiden Schritte das, was sich ändert:

Schritt Betrieb Eingabe 1 Dims (Kind) Eingabe 2 Dims (Kind) Ausgangsdunkeln (Kind)
8 Matrixmultiplikation in jedem Kopf H = 8 Bxhxsxl
(1 x 1 x 20 x 64)
L x d
(64 x 512)
Bxsxhxd
(1 x 20 x 1 x 512)
9 Summe über Köpfen (H -Dimension) Bxsxhxd
(1 x 20 x 1 x 512)
N / A B x s x d
(1 x 20 x 512)

Randnotiz: Diese „Summierung über“ erinnert an die Summierung über verschiedene Kanäle in CNNs. In CNNs arbeitet jeder Filter auf der Eingabe, und dann wir Summe die Ausgänge über Kanäle hinweg. Gleiches gilt hier – jeder Kopf kann als Kanal gesehen werden, und das Modell lernt eine Gewichtsmatrix, um den Beitrag jedes Kopfes in den endgültigen Ausgangsraum zuzuordnen.

Aber warum ist das Projekt + Summe mathematisch äquivalent zu concat + venture? Kurz gesagt, weil die Projektionsgewichte in der mechanistischen Perspektive nur geschnittene Versionen der Gewichte in der traditionellen Sicht sind (über die geschnitten D Dimension und aufgeteilt, um jedem Kopf zu entsprechen).

Bild des Autors: Warum funktioniert das Neuaufbau funktioniert

Konzentrieren wir uns vor der Multiplikation mit Wₒ auf die H- und D -Abmessungen. Aus dem Bild oben verfügt jeder Kopf jetzt über einen Vektor der Größe 64, der mit der Gewichtsmatrix der Kind (64 x 512) multipliziert wird. Bezeichnen wir das Ergebnis von R und Kopf durch h.

Um R₁₁ zu bekommen, haben wir diese Gleichung:

R₁, ₁ = h₁, ₁ x wₒ₁, ₁ + h₁, ₂ x wₒ₂, ₁ +…. + h₁ₓ₆₄ x wₒ₆₄, ₁

Nehmen wir nun an, wir hätten die Köpfe verkettet, um eine Aufmerksamkeitsausgangsform von (1 x 512) und die Gewichtsmatrix der Kind (512, 512) zu erhalten, dann wäre die Gleichung gewesen:

R₁, ₁ = h₁, ₁ x wₒ₁, ₁ + h₁, ₂ x wₒ₂, ₁ +…. + H₁ₓ₅₁₂ x wₒ₅₁₂₁

Additionally der Teil H₁ₓ₆₅ x wₒ₆₅₁ +… + h₁ₓ₅₁₂ x wₒ₅₁₂₁ wäre hinzugefügt worden. Dieser Teil ist jedoch der Teil, der in den anderen Köpfen in Modulo 64 vorhanden ist. Anders gesagt, wenn es keine Verkettung gibt, wₒ₆₅₁ ist der Wert hinter Wₒ₁, ₁ im zweiten Kopf, Wₒ₁₂₉, ₁ ist der Wert hinter Wₒ₁, ₁ im dritten Kopf und so weiter, wenn wir uns vorstellen, dass die Werte für jeden Kopf hintereinander liegen. Daher führt der Betrieb „Summieren über die Köpfe“ auch ohne Verkettung dazu, dass die gleichen Werte hinzugefügt werden.

Zusammenfassend lässt sich sagen, dass diese Erkenntnis die Grundlage für die Betrachtung von Transformatoren als rein additive Modelle legt, da alle Operationen in einem Transformator die anfängliche Einbettung einnehmen und sie hinzufügen. Diese Ansicht eröffnet neue Möglichkeiten wie die Verfolgung von Funktionen, wie sie über gelernt werden Ergänzungen Durch die Schichten (Schaltungsverfolgung genannt), worum es bei der mechanistischen Interpretierbarkeit in meinen nächsten Artikeln angezeigt wird.


Wir haben gezeigt, dass diese Ansicht mathematisch der sehr unterschiedlichen Ansicht entspricht, dass die Aufmerksamkeit mit mehreren Kopf durch Aufteilen von Q, Okay, V parallelisiert und die Berechnung der Aufmerksamkeit optimiert. Lesen Sie mehr darüber in diesem Weblog Hier Und das tatsächliche Papier, das diese Punkte einführt, ist Hier.

[ad_2]

]]>
https://chatgpz.de/machine-learning/transformatoren-und-aufmerksamkeit-sind-nur-ausgefallene-zusatzmaschinen/feed/ 0 11026
Lineare Aufmerksamkeit ist alles, was Sie brauchen. Selbstaufmerksamkeit zu einem Bruchteil der… | von Sam Maddrell-Mander | Juni 2024 https://chatgpz.de/machine-learning/lineare-aufmerksamkeit-ist-alles-was-sie-brauchen-selbstaufmerksamkeit-zu-einem-bruchteil-der-von-sam-maddrell-mander-juni-2024/ https://chatgpz.de/machine-learning/lineare-aufmerksamkeit-ist-alles-was-sie-brauchen-selbstaufmerksamkeit-zu-einem-bruchteil-der-von-sam-maddrell-mander-juni-2024/#respond Thu, 06 Jun 2024 03:27:46 +0000 https://chatgpz.de/machine-learning/lineare-aufmerksamkeit-ist-alles-was-sie-brauchen-selbstaufmerksamkeit-zu-einem-bruchteil-der-von-sam-maddrell-mander-juni-2024/ [ad_1]

Das ist etwas, was jeder, der viel Zeit mit Transformatoren und Selbstaufmerksamkeit verbracht hat, schon hundertmal gehört hat. Beides ist absolut wahr, wir haben das alle schon erlebt: Wenn man versucht, die Kontextgröße seines Modells zu erhöhen, kommt plötzlich alles zum Stillstand. Doch gleichzeitig gibt es, so scheint es, praktisch jede Woche ein neues hochmodernes Modell mit einer neuen rekordverdächtigen Kontextlänge. (Gemini hat eine Kontextlänge von 2 Millionen Token!)

Es gibt viele ausgefeilte Methoden wie RingAttention, die das Coaching unglaublich langer Kontextlängen in großen verteilten Systemen ermöglichen, aber was mich heute interessiert, ist eine einfachere Frage.

Wie weit kommen wir allein mit linearer Aufmerksamkeit?

Dies wird eine Artwork Blitztour, aber haben Sie etwas Geduld, denn wir werden ein paar wichtige Punkte ansprechen, bevor wir uns mit den Ergebnissen befassen.

Wir können den traditionellen Aufmerksamkeitsmechanismus im Wesentlichen mit zwei Kernpunkten zusammenfassen:

  • Zunächst nimmt der typische Softmax-Aufmerksamkeitsausdruck das Produkt aus Abfrage- und Schlüsselmatrizen, normalisiert es zur Gewährleistung der Stabilität und nimmt dann das Softmax (zeilenweise), um die Aufmerksamkeitswerte zwischen den einzelnen Elementen der Sequenz zu erhalten.
  • Zweitens wird die Zeitkomplexität von den N² Skalarprodukten dominiert, und das Produkt innerhalb des Softmax ist der limitierende Faktor. Dort berechnen wir die Aufmerksamkeitswerte.

Dies wird in der traditionellen Type wie folgt ausgedrückt:

Traditionelle Formulierung des Softmax-Aufmerksamkeitsmechanismus.

Es stellt sich heraus, dass wir etwas anders darüber nachdenken können, wenn wir unsere Mathematikerfreunde fragen. Man kann sich den Softmax als eine von vielen Möglichkeiten vorstellen, die Wahrscheinlichkeitsverteilung zu beschreiben, die Token miteinander in Beziehung setzt. Wir können jedes beliebige Ähnlichkeitsmaß verwenden (das Skalarprodukt ist eines der einfachsten), und solange wir es normalisieren, ist alles in Ordnung.

Allgemeiner Ausdruck für Aufmerksamkeit unter Verwendung einer beliebigen Ähnlichkeitsfunktion.

Es ist ein bisschen schlampig, das zu sagen Ist Aufmerksamkeit, denn tatsächlich ist es nur die Aufmerksamkeit, die wir kennen und lieben, wenn die Ähnlichkeitsfunktion die Exponentialfunktion des Skalarprodukts von Abfragen und Schlüsseln (siehe unten) ist, wie wir es im Softmax finden. Aber hier wird es interessant: Was wäre, wenn wir statt dieses Ausdrucks eine Näherung vornehmen könnten?

Nähern Sie die Ähnlichkeitsfunktion aus der Selbstaufmerksamkeit mit zwei Characteristic-Maps an.

Wir können davon ausgehen, dass es eine Characteristic-Map gibt.phi” was uns ein Ergebnis gibt quick das gleiche wie die Exponentialfunktion des Skalarprodukts. Und entscheidend ist, dass wir den Ausdruck auf diese Weise schreiben können, um mit der Reihenfolge der Matrixmultiplikationsoperationen zu spielen.

Im Papier Sie schlagen die Exponential Linear Unit (ELU) aufgrund einer Reihe nützlicher Eigenschaften als Merkmalskarte vor:

  1. Für Werte über 0 liefert ELU(x) ein lineares Ergebnis, das zwar nicht mit der Exponentialfunktion identisch ist, aber die relative Reihenfolge zwischen den Wertungen beibehält.
  2. Bei Werten kleiner oder gleich 0 bleibt der Exponentialterm der kontinuierliche Charakter der Funktion erhalten und stellt sicher, dass die Gradienten nicht einfach verschwinden.

Wir werden hier nicht allzu viel Zeit darauf verwenden, aber es ist empirisch ziemlich intestine bestätigt, dass dies eine gute Annäherung an die Softmax-Funktion ist.

Dadurch können wir die Reihenfolge der Operationen ändern. Wir können zuerst das Produkt unserer Characteristic-Map von Okay mit V nehmen, um einen KV-Block zu erstellen, und dann das Produkt mit Q. Das quadratische Produkt wird über die Modelldimensionsgröße und nicht über die Sequenzlänge bestimmt.

Wenn wir dies alles in den linearen Aufmerksamkeitsausdruck einfügen, erhalten wir:

Lineare Aufmerksamkeit mithilfe von Characteristic-Maps zur Annäherung an den Softmax-Ähnlichkeitswert.

Wobei wir die Begriffe in den Klammern nur einmal professional Abfragezeile berechnen müssen.

(Wenn Sie wissen möchten, wie die gelegentliche Maskierung hier hineinpasst und wie die Farbverläufe berechnet werden, werfen Sie einen Blick in das Dokument. Oder schauen Sie in diesem Bereich nach einem zukünftigen Weblog.)

Die mathematischen Argumente sind überzeugend, aber persönlich bin ich immer etwas misstrauisch, bis ich einige Benchmarks gesehen habe.

Sehen wir uns zunächst die Codeausschnitte an, die jeden dieser Begriffe beschreiben. Die Softmax-Aufmerksamkeit wird Ihnen sehr vertraut vorkommen, wir machen hier nichts Ausgefallenes.

class TraditionalAttention(nn.Module):
def __init__(self, d_k):
tremendous(TraditionalAttention, self).__init__()
self.d_k = d_k

def ahead(self, Q, Okay, V):
Z = torch.sqrt(torch.tensor(self.d_k, machine=Q.machine, dtype=torch.float32))
scores = torch.matmul(Q, Okay.transpose(-2, -1)) / Z
attention_weights = F.softmax(scores, dim=-1)
output = torch.matmul(attention_weights, V)
return output

Dann beginnen wir für die lineare Aufmerksamkeit mit dem Abrufen der Abfrage-, Schlüssel- und Wertematrizen und wenden dann die ELU(x)-Funktionszuordnung auf die Abfrage und die Schlüssel an. Dann verwenden wir die Einsummennotation, um die Multiplikationen durchzuführen.

class LinearAttention(nn.Module):
def __init__(self):
tremendous(LinearAttention, self).__init__()
self.eps = 1e-6

def elu_feature_map(self, x):
return F.elu(x) + 1

def ahead(self, Q, Okay, V):
Q = self.elu_feature_map(Q)
Okay = self.elu_feature_map(Okay)
KV = torch.einsum("nsd,nsd->ns", Okay, V)
# Compute the normalizer
Z = 1/(torch.einsum("nld,nd->nl", Q, Okay.sum(dim=1))+self.eps)
# Lastly compute and return the brand new values
V = torch.einsum("nld,ns,nl->nd", Q, KV, Z)
return V.contiguous()

Dies in Code geschrieben zu sehen ist schön und intestine, aber was bedeutet es tatsächlich experimentell? Von welcher Leistungssteigerung sprechen wir hier? Es kann schwierig sein, den Grad der Beschleunigung zu erfassen, wenn man von einem quadratischen zu einem linearen Engpass wechselt, additionally habe ich das folgende Experiment durchgeführt.

Wir werden eine einzelne Aufmerksamkeitsebene mit einer festen d_k-Modelldimension von 64 verwenden und die Zeit für einen Vorwärtsdurchlauf eines Sequenzsatzes mit 32 Batchgrößen als Benchmark verwenden. Die einzige zu ändernde Variable ist die Sequenzlänge, die zwischen 128 und 6000 liegt (die GPT-3-Kontextlänge als Referenz beträgt 2048). Jeder Durchlauf wird 100 Mal durchgeführt, um einen Mittelwert und eine Standardabweichung zu erhalten, und die Experimente werden mit einer Nvidia T4 GPU durchgeführt.

Für ein so einfaches Experiment sind die Ergebnisse ziemlich bemerkenswert.

Benchmarks: Messen der Zeit professional Iteration für eine einzelne Sequenz mit sowohl traditioneller (Softmax-)Aufmerksamkeit als auch linearer Aufmerksamkeit. Jede Sequenzlänge wird über 100 Iterationen gemittelt und die Standardabweichung aufgezeichnet. Die verwendeten Sequenzlängen reichen von 128 bis 6000. Das Verhältnis wird auch angezeigt, um die verbesserte Leistung leichter messen zu können.

Die Ergebnisse zeigen, dass wir sogar bei einem unglaublich kleinen Spielzeugbeispiel eine bis zu 60-fache Beschleunigung erreichen.

Diskussion

Hieraus lassen sich einige offensichtliche Erkenntnisse gewinnen:

  1. Der Vorteil der linearen Aufmerksamkeit ist enorm – entweder in Bezug auf die Geschwindigkeit, ein höherer Durchsatz ist immer eine gute Sache. Oder in Bezug auf den Speicherbedarf zur Verarbeitung langer Sequenzen. In Umgebungen mit wenig Speicher kann dies ein großer Vorteil sein.
  2. Das Verhältnisdiagramm weist einen überraschenden Knick auf – was uns vermuten lässt, dass hier eine zusätzliche Optimierung auf niedrigerer Ebene stattfindet, was bedeutet, dass das erwartete Verhältnis nicht ganz eintritt. Wir müssen dieses Ergebnis additionally mit Vorsicht genießen.

Der Vollständigkeit halber sei hier nicht verwechselt mit „lineare Aufmerksamkeit ist bei kleinen Modellen 60-mal schneller“. In Wirklichkeit machen die Feedforward-Schichten oft einen größeren Teil der Parameter in einem Transformer aus, und die Kodierung/Dekodierung ist oft auch eine Komponente mit limitierender Größe. Aber bei diesem eng definierten Downside ist das ziemlich beeindruckend!

[ad_2]

]]>
https://chatgpz.de/machine-learning/lineare-aufmerksamkeit-ist-alles-was-sie-brauchen-selbstaufmerksamkeit-zu-einem-bruchteil-der-von-sam-maddrell-mander-juni-2024/feed/ 0 1185
Flash Consideration (Schnelle und speichereffiziente exakte Aufmerksamkeit mit IO-Consciousness): Ein tiefer Einblick | von Anish Dubey | Mai 2024 https://chatgpz.de/machine-learning/flash-consideration-schnelle-und-speichereffiziente-exakte-aufmerksamkeit-mit-io-consciousness-ein-tiefer-einblick-von-anish-dubey-mai-2024/ https://chatgpz.de/machine-learning/flash-consideration-schnelle-und-speichereffiziente-exakte-aufmerksamkeit-mit-io-consciousness-ein-tiefer-einblick-von-anish-dubey-mai-2024/#respond Wed, 29 May 2024 14:58:19 +0000 https://chatgpz.de/machine-learning/flash-attention-schnelle-und-speichereffiziente-exakte-aufmerksamkeit-mit-io-awareness-ein-tiefer-einblick-von-anish-dubey-mai-2024/ [ad_1]

Flash Consideration ist ein leistungsoptimierender Transformator-Consideration-Mechanismus, der eine Effizienz von 15 % bietet

Foto von Sander Traa An Unsplash

Flash Consideration ist ein Transformator-Aufmerksamkeitsmechanismus zur Leistungsoptimierung, der im Hinblick auf die Echtzeitgeschwindigkeit eine Effizienz von 15 % bietet, und zwar ohne Annäherung.

Da Transformer-Modelle bei langen Sequenzen langsam und speicherhungrig sind (Zeit- und Speicherkomplexität sind quadratischer Natur), ist Flash Consideration (Papier) bietet eine Finish-to-Finish-Beschleunigung im Echtzeittakt von 15 % auf BERT-large und die dreifache Geschwindigkeit auf GPT-2.

Wenn man bedenkt, dass das Trainieren dieser großen Modelle enorme Mengen an Energie verbraucht, kann Flash Consideration mit Software program- und Hardwareoptimierung eine Effizienz von 15 % erzielen, was hinsichtlich der Verbesserung einen enormen Gewinn darstellt.

Nachfolgend werden einige der grundlegenden Konzepte von Flash Consideration und deren Implementierung erläutert.

Grundlegende Konzepte rund um Rechenleistung und Speicher

Bevor wir tiefer in die Thematik Rechenleistung und Speicher eintauchen, wollen wir sie noch einmal betrachten:

Was ist Compute?

  • Zeit, die Ihr GPU für die Berechnung tatsächlicher Gleitkommaoperationen (FLOPS) aufwendet

Was ist Speicher?

  • Zeitaufwand für die Übertragung von Tensoren innerhalb einer GPU

Im Idealfall soll unsere gCPU ständig Matrixmultiplikationen durchführen und nicht durch den Speicher eingeschränkt werden. In Wirklichkeit hat die Rechenleistung jedoch im Vergleich zum Speicher größere Fortschritte gemacht, und wir befinden uns in einer Welt, in der die gCPU im Leerlauf wartet, bis Daten geladen sind. Dies wird normalerweise als Speicher gebunden Operation. Siehe unten das erläuternde Diagramm, das dies darstellt. Matrixmultiplikation wird als Berechnung betrachtet und der Speicher speichert die Daten (betrachten Sie ihn als Lager). Die Berechnung benötigt Daten zur Verarbeitung und die Speicherbandbreite muss diese Operation unterstützen.

Foto von https://horace.io/brrr_intro.html

Was ist Speicherhierarchie?

Die A100 GPU hat 40–80 GB von Excessive Bandwidth Reminiscence mit einer Bandbreite von 1,5–2,0 TB/s Und 192 KB On-Chip-SRAM mit jeweils 108 Streaming-Multiprozessoren mit einer Bandbreite von ca. 19 TB/s.

Foto von https://arxiv.org/abs/2205.14135

Vor dem Hintergrund des oben genannten Kontexts ist Self-Consideration-Architektur erinnerungsgebunden.

Foto vom Autor

Betrachtet man die Aufmerksamkeitsmathematik, ist es eine Softmax-Operation, die die Speicherbindung verursacht.

  • Quantitativer Beweis: Wie Sie unten sehen können, nehmen Operationen wie Softmax, Dropout und Maskierung im Vergleich zur Matrixmultiplikation (Matmul) den Großteil der Zeit in Anspruch.
Foto von https://arxiv.org/abs/2205.14135

Warum wird Softmax zu einer speichergebundenen Operation?

Der Maßstab, in dem es betrieben wird, ist unser größter Engpass. Im folgenden Diagramm

  • N -> Anzahl der Token
  • d -> Anzahl der Einbettungsdimensionen
  • Wenn Abfrage und Schlüssel multipliziert werden, explodiert die Aufmerksamkeitsmatrix auf N * N, was viel Speicher beansprucht. Als Referenz (d ~128; N ~128.000 Token; Google Gemini: ~1 Million Token)
Foto von FlashAttention — Tri Dao | Stanford MLSys #67

Unten sehen Sie den Algorithmus zur Implementierung eines Selbstaufmerksamkeitsmechanismus

Foto von https://arxiv.org/abs/2205.14135

Wie im obigen Abschnitt erwähnt, ist das Übertragen von Informationen an HBM (Schreiben von S an HBM) und das anschließende Zurückladen von HBM an gCPU, um Softmax zu berechnen, und das anschließende Zurückschreiben an HBM eine Menge an Informationen, die es speichergebundener Vorgang.

Zusammen mit dem Diagramm erklären die folgenden Schritte, wie die Selbstaufmerksamkeit durch Matrixmultiplikation berechnet wird.

Schritt 1:

  • Ich habe das vereinfacht. In der Praxis wird jedes Token mit Positionscodierung hinzugefügt, um Einbettungen zu generieren, die in eine lineare Schicht eingespeist werden, um zu generieren. Zur Veranschaulichung habe ich eine Dimension von 3 verwendet (normalerweise liegt sie zwischen 64 und 128). Dies ist eine Standardeingabe für die Transformer-Architektur.

Schritt 2

  • Schlüssel -> Schlüssel‘ (Transponierung) wird berechnet und mit Abfrage multipliziert, um QK‘ zu erhalten, was N*N ist. Dies enthält die Aufmerksamkeit jedes Tokens mit den übrigen Token. Das folgende Diagramm zeigt auch die Beziehung. Da es sich um Token handelt und wir die Wichtigkeit jedes Tokens im Verhältnis zueinander berechnen müssen, wird die Softmax-Operation zeilenweise angewendet, um sie von 0 -1 zu normalisieren.
  • Dieser Schritt erfordert eine Bewegung zu HBM und ist der teuerste Vorgang wie wir besprochen haben. Das gesamte Flash-Aufmerksamkeitspapier befasst sich mit der Optimierung dieses Prozesses.

Schritt 3

  • Softmax(QK‘) * V wird als endgültige Ausgabematrix berechnet. Die Dimension ist hier dieselbe wie die Eingabeeinbettungen von Schlüssel, Abfrage und Wert.
  • Letzte Zeile in der Ausgabematrix
  • 1*5 bedeutet, dass die Einbettung von „diesem“ geändert werden sollte, um Beziehungen mit anderen Token einzubinden.
  • 2*5 bedeutet, dass die Einbettung von „ist“ geändert werden sollte, um Beziehungen mit anderen Token einzubinden.
  • Dasselbe wie oben für die restlichen Zeilen
Foto des Autors: Illustratives Diagramm zur Funktionsweise des Selbstaufmerksamkeitsmechanismus

Die Grundidee wird durch das folgende Diagramm erklärt, in dem Schlüssel-, Abfrage- und Wertblöcke vom HBM zum SRAM übertragen werden. Durch einige mathematische Methods (siehe unten) ist die hier durchgeführte Berechnung keine ungefähre Antwort, sondern eine tatsächlich richtige.

Mit dieser Implementierung kann Papier die Wall-Pace-Zeit reduzieren, indem es auf Informationen in Blöcken zugreift, ohne die Korrektheit zu beeinträchtigen.

Foto von https://arxiv.org/abs/2205.14135

Algorithmus hinter dem Papier: Wie wird Flash Consideration implementiert?

Dies ist der komplexeste Teil des Dokuments. Lassen Sie uns dieses Downside in Unteraspekte aufteilen und tiefer eintauchen.

Das folgende Diagramm unterteilt die Matrix in Blöcke und zeigt, wie jeder Block zur Berechnung des partiellen Softmax und anschließend des korrekten Softmax verwendet wird.

  • Ersteingabe: Token: Dies ist ein Flash-Consideration-Papier
  • Schlüssel: 4 (Token) x 3 (Dimensionen), Abfrage: 4 (Token) x 3 (Dimensionen) und Wert: 4 (Token) x 3 (Dimensionen)
Bild vom Autor geändert. Originalbild von https://arxiv.org/abs/2205.14135

Schritt 0

  • Angenommen, der Speicher ist 24 Byte groß
  • SRAM wird in 4 Blöcke unterteilt (Abfrage, Schlüssel, Wert und Ausgabematrix)
  • Abfrage, Schlüssel, Wert und Ausgabe erhalten jeweils = 6 Bytes zum Speichern ihrer Informationen (12 Bytes/4)
  • Jede Dimension ist 3, da jede Einbettung nicht gebrochen werden kann, additionally
  • Abfrage: 6 Bytes/ 3 (Dimension) = 2. Gleiches gilt für Wert, Schlüssel und Ausgabe
  • Daher gibt (M/4d) die Größe jedes Blocks an. In diesem Fall beträgt die Blockgröße 2. Das bedeutet, dass 2 Zeilen in den SRAM geladen werden können.
  • Im Allgemeinen beträgt die Blockgröße (M/4d) und die Anzahl der Blöcke (N*4D/M).

Schritt 1 und 2: Unten wird eine Tabelle hinzugefügt, die die Schritte 1 und 2 zur Funktionsweise von Flash Consideration veranschaulicht und die Speicher- und Rechenaspekte davon vergleicht.

Foto vom Autor: Schrittweise Aufschlüsselung der Speicher- und Rechenleistungsnutzung in Flash Achtung

Das folgende Diagramm hilft dabei, die in Flash Consideration verwendete Matrixmultiplikation (Block für Block) zu visualisieren.

Foto des Autors: Illustratives Diagramm zur Funktionsweise des Flash-Consideration-Mechanismus

Was ist der mathematische Aspekt von Softmax?

Einer der kritischsten Aspekte des Dokuments ist, wie das Zerlegen von Matrizen dennoch zur Berechnung der Softmax-Genauigkeit führt. Lassen wir das mathematische Beispiel unten aus, das zeigt, wie zwei verschiedene Matrizen zusammengefasst werden können, um erneut Softmax zu berechnen.

Instinct

  • Dies ist die schöne Eigenschaft von Exponenten, die hier ausgenutzt wird.
  • Jeder Softmax wird einzeln berechnet, aber gleichzeitig wird der Maximalwert der Zeile zusammen mit dem summierten Exponentenwert gespeichert.
  • Beim Zusammenführen mit einer anderen Matrix müssen wir prüfen, wie stark sich das Most vom globalen Most der beiden Matrizen unterscheidet. Und aufgrund des Exponenten werden sowohl Zähler als auch Nenner mit e^(aktuelles_Maximum – globales_Maximum) angepasst, um dies zu berücksichtigen.

Logik ist ziemlich komplex, deshalb wird unten ein Beispiel durchgegangen. Wenn Sie sich mit einem Beispiel vertraut gemacht haben, wird die obige Instinct sehr viel Sinn ergeben.

Foto vom Autor: Beispiel zur Demonstration, wie man eine Matrix in Unterkomponenten aufteilt und diese schließlich kombiniert, um Softmax zu berechnen

Schauen wir uns die Komplexitätsanalyse an, um ein Gefühl dafür zu bekommen, wie sich die Dinge verändert haben

Selbstaufmerksamkeit

  • Während der Berechnung von S = QK‘ wird eine N*N-Matrix erstellt, die zurück zum HRAM übertragen und anschließend aus dem HRAM abgerufen werden muss.
  • Daher ist O(N*N + N*N) = O(N*N) HBM-Zugriff

Blitzlicht

  • Äußere Schleife: Auf Schlüssel und Abfrage wird O(Nd) mal zugegriffen
  • Innere Schleife: Zum Laden von HBM sind nur O(Nd/M) erforderlich, da auf Blöcken gearbeitet wird
  • Insgesamt: O(N*N*d*d/M)
  • In der Praxis ist d viel kleiner als M. d liegt im Bereich von (64–128), während M im Bereich von 100 KB liegt. Daher ist der HBM-Zugriff optimiert
  • Wir begannen mit dem Ziel, den HBM-Zugriff zu optimieren, und mit dieser Komplexitätsanalyse sehen wir, dass das Papier die HBM-Zugriff über den Faktor (d*d/M) ohne Näherung.

So ein komplexes Papier mit enormer Effizienzsteigerung. Ich hoffe, die obige Erklärung vermittelt einen Eindruck davon, wie Flash Consideration die Leistung optimiert und verbessert. Ich habe Block Sparse Flash Consideration noch nicht behandelt. Wie sieht es im Vergleich zu anderen Optimierungstechniken, Forwards Cross Optimization usw. aus? Ich hoffe, das in einem zukünftigen Beitrag behandeln zu können.

Verweise

[ad_2]

]]>
https://chatgpz.de/machine-learning/flash-consideration-schnelle-und-speichereffiziente-exakte-aufmerksamkeit-mit-io-consciousness-ein-tiefer-einblick-von-anish-dubey-mai-2024/feed/ 0 995