PCA를 공부해보자. 사실 이 포스팅은 내가 한 2주 전에 써보려고 했었는데 뭔가 잘 안써져서 헤매고 있다가 지금 다시 정리되서 다시 쓰려고 한다. 우선 가장 헷깔렸던 부분이 eigenvalue와 eigenvector의 기하학적인 해석이랄까.. eigenvalue와 eigenvector를 구할 줄은 아는데 뭔가 기하학적으로 그것이 무엇을 의미하는지 왜 의미가 있는지가 잘 이해가 안 됐다.


이번 포스팅에서는 eigenvalue와 eigenvector의 기하학적인 의미를 설명하고 그것이 PCA와 어떤 관계가 있는 것인지를 설명하려고 한다.


우선 eigenvalue와 eigenvector에 대해서 기하학적으로 잘 이해해보자. 우리가 어떤 vector 하나가 있을 때 이것을 행렬로 distort시킬 수 있다.

vector b는 vector v를 A라는 행렬을 통해 왜곡시킨 vector이다. A를 통해서 [1,3]이 [-1, 5]로 왜곡되었다. 그런데 vector 중에는 A를 거쳐도 왜곡되지 않는 그런 vector들이 있다. 이것이 eigenvector이다. eigenvector는 A를 거쳐도 크기만 바뀔 뿐 방향은 그대로이다. 이것이 기하학적으로 갖는 의미는 이와 같다. 아래와 같이 특정 공간 안에 무수히 많은 vector들이 있다고 해보자. 이 공간을 어떤 행렬을 통해 왜곡을 시켰을 때, 다른 vector들은 방향이 변하는데, 방향이 변하지 않는 vector 즉 eigenvector들이 있다. 아래의 그림에서 파란색 보라색이 eigenvector들이다.

출처 : https://deeplearning4j.org/eigenvector


eigenvector의 방향이 결국 어떤 행렬이 공간을 왜곡시키는 방향이다. 즉 공간이 왜곡되는 가장 Principal한 방향이라는 것이다. 제일 처음에 예로 든 Matrix A를 놓고 봐보자. 우선 A의 eigenvalue eigenvector를 구하면 다음과 같다.


2개가 나온다. 하나는 u=[1/sqrt(2), -1/sqrt(2)] 다른 하나는 v=[1/sqrt(2), 1/sqrt(2)]이다. u의 eigenvalue는 3이고 v의 eigenvalue는 -1이다. 즉 u가 가장 크게 A를 왜곡시키는 방향이라는 것이다. 그러면 v는 무엇인가? A는 v방향으로도 왜곡을 시키기는 한다. 그런데 u방향만큼은 아니라는 것이다. u와 v를 봤을 때, 두 vector는 수직이다. 그렇다. 모든 eigenvector들은 서로 수직이다. 마치 이렇게 놓고 볼 수 있다.

위와 같이 데이터가 x축 방향으로 놓여있다. 그런데 각각의 데이터가 y방향도 있기는 하다. 그래서 y축도 있는데, x축과 y축은 수직이다. 즉 우리가 머리속에 x축 y축을 그리는 개념이 eigenvector와 비슷하다는 것이다. 다만 한가지 추가된 것이 있다면 각각의 eigenvector가 상응하는 eigenvalue를 가진다는 것 정도이다.


자 eigenvalue와 eigenvector의 기하학적인 의미는 이제 충분히 알아본 것 같다. 그럼 이제 PCA를 설명해보자. PCA는 multi-dimension 데이터에 대해서 eigenvalue와 eigenvector를 구해서 데이터가 흩어져있는 공간의 가장 principal한 방향들을 구하는 것이다. 또 그 방향을 구하면 그에 상응하는 크기인 eigenvalue를 같이 구하게 되는데 그로 인해 데이터들이 어떤 방향으로 얼만큼 중요도를 가지고 있는지를 알 수 있게 된다.


PCA를 실제로 어떻게 구하는지 예제 데이터로 설명해보자. 우선 아래와 같은 데이터가 있다고 해보자.


