ViT와 시계열 Transformer 모델링 설계 전략
Vision Transformer와 Time Series Transformer의 토큰화, 어텐션 설계, 학습·배포 운영 전략을 정리한다.
2026-08-14 · 최초 발행 2024-04-29
이미지 패치와 시간 윈도에서 시작하는 Transformer
Vision Transformer(ViT)와 Time Series Transformer(TST)는 입력을 토큰 시퀀스로 바꾼 뒤 어텐션으로 관계를 학습한다는 점에서는 같다. 차이는 토큰이 담는 구조다. ViT는 이미지의 2D 공간을 패치로 바꾸고, TST는 시간 흐름과 다변량 관측치를 윈도 또는 패치로 다룬다.
ViT는 이미지를 고정 크기 패치로 나누고 각 패치를 선형 임베딩한 뒤 Transformer Encoder에 넣는 아키텍처다. CNN보다 유도 귀납 편향이 적기 때문에 대규모 사전학습(SSL/SL)에서 강한 일반화 성능을 낼 수 있다. 패치 크기, 해상도, 사전학습 데이터의 규모는 성능과 자원 사용량에 직접 영향을 준다.
TST는 시계열을 일정 길이의 윈도나 패치로 토큰화하고 Positional Encoding, Time2Vec, 연령 인코딩 등의 시간 인지 정보를 결합한다. 이후 Transformer Encoder 또는 Decoder가 예측·분류·탐지를 수행한다. 긴 종속성, 불규칙 샘플링, 결측 처리는 어텐션과 마스킹으로 다루며, O(L^2) 비용이 부담되는 긴 시퀀스에서는 선형·희소 어텐션, FFT, 저랭크 근사를 활용한다.
입력 표현과 인코더 설계에서 결정되는 차이
두 모델 모두 입력을 토큰으로 변환하고 순서 정보를 보존해야 한다. 위치 인코딩에는 절대·상대·로터리(ROPE) 방식을 적용할 수 있다. Self-Attention 계층은 멀티헤드로 여러 서브공간의 표현을 강화하고, Pre-LN, Dropout/Stochastic Depth, LayerScale은 학습 안정성을 위한 선택지다. 출력부는 분류, 회귀, 분할, 탐지 목적에 맞춰 별도로 설계하며, 멀티태스크라면 공유 인코더와 분기 헤드를 구성할 수 있다.
ViT에서는 H×W 이미지를 P×P 패치로 분할해 선형 투영하고, [CLS] 토큰으로 전역 표현을 집약한다. 패치가 커지면 연산량은 줄지만 세부 표현은 손실될 수 있다. 2D 위치 인코딩은 절대 PE로 단순하게 구성하거나, 이동과 스케일 변화에 더 강인한 상대 PE를 선택할 수 있다. 고해상도 입력에서는 인터폴레이션도 사용한다.
학습에서는 RandAugment, Mixup, CutMix 같은 강한 증강과 라벨 스무딩, AdamW, Cosine LR 조합을 활용한다. 자원이 제한된 조건에서는 MAE 사전학습이나 DeiT distillation으로 데이터 효율성을 높일 수 있다.
TST는 다변량 특징을 선형 투영해 토큰을 만들고, 시간 간격·캘린더 피처·마스킹 벡터를 함께 넣어 불규칙성을 반영한다. 미래 정보 누설을 피하려면 Causal 마스킹이 필요하다. 긴 시퀀스에는 Performer, Linformer, Longformer, Informer를 선택할 수 있고, 시계열 전용 모델로 iTransformer와 TSMixer도 고려 대상이다.
결측값은 임베딩 단계에서 결측 마스크를 입력으로 전달할 수 있다. 전진 채움이나 중앙값 같은 간단한 임퓨테이션을 적용하거나 Denoising 목표를 병행하는 방식도 가능하다. 이때 학습·검증 데이터를 시간 순서로 엄격히 분리해야 레이블 누설을 막을 수 있다.
데이터 검증부터 배포까지의 흐름
모델링은 데이터 형식, 범위, 결측을 확인하고 스키마와 라벨 무결성을 점검하는 단계에서 시작한다. 이어 이미지 패치 또는 시계열 윈도를 만들고, 스케일링과 위치·시간 인코딩을 결합한다.
학습 구성에서는 손실 함수, 스케줄러, 정규화, 마스킹과 증강을 정하고 혼합 정밀도·체크포인트·분산 전략을 선택한다. 검증과 배포 단계에서는 오프라인 벤치마크, 온라인 A/B, 모니터링 지표와 알림을 연결한다.
입력 제약도 초기에 처리해야 한다.
- 이미지 크기 % 패치 크기 ≠ 0이면 패딩 또는 리사이즈가 필요하다.
- 시계열 결측 비율 > 임계값이면 샘플을 제외하거나 강건한 임퓨테이션 파이프라인을 적용한다.
- 시퀀스 길이 > 최대 토큰 길이면 중첩된 슬라이딩 윈도로 나누고 메모리 제약에 맞춰 배치를 조정한다.
도메인별 적용 시 고려할 점
ViT는 제조 결함 검사에서 고해상도 이미지 분류와 세그멘테이션에 사용할 수 있다. 라벨이 부족한 경우 MAE 사전학습 후 소량 파인튜닝을 적용한다. 의료 영상에서는 병변 검출과 세그멘테이션에 쓰이며, 강건성을 위해 stain normalization과 Test-Time Augmentation을 병행한다. 위성·원격탐사에서는 다중스펙트럼 입력, 대해상도 타일링, 메타데이터 인코딩을 함께 고려한다.
TST는 에너지·물류·클라우드 리소스의 수요와 부하 예측에 활용되며, 캘린더·이벤트 피처와 외생 변수를 결합한다. AIOps와 Observability에서는 다변량 지표의 이상탐지에 적용하고, 결측 마스크와 변동성 스케일링으로 오탐을 줄인다. 금융 신호 처리에서는 다주기 패턴을 포착하고 원인 분석을 위해 어텐션을 가시화할 수 있다.
성능 기대와 비용의 균형
ImageNet-1k 기준으로 ViT-B 계열은 강한 레시피와 사전학습을 적용했을 때 ResNet-50 대비 Top-1 정확도 우위가 보고됐다. 최신 수치는 변동하므로 최신 정보 확인이 필요하다. 고해상도 입력에서는 토큰 수가 증가하면서 정확도는 상승할 수 있지만 지연도 함께 증가한다.
TST는 공공 벤치마크에서 RNN/LSTM 대비 MSE/MAE 개선 사례가 다수 보고됐다. 다만 데이터와 윈도 설계에 민감하므로 최신 정보 확인이 필요하다. 선형·희소 어텐션을 이용해 O(L)~O(L log L) 근사를 적용하면 지연과 메모리를 줄일 수 있다.
두 계열 모두 장기 의존성과 다변량 상호작용을 모델링하고, 태스크 간 파라미터 공유로 유지보수성을 높일 수 있다. 사전학습과 전이학습은 라벨 비용을 줄이고 도메인 적응의 유연성을 높이는 수단이다.
학습과 운영에서 놓치기 쉬운 제약
ViT는 강한 증강과 대규모 사전학습을 중심으로 설계한다. 패치 크기(P)와 해상도(HW)를 정할 때 토큰 수 ~ (H/P)*(W/P) 제곱 스케일 비용을 함께 검토해야 한다.
TST는 Train/Val split을 시간 축으로 나눠 누설을 막고, RobustScaler 또는 Per-series normalization과 결측 마스크 입력을 병행한다. 긴 시퀀스에서는 Performer, Linformer, Longformer, Informer 중 하나를 선택하되 근사 오차와 지연 절감 사이의 트레이드오프를 평가한다.
공통적으로 Mixed Precision(FP16/BF16), Gradient Checkpointing, FlashAttention, Pre-LN, LayerScale, Stochastic Depth를 사용할 수 있다. Warmup과 Cosine 스케줄, AdamW(β2 조정 0.95~0.999), grad-norm 클리핑은 학습 안정화에 활용된다. 라벨 스무딩과 EMA는 일반화 향상에 쓰이며, 시계열 학습에서는 teacher forcing와 scheduled sampling을 조합할 수 있다.
배포 시에는 TorchScript, ONNX, TensorRT로 컴파일과 최적화를 수행하고, 윈도 기반 스트리밍 추론을 위해 rolling buffer를 구성한다. 운영 지표는 입력 분포와 드리프트, 지연과 메모리, 예측 잔차와 알람율을 포함하며 재학습 파이프라인 자동화까지 연결한다.
모델별 운영 조건
| 항목 | ViT | TST |
|---|---|---|
| 성능 | 대규모 사전학습 시 최상급 이미지 인식 성능. 고해상도에서 강점 | 장기 의존성·다변량 상호작용 모델링 우수. 데이터 설계 민감 |
| 확장성 | 토큰 수 제곱 스케일. 패치/해상도로 제어 | 시퀀스 길이 제곱 스케일. 선형/희소 어텐션으로 완화 |
| 일관성 | 다양한 시각 태스크에 전이 용이 | 도메인·주기성·불규칙성에 따라 성능 변동 큼 |
| 안정성 | Pre-LN, 증강, 사전학습으로 안정 | 결측/누설 관리가 안정성 핵심. 마스킹 설계 중요 |
| 운영 편의 | 배치 추론 용이, 대용량 메모리 요구 | 스트리밍/온라인 추론 적합, 윈도 관리 필요 |
PyTorch로 구성한 ViT 분류 예시
# pip install torch torchvision
import torch, torch.nn as nn
class PatchEmbed(nn.Module):
def __init__(self, img_size=224, patch=16, in_ch=3, dim=768):
super().__init__()
self.proj = nn.Conv2d(in_ch, dim, kernel_size=patch, stride=patch)
self.num_patches = (img_size // patch) ** 2
def forward(self, x):
x = self.proj(x) # B, dim, H/P, W/P
x = x.flatten(2).transpose(1, 2) # B, N, dim
return x
class ViT(nn.Module):
def __init__(self, img_size=224, patch=16, dim=384, depth=6, heads=6, mlp=768, nclass=1000):
super().__init__()
self.pe = nn.Parameter(torch.zeros(1, (img_size//patch)**2 + 1, dim))
self.cls = nn.Parameter(torch.zeros(1, 1, dim))
self.embed = PatchEmbed(img_size, patch, 3, dim)
encoder_layer = nn.TransformerEncoderLayer(d_model=dim, nhead=heads, dim_feedforward=mlp, batch_first=True, norm_first=True)
self.encoder = nn.TransformerEncoder(encoder_layer, num_layers=depth)
self.head = nn.Linear(dim, nclass)
nn.init.trunc_normal_(self.pe, std=0.02); nn.init.trunc_normal_(self.cls, std=0.02)
def forward(self, x):
tok = self.embed(x) # B,N,C
cls = self.cls.expand(x.size(0), -1, -1)
x = torch.cat([cls, tok], dim=1) + self.pe
x = self.encoder(x)
return self.head(x[:,0])
# dummy train step
device = "cuda" if torch.cuda.is_available() else "cpu"
model = ViT().to(device)
opt = torch.optim.AdamW(model.parameters(), lr=3e-4, weight_decay=0.05)
scaler = torch.cuda.amp.GradScaler(enabled=(device=="cuda"))
model.train()
for _ in range(2):
imgs = torch.randn(8,3,224,224, device=device)
labels = torch.randint(0,1000,(8,), device=device)
opt.zero_grad()
with torch.cuda.amp.autocast(enabled=(device=="cuda")):
logits = model(imgs)
loss = nn.CrossEntropyLoss(label_smoothing=0.1)(logits, labels)
scaler.scale(loss).backward()
scaler.step(opt); scaler.update()
입력 이미지 크기 224, 패치 16, 분류 클래스 1000을 가정한다. 이미지 크기가 패치로 나누어떨어지지 않으면 패딩 또는 리사이즈가 필요하다.
PyTorch로 구성한 다변량 시계열 예측 예시
# pip install torch
import torch, torch.nn as nn
class TST(nn.Module):
def __init__(self, d_in=8, d_model=256, depth=4, heads=4, ff=512, out_horizon=24):
super().__init__()
self.proj = nn.Linear(d_in, d_model)
self.pe = nn.Parameter(torch.zeros(1, 1024, d_model)) # 최대 길이 1024 가정
enc_layer = nn.TransformerEncoderLayer(d_model=d_model, nhead=heads, dim_feedforward=ff, batch_first=True, norm_first=True)
self.encoder = nn.TransformerEncoder(enc_layer, num_layers=depth)
self.head = nn.Linear(d_model, out_horizon) # 단일 타깃 예측 가정
nn.init.trunc_normal_(self.pe, std=0.02)
def forward(self, x, attn_mask=None):
# x: B,T,D
T = x.size(1)
z = self.proj(x) + self.pe[:, :T]
z = self.encoder(z, mask=attn_mask)
# 마지막 토큰의 표현으로 미래 예측
y = self.head(z[:, -1])
return y
# dummy data: B=16, T=96, D=8, 예측 24 스텝
device = "cuda" if torch.cuda.is_available() else "cpu"
model = TST().to(device)
opt = torch.optim.AdamW(model.parameters(), lr=2e-4, weight_decay=0.01)
criterion = nn.L1Loss()
model.train()
for _ in range(2):
x = torch.randn(16, 96, 8, device=device)
target = torch.randn(16, 24, device=device)
# causal mask(필요 시): 현재 단순 인코더로 과거만 입력
opt.zero_grad()
y = model(x)
loss = criterion(y, target)
loss.backward(); opt.step()
이 구현은 단일 타깃 다변량 입력과 인코더 기반 direct forecasting을 가정한다. 학습과 검증은 시간 순서를 유지해 분리하고, 외생 변수에는 예측 시점에 사용할 수 있는 정보만 포함해야 한다.
토큰 설계와 운영 파이프라인을 함께 맞추기
ViT와 TST의 공통 기반은 토큰화, 위치 인코딩, 어텐션이지만, 실제 성능은 2D 공간과 시간 구조에 맞춘 토큰 설계에서 갈린다. 작은 모델로 전처리와 추론 파이프라인을 먼저 확립한 뒤 강한 레시피와 사전학습을 적용하고, 선형·희소 어텐션 및 혼합 정밀도를 도입한다. 이후 모니터링과 재학습 자동화까지 이어져야 운영 가능한 모델이 된다.