非常奇怪 – 当我使用断点时,代码(使用Random)的工作方式不同

我正在研究一个神经网络项目,我有两个这样的类:

public class Net { // Net object is made of neurons public List Neurons = new List(); // 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 weights = new List(); // 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]; } } 

当我运行该代码时 – 我得到这样的东西 (所有权重都相同):

在此处输入图像描述

当我看到它时 – 我试图调试并发现我的错误。 但是, 当我在神经元构造函数中放置断点时 – 我的网络根据需要进行初始化(权重不同):

在此处输入图像描述

我尝试使用调试和发布配置 – 结果相同。

有人能解释一下这里发生了什么吗?

魔法?

但是,当我在神经元构造函数中放置断点时 – 我的网络初始化为我想要的(神经元是不同的):

据推测,断点为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

使用当前系统时间生成随机数。

在进行调试时,您可以在每一代之间进行一段时间。 当你运行代码时,它运行得如此之快以至于种子是相同的,因此,生成的randoms是相同的。

解决方案:声明一个类成员包含随机实例,并为每个新随机调用.Next()方法。

 private static rnd = new Random(); 

删除此行:

 Random rnd = new Random(); 

你完成了

创建一个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()); } }