brunch

You can make anything
by writing

C.S.Lewis

by 라인하트 Jan 20. 2021

머신러닝 옥타브 실습(5-3): 댐의 방수량 예측

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


Programming Exercise 5: 

Regularized Linear Regression and Bias v.s. Variance (정규화된 선형 회귀와 편향/분산)


3. Polynomial regression (다항 회귀)  


   The problem with our linear model was that it was too simple for the data and resulted in underfitting (high bias). In this part of the exercise, you will address this problem by adding more features.

   For use polynomial regression, our hypothesis has the form:


   Noticethatbydefiningx1 =(waterLevel),x2 =(waterLevel)2,...,xp = (waterLevel)p, we obtain a linear regression model where the features are the various powers of the original value (waterLevel).

   Now, you will add more features using the higher powers of the existing feature x in the dataset. Your task in this part is to complete the code in polyFeatures.m so that the function maps the original training set X of size m × 1 into its higher powers. Specifically, when a training set X of size m × 1 is passed into the function, the function should return a m×p matrix X poly, where column 1 holds the original values of X, column 2 holds the values of X.^2, column 3 holds the values of X.^3, and so on. Note that you don’t have to account for the zero-eth power in this function.

   Now you have a function that will map features to a higher dimension, and Part 6 of ex5.m will apply it to the training set, the test set, and the cross validation set (which you haven’t used yet).


   직선으로 구현한 선형 모델의 문제는 데이터와 달리 너무 단순하여 과소 적합 (높은 편향)을 초래하는 것입니다. 과소 적합 문제를 해결하기 위해 이번 실습은 더 많은 피처를 추가합니다.  다항 회귀의 피처는 다음과 같이 생성합니다.  


   x1 = 수위 

   x2 =  (수위)^2

   ...

   x3 = (수위)^p


   다수의 고차 다항식을 사용하는 다항 회귀 모델입니다. 기존 피처 x를 제곱하여 더 많은 피처를 추가합니다. 함수가 m X 1 크기의 학습 셋 X가 고차 다항식과 매핑하도록 polyfeatures.m코드를 완성합니다. 특히, 크기 m X 1 학습 셋 X는 m X p 차원의 X_poly 행렬을 반환합니다. 열 1은 X의 원래 값이고, 열 2는 X의 성분에^2이고, 열 3은 X.^3입니다. 이 함수에서 X.^0는 고려하지 않습니다. 

   더 높은 차원의 피처를 매핑하는 함수가 있고, ex5.m은 학습 셋과 교차 검증 셋에 적용합니다.


<해설 1: 피처를 확장하기>


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


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

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

clc                   % 터미널을 깨끗이 정리 


load ('ex5data1.mat');    % 옥타브 프로그램으로 데이터 업로드 

[m,n] = size(X);                % 학습 예제의 수와 피처의 수를 정의



(2) polyFeatures.m 파일 분석



function [X_poly] = polyFeatures(X, p)

%POLYFEATURES 데이터 X를 p의 제곱까지 매핑 

%   [X_poly] = POLYFEATURES(X, p)  m x 1차원 데이터 행렬 X를 다항 피처로 매칭

%                     X_poly(i, :) = [X(i) X(i).^2 X(i).^3 ...  X(i).^p];

%


% 반환할 변수 초기화.

X_poly = zeros(numel(X), p);


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

% Instructions: 벡터 X가 있을 때 X_poly를 반환  




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


end


(3) 다항 회귀를 위해 피처를 변환


   다항 회귀를 만들기 위해 피처 x를 1에서부터 8 제곱까지 확장하여 m X 8차원의 행렬을 생성합니다. 보통은 이중 For 루프를 사용하여 각 행렬 성분의 값을 생성하는 방식을 이용합니다. 


p = 8;


for i = 1:size(X,1)

   for j = 1:p

    X_poly1(i,j) = X(i,1).^j

    end

end


>> X_poly1

