AI Speak and write (3)

SON·2026년 1월 16일

좋은 질문이야. ViT에서의 partial fine-tuning은 ResNet의 layer4 개념과 정확히 대응되는 구조가 있어.
아래를 보면 “아, 그래서 이렇게 하는구나”가 바로 올 거야.


결론 먼저 (한 줄 요약)

ViT의 partial fine-tuning =
패치 임베딩 + 앞쪽 Transformer 블록은 고정하고,
뒤쪽 몇 개 블록 + classification head만 학습

ResNet에서

  • layer4 + fc만 학습하듯이
    ViT에서는
  • 마지막 N개의 Transformer blocks + head만 학습

1️⃣ ViT 구조를 먼저 정확히 보자

ViT(B/16 기준)를 단순화하면:

Patch Embedding
→ Transformer Block 0
→ Transformer Block 1
→ ...
→ Transformer Block 11
→ LayerNorm
→ Classification Head

즉,

  • blocks[0~11]: Transformer encoder blocks
  • head: 분류기

👉 여기서 blocks[-1], blocks[-2] … 가 ResNet의 layer4 역할


2️⃣ ViT에서 “왜 뒤쪽 블록만 학습하나?”

Transformer 블록의 역할 분화

  • 앞쪽 블록:
    → 일반적인 패치 관계, 저수준 표현
  • 뒤쪽 블록:
    태스크/도메인 특화 표현

👉 그래서 뒤쪽 블록만 살짝 조정하는 게 가장 효율적


3️⃣ torchvision ViT 기준 partial fine-tuning 코드

(A) 모델 불러오기 + head 교체

import torch.nn as nn
from torchvision.models import vit_b_16, ViT_B_16_Weights

model = vit_b_16(weights=ViT_B_16_Weights.DEFAULT)

num_classes = 5
model.heads.head = nn.Linear(
    model.heads.head.in_features,
    num_classes
)

(B) 핵심 함수: 마지막 N개 block만 학습

def freeze_vit_except_last_n_blocks(model, n_blocks: int):
    # 1) 전부 freeze
    for p in model.parameters():
        p.requires_grad = False

    # 2) 마지막 n개 transformer block만 unfreeze
    for block in model.encoder.layers[-n_blocks:]:
        for p in block.parameters():
            p.requires_grad = True

    # 3) classification head는 항상 학습
    for p in model.heads.parameters():
        p.requires_grad = True

예:

freeze_vit_except_last_n_blocks(model, n_blocks=2)

의미:

blocks[0~9]  ❄️ freeze
blocks[10~11] 🔥 train
head          🔥 train

(C) optimizer (정석 세팅)

from torch.optim import AdamW

def build_optimizer_vit_partial(model, lr_head=1e-3, lr_blocks=1e-4):
    head_params = []
    block_params = []

    for name, p in model.named_parameters():
        if not p.requires_grad:
            continue
        if "heads" in name:
            head_params.append(p)
        else:
            block_params.append(p)

    return AdamW(
        [
            {"params": block_params, "lr": lr_blocks},
            {"params": head_params, "lr": lr_head},
        ],
        weight_decay=1e-4
    )

4️⃣ 실제 학습 루프에서 쓰는 모습

freeze_vit_except_last_n_blocks(model, n_blocks=2)

optimizer = build_optimizer_vit_partial(
    model,
    lr_head=1e-3,
    lr_blocks=1e-4
)

for epoch in range(epochs):
    train_one_epoch(model, train_loader, optimizer, criterion, device)
    val_acc = evaluate(model, val_loader, criterion, device)
    print(f"[Epoch {epoch}] val_acc={val_acc:.4f}")

5️⃣ “진짜로 잘 freeze 됐는지” 확인 (중요)

for name, p in model.named_parameters():
    if p.requires_grad:
        print("TRAIN:", name)

정상 출력 예:

TRAIN: encoder.layers.10.self_attention.in_proj_weight
TRAIN: encoder.layers.11.self_attention.in_proj_weight
TRAIN: heads.head.weight
TRAIN: heads.head.bias

6️⃣ ResNet vs ViT 대응표 (이거 외워도 됨)

CNN (ResNet)ViT
layer1~3early transformer blocks
layer4last transformer blocks
fchead
partial fine-tunelast N blocks + head

