transformer 位置编码

文章介绍了在PyTorch中使用图像位置编码的方法,以及如何实现Transformer中的位置编码,包括三角函数式位置编码的详细解释和特点,如唯一性、一致性、可扩展性和确定性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

pytorchcv cv图像位置编码

pytorch 实现位置编码

位置编码使用例子:

通俗易懂的:

从上面效果图可以看出,这个三角函数式位置编码满足以下四个特点:

transformer 位置编码

transformer 位置编码通俗解释

绝对位置和相对位置


pytorchcv cv图像位置编码


import numpy as np

# 创建一个223x223的矩阵,这里以全0矩阵为例
original_matrix = np.zeros((3, 3))

# 创建一个224x224的新矩阵,初始值设为0.1
expanded_matrix = np.full((4, 4), 0.1)

# 将原始矩阵的值复制到新矩阵的前223行和列
expanded_matrix[:3, :3] = original_matrix

# 现在expanded_matrix是一个224x224的矩阵,新的行和列已经初始化为0.1
# 如果需要,可以这样验证
print(expanded_matrix)
print(expanded_matrix.shape)  # 输出: (224, 224)

pytorch 实现位置编码

转自:https://www.jianshu.com/p/303fef5c212a

import torch
from torch import nn 
from d2l import torch as d2l
#@save
class PositionalEncoding(nn.Module):
    """位置编码"""
    def __init__(self, num_hiddens, dropout, max_len=1000):
        super(PositionalEncoding, self).__init__()
        self.dropout = nn.Dropout(dropout)
        # 创建一个足够长的P
        self.P = torch.zeros((1, max_len, num_hiddens))
        X = torch.arange(max_len, dtype=torch.float32).reshape(
            -1, 1) / torch.pow(10000, torch.arange(
            0, num_hiddens, 2, dtype=torch.float32) / num_hiddens)
        self.P[:, :, 0::2] = torch.sin(X)
        self.P[:, :, 1::2] = torch.cos(X)

    def forward(self, X):
        X = X + self.P[:, :X.shape[1], :].to(X.device)
        return self.dropout(X)
encoding_dim, num_steps = 32, 60
pos_encoding = PositionalEncoding(encoding_dim, 0)
pos_encoding.eval()
X = pos_encoding(torch.zeros((1, num_steps, encoding_dim)))
P = pos_encoding.P[:, :X.shape[1], :]
d2l.plot(torch.arange(num_steps), P[0, :, 6:10].T, xlabel='Row (position)',
         figsize=(6, 2.5), legend=["Col %d" % d for d in torch.arange(6, 10)])
P = P[0, :, :].unsqueeze(0).unsqueeze(0)
d2l.show_heatmaps(P, xlabel='Column (encoding dimension)',
                  ylabel='Row (position)', figsize=(3.5, 4), cmap='Blues')


位置编码使用例子:

import time

import numpy as np
import torch
from torch import nn


# 定义Transformer模型
class TimeSeriesTransformer(nn.Module):
    def __init__(self, input_size, num_layers, num_heads, dropout=0.1):
        super(TimeSeriesTransformer, self).__init__()
        self.model_type = 'Transformer'
        self.src_mask = None
        self.pos_encoder = PositionalEncoding(input_size, dropout)
        self.encoder_layer = nn.TransformerEncoderLayer(d_model=input_size, nhead=num_heads, dropout=dropout)
        self.transformer_encoder = nn.TransformerEncoder(self.encoder_layer, num_layers=num_layers)
        self.decoder = nn.Linear(288, 32)

    def forward(self, src):
        src = self.pos_encoder(src)
        output = self.transformer_encoder(src, self.src_mask)
        output=output.reshape(output.size(0), -1)
        output = self.decoder(output)
        return output.reshape(-1, 4, 8)

# 位置编码
class PositionalEncoding(nn.Module):
    def __init__(self, input_size, dropout=0.1, max_len=5000):
        super(PositionalEncoding, self).__init__()
        self.dropout = nn.Dropout(p=dropout)

        pe = torch.zeros(max_len, input_size)
        position = torch.arange(0, max_len, dtype=torch.float).unsqueeze(1)

        # 生成正弦用的div_term,对于维度为9的输入,我们需要5个正弦值
        div_term_even = torch.exp(torch.arange(0, input_size, 2).float() * (-np.log(10000.0) / input_size))
        # 生成余弦用的div_term,对于维度为9的输入,我们需要4个余弦值
        div_term_odd = torch.exp(torch.arange(1, input_size, 2).float() * (-np.log(10000.0) / input_size))

        # 正弦赋值,对于维度为9的输入,我们应该赋值给索引0, 2, 4, 6, 8
        pe[:, 0::2] = torch.sin(position * div_term_even.unsqueeze(0))

        # 余弦赋值,对于维度为9的输入,我们应该赋值给索引1, 3, 5, 7
        pe[:, 1::2] = torch.cos(position * div_term_odd.unsqueeze(0))

        pe = pe.unsqueeze(0).transpose(0, 1)
        self.register_buffer('pe', pe)

    def forward(self, x):
        x = x + self.pe[:x.size(0), :]
        return self.dropout(x)