X_poly1 =

 Columns 1 through 5:

  -1.5937e+01   2.5398e+02  -4.0476e+03   6.4506e+04  -1.0280e+06

  -2.9153e+01   8.4990e+02  -2.4777e+04   7.2232e+05  -2.1058e+07

   3.6190e+01   1.3097e+03   4.7397e+04   1.7153e+06   6.2075e+07

   3.7492e+01   1.4057e+03   5.2701e+04   1.9759e+06   7.4080e+07

  -4.8059e+01   2.3097e+03  -1.1100e+05   5.3345e+06  -2.5637e+08

  -8.9415e+00   7.9950e+01  -7.1487e+02   6.3919e+03  -5.7153e+04

   1.5308e+01   2.3433e+02   3.5871e+03   5.4910e+04   8.4055e+05

  -3.4706e+01   1.2045e+03  -4.1805e+04   1.4509e+06  -5.0355e+07

   1.3892e+00   1.9297e+00   2.6807e+00   3.7239e+00   5.1731e+00

  -4.4384e+01   1.9699e+03  -8.7432e+04   3.8806e+06  -1.7223e+08

   7.0135e+00   4.9189e+01   3.4499e+02   2.4196e+03   1.6970e+04

   2.2763e+01   5.1814e+02   1.1794e+04   2.6847e+05   6.1112e+06


 Columns 6 through 8:

   1.6383e+07  -2.6110e+08   4.1610e+09

   6.1390e+08  -1.7897e+10   5.2175e+11

   2.2465e+09   8.1298e+10   2.9422e+12

   2.7774e+09   1.0413e+11   3.9041e+12

   1.2321e+10  -5.9212e+11   2.8457e+13

   5.1103e+05  -4.5694e+06   4.0857e+07

   1.2867e+07   1.9696e+08   3.0151e+09

   1.7476e+09  -6.0653e+10   2.1051e+12

   7.1863e+00   9.9828e+00   1.3868e+01

   7.6444e+09  -3.3929e+11   1.5059e+13

   1.1902e+05   8.3473e+05   5.8544e+06

   1.3911e+08   3.1665e+09   7.2077e+10


   또 다른 방법은 행렬을 이용하는 방법입니다. For 루프를 한 번만 사용합니다.


p = 8;


for j = 1: p

    X_poly2 (:,j)=  X.^j

end


>> X_poly2

X_poly2 =

 Columns 1 through 5:

  -1.5937e+01   2.5398e+02  -4.0476e+03   6.4506e+04  -1.0280e+06

  -2.9153e+01   8.4990e+02  -2.4777e+04   7.2232e+05  -2.1058e+07

   3.6190e+01   1.3097e+03   4.7397e+04   1.7153e+06   6.2075e+07

   3.7492e+01   1.4057e+03   5.2701e+04   1.9759e+06   7.4080e+07

  -4.8059e+01   2.3097e+03  -1.1100e+05   5.3345e+06  -2.5637e+08

  -8.9415e+00   7.9950e+01  -7.1487e+02   6.3919e+03  -5.7153e+04

   1.5308e+01   2.3433e+02   3.5871e+03   5.4910e+04   8.4055e+05

  -3.4706e+01   1.2045e+03  -4.1805e+04   1.4509e+06  -5.0355e+07

   1.3892e+00   1.9297e+00   2.6807e+00   3.7239e+00   5.1731e+00

  -4.4384e+01   1.9699e+03  -8.7432e+04   3.8806e+06  -1.7223e+08

   7.0135e+00   4.9189e+01   3.4499e+02   2.4196e+03   1.6970e+04

   2.2763e+01   5.1814e+02   1.1794e+04   2.6847e+05   6.1112e+06


 Columns 6 through 8:

   1.6383e+07  -2.6110e+08   4.1610e+09

   6.1390e+08  -1.7897e+10   5.2175e+11

   2.2465e+09   8.1298e+10   2.9422e+12

   2.7774e+09   1.0413e+11   3.9041e+12

   1.2321e+10  -5.9212e+11   2.8457e+13

   5.1103e+05  -4.5694e+06   4.0857e+07

   1.2867e+07   1.9696e+08   3.0151e+09

   1.7476e+09  -6.0653e+10   2.1051e+12

   7.1863e+00   9.9828e+00   1.3868e+01

   7.6444e+09  -3.3929e+11   1.5059e+13

   1.1902e+05   8.3473e+05   5.8544e+06

   1.3911e+08   3.1665e+09   7.2077e+10


  두 방식 중에 단순한 방법을 선택합니다.  



<정답>


function [X_poly] = polyFeatures(X, p)

%POLYFEATURES 데이터 X를 p의 제곱까지 매핑 

%   [X_poly] = POLYFEATURES(X, p)  m x 1차원 데이터 행렬 X를 다항 피처로 매칭

%                     X_poly(i, :) = [X(i) X(i).^2 X(i).^3 ...  X(i).^p];

%


% 반환할 변수 초기화.

X_poly = zeros(numel(X), p);


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

% Instructions: 벡터 X가 있을 때 X_poly를 반환  


for j = 1: p

    X_poly (:,j)=  X.^j

end



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


end


<결과 확인>






