您的位置:

深度学习之PyTorch中torch.nn.embedding详解

一、什么是torch.nn.embedding

torch.nn.embedding是PyTorch的一个模块,是神经网络中一个重要的embedding层,广泛应用于自然语言处理(NLP)中。对于一段文本,可以将每个单词用一个向量表示,向量的长度由用户指定,这些向量组成的矩阵就称为“embedding矩阵”。通过embedding层的转换,可以将原始信息变成计算机可用的向量,并帮助神经网络结构自动学习语义信息。

关于embedding的实现方式,比较常见的有One-Hot编码、预训练向量和自适应embedding。One-Hot编码是将每个单词表示为一个稀疏的高维向量,向量的维度为单词表的大小。预训练向量是将每个单词表示为一个维度固定的稠密向量,这些向量可以通过线性变换等方式预先训练获得。自适应embedding则是通过神经网络在训练过程中动态学习单词的嵌入向量。

import torch.nn as nn
import torch

# 定义一个embedding矩阵
emb = nn.Embedding(num_embeddings=100, embedding_dim=10)

# 随机生成一个长度为5的序列
input_seq = torch.randint(low=0, high=100, size=(1, 5))

# 将序列映射为embedding表示
emb_seq = emb(input_seq)

print(emb_seq)

这段代码定义了一个embedding矩阵,将矩阵的大小设置为(100, 10),表示有100个单词,每个单词用10维的向量表示。接着,使用torch.randint随机生成一个长度为5的序列,并将其映射为对应的embedding向量。最终,输出了一个大小为(1, 5, 10)的矩阵。

二、torch.nn.embedding的使用方法

1、num_embeddings和embedding_dim

torch.nn.embedding的参数中,num_embeddings表示词表的大小,即最大单词数。embedding_dim表示每个单词使用的嵌入维度大小。一般而言,embedding_dim的大小与模型的复杂度和单词量成正比。num_embeddings和embedding_dim的设置对训练效果有很大的影响,需要根据实际情况进行调节。

import torch.nn as nn
import torch

# 定义一个embedding矩阵
emb = nn.Embedding(num_embeddings=100, embedding_dim=10)

print(emb.weight.shape)

这段代码定义了一个embedding矩阵,将矩阵的大小设置为(100, 10),表示有100个单词,每个单词用10维的向量表示。接着,使用emb.weight.shape输出了矩阵的大小。

2、padding_idx

在自然语言处理中,一般会将不同长度的文本转换为固定长度的向量。然而,如果直接在不同长度之间加入0来实现padding,则可能导致模型计算时出错。padding_idx这个参数则是用来解决此问题的,它指定了padding的单词在embedding矩阵中的下标。这样,在实际计算时就可以跳过这个下标对应的单词。

import torch.nn as nn
import torch

# 定义一个embedding矩阵
emb = nn.Embedding(num_embeddings=100, embedding_dim=10, padding_idx=0)

# 定义一个长度为4的序列,其中包含0
input_seq = torch.tensor([0, 1, 2, 0])

# 将序列映射为embedding表示
emb_seq = emb(input_seq)

print(emb_seq)

这段代码定义了一个embedding矩阵,将矩阵的大小设置为(100, 10),padding_idx为0。接着,定义一个长度为4的序列,其中包含0,并将其映射为对应的embedding向量。最终,输出了一个大小为(4, 10)的矩阵。

3、max_norm和norm_type

在训练中,我们可以使用max_norm和norm_type这两个参数控制嵌入向量的大小。max_norm指定了最大的范数大小,norm_type指定使用哪种范数计算向量大小。通过限制嵌入向量的大小,可以避免过度参数化,进而克服过拟合问题。

import torch.nn as nn
import torch

# 定义一个embedding矩阵,指定max_norm和norm_type
emb = nn.Embedding(num_embeddings=100, embedding_dim=10, max_norm=1.0, norm_type=2.0)

