콘텐츠로 이동

딥러닝

면접에서 자주 나오는 딥러닝 질문들

질문 목록

기본 개념

  • [ ] 딥러닝은 무엇인가요?
  • [ ] 왜 갑자기 딥러닝이 부흥했을까요?
  • [ ] 마지막으로 읽은 논문은 무엇인가요?
  • [ ] Cost Function과 Activation Function은 무엇인가요?
  • [ ] Data Normalization은 무엇이고 왜 필요한가요?

Activation Function

  • [ ] 알고있는 Activation Function에 대해 알려주세요
  • [ ] 요즘 Sigmoid 보다 ReLU를 많이 쓰는 이유는?
  • [ ] Non-Linearity라는 말의 의미와 그 필요성은?
  • [ ] ReLU로 어떻게 곡선 함수를 근사하나?
  • [ ] ReLU의 문제점은?
  • [ ] Bias는 왜 있는걸까?

학습 과정

  • [ ] Gradient Descent에 대해서 쉽게 설명한다면?
  • [ ] 왜 꼭 Gradient를 써야 할까?
  • [ ] GD 중에 때때로 Loss가 증가하는 이유는?
  • [ ] 중학생이 이해할 수 있게 더 쉽게 설명 한다면?
  • [ ] Back Propagation에 대해서 쉽게 설명 한다면?
  • [ ] Local Minima 문제에도 불구하고 딥러닝이 잘 되는 이유는?
  • [ ] GD가 Local Minima 문제를 피하는 방법은?
  • [ ] 찾은 해가 Global Minimum인지 아닌지 알 수 있는 방법은?

데이터 분할

  • [ ] Training 세트와 Test 세트를 분리하는 이유는?
  • [ ] Validation 세트가 따로 있는 이유는?
  • [ ] Test 세트가 오염되었다는 말의 뜻은?

정규화 기법

  • [ ] 오버피팅일 경우 어떻게 대처해야 할까요?
  • [ ] Regularization이란 무엇인가?
  • [ ] Batch Normalization의 효과는?
  • [ ] Dropout의 효과는?
  • [ ] BN 적용해서 학습 이후 실제 사용시에 주의할 점은?
  • [ ] GAN에서 Generator 쪽에도 BN을 적용해도 될까?

Optimizer

  • [ ] SGD, RMSprop, Adam에 대해서 아는대로 설명한다면?
  • [ ] SGD에서 Stochastic의 의미는?
  • [ ] 미니배치를 작게 할때의 장단점은?
  • [ ] 모멘텀의 수식을 적어 본다면?

초기화/하이퍼파라미터

  • [ ] 하이퍼 파라미터는 무엇인가요?
  • [ ] Weight Initialization 방법에 대해 말해주세요
  • [ ] 볼츠만 머신은 무엇인가요?

프레임워크/구현

  • [ ] Tensorflow, Keras, PyTorch, Caffe, Mxnet 중 선호하는 프레임워크는?
  • [ ] 간단한 MNIST 분류기를 MLP+CPU 버전으로 numpy로 만든다면?
  • [ ] 어느 정도 돌아가는 녀석을 작성하기까지 몇시간 정도 걸릴까?
  • [ ] Back Propagation은 몇줄인가?
  • [ ] CNN으로 바꾼다면 얼마나 추가될까?
  • [ ] 간단한 MNIST 분류기를 TF, Keras, PyTorch 등으로 작성하는데?
  • [ ] CNN이 아닌 MLP로 해도 잘 될까?
  • [ ] 마지막 레이어 부분에 대해서 설명 한다면?
  • [ ] 학습은 BCE loss로 하되 상황을 MSE loss로 보고 싶다면?
  • [ ] 만약 한글 (인쇄물) OCR을 만든다면 데이터 수집은?

GPU/하드웨어

  • [ ] 딥러닝할 때 GPU를 쓰면 좋은 이유는?
  • [ ] 학습 중인데 GPU를 100% 사용하지 않고 있다
  • [ ] GPU를 두개 다 쓰고 싶다
  • [ ] 학습시 필요한 GPU 메모리는 어떻게 계산하는가?

디버깅/실무

  • [ ] TF, Keras, PyTorch 등을 사용할 때 디버깅 노하우는?
  • [ ] 뉴럴넷의 가장 큰 단점은 무엇인가?
  • [ ] One-Shot Learning은 무엇인가?

답변

딥러닝은 무엇인가요?

한 줄 정의

여러 층(layer)의 신경망을 통해 데이터에서 계층적 표현을 자동으로 학습하는 기법

딥러닝 vs 머신러닝

전통 ML:
입력 → [수동 피처 추출] → [모델] → 출력
       ↑ 사람이 설계

딥러닝:
입력 → [자동 피처 학습] → 출력
       ↑ 데이터에서 스스로 학습

왜 "딥(Deep)"인가?

얕은 네트워크 (1-2 층):
입력 → [은닉층] → 출력

깊은 네트워크 (수십~수백 층):
입력 → [층1] → [층2] → ... → [층N] → 출력
       ↓       ↓              ↓
      저수준   중수준         고수준
      (엣지)   (패턴)         (의미)

계층적 표현 학습

이미지 예시:
층 1: 엣지, 색상 감지
층 2: 텍스처, 코너 감지
층 3: 부분 (눈, 코, 귀)
층 N: 전체 객체 (고양이, 강아지)

각 층이 더 추상적인 특징 학습

딥러닝의 구성 요소

요소 역할
뉴런 가중치 합 + 활성화 함수
층 (Layer) 뉴런들의 집합
활성화 함수 비선형성 추가 (ReLU 등)
손실 함수 예측 오차 측정
역전파 기울기 계산하여 학습
옵티마이저 가중치 업데이트 (Adam 등)

면접 포인트

  • 계층적 표현 학습: 저수준 → 고수준 특징
  • 자동 피처 학습: 수동 피처 엔지니어링 불필요
  • 깊을수록: 더 복잡한 패턴 학습 가능

왜 갑자기 딥러닝이 부흥했을까요?

한 줄 답변

데이터 + GPU + 알고리즘 혁신의 동시 발전 (2012년 AlexNet)

세 가지 요인

1. 빅데이터
   - ImageNet (1400만 이미지)
   - 인터넷, SNS, 모바일 데이터 폭발
   - 딥러닝은 데이터가 많을수록 성능 ↑

2. GPU 컴퓨팅
   - NVIDIA CUDA (2007)
   - 병렬 연산 → 학습 100배 가속
   - 클라우드로 GPU 접근 용이

3. 알고리즘 혁신
   - ReLU: Vanishing Gradient 해결
   - Dropout: 과적합 방지
   - Batch Normalization: 학습 안정화

역사적 타임라인

1960s: 퍼셉트론 발명
1969:  XOR 문제 → 1차 AI 겨울
1986:  역전파 알고리즘
1990s: SVM, 앙상블 전성기 → 2차 AI 겨울
2006:  Deep Belief Network (Hinton)
2012:  ★ AlexNet - ImageNet 우승 (오차 15% 감소)
2014:  GAN, Adam optimizer
2015:  ResNet (152층)
2017:  Transformer → NLP 혁명

2012년 AlexNet의 의미

ImageNet Challenge 2012:

기존 최고 성능: 26% 오류율 (전통 CV)
AlexNet:        15% 오류율 (딥러닝)

→ 11% 포인트 차이는 혁명적!
→ 모든 분야에서 딥러닝 연구 시작

AlexNet의 핵심 기술

기술 효과
ReLU 깊은 학습 가능
Dropout 과적합 방지
GPU 학습 대규모 모델 학습 가능
Data Augmentation 데이터 부족 보완

면접 포인트

  • 2012 AlexNet: 딥러닝 부흥의 시작점
  • 삼박자: 데이터 + GPU + 알고리즘
  • ReLU, Dropout: 핵심 기술 혁신

Cost Function과 Activation Function은 무엇인가요?

한 줄 정의

Cost Function: 예측 오차를 측정 | Activation Function: 비선형성을 추가

Cost Function (손실 함수)

역할: "모델이 얼마나 틀렸는지" 수치화

