57943


ディープラーニングはかなり駆け出しです。  
機械学習については基礎の基礎を勉強した程度の無知です。

ディープラーニングで時系列の予想を行いたいのですが何をしても出力結果がほぼ一定の値になってしまします。  
層の数を大きく変えても、活性化関数を見直して試行錯誤しても  
学習後のモデルに何を渡してもほぼ一定の値を返すようになってしまいます。

下記のコードや説明を見て間違っている部分ありましたら指摘いただきたいです。

# やりたいこと

  * 時系列株の予想（上昇、変わらず、下落 の3パターン）  
過去20日のデータを元に今後数日以内に上昇、変わらず、下落を予想

  * deeplearning4jを使用（時系列は再帰型ニューラルネットワークを使用すると良い？）

# 入力と出力

### 入力データのshapeは、[numExamples,inputSize,timeSeriesLength]

  * 現在学習はfitメソッドで1セットずつ行っているため`numExamples`は`1`
  * `inputSize`は時系列の日数である`20`
  * `timeSeriesLength`は時系列のパラメータで私の場合  
`始値`、`終値`、`独自のデータ`の3つ分なので`3`  
独自データとは、アルゴリズム考えるのが得意なので機械学習ではない方法で発見したアルゴリズムで計算したデータです。  
その日のとある変化を示し、将来の株価上下に明らかな関連性があるデータです。  
（なので実際、機械学習しなくてもいいのですが誤差を除去したりしたいので）

### 出力データのshapeは、[numExamples,outputSize,timeSeriesLength]

  * `timeSeriesLength`は上記入力で説明したとおり`1`
  * `outputSize`は`3`（上昇、変わらず、下落の3パターンを予測したいので）
  * `timeSeriesLength`は上記入力と合わせる必要があるみたいなので仕方なく`20`  
本来はアウトプットは1次元3要素であればいいのですが、、、

### 定数（試行錯誤中で全体的にコード整ってなくてすいません）

[code]

    //  【A】過去　解析データ
    //  入力データの数（シグナルの点灯、解析自体はこの日数に関係しない　あくまで入力データ数）
    const val analyzeDays = 20
    
    //  【B】未来　検知の有効期限
    //  シグナル検知後、何日後までの株価上下を当たりとするか
    const val signalLimitDays = 10
    
    const val numInputs = 3
    //const val numHiddenNodes = 1000
    const val numOutputs = 1
    
[/code]

### ネットワーク

[code]

    fun createNeurarlNetwork(): MultiLayerNetwork {
        val conf = NeuralNetConfiguration.Builder()
                .seed(1992)
                //.iterations(iterations)
                .updater(RmsProp(0.01))
                .optimizationAlgo(OptimizationAlgorithm.STOCHASTIC_GRADIENT_DESCENT)
                .weightInit(WeightInit.XAVIER)
                //.regularization(true)
                .l2(1e-4)
                .list()
                .layer(0, GravesLSTM.Builder().nIn(numInputs).nOut(512).activation(Activation.TANH).gateActivationFunction(Activation.HARDSIGMOID).dropOut(0.1).build())
                .layer(1, GravesLSTM.Builder().nIn(512).nOut(512).activation(Activation.TANH).gateActivationFunction(Activation.HARDSIGMOID).dropOut(0.1).build())
                .layer(2, DenseLayer.Builder().nIn(512).nOut(128).activation(Activation.RELU).build())
                .layer(3, RnnOutputLayer.Builder().nIn(128).nOut(numOutputs).activation(Activation.IDENTITY).lossFunction(LossFunctions.LossFunction.MSE).build())
                .backpropType(BackpropType.TruncatedBPTT)
                .tBPTTForwardLength(analyzeDays)
                .tBPTTBackwardLength(analyzeDays)
                .validateOutputLayerConfig(false)
                //.pretrain(false)
                //.backprop(true)
                .build()
        val net = MultiLayerNetwork(conf)
        net.init()
        return net
    }
    
[/code]

