从零开始复现GPT2(三):词表,Tokenizer和语料库的实现


源码地址:https://gitee.com/guojialiang2023/gpt2


GPT2

  • 模型
    • 词表
    • Tokenizer
      • `Tokenizer` 类
      • `_normalize` 方法
      • `_tokenize` 方法
      • `_CHINESE_CHAR_RANGE` 和 `_PUNCTUATION_RANGE`
    • 数据集
    • 语料库
      • `TokenizedCorpus` 类

模型

在这里插入图片描述

词表

定义了一个名为 Vocab 的类,用于处理和管理一个词汇表。这个词汇表是从一个文本文件中加载的,通常用于自然语言处理任务。

  1. 类定义与初始化 (__init__ 方法)

    • Vocab 类在初始化时接收几个参数:

      • vocab_path: 一个字符串,表示词汇表文件的路径。
      • unk_token, bos_token, eos_token, pad_token: 这些是特殊的标记,分别用于表示未知词汇、句子开始、句子结束和填充。这些特殊标记有默认值。
    • 在初始化过程中,类首先会保存这些特殊标记为属性,然后从 vocab_path 指定的文件中加载词汇,并将特殊标记添加到词汇表的开始。

    • self.words 是一个列表,包含了所有的词汇(包括额外的特殊标记)。

    • self.vocab 是一个字典,将每个词汇映射到其在列表中的索引,以便快速查找。

  2. 索引或词汇检索 (__getitem__ 方法)

    • 这个方法允许使用词汇(字符串)或索引(整数)来检索对应的索引或词汇。如果输入是字符串,它返回该字符串对应的索引;如果输入是整数,它返回该索引对应的词汇。
  3. 词汇存在性检查 (__contains__ 方法)

    • 此方法用于检查一个特定的词汇是否存在于词汇表中。
  4. 获取词汇表长度 (__len__ 方法)

    • 这个方法返回词汇表的长度。这里有一个特殊的处理:词汇表的大小被调整为8的倍数。这是为了确保某些计算上的效率,如前面所讨论的。
  5. 特殊标记的索引属性

    • unk_idx, bos_idx, eos_idx, pad_idx 分别提供了 unk_token, bos_token, eos_token, pad_token 这些特殊标记在词汇表中的索引。这对于某些处理流程(如输入预处理或模型的解码过程)是很有用的。
from typing import Unionclass Vocab(object):def __init__(self,vocab_path: str,unk_token: str = '<unk>',bos_token: str = '<s>',eos_token: str = '</s>',pad_token: str = '<pad>'):self.unk_token = unk_tokenself.bos_token = bos_tokenself.eos_token = eos_tokenself.pad_token = pad_tokenwith open(vocab_path, 'r', encoding='utf-8') as fp:self.additional_tokens = [bos_token, eos_token, pad_token]# The additional tokens would be inserted before the words.self.words = self.additional_tokens + fp.read().split()self.vocab = {word: i for i, word in enumerate(self.words)}def __getitem__(self, idx_or_token: Union[int, str]) -> Union[str, int]:if isinstance(idx_or_token, str):return self.vocab[idx_or_token]else:return self.words[idx_or_token]def __contains__(self, token: str) -> bool:return token in self.wordsdef __len__(self) -> int:# Note that vocabulary size must be a multiple of 8 although the actual# number of words is less than it.return (len(self.words) + 7) // 8 * 8@propertydef unk_idx(self) -> int:return self.vocab[self.unk_token]@propertydef bos_idx(self) -> int:return self.vocab[self.bos_token]@propertydef eos_idx(self) -> int:return self.vocab[self.eos_token]@propertydef pad_idx(self) -> int:return self.vocab[self.pad_token]

注意,构建词表时,词表的长度必须为8的倍数。
在构建词表的场景中,将词表大小设置为8的倍数可以确保数据在内存中的对齐。内存对齐是指数据在内存中按照一定的边界存储,这样做可以减少CPU或GPU在访问内存时的负载,从而提高数据处理的速度和效率。如果数据没有对齐,处理器可能需要进行额外的内存访问操作来获取完整的数据,这会增加处理时间和能耗。‘

Tokenizer

