Почему в этом примере частота ошибок OpenCV3.1 NormalBayesClassifier так высока?

Я пытаюсь использовать OpenCV3.1 NormalBayesClassifier на простой проблеме, для которой я могу легко генерировать данные обучения. Я остановился на классификации входных чисел как четных или нечетных. Очевидно, что это может быть вычислено напрямую со 100% точностью, но смысл в том, чтобы использовать возможности ML OpenCV, чтобы ознакомиться с ним.

Итак, мой первый вопрос — есть ли теоретическая причина, почему NormalBayesClassifier не будет подходящей моделью для этой проблемы?

Если нет, то второй вопрос: почему у меня такой высокий уровень ошибок? cv::ml::StatModel::calcError() дает мне выходы 30% — 70%.

В-третьих, как лучше снизить уровень ошибок?

Вот минимальный автономный фрагмент кода, демонстрирующий проблему:

(Чтобы было ясно, классификация / результат должен быть 0 для четного числа и 1 на нечетное число).

#include <ml.h>
#include <iomanip>

int main() {

const int numSamples = 1000;
cv::RNG rng = cv::RNG::RNG((uint64) time(NULL));

// construct training sample data

cv::Mat samples;
samples.create(numSamples, 1, CV_32FC1);

for (int i = 0; i < numSamples; i++) {
samples.at<float>(i) = (int)rng(10000);
}

// construct training response data

cv::Mat responses;
responses.create(numSamples, 1, CV_32SC1);

for (int i = 0; i < numSamples; i++) {
int sample = (int) samples.at<float>(i);
int response = (sample % 2);
responses.at<int>(i) = response;
}

cv::Ptr<cv::ml::TrainData> data = cv::ml::TrainData::create(samples, cv::ml::ROW_SAMPLE, responses);

data->setTrainTestSplitRatio(.9);

cv::Ptr<cv::ml::NormalBayesClassifier> classifier = cv::ml::NormalBayesClassifier::create();

classifier->train(data);

float errorRate = classifier->calcError(data, true, cv::noArray());

std::cout << "Bayes error rate: [" << errorRate << "]" << std::endl;

// construct prediction inputs
const int numPredictions = 10;

cv::Mat predictInputs;
predictInputs.create(numPredictions, 1, CV_32FC1);

for (int i = 0; i < numPredictions; i++) {
predictInputs.at<float>(i) = (int)rng(10000);
}

cv::Mat predictOutputs;
predictOutputs.create(numPredictions, 1, CV_32SC1);

// run prediction

classifier->predict(predictInputs, predictOutputs);

int numCorrect = 0;

for (int i = 0; i < numPredictions; i++) {
int input = (int)predictInputs.at<float>(i);
int output = predictOutputs.at<int>(i);
bool correct = (input % 2 == output);

if (correct)
numCorrect++;

std::cout << "Input = [" << (int)predictInputs.at<float>(i) << "], " << "predicted output = [" << predictOutputs.at<int>(i) << "], " << "correct = [" << (correct ? "yes" : "no") << "]"  << std::endl;
}

float percentCorrect = (float)numCorrect / numPredictions * 100.0f;

std::cout << "Percent correct = [" << std::fixed << std::setprecision(0) << percentCorrect << "]" << std::endl;
}

Пример прогона:

Bayes error rate: [36]
Input = [9150], predicted output = [1], correct = [no]
Input = [3829], predicted output = [0], correct = [no]
Input = [4985], predicted output = [0], correct = [no]
Input = [8113], predicted output = [1], correct = [yes]
Input = [7175], predicted output = [0], correct = [no]
Input = [811], predicted output = [1], correct = [yes]
Input = [699], predicted output = [1], correct = [yes]
Input = [7955], predicted output = [1], correct = [yes]
Input = [8282], predicted output = [1], correct = [no]
Input = [1818], predicted output = [0], correct = [yes]
Percent correct = [50]

2

Решение

В вашем коде вы предоставляете алгоритму одну особенность, которая является числом для классификации. Этого недостаточно, если вы не предоставите несколько примеров одних и тех же номеров несколько раз. Если вы хотите, чтобы алгоритм обучения узнал что-то нечетное против четного, вам нужно подумать о том, какие функции могут быть использованы классификатором для изучения этого. Большинство методов машинного обучения требуют, прежде всего, тщательной разработки функций.

Поскольку вы хотите поэкспериментировать с ML, я предлагаю следующее:

  1. Для каждого числа создайте, скажем, 5 функций, по одной для кодирования каждой цифры. Таким образом, 5 будет 00005 или f1 = 0, f2 = 0, f3 = 0, f4 = 0, f5 = 0, а 11098 будет f1 = 1, f2 = 2, f3 = 0, f4 = 9, f5 = 8.
  2. Если у вас есть номера больше этого, вы можете сохранить только последние 5 цифр.
  3. Тренируй свой классификатор
  4. Тест с той же кодировкой. От классификатора вы хотели бы узнать, что только последняя цифра важна для определения нечетного и четного

Если вы хотите больше поиграть с ним, вы можете кодировать числа в двоичном формате. Что бы классификатору было еще проще узнать, что делает число нечетным или четным.

1

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

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

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