位置编码是一种将词汇位置信息注入到转换器架构中的技术。
词序对理解语句语义至关重要。例如"Allen 遛狗"与"狗遛 Allen"虽词汇相同,含义却完全迥异。在使用深度学习和神经网络实现自然语言处理 (NLP) 应用时,我们需要创建一种使机器保持词序以生成逻辑输出的机制。
传统上,循环神经网络 (RNN) 或长短期记忆 (LSTM) 等模型具备内置词序处理机制。RNN 和 LSTM 按顺序处理输入,一次处理一个词元,并记住序列中所有词汇位置。换句话说,n 维向量,也称为“输入向量”,被依次处理,这本身就是一种学习顺序。相比之下,其他利用卷积神经网络 (CNN) 或 转换器 (Vaswani 等人,2017 年) 的架构不保留词序,而是并行处理词元。因此,我们需要实现一种能显式表征序列词序的机制——即位置编码技术。位置编码允许转换器保留词序信息,实现并行化和高效模型训练。您可以经常在 GitHub 上找到位置编码的实现案例。
在自然语言中,句子或语序中的词序决定了句子的内在含义。此外,对于机器学习来说,词序编码可以提供一本“字典”,让我们知道每个单词应该放在哪里。这些信息在整个转换器模型的训练过程中都会被保留和泛化,从而实现了并行化,并在训练效率上超越 RNN 和 LSTM。
我们再回顾一下这个示例:
为了实现这一目标,我们首先将每个词处理为表示其含义的矢量,例如,将“狗”编码为一个高维数组,以表示其概念。用专业术语来说,每个词或子词都会映射到不同长度的输入嵌入。然而,意义向量本身并不能告诉我们“狗”在句子中出现的位置。位置编码会添加第二个向量,即对位置索引进行编码的向量,例如“第一个词”或“第二个词”,依此类推。然后将这两个向量相加,表示词是什么以及词在哪里。由此产生的向量通常称为位置编码向量。
创建位置编码的方法有很多种。在本文中,我们将探讨使用正弦函数的最著名例子,该函数由《Attention is all you need》1作者引入,用于创建位置编码。
在 Vaswani 等人 2017 年论文的核心思想是,通过正弦波形函数(特别是正弦函数和余弦函数)为序列中的每个位置生成固定且确定的编码 .
正弦函数是产生平滑波长模式的基础数学概念。特别是,作者在原始转换器函数中使用余弦和正弦函数来帮助位置编码。
如果我们绘制 以及 我们将看到一条曲线在 -1 和 1 之间以重复的周期性模式上升和下降。
正弦波的一些特性使其成为位置编码的强大工具:
让我们绘制正弦波和余弦波,直观地了解它们的外观:
import numpy as np
import matplotlib.pyplot as plt
# Create an array of 100 x values evenly spaced from 0 to 2π (approx 6.28)
x = np.linspace(0, 2 * np.pi, 100)
# Compute the sine and cosine of each x value
sin_values = np.sin(x)
# Create the plot
plt.figure(figsize=(5, 2))
plt.plot(x, sin_values, label='sin(x)', color='blue')
# Customize the plot
plt.title('Sine Function')
plt.xlabel('x')
plt.ylabel('Function value')
plt.axhline(0, color='black', linewidth=0.5) # horizontal line at y=0
plt.axvline(0, color='black', linewidth=0.5) # vertical line at x=0
#plt.grid(True, linestyle='--', alpha=0.5)
plt.legend()
plt.tight_layout()
# Show the plot
plt.show()
正弦函数
现在我们来看看如何绘制余弦函数图:
#apply the cosine function to the same array, x
cosine = np.cos(x)
plt.figure(figsize = (5,2))
plt.plot(x, cosine, label = 'cos(x)', color = 'blue')
plt.title('The Cosine Function')
plt.xlabel('x')
plt.ylabel('Function value')
plt.axhline(0, color='black', linewidth=0.5) # horizontal line at y=0
plt.axvline(0, color='black', linewidth=0.5) # vertical line at x=0
#plt.grid(True, linestyle='--', alpha=0.5)
plt.legend()
plt.tight_layout()
由原始转换器论文作者(Vaswani 等人,2017 年)定义的正弦位置编码公式如下所示:
偶数位置:
奇数位置:
:词汇在句中的位置(如首词为 0,次词为 1,依此类推。)
:嵌入向量的维度索引。映射到列索引。2i 表示偶数位置,2i+1 表示奇数位置
:预定义的词元嵌入维度(如 512)
:用户定义的标量值(如 10000)
:位置函数,将输入序列中位置 k 映射为位置编码的函数
通过此公式,每个位于 k 位置的词汇将获得基于其位置的嵌入值。以所使用的“Allen 遛狗”为例,我们可以计算各单词的位置嵌入:
- = "Allen"
- = "walks"
- ="dog"
让我们编写一个简单的 Python 函数来计算以下值: :
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
我们调用该函数并输入示例中的相应值后,序列长度为 3,简化维度为 ,和
P = getPositionEncoding(seq_len=3, d=4, n=10000)
print(P)
我们得到如下编码矩阵(也称为张量):
[[ 0. 1. 0. 1. ]
[ 0.84147098 0.54030231 0.09983342 0.99500417]
[ 0.90929743 -0.41614684 0.19866933 0.98006658]]
为了更具体地表示此结果,我们得到
| 词汇位置 | Dim 0 sin(pos ÷ 10000^(0 ÷ 4)) | Dim 1 cos(pos ÷ 10000^(0 ÷ 4)) | Dim 2 sin(pos ÷ 10000^(2 ÷ 4)) | Dim 3 cos(pos ÷ 10000^(2 ÷ 4)) |
|---|---|---|---|---|
| “Allen” k = 0 | 0.0000 | 0.0000 | 0.0000 | 1.0000 |
| “walks” k = 1 | 0.841471 | 0.540302 | 0.010000 | 0.999950 |
| “dog” k = 2 | 0.909297 | -0.416147 | 0.020000 | 0.999800 |
此处可见各词汇及其对应位置嵌入的具体数值。然而,我们不能直接使用这些词嵌入来解读词序。计算所得值用于向转换器输入向量注入位置信息。由于输入 以及 不同,每个位置 将对应不同正弦函数。不同正弦函数的相应位置为我们提供了有关“Allen 遛狗”中词汇的绝对位置与相对位置信息。换句话说,模型可以利用这些信息,学会将这些模式与顺序、间距和结构联系起来。
现在,让我们执行一个 python 函数,将位置矩阵可视化
import numpy as np
import matplotlib.pyplot as plt
def get_position_encoding(seq_len, d_model, n=10000):
P = np.zeros((seq_len, d_model))
for pos in range(seq_len):
for i in range(d_model):
angle = pos / np.power(n, (2 * (i // 2)) / d_model)
P[pos, i] = np.sin(angle) if i % 2 == 0 else np.cos(angle)
return P
# Parameters
seq_len = 100 # Number of tokens
d_model = 512 # Embedding dimensions
# Generate positional encoding
P = get_position_encoding(seq_len, d_model)
# Plot
plt.figure(figsize=(10, 6))
cax = plt.matshow(P, cmap='viridis', aspect='auto')
plt.title("Sinusoidal Positional Encoding Heatmap")
plt.xlabel("Embedding Dimension")
plt.ylabel("Token Position")
plt.colorbar(cax)
plt.tight_layout()
plt.show()
我们可以看到,频率因 x 的值而异,输入词汇 k 的每个对应位置的差异范围为 —函数范围 。在此基础上,我们基于编码器和解码器的 转换器模型将学习并保留各词汇的不同位置编码,使模型能够保留信息用于训练。编码位置向量在训练过程中保持静态,从而实现并行计算。
使用面向 AI 构建器的新一代企业级开发平台 IBM watsonx.ai,可以训练、验证、调整和部署生成式 AI、基础模型和机器学习功能。使用一小部分数据,即可在很短的时间内构建 AI 应用程序。
借助 IBM 业界领先的人工智能专业知识和解决方案组合,让人工智能在您的业务中发挥作用。
通过增加 AI 重塑关键工作流程和运营,最大限度提升体验、实时决策和商业价值。
1. “Attention Is All You Need”, Ashish Vaswani et al., Proceedings of the 31st International Conference on Neural Information Processing Systems, arXiv:1706.03762v7, 2023年8月2日修订。
2. “Long Short-Term Memories”, Sepp Hochreiter and Jürgen Schmidhuber. 1997. Long Short-Term Memory. Neural Comput. 9, 8 (November 15, 1997), 1735–1780.,
3. “Foundations of Recurrent Neural Networks (RNNs) and Long Short-Term Memories” Alex Sherstinsky et al., Elsevier “Physica D: Nonlinear Phenomena” journal, Volume 404, March 2020: Special Issue on Machine Learning and Dynamical Systems