12월 21, 2025
44 분 읽기

AI 연구 과학자 면접 질문

interview
career-advice
job-search
AI 연구 과학자 면접 질문
Milad Bonakdar

Milad Bonakdar

작성자

딥러닝, 트랜스포머, 실험 설계, 모델 평가, 연구 발표를 중심으로 AI 연구 과학자 면접을 준비하는 질문 모음입니다.


소개

AI 연구 과학자 면접은 연구자처럼 사고할 수 있는지를 봅니다. 가설을 세우고, 설계 선택을 설명하고, 핵심 아이디어를 구현하고, 모델을 공정하게 평가하며, 논문이나 연구 발표의 트레이드오프를 명확히 말할 수 있어야 합니다. 딥러닝과 트랜스포머 질문뿐 아니라 실험 설계, 재현성, 안전성, 다음 연구 방향도 자주 다룹니다.

이 가이드는 기술적으로 정확하고 설명하기 쉬운 답변을 연습하는 데 초점을 둡니다. 강한 지원자는 수식과 코드를 연구 판단과 연결합니다. 왜 그 방법이 효과적일지, 어떻게 검증할지, 어떤 실패 사례를 볼지, 불확실성을 어떻게 전달할지까지 말할 수 있어야 합니다.


딥러닝 이론 (5 문제)

1. 역전파와 연쇄 법칙을 자세히 설명하세요.

답변: 역전파는 연쇄 법칙을 사용하여 효율적으로 기울기를 계산합니다.

  • 연쇄 법칙: 합성 함수의 경우, 미분은 미분들의 곱입니다.
  • 순전파: 출력을 계산하고 중간값을 캐싱합니다.
  • 역전파: 출력에서 입력으로 기울기를 계산합니다.
import numpy as np

# 역전파를 시연하기 위한 간단한 신경망
class SimpleNN:
    def __init__(self, input_size, hidden_size, output_size):
        # 가중치 초기화
        self.W1 = np.random.randn(input_size, hidden_size) * 0.01
        self.b1 = np.zeros((1, hidden_size))
        self.W2 = np.random.randn(hidden_size, output_size) * 0.01
        self.b2 = np.zeros((1, output_size))
    
    def sigmoid(self, x):
        return 1 / (1 + np.exp(-x))
    
    def sigmoid_derivative(self, x):
        return x * (1 - x)
    
    def forward(self, X):
        # 레이어 1
        self.z1 = np.dot(X, self.W1) + self.b1
        self.a1 = self.sigmoid(self.z1)
        
        # 레이어 2
        self.z2 = np.dot(self.a1, self.W2) + self.b2
        self.a2 = self.sigmoid(self.z2)
        
        return self.a2
    
    def backward(self, X, y, output, learning_rate=0.01):
        m = X.shape[0]
        
        # 출력 레이어 기울기
        # dL/da2 = a2 - y (이진 교차 엔트로피의 경우)
        # dL/dz2 = dL/da2 * da2/dz2 = (a2 - y) * sigmoid'(z2)
        dz2 = output - y
        dW2 = (1/m) * np.dot(self.a1.T, dz2)
        db2 = (1/m) * np.sum(dz2, axis=0, keepdims=True)
        
        # 숨겨진 레이어 기울기 (연쇄 법칙)
        # dL/da1 = dL/dz2 * dz2/da1 = dz2 * W2.T
        # dL/dz1 = dL/da1 * da1/dz1 = dL/da1 * sigmoid'(z1)
        da1 = np.dot(dz2, self.W2.T)
        dz1 = da1 * self.sigmoid_derivative(self.a1)
        dW1 = (1/m) * np.dot(X.T, dz1)
        db1 = (1/m) * np.sum(dz1, axis=0, keepdims=True)
        
        # 가중치 업데이트
        self.W2 -= learning_rate * dW2
        self.b2 -= learning_rate * db2
        self.W1 -= learning_rate * dW1
        self.b1 -= learning_rate * db1
    
    def train(self, X, y, epochs=1000):
        for epoch in range(epochs):
            # 순전파
            output = self.forward(X)
            
            # 역전파
            self.backward(X, y, output)
            
            if epoch % 100 == 0:
                loss = -np.mean(y * np.log(output) + (1-y) * np.log(1-output))
                print(f'Epoch {epoch}, Loss: {loss:.4f}')

