Go语言实现大模型分词器tokenizer

文章目录

  • 前言
  • 核心结构体定义
  • 构造函数
  • 文本初始处理
  • 组词
  • 构建词组索引
  • 训练数据
  • 编码
  • 解码
  • 打印状态信息
  • 运行效果
  • 总结

前言

大模型的tokenizer用于将原始文本输入转化为模型可处理的输入形式。tokenizer将文本分割成单词、子词或字符,并将其编码为数字表示。大模型的tokenizer通常基于词表进行编码,使用词嵌入将单词映射为向量表示。tokenizer还可以将输入文本进行填充和截断,以确保所有输入序列的长度一致,以便于模型的批量处理。

这篇博客的tokenizer分析器使用纯粹的Go语言标准库实现,不借用任何其它第三方库。用轮子是生活,造轮子是信仰。

核心结构体定义

type BytePairEncoder struct {wsToken  stringunkToken string// k: word, v: tokenswordToken map[string]*[]string// k: word, v: countwordCount map[string]int// k: token, v: counttokenCount map[string]int// k: id, v: tokenidToken map[int]string// k: token, v: idtokenId map[string]int
}

构造函数

func DefaultBytePairEncoder() *BytePairEncoder {return NewBytePairEncoder("_", " ")
}func NewBytePairEncoder(wsToken, unkToken string) *BytePairEncoder {return &BytePairEncoder{wsToken:    wsToken,unkToken:   unkToken,wordToken:  make(map[string]*[]string),wordCount:  make(map[string]int),tokenCount: make(map[string]int),idToken:   make(map[int]string),tokenId:   make(map[string]int),}
}

文本初始处理

func (e *BytePairEncoder) wordToTokens(word string) *[]string {parts := []rune(word)n := len(parts)res := make([]string, n)for i := 0; i < n; i++ {token := string(parts[i])e.tokenCount[token]++res[i] = token}return &res
}func (e *BytePairEncoder) preprocess(text string) []string {text = strings.TrimSpace(text)return strings.Fields(text)
}func (e *BytePairEncoder) processWord(word string) {e.wordToken[word] = e.wordToTokens(word)e.wordCount[word]++
}func (e *BytePairEncoder) initState(text string) {words := e.preprocess(text)for _, word := range words {e.processWord(e.wsToken + word)}
}

组词

func (e *BytePairEncoder) mergePair() {// k: token, v: countm := make(map[string]int)for word, tokens := range e.wordToken {n := len(*tokens) - 1for i := 0; i < n; i++ {m[(*tokens)[i]+(*tokens)[i+1]] += e.wordCount[word]}}maxToken := ""maxCount := 0for k, v := range m {if v > maxCount {maxToken = kmaxCount = v}}if maxCount < 2 {return}e.tokenCount[maxToken] = maxCountfor _, tokens := range e.wordToken {n := len(*tokens) - 1for i := 0; i < n; i++ {if (*tokens)[i]+(*tokens)[i+1] == maxToken {e.tokenCount[(*tokens)[i]]--e.tokenCount[(*tokens)[i+1]]--post := (*tokens)[i+1:]post[0] = maxToken*tokens = (*tokens)[:i]*tokens = append((*tokens), post...)*tokens = (*tokens)[:len(*tokens)]i--n -= 2}}}
}func (e *BytePairEncoder) merge(steps int) {for i := 0; i < steps; i++ {e.mergePair()}
}

构建词组索引

func (e *BytePairEncoder) buildIndex() {e.tokenId[e.unkToken] = 0e.idToken[0] = e.unkTokeni := 1for token := range e.tokenCount {e.tokenId[token] = ie.idToken[i] = tokeni++}
}

训练数据

func (e *BytePairEncoder) Train(text string, steps int) {e.initState(text)e.merge(steps)e.buildIndex()
}

编码

