Exemplo n.º 1
0
    def check_X(self, mask):
        """
        Check update equations of parent X.

        Use a simple model that has parent nodes and a child node around
        MatrixDot.
        """

        # Parent nodes
        A = Gaussian(self.a.reshape((self.D3,self.D2,1,self.M*self.N)),
                     np.identity(self.M*self.N),
                     name='A')
        X = Gaussian(np.zeros(self.N),
                     np.identity(self.N),
                     plates=(self.D3,1,self.D1),
                     name='X')
        # Node itself
        AX = MatrixDot(A, X, name='AX')
        # Child node
        Y = Gaussian(AX,
                     self.Lambda,
                     plates=(self.D4,self.D3,self.D2,self.D1),
                     name='Y')
        
        # Put in data
        Y.observe(self.y, mask=mask)

        # VB model
        Q = VB(Y, X)
        Q.update(X, repeat=1)
        u = X.get_moments()

        # Compute true solution
        mask = np.ones((self.D4,self.D3,self.D2,self.D1)) * mask
        vv = mask[...,np.newaxis,np.newaxis] * self.vv
        aa = np.einsum('...ki,...kl,...lj->...ij', self.a, vv, self.a)
        aa = aa + np.einsum('...ij,...kl,...kl->...ij', 
                            np.identity(self.N),
                            np.identity(self.M),
                            vv)
        aa = np.sum(aa, axis=2, keepdims=True)
        aa = np.sum(aa, axis=0)
        Cov_X = linalg.chol_inv(linalg.chol(aa + np.identity(self.N)))
        mu_X = np.einsum('...kj,...kl,...l->...j', 
                         self.a,
                         vv,
                         self.y)
        mu_X = np.sum(mu_X, axis=2, keepdims=True)
        mu_X = np.sum(mu_X, axis=0)
        mu_X = np.einsum('...ij,...j->...i', Cov_X, mu_X)

        # Compare VB results to the analytic solution:
        Cov_vb = u[1] - u[0][...,np.newaxis,:]*u[0][...,:,np.newaxis]
        testing.assert_allclose(Cov_vb, Cov_X,
                                err_msg="Incorrect second moment.")
        testing.assert_allclose(u[0], mu_X,
                                err_msg="Incorrect first moment.")
Exemplo n.º 2
0
    def check_A(self, mask):
        """
        Check update equations of parent A.

        Use a simple model that has parent nodes and a child node around
        MatrixDot.
        """

        # Parent nodes
        A = Gaussian(np.zeros(self.M*self.N), 
                     np.identity(self.M*self.N),
                     plates=(self.D3,self.D2,1),
                     name='A')
        X = Gaussian(self.x, np.identity(self.N), name='X')
        # Node itself
        AX = MatrixDot(A, X, name='AX')
        # Child node
        Y = Gaussian(AX,
                     self.Lambda,
                     plates=(self.D4,self.D3,self.D2,self.D1),
                     name='Y')
        
        # Put in data
        Y.observe(self.y, mask=mask)

        # VB model
        Q = VB(Y, A)
        Q.update(A, repeat=1)
        u = A.get_moments()

        # Compute true solution
        mask = np.ones((self.D4,self.D3,self.D2,self.D1)) * mask
        vv = mask[...,np.newaxis,np.newaxis] * self.vv
        xx = (self.x[...,:,np.newaxis] * self.x[...,np.newaxis,:]
              + np.identity(self.N))
        Cov_A = (vv[...,:,np.newaxis,:,np.newaxis] * 
                 xx[...,np.newaxis,:,np.newaxis,:]) # from data
        Cov_A = np.sum(Cov_A, axis=(0,3), keepdims=True)
        Cov_A = np.reshape(Cov_A, 
                           (self.D3,self.D2,1,self.M*self.N,self.M*self.N))
        Cov_A = Cov_A + np.identity(self.M*self.N) # add prior
        Cov_A = linalg.chol_inv(linalg.chol(Cov_A))
        mu_A = np.einsum('...ij,...j,...k->...ik', vv, self.y, self.x)
        mu_A = np.sum(mu_A, axis=(0,3))
        mu_A = np.reshape(mu_A, (self.D3,self.D2,1,self.M*self.N))
        mu_A = np.einsum('...ij,...j->...i', Cov_A, mu_A)


        # Compare VB results to the analytic solution:
        Cov_vb = u[1] - u[0][...,np.newaxis,:]*u[0][...,:,np.newaxis]
        testing.assert_allclose(Cov_vb, Cov_A,
                                err_msg="Incorrect second moment.")
        testing.assert_allclose(u[0], mu_A,
                                err_msg="Incorrect first moment.")
