본문 바로가기
NLP/AI 이론

[AI Math] 벡터와 행렬의 개념

by ㅣlㅣl 2024. 1. 28.

네이버 부스트코스에서 제공하는 임성빈 님의 강의를 참고하여 작성된 포스팅입니다.


 

 

벡터의 개념

  • 벡터의 차원 : 벡터에 있는 요소의 개수
  • 벡터는 공간에서 한 점을 나타냄
  • 1차원 공간에서는 주로 스칼라로 부름
  • 원점으로부터의 상대적 위치 표현하는 화살표
  • 벡터의 스칼라곱 = 방향은 그대로, 길이만 변함
  • 같은 shape이면 덧셈, 뺄셈, 성분곱(element-wise) 계산 가능

 

벡터의 덧셈, 뺄셈

벡터의 덧셈, 뺄셈 = 다른 벡터로부터 상대적 위치 이동

 

norm

원점에서부터의 거리 → 거리는 차원에 상관없이 임의의 차원 d에서 성립함

  • L1 norm : 각 성분의 변화량 절대값을 모두 더함
$$
||x||_1 = \sum^d_{i=1} |x_i|
$$
  • L2 norm : 피타고리스 정리로 유클리드 거리 계산
$$
||x||_2 = \sqrt{\sum^d_{i=1} |x_i|^2}
$$
def l1_norm(x):
    x_norm = np.abs(x)
    x_norm = np.sum(x_norm)
    return x_norm

def l2_norm(x): # = np.linalg.norm
    x_norm = x*x
    x_norm = np.sum(x_norm)
    x_norm = np.sqrt(x_norm)
    return x_norm
  • 노름의 종류에 따라 기하학적 성질이 달라짐
    • L1 : robust 학습, Lasso 회귀
    • L2 : Laplace 근사, Ridge 회귀

 

  • 두 벡터 사이의 거리로 각도 계산
    • 두 벡터의 내적 (성분곱 다 더하기)* 을 두 벡터의 L2 곱으로 나누어 theta의 코사인 값을 계산한다.
    • 제2코사인법칙→ 세 변의 길이를 알 때 끼인 각 크기를 알 수 있음
      $$
      <x,y> = \sum^d_{i=1}x_iy_i
      $$
    • $$
      cos \theta = \frac{||x||^2_2 + ||y||^2_2 - ||x-y||^2_2}{2||x||_2||y||_2} = \frac{2<x,y>}{2||x||_2||y||_2}
      $$
    • $$
      a^2 = b^2 + c^2 - 2bccosA
      $$
    • 코사인의 역함수(아크코사인)을 계산하면 두 벡터 사이의 각도인 theta를 구할 수 있다.
    • def angle(x,y): # np.inner : 내적 계산 v = np.inner(x,y) / (l2_norm(x) * l2_norm(y)) theta = np.arccos(v) return theta
  • L2 norm으로만 구할 수 있음 → 제2코사인법칙 이용해서 계산

 

 

내적의 해석

내적은 정사영(=orthogonal projection) 된 벡터의 길이와 관련 있음

Proj(x) = 벡터 y로 정사영된 벡터 x의 그림자를 의미함

  • 코사인 제1법칙
  • $$
    a = bcosC + ccosB
    $$

코사인법칙에 의해 proj(x) 길이는 ||x||cos(theta)

💡 내적은 정사영 길이를 벡터 y의 길이 ||y|| 만큼 조정한 값

 


 

행렬의 개념

행렬은 벡터를 원소로 가지는 2차원 배열

  • 전치행렬 : 행과 열의 인덱스가 바뀐 행렬 (X^T)
  • 벡터 : 공간의 한 점 / 행렬 : 공간의 여러 점들
  • 행렬의 i번째 행벡터 x_ii번째 데이터를 의미
  • x_ij는 i번째 데이터의 j번째 변수 값을 의미

 

행렬의 덧셈, 뺄셈, 성분곱, 스칼라곱

  • 행렬끼리 같은 shape을 가지면 덧셈, 뺄셈, 성분곱, 스칼라곱 계산 가능
    → 벡터와 크게 다르지 않음! (각 인덱스 위치끼리 계산)

 

행렬곱셈 (matrix multipulication)

💡 행렬곱은 i번째 행벡터j번째 열벡터 사이의 내적을 성분으로 가지는 행렬을 계산

💡 행렬곱 XY를 계산할 때, X의 column 개수Y의 row 개수가 같아야 한다

# numpy에서 @ 연산을 사용해 행렬곱 가능
X = np.array([1,-2,3],[7,5,0],[-2,-1,2]) # 3,3
Y = np.array([0,1],[1,-1],[-2,1]) # 3,2

X@Y

 

numpy.inner

i번째 행벡터와 j번째 행벡터 사이의 내적을 성분으로 가지는 행렬 계산!

따라서 두 행렬의 원소 개수가 같아야 한다

수학에서는 보통 tr(XY^T) = i번째 행벡터와 j번째 열벡터 를 내적으로 계산하는 것과 차이가 있다!

 