Loss = f(예측값, 실제값)

학습 = Loss를 최소화하는 가중치 찾기
문제 유형 Cost Function 수식
회귀 MSE Σ(y - ŷ)² / n
이진 분류 Binary Cross-Entropy -Σ[y·log(ŷ) + (1-y)·log(1-ŷ)]
다중 분류 Categorical Cross-Entropy -Σ y·log(ŷ)
import torch.nn as nn

# 회귀
loss_fn = nn.MSELoss()

# 이진 분류
loss_fn = nn.BCEWithLogitsLoss()

# 다중 분류
loss_fn = nn.CrossEntropyLoss()

Activation Function (활성화 함수)

역할: 비선형성 추가

선형만 있으면:
f(g(x)) = W₂(W₁x) = (W₂W₁)x = Wx
→ 아무리 깊어도 선형!

비선형 추가:
f(g(x)) = σ(W₂·σ(W₁x))
→ 복잡한 패턴 학습 가능
활성화 함수 수식 특징
Sigmoid 1/(1+e^-x) 출력 (0,1), Vanishing Gradient
Tanh (e^x-e^-x)/(e^x+e^-x) 출력 (-1,1)
ReLU max(0, x) 현재 표준, 빠름
Leaky ReLU max(0.01x, x) Dead ReLU 해결
Softmax e^xᵢ/Σe^xⱼ 다중 분류 출력층
import torch.nn as nn

# 은닉층
nn.ReLU()
nn.LeakyReLU(0.01)
nn.GELU()  # Transformer에서 사용

# 출력층
nn.Sigmoid()   # 이진 분류
nn.Softmax(dim=1)  # 다중 분류

둘의 관계

Forward Pass:
입력 → [선형변환] → [Activation] → ... → 출력
                                         ↓
                            Cost Function으로 오차 계산
                                         ↓
Backward Pass:                      역전파로 학습

면접 포인트

  • Cost Function: 학습 목표 (최소화 대상)
  • Activation: 비선형성 (복잡한 패턴 학습)
  • ReLU: 현재 표준 활성화 함수

Data Normalization은 무엇이고 왜 필요한가요?

한 줄 정의

입력 데이터의 스케일을 통일하여 학습을 안정화하고 수렴 속도를 높이는 전처리

왜 필요한가?

정규화 없이:
- 피처 A: 0~1
- 피처 B: 1000~10000

→ 피처 B의 영향이 지배적
→ Gradient가 불균형
→ 학습 불안정, 수렴 느림

정규화 후:
- 피처 A: 0~1
- 피처 B: 0~1

→ 균형 잡힌 학습

시각적 이해

정규화 전:                    정규화 후:
     ↑                            ↑
     │    /                       │  ●
     │   /   ← 지그재그           │    ← 빠른 수렴
     │  /                         │  ↓
     │ /                          ●────→
     └────────→

정규화 방법

방법 수식 결과 특징
Min-Max (x-min)/(max-min) [0, 1] 이미지에 자주 사용
Z-score (x-μ)/σ 평균0, 분산1 가장 일반적
/255 x/255 [0, 1] 이미지 픽셀 정규화
# 이미지 정규화
images = images / 255.0  # [0, 255] → [0, 1]

# 또는 ImageNet 기준 정규화
normalize = transforms.Normalize(
    mean=[0.485, 0.456, 0.406],
    std=[0.229, 0.224, 0.225]
)

딥러닝에서의 정규화

1. 입력 정규화: 데이터 전처리
2. Batch Normalization: 층 사이 정규화
3. Layer Normalization: Transformer에서 사용

각각 다른 위치, 다른 목적

주의사항

# ❌ 잘못된 방법 (Data Leakage)
mean = X_전체.mean()
std = X_전체.std()

# ✅ 올바른 방법
mean = X_train.mean()
std = X_train.std()
X_train_norm = (X_train - mean) / std
X_test_norm = (X_test - mean) / std  # train 통계 사용

면접 포인트

  • 스케일 통일 → 학습 안정화, 수렴 속도 ↑
  • Test에는 Train 통계 사용 (Data Leakage 방지)
  • 이미지: /255 또는 ImageNet 정규화

알고있는 Activation Function에 대해 알려주세요

한 줄 정의

뉴런의 출력에 비선형성을 추가하여 복잡한 패턴을 학습할 수 있게 하는 함수

주요 활성화 함수

함수 수식 범위 특징
Sigmoid σ(x) = 1/(1+e^-x) (0, 1) 이진 분류 출력, Vanishing Gradient
Tanh (e^x-e^-x)/(e^x+e^-x) (-1, 1) 0 중심, Vanishing Gradient
ReLU max(0, x) [0, ∞) 현재 표준, 빠름, Dead ReLU
Leaky ReLU max(αx, x) (-∞, ∞) Dead ReLU 해결
ELU x if x>0, α(e^x-1) else (-α, ∞) 음수 출력, 부드러움
GELU x·Φ(x) - Transformer 표준
Swish x·σ(x) - 자기 게이트, 부드러움
Softmax e^xᵢ/Σe^xⱼ (0, 1), 합=1 다중 분류 출력

시각적 비교

Sigmoid:          ReLU:            Leaky ReLU:
    ___               /               /
   /              ___/            ___/
  /                               /  (기울기 0.01)

용도별 선택

위치 추천 활성화 함수
은닉층 (일반) ReLU, Leaky ReLU
은닉층 (Transformer) GELU
출력층 (이진 분류) Sigmoid
출력층 (다중 분류) Softmax
출력층 (회귀) 없음 (Linear)

코드

import torch.nn as nn

# 은닉층
nn.ReLU()
nn.LeakyReLU(negative_slope=0.01)
nn.GELU()
nn.SiLU()  # Swish

# 출력층
nn.Sigmoid()
nn.Softmax(dim=-1)

면접 포인트

  • ReLU: 현재 표준, 빠름, Dead ReLU 주의
  • GELU: Transformer (BERT, GPT)에서 사용
  • Softmax: 다중 분류 출력층 전용

요즘 Sigmoid 보다 ReLU를 많이 쓰는 이유는?

한 줄 답변

Vanishing Gradient 문제 해결 + 계산 효율성

Sigmoid의 문제

Sigmoid: σ(x) = 1/(1+e^-x)
미분:    σ'(x) = σ(x)(1-σ(x))

최대 미분값: 0.25 (x=0일 때)

층이 깊어지면:
0.25 × 0.25 × 0.25 × ... = 거의 0

→ Vanishing Gradient!
→ 앞쪽 층이 학습 안 됨

ReLU의 장점

ReLU: f(x) = max(0, x)
미분: f'(x) = 1 (x>0), 0 (x≤0)

양수 영역에서:
1 × 1 × 1 × ... = 1

→ Gradient가 사라지지 않음!
→ 깊은 네트워크 학습 가능

비교

Sigmoid ReLU
미분 최대 0.25 1
계산 exp 연산 (느림) max 연산 (빠름)
희소성 없음 있음 (0이 많음)
Vanishing Gradient 심함 없음
출력 범위 (0, 1) [0, ∞)

계산 효율성

# Sigmoid: 지수 연산
def sigmoid(x):
    return 1 / (1 + np.exp(-x))

# ReLU: 단순 비교
def relu(x):
    return np.maximum(0, x)

# ReLU가 훨씬 빠름!

그래도 Sigmoid를 쓰는 경우

1. 출력층 (이진 분류): 확률 값 필요
2. Gate 메커니즘: LSTM, GRU의 게이트
3. Attention: 0~1 범위 필요할 때

면접 포인트

  • Vanishing Gradient: Sigmoid 미분 최대 0.25
  • ReLU: 미분이 1, 깊은 네트워크 학습 가능
  • 계산 속도: ReLU가 훨씬 빠름

Non-Linearity라는 말의 의미와 그 필요성은?

한 줄 정의

입력과 출력이 직선 관계가 아닌 것. 복잡한 패턴 학습에 필수

선형 vs 비선형

선형: y = ax + b
      직선으로만 표현 가능

비선형: y = σ(ax + b)
       곡선, 복잡한 패턴 표현 가능