# 사용 예
X = np.array([[0, 0], [0, 1], [1, 0], [1, 1]])
y = np.array([[0], [1], [1], [0]])  # XOR

nn = SimpleNN(input_size=2, hidden_size=4, output_size=1)
nn.train(X, y, epochs=5000)

희소성: 매우 흔함 난이도: 어려움


2. 기울기 소실 문제는 무엇이며 어떻게 해결합니까?

답변: 기울기 소실은 깊은 네트워크에서 기울기가 매우 작아질 때 발생합니다.

  • 원인:
    • 시그모이드/tanh 활성화 함수 (미분 < 1)
    • 깊은 네트워크 (기울기가 곱해짐)
  • 해결책:
    • ReLU 활성화 함수
    • 배치 정규화
    • 잔차 연결 (ResNet)
    • RNN을 위한 LSTM/GRU
    • 신중한 초기화 (Xavier, He)
import torch
import torch.nn as nn

# 문제: 시그모이드를 사용한 깊은 네트워크
class VanishingGradientNet(nn.Module):
    def __init__(self):
        super().__init__()
        self.layers = nn.Sequential(*[
            nn.Sequential(nn.Linear(100, 100), nn.Sigmoid())
            for _ in range(20)  # 20 레이어
        ])
    
    def forward(self, x):
        return self.layers(x)

# 해결책 1: ReLU 활성화 함수
class ReLUNet(nn.Module):
    def __init__(self):
        super().__init__()
        self.layers = nn.Sequential(*[
            nn.Sequential(nn.Linear(100, 100), nn.ReLU())
            for _ in range(20)
        ])
    
    def forward(self, x):
        return self.layers(x)

# 해결책 2: 잔차 연결
class ResidualBlock(nn.Module):
    def __init__(self, dim):
        super().__init__()
        self.layers = nn.Sequential(
            nn.Linear(dim, dim),
            nn.ReLU(),
            nn.Linear(dim, dim)
        )
    
    def forward(self, x):
        return x + self.layers(x)  # 스킵 연결

class ResNet(nn.Module):
    def __init__(self):
        super().__init__()
        self.blocks = nn.Sequential(*[
            ResidualBlock(100) for _ in range(20)
        ])
    
    def forward(self, x):
        return self.blocks(x)

# 해결책 3: 배치 정규화
class BatchNormNet(nn.Module):
    def __init__(self):
        super().__init__()
        self.layers = nn.Sequential(*[
            nn.Sequential(
                nn.Linear(100, 100),
                nn.BatchNorm1d(100),
                nn.ReLU()
            )
            for _ in range(20)
        ])
    
    def forward(self, x):
        return self.layers(x)

# 기울기 흐름 분석
def analyze_gradients(model, x, y):
    model.zero_grad()
    output = model(x)
    loss = nn.MSELoss()(output, y)
    loss.backward()
    
    # 기울기 크기 확인
    for name, param in model.named_parameters():
        if param.grad is not None:
            grad_norm = param.grad.norm().item()
            print(f"{name}: {grad_norm:.6f}")

희소성: 매우 흔함 난이도: 어려움


3. 어텐션 메커니즘과 자기 어텐션을 설명하세요.

답변: 어텐션을 통해 모델은 입력의 관련 부분에 집중할 수 있습니다.

  • 어텐션: 쿼리-키 유사성을 기반으로 한 값의 가중 합
  • 자기 어텐션: 쿼리, 키, 값이 동일한 소스에서 오는 어텐션
  • 스케일링된 닷-프로덕트 어텐션: Q·K^T / √d_k
import torch
import torch.nn as nn
import torch.nn.functional as F
import math

