当前位置: 首页 > article >正文

手动实现一个迷你Llama:使用SentencePiece实现自己的tokenizer

  • 自己训练一个tokenizer
    • tokenizer需要的模块
    • SentencePiece 库
    • tokenizer类中的初始化函数
    • tokenizer类中的encode函数
    • tokenizer类中的decode函数
    • 完整代码
    • 训练函数
      • 数据分片
      • 临时文件
      • SentencePiece 训练参数

自己训练一个tokenizer

tokenizer需要的模块

  • encode: 将句子转换为token
  • decode: 将token转换为句子

SentencePiece 库

是由 Google 开发的一种开源的文本分词和标记化工具,广泛应用于自然语言处理(NLP)任务中。它支持多种子词分词算法,如 字节对编码 (BPE) 和 Unigram 语言模型,能够将文本分割成子词单元(subwords),从而提高模型的泛化能力和任务效率

SentencePieceProcessor 是 SentencePiece 库的核心类,用于加载和使用训练好的 SentencePiece 模型,执行分词(Tokenization)、编码(Encoding)和解码(Decoding)等操作。它是 SentencePiece 模型的主要接口,提供了丰富的功能来处理文本数据。

tokenizer类中的初始化函数

def __init__(self, tokenizer_model=None):"""初始化分词器。加载预训练的SentencePiece模型,并设置一些特殊的token ID。参数:tokenizer_model: str, 可选,分词器模型的路径,如果不指定则使用默认路径 TOKENIZER_MODEL。"""# 如果提供了分词器模型路径,使用该路径;否则使用默认模型路径model_path = tokenizer_model if tokenizer_model else TOKENIZER_MODEL# 确保模型文件存在assert os.path.isfile(model_path), model_path# 加载 SentencePiece 模型self.sp_model = SentencePieceProcessor(model_file=model_path)self.model_path = model_path# 获取分词器的特殊token和词汇表大小self.n_words: int = self.sp_model.vocab_size()  # 词汇表大小self.bos_id: int = self.sp_model.bos_id()       # 句子开头 (BOS) 的IDself.eos_id: int = self.sp_model.eos_id()       # 句子结尾 (EOS) 的IDself.pad_id: int = self.sp_model.pad_id()       # 填充 (PAD) 的ID

解释:

  • 特殊token:BOS是句子开头的标记,EOS是句子结尾的标记,PAD是填充的标记。它们在分词器中用于标记句子的开头和结尾,以及填充空白位置。
  • 词汇表大小:SentencePiece模型中的词汇表大小,表示模型可以处理的最大词汇数量。
  • SentencePiece : 加载预训练过的分词模型

tokenizer类中的encode函数

def encode(self, s: str, bos: bool, eos: bool) -> List[int]:"""将字符串编码为词元ID列表。可以选择是否添加句子开头 (BOS) 和句子结尾 (EOS) 标记。参数:s: str, 要编码的字符串。bos: bool, 是否在编码的词元列表前添加 BOS 标记。eos: bool, 是否在编码的词元列表末尾添加 EOS 标记。返回:List[int]: 编码后的词元ID列表。"""# 确保输入是字符串类型assert type(s) is str# 使用SentencePiece将字符串编码为词元IDt = self.sp_model.encode(s)# 如果需要BOS标记,将其添加到词元列表开头if bos:t = [self.bos_id] + t# 如果需要EOS标记,将其添加到词元列表末尾if eos:t = t + [self.eos_id]return t

tokenizer类中的decode函数

def decode(self, t: List[int]) -> str:"""将词元ID列表解码为字符串。参数:t: List[int], 词元ID列表。返回:str: 解码后的字符串。"""return self.sp_model.decode(t)

完整代码

