1616
1717@ModelBase .register ("DeepseekOCRForCausalLM" )
1818class DeepseekOCRVisionModel (MmprojModel ):
19+ def __init__ (self , * args , ** kwargs ):
20+ super ().__init__ (* args , ** kwargs )
21+ self .clip_projector_type = gguf .VisionProjectorType .DEEPSEEKOCR
22+
1923 def set_gguf_parameters (self ):
2024 super ().set_gguf_parameters ()
2125 hparams = self .hparams
22- self .gguf_writer .add_clip_projector_type (gguf . VisionProjectorType . DEEPSEEKOCR )
26+ self .gguf_writer .add_clip_projector_type (self . clip_projector_type )
2327 # default values below are taken from HF tranformers code
2428 self .gguf_writer .add_vision_attention_layernorm_eps (hparams .get ("layer_norm_eps" , 1e-6 ))
2529 self .gguf_writer .add_vision_use_gelu (True )
@@ -49,22 +53,27 @@ def get_vision_config(self) -> dict[str, Any]:
4953 raise ValueError ("DeepseekOCR model requires 'vision_config' in the model configuration, but it was not found" )
5054
5155 vision_config ['sam' ] = vision_config ['width' ]['sam_vit_b' ]
52- vision_config .update (vision_config ['width' ]['clip-l-14-224' ])
53- vision_config ['hidden_size' ] = vision_config ['width' ]
54- vision_config ['num_heads' ] = vision_config ['heads' ]
55- vision_config ['intermediate_size' ] = vision_config ['heads' ] * 4
56+ if vision_config ['width' ].get ('clip-l-14-224' ) is not None :
57+ vision_config .update (vision_config ['width' ]['clip-l-14-224' ])
58+ if isinstance (vision_config ['width' ], int ):
59+ vision_config ['hidden_size' ] = vision_config ['width' ]
60+ if vision_config .get ('heads' ) is not None :
61+ vision_config ['num_heads' ] = vision_config ['heads' ]
62+ vision_config ['intermediate_size' ] = vision_config ['heads' ] * 4
5663
5764 return vision_config
5865
5966 def tensor_force_quant (self , name , new_name , bid , n_dims ):
60- if ".embeddings." in name or 'pos_embed' in name :
61- return gguf .GGMLQuantizationType .F32
62- if ".rel_pos_h" in name or '.rel_pos_w' in name :
63- return gguf .GGMLQuantizationType .F32
64- if ".neck." in name or ".net_" in name :
65- return gguf .GGMLQuantizationType .F32
67+ for nq_name in ('.embeddings.' , 'pos_embed' , '.rel_pos_h' , '.rel_pos_w' , '.neck.' , '.net_' ):
68+ if nq_name in name :
69+ return gguf .GGMLQuantizationType .F32
6670 return super ().tensor_force_quant (name , new_name , bid , n_dims )
6771
72+ def modify_tensors (self , data_torch : Tensor , name : str , bid : int | None ) -> Iterable [tuple [str , Tensor ]]:
73+ if name .endswith ("view_seperator" ):
74+ data_torch = data_torch .unsqueeze (0 )
75+ yield from super ().modify_tensors (data_torch , name , bid )
76+
6877 @classmethod
6978 def filter_tensors (cls , item : tuple [str , Callable [[], Tensor ]]) -> tuple [str , Callable [[], Tensor ]] | None :
7079 name , gen = item
@@ -81,6 +90,33 @@ def filter_tensors(cls, item: tuple[str, Callable[[], Tensor]]) -> tuple[str, Ca
8190 return super ().filter_tensors ((name , gen ))
8291
8392
93+ @ModelBase .register ("DeepseekOCR2ForCausalLM" )
94+ class DeepseekOCR2VisionModel (DeepseekOCRVisionModel ):
95+ def __init__ (self , * args , ** kwargs ):
96+ super ().__init__ (* args , ** kwargs )
97+ self .clip_projector_type = gguf .VisionProjectorType .DEEPSEEKOCR2
98+
99+ def set_gguf_parameters (self ):
100+ # the vision tower's qwen2 encoder is built from fixed defaults,
101+ # see build_qwen2_decoder_as_encoder() in deepencoderv2.py
102+ if self .hparams .get ("patch_size" ) is None :
103+ self .hparams ["patch_size" ] = 16
104+ if self .hparams .get ("intermediate_size" ) is None :
105+ self .hparams ["intermediate_size" ] = 4864
106+ if self .hparams .get ("num_attention_heads" ) is None :
107+ self .hparams ["num_attention_heads" ] = 14
108+ super ().set_gguf_parameters ()
109+ # qwen2 encoder is GQA: 14 Q heads, 2 KV heads
110+ self .gguf_writer .add_vision_head_count_kv (2 )
111+
112+ def get_vision_config (self ) -> dict [str , Any ]:
113+ vision_config = super ().get_vision_config ()
114+ vision_config ['hidden_size' ] = vision_config ['width' ]['qwen2-0-5b' ]['dim' ]
115+ if vision_config .get ('layers' ) is None :
116+ vision_config ['layers' ] = 24
117+ return vision_config
118+
119+
84120@ModelBase .register ("DeepseekForCausalLM" )
85121class DeepseekModel (TextModel ):
86122 model_arch = gguf .MODEL_ARCH .DEEPSEEK
@@ -188,13 +224,21 @@ def __init__(self, *args, **kwargs):
188224 self .origin_hf_arch = hparams .get ('architectures' , [None ])[0 ]
189225
190226 # special handling for Deepseek OCR
191- if self .origin_hf_arch == "DeepseekOCRForCausalLM" :
227+ if self .origin_hf_arch in ( "DeepseekOCRForCausalLM" , "DeepseekOCR2ForCausalLM" ) :
192228 self .model_arch = gguf .MODEL_ARCH .DEEPSEEK2OCR
193229 self .gguf_writer .arch = gguf .MODEL_ARCH_NAMES [self .model_arch ]
194230 self .gguf_writer .add_architecture ()
195231 # default jinja template
196232 self .gguf_writer .add_chat_template ("{% for m in messages %}{{m['content']}}{% endfor %}" )
197233
234+ @classmethod
235+ def filter_tensors (cls , item : tuple [str , Callable [[], Tensor ]]) -> tuple [str , Callable [[], Tensor ]] | None :
236+ name , _ = item
237+ # DeepSeek-OCR vision encoder (SAM + DeepSeek-OCR-2 qwen2 tower)
238+ if "sam_model" in name or "qwen2_model" in name :
239+ return None
240+ return super ().filter_tensors (item )
241+
198242 def set_vocab (self ):
199243 try :
200244 self ._set_vocab_gpt2 ()
0 commit comments