class ScaledDotProductAttention(nn.Module):
    def __init__(self, temperature):
        super().__init__()
        self.temperature = temperature
    
    def forward(self, q, k, v, mask=None):
        """
        q: (batch, seq_len, d_k)
        k: (batch, seq_len, d_k)
        v: (batch, seq_len, d_v)
        """
        # 어텐션 점수 계산
        attn = torch.matmul(q, k.transpose(-2, -1)) / self.temperature
        
        # 마스크 적용 (패딩 또는 인과 관계 어텐션)
        if mask is not None:
            attn = attn.masked_fill(mask == 0, -1e9)
        
        # 어텐션 가중치를 얻기 위한 소프트맥스
        attn_weights = F.softmax(attn, dim=-1)
        
        # 값에 어텐션 적용
        output = torch.matmul(attn_weights, v)
        
        return output, attn_weights

class MultiHeadAttention(nn.Module):
    def __init__(self, d_model, n_heads, dropout=0.1):
        super().__init__()
        assert d_model % n_heads == 0
        
        self.d_model = d_model
        self.n_heads = n_heads
        self.d_k = d_model // n_heads
        
        # 선형 투영
        self.w_q = nn.Linear(d_model, d_model)
        self.w_k = nn.Linear(d_model, d_model)
        self.w_v = nn.Linear(d_model, d_model)
        self.w_o = nn.Linear(d_model, d_model)
        
        self.attention = ScaledDotProductAttention(temperature=math.sqrt(self.d_k))
        self.dropout = nn.Dropout(dropout)
    
    def forward(self, q, k, v, mask=None):
        batch_size = q.size(0)
        
        # 선형 투영 및 헤드로 분할
        q = self.w_q(q).view(batch_size, -1, self.n_heads, self.d_k).transpose(1, 2)
        k = self.w_k(k).view(batch_size, -1, self.n_heads, self.d_k).transpose(1, 2)
        v = self.w_v(v).view(batch_size, -1, self.n_heads, self.d_k).transpose(1, 2)
        
        # 어텐션 적용
        output, attn_weights = self.attention(q, k, v, mask)
        
        # 헤드 연결
        output = output.transpose(1, 2).contiguous().view(batch_size, -1, self.d_model)
        
        # 최종 선형 투영
        output = self.w_o(output)
        
        return output, attn_weights

# 사용 예
d_model = 512
n_heads = 8
seq_len = 10
batch_size = 2

mha = MultiHeadAttention(d_model, n_heads)
x = torch.randn(batch_size, seq_len, d_model)

# 자기 어텐션 (q, k, v 모두 x에서)
output, attn = mha(x, x, x)
print(f"Output shape: {output.shape}")
print(f"Attention weights shape: {attn.shape}")

희소성: 매우 흔함 난이도: 어려움


4. 배치 정규화와 레이어 정규화의 차이점은 무엇입니까?

답변: 둘 다 활성화를 정규화하지만 다른 차원을 따라 정규화합니다.

  • 배치 정규화:
    • 배치 차원에 걸쳐 정규화
    • 배치 통계 필요
    • 작은 배치, RNN에 문제 있음
  • 레이어 정규화:
    • 특징 차원에 걸쳐 정규화
    • 배치 크기와 무관
    • RNN, 트랜스포머에 더 적합
import torch
import torch.nn as nn

# 배치 정규화
class BatchNormExample(nn.Module):
    def __init__(self, num_features):
        super().__init__()
        self.bn = nn.BatchNorm1d(num_features)
    
    def forward(self, x):
        # x: (batch_size, num_features)
        # 각 특징에 대해 배치 차원에 걸쳐 정규화
        return self.bn(x)

# 레이어 정규화
class LayerNormExample(nn.Module):
    def __init__(self, normalized_shape):
        super().__init__()
        self.ln = nn.LayerNorm(normalized_shape)
    
    def forward(self, x):
        # x: (batch_size, seq_len, d_model)
        # 각 샘플에 대해 특징 차원에 걸쳐 정규화
        return self.ln(x)

# 수동 구현
class ManualLayerNorm(nn.Module):
    def __init__(self, normalized_shape, eps=1e-5):
        super().__init__()
        self.eps = eps
        self.gamma = nn.Parameter(torch.ones(normalized_shape))
        self.beta = nn.Parameter(torch.zeros(normalized_shape))
    
    def forward(self, x):
        # 마지막 차원에 걸쳐 평균 및 분산 계산
        mean = x.mean(dim=-1, keepdim=True)
        var = x.var(dim=-1, keepdim=True, unbiased=False)
        
        # 정규화
        x_norm = (x - mean) / torch.sqrt(var + self.eps)
        
        # 스케일 및 이동
        return self.gamma * x_norm + self.beta

