Active Learning (능동 학습)¶
메타 정보¶
| 항목 | 내용 |
|---|---|
| 분류 | Data-Efficient Learning / Human-in-the-Loop ML |
| 핵심 논문 | "Active Learning Literature Survey" (Settles, 2009), "Deep Bayesian Active Learning with Image Data" (Gal et al., ICML 2017), "Deep Batch Active Learning by Diverse, Uncertain Gradient Lower Bounds" (Ash et al., ICLR 2020), "A Survey on Deep Active Learning: Recent Advances and New Frontiers" (Li et al., IEEE TNNLS 2024) |
| 주요 저자 | Burr Settles (종합 서베이), Yarin Gal (BALD/Bayesian AL), Jordan Ash (BADGE), Andreas Kirsch (BatchBALD), Donggeun Yoo (Learning Loss) |
| 핵심 개념 | 모델이 가장 유익한 비레이블 샘플을 능동적으로 선택하여 오라클(인간)에게 레이블링을 요청함으로써, 최소 레이블로 최대 성능을 달성하는 학습 패러다임 |
| 관련 분야 | Semi-Supervised Learning, Data-Centric AI, Annotation, Curriculum Learning, Few-Shot Learning |
정의¶
Active Learning은 레이블링 비용이 높을 때, 모델이 스스로 "어떤 데이터를 레이블링하면 가장 도움이 될까?"를 판단하여 질의(query)하는 반복적 학습 방법론이다.
핵심 문제 설정:
주어진 것:
L = {(x_1, y_1), ..., (x_n, y_n)} 소량 레이블 데이터
U = {x_{n+1}, ..., x_{n+m}} 대량 비레이블 데이터 (m >> n)
B = 레이블링 예산 (한 라운드에 질의 가능한 샘플 수)
f_theta: 현재 모델
목표:
U에서 B개 샘플을 선택하여 레이블링하고 L에 추가함으로써
f_theta의 성능을 최대로 향상시키는 것
액티브 러닝 루프:
for t = 1, 2, ..., T:
1. f_theta를 L로 학습
2. 쿼리 전략 a(x; f_theta)로 U에서 상위 B개 선택: S_t
3. 오라클이 S_t에 레이블 부여
4. L <- L + S_t, U <- U - S_t
5. 종료 조건 확인 (예산 소진, 목표 성능 도달)
vs 랜덤 샘플링:
동일 예산 B x T개 레이블에서
액티브 러닝의 성능 > 랜덤 샘플링의 성능
학습 시나리오¶
Active Learning은 비레이블 데이터에 접근하는 방식에 따라 세 가지 시나리오로 나뉜다.
1. Pool-Based Active Learning (가장 일반적)
+-----------+ 쿼리 전략 +--------+ 레이블 +--------+
| 비레이블 | ----으로 선택---> | 선택된 | ---요청---> | 오라클 |
| 풀 U | | 샘플 | | (인간) |
+-----------+ +--------+ +--------+
^ |
| 레이블된 데이터 |
+---<--- 모델 재학습 ---<--- L에 추가 ---<---------------+
전체 U를 평가하여 최적 B개 선택. 계산 비용 O(|U|)
2. Stream-Based Selective Sampling
데이터가 순차적으로 도착 -> 각 x에 대해 질의 여부 결정
질의 결정: a(x) > threshold 이면 질의, 아니면 패스
메모리 효율적, 실시간 시스템에 적합
3. Membership Query Synthesis
모델이 직접 합성한 인스턴스로 질의
입력 공간의 어떤 점이든 질의 가능
문제: 합성된 인스턴스가 비현실적일 수 있음 (예: 읽을 수 없는 이미지)
쿼리 전략 (Query Strategies)¶
1. 불확실성 기반 (Uncertainty Sampling)¶
모델이 가장 확신하지 못하는 샘플을 선택한다. 가장 직관적이고 널리 사용되는 접근법.
(a) Least Confidence
x* = argmax_{x in U} (1 - P(y_hat | x))
y_hat = argmax_y P(y|x): 최고 확률 클래스
단점: 최고 확률 외 나머지 클래스 정보 무시
(b) Margin Sampling
x* = argmin_{x in U} [P(y_1 | x) - P(y_2 | x)]
y_1, y_2: 확률 1위, 2위 클래스
마진이 작을수록 결정 경계에 가까움
이진 분류에서 Least Confidence와 동치
(c) Entropy Sampling
x* = argmax_{x in U} H(Y|x) = argmax_{x in U} [-sum_c P(y_c|x) log P(y_c|x)]
모든 클래스의 확률 분포를 고려
다중 클래스에서 가장 정보량이 많은 기준
비교:
Least Confidence: P = [0.5, 0.3, 0.2] -> score = 0.5
Margin: P = [0.5, 0.3, 0.2] -> score = 0.2 (작을수록 불확실)
Entropy: P = [0.5, 0.3, 0.2] -> score = 1.03 (클수록 불확실)
2. 위원회 기반 (Query by Committee, QBC)¶
여러 모델의 예측 불일치도가 높은 샘플을 선택한다.
C = {f_1, f_2, ..., f_K}: K개 모델의 위원회
불일치 측정:
(a) Vote Entropy
x* = argmax_{x in U} [-sum_c (V(c,x)/K) log(V(c,x)/K)]
V(c,x): 클래스 c로 예측한 모델 수
(b) KL Divergence (Consensus Entropy)
x* = argmax_{x in U} [1/K sum_k KL(P_k || P_avg)]
P_avg = 1/K sum_k P_k
위원회 구성 방법:
- Bagging: 부트스트랩 샘플로 학습
- Random Subspace: 특성 부분집합
- 다른 초기화 / 아키텍처
- MC Dropout (암묵적 앙상블)
3. 베이지안 액티브 러닝¶
사후 분포의 불확실성을 활용한다. 딥러닝에서 가장 이론적으로 탄탄한 접근법.
BALD (Bayesian Active Learning by Disagreement) [Gal et al., ICML 2017]:
a_BALD(x) = I(y; theta | x, D)
= H(y|x, D) - E_{p(theta|D)}[H(y|x, theta)]
= 예측 엔트로피 (총 불확실성) - 기대 조건부 엔트로피 (알레아토릭)
= 에피스테믹 불확실성 (모델이 모르는 것)
MC Dropout 근사:
1. 드롭아웃을 켠 상태로 T번 전방 패스
2. P(y|x) ~= 1/T sum_{t=1}^T P(y|x, theta_t) <- 예측 엔트로피 계산용
3. 각 theta_t에서의 H(y|x, theta_t) 평균 <- 조건부 엔트로피
장점: 에피스테믹 vs 알레아토릭 불확실성 분리
단점: 다수 전방 패스로 계산 비용 높음
BatchBALD [Kirsch et al., NeurIPS 2019]:
BALD를 배치로 확장. 배치 내 상호 정보량 최대화:
a_BatchBALD(S) = I(y_S; theta | D)
개별 BALD 합산 대비 배치 내 중복 정보 제거
그리디 알고리즘으로 근사 (NP-hard)
4. 다양성 기반 (Diversity Sampling)¶
불확실성만으로는 유사한 샘플이 중복 선택될 수 있다. 다양성 전략은 데이터 공간의 커버리지를 최대화한다.
(a) Core-Set Selection [Sener & Savarese, ICLR 2018]
목표: 레이블 데이터 L과 비레이블 U의 특성 공간에서 최대 거리를 최소화
min_{S subset U, |S|=B} max_{x in U\S} min_{x' in L+S} d(phi(x), phi(x'))
phi(x): 학습된 특성 표현
k-Center 문제로 환원 (2-근사 그리디 알고리즘)
장점: 공간 커버리지 보장
한계: 불확실성 무시, 특성 표현 품질에 의존
(b) TypiClust [Hacohen et al., NeurIPS 2022]
사전학습 표현에서 클러스터링 후 "전형적" (typical) 샘플 선택
초기 라운드(극소량 레이블)에서 특히 효과적
CIFAR-10에서 10개 레이블만으로 93.2% 달성 (사전학습 표현 활용)
(c) ProbCover [Yehuda et al., ICLR 2023]
확률적 커버리지 기반 선택
특성 공간에서 볼 커버리지 최대화
저예산 환경에서 Core-Set 대비 우수
5. 기대 모델 변화 (Expected Model Change)¶
레이블링 후 모델 파라미터 변화가 가장 큰 샘플을 선택한다.
Expected Gradient Length (EGL):
x* = argmax_{x in U} E_{P(y|x)}[||nabla_theta L(f_theta(x), y)||]
각 가능한 레이블 y에 대해:
- 해당 (x, y)의 그래디언트 크기 계산
- 현재 모델의 예측 P(y|x)로 가중 평균
직관: 그래디언트가 크면 모델이 많이 변한다 = 정보가 많다
기대 오류 감소 (Expected Error Reduction):
x* = argmin_{x in U} E_{P(y|x)}[E_loss(f_{theta+(x,y)})]
각 후보 (x,y)를 추가하여 재학습 후 전체 오류 추정
계산 비용 매우 높음 (후보 x B개 각각에 대해 재학습 필요)
6. 하이브리드 및 딥러닝 특화 전략¶
BADGE (Batch Active learning by Diverse Gradient Embeddings)
[Ash et al., ICLR 2020]:
핵심 아이디어: 그래디언트 임베딩 = 불확실성 + 다양성 동시 포착
1. 각 x in U에 대해 "환각 그래디언트" 계산:
g_x = nabla_theta L(f_theta(x), y_hat)
y_hat = argmax_y P(y|x)
마지막 선형 레이어의 그래디언트만 사용 (차원 = 클래스 수 x 특성 차원)
2. g_x에 k-means++ 초기화로 B개 선택
그래디언트 크기 -> 불확실성 반영
그래디언트 방향 -> 다양성 반영
장점: 단순하면서도 불확실성+다양성 자동 균형
ICLR 2020 이후 batch AL의 de facto 기준선
Learning Loss for Active Learning [Yoo & Kweon, CVPR 2019]:
손실 예측 모듈을 부착하여 예측 손실이 높은 샘플 선택
모델 구조와 무관하게 적용 가능
ALFA-Mix [Parvaneh et al., CVPR 2022]:
MixUp 보간으로 결정 경계 근처 샘플 탐색
특성 공간에서 interpolation -> 예측 변화가 큰 영역 식별
실험적 비교¶
주요 벤치마크에서의 전략 비교 (Li et al., IEEE TNNLS 2024 서베이 기반):
CIFAR-10 / ResNet-18 기준 (1000 레이블 예산):
전략 | 정확도(%) | 특징
--------------------- | --------- | ---------------------------
Random | 78.2 | 기준선
Entropy | 81.5 | 단순, 빠름
Core-Set | 80.1 | 다양성, 불확실성 무시
BALD (MC Dropout) | 82.3 | 이론적, 계산 비용 높음
BADGE | 83.1 | 하이브리드, 강력한 기준선
TypiClust | 84.5 | 사전학습 표현 필수
BatchBALD | 82.8 | 배치 상호정보, 확장성 제한
저예산 (50-200 레이블):
TypiClust, ProbCover 등 다양성 기반이 우세
불확실성 기반은 모델이 불안정하여 성능 저하
중/고예산 (1000+ 레이블):
BADGE, BALD 등 하이브리드/불확실성 기반이 우세
모델이 안정화되면서 불확실성 추정이 신뢰성 확보
파운데이션 모델 시대의 Active Learning¶
사전학습 모델과 LLM의 등장으로 Active Learning 패러다임이 변화하고 있다.
1. 사전학습 표현 활용
- 사전학습된 특성 공간에서 클러스터링/다양성 선택
- 모델 학습 없이도 좋은 초기 배치 선택 가능
- TypiClust, ProbCover 계열
2. LLM as Oracle (LLM을 오라클로 활용)
- 인간 대신 LLM이 레이블링 수행
- 비용: 인간 어노테이터 대비 10-100배 저렴
- 품질: 도메인에 따라 인간 수준 또는 그 이하
- 연구: "LLMs in the Loop" (Kholodna et al., 2024)
하이브리드 접근:
쉬운 샘플 -> LLM 레이블링
어려운/불확실 샘플 -> 인간 전문가 레이블링
3. Active Fine-Tuning
- 사전학습 모델의 fine-tuning 데이터를 능동적으로 선택
- 전체 데이터의 일부만으로 full fine-tuning에 근접
- PEFT(LoRA 등)와 결합하여 효율 극대화
4. Active Learning for RLHF
- 인간 피드백 수집의 효율화
- 가장 유익한 비교 쌍(preference pair) 선택
- DPO/RLHF 학습 데이터 최적화
Python 구현 예시¶
1. 기본 Uncertainty Sampling (scikit-learn)¶
import numpy as np
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import make_classification
# 데이터 생성
X, y = make_classification(n_samples=1000, n_features=20,
n_informative=10, random_state=42)
# 초기 레이블 (20개)
n_initial = 20
indices = np.random.RandomState(42).permutation(len(X))
labeled_idx = list(indices[:n_initial])
unlabeled_idx = list(indices[n_initial:])
budget_per_round = 10
n_rounds = 20
accuracies = []
for round_i in range(n_rounds):
# 모델 학습
model = RandomForestClassifier(n_estimators=100, random_state=42)
model.fit(X[labeled_idx], y[labeled_idx])
# 전체 테스트 정확도 (실제로는 별도 테스트셋 사용)
acc = model.score(X, y)
accuracies.append(acc)
if not unlabeled_idx:
break
# 불확실성 계산 (엔트로피)
proba = model.predict_proba(X[unlabeled_idx])
entropy = -np.sum(proba * np.log(proba + 1e-10), axis=1)
# 상위 B개 선택
top_k = min(budget_per_round, len(unlabeled_idx))
query_indices = np.argsort(entropy)[-top_k:]
# 레이블 추가
for idx in query_indices:
labeled_idx.append(unlabeled_idx[idx])
# 풀에서 제거 (역순 정렬 후 제거)
for idx in sorted(query_indices, reverse=True):
unlabeled_idx.pop(idx)
print(f"초기 정확도: {accuracies[0]:.4f}")
print(f"최종 정확도: {accuracies[-1]:.4f}")
print(f"사용 레이블: {n_initial + budget_per_round * n_rounds}")
2. BADGE 구현 (PyTorch)¶
import torch
import torch.nn as nn
import numpy as np
from sklearn.cluster import kmeans_plusplus
class SimpleClassifier(nn.Module):
def __init__(self, input_dim, hidden_dim, num_classes):
super().__init__()
self.features = nn.Sequential(
nn.Linear(input_dim, hidden_dim),
nn.ReLU(),
nn.Linear(hidden_dim, hidden_dim),
nn.ReLU(),
)
self.classifier = nn.Linear(hidden_dim, num_classes)
def forward(self, x):
h = self.features(x)
return self.classifier(h)
def get_features(self, x):
return self.features(x)
def compute_badge_embeddings(model, X_pool, num_classes):
"""BADGE: 환각 그래디언트 임베딩 계산"""
model.eval()
with torch.no_grad():
features = model.get_features(X_pool) # (N, hidden_dim)
logits = model.classifier(features) # (N, num_classes)
probs = torch.softmax(logits, dim=1)
y_hat = torch.argmax(probs, dim=1) # 예측 레이블
# 환각 그래디언트: 마지막 레이어의 그래디언트
# g_x = (p - e_{y_hat}) outer_product h
# 간소화: (p_c - 1[c=y_hat]) * h 를 모든 c에 대해 concat
one_hot = torch.zeros_like(probs)
one_hot.scatter_(1, y_hat.unsqueeze(1), 1.0)
grad_weights = probs - one_hot # (N, num_classes)
# 그래디언트 임베딩: (N, num_classes * hidden_dim)
embeddings = torch.einsum('nc,nh->nch', grad_weights, features)
embeddings = embeddings.reshape(len(X_pool), -1)
return embeddings.numpy()
def badge_query(model, X_pool, budget, num_classes):
"""BADGE: k-means++로 다양한 배치 선택"""
embeddings = compute_badge_embeddings(model, X_pool, num_classes)
# k-means++ 초기화로 B개 중심 선택
_, indices = kmeans_plusplus(embeddings, n_clusters=budget, random_state=42)
return indices
# 사용 예시
# model = SimpleClassifier(input_dim=20, hidden_dim=64, num_classes=2)
# ... 학습 후 ...
# query_idx = badge_query(model, X_pool_tensor, budget=10, num_classes=2)
3. MC Dropout BALD (PyTorch)¶
import torch
import torch.nn.functional as F
class MCDropoutModel(nn.Module):
def __init__(self, input_dim, hidden_dim, num_classes, dropout_rate=0.5):
super().__init__()
self.net = nn.Sequential(
nn.Linear(input_dim, hidden_dim),
nn.ReLU(),
nn.Dropout(dropout_rate),
nn.Linear(hidden_dim, hidden_dim),
nn.ReLU(),
nn.Dropout(dropout_rate),
nn.Linear(hidden_dim, num_classes),
)
def forward(self, x):
return self.net(x)
def bald_acquisition(model, X_pool, n_forward=30):
"""BALD: 에피스테믹 불확실성 추정"""
model.train() # 드롭아웃 활성화 상태 유지
all_probs = []
with torch.no_grad():
for _ in range(n_forward):
logits = model(X_pool)
probs = F.softmax(logits, dim=1)
all_probs.append(probs)
# (T, N, C)
all_probs = torch.stack(all_probs)
# 예측 엔트로피: H[y|x, D]
mean_probs = all_probs.mean(dim=0) # (N, C)
predictive_entropy = -(mean_probs * torch.log(mean_probs + 1e-10)).sum(dim=1)
# 기대 조건부 엔트로피: E[H[y|x, theta]]
per_sample_entropy = -(all_probs * torch.log(all_probs + 1e-10)).sum(dim=2) # (T, N)
expected_entropy = per_sample_entropy.mean(dim=0) # (N,)
# BALD = 에피스테믹 불확실성
bald_scores = predictive_entropy - expected_entropy
return bald_scores.numpy()
# 사용 예시
# scores = bald_acquisition(model, X_pool_tensor, n_forward=30)
# query_idx = np.argsort(scores)[-budget:]
4. modAL 라이브러리 활용¶
from modAL.models import ActiveLearner, Committee
from modAL.uncertainty import entropy_sampling, margin_sampling
from modAL.disagreement import vote_entropy_sampling
from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier
# 단일 모델 액티브 러닝
learner = ActiveLearner(
estimator=RandomForestClassifier(n_estimators=100),
query_strategy=entropy_sampling,
X_training=X_initial,
y_training=y_initial,
)
# 액티브 러닝 루프
for _ in range(n_rounds):
query_idx, query_inst = learner.query(X_pool, n_instances=10)
learner.teach(X_pool[query_idx], y_pool[query_idx])
X_pool = np.delete(X_pool, query_idx, axis=0)
y_pool = np.delete(y_pool, query_idx, axis=0)
# QBC (위원회 기반)
learner1 = ActiveLearner(estimator=RandomForestClassifier(),
X_training=X_initial, y_training=y_initial)
learner2 = ActiveLearner(estimator=GradientBoostingClassifier(),
X_training=X_initial, y_training=y_initial)
committee = Committee(
learner_list=[learner1, learner2],
query_strategy=vote_entropy_sampling,
)
query_idx, _ = committee.query(X_pool, n_instances=10)
실무 적용 가이드¶
전략 선택 기준¶
의사결정 트리:
레이블 예산이 극히 적은가? (< 100)
|-- Yes -> 사전학습 표현 + 다양성 기반 (TypiClust, ProbCover)
|-- No -> 모델이 확률 예측을 제공하는가?
|-- Yes -> 불확실성 + 다양성 하이브리드 (BADGE)
|-- No -> Core-Set 또는 Learning Loss
배치 크기가 큰가? (> 100)
|-- Yes -> 배치 다양성 필수 (BADGE, BatchBALD, DPP)
|-- No -> 단순 불확실성도 효과적 (Entropy, BALD)
도메인:
- 텍스트 분류: Entropy + 길이/다양성 결합
- 이미지 분류: BADGE 또는 Core-Set
- 객체 탐지: Learning Loss (박스 수준 불확실성)
- 의료 영상: BALD (불확실성 해석 필요)
- 시계열: 윈도우 수준 불확실성 + 시간적 다양성
흔한 함정과 해결책¶
| 함정 | 원인 | 해결 |
|---|---|---|
| 샘플링 편향 | 불확실성만 추구하여 특정 영역에 집중 | 다양성 전략 결합 (BADGE, Core-Set) |
| 콜드 스타트 | 초기 모델이 부정확하여 쿼리 전략 실패 | 첫 라운드는 랜덤 또는 클러스터 중심 선택 |
| 중복 선택 | 배치 내 유사한 샘플 반복 | BatchBALD, DPP, k-means++ 기반 다양화 |
| 클래스 불균형 악화 | 소수 클래스가 불확실성 높아 편향 | 클래스 비율 제약 또는 계층적 샘플링 |
| 노이즈 레이블 | 어려운 샘플일수록 레이블 오류율 높음 | 품질 검증 루프, 다수 어노테이터, LLM 교차 검증 |
| 과도한 계산 비용 | BALD의 다수 전방 패스, EGL의 그래디언트 계산 | 서브샘플링, 근사 방법, 배치 병렬화 |
종료 조건 설정¶
1. 예산 기반: 총 B_total개 레이블 소진 시 종료
2. 성능 기반: 검증셋 성능이 목표치 도달
3. 수렴 기반: 추가 레이블의 성능 개선이 임계값 이하
4. 불확실성 기반: 비레이블 풀의 최대 불확실성이 임계값 이하
실무 권장:
- 예산 기반을 기본으로 설정
- 성능 기반을 조기 종료 조건으로 추가
- 매 라운드 검증셋 성능 모니터링
참고 문헌¶
| 논문 | 저자 | 출처 | 기여 |
|---|---|---|---|
| "Active Learning Literature Survey" | Settles | UW-Madison TR 2009 | 전통적 AL 종합 서베이, 쿼리 전략 분류 체계 확립 |
| "Deep Bayesian Active Learning with Image Data" | Gal, Islam, Ghahramani | ICML 2017 | BALD + MC Dropout으로 딥러닝 AL 개척 |
| "Active Learning for CNNs: A Core-Set Approach" | Sener, Savarese | ICLR 2018 | Core-Set 기반 다양성 전략, 기하학적 접근 |
| "BatchBALD: Efficient and Diverse Batch Acquisition for Deep Bayesian AL" | Kirsch, van Amersfoort, Gal | NeurIPS 2019 | BALD의 배치 확장, 상호 정보량 기반 |
| "Learning Loss for Active Learning" | Yoo, Kweon | CVPR 2019 | 손실 예측 모듈, 모델 무관 접근 |
| "Deep Batch AL by Diverse, Uncertain Gradient Lower Bounds" | Ash, Zhang, Krishnamurthy, Langford, Agarwal | ICLR 2020 | BADGE, 그래디언트 임베딩으로 불확실성+다양성 통합 |
| "Active Learning at the ImageNet Scale" | Hacohen, Dekel, Weinshall | NeurIPS 2022 | TypiClust, 사전학습 표현 기반 저예산 AL |
| "Stochastic Batch Acquisition" | Kirsch, Rainforth, Gal | TMLR 2023 | 확률적 배치 선택, 단순하지만 효과적 |
| "A Survey on Deep Active Learning" | Li, Wang et al. | IEEE TNNLS 2024 | 최신 DAL 종합 서베이 (300+ 논문) |
| "A Survey of Deep Active Learning for Foundation Models" | (multiple) | Intelligent Computing 2024 | 파운데이션 모델 시대 AL 서베이 |
구현 도구¶
| 도구 | 언어 | 특징 |
|---|---|---|
| modAL | Python (scikit-learn) | 가장 직관적, 교육용 |
| baal (BayesianAL) | Python (PyTorch) | MC Dropout, BALD 등 베이지안 특화 |
| small-text | Python (PyTorch/Transformers) | NLP 특화, Transformer 통합 |
| ALiPy | Python | 다양한 전략, 벤치마크 지원 |
| libact | Python | 경량, Pool-based 특화 |