Functionsモジュールの実装|Excel VBAでIris分類問題

今回は今後必要になる機能(関数)をまとめた「Functions」モジュールを実装していきます。
前回やったランダムで行数を取得する関数「GetRandomRow」のような、ニューラルネットワークで機械学習する際にあると便利な関数をまとめておくことで、メインのコードではこれらの関数を呼び出すだけで簡単に使用することができます

たとえば機械学習に優れた言語であるPythonの場合は「NumPy」の「dot」を使うことで簡単に行列計算を行うことができます。
しかしVBAにはそのような機能がないためこのモジュールに「NumPy」の「dot」と同じ機能を持つ関数「dot」を作成します。これにより、このFunctionsモジュールの関数「dot」を呼び出すことで「NumPy」の「dot」と同じように行列計算(VBAでは配列計算ですが)を行うことが可能にな流というわけです。

このようにPythonでは用意されていてVBAに無い機能をはじめ、いくつかの機能をここでまとめていきます。初めはいつ使う機能かわからないものも多いと思いうので、単純にコピペだけでもOKです。

 

unctionsモジュールの実装

まずは標準モジュールで「Functions」というモジュールを作成します。

「Functions」では「Option Base 1」を使い配列を「1」スタートにします。
これは要素数とインデックスを合わせ配列同士の計算をわかりやすくするためです。

以下はFunctionsモジュールの全コードです。

以下では各関数で何を行っているかを簡単に解説していきます。

 

Function GetRandomRow

関数「GetRandomRow」は入力された範囲内で、入力された個数分の整数をランダムで生成し、1つの配列に入れて返す関数です。

引数としては「DataCount」と「MaxDataCount」、省略可能な「MinDataCount」があります。
どれも整数型で個数(DataCount)と範囲(MinDataCount〜MaxDataCount)を表しています。

やっていることは単純で、
たとえばDataCount=10、MinDataCount=100、MinDataCount=25とします。
この場合、返ってくるのは25以上100以下の範囲での10個の整数が入った配列です。
このとき整数は毎回ランダムで重複無しになっています。
(MinDataCountを省略した場合は「1〜」の範囲となります)

前回、Irisデータセットの前処理を行う際に使った関数と同じなので、
 前回作成した「preprocess」モジュール内の関数「GetRandomRow」は削除しておきましょう。

 

Function RandomWeight

関数「RandomWeight」は入力された値の数だけランダムで重みパラメータを生成し、2次元配列として返す関数です。

引数としては「size1」「size2」があります。
これらは返り値である2次元配列の”かたち”を決めるもので、「size1」×「size2」個の重みパラメータが作成されます。重みパラメータの値は-1以上1以下の小数でランダムに生成されます。生成した値は全て2次元配列の「List()」に格納し、この2次元配列を返します。

重みパラメータのランダム生成は、学習の1番初めに行う初期設定のようなものです。これは重みパラメータの初期値がすべて「0」の状態で学習を始めると、学習がうまく進まなくなるための仮の値です。今後ニューラルネットワークの学習を進めることでこの重みパラメータが適正なアタイへと徐々に変化していきます。

 

Function zeros

関数「zeros」は入力された値の数だけ「0」の要素を持つ1次元配列を返す関数です。

引数としては「size1」があります。
これは返り値である1次元配列の要素数を決めるものです。

機能自体は非常にシンプルで、「size1」個の要素を持つ配列を返すだけです。
このとき、要素の値は全て「0」で返します。

たとえば「size1=5」の場合、返ってくる1次元配列は「zeros(0,0,0,0,0)」となります。

前項の関数「RandomWeight」は重みパラメータの初期化に使いましたが、この関数はバイアスパラメータの初期化の際に使います。重みパラメータは「0」であると学習が進みませんがバイアスパラメータの値は「0」でも問題がないためです。こちらも同様にニューラルネットワークの学習が進むにつれ値が適正なものに変化していきます。

 

Function dot

関数「dot」は入力された1次元配列と2次元配列の積を配列として返す関数です。

引数としては「x()」と「W()」があります。
「x()」は1次元配列、「W()」は2次元配列である必要があります。
この関数では2つの引数の積を1つの1次元配列として返します。

ここで行う計算は行列での掛け算と同じです。
VBAでは行列がないため配列を使って計算していますが中身は同じです。

たとえば「x()」の要素数が「3」、「W()」の要素数が「3×2」の場合
以下のような計算が行われ、最終的には要素数が「2」の1次元配列が出来上がります。

 

Function dot2

関数「dot2」は入力された1次元配列と1次元配列の積を2次元配列として返す関数です。

引数としては「xT()」と「dout()」があります。
「xT()」と「dout()」はともに1次元配列である必要があります。
この関数では2つの引数の積を1つの2次元配列として返します。

1次元配列同士の掛け算ですが、行列のかたちとしては「n×1」と「1×m」になります。
(つまり計算後の行列のかたちは「n×m」となります)

たとえば「xT()」の要素数が「3」、「dout()」の要素数が「3」の場合
以下のような計算が行われ、最終的には要素数が「3×3」の2次元配列が出来上がります。

 