# 随机生成一个长度为5的序列
input_seq = torch.randint(low=0, high=100, size=(1, 5))

# 将序列映射为embedding表示
emb_seq = emb(input_seq)

print(emb_seq)

这段代码定义了一个embedding矩阵,将矩阵的大小设置为(100, 10),max_norm为1,norm_type为2。接着,使用torch.randint随机生成一个长度为5的序列,并将其映射为对应的embedding向量。最终,输出了一个大小为(1, 5, 10)的矩阵。

三、torch.nn.embedding的应用场景

1、文本分类

在文本分类任务中,需要将每个单词转换为一个向量,并将整个文本表示为一个向量。可以使用torch.nn.embedding将每个单词映射为一个指定维度的向量,并将这些向量按照顺序连接成一个新的向量作为整个文本的表示。

import torch.nn as nn
import torch

# 定义一个embedding矩阵
emb = nn.Embedding(num_embeddings=100, embedding_dim=10)

# 定义一个长度为5的序列
input_seq = torch.tensor([1, 2, 3, 4, 5])

# 将序列映射为embedding表示
emb_seq = emb(input_seq)

# 对embedding结果进行池化操作
pooled_seq = torch.mean(emb_seq, dim=0)

# 获取整个文本的表示向量
text_repr = pooled_seq.unsqueeze(0)

print(text_repr)

这段代码定义了一个embedding矩阵,将矩阵的大小设置为(100, 10)。接着,定义一个长度为5的序列,并将其映射为对应的embedding向量。接着,使用torch.mean对embedding结果进行池化操作,并通过unsqueeze(0)将结果转换为一个大小为(1, 10)的矩阵,作为整个文本的表示向量。

2、语言模型

在语言模型任务中,需要根据先前的单词预测下一个单词。可以使用torch.nn.embedding将每个单词映射为一个指定维度的向量,并训练一个RNN等模型,将先前的单词作为输入,预测下一个单词。

import torch.nn as nn
import torch

# 定义一个embedding矩阵
emb = nn.Embedding(num_embeddings=100, embedding_dim=10)

# 定义一段文本
input_seq = torch.tensor([1, 2, 3, 4, 5])

# 将整个文本映射为embedding表示
emb_seq = emb(input_seq)

# 定义一个RNN模型
rnn = nn.RNN(input_size=10, hidden_size=20, batch_first=True)

# 将embedding结果作为模型的输入
output, hidden = rnn(emb_seq.unsqueeze(0))

print(output)

这段代码定义了一个embedding矩阵,将矩阵的大小设置为(100, 10)。接着,定义一段文本,并将其映射为对应的embedding向量。接着,定义一个RNN模型,将embedding结果作为模型的输入,得到模型的输出。

3、词嵌入可视化

使用torch.nn.embedding,可以将一个单词表示为一个固定维度的向量。该向量包含了单词的词义信息。我们可以使用PCA等降维方法,将这些向量可视化在二维或三维空间中,从而直观地了解单词在语义上的相似性。

import torch.nn as nn
import torch
import matplotlib.pyplot as plt
from sklearn.decomposition import PCA

# 定义一个embedding矩阵
emb = nn.Embedding(num_embeddings=100, embedding_dim=10)

# 得到嵌入向量集合
embeddings = emb.weight.detach().numpy()

# 使用PCA进行降维
pca = PCA(n_components=2)
pca_embeddings = pca.fit_transform(embeddings)

# 绘制散点图
words = ['word_%d'%i for i in range(100)]
x = pca_embeddings[:,0]
y = pca_embeddings[:,1]
plt.scatter(x, y)

for i, word in enumerate(words):
    plt.annotate(word, (x[i], y[i]))

plt.show()

这段代码定义了一个embedding矩阵,将矩阵的大小设置为(100, 10)。接着,使用PCA对矩阵降维。最后,通过matplotlib的scatter函数绘制散点图,并在每个点上添加对应的点名。