Code › codeit-ai-sprint
머신러닝의 첫걸음과 선형대수가 필요한 이유
코드잇 머신러닝 기본기와 선형대수 기초
파이썬 기본 문법을 정리한 데 이어, 드디어 머신러닝 기본기 라는 강의를 골라서 듣기 시작했다. 이번 챕터에서는 인공지능과 머신러닝, 딥러닝의 관계부터 시작해 지도학습의 핵심 알고리즘 중 하나인 k-NN(k-Nearest Neighbors), 그리고 머신러닝의 뼈대가 되는 선형대수학의 행렬과 벡터 개념을 다뤘다. 단순히 수식을 외우는 게 아니라, 개발자 관점에서 이 개념들이 왜 효율적인지 다시금 생각해보는 계기가 되었다.
가장 먼저 인공지능(AI), 머신러닝(ML), 딥러닝(DL)의 관계를 명확히 짚고 넘어갔다. 흔히 혼용되어 쓰이지만 포괄 관계다. 가장 거대한 범주인 인공지능 안에 머신러닝이 있고, 그 머신러닝의 한 종류로 신경망의 층(layer)을 깊게 쌓아 올린 ‘딥러닝’이 존재한다. 특히 현대의 딥러닝은 빅데이터를 기반으로 이 깊은 층을 학습시키면서 인간이 직접 규칙을 찾기 어려운 복잡한 패턴을 스스로 찾아내며 폭발적으로 성장하게 되었다. Tom Mitchell 교수의 정의처럼, “더 많은 경험(Data)을 쌓을수록 성능(Task)이 향상되는 시스템”이 곧 머신러닝의 본질인 셈이다.
┌───────────────────────────────┐ │ Artificial │ │ Intelligence │ │ ┌─────────────────────────┐ │ │ │ Machine Learning │ │ │ │ ┌───────────────────┐ │ │ │ │ │ Deep Learning │ │ │ │ │ └───────────────────┘ │ │ │ └─────────────────────────┘ │ └───────────────────────────────┘
강의는 머신러닝의 여러 유형 중 가장 대중적이고 많이 활용되는 ‘지도학습(Supervised Learning)‘을 위주로 진행되었다. 지도학습의 핵심은 데이터와 함께 반드시 ‘정답(Label)‘을 프로그램에 함께 제공해야 한다는 점이다. 지도학습은 크게 두 가지 문제로 나뉜다. 이메일이 스팸인지 아닌지처럼 이산적인 결과를 맞추는 ‘분류(Classification)‘와, 과거 데이터를 기반으로 아파트 가격 같은 연속적인 수치를 예측하는 ‘회귀(Regression)‘가 그것이다. 반면 ‘비지도학습(Unsupervised Learning)‘은 정답 없이 프로그램이 데이터의 자체적인 특성과 구조를 알아서 파악하도록 유도한다.
이 분류 문제를 해결하는 가장 직관적인 알고리즘으로 k-NN(k-Nearest Neighbors, k-최근접 이웃)을 배웠다. 예를 들어 타이타닉 생존자 예측 데이터에서 특정 탑승자의 티켓 가격과 연령 정보가 주어졌을 때, 이 데이터와 가장 ‘거리가 가까운’ 이웃 데이터 k개를 확인하는 방식이다. k가 5라면 주변의 가장 가까운 탑승자 5명을 보고, 그중 생존자가 사망자보다 많으면 이 탑승자도 생존했을 것이라 예측한다. 즉, 주변 데이터의 ‘다수결’을 따르는 매우 직관적이면서도 강력한 알고리즘이다.
이러한 데이터의 ‘거리’를 계산하고 수많은 변수를 다루기 위해서 선형대수학, 미적분학, 확률과 통계 같은 수학적 베이스가 요구된다. 특히 수천, 수만 개의 데이터를 다룰 때 선형대수의 ‘행렬(Matrix)‘이 중요한 요소인 것 같다. 수많은 정보를 하나의 행렬로 묶어 표현하면 코드가 간결해질 뿐만 아니라, 컴퓨터(특히 GPU)가 한 번에 병렬로 연산하기 매우 효율적인 구조가 되기 때문이다. 전공때 배운 행렬은 오래되어 기억이 나지 않는데, 이번 강의로 다시 배우게 되어서 좋다.
이 강의에서 벡터를 공부하다 보면 한 가지 의문이 생긴다. 벡터는 행벡터(Row Vector)와 열벡터(Column Vector)로 나뉘는데, 왜 머신러닝 생태계와 수학 논문에서는 관례적으로 ‘열벡터’를 기본 표준으로 삼을까? 개인적으로 궁금해서 찾아보니, 여기에는 선형사상(Linear Transformation)의 정형화된 행렬 곱셈 연산 방식 때문이라고 한다 (무슨말?)
수학에서 함수 f(x)를 표현할 때 입력값 x는 보통 오른쪽에 위치한다. 이를 선형대수의 행렬 곱셈 Ax 형태로 매핑하려면, 행렬 A의 오른쪽에 곱해지는 벡터 x는 반드시 세로 형태인 ‘열벡터’여야만 차원(Dimension) 계산이 맞아떨어진다. 데이터 한 건을 하나의 열벡터로 정의해두어야 여러 데이터를 묶어 행렬 A를 만들 때도 확장성이 깔끔해진다. 가로로 눕혀진 행벡터 중심(xA)으로 수식을 전개하면 행렬 연산의 방향이 우측에서 좌측으로 흘러 직관적이지 않고, 신경망 구조를 설계할 때 가중치 행렬과의 곱을 표현하기가 복잡해진다.
마지막으로 파이썬에서 이 행렬과 벡터를 다루기 위해 필수적인 라이브러리인 numpy 실습을 가볍게 진행했다. 파이썬 기본 리스트로 행렬 연산을 구현하려면 중첩 반복문을 복잡하게 돌려야 하지만, 넘파이를 활용하면 대수학 문법 그대로 깔끔하게 행렬을 생성하고 덧셈이나 스칼라곱을 처리할 수 있다.
import numpy as np
# 2x3 행렬 생성
A = np.array([
[1, 2, 3],
[4, 5, 6]
])
# 스칼라곱 연산 (모든 요소에 2를 곱함)
result = A * 2
print(result)
# [[ 2 4 6]
# [ 8 10 12]]