• 深度学习:pytorch nn.Embedding详解


    目录

    1 nn.Embedding介绍

    1.1 nn.Embedding作用

    1.2 nn.Embedding函数描述

    1.3 nn.Embedding词向量转化

    2 nn.Embedding实战

    2.1 embedding如何处理文本

    2.2 embedding使用示例

    2.3 nn.Embedding的可学习性


    1 nn.Embedding介绍

    1.1 nn.Embedding作用

    nn.Embedding是PyTorch中的一个常用模块,其主要作用是将输入的整数序列转换为密集向量表示。在自然语言处理(NLP)任务中,可以将每个单词表示成一个向量,从而方便进行下一步的计算和处理。

    1.2 nn.Embedding函数描述

    nn.Embedding是将输入向量化,定义如下:

    1. torch.nn.Embedding(num_embeddings,
    2. embedding_dim,
    3. padding_idx=None,
    4. max_norm=None,
    5. norm_type=2.0,
    6. scale_grad_by_freq=False,
    7. sparse=False,
    8. _weight=None,
    9. _freeze=False,
    10. device=None,
    11. dtype=None)

    参数说明:

    • num_embeddings :字典中词的个数
    • embedding_dim:embedding的维度
    • padding_idx(索引指定填充):如果给定,则遇到padding_idx中的索引,则将其位置填0(0是默认值,事实上随便填充什么值都可以)。

    注:embeddings中的值是正态分布N(0,1)中随机取值。

    1.3 nn.Embedding词向量转化

    在PyTorch中,nn.Embedding用来实现词与词向量的映射。nn.Embedding具有一个权重(.weight),形状是(num_words, embedding_dim)。例如一共有100个词,每个词用16维向量表征,对应的权重就是一个100×16的矩阵。

    Embedding的输入形状N×W,N是batch size,W是序列的长度,输出的形状是N×W×embedding_dim。

    Embedding输入必须是LongTensor,FloatTensor需通过tensor.long()方法转成LongTensor。

    Embedding的权重是可以训练的,既可以采用随机初始化,也可以采用预训练好的词向量初始化。

    2 nn.Embedding实战

    2.1 embedding如何处理文本

    在NLP任务中,首先要对文本进行处理,将文本进行编码转换,形成向量表达,embedding处理文本的流程如下:

    (1)输入一段文本,中文会先分词(如jieba分词),英文会按照空格提取词

    (2)首先将单词转成字典的形式,由于英语中以空格为词的分割,所以可以直接建立词典索引结构。类似于:word2id = {'i' : 1, 'like' : 2, 'you' : 3, 'want' : 4, 'an' : 5, 'apple' : 6} 这样的形式。如果是中文的话,首先进行分词操作。

    (3)然后再以句子为list,为每个句子建立索引结构,list [ [ sentence1 ] , [ sentence2 ] ] 。以上面字典的索引来说,最终建立的就是 [ [ 1 , 2 , 3 ] , [ 1 , 4 , 5 , 6 ] ] 。这样长短不一的句子

    (4)接下来要进行padding的操作。由于tensor结构中都是等长的,所以要对上面那样的句子做padding操作后再利用 nn.Embedding 来进行词的初始化。padding后的可能是这样的结构

    [ [ 1 , 2 , 3, 0 ] , [ 1 , 4 , 5 , 6 ] ] 。其中0作为填充。(注意:由于在NMT任务中肯定存在着填充问题,所以在embedding时一定存在着第三个参数,让某些索引下的值为0,代表无实际意义的填充)

    2.2 embedding使用示例

    比如有两个句子:

    • I want a plane

    • I want to travel to Beijing

    将两个句子转化为ID映射:

    {I:1,want:2,a:3,plane:4,to:5,travel:6,Beijing:7}

    转化成ID表示的两个句子如下:

    • 1,2,3,4

    • 1,2,5,6,5,7

    1. import torch
    2. from torch import nn
    3. # 创建最大词个数为10,每个词用维度为4表示
    4. embedding = nn.Embedding(10, 4)
    5. # 将第一个句子填充0,与第二个句子长度对齐
    6. in_vector = torch.LongTensor([[1, 2, 3, 4, 0, 0], [1, 2, 5, 6, 5, 7]])
    7. out_emb = embedding(in_vector)
    8. print(in_vector.shape)
    9. print((out_emb.shape))
    10. print(out_emb)
    11. print(embedding.weight)

    运行结果显示如下:

    1. torch.Size([2, 6])
    2. torch.Size([2, 6, 4])
    3. tensor([[[-0.6642, -0.6263, 1.2333, -0.6055],
    4. [ 0.9950, -0.2912, 1.0008, 0.1202],
    5. [ 1.2501, 0.1923, 0.5791, -1.4586],
    6. [-0.6935, 2.1906, 1.0595, 0.2089],
    7. [ 0.7359, -0.1194, -0.2195, 0.9161],
    8. [ 0.7359, -0.1194, -0.2195, 0.9161]],
    9. [[-0.6642, -0.6263, 1.2333, -0.6055],
    10. [ 0.9950, -0.2912, 1.0008, 0.1202],
    11. [-0.3216, 1.2407, 0.2542, 0.8630],
    12. [ 0.6886, -0.6119, 1.5270, 0.1228],
    13. [-0.3216, 1.2407, 0.2542, 0.8630],
    14. [ 0.0048, 1.8500, 1.4381, 0.3675]]], grad_fn=)
    15. Parameter containing:
    16. tensor([[ 0.7359, -0.1194, -0.2195, 0.9161],
    17. [-0.6642, -0.6263, 1.2333, -0.6055],
    18. [ 0.9950, -0.2912, 1.0008, 0.1202],
    19. [ 1.2501, 0.1923, 0.5791, -1.4586],
    20. [-0.6935, 2.1906, 1.0595, 0.2089],
    21. [-0.3216, 1.2407, 0.2542, 0.8630],
    22. [ 0.6886, -0.6119, 1.5270, 0.1228],
    23. [ 0.0048, 1.8500, 1.4381, 0.3675],
    24. [ 0.3810, -0.7594, -0.1821, 0.5859],
    25. [-1.4029, 1.2243, 0.0374, -1.0549]], requires_grad=True)

    注意:

    • 句子中的ID不能大于最大词的index(上面例子中,不能大于10)
    • embeding的输入必须是维度对齐的,如果长度不够,需要预先做填充

    2.3 nn.Embedding的可学习性

    nn.Embedding中的参数并不是一成不变的,它也是会参与梯度下降的。也就是更新模型参数也会更新nn.Embedding的参数,或者说nn.Embedding的参数本身也是模型参数的一部分。

    1. import torch
    2. from torch import nn
    3. # 创建最大词个数为10,每个词用维度为4表示
    4. embedding = nn.Embedding(10, 4)
    5. # 将第一个句子填充0,与第二个句子长度对齐
    6. in_vector = torch.LongTensor([[1, 2, 3, 4, 0, 0], [1, 2, 5, 6, 5, 7]])
    7. optimizer = torch.optim.SGD(embedding.parameters(), lr=0.01)
    8. criteria = nn.MSELoss()
    9. for i in range(1000):
    10. outputs = embedding(torch.LongTensor([1, 2, 3, 4]))
    11. loss = criteria(outputs, torch.ones(4, 4))
    12. loss.backward()
    13. optimizer.step()
    14. optimizer.zero_grad()
    15. print(embedding.weight)
    16. new_output = embedding(in_vector)
    17. print(new_output)

    经过1000epochs的训练后,查看新的编码结果,显示如下:

    1. Parameter containing:
    2. tensor([[-0.2475, -1.3436, -0.0449, 0.2093],
    3. [ 0.4831, 0.5887, 1.2278, 1.1106],
    4. [ 1.1809, 0.7451, 0.2049, 1.3053],
    5. [ 0.7369, 1.1276, 1.0066, 0.4399],
    6. [ 1.3064, 0.3979, 0.8753, 0.9410],
    7. [-0.6222, 0.2574, 1.1211, 0.1801],
    8. [-0.5072, 0.2564, 0.5500, 0.3136],
    9. [-1.7473, 0.0504, -0.0633, -0.3138],
    10. [-2.4507, -0.6092, 0.0348, -0.4384],
    11. [ 0.9458, -0.2867, -0.0285, 1.1842]], requires_grad=True)
    12. tensor([[[ 0.4831, 0.5887, 1.2278, 1.1106],
    13. [ 1.1809, 0.7451, 0.2049, 1.3053],
    14. [ 0.7369, 1.1276, 1.0066, 0.4399],
    15. [ 1.3064, 0.3979, 0.8753, 0.9410],
    16. [-0.2475, -1.3436, -0.0449, 0.2093],
    17. [-0.2475, -1.3436, -0.0449, 0.2093]],
    18. [[ 0.4831, 0.5887, 1.2278, 1.1106],
    19. [ 1.1809, 0.7451, 0.2049, 1.3053],
    20. [-0.6222, 0.2574, 1.1211, 0.1801],
    21. [-0.5072, 0.2564, 0.5500, 0.3136],
    22. [-0.6222, 0.2574, 1.1211, 0.1801],
    23. [-1.7473, 0.0504, -0.0633, -0.3138]]], grad_fn=)

    权重参数和编码结果都发生了很大变化,所以nn.Embedding在构建模型过程中,可以作为模型的一部分,进行共同训练。

  • 相关阅读:
    20221115 今天的世界发生了什么
    除镍树脂-HP4020
    Jmeter压测——BlazeMeter录制脚本+Jmeter进行测试
    springboot 捕获数据库唯一索引导致的异常
    Linux开发讲课14--- CPU100%该如何处理
    【vue循环】如何显示商家与商家里的商品数据?
    前后端分离毕设项目之springboot同城上门喂遛宠物系统(内含文档+源码+教程)
    AidLux OS搭建web站点
    ArrayList为什么线程不安全以及三种解决办法【详细】
    会话控制学习
  • 原文地址:https://blog.csdn.net/lsb2002/article/details/132993128