Transformers, the tech behind LLMs | Deep Learning Chapter 5


Predict, sample, repeat (예측, 샘플링, 반복) (0:00)

GPT라는 이니셜은 Generative Pretrained Transformer(생성형 사전 훈련 트랜스포머)를 의미합니다. 첫 번째 단어(Generative)는 충분히 직관적입니다. 새로운 텍스트를 '생성'하는 봇이라는 뜻이죠. Pretrained(사전 훈련된)는 모델이 방대한 양의 데이터로 학습 과정을 거쳤다는 것을 의미하며, 이 접두사는 추가적인 훈련을 통해 특정 작업에 맞게 미세 조정(fine-tune)할 여지가 더 있음을 암시합니다. 하지만 마지막 단어, 그것이 바로 진짜 핵심입니다. 트랜스포머(Transformer)는 특정 종류의 신경망(neural network), 즉 머신러닝 모델이며, 현재 AI 붐의 근간이 되는 핵심적인 발명품입니다.

제가 이 영상과 이어지는 챕터들에서 하고자 하는 것은 트랜스포머 내부에서 실제로 어떤 일이 일어나는지에 대해 시각적으로 설명하는 것입니다. 우리는 그 안을 흐르는 데이터를 따라가며 단계별로 살펴볼 것입니다. 트랜스포머를 사용해 만들 수 있는 모델에는 여러 종류가 있습니다. 어떤 모델은 오디오를 입력받아 스크립트(transcript)를 생성합니다. 이 문장은 그 반대로 텍스트만으로 합성 음성을 만들어내는 모델에서 나온 것입니다. 2022년에 세계를 강타했던 DALL-E나 Midjourney처럼 텍스트 설명을 입력받아 이미지를 생성하는 모든 도구들도 트랜스포머에 기반합니다. 비록 '파이 생명체(pi creature)'가 무엇인지 제대로 이해시키지는 못했지만, 저는 이런 일이 조금이라도 가능하다는 사실 자체에 여전히 경탄을 금치 못합니다.

그리고 2017년 구글이 선보인 최초의 트랜스포머는 한 언어의 텍스트를 다른 언어로 번역하는 특정 사용 사례를 위해 발명되었습니다. 하지만 우리가 집중해서 볼 변형 모델은 ChatGPT와 같은 도구의 기반이 되는 유형으로, 텍스트 한 조각을, 어쩌면 주변의 이미지나 소리와 함께 입력받아, 그 구절 다음에 무엇이 올지를 예측하도록 훈련된 모델일 것입니다. 그 예측은 다음에 올 수 있는 여러 텍스트 덩어리(chunk)들에 대한 확률 분포(probability distribution)의 형태를 띱니다.

언뜻 보기에는 다음 단어를 예측하는 것이 새로운 텍스트를 생성하는 것과는 매우 다른 목표처럼 느껴질 수 있습니다. 하지만 일단 이런 예측 모델을 갖게 되면, 더 긴 텍스트를 생성하게끔 시도해 볼 수 있는 간단한 방법이 있습니다. 바로 초기 스니펫(snippet)을 주고, 방금 생성한 분포에서 무작위로 샘플을 하나 뽑아 그 텍스트에 덧붙인 다음, 새로 추가된 내용을 포함한 전체 텍스트를 기반으로 새로운 예측을 하도록 전체 과정을 다시 실행하는 것입니다. 여러분은 어떨지 모르겠지만, 저는 이게 실제로 작동할 것 같다는 느낌이 정말 들지 않습니다.

예를 들어, 이 애니메이션에서 저는 제 노트북으로 GPT-2를 실행하면서, 시드 텍스트(seed text)를 기반으로 이야기를 생성하기 위해 다음 텍스트 덩어리를 반복적으로 예측하고 샘플링하도록 하고 있습니다. 그 이야기는 사실 별로 말이 되지 않습니다. 하지만 이것을 훨씬 더 크기만 한 동일한 기본 모델인 GPT-3 API 호출로 바꾸면, 갑자기 거의 마법처럼 말이 되는 이야기가 나옵니다. 심지어 파이 생명체는 수학과 계산의 땅에 살 것이라고 추론하는 것처럼 보이는 이야기 말이죠.

여기서 보여주는 반복적인 예측과 샘플링 과정이 바로 여러분이 ChatGPT나 다른 대규모 언어 모델들과 상호작용하며 한 단어씩 생성되는 것을 볼 때 일어나는 일의 본질입니다. 사실, 제가 정말로 즐길 만한 기능 중 하나는 모델이 선택하는 각각의 새로운 단어에 대한 기저의 분포(underlying distribution)를 볼 수 있는 기능일 겁니다.


Inside a transformer (트랜스포머 내부) (3:03)

트랜스포머를 데이터가 어떻게 흘러가는지에 대한 매우 개괄적인 프리뷰로 시작해 보겠습니다. 각 단계의 세부 사항에 대한 동기를 부여하고, 해석하고, 확장하는 데 훨씬 더 많은 시간을 할애하겠지만, 대체로 말해서, 이런 챗봇 중 하나가 특정 단어를 생성할 때 내부에서는 이런 일이 벌어집니다.

