trybeetle

take it slow!!

Cross Validation と Learning curve


Posted on July 25, 2018, 9:46 p.m.



Cross Validation と Learning curveについて記載します。
CourseraのMachine Learningコースを元にしています。

Datasetが100あり、Training用、Cross Validation用、Test用と分けて使う場合は、60:20:20の割合に分けて使用します。
※この時Datasetからrandomに取り出す様にします。一度目のDatasetの分割でTraining1⇒CrossValidation1⇒Test1と計算が完了したら、再度Datasetからrandomに各datasetを取り出し、同様に計算を実行することで精度を上げます。

流れとしては、下記のとおりです。

  • training用dataで重みThetaの値を求める
  • validation用dataで↑で求めたThetaの値を使い、コストJを算出する
  • 算出されたグラフを見て、biasに問題があるか、varianceに問題があるか判断する。

Datasetの読み込み

まずは、データを読み込みます。今回のデータはX1とyのみのデータでhypothesisはpolynomial(多項式)なものを想定しています。loadすることで、X, y, Xval, yval, Xtest, ytestまでを設定してくれます。


    load ('ex5data1.mat');
    m = size(X, 1);

続いて、polynomialな計算式をhypothesisとして定義します。
まずは、下記のようにPolynomialにするための関数とNormalizationのための関数を用意します。


    function [X_poly] = polyFeatures(X, p)
    for i = 1:p
        X_poly(:,i) = X.^i;
    endfor;
    end

    function [X_norm, mu, sigma] = featureNormalize(X)
    mu = mean(X);
    X_norm = bsxfun(@minus, X, mu);
    sigma = std(X_norm);
    X_norm = bsxfun(@rdivide, X_norm, sigma);
    end

training用、CrossValidation用、Test用それぞれのデータに対しNormalizationまで行います。


    p = 8;

    % Map X onto Polynomial Features and Normalize
    X_poly = polyFeatures(X, p);
    [X_poly, mu, sigma] = featureNormalize(X_poly);  % Normalize
    X_poly = [ones(m, 1), X_poly];                   % Add Ones

    % Map X_poly_test and normalize (using mu and sigma)
    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];         % Add Ones

    % Map X_poly_val and normalize (using mu and sigma)
    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];           % Add Ones

Cost関数の定義

今回のcost関数は下記の様に2乗誤差で定義します。


    function [J, grad] = linearRegCostFunction(X, y, theta, lambda)
    m = length(y); % number of training examples
    J = 0;
    grad = zeros(size(theta));
    mask = ones(size(theta));
    mask(1) = 0;

    h_theta = X * theta;
    Jreg = lambda/(2*m) * ((theta .* mask)' * (theta .* mask));
    J = 1/(2*m) * sum((h_theta - y).^2) + Jreg;

    gradreg = lambda/m * (theta .* mask);
    grad = 1/m * ((h_theta - y)' * X)' + gradreg;

    end

Learning Curveの算出

まず、θの最適解を求めるため、gradient実行のための関数を用意します。


    function [theta] = trainLinearReg(X, y, lambda)
    initial_theta = zeros(size(X, 2), 1);
    costFunction = @(t) linearRegCostFunction(X, y, t, lambda);
    options = optimset('MaxIter', 200, 'GradObj', 'on');
    theta = fmincg(costFunction, initial_theta, options);
    end

gradientを実行し、thetaを求めます。


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

Learning curve用の関数を定義します。


    function [error_train, error_val] = learningCurve(X, y, Xval, yval, lambda)
    m = size(X, 1);
    error_train = zeros(m, 1);
    error_val   = zeros(m, 1);
    for i = 1:m
        X_train = X(1:i, :);
        y_train = y(1:i);
        theta = trainLinearReg(X_train, y_train, lambda);
        error_train(i) = linearRegCostFunction(X_train, y_train, theta, 0);
        error_val(i) = linearRegCostFunction(Xval, yval, theta, 0);
    endfor;
    end

Learning curveをplotします。また、trainingとcvのerror値も出力します。


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

    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')

    % display the training and cv error
    fprintf('Polynomial Regression (lambda = %f)\n\n', lambda);
    fprintf('# Training Examples\tTrain Error\tCross Validation Error\n');
    for i = 1:m
        fprintf('  \t%d\t\t%f\t%f\n', i, error_train(i), error_val(i));
    endfor

plotされたグラフを見て、biasに問題があるか、varianceに問題があるか判断します。
biasに問題があれば、featureを足してあげたり複雑化させる必要があります。
varianceに問題があれば、lambdaの値を上げたり、datasetを増やしてあげたりする必要があります。


Lambdaの最適値を求める

上記では、X軸に実行したdataset数を置きましたが、X軸にLamdaの値を置き、Y軸にはそのままコストを表示することで、Lamdaの最適値を求めることもできます。

まず、関数を定めます。下記の様に、lambdaを0~10の間で試行用の値を設定し、その値に応じたtraining時のコストとvalidation時のコストを求めます。


    function [lambda_vec, error_train, error_val] = validationCurve(X, y, Xval, yval)
    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);

    for i = 1:size(lambda_vec)
        lambda = lambda_vec(i);
        theta = trainLinearReg(X, y, lambda);
        J_train = linearRegCostFunction(X, y, theta, 0);
        error_train(i) = J_train;

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

validation curveをplotします。また、trainingとcvのerror値も出力します。


    [lambda_vec, error_train, error_val] = validationCurve(X_poly, y, X_poly_val, yval);

    plot(lambda_vec, error_train, lambda_vec, error_val);
    legend('Train', 'Cross Validation');
    xlabel('lambda');
    ylabel('Error');

    fprintf('lambda\t\tTrain Error\tValidation Error\n');
    for i = 1:length(lambda_vec)
    	fprintf(' %f\t%f\t%f\n', ...
                lambda_vec(i), error_train(i), error_val(i));
    end

validation errorが最小となるlambdaが最適値です。

以上になります。


Category:ML
Tag: ML Octave
July 25, 2018, 9:46 p.m.

Comments