0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

PyTorch教程-15.6. 子词嵌入

jf_pJlTbmA9 来源:PyTorch 作者:PyTorch 2023-06-05 15:44 次阅读

在英语中,诸如“helps”、“helped”和“helping”之类的词是同一个词“help”的变形形式。“dog”与“dogs”的关系与“cat”与“cats”的关系相同,“boy”与“boyfriend”的关系与“girl”与“girlfriend”的关系相同。在法语和西班牙语等其他语言中,许多动词有超过 40 种变形形式,而在芬兰语中,一个名词可能有多达 15 种格。在语言学中,形态学研究词的形成和词的关系。然而,word2vec 和 GloVe 都没有探索单词的内部结构。

15.6.1。fastText 模型

回想一下单词在 word2vec 中是如何表示的。在skip-gram模型和连续词袋模型中,同一个词的不同变形形式直接由不同的向量表示,没有共享参数。为了使用形态信息,fastText 模型提出了一种子词嵌入方法,其中一个子词是一个字符n-gram (Bojanowski等人,2017 年)。与学习词级向量表示不同,fastText 可以被视为子词级 skip-gram,其中每个中心词由其子词向量的总和表示。

让我们举例说明如何使用单词“where”为 fastText 中的每个中心词获取子词。首先,在单词的首尾添加特殊字符“<”和“>”,以区别于其他子词的前缀和后缀。然后,提取字符n-克从字。例如,当n=3,我们得到所有长度为 3 的子词:“”,以及特殊子词“”。

在 fastText 中,对于任何单词w, 表示为Gw其所有长度在 3 到 6 之间的子字及其特殊子字的并集。词汇表是所有词的子词的并集。出租zg是子词的向量g在字典中,向量vw为词w作为 skip-gram 模型中的中心词的是其子词向量的总和:

(15.6.1)vw=∑g∈Gwzg.

fastText 的其余部分与 skip-gram 模型相同。与skip-gram模型相比,fastText中的词汇量更大,导致模型参数更多。此外,为了计算一个词的表示,必须将其所有子词向量相加,从而导致更高的计算复杂度。然而,由于具有相似结构的词之间的子词共享参数,稀有词甚至词汇表外的词可能会在 fastText 中获得更好的向量表示。

15.6.2。字节对编码

在 fastText 中,所有提取的子词都必须具有指定的长度,例如3到6,因此无法预定义词汇量大小。为了允许在固定大小的词汇表中使用可变长度的子词,我们可以应用一种称为字节对编码(BPE) 的压缩算法来提取子词 ( Sennrich et al. , 2015 )。

字节对编码对训练数据集进行统计分析,以发现单词中的常见符号,例如任意长度的连续字符。从长度为 1 的符号开始,字节对编码迭代地合并最频繁的一对连续符号以产生新的更长的符号。请注意,为了提高效率,不考虑跨越单词边界的对。最后,我们可以使用子词这样的符号来分词。字节对编码及其变体已用于流行的自然语言处理预训练模型中的输入表示,例如 GPT-2 (Radford等人,2019 年)和 RoBERTa (Liu等人,2019 年). 下面,我们将说明字节对编码的工作原理

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

import collections

symbols = ['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]']

import collections

symbols = ['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_ tall er_ man”)中恢复单词序列(例如,“a taller 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

{'f a s t _': 4, 'f a s t e r _': 3, 't a l l _': 5, 't a l l e r _': 4}

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

{'f a s t _': 4, 'f a s t e r _': 3, 't a l l _': 5, 't a l l e r _': 4}

我们定义了以下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):
      # Key of `pairs` is a tuple of two consecutive symbols
      pairs[symbols[i], symbols[i + 1]] += freq
  return max(pairs, key=pairs.get) # Key of `pairs` with the max value

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):
      # Key of `pairs` is a tuple of two consecutive symbols
      pairs[symbols[i], symbols[i + 1]] += freq
  return max(pairs, key=pairs.get) # Key of `pairs` with the max value

作为一种基于连续符号频率的贪婪方法,字节对编码将使用以下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

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'merge #{i + 1}:', max_freq_pair)

merge #1: ('t', 'a')
merge #2: ('ta', 'l')
merge #3: ('tal', 'l')
merge #4: ('f', 'a')
merge #5: ('fa', 's')
merge #6: ('fas', 't')
merge #7: ('e', 'r')
merge #8: ('er', '_')
merge #9: ('tall', '_')
merge #10: ('fast', '_')

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'merge #{i + 1}:', max_freq_pair)

merge #1: ('t', 'a')
merge #2: ('ta', 'l')
merge #3: ('tal', 'l')
merge #4: ('f', 'a')
merge #5: ('fa', 's')
merge #6: ('fas', 't')
merge #7: ('e', 'r')
merge #8: ('er', '_')
merge #9: ('tall', '_')
merge #10: ('fast', '_')

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

print(symbols)

['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]', 'ta', 'tal', 'tall', 'fa', 'fas', 'fast', 'er', 'er_', 'tall_', 'fast_']

print(symbols)

['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]', 'ta', 'tal', 'tall', 'fa', 'fas', 'fast', 'er', 'er_', 'tall_', 'fast_']

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

print(list(token_freqs.keys()))

['fast_', 'fast er_', 'tall_', 'tall er_']

print(list(token_freqs.keys()))

['fast_', 'fast er_', 'tall_', 'tall er_']

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

def segment_BPE(tokens, symbols):
  outputs = []
  for token in tokens:
    start, end = 0, len(token)
    cur_output = []
    # Segment token with the longest possible subwords from symbols
    while start < len(token) and start < end:
      if token[start: end] in symbols:
        cur_output.append(token[start: end])
        start = end
        end = len(token)
      else:
        end -= 1
    if start < len(token):
      cur_output.append('[UNK]')
    outputs.append(' '.join(cur_output))
  return outputs