func (e *BytePairEncoder) segment(words []string) []int {res := make([]int, 0)for _, word := range words {parts := []rune(word)NEXT:for i := len(parts); i >= 1; i-- {if code, ok := e.tokenId[string(parts[:i])]; ok {parts = parts[i:]res = append(res, code)goto NEXT}}if len(parts) == 0 {continue}code := e.tokenId[string(parts[0])]res = append(res, code)parts = parts[1:]if len(parts) != 0 {goto NEXT}}return res
}func (e *BytePairEncoder) Encode(text string) []int {words := e.preprocess(text)return e.segment(words)
}

解码

func (e *BytePairEncoder) Decode(codes []int) []string {res := make([]string, 0)for _, code := range codes {res = append(res, e.idToken[code])}return res
}

打印状态信息

func (e *BytePairEncoder) Dump() {fmt.Println("===== dump state ======")fmt.Println("===> dump wordToken <===")for word, tokens := range e.wordToken {fmt.Println(word, "=>", *tokens)}fmt.Println()fmt.Println("===> dump wordcnt <===")for word, count := range e.wordCount {fmt.Println(word, "=>", count)}fmt.Println()fmt.Println("===> dump tokenCount <===")for token, count := range e.tokenCount {fmt.Println(token, "=>", count)}fmt.Println()fmt.Println("===> dump idTokens <===")for code, token := range e.idToken {fmt.Println(code, "=>", token)}fmt.Println()fmt.Println("===> dump tokenIds <===")for token, code := range e.tokenId {fmt.Println(token, "=>", code)}fmt.Println()
}

运行效果

我们的tokenizer已经开发完毕,现在可以运行我们的tokenizer,看看是否能达到我们想要的效果

package mainimport ("fmt""os""tokenizer"
)func main() {trainData, err := os.ReadFile("./data.txt")if err != nil {panic(err)}steps := 50enc := tokenizer.DefaultBytePairEncoder()enc.Train(string(trainData), steps)input := "提取数据特征进行预测"codes := enc.Encode(input)tokens := enc.Decode(codes)fmt.Println(codes)fmt.Println(tokens)
}

输入数据集
data.txt

机器学习、深度学习和强化学习是人工智能领域中的三个重要技术方向。以下是它们的区别:
机器学习:机器学习是一种通过从数据中自动学习模式和规律来进行预测和决策的方法。它涉及到使用算法和统计模型,从数据中提取特征并进行模型训练,进而对未知数据进行预测或分类。机器学习的重点在于自动学习和泛化能力,它不需要明确的指令或规则来执行任务,而是通过数据和经验来改善性能。
深度学习:深度学习是机器学习的一个分支,它使用包含多个神经网络层的深度神经网络进行学习和预测。深度学习模型通过层层堆叠的方式,从原始数据中学习到多个抽象层次的特征表示。深度学习的优势在于可以自动提取复杂的特征,并通过大规模数据的训练来优化模型性能。它被广泛应用于计算机视觉、自然语言处理和语音识别等领域。
强化学习:强化学习是一种机器学习的方法,旨在让机器学习从环境中的交互中通过试错来改善性能。它通过不断与环境进行交互,观察环境状态并执行动作,然后从环境的反馈中学习如何在给定环境中做出最优的决策。强化学习的目标是通过学习最优的策略来最大化累积奖励。强化学习在游戏、机器人控制和优化问题等领域有着广泛应用。
总的来说,机器学习是从数据中学习模式和规律,深度学习是机器学习的一种方法,使用深度神经网络来提取复杂的特征表示,强化学习是通过试错学习从环境中改善性能。

运行效果
在这里插入图片描述

可以根据情况使用Dump函数打印状态信息查看更多细节

总结

恭喜你已经制作了一个属于自己的tokenizer分词器,我们实现的相对粗糙一点,但是对于初学者是难得的实战项目,麻雀虽小,五脏俱全。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/184770.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

记录一下npm包的关键字段

