Spaces:
Paused
Paused
| from __future__ import annotations | |
| from math import ceil | |
| import numpy as np | |
| from .m0_affine import pad_last_dim | |
| def _quantize_lut_flat_values( | |
| flat_values: np.ndarray, | |
| *, | |
| levels: int, | |
| refine_steps: int, | |
| preconditioner: str, | |
| precondition_strength: float, | |
| ) -> tuple[np.ndarray, np.ndarray]: | |
| fit_values = flat_values.astype(np.float32, copy=False) | |
| restore_mean = np.float32(0.0) | |
| restore_scale = np.float32(1.0) | |
| if preconditioner == "tanh": | |
| restore_mean = np.float32(np.mean(flat_values, dtype=np.float64)) | |
| centered = flat_values - restore_mean | |
| restore_scale = np.float32(np.std(centered, dtype=np.float64)) | |
| if restore_scale < np.float32(1e-6): | |
| restore_scale = np.float32(1.0) | |
| fit_values = np.tanh(centered / (restore_scale * np.float32(precondition_strength))).astype(np.float32, copy=False) | |
| elif preconditioner != "none": | |
| raise ValueError("unsupported preconditioner") | |
| lut = np.quantile(fit_values, np.linspace(0.0, 1.0, num=levels, dtype=np.float32)).astype(np.float32) | |
| if levels > 1: | |
| for _ in range(refine_steps): | |
| boundaries = (lut[:-1] + lut[1:]) * np.float32(0.5) | |
| codes = np.searchsorted(boundaries, fit_values, side="left").astype(np.int32) | |
| counts = np.bincount(codes, minlength=levels) | |
| sums = np.bincount(codes, weights=fit_values.astype(np.float64, copy=False), minlength=levels) | |
| updated = lut.copy() | |
| valid = counts > 0 | |
| updated[valid] = (sums[valid] / counts[valid]).astype(np.float32, copy=False) | |
| if np.allclose(updated, lut, atol=1e-6, rtol=0.0): | |
| lut = updated | |
| break | |
| lut = updated | |
| boundaries = (lut[:-1] + lut[1:]) * np.float32(0.5) | |
| codes = np.searchsorted(boundaries, fit_values, side="left").astype(np.uint8, copy=False) | |
| else: | |
| codes = np.zeros_like(fit_values, dtype=np.uint8) | |
| if preconditioner == "tanh": | |
| lut = np.clip(lut, -0.999, 0.999) | |
| lut = ( | |
| np.arctanh(lut).astype(np.float32) * np.float32(restore_scale * precondition_strength) | |
| + np.float32(restore_mean) | |
| ) | |
| return codes, lut | |
| def _quantize_lut_segment_matrix( | |
| segment_values: np.ndarray, | |
| *, | |
| levels: int, | |
| refine_steps: int, | |
| preconditioner: str, | |
| precondition_strength: float, | |
| ) -> tuple[np.ndarray, np.ndarray]: | |
| group_count = int(segment_values.shape[0]) | |
| token_count = int(segment_values.shape[1]) | |
| group_size = int(segment_values.shape[2]) | |
| codes = np.zeros((group_count, token_count * group_size), dtype=np.uint8) | |
| lut = np.zeros((group_count, levels), dtype=np.float32) | |
| flat_values = segment_values.reshape(group_count, token_count * group_size) | |
| for group_index in range(group_count): | |
| group_codes, group_lut = _quantize_lut_flat_values( | |
| flat_values[group_index], | |
| levels=levels, | |
| refine_steps=refine_steps, | |
| preconditioner=preconditioner, | |
| precondition_strength=precondition_strength, | |
| ) | |
| codes[group_index] = group_codes | |
| lut[group_index] = group_lut | |
| return codes.reshape(segment_values.shape), lut | |
| def quantize_tensor_lut( | |
| values: np.ndarray, | |
| *, | |
| group_size: int, | |
| bits: int, | |
| segment_count: int = 1, | |
| refine_steps: int = 6, | |
| preconditioner: str = "none", | |
| precondition_strength: float = 2.0, | |
| ) -> tuple[np.ndarray, np.ndarray, int]: | |
| array = np.asarray(values, dtype=np.float32) | |
| if array.ndim != 2: | |
| raise ValueError("values must have shape [token_count, head_dim]") | |
| token_count, head_dim = array.shape | |
| segment_count = max(1, min(int(segment_count), token_count)) | |
| num_groups = ceil(head_dim / group_size) | |
| padded_head_dim = num_groups * group_size | |
| padded = pad_last_dim(array, padded_head_dim) | |
| grouped = padded.reshape(token_count, num_groups, group_size) | |
| levels = 1 << bits | |
| codebooks = np.zeros((num_groups, segment_count, levels), dtype=np.float32) | |
| codes = np.zeros((token_count, num_groups, group_size), dtype=np.uint8) | |
| segment_slices = np.array_split(np.arange(token_count, dtype=np.int32), segment_count) | |
| grouped_by_group = np.transpose(grouped, (1, 0, 2)) | |
| for segment_index, token_indices in enumerate(segment_slices): | |
| segment_values = grouped_by_group[:, token_indices, :] | |
| segment_codes, segment_lut = _quantize_lut_segment_matrix( | |
| segment_values, | |
| levels=levels, | |
| refine_steps=refine_steps, | |
| preconditioner=preconditioner, | |
| precondition_strength=precondition_strength, | |
| ) | |
| codes[token_indices] = np.transpose(np.clip(segment_codes, 0, levels - 1), (1, 0, 2)) | |
| codebooks[:, segment_index] = segment_lut | |
| return codes, codebooks, padded_head_dim | |
| def dequantize_group_lut(codes: np.ndarray, *, codebook: np.ndarray) -> np.ndarray: | |
| code_array = np.asarray(codes, dtype=np.int64) | |
| lut = np.asarray(codebook, dtype=np.float32) | |
| if lut.ndim == 1: | |
| return lut[code_array] | |
| if lut.ndim == 2 and code_array.ndim == 2: | |
| token_count = code_array.shape[0] | |
| segment_count = lut.shape[0] | |
| if segment_count == 1: | |
| return lut[0][code_array] | |
| segment_ids = (np.arange(token_count, dtype=np.int64) * segment_count) // max(token_count, 1) | |
| return lut[segment_ids[:, None], code_array] | |
| if lut.ndim == 2 and code_array.ndim == 1 and lut.shape[0] == code_array.shape[0]: | |
| return lut[np.arange(lut.shape[0]), code_array] | |
| raise ValueError("unsupported codebook shape for LUT decode") | |