Transformer와 Attention (260831)

WonTerry·2026년 8월 31일

Deep Learning

목록 보기
29/40

Part I

Vision Transformer (ViT)를 이해하기 위해서는 그 뿌리가 되는 Transformer 구조와 핵심 엔진인 Attention 메커니즘을 먼저 이해해야 합니다.

이해하기 쉬운 순서로 단계별로 설명해 드릴게요.


1. Attention (어텐션) 메커니즘: "어디에 집중할 것인가?"

Transformer의 핵심은 "Attention(주의 집중)"입니다.

  • 개념: 문장 안의 단어들을 처리할 때, 특정 단어의 의미를 파악하기 위해 문장 내의 어떤 단어들과 밀접한 관계가 있는지를 계산하는 방식입니다.
  • 예시: "나는 사과를 먹는다"라는 문장에서 '먹는다'라는 단어를 이해하려면, '나'와 '사과'라는 단어에 더 많은 주의(Attention)를 기울여야 합니다.
  • 작동 원리 (Q, K, V): 수학적으로는 세 가지 요소를 사용합니다.
    • Query (Q): "내가 지금 찾고자 하는 정보는 무엇인가?" (질문)
    • Key (K): "나는 어떤 정보를 가지고 있는가?" (검색 대상의 특징)
    • Value (V): "내가 가진 실제 정보 값은 무엇인가?" (실제 데이터)
    • 과정: Query와 Key를 비교하여 유사도(Similarity)를 구하고, 그 유사도만큼 Value를 가져와서 최종 정보를 업데이트합니다. 이를 통해 중요한 정보는 강조하고, 중요하지 않은 정보는 걸러냅니다.
  • Self-Attention: 문장 내의 모든 단어가 서로를 쳐다보며 관계를 계산하는 것을 말합니다. 이를 통해 단어 간의 맥락(Context)을 완벽하게 파악할 수 있습니다.

2. Transformer: "순서(Sequence)를 다루는 혁신"

Transformer는 위에서 설명한 Attention 메커니즘을 기반으로 만들어진 신경망 모델의 아키텍처입니다. 원래는 자연어 처리(NLP, 텍스트 분석)를 위해 개발되었습니다.

  • 의미: 입력된 데이터(단어의 나열)를 받아, 문맥을 파악하여 의미 있는 다른 형태의 데이터(출력)로 변환(Transform)한다는 의미를 담고 있습니다.
  • 기존 방식(RNN)과의 차이점:
    • 기존에는 문장을 앞에서부터 한 단어씩 차례대로 읽었습니다(RNN). 이 방식은 문장이 길어지면 앞부분 내용을 까먹는 '장기 의존성' 문제가 있었습니다.
    • Transformer는 Attention을 사용해 문장 전체를 한꺼번에 봅니다. 덕분에 문장이 아무리 길어도 모든 단어 사이의 관계를 직접 연결할 수 있어 훨씬 빠르고 정확합니다.

3. Vision Transformer (ViT): "이미지를 문장처럼 읽다"

그동안 이미지 처리(Computer Vision) 분야는 이미지의 국소적인 부분(예: 선, 색상)을 훑으며 특징을 찾는 CNN(Convolutional Neural Network)이 지배해왔습니다. 하지만 Google 연구진이 "이미지도 문장처럼 다루면 안 될까?"라는 아이디어에서 나온 것이 바로 Vision Transformer (ViT)입니다.

