OpenCV 3.1.0 を使用して、ガウス混合モデルを EM を使用して 2 クラスのデータに適合させています。サンプルにはラベルが付けられているため、トレーニング中にEM::trainEを使用してクラス平均と共分散を提供します。予測されたラベルを確認すると、それらはデータによく適合しているように見えますが、逆です (クラス 1 のサンプルはほとんど常にクラス 0 にあると予測され、その逆も同様です)。モデルのトレーニング方法は次のとおりです。
// Run EM
Mat predicted_labels(samples.rows, 1, CV_64F);
Mat means0(EM_CLASS_COUNT, SAMPLE_DIMENSIONS, CV_64F);
const int sizes[]{ EM_CLASS_COUNT, SAMPLE_DIMENSIONS, SAMPLE_DIMENSIONS };
Mat covar0(3, sizes, CV_64F);
for (int i = 0; i < EM_CLASS_COUNT; ++i) {
calcCovarMatrix(class_samples[i], Mat(SAMPLE_DIMENSIONS, SAMPLE_DIMENSIONS, samples.type(), covar0.row(i).data), means0.row(i), COVAR_NORMAL | COVAR_ROWS);
}
Ptr<EM> model = EM::create();
model->setClustersNumber(EM_CLASS_COUNT);
model->trainE(samples, means0, covar0, noArray(), noArray(), predicted_labels);
// Print results
for (int i = 0; i < csv_data.size(); ++i) {
printf("(%f, %f, %f): %d -> %d\n", samples.at<double>(i, 0), samples.at<double>(i, 1), samples.at<double>(i, 2), sample_labels.at<int>(i), predicted_labels.at<int>(i));
}
Mat error = (sample_labels != predicted_labels) / 255;
printf("Error rate: %f\n", norm(error, NORM_L1) / error.rows);
Mat means = model->getMeans();
printf("Sample means: 0:(%f, %f, %f), 1:(%f, %f, %f)\n", means0.at<double>(0, 0), means0.at<double>(0, 1), means0.at<double>(0, 2), means0.at<double>(1, 0), means0.at<double>(1, 1), means0.at<double>(1, 2));
printf("Calculated means: 0:(%f, %f, %f), 1:(%f, %f, %f)\n", means.at<double>(0, 0), means.at<double>(0, 1), means.at<double>(0, 2), means.at<double>(1, 0), means.at<double>(1, 1), means.at<double>(1, 2));
コンソールに出力されたデータを確認すると、各クラスの計算された平均は、反対のクラスの標本平均に最も近くなっています。
Sample means: 0:(184.912913, 192.435435, 185.291291), 1:(149.543210, 150.604938, 129.833333)
Calculated means: 0:(147.953284, 153.951035, 139.721160), 1:(209.889542, 214.448519, 206.625586)
これは、サンプル データとトレーニング済みモデルの視覚化であり、スワップされた分類を示しています。赤はクラス 0、青はクラス 1 で、共分散検索にバグがあるため、等高線は楕円ではなく円になります。
各ガウスが作成されたサンプルで最適化されるようにする方法はありますか、それとも各ガウスに属するクラスラベルを識別する標準的な方法はありますか?