我一直在阅读有关神经网络的信息,并使用backprogpagation进行培训,主要是this Coursera course,还有来自here和here的额外阅读。我以为我对核心算法的掌握非常好,但是我尝试构建一个反向传播训练的神经网络还没有完全解决,我不知道为什么。
代码是C ++,目前还没有矢量化。
我想构建一个简单的2输入神经元,1个隐藏神经元,1个输出神经元,网络来模拟AND功能。只是为了理解这些概念在进入更复杂的例子之前是如何工作的当我在权重和偏差的值中手工编码时,我的前向传播代码就起作用了。
float NeuralNetwork::ForwardPropagte(const float *dataInput)
{
int number = 0; // Write the input data into the input layer
for ( auto & node : m_Network[0])
{
node->input = dataInput[number++];
}
// For each layer in the network
for ( auto & layer : m_Network)
{
// For each neuron in the layer
for (auto & neuron : layer)
{
float activation;
if (layerIndex != 0)
{
neuron->input += neuron->bias;
activation = Sigmoid( neuron->input);
} else {
activation = neuron->input;
}
for (auto & pair : neuron->outputNeuron)
{
pair.first->input += static_cast<float>(pair.second)*activation;
}
}
}
return Sigmoid(m_Network[m_Network.size()-1][0]->input);
}
其中一些变量命名相当差,但基本上,神经元 - >输出神经元是对的矢量。第一个是指向下一个神经元的指针,第二个是重量值。神经元 - >输入是神经网络方程中的“z”值,即所有wieghts *激活+ bais的总和。 Sigmoid由下式给出:
float NeuralNetwork::Sigmoid(float value) const
{
return 1.0f/(1.0f + exp(-value));
}
这两个似乎按预期工作。通过网络后,所有'z'或'neuron-&gt;输入'值将重置为零(或反向传播后)。
然后我按照下面的psudo代码训练网络。培训代码多次运行。
for trainingExample=0 to m // m = number of training examples
perform forward propagation to calculate hyp(x)
calculate cost delta of last layer
delta = y - hyp(x)
use the delta of the output to calculate delta for all layers
move over the network adjusting the weights based on this value
reset network
实际代码在这里:
void NeuralNetwork::TrainNetwork(const std::vector<std::pair<std::pair<float,float>,float>> & trainingData)
{
for (int i = 0; i < 100; ++i)
{
for (auto & trainingSet : trainingData)
{
float x[2] = {trainingSet.first.first,trainingSet.first.second};
float y = trainingSet.second;
float estimatedY = ForwardPropagte(x);
m_Network[m_Network.size()-1][0]->error = estimatedY - y;
CalculateError();
RunBackpropagation();
ResetActivations();
}
}
}
使用反传播函数:
void NeuralNetwork::RunBackpropagation()
{
for (int index = m_Network.size()-1; index >= 0; --index)
{
for(auto &node : m_Network[index])
{
// Again where the "outputNeuron" is a list of the next layer of neurons and associated weights
for (auto &weight : node->outputNeuron)
{
weight.second += weight.first->error*Sigmoid(node->input);
}
node->bias = node->error; // I'm not sure how to adjust the bias, some of the formulas seemed to point to this. Is it correct?
}
}
}
和计算成本:
void NeuralNetwork::CalculateError()
{
for (int index = m_Network.size()-2; index > 0; --index)
{
for(auto &node : m_Network[index])
{
node->error = 0.0f;
float sigmoidPrime = Sigmoid(node->input)*(1 - Sigmoid(node->input));
for (auto &weight : node->outputNeuron)
{
node->error += (weight.first->error*weight.second)*sigmoidPrime;
}
}
}
}
我将权重随机化并在数据集上运行:
x = {0.0f,0.0f} y =0.0f
x = {1.0f,0.0f} y =0.0f
x = {0.0f,1.0f} y =0.0f
x = {1.0f,1.0f} y =1.0f
当然,我不应该使用相同的数据集进行训练和测试,但我只是想让基本的反向传播算法运行起来。当我运行此代码时,我看到权重/偏差如下:
Layer 0
Bias 0.111129
NeuronWeight 0.058659
Bias -0.037814
NeuronWeight -0.018420
Layer 1
Bias 0.016230
NeuronWeight -0.104935
Layer 2
Bias 0.080982
训练集运行并且delta [outputLayer]的均方误差看起来像:
Error: 0.156954
Error: 0.152529
Error: 0.213887
Error: 0.305257
Error: 0.359612
Error: 0.373494
Error: 0.374910
Error: 0.374995
Error: 0.375000
... remains at this value for ever...
最终的权重看起来像:(他们总是以这个价值结束)
Layer 0
Bias 0.000000
NeuronWeight 15.385233
Bias 0.000000
NeuronWeight 16.492933
Layer 1
Bias 0.000000
NeuronWeight 293.518585
Layer 2
Bias 0.000000
我接受这似乎是学习神经网络的一种迂回方式,而且(目前)实施非常不理想。但是,任何人都可以发现我做出无效假设的任何一点,或者执行或公式是错误的吗?
修改
感谢偏置值的反馈,我停止将它们应用于输入层并停止通过sigmoid函数传递输入层。另外我的Sigmoid主要功能无效。但网络仍然无法正常工作。我已经更新了上面的错误和输出,现在发生了什么。
答案 0 :(得分:4)
正如lejilot所说,那里你有很多偏见。 你不需要在最后一层中存在偏差,它是一个输出层,偏置必须连接到它的输入,而不是它的输出。看一下下图:
在此图片中,您可以看到每层只有一个偏差,除了最后一个偏差,不需要偏差。
Here you can read一种非常直观的神经网络方法。它是在Python中,但它可以帮助您更好地理解神经网络的一些概念。
答案 1 :(得分:1)
我解决了我的问题(超出了上面的最初偏见/签署的主要问题)。我开始减去而不是增加权重。在我看到的来源中,他们在delta值计算中有一个减号,我没有,但我保持他们的格式为权重添加否定值。另外,我很困惑如何处理重量并误读了一个来源,它将其分配给错误。我现在看到直觉将它视为正常体重,但乘以偏差常数1而不是z。在我添加了这些更改后,迭代训练集~1000次可以模拟简单的按位表达式,如OR和AND。