배우기 · 10
비전 트랜스포머
합성곱은 이웃을 본다. 트랜스포머는 모든 패치가 모든 패치를 보고 무엇이 중요한지 스스로 정하게 한다. 그림을 패치로 자르는 일은 stride 를 패치 크기로 맞춘 합성곱 하나다 — 그다음부터는 그림이 없다. 수열만 있다.
이 레슨은 borch.ts 가 torch 보다 좁은 네 곳이 드러나는 자리이기도 하다. 각각을 각주가 아니라 마주치는 자리에서 이름 붙였다. 넷 다 torch 튜토리얼에서 복사해 오면 돌지 않는 줄이기 때문이다.
패치가 곧 토큰
Conv2d(1, D, patch, patch, 0) 는 패치마다 길이 D 벡터 하나를
[N, D, H', W'] 배치로 낸다. 수열은 [N, 토큰, D] 를 원하므로
맵을 펴고 뒤 두 축을 맞바꾼다.
transpose 는 2차원 전용이다.
3차원 텐서에 대한 torch 의 x.transpose(1, 2) 에 해당하는 것이 없다.
permute([0, 2, 1]) 이 같은 말을 하고, 이쪽은 돈다.
어텐션, 그리고 배치가 안 되는 선형층
nn.MultiheadAttention(D, heads) 는 질의·키·값을 받는다. 같은 텐서를
셋 다 넣으면 self-attention 이다 — 토큰마다 모든 토큰에게 무엇을 가졌는지 묻는다.
(출력, 가중치) 를 내므로 const [out] = att(...) 는 여기서
텐서를 구조 분해해 쓸 수 없는 것을 준다. 다만 가중치가 사라진 것은 아니다 —
nn.multiHeadAttentionForward 가 torch 의
multi_head_attention_forward 이고 둘 다 돌려준다(헤드 평균 또는
헤드별). 손대기 전에 알아야 할 것 둘: 짝이 아니라
객체 { output, weights } 를 내고, 층이 배치 우선인 것과
달리 길이 우선 (L, N, E) 를 받는다. 배치 우선로 넣으면
아무 말 없이 엉뚱한 축을 섞는다.차이 3 —
nn.Linear 는 2차원 전용이다.
[N, 토큰, D] 를 주면 거절하고 이유를 말한다:
mm 은 2차원 곱하기 2차원. 배치는 아직 없다. 배치 축과 토큰 축을 접었다가
뒤에 펴는 것은 근사가 아니라 정확히 같은 계산이다 — 선형층은 어차피 행마다
독립적으로 처리한다.
클래스 토큰
수열을 예측 하나로 바꿀 무언가가 필요하다. 토큰을 평균 내는 것이 뻔한 수인데 여기서는 틀린 수다. 아래 과제에서는 패치 하나만 밝고, 그것이 평균에 보태는 몫은 어디에 있든 같다 — 답이 평균에 지워진다. 트랜스포머는 대신 어느 패치에도 속하지 않는 학습되는 토큰 하나를 앞에 붙이고, 어텐션이 그것을 채우게 한 뒤 거기서 클래스를 읽는다.
expand 와 repeat 은 배열이 아니라 인자를
낱개로 받는다. repeat([n, 1, 1]) 은 원소 하나짜리 모양으로 읽혀
차원이 줄어든다며 실패한다. repeat(n, 1, 1) 이 torch 도 받는 그 호출이다.
오류 메시지가 엉뚱한 곳을 가리키므로, 십 분을 쓰기 전에 알아 둘 값어치가 있다.
합치면
8×8 그림, 사분면 중 하나가 밝고, 라벨은 어느 사분면인가다. 어텐션에게 진짜 할 일이 있다 — 켜진 패치를 찾아 그것이 어디였는지 알리기. 위치는 패치 내용에 아예 없다. 수열에 더해지는, 학습되는 위치 임베딩에 있다.
이것이 이 사이트에서 가장 느린 블록이다 — 십 초쯤 걸린다. 멈춘 건가 싶지 않도록 진행 줄을 도중에 찍는다.
좁혀 놓고 멈추는 것을 보라
위의 실행은 내려가는 길에 loss 0.347 근처를 지나갔다가 빠져나온다.
D = 16 에 헤드 둘이면 빠져나오지 못한다. 같은 코드, 같은 과제 —
폭과 헤드 수만 다르다. 한 번 뽑기의 운이 아니도록 씨앗 셋을 돌린다.
ln(2) / 2 는 예제의
절반에서 두 답 사이를 반반으로 가르고 나머지 절반은 맞히는 모델이 받는 값이다 —
위의 정확도가 말하는 것이 정확히 그것이다. 사분면 한 쌍을 못 가르고 포기하니
argmax 가 그 쌍에서 매번 같은 쪽을 집고, 네 클래스 중 셋이 맞게 나온다.라이브러리를 탓하기 전에 확인할 값어치가 있었고, 확인했다:
cat·narrow·permute 는 모두 기울기를 옳게
나르고, 헤드 수는 답을 실제로 바꾼다. 정체는 모델의 것이지 런타임의 것이 아니다.이 블록이 있는 이유는 여기 있던 문장이 저 숫자들을 만들어 보이지 않고 주장했기 때문이다. 그 문장은 이 모델이 씨앗을 바꿔도 0.3466 에 앉는다고 했고, 실제로 잰 것은 셋이었다. 예제가 돈다는 것이 논거인 페이지가, 자기 예제가 하지 않는 주장을 하고 있으면 안 된다.
여기까지가 마지막 레슨이다. 튜토리얼은 대신 문제 하나를 끝까지 끌고 가고, Playground 는 아무것도 안 쓰인 같은 런타임이다.