MATLAB,Python,Scilab,Julia比較 第4章 その82【誤差逆伝播法⑨】

MATLAB,Python,Scilab,Julia比較 第4章 その82【誤差逆伝播法⑨】 数値計算

バックナンバーはこちら。
https://www.simulationroom999.com/blog/compare-matlabpythonscilabjulia4-backnumber/

はじめに

多層パーセプトロンの誤差逆伝播法を行う。
今回はScilabで実現。

登場人物

博識フクロウのフクさん

指差しフクロウ

イラストACにて公開の「kino_k」さんのイラストを使用しています。
https://www.ac-illust.com/main/profile.php?id=iKciwKA9&area=1

エンジニア歴8年の太郎くん

技術者太郎

イラストACにて公開の「しのみ」さんのイラストを使用しています。
https://www.ac-illust.com/main/profile.php?id=uCKphAW2&area=1

誤差逆伝播法の各演算【再掲】

太郎くん
太郎くん

まずは、前回求めた誤差逆伝播法の各演算を再掲。

隠れ層の重み\(W_2\)とバイアス\(b_2\)の勾配(\(\Delta W_2,\Delta b_2\))を特定

\(
\Delta W_2=\Delta_2 A_2
\)

\(
\Delta b_2=\Delta_2 1
\)

入力層の重み\(W_1\)とバイアス\(b_1\)の勾配(\(\Delta W_1,\Delta b_1\))を特定

\(
\Delta W_1=\Delta_1 X
\)

\(
\Delta b_1=\Delta_1 1
\)

各勾配から各重み、各バイアスを更新(学習率\(\mu\)を掛けておく)

\(
\begin{eqnarray}
W_1&=&W_1-\mu\Delta W_1\\
b_1&=&b_1-\mu\Delta b_1\\
W_2&=&W_2-\mu\Delta W_2\\
b_2&=&b_2-\mu\Delta b_2\\
\end{eqnarray}
\)

フクさん
フクさん

これをScilabで実現する。

Scilabコード

フクさん
フクさん

Scilabコードは以下。

// データの準備
X = [0 0; 0 1; 1 0; 1 1]; // 入力データ
Y = [0; 1; 1; 0]; // 出力データ

// シグモイド関数
function y = sigmoid(x)
    y = 1 ./ (1 + exp(-x));
endfunction

// シグモイド関数の導関数
function y = sigmoid_derivative(x)
    y = sigmoid(x) .* (1 - sigmoid(x));
endfunction

// ネットワークの構築
hidden_size = 2; // 隠れ層のユニット数
output_size = 1; // 出力層のユニット数
learning_rate = 0.5; // 学習率

input_size = size(X, 2);
W1 = rand(input_size, hidden_size, 'normal'); // 入力層から隠れ層への重み行列
b1 = rand(1, hidden_size, 'normal'); // 隠れ層のバイアス項
W2 = rand(hidden_size, output_size, 'normal'); // 隠れ層から出力層への重み行列
b2 = rand(1, output_size, 'normal'); // 出力層のバイアス項

// 学習
epochs = 4000; // エポック数

errors = zeros(epochs, 1); // エポックごとの誤差を保存する配列

for epoch = 1:epochs
    // 順伝播
    Z1 = X * W1 + ones(size(X, 1), 1) * b1; // 隠れ層の入力
    A1 = sigmoid(Z1); // 隠れ層の出力
    Z2 = A1 * W2 + b2; // 出力層の入力
    A2 = sigmoid(Z2); // 出力層の出力

    // 誤差計算(平均二乗誤差)
    error = (1 / size(X, 1)) * sum((A2 - Y).^2);
    errors(epoch) = error;

    // 逆伝播
    delta2 = (A2 - Y) .* sigmoid_derivative(Z2);
    delta1 = (delta2 * W2') .* sigmoid_derivative(Z1);

    grad_W2 = A1' * delta2;
    grad_b2 = sum(delta2);
    grad_W1 = X' * delta1;
    grad_b1 = sum(delta1);

    // パラメータの更新
    W1 = W1 - learning_rate * grad_W1;
    b1 = b1 - learning_rate * grad_b1;
    W2 = W2 - learning_rate * grad_W2;
    b2 = b2 - learning_rate * grad_b2;
end

// 決定境界線の表示
h = 0.01; // メッシュの間隔
[x1, x2] = meshgrid(min(X(:, 1)) - 0.5:h:max(X(:, 1)) + 0.5, min(X(:, 2)) - 0.5:h:max(X(:, 2)) + 0.5);
X_mesh = [x1(:) x2(:)];

hidden_layer_mesh = sigmoid(X_mesh * W1 + ones(size(X_mesh, 1), 1) * b1);
output_layer_mesh = sigmoid(hidden_layer_mesh * W2 + b2);
y_mesh = round(output_layer_mesh); // 出力を0または1に丸める

clf;
x = X_mesh(:, 1);
y = X_mesh(:, 2);

idx_boundary = find(y_mesh(1:$-1) <> y_mesh(2:$)); // 境界のインデックスを取得
boundary_x = x(idx_boundary); // 境界のx座標
boundary_y = y(idx_boundary); // 境界のy座標

scatter(boundary_x, boundary_y, 3, 'k', 'fill'); // 境界を黒でプロット
scatter(X(Y==0, 1), X(Y==0, 2), 100, 'r', 'fill');
scatter(X(Y==1, 1), X(Y==1, 2), 100, 'b', 'fill');
xlabel("X1");
ylabel("X2");
title("XOR Classification");
legend("Boundary", "Class 1", "Class 0");

xgrid; // グリッドの表示

処理結果

フクさん
フクさん

処理結果は以下。

多層パーセプトロンで分類(Scilab)
フクさん
フクさん

尚、Scilabは等高線による分類表記がうまく行かなかったため、
境界線をplotしている。

まとめ

フクさん
フクさん

まとめだよ。

  • 多層パーセプトロンによる分類をScilabで実施。
    • 一応ちゃんと分類できた。
    • 等高線による分類表記がうまく行かなかったため、境界線をplotしている。

バックナンバーはこちら。

Pythonで動かして学ぶ!あたらしい線形代数の教科書

https://amzn.to/3OE5bVp

ゼロから作るDeep Learning ―Pythonで学ぶディープラーニングの理論と実装

https://amzn.to/3OBiaax

ゼロからはじめるPID制御

https://amzn.to/3SvzuyR

OpenCVによる画像処理入門

https://amzn.to/498ZUgK

恋する統計学[回帰分析入門(多変量解析1)] 恋する統計学[記述統計入門]

https://amzn.to/3STAe2i

Pythonによる制御工学入門

https://amzn.to/3uskuK5

理工系のための数学入門 ―微分方程式・ラプラス変換・フーリエ解析

https://amzn.to/3UAunQK

コメント

タイトルとURLをコピーしました