3.1 Learning Polynomial Regression (다항 회귀 학습하기)


   After you have completed polyFeatures.m, the ex5.m script will proceed to train polynomial regression using your linear regression cost function.

   Keep in mind that even though we have polynomial terms in our feature vector, we are still solving a linear regression optimization problem. The polynomial terms have simply turned into features that we can use for linear regression. We are using the same cost function and gradient that you wrote for the earlier part of this exercise.

   For this part of the exercise, you will be using a polynomial of degree 8. It turns out that if we run the training directly on the projected data, will not work well as the features would be badly scaled (e.g., an example with x = 40 will now have a feature x8 = 408 = 6.5 × 1012). Therefore, you will need to use feature normalization.

   Before learning the parameters θ for the polynomial regression, ex5.m will first call featureNormalize and normalize the features of the training set, storing the mu, sigma parameters separately. We have already implemented this function for you and it is the same function from the first exercise.

   After learning the parameters θ, you should see two plots (Figure 4,5) generated for polynomial regression with λ = 0.

   From Figure 4, you should see that the polynomial fit is able to follow the datapoints very well - thus, obtaining a low training error. However, the polynomial fit is very complex and even drops off at the extremes. This is an indicator that the polynomial regression model is overfitting the training data and will not generalize well.

   To better understand the problems with the unregularized (λ = 0) model, you can see that the learning curve (Figure 5) shows the same effect where the low training error is low, but the cross validation error is high. There is a gap between the training and cross validation errors, indicating a high variance problem.

   One way to combat the overfitting (high-variance) problem is to add regularization to the model. In the next section, you will get to try different λ parameters to see how regularization can lead to a better model.


   PolyFeatures.m 파일은 m X 1 피처 벡터를  m X 8 피처 행렬로 변환하고, ex5.m 파일은 다항 회귀 비용 함수를 사용하여 다항 회귀를 훈련합니다. 

   피처 벡터에 다항식 항을 적용하더라도 선형 회귀 최적화 문제를 해결합니다. 다항식 항은 단순히 선형 회귀에 있는 피처로 전환하였습니다. 이전 실습에서 작성한 linearRegCostFunction.m 파일은 다항식 회귀에 대한 비용과 기울기를 계산합니다.  

   실습은 8차 다항식을 사용합니다. 데이터 값의 크기의 차이가 너무 크기 때문에 제대로 작동하지 않을 수 있습니다. (예를 들면, x1= 40인 피처와 x8 = 40^8 = 6.5 X 10^12) 그러므로 피처 정규화(feature Normalization)가 필요합니다. 

   다항 회귀에서 파라미터 θ를 학습하기 전에 ex5.m 파일은 featureNormailize.m 파일을 호출합니다. featureNoramilize.m 파일은 학습 셋의 피처 정규화를 수행하고, 평균 mu와 표준 편차 sigma를 함께 반환합니다. 피처 정규화는 첫 번째 실습에서 이미 구현했던  기능입니다.

   파라미터 θ를 학습한 후 λ = 0인 다항 회귀에 대해 생성한 두 개의 그림이 있습니다. 그림 4는 데이터 셋에 최적인 다항식 가설을 얻을 수 있고 매우 낮은 학습 오차를 유지합니다. 그러나 다항식 적합한 매우 복잡하고 학습 데이터 셋에 과적합한 상태이므로 일반화되지 않을 것입니다. 

   λ = 0 인 비정규화 모델을 더 잘 이해하기 위해 학습 곡선(그림 5)은 낮은 학습 오차를 가지지만 반대로 높은 교차 검증 오차를 가집니다. 학습 오차와 교차 검증 오차 사이의 차이가 크므로 분산 문제가 있다는 것을 나타냅니다.

   과적합(고분산) 문제를 해결하는 한 가지 방법은 모델을 정규화하는 것입니다. 다음 섹션에서 정규화가 어떻게 더 나은 모델을 만드는 지를 알아보기 위해 정규화 파라미터 λ의 값에 변화를 줄 것입니다. 





<해설 1 : 피처 스케일링>


   ex5.m 파일은 polyFeatures.m 파일을 활용해 m X 1 행렬을 m X 8 행렬로 늘립니다. 즉, 12 X 8 행렬이 됩니다.


p = 8;

X_poly = polyFeatures(X, p);


   그리고, featureNormalize.m 파일을 호출하여 Feature Nomailization을 수행합니다.


(1) featureNormalization.m 파일 분석


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

%FEATURENORMALIZE 데이터 행렬 X를 피처 스케일링  

%   FEATURENORMALIZE(X) 

%   각 피처의 평균 0 , 표준편차 1인 피처 스케일링한 버전을 반환

%   This is often a good preprocessing step to do when

%   working with learning algorithms.


mu = mean(X);

X_norm = bsxfun(@minus, X, mu);   % 행렬 X에서 평균 mu를 빼기


sigma = std(X_norm);

X_norm = bsxfun(@rdivide, X_norm, sigma);  



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


end


(2) bsxfun() 함수의 이해


   bsxfun() 함수는 행렬 연산에 사용하기 편리합니다. 행렬의 차원이 달라도 자동으로 열을 확산하여 계산합니다. 행렬의 열 단위로 평균을 구한 값을 모든 성분에 각각 빼려고 할 때 행렬 차원이 맞지 않습니다. 예를 들면, A는 3 X 3 차 행렬이고, mean(A)는 1 X 3차원 행 벡터입니다. 두 행렬을 빼면 mean(A) 행렬을 3 X 3차원 행렬로 변환하여 연산합니다. 이것이 bsxfun() 함수가 하는 역할입니다.  


