3
3
# wujian@17.10.25
4
4
5
5
import math
6
+ import os
6
7
import numpy as np
7
8
8
9
LOG_PI = math .log (math .pi )
@@ -45,76 +46,90 @@ def __init__(self, num_bins, time_steps, num_channels):
45
46
# lambda, phi, R for noisy/noise part
46
47
self .lambda_ = np .random .rand (num_bins , time_steps ).astype (np .complex )
47
48
self .phi = np .ones ([num_bins , time_steps ]).astype (np .complex )
48
- # type matrix
49
- self .R = [np .matrix (np .eye (num_channels , num_channels ).astype (np .complex )) \
50
- for i in range (num_bins )]
51
-
49
+
50
+ def init_sigma (self , sigma ):
51
+ """
52
+ Inputs: sigma is a np.matrix list
53
+ Keeps \sigma^{-1} and det(\sigma), \sigma equals \mean(y^H * y)
54
+ """
55
+ assert type (sigma ) == list
56
+ self .sigma_inv = [mat .I for mat in sigma ]
57
+ self .sigma_det = [np .linalg .det (mat ) for mat in sigma ]
58
+
52
59
def check_inputs (self , inputs ):
53
60
num_bins , time_steps , num_channels = inputs .shape
54
61
assert num_bins == self .num_bins and time_steps == self .time_steps \
55
- and num_channels == self .dim , 'inputs dim does not match CGMM config'
62
+ and num_channels == self .dim , 'Inputs dim does not match CGMM config'
56
63
57
64
def log_likelihood (self , spectrums ):
58
65
self .check_inputs (spectrums )
59
66
posteriors = 0.0
60
67
for f in range (self .num_bins ):
61
- sigma_inv = self .R [f ].I
62
- sigma_det = np .linalg .det (self .R [f ])
63
68
for t in range (self .time_steps ):
64
69
posteriors += self .lambda_ [f , t ] * gmm_posterior (spectrums [f , t ], \
65
- self .phi [f , t ], sigma_inv , sigma_det )
70
+ self .phi [f , t ], self . sigma_inv [ f ], self . sigma_det [ f ] )
66
71
return posteriors
67
72
68
73
def accu_stats (self , spectrums ):
69
74
self .check_inputs (spectrums )
70
75
stats = np .zeros ([self .num_bins , self .time_steps ]).astype (np .complex )
71
76
for f in range (self .num_bins ):
72
- sigma_inv = self .R [f ].I
73
- sigma_det = np .linalg .det (self .R [f ])
74
77
for t in range (self .time_steps ):
75
78
stats [f , t ] = gmm_posterior (spectrums [f , t ], self .phi [f , t ], \
76
- sigma_inv , sigma_det )
79
+ self . sigma_inv [ f ], self . sigma_det [ f ] )
77
80
return stats
78
81
79
82
def update_lambda (self , spectrums , stats ):
80
83
print ('update lambda...' )
84
+ assert stats .shape == self .lambda_ .shape
81
85
for f in range (self .num_bins ):
82
- sigma_inv = self .R [f ].I
83
- sigma_det = np .linalg .det (self .R [f ])
84
86
for t in range (self .time_steps ):
85
87
self .lambda_ [f , t ] = gmm_posterior (spectrums [f , t ], self .phi [f , t ], \
86
- sigma_inv , sigma_det ) / stats [f , t ]
88
+ self .sigma_inv [f ], self .sigma_det [f ])
89
+ self .lambda_ = self .lambda_ / stats
87
90
88
- def update_phi (self , spectrums ):
91
+ def update_phi (self , covar ):
89
92
print ('update phi...' )
90
93
for f in range (self .num_bins ):
91
- inv_R = self .R [f ].I
92
94
for t in range (self .time_steps ):
93
- y = np .matrix ( spectrums [ f , t ])
94
- self .phi [ f , t ] = np . trace ( y . H * y * inv_R ) / self .dim
95
+ self . phi [ f , t ] = np .trace ( covar [ f * self . time_steps + t ] * self . sigma_inv [ f ])
96
+ self .phi = self . phi / self .dim
95
97
96
- def update_R (self , spectrums ):
98
+ def update_R (self , covar ):
97
99
print ('update R...' )
98
100
for f in range (self .num_bins ):
99
101
sum_lambda = self .lambda_ [f ].sum ()
100
- self . R [ f ] = 0
102
+ R = np . matrix ( np . zeros ([ self . dim , self . dim ]). astype ( np . complex ))
101
103
for t in range (self .time_steps ):
102
- y = np .matrix (spectrums [f , t ])
103
- self .R [f ] += self .lambda_ [f , t ] * y .H * y / self .phi [f , t ]
104
- self .R [f ] = self .R [f ] / sum_lambda
104
+ R += self .lambda_ [f , t ] * covar [f * self .time_steps + t ] / self .phi [f , t ]
105
+ R = R / sum_lambda
106
+ self .sigma_inv [f ] = R .I
107
+ self .sigma_det [f ] = np .linalg .det (R )
105
108
106
- def update_parameters (self , spectrums , stats ):
109
+ def update_parameters (self , spectrums , covar , stats ):
107
110
self .check_inputs (spectrums )
111
+ assert len (covar ) == self .num_bins * self .time_steps and type (covar ) == list
108
112
self .update_lambda (spectrums , stats )
109
- self .update_phi (spectrums )
110
- self .update_R (spectrums )
113
+ self .update_phi (covar )
114
+ self .update_R (covar )
111
115
112
116
class CGMMTrainer (object ):
113
117
def __init__ (self , num_bins , time_steps , num_channels ):
114
118
self .noise_part = CGMM (num_bins , time_steps , num_channels )
115
119
self .noisy_part = CGMM (num_bins , time_steps , num_channels )
116
120
self .num_samples = num_bins * time_steps
117
-
121
+
122
+ def init_sigma (self , spectrums ):
123
+ # precompute the covariance matrix of each channel
124
+ print ("initialize sigma..." )
125
+ num_bins , time_steps , num_channels = spectrums .shape
126
+ self .covar = [y .H * y for y in [np .matrix (spectrums [f , t ]) \
127
+ for f in range (num_bins ) for t in range (time_steps )]]
128
+ self .noise_part .init_sigma ([np .matrix (np .eye (num_channels , \
129
+ num_channels ).astype (np .complex )) for f in range (num_bins )])
130
+ self .noisy_part .init_sigma ([sum (self .covar [f * time_steps : \
131
+ (f + 1 ) * time_steps ]) / time_steps for f in range (num_bins )])
132
+
118
133
def log_likelihood (self , spectrums ):
119
134
return (self .noise_part .log_likelihood (spectrums ) + \
120
135
self .noisy_part .log_likelihood (spectrums )) / self .num_samples
@@ -125,14 +140,22 @@ def accu_stats(self, spectrums):
125
140
self .noise_part .accu_stats (spectrums )
126
141
127
142
def update_parameters (self , spectrums , stats ):
128
- self .noise_part .update_parameters (spectrums , stats )
129
- self .noisy_part .update_parameters (spectrums , stats )
130
-
143
+ self .noise_part .update_parameters (spectrums , self .covar , stats )
144
+ self .noisy_part .update_parameters (spectrums , self .covar , stats )
145
+
146
+ def save_param (self , dest ):
147
+ sigma_ny = [mat .I for mat in self .noisy_part .sigma_inv ]
148
+ sigma_ne = [mat .I for mat in self .noise_part .sigma_inv ]
149
+ if not os .path .exists (dest ):
150
+ os .mkdir (dest )
151
+ np .save (os .path .join (dest , 'sigma_noisy' ), sigma_ny )
152
+ np .save (os .path .join (dest , 'sigma_noise' ), sigma_ne )
153
+
131
154
def train (self , spectrums , iters = 30 ):
155
+ self .init_sigma (spectrums )
132
156
print ('Likelihood: ({0.real:.5f}, {0.imag:.5f}i)' .format (self .log_likelihood (spectrums )))
133
157
for it in range (1 , iters + 1 ):
134
158
stats = self .accu_stats (spectrums )
135
159
self .update_parameters (spectrums , stats )
136
160
print ('epoch {0:2d}: Likelihood = ({1.real:.5f}, {1.imag:.5f}i)' .format (it , \
137
161
self .log_likelihood (spectrums )))
138
-
0 commit comments