brunch

You can make anything
by writing

C.S.Lewis

by 라인하트 Feb 12. 2021

머신러닝 옥타브 실습(7-5): 얼굴 이미지 주성분분석

   온라인 강의 플랫폼 코세라의 창립자인 앤드류 응 (Andrew Ng) 교수는 인공지능 업계의 거장입니다. 그가 스탠퍼드 대학에서 머신 러닝 입문자에게 한 강의를 그대로 코세라 온라인 강의 (Coursera.org)에서 무료로 배울 수 있습니다. 이 강의는 머신러닝 입문자들의 필수코스입니다. 인공지능과 머신러닝을 혼자 공부하면서 자연스럽게 만나게 되는 강의입니다. 


Programming Exercise 7: 

K-means Clustering and Principal Component Analysis (K-평균 클러스터링과 주성분 분석)


2. Principal Component Analysis 

(주성분 분석)



2.4 Face Image Dataset


   In this part of the exercise, you will run PCA on face images to see how it can be used in practice for dimension reduction. The dataset ex7faces.mat contains a dataset X of face images, each 32 × 32 in grayscale. Each row of X corresponds to one face image (a row vector of length 1024). The next step in ex7 pca.m will load and visualize the first 100 of these face images (Figure 7).



   이번 실습은 얼굴 이미지에 PCA를 실행하여 실제로 차원 축소가 어떻게 사용되는 지를 확인합니다.  ex7faces.mat 파일은  32 X 32차원의 흑백 얼굴 이미지 5,000개를 가진 데이터 셋으로 데이터 행렬 X를 자동으로 할당합니다. 데이터 행렬 X의 각 행은 얼굴 이미지 한 개로 1024열의 얼굴 이미지를 표현합니다.  ex7_pca.m 파일은 다음 단계에서 얼굴 이미지 중 100개를 로드하고 시각화합니다. 


< Part 4: 얼굴 데이터 시각화>


(1) 이미지 업로드


clear ;             % 옥타브 프로그램에 모든 변수를 제거

close all;         % 터미널 이외의 창을 닫음

clc                   % 터미널을 깨끗이 정리 


load ('ex7faces.mat');


>> load ('ex7faces.mat')

>> whos

Variables in the current scope:


   Attr Name        Size                     Bytes  Class

   ==== ====        ====                     =====  =====

        X             5000x1024                40960000  double


Total is 5120000 elements using 40960000 bytes

 


(2) 100개의 얼굴 이미지를 무작위로 표시  


   데이터 행렬 X에서 100개의 얼굴 이미지를 표시하기 위해 displayData.m 파일을 사용합니다. displayData.m 파일에 첫 번째에서부터 100번째 예제까지 제공합니다.


displayData(X(1:100, :));


   displayData.m 파일은 반환하는 변수가 없습니다.


(3) displayData.m 파일 분석

function [h, display_array] = displayData(X, example_width)

%DISPLAYDATA  2차원 데이터를 격자구조로 표시 

%   [h, display_array] = DISPLAYDATA(X, example_width)

%         데이터 행렬 X와 example_width 변수를 제공 받음

%         요청한다면 h와 display_array를 반환


%  example_width 변수를 제공받지 못하면 자동으로 추가 

if ~exist('example_width', 'var') || isempty(example_width) 

example_width = round(sqrt(size(X, 2)));

end


% 컬러 맵을 흑백으로 설정 

colormap(gray);


% 행과 열을 계산 

[m n] = size(X);

example_height = (n / example_width);


% 표시할 얼굴 이미지의 수를 계산

display_rows = floor(sqrt(m));

display_cols = ceil(m / display_rows);


% 얼굴 이미지 간 패딩(빈 공간)의 크기 선언

pad = 1;


% 빈 공간 설정 

display_array = - ones(pad + display_rows * (example_height + pad), ...

                       pad + display_cols * (example_width + pad));


% 각 학습 예제를 display_array에 삽입 

curr_ex = 1;

     for j = 1:display_rows            % 1번 열부터 시작

           for i = 1:display_cols        % 1번 행부터 시작


                if curr_ex > m,          % curr_ex의 모든 학습 예제를 표시한다면 루프 탈출 

                       break; 

                 end


                    % 패치를 복사하고 최대값

                  max_val = max(abs(X(curr_ex, :)));  


