Buckets:
| import heapq | |
| import warnings | |
| from functools import lru_cache | |
| from typing import Dict, List, Set, Tuple, Any | |
| from dataclasses import dataclass, field | |
| from constants import ( | |
| TIER_ORDER, TIER_BPW, GGUF_OVERHEAD_FACTOR, CLASS_MAX_TIER, | |
| CAN_Q3, ALLOW_LOWER_FLOOR, MTP_DEPLOY_TIER, get_tensor_class, get_tensor_type, | |
| is_mtp_tensor, | |
| ) | |
| # Выносим делитель в константу (8 бит * 1024 байт * 1024 кбайт) | |
| BITS_IN_MIB = 8 * 1024 * 1024.0 | |
| # Предвычисляем множители размеров для каждого тира (ускорение математики) | |
| TIER_SIZE_MULTIPLIER = { | |
| tier: (bpw / BITS_IN_MIB) * GGUF_OVERHEAD_FACTOR | |
| for tier, bpw in TIER_BPW.items() | |
| } | |
| # K-quants используют блоки по 256 элементов и требуют выравнивания (padding) 3D-тензоров MoE | |
| K_QUANTS = {"Q3_K", "Q4_K", "Q5_K", "Q6_K"} | |
| MOE_PAD_TYPES = {"ffn_gate_exps", "ffn_up_exps", "ffn_down_exps", "ffn_down"} | |
| MSE_BPW = { | |
| "IQ1_S": 1.5625, "IQ2_XXS": 2.0625, "IQ2_XS": 2.3125, | |
| "IQ2_S": 2.5, | |
| "IQ3_XXS": 3.0625, | |
| "Q3_K": 3.4375, "IQ3_S": 3.44, | |
| "IQ4_XS": 4.25, "IQ4_NL": 4.25, "Q4_K": 4.50, | |
| "Q5_K": 5.50, "Q6_K": 6.5625, "Q8_0": 8.50, "F16": 16.0, | |
| } | |
| class UpgradeItem: | |
| """Элемент очереди апгрейдов. Сравнивается только по neg_utility.""" | |
| neg_utility: float | |
| group_id: int = field(compare=False) | |
| next_tier: str = field(compare=False) | |
| cost_delta: float = field(compare=False) | |
| def _tier_index(tier: str) -> int: | |
| if tier not in TIER_ORDER: | |
| raise ValueError(f"Unknown tier: {tier}") | |
| return TIER_ORDER.index(tier) | |
| def _tier_at(idx: int) -> str: | |
| if not (0 <= idx < len(TIER_ORDER)): | |
| raise IndexError(f"Tier index {idx} out of range") | |
| return TIER_ORDER[idx] | |
| def _size_mib(tier: str, n_elements: int) -> float: | |
| """Размер тензора в MiB с учётом оверхеда GGUF.""" | |
| if n_elements <= 0: | |
| return 0.0 | |
| return n_elements * TIER_SIZE_MULTIPLIER.get(tier, 0.0) | |
| def _mse_delta(cur_tier: str, next_tier: str) -> float: | |
| return (2 ** (-2 * MSE_BPW[cur_tier])) - (2 ** (-2 * MSE_BPW[next_tier])) | |
| def _push_upgrade(group_id: int, | |
| group_registry: Dict[int, Tuple[List[str], int, int]], | |
| assignments: Dict[str, str], | |
| tensor_importance: Dict[str, float], | |
| upgrade_queue: List[UpgradeItem], | |
| importance_table: Dict[str, Any]): | |
| # Храним 3 элемента: имена, реальный размер, размер с padding | |
| g_names, g_elements, g_elements_padded = group_registry[group_id] | |
| rep_name = g_names[0] | |
| cur_tier = assignments[rep_name] | |
| cur_idx = _tier_index(cur_tier) | |
| rep_info = importance_table.get(rep_name, {}) | |
| ttype = rep_info["type"] if "type" in rep_info else get_tensor_type(rep_name) | |
| cls = get_tensor_class(ttype) | |
| max_tier = CLASS_MAX_TIER.get(cls, "Q8_0") | |
| if cur_idx >= _tier_index(max_tier) or cur_idx >= len(TIER_ORDER) - 1: | |
| return | |
| next_tier = _tier_at(cur_idx + 1) | |
| # Выбираем размер в зависимости от того, относится ли тир к K-quants | |
| cur_size_g = g_elements_padded if cur_tier in K_QUANTS else g_elements | |
| next_size_g = g_elements_padded if next_tier in K_QUANTS else g_elements | |
| cost_delta = _size_mib(next_tier, next_size_g) - _size_mib(cur_tier, cur_size_g) | |
| quality_delta = _mse_delta(cur_tier, next_tier) | |
| if quality_delta <= 0: | |
| return | |
| if cost_delta == 0: | |
| utility_per_mb = float('inf') | |
| elif cost_delta < 0: | |
| return | |
| else: | |
| total_g_imp = sum(tensor_importance.get(n, 0) for n in g_names) | |
| utility_per_mb = (total_g_imp * quality_delta) / cost_delta | |
| heapq.heappush(upgrade_queue, UpgradeItem(-utility_per_mb, group_id, next_tier, cost_delta)) | |
| def compute_initial_assignments(non_mtp_names: Set[str], mtp_names: Set[str], | |
| importance_table: Dict, allow_q3: bool, is_qat: bool = False) -> Dict[str, str]: | |
| assignments = {name: MTP_DEPLOY_TIER for name in mtp_names} | |
| for name in non_mtp_names: | |
| rep_info = importance_table.get(name, {}) | |
| has_imatrix = "importance_mean" in rep_info | |
| ttype = rep_info["type"] if "type" in rep_info else get_tensor_type(name) | |
| cls = get_tensor_class(ttype) | |
| if cls in ("norms", "ssm_params"): | |
| assignments[name] = "F16" | |
| elif cls == "embd": | |
| assignments[name] = "Q4_K" if is_qat else "Q5_K" | |
| else: | |
| base_floor = ("Q4_K" if cls == "attn_proj" else "IQ4_XS") if is_qat else "Q4_K" | |
| if allow_q3 and cls in CAN_Q3 and has_imatrix: | |
| assignments[name] = ALLOW_LOWER_FLOOR | |
| else: | |
| assignments[name] = base_floor | |
| return assignments | |
| def build_groups(tied_groups: List[List[str]], non_mtp_names: Set[str], | |
| ne_map: Dict[str, int], padded_ne_map: Dict[str, int]) -> Dict[int, Tuple[List[str], int, int]]: | |
| group_registry = {} | |
| assigned_tensors = set() | |
| for group_idx, group in enumerate(tied_groups): | |
| clean_group = [n for n in group if n in non_mtp_names] | |
| if clean_group: | |
| g_elements = sum(ne_map.get(n, 0) for n in clean_group) | |
| g_elements_padded = sum(padded_ne_map.get(n, 0) for n in clean_group) | |
| group_registry[group_idx] = (clean_group, g_elements, g_elements_padded) | |
| assigned_tensors.update(clean_group) | |
| unassigned_tensors = non_mtp_names - assigned_tensors | |
| next_group_idx = len(group_registry) | |
| for name in unassigned_tensors: | |
| group_registry[next_group_idx] = ([name], ne_map.get(name, 0), padded_ne_map.get(name, 0)) | |
| next_group_idx += 1 | |
| return group_registry | |
| def optimal_classify(importance_table: dict, tied_groups: list, model: dict, | |
| target_size_mib: float, allow_q3: bool = False) -> Tuple[dict, dict]: | |
| if target_size_mib <= 0: | |
| raise ValueError("target_size_mib must be positive") | |
| features = model.get("features", {}) | |
| has_mtp = features.get("has_mtp", False) | |
| n_layers = features.get("n_layers", 31) | |
| is_qat = features.get("is_qat", False) | |
| model_tensors = model.get("tensors", {}) | |
| ne_map = {k: v["n_elements"] for k, v in model_tensors.items()} | |
| for tname, info in importance_table.items(): | |
| if tname not in ne_map: | |
| ne_map[tname] = info["n_elements"] | |
| # --- Вычисление MoE Padding (Целочисленное выравнивание) --- | |
| moe_d_ff = features.get("moe_intermediate_size", 0) | |
| padded_ne_map = dict(ne_map) | |
| if moe_d_ff > 0 and moe_d_ff % 256 != 0: | |
| aligned_d_ff = ((moe_d_ff + 255) // 256) * 256 | |
| for name, n_el in ne_map.items(): | |
| ttype = importance_table.get(name, {}).get("type", get_tensor_type(name)) | |
| if ttype in MOE_PAD_TYPES: | |
| padded_ne_map[name] = (n_el // moe_d_ff) * aligned_d_ff | |
| # ----------------------------------------------------------- | |
| all_names = set(ne_map.keys()) | |
| mtp_names = {n for n in all_names if is_mtp_tensor(n, n_layers)} if has_mtp else set() | |
| non_mtp_names = all_names - mtp_names | |
| tensor_importance = {} | |
| for name in non_mtp_names: | |
| raw_imp = importance_table.get(name, {}).get("importance_mean", 0.0) | |
| tensor_importance[name] = raw_imp | |
| assignments = compute_initial_assignments(non_mtp_names, mtp_names, importance_table, allow_q3, is_qat) | |
| group_registry = build_groups(tied_groups, non_mtp_names, ne_map, padded_ne_map) | |
| mtp_cost = sum(_size_mib(MTP_DEPLOY_TIER, ne_map.get(n, 0)) for n in mtp_names) | |
| effective_target = target_size_mib - mtp_cost | |
| current_size = sum( | |
| _size_mib(assignments[n], padded_ne_map.get(n, ne_map.get(n, 0)) if assignments[n] in K_QUANTS else ne_map.get(n, 0)) | |
| for n in non_mtp_names | |
| ) | |
| if current_size > effective_target: | |
| warnings.warn(f"Initial size {current_size:.1f} MiB already exceeds target {effective_target:.1f} MiB", RuntimeWarning) | |
| upgrade_queue = [] | |
| for g_id in group_registry: | |
| _push_upgrade(g_id, group_registry, assignments, tensor_importance, upgrade_queue, importance_table) | |
| while upgrade_queue: | |
| item = heapq.heappop(upgrade_queue) | |
| g_id, next_tier, cost_delta = item.group_id, item.next_tier, item.cost_delta | |
| if cost_delta > 0 and current_size + cost_delta > effective_target: | |
| continue | |
| for n in group_registry[g_id][0]: | |
| assignments[n] = next_tier | |
| current_size += cost_delta | |
| _push_upgrade(g_id, group_registry, assignments, tensor_importance, upgrade_queue, importance_table) | |
| return assignments, padded_ne_map | |
| def compute_stats(assignments: dict, ne_map: dict = None, padded_ne_map: dict = None) -> dict: | |
| """Собирает статистику по тирам с точным учётом K_QUANTS padding.""" | |
| stats = {"by_tier_count": {}, "by_tier_mib": {}, "total_mib": 0.0, "tensor_count": 0} | |
| for name, tier in assignments.items(): | |
| if not isinstance(tier, str): | |
| continue | |
| stats["tensor_count"] += 1 | |
| stats["by_tier_count"][tier] = stats["by_tier_count"].get(tier, 0) + 1 | |
| if ne_map: | |
| if padded_ne_map and tier in K_QUANTS: | |
| elements = padded_ne_map.get(name, ne_map.get(name, 0)) | |
| else: | |
| elements = ne_map.get(name, 0) | |
| size = _size_mib(tier, elements) | |
| stats["by_tier_mib"][tier] = stats["by_tier_mib"].get(tier, 0.0) + size | |
| stats["total_mib"] += size | |
| return stats | |
Xet Storage Details
- Size:
- 10 kB
- Xet hash:
- 932fdffe31bb27171b0d5f442a35282f0e5f25dbafb5a8036c9e07a4dddd495e
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.