代码实现了一个文本标记化(Tokenization)工具,特别适用于处理中文文本。它包含了一个Tokenizer类,这个类使用了一个词汇表(Vocab)实例和一些其他参数来进行文本的处理和标记化。下面是对代码中主要部分的详细解释:

Tokenizer

  • 构造函数 (__init__):

    • vocab: 一个Vocab类的实例,包含了词汇表和一些特殊标记(如未知词标记unk_token)。
    • max_word_len: 最大词长,默认为100。这是为了防止处理极长的单词时出现性能问题。
  • encode 方法:

    • 输入一个字符串text,返回一个标记化后的字符串列表。
    • 它首先对文本进行标准化(_normalize),然后对每个标准化后的词进行标记化(_tokenize)。
  • decode 方法:

    • 将标记列表转换回字符串形式。
    • 主要是将特殊字符(如标点符号)重新还原到它们在文本中的正确位置。

_normalize 方法

  • 对输入文本进行预处理。
  • 首先,它通过正则表达式删除控制字符和替换空白字符。
  • 接着,它在中文字符之间插入空格,以确保在后续的标记化过程中中文字符被正确分隔。
  • 最后,它对文本进行额外的分割,特别是在标点符号处进行分割。

_tokenize 方法

  • 对文本进行实际的标记化处理。
  • 这个方法通过对每个单词进行分解,尝试找到词汇表中的匹配项。
  • 如果单词太长或者无法匹配词汇表中的任何词,它会使用未知词标记(unk_token)。
  • 对于每个词,它使用贪心算法逐步减少词的长度,直到找到词汇表中的匹配项。

_CHINESE_CHAR_RANGE_PUNCTUATION_RANGE

  • 这两个变量定义了用于正则表达式的字符范围。
  • _CHINESE_CHAR_RANGE 包含了中文字符的Unicode范围。
  • _PUNCTUATION_RANGE 包含了标点符号的字符范围。
import regex as re
from data import Vocab
from typing import List_CHINESE_CHAR_RANGE = ('\u4e00-\u9fff\u3400-\u4dbf\U00020000-\U0002a6df''\U0002a700-\U0002b73f\U0002b740-\U0002b81f''\U0002b820-\U0002ceaf\uf900-\ufaff''\U0002f800-\U0002fa1f')
_PUNCTUATION_RANGE = '\\p{P}\x21-\x2f\x3a-\x40\x5b-\x60\x7b-\x7e'class Tokenizer(object):def __init__(self,vocab: Vocab,max_word_len: int = 100):self.vocab = vocabself.exclude_tokens = [vocab.unk_token] + vocab.additional_tokensself.max_word_len = max_word_lendef encode(self, text: str) -> List[str]:return [tokenfor normalized in self._normalize(text)for token in self._tokenize(normalized)]def decode(self, tokens: List[str]) -> str:return (' '.join(tokens).replace(' ##', '').replace(' .', '.').replace(' ?', '?').replace(' !', '!').replace(' ,', ',').replace(' \' ', '\'').replace(' \" ', '\"').replace('\'\'', '\' \'').replace('\"\"', "\" \""))def _normalize(self, text: str) -> List[str]:# Normalize whitespace characters and remove control characters.text = ' '.join(re.sub('[\x00\uFFFD\\p{C}]', '', t)for t in text.split())# Insert whitespaces between chinese characters.text = re.sub(f'([{_CHINESE_CHAR_RANGE}])', r' \1 ', text)normalized = []for t in text.split():if t in self.exclude_tokens:normalized.append(t)else:# Prevent from treating tokens with punctuations.normalized += re.split(f'([{_PUNCTUATION_RANGE}])', t.lower())return ' '.join(normalized).split()def _tokenize(self, text: str) -> List[str]:subwords = []for token in text.split():if len(token) > self.max_word_len:subwords.append(self.vocab.unk_token)continuechildren = []while token and token != '##':current, token = token, ''while current and current != '##':# If subword is in vocabulary, add to list and re-calibrate# the target token.if current in self.vocab:children.append(current)token = '##' + tokenbreak# If subword is not in vocabulary, reduce the search range# and test it again.current, token = current[:-1], current[-1] + token# Process current token as `unknown` since there is no any# proper tokenization (in greedy).if not current:children, token = None, Nonesubwords += children or [self.vocab.unk_token]return subwords

