我正在研究一个神经网络项目,我有两个这样的课程:
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];
}
}
当我运行该代码时 - 我得到的内容(所有权重都相同):
当我看到它时 - 我试图调试并发现我的错误。但是,当我在神经元构造函数中放置断点时 - 我的网络根据需要进行初始化(权重不同):
我尝试使用调试和发布配置 - 结果相同。
有人能解释一下这里发生了什么吗?
魔术吗
答案 0 :(得分: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
(因此引入延迟时的差异)。如果每次都必须创建一个新实例,也可以提供自己的种子。
此行为记录为here,具体为:
...因为时钟具有有限的分辨率,使用无参数 构造函数以紧密连续的方式创建不同的Random对象 创建随机数生成器,生成相同的序列 随机数。 [...]通过创建单个问题可以避免此问题 随机对象而不是多个对象。
或者,您可以使用System.Security.Cryptography.RNGCryptoServiceProvider
。
答案 1 :(得分:8)
使用当前系统时间生成随机数。
在进行调试时,您可以在每一代之间进行一段时间。当你运行代码时,它运行得如此之快以至于种子是相同的,因此生成的randoms是相同的。
解决方案:声明一个类成员包含随机实例,并为每个新随机函数调用.Next()
方法。
private static rnd = new Random();
删除此行:
Random rnd = new Random();
你完成了
答案 2 :(得分:1)
创建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());
}
}