| import torch
|
| from torch import nn
|
| from typing import Optional, Tuple, List
|
| from quantize.int_linear import QuantLinear
|
| from quantize.int_matmul import QuantMatMul
|
| import torch.nn.functional as F
|
| from quantize.slider_norm import SliderLlamaRMSNorm
|
| from quantize.slider_norm import RMSN
|
| from collections import OrderedDict
|
| import math
|
| from transformers.models.llama.modeling_llama import LlamaRotaryEmbedding,apply_rotary_pos_emb,LlamaRMSNorm,repeat_kv
|
| from transformers.models.llama.configuration_llama import LlamaConfig
|
| from transformers.activations import ACT2FN
|
| import copy
|
| from models.transformation import *
|
|
|
| from transformers.models.qwen3_moe.modeling_qwen3_moe import Qwen3MoeSparseMoeBlock
|
|
|
|
|
| from quantize.int_linear_lora import LoRAQuantLinear
|
|
|
| from models.hadamard_utils import random_hadamard_matrix
|
|
|
| from quantize.utils import cleanup_memory
|
|
|
| class QuantLlamaMLP(nn.Module):
|
| def __init__(
|
| self,
|
| org_module: nn.Module,
|
| hidden_act: str,
|
| args=None,
|
| use_lora=False,
|
| lora_attr=None,
|
| ):
|
| super().__init__()
|
| self.lora_attr = lora_attr
|
| self.merged_down = False
|
|
|
| self.args = args
|
| if use_lora:
|
| self.gate_proj = LoRAQuantLinear(
|
| org_module.gate_proj,
|
| args.weight_quant_params,
|
| args.act_quant_params,
|
| r=args.lora_rank,
|
| lora_attr=self.lora_attr
|
| )
|
| self.down_proj = LoRAQuantLinear(
|
| org_module.down_proj,
|
| args.weight_quant_params,
|
| args.act_quant_params,
|
| r=args.lora_rank,
|
| lora_attr=self.lora_attr
|
| )
|
| self.up_proj = LoRAQuantLinear(
|
| org_module.up_proj,
|
| args.weight_quant_params,
|
| args.act_quant_params,
|
| r=args.lora_rank,
|
| lora_attr=self.lora_attr
|
| )
|
| else:
|
| self.gate_proj = QuantLinear(
|
| org_module.gate_proj,
|
| args.weight_quant_params,
|
| args.act_quant_params,
|
| )
|
| self.down_proj = QuantLinear(
|
| org_module.down_proj,
|
| args.weight_quant_params,
|
| args.act_quant_params,
|
| )
|
| self.up_proj = QuantLinear(
|
| org_module.up_proj, args.weight_quant_params, args.act_quant_params
|
| )
|
| self.act_fn = ACT2FN[hidden_act]
|
|
|
|
|
|
|
|
|
| def forward(self, x):
|
|
|
| return self.down_proj(self.act_fn(self.gate_proj(x)) * self.up_proj(x))
|
|
|
| def get_quant_moe_mlp(org_module: nn.Module,args,config,use_lora,lora_attr):
|
| if args.quant_gate is True or args.update_gate is True:
|
| if use_lora:
|
| weight_quant_params = copy.deepcopy(args.weight_quant_params)
|
| act_quant_params = copy.deepcopy(args.act_quant_params)
|
|
|
| if args.update_gate is True:
|
| weight_quant_params["n_bits"] = 16
|
| act_quant_params["n_bits"] = 16
|
|
|
| org_module.gate = LoRAQuantLinear(
|
| org_module.gate,
|
| weight_quant_params,
|
| act_quant_params,
|
| r=args.lora_rank,
|
| lora_attr=lora_attr
|
| )
|
| else:
|
| org_module.gate = QuantLinear(
|
| org_module.gate,
|
| args.weight_quant_params,
|
| args.act_quant_params,
|
| )
|
|
|
|
|
| for i in range(len(org_module.experts)):
|
| ori_mlp = org_module.experts[i]
|
| org_module.experts[i] = QuantLlamaMLP(
|
| org_module=ori_mlp,
|
| hidden_act=config.hidden_act,
|
| args=args,
|
| use_lora=use_lora,
|
| lora_attr=lora_attr
|
| )
|
| return org_module
|
|
|
|
|
| class QuantLlamaAttention(nn.Module):
|
| """Multi-headed attention from 'Attention Is All You Need' paper"""
|
|
|
| def __init__(self,
|
| org_module: nn.Module,
|
| config: LlamaConfig,
|
| args=None,
|
| use_lora=False,
|
| lora_attr=None,
|
| layer_id = None,
|
| ):
|
| super().__init__()
|
| self.config = config
|
| self.hidden_size = config.hidden_size
|
| self.num_heads = config.num_attention_heads
|
|
|
| self.head_dim = getattr(config, "head_dim", config.hidden_size // config.num_attention_heads)
|
| self.num_key_value_groups = config.num_attention_heads // config.num_key_value_heads
|
| self.num_key_value_heads = config.num_key_value_heads
|
| self.max_position_embeddings = config.max_position_embeddings
|
| self.lora_attr = lora_attr
|
| self.merge_v = False
|
| self.layer_idx = layer_id
|
| self.scaling = self.head_dim**-0.5
|
| self.add_norm_model_list = ["qwen3" ,"qwen3_moe"]
|
|
|
|
|
| if config.model_type in self.add_norm_model_list :
|
| self.q_norm = copy.deepcopy(org_module.q_norm)
|
| self.k_norm = copy.deepcopy(org_module.k_norm)
|
|
|
| self.merged_vo = False
|
|
|
| self.args = args
|
| if (self.head_dim * self.num_heads) != self.hidden_size and self.config.model_type not in self.add_norm_model_list:
|
| raise ValueError(
|
| f"hidden_size must be divisible by num_heads (got `hidden_size`: {self.hidden_size}"
|
| f" and `num_heads`: {self.num_heads})."
|
| )
|
|
|
|
|
| self.rotary_emb = LlamaRotaryEmbedding(self.config)
|
|
|
| if use_lora:
|
| self.k_proj = LoRAQuantLinear(
|
| org_module.k_proj,
|
| args.weight_quant_params,
|
| args.act_quant_params,
|
| disable_input_quant=False,
|
| r=args.lora_rank,
|
| lora_attr=self.lora_attr
|
| )
|
| self.v_proj = LoRAQuantLinear(
|
| org_module.v_proj,
|
| args.weight_quant_params,
|
| args.act_quant_params,
|
| disable_input_quant=False,
|
| r=args.lora_rank,
|
| lora_attr=self.lora_attr
|
| )
|
| self.q_proj = LoRAQuantLinear(
|
| org_module.q_proj,
|
| args.weight_quant_params,
|
| args.act_quant_params,
|
| disable_input_quant=False,
|
| r=args.lora_rank,
|
| lora_attr=self.lora_attr
|
| )
|
| self.o_proj = LoRAQuantLinear(
|
| org_module.o_proj,
|
| args.weight_quant_params,
|
| args.act_quant_params,
|
| r=args.lora_rank,
|
| lora_attr=self.lora_attr
|
| )
|
| else:
|
| self.k_proj = QuantLinear(
|
| org_module.k_proj,
|
| args.weight_quant_params,
|
| args.act_quant_params,
|
| disable_input_quant=False,
|
| )
|
| self.v_proj = QuantLinear(
|
| org_module.v_proj,
|
| args.weight_quant_params,
|
| args.act_quant_params,
|
| disable_input_quant=False,
|
| )
|
| self.q_proj = QuantLinear(
|
| org_module.q_proj,
|
| args.weight_quant_params,
|
| args.act_quant_params,
|
| disable_input_quant=False,
|
| )
|
| self.o_proj = QuantLinear(
|
| org_module.o_proj, args.weight_quant_params, args.act_quant_params
|
| )
|
|
|
| self.qkt_matmul = QuantMatMul(
|
| args.q_quant_params, args.k_quant_params, matmul_func=torch.matmul
|
| )
|
| self.pv_matmul = QuantMatMul(
|
| args.p_quant_params, args.v_quant_params, matmul_func=torch.matmul
|
| )
|
|
|
| self.use_weight_quant = False
|
| self.use_act_quant = False
|
|
|
|
|
|
|
|
|
| def _shape(self, tensor: torch.Tensor, seq_len: int, bsz: int):
|
| return tensor.view(bsz, seq_len, self.num_heads, self.head_dim).transpose(1, 2).contiguous()
|
|
|
| def forward(
|
| self,
|
| hidden_states: torch.Tensor,
|
| attention_mask: Optional[torch.Tensor] = None,
|
| position_ids: Optional[torch.LongTensor] = None,
|
| past_key_value: Optional[Tuple[torch.Tensor]] = None,
|
| output_attentions: bool = False,
|
| use_cache: bool = False,
|
| cache_position: Optional[torch.LongTensor] = None,
|
| position_embeddings: Tuple[torch.Tensor, torch.Tensor] = None,
|
| ) -> Tuple[torch.Tensor, Optional[torch.Tensor], Optional[Tuple[torch.Tensor]]]:
|
| bsz, q_len, _ = hidden_states.size()
|
|
|
| input_shape = hidden_states.shape[:-1]
|
| hidden_shape = (*input_shape, -1, self.head_dim)
|
|
|
| if self.config.model_type in self.add_norm_model_list:
|
|
|
| query_states = self.q_norm(self.q_proj(hidden_states).view(hidden_shape)).transpose(1, 2)
|
| key_states = self.k_norm(self.k_proj(hidden_states).view(hidden_shape)).transpose(1, 2)
|
| else:
|
| query_states = self.q_proj(hidden_states).view(hidden_shape).transpose(1, 2)
|
| key_states = self.k_proj(hidden_states).view(hidden_shape).transpose(1, 2)
|
|
|
| value_states = self.v_proj(hidden_states).view(hidden_shape).transpose(1, 2)
|
|
|
|
|
|
|
| kv_seq_len = key_states.shape[-2]
|
|
|
| if past_key_value is not None:
|
|
|
| if self.layer_idx is None:
|
| raise ValueError(
|
| f"The cache structure has changed since version v4.36. If you are using {self.__class__.__name__} "
|
| "for auto-regressive decoding with k/v caching, please make sure to initialize the attention class "
|
| "with a layer index."
|
| )
|
| kv_seq_len += past_key_value.get_usable_length(kv_seq_len, self.layer_idx)
|
|
|
| cos, sin = position_embeddings
|
| query_states, key_states = apply_rotary_pos_emb(query_states, key_states, cos, sin, position_ids)
|
|
|
|
|
|
|
|
|
|
|
| if past_key_value is not None:
|
|
|
| cache_kwargs = {"sin": sin, "cos": cos, "cache_position": cache_position}
|
| key_states, value_states = past_key_value.update(key_states, value_states, self.layer_idx, cache_kwargs)
|
|
|
| key_states = repeat_kv(key_states, self.num_key_value_groups)
|
| value_states = repeat_kv(value_states, self.num_key_value_groups)
|
|
|
|
|
|
|
| query_states = self.qkt_matmul.quant_x1(query_states)
|
| key_states = self.qkt_matmul.quant_x2(key_states)
|
| attn_weights = self.qkt_matmul(query_states, key_states.transpose(2, 3)) * self.scaling
|
|
|
|
|
| if attention_mask is not None:
|
| causal_mask = attention_mask[:, :, :, : key_states.shape[-2]]
|
| attn_weights = attn_weights + causal_mask
|
| attn_weights = torch.max(attn_weights, torch.tensor(torch.finfo(attn_weights.dtype).min))
|
|
|
| attn_weights = nn.functional.softmax(attn_weights, dim=-1, dtype=torch.float32).to(query_states.dtype)
|
| attn_weights = self.pv_matmul.quant_x1(attn_weights)
|
| value_states = self.pv_matmul.quant_x2(value_states)
|
| attn_output = self.pv_matmul(attn_weights, value_states)
|
|
|
|
|
| attn_output = attn_output.transpose(1, 2).contiguous()
|
| attn_output = attn_output.reshape(*input_shape, -1).contiguous()
|
|
|
|
|
| attn_output = self.o_proj(attn_output)
|
|
|
| if not output_attentions:
|
| attn_weights = None
|
|
|
| return attn_output, attn_weights, past_key_value
|
|
|
|
|
|
|
|
|
| class QuantLlamaDecoderLayer(nn.Module):
|
| def __init__(self,
|
| config: LlamaConfig,
|
| ori_layer,
|
| layer_id,
|
| args,
|
| quant_mode="fp16",
|
| use_lora=False,
|
| lora_attr=None,
|
| ):
|
| super().__init__()
|
| self.use_lora = use_lora
|
| self.hidden_size = config.hidden_size
|
| self.lora_attr = lora_attr
|
|
|
| self.self_attn = QuantLlamaAttention(
|
| org_module=ori_layer.self_attn,
|
| config=config,
|
| args=args,
|
| use_lora=self.use_lora,
|
| lora_attr=self.lora_attr,
|
| layer_id = layer_id,
|
| )
|
| if isinstance(ori_layer.mlp, Qwen3MoeSparseMoeBlock):
|
| self.mlp = get_quant_moe_mlp(
|
| org_module=ori_layer.mlp,
|
| args=args,
|
| config=config,
|
| use_lora=self.use_lora,
|
| lora_attr=self.lora_attr
|
| )
|
| else:
|
| self.mlp = QuantLlamaMLP(
|
| org_module=ori_layer.mlp,
|
| hidden_act=config.hidden_act,
|
| args=args,
|
| use_lora=self.use_lora,
|
| lora_attr=self.lora_attr
|
| )
|
|
|
| self.input_layernorm = SliderLlamaRMSNorm(ori_layer.input_layernorm,eps=ori_layer.input_layernorm.variance_epsilon)
|
| self.post_attention_layernorm = SliderLlamaRMSNorm(ori_layer.post_attention_layernorm,eps=ori_layer.post_attention_layernorm.variance_epsilon)
|
| self.eval_mode = False
|
| self.quant_mode = quant_mode
|
|
|
| assert self.quant_mode in ["slider","lora_only","fp16"],"only supprot quant_mode in [slider,fp16]"
|
| self.finished_quant = False
|
| self.revocer_act = False
|
|
|
| self.layer_id = layer_id
|
|
|
| self.massive_act_loc_mask = None
|
| self.modify_massive_act = False
|
| self.args = args
|
| self.Q_merged = False
|
|
|
| self.update_quant_mode(self.quant_mode,args)
|
|
|
|
|
|
|
| def update_quant_mode(self,new_mode,args=None):
|
| self.quant_mode = new_mode
|
| support_list = ["weight_merge","slider","lora_only","fp16"]
|
| assert self.quant_mode in support_list,f"only supprot quant_mode in {support_list}"
|
|
|
| if self.quant_mode == "fp16":
|
| self.set_quant_state(weight_quant=False,act_quant=False,quant_rate=args.quant_rate)
|
| for name, module in self.named_modules():
|
|
|
| if hasattr(module,"use_temporary_parameter"):
|
| module.use_temporary_parameter=False
|
| self.clear_temp_variable()
|
| elif self.quant_mode == "weight_merge":
|
| self.set_quant_state(weight_quant=False,act_quant=bool(args.abits<16),quant_rate=args.quant_rate)
|
|
|
| if self.finished_quant is False:
|
|
|
| if args.quant_mode_layer_list[self.layer_id] in ["slider"]:
|
| self.smooth_inplace()
|
| with torch.no_grad():
|
| for name, module in self.named_modules():
|
| if hasattr(module,"use_temporary_parameter"):
|
| module.use_temporary_parameter=False
|
| if isinstance(module, LoRAQuantLinear):
|
| module.merged = True
|
|
|
|
|
| if args.lora_rank > 0 :
|
| for i in range(module.lora_iter_num):
|
| if args.export_model_path and args.export_model_mode =="fp16":
|
| module.weight = module.weight + module.lora_B[i] @ module.lora_A[i] * module.scaling
|
| else:
|
| module.weight = module.weight_quantizer(module.weight + module.lora_B[i] @ module.lora_A[i] * module.scaling)
|
| else:
|
| module.weight = module.weight_quantizer(module.weight)
|
| elif isinstance(module, QuantLinear):
|
| if args.export_model_path and args.export_model_mode =="fp16":
|
| module.weight = module.weight
|
| else:
|
| module.weight = module.weight_quantizer(module.weight)
|
|
|
| else:
|
| pass
|
| self.finished_quant = True
|
| self.clear_temp_variable()
|
| else:
|
| self.set_quant_state(weight_quant=True,act_quant=bool(args.abits<16),quant_rate=args.quant_rate)
|
| self.clear_temp_variable()
|
|
|
| def update_quant_parms(self,weight_quant_params):
|
| for name, module in self.named_modules():
|
| if isinstance(module, QuantLinear):
|
| module.update_quant_parms(weight_quant_params)
|
|
|
|
|
| def forward(
|
| self,
|
| hidden_states: torch.Tensor,
|
| attention_mask: Optional[torch.Tensor] = None,
|
| position_ids: Optional[torch.LongTensor] = None,
|
| past_key_value: Optional[Tuple[torch.Tensor]] = None,
|
| output_attentions: Optional[bool] = False,
|
| use_cache: Optional[bool] = False,
|
| cache_position: Optional[torch.LongTensor] = None,
|
| position_embeddings: Optional[Tuple[torch.Tensor, torch.Tensor]] = None,
|
| output_router_logits = False,
|
| ) -> Tuple[torch.FloatTensor, Optional[Tuple[torch.FloatTensor, torch.FloatTensor]]]:
|
| """
|
| Args:
|
| hidden_states (`torch.FloatTensor`): input to the layer of shape `(batch, seq_len, embed_dim)`
|
| attention_mask (`torch.FloatTensor`, *optional*): attention mask of size
|
| `(batch, 1, tgt_len, src_len)` where padding elements are indicated by very large negative values.
|
| output_attentions (`bool`, *optional*):
|
| Whether or not to return the attentions tensors of all attention layers. See `attentions` under
|
| returned tensors for more detail.
|
| use_cache (`bool`, *optional*):
|
| If set to `True`, `past_key_values` key value states are returned and can be used to speed up decoding
|
| (see `past_key_values`).
|
| past_key_value (`Tuple(torch.FloatTensor)`, *optional*): cached past key and value projection states
|
| """
|
|
|
|
|
|
|
| if not (self.quant_mode in ["fp16","weight_merge","lora_only"]):
|
| if self.quant_mode in ["slider"]:
|
| self.smooth_and_quant_temporary()
|
| else:
|
| raise NotImplementedError("only supprot quant_mode in [slider,lora_only,weight_merge,fp16]")
|
|
|
|
|
| residual = hidden_states
|
|
|
| hidden_states = self.input_layernorm(hidden_states)
|
|
|
|
|
|
|
| hidden_states, self_attn_weights, present_key_value = self.self_attn(
|
| hidden_states=hidden_states,
|
| attention_mask=attention_mask,
|
| position_ids=position_ids,
|
| past_key_value=past_key_value,
|
| output_attentions=output_attentions,
|
| use_cache=use_cache,
|
| cache_position=cache_position,
|
| position_embeddings=position_embeddings,
|
|
|
| )
|
| hidden_states = residual + hidden_states
|
|
|
|
|
| residual = hidden_states
|
| hidden_states = self.post_attention_layernorm(hidden_states)
|
|
|
|
|
| hidden_states = self.mlp(hidden_states)
|
|
|
| if isinstance(hidden_states, tuple):
|
| hidden_states, router_logits = hidden_states
|
| else:
|
| router_logits = None
|
|
|
| hidden_states = residual + hidden_states
|
|
|
| outputs = (hidden_states,)
|
|
|
| if output_attentions:
|
| outputs += (self_attn_weights,)
|
|
|
| if use_cache:
|
| outputs += (present_key_value,)
|
|
|
| if self.eval_mode:
|
| self.clear_temp_variable()
|
|
|
| if output_attentions:
|
| outputs += (self_attn_weights,)
|
|
|
| if output_router_logits:
|
| outputs += (router_logits,)
|
| return outputs
|
|
|
| def set_quant_state(self, weight_quant: bool = False, act_quant: bool = False, quant_rate:float = 1.0):
|
|
|
| self.use_weight_quant = weight_quant
|
| self.use_act_quant = act_quant
|
| self.quant_rate = quant_rate
|
| names = []
|
| for name, m in self.named_modules():
|
| if isinstance(m, (QuantLinear, QuantMatMul)):
|
| names.append(name)
|
| m.set_quant_state(weight_quant, act_quant, quant_rate)
|
|
|
| def smooth_and_quant_temporary(self):
|
| with torch.no_grad():
|
| for name, module in self.named_parameters():
|
| if "smooth_scale" in name:
|
| module.data = truncate_number(module)
|
|
|
|
|
|
|
| smooth_ln_fcs_temporary(self.input_layernorm,[self.self_attn.q_proj, self.self_attn.k_proj, self.self_attn.v_proj],
|
| self.qkv_smooth_scale,self.qkv_smooth_shift)
|
| smooth_ln_fcs_temporary(self.post_attention_layernorm,[self.mlp.up_proj,self.mlp.gate_proj],
|
| self.fc1_smooth_scale,self.fc1_smooth_shift)
|
| smooth_fc_fc_temporary(self.self_attn.v_proj,self.self_attn.o_proj,
|
| self.out_smooth_scale, self.out_smooth_shift,num_key_value_groups=self.self_attn.num_key_value_groups,head_dim=self.self_attn.head_dim,args=self.args)
|
| smooth_q_k_temporary(self.self_attn.q_proj, self.self_attn.k_proj,
|
| self.qkt_smooth_scale,num_key_value_groups=self.self_attn.num_key_value_groups,head_dim=self.self_attn.head_dim,args=self.args)
|
| if self.args.use_down_scale is True:
|
| smooth_fc_fc_temporary(self.mlp.up_proj,self.mlp.down_proj,
|
| self.fc2_smooth_scale,self.fc2_smooth_shift)
|
| else:
|
| self.mlp.down_proj.temp_weight = self.mlp.down_proj.weight
|
|
|
|
|
|
|
| for name, module in self.named_modules():
|
| if isinstance(module, QuantLinear):
|
| if hasattr(module, "temp_weight"):
|
| module.temp_weight = module.temp_weight
|
| else:
|
| module.temp_weight = module.weight
|
| if not hasattr(module, "temp_bias"):
|
| module.temp_bias = module.bias
|
| module.use_temporary_parameter=True
|
|
|
| def clear_temp_variable(self):
|
| for name, module in self.named_modules():
|
| if hasattr(module,"temp_weight"):
|
| del module.temp_weight
|
| if hasattr(module,"temp_bias"):
|
| del module.temp_bias
|
|
|
|
|
| @torch.no_grad()
|
| def smooth_inplace(self):
|
| if self.let:
|
| for name, module in self.named_parameters():
|
| if "smooth_scale" in name:
|
| module.data = truncate_number(module)
|
| smooth_ln_fcs_inplace(self.input_layernorm,[self.self_attn.q_proj, self.self_attn.k_proj, self.self_attn.v_proj],
|
| self.qkv_smooth_scale,self.qkv_smooth_shift)
|
| smooth_ln_fcs_inplace(self.post_attention_layernorm,[self.mlp.up_proj,self.mlp.gate_proj],
|
| self.fc1_smooth_scale,self.fc1_smooth_shift)
|
| smooth_fc_fc_inplace(self.self_attn.v_proj,self.self_attn.o_proj,
|
| self.out_smooth_scale, self.out_smooth_shift,self.self_attn.num_key_value_groups,head_dim=self.self_attn.head_dim,args=self.args)
|
| smooth_q_k_inplace(self.self_attn.q_proj, self.self_attn.k_proj,
|
| self.qkt_smooth_scale,self.self_attn.num_key_value_groups,head_dim=self.self_attn.head_dim,args=self.args)
|
| if self.args.use_down_scale is True:
|
| smooth_fc_fc_inplace(self.mlp.up_proj,self.mlp.down_proj,
|
| self.fc2_smooth_scale,self.fc2_smooth_shift)
|
|
|
| def get_slider_parameters(self, use_list=["scale"]):
|
| params = []
|
| for n, m in self.named_parameters():
|
| if any(n.find(t) > -1 for t in use_list):
|
| params.append(m)
|
| return iter(params)
|
|
|
| def get_lwc_parameters(self):
|
| params = []
|
| for n, m in self.named_parameters():
|
| if n.find('bound_factor') > -1:
|
| params.append(m)
|
| return iter(params)
|
|
|
| def slider_parameters(self, use_list=["scale"]):
|
| params = []
|
| for n, m in self.named_parameters():
|
| if n.find('bound_factor') > -1 or any(n.find(t) > -1 for t in use_list):
|
| params.append(m)
|
| return iter(params)
|
|
|
| def slider_state_dict(self, destination=None, prefix='', keep_vars=False):
|
| if destination is None:
|
| destination = OrderedDict()
|
| for name, param in self.named_parameters():
|
| if name.find('smooth') > -1 or name.find('bound_factor') > -1:
|
| destination[prefix + name] = param if keep_vars else param.detach()
|
| return destination
|
|
|
| def register_scales_and_zeros(self):
|
| for name, module in self.named_modules():
|
| if isinstance(module, QuantLinear):
|
| module.weight_quantizer.register_scales_and_zeros()
|
|
|