位置エンコーディング

Posted: 2023-03-10 (Updated: 2023-04-15)

文中における単語の位置を\( \mathcal{T} = \{0,\,1,\,\ldots,\,T\} \)の元で表す.位置エンコーディングとは,多くの場合,写像\( f\colon \mathcal{T} \to \mathbb{R}^D \)(\(D\)は正整数)で, 特に単射であるもの,すなわち \begin{align} t \neq t' \; \Rightarrow \; f(t) \neq f(t') \label{uniqueness} \end{align} を満たすものを指す.さらに実用の観点から,以下を満たしていることが望ましい.

  1. 有界である.
  2. 決定的(非確率的)である.
  3. 文長に依存しない.
  4. 相対位置が簡潔に表現できる.

Vaswani et al. 2017では(自分の都合で記法を換えているが)以下のように計算される.まず\( D \)を正の偶数に限定する.そして像\( f(t) \)の第\( i \)成分\( {f(t)}_i \)と表すとき, \begin{align*} {f(t)}_i = \begin{cases} \sin (\omega_{\varphi(i)}\, t) & \text{if \(i \equiv 1 \bmod 2\)}, \\ \cos (\omega_{\varphi(i)}\, t) & \text{otherwise} \\ \end{cases} \end{align*} と定める.ここで \begin{align*} \varphi(i) = 2 \left\lfloor \frac{i - 1}{2} \right\rfloor,\quad \omega_k = \frac{1}{10000^{ \frac{k}{D} } } \end{align*} である.これは(\(\ref{uniqueness}\))を満たす.なぜならば\( 0 \leq \theta \leq 1 \)の範囲では\( \theta \lt \theta' \)ならば\( \sin \theta \lt \sin \theta' \)かつ\( \cos \theta \gt \cos \theta' \)が成り立つからである. また,満たしていることが望ましい性質i.–iii.についても明らかに満たされている.iv.については,後で確認する.

\begin{gather*} \varphi(1) = 0,\quad\varphi(2) = 0,\\ \varphi(3) = 2,\quad\varphi(4) = 2,\\ \varphi(5) = 4,\quad\varphi(6) = 4,\\ \varphi(7) = 6,\quad\varphi(8) = 6. \end{gather*}

\( D = 128 \)のとき \begin{gather*} f(0) = \begin{pmatrix} \sin (0) \\ \cos (0) \\ \vdots \\ \sin (0) \\ \cos (0) \end{pmatrix} = \begin{pmatrix} 0 \\ 1 \\ \vdots \\ 0 \\ 1 \end{pmatrix} ,\\[4pt] f(1) = \begin{pmatrix} \sin (\omega_{\varphi(1)}) \\ \cos (\omega_{\varphi(2)}) \\ \vdots \\ \sin (\omega_{\varphi(127)}) \\ \cos (\omega_{\varphi(128)}) \end{pmatrix} = \begin{pmatrix} \sin {\frac{1}{10000^{0/128}}} \\ \cos {\frac{1}{10000^{0/128}}} \\ \vdots \\ \sin {\frac{1}{10000^{126/128}}} \\ \cos {\frac{1}{10000^{126/128}}} \\ \end{pmatrix} \approx \begin{pmatrix} 0.8414 \\ 0.5403 \\ \vdots \\ 0.0001 \\ 0.9999 \end{pmatrix} ,\\[4pt] f(2) = \begin{pmatrix} \sin (\omega_{\varphi(1)} \cdot 2) \\ \cos (\omega_{\varphi(2)} \cdot 2) \\ \vdots \\ \sin (\omega_{\varphi(127)} \cdot 2) \\ \cos (\omega_{\varphi(128)} \cdot 2) \end{pmatrix} = \begin{pmatrix} \sin {\frac{2}{10000^{0/128}}} \\ \cos {\frac{2}{10000^{0/128}}} \\ \vdots \\ \sin {\frac{2}{10000^{126/128}}} \\ \cos {\frac{2}{10000^{126/128}}} \\ \end{pmatrix} \approx \begin{pmatrix} 0.9092 \\ -0.4161 \\ \vdots \\ 0.0002 \\ 0.9999 \end{pmatrix} \end{gather*} となる.

各成分ごとに三角関数の周期を変えることで,(\(\ref{uniqueness}\))を簡単に満たすことができる.下の図1と図2を見ると分かるように,\( \sin (\omega\, t) \)は\( \omega \)が小さくなるほど,周期\( (= 2\pi / \omega) \)が大きくなる. すなわち,成分を縦に並べたとき,下の方にある成分ほどゆっくり変化する.

図1:\(y = \sin x\)のグラフ.周期は\(2\pi\).
y = sin x
図2:\(\displaystyle y = \sin \frac{1}{2}x\)のグラフ.周期は\( \displaystyle \frac{2\pi }{1 / 2} = 4\pi \).
y = sin 1/2 x
ヒートマップを使って可視化すると図3のようになる.
図 3:\( D = 128,\,t = 0,\,\ldots,\,50 \)のヒートマップ.
ヒートマップの作成に使用したPythonスクリプト.
import itertools

import numpy
import seaborn
from matplotlib import pyplot


def main() -> None:
    D = 128
    T = 51
    data = numpy.zeros((T, D), dtype=float)
    for (t, d) in itertools.product(range(T), range(D)):
        f = numpy.sin if d % 2 == 0 else numpy.cos
        omega = 1 / (10_000 ** (2 * numpy.floor(d / 2) / D))
        data[t, d] = f(omega * t)
    h = seaborn.heatmap(data.T, vmin=-1.0, cbar_kws={'ticks': [-1.0, -0.5, 0.0, 0.5, 1.0]})
    h.set_xlabel('t (position)')
    h.set_ylabel('i (dimension)')
    xticklabels = [t for t in range(T) if t % 10 == 0]
    h.set_xticks([x + 0.5 for x in xticklabels])
    h.set_xticklabels(xticklabels)
    yticklabels = [1] + [y for y in range(D + 1) if y % 16 == 0 and y > 0]
    h.set_yticks([y - 0.5 for y in yticklabels])
    h.set_yticklabels(yticklabels)
    pyplot.savefig('../images/heatmap.svg', bbox_inches='tight', transparent=True)
    pyplot.show()


if __name__ == '__main__':
    main()

最後にiv.について確認する.

証明 \begin{align*} f(t + \varDelta t) &= \begin{pmatrix} \sin (\omega_{\varphi(1)}\, (t + \varDelta t)) \\ \cos (\omega_{\varphi(2)}\, (t + \varDelta t)) \\ \vdots \\ \sin (\omega_{\varphi(D - 1)}\, (t + \varDelta t)) \\ \cos (\omega_{\varphi(D)}\, (t + \varDelta t)) \end{pmatrix} \\[4pt] &= \begin{pmatrix} \sin (\omega_0 \, t + \omega_0 \, \varDelta t) \\ \cos (\omega_0 \, t + \omega_0 \, \varDelta t) \\ \vdots \\ \sin (\omega_{D/2}\, t + \omega_{D/2}\, \varDelta t) \\ \cos (\omega_{D/2}\, t + \omega_{D/2}\, \varDelta t) \end{pmatrix} \\[4pt] &= \begin{pmatrix} \sin (\omega_0\, t) \cos (\omega_0\, \varDelta t) + \cos (\omega_0\, t) \sin (\omega_0\, \varDelta t) \\ \cos (\omega_0\, t) \cos (\omega_0\, \varDelta t) - \sin (\omega_0\, t) \sin (\omega_0\, \varDelta t) \\ \vdots \\ \sin (\omega_{D/2}\, t) \cos (\omega_{D/2}\, \varDelta t) + \cos (\omega_{D/2}\, t) \sin (\omega_{D/2}\, \varDelta t) \\ \cos (\omega_{D/2}\, t) \cos (\omega_{D/2}\, \varDelta t) - \sin (\omega_{D/2}\, t) \sin (\omega_{D/2}\, \varDelta t) \\ \end{pmatrix} \\[4pt] &= \begin{pmatrix} \cos(\omega_0\,\varDelta t) & \sin(\omega_0\,\varDelta t) & \cdots & 0 & 0 \\ -\sin(\omega_0\,\varDelta t) & \cos(\omega_0\,\varDelta t) & \cdots & 0 & 0 \\ \vdots & \vdots & \ddots & \vdots & \vdots \\ 0 & 0 & \cdots & \cos(\omega_{D/2}\,\varDelta t) & \sin(\omega_{D/2}\,\varDelta t) \\ 0 & 0 & \cdots & -\sin(_{D/2}\,\varDelta t) & \cos(\omega_{D/2}\,\varDelta t) \\ \end{pmatrix} \begin{pmatrix} \sin (\omega_0\, t) \\ \cos (\omega_0\, t) \\ \vdots \\ \sin (\omega_{D/2}\, t) \\ \cos (\omega_{D/2}\, t) \end{pmatrix} \\[4pt] &= A(\varDelta t) f(t). \end{align*} ここで \begin{gather} A(\varDelta t) = \begin{pmatrix} R_0\,(\varDelta t) & O & \cdots & O \\ O & R_2\,(\varDelta t) & \cdots & O \\ \vdots & \vdots & \ddots & \vdots \\ O & O & \cdots & R_{D/2}\,(\varDelta t) \\ \end{pmatrix}, \notag \\[4pt] R_k(\varDelta t) = \begin{pmatrix} \cos (\omega_k\,\varDelta t) & \sin (\omega_k\,\varDelta t) \\ -\sin (\omega_k\,\varDelta t) & \cos (\omega_k\,\varDelta t) \\ \end{pmatrix}. \tag*{∎} \end{gather}

\( R_k (\varDelta t) \)は\( \mathbb{R}^2 \)の要素を\( - \omega_k\, \varDelta t \)だけ回転させる線型変換である.この結果を得るために\( \sin,\, \cos \)の両方を用い,また\( \omega \)の添え字を2個ずつ同じにしているのである.

参考文献