2017년 Google의 논문 "Attention is all you need"에서 처음 소개된 트랜스포머는 현대 AI의 근간이 되는 혁신적인 모델입니다. 기존 RNN의 한계를 극복하고 BERT, GPT와 같은 거대 모델의 시대를 연 트랜스포머에 대해 자세히 알아보겠습니다.
트랜스포머(Transformer)
트랜스포머는 어텐션(Attention) 메커니즘을 활용하여 시퀀스 데이터를 학습하는 신경망 구조입니다.
- 병렬 연산: RNN처럼 순차적으로 계산하지 않고 전체 문장을 한 번에 처리하여 학습 속도가 매우 빠릅니다.
- 장기 의존성(Long-term Dependency) 해결: 문장이 길어져도 단어 간의 관계를 손실 없이 파악합니다.
- 핵심 원리: '셀프 어텐션(Self-Attention)'을 통해 문장 내 단어들의 관계를 동적으로 학습합니다.

1. 트랜스포머의 핵심 특징
① 셀프 어텐션 (Self-Attention)
각 토큰이 다른 모든 토큰과 어떤 관계가 있는지 가중치를 계산합니다. Query(Q), Key(K), Value(V) 세 개의 벡터를 사용하여 유사도를 구하고, 중요한 정보에 더 집중(Attention)합니다.
② 멀티-헤드 어텐션 (Multi-Head Attention)
여러 개의 어텐션 '헤드'를 병렬로 운용합니다. 각 헤드는 문법적 관계, 의미적 관계, 대명사 참조 등 서로 다른 관점에서 문맥을 파악하여 더 풍부한 표현을 얻습니다.
③ 포지셔널 인코딩 (Positional Encoding)
순차적으로 데이터를 읽지 않는 트랜스포머를 위해 단어의 위치 정보를 주입하는 기법입니다. 사인(Sin)과 코사인(Cos) 함수를 이용해 위치마다 고유한 패턴의 벡터를 생성하여 더해줍니다.
④ 레이어 정규화 (Layer Normalization)
트랜스포머는 배치 정규화(BatchNorm) 대신 레이어 정규화(LayerNorm)를 사용합니다.
| 구분 | 배치 정규화 (BatchNorm) | 레이어 정규화 (LayerNorm) |
| 기준 | 배치 내 여러 샘플의 동일 채널 | 한 샘플 내의 모든 특징(Feature) |
| 장점 | 학습 가속화 (CNN에 적합) | 가변적인 문장 길이에 안정적 (NLP에 적합) |
| 비유 | "반 전체 평균으로 내 점수 보정" | "내 과목들 평균으로 내 점수 보정" |
2. 포지셔널 인코딩(Positional Encoding) 깊이 보기 ⭐
트랜스포머에게 위치 정보를 알려주는 방식은 마치 "서로 다른 속도로 도는 여러 개의 시계"를 사용하는 것과 같습니다.
- 주기성: 사인/코사인 파형을 사용하므로 모델이 n칸 떨어진 단어와의 상대적 거리를 선형적으로 이해할 수 있습니다.
- 확장성: 학습 데이터보다 긴 문장이 들어와도 위치 정보를 고유하게 부여할 수 있습니다.
3. 피드포워드 신경망과 잔차 연결
피드포워드 신경망 (FFN)
어텐션이 단어 간의 '관계'를 파악했다면, FFN은 각 단어 벡터를 개별적으로 더 복잡하게 변환하여 표현력을 높입니다. 보통 차원 확장 → 활성화 함수(ReLU/GELU) → 차원 축소 과정을 거칩니다.
잔차 연결 (Residual Connection)
"원래 정보 + 새로 학습한 정보"를 더해주는 구조입니다. 층이 깊어져도 정보가 사라지는 기울기 소실(Gradient Vanishing) 문제를 방지하고 학습을 안정화합니다.
4. 마스크드 어텐션 (Masked Attention)
디코더(Decoder)에서 사용되는 핵심 기법입니다. 문장을 생성할 때 미래의 단어를 미리 보고 커닝하는 것을 방지하기 위해, 현재 위치 이후의 단어들은 어텐션 점수를 $-\infty$로 처리하여 가립니다.
5. 트랜스포머 직접 구현하기 (TensorFlow/Keras)
이제 위에서 배운 개념들을 코드로 구현해 보겠습니다. 이 코드는 간단한 긍정/부정 감성 분류 모델입니다.
데이터 전처리 및 준비
import tensorflow as tf
from tensorflow.keras.models import Model
from tensorflow.keras.layers import Dense, Embedding, GlobalAveragePooling1D, LayerNormalization, Dropout, Input
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
import keras
# 데이터 로드 (경로는 사용자 환경에 맞춰 수정)
dataframe = pd.read_csv('sentiment_data.csv')
sentences = dataframe['sentence'].astype(str).tolist()
labels = dataframe['label'].tolist()
y = np.array(labels, dtype=np.float32)
# 토크나이징 및 패딩
embedding_dim = 128
max_len = 10
tokenizer = tf.keras.preprocessing.text.Tokenizer(oov_token='<OOV>')
tokenizer.fit_on_texts(sentences)
sequences = tokenizer.texts_to_sequences(sentences)
word_index = tokenizer.word_index
vocab_size = len(word_index) + 1
data = tf.keras.preprocessing.sequence.pad_sequences(sequences, maxlen=max_len, padding='post')
X_train, X_val, y_train, y_val = train_test_split(data, y, test_size=0.2, random_state=2026, stratify=y)
포지셔널 인코딩 정의
def get_positional_encoding(max_len, d_model):
pos_enc = np.zeros((max_len, d_model), dtype=np.float32)
for pos in range(max_len):
for i in range(0, d_model, 2):
pos_enc[pos, i] = np.sin(pos / (10000 ** (2 * i / d_model)))
if i + 1 < d_model:
pos_enc[pos, i + 1] = np.cos(pos / (10000 ** (2 * (i + 1) / d_model)))
return pos_enc
positional_encoding = get_positional_encoding(max_len, embedding_dim)
멀티-헤드 셀프 어텐션 레이어 구현
class MultuHeadSelgAttentionalLayer(tf.keras.layers.Layer):
def __init__(self, num_heads, key_dim, dropout_rate=0.0):
super().__init__()
self.mha = tf.keras.layers.MultiHeadAttention(
num_heads = num_heads,
key_dim = key_dim,
dropout = dropout_rate
)
self.norm = LayerNormalization(epsilon=1e-6)
def call(self, x, padding_mask=None, training=None):
attn_mask = None
if padding_mask is not None:
# MultiHeadAttention이 기대하는 (batch, query_seq, key_seq) 형태로 확장
attn_mask = padding_mask[:, tf.newaxis, :]
# Self-Attention 수행
attn = self.mha(query=x, value=x, key=x, training=training, attention_mask=attn_mask)
return self.norm(x + attn) # 잔차 연결 및 정규화
모델 빌드 및 학습
num_heads = 8
key_dim = embedding_dim // num_heads
inputs = Input(shape=(max_len,), dtype=tf.int32)
# 패딩 토큰(0)을 마스킹 처리
padding_mask = keras.ops.not_equal(inputs, 0)
# 1. 임베딩 + 포지셔널 인코딩
x = Embedding(input_dim=vocab_size, output_dim=embedding_dim, mask_zero=True)(inputs)
x = x + positional_encoding
# 2. 트랜스포머 어텐션 블록
x = MultuHeadSelgAttentionalLayer(num_heads=num_heads, key_dim=key_dim, dropout_rate=0.1)(
x, padding_mask=padding_mask
)
# 3. 분류를 위한 출력층
gap = GlobalAveragePooling1D()
x = gap(x, mask=padding_mask)
x = Dense(128, activation='relu')(x)
x = Dropout(0.5)(x)
outputs = Dense(1, activation='sigmoid')(x)
model = Model(inputs=inputs, outputs=outputs)
model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])
# 모델 요약 및 학습
model.summary()
history = model.fit(X_train, y_train, epochs=10, batch_size=16, validation_data=(X_val, y_val))
추론 결과 확인
sample_texts = ["This is the best thing I’ve ever bought!", "The service was terrible and rude."]
sample_sequences = tokenizer.texts_to_sequences(sample_texts)
sample_data = tf.keras.preprocessing.sequence.pad_sequences(sample_sequences, maxlen=max_len, padding='post')
predictions = model.predict(sample_data)
for i, text in enumerate(sample_texts):
label = 'Positive' if predictions[i] > 0.5 else 'Negative'
print(f"Text: {text} -> Prediction: {label}")
마무리하며
트랜스포머는 단순히 자연어 처리를 넘어 컴퓨터 비전(ViT), 오디오 처리 등 모든 AI 분야의 표준이 되었습니다. 오늘 정리한 셀프 어텐션, 포지셔널 인코딩, 레이어 정규화는 그 핵심 중의 핵심입니다. 이 구조를 직접 코드로 구현해 봄으로써 모델이 데이터를 어떻게 바라보는지 더 깊이 이해할 수 있었습니다.
다음에는 트랜스포머 논문에 대한 블로그를 작성해보도록 하겠습니다!!
'개념 정리 step2 > 멀티모달(Multi-modal)' 카테고리의 다른 글
| [Deep Learning] Vision Transformer(ViT) Multi-Branch 구현 실습 (0) | 2026.01.23 |
|---|---|
| [NLP] KLUE-BERT 기반 멀티레이블 혐오 표현 분류 실습 (0) | 2026.01.22 |
| [딥러닝 NLP] NLU에서 트랜스포머 어텐션까지 핵심 개념 정리 (1) | 2026.01.16 |
| [RNN] 시퀀스 데이터와 순환 신경망(RNN) 학습 정리 (1) | 2026.01.15 |
| [NLP] 단어 임베딩: Word2Vec부터 FastText, GloVe (0) | 2026.01.14 |