
Sharptoken é uma biblioteca C# que serve como uma porta da biblioteca Python Tiktoken. Ele fornece funcionalidade para codificar e decodificar tokens usando codificações baseadas em GPT. Esta biblioteca é construída para .NET 6, .NET 8 e .NET Standard 2.0, tornando -o compatível com uma ampla gama de estruturas.
Importante
A funcionalidade em SharpToken foi adicionada ao Microsoft.ML.Tokenizers . Microsoft.ML.Tokenizers é uma biblioteca de tokenizer que está sendo desenvolvida pela equipe .NET e daqui para frente, o local central para o desenvolvimento do tokenizador na .NET. Ao usar Microsoft.ML.Tokenizers , você deve ver um desempenho aprimorado sobre as implementações da Biblioteca do Tokenizer existentes, incluindo SharpToken . É esperado uma versão estável do Microsoft.ML.Tokenizers ao lado do lançamento .NET 9.0 (novembro de 2024). As instruções para migração podem ser encontradas em https://github.com/dotnet/machinelearning/blob/main/docs/code/microsoft-ml-tokenizers-migration-guide.md.
Para instalar o Sharptoken, use o Nuget Package Manager:
Install-Package SharpTokenOu, se você preferir usar a .NET CLI:
dotnet add package SharpTokenPara mais informações, visite a página do pacote Nuget.
Para usar o Sharptoken em seu projeto, primeiro importe a biblioteca:
using SharpToken ;Em seguida, crie uma instância de gptoncoding especificando a codificação ou modelo desejado:
// Get encoding by encoding name
var encoding = GptEncoding . GetEncoding ( " cl100k_base " ) ;
// Get encoding by model name
var encoding = GptEncoding . GetEncodingForModel ( " gpt-4 " ) ;Você pode usar o método de codificação para codificar uma string:
var encoded = encoding . Encode ( " Hello, world! " ) ; // Output: [9906, 11, 1917, 0]E use o método de decodificação para decodificar os tokens codificados:
var decoded = encoding . Decode ( encoded ) ; // Output: "Hello, world!"Sharptoken também fornece um método de contagem de alto desempenho. É útil verificar o tamanho do prompt antes de enviá -lo para um LLM ou usá -lo em um textsplitter/chunker para rag.
var count = encoding . CountTokens ( " Hello, world! " ) ; // Output: 4 Atualmente, a Sharptoken suporta os seguintes modelos:
r50k_basep50k_basep50k_editcl100k_baseo200k_baseVocê pode usar qualquer um desses modelos ao criar uma instância do GPTEncoding:
var r50kBaseEncoding = GptEncoding . GetEncoding ( " r50k_base " ) ;
var p50kBaseEncoding = GptEncoding . GetEncoding ( " p50k_base " ) ;
var p50kEditEncoding = GptEncoding . GetEncoding ( " p50k_edit " ) ;
var cl100kBaseEncoding = GptEncoding . GetEncoding ( " cl100k_base " ) ;
var o200kBaseEncoding = GptEncoding . GetEncoding ( " o200k_base " ) ;Além de especificar nomes de modelos diretos, o Sharptoken também fornece funcionalidade para mapear nomes de modelos com base em prefixos específicos. Isso permite que os usuários recuperem uma codificação com base no prefixo de um modelo.
Aqui estão os prefixos suportados atuais e suas codificações correspondentes:
| Prefixo do modelo | Codificação |
|---|---|
gpt-4o | o200k_base |
gpt-4- | cl100k_base |
gpt-3.5-turbo- | cl100k_base |
gpt-35-turbo | cl100k_base |
Exemplos de nomes de modelos que se enquadram nesses prefixos incluem:
gpt-4o : gpt-4o , gpt-4o-2024-05-13 , etc.gpt-4- : gpt-4-0314 , gpt-4-32k , etc.gpt-3.5-turbo- : gpt-3.5-turbo-0301 , gpt-3.5-turbo-0401 , etc.gpt-35-turbo . Para recuperar o nome de codificação com base em um nome de modelo ou seu prefixo, você pode usar o método GetEncodingNameForModel :
string encodingName = Model . GetEncodingNameForModel ( " gpt-4-0314 " ) ; // This will return "cl100k_base" Se o nome do modelo fornecido não corresponder a nenhum nome ou prefixo de modelos diretos, o método retornará null .
Quando você codifica uma sequência usando o método de codificação, o valor retornado é uma lista de números inteiros que representam tokens na codificação especificada. Esses tokens são uma maneira compacta de representar o texto de entrada e podem ser processados com mais eficiência por vários algoritmos.
Por exemplo, codificando o texto "Hello World!" O uso da codificação CL100K_BASE pode produzir a seguinte lista de números inteiros:
var encoded = cl100kBaseEncoding . Encode ( " Hello world! " ) ; // Output: [9906, 1917, 0] Você pode usar o método Decode para converter esses valores inteiros tokenizados de volta ao texto original:
var decoded = cl100kBaseEncoding . Decode ( encoded ) ; // Output: "Hello world!" Com o Sharptoken, você pode alternar perfeitamente entre diferentes codificações para encontrar o que melhor atende às suas necessidades. Lembre -se de usar a mesma codificação para os métodos de Encode e Decode para garantir resultados precisos.
O SharpToken permite especificar conjuntos personalizados de tokens especiais permitidos ao codificar o texto. Para fazer isso, passe um hashset contendo os tokens especiais permitidos como um parâmetro para o método da codificação:
const string encodingName = " cl100k_base " ;
const string inputText = " Some Text <|endofprompt|> " ;
var allowedSpecialTokens = new HashSet < string > { " <|endofprompt|> " } ;
var encoding = GptEncoding . GetEncoding ( encodingName ) ;
var encoded = encoding . Encode ( inputText , allowedSpecialTokens ) ;
var expectedEncoded = new List < int > { 8538 , 2991 , 220 , 100276 } ;
Assert . Equal ( expectedEncoded , encoded ) ; Da mesma forma, você pode especificar conjuntos personalizados de tokens especiais não permitidos ao codificar o texto. Passe um HashSet<string> contendo os tokens especiais não permitidos como um parâmetro para o método da codificação:
const string encodingName = " cl100k_base " ;
const string inputText = " Some Text " ;
var encoding = GptEncoding . GetEncoding ( encodingName ) ;
void TestAction ( )
{
encoding . Encode ( inputText , disallowedSpecial : new HashSet < string > { " Some " } ) ;
}
Assert . Throws < ArgumentException > ( TestAction ) ; Neste exemplo, uma ArgumentException é jogada porque o texto de entrada contém um token especial não permitido
O Sharptoken inclui um conjunto de casos de teste no arquivo testplans.txt para garantir sua compatibilidade com a biblioteca Python Tiktoken. Esses casos de teste validam a funcionalidade e o comportamento do Sharptoken, fornecendo uma referência confiável para os desenvolvedores. A execução dos testes de unidade e a verificação dos casos de teste ajuda a manter a consistência entre a biblioteca C# Sharptoken e a implementação original do Python.
Sharptoken é a biblioteca mais rápida com as alocações mais baixas!
[ SimpleJob ( RuntimeMoniker . Net60 ) ]
[ SimpleJob ( RuntimeMoniker . Net80 ) ]
[ SimpleJob ( RuntimeMoniker . Net471 ) ]
[ RPlotExporter ]
[ MemoryDiagnoser ]
public class CompareBenchmark
{
private GptEncoding _sharpToken ;
private TikToken _tikToken ;
private ITokenizer _tokenizer ;
private Tokenizer _mlTokenizer ;
private string _kLongText ;
[ GlobalSetup ]
public async Task Setup ( )
{
_sharpToken = GptEncoding . GetEncoding ( " cl100k_base " ) ;
_tikToken = await TikToken . GetEncodingAsync ( " cl100k_base " ) . ConfigureAwait ( false ) ;
_tokenizer = await TokenizerBuilder . CreateByModelNameAsync ( " gpt-4 " ) . ConfigureAwait ( false ) ;
_kLongText = " King Lear, one of Shakespeare's darkest and most savage plays, tells the story of the foolish and Job-like Lear, who divides his kingdom, as he does his affections, according to vanity and whim. Lear’s failure as a father engulfs himself and his world in turmoil and tragedy. " ;
}
[ Benchmark ]
public int SharpToken ( )
{
var sum = 0 ;
for ( var i = 0 ; i < 10000 ; i ++ )
{
var encoded = _sharpToken . Encode ( _kLongText ) ;
var decoded = _sharpToken . Decode ( encoded ) ;
sum += decoded . Length ;
}
return sum ;
}
[ Benchmark ]
public int TiktokenSharp ( )
{
var sum = 0 ;
for ( var i = 0 ; i < 10000 ; i ++ )
{
var encoded = _tikToken . Encode ( _kLongText ) ;
var decoded = _tikToken . Decode ( encoded ) ;
sum += decoded . Length ;
}
return sum ;
}
[ Benchmark ]
public int TokenizerLib ( )
{
var sum = 0 ;
for ( var i = 0 ; i < 10000 ; i ++ )
{
var encoded = _tokenizer . Encode ( _kLongText ) ;
var decoded = _tokenizer . Decode ( encoded . ToArray ( ) ) ;
sum += decoded . Length ;
}
return sum ;
}
[ Benchmark ]
public int MLTokenizers ( )
{
var sum = 0 ;
for ( var i = 0 ; i < 10000 ; i ++ )
{
var encoded = _mlTokenizer . EncodeToIds ( _kLongText ) ;
var decoded = _mlTokenizer . Decode ( encoded ) ;
sum += decoded . Length ;
}
return sum ;
}
} BenchmarkDotNet v0.13.9+228a464e8be6c580ad9408e98f18813f6407fb5a, Windows 11 (10.0.22631.3296)
11th Gen Intel Core i9-11950H 2.60GHz, 1 CPU, 16 logical and 8 physical cores
.NET SDK 9.0.100-preview.2.24157.14
[Host] : .NET 8.0.3 (8.0.324.11423), X64 RyuJIT AVX2
.NET 6.0 : .NET 6.0.28 (6.0.2824.12007), X64 RyuJIT AVX2
.NET 8.0 : .NET 8.0.3 (8.0.324.11423), X64 RyuJIT AVX2
.NET Framework 4.7.1 : .NET Framework 4.8.1 (4.8.9181.0), X64 RyuJIT VectorSize=256
| Método | Trabalho | Tempo de execução | Significar | Erro | Stddev | Mediana | Gen0 | Gen1 | Alocado |
|---|---|---|---|---|---|---|---|---|---|
| Mltokenizers | .NET 8.0 | .NET 8.0 | 60,55 ms | 1.143 ms | 1.123 ms | 60,45 ms | 1000.0000 | - | 13.12 MB |
| Mltokenizers | .NET 6.0 | .NET 6.0 | 95,75 MS | 1.374 ms | 1.147 ms | 95,54 ms | 10500.0000 | - | 126,19 MB |
| Mltokenizers | .NET Framework 4.7.1 | .NET Framework 4.7.1 | 291.77 MS | 5.811 ms | 11.195 MS | 291.64 MS | 21000.0000 | - | 127,33 MB |
| Sharptoken | .NET 8.0 | .NET 8.0 | 87,78 MS | 1,700 ms | 1,590 ms | 87,34 MS | 1000.0000 | - | 22.13 MB |
| Sharptoken | .NET 6.0 | .NET 6.0 | 128,84 MS | 1,718 ms | 1.607 ms | 128.17 MS | 16250.0000 | 500.0000 | 196.31 MB |
| Sharptoken | .NET Framework 4.7.1 | .NET Framework 4.7.1 | 356.21 ms | 6.843 ms | 10.854 ms | 355,09 ms | 34000.0000 | 1000.0000 | 204,39 MB |
| TokenizerLib | .NET 8.0 | .NET 8.0 | 109,26 ms | 2.082 ms | 4.482 MS | 107,90 ms | 18200.0000 | 600.0000 | 217,82 MB |
| TokenizerLib | .NET 6.0 | .NET 6.0 | 126.16 MS | 2.959 MS | 8.630 ms | 122.34 MS | 18000.0000 | 500.0000 | 217,82 MB |
| TokenizerLib | .NET Framework 4.7.1 | .NET Framework 4.7.1 | 374.71 MS | 7.374 MS | 16.794 MS | 370.12 MS | 40000.0000 | 1000.0000 | 243,79 MB |
| Tiktokensharp | .NET 8.0 | .NET 8.0 | 177,34 MS | 3,506 ms | 8.797 MS | 174,98 MS | 28000.0000 | 1000.0000 | 338,98 MB |
| Tiktokensharp | .NET 6.0 | .NET 6.0 | 196.17 MS | 3.912 ms | 8.422 MS | 195.52 MS | 26000.0000 | 666.6667 | 313.26 MB |
| Tiktokensharp | .NET Framework 4.7.1 | .NET Framework 4.7.1 | 488.22 MS | 9.696 MS | 15.931 MS | 487.17 MS | 63000.0000 | 1000.0000 | 378.31 MB |
Sharptoken é o desempenho extremamente otimizado no Net8.0. Ele usa instruções modernas de CPU multibyte e quase nenhuma alocações de heap.
Todos os métodos principais foram testados em um texto de entrada grande e pequeno.
Entradas:
SmallText : 453 B (texto/liso)LargeText : 51 KB (texto/html)Métodos:
Encode : texto para tokensDecode : tokens para textoCountTokens : API de alto desempenho para contar fichas de texto BenchmarkDotNet v0.13.12, Windows 11 (10.0.22631.3296/23H2/2023Update/SunValley3)
AMD Ryzen 9 3900X, 1 CPU, 24 logical and 12 physical cores
.NET SDK 8.0.200
[Host] : .NET 8.0.2 (8.0.224.6711), X64 RyuJIT AVX2
.NET 6.0 : .NET 6.0.16 (6.0.1623.17311), X64 RyuJIT AVX2
.NET 8.0 : .NET 8.0.2 (8.0.224.6711), X64 RyuJIT AVX2
.NET Framework 4.7.1 : .NET Framework 4.8.1 (4.8.9181.0), X64 RyuJIT VectorSize=256
| Método | Significar | Erro | Stddev | Razão | Razão | Alocado | Razão de alocação |
|---|---|---|---|---|---|---|---|
| .NET 8.0 | |||||||
| Encode_smallText | 22.649 nós | 0,4244 US | 0,4359 EUA | 0,28 | 0,01 | 696 b | 0,02 |
| Encode_largetext | 4.542,505 nós | 87.7988 nós | 104.5182 US | 0,24 | 0,01 | 155547 b | 0,03 |
| Decode_smallText | 1.623 nós | 0,0324 US | 0,0373 US | 0,44 | 0,02 | 2320 b | 0,98 |
| Decode_largetext | 454.570 nós | 6.8980 US | 6.4524 US | 0,80 | 0,02 | 286979 b | 1,00 |
| CountTokens_sMallText | 22.008 nós | 0,1165 US | 0.0909 US | 0,28 | 0,00 | 184 b | 0,005 |
| CountTokens_LargeText | 4.231.353 US | 14.5157 US | 11.3329 EUA | 0,23 | 0,00 | 195 b | 0,000 |
| .NET 6.0 | |||||||
| Encode_smallText | 36.370 nós | 0,7178 US | 1.0962 US | 0,45 | 0,02 | 37344 b | 0,91 |
| Encode_largetext | 11.213.070 nós | 219.6291 US | 269.7243 US | 0,59 | 0,02 | 5062574 b | 0,91 |
| Decode_smallText | 2.588 nós | 0,0394 US | 0,0350 US | 0,70 | 0,02 | 2320 b | 0,98 |
| Decode_largetext | 489.467 US | 8.9195 US | 8.3433 US | 0,86 | 0,02 | 286985 b | 1,00 |
| CountTokens_sMallText | 34.758 nós | 0,2027 US | 0,1896 US | 0,45 | 0,01 | 36832 b | 0,907 |
| CountTokens_LargeText | 11.252.083 nós | 215.8912 US | 212.0340 US | 0,61 | 0,01 | 4907169 b | 0,907 |
| .NET Framework 4.7.1 | |||||||
| Encode_smallText | 79.947 nós | 1.5621 US | 3.0097 nós | 1,00 | 0,00 | 41138 b | 1,00 |
| Encode_largetext | 18.961.252 US | 253.1816 US | 236.8262 US | 1,00 | 0,00 | 5567685 b | 1,00 |
| Decode_smallText | 3.723 nós | 0,0728 US | 0,0997 US | 1,00 | 0,00 | 2375 b | 1,00 |
| Decode_largetext | 570.787 US | 11.0356 US | 11.8080 US | 1,00 | 0,00 | 287496 b | 1,00 |
| CountTokens_sMallText | 77.521 US | 1.0802 US | 0,9020 US | 1,00 | 0,00 | 40616 b | 1.000 |
| CountTokens_LargeText | 18.485.392 nós | 313.5834 US | 277.9836 US | 1,00 | 0,00 | 5413237 b | 1.000 |
Se você encontrar algum problema ou ter sugestões de melhorias, sinta -se à vontade para abrir um problema ou enviar uma solicitação de tração no repositório do projeto.
Espero que você ache o Sharptoken útil para seus projetos e dê as boas -vindas a qualquer feedback que possa ter.