Download model/domain_assignment/assigners.py from OneScience-Group/Chainsaw: direct link, hf CLI and curl.
- Browser
- Download file 2.6 kB
-
https://huggingface.co/OneScience-Group/Chainsaw/resolve/main/model/domain_assignment/assigners.py
- Command line
-
hf download hf://OneScience-Group/Chainsaw/model/domain_assignment/assigners.py
-
curl -L -o assigners.py https://huggingface.co/OneScience-Group/Chainsaw/resolve/main/model/domain_assignment/assigners.py
2.6 kB
| import numpy as np | |
| import torch | |
| from model.domain_assignment.sparse_lowrank import greedy_V | |
| class BaseAssigner: | |
| def __call__(self, y_pred, uncertainty=False): | |
| assert y_pred.ndim == 2 | |
| if torch.is_tensor(y_pred): | |
| y_pred = y_pred.detach().cpu().numpy() | |
| return self.assign_domains(y_pred) | |
| class SparseLowRank(BaseAssigner): | |
| """Use Brooks' method to generate a matrix of cluster assignments, | |
| and post-process to remove any excessively small clusters. | |
| """ | |
| def __init__(self, N_iters=3, K_init=4, linker_threshold=5, cost_type="mse"): | |
| self.N_iters = N_iters | |
| self.K_init = K_init | |
| self.linker_threshold = linker_threshold | |
| self.cost_type = cost_type | |
| def get_entropy(self, y_pred): | |
| """calculate the entropy of the upper triangle of the matrix | |
| used for uncertainty calculation but does not correlate with NDO as well | |
| as likelihood of assignment under y_pred | |
| """ | |
| return np.triu(-1 * y_pred * np.log(y_pred) - (1 - y_pred) * np.log(1 - y_pred), 1).sum() | |
| def assign_domains(self, y_pred): | |
| # N x K, columns are then indicator vectors | |
| epsilon = 1e-6 | |
| y_pred = np.clip(y_pred, epsilon, 1-epsilon) | |
| V, loss = greedy_V(y_pred, N_iters=self.N_iters, K_init=self.K_init, cost_type=self.cost_type) | |
| K = V.shape[-1] | |
| A = V@V.T | |
| average_likelihood = np.exp((A * np.log(y_pred) + (1-(A))*np.log(1-y_pred)).mean()) | |
| # throw away small clusters | |
| V = np.where( | |
| V.sum(0, keepdims=True) < self.linker_threshold, # 1, K | |
| np.zeros_like(V), | |
| V, | |
| ) | |
| assignments = { | |
| "linker": np.argwhere((V == 0).sum(-1) == K).reshape(-1) | |
| } | |
| domain_ix = 1 | |
| for col_ix in range(K): | |
| cluster_inds = np.argwhere(V[:, col_ix] == 1).reshape(-1) | |
| if cluster_inds.size > 0: | |
| assignments[f"domain_{domain_ix}"] = cluster_inds | |
| domain_ix += 1 | |
| return assignments, round(average_likelihood, 4) | |
| class SpectralClustering(BaseAssigner): | |
| """Challenge is how to determine n_clusters. | |
| We can look at eigengaps | |
| Or use MSE, running clustering multiple times. | |
| Or use Brooks' method and then refine with SC. | |
| """ | |
| def __init__(self, n_cluster_method="mse", max_domains=10): | |
| self.n_cluster_method = n_cluster_method | |
| self.max_domains = max_domains # TODO - make this flexible or length dependent. | |
| def assign_domains(self, y_pred): | |
| raise NotImplementedError() | |