
SharPtoken es una biblioteca C# que sirve como un puerto de la biblioteca de Python Tiktoken. Proporciona funcionalidad para codificar y decodificar tokens utilizando codificaciones basadas en GPT. Esta biblioteca está construida para .NET 6, .NET 8 y .NET Standard 2.0, lo que la hace compatible con una amplia gama de marcos.
Importante
La funcionalidad en SharpToken se ha agregado a Microsoft.ML.Tokenizers . Microsoft.ML.Tokenizers es una biblioteca de tokenizador desarrollada por el equipo de .NET y en el futuro, el lugar central para el desarrollo de tokenizer en .NET. Al usar Microsoft.ML.Tokenizers , debe ver un rendimiento mejorado sobre las implementaciones de biblioteca de tokenizer existentes, incluida SharpToken . Se espera una versión estable de Microsoft.ML.Tokenizers junto con la versión .NET 9.0 (noviembre de 2024). Las instrucciones para la migración se pueden encontrar en https://github.com/dotnet/machinelearning/blob/main/docs/code/microsoft-ml-tokenizers-migration-guide.md.
Para instalar SharPtoken, use el Administrador de paquetes Nuget:
Install-Package SharpTokenO, si prefiere usar el .net CLI:
dotnet add package SharpTokenPara obtener más información, visite la página del paquete Nuget.
Para usar SharPtoken en su proyecto, primero importe la biblioteca:
using SharpToken ;A continuación, cree una instancia de gpTencoding especificando la codificación o modelo deseado:
// Get encoding by encoding name
var encoding = GptEncoding . GetEncoding ( " cl100k_base " ) ;
// Get encoding by model name
var encoding = GptEncoding . GetEncodingForModel ( " gpt-4 " ) ;Luego puede usar el método de codificación para codificar una cadena:
var encoded = encoding . Encode ( " Hello, world! " ) ; // Output: [9906, 11, 1917, 0]Y use el método de decodificación para decodificar los tokens codificados:
var decoded = encoding . Decode ( encoded ) ; // Output: "Hello, world!"SharPtoken también proporciona un método de recuento de alto rendimiento. Es útil verificar el tamaño de inmediato antes de enviarlo a un LLM o usarlo en un bolso de texto/quunker para RAG.
var count = encoding . CountTokens ( " Hello, world! " ) ; // Output: 4 SharPtoken actualmente admite los siguientes modelos:
r50k_basep50k_basep50k_editcl100k_baseo200k_basePuede usar cualquiera de estos modelos al crear una instancia 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 " ) ;Además de especificar nombres de modelos directos, SharPtoken también proporciona funcionalidad para asignar nombres de modelos basados en prefijos específicos. Esto permite a los usuarios recuperar una codificación basada en el prefijo de un modelo.
Aquí están los prefijos compatibles actuales y sus codificaciones correspondientes:
| Prefijo modelo | Codificación |
|---|---|
gpt-4o | o200k_base |
gpt-4- | cl100k_base |
gpt-3.5-turbo- | cl100k_base |
gpt-35-turbo | cl100k_base |
Los ejemplos de nombres de modelos que caen en estos prefijos incluyen:
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 el nombre de codificación basado en un nombre de modelo o en su prefijo, puede usar el método GetEncodingNameForModel :
string encodingName = Model . GetEncodingNameForModel ( " gpt-4-0314 " ) ; // This will return "cl100k_base" Si el nombre del modelo proporcionado no coincide con ningún nombre de modelo directo o prefijos, el método devolverá null .
Cuando codifica una cadena usando el método de codificación, el valor devuelto es una lista de enteros que representan tokens en la codificación especificada. Estos tokens son una forma compacta de representar el texto de entrada y pueden procesarse de manera más eficiente por varios algoritmos.
Por ejemplo, codificando el texto "¡Hola mundo!" El uso de la codificación CL100K_BASE puede producir la siguiente lista de enteros:
var encoded = cl100kBaseEncoding . Encode ( " Hello world! " ) ; // Output: [9906, 1917, 0] Luego puede usar el método Decode para convertir estos valores enteros tokenizados nuevamente en el texto original:
var decoded = cl100kBaseEncoding . Decode ( encoded ) ; // Output: "Hello world!" Con Sharptoken, puede cambiar sin problemas entre diferentes codificaciones para encontrar la que mejor se adapte a sus necesidades. Solo recuerde usar la misma codificación para los métodos Encode y Decode para garantizar resultados precisos.
SharPtoken le permite especificar conjuntos personalizados de tokens especiales permitidos al codificar el texto. Para hacer esto, pase un hashset que contenga los tokens especiales permitidos como parámetro para el método de codificación:
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 ) ; Del mismo modo, puede especificar conjuntos personalizados de tokens especiales no permitidos al codificar el texto. Pase un HashSet<string> que contiene los tokens especiales no permitidos como parámetro para el método de codificación:
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 ) ; En este ejemplo, se lanza una ArgumentException porque el texto de entrada contiene un token especial no permitido
SharPtoken incluye un conjunto de casos de prueba en el archivo testplans.txt para garantizar su compatibilidad con la biblioteca Python Tiktoken. Estos casos de prueba validan la funcionalidad y el comportamiento de SharPtoken, proporcionando una referencia confiable para los desarrolladores. Ejecutar las pruebas unitarias y verificar los casos de prueba ayuda a mantener la consistencia entre la biblioteca C# Sharptoken y la implementación original de Python.
¡Sharptoken es la biblioteca más rápida con las asignaciones más bajas!
[ 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 | Trabajo | Tiempo de ejecución | Significar | Error | Stddev | Mediana | Gen0 | Gen1 | Asignado |
|---|---|---|---|---|---|---|---|---|---|
| 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 está optimizado por el rendimiento extramericano en Net8.0. Utiliza instrucciones modernas de CPU multibyte y casi no hay asignaciones de montón.
Todos los métodos centrales se han probado en un texto de entrada grande y pequeño.
Entradas:
SmallText : 453 B (texto/simple)LargeText : 51 kb (texto/html)Métodos:
Encode : texto a tokensDecode : Tokens to TextCountTokens : API de alto rendimiento para contar tokens 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 | Error | Stddev | Relación | Ratiosd | Asignado | Asignación de la relación |
|---|---|---|---|---|---|---|---|
| .NET 8.0 | |||||||
| Encode_smallText | 22.649 nosotros | 0.4244 EE. UU. | 0.4359 EE. UU. | 0.28 | 0.01 | 696 B | 0.02 |
| Encode_largetext | 4,542.505 EE. UU. | 87.7988 EE. UU. | 104.5182 EE. UU. | 0.24 | 0.01 | 155547 b | 0.03 |
| Decode_smallText | 1.623 EE. UU. | 0.0324 US | 0.0373 US | 0.44 | 0.02 | 2320 b | 0.98 |
| Decode_largetext | 454.570 EE. UU. | 6.8980 US | 6.4524 EE. UU. | 0.80 | 0.02 | 286979 b | 1.00 |
| CountTokens_smallText | 22.008 EE. UU. | 0.1165 US | 0.0909 EE. UU. | 0.28 | 0.00 | 184 B | 0.005 |
| CountTokens_LarGetext | 4,231.353 EE. UU. | 14.5157 EE. UU. | 11.3329 EE. UU. | 0.23 | 0.00 | 195 b | 0.000 |
| .NET 6.0 | |||||||
| Encode_smallText | 36.370 EE. UU. | 0.7178 US | 1.0962 EE. UU. | 0.45 | 0.02 | 37344 b | 0.91 |
| Encode_largetext | 11,213.070 US | 219.6291 EE. UU. | 269.7243 EE. UU. | 0.59 | 0.02 | 5062574 b | 0.91 |
| Decode_smallText | 2.588 EE. UU. | 0.0394 EE. UU. | 0.0350 US | 0.70 | 0.02 | 2320 b | 0.98 |
| Decode_largetext | 489.467 EE. UU. | 8.9195 EE. UU. | 8.3433 EE. UU. | 0.86 | 0.02 | 286985 b | 1.00 |
| CountTokens_smallText | 34.758 EE. UU. | 0.2027 US | 0.1896 EE. UU. | 0.45 | 0.01 | 36832 b | 0.907 |
| CountTokens_LarGetext | 11,252.083 EE. UU. | 215.8912 EE. UU. | 212.0340 US | 0.61 | 0.01 | 4907169 b | 0.907 |
| .NET Framework 4.7.1 | |||||||
| Encode_smallText | 79.947 EE. UU. | 1.5621 EE. UU. | 3.0097 EE. UU. | 1.00 | 0.00 | 41138 b | 1.00 |
| Encode_largetext | 18,961.252 EE. UU. | 253.1816 EE. UU. | 236.8262 EE. UU. | 1.00 | 0.00 | 5567685 b | 1.00 |
| Decode_smallText | 3.723 EE. UU. | 0.0728 US | 0.0997 US | 1.00 | 0.00 | 2375 b | 1.00 |
| Decode_largetext | 570.787 EE. UU. | 11.0356 EE. UU. | 11.8080 EE. UU. | 1.00 | 0.00 | 287496 b | 1.00 |
| CountTokens_smallText | 77.521 EE. UU. | 1.0802 EE. UU. | 0.9020 US | 1.00 | 0.00 | 40616 b | 1.000 |
| CountTokens_LarGetext | 18,485.392 EE. UU. | 313.5834 EE. UU. | 277.9836 EE. UU. | 1.00 | 0.00 | 5413237 b | 1.000 |
Si encuentra algún problema o tiene sugerencias de mejoras, no dude en abrir un problema o enviar una solicitud de extracción en el repositorio del proyecto.
Espero que encuentre útil a Sharptoken para sus proyectos y agradezca cualquier comentario que pueda tener.