行列の積の計算
ディープラーニングに必要な行列の積をPerlで求める方法を解説します。
重み行列と入力ベクトルの掛け算を行う場合に、必要です。
行列の計算にはいくつかの条件を設けておきます。
一つ目は、列優先の行列であるということです。列優先の行列というのは、列方向の向きにデータを持つということです。
# 数学の行列表現
# 3行2列の行列
# 1 4
# 2 5
# 3 6
# 列優先でのデータのもちかた
my $mat = {
values => [1, 2, 3, 4, 5, 6],
rows_length => 3,
columns_length => 2,
};
列優先にしておく理由は、BLASという行列計算ライブラリを使う場合と、整合性をとるためです。
まずPerlで、行列演算を行い。それをSPVMに移植します。そして、最後に、BLUSと呼ばれるC言語ライブラリや、cuBLUSと呼ばれるcudaのGPUの計算を行えるライブラリに移植可能なようにします。
行列の積を求める
行列の積を求めましょう。3×2の行列と、2×1の行列(つまりベクトル)の積を求めます。
use strict;
use warnings;
# 行列の積を求める
sub mat_mul {
my ($mat1, $mat2) = @_;
my $mat1_rows_length = $mat1->{rows_length};
my $mat1_columns_length = $mat1->{columns_length};
my $mat1_values = $mat1->{values};
my $mat2_rows_length = $mat2->{rows_length};
my $mat2_columns_length = $mat2->{columns_length};
my $mat2_values = $mat2->{values};
# 行列の積の計算
my $mat_out_values = [];
for(my $row = 0; $row < $mat1_rows_length; $row++) {
for(my $col = 0; $col < $mat2_columns_length; $col++) {
for(my $incol = 0; $incol < $mat1_columns_length; $incol++) {
$mat_out_values->[$row + $col * $mat1_rows_length]
+= $mat1_values->[$row + $incol * $mat1_rows_length] * $mat2_values->[$incol + $col * $mat2_rows_length];
}
}
}
my $mat_out = {
rows_length => $mat1_rows_length,
columns_length => $mat2_columns_length,
values => $mat_out_values,
};
return $mat_out;
}
# 重み(3行2列の行列)
# 1 4
# 2 5
# 3 6
my $mat1 = {
values => [1, 2, 3, 4, 5, 6],
rows_length => 3,
columns_length => 2,
};
# 入力ベクトル(2行1列の行列)
# 7 9
# 8 10
my $mat2 = {
values => [7, 8, 9, 10],
rows_length => 2,
columns_length => 2,
};
# 計算方法
# 1 * 7 + 4 * 8 1 * 9 + 4 * 10
# 2 * 7 + 5 * 8 2 * 9 + 5 * 10
# 3 * 7 + 6 * 8 3 * 9 + 6 * 10
my $outputs_mul = mat_mul($mat1, $mat2);
# rows_length => 3, columns_length => 2, values : [39, 54, 69, 49, 68, 87]
use Data::Dumper;
print Dumper $outputs_mul;
Perlでの行列の積の計算には、C言語で書かれた行列の積の計算アルゴリズムがありましたので、それを流用しました。
行列の積の計算は、一般には、3重ループになります。
Perl AI深層学習入門