def segment_BPE(tokens, symbols):
  outputs = []
  for token in tokens:
    start, end = 0, len(token)
    cur_output = []
    # Segment token with the longest possible subwords from symbols
    while start < len(token) and start < end:
      if token[start: end] in symbols:
        cur_output.append(token[start: end])
        start = end
        end = len(token)
      else:
        end -= 1
    if start < len(token):
      cur_output.append('[UNK]')
    outputs.append(' '.join(cur_output))
  return outputs

在下文中,我们使用symbols从上述数据集中学习的列表中的子词来分割tokens代表另一个数据集。

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

['tall e s t _', 'fa t t er_']

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

['tall e s t _', 'fa t t er_']

15.6.3。概括

fastText 模型提出了一种子词嵌入方法。基于 word2vec 中的 skip-gram 模型,它将中心词表示为其子词向量的总和。

字节对编码对训练数据集进行统计分析,以发现单词中的常见符号。作为一种贪婪的方法,字节对编码迭代地合并最频繁的一对连续符号。

子词嵌入可以提高罕见词和词典外词的表示质量。

15.6.4。练习

例如,大约有3×108可能的 6-英语克。当子词太多时会出现什么问题?如何解决这个问题?提示:参考 fastText 论文(Bojanowski et al. , 2017)第 3.2 节的结尾。

如何设计基于连续词袋模型的子词嵌入模型?

获得尺寸词汇表m, 当初始符号词汇量为n?

如何扩展字节对编码的思想来提取短语?

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • pytorch
    +关注

    关注

    2

    文章

    777

    浏览量

    12908
收藏 人收藏

    评论

    相关推荐

    Pytorch入门之的基本操作

    Pytorch入门之基本操作
    发表于 05-22 17:15

    PyTorch如何入门

    PyTorch 入门实战(一)——Tensor
    发表于 06-01 09:58

    Pytorch代码移植嵌入式开发笔记,错过绝对后悔

    @[TOC]Pytorch 代码移植嵌入式开发笔记目前在做开发完成后的AI模型移植到前端的工作。 由于硬件设施简陋,需要把代码和算法翻译成基础加乘算法并输出每个环节参数。记录几点实用技巧以及项目
    发表于 11-08 08:24

    Pytorch模型如何通过paddlelite部署到嵌入式设备?

    Pytorch模型如何通过paddlelite部署到嵌入式设备?
    发表于 12-23 09:38

    Pytorch AI语音助手

    想做一个Pytorch AI语音助手,有没有好的思路呀?
    发表于 03-06 13:00

    如何安装TensorFlow2 Pytorch

    如何安装TensorFlow2 Pytorch
    发表于 03-07 07:32

    ch582做的蓝牙键盘,无法连iphone手机怎么解决?

    用ch582做的蓝牙键盘鼠标,无法连iphone12、13.但是iphone6、7可以。ios版本都是最新15.6.看看是否LIB库问题。我现在用的是你们最新的7月15号发布的最新LIB库
    发表于 09-21 07:35

    通过Cortex来非常方便的部署PyTorch模型

    该框架的 python 风格,其学习曲线的温和性,以及它对快速和简单原型的方便实现,使 PyTorch 明显成为研究人员的最爱。因此,它正在推动一些最酷的机器学习项目:Transformers
    发表于 11-01 15:25

    如何往星光2板子里装pytorch

    如题,想先gpu版本的pytorch只安装cpu版本的pytorch,pytorch官网提供了基于conda和pip两种安装方式。因为咱是risc架构没对应的conda,而使用pip安装提示也没有
    发表于 09-12 06:30

    驻留特征在电话语音确认中的应用

    语速和插入删除错误是导致自动电话转接系统发生错误的重要原因。该文给出一种基于似然比(LLR)和驻留特征融合的语音确认方法减少上述错误。提出基于最小分类错误准则
    发表于 04-02 08:37 17次下载

    关于GN-GloVe的嵌入技术详解

    带有这样的偏见的嵌入模型,会给下游的NLP应用带来严重问题。例如,基于嵌入技术的简历自动筛选系统或工作自动推荐系统,会歧视某种性别的候选人(候选人的姓名反映了性别)。除了造成这种明
    的头像 发表于 09-23 09:25 3674次阅读

    PyTorch教程15.5之带全局向量的嵌入(GloVe)

    电子发烧友网站提供《PyTorch教程15.5之带全局向量的嵌入(GloVe).pdf》资料免费下载
    发表于 06-05 11:01 0次下载
    <b class='flag-5'>PyTorch</b>教程15.5之带全局向量的<b class='flag-5'>词</b><b class='flag-5'>嵌入</b>(GloVe)

    PyTorch教程15.6之子嵌入

    电子发烧友网站提供《PyTorch教程15.6之子嵌入.pdf》资料免费下载
    发表于 06-05 11:02 0次下载
    <b class='flag-5'>PyTorch</b>教程<b class='flag-5'>15.6</b>之子<b class='flag-5'>词</b><b class='flag-5'>嵌入</b>

    PyTorch教程-15.5。带全局向量的嵌入 (GloVe)

    15.5。带全局向量的嵌入 (GloVe)¶ Colab [火炬]在 Colab 中打开笔记本 Colab [mxnet] Open the notebook in Colab
    的头像 发表于 06-05 15:44 357次阅读

    2.0优化PyTorch推理与AWS引力处理器

    2.0优化PyTorch推理与AWS引力处理器
    的头像 发表于 08-31 14:27 423次阅读
    2.0优化<b class='flag-5'>PyTorch</b>推理与AWS引力<b class='flag-5'>子</b>处理器