У меня есть код машинного обучения для Bag of Visual Words на Python, который хорошо работает и дает хорошие и значимые результаты. Мне нужно переместить код на C ++. Я написал код для C ++, но я не получил ожидаемых результатов, и теперь я застрял в этом вопросе, не мог найти то, что не так в течение 10 дней, борясь с кодом. Итак, я объясню код, я могу сделать что-то не так и, возможно, кто-то может придумать идею:
каждый шаг моего алгоритма работает так же, как BOW (мешок слов): сначала я извлекаю свои визуальные особенности из видеокадров и сохраняю их в структуре, как показано ниже: activities
это массив структур, которые содержат особенности моих видео и соответствующей информации каждого из них.
Mat Features = allFeatures(Range::all(),Range(40,136));
activities[i].activityLabel = file_to_action(descriptorNameList.at(i));
activities[i].activityIntLabel = actionLabel_to_action_num(activities[i].activityLabel);
activities[i].frameSize = framesize;
activities[i].subjectID = file_to_subject(descriptorNameList.at(i));
features.copyTo(activities[i].Features);
затем из видео я выбираю те, которые я использую для обучения, извлекаю их особенности и помещаю их в большой Mat
Матрица openCV, а затем я вызову алгоритм kmeans для кластеризации этой матрицы и моих функций:
Mat TrainingDescriptors;
и внутри цикла я возвращаю функции обучения в эту матрицу:
TrainingDescriptors.push_back(activities[i].Features);
и часть kmeans:
int dictionarySize = 4000;
Mat dictionary;
Mat labels;
Mat TrainingDescriptorsFloat;
TrainingDescriptors.convertTo(TrainingDescriptorsFloat,CV_32F);
kmeans(TrainingDescriptorsFloat,dictionarySize,labels,TermCriteria( CV_TERMCRIT_EPS|CV_TERMCRIT_ITER, 10000, 0.0001),5, KMEANS_PP_CENTERS, dictionary);
теперь у меня есть свой визуальный словарь и приведенные ярлыки. Затем я создам гистограммы из полученных ярлыков для каждого из моих видео. (поскольку у каждого моего видео свой размер кадра, я сохраняю количество кадров и использую его, когда хочу создать гистограмму полученных меток из kmeans). внутри цикла я создаю гистограммы:
id = Orders.at<int>(i);
int from = activities[id].frame_from;
int to = activities[id].frame_to;
Mat labelsForHist = labels(Range(from,to),Range(0,1));
Mat labelsForHistFloat;
labelsForHist.convertTo(labelsForHistFloat, CV_32F);
calcHist(&labelsForHistFloat,1,channels,Mat(),hist,1,&histSize,&histRange,uniform,accumulate);
normalize(hist,hist,1,0,NORM_L1,-1,Mat());
hist.copyTo(activities[id].Histogram);
Я конвертирую ярлыки во всплывающие calcHist
функция просто принимает float
и я также нормализую гистограммы с помощью функции нормализации opencv и сохраняю их в каждой структуре.
Я думал, что моя проблема была в создании гистограмм, как я объяснил Вот до.
Теперь я должен рассчитать гистограммы для моих тестовых видео и после этого поместить тренировочные и тестовые гистограммы в SVM.
Я создаю гистограммы тестирования видео, сравнивая характеристики видео в каждом кадре с полученным словарем (сравнивая их расстояния l2). внутри цикла:
for(int j= 0;j < sz;j++)
{
float score;
float minscore = 1000;
float lbl;
for(int k = 0; k< dictionarySize;k++)
{
score = norm(features.at<float>(j),dictionary.at<float>(k),NORM_L2,Mat());
if(score < minscore)
{
minscore =score;
lbl = k;
}
}
lbels.push_back(lbl);
}
и затем я вычисляю гистограммы внутри другого цикла следующим образом:
id = testingOrders.at<int>(i);
int from = activities[id].frame_from;
int to = activities[id].frame_to;
Mat labelsForHist = lbels(Range(from,to),Range(0,1));
Mat labelsForHistFloat;
labelsForHist.convertTo(labelsForHistFloat, CV_32F);
calcHist(&labelsForHistFloat,1,channels,Mat(),hist,1,&histSize,&histRange,uniform,accumulate);
normalize(hist,hist,1,0,NORM_L1,-1,Mat());
hist.copyTo(activities[id].Histogram);
Теперь я читаю гистограммы, как формат объяснил в LibSVM документация с моими параметрами. это параметры для моего SVM, в некоторых сообщениях люди говорят, что параметр должен быть настроен для получения правильных результатов, но я изменил их и попробовал с несколькими значениями.
param.svm_type = C_SVC;// NU_SVC
param.kernel_type = RBF;// //LINEAR // POLY //SIGMOID
param.degree = 3;
param.gamma = 1; // 1/num_features /0,0.5,1,10
param.coef0 = 0;
param.nu = 0.5;
param.cache_size = 100;
param.C = 10; //1,10,1000
param.eps = 1e-3;
param.p = 0.1;
param.shrinking = 1;
param.probability = 0;
param.nr_weight = 0;
param.weight_label = NULL;
param.weight = NULL;
cross_validation = 0;
Я тренирую векторную машину с гистограммами поездов в prob
и параметры машины и сохранить обученную модель:
model = svm_train(&prob,¶m);
и с обученной моделью вот как я тестирую тестовые видео:
if(allActivities[i].order == testingOrders.at<int>(j))
{
int a = elements.at(j);
//x_space_test = Malloc(struct svm_node,a+1);
x_space_test = (struct svm_node *) realloc(x_space_test,(a+1)*sizeof(struct svm_node));
Mat hist;
allActivities[i].Histogram.copyTo(hist);
cv::Size histsize = hist.size();
int hs = histsize.height;
int l = 0;
for(int k=0; k < hs; k++)
{
if(hist.at<float>(k,0) != 0)
{
x_space_test[l].value = hist.at<float>(k,0);
x_space_test[l].index = k+1;
cout<<x_space_test[l].value<<" "<<x_space_test[l].index<<endl;
l++;
}
}
x_space_test[l].value = 0;
x_space_test[l].index = -1;
cout<<x_space_test[l].value<<" "<<x_space_test[l].index<<endl;
target_label = (double)allActivities[i].activityIntLabel;
cout<<"target label: "<<target_label;
if (predict_probability && (svm_type==C_SVC || svm_type==NU_SVC))
{
predict_label = svm_predict_probability(model,x_space_test,prob_estimates);
fprintf(output,"%g",predict_label);
for(j=0;j<nr_class;j++)
fprintf(output," %g",prob_estimates[j]);
fprintf(output,"\n");
}
else
{
predict_label = svm_predict(model,x_space_test);
fprintf(output,"%g\n",predict_label);
}
cout<<" predict label: "<<predict_label<<endl;
if(predict_label == target_label)
++correct;
error += (predict_label-target_label)*(predict_label-target_label);
sump += predict_label;
sumt += target_label;
sumpp += predict_label*predict_label;
sumtt += target_label*target_label;
sumpt += predict_label*target_label;
++total;
break;
}
проблема в том, что я всегда получаю одинаковые метки для всех видео, например, метка всегда 2. если я изменяю параметры несколько раз, я получаю другие метки, но все они ошибочны, и я получаю 0% производительности, в то время как я получаю 98% производительности в python.
1) Я подозревал, что гистограммы (функция calcHist в opencv), как я объяснил в другом посте, не работают должным образом. Я создаю их в Matlab, и они были такими же, как C ++, но отличаются от Python.
Теперь 2) Я думаю, что они могут быть что-то не так в kmeans
Алгоритм и он не работает хорошо, как scikit
Алгоритм минибат Kmeans в Python.
или 3) последнее предположение — проблема с SVM-частью кода. Я делаю что-то не так в SVM
извините за длинный пост, но, возможно, у кого-то есть идеи, которые могут помочь мне избавиться от разочарования.
Задача ещё не решена.