본문으로 건너뛰기

쌍선형 모델: DistMult와 ComplEx

📍 현재 위치: I부 · 지식 그래프 임베딩 — 3장. 이동 모델은 관계가 변위라는 데 승부를 걸었고 그 대가로 일대다 붕괴를 치렀습니다; 이 장은 동사를 더하기에서 곱하기로 바꾸어 다르지만 더 날카로운 실패와 마주합니다.

지난 장은 걷는 모델로 끝을 맺었습니다: 머리의 점을 관계의 화살표를 따라 밀었을 때 꼬리의 점 가까이에 떨어지면, 트리플은 그럴듯합니다. 이 장은 걷기를 근본적으로 다른 기하학적 동사로 대체합니다. 쌍선형 모델(bilinear model)은 좌표들을 곱하고 그 곱들을 더함으로써 트리플을 채점하며, 그래서 두 점이 서로 가까이 있을 때가 아니라 머리, 관계, 꼬리가 차원마다 일치할 때 사실이 그럴듯해집니다. 곱셈은 이동이 결코 내줄 수 없는 실질적인 것들을 사 주는데, 그중에는 대칭 관계를 그 양 끝점을 무너뜨리지 않고 표현하는 능력도 있습니다. 그러나 가장 단순한 곱셈 모델인 DistMult는 그것들을 하나의 정리로 진술하고 두 줄로 증명할 수 있는 대가를 치르고서야 사들입니다: DistMult의 점수는 어떤 파라미터 설정에서도, 결코, 트리플과 그 역방향을 구별할 수 없습니다. 우리 그래프에는 그것이 치명적인 관계가 하나 있습니다. 사실 (p2, cites, p1)은 참이고 그 역방향은 거짓인데, 커밋된 실행은 DistMult가 두 방향에 비트 단위로 동일한 점수를 매기는 것을 보여 줄 것입니다. 그 수선책인 ComplEx는 곱셈적 형태를 유지한 채 단 한 가지만을 바꿉니다: 벡터가 복소수 값이 되고 꼬리가 켤레화됩니다. 그 켤레화는 전개된 점수 안의 부호 하나를 뒤집고, 뒤집힌 부호는 점수를 방향에 민감하게 만들며, 같은 실행은 두 인용 방향이 11점 넘게 갈라지는 것을 보여 줍니다. 그 사이의 모든 손실과 모든 그래디언트는 손으로 유도되어 커밋된 코드에 대조해 확인되며, 모든 숫자는 실제 실행에서 인용됩니다.

쉽게 말하면

설문지로 제안된 짝을 채점하는 매칭 서비스를 상상해 보십시오. 모든 개체는 열여섯 개의 슬라이더에 답을 채워 넣었고, 모든 관계는 각 질문이 얼마나 중요한지를 말해 주는 채점 기준표입니다. "p2가 p1을 인용하는가"를 채점하려면, 1번 질문을 가져와 p2의 답과 채점 기준표의 가중치와 p1의 답을 곱하고, 열여섯 개 질문 모두에 대해 같은 일을 한 다음, 전부 더합니다. 곱이 크고 양수라는 것은 셋이 일치한다는 뜻이며, 그 합이 점수입니다. 이제 결함을 알아채 보십시오: 채점 기준표는 어느 설문지가 머리에서 왔고 어느 것이 꼬리에서 왔는지 전혀 알지 못합니다. 곱셈은 순서를 신경 쓰지 않으므로, "p2가 p1을 인용한다"와 "p1이 p2를 인용한다"는 정확히 같은 열여섯 개의 곱과 정확히 같은 합을 만들어 냅니다. "공동연구한다"처럼 양방향 관계라면 이는 괜찮을 뿐 아니라 이상적이기까지 합니다. 그러나 "인용한다"처럼 한 방향 관계라면 이는 가망이 없습니다. ComplEx의 해법은 모든 질문에 두 개의 채널을 주고, 꼬리의 두 번째 채널을 부호를 뒤집어서 읽는 것인데, 이는 꼬리를 거울에 비친 정답지에 대고 채점하는 것과 같습니다. 이제 머리와 꼬리가 서로 다르게 처리되므로, 둘을 맞바꾸면 점수가 달라지고, 방향은 모델이 배울 수 있는 무언가가 됩니다.

이 장에서 다루는 내용

  • 일반적인 쌍선형 점수: 관계마다 완전한 d×dd \times d 행렬을 갖는 RESCAL의 ehWret\mathbf{e}_h^\top W_r \mathbf{e}_t를 이중합으로 전개하고, 그것을 줄여야 할 동기가 되는 파라미터 청구서를 다룹니다.
  • 대각 제한: 행렬의 대각만을 남겨 이중합을 ieh[i]wr[i]et[i]\sum_i e_h[i]\, w_r[i]\, e_t[i]로 붕괴시키는 DistMult와, TransE, RESCAL, DistMult, ComplEx에 걸친 파라미터 개수 표를 다룹니다.
  • 증명된 대칭 정리: 실수 곱셈의 교환법칙이 어떤 관계에 대해서든 어떤 파라미터 설정에 대해서든 대각 점수를 머리와 꼬리를 맞바꾸는 것에 대해 불변으로 만드는 이유와, cites 위에서 그 동점을 마지막 자릿수까지 보여 주는 커밋된 실행을 다룹니다.
  • 부드럽게 살펴보는 복소 벡터: 실수 벡터 한 쌍으로서의 Cd\mathbb{C}^d, 켤레, 그리고 방향을 되살리는 마이너스 부호 하나가 눈에 보이도록 네 개의 실수 항으로 한 단계씩 전개되는 ComplEx의 점수 Reeh,wr,et\mathrm{Re}\langle \mathbf{e}_h, \mathbf{w}_r, \overline{\mathbf{e}_t} \rangle를 다룹니다.
  • 로지스틱 손실과 모든 그래디언트: L=softplus(ys)L = \mathrm{softplus}(-y\,s), 연쇄 법칙을 통해 고리마다 쌓아 올린 도함수 L/s=yσ(ys)\partial L/\partial s = -y\,\sigma(-y\,s), DistMult의 세 편미분과 ComplEx의 여섯 편미분, L2 가중치 감쇠 갱신, 그리고 모든 공식을 2×10102 \times 10^{-10} 이내로 확인해 주는 중심 차분 검사를 다룹니다.
  • 커밋된 정면 대결: 두 모델의 훈련 손실 곡선, 대칭 표(DistMult 4.8879 대 4.8879; ComplEx 6.6413 대 −4.5805), 그리고 필터링된 순위 매김 결과를 다루며, 모두 결정론적 실행에서 나온 실제 숫자입니다.
  • 곱셈이 사 주는 것: 붕괴 없는 대칭 관계, 대칭과 반대칭 사이를 잇는 관계별 다이얼, 그리고 ComplEx의 완전 표현력 보장을 다룹니다.
  • 아직 풀리지 않은 부분: 점 임베딩 위의 점수는 낱개의 엣지 순위를 매길 뿐이지만, 개념과 질의의 답은 집합이며, 점에는 포함의 기하가 없다는 것을 다룹니다; II부는 집합에 그 자신의 도형을 부여합니다.

걷기에서 곱하기로: 일반적인 쌍선형 점수

문제의 형태를 다시 떠올려 봅시다. 학계 그래프의 13개 개체 각각은 개체 임베딩(entity embedding), 즉 dd개의 실수로 이루어진 벡터를 받습니다(dd임베딩 차원(embedding dimension)이며, 동반 코드는 이번에도 d=16d = 16을 씁니다). 달라지는 것은 관계가 받는 것입니다. TransE는 관계에 더할 벡터 하나를 주었습니다. 쌍선형 계열은 관계에 상호작용 가중치의 표를 줍니다: 임베딩 차원마다 하나의 행과 하나의 열을 갖는 완전한 d×dd \times d 관계 행렬(relation matrix) WrW_r이며, 그 항목 Wr[i,j]W_r[i,j]는 머리의 좌표 ii가 꼬리의 좌표 jj와 상호작용하는 것이 관계 rr의 증거로 얼마나 인정되는지를 말해 줍니다. 점수는 쌍선형 형식(bilinear form)입니다

s(h,r,t)  =  ehWret  =  i=1dj=1deh[i]  Wr[i,j]  et[j],s(h, r, t) \;=\; \mathbf{e}_h^\top W_r\, \mathbf{e}_t \;=\; \sum_{i=1}^{d} \sum_{j=1}^{d} e_h[i]\; W_r[i,j]\; e_t[j],