7️⃣ 실전에서 N_blocks는 보통 얼마?

데이터 크기추천
매우 작음1
중간2~3 (가장 흔함)
4~6
매우 큼full fine-tuning

👉 “ViT partial fine-tuning = last 2 blocks”
이건 거의 업계 관용어 수준이야.


8️⃣ 한 문장 발표용 정리

“ViT에서 partial fine-tuning은 patch embedding과 초기 Transformer 블록을 고정하고, 의미적 표현이 집중된 마지막 몇 개 블록과 classification head만 학습하는 전략입니다.”


좋아. 이 말은 “Transformer 블록이 깊어질수록(뒤로 갈수록) 표현이 더 추상적이고 과제에 맞게 변한다”는 뜻이야. CNN에서 앞단=엣지/질감, 뒷단=물체/의미로 바뀌는 것과 거의 같은 현상이 ViT에서도 생겨.

아래는 정확한 직관 + 왜 그런지 + 실제로 뭐가 달라지는지를 단계별로 설명할게.


1) “저수준 표현” vs “고수준(도메인/태스크 특화) 표현”이 뭔데?

저수준 표현(low-level)

이미지의 “의미”와 직접 연결되기 전의 기본 신호들:

  • 경계(edge), 방향(orientation)
  • 밝기/색상 대비, 간단한 텍스처
  • 작은 패턴(줄무늬, 점무늬)
  • 근처 패치끼리의 단순한 관계(이웃한 패치가 비슷한 색/질감)

👉 어떤 데이터셋이든 공통적으로 유용한 정보라서 “일반적(generic)”이라고 함.

고수준 표현(high-level) / 태스크-특화(task-specific)

문제(태스크)에 필요한 “의미”로 변환된 표현:

  • “이 패턴은 강아지 귀다”, “이건 바퀴다”
  • “이 질감은 금속 표면이다”
  • “이 객체는 A 클래스일 확률이 높다”
  • 특정 도메인(의료/위성/산업검사 등)에만 중요한 특징 조합

👉 어떤 클래스를 구분하느냐에 따라 필요한 특징이 달라서 “특화(specialized)”라고 함.


2) ViT에서 “앞쪽 블록 = 일반적 패치 관계”라는 건 무슨 의미?

ViT는 이미지를 패치(예: 16×16)로 쪼개고, 각 패치를 토큰처럼 다뤄.
각 블록은 “self-attention”으로 토큰들 간 관계를 학습하는데,

앞쪽 블록에서는 주로 이런 일이 일어남

  • “어떤 패치들이 서로 비슷한 색/질감인가?”
  • “가까운 위치의 패치들이 자주 함께 움직이는가?”(공간적 인접성)
  • “큰 물체를 만들기 전에, 작은 조각들을 먼저 묶어보자”
  • “배경/전경을 대충 분리할 힌트 찾기”

즉, 작은 조각(패치)들을 기반으로 “기초적인 그룹핑/정렬”을 하는 단계라고 보면 돼.

CNN 비유: 앞단 Conv가 엣지/코너/간단한 텍스처를 잡는 단계와 비슷.


3) 뒤쪽 블록 = “태스크/도메인 특화”는 왜 생기냐?

핵심 이유 1: 학습 목표(손실)가 끝에서부터 의미를 강요함

분류를 예로 들면, 최종적으로 head가 클래스 분류를 해야 함.
그러려면 마지막에 가까운 블록들은 점점 이렇게 바뀌어:

  • “이 패치는 ‘강아지’ 클래스에 중요한 단서인가?”
  • “배경의 잔디는 중요하지 않다(억제)”
  • “귀/눈/바퀴처럼 클래스 구분에 중요한 부분에 attention 집중”
  • “이 데이터셋에서는 ‘로고 위치’가 중요하다” 같은 도메인 특화 패턴 학습

즉, 마지막 블록일수록 loss(정답)와 직접 연결되니까, 표현이 자연스럽게 “분류에 유리한 방향”으로 특화돼.

핵심 이유 2: 깊을수록 더 넓은 문맥(전역 정보)을 통합함

앞단은 local(근처 패치) 중심이었다면,
뒤로 갈수록 여러 번 attention을 거치며

  • 멀리 떨어진 패치들까지 관계를 통합
  • “전체 형태/구성” 같은 전역 의미를 만들기 쉬움