display_array(pad + (j - 1) * (example_height + pad) + (1:example_height), ...

              pad + (i - 1) * (example_width + pad) + (1:example_width)) = ...

reshape(X(curr_ex, :), example_height, example_width) / max_val;


curr_ex = curr_ex + 1;

          end


          if curr_ex > m, 

              break; 

          end


end


% 이미지를 표시 

h = imagesc(display_array, [-1 1]);


% axis의 값을 표시하지 않음 

axis image off


drawnow;


end


   제공된 변수 중에 example_width 변수가 없을 때 example_width 변수를 자동으로 생성합니다.  OR 연산을 나타내는 ||은 1이 하나라도 있으면 참입니다. 따라서, example_width가 없다면 조건문의 내용을 무조건 실행합니다. 


if ~exist('example_width', 'var') || isempty(example_width) 

   example_width = round(sqrt(size(X, 2)));

end


example_width 변수를 제공하지 않았다면 참인 1로 설정하고, isempty(example_width)는 있다면 변수


>> exist('example_width', 'var')

ans = 0

>> ~exist('example_width', 'var')

ans =  1


   example_width = round(sqrt(sixe(X,2))); 코드의 의미를 확인합니다. 


>> size(X,2)          % 데이터 행렬 X는 5000 X 1024차원이고, 열의 개수를 반환 

ans =  1024

>> sqrt(size(X,2))                    % 제곱근을 계산

ans =  32

>> round (sqrt(size(X,2)))    % round 함수는 소수점을 정수로 반올림

ans =  32


   displayData.m 파일은 100개의 데이터만 사용하기 때문에 표시할 학습 예제의 가로길이를 계산합니다. 


X100 = X(1:100,:);

example_width = round(sqrt(size(X,2)))


>> X100 = X(1:100,:);

>> example_width = round(sqrt(size(X100,2)))

example_width =  32


  표시할 학습 예제의 세로 길이를 계산합니다. 

 

[m n] = size(X100)

example_height = (n / example_width)


>> [m n] = size(X100)

m =  100

n =  1024

>> example_height = (n / example_width)

example_height =  32

   

   몇 개의 얼굴 이미지를 가로와 세로에 표시할지를 계산합니다. 


먼저 행의 개수를 계산합니다. 

display_rows = floor(sqrt(m));


>> [m n] = size(X100)

m =  100

n =  1024

>> sqrt(m)               % 제곱근을 계산

ans =  10

>> floor(sqrt(m))           % 내림으로 계산

ans =  10

>> display_rows = floor(sqrt(m))

display_rows =  10


다음으로 열의 개수를 계산합니다. 

display_cols = ceil(m / display_rows);


>> m/display_rows

ans=10

>> ceil(m/display_rows)

ans =  10

>> display_cols = ceil(m / display_rows)

display_cols =  10


   얼굴 이미지를 표시하기 위해 배치 방법을 정의합니다.  


display_array = - ones(pad + display_rows * (example_height + pad), ...

                       pad + display_cols * (example_width + pad));


   먼저 display_array 행렬의 행을 먼저 계산합니다. 


>> pad = 1

pad =  1


>> example_height

example_height =  32


>> example_height + pad

ans =  33


>> display_rows * (example_height + pad)

ans =  330


>> pad + display_rows * (example_height + pad)

ans =  331


   먼저 display_array 행렬의 열을 계산합니다. 


>> pad

pad =  1


>> example_width

example_width =  32


>> example_width + pad

ans =  33


>> display_cols * (example_width + pad)

ans =  330


>> pad + display_cols * (example_width + pad)

ans =  331


따라서, display_array를 계산하는 코드는 다음과 같이 표현할 수 있습니다.



display_array = - ones(331, 331);


 display_array 행렬은 331 X 331차원 행렬이고 값은 -1로 채워져 있습니다. 



최대값을 확인합니다. 


curr_ex = 1

max_val = max(abs(X(curr_ex, :)));  


>> curr_ex = 1

curr_ex =  1


>> X(curr_ex,:)       % 1 X 1024차원의 학습 예제