여기서 위 첨자 \top전치(transpose)로, 열벡터 eh\mathbf{e}_h를 행벡터로 바꾸어 행렬 곱이 정의되도록 하며, 첨자 iijj는 각각 dd개의 좌표를 훑습니다. 이중합은 안쪽에서 바깥쪽으로 읽으십시오: 머리의 좌표 하나와 꼬리의 좌표 하나로 이루어진 d2d^2개의 쌍별 곱을 모두 만들고, 각 쌍을 그것을 관장하는 행렬 항목으로 가중치를 매긴 다음, 전부 더합니다. "쌍선형"(bilinear)은 이 형태를 정확히 가리키는 이름입니다: et\mathbf{e}_t를 고정하면 점수는 eh\mathbf{e}_h에 대한 선형 함수이고, eh\mathbf{e}_h를 고정하면 et\mathbf{e}_t에 대해 선형입니다; 각 인자에 대해 따로따로 선형이므로 (bi)-선형입니다.

이것이 바로 RESCAL이라 불리는 모델이며, 유용한 두 번째 해석을 함께 가져옵니다 [1]. 그래프 전체를 가능한 트리플마다 0/1 항목 하나씩을 갖는 삼중 배열(텐서, tensor) XX로 쌓아, 사실이 성립할 때 정확히 X[h,r,t]=1X[h, r, t] = 1이 되도록 합니다. 그러면 참인 트리플에서는 s(h,r,t)s(h,r,t)를 크게, 거짓인 트리플에서는 작게 만들라고 임베딩에 요구하는 것은, 곧 텐서 분해(tensor factorization)를 요구하는 것입니다: 작은 공유 인자 집합으로부터 근접 텐서(incidence tensor)를 재구성하는 근사 X[h,r,t]ehWretX[h,r,t] \approx \mathbf{e}_h^\top W_r \mathbf{e}_t입니다. 링크 예측(link prediction)은 그 분해의 일반화가 됩니다: 우리가 한 번도 관측하지 못한 XX의 항목들은, 우리가 관측한 항목들을 재구성하는 바로 그 저차원 인자들에 의해 예측됩니다.

문제는 청구서입니다. 모든 관계는 자기만의 d×dd \times d 행렬을 지니며, 행렬은 이차적으로 비쌉니다. d=16d = 16인 우리의 작은 그래프에서, 관계 하나는 162=25616^2 = 256개의 숫자를 대가로 치르고 5개의 관계 행렬은 이미 5×256=12805 \times 256 = 1280을 치르는데, 이는 개체들이 치르는 13×16=20813 \times 16 = 208을 압도합니다; 관계가 수천 개이고 dd가 수백에 이르는 실제 그래프에서는 관계 행렬이 모든 것을 지배하며 수렴하기 한참 전에 과적합됩니다. 자연스러운 대응은 WrW_r을 제약하는 것이며, 곱셈적 성격을 유지하면서도 가장 단순한 제약이 다음 절의 주제입니다.

대각 제한: DistMult

DistMult는 관계 행렬의 대각만을 남깁니다 [2]. 형식적으로는 Wr=diag(wr)W_r = \mathrm{diag}(\mathbf{w}_r)을 요구합니다: 주대각을 따라 늘어선 항목 Wr[i,i]=wr[i]W_r[i,i] = w_r[i]를 제외하고는 어디서나 0인 행렬이며, 그래서 각 관계는 다시 한번 dd개의 숫자만으로 기술됩니다. 이를 이중합에 대입하면, iji \neq j인 모든 항은 Wr[i,j]=0W_r[i,j] = 0이 되어 사라지고, 첨자가 일치하는 dd개의 항만 남습니다:

s(h,r,t)  =  i=1dj=1deh[i]  Wr[i,j]  et[j]  =  i=1deh[i]  wr[i]  et[i].s(h, r, t) \;=\; \sum_{i=1}^{d} \sum_{j=1}^{d} e_h[i]\; W_r[i,j]\; e_t[j] \;=\; \sum_{i=1}^{d} e_h[i]\; w_r[i]\; e_t[i].

점수는 삼중 내적(three-way inner product)입니다: 좌표마다 머리의 값, 관계의 가중치, 꼬리의 값을 곱한 다음 더합니다. 각 차원은 하나의 잠재 특징이며, 셋 모두가 함께 밝게 켜지는 차원, 즉 양수 곱하기 양수 곱하기 양수인(혹은 음수의 개수가 짝수인) 차원이 있을 때 트리플은 높은 점수를 받고, 관계 벡터 wr\mathbf{w}_r은 그 관계가 어떤 차원에 얼마나 신경 쓰며 어떤 부호로 신경 쓰는지를 말해 줍니다. 커밋된 구현은 return 한 줄이며, 그 독스트링은 다음 절이 증명할 문제를 미리 알립니다(bilinear.py 57–65번째 줄):

def distmult_score(ent: np.ndarray, rel: np.ndarray,
hi: int, ri: int, ti: int) -> float:
"""DistMult's score s(h, r, t) = Σ_i e_h[i] · w_r[i] · e_t[i].

Because elementwise multiplication commutes, s(h, r, t) = s(t, r, h) for
every choice of parameters — the symmetry defect demonstrated below. The
grouping w_r ⊙ (e_h ⊙ e_t) makes that equality exact even in floating
point: swapping h and t produces the bitwise-identical product array."""
return float(np.sum(rel[ri] * (ent[hi] * ent[ti])))

이제 파라미터 산술은 DistMult의 손을 결정적으로 들어 줍니다. 다음은 우리 그래프에 대한 전체 청구서입니다: 13개 개체와 5개 관계에 행마다 16개의 실수 차원이며, 각 모델의 관계 표현을 명시적으로 적었습니다. 표에서 기호 \in은 "~의 원소이다"라고 읽으며, R16\mathbb{R}^{16}은 16개 실수로 이루어진 벡터들의 집합, R16×16\mathbb{R}^{16 \times 16}은 16×16 실수 행렬들의 집합, C8\mathbb{C}^{8}은 8개 복소수로 이루어진 벡터들의 집합입니다(이 개념은 두 절 뒤에서 풀어냅니다):

모델관계 표현관계당 파라미터 수우리 그래프에서의 총계대칭 rr 처리반대칭 rr 처리
TransE이동 벡터 wrR16\mathbf{w}_r \in \mathbb{R}^{16}16208+80=288208 + 80 = 288붕괴를 통해서만가능
RESCAL완전 행렬 WrR16×16W_r \in \mathbb{R}^{16 \times 16}256208+1280=1488208 + 1280 = 1488가능가능
DistMult대각 wrR16\mathbf{w}_r \in \mathbb{R}^{16}16208+80=288208 + 80 = 288항상 (강제됨)불가능
ComplEx복소 벡터 wrC8\mathbf{w}_r \in \mathbb{C}^{8}실수 16개208+80=288208 + 80 = 288가능 (wim=0\mathbf{w}_{\mathrm{im}} = 0)가능 (wre=0\mathbf{w}_{\mathrm{re}} = 0)

DistMult는 RESCAL의 곱셈적 상호작용을 유지하면서도 TransE의 288개 파라미터와 정확히 일치하며, 그 시대의 표준 벤치마크에서 놀라울 만큼 강력했습니다 [2]. 그러나 표의 마지막 두 열을 다시 보십시오. DistMult 행의 "강제됨"이라는 단어와 그 옆의 "불가능"이라는 단어는 하나의 정리의 양 끝이며, 그 정리는 바로 지금 증명할 수 있을 만큼 짧습니다.

대칭 정리

정리. 개체 hhtt의 어떤 선택에 대해서든, 어떤 관계 rr에 대해서든, 그리고 임베딩 파라미터의 가능한 모든 값에 대해서든, DistMult의 점수는 s(h,r,t)=s(t,r,h)s(h, r, t) = s(t, r, h)를 만족합니다.

증명. 임의의 차원 ii를 고정합시다. s(h,r,t)s(h,r,t)ii번째 항은 세 실수의 곱 eh[i]wr[i]et[i]e_h[i] \cdot w_r[i] \cdot e_t[i]입니다. 실수의 곱셈은 교환법칙을 만족합니다, 즉 모든 실수 aabb에 대해 ab=baab = ba이므로, 세 인자는 자유롭게 재배열될 수 있습니다: eh[i]wr[i]et[i]=et[i]wr[i]eh[i]e_h[i]\, w_r[i]\, e_t[i] = e_t[i]\, w_r[i]\, e_h[i]. 이는 각 ii에 대해 개별적으로 성립하며, 같은 항들을 더하면 같은 합이 나옵니다:

s(h,r,t)  =  i=1deh[i]wr[i]et[i]  =  i=1det[i]wr[i]eh[i]  =  s(t,r,h).s(h, r, t) \;=\; \sum_{i=1}^{d} e_h[i]\, w_r[i]\, e_t[i] \;=\; \sum_{i=1}^{d} e_t[i]\, w_r[i]\, e_h[i] \;=\; s(t, r, h). \qquad \blacksquare

