【VBA編】(順伝播)動作確認(1)
動作確認
前回までで順伝播については入力から出力まで計算できるようになりました。
ここまででいったん正しく動作するかを確認してみましょう。
ただ、その前にコードをいくつか追加しておきます。
それぞれ「----追加----」の部分を追加してください。
標準モジュール【G】
'[G - 標準モジュール] Option Explicit Public Const RNG_TRAIN_DATA_PATH As String = "C2" '訓練データのパスを格納するセル Public Const RNG_TEST_DATA_PATH As String = "C3" 'テストデータのパスを格納するセル Public Enum RW DATA_TITLE = 1 'データのタイトル行 DATA_START = 2 'データの開始行 End Enum Public Enum CL DATA_LABEL = 1 'データのラベル列 DATA_START = 2 'データの開始列 End Enum '活性化関数 Public Enum ACT ReLU = 1 Softmax = 2 End Enum '----追加---- 'Irisの種類名 Public Const VAL_SETOSA As String = "Iris-setosa" Public Const VAL_VERSICOLOR As String = "Iris-versicolor" Public Const VAL_VIRGINICA As String = "Iris-virginica" 'Irisの種類インデックス Public Enum IRIS SETOSA = 1 VERSICOLOR = 2 VIRGINICA = 3 End Enum '----ここまで----
Irisの種類名と種類インデックスを追加しています。
クラスモジュール【classUnit】
'[classUnit - ユニットクラス] Option Explicit Option Base 1 Dim mWeightList() As Double '重みのリスト Dim mBias As Double 'バイアス Dim mU As Double '活性化関数適用前の合計値 Dim mZ As Double '出力値 'パラメータ(重みとバイアス)を初期化する '[引数] <- aWeightCount : Long / 重みの数 Public Sub Initialize(ByRef aWeightCount As Long) Dim i As Long ReDim mWeightList(aWeightCount) '各重みをランダム値で初期化 For i = 1 To aWeightCount mWeightList(i) = ML.getRandom() Next 'バイアスを0で初期化 mBias = 0 End Sub '活性化関数適用前の合計値を計算する '入力値にそれぞれの重みを掛けてバイアス値を加える '[引数] <- aInputDataList() : Double / 入力値のリスト Public Sub CalcU(ByRef aInputDataList() As Double) Dim i As Long mU = mBias For i = 1 To UBound(aInputDataList) mU = mU + (mWeightList(i) * aInputDataList(i)) Next End Sub '活性化関数適用前の合計値を返す '[戻り値] -> U : Double / 活性化関数適用前の合計値 Public Property Get U() As Double U = mU End Property '出力値を格納する '[引数] <- aActivatedU : Double / 活性化関数適用後の合計値 Public Property Let Z(ByRef aActivatedU As Double) mZ = aActivatedU End Property '出力値を返す '[戻り値] -> Z : Double / 出力値 Public Property Get Z() As Double Z = mZ End Property '----追加---- 'バイアス値をセットする '[引数] <- aBias : Double / バイアス値 Public Sub SetBias(ByRef aBias As Double) mBias = aBias End Sub '重みをセットする '[引数] <- aIndex : Long / インデックス, aW : Double / 重み Public Sub SetW(ByRef aIndex As Long, ByRef aW As Double) mWeightList(aIndex) = aW End Sub '----ここまで----
サブプロシージャ「SetBias()」「SetW()」を追加しています。
クラスモジュール【classHiddenLayer】
'[classHiddenLayer - 隠れ層クラス] Option Explicit Option Base 1 Dim mUnitList() As classUnit 'ユニット格納用リスト Dim mUnitCount As Long '自レイヤーのユニット数 Dim mAct As Long '活性関数の種類 '----追加---- Dim mWeightCount As Long '自レイヤーに属するユニットが持つ重みの数 '----ここまで---- '自レイヤーのユニットを作成する '[引数] <- aUnitCount : Long / ユニットの数, aInputCount : Long / 入力データの数, aActivationFunction : Long / 活性化関数の種類 Public Sub Initialize(ByRef aUnitCount As Long, ByRef aInputCount As Long, ByRef aActivationFunction As Long) Dim i As Long ReDim mUnitList(aUnitCount) '必要な数だけユニットを作成しユニット格納用リストに格納する For i = 1 To aUnitCount Set mUnitList(i) = New classUnit 'Newしたユニットを初期化する Call mUnitList(i).Initialize(aInputCount) Next mUnitCount = aUnitCount mAct = aActivationFunction '----追加---- mWeightCount = aInputCount '----ここまで---- End Sub '順伝播:各ユニットのuとzを求める '[引数] <- aInputDataList() : Double / 入力データのリスト Public Sub Forward(ByRef aInputDataList() As Double) Dim i As Long 'ユニットに入力値を渡して u を計算する For i = 1 To mUnitCount Call mUnitList(i).CalcU(aInputDataList) Next '活性化関数を適用して z を計算する Call activateU End Sub '次の層に渡すための出力リストを準備する '[戻り値] -> OutputDataList() : Double / 自層の各ユニットの出力値のリスト Public Function OutputDataList() As Double() Dim i As Long Dim outputDatas() As Double ReDim outputDatas(mUnitCount) For i = 1 To mUnitCount outputDatas(i) = mUnitList(i).Z Next OutputDataList = outputDatas() End Function 'ユニットの u に活性化関数を適用する Private Sub activateU() If mAct = ACT.ReLU Then Call activationReLU End If End Sub 'ユニットの u にReLUを適用する Private Sub activationReLU() Dim i As Long For i = 1 To mUnitCount mUnitList(i).Z = ML.actReLU(mUnitList(i).U) Next End Sub '----追加---- '重みとバイアスの値をシートから読み込む '[引数] <- aSh : Worksheet / 読み込み先のシート Public Sub LoadWeight(ByRef aSh As Worksheet) Dim i As Long Dim j As Long With aSh For i = 1 To mUnitCount Call mUnitList(i).SetBias(.Cells(i, 1).Value) For j = 1 To mWeightCount Call mUnitList(i).SetW(j, .Cells(i, j + 1).Value) Next Next End With End Sub '----ここまで----
モジュールレベル変数「mWeightCount」とInitializeプロシージャに[ mWeightCount = aInputCount ]、あとサブプロシージャ「LoadWeight()」を追加しています。「LoadWeight()」は(テスト用の)重みとバイアスの値をシートから読み込むためのプロシージャです。
クラスモジュール【classOutputLayer】
'[classOutputLayer - 出力層クラス] Option Explicit Option Base 1 Dim mUnitList() As classUnit 'ユニット格納用リスト Dim mUnitCount As Long '自レイヤーのユニット数 Dim mAct As Long '活性関数の種類 '----追加---- Dim mWeightCount As Long '自レイヤーに属するユニットが持つ重みの数 '----ここまで---- '自レイヤーのユニットを作成する '[引数] <- aUnitCount : Long / ユニットの数, aInputCount : Long / 入力データの数, aActivationFunction : Long / 活性化関数の種類 Public Sub Initialize(ByRef aUnitCount As Long, ByRef aInputCount As Long, ByRef aActivationFunction As Long) Dim i As Long ReDim mUnitList(aUnitCount) '必要な数だけユニットを作成しユニット格納用リストに格納する For i = 1 To aUnitCount Set mUnitList(i) = New classUnit 'Newしたユニットを初期化する Call mUnitList(i).Initialize(aInputCount) Next mUnitCount = aUnitCount mAct = aActivationFunction '----追加---- mWeightCount = aInputCount '----ここまで---- End Sub '順伝播:各ユニットのuとzを求める '[引数] <- aInputDataList() : Double / 入力データのリスト Public Sub Forward(ByRef aInputDataList() As Double) Dim i As Long 'ユニットに入力値を渡して u を計算する For i = 1 To mUnitCount Call mUnitList(i).CalcU(aInputDataList) Next '活性化関数を適用して z を計算する Call activateU End Sub '次の層に渡すための出力リストを準備する '[戻り値] -> OutputDataList() : Double / 自層の各ユニットの出力値のリスト Public Function OutputDataList() As Double() Dim i As Long Dim outputDatas() As Double ReDim outputDatas(mUnitCount) For i = 1 To mUnitCount outputDatas(i) = mUnitList(i).Z Next OutputDataList = outputDatas() End Function 'ユニットの u に活性化関数を適用する Private Sub activateU() If mAct = ACT.Softmax Then Call activationSoftmax End If End Sub 'ユニットの u にSoftmaxを適用する Private Sub activationSoftmax() Dim i As Long Dim uList() As Double 'Softmaxの計算には全出力値が必要となるため、配列に格納 ReDim uList(mUnitCount) For i = 1 To mUnitCount uList(i) = mUnitList(i).U Next For i = 1 To mUnitCount mUnitList(i).Z = ML.actSoftmax(uList, i) Next End Sub '最も大きい出力値のユニットのインデックスを返す Public Function GetAnswerIndex() As Long Dim i As Long Dim ans As Long ans = 1 For i = 2 To mUnitCount If mUnitList(i).Z > mUnitList(ans).Z Then ans = i End If Next GetAnswerIndex = ans End Function '----追加---- '重みとバイアスの値をシートから読み込む '[引数] <- aSh : Worksheet / 読み込み先のシート Public Sub LoadWeight(ByRef aSh As Worksheet) Dim i As Long Dim j As Long With aSh For i = 1 To mUnitCount Call mUnitList(i).SetBias(.Cells(i, 1).Value) For j = 1 To mWeightCount Call mUnitList(i).SetW(j, .Cells(i, j + 1).Value) Next Next End With End Sub '----ここまで----
classHiddenLayerと同じく、モジュールレベル変数「mWeightCount」とInitializeプロシージャに[ mWeightCount = aInputCount ]、あとサブプロシージャ「LoadWeight()」を追加しています。
次回は動作確認用のコードを書いていく予定です。