여기서 중요한 개념이 있는데 우리는 이 데이터를 바로 사용하지 않는다는 것이다. 우리는 이 데이터의 covariance matrix를 구해서 그것에 대하여 eigenvalue eigenvector를 구할 것이다. (eigenvalue와 eigenvector는 반드시 nxn matirx에서만 구할 수 있다.)


위에 주어진 데이터는 10x4 matrix이다. 이것의 covariance matrix C를 구하면 우리는 4x4 matrix를 구할 수 있다.


여기서 4x4 covariance matrix C와 이것의 eigenvector간의 관계를 잘 생각해보자.


L1v1은 c11, c12, c13, c14에 의해 결정된다. 만일 c11이 무지 크고 c12, c13, c14가 무지 작은 숫자라면 결과적으로 L1v1은 c11에 의해서 가장 크게 결정된다는 이야기이다. 이 얘기는 무엇이냐? c11은 covariance matrix에서 dimension1의 covariance이고, c12, c13, c14는 각각 dimension2,3,4와의 covariance인데, c12, c13, c14가 작은 숫자라는 말은 dimension1-dimension2, dimension1-dimension3, dimension1-dimension4의 관계는 거의 없다는 말이다 서로서로 랜덤이라는 말이다. 이것이 우리가 covariance matrix를 구해야 하는 이유이다. covariance matrix를 구함으로서 우리는 각각의 dimension이 서로 다른 dimension과 갖는 정도를 숫자로 표시할 수 있다. (covariance)


따라서 covariance matrix C의 eigenvalue와 eigenvector를 구한다는 의미는 C가 왜곡시키는 공간의 방향을 알아보겠다는 의도가 된다. 그리고 왜곡된 vector들은 covariance matrix의 각 원소에 의해 영향을 받는 것이다.


지금까지 이해한 내용을 살짝 정리해서 PCA를 구하는 식을 한번 구해보자.

(단, A는 데이터를 통해서 구한 Covariance Matrix이며, [v11, v12, v13, v14]가 eigenvalue 람다1에 대한 eigenvector이다.)


여기서 V는 eigenvector들이며 이들은 서로 orthonormal하기 때문에 V의 역행렬은 V의 Transpose와 같다. 따라서 최종식은 아래와 같다.


실제로 맞는지 위의 10x4 데이터를 바탕으로 확인해보자. 10x4 데이터의 Covariance Matrix의 eigenvalue와 eigenvector를 구해서 위의 식대로 계산을 해보면 실제로 아래와 같이 원래의 Covariance Matrix가 나온다.


만일 우리가 이 데이터를 4차원이 아닌 2차원으로 줄이려면 어떻게 해야할까? 4차원 데이터이니까 우리는 eigenvector, eigenvalue가 각각 4개씩 있다. 4차원에서 2차원으로 줄이려면 가장 큰 eigenvalue 2개에 해당하는 eigenvector를 원본 데이터와 행렬 곱해주면 된다. 즉 가장 큰 eigenvalue 2개에 해당하는 eigenvector 2개를 원본 데이터와 곱하면 아래와 같이 된다.


(10x4) x Transpose(2x4)

(10x4) x (4x2) = (2x10) = Net Data


(2x4) 행렬은 가장 큰 eigenvalue 2개에 해당하는 eigenvector 2개를 의미하고

(10x4) 행렬은 원본 데이터를 의미한다. 행렬 곱셈을 해주기 위해서 2개의 eigenvector 행렬의 Transpose를 구해서 원본 데이터 행렬 뒤에 곱해주면 차원이 줄어든 새로운 행렬이 된다. 이 때 우리는 eigenvalue가 가장 큰 2개의 eigenvector를 구해서 곱해줬기 때문에 데이터의 Variance 손실을 최소화해줄 수 있으면서 차원은 줄일 수 있게 된다.


자 이제 지금까지 설명한 원리를 바탕으로 PCA를 구하는 과정을 생각해보자.

1. multi dimension 데이터를 준비한다.

2. 해당 multi dimension 데이터의 covariance matrix를 구한다.

3. covariance matrix의 eigenvalue, eigenvector를 구한다.

4. 줄이고 싶은 dimension만큼의 eigenvector를 원본 데이터에 matrix dotproduct을 구한다.


