A arte do design imediato: limites imediatos e recuperação de tokens
Este (escrito em conjunto com Marco Tulio Ribeiro ) é a parte 2 de uma série sobre a arte do prompt design (parte 1 aqui ), onde falamos sobre o controle de large language models (LLMs) com guidance
.
Nesta postagem, discutiremos como os métodos de tokenização gananciosos usados por modelos de linguagem podem introduzir um viés sutil e poderoso em seus prompts, levando a gerações confusas.
Os modelos de linguagem não são treinados em texto bruto, mas sim em tokens, que são blocos de texto que geralmente ocorrem juntos, semelhantes a palavras. Isso afeta a forma como os modelos de linguagem 'vêem' o texto, incluindo prompts (já que os prompts são apenas conjuntos de tokens). Os modelos de estilo GPT utilizam métodos de tokenização como Byte Pair Encoding (BPE), que mapeia todos os bytes de entrada para IDs de token de maneira gananciosa. Isso é bom para treinamento, mas pode levar a problemas sutis durante a inferência, conforme mostrado no exemplo abaixo.
Um exemplo de um problema de limite imediato
Considere o seguinte exemplo, onde estamos tentando gerar uma string de 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'))
Embora as URLs em treinamento sejam codificadas com o token 1358 ( ://
), nosso prompt faz com que o LLM veja o token 27
( :
), o que elimina a conclusão ao dividir artificialmente ://
.
Na verdade, o modelo pode ter certeza de que ver token 27
( :
) significa que o que vem a seguir é muito improvável que seja algo que possa ter sido codificado junto com os dois pontos usando um “token mais longo” como ://
, já que nos dados de treinamento do modelo esses caracteres seriam foram codificadas junto com os dois pontos (uma exceção a isso que discutiremos mais tarde é a regularização de subpalavras durante o treinamento). O fato de que ver um token significa ver a incorporação desse token e também que tudo o que vem a seguir não foi compactado pelo tokenizer ganancioso é fácil de esquecer, mas é importante nos limites do prompt.
Vamos pesquisar a representação de string de todos os tokens no vocabulário do modelo para ver quais começam com dois pontos:
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(" ["))
Corrigindo viés não intencional com “recuperação de token”
O que podemos fazer para evitar esses preconceitos não intencionais? Uma opção é sempre terminar nossos prompts com tokens que não podem ser estendidos em tokens mais longos (por exemplo, uma tag de função para modelos baseados em chat), mas essa é uma limitação severa.
Em vez disso, guidance
tem um recurso chamado “recuperação de token”, que automaticamente faz o backup do processo de geração por um token antes do final do prompt e, em seguida, restringe o primeiro token gerado a ter um prefixo que corresponda ao último token no prompt. Em nosso exemplo de URL, isso significaria remover o :
e forçar a geração do primeiro token para ter um :
prefixo. A recuperação de token permite que os usuários expressem prompts da maneira que desejarem, sem se preocupar com limites de token.
Por exemplo, vamos reexecutar alguns dos exemplos de URL acima com a recuperação de token ativada (é ativada por padrão para os modelos do Transformer, então removemos 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 você está familiarizado com a forma como os modelos de linguagem são treinados, pode estar se perguntando como a regularização de subpalavras se encaixa em tudo isso. A regularização de subpalavras é uma técnica em que, durante o treinamento, tokenizações subótimas são introduzidas aleatoriamente para aumentar a robustez do modelo. Isso significa que o modelo nem sempre vê a melhor tokenização gananciosa. A regularização de subpalavras é ótima para ajudar o modelo a ser mais robusto em relação aos limites de token, mas não remove completamente o viés que o modelo tem em relação à tokenização gananciosa padrão. Isso significa que, embora dependendo da quantidade de regularização de subpalavra durante o treinamento, os modelos possam exibir mais ou menos viés de limites de token, todos os modelos ainda têm esse viés. E, como mostrado acima, ainda pode ter um impacto poderoso e inesperado na saída do modelo.
Conclusão
Ao escrever prompts, lembre-se de que a tokenização gulosa pode ter um impacto significativo em como os modelos de linguagem interpretam seus prompts, especialmente quando o prompt termina com um token que pode ser estendido em um token mais longo. Essa fonte de viés fácil de perder pode afetar seus resultados de maneiras surpreendentes e não intencionais.
Para lidar com isso, termine seu prompt com um token não extensível ou use algo como guidance
o recurso de "cura de token" para que você possa expressar seus prompts da maneira que desejar, sem se preocupar com artefatos de limite de token.
Para reproduzir você mesmo os resultados deste artigo, verifique a versão para notebook .