数据集

import torch
from typing import Optional, Dict, Anyclass Dataset(object):def skip(self, count: int):raise NotImplementedError()def fetch(self, batch: Optional[int] = None) -> Dict[str, torch.Tensor]:raise NotImplementedError()def where(self) -> Dict[str, Any]:raise NotImplementedError()def assign(self, where: Dict[str, Any]):raise NotImplementedError()

语料库

代码定义了一个名为 TokenizedCorpus 的类,它继承自 Dataset 类。这个类的主要目的是为了处理一个经过分词处理的语料库,并在此基础上提供一些实用功能,适用于深度学习和自然语言处理任务中。以下是对代码的详细解释:

TokenizedCorpus

  • 构造函数 (__init__):

    • corpus_path: 语料库文件的路径。
    • vocab: 一个 Vocab 类的实例,包含词汇表。
    • seq_len: 序列长度,定义了语料库中每个样本的固定长度。
    • repeat: 一个布尔值,指示是否在语料库读取完毕后从头开始重复。
  • skip 方法:

    • 跳过指定数量的行(即样本)。
    • 如果到达文件末尾且 repeat 为真,则会从文件开始处继续读取。
    • 如果 repeat 为假,则在达到文件末尾时抛出 StopIteration 异常。
  • _fetch_one 方法:

    • 私有方法,用于获取单个样本。
    • 从文件中读取一行,将其分割为标记,并将这些标记转换为它们在词汇表中的索引。
    • 在序列的开始和结束添加特殊标记(如 BOS(开始标记)和 EOS(结束标记))。
    • 如果必要,使用 PAD(填充标记)将序列长度扩充至 seq_len
    • 返回一个包含输入和输出序列的字典。
  • fetch 方法:

    • 公开方法,用于获取一个或多个样本。
    • 如果未指定 batch,则获取单个样本;如果指定了 batch,则获取指定数量的样本。
    • 将样本数据转换为 PyTorch 张量。
  • where 方法:

    • 返回当前文件读取位置的信息。
    • 这对于记录和恢复数据读取位置很有用。
  • assign 方法:

    • 设置文件读取位置。
    • 通过 where 方法得到的位置信息可以用来恢复读取位置。
import torch
from gpt2.data import Dataset, Vocab
from typing import Dict, Any, List, Optionalclass TokenizedCorpus(Dataset):def __init__(self,corpus_path: str,vocab: Vocab,seq_len: int,repeat: bool = True):self.corpus_fp = open(corpus_path, 'r', encoding='utf-8')self.vocab = vocabself.seq_len = seq_lenself.repeat = repeatdef skip(self, count: int):for _ in range(count):if not self.corpus_fp.readline():# Raise error when all sequences are fetched.if not self.repeat:raise StopIteration()# Or, move to the first of the corpus.self.corpus_fp.seek(0)self.corpus_fp.readline()def _fetch_one(self) -> Dict[str, List[int]]:while True:# Read subword-tokenized sequence from corpus.line = self.corpus_fp.readline()if not line:# Raise error when all sequences are fetched.if not self.repeat:raise StopIteration()# Or, move to the first of the corpus.self.corpus_fp.seek(0)continue# Use token indices rather than the token names directly.indices = [self.vocab[t] for t in line.split()]if len(indices) + 2 > self.seq_len:continue# Decorate the sequence with additional tokens.indices = [self.vocab.bos_idx] + indices + [self.vocab.eos_idx]indices += [self.vocab.pad_idx] * (self.seq_len - len(indices) + 1)return {'input': indices[:-1], 'output': indices[1:]}def fetch(self, batch: Optional[int] = None) -> Dict[str, torch.Tensor]:if batch is None:data = self._fetch_one()else:data = [self._fetch_one() for _ in range(batch)]data = {k: [d[k] for d in data] for k in data[0]}return {k: torch.tensor(v, dtype=torch.long) for k, v in data.items()}def where(self) -> Dict[str, Any]:return {'offset': self.corpus_fp.tell()}def assign(self, where: Dict[str, Any]):self.corpus_fp.seek(where['offset'])

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

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

相关文章

