@@ -96,6 +96,8 @@ ggml_tensor * clip_graph_deepseekocr::build_sam(ggml_tensor * inp_raw) {
9696 const int n_heads = hparams.sam_n_head ;
9797 const int d_heads = n_embd / n_heads;
9898 const int window = hparams.attn_window_size ;
99+ // SAM stage runs its layernorms at 1e-6
100+ const float sam_eps = 1e-6f ;
99101
100102 ggml_tensor * inpL;
101103
@@ -134,7 +136,7 @@ ggml_tensor * clip_graph_deepseekocr::build_sam(ggml_tensor * inp_raw) {
134136 ggml_tensor * shortcut = cur;
135137
136138 // layernorm1
137- cur = build_norm (cur, layer.ln_1_w , layer.ln_1_b , NORM_TYPE_NORMAL , eps , il);
139+ cur = build_norm (cur, layer.ln_1_w , layer.ln_1_b , NORM_TYPE_NORMAL , sam_eps , il);
138140
139141 const int64_t w0 = cur->ne [1 ];
140142 const int64_t h0 = cur->ne [2 ];
@@ -214,7 +216,7 @@ ggml_tensor * clip_graph_deepseekocr::build_sam(ggml_tensor * inp_raw) {
214216 ggml_tensor * inpFF = cur;
215217
216218 // layernorm2
217- cur = build_norm (inpFF, layer.ln_2_w , layer.ln_2_b , NORM_TYPE_NORMAL , eps , il);
219+ cur = build_norm (inpFF, layer.ln_2_w , layer.ln_2_b , NORM_TYPE_NORMAL , sam_eps , il);
218220
219221 // ffn
220222 cur = build_ffn (cur, layer.ff_up_w , layer.ff_up_b , nullptr , nullptr , layer.ff_down_w , layer.ff_down_b ,
@@ -229,12 +231,12 @@ ggml_tensor * clip_graph_deepseekocr::build_sam(ggml_tensor * inp_raw) {
229231
230232 cur = ggml_conv_2d (ctx0, model.neck_0_w , cur, 1 , 1 , 0 , 0 , 1 , 1 );
231233 cur = ggml_cont (ctx0, ggml_permute (ctx0, cur, 1 , 2 , 0 , 3 ));
232- cur = build_norm (cur, model.neck_1_w , model.neck_1_b , NORM_TYPE_NORMAL , hparams. eps , -1 );
234+ cur = build_norm (cur, model.neck_1_w , model.neck_1_b , NORM_TYPE_NORMAL , sam_eps , -1 );
233235 cur = ggml_cont (ctx0, ggml_permute (ctx0, cur, 2 , 0 , 1 , 3 ));
234236
235237 cur = ggml_conv_2d (ctx0, model.neck_2_w , cur, 1 , 1 , 1 , 1 , 1 , 1 );
236238 cur = ggml_cont (ctx0, ggml_permute (ctx0, cur, 1 , 2 , 0 , 3 ));
237- cur = build_norm (cur, model.neck_3_w , model.neck_3_b , NORM_TYPE_NORMAL , hparams. eps , -1 );
239+ cur = build_norm (cur, model.neck_3_w , model.neck_3_b , NORM_TYPE_NORMAL , sam_eps , -1 );
238240 cur = ggml_cont (ctx0, ggml_permute (ctx0, cur, 2 , 0 , 1 , 3 ));
239241
240242 cur = ggml_conv_2d (ctx0, model.net_2 , cur, 2 , 2 , 1 , 1 , 1 , 1 );
@@ -248,16 +250,50 @@ ggml_tensor * clip_graph_deepseekocr::build_sam(ggml_tensor * inp_raw) {
248250ggml_cgraph * clip_graph_deepseekocr::build () {
249251 // patch embedding
250252 ggml_tensor * inp_raw = build_inp_raw ();
253+
254+ bool is_overview = img.add_viewsep ;
255+ int n_tiles_per_row = 0 ;
256+
257+ // note: we expect either a batch of rows or a batch of overviews, but not a mix of both
258+
259+ if (!is_overview) {
260+ // handle the case where we have a batch of rows
261+ // sanity check
262+ for (auto & entry : img_batch->entries ) {
263+ if (entry.add_viewsep ) {
264+ throw std::runtime_error (" DeepSeek-OCR: mixed overview and non-overview images in batch" );
265+ }
266+ if (entry.nx () != img.nx () || entry.ny () != img.ny ()) {
267+ throw std::runtime_error (" DeepSeek-OCR: mixed image sizes in batch" );
268+ }
269+ }
270+
271+ GGML_ASSERT (img.ny () >= img.nx ());
272+ GGML_ASSERT (img.ny () % img.nx () == 0 );
273+ n_tiles_per_row = img.ny () / img.nx ();
274+
275+ // input shape: [tile_size, tile_size * n_tiles_per_row, 3]
276+ // we want to reshape it to [tile_size, tile_size, 3, n_tiles_per_row]
277+ inp_raw = ggml_reshape_4d (ctx0, inp_raw, img.nx (), img.nx (), n_tiles_per_row, 3 );
278+ inp_raw = ggml_cont (ctx0, ggml_permute (ctx0, inp_raw, 0 , 1 , 3 , 2 ));
279+ }
280+
251281 ggml_tensor * sam_out = build_sam (inp_raw);
252282
283+ if (!is_overview) {
284+ n_batch = n_tiles_per_row;
285+ }
286+
253287 const int clip_n_patches = sam_out->ne [0 ] * sam_out->ne [1 ];
254288
255289 ggml_tensor * clip_out;
256290 // Building DS-OCR CLIP
257291 {
258292 ggml_tensor * inp;
259293
260- inp = ggml_reshape_2d (ctx0, sam_out, clip_n_patches, sam_out->ne [2 ]);
294+ // sam_out: [patch_h, patch_w, n_embd, n_batch]
295+ // -> [n_embd, clip_n_patches, n_batch]
296+ inp = ggml_reshape_3d (ctx0, sam_out, clip_n_patches, sam_out->ne [2 ], sam_out->ne [3 ]);
261297 inp = ggml_cont (ctx0, ggml_permute (ctx0, inp, 1 , 0 , 2 , 3 ));
262298
263299 ggml_tensor * new_pos_embd = model.position_embeddings ;
@@ -281,8 +317,11 @@ ggml_cgraph * clip_graph_deepseekocr::build() {
281317 n_pos = tgt_size * tgt_size + 1 ;
282318 }
283319
284- // add CLS token
285- inp = ggml_concat (ctx0, model.class_embedding , inp, 1 );
320+ // add CLS token per batch item
321+ // inp: [n_embd, clip_n_patches, n_batch]
322+ // class_embedding: [n_embd] -> [n_embd, 1, n_batch]
323+ ggml_tensor * cls_embd = ggml_repeat_4d (ctx0, model.class_embedding , n_embd, 1 , n_batch, 1 );
324+ inp = ggml_concat (ctx0, cls_embd, inp, 1 );
286325
287326 // for selecting learned pos embd, used by ViT
288327 ggml_tensor * positions = ggml_cast (ctx0, ggml_arange (ctx0, 0 , n_pos, 1 ), GGML_TYPE_I32 );
@@ -294,25 +333,56 @@ ggml_cgraph * clip_graph_deepseekocr::build() {
294333 clip_out = cur;
295334 }
296335
336+ // sam_out: [patch_h, patch_w, n_embd, n_batch]
337+ // -> [n_embd, clip_n_patches, n_batch]
297338 sam_out = ggml_cont (ctx0, ggml_permute (ctx0, sam_out, 1 , 2 , 0 , 3 ));
298- sam_out = ggml_reshape_2d (ctx0, sam_out, sam_out->ne [0 ], clip_n_patches);
299- clip_out = ggml_view_2d (ctx0, clip_out, n_embd, clip_n_patches, clip_out->nb [1 ], clip_out->nb [1 ]);
339+ sam_out = ggml_reshape_3d (ctx0, sam_out, sam_out->ne [0 ], clip_n_patches, n_batch);
340+
341+ // clip_out: [n_embd, n_pos, n_batch] where n_pos = clip_n_patches + 1 (CLS)
342+ // strip CLS token: skip first position, view only the patch tokens
343+ clip_out = ggml_view_3d (ctx0, clip_out, n_embd, clip_n_patches, n_batch,
344+ clip_out->nb [1 ], clip_out->nb [2 ], clip_out->nb [1 ]);
300345
301346 ggml_tensor * cur;
302347 cur = ggml_concat (ctx0, clip_out, sam_out, 0 );
303348 cur = ggml_mul_mat (ctx0, model.mm_fc_w , cur);
304349 cur = ggml_add (ctx0, cur, model.mm_fc_b );
305350
306- const auto h = static_cast <int >(std::sqrt (static_cast <float >(cur->ne [1 ])));
307- const auto w = h;
308- const auto n_dim = cur->ne [0 ];
351+ if (is_overview) {
352+ // global view: weave one newline per row + trailing view separator
353+ const auto h = static_cast <int >(std::sqrt (static_cast <float >(cur->ne [1 ])));
354+ const auto w = h;
355+ const auto n_dim = cur->ne [0 ];
356+
357+ ggml_tensor * imgnl = ggml_repeat_4d (ctx0, model.image_newline , n_dim, 1 , h, 1 );
358+ cur = ggml_reshape_3d (ctx0, cur, n_dim, w, h);
359+ cur = ggml_reshape_2d (ctx0, ggml_concat (ctx0, cur, imgnl, 1 ), n_dim, (w + 1 ) * h);
360+ cur = ggml_concat (ctx0, cur, model.view_seperator , 1 ); // (n_dim, h*(w+1) + 1)
361+ } else {
362+ // tile row: interleave tiles within each row, add newline per row
363+ const int grid_x = static_cast <int >(std::sqrt (static_cast <float >(clip_n_patches)));
364+ const int grid_y = grid_x;
365+ const auto n_dim = cur->ne [0 ];
309366
310- ggml_tensor * imgnl;
367+ // (n_dim, clip_n_patches, n_batch) -> (n_dim, grid_x, grid_y, n_batch)
368+ cur = ggml_reshape_4d (ctx0, cur, n_dim, grid_x, grid_y, n_batch);
311369
312- imgnl = ggml_repeat_4d (ctx0, model.image_newline , n_dim, 1 , h, 1 );
313- cur = ggml_reshape_3d (ctx0, cur, n_dim, w, h);
314- cur = ggml_reshape_2d (ctx0, ggml_concat (ctx0, cur, imgnl, 1 ), n_dim, (w + 1 ) * h);
315- cur = ggml_concat (ctx0, cur, model.view_seperator , 1 ); // (n_dim, h*(w+1) + 1)
370+ // tiles: re-order from A.row0 A.row1 B.row0 B.row1 ...
371+ // to A.row0 B.row0 A.row1 B.row1 ...
372+ // then add nl: A.row0 B.row0 [nl] A.row1 B.row1 [nl] ...
373+ // interleave tiles: (n_dim, grid_x, grid_y, n_batch) -> (n_dim, grid_x, n_batch, grid_y)
374+ cur = ggml_cont (ctx0, ggml_permute (ctx0, cur, 0 , 1 , 3 , 2 ));
375+
376+ // merge: (n_dim, grid_x, n_batch, grid_y) -> (n_dim, grid_x*n_batch, grid_y, 1)
377+ cur = ggml_reshape_4d (ctx0, cur, n_dim, grid_x * n_batch, grid_y, 1 );
378+
379+ // append newline per row: (n_dim, grid_x*n_batch+1, grid_y, 1)
380+ ggml_tensor * imgnl = ggml_repeat_4d (ctx0, model.image_newline , n_dim, 1 , grid_y, 1 );
381+ cur = ggml_concat (ctx0, cur, imgnl, 1 );
382+
383+ // flatten: (n_dim, (grid_x*n_batch+1)*grid_y)
384+ cur = ggml_reshape_2d (ctx0, cur, n_dim, (grid_x * n_batch + 1 ) * grid_y);
385+ }
316386
317387 cb (cur, " dsocr_output" , -1 );
318388
0 commit comments