ディープラーニングの解析結果が常に同じ値になります
売上個数予想のプログラムを作っていますが、
学習させた後MultiLayerNetwork.output(xxx)
させた結果が常に同じ値になり困っています。
事前に学習データをAI.MaxInputStringLength
(20)のパラメータに変換済みでそのサンプルが数万個あります。
つまり、入力は20のパラメータがあります。
今回は売上個数の予想なので出力は1つです。
(ディープラーニングは初めてなのでまずはそれっぽい結果が出るだけでよく、モデル構築は勘に近いです)
下記コードは処理を読める程度に必要な部分だけを抜粋しています。
AI.MaxInputStringLength
は 入力パラメータ数なので20
です。 (Stringとついてますが入力は事前処理しているので文字列ではありません)
ニューラルネットワークモデル
val modelConfig = NeuralNetConfiguration.Builder()
.seed(1142)
.optimizationAlgo(OptimizationAlgorithm.STOCHASTIC_GRADIENT_DESCENT)
.iterations(1000)
.learningRate(0.001)
//.updater(Updater.NESTEROVS).momentum(0.9)
//.regularization(true).l2(1e-4)
.list()
.layer(0, DenseLayer.Builder()
.nIn(MaxInputStringLength)
.nOut(500)
.activation(Activation.SIGMOID)
.weightInit(WeightInit.XAVIER)
.build())
var layer = 1 // ↑inputが0だから1から始まる
var beforeOutputCount = 500 // ↑inputのアウトプットの数
val middleLayerLength = 100
for (i in 0 until middleLayerLength) {
val outputCount = 500
modelConfig.layer(
layer++, DenseLayer.Builder()
.nIn(beforeOutputCount)
.nOut(outputCount)
.activation(Activation.RELU)
.weightInit(WeightInit.XAVIER)
.build()
)
beforeOutputCount = outputCount
}
modelConfig.layer(layer, OutputLayer.Builder()
.nIn(beforeOutputCount)
.nOut(1)
.activation(Activation.SIGMOID)
.weightInit(WeightInit.XAVIER)
.build())
val model = MultiLayerNetwork(modelConfig.build())
model.init()
データセットの作成(20インプット1アウトプット * サンプルの数 を一つのDataSetに)
fun loadDataSet(apps: LinkedList<App>): DataSet {
// 省略解説 dataCount は学習データの数(数万)
// 省略解説 AI.MaxInputStringLength はinputの数(今回は常に20)
// データ領域を用意する
val inputBuff = FloatArray(AI.MaxInputStringLength * dataCount)
val answerBuff = FloatArray(dataCount)
// データを格納する
var inputOffset = 0
var answerOffset = 0
for ({省略解説 学習データの数だけ繰り返す dataCount}) {
// 入力
// 省略解説 `putInputメソッド`はforで回されてきた`学習データ`を`inputBuff`に格納して新しいオフセットを返す
// メソッド内部で`学習データ`の`inputの数`だけ格納されるのでこのメソッドは`inputOffset+AI.MaxInputStringLength`の値を常に返すことになる
inputOffset = putInput(inputBuff, inputOffset, AI.MaxInputStringLength)
// 回答
answerBuff[answerOffset++] = meta.salesCount.toFloat()
}
return DataSet(
Nd4j.create(
inputBuff,
intArrayOf(dataCount, MaxInputStringLength)
),
Nd4j.create(
answerBuff,
intArrayOf(dataCount, 1)
)
)
}
学習部分
model.fit(loadDataSet(xxx))
運用部分
val out = model.output(Nd4j.create(/*省略解説 インプット配列 AI.MaxInputStringLength文の長さを持つ*/))
この運用部分のoutの値がmodel.output
に何を渡しても常に一定の値になってしまします。(だいたい 0.99997754 みたいな)
渡すデータの次元を指定しないといけないのかなと思い
val out = model.output(Nd4j.create(inputBuff, intArrayOf(1, AI.MaxInputStringLength)))
にしてもやはり同じ値が返ってきました。