왜 비선형이 필요한가?

선형만 있으면:
층1: y = W₁x
층2: z = W₂y = W₂W₁x = (W₂W₁)x = Wx

→ 아무리 층을 쌓아도 결국 선형!
→ 100층 네트워크 = 1층 네트워크와 표현력 동일
비선형 추가:
층1: y = σ(W₁x)
층2: z = σ(W₂y) = σ(W₂·σ(W₁x))

→ 선형 결합 불가!
→ 층이 깊을수록 복잡한 함수 표현 가능

시각적 이해

선형 분류:                비선형 분류:
    │  ○○○                  ╭──────╮
    │   ○○○                │ ○○○  │
────┼────── (직선만)        │  ○○○ │ (곡선 경계)
  ● ● ●│                   │ ● ● ●│
 ● ● ● │                   ╰──────╯

XOR 문제: 선형으로 불가!

Universal Approximation Theorem

"충분한 뉴런 + 비선형 활성화 함수
 → 어떤 연속 함수도 근사 가능"

핵심: 비선형 활성화 함수가 있어야 성립!

코드로 이해

# 선형만 (의미 없음)
x = W2 @ (W1 @ x)  # = (W2 @ W1) @ x

# 비선형 추가 (표현력 증가)
x = W2 @ relu(W1 @ x)  # 합성 불가, 더 복잡한 함수

면접 포인트

  • 선형만: 층 쌓아도 결국 1개 층과 동일
  • 비선형: 층마다 표현력 증가
  • Universal Approximation: 비선형이 있어야 어떤 함수든 근사

ReLU로 어떻게 곡선 함수를 근사하나?

한 줄 답변

여러 직선 조각을 결합하여 곡선을 구간별 선형 근사(Piecewise Linear)

직관적 이해

하나의 ReLU = 하나의 꺾인 직선

      /
     /
____/  ← ReLU(x)

여러 ReLU 조합 = 여러 번 꺾인 선 = 곡선 근사

원래 곡선:    ⌢
ReLU 근사:   /\
            /  \
           /    \___

구간별 선형 근사

f(x) = w₁·ReLU(x-a₁) + w₂·ReLU(x-a₂) + ... + b

각 ReLU가 특정 지점에서 "켜짐"
→ 구간마다 다른 기울기
→ 곡선처럼 보임

예시: sin(x) 근사

sin(x)를 ReLU로 근사:

실제 sin:  ∿∿∿∿∿

ReLU 근사:  /\  /\  /\
           /  \/  \/  \

뉴런 많을수록 더 부드러운 근사

시각적 증명

ReLU 1개: /
          \___

ReLU 2개:  /\
          /  \___

ReLU 4개:  /\  /
          /  \/\___

ReLU n개: 거의 곡선!

Universal Approximation

이론적으로:
- 1개 은닉층 + 충분한 ReLU 뉴런
- → 어떤 연속 함수도 근사 가능

실제로:
- 깊은 네트워크가 더 효율적
- 적은 뉴런으로 복잡한 함수 근사

코드 예시

import numpy as np
import matplotlib.pyplot as plt

# ReLU 조합으로 sin 근사
def piecewise_linear(x, n_pieces=10):
    result = np.zeros_like(x)
    for i in range(n_pieces):
        # 각 ReLU가 다른 지점에서 활성화
        result += np.maximum(0, x - i * 0.5) * np.sin(i)
    return result

면접 포인트

  • 구간별 선형 근사: 여러 직선으로 곡선 표현
  • 뉴런 많을수록 더 정밀한 근사
  • Universal Approximation 이론적 근거

ReLU의 문제점은?

한 줄 답변

Dead ReLU: 음수 입력에서 항상 0 출력 → 학습 불가

Dead ReLU 문제

ReLU: f(x) = max(0, x)
미분: f'(x) = 0 (x ≤ 0)

만약 뉴런 입력이 항상 음수면:
- 출력: 항상 0
- Gradient: 항상 0
- 가중치 업데이트: 0

→ 영원히 죽은 상태!

언제 발생하나?

1. 큰 Learning Rate
   → 가중치가 큰 음수로 업데이트
   → 입력이 항상 음수

2. 나쁜 초기화
   → 처음부터 음수 영역에 갇힘

3. Bias 문제
   → 큰 음수 bias

해결책

방법 설명 수식
Leaky ReLU 음수에서 작은 기울기 max(0.01x, x)
PReLU 기울기를 학습 max(αx, x), α 학습
ELU 부드러운 음수 처리 x if x>0, α(e^x-1) else
GELU 가우시안 기반 x·Φ(x)
import torch.nn as nn

# Dead ReLU 방지
nn.LeakyReLU(negative_slope=0.01)  # 가장 간단
nn.PReLU()  # 기울기 학습
nn.ELU(alpha=1.0)  # 부드러움
nn.GELU()  # Transformer 표준

다른 문제점들

1. 출력이 무한대로 갈 수 있음
   → Batch Normalization으로 완화

2. 0에서 미분 불가능
   → 실제로는 큰 문제 아님 (0이나 1로 처리)

3. 출력이 0 중심이 아님
   → Batch Norm으로 해결

면접 포인트

  • Dead ReLU: 음수 영역에서 Gradient = 0
  • 해결: Leaky ReLU, PReLU, ELU
  • 원인: 큰 LR, 나쁜 초기화

Bias는 왜 있는걸까?

한 줄 답변

활성화 함수를 좌우로 이동시켜 더 유연한 함수 근사 가능

Bias의 역할

Bias 없이: y = wx
→ 항상 원점을 통과하는 직선만 가능

Bias 포함: y = wx + b
→ 원점을 벗어난 직선 가능
          │                    │
          │  /                 │    /
          │ /                  │   /
──────────┼/────              ─┼──/────── (b > 0)
          │                    │
     Bias 없음            Bias 있음

활성화 함수 이동

ReLU(wx): 항상 x=0에서 꺾임
ReLU(wx + b): x = -b/w에서 꺾임

→ Bias로 "꺾이는 지점" 조절
→ 더 다양한 패턴 학습 가능

뉴런 단위 해석

뉴런 활성화 조건:
wx + b > 0
wx > -b

Bias = 활성화 임계값
→ 각 뉴런이 언제 "켜질지" 결정

코드 예시

import torch.nn as nn

# Bias 포함 (기본값)
linear = nn.Linear(10, 5, bias=True)

# Bias 제외 (특수 경우)
linear_no_bias = nn.Linear(10, 5, bias=False)

# Batch Normalization 후에는 Bias 불필요
# (BN이 shift 역할을 하므로)
conv = nn.Conv2d(3, 64, 3, bias=False)
bn = nn.BatchNorm2d(64)

Bias 없는 경우

1. Batch Normalization 바로 앞
   → BN의 beta가 Bias 역할

2. Residual Connection 특정 구현
   → 생략해도 학습 가능

3. 메모리 최적화 필요 시
   → 파라미터 수 약간 감소

면접 포인트

  • 함수 이동: 활성화 함수 위치 조절
  • 활성화 임계값: 뉴런이 언제 켜지는지
  • BN 후에는 불필요: BN이 대체

Gradient Descent에 대해서 쉽게 설명한다면?

한 줄 정의

손실 함수의 기울기(Gradient) 반대 방향으로 조금씩 이동하여 최솟값을 찾는 방법

비유: 눈 감고 산 내려가기

산 정상에서 눈 감고 가장 낮은 곳 찾기:

1. 현재 위치에서 발로 경사 느끼기 (Gradient 계산)
2. 가장 가파른 내리막 방향으로 한 걸음 (업데이트)
3. 반복

결국 골짜기(최솟값)에 도달!

수식

θ_new = θ - α × ∇L(θ)

θ: 현재 파라미터 (가중치)
α: 학습률 (한 걸음 크기)
∇L(θ): 손실 함수의 기울기

기울기 반대 방향 = 손실 줄어드는 방향

시각적 이해

   Loss
     ↑
     │  ●
     │   ↘
     │    ↘
     │     ●
     │      ↘
     │       ●  ← 최솟값
     └──────────→ θ

점점 아래로 (Loss 감소)

