《动手学深度学习》-52文本预处理实现

原始文本 → 规范化文本 → token 序列 → 词表(token↔id) → 数字序列(id 序列)

核心:构建词表(Vocab)

词表是文本数字化的关键,它维护两种映射:

  1. token → index(token_to_idx):把词映射成数字 id

  2. index → token(idx_to_token):把数字 id 还原成词

构建词表时,一般要处理三个关键机制:

  1. 未知词 <unk>

现实中一定会遇到训练时没见过的词。因此词表会预留一个特殊 token:<unk>,代表"未知词"。

当查不到某个 token 时,用 <unk> 的 id 代替。常见约定:<unk> 的 id 是 0。

  1. 保留 token(reserved_tokens)

有些 token 是任务必需的特殊标记,比如:

  • <pad>:填充到固定长度

  • <bos>:句子开始

  • <eos>:句子结束

  • <mask>:掩码(BERT 类模型)

这些 token 通常放在词表最前面(紧跟 <unk>),确保它们有稳定的 id。

  1. 最小频次过滤(min_freq)

文本里有大量低频词,如果全部纳入词表:

  • 词表会非常大,占内存、训练慢

  • 很多低频词对模型帮助小,但会引入稀疏噪声

因此常设置 min_freq,只保留出现次数 ≥ min_freq 的 token。低频词统一用 <unk> 替代。

复制代码
2.代码

def read_time_machine(payh='D:/PycharmDocument/limu/data/timemachine.txt'):
    with open(payh,'r',encoding='utf-8') as f:
        lines=f.readlines()
    return [re.sub('[^A-Za-z]+',' ',line).strip().lower() for line in lines]
lines=read_time_machine()
# print(lines[10])
# print(len(lines))
def tokenize(lines,token='word'):
    if token=='word':
        return [line.split() for line in lines]
    elif token=='char':
        return [list(line) for line in lines]
    else:
        print('wrong token')
tokens=tokenize(lines,'word')
# for i in range(11):
#     print(tokens[i])
复制代码
#词汇表,将字符串映射到数字索引
class Vocab:
    def __init__(self,tokens=None,min_freq=0,reserved_tokens=None):
        if tokens is None:
            tokens=[]
        if reserved_tokens is None:
            reserved_tokens=[]
        counter=count_cropus(tokens)
        self.token_freqs=sorted(counter.items(),key=lambda x:x[1],reverse=True)#讲词频排序
        self.unk,uniq_tokens=0,['<unk>']+reserved_tokens#初始化,uniq_tokens起始设置为unk和reserved_tokens
        uniq_tokens+=[token for token,freq in self.token_freqs#讲词频高且不在reserved_tokens里的token依次加载,此时为全部的token
                      if freq>=min_freq and token not in reserved_tokens]
        self.idx_to_token,self.token_to_idx=[],dict()
        for token in uniq_tokens:
            self.idx_to_token.append(token)
            self.token_to_idx[token]=len(self.idx_to_token)-1#构建词汇-数字索引,一一对应
    def __len__(self):
        return len(self.token_to_idx)
    def __getitem__(self,tokens):#获取数字
        if not isinstance(tokens,(list,tuple)):
            return self.token_to_idx.get(tokens,self.unk)
        return [self.__getitem__(token) for token in tokens]
    def to_tokens(self,indices):#获取char
        if not isinstance(indices,(list,tuple)):
            return self.idx_to_token[indices]
        return [self.idx_to_token[index] for index in indices]
def count_cropus(tokens):
    if len(tokens)==0 or isinstance(tokens[0],list):
        tokens=[token for line in tokens for token in line]
    return collections.Counter(tokens)
vocab=Vocab(tokens)
# print(list(vocab.token_to_idx.items())[:10])
复制代码
for i in [0,10]:
    print(tokens[i])
    print(vocab[tokens[i]])
复制代码
def load_crops_time_machine(max_tokens=-1):
    lines=read_time_machine()
    tokens=tokenize(lines,'char')
    vocab=Vocab(tokens)
    corpus=[vocab[token] for line in tokens for token in line]
    if max_tokens>0:
        corpus=corpus[:max_tokens]
    return corpus,vocab
corpus,vocab=load_crops_time_machine()
print(len(corpus))
print(len(vocab))
相关推荐
文心快码BaiduComate12 分钟前
百度云与光本位签署战略合作:用AI Agent 重构芯片研发流程
前端·人工智能·架构
风象南1 小时前
Claude Code这个隐藏技能,让我告别PPT焦虑
人工智能·后端
曲幽1 小时前
FastAPI压力测试实战:Locust模拟真实用户并发及优化建议
python·fastapi·web·locust·asyncio·test·uvicorn·workers
Mintopia2 小时前
OpenClaw 对软件行业产生的影响
人工智能
陈广亮2 小时前
构建具有长期记忆的 AI Agent:从设计模式到生产实践
人工智能
会写代码的柯基犬2 小时前
DeepSeek vs Kimi vs Qwen —— AI 生成俄罗斯方块代码效果横评
人工智能·llm
Mintopia3 小时前
OpenClaw 是什么?为什么节后热度如此之高?
人工智能
爱可生开源社区3 小时前
DBA 的未来?八位行业先锋的年度圆桌讨论
人工智能·dba
叁两6 小时前
用opencode打造全自动公众号写作流水线,AI 代笔太香了!
前端·人工智能·agent
敏编程6 小时前
一天一个Python库:jsonschema - JSON 数据验证利器
python