module: 字段指定了 ES 模块版本的入口文件路径&#xff0c;main: 字段则指定了 CommonJS 模块版本的入口文件路径。 注意&#xff1a;尽管 module 字段在构建工具中被广泛支持&#xff0c;但它并不是所有 JavaScript 环境都遵循的规范。在 Node.js 中&#xff0c;通常使用 mai…

【广州华锐视点】VR模拟法庭审判实训,零距离感受庭审全过程

随着科技的不断发展&#xff0c;虚拟现实&#xff08;VR&#xff09;技术已经逐渐渗透到各个领域&#xff0c;为人们提供了全新的体验方式。在法律领域&#xff0c;VR技术的应用也日益受到关注。近年来&#xff0c;越来越多的法学院和培训机构开始尝试将VR技术引入模拟法庭实践…

电商数据采集中如何采集1688平台商品详情SKU数据

一、背景介绍 1688.com是阿里旗下国内最大的B2B批发采购平台&#xff0c;1688分销客是依托此平台的官方营销平台&#xff0c;通过此平台API接口的接入推广平台商家的商品&#xff0c;按照商品成交金额的一定比例获得佣金。可以调用1688平台上的商品详情&#xff0c;SKU数据&…

社区内涝积水监测系统作用,改善社区积水

随着社区化进程的加速&#xff0c;社区基础设施的重要性日益凸显。在这个背景下&#xff0c;社区生命线和内涝积水监测系统成为了关注的焦点。它们在维护社区安全&#xff0c;特别是在应对暴雨等极端天气条件下&#xff0c;发挥着至关重要的作用。 WITBEE万宾时刻关注社区内涝积…

PCL 最小二乘拟合圆柱(C++详细过程版)

目录 一、算法原理1、算法简介2、参考文献二、代码实现三、结果展示四、测试数据本文由CSDN点云侠原创,原文链接。如果你不是在点云侠的博客中看到该文章,那么此处便是不要脸的爬虫与GPT。 一、算法原理 1、算法简介 圆柱拟合步骤主要包括两步: 一是确定柱面模型参数初始值…

关于大模型在文本分类上的尝试

文章目录 前言所做的尝试总结前言 总共25个类别,在BERT上的效果是48%,数据存在不平衡的情况,训练数据分布如下: 训练数据不多,4000左右 所做的尝试 1、基于 Qwen-14b-base 做Lora SFT,Loss忘记记录 准确率在68%左右 Lora配置 class LoraArguments:lora_r: int = 64…

使用机器学习方法进行分析和处理:对高质量图像进行压缩

使用SVD&#xff08;奇异值分解&#xff09;进行图像压缩与普通压缩工具压缩的主要区别在于压缩原理和压缩效果。 压缩原理&#xff1a; 普通图像压缩工具通常采用有损压缩或无损压缩算法&#xff0c;如JPEG、PNG等&#xff0c;它们主要针对图像的像素进行变换和编码。而SVD图像…

算法高频题目

LRUCache实现 思路&#xff1a;使用linkedHashMap。按照插入顺序的有序链表。 get 操作。cache不包含&#xff0c;返回-1。包含。我们需要当前key重新put。 /将 key 变为最近使用 put。如果包含。修改当前key值。然后将key变成最近使用。不包含。如果cacheSize大于当前最大size…

[cocos creator] Label设置为RESIZE_HEIGHT,获取height

问题描述&#xff1a; 需要在scrollview 中显示item, item的高度由子节点label的高度动态决定&#xff0c;但更改string后&#xff0c;获取label的高度仍为初始值。 解决办法&#xff1a; //改变string内容 node.getComponent(Label).string str; //加上这一句 node.getCom…

【JavaEE初阶】volatile 关键字、wait 和 notify

目录 一、volatile 关键字 1、volatile 能保证内存可见性 2、volatile 不保证原子性 二、wait 和 notify 1、wait()方法 2、notify()方法 3、notifyAll()方法 4、wait 和 sleep 的对比 一、volatile 关键字 1、volatile 能保证内存可见性 我们前面的线程安全文章中&…

