JWS C Library
C language utility library
|
00001 /* 00002 * This work is licensed under a Creative Commons 00003 * Attribution-Noncommercial-Share Alike 3.0 United States License. 00004 * 00005 * http://creativecommons.org/licenses/by-nc-sa/3.0/us/ 00006 * 00007 * You are free: 00008 * 00009 * to Share - to copy, distribute, display, and perform the work 00010 * to Remix - to make derivative works 00011 * 00012 * Under the following conditions: 00013 * 00014 * Attribution. You must attribute the work in the manner specified by the 00015 * author or licensor (but not in any way that suggests that they endorse you 00016 * or your use of the work). 00017 * 00018 * Noncommercial. You may not use this work for commercial purposes. 00019 * 00020 * Share Alike. If you alter, transform, or build upon this work, you may 00021 * distribute the resulting work only under the same or similar license to 00022 * this one. 00023 * 00024 * For any reuse or distribution, you must make clear to others the license 00025 * terms of this work. The best way to do this is by including this header. 00026 * 00027 * Any of the above conditions can be waived if you get permission from the 00028 * copyright holder. 00029 * 00030 * Apart from the remix rights granted under this license, nothing in this 00031 * license impairs or restricts the author's moral rights. 00032 */ 00033 00034 00046 #include <jwsc/config.h> 00047 00048 #include <stdlib.h> 00049 #include <stdio.h> 00050 #include <assert.h> 00051 #include <math.h> 00052 #include <inttypes.h> 00053 00054 #include "jwsc/base/limits.h" 00055 #include "jwsc/vector/vector.h" 00056 #include "jwsc/vector/vector_math.h" 00057 #include "jwsc/matrix/matrix.h" 00058 #include "jwsc/matrix/matrix_math.h" 00059 #include "jwsc/matblock/matblock.h" 00060 #include "jwsc/prob/mv_pdf.h" 00061 #include "jwsc/stat/stat.h" 00062 #include "jwsc/stat/kmeans.h" 00063 #include "jwsc/stat/gmm.h" 00064 00065 00070 static void ensure_non_singular_covariance_d(Matrix_d** m, double min) 00071 { 00072 uint32_t n, N; 00073 00074 Matrix_d* v = NULL; 00075 Vector_d* d = NULL; 00076 Matrix_d* dd = NULL; 00077 Error* e; 00078 00079 N = (*m)->num_rows; 00080 00081 /* 00082 for (n = 0; n < N; n++) 00083 { 00084 if ((*m)->elts[ n ][ n ] < min) 00085 { 00086 (*m)->elts[ n ][ n ] = min; 00087 } 00088 } 00089 */ 00090 00091 assert((e = solve_real_symmetric_matrix_eigenproblem_d(&v, &d, *m)) == NULL); 00092 create_zero_matrix_d(&dd, N, N); 00093 00094 for (n = 0; n < N; n++) 00095 { 00096 if (d->elts[ n ] < min) 00097 { 00098 dd->elts[ n ][ n ] = min; 00099 } 00100 else 00101 { 00102 dd->elts[ n ][ n ] = d->elts[ n ]; 00103 } 00104 } 00105 00106 multiply_matrices_d(m, v, dd); 00107 transpose_matrix_d(&v, v); 00108 multiply_matrices_d(m, *m, v); 00109 00110 free_matrix_d(v); 00111 free_vector_d(d); 00112 free_matrix_d(dd); 00113 } 00114 00115 00117 static void gmm_e_step_d 00118 ( 00119 const Matrix_d* mu, 00120 const Matblock_d* sigma, 00121 const Vector_d* pi, 00122 Matrix_d* gamma, 00123 const Matrix_d* x 00124 ) 00125 { 00126 uint32_t n, N; 00127 uint32_t k, K; 00128 double C_n; 00129 00130 Vector_d* p_k = 0; 00131 Vector_d* mu_k = 0; 00132 Matrix_d* sigma_k = 0; 00133 Error* e; 00134 00135 N = x->num_rows; 00136 K = pi->num_elts; 00137 00138 create_zero_matrix_d(&gamma, N, K); 00139 00140 for (k = 0; k < K; k++) 00141 { 00142 copy_vector_from_matrix_d(&mu_k, mu, MATRIX_ROW_VECTOR, k); 00143 copy_matrix_from_matblock_d(&sigma_k, sigma, MATBLOCK_MAT_MATRIX, k); 00144 00145 assert((e = set_mv_gaussian_pdf_d(&p_k, mu_k, sigma_k, x)) == 0); 00146 00147 copy_vector_into_matrix_d(&gamma, gamma, p_k, MATRIX_COL_VECTOR, k); 00148 } 00149 00150 for (n = 0; n < N; n++) 00151 { 00152 C_n = 0; 00153 00154 for (k = 0; k < K; k++) 00155 { 00156 gamma->elts[ n ][ k ] *= pi->elts[ k ]; 00157 00158 C_n += gamma->elts[ n ][ k ]; 00159 } 00160 00161 assert(C_n > 0); 00162 00163 for (k = 0; k < K; k++) 00164 { 00165 gamma->elts[ n ][ k ] /= C_n; 00166 } 00167 } 00168 00169 free_vector_d(p_k); 00170 free_vector_d(mu_k); 00171 free_matrix_d(sigma_k); 00172 } 00173 00174 00176 static void gmm_m_step_d 00177 ( 00178 Matrix_d* mu, 00179 Matblock_d* sigma, 00180 Vector_d* pi, 00181 const Matrix_d* gamma, 00182 const Matrix_d* x 00183 ) 00184 { 00185 uint32_t k, K; 00186 uint32_t n, N; 00187 uint32_t d, dd, D; 00188 double s_1, s_2; 00189 00190 Vector_d* mu_k = NULL; 00191 Matrix_d* sigma_k = NULL; 00192 00193 K = pi->num_elts; 00194 N = x->num_rows; 00195 D = x->num_cols; 00196 00197 create_zero_vector_d(&pi, K); 00198 00199 // mu 00200 create_matrix_d(&mu, K, D); 00201 for (k = 0; k < K; k++) 00202 { 00203 create_zero_vector_d(&mu_k, D); 00204 00205 for (n = 0; n < N; n++) 00206 { 00207 for (d = 0; d < D; d++) 00208 { 00209 mu_k->elts[ d ] += gamma->elts[ n ][ k ]*x->elts[ n ][ d ]; 00210 } 00211 00212 pi->elts[ k ] += gamma->elts[ n ][ k ]; 00213 } 00214 00215 assert(pi->elts[ k ] > 0); 00216 00217 multiply_vector_by_scalar_d(&mu_k, mu_k, 1.0 / pi->elts[ k ]); 00218 copy_vector_into_matrix_d(&mu, mu, mu_k, MATRIX_ROW_VECTOR, k); 00219 } 00220 00221 // sigma 00222 create_matblock_d(&sigma, K, D, D); 00223 for (k = 0; k < K; k++) 00224 { 00225 create_zero_matrix_d(&sigma_k, D, D); 00226 00227 for (n = 0; n < N; n++) 00228 { 00229 for (d = 0; d < D; d++) 00230 { 00231 s_1 = x->elts[ n ][ d ] - mu->elts[ k ][ d ]; 00232 00233 for (dd = 0; dd < D; dd++) 00234 { 00235 s_2 = x->elts[ n ][ dd ] - mu->elts[ k ][ dd ]; 00236 00237 sigma_k->elts[ d ][ dd ] += gamma->elts[ n ][ k ] * s_1*s_2; 00238 } 00239 } 00240 } 00241 00242 multiply_matrix_by_scalar_d(&sigma_k, sigma_k, 1.0 / pi->elts[ k ]); 00243 ensure_non_singular_covariance_d(&sigma_k, 1.0e-1); 00244 copy_matrix_into_matblock_d(&sigma, sigma, sigma_k, 00245 MATBLOCK_MAT_MATRIX, k); 00246 } 00247 00248 // pi 00249 multiply_vector_by_scalar_d(&pi, pi, 1.0 / N); 00250 00251 free_vector_d(mu_k); 00252 free_matrix_d(sigma_k); 00253 } 00254 00255 00262 double gmm_log_likelihood_d 00263 ( 00264 const Matrix_d* mu, 00265 const Matblock_d* sigma, 00266 const Vector_d* pi, 00267 const Matrix_d* x 00268 ) 00269 { 00270 uint32_t n, N; 00271 uint32_t k, K; 00272 double ll; 00273 00274 Matrix_d* p = 0; 00275 Vector_d* p_k = 0; 00276 Vector_d* q = 0; 00277 Vector_d* mu_k = 0; 00278 Matrix_d* sigma_k = 0; 00279 Error* e; 00280 00281 N = x->num_rows; 00282 K = pi->num_elts; 00283 00284 create_matrix_d(&p, N, K); 00285 00286 for (k = 0; k < K; k++) 00287 { 00288 copy_vector_from_matrix_d(&mu_k, mu, MATRIX_ROW_VECTOR, k); 00289 copy_matrix_from_matblock_d(&sigma_k, sigma, MATBLOCK_MAT_MATRIX, k); 00290 00291 assert((e = set_mv_gaussian_pdf_d(&p_k, mu_k, sigma_k, x)) == 0); 00292 00293 copy_vector_into_matrix_d(&p, p, p_k, MATRIX_COL_VECTOR, k); 00294 } 00295 00296 multiply_matrix_and_vector_d(&q, p, pi); 00297 ll = 0; 00298 00299 for (n = 0; n < N; n++) 00300 { 00301 ll += log((q->elts[ n ] < JWSC_MIN_LOG_ARG) 00302 ? JWSC_MIN_LOG_ARG : q->elts[ n ]); 00303 } 00304 00305 #if defined(JWSC_HAVE_ISNAN) && defined(JWSC_HAVE_ISINF) 00306 assert(!isnan(ll) && !isinf(ll)); 00307 #endif 00308 00309 free_matrix_d(p); 00310 free_vector_d(p_k); 00311 free_vector_d(q); 00312 free_vector_d(mu_k); 00313 free_matrix_d(sigma_k); 00314 00315 return ll; 00316 } 00317 00318 00331 void gmm_kmeans_init_d 00332 ( 00333 Matrix_d** mu_out, 00334 Matblock_d** sigma_out, 00335 Vector_d** pi_out, 00336 const Matrix_d* x, 00337 uint32_t K 00338 ) 00339 { 00340 uint32_t d, D; 00341 uint32_t n, nn, N; 00342 uint32_t k; 00343 00344 Vector_i32* members = NULL; 00345 Vector_u32* counts = NULL; 00346 Matrix_d* x_k = NULL; 00347 Matrix_d* sigma_k = NULL; 00348 00349 D = x->num_cols; 00350 N = x->num_rows; 00351 00352 init_kmeans_randomly_d(mu_out, x, K); 00353 kmeans_d(mu_out, &members, x, K, 2); 00354 00355 create_matblock_d(sigma_out, K, D, D); 00356 create_zero_vector_u32(&counts, K); 00357 00358 for (n = 0; n < N; n++) 00359 { 00360 k = members->elts[ n ]; 00361 counts->elts[ k ]++; 00362 } 00363 for (k = 0; k < K; k++) 00364 { 00365 create_matrix_d(&x_k, counts->elts[ k ], D); 00366 00367 nn = 0; 00368 for (n = 0; n < N; n++) 00369 { 00370 if (k == members->elts[ n ]) 00371 { 00372 for (d = 0; d < D; d++) 00373 { 00374 x_k->elts[ nn ][ d ] = x->elts[ n ][ d ]; 00375 } 00376 nn++; 00377 } 00378 } 00379 00380 mv_sample_covariance_d(&sigma_k, x_k); 00381 ensure_non_singular_covariance_d(&sigma_k, 1.0e-1); 00382 copy_matrix_into_matblock_d(sigma_out, *sigma_out, sigma_k, 00383 MATBLOCK_MAT_MATRIX, k); 00384 } 00385 00386 create_vector_d(pi_out, K); 00387 for (k = 0; k < K; k++) 00388 { 00389 (*pi_out)->elts[ k ] = counts->elts[ k ] / (double)N; 00390 } 00391 00392 free_vector_i32(members); 00393 free_vector_u32(counts); 00394 free_matrix_d(x_k); 00395 free_matrix_d(sigma_k); 00396 } 00397 00398 00413 void gmm_stats_init_d 00414 ( 00415 Matrix_d** mu_out, 00416 Matblock_d** sigma_out, 00417 Vector_d** pi_out, 00418 const Matrix_d* x, 00419 uint32_t K 00420 ) 00421 { 00422 uint32_t k; 00423 uint32_t D; 00424 00425 Vector_d* mu_0 = 0; 00426 Vector_d* mu_k = 0; 00427 Matrix_d* sigma_k = 0; 00428 00429 D = x->num_cols; 00430 00431 if (*pi_out == NULL) 00432 { 00433 create_init_vector_d(pi_out, K, 1.0 / (double)K); 00434 } 00435 else 00436 { 00437 assert((*pi_out)->num_elts == K); 00438 } 00439 00440 if (*sigma_out == NULL) 00441 { 00442 create_matblock_d(sigma_out, K, D, D); 00443 mv_sample_covariance_d(&sigma_k, x); 00444 ensure_non_singular_covariance_d(&sigma_k, 1.0e-1); 00445 00446 for (k = 0; k < K; k++) 00447 { 00448 copy_matrix_into_matblock_d(sigma_out, *sigma_out, sigma_k, 00449 MATBLOCK_MAT_MATRIX, k); 00450 } 00451 } 00452 else 00453 { 00454 assert((*sigma_out)->num_mats == K && (*sigma_out)->num_rows == D 00455 && (*sigma_out)->num_cols == D); 00456 00457 for (k = 0; k < K; k++) 00458 { 00459 copy_matrix_from_matblock_d(&sigma_k, *sigma_out, 00460 MATBLOCK_MAT_MATRIX, k); 00461 ensure_non_singular_covariance_d(&sigma_k, 1.0e-1); 00462 copy_matrix_into_matblock_d(sigma_out, *sigma_out, sigma_k, 00463 MATBLOCK_MAT_MATRIX, k); 00464 } 00465 } 00466 00467 if (*mu_out == NULL) 00468 { 00469 create_matrix_d(mu_out, K, D); 00470 mv_sample_mean_d(&mu_0, x); 00471 copy_vector_into_matrix_d(mu_out, *mu_out, mu_0, MATRIX_ROW_VECTOR, 0); 00472 00473 for (k = 1; k < K; k++) 00474 { 00475 sample_mv_gaussian_pdf_d(&mu_k, mu_0, sigma_k); 00476 copy_vector_into_matrix_d(mu_out, *mu_out, mu_k, 00477 MATRIX_ROW_VECTOR, k); 00478 } 00479 } 00480 else 00481 { 00482 assert((*mu_out)->num_rows == K && (*mu_out)->num_cols == D); 00483 } 00484 00485 free_vector_d(mu_0); 00486 free_vector_d(mu_k); 00487 free_matrix_d(sigma_k); 00488 } 00489 00490 00505 void train_gmm_d 00506 ( 00507 Matrix_d** mu_out, 00508 Matblock_d** sigma_out, 00509 Vector_d** pi_out, 00510 Matrix_d** gamma_out, 00511 const Matrix_d* x, 00512 uint32_t K 00513 ) 00514 { 00515 double ll, ll_prev; 00516 00517 Matrix_d* mu; 00518 Matblock_d* sigma; 00519 Vector_d* pi; 00520 Matrix_d* gamma = 0; 00521 00522 gmm_kmeans_init_d(mu_out, sigma_out, pi_out, x, K); 00523 mu = *mu_out; 00524 sigma = *sigma_out; 00525 pi = *pi_out; 00526 00527 if (gamma_out) 00528 { 00529 create_matrix_d(gamma_out, x->num_rows, pi->num_elts); 00530 gamma = *gamma_out; 00531 } 00532 else 00533 { 00534 create_matrix_d(&gamma, x->num_rows, pi->num_elts); 00535 } 00536 00537 ll_prev = 0; 00538 ll = log(0); 00539 00540 while (fabs(ll - ll_prev) > 1.0e-10) 00541 { 00542 gmm_e_step_d(mu, sigma, pi, gamma, x); 00543 gmm_m_step_d(mu, sigma, pi, gamma, x); 00544 00545 ll_prev = ll; 00546 ll = gmm_log_likelihood_d(mu, sigma, pi, x); 00547 } 00548 00549 if (!gamma_out) 00550 { 00551 free_matrix_d(gamma); 00552 } 00553 }