정리가 말하지 않는 것에 주목하십시오. 이 정리는 DistMult가 방향을 혼동하는 경향이 있다거나, 방향과 씨름한다거나, 방향을 배우려면 더 많은 데이터가 필요하다고 말하지 않습니다. 이 정리는 두 점수가 파라미터의 같은 함수라고 말합니다. 어떤 경사 하강 스텝도, 어떤 데이터셋도, 어떤 훈련 일정도, 어떤 차원 개수도 그 둘을 다르게 만들 수 없는데, 왜냐하면 어떤 숫자를 채워 넣기도 전에 이미 대수적 표현으로서 서로 같기 때문입니다. 이 항등식은 커밋된 코드 안의 부동소수점 연산에서도 살아남습니다: rel[ri] * (ent[hi] * ent[ti])라는 묶음은 wr(ehet)\mathbf{w}_r \odot (\mathbf{e}_h \odot \mathbf{e}_t)를 계산하는데, 여기서 \odot아다마르 곱(Hadamard product), 즉 벡터의 원소별 곱셈이며, (ab)[j]=a[j]b[j](\mathbf{a} \odot \mathbf{b})[j] = a[j]\,b[j]입니다. hhtt를 맞바꾸는 것은 안쪽 아다마르 곱의 두 인자를 맞바꾸는 것인데, NumPy는 이를 교환법칙에 따라 곱하므로, 곱 배열은 비트 단위로 동일하고 두 점수는 마지막 자릿수까지 일치합니다(bilinear.py 61–65번째 줄).

우리 자신의 그래프 위에서의 귀결

우리 그래프에는 이 정리가 벌하는 바로 그 관계가 있습니다. cites 관계는 인용하는 논문에서 인용되는 논문으로 성립합니다: 훈련 집합은 (p2, cites, p1)과 (p3, cites, p2)를 담고 있으며, 인용은 반대칭(antisymmetric)적인데, 나중에 발표된 논문이 앞선 논문을 인용하지 그 반대는 결코 성립하지 않기 때문입니다. 제 역할을 하는 모델이라면 (p2, cites, p1)에 높은 점수를, (p1, cites, p2)에 낮은 점수를 매겨야 합니다. 정리는 DistMult가 원리적으로조차 그럴 수 없다고 말합니다: 훈련이 참인 방향에 대해 벌어들이는 점수가 무엇이든, 그것은 거짓인 방향에도 똑같이 대물림됩니다. 다음은 두 모델이 1000에폭 동안 훈련한 뒤 출력되는 커밋된 시연입니다(둘째 열은 곧 이어서 만들 ComplEx의 것이니, 한 페이지만 기다려 주십시오):

the symmetry problem: `cites` is antisymmetric, and only the
forward direction (p2, cites, p1) was ever trained as true
score DistMult ComplEx
s(p2, cites, p1) true 4.8879 6.6413
s(p1, cites, p2) false 4.8879 -4.5805
|forward - reverse| 0.0000 11.2217

DistMult 열은 정리가 경험적으로 나타난 모습입니다: 순방향과 역방향은 각각 4.8879와 4.8879이며, 하니스는 그 동점을 단순히 출력만 하는 것이 아니라 단언(assert)하는데, 절댓값 차이가 10910^{-9} 미만이어야 한다고 요구합니다(bilinear.py 332번째 줄); 실행의 요약 줄은 측정된 차이를 0.0e+00으로 보고하며, 이는 방금 설명한 이유로 비트까지 정확합니다. 훈련은 마치 널빤지 하나의 양쪽 끝처럼 두 방향을 함께 끌어올렸습니다. 그리고 이 실패는 스스로를 강화합니다: 참인 사실의 점수를 밀어 올리는 모든 그래디언트는 거짓인 역방향의 점수도 정확히 같은 만큼 밀어 올리는데, 왜냐하면 같은 함수는 같은 그래디언트를 갖기 때문입니다.

학계 지식 그래프 위에서 이루어지는 쌍선형 점수 매기기를 보여 주는 세 패널짜리 도해입니다. DistMult라는 제목이 붙은 왼쪽 패널은 머리 e_h, 관계 w_r, 꼬리 e_t로 표시된 16칸짜리 가로 벡터 띠 세 개를 세로로 쌓아 보여 주며, 세로 정렬선이 각 차원의 세 칸이 그 아래의 곱 칸으로 곱해지는 것을, 그리고 그 곱 칸들이 하나의 점수로 합산되는 것을 보여 줍니다; 캡션은 머리, 관계, 꼬리가 함께 밝아지는 곳에서 트리플이 높은 점수를 받는다고 적어 둡니다. 대칭 결함이라는 제목이 붙은 가운데 패널은 논문 p2와 논문 p1이 p2에서 p1을 향하며 참으로 표시된 cites 화살표로 이어지고, 반대 방향을 향하며 거짓으로 표시된 두 번째 점선 화살표가 그려진 모습을 보여 주는데, 두 화살표 모두 4.8879는 4.8879와 같다고 적힌 같은 점수 상자로 흘러 들어가며, 머리와 꼬리 띠를 맞바꾸는 것은 각 차원의 세 인자를 재배열할 뿐이므로 어떤 파라미터 설정에서도 동일하다는 도장이 찍혀 있습니다. ComplEx의 수선이라는 제목이 붙은 오른쪽 패널은 각 벡터 칸이 re와 im이라 표시된 두 개의 작은 채널로 나뉘는 모습을 보여 주며, 켤레화를 나타내기 위해 꼬리의 im 채널은 부호가 뒤집힌 채로 그려져 있습니다; 네 개의 실수 곱 항이 나열되어 있고 넷째 항에는 강조된 마이너스 부호가 붙어 있으며, 두 개의 점수 상자는 순방향이 6.6413이고 역방향이 음수 4.5805여서 11.22만큼 벌어짐을 보여 줍니다. 한 그림 안의 쌍선형 점수 매기기: DistMult는 머리, 관계, 꼬리를 차원마다 곱하고 합산하며(왼쪽), 이는 점수를 방향에 대해 증명 가능하게 눈멀게 만듭니다(가운데); ComplEx는 각 차원을 실수 채널과 허수 채널로 나누고 꼬리를 켤레화하며, 그렇게 뒤집힌 부호 하나가 두 인용 방향을 11.22만큼 갈라놓습니다(오른쪽). 저자가 AI의 도움을 받아 직접 제작한 원본 도해.

부드럽게 살펴보는 복소 벡터

수선책을 위해서는 대학 1학년 대수학의 한 조각을 다시 꺼내 놓아야 합니다. 복소수(complex number)는 z=a+biz = a + b\,\mathrm{i}로 쓰이는 실수 한 쌍인데, 여기서 i\mathrm{i}는 단 하나의 규칙 i2=1\mathrm{i}^2 = -1을 따르는 형식적 기호입니다; 수 aa실수부(real part), bb허수부(imaginary part)입니다. 두 복소수는 평범한 분배법칙에 그 규칙 하나를 더해 곱해지며, 이를 한 번 완전히 해 볼 가치가 있는 까닭은 ComplEx의 점수 전개가 이 계산을 세 인자 깊이로 반복하는 것이기 때문입니다:

(a+bi)(c+di)  =  ac+adi+bci+bdi2  =  (acbd)+(ad+bc)i,(a + b\,\mathrm{i})(c + d\,\mathrm{i}) \;=\; ac + ad\,\mathrm{i} + bc\,\mathrm{i} + bd\,\mathrm{i}^2 \;=\; (ac - bd) + (ad + bc)\,\mathrm{i},

마지막 단계에서는 i2=1\mathrm{i}^2 = -1을 사용해 bdbd 항을 마이너스 부호와 함께 실수부로 접어 넣었습니다. zz켤레(conjugate)는 z\overline{z}로 쓰이며, 허수부의 부호를 뒤집습니다: a+bi=abi\overline{a + b\,\mathrm{i}} = a - b\,\mathrm{i}. 켤레화는 이 장에서 복소수의 두 채널을 비대칭적으로 다루는 유일한 연산이며, 그 비대칭성이야말로 이 트릭의 전부입니다.

복소 벡터(complex vector) uCk\mathbf{u} \in \mathbb{C}^k(kk개의 복소수로 이루어진 목록들의 집합)는 코드에서 전혀 이국적이지 않습니다: 길이 kk짜리 실수 벡터 두 개, 즉 실수부를 담는 것 하나와 허수부를 담는 것 하나로 저장됩니다. 커밋된 구현은 정확히 이렇게 하여 배열 e_re, e_im, w_re, w_im을 유지하며, DistMult와 같은 예산을 나눕니다: d=16d = 16개의 실수 차원을 k=d/2=8k = d/2 = 8개의 복소 차원으로 읽습니다(bilinear.py 37번째 줄과 261–265번째 줄), 그래서 위 표의 파라미터 총계는 288로 맞아떨어집니다.