ViT의 핵심 동작 과정

  1. Patch Partition (이미지를 조각내기): Transformer는 원래 '단어(Token)'를 입력받는 모델입니다. 이미지는 2차원 데이터죠. 그래서 이미지를 바둑판 모양의 작은 정사각형 조각(Patch)들로 쪼갭니다. (예: 224x224 이미지를 16x16 크기의 조각들로 분할)
  2. Linear Projection (벡터화): 쪼개진 이미지 조각들을 1차원 형태의 숫자 배열(Vector)로 쭉 펼칩니다. 이제 이미지 조각 하나하나가 문장의 '단어'와 같은 역할을 하게 됩니다.
  3. Positional Embedding (위치 정보 추가): Transformer는 데이터를 한꺼번에 입력받기 때문에, 이미지 조각들이 이미지의 어디에 위치했는지(왼쪽 위인지, 오른쪽 아래인지)를 모릅니다. 그래서 각 조각에 "나는 몇 번째 조각이다"라는 위치 정보를 더해줍니다.
  4. Transformer Encoder (맥락 파악): 이제 이미지 조각들이 Transformer 모델로 들어갑니다. Self-Attention을 통해 "이 조각은 저 조각과 관련이 있구나(예: 강아지의 귀 조각과 눈 조각)"라는 것을 스스로 학습합니다.
  5. Classification (분류): 마지막으로 전체적인 맥락을 파악하여 "이 이미지는 강아지다"라고 결론을 내립니다.

요약 및 비교

구분CNN (기존 이미지 방식)ViT (Vision Transformer)
핵심 원리필터(Kernel)를 이용해 주변 픽셀을 훑음이미지를 조각내어 단어처럼 처리
주요 특징국소적(Local) 특징 추출에 강함전역적(Global) 관계 파악에 강함
장점데이터가 적어도 학습이 비교적 잘 됨데이터가 아주 많을 때 성능이 압도적임
관점"옆에 있는 픽셀은 무엇인가?""이미지 전체에서 이 조각은 무엇과 연관되나?"

결론적으로, ViT는 이미지의 국소적인 부분에 집중하던 기존 방식을 벗어나, Self-Attention을 통해 이미지 전체의 맥락을 한꺼번에 파악하려는 시도이며, 현재 AI 성능을 비약적으로 높인 핵심 기술 중 하나입니다.


Part II

Attention 메커니즘을 이해하는 가장 좋은 방법은 수학적 수식을 코드로 직접 구현해 보는 것입니다. 딥러닝 프레임워크(PyTorch, TensorFlow)를 사용하면 한 줄로 끝날 수도 있지만, 원리를 이해하기 위해 NumPy만을 사용하여 가장 직관적으로 작성한 코드를 보여드리겠습니다.

이 예제에서는 "문장 속의 단어들이 서로 얼마나 연관되어 있는가?"를 계산하는 과정을 시뮬레이션합니다.

import numpy as np

def softmax(x):
    """입력값의 합이 1이 되도록 변환하는 함수 (확률로 변환)"""
    exp_x = np.exp(x - np.max(x))
    return exp_x / exp_x.sum()

def simple_attention(Q, K, V):
    """
    Scaled Dot-Product Attention을 구현한 함수
    Q: Query (내가 찾고자 하는 정보)
    K: Key (각 정보의 특징/제목)
    V: Value (실제 정보의 내용)
    """
    # 1. Dot-product: Query와 Key를 곱해 유사도(Score)를 구함
    # 어떤 단어가 내(Query)가 찾는 내용과 얼마나 닮았는지 계산
    scores = np.dot(Q, K.T)
    
    # 2. Scaling: 값이 너무 커지는 것을 방지 (수치적 안정성)
    d_k = K.shape[-1]
    scaled_scores = scores / np.sqrt(d_k)
    
    # 3. Softmax: 유사도를 0~1 사이의 확률값(Weight)으로 변환
    # "이 단어에는 70%의 주의를 기울이고, 저 단어에는 10%를 기울여라"라는 의미
    attention_weights = softmax(scaled_scores)
    
    # 4. Weighted Sum: 확률값(Weight)만큼 실제 정보(Value)를 가져옴
    # 중요한 정보는 많이 가져오고, 중요하지 않은 정보는 적게 가져옴
    output = np.dot(attention_weights, V)
    
    return output, attention_weights

# --- 시뮬레이션 데이터 설정 ---

# 3개의 단어가 있다고 가정 (각 단어는 4차원의 특징을 가짐)
# 단어 1: "사과"
# 단어 2: "먹는다"
# 단어 3: "맛있다"

