[BERT] 심화 개념 정리 (Word2Vec 대비 이해 중심)
이 문서는 BERT를 "왜 필요했는지"를 Word2Vec/GloVe와 비교해 설명합니다. 실험 수치는 BERT_MLM_experiment를 참고하세요.
아주 쉽게 한 줄 요약
BERT는 "단어 자체"가 아니라 "문장 안에서의 단어 의미"를 학습하는 모델입니다.
당시 상황과 역사적 맥락
2018년 이전에는 Word2Vec/GloVe 같은 정적 임베딩이 널리 쓰였습니다. 문제는 다의어였습니다. 예를 들어 "bank"는 은행/강둑 두 의미가 있는데, 정적 임베딩은 문맥과 관계없이 같은 벡터를 줍니다. BERT는 이 문제를 문맥 기반 임베딩으로 해결했습니다.
Word2Vec의 단점 vs BERT의 개선
| 항목 | Word2Vec/GloVe | BERT |
|---|---|---|
| 임베딩 성격 | 정적(static) | 문맥 기반(contextual) |
| 다의어 처리 | 어려움 (항상 같은 벡터) | 문맥에 따라 다른 벡터 |
| 문장 이해 태스크 | 추가 모델 의존 큼 | 사전학습 표현을 바로 활용 가능 |
| 계산 비용 | 상대적으로 가벼움 | 더 무거움 (Attention 비용) |
예시: "I went to the bank"와 "I sat on the river bank"에서 BERT는 bank 표현을 다르게 만들 수 있습니다.
1단. 문제 정의
단방향 또는 정적 임베딩 기반 모델은 문맥 이해가 필요한 태스크에서 표현 한계가 있었습니다.
2단. 기존 한계
- 단어 의미가 문맥에 따라 달라져도 같은 벡터를 쓰는 문제
- 좌/우 문맥을 동시에 반영하기 어려운 학습 목표
- 태스크마다 많은 라벨 데이터와 튜닝이 필요한 운영 부담
3단. 핵심 아이디어
BERT는 Transformer Encoder를 사용해 양방향 문맥을 동시에 봅니다. 학습은 MLM(Masked Language Modeling) 중심으로 진행해, 가려진 단어를 주변 문맥으로 복원하게 만듭니다.
BERT의 bidirectional은 어디서 나오나?
핵심: BERT에 별도의 "양방향 전용 레이어"가 있는 것이 아닙니다.
BERT 구조 자체는 Transformer encoder stack이고, 양방향성은 MLM 학습 방식으로 형성됩니다.
1) 입력 구조
예: [CLS] I love machine learning [SEP]
토큰화 예: input_ids = [101, 1045, 2293, 3698, 4083, 102]
입력 임베딩은 보통 다음 합으로 구성됩니다.
최종 입력 텐서 shape 예: (sequence_length, hidden_size) = (6, 768)
2) Transformer encoder stack (구조 자체는 단순)
for layer in layers:
X = self_attention(X)
X = feed_forward(X)
즉 embedding -> attention -> ffn -> attention -> ffn -> ... 반복입니다.
3) GPT와 BERT의 핵심 차이
GPT(Decoder LM)는 미래 토큰을 보지 못하도록 causal mask를 씁니다.
1 0 0 0
1 1 0 0
1 1 1 0
1 1 1 1
반면 BERT(Encoder MLM)는 self-attention에서 좌/우 문맥을 함께 보며, 입력 일부를 [MASK]로 가려 복원하도록 학습합니다.
정리: 구조 차이보다 "attention 가시성 + 학습 목표" 차이가 bidirectional/unidirectional 성격을 만든다고 보는 것이 정확합니다.
GPT vs BERT를 확률식으로 보면
- GPT:
P(w_t | w_1 ... w_{t-1})(왼쪽 문맥 기반) - BERT:
P(w_i | left + right context)(양쪽 문맥 기반)
즉 GPT는 word3 -> word1, word2만 보지만, BERT는 word3 -> word1, word2, word4, word5까지 함께 참고할 수 있습니다.
4) 왜 그냥 양방향으로 두면 안 되나? (information leakage)
문장을 그대로 넣고 같은 위치 단어를 예측하면, 정답 토큰이 입력에 이미 존재해 복사만 해도 되는 문제가 생깁니다.
예: I love machine learning에서 machine 예측 시, 입력에 machine이 그대로 있으면 학습이 무의미해집니다. 이것이 information leakage입니다.
5) 그래서 MLM이 필요하다
BERT는 토큰 일부를 [MASK]로 가려 누수를 막습니다.
예: I love [MASK] learning -> 정답: machine
모델은 왼쪽(love)과 오른쪽(learning) 문맥을 동시에 사용해 마스크 토큰을 복원해야 하므로, bidirectional 학습이 성립합니다.
6) 구조를 코드로 보면
class BertModel(nn.Module):
def __init__(self):
self.embeddings = BertEmbedding()
self.encoder = TransformerEncoder()
def forward(self, input_ids):
x = self.embeddings(input_ids)
for layer in self.encoder:
x = layer(x)
return x
class TransformerLayer(nn.Module):
def forward(self, x):
attn = self.self_attention(x)
x = x + attn
ff = self.feed_forward(x)
x = x + ff
return x
scores = Q @ K.T / sqrt(d)
weights = softmax(scores)
output = weights @ V
BERT encoder self-attention에서는 causal mask를 쓰지 않으므로, 토큰들이 서로 전역적으로 참조할 수 있습니다.
7) MLM loss는 어디에 걸리나
핵심은 마스크된 위치에만 loss를 계산한다는 점입니다.
logits = linear(hidden_states)
loss = cross_entropy(
logits[mask_positions],
target_tokens
)
즉 모든 토큰이 아니라 mask_positions만 학습 신호를 받습니다.
8) 최종 정리
- Transformer encoder: 모든 토큰 상호참조
- MLM objective: 정보 누수 차단 + 양방향 문맥 복원 강제
그래서 BERT의 bidirectional은 "특수 레이어"가 아니라 encoder 가시성 + MLM 학습목표 조합으로 구현됩니다.
왜 GPT는 BERT처럼 bidirectional을 쓰지 않고 autoregressive를 쓰나?
핵심 차이는 목표 태스크입니다.
- BERT: 문장 이해 중심 (분류/판별/추출)
- GPT: 문장 생성 중심 (다음 토큰 생성)
BERT가 강한 것과 약한 것
BERT는 P(w_i | left + right context)를 학습합니다. 예: I love [MASK] learning에서 좌/우 문맥을 동시에 보고 마스크를 복원합니다.
이 방식은 이해 태스크에는 강력하지만, 빈 입력에서 자유 생성을 직접 수행하는 구조는 아닙니다.
GPT가 생성 가능한 이유
GPT는 P(w_t | w_1...w_{t-1}) 형태의 autoregressive LM입니다. 즉 "지금까지 생성한 토큰"만 보고 다음 토큰을 예측합니다.
예: I love machine -> 다음 후보 learning, models, ...
이 예측을 반복해 문장을 한 토큰씩 생성합니다.
이를 위해 decoder self-attention에서 causal mask를 사용합니다.
1 0 0 0
1 1 0 0
1 1 1 0
1 1 1 1
즉 token3는 token1, token2까지만 보고 미래 토큰은 보지 못합니다.
구조 비교 한눈에
- BERT: encoder + MLM + bidirectional attention
- GPT: decoder-only + autoregressive + causal attention
그래서 BERT는 "문장 이해 모델", GPT는 "문장 생성 모델"로 역할이 갈립니다.
왜 요즘 LLM은 decoder-only가 주류인가
최근 제품/서비스의 핵심 요구가 고품질 생성(대화, 작성, 코드, 에이전트)이기 때문입니다. autoregressive 학습-추론 경로가 이 목적에 직접 맞습니다.
실무적으로도 GPT/LLaMA/Claude 계열처럼 decoder-only Transformer가 대규모 생태계의 표준이 되었습니다.
모델 구조/구성요소 역할

