記事「MQL5行列を使用した誤差逆伝播法によるニューラルネットワーク」についてのディスカッション - ページ 2

 
Lorentzos Roussos #:

しかし、活性化値は導出関数に渡され、導出関数は活性化前の値を期待します。そういうことだ。

あなたは間違っていると思います。y'(x)=y(x)*(1-y(x))、ここでxは活性化前のニューロンの状態、y(x)は活性化関数を適用した結果です。導出を計算するために活性化前の値を使用せず、代わりに活性化の結果(y)を使用 します。以下に簡単なテストを示す:

double derivative(double output)
{
  return output * (1 - output);
}

void OnStart()
{
  vector x = {{0.68}};
  vector y;
  x.Activation(y, AF_SIGMOID);                            // y[0]に "y(x) "として活性化/シグモイドの結果を取得
  vector d;
  x.Derivative(d, AF_SIGMOID);                            // x におけるシグモイドの導関数を得る
  Print(derivative(x[0]), " ", derivative(y[0]), " ", d); //0.2176 0.2231896389723258 [0.2231896389723258]
}
 
Stanislav Korotky #:

あなたは間違っていると思う。y'(x)=y(x)*(1-y(x))、ここでxは活性化前のニューロンの状態、y(x)は活性化関数を適用した結果です。導出を計算するために活性化前の値を使用せず、代わりに活性化の結果(y)を使用 します。以下に簡単なテストを示す:

正しい導関数はx値から呼び出された導関数と一致します。

バックプロップ関数では、同等のy.Derivative(d,AF_SIGMOID)を呼び出しています。

記事のバックプロップでは出力行列はyであり、そこから導関数を呼び出すためにxと等価な行列を保存しているとは思えません。

(これもmq関数によると)

--

あなたの例でも、xから微分を呼び出している。

ロシア語のフォーラムで教えてあげればいい。彼らがドキュメントにそれを追加することができれば、多くの人々の時間を節約することができます。

ありがとう。

 
Stanislav Korotky #:

あなたは間違っていると思う。y'(x)=y(x)*(1-y(x))、ここでxは活性化前のニューロンの状態、y(x)は活性化関数を適用した結果です。導出を計算するために活性化前の値を使用せず、代わりに活性化の結果(y)を使用 します。以下に簡単なテストを示す:

単純化してみましょう。

これはあなたの例です。

double derivative(double output)
{
  return output * (1 - output);
}

void OnStart()
{
  vector x = {{0.68}};
  vector y;
  x.Activation(y, AF_SIGMOID);                            // y[0]に "y(x) "として活性化/シグモイドの結果を取得
  vector d;
  x.Derivative(d, AF_SIGMOID);                            // x におけるシグモイドの導関数を得る
  Print(derivative(x[0]), " ", derivative(y[0]), " ", d); //0.2176 0.2231896389723258 [0.2231896389723258]
}

あなたの例では、導関数ベクトルdを埋めるためにx.Derivativeを呼び出して います。

y.Derivativeを呼び出して 導関数を埋めていないのはなぜですか?それは間違った値を返すからです。(そして、おそらくあなたはそれを見たからx.Derivativeを 使ったのでしょう)。

yとは 何ですか?xの 活性化値です。

ということは、これを実行すると:

x.Activation(y, AF_SIGMOID);  

yを xの 活性化値で埋めていますが、yではなくxに対して 導関数を呼び出しています。

あなたの記事では、フィードフォワードのテンポは x であり

matrix temp = outputs[i].MatMul(weights[i]);

そしてyは xの 活性化値と なります。 それはどのような行列ですか?

temp.Activation(outputs[i + 1], i < n - 1 ? af : of)

出力 です。 記事中のy( 例では微分を呼び出していない)は 出力 行列です

(私たちが上のコードで見ているのは、例のx.Activation(y,AF)に相当するもので、yを活性化値で埋めます。)

あなたのバックプロップコードではx.Derivativeを呼び出して いません。なぜならx(matrix temp = outputs[i].MatMul(weights[i]);)

はどこにも保存されておらず、呼び出すことはできません。y.Derivativeを呼び出して いますが、これは間違った値を返します。

outputs[n].Derivative(temp, of)
outputs[i].Derivative(temp, af)

なぜならyは 活性化値を持って いるからです。

繰り返しますが、mql5関数によると、y.Derivativeは間違った値を返します。

ですから、あなたの例では正しい呼び出しをしていますが、あなたの記事では間違った呼び出しをしていることになります。

乾杯

 

これが欲しいんだね:

   bool backProp(const matrix &target)
   {
      if(!ready) return false;
   
      if(target.Rows() != outputs[n].Rows() ||
         target.Cols() != outputs[n].Cols())
         return false;
      
      // 出力層
      matrix temp;
      //*if(!outputs[n].Derivative(temp, of))
      //* false を返す;
      if(!outputs[n - 1].MatMul(weights[n - 1]).Derivative(temp, of))
         return false;
      matrix loss = (outputs[n] - target) * temp; // 行ごとのデータレコード
     
      for(int i = n - 1; i >= 0; --i) // 出力を除く各レイヤー
      {
         //*// remove unusable pseudo-errors for neurons, added as constant bias source
         //*// (in all layers except for the last (where it wasn't added))
         //*if(i < n - 1) loss.Resize(loss.Rows(), loss.Cols() - 1);
         #ifdef  BATCH_PROP
         matrix delta = speed[i] * outputs[i].Transpose().MatMul(loss);
         adjustSpeed(speed[i], delta * deltas[i]);
         deltas[i] = delta;
         #else
         matrix delta = speed * outputs[i].Transpose().MatMul(loss);
         #endif
         
         //*if(!outputs[i].Derivative(temp, af))
         //* false を返す;
         //*loss = loss.MatMul(weights[i].Transpose()) * temp;
         if(i > 0) // 損失を前のレイヤーに逆伝播する
         {
            if(!outputs[i - 1].MatMul(weights[i - 1]).Derivative(temp, af))
               return false;
            matrix mul = loss.MatMul(weights[i].Transpose());
            定数バイアスソースとして追加されたニューロンについて、 // 使えない擬似エラーを取り除く
            mul.Resize(mul.Rows(), mul.Cols() - 1);
            loss = mul * temp;
         }
         
         weights[i] -= delta;
      }
      return true;
   }