# 비교
batch_size, seq_len, d_model = 2, 10, 512

# 배치 정규화 (CNN용)
x_cnn = torch.randn(batch_size, d_model, 28, 28)
bn = nn.BatchNorm2d(d_model)
out_bn = bn(x_cnn)

# 레이어 정규화 (트랜스포머용)
x_transformer = torch.randn(batch_size, seq_len, d_model)
ln = nn.LayerNorm(d_model)
out_ln = ln(x_transformer)

print(f"Batch Norm output: {out_bn.shape}")
print(f"Layer Norm output: {out_ln.shape}")

희소성: 흔함 난이도: 중간


5. 트랜스포머 아키텍처를 자세히 설명하세요.

답변: 트랜스포머는 순환 없이 시퀀스 모델링을 위해 자기 어텐션을 사용합니다.

Loading diagram...
  • 구성 요소:
    • 인코더: 자기 어텐션 + FFN
    • 디코더: 마스크된 자기 어텐션 + 교차 어텐션 + FFN
    • 위치 인코딩: 위치 정보 주입
    • 멀티 헤드 어텐션: 병렬 어텐션 메커니즘
import torch
import torch.nn as nn
import math

class PositionalEncoding(nn.Module):
    def __init__(self, d_model, max_len=5000):
        super().__init__()
        
        # 위치 인코딩 행렬 생성
        pe = torch.zeros(max_len, d_model)
        position = torch.arange(0, max_len, dtype=torch.float).unsqueeze(1)
        div_term = torch.exp(torch.arange(0, d_model, 2).float() * 
                            (-math.log(10000.0) / d_model))
        
        pe[:, 0::2] = torch.sin(position * div_term)
        pe[:, 1::2] = torch.cos(position * div_term)
        
        pe = pe.unsqueeze(0)
        self.register_buffer('pe', pe)
    
    def forward(self, x):
        return x + self.pe[:, :x.size(1)]

class TransformerEncoderLayer(nn.Module):
    def __init__(self, d_model, n_heads, d_ff, dropout=0.1):
        super().__init__()
        
        # 멀티 헤드 어텐션
        self.self_attn = nn.MultiheadAttention(d_model, n_heads, dropout=dropout)
        
        # 피드 포워드 네트워크
        self.ffn = nn.Sequential(
            nn.Linear(d_model, d_ff),
            nn.ReLU(),
            nn.Dropout(dropout),
            nn.Linear(d_ff, d_model)
        )
        
        # 레이어 정규화
        self.norm1 = nn.LayerNorm(d_model)
        self.norm2 = nn.LayerNorm(d_model)
        
        self.dropout = nn.Dropout(dropout)
    
    def forward(self, x, mask=None):
        # 잔차 연결을 사용한 자기 어텐션
        attn_output, _ = self.self_attn(x, x, x, attn_mask=mask)
        x = self.norm1(x + self.dropout(attn_output))
        
        # 잔차 연결을 사용한 피드 포워드
        ffn_output = self.ffn(x)
        x = self.norm2(x + self.dropout(ffn_output))
        
        return x

class TransformerEncoder(nn.Module):
    def __init__(self, vocab_size, d_model, n_heads, d_ff, n_layers, dropout=0.1):
        super().__init__()
        
        self.embedding = nn.Embedding(vocab_size, d_model)
        self.pos_encoding = PositionalEncoding(d_model)
        
        self.layers = nn.ModuleList([
            TransformerEncoderLayer(d_model, n_heads, d_ff, dropout)
            for _ in range(n_layers)
        ])
        
        self.dropout = nn.Dropout(dropout)
    
    def forward(self, x, mask=None):
        # 임베딩 + 위치 인코딩
        x = self.embedding(x) * math.sqrt(self.embedding.embedding_dim)
        x = self.pos_encoding(x)
        x = self.dropout(x)
        
        # 인코더 레이어 적용
        for layer in self.layers:
            x = layer(x, mask)
        
        return x