원래 더 자세하게 PCA를 쓰려면 원래 데이터 복구도 해야되는데 그냥 여기까지 하려고 한다. 원래 데이터 복구하는 부분은 식을 생각해보면 별로 어렵지는 않은 부분이기 때문이다.

Posted by 빛나유
,

저번에 포스팅한 내용은 Tensorflow의 아주 기본적인 동작방식에 대한 내용이었다. 물론 그렇다고 지금 포스팅이 아주 기술적인 내용이 될 것은 아니지만, 적어도 이번 포스팅은 개인적으로 기분이 좋은 포스팅이다. 왜냐하면 내가 처음으로 작성한 Tensorflow 코딩에 대한 line by line 설명 포스팅이니까.


Tensorflow 공식 홈페이지에 가면 "Get started" 메뉴가 있다. 그 메뉴를 클릭하면 제일 처음에 나오는 코드가 Linear Regression이다. 나는 한번 Multi linear regression을 작성해봤다. 별거 아니지만 그래도 뭐든 첫 시작은 의미가 있다.


자 코드를 한줄 한줄 설명하기 전에 어떤 Multi linear regression을 구현할 것인지 살짝 설명을 해보자. 특정 x와 y관계가 아래와 같다고 해보자.


y = 0.27*x1 + 0.28*x2 + 0.38*x3 + 0.54


x는 3차원 데이터이고 0.54라는 bias가 있는 식으로 y를 정의했다. Multi linear regression은 내가 예전에 포스팅을 해둔 것이 있다. 이 포스팅 내용에 나오는 수식을 바탕으로 Tensorflow 수식을 작성했다. 포스팅 링크는 아래에 있다.


http://operatingsystems.tistory.com/entry/Data-Mining-Multi-linear-regression


위의 포스팅 식을 정리하면,


y  = 0.27*x1 + 0.28*x2 + 0.38*x3 + 0.54

y^= a1*x1 + a2*x2 + a3*x3 + a4


에서 (y - y^)의 제곱의 차이를 최소화하기 위하여 a1, a2, a3, a4로 미분을 하여 적절한 a1, a2, a3, a4를 구하는 것이다. 즉 이 식을 Tensorflow로 작성하기 위해서 아래의 4스텝이 필요하다.


1. x와 y를 구한다.

2. y^을 구한다.

3. (y - y^)의 제곱의 합을 구한다.

4. 그 값에 대하여 미분을 수행한다.


위의 4스텝을 차근차근 Tensorflow로 작성해보자.


## Step1 : x와 y를 구한다.

x_data는 numpy로 랜덤하게 구한다. x1, x2, x3밖에 없는데 왜 4차원데이터를 구했는지 궁금하면... 위의 Multi linear regression포스팅을 보면 답이나온다.


## Step2 : y^을 구한다.

a는 변수이기 때문에 tf.Variable로 선언한다. shape은 당연히 4차원으로 한다. tf.random_uniform은 [numfeat] shape의 랜덤한 -1과 1사이의 숫자를 고르게(uniform하게) 얻기 위해서 필요하다. 즉, 우선 랜덤하게 a1, a2, a3, a4를 구해놓고 나중에 optimize하겠다는 것이다.


## Step3 : (y - y^)의 제곱의 합을 구한다.

y - y^은 위와 같이 y_data-formula로 구하면 된다. 그 값들에 대하여 square를 구하고 그 값들을 reduce_mean한다. 여기서 reduce의 의미는 여러 숫자가 하나의 숫자로 됐다는 의미의 reduce이다. 1, 2, 3, 4, 5, 6, 7, 8, 9, 10이라는 열 개의 숫자에 대하여 평균을 구하면 5.5라는 하나의 숫자로 표현된다. 숫자 10개가 숫자 하나로 줄여져서 표현된다는 것이다. 그런 의미에서의 reduce이다. 


## Step4 : 그 값에 대하여 미분을 수행한다.

Gradient Descent를 이용하여 미분하여 loss를 최소화하는 식을 세운다.


위의 과정을 모두 끝냈으면 마지막으로 Variable Initialize하고 Tensorflow 돌리면 된다.

