Feed Forward Network와 비선형 변환
Attention 다음에 남는 일
앞 장까지 우리는 Transformer가 문장을 어떻게 바라보는지 살펴보았습니다. 토큰은 임베딩 벡터가 되고, 위치 정보가 더해지며, Attention을 통해 문맥 속 다른 토큰들과 연결됩니다. 예를 들어 "그것은 달았다"라는 문장에서 "그것"이라는 토큰은 앞에 나온 "사과"를 강하게 참고할 수 있습니다. Attention은 이런 연결을 계산해 각 토큰 표현 안에 필요한 문맥 정보를 모아 줍니다.
그런데 여기서 한 가지 질문이 남습니다.
정보를 모은 다음에는 무엇을 할까요?
Attention이 "이 토큰은 저 토큰을 참고해야 해"라고 알려 주는 장치라면, 그다음에는 모아 온 정보를 바탕으로 각 토큰의 표현을 더 쓸모 있게 가공해야 합니다. 이 일을 맡는 구성 요소가 바로 Feed Forward Network, 줄여서 FFN입니다.
이 장의 핵심은 단순합니다. Attention이 정보를 모은다면, FFN은 모은 정보를 토큰별로 가공합니다.

Transformer Block의 두 박자
Transformer는 하나의 거대한 계산 덩어리처럼 보이지만, 안쪽을 들여다보면 비슷한 구조가 반복됩니다. GPT 계열 모델을 단순화해서 보면 여러 개의 Transformer Block이 층층이 쌓여 있고, 각 블록 안에는 크게 두 가지 핵심 장치가 들어 있습니다.
첫 번째는 지금까지 배운 Self-Attention입니다. Self-Attention은 문장 안의 토큰들이 서로를 참고하게 만듭니다. 어떤 토큰이 어떤 토큰을 얼마나 봐야 하는지 계산하고, 그 결과를 이용해 각 토큰의 표현을 업데이트합니다.
두 번째가 이번 장의 주인공인 Feed Forward Network입니다. FFN은 Attention을 통과한 각 토큰 벡터를 다시 한 번 변환합니다. 여기서 중요한 점은 FFN이 토큰 사이를 직접 섞지 않는다는 것입니다. 토큰 사이의 정보 교환은 주로 Attention이 담당합니다. FFN은 이미 섞여 들어온 정보를 각 토큰 자리에서 따로 가공합니다.
단순하게 표현하면 한 블록의 흐름은 다음과 같습니다.
입력 토큰 표현
↓
Self-Attention: 토큰들이 서로를 참고한다
↓
Feed Forward Network: 각 토큰 표현을 더 풍부하게 바꾼다
↓
다음 Transformer Block으로 전달실제 Transformer Block에는 여기에 LayerNorm과 Residual Connection이라는 중요한 장치가 함께 들어갑니다. 이 둘은 다음 장에서 자세히 살펴보겠습니다. 지금은 큰 흐름만 기억하면 됩니다. Transformer Block은 대체로 관계 보기 → 가공하기라는 두 박자를 반복합니다.
마치 회의와 비슷합니다. Attention은 회의 시간입니다. 각 참석자가 다른 사람의 말을 듣고, 누구의 의견을 참고할지 정합니다. FFN은 회의가 끝난 뒤 각자 자리로 돌아가 자신의 노트를 정리하는 시간입니다. 들은 내용을 그대로 두는 것이 아니라, 자기 역할에 맞게 다시 해석하고 정리합니다.
FFN은 토큰별 작은 가공 공장이다
문장이 모델 안으로 들어가면 보통 다음과 같은 행렬 형태로 표현됩니다.
[토큰 개수, 임베딩 차원]예를 들어 토큰이 5개이고 각 토큰이 4차원 벡터라면, 입력은 5행 4열짜리 표처럼 볼 수 있습니다. 각 행은 하나의 토큰이고, 각 열은 그 토큰을 설명하는 특징 값입니다.
Attention은 이 표에서 주로 행과 행 사이의 관계를 계산합니다. 첫 번째 토큰이 세 번째 토큰을 얼마나 참고할지, 네 번째 토큰이 두 번째 토큰을 얼마나 참고할지처럼 토큰들 사이의 연결을 다룹니다.
반면 FFN은 각 행을 따로 처리합니다. 첫 번째 토큰 벡터를 변환하고, 두 번째 토큰 벡터를 변환하고, 세 번째 토큰 벡터를 변환합니다. 모든 토큰에 같은 FFN이 적용되지만, 계산은 각 토큰 위치에서 독립적으로 일어납니다.
이것을 흔히 position-wise feed-forward network라고 부릅니다. 여기서 position-wise란 "각 위치마다 따로 적용된다"는 뜻입니다. 문장의 첫 번째 위치, 두 번째 위치, 세 번째 위치에 같은 변환기를 가져다 대는 셈입니다.
중요한 점은 FFN이 문맥을 모른다는 뜻이 아닙니다. FFN에 들어오는 토큰 벡터는 이미 Attention을 거친 상태입니다. 즉, 그 벡터 안에는 다른 토큰에서 가져온 정보가 섞여 있습니다. FFN은 그 섞인 정보를 토큰별로 다시 정리합니다.
예를 들어 "그것은 달았다"에서 "그것"의 벡터가 Attention을 통해 "사과" 정보를 많이 가져왔다고 해 봅시다. 그러면 FFN은 그 벡터를 보며 "이 토큰은 앞의 명사를 가리키는 대명사이고, 문맥상 과일과 연결되어 있으며, 뒤의 '달았다'와도 의미적으로 잘 맞는다"는 식의 더 정교한 내부 표현으로 바꿀 수 있습니다. 물론 모델이 사람처럼 이런 문장을 머릿속으로 말하는 것은 아닙니다. 실제로는 수많은 숫자 변환이 일어납니다. 하지만 그 숫자 변환의 효과를 사람이 이해하기 쉽게 풀면 이렇게 설명할 수 있습니다.
기본 구조: 넓혔다가, 꺾고, 다시 줄인다
FFN의 구조는 의외로 단순합니다. 보통 두 개의 선형층 사이에 활성화 함수가 들어갑니다.
입력 벡터
↓
첫 번째 선형층
↓
활성화 함수
↓
두 번째 선형층
↓
출력 벡터수식으로 쓰면 다음과 비슷합니다.
y = W₂ · activation(W₁ · x + b₁) + b₂여기서 x는 하나의 토큰 벡터입니다. W₁과 W₂는 학습되는 가중치 행렬이고, b₁과 b₂는 bias라고 부르는 보정값입니다. activation은 ReLU나 GELU 같은 활성화 함수입니다.
처음 이 구조를 보면 너무 간단해서 의아할 수 있습니다. "토큰 사이 관계를 계산하는 Attention은 복잡해 보였는데, FFN은 그냥 선형층 두 개 아닌가?"라는 생각이 들 수 있습니다. 하지만 이 단순한 구조가 Transformer의 표현력을 크게 끌어올립니다.
첫 번째 선형층은 입력 벡터를 더 큰 공간으로 펼칩니다. 두 번째 선형층은 펼쳐진 정보를 다시 원래 차원으로 압축합니다. 중간의 활성화 함수는 이 과정에 비선형성을 넣어 줍니다. 그래서 FFN은 단순한 크기 변환기가 아니라, 토큰 표현을 새로운 방식으로 구부리고 재조합하는 장치가 됩니다.
비유하자면 첫 번째 선형층은 재료를 작업대 위에 넓게 펼치는 단계입니다. 활성화 함수는 어떤 재료는 살리고 어떤 재료는 약하게 만들며, 두 번째 선형층은 그렇게 손질된 재료를 다시 하나의 요리로 담아내는 단계입니다.
선형층은 무엇을 하는가
선형층은 벡터를 다른 벡터로 바꾸는 가장 기본적인 신경망 연산입니다. 입력 벡터의 값들에 가중치를 곱하고 더해서 새로운 값을 만듭니다. 예를 들어 어떤 토큰 벡터가 768개의 숫자로 되어 있다면, 선형층은 이 768개 숫자를 조합해 새로운 숫자 묶음을 만듭니다.
선형층의 힘은 "조합"에 있습니다. 어떤 차원은 문법적인 단서와 관련이 있을 수 있고, 어떤 차원은 의미적인 단서와 관련이 있을 수 있으며, 어떤 차원은 문맥에서의 역할과 관련이 있을 수 있습니다. 선형층은 이 값들을 서로 다른 비율로 섞어 새로운 특징을 만들어 냅니다.
예를 들어 한 토큰 벡터 안에 다음과 같은 정보가 희미하게 들어 있다고 상상해 봅시다. 이 토큰이 명사인지, 앞 문장의 어떤 대상을 가리키는지, 긍정적인 분위기와 관련되는지, 뒤에 올 말과 어떤 관계를 맺는지 같은 정보입니다. 선형층은 이런 여러 신호를 조합해 더 유용한 내부 특징을 만들 수 있습니다.
하지만 선형층만 여러 번 쌓는다고 모든 문제가 해결되지는 않습니다. 선형 변환 뒤에 또 선형 변환을 붙이면, 전체적으로는 여전히 하나의 선형 변환으로 합쳐질 수 있기 때문입니다.
조금 더 쉽게 말해 보겠습니다. 종이를 한 방향으로 밀고, 다시 다른 방향으로 밀었다고 해도 결국 "한 번에 이렇게 밀었다"고 표현할 수 있습니다. 선형 변환도 비슷합니다. 중간에 특별한 꺾임이 없다면 여러 번 적용해도 하나의 선형 변환과 크게 다르지 않습니다.
그래서 필요한 것이 활성화 함수입니다.
활성화 함수는 왜 필요한가
활성화 함수는 신경망에 비선형성을 넣어 주는 장치입니다. 비선형성이라는 말이 조금 딱딱하게 들리지만, 핵심은 간단합니다. 입력과 출력의 관계가 곧은 직선 하나로만 설명되지 않게 만드는 것입니다.
현실의 언어는 직선처럼 단순하지 않습니다. 같은 단어라도 문맥에 따라 역할이 달라지고, 작은 표현 차이가 전체 의미를 바꾸기도 합니다. "좋다"라는 단어도 진심 어린 칭찬일 수 있고, 비꼬는 말일 수도 있습니다. "안 나쁘다"는 단순히 "나쁘다"의 반대가 아니라 미묘한 긍정일 수 있습니다. 이런 복잡한 패턴을 다루려면 모델 안에도 구부러진 변환이 필요합니다.
ReLU는 대표적인 활성화 함수입니다. 입력이 0보다 작으면 0으로 만들고, 0보다 크면 그대로 통과시킵니다. 아주 단순하지만 강력합니다. 어떤 신호는 끄고, 어떤 신호는 살리는 스위치처럼 작동합니다.
GELU도 Transformer 계열에서 자주 사용되는 활성화 함수입니다. ReLU가 비교적 딱 잘라 켜고 끄는 느낌이라면, GELU는 더 부드럽게 신호를 조절합니다. 작은 값이라고 무조건 버리기보다 확률적인 감각으로 완만하게 줄이거나 통과시키는 것에 가깝습니다. 그래서 언어처럼 미묘한 신호가 많은 데이터에서 자연스럽게 잘 맞는 경우가 많습니다.
중요한 것은 특정 함수 이름을 외우는 것이 아닙니다. 핵심은 활성화 함수가 선형 변환 사이에 들어가 모델이 더 복잡한 패턴을 표현할 수 있게 만든다는 점입니다. 선형층이 재료를 섞는다면, 활성화 함수는 그 재료를 자르고 접고 구부리는 역할을 합니다.
왜 중간 차원을 더 크게 만들까
Transformer의 FFN은 보통 입력 차원보다 훨씬 큰 중간 차원을 사용합니다. 예를 들어 토큰 벡터의 차원이 768이라면, FFN 내부에서는 이를 3072차원 정도로 넓혔다가 다시 768차원으로 줄일 수 있습니다. 꼭 항상 4배라는 법칙이 있는 것은 아니지만, 이런 식으로 중간 공간을 크게 잡는 설계가 널리 쓰입니다.
왜 굳이 넓혔다가 다시 줄일까요? 그냥 768차원에서 768차원으로 변환하면 더 간단하지 않을까요?
중간 차원을 키우는 이유는 더 많은 특징을 잠시 펼쳐 놓기 위해서입니다. 입력 벡터 안에는 여러 정보가 압축되어 있습니다. 문법적 역할, 의미적 뉘앙스, 앞뒤 문맥에서 가져온 단서, 다음 토큰을 예측하는 데 필요한 힌트가 한 벡터 안에 섞여 있습니다. FFN은 첫 번째 선형층을 통해 이 압축된 정보를 더 넓은 공간으로 펼칩니다.
넓은 작업대가 있으면 재료를 더 잘 분리해 볼 수 있습니다. 좁은 책상 위에서는 종이, 노트북, 커피잔, 펜이 서로 겹쳐 보이지만, 넓은 책상 위에 올려 두면 각각의 위치와 역할이 더 분명해집니다. FFN의 hidden dimension, 즉 중간 차원도 비슷합니다. 더 큰 공간은 모델이 더 다양한 내부 특징을 만들 여유를 줍니다.
그다음 두 번째 선형층은 이 넓은 표현을 다시 원래 차원으로 압축합니다. 그냥 줄이는 것이 아니라, 필요한 특징을 골라 다음 블록이 쓰기 좋은 형태로 정리합니다. 이 과정에서 토큰 벡터는 이전보다 더 정교한 표현이 됩니다.
이 구조는 다음과 같이 볼 수 있습니다.
768차원 입력
↓
3072차원으로 확장
↓
활성화 함수로 비선형 변환
↓
768차원으로 압축숫자는 모델마다 다르지만, 아이디어는 같습니다. 잠시 넓게 펼친 뒤, 중요한 정보를 가공해 다시 담는다. 이것이 FFN의 핵심 동작입니다.
FFN은 파라미터를 많이 가진다
Transformer를 처음 배울 때는 Attention이 가장 화려해 보입니다. Query, Key, Value가 등장하고, Attention score를 계산하고, mask를 씌우고, 여러 head를 병렬로 돌립니다. 그래서 모델의 똑똑함이 대부분 Attention에서 나온다고 느끼기 쉽습니다.
하지만 실제 모델 안에서 FFN은 매우 큰 비중을 차지합니다. 특히 파라미터 수를 보면 FFN의 존재감이 뚜렷합니다.
간단히 계산해 보겠습니다. 입력 차원이 d_model이고 중간 차원이 d_ff라고 합시다. FFN에는 대략 두 개의 큰 가중치 행렬이 있습니다. 첫 번째는 d_model에서 d_ff로 가는 행렬이고, 두 번째는 d_ff에서 다시 d_model로 돌아오는 행렬입니다.
따라서 FFN의 주요 파라미터 수는 대략 다음과 같습니다.
d_model × d_ff + d_ff × d_model
= 2 × d_model × d_ff만약 d_model이 768이고 d_ff가 3072라면, 두 행렬의 파라미터 수만 약 470만 개입니다. 여기에 bias까지 더해집니다. 이것이 Transformer Block 하나에 들어가는 FFN의 크기입니다. 이런 블록이 여러 층 쌓이면 FFN이 전체 모델 파라미터에서 상당한 비중을 차지하게 됩니다.
물론 파라미터가 많다고 무조건 좋은 모델이 되는 것은 아닙니다. 하지만 충분한 데이터와 적절한 학습이 있다면, 더 많은 파라미터는 더 복잡한 패턴을 저장하고 표현할 수 있는 여지를 줍니다. FFN은 바로 이 지점에서 모델의 표현력에 크게 기여합니다.
Attention이 "어디를 볼 것인가"를 정한다면, FFN은 "본 것을 어떻게 해석하고 바꿀 것인가"를 담당합니다. Attention만 있고 FFN이 약하다면, 모델은 정보를 모으기는 하지만 그것을 충분히 가공하지 못합니다. 반대로 FFN만 있고 Attention이 없다면, 각 토큰이 서로의 정보를 제대로 가져오기 어렵습니다. Transformer가 강력한 이유는 이 둘이 반복적으로 협력하기 때문입니다.
토큰 표현은 층을 지날수록 달라진다
이제 Transformer Block이 여러 개 쌓인 모습을 상상해 봅시다. 첫 번째 블록의 Attention은 가까운 단어 관계나 간단한 문법 단서를 잡을 수 있습니다. 그 뒤의 FFN은 이 정보를 토큰별로 가공합니다. 두 번째 블록은 이미 한 번 가공된 표현을 받아 다시 Attention을 수행합니다. 더 풍부해진 표현을 바탕으로 더 복잡한 관계를 볼 수 있습니다. 그리고 다시 FFN이 그 결과를 가공합니다.
이 과정이 여러 층 반복되면서 토큰 벡터는 점점 달라집니다. 처음에는 단순히 특정 토큰의 의미와 위치에 가까운 표현이었지만, 층을 지날수록 문맥 속 역할이 담긴 표현으로 변합니다.
예를 들어 "은행에 갔다"라는 문장을 생각해 봅시다. "은행"은 돈을 맡기는 금융기관일 수도 있고, 강가의 둑을 뜻할 수도 있습니다. 한국어에서는 보통 "은행에 갔다"라고 하면 금융기관일 가능성이 높습니다. 하지만 더 긴 문맥에서 "강물이 불어나 은행에 갔다" 같은 표현이 나온다면 다른 의미로 해석될 수 있습니다.
Attention은 주변 문맥에서 어떤 단서를 가져올지 계산합니다. FFN은 그 단서가 섞인 토큰 표현을 다시 가공합니다. 여러 층을 거치면 "은행"이라는 토큰의 벡터는 단순한 단어 벡터가 아니라, 현재 문맥에서 어떤 의미로 쓰였는지에 가까운 표현이 됩니다.
LLM이 문맥에 맞는 답을 생성할 수 있는 이유도 이 반복 구조와 관련이 있습니다. 한 번의 Attention과 한 번의 FFN으로 모든 것을 해결하는 것이 아닙니다. 관계를 보고, 가공하고, 다시 관계를 보고, 다시 가공하는 과정이 깊게 쌓이면서 더 정교한 예측이 가능해집니다.
FFN은 기억 창고일까, 계산 장치일까
FFN을 설명할 때 흥미로운 관점이 하나 있습니다. FFN은 단순한 계산 장치이면서 동시에 모델이 학습한 패턴을 담고 있는 일종의 저장 공간처럼 볼 수도 있습니다.
물론 사람의 기억처럼 문장이나 사실이 그대로 저장되어 있다는 뜻은 아닙니다. "서울은 대한민국의 수도다"라는 문장이 어느 한 뉴런에 통째로 들어 있는 식은 아닙니다. 하지만 학습 과정에서 수많은 텍스트를 보며 형성된 통계적 패턴은 FFN의 가중치 안에 분산되어 담깁니다.
어떤 입력 벡터가 들어오면 FFN은 그 벡터가 가진 특징에 반응합니다. 특정 의미 조합, 문법 패턴, 문체적 단서, 추론에 필요한 중간 특징이 활성화될 수 있습니다. 그래서 FFN은 토큰 표현을 변환하는 동시에, 학습된 패턴을 꺼내 적용하는 역할도 합니다.
예를 들어 "파리는 프랑스의"라는 문맥이 들어왔을 때, 모델은 다음 토큰으로 "수도"나 관련 단어를 높은 확률로 둘 수 있습니다. 이때 Attention은 문맥의 관련 토큰을 모으고, FFN은 그 표현을 다음 예측에 유리한 방향으로 바꾸는 데 참여합니다. 모델 내부의 지식은 Attention에만 있지도, FFN에만 있지도 않습니다. 여러 구성 요소의 가중치와 계산 과정 전체에 흩어져 있습니다. 다만 FFN은 많은 파라미터를 가지고 있기 때문에 이런 패턴 표현에 특히 큰 역할을 합니다.
FFN을 작은 코드 감각으로 이해하기
나중에 우리는 Mini GPT를 직접 구현하면서 FFN에 해당하는 모듈을 코드로 만들게 됩니다. 지금은 코드를 완전히 이해할 필요는 없지만, 구조가 얼마나 단순한지 미리 감각만 잡아 보겠습니다.
PyTorch 스타일로 쓰면 FFN은 대략 다음과 비슷합니다.
ffn = Sequential(
Linear(d_model, d_ff),
GELU(),
Linear(d_ff, d_model)
)이 짧은 코드 안에 지금까지 설명한 흐름이 모두 들어 있습니다. 첫 번째 Linear는 토큰 벡터를 더 큰 차원으로 펼칩니다. GELU는 비선형성을 넣습니다. 두 번째 Linear는 다시 원래 차원으로 돌려보냅니다.
입력이 여러 토큰으로 이루어진 행렬이라면, 이 FFN은 각 토큰 위치에 같은 방식으로 적용됩니다. 예를 들어 입력이 [batch_size, sequence_length, d_model] 형태라면 출력도 [batch_size, sequence_length, d_model] 형태입니다. 중간에서 잠시 [batch_size, sequence_length, d_ff]로 커졌다가 다시 돌아올 뿐입니다.
이 점이 중요합니다. FFN을 지나도 토큰 개수는 바뀌지 않습니다. 각 토큰 벡터의 최종 차원도 유지됩니다. 그래야 다음 Transformer Block이 같은 형식의 입력을 받을 수 있습니다. Transformer는 같은 모양의 블록을 여러 번 쌓는 구조이기 때문에, 각 블록의 출력 형태가 다음 블록의 입력 형태와 맞아야 합니다.
Attention과 FFN을 함께 봐야 한다
이제 Attention과 FFN의 역할을 나란히 정리해 봅시다.
Attention은 문장 안의 토큰들이 서로 정보를 주고받게 합니다. "이 단어는 앞의 어떤 단어와 관련이 있는가?", "현재 위치에서 어떤 문맥을 참고해야 하는가?" 같은 문제를 다룹니다.
FFN은 그렇게 모인 정보를 각 토큰 자리에서 다시 변환합니다. "이 토큰 표현 안에 들어온 정보들을 어떤 특징으로 바꿀 것인가?", "다음 층이나 다음 토큰 예측에 더 유용한 형태로 어떻게 정리할 것인가?"를 담당합니다.
둘의 차이를 표로 표현하면 다음과 같습니다.
| 구성 요소 | 주된 역할 | 계산 관점 |
|---|---|---|
| Self-Attention | 토큰 사이의 관계를 계산하고 정보를 모은다 | 토큰 간 혼합 |
| Feed Forward Network | 각 토큰 표현을 더 풍부하게 가공한다 | 특징 차원 변환 |
| Transformer Block | Attention과 FFN을 반복해 표현을 깊게 만든다 | 관계 보기와 가공하기의 반복 |
이 둘은 경쟁 관계가 아닙니다. Transformer 안에서 Attention과 FFN은 서로 다른 일을 나눠 맡습니다. Attention 없는 FFN은 각 토큰을 고립된 상태로 처리하기 쉽고, FFN 없는 Attention은 모아 온 정보를 충분히 복잡하게 변환하기 어렵습니다. 둘이 함께 있을 때 토큰 표현은 문맥을 반영하면서도 점점 더 풍부해집니다.
비선형 변환이 만드는 깊이
LLM을 "다음 토큰 예측 모델"이라고 말하면, 어떤 사람은 그것을 너무 단순하게 받아들입니다. "그냥 다음 단어 맞히기라면 별거 아닌 것 아닌가?"라고 생각할 수 있습니다. 하지만 다음 토큰을 잘 예측하려면 문법, 의미, 상식, 문체, 맥락, 사용자의 의도까지 수많은 단서를 종합해야 합니다.
Transformer는 이 복잡한 일을 한 번에 처리하지 않습니다. 각 층에서 조금씩 표현을 바꿉니다. Attention은 필요한 정보를 끌어오고, FFN은 그 정보를 비선형적으로 가공합니다. 이 과정이 수십 층, 수백 층에 걸쳐 반복되면 단순한 토큰 ID에서 출발한 숫자 벡터가 놀라울 정도로 풍부한 문맥 표현으로 변합니다.
비선형 변환은 여기서 핵심적인 역할을 합니다. 직선적인 계산만으로는 언어의 복잡한 경계를 잘 표현하기 어렵습니다. 어떤 문맥에서는 같은 표현이 긍정이고, 다른 문맥에서는 부정일 수 있습니다. 어떤 질문에서는 짧은 답이 좋고, 다른 질문에서는 긴 설명이 필요합니다. 이런 복잡한 판단을 가능하게 하려면 모델 내부의 표현 공간이 여러 방향으로 접히고 나뉘고 다시 합쳐질 수 있어야 합니다.
FFN은 바로 그 접힘을 만들어 냅니다. 선형층으로 펼치고, 활성화 함수로 꺾고, 다시 선형층으로 압축합니다. 이 단순한 반복이 Transformer의 깊이를 만듭니다.
작은 GPT를 만들 때 다시 만날 FFN
이 책의 3부에서 우리는 작은 GPT를 직접 구현합니다. 그때 Transformer Block을 만들면서 Attention 모듈뿐 아니라 FFN 모듈도 직접 코드로 작성할 것입니다. 지금 이해한 내용은 그 실습의 바탕이 됩니다.
그때 기억해야 할 것은 복잡한 수식이 아닙니다. 다음 감각이면 충분합니다.
FFN은 각 토큰에 적용되는 작은 신경망입니다. 입력 차원을 더 큰 hidden dimension으로 넓혔다가 활성화 함수를 거쳐 다시 원래 차원으로 줄입니다. 이 과정에서 토큰 표현은 더 풍부해지고, 모델은 더 복잡한 언어 패턴을 표현할 수 있게 됩니다.
우리가 만드는 것은 ChatGPT급 모델이 아닙니다. 하지만 작은 GPT 안에도 같은 원리가 들어갑니다. Self-Attention으로 문맥 정보를 모으고, FFN으로 각 토큰 표현을 가공합니다. 규모는 작아도 구조의 핵심은 같습니다. 그래서 직접 만들어 보는 경험이 중요합니다. 작은 모델을 구현해 보면, 거대한 LLM도 완전히 다른 마법이 아니라 같은 원리를 크게 확장한 시스템이라는 사실이 보이기 시작합니다.
다음 장으로
이제 Transformer Block의 두 핵심 축을 배웠습니다. Attention은 토큰 사이의 관계를 보고, FFN은 각 토큰 표현을 비선형적으로 가공합니다. 그런데 실제 모델은 이 두 장치를 그냥 순서대로 붙여 놓기만 하지 않습니다. 깊은 신경망을 안정적으로 학습시키려면 중간중간 값의 흐름을 조절하고, 원래 정보를 잃지 않게 도와주는 장치가 필요합니다.
다음 장에서는 그 역할을 하는 LayerNorm과 Residual Connection을 살펴봅니다. 이 둘을 이해하면 Transformer Block의 전체 모습이 훨씬 선명해집니다.
이 노트는 보도·비평·교육·연구 목적으로 작성되었습니다. 저작권 문의가 있으시면 에서 알려주세요.