import os
import struct
from sentencepiece import SentencePieceProcessor
from typing import ListTOKENIZER_MODEL = "./data/tok4096.model"class Tokenizer:def __init__(self, tokenizer_model=None):"""初始化分词器。加载预训练的SentencePiece模型,并设置一些特殊的token ID。参数:tokenizer_model: str, 可选,分词器模型的路径,如果不指定则使用默认路径 TOKENIZER_MODEL。"""# 如果提供了分词器模型路径,使用该路径;否则使用默认模型路径model_path = tokenizer_model if tokenizer_model else TOKENIZER_MODEL# 确保模型文件存在assert os.path.isfile(model_path), model_path# 加载 SentencePiece 模型self.sp_model = SentencePieceProcessor(model_file=model_path)self.model_path = model_path# 获取分词器的特殊token和词汇表大小self.n_words: int = self.sp_model.vocab_size()  # 词汇表大小self.bos_id: int = self.sp_model.bos_id()       # 句子开头 (BOS) 的IDself.eos_id: int = self.sp_model.eos_id()       # 句子结尾 (EOS) 的IDself.pad_id: int = self.sp_model.pad_id()       # 填充 (PAD) 的ID# 验证分词器词汇表大小是否正确assert self.sp_model.vocab_size() == self.sp_model.get_piece_size()def encode(self, s: str, bos: bool, eos: bool) -> List[int]:"""将字符串编码为词元ID列表。可以选择是否添加句子开头 (BOS) 和句子结尾 (EOS) 标记。参数:s: str, 要编码的字符串。bos: bool, 是否在编码的词元列表前添加 BOS 标记。eos: bool, 是否在编码的词元列表末尾添加 EOS 标记。返回:List[int]: 编码后的词元ID列表。"""# 确保输入是字符串类型assert type(s) is str# 使用SentencePiece将字符串编码为词元IDt = self.sp_model.encode(s)# 如果需要BOS标记,将其添加到词元列表开头if bos:t = [self.bos_id] + t# 如果需要EOS标记,将其添加到词元列表末尾if eos:t = t + [self.eos_id]return tdef decode(self, t: List[int]) -> str:"""将词元ID列表解码为字符串。参数:t: List[int], 词元ID列表。返回:str: 解码后的字符串。"""return self.sp_model.decode(t)

训练函数

def train_vocab(vocab_size: int=32000, num_shards: int=20):"""vocab_size: int, 词汇表的大小,决定分词器的词汇量。num_shards: int, 用于加快词汇表训练的效率,指定要处理的分片数量。"""# 确保词汇表大小为正数assert vocab_size > 0, "Vocab size must be positive"# SentencePiece 模型的前缀路径,将用于保存分词器prefix = os.path.join(DATA_CACHE_DIR, f"tok{vocab_size}")# 1) 将多个分片中的文本导出为单个文本文件 tiny.txttiny_file = os.path.join(DATA_CACHE_DIR, "tiny.txt")data_dir = os.path.join(DATA_CACHE_DIR, "TinyStories_all_data")shard_filenames = sorted(glob.glob(os.path.join(data_dir, "*.json")))# 创建 tiny.txt 文件并写入指定数量的分片中的文本print(f"Writing temporary file {tiny_file} with {num_shards} shards...")with open(tiny_file, "w", encoding="utf-8") as of:# 遍历前 num_shards 个分片for shard in tqdm(shard_filenames[:num_shards]):with open(shard, "r") as f:data = json.load(f)  # 读取分片中的JSON数据# 遍历每个例子,将其中的故事文本写入 tiny.txt 文件for example in data:text = example["story"]text = text.strip()  # 去除文本首尾的空白字符of.write(text + "\n")  # 每个文本写入一行# 输出生成的 tiny.txt 文件的大小print(f"Size is: {os.path.getsize(tiny_file) / 1024 / 1024:.2f} MB")# 2) 使用 SentencePiece 训练分词器print("Will now train the vocab...")spm.SentencePieceTrainer.train(input=tiny_file,         # 输入文件为之前生成的 tiny.txtmodel_prefix=prefix,     # 模型前缀路径model_type="bpe",        # 使用 Byte-Pair Encoding (BPE) 训练分词器vocab_size=vocab_size,   # 词汇表大小self_test_sample_size=0, # 自测样本大小设置为 0input_format="text",     # 输入文件格式为纯文本character_coverage=1.0,  # 覆盖所有字符(包括非常见字符)num_threads=os.cpu_count(),  # 使用 CPU 的线程数split_digits=True,       # 拆分数字allow_whitespace_only_pieces=True,  # 允许仅由空格组成的词元byte_fallback=True,      # 启用字节级回退unk_surface=r" \342\201\207 ",  # UNK token 表示未知字符的方式normalization_rule_name="identity"  # 使用“identity”归一化规则)# 3) 可选的清理操作,询问用户是否删除临时文件 tiny.txtdec = input(f"Delete the temporary file {tiny_file}? [y/N] ")if dec.lower() == "y":os.remove(tiny_file)  # 删除临时文件print(f"Deleted {tiny_file}")# 输出模型保存的路径print(f"Trained tokenizer is in {prefix}.model")print("Done.")

