7
7
from scipy .stats import multivariate_normal as ss_multivariate_normal
8
8
from scipy .stats import wishart as ss_wishart
9
9
from scipy .stats import multivariate_t as ss_multivariate_t
10
+ from scipy .stats import dirichlet as ss_dirichlet
11
+ from scipy .special import gammaln , digamma , xlogy
10
12
import matplotlib .pyplot as plt
11
13
12
14
from .. import base
@@ -450,7 +452,7 @@ class LearnModel(base.Posterior,base.PredictiveMixin):
450
452
the inverse matrices of hn_w_mats
451
453
r_vecs : numpy.ndarray
452
454
vectors of real numbers. The sum of its elenemts is 1.
453
- Ns : numpy.ndarray
455
+ ns : numpy.ndarray
454
456
positive real numbers
455
457
s_mats : numpy.ndarray
456
458
positive difinite symmetric matrices
@@ -486,6 +488,9 @@ def __init__(
486
488
self .h0_w_mats = np .tile (np .identity (self .degree ),[self .num_classes ,1 ,1 ])
487
489
self .h0_w_mats_inv = np .linalg .inv (self .h0_w_mats )
488
490
491
+ self .LN_C_H0_ALPHA = 0.0
492
+ self .LN_B_H0_W_NUS = np .empty (self .num_classes )
493
+
489
494
# hn_params
490
495
self .hn_alpha_vec = np .empty ([self .num_classes ])
491
496
self .hn_m_vecs = np .empty ([self .num_classes ,self .degree ])
@@ -494,6 +499,15 @@ def __init__(
494
499
self .hn_w_mats = np .empty ([self .num_classes ,self .degree ,self .degree ])
495
500
self .hn_w_mats_inv = np .empty ([self .num_classes ,self .degree ,self .degree ])
496
501
502
+ # statistics
503
+ self .r_vecs = None
504
+ self .x_bar_vecs = np .empty ([self .num_classes ,self .degree ])
505
+ self .ns = np .empty (self .num_classes )
506
+ self .s_mats = np .empty ([self .num_classes ,self .degree ,self .degree ])
507
+ self .e_lambda_mats = np .empty ([self .num_classes ,self .degree ,self .degree ])
508
+ self .e_ln_lambda_dets = np .empty (self .num_classes )
509
+ self .e_ln_pi_vec = np .empty (self .num_classes )
510
+
497
511
# p_params
498
512
self .p_pi_vec = np .empty ([self .num_classes ])
499
513
self .p_mu_vecs = np .empty ([self .num_classes ,self .degree ])
@@ -564,6 +578,15 @@ def set_h0_params(
564
578
self .h0_w_mats [:] = h0_w_mats
565
579
self .h0_w_mats_inv [:] = np .linalg .inv (self .h0_w_mats )
566
580
581
+ self .LN_C_H0_ALPHA = gammaln (self .h0_alpha_vec .sum ()) - gammaln (self .h0_alpha_vec ).sum ()
582
+ self .LN_B_H0_W_NUS = (
583
+ - self .h0_nus * np .linalg .slogdet (self .h0_w_mats )[1 ]
584
+ - self .h0_nus * self .degree * np .log (2.0 )
585
+ - self .degree * (self .degree - 1 )/ 2.0 * np .log (np .pi )
586
+ - np .sum (gammaln ((self .h0_nus [:,np .newaxis ]- np .arange (self .degree )) / 2.0 ),
587
+ axis = 1 ) * 2.0
588
+ ) / 2.0
589
+
567
590
self .reset_hn_params ()
568
591
569
592
def get_h0_params (self ):
@@ -689,6 +712,67 @@ def overwrite_h0_params(self):
689
712
690
713
self .calc_pred_dist ()
691
714
715
+ def calc_vl (self ):
716
+ self .e_lambda_mats = self .hn_nus [:,np .newaxis ,np .newaxis ] * self .hn_w_mats
717
+ self .e_ln_lambda_dets = (np .sum (digamma ((self .hn_nus [:,np .newaxis ]- np .arange (self .degree )) / 2.0 ),axis = 1 )
718
+ + self .degree * np .log (2.0 )
719
+ - np .linalg .slogdet (self .hn_w_mats_inv )[1 ])
720
+ self .e_ln_pi_vec = digamma (self .hn_alpha_vec ) - digamma (self .hn_alpha_vec .sum ())
721
+
722
+ # tentative
723
+ self .ns = np .ones (self .num_classes ) * 10
724
+ self .s_mats = np .tile (np .identity (self .degree ),[self .num_classes ,1 ,1 ]) * 5
725
+ self .r_vecs = np .ones ([20 ,self .degree ])/ self .degree
726
+ self .x_bar_vecs = np .ones ([self .num_classes ,self .degree ])
727
+
728
+ vl = 0.0
729
+
730
+ # E[ln p(X|Z,mu,Lambda)]
731
+ vl += np .sum (
732
+ self .ns
733
+ * (self .e_ln_lambda_dets - self .degree / self .hn_kappas
734
+ - (self .s_mats * self .e_lambda_mats ).sum (axis = (1 ,2 ))
735
+ - ((self .x_bar_vecs - self .hn_m_vecs )[:,np .newaxis ,:]
736
+ @ self .e_lambda_mats
737
+ @ (self .x_bar_vecs - self .hn_m_vecs )[:,:,np .newaxis ]
738
+ )[:,0 ,0 ]
739
+ - self .degree * np .log (2 * np .pi )
740
+ )
741
+ ) / 2.0
742
+
743
+ # E[ln p(Z|pi)]
744
+ vl += (self .ns * self .e_ln_pi_vec ).sum ()
745
+
746
+ # E[ln p(pi)]
747
+ vl += self .LN_C_H0_ALPHA + ((self .h0_alpha_vec - 1 ) * self .e_ln_pi_vec ).sum ()
748
+
749
+ # E[ln p(mu,Lambda)]
750
+ vl += np .sum (
751
+ self .degree * (np .log (self .h0_kappas ) - np .log (2 * np .pi ) - self .h0_kappas / self .hn_kappas )
752
+ - ((self .hn_m_vecs - self .h0_m_vecs )[:,np .newaxis ,:]
753
+ @ self .e_lambda_mats
754
+ @ (self .hn_m_vecs - self .h0_m_vecs )[:,:,np .newaxis ])[:,0 ,0 ]
755
+ + 2.0 * self .LN_B_H0_W_NUS
756
+ + (self .h0_nus - self .degree ) / 2.0 * self .e_ln_lambda_dets
757
+ - np .sum (self .h0_w_mats_inv * self .hn_w_mats ,axis = (1 ,2 ))
758
+ ) / 2.0
759
+
760
+ # E[ln q(Z|pi)]
761
+ vl -= np .sum (xlogy (self .r_vecs ,self .r_vecs ))
762
+
763
+ # E[ln q(pi)]
764
+ vl += ss_dirichlet .entropy (self .hn_alpha_vec )
765
+
766
+ # E[ln q(mu,Lambda)]
767
+ vl += np .sum (
768
+ + self .degree * (1.0 + np .log (2.0 * np .pi ) - np .log (self .hn_kappas ))
769
+ - self .LN_B_H0_W_NUS * 2.0
770
+ - (self .hn_nus - self .degree )* self .e_ln_lambda_dets
771
+ + self .hn_nus * self .degree
772
+ ) / 2.0
773
+
774
+ return vl
775
+
692
776
def update_posterior (self ,x ):
693
777
pass
694
778
# """Update the hyperparameters of the posterior distribution using traning data.
0 commit comments