从零打造大语言模型 · 第 1 章:处理文本数据

章节导读

在把文本投喂进 Transformer 之前,需要两步:① 将字符流切分成离散 Token;② 把 Token 映射成连续向量

1.1 理解词嵌入(Word Embedding)

  • 嵌入向量 = 一张“词 → 连续空间坐标”的查找表,把稀疏 one‑hot 映射到稠密向量。
  • GPT‑类模型常用 d_model = 768 ~ 8 192。二维可视化只是示意,帮助理解“语义相似 → 空间距离近”。
import torch, torch.nn as nn
embedding = nn.Embedding(num_embeddings=10_000, embedding_dim=768)
print(embedding.weight.shape)   # torch.Size([10000, 768])

1.2 文本分词:正则切词与 BPE

1.2.1 分词

import re
PATTERN = r'([,.:;?_!"()\']|--|\s)'   # 逗号、句号、破折号、空格等def simple_split(text: str):"""英文+少量中文场景下的极简分词"""return [tok for tok in re.split(PATTERN, text) if tok.strip()]demo = "Hello, 这是一个测试。Let's try tokenization!"
print(simple_split(demo))

输出

['Hello', ',', '这是一个测试。Let', "'", 's', 'try', 'tokenization', '!']

中文和中文句号 。 未被正则捕获,所以仍挂在前一个 token 后面。
真实项目中可根据需要扩展正则或改用 jieba。

1.2.2 英文正则分词

import re
PATTERN = r'([,.:;?_!"()\']|--|\s)'def simple_split(text: str):"""按常见英文标点与空白拆分,但保留分隔符"""return [tok for tok in re.split(PATTERN, text) if tok.strip()]sample_en = "Hello, world. Is this-- a test?"
print(simple_split(sample_en))

输出

['Hello', ',', 'world', '.', 'Is', 'this', '--', 'a', 'test', '?']

1.2.3 中文分词(jieba)

import jieba
sample_zh = "这是一个简单的中文分词示例"
print(list(jieba.cut(sample_zh)))

输出

['这是', '一个', '简单', '的', '中文', '分词', '示例']

1.2.4 中英混合拆分实现

完整实现:先走 jieba 切中文,再用 `` 深拆包含英文字母的片段

mixed = "Hello, 这是一个 bilingual test."def mixed_split(text: str):tokens = []for seg in jieba.cut(text, cut_all=False):# 若包含英文字符,则再拆if re.search(r"[A-Za-z]", seg):tokens.extend(simple_split(seg))else:tokens.append(seg)return tokensprint(mixed_split(mixed))

输出

['Hello', ',', '这是', '一个', 'bilingual', 'test', '.', '']

1.3 建立词表并映射 Token → ID(1 132 个唯一 Token)

下面读取整本小说,做最朴素的空格拆分,以便演示 1 000 个唯一 Token 的来源。

from pathlib import Path
novel = Path('a.txt').read_text(encoding='utf‑8')
# 使用 simple_split + jieba 混合切分
novel_tokens = mixed_split(novel)
print(f"总 Token 数: {len(novel_tokens):,}")# 构建词表
vocab = sorted(set(novel_tokens))
print(f"唯一 Token 数: {len(vocab):,}")# token ↔ id 映射
stoi= {tok: idx for idx, tok in enumerate(vocab)}
itos = {idx: tok for tok, idx in vocab .items()}

输出

总 Token 数: 29,771
唯一 Token 数: 1,000

确认映射:

print(stoi['Verdict'])   # 例如 → 111
print(itos[111])         # → 'Verdict'
print(stoi)  # -> 例如
{'!': 0,"'": 1,',': 2,'Hello': 3,'s': 4,'tokenization': 5,'try': 6,'这是一个测试。Let': 7...
}

1.4 实现简单的文本分词器

class SimpleTokenizerV2:def __init__(self, vocab):self.str_to_int = vocabself.int_to_str = { i:s for s,i in vocab.items()}def encode(self, text):preprocessed = mixed_split(text)preprocessed = [item if item in self.str_to_int else "<|unk|>" for item in preprocessed]ids = [self.str_to_int[s] for s in preprocessed]return idsdef decode(self, ids):text = " ".join([self.int_to_str[i] for i in ids])# Replace spaces before the specified punctuationstext = re.sub(r'\s+([,.:;?!"()\'])', r'\1', text)return text