数据分片

数据被分割成多个分片文件(.json 格式),每个分片文件包含多个文本样本。通过 num_shards 参数控制处理的分片数量,可以加快训练速度,减少每次加载到内存中的数据量,提高训练效率。

临时文件

tiny.txt 是一个临时文件,用于将多个分片中的文本合并成一个文件,便于 SentencePiece 训练。训练完成后,可以选择删除该临时文件以节省磁盘空间。

SentencePiece 训练参数

model_type=“bpe”:使用 BPE 算法进行分词。vocab_size:指定词汇表大小。character_coverage=1.0:覆盖所有字符,包括非常见字符。byte_fallback=True:启用字节级回退,确保所有字符都能被处理。num_threads=os.cpu_count():使用 CPU 的所有线程加速训练。

相关文章:

手动实现一个迷你Llama:使用SentencePiece实现自己的tokenizer

自己训练一个tokenizertokenizer需要的模块SentencePiece 库tokenizer类中的初始化函数tokenizer类中的encode函数tokenizer类中的decode函数完整代码训练函数数据分片临时文件SentencePiece 训练参数 自己训练一个tokenizer tokenizer需要的模块 encode: 将句子转换为tokend…...

【超详细】讲解Ubuntu上如何配置分区方案

Ubuntu 的分区方案 一、通用分区方案(200G为例) EFI系统分区(仅UEFI启动模式需要,) 大小:512MB–1GB类型:主分区(FAT32格式)挂载点:/boot/efi说明&#xff1…...

Gradle-基础

一.安装 1. 2.配置环境变量 GRADLE_HOME D:\gradle\gradle-5.6.4 GRADLE_USER_HOME D:\gradle\localRepository 3.下载源配置 安装目录下的init.d文件夹里创建一个init.gradle文件,下载顺序从上到下,内容&#xff1…...

Anolis系统下安装Jenkins

1.安装java、maven yum install -y java-17-openjdk-devel maven git wget 2.配置环境变量 1.查看java和maven所在目录 [rootlocalhost ~]# which java /usr/bin/java [rootlocalhost bin]# ll /usr/bin/java lrwxrwxrwx 1 root root 22 4月 1 17:20 /usr/bin/java ->…...

Python网络爬虫:从入门到实践

目录 什么是网络爬虫? 网络爬虫的工作原理 常用Python爬虫库 编写爬虫的步骤 实战示例 注意事项与道德规范 未来趋势 1. 什么是网络爬虫? 网络爬虫(Web Crawler)是一种自动化程序,通过模拟人类浏览行为&#x…...

LabVIEW 调用 Python 函数

此程序是 LabVIEW 调用 Python 函数实现双精度数相加的典型示例。通过 LabVIEW 搭建交互框架,借助 “Open Python Session” 创建 Python 代码运行环境,定位 Python 模块路径后调用 “Add” 函数,最终实现数据处理并关闭会话。整个流程展现了…...

视频分析设备平台EasyCVR视频结构化AI智能分析:筑牢校园阳光考场远程监控网

一、背景分析​ 近年来,学校考试的舞弊现象屡禁不止,严重破坏考试的公平性,不仅损害广大考生的切身利益,也在社会上造成恶劣的影响。为有效制止舞弊行为,收集确凿的舞弊证据,在考场部署一套可靠的视频监控…...

AWS用Glue读取S3文件上传数据到Redshift,再导出到Quicksight完整版,含VPC配置

1. 项目背景 AWS的官方文档,关于Glue和Vpc配置部分已经比较旧了,按照官方文档配置的流程始终跑不通,花了一番时间和波折后,才终于完整的跑通了。 在数据分析和商业智能(BI)领域,我们常需要将存…...

Qt WebSockets使用

