一些背景信息:
我在C++中编写了一个单层多输出感知器类。它使用典型的WX + b判别函数,并允许用户定义激活函数。我已经相当彻底地测试了所有内容,一切似乎都按预期工作。我注意到代码中有一个小逻辑错误,当我尝试修复它时,网络的表现比之前差得多。错误如下:
我使用以下代码评估每个输出神经元的值:
output[i] = activate_(std::inner_product(weights_[i].begin(), weights_[i].end(), features.begin(), -1 * biases_[i]));
在这里,我将偏置输入视为固定的-1,但当我对每个偏置应用学习规则时,我将输入视为+1。
// 偏置可以被视为具有恒定特征值1的权重。biases_[i] = weight_update(1, error, learning_rate_, biases_[i]);
所以我尝试通过更改对weight_updated的调用来修复我的错误,使其与输出评估一致:
biases_[i] = weight_update(-1, error, learning_rate_, biases_[i]);
但这样做导致准确率下降了20%!过去几天我一直在试图找出代码中可能解释这种奇怪行为的其他逻辑错误,但一无所获。是否有比我更有知识的人能提供一些见解?我在下面提供了整个类供参考。提前感谢您。
#ifndef SINGLE_LAYER_PERCEPTRON_H#define SINGLE_LAYER_PERCEPTRON_H#include <cassert>#include <functional>#include <numeric>#include <vector>#include "functional.h"#include "random.h"namespace qp {namespace rf {namespace {template <typename Feature>double weight_update(const Feature& feature, const double error, const double learning_rate, const double current_weight) { return current_weight + (learning_rate * error * feature);}template <typename T>using Matrix = std::vector<std::vector<T>>;} // namespacetemplate <typename Feature, typename Label, typename ActivationFn>class SingleLayerPerceptron { public: // 仅用于测试。 SingleLayerPerceptron(const Matrix<double>& weights, const std::vector<double>& biases, double learning_rate) : weights_(weights), biases_(biases), n_inputs_(weights.front().size()), n_outputs_(biases.size()), learning_rate_(learning_rate) {} // 用[-1, 1]范围内的随机权重和偏置初始化层。 SingleLayerPerceptron(std::size_t n_inputs, std::size_t n_outputs, double learning_rate) : n_inputs_(n_inputs), n_outputs_(n_outputs), learning_rate_(learning_rate) { weights_.resize(n_outputs_); std::for_each( weights_.begin(), weights_.end(), [this](std::vector<double>& wv) { generate_back_n(wv, n_inputs_, std::bind(random_real_range<double>, -1, 1)); }); generate_back_n(biases_, n_outputs_, std::bind(random_real_range<double>, -1, 1)); } std::vector<double> predict(const std::vector<Feature>& features) const { std::vector<double> output(n_outputs_); for (auto i = 0ul; i < n_outputs_; ++i) { output[i] = activate_(std::inner_product(weights_[i].begin(), weights_[i].end(), features.begin(), -1 * biases_[i])); } return output; } void learn(const std::vector<Feature>& features, const std::vector<double>& true_output) { const auto actual_output = predict(features); for (auto i = 0ul; i < n_outputs_; ++i) { const auto error = true_output[i] - actual_output[i]; for (auto weight = 0ul; weight < n_inputs_; ++weight) { weights_[i][weight] = weight_update( features[weight], error, learning_rate_, weights_[i][weight]); } // 偏置可以被视为具有恒定特征值1的权重。 biases_[i] = weight_update(1, error, learning_rate_, biases_[i]); } } private: Matrix<double> weights_; // n_outputs x n_inputs std::vector<double> biases_; // 1 x n_outputs std::size_t n_inputs_; std::size_t n_outputs_; ActivationFn activate_; double learning_rate_;};struct StepActivation { double operator()(const double x) const { return x > 0 ? 1 : -1; }};} // namespace rf} // namespace qp#endif /* SINGLE_LAYER_PERCEPTRON_H */
回答:
我最终解决了这个问题…
我的修复确实是正确的,准确率的损失只是由于拥有幸运(或不幸)的数据集所致。