中間層における計算 - m個の入力をn個の出力に変換する
ディープラーニングにおける中間層における計算として、m個の入力をn個の出力に変換する方法を解説します。
ディープラーニングでは、複数の入力と複数の出力を、多段階に連続的につなぎ、最終的な出力を得ることをします。
このとき、m個の入力から、n個の出力を得る必要があります。
たとえば、4つの入力に対して、5つの出力を得る。5つの入力から、3つの出力を得るということを行います。
(x0, x1, x2, x3) ↓ (y0, y1, y2, y3, y4) ↓ (z0, z1, z2)
二つの入力から三つの出力を得る
では、簡単な例として、二つの入力から三つの出力を得る方法を記述してみましょう。まずPerlのコードで書きます。
use strict; use warnings; my $x0 = 0.5; my $x1 = 0.8; my $w00 = 0.1; my $w01 = -0.4; my $w10 = 0.2; my $w11 = -0.5; my $w20 = 0.3; my $w21 = 1.3; my $b0 = 0.3; my $b1 = -0.9; my $b2 = 0.5; my $y0 = ($w00 * $x0) + ($w01 * $x1) + $b0; my $y1 = ($w10 * $x0) + ($w11 * $x1) + $b1; my $y2 = ($w20 * $x0) + ($w21 * $x1) + $b2; print "($y0, $y1, $y2)\n";
出力結果は以下のようになります。
(0.0299999999999999, -1.2, 1.69)
このような計算を行うことで、($x1, $x2)という二つの入力値から($y0, $y1, $y2)という三つの出力を得ることができました。
活性化関数で出力を変換する
ディープラーニングでは、次の入力に渡す前に、出力を、ある規則によって変換する必要があります。この変換が必要な理由は、この変換を行わないと学習が進まないためです。
このような関数は活性化関数と呼ばれ、活性化関数の一つとして、ReLUと呼ばれる関数があります。
# ReLU関数 sub relu { my ($num) = @_; return $num > 0 : $num : 0; }
この関数は、入力が0より大きければ、その値を返し、0以下の場合は、0を返します。
先のサンプルに活性化関数を適用してみましょう。関数で書く必要はないので、ソースコードにべた書きします。
use strict; use warnings; my $x0 = 0.5; my $x1 = 0.8; my $w00 = 0.1; my $w01 = -0.4; my $w10 = 0.2; my $w11 = -0.5; my $w20 = 0.3; my $w21 = 1.3; my $b0 = 0.3; my $b1 = -0.9; my $b2 = 0.5; my $y0 = ($w00 * $x0) + ($w01 * $x1) + $b0; my $y1 = ($w10 * $x0) + ($w11 * $x1) + $b1; my $y2 = ($w20 * $x0) + ($w21 * $x1) + $b2; $y0 = $y0 > 0 ? $y0 : 0; $y1 = $y1 > 0 ? $y1 : 0; $y2 = $y2 > 0 ? $y2 : 0; print "($y0, $y1, $y2)\n";
出力結果は以下のようになります。値がマイナスの場合は、0に変わっています。
(0.0299999999999999, 0, 1.69)
m個の入力をn個の出力に変換する処理の一般化
m個の入力をn個の出力に変換する処理を一般化してみましょう。もう一度、下の処理をじっくりみてください。
use strict; use warnings; my $x0 = 0.5; my $x1 = 0.8; my $w00 = 0.1; my $w01 = -0.4; my $w10 = 0.2; my $w11 = -0.5; my $w20 = 0.3; my $w21 = 1.3; my $b0 = 0.3; my $b1 = -0.9; my $b2 = 0.5; my $y0 = ($w00 * $x0) + ($w01 * $x1) + $b0; my $y1 = ($w10 * $x0) + ($w11 * $x1) + $b1; my $y2 = ($w20 * $x0) + ($w21 * $x1) + $b2; $y0 = $y0 > 0 ? $y0 : 0; $y1 = $y1 > 0 ? $y1 : 0; $y2 = $y2 > 0 ? $y2 : 0; print "($y0, $y1, $y2)\n";
必要な情報を、漏れなく書き出してみましょう。
入力の個数は、2個。
出力の個数は、3個。
必要な$wパラメーターの個数はいくつでしょうか。これは「入力個数「2」 * 出力個数「3」 = 6」です。
必要な$bパラメーターの個数はいくつでしょうか? 出力個数「3」と同じです。
入力は
[$x0, $x1]
パラメーター$wは、
[ $w00, $w01, $w10, $w11, $w20, $w21, ]
パラメーター$bは、
[ $b0, $b1, $b2, ]
受け取る出力は
[$y0, $y1, $y2]
です。
配列化
では、コーディングしてみます。最初は、配列化です。最初の例と、と同じ出力を得ることができれば、正解ですね。
目を凝らして、法則性を眺めてください。
use strict; use warnings; my $x = [0.5, 0.8]; my $y = [0, 0, 0]; my $x_len = @$x; my $y_len = @$y; my $w = [ 0.1, -0.4, 0.2, -0.5, 0.3, 1.3, ]; my $b = [ 0.3, -0.9, 0.5, ]; $y->[0] = ($w->[$x_len * 0 + 0] * $x->[0]) + ($w->[$x_len * 0 + 1] * $x->[1]) + $b->[0]; $y->[1] = ($w->[$x_len * 1 + 0] * $x->[0]) + ($w->[$x_len * 1 + 1] * $x->[1]) + $b->[1]; $y->[2] = ($w->[$x_len * 2 + 0] * $x->[0]) + ($w->[$x_len * 2 + 1] * $x->[1]) + $b->[2]; $y->[0] = $y->[0] > 0 ? $y->[0] : 0; $y->[1] = $y->[1] > 0 ? $y->[1] : 0; $y->[2] = $y->[2] > 0 ? $y->[2] : 0; print "($y->[0], $y->[1], $y->[2])\n";
出力結果は以下で、同じになりました。
(0.661503159202952, 0.802183888558582, 0.755838899094797)
ループ化
配列化が終わったら、次はループ化です。配列というデータ構造にすることで、ループのアルゴリズムを適用できます。二重ループで処理を書き直してみます。最初の例と、と同じ出力を得ることができれば、正解ですね。
use strict; use warnings; my $x = [0.5, 0.8]; my $y = [0, 0, 0]; my $x_len = @$x; my $y_len = @$y; my $w = [ 0.1, -0.4, 0.2, -0.5, 0.3, 1.3, ]; my $b = [ 0.3, -0.9, 0.5, ]; for (my $y_index = 0; $y_index < $y_len; $y_index++) { my $total = 0; for (my $x_index = 0; $x_index < $x_len; $x_index++) { $total += ($w->[$x_len * $y_index + $x_index] * $x->[$x_index]); } $total += $b->[$y_index]; $y->[$y_index] = $total > 0 ? $total : 0; } print "($y->[0], $y->[1], $y->[2])\n";
出力結果は以下で、同じになりました。
(0.0299999999999999, 0, 1.69)
これで、mが2以外の数になったり、nが3以外の数になっても、対応できるようになりました。
ディープラーニングに必要な技術の中の、m個の入力をn個の出力に変換する方法、活性化関数の適用の学習を終えました。