5

私はニューラルネットワークプロジェクトに取り組んでおり、次のような2つのクラスがあります:

public class Net
{
    // Net object is made of neurons
    public List<Neuron> Neurons = new List<Neuron>();

    // neurons are created in Net class constructor
    public Net(int neuronCount, int neuronInputs)
    {
        for (int n = 0; n < neuronCount; n++)
        {
            Neurons.Add(new Neuron(n, neuronInputs));
        }
    }
}

public class Neuron
{
    public int index; // neuron has index

    public List<double> weights = new List<double>(); // and list of weights

    // Neuron constructor is supposed to add random weights to new neuron
    public Neuron(int neuronIndex, int neuronInputs)
    {
        Random rnd = new Random();

        for (int i = 0; i < neuronInputs; i++)
        {
            this.index = neuronIndex;
            this.weights.Add(rnd.NextDouble());
        }
    }

ネットワークを作成して表示しようとすると、「コンテンツ」です。

Neuro.Net Network = new Neuro.Net(4, 4); // creating network with 4 neurons with 4 weights each

// dgv is a DataGridView for weights preview
dgv.Rows.Clear();
dgv.Columns.Clear();

// creating columns
foreach (Neuro.Neuron neuron in Network.Neurons)
{
    dgv.Columns.Add("colN" + neuron.index, "N" + neuron.index);
}

dgv.Rows.Add(Network.Neurons[0].weights.Count());

for (int n = 0; n < Network.Neurons.Count(); n++)
{
   for (int w = 0; w < Network.Neurons[n].weights.Count(); w++)
   {
       dgv.Rows[w].Cells[n].Value = Network.Neurons[n].weights[w];
   }
}

そのコードを実行すると、次のような結果が得られます(すべての重みは同じです)。

ここに画像の説明を入力

私がそれを見たとき - 私は自分の間違いをデバッグして見つけようとしました。ただし、ニューロン コンストラクターにブレークポイントを配置すると、ネットワークが必要に応じて初期化されます (重みが異なります)。

ここに画像の説明を入力

デバッグ構成とリリース構成を使用しようとしましたが、結果は同じでした。

誰かがここで何が起こっているのか説明できますか?

魔法?

4

3 に答える 3

14

ただし、ニューロン コンストラクターにブレークポイントを配置すると、ネットワークは必要に応じて初期化されます (ニューロンは異なります)。

おそらく、ブレークポイントはRandom()、別の数でシードされるのに十分な遅延をもたらします。遅延は、(明らかに) コードを一時停止することによって、または条件付きブレークポイントの一致しない評価 (実行がわずかに遅くなる) によって引き起こされる可能性があります。

持っている方が良いでしょう:

private static readonly Random _random = new Random();

_random.Next()次のように、新しいインスタンスを作成せずに呼び出します。

public Neuron(int neuronIndex, int neuronInputs)
{
    for (int i = 0; i < neuronInputs; i++)
    {
        this.index = neuronIndex;
        this.weights.Add(_random.NextDouble());
    }
}

Random のパラメーターなしのコンストラクターが使用しますEnvironment.TickCount(したがって、遅延が導入された場合の違い)。毎回新しいインスタンスを作成する必要がある場合は、独自のシードを提供することもできます。

この動作は、具体的には次の場所に文書化されています。

...クロックの分解能は有限であるため、パラメーターなしのコンストラクターを使用して異なる Random オブジェクトを連続して作成すると、同一の乱数シーケンスを生成する乱数ジェネレーターが作成されます。[...] この問題は、複数のオブジェクトではなく単一の Random オブジェクトを作成することで回避できます。

または、 を使用することもできますSystem.Security.Cryptography.RNGCryptoServiceProvider

于 2013-03-01T16:17:01.510 に答える
8

乱数は、現在のシステム時刻を使用して生成されます。

デバッグするときは、各世代の間に時間を空けます。コードを実行すると、非常に高速に実行されるため、シードが同じであるため、生成されるランダムは等しくなります。

解決策: ランダム インスタンスを含むクラス メンバーを宣言し、新しいランダムごとに.Next()メソッドを呼び出します。

private static rnd = new Random();

次の行を削除します。

Random rnd = new Random();

そして、あなたは終わった

于 2013-03-01T16:16:36.720 に答える
2

Randomクラスの静的インスタンスを作成します。

コンストラクター内では、毎回 Random が初期化されるため、同様の数値が発生する可能性があります!

private static readonly Random rnd = new Random();
public Neuron(int neuronIndex, int neuronInputs)
{
    private static readonly rnd = new Random();     

    for (int i = 0; i < neuronInputs; i++)
    {
        this.index = neuronIndex;
        this.weights.Add(rnd.NextDouble());
    }
}
于 2013-03-01T16:19:53.710 に答える