BERT 개념이해 #7 Residual Connection #
#2026-03-04
#1 Residual Connection이 필요한 이유: 깊어질수록 “처음 레이어”가 점점 학습을 못 한다
BERT는 Transformer layer를 12개 쌓는다. 레이어를 많이 쌓으면 표현이 정교해지고, 멀리 떨어진 단어 관계도 잘 잡고, 문맥 이해도 깊어진다. 그런데 깊은 신경망에는 오래된 고질병이 있다. 뒤쪽 레이어에서 나온 손실(loss)의 신호가 앞쪽 레이어까지 거슬러 올라갈 때, 그 신호가 길을 잃거나 너무 약해지거나, 반대로 너무 커져서 터지는 문제다.
역전파는 기본적으로 “곱셈의 연쇄”다. 12개의 레이어를 통과했다면, 그래디언트도 12번의 변화율을 연속으로 곱한다. 그 변화율들이 대부분 1보다 조금 작기만 해도, 곱을 반복하면 급격히 0에 가까워진다. 이게 그래디언트 소실이다. 반대로 대부분이 1보다 조금 크기만 해도 곱을 반복하면 폭발한다. 이런 상황이 되면 앞쪽 레이어는 “수정하라는 신호”를 거의 못 받거나, 너무 큰 신호를 받아 학습이 불안정해진다. 결국 깊은 모델을 만들고 싶어도 학습이 안 되는 벽을 만난다.
Residual connection은 이 벽을 깨기 위해 “그래디언트가 확실히 흐르는 고속도로”를 하나 만들어주는 장치다.
레이어 1 → 레이어 2 → ... → 레이어 12 → 손실
역전파 시:
그래디언트 = ∂Loss/∂Layer1
= (∂Loss/∂L12) × (∂L12/∂L11) × ... × (∂L2/∂L1)
12개의 값을 연속으로 곱함
각 값이 0.5이면: 0.5^12 ≈ 0.00024 ← 그래디언트 소실!
각 값이 2.0이면: 2^12 = 4096 ← 그래디언트 폭발!
-> Residual Connection(잔차 연결)은 입력을 변환 결과에 그대로 더해주는 "지름길"을 만들어, 깊은 네트워크에서도 그래디언트가 안정적으로 흐르게 한다.
#
#2 핵심 아이디어: “변환 결과”에 “원본 입력”을 그냥 더해버린다
Residual이 없는 레이어는 보통 이렇게 생각한다. 입력 x를 받아서 어떤 복잡한 함수 F(x)로 바꿔서 그걸 출력으로 내보낸다. 즉 출력은 F(x)다. 그런데 residual이 있으면 출력은 F(x)가 아니라 x + F(x)가 된다. 입력을 그대로 복사해두었다가, 변환 결과에 그냥 더해버리는 것이다.
이게 왜 중요한지 음악 스튜디오 비유로 보면 바로 감이 온다. 보컬 원본 트랙이 있고, 그 위에 리버브나 EQ 같은 효과를 입힌 트랙이 있다. 최종 출력은 원본 + 효과다. 만약 효과가 마음에 안 들면? 효과 트랙을 0으로 만들면 된다. 그러면 출력은 원본 그대로다. 즉 시스템은 최소한 “원본을 망치지 않는 상태”에서 출발할 수 있다.
원본 신호 (vocals): ────────────────────────────────→ 출력에 더함
↓ ↑
효과 처리 (reverb, EQ) → 처리된 신호
결과:
출력 = 원본 + 효과
→ 효과를 제거하고 싶으면 weights=0으로 → 원본 신호만 남음
→ 학습 초반: 랜덤 초기화된 레이어가 "아무것도 안 하는" 상태에서 시작 가능
신경망에서도 똑같다. residual 구조에서는 F(x)가 0이 되면 출력은 x가 된다. 레이어가 “아무것도 안 하는 상태”를 쉽게 만들 수 있다. 이게 학습 초반에 엄청난 차이를 만든다. 랜덤 초기화된 레이어가 괜히 표현을 망가뜨리더라도, residual이 있으면 원본 정보가 지름길로 그대로 다음으로 전달될 수 있다.
Residual 없는 레이어:
output = F(x) ← F: Linear+Attention 등 변환
Residual 있는 레이어:
output = x + F(x) ← 입력 x를 그대로 더함
학습 목표:
Residual 없음: F(x) 자체가 원하는 값이 되어야 함
Residual 있음: F(x)가 x에서 얼마나 변화해야 하는지(잔차)만 학습
→ F(x) = 0이면 출력 = 입력 (변화 없음)
→ 훨씬 쉬운 학습 목표!
Residual의 또 다른 핵심은 학습 목표를 바꿔버린다는 점이다. residual이 없으면 레이어는 “원하는 출력 전체”를 F(x)로 만들어야 한다. 즉 처음부터 끝까지 다 책임져야 한다. 반면 residual이 있으면 레이어는 “x를 얼마나 바꿀지”, 즉 변화량만 학습하면 된다. 말 그대로 잔차(residual)를 학습하는 셈이다.
이 관점이 왜 쉬운지 직관적으로 생각해보자. 우리가 이미 꽤 괜찮은 초안이 있는데, 거기에 빨간펜으로 수정만 하면 훨씬 쉽다. 완전히 빈 종이에 처음부터 다시 쓰는 것보다, “필요한 부분만 조금 바꾸는 일”이 훨씬 수월하다. Transformer layer는 residual 덕분에 매 층마다 “이전 표현을 전부 갈아엎는” 대신 “이전 표현에 부족한 정보만 덧붙이는” 방식으로 작동할 수 있다. 그래서 12층을 쌓아도 점진적으로 의미가 정교해진다.
#
#3 그래디언트가 안정적으로 흐르는 이유: 미분에 ‘1’이 항상 포함된다
Residual이 진짜로 학습을 살리는 이유를 수학적으로 한 줄로 보면 이거다. 출력이 x + F(x)이면, x에 대한 미분은 1 + ∂F/∂x가 된다. 여기서 ‘1’이 굉장히 큰 의미를 가진다. 레이어의 변환 F(x)가 어떤 이유로 미분값이 작아져도, 최소한 1이 남는다. 즉 그래디언트가 “완전히 끊겨서 0이 되는 길”이 구조적으로 막힌다.
이걸 상상해보면, 원래는 12개의 레이어를 거치면서 매번 “좁은 길”을 지나야 했는데, residual이 있으면 각 레이어마다 “기본적으로 열려 있는 넓은 길(=1)”이 같이 존재하는 것이다. 그래서 깊이가 깊어져도 앞단으로 신호가 도달할 가능성이 훨씬 높아진다.
Residual Connection의 역전파:
output = x + F(x)
∂output/∂x = 1 + ∂F(x)/∂x
↑ ↑
항상 1 변환 레이어의 그래디언트
핵심:
항상 1이 더해지므로
→ ∂F(x)/∂x가 아무리 작아도(0이 되어도)
→ ∂output/∂x ≥ 1
역전파 체인에서:
∂Loss/∂x₁ = (1 + g₁₂)(1 + g₁₁)...(1 + g₁) × ∂Loss/∂x₁₂
= 항상 1 이상의 값들의 곱
→ 그래디언트 소실이 구조적으로 방지됨
물론 1 + ∂F/∂x가 항상 1 이상이라는 식의 직관은 “대략적인 방향성”으로 이해하는 게 좋다. 실제로는 LayerNorm이나 다양한 연산이 섞이면서 스케일이 조정되고, 완전히 단순한 곱셈처럼만 되지는 않는다. 그럼에도 핵심 메시지는 변하지 않는다. residual이 있으면 “그래디언트가 흐를 수 있는 직접 경로”가 생기고, 그게 깊은 네트워크 학습을 가능하게 만든다.
#
#4 BERT에서 Residual이 들어가는 위치: 한 레이어에 두 번, 중요한 구간마다
Transformer layer는 크게 두 블록으로 나뉜다. 첫 번째는 Self-Attention 블록이고, 두 번째는 FFN(MLP) 블록이다. BERT는 이 두 블록 각각에 residual을 붙인다.
Self-Attention은 “문장 내에서 누구를 얼마나 참고할지”를 계산해 새로운 표현을 만들지만, 이 과정에서 표현이 크게 흔들릴 수도 있다. 그래서 attention 출력에 dropout을 한 뒤 입력 x를 더해준다. 그러면 attention이 실수해도 원본이 살아남는다. 그 다음 LayerNorm으로 스케일을 안정화한다.
FFN은 “토큰별로 비선형 조합을 만들어 특징을 재구성”하는 부분이라, 역시 표현이 크게 변할 수 있다. 그래서 FFN 출력에도 dropout을 하고 다시 입력을 더해준다. 그리고 LayerNorm으로 마무리한다.
즉 BERT는 레이어 안에서 가장 큰 변화가 일어나는 두 지점마다 “원본을 지키는 지름길”을 깔아둔 셈이다.
입력 x ──────────────────────────────────────────────→ 잔차(residual)
↓ ↑
Self-Attention(x) |
→ Dropout |
→ Add ← ─────────────────────────────────── ┘ (잔차 연결 ①)
→ LayerNorm
↓ (새로운 x)
새로운 x ─────────────────────────────────────────────→ 잔차(residual)
↓ ↑
FFN(x): Linear → GELU → Linear |
→ Dropout |
→ Add ← ─────────────────────────────────── ┘ (잔차 연결 ②)
→ LayerNorm
#
#5 Post-Norm과 Pre-Norm: ‘정규화를 어디에 두느냐’가 안정성에 영향을 준다
BERT 원본 구조는 Post-Norm이다. 즉 Add를 먼저 하고 그 다음에 LayerNorm을 한다. 이 구조는 사전학습된 BERT 가중치와 형태가 동일하기 때문에, 그대로 가져와서 fine-tuning하기에 일관성이 좋다.
반면 최근의 많은 트랜스포머 변형은 Pre-Norm을 쓴다. 정규화를 먼저 하고 변환을 한 뒤 마지막에 residual로 더한다. 이 구조는 residual 경로에 “정규화의 영향이 덜 끼는” 형태가 되어, 아주 깊은 모델에서 학습이 더 안정적이라고 알려져 있다. 다만 구조가 달라지면 기존 사전학습 가중치와 정확히 맞지 않는 문제가 생길 수 있어서, BERT 계열에서는 원본 호환을 위해 Post-Norm을 유지하는 경우가 많다.
Post-Norm (BERT 원본, 이 모델):
output = LayerNorm(x + F(x))
← Add 후에 LayerNorm
장점: 원래 BERT 사전학습 가중치와 일치
단점: 깊은 모델에서 학습 불안정 가능
Pre-Norm (최근 트렌드):
output = x + F(LayerNorm(x))
← LayerNorm 후에 F, 그리고 Add
장점: 더 안정적인 학습 (그래디언트 분산 줄어듦)
단점: 사전학습 가중치 구조와 다름
이 모델: Post-Norm (BERT 원본 구조 유지)
#
#6 표현 관점에서의 의미: residual은 “원본 의미가 사라지지 않게” 지켜준다
Residual은 그래디언트만 살리는 장치가 아니다. 표현 자체도 보호한다. 레이어가 깊어질수록 표현은 점점 문맥화되지만, 그 과정에서 원본 단어 정보나 초기 신호가 완전히 사라지면 곤란하다. residual은 매 층마다 “이전 표현을 그대로 가져가는 길”을 남겨두기 때문에, 모델이 필요하면 초기 정보를 계속 유지할 수 있다. 그래서 “bank” 같은 단어가 문맥에 따라 금융기관/강둑으로 갈라지는 과정에서도, 완전히 새로 덮어쓰는 게 아니라 “기존 의미 위에 문맥 정보를 누적해서 얹는” 방식으로 발전할 수 있다.
각 레이어를 통과하면서 표현이 변화:
입력 (BERT Embedding):
"bank" = [일반적인 의미의 벡터]
Layer 1 후 (x + F(x)):
"bank" = [입력 정보 + 주변 단어 문맥 정보 추가]
≈ 입력과 비슷 + 약간의 변화
Layer 6 후:
"bank" = [상당히 변환된 벡터]
"I went to the bank to deposit money"에서
→ bank ≈ 금융 기관 의미 쪽으로
Layer 12 후:
"bank" = [완전히 문맥화된 벡터]
→ 은행/강둑 의미가 완벽히 분리됨
잔차 연결 없으면:
Layer 12를 통과하면 원본 정보가 완전히 사라질 수 있음
→ 이전 레이어들의 중요한 표현 소실
잔차 연결이 있으면:
→ 각 레이어는 "이전 표현에서 뭘 더 알아야 하는가"만 학습
→ 원본 정보가 지름길로 전달됨
#
#cf2 Pre-Norm vs Post-Norm: 그래디언트 비교
Post-Norm에서 그래디언트:
∂Loss/∂x = (LayerNorm의 스케일) × (1 + ∂F/∂x)
LayerNorm이 포함되어 스케일이 변화할 수 있음
깊은 모델에서 미세한 불안정성 가능
Pre-Norm에서 그래디언트:
output = x + F(LayerNorm(x))
∂output/∂x = 1 + ∂F/∂x × (LayerNorm의 Jacobian)
"1 +"이 직접 잔차 경로에 있음
→ 레이어 깊이에 무관하게 그래디언트 1이 보장
#
#8 정리: Residual은 깊은 트랜스포머를 가능하게 만든 가장 단순한 핵심 장치다
Residual connection은 output = x + F(x)라는 단순한 덧셈이지만, 그 효과는 결정적이다. 학습 관점에서는 그래디언트가 흐르는 지름길을 만들어 소실과 폭발을 완화하고, 최적화 관점에서는 레이어가 전체 변환이 아니라 변화량만 학습하게 만들어 학습을 쉽게 한다. 표현 관점에서는 원본 정보가 레이어를 지나며 사라지는 것을 막고, 문맥 정보를 단계적으로 누적시키는 토대를 제공한다. 그래서 BERT처럼 레이어를 여러 개 쌓은 모델이 실제로 학습 가능해진다.
- Residual =
output = x + F(x)(입력을 변환 결과에 그대로 더함) - 역할: 깊은 네트워크에서 그래디언트 소실/폭발 방지
- 직관: F(x)가 “전체 변환"이 아닌 “잔차(변화량)“만 학습 → 더 쉬운 최적화
- BERT 각 레이어에서 2번 사용: Attention Sublayer 후, FFN Sublayer 후
- 항상
Add → LayerNorm순서로 (Post-Norm, BERT 원본 구조) - 파라미터 없음: 단순한 덧셈 연산이지만 깊은 Transformer를 가능하게 하는 핵심 설계