목록으로

Chapter 8: AI/ML 응용

진행률: 8 / 8
예상 시간: 25분난이도: 중급

AI/ML 응용

학습 목표

  • 신경망에서의 행렬 연산 이해
  • 역전파 알고리즘의 수학적 기초
  • 최적화와 텐서 연산

신경망과 행렬 연산

순전파 (Forward Pass)

z = Wx + b
a = σ(z)

W: 가중치 행렬, x: 입력, b: 편향, σ: 활성화 함수

배치 처리

X: (배치크기 × 특징수)
병렬 처리로 효율성 극대화

GPU 최적화

행렬 곱셈의 병렬화
CUDA/cuBLAS 활용

역전파와 경사하강법

체인 룰

∂L/∂W = ∂L/∂z · ∂z/∂W = δ · x^T

SGD

W = W - η∇W

Adam

적응적 학습률

RMSprop

기울기 제곱 평균

주요 ML 알고리즘의 선형대수

PCA (주성분 분석)

  • • 공분산 행렬 계산
  • • 고유값 분해
  • • 차원 축소

SVM (서포트 벡터 머신)

  • • 커널 트릭 (내적 계산)
  • • 이차 계획법
  • • 라그랑주 승수

선형 회귀

  • • 정규방정식: (X^TX)^(-1)X^Ty
  • • QR 분해 활용
  • • Ridge/Lasso 정규화

Word2Vec

  • • 단어 임베딩 행렬
  • • 내적을 통한 유사도
  • • SVD 기반 차원 축소

텐서와 딥러닝

CNN

4D 텐서: (N, C, H, W)
컨볼루션 = 행렬 곱셈

RNN/LSTM

3D 텐서: (배치, 시퀀스, 특징)
게이트 = 행렬 연산

Transformer

어텐션 = Q·K^T / √d
다중 헤드 어텐션

딥러닝 구현 예제

import numpy as np

class NeuralNetwork:
    """간단한 신경망 구현"""
    
    def __init__(self, layers):
        """
        layers: [입력층, 은닉층1, ..., 출력층]
        """
        self.layers = layers
        self.weights = []
        self.biases = []
        
        # 가중치 초기화 (Xavier)
        for i in range(len(layers) - 1):
            w = np.random.randn(layers[i], layers[i+1]) * np.sqrt(2/layers[i])
            b = np.zeros((1, layers[i+1]))
            self.weights.append(w)
            self.biases.append(b)
    
    def relu(self, x):
        """ReLU 활성화 함수"""
        return np.maximum(0, x)
    
    def relu_derivative(self, x):
        """ReLU 도함수"""
        return (x > 0).astype(float)
    
    def softmax(self, x):
        """Softmax 활성화 함수"""
        exp_x = np.exp(x - np.max(x, axis=1, keepdims=True))
        return exp_x / np.sum(exp_x, axis=1, keepdims=True)
    
    def forward(self, X):
        """순전파"""
        self.activations = [X]
        self.z_values = []
        
        for i in range(len(self.weights)):
            z = self.activations[-1] @ self.weights[i] + self.biases[i]
            self.z_values.append(z)
            
            # 마지막 층은 softmax, 나머지는 ReLU
            if i == len(self.weights) - 1:
                a = self.softmax(z)
            else:
                a = self.relu(z)
            
            self.activations.append(a)
        
        return self.activations[-1]
    
    def backward(self, X, y, learning_rate=0.01):
        """역전파 및 가중치 업데이트"""
        m = X.shape[0]
        
        # 출력층 그래디언트
        delta = self.activations[-1] - y
        
        # 역전파
        for i in range(len(self.weights) - 1, -1, -1):
            # 가중치 그래디언트
            dW = (self.activations[i].T @ delta) / m
            db = np.sum(delta, axis=0, keepdims=True) / m
            
            # 가중치 업데이트
            self.weights[i] -= learning_rate * dW
            self.biases[i] -= learning_rate * db
            
            # 다음 층을 위한 델타 계산
            if i > 0:
                delta = (delta @ self.weights[i].T) * self.relu_derivative(self.z_values[i-1])
    
    def train(self, X, y, epochs=1000, learning_rate=0.01, batch_size=32):
        """미니배치 SGD 훈련"""
        n_samples = X.shape[0]
        
        for epoch in range(epochs):
            # 데이터 셔플
            indices = np.random.permutation(n_samples)
            X_shuffled = X[indices]
            y_shuffled = y[indices]
            
            # 미니배치 훈련
            for i in range(0, n_samples, batch_size):
                X_batch = X_shuffled[i:i+batch_size]
                y_batch = y_shuffled[i:i+batch_size]
                
                # 순전파
                output = self.forward(X_batch)
                
                # 역전파
                self.backward(X_batch, y_batch, learning_rate)
            
            # 손실 계산 (크로스 엔트로피)
            if epoch % 100 == 0:
                output = self.forward(X)
                loss = -np.mean(np.sum(y * np.log(output + 1e-8), axis=1))
                print(f"Epoch {epoch}, Loss: {loss:.4f}")

# PCA 구현
def pca(X, n_components):
    """주성분 분석"""
    # 1. 데이터 중심화
    X_centered = X - np.mean(X, axis=0)
    
    # 2. 공분산 행렬
    cov_matrix = (X_centered.T @ X_centered) / (X.shape[0] - 1)
    
    # 3. 고유값 분해
    eigenvalues, eigenvectors = np.linalg.eig(cov_matrix)
    
    # 4. 고유값 기준 정렬
    idx = eigenvalues.argsort()[::-1]
    eigenvalues = eigenvalues[idx]
    eigenvectors = eigenvectors[:, idx]
    
    # 5. 상위 n개 주성분 선택
    components = eigenvectors[:, :n_components]
    
    # 6. 변환
    X_transformed = X_centered @ components
    
    # 설명된 분산 비율
    explained_variance_ratio = eigenvalues[:n_components] / np.sum(eigenvalues)
    
    return X_transformed, components, explained_variance_ratio

# 사용 예제
if __name__ == "__main__":
    # 신경망 테스트
    nn = NeuralNetwork([784, 128, 64, 10])  # MNIST용
    
    # 더미 데이터
    X = np.random.randn(100, 784)
    y = np.eye(10)[np.random.randint(0, 10, 100)]  # one-hot
    
    nn.train(X, y, epochs=100, learning_rate=0.01)
    
    # PCA 테스트
    X_pca, components, var_ratio = pca(X, n_components=50)
    print(f"\nPCA: {var_ratio.sum():.2%} 분산 설명")