trybeetle

take it slow!!

Neural Networkについて


Posted on July 22, 2018, 4:37 p.m.



Neural Networkの実施内容(octave)について記載します。
CourseraのMachine Learningコースを元にしています。

Neural Networkでは、Input layerとOutput layerの間にhidden layerが入ります。Hidden layerが入ることにより、binary classificationの場合には、XORやXNORを表現することができ、より意図した境界線を表現することができます。
hidden layerの数に応じて、重みの値θの階層も増えます。複数の階層のθの最適解を求めるために、FeedForward propagationの後に、Backward propagationを使用して算出します。


トレーニングデータの読み込み

まずは、パラメータの値(各レイヤーのunit数)を設定します。ここでは、3層レイヤーとし、input layerのunit数を400,、hidden layerのunit数を25、output layerのunit数を10とします。


    input_layer_size  = 400;  % 20x20 Input Images of Digits
    hidden_layer_size = 25;   % 25 hidden units
    num_labels = 10;          % 10 labels, from 1 to 10

続いて、courseraのコースで、トレーニングデータとして、octaveの.matファイルが用意されているのでロードします。ロードにより、自動的に、featureのX matrixと、labelのy vectorが定義されます。ついでに、traning dataset数も求めます。


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

Xは、5000(traningSet数) * 400(feature数)のmatrixです。yは、5000(traningSet数)のベクトルで、label値には、1~10の値が格納されます。octaveでは、1から数字が始まるので、10の値は、digit 0を表現しています。


Thetaの初期化

Thetaの初期化を行います。Thetaをall 0と仮置きした場合、gradient descent実行時にupdateがされるたびにThetaが0のため、各layerのunitの値が同じままになってしまいます。そのため、Thetaの初期値は、ランダムな小さい値をとることとします。


    function W = debugInitializeWeights(fan_out, fan_in)
    W = zeros(fan_out, 1 + fan_in);
    W = reshape(sin(1:numel(W)), size(W)) / 10;
    end

    initial_Theta1 = randInitializeWeights(input_layer_size, hidden_layer_size);
    initial_Theta2 = randInitializeWeights(hidden_layer_size, num_labels);
    initial_nn_params = [initial_Theta1(:) ; initial_Theta2(:)];

Cost Functionの定義

まず、Cost functionを計算する際に、sigmoid関数とその微分を計算する必要があるため、下記に関数を定義します。


    function g = sigmoid(z)
    g = 1.0 ./ (1.0 + exp(-z));
    end

    function g = sigmoidGradient(z)
    g = zeros(size(z));
    g = sigmoid(z) .* (1 - sigmoid(z));
    end

下記に、CostFunction関数を定義します。fmincgを実行時に、このCostFunction関数を呼び出します。まずは、FeedForwardでoutputレイヤーまで算出します。その後、Backward propagationでdeltaの値を求めます。

  • FeedForwardでoutput layerの値a3を求める
  • delta3の値を求める(delta3はz3で微分したもの)
  • delta2の値も求める(delta2はz2で微分したもの)※delta1の値は、a1=Xでinputの値でz1はないので、求めない
  • Delta2の値を求める(Delta2はw2で微分したもの)※Chain ruleで求める※delta3を使う
  • Delta1の値を求める(Delta1はw1で微分したもの※Chain ruleで求める※delta2を使う
  • 上で求めたDeltaの値に対してtrainingdataset数mで割ってaverageを出す
  • 上記のDeltaのaverageの値を返り値として、Gradientで使用する

    function [J grad] = nnCostFunction(nn_params, input_layer_size, hidden_layer_size, num_labels, X, y, lambda)
    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));

    Y = zeros(m, num_labels);
    for i = 1:m
        Y(i, y(i)) = 1;
    endfor

    a1 = X;
    z2 = [ones(m, 1) a1] * Theta1';
    a2 = sigmoid(z2);
    z3 = [ones(m, 1) a2] * Theta2';
    a3 = sigmoid(z3);

    Jreg = lambda/(2*m) * (sum(sum(Theta1(:, 2:end).^2)) + sum(sum(Theta2(:, 2:end).^2)));
    J = 1/m * sum(sum(-Y .* log(a3) - (1 - Y) .* log(1 - a3))) + Jreg;

    delta3 = a3 - Y;

    delta2 = delta3 * Theta2(:, 2:end) .* sigmoidGradient(z2);

    Delta2 = delta3' * [ones(m,1) a2];
    Delta1 = delta2' * [ones(m,1) a1];

    Theta2_grad = 1/m * Delta2 + lambda / m * [zeros(size(Theta2), 1) Theta2(:, 2:end)];
    Theta1_grad = 1/m * Delta1 + lambda / m * [zeros(size(Theta1), 1) Theta1(:, 2:end)] ;

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

    end