학습률의 중요성

α가 너무 크면:          α가 너무 작으면:
     ↗↘↗↘                 ●
    /    \                  ●
   /      \                   ●
  ●        ● (발산)            ...아직 멀었음

적당한 α:
  ●
   ↘
    ↘
     ● (수렴)

코드

# 직접 구현
for epoch in range(epochs):
    loss = model(x)
    gradient = compute_gradient(loss)
    weights = weights - learning_rate * gradient

# PyTorch
optimizer = torch.optim.SGD(model.parameters(), lr=0.01)
optimizer.zero_grad()
loss.backward()  # gradient 계산
optimizer.step()  # 업데이트

면접 포인트

  • 기울기 반대 방향으로 이동
  • 학습률: 한 번에 얼마나 이동할지
  • 비유: 눈 감고 산 내려가기

왜 꼭 Gradient를 써야 할까?

한 줄 답변

고차원 공간에서 효율적으로 최솟값 방향을 찾을 수 있는 유일한 방법

대안과 비교

방법 복잡도 문제점
Grid Search O(n^d) 차원의 저주, 불가능
Random Search - 수렴 보장 없음
유전 알고리즘 - 느림, 대규모 불가
Gradient O(n) 미분 가능해야 함

고차원에서의 효율성

파라미터가 1억개인 신경망:

Grid Search: 각 파라미터 10개 값 → 10^100000000 조합
            → 우주가 멸망해도 못 끝남

Gradient: 1억 개 방향 중 최적 방향을 한 번에 계산
         → 효율적!

Gradient의 의미

Gradient = 각 파라미터가 Loss에 미치는 영향

∂L/∂w₁ = +2  → w₁을 줄이면 Loss 감소
∂L/∂w₂ = -1  → w₂를 늘리면 Loss 감소

→ 모든 파라미터의 최적 이동 방향을 동시에 알 수 있음!

미분 가능성 요구

Gradient를 쓰려면 미분 가능해야 함:
→ 모든 연산이 미분 가능하도록 설계

ReLU의 0에서 미분 불가?
→ 실제로는 subgradient 사용, 큰 문제 없음

면접 포인트

  • 고차원에서 유일한 효율적 방법
  • 각 파라미터별 최적 방향 동시 계산
  • 미분 가능 함수 필요 → 딥러닝 구조 설계 영향

GD 중에 때때로 Loss가 증가하는 이유는?

한 줄 답변

학습률이 너무 크거나, 미니배치 노이즈, 손실 지형의 복잡성 때문

주요 원인

원인 설명
학습률 과대 최솟값을 뛰어넘음
미니배치 노이즈 배치마다 gradient 다름
Saddle Point 탈출 과정에서 일시 증가
정규화 효과 Dropout, BN의 확률적 특성

학습률 문제

LR이 너무 크면:
       ↗↘
      ↗  ↘
     ●    ●    ← 최솟값을 뛰어넘어 반대편으로
          ↗↘

→ Loss가 오락가락
→ 수렴 안 함

미니배치 노이즈 (SGD)

전체 데이터 Gradient ≠ 미니배치 Gradient

배치 A: gradient = (1, 2)
배치 B: gradient = (-1, 3)
배치 C: gradient = (2, -1)

→ 각 스텝이 약간 다른 방향
→ 지그재그, 일시적 Loss 증가 가능
→ 장기적으로는 평균이 맞음

괜찮은 증가 vs 문제 있는 증가

괜찮음:
- 일시적 증가 후 다시 감소
- 노이즈 범위 내 변동

문제:
- 계속 증가
- 발산 (NaN, Inf)

→ Learning Rate 줄여보기
→ Gradient Clipping 적용

해결책

# Learning Rate 감소
optimizer = optim.Adam(model.parameters(), lr=1e-4)

# Learning Rate Scheduler
scheduler = optim.lr_scheduler.ReduceLROnPlateau(
    optimizer, patience=5
)

# Gradient Clipping
torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)

면접 포인트

  • LR 과대: 최솟값 뛰어넘음
  • SGD 노이즈: 미니배치 차이로 변동
  • 일시적 증가는 정상, 지속적 증가는 문제

Back Propagation에 대해서 쉽게 설명 한다면?

한 줄 정의

Chain Rule을 이용해 출력층에서 입력층으로 역방향으로 기울기를 전파하는 알고리즘

비유: 책임 추적

학생이 시험을 망쳤다 (Loss)
↓
어떤 선생님이 잘못 가르쳤나? (각 층의 책임)
↓
최근 선생님부터 역순으로 추적

출력 → ... → 입력
(역방향으로 책임 전파)

수학적 원리: Chain Rule

y = f(g(h(x)))

dy/dx = dy/dg × dg/dh × dh/dx

→ 각 층의 미분을 곱해서 전체 미분 계산

Forward vs Backward

Forward Pass (순방향):
입력 x → [W1] → z1 → [ReLU] → a1 → [W2] → z2 → Loss

Backward Pass (역방향):
dL/dW2 ← dL/dz2 ← dL/da1 ← dL/dz1 ← dL/dW1

단계별 과정

1. Forward: 입력 → 출력 → Loss 계산
2. Output Layer: dL/dW_출력 계산
3. Hidden Layer: Chain Rule로 dL/dW 계산 (역순)
4. Update: W = W - lr × dL/dW

코드

# PyTorch에서는 자동으로 처리
loss = criterion(output, target)
loss.backward()  # 역전파 (모든 gradient 계산)
optimizer.step()  # 가중치 업데이트

핵심: 중간 결과 저장

Forward에서 계산한 중간값 저장:
- z1, a1, z2 등

Backward에서 재사용:
- 저장 안 하면 다시 계산해야 함
- → 메모리 vs 계산 trade-off

면접 포인트

  • Chain Rule: 합성함수 미분
  • 역방향 전파: 출력 → 입력 방향
  • Forward에서 중간값 저장 필요

Local Minima 문제에도 불구하고 딥러닝이 잘 되는 이유는?

한 줄 답변

고차원에서는 Local Minima보다 Saddle Point가 더 많고, 대부분의 Local Minima도 충분히 좋음

고차원의 특성

저차원 (2D/3D): Local Minima 많음
고차원 (수백만 차원): Saddle Point가 대부분

이유:
- Local Minima = 모든 방향에서 최솟값
- 고차원에서 "모든" 방향이 동시에 최소? → 확률적으로 매우 낮음
- 대부분은 어떤 방향은 최소, 다른 방향은 최대 (Saddle Point)

Saddle Point vs Local Minima

Saddle Point (안장점):      Local Minima:
     ↗                          ↘↙
   ↙  ↘                         \_/
     ↖
어떤 방향: 최소             모든 방향: 최소
다른 방향: 최대             (고차원에서 드묾)

Local Minima도 괜찮은 이유

연구 결과:
- 대부분의 Local Minima는 Loss가 비슷
- Global Minima와 성능 차이 미미
- 오히려 Global Minima는 과적합 위험

"어떤 Local Minima든 찾으면 OK"

Saddle Point 탈출 방법

방법 설명
Momentum 관성으로 평평한 구간 통과
SGD 노이즈 랜덤 방향으로 탈출
Adam 적응적 학습률로 효과적 탈출
# Momentum으로 Saddle Point 탈출
optimizer = optim.SGD(params, lr=0.01, momentum=0.9)

# Adam (더 효과적)
optimizer = optim.Adam(params, lr=0.001)

면접 포인트

  • 고차원: Saddle Point >> Local Minima
  • Local Minima도 OK: 대부분 성능 비슷
  • Momentum, Adam으로 Saddle Point 탈출

GD가 Local Minima 문제를 피하는 방법은?

한 줄 답변

Momentum, SGD 노이즈, 학습률 조절 등으로 local minima/saddle point 탈출

주요 방법

방법 원리
Momentum 관성으로 작은 골짜기 통과
SGD 노이즈 미니배치 변동성이 탈출 도움
학습률 스케줄링 큰 LR → 작은 LR
Random Restart 여러 초기값에서 시작
Simulated Annealing 확률적 탈출

Momentum

