我正处于调试过程中的神经进化程序每次调用时都不会产生随机值。在程序中,使用以下语句初始化Network对象的向量:
vector<Network> population(POPULATION_SIZE, Network(sizes, inputCount));
为什么我认为该计划不会融合到一个最佳解决方案,总是,前100个人口是相同的。当以这种方式初始化网络时,连接权重和神经元偏差(每个)用以下类函数初始化:
double Network::randDouble(double low, double high) {
/*default_random_engine generator(std::chrono::system_clock::now().time_since_epoch().count());
uniform_real_distribution<double> distribution(low, high);
return distribution(generator);*/
/*srand(time(NULL));
double temp;
if (low > high) {
temp = low;
low = high;
high = temp;
}
temp = (rand() / (static_cast<double>(RAND_MAX) + 1.0)) * (high - low) + low;
return temp;*/
/*mt19937 rgn(std::chrono::system_clock::now().time_since_epoch().count());
uniform_real_distribution<double> gen(low, high);
return gen(rgn);*/
default_random_engine rd;
uniform_real_distribution<double> gen(low, high);
auto val = std::bind(gen, rd);
return val();
}
以前尝试过的3个注释掉的部分用于生成所需的功能。在每种情况下,它们为每个网络生成相同的数字(从1个权重到另一个权重,但不是1个网络到另一个网络)。尝试的方法基于这里的答案:
此外,第二种方法在有或没有种子的情况下产生相同的结果。我肯定错过了什么。
另一个尽管可能无关紧要的问题是,使用它的函数可以使用OpenMP并行化,并且当并行调用时,结果可能是相同的。
答案 0 :(得分:2)
您的问题是每次生成数字时都在初始化(播种)随机生成器。在简单srand()
的情况下,您应该在程序启动时只调用srand()
一次,然后在每次需要一个数字时调用rand()
。在更复杂的情况下,您应该只构建一次生成器(在整个程序运行中),并根据需要多次使用它。
答案 1 :(得分:1)
C ++ 11标准随机数引擎(以及大多数其他随机生成器)实际上是伪 - 随机数字序列的生成器。伪随机意味着序列是可重复的。每次给定的伪随机生成器播种相同的种子时,它将始终产生相同的序列。 (但这并不是你代码中发生的事情。请继续阅读。)
在C ++ 11中,播种发生在实例化随机数引擎时。这意味着您需要为每个伪随机序列实例化一次引擎。你的代码在每次调用Network :: randDouble()方法时播放引擎的方式,都不能指望得到引擎设计产生的伪随机序列。相反,您将从调用system_clock :: ...或time()方法的序列中获得一系列第一个数字。
对system_clock :: now()。time_since_epoch()。count()的调用以整数期间返回时间。 期间指的是模板类std :: chrono :: duration的特化,它由time_since_epoch()返回。默认情况下,该时间段可能是秒,这可以解释为什么所有网络对象在每次调用Network :: randDouble()时都会获得相同的种子。
如果您希望每个网络都有不同的序列,您应该更好地在网络类的 c-tor 中实例化伪随机引擎,并为每个对象播种不同的种子。网络课程。这意味着引擎或引擎对象的指针应该是该类的成员。
示例:
class Network {
...
protected:
mt19937 rd;
...
}
Network::Network(int rndseed) :
rd(rndseed)
{
...
}
double Network::randDouble(double low, double high) {
uniform_real_distribution<double> gen(low, high);
auto val = gen(rd);
return val;
}
为了确保伪随机引擎的每个实例都获得不同的种子,您可以使用像后续整数一样简单的东西。如果你想使用系统时钟,那么即使你使用std :: chrono :: high_resolution_clock,每次保证种子不同也要复杂得多。 CPU速度非常快,您需要特别注意确保您使用的时钟计数在两次调用之间实际发生了变化。