【VBA編】ニューラルネットワーク(マクロの登録)
マクロの登録
各ボタンにマクロを登録します。
ボタン | プロシージャ名 |
---|---|
データ読み込み | Click_データ読み込み |
重みクリア | Click_学習状況クリア |
学習開始 | Click_学習開始 |
テスト開始 | Click_テスト開始 |
学習開始
【学習開始】ボタンを押下すると、訓練データによる学習が開始されます。
ロスの値が学習終了判定値を下回るか、エポック数が最大エポック数を超えると学習を終了します。
学習が終了すると、正解数、正解率が計算されます。
テスト開始
【テスト開始】ボタンを押下すると、テストデータによるテストが実行されます。
学習に使われていないテストデータでどれくらい正解するかを調べ、正しく学習されていることを確認します。
なお、学習前に【テスト開始】をした場合、ニューラルネットワークはいいかげんな判断を行います。
【VBA編】ニューラルネットワーク(mdlSupervisor)
スーパーバイザ
メインの処理となるモジュールです。
'[mdlSupervisor - 標準モジュール] Option Explicit Option Base 1 Dim mcInLayer As classInputLayer Dim mcHLayer1 As classHiddenLayer Dim mcHLayer2 As classHiddenLayer Dim mcOutLayer As classOutputLayer 'ユニット数を設定する '[引数] <- aWsInputData : Worksheet / 入力データのあるシート '[戻り値] -> なし Private Sub setUnitCount(ByRef aWsInputData As Worksheet) With aWsInputData G.UnitCount_IN = .Cells(RW.DATA_TITLE, Columns.count).End(xlToLeft).Column - 1 End With G.UnitCount_H1 = 3 G.UnitCount_H2 = 4 G.UnitCount_OUT = 3 End Sub 'ユニットを作成する '[引数] <- なし '[戻り値] -> なし Private Sub makeUnit() Dim actHidden As Long Dim actOutput As Long Set mcInLayer = New classInputLayer Set mcHLayer1 = New classHiddenLayer Set mcHLayer2 = New classHiddenLayer Set mcOutLayer = New classOutputLayer With ws_Main actHidden = getActivationFunction(.Range(G.RNG_ACT_HIDDEN).Value) actOutput = getActivationFunction(.Range(G.RNG_ACT_OUTPUT).Value) End With Call mcHLayer1.Initialize(G.UnitCount_H1, G.UnitCount_IN, actHidden) Call mcHLayer2.Initialize(G.UnitCount_H2, G.UnitCount_H1, actHidden) Call mcOutLayer.Initialize(G.UnitCount_OUT, G.UnitCount_H2, actOutput) End Sub Public Sub Click_学習開始() Call StartTrain End Sub Public Sub Click_テスト開始() Call StartTest End Sub Public Sub Click_学習状況クリア() ws_W_H1.Cells.Clear ws_W_H2.Cells.Clear ws_W_Out.Cells.Clear Call clearResult End Sub Public Sub StartTrain() Dim r As Long Dim c As Long Dim eRow As Long Dim eCol As Long Dim label As String Dim t() As Long Dim datas() As Double Dim res() As Double Dim e As Double Dim sumE As Double Dim i As Long Dim epoc As Long Dim minLoss As Double Dim maxEpoc As Long Dim cnt As Long Dim ansIndex As Long Dim ansRate As Double Call setUnitCount(ws_Train_Data_Input) Call makeUnit With ws_Main G.LearningRate = CDbl(.Range(G.RNG_LEARNING_RATE).Value) minLoss = CDbl(.Range(G.RNG_MIN_LOSS).Value) maxEpoc = CLng(.Range(G.RNG_MAX_EPOCH).Value) If .Range(G.RNG_W_LOAD).Value = "はい" Then Call mcHLayer1.LoadWeight(ws_WI_H1) Call mcHLayer2.LoadWeight(ws_WI_H2) Call mcOutLayer.LoadWeight(ws_WI_Out) Else Call mcHLayer1.SaveWeight(ws_WI_H1) Call mcHLayer2.SaveWeight(ws_WI_H2) Call mcOutLayer.SaveWeight(ws_WI_Out) End If End With Call clearResult On Error GoTo ErrorLabel With ws_Train_Data_Input eRow = .Cells(Rows.count, 1).End(xlUp).Row eCol = .Cells(RW.DATA_TITLE, Columns.count).End(xlToLeft).Column ReDim datas(eCol - 1) Do epoc = epoc + 1 If epoc > maxEpoc Then Exit Do End If sumE = 0 cnt = 0 For r = 2 To eRow cnt = cnt + 1 For c = 2 To eCol datas(c - 1) = .Cells(r, c).Value Next label = .Cells(r, CL.DATA_LABEL).Value t = getT(G.UnitCount_OUT, label) Call mcHLayer1.Forward(datas) Call mcHLayer2.Forward(mcHLayer1.OutputDataList) Call mcOutLayer.Forward(mcHLayer2.OutputDataList) ansIndex = mcOutLayer.GetAnswerIndex ansRate = mcOutLayer.GetAnswerRate(ansIndex) Call getAnswer(ws_Train_Result, r, ansIndex, ansRate, label) res = mcOutLayer.OutputDataList e = ML.crossEntropyError(t, res) sumE = sumE + e Call mcOutLayer.Backprop(t) For i = 1 To G.UnitCount_H2 Call mcHLayer2.Backprop(i, mcOutLayer.deltaList, mcOutLayer.GetWeightList(i)) Next For i = 1 To G.UnitCount_H1 Call mcHLayer1.Backprop(i, mcHLayer2.deltaList, mcHLayer2.GetWeightList(i)) Next Next With ws_Main DoEvents .Cells(epoc, CL.LOSS_).Value = (sumE / cnt) Application.Calculate .Cells(epoc, CL.LOSS_CORRECT).Value = .Range(G.RNG_TRAIN_CORRECT_COUNT).Value DoEvents End With Loop Until sumE / cnt < minLoss End With Call mcHLayer1.SaveWeight(ws_W_H1) Call mcHLayer2.SaveWeight(ws_W_H2) Call mcOutLayer.SaveWeight(ws_W_Out) Exit Sub ErrorLabel: MsgBox "パラメータが発散しました。", vbOKOnly + vbExclamation End Sub Public Sub StartTest() Dim r As Long Dim c As Long Dim eRow As Long Dim eCol As Long Dim label As String Dim t() As Long Dim datas() As Double Dim ansIndex As Long Dim irisName As String Dim ansRate As Double Call setUnitCount(ws_Test_Data_Input) Call makeUnit Call mcHLayer1.LoadWeight(ws_W_H1) Call mcHLayer2.LoadWeight(ws_W_H2) Call mcOutLayer.LoadWeight(ws_W_Out) With ws_Test_Data_Input eRow = .Cells(Rows.count, 1).End(xlUp).Row eCol = .Cells(RW.DATA_TITLE, Columns.count).End(xlToLeft).Column ReDim datas(eCol - 1) For r = 2 To eRow For c = 2 To eCol datas(c - 1) = .Cells(r, c).Value Next label = .Cells(r, CL.DATA_LABEL).Value t = getT(G.UnitCount_OUT, label) Call mcHLayer1.Forward(datas) Call mcHLayer2.Forward(mcHLayer1.OutputDataList) Call mcOutLayer.Forward(mcHLayer2.OutputDataList) ansIndex = mcOutLayer.GetAnswerIndex ansRate = mcOutLayer.GetAnswerRate(ansIndex) Call getAnswer(ws_Test_Result, r, ansIndex, ansRate, label) Next End With End Sub Private Sub getAnswer(ByRef wsResult As Worksheet, ByRef tr As Long, ByRef ansIndex As Long, ByRef ansRate As Double, ByRef label As String) Dim irisName As String Select Case ansIndex Case IRIS.SETOSA irisName = G.VAL_SETOSA Case IRIS.VERSICOLOR irisName = G.VAL_VERSICOLOR Case IRIS.VIRGINICA irisName = G.VAL_VIRGINICA End Select With wsResult .Cells(tr, CL.RESULT_LABEL).Value = label .Cells(tr, CL.RESULT_ANSWER).Value = irisName .Cells(tr, CL.RESULT_RATE).Value = Format(ansRate, "0.0%") .Cells(tr, CL.RESULT_TF).Value = (irisName = label) End With End Sub Private Function getT(ByRef tCount As Long, ByRef label As String) As Long() Dim labels() As Long ReDim labels(tCount) Select Case label Case G.VAL_SETOSA labels(IRIS.SETOSA) = 1 Case G.VAL_VERSICOLOR labels(IRIS.VERSICOLOR) = 1 Case G.VAL_VIRGINICA labels(IRIS.VIRGINICA) = 1 End Select getT = labels End Function Private Sub clearResult() With ws_Train_Result .Cells.Clear .Cells(1, CL.RESULT_LABEL).Value = "ラベル" .Cells(1, CL.RESULT_ANSWER).Value = "NNの答え" .Cells(1, CL.RESULT_RATE).Value = "自信度" .Cells(1, CL.RESULT_TF).Value = "判定" End With With ws_Test_Result .Cells.Clear .Cells(1, CL.RESULT_LABEL).Value = "ラベル" .Cells(1, CL.RESULT_ANSWER).Value = "NNの答え" .Cells(1, CL.RESULT_RATE).Value = "自信度" .Cells(1, CL.RESULT_TF).Value = "判定" End With With ws_Main .Range(.Columns(CL.LOSS_), .Columns(CL.LOSS_CORRECT)).Clear End With End Sub Private Function getActivationFunction(ByRef arg As String) As Long Dim res As Long Select Case arg Case G.VAL_ACT_ReLU res = ACT.ReLU Case G.VAL_ACT_Softmax res = ACT.Softmax End Select getActivationFunction = res End Function
【VBA編】ニューラルネットワーク(classOutputLayer)
出力層クラス
出力層のユニットを管理するクラスです。
'[classOutputLayer - 出力層クラス] Option Explicit Option Base 1 Dim mUnitList() As classUnit 'ユニット格納用リスト Dim mUnitCount As Long '自レイヤーのユニット数 Dim mAct As Long '活性関数の種類 Dim mWeightCount As Long '自レイヤーに属するユニットが持つ重みの数 Dim mInputDataList() As Double Dim mDeltaList() As Double '自レイヤーのユニットを作成する '[引数] <- 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 'バックプロパゲーション用に入力値を覚えておく mInputDataList = aInputDataList 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 Sub Backprop(ByRef aT() As Long) Dim i As Long Dim Z() As Double Z = OutputDataList ReDim mDeltaList(mUnitCount) For i = 1 To mUnitCount mDeltaList(i) = Z(i) - aT(i) 'ユニットの重みを更新 Call mUnitList(i).Backprop(mDeltaList(i), mInputDataList) Next End Sub Public Function deltaList() As Double() deltaList = mDeltaList End Function Public Function GetWeightList(ByRef aWeightIndex As Long) As Double() Dim i As Long Dim res() As Double ReDim res(mUnitCount) For i = 1 To mUnitCount res(i) = mUnitList(i).GetW(aWeightIndex) Next GetWeightList = res End Function '最も大きい出力値のユニットのインデックスを返す 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 Public Function GetAnswerRate(ByRef aIndex As Long) As Double GetAnswerRate = mUnitList(aIndex).Z End Function Public Sub SaveWeight(ByRef aSh As Worksheet) Dim i As Long Dim j As Long With aSh .Cells.Clear For i = 1 To mUnitCount .Cells(i, 1).Value = mUnitList(i).GetBias For j = 1 To mWeightCount .Cells(i, j + 1).Value = mUnitList(i).GetW(j) Next Next End With 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
【VBA編】ニューラルネットワーク(classHiddenLayer)
隠れ層
隠れ層のユニットを管理するクラスです。
'[classHiddenLayer - 隠れ層クラス] Option Explicit Option Base 1 Dim mUnitList() As classUnit 'ユニット格納用リスト Dim mUnitCount As Long '自レイヤーのユニット数 Dim mAct As Long '活性関数の種類 Dim mWeightCount As Long '自レイヤーに属するユニットが持つ重みの数 Dim mInputDataList() As Double '入力用データリスト Dim mDeltaList() As Double '逆伝播時の勾配格納用リスト '自レイヤーのユニットを作成する '[引数] <- 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) ReDim mDeltaList(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 ' バックプロパゲーション用に入力値を覚えておく mInputDataList = aInputDataList 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 Private Function calcDiff(ByRef aU As Double) As Double Dim res As Double If mAct = ACT.ReLU Then res = diffReLU(aU) End If calcDiff = res End Function Private Function diffReLU(ByRef aU As Double) As Double Dim res As Double If aU > 0 Then res = 1# Else res = 0# End If diffReLU = res End Function Public Sub Backprop(ByRef aIndex As Long, ByRef aDeltaList() As Double, ByRef aWeightList() As Double) Dim i As Long Dim delta As Double For i = 1 To UBound(aDeltaList) delta = delta + (aDeltaList(i) * aWeightList(i) * calcDiff(mUnitList(aIndex).U)) Next mDeltaList(aIndex) = delta 'ユニットの重みを更新 Call mUnitList(aIndex).Backprop(delta, mInputDataList) End Sub Public Function deltaList() As Double() deltaList = mDeltaList End Function Public Function GetWeightList(ByRef aWeightList As Long) As Double() Dim i As Long Dim res() As Double ReDim res(mUnitCount) For i = 1 To mUnitCount res(i) = mUnitList(i).GetW(aWeightList) Next GetWeightList = res End Function Public Sub SaveWeight(ByRef aSh As Worksheet) Dim i As Long Dim j As Long With aSh .Cells.Clear For i = 1 To mUnitCount .Cells(i, 1).Value = mUnitList(i).GetBias For j = 1 To mWeightCount .Cells(i, j + 1).Value = mUnitList(i).GetW(j) Next Next End With 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
【VBA編】ニューラルネットワーク(classInputLayer)
入力層のユニット管理
入力層のユニットを管理するためのクラスです。
'[classInputLayer - 入力層のユニットを管理するためのクラス] Option Explicit Option Base 1 Dim mInUnitList() As classInputUnit 'ユニット格納用リスト Dim mInUnitCount As Long '入力層のユニット数 '入力層のユニットに入力値を格納する '[引数] <- aInputDataList() : Double / 入力値のリスト Public Sub DataInput(ByRef aInputDataList() As Double) Dim i As Long Dim cInUnit As classInputUnit mInUnitCount = UBound(aInputDataList) ReDim mInUnitList(mInUnitCount) For i = 1 To mInUnitCount Set mInUnitList(i) = New classInputUnit mInUnitList(i).X = aInputDataList(i) Next End Sub '入力層のユニットの出力値を得る '[戻り値] -> OutputDataList() : Double / 出力値のリスト Public Function OutputDataList() As Double() Dim i As Long Dim outputDatas() As Double ReDim outputDatas(mInUnitCount) For i = 1 To mInUnitCount outputDatas(i) = mInUnitList(i).X Next OutputDataList = outputDatas() End Function
【VBA編】ニューラルネットワーク(classInputUnit, classUnit)
入力層のユニットクラス
入力層のみ実装が異なります。
'[classInputUnit - 入力層のユニットクラス] Option Explicit Dim mX As Double '入力データをセットする '[引数] <- inputData : Double / 入力データ Public Property Let X(ByRef aInputData As Double) mX = aInputData End Property '入力データを返す '[戻り値] -> X : Double / 入力データ Public Property Get X() As Double X = mX End Property
ユニットクラス
ユニットクラスの実装です。
'[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 'バイアス値を返す '[戻り値] -> GetBias : Double / バイアス値 Public Function GetBias() As Double GetBias = mBias End Function '重みをセットする '[引数] <- aIndex : Long / インデックス, aW : Double / 重み Public Sub SetW(ByRef aIndex As Long, ByRef aW As Double) mWeightList(aIndex) = aW End Sub '重みを返す '[引数] <- aIndex : Long / インデックス '[戻り値] -> GetW : Double / 重み Public Function GetW(ByRef aIndex As Long) As Double GetW = mWeightList(aIndex) End Function 'バックプロパゲーション(重みを更新する) '(学習率 × 勾配 × 入力値)の計算結果を重みから引いて、重みを更新する 'バイアスも同様に計算する(ただし、バイアスの入力値は 1) '[引数] <- aDelta : Double / 勾配の計算結果, aInputDataList() : Double / 入力値のリスト 'Public Sub UpdateWeight(ByRef aDelta As Double, ByRef aInputDataList() As Double) Public Sub Backprop(ByRef aDelta As Double, ByRef aInputDataList() As Double) Dim i As Long For i = 1 To UBound(mWeightList) mWeightList(i) = mWeightList(i) - (G.LearningRate * aDelta * aInputDataList(i)) Next mBias = mBias - (G.LearningRate * aDelta * 1) End Sub
【VBA編】ニューラルネットワーク(ML)
演算用モジュール
活性化関数や損失関数を実装します。
'[ML - マシンラーニング演算用モジュール] Option Explicit Option Base 1 '活性化関数 ReLU '[引数] <- aU : Double / ユニットの u '[戻り値] -> actReLU : Double / ReLU適用後の値 Public Function actReLU(ByVal aU As Double) As Double actReLU = WorksheetFunction.max(aU, 0) End Function '活性化関数 Softmax '[引数] <- aUList() : Double / 出力層のすべての出力値のリスト, aIndex : Long / 対象のユニットのインデックス '[戻り値] -> actSoftmax : Double / Softmax適用後の値 Public Function actSoftmax(ByRef aUList() As Double, ByRef aIndex As Long) As Double Dim i As Long Dim max As Double Dim sum As Double 'オーバーフロー対策ですべての出力値から最大値を引く必要があるため最大値を求めておく max = WorksheetFunction.max(aUList) '分母部分の計算 sum = 0 For i = 1 To UBound(aUList) sum = sum + Exp(aUList(i) - max) Next '該当ユニットの出力値を全出力値で割る actSoftmax = Exp(aUList(aIndex) - max) / sum End Function '-1 < num < 1 で0以外のランダム値を返す '[戻り値] -> getRandom() : Double / -1 より大きく 1 より小さいランダム値(0以外) Public Function getRandom() As Double Dim i As Long Dim res As Double Randomize Do res = (Rnd * 2) - 1 Loop Until res <> 0 getRandom = res End Function '損失関数 クロスエントロピーエラー '[引数] <- aT() : Long / 正解ラベル(one-hot表現された教師データ), ' aZ : Double / ニューラルネットワークの出した予想確率(出力層ユニットの出力値) '[戻り値] -> crossEntropyError : Double / crossEntropyErrorの値 Public Function crossEntropyError(ByRef aT() As Long, ByRef aZ() As Double) As Double Dim i As Long Dim res As Double res = 0 For i = 1 To UBound(aT) res = res + (aT(i) * Log(aZ(i) + 0.0000001)) 'エラー回避のために微小な値を足している Next res = res * -1 crossEntropyError = res End Function