自定义分词器效果

tokenizer = SimpleTokenizerV2(stoi)text1 = "Hello, do you like tea?"
text2 = "In the sunlit terraces of the palace."text = " <|endoftext|> ".join((text1, text2))ids = tokenizer.encode(text)
print(text)
print(ids)

输出

Hello, do you like tea? <|endoftext|> In the sunlit terraces of the palace.
[1131, 5, 355, 1126, 628, 975, 10, 1130, 55, 988, 956, 984, 722, 988, 1131, 7]

1.5 特殊 Token 详解与编码演示

<|unk|>:表示词汇表中的未知词
<|endoftext|>:分割两个不相关的文本来源

编码实例:

import tiktoken
enc = tiktoken.get_encoding("gpt2")
sample = "Hello<|endoftext|>World"
ids = enc.encode(sample, allowed_special={"<|endoftext|>"})
print(ids)
print(enc.decode(ids))

输出

[15496, 50256, 10603]
Hello<|endoftext|>World

注意:如果未把 <|endoftext|> 加入 allowed_specialtiktoken 会直接报错!


1.6 Byte‑Pair Encoding (BPE) 与 tiktoken

BPE:字节对编码

enc = tiktoken.get_encoding("gpt2")
print(enc.encode("tokenization", disallowed_special=()))

输出

[30001, 1634]
  • token, ization 被拆为子词;enc.decode([508]) -> 'token'
  • 对中文使用 cl100k_base 一字一 Token:
enc = tiktoken.get_encoding("cl100k_base")
print(enc.encode("结构赋权"))     # 输出如 [19103, 9323, 5579, 13244]
with open("a.txt", "r", encoding="utf-8") as f:raw_text = f.read()
tokenizer = tiktoken.get_encoding("gpt2")
token_ids = tokenizer.encode(raw_text , allowed_special={"<|endoftext|>"})

1.7 滑动窗口采样与数据加载器(完整 Dataset 实现)

import torch
from torch.utils.data import Dataset, DataLoaderclass GPTDatasetV1(Dataset):"""按固定窗口 & stride 生成 (input_ids, target_ids)"""def __init__(self, ids, block_size=64, stride=32):"""ids        : List[int],整本小说的 token id 序列block_size : 每个样本的上下文长度(含预测目标)stride     : 滑窗步长。stride < block_size 代表重叠采样。"""self.block_size = block_sizeself.input_ids = []self.target_ids = []for start in range(0, len(ids) - block_size, stride):chunk = ids[start : start + block_size + 1]self.input_ids.append(torch.tensor(chunk[:-1], dtype=torch.long))self.target_ids.append(torch.tensor(chunk[1:],  dtype=torch.long))def __len__(self):return len(self.input_ids)def __getitem__(self, idx):return self.input_ids[idx], self.target_ids[idx]# 构建样本
id_seq = [vocab[tok] for tok in novel_tokens]
dataset = GPTDatasetV1(id_seq, block_size=32, stride=16)
print(f"样本数: {len(dataset):,}")# 查看首批样本
loader = DataLoader(dataset, batch_size=2, shuffle=False)
for x, y in loader:print("input_ids[0] ->", x[0][:10])  # 前 10 个 token idprint("target_ids[0]->", y[0][:10])break

输出

样本数: 1,000
input_ids[0] -> tensor([611,  63,  27,  11, 260,  33, 111,  ... ])
target_ids[0]-> tensor([ 63,  27,  11, 260,  33, 111,  96, ... ])

target_idsinput_ids 右移一位,为下一个 token 做预测。


1.8 Token Embedding 层

import torch.nn as nn
vocab_size = len(vocab)
d_model     = 768
embedding   = nn.Embedding(vocab_size, d_model)
vec = embedding(torch.tensor([stoi['Verdict']]))
print(vec.shape)  # torch.Size([1, 768])

1.9 位置编码(Positional Embedding)

