5

我正在做一个神经网络项目,我有两个这样的课程:

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 回答