ComplEx: 꼬리를 켤레화하기

ComplEx는 DistMult의 삼중 곱을 유지한 채 인자 하나만을 바꿉니다 [3]. 세 복소 벡터의 삼선형 곱(trilinear product)을 그것들의 원소별 곱의 합, u,v,w=iuiviwi\langle \mathbf{u}, \mathbf{v}, \mathbf{w} \rangle = \sum_i u_i\, v_i\, w_i로 정의하며, 이는 하나의 복소수입니다. ComplEx는 꼬리를 켤레화하고 실수부만을 남겨(복소수의 실수 성분을 뽑아내는 함수인 Re()\mathrm{Re}(\cdot)로 표기합니다) 트리플을 채점합니다:

s(h,r,t)  =  Reeh,  wr,  et  =  Rei=1keh[i]  wr[i]  et[i].s(h, r, t) \;=\; \mathrm{Re}\,\big\langle \mathbf{e}_h,\; \mathbf{w}_r,\; \overline{\mathbf{e}_t} \big\rangle \;=\; \mathrm{Re} \sum_{i=1}^{k} e_h[i]\; w_r[i]\; \overline{e_t[i]}.

이것이 실제로 무엇을 계산하는지 보려면, 항 하나를 실수부와 허수부로 전개해 봅시다; eh[i]e_h[i]의 두 채널을 hre,himh_{\mathrm{re}}, h_{\mathrm{im}}으로 쓰고, 관계와 꼬리에 대해서도 마찬가지로 씁니다(여섯 기호 모두 실수이며, 차원 첨자는 생략합니다). 곱해지는 인자는 (hre+himi)(wre+wimi)(tretimi)(h_{\mathrm{re}} + h_{\mathrm{im}}\mathrm{i})(w_{\mathrm{re}} + w_{\mathrm{im}}\mathrm{i})(t_{\mathrm{re}} - t_{\mathrm{im}}\mathrm{i})이며, 마지막 인자의 마이너스 부호가 바로 켤레화입니다. 앞서 유도한 곱셈 규칙을 사용해 처음 두 인자를 곱합니다:

(hre+himi)(wre+wimi)  =  (hrewrehimwim)  +  (hrewim+himwre)i.(h_{\mathrm{re}} + h_{\mathrm{im}}\mathrm{i})(w_{\mathrm{re}} + w_{\mathrm{im}}\mathrm{i}) \;=\; (h_{\mathrm{re}} w_{\mathrm{re}} - h_{\mathrm{im}} w_{\mathrm{im}}) \;+\; (h_{\mathrm{re}} w_{\mathrm{im}} + h_{\mathrm{im}} w_{\mathrm{re}})\,\mathrm{i}.

이제 이것을 (tretimi)(t_{\mathrm{re}} - t_{\mathrm{im}}\mathrm{i})와 곱하고 실수부만 남깁니다. 실수부는 두 가지 방식으로 생겨납니다: 실수 곱하기 실수, 그리고 i(i)=+1\mathrm{i} \cdot (-\mathrm{i}) = +1을 통한 허수 곱하기 허수입니다:

Re()  =  (hrewrehimwim)tre  +  (hrewim+himwre)tim.\mathrm{Re}(\cdots) \;=\; (h_{\mathrm{re}} w_{\mathrm{re}} - h_{\mathrm{im}} w_{\mathrm{im}})\, t_{\mathrm{re}} \;+\; (h_{\mathrm{re}} w_{\mathrm{im}} + h_{\mathrm{im}} w_{\mathrm{re}})\, t_{\mathrm{im}}.

두 곱을 분배하면 점수의 차원별 기여분은 정확히 네 개의 실수 항으로 떨어집니다:

wrehretre  +  wrehimtim  +  wimhretim    wimhimtre.w_{\mathrm{re}} h_{\mathrm{re}} t_{\mathrm{re}} \;+\; w_{\mathrm{re}} h_{\mathrm{im}} t_{\mathrm{im}} \;+\; w_{\mathrm{im}} h_{\mathrm{re}} t_{\mathrm{im}} \;-\; w_{\mathrm{im}} h_{\mathrm{im}} t_{\mathrm{re}}.

이것이 정확히 커밋된 코드가 계산하는 것이며, 그 독스트링은 결정적인 부호가 어디서 오는지를 말해 줍니다(bilinear.py 99–115번째 줄):

def complex_score(ent_re: np.ndarray, ent_im: np.ndarray,
rel_re: np.ndarray, rel_im: np.ndarray,
hi: int, ri: int, ti: int) -> float:
"""ComplEx's score s = Re(⟨e_h, w_r, conj(e_t)⟩), expanded over the real
(``_re``) and imaginary (``_im``) parts into its four real terms:

s = Σ_i [ w_re·h_re·t_re + w_re·h_im·t_im
+ w_im·h_re·t_im − w_im·h_im·t_re ]

The last term's minus sign comes from conj(e_t) = t_re − i·t_im; it is the
only asymmetry in the formula, and it is what lets ComplEx score
(p2, cites, p1) and (p1, cites, p2) differently."""
h_re, h_im = ent_re[hi], ent_im[hi]
w_re, w_im = rel_re[ri], rel_im[ri]
t_re, t_im = ent_re[ti], ent_im[ti]
return float(np.sum(w_re * h_re * t_re + w_re * h_im * t_im
+ w_im * h_re * t_im - w_im * h_im * t_re))

이제 네 항을 그것들이 사용하는 관계 채널에 따라 다시 묶어 봅시다, 그 묶음이 모델의 구조를 드러내기 때문입니다. 두 개의 wrew_{\mathrm{re}} 항과 두 개의 wimw_{\mathrm{im}} 항은 다음으로 모입니다

s(h,r,t)  =  i=1kwre[i](hre[i]tre[i]+him[i]tim[i])  +  i=1kwim[i](hre[i]tim[i]him[i]tre[i]).s(h,r,t) \;=\; \sum_{i=1}^{k} w_{\mathrm{re}}[i]\,\big(h_{\mathrm{re}}[i]\, t_{\mathrm{re}}[i] + h_{\mathrm{im}}[i]\, t_{\mathrm{im}}[i]\big) \;+\; \sum_{i=1}^{k} w_{\mathrm{im}}[i]\,\big(h_{\mathrm{re}}[i]\, t_{\mathrm{im}}[i] - h_{\mathrm{im}}[i]\, t_{\mathrm{re}}[i]\big).

hhtt를 맞바꾸고 각 괄호를 지켜보십시오. 첫째 괄호 hretre+himtimh_{\mathrm{re}} t_{\mathrm{re}} + h_{\mathrm{im}} t_{\mathrm{im}}trehre+timhimt_{\mathrm{re}} h_{\mathrm{re}} + t_{\mathrm{im}} h_{\mathrm{im}}으로 옮겨 가는데, 이는 같은 식입니다: 맞바꿈에 대해 대칭(symmetric)입니다. 둘째 괄호 hretimhimtreh_{\mathrm{re}} t_{\mathrm{im}} - h_{\mathrm{im}} t_{\mathrm{re}}trehimtimhret_{\mathrm{re}} h_{\mathrm{im}} - t_{\mathrm{im}} h_{\mathrm{re}}로 옮겨 가는데, 이는 정확히 그것의 부호를 뒤집은 것입니다: 반대칭(antisymmetric)입니다. 맞바꾼 점수를 원래 점수에서 빼면, 대칭인 부분은 상쇄되고 반대칭인 부분은 두 배가 됩니다:

s(h,r,t)s(t,r,h)  =  2i=1kwim[i](hre[i]tim[i]him[i]tre[i]).s(h, r, t) - s(t, r, h) \;=\; 2 \sum_{i=1}^{k} w_{\mathrm{im}}[i]\,\big(h_{\mathrm{re}}[i]\, t_{\mathrm{im}}[i] - h_{\mathrm{im}}[i]\, t_{\mathrm{re}}[i]\big).

그러므로 모든 관계는 다이얼을 하나씩 소유합니다. wim=0\mathbf{w}_{\mathrm{im}} = \mathbf{0}으로 두면 그 차이는 모든 개체 쌍에 대해 사라집니다: 관계는 완벽하게 대칭적이 되고, 점수는 각 차원의 두 채널이 관계 가중치 wre[i]w_{\mathrm{re}}[i]를 공유하는, 두 배가 된 채널들에 대한 DistMult식 합으로 환원됩니다; 개체의 허수부까지 0으로 두면 남는 것은 정확히 kk차원 DistMult이므로, ComplEx는 순수한 실수 임베딩이라는 특수한 경우로서 DistMult를 포함합니다. wre=0\mathbf{w}_{\mathrm{re}} = \mathbf{0}으로 두면 반대칭 부분만 살아남아 s(h,r,t)=s(t,r,h)s(h,r,t) = -s(t,r,h)를 주는, 완벽하게 반대칭적인 관계가 됩니다. 훈련은 각 관계의 두 채널을 독립적으로 조율하므로, collaborates 유형의 관계와 cites 유형의 관계가 하나의 모델 안에 공존할 수 있으며, 각각은 대칭성 스펙트럼 위에서 데이터가 밀어붙이는 자리에 놓입니다. 켤레화 하나가 다이얼 전체를 사 준 것입니다.

