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

深度学习处理文本(12)

接下来,我们准备两个单独的TextVectorization层:一个用于英语,一个用于西班牙语。我们需要自定义字符串的预处理方式。我们需要保留插入的词元"[start]“和”[end]"。默认情况下,字符[和]将被删除,但我们希望保留它们,以便区分单词“start”与开始词元"[start]"。不同语言的标点符号是不同的。在西班牙语的TextVectorization层中,如果要删除标点符号,也需要删除字符¿。请注意,对于真实的翻译模型,我们会将标点符号作为单独的词元,而不会将其删除,因为我们希望能够生成带有正确标点符号的句子。在这个示例中,为简单起见,我们会去掉所有的标点符号,如代码清单11-26所示。

代码清单11-26 将英语和西班牙语的文本对向量化

import tensorflow as tf
import string
import re

strip_chars = string.punctuation + "¿"---- (本行及以下6)为西班牙语的TextVectorization层准备一个自定义的字符串标准化函数:保留[],但去掉¿(同时去掉string.punctuation中的其他所有字符)
strip_chars = strip_chars.replace("[", "")
strip_chars = strip_chars.replace("]", "")

def custom_standardization(input_string):
    lowercase = tf.strings.lower(input_string)
    return tf.strings.regex_replace(
        lowercase, f"[{re.escape(strip_chars)}]", "")

vocab_size = 15000---- (本行及以下1)为简单起见,只查看每种语言前15 000个最常见的单词,并将句子长度限制为20个单词
sequence_length = 20

source_vectorization = layers.TextVectorization(----英语层
    max_tokens=vocab_size,
    output_mode="int",
    output_sequence_length=sequence_length,
)
target_vectorization = layers.TextVectorization(----西班牙语层
    max_tokens=vocab_size,
    output_mode="int",
    output_sequence_length=sequence_length + 1,----生成的西班牙语句子多了一个词元,因为在训练过程中需要将句子偏移一个时间步
    standardize=custom_standardization,
)
train_english_texts = [pair[0] for pair in train_pairs]
train_spanish_texts = [pair[1] for pair in train_pairs]
source_vectorization.adapt(train_english_texts)---- (本行及以下1)学习每种语言的词表
target_vectorization.adapt(train_spanish_texts)

最后,我们可以将数据转换为tf.data管道,如代码清单11-27所示。我们希望它能够返回一个元组(inputs, target),其中inputs是一个字典,包含两个键,分别是“编码器输入”​(英语句子)和“解码器输入”​(西班牙语句子)​,target则是向后偏移一个时间步的西班牙语句子。

代码清单11-27 准备翻译任务的数据集

batch_size = 64

def format_dataset(eng, spa):
    eng = source_vectorization(eng)
    spa = target_vectorization(spa)
    return ({
        "english": eng,
        "spanish": spa[:, :-1],----输入西班牙语句子不包含最后一个词元,以保证输入和目标具有相同的长度
    }, spa[:, 1:])----目标西班牙语句子向后偏移一个时间步。二者长度相同,都是20个单词

def make_dataset(pairs):
    eng_texts, spa_texts = zip(*pairs)
    eng_texts = list(eng_texts)
    spa_texts = list(spa_texts)
    dataset = tf.data.Dataset.from_tensor_slices((eng_texts, spa_texts))
    dataset = dataset.batch(batch_size)
    dataset = dataset.map(format_dataset, num_parallel_calls=4)
    return dataset.shuffle(2048).prefetch(16).cache()----利用内存缓存来加快预处理速度

train_ds = make_dataset(train_pairs)
val_ds = make_dataset(val_pairs)

这个数据集如下所示。

>>> for inputs, targets in train_ds.take(1):
>>>     print(f"inputs['english'].shape: {inputs['english'].shape}")
>>>     print(f"inputs['spanish'].shape: {inputs['spanish'].shape}")
>>>     print(f"targets.shape: {targets.shape}")
inputs["english"].shape: (64, 20)
inputs["spanish"].shape: (64, 20)
targets.shape: (64, 20)

数据已准备就绪,我们可以开始构建模型了。我们首先构建一个序列到序列的循环模型,然后再继续构建Transformer。

