PCA의 경우 정방행렬만을 고유벡터로 분해할 수 있지만, SVD는 정방행렬 뿐만 아니라 행과 열의 크기가 다른 행렬에도 적용할 수 있다. 일반적으로 SVD는 특이값 분해로 불리며, m x n 크기의 행렬 A를 특이 벡터(singular vector)로 이루어진 행렬 U와 V, 대각 행렬 ∑로 분해된다. 수식으로 표현하면 아래와 같이 표현된다.
모든 특이 벡터는 서로 직교(orthogonal)하는 성질을 가지며, 대각 행렬 ∑의 대각 성분이 행렬 A의 특이값이다.
일반적으로 ∑는 m x n의 크기를 가지기 때문에 ∑의 비대각 부분과 대각 원소중 특이값이 0인 부분도 모두 제거해주며 제거한 부분에 대응되는 U와 V의 원소도 같이 제거하여 차원을 줄인 상태로 SVD를 적용한다. 이렇게 간단한 형태로 SVD를 적용하면 A의 차원이 m x n일때, U의 차원을 m x p, ∑의 차원을 p x p, V의 차원을 n x p로 분해하게 된다. 이렇게 분해하는 방법을 Truncated SVD라고 한다.
📌 파이썬 구현코드
import numpy as np
import math
import matplotlib.pyplot as plt
import matplotlib.image as image
from keras.datasets import cifar10
((x_train, y_train), (x_test, y_test)) = cifar10.load_data()
N, row, col, c = x_train.shape
print(N, row, col, c)
데이터 셋은 간단하게 keras의 cifar10을 활용하였고
x_train의 이미지 만을 활용해서 SVD를 확인해보겠다.
아래 print의 결과는 50000(N) 32(row) 32(col) 3(c)이 되겠다.
📌 파이썬 구현코드
X = x_train.reshape(N, row*col*c)
X = X.T
C = np.cov(X)
U,s,V = np.linalg.svd(C) # U(3072, 3072), s(3072,) V(3072, 3072)
S = np.diag(s)
V = V.T
x_train 데이터를 행렬로 변환하기 위해 reshape을 적용 (50000, 3072)
C는 covariance matrix를 구하기 위해 numpy의 cov 메소드를 사용 (3072, 3072)
np.linalg의 svd를 통해 U, s, V로 도출되게 된다.
📌 파이썬 구현코드
D_reduce = 500
X2Z = U[:,0:D_reduce] # D x D_reduce, projection (3072, 100)
Z2X = U[:,0:D_reduce].T # D_reduce x D, reconstruction (100, 3072)
Z = X.T.dot(X2Z) # (N x D) dot (D x D_reduce) (50000, 100)
X_reconst = Z.dot(Z2X) # (N x D_reduce) dot (D_reduce x D) (50000, 3072)
다음은 D_reduce를 100으로 하여 100개의 차원으로 reconstruct를 진행해보았다.
📌 파이썬 구현코드
n = np.random.randint(0,N,5)
plt.figure(figsize = (16,7))
for i in range(5):
img = X_reconst[n[i],:]
img = img.astype(int)
img[img < 0] = 0
img[img > 255] = 255
plt.subplot(2,5,i + 1)
plt.imshow(X[:,n[i]].reshape(row,col,c))
plt.tight_layout()
plt.subplot(2,5,i + 6)
plt.imshow(img.reshape(row,col,c))
plt.tight_layout()
plt.savefig('PCA.eps')
위의 사진은 원본이고 아래는 SVD를 활용하여 차원 축소한 이미지이다.
100개의 차원으로 했을때 이미지가 표현력이 떨어지지만
아래와 같은 코드를 통해 Singular Value를 시각화를 할 수 있다.
plt.plot(np.cumsum(s)/np.sum(s))
실습에서 사용한 데이터를 적용했다면 Singular Value는 3072개가 나왔을텐데 1번부터 3072번까지 Singular Value를 누적을 해서 더한 값이다.
위의 그래프를 보면 500개의 차원으로 reconstruct시에는 전체 Singular Value의 100프로로 표현이 가능하다. 아래는 D_reduce를 500으로 했을 때의 결과이다.
원본 이미지와의 차이는 크게 나지 않음을 보인다.
이미지 차원 축소는 중요한 정보와 패턴을 유지하면서 이미지의 차원(특징) 수를 줄이는 데 사용되는 기술이다. 이 프로세스는 컴퓨터 비전, 이미지 처리 및 기계 학습과 같은 다양한 영역에서 유용할 것으로 생각되고 실습에서는 SVD를 사용해서 이미지 압축을 해보았다. 이미지 차원 축소의 주요 결과 및 용도는 다음과 같이 생각해 볼 수 있겠다.
References