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

【自然语言处理】预训练06:子词嵌入

在这里插入图片描述

【作者主页】Francek Chen
【专栏介绍】 ⌈ ⌈ PyTorch深度学习 ⌋ ⌋ 深度学习 (DL, Deep Learning) 特指基于深层神经网络模型和方法的机器学习。它是在统计机器学习、人工神经网络等算法模型基础上,结合当代大数据和大算力的发展而发展出来的。深度学习最重要的技术特征是具有自动提取特征的能力。神经网络算法、算力和数据是开展深度学习的三要素。深度学习在计算机视觉、自然语言处理、多模态数据分析、科学探索等领域都取得了很多成果。本专栏介绍基于PyTorch的深度学习算法实现。
【GitCode】专栏资源保存在我的GitCode仓库:https://gitcode.com/Morse_Chen/PyTorch_deep_learning。

文章目录

    • 一、fastText模型
    • 二、字节对编码
    • 小结


  在英语中,“helps”“helped”和“helping”等单词都是同一个词“help”的变形形式。“dog”和“dogs”之间的关系与“cat”和“cats”之间的关系相同,“boy”和“boyfriend”之间的关系与“girl”和“girlfriend”之间的关系相同。在法语和西班牙语等其他语言中,许多动词有40多种变形形式,而在芬兰语中,名词最多可能有15种变形。在语言学中,形态学研究单词形成和词汇关系。但是,word2vec和GloVe都没有对词的内部结构进行探讨。

一、fastText模型

  回想一下词在word2vec中是如何表示的。在跳元模型和连续词袋模型中,同一词的不同变形形式直接由不同的向量表示,不需要共享参数。为了使用形态信息,fastText模型提出了一种子词嵌入方法,其中子词是一个字符 n n n-gram。fastText可以被认为是子词级跳元模型,而非学习词级向量表示,其中每个中心词由其子词级向量之和表示。

  让我们来说明如何以单词“where”为例获得fastText中每个中心词的子词。首先,在词的开头和末尾添加特殊字符“<”和“>”,以将前缀和后缀与其他子词区分开来。然后,从词中提取字符 n n n-gram。例如,值 n = 3 n=3 n=3时,我们将获得长度为3的所有子词:“<wh”“whe”“her”“ere”“re>”和特殊子词“<where>”。

  在fastText中,对于任意词 w w w,用 G w \mathcal{G}_w Gw表示其长度在3和6之间的所有子词与其特殊子词的并集。词表是所有词的子词的集合。假设 z g \mathbf{z}_g zg是词典中的子词 g g g的向量,则跳元模型中作为中心词的词 w w w的向量 v w \mathbf{v}_w vw是其子词向量的和:
v w = ∑ g ∈ G w z g (1) \mathbf{v}_w = \sum_{g\in\mathcal{G}_w} \mathbf{z}_g \tag{1} vw=gGwzg(1)

  fastText的其余部分与跳元模型相同。与跳元模型相比,fastText的词量更大,模型参数也更多。此外,为了计算一个词的表示,它的所有子词向量都必须求和,这导致了更高的计算复杂度。然而,由于具有相似结构的词之间共享来自子词的参数,罕见词甚至词表外的词在fastText中可能获得更好的向量表示。

二、字节对编码

  在fastText中,所有提取的子词都必须是指定的长度,例如 3 3 3 6 6 6,因此词表大小不能预定义。为了在固定大小的词表中允许可变长度的子词,我们可以应用一种称为字节对编码(Byte Pair Encoding,BPE)的压缩算法来提取子词。

  字节对编码执行训练数据集的统计分析,以发现单词内的公共符号,诸如任意长度的连续字符。从长度为1的符号开始,字节对编码迭代地合并最频繁的连续符号对以产生新的更长的符号。请注意,为提高效率,不考虑跨越单词边界的对。最后,我们可以使用像子词这样的符号来切分单词。字节对编码及其变体已经用于诸如GPT-2和RoBERTa等自然语言处理预训练模型中的输入表示。在下面,我们将说明字节对编码是如何工作的。

  首先,我们将符号词表初始化为所有英文小写字符、特殊的词尾符号'_'和特殊的未知符号'[UNK]'

import collectionssymbols = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm','n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z','_', '[UNK]']

  因为我们不考虑跨越词边界的符号对,所以我们只需要一个字典raw_token_freqs将词映射到数据集中的频率(出现次数)。注意,特殊符号'_'被附加到每个词的尾部,以便我们可以容易地从输出符号序列(例如,“a_all er_man”)恢复单词序列(例如,“a_all er_man”)。由于我们仅从单个字符和特殊符号的词开始合并处理,所以在每个词(词典token_freqs的键)内的每对连续字符之间插入空格。换句话说,空格是词中符号之间的分隔符。

raw_token_freqs = {'fast_': 4, 'faster_': 3, 'tall_': 5, 'taller_': 4}
token_freqs = {}
for token, freq in raw_token_freqs.items():token_freqs[' '.join(list(token))] = raw_token_freqs[token]
token_freqs

在这里插入图片描述

  我们定义以下get_max_freq_pair函数,其返回词内最频繁的连续符号对,其中词来自输入词典token_freqs的键。

