brunch

You can make anything
by writing

C.S.Lewis

by 라인하트 Jan 08. 2021

머신러닝 옥타브 실습(4-1):신경망손글씨 인식

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



Programming Exercise 4: Neural Networks Learning

프로그래밍 실습 4 : 신경망 학습   


1. Neural Networks (신경망)


   In the previous exercise, you implemented feedforward propagation for neu- ral networks and used it to predict handwritten digits with the weights we provided. In this exercise, you will implement the backpropagation algorithm to learn the parameters for the neural network.

   The provided script, ex4.m, will help you step through this exercise.


   지난 실습에서  주어진 가중치 파라미터 Θ 를 이용하여 신경망의 순전파 알고리즘을 구현하였습니다. 이번 실습에서 신경망의 파라미터 Θ를 학습하는 역전파 알고리즘을 구현합니다. 

   ex4.m 파일은 실습을 진행하는 데 도움을 줄 것입니다. 


1.1 Visualizing the data (데이터 시각화)


   In the first part of ex4.m, the code will load the data and display it on a 2-dimensional plot (Figure 1) by calling the function displayData.


   ex4.m 파일의 첫 부부는 데이터를 로드하고 displayData 함수를 호출하여 평면 그림을 표시합니다. 



   This is the same dataset that you used in the previous exercise. There are 5000 training examples in ex3data1.mat, where each training example is a 20 pixel by 20 pixel grayscale image of the digit. Each pixel is represented by a floating point number indicating the grayscale intensity at that location. The 20 by 20 grid of pixels is “unrolled” into a 400-dimensional vector. Each of these training examples becomes a single row in our data matrix X. This gives us a 5000 by 400 matrix X where every row is a training example for a handwritten digit image.



   The second part of the training set is a 5000-dimensional vector y that contains labels for the training set. To make things more compatible with Octave/MATLAB indexing, where there is no zero index, we have mapped the digit zero to the value ten. Therefore, a “0” digit is labeled as “10”, while the digits “1” to “9” are labeled as “1” to “9” in their natural order.


   지난 실습에서 사용한 것과 동일한 데이터 셋입니다. ex3data1.mat 파일은 5,000개의 학습 예제가 있고, 각 학습 예제는 20 X 20 픽셀의 회색 이미지입니다. 각 픽셀은 선명도를 부동 소수점 숫자로 표시합니다. 20 X20 픽셀 격자는 400 파원 벡터로 언롤링됩니다.  각 학습 예제는 데이터 행렬 X에서 단일 행입니다. 모든 행이 손글씨 숫자 이미지이고 5,000 X 400 행렬 X입니다. 


   학습 셋의 두 번째 부분은 레이블을 나타내는 5,000차원 벡터 y입니다. 0-인텍스가 없는 옥타브 프로그램은 숫자 0을 10에 매핑합니다. 따라서, 0 숫자는 10으로 레이블이 지정되고 1에서 9까지의 숫자는 순서대로 1에서 9로 지정합니다. 


1.2 Model representation 


   Our neural network is shown in Figure 2. It has 3 layers – an input layer, a hidden layer and an output layer. Recall that our inputs are pixel values of digit images. Since the images are of size 20 × 20, this gives us 400 input layer units (not counting the extra bias unit which always outputs +1). The training data will be loaded into the variables X and y by the ex4.m script.

   You have been provided with a set of network parameters (Θ(1),Θ(2)) already trained by us. These are stored in ex4weights.mat and will be loaded by ex4.m into Theta1 and Theta2. The parameters have dimensions that are sized for a neural network with 25 units in the second layer and 10 output units (corresponding to the 10 digit classes).


   그림 2에 신경망의 그림이 있습니다. 입력층, 은닉층, 출력층의 3개 층이 있습니다. 입력은 숫자로 된 20 X 20 이미지의 픽셀 값이고 400개의 입력 유닛으로 구성합니다. (항상 1의 값을 가지는 바이어스 유닛은 미포함). 학습 데이터는 변수 X, y를 함께 옥타브 프로그램에 로드합니다.

    ex4weights.mat 파일은 신경망 파라미터 Θ^(1)과 Θ^(2)을 제공합니다. 파라미터 Θ^(1)는 Theta1으로  Θ^(2)는 Theta2로 변수가 자동 지정합니다. 신경망의 두 번째 층은 25 은닉 유닛과 세 번째 층은 10개의 출력 유닛으로 구성합니다. 