Qt WebSockets 是 Qt 官方提供的 WebSocket 协议 实现库,支持全双工通信(客户端/服务端),适用于实时交互应用(如聊天、游戏、实时数据监控)。 1. 核心功能 完整的 WebSocket 协议支持 符合 RFC 6455 标准,支持 ws:// 和 wss://(加密)。 自动处理握手、帧拆分、Ping/…...

Docker学习--容器生命周期管理相关命令--start/stop/restart命令

docker start 命令作用: 启动一个或多个已经创建的容器。 语法: docker start [参数] CONTAINER [CONTAINER…](要操作的容器的名称,可以同时操作多个) 参数解释: -a:附加到容器的标准输入输出…...

dom操作笔记、xml和document等

文章目录 mybatis dom部分 dom(Document Object Model文档对象模型)。 xml和html都属于dom,每天都会用到,一直以为很简单,直到有一天,操作mybatis的xml时候惨不忍睹,被上了一课,做个笔记整理下吧。 xml和ht…...

Python爬虫第3节-会话、Cookies及代理的基本原理

目录 一、会话和Cookies 1.1 静态网页和动态网页 1.2 无状态HTTP 1.3 常见误区 二、代理的基本原理 2.1 基本原理 2.2 代理的作用 2.3 爬虫代理 2.4 代理分类 2.5 常见代理设置 一、会话和Cookies 大家在浏览网站过程中,肯定经常遇到需要登录的场景。有些…...

OkHttpHttpClient

学习链接 okhttp github okhttp官方使用文档 SpringBoot 整合okHttp okhttp3用法 Java中常用的HTTP客户端库:OkHttp和HttpClient(包含请求示例代码) 深入浅出 OkHttp 源码解析及应用实践 httpcomponents-client github apache httpclie…...

android设备出厂前 按键测试 快速实现-屏蔽Home,Power等键

android整机测试,需要测试按键。 一般的键好按,好测试。如:音量加 ,音量- 。 但是,有些按键就不好测了。譬如:电源键(Power),Home键,Menu键,Bac…...

Spring Boot3使用Spring AI通过Ollama集成deepseek

文章目录 项目地址版本信息集成步骤 项目地址 DeepSeekSpringAI实战AI家庭医生应用 版本信息 版本Spring Boot3.4.4JDK21spring-ai1.0.0-M6ollama0.6.3LLMdeepseek:14b 集成步骤 引入依赖 <dependency><groupId>org.springframework.ai</groupId><a…...

c++柔性数组、友元、类模版

目录 1、柔性数组&#xff1a; 2、友元函数&#xff1a; 3、静态成员 注意事项 面试题&#xff1a;c/c static的作用? C语言&#xff1a; C: 为什么可以创建出 objx 4、对象与对象之间的关系 5、类模版 1、柔性数组&#xff1a; #define _CRT_SECURE_NO_WARNINGS #…...

win10 快速搭建 lnmp+swoole 环境 ,部署laravel6 与 swoole框架laravel-s项目1

参考文献 1.dnmp环境 https://github.com/yeszao/dnmp 2.laravel6.0文档 https://learnku.com/docs/laravel/6.x 3.laravels 文档 https://github.com/hhxsv5/laravel-s/blob/master/README-CN.md 安装前准备 1.确认已经安装且配置好docker&#xff0c;能在cmd 中运行 docker …...

【Kafka基础】基础概念解析与消息队列对比

1 Kafka 是什么&#xff1f; Kafka是一个 分布式流处理平台&#xff0c;主要用于 高吞吐量、低延迟的实时数据流处理&#xff0c;最初由LinkedIn开发。 核心特点&#xff1a; 高吞吐量&#xff1a;支持每秒百万级消息处理持久化存储&#xff1a;消息可持久化到磁盘&#xff0c;…...

vue将组件中template转为js

在 Vue 中&#xff0c;组件的 template 需要被转换为 JavaScript 渲染函数&#xff08;Render Function&#xff09;才能在浏览器中运行。Vue 2 和 Vue 3 的转换机制有所不同&#xff0c;主要体现在编译时机、编译工具和输出结果上。 1. Vue 2 的 Template 转换 转换方式 Vue…...

Centos 8 安装教程(新手版)