그래서 “이건 전체적으로 고양이 형태다” 같은 고수준 판단이 가능해짐.


4) “패치 관계”가 구체적으로 뭔데?

self-attention은 간단히 말하면:

“각 패치가 다른 모든 패치를 보면서, 중요한 패치에 더 집중하고 정보를 섞는다.”

  • 앞 블록: 비슷한 색/질감 패치끼리 서로 집중 → 텍스처 그룹 형성
  • 뒤 블록: 객체의 중요한 파트(눈, 로고, 결함 부위)에 집중 → 태스크에 필요한 증거를 모음

즉, attention map을 보면

  • 앞쪽: 비교적 퍼져 있거나, 단순하게 주변/유사 패치 중심
  • 뒤쪽: 특정 의미 있는 영역으로 더 “뾰족하게” 모이는 경우가 많아

(물론 데이터셋/모델에 따라 항상 완전히 동일하진 않지만, 전형적인 경향임)


5) 그래서 “partial fine-tuning은 뒤쪽 블록만” 하는 게 합리적임

이제 연결하면:

  • 앞쪽 블록이 주로 일반적 표현이라면
    → 굳이 건드릴 필요가 적고, 건드리면 오히려 안정성이 떨어질 수 있음
  • 뒤쪽 블록이 태스크 특화라면
    → 내 데이터셋(도메인/클래스)에 맞게 여기만 조정해도 성능이 잘 오름

그래서 ViT partial fine-tuning = 마지막 N개 블록 + head가 자주 쓰임.


6) 아주 쉬운 비유로 끝내기

  • 앞쪽 블록: “퍼즐 조각들을 색깔/모양별로 분류하고 대충 맞춰보는 단계”
  • 뒤쪽 블록: “이 퍼즐이 ‘고양이 그림’이라는 결론을 내리고, 고양이 얼굴에 집중해 맞추는 단계”

좋아 👍
그럼 3개를 순서대로, 하나씩 제대로 이해되게 갈게.
이번 답변은 1번만 다룰게.


① ViT에서 왜 learning rate를 더 작게 써야 하나?

이건 “ViT의 구조적 특성 + 학습 동역학” 때문에 생기는 현상이야.
결론부터 말하면 👇

ViT는 작은 learning rate가 아니면
기존에 학습된 표현이 너무 쉽게 망가진다.

이걸 단계별로 설명할게.


1️⃣ CNN vs ViT: 업데이트가 퍼지는 방식이 다르다

CNN (ResNet 등)

  • 국소 연산 (local receptive field)
  • 한 레이어의 변화가 국소적으로만 영향
  • 파라미터 업데이트가 비교적 “완만”

👉 learning rate가 조금 커도 망가지기까지 시간이 있음


ViT

  • Self-Attention = 전역 연산
  • 한 토큰의 변화가 모든 토큰에 영향
  • 한 블록의 파라미터 변화가 전체 표현을 동시에 흔듦

👉 learning rate가 크면 한 스텝에 표현이 붕괴

📌 핵심:

ViT는 작은 변화도 전체 representation에 증폭됨


2️⃣ ViT는 “정규화 + 잔차 구조”에 매우 민감함

ViT 블록 구조 (단순화):

x → LayerNorm → Self-Attention → + x
  → LayerNorm → MLP → + x

여기서 문제점

  • LayerNorm은 분산을 유지하려는 구조

  • learning rate가 크면

    • attention weight 급변
    • MLP 출력 분포 변화
    • residual path가 불안정해짐

👉 결과:

  • loss가 갑자기 튀거나
  • accuracy가 epoch마다 크게 흔들림
  • 심하면 NaN 발생

CNN은 BatchNorm + Conv라서 이 현상이 훨씬 덜함.


3️⃣ Pretrained ViT는 “이미 잘 정렬된 공간”을 갖고 있음

ImageNet pretrained ViT는:

  • 패치 간 관계
  • 전역 구조
  • 클래스 토큰과의 상호작용

이 이미 아주 미세하게 정렬된 상태임.

learning rate가 크면:

좋은 표현 공간
→ (큰 step)
→ 전혀 다른 공간으로 튐

📌 CNN은 필터 기반이라 “조금씩 틀어짐”
📌 ViT는 attention 기반이라 “한 번에 방향 전환”