손으로 유도하는 손실과 모든 그래디언트

두 모델은 동일하게 훈련되므로, 이 유도는 두 번 값을 합니다. 15개의 훈련 트리플 각각은 레이블(label) y=+1y = +1을 갖는 양성이며; 각각은 매 에폭 y=1y = -1을 갖는 균등 표집 오염물 하나와 짝지어지고, 그 오염물이 그 자체로 알려진 참인 트리플일 때마다 다시 뽑히는데, 이는 지난 장과 같은 함정이자 같은 해법입니다(bilinear.py 215–227번째 줄). 예시별 목적 함수는 로지스틱 손실(logistic loss)입니다:

L  =  softplus(ys)  =  ln ⁣(1+eys),L \;=\; \mathrm{softplus}(-y\,s) \;=\; \ln\!\big(1 + e^{-y\,s}\big),

여기서 ln\ln자연로그(natural logarithm, 지수 함수의 역함수이므로 lnex=x\ln e^x = x)이고, softplus(x)=ln(1+ex)\mathrm{softplus}(x) = \ln(1 + e^x)는 매끄러운 램프입니다: 큰 음수 xx에서는 0에 가깝고, 큰 양수 xx에서는 xx 자신에 가깝습니다. 손실을 읽기 위해, 1권에서 σ(x)=1/(1+ex)\sigma(x) = 1/(1 + e^{-x})가 시그모이드였음을 떠올리고, 항등식 lnσ(x)=ln11+ex=ln(1+ex)=softplus(x)-\ln \sigma(x) = -\ln\frac{1}{1+e^{-x}} = \ln(1 + e^{-x}) = \mathrm{softplus}(-x)에 주목하십시오. 따라서 L=lnσ(ys)L = -\ln \sigma(y\,s)입니다: σ(s)\sigma(s)를 트리플이 참일 모델의 확률로 읽는다면, σ(ys)\sigma(y\,s)는 모델이 올바른 레이블에 부여하는 확률이고, 손실은 옳게 맞혔을 로그가능도의 음수입니다. 양성이 높게 채점되거나 음성이 낮게 채점되면 ysy\,s가 커져 손실은 거의 0이 됩니다; 자신만만한 실수는 ysy\,s를 매우 음수로 만들고 손실은 힌지의 클램프되지 않은 쪽처럼 선형으로 커집니다. 코드는 이를 np.logaddexp(0.0, -y * s)로 안정적으로 계산하는데, 이는 오버플로 없이 계산된 ln(e0+eys)\ln(e^0 + e^{-ys})입니다(bilinear.py 85번째 줄).