>> A

A =

    1    2   10

    3    4   20

    9    6   15


>> mean(A)

ans =

    4.3333    4.0000   15.0000


>> A - mean(A)                   % 차원이 맞지 않아 오류가 발생하지만 확장하여 계산

warning: operator -: automatic broadcasting operation applied

ans =

  -3.33333  -2.00000  -5.00000

  -1.33333   0.00000   5.00000

   4.66667   2.00000   0.00000


>> bsxfun(@minus, A, mean(A))   % 오류 없이 확장하여 계산

ans =

  -3.33333  -2.00000  -5.00000

  -1.33333   0.00000   5.00000

   4.66667   2.00000   0.00000



  bszfun은 다양한 계산이 가능합니다.


plus           덧셈 (+)

minus       뺄셈 (-)

times        곱셈 (.*)

rdivide     나눗셈 (우측 행렬로 나누기) (./)

ldivide      나눗셈 (좌측 행렬로 나누기) (.\)

power       거듭제곱 (.^)

eq              같음 (==)

ne              같지 않음 (~=)

gt                보다 큼 (>)

ge               보다 크거나 같음 (>=)

lt                 보다 작음 (<)

le                 보다 작거나 같음 (<=)

max              최대값

min               최솟값

mod             나눗셈의 나머지

rem               나눗셈의 나머지



(3) 피처 스케일링 코드 작성


   피처 스케일링을 구하는 공식은 다음과 같습니다.

   공식을 행렬에 적용하기 위해 bsxfun() 함수를 사용합니다.


mu = mean(X);

sigma = std(X); 

X_norm =  bsxfun(@rdivide, bsxfun(@minus, X, mu), sigma)


옥타브에 다음과 같이 입력합니다.


>> mu = mean(X);

>> sigma = std(X);

>> X_norm =  bsxfun(@rdivide, bsxfun(@minus, X, mu), sigma)

X_norm =

  -0.36214

  -0.80320

   1.37747

   1.42094

  -1.43415

  -0.12869

   0.68058

  -0.98853

   0.21608

  -1.31150

   0.40378

   0.92938



(4) 데이터 행렬 X에 바이어스 항 추가 


   1로 구성된 바이어스 항을 추가합니다.


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



<해설 2 : 테스트 셋 / 교차 검증 셋에 적용하기>


   학습 셋에 적용한 것과 마찬가지로 테스트 셋에도 적용합니다. 적용하기 전에 정리합니다.


(1) 기본 변수 설정


clear;  close all; clc 


load ('ex5data1.mat');    

[m,n] = size(X);        


(2) 학습 셋에 대해 피처 확장, 피처 스케일링, 바이어스 항 추가


p = 8;

X_poly = polyFeatures(X, p);


[X_poly, mu, sigma] = featureNormalize(X_poly); 

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


(3) 테스트 셋에 대해  피처 확장, 피처 스케일링, 바이어스 항 추가


X_poly_test = polyFeatures(Xtest, p);                        

X_poly_test = bsxfun(@minus, X_poly_test, mu);        

X_poly_test = bsxfun(@rdivide, X_poly_test, sigma);    

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

    

(4) 교차 검증 셋에 대해  피처 확장, 피처 스케일링, 바이어스 항 추가


X_poly_val = polyFeatures(Xval, p);

X_poly_val = bsxfun(@minus, X_poly_val, mu);

X_poly_val = bsxfun(@rdivide, X_poly_val, sigma);

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

 

(5) 각 데이터 행렬 확인


>> whos

Variables in the current scope:


   Attr Name             Size                     Bytes  Class

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

        X                       12x1                         96  double

        X_poly             12x9                        864  double

        X_poly_test    21x9                       1512  double

        X_poly_val     21x9                       1512  double

        Xtest                21x1                        168  double

        Xval                  21x1                        168  double

        ans                   1x2                         16  double

        m                      1x1                          8  double

        mu                   1x8                         64  double

        n                      1x1                          8  double

        p                      1x1                          8  double

        sigma             1x8                         64  double

        y                      12x1                         96  double

        ytest               21x1                        168  double

        yval                21x1                        168  double


Total is 615 elements using 4920 bytes



<해설 3 : 도식화하기>


(1) 데이터 X를 도식화


   원래 데이터 X와 y를 도식화합니다. 데이터 시각화 부분에서 이미 다루었습니다.


plot(X, y, 'rx', 'MarkerSize', 5, 'LineWidth', 1.5);

xlabel('Change in water level (x)');

