본문 바로가기
AI/참고자료

[AI] 미적분과 머신러닝

by SeungyubLee 2025. 10. 23.

※ 머신러닝의 기본 아이디어

머신러닝은 데이터를 보고 스스로 규칙을 찾는 과정이다.

예를 들어,

"광고비를 얼마나 쓰면 매출이 얼마나 오를까?", "사진 속에 고양이가 있을까?"
이런 걸 컴퓨터가 스스로 배우는 과정이 바로 머신러닝이다.

 

여기서 "배운다"는 건 결국 숫자들을 조정해서 "오차를 줄이는" 과정인 것이다.

※ 미적분은 "오차를 줄이는 길"을 알려주는 지도

모델이 처음엔 엉뚱한 예측을 한다. 그래서 오차(=실제값과 예측값의 차이)를 계산하고,
그 오차를 줄이기 위해 모델의 숫자(가중치)를 조금씩 바꾼다.

이때 "얼마나 바꿔야 오차가 줄어들까?"를 알려주는 게 바로 미분이다.

 

쉽게 말하면, 미분은 "지금 이 방향으로 조금 움직였을 때 오차가 얼마나 변하는지"를 알려주는 나침반이라고 할 수 있다.

 

오차가 줄어드는 방향 → 그 방향으로 숫자를 조정
오차가 커지는 방향 → 그 반대로 이동

 

이 과정을 경사 하강법(Gradient Descent)이라고 부른다.

※ 경사 하강법 비유 (산 내려가기)

마치 안개 낀 산에서 가장 낮은 지점(최소 오차)을 찾는 것과 같다.

현재 위치에서 조금 움직여본 뒤, "여기서 아래로 내려가려면 어느 방향으로 가야 하지?"를 미분으로 계산한다.
그리고 그 방향으로 조금씩 이동하면서 계속 반복한다.

 

이걸 수천, 수만 번 반복하면서
모델은 "가장 낮은 오차" 즉, 가장 정확한 예측을 하는 상태를 찾아간다.

※ 적분은 전체 흐름을 이해할 때 사용

미분이 "순간적인 변화"를 본다면, 적분은 그 변화들을 모두 모아서 전체적인 양을 계산한다.

예를 들어,

어떤 함수의 전체 면적(예 : 확률 분포에서 0~1 구간의 확률 합)을 구할 때, 연속된 데이터의 누적 값을 계산할 때,
미분 방정식 기반의 모델(예 : 물체의 이동, 물리적 변화량 예측)을 다룰 때 적분이 쓰인다.

(특히 확률 분포, 손실 함수, 신경망의 활성화 계산 같은 곳)

※ 요약

미적분은 머신러닝이 '배움'을 가능하게 만드는 핵심 언어이다.
미분"어디로 가야 할지"를, 적분"전체 그림"을 알려준다.


1) 미적분 기본 개념


2) 미적분 기본 수식


3) 기본 수식 활용 파이썬 코드

▶ 수치 미분/적분(중심차분·리만합)과 연쇄법칙 검증 예시

import numpy as np

# 1) 수치 미분: 중심 차분
def numerical_derivative(f, x, h=1e-6):
    return (f(x + h) - f(x - h)) / (2*h)

# 2) 수치 적분: 등분할 리만합
def numerical_integral(f, a, b, n=100_000):
    xs = np.linspace(a, b, n+1)
    dx = (b - a) / n
    # 중점 리만합
    mids = (xs[:-1] + xs[1:]) / 2
    return np.sum(f(mids) * dx)

# 예시 함수
f = lambda x: x**3 - 3*x + 2

x0 = 1.5
print("f'(x0) ~", numerical_derivative(f, x0))
print("∫_0^2 f(x) dx ~", numerical_integral(f, 0, 2))

# 3) 연쇄법칙 검증: h(x) = σ(g(x)), g(x)=x^2, σ(z)=1/(1+e^{-z})
sigmoid = lambda z: 1.0 / (1.0 + np.exp(-z))
g = lambda x: x**2
h = lambda x: sigmoid(g(x))

# 연쇄법칙에 의한 해석 도함수: h'(x) = σ(g(x))*(1-σ(g(x))) * 2x
def h_prime_chain(x):
    s = sigmoid(g(x))
    return s * (1 - s) * (2*x)