1.需要在阿里开源镜像站下载对应的镜像&#xff0c;如下&#xff1a;https://mirrors.aliyun.com/centos/8.5.2111/isos/x86_64/ 2.打开VM虚拟机&#xff0c;创建新的虚拟机&#xff0c;选择自定义 如图所示点击进行&#xff1a; 选择下载好的镜像 选择“Linux”&#xff0c;版…...

Vue2函数式组件实战:手写可调用的动态组件,适用于toast轻提示、tip提示、dialog弹窗等

Vue2函数式组件实战&#xff1a;手写可调用的动态组件 一、需求场景分析 在开发中常遇到需要动态调用的组件场景&#xff1a; 全局弹窗提示即时消息通知动态表单验证需要脱离当前DOM树的悬浮组件 传统组件调用方式的痛点&#xff1a;必须预先写入模板&#xff0c;可能还要用…...

ESLint语法报错

ESLint语法报错 运行报错 You may use special comments to disable some warnings. Use // eslint-disable-next-line to ignore the next line. Use /* eslint-disable */ to ignore all warnings in a file.解决方案 关闭eslint的语法检测&#xff0c;在eslintrc.js文件中…...

大象如何学会太空漫步?美的:科技领先、To B和全球化

中国企业正处在转型的十字路口。一边是全新的技术、全新的市场机遇&#xff1b;一边是转型要面临的沉重负累和巨大投入&#xff0c;无数中国制造、中国品牌仍在寻路&#xff0c;而有的人已经走至半途。 近日&#xff0c;美的集团交出了一份十分亮眼的2024年财报。数据显示&…...

Leetcode 3500. Minimum Cost to Divide Array Into Subarrays

Leetcode 3500. Minimum Cost to Divide Array Into Subarrays 1. 解题思路2. 代码实现 题目链接&#xff1a;3500. Minimum Cost to Divide Array Into Subarrays 1. 解题思路 这一题非常惭愧&#xff0c;没有自己搞定&#xff0c;基本是抄的大佬们的代码&#xff0c;甚至抄…...

已经使用中的clickhouse更改数据目录

在更换的目录操作&#xff0c;这里更换的目录为home目录&#xff0c;原先安装的目录在/soft/clickhouse/ ,在该目录下有data目录和log目录 更改前目录 更改后目录 1、停止clickhouse服务 sudo systemctl stop clickhouse-server 2、在home目录创建clickhouse目录,在clickho…...

PHP的相关配置和优化

进入etc下面 去掉注释 pid run/php-fpm.pid #指定pid文件存放位置 生成一下子配置文件 这些都是生成的fastcgi的配置文件 进入php中&#xff0c;然后复制模版&#xff0c;生成配置文件 然后编辑文件更改时区 改完之后可以生成启动脚本 这时候刷新之后&#xff0c;再启动会报…...

体重秤PCBA电路方案组成结构

体重秤PCBA电路主要由以下几个部分组成&#xff1a; 主控芯片电路 芯片选择&#xff1a;通常采用低功耗、高性能的单片机作为主控芯片&#xff0c;如前面提到的SIC8833等。这类芯片具备丰富的外设接口&#xff0c;可方便地与其他模块进行通信和控制。 电路连接&#xff1a;主控…...

android 加载本地.svg资源的几种引入方式

在 Android 中&#xff0c;可以在 XML 布局文件中引入本地 .svg 资源&#xff0c;但需要先转换为 Android 可识别的格式。主要有以下几种方式&#xff1a; 方式 1&#xff1a;使用 Vector Asset&#xff08;官方推荐&#xff09; Android 不支持直接加载 .svg&#xff0c;但可…...

fio磁盘测试工具使用笔记

本文介绍磁盘性能测试工具fio在某国产操作系统&#xff08;内核4.19&#xff0c;gcc为7.3.0&#xff09;上的编译和使用。 背景 某项目使用物理机安装某数据库&#xff0c;相关人员提到磁盘性能方面的要求&#xff0c;用fio测试32k的随机读写&#xff0c;性能要达到1万 IOPS。…...

JavaScrip——BOM编程

一、BOM核心对象与导航控制 1. location对象&#xff1a;页面跳转与刷新 // 跳转到指定URL location.href "https://example.com"; // 刷新当前页面 location.reload(); // 示例&#xff1a;点击按钮跳转 document.querySelector("#btn").onclick () &…...