ylabel('Water flowing out of the dam (y)');



(2) 다항 회귀의 최적화된 파라미터 theta 계산


   파라미터 theta는 고급 최적화 알고리즘을 이용하는 fmincg() 함수가 계산합니다. fmincg() 함수는 비용을 나타내는 Cost와 기울기를 나타내는 grad 값이 필요하고, linearRegCostFunction.m 파일은 두 값을 반환합니다. 따라서, trainLinearReg() 함수를 호출하면 데이터에 최적인 theta를 반환합니다.


lambda = 0;

[theta] = trainLinearReg(X_poly, y, lambda);


(3) plotFit.m 파일 분석


function plotFit(min_x, max_x, mu, sigma, theta, p)

%PLOTFIT 기존 그래프에 학습한 다항 회귀를 도식화 

%  

%   PLOTFIT(min_x, max_x, mu, sigma, theta, p) 

%   피처를 다항식으로 확장하고 피처 정규화(mu, sigma)로 수행한 다항식을 확장 


% 기존 그림 위에 도식화

hold on;


% 최소값 및 최대값보다 약간 더 크게 도식화하기 위해 최소와 최대값에 약간의 값을 추가 

x = (min_x - 15: 0.05 : max_x + 25)';


% X를 다항식으로 확대하고 피처 정규화를 수행  

X_poly = polyFeatures(x, p);

X_poly = bsxfun(@minus, X_poly, mu);

X_poly = bsxfun(@rdivide, X_poly, sigma);


% 바이어스 항을 추가

X_poly = [ones(size(x, 1), 1) X_poly];


% Plot

plot(x, X_poly * theta, '--', 'LineWidth', 2)


% 현재 그림에 작성을 중지

hold off


end


(4) 학습 데이터에 적합한 다항 회귀 도식화


   plotFit.m 파일을 호출하여 그립니다. 


plotFit(min(X), max(X), mu, sigma, theta, p);



(5) 학습 곡선 도식화 


   이미 지난 실습에서 만들어는 learningCurve.m 파일을 호출하여 그림을 그립니다. 


[error_train, error_val] = learningCurve(X_poly, y, X_poly_val, yval, lambda);


figure(3);

plot(1:m, error_train, 1:m, error_val);




title(sprintf('Polynomial Regression Learning Curve (lambda = %f)', lambda));

xlabel('Number of training examples')

ylabel('Error')

axis([0 13 0 100])

legend('Train', 'Cross Validation')




3.2 Optional (ungraded) exercise: Adjusting the regularization parameter (옵션 실습 : 정규화 파라미터 조정하기)


   In this section, you will get to observe how the regularization parameter affects the bias-variance of regularized polynomial regression. You should now modify the the lambda parameter in the ex5.m and try λ = 1, 100. For each of these values, the script should generate a polynomial fit to the data and also a learning curve.

   For λ = 1, you should see a polynomial fit that follows the data trend well (Figure 6) and a learning curve (Figure 7) showing that both the cross validation and training error converge to a relatively low value. This shows the λ = 1 regularized polynomial regression model does not have the high- bias or high-variance problems. In effect, it achieves a good trade-off between bias and variance.

   For λ = 100, you should see a polynomial fit (Figure 8) that does not follow the data well. In this case, there is too much regularization and the model is unable to fit the training data.


   이번 실습은 정규화 파라미터 λ가 정규화된 다항 회귀의 편향과 분산에 어떤 영향을 미치는 지를 점검합니다. ex5.m 파일은 정규화 파라미터 λ의 값을  lamda =1과 lamda = 100로 수정합니다. lambda의 값에 따른 다항식 피팅과 학습곡선을 작성합니다. 

    λ = 1일 때 데이터의 그림 6과 같은 가설이 만들어지고 그림 7과 같이 교차 검증 오차와 학습 오차가 모두 상대적으로 낮은 값으로 수렵합니다. λ = 1 정규화된 다항 회귀 모델은 고 편향 또는 고 분산 문제가 없습니다. 실제로 편향과 분산 사이에 적절한 균현을 이룹니다. 

   λ = 100일 때 그림 8과 같이 데이터를 잘 따르지 않는 다항식 모델이 만들어 만들어집니다. 정규화가 너무 튼 값이어서 모델이 학습 데이터에 적합하지 않습니다. 




<해설 : λ = 1 >


(1) 기본 변수 설정


clear;  close all; clc 


load ('ex5data1.mat');    

[m,n] = size(X);        


(2) 데이터 X 도식화 


plot(X, y, 'rx', 'MarkerSize', 5, 'LineWidth', 1.5);

xlabel('Change in water level (x)');

ylabel('Water flowing out of the dam (y)');


(3) 다항 회귀 가설 도식화

 

   데이터 적합한 다항 회귀 가설을 그립니다. 우선 다항 회귀식을 만들고, 피처 정규화를 하고, 데이터에 적합한 파라미터 theta를 찾은 후에 도식화합니다. 


