从这节课开始,就正式进入代码部分了,就按照 Transformer 的模型结构顺序来讲解。首先就是文本向量化,需要把文字转化成向量,才能进行数学运算。

完整的文本向量化过程,要分为两步,第一步是是把文字转化为一个索引,也就是找到这个字在词表中的索引位置;第二步,就是从随机生成的 lookup table 中,找这个索引对应的向量,作为这个词的表征。

直观示例

# 词表
不  0
抛  1
弃  2
放  3
永  4
言  5

# lookup table
[[ 0.8876, -0.4091, -0.6816],
[-1.4386,  0.3714, -1.5079],
[ 0.7514,  0.5945,  0.9892],
[ 0.7097, -0.2346, -0.1921],
[ 0.9248,  1.4994, -2.5817],
[-1.8989, -0.7199, -1.7468]]

# 永不言弃

代码示例

1、文本向量化

完整词表,要结合语料才能生成,放到后面再处理。假设词表大小为10,词向量维度为8。

import math
import torch
from torch import nn

# 实例化类
emb = nn.Embedding(10, 8)

# lookup table
print(emb.weight)

# 单个词向量
print(emb(torch.tensor([1])))

# 两个句子
print(emb(torch.tensor([
    [1, 2, 3],
    [1, 5, 0],
])))

# 指定填充id
emb = nn.Embedding(10, 8, padding_idx=0)

2、封装 Embedding 类(文本嵌入层)

class Embeddings(nn.Module):
    def __init__(self, vocab_size, d_model):
        super().__init__()
        # Embedding层
        self.lut = nn.Embedding(vocab_size, d_model)
        # Embedding维数
        self.d_model = d_model

    def forward(self, x):
        # 返回x对应的embedding矩阵,需要乘以math.sqrt(d_model)
        return self.lut(x) * math.sqrt(self.d_model)

emb = Embeddings(10, 8)
inputs = torch.tensor([
    [1, 2, 3],
    [4, 5, 0],
])
output1 = emb(inputs)
print(output1)

封装过程比较简单,但需要注意是,最后返回值是词向量乘以 math.sqrt(self.d_model) ,论文中有提及,但没有说明原因,同时这也是面试中的一个考点。

主要原因是,在后面要对模型参数进行初始化,初始化的方法是 xavier,这个方法随机初始化的参数,随机抽样分布满足N(0, 1/d_model),d_model越大,方差会越小,乘以 math.sqrt(self.d_model),可以拉回到 N(0, 1) 分布。

参考论文:Understanding the difficulty of training deep feedforward neural networks

本文链接:http://edu.ichenhua.cn/edu/note/651

版权声明:本文为「陈华编程」原创课程讲义,请给与知识创作者起码的尊重,未经许可不得传播或转售!