먼저, 입력은 여러 개의 작은 조각으로 나뉩니다. 이 조각들을 토큰(token)이라고 부르며, 텍스트의 경우 보통 단어나 단어의 일부, 또는 다른 흔한 문자 조합이 됩니다. 만약 이미지나 소리가 포함된다면, 토큰은 그 이미지의 작은 조각(patch)이나 그 소리의 작은 덩어리(chunk)가 될 수 있습니다. 그리고 이 토큰들 각각은 벡터(vector), 즉 어떤 숫자들의 목록과 연결되는데, 이 벡터는 해당 조각의 의미를 어떻게든 인코딩(encode)하기 위한 것입니다. 이 벡터들을 매우 높은 차원의 공간에서 좌표를 부여하는 것이라고 생각하면, 비슷한 의미를 가진 단어들은 그 공간에서 서로 가까운 벡터에 위치하는 경향이 있습니다.

이 벡터 시퀀스는 어텐션 블록(attention block)으로 알려진 연산을 통과하게 되는데, 이를 통해 벡터들은 서로 소통하며 정보를 주고받아 자신의 값을 업데이트할 수 있습니다. 예를 들어, '머신러닝 모델(a machine learning model)'이라는 구절에서의 '모델'이라는 단어의 의미는 '패션모델(a fashion model)'이라는 구절에서의 의미와 다릅니다. 어텐션 블록은 문맥 속에서 어떤 단어가 다른 단어들의 의미를 업데이트하는 데 관련이 있는지, 그리고 그 의미가 정확히 어떻게 업데이트되어야 하는지를 알아내는 역할을 합니다. 다시 말하지만, 제가 '의미'라는 단어를 사용할 때마다, 이것은 어떻게든 그 벡터들의 항목(entries) 안에 온전히 인코딩되어 있는 것입니다.

그 후에 이 벡터들은 다른 종류의 연산을 통과하는데, 읽고 계신 자료에 따라 이는 다층 퍼셉트론(multi-layer perceptron) 또는 피드포워드 레이어(feed-forward layer)라고 불릴 것입니다. 여기서는 벡터들이 서로 소통하지 않고, 모두 병렬적으로 동일한 연산을 거칩니다. 이 블록은 해석하기가 조금 더 어렵긴 하지만, 나중에 이 단계가 각 벡터에 대해 긴 질문 목록을 던지고 그 질문에 대한 답을 기반으로 벡터를 업데이트하는 것과 약간 비슷하다는 점에 대해 이야기할 것입니다. 이 두 블록의 모든 연산은 거대한 행렬 곱셈 더미처럼 보이며, 우리의 주된 임무는 그 기저의 행렬들을 읽는 법을 이해하는 것이 될 것입니다.

중간에 일어나는 일부 정규화(normalization) 단계에 대한 세부 사항은 대충 넘어가고 있지만, 어쨌든 이건 개괄적인 프리뷰니까요. 그 후, 과정은 본질적으로 반복됩니다. 어텐션 블록과 다층 퍼셉트론 블록 사이를 오가다가, 맨 마지막에 이르러서는 구절의 모든 핵심적인 의미가 시퀀스의 맨 마지막 벡터에 어떻게든 녹아들어 가 있기를 바라게 됩니다. 그런 다음 우리는 그 마지막 벡터에 특정 연산을 수행하여 다음에 올 수 있는 모든 가능한 토큰, 즉 모든 가능한 작은 텍스트 덩어리들에 대한 확률 분포를 생성합니다.

그리고 말씀드렸듯이, 일단 텍스트 스니펫이 주어졌을 때 다음에 올 것을 예측하는 도구를 갖게 되면, 약간의 시드 텍스트(seed text)를 입력하고 다음에 올 것을 예측하고, 분포에서 샘플링하고, 그것을 덧붙이고, 다시 반복하는 이 게임을 계속하게 할 수 있습니다. 이 분야를 아시는 분들 중 일부는 ChatGPT가 등장하기 훨씬 전에 초기 GPT-3 데모가 어땠는지 기억하실 겁니다. 초기 스니펫을 기반으로 이야기나 에세이를 자동 완성하게 했었죠. 이런 도구를 챗봇으로 만들기 위한 가장 쉬운 출발점은, 사용자가 도움이 되는 AI 어시스턴트와 상호작용하는 설정을 확립하는 약간의 텍스트, 즉 시스템 프롬프트(system prompt)를 두는 것입니다. 그리고 사용자의 초기 질문이나 프롬프트를 대화의 첫 부분으로 사용한 다음, 그런 도움이 되는 AI 어시스턴트가 응답으로 무엇을 말할지 예측하기 시작하게 하는 것입니다. 이것이 잘 작동하게 만들기 위해 필요한 추가적인 훈련 단계에 대해 더 할 말이 있지만, 개괄적으로는 이런 아이디어입니다.