若依CMS代码审计

1.安装 安装过程 ruoyi-admin\src\main\resources\application-druid.yml配置数据库等信息 2.审计过程 2.1 文件下载漏洞(v4.7.6) 在com.ruoyi.web.controller.common.resourceDownload存在文件下载 首先简单分析下其代码&#xff1a;请求url如&#xff1a;http://127.0.0.1/c…

自然语言处理(NLP)技术使用

自然语言处理&#xff08;NLP&#xff09;技术使用 以下是一些自然语言处理&#xff08;NLP&#xff09;技术的例子&#xff1a;以上只是一些NLP技术的例子&#xff0c;还有许多其他的技术和应用&#xff0c;如文本分类、文本生成、问答系统等。NLP技术的发展正逐渐改变人们与计…

vivado 配置内存IP

配置内存IP UltraScale体系结构内存IP支持DDR3和DDR4 SDRAM的配置&#xff0c;QDRIIPLUS SRAM和RLDRAM3型接口。截至2015.3&#xff0c;内存IP已被拆分基于内存接口标准和工具流&#xff0c;将其划分为不同的IP。“自定义IP”对话框框包含基本和高级配置选项&#xff0c;其中包…

git使用以及工作中开发流程

Git是当前最先进、最主流的分布式版本控制系统&#xff0c;免费、开源。 主要概念&#xff1a; 基本流程&#xff1a; 命令&#xff1a; git commit -a # 省略了add到暂存区的步骤&#xff0c;直接提交工作区的修改内容到版本库&#xff0c;不包括新增的文件。git fetc…

校园圈子论坛系统--APP小程序H5,前后端源码交付,支持二开!uniAPP+PHP书写!

随着移动互联网的快速发展&#xff0c;校园社交成为了大学生们日常生活中重要的一部分。为了方便校园内学生的交流和互动&#xff0c;校园社交小程序逐渐走入人们的视野。本文将探讨校园社交小程序的开发以及其带来的益处。 校园社交小程序的开发涉及许多技术和设计方面。首先&…

Qt|QPushButton控件讲解

前提 按钮分为了四种状态&#xff1a;常态、聚焦、按下、禁用 前一段时间更新了MFC框架下CButton的自绘。因为MFC框架下的按钮限制性很高&#xff0c;所以只能由自绘实现各种风格&#xff0c;但是QT框架完美的解决了这个问题&#xff0c;我们只需要了解如何调用&#xff0c;就…

封装通用mixins,在vue中实现a-table组件的可伸缩列(详细且使用便捷)

1、实现效果 2、使用场景 vue2 antd-vue 1.x版本由于antd-vue 1.x版本的组件库没有提供可伸缩列的功能&#xff0c;才需要我们手动开发在antd-vue 3.x版本以上的表格已经支持这个功能&#xff0c;不需要我们再去手动开发 3、话不多说&#xff0c;上代码 首先安装vue-dragga…

语义分割:从早期探索到深度学习的突破

语义分割&#xff1a;从早期探索到深度学习的突破 语义分割的端倪&#xff1a;从早期探索到深度学习的突破引言早期技术&#xff1a;图像处理与模式识别边缘检测区域生长图割(Graph Cut)聚类方法 深度学习的兴起&#xff1a;CNN革命2012年 AlexNet的突破全卷积网络&#xff08;…

6、基于机器学习的预测

应用机器学习的任何预测任务与这四个策略。 文章目录 1、简介1.1定义预测任务1.2准备预测数据1.3多步预测策略1.3.1多输出模型1.3.2直接策略1.3.3递归策略1.3.4DirRec 策略2、流感趋势示例2.1多输出模型2.2直接策略1、简介 在第二课和第三课中,我们将预测视为一个简单的回归问…

vue核心知识点

一、Vue基础知识点总结 开发vue项目的模式有两种&#xff1a; 基于vue.js&#xff0c;在html中引入vue.js&#xff0c;让vue.js管理div#app元素。基于脚手架环境&#xff1a;通过vue脚手架环境可以方便的创建一个通用的vue项目框架的模板&#xff0c;在此基础之上开发vue项目…

基于SpringBoot Vue学生信息管理