# 1. Query: "먹는다"라는 단어의 의미를 더 정확히 알고 싶어 하는 상황
# (즉, "먹는다"와 연관된 정보를 찾고 싶음)
Q = np.array([[0, 1, 0, 0]]) 

# 2. Key: 각 단어가 가진 특징 (단어 1, 2, 3의 특징)
K = np.array([
    [1, 0, 0, 0],  # 사과 의 특징
    [0, 1, 0, 0],  # 먹는다 의 특징
    [0, 0, 1, 0],  # 맛있다 의 특징
])

# 3. Value: 각 단어가 가진 실제 데이터 값 (단어 1, 2, 3의 내용물)
V = np.array([
    [10, 10, 10, 10], # 사과의 내용
    [20, 20, 20, 20], # 먹는다의 내용
    [30, 30, 30, 30]  # 맛있다의 내용
])

# 실행
result, weights = simple_attention(Q, K, V)

print("--- Attention 시뮬레이션 결과 ---")
print(f"입력 Query (찾고 싶은 것): {Q}")
print("-" * 30)
print(f"Attention Weights (각 단어에 대한 집중도): \n{weights}")
print("-" * 30)
print(f"최종 결과값 (가져온 정보): {result}")

코드 설명 (이게 왜 Attention인가?)

이 코드의 핵심은 "관련성(Similarity) \rightarrow 가중치(Weight) \rightarrow 결과(Weighted Value)"로 이어지는 흐름입니다.

  1. Query (질문): "나는 '먹는다'라는 동작과 관련된 정보를 찾고 싶어!" (Q)
  2. Key (목록/제목): "나는 '사과'야", "나는 '먹는다'야", "나는 '맛있다'야" (K)
    • np.dot(Q, K.T)를 하면, 질문(Q)과 가장 닮은 키(K)가 무엇인지 숫자로 나옵니다. 위 예제에서는 [0, 1, 0][0, 1, 0]이 곱해져서 두 번째 단어가 가장 높은 점수를 받게 됩니다.
  3. Softmax (확률화): 점수를 "비중"으로 바꿉니다. 예를 들어 [0.1, 0.8, 0.1]이라는 결과가 나오면, "80%는 두 번째 단어에 집중해!"라는 뜻이 됩니다.
  4. Value (실제 정보): "그럼 그 비중만큼 정보를 가져올게!" (V)
    • np.dot(weights, V)를 하면, 80%만큼은 두 번째 단어의 데이터(20)를 가져오고, 나머지 10%씩은 첫 번째(10)와 세 번째(30) 데이터를 섞어서 가져옵니다.
    • 계산: (0.1×10)+(0.8×20)+(0.1×30)=1+16+3=20(0.1 \times 10) + (0.8 \times 20) + (0.1 \times 30) = 1 + 16 + 3 = 20

결론

이 코드를 통해 Attention은 "질문(Q)과 가장 유사한 데이터(K)를 찾아, 그 비중(Weight)만큼 실제 정보(V)를 뽑아내는 과정"임을 알 수 있습니다. 이것이 문장 전체를 훑으며 단어 간의 관계를 파악하는 Transformer의 기본 원리입니다.


Part III

딥러닝 프레임워크(PyTorch)를 사용하면 행렬 연산이 최적화되어 있어 코드가 훨씬 간결해집니다. 이번에는 PyTorch를 사용하여, 딥러닝 논문에서 가장 많이 쓰이는 "Scaled Dot-Product Attention"을 가장 핵심적인 수식 위주로 구현해 보겠습니다.

이 코드는 복잡한 신경망 모델 전체를 만드는 것이 아니라, Attention의 핵심 엔진(연산 부분)만 보여줍니다.

import torch
import torch.nn.functional as F