# 사용 예
vocab_size = 10000
d_model = 512
n_heads = 8
d_ff = 2048
n_layers = 6

encoder = TransformerEncoder(vocab_size, d_model, n_heads, d_ff, n_layers)

# 입력: (batch_size, seq_len)
x = torch.randint(0, vocab_size, (2, 10))
output = encoder(x)
print(f"Output shape: {output.shape}")  # (2, 10, 512)

희소성: 매우 흔함 난이도: 어려움


연구 방법론 (4 문제)

6. 연구 문제와 가설을 어떻게 공식화합니까?

답변: 연구는 격차를 식별하고 검증 가능한 가설을 공식화하는 것으로 시작됩니다.

  • 단계:
    1. 문헌 조사: 최첨단 기술 이해
    2. 격차 식별: 무엇이 누락되었거나 개선될 수 있습니까?
    3. 가설 공식화: 구체적이고 검증 가능한 주장
    4. 실험 설계: 가설을 테스트하는 방법?
    5. 지표 정의: 성공을 측정하는 방법?
  • 예:
    • 격차: 현재 모델은 장거리 의존성에 어려움을 겪습니다.
    • 가설: 희소 어텐션은 복잡성을 줄이면서 성능을 유지할 수 있습니다.
    • 실험: 긴 시퀀스에서 희소 어텐션과 전체 어텐션 비교
    • 지표: 퍼플렉서티, 정확도, 추론 시간

희소성: 매우 흔함 난이도: 중간


7. 제거 연구를 어떻게 설계합니까?

답변: 제거 연구는 개별 구성 요소의 기여도를 분리합니다.

  • 목적: 모델이 작동하는 이유 이해
  • 방법: 한 번에 하나의 구성 요소 제거/수정
  • 모범 사례:
    • 다른 모든 변수 제어
    • 동일한 랜덤 시드 사용
    • 신뢰 구간 보고
    • 여러 데이터 세트에서 테스트
# 제거 연구 예
class ModelWithAblations:
    def __init__(self, use_attention=True, use_residual=True, use_dropout=True):
        self.use_attention = use_attention
        self.use_residual = use_residual
        self.use_dropout = use_dropout
    
    def build_model(self):
        layers = []
        
        if self.use_attention:
            layers.append(AttentionLayer())
        
        layers.append(FFNLayer())
        
        if self.use_dropout:
            layers.append(nn.Dropout(0.1))
        
        if self.use_residual:
            return ResidualWrapper(nn.Sequential(*layers))
        else:
            return nn.Sequential(*layers)

# 제거 실험 실행
configs = [
    {'use_attention': True, 'use_residual': True, 'use_dropout': True},   # 전체 모델
    {'use_attention': False, 'use_residual': True, 'use_dropout': True},  # 어텐션 없음
    {'use_attention': True, 'use_residual': False, 'use_dropout': True},  # 잔차 없음
    {'use_attention': True, 'use_residual': True, 'use_dropout': False},  # 드롭아웃 없음
]

results = []
for config in configs:
    model = ModelWithAblations(**config)
    accuracy = train_and_evaluate(model, seed=42)
    results.append({**config, 'accuracy': accuracy})

# 결과 분석
import pandas as pd
df = pd.DataFrame(results)
print(df)

희소성: 매우 흔함 난이도: 중간


8. 연구에서 재현성을 어떻게 보장합니까?

답변: 재현성은 과학적 타당성에 매우 중요합니다.

  • 모범 사례:
    • 코드: 버전 관리, 명확한 문서
    • 데이터: 버전, 전처리 문서화
    • 환경: Docker, requirements.txt
    • 시드: 모든 랜덤 시드 고정
    • 하이퍼파라미터: 모든 설정 기록
    • 하드웨어: GPU/CPU 사양 문서화
import random
import numpy as np
import torch
import os

def set_all_seeds(seed=42):
    """재현성을 위해 시드 설정"""
    random.seed(seed)
    np.random.seed(seed)
    torch.manual_seed(seed)
    torch.cuda.manual_seed_all(seed)
    os.environ['PYTHONHASHSEED'] = str(seed)
    
    # 결정적 연산
    torch.backends.cudnn.deterministic = True
    torch.backends.cudnn.benchmark = False