RNN的序列到序列学习

2015年~2017年,RNN主宰了序列到序列学习,不过随后被Transformer超越。RNN是现实世界中的许多机器翻译系统的基础。2017年前后的谷歌翻译模型由7个大型LSTM层堆叠而成。这种方法在今天仍然值得一学,因为它为理解序列到序列模型提供了一个简单的切入点。使用RNN将一个序列转换为另一个序列,最简单的方法是在每个时间步都保存RNN的输出。这在Keras中的实现如下所示。

inputs = keras.Input(shape=(sequence_length,), dtype="int64")
x = layers.Embedding(input_dim=vocab_size, output_dim=128)(inputs)
x = layers.LSTM(32, return_sequences=True)(x)
outputs = layers.Dense(vocab_size, activation="softmax")(x)
model = keras.Model(inputs, outputs)

但是,这种方法有两个主要问题。目标序列必须始终与源序列的长度相同。在实践中,这种情况很少见。从技术上来说,这一点并不重要,因为可以对源序列或目标序列进行填充,使二者长度相同。由于RNN逐步处理的性质,模型将仅通过查看源序列第0~N个词元来预测目标序列的第N个词元。这种限制不适用于大多数任务,特别是翻译。比如将“The weather is nice today”​(今天天气不错)翻译成法语,应该是“Il fait beau aujourd’hui”​。模型需要能够仅从“The”预测出“Il”​,仅从“The weather”预测出“Il fait”​,以此类推,这根本不可能。如果你是一名译员,你会先阅读整个源句子,然后再开始翻译。如果你要处理的两种语言具有非常不同的词序,比如英语和日语,那么这一点就尤为重要。这正是标准的序列到序列模型所做的。

在一个正确的序列到序列模型中(如图11-13所示)​,首先使用一个RNN(编码器)将整个源序列转换为单一向量(或向量集)​。它既可以是RNN的最后一个输出,也可以是最终的内部状态向量。然后,使用这个向量(或向量集)作为另一个RNN(解码器)的初始状态。解码器会查看目标序列的第0~N个元素,并尝试预测目标序列中的第N+1个时间步

在这里插入图片描述

http://www.dtcms.com/a/111756.html

相关文章:

  • Linux的 /etc/sysctl.conf 笔记250404
  • AI大模型:(二)1.3 linux本地部署通义万相2.1+deepseek视频生成
  • ARM Cortex-A7 处理器支持的汇编指令集全面总结
  • 【Cursor】打开Vscode设置
  • 【nacos安装指南】
  • 关于termux运行pc交叉编译的aarch64 elf的问题
  • Leetcode hot100(day 5)
  • 【学Rust写CAD】30 Alpha256结构体补充方法(alpha256.rs)
  • 人工智能在前端开发中的应用探索
  • php8 ?-> nullsafe 操作符 使用教程
  • YOLO目标检测系列
  • 指令补充+样式绑定+计算属性+监听器
  • 鸿蒙 —— 系统图标大全
  • NLP高频面试题(三十六)——深入理解思维链(Chain-of-Thought)提示方法
  • Obsidian按下三个横线不能出现文档属性
  • 鸿蒙 —— 关系型数据库
  • 本节课课堂总结
  • Linux系统编程:进程管理、内存对比与树莓派应用
  • 【AI学习】MCP的简单快速理解
  • 解决backtrader框架下日志ValueError: I/O operation on closed file.报错(jupyternotebook)
  • el-table固定表头,动态计算高度
  • 基础IO(linux)
  • 公司论坛数据构建情感标注数据集思考
  • 使用minio客户端mc工具迁移指定文件到本地
  • C++设计模式-策略模式:从基本介绍,内部原理、应用场景、使用方法,常见问题和解决方案进行深度解析
  • [GN] Python3基本数据类型 -- 与C的差异
  • 灭火器离位检测:智能视觉守护安全
  • Java异步编程实战:线框-管道模型的设计与实现
  • LabVIEW 中数字转字符串常用汇总
  • MoE Align Sort在医院AI医疗领域的前景分析(代码版)