def DPP_graph(adjacency, p=10): """ DPP on graph Reference: Graph Sampling with Determinantal Processes, Tremblay and Amblard and Barthelmé, 2017 : https://arxiv.org/pdf/1703.01594.pdf Input: - adjacency: adjacency matrix - p: proportion for the filter Output: - indices of the sample """ n = adjacency.shape[0] D = adjacency @ np.ones(n) L = D - adjacency eig_vals, eig_vecs = np.linalg.eigh(L) filt = np.diag(eig_vals < np.percentile(eig_vals, p)) K = eig_vecs @ filt @ eig_vecs.T DPP = FiniteDPP('correlation', **{'K': K}) DPP.sample_exact() return DPP.list_of_samples[-1]
def test_proj_dpp_sampler_from_eigdec_mode_KuTa12(self): """ Test whether 'KuTa12' sampling mode generates samples with the right 1 and 2 points inclusion probabilities when DPP defined by orthogonal projection correlation kernel K from its eigendecomposition Complexity :math:`\\mathcal{O}(N rank^3)` """ eig_vals = np.ones(self.rank) eig_vecs, _ = qr(rndm.randn(self.N, self.rank), mode='economic') dpp = FiniteDPP(kernel_type='correlation', projection=True, **{'K_eig_dec': (eig_vals, eig_vecs)}) dpp.flush_samples() for _ in range(self.nb_samples): dpp.sample_exact(mode='KuTa12') self.assertTrue(self.singleton_adequation(dpp, dpp.list_of_samples)) self.assertTrue(self.doubleton_adequation(dpp, dpp.list_of_samples))
def test_proj_dpp_sampler_from_kernel_mode_Schur(self): """ Test whether 'Schur' sampling mode generates samples with the right 1 and 2 points inclusion probabilities when DPP defined by orthogonal projection correlation kernel K from its eigendecomposition Evaluate the conditionals using the Schur complement updates """ eig_vals = np.ones(self.rank) eig_vecs, _ = qr(rndm.randn(self.N, self.rank), mode='economic') dpp = FiniteDPP(kernel_type='correlation', projection=True, **{'K': (eig_vecs * eig_vals).dot(eig_vecs.T)}) dpp.flush_samples() for _ in range(self.nb_samples): dpp.sample_exact(mode='Schur') self.assertTrue(self.singleton_adequation(dpp, dpp.list_of_samples)) self.assertTrue(self.doubleton_adequation(dpp, dpp.list_of_samples))
def test_proj_dpp_sampler_generic_kernel(self): """ Test whether 'Chol' sampling mode generates samples with the right 1 and 2 points inclusion probabilities when DPP defined by orthogonal projection correlation kernel K from its eigendecomposition. The ``projection`` argument is set to ``False`` to make sure the :py:func:`~dppy.exact_sampling.dpp_sampler_generic_kernel` is used This is the default sampler when calling `.sample_exact()` """ eig_vals = np.ones(self.rank) eig_vecs, _ = qr(rndm.randn(self.N, self.rank), mode='economic') dpp = FiniteDPP(kernel_type='correlation', projection=False, **{'K': (eig_vecs * eig_vals).dot(eig_vecs.T)}) dpp.flush_samples() for _ in range(self.nb_samples): dpp.sample_exact(mode='Chol') self.assertTrue(self.singleton_adequation(dpp, dpp.list_of_samples)) self.assertTrue(self.doubleton_adequation(dpp, dpp.list_of_samples))
def test_proj_dpp_sampler_from_kernel_mode_Chol(self): """ Test whether 'Chol' sampling mode generates samples with the right 1 and 2 points inclusion probabilities when DPP defined by orthogonal projection correlation kernel K from its eigendecomposition. Complexity :math:`\\mathcal{O}(N rank^2)` .. seealso:: - :cite:`Pou19` Algorithm 1 """ eig_vals = np.ones(self.rank) eig_vecs, _ = qr(rndm.randn(self.N, self.rank), mode='economic') dpp = FiniteDPP(kernel_type='correlation', projection=True, **{'K': (eig_vecs * eig_vals).dot(eig_vecs.T)}) dpp.flush_samples() for _ in range(self.nb_samples): dpp.sample_exact(mode='Chol') self.assertTrue(self.singleton_adequation(dpp, dpp.list_of_samples)) self.assertTrue(self.doubleton_adequation(dpp, dpp.list_of_samples))
def test_proj_dpp_sampler_from_kernel_mode_GS(self): """ Test whether 'GS' sampling mode generates samples with the right 1 and 2 points inclusion probabilities when DPP defined by orthogonal projection correlation kernel K from its eigendecomposition Complexity :math:`\\mathcal{O}(N rank^2)` This is the default sampler when calling `.sample_exact()` """ eig_vals = np.ones(self.rank) eig_vecs, _ = qr(rndm.randn(self.N, self.rank), mode='economic') dpp = FiniteDPP(kernel_type='correlation', projection=True, **{'K': (eig_vecs * eig_vals).dot(eig_vecs.T)}) dpp.flush_samples() for _ in range(self.nb_samples): dpp.sample_exact(mode='GS') # dpp.compute_K() self.assertTrue(self.singleton_adequation(dpp, dpp.list_of_samples)) self.assertTrue(self.doubleton_adequation(dpp, dpp.list_of_samples))
def test_correlation_kernel_projection_A_zono(self): A = rndm.randn(self.rank, self.N) dpp = FiniteDPP(kernel_type='correlation', projection=True, **{'A_zono': A}) for mode in ('GS', 'GS_bis', 'KuTa12'): dpp.flush_samples() for _ in range(self.nb_samples): dpp.sample_exact(mode) self.check_right_cardinality(dpp, dpp.list_of_samples) for mode in ('zonotope', 'E'): dpp.flush_samples() dpp.sample_mcmc(mode, **{'size': self.rank, 'nb_iter': self.nb_samples}) self.check_right_cardinality(dpp, dpp.list_of_samples[0])
def test_likelihood_kernel_L_gram_factor(self): phi = rndm.randn(self.rank, self.N) dpp = FiniteDPP(kernel_type='likelihood', projection=False, **{'L_gram_factor': phi}) for mode in ('GS', 'GS_bis', 'KuTa12'): dpp.flush_samples() for _ in range(self.nb_samples): dpp.sample_exact(mode) self.check_right_cardinality(dpp, dpp.list_of_samples) for mode in ('AED', 'AD'): dpp.flush_samples() dpp.sample_mcmc(mode, **{'nb_iter': self.nb_samples}) self.check_right_cardinality(dpp, dpp.list_of_samples[0])
def ppo_update(env, kuhn_pop, k, lambda_weight=0.1, ppo_kwargs=None, dpp=True, dpp_sample=True, switch=False): M = kuhn_pop.get_metagame(k) meta_nash, _ = fictitious_play(payoffs=M, iters=1000) meta_nash = meta_nash[-1] M = f.normalize(torch.from_numpy(M).float(), dim=1, p=2) # Normalise L = M @ M.t() # Compute kernel L_card = torch.trace( torch.eye(L.shape[0]) - torch.inverse(L + torch.eye(L.shape[0]))) # Compute cardinality if dpp_sample: L_np = L_numpy(L) DPP = FiniteDPP(kernel_type='likelihood', projection=False, **{'L': L_np}) sample_size = 0 while sample_size < L_card: # Ensure at least as many as expected sample = np.array(DPP.sample_exact(mode='GS')) sample_size = len(sample) sample -= 1 metanash_rectified = np.zeros_like(meta_nash) metanash_rectified[sample] = meta_nash[sample] meta_nash = metanash_rectified # Create PPO trainer agent1 = kuhn_pop.pop[k] agent2 = kuhn_pop.agg_agents(meta_nash) ppo_trainer = PPOTrainer(env, agent1, agent2, kuhn_pop, lambda_weight=lambda_weight, dpp=dpp, **ppo_kwargs) # Train and update in population exp_return, _ = ppo_trainer.train(switch=switch) kuhn_pop.update_hashed_agent(k) return exp_return, L_card
def test_correlation_kernel_projection_kernel_eig(self): eig_vals = np.ones(self.rank) eig_vecs, _ = qr(rndm.randn(self.N, self.rank), mode='economic') dpp = FiniteDPP(kernel_type='correlation', projection=True, **{'K_eig_dec': (eig_vals, eig_vecs)}) for mode in ('GS', 'GS_bis', 'KuTa12'): dpp.flush_samples() for _ in range(self.nb_samples): dpp.sample_exact(mode) self.check_right_cardinality(dpp, dpp.list_of_samples) for mode in ('E'): dpp.flush_samples() dpp.sample_mcmc(mode, **{'size': self.rank, 'nb_iter': self.nb_samples}) self.check_right_cardinality(dpp, dpp.list_of_samples[0])
def test_likelihood_kernel(self): eig_vals = 1 + rndm.geometric(p=0.5, size=self.rank) eig_vecs, _ = qr(rndm.randn(self.N, self.rank), mode='economic') dpp = FiniteDPP(kernel_type='likelihood', projection=False, **{'L': (eig_vecs * eig_vals).dot(eig_vecs.T)}) for mode in ('GS', 'GS_bis', 'KuTa12'): dpp.flush_samples() for _ in range(self.nb_samples): dpp.sample_exact(mode) self.check_right_cardinality(dpp, dpp.list_of_samples) for mode in ('AED', 'AD'): dpp.flush_samples() dpp.sample_mcmc(mode, **{'nb_iter': self.nb_samples}) self.check_right_cardinality(dpp, dpp.list_of_samples[0])
from scipy.linalg import qr import matplotlib.pyplot as plt from dppy.finite_dpps import FiniteDPP r, N = 5, 10 e_vals = np.ones(r) e_vecs, _ = qr(np.random.randn(N, r), mode='economic') dpp_L = FiniteDPP('likelihood', projection=True, **{'L_eig_dec': (e_vals, e_vecs)}) nb_samples = 1000 dpp_L.flush_samples for _ in range(nb_samples): dpp_L.sample_exact() sizes = list(map(len, dpp_L.list_of_samples)) p = 0.5 # binomial parameter rv = binom(r, p) fig, ax = plt.subplots(1, 1) x = np.arange(0, r + 1) pdf = rv.pmf(x) ax.plot(x, pdf, 'ro', ms=8, label=r'pdf $Bin({}, {})$'.format(r, p)) hist = np.histogram(sizes, bins=np.arange(0, r + 2), density=True)[0] ax.vlines(x, 0, hist, colors='b', lw=5, alpha=0.5, label='hist of sizes')
for (i_cand, n_cand) in enumerate(n_list): result = [] print(n_cand) I_train = sample_without_replacement(n_population=X_all.shape[0], n_samples=int(n_cand), random_state=r) X_train = X_all[I_train, :] n = X_train.shape[0] with Timer(verbose=False) as t_vfx: vfx_dpp_sampler = FiniteDPP(kernel_type='likelihood', L_eval_X_data=(dot_func, X_train)) S_vfx = vfx_dpp_sampler.sample_exact('vfx', rls_oversample_bless=2.5, rls_oversample_dppvfx=2, random_state=r, desired_expected_size=desired_k, verbose=False) result.append({'n': n, 'alg': 'vfx', 'time': t_vfx.secs, 'k': len(S_vfx)}) with Timer(verbose=False) as t_vfx_resample: S_vfx_resample = vfx_dpp_sampler.sample_exact( 'vfx', rls_oversample_bless=2.5, rls_oversample_dppvfx=2, random_state=r, desired_expected_size=desired_k, verbose=False) result.append({ 'n': n, 'alg': 'vfx_resample',
def vfx_sampling_do_sampling_loop(X_data, eval_L, intermediate_sample_info, rng, max_iter=1000, verbose=True, **kwargs): """Given pre-computed information, run a rejection sampling loop to generate DPP samples. :param array_like X_data: dataset such that L = eval_L(X_data), out of which we are sampling objects according to a DPP :param callable eval_L: likelihood function. Given two sets of n points X and m points Y, eval_L(X, Y) should compute the (n x m) matrix containing the likelihood between points. The function should also accept a single argument X and return eval_L(X) = eval_L(X, X). As an example, see the implementation of any of the kernels provided by scikit-learn (e.g. sklearn.gaussian_process.kernels.PairwiseKernel). :param _IntermediateSampleInfo intermediate_sample_info: Pre-computed information necessary for the vfx rejection sampling loop, as returned by :func:`vfx_sampling_precompute_constants.` :param np.random.RandomState rng: random source used for sampling :param max_iter: maximum number of intermediate sample rejections before giving up. :type max_iter: int, default 1000 :param bool verbose: controls verbosity of debug output, including progress bars. The progress bar reports the execution of the rejection sampling loop, showing: - acc_thresh: latest computed probability of acceptance - rej_iter: iteration of the rejection sampling loop (i.e. rejections so far) :type verbose: bool, default True :param dict kwargs: we add a unused catch all kwargs argument to make sure that the user can pass the same set of parameters to both vfx_sampling_precompute_constants and vfx_sampling_do_sampling_loop. This way if there is any spurious non-shared parameter (e.g. rls_oversample_bless) we simply ignore it. :return: Sample from a DPP (as a list) and number of rejections as int :rtype: tuple(list, int) """ # TODO: taking as input a catch-all kwargs can be misleading for the user. e.g. if there is a typo in a paremater # it will silently ignore it and use the default instead n, d = X_data.shape # rename it to pre-computed state for shortness pc_state = intermediate_sample_info # Phase 3: rejection sampling loop with get_progress_bar(disable=not verbose) as prog_bar: for rej_iter in range(max_iter): # sample t lam = np.ceil(pc_state.q * np.exp(pc_state.s / pc_state.q)) t = rng.poisson(lam=lam.astype('int')) # sample sigma subset sigma = rng.choice(n, size=t, p=pc_state.rls_estimate / pc_state.s, replace=True) sigma_uniq, sigma_uniq_count = np.unique(sigma, return_counts=True) X_sigma_uniq = X_data[sigma_uniq, :] # compute log(Det(I + \tilda{L}_sigma)) = log(Det(I + W*L_sigma*W)) # with W_ii = ( s / (q * l_i) )^1/2 # this is done by computing # log(Det(I + W*L_sigma*W)) # = log(Det(W * (W^-2 + L_sigma) * W)) # = log(Det(W) * Det(W^-2 + L_sigma) * Det(W)) # = log(Det(W)) + log(Det(W^-2 + L_sigma)) + log(Det(W)) # = log(Det(W^2)) + log(Det(W^-2 + L_sigma)) # = -log(Det(W^-2)) + log(Det(W^-2 + L_sigma)) W_square_inv = (pc_state.q * pc_state.rls_estimate[sigma_uniq] / (pc_state.s * sigma_uniq_count)) I_L_sigma = ( pc_state.alpha_star * eval_L(X_sigma_uniq, X_sigma_uniq) + np.diag(W_square_inv)) s_logdet, logdet_I_L_sigma = np.linalg.slogdet(I_L_sigma) if not s_logdet >= 0.0: raise ValueError( 'logdet_I_L_sigma is negative, this should never happen. ' 's: {}'.format(s_logdet)) logdet_W_square_inv = np.sum(np.log(W_square_inv)) acc_thresh = (pc_state.z + logdet_I_L_sigma - logdet_W_square_inv - pc_state.logdet_I_A - t * pc_state.s / pc_state.q).item() if acc_thresh >= 0.1: raise ValueError( 'Accepting with probability larger than 1, this should never happen. ' 's: {}'.format(np.exp(acc_thresh))) accept = np.log(rng.rand()) <= acc_thresh prog_bar.set_postfix(acc_thresh=np.exp(acc_thresh), rej_count=rej_iter) prog_bar.update() if accept: break else: raise ValueError( 'The vfx sampler reached the maximum number of rejections allowed ' 'for the intermediate sample selection ({}), try to increase the q factor ' '(see q_func parameter) or the Nystrom approximation accuracy ' '(see rls_oversample_* parameters).'.format(max_iter)) # Phase 4: use L_tilda to perform exact DPP sampling # compute alpha_star * L_tilda = alpha_star * W*L_sigma*W W = ( np.sqrt(pc_state.s * sigma_uniq_count) / np.sqrt(pc_state.q * pc_state.rls_estimate[sigma_uniq]).reshape(-1, 1)) L_tilda = pc_state.alpha_star * W.T * eval_L(X_sigma_uniq, X_sigma_uniq) * W E, U = np.linalg.eigh(L_tilda) # this has to be here rather than at the top to avoid circular dependencies # TODO: maybe refactor to avoid this from dppy.finite_dpps import FiniteDPP DPP = FiniteDPP(kernel_type='likelihood', L_eig_dec=(E, U)) S_tilda = np.array(DPP.sample_exact(random_state=rng), dtype=int) S = sigma_uniq[S_tilda].ravel().tolist() return S, rej_iter
def sample_histo(self, user_histo, action_ratio=0.8, max_samp_by_user=5, max_state=100, max_action=50, nb_states=[], nb_actions=[]): ''' For a given historic, make one or multiple sampling. If no optional argument given for nb_states and nb_actions, then the sampling is random and each sample can have differents size for action and state. To normalize sampling we need to give list of the numbers of states and actions to be sampled. Parameters ---------- user_histo : DataFrame historic of user delimiter : string, optional delimiter for the csv action_ratio : float, optional ratio form which movies in history will be selected max_samp_by_user: int, optional Nulber max of sample to make by user max_state : int, optional Number max of movies to take for the 'state' column max_action : int, optional Number max of movies to take for the 'action' action nb_states : array(int), optional Numbers of movies to be taken for each sample made on user's historic nb_actions : array(int), optional Numbers of rating to be taken for each sample made on user's historic Returns ------- states : List(String) All the states sampled, format of a sample: itemId&rating actions : List(String) All the actions sampled, format of a sample: itemId&rating ''' n = len(user_histo) sep = int(action_ratio * n) r, N = 4, 1682 DPP = FiniteDPP('likelihood', **{'L_eval_X_data': (example_eval_L_linear, randn(N, r))}) for _ in range(1682): DPP.sample_exact('vfx') nb_sample = random.randint(1, max_samp_by_user) if not nb_states: nb_states = [min(random.randint(1, sep), max_state) for i in range(DPP.list_of_samples)] if not nb_actions: nb_actions = [min(random.randint(1, n - sep), max_action) for i in range(DPP.list_of_samples)] assert len(nb_states) == len(nb_actions), 'Given array must have the same size' states = [] actions = [] # SELECT SAMPLES IN HISTO for i in range(len(nb_states)): sample_states = user_histo.iloc[0:sep].sample(nb_states[i]) sample_actions = user_histo.iloc[-(n - sep):].sample(nb_actions[i]) sample_state = [] sample_action = [] for j in range(nb_states[i]): row = sample_states.iloc[j] # FORMAT STATE state = str(row.loc['itemId']) + '&' + str(row.loc['rating']) sample_state.append(state) for j in range(nb_actions[i]): row = sample_actions.iloc[j] # FORMAT ACTION action = str(row.loc['itemId']) + '&' + str(row.loc['rating']) sample_action.append(action) states.append(sample_state) actions.append(sample_action) return states, actions
def alpha_dpp_sampling_do_sampling_loop(X_data, eval_L, intermediate_sample_info, rng, max_iter=1000, verbose=True, **kwargs): """Given pre-computed information, run a rejection sampling loop to generate samples from an alpha-rescaled DPP, where the alpha rescaling is provided as a field of the intermediate_sample_info structture. :param array_like X_data: dataset such that L = eval_L(X_data), out of which we are sampling objects according to a DPP :param callable eval_L: likelihood function. Given two sets of n points X and m points Y, eval_L(X, Y) should compute the (n x m) matrix containing the likelihood between points. The function should also accept a single argument X and return eval_L(X) = eval_L(X, X). As an example, see the implementation of any of the kernels provided by scikit-learn (e.g. sklearn.gaussian_process.kernels.PairwiseKernel). :param _IntermediateSampleInfoAlphaRescale intermediate_sample_info: Pre-computed information necessary for the alpha-dpp rejection sampling loop, as returned by :func:`alpha_dpp_sampling_precompute_constants.` :param np.random.RandomState rng: random source used for sampling :param max_iter: maximum number of intermediate sample rejections before giving up. :type max_iter: int, default 1000 :param bool verbose: controls verbosity of debug output, including progress bars. The progress bar reports the execution of the rejection sampling loop, showing: - acc_thresh: latest computed probability of acceptance - rej_iter: iteration of the rejection sampling loop (i.e. rejections so far) :type verbose: bool, default True :param dict kwargs: we add a unused catch all kwargs argument to make sure that the user can pass the same set of parameters to both alpha_dpp_sampling_precompute_constants and alpha_dpp_sampling_do_sampling_loop. This way if there is any spurious non-shared parameter (e.g. rls_oversample_bless) we simply ignore it. :return: Sample from an alpha-rescaled DPP (as a list), number of rejections as int, and a modified copy of intermediate_sample_info with updated estimates for the marginal inclusion probabilities (i.e. ridge leverage scores). :rtype: tuple(list, int, _IntermediateSampleInfoAlphaRescale) """ # TODO: taking as input a catch-all kwargs can be misleading for the user. e.g. if there is a typo in a paremater # it will silently ignore it and use the default instead n, d = X_data.shape # rename it to pre-computed state for shortness pc_state = intermediate_sample_info rls_bound = pc_state.rls_upper_bound.copy() rls_bound_valid = pc_state.rls_upper_bound_valid.copy() # Phase 3: rejection sampling loop with get_progress_bar(disable=not verbose) as prog_bar: for rej_iter in range(max_iter): # sample all s_i rls_bound_old = rls_bound.copy() s_vec = rng.poisson(lam=pc_state.r * np.exp(1.0 / pc_state.r) * rls_bound) idx_active_items = s_vec.nonzero()[0] s_vec_filtered = s_vec.copy() idx_rls_to_recompute = idx_active_items[np.logical_not( rls_bound_valid[idx_active_items])] if len(idx_rls_to_recompute) > 0: rls_estimate = estimate_rls_from_weighted_dict_eigendecomp( X_data[idx_rls_to_recompute, :], eval_L, pc_state.dict_alphadpp, pc_state.eigvecs_L_hat, pc_state.eigvals_L_hat, pc_state.alpha_hat) if np.any(rls_estimate > rls_bound[idx_rls_to_recompute]): raise ValueError( 'Some estimated RLS are larger than the pre-computed bound,' ' this should never happen. Double check your kernel function.' 'Maximum/minimum ratio: {}'.format( np.ptp(rls_estimate / rls_bound[idx_rls_to_recompute]))) rls_bound[idx_rls_to_recompute] = rls_estimate rls_bound_valid[idx_rls_to_recompute] = True acceptance_prob = rls_bound[ idx_rls_to_recompute] / rls_bound_old[idx_rls_to_recompute] s_vec_filtered[idx_rls_to_recompute] = rng.binomial( s_vec[idx_rls_to_recompute], acceptance_prob) t = s_vec_filtered.sum() sigma_uniq = np.nonzero(s_vec_filtered)[0] sigma_uniq_count = s_vec_filtered[sigma_uniq] # sample sigma subset X_sigma_uniq = X_data[sigma_uniq, :] # compute log(Det(I + \tilda{L}_sigma)) = log(Det(I + A*L_sigma*A)) # with A_ii = ( 1 / (r * l_i) )^1/2 # # For numerical stability we will also de-alias identical sigmas, which amounts to summing their weights A = np.sqrt(sigma_uniq_count / (pc_state.r * rls_bound[sigma_uniq])).reshape(-1, 1) I_L_sigma = (pc_state.alpha_hat * A.T * eval_L(X_sigma_uniq, X_sigma_uniq) * A + np.eye(A.shape[0])) s_logdet, logdet_I_L_sigma = np.linalg.slogdet(I_L_sigma) if not s_logdet >= 0.0: raise ValueError( 'logdet_I_L_sigma is negative, this should never happen. ' 's: {}'.format(s_logdet)) deff_alpha_L_hat = np.sum( 1.0 - 1.0 / (pc_state.alpha_hat * pc_state.eigvals_L_hat + 1.0)) log_det_alpha_L_hat = np.sum( np.log(1.0 + (pc_state.alpha_hat * pc_state.eigvals_L_hat))) acc_thresh = (deff_alpha_L_hat + logdet_I_L_sigma - log_det_alpha_L_hat - (t / pc_state.r)).item() if acc_thresh >= 0.0: raise ValueError( 'Accepting with probability larger than 1, this should never happen. ' 's: {}'.format(np.exp(acc_thresh))) accept = np.log(rng.rand()) <= acc_thresh prog_bar.set_postfix(acc_thresh=np.exp(acc_thresh), rej_count=rej_iter) prog_bar.update() if accept: break else: raise ValueError( 'The alpha-dpp sampler reached the maximum number of rejections allowed ' 'for the intermediate sample selection ({}), try to increase the q factor ' '(see q_func parameter) or the Nystrom approximation accuracy ' '(see rls_oversample_* parameters).'.format(max_iter)) # Phase 4: use L_tilda to perform exact DPP sampling # compute alpha_star * L_tilda = alpha_star * A*L_sigma*A # with A_ii = ( 1 / (r * l_i) )^1/2 A = np.sqrt(sigma_uniq_count / (pc_state.r * rls_bound[sigma_uniq])).reshape(-1, 1) L_tilda = pc_state.alpha_hat * A.T * eval_L(X_sigma_uniq, X_sigma_uniq) * A E, U = np.linalg.eigh(L_tilda) # this has to be here rather than at the top to avoid circular dependencies # TODO: maybe refactor to avoid this from dppy.finite_dpps import FiniteDPP DPP = FiniteDPP(kernel_type='likelihood', L_eig_dec=(E, U)) S_tilda = np.array(DPP.sample_exact(random_state=rng), dtype=int) S = sigma_uniq[S_tilda].ravel().tolist() intermediate_sample_info = intermediate_sample_info._replace( rls_upper_bound=rls_bound) intermediate_sample_info = intermediate_sample_info._replace( rls_upper_bound_valid=rls_bound_valid) return S, rej_iter, intermediate_sample_info
def run_dpp_option2(current_player, meta_game, meta_probabilities, dpp_iters=10000, uniform=False): rng = RandomState(0) meta_game = meta_game[current_player] if current_player == 0: nb_policies = meta_game.shape[1] probabilities_enemy = meta_probabilities[1] elif current_player == 1: nb_policies = meta_game.shape[0] meta_game = meta_game.T probabilities_enemy = meta_probabilities[0] else: raise NotImplementedError L = np.zeros((nb_policies, nb_policies)) for n in range(nb_policies): for m in range(n, nb_policies): L[n, m] = np.dot(meta_game[:, n], meta_game[:, m]) / (np.linalg.norm( meta_game[:, n]) * np.linalg.norm(meta_game[:, m])) if n != m: L[m, n] = L[n, m] DPP = FiniteDPP(kernel_type='likelihood', projection=False, **{'L': L}) K = np.eye(L.shape[0]) - np.linalg.inv(L + np.eye(L.shape[0])) E_cardinality = np.trace(K) # Sample and probabilities sample_size = 0 iters = 0 while sample_size < E_cardinality: sample = np.array(DPP.sample_exact(mode='GS', random_state=rng)) sample_size = len(sample) iters += 1 if iters > dpp_iters: sample = np.arange(len(probabilities_enemy)) print( " ####################### TOO MANY!! #######################################" ) break if not uniform: if len(sample) == len(probabilities_enemy): return probabilities_enemy probabilities_enemy_rectified = np.zeros_like(probabilities_enemy) probabilities_enemy_rectified[sample] = probabilities_enemy[sample] return probabilities_enemy_rectified else: if len(sample) == len(probabilities_enemy): return (1. / len(sample)) * np.ones_like(probabilities_enemy) probabilities_enemy_rectified = np.zeros_like(probabilities_enemy) probabilities_enemy_rectified[sample] = ( 1. / len(sample)) * np.ones_like(probabilities_enemy)[sample] return probabilities_enemy_rectified
def update_set(x_pool, x_train, y_pool, y_train, step, method='basic_bern', model=None, nn_runs=100): images = torch.FloatTensor(x_pool) inferencer = Inferencer(model) if method == 'random': idxs = range(step) elif method == 'AL_dpp': mask = build_mask('basic_bern') estimator = build_estimator('bald_masked', inferencer, dropout_mask=mask, num_classes=10, keep_runs=True, nn_runs=nn_runs) estimator.estimate(images) # to generate mcd mcd = estimator.last_mcd_runs().reshape(-1, nn_runs * 10) dpp = FiniteDPP('likelihood', **{'L': np.corrcoef(mcd)}) idxs = set() while len(idxs) < step: dpp.sample_exact() idxs.update(dpp.list_of_samples[-1]) idxs = list(idxs)[:step] elif method == 'error_oracle': predictions = F.softmax(inferencer(images), dim=1).detach().cpu().numpy() errors = -np.log(predictions[np.arange(len(predictions)), y_pool]) idxs = np.argsort(errors)[::-1][:step] elif method == 'stoch_oracle': predictions = F.softmax(inferencer(images), dim=1).detach().cpu().numpy() errors = -np.log(predictions[np.arange(len(predictions)), y_pool]) idxs = np.random.choice(len(predictions), step, replace=False, p=errors / sum(errors)) elif method == 'max_entropy': predictions = F.softmax(inferencer(images), dim=1).detach().cpu().numpy() entropies = entropy(predictions) idxs = np.argsort(entropies)[::-1][:10] print(idxs) else: mask = build_mask(method) estimator = build_estimator('bald_masked', inferencer, dropout_mask=mask, num_classes=10, nn_runs=nn_runs) estimations = estimator.estimate(images) idxs = np.argsort(estimations)[::-1][:step] estimator.reset() x_add, y_add = np.copy(x_pool[idxs]), np.copy(y_pool[idxs]) x_train = np.concatenate((x_train, x_add)) y_train = np.concatenate((y_train, y_add)) x_pool = np.delete(x_pool, idxs, axis=0) y_pool = np.delete(y_pool, idxs, axis=0) return x_pool, x_train, y_pool, y_train
def update_set(x_pool, x_train, y_pool, y_train, step, method='mc_dropout', model=None, nn_runs=100, task='classification', samples=None): if samples is None: device = 'cuda' if torch.cuda.is_available() else 'cpu' samples = torch.DoubleTensor(x_pool).to(device) if method == 'random': idxs = range(step) elif method == 'AL_dpp': mask = build_mask('mc_dropout') estimator = build_estimator('bald_masked', model, dropout_mask=mask, num_classes=10, keep_runs=True, nn_runs=nn_runs) estimator.estimate(samples) # to generate mcd mcd = estimator.last_mcd_runs().reshape(-1, nn_runs * 10) dpp = FiniteDPP('likelihood', **{'L': np.corrcoef(mcd)}) idxs = set() while len(idxs) < step: dpp.sample_exact() idxs.update(dpp.list_of_samples[-1]) idxs = list(idxs)[:step] elif method == 'error_oracle': predictions = F.softmax(model(samples), dim=1).detach().cpu().numpy() errors = -np.log(predictions[np.arange(len(predictions)), y_pool]) idxs = np.argsort(errors)[::-1][:step] elif method == 'stoch_oracle': predictions = F.softmax(model(samples), dim=1).detach().cpu().numpy() errors = -np.log(predictions[np.arange(len(predictions)), y_pool]) idxs = np.random.choice(len(predictions), step, replace=False, p=errors / sum(errors)) elif method == 'max_entropy': predictions = F.softmax(model(samples), dim=1).detach().cpu().numpy() entropies = entropy(predictions) idxs = np.argsort(entropies)[::-1][:step] else: if task == 'classification': estimator = build_estimator('bald_masked', model, dropout_mask=method, num_classes=10, nn_runs=nn_runs) else: estimator = build_estimator('mcdue_masked', model, dropout_mask=method, nn_runs=nn_runs) estimations = estimator.estimate(samples) idxs = np.argsort(estimations)[::-1][:step] estimator.reset() x_add, y_add = np.copy(x_pool[idxs]), np.copy(y_pool[idxs]) x_train = np.concatenate((x_train, x_add)) y_train = np.concatenate((y_train, y_add)) x_pool = np.delete(x_pool, idxs, axis=0) y_pool = np.delete(y_pool, idxs, axis=0) return x_pool, x_train, y_pool, y_train