Chapter layout (챕터 구성) (6:36)

이번 챕터에서 우리는 네트워크의 맨 처음과 맨 끝에서 일어나는 일들에 대한 세부 사항을 확장해 볼 것이고, 또한 트랜스포머가 등장할 무렵에는 모든 머신러닝 엔지니어에게 제2의 천성처럼 되었을 몇 가지 중요한 배경지식을 복습하는 데에도 많은 시간을 할애하고 싶습니다. 만약 그 배경지식에 익숙하고 조금 성급하시다면, 다음 챕터로 건너뛰셔도 괜찮을 겁니다. 다음 챕터는 일반적으로 트랜스포머의 심장으로 여겨지는 어텐션 블록에 초점을 맞출 것입니다. 그 후에는 이 다층 퍼셉트론 블록, 훈련이 작동하는 방식, 그리고 그때까지 생략되었을 여러 다른 세부 사항에 대해 더 이야기하고 싶습니다.


The premise of Deep Learning (딥러닝의 전제) (7:20)

더 넓은 맥락에서, 이 영상들은 딥러닝에 대한 미니 시리즈의 추가분입니다. 이전 영상들을 보지 않으셨어도 괜찮고, 순서 없이 보셔도 된다고 생각합니다. 하지만 트랜스포머에 본격적으로 뛰어들기 전에, 딥러닝의 기본 전제와 구조에 대해 우리가 같은 이해를 하고 있는지 확인하는 것이 가치 있다고 생각합니다.

너무 뻔한 말을 할 위험을 무릅쓰고 말하자면, 이것은 머신러닝(machine learning)의 한 접근법으로, 데이터를 사용해 모델이 어떻게 행동할지 결정하는 모든 모델을 설명합니다. 무슨 말이냐면, 이미지를 입력받아 그것을 설명하는 레이블을 출력하는 함수나, 텍스트 구절이 주어졌을 때 다음 단어를 예측하는 저희 예시처럼, 어느 정도의 직관과 패턴 인식이 필요한 다른 어떤 작업을 원한다고 해보죠. 요즘 우리는 이걸 거의 당연하게 여기지만, 머신러닝의 아이디어는 그 작업을 코드로 명시적으로 절차를 정의하려 하는 대신에(이는 AI 초창기에 사람들이 하던 방식입니다), 여러 개의 손잡이나 다이얼처럼, 조정 가능한 매개변수(tunable parameter)를 가진 매우 유연한 구조를 설정하는 것입니다. 그런 다음, 어떻게든, 주어진 입력에 대해 출력이 어떠해야 하는지에 대한 많은 예시를 사용해 이 행동을 모방하도록 그 매개변수들의 값을 조금씩 수정하고 조정합니다.

예를 들어, 아마도 가장 간단한 형태의 머신러닝은 선형 회귀(linear regression)일 것입니다. 입력과 출력이 각각 단일 숫자인 경우죠. 집의 면적과 가격 같은 것 말입니다. 여기서 원하는 것은 미래의 집값을 예측하기 위해 이 데이터를 가장 잘 나타내는 최적선(line of best fit)을 찾는 것입니다. 그 선은 기울기와 y절편이라는 두 개의 연속적인 매개변수로 설명되며, 선형 회귀의 목표는 데이터와 가깝게 일치하도록 그 매개변수들을 결정하는 것입니다.

말할 필요도 없이, 딥러닝 모델은 훨씬 더 복잡해집니다. 예를 들어 GPT-3는 2개가 아니라, 1750억 개의 매개변수를 가지고 있습니다. 하지만 여기서 중요한 점은, 훈련 데이터에 심하게 과적합(overfitting)되거나 훈련이 완전히 불가능(intractable)해지는 것 없이, 수많은 매개변수를 가진 거대한 모델을 만들 수 있다는 것이 당연한 일이 아니라는 겁니다. 딥러닝은 지난 수십 년간 놀라울 정도로 확장이 잘 된다는 것이 증명된 모델의 한 종류를 설명합니다. 그것들을 하나로 묶는 것은 모두 동일한 훈련 알고리즘을 사용한다는 점인데, 바로 역전파(backpropagation)라고 불립니다. 저희가 이전 챕터에서 이야기했었죠. 그리고 우리가 앞으로 나아가면서 여러분이 가졌으면 하는 맥락은, 이 훈련 알고리즘이 대규모로 잘 작동하기 위해서, 이 모델들은 특정 형식을 따라야만 한다는 것입니다. 그리고 만약 이 형식을 알고 시작한다면, 트랜스포머가 언어를 처리하는 방식에 대한 많은 선택들을 설명하는 데 도움이 됩니다. 그렇지 않으면 그 선택들이 다소 임의적으로 느껴질 위험이 있습니다.

