char-fork/llama.cpp
git clone https://git.t4t.associates/char-fork/llama.cpp
de8656bd9
char/aliceai-t5-moe
1#pragma once 2 3#include "ggml.h" 4#include "clip-model.h" 5 6#include <vector> 7#include <string> 8 9#define MTMD_INTERNAL_HEADER 10 11struct mtmd_image_preproc_out { 12std ::vector < clip_image_f32 > entries ; 13// grid size is required for llava-uhd style models 14 15clip_image_f32 overview ;// overview image (downscaled image) 16int grid_x = 0 ; 17int grid_y = 0 ; 18 19void append (const clip_hparams & hparams ,const clip_image_u8 & img ,bool normalized = true); 20void append (const clip_hparams & hparams ,const std ::vector < clip_image_u8 > & imgs ,bool normalized = true); 21void append (const clip_hparams & hparams ,clip_image_f32 & img ,bool normalized = true); 22 23void append_overview (const clip_hparams & hparams ,const clip_image_u8 & img ,bool normalized = true); 24bool has_overview ()const { 25return overview .nx ()> 0 || overview .ny ()> 0 ; 26 } 27}; 28 29// base class, models must inherit from this class 30struct mtmd_image_preprocessor { 31const clip_hparams & hparams ; 32 33mtmd_image_preprocessor (const clip_ctx * ctx ): hparams ( * clip_get_hparams ( ctx )) {} 34 35virtual ~ mtmd_image_preprocessor () = default ; 36virtual mtmd_image_preproc_out preprocess ( const clip_image_u8 & img ) const = 0 ; 37}; 38 39/** 40* implementation of LLaVA-UHD: 41* - https://arxiv.org/pdf/2403.11703 42* - https://github.com/thunlp/LLaVA-UHD 43* - https://github.com/thunlp/LLaVA-UHD/blob/302301bc2175f7e717fb8548516188e89f649753/llava_uhd/train/llava-uhd/slice_logic.py#L118 44* 45* overview: 46* - an image always have a single overview (downscaled image) 47* - an image can have 0 or multiple slices, depending on the image size 48* - each slice can then be considered as a separate image 49* 50* note: the term "slice" and "tile" are used interchangeably 51* 52* for example: 53* 54* [overview] --> [slice 1] --> [slice 2] 55* | | 56* +--> [slice 3] --> [slice 4] 57* 58* NOTE: for the ordering of overview, set "ov_img_first" on the mtmd_context 59*/ 60struct mtmd_image_preprocessor_llava_uhd : mtmd_image_preprocessor { 61mtmd_image_preprocessor_llava_uhd ( const clip_ctx * ctx ) : mtmd_image_preprocessor ( ctx ) {} 62mtmd_image_preproc_out preprocess ( const clip_image_u8 & img ) const override ; 63 64struct slice_coordinates { 65int x; 66int y; 67clip_image_size size; 68}; 69 70struct slice_instructions { 71clip_image_size overview_size; // size of downscaled image 72clip_image_size refined_size; // size of image right before slicing (must be multiple of slice size) 73clip_image_size grid_size; // grid_size.width * grid_size.height = number of slices 74std ::vector < slice_coordinates > slices; 75}; 76 77virtual slice_instructions get_slice_instructions ( const clip_image_size & original_size ) const ; 78 79struct slice_output { 80clip_image_u8 overview ; 81std :: vector < clip_image_u8 > slices ; 82}; 83slice_output slice_image ( const clip_image_u8 & img, const slice_instructions & inst) const; 84 85protected : 86clip_image_size get_best_resize ( const clip_image_size & original_size, int scale_resolution, int patch_size, bool allow_upscale = false) const ; 87 88/** 89* Selects the best resolution from a list of possible resolutions based on the original size. 90* 91* For example, when given a list of resolutions: 92* - 100x100 93* - 200x100 94* - 100x200 95* - 200x200 96* 97* And an input image of size 111x200, then 100x200 is the best fit (least wasted resolution). 98* 99* @param original_size The original size of the image 100* @param possible_resolutions A list of possible resolutions 101* @return The best fit resolution 102*/ 103clip_image_size select_best_resolution ( const clip_image_size & original_size, const std ::vector < clip_image_size > & possible_resolutions) const; 104 105private : 106clip_image_size resize_maintain_aspect_ratio ( const clip_image_size & orig, const clip_image_size & target_max) const; 107int ensure_divide ( int length, int patch_size) const; 108clip_image_size get_refine_size ( const clip_image_size & original_size, const clip_image_size & grid, int scale_resolution, int patch_size, bool allow_upscale = false) const ; 109clip_image_size get_best_grid ( const int max_slice_nums, const int multiple, const float log_ratio) const; 110}; 111 112// downscale or upscale the input image to fixed size 113struct mtmd_image_preprocessor_fixed_size : mtmd_image_preprocessor { 114mtmd_image_preprocessor_fixed_size( const clip_ctx * ctx) : mtmd_image_preprocessor ( ctx ) {} 115mtmd_image_preproc_out preprocess ( const clip_image_u8 & img) const override; 116}; 117 118// resize image to multiple of patch_size*n_merge, while preserving aspect ratio 119// if image_resize_pad is true, the resized image will be padded, otherwise it will be either stretched or center-cropped depending on image_resize_pad 120// this is used by models with native support for dynamic image size, for example: Qwen-VL, Pixtral, Kimi-VL, etc 121struct mtmd_image_preprocessor_dyn_size : mtmd_image_preprocessor { 122mtmd_image_preprocessor_dyn_size( const clip_ctx * ctx) : mtmd_image_preprocessor ( ctx ) {} 123mtmd_image_preproc_out preprocess ( const clip_image_u8 & img) const override; 124}; 125 126// similar to mtmd_image_preprocessor_dyn_size, but resize the image to have longest edge equal to hparams.image_longest_edge, while preserving aspect ratio 127struct mtmd_image_preprocessor_longest_edge : mtmd_image_preprocessor { 128mtmd_image_preprocessor_longest_edge( const clip_ctx * ctx) : mtmd_image_preprocessor ( ctx ) {} 129mtmd_image_preproc_out preprocess ( const clip_image_u8 & img) const override; 130}; 131 132// ref: inference/image_processor.py in the HF repo (DeepSeek-V4-Flash-Vision) 133struct mtmd_image_preprocessor_deepseek4v : mtmd_image_preprocessor { 134mtmd_image_preprocessor_deepseek4v( const clip_ctx * ctx) : mtmd_image_preprocessor ( ctx ) {} 135mtmd_image_preproc_out preprocess ( const clip_image_u8 & img) const override; 136 137private : 138struct grid_info { 139int n_llm_h ; 140int n_llm_w ; 141int n_tokens ; // token count of the block (incl. newline/pad rows and start/end, excl. lead pads) 142}; 143static grid_info grid_tokens ( int best_height, int best_width, int patch_size, int r); 144static void solve_resize_ratio ( int height, int width, int p, int r, int max_n_token, int & best_height, int & best_width); 145static void safe_resize ( int height, int width, int & best_height, int & best_width, int p, int r, int max_n_token); 146}; 147 148// custom llava-uhd slicing logic for MiniCPM-V 149struct mtmd_image_preprocessor_minicpmv : mtmd_image_preprocessor_llava_uhd { 150using mtmd_image_preprocessor_llava_uhd::mtmd_image_preprocessor_llava_uhd; 151slice_instructions get_slice_instructions ( const clip_image_size & original_size) const override; 152}; 153 154// custom llava-uhd slicing logic for LFM2 155// ref: https://github.com/huggingface/transformers/blob/v5.1.0/src/transformers/models/lfm2_vl/image_processing_lfm2_vl_fast.py 156struct mtmd_image_preprocessor_lfm2 : mtmd_image_preprocessor_llava_uhd { 157// ref: https://huggingface.co/LiquidAI/LFM2.5-VL-1.6B/blob/main/processor_config.json 158static constexpr int min_tiles = 2 ; 159static constexpr int max_tiles = 10 ; 160static constexpr float max_pixels_tolerance = 2.0f ; 161static constexpr int tile_size = 512 ; 162 163using mtmd_image_preprocessor_llava_uhd::mtmd_image_preprocessor_llava_uhd; 164mtmd_image_preproc_out preprocess ( const clip_image_u8 & img) const override; 165slice_instructions get_slice_instructions ( const clip_image_size & original_size) const override; 166 167static bool should_tile ( const clip_hparams & hparams, const clip_image_size & original_size); 168 169private : 170clip_image_size find_closest_aspect_ratio ( 171float aspect_ratio, 172const std ::vector < clip_image_size > & target_ratios, 173int width, int height) const; 174std::vector < clip_image_size > get_target_ratios () const; 175clip_image_size get_grid_layout ( int height, int width) const; 176}; 177 178struct mtmd_image_preprocessor_idefics3 : mtmd_image_preprocessor_llava_uhd { 179mtmd_image_preprocessor_idefics3( const clip_ctx * ctx) : mtmd_image_preprocessor_llava_uhd ( ctx ) {} 180mtmd_image_preproc_out preprocess ( const clip_image_u8 & img) const override; 181}; 182 183struct mtmd_image_preprocessor_internvl : mtmd_image_preprocessor_llava_uhd { 184mtmd_image_preprocessor_internvl( const clip_ctx * ctx) : mtmd_image_preprocessor_llava_uhd ( ctx ) {} 185mtmd_image_preproc_out preprocess ( const clip_image_u8 & img) const override; 186}; 187 188// DeepSeek-OCR (v1/v2) global view + optional local tile grid 189struct mtmd_image_preprocessor_deepseekocr : mtmd_image_preprocessor { 190mtmd_image_preprocessor_deepseekocr( const clip_ctx * ctx) 191: mtmd_image_preprocessor ( ctx ), 192fuse_row (clip_get_projector_type( ctx ) == PROJECTOR_TYPE_DEEPSEEKOCR ), 193base_size ( hparams .image_size), 194tile_size ( hparams .preproc_tile_size), 195min_tiles ( hparams .preproc_min_tiles), 196max_tiles ( hparams .preproc_max_tiles) {} 197mtmd_image_preproc_out preprocess ( const clip_image_u8 & img) const override; 198 199private: 200bool fuse_row; // v1 fuses a tile-row into one image; v2 keeps tiles separate 201int base_size; // global view 202int tile_size; // each tile 203int min_tiles; 204int max_tiles; 205 206std ::vector < clip_image_size > get_target_ratios () const; 207clip_image_size find_closest_aspect_ratio ( 208float aspect_ratio, 209const std ::vector < clip_image_size > & target_ratios, 210int width, int height) const; 211}; 212 213// custom image preprocessing for Step3VL 214// ref: https://huggingface.co/stepfun-ai/Step3-VL-10B/blob/main/processing_step3.py 215struct mtmd_image_preprocessor_step3vl : mtmd_image_preprocessor_llava_uhd { 216mtmd_image_preprocessor_step3vl( const clip_ctx * ctx) : mtmd_image_preprocessor_llava_uhd ( ctx ) {} 217mtmd_image_preproc_out preprocess ( const clip_image_u8 & img) const override; 218static slice_instructions build_slice_instructions ( const clip_hparams & params, const clip_image_size & prepared_size); 219 220private : 221static constexpr int default_image_longest_edge = 3024 ; 222static constexpr int default_image_crop_size = 504 ; 223static constexpr float small_aspect_ratio_limit = 1.5f ; 224static constexpr float wide_aspect_ratio_limit = 4.0f ; 225static constexpr float crop_rounding_threshold = 0.2f ; 226 227void img_u8_resize_bilinear_to_f32 ( 228const clip_image_u8 & src, 229clip_image_f32 & dst, 230int target_width, 231int target_height, 232const float mean[ 3 ], 233const float std[ 3 ]) const; 234static int get_image_longest_edge ( const clip_hparams & params); 235static int determine_window_size ( const clip_hparams & params, int longer, int shorter); 236static int calc_crop_extent ( int length, int window_size); 237static std ::vector < int > calc_grid ( int length, int window_size); 238static clip_image_u8 prepare_image ( const clip_image_u8 & img, const clip_hparams & params); 239static clip_image_u8 crop_with_black_padding ( const clip_image_u8 & image, int x, int y, int w, int h); 240}; 241 242struct mtmd_image_preprocessor_youtuvl : mtmd_image_preprocessor { 243mtmd_image_preprocessor_youtuvl( const clip_ctx * ctx) : mtmd_image_preprocessor ( ctx ) {} 244mtmd_image_preproc_out preprocess ( const clip_image_u8 & img) const override; 245}; 246 247// llava-next "anyres": stacks the overview and all tiles into one image, assembled by clip in a single graph 248struct mtmd_image_preprocessor_granite : mtmd_image_preprocessor_llava_uhd { 249mtmd_image_preprocessor_granite( const clip_ctx * ctx) : mtmd_image_preprocessor_llava_uhd ( ctx ) {} 250mtmd_image_preproc_out preprocess ( const clip_image_u8 & img) const override; 251}; 252 253// pick the patch grid closest to the input aspect ratio under the per-image token cap, stretch-resize. 254struct mtmd_image_preprocessor_muse_glimmer : mtmd_image_preprocessor { 255mtmd_image_preprocessor_muse_glimmer( const clip_ctx * ctx) : mtmd_image_preprocessor ( ctx ) {} 256mtmd_image_preproc_out preprocess ( const clip_image_u8 & img) const override ; 257};