
LLM은 사실을 어떻게 저장할까 | Deep Learning Chapter 7
요약
LLM이 특정 사실을 모델 내부의 파라미터에 어떻게 저장하는지 기계론적 관점에서 탐구합니다. 특히 Google DeepMind의 연구를 바탕으로 MLP(Multi-Layer Perceptrons)가 사실 저장에 핵심적인 역할을 한다는 점을 다룹니다.
핵심 포인트
- LLM은 수천억 개의 파라미터를 통해 방대한 사실을 암기함
- 사실 저장은 주로 MLP(다층 퍼셉트론) 블록에서 일어나는 것으로 추정됨
- 트랜스포머 아키텍처 내 어텐션과 MLP의 역할 차이 분석
- 특정 인물과 스포츠 매칭 사례를 통한 사실 저장 메커니즘 설명
비디오: LLM은 사실을 어떻게 저장할까 | Deep Learning Chapter 7
채널: 3Blue1Brown
길이: 22분 42초
출처: 자막 (수동, 영문)
대규모 언어 모델 (LLM)에 "마이클 조던은 [ ] 종목의 스포츠를 한다"라는 문구를 입력하고 다음에 올 말을 예측하게 했을 때, 모델이 '농구'라고 정확히 예측한다면, 이는 모델의 수천억 개 파라미터 (parameters) 어딘가에 특정 인물과 그가 하는 특정 스포츠에 대한 지식이 내재되어 있음을 시사합니다. 그리고 일반적으로 이러한 모델을 다뤄본 사람이라면 모델이 엄청나게 많은 사실을 암기하고 있다는 점을 분명히 느낄 것입니다. 따라서 여러분이 던질 수 있는 합리적인 질문은, 그것이 정확히 어떻게 작동하느냐는 것입니다.
그리고 그 사실들은 어디에 저장되어 있을까요? 지난 12월, Google DeepMind의 몇몇 연구자들이 이 질문에 대한 연구 내용을 게시했으며, 그들은 운동선수를 해당 스포츠와 매칭하는 이 구체적인 사례를 사용했습니다. 사실이 어떻게 저장되는지에 대한 완전한 기계론적 이해 (mechanistic understanding)는 여전히 미해결 상태로 남아 있지만, 그들은 몇 가지 흥미로운 부분적인 결과들을 얻었습니다. 여기에는 사실들이 네트워크의 특정 부분, 즉 화려하게는 다층 퍼셉트론 (multi-layer perceptrons) 또는 줄여서 MLP라고 불리는 곳에 저장되어 있는 것 같다는 매우 일반적이고 높은 수준의 결론이 포함되어 있습니다.
지난 몇 개의 장에서 여러분과 저는 대규모 언어 모델 (LLM)의 근간이 되는 아키텍처이자 많은 현대 AI의 기반이 되는 트랜스포머 (transformers)의 세부 사항을 파헤쳐 왔습니다. 가장 최근 장에서는 어텐션 (Attention)이라고 불리는 부분에 집중했습니다. 이제 다음 단계로 여러분과 저는 네트워크의 다른 큰 부분을 구성하는 이 다층 퍼셉트론 (MLPs) 내부에서 어떤 일이 일어나는지 세부적으로 살펴볼 것입니다. 이곳의 계산은 특히 어텐션 (attention)과 비교했을 때 실제로 상대적으로 단순합니다.
본질적으로 이는 중간에 단순한 무언가가 끼어 있는 한 쌍의 행렬 곱셈 (matrix multiplications)으로 귀결됩니다. 하지만 이러한 계산이 무엇을 하고 있는지 해석하는 것은 매우 어렵습니다. 여기서 우리의 주요 목표는 계산 과정을 단계별로 짚어가며 기억에 남도록 만드는 것이지만, 이러한 블록 중 하나가 적어도 원칙적으로 어떻게 구체적인 사실을 저장할 수 있는지에 대한 특정 사례를 보여주는 맥락에서 이를 진행하고자 합니다. 구체적으로, '마이클 조던(Michael Jordan)은 농구를 한다'라는 사실을 저장하는 사례를 다룰 것입니다. 여기서 설명 방식은 DeepMind의 연구원 중 한 명인 Neil Nanda와 나누었던 대화에서 영감을 얻었다는 점을 언급해 둡니다.
대부분의 경우, 여러분이 지난 두 장을 시청했거나 트랜스포머 (transformer)가 무엇인지에 대한 기본적인 감각을 가지고 있다고 가정하겠습니다. 하지만 복습은 언제나 도움이 되므로, 전체적인 흐름을 빠르게 상기시켜 드리겠습니다. 당신과 나는 텍스트 조각을 입력받아 다음에 올 내용을 예측하도록 훈련된 모델을 공부해 왔습니다. 입력된 텍스트는 먼저 일련의 토큰 (tokens)으로 분해되는데, 이는 일반적으로 단어 또는 단어의 작은 조각인 작은 덩어리들을 의미하며, 각 토큰은 고차원 벡터 (high-dimensional vector), 즉 긴 숫자 리스트와 연관됩니다.
이 벡터 시퀀스는 그런 다음 두 가지 종류의 연산을 반복해서 통과합니다. 벡터들이 서로 정보를 전달할 수 있게 해주는 어텐션 (attention), 그리고 오늘 우리가 깊이 파고들 부분인 다층 퍼셉트론 (multilayer perceptrons)입니다. 또한 그 사이에는 특정 정규화 (normalization) 단계가 있습니다. 벡터 시퀀스가 이 두 블록의 수많은 반복 과정을 거치고 나면, 최종적으로 각 벡터가 문맥(입력된 다른 모든 단어들)과 훈련을 통해 모델 가중치 (model weights)에 구워진 일반적인 지식 모두로부터 충분한 정보를 흡수하여, 다음에 올 토큰이 무엇인지 예측하는 데 사용될 수 있기를 기대합니다.
제가 여러분의 머릿속에 담아두길 바라는 핵심 아이디어 중 하나는, 이 모든 벡터들이 매우, 매우 고차원적인 공간 (high-dimensional space)에 존재한다는 것입니다. 그리고 그 공간을 생각할 때, 서로 다른 방향 (directions)이 서로 다른 종류의 의미를 인코딩 (encode)할 수 있습니다. 그래서 제가 자주 인용하는 아주 고전적인 예시가 있는데, 만약 'woman'의 임베딩 (embedding)을 보고 거기서 'man'의 임베딩을 뺀 다음, 그 작은 차이만큼을 'uncle'과 같은 다른 남성적인 명사에 더한다면, 여러분은 그에 대응하는 여성 명사와 매우, 매우 가까운 지점에 도달하게 된다는 것입니다.
이런 의미에서, 이 특정한 방향은 성별 (gender) 정보를 인코딩합니다. 아이디어는 이 초고차원 공간 내의 다른 많은 구별되는 방향들이 모델이 표현하고자 하는 다른 특징 (features)들에 대응할 수 있다는 것입니다. 하지만 트랜스포머 (transformer)에서 이 벡터들은 단순히 단일 단어의 의미만을 인코딩하는 것은 아닙니다. 벡터들이 네트워크를 통해 흐르면서, 주변의 모든 문맥 (context)과 모델의 지식에 기반하여 훨씬 더 풍부한 의미를 흡수합니다. 궁극적으로, 각 벡터는 다음에 올 것이 무엇인지 예측하기에 충분해야 하므로, 단일 단어의 의미를 훨씬, 훨씬 뛰어넘는 무언가를 인코딩해야 합니다.
우리는 이미 어텐션 블록 (attention blocks)이 어떻게 문맥을 통합할 수 있게 하는지 살펴보았습니다. 하지만 모델 파라미터 (parameters)의 대다수는 실제로 MLP 블록 내에 존재하며, 이들이 무엇을 하고 있는지에 대한 한 가지 생각은 사실을 저장하기 위한 추가적인 용량 (capacity)을 제공한다는 것입니다. 앞서 말씀드렸듯이, 이번 레슨은 'Michael Jordan은 농구를 한다'라는 사실을 정확히 어떻게 저장할 수 있는지에 대한 구체적인 토이 예시 (toy example)에 집중할 것입니다. 이제, 이 토이 예시를 위해서는 여러분과 제가 그 고차원 공간에 대해 몇 가지 가정을 해야 합니다.
첫째, 우리는 하나의 방향이 'Michael'이라는 이름(first name)의 개념을 나타내고, 그와 거의 수직인 또 다른 방향은 'Jordan'이라는 성(last name)의 개념을 나타내며, 세 번째 방향은 '농구(basketball)'의 개념을 나타낸다고 가정할 것입니다. 구체적으로 제가 의미하는 바는, 만약 여러분이 네트워크를 살펴보고 처리 중인 벡터 중 하나를 뽑아냈을 때, 그 벡터와 'Michael'이라는 이름 방향 사이의 내적(dot product) 값이 1이라면, 그 벡터가 해당 이름의 개념을 가진 사람이라는 아이디어를 인코딩(encoding)하고 있다는 것을 의미합니다.
그렇지 않다면, 그 내적 값은 0 또는 음수가 될 것이며, 이는 해당 벡터가 그 방향과 실제로 정렬되지 않았음을 의미합니다. 그리고 단순화를 위해, 만약 그 내적 값이 1보다 크다면 그것이 무엇을 의미할 것인가라는 매우 합리적인 질문은 완전히 무시하도록 합시다. 마찬가지로, 다른 방향들과의 내적 값은 해당 벡터가 'Jordan'이라는 성이나 '농구'를 나타내는지 여부를 알려줄 것입니다. 따라서 어떤 벡터가 'Michael Jordan'이라는 전체 이름을 나타내고자 한다면, 이 두 방향 모두와의 내적 값이 1이어야 합니다.
'Michael Jordan'이라는 텍스트는 두 개의 서로 다른 토큰(token)에 걸쳐 있으므로, 이는 또한 이전의 어텐션 블록(attention block)이 이 두 벡터 중 두 번째 벡터로 정보를 성공적으로 전달하여, 두 이름 모두를 인코딩할 수 있도록 보장해야 한다는 가정이 필요함을 의미합니다. 이러한 모든 가정을 바탕으로, 이제 본격적으로 수업의 핵심 내용으로 들어가 보겠습니다. 다층 퍼셉트론(multilayer perceptron) 내부에서는 어떤 일이 일어날까요? 블록으로 흘러 들어오는 이 벡터들의 시퀀스를 생각해 볼 수 있는데, 기억하세요, 각 벡터는 원래 입력 텍스트의 토큰 중 하나와 연관되어 있었습니다.
그 시퀀스로부터 나오는 각각의 개별 벡터는 일련의 짧은 연산 과정을 거치게 되는데, 잠시 후에 이 과정을 자세히 살펴보겠습니다. 그리고 마지막에는 동일한 차원을 가진 또 다른 벡터를 얻게 됩니다. 그 다른 벡터는 처음에 흘러 들어왔던 원래의 벡터에 더해지며, 그 합계가 결과물로서 흘러나가게 됩니다. 이 연산 시퀀스는 입력의 모든 토큰과 연관된 시퀀스 내의 모든 벡터에 적용되는 것이며, 이 모든 과정은 병렬적으로(in parallel) 일어납니다. 특히, 이 단계에서 벡터들은 서로 대화하지 않으며, 각자 자기만의 일을 수행하는 식입니다.
그리고 여러분과 저에게 이것은 사실 훨씬 더 단순하게 느껴지는데, 왜냐하면 이 블록을 통과할 때 단 하나의 벡터에 어떤 일이 일어나는지만 이해한다면, 사실상 모든 벡터에 어떤 일이 일어나는지를 이해하는 것과 같기 때문입니다. 제가 이 블록이 'Michael Jordan은 농구를 한다'는 사실을 인코딩(encode)할 것이라고 말할 때, 제 의미는 만약 이름 'Michael'과 성 'Jordan'을 인코딩하는 벡터가 흘러 들어온다면, 이 계산 시퀀스가 'basketball'이라는 방향을 포함하는 무언가를 생성할 것이고, 그것이 해당 위치의 벡터에 더해질 것이라는 뜻입니다.
이 프로세스의 첫 번째 단계는 해당 벡터를 매우 큰 행렬(matrix)과 곱하는 것처럼 보입니다. 놀라운 일은 아니죠, 이것은 딥러닝(deep learning)이니까요. 그리고 우리가 지금까지 봐왔던 다른 모든 행렬과 마찬가지로, 이 행렬은 데이터로부터 학습된 모델 파라미터(model parameters)로 채워져 있습니다. 여러분은 이를 모델의 동작을 결정하기 위해 미세하게 조정되고 튜닝되는 수많은 노브(knobs)와 다이얼(dials)의 집합으로 생각할 수 있습니다. 이제 행렬 곱셈(matrix multiplication)을 생각하는 좋은 방법 중 하나는, 그 행렬의 각 행을 하나의 벡터로 상상하고, 그 행들과 처리 중인 벡터 사이의 수많은 내적(dot products)을 구하는 것입니다. 여기서 처리 중인 벡터를 임베딩(embedding)의 약자인 E로 표시하겠습니다.
예를 들어, 만약 첫 번째 행이 우리가 존재한다고 가정하는 'Michael'이라는 이름의 방향과 우연히 일치한다고 가정해 봅시다. 그렇다면 이 출력의 첫 번째 성분, 즉 여기 있는 내적(dot product) 값은 해당 벡터가 'Michael'이라는 이름을 인코딩(encode)하고 있다면 1이 될 것이고, 그렇지 않다면 0 또는 음수가 될 것입니다. 훨씬 더 재미있는 점은, 만약 그 첫 번째 행이 'Michael'이라는 이름과 'Jordan'이라는 성의 방향을 더한 것이라면 어떤 의미가 될지 잠시 생각해 보는 것입니다. 단순화를 위해 이를 M 더하기 J(M + J)라고 적어 보겠습니다.
그다음, 이 임베딩(embedding) E와 내적을 구하면 식이 아주 깔끔하게 분배되는데, 즉 M ⋅ E 더하기 J ⋅ E 형태가 됩니다. 여기서 주목할 점은, 만약 해당 벡터가 'Michael Jordan'이라는 전체 이름을 인코딩하고 있다면 최종 값이 2가 될 것이고, 그렇지 않다면 1 또는 1보다 작은 값이 될 것이라는 점입니다. 그리고 이것은 이 행렬의 단 한 행일 뿐입니다. 다른 모든 행은 병렬적으로 다른 종류의 질문을 던지거나, 처리 중인 벡터의 다른 유형의 특징들을 탐색(probing)하는 것으로 생각할 수 있습니다. 매우 빈번하게 이 단계에서는 데이터로부터 학습된 모델 파라미터(model parameters)로 가득 찬 또 다른 벡터를 출력에 더하는 과정도 포함됩니다.
이 다른 벡터를 편향(bias)이라고 부릅니다. 우리의 예시를 위해, 이 편향의 첫 번째 성분 값이 -1이라고 상상해 보시기 바랍니다. 즉, 우리의 최종 출력은 해당 관련 내적 값에서 1을 뺀 형태가 됩니다. 여러분은 왜 제가 모델이 이것을 학습했다고 가정하라고 하는지 합리적으로 의문을 가질 수 있는데, 잠시 후에 벡터가 'Michael Jordan'이라는 전체 이름을 인코딩할 때만 양수이고, 그렇지 않으면 0 또는 음수가 되는 값을 갖는 것이 왜 매우 깔끔하고 유용한지 알게 될 것입니다.
이 행렬의 총 행(row)의 수, 즉 우리가 계속 추적해 온 GPT-3의 경우 질문의 수와 유사한 이 값은 50,000을 약간 밑돕니다. 사실, 이는 이 임베딩 공간 (embedding space) 차원 수의 정확히 4배입니다. 이는 설계상의 선택입니다. 더 늘릴 수도 있고 더 줄일 수도 있지만, 깔끔한 배수를 갖는 것이 하드웨어 친화적인 경향이 있습니다. 가중치 (weights)로 가득 찬 이 행렬이 우리를 더 높은 차원의 공간으로 매핑하므로, 이를 $W_{up}$이라는 약어로 표기하겠습니다.
우리가 처리 중인 벡터는 계속해서 $E$로 표기하고, 이 편향 (bias) 벡터는 $B_{up}$으로 표기하여 다시 다이어그램에 배치하겠습니다. 이 시점에서 발생하는 문제는 이 연산이 순수하게 선형적 (linear)이라는 것이지만, 언어는 매우 비선형적 (non-linear)인 과정이라는 점입니다. 만약 우리가 측정하는 항목이 'Michael plus Jordan'에 대해 높은 값을 가진다면, 개념적으로 관련이 없음에도 불구하고 'Michael plus Phelps'나 'Alexis plus Jordan'에 의해서도 필연적으로 어느 정도 활성화될 것입니다. 여러분이 진정으로 원하는 것은 전체 이름에 대한 단순한 '예' 또는 '아니오'입니다.
따라서 다음 단계는 이 거대한 중간 벡터 (intermediate vector)를 매우 단순한 비선형 함수 (non-linear function)에 통과시키는 것입니다. 흔히 쓰이는 선택지는 모든 음수 값을 0으로 매핑하고 모든 양수 값은 그대로 두는 함수입니다. 그리고 지나치게 화려한 이름을 붙이는 딥러닝 (deep learning)의 전통을 따라, 이 매우 단순한 함수는 흔히 정류 선형 유닛 (rectified linear unit), 줄여서 ReLU라고 불립니다. 그래프는 다음과 같습니다. 중간 벡터의 첫 번째 항목이 전체 이름이 'Michael Jordan'일 때만 1이고, 그렇지 않으면 0 또는 음수인 우리의 가상 예시를 들어보면, ReLU를 통과시킨 후에는 모든 0과 음수 값이 단순히 0으로 잘려나가(clipped) 매우 깔끔한 값을 얻게 됩니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 YouTube 3Blue1Brown (수학/ML)의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기