첫째, 어떤 종류의 모델을 만들든, 입력은 실수의 배열로 형식화되어야 합니다. 이는 단순히 숫자 목록일 수도 있고, 2차원 배열일 수도 있으며, 혹은 매우 자주 더 높은 차원의 배열을 다루는데, 이때 일반적으로 사용되는 용어는 텐서(tensor)입니다. 여러분은 종종 그 입력 데이터가 점진적으로 여러 개의 개별적인 층(layer)으로 변환된다고 생각합니다. 이때 각 층은 항상 어떤 종류의 실수 배열로 구조화되어 있으며, 최종적으로 출력으로 간주하는 마지막 층에 도달할 때까지 계속됩니다. 예를 들어, 저희 텍스트 처리 모델의 마지막 층은 가능한 모든 다음 토큰에 대한 확률 분포를 나타내는 숫자 목록입니다.

딥러닝에서, 이 모델 매개변수들은 거의 항상 가중치(weight)라고 불립니다. 이는 이 모델들의 핵심 특징이, 이 매개변수들이 처리 중인 데이터와 상호작용하는 유일한 방법은 가중합(weighted sum)을 통하는 것이기 때문입니다. 또한 중간중간 비선형 함수를 뿌려주기도 하지만, 그것들은 매개변수에 의존하지 않습니다. 하지만 일반적으로 가중합이 이렇게 노골적으로 명시된 것을 보기보다는, 행렬-벡터 곱(matrix vector product)의 다양한 구성요소로 함께 묶여 있는 것을 발견하게 될 겁니다. 행렬-벡터 곱셈이 어떻게 작동하는지 돌이켜보면, 이는 같은 말을 하는 셈입니다. 출력의 각 구성요소는 가중합처럼 보입니다. 단지 처리 중인 데이터로부터 가져온 벡터를 변환하는, 조정 가능한 매개변수로 채워진 행렬이라고 생각하는 것이 우리에게 종종 개념적으로 더 깔끔할 뿐입니다.

예를 들어, GPT-3의 그 1750억 개의 가중치들은 28,000개에 약간 못 미치는 개별 행렬들로 구성되어 있습니다. 그 행렬들은 다시 8개의 다른 카테고리로 나뉘며, 우리가 할 일은 그 각 카테고리를 하나씩 살펴보며 그 유형이 무슨 일을 하는지 이해하는 것입니다. 진행하면서, 그 1750억 개가 정확히 어디서 오는지 세기 위해 GPT-3의 특정 숫자를 참조하는 것은 꽤 재미있다고 생각합니다. 비록 요즘에는 더 크고 더 나은 모델들이 있지만, 이 모델은 ML 커뮤니티 밖에서 세계의 주목을 받은 최초의 대규모 언어 모델로서 어떤 매력을 가지고 있습니다. 또한 현실적으로, 회사들은 더 현대적인 네트워크의 구체적인 수치에 대해서는 입을 더 굳게 다무는 경향이 있습니다.

저는 시작하기에 앞서 장면을 설정하고 싶습니다. ChatGPT와 같은 도구의 내부를 들여다볼 때, 거의 모든 실제 계산은 행렬-벡터 곱셈처럼 보인다는 것입니다. 수십억 개의 숫자 바다에서 길을 잃을 위험이 약간 있지만, 여러분은 모델의 가중치(항상 파란색이나 빨간색으로 칠할 겁니다)와 처리되는 데이터(항상 회색으로 칠할 겁니다)를 마음속으로 매우 명확하게 구분해야 합니다. 가중치가 실제 뇌이며, 훈련 중에 학습되는 것들이고, 모델이 어떻게 행동할지를 결정합니다. 처리되는 데이터는 단지 특정 실행을 위해 모델에 입력된 특정 입력, 예를 들어 텍스트 스니펫 예시 같은 것을 인코딩할 뿐입니다.


Word embeddings (단어 임베딩) (12:27)

이 모든 것을 기초로, 이 텍스트 처리 예시의 첫 번째 단계, 즉 입력을 작은 덩어리로 나누고 그 덩어리들을 벡터로 바꾸는 과정을 자세히 살펴보겠습니다. 저는 그 덩어리들을 토큰이라고 부른다고 언급했는데, 이는 단어의 일부나 구두점일 수 있습니다. 하지만 이번 챕터와 특히 다음 챕터에서는, 우리가 이해하기 쉽도록 그것이 좀 더 깔끔하게 단어 단위로 나뉜다고 가정하고 싶습니다. 우리 인간은 단어로 생각하기 때문에, 이렇게 하면 작은 예시들을 참조하고 각 단계를 명확히 하기가 훨씬 쉬워질 겁니다.

모델은 미리 정의된 어휘집, 즉 가능한 모든 단어의 목록을 가지고 있는데, 가령 5만 개 정도가 있다고 합시다. 그리고 우리가 마주칠 첫 번째 행렬인 임베딩 행렬(embedding matrix)은 이 단어들 각각에 대해 하나의 열(column)을 가지고 있습니다. 이 열들이 첫 단계에서 각 단어가 어떤 벡터로 변환될지를 결정합니다. 우리는 이것을 WE​라고 표기하며, 우리가 보게 될 모든 행렬처럼 그 값들은 처음엔 무작위지만 데이터를 기반으로 학습될 것입니다.

