Transformer中的位置编码PE(position encoding)

Transformer中的位置编码PE(position encoding)

对应视频讲解:

【代码详解】扩散模型中如何融合时间信息t到图x上(x+t),Transformer中的位置编码PE(position encoding)

nn.Embedding使用:http://t.csdnimg.cn/m2nKN

1.提出背景

transformer模型的attention机制并没有包含位置信息,即一句话中词语在不同的位置时在transformer中是没有区别的

2.解决背景

给encoder层和decoder层的输入添加了一个额外的向量Positional Encoding(PE),与embedding维度一致

embedding维度:

  • 句子:词向量的维度大小,如512
  • 图片:通道数

实际应用中,会对位置信息向量如[1,2,…,16]先进行位置编码,位置编码的维度可以先保持与句子编码维度一致,如512。再通过一个线性层,将维度降为需要的通道数,最后再进行信息合并。

3. 创建一个位置编码器PE

需要的输入设置

  • 序列的最大长度 max_seq_len,如1000
  • 编码向量的维度 d_model,如512或128

主体逻辑

  1. 计算PE矩阵
  2. 重新定义嵌入层:将嵌入层的权重替换为PE(不可训练)

PE计算
PE为二维矩阵,大小跟输入embedding的维度一样,行表示词语,列表示词向量;pos 表示词语在句子中的位置;dmodel表示词向量的维度;i表示词向量的位置。因此,上述公式表示在每个词语的词向量的偶数位置添加sin变量,奇数位置添加cos变量,以此来填满整个PE矩阵,然后加到input embedding中去,这样便完成位置编码的引入了。

参考:https://blog.csdn.net/qq_34771726/article/details/102918440

class PositionalEncoding(nn.Module):

    def __init__(self, max_seq_len: int, d_model: int):
        super().__init__()

        # Assume d_model is an even number for convenience
        assert d_model % 2 == 0   # 为了编码方便

        # ---1.计算PE矩阵
        # 位置编码二维矩阵PE的大小: [max_seq_len, d_model]
        pe = torch.zeros(max_seq_len, d_model)  # 初始化为零矩阵
        # 行:i向量 [0,1,2,..., 999]  表示每个时间步t
        i_seq = torch.linspace(0, max_seq_len - 1, max_seq_len)
        # 列:j向量 [0,2,4,6,8]       表示偶数位
        j_seq = torch.linspace(0, d_model - 2, d_model // 2)   #(0, 8, 5)
        # 生成网格数据: 2个矩阵[1000, 5]
        pos, two_i = torch.meshgrid(i_seq, j_seq)
        pe_2i = torch.sin(pos / 10000**(two_i / d_model))    # 偶数位sin
        pe_2i_1 = torch.cos(pos / 10000**(two_i / d_model))  # 奇数位cos
        # stack拼接到第2个维度[0,1,2],在把3维重塑为2维
        pe = torch.stack((pe_2i, pe_2i_1), 2).reshape(max_seq_len, d_model)

        # ---2.定义嵌入层
        self.embedding = nn.Embedding(max_seq_len, d_model)  # 定义了一个嵌入层
        self.embedding.weight.data = pe      # 使用位置编码计算好的嵌入矩阵对其进行初始化
        self.embedding.requires_grad_(False) # 将其参数设为不可训练

    def forward(self, t):
        # 调用嵌入层方法
        # t表示抽取的时间点向量: [32, 43, 85, 31, 86, 90, 67, 61, 50, 33, 87, 48, 31, 48, 48, 93]
        return self.embedding(t)

4.调用位置编码器PE

  1. 对输入的位置向量,如[1,2,…,16]. 先经过PE编码为词向量长度: [16, 1, 128]
  2. 与原图x拼接,即x+t
  • 先经过一个线性层,将词向量维度转换为与图片通道数一致
  • 与原图相加拼接
‘’‘
对输入时间点的位置编码
’‘’
# 1. 设置位置编码器PE
max_seq_len = 1000   # 最大序列长度
d_model = 128        # 编码向量的维度
pe = PositionalEncoding(max_seq_len, d_model)
pe

# 2.随机抽取时间点
n_steps = 100
batch_size = 16
t1 = torch.randint(0, n_steps, (batch_size, ))    # 随机抽取16个时间点

# 3.对时间点进行PE编码
p1 = pe(t1)
p1    # 得到位置编码结果[1000, 128]

将编码后的时间与原图进行拼接

‘’‘
将编码后的时间与原图进行拼接
’‘’
pe_dim = 128   # 词向量维度
channel = 1    # 图片通道数C
n = 16   # 图片批量大小(也就是上面时间t的步数)

# 1.先经过一个线性层,将词向量维度转换为与图片通道数一致
# 设置映射空间层
pe_linear = nn.Sequential(nn.Linear(pe_dim, channel), 
                           nn.ReLU(),
                           nn.Linear(channel, channel))
# 将128的词词向量维度转换为1的图片通道数
pe_v = pe_linear(p1).reshape(n, -1, 1, 1)  # (1, 128) -> (1,1) -> (1,1,1)
# pe_linear: 降维 128 -> 1 通道数
# reshape: 整理维度 [n, C, 1, 1]

# 2.将整理后的位置编码与图片连接
# 原图
x = torch.randn(1, 28, 28) 

# 拼接
x + pe_v  
# [16, 1, 28, 28]  
# 16: 数据批量大小(时间点的个数 - batch_size)
# 1: 通道数
# 28*28: 图片大小

对应视频讲解:

【代码详解】扩散模型中如何融合时间信息t到图x上(x+t),Transformer中的位置编码PE(position encoding)

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值