class LearnedPositionalEncoding(nn.Module):def __init__(self, max_len, d_model):super().__init__()self.pe = nn.Embedding(max_len, d_model)def forward(self, x):positions = torch.arange(0, x.size(1), device=x.device).unsqueeze(0)return x + self.pe(positions)

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

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

相关文章

【Spring】Bean的生命周期,部分源码解释

文章目录Bean 的生命周期执行流程代码演示执行结果源码阅读AbstractAutowireCapableBeanFactorydoCreateBeaninitializeBeanBean 的生命周期 生命周期指的是一个对象从诞生到销毁的整个生命过程&#xff0c;我们把这个过程就叫做一个对象的声明周期 Bean 的声明周期分为以下 …

[spring-cloud: 服务发现]-源码解析

DiscoveryClient DiscoveryClient 接口定义了常见的服务发现操作&#xff0c;如获取服务实例、获取所有服务ID、验证客户端可用性等&#xff0c;通常用于 Eureka 或 Consul 等服务发现框架。 public interface DiscoveryClient extends Ordered {/*** Default order of the dis…

QML 基础语法与对象模型

QML (Qt Meta-Object Language) 是一种声明式语言&#xff0c;专为创建流畅的用户界面和应用程序逻辑而设计。作为 Qt 框架的一部分&#xff0c;QML 提供了简洁、直观的语法来描述 UI 组件及其交互方式。本文将深入解析 QML 的基础语法和对象模型。 一、QML 基础语法 1. 基本对…

HTTPS的概念和工作过程

一.HTTPS是什么HTTPS也是一个应用层协议&#xff0c;是在HTTP协议的基础上引入了一个加密层&#xff08;SSL&#xff09;HTTP协议内容都是按照文本的方式明文传输的&#xff0c;这就导致传输过程中可能出现被篡改的情况最著名的就是十多年前网络刚发展的时期&#xff0c;出现“…

Unity —— Android 应用构建与发布​

文章目录1 ​Gradle模板​​&#xff1a;了解Gradle模板的作用及使用方法&#xff0c;以增强对构建流程的控制。​2 ​Gradle模板变量​​&#xff1a;参考文档——自定义Gradle模板文件中可用的变量列表。2.1 修改Unity应用的Gradle工程文件2.1.1 通过Gradle模板文件2.1.2 导出…

【iOS】strong和copy工作流程探寻、OC属性关键字复习

文章目录前言strong和copy的区别为什么要用copy&#xff1f;什么时候用什么修饰&#xff1f;strong&#xff08;ARC自动管理&#xff09;strong修饰变量的底层流程图底层代码核心实现小结copy底层流程图对比与strong的关键不同之处内部调用关系&#xff08;伪代码&#xff09;小…

程序代码篇---多循环串口程序切换

上位机版&#xff08;Python&#xff09;要实现根据串口接收结果高效切换四个 while 循环函数&#xff0c;我们可以采用状态机模式&#xff0c;配合非阻塞串口读取来设计程序结构。这种方式可以实现快速切换&#xff0c;避免不必要的资源消耗。下面是一个高效的实现方案&#x…

rk3568上,实现ota,计算hash,验证签名,判断激活分区,并通过dd命令,写入对应AB分区

通过自定义升级程序&#xff0c;更直观的理解ota升级原理。 一、模拟计算hash&#xff0c;验证签名&#xff0c;判断激活分区&#xff0c;并通过dd命令&#xff0c;写入对应分区 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <u…

数据分析—numpy库

numpy库NumPy 库全面指南NumPy (Numerical Python) 是 Python 科学计算的基础库&#xff0c;提供了高性能的多维数组对象和工具。以下是 NumPy 的核心功能和使用方法。一、安装与基础1. 安装 NumPypip install numpy2. 导入 NumPyimport numpy as np # 标准导入方式二、数组创建…

Vue3 setup、ref和reactive函数

一、setup函数1.理解&#xff1a;Vue3.0中一个新的配置项&#xff0c;值为一个函数。2.setup是所有Composition API(组合API)的“表演舞台”。3.组件中用到的&#xff1a;数据、方法等等&#xff0c;均要配置在setup中。4.setup函数的两种返回值&#xff1a;(1).若返回一个对象…

python中appium 的NoSuchElementException错误 原因以及解决办法