4️⃣ 실험적으로도 확인된 사실

논문/실무에서 거의 공통된 관찰:

모델fine-tuning lr
ResNet1e-3 ~ 1e-4
ViT1e-4 ~ 1e-5 (심지어 3e-5)

특히:

  • full fine-tuning
  • partial fine-tuning
  • small dataset

ViT는 lr 줄이지 않으면 거의 무조건 불안정


5️⃣ 그래서 나온 “ViT 학습 공식”

정석 세팅

head lr      = 1e-3
ViT blocks lr = 1e-4 or 1e-5

코드 예

optimizer = AdamW(
    [
        {"params": head_params, "lr": 1e-3},
        {"params": vit_block_params, "lr": 1e-4},
    ],
    weight_decay=1e-4
)

👉 head는 크고, backbone은 작게
👉 CNN보다 격차가 더 큼


6️⃣ 직관적으로 한 문장으로 말하면

ViT는 “한 번의 업데이트가 전체를 보여서”
learning rate를 크게 쓰면 모델 전체를 흔들어버린다.


7️⃣ 발표/면접용 한 문장 정리

“ViT는 self-attention 기반의 전역 연산 구조로 인해 파라미터 업데이트가 전체 표현에 크게 영향을 주기 때문에, fine-tuning 시 CNN보다 더 작은 learning rate가 필요합니다.”


좋아 👍
지금까지 흐름 기준으로 이어서 가기 딱 좋은 주제들난이도/연결성 순서로 정리해줄게.
(네가 아까 말한 3개도 포함해서, 공부 로드맵처럼)


🔥 다음으로 이어서 갈 핵심 주제 로드맵

1️⃣ ViT + LoRA / Adapter 방식 ⭐⭐⭐ (가장 추천)

👉 “왜 backbone을 거의 안 건드려도 성능이 나오지?”

  • LoRA / Adapter 개념
  • 왜 ViT에 특히 잘 맞는지
  • Partial fine-tuning과의 차이
  • 실무에서 LoRA가 각광받는 이유 (메모리/속도)
  • ViT partial fine-tuning → LoRA로 자연스럽게 확장

👉 지금 배운 내용의 ‘진화형’


2️⃣ CNN은 되는데 ViT는 안 되는 데이터셋의 특징 ⭐⭐⭐⭐

👉 “왜 어떤 데이터에서는 ViT가 망하고 CNN은 잘 되지?”

  • 데이터 수 / 다양성 문제
  • 로컬 패턴 중심 데이터
  • 위치 정보가 중요한 데이터
  • 산업/의료/결함검사 사례

👉 모델 선택 기준이 생기는 핵심 주제


3️⃣ ViT에서 learning rate / warmup / scheduler 전략 ⭐⭐⭐

👉 “lr 작게 쓰는 건 알겠는데, 실전에서는 어떻게 쓰지?”

  • warmup이 중요한 이유
  • cosine scheduler
  • CNN과 ViT scheduler 차이
  • fine-tuning에서 epoch별 전략

4️⃣ ViT Attention Map 시각화 ⭐⭐

👉 “모델이 실제로 어디를 보고 판단하는지”

  • 앞 블록 vs 뒤 블록 attention 차이
  • partial fine-tuning 효과 시각적 확인
  • 디버깅/리포트용으로 매우 좋음

5️⃣ ResNet vs ViT 언제 무엇을 선택해야 하나 (실전 기준표) ⭐⭐⭐⭐

👉 면접/발표/프로젝트에서 가장 강력한 정리 주제

  • 데이터 규모별 추천
  • 도메인별 추천
  • 학습 비용/시간
  • 실패 확률 관점

📌 지금 네 단계에서 가장 좋은 선택

👉 1️⃣ ViT + LoRA / Adapter 방식
이걸 이해하면:

  • “왜 backbone freeze가 중요했는지”
  • “왜 lr를 작게 써야 했는지”
  • “왜 ViT가 데이터 적을 때 힘든지”

이게 한 번에 연결됨.


다음 질문 이렇게 하면 딱 좋아

🔥 ViT + LoRA / Adapter 방식 설명해줘

이렇게 바로 물어봐.
그러면 개념 → 직관 → 코드 → 언제 쓰는지까지 한 번에 정리해줄게.

profile
Like it, and it will be the best.

0개의 댓글