- 🍨 本文为🔗365天深度学习训练营 中的学习记录博客
- 🍖 原作者:K同学啊
目录
- 前言
- 什么是位置编码
- 1. 定义
- 2. 三角函数
- 3. 位置编码公式
- 4. 位置编码示例
- 可视化理解位置编码
- 1. 代码实现
- 2. 观察不同位置对应的曲线
- 3. 整句话的位置编码可视化
- 总结与心得体会
前言
在NLP任务中,单词的序列顺序是非常重要的,将单词的顺序重新排列,整个句子的意思可能会发生改变。在RNN循环神经网络中,有着处理序列顺序的内置机制。Transformer通过引入位置编码机制来保存文本中字符的位置信息。
什么是位置编码
1. 定义
位置编码记录了文本中字符的位置信息,它并没有使用单个数字(例如索引值)的形式来记录位置信息。原因主要有:
- 对于长序列,索引的大小可能会变得很大,不利于存储。
- 将索引值规范化到0-1之间,可能会为可变长度序列带来问题(它们的标准化方式不同)。
Transformer使用智能位置编码方案,第个位置/索引都映射到了一个向量,所以位置编码层的输出明天是一个矩阵,其中矩阵的每一行代表序列中的一个编码对象与其位置信息相加。
2. 三角函数
正弦函数的值域为[-1, 1],可以等效地使用正弦函数或余弦函数。
3. 位置编码公式
假设你有一个长度为L的输入序列,要计算第K个元素的位置编码,可以由不同频率的正弦和余弦函数给出:
P ( k , 2 i ) = s i n ( k n 2 i / d ) P(k, 2i) = sin(\frac k {n^{2i/d}}) P(k,2i)=sin(n2i/dk)
P ( k , 2 i + 1 ) = c o s ( k n 2 i / d ) P(k, 2i + 1) = cos(\frac k {n^{2i/d}}) P(k,2i+1)=cos(n2i/dk)
参数详解:
- k k k: 对象(也就是句子中的字符)在输入序列中的位置, 0 < = k < L / 2 0<=k<L/2 0<=k<L/2
- d d d: 输出嵌入空间的维度
- P ( k , j ) P(k,j) P(k,j): 位置函数,用于映射输入序列中k处的元素到位置矩阵的 ( k , j ) (k, j) (k,j)处
- n n n: 用户定义的标量(论文中作者设置的是10000)
- i i i: 用于映射到列索引, 0 < = i < d / 2 0<=i<d/2 0<=i<d/2,单个值i映射到正弦和余弦函数
4. 位置编码示例
以"I am a robot"为例,并且设置n=100, d=4,下面是过程,注意仅是位置编码,所以和具体的字符是无关的。使用"You are a doctor"计算完会得到一样的结果。
可视化理解位置编码
1. 代码实现
import numpy as np
import matplotlib.pyplot as pltdef getPositionalEncoding(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 PP = getPositionalEncoding(4, 4)
print(P)
打印结果
[[ 0. 1. 0. 1. ][ 0.84147098 0.54030231 0.00999983 0.99995 ][ 0.90929743 -0.41614684 0.01999867 0.99980001][ 0.14112001 -0.9899925 0.0299955 0.99955003]]
2. 观察不同位置对应的曲线
我们把d和n固定,只改变位置参数k,然后画出不同k对应的图像,观察他们之间的区别
def plotSinusoid(k, d=512, n=10000):x = np.arange(0, 100)denominator = np.power(n, 2*x/d)y = np.sin(k / denominator)plt.plot(x, y)plt.title('k = ' + str(k))fig = plt.figure(figsize=(15, 4))
for i in range(4):plt.subplot(1, 4, i + 1)plotSinusoid(i*4)
从图中可以看出,每个位置的曲线都不相同,并且当 i i i固定时,对应的波长为
λ i = 2 π n 2 i / d \lambda_i = 2 \pi n^{2i/d} λi=2πn2i/d
因此,正弦曲线的波长形成几何函数。位置编码方案具有许多优点:
- 正弦和余弦函数的值在[-1,1]内,这使位置编码矩阵的值保持在归一化范围内
- 由于每个位置的正弦曲线都不同,因此你可以采用独特的方式对每个位置进行编码
- 有一种方法可以测量或量化不同位置之间的相似性,从而使你能够对单词的相对位置进行编码
3. 整句话的位置编码可视化
P = getPositionalEncoding(100, 512)
cax = plt.matshow(P)
plt.gcf().colorbar(cax)
transformer中的位置编码层把位置向量和单词编码相加,并输入到后续的层。
总结与心得体会
之前看过一些资料说Transformer中的位置编码,但是没有直观的概念一直只停留在利用正弦和余弦曲线进行编码。经过本次学习对编码的过程和原理有了一个形象的概念。通过对位置编码的学习,我感觉它很像傅里叶变换中的一些东西,所以虽然已经身处于深度学习阶段,传统的机器学习方法,甚至是基本的数学方法,仍然能提供一些思路,并解决一些问题,并不能放松对传统方法的学习。