일반 GD:     Momentum:
    ↘            ↘
     ●           ●↘  ← 관성으로 작은
    (갇힘)        ↘●    골짜기 넘어감

v = β × v + ∇L
θ = θ - α × v

관성 (β): 이전 방향 유지

SGD 노이즈

전체 데이터: 정확한 gradient → 갇힐 수 있음
미니배치: 노이즈 있는 gradient → 탈출 가능

노이즈가 오히려 도움!
→ "정규화" 효과까지

Learning Rate 조절

초반: 큰 LR → 빠르게 탐색, local minima 탈출
후반: 작은 LR → 정밀 수렴
# Warm Restart (Cosine Annealing)
scheduler = optim.lr_scheduler.CosineAnnealingWarmRestarts(
    optimizer, T_0=10, T_mult=2
)

# 주기적으로 LR을 올려서 탈출 시도

면접 포인트

  • Momentum: 관성으로 작은 minima 통과
  • SGD 노이즈: 미니배치 변동성이 탈출 도움
  • LR Scheduling: 큰→작은으로 탐색+수렴

Training 세트와 Test 세트를 분리하는 이유는?

한 줄 답변

모델의 일반화 성능을 평가하기 위해 (본 적 없는 데이터에서의 성능)

분리하지 않으면?

Train 데이터로만 평가:
- 모델이 "암기"해도 좋은 점수
- 실제 성능을 알 수 없음

예: 시험 문제를 미리 보고 외운 학생
→ 시험 점수 100점이지만 실력은?

올바른 평가

Train: 학습에 사용
Test: 평가에만 사용 (학습에 절대 사용 안 함)

→ Test 성능 = "처음 보는 데이터"에서의 성능
→ 일반화 성능 추정

면접 포인트

  • 일반화 성능 측정 목적
  • Train에서 좋아도 Test에서 나쁘면 과적합
  • Test는 마지막에 한 번만 사용

Validation 세트가 따로 있는 이유는?

한 줄 답변

하이퍼파라미터 튜닝과 Early Stopping 등 학습 중 의사결정에 사용

Train/Val/Test 역할

세트 역할 사용 시점
Train 모델 학습 매 epoch
Validation 하이퍼파라미터 선택, Early Stop 학습 중
Test 최종 성능 평가 마지막 1회

Validation이 필요한 이유

Test로 하이퍼파라미터 튜닝하면?
→ Test에 과적합!
→ 진짜 일반화 성능 모름

해결: Validation으로 튜닝
     Test는 최종 평가용으로 보존

사용 예시

# Early Stopping
best_val_loss = float('inf')
for epoch in range(epochs):
    train_loss = train(model, train_loader)
    val_loss = evaluate(model, val_loader)

    if val_loss < best_val_loss:
        best_val_loss = val_loss
        save_model(model)
    else:
        patience -= 1
        if patience == 0:
            break  # Early Stop

# 최종 평가 (Test는 여기서 한 번만)
test_accuracy = evaluate(model, test_loader)

면접 포인트

  • Validation: 하이퍼파라미터 튜닝, Early Stop
  • Test: 최종 평가만 (1회)
  • Test로 튜닝하면 Test에 과적합

Test 세트가 오염되었다는 말의 뜻은?

한 줄 답변

Test 데이터 정보가 학습 과정에 누출되어 일반화 성능 평가가 불가능해진 상태

오염 사례

유형 예시
직접 사용 Test로 하이퍼파라미터 튜닝
전처리 누수 전체 데이터로 스케일러 fit
데이터 누수 Train/Test에 같은 데이터
시간 누수 미래 데이터로 과거 예측 학습

전처리 누수 예시

# ❌ 오염 (Data Leakage)
scaler.fit(전체_데이터)  # Test 통계 포함!
X_train = scaler.transform(X_train)
X_test = scaler.transform(X_test)

# ✅ 올바름
scaler.fit(X_train만)  # Train만!
X_train = scaler.transform(X_train)
X_test = scaler.transform(X_test)

왜 문제인가?

오염되면:
- Test 성능이 실제보다 좋게 나옴
- 실제 배포 시 성능 급락
- "일반화 성능"을 측정하는 의미 상실

면접 포인트

  • Test 정보가 학습에 누출 = 오염
  • 전처리도 Train 데이터만으로
  • 오염 시 Test 성능 = 낙관적 추정

오버피팅일 경우 어떻게 대처해야 할까요?

한 줄 답변

데이터 증강, 정규화(Dropout, L2), Early Stopping, 모델 단순화

오버피팅 진단

Train Loss: 계속 감소
Val Loss: 어느 시점부터 증가

     │  Train
Loss │   ↘____
     │       ↗ Val (과적합 시작)
     └────────→ Epoch

해결 방법

방법 설명
데이터 증강 학습 데이터 늘리기
Dropout 랜덤 뉴런 비활성화
L2 정규화 가중치 크기 패널티
Batch Norm 내부 공변량 이동 감소
Early Stopping Val 성능 기준 조기 종료
모델 단순화 층/뉴런 수 감소

코드 예시

# Dropout
nn.Dropout(p=0.5)

# L2 정규화 (weight_decay)
optimizer = optim.Adam(params, lr=0.001, weight_decay=1e-4)

# Early Stopping
if val_loss > best_val_loss:
    patience -= 1
    if patience == 0:
        break

# Data Augmentation
transforms.RandomHorizontalFlip()
transforms.RandomRotation(15)

면접 포인트

  • 데이터 ↑: Data Augmentation
  • 모델 복잡도 ↓: Dropout, L2, 단순화
  • 학습 조절: Early Stopping

Regularization이란 무엇인가?

한 줄 정의

모델의 복잡도를 제한하여 과적합을 방지하는 기법

정규화 종류

종류 방법
L1/L2 가중치에 패널티
Dropout 뉴런 랜덤 비활성화
Batch Norm 분포 정규화
Data Augmentation 데이터 다양화
Early Stopping 조기 종료
Weight Decay L2와 동일 (PyTorch)

수식

L1: Loss + λΣ|w|     → Sparse
L2: Loss + λΣw²      → Small weights

면접 포인트

  • 과적합 방지 목적
  • Dropout, L2, BN이 대표적
  • Bias-Variance tradeoff 조절

Batch Normalization의 효과는?

한 줄 정의

미니배치 단위로 평균 0, 분산 1로 정규화하여 학습 안정화

효과

효과 설명
학습 안정화 Internal Covariate Shift 감소
빠른 수렴 더 큰 Learning Rate 사용 가능
정규화 효과 약간의 과적합 방지
초기화 민감도 감소 초기값에 덜 민감

수식

μ = mean(x)
σ² = var(x)
x̂ = (x - μ) / √(σ² + ε)
y = γx̂ + β   ← 학습 가능 파라미터

코드

nn.BatchNorm2d(num_features)  # CNN 뒤
nn.BatchNorm1d(num_features)  # FC 뒤

면접 포인트

  • 미니배치 정규화 → 학습 안정화, 수렴 속도 ↑
  • γ, β: 학습 가능 (스케일, 시프트)
  • Train과 Inference 모드 다름 (running mean/var)

Dropout의 효과는?

한 줄 정의

학습 시 뉴런을 랜덤하게 비활성화하여 과적합을 방지하는 정규화 기법

동작 원리

학습 시 (p=0.5):
[●]─[●]─[●]      랜덤하게 50% 비활성화
[●]─[○]─[●]  →  [○]: 비활성화 (출력=0)
[●]─[●]─[○]      [●]: 활성화

추론 시:
[●]─[●]─[●]      모든 뉴런 사용
[●]─[●]─[●]  →  단, 출력을 (1-p)로 스케일
[●]─[●]─[●]

왜 효과적인가?

효과 설명
앙상블 효과 매번 다른 서브네트워크 학습 → 여러 모델 평균 효과
Co-adaptation 방지 특정 뉴런 조합에 의존 못함
노이즈 주입 학습 데이터에 노이즈 추가 효과
희소 표현 더 로버스트한 특징 학습

앙상블 해석

Dropout p=0.5, 뉴런 n개:
→ 가능한 서브네트워크: 2^n 개