Numerical testの実施

Gradient Descentを実施し、最適解を求める前に、これまでに設定したFeedForward propagationやBackward propagationが問題ないことを確認するために、テストを実施します。小規模のランダムでテストデータを作成し、Cost functionの実行結果とNumerical Gradientの実行結果を比較します。

まず、各種パラメータを設定します。


    test_input_layer_size = 3;
    test_hidden_layer_size = 5;
    test_num_labels = 3;
    test_m = 5;
    test_Theta1 = debugInitializeWeights(test_hidden_layer_size, test_input_layer_size);
    test_Theta2 = debugInitializeWeights(test_num_labels, test_hidden_layer_size);
    test_nn_params = [test_Theta1(:) ; test_Theta2(:)];
    test_X  = debugInitializeWeights(test_m, test_input_layer_size - 1);
    test_y  = 1 + mod(1:test_m, test_num_labels)';
    test_lambda = 1;

Numerical Gradientの実行用関数を用意します。小さな値epsilon(e)を設定し、θ=θ-eとθ=θ+e間の傾き(numgrad)を算出します。


    function numgrad = computeNumericalGradient(J, theta)

    numgrad = zeros(size(theta));
    perturb = zeros(size(theta));
    e = 1e-4;
    for p = 1:numel(theta)
        % Set perturbation vector
        perturb(p) = e;
        loss1 = J(theta - perturb);
        loss2 = J(theta + perturb);
        % Compute Numerical Gradient
        numgrad(p) = (loss2 - loss1) / (2*e);
        perturb(p) = 0;
    endfor

    end

上記のテスト用パラメータを用いて、costFunctionとnumericalGradientを実行します。左側にnumericalGradientの実行結果を、右側にcostFunctionの実行結果を表示し、比較します。


    test_costFunc = @(p) nnCostFunction(p, test_input_layer_size, test_hidden_layer_size, test_num_labels, test_X, test_y, test_lambda);
    [test_cost, test_grad] = test_costFunc(test_nn_params);
    test_numgrad = computeNumericalGradient(test_costFunc, test_nn_params);
    disp([test_numgrad test_grad]);

Trainingの実施

先のステップのテストで問題なければ、training datasetを元にGradient computationを実行します。optimizerとして、fmincgを使用します。fmincgはoctaveの機能ではないため、fmincgのファイルも同一ディレクトリに配置しておく必要があります。


    options = optimset('MaxIter', 50);
    lambda = 1;
    costFunction = @(p) nnCostFunction(p, input_layer_size, hidden_layer_size, num_labels, X, y, lambda);
    [nn_params, cost] = fmincg(costFunction, initial_nn_params, options);

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

確認

求めたTheta1とTheta2を使用したモデルのaccuracyを算出します。


    function p = predict(Theta1, Theta2, X)

    m = size(X, 1);
    num_labels = size(Theta2, 1);
    p = zeros(size(X, 1), 1);
    h1 = sigmoid([ones(m, 1) X] * Theta1');
    h2 = sigmoid([ones(m, 1) h1] * Theta2');
    [dummy, p] = max(h2, [], 2);

    end

    pred = predict(Theta1, Theta2, X);
    accuracy = mean(double(pred == y)) * 100;

以上、Neural Networkについてでした。


Category:ML
Tag: ML Octave
July 22, 2018, 4:37 p.m.

Comments