위의 식에서 epochs는 200으로 두었다. 당연히 우리가 원하는 45번째 줄에서의 a의 값은 33번째 줄에 나타나있는 것처럼 0.54, 0.27, 0.48, 0.38이 되어야 한다. 실제로 그렇게 나오는지 위의 코드를 수행해보자.


# 코드 실행


우와 진짜 트레이닝 후에는 0.54, 0.27, 0.48, 0.38로 값이 가까워진다. 우와.


뭐 이렇게 하는거다. 이번 포스팅에서는 Multi linear regression을 Tensor flow를 구현했다. 다음 포스팅은 SVM 구현이다. SVM 구현하고 ANN까지 구현해볼거다. 어떤 알고리즘이나 함수를 구현하는 포스팅은 내 스타일상 맞지는 않다. 그런데 Tensorflow는 한 3개정도는 해봐도 될거 같다고 생각해서 포스팅한다. 그 3개가 Multi linear regression, SVM, ANN이다. 순전히 Tensorflow를 잘 활용하고 익숙해지기 위한 연습예제이다. 

'etc...' 카테고리의 다른 글

[Semantic Web] Linked Data and RDF  (0) 2017.02.06
[Semantic Web] Basic of Semantic Web  (2) 2017.02.06
[Tensorflow] Basic of Tensorflow  (0) 2016.11.27
[Programming] OOP  (0) 2015.12.18
[Algorithm] Graph  (0) 2015.12.18
Posted by 빛나유
,

얼마전에 회사에서 일하다가 Tensorflow 때문에 살짝 자극받았다. 그리고 오늘 토요일!! Tensorflow 기본부터 조금씩 공부해봤다.


우선 Tensorflow는 Google에서 만든 Machine Learning Build-up package같은거라고 보면 된다. 보통 data mining할 때 sklearn같은 Python Package를 많이 사용한다. 여기에는 각종 data mining 알고리즘이 구현되어있다. Tensorflow는 레고조각 같은거다. 각 부품이 작성되어있고 그 부품을 이용해서 우리가 알고리즘을 구현하는 것이다. 


보통 language에 대해서는 포스팅을 안하는데, Tensorflow는 살짝 해두려고 한다. 일단 기존의 Python 작동방식과 조금 다르다. 그래서 헷깔릴수 있기 때문에 살짝 정리하련다. 


우선, Tensor가 뭔지 알아보자. Wikipedia에 보면 Tensor는 Scalar, Vector들의 linear relation을 표현한 어떤 Object라고 설명되어있다. 그래서 Dot Product와 같은 것들이 Tensor의 한 예라고 설명을 한다. 수학적으로 조금 약해서 정확하게 이해를 못 했지만, Tensorflow 공식 웹 페이지에는 Tensor는 n-dimensional array 또는 list라고 생각하면 된다고 한다. "생각하면 된다" 라고 말하는 것은, 정확한 개념은 아니라는 것이다.(나는 그렇게 생각한다) 정확히 아래와 같이 써있다.


You can think of a TensorFlow tensor as an n-dimensional array or list. A tensor has a static type, a rank, and a shape.


"think of" 뭐 그냥 그렇게 생각하면 된다. 라는 의미로 나는 해석했다. 아무튼 이 Tensor는 type, rank, shape이 있다고 한다. Rank부터 알아보자. Rank는 Linear Algebra에서 나왔던 그 rank가 아니다. 나도 잘 몰라서 Rank가 뭔지 정확한 개념으로는 설명을 못 하겠다. 그런데 이렇게 생각하면 쉽다.


"하나의 n-dimensional array 또는 list에서의 각각의 하나의 데이터를 표현하기 위한 index의 dimension"


예를 들어보자.

[1, 2, 3] 이라는 벡터!! 각각의 Index는 0, 1, 2 이런식으로 숫자 하나만 있으면 Index를 표현할 수 있다. 그래서 벡터의 rank는 1이다.


행렬의 rank는 2이다.

1, 2, 3

4, 5, 6

7, 8, 9


각각의 데이터를

(0, 0) = 1

(0, 1) = 2

(0, 2) = 3

...

(2, 2) = 9

와 같이 숫자 두개로 각각의 데이터를 표현할 수 있으니까. 그러니까 행렬들은 rank가 2이다.