np.inner와 np.dot의 차이는 뭘까?

  • numpy.dot(a, b)
    • a, b 둘 다 1-D array : vector의 inner product
    • a, b 둘 다 2-D array : matrix multiplication -> matmul이나 a@b가 더 권장됨
    • a나 b가 0-D (scalar) : multiply -> multiply나 a*b가 권장됨
    • a : N-D array / b : 1-D array : a, b의 last axis의 sum product
    • a : N-D array / b : M-D array : a의 last axis & b의 second-last sum product
dot(a, b)[i,j,k,m] = sum(a[i,j,:] * b[k,:,m])
a = [[1, 0], [0, 1]]
b = [[4, 1], [2, 2]]
np.dot(a, b)
array([[4, 1],
       [2, 2]])

 

  • numpy.inner(a,b)
    • a, b 둘 다 1-D array : vector의 inner product
    • a : N-D array / b : M-D array : a의 last axis & b의 last axis의 sum product
a = np.arange(24).reshape((2,3,4))
b = np.arange(4)
c = np.inner(a, b)
c.shape
(2, 3)
c
array([[ 14,  38,  62],
       [ 86, 110, 134]])

 

즉 1-D array일 때는 기본적으로 동일하게 inner product를 수행하지만, 

2차원 이상의 array 연산을 수행할 때 차이가 드러난다.

>>> a=np.array([[1,2],[3,4]])
>>> b=np.array([[11,12],[13,14]])
>>> np.dot(a,b)
array([[37, 40],
       [85, 92]])
>>> np.inner(a,b)
array([[35, 41],
       [81, 95]])

 

 

이런 식으로 결과 값에 차이가 나는 것을 볼 수 있다.

 

 

행렬을 이해하는 법

  • 데이터를 저장
  • 서로 다른 데이터를 연결하는 하나의 연산자
  • 행렬곱을 통해 벡터를 다른 차원의 공간으로 보낼 수 있음
    • 모든 선형변환은 행렬곱으로 계산할 수 있다
  • 행렬곱을 통해 패턴 추출, 데이터 압축 가능

 

역행렬

행렬 A의 연산을 거꾸로 되돌리는 행렬 = $A^{-1}$

행과 열 숫자가 같고, 행렬식이 0이 아닌 경우에만 계산 가능

  • 역행렬은 곱 순서 상관 없음

$$
AA^{-1} = A^{-1}A = I
$$

 

항등행렬 (=단위 행렬)

임의의 행렬에 곱했을 때 자기자신이 나오는 행렬

X = np.array([1,-2,3],[7,5,0],[-2,-1,2]) # 3,3

np.linalg.inv(X) # X의 역행렬
X @ np.linalg.inv(X) # 단위행렬

 

유사역행렬, 무어-펜로즈 역행렬

역행렬을 계산할 수 없을 때

  • 행과 열의 숫자가 달라도 계산 가능
  • 역행렬 표시하는 -1 기호 대신 + 기호 사용 ($A^+$)
  • 행 개수 ≥ 열 개수 : 전체 행렬 X A행렬
  • 행 개수 ≤ 열 개수 : A행렬 X 전체 행렬

→ 순서 바뀌면 다른 결과 나오므로 조심할 것!

Y = np.array([0,1],[1,-1],[-2,1]) # 3,2

np.linalg.pinv(Y) # Y의 유사역행렬
np.linalg.pinv(Y) @ Y # 행 개수 >= 열 개수 -> A^+A = I 

 

응용 1. 연립방정식 풀기

np.linalg.pinv (유사역행렬) 이용해서 연립방정식 해 구하기

💡 n ≤ m일때만 (행이 열 개수보다 작을 때만) 정확한 해를 구할 수 있음

 

응용2. 선형회귀분석

np.linalg.pinv (유사역행렬) 이용해서 데이터를 선형모델로 해석하는 선형회귀식 그리기

  • Xb = 선형회귀식
  • $X\beta = \hat{y} = 선형회귀식$, $y : 실제 값$

💡 오차 (y와 y hat의 L2 norm)을 최소화하는 방식으로 회귀가 진행됨

from sklearn.linear_model import LinearRegression

model = LinearRegression()
model.fit(X, y)

y_test = model.predict(x_test)

# y절편 (intercept) 항을 직접 추가해야만 LinearRegression과 같은 효과를 낼 수 있음!
X_ = np.array([np.append(x, [1]) for x in X])
beta = np.linalg.pinv(X_) @ y
y_test = np.append(x, [1]) @ beta

 

'NLP > AI 이론' 카테고리의 다른 글

[AI Math] 딥러닝 수식 뽀개기  (0) 2024.04.16
[AI Math] 경사하강법  (1) 2024.01.28
[Python] NumPy & Pandas  (1) 2024.01.28
[Python] Python Data Handling  (1) 2024.01.28
[Python] Python File/Exception/Log Handler  (2) 2024.01.28