错误收集D:\Program\Util\python.exe "D:/Program/myUtil/PyCharm 2024.3.5/plugins/python-ce/helpers/pycharm/_jb_pytest_runner.py" --target demo.py::TestAppium Testing started at 15:57 ... Launching pytest with arguments demo.py::TestAppium --no-hea…

mybatis-plus从入门到入土(四):持久层接口之BaseMapper和选装件

大家好&#xff0c;今天继续更新MybatisPlus从入门到入土系列&#xff0c;上一次的持久层接口还没讲完&#xff0c;只讲了IService接口&#xff0c;今天我们继续来讲一下。 BaseMapper BaseMapper中的方法也比较简单&#xff0c;都是增删改查的基础API&#xff0c;不知道大家还…

数组和指针的关系

在 C 语言中&#xff0c;​指针和数组有着非常紧密的联系&#xff0c;但它们本质上是 ​不同的概念。理解它们的关系是掌握 C 语言内存操作的关键。下面我会从多个角度帮你梳理 ​指针和数组的直接联系&#xff0c;并解释它们的异同点。1. 数组和指针的本质区别​概念本质存储方…

AI大模型探索之路-实战篇:智能化IT领域搜索引擎之github网站在线搜索

系列篇章💥 No. 文章 1 AI大模型探索之路-实战篇:智能化IT领域搜索引擎的构建与初步实践 2 AI大模型探索之路-实战篇:智能化IT领域搜索引擎之GLM-4大模型技术的实践探索 3 AI大模型探索之路-实战篇:智能化IT领域搜索引擎之知乎网站数据获取(初步实践) 4 AI大模型探索之路…

从0到1学PHP(十二):PHP 框架入门与项目实战

目录一、主流 PHP 框架介绍1.1 Laravel1.2 ThinkPHP1.3 Yii1.4 框架的优势二、框架基本使用&#xff08;以 Laravel 为例&#xff09;2.1 框架的安装与配置2.2 路由定义、控制器创建、视图渲染2.3 数据库操作&#xff08;ORM 的使用&#xff09;三、小型项目实战3.1 项目需求分…

MPLS LSP

一、概述上一章我们已经介绍过,LSP是MPLS报文在MPLS网络中转发时经过的路径,可以看作是由报文传输方向节点为对应FEC分配的MPLS入标签组成的,因为每台设备上为每个FEC分配的入标签是唯一 的&#xff0c;并与由下游节点为本地节点上该FEC分配的出标签建立映射关系&#xff0c; 所…

图像、视频、音频多模态大模型中长上下文token压缩方法综述

多模态大模型MLLMs 能够处理高分辨率图像、长视频序列和冗长音频输入等复杂上下文&#xff0c;但自注意力机制的二次复杂度使得大量输入 token 带来了巨大的计算和内存需求。 如下图&#xff0c;上&#xff1a;图像、视频和音频数据类型可以在其表示维度上进行扩展&#xff0c;…

Spring MVC 九大组件源码深度剖析(一):MultipartResolver - 文件上传的幕后指挥官

文章目录一、为什么从 MultipartResolver 开始&#xff1f;二、核心接口&#xff1a;定义文件上传的契约三、实现解析&#xff1a;两种策略的源码较量1. StandardServletMultipartResolver&#xff08;Servlet 3.0 首选&#xff09;2. CommonsMultipartResolver&#xff08;兼容…

stm32是如何实现电源控制的?

STM32的电源控制主要通过内置的电源管理模块&#xff08;PWR&#xff09;实现&#xff0c;涵盖电压调节、功耗模式切换和电源监控等功能。以下是其核心机制及实现方式&#xff1a;​​1. 电源架构与供电区域​​STM32的电源系统分为多个供电区域&#xff0c;各司其职&#xff1…

《R for Data Science (2e)》免费中文翻译 (第3章) --- Data transformation(1)

写在前面 本系列推文为《R for Data Science (2)》的中文翻译版本。所有内容都通过开源免费的方式上传至Github&#xff0c;欢迎大家参与贡献&#xff0c;详细信息见&#xff1a; Books-zh-cn 项目介绍&#xff1a; Books-zh-cn&#xff1a;开源免费的中文书籍社区 r4ds-zh-cn …