Пример #1
0
    # Beta min value
    if latent_dim == 2:
        beta_min = 0.6
    elif latent_dim == 3:
        beta_min = 0.2
    elif latent_dim == 5:
        beta_min = 0.25
    elif latent_dim == 7:
        beta_min = 0.22
    elif latent_dim == 10:
        beta_min = 0.2
    elif latent_dim == 12:
        beta_min = 0.16

    # Instantiate the manifolds
    spd_manifold = pyman_man.PositiveDefinite(dim)
    latent_spd_manifold = pyman_man.PositiveDefinite(latent_dim)

    # Update the random function of the manifold (the original one samples only eigenvalues between 1 and 2).
    # We need to specify the minimum and maximum eigenvalues of the random matrices. This is done when defining bounds.
    spd_manifold.rand = types.MethodType(spd_sample, spd_manifold)

    # Define the test function
    # Parameters for the nested test function
    grassmann_manifold = pyman_man.Grassmann(dim, latent_dim)
    projection_matrix_test = torch.from_numpy(
        grassmann_manifold.rand()).double()

    # Define the nested test function
    test_function = functools.partial(
        projected_function_spd,
Пример #2
0
    # Define the dimension
    # If the dimension is changed:
    # - the optimization domain must be updated as one domain per dimension is required by gpflowopt
    dim = 2

    # Define the dimension of the Mandel vector notation
    dim_vec = int(dim + dim * (dim - 1) / 2)

    # True to display sphere figures (possible only if the dimension is 3 (3D graphs))
    display_figures = True

    # Number of BO iterations
    nb_iter_bo = 25

    # Instantiate the manifold (for the objective function and for initial observations, to have the same as GaBO)
    spd_manifold = pyman_man.PositiveDefinite(dim)

    # Bounding eigenvalues
    min_eigenvalue = 0.001
    max_eigenvalue = 5.

    # Define minimum and maximum eigenvalue constraints
    def minimum_eigenvalue_constraint(x_chol):
        indices = np.tril_indices(dim)
        xL = np.zeros((dim, dim))
        xL[indices] = x_chol

        x = np.dot(xL, xL.T)
        eig, _ = np.linalg.eig(x)
        return np.min(eig) - min_eigenvalue
Пример #3
0
def optimize_reconstruction_parameters_nested_spd(
        x_data,
        x_data_projected,
        projection_matrix,
        inner_solver,
        cost_function=min_affine_invariant_distance_reconstruction_cost,
        nb_init_candidates=100,
        maxiter=50):
    """
    This function computes the parameters of the mapping "projection_from_nested_spd_to_spd" from nested SPD matrices
    Y = W'XW to SPD matrices Xrec, so that the distance between the original data X and the reconstructed data Xrec
    is minimized.
    To do so, we consider that the nested SPD matrix Y = W'XW is the d x d upper-left part of the rotated matrix
    Xr = R'XR, where R = [W, V] and Xr = [Y B; B' C].
    In order to recover X, we assume a constant SPD matrix C, and B = Y^0.5*K*C^0.5 to ensure the PDness of Xr, with
    K a contraction matrix (norm(K) <=1). We first reconstruct Xr, and then Xrec as X = RXrR'.
    We are minimizing the squared distance between X and Xrec, by optimizing the complement to the projection matrix V,
    the bottom SPD matrix C, and the contraction matrix K. The contraction matrix K is described here as a norm-1
    matrix multiplied by a factor in [0,1] (unconstraintly optimized by transform it with a sigmoid function).
    The augmented Lagrange optimization method on Riemannian manifold is used to optimize the parameters on the product
    of manifolds G(D,D-d), SPD(D-d), S(d*(D-d)) and Eucl(1), while respecting the constraint W'V = 0.

    Parameters
    ----------
    :param x_data: set of high-dimensional SPD matrices                                             (N x D x D)
    :param x_data_projected: set of low-dimensional SPD matrices (projected from x_data)            (N x d x d)
    :param projection_matrix: element of the Grassmann manifold                                     (D x d)
    :param inner_solver: inner solver for the ALM on Riemnannian manifolds

    Optional parameters
    -------------------
    :param nb_init_candidates: number of initial candidates for the optimization
    :param maxiter: maximum iteration of ALM solver

    Returns
    -------
    :return: projection_complement_matrix: element of the Grassmann manifold                        (D x D-d)
        so that torch.mm(projection_complement_matrix.T, projection_matrix) = 0.
    :return: bottom_spd_matrix: bottom-right part of the rotated SPD matrix                         (D-d, D-d)
    :return: contraction_matrix: matrix whose norm is <=1                                           (d x D-d)
    """
    # Dimensions
    dim = x_data.shape[1]
    latent_dim = projection_matrix.shape[1]

    # Product of manifolds for the optimization
    manifolds_list = [
        pyman_man.Grassmann(dim, dim - latent_dim),
        pyman_man.PositiveDefinite(dim - latent_dim),
        pyman_man.Sphere(latent_dim * (dim - latent_dim)),
        pyman_man.Euclidean(1)
    ]
    product_manifold = pyman_man.Product(manifolds_list)

    # Constraint on the norm of the contraction matrix
    contraction_norm_constraint = gpytorch.constraints.Interval(0., 1.)

    # Constraint W'V = 0
    def constraint_fct(parameters):
        cost = torch.norm(torch.mm(parameters[0].T, projection_matrix))
        zero_element_needed_for_correct_grad = 0. * torch.norm(parameters[1]) + 0. * torch.norm(parameters[2]) + \
                                               0. * torch.norm(parameters[3])
        return cost + zero_element_needed_for_correct_grad

    # Reconstruction cost
    def reconstruction_cost(parameters):
        projection_complement_matrix = parameters[0]
        bottom_spd_matrix = parameters[1]
        contraction_norm = contraction_norm_constraint.transform(parameters[3])
        contraction_matrix = contraction_norm * parameters[2].view(
            latent_dim, dim - latent_dim)

        return cost_function(x_data, x_data_projected, projection_matrix,
                             projection_complement_matrix, bottom_spd_matrix,
                             contraction_matrix)

    # Generate candidate for initial data
    x0_candidates = [
        product_manifold.rand() for i in range(nb_init_candidates)
    ]
    x0_candidates_torch = []
    for x0 in x0_candidates:
        x0_candidates_torch.append([torch.from_numpy(x) for x in x0])
    y0_candidates = [
        reconstruction_cost(x0_candidates_torch[i])
        for i in range(nb_init_candidates)
    ]

    # Initialize with the best of the candidates
    y0, x_init_idx = torch.Tensor(y0_candidates).min(0)
    x0 = x0_candidates[x_init_idx]

    # Define the optimization problem
    reconstruction_problem = Problem(manifold=product_manifold,
                                     cost=reconstruction_cost,
                                     arg=torch.Tensor(),
                                     verbosity=0)
    # Define ALM solver
    solver = AugmentedLagrangeMethod(maxiter=maxiter,
                                     inner_solver=inner_solver,
                                     lambdas_fact=0.05)

    # Solve
    spd_parameters_np = solver.solve(reconstruction_problem,
                                     x=x0,
                                     eq_constraints=constraint_fct)

    # Parameters to torch data
    projection_complement_matrix = torch.from_numpy(spd_parameters_np[0])
    bottom_spd_matrix = torch.from_numpy(spd_parameters_np[1])
    contraction_norm = contraction_norm_constraint.transform(
        torch.from_numpy(spd_parameters_np[3]))
    contraction_matrix = contraction_norm * torch.from_numpy(
        spd_parameters_np[2]).view(latent_dim, dim - latent_dim)

    return projection_complement_matrix, bottom_spd_matrix, contraction_matrix