특이값 분해(Singular Value Decomposition)란 무엇인가? PyTorch, TensorFlow, Numpy 사용해 특이값 분해하기

2024. 8. 16. 08:18·Machine Learning Math/Linear Algebra
반응형

특이값 분해란 무엇인가?

특이값 분해(Singular Value Decomposition, SVD)란 $m x n$ 차원의 행렬을 대각화해 세 개의 행렬로 분해하는 방법이다. 고유값 분해와 비슷하지만, 고유값 분해는 정사각 행렬에만 사용 가능한 반면, 특이값 분해는 직사각 행렬일 때도 사용 가능해 활용도가 높다.

 

특이값 분해를 수식으로 표현하면 다음과 같다. 

 

$$\mathbf{X} = \mathbf{U} \mathbf{\Sigma} \mathbf{V}^T$$

 

여기서 각 기호는 다음과 같다.

$\mathbf{X}$ : $m \times n$ 행렬.

$\mathbf{U}$ : $m \times m$ 정사각 행렬로, $\mathbf{X}$의 좌특이 벡터(Left Singular Vectors)로 구성돼 직교 행렬이 된다

$\mathbf{\Sigma}$: $m \times n$ 대각 행렬

$\mathbf{V}$: $n \times n$ 정사각 행렬로,  $\mathbf{X}$의 우특이 벡터(Left Singular Vectors)로 구성돼 직교 행렬이 된다.

 

특이값 분해 하는 방법

다음 행렬 $\mathbf{X}$에 대해 특이값 분해를 수행하면서 특이값 분해를 하는 방법을 알아본다.

 

$$\begin{bmatrix}
1 & 2 \\
-1 & 2 \\
0 & 1
\end{bmatrix}$$

 

$\mathbf{U}$ 구하기

$\mathbf{U}$ 를 구하기 위해서는 $\mathbf{X}\mathbf{X^T}$의 고유 벡터를 구해야 한다. 여기서 나오는 고유 벡터들이 $\mathbf{U}$가 된다.

A = np.array([[1, 2], [-1, 2], [0, 1]])
eigenValues, U = np.linalg.eig(np.dot(A,A.T))
print("U: ",U)

 

U:  [[-6.66666667e-01 -7.07106781e-01 -2.35702260e-01]
 [-6.66666667e-01  7.07106781e-01 -2.35702260e-01]
 [-3.33333333e-01 -5.78537465e-17  9.42809042e-01]]

 

$\mathbf{\Sigma}$ 구하기

$\mathbf{\Sigma}$ 는 $\mathbf{X}\mathbf{X^T}$나 $\mathbf{X^T}\mathbf{X}$의 고유값이다. 둘은 같은 고유값을 가지기 때문에 같은 값이 된다. 앞서 구한 eigenValue에 루트를 씌워 구해보자.

A = np.array([[1, 2], [-1, 2], [0, 1]])
eigenValues, U = np.linalg.eig(np.dot(A,A.T))
print("U: ",U)
print("eigenValuesRoot", np.sqrt(eigenValues))

 

그러면 다음과 같은 값이 나온다. 여기서 세번째 값이 매우 작은 값으로 0인 것을 볼 수 있으니, 고유값에 루트를 취한 값은 3.0과 1.414인 것을 볼 수 있다.

eigenValuesRoot [3.00000000e+00 1.41421356e+00 3.22909121e-09]

 

 

$\mathbf{V}$ 구하기

$\mathbf{V}$ 를 구하기 위해서는 $\mathbf{X^T}\mathbf{X}$의 고유 벡터를 구해야 한다. 여기서 나오는 고유 벡터들이 $\mathbf{V}$가 된다.

eigenValues2, V = np.linalg.eig(np.dot(A.T,A))
print("V:", V)
print("eigenValuesRoot", np.sqrt(eigenValues2))

 

그러면 결과값은 다음과 같은 것을 볼 수 있다.

V: [[1. 0.]
 [0. 1.]]
eigenValuesRoot [1.41421356 3.        ]

 

여기서 보면 고유값에 루트를 취한 값(eigenValuesRoot)이 위에서 구한 3.0과 1.414과 같은 값인 것을 볼 수 있다.

 

구한 값으로 원래 행렬 계산해보기

이제 $\mathbf{U}$, $\mathbf{\Sigma}$, $\mathbf{V}$ 를 구했으니, 구한 값으로 원래 행렬을 계산해보자.

 

$$\mathbf{X} = \mathbf{U} \mathbf{\Sigma} \mathbf{V}^T$$

 

위의 수식을 계산해야 하므로, 다음과 같이 파이썬 코드를 만들 수 있다.

Sigma = np.concatenate((np.diag(np.sqrt(eigenValues)[:-1]), [[0, 0]]), axis=0)
np.matmul(np.matmul(U, Sigma), VT)

 

그러면 다음과 같은 결과가 나온다.

 

 

결과의 행렬이 우리가 특이값 분해를 실행한 행렬과 같은 것을 볼 수 있다.

 

$$\begin{bmatrix}
1 & 2 \\
-1 & 2 \\
0 & 1
\end{bmatrix}$$

 

 

하지만, 위와 같이 특이값 분해를 실행하면 너무 복잡하다. 머신러닝 라이브러리들에서는 이를 위한 간단한 방법을 제공한다. 이어서 그 방법들을 알아보자.

 

Numpy, TensorFlow, PyTorch 사용해 특이값 분해하기

Numpy 사용해 특이값 분해하기

Numpy 사용해 특이값 분해를 하려면 linalg패키지의 svd 함수를 사용하면 된다.

import numpy as np

A = np.array([[1, 2], [-1, 2], [2, 3]])
U, d, VT = np.linalg.svd(A)
print("U:",U)
print("V:",VT.T)