점수를 관통하는 연쇄. 어떤 파라미터에 대해서든 LL의 그래디언트는 ss를 거쳐 인수분해되므로, 먼저 softplus를 미분합니다. 미적분학의 사실 하나가 이 일을 해냅니다: 자연로그는 ddvlnv=1v\frac{d}{dv}\ln v = \frac{1}{v}로 미분되므로, 연쇄 법칙은 임의의 안쪽 함수 vv에 대해 ddulnv(u)=v(u)v(u)\frac{d}{du}\ln v(u) = \frac{v'(u)}{v(u)}를 줍니다; 여기서 안쪽 함수는 v(u)=1+euv(u) = 1 + e^u이고 그 도함수는 eue^u입니다. u=ysu = -y\,s일 때,

ddusoftplus(u)  =  dduln(1+eu)  =  eu1+eu  =  1eu+1  =  σ(u),\frac{d}{du}\,\mathrm{softplus}(u) \;=\; \frac{d}{du} \ln(1 + e^u) \;=\; \frac{e^u}{1 + e^u} \;=\; \frac{1}{e^{-u} + 1} \;=\; \sigma(u),

둘째 단계에서는 ddulnv=vv\frac{d}{du}\ln v = \frac{v'}{v}를 적용했고, 셋째 단계에서는 분자와 분모에 eue^{-u}를 곱했습니다. softplus의 도함수는 시그모이드입니다. 이제 u=ysu = -y\,s를 관통하는 연쇄 법칙을 적용하는데, ss에 대한 그 도함수는 상수 y-y입니다; 기호 \partial편미분(partial derivative)을 나타내며, 다른 모든 인자를 고정한 채 이름 붙은 변수에 대한 변화율입니다:

Ls  =  σ(ys)(ys)s  =  yσ(ys).\frac{\partial L}{\partial s} \;=\; \sigma(-y\,s) \cdot \frac{\partial(-y\,s)}{\partial s} \;=\; -\,y\,\sigma(-y\,s).

이것이 그대로 dl_ds = -y * _sigmoid(-y * s)입니다(bilinear.py 86–87번째 줄). 이는 1권에서 시그모이드와 교차 엔트로피가 함께 만들어 냈던 것과 똑같이 깔끔한 오차 신호입니다. 이를 확인하려면 시그모이드의 반사 항등식(reflection identity) 하나가 필요합니다:

σ(s)  =  11+es  =  eses+1  =  (es+1)1es+1  =  111+es  =  1σ(s),\sigma(-s) \;=\; \frac{1}{1 + e^{s}} \;=\; \frac{e^{-s}}{e^{-s} + 1} \;=\; \frac{(e^{-s} + 1) - 1}{e^{-s} + 1} \;=\; 1 - \frac{1}{1 + e^{-s}} \;=\; 1 - \sigma(s),

둘째 단계에서는 분자와 분모에 ese^{-s}를 곱했고, 셋째 단계에서는 분자를 분모 빼기 1로 다시 썼으며, 그 분수를 쪼개면 1 빼기 시그모이드의 정의식이 남습니다. 따라서 y=+1y = +1일 때 그래디언트 σ(s)-\sigma(-s)σ(s)1\sigma(s) - 1과 같고, y=1y = -1일 때는 곧바로 σ(s)\sigma(s), 즉 σ(s)0\sigma(s) - 0입니다; p=σ(s)p = \sigma(s)로 쓰고 레이블을 y~{0,1}\tilde{y} \in \{0, 1\}로 다시 코딩하면 L/s=py~\partial L / \partial s = p - \tilde{y}, 즉 예측 빼기 목표값을 얻습니다.

DistMult의 세 편미분. 점수 s=ieh[i]wr[i]et[i]s = \sum_i e_h[i]\, w_r[i]\, e_t[i]는 머리의 각 좌표 eh[j]e_h[j]가 정확히 한 항, 즉 jj번째 항에만 나타나고, 거기서 계수 wr[j]et[j]w_r[j]\, e_t[j]와 함께 선형으로 나타나는 합입니다. 선형 함수를 미분하면 그 계수를 그대로 읽어 냅니다:

seh[j]=wr[j]et[j],swr[j]=eh[j]et[j],set[j]=eh[j]wr[j].\frac{\partial s}{\partial e_h[j]} = w_r[j]\, e_t[j], \qquad \frac{\partial s}{\partial w_r[j]} = e_h[j]\, e_t[j], \qquad \frac{\partial s}{\partial e_t[j]} = e_h[j]\, w_r[j].

dd개씩의 편미분을 각각 벡터로 모으고, (대칭 정리와 함께 도입한) 원소별 곱셈인 아다마르 곱 \odot을 다시 사용하면, 연쇄 법칙은 세 그래디언트 모두를 한 번에 내줍니다:

Leh=Ls(wret),Lwr=Ls(ehet),Let=Ls(ehwr).\frac{\partial L}{\partial \mathbf{e}_h} = \frac{\partial L}{\partial s}\,\big(\mathbf{w}_r \odot \mathbf{e}_t\big), \qquad \frac{\partial L}{\partial \mathbf{w}_r} = \frac{\partial L}{\partial s}\,\big(\mathbf{e}_h \odot \mathbf{e}_t\big), \qquad \frac{\partial L}{\partial \mathbf{e}_t} = \frac{\partial L}{\partial s}\,\big(\mathbf{e}_h \odot \mathbf{w}_r\big).

커밋된 함수는 이 공식들을 주석으로 유도 과정을 보존한 채 담고 있습니다(bilinear.py 82–91번째 줄):

# s(h, r, t) = Σ_i e_h[i] · w_r[i] · e_t[i] (grouped as in distmult_score)
s = float(np.sum(w_r * (e_h * e_t)))
# L = softplus(−y·s) = ln(1 + e^{−y·s}) (computed stably via logaddexp)
loss = float(np.logaddexp(0.0, -y * s))
# dL/ds = −y · σ(−y·s) (softplus′ = σ, then the chain rule through −y·s)
dl_ds = -y * _sigmoid(-y * s)
# ∂s/∂e_h = w_r ⊙ e_t ; ∂s/∂w_r = e_h ⊙ e_t ; ∂s/∂e_t = e_h ⊙ w_r
grads = {"h": dl_ds * w_r * e_t,
"r": dl_ds * e_h * e_t,
"t": dl_ds * e_h * w_r}

ComplEx의 여섯 편미분. ComplEx는 트리플마다 여섯 개의 파라미터 블록을 갖습니다(머리, 관계, 꼬리 각각에 두 채널씩), 그리고 네 항짜리 전개는 각 편미분을 단순한 장부 정리 작업으로 만들어 줍니다: 그 변수를 포함하는 항들을 찾아 그 계수를 읽어 내면 됩니다. hreh_{\mathrm{re}}를 예로 들면: 이는 계수 wretrew_{\mathrm{re}} t_{\mathrm{re}}를 갖는 항 1과 계수 wimtimw_{\mathrm{im}} t_{\mathrm{im}}를 갖는 항 3에 나타나므로, s/hre=wretre+wimtim\partial s / \partial h_{\mathrm{re}} = w_{\mathrm{re}} t_{\mathrm{re}} + w_{\mathrm{im}} t_{\mathrm{im}}입니다. tret_{\mathrm{re}}를 예로 들면: 이는 계수 wrehrew_{\mathrm{re}} h_{\mathrm{re}}를 갖는 항 1과 계수 wimhim-w_{\mathrm{im}} h_{\mathrm{im}}를 갖는 항 4에 나타나므로, s/tre=wrehrewimhim\partial s / \partial t_{\mathrm{re}} = w_{\mathrm{re}} h_{\mathrm{re}} - w_{\mathrm{im}} h_{\mathrm{im}}입니다. 이 둘이 서로 다른 식이라는 점에 주목하십시오: 머리와 꼬리의 편미분은 더 이상 서로를 거울처럼 비추지 않는데, 이것이 깨진 대칭성이 그래디언트 수준에서 드러나는 모습입니다. 나머지 네 개도 같은 절차를 따르며, 코드는 그 완전한 검토 흔적을 주석 안에 담고 있습니다(bilinear.py 136–149번째 줄):

grads = {
# ∂s/∂h_re = w_re·t_re + w_im·t_im (terms 1 and 3 contain h_re)
"h_re": dl_ds * (w_re * t_re + w_im * t_im),
# ∂s/∂h_im = w_re·t_im − w_im·t_re (terms 2 and 4 contain h_im)
"h_im": dl_ds * (w_re * t_im - w_im * t_re),
# ∂s/∂w_re = h_re·t_re + h_im·t_im (terms 1 and 2 contain w_re)
"r_re": dl_ds * (h_re * t_re + h_im * t_im),
# ∂s/∂w_im = h_re·t_im − h_im·t_re (terms 3 and 4 contain w_im)
"r_im": dl_ds * (h_re * t_im - h_im * t_re),
# ∂s/∂t_re = w_re·h_re − w_im·h_im (terms 1 and 4 contain t_re)
"t_re": dl_ds * (w_re * h_re - w_im * h_im),
# ∂s/∂t_im = w_re·h_im + w_im·h_re (terms 2 and 3 contain t_im)
"t_im": dl_ds * (w_re * h_im + w_im * h_re),
}

갱신, 그리고 가중치 감쇠. 쌍선형 점수는 벡터 크기와 함께 커지므로, 제약이 없는 훈련은 구조를 배우지 않고도 양성의 점수를 밀어 올리기 위해 노름을 부풀릴 수 있습니다. 지난 장의 강제 재정규화 대신, 이 장은 더 부드러운 표준 도구인 L2 가중치 감쇠(L2 weight decay)를 사용합니다: 예시가 건드리는 각 파라미터 행 v\mathbf{v}에 대해 계수 λ=103\lambda = 10^{-3}을 갖는 벌점 λ2v2\frac{\lambda}{2}\lVert \mathbf{v} \rVert^2을 더합니다; 여기서 v2\lVert \mathbf{v} \rVert^2은 제곱된 유클리드 노름(Euclidean norm)이며, 첨자 mm이 그 행의 차원들을 훑는 좌표 제곱합 mv[m]2\sum_m v[m]^2입니다. 그 그래디언트는 벌점을 좌표별로 미분하여 구합니다, v[j]λ2mv[m]2=λ22v[j]=λv[j]\frac{\partial}{\partial v[j]} \frac{\lambda}{2} \sum_m v[m]^2 = \frac{\lambda}{2} \cdot 2\,v[j] = \lambda\, v[j]이므로, 벌점은 단순히 그래디언트에 λv\lambda \mathbf{v}를 더하고, 확률적 경사 하강 스텝은 다음이 됩니다

v    vη(Lv+λv),\mathbf{v} \;\leftarrow\; \mathbf{v} - \eta\left(\frac{\partial L}{\partial \mathbf{v}} + \lambda\,\mathbf{v}\right),

이는 손실 신호 위에 학습률 η=0.05\eta = 0.05로, 건드려진 모든 행을 원점 쪽으로 부드럽게 끌어당기는 것입니다(하이퍼파라미터는 bilinear.py 37–42번째 줄, DistMult 갱신은 245–250번째 줄, ComplEx의 네 배열 판본은 276–284번째 줄).

신뢰하되, 검증하기. 위의 모든 공식은 훈련이 시작되기 전에 검사됩니다. 하니스는 건드려진 각 행의 각 좌표를 ε=106\varepsilon = 10^{-6}으로 ±ε\pm\varepsilon만큼 흔들고, 오차가 ε\varepsilon에 대해 이차적으로 줄어드는 중심 차분(central difference) (L(v+ε)L(vε))/2ε\big(L(v + \varepsilon) - L(v - \varepsilon)\big)/2\varepsilon을 해석적 편미분과 비교합니다(bilinear.py 157–166번째 줄). 커밋된 실행은 다음을 보고합니다:

gradient check (central differences, eps = 1e-6, untrained params)
DistMult max |analytic - numeric| = 8.979e-11
ComplEx max |analytic - numeric| = 1.585e-10

모든 편미분, 두 레이블, 모든 좌표에 걸친 가장 큰 불일치는 약 101010^{-10}입니다: 손으로 유도한 그래디언트가 참된 그래디언트입니다.

커밋된 정면 대결

이제 두 모델은 동일한 조건 아래에서 훈련됩니다: 같은 15개의 양성, 같은 음성 샘플러, 같은 시드, 1000에폭입니다. 하니스는 30개의 레이블 붙은 트리플(15개 양성 더하기 15개 음성)에 대한 평균 손실을 일곱 개의 체크포인트에서 스냅샷으로 남깁니다:

training: logistic loss softplus(-y*s), 15 positives + 1 uniform negative each,
SGD lr=0.05, L2 weight decay 0.001 on touched rows, d=16 real dims (8 complex), 1000 epochs, seed 0
epoch | DistMult | ComplEx (mean loss over the 30 labelled triples)
1 | 0.8173 | 0.7997
10 | 0.5931 | 0.5593
50 | 0.3460 | 0.2904
100 | 0.2013 | 0.2201
250 | 0.0298 | 0.0163
500 | 0.1363 | 0.0041
1000 | 0.0143 | 0.0034

두 개의 눈금 기준점이 표를 읽을 만하게 만들어 줍니다. 모든 트리플에 s=0s = 0을 매기는 모델은 예시당 softplus(0)=ln20.6931\mathrm{softplus}(0) = \ln 2 \approx 0.6931을 치르므로, 그 표시 바로 위에 있는 에폭 1의 값은 무작위 초기화가 무관심보다 살짝 더 나쁘게 시작한다는 뜻입니다. 그리고 곡선이 단조롭게 내려갈 의무는 없습니다: 매 에폭은 새로운 무작위 음성을 뽑으므로, 마침 어려운 오염물을 표집하게 된 에폭은 평균을 튀어 오르게 할 수 있는데, 이것이 바로 에폭 500에서 DistMult의 0.1363이 나타내는 것입니다. 두 모델 모두 결국 자신의 훈련 쌍에 잘 들어맞습니다; 손실 표만으로는 둘을 구별할 수 없습니다. 구조적인 차이는 이어지는 두 표 안에 있습니다.

첫째, 앞서 온전히 인용했던 대칭 표를 이제 두 열 모두 읽을 수 있는 채로 살펴봅시다. DistMult는 4.8879 대 4.8879로 동점입니다. ComplEx는 참인 방향에 6.6413을, 거짓인 역방향에 −4.5805를 매겨 11.2217의 간격을 벌리며, 하니스는 그 간격이 0.1을 넘는다고 단언합니다(bilinear.py 334번째 줄). 원점수를 시그모이드에 통과시켜 로지스틱 손실이 훈련시킨 확률로 바꾸어 봅시다: DistMult는 "p1이 p2를 인용한다"는 거짓 사실을 확률 σ(4.8879)0.993\sigma(4.8879) \approx 0.993로 믿는데, 이는 피할 수 없습니다, 왜냐하면 참인 사실도 정확히 같은 강도로 믿기 때문입니다. ComplEx는 참인 방향을 σ(6.6413)0.999\sigma(6.6413) \approx 0.999로, 거짓인 방향을 σ(4.5805)0.010\sigma(-4.5805) \approx 0.010으로 믿습니다. 만약 그 거짓 역방향이 음성 예시(y=1y = -1)로 제시된 적이 있었다면, DistMult는 손실로 softplus(4.8879)4.90\mathrm{softplus}(4.8879) \approx 4.90을 치렀을 것이고 그에 대해 아무것도 할 수 없었을 것입니다: 정리에 의해, 역방향의 점수를 낮추는 그래디언트는 참인 사실의 점수를 낮추는 그래디언트와 같은 벡터이므로, 모델은 오직 한 오류를 다른 오류와 맞바꿀 수 있을 뿐입니다. ComplEx는 softplus(4.5805)0.0102\mathrm{softplus}(-4.5805) \approx 0.0102를 치를 것인데, 이는 사실상 아무것도 아닙니다.

둘째, 링크 예측에서 가져온 공유된 필터링 평가입니다: 3개의 제외해 둔 시험 트리플을 머리와 꼬리로 오염시켜 만든 여섯 개의 순위 질의를, 알려진 참인 경쟁자를 걸러 낸 채 13개 개체 전부에 대해 채점합니다(후보별 채점과 필터링은 kg.py 79–104번째 줄, 여섯 질의의 집계는 110–122번째 줄):

filtered link prediction (6 ranking queries over 13 entities)
model | MRR Hits@1 Hits@3 Hits@10 | ranks (tail,head per test triple)
DistMult | 0.1962 0.0000 0.1667 0.8333 | [2, 5, 10, 5, 13, 10]
ComplEx | 0.5167 0.3333 0.6667 1.0000 | [1, 1, 10, 6, 3, 2]

순위 목록을 시험 트리플 순서대로 읽어 봅시다: (bob, advises, dave), (bob, authored, p1), (erin, affiliated, cmu) 각각에 대해 먼저 꼬리-오염 순위, 그다음 머리-오염 순위입니다. ComplEx는 지도 질의의 양방향 모두를 완벽하게 답해 순위 1과 1을 얻고, 모든 질의를 상위 열 안에 두어 필터링된 평균 역순위 0.5167을 얻습니다. DistMult는 참인 답을 결코 1순위에 두지 못하며, 최악의 질의인 "erin이 어느 기관에 소속되어 있는가"에서는 참인 꼬리 cmu를 13개 개체 가운데 꼴찌인 순위 13에 둡니다(erin에게는 알려진 다른 소속이 없으므로 그 질의에서는 아무것도 걸러지지 않고 13이 가능한 최악의 순위입니다). 어느 숫자든 너무 깊이 읽어 들이기 전에 두 가지 유보가 정직하게 필요합니다. 13개 개체짜리 그래프 위의 여섯 질의는 벤치마크가 아니라 시연입니다; 순위 하나가 2에서 1로 옮겨 가는 것만으로도 MRR은 0.08만큼 바뀝니다. 그리고 지난 장에서 TransE는 같은 프로토콜에서 0.7778을 얻었으므로, "곱셈이 이동을 이긴다"는 것은 여기서 얻을 교훈이 아닙니다; 이 작고 사슬이 많은 그래프에서는, 어떤 모델에 대해서도 하이퍼파라미터 튜닝 없이, 이동이 마침 잘 들어맞을 뿐입니다. 지속되는 내용은 하니스가 눈대중이 아니라 단언하는 한 쌍의 구조적 사실입니다: DistMult의 동점은 정확하고 파라미터와 무관하며, ComplEx의 수선은 넓습니다(bilinear.py 332번째 줄과 334번째 줄).

곱셈이 사 주는 것

대칭 정리는 쌍선형 모델에 대한 기소장처럼 읽히므로, 매듭을 짓는 것이 가치가 있습니다: DistMult의 동점을 강제하는 바로 그 곱셈적 구조가 이동이 갖지 못한 능력들을 이 계열에 부여하며, 수선된 모델은 그 능력들을 모두 유지합니다.

원할 때 대칭성 그 자체. collaboratesWith처럼 어떤 관계가 정말로 대칭적이라고 해 봅시다. TransE는 대칭 쌍을 무너뜨림으로써만 정확히 맞출 수 있습니다: eh+wr=et\mathbf{e}_h + \mathbf{w}_r = \mathbf{e}_tet+wr=eh\mathbf{e}_t + \mathbf{w}_r = \mathbf{e}_h가 둘 다 성립한다면, 첫째를 둘째에 대입하면 eh+2wr=eh\mathbf{e}_h + 2\mathbf{w}_r = \mathbf{e}_h를 얻으므로 2wr=02\mathbf{w}_r = \mathbf{0}이고, 따라서 wr=0\mathbf{w}_r = \mathbf{0}이며, 그러면 첫째 방정식은 eh=et\mathbf{e}_h = \mathbf{e}_t를 강제합니다: 관계는 "같은 점이다"로 붕괴합니다. DistMult는 대칭 관계를 공짜로 얻고, ComplEx는 그 관계에 대해 wim0\mathbf{w}_{\mathrm{im}} \approx \mathbf{0}을 배우면서도 cites에 대해서는 wim\mathbf{w}_{\mathrm{im}}을 크게 유지함으로써 그것을 얻습니다. 전개 절에서 유도한 다이얼은 어떤 이동 모델도 내주지 못하는 관계별 선택입니다.

등급이 매겨진, 특징별 상호작용. 이동 점수는 기하학적입니다: 착지점이 얼마나 빗나갔는지만 보고할 수 있습니다. 곱셈 점수는 특징-논리적(feature-logical)입니다: 각 차원이 부호와 크기를 갖고 찬성 또는 반대의 증거를 제공하며, 관계 벡터는 중요한 특징들을 선택하고 가중치를 매깁니다. 이것이 바로 쌍선형 계열이, "그" 착지점이 존재하지 않는, 함수도 아니고 거의 함수에 가깝지도 않은 관계에서 잘 작동하는 이유입니다.

용량 보장. 긍정적인 쪽에도 정리가 하나 있습니다. ComplEx는 완전 표현력(fully expressive)을 갖습니다: 어떤 유한한 지식 그래프에 대해서도, 그리고 가능한 모든 트리플에 대한 참/거짓의 어떤 할당에 대해서도, 그 할당을 정확히 실현하는 점수를 내주는 임베딩 차원과 복소 임베딩 설정이 존재합니다. 단일 관계에 대한 존재 결과는 모델과 함께 나왔고 [3], 필요한 차원에 대한 명시적 상한을 갖는 다중 관계 정리는 그 분해의 확장된 논의에서 나왔습니다 [4]. DistMult에게 반대칭성이 그렇듯 구조적으로 손 닿지 않는 그래프 패턴은 존재하지 않습니다. 이 보장은 신중하게 읽어야 합니다: 그 구성은 그래프 자체의 크기에 맞먹는 차원을 필요로 할 수도 있으며, 무엇이든 암기할 수 있을 만큼 충분한 용량을 가진 모델이라고 해서 그것만으로 일반화하는 모델이 되는 것은 아닙니다; 커밋된 실행의 낮은 dd와 가중치 감쇠가 실제 귀납적 작업을 해내고 있습니다. 완전 표현력이 ComplEx만의 것도 아닙니다. SimplE는 각 개체에 머리-역할과 꼬리-역할의 별도 임베딩을 부여하고 이를 역관계를 통해 서로 묶음으로써 다른 경로로 같은 보장에 도달합니다 [5]; "쌍선형이지만 방향에 민감한" 설계 공간에는 여러 출구가 있으며, 켤레화는 DistMult의 파라미터 예산을 벗어나지 않고 그곳에 도달하는데, 그 예산은 SimplE의 두 역할 분할과도 정확히 일치합니다.

아직 풀리지 않은 부분

I부의 모든 것은, 이동이든 쌍선형이든, 하나의 암묵적인 가정을 공유합니다: 예측의 단위는 두 사이의 낱개 엣지라는 것입니다. 점수 s(h,r,t)s(h, r, t)는 두 개체를 받아 숫자 하나를 반환합니다; 평가는 후보 개체들의 순위를 하나씩 매깁니다. 그러나 2권이 실제로 무엇에 관해 추론했는지 되돌아보십시오. Researcher는 개체가 아닙니다; 그것은 개체들의 집합개념이며, 완성 알고리즘이 도출한 포섭 Professor ⊑ Researcher는 집합 포함에 관한 주장입니다. "구성원이 p3에게 인용된 논문을 저술한 기관들"과 같은 다중 홉 질의도 마찬가지로 답들의 집합을 나타내며, 그 집합은 비어 있을 수도, 클 수도 있습니다. 점은 다른 점을 포함할 수 없으며, 내적 안에는 "이 모음의 모든 구성원은 저 모음에도 속한다"를 표현하는 것이 아무것도 없습니다. 각 개념을 그 인스턴스들의 중심점으로 임베딩하여 이를 흉내 내 볼 수도 있겠지만, 중심점은 범위를 잊어버립니다: 인스턴스 3개짜리 Topic과 인스턴스 5개짜리 Person은 둘 다 단일한 점이 될 것이고, "기하가 그 포섭을 함의하는가"라는 정리 모양의 질문은 아예 기하학적 지시 대상을 갖지 못할 것입니다. 빠진 것은 더 나은 점수 함수가 아닙니다; 그것은 안쪽을 가진, 다른 종류의 기하학적 대상입니다. 영역 기반 기하가 2권의 논리적 보장을 담아낼 수 있는지, 그리고 학습 가능성 면에서 어떤 대가를 치르는지가, 이 권의 나머지 부분이 풀어 나갈 열린 질문입니다.

왜 중요한가

신경-기호적 기획에서, 이 장은 이 권의 첫 번째 순수한 표본, 즉 아키텍처 수준의 논리적 개입을 전달합니다. cites의 반대칭성은 정확히 2권의 온톨로지가 한 줄로 진술하는 그런 유형의 공리이며, 대칭 정리는 그 공리가 학습 불가능한 모델 계열 전체를 보여 줍니다: 어떤 데이터도, 어떤 옵티마이저도, 어떤 일정도 DistMult에게 그 점수 함수가 표현할 수 없는 구별을 가르칠 수 없습니다. 이것이 이 권이 계속해서 던지는 질문, "기하는 어떤 논리를 허용하는가?"의 가장 날카로운 형태이며, 앞으로의 모든 것에 대한 방법을 정합니다: 어떤 모델을 훈련시켜 기호적 속성을 존중하게 만들기 전에, 먼저 그 기하가 애초에 그 속성을 표현할 수 있는지를 확인하십시오. 그 수선책 역시 못지않게 교훈적입니다. ComplEx는 용량도, 파라미터도, 깊이도 더하지 않았습니다; 그것은 대수(algebra)를 바꾸었고(실수에서 복소수로, 켤레화 하나와 함께), 증명 가능하게 부재하던 능력이 나타났습니다. 4권이 임베딩 점수 위에 미분 가능한 논리를 세울 때, 이 교훈은 끊임없이 되풀이됩니다: 점수의 대수적 형태가 경사 하강이 도달할 수 있는 논리적 패턴이 무엇인지를 결정하며, 4.8879 = 4.8879와 6.6413 대 −4.5805 사이의 확인 가능하고 단언으로 지켜지는 간격이야말로 커밋된 코드 안에서 "기하가 그 공리를 허용한다"는 것이 어떤 모습인지를 보여 줍니다.

핵심 용어

  • 쌍선형 형식(Bilinear form) — 꼬리를 고정했을 때 머리 임베딩에 대해 선형이고 머리를 고정했을 때 꼬리에 대해 선형인 점수 ehWret\mathbf{e}_h^\top W_r \mathbf{e}_t; 일반적인 곱셈적 트리플 점수입니다.
  • 텐서 분해(Tensor factorization) — 지식 그래프의 0/1 근접 텐서를 저차원의 공유 인자들로부터 재구성하는 것으로, 링크 예측에 대한 RESCAL의 해석입니다.
  • DistMult — 대각 제한 Wr=diag(wr)W_r = \mathrm{diag}(\mathbf{w}_r)이며, 관계당 dd개의 파라미터로 삼중 내적 s=ieh[i]wr[i]et[i]s = \sum_i e_h[i]\, w_r[i]\, e_t[i]를 줍니다.
  • 대칭 결함(Symmetry defect) — 실수 곱셈의 교환법칙에 의해 DistMult의 점수가 어떤 파라미터 설정에서도 s(h,r,t)=s(t,r,h)s(h,r,t) = s(t,r,h)를 만족한다는 정리이며, cites와 같은 반대칭적 관계에서는 치명적입니다.
  • 복소 켤레(Complex conjugate) — a+bi=abi\overline{a + b\,\mathrm{i}} = a - b\,\mathrm{i}라는 사상이며, 꼬리 임베딩에 적용되었을 때 ComplEx의 점수에서 유일하게 비대칭적인 연산입니다.
  • ComplExCd/2\mathbb{C}^{d/2} 안의 임베딩을 Reeh,wr,et\mathrm{Re}\langle \mathbf{e}_h, \mathbf{w}_r, \overline{\mathbf{e}_t} \rangle로 채점하는 모델이며, 그 네 항짜리 실수 전개는 wre\mathbf{w}_{\mathrm{re}}로 가중된 대칭 부분과 wim\mathbf{w}_{\mathrm{im}}으로 가중된 반대칭 부분으로 나뉩니다.
  • 아다마르 곱(Hadamard product) ⊙ — 벡터의 원소별 곱셈이며, DistMult의 편미분은 s/eh=wret\partial s/\partial \mathbf{e}_h = \mathbf{w}_r \odot \mathbf{e}_t와 그 두 형제입니다.
  • 로지스틱 손실 / softplus(Logistic loss) — L=softplus(ys)=lnσ(ys)L = \mathrm{softplus}(-y\,s) = -\ln\sigma(y\,s)이며, 올바른 ±1 레이블의 음의 로그가능도이고, 도함수는 L/s=yσ(ys)\partial L/\partial s = -y\,\sigma(-y\,s)입니다.
  • L2 가중치 감쇠(L2 weight decay) — 그래디언트 λv\lambda\mathbf{v}가 건드려진 행들을 원점 쪽으로 끌어당기는 벌점 λ2v2\frac{\lambda}{2}\lVert\mathbf{v}\rVert^2이며, 곱셈적 점수가 불러들이는 노름 팽창을 길들입니다.
  • 완전 표현력(Fully expressive) — 충분한 차원이 주어지면 유한한 그래프 위의 어떤 참/거짓 할당이든 정확히 실현할 수 있는 모델 계열이며, ComplEx와 SimplE는 둘 다 이를 만족하지만 DistMult는 증명 가능하게 그렇지 못합니다.

이 장이 이끄는 곳

I부가 완성되었습니다: 개체를 위한 점, 관계를 위한 화살표 또는 곱셈적 채점 기준표, 그리고 두 계열 모두가 겨룰 수 있는 필터링된 순위 채점판입니다. 아직 풀리지 않은 부분은 그 천장의 이름을 붙였고, II부는 그것을 끌어올립니다. 공과 원뿔집합의 기하를 시작합니다: 개념은 안쪽을 가진 영역이 되고, 소속은 "이 점이 안에 놓여 있다"가 되며, 2권의 포섭 Professor ⊑ Researcher는 그림이 참으로 만들 수 있는 진술, 즉 한 영역이 다른 영역 안에 포함되는 것이 됩니다. 첫 번째 영역들은 안쪽을 가진 가장 단순한 도형인 공이 될 것이고, 첫 번째 질문은 이 장이 우리에게 무엇이든 훈련시키기 전에 던지라고 가르쳐 준 바로 그 질문일 것입니다: 그 기하는 대체 어떤 공리를 표현할 수 있는가?


동반 코드: examples/neural/bilinear.py는 두 모델 모두를 NumPy로 처음부터 구현하며, 모든 그래디언트는 주석 안에 손으로 유도되어 있고 훈련 전에 중심 차분으로 검증됩니다; examples/neural/kg.py는 18개 트리플짜리 학계 그래프, 15/3 분할, 그리고 이 권의 모든 모델이 공유하는 필터링된 순위 평가를 제공합니다. 이 장의 모든 숫자를 재현하려면 python3 examples/neural/bilinear.py를 실행하십시오; 이 모듈의 단언들(그래디언트 검사가 10610^{-6} 미만, 두 모델 모두 최종 훈련 손실이 에폭 1의 손실 미만, DistMult의 동점이 10910^{-9} 미만, ComplEx의 간격이 0.10.1 초과, ComplEx의 MRR이 최소 0.40.4)이 그 수용 기준입니다.