ans =

 Columns 1 through 5:

   -37.86631   -45.86631   -53.86631   -51.86631   -40.86631

...


>> abs(X(curr_ex, :))  % 절대값을 반환

ans =

 Columns 1 through 5:

    37.86631    45.86631    53.86631    51.86631    40.86631

...


>> max(abs(X(curr_ex, :)))    % 예제 별로 행렬 성분 중 최대값을 반환

ans =  123.87


   얼굴 이미지를 331 X 331차원의 행렬  display_array에 배치합니다.  


display_array(pad + (j - 1) * (example_height + pad) + (1:example_height), ...

              pad + (i - 1) * (example_width + pad) + (1:example_width)) = ...

reshape(X(curr_ex, :), example_height, example_width) / max_val;



display_array의 첫 번째 성분을 정의합니다. 


>> j = 1;

>> example_height + pad

ans =  33


>> (j - 1) * (example_height + pad) % 1행 1열부터 시작하도록 j-1을 추가

ans = 0


>> pad + (j - 1) * (example_height + pad)

ans =  1


>> 1:example_height

ans =

 Columns 1 through 13:

    1    2    3    4    5    6    7    8    9   10   11   12   13


 Columns 14 through 26:

   14   15   16   17   18   19   20   21   22   23   24   25   26


 Columns 27 through 32:

   27   28   29   30   31   32



>> pad + (j - 1) * (example_height + pad) + (1:example_height)

ans =

 Columns 1 through 13:

    2    3    4    5    6    7    8    9   10   11   12   13   14


 Columns 14 through 26:

   15   16   17   18   19   20   21   22   23   24   25   26   27


 Columns 27 through 32:

   28   29   30   31   32   33


첫 번째 이미지는 행은 2부터 33까지 배치합니다. 


첫 번째 성분의 열 부분을 계산합니다. 


>> i = 1

i =  1


>> pad + (i - 1) * (example_width + pad)

ans =  1


>> (1:example_width)

ans =

 Columns 1 through 13:

    1    2    3    4    5    6    7    8    9   10   11   12   13


 Columns 14 through 26:

   14   15   16   17   18   19   20   21   22   23   24   25   26


 Columns 27 through 32:

   27   28   29   30   31   32


>> pad + (i - 1) * (example_width + pad) + (1:example_width)

ans =

 Columns 1 through 13:

    2    3    4    5    6    7    8    9   10   11   12   13   14


 Columns 14 through 26:

   15   16   17   18   19   20   21   22   23   24   25   26   27


 Columns 27 through 32:

   28   29   30   31   32   33



  정리하면, 첫 번째 32 X 32 크기의 얼굴 이미지를 display_array의 위치를 지정합니다


display_array(2:33, 2:33)


  다음으로 1 X 1024차원의 학습 예제를 재배열하여 32 X 32차원으로 변경합니다.  


reshape(X(curr_ex, :), example_height, example_width) 


   그리고, -1과 1 사이에 값을 두기 위해 얼굴 이미지마다 최대 값 max_val로 나누어 줍니다.

최종 정리하면,

display_array(2:33, 2:33) = reshape(X(1, :), 32, 32) / max_val



(4) 얼굴 이미지 시각화 


displayData(X(1:100, :));


displayData(X(1:200, :));


displayData(X(1:400, :));

displayData(X(1:1600, :));



2.4.1 PCA on Faces (얼굴 이미지에 PCA 적용)


   To run PCA on the face dataset, we first normalize the dataset by subtracting the mean of each feature from the data matrix X. The script ex7 pca.m will do this for you and then run your PCA code. After running PCA, you will obtain the principal components of the dataset. Notice that each principal component in U (each row) is a vector of length n (where for the face dataset, n = 1024). It turns out that we can visualize these principal components by reshaping each of them into a 32 × 32 matrix that corresponds to the pixels in the original dataset. The script ex7 pca.m displays the first 36 principal components that describe the largest variations (Figure 8). If you want, you can also change the code to display more principal components to see how they capture more and more details.


   얼굴 데이터 셋에서 PCA를 실행하려면 먼저 데이터 행렬 X에서 각 피처의 평균을 빼서 데이터셋을 정규화합니다. ex7_pca.m 파일은 평균 정규화를 수행하고 PCA 알고리즘을 실행하면 데이터 셋의 주성분을 얻습니다. 고유 벡터 U의 각각의 주성분(각 행)은 n의 길이를 가진 벡터입니다. 얼굴 데이터 셋은 피처 n = 1024입니다. 데이터셋의 1024개의 픽셀을 32 X 32 행렬로 reshape() 함수로 재배열한 후 시각화합니다. ex7_pca.m 파일은 첫 36개의 주성분을 그림 8과 같이 표시합니다. 더 많은 주성분을 표시하도록 코드를 변경하여 더 많은 세부 정보를 표시할 수 있습니다.