### 学習（学習データの 上昇、変わらず、下落 のデータパターンはおなじ数になるように用意しています）

[code]

    //  データ構成
    var inIdx = 0
    val inBuff = FloatArray(3*analyzeDays)
    
    //  【A】過去を格納
    for (i in 0 until analyzeDays) {
        val r = res[i]
        inBuff[inIdx++] = r.data.start
        inBuff[inIdx++] = r.data.end
        inBuff[inIdx++] = r.magnitude
        //inBuff[inIdx++] = r.resistance
    }
    
    //
    //  B期間で株価の上下が見られるか解析
    //--
    
    省略
    inBuffに格納したデータの正解（期待値）
    
    val outBuff = 
    
    //  正解が上昇の場合
    floatArrayOf(1F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F)
    
    //  正解が変わらずの場合
    floatArrayOf(0F, 1F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F)
    
     //  正解が下落場合
    floatArrayOf(0F, 0F, 1F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F)
     //--
     //             
    
     for (i in 0..5) {
         neuralNetwork.fit(
             Nd4j.create(
                            inBuff,
                            intArrayOf(1, 3, analyzeDays)
                        ),
             Nd4j.create(
                            outBuff,
                            intArrayOf(1, numOutputs, analyzeDays)
                        )
             )
     }
    
[/code]

### 実用（予想）

[code]

    //  inputは上記「学習」と同じ形式
    neuralNetwork.output(
                        Nd4j.create(
                                inBuff,
                                intArrayOf(1, 3, analyzeDays)
                        )
    )
    
[/code]

### 出力結果

[code]

    [[[    0.3230,    0.3230,    0.2329,    0.0089,   -0.0144,   -0.0179,   -0.0185,   -0.0186,   -0.0186,   -0.0186,   -0.0186,   -0.0186,   -0.0186,   -0.0186,   -0.0186,   -0.0186,   -0.0186,   -0.0186,   -0.0186,   -0.0186]]]
    
[/code]

### ↑入力に度のデータを渡しても上記とほぼ変わらない一定の値になってしまいます。

[code]

    [[[    0.3230,    0.3230,    0.2144,    0.0076,   -0.0147,   -0.0180,   -0.0185,   -0.0186,   -0.0186,   -0.0186,   -0.0186,   -0.0186,   -0.0186,   -0.0186,   -0.0186,   -0.0186,   -0.0186,   -0.0186,   -0.0186,   -0.0186,   -0.0186,   -0.0186,   -0.0186,   -0.0186,   -0.0186,   -0.0186,   -0.0186]]]
    
[/code]

学習の様子を見ているとうまく進んでいるように見えますがこのような結果になってしまいます。  
学習データは10年間の全銘柄分あるので十分なはずなのでなにか根本的に間違っているのでしょうが  
いくら時間をかけても解決できないのでどうかお力を貸していただけるとうれしいです。


CC BY-SA 4.0
2019-09-07T18:31:58.053
57922
2019-09-09T03:18:25.197
10346
question
機械学習 深層学習 deeplearning4j
ディープラーニングで出力される予想が常に一定の値


今の実装の方針で直近20回のデータから回帰で予測する場合の出力の教師データは次のような形じゃないかと思います。

[code]

    //  正解が上昇の場合
    floatArrayOf(0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 1F)
    
    //  正解が変わらずの場合
    floatArrayOf(0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F)
    //  正解が下落場合
    floatArrayOf(0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, -1F)
    
[/code]

「本来はアウトプットは1次元3要素であればいいのですが」ということで時系列として出力する必要がなければ1次元畳み込みで実装もできそうです。  
また、上昇、変わらず、下落 の3パターンということでしたら、`numOutputs =
3`で`Activation.SOFTMAX`と`LossFunction.NEGATIVELOGLIKELIHOOD`で実装してもいいのではないでしょうか。


CC BY-SA 4.0
2019-09-09T03:18:25.197
57943
2019-09-09T03:18:25.197
241
57922
answer