【发布时间】:2017-11-30 06:44:38
【问题描述】:
我很难生成一个最小的示例,因为我认为它与我的更多代码有关。不过,我相信我已经在下面提供了相关代码。
我已经删除了我认为对问题不是很重要的类等部分。
我有一个使用神经元的神经网络类:
神经元
template<std::size_t NumInputs>
class Neuron
{
public:
Neuron()
{
for(auto& i : m_inputValues)
i = 0;
for(auto& e : m_eligibilityTraces)
e = 0;
for(auto& w : m_weights)
w = 0;
m_biasWeight = 0;
m_biasEligibilityTrace = 0;
m_outputValue = 0;
}
void SetInputValue(const std::size_t index, const double value)
{
m_inputValues[index] = value;
}
void SetWeight(const std::size_t index, const double weight)
{
if(std::isnan(weight))
throw std::runtime_error("Shit! this is a nan bread");
m_weights[index] = weight;
}
void SetBiasWeight(const double weight)
{
m_biasWeight = weight;
}
double GetInputValue(const std::size_t index) const
{
return m_inputValues[index];
}
double GetWeight(const std::size_t index) const
{
return m_weights[index];
}
double GetBiasWeight() const
{
return m_biasWeight;
}
double CalculateOutput()
{
double m_outputValue = 0;
for(std::size_t i = 0; i < NumInputs; ++i)
{
m_outputValue += m_inputValues[i] * m_weights[i];
}
m_outputValue += 1.0 * m_biasWeight;
m_outputValue = sigmoid(m_outputValue);
return m_outputValue;
}
double GetOutput() const
{
return m_outputValue;
}
double GetEligibilityTrace(const std::size_t index) const
{
return m_eligibilityTraces[index];
}
void SetEligibilityTrace(const std::size_t index, const double eligibility)
{
m_eligibilityTraces[index] = eligibility;
}
void SetBiasEligibility(const double eligibility)
{
m_biasEligibilityTrace = eligibility;
}
double GetBiasEligibility() const
{
return m_biasEligibilityTrace;
}
private:
std::array<double,NumInputs> m_inputValues;
std::array<double,NumInputs> m_weights;
std::array<double,NumInputs> m_eligibilityTraces;
double m_biasWeight;
double m_biasEligibilityTrace;
double m_outputValue;
};
神经网络
template<std::size_t NumInputs, std::size_t NumHidden, std::size_t NumOutputs>
class NeuralNetwork
{
public:
...
std::array<double,NumOutputs> FeedForward(const std::array<double,NumInputs>& inputValues)
{
for(auto& hiddenNeuron : m_hiddenNeurons)
{
for(std::size_t i = 0; i < NumInputs; ++i)
hiddenNeuron.SetInputValue(i,inputValues[i]);
hiddenNeuron.CalculateOutput();
}
std::array<double, NumOutputs> returnValue;
for(std::size_t h = 0; h < NumHidden; ++h)
{
auto hiddenOutput = m_hiddenNeurons[h].GetOutput();
for(std::size_t o = 0; o < NumOutputs; ++o)
m_outputNeurons[o].SetInputValue(h, hiddenOutput);
}
for(std::size_t o = 0; o < NumOutputs; ++o)
{
returnValue[o] = m_outputNeurons[o].CalculateOutput();
}
return returnValue;
}
private:
std::array<Neuron<NumInputs>,NumHidden> m_hiddenNeurons;
std::array<Neuron<NumHidden>,NumOutputs> m_outputNeurons;
};
对于NeuralNetwork<86,86,2>,一切正常,但考虑到我需要更多输入变量,即NeuralNetwork<170,170,2>,当我启用-O2 编译器标志时,FeedForward 方法会产生堆栈溢出。设置-g 标志不会产生此问题。
如果我删除 FeedForward 方法的这一部分,我不会得到堆栈溢出:
for(std::size_t h = 0; h < NumHidden; ++h)
{
auto hiddenOutput = m_hiddenNeurons[h].GetOutput();
for(std::size_t o = 0; o < NumOutputs; ++o)
m_outputNeurons[o].SetInputValue(h, hiddenOutput);
}
我不明白为什么会产生堆栈溢出。隐藏单元数为170,输出单元数为2;当然这还不足以导致溢出,尤其是考虑到上面我循环了 170 个输入到 170 个隐藏单元。
正如您在Neuron 类中看到的,GetOutput() 方法不涉及任何其他函数调用,SetInputValue() 也不做类似的事情。没有递归。
删除的部分在没有内部循环的情况下可以正常工作。但是下面的循环会导致堆栈溢出。
即这会导致堆栈溢出:
for(std::size_t h = 0; h < NumHidden; ++h)
{
auto hiddenOutput = m_hiddenNeurons[h].GetOutput();
// for(std::size_t o = 0; o < NumOutputs; ++o)
// m_outputNeurons[o].SetInputValue(h, hiddenOutput);
}
for(std::size_t o = 0; o < NumOutputs; ++o)
{
returnValue[o] = m_outputNeurons[o].CalculateOutput();
}
而这不是:
for(std::size_t h = 0; h < NumHidden; ++h)
{
auto hiddenOutput = m_hiddenNeurons[h].GetOutput();
// for(std::size_t o = 0; o < NumOutputs; ++o)
// m_outputNeurons[o].SetInputValue(h, hiddenOutput);
}
for(std::size_t o = 0; o < NumOutputs; ++o)
{
//returnValue[o] = m_outputNeurons[o].CalculateOutput();
}
这没有意义,因为循环没有嵌套......
【问题讨论】:
-
NumOutputs的典型值是多少?returnValue分配在堆栈上,所以如果它足够大,它会导致你的问题。在您的“不”示例中,由于您从不写信给它,returnValue可能会被优化掉。 -
NumOutputs是 2 -
另外:你是在堆栈还是堆上分配网络?那是一个大类,所以当你到达那个点时,你可能已经没有多少筹码了。
-
我在堆栈上分配。但你知道为什么,我刚刚意识到我正在复制它,而这在代码的另一部分是不必要的。在我调用
FeedForward时,第二个本地堆栈变量应该已经被删除,但删除它似乎可以解决问题。将来,我会在堆上分配这么大的东西 -
在 Windows 上,默认最大值。堆栈大小为每个线程 1MB。在我的计算中,您的
NeuralNetwork<170,170,2>已经大于 700,000 字节。我推荐像std::make_unique<NeuralNetwork<170, 170, 2>>这样的堆分配。
标签: c++ stack-overflow