% 옥타브 프로그램으로 가중치인 파라미터 Theta를 로드 
 
load('ex4weights.mat'); 

%. 행렬 Theta1은  25 X 401 차원이고, 행렬 Theta2는 10 X 26 차원입니다. 




<해설>


(1) 데이터 업로드 및 기본 변수 설정 


clear; close all; clc         

load ('ex4data1.mat');  % 5000X 400의 손글씨 숫자 흑백 이미지 행렬을 업로드   

[m, n] = size(X);              % 행렬 X가 5000X 400차원일 때 m = 5000, n= 400    


(2) 신경망 변수 설정


input_layer_size  = 400;    % 20x20 이미지를 입력하기 위한 유닛 수

hidden_layer_size = 25;     % 25 은닉 유닛의 수 

num_labels = 10;                   % 멀티 클래스의 수, 0은 10으로 처리

   

(3) 데이터 시각화


rand_index = randperm(m,100);  

sel = X (rand_index,:);  


displayData (sel);


(4) 파라미터 Theta1과 Theta2를 업로드


       ex4weights.mat 파일은 신경망 파라미터 Θ^(1)과 Θ^(2)을 제공합니다. 파라미터 행렬 Θ^(1)는  25 X 401차원이고 변수는 Theta1입니다. 파라미터 행렬  Θ^(2)는 10 X 26차원 행렬이고 변수는 Theta2입니다. 


load('ex4weights.mat');



(5) unrolling parameter의 이해


   선형 회귀와 로지스틱 회귀는 파라미터 벡터 θ를 사용합니다. 파라미터 벡터 θ는 학습 데이터 셋의 피처 수만큼 필요합니다. 그러나 신경망은 파라미터 행렬 Θ를 사용합니다. 파라미터 행렬 Θ는 s(j+1) x (sj +1) 만큼 필요합니다. sj는 층별 유닛의 수이고 j는 아래 첨자입니다. 예를 들어, 첫 번째 층은 400개 입력 유닛이고 두 번째층이 25개 은닉 유닛이라면 파라미터 행렬 Θ 는 401X 26입니다.  


   따라서, 고급 최적화 알고리즘을 사용할 때는 파라미터 행렬 Θ를 파라미터 벡터  θ로 변경해야 합니다. 즉, 파라미터 행렬을 파라미터 벡터로 변경하는 것을 unrolling parameter라고 합니다. 


Theta1(:)  % Theta1을 25 X 401차원 행렬에서 10025 X 1차원 벡터로 전환

Theta2(:)   % Theta2를 10 X 26차원 행렬에서 260 X 1차원 벡터로 전환


   두 벡터 Theta1과 Theta2를 하나의 nn_params 벡터로 전환합니다. nn_params는 10285 X 1차원 벡터입니다.


nn_params = [Theta1(:) ; Theta2(:)];

 



1.3 Feedforward and cost function

        (피드 포워드와 비용 함수) 

        (피드 포워드와 비용 함수) 