shape은 python numpy에서 ".shape"하면 나오는 값과 같다.

1, 2, 3

4, 5, 6

과 같은 matrix는 당연히 shape은 (2, 3) rank는 행렬이니까 무조건 2이다. shape은 어렵지 않으니 간단히 넘어간다. 


Type도 어렵지 않다. 아래와 같은 여러가지 Type을 가진덴다. 그런데 Tensorflow에서는 Type은 잘 고려해줘야 되는 것 같다. 자동으로 형 변환이 안되는 것 같다.


Tensorflow에서 모든 변수들은 Tensor object로 표현된다. 변수는 아래의 세가지 방법으로 가능하다.

1. 상수선언 : tensorflow.constant()

2. 변수선언 : tensorflow.Variable()

3. 미리선언 : tensorflow.placeholder()


상수선언, 변수선언은 알겠는데 미리선언?? 이게 뭐냐?? 말 그대로 미리 자리잡아놓겠다는 것인데, 우선 그런게 있다고 알고 넘어가자. 조금 있다가 다 알게될 내용이다.


실제로 예제를 보자.

# source code


# result

1.0

[1 2 3]


위의 예제는 상수를 print하는 아주 간단한 예제이다. 상수 선언하는 부분은 별로 안어려운데 뭔가 이상한게 있다. "To print constant"라고 해서 상수 print하는 부분이 뭔가 조금 복잡하다. 


Tensorflow에서는 그냥 "print x"와 같이 간단하게 print가 안된다. 반드시 tf.Session()을 통해서 session 오픈하고 tf.Session().run()을 통해서 값을 받아서 print해야 한다. 이점이 기존의 Python과 상당히 다른 부분이다. 즉, tf.Session().run()을 하기 전까지는 그냥 값을 가질 준비만 되어있는 것이지 실제로 값을 가지고 있는 것은 아니라고 보면 된다. 모든 것은 tf.Session().run()이 실행되어야 변수는 실제로 값을 갖게 되고 함수는 실행이 된다. 


변수 print하는 것은 아래와 같다.

# source code


# result

[ 0.  0.  0.  0.  0.  0.  0.  0.  0.  0.]


변수 print하는 부분에서 중요한 것은 tf.initialize_all_variables()이다. 변수를 초기화하겠다는 것이다. tf.Variable()을 통해서 변수를 선언하면 그 변수는 반드시 initialize된 후에 tf.Session().run()을 통해 실제 값을 가져야 한다. 즉 위의 코드에서 9번줄이 빠지면 에러가 난다. 반드시 initialize이후에 run()해줘야 된다.


마지막으로 placeholder를 봐보자.

# source code


# result 

[[2 3 4]

 [5 6 7]]


위의 예제에서 phd_f = phd_x + 1이라고 해뒀고, phd_x는 shape이 (2, 3)인 matrix가 되겠다. 즉 shape이 (2, 3)인 phd_x matrix의 각각 요소에 1을 더한것을 phd_f로 하겠다는 것이다.


phd_f라는 식을 세웠으니 tf.Session().run()으로 돌려보자. 다시 한번 말하지만, Tensorflow에서 모든 것은 tf.Session().run()을 통해서 실제로 수행될 수 있다. phd_f를 돌려서 값을 구하려고 보니, 아직 phd_x가 없다. 그래서 feed해주는 것이다. 무슨 형태로? dictionary형태로.


phd_x에 feed된 [[1, 2, 3], [4, 5, 6]]은 (2, 3) matrix이다. 이건 당연히 5번째 줄에서 선언한 그대로여야 한다. 다르면 에러난다.


여기까지가 아주아주아주 기본적인 Tensorflow의 변수선언 부분이다. 다음 포스팅에서는 Tensorflow를 이용해서 Linear Regression을 구현해보려고 한다.

'etc...' 카테고리의 다른 글

[Semantic Web] Basic of Semantic Web  (2) 2017.02.06
[Tensorflow] Multi linear Regreassion  (1) 2016.11.27
[Programming] OOP  (0) 2015.12.18
[Algorithm] Graph  (0) 2015.12.18
[Algorithm] Sorting Algorithm  (0) 2015.12.17
Posted by 빛나유
,