각 미니배치마다 다른 서브네트워크 학습
→ 추론 시 모든 서브네트워크 평균!

= 매우 많은 모델의 앙상블

코드

import torch.nn as nn

# Dropout 적용
model = nn.Sequential(
    nn.Linear(784, 256),
    nn.ReLU(),
    nn.Dropout(p=0.5),  # 50% 비활성화
    nn.Linear(256, 128),
    nn.ReLU(),
    nn.Dropout(p=0.5),
    nn.Linear(128, 10)
)

# 학습/추론 모드 전환
model.train()  # Dropout 활성화
model.eval()   # Dropout 비활성화, 스케일링 적용

주의사항

# ⚠️ 추론 시 반드시 eval() 모드!
model.eval()  # 중요!
with torch.no_grad():
    output = model(x)

# eval() 안 하면:
# - Dropout이 계속 적용됨
# - 결과가 매번 달라짐
# - 성능 저하

위치별 Dropout 비율

일반적 권장:
- 입력층 직후: 0.2
- 은닉층: 0.5
- 출력층 직전: 사용 안 함

CNN에서:
- FC 층에만 주로 사용
- Conv 층은 0.2~0.3 또는 사용 안 함

면접 포인트

  • 앙상블 효과: 2^n개 서브네트워크 학습
  • Co-adaptation 방지: 특정 뉴런 의존 방지
  • train/eval 모드 전환 필수

BN 적용해서 학습 이후 실제 사용시에 주의할 점은?

한 줄 답변

eval() 모드 전환 필수! Training 통계 대신 Running Statistics 사용

Train vs Inference 차이

Training (model.train()):
- 현재 미니배치의 mean, var 계산
- Running mean, var 업데이트 (이동 평균)

Inference (model.eval()):
- 미니배치 통계 ❌
- 저장된 Running mean, var 사용 ✓

Running Statistics

학습 중 누적:
running_mean = momentum × running_mean + (1-momentum) × batch_mean
running_var = momentum × running_var + (1-momentum) × batch_var

기본 momentum = 0.1

→ 전체 학습 데이터의 통계 근사

주의사항

# ⚠️ 반드시 eval() 모드!
model.eval()  # 중요!!!

with torch.no_grad():
    output = model(x)

# eval() 안 하면?
# - 추론 시 배치마다 다른 결과
# - 배치 크기에 따라 성능 변동
# - 배치 크기 1이면 정규화 불가

문제 상황과 해결

문제 원인 해결
배치마다 결과 다름 eval() 안 함 model.eval() 추가
배치 크기 1에서 오류 Train 모드 BN eval() 전환
학습-추론 성능 차이 큼 통계 불일치 충분한 학습 또는 학습률 조정

실제 사용 패턴

# 올바른 추론 코드
def predict(model, x):
    model.eval()  # 1. eval 모드 전환
    with torch.no_grad():  # 2. gradient 계산 끄기
        output = model(x)
    return output

# 학습 재개 시
model.train()  # train 모드로 복원

저장/불러오기

# 저장 시 running statistics 포함
torch.save(model.state_dict(), 'model.pth')

# 불러오기
model.load_state_dict(torch.load('model.pth'))
model.eval()  # 추론 모드!

면접 포인트

  • eval() 모드: Running mean/var 사용
  • train() 모드: 미니배치 통계 사용
  • 배치 크기 1에서 Train 모드 BN 불가

SGD, RMSprop, Adam에 대해서 아는대로 설명한다면?

한 줄 정의

SGD: 기본 | RMSprop: 적응적 학습률 | Adam: Momentum + RMSprop 결합

비교 표

Optimizer 특징 수식 핵심
SGD 기본, 단순 θ = θ - α∇L
SGD+Momentum 관성 추가 v = βv + ∇L
RMSprop 학습률 적응 α / √(v + ε)
Adam Momentum + RMSprop m/(√v + ε)

SGD (Stochastic Gradient Descent)

θ = θ - α × ∇L

단점:
- 모든 파라미터에 동일한 학습률
- 희소 feature에 불리
- 수렴 느림

SGD + Momentum

v = β × v + ∇L        (관성)
θ = θ - α × v

β: 보통 0.9

장점:
- Local minima 탈출
- 수렴 속도 개선
- 진동 감소

RMSprop

v = β × v + (1-β) × (∇L)²   (기울기 제곱의 이동평균)
θ = θ - α / √(v + ε) × ∇L

특징:
- 파라미터별 적응적 학습률
- 자주 업데이트되는 파라미터: LR 감소
- 드물게 업데이트: LR 유지

Adam (Adaptive Moment Estimation)

m = β₁ × m + (1-β₁) × ∇L        (1st moment, 평균)
v = β₂ × v + (1-β₂) × (∇L)²    (2nd moment, 분산)

m̂ = m / (1 - β₁ᵗ)              (Bias 보정)
v̂ = v / (1 - β₂ᵗ)

θ = θ - α × m̂ / (√v̂ + ε)

기본값: β₁=0.9, β₂=0.999, ε=1e-8

코드

import torch.optim as optim

# SGD
optim.SGD(params, lr=0.01)

# SGD + Momentum
optim.SGD(params, lr=0.01, momentum=0.9)

# RMSprop
optim.RMSprop(params, lr=0.001, alpha=0.99)

# Adam (가장 많이 사용)
optim.Adam(params, lr=0.001, betas=(0.9, 0.999))

# AdamW (L2 정규화 개선)
optim.AdamW(params, lr=0.001, weight_decay=0.01)

선택 가이드

일반적 추천: Adam → 빠른 수렴, 튜닝 용이
대규모 모델: AdamW → 정규화 개선
세밀한 수렴: SGD+Momentum → 종종 더 좋은 최종 성능
Transformer: AdamW + warmup

면접 포인트

  • Adam = Momentum + RMSprop
  • 적응적 학습률: RMSprop, Adam
  • 실무 기본: Adam/AdamW

SGD에서 Stochastic의 의미는?

한 줄 답변

미니배치를 랜덤 샘플링하여 gradient를 계산하는 것 (확률적 = Stochastic)

Full Batch vs Stochastic

Full Batch GD:
- 전체 데이터로 gradient 계산
- 정확하지만 느림
- 메모리 많이 사용

Stochastic GD (SGD):
- 랜덤 샘플(미니배치)로 gradient 계산
- 노이즈 있지만 빠름
- 메모리 효율적

왜 Stochastic?

전체 데이터 N개:
True Gradient = (1/N) × Σ∇L(xᵢ)

미니배치 B개:
SGD Gradient = (1/B) × Σ∇L(xⱼ)  (j는 랜덤 샘플)

기대값:
E[SGD Gradient] = True Gradient

→ 평균적으로 맞는 방향!
→ 노이즈가 오히려 정규화 효과

시각적 이해

Full Batch:            SGD:
     ↘                   ↘
      ↘                  ↗↘    ← 지그재그
       ↘                  ↘↗
        ●                  ●

정확하지만 느림       노이즈 있지만 빠름
                     + Local minima 탈출 가능

미니배치 크기별 비교

방식 배치 크기 특징
Full Batch GD 전체 정확, 느림, 메모리 ↑
SGD 1 매우 노이즈, 빠름
Mini-batch SGD 32~512 균형, 실용적

면접 포인트

  • Stochastic = 랜덤 샘플링
  • 기대값은 True Gradient와 동일
  • 노이즈가 정규화 + Local minima 탈출 효과

미니배치를 작게 할때의 장단점은?

한 줄 답변

장점: 노이즈로 정규화/탈출 효과 | 단점: 학습 불안정, GPU 효율 저하

배치 크기별 특성

배치 크기 Gradient 노이즈 일반화 학습 속도 GPU 활용
작음 (8-32) 높음 좋음 느림 낮음
중간 (64-256) 중간 중간 중간 적정
큼 (512+) 낮음 나쁠 수 있음 빠름 높음

작은 배치의 장점

1. 정규화 효과 (Regularization)
   - Gradient 노이즈가 암묵적 정규화
   - 과적합 방지

2. Local Minima 탈출
   - 노이즈로 작은 골짜기 탈출
   - 더 평평한(flat) minima 도달

