
Sharptoken是一个C#图书馆,用作Python Tiktoken库的港口。它提供了使用基于GPT的编码来编码和解码令牌的功能。该库是为.NET 6,.NET 8和.NET标准2.0构建的,使其与广泛的框架兼容。
重要的
SharpToken中的功能已添加到Microsoft.ML.Tokenizers中。 Microsoft.ML.Tokenizers是一个由.NET团队开发的令牌库,并将其展开,这是.NET中的引物开发的中心地点。通过使用Microsoft.ML.Tokenizers ,您应该看到比现有的令牌库实现(包括SharpToken的性能改进。预计Microsoft.ML.Tokenizers的稳定版本与.NET 9.0版本(2024年11月)。可以在https://github.com/dotnet/machinelearning/blob/main/main/docs/code/microsoft-mlosoft-ml-tokenizers-migration-migration-guide.md上找到迁移的说明。
要安装Sharptoken,请使用Nuget软件包管理器:
Install-Package SharpToken或者,如果您喜欢使用.NET CLI:
dotnet add package SharpToken有关更多信息,请访问Nuget软件包页面。
要在您的项目中使用Sharptoken,请首先导入库:
using SharpToken ;接下来,通过指定所需的编码或模型来创建gptencing的实例:
// Get encoding by encoding name
var encoding = GptEncoding . GetEncoding ( " cl100k_base " ) ;
// Get encoding by model name
var encoding = GptEncoding . GetEncodingForModel ( " gpt-4 " ) ;然后,您可以使用编码方法来编码一个字符串:
var encoded = encoding . Encode ( " Hello, world! " ) ; // Output: [9906, 11, 1917, 0]并使用解码方法解码编码的令牌:
var decoded = encoding . Decode ( encoded ) ; // Output: "Hello, world!"Sharptoken还提供了高性能计数方法。在将其发送到LLM之前检查提示尺寸或在Textsplitter/Chunker中将其用于抹布很有用。
var count = encoding . CountTokens ( " Hello, world! " ) ; // Output: 4 Sharptoken目前支持以下模型:
r50k_basep50k_basep50k_editcl100k_baseo200k_base在创建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 " ) ;除了指定直接模型名称外,Sharptoken还根据特定前缀为映射模型名称提供功能。这允许用户根据模型的前缀检索编码。
这是当前受支持的前缀及其相应的编码:
| 模型前缀 | 编码 |
|---|---|
gpt-4o | o200k_base |
gpt-4- | cl100k_base |
gpt-3.5-turbo- | cl100k_base |
gpt-35-turbo | cl100k_base |
属于这些前缀下的模型名称的示例包括:
gpt-4o : gpt-4o , gpt-4o-2024-05-13 ,等等。gpt-4- : gpt-4-0314 , gpt-4-32k等。gpt-3.5-turbo- : gpt-3.5-turbo-0301 , gpt-3.5-turbo-0401 ,等等。gpt-35-turbo 。要根据模型名称或其前缀检索编码名称,您可以使用GetEncodingNameForModel方法:
string encodingName = Model . GetEncodingNameForModel ( " gpt-4-0314 " ) ; // This will return "cl100k_base"如果提供的模型名称与任何直接模型名称或前缀不匹配,则该方法将返回null 。
当您使用编码方法编码字符串时,返回的值是代表指定编码中令牌的整数列表。这些令牌是表示输入文本的紧凑方法,可以通过各种算法更有效地处理。
例如,编码文本“ Hello World!”使用CL100K_BASE编码可能会产生以下整数列表:
var encoded = cl100kBaseEncoding . Encode ( " Hello world! " ) ; // Output: [9906, 1917, 0]然后,您可以使用Decode方法将这些令牌化整数值转换回原始文本:
var decoded = cl100kBaseEncoding . Decode ( encoded ) ; // Output: "Hello world!"使用Sharptoken,您可以在不同的编码之间无缝切换,以找到最适合您需求的编码。只需记住,对Encode和Decode方法都使用相同的编码以确保结果。
Sharptoken允许您在编码文本时指定允许的特殊令牌的自定义集。为此,请传递包含允许的特殊令牌作为参数的主题集,以将其传递给编码方法:
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 ) ;同样,您可以在编码文本时指定自定义的特殊令牌。传递一个HashSet<string>其中包含不允许的特殊令牌作为编码方法的参数:
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 ) ;在此示例中,抛出了一个ArgumentException ,因为输入文本包含不允许的特殊令牌
Sharptoken在testplans.txt文件中包含一组测试用例,以确保其与Python Tiktoken库的兼容性。这些测试用例验证了Sharptoken的功能和行为,为开发人员提供了可靠的参考。运行单元测试并验证测试用例有助于保持C#Sharptoken库与原始Python实现之间的一致性。
Sharptoken是最快的库,分配最低!
[ 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
| 方法 | 工作 | 运行时 | 意思是 | 错误 | stddev | 中位数 | Gen0 | Gen1 | 分配 |
|---|---|---|---|---|---|---|---|---|---|
| mltokenizers | .NET 8.0 | .NET 8.0 | 60.55毫秒 | 1.143 ms | 1.123 ms | 60.45毫秒 | 1000.0000 | - | 13.12 MB |
| mltokenizers | .NET 6.0 | .NET 6.0 | 95.75毫秒 | 1.374 ms | 1.147 ms | 95.54毫秒 | 10500.0000 | - | 126.19 MB |
| mltokenizers | .NET框架4.7.1 | .NET框架4.7.1 | 291.77毫秒 | 5.811 ms | 11.195毫秒 | 291.64 ms | 21000.0000 | - | 127.33 MB |
| Sharptoken | .NET 8.0 | .NET 8.0 | 87.78毫秒 | 1.700毫秒 | 1.590毫秒 | 87.34 ms | 1000.0000 | - | 22.13 MB |
| Sharptoken | .NET 6.0 | .NET 6.0 | 128.84毫秒 | 1.718毫秒 | 1.607毫秒 | 128.17毫秒 | 16250.0000 | 500.0000 | 196.31 MB |
| Sharptoken | .NET框架4.7.1 | .NET框架4.7.1 | 356.21 ms | 6.843 ms | 10.854 ms | 355.09毫秒 | 34000.0000 | 1000.0000 | 204.39 MB |
| tokenizerlib | .NET 8.0 | .NET 8.0 | 109.26毫秒 | 2.082 ms | 4.482毫秒 | 107.90毫秒 | 18200.0000 | 600.0000 | 217.82 MB |
| tokenizerlib | .NET 6.0 | .NET 6.0 | 126.16 ms | 2.959毫秒 | 8.630毫秒 | 122.34 ms | 18000.0000 | 500.0000 | 217.82 MB |
| tokenizerlib | .NET框架4.7.1 | .NET框架4.7.1 | 374.71 ms | 7.374毫秒 | 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毫秒 | 8.797毫秒 | 174.98毫秒 | 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毫秒 | 26000.0000 | 666.6667 | 313.26 MB |
| tiktokensharp | .NET框架4.7.1 | .NET框架4.7.1 | 488.22毫秒 | 9.696毫秒 | 15.931 MS | 487.17毫秒 | 63000.0000 | 1000.0000 | 378.31 MB |
Sharptoken在Net8.0上进行了超出性能。它使用现代的多重CPU指令,几乎没有堆分配。
所有核心方法均已在大型和小输入文本上进行了测试。
输入:
SmallText :453 B(文本/平原)LargeText :51 kb(文本/html)方法:
Encode :文字到令牌Decode :文字的令牌CountTokens :高性能API计算文本的令牌 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
| 方法 | 意思是 | 错误 | stddev | 比率 | 比率 | 分配 | 同种比率 |
|---|---|---|---|---|---|---|---|
| .NET 8.0 | |||||||
| Encode_smallText | 22.649美国 | 0.4244美国 | 0.4359 US | 0.28 | 0.01 | 696 b | 0.02 |
| encode_largetext | 美国4,542.505 | 87.7988美国 | 104.5182美国 | 0.24 | 0.01 | 155547 b | 0.03 |
| DECODE_SMALLTEXT | 1.623我们 | 0.0324美国 | 0.0373 US | 0.44 | 0.02 | 2320 b | 0.98 |
| decode_largetext | 454.570美国 | 6.8980美国 | 6.4524美国 | 0.80 | 0.02 | 286979 b | 1.00 |
| counttokens_smallText | 22.008美国 | 0.1165美国 | 0.0909 US | 0.28 | 0.00 | 184 b | 0.005 |
| counttokens_largetext | 美国4,231.353 | 14.5157美国 | 11.3329美国 | 0.23 | 0.00 | 195 b | 0.000 |
| .NET 6.0 | |||||||
| Encode_smallText | 36.370美国 | 0.7178 US | 1.0962美国 | 0.45 | 0.02 | 37344 b | 0.91 |
| encode_largetext | 11,213.070美国 | 219.6291美国 | 269.7243美国 | 0.59 | 0.02 | 5062574 b | 0.91 |
| DECODE_SMALLTEXT | 2.588美国 | 0.0394美国 | 0.0350美国 | 0.70 | 0.02 | 2320 b | 0.98 |
| decode_largetext | 489.467美国 | 8.9195美国 | 8.3433美国 | 0.86 | 0.02 | 286985 b | 1.00 |
| counttokens_smallText | 34.758美国 | 0.2027美国 | 0.1896美国 | 0.45 | 0.01 | 36832 b | 0.907 |
| counttokens_largetext | 11,252.083美国 | 215.8912美国 | 212.0340美国 | 0.61 | 0.01 | 4907169 b | 0.907 |
| .NET框架4.7.1 | |||||||
| Encode_smallText | 79.947美国 | 1.5621美国 | 3.0097美国 | 1.00 | 0.00 | 41138 b | 1.00 |
| encode_largetext | 18,961.252美国 | 253.1816美国 | 236.8262美国 | 1.00 | 0.00 | 5567685 b | 1.00 |
| DECODE_SMALLTEXT | 3.723美国 | 0.0728 US | 0.0997美国 | 1.00 | 0.00 | 2375 b | 1.00 |
| decode_largetext | 570.787美国 | 11.0356美国 | 11.8080美国 | 1.00 | 0.00 | 287496 b | 1.00 |
| counttokens_smallText | 77.521美国 | 1.0802美国 | 0.9020美国 | 1.00 | 0.00 | 40616 b | 1.000 |
| counttokens_largetext | 18,485.392美国 | 313.5834美国 | 277.9836美国 | 1.00 | 0.00 | 5413237 b | 1.000 |
如果您遇到任何问题或提出改进的建议,请随时打开问题或在项目存储库上提交拉动请求。
希望您发现Sharptoken对您的项目有用,并欢迎您可能获得的任何反馈。