lambda = 0;


p=8;


X_poly = polyFeatures(X, p);

[X_poly, mu, sigma] = featureNormalize(X_poly);

[theta] = trainLinearReg([ones(m,1) X_poly], y, lambda);


plotFit(min(X), max(X), mu, sigma, theta, p);



(4) 학습 곡선 도식화 


   학습 곡선을 그립니다.  우선 교차 검증 셋에 대한 다항 회귀식을 만들고, 피처 정규화를 합니다. 


X_poly_val = polyFeatures(Xval, p);

X_poly_val = bsxfun(@minus, X_poly_val, mu);

X_poly_val = bsxfun(@rdivide, X_poly_val, sigma);

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


   학습 곡선을 그리기 위한 오차를 계산합니다. 


lambda = 0;

[theta] = trainLinearReg(X_poly, y, lambda);


[error_train, error_val] = learningCurve(X_poly, y, X_poly_val, yval, lambda);

plot(1:m, error_train, 1:m, error_val);



hold on


title(sprintf('Polynomial Regression Learning Curve (lambda = %f)', lambda));

xlabel('Number of training examples')

ylabel('Error')

axis([0 13 0 100])

legend('Train', 'Cross Validation')



<해설 : λ = 100 >


(1) 기본 변수 설정


clear;  close all; clc 


load ('ex5data1.mat');    

[m,n] = size(X);        


(2) 데이터 X 도식화 


plot(X, y, 'rx', 'MarkerSize', 5, 'LineWidth', 1.5);

xlabel('Change in water level (x)');

ylabel('Water flowing out of the dam (y)');


(3) 다항 회귀 가설 도식화

 

   데이터 적합한 다항 회귀 가설을 그립니다. 우선 다항 회귀식을 만들고, 피처 정규화를 하고, 데이터에 적합한 파라미터 theta를 찾은 후에 도식화합니다. 


lambda = 100;


p=8;


X_poly = polyFeatures(X, p);

[X_poly, mu, sigma] = featureNormalize(X_poly);

[theta] = trainLinearReg([ones(m,1) X_poly], y, lambda);


plotFit(min(X), max(X), mu, sigma, theta, p);




(4) 학습 곡선 도식화 


   학습 곡선을 그립니다.  우선 교차 검증 셋에 대한 다항 회귀식을 만들고, 피처 정규화를 합니다. 



X_poly_val = polyFeatures(Xval, p);

X_poly_val = bsxfun(@minus, X_poly_val, mu);

X_poly_val = bsxfun(@rdivide, X_poly_val, sigma);



   학습 곡선을 그리기 위한 오차를 계산합니다. 


[error_train, error_val] = learningCurve(X_poly, y, X_poly_val, yval, lambda);


plot(1:m, error_train, 1:m, error_val);

hold on


title(sprintf('Polynomial Regression Learning Curve (lambda = %f)', lambda));

xlabel('Number of training examples')

ylabel('Error')

axis([0 13 0 100])

legend('Train', 'Cross Validation')



3.3 Selecting λ using a cross validation set

         (교차 검증 셋을 사용하여 정규화 파라미터  λ 선택하기)


   From the previous parts of the exercise, you observed that the value of λ can significantly affect the results of regularized polynomial regression on the training and cross validation set. In particular, a model without regular- ization (λ = 0) fits the training set well, but does not generalize. Conversely, a model with too much regularization (λ = 100) does not fit the training set and testing set well. A good choice of λ (e.g., λ = 1) can provide a good fit to the data.

   In this section, you will implement an automated method to select the λ parameter. Concretely, you will use a cross validation set to evaluate how good each λ value is. After selecting the best λ value using the cross validation set, we can then evaluate the model on the test set to estimate how well the model will perform on actual unseen data.

   Your task is to complete the code in validationCurve.m. Specifically,