x1 = 0.7
num = numerical_derivative(h, x1)
ana = h_prime_chain(x1)
print("h'(x1) 수치≈", num, " / 해석=", ana, " / 오차=", abs(num-ana))

4) 머신러닝에 필요한 수식


5) 머신러닝에 필요한 수식 활용 파이썬 코드

▶ 5.1 선형회귀 : MSE + L2 정규화의 그라디언트 & 경사하강

import numpy as np

rng = np.random.default_rng(0)

# 가짜 데이터 생성: y = 3x1 - 2x2 + 노이즈
n, d = 200, 2
X = rng.normal(size=(n, d))
true_w = np.array([3.0, -2.0])
y = X @ true_w + rng.normal(scale=0.5, size=n)

def mse_l2_loss_and_grad(w, X, y, lam=0.0):
    n = X.shape[0]
    r = X @ w - y
    loss = 0.5 * np.mean(r**2) + 0.5 * lam * np.sum(w**2)
    grad = (X.T @ r) / n + lam * w
    return loss, grad

w = np.zeros(d)
lr, lam = 0.1, 0.1

for t in range(200):
    loss, grad = mse_l2_loss_and_grad(w, X, y, lam)
    w -= lr * grad

print("학습된 w:", w)
print("진짜 w :", true_w)

 

 5.2 로지스틱 회귀 : 이진 크로스엔트로피의 그라디언트 & 경사하강

import numpy as np

rng = np.random.default_rng(1)

# 데이터: 2차원 선형 분리 가능
n, d = 400, 2
X = rng.normal(size=(n, d))
w_true = np.array([2.0, -1.0])
logits = X @ w_true
prob = 1 / (1 + np.exp(-logits))
y = (prob > 0.5).astype(float)

def sigmoid(z):
    return 1 / (1 + np.exp(-z))

def binlogreg_loss_and_grad(w, X, y):
    n = X.shape[0]
    z = X @ w
    yhat = sigmoid(z)
    eps = 1e-12
    loss = -np.mean(y * np.log(yhat + eps) + (1 - y) * np.log(1 - yhat + eps))
    grad = (X.T @ (yhat - y)) / n
    return loss, grad

w = np.zeros(d)
lr = 0.5

for t in range(300):
    loss, grad = binlogreg_loss_and_grad(w, X, y)
    w -= lr * grad

print("학습된 w:", w)
print("진짜 w :", w_true)

 

 5.3 소프트맥스 회귀 : 다중분류 그라디언트

import numpy as np

rng = np.random.default_rng(42)

# 3클래스, 2차원 특징
n, d, K = 600, 2, 3
X = rng.normal(size=(n, d))

# 가중치로 라벨 생성
W_true = np.array([[2.0, -1.0, 0.5],
                   [0.5,  1.5, -2.0]])
Z = X @ W_true
Z -= Z.max(axis=1, keepdims=True)  # 안정화
expZ = np.exp(Z)
P = expZ / expZ.sum(axis=1, keepdims=True)
y_idx = np.argmax(P + rng.normal(scale=0.1, size=P.shape), axis=1)

# 원-핫
Y = np.eye(K)[y_idx]

def softmax_logits(Z):
    Z = Z - Z.max(axis=1, keepdims=True)
    expZ = np.exp(Z)
    return expZ / expZ.sum(axis=1, keepdims=True)

def softmax_ce_loss_and_grad(W, X, Y):
    n = X.shape[0]
    Z = X @ W
    Yhat = softmax_logits(Z)
    eps = 1e-12
    loss = -np.sum(Y * np.log(Yhat + eps)) / n
    grad = (X.T @ (Yhat - Y)) / n
    return loss, grad

W = np.zeros((d, K))
lr = 0.5

for t in range(300):
    loss, grad = softmax_ce_loss_and_grad(W, X, Y)
    W -= lr * grad

print("학습된 W:\n", W)
print("진짜 W:\n", W_true)

 

 5.4 헤시안 예시(선형회귀 + L2)

import numpy as np

def hessian_linear_ridge(X, lam=0.0):
    n = X.shape[0]
    d = X.shape[1]
    return (X.T @ X) / n + lam * np.eye(d)

# 샘플
Xsmall = np.array([[1.0, 2.0],
                   [0.0, 1.0],
                   [3.0, 4.0]])
H = hessian_linear_ridge(Xsmall, lam=0.1)
print("Hessian:\n", H)