3. 메모리 절약
   - GPU 메모리 적게 사용
   - 큰 모델 학습 가능

작은 배치의 단점

1. 학습 불안정
   - Gradient 분산 큼
   - Loss 진동

2. 느린 학습
   - iteration당 업데이트 횟수 ↑
   - 전체 epoch 시간 ↑

3. GPU 효율 저하
   - 병렬 처리 활용 못함
   - GPU utilization 낮음

4. BatchNorm 문제
   - 통계 추정 불안정
   - 배치 크기 8 미만 비추천

큰 배치의 trade-off

큰 배치 사용 시:
- 학습률도 비례해서 증가 필요
- Linear Scaling Rule: LR × (batch_size / base_batch)
- Warmup 필수

Sharp Minima 문제:
- 큰 배치 → Sharp minima로 수렴
- 일반화 성능 저하 가능

실무 권장

# 일반적인 선택
batch_size = 32 ~ 128

# 메모리 부족 시
batch_size = 8 ~ 16 + Gradient Accumulation

# Gradient Accumulation
accumulation_steps = 4
for i, (x, y) in enumerate(loader):
    loss = model(x, y) / accumulation_steps
    loss.backward()
    if (i + 1) % accumulation_steps == 0:
        optimizer.step()
        optimizer.zero_grad()

면접 포인트

  • 작은 배치: 노이즈 ↑ → 정규화 효과, 일반화 좋음
  • 큰 배치: 효율적이지만 sharp minima 위험
  • BN은 배치 8 이상 권장

모멘텀의 수식을 적어 본다면?

한 줄 정의

이전 gradient의 지수 이동평균을 현재 업데이트에 반영하는 방식

수식

Standard Momentum:
v_t = β × v_{t-1} + ∇L(θ_{t-1})
θ_t = θ_{t-1} - α × v_t

β: momentum 계수 (보통 0.9)
α: 학습률
v: 속도 (velocity)

직관적 이해

공이 산을 굴러내려가는 것:

일반 GD:     Momentum:
  ●            ●
  ↓            ↓ (가속!)
  ●            ●
  ↓              ↓↓ (더 가속)
  ●              ●
               (관성으로 통과)

왜 효과적인가?

1. 진동 감소
   지그재그 경로 → 매끄러운 경로

   Without:       With Momentum:
   ↗↘↗↘          →→→→
     ↘              →

2. 가속 효과
   평평한 구간에서 속도 유지

3. Local minima 탈출
   관성으로 작은 골짜기 넘어감

Nesterov Momentum (NAG)

Standard: 현재 위치에서 gradient
Nesterov: 미리 가본 위치에서 gradient

v_t = β × v_{t-1} + ∇L(θ_{t-1} - β × v_{t-1})
θ_t = θ_{t-1} - α × v_t

"앞서 보기(lookahead)" → 더 정확한 방향

코드

import torch.optim as optim

# Standard Momentum
optimizer = optim.SGD(params, lr=0.01, momentum=0.9)

# Nesterov Momentum
optimizer = optim.SGD(params, lr=0.01, momentum=0.9, nesterov=True)

β값에 따른 효과

β = 0:   Momentum 없음 (일반 SGD)
β = 0.9: 표준 (90% 관성 유지)
β = 0.99: 강한 관성 (수렴 느려질 수 있음)

면접 포인트

  • v = βv + ∇L, θ = θ - αv
  • β = 0.9 표준
  • Nesterov: 앞서서 gradient 계산 → 더 정확

하이퍼 파라미터는 무엇인가요?

한 줄 정의

학습 전에 사람이 설정하는 값. 모델이 학습하지 않음

파라미터 vs 하이퍼파라미터

구분 파라미터 하이퍼파라미터
예시 Weight, Bias Learning Rate, Batch Size
설정 학습으로 결정 사람이 설정
최적화 Gradient Descent Grid Search, Random Search

주요 하이퍼파라미터

학습 관련:
- Learning Rate: 가장 중요!
- Batch Size: 32~512
- Epochs: 학습 반복 횟수
- Optimizer 종류: Adam, SGD 등

모델 구조:
- 층 수 (Depth)
- 뉴런 수 (Width)
- Dropout 비율
- Activation Function

정규화:
- Weight Decay (L2)
- Dropout Rate
- Early Stopping patience

튜닝 방법

방법 설명
Grid Search 모든 조합 시도
Random Search 랜덤 샘플링 (더 효율적)
Bayesian Optimization 이전 결과로 다음 추정
Learning Rate Finder LR 자동 탐색
# Random Search 예시
from sklearn.model_selection import RandomizedSearchCV

param_dist = {
    'lr': [1e-4, 1e-3, 1e-2],
    'batch_size': [32, 64, 128],
    'dropout': [0.3, 0.5, 0.7]
}

면접 포인트

  • 학습 전 설정, 학습으로 결정 안 됨
  • Learning Rate가 가장 중요
  • Grid Search < Random Search (효율성)

Weight Initialization 방법에 대해 말해주세요

한 줄 정의

학습 시작 전 가중치 초기값 설정 방법. Vanishing/Exploding Gradient 방지

왜 중요한가?

나쁜 초기화:
- 모든 가중치 = 0: 모든 뉴런 동일 → 학습 안 됨
- 너무 큰 값: Exploding Gradient
- 너무 작은 값: Vanishing Gradient

좋은 초기화:
- 층마다 활성값 분산 유지
- 깊은 네트워크도 안정적 학습

주요 초기화 방법

방법 수식 적합한 활성화
Xavier/Glorot W ~ N(0, 2/(n_in + n_out)) Sigmoid, Tanh
He (Kaiming) W ~ N(0, 2/n_in) ReLU, Leaky ReLU
LeCun W ~ N(0, 1/n_in) SELU

Xavier (Glorot) Initialization

이론:
- 입력과 출력의 분산을 동일하게 유지
- Sigmoid, Tanh에 적합

Var(W) = 2 / (n_in + n_out)

n_in: 입력 뉴런 수
n_out: 출력 뉴런 수

He (Kaiming) Initialization

이론:
- ReLU가 절반의 뉴런만 활성화
- Xavier보다 2배 큰 분산 필요

Var(W) = 2 / n_in

ReLU 계열에 필수!

코드

import torch.nn as nn

# Xavier (Tanh, Sigmoid)
nn.init.xavier_uniform_(layer.weight)
nn.init.xavier_normal_(layer.weight)

# He/Kaiming (ReLU)
nn.init.kaiming_uniform_(layer.weight, mode='fan_in', nonlinearity='relu')
nn.init.kaiming_normal_(layer.weight, mode='fan_in', nonlinearity='relu')

# PyTorch Linear/Conv는 기본적으로 Kaiming 사용

실무 팁

일반적으로:
- PyTorch 기본 초기화 그대로 사용
- ReLU 계열: He (이미 기본값)
- Transformer: 특별한 초기화 (GPT-2 스타일)

문제 발생 시:
- Gradient Exploding → 초기화 분산 줄이기
- Gradient Vanishing → 초기화 분산 늘리기

면접 포인트

  • Xavier: Sigmoid/Tanh, 분산 = 2/(n_in + n_out)
  • He: ReLU, 분산 = 2/n_in
  • 목표: 층간 분산 유지 → Gradient 안정화

딥러닝할 때 GPU를 쓰면 좋은 이유는?

한 줄 답변

병렬 연산에 최적화되어 행렬 연산이 CPU보다 수십~수백 배 빠름

CPU vs GPU

특성 CPU GPU
코어 수 8~64 수천 개
코어당 성능 높음 낮음
용도 순차적 복잡 연산 단순 병렬 연산
메모리 대역폭 낮음 높음

왜 GPU가 딥러닝에 적합한가?

딥러닝 = 대부분 행렬 연산

행렬 곱: C = A × B
- 각 원소 계산이 독립적
- 동시에 병렬 처리 가능

GPU:
- 수천 코어가 각 원소 동시 계산
- 높은 메모리 대역폭으로 빠른 데이터 전송

시각적 이해

CPU (8코어):
████████ ████████ ...  (순차 처리)

