학습 중에는 각 원소를 확률 p로 무작위로 0으로 만들고, 남은 원소를 1/(1-p)배 해서 출력의 기댓값을 유지해. 평가 중에는 아무 변화도 주지 않아. 모델이 특정 뉴런 하나에 지나치게 의존하지 못하게 하는 고전적인 정규화 기법이야.
Transformer의 FFN과 어텐션에는 0.1, 예전의 완전 연결 계층에는 0.5가 흔해. 현대적인 모델은 2015년 무렵의 논문보다 드롭아웃을 더 절제해서 쓰는 편이야.
nn.Embedding
정수 인덱스를 밀집 벡터로 바꾸는 조회 테이블이야. 범주형 입력을 다루는 여러 곳에 사용해:
NLP의 토큰 임베딩(어휘 → 벡터).
위치 임베딩.
추천 시스템의 사용자·항목 임베딩.
개념적으로는 (num_embeddings, embedding_dim) 모양의 가중치 행렬이고, embed(idx)는 weight[idx]를 반환해. 직접 weight[idx]를 쓰지 않고 nn.Embedding을 사용하는 이유는 PyTorch가 희소 기울기를 효율적으로 처리하고, 갱신하지 않을 패딩 인덱스를 지원하며, 옵티마이저와 자연스럽게 통합하기 때문이야.
nn.ModuleList: 깊이가 동적인 모델
앞에서 이미 배웠지만 한 번 더 강조할게. N계층 Transformer나 여러 ResNet 블록처럼 순전파에서 계층을 순회해야 한다면 nn.ModuleList를 사용해. 일반 Python 목록은 PyTorch가 추적하지 못해.
Code
드롭아웃: 학습 대 평가 행동·python
import torch
import torch.nn as nn
drop = nn.Dropout(p=0.5)
x = torch.ones(1, 8)
drop.train()
print(drop(x)) # ~half the entries zeroed, rest scaled by 2
# tensor([[2., 0., 0., 2., 0., 2., 2., 0.]]) (varies)
drop.eval()
print(drop(x)) # tensor([[1., 1., 1., 1., 1., 1., 1., 1.]]) — no-op
임베딩: 조회 테이블·python
import torch
import torch.nn as nn
# Vocab of 10,000 tokens, each represented by a 256-dim vector
embed = nn.Embedding(num_embeddings=10000, embedding_dim=256)
token_ids = torch.tensor([42, 100, 7, 2023])
vectors = embed(token_ids)
print(vectors.shape) # torch.Size([4, 256])
# Batched
batch = torch.randint(0, 10000, (32, 50)) # batch=32, seq=50
print(embed(batch).shape) # torch.Size([32, 50, 256])
# padding_idx — vector for index 0 stays zero and isn't trained
embed_pad = nn.Embedding(10000, 256, padding_idx=0)
print(embed_pad.weight[0].sum()) # tensor(0.) — guaranteed
합치기: 최소 Transformer 블록·python
import torch
import torch.nn as nn
class TransformerBlock(nn.Module):
def __init__(self, d_model=512, n_head=8, d_ff=2048, drop=0.1):
super().__init__()
self.attn = nn.MultiheadAttention(d_model, n_head, dropout=drop, batch_first=True)
self.ln1 = nn.LayerNorm(d_model)
self.ln2 = nn.LayerNorm(d_model)
self.ff = nn.Sequential(
nn.Linear(d_model, d_ff),
nn.GELU(),
nn.Dropout(drop),
nn.Linear(d_ff, d_model),
nn.Dropout(drop),
)
def forward(self, x, attn_mask=None):
# Pre-LN style — modern Transformer convention
h = self.ln1(x)
h, _ = self.attn(h, h, h, attn_mask=attn_mask, need_weights=False)
x = x + h # residual connection
h = self.ln2(x)
h = self.ff(h)
x = x + h # residual connection
return x
block = TransformerBlock()
x = torch.randn(2, 16, 512) # batch=2, seq=16, dim=512
print(block(x).shape) # torch.Size([2, 16, 512])
세 번째 코드 블록의 TransformerBlock 여섯 개를 nn.ModuleList로 묶어 TransformerEncoder를 만들어 봐. 깊이는 설정 사전의 값으로 정하게 해. d_model=512일 때 블록 하나의 매개변수가 약 315만 개, 전체가 약 1,890만 개인지 확인해.
Progress
Progress is local-only — sign in to sync across devices.