# 1. 데이터 준비 (입력 데이터)
# [단어 개수, 특징 차원(Dimension)]
# 여기서는 3개의 단어가 있고, 각 단어는 4개의 숫자(특징)로 이루어져 있다고 가정합니다.
dim = 4
Q = torch.randn(1, dim)      # Query: "내가 궁금한 것" (1개의 단어)
K = torch.randn(3, dim)      # Key: "데이터들의 특징" (3개의 단어)
V = torch.randn(3, dim)      # Value: "데이터들의 실제 값" (3개의 단어)

print("--- 입력 데이터 ---")
print(f"Query shape: {Q.shape}")
print(f"Key shape: {K.shape}")
print(f"Value shape: {V.shape}\n")

# 2. Attention 연산 (핵심 3단계)

# [Step 1] Similarity Score: Q와 K를 곱해 유사도를 구함 (Dot-product)
# Q(1x4)와 K의 전치행렬(4x3)를 곱하면 1x3 크기의 유사도 점수가 나옵니다.
scores = torch.matmul(Q, K.transpose(-2, -1))

# [Step 2] Scaling: 점수가 너무 커지지 않게 조정 (루트 d_k로 나눔)
# 이는 학습의 안정성을 위해 반드시 필요한 과정입니다.
scaling_factor = torch.sqrt(torch.tensor(dim, dtype=torch.float32))
scaled_scores = scores / scaling_factor

# [Step 3] Softmax & Weighted Sum: 가중치를 구하고 정보를 취합함
# Softmax를 통해 각 점수를 "비중(확률)"으로 변환합니다.
attention_weights = F.softmax(scaled_scores, dim=-1)

# 가중치(1x3)를 Value(3x4)에 곱하여 최종 정보를 추출합니다.
output = torch.matmul(attention_weights, V)

# 3. 결과 출력
print("--- Attention 결과 ---")
print(f"1. Attention Weights (각 단어에 대한 집중도):\n{attention_weights}")
print(f"\n2. Final Output (취합된 정보):\n{output}")

코드 핵심 포인트 (왜 이게 단순한가?)

  1. torch.matmul (Matrix Multiplication):
    • NumPy의 np.dot보다 훨씬 강력합니다. 딥러닝에서는 데이터가 '배치(Batch)' 단위로 들어오는데, matmul은 여러 개의 데이터를 한꺼번에(병렬로) 계산하는 데 최적화되어 있습니다.
  2. F.softmax:
    • 복잡한 수식 없이, 특정 차원(dim=-1)을 기준으로 모든 값의 합이 1이 되도록 아주 간단하게 계산해 줍니다.
  3. 텐서(Tensor) 연산:
    • 데이터의 차원(Shape)만 맞으면, matmul 하나로 "어떤 단어가 중요한가?"와 "그 정보들을 어떻게 섞을 것인가?"를 순식간에 해결합니다.

수식과 코드 매핑

우리가 수학에서 배우는 Attention 수식은 다음과 같습니다:
Attention(Q,K,V)=softmax(QKTdk)V\text{Attention}(Q, K, V) = \text{softmax}\left(\frac{QK^T}{\sqrt{d_k}}\right)V

위의 코드를 수식 순서대로 매칭하면 이렇습니다:
1. scores = torch.matmul(Q, K.transpose(-2, -1)) \rightarrow QKTQK^T
2. scaled_scores = scores / scaling_factor \rightarrow QKTdk\frac{QK^T}{\sqrt{d_k}}
3. attention_weights = F.softmax(scaled_scores, dim=-1) \rightarrow softmax()\text{softmax}(\dots)
4. output = torch.matmul(attention_weights, V) \rightarrow ()V(\dots)V

이것이 바로 Transformer 모델의 심장부이며, 이 단순한 연산이 수만 번 반복되면서 AI가 문맥을 이해하게 됩니다.

profile
Hello, I'm Terry! 👋 Enjoy every moment of your life! 🌱 My current interests are Signal processing, Machine learning, Python, Database, LLM & RAG, MCP & ADK, Multi-Agents, Physical AI, ROS2...

0개의 댓글