fixing wrong results, segfaults and out of memory in CvEM (Patch #1351)


Added by Alexander Alekseychuk over 13 years ago. Updated almost 13 years ago.


Status:Done Start date:
Priority:High Due date:
Assignee:Maria Dimashova % Done:

0%

Category:ml
Target version:2.4.0
Affected version: Operating System:
Difficulty: HW Platform:
Pull request:

Description

Expectation Maximization algorithm (CvEM class in modules/ml/src/em.cpp) is broken starting from at least release 2.3.0 and up to the current svn (revision 6603). The reason for that is the replacement of native implementation of CvEM::kmeans through the general purpose cv::kmeans. This replacement is a good idea in general, but in particular it has introduced at least two problems:

Problem 1: cv::kmeans estimates cluster centres and then assign sample labels based on closeness to a centre. It does not guarantee, however, what there will be no empty clusters at the end and all class labels are used in sample labelling. Native CvEM::kmeans had a workaround for this. Now, if cv::kmeans finds less classes as requested, the result is not properly handled and results in unpredictable behaviour, e.g. wrong results and allocation of unnecessary memory of random size among overs. Suddenly if a large enough piece of memory is requested this also results in out_of_memory exception and execution interruption.

The memory allocation problem is caused by the internal function cvSortSamplesByClasses which sorts pre-labelled by the kmeans samples and stores ranges occupied by each class in an array. If less as expected labels are generated by kmeans, the reminder of the array (class_ranges) remains uninitialized. The cvSortSamplesByClasses cannot behave differently because it does not know how many classes (labels) are expected.

In the patch, the problem is fixed by letting cvSortSamplesByClasses a possibility to inform calling code about real number of classes found in the prelabelled data (and thus how many entries in class_ranges contain meaningful values). Thus the calling code can behave correctly (which is also done in this patch).

Problem 2: Previous (native) implementation of CvEM::kmeans can utilize cluster centres supplied to it as initialization. Now it is not possible and training of EM starting with E-step and only mixture averages does not work correctly.

Solution: imho, the best for the moment is to revert to older CvEM::kmeans (which is done in the patch). Yes, I am aware of deficits of the native CvEM::kmeans but if one wants to use advanced initialization, she/he can exec cv::kmeans externally and then supply centres to EM starting with E-step (which works again with this patch). In the long run (actually I hope to do it quite soon) it is a good idea to let standard cv::kmeans to accept user supplied cluster centres but not only user supplied sample labelling (which will solve problem 2) and to ensure that no empty clusters are returned (which will solve problem 1). Then it will be possible to get rid of CvEM::kmeans and use cv::kmeans again.


old-kmeans.patch - patch to fix problems in CvEM rev. 6603 (12.9 kB) Alexander Alekseychuk, 2011-09-01 02:37 pm


Related issues

related to Patch #1361: fixing a bug, improving CvEM::predict and CvEM::calcLikel... Done

Associated revisions

Revision 36e7697d
Added by Alexander Smorkalov over 11 years ago

Merge pull request #1351 from barisdemiroz:eclipse-java-tutorial

History

Updated by Russell Toris over 13 years ago

I have also been having this exact problem. Thanks for the workaround but does anyone know if this will be addressed in the official release? In particular, I use the Ubuntu repository builds from ROS to install OpenCV so that I can release my software as ROS stacks (and know it will work elsewhere) and it would be nice if a fix were implemented there as well.

Updated by Vadim Pisarevsky over 13 years ago

thanks for the report and for the patch!

the proposed solution can not be accepted, as the embedded into CvEM k-means is 1) duplication of the code 2) it's inferior to the new k-means except for the bug you mentioned.

So, let's improve the existing k-means, rather than reverting the history.

Also, a single function that does not work properly is a major bug, not critical one.

  • Status deleted (Open)

Updated by Alexander Alekseychuk over 13 years ago

In my policy, a bug which causes segfaults and out of memory conditions because of wild memory allocation, disregarding unusable results in case if it successfully passes this step, and which is present in two releases is a critical one. But it is up to you how to call it, I will not insist.

Modification of the cv::kmeans to fulfil both requirements mentioned in the original posting is not trivial and will require its major rewrite. I do not have time for this right now, although will do it some day if nobody else will. But right now the trunk version is broken too. So in my eyes it is better to sacrifice some elegance, make one step back, and restore functionality of the important part of code (I mean CvEM) than lease it broken as it is now.

Updated by smithericsmith - over 13 years ago

Thanks for the patch, it allows me to use CvEM.

I have one suggestion for the patch, on line 18 of the patch:

int nclusters_found;

I suggest initializing this variable in the following way:

int nclusters_found = nclusters;

As nclusters_found is only initialized if nclusters>1, and is used regardless. This causes unstable results (segfault) if nclusters is set to 1.

Updated by Alexander Alekseychuk over 13 years ago

Thanks for the fix, meanwhile I have also noticed this :) It was already addressed in a bit another way in the next patch here (line 817): [https://code.ros.org/trac/opencv/attachment/ticket/1361/em.patch]

Updated by Alexander Shishkov about 13 years ago

  • Description changed from Expectation Maximization algorithm (CvEM class in modules/ml/src/em.cpp) is b... to Expectation Maximization algorithm (CvEM class in modules/ml/src/em.cpp) is b... More

Updated by Kirill Kornyakov about 13 years ago

  • Tracker changed from Feature to Patch

Updated by Alexander Shishkov almost 13 years ago

  • Target version deleted ()

Updated by Alexander Shishkov almost 13 years ago

  • Status set to Open

Updated by Alexander Shishkov almost 13 years ago

  • Assignee deleted (Vadim Pisarevsky)

Updated by Maria Dimashova almost 13 years ago

  • Assignee set to Maria Dimashova

Updated by Alexander Shishkov almost 13 years ago

  • Target version deleted ()

Updated by Maria Dimashova almost 13 years ago

Thank you for the report and patch. cv::kmeans was fixed and it cann't return empty clusters now.
Note, we added new c++ implementation cv::EM and moved CvEM to the legacy module (cv::EM will be available in coming opencv2.4). So you will need to change include file from ml to legacy module. The implementation of CvEM methods was replaced by the call of cv::EM ones. CvEM writes the trained model in new format now, because previous version of write method had a bug (it saved all matrices twice).
cv::EM should solve many issues of the previous implementation. We added several new tests to check this. If you'll have some other problems from r8075, please open an issue.

  • Status changed from Open to Done

Updated by Andrey Kamaev almost 13 years ago

  • Target version set to 2.4.0

Also available in: Atom PDF