大家好✌&#xff01;我是Dwzun。很高兴你能来阅读我&#xff0c;我会陆续更新Java后端、前端、数据库、项目案例等相关知识点总结&#xff0c;还为大家分享优质的实战项目&#xff0c;本人在Java项目开发领域有多年的经验&#xff0c;陆续会更新更多优质的Java实战项目&#x…

Redis -- 单线程模型

失败是成功之母 ——法国作家巴尔扎克 目录 单线程模型 Redis为什么这么快 单线程模型 redis只使用一个线程&#xff0c;处理所有的命令请求&#xff0c;不是说redis服务器进场内部真的就只有一个线程&#xff0c;其实也有多个线程&#xff0c;那就是处理网络和io的线程。 R…

图像去噪——SpatiallyAdaptiveSSID网络推理测试(详细图文教程)

SpatiallyAdaptiveSSID 是一种有效的图像去噪方法&#xff0c;它通过自适应地处理不同区域的噪声&#xff0c;能够在保持图像细节的同时&#xff0c;有效地去除噪声。 目录 一、SpatiallyAdaptiveSSID网络简介二、源码包准备2.1 测试集2.2 模型权重文件 三、测试环境四、推理测…

C#,斯特林数(Stirling Number)的算法与源代码

1 斯特林数 在组合数学&#xff0c;斯特林数可指两类数&#xff0c;第一类斯特林数和第二类斯特林数&#xff0c;都是由18世纪数学家James Stirling提出的。它们自18世纪以来一直吸引许多数学家的兴趣&#xff0c;如欧拉、柯西、西尔沃斯特和凯莱等。后来哥本哈根&#xff08;…

氢气泄漏检测仪使用方法:守护安全,从细节开始

随着科技的发展&#xff0c;我们的生活和工作环境中充满了各种潜在的危险。其中&#xff0c;氢气作为一种清洁能源&#xff0c;其使用日益广泛&#xff0c;但同时也带来了泄漏的风险。为了确保我们的安全&#xff0c;了解并正确使用氢气泄漏检测仪至关重要。下面将详细介绍氢气…

用户界面(UI)、用户体验(UE)和用户体验(UX)的差异

对一个应用程序而言&#xff0c;UX/UE (user experience) 设计和 UI (user interface) 设计非常重要。UX设计包括可视化布局、信息结构、可用性、图形、互动等多个方面。UI设计也属于UX范畴。正是因为三者在一定程度上具有重叠的工作内容&#xff0c;很多从业多年的设计师都分不…

[香橙派开发系列]使用蓝牙和手机进行信息的交换

文章目录 前言一、HC05蓝牙模块1.HC05概述2.HC05的连接图3.进入HC05的命令模式4.常用的AT指令4.1 检查AT是否上线4.2 重启模块4.3 获取软件版本号4.4 恢复默认状态4.5 获取蓝牙的名称4.6 设置蓝牙模块的波特率4.7 查询蓝牙的连接模式4.8 查询模块角色 5.连接电脑6.通过HC05发送…

【大厂AI课学习笔记】1.4 算法的进步(1)

2006年以来&#xff0c;以深度学习为代表的机器学习算法的发展&#xff0c;启发了人工智能的发展。 MORE&#xff1a; 自2006年以来&#xff0c;深度学习成为了机器学习领域的一个重要分支&#xff0c;引领了人工智能的飞速发展。作为人工智能专家&#xff0c;我将阐述这一时期…

算法——A/算法通识

目录 一、复杂度分析 A/时间复杂度 B/空间复杂度 C/分析技巧 二、枚举分析 A/枚举算法介绍 B/解空间的类型 C/循环枚举解空间 三、模拟算法 四、递归 A/递归介绍 递归的两个关键要素&#xff1a; B/递归如何实现 C/递归和循环的比较 一、复杂度分析 A/时间复杂度…

腾讯mini项目总结-指标监控服务重构

项目概述 本项目的背景是&#xff0c;当前企业内部使用的指标监控服务的方案的成本很高&#xff0c;无法符合用户的需求&#xff0c;于是需要调研并对比测试市面上比较热门的几款开源的监控方案&#xff08;选择了通用的OpenTelemetry协议&#xff1a;Signoz&#xff0c;otel-…