SHOGUN  v3.0.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Kernel.cpp
Go to the documentation of this file.
1 /*
2  * EXCEPT FOR THE KERNEL CACHING FUNCTIONS WHICH ARE (W) THORSTEN JOACHIMS
3  * COPYRIGHT (C) 1999 UNIVERSITAET DORTMUND - ALL RIGHTS RESERVED
4  *
5  * this program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * Written (W) 1999-2009 Soeren Sonnenburg
11  * Written (W) 1999-2008 Gunnar Raetsch
12  * Copyright (C) 1999-2009 Fraunhofer Institute FIRST and Max-Planck-Society
13  */
14 
15 #include <shogun/lib/config.h>
16 #include <shogun/lib/common.h>
17 #include <shogun/io/SGIO.h>
18 #include <shogun/io/File.h>
19 #include <shogun/lib/Time.h>
20 #include <shogun/lib/Signal.h>
21 
22 #include <shogun/base/Parallel.h>
23 
24 #include <shogun/kernel/Kernel.h>
27 #include <shogun/base/Parameter.h>
28 
30 
31 #include <string.h>
32 #include <unistd.h>
33 #include <math.h>
34 
35 #ifdef HAVE_PTHREAD
36 #include <pthread.h>
37 #endif
38 
39 using namespace shogun;
40 
42 {
43  init();
45 }
46 
47 CKernel::CKernel(int32_t size) : CSGObject()
48 {
49  init();
50 
51  if (size<10)
52  size=10;
53 
54  cache_size=size;
56 }
57 
58 
59 CKernel::CKernel(CFeatures* p_lhs, CFeatures* p_rhs, int32_t size) : CSGObject()
60 {
61  init();
62 
63  if (size<10)
64  size=10;
65 
66  cache_size=size;
67 
69  init(p_lhs, p_rhs);
71 }
72 
74 {
75  if (get_is_initialized())
76  SG_ERROR("Kernel still initialized on destruction.\n")
77 
80 
81  SG_INFO("Kernel deleted (%p).\n", this)
82 }
83 
84 #ifdef USE_SVMLIGHT
85 void CKernel::resize_kernel_cache(KERNELCACHE_IDX size, bool regression_hack)
86 {
87  if (size<10)
88  size=10;
89 
91  cache_size=size;
92 
93  if (has_features() && get_num_vec_lhs())
94  kernel_cache_init(cache_size, regression_hack);
95 }
96 #endif //USE_SVMLIGHT
97 
98 bool CKernel::init(CFeatures* l, CFeatures* r)
99 {
100  SG_DEBUG("entering CKernel::init(%p, %p)\n", l, r)
101 
102  /* make sure that features are not deleted if same ones are used */
103  SG_REF(l);
104  SG_REF(r);
105 
106  //make sure features were indeed supplied
107  REQUIRE(l, "CKernel::init(%p, %p): LHS features required!\n", l, r)
108  REQUIRE(r, "CKernel::init(%p, %p): RHS features required!\n", l, r)
109 
110  //make sure features are compatible
113 
114  //remove references to previous features
116 
117  //increase reference counts
118  SG_REF(l);
119  if (l==r)
120  lhs_equals_rhs=true;
121  else // l!=r
122  SG_REF(r);
123 
124  lhs=l;
125  rhs=r;
126 
129 
132 
133  /* unref "safety" refs from beginning */
134  SG_UNREF(r);
135  SG_UNREF(l);
136 
137  SG_DEBUG("leaving CKernel::init(%p, %p)\n", l, r)
138  return true;
139 }
140 
142 {
143  SG_REF(n);
144  if (lhs && rhs)
145  n->init(this);
146 
148  normalizer=n;
149 
150  return (normalizer!=NULL);
151 }
152 
154 {
156  return normalizer;
157 }
158 
160 {
161  return normalizer->init(this);
162 }
163 
165 {
167 }
168 
169 #ifdef USE_SVMLIGHT
170 /****************************** Cache handling *******************************/
171 
172 void CKernel::kernel_cache_init(int32_t buffsize, bool regression_hack)
173 {
174  int32_t totdoc=get_num_vec_lhs();
175  if (totdoc<=0)
176  {
177  SG_ERROR("kernel has zero rows: num_lhs=%d num_rhs=%d\n",
179  }
180  uint64_t buffer_size=0;
181  int32_t i;
182 
183  //in regression the additional constraints are made by doubling the training data
184  if (regression_hack)
185  totdoc*=2;
186 
187  buffer_size=((uint64_t) buffsize)*1024*1024/sizeof(KERNELCACHE_ELEM);
188  if (buffer_size>((uint64_t) totdoc)*totdoc)
189  buffer_size=((uint64_t) totdoc)*totdoc;
190 
191  SG_INFO("using a kernel cache of size %lld MB (%lld bytes) for %s Kernel\n", buffer_size*sizeof(KERNELCACHE_ELEM)/1024/1024, buffer_size*sizeof(KERNELCACHE_ELEM), get_name())
192 
193  //make sure it fits in the *signed* KERNELCACHE_IDX type
194  ASSERT(buffer_size < (((uint64_t) 1) << (sizeof(KERNELCACHE_IDX)*8-1)))
195 
196  kernel_cache.index = SG_MALLOC(int32_t, totdoc);
197  kernel_cache.occu = SG_MALLOC(int32_t, totdoc);
198  kernel_cache.lru = SG_MALLOC(int32_t, totdoc);
199  kernel_cache.invindex = SG_MALLOC(int32_t, totdoc);
200  kernel_cache.active2totdoc = SG_MALLOC(int32_t, totdoc);
201  kernel_cache.totdoc2active = SG_MALLOC(int32_t, totdoc);
202  kernel_cache.buffer = SG_MALLOC(KERNELCACHE_ELEM, buffer_size);
203  kernel_cache.buffsize=buffer_size;
204  kernel_cache.max_elems=(int32_t) (kernel_cache.buffsize/totdoc);
205 
206  if(kernel_cache.max_elems>totdoc) {
207  kernel_cache.max_elems=totdoc;
208  }
209 
210  kernel_cache.elems=0; // initialize cache
211  for(i=0;i<totdoc;i++) {
212  kernel_cache.index[i]=-1;
213  kernel_cache.lru[i]=0;
214  }
215  for(i=0;i<totdoc;i++) {
216  kernel_cache.occu[i]=0;
217  kernel_cache.invindex[i]=-1;
218  }
219 
220  kernel_cache.activenum=totdoc;;
221  for(i=0;i<totdoc;i++) {
222  kernel_cache.active2totdoc[i]=i;
223  kernel_cache.totdoc2active[i]=i;
224  }
225 
226  kernel_cache.time=0;
227 }
228 
230  int32_t docnum, int32_t *active2dnum, float64_t *buffer, bool full_line)
231 {
232  int32_t i,j;
233  KERNELCACHE_IDX start;
234 
235  int32_t num_vectors = get_num_vec_lhs();
236  if (docnum>=num_vectors)
237  docnum=2*num_vectors-1-docnum;
238 
239  /* is cached? */
240  if(kernel_cache.index[docnum] != -1)
241  {
242  kernel_cache.lru[kernel_cache.index[docnum]]=kernel_cache.time; /* lru */
243  start=((KERNELCACHE_IDX) kernel_cache.activenum)*kernel_cache.index[docnum];
244 
245  if (full_line)
246  {
247  for(j=0;j<get_num_vec_lhs();j++)
248  {
249  if(kernel_cache.totdoc2active[j] >= 0)
250  buffer[j]=kernel_cache.buffer[start+kernel_cache.totdoc2active[j]];
251  else
252  buffer[j]=(float64_t) kernel(docnum, j);
253  }
254  }
255  else
256  {
257  for(i=0;(j=active2dnum[i])>=0;i++)
258  {
259  if(kernel_cache.totdoc2active[j] >= 0)
260  buffer[j]=kernel_cache.buffer[start+kernel_cache.totdoc2active[j]];
261  else
262  {
263  int32_t k=j;
264  if (k>=num_vectors)
265  k=2*num_vectors-1-k;
266  buffer[j]=(float64_t) kernel(docnum, k);
267  }
268  }
269  }
270  }
271  else
272  {
273  if (full_line)
274  {
275  for(j=0;j<get_num_vec_lhs();j++)
276  buffer[j]=(KERNELCACHE_ELEM) kernel(docnum, j);
277  }
278  else
279  {
280  for(i=0;(j=active2dnum[i])>=0;i++)
281  {
282  int32_t k=j;
283  if (k>=num_vectors)
284  k=2*num_vectors-1-k;
285  buffer[j]=(KERNELCACHE_ELEM) kernel(docnum, k);
286  }
287  }
288  }
289 }
290 
291 
292 // Fills cache for the row m
294 {
295  register int32_t j,k,l;
296  register KERNELCACHE_ELEM *cache;
297 
298  int32_t num_vectors = get_num_vec_lhs();
299 
300  if (m>=num_vectors)
301  m=2*num_vectors-1-m;
302 
303  if(!kernel_cache_check(m)) // not cached yet
304  {
305  cache = kernel_cache_clean_and_malloc(m);
306  if(cache) {
307  l=kernel_cache.totdoc2active[m];
308 
309  for(j=0;j<kernel_cache.activenum;j++) // fill cache
310  {
311  k=kernel_cache.active2totdoc[j];
312 
313  if((kernel_cache.index[k] != -1) && (l != -1) && (k != m)) {
314  cache[j]=kernel_cache.buffer[((KERNELCACHE_IDX) kernel_cache.activenum)
315  *kernel_cache.index[k]+l];
316  }
317  else
318  {
319  if (k>=num_vectors)
320  k=2*num_vectors-1-k;
321 
322  cache[j]=kernel(m, k);
323  }
324  }
325  }
326  else
327  perror("Error: Kernel cache full! => increase cache size");
328  }
329 }
330 
331 
332 void* CKernel::cache_multiple_kernel_row_helper(void* p)
333 {
334  int32_t j,k,l;
335  S_KTHREAD_PARAM* params = (S_KTHREAD_PARAM*) p;
336 
337  for (int32_t i=params->start; i<params->end; i++)
338  {
339  KERNELCACHE_ELEM* cache=params->cache[i];
340  int32_t m = params->uncached_rows[i];
341  l=params->kernel_cache->totdoc2active[m];
342 
343  for(j=0;j<params->kernel_cache->activenum;j++) // fill cache
344  {
345  k=params->kernel_cache->active2totdoc[j];
346 
347  if((params->kernel_cache->index[k] != -1) && (l != -1) && (!params->needs_computation[k])) {
348  cache[j]=params->kernel_cache->buffer[((KERNELCACHE_IDX) params->kernel_cache->activenum)
349  *params->kernel_cache->index[k]+l];
350  }
351  else
352  {
353  if (k>=params->num_vectors)
354  k=2*params->num_vectors-1-k;
355 
356  cache[j]=params->kernel->kernel(m, k);
357  }
358  }
359 
360  //now line m is cached
361  params->needs_computation[m]=0;
362  }
363  return NULL;
364 }
365 
366 // Fills cache for the rows in key
367 void CKernel::cache_multiple_kernel_rows(int32_t* rows, int32_t num_rows)
368 {
369 #ifdef HAVE_PTHREAD
370  int32_t nthreads=parallel->get_num_threads();
371 
372  if (nthreads<2)
373  {
374 #endif
375  for(int32_t i=0;i<num_rows;i++)
376  cache_kernel_row(rows[i]);
377 #ifdef HAVE_PTHREAD
378  }
379  else
380  {
381  // fill up kernel cache
382  int32_t* uncached_rows = SG_MALLOC(int32_t, num_rows);
383  KERNELCACHE_ELEM** cache = SG_MALLOC(KERNELCACHE_ELEM*, num_rows);
384  pthread_t* threads = SG_MALLOC(pthread_t, nthreads-1);
385  S_KTHREAD_PARAM* params = SG_MALLOC(S_KTHREAD_PARAM, nthreads-1);
386  int32_t num_threads=nthreads-1;
387  int32_t num_vec=get_num_vec_lhs();
388  ASSERT(num_vec>0)
389  uint8_t* needs_computation=SG_CALLOC(uint8_t, num_vec);
390 
391  int32_t step=0;
392  int32_t num=0;
393  int32_t end=0;
394 
395  // allocate cachelines if necessary
396  for (int32_t i=0; i<num_rows; i++)
397  {
398  int32_t idx=rows[i];
399  if (idx>=num_vec)
400  idx=2*num_vec-1-idx;
401 
402  if (kernel_cache_check(idx))
403  continue;
404 
405  needs_computation[idx]=1;
406  uncached_rows[num]=idx;
407  cache[num]= kernel_cache_clean_and_malloc(idx);
408 
409  if (!cache[num])
410  SG_ERROR("Kernel cache full! => increase cache size\n")
411 
412  num++;
413  }
414 
415  if (num>0)
416  {
417  step= num/nthreads;
418 
419  if (step<1)
420  {
421  num_threads=num-1;
422  step=1;
423  }
424 
425  for (int32_t t=0; t<num_threads; t++)
426  {
427  params[t].kernel = this;
428  params[t].kernel_cache = &kernel_cache;
429  params[t].cache = cache;
430  params[t].uncached_rows = uncached_rows;
431  params[t].needs_computation = needs_computation;
432  params[t].num_uncached = num;
433  params[t].start = t*step;
434  params[t].end = (t+1)*step;
435  params[t].num_vectors = get_num_vec_lhs();
436  end=params[t].end;
437 
438  int code=pthread_create(&threads[t], NULL,
439  CKernel::cache_multiple_kernel_row_helper, (void*)&params[t]);
440 
441  if (code != 0)
442  {
443  SG_WARNING("Thread creation failed (thread %d of %d) "
444  "with error:'%s'\n",t, num_threads, strerror(code));
445  num_threads=t;
446  end=t*step;
447  break;
448  }
449  }
450  }
451  else
452  num_threads=-1;
453 
454 
455  S_KTHREAD_PARAM last_param;
456  last_param.kernel = this;
457  last_param.kernel_cache = &kernel_cache;
458  last_param.cache = cache;
459  last_param.uncached_rows = uncached_rows;
460  last_param.needs_computation = needs_computation;
461  last_param.start = end;
462  last_param.num_uncached = num;
463  last_param.end = num;
464  last_param.num_vectors = get_num_vec_lhs();
465 
466  cache_multiple_kernel_row_helper(&last_param);
467 
468 
469  for (int32_t t=0; t<num_threads; t++)
470  {
471  if (pthread_join(threads[t], NULL) != 0)
472  SG_WARNING("pthread_join of thread %d/%d failed\n", t, num_threads)
473  }
474 
475  SG_FREE(needs_computation);
476  SG_FREE(params);
477  SG_FREE(threads);
478  SG_FREE(cache);
479  SG_FREE(uncached_rows);
480  }
481 #endif
482 }
483 
484 // remove numshrink columns in the cache
485 // which correspond to examples marked
487  int32_t totdoc, int32_t numshrink, int32_t *after)
488 {
489  ASSERT(totdoc > 0);
490  register int32_t i,j,jj,scount; // 0 in after.
491  KERNELCACHE_IDX from=0,to=0;
492  int32_t *keep;
493 
494  keep=SG_MALLOC(int32_t, totdoc);
495  for(j=0;j<totdoc;j++) {
496  keep[j]=1;
497  }
498  scount=0;
499  for(jj=0;(jj<kernel_cache.activenum) && (scount<numshrink);jj++) {
500  j=kernel_cache.active2totdoc[jj];
501  if(!after[j]) {
502  scount++;
503  keep[j]=0;
504  }
505  }
506 
507  for(i=0;i<kernel_cache.max_elems;i++) {
508  for(jj=0;jj<kernel_cache.activenum;jj++) {
509  j=kernel_cache.active2totdoc[jj];
510  if(!keep[j]) {
511  from++;
512  }
513  else {
514  kernel_cache.buffer[to]=kernel_cache.buffer[from];
515  to++;
516  from++;
517  }
518  }
519  }
520 
521  kernel_cache.activenum=0;
522  for(j=0;j<totdoc;j++) {
523  if((keep[j]) && (kernel_cache.totdoc2active[j] != -1)) {
524  kernel_cache.active2totdoc[kernel_cache.activenum]=j;
525  kernel_cache.totdoc2active[j]=kernel_cache.activenum;
526  kernel_cache.activenum++;
527  }
528  else {
529  kernel_cache.totdoc2active[j]=-1;
530  }
531  }
532 
533  kernel_cache.max_elems=
534  (int32_t)(kernel_cache.buffsize/kernel_cache.activenum);
535  if(kernel_cache.max_elems>totdoc) {
536  kernel_cache.max_elems=totdoc;
537  }
538 
539  SG_FREE(keep);
540 
541 }
542 
544 {
545  int32_t maxlru=0,k;
546 
547  for(k=0;k<kernel_cache.max_elems;k++) {
548  if(maxlru < kernel_cache.lru[k])
549  maxlru=kernel_cache.lru[k];
550  }
551  for(k=0;k<kernel_cache.max_elems;k++) {
552  kernel_cache.lru[k]-=maxlru;
553  }
554 }
555 
557 {
558  SG_FREE(kernel_cache.index);
559  SG_FREE(kernel_cache.occu);
560  SG_FREE(kernel_cache.lru);
561  SG_FREE(kernel_cache.invindex);
562  SG_FREE(kernel_cache.active2totdoc);
563  SG_FREE(kernel_cache.totdoc2active);
564  SG_FREE(kernel_cache.buffer);
565  memset(&kernel_cache, 0x0, sizeof(KERNEL_CACHE));
566 }
567 
568 int32_t CKernel::kernel_cache_malloc()
569 {
570  int32_t i;
571 
573  for(i=0;i<kernel_cache.max_elems;i++) {
574  if(!kernel_cache.occu[i]) {
575  kernel_cache.occu[i]=1;
576  kernel_cache.elems++;
577  return(i);
578  }
579  }
580  }
581  return(-1);
582 }
583 
584 void CKernel::kernel_cache_free(int32_t cacheidx)
585 {
586  kernel_cache.occu[cacheidx]=0;
587  kernel_cache.elems--;
588 }
589 
590 // remove least recently used cache
591 // element
592 int32_t CKernel::kernel_cache_free_lru()
593 {
594  register int32_t k,least_elem=-1,least_time;
595 
596  least_time=kernel_cache.time+1;
597  for(k=0;k<kernel_cache.max_elems;k++) {
598  if(kernel_cache.invindex[k] != -1) {
599  if(kernel_cache.lru[k]<least_time) {
600  least_time=kernel_cache.lru[k];
601  least_elem=k;
602  }
603  }
604  }
605 
606  if(least_elem != -1) {
607  kernel_cache_free(least_elem);
608  kernel_cache.index[kernel_cache.invindex[least_elem]]=-1;
609  kernel_cache.invindex[least_elem]=-1;
610  return(1);
611  }
612  return(0);
613 }
614 
615 // Get a free cache entry. In case cache is full, the lru
616 // element is removed.
617 KERNELCACHE_ELEM* CKernel::kernel_cache_clean_and_malloc(int32_t cacheidx)
618 {
619  int32_t result;
620  if((result = kernel_cache_malloc()) == -1) {
621  if(kernel_cache_free_lru()) {
622  result = kernel_cache_malloc();
623  }
624  }
625  kernel_cache.index[cacheidx]=result;
626  if(result == -1) {
627  return(0);
628  }
629  kernel_cache.invindex[result]=cacheidx;
630  kernel_cache.lru[kernel_cache.index[cacheidx]]=kernel_cache.time; // lru
631  return &kernel_cache.buffer[((KERNELCACHE_IDX) kernel_cache.activenum)*kernel_cache.index[cacheidx]];
632 }
633 #endif //USE_SVMLIGHT
634 
635 void CKernel::load(CFile* loader)
636 {
639 }
640 
641 void CKernel::save(CFile* writer)
642 {
643  SGMatrix<float64_t> k_matrix=get_kernel_matrix<float64_t>();
645  writer->set_matrix(k_matrix.matrix, k_matrix.num_rows, k_matrix.num_cols);
647 }
648 
650 {
651  SG_DEBUG("entering CKernel::remove_lhs_and_rhs\n")
652  if (rhs!=lhs)
653  SG_UNREF(rhs);
654  rhs = NULL;
655  num_rhs=0;
656 
657  SG_UNREF(lhs);
658  lhs = NULL;
659  num_lhs=0;
660  lhs_equals_rhs=false;
661 
662 #ifdef USE_SVMLIGHT
663  cache_reset();
664 #endif //USE_SVMLIGHT
665  SG_DEBUG("leaving CKernel::remove_lhs_and_rhs\n")
666 }
667 
669 {
670  if (rhs==lhs)
671  rhs=NULL;
672  SG_UNREF(lhs);
673  lhs = NULL;
674  num_lhs=0;
675  lhs_equals_rhs=false;
676 #ifdef USE_SVMLIGHT
677  cache_reset();
678 #endif //USE_SVMLIGHT
679 }
680 
683 {
684  if (rhs!=lhs)
685  SG_UNREF(rhs);
686  rhs = NULL;
687  num_rhs=0;
688  lhs_equals_rhs=false;
689 
690 #ifdef USE_SVMLIGHT
691  cache_reset();
692 #endif //USE_SVMLIGHT
693 }
694 
695 #define ENUM_CASE(n) case n: SG_INFO(#n " ") break;
696 
698 {
699  SG_INFO("%p - \"%s\" weight=%1.2f OPT:%s", this, get_name(),
701  get_optimization_type()==FASTBUTMEMHUNGRY ? "FASTBUTMEMHUNGRY" :
702  "SLOWBUTMEMEFFICIENT");
703 
704  switch (get_kernel_type())
705  {
765  }
766 
767  switch (get_feature_class())
768  {
779  ENUM_CASE(C_WD)
789  }
790 
791  switch (get_feature_type())
792  {
807  }
808  SG_INFO("\n")
809 }
810 #undef ENUM_CASE
811 
813  int32_t count, int32_t *IDX, float64_t * weights)
814 {
815  SG_ERROR("kernel does not support linadd optimization\n")
816  return false ;
817 }
818 
820 {
821  SG_ERROR("kernel does not support linadd optimization\n")
822  return false;
823 }
824 
826 {
827  SG_ERROR("kernel does not support linadd optimization\n")
828  return 0;
829 }
830 
832  int32_t num_vec, int32_t* vec_idx, float64_t* target, int32_t num_suppvec,
833  int32_t* IDX, float64_t* weights, float64_t factor)
834 {
835  SG_ERROR("kernel does not support batch computation\n")
836 }
837 
838 void CKernel::add_to_normal(int32_t vector_idx, float64_t weight)
839 {
840  SG_ERROR("kernel does not support linadd optimization, add_to_normal not implemented\n")
841 }
842 
844 {
845  SG_ERROR("kernel does not support linadd optimization, clear_normal not implemented\n")
846 }
847 
849 {
850  return 1;
851 }
852 
854  int32_t vector_idx, float64_t * subkernel_contrib)
855 {
856  SG_ERROR("kernel compute_by_subkernel not implemented\n")
857 }
858 
859 const float64_t* CKernel::get_subkernel_weights(int32_t &num_weights)
860 {
861  num_weights=1 ;
862  return &combined_kernel_weight ;
863 }
864 
866 {
867  int num_weights = 1;
868  const float64_t* weight = get_subkernel_weights(num_weights);
869  return SGVector<float64_t>(const_cast<float64_t*>(weight),1,false);
870 }
871 
873 {
874  ASSERT(weights.vector)
875  if (weights.vlen!=1)
876  SG_ERROR("number of subkernel weights should be one ...\n")
877 
878  combined_kernel_weight = weights.vector[0] ;
879 }
880 
882 {
883  if (kernel)
884  {
885  CKernel* casted=dynamic_cast<CKernel*>(kernel);
886  REQUIRE(casted, "CKernel::obtain_from_generic(): Error, provided object"
887  " of class \"%s\" is not a subclass of CKernel!\n",
888  kernel->get_name());
889  return casted;
890  }
891  else
892  return NULL;
893 }
894 
896 {
897  int32_t num_suppvec=svm->get_num_support_vectors();
898  int32_t* sv_idx=SG_MALLOC(int32_t, num_suppvec);
899  float64_t* sv_weight=SG_MALLOC(float64_t, num_suppvec);
900 
901  for (int32_t i=0; i<num_suppvec; i++)
902  {
903  sv_idx[i] = svm->get_support_vector(i);
904  sv_weight[i] = svm->get_alpha(i);
905  }
906  bool ret = init_optimization(num_suppvec, sv_idx, sv_weight);
907 
908  SG_FREE(sv_idx);
909  SG_FREE(sv_weight);
910  return ret;
911 }
912 
914 {
916  if (lhs_equals_rhs)
917  rhs=lhs;
918 }
919 
921 {
923 
924  if (lhs_equals_rhs)
925  rhs=NULL;
926 }
927 
929 {
931 
932  if (lhs_equals_rhs)
933  rhs=lhs;
934 }
935 
937  SG_ADD(&cache_size, "cache_size",
938  "Cache size in MB.", MS_NOT_AVAILABLE);
939  SG_ADD((CSGObject**) &lhs, "lhs",
940  "Feature vectors to occur on left hand side.", MS_NOT_AVAILABLE);
941  SG_ADD((CSGObject**) &rhs, "rhs",
942  "Feature vectors to occur on right hand side.", MS_NOT_AVAILABLE);
943  SG_ADD(&lhs_equals_rhs, "lhs_equals_rhs",
944  "If features on lhs are the same as on rhs.", MS_NOT_AVAILABLE);
945  SG_ADD(&num_lhs, "num_lhs", "Number of feature vectors on left hand side.",
947  SG_ADD(&num_rhs, "num_rhs", "Number of feature vectors on right hand side.",
949  SG_ADD(&combined_kernel_weight, "combined_kernel_weight",
950  "Combined kernel weight.", MS_AVAILABLE);
951  SG_ADD(&optimization_initialized, "optimization_initialized",
952  "Optimization is initialized.", MS_NOT_AVAILABLE);
953  SG_ADD((machine_int_t*) &opt_type, "opt_type",
954  "Optimization type.", MS_NOT_AVAILABLE);
955  SG_ADD(&properties, "properties", "Kernel properties.", MS_NOT_AVAILABLE);
956  SG_ADD((CSGObject**) &normalizer, "normalizer", "Normalize the kernel.",
957  MS_AVAILABLE);
958 }
959 
960 
961 void CKernel::init()
962 {
963  cache_size=10;
964  kernel_matrix=NULL;
965  lhs=NULL;
966  rhs=NULL;
967  num_lhs=0;
968  num_rhs=0;
969  lhs_equals_rhs=false;
974  normalizer=NULL;
975 
976 #ifdef USE_SVMLIGHT
977  memset(&kernel_cache, 0x0, sizeof(KERNEL_CACHE));
978 #endif //USE_SVMLIGHT
979 
981 }
982 
983 namespace shogun
984 {
986 template <class T> struct K_THREAD_PARAM
987 {
991  int32_t start;
993  int32_t end;
995  int32_t total_start;
997  int32_t total_end;
999  int32_t m;
1001  int32_t n;
1007  bool verbose;
1008 };
1009 }
1010 
1011 template <class T> void* CKernel::get_kernel_matrix_helper(void* p)
1012 {
1013  K_THREAD_PARAM<T>* params= (K_THREAD_PARAM<T>*) p;
1014  int32_t i_start=params->start;
1015  int32_t i_end=params->end;
1016  CKernel* k=params->kernel;
1017  T* result=params->result;
1018  bool symmetric=params->symmetric;
1019  int32_t n=params->n;
1020  int32_t m=params->m;
1021  bool verbose=params->verbose;
1022  int64_t total_start=params->total_start;
1023  int64_t total_end=params->total_end;
1024  int64_t total=total_start;
1025 
1026  for (int32_t i=i_start; i<i_end; i++)
1027  {
1028  int32_t j_start=0;
1029 
1030  if (symmetric)
1031  j_start=i;
1032 
1033  for (int32_t j=j_start; j<n; j++)
1034  {
1035  float64_t v=k->kernel(i,j);
1036  result[i+j*m]=v;
1037 
1038  if (symmetric && i!=j)
1039  result[j+i*m]=v;
1040 
1041  if (verbose)
1042  {
1043  total++;
1044 
1045  if (symmetric && i!=j)
1046  total++;
1047 
1048  if (total%100 == 0)
1049  SG_OBJ_PROGRESS(k, total, total_start, total_end)
1050 
1052  break;
1053  }
1054  }
1055 
1056  }
1057 
1058  return NULL;
1059 }
1060 
1061 template <class T>
1063 {
1064  T* result = NULL;
1065 
1066  REQUIRE(has_features(), "no features assigned to kernel\n")
1067 
1068  int32_t m=get_num_vec_lhs();
1069  int32_t n=get_num_vec_rhs();
1070 
1071  int64_t total_num = int64_t(m)*n;
1072 
1073  // if lhs == rhs and sizes match assume k(i,j)=k(j,i)
1074  bool symmetric= (lhs && lhs==rhs && m==n);
1075 
1076  SG_DEBUG("returning kernel matrix of size %dx%d\n", m, n)
1077 
1078  result=SG_MALLOC(T, total_num);
1079 
1080  int32_t num_threads=parallel->get_num_threads();
1081  if (num_threads < 2)
1082  {
1083  K_THREAD_PARAM<T> params;
1084  params.kernel=this;
1085  params.result=result;
1086  params.start=0;
1087  params.end=m;
1088  params.total_start=0;
1089  params.total_end=total_num;
1090  params.n=n;
1091  params.m=m;
1092  params.symmetric=symmetric;
1093  params.verbose=true;
1094  get_kernel_matrix_helper<T>((void*) &params);
1095  }
1096  else
1097  {
1098  pthread_t* threads = SG_MALLOC(pthread_t, num_threads-1);
1099  K_THREAD_PARAM<T>* params = SG_MALLOC(K_THREAD_PARAM<T>, num_threads);
1100  int64_t step= total_num/num_threads;
1101 
1102  int32_t t;
1103 
1104  num_threads--;
1105  for (t=0; t<num_threads; t++)
1106  {
1107  params[t].kernel = this;
1108  params[t].result = result;
1109  params[t].start = compute_row_start(t*step, n, symmetric);
1110  params[t].end = compute_row_start((t+1)*step, n, symmetric);
1111  params[t].total_start=t*step;
1112  params[t].total_end=(t+1)*step;
1113  params[t].n=n;
1114  params[t].m=m;
1115  params[t].symmetric=symmetric;
1116  params[t].verbose=false;
1117 
1118  int code=pthread_create(&threads[t], NULL,
1119  CKernel::get_kernel_matrix_helper<T>, (void*)&params[t]);
1120 
1121  if (code != 0)
1122  {
1123  SG_WARNING("Thread creation failed (thread %d of %d) "
1124  "with error:'%s'\n",t, num_threads, strerror(code));
1125  num_threads=t;
1126  break;
1127  }
1128  }
1129 
1130  params[t].kernel = this;
1131  params[t].result = result;
1132  params[t].start = compute_row_start(t*step, n, symmetric);
1133  params[t].end = m;
1134  params[t].total_start=t*step;
1135  params[t].total_end=total_num;
1136  params[t].n=n;
1137  params[t].m=m;
1138  params[t].symmetric=symmetric;
1139  params[t].verbose=true;
1140  get_kernel_matrix_helper<T>(&params[t]);
1141 
1142  for (t=0; t<num_threads; t++)
1143  {
1144  if (pthread_join(threads[t], NULL) != 0)
1145  SG_WARNING("pthread_join of thread %d/%d failed\n", t, num_threads)
1146  }
1147 
1148  SG_FREE(params);
1149  SG_FREE(threads);
1150  }
1151 
1152  SG_DONE()
1153 
1154  return SGMatrix<T>(result,m,n,true);
1155 }
1156 
1159 
1160 template void* CKernel::get_kernel_matrix_helper<float64_t>(void* p);
1161 template void* CKernel::get_kernel_matrix_helper<float32_t>(void* p);

SHOGUN Machine Learning Toolbox - Documentation