【发布时间】:2017-07-13 04:22:03
【问题描述】:
再次感谢您抽出宝贵时间阅读这篇文章。
我知道这个问题已经被问了很多,并且我查看了很多关于这个问题的帖子:但是,我对使用反向传播成功进行异或学习的探索仍未完成。
我按照建议尝试了调整学习率、动量、有/无偏差等,但仍然没有成功。
网络由 2 个输入神经元、2 个隐藏神经元、1 个输出、所有 Sigmoid 组成。 对于每个输入,输出神经元似乎总是收敛在 0.5 左右。
因此,我要求您提供宝贵的技能。 我正在使用自制的 C++ 库(这样我可以深入了解基础知识的工作原理)。
以下是我的代码的兴趣线:
从输出神经元获取误差导数
void ClOutputSigmoidNeuron::ComputeErrorGradient()
{
double wanted_output = this->m_dataset->GetNextData();
double delta = wanted_output - this->m_result_buffer;
this->m_error_gradient = delta * this->SigmoidDerivative(this->m_result_buffer);
}
获取隐藏神经元的误差导数
void ClSigmoidNeuron::ComputeErrorGradient()
{
double tmpBuffer = 0.00;
for(std::size_t i=0;i<this->m_output_connections.size();i++)
{
ClNeuron* target_neuron = (ClNeuron*)m_output_connections[i]->m_target_neuron;
tmpBuffer += (target_neuron->m_error_gradient * this->m_output_connections[i]->m_weight);
}
//Get the sigmoid derivative
this->m_error_gradient = tmpBuffer * this->SigmoidDerivative(this->m_result_buffer);
}
一般神经元的权重更新:
void ClNeuron::UpdateWeights()
{
for(std::size_t i=0;i<this->m_input_connections.size();i++)
{
double momentum = this->m_input_connections[i]->m_weight_last_delta * this->m_input_connections[i]->m_momentum_value;
double new_weight_delta = this->m_learning_rate * this->m_error_gradient * this->m_input_connections[i]->m_data + momentum ;
this->m_input_connections[i]->m_weight += new_weight_delta;
this->m_input_connections[i]->m_weight_last_delta = new_weight_delta;
this->m_input_connections[i]->m_number_of_time_updated++;
}
}
传递函数
double ClNeuron::Sigmoid(double p_value)
{
return 1.00 / (1.00 + std::exp(p_value*-1.00));
}
double ClNeuron::SigmoidDerivative(double p_value)
{
double sigmoid = this->Sigmoid(p_value);
return sigmoid * (1.00 - sigmoid);
}
用于训练的函数
bool ClBackPropagationSupervisedTrainer::Train()
{
for (std::size_t i = 0; i < this->m_dataset_size; i++)
{
this->m_network->Fire();
if (!this->m_network->ComputeErrorGradients())
{
std::cout << "ClBackPropagationSupervisedTrainer:Train - Oups" << std::endl;
return false;
}
this->m_network->UpdateWeights();
}
return true;
}
再次感谢您阅读本文,我知道这个问题被问了很多! 非常感谢您指出正确的方向。
【问题讨论】:
-
我一直在探索这个,只是注意到我的同样的问题。当我将双曲正切用于我的激活函数时,它运行良好。它也适用于泄漏的 ReLU。但从来没有用 ReLU 完全学会它。我仍在试图弄清楚为什么其中一些激活函数在这种微不足道的情况下不起作用。
标签: c++ neural-network backpropagation