L'arte del design tempestivo: confini tempestivi e guarigione dei token

May 09 2023
Questa (scritta insieme a Marco Tulio Ribeiro) è la seconda parte di una serie sull'arte del prompt design (parte 1 qui), in cui si parla del controllo dei grandi modelli linguistici (LLM) con una guida. In questo post, discuteremo di come gli avidi metodi di tokenizzazione utilizzati dai modelli linguistici possono introdurre un pregiudizio sottile e potente nei tuoi suggerimenti, portando a generazioni sconcertanti.
Tutte le immagini sono creazioni originali.

Questa (scritta insieme a Marco Tulio Ribeiro ) è la seconda parte di una serie sull'arte del prompt design (parte 1 qui ), in cui si parla del controllo di modelli di linguaggio di grandi dimensioni (LLM) con guidance.

In questo post, discuteremo di come gli avidi metodi di tokenizzazione utilizzati dai modelli linguistici possono introdurre un pregiudizio sottile e potente nei tuoi suggerimenti, portando a generazioni sconcertanti.

I modelli linguistici non vengono addestrati sul testo grezzo, ma piuttosto sui token, che sono pezzi di testo che spesso si presentano insieme, simili alle parole. Ciò influisce sul modo in cui i modelli linguistici "vedono" il testo, inclusi i prompt (poiché i prompt sono solo insiemi di token). I modelli in stile GPT utilizzano metodi di tokenizzazione come Byte Pair Encoding (BPE), che mappano tutti i byte di input agli ID token in modo avido. Questo va bene per l'addestramento, ma può portare a problemi sottili durante l'inferenza, come mostrato nell'esempio seguente.

Un esempio di un problema al contorno del prompt

Considera il seguente esempio, in cui stiamo cercando di generare una stringa URL HTTP:

import guidance

# we use StableLM as an example, but these issues impact all models to varying degrees
guidance.llm = guidance.llms.Transformers("stabilityai/stablelm-base-alpha-3b", device=0)

# we turn token healing off so that guidance acts like a normal prompting library
program = guidance('The link is <a href="http:{{gen max_tokens=10 token_healing=False}}')
program()

      
                
Notebook output.

guidance('The link is <a href="http{{gen max_tokens=10 token_healing=False}}')()

      
                

print_tokens(guidance.llm.encode('The link is <a href="http:'))

      
                

print_tokens(guidance.llm.encode('The link is <a href="http://www.google.com/search?q'))

      
                

Mentre gli URL in addestramento sono codificati con il token 1358 ( ://), il nostro prompt fa invece in modo che l'LLM veda il token 27( :), che annulla il completamento suddividendo artificialmente ://.

In effetti, il modello può essere abbastanza sicuro che vedere token 27( :) significhi che ciò che viene dopo è molto improbabile che sia stato codificato insieme ai due punti utilizzando un "token più lungo" come ://, poiché nei dati di addestramento del modello quei caratteri sarebbero sono stati codificati insieme ai due punti (un'eccezione a ciò che discuteremo più avanti è la regolarizzazione delle sottoparole durante l'addestramento). Il fatto che vedere un token significhi sia vedere l'incorporamento di quel token sia anche che tutto ciò che viene dopo non è stato compresso dall'avido tokenizer è facile da dimenticare, ma è importante nei limiti rapidi.

Cerchiamo nella rappresentazione di stringa di tutti i token nel vocabolario del modello, per vedere quali iniziano con i due punti:

print_tokens(guidance.llm.prefix_matches(":"))

      
                

print_tokens(guidance.llm.prefix_matches("http"))

      
                

# Accidentally adding a space, will lead to weird generation
guidance('I read a book about {{gen max_tokens=5 token_healing=False temperature=0}}')()

      
                
# No space, works as expected guidance('I read a book about{{gen max_tokens=5 token_healing=False temperature=0}}')()

guidance('An example ["like this"] and another example [{{gen max_tokens=10 token_healing=False}}')()

      
                

print_tokens(guidance.llm.prefix_matches(" ["))

      
                

Risolvere pregiudizi involontari con la "guarigione dei token"

Cosa possiamo fare per evitare questi pregiudizi involontari? Un'opzione è terminare sempre i nostri prompt con token che non possono essere estesi in token più lunghi (ad esempio un tag di ruolo per i modelli basati su chat), ma questa è una grave limitazione.

Al contrario, guidanceha una funzione chiamata "guarigione token", che esegue automaticamente il backup del processo di generazione di un token prima della fine del prompt, quindi vincola il primo token generato ad avere un prefisso che corrisponda all'ultimo token nel prompt. Nel nostro esempio di URL, ciò significherebbe rimuovere :e forzare la generazione del primo token in modo che abbia un :prefisso. La guarigione del token consente agli utenti di esprimere i prompt come desiderano, senza preoccuparsi dei limiti del token.

Ad esempio, eseguiamo nuovamente alcuni degli esempi di URL sopra con la correzione dei token attivata (è attiva per impostazione predefinita per i modelli Transformer, quindi rimuoviamo token_healing=False):

# With token healing we generate valid URLs,
# even when the prompt ends with a colon:
guidance('The link is <a href="http:{{gen max_tokens=10}}')()

      
                
# With token healing, we will sometimes generate https URLs, # even when the prompt ends with "http": program = guidance('''The link is <a href="http{{gen 'completions' max_tokens=10 n=10 temperature=1}}''') program()["completions"]

# Accidentally adding a space will not impact generation
program = guidance('''I read a book about {{gen max_tokens=5 temperature=0}}''')
program()

      
                
# This will generate the same text as above program = guidance('''I read a book about{{gen max_tokens=6 temperature=0}}''') program()

guidance('An example ["like this"] and another example [{{gen max_tokens=10}}')()

      
                

Se hai familiarità con il modo in cui vengono addestrati i modelli linguistici, potresti chiederti come si inserisce la regolarizzazione delle sottoparole in tutto questo. La regolarizzazione delle sottoparole è una tecnica in cui durante l'addestramento vengono introdotte casualmente tokenizzazioni non ottimali per aumentare la robustezza del modello. Ciò significa che il modello non vede sempre la migliore tokenizzazione avida. La regolarizzazione delle sottoparole è ottima per aiutare il modello a essere più robusto rispetto ai limiti dei token, ma non rimuove del tutto il pregiudizio che il modello ha nei confronti della tokenizzazione avida standard. Ciò significa che mentre, a seconda della quantità di regolarizzazione delle sottoparole durante l'addestramento, i modelli possono mostrare più o meno pregiudizi sui limiti dei token, tutti i modelli hanno ancora questo pregiudizio. E come mostrato sopra può ancora avere un impatto potente e inaspettato sull'output del modello.

Conclusione

Quando scrivi prompt, ricorda che la tokenizzazione avida può avere un impatto significativo sul modo in cui i modelli linguistici interpretano i tuoi prompt, in particolare quando il prompt termina con un token che potrebbe essere esteso in un token più lungo. Questa fonte di distorsione facile da perdere può influire sui risultati in modi sorprendenti e non intenzionali.

Per risolvere questo problema, terminare il prompt con un token non estendibile o utilizzare qualcosa come guidancela funzione "token healing" di in modo da poter esprimere i prompt come si desidera, senza preoccuparsi degli artefatti del limite del token.

Per riprodurre tu stesso i risultati in questo articolo, dai un'occhiata alla versione per notebook .