< Part 5: 얼굴 데이터에 PCA 적용하기>


(1) 이미지 업로드


clear ;             % 옥타브 프로그램에 모든 변수를 제거

close all;         % 터미널 이외의 창을 닫음

clc                   % 터미널을 깨끗이 정리 


load ('ex7faces.mat');


(2) 데이터 행렬 X 정규화


   학습 데이터를 정규화하기 위한 featureNormalize.m 파일을 이미 분석했습니다. 이 파일은 데이터 행렬 X를 입력하면, 정규화된 데이터 행렬 X_norm, 평균 mu, 표준편차 sigma를 반환합니다. 


[X_norm, mu, sigma] = featureNormalize(X);



(3) 주성분 분석 알고리즘 PCA 실행


   학습 데이터에 주성분 분석 알고리즘  PCA을 적용하기 위한 pca.m 파일을 작성했습니다. 이 파일은 정규화된 데이터 행렬 X_norm을 입력하면, 주성분을 나타내는 고유 벡터 U와  대각 행렬 S를 반환합니다. 


[U, S] = pca(X_norm);


   주성분을 나타내는 고유 벡터 U는 피처의 개수를 나타내는 n X n 행렬이고, 대각 행렬 S도 n X n 행렬입니다.


>> size(U)

ans =

   1024   1024


>> size(S)

ans =

   1024   1024


(4) 36개의 고유 벡터를 시각화


   얼굴 이미지를 시각화하기 위한 displayData.m 파일을 작성했습니다. 이 파일은 주성분을 나타내는 고유 벡터 U의 K열만을 입력하면, K개의 얼굴 이미지를 표시합니다.