if __name__ == '__main__':

    net = TimeSeriesTransformer(input_size=9, num_layers=10, num_heads=3)

    for i in range(10):
        data = torch.rand(16, 32,9)

        start = time.time()
        out = net(data)

        print('time', time.time() - start, out.size())

通俗易懂的:

以下内容转自:

Transformer的位置编码_transformer 位置编码器-优快云博客

建议看原文,本文不完整,

1. 什么是位置编码,为什么要使用位置编码
简单来说位置编码就是给一个句子中的每个token一个位置信息,通过位置编码可以明确token的前后顺序关系。

对任何语言来说,句子中词汇的顺序和位置都是非常重要的。它们定义了语法,从而定义了句子的实际语义。RNN结构本身就涵盖了单词的顺序,RNN按顺序逐字分析句子,这就直接在处理的时候整合了文本的顺序信息。

但Transformer架构抛弃了循环机制,仅采用多头自注意机制。避免了RNN较大的时间成本。并且从理论上讲,它可以捕捉句子中较长的依赖关系。

由于句子中的单词同时流经Transformer的编码器、解码器堆栈,模型本身对每个单词没有任何位置信息的。因此,仍然需要一种方法将单词的顺序整合到模型中。

想给模型一些位置信息,一个方案是在每个单词中添加一条关于其在句子中位置的信息。我们称之为“信息片段”,即位置编码。

2. 两种简单的位置编码
最容易想到两种位置编码:
(1)为每个时间步添加一个0-1范围内的数字,其中0表示第一个单词,1表示最后一个单词。

我喜欢吃洋葱 【0 0.16 0.32.....1】

我真的不喜欢吃洋葱【0 0.125 0.25.....1】


问题:我们可以看到,如果句子长度不同,那么位置编码是不一样,所以无法表示句子之间有什么相似性。

(2)1-n正整数范围分配

我喜欢吃洋葱 【1,2,3,4,5,6】

我真的不喜欢吃洋葱【1,2,3,4,5,6,7】



问题:往往句子越长,后面的值越大,数字越大说明这个位置占的权重也越大,这样的方式无法凸显每个位置的真实的权重。

3. Transformer的位置编码
可以看到上面两种简单的位置编码方式都有明显的不足,理想情况下,应满足以下标准:

每个时间步都有唯一的编码。
在不同长度的句子中,两个时间步之间的距离应该一致。
模型不受句子长短的影响,并且编码范围是有界的。(不会随着句子加长数字就无限增大)
必须是确定性的。
Transformer的作者设计了一种可以满足上面要求的三角函数位置编码方式。首先为每个不同位置的单词(token)单独生成一个位置向量(或者叫位置嵌入,即position embedding,缩写为PE);其次,这种编码并没有集成到模型本身中,该向量用于为每个单词提供有关其在句子中位置的信息,也就是说,其修改了模型的输入,添加了单词的顺序信息。

位置编码方式如下:

4. 为什么要使用三角函数进行位置编码
可以使得不同位置的编码向量之间有一定的规律性,比如相邻位置之间的差异较小,而距离较远的位置之间的差异较大。

这是由正弦和余弦函数的连续性和单调性保证的,即对于任意两个相邻的位置,它们对应的编码向量在每一个维度上都只有微小的变化,而对于任意两个距离较远的位置,它们对应的编码向量在每一个维度上都有较大的差异。

可以使得编码向量在任意维度上都能保持唯一性,即不同位置在同一个维度上不会有相同的值。

这是由正弦和余弦函数的周期性和相位差保证的,即对于任意两个不同的位置,它们对应的编码向量在每一个维度上都不相等。


我们假设max_len为50, d dd 取128,所以 w ww 的取值范围就是0.0001~1,t tt 的范围是0~49,所以三角函数自变量的取值范围是0~49,结果的取值范围为-1~1。则在 t tt 为0时,对应的位置编码为[0, 1, 0, 1, 0, 1, ···, 0, 1],这一点可以从下图的第一行看出来是0,1交替的。

相邻token位置编码每一位的 w ww 相同只有 t tt 相差1,由于三角函数的连续性,所以相邻token的位置编码值只有比很小的差别。


从上面效果图可以看出,这个三角函数式位置编码满足以下四个特点:

语句中每个词的位置编码是唯一的;
不同长度的句子中任意相邻两个词的间隔距离是一致的;
模型可以很容易处理更长的语句,并且值有界;
位置编码是确定性的。


原文链接:https://blog.youkuaiyun.com/comli_cn/article/details/130427510

transformer 位置编码

transformer 位置编码通俗解释

Transformer位置编码图解 - 知乎

import numpy as np
import matplotlib.pyplot as plt

def getPositionEncoding(seq_len, d, n=10000):
    P = np.zeros((seq_len, d))
    for k in range(seq_len):
        for i in np.arange(int(d/2)):
            denominator = np.power(n, 2*i/d)
            P[k, 2*i] = np.sin(k/denominator)
            P[k, 2*i+1] = np.cos(k/denominator)
    return P

P = getPositionEncoding(seq_len=4, d=4, n=100)
print(P)

绝对位置和相对位置

Transformer位置编码(基础) - 知乎

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AI算法网奇

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值