# 모든 것 기록
import logging
import json

def log_experiment(config, results):
    experiment_log = {
        'timestamp': datetime.now().isoformat(),
        'config': config,
        'results': results,
        'environment': {
            'python_version': sys.version,
            'torch_version': torch.__version__,
            'cuda_version': torch.version.cuda,
            'gpu': torch.cuda.get_device_name(0) if torch.cuda.is_available() else 'CPU'
        }
    }
    
    with open('experiment_log.json', 'w') as f:
        json.dump(experiment_log, f, indent=2)

# 코드 및 모델 공유
"""
# README.md
## 재현성

### 환경
```bash
conda create -n research python=3.9
conda activate research
pip install -r requirements.txt

데이터

Download from: [link] Preprocess: python preprocess.py

훈련

python train.py --config configs/experiment1.yaml --seed 42

평가

python evaluate.py --checkpoint checkpoints/best_model.pt

"""


**희소성:** 매우 흔함
**난이도:** 쉬움

---

### 9. 모델을 공정하게 평가하고 비교하는 방법은 무엇입니까?

**답변:**
공정한 비교에는 신중한 실험 설계가 필요합니다.
- **고려 사항:**
    - **동일한 데이터 분할:** 동일한 훈련/검증/테스트 사용
    - **여러 실행:** 평균 및 표준 편차 보고
    - **통계 테스트:** T-검정, 윌콕슨
    - **계산 비용:** FLOP, 매개변수, 시간
    - **여러 지표:** 체리 피킹하지 마세요
    - **여러 데이터 세트:** 일반화

