Instance Variable & Method Visibility Rule
1.설계 의도:
- 파이토치의 state_dict 직렬화 메커니즘을 고려하여 변수 언더스코어 규칙을 설계함. 학습되어야 할 레이어와 파라미터는 _ 없이 공개하여 공식 Key로 등록하고, 외부에서 사용할 수 있게 함.
- 모델의 구조와 무관한 정적 설정값, 외부에서 함부로 건드리면 안 되는 내부 로직에는 _를 붙여 격리하여 모델 저장 파일의 가독성을 확보하고 오용을 방지하고자 함
2. 빠른 판단 가이드
- 인스턴스 변수
# 질문: "학습(gradient)으로 업데이트되는가?"
self.conv1 = nn.Conv2d(...) # YES → Public
self.param = nn.Parameter(...) # YES → Public
self._dropout_rate = 0.5 # NO → Private
self._optimizer = optimizer # NO → Private
- 메서드
# 질문: "외부(main.py, DataLoader 등)에서 직접 호출하는가?"
def train(self): # YES → Public
def forward(self, x): # YES → Public
def __getitem__(self, idx): # YES → Public (표준 API)
def _run_epoch(self): # NO → Internal
def _load_from_disk(self, idx): # NO → Internal
def _init_weights(self): # NO → Internal
3. 상세 내용
(1)인스턴스 변수 규칙
기본 원칙: Private (언더스코어 O)
-대상: 내부 구현 상세, 설정값, 플래그
-의미: "외부에서 직접 접근 금지, 나중에 구현이 바뀔 수 있음"
-클래스: Trainer, Dataset, nn.Module(State), 유틸리티 클래스 등
-예시: self._optimizer, self._best_loss, self._checkpoint_dir
class Trainer:
def __init__(self, model, optimizer):
# [Public] 외부에서 접근/수정 가능한 안정적인 인터페이스
self.model = model
self.current_epoch = 0
# [Private] 내부 구현 상세 (외부 접근 비권장, 언제든 로직 변경 가능)
self._optimizer = optimizer # 예: 나중에 다른 옵티마이저로 교체될 수 있음
self._best_loss = float('inf') # 내부 추적용 변수
self._checkpoint_dir = "/tmp" # 저장 로직이 S3로 바뀔 수도 있음
예외:
nn.Module의 경우 Public (언더스코어 X)
-대상: 학습 가능한 레이어와 파라미터
-이유: state_dict() 저장 시 공개 API 키가 되기 때문
-주의: 설정값(정적 파라미터)는 여전히 _ 사용
예외 1: 학습 가능한 레이어
class VisionTransformer(nn.Module):
def __init__(self, *, input_dim: int, output_dim: int) -> None:
super().__init__()
# ✅ Public: 학습 가능한 레이어
# 이유: state_dict에 'conv1.weight', 'conv1.bias'로 저장됨
self.conv1 = nn.Conv2d(3, 64, kernel_size=3)
self.fc = nn.Linear(input_dim, output_dim)
self.lstm = nn.LSTM(128, 256)
# ❌ 잘못된 예
# self._conv1 = nn.Conv2d(3, 64, kernel_size=3)
# → state_dict에 '_conv1.weight'로 저장되어 재사용 어려움!
예외 2: 학습 가능한 파라미터
class VisionTransformer(nn.Module):
def __init__(self):
super().__init__()
# ✅ Public: 레이어에 속하지 않는 독립적인 학습 파라미터
# 이유: optimizer가 업데이트하는 대상
self.pos_embedding = nn.Parameter(torch.zeros(1, 196, 768))
self.class_token = nn.Parameter(torch.randn(1, 1, 768))
# ❌ 잘못된 예
# self._pos_embedding = nn.Parameter(torch.zeros(1, 196, 768))
# → state_dict에 '_pos_embedding'으로 저장됨
Private: 정적 하이퍼파라미터
class VisionTransformer(nn.Module):
def __init__(self):
super().__init__()
# 레이어 (Public)
self.conv1 = nn.Conv2d(3, 64, kernel_size=3)
# 🔒 Private: 학습되지 않는 설정값
# 이유: state_dict에 포함 불필요, 내부 로직용
self._dropout_rate = 0.5 # 정적 하이퍼파라미터
self._is_initialized = False # 내부 로직 제어용 플래그
self._debug_mode = True # 디버깅 설정
self._num_layers = 12 # 모델 구조 정보
2.메서드 규칙
Public 메서드
-규칙: 접두사 없이 작성
-대상: 외부에서 직접 호출하는 진입점
-의미: 안정적인 인터페이스, 외부에서 호출 가능
Internal 메서드
-규칙: _ 접두사 사용
-대상: Public 메서드를 돕는 헬퍼 함수(Helper)나 내부 구현 상세(Refactoring 대상).
-의미: "내부용, 외부 호출 금지, 나중에 로직 변경 가능"
# [Example] 메서드 가시성 적용 가이드
class Trainer:
def __init__(self, model):
self.model = model
# [Public] 외부(main.py 등)에서 "학습 시작!"을 명령할 때 호출하는 진입점
def train(self):
for epoch in range(10):
self._run_epoch() # 내부 로직 호출
# [Internal] 학습 한 바퀴를 돌리는 구체적인 방법 (구현 상세)
# 굳이 외부에서 이 메서드만 따로 호출할 일이 없으므로 숨김
def _run_epoch(self):
pass
# [Internal] 가중치 초기화는 학습 시작 전 내부적으로 한 번만 수행
# 외부에서 임의로 호출하여 학습된 모델을 초기화하는 사고를 방지하기 위해 숨김
def _init_weights(self):
pass
class CustomDataset(Dataset):
# [Public] PyTorch DataLoader가 "데이터 몇 개야?"라고 물어볼 때 쓰는 공개 API
def __len__(self):
return 100
# [Public] DataLoader가 "i번째 데이터 줘"라고 할 때 쓰는 공개 API
# 외부 사용자는 이 내부가 어떻게 변하는지 전혀 신경 쓸 필요 없음
def __getitem__(self, idx):
return self._load_from_disk(idx)
# [Internal] 실제로 하드디스크에서 파일을 읽어오는 구체적인 방식
# 나중에 AWS(S3)로 로직을 바꿔도 외부(__getitem__)는 알 필요 없음
def _load_from_disk(self, idx):
"""데이터 로딩 구현 상세"""
pass
class VisionTransformer(nn.Module):
# [Public] PyTorch가 추론 시 호출하는 표준 메서드
def forward(self, x):
if self._debug_mode:
self._log_shapes(x)
return x
# [Internal] 개발자용 디버깅 도구
# 실제 서비스 배포 시에는 필요 없거나 바뀔 수 있는 기능이므로 숨김
def _log_shapes(self, x):
print(f"Shape: {x.shape}")
'스프린트미션' 카테고리의 다른 글
| 위클리페이퍼 7 (0) | 2026.03.03 |
|---|---|
| 위클리 페이퍼 #6 (0) | 2026.02.22 |
| 규칙3 (0) | 2026.02.12 |
| 규칙1 (0) | 2026.02.12 |
| [AI] 위클리페이퍼 #5 (0) | 2026.02.09 |