def get_max_freq_pair(token_freqs):pairs = collections.defaultdict(int)for token, freq in token_freqs.items():symbols = token.split()for i in range(len(symbols) - 1):# “pairs”的键是两个连续符号的元组pairs[symbols[i], symbols[i + 1]] += freqreturn max(pairs, key=pairs.get)  # 具有最大值的“pairs”键

  作为基于连续符号频率的贪心方法,字节对编码将使用以下merge_symbols函数来合并最频繁的连续符号对以产生新符号。

def merge_symbols(max_freq_pair, token_freqs, symbols):symbols.append(''.join(max_freq_pair))new_token_freqs = dict()for token, freq in token_freqs.items():new_token = token.replace(' '.join(max_freq_pair),''.join(max_freq_pair))new_token_freqs[new_token] = token_freqs[token]return new_token_freqs

  现在,我们对词典token_freqs的键迭代地执行字节对编码算法。在第一次迭代中,最频繁的连续符号对是't''a',因此字节对编码将它们合并以产生新符号'ta'。在第二次迭代中,字节对编码继续合并'ta''l'以产生另一个新符号'tal'

num_merges = 10
for i in range(num_merges):max_freq_pair = get_max_freq_pair(token_freqs)token_freqs = merge_symbols(max_freq_pair, token_freqs, symbols)print(f'合并# {i+1}:',max_freq_pair)

在这里插入图片描述

  在字节对编码的10次迭代之后,我们可以看到列表symbols现在又包含10个从其他符号迭代合并而来的符号。

print(symbols)

在这里插入图片描述

  对于在词典raw_token_freqs的键中指定的同一数据集,作为字节对编码算法的结果,数据集中的每个词现在被子词“fast_”“fast”“er_”“tall_”和“tall”分割。例如,单词“fast er_”和“tall er_”分别被分割为“fast er_”和“tall er_”。

print(list(token_freqs.keys()))

在这里插入图片描述

  请注意,字节对编码的结果取决于正在使用的数据集。我们还可以使用从一个数据集学习的子词来切分另一个数据集的单词。作为一种贪心方法,下面的segment_BPE函数尝试将单词从输入参数symbols分成可能最长的子词。

def segment_BPE(tokens, symbols):outputs = []for token in tokens:start, end = 0, len(token)cur_output = []# 具有符号中可能最长子字的词元段while start < len(token) and start < end:if token[start: end] in symbols:cur_output.append(token[start: end])start = endend = len(token)else:end -= 1if start < len(token):cur_output.append('[UNK]')outputs.append(' '.join(cur_output))return outputs

  我们使用列表symbols中的子词(从前面提到的数据集学习)来表示另一个数据集的tokens

tokens = ['tallest_', 'fatter_']
print(segment_BPE(tokens, symbols))

在这里插入图片描述

小结

  • fastText模型提出了一种子词嵌入方法:基于word2vec中的跳元模型,它将中心词表示为其子词向量之和。
  • 字节对编码执行训练数据集的统计分析,以发现词内的公共符号。作为一种贪心方法,字节对编码迭代地合并最频繁的连续符号对。
  • 子词嵌入可以提高稀有词和词典外词的表示质量。
http://www.dtcms.com/a/592803.html

相关文章:

  • 地球的螺旋运动、四季轮回与椭圆轨道:统一场论下的宇宙新图景
  • html格式网站与网站开发有关的岗位是哪些
  • 底层视觉及图像增强-项目实践(十六-0-(6):线性映射技术在LED显示驱动中的工程实践与创新):从奥运大屏,到手机小屏,快来挖一挖里面都有什么
  • 2.7 模型评估与 A/B 测试
  • 政务终端一体化安全解决方案
  • 模板工程的建立
  • 开发者实践:电梯梯控的 非侵入式 与安全模块的电气解耦
  • Redis 高可用集群部署实战:单Docker实现1主2从3
  • 成都在线制作网站作文网入口
  • 想更新公司网站怎么做利于优化的wordpress模板
  • APP开发技术选型:原生 vs 跨端 (Flutter/React Native) 对比与适配场景
  • 智能指针在仓颉技术中的深度实践:从原理到架构的全维解析
  • Flutter开发全攻略:从入门到精通
  • Flutter持续健康发展的多维度分析
  • Flutter架构解析:从引擎层到应用层
  • 六大 API 架构风格
  • LoRA: Low-Rank Adaptation of Large Language Models及其反思
  • 搜索网站做淘宝客怎么在电脑上建立自己的网站
  • 股票投资方法论
  • SSE通信技术详解:Node.js实现服务器端事件推送
  • 广州市建设工程定额管理网站重写路由 wordpress
  • 有什么做兼职的医疗网站做网站应选那个主题
  • Visual Basic创建工具栏
  • IDEA的Code Style配置(使用google的Java Code Stytle)
  • 一个网站空间如何放两个网站内容
  • Vue 绑定class样式
  • LeetCode 153.寻找旋转排序数组中的最小值
  • 无人船 | 图解基于MPC控制的路径跟踪算法(以全驱动无人艇WAMV为例)
  • 蓝牙标签APP与网页端操作常见问题指南
  • 深度测评解析 CANN:从 ACL 到自定义算子,解锁昇腾计算的全部潜能