단어를 벡터로 바꾸는 것은 트랜스포머가 나오기 오래전부터 머신러닝에서 흔한 관행이었지만, 이전에 본 적이 없다면 약간 이상하게 느껴질 수 있습니다. 그리고 이는 뒤따르는 모든 것의 기초를 설정하므로, 잠시 시간을 내어 익숙해져 봅시다. 우리는 종종 이것을 단어 임베딩(embedding a word)이라고 부르는데, 이는 이 벡터들을 어떤 고차원 공간의 점으로서 매우 기하학적으로 생각하게끔 합니다. 세 개의 숫자 목록을 3D 공간의 점 좌표로 시각화하는 것은 문제가 없겠지만, 단어 임베딩은 훨씬 더 높은 차원인 경향이 있습니다. GPT-3에서는 12,288차원이며, 앞으로 보시겠지만, 많은 뚜렷한 방향을 가진 공간에서 작업하는 것이 중요합니다.

3D 공간을 통해 2차원 단면을 잘라 모든 점을 그 단면에 투영할 수 있는 것과 같은 방식으로, 간단한 모델이 제게 제공하는 단어 임베딩 애니메이션을 위해, 저는 이 매우 높은 차원 공간을 통해 3차원 단면을 선택하고 단어 벡터들을 그곳에 투영하여 결과를 표시하는 유사한 작업을 할 것입니다. 여기서 중요한 아이디어는, 모델이 훈련 중에 단어가 벡터로 정확히 어떻게 임베딩될지를 결정하기 위해 가중치를 미세 조정하면서, 공간상의 방향들이 일종의 의미론적 의미(semantic meaning)를 갖는 임베딩 집합에 수렴하는 경향이 있다는 것입니다.

제가 여기서 실행하는 간단한 단어-벡터 변환 모델의 경우, 'tower(탑)'의 임베딩과 가장 가까운 모든 단어를 검색해 보면, 모두 매우 비슷한 '탑스러운' 분위기를 풍기는 것을 알 수 있습니다. 만약 파이썬을 켜고 집에서 따라 해보고 싶으시다면, 이것이 제가 애니메이션을 만드는 데 사용하고 있는 특정 모델입니다. 트랜스포머는 아니지만, 공간의 방향이 의미론적 의미를 가질 수 있다는 아이디어를 설명하기에는 충분합니다.

이것의 매우 고전적인 예시는 'woman(여성)'과 'man(남성)' 벡터의 차이를 구하면(이는 공간에서 한쪽 끝에서 다른 쪽 끝을 연결하는 작은 벡터로 시각화할 수 있습니다), 'king(왕)'과 'queen(여왕)' 벡터의 차이와 매우 유사하다는 것입니다. 그래서 만약 여러분이 여성 군주를 뜻하는 단어를 몰랐다고 가정해 봅시다. 'king' 벡터를 가져와서 이 'woman' 빼기 'man' 방향을 더하고, 그 지점과 가장 가까운 임베딩을 검색하여 찾을 수 있습니다. 적어도, 어느 정도는요. 이것이 제가 사용하는 모델의 고전적인 예시임에도 불구하고, 'queen'의 실제 임베딩은 이것이 암시하는 것보다 사실 조금 더 멀리 떨어져 있습니다. 아마도 훈련 데이터에서 'queen'이 사용되는 방식이 단순히 'king'의 여성 버전만은 아니기 때문일 겁니다. 제가 직접 해봤을 때, 가족 관계가 그 아이디어를 훨씬 더 잘 설명하는 것 같았습니다. 요점은, 훈련 중에 모델이 이 공간의 한 방향이 성별 정보를 인코딩하도록 임베딩을 선택하는 것이 유리하다는 것을 발견한 것처럼 보인다는 것입니다.

또 다른 예로, 'Italy(이탈리아)'의 임베딩을 가져와서 'Germany(독일)'의 임베딩을 빼고, 그것을 'Hitler(히틀러)'의 임베딩에 더하면, 'Mussolini(무솔리니)'의 임베딩과 매우 가까운 것을 얻게 됩니다. 마치 모델이 어떤 방향은 이탈리아적인 것과, 다른 방향은 제2차 세계대전 추축국 지도자들과 연관 짓도록 학습한 것 같습니다. 이와 관련하여 제가 가장 좋아하는 예시는, 어떤 모델에서는 'Germany'와 'Japan'의 차이를 구해서 'sushi(스시)'에 더하면 'bratwurst(브라트부르스트, 독일식 소시지)'와 매우 가까워진다는 것입니다. 또한 가장 가까운 이웃을 찾는 이 게임을 하면서, 'cat(고양이)'이 'beast(야수)'와 'monster(괴물)' 모두와 매우 가깝다는 것을 보고 매우 기뻤습니다.