```python
import numpy as np
from scipy import stats

class ModelComparison:
    def __init__(self, n_runs=5):
        self.n_runs = n_runs
        self.results = {}
    
    def evaluate_model(self, model_name, model_fn, X_train, y_train, X_test, y_test):
        scores = []
        
        for seed in range(self.n_runs):
            # 이 실행에 대한 시드 설정
            set_all_seeds(seed)
            
            # 모델 훈련
            model = model_fn()
            model.fit(X_train, y_train)
            
            # 평가
            score = model.score(X_test, y_test)
            scores.append(score)
        
        self.results[model_name] = {
            'scores': scores,
            'mean': np.mean(scores),
            'std': np.std(scores),
            'ci_95': stats.t.interval(
                0.95, len(scores)-1,
                loc=np.mean(scores),
                scale=stats.sem(scores)
            )
        }
    
    def compare_models(self, model_a, model_b):
        """통계적 유의성 테스트"""
        scores_a = self.results[model_a]['scores']
        scores_b = self.results[model_b]['scores']
        
        # 쌍체 t-검정
        statistic, p_value = stats.ttest_rel(scores_a, scores_b)
        
        return {
            'statistic': statistic,
            'p_value': p_value,
            'significant': p_value < 0.05,
            'better_model': model_a if np.mean(scores_a) > np.mean(scores_b) else model_b
        }
    
    def report(self):
        for model_name, result in self.results.items():
            print(f"\n{model_name}:")
            print(f"  Mean: {result['mean']:.4f}")
            print(f"  Std:  {result['std']:.4f}")
            print(f"  95% CI: [{result['ci_95'][0]:.4f}, {result['ci_95'][1]:.4f}]")

# 사용법
comparison = ModelComparison(n_runs=10)
comparison.evaluate_model('Model A', lambda: ModelA(), X_train, y_train, X_test, y_test)
comparison.evaluate_model('Model B', lambda: ModelB(), X_train, y_train, X_test, y_test)

comparison.report()
result = comparison.compare_models('Model A', 'Model B')
print(f"\nStatistical test: p-value = {result['p_value']:.4f}")

희소성: 매우 흔함 난이도: 중간


고급 주제 (4 문제)

10. 대조 학습 및 응용 분야를 설명하세요.

답변: 대조 학습은 유사한 샘플과 유사하지 않은 샘플을 비교하여 표현을 학습합니다.

  • 핵심 아이디어: 유사한 샘플을 함께 당기고, 유사하지 않은 샘플을 밀어냅니다.
  • 손실: InfoNCE, NT-Xent
  • 응용 분야: SimCLR, MoCo, CLIP
import torch
import torch.nn as nn
import torch.nn.functional as F

class ContrastiveLoss(nn.Module):
    def __init__(self, temperature=0.5):
        super().__init__()
        self.temperature = temperature
    
    def forward(self, features):
        """
        features: (2*batch_size, dim) - 증강된 샘플 쌍
        """
        batch_size = features.shape[0] // 2
        
        # 특징 정규화
        features = F.normalize(features, dim=1)
        
        # 유사성 행렬 계산
        similarity_matrix = torch.matmul(features, features.T)
        
        # 레이블 생성 (양성 쌍)
        labels = torch.cat([torch.arange(batch_size) + batch_size,
                           torch.arange(batch_size)]).to(features.device)
        
        # 자체 유사성을 제거하기 위한 마스크
        mask = torch.eye(2 * batch_size, dtype=torch.bool).to(features.device)
        similarity_matrix = similarity_matrix.masked_fill(mask, -9e15)
        
        # 손실 계산
        similarity_matrix = similarity_matrix / self.temperature
        loss = F.cross_entropy(similarity_matrix, labels)
        
        return loss

class SimCLR(nn.Module):
    def __init__(self, encoder, projection_dim=128):
        super().__init__()
        self.encoder = encoder
        self.projection = nn.Sequential(
            nn.Linear(encoder.output_dim, 512),
            nn.ReLU(),
            nn.Linear(512, projection_dim)
        )
    
    def forward(self, x1, x2):
        # 두 개의 증강된 뷰 인코딩
        h1 = self.encoder(x1)
        h2 = self.encoder(x2)
        
        # 대조 공간으로 투영
        z1 = self.projection(h1)
        z2 = self.projection(h2)
        
        # 대조 손실을 위해 연결
        features = torch.cat([z1, z2], dim=0)
        
        return features

# 훈련 루프
model = SimCLR(encoder, projection_dim=128)
criterion = ContrastiveLoss(temperature=0.5)
optimizer = torch.optim.Adam(model.parameters())

for epoch in range(100):
    for batch in dataloader:
        # 두 개의 증강된 뷰 가져오기
        x1, x2 = augment(batch)
        
        # 순전파
        features = model(x1, x2)
        loss = criterion(features)
        
        # 역전파
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

희소성: 흔함 난이도: 어려움


11. Vision Transformers (ViT)는 무엇이며 어떻게 작동합니까?

답변: Vision Transformers는 트랜스포머 아키텍처를 이미지에 적용합니다.

  • 핵심 아이디어:
    • 이미지를 패치로 분할
    • 패치의 선형 임베딩
    • 위치 임베딩 추가
    • 트랜스포머 인코더 적용
  • 장점: 확장성, 글로벌 수용 필드
  • 과제: 큰 데이터 세트 필요
import torch
import torch.nn as nn

class PatchEmbedding(nn.Module):
    def __init__(self, img_size=224, patch_size=16, in_channels=3, embed_dim=768):
        super().__init__()
        self.img_size = img_size
        self.patch_size = patch_size
        self.n_patches = (img_size // patch_size) ** 2
        
        # 패치 추출 및 임베딩을 위한 컨볼루션
        self.projection = nn.Conv2d(
Newsletter subscription

실제로 효과가 있는 주간 커리어 팁

최신 인사이트를 받은 편지함으로 직접 받아보세요

채용 담당자에게 눈에 띄고 꿈의 직장을 얻으세요

ATS를 통과하고 채용 담당자에게 깊은 인상을 주는 AI 기반 이력서로 커리어를 변화시킨 수천 명의 사람들과 함께하세요.

지금 만들기 시작

이 게시물 공유

50% 더 빠르게 채용되세요

전문적이고 AI로 강화된 이력서를 사용하는 구직자는 표준 10주에 비해 평균 5주 만에 일자리를 얻습니다. 기다리지 말고 면접을 시작하세요.