2017-03-18 23 views
0

JavaScriptで勾配降下アルゴリズムを使用した非常に単純な線形回帰を実装しましたが、複数のソースを参照していくつかのことを試した後、収束することはできません。直線回帰の勾配降下が収束しない

データは絶対線形であり、入力としては0〜30の数字だけで、x * 3は正しい出力として学習します。

  • Andrew Ng's course on Gradient Descent for Linear Regression Nanodegree
  • (Udacityのディープラーニング基礎から

    • 演習:私は含めて、さまざまな場所から数式を取っ

      train(input, output) { 
          const predictedOutput = this.predict(input); 
          const delta = output - predictedOutput; 
      
          this.m += this.learningRate * delta * input; 
          this.b += this.learningRate * delta; 
      } 
      
      predict(x) { 
          return x * this.m + this.b; 
      } 
      

      この

      は勾配降下の背後にあるロジックですalso here
    • Stanford's CS229 Lecture Notes
    • this other PDF slides I found from Carnegie Mellon

    私はすでに試みた:

    • 正規化入力値と出力値を[-1、1]〜[0,1に
    • 正規化入力値と出力値の範囲]範囲
    • 平均値= 0、標準偏差= 1の正規化入出力値
    • 学習率を下げる(1e-7は私が行ったのと同じくらい低い)
    • 非ゼロバイアス(y = x * 3 + 2
    • -1と1の間のランダム
    • 非ゼロ値を持つ重みを初期化して設定線形データを有する全て( y = x * 3
    • にバイアスなしで設定線形データを有します

    なお、重み(this.bおよびthis.m)はデータ値に近づくことはなく、無限に広がります。

    明らかに何か間違っていますが、私はそれが何であるか把握できません。


    更新:オンライン学習によると、私は、一次関数に簡単な近似をモデル化しようとしている

    ここに私の問題は、正確に何であるかを見つけ出すことに役立ちもう少し文脈です線形回帰擬似ニューロン。それによって、私のパラメータは次のとおりです。

    • 重み:[this.mthis.b]
    • 入力:[x1]
    • 活性化機能:など、私のネットとしてのアイデンティティ機能z(x) = x

    y = this.m * x + this.b * 1で表され、近似したいデータ駆動関数をシミュレートします(y = 3 * x)。

    私のネットワークは、パラメータthis.m = 3this.b = 0を「学習」したいのですが、ローカルミニマムに陥っているようです。

    私の誤差関数は、平均二乗誤差である:

    error(allInputs, allOutputs) { 
        let error = 0; 
        for (let i = 0; i < allInputs.length; i++) { 
        const x = allInputs[i]; 
        const y = allOutputs[i]; 
        const predictedOutput = this.predict(x); 
        const delta = y - predictedOutput; 
    
        error += delta * delta; 
        } 
    
        return error/allInputs.length; 
    } 
    

    私の重みを更新するための私のロジックはのためにwi -= alpha * dError/dwi

    (私がこれまでにチェックした情報源による)になります私は体重をthis.mthis.bと呼びますので、JavaScriptコードに戻すことができます。予測値はy^とも呼ばれます。ここから

    :体重補正ロジックにあることを適用する

    error = y - y^ 
         = y - this.m * x + this.b 
    
    dError/dm = -x 
    dError/db = 1 
    

    そしてそう、:

    this.m += alpha * x 
    this.b -= alpha * 1 
    

    しかし、これは全く正しいようではありません。

    +0

    文脈のないコードがあるため、これは広すぎます。しかし、この '' 'this.m + = this.learningRate * delta * input;' 'は馴染んでいません。入力はここでは何もしません。バイアス処理も奇妙に見えます。私はJSに精通していないので、私はそれらの表現がベクトル化された表現であると期待していますか?そうでない場合は、最初から始めてください。 – sascha

    +0

    学習アルゴリズムは 'w + = learningRate * gradient * input'ではありませんか?それは、常に「m」に関して「y = m.x + b」の導関数の結果として現れる。 (どちらか、それとも私はそれを完全に誤解しています) – Alpha

    +0

    @sascha PS:これよりもはるかに多くのコードはありませんが、教えてください。 – Alpha

    答えて

    1

    私は最終的に何が間違っているのかを見つけました。この分野の初心者にも役立つことを願って私自身の質問に答えています。

    最初に、サシャが言ったように、理論的な誤解がありました。あなたの調整に入力値がそのまま含まれているのは正しいかもしれませんが、彼が言ったように、それは既にグラデーションの一部であるはずです。これはすべてエラー関数の選択に依存します。

    エラー機能は、実際の値からどれくらい離れているかを測定するために使用する測定値であり、その測定値は一貫している必要があります。私は平均平方誤差を測定ツールとして使用していました(私のerrorメソッドで見ることができますが)、トレーニング方法の中で純粋な絶対誤差(y^ - y)を使用してエラーを測定していました。 グラジエントは、このエラー機能の選択によって異なります。したがって、1つだけを選択してそれに固執してください。

    次に、は、何が間違っているかをテストするために仮定を単純化します。この場合、近似する関数は(y = x * 3)なので、重み付け(this.bthis.m)を手作業で正しい値に設定しても、エラーは発散することがわかりました。この場合、体重の初期化は問題ではないことを意味します。

    さらに検索したところ、私のエラーは他のものでした:ネットワークにデータを供給していた機能が誤って3の値を予測出力に渡していました。ネットワークがy = 0 * x + 3this.b = 3this.m = 0)に近似しようとしていたためでしたが、小さな学習率と誤差関数派生の誤差のためにthis.bは正しい値に近づかず、this.mとなりましたそれに適応するために野生のジャンプ。

    最後には、ネットワークがを訓練しているときにエラー測定値を記録しているので、何が起こっているかについての洞察を得ることができます。これは、簡単な過大フィット、大きな学習率、簡単な単純なミスの違いを識別するのに役立ちます。

    関連する問題