Exemplo n.º 3
0
    def check_A(self, mask):
        """
        Check update equations of parent A.

        Use a simple model that has parent nodes and a child node around
        MatrixDot.
        """

        # Parent nodes
        A = Gaussian(np.zeros(self.M * self.N),
                     np.identity(self.M * self.N),
                     plates=(self.D3, self.D2, 1),
                     name='A')
        X = Gaussian(self.x, np.identity(self.N), name='X')
        # Node itself
        AX = MatrixDot(A, X, name='AX')
        # Child node
        Y = Gaussian(AX,
                     self.Lambda,
                     plates=(self.D4, self.D3, self.D2, self.D1),
                     name='Y')

        # Put in data
        Y.observe(self.y, mask=mask)

        # VB model
        Q = VB(Y, A)
        Q.update(A, repeat=1)
        u = A.get_moments()

        # Compute true solution
        mask = np.ones((self.D4, self.D3, self.D2, self.D1)) * mask
        vv = mask[..., np.newaxis, np.newaxis] * self.vv
        xx = (self.x[..., :, np.newaxis] * self.x[..., np.newaxis, :] +
              np.identity(self.N))
        Cov_A = (vv[..., :, np.newaxis, :, np.newaxis] *
                 xx[..., np.newaxis, :, np.newaxis, :])  # from data
        Cov_A = np.sum(Cov_A, axis=(0, 3), keepdims=True)
        Cov_A = np.reshape(
            Cov_A, (self.D3, self.D2, 1, self.M * self.N, self.M * self.N))
        Cov_A = Cov_A + np.identity(self.M * self.N)  # add prior
        Cov_A = linalg.chol_inv(linalg.chol(Cov_A))
        mu_A = np.einsum('...ij,...j,...k->...ik', vv, self.y, self.x)
        mu_A = np.sum(mu_A, axis=(0, 3))
        mu_A = np.reshape(mu_A, (self.D3, self.D2, 1, self.M * self.N))
        mu_A = np.einsum('...ij,...j->...i', Cov_A, mu_A)

        # Compare VB results to the analytic solution:
        Cov_vb = u[1] - u[0][..., np.newaxis, :] * u[0][..., :, np.newaxis]
        testing.assert_allclose(Cov_vb,
                                Cov_A,
                                err_msg="Incorrect second moment.")
        testing.assert_allclose(u[0], mu_A, err_msg="Incorrect first moment.")
Exemplo n.º 4
0
    def check_X(self, mask):
        """
        Check update equations of parent X.

        Use a simple model that has parent nodes and a child node around
        MatrixDot.
        """

        # Parent nodes
        A = Gaussian(self.a.reshape((self.D3, self.D2, 1, self.M * self.N)),
                     np.identity(self.M * self.N),
                     name='A')
        X = Gaussian(np.zeros(self.N),
                     np.identity(self.N),
                     plates=(self.D3, 1, self.D1),
                     name='X')
        # Node itself
        AX = MatrixDot(A, X, name='AX')
        # Child node
        Y = Gaussian(AX,
                     self.Lambda,
                     plates=(self.D4, self.D3, self.D2, self.D1),
                     name='Y')

        # Put in data
        Y.observe(self.y, mask=mask)

        # VB model
        Q = VB(Y, X)
        Q.update(X, repeat=1)
        u = X.get_moments()

        # Compute true solution
        mask = np.ones((self.D4, self.D3, self.D2, self.D1)) * mask
        vv = mask[..., np.newaxis, np.newaxis] * self.vv
        aa = np.einsum('...ki,...kl,...lj->...ij', self.a, vv, self.a)
        aa = aa + np.einsum('...ij,...kl,...kl->...ij', np.identity(self.N),
                            np.identity(self.M), vv)
        aa = np.sum(aa, axis=2, keepdims=True)
        aa = np.sum(aa, axis=0)
        Cov_X = linalg.chol_inv(linalg.chol(aa + np.identity(self.N)))
        mu_X = np.einsum('...kj,...kl,...l->...j', self.a, vv, self.y)
        mu_X = np.sum(mu_X, axis=2, keepdims=True)
        mu_X = np.sum(mu_X, axis=0)
        mu_X = np.einsum('...ij,...j->...i', Cov_X, mu_X)

        # Compare VB results to the analytic solution:
        Cov_vb = u[1] - u[0][..., np.newaxis, :] * u[0][..., :, np.newaxis]
        testing.assert_allclose(Cov_vb,
                                Cov_X,
                                err_msg="Incorrect second moment.")
        testing.assert_allclose(u[0], mu_X, err_msg="Incorrect first moment.")
Exemplo n.º 5
0
    def compute_fixed_moments(self, Lambda, gradient=None):
        """ Compute moments for fixed x. """
        L = linalg.chol(Lambda, ndim=self.ndim)
        ldet = linalg.chol_logdet(L, ndim=self.ndim)
        u = [Lambda, ldet]

        if gradient is None:
            return u

        du0 = gradient[0]
        du1 = (misc.add_trailing_axes(gradient[1], 2 * self.ndim) *
               linalg.chol_inv(L, ndim=self.ndim))

        du = du0 + du1

        return (u, du)
Exemplo n.º 6
0
    def compute_fixed_moments(self, Lambda, gradient=None):
        """ Compute moments for fixed x. """
        L = linalg.chol(Lambda, ndim=self.ndim)
        ldet = linalg.chol_logdet(L, ndim=self.ndim)
        u = [Lambda,
             ldet]

        if gradient is None:
            return u

        du0 = gradient[0]
        du1 = (
            misc.add_trailing_axes(gradient[1], 2*self.ndim)
            * linalg.chol_inv(L, ndim=self.ndim)
        )

        du = du0 + du1

        return (u, du)
Exemplo n.º 7
0
    def compute_moments_and_cgf(self, phi, mask=True):
        r"""
        Return moments and cgf for given natural parameters

        .. math::

            \langle u \rangle =
            \begin{bmatrix}
              \phi_2 (-\phi_1)^{-1}
              \\
              -\log|-\phi_1| + \psi_k(\phi_2)
            \end{bmatrix}
            \\
            g(\phi) = \phi_2 \log|-\phi_1| - \log \Gamma_k(\phi_2)
        """
        U = linalg.chol(-phi[0])
        k = np.shape(phi[0])[-1]
        #k = self.dims[0][0]
        logdet_phi0 = linalg.chol_logdet(U)
        u0 = phi[1][...,np.newaxis,np.newaxis] * linalg.chol_inv(U)
        u1 = -logdet_phi0 + misc.multidigamma(phi[1], k)
        u = [u0, u1]
        g = phi[1] * logdet_phi0 - special.multigammaln(phi[1], k)
        return (u, g)
Exemplo n.º 8
0
    def compute_moments_and_cgf(self, phi, mask=True):
        r"""
        Return moments and cgf for given natural parameters

        .. math::

            \langle u \rangle =
            \begin{bmatrix}
              \phi_2 (-\phi_1)^{-1}
              \\
              -\log|-\phi_1| + \psi_k(\phi_2)
            \end{bmatrix}
            \\
            g(\phi) = \phi_2 \log|-\phi_1| - \log \Gamma_k(\phi_2)
        """
        U = linalg.chol(-phi[0])
        k = np.shape(phi[0])[-1]
        #k = self.dims[0][0]
        logdet_phi0 = linalg.chol_logdet(U)
        u0 = phi[1][..., np.newaxis, np.newaxis] * linalg.chol_inv(U)
        u1 = -logdet_phi0 + misc.multidigamma(phi[1], k)
        u = [u0, u1]
        g = phi[1] * logdet_phi0 - special.multigammaln(phi[1], k)
        return (u, g)