you should should use the trainLinearReg function to train the model using different values of λ and compute the training error and cross validation error. You should try λ in the following range: {0, 0.001, 0.003, 0.01, 0.03, 0.1, 0.3, 1, 3, 10}.

   After you have completed the code, the next part of ex5.m will run your function can plot a cross validation curve of error v.s. λ that allows you select which λ parameter to use. You should see a plot similar to Figure 9. In this figure, we can see that the best value of λ is around 3. Due to randomness in the training and validation splits of the dataset, the cross validation error can sometimes be lower than the training error.


   정규화 파라미터 lambda(λ) 값이 학습 및 교차 검증 세트에 대한 정규화된 다항식 회귀에 상당한 영향을  미칩니다.  


   정규화가 없는 모델 (λ = 0)는 학습 셋에 적합하지만 일반화하지 않습니다. 

   정규화가 너무 높은 모델 (λ = 100)은 학습 셋과 테스트 셋에 적합하지 않습니다. 

   좋은 정규화가 적용된 모델 (λ = 1)은 데이터에 적합하고 일반화가 달 됩니다.


   이번 실습에서 정규화 파라미터 λ를 선택하는 자동화된 방법을 구현합니다. 구체적으로 교차 검증 셋에서 λ값이 얼마나 좋은 지를 평가합니다. 교차 검증 셋에서 최상의 λ값을 선택한 후에 테스트 셋에서 모델을 평가하여 실제 보이지 않는 데이터에서 모델이 얼마나 잘 수행되는 지를 추정합니다. 

   validationCurve.m 파일의 코드를 완성합니다. trainLinearReg() 함수를 사용하여 여러 가지 λ값을 사용하여 모델을 훈련하고 학습 오차 및 교차 검증 오류를 계산합니다. 다음 범위의 λ 값에서 실행합니다.

  {0, 0.001, 0.003, 0.01, 0.03, 0.1, 0.3, 1, 3, 10}.

   코드를 완료하면 ex5.m 파일을 실행하고 오차 대 오차 교차 검증 곡선을 그립니다. 사용할 정규화 파라미터 lamda를 선택합니다. 그림에서 최적의 lambda 값은 3입니다.  그림 9와 같은 유사한 플롯이 표시됩니다. 데이터 셋의 훈련 및 교차 검증 셋이 무작위로 생성되므로 교차 검증 오류가 때때로 학습 오차보다 낮을 수 있습니다.



<해 >


(1) 기본 변수 설정


clear;  close all; clc 


load ('ex5data1.mat');    

[m,n] = size(X);        



(2) validationCurve.m 파일 분석


function [lambda_vec, error_train, error_val] = validationCurve(X, y, Xval, yval)

%VALIDATIONCURVE 학습 오차와 교차 검증 오차를 생성 

%.   lambda를 선택할 수 있는 교차 검증 곡선을 도식화 

%   [lambda_vec, error_train, error_val] = VALIDATIONCURVE(X, y, Xval, yval) returns the train

%       lambda 값에 따른 학습 오차 (error_train)와 검증 오차 ( error_val)를 반환

%      학습 셋(X, y)과 교차 검증 셋 (Xval, yval)


% lambda_vec 초기화 (값 변경 불가) 

lambda_vec = [0 0.001 0.003 0.01 0.03 0.1 0.3 1 3 10]';


% 반환할 변수 초기화

error_train = zeros(length(lambda_vec), 1);

error_val = zeros(length(lambda_vec), 1);


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

% Instructions: Fill in this function to return training errors in 

%               lambda 값에 따른 학습 오차 (error_train)와 검증 오차 ( error_val)를 반환

%               lambda_vec 오차를 계산하기 위해 정규화 파라미터 lambda 값을 포함 

%               (예,    lambda = lambda_vec(i) 일 때  error_train(i)와 error_val(i) 값을 계산 

%             

% Note: 

%            lambda_vec을 루프로 구현

%

%       for i = 1:length(lambda_vec)

%           lambda = lambda_vec(i);

%           %  정규화 파라미터 lambda에 대한 학습 및 교차 검증 오차를 계산 

%           %  error_train(i)과 error_val(i) 값을 저장

%           ....

%       end







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


end


(3) 정규화 파라미터 lambda의 값의 변화에 theta를 계산


ex5.m 파일은 직접 다항 회귀의 학습 셋 (X_poly, y)와 교차 검증 셋 (X_poly_val, yval)를  전달합니다. 따라서, validationCurve.m 파일은 lambda 값에 따른 에러 값을 반환합니다.


우선은 각 lambda에 따른 학습 셋에 최적화된 파라미터 theta를 계산합니다. 


lambda_vec = [0 0.001 0.003 0.01 0.03 0.1 0.3 1 3 10];


for i = 1:length(lambda_vec)

       lambda = lambda_vec(i);

       theta = trainLinearReg(X_poly, y, lambda);

end


옥타브 프로그램에 입력하여 정상 동작하는 것을 확인합니다. 


>> lambda_vec = [0 0.001 0.003 0.01 0.03 0.1 0.3 1 3 10];

>> for i = 1:length(lambda_vec)

       lambda = lambda_vec(i);

       theta = trainLinearReg(X_poly, y, lambda);

end

Iteration   200 | Cost: 6.300295e+01

Iteration   200 | Cost: 6.311299e+01

Iteration   200 | Cost: 6.315346e+01

Iteration   200 | Cost: 6.323875e+01

Iteration   200 | Cost: 6.338412e+01

Iteration   159 | Cost: 6.369470e+01

Iteration    91 | Cost: 6.426874e+01

Iteration    62 | Cost: 6.560415e+01

Iteration    47 | Cost: 6.793511e+01

Iteration    39 | Cost: 7.186087e+01


>> theta

theta =


   1.3427e+01

   2.3808e+00

   5.4533e-02

   1.4948e+00

   2.4373e-02

   9.2453e-01

   3.1551e-03

   5.6733e-01


>>


(4) 학습 오차와 교차 검증 오차를 계산  


lambda_vec = [0 0.001 0.003 0.01 0.03 0.1 0.3 1 3 10];


for i = 1:length(lambda_vec)

       lambda = lambda_vec(i);

       theta = trainLinearReg(X_poly, y, lambda);

         error_train(i) = linearRegCostFunction(X_poly, y, theta, 0);

         error_val(i) = linearRegCostFunction(X_poly_val, yval, theta, 0);

end


옥타브 프로그램에 입력하여 정상 동작하는 것을 확인합니다. 


>> for i = 1:length(lambda_vec)

       lambda = lambda_vec(i);

         error_train(i) = linearRegCostFunction);

