简体中文
Openai的Tiktoken Go。
Tiktoken是一个快速的BPE令牌,可与OpenAI的型号一起使用。
这是原始tiktoken的港口。
go get github.com/pkoukk/tiktoken-goTiktoken-Go具有与原始Tiktoken库相同的缓存机制。
您可以使用环境变量tiktoken_cache_dir设置缓存目录。
设置此变量后,Tiktoken-go将使用此目录来缓存令牌字典。
如果您不设置此环境变量,则每次首次初始化编码时,Tiktoken-go都会下载字典。
如果您不想每次使用缓存或下载字典,则可以使用替代BPE加载程序。
只需致电tiktoken.SetBpeLoader然后致电tiktoken.GetEncoding或tiktoken.EncodingForModel 。
BpeLoader是一个接口,您可以通过实现此接口来实现自己的BPE加载程序。
离线BPE加载程序从嵌入文件加载BPE字典,如果您不想在运行时下载字典会有所帮助。
由于BPE词典的大小,该装载机在其他项目中。
如果您需要此加载程序:tiktoken_loader
package main
import (
"fmt"
"github.com/pkoukk/tiktoken-go"
)
func main () {
text := "Hello, world!"
encoding := "cl100k_base"
// if you don't want download dictionary at runtime, you can use offline loader
// tiktoken.SetBpeLoader(tiktoken_loader.NewOfflineLoader())
tke , err := tiktoken . GetEncoding ( encoding )
if err != nil {
err = fmt . Errorf ( "getEncoding: %v" , err )
return
}
// encode
token := tke . Encode ( text , nil , nil )
//tokens
fmt . Println (( token ))
// num_tokens
fmt . Println ( len ( token ))
} package main
import (
"fmt"
"github.com/pkoukk/tiktoken-go"
)
func main () {
text := "Hello, world!"
encoding := "gpt-3.5-turbo"
tkm , err := tiktoken . EncodingForModel ( encoding )
if err != nil {
err = fmt . Errorf ( "getEncoding: %v" , err )
return
}
// encode
token := tkm . Encode ( text , nil , nil )
// tokens
fmt . Println ( token )
// num_tokens
fmt . Println ( len ( token ))
}以下是用于计算传递给GPT-3.5-Turbo或GPT-4的消息的示例函数。
以下代码是根据Wednesday, 28 June 2023 Openai-Cook Books示例编写的。
请注意,该消息的令牌计算方法可能随时更改,因此此代码不一定在将来适用。
如果您需要准确的计算,请参阅官方文档。
如果您发现此代码不再适用,请随时提交PR或问题。
package main
import (
"fmt"
"github.com/pkoukk/tiktoken-go"
"github.com/sashabaranov/go-openai"
)
// OpenAI Cookbook: https://github.com/openai/openai-cookbook/blob/main/examples/How_to_count_tokens_with_tiktoken.ipynb
func NumTokensFromMessages ( messages []openai. ChatCompletionMessage , model string ) ( numTokens int ) {
tkm , err := tiktoken . EncodingForModel ( model )
if err != nil {
err = fmt . Errorf ( "encoding for model: %v" , err )
log . Println ( err )
return
}
var tokensPerMessage , tokensPerName int
switch model {
case "gpt-3.5-turbo-0613" ,
"gpt-3.5-turbo-16k-0613" ,
"gpt-4-0314" ,
"gpt-4-32k-0314" ,
"gpt-4-0613" ,
"gpt-4-32k-0613" :
tokensPerMessage = 3
tokensPerName = 1
case "gpt-3.5-turbo-0301" :
tokensPerMessage = 4 // every message follows <|start|>{role/name}n{content}<|end|>n
tokensPerName = - 1 // if there's a name, the role is omitted
default :
if strings . Contains ( model , "gpt-3.5-turbo" ) {
log . Println ( "warning: gpt-3.5-turbo may update over time. Returning num tokens assuming gpt-3.5-turbo-0613." )
return NumTokensFromMessages ( messages , "gpt-3.5-turbo-0613" )
} else if strings . Contains ( model , "gpt-4" ) {
log . Println ( "warning: gpt-4 may update over time. Returning num tokens assuming gpt-4-0613." )
return NumTokensFromMessages ( messages , "gpt-4-0613" )
} else {
err = fmt . Errorf ( "num_tokens_from_messages() is not implemented for model %s. See https://github.com/openai/openai-python/blob/main/chatml.md for information on how messages are converted to tokens." , model )
log . Println ( err )
return
}
}
for _ , message := range messages {
numTokens += tokensPerMessage
numTokens += len ( tkm . Encode ( message . Content , nil , nil ))
numTokens += len ( tkm . Encode ( message . Role , nil , nil ))
numTokens += len ( tkm . Encode ( message . Name , nil , nil ))
if message . Name != "" {
numTokens += tokensPerName
}
}
numTokens += 3 // every reply is primed with <|start|>assistant<|message|>
return numTokens
}| 编码名称 | Openai型号 |
|---|---|
o200k_base | gpt-4o |
cl100k_base | gpt-4 , gpt-3.5-turbo , text-embedding-ada-002 , text-embedding-3-small , text-embedding-3-large |
p50k_base | codex型号, text-davinci-002 , text-davinci-003 |
r50k_base (或gpt2 ) | 像davinci这样的GPT-3车型 |
| 模型名称 | Openai型号 |
|---|---|
| GPT-4O-* | O200K_BASE |
| GPT-4-* | cl100k_base |
| gpt-3.5-turbo-* | cl100k_base |
| GPT-4O | O200K_BASE |
| GPT-4 | cl100k_base |
| GPT-3.5-Turbo | cl100k_base |
| text-davinci-003 | p50k_base |
| text-davinci-002 | p50k_base |
| text-davinci-001 | r50k_base |
| Text-Curie-001 | r50k_base |
| 文字bbbage-001 | r50k_base |
| Text-ADA-001 | r50k_base |
| 达文奇 | r50k_base |
| 居里 | r50k_base |
| 巴巴奇 | r50k_base |
| 艾达 | r50k_base |
| 代码davinci-002 | p50k_base |
| 代码davinci-001 | p50k_base |
| Code-Cushman-002 | p50k_base |
| Code-Cushman-001 | p50k_base |
| Davinci-Codex | p50k_base |
| Cushman-Codex | p50k_base |
| text-davinci-edit-001 | p50k_edit |
| Code-Davinci-edit-001 | p50k_edit |
| 文本插入-ADA-002 | cl100k_base |
| text-embedding-3-small | cl100k_base |
| 文本插入3大 | cl100k_base |
| 文本相似性davinci-001 | r50k_base |
| 文本相似性-Curie-001 | r50k_base |
| 文本相似性babbage-001 | r50k_base |
| 文本相似性-ADA-001 | r50k_base |
| Text-Search-Search-Davinci-Doc-001 | r50k_base |
| 文本搜索-CURIE-DOC-001 | r50k_base |
| 文本搜索 - 宝贝-DOC-001 | r50k_base |
| Text-Search-SADA-DOC-001 | r50k_base |
| 代码搜索宝贝代码-001 | r50k_base |
| 代码搜索-ADA-CODE-001 | r50k_base |
| GPT2 | GPT2 |
您可以在测试文件夹中运行测试
结果
结果
您可以在测试文件夹中运行基准测试
| 姓名 | 时间/OP | 操作系统 | 中央处理器 | 文本 | 时代 |
|---|---|---|---|---|---|
| tiktoken-go | 8795ns | MacOS 13.2 | 苹果M1 | Udhr | 100000 |
| tiktoken | 8838ns | MacOS 13.2 | 苹果M1 | Udhr | 100000 |
看起来表演几乎是相同的。
也许区别是由于机器性能的差异。
也许我的基准方法不合适。
如果您有更好的基准方法或要添加基准结果,请随时提交PR。
对于新的o200k_base编码,它似乎比cl100k_base慢。 Tiktoken-Go在以下基准测试中的速度比Tiktoken稍慢。
| 姓名 | 编码 | 时间/OP | 操作系统 | 中央处理器 | 文本 | 时代 |
|---|---|---|---|---|---|---|
| tiktoken-go | O200K_BASE | 108522 ns | Ubuntu 22.04 | AMD Ryzen 9 5900HS | Udhr | 100000 |
| tiktoken | O200K_BASE | 70198 ns | Ubuntu 22.04 | AMD Ryzen 9 5900HS | Udhr | 100000 |
| tiktoken-go | cl100k_base | 94502 ns | Ubuntu 22.04 | AMD Ryzen 9 5900HS | Udhr | 100000 |
| tiktoken | cl100k_base | 54642 ns | Ubuntu 22.04 | AMD Ryzen 9 5900HS | Udhr | 100000 |
麻省理工学院