Docker安装可视化工具Portainer

目录 Portainer简介 Portainer安装 Portainer简介 Portainer是一款开源的容器管理平台&#xff0c;支持多种容器技术&#xff0c;如Docker、Kubernetes和Swarm等。它提供了一个易于使用的Web UI界面&#xff0c;可用于管理和监控容器和集群。Portainer旨在使容器管理更加简单…

前端三大MV*模式:MVC、mvvm、mvp模式介绍

MVC&#xff08;同步通信为主&#xff09;&#xff1a;Model、View、Controller MVP(异步通信为主)&#xff1a;Model、View、Presenter MVVM(异步通信为主)&#xff1a;Model、View、ViewModel mvc模式介绍 MVC&#xff08;Model–View–Controller&#xff09;模式是软件…

Elk:filebeat 日志收集工具和logstash

Elk:filebeat 日志收集工具和logstash Filebeat是一个轻量级的日志手机工具,所使用的系统资源比logstash部署和启动时使用的资源要小得多 Filebeat可以在非java环境使用&#xff0c;他可以代理logstash在非java环境上收集日志 缺点 Filebeat无法实现数据的过滤,一般是结合l…

Direct local .aar file dependencies are not supported when building an AAR.

Direct local .aar file dependencies are not supported when building an AAR. 问题描述&#xff1a;打debug包没有问题&#xff0c;但是打release包(无论是apk还是aar包)时会报错“Direct local .aar file dependencies are not supported when building an AAR.” 原因&a…

Linux添加 交换分区/文件 .swap

需求提出 编译时系统卡死 分析 make -j64将内存消耗干净&#xff0c;需要减少-j数量&#xff0c;或者添加swap交换分区 参考链接 Linux交换空间&#xff08;swap space)-CSDN Linux下增加、删除Swap文件 增加交换分区 swap 解决编译时内存不足问题-博客 添加swap文件 以…

【路径规划】move_base、路径规划算法、局部避障算法介绍

资料整理供个人学习使用。 文章目录 一、move_base1、move_base 包内容2、move_base 参数解析1. move_base 参数2. 全局代价地图参数3. 局部代价地图参数4. 全局规划器参数5. 局部规划器参数 二、路径规划1、Dijkstra2、最佳优先搜索3、A*4、A* 和 Dijkstra 比较 三、局部避障1…

k8s部署es和skywalking

使用k8s部署es和skywalking skywalking介绍 skywalking架构 整个架构&#xff0c;分成上、下、左、右四部分&#xff1a; 上部分 Agent &#xff1a;负责从应用中&#xff0c;收集链路信息&#xff0c;发送给 SkyWalking OAP 服务器。目前支持 SkyWalking、Zikpin、Jaeger 等…

【腾讯云 HAI域探秘】使用高性能应用服务HAI快速开发一款赛博朋克风拼图游戏,化繁从简,低成本进入人工智能时代。

前言 人工智能&#xff08;AI&#xff09;是当今科技领域的热门话题&#xff0c;尤其是自然语言处理&#xff08;NLP&#xff09;技术&#xff0c;它可以让机器理解和生成自然语言。随着大型语言模型&#xff08;LLM&#xff09;的发展&#xff0c;如 GPT-3、DALL-E 等&#xf…

蓝桥杯每日一题2023.11.29

题目描述 #include <stdio.h> #include <string.h>void StringInGrid(int width, int height, const char* s) {int i,k;char buf[1000];strcpy(buf, s);if(strlen(s)>width-2) buf[width-2]0;printf("");for(i0;i<width-2;i) printf("-"…

常见场景题-幂等性该如何设计?

幂等性如何设计&#xff1f; 答&#xff1a;幂等性的设计有以下几种方案&#xff1a; 方案一&#xff1a;唯一索引或唯一组合索引 对订单的幂等性设计&#xff0c;可以使用订单号作为唯一索引&#xff0c;这样如果多次插入的话&#xff0c;就会报错 DuplicatedKeyException…