diff --git a/SUMMARY.md b/SUMMARY.md index 33ae4e36e..d1df1089d 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -838,6 +838,7 @@ * [Low-Power Wide Area Network](todo/radio-hacking/low-power-wide-area-network.md) * [Pentesting BLE - Bluetooth Low Energy](todo/radio-hacking/pentesting-ble-bluetooth-low-energy.md) * [Industrial Control Systems Hacking](todo/industrial-control-systems-hacking/README.md) +* [LLM Training](todo/llm-training.md) * [Burp Suite](todo/burp-suite.md) * [Other Web Tricks](todo/other-web-tricks.md) * [Interesting HTTP](todo/interesting-http.md) diff --git a/todo/llm-training.md b/todo/llm-training.md new file mode 100644 index 000000000..fc8090b7c --- /dev/null +++ b/todo/llm-training.md @@ -0,0 +1,46 @@ +# LLM Training + +## Tokenizing + +Tokenizing consiste nel separare i dati in specifici chunk e assegnare loro ID specifici (numeri).\ +Un tokenizer molto semplice per i testi potrebbe semplicemente prendere ogni parola di un testo separatamente, e anche i simboli di punteggiatura e rimuovere gli spazi.\ +Pertanto, `"Hello, world!"` sarebbe: `["Hello", ",", "world", "!"]` + +Poi, per assegnare a ciascuna delle parole e simboli un token ID (numero), è necessario creare il **vocabolario** del tokenizer. Se stai tokenizzando, ad esempio, un libro, questo potrebbe essere **tutte le diverse parole del libro** in ordine alfabetico con alcuni token extra come: + +* `[BOS] (Inizio della sequenza)`: Posizionato all'inizio di un testo, indica l'inizio di un testo (usato per separare testi non correlati). +* `[EOS] (Fine della sequenza)`: Posizionato alla fine di un testo, indica la fine di un testo (usato per separare testi non correlati). +* `[PAD] (padding)`: Quando una dimensione del batch è maggiore di uno (di solito), questo token è usato per aumentare la lunghezza di quel batch per essere grande come gli altri. +* `[UNK] (sconosciuto)`: Per rappresentare parole sconosciute. + +Seguendo l'esempio, avendo tokenizzato un testo assegnando a ciascuna parola e simbolo del testo una posizione nel vocabolario, la frase tokenizzata `"Hello, world!"` -> `["Hello", ",", "world", "!"]` sarebbe qualcosa come: `[64, 455, 78, 467]` supponendo che `Hello` sia alla posizione 64, "`,"` sia alla posizione `455`... nell'array del vocabolario risultante. + +Tuttavia, se nel testo usato per generare il vocabolario la parola `"Bye"` non esistesse, questo risulterebbe in: `"Bye, world!"` -> `["[UNK]", ",", "world", "!"]` -> `[987, 455, 78, 467]` supponendo che il token per `[UNK]` sia a 987. + +### BPE - Byte Pair Encoding + +Per evitare problemi come la necessità di tokenizzare tutte le possibili parole per i testi, i LLM come GPT utilizzano BPE che fondamentalmente **codifica coppie di byte frequenti** per ridurre la dimensione del testo in un formato più ottimizzato fino a quando non può essere ridotto ulteriormente (controlla [**wikipedia**](https://en.wikipedia.org/wiki/Byte\_pair\_encoding)). Nota che in questo modo non ci sono parole "sconosciute" per il vocabolario e il vocabolario finale sarà tutti i set scoperti di byte frequenti raggruppati il più possibile mentre i byte che non sono frequentemente collegati con lo stesso byte saranno un token a sé. + +## Data Sampling + +I LLM come GPT funzionano prevedendo la parola successiva basata su quelle precedenti, quindi per preparare alcuni dati per l'addestramento è necessario preparare i dati in questo modo. + +Ad esempio, usando il testo "Lorem ipsum dolor sit amet, consectetur adipiscing elit," + +Per preparare il modello ad apprendere a prevedere la parola successiva (supponendo che ogni parola sia un token usando il tokenizer molto basilare), e usando una dimensione massima di 4 e una finestra mobile di 1, questo è come il testo dovrebbe essere preparato: +```javascript +Input: [ +["Lorem", "ipsum", "dolor", "sit"], +["ipsum", "dolor", "sit", "amet,"], +["dolor", "sit", "amet,", "consectetur"], +["sit", "amet,", "consectetur", "adipiscing"], +], +Target: [ +["ipsum", "dolor", "sit", "amet,"], +["dolor", "sit", "amet,", "consectetur"], +["sit", "amet,", "consectetur", "adipiscing"], +["amet,", "consectetur", "adipiscing", "elit,"], +["consectetur", "adipiscing", "elit,", "sed"], +] +``` +Nota che se la finestra scorrevole fosse stata 2, significa che la prossima voce nell'array di input inizierà 2 token dopo e non solo uno, ma l'array target continuerà a prevedere solo 1 token. In pytorch, questa finestra scorrevole è espressa nel parametro `stride`.