- Token/Segment/Position Embedding: 단어 의미+문장쌍 구분+순서 정보 결합
- Encoder Stack: 문맥 정보를 층층이 통합해 contextual representation 생성
- MLM Head: [MASK] 위치 단어 복원
- [CLS] 경로: 문장 분류/판단 태스크 입력 벡터
Encoder 블록 내부를 더 자세히 보기
BERT-base는 같은 Encoder 블록을 12번 반복합니다. 한 블록 안에서 일어나는 일은 아래 순서입니다.
- Multi-Head Self-Attention: 각 토큰이 다른 토큰을 얼마나 참고할지 계산
- Add & LayerNorm: 원래 입력을 더해(residual) 정보 손실을 줄이고 정규화로 학습 안정화
- Position-wise FFN: 각 토큰 벡터를 비선형 변환해 표현력 확장
- Add & LayerNorm: 다시 residual+정규화로 깊은 층 학습 안정화
즉, 한 층은 \"토큰 간 관계 학습(Attention)\"과 \"토큰 자체 표현 강화(FFN)\"를 한 번씩 수행합니다. 이 과정을 여러 층 반복하면서 단어의 의미가 점점 문맥 친화적으로 바뀝니다.
입력에서 출력까지 텐서 흐름
- 입력 길이
L, hidden 크기H라면 임베딩 출력은 보통[L, H] - Self-Attention을 지나도 shape은
[L, H]유지 (정보 내용만 갱신) - 12층을 지나 최종 hidden
[L, H]를 얻고, 여기서: [CLS]위치 벡터[H]-> 분류 head[MASK]위치 벡터[H]-> vocab 크기 로짓[|V|]-> softmax
이렇게 보면 BERT는 \"문장 전체 표현\"과 \"토큰 단위 복원\"을 같은 백본에서 동시에 지원하는 구조라는 점이 명확해집니다.
CLS 토큰은 정확히 무엇인가?
BERT 입력은 보통 [CLS] ...tokens... [SEP] 형태입니다. 여기서 [CLS]는 실제 단어가 아니라 문장 단위 태스크를 위한 특수 토큰입니다.
예: [CLS] I love machine learning [SEP]
Self-attention에서는 모든 토큰이 서로를 보므로, [CLS]도 전체 토큰과 상호작용합니다. 층을 거치며 [CLS] 벡터에 문장 전역 정보가 누적됩니다.
그래서 분류 태스크에서는 마지막 층의 h_CLS를 바로 분류기에 넣습니다.
왜 앞에 [CLS]를 넣으면 문장 요약 벡터가 되나?
직관적으로 [CLS]는 빈 메모장 토큰입니다. 각 attention 층에서 다른 토큰 정보를 가중합으로 받아 업데이트되기 때문에, 깊어질수록 문장 요약 성격이 강해집니다.
즉 [CLS]의 의미는 고정된 것이 아니라 학습으로 형성됩니다. "문장 단위 목표를 잘 맞추도록" 최적화되면서 문장 대표 벡터 역할을 하게 됩니다.
연산 과정 상세
- 문장을 토큰화하고 일부 토큰을 [MASK]로 치환
- 임베딩 결합 후 인코더 스택 통과
- 마스크 위치 hidden state를 MLM head에 넣어 단어 확률 분포 계산
- 정답 단어와의 차이를 loss로 계산해 역전파
NSP는 무엇이고 왜 논쟁이 있었나
NSP(Next Sentence Prediction)는 "문장 B가 문장 A의 실제 다음 문장인가"를 맞히는 보조 과제입니다. BERT는 NSP를 포함했지만, RoBERTa는 NSP를 제거하고도 성능이 좋아질 수 있음을 보였습니다.
핵심 교훈은 "모든 보조 과제가 항상 도움되는 것은 아니다"입니다. 실무에서는 태스크에 실제로 기여하는 목표만 남기는 것이 중요합니다.
요즘도 CLS를 쓰나? (실무 답변)
결론: 분류에서는 여전히 자주 쓰지만, 임베딩 검색에서는 항상 최선이 아닙니다.
- 분류/판별: CLS 사용이 여전히 일반적
- Semantic search/유사도: mean pooling 또는 전용 임베딩 모델이 더 좋은 경우가 많음
이유는 BERT pretraining 목표(MLM/NSP)가 "문장 거리 최적화" 자체를 직접 목표로 하지 않기 때문입니다.
그래서 문장 임베딩 실무에서는 보통 아래를 더 많이 씁니다.
- Mean pooling (패딩 제외 토큰 평균)
- Sentence-BERT 계열(contrastive/siamese 학습)
- 최신 embedding 모델(e5, bge, text-embedding 계열)
현업 규칙으로는 "CLS는 strong baseline, 검색은 전용 임베딩 우선 검증"이 안전합니다.
핵심 요약 (딱 4줄)
- BERT 원래 설계:
sentence vector = CLS - 요즘 임베딩 실무:
sentence vector = mean pooling이 더 흔함 - CLS는 문장 분류에는 강력하지만, 문장 유사도에서는 항상 최선이 아님
- 그래서 mean pooling + contrastive training 조합을 많이 사용
왜 mean pooling만 해도 문장 의미 벡터가 되나?
겉보기엔 "단어 벡터 평균"이라 단순해 보이지만, 평균 대상이 이미 문맥화된 토큰 벡터라는 점이 핵심입니다.
- Transformer 층을 지난 토큰 벡터는 주변 단어 정보를 이미 포함
- 즉 각 토큰이 문장 문맥의 요약을 부분적으로 들고 있음
- 평균을 취하면 이런 부분 요약들이 안정적으로 합쳐져 문장 전반 의미를 반영
그래서 표면 단어가 조금 달라도 의미가 비슷한 문장은 가까운 벡터가 될 수 있습니다. contrastive 학습을 추가하면 이 정렬이 더 강해집니다.
핵심 수식/기호 설명
L_MLM = -sum_t log P(x_t | x_masked)softmax(z_i)=exp(z_i)/sum_j exp(z_j)
기호: x_t(정답 토큰), x_masked(마스킹 입력), z_i(토큰 i 로짓).
직관: "문맥이 맞으면 정답 단어 확률을 높이고, 틀리면 낮춘다"를 반복해 단어 의미를 정교화합니다.
BERT 벡터는 어떻게 만들어지나?
처음 단어는 텍스트일 뿐입니다. 컴퓨터가 계산하려면 숫자로 바꿔야 하므로 임베딩 벡터를 사용합니다.
핵심은 이 벡터가 고정 사전이 아니라 학습 중에 계속 업데이트된다는 점입니다.
- 초기값: 랜덤에 가까운 임베딩
- 학습: MLM 예측 오차(loss) 발생
- 역전파: gradient descent로 임베딩 행렬 포함 파라미터 업데이트
임베딩 행렬은 보통 [vocab_size, hidden_dim] 형태입니다. 예: 30000 x 768.
학습이 진행되면 비슷한 단어는 가까운 벡터로 정렬되고, BERT에서는 같은 단어도 문맥에 따라 다른 표현으로 바뀝니다.
예: bank는 금융 문맥과 강둑 문맥에서 다른 contextual vector를 가집니다.
4단. 비용/리스크
- Attention O(n^2)로 긴 입력에서 비용 증가
- 사전학습 도메인과 실제 서비스 도메인이 다르면 성능 하락
- 작은 toy 실험 수치를 일반 성능으로 과대해석할 위험
5단. 실무 적용
- 분류/NER/reranker/문서이해에 강함
- 생성 중심 서비스는 GPT/T5 등 decoder 또는 encoder-decoder도 함께 검토
- 도입 순서: base 모델 검증 -> 도메인 적응 -> latency/비용 최적화
역사적 의미와 후속 영향
- "사전학습 + 미세조정"을 산업 표준으로 정착
- RoBERTa/ALBERT/DeBERTa 등 후속 encoder 계열 발전 촉진
- 문서 이해/검색 랭킹 파이프라인의 실무 표준 백본으로 자리잡음
예상 질문과 답변
Q1. BERT가 Word2Vec보다 본질적으로 나은 점은?
A1. 문맥에 따라 단어 벡터가 달라진다는 점입니다. 다의어 처리에서 큰 차이가 납니다.
Q2. MLM은 왜 효과적인가?
A2. 주변 단어를 보고 빈칸을 채워야 하므로 문맥 이해를 강제하기 때문입니다.
Q3. BERT의 가장 큰 비용 이슈는?
A3. 긴 입력에서 Attention 비용이 커져 추론 지연과 메모리 사용이 증가합니다.
Q4. NSP를 꼭 써야 하나?
A4. 반드시 그렇진 않습니다. RoBERTa처럼 제거하고도 성능 개선 사례가 있습니다.
Q5. 실무에서 BERT를 언제 우선 고려하나?
A5. 생성보다 "이해"가 핵심인 태스크(분류/검색 랭킹/정보추출)에서 우선 고려합니다.