машинное обучение — C ++: однослойный многоканальный перцептрон

Немного предыстории:

Я написал однослойный многопоточный класс персептрона на C ++. Он использует типичную дискриминантную функцию WX + b и допускает определяемые пользователем функции активации. Я проверил все довольно тщательно и, кажется, все работает так, как я ожидаю. Я заметил небольшую логическую ошибку в моем коде, и когда я попытался это исправить, сеть работала намного хуже, чем раньше. Ошибка заключается в следующем:

Я оцениваю значение на каждом выходном нейроне, используя следующий код:

output[i] =
activate_(std::inner_product(weights_[i].begin(), weights_[i].end(),
features.begin(), -1 * biases_[i]));

Здесь я рассматриваю вход смещения как фиксированный -1, но когда я применяю правило обучения к каждому смещению, я рассматриваю вход как +1.

// Bias can be treated as a weight with a constant feature value of 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>>;

}  // namespace

template <typename Feature, typename Label, typename ActivationFn>
class SingleLayerPerceptron {
public:
// For testing only.
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) {}

// Initialize the layer with random weights and biases in [-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]);
}
// Bias can be treated as a weight with a constant feature value of 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 */

0

Решение

В итоге я понял это …

Мое исправление было действительно правильным, и потеря точности была просто следствием наличия удачного (или неудачного) набора данных.

0

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]