개념
사건, 표본공간, 확률
표본공간(sample space) S는 가능한 모든 결과(outcome)의 집합입니다. 사건(event)은 표본공간의 부분집합입니다. 확률은 사건을 0과 1 사이의 숫자로 매핑(mapping)합니다.
동전 던지기:
S = {H, T}
P(H) = 0.5, P(T) = 0.5
주사위 한 번 굴리기:
S = {1, 2, 3, 4, 5, 6}
P(짝수) = P({2, 4, 6}) = 3/6 = 0.5
확률 전체는 세 가지 공리(axiom)에서 시작합니다.
- 모든 사건
A에 대해 P(A) >= 0입니다.
P(S) = 1입니다. 무엇인가는 반드시 일어납니다.
A와 B가 동시에 일어날 수 없으면 P(A or B) = P(A) + P(B)입니다.
베이즈 정리(Bayes' theorem), 기댓값(expectation), 분포(distribution) 같은 나머지 개념은 모두 이 세 규칙에서 나옵니다.
조건부 확률과 독립성
조건부 확률(conditional probability) P(A|B)는 B가 일어났다는 조건에서 A가 일어날 확률입니다.
P(A|B) = P(A and B) / P(B)
예시: 카드 한 벌
P(King | Face card) = P(King and Face card) / P(Face card)
= (4/52) / (12/52)
= 4/12 = 1/3
두 사건이 독립(independent)이라는 것은 하나를 알아도 다른 하나에 대해 아무 정보도 얻지 못한다는 뜻입니다.
독립: P(A|B) = P(A)
동치: P(A and B) = P(A) * P(B)
동전 던지기는 독립입니다. 카드를 복원하지 않고 뽑는 상황은 독립이 아닙니다.
확률질량함수와 확률밀도함수
이산 확률변수(discrete random variable)는 확률질량함수(probability mass function; PMF)를 가집니다. 각 결과(outcome)에는 직접 읽을 수 있는 특정 확률이 있습니다.
PMF: P(X = k)
공정한 주사위:
P(X = 1) = 1/6
P(X = 2) = 1/6
...
P(X = 6) = 1/6
모든 확률의 합 = 1
연속 확률변수(continuous random variable)는 확률밀도함수(probability density function; PDF)를 가집니다. 한 점에서의 밀도(density)는 확률이 아닙니다. 확률은 구간 위에서 밀도를 적분해야 나옵니다.
PDF: f(x)
P(a <= X <= b) = a부터 b까지 f(x)의 적분값
f(x)는 1보다 클 수 있습니다. 확률이 아니라 밀도이기 때문입니다.
-inf부터 +inf까지 f(x) dx의 적분값 = 1
이 구분은 ML에서 중요합니다. 분류 모델의 출력은 이산적인 선택이므로 PMF입니다. 변분 오토인코더(Variational Autoencoder; VAE)의 잠재 공간(latent space)은 연속적이므로 PDF를 사용합니다.
자주 쓰는 분포
베르누이(Bernoulli): 한 번의 시행, 두 가지 결과. 이진 분류(binary classification)를 모델링합니다.
P(X = 1) = p
P(X = 0) = 1 - p
평균 = p, 분산 = p(1-p)
범주형(Categorical): 한 번의 시행, k개 결과. 다중 클래스 분류(multi-class classification), 즉 소프트맥스 출력을 모델링합니다.
P(X = i) = p_i, 단 sum of p_i = 1
예시: P(cat) = 0.7, P(dog) = 0.2, P(bird) = 0.1
균등(Uniform): 모든 결과의 가능도(likelihood)가 같습니다. 무작위 초기화(random initialization)에 사용됩니다.
이산: P(X = k) = 1/n for k in {1, ..., n}
연속: f(x) = 1/(b-a) for x in [a, b]
정규(Normal, Gaussian): 종 모양의 곡선(bell curve)입니다. 평균(mean, mu)과 분산(variance, sigma^2)으로 매개화됩니다.
f(x) = (1 / sqrt(2*pi*sigma^2)) * exp(-(x - mu)^2 / (2*sigma^2))
표준 정규(standard normal): mu = 0, sigma = 1
데이터의 68%가 1 sigma 이내
95%가 2 sigma 이내
99.7%가 3 sigma 이내
포아송(Poisson): 고정된 구간 안에서 드물게 일어나는 사건의 발생 횟수(count)입니다. 사건 발생률(event rate)을 모델링합니다.
P(X = k) = (lambda^k * e^(-lambda)) / k!
평균 = lambda, 분산 = lambda
기댓값과 분산
기댓값(expected value)은 결과의 가중 평균(weighted average)입니다.
이산: E[X] = sum of x_i * P(X = x_i)
연속: E[X] = integral of x * f(x) dx
분산(variance)은 평균 주변의 퍼진 정도(spread)를 측정합니다.
Var(X) = E[(X - E[X])^2] = E[X^2] - (E[X])^2
표준편차(standard deviation) = sqrt(Var(X))
ML에서 기댓값은 손실 함수의 형태로 자주 등장합니다. 데이터 분포 위에서 평균 손실을 계산하기 때문입니다. 분산은 모델의 안정성(stability)을 알려 줍니다. 기울기(gradient)의 분산이 크면 학습이 잡음(noise)에 흔들립니다.
결합분포와 주변분포
결합분포(joint distribution) P(X, Y)는 두 확률 변수를 함께 설명합니다.
결합 PMF 예시(X = 날씨, Y = 우산):
| Y=0 (우산 없음) | Y=1 (우산 있음) | 주변분포 P(X) |
|---|
| X=0 (맑음) | 0.40 | 0.10 | P(X=0) = 0.50 |
| X=1 (비) | 0.05 | 0.45 | P(X=1) = 0.50 |
| 주변분포 P(Y) | P(Y=0) = 0.45 | P(Y=1) = 0.55 | 1.00 |
주변분포(marginal distribution)는 다른 변수를 합으로 제거해 얻습니다.
P(X = x) = 모든 y에 대해 P(X = x, Y = y)를 sum
위 표의 행 합계와 열 합계가 주변분포입니다.
정규분포가 어디에나 등장하는 이유
중심극한정리는 많은 독립 확률 변수의 합 또는 평균이, 원래 분포의 모양과 무관하게 정규분포로 수렴한다고 말합니다.
주사위 1개 굴리기: 균등 분포(평평함)
주사위 2개의 평균: 삼각 분포(가운데가 솟음)
주사위 30개의 평균: 거의 완벽한 종 모양
이 현상은 어떤 출발 분포에서도 동일하게 일어납니다.
그래서 아래와 같은 현상이 나타납니다.
- 측정 오차(measurement error)는 대체로 정규분포에 가깝습니다. 작은 독립적 원인이 많이 합쳐지기 때문입니다.
- 신경망(neural network)의 가중치 초기화(weight initialization)는 정규분포를 사용합니다.
- 확률적 경사 하강법(Stochastic Gradient Descent; SGD)의 기울기 잡음(gradient noise)도 대체로 정규분포에 가깝습니다. 많은 샘플 기울기의 합이기 때문입니다.
- 정규분포는 주어진 평균과 분산에 대해 최대 엔트로피 분포(maximum entropy distribution)입니다.
로그 확률
원시 확률(raw probability)은 수치적 문제를 만듭니다. 작은 확률을 많이 곱하면 빠르게 0으로 언더플로(underflow)가 발생합니다.
P(sentence) = P(word1) * P(word2) * ... * P(word_n)
= 0.01 * 0.003 * 0.02 * ...
-> 0.0 (약 30개 항을 곱한 뒤 언더플로 발생)
로그 확률(log probability)은 이 문제를 해결합니다. 곱셈이 덧셈으로 바뀝니다.
log P(sentence) = log P(word1) + log P(word2) + ... + log P(word_n)
= -4.6 + -5.8 + -3.9 + ...
-> 유한한 값 (언더플로 없음)
규칙은 아래와 같습니다.
log(a * b) = log(a) + log(b)
- 로그 확률은 항상 0 이하입니다.
0 < P <= 1이기 때문입니다.
- 값이 더 음수일수록 발생 가능성이 더 낮습니다.
- 교차 엔트로피 손실은 정답 클래스의 음의 로그 확률입니다.
확률분포로서의 소프트맥스
신경망은 원시 점수(raw score), 즉 로짓(logit)을 출력합니다. 소프트맥스(softmax)는 로짓을 유효한 확률 분포로 변환합니다.
softmax(z_i) = exp(z_i) / sum(exp(z_j) for all j)
성질:
- 모든 출력값은 (0, 1) 사이에 있습니다.
- 모든 출력값의 합은 1입니다.
- 입력의 상대적 순서를 보존합니다.
- exp()는 로짓 사이의 차이를 증폭합니다.
소프트맥스 기법(softmax trick)은 오버플로(overflow)를 막기 위해 지수 함수를 적용하기 전에 최대 로짓을 빼는 방법입니다.
z = [100, 101, 102]
exp(102) = 오버플로
z_shifted = z - max(z) = [-2, -1, 0]
exp(0) = 1 (안전함)
같은 결과를 얻으면서 오버플로를 피합니다.
로그 소프트맥스(log-softmax)는 수치 안정성을 위해 소프트맥스와 로그를 결합합니다. PyTorch는 교차 엔트로피 손실 내부에서 이 방식을 사용합니다.
표본추출
표본추출(sampling)은 분포에서 무작위 값을 뽑는 일입니다. ML에서는 아래처럼 쓰입니다.
- 드롭아웃(dropout)은 어떤 뉴런(neuron)을 0으로 만들지 무작위로 표본추출합니다.
- 데이터 증강(data augmentation)은 무작위 변환을 표본추출합니다.
- 언어 모델은 예측된 분포에서 다음 토큰(token)을 표본추출합니다.
- 디퓨전 모델은 잡음(noise)을 표본추출한 뒤 점진적으로 잡음을 제거(denoise)합니다.
임의의 분포에서 표본추출하려면 역변환 표본추출(inverse transform sampling), 기각 표본추출(rejection sampling), VAE에서 쓰는 재매개변수화 기법(reparameterization trick) 같은 기법이 필요합니다.
직접 만들기
Step 1: 확률 기본기
import math
import random
def factorial(n):
result = 1
for i in range(2, n + 1):
result *= i
return result
def combinations(n, k):
return factorial(n) // (factorial(k) * factorial(n - k))
def conditional_probability(p_a_and_b, p_b):
return p_a_and_b / p_b
p_king_given_face = conditional_probability(4/52, 12/52)
print(f"P(King | Face card) = {p_king_given_face:.4f}")
Step 2: 처음부터 구현하는 PMF와 PDF
def bernoulli_pmf(k, p):
return p if k == 1 else (1 - p)
def categorical_pmf(k, probs):
return probs[k]
def poisson_pmf(k, lam):
return (lam ** k) * math.exp(-lam) / factorial(k)
def uniform_pdf(x, a, b):
if a <= x <= b:
return 1.0 / (b - a)
return 0.0
def normal_pdf(x, mu, sigma):
coeff = 1.0 / (sigma * math.sqrt(2 * math.pi))
exponent = -0.5 * ((x - mu) / sigma) ** 2
return coeff * math.exp(exponent)
Step 3: 기댓값과 분산
def expected_value(values, probabilities):
return sum(v * p for v, p in zip(values, probabilities))
def variance(values, probabilities):
mu = expected_value(values, probabilities)
return sum(p * (v - mu) ** 2 for v, p in zip(values, probabilities))
die_values = [1, 2, 3, 4, 5, 6]
die_probs = [1/6] * 6
mu = expected_value(die_values, die_probs)
var = variance(die_values, die_probs)
print(f"주사위: E[X] = {mu:.4f}, Var(X) = {var:.4f}, SD = {var**0.5:.4f}")
Step 4: 분포에서 표본추출하기
def sample_bernoulli(p, n=1):
return [1 if random.random() < p else 0 for _ in range(n)]
def sample_categorical(probs, n=1):
cumulative = []
total = 0
for p in probs:
total += p
cumulative.append(total)
samples = []
for _ in range(n):
r = random.random()
for i, c in enumerate(cumulative):
if r <= c:
samples.append(i)
break
return samples
def sample_normal_box_muller(mu, sigma, n=1):
samples = []
for _ in range(n):
u1 = random.random()
u2 = random.random()
z = math.sqrt(-2 * math.log(u1)) * math.cos(2 * math.pi * u2)
samples.append(mu + sigma * z)
return samples
Step 5: 소프트맥스와 로그 확률
def softmax(logits):
max_logit = max(logits)
shifted = [z - max_logit for z in logits]
exps = [math.exp(z) for z in shifted]
total = sum(exps)
return [e / total for e in exps]
def log_softmax(logits):
max_logit = max(logits)
shifted = [z - max_logit for z in logits]
log_sum_exp = max_logit + math.log(sum(math.exp(z) for z in shifted))
return [z - log_sum_exp for z in logits]
def cross_entropy_loss(logits, target_index):
log_probs = log_softmax(logits)
return -log_probs[target_index]
Step 6: 중심극한정리 시연
def demonstrate_clt(dist_fn, n_samples, n_averages):
averages = []
for _ in range(n_averages):
samples = [dist_fn() for _ in range(n_samples)]
averages.append(sum(samples) / len(samples))
return averages
Step 7: 시각화
import matplotlib.pyplot as plt
xs = [mu + sigma * (i - 500) / 100 for i in range(1001)]
ys = [normal_pdf(x, mu, sigma) for x, mu, sigma in ...]
plt.plot(xs, ys)
전체 구현과 시각화는 code/probability.py에 있습니다.
사용해보기
NumPy와 SciPy를 사용하면 위에서 만든 기능들은 한 줄짜리 호출이 됩니다.
import numpy as np
from scipy import stats
normal = stats.norm(loc=0, scale=1)
samples = normal.rvs(size=10000)
print(f"평균: {np.mean(samples):.4f}, 표준편차: {np.std(samples):.4f}")
print(f"P(X < 1.96) = {normal.cdf(1.96):.4f}")
logits = np.array([2.0, 1.0, 0.1])
from scipy.special import softmax, log_softmax
probs = softmax(logits)
log_probs = log_softmax(logits)
print(f"소프트맥스: {probs}")
print(f"로그 소프트맥스: {log_probs}")
이미 처음부터 만들어 봤기 때문에 라이브러리 호출이 내부에서 무엇을 하는지 알 수 있습니다.
산출물 만들기
이 lesson의 검수 대상은 아래 두 가지입니다.
code/probability.py: PMF, PDF, 표본추출, 소프트맥스, 교차 엔트로피, 중심극한정리 시연 구현
outputs/skill-probability-reasoning.md: ML 문제에 맞는 확률 분포를 고르는 데 사용하는 skill
연습문제
- (쉬움) 지수 분포(exponential distribution)에 대해 역변환 표본추출을 구현합니다. 10,000개의 값을 표본추출하고 히스토그램(histogram)을 참 PDF와 비교합니다.
- (중간) 가중된 주사위(loaded dice) 두 개의 결합분포 표를 만듭니다. 주변분포를 계산하고 두 주사위가 독립인지 확인합니다.
- (중간) 정답 클래스가 인덱스 3일 때, 로짓
[2.0, 0.5, -1.0, 3.0, 0.1]을 출력하는 5클래스 분류기의 교차 엔트로피 손실을 계산합니다. 그런 다음 PyTorch의 nn.CrossEntropyLoss로 검증합니다.
- (어려움) 로그 확률의 리스트를 받아 가장 가능성이 높은 시퀀스, 전체 로그 확률, 그에 대응하는 원시 확률을 반환하는 함수를 작성합니다. 각 단어의 확률이 0.01인 50단어 문장으로 테스트합니다.
핵심 용어
| 용어 | 흔한 설명 | 실제 의미 |
|---|
| 표본공간(Sample space) | 모든 가능성 | 실험(experiment)에서 가능한 모든 결과의 집합 S |
| 확률질량함수(PMF) | 확률 함수 | 이산 결과 각각의 정확한 확률을 주며 전체 합이 1인 함수 |
| 확률밀도함수(PDF) | 확률 곡선 | 연속 변수의 밀도 함수. 구간 위에서 적분해야 확률이 된다 |
| 조건부 확률(Conditional probability) | 어떤 조건에서의 확률 | P(A|B) = P(A and B) / P(B). 베이지안적 사고와 베이즈 정리의 기반 |
| 독립성(Independence) | 서로 영향을 주지 않음 | P(A and B) = P(A) * P(B). 한 사건을 알아도 다른 사건에 대한 정보가 없다 |
| 기댓값(Expected value) | 평균 | 모든 결과의 확률 가중 합. 손실 함수는 기댓값으로 볼 수 있다 |
| 분산(Variance) | 퍼진 정도 | 평균으로부터의 제곱 편차의 기댓값. 분산이 크면 추정값이 잡음에 흔들리고 불안정하다 |
| 정규분포(Normal distribution) | 종 모양 곡선 | f(x) = (1/sqrt(2*pi*sigma^2)) * exp(-(x-mu)^2/(2*sigma^2)). 중심극한정리 덕분에 자주 등장한다 |
| 중심극한정리(Central Limit Theorem) | 평균은 정규가 된다 | 많은 독립 표본의 평균은 원천 분포와 무관하게 정규분포로 수렴한다 |
| 결합분포(Joint distribution) | 두 변수를 함께 보기 | P(X, Y)는 X와 Y 결과의 각 조합에 대한 확률을 설명한다 |
| 주변분포(Marginal distribution) | 다른 변수를 합으로 제거 | P(X) = sum_y P(X, Y). 결합분포에서 한 변수의 분포를 복원한다 |
| 로그 확률(Log probability) | 확률의 로그 | log P(x). 곱을 합으로 바꿔 긴 시퀀스에서 수치적 언더플로를 막는다 |
| 소프트맥스(Softmax) | 점수를 확률로 바꾸기 | softmax(z_i) = exp(z_i) / sum(exp(z_j)). 실수값 로짓을 유효한 확률 분포로 매핑한다 |
| 교차 엔트로피(Cross-entropy) | 손실 함수 | -sum(p_true * log(p_predicted)). 두 분포가 얼마나 다른지 측정한다. 낮을수록 좋다 |
| 로짓(Logits) | 모델의 원시 출력 | 소프트맥스 적용 전의 정규화되지 않은 점수. 로지스틱 함수(logistic function)에서 이름이 왔다 |
| 표본추출(Sampling) | 무작위 값 뽑기 | 확률 분포를 따라 값을 생성하는 일. 모델이 출력을 만들어 내는 방식이다 |
더 읽을거리