pytorch embedding,pytorch rnn简单示例

  pytorch embedding,pytorch rnn简单示例

  本文主要介绍神经网络的使用。嵌入在PyTorch中,通过示例代码非常详细的介绍,对大家的学习或者工作有一定的参考价值。有需要的朋友下面跟边肖学习。

  00-1010一、预备知识1.1语料库)1.2令牌)1.3词汇二。nn.embedding Basis 2.1为什么嵌入?2.2基本参数2.3的区别。嵌入和nn。神经网络的线性2.4更新问题。嵌入三。高级3.1所有参数3.2嵌入预训练单词IV。最后

  

目录

  

一、前置知识

  太长无法阅读版本:NLP任务所依赖的语言数据称为语料库。

  详细版:语料库(复数为Corpus)是组织成数据集的真实文本或音频的集合。这里的真实性指的是以该语言为母语的人产生的文本或音频。语料库可以包括从报纸、小说、食谱、广播到电视节目、电影和推特的一切。在自然语言处理中,语料库包含可用于训练AI的文本和语音数据。

  

1.1 语料库(Corpus)

  为了简单起见,我们假设我们的语料库只有三个英文句子,都经过处理(全部小写去掉标点):

  corpus=[他是老工人,英语是有用的工具,电影院很远]

  我们经常需要将它标记化成为一个序列,这里我们只需要简单的拆分:

  定义标记化(语料库):

  为语料库中的句子返回[sentence.split()

  令牌=令牌化(语料库)

  打印(代币)

  # [[他,是,安,老,工],[英,是,有用,工具],[the ,影院,是,远,远]]

  这里我们在词的层面做词汇化,也可以在字的层面做词汇化。

  

1.2 词元(Token)

  词汇表包含语料库中的所有单词,没有重复,并且它的实现非常容易:

  vocab=set(sum(tokens,[]))

  打印(词汇)

  # { 是,有用,安,老,远,远,一,他,工具,电影,英语,工人 }

  在NLP任务中,单词通常不是最重要的。我们需要为词汇表中的每个单词分配一个惟一的索引,并建立一个单词到索引的映射:word2idx。这里我们根据单词出现的频率来构建word2idx。

  从集合导入计数器

  word2idx={

  word: idx

  对于idx,枚举中的(word,freq(

  已排序(计数器(sum(tokens,[]))。items(),key=lambda x: x[1],reverse=True))

  }

  打印(word2idx)

  # { 是 : 0,他 : 1,安 : 2,老 : 3,工人 : 4,英语 : 5,甲 : 6,有用 : 7,工具 : 8,工 : 9, c

  inema: 10, far: 11, away: 12}

  

  反过来,我们还可以构建 idx2word

  

idx2word = {idx: word for word, idx in word2idx.items()}

  print(idx2word)

  # {0: is, 1: he, 2: an, 3: old, 4: worker, 5: english, 6: a, 7: useful, 8: tool, 9: the, 10: cinema, 11: far, 12: away}

  

  对于 1.2 节中的 tokens,也可以转化为索引的表示:

  

encoded_tokens = [[word2idx[token] for token in line] for line in tokens]

  print(encoded_tokens)

  # [[1, 0, 2, 3, 4], [5, 0, 6, 7, 8], [9, 10, 0, 11, 12]]

  

  这种表示方式将在后续讲解 nn.Embedding 时提到。

  

  

二、nn.Embedding 基础

  

  

2.1 为什么要 embedding?

  RNN无法直接处理单词,因此需要通过某种方法把单词变成数字形式的向量才能作为RNN的输入。这种把单词映射到向量空间中的一个向量的做法称为词嵌入(word embedding),对应的向量称为词向量(word vector)。

  

  

2.2 基础参数

  我们首先讲解 nn.Embedding 中的基础参数,了解它的基本用法后,再讲解它的全部参数。

  基础参数如下:

  

nn.Embedding(num_embeddings, embedding_dim)

  

  其中 num_embeddings 是词表的大小,即 len(vocab)embedding_dim 是词向量的维度。

  我们使用第一章节的例子,此时词表大小为 12 12 12,不妨设嵌入后词向量的维度是 3 3 3(即将单词嵌入到三维向量空间中),则 embedding 层应该这样创建:

  

torch.manual_seed(0) # 为了复现性

  emb = nn.Embedding(12, 3)

  

  embedding 层中只有一个参数 weight,在创建时它会从标准正态分布中进行初始化:

  

print(emb.weight)

  # Parameter containing:

  # tensor([[-1.1258, -1.1524, -0.2506],

  # [-0.4339, 0.8487, 0.6920],

  # [-0.3160, -2.1152, 0.3223],

  # [-1.2633, 0.3500, 0.3081],

  # [ 0.1198, 1.2377, 1.1168],

  # [-0.2473, -1.3527, -1.6959],

  # [ 0.5667, 0.7935, 0.4397],

  # [ 0.1124, 0.6408, 0.4412],

  # [-0.2159, -0.7425, 0.5627],

  # [ 0.2596, 0.5229, 2.3022],

  # [-1.4689, -1.5867, 1.2032],

  # [ 0.0845, -1.2001, -0.0048]], requires_grad=True)

  

  这里我们可以把 weight 当作 embedding 层的一个权重。

  接下来再来看一下 nn.Embedding 的输入。直观来看,给定一个已经词元化的句子,将其中的单词输入到 embedding 层应该得到相应的词向量。事实上,nn.Embedding 接受的输入并不是词元化后的句子,而是它的索引形式,即第一章节中提到的 encoded_tokens

  nn.Embedding 可以接受任何形状的张量作为输入,但因为传入的是索引,所以张量中的每个数字都不应超过 len(vocab) - 1,否则就会报错。接下来,nn.Embedding 的作用就像一个查找表(Lookup Table)一样,通过这些索引在 weight 中查找并返回相应的词向量。

  

print(emb.weight)

  # tensor([[-1.1258, -1.1524, -0.2506],

  # [-0.4339, 0.8487, 0.6920],

  # [-0.3160, -2.1152, 0.3223],

  # [-1.2633, 0.3500, 0.3081],

  # [ 0.1198, 1.2377, 1.1168],

  # [-0.2473, -1.3527, -1.6959],

  # [ 0.5667, 0.7935, 0.4397],

  # [ 0.1124, 0.6408, 0.4412],

  # [-0.2159, -0.7425, 0.5627],

  # [ 0.2596, 0.5229, 2.3022],

  # [-1.4689, -1.5867, 1.2032],

  # [ 0.0845, -1.2001, -0.0048]], requires_grad=True)

  sentence = torch.tensor(encoded_tokens[0]) # 一共有三个句子,这里只使用第一个句子

  print(sentence)

  # tensor([1, 0, 2, 3, 4])

  print(emb(sentence))

  # tensor([[-0.4339, 0.8487, 0.6920],

  # [-1.1258, -1.1524, -0.2506],

  # [-0.3160, -2.1152, 0.3223],

  # [-1.2633, 0.3500, 0.3081],

  # [ 0.1198, 1.2377, 1.1168]], grad_fn=<EmbeddingBackward0>)

  print(emb.weight[sentence] == emb(sentence))

  # tensor([[True, True, True],

  # [True, True, True],

  # [True, True, True],

  # [True, True, True],

  # [True, True, True]])

  

  

  

2.3 nn.Embedding 与 nn.Linear 的区别

  细心的读者可能已经看出 nn.Embeddingnn.Linear 似乎很像,那它们到底有什么区别呢?

  回顾 nn.Linear,若不开启 bias,设输入向量为 x,nn.Linear.weight 对应的矩阵为 A(形状为 hidden_size × input_size),则计算方式为:

  

y=xAT

  其中 x , y 均为行向量。

  假如 x 是one-hot向量,第 i 个位置是 1 1 1,那么 y 就是 A T 的第 i i 行。

  现给定一个单词 w ,假设它在 word2idx 中的索引就是 i ,在 nn.Embedding 中,我们根据这个索引 i 去查找 emb.weight 的第 i 行。而在 nn.Linear 中,我们则是将这个索引 i 编码成一个one-hot向量,再去乘上对应的权重矩阵得到矩阵的第 i 行。

  请看下例:

  

torch.manual_seed(0)

  vocab_size = 4 # 词表大小为4

  embedding_dim = 3 # 词向量维度为3

  weight = torch.randn(4, 3) # 随机初始化权重矩阵

  # 保持线性层和嵌入层具有相同的权重

  linear_layer = nn.Linear(4, 3, bias=False)

  linear_layer.weight.data = weight.T # 注意转置

  emb_layer = nn.Embedding(4, 3)

  emb_layer.weight.data = weight

  idx = torch.tensor(2) # 假设某个单词在word2idx中的索引为2

  word = torch.tensor([0, 0, 1, 0]).to(torch.float) # 上述单词的one-hot表示

  print(emb_layer(idx))

  # tensor([ 0.4033, 0.8380, -0.7193], grad_fn=<EmbeddingBackward0>)

  print(linear_layer(word))

  # tensor([ 0.4033, 0.8380, -0.7193], grad_fn=<SqueezeBackward3>)

  

  从中我们可以总结出:

  

  • nn.Linear 接受向量作为输入,而 nn.Embedding 则是接受离散的索引作为输入;
  • nn.Embedding 实际上就是输入为one-hot向量,且不带bias的 nn.Linear

  此外,nn.Linear 在运算过程中做了矩阵乘法,而 nn.Embedding 是直接根据索引查表,因此在该情景下 nn.Embedding 的效率显然更高。

  

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: