def build_poe(self, b_frames, tau_frames, win_mats, sdw=None): """ Computes natural parameters for a Gaussian product-of-experts model. The natural parameters (b-value vector and precision matrix) are returned. The returned precision matrix is stored as a BandMat. Mathematically the b-value vector is given as: b = \sum_d \transpose{W_d} \tilde{b}_d and the precision matrix is given as: P = \sum_d \transpose{W_d} \text{diag}(\tilde{tau}_d) W_d where $W_d$ is the window matrix for window $d$ as specified by an element of `win_mats`, $\tilde{b}_d$ is the sequence over time of b-value parameters for window $d$ as given by a column of `b_frames`, and $\tilde{\tau}_d$ is the sequence over time of precision parameters for window $d$ as given by a column of `tau_frames`. """ if sdw is None: sdw = max([win_mat.l + win_mat.u for win_mat in win_mats]) num_windows = len(win_mats) frames = len(b_frames) assert np.shape(b_frames) == (frames, num_windows) assert np.shape(tau_frames) == (frames, num_windows) assert all([win_mat.l + win_mat.u <= sdw for win_mat in win_mats]) b = np.zeros((frames, )) prec = bm.zeros(sdw, sdw, frames) for win_index, win_mat in enumerate(win_mats): bm.dot_mv_plus_equals(win_mat.T, b_frames[:, win_index], target=b) bm.dot_mm_plus_equals(win_mat.T, win_mat, target_bm=prec, diag=float64(tau_frames[:, win_index])) return b, prec
def unit_variance_mlpg_matrix(windows, T): """Compute MLPG matrix assuming input is normalized to have unit-variances. Let :math:`\mu` is the input mean sequence (``num_windows*T x static_dim``), :math:`W` is a window matrix ``(T x num_windows*T)``, assuming input is normalized to have unit-variances, MLPG can be written as follows: .. math:: y = R \mu where .. math:: R = (W^{T} W)^{-1} W^{T} Here we call :math:`R` as the MLPG matrix. Args: windows: (list): List of windows. T (int): Number of frames. Returns: numpy.ndarray: MLPG matrix (``T x nun_windows*T``). See also: :func:`nnmnkwii.autograd.UnitVarianceMLPG`, :func:`nnmnkwii.paramgen.mlpg`. Examples: >>> from nnmnkwii import paramgen as G >>> import numpy as np >>> windows = [ ... (0, 0, np.array([1.0])), ... (1, 1, np.array([-0.5, 0.0, 0.5])), ... (1, 1, np.array([1.0, -2.0, 1.0])), ... ] >>> G.unit_variance_mlpg_matrix(windows, 3) array([[ 2.73835927e-01, 1.95121944e-01, 9.20177400e-02, 9.75609720e-02, -9.09090936e-02, -9.75609720e-02, -3.52549881e-01, -2.43902430e-02, 1.10864742e-02], [ 1.95121944e-01, 3.41463417e-01, 1.95121944e-01, 1.70731708e-01, -5.55111512e-17, -1.70731708e-01, -4.87804860e-02, -2.92682916e-01, -4.87804860e-02], [ 9.20177400e-02, 1.95121944e-01, 2.73835927e-01, 9.75609720e-02, 9.09090936e-02, -9.75609720e-02, 1.10864742e-02, -2.43902430e-02, -3.52549881e-01]], dtype=float32) """ win_mats = build_win_mats(windows, T) sdw = np.max([win_mat.l + win_mat.u for win_mat in win_mats]) P = bm.zeros(sdw, sdw, T) for win_index, win_mat in enumerate(win_mats): bm.dot_mm_plus_equals(win_mat.T, win_mat, target_bm=P) chol_bm = bla.cholesky(P, lower=True) Pinv = cholesky_inv_banded(chol_bm.full(), width=chol_bm.l + chol_bm.u + 1) cocatenated_window = full_window_mat(win_mats, T) return Pinv.dot(cocatenated_window.T).astype(np.float32)
def _get_banded_test_mat(win_mats, T): import bandmat as bm sdw = max([win_mat.l + win_mat.u for win_mat in win_mats]) P = bm.zeros(sdw, sdw, T) for win_index, win_mat in enumerate(win_mats): bm.dot_mm_plus_equals(win_mat.T, win_mat, target_bm=P) return P
def test_zeros(self, its=50): for it in range(its): size = random.choice([0, 1, randint(0, 10), randint(0, 100)]) l = random.choice([0, 1, randint(0, 10)]) u = random.choice([0, 1, randint(0, 10)]) mat_bm = bm.zeros(l, u, size) assert mat_bm.l == l assert mat_bm.u == u assert_allequal(mat_bm.full(), np.zeros((size, size)))
def build_wuw(self, frame_number, tau_frames, win_mats, sdw=None): if sdw is None: sdw = max([ win_mat.l + win_mat.u for win_mat in win_mats ]) prec = bm.zeros(sdw, sdw, frame_number) for win_index, win_mat in enumerate(win_mats): bm.dot_mm_plus_equals(win_mat.T, win_mat, target_bm=prec, diag=float64(tau_frames[:, win_index])) return prec
def build_wu(self, frame_number, tau_frames, win_mats, sdw=None): if sdw is None: sdw = max([ win_mat.l + win_mat.u for win_mat in win_mats ]) wu_list = [] for win_index, win_mat in enumerate(win_mats): temp_wu = bm.zeros(sdw, sdw, frame_number) bm.dot_mm_plus_equals(win_mat.T, win_mats[0], target_bm=temp_wu, diag=float64(tau_frames[:, win_index])) wu_list.append(temp_wu.full()) return wu_list
def build_wuw(self, frame_number, tau_frames, win_mats, sdw=None): if sdw is None: sdw = max([win_mat.l + win_mat.u for win_mat in win_mats]) prec = bm.zeros(sdw, sdw, frame_number) for win_index, win_mat in enumerate(win_mats): bm.dot_mm_plus_equals(win_mat.T, win_mat, target_bm=prec, diag=float64(tau_frames[:, win_index])) return prec
def build_wu(self, frame_number, tau_frames, win_mats, sdw=None): if sdw is None: sdw = max([win_mat.l + win_mat.u for win_mat in win_mats]) wu_list = [] for win_index, win_mat in enumerate(win_mats): temp_wu = bm.zeros(sdw, sdw, frame_number) bm.dot_mm_plus_equals(win_mat.T, win_mats[0], target_bm=temp_wu, diag=float64(tau_frames[:, win_index])) wu_list.append(temp_wu.full()) return wu_list
def gen_pos_def_BandMat(size, depth=None, contrib_rank=2, transposed=None): """Generates a random positive definite BandMat.""" assert contrib_rank >= 0 if depth is None: depth = random.choice([0, 1, randint(0, 10)]) if transposed is None: transposed = rand_bool() mat_bm = bm.zeros(depth, depth, size) for _ in range(contrib_rank): diff = randint(0, depth + 1) chol_bm = gen_BandMat(size, l=depth - diff, u=diff) bm.dot_mm_plus_equals(chol_bm, chol_bm.T, mat_bm) if transposed: mat_bm = mat_bm.T randomize_extra_entries_bm(mat_bm) return mat_bm
def build_poe(self, b_frames, tau_frames, win_mats, sdw=None): if sdw is None: sdw = max([win_mat.l + win_mat.u for win_mat in win_mats]) num_windows = len(win_mats) frames = len(b_frames) assert np.shape(b_frames) == (frames, num_windows) assert np.shape(tau_frames) == (frames, num_windows) assert all([win_mat.l + win_mat.u <= sdw for win_mat in win_mats]) b = np.zeros((frames,)) prec = bm.zeros(sdw, sdw, frames) for win_index, win_mat in enumerate(win_mats): bm.dot_mv_plus_equals(win_mat.T, b_frames[:, win_index], target=b) bm.dot_mm_plus_equals(win_mat.T, win_mat, target_bm=prec, diag=float64(tau_frames[:, win_index])) return b, prec
def test_sum_overlapping_m(self, its=50): for it in range(its): num_contribs = random.choice([0, 1, randint(10), randint(100)]) step = random.choice([1, randint(2), randint(10)]) width = max(step, 1) + random.choice([0, 1, randint(10)]) depth = width - 1 assert depth >= 0 overlap = width - step mat_size = num_contribs * step + overlap contribs = randn(num_contribs, width, width) target_bm = gen_BandMat(mat_size, l=depth, u=depth) target_bm_orig = target_bm.copy() mat_bm = bmo.sum_overlapping_m(contribs, step=step) assert mat_bm.size == mat_size assert mat_bm.l == mat_bm.u == depth # check target-based version adds to target_bm correctly bmo.sum_overlapping_m(contribs, step=step, target_bm=target_bm) assert_allclose(*cc(target_bm, target_bm_orig + mat_bm)) if num_contribs == 0: # check action for no contributions assert_allequal(mat_bm.full(), np.zeros((overlap, overlap))) elif num_contribs == 1: # check action for a single contribution assert_allequal(mat_bm.full(), contribs[0]) else: # check action under splitting list of contributions in two split_pos = randint(num_contribs + 1) mat_bm_again = bm.zeros(depth, depth, mat_size) bmo.sum_overlapping_m( contribs[:split_pos], step=step, target_bm=mat_bm_again.sub_matrix_view( 0, split_pos * step + overlap ) ) bmo.sum_overlapping_m( contribs[split_pos:], step=step, target_bm=mat_bm_again.sub_matrix_view( split_pos * step, mat_size ) ) assert_allclose(*cc(mat_bm, mat_bm_again))
def build_poe(self, b_frames, tau_frames, win_mats, sdw=None): # tau_frames.astype('float64') if sdw is None: sdw = max([ win_mat.l + win_mat.u for win_mat in win_mats ]) num_windows = len(win_mats) frames = len(b_frames) assert np.shape(b_frames) == (frames, num_windows) assert np.shape(tau_frames) == (frames, num_windows) assert all([ win_mat.l + win_mat.u <= sdw for win_mat in win_mats ]) b = np.zeros((frames,)) prec = bm.zeros(sdw, sdw, frames) for win_index, win_mat in enumerate(win_mats): bm.dot_mv_plus_equals(win_mat.T, b_frames[:, win_index], target=b) bm.dot_mm_plus_equals(win_mat.T, win_mat, target_bm=prec, diag=float64(tau_frames[:, win_index])) return b, prec
def test_sum_overlapping_m(self, its=50): for it in range(its): num_contribs = random.choice([0, 1, randint(10), randint(100)]) step = random.choice([1, randint(2), randint(10)]) width = max(step, 1) + random.choice([0, 1, randint(10)]) depth = width - 1 assert depth >= 0 overlap = width - step mat_size = num_contribs * step + overlap contribs = randn(num_contribs, width, width) target_bm = gen_BandMat(mat_size, l=depth, u=depth) target_bm_orig = target_bm.copy() mat_bm = bmo.sum_overlapping_m(contribs, step=step) assert mat_bm.size == mat_size assert mat_bm.l == mat_bm.u == depth # check target-based version adds to target_bm correctly bmo.sum_overlapping_m(contribs, step=step, target_bm=target_bm) assert_allclose(*cc(target_bm, target_bm_orig + mat_bm)) if num_contribs == 0: # check action for no contributions assert_allequal(mat_bm.full(), np.zeros((overlap, overlap))) elif num_contribs == 1: # check action for a single contribution assert_allequal(mat_bm.full(), contribs[0]) else: # check action under splitting list of contributions in two split_pos = randint(num_contribs + 1) mat_bm_again = bm.zeros(depth, depth, mat_size) bmo.sum_overlapping_m(contribs[:split_pos], step=step, target_bm=mat_bm_again.sub_matrix_view( 0, split_pos * step + overlap)) bmo.sum_overlapping_m(contribs[split_pos:], step=step, target_bm=mat_bm_again.sub_matrix_view( split_pos * step, mat_size)) assert_allclose(*cc(mat_bm, mat_bm_again))
def build_poe(b_frames, tau_frames, win_mats, sdw=None): if sdw is None: sdw = max([win_mat.l + win_mat.u for win_mat in win_mats]) num_windows = len(win_mats) frames = len(b_frames) b = numpy.zeros((frames, )) prec = bandmat.zeros(sdw, sdw, frames) for win_index, win_mat in enumerate(win_mats): bandmat.dot_mv_plus_equals(win_mat.T, b_frames[:, win_index], target=b) bandmat.dot_mm_plus_equals(win_mat.T, win_mat, target_bm=prec, diag=tau_frames[:, win_index]) return b, prec
def build_poe(b_frames, tau_frames, win_mats, sdw=None): r"""Computes natural parameters for a Gaussian product-of-experts model. The natural parameters (b-value vector and precision matrix) are returned. The returned precision matrix is stored as a BandMat. Mathematically the b-value vector is given as: b = \sum_d \transpose{W_d} \tilde{b}_d and the precision matrix is given as: P = \sum_d \transpose{W_d} \text{diag}(\tilde{tau}_d) W_d where $W_d$ is the window matrix for window $d$ as specified by an element of `win_mats`, $\tilde{b}_d$ is the sequence over time of b-value parameters for window $d$ as given by a column of `b_frames`, and $\tilde{\tau}_d$ is the sequence over time of precision parameters for window $d$ as given by a column of `tau_frames`. """ if sdw is None: sdw = max([ win_mat.l + win_mat.u for win_mat in win_mats ]) num_windows = len(win_mats) frames = len(b_frames) assert np.shape(b_frames) == (frames, num_windows) assert np.shape(tau_frames) == (frames, num_windows) assert all([ win_mat.l + win_mat.u <= sdw for win_mat in win_mats ]) b = np.zeros((frames,)) prec = bm.zeros(sdw, sdw, frames) for win_index, win_mat in enumerate(win_mats): bm.dot_mv_plus_equals(win_mat.T, b_frames[:, win_index], target=b) bm.dot_mm_plus_equals(win_mat.T, win_mat, target_bm=prec, diag=tau_frames[:, win_index]) return b, prec
def mlpg_grad(mean_frames, variance_frames, windows, grad_output): """MLPG gradient computation Parameters are same as :func:`nnmnkwii.paramgen.mlpg` except for ``grad_output``. See the function docmenent for what the parameters mean. Let :math:`d` is the index of static features, :math:`l` is the index of windows, gradients :math:`g_{d,l}` can be computed by: .. math:: g_{d,l} = (\sum_{l} W_{l}^{T}P_{d,l}W_{l})^{-1} W_{l}^{T}P_{d,l} where :math:`W_{l}` is a banded window matrix and :math:`P_{d,l}` is a diagonal precision matrix. Assuming the variances are diagonals, MLPG can be performed in dimention-by-dimention efficiently. Let :math:`o_{d}` be ``T`` dimentional back-propagated gradients, the resulting gradients :math:`g'_{l,d}` to be propagated are computed as follows: .. math:: g'_{d,l} = o_{d}^{T} g_{d,l} Args: mean_frames (numpy.ndarray): Means. variance_frames (numpy.ndarray): Variances. windows (list): Windows. grad_output: Backpropagated output gradient, shape (``T x static_dim``) Returns: numpy.ndarray: Gradients to be back propagated, shape: (``T x D``) See also: :func:`nnmnkwii.autograd.mlpg`, :class:`nnmnkwii.autograd.MLPG` """ T, D = mean_frames.shape win_mats = build_win_mats(windows, T) static_dim = D // len(windows) max_win_width = np.max([max(win_mat.l, win_mat.u) for win_mat in win_mats]) grads = np.zeros((T, D), dtype=np.float32) for d in range(static_dim): sdw = max([win_mat.l + win_mat.u for win_mat in win_mats]) # R: \sum_{l} W_{l}^{T}P_{d,l}W_{l} R = bm.zeros(sdw, sdw, T) # overwritten in the loop # dtype = np.float64 for bandmat precisions = np.zeros((len(windows), T), dtype=np.float64) for win_idx, win_mat in enumerate(win_mats): precisions[win_idx] = 1 / \ variance_frames[:, win_idx * static_dim + d] # use zero precisions at edge frames for dynamic features if win_idx != 0: precisions[win_idx, :max_win_width] = 0 precisions[win_idx, -max_win_width:] = 0 bm.dot_mm_plus_equals(win_mat.T, win_mat, target_bm=R, diag=precisions[win_idx]) for win_idx, win_mat in enumerate(win_mats): # r: W_{l}^{T}P_{d,l} r = bm.dot_mm(win_mat.T, bm.diag(precisions[win_idx])) # grad_{d, l} = R^{-1r} grad = solve_banded((R.l, R.u), R.data, r.full()) assert grad.shape == (T, T) # Finally we get grad for a particular dimension grads[:, win_idx * static_dim + d] = grad_output[:, d].T.dot(grad) return grads