Module neuralops.compression_engine.come_compressor
CoMe: Compress LLMs through Layer Concatenation and Shedding with Learnable Inter-Layer Interpolation Adapters.
Registered in COMPRESSOR_REGISTRY as 'come' and 'come_compressor'.
Mathematical Formulation: 1. Layer Shedding & Uniform Strided Selection: I_keep = {i_0, i_1, …, i_{K-1}}, i_k = round(k * (L-1) / (K-1))
- Learnable Low-Rank Interpolation Bridge between Non-Consecutive Layers: W_bridge = I + B @ A (B: hidden x r, A: r x hidden) h_bridged = h + alpha * (W_bridge h - h) = h + alpha * (B @ A) h Initialized with B = 0 so bridge is identity at init.
Functions
def come_factory(model: Any, comp_config: Any = None, **kwargs: Any) ‑> Any-
Expand source code
@COMPRESSOR_REGISTRY.register("come_factory") @COMPRESSOR_REGISTRY.register("come_compressor_factory") def come_factory(model: Any, comp_config: Any = None, **kwargs: Any) -> Any: """Factory function for the CoMe compressor.""" return_tuple = kwargs.pop("return_stats", kwargs.pop("return_tuple", False)) rank = kwargs.pop( "rank", _cfg_get(comp_config, "rank", _cfg_get(comp_config, "come_rank", None)), ) if rank is not None: rank = int(rank) target_layers = kwargs.pop( "target_layers", _cfg_get( comp_config, "come_target_layers", _cfg_get(comp_config, "target_layers", None), ), ) if target_layers is not None: target_layers = int(target_layers) sparsity_kw = kwargs.pop("sparsity", None) sparsity_cfg = _cfg_get( comp_config, "come_sparsity", _cfg_get(comp_config, "sparsity", None), ) if sparsity_kw is not None: sparsity = float(sparsity_kw) elif sparsity_cfg is not None: sparsity = float(sparsity_cfg) elif rank is not None: sparsity = _rank_to_sparsity(rank) else: sparsity = 0.10 bridge_rank_kw = kwargs.pop("bridge_rank", None) bridge_rank_cfg = _cfg_get( comp_config, "come_bridge_rank", _cfg_get(comp_config, "bridge_rank", None), ) if bridge_rank_kw is not None: bridge_rank = int(bridge_rank_kw) elif bridge_rank_cfg is not None: bridge_rank = int(bridge_rank_cfg) else: # derive from rank if possible, else let __init__ decide bridge_rank = None alpha_init = float( kwargs.pop( "alpha_init", _cfg_get( comp_config, "come_alpha_init", _cfg_get(comp_config, "alpha_init", 0.1), ), ) ) lora_r = int( kwargs.pop( "lora_r", _cfg_get( comp_config, "come_lora_r", _cfg_get( comp_config, "lora_r", _cfg_get(comp_config, "lora_rank", 16), ), ), ) ) lora_alpha = float( kwargs.pop( "lora_alpha", _cfg_get( comp_config, "come_lora_alpha", _cfg_get(comp_config, "lora_alpha", 1.0), ), ) ) skip_attention_qkv = bool( kwargs.pop( "skip_attention_qkv", _cfg_get( comp_config, "come_skip_attention_qkv", _cfg_get(comp_config, "skip_attention_qkv", True), ), ) ) protect_critical = bool( kwargs.pop( "protect_critical", _cfg_get(comp_config, "protect_critical", True), ) ) target_attention_only = bool( kwargs.pop( "target_attention_only", _cfg_get( comp_config, "come_target_attention_only", _cfg_get(comp_config, "target_attention_only", False), ), ) ) tokenizer = getattr(model, "tokenizer", kwargs.pop("tokenizer", None)) recalibrate_ln = bool( kwargs.pop( "recalibrate_ln", _cfg_get( comp_config, "come_recalibrate_ln", _cfg_get(comp_config, "recalibrate_ln", True), ), ) ) allow_forward_failure = bool( kwargs.pop( "allow_forward_failure", _cfg_get(comp_config, "allow_forward_failure", False), ) ) compressor = CoMeCompressor( model, tokenizer=tokenizer, target_layers=target_layers, sparsity=sparsity, bridge_rank=bridge_rank, alpha_init=alpha_init, lora_r=lora_r, lora_alpha=lora_alpha, skip_attention_qkv=skip_attention_qkv, protect_critical=protect_critical, target_attention_only=target_attention_only, recalibrate_ln=recalibrate_ln, allow_forward_failure=allow_forward_failure, rank=rank, comp_config=comp_config, **kwargs, ) compressed_model, stats = compressor.compress() if return_tuple: return compressed_model, stats return compressed_modelFactory function for the CoMe compressor.
Classes
class CoMeBridge (hidden_size: int, bridge_rank: int = 64, alpha_init: float = 0.1)-
Expand source code
class CoMeBridge(nn.Module): """ Learnable low-rank interpolation adapter bridging representation gaps between non-consecutive layers. W_bridge = I + B @ A (B: hidden x r, A: r x hidden) y = x + alpha * (W_bridge x - x) = x + alpha * (B @ A) x At initialization B = 0, so the bridge is exactly the identity and only alpha influences the output; gradient flows to A and alpha from step 1. Robustly handles Tensor, tuple, list, dict, and BaseModelOutput returns. """ def __init__( self, hidden_size: int, bridge_rank: int = 64, alpha_init: float = 0.1, ) -> None: super().__init__() self.hidden_size = int(hidden_size) self.bridge_rank = int(max(1, min(bridge_rank, hidden_size))) # Low-rank factors (actual residual low-rank approximation) self.A = nn.Parameter(torch.empty(self.bridge_rank, self.hidden_size)) self.B = nn.Parameter(torch.zeros(self.hidden_size, self.bridge_rank)) # Optional bias on the low-rank correction (kept zero by default) self.correction_bias = nn.Parameter(torch.zeros(self.hidden_size)) # Learnable mixing coefficient (scalar per bridge) self.alpha = nn.Parameter(torch.tensor(float(alpha_init))) # Initialize A with kaiming to get good gradient flow nn.init.kaiming_uniform_(self.A, a=math.sqrt(5)) def _bridge_tensor(self, t: torch.Tensor) -> torch.Tensor: if t.ndim >= 2 and t.shape[-1] == self.hidden_size: A = self.A.to(device=t.device, dtype=t.dtype) B = self.B.to(device=t.device, dtype=t.dtype) cb = self.correction_bias.to(device=t.device, dtype=t.dtype) # residual = B @ (A @ t^T)^T + bias low = F.linear(F.linear(t, A), B) + cb return t + self.alpha.to(device=t.device, dtype=t.dtype) * low return t def forward(self, hidden_states: Any, *args: Any, **kwargs: Any) -> Any: # Tuple return if isinstance(hidden_states, tuple): if len(hidden_states) > 0 and isinstance(hidden_states[0], torch.Tensor): return (self._bridge_tensor(hidden_states[0]), *hidden_states[1:]) return hidden_states # List return if isinstance(hidden_states, list): if len(hidden_states) > 0 and isinstance(hidden_states[0], torch.Tensor): return [self._bridge_tensor(hidden_states[0])] + hidden_states[1:] return hidden_states # Dict return if isinstance(hidden_states, dict): out_dict = dict(hidden_states) for k in ("last_hidden_state", "hidden_states", "x"): if k in out_dict and isinstance(out_dict[k], torch.Tensor): out_dict[k] = self._bridge_tensor(out_dict[k]) return out_dict return hidden_states # BaseModelOutput or objects with .last_hidden_state / .hidden_states modified = False if hasattr(hidden_states, "last_hidden_state"): t = hidden_states.last_hidden_state if isinstance(t, torch.Tensor): hidden_states.last_hidden_state = self._bridge_tensor(t) modified = True if hasattr(hidden_states, "hidden_states"): hs = hidden_states.hidden_states if isinstance(hs, tuple) and len(hs) > 0 and isinstance(hs[-1], torch.Tensor): new_hs = list(hs) new_hs[-1] = self._bridge_tensor(new_hs[-1]) hidden_states.hidden_states = tuple(new_hs) modified = True if modified: return hidden_states # Raw tensor if isinstance(hidden_states, torch.Tensor): return self._bridge_tensor(hidden_states) return hidden_statesLearnable low-rank interpolation adapter bridging representation gaps between non-consecutive layers.
W_bridge = I + B @ A (B: hidden x r, A: r x hidden) y = x + alpha * (W_bridge x - x) = x + alpha * (B @ A) xAt initialization B = 0, so the bridge is exactly the identity and only alpha influences the output; gradient flows to A and alpha from step 1. Robustly handles Tensor, tuple, list, dict, and BaseModelOutput returns.
Initialize internal Module state, shared by both nn.Module and ScriptModule.
Ancestors
- torch.nn.modules.module.Module
Methods
def forward(self, hidden_states: Any, *args: Any, **kwargs: Any) ‑> Any-
Expand source code
def forward(self, hidden_states: Any, *args: Any, **kwargs: Any) -> Any: # Tuple return if isinstance(hidden_states, tuple): if len(hidden_states) > 0 and isinstance(hidden_states[0], torch.Tensor): return (self._bridge_tensor(hidden_states[0]), *hidden_states[1:]) return hidden_states # List return if isinstance(hidden_states, list): if len(hidden_states) > 0 and isinstance(hidden_states[0], torch.Tensor): return [self._bridge_tensor(hidden_states[0])] + hidden_states[1:] return hidden_states # Dict return if isinstance(hidden_states, dict): out_dict = dict(hidden_states) for k in ("last_hidden_state", "hidden_states", "x"): if k in out_dict and isinstance(out_dict[k], torch.Tensor): out_dict[k] = self._bridge_tensor(out_dict[k]) return out_dict return hidden_states # BaseModelOutput or objects with .last_hidden_state / .hidden_states modified = False if hasattr(hidden_states, "last_hidden_state"): t = hidden_states.last_hidden_state if isinstance(t, torch.Tensor): hidden_states.last_hidden_state = self._bridge_tensor(t) modified = True if hasattr(hidden_states, "hidden_states"): hs = hidden_states.hidden_states if isinstance(hs, tuple) and len(hs) > 0 and isinstance(hs[-1], torch.Tensor): new_hs = list(hs) new_hs[-1] = self._bridge_tensor(new_hs[-1]) hidden_states.hidden_states = tuple(new_hs) modified = True if modified: return hidden_states # Raw tensor if isinstance(hidden_states, torch.Tensor): return self._bridge_tensor(hidden_states) return hidden_statesDefine the computation performed at every call.
Should be overridden by all subclasses.
Note
Although the recipe for forward pass needs to be defined within this function, one should call the :class:
Moduleinstance afterwards instead of this since the former takes care of running the registered hooks while the latter silently ignores them.
class CoMeBridgedLayer (layer: nn.Module,
bridge: CoMeBridge | None = None)-
Expand source code
class CoMeBridgedLayer(nn.Module): """Wraps a retained transformer layer with a learnable CoMeBridge.""" def __init__(self, layer: nn.Module, bridge: CoMeBridge | None = None) -> None: super().__init__() self.layer = layer self.bridge = bridge def __getattr__(self, name: str) -> Any: try: return super().__getattr__(name) except AttributeError: if "layer" in self.__dict__ or ( "_modules" in self.__dict__ and "layer" in self._modules ): return getattr(self.layer, name) raise def __getitem__(self, key: Any) -> Any: return self.layer[key] def __contains__(self, key: Any) -> bool: return key in self.layer def forward(self, hidden_states: Any = None, *args: Any, **kwargs: Any) -> Any: if hidden_states is None and "hidden_states" in kwargs: hidden_states = kwargs.pop("hidden_states") if hidden_states is not None: args = (hidden_states,) + args attn_mask = kwargs.pop("attention_mask", None) if attn_mask is not None: if getattr(attn_mask, "dtype", None) == torch.int64: attn_mask = attn_mask.to(torch.bool) kwargs["attention_mask"] = attn_mask out = self.layer(*args, **kwargs) if self.bridge is not None: out = self.bridge(out) return outWraps a retained transformer layer with a learnable CoMeBridge.
Initialize internal Module state, shared by both nn.Module and ScriptModule.
Ancestors
- torch.nn.modules.module.Module
Methods
def forward(self, hidden_states: Any = None, *args: Any, **kwargs: Any) ‑> Any-
Expand source code
def forward(self, hidden_states: Any = None, *args: Any, **kwargs: Any) -> Any: if hidden_states is None and "hidden_states" in kwargs: hidden_states = kwargs.pop("hidden_states") if hidden_states is not None: args = (hidden_states,) + args attn_mask = kwargs.pop("attention_mask", None) if attn_mask is not None: if getattr(attn_mask, "dtype", None) == torch.int64: attn_mask = attn_mask.to(torch.bool) kwargs["attention_mask"] = attn_mask out = self.layer(*args, **kwargs) if self.bridge is not None: out = self.bridge(out) return outDefine the computation performed at every call.
Should be overridden by all subclasses.
Note
Although the recipe for forward pass needs to be defined within this function, one should call the :class:
Moduleinstance afterwards instead of this since the former takes care of running the registered hooks while the latter silently ignores them.
class CoMeCompressor (model: nn.Module,
tokenizer: Any | None = None,
target_layers: int | None = None,
sparsity: float = 0.1,
bridge_rank: int | None = None,
alpha_init: float = 0.1,
lora_r: int = 16,
lora_alpha: float = 1.0,
skip_attention_qkv: bool = True,
protect_critical: bool = True,
target_attention_only: bool = False,
recalibrate_ln: bool = True,
allow_forward_failure: bool = False,
device: str | torch.device | None = None,
target_modules: list[str] | None = None,
rank: int | None = None,
**kwargs: Any)-
Expand source code
@COMPRESSOR_REGISTRY.register("come") @COMPRESSOR_REGISTRY.register("come_compressor") class CoMeCompressor(BaseCompressor): """ CoMe Compressor: Layer shedding with learnable low-rank interpolation adapters (bridges) between non-consecutive retained layers. Config parameters (via kwargs or comp_config): rank : int, optional — SVD-style rank. If provided and bridge_rank/sparsity are not explicitly set, they are derived from rank via safe mappings. target_layers : int, optional — target layer count after shedding. sparsity : float, default 0.10 — fraction of layers to remove. bridge_rank : int, optional — bottleneck rank for the low-rank interpolation bridge (B @ A). If not set, derived from rank (rank // 4) or defaults to 64 for the full hidden size. alpha_init : float, default 0.1 — initial bridge mixing coeff. lora_r : int, default 16 — post-shedding LoRA rank. lora_alpha : float, default 1.0 — LoRA scaling. target_attention_only : bool, default False. skip_attention_qkv : bool, default True — protect asymmetric GQA. recalibrate_ln : bool, default True. allow_forward_failure : bool, default False. """ is_custom_attention: bool = True def __init__( self, model: nn.Module, tokenizer: Any | None = None, target_layers: int | None = None, sparsity: float = 0.10, bridge_rank: int | None = None, alpha_init: float = 0.1, lora_r: int = 16, lora_alpha: float = 1.0, skip_attention_qkv: bool = True, protect_critical: bool = True, target_attention_only: bool = False, recalibrate_ln: bool = True, allow_forward_failure: bool = False, device: str | torch.device | None = None, target_modules: list[str] | None = None, rank: int | None = None, **kwargs: Any, ) -> None: super().__init__(model, name="come", **kwargs) conf = kwargs.get("comp_config", kwargs.get("cfg")) # -------- Read config with precedence: explicit kwarg > comp_config > default -------- rank = _cfg_get(conf, "rank", _cfg_get(conf, "come_rank", rank)) if rank is not None: rank = int(rank) target_layers = _cfg_get( conf, "come_target_layers", _cfg_get(conf, "target_layers", target_layers) ) if target_layers is not None: target_layers = int(target_layers) # sparsity: if rank provided and sparsity not explicitly overridden, derive sparsity_explicit = _cfg_get( conf, "come_sparsity", _cfg_get(conf, "sparsity", kwargs.get("sparsity")), ) if sparsity_explicit is None and rank is not None: sparsity = _rank_to_sparsity(rank) elif sparsity_explicit is not None: sparsity = float(sparsity_explicit) # else: keep the constructor default (0.10) # bridge_rank: if rank provided and bridge_rank not explicitly overridden, derive bridge_rank_explicit = _cfg_get( conf, "come_bridge_rank", _cfg_get(conf, "bridge_rank", bridge_rank), ) hidden_size_probe = None for attr in ("hidden_size", "d_model", "dim"): if hasattr(model, "config") and hasattr(model.config, attr): hidden_size_probe = int(getattr(model.config, attr)) break if bridge_rank_explicit is None and rank is not None and hidden_size_probe: bridge_rank = _rank_to_bridge_rank(rank, hidden_size_probe) elif bridge_rank_explicit is not None: bridge_rank = int(bridge_rank_explicit) else: # default: full hidden size (no bottleneck) — safest default bridge_rank = hidden_size_probe or 64 alpha_init = float( _cfg_get(conf, "come_alpha_init", _cfg_get(conf, "alpha_init", alpha_init)) ) lora_r = int( _cfg_get( conf, "come_lora_r", _cfg_get(conf, "lora_r", _cfg_get(conf, "lora_rank", lora_r)), ) ) lora_alpha = float( _cfg_get(conf, "come_lora_alpha", _cfg_get(conf, "lora_alpha", lora_alpha)) ) skip_attention_qkv = bool( _cfg_get( conf, "come_skip_attention_qkv", _cfg_get(conf, "skip_attention_qkv", skip_attention_qkv), ) ) protect_critical = bool(_cfg_get(conf, "protect_critical", protect_critical)) target_attention_only = bool( _cfg_get( conf, "come_target_attention_only", _cfg_get(conf, "target_attention_only", target_attention_only), ) ) recalibrate_ln = bool( _cfg_get( conf, "come_recalibrate_ln", _cfg_get(conf, "recalibrate_ln", recalibrate_ln), ) ) allow_forward_failure = bool( _cfg_get( conf, "allow_forward_failure", _cfg_get(kwargs, "allow_forward_failure", allow_forward_failure), ) ) # -------- Store -------- self.tokenizer = tokenizer or kwargs.get("tokenizer", getattr(model, "tokenizer", None)) self.target_layers = target_layers self.sparsity = max(0.0, min(sparsity, 0.95)) self.bridge_rank = int(bridge_rank) self.alpha_init = alpha_init self.lora_r = lora_r self.lora_alpha = lora_alpha self.skip_attention_qkv = skip_attention_qkv self.protect_critical = protect_critical self.target_attention_only = target_attention_only self.recalibrate_ln = recalibrate_ln self.allow_forward_failure = allow_forward_failure self.target_modules = target_modules self.rank = rank self.target_device = ( torch.device(device) if device is not None else (next(model.parameters(), torch.tensor(0.0)).device) ) self.comp_config = conf self.compressed_layers: list[str] = [] self.fallback_layers: list[str] = [] self.skipped_layers: list[str] = [] self.stats: dict[str, Any] = {} # ------------------------------------------------------------------ # helpers # ------------------------------------------------------------------ def _is_gqa_asymmetric(self, name: str, module: nn.Module) -> bool: if not self.skip_attention_qkv or self.target_attention_only: return False cfg = getattr(self.model, "config", None) num_heads = getattr(cfg, "num_attention_heads", None) num_kv_heads = getattr(cfg, "num_key_value_heads", None) if num_heads is not None and num_kv_heads is not None and num_kv_heads < num_heads: name_lower = name.lower() if any( p in name_lower for p in [ "q_proj", "k_proj", "v_proj", "query", "key", "value", "c_attn", ] ): return True return False def _is_target_module(self, name: str, module: nn.Module) -> bool: if isinstance(module, (CoMeLoRALinear, CoMeBridge, CoMeBridgedLayer)): return False if ".bridge." in name or name.endswith(".bridge"): return False if any( name.endswith(sfx) for sfx in [".base_layer", ".lora_A", ".lora_B", ".lora_dropout", ".linear"] ): return False target_mod = getattr(module, "base_layer", getattr(module, "linear", module)) cls_name = module.__class__.__name__.lower() target_cls = target_mod.__class__.__name__.lower() is_linear_like = ( isinstance(module, nn.Linear) or isinstance(target_mod, nn.Linear) or ( Conv1D is not None and (isinstance(module, Conv1D) or isinstance(target_mod, Conv1D)) ) or "conv1d" in cls_name or "conv1d" in target_cls or hasattr(module, "nf") or hasattr(target_mod, "nf") ) if not is_linear_like: return False name_lower = name.lower() if any( skip in name_lower for skip in [ "classifier", "score", "lm_head", "pooler", "embed", "logits_processor", "head", "pre_classifier", ] ): return False if self._is_gqa_asymmetric(name, module): return False if self.target_attention_only: ffn_patterns = [ "ffn", "mlp", "lin1", "lin2", "intermediate", "gate_proj", "up_proj", "down_proj", "c_fc", ] if any(p in name_lower for p in ffn_patterns): return False if "output.dense" in name_lower and "attention" not in name_lower: return False attn_patterns = [ "attn", "attention", "q_proj", "k_proj", "v_proj", "o_proj", "out_lin", "q_lin", "k_lin", "v_lin", "c_attn", "c_proj", "query", "key", "value", "in_proj_qkv", "out_proj", ] if not any(p in name_lower for p in attn_patterns): return False else: if self.protect_critical and not should_compress_linear(self.model, name): return False if self.target_modules is not None: return any(t in name for t in self.target_modules) return True def _get_hidden_size(self, layer: nn.Module) -> int: if hasattr(self, "model") and hasattr(self.model, "config"): for attr in ("hidden_size", "d_model", "dim"): if hasattr(self.model.config, attr): return int(getattr(self.model.config, attr)) for attr in ("hidden_size", "d_model", "dim", "embed_dim"): if hasattr(layer, attr): return int(getattr(layer, attr)) if hasattr(layer, "config"): for attr in ("hidden_size", "d_model", "dim"): if hasattr(layer.config, attr): return int(getattr(layer.config, attr)) _OUTPUT_PROJ_KEYS = ("o_proj", "out_proj", "output", "dense") for name, m in layer.named_modules(): if isinstance(m, nn.Linear) and any(k in name for k in _OUTPUT_PROJ_KEYS): return m.out_features sizes = [m.in_features for _, m in layer.named_modules() if isinstance(m, nn.Linear)] if sizes: from collections import Counter return Counter(sizes).most_common(1)[0][0] for m in layer.modules(): if isinstance(m, nn.LayerNorm): ns = m.normalized_shape return ns[0] if isinstance(ns, (tuple, list)) else int(ns) raise ValueError(f"Cannot determine hidden_size for {type(layer).__name__}") def _find_layer_container( self, ) -> tuple[nn.Module | None, str | None, nn.ModuleList | None]: candidates = [ ( "roberta.encoder.layer", lambda m: getattr( getattr(getattr(m, "roberta", None), "encoder", None), "layer", None ), ), ( "bert.encoder.layer", lambda m: getattr( getattr(getattr(m, "bert", None), "encoder", None), "layer", None ), ), ( "distilbert.transformer.layer", lambda m: getattr( getattr(getattr(m, "distilbert", None), "transformer", None), "layer", None, ), ), ( "transformer.layer", lambda m: getattr(getattr(m, "transformer", None), "layer", None), ), ( "transformer.h", lambda m: getattr(getattr(m, "transformer", None), "h", None), ), ( "transformer.blocks", lambda m: getattr(getattr(m, "transformer", None), "blocks", None), ), ( "model.layers", lambda m: getattr(getattr(m, "model", None), "layers", None), ), ( "model.decoder.layers", lambda m: getattr( getattr(getattr(m, "model", None), "decoder", None), "layers", None ), ), ( "model.encoder.layers", lambda m: getattr( getattr(getattr(m, "model", None), "encoder", None), "layers", None ), ), ( "encoder.layer", lambda m: getattr(getattr(m, "encoder", None), "layer", None), ), ( "decoder.layer", lambda m: getattr(getattr(m, "decoder", None), "layer", None), ), ("layers", lambda m: getattr(m, "layers", None)), ("h", lambda m: getattr(m, "h", None)), ("blocks", lambda m: getattr(m, "blocks", None)), ( "model.encoder.block", lambda m: getattr( getattr(getattr(m, "model", None), "encoder", None), "block", None ), ), ( "model.decoder.block", lambda m: getattr( getattr(getattr(m, "model", None), "decoder", None), "block", None ), ), ( "encoder.block", lambda m: getattr(getattr(m, "encoder", None), "block", None), ), ( "decoder.block", lambda m: getattr(getattr(m, "decoder", None), "block", None), ), ] for name, getter in candidates: res = getter(self.model) if isinstance(res, (nn.ModuleList, nn.Sequential, list)) and len(res) > 0: parts = name.split(".") parent = self.model for p in parts[:-1]: parent = getattr(parent, p) return parent, parts[-1], res best_match = None max_score = -1 for name, module in self.model.named_modules(): if isinstance(module, (nn.ModuleList, nn.Sequential)) and len(module) >= 2: parts = name.split(".") last = parts[-1].lower() is_layer_name = any(k in last for k in ["layer", "h", "block"]) score = len(module) + (1000 if is_layer_name else 0) if score > max_score: max_score = score parent = self.model for p in parts[:-1]: parent = getattr(parent, p) best_match = (parent, parts[-1], module) if best_match is not None: return best_match return None, None, None # ------------------------------------------------------------------ # compress # ------------------------------------------------------------------ def compress(self, **kwargs: Any) -> tuple[nn.Module, dict[str, Any]]: parent, attr_name, layers = self._find_layer_container() bridges_inserted = 0 self.compressed_layers = [] self.fallback_layers = [] self.skipped_layers = [] orig_len = 0 keep_len = 0 if layers is not None and parent is not None and attr_name is not None: orig_len = len(layers) keep_len = max(1, int(round(orig_len * (1.0 - self.sparsity)))) if self.target_layers is not None: keep_len = min(orig_len, max(1, self.target_layers)) if keep_len < orig_len: kept_indices = np.round(np.linspace(0, orig_len - 1, keep_len)).astype(int).tolist() seen = set() kept_indices = [x for x in kept_indices if not (x in seen or seen.add(x))] bridged_module_list = nn.ModuleList() for i, layer_idx in enumerate(kept_indices): layer = layers[layer_idx] is_gap = i < len(kept_indices) - 1 and kept_indices[i + 1] > layer_idx + 1 if is_gap: hidden_size = self._get_hidden_size(layer) # Use hidden_size as cap on bridge_rank effective_bridge_rank = max(1, min(self.bridge_rank, hidden_size)) bridge = CoMeBridge( hidden_size=hidden_size, bridge_rank=effective_bridge_rank, alpha_init=self.alpha_init, ) p = next(layer.parameters(), None) if p is not None: bridge = bridge.to(device=p.device, dtype=p.dtype) bridged_module_list.append(CoMeBridgedLayer(layer, bridge=bridge)) bridges_inserted += 1 else: bridged_module_list.append(layer) setattr(parent, attr_name, bridged_module_list) self.compressed_layers.append(f"{attr_name} (shed {orig_len - keep_len} layers)") else: # Fallback SVD compression (still supported) seen_weights: set[int] = set() for name, module in list(self.model.named_modules()): if self._is_target_module(name, module): target_mod = getattr(module, "base_layer", getattr(module, "linear", module)) w_id = id(target_mod.weight) if w_id in seen_weights: self.skipped_layers.append(name) continue seen_weights.add(w_id) try: raw_w = target_mod.weight.data cls_name = module.__class__.__name__.lower() is_conv1d = ( "conv1d" in cls_name or hasattr(module, "nf") or hasattr(target_mod, "nf") ) W = ( raw_w.t().contiguous().clone().float() if is_conv1d else raw_w.clone().float() ) U, S, Vt = torch.linalg.svd(W, full_matrices=False) # Prefer explicit rank, otherwise derive from sparsity if self.rank is not None: r = max(1, min(int(self.rank), len(S))) else: r = max(1, int(len(S) * (1.0 - self.sparsity))) from neuralops.compression_engine.aa_svd_compressor import ( SVDLinear, ) in_features = W.shape[1] out_features = W.shape[0] svd_layer = SVDLinear( in_features=in_features, out_features=out_features, rank=r, bias=getattr(target_mod, "bias", None) is not None, ) svd_layer.set_low_rank_factors(U[:, :r] * S[:r], Vt[:r, :]) if getattr(target_mod, "bias", None) is not None: svd_layer.bias.data.copy_(target_mod.bias.data) replace_module(self.model, name, svd_layer) self.compressed_layers.append(name) except Exception as e: logger.warning("CoMe fallback SVD failed on %s: %s", name, e) self.fallback_layers.append(name) for p in module.parameters(): p.requires_grad = False # Optional post-shedding LoRA if self.lora_r > 0: seen_weights: set[int] = set() for name, module in list(self.model.named_modules()): if self._is_target_module(name, module): target_mod = getattr(module, "base_layer", getattr(module, "linear", module)) has_lora = (hasattr(module, "lora_A") and module.lora_A is not None) or hasattr( module, "base_layer" ) w_id = id(target_mod.weight) if w_id in seen_weights: self.skipped_layers.append(name) continue seen_weights.add(w_id) if has_lora: target_mod.weight.requires_grad = False if ( getattr(target_mod, "bias", None) is not None and target_mod.bias is not None ): target_mod.bias.requires_grad = False for p_name, p in module.named_parameters(): if any(t in p_name.lower() for t in ("lora_a", "lora_b", "adapter")): p.requires_grad = True else: lora_mod = CoMeLoRALinear.from_linear( target_mod, lora_r=self.lora_r, lora_alpha=self.lora_alpha, ) replace_module(self.model, name, lora_mod) # LayerNorm recalibration if self.recalibrate_ln: try: recalibrate_layernorms( self.model, tokenizer=self.tokenizer, device=self.target_device, ) except Exception as e: logger.warning("CoMe LayerNorm recalibration skipped: %s", e) # Forward sanity check forward_check_success = False try: self.model.eval() with torch.no_grad(): d = next(self.model.parameters()).device dummy = torch.randint(0, 100, (1, 16), device=d) self.model(dummy) forward_check_success = True except Exception as e: logger.error("CoMe post-compression forward sanity check failed: %s", e) if not self.allow_forward_failure: raise RuntimeError(f"CoMe post-compression forward check failed: {e}") from e self._compressed_params = self._count_params(self.model) shed_count = orig_len - keep_len if orig_len > 0 else 0 reduc_ratio = float(shed_count) / orig_len if orig_len > 0 else self.sparsity flops_reduction = f"{reduc_ratio * 100:.1f}%" bridge_params_count = sum( p.numel() for m in self.model.modules() if isinstance(m, CoMeBridge) for p in m.parameters() ) lora_params_count = sum( p.numel() for m in self.model.modules() if isinstance(m, CoMeLoRALinear) for p in [m.lora_A, m.lora_B] if p is not None ) stats = self.get_compression_stats() num_compressed = len(self.compressed_layers) num_fallback = len(self.fallback_layers) # Write BOTH naming conventions so downstream readers find them stats.update( { "original_layer_count": orig_len, "kept_layer_count": keep_len, "shed_layer_count": shed_count, "layer_reduction_ratio": reduc_ratio, "estimated_flops_reduction": flops_reduction, "bridges_inserted": bridges_inserted, "bridge_rank": self.bridge_rank, "rank": self.rank, "bridge_parameters": bridge_params_count, "lora_parameters": lora_params_count, "trainable_parameters": sum(p.numel() for p in self.get_trainable_params()), "target_layers": self.target_layers, "sparsity": self.sparsity, "lora_r": self.lora_r, "lora_alpha": self.lora_alpha, "target_attention_only": self.target_attention_only, "recalibrate_ln": self.recalibrate_ln, "compressed_layers": self.compressed_layers, "fallback_layers": self.fallback_layers, "skipped_layers": self.skipped_layers, # Primary keys expected by run_quality_sweep.py: "num_compressed": num_compressed, "num_fallback": num_fallback, # Alternate key names used by some readers: "num_compressed_layers": num_compressed, "num_fallback_layers": num_fallback, "compressed_layers_count": num_compressed, "fallback_layer_count": num_fallback, "num_skipped": len(self.skipped_layers), "forward_check_success": forward_check_success, "method": "come_layer_shedding_with_bridges", } ) self.stats = stats self.model.compression_stats = stats # Also attach to the compressor instance itself so nested pipelines can recover it try: self.model._come_stats = stats except Exception: pass return self.model, stats def get_trainable_params(self) -> list[nn.Parameter]: trainable = [] for _, param in self.model.named_parameters(): if param.requires_grad: trainable.append(param) return trainableCoMe Compressor: Layer shedding with learnable low-rank interpolation adapters (bridges) between non-consecutive retained layers.
Config parameters (via kwargs or comp_config): rank : int, optional — SVD-style rank. If provided and bridge_rank/sparsity are not explicitly set, they are derived from rank via safe mappings. target_layers : int, optional — target layer count after shedding. sparsity : float, default 0.10 — fraction of layers to remove. bridge_rank : int, optional — bottleneck rank for the low-rank interpolation bridge (B @ A). If not set, derived from rank (rank // 4) or defaults to 64 for the full hidden size. alpha_init : float, default 0.1 — initial bridge mixing coeff. lora_r : int, default 16 — post-shedding LoRA rank. lora_alpha : float, default 1.0 — LoRA scaling. target_attention_only : bool, default False. skip_attention_qkv : bool, default True — protect asymmetric GQA. recalibrate_ln : bool, default True. allow_forward_failure : bool, default False.
Ancestors
Class variables
var is_custom_attention : bool-
The type of the None singleton.
Methods
def get_trainable_params(self) ‑> list[torch.nn.parameter.Parameter]-
Expand source code
def get_trainable_params(self) -> list[nn.Parameter]: trainable = [] for _, param in self.model.named_parameters(): if param.requires_grad: trainable.append(param) return trainable
Inherited members
class CoMeLoRALinear (in_features: int,
out_features: int,
weight: torch.Tensor,
bias: torch.Tensor | None = None,
lora_r: int = 0,
lora_alpha: float = 1.0,
device: torch.device | None = None,
dtype: torch.dtype | None = None)-
Expand source code
class CoMeLoRALinear(nn.Module): """Linear layer: frozen base weights + optional trainable LoRA adapters.""" def __init__( self, in_features: int, out_features: int, weight: torch.Tensor, bias: torch.Tensor | None = None, lora_r: int = 0, lora_alpha: float = 1.0, device: torch.device | None = None, dtype: torch.dtype | None = None, ) -> None: super().__init__() self.in_features = in_features self.out_features = out_features self.nf = out_features # Conv1D compatibility self.lora_r = int(lora_r) self.lora_alpha = float(lora_alpha) self.scaling = (self.lora_alpha / self.lora_r) if self.lora_r > 0 else 1.0 target_device = device if device is not None else weight.device target_dtype = dtype if dtype is not None else weight.dtype self.weight = nn.Parameter( weight.to(device=target_device, dtype=target_dtype), requires_grad=False, ) if bias is not None: self.bias = nn.Parameter( bias.to(device=target_device, dtype=target_dtype), requires_grad=False, ) else: self.register_parameter("bias", None) if self.lora_r > 0: self.lora_A = nn.Parameter( torch.empty((self.lora_r, in_features), dtype=target_dtype, device=target_device) ) self.lora_B = nn.Parameter( torch.zeros( (out_features, self.lora_r), dtype=target_dtype, device=target_device, ) ) nn.init.kaiming_uniform_(self.lora_A, a=math.sqrt(5)) else: self.register_parameter("lora_A", None) self.register_parameter("lora_B", None) @classmethod def from_linear( cls, linear: nn.Module, lora_r: int = 0, lora_alpha: float = 1.0, ) -> CoMeLoRALinear: target_mod = getattr(linear, "base_layer", getattr(linear, "linear", linear)) cls_name = target_mod.__class__.__name__.lower() is_conv1d = "conv1d" in cls_name or hasattr(target_mod, "nf") raw_w = target_mod.weight.detach() if is_conv1d: in_f = raw_w.shape[0] out_f = raw_w.shape[1] w = raw_w.t().contiguous().clone() else: out_f = raw_w.shape[0] in_f = raw_w.shape[1] w = raw_w.clone() bias = ( target_mod.bias.detach().clone() if getattr(target_mod, "bias", None) is not None and target_mod.bias is not None else None ) return cls( in_features=in_f, out_features=out_f, weight=w, bias=bias, lora_r=lora_r, lora_alpha=lora_alpha, device=w.device, dtype=w.dtype, ) def forward(self, x: torch.Tensor) -> torch.Tensor: orig_shape = x.shape x_flat = x.reshape(-1, self.in_features) out = F.linear( x_flat, self.weight.to(x_flat.dtype), self.bias.to(x_flat.dtype) if self.bias is not None else None, ) if self.lora_r > 0 and self.lora_A is not None and self.lora_B is not None: lora_out = F.linear(F.linear(x_flat.to(self.lora_A.dtype), self.lora_A), self.lora_B) out = out + (self.scaling * lora_out).to(out.dtype) return out.reshape(*orig_shape[:-1], self.out_features)Linear layer: frozen base weights + optional trainable LoRA adapters.
Initialize internal Module state, shared by both nn.Module and ScriptModule.
Ancestors
- torch.nn.modules.module.Module
Static methods
def from_linear(linear: nn.Module, lora_r: int = 0, lora_alpha: float = 1.0) ‑> CoMeLoRALinear
Methods
def forward(self, x: torch.Tensor) ‑> torch.Tensor-
Expand source code
def forward(self, x: torch.Tensor) -> torch.Tensor: orig_shape = x.shape x_flat = x.reshape(-1, self.in_features) out = F.linear( x_flat, self.weight.to(x_flat.dtype), self.bias.to(x_flat.dtype) if self.bias is not None else None, ) if self.lora_r > 0 and self.lora_A is not None and self.lora_B is not None: lora_out = F.linear(F.linear(x_flat.to(self.lora_A.dtype), self.lora_A), self.lora_B) out = out + (self.scaling * lora_out).to(out.dtype) return out.reshape(*orig_shape[:-1], self.out_features)Define the computation performed at every call.
Should be overridden by all subclasses.
Note
Although the recipe for forward pass needs to be defined within this function, one should call the :class:
Moduleinstance afterwards instead of this since the former takes care of running the registered hooks while the latter silently ignores them.