그러면 다음과 같은 값이 나온다.

U: [[-0.50395811  0.0600165  -0.86164044]
 [-0.32223601 -0.93862263  0.12309149]
 [-0.80136769  0.33968453  0.49236596]]
V: [[-0.40266324  0.91534819]
 [-0.91534819 -0.40266324]]

 

이 값들은 $\mathbf{A}\mathbf{A^T}$ 에 대한 고유 값 분해를 한 것과 같은 비슷한 결과를 내는 것을 볼 수 있다.

eigenValues, V3 = np.linalg.eig(np.dot(A,A.T))
print("Eigen V3: ",V3)

eigenValues, V2 = np.linalg.eig(np.dot(A.T,A))
print("Eigen V2:", V2)
Eigen V3:  [[ 0.50395811  0.86164044  0.0600165 ]
 [ 0.32223601 -0.12309149 -0.93862263]
 [ 0.80136769 -0.49236596  0.33968453]]
Eigen V2: [[-0.91534819 -0.40266324]
 [ 0.40266324 -0.91534819]]

 

 

TensorFlow 사용해 특이값 분해하기

같은 연산을 TensorFlow를 사용해 하려면 linalg.svd 함수를 사용하면 된다.

import tensorflow as tf

A = tf.constant([[1, 2], [-1, 2], [2, 3]], dtype=tf.float32)

S, U, VT = tf.linalg.svd(A, full_matrices=True)

print("V:", tf.transpose(VT))
print("U:", U)

 

그러면 같은 결과가 나오는 것을 볼 수 있다.

V: tf.Tensor(
[[ 0.40266326  0.91534823]
 [ 0.91534823 -0.40266326]], shape=(2, 2), dtype=float32)
U: tf.Tensor(
[[ 0.50395805  0.06001655 -0.86164033]
 [ 0.322236   -0.9386227   0.12309146]
 [ 0.8013677   0.33968455  0.49236602]], shape=(3, 3), dtype=float32)

 

 

PyTorch 사용해 특이값 분해하기

같은 연산을 PyTorch를 사용해 하려면 svd 함수를 사용하면 된다. 

import torch

A = torch.tensor([[1, 2], [-1, 2], [2, 3]], dtype=torch.float32)

U, S, VT = torch.svd(A)

print("V:", VT.T)
print("U:", U)

 

그러면 같은 결과가 나오는 것을 볼 수 있다.

V: tensor([[-0.4027, -0.9153],
        [ 0.9153, -0.4027]])
U: tensor([[-0.5040,  0.0600],
        [-0.3222, -0.9386],
        [-0.8014,  0.3397]])
반응형
저작자표시 비영리 변경금지 (새창열림)

'Machine Learning Math > Linear Algebra' 카테고리의 다른 글

무어 펜로즈 유사 역행렬(Moore-Penrose Pseudoinverse) 한 번에 정리하기: Numpy, TensorFlow, PyTorch 사용해 구하는 방법 정리  (0) 2024.08.18
고윳값 분해(Eigen Decomposition) 란 무엇인가? Numpy, TensorFlow, PyTorch 사용해 고유값 분해 해보기  (0) 2024.08.06
고유 벡터(Eigenvector)와 고유 값(Eigenvalue)이란 무엇인가? Numpy, TensorFlow, PyTorch로 고유 벡터 구해보기  (0) 2024.08.02
아핀 변환(Affine Transformation)이란 무엇인가?  (0) 2024.08.01
직교 행렬(Orthogonal Matrix)이란 무엇인가?  (0) 2024.07.31


'Machine Learning Math/Linear Algebra' 카테고리의 다른 글
  • 무어 펜로즈 유사 역행렬(Moore-Penrose Pseudoinverse) 한 번에 정리하기: Numpy, TensorFlow, PyTorch 사용해 구하는 방법 정리
  • 고윳값 분해(Eigen Decomposition) 란 무엇인가? Numpy, TensorFlow, PyTorch 사용해 고유값 분해 해보기
  • 고유 벡터(Eigenvector)와 고유 값(Eigenvalue)이란 무엇인가? Numpy, TensorFlow, PyTorch로 고유 벡터 구해보기
  • 아핀 변환(Affine Transformation)이란 무엇인가?
심플코드
심플코드
프로그래밍을 어렵지 않게 풀어서 설명하는 기술 블로그
    반응형
  • 심플코드
    심플코드
    심플코드
  • 전체
    오늘
    어제
    • 분류 전체보기 (96)
      • 안드로이드를 위한 Coroutines (2)
      • Unit Testing (19)
      • GitHub Actions (0)
      • 공식 문서 번역 (35)
        • Coroutines 공식 문서 (35)
      • 알고리즘 (7)
        • Kotlin 자료구조 (0)
        • 알고리즘 (7)
        • Kotlin으로 구현하는 자료구조 (0)
      • 코딩 테스트 (0)
      • Deep Learning (0)
      • Machine Learning Math (17)
        • Linear Algebra (17)
      • ML (0)
      • Docker (15)
      • Kubernetes (1)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

    • 코틀린 코루틴의 정석 책 출간 소식
  • 인기 글

  • 태그

    Docker
    코루틴 채널
    Coroutines Context
    도커
    Kotlin
    코루틴
    컨테이너
    numpy
    mockito
    TensorFlow
    unit test
    coroutine
    unit testing
    Coroutines
    pytorch
    Coroutines Flow
    Coroutines Channel
    코루틴 Flow
    Machine Learning
    junit
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
심플코드
특이값 분해(Singular Value Decomposition)란 무엇인가? PyTorch, TensorFlow, Numpy 사용해 특이값 분해하기
상단으로

티스토리툴바