当我们使用 PyTorch 构建神经网络时,经常使用到一些内置的网络层。本篇文章主要介绍下列层的使用:
- 线性层(Linear)
- 词嵌入层(Embedding)
- 循环网络层(RNN、GRU、LSTM)
1. 线性层
torch.nn.Linear(in_features, out_features, bias=True, device=None)
- in_features 表示输入数据特征维度
- out_features 表示输出数据特征的维度
- bias 表示使用计算偏置
- device 表示指定计算设备
我们可以通过以下代码访问线性层的参数、偏置:
linear = nn.Linear(10, 20) # 权重 print(linear.weight) # 偏置 print(linear.bias)
PyTorch 中线性层的 weight 和 bias 使用范围 (-sqrt(1/in_features), sqrt(1/in_features))的均匀分布进行初始化。
线性层的计算公式如下:
import torch.nn as nn import torch def test(): # 输入数据 inputs = torch.randn(1, 10) # 线性层计算输出 linear = nn.Linear(10, 20) outputs = linear(inputs) print(outputs) # 手动计算输出 outputs = inputs @ linear.weight.data.T + linear.bias.data print(outputs) if __name__ == '__main__': test()
程序输出结果:
tensor([[ 0.6065, 0.8099, -0.2903, 0.5085, 0.9268, -0.2801, -0.3360, 0.2642, -0.6695, 0.1063, 0.8341, -0.3041, 0.0055, 0.9461, -0.0116, 0.0872, 0.3282, -0.7090, -0.9739, -0.0739]], grad_fn=<AddmmBackward>) tensor([[ 0.6065, 0.8099, -0.2903, 0.5085, 0.9268, -0.2801, -0.3360, 0.2642, -0.6695, 0.1063, 0.8341, -0.3041, 0.0055, 0.9461, -0.0116, 0.0872, 0.3282, -0.7090, -0.9739, -0.0739]])
我们发现输出结果是一样的。
2. 词嵌入层
torch.nn.Embedding(num_embeddings, embedding_dim, padding_idx=None, device=None)
- num_embeddings 表示词表中词的数量
- embedding_dim 表示词嵌入的维度
- padding_idx 表示填充词在词表中的序号,默认 None 表示不进行填充,稍后我们了解下该参数的作用
nn.Embedding 层的初始权重默认使用从均值为 0、标准差为 1 的标准正态分布中取值初始化,其并不是固定不变的,而是随着正向计算,反向传播会进行更新。
import torch import torch.nn as nn def test(): # num_embeddings 表示词表共有 10 个单词 # embedding_dim 表示每个词有 3 维度 embedding = nn.Embedding(num_embeddings=10, embedding_dim=3, padding_idx=4) # 词嵌入矩阵 print(embedding.weight.data) print('-' * 50) # 句子进行词嵌入 sentence = torch.tensor([[1, 2, 3], [6, 7, 8]]) sentence_embedding = embedding(sentence) print(sentence_embedding.data) print('-' * 50) sentence = torch.tensor([[1, 1, 4, 4], [6, 7, 8, 9]]) sentence_embedding = embedding(sentence) print(sentence_embedding.data) if __name__ == '__main__': test()
程序输出结果:
tensor([[ 2.7255, 1.1158, 0.9272], [-0.3430, 1.3805, 0.8425], [ 0.1564, -0.9834, -0.5991], [-0.9682, 0.0776, -2.0535], [ 0.0000, 0.0000, 0.0000], [-0.5484, -0.4215, 0.1984], [ 0.1445, -0.4071, 1.0063], [ 0.8116, 0.6240, -0.1881], [ 0.4918, -0.8921, -0.1006], [-0.2029, 1.5831, 0.5203]]) -------------------------------------------------- tensor([[[-0.3430, 1.3805, 0.8425], [ 0.1564, -0.9834, -0.5991], [-0.9682, 0.0776, -2.0535]], [[ 0.1445, -0.4071, 1.0063], [ 0.8116, 0.6240, -0.1881], [ 0.4918, -0.8921, -0.1006]]]) -------------------------------------------------- tensor([[[-0.3430, 1.3805, 0.8425], [-0.3430, 1.3805, 0.8425], [ 0.0000, 0.0000, 0.0000], [ 0.0000, 0.0000, 0.0000]], [[ 0.1445, -0.4071, 1.0063], [ 0.8116, 0.6240, -0.1881], [ 0.4918, -0.8921, -0.1006], [-0.2029, 1.5831, 0.5203]]])
我们发现,当 padding_idx 设置为 4 时,embedding.weight.data 第 4 下标位置就被设置为 0,那么当我们的 sentence 中句子长度不一,需要对较短的句子进行 padding 时,就可以用 4 来代替了。同理的,默认 padding_idx 的值为 0,所以在不修改其默认值的情况下,可以使用 0 来 padding 较短的 sentence。