
Sharptoken est une bibliothèque C # qui sert de port de la bibliothèque Python Tiktoken. Il fournit des fonctionnalités pour les jetons de codage et de décodage à l'aide de codages basés sur GPT. Cette bibliothèque est conçue pour .NET 6, .NET 8 et .NET Standard 2.0, ce qui le rend compatible avec une large gamme de frameworks.
Important
La fonctionnalité à SharpToken a été ajoutée à Microsoft.ML.Tokenizers . Microsoft.ML.Tokenizers est une bibliothèque de tokenzer développée par l'équipe .NET et à l'avenir, le lieu central pour le développement de tokenizer dans .NET. En utilisant Microsoft.ML.Tokenizers , vous devriez voir des performances améliorées sur les implémentations de bibliothèque de tokenzer existantes, y compris SharpToken . Une version stable de Microsoft.ML.Tokenizers est attendue parallèlement à la version .NET 9.0 (novembre 2024). Des instructions pour la migration peuvent être trouvées sur https://github.com/dotnet/machinearning/blob/main/docs/code/microsoft-ml-Tokenizers-Migration-Guide.md.
Pour installer Sharptoken, utilisez le gestionnaire de packages NuGet:
Install-Package SharpTokenOu, si vous préférez utiliser la CLI .net:
dotnet add package SharpTokenPour plus d'informations, visitez la page Package NuGet.
Pour utiliser Sharptoken dans votre projet, importez d'abord la bibliothèque:
using SharpToken ;Ensuite, créez une instance de gptencoding en spécifiant le codage ou le modèle souhaité:
// Get encoding by encoding name
var encoding = GptEncoding . GetEncoding ( " cl100k_base " ) ;
// Get encoding by model name
var encoding = GptEncoding . GetEncodingForModel ( " gpt-4 " ) ;Vous pouvez ensuite utiliser la méthode d'encodage pour coder une chaîne:
var encoded = encoding . Encode ( " Hello, world! " ) ; // Output: [9906, 11, 1917, 0]Et utilisez la méthode de décodage pour décoder les jetons codés:
var decoded = encoding . Decode ( encoded ) ; // Output: "Hello, world!"Sharptoken fournit également une méthode de nombre élevé de performances. Il est utile de vérifier la taille de l'invite avant de l'envoyer dans un LLM ou de l'utiliser dans un TextsPlitter / Chunker pour RAG.
var count = encoding . CountTokens ( " Hello, world! " ) ; // Output: 4 Sharptoken prend actuellement en charge les modèles suivants:
r50k_basep50k_basep50k_editcl100k_baseo200k_baseVous pouvez utiliser l'un de ces modèles lors de la création d'une instance de 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 " ) ;Outre la spécification des noms de modèles directs, SharpToken fournit également des fonctionnalités pour cartographier des noms de modèle basés sur des préfixes spécifiques. Cela permet aux utilisateurs de récupérer un encodage en fonction du préfixe d'un modèle.
Voici les préfixes pris en charge actuels et leurs encodages correspondants:
| Préfixe modèle | Codage |
|---|---|
gpt-4o | o200k_base |
gpt-4- | cl100k_base |
gpt-3.5-turbo- | cl100k_base |
gpt-35-turbo | cl100k_base |
Des exemples de noms de modèles qui relèvent de ces préfixes comprennent:
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 . Pour récupérer le nom de codage en fonction d'un nom de modèle ou de son préfixe, vous pouvez utiliser la méthode GetEncodingNameForModel :
string encodingName = Model . GetEncodingNameForModel ( " gpt-4-0314 " ) ; // This will return "cl100k_base" Si le nom du modèle fourni ne correspond à aucun nom ou préfixe de modèle direct, la méthode renvoie null .
Lorsque vous codez une chaîne à l'aide de la méthode d'encodage, la valeur retournée est une liste d'entiers qui représentent des jetons dans le codage spécifié. Ces jetons sont une manière compacte de représenter le texte d'entrée et peuvent être traitées plus efficacement par divers algorithmes.
Par exemple, encodant le texte "Hello World!" L'utilisation du codage CL100K_BASE peut produire la liste des entiers suivants:
var encoded = cl100kBaseEncoding . Encode ( " Hello world! " ) ; // Output: [9906, 1917, 0] Vous pouvez ensuite utiliser la méthode Decode pour convertir ces valeurs entières tokenisées dans le texte d'origine:
var decoded = cl100kBaseEncoding . Decode ( encoded ) ; // Output: "Hello world!" Avec Sharptoken, vous pouvez basculer de manière transparente entre différents encodages pour trouver celui qui convient le mieux à vos besoins. N'oubliez pas d'utiliser le même codage pour les méthodes Encode et Decode pour garantir des résultats précis.
Sharptoken vous permet de spécifier des ensembles personnalisés de jetons spéciaux autorisés lors du codage du texte. Pour ce faire, passer un hashset contenant les jetons spéciaux autorisés comme paramètre à la méthode d'encoder:
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 ) ; De même, vous pouvez spécifier des ensembles personnalisés de jetons spéciaux refusés lors du codage du texte. Passez un HashSet<string> contenant les jetons spéciaux refusés comme paramètre à la méthode d'encodage:
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 ) ; Dans cet exemple, un ArgumentException est lancé parce que le texte d'entrée contient un jeton spécial refusé
Sharptoken comprend un ensemble de cas de test dans le fichier TestPlans.txt pour assurer sa compatibilité avec la bibliothèque Python Tiktoken. Ces cas de test valident la fonctionnalité et le comportement de Sharptoken, fournissant une référence fiable pour les développeurs. L'exécution des tests unitaires et la vérification des cas de test aident à maintenir la cohérence entre la bibliothèque C # Sharptoken et l'implémentation d'origine Python.
Sharptoken est la bibliothèque la plus rapide avec les allocations les plus basses!
[ 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éthode | Emploi | Temps d'exécution | Signifier | Erreur | Stddev | Médian | Gen0 | Gen1 | Alloué |
|---|---|---|---|---|---|---|---|---|---|
| Mltenkeisers | .NET 8.0 | .NET 8.0 | 60,55 ms | 1,143 ms | 1,123 ms | 60,45 ms | 1000.0000 | - | 13,12 Mb |
| Mltenkeisers | .NET 6.0 | .NET 6.0 | 95,75 ms | 1,374 ms | 1,147 ms | 95,54 ms | 10500.0000 | - | 126,19 MB |
| Mltenkeisers | .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 est extrêmement optimisé des performances sur Net8.0. Il utilise des instructions de processeur multi-gobete modernes et presque aucune allocation de tas.
Toutes les méthodes de base ont été testées sur un grand et un petit texte d'entrée.
Entrées:
SmallText : 453 b (texte / plaine)LargeText : 51 kb (texte / html)Méthodes:
Encode : texte en jetonsDecode : jetons au texteCountTokens : API haute performance pour compter les jetons de texte 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éthode | Signifier | Erreur | Stddev | Rapport | Ratiosd | Alloué | Ratio alloc |
|---|---|---|---|---|---|---|---|
| .NET 8.0 | |||||||
| Encode_smallText | 22.649 US | 0,4244 US | 0,4359 US | 0,28 | 0,01 | 696 b | 0,02 |
| Encode_largetExt | 4 542,505 États-Unis | 87.7988 US | 104.5182 US | 0,24 | 0,01 | 155547 b | 0,03 |
| Decode_smalltext | 1.623 US | 0,0324 US | 0,0373 US | 0,44 | 0,02 | 2320 b | 0,98 |
| Decode_largetExt | 454.570 US | 6.8980 US | 6.4524 US | 0,80 | 0,02 | 286979 b | 1,00 |
| CountTokens_smallText | 22.008 US | 0,1165 US | 0,0909 US | 0,28 | 0,00 | 184 b | 0,005 |
| CountTokens_LargetExt | 4 231,353 États-Unis | 14.5157 US | 11.3329 US | 0,23 | 0,00 | 195 b | 0.000 |
| .NET 6.0 | |||||||
| Encode_smallText | 36.370 US | 0,7178 US | 1.0962 US | 0,45 | 0,02 | 37344 b | 0,91 |
| Encode_largetExt | 11 213,070 États-Unis | 219.6291 US | 269.7243 US | 0,59 | 0,02 | 5062574 B | 0,91 |
| Decode_smalltext | 2,588 US | 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 US | 0,2027 US | 0.1896 US | 0,45 | 0,01 | 36832 b | 0,907 |
| CountTokens_LargetExt | 11 252,083 États-Unis | 215.8912 US | 212.0340 US | 0,61 | 0,01 | 4907169 b | 0,907 |
| .NET Framework 4.7.1 | |||||||
| Encode_smallText | 79.947 US | 1.5621 US | 3.0097 US | 1,00 | 0,00 | 41138 b | 1,00 |
| Encode_largetExt | 18 961,252 États-Unis | 253.1816 US | 236.8262 US | 1,00 | 0,00 | 5567685 b | 1,00 |
| Decode_smalltext | 3,723 US | 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 États-Unis | 313.5834 US | 277.9836 US | 1,00 | 0,00 | 5413237 B | 1.000 |
Si vous rencontrez des problèmes ou avez des suggestions d'amélioration, n'hésitez pas à ouvrir un problème ou à soumettre une demande de traction sur le référentiel du projet.
J'espère que vous trouverez Sharptoken utile pour vos projets et accueillez les commentaires que vous pourriez avoir.