char-fork/llama.cpp
git clone https://git.t4t.associates/char-fork/llama.cpp
fa88ae936
char/aliceai-t5-moe
1from __future__import annotations 2 3import json 4import math 5import re 6 7from typing import Callable ,Iterable ,TYPE_CHECKING 8 9import torch 10 11if TYPE_CHECKING : 12from torch import Tensor 13 14from .base import MmprojModel ,ModelBase ,TextModel ,gguf 15 16 17@ ModelBase . register ( "Ernie4_5_ForCausalLM" , "Ernie4_5ForCausalLM" ) 18@ ModelBase . example ( "baidu/ERNIE-4.5-0.3B-PT" ) 19class Ernie4_5Model (TextModel ): 20model_arch = gguf .MODEL_ARCH .ERNIE4_5 21 22def set_vocab (self ): 23self ._set_vocab_sentencepiece () 24 25tokenizer_config_file = self .dir_model / 'tokenizer_config.json' 26if tokenizer_config_file .is_file (): 27with open (tokenizer_config_file ,"r" ,encoding = "utf-8" )as f : 28tokenizer_config_json = json .load (f ) 29if "add_prefix_space" in tokenizer_config_json : 30self .gguf_writer .add_add_space_prefix (tokenizer_config_json ["add_prefix_space" ]) 31 32def set_gguf_parameters (self ): 33super ().set_gguf_parameters () 34 35@classmethod 36def filter_tensors (cls ,item :tuple [str ,Callable [[],Tensor ]])-> tuple [str ,Callable [[],Tensor ]]| None : 37name ,gen = item 38 39if "ernie." in name : 40name = name .replace ("ernie." ,"model." ) 41 42return super ().filter_tensors ((name ,gen )) 43 44def modify_tensors (self ,data_torch :Tensor ,name :str ,bid :int | None )-> Iterable [tuple [str ,Tensor ]]: 45num_heads = self .hparams ["num_attention_heads" ] 46num_kv_heads = self .hparams ["num_key_value_heads" ] 47if (head_dim := self .hparams .get ("head_dim" ))is None : 48head_dim = self .hparams ["hidden_size" ]// num_heads 49 50# split the qkv weights 51# qkv_proj shape: [(num_heads + 2 * num_kv_heads) * head_dim, hidden_size] 52if "qkv_proj" in name : 53name_q = name .replace ("qkv_proj.weight" ,"q_proj.weight" ) 54name_k = name .replace ("qkv_proj.weight" ,"k_proj.weight" ) 55name_v = name .replace ("qkv_proj.weight" ,"v_proj.weight" ) 56total_q_dim = num_heads * head_dim 57total_k_dim = num_kv_heads * head_dim 58total_v_dim = num_kv_heads * head_dim 59q_proj_weight ,k_proj_weight ,v_proj_weight = data_torch .split ([total_q_dim ,total_k_dim ,total_v_dim ],dim = 0 ) 60yield from super ().modify_tensors (q_proj_weight ,name_q ,bid ) 61yield from super ().modify_tensors (k_proj_weight ,name_k ,bid ) 62yield from super ().modify_tensors (v_proj_weight ,name_v ,bid ) 63# split the up_gate_proj into gate and up 64# up_gate_proj shape: [2 * intermediate_size, hidden_size] 65elif "up_gate_proj" in name : 66name_up = name .replace ("up_gate_proj.weight" ,"up_proj.weight" ) 67name_gate = name .replace ("up_gate_proj.weight" ,"gate_proj.weight" ) 68dim_half = data_torch .shape [0 ]// 2 69gate_proj_weight ,up_proj_weight = data_torch .split (dim_half ,dim = 0 ) 70yield from super ().modify_tensors (gate_proj_weight ,name_gate ,bid ) 71yield from super ().modify_tensors (up_proj_weight ,name_up ,bid ) 72else : 73yield from super ().modify_tensors (data_torch ,name ,bid ) 74 75 76@ ModelBase . register ( "Ernie4_5_MoeForCausalLM" ) 77@ ModelBase . example ( "baidu/ERNIE-4.5-21B-A3B-PT" ) 78class Ernie4_5MoeModel (Ernie4_5Model ): 79model_arch = gguf .MODEL_ARCH .ERNIE4_5_MOE 80_experts :list [dict [str ,Tensor ]]| None = None 81 82def __init__ (self ,* args ,** kwargs ): 83super ().__init__ (* args ,** kwargs ) 84self ._experts = [{}for _ in range (self .block_count )] 85 86def set_gguf_parameters (self ): 87super ().set_gguf_parameters () 88self .gguf_writer .add_expert_count (self .hparams ["moe_num_experts" ]) 89self .gguf_writer .add_expert_used_count (self .hparams ["moe_k" ]) 90self .gguf_writer .add_interleave_moe_layer_step (self .hparams ["moe_layer_interval" ]) 91self .gguf_writer .add_leading_dense_block_count (self .hparams ["moe_layer_start_index" ]) 92if (moe_intermediate_size := self .hparams .get ("moe_intermediate_size" ))is not None : 93self .gguf_writer .add_expert_feed_forward_length (moe_intermediate_size ) 94if (shared_expert_count := self .hparams .get ('moe_num_shared_experts' ))is not None : 95self .gguf_writer .add_expert_shared_count (shared_expert_count ) 96if shared_expert_count > 0 and (shared_expert_intermediate_size := self .hparams .get ('intermediate_size' ))is not None and (num_key_value_heads := self .hparams .get ('num_key_value_heads' ))is not None : 97self .gguf_writer .add_expert_shared_feed_forward_length (shared_expert_intermediate_size // num_key_value_heads ) 98 99@classmethod 100def filter_tensors (cls ,item :tuple [str ,Callable [[],Tensor ]])-> tuple [str ,Callable [[],Tensor ]]| None : 101name ,gen = item 102 103# skip Multi-Token Prediction (MTP) layers (again, same as DeepseekV2) 104match = re .match (r"model.mtp_block.(\d+)" ,name ) 105if match : 106return None 107 108# skip all other MTP tensors for now 109match = re .match (r"model.mtp_emb_norm.(\d+)" ,name ) 110if match : 111return None 112 113match = re .match (r"model.mtp_hidden_norm.(\d+)" ,name ) 114if match : 115return None 116 117match = re .match (r"model.mtp_linear_proj.(\d+)" ,name ) 118if match : 119return None 120 121return super ().filter_tensors (item ) 122 123def modify_tensors (self ,data_torch :Tensor ,name :str ,bid :int | None )-> Iterable [tuple [str ,Tensor ]]: 124# process the experts separately 125if name .find ("mlp.experts" )!= - 1 : 126n_experts = self .hparams ["moe_num_experts" ] 127assert bid is not None 128 129if self ._experts is None : 130self ._experts = [{}for _ in range (self .block_count )] 131 132self ._experts [bid ][name ]= data_torch 133 134if len (self ._experts [bid ])>= n_experts * 3 : 135# merge the experts into a single 3d tensor 136for w_name in ["gate_proj" ,"up_proj" ,"down_proj" ]: 137datas :list [Tensor ]= [] 138 139for xid in range (n_experts ): 140ename_to_retrieve = f"model.layers. { bid } .mlp.experts. { xid } . { w_name } .weight" 141datas .append (self ._experts [bid ][ename_to_retrieve ]) 142del self ._experts [bid ][ename_to_retrieve ] 143 144data_torch = torch .stack (datas ,dim = 0 ) 145merged_name = f"model.layers. { bid } .mlp.experts. { w_name } .weight" 146yield from super ().modify_tensors (data_torch ,merged_name ,bid ) 147else : 148yield from ModelBase .modify_tensors (self ,data_torch ,name ,bid ) 149 150def prepare_tensors (self ): 151super ().prepare_tensors () 152 153if self ._experts is not None : 154# flatten `list[dict[str, Tensor]]` into `list[str]` 155experts = [k for d in self ._experts for k in d .keys ()] 156if len (experts )> 0 : 157raise ValueError (f"Unprocessed experts: { experts } " ) 158 159 160@ ModelBase . register ( "PaddleOCRVLForConditionalGeneration" ) 161@ ModelBase . example ( "PaddlePaddle/PaddleOCR-VL" ) 162class PaddleOCRModel (Ernie4_5Model ): 163model_arch = gguf .MODEL_ARCH .PADDLEOCR 164 165 166@ ModelBase . register ( "PaddleOCRVisionModel" ) 167@ ModelBase . example ( "PaddlePaddle/PaddleOCR-VL" ) 168class PaddleOCRVisionModel (MmprojModel ): 169# PaddleOCR-VL uses a modified version of Siglip 170min_pixels :int = 0 171max_pixels :int = 0 172 173def __init__ (self ,* args ,** kwargs ): 174super ().__init__ (* args ,** kwargs ) 175assert self .hparams_vision is not None 176self .min_pixels = self .preprocessor_config ["min_pixels" ] 177self .max_pixels = self .preprocessor_config ["max_pixels" ] 178self .hparams_vision ["image_size" ]= int (math .sqrt (self .max_pixels )) 179 180def set_gguf_parameters (self ): 181super ().set_gguf_parameters () 182assert self .hparams_vision is not None 183hparams = self .hparams_vision 184self .gguf_writer .add_clip_projector_type (gguf .VisionProjectorType .PADDLEOCR ) 185self .gguf_writer .add_vision_max_pixels (self .max_pixels ) 186self .gguf_writer .add_vision_min_pixels (self .min_pixels ) 187self .gguf_writer .add_vision_use_gelu (True ) 188self .gguf_writer .add_vision_attention_layernorm_eps (hparams .get ("rms_norm_eps" ,1e-6 )) 189 190@classmethod 191def filter_tensors (cls ,item :tuple [str ,Callable [[],Tensor ]])-> tuple [str ,Callable [[],Tensor ]]| None : 192name ,gen = item 193 194if "vision_model" not in name and "mlp_AR" not in name : 195return None 196name = name .replace ("visual." ,"model." ) 197if "packing_position_embedding" in name : 198# unused 199return None 200if "vision_model.head" in name : 201# we don't yet support image embeddings for this model 202return None 203 204return super ().filter_tensors ((name ,gen ))