ambda);  error_val(i) = linearRegCostFunctionon(X_poly, y, theta, la

ta, lambda);or_val(i) = linearRegCostFunction(X_poly_val, yval, thet

end

Iteration   200 | Cost: 6.300295e+01

Iteration   200 | Cost: 6.311299e+01

Iteration   200 | Cost: 6.315346e+01

Iteration   200 | Cost: 6.323875e+01

Iteration   200 | Cost: 6.338412e+01

Iteration   159 | Cost: 6.369470e+01

Iteration    91 | Cost: 6.426874e+01

Iteration    62 | Cost: 6.560415e+01

Iteration    47 | Cost: 6.793511e+01

Iteration    39 | Cost: 7.186087e+01


>> error_train

error_train =

   63.003

   63.113

   63.153

   63.239

   63.384

   63.695

   64.269

   65.604

   67.935

   71.861

   77.195

   77.881


>> error_val

error_val =

    79.637

   101.067

    99.499

    95.915

    90.209

    83.970

    79.811

    77.525

    78.287

    82.848

    96.486

    96.516


(5) lambda에 따른 학습 곡선 도식화


close all;


plot(lambda_vec, error_train, lambda_vec, error_val);

legend('Train', 'Cross Validation');

xlabel('lambda');

ylabel('Error');



lambda          Train Error     Validation Error

 0.000000       0.138384        18.559978

 0.001000       0.181198        20.463231

 0.003000       0.177951        18.555162

 0.010000       0.222659        17.166791

 0.030000       0.281857        12.830329

 0.100000       0.459318        7.587014

 0.300000       0.921760        4.636833

 1.000000       2.076188        4.260625

 3.000000       4.901351        3.822907

 10.000000      16.092213       9.945508



<정답>


function [lambda_vec, error_train, error_val] = validationCurve(X, y, Xval, yval)

%VALIDATIONCURVE 학습 오차와 교차 검증 오차를 생성 

%.   lambda를 선택할 수 있는 교차 검증 곡선을 도식화 

%   [lambda_vec, error_train, error_val] = VALIDATIONCURVE(X, y, Xval, yval) returns the train

%       lambda 값에 따른 학습 오차 (error_train)와 검증 오차 ( error_val)를 반환

%      학습 셋(X, y)과 교차 검증 셋 (Xval, yval)


% lambda_vec 초기화 (값 변경 불가) 

lambda_vec = [0 0.001 0.003 0.01 0.03 0.1 0.3 1 3 10]';


% 반환할 변수 초기화

error_train = zeros(length(lambda_vec), 1);

error_val = zeros(length(lambda_vec), 1);


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

% Instructions: Fill in this function to return training errors in 

%               lambda 값에 따른 학습 오차 (error_train)와 검증 오차 ( error_val)를 반환

%               lambda_vec 오차를 계산하기 위해 정규화 파라미터 lambda 값을 포함 

%               (예,    lambda = lambda_vec(i) 일 때  error_train(i)와 error_val(i) 값을 계산 

%             

% Note: 

%            lambda_vec을 루프로 구현

%

%       for i = 1:length(lambda_vec)

%           lambda = lambda_vec(i);

%           %  정규화 파라미터 lambda에 대한 학습 및 교차 검증 오차를 계산 

%           %  error_train(i)과 error_val(i) 값을 저장

%           ....

%       end



for i = 1:length(lambda_vec)

       lambda = lambda_vec(i);

       theta = trainLinearReg(X, y, lambda);

         error_train(i) = linearRegCostFunction(X, y, theta, 0);

         error_val(i) = linearRegCostFunction(Xval, yval, theta, 0);

end



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


end


<결과 확인>




매거진의 이전글 머신러닝 옥타브 실습(5-2): 댐의 방수량 예측
브런치는 최신 브라우저에 최적화 되어있습니다. IE chrome safari