티스토리 뷰

이 주에는 Data의 Classification문제를 다룬다. 내용 참고는 wiki docs에서 하는게 좋다. (https://wikidocs.net/book/587)한글 자막 없는 강의도 있고 사실 강의를 듣는거보다 wiki docs를 읽는게 영어 못하는 우리의 입장에서는 더 잘 이해가 된다. 이번 거는 내용 이해가 진짜 중요하다. 내용 잘 이해하고 과제를 풀어보도록 하자.

나같이 똑똑하지 않은 사람들에게 팁을 주자면 옆에 종이든 뭐든 메모할 수 있는 것을 놓고 풀어보자.. 행렬 연산은 복잡하니까 그냥 암산으로 척척!하기가 힘들다.. 물론 똑똑한 사람들은 잘 한다.

아 그냥 5개 채우면 되겠구나, 그리고 읽어보면 ex2.m이랑 ex2_reg.m이 메인 실행파일인 것 같다. 아마 reg가 붙은 건 regularization을 했다는 거겠지, 본론으로 넘어가자

(1)PlotData.m

ex2.m을 보면 PlotData()함수를 이용해 Data plot을 한다. 아무래도 기본 Plot함수를 여러 번 써야하다보니 그냥 다른 함수 파일로 기능화한것 같다. 별로 어려운 함수는 아니다. 근데, 이 pdf파일에서 제시하는 방법을 보면 find()함수를 쓰고 있다. 이 함수가 꽤나 유용해서 기억하면 좋을 것 같다. 해당 matrix에 대한 조건 제시문을 함수의 인수로 전달받아 만족하는 행의 index n개를 n*1행렬로 반환하는 함수인데, 이 함수에서는 다음과 같이 활용되었다.

function plotData(X, y)
%PLOTDATA Plots the data points X and y into a new figure 
%   PLOTDATA(x,y) plots the data points with + for the positive examples
%   and o for the negative examples. X is assumed to be a Mx2 matrix.

% Create New Figure
figure; hold on;

% ====================== YOUR CODE HERE ======================
% Instructions: Plot the positive and negative examples on a
%               2D plot, using the option 'k+' for the positive
%               examples and 'ko' for the negative examples.
%
posi=find(y==1);
nega=find(y==0);
plot(X(posi,1),X(posi,2),'k+');
plot(X(nega,1),X(nega,2),'ko');

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



hold off;

end

for문과if문으로 돌릴 필요 없이 코드가 깔끔해지니까 잘 써먹도록 하자. 나는 뒤의 예제에서도 잘 썼다.

(2) sigmoid.m

별로 안 어렵다. 주어진 값 z에 대해 1/(1+e^-z)를 반환하는 함수다. 단, z가 행렬일 때 함수의 반환 값도 행렬이어야 하므로 그것을 조금 고려해서 .연산을 써야한다. 밑은 코드다.

function g = sigmoid(z)
%SIGMOID Compute sigmoid function
%   g = SIGMOID(z) computes the sigmoid of z.

% You need to return the following variables correctly 
g = zeros(size(z));

% ====================== YOUR CODE HERE ======================
% Instructions: Compute the sigmoid of each value of z (z can be a matrix,
%               vector or scalar).
g=1./(1+exp(-z));


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

end

./연산을 주의해서 보면 된다. 처음에는 상수에 대한 나눗셈이라 걍 /로 될 줄 알았는데 제수항이 행렬이다 보니 ./로 나눠야 하나 보다. 만약 행렬을 상수로 나누는 경우에는 그냥 /로 나누면 상식적인 연산이 수행된다.

근데 예제 구현에서 좀 궁금했던 점은 h를 그냥 모듈로 구현했으면 후의 코드가 상당히 짧아질텐데 왜 그렇게하지 않았는지다. 뒤의 코드가 sigmoid에 넣을게 좀 많아지거든,,

(3) Costfunction.m

function [J, grad] = costFunction(theta, X, y)
%COSTFUNCTION Compute cost and gradient for logistic regression
%   J = COSTFUNCTION(theta, X, y) computes the cost of using theta as the
%   parameter for logistic regression and the gradient of the cost
%   w.r.t. to the parameters.

% Initialize some useful values
m = length(y); % number of training examples

% You need to return the following variables correctly 
J = 0;
grad = zeros(size(theta));
% ====================== YOUR CODE HERE ======================
% Instructions: Compute the cost of a particular choice of theta.
%               You should set J to the cost.
%               Compute the partial derivatives and set grad to the partial
%               derivatives of the cost w.r.t. each parameter in theta
for i=1:m
    J=J-(y(i)*log(sigmoid(X(i,:)*theta))+(1-y(i))*log(1-sigmoid(X(i,:)*theta)));
    grad=grad+(sigmoid(X(i,:)*theta)-y(i)).*X(i,:)';
end
J=J/m;
grad=grad/m;
% Note: grad should have the same dimensions as theta









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

end

주어진 값에 대해 Cost와 Grad를 계산하는 함수다. 오해하면 안 되는 것은 Gradient Descent를 하는 함수가 아니라 그냥 단순히 계산만 하는 함수라는 것이다. 따라서 PDF에 있는 두개의 식을 그냥 구현해주면 된다. sigmoid(X(i,:)*theta) 이게 h함수를 그대로 쓴건데 좀 어렵게 느껴질 수도 있을 듯. X(i,:)*theta가 식의 theta^t*x^i다.

그리고 이렇게 굳이 for문으로 안 돌리고 아름답게(?) 행렬 연산으로 쓸 수도 있는데 그건 밑의 CostfunctionReg.m에서 그런 방법으로 구현하였다. 깔끔하고 예쁘긴 한데 남이 알아보긴 어렵다. 그리고 솔직히 하는 연산의 횟수는 Big-Oh로 치면 똑같은데 더 빠른지도 잘 모르겠다 ㅋㅋ (병렬연산은 직렬연산 여러번보다 더 빠른가? 하드웨어맹이라 알 수 없다.)

(4) Predict.m

function p = predict(theta, X)
%PREDICT Predict whether the label is 0 or 1 using learned logistic 
%regression parameters theta
%   p = PREDICT(theta, X) computes the predictions for X using a 
%   threshold at 0.5 (i.e., if sigmoid(theta'*x) >= 0.5, predict 1)
m = size(X, 1); % Number of training examples
% You need to return the following variables correctly
p = zeros(m, 1);
% ====================== YOUR CODE HERE ======================
% Instructions: Complete the following code to make predictions using
%               your learned logistic regression parameters. 
%               You should set p to a vector of 0's and 1's
%
p(find(sigmoid(X*theta)>=0.5))=1;
% =========================================================================


end

주어진 theta와 X에 대해서 그 값이 0.5이상이면 1로, 0.5미만이면 0으로 판단하여 반환하는 함수를 만들면 된다.

find함수를 잘 써서 한 줄로 구현 가능하다. 물론 여러줄로 하나 한 줄로 하나 뭐 비슷하다. 그래도 한 줄로 쓰면 기분좋으니까 짧게 써봤다. 기본적으로 zeros행렬이니까 1인 부분만 채워도 돼서 한 줄로 썼다.

(5) CostfunctionReg.m--------------*

코드부터 보자. 설명은 귀찮다. 그냥 식을 구현하면 된다.

function [J, grad] = costFunctionReg(theta, X, y, lambda)

m = length(y); % number of training examples
J = 0;
grad = zeros(size(theta));

for i=1:m
     J=J-(y(i)*log(sigmoid(X(i,:)*theta))+(1-y(i))*log(1-sigmoid(X(i,:)*theta)));
end
J=J+theta(2:size(theta))'*theta(2:size(theta))/2*lambda;
J=J/(m);
grad(1)=X(:,1)'*(sigmoid(X*theta)-y)/m;
grad(2:size(theta))=(X(:,2:size(theta))'*(sigmoid(X*theta)-y)+theta(2:size(theta))*lambda)/m;

end

grad는 for문 안 돌리고 매트랩스러운 계산을 해보려고 노력했다. grad(1)은 Reg를 적용하지 않으니까 따로 계산해주어야한다. 근데 내가 한 일주일 후에 보면 뭔 코드인지 모를 것 같다. 괜히 포문 돌려서 해도 되는 연산을 억지스럽게 포문 안 쓰고 하려니까 이렇게 된다.

댓글