특히 다음 챕터를 위해 염두에 두면 도움이 되는 수학적 직관 하나는, 두 벡터의 내적(dot product)이 그들이 얼마나 잘 정렬되어 있는지를 측정하는 방법으로 생각될 수 있다는 것입니다. 계산적으로, 내적은 모든 해당하는 구성요소를 곱한 다음 그 결과를 더하는 것을 포함하는데, 우리 계산의 상당 부분이 가중합처럼 보여야 하므로 이는 좋은 일입니다. 기하학적으로, 내적은 벡터들이 비슷한 방향을 가리킬 때 양수이고, 수직일 때 0이며, 반대 방향을 가리킬 때 음수입니다.

예를 들어, 여러분이 이 모델로 실험하면서, 'cats(고양이들)'의 임베딩에서 'cat(고양이)'을 뺀 것이 이 공간에서 일종의 복수성(plurality) 방향을 나타낼 수 있다고 가설을 세운다고 해봅시다. 이를 테스트하기 위해, 저는 이 벡터를 가져와서 특정 단수 명사들의 임베딩과 내적을 계산하고, 해당하는 복수 명사들과의 내적과 비교할 것입니다. 직접 해보시면, 복수형들이 실제로 단수형들보다 일관되게 더 높은 값을 주는 것을 알 수 있는데, 이는 그들이 이 방향과 더 많이 정렬되어 있음을 나타냅니다. 또한 이 내적을 'one', 'two', 'three' 등과 같은 단어들의 임베딩과 계산하면 값이 증가하는 것도 재미있습니다. 마치 모델이 특정 단어를 얼마나 복수형으로 여기는지를 정량적으로 측정할 수 있는 것 같습니다.

다시 말하지만, 단어가 어떻게 임베딩되는지에 대한 구체적인 내용은 데이터를 사용하여 학습됩니다. 각 단어에 어떤 일이 일어나는지 알려주는 열을 가진 이 임베딩 행렬은 우리 모델의 첫 번째 가중치 더미입니다. GPT-3 숫자를 사용하면, 어휘 크기는 구체적으로 50,257개이며, 다시 말하지만 기술적으로 이것은 단어 자체가 아니라 토큰으로 구성됩니다. 임베딩 차원은 12,288이고, 이 둘을 곱하면 약 6억 1,700만 개의 가중치로 구성된다는 것을 알 수 있습니다. 이것을 현재까지의 집계에 추가해 봅시다. 끝까지 갔을 때 총 1,750억 개까지 세어야 한다는 것을 기억하면서요.


Embeddings beyond words (단어를 넘어서는 임베딩) (18:25)

트랜스포머의 경우, 이 임베딩 공간의 벡터들을 단순히 개별 단어를 나타내는 것으로만 생각해서는 안 됩니다. 한 가지 이유는, 나중에 이야기하겠지만, 그것들이 단어의 위치 정보도 인코딩하기 때문입니다. 하지만 더 중요한 것은, 그것들이 문맥을 빨아들이는 능력을 가지고 있다고 생각해야 한다는 것입니다. 예를 들어, 'king(왕)'이라는 단어의 임베딩으로 시작했던 벡터가 이 네트워크의 여러 블록에 의해 점진적으로 이리저리 당겨져서, 끝에 가서는 그가 스코틀랜드에 살았던 왕이었고, 이전 왕을 살해한 후 왕위에 올랐으며, 셰익스피어식 언어로 묘사되고 있다는 것을 어떻게든 인코딩하는 훨씬 더 구체적이고 미묘한 방향을 가리키게 될 수 있습니다.

주어진 단어에 대한 여러분 자신의 이해를 생각해 보세요. 그 단어의 의미는 분명히 주변 환경에 의해 정보를 얻으며, 때로는 먼 거리의 문맥을 포함하기도 합니다. 따라서 다음에 올 단어를 예측할 수 있는 모델을 구성할 때, 목표는 어떻게든 모델이 문맥을 효율적으로 통합할 수 있는 능력을 부여하는 것입니다.

분명히 해두자면, 가장 첫 단계에서 입력 텍스트를 기반으로 벡터 배열을 만들 때, 그 각각은 단순히 임베딩 행렬에서 뽑아온 것입니다. 따라서 처음에는 각각이 주변의 입력 없이 단일 단어의 의미만을 인코딩할 수 있습니다. 하지만 여러분은 이 네트워크가 흘러가는 주된 목표가, 그 벡터들 각각이 단순한 개별 단어가 나타낼 수 있는 것보다 훨씬 더 풍부하고 구체적인 의미를 빨아들일 수 있게 하는 것이라고 생각해야 합니다.