Recall that the cost function for the neural network (without regularization) is


   where hθ(x(i)) is computed as shown in the Figure 2 and K = 10 is the total number of possible labels. Note that hθ(x(i))k = a(3) is the activation (output value) of the k-th output unit. Also, recall that whereas the original labels (in the variable y) were 1, 2, ..., 10, for the purpose of training a neural network, we need to recode the labels as vectors containing only values 0 or 1, so that



   For example, if x(i) is an image of the digit 5, then the corresponding y(i) (that you should use with the cost function) should be a 10-dimensional vector with y5 = 1, and the other elements equal to 0.

   You should implement the feedforward computation that computes hθ(x(i)) for every example i and sum the cost over all examples. Your code should also work for a dataset of any size, with any number of labels (you can assume that there are always at least K ≥ 3 labels).


   신경망의 비용 함수는 다음과 같습니다. 여기서  hθ(x^(i)) 그림 2와 같이 계산하고 K =10은 총 레이블의 수입니다.  hθ(x^(i))k = a^(3)은 k번째 출력 단위의 활성화 (출력 값)입니다. 또한, 원래 레이블은 1,2,..., 10이었지만 신경망이 학습하는 레이블은 0 또는 1 값만 포함하는 벡터로 다시 코딩합니다. 


   예를 들어, x^(i)가 숫자 5의 이미지인 경우 y^(i)(비용 함수와 함께 사용함)는 y(5) = 1인 10차원 벡터입니다. 

   모든 예제 i에 대해  hθ(x^(i)를 계산하고 모든 예제에 대한 비용을 합산하는 피드 포워드 계산을 구현해야 합니다. 코드는 레이블의 수에 관계없이 모든 크기의 데이터 셋에서 동작합니다. (항상 최소 k는 3보다 크거가 같다)


Implementation Note: 

   The matrix X contains the examples in rows (i.e., X(i,:)’ is the i-th training example x(i), expressed as a n × 1 vector.) When you complete the code in nnCostFunction.m, you will need to add the column of 1’s to the X matrix. The parameters for each unit in the neural network is represented in Theta1 and Theta2 as one row. Specifically, the first row of Theta1 corresponds to the first hidden unit in the second layer. You can use a for-loop over the examples to compute the cost.


구현 참고 사항:

   행렬 X의 행은 학습 예제입니다. X(i,:)는 행 벡터를 표현하고 i 번째 예제입니다. nnCostFunction.m 파일의 코드를 완성할 때 다음을 고려합니다. 행렬 X에 1열을 추가합니다. 신경망의 각 단위에 대한 파라미터는 Theta1 및 Theta2에 하나의 행으로 표시합니다. 특히, Theta1의 첫 번째 행은 2층의 첫 번째 은닉 유닛에 해당합니다. For 루프를 사용하여 비용을 계산합니다.


   Once you are done, ex4.m will call your nnCostFunction using the loaded set of parameters for Theta1 and Theta2. You should see that the cost is about 0.287629.


   완료되면 ex4.m은 Theta1 및 Theta2에 로드된 파라미터 셋을 사용하여 nnCostFunction을 호출합니다. 비용은 약 0.287629입니다. 




<해설>


(1) 데이터 업로드 및 기본 변수 설정 


clear; close all; clc         

load ('ex4data1.mat');  % 5000X 400의 손글씨 숫자 흑백 이미지 행렬을 업로드   

[m, n] = size(X);              % 행렬 X가 5000X 400차원일 때 m = 5000, n= 400    


(2) 신경망 변수 설정


input_layer_size  = 400;    % 20x20 이미지를 입력하기 위한 유닛 수

hidden_layer_size = 25;     % 25 은닉 유닛의 수 

num_labels = 10;                   % 멀티 클래스의 수, 0은 10으로 처리


load('ex4weights.mat');   

nn_params = [Theta1(:) ; Theta2(:)];      % Theta1과 Theta2를 벡터로 변환하고 합침 

lambda = 0;                                             % 정규화 파라미터 λ를 초기화


(3) nnCostFunction.m 파일 분석



function [J grad] = nnCostFunction(nn_params,input_layer_size, ...

                                   hidden_layer_size, num_labels, X, y, lambda)

%NNCOSTFUNCTION  2층 신경망의 비용 함수 구현 

%

%   [J grad] = NNCOSTFUNCTON(nn_params, hidden_layer_size, num_labels, ...

%   X, y, lambda) 신경망의 비용 J과 기울기 grad를 계산 

%   신경망의 파라미터는 벡터 nn_params로 변환했다가 가중치 행렬로 다시 변환

%

%   변환될 파라미터는 신경망의 편미분에 대한 unrolled 벡터가 변환

%   

%   Reshape() 함수로 nn_params를 Theta1과 Theta2로 전환 

Theta1 = reshape(nn_params(1:hidden_layer_size * (input_layer_size + 1)), ...

                 hidden_layer_size, (input_layer_size + 1));


Theta2 = reshape(nn_params((1 + (hidden_layer_size * (input_layer_size + 1))):end), ...

                 num_labels, (hidden_layer_size + 1));


% 변수 초기화 

m = size(X, 1);

         

% 반환할 변수 초기화  

J = 0;

Theta1_grad = zeros(size(Theta1));

Theta2_grad = zeros(size(Theta2));


% ====================== YOUR CODE HERE ======================

% Instructions: 다음 두 부분을 코드로 완성 

%

% Part 1: 신경망을 피드포워드하고 변수 J에 비용을 반환

 %             Part 1을 구현한 후 비용 함수 계산이 맞는 지를 확인

%

% Part 2: 경사를 계산하기 위해 역전파 알고리즘을 구현

%               (Theta1_grad과 Theta2_grad 에 있는 Theta1과 Theta2의 비용 함수의 편미분을 반환

%              Part 2를 구현 후 checkNNGradients를 실행하여 맞는 지를 확인

%

%         노트:  벡터 y는 1부터 K까지를 포함하는 벡터

%               신경망의 비용 함수에 사용되는 1 또는 0으로 된 이진 벡터 

%

%         힌트: 학습 예제를 대상으로 For 루프를 사용하여 역전파를 구현 

%          

%

% Part 3: 비용 함수와 기울기에 대해 정규화를 구현

%

%         힌트: 역전파 코드를 활용하여 정규화된 비용 함수와 기울기 구현 

%                  정규화를 위한 경사를 계산하고 Part 2의 Theta1_grad와 Theta2_grad를 추가

%        

%



% -------------------------------------------------------------


% =========================================================================


% 기울기를 언롤링(Unroll)

grad = [Theta1_grad(:) ; Theta2_grad(:)];



end


(4) 벡터 nn_params를 재설계


   신경망 파라미터 벡터 nn_parms는 첫 번째 층인 입력층에서 사용하는 가중치 파라미터 Theta1과 두 번째층인 은닉층에서 사용하는 가중치 파라미터 Theta2가 포함된 10285 X 1차원입니다. 벡터 nn_params를 다시 두 개의 변수 Theta1과 Theta2로 분리합니다. 


   reshape() 함수는 Theta1과 Theta2의 원래 차원으로 변환합니다. reshape() 함수는 행렬을 원하는 차원으로 재배열합니다. 


>> reshape(1:15, 3, 5)     % 1에서 15까지를 3 X 5차원 행렬로 변환

ans =

    1    4    7   10   13

    2    5    8   11   14

    3    6    9   12   15


   아래 변수는 이미 선언한 값입니다. 


   hidden_layer_size : 25  은닉층( Hidden Layer) 은닉 유닛의 수 

   input_layer_size : 400   입력층 (Input Layer) 입력 유닛의 수

   num_labels : 10                    % 멀티 클래스의 수, 0은 10으로 처리

   +1                                       바이어스 유닛


   Theta1 = reshape(nn_params(1:hidden_layer_size * (input_layer_size + 1)), ...

                 hidden_layer_size, (input_layer_size + 1));


    위의 식은 Theta1 = reshape(nn_params(1:25*401, 25,401)과 같습니다. Theta1은 25 X 401 행렬로 재설계합니다. 


Theta2 = reshape(nn_params((1 + (hidden_layer_size * (input_layer_size + 1))):end), num_labels, (hidden_layer_size + 1));


    위의 식은 Theta2 = reshape(nn_params(25*401+1:end, 10,26)과 같습니다. Theta1은 10 X 26 행렬로 재설계합니다. 



(5) 반환할 변수 초기화  


J = 0;

Theta1_grad = zeros(size(Theta1));      % 25 X 401 행렬 Theta1과 동일한 크기 

Theta2_grad = zeros(size(Theta2));      % 10 X 26 행렬 Theta2와 동일한 크기



(6) 신경망의 입력층 a^(1) : 바이어스항 추가


   신경망의 입력층은 데이터 행렬 X에 항상 1의 값을 가지는 바이어스 항을 추가합니다.


X = [ones(m,1) X];


(7) 신경망의 은닉층 a^(2) : 파라미터 행렬 Theta1* a^(1) 계산


   신경망의 두 번째 층의 활성화 함수는 파라미터 행렬 Theta1과 데이터 x 간의 곱셈을 합니다. 


a2 = sigmoid(X*Theta1');

    

   먼저 입력층에서 은닉층으로 넘어갈 때 파라미터 행렬Theta1과 데이터 행렬 X를 행렬 곱셈하여 은닉층 활성화 함수 행렬 a2를 계산합니다. 데이터 행렬 X는 인터셉트 항 를 추가하여 5,000×401 차원이고, 파라미터 행렬 Theta1은 25×401 차원입니다. 은닉층 활성화 함수 행렬 a2는 5,000×25 차원입니다. 



(8) 신경망의 출력층 a^(3): 파라미터 행렬 Theta2*a^(2) 계산


   다음으로 은닉층에서 출력층으로 넘어갈 때 파라미터 행렬 Theta2를 이용하여 출력층 활성화 함수 a3를 계산합니다. 은닉층 활성화 함수 행렬 a2는 인터셉트 항 를 추가하여 5,000×26 차원이고, 파라미터 행렬 Theta2는  10×26 차원입니다. 출력층 활성화 함수 행렬 a3는 5,000×10 차원입니다.

a2 = [ones(size(a2,1), 1) a2];

a3 = sigmoid(a2*Theta2');


(9) y의 레이블을 벡터로 변환


   프로그래밍 실습 3에서는 max() 함수를 이용하여 5000×10 차원 행렬 a3를 5,000×1 차원으로 재배열하여 5,000×1 차원의 실제값 벡터 y였습니다. 여기서는 반대로 실제값 y를 5,000×10차원 행렬로 재배열하여 a3와 비교합니다. 


for k = 1:m

    yVec(k,y(k)) = 1;

end


   예를 들어, y(1)이 10 일 때 yVec(1,10) 의 값은 1이고 나머지는 0입니다. y(1000)이 1일 때 yVec(1000,1)의 값은 1이고 나머지는 0입니다. 옥타브 프로그램에서 직접 확인합니다. 


>> y(1)

ans =  10


>> yVec(1,:)

ans =

   0   0   0   0   0   0   0   0   0   1 


>> y(1000)

ans =  1


>> yVec(1000,:)

ans =

   1   0   0   0   0   0   0   0   0   0



(10) 비용 함수를 계산 


   신경망의 비용 함수 공식을 옥타브 프로그램의 코드로 변환합니다. 

   


J = - 1/m *sum(sum  (yVec .*log(a3) + (1-yVec) .*log(1-a3)))


   yVec은 5,000×10 차원이고, a3는 5,000×10차원 행렬입니다. 두 행렬 성분간 곱셈을 합니다. 모든 값을 하나로 합치고 총 학습 예제의 수로 나누어 줍니다. 

   따라서, 옥타브 프로그램에서 실제 계산한 결과 값입니다. 


>> J = - 1/m *sum(sum  (yVec .*log(a3) + (1-yVec) .*log(1-a3)))

J =  0.28763


문제에서 말한 비용 약 0.287629와 같은 값이 나왔습니다. 


<정답> 


function [J grad] = nnCostFunction(nn_params,input_layer_size, ...

                                   hidden_layer_size, num_labels, X, y, lambda)

%NNCOSTFUNCTION  2층 신경망의 비용 함수 구현 

%

%   [J grad] = NNCOSTFUNCTON(nn_params, hidden_layer_size, num_labels, ...

%   X, y, lambda) 신경망의 비용 J과 기울기 grad를 계산 

%   신경망의 파라미터는 벡터 nn_params로 변환했다가 가중치 행렬로 다시 변환

%

%   변환될 파라미터는 신경망의 편미분에 대한 unrolled 벡터가 변환

%   

%   Reshape() 함수로 nn_params를 Theta1과 Theta2로 전환 

Theta1 = reshape(nn_params(1:hidden_layer_size * (input_layer_size + 1)), ...

                 hidden_layer_size, (input_layer_size + 1));


Theta2 = reshape(nn_params((1 + (hidden_layer_size * (input_layer_size + 1))):end), ...

                 num_labels, (hidden_layer_size + 1));


% 변수 초기화 

m = size(X, 1);

         

% 반환할 변수 초기화  

J = 0;

Theta1_grad = zeros(size(Theta1));

Theta2_grad = zeros(size(Theta2));


% ====================== YOUR CODE HERE ======================

% Instructions: 다음 두 부분을 코드로 완성 

%

% Part 1: 신경망을 피드포워드하고 변수 J에 비용을 반환

 %             Part 1을 구현한 후 비용 함수 계산이 맞는 지를 확인

%

% Part 2: 경사를 계산하기 위해 역전파 알고리즘을 구현

%               (Theta1_grad과 Theta2_grad 에 있는 Theta1과 Theta2의 비용 함수의 편미분을 반환

%              Part 2를 구현 후 checkNNGradients를 실행하여 맞는 지를 확인

%

%         노트:  벡터 y는 1부터 K까지를 포함하는 벡터

%               신경망의 비용 함수에 사용되는 1 또는 0으로 된 이진 벡터 

%

%         힌트: 학습 예제를 대상으로 For 루프를 사용하여 역전파를 구현 

%          

%

% Part 3: 비용 함수와 기울기에 대해 정규화를 구현

%

%         힌트: 역전파 코드를 활용하여 정규화된 비용 함수와 기울기 구현 

%                  정규화를 위한 경사를 계산하고 Part 2의 Theta1_grad와 Theta2_grad를 추가

%        

%




X = [ones(m,1) X];

a2 = sigmoid(X*Theta1'); 


a2 = [ones(size(a2,1), 1) a2];

a3 = sigmoid(a2*Theta2'); 


for k = 1:m

    yVec(k,y(k)) = 1;

end 


% Computing Cost Function J

J = - 1/m *sum(sum(yVec .*log(a3) + (1-yVec) .*log(1-a3)));


% -------------------------------------------------------------


% =========================================================================


% 기울기를 언롤링(Unroll)

grad = [Theta1_grad(:) ; Theta2_grad(:)];



end


<결과 확인>


clear; close all; clc         

load ('ex4data1.mat');    

[m, n] = size(X);              


input_layer_size  = 400;    

hidden_layer_size = 25;     

num_labels = 10;                 


load('ex4weights.mat');   

nn_params = [Theta1(:) ; Theta2(:)];     

lambda = 0;


J = nnCostFunction(nn_params, input_layer_size, hidden_layer_size, ...

                   num_labels, X, y, lambda)


   결과 값은 다음과 같습니다.

J =  0.28763





매거진의 이전글 머신러닝 옥타브 실습 (3-3) : 손글씨 숫자 인식
작품 선택
키워드 선택 0 / 3 0
댓글여부
afliean
브런치는 최신 브라우저에 최적화 되어있습니다. IE chrome safari