| import numpy as np |
|
|
| from heapr.scoring import ( |
| InMemoryCovarianceStore, |
| accumulate_covariance_from_trace, |
| compute_atomic_scores_for_expert, |
| compute_down_covariance_quadratic, |
| score_atomic_outputs_np, |
| score_delta_vectors_np, |
| score_group_outputs_np, |
| ) |
|
|
|
|
| def test_score_delta_vectors_identity_covariance(): |
| delta = np.array([[1.0, 2.0], [3.0, 4.0]]) |
| cov = np.eye(2) |
|
|
| np.testing.assert_allclose(score_delta_vectors_np(delta, cov), [2.5, 12.5]) |
|
|
|
|
| def test_atomic_scores_average_over_tokens(): |
| outputs = np.array( |
| [ |
| [[1.0, 0.0], [0.0, 2.0]], |
| [[3.0, 0.0], [0.0, 4.0]], |
| ] |
| ) |
| cov = np.eye(2) |
|
|
| np.testing.assert_allclose(score_atomic_outputs_np(outputs, cov), [2.5, 5.0]) |
|
|
|
|
| def test_exact_group_score_includes_cross_terms(): |
| outputs = np.array([[[1.0, 0.0], [1.0, 0.0]]]) |
| cov = np.eye(2) |
| group_indices = np.array([[0, 1]]) |
|
|
| |
| |
| np.testing.assert_allclose(score_group_outputs_np(outputs, cov, group_indices), [2.0]) |
|
|
|
|
| def test_compute_atomic_scores_matches_expanded_delta_formula(): |
| import torch |
|
|
| hidden_states = torch.tensor( |
| [[0.2, -0.4, 0.8], [1.2, 0.5, -0.3], [-0.7, 0.1, 0.4]], |
| dtype=torch.float32, |
| ) |
| routing_weights = torch.tensor([0.9, 0.4, 0.7], dtype=torch.float32) |
| gate = torch.tensor([[0.5, -0.2, 0.1], [-0.3, 0.7, 0.2]], dtype=torch.float32) |
| up = torch.tensor([[0.1, 0.4, -0.6], [0.8, -0.5, 0.3]], dtype=torch.float32) |
| gate_up = torch.cat([gate, up], dim=0) |
| down = torch.tensor([[0.2, -0.1], [0.5, 0.7], [-0.4, 0.3]], dtype=torch.float32) |
| covariance = np.array( |
| [[1.2, 0.1, -0.2], [0.1, 0.8, 0.3], [-0.2, 0.3, 1.5]], |
| dtype=np.float32, |
| ) |
| moe_scale = 1.3 |
|
|
| actual = compute_atomic_scores_for_expert( |
| hidden_states, |
| routing_weights, |
| gate_up, |
| down, |
| covariance, |
| moe_scale=moe_scale, |
| atom_chunk=1, |
| ) |
|
|
| gate_values = torch.nn.functional.silu(hidden_states @ gate.T) |
| up_values = hidden_states @ up.T |
| atomic_values = gate_values * up_values |
| expected = [] |
| cov = torch.as_tensor(covariance) |
| for atom in range(down.shape[1]): |
| delta = ( |
| atomic_values[:, atom, None] |
| * down[:, atom][None, :] |
| * routing_weights[:, None] |
| * moe_scale |
| ) |
| expected.append(0.5 * torch.sum((delta @ cov) * delta, dim=-1).mean()) |
|
|
| torch.testing.assert_close(actual, torch.stack(expected)) |
|
|
|
|
| def test_device_covariance_accumulation_matches_cpu_path(): |
| import types |
|
|
| import torch |
|
|
| grad = torch.tensor( |
| [[[1.0, 2.0], [3.0, 4.0], [-1.0, 0.5]]], |
| dtype=torch.float32, |
| ) |
| selected = torch.tensor([[0, 1], [1, 1], [0, 0]]) |
| output = types.SimpleNamespace(grad=grad) |
| record = types.SimpleNamespace(layer_sparse_idx=0, output=output, selected_experts=selected) |
| trace = types.SimpleNamespace(routes=[record]) |
|
|
| cpu_store = InMemoryCovarianceStore(hidden_size=2) |
| device_store = InMemoryCovarianceStore(hidden_size=2) |
| accumulate_covariance_from_trace(trace, cpu_store, device_accumulation=False) |
| accumulate_covariance_from_trace(trace, device_store, device_accumulation=True) |
|
|
| assert cpu_store.counts == device_store.counts |
| np.testing.assert_allclose(cpu_store.normalized(0, 0), device_store.normalized(0, 0)) |
| np.testing.assert_allclose(cpu_store.normalized(0, 1), device_store.normalized(0, 1)) |
|
|
|
|
| def test_compute_down_covariance_quadratic_matches_manual_formula(): |
| import torch |
|
|
| down = torch.tensor([[0.2, -0.1], [0.5, 0.7], [-0.4, 0.3]], dtype=torch.float32) |
| covariance = np.array( |
| [[1.2, 0.1, -0.2], [0.1, 0.8, 0.3], [-0.2, 0.3, 1.5]], |
| dtype=np.float32, |
| ) |
|
|
| actual = compute_down_covariance_quadratic(down, covariance, atom_chunk=1) |
| cov = torch.as_tensor(covariance) |
| expected = torch.stack([down[:, atom] @ cov @ down[:, atom] for atom in range(down.shape[1])]) |
| torch.testing.assert_close(actual, expected) |
|
|
|
|