Function add

関数「add」は入力された1次元配列と1次元配列の要素ごとの和を1次元配列として返す関数です。

引数としては「xT()」と「dout()」があります。
「xT()」と「dout()」はともに1次元配列である必要があります。
このとき2つの引数の要素数は同じである必要があります。

この関数では2つの引数の各要素ごとの和を1次元配列として返します。

たとえば「xT(1,2,3)」と「dout(4,5,6)」というような値を持っていた時
返ってくる配列は「add(5,7,9)」となります。

 

Function Sigmoid

関数「Sigmoid」は入力された値にSigmoid関数を適応する関数です。

引数としては「A()」があります。
これは重み付き入力値の総和にバイアスを加算した値が入った1次元配列です。

今後実装していく「Affineレイヤ」というレイヤで活性化関数として呼び出して使うことができるようにしておきます。基本的には活性化関数として「ReLU関数」を使う予定ですが、Sigmoid関数にも切り替えられるようにここで関数を作成しておきます。

 

Function softmax

関数「softmax」は入力された値にSoftmax関数を適応する関数です。

引数としては「x()」があります。
これは重み付き入力値の総和にバイアスを加算した値が入った1次元配列です。

今後、Softmax関数の機能と交差エントロピーの機能をまとめた「Softmax-with-Lossレイヤ」というものをクラスモジュールで実装していきます。

そのレイヤ内でSoftmax関数を実装してもいいのですが、レイヤ内はできる限りシンプルな構造にしたいのでここでSoftmax関数の機能を作っておき、あとは呼び出すだけという状態にしておきます。

 

Function cross_entropy_error

関数「cross_entropy_error」は損失関数である交差エントロピー誤差を求めるための関数です。

引数としては「y()」と「t()」があります。
「y()」はSoftmax関数の最終出力の入った1次元配列、
「t()」は正解ラベル(one-hot表現)の入った1次元配列です。

この関数で最終的に出力されるのが、いわゆる「Loss値」です。
このLoss値が0に近いほど、重み/バイアスパラメータが適切な値になっていることを表します。

前項の関数「softmax」と同じく、今後実装していく「Softmax-with-Lossレイヤ」で機能を呼び出すだけの状態にしておくため、この「Functions」モジュールで実装しています。

 

Function one_hot_t

関数「one_hot_t」は入力された値を「one-hot表現」に変換して1次元配列として返します。

引数としては「t_size」と「label」があります。
「t_size」は返り値の1次元配列の要素数、「label」は「1〜3」のいずれかの値です。
(Iris学習の場合、分類する花の種類の3種類あるので「t_size」は「3」で固定です)

「one-hot表現」とは1つの値が「1」でそれ以外の値が「0」で表現されたベクトル(ここでいう配列)のことを指します。

この関数では引数「label」(Irisの正解ラベル)に応じて以下のように変換し、変換後の値を1次元配列として返します。

「label=1 (Setosa)」の場合は「1,0,0」
「label=2 (Versicolor)」の場合は「0,1,0」
「label=3 (Virginica)」の場合は「0,0,1」

上記のように正解の花の種類を表す文字列にラベル(番号)をつけることで、ニューラルネットワーク内で数字として扱うことが可能になります。最終的にニューラルネットワークが導き出した答えが「1」の場合は「Setosa」、「2」の場合は「Versicolor」、「3」の場合は「Virginica」というようにここで指定したラベルで出力されます。

 

まとめ

ここでは今後作成していくレイヤやモジュールで扱うための様々な関数をまとめて実装しました。
今回実装したFunctionsモジュールの機能をまとめると以下の通りです。

Function GetRandomRow:ランダムで生成した行数を返す
Function RandomWeight:ランダムで生成した重みパラメータを返す(重みの初期化)
Function zeros:要素がすべて0の配列を返す(バイアスの初期化)
Function dot:配列同士の積を返す(1次元配列×2次元配列)
Function dot2:配列同士の積を返す(1次元配列×1次元配列)
Function add:配列同士の和を返す(1次元配列+1次元配列)
Function Sigmoid:Sigmoid関数を適応した値を返す
Function softmax:Softmax関数を適応した値を返す
Function cross_entropy_error:交差エントロピー誤差を返す
Function one_hot_t:入力値をone-hot表現に変換した値を返す

おそらく関数だけ見ても何のためにあるのか理解できないと思うので、今後作成していく内容を見ながら適宜本ページに戻ってきて確認して下さい。
逆にいえばはじめのうちはあまり理解していなくても問題ありません。

次回は今回実装したいくつかの関数も使用してAffineレイヤを実装していきます。
以降からはニューラルネットワークの「層(レイヤ)」を実装していく内容になってきます。
つまりはニューラルネットワークを作り始めるということですが、ニューラルネットワークが全て完成しないとわからない部分もあるので初めのうちはあまり難しく考えずに進めてみましょう。

【次回】Affineレイヤの実装
【前回】Irisデータセットの前処理
メインページ
 

 icon-book 参考書籍

2021年2月2日AI, Deep Learning, Excel, VBA

Posted by Lic