GPU (1000+ 코어):
████████████████████████████████████████  (동시 처리)
████████████████████████████████████████
████████████████████████████████████████
...

속도 비교 예시

ImageNet 학습 (ResNet-50):
CPU: 수 주
GPU (V100 1장): 수 일
GPU (V100 8장): 수 시간

→ 100배 이상 차이!

GPU 활용 코드

import torch

# GPU 사용 설정
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')

# 모델과 데이터를 GPU로
model = model.to(device)
x = x.to(device)
y = y.to(device)

# 학습
output = model(x)
loss = criterion(output, y)

주요 GPU 연산

병렬 처리에 적합:
- 행렬 곱셈 (Linear layer)
- Convolution
- Element-wise 연산 (ReLU, Softmax)
- Batch 처리

병렬 처리에 부적합:
- 순차적 의존성 있는 연산
- 작은 데이터 (GPU 전송 오버헤드)

면접 포인트

  • 병렬 연산: 수천 코어, 행렬 연산 최적화
  • 메모리 대역폭: 빠른 데이터 처리
  • CPU는 순차, GPU는 병렬

학습시 필요한 GPU 메모리는 어떻게 계산하는가?

한 줄 답변

모델 파라미터 + 활성값 + Gradient + 옵티마이저 상태 합산

메모리 구성 요소

구성 요소 설명 크기
Model Parameters Weight, Bias P × 4 bytes (FP32)
Gradients 각 파라미터의 gradient P × 4 bytes
Optimizer States Adam: m, v P × 8 bytes (Adam)
Activations 중간 층 출력 가변 (배치 비례)

대략적 계산

FP32 기준:

모델 파라미터: P 개
총 메모리 ≈ P × 4 × (1 + 1 + 2) + Activations
         = P × 16 bytes + Activations

예: 1B 파라미터 모델
= 1B × 16 bytes = 16GB + Activations

Activations ≈ Batch × Sequence × Hidden × Layers × 4 bytes

실제 예시

GPT-2 Small (125M):
- Parameters: 125M × 4 = 500 MB
- Gradients: 500 MB
- Adam states: 1 GB
- Activations (batch=32): ~3 GB
→ 총 ~5 GB

BERT-Base (110M):
- 유사하게 ~4-6 GB (batch 32)

배치 크기와 메모리

배치 크기 ↑ → Activations ↑ → 메모리 ↑

Activations ∝ Batch Size

메모리 부족 시:
1. Batch Size 줄이기
2. Gradient Accumulation
3. Mixed Precision (FP16)
4. Gradient Checkpointing

메모리 최적화 기법

# 1. Mixed Precision (메모리 ~50% 절약)
from torch.cuda.amp import autocast, GradScaler
scaler = GradScaler()

with autocast():
    output = model(x)
    loss = criterion(output, y)

# 2. Gradient Checkpointing (메모리 ↓, 계산 ↑)
from torch.utils.checkpoint import checkpoint
output = checkpoint(layer, input)

# 3. Gradient Accumulation
accumulation_steps = 4
loss = loss / accumulation_steps

확인 방법

# 현재 GPU 메모리 사용량
print(torch.cuda.memory_allocated() / 1e9, "GB")
print(torch.cuda.memory_reserved() / 1e9, "GB")

# NVIDIA SMI
# nvidia-smi

면접 포인트

  • 파라미터 + Gradient + Optimizer + Activations
  • Adam은 m, v 저장 → 파라미터의 3배
  • Activations은 배치 크기에 비례

뉴럴넷의 가장 큰 단점은 무엇인가?

한 줄 답변

해석 불가능성(Black Box), 데이터 의존성, 계산 비용

주요 단점

단점 설명
Black Box 왜 그런 결정을 했는지 설명 어려움
데이터 필요 대량의 레이블된 데이터 필요
계산 비용 GPU, 전력, 시간 많이 소모
과적합 데이터 부족 시 쉽게 과적합
재현성 동일 결과 재현 어려움

1. Black Box 문제

전통 ML:                딥러닝:
"나이 > 60이면 고위험"   "이 환자는 고위험"
↓                       ↓
이해 가능               왜? 모름

규제 산업(금융, 의료)에서 문제:
- 설명 의무 (XAI 필요)
- 신뢰성 문제

2. 데이터 의존성

전통 ML: 수백~수천 샘플로 가능
딥러닝: 수만~수백만 샘플 필요

데이터 부족 시:
- 과적합
- 일반화 실패
- Transfer Learning으로 일부 완화

3. 계산 비용

GPT-3 학습:
- 수천 GPU
- 수백만 달러 전기료
- 수 주 학습 시간
- 막대한 CO2 배출

vs 전통 ML:
- CPU로 충분
- 수 분~수 시간

4. 기타 단점

불확실성 추정 어려움:
- "확신도"가 실제 확률 아님
- Calibration 필요

적대적 공격 취약:
- 미세한 노이즈로 완전히 다른 예측
- 보안 문제

분포 이동에 약함:
- 학습 분포와 다른 데이터에 취약
- OOD (Out-of-Distribution) 감지 필요

대안/완화 방법

문제 완화 방법
Black Box XAI (SHAP, LIME, Attention 시각화)
데이터 부족 Transfer Learning, Data Augmentation
계산 비용 경량화, 양자화, Pruning
불확실성 Bayesian NN, MC Dropout

면접 포인트

  • Black Box: 해석/설명 어려움
  • 데이터/계산 비용 높음
  • 완화: XAI, Transfer Learning, 경량화

One-Shot Learning은 무엇인가?

한 줄 정의

단 하나의 예시만으로 새로운 클래스를 인식하는 학습 방식

Few-Shot Learning 분류

Zero-Shot: 예시 0개 (설명만으로)
One-Shot: 예시 1개
Few-Shot: 예시 2~5개

일반 딥러닝: 수천~수만 예시 필요

왜 필요한가?

현실 상황:
- 희귀 질병: 사례 1건
- 새로운 사기 패턴: 첫 발생
- 얼굴 인식: 등록 사진 1장

기존 딥러닝 한계:
- 새 클래스마다 대량 데이터 수집
- 재학습 필요
- 비현실적

주요 접근법

방법 원리
Siamese Network 두 입력의 유사도 학습
Prototypical Network 클래스별 프로토타입 비교
Matching Network Attention 기반 매칭
MAML 빠르게 적응하는 초기값 학습

Siamese Network

          ┌──────────┐
입력 A ──→│          │──→ 임베딩 A
          │ 공유 CNN │              ├→ 거리 계산 → 같은 클래스?
입력 B ──→│          │──→ 임베딩 B
          └──────────┘

같은 클래스: 거리 작게
다른 클래스: 거리 크게

→ 새 클래스도 1장으로 임베딩 비교

Prototypical Network

Support Set (각 클래스 1개):
클래스 A: [●]  →  프로토타입 A (평균)
클래스 B: [■]  →  프로토타입 B (평균)
클래스 C: [▲]  →  프로토타입 C (평균)

Query:
새 입력 [?] → 어느 프로토타입에 가까운가?

코드 예시 (Siamese)

class SiameseNetwork(nn.Module):
    def __init__(self):
        super().__init__()
        self.encoder = nn.Sequential(
            nn.Conv2d(1, 64, 3),
            nn.ReLU(),
            # ...
        )

    def forward(self, x1, x2):
        # 같은 encoder로 임베딩
        z1 = self.encoder(x1)
        z2 = self.encoder(x2)
        # 거리 계산
        distance = torch.abs(z1 - z2)
        return distance

# 학습: Contrastive Loss
# 같은 클래스면 거리 ↓, 다른 클래스면 거리 ↑

응용 분야

1. 얼굴 인식/검증
   - 등록 사진 1장으로 본인 확인

2. 서명/지문 검증
   - 등록 샘플과 비교

3. 약물 발견
   - 새로운 분자 유사성

4. 음성 인식
   - 화자 등록 (몇 초 음성)

면접 포인트

  • 1개 예시로 새 클래스 인식
  • Siamese: 유사도 학습
  • Prototypical: 클래스 프로토타입 비교
  • 응용: 얼굴 인식, 서명 검증