SpectralCluster.cpp 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  1. /**
  2. * @file SpectralCluster.cpp
  3. * @brief spectral clustering by kmeans-clustering of eigenvectors
  4. * @author Erik Rodner, Alexander Freytag
  5. * @date 11/13/2007
  6. */
  7. #include <iostream>
  8. #include <core/vector/Distance.h>
  9. #include <core/vector/Eigen.h>
  10. #include <map>
  11. #include "vislearning/math/cluster/SpectralCluster.h"
  12. using namespace OBJREC;
  13. using namespace std;
  14. using namespace NICE;
  15. ///////////////////// ///////////////////// /////////////////////
  16. // CONSTRUCTORS / DESTRUCTORS
  17. ///////////////////// ///////////////////// /////////////////////
  18. SpectralCluster::SpectralCluster() : ClusterAlgorithm() , kmeans()
  19. {
  20. this->noClusters = 20;
  21. this->alpha = 1.0;
  22. }
  23. SpectralCluster::SpectralCluster ( int _noClusters, double alpha ) : noClusters(_noClusters), kmeans(_noClusters)
  24. {
  25. this->alpha = alpha;
  26. }
  27. SpectralCluster::SpectralCluster( const NICE::Config * _conf, const std::string & _confSection)
  28. {
  29. this->initFromConfig( _conf, _confSection );
  30. }
  31. SpectralCluster::~SpectralCluster()
  32. {
  33. }
  34. void SpectralCluster::initFromConfig( const NICE::Config* _conf, const std::string& _confSection )
  35. {
  36. this->noClusters = _conf->gI( _confSection, "noClusters", 20);
  37. this->alpha = _conf->gD( _confSection, "alpha", 1.0);
  38. this->kmeans.initFromConfig( _conf );
  39. }
  40. ///////////////////// ///////////////////// /////////////////////
  41. // CLUSTERING STUFF
  42. ///////////////////// ///////////////////// //////////////////
  43. void SpectralCluster::getSimilarityMatrix ( const VVector & features,
  44. NICE::Matrix & laplacian,
  45. double alpha )
  46. {
  47. NICE::Matrix distances ( laplacian );
  48. double mindist = numeric_limits<double>::max();
  49. double maxdist = - numeric_limits<double>::max();
  50. long int count = 0;
  51. double mean = 0.0;
  52. double stddev = 0.0;
  53. NICE::EuclidianDistance<double> distance;
  54. for ( int i = 0 ; i < (int)features.size() ; i++ )
  55. {
  56. const NICE::Vector & xi = features[i];
  57. for ( int j = i ; j < (int)features.size() ; j++ )
  58. {
  59. const NICE::Vector & xj = features[j];
  60. // double sim = xi * xj;
  61. double dist = distance.calculate ( xi, xj );
  62. distances(i, j) = dist;
  63. if ( dist < mindist )
  64. mindist = dist;
  65. if ( dist > maxdist )
  66. maxdist = dist;
  67. count++;
  68. mean += dist;
  69. }
  70. }
  71. mean /= count;
  72. for ( int i = 0 ; i < (int)features.size() ; i++ )
  73. {
  74. for ( int j = i ; j < (int)features.size() ; j++ )
  75. {
  76. double d = ( mean - distances(i, j) );
  77. stddev += d*d;
  78. }
  79. }
  80. stddev /= count;
  81. double norm = alpha / (2.0 * stddev);
  82. for ( int i = 0 ; i < (int)features.size() ; i++ )
  83. {
  84. for ( int j = i ; j < (int)features.size() ; j++ )
  85. {
  86. double sim = exp(-distances(i, j) * norm );
  87. laplacian(i, j) = - sim;
  88. laplacian(j, i) = - sim;
  89. }
  90. }
  91. }
  92. void SpectralCluster::computeLaplacian ( const NICE::VVector & features,
  93. NICE::Matrix & laplacian,
  94. int method, double alpha )
  95. {
  96. laplacian.set(0.0);
  97. getSimilarityMatrix(features, laplacian, alpha);
  98. NICE::Vector d ( laplacian.rows() );
  99. d.set(0.0);
  100. for ( int i = 0 ; i < (int)laplacian.rows(); i++ )
  101. {
  102. for ( int j = 0 ; j < (int)laplacian.cols(); j++ )
  103. {
  104. d[i] -=laplacian(i, j);
  105. }
  106. }
  107. // Now we got the negative weight matrix laplacian : -W
  108. // and the degree matrix : D
  109. // calculate normalization
  110. // D^-1 * L
  111. if ( method == L_RW_NORMALIZED )
  112. {
  113. // L = D^-1 L_unnormalized = I - D^-1*W
  114. for ( int i = 0 ; i < (int)laplacian.rows() ; i++ )
  115. {
  116. for ( int j = 0 ; j < (int)laplacian.cols() ; j++ )
  117. {
  118. laplacian(i, j) *= (1.0/d[i]);
  119. }
  120. }
  121. for ( int i = 0 ; i < (int)laplacian.rows() ; i++ )
  122. {
  123. laplacian(i, i) += 1.0;
  124. }
  125. }
  126. else if ( method == L_UNNORMALIZED )
  127. {
  128. // unnormalized version
  129. // L = D - W
  130. for ( int i = 0 ; i < (int)laplacian.rows() ; i++ )
  131. {
  132. laplacian(i, i) += d[i];
  133. }
  134. }
  135. }
  136. void SpectralCluster::cluster ( const NICE::VVector & features,
  137. NICE::VVector & prototypes,
  138. std::vector<double> & weights,
  139. std::vector<int> & assignment )
  140. {
  141. if ( features.size() <= 0 ) {
  142. fprintf (stderr, "FATAL ERROR: not enough features vectors provided\n");
  143. exit(-1);
  144. }
  145. const NICE::Vector & x = features[0];
  146. int dimension = x.size();
  147. NICE::Matrix laplacian ( features.size(), features.size() );
  148. computeLaplacian ( features, laplacian, L_RW_NORMALIZED, alpha );
  149. //computeLaplacian ( features, laplacian, L_UNNORMALIZED, alpha );
  150. NICE::Matrix eigvect;
  151. NICE::Vector eigvals;
  152. try {
  153. NICE::eigenvectorvalues ( laplacian, eigvect, eigvals );
  154. }
  155. catch (...)
  156. {
  157. std::cerr << "You should adjust the alpha parameter, or the features are somehow weird" << std::endl;
  158. std::cerr << "Laplacian = " << laplacian(0, 0, min((int)laplacian.rows()-1, 5), min((int)laplacian.cols()-1, 5)) << std::endl;
  159. throw Exception ("Laplacian matrix is singular or not well-conditioned!");
  160. }
  161. std::map<double, int> eigvals_sorted;
  162. for ( int i = 0 ; i < (int)eigvals.size(); i++ )
  163. {
  164. eigvals_sorted.insert ( make_pair( eigvals[i], i ) );
  165. }
  166. NICE::VVector spectral_features;
  167. for ( int i = 0 ; i < (int)eigvect.rows() ; i++ )
  168. {
  169. NICE::Vector eigvec_k ( noClusters );
  170. map<double, int>::const_iterator k = eigvals_sorted.begin();
  171. for ( int j = 0 ; j < noClusters ; j++ )
  172. {
  173. int eigval_index = k->second;
  174. eigvec_k[j] = eigvect(i, eigval_index ) ;
  175. k++;
  176. }
  177. spectral_features.push_back ( eigvec_k );
  178. }
  179. this->kmeans.cluster ( spectral_features, prototypes, weights, assignment );
  180. // recompute prototypes
  181. for ( int k = 0 ; k < noClusters ; k++ )
  182. {
  183. prototypes[k].resize( dimension );
  184. prototypes[k].set(0);
  185. weights[k] = 0;
  186. }
  187. int j = 0;
  188. for ( VVector::const_iterator i = features.begin();
  189. i != features.end();
  190. i++, j++ )
  191. {
  192. int k = assignment[j];
  193. NICE::Vector & p = prototypes[k];
  194. const NICE::Vector & x = *i;
  195. p += x;
  196. weights[k]++;
  197. }
  198. for ( int k = 0 ; k < noClusters ; k++ )
  199. {
  200. NICE::Vector & p = prototypes[k];
  201. if ( weights[k] <= 0 )
  202. {
  203. fprintf (stderr, "FATAL ERROR: spectral clustering produced empty cluster !\n");
  204. exit(-1);
  205. }
  206. p *= ( 1.0 / weights[k] );
  207. weights[k] = weights[k] / features.size();
  208. }
  209. }
  210. ///////////////////// INTERFACE PERSISTENT /////////////////////
  211. // interface specific methods for store and restore
  212. ///////////////////// INTERFACE PERSISTENT /////////////////////
  213. void SpectralCluster::restore ( std::istream & is, int format )
  214. {
  215. //delete everything we knew so far...
  216. this->clear();
  217. if ( is.good() )
  218. {
  219. std::string tmp;
  220. is >> tmp; //class name
  221. if ( ! this->isStartTag( tmp, "SpectralCluster" ) )
  222. {
  223. std::cerr << " WARNING - attempt to restore SpectralCluster, but start flag " << tmp << " does not match! Aborting... " << std::endl;
  224. throw;
  225. }
  226. bool b_endOfBlock ( false ) ;
  227. while ( !b_endOfBlock )
  228. {
  229. is >> tmp; // start of block
  230. if ( this->isEndTag( tmp, "SpectralCluster" ) )
  231. {
  232. b_endOfBlock = true;
  233. continue;
  234. }
  235. tmp = this->removeStartTag ( tmp );
  236. if ( tmp.compare("noClusters") == 0 )
  237. {
  238. is >> this->noClusters;
  239. is >> tmp; // end of block
  240. tmp = this->removeEndTag ( tmp );
  241. }
  242. else if ( tmp.compare("alpha") == 0 )
  243. {
  244. is >> this->alpha;
  245. is >> tmp; // end of block
  246. tmp = this->removeEndTag ( tmp );
  247. }
  248. else if ( tmp.compare("kmeans") == 0 )
  249. {
  250. this->kmeans.restore ( is );
  251. is >> tmp; // end of block
  252. tmp = this->removeEndTag ( tmp );
  253. }
  254. else
  255. {
  256. std::cerr << "WARNING -- unexpected SpectralCluster object -- " << tmp << " -- for restoration... aborting" << std::endl;
  257. throw;
  258. }
  259. }
  260. }
  261. else
  262. {
  263. std::cerr << "SpectralCluster::restore -- InStream not initialized - restoring not possible!" << std::endl;
  264. throw;
  265. }
  266. }
  267. void SpectralCluster::store ( std::ostream & os, int format ) const
  268. {
  269. if (os.good())
  270. {
  271. // show starting point
  272. os << this->createStartTag( "SpectralCluster" ) << std::endl;
  273. os << this->createStartTag( "noClusters" ) << std::endl;
  274. os << this->noClusters << std::endl;
  275. os << this->createEndTag( "noClusters" ) << std::endl;
  276. os << this->createStartTag( "alpha" ) << std::endl;
  277. os << this->alpha << std::endl;
  278. os << this->createEndTag( "alpha" ) << std::endl;
  279. os << this->createStartTag( "kmeans" ) << std::endl;
  280. this->kmeans.store ( os );
  281. os << this->createEndTag( "kmeans" ) << std::endl;
  282. // done
  283. os << this->createEndTag( "SpectralCluster" ) << std::endl;
  284. }
  285. else
  286. {
  287. std::cerr << "OutStream not initialized - storing not possible!" << std::endl;
  288. }
  289. }
  290. void SpectralCluster::clear ()
  291. {
  292. }