displayData(U(:, 1:36)');


   고유 벡터 U는 1024 X 1024차원 행렬이고 주성분을 나타내는 K = 36입니다. 따라서, 첫 번째부터 36 번째까지의 얼굴 이미지 데이터를 표시합니다. 



(5) K의 크기를 변경하여 데이터 셋 표시


>> displayData(U(:, 1:64)')

ans = -1.2937

>> displayData(U(:, 1:100)')

ans = -1.9092




2.4.2 Dimensionality Reduction (차원 축소)


   Now that you have computed the principal components for the face dataset, you can use it to reduce the dimension of the face dataset. This allows you to use your learning algorithm with a smaller input size (e.g., 100 dimensions) instead of the original 1024 dimensions. This can help speed up your learning algorithm.


   얼굴 이미지를 가진 데이터 셋의 주성분을 활용하여 얼굴 데이터 셋의 차원을 줄일 수 있습니다. 1024차원의 원래 얼굴 이미지를 100차원과 같이 더 작은 입력 크기로 줄여서 학습 알고리즘을 사용할 수 있습니다. 차원 감소는 학습 알고리즘의 속도를 개선합니다.   


   


   The next part in ex7 pca.m will project the face dataset onto only the first 100 principal components. Concretely, each face image is now described by a vector z(i) ∈ R100.

   To understand what is lost in the dimension reduction, you can recover the data using only the projected dataset. In ex7 pca.m, an approximate recovery of the data is performed and the original and projected face images are displayed side by side (Figure 9). From the reconstruction, you can ob- serve that the general structure and appearance of the face are kept while the fine details are lost. This is a remarkable reduction (more than 10×) in the dataset size that can help speed up your learning algorithm significantly. For example, if you were training a neural network to perform person recog- nition (gven a face image, predict the identitfy of the person), you can use the dimension reduced input of only a 100 dimensions instead of the original pixels.


   이번 실습은 얼굴 데이터 셋을 처음 100개의 주성분에만 투영합니다. 구체적으로 각 얼굴 이미지의 z^(i)는 R^(100) 차원 벡터입니다.

   차원 축소에서 손실되는 것을 이해하기 위해 투영된 데이터 셋만을 사용하여 데이터를 복구합니다. ex7_pca.m 파일은 투영된 데이터를 원래 데이터의 근사값으로 얼굴 이미지를 그림 9와 같이 복원합니다. 재구성 과정에서 얼굴의 일반적인 구조는 유지되지만 미세한 세부 요소는 손실됩니다. 하지만, 학습 알고리즘의 속도를 크게 높일 수 있도록 데이터셋의 크기를 10배 이상 축소합니다. 예를 들어, 신경망이 얼굴 인식을 학습할 때 원래 픽셀 대신 차원을 축소하여 100차원을 사용합니다.


< Part 6: 얼굴 데이터의 차원을 축소하기>


(1) 정규화된 얼굴 데이터를 주성분에 투영하기


   얼굴 데이터를 주성분에 투영하기 위한 projectData.m 파일을 작성했습니다. 이 파일은 정규화된 얼굴 데이터 행렬 X_norm, 고유 벡터 U, 그리고 PCA 파라미터 K를 입력하면, 투영된 데이터 행렬 Z를 반환합니다.


K = 100;

Z = projectData(X_norm, U, K);


   여기서, PCA 파라미터 K는 고유 벡터 U의 주성분의 크기를 결정합니다. 


>> size(Z)

ans =

   5000    100


   반환된 투영된 데이터 행렬 Z는 5000 X 100차원 행렬입니다. 



< Part 7: PCA 차원 축소를 실행한 얼굴 데이터 시각화>


(1) 투영된 데이터를 원래 데이터의 근사치로 복원


   투영된 데이터를 원래 데이터로 복원하기 위한 recoverData.m 파일을 작성했습니다. 이 파일은 투영된 데이터 행렬 Z, 고유 벡터 U, 그리고 PCA 파라미터 K를 입력하면, 원래 데이터의 근사치 행렬 X_rec를 반환합니다.


K = 100;

X_rec  = recoverData(Z, U, K);


   여기서, PCA 파라미터 K는 데이터를 주성분에 투영할 때  사용한 값입니다.


>> size(X_rec)

ans =

   5000   1024


   X_rec 차원을 원래 데이터 행렬 X와 동일합니다.


(2) 정규화된 데이터를 왼쪽에 표시


   정규화된 원래 데이터 X_norm과 주성분에 투영된 데이터 X_rec를 비교합니다.  


subplot(1, 2, 1);         % 그림 창을 두 개로 나누고 왼쪽에 표시

displayData(X_norm(1:100,:));      % 처음 100개 데이터만 표시

title('Original faces');

axis square;



(3) 원래 데이터의 근사치로 복원된 데이터를 오른쪽에 표시


  정규화된 원래 데이터 X_norm과 주성분에 투영된 데이터 X_rec를 비교합니다.  


subplot(1, 2, 2);                % 두 개로 나누어진 그림 창의 오른쪽에 표시

displayData(X_rec(1:100,:));

title('Recovered faces');

axis square;





2.5 Optional (ungraded) exercise: PCA for visualization

      (선택 실습 : PCA 알고리즘을 이용한 시각화)

      (선택 실습 : PCA 알고리즘을 이용한 시각화)



   In the earlier K-means image compression exercise, you used the K-means algorithm in the 3-dimensional RGB space. In the last part of the ex7 pca.m script, we have provided code to visualize the final pixel assignments in this 3D space using the scatter3 function. Each data point is colored according to the cluster it has been assigned to. You can drag your mouse on the figure to rotate and inspect this data in 3 dimensions.

   It turns out that visualizing datasets in 3 dimensions or greater can be cumbersome. Therefore, it is often desirable to only display the data in 2D even at the cost of losing some information. In practice, PCA is often used to reduce the dimensionality of data for visualization purposes. In the next part of ex7 pca.m, the script will apply your implementation of PCA to the 3- dimensional data to reduce it to 2 dimensions and visualize the result in a 2D scatter plot. The PCA projection can be thought of as a rotation that selects the view that maximizes the spread of the data, which often corresponds to the “best” view.


   지난번에 K-평균을 활용한 이미지 압축 실습을 했었습니다. 3차원 공간의 RGB 데이터에서 K-평균 알고리즘을 사용했습니다. ex7_pca.m 파일의 마지막 실습은 scatter3() 함수를 이용하여  3차원 공간에서 할당된 픽셀을 시각화하는 코드를 제공했습니다. 각 데이터 포인트는 할당된 클러스에 따라 색상을 지정합니다.  그림에서 마우스를 드래그하여 데이터를 3차원으로 회전하고 검사합니다.

   데이터 셋을 3차원 이상으로 시각화하는 것은 번거롭습니다. 따라서 일부 정도가 손실되더라도 데이터를 2D로 표시하는 것이 좋습니다. 실제로 PCA는 시각화 목적으로 데이터의 차원을 줄이기 위해 사용합니다. ex7_pca.m 파일은 PCA 알고리즘을 사용하여 3차원 데이터를 2차원으로 축소하고 결과를 2D 산포도로 시각화합니다. PCA에 투영도니 데이터는 데이터의 확산을 최대화하는 보기를 선택하는 것으로 생각합니다. 




< Part 8: PCA 차원 축소를 활용한 데이터 시각화>


(1) 옥타브 프로그램 초기화 이미지 업로드


clear;             

close all;         

clc                  


A = double(imread('bird_small.png'));


   이미지 압축을 실습하기 위해 사용했던 새 그림을 옥타브 프로그램에 로드합니다. 


>> A = double(imread('bird_small.png'));

>> whos

Variables in the current scope:


   Attr Name        Size                     Bytes  Class

   ==== ====        ====                     =====  =====

        A               128x128x3                 393216  double


Total is 49152 elements using 393216 bytes


(2) 최대값으로 피처 스케일링


   3차원 공간에 할당된 RGB 데이터를 0과 1 사이의 값으로 두기 위해 피처 스케일링을 수행합니다. 모든 값이 1과 255 사이의 값을 가지는 8비트이므로 단순하게 255로 나눕니다.


A = A / 255;


   이미지 파일에서 불러들인 원본 이미지 데이터입니다.


>> A

A =

ans(:,:,1) =

 Columns 1 through 11:

   219   230   226   223   225   228   228   228   225   218   221

   230   224   226   221   229   231   228   226   224   216   215

   ...


   최대값으로 단순하게 피처 스케일링을 한 데이터입니다.


>> A = A/255

A =

ans(:,:,1) =

 Columns 1 through 6:

   0.858824   0.901961   0.886275   0.874510   0.882353   0.894118

   0.901961   0.878431   0.886275   0.866667   0.898039   0.905882

   ...


(3) 2차원 데이터로 재배열


   RGB 데이터를 표현하기 위해 3차원 공간에 나열된 데이터를 2차원 공간으로 변환합니다.  데이터를 변환하기 위해 reshape() 함수를 사용합니다. 


img_size = size(A);

X = reshape(A, img_size(1) * img_size(2), 3);


   3차원 공간의 데이터 A는 2차원 공간의 데이터 X로 변환합니다. 즉, 128 X 128 X 3차원 행렬을 16384 X 3차원 행렬로 변환합니다. 


>> size(A)

ans =

   128   128     3


>> size(X)

ans =

   16384       3



(4) 초기 클러스터 중심을 무작위로 결정


   초기 클러스터 중심을 무작위로 결정하기 위한 kMeansInitCentroids.m 파일을 작성했습니다. 이 파일은 데이터 행렬 X와 PCA 파라미터 K를 입력하면, 무작위로 초기화된 클러스터 중심의 위치 initial_centroids를 반환합니다.


K = 16; 

initial_centroids = kMeansInitCentroids(X, K);

 

   여기서, 255가지 색상으로 표시된 이미지를 16 가지 색상으로 표현하기 위해 PCA 파라미터 K의 값을 16으로 지정합니다. 


>> initial_centroids

initial_centroids =

   0.082353   0.086275   0.094118

   0.078431   0.098039   0.082353

   0.792157   0.611765   0.309804

   0.850980   0.737255   0.764706

   0.105882   0.117647   0.109804

   0.992157   0.717647   0.431373

   0.992157   0.988235   0.854902

   0.549020   0.615686   0.623529

   0.450980   0.486275   0.435294

   0.968627   0.925490   0.678431

   0.549020   0.603922   0.890196

   0.062745   0.082353   0.074510

   0.980392   0.949020   0.725490

   0.964706   0.925490   0.635294

   0.862745   0.760784   0.525490

   0.294118   0.368627   0.439216


   kMeanInitCentroids.m 은 전체 16384 X 3차원 행렬 X를 무작위로 재배치하고, 첫 번째 학습 예제부터 16개의 학습 데이터를 무작위로 선택하여 반환합니다. Initial_centroids는 16 X 3차원 행렬이고, 1열은 빨간색(Red), 2열은 초록색(Green), 3열은 파란색(Blue)의 강도를 0과 1 사이의 값으로 표현합니다. 원래는 8비트로 0에서 255 사이의 값으로 표현하지만 최대값 255로 나눈 피처 스케일링을 적용했습니다.  



(5) K-평균 알고리즘 실행


   K-평균 알고리즘을 구현하기 위한 runkMeans.m 파일을 작성했습니다. 이 파일은 데이터 행렬 X, 초기 클러스터 중심 initial_centrodis, 그리고 최대 반복 회수 max_iters를 입력하면, 전역 최소값을 가진 클러스터 중심 centroids와 인덱스 idx를 반환합니다. 


max_iters = 10;

[centroids, idx] = runkMeans(X, initial_centroids, max_iters);


   K-평균 알고리즘이 최소값에 머물도록 10회 반복하기 위해 max_iters는 10입니다. 

   runkMeans.m 파일은 256가지 색깔의 이미지를 가장 많이 사용하는 색깔인 16가지를 결정하고 centroids로 반환합니다. centroids는 16가지 색깔의 사전과 같습니다. 


>> centroids

centroids =

   0.147967   0.153980   0.145920

   0.097345   0.105126   0.094816

   0.733443   0.541760   0.263505

   0.773765   0.723771   0.729831

   0.251495   0.224603   0.210479

   0.903565   0.637286   0.331545

   0.964247   0.954359   0.862507

   0.592686   0.518305   0.474620

   0.543610   0.400605   0.219730

   0.962987   0.797806   0.691459

   0.470366   0.575126   0.770272

   0.067273   0.073096   0.062835

   0.978102   0.928917   0.716236

   0.937090   0.812152   0.526094

   0.805355   0.688828   0.466007

   0.376963   0.331214   0.325400


   idx는 16384 X 1차원 행렬입니다. centroids 행렬에 정의된 색상 인덱스를 표시합니다. 예를 들어, 첫 번째 픽셀의 색상이 centrodis의 15번째 행과 같은 클러스터에 속한다면, idx^(1) = 15입니다. 


>> size(idx)

ans =

   16384       1


>> idx

idx =

   15

   14

   14

   15

   15

   15

   ...



(5) 복잡한 계산을 위한 코드(1)


   학습 알고리즘이 속도를 얼마나 개선하는 지를 확인하기 위해 CPU 자원을 많이 소모하는 복잡한 계산을 수행하는 코드를 만듭니다. 이런 코드에 적합한 rand() 함수를 사용합니다. rand() 함수는 0과 1 사이의 난수를 생성합니다. 


>> rand             % rand 함수는 임의의 값 1개를 반환

ans =  0.87129

>> rand

ans =  0.62109


>> rand(2)           % rand는 임의의 값 2 X 2 행렬로 반환

ans =

   0.071069   0.808010

   0.645266   0.267378


>> rand(3)                % rand는 임의의 값 3 X 3 행렬로 반환

ans =

   0.34939   0.20160   0.73918

   0.37377   0.57259   0.86952

   0.33945   0.59338   0.64518


>> rand(3,1)              % rand는 임의의 값 3 X 1 행렬로 반환

ans =

   0.11783

   0.11641

   0.13374


   복잡한 계산은 다음과 같습니다. 


sel = floor(rand(1000, 1) * size(X, 1)) + 1;


   정리하면, sel = floor ( 1000X1 벡터 * 16384) + 1을 계산한 결과를 내림합니다. 컴퓨터가 계산에 좀 시간이 걸려야 비교를 할 수 있으므로 벡터의 값을 올립니다. 그러나, 뒷 과정이 복잡하므로 1,000으로 먼저 완료합니다. 


(5) 복잡한 계산을 위한 코드(2)


   hsv() 함수는 HSV 컬러맵 반환합니다. 


palette = hsv(K);


   PCA 파라미터 K는 16입니다. 따라서, 컬러맵은 16개의 색을 반환합니다.


>> hsv(K)

ans =

   1.00000   0.00000   0.00000

   1.00000   0.37500   0.00000

   1.00000   0.75000   0.00000

   0.87500   1.00000   0.00000

   0.50000   1.00000   0.00000

   0.12500   1.00000   0.00000

   0.00000   1.00000   0.25000

   0.00000   1.00000   0.62500

   0.00000   1.00000   1.00000

   0.00000   0.62500   1.00000

   0.00000   0.25000   1.00000

   0.12500   0.00000   1.00000

   0.50000   0.00000   1.00000

   0.87500   0.00000   1.00000

   1.00000   0.00000   0.75000

   1.00000   0.00000   0.37500


>> palette = hsv(K);


  colors는 난수를 표시한 sel을 이용하여 나타냅니다.


>> colors = palette(idx(sel),:);


>> size(colors)

ans =

   10000         3



(7) 데이터 시각화 : 원래 데이터 X 


   데이터를 3차원으로 표시하는 scatter3() 함수를 사용합니다. scatter3(X, Y, Z)는 3개의 벡터값을 바탕으로 지정된 위치에 데이터를 작은 원으로 표시합니다. 


>> scatter3(X, Y, Z)  % 3개의 벡터 값을 기준으로 데이터를 작은 원으로 표시


>> scatter3(X,Y,Z, 10)   % 데이터의 크기를 10으로 지정


>> scatter3(X, Y, Z, 10, C)  % 데이터를 C로 지정된 크기로 설정



figure;

scatter3(X(sel, 1), X(sel, 2), X(sel, 3), 10, colors);

 



title('Pixel dataset plotted in 3D. Color shows centroid memberships');



(8) 데이터 시각화 : PCA로 차원 감소된 데이터 


   학습 데이터를 정규화하기 위한 featureNormalize.m 파일을 이미 분석했습니다. 이 파일은 데이터 행렬 X를 입력하면, 정규화된 데이터 행렬 X_norm, 평균 mu, 표준편차 sigma를 반환합니다. 


[X_norm, mu, sigma] = featureNormalize(X);


   학습 데이터에 주성분 분석 알고리즘  PCA을 적용하기 위한 pca.m 파일을 작성했습니다. 이 파일은 정규화된 데이터 행렬 X_norm을 입력하면, 주성분을 나타내는 고유 벡터 U와  대각 행렬 S를 반환합니다. 


[U, S] = pca(X_norm);


   학습 데이터를 주성분에 투영하기 위한 projectData.m 파일을 작성했습니다. 이 파일은 정규화된 데이터 행렬 X_norm, 고유 벡터 U, 그리고 PCA 파라미터 K를 입력하면, 투영된 데이터 행렬 Z를 반환합니다.


Z = projectData(X_norm, U, 2);


   여기서, PCA 파라미터 K는 고유 벡터 U의 주성분의 크기를 결정합니다.  3차원 데이터를 2차원으로 줄입니다. 


   투영된 데이터 Z를 그립니다.



palette = hsv(K + 1);

colors = palette(idx(sel), :);


scatter(Z(sel,1), Z(sel,2), 15, colors);



title('Pixel dataset plotted in 2D, using PCA for dimensionality reduction');



매거진의 이전글 머신러닝 옥타브 실습(7-4): PCA 주성분 분석
브런치는 최신 브라우저에 최적화 되어있습니다. IE chrome safari