네트워크는 한 번에 고정된 수의 벡터만 처리할 수 있는데, 이를 컨텍스트 크기(context size)라고 합니다. GPT-3는 2048의 컨텍스트 크기로 훈련되었으므로, 네트워크를 통해 흐르는 데이터는 항상 2048개의 열을 가진 배열처럼 보이며, 각 열은 12,000차원입니다. 이 컨텍스트 크기는 트랜스포머가 다음 단어를 예측할 때 통합할 수 있는 텍스트의 양을 제한합니다. 이것이 바로 초기 버전의 ChatGPT와 같은 특정 챗봇과 긴 대화를 할 때, 대화를 너무 오래 이어가면 봇이 대화의 맥을 놓치는 듯한 느낌을 주었던 이유입니다.


Unembedding (언임베딩) (20:22)

어텐션의 세부 사항은 적절한 때에 다룰 것이지만, 잠시 건너뛰고 맨 마지막에 어떤 일이 일어나는지에 대해 잠시 이야기하고 싶습니다. 기억하세요, 원하는 출력은 다음에 올 수 있는 모든 토큰에 대한 확률 분포입니다. 예를 들어, 맨 마지막 단어가 'Professor(교수)'이고, 문맥에 'Harry Potter(해리 포터)' 같은 단어가 포함되어 있고, 바로 앞에 'least favorite teacher(가장 싫어하는 선생님)'라는 말이 보인다면, 그리고 토큰이 그냥 완전한 단어처럼 보인다고 제가 가정하는 것을 너그러이 봐주신다면, 해리 포터에 대한 지식을 쌓은 잘 훈련된 네트워크는 아마도 'Snape(스네이프)'라는 단어에 높은 숫자를 할당할 것입니다.

이것은 두 가지 다른 단계를 포함합니다. 첫 번째는 그 문맥의 맨 마지막 벡터를 어휘집에 있는 각 토큰에 하나씩, 5만 개의 값 목록으로 매핑하는 다른 행렬을 사용하는 것입니다. 그런 다음 이것을 확률 분포로 정규화하는 함수가 있는데, 소프트맥스(softmax)라고 불리며 잠시 후에 더 자세히 이야기할 것입니다. 하지만 그 전에, 예측을 하기 위해 이 마지막 임베딩만 사용하는 것이 약간 이상하게 보일 수 있습니다. 마지막 단계에서 수천 개의 다른 벡터들이 각자 풍부한 문맥적 의미를 가진 채로 그 레이어에 그냥 앉아 있는데도 말이죠. 이것은 훈련 과정에서, 최종 레이어의 각 벡터를 사용하여 그 바로 다음에 올 것을 동시에 예측하게 하면 훨씬 더 효율적이라는 사실과 관련이 있습니다. 나중에 훈련에 대해 더 할 말이 많지만, 지금은 그냥 그것을 언급하고 싶습니다.

이 행렬은 언임베딩 행렬(Unembedding matrix)이라고 불리며 우리는 WU​라는 라벨을 붙입니다. 다시 말하지만, 우리가 보는 모든 가중치 행렬처럼, 그 항목들은 무작위로 시작하지만 훈련 과정에서 학습됩니다. 총 매개변수 수를 계속 기록해 보면, 이 언임베딩 행렬은 어휘집의 각 단어에 대해 하나의 행을 가지며, 각 행은 임베딩 차원과 동일한 수의 요소를 가집니다. 이것은 임베딩 행렬과 매우 유사하며, 순서만 바뀐 것입니다. 그래서 네트워크에 또 다른 6억 1,700만 개의 매개변수를 추가하게 되며, 현재까지의 집계는 10억을 약간 넘는 수준으로, 우리가 최종적으로 도달할 1,750억 개에 비하면 작지만 결코 미미하지는 않은 부분입니다.


Softmax with temperature (온도(Temperature)를 사용한 소프트맥스) (22:22)

이번 챕터의 마지막 미니 레슨으로, 이 소프트맥스(softmax) 함수에 대해 좀 더 이야기하고 싶습니다. 왜냐하면 어텐션 블록에 대해 깊이 들어갈 때 다시 한번 등장하기 때문입니다. 아이디어는, 만약 숫자 시퀀스가 확률 분포처럼 작동하게 하고 싶다면, 예를 들어 가능한 모든 다음 단어에 대한 분포처럼 말이죠, 각 값은 0과 1 사이여야 하고, 또한 모든 값의 합이 1이 되어야 한다는 것입니다. 하지만 여러분이 하는 모든 일이 행렬-벡터 곱셈처럼 보이는 딥러닝 게임을 하고 있다면, 기본적으로 얻게 되는 출력값들은 전혀 이 규칙을 따르지 않습니다. 값들은 종종 음수이거나 1보다 훨씬 크고, 거의 확실하게 합계가 1이 되지 않습니다.