考えておくよ。

 
Stanislav Korotky #:

だから、これが欲しいんだろ:

考えておくよ。

一見したところ、問題なさそうだ。その場で計算した方が、ストレージより早いと思う。

👍

 
Lorentzos Roussos #:

一見、問題なさそうに見える。その場での計算は、ストレージよりも速いと思います。

もともと活性化関数の出力を介してコード化されている理由がわかった気がする。というのも、その方がシンプルで効果的だからです(行列APIに適応している間は、その違いに注意を払っていませんでした)。例えば

sigmoid' = sigmoid * (1 - sigmoid)
tanh' = 1 - tanh^2
softsign' = (1 - |softsign|)^2

この方法だと、アクティベーション前の引数(行列)を保持したり、バックプロパゲーションの段階で再計算したりする必要がない(修正版ではそうなっている)。私はどちらのアプローチも好きではない。いわば「自己微分」の計算の方がエレガントに見える。したがって、私はサポートされているすべての(あるいは多くの)活性化関数の自己導関数に関する公式が書かれたリファレンスを見つけ、元のアプローチに戻りたい。

興味深いのは、自己導関数が活性化関数から厳密に導かれる必要はなく、同等の効果を持つ関数であれば何でもいいということだ。
 
Stanislav Korotky #:

元々活性化関数の出力を介してコード化されている理由はわかっているつもりだ。というのも、その方がシンプルで効果的だからだ(行列APIに適応している間は、その違いに注意を払っていなかった)。例えば

この方法だと、アクティベーション前の引数(行列)を保持したり、バックプロパゲーションの段階で再計算したりする必要がない(修正版ではそうなっている)。私はどちらのアプローチも好きではない。いわば「自己微分」の計算の方がエレガントに見える。したがって、サポートされているすべての(あるいは多くの)活性化関数の自己導関数に関する公式が書かれたリファレンスを見つけ、元のアプローチに戻りたい。

しかし、mqはこの方法を採用したので、すべての活性化関数に適用されます。

簡単に言うと、.Derivative 関数が活性化関数に「適応」する代わりに(あなたが言った3つの関数が出力を受け取ることができるように)、関数が活性化前の値を受け取るようにしたのです。それはいいのですが、問題はそれがドキュメントに書かれていない ことです

誰が見ても、デフォルトではAFに適応するという前提になっている。

これは(例えば私のような)新参者にとっては良くないことで、始める前から "取り組む "ことになる。

(オブジェクト・ベースとマトリックス・ベースのネットワークの比較も非常に興味深い記事になるだろうし、数学に詳しくない多くのコーダーの助けになるだろう)。

とにかく、私はそれをモデレーターがドキュメンテーションの問題を報告するために持っているスレッドに 置いた。

(オフトピック : このTanHを使うことができます。)

double customTanH(double of){
  double ex=MathExp(2*of);
  return((ex-1.0)/(ex+1.0));
}
興味深いのは、自己微分式が活性化関数から厳密に導かれる必要はないということです。

つまり「代用」ですか?

例えば、あるノードの出力にエラーが発生した場合、その出力の「ゆらぎ」がわかっているので、より単純な活性化関数に「シフト」して導けばうまくいく、ということですか?

つまり、理論的には出力を「正則化」するようなもので、正則化を行わず、活性化の導関数の前に正則化の導関数を乗じるだけなのでしょうか?

例えば.

tanh output -1 -> +1 
sigmoid output 0 -> +1 
tanh to sigmoid output = (tanh_out+1)/2.0
and you just multiply by the derivative of that which is 0.5 ? (without touching the tanh outputs at all)
mql5 documentation errors, defaults or inconsistencies.
mql5 documentation errors, defaults or inconsistencies.
  • 2023.04.07
  • www.mql5.com
Page : https://www.mql5.com/en/docs/globals/globalvariabletime This is inexact, GlobalVariableCheck() does NOT modify the last access time. 2023.04...
 
バグ修正。
ファイル:
MatrixNet.mqh  23 kb
 

この件に関して、管理者がモデレーターのスレッドに返信しました。興味があるかもしれない

取引、自動売買システム、取引戦略のテストに関するフォーラム

mql5ドキュメントのエラー、デフォルト、または矛盾。

ラシッドウマロフ、2023.04.18 11:36

できるだけ早く改善されます。しばらくの間、このインクルードファイルを参考としてお使いください。

Stanislav Korotky
 
Stanislav Korotky # : バグ修正。

スタニスラフ・コロツキー

ニューラルネットワークのコンセプトをMQLに取り入れたあなたの努力は高く評価できる。これは私のような初心者にとって、本当に素晴らしい作品だ。ありがとう。)

バグを修正したファイルを更新してくれてありがとう。 しかし、ダウンロードエリアのファイルを差し替えた方がいいと思います。

幸いなことに、私はこのトピックに関するディスカッションを調べ、ファイルにバグがあることを知りました。そして、今、私は修正を探そうとしていたよりも、私はここにこのファイルのリンクを見つけました。

行番号490-493, 500, 515-527にバグフィックスのためのこれらの場所があることを望みます。それ以外の場所であれば、行番号に言及するか、//*BugFix ... をマークしてください。

よろしくお願いします。