在Attention Is All You Need中,作者们实现了一种位置编码(它增加了关于单词在序列中位置的信息)。为此,他们使用了正弦位置编码:
PE(pos,2i) = sin(pos/10000**(2*i/hidden_units))PE(pos,2i+1) = cos(pos/10000**(2*i/hidden_units))
其中pos是位置,i是维度。这必须生成一个形状为[max_length, embedding_size]的嵌入矩阵,即,给定序列中的一个位置,它返回PE[position,:]的张量。
我找到了Kyubyong的实现,但我不是完全理解它。
我尝试用numpy这样实现它:
hidden_units = 100 # 嵌入的维度vocab_size = 10 # 最大句子长度# 矩阵[[1, ..., 99], [1, ..., 99], ...]i = np.tile(np.expand_dims(range(hidden_units), 0), [vocab_size, 1])# 矩阵[[1, ..., 1], [2, ..., 2], ...]pos = np.tile(np.expand_dims(range(vocab_size), 1), [1, hidden_units])# 应用中间函数pos = np.multiply(pos, 1/10000.0)i = np.multiply(i, 2.0/hidden_units)matrix = np.power(pos, i)# 对偶数列应用正弦函数matrix[:, 1::2] = np.sin(matrix[:, 1::2]) # 偶数# 对奇数列应用余弦函数matrix[:, ::2] = np.cos(matrix[:, ::2]) # 奇数# 绘图im = plt.imshow(matrix, cmap='hot', aspect='auto')
我不明白这个矩阵如何提供输入位置的信息。有人能首先告诉我这是否是计算它的正确方法,其次是背后的原理是什么吗?
谢谢你。
回答:
我在pytorch实现中找到了答案:
# 保留维度0用于填充标记的位置编码零向量position_enc = np.array([ [pos / np.power(10000, 2*i/d_pos_vec) for i in range(d_pos_vec)] if pos != 0 else np.zeros(d_pos_vec) for pos in range(n_position)])position_enc[1:, 0::2] = np.sin(position_enc[1:, 0::2]) # 维度2iposition_enc[1:, 1::2] = np.cos(position_enc[1:, 1::2]) # 维度2i+1return torch.from_numpy(position_enc).type(torch.FloatTensor)
其中d_pos_vec是嵌入维度,n_position是最大序列长度。
编辑:
在论文中,作者们说这种嵌入矩阵的表示允许“模型推断到比训练期间遇到的序列长度更长的序列”。
两个位置之间的唯一区别是pos
变量。查看下面的图像以获得图形表示。