소프트맥스는 임의의 숫자 목록을 유효한 분포로 바꾸는 표준적인 방법으로, 가장 큰 값들이 1에 가장 가깝게 되고 작은 값들은 0에 매우 가깝게 되도록 만듭니다. 사실 이것만 아셔도 충분합니다. 하지만 궁금하시다면, 작동 방식은 먼저 각 숫자를 e의 거듭제곱으로 만드는 것입니다. 그러면 이제 양수 값들의 목록을 갖게 되죠. 그런 다음 그 양수 값들의 합계를 구해서 각 항목을 그 합계로 나누면, 합이 1이 되는 목록으로 정규화됩니다. 만약 입력값 중 하나가 나머지보다 의미 있게 크다면, 출력에서는 해당하는 항이 분포를 지배하게 되어, 만약 거기서 샘플링한다면 거의 확실하게 최댓값을 내는 입력을 고르게 될 것입니다. 하지만 다른 값들이 비슷하게 클 때 그 값들도 분포에서 의미 있는 가중치를 얻게 되고, 입력을 연속적으로 변화시킴에 따라 모든 것이 연속적으로 변한다는 의미에서, 그냥 최댓값만 고르는 것보다는 더 부드럽습니다(softer).

ChatGPT가 이 분포를 사용해 다음 단어를 생성할 때와 같은 몇몇 상황에서는, 지수의 분모에 상수 T를 넣어 이 함수에 약간의 재미를 더할 여지가 있습니다. 우리는 이것을 온도(temperature)라고 부르는데, 특정 열역학 방정식에서 온도의 역할과 희미하게 닮았기 때문입니다. 그 효과는 T가 클수록 더 낮은 값들에 더 많은 가중치를 부여하게 되어 분포가 좀 더 균일해지고, T가 작을수록 더 큰 값들이 더 공격적으로 지배하게 됩니다. 극단적으로 T를 0으로 설정하면 모든 가중치가 최댓값으로 쏠리게 됩니다.

예를 들어, 제가 GPT-3에게 "옛날 옛적에 A가 살았어요(once upon a time there was A)"라는 시드 텍스트로 이야기를 생성하게 할 건데, 각각 다른 온도를 사용할 겁니다. 온도 0은 항상 가장 예측 가능한 단어를 선택한다는 의미이며, 그 결과는 진부한 '골디락스'의 파생물 같은 것이 됩니다. 더 높은 온도는 덜 가능성 있는 단어를 선택할 기회를 주지만, 위험이 따릅니다. 이 경우, 이야기는 한국 출신의 젊은 웹 아티스트에 대한 것으로 더 독창적으로 시작하지만, 금방 횡설수설로 변질됩니다.

기술적으로 말하면, API는 실제로 2보다 큰 온도를 선택하게 해주지 않습니다. 여기에는 수학적인 이유가 없으며, 단지 그들의 도구가 너무 터무니없는 것을 생성하는 것으로 보이는 것을 막기 위해 부과된 임의의 제약일 뿐입니다. 그래서 궁금하시다면, 이 애니메이션이 실제로 작동하는 방식은 GPT-3가 생성하는 가장 확률 높은 다음 토큰 20개를 가져와서(이것이 그들이 제공하는 최댓값인 것 같습니다), 그 확률들을 1/5의 지수를 기반으로 조정하는 것입니다.

또 다른 전문 용어로서, 이 함수의 출력 구성요소를 확률이라고 부르는 것과 같은 방식으로, 사람들은 종종 그 입력값들을 로짓(logit)이라고 부릅니다. (어떤 사람은 '로짓'이라고 하고 어떤 사람은 '로자잇'이라고 하는데, 저는 '로짓'이라고 하겠습니다.) 예를 들어, 어떤 텍스트를 입력하면 이 모든 단어 임베딩이 네트워크를 통해 흐르고, 언임베딩 행렬과의 최종 곱셈을 수행하게 되는데, 머신러닝 분야 사람들은 그 정규화되지 않은 원시 출력의 구성요소들을 다음 단어 예측을 위한 로짓이라고 부를 것입니다.


Up next (다음 내용) (26:03)

이번 챕터의 주된 목표 중 상당 부분은 가라테 키드(Karate Kid)의 'wax-on-wax-off(차에 왁스를 칠하고 닦아내기)' 방식처럼, 어텐션 메커니즘을 이해하기 위한 기초를 닦는 것이었습니다. 보시다시피, 단어 임베딩, 소프트맥스, 내적이 어떻게 유사성을 측정하는지에 대한 강한 직관이 있고, 또한 대부분의 계산이 조정 가능한 매개변수로 가득 찬 행렬과의 행렬 곱셈처럼 보여야 한다는 기본 전제를 이해하고 있다면, 현대 AI 붐 전체의 초석이라 할 수 있는 이 어텐션 메커니즘을 이해하는 것이 비교적 순조로울 것입니다. 그러니, 다음 챕터에서 저와 함께해 주세요.

제가 이 영상을 게시하는 지금, 다음 챕터의 초안이 Patreon 후원자분들이 검토하실 수 있도록 공개되어 있습니다. 최종 버전은 1~2주 안에 공개될 예정이며, 보통 그 검토를 바탕으로 제가 얼마나 수정하느냐에 따라 일정이 달라집니다. 그동안 어텐션에 대해 깊이 파고들고 싶으시거나 채널에 약간의 도움을 주고 싶으시다면, 그곳에 준비되어 있습니다.