1use anyhow::{Context, Result};
22use serde::Deserialize;
23use std::path::Path;
24
25pub const LN_EPS: f32 = 1e-5;
27
28pub const IMAGE_MEAN: [f32; 3] = [0.485, 0.456, 0.406];
30pub const IMAGE_STD: [f32; 3] = [0.229, 0.224, 0.225];
31
32#[derive(Debug, Clone)]
34pub struct Florence2VisionConfig {
35 pub dim_embed: Vec<usize>,
36 pub depths: Vec<usize>,
37 pub num_heads: Vec<usize>,
38 pub num_groups: Vec<usize>,
39 pub patch_size: Vec<usize>,
40 pub patch_stride: Vec<usize>,
41 pub patch_padding: Vec<usize>,
42 pub patch_prenorm: Vec<bool>,
43 pub window_size: usize,
44 pub projection_dim: usize,
45 pub mlp_ratio: f64,
46 pub image_pos_embed_max: usize,
48 pub visual_temporal_max: usize,
50 pub image_feature_source: Vec<String>,
52}
53
54impl Florence2VisionConfig {
55 pub fn num_stages(&self) -> usize {
56 self.dim_embed.len()
57 }
58 pub fn dim_out(&self) -> usize {
60 *self.dim_embed.last().unwrap()
61 }
62}
63
64#[derive(Debug, Clone)]
66pub struct Florence2TextConfig {
67 pub vocab_size: usize,
68 pub d_model: usize,
69 pub encoder_layers: usize,
70 pub decoder_layers: usize,
71 pub encoder_attention_heads: usize,
72 pub decoder_attention_heads: usize,
73 pub encoder_ffn_dim: usize,
74 pub decoder_ffn_dim: usize,
75 pub max_position_embeddings: usize,
76 pub scale_embedding: bool,
77 pub bos_token_id: u32,
78 pub eos_token_id: u32,
79 pub pad_token_id: u32,
80 pub decoder_start_token_id: u32,
81 pub forced_bos_token_id: u32,
82 pub forced_eos_token_id: u32,
83 pub num_beams: usize,
84 pub no_repeat_ngram_size: usize,
85}
86
87impl Florence2TextConfig {
88 pub const POS_OFFSET: usize = 2;
90 pub fn enc_head_dim(&self) -> usize {
91 self.d_model / self.encoder_attention_heads
92 }
93 pub fn dec_head_dim(&self) -> usize {
94 self.d_model / self.decoder_attention_heads
95 }
96}
97
98#[derive(Debug, Clone)]
100pub struct Florence2Config {
101 pub vision: Florence2VisionConfig,
102 pub text: Florence2TextConfig,
103 pub vocab_size: usize,
104 pub projection_dim: usize,
105}
106
107impl Florence2Config {
108 pub fn large() -> Self {
110 Self {
111 vision: Florence2VisionConfig {
112 dim_embed: vec![256, 512, 1024, 2048],
113 depths: vec![1, 1, 9, 1],
114 num_heads: vec![8, 16, 32, 64],
115 num_groups: vec![8, 16, 32, 64],
116 patch_size: vec![7, 3, 3, 3],
117 patch_stride: vec![4, 2, 2, 2],
118 patch_padding: vec![3, 1, 1, 1],
119 patch_prenorm: vec![false, true, true, true],
120 window_size: 12,
121 projection_dim: 1024,
122 mlp_ratio: 4.0,
123 image_pos_embed_max: 50,
124 visual_temporal_max: 100,
125 image_feature_source: vec!["spatial_avg_pool".into(), "temporal_avg_pool".into()],
126 },
127 text: Florence2TextConfig {
128 vocab_size: 51289,
129 d_model: 1024,
130 encoder_layers: 12,
131 decoder_layers: 12,
132 encoder_attention_heads: 16,
133 decoder_attention_heads: 16,
134 encoder_ffn_dim: 4096,
135 decoder_ffn_dim: 4096,
136 max_position_embeddings: 4096,
137 scale_embedding: false,
138 bos_token_id: 0,
139 eos_token_id: 2,
140 pad_token_id: 1,
141 decoder_start_token_id: 2,
142 forced_bos_token_id: 0,
143 forced_eos_token_id: 2,
144 num_beams: 3,
145 no_repeat_ngram_size: 3,
146 },
147 vocab_size: 51289,
148 projection_dim: 1024,
149 }
150 }
151
152 pub fn from_hf_config_json(path: &Path) -> Result<Self> {
154 let raw = std::fs::read_to_string(path)
155 .with_context(|| format!("read florence2 config {}", path.display()))?;
156 let hf: HfConfig = serde_json::from_str(&raw)
157 .with_context(|| format!("parse florence2 config {}", path.display()))?;
158 Ok(hf.into_config())
159 }
160
161 pub fn embed_scale(&self) -> f32 {
163 if self.text.scale_embedding {
164 (self.text.d_model as f32).sqrt()
165 } else {
166 1.0
167 }
168 }
169}
170
171#[derive(Debug, Deserialize)]
174struct HfConfig {
175 vocab_size: usize,
176 projection_dim: usize,
177 text_config: HfTextConfig,
178 vision_config: HfVisionConfig,
179}
180
181#[derive(Debug, Deserialize)]
182struct HfTextConfig {
183 vocab_size: usize,
184 d_model: usize,
185 encoder_layers: usize,
186 decoder_layers: usize,
187 encoder_attention_heads: usize,
188 decoder_attention_heads: usize,
189 encoder_ffn_dim: usize,
190 decoder_ffn_dim: usize,
191 max_position_embeddings: usize,
192 #[serde(default)]
193 scale_embedding: bool,
194 bos_token_id: u32,
195 eos_token_id: u32,
196 pad_token_id: u32,
197 decoder_start_token_id: u32,
198 forced_bos_token_id: u32,
199 forced_eos_token_id: u32,
200 #[serde(default = "default_beams")]
201 num_beams: usize,
202 #[serde(default = "default_ngram")]
203 no_repeat_ngram_size: usize,
204}
205
206fn default_beams() -> usize {
207 3
208}
209fn default_ngram() -> usize {
210 3
211}
212
213#[derive(Debug, Deserialize)]
214struct HfVisionConfig {
215 dim_embed: Vec<usize>,
216 depths: Vec<usize>,
217 num_heads: Vec<usize>,
218 num_groups: Vec<usize>,
219 patch_size: Vec<usize>,
220 patch_stride: Vec<usize>,
221 patch_padding: Vec<usize>,
222 patch_prenorm: Vec<bool>,
223 window_size: usize,
224 projection_dim: usize,
225 image_pos_embed: HfPosEmbed,
226 visual_temporal_embedding: HfTemporalEmbed,
227 image_feature_source: Vec<String>,
228}
229
230#[derive(Debug, Deserialize)]
231struct HfPosEmbed {
232 max_pos_embeddings: usize,
233}
234
235#[derive(Debug, Deserialize)]
236struct HfTemporalEmbed {
237 max_temporal_embeddings: usize,
238}
239
240impl HfConfig {
241 fn into_config(self) -> Florence2Config {
242 let v = self.vision_config;
243 let t = self.text_config;
244 Florence2Config {
245 vision: Florence2VisionConfig {
246 dim_embed: v.dim_embed,
247 depths: v.depths,
248 num_heads: v.num_heads,
249 num_groups: v.num_groups,
250 patch_size: v.patch_size,
251 patch_stride: v.patch_stride,
252 patch_padding: v.patch_padding,
253 patch_prenorm: v.patch_prenorm,
254 window_size: v.window_size,
255 projection_dim: v.projection_dim,
256 mlp_ratio: 4.0,
257 image_pos_embed_max: v.image_pos_embed.max_pos_embeddings,
258 visual_temporal_max: v.visual_temporal_embedding.max_temporal_embeddings,
259 image_feature_source: v.image_feature_source,
260 },
261 text: Florence2TextConfig {
262 vocab_size: t.vocab_size,
263 d_model: t.d_model,
264 encoder_layers: t.encoder_layers,
265 decoder_layers: t.decoder_layers,
266 encoder_attention_heads: t.encoder_attention_heads,
267 decoder_attention_heads: t.decoder_attention_heads,
268 encoder_ffn_dim: t.encoder_ffn_dim,
269 decoder_ffn_dim: t.decoder_ffn_dim,
270 max_position_embeddings: t.max_position_embeddings,
271 scale_embedding: t.scale_embedding,
272 bos_token_id: t.bos_token_id,
273 eos_token_id: t.eos_token_id,
274 pad_token_id: t.pad_token_id,
275 decoder_start_token_id: t.decoder_start_token_id,
276 forced_bos_token_id: t.forced_bos_token_id,
277 forced_eos_token_id: t.forced_eos_token_id,
278 num_beams: t.num_beams,
279 no_repeat_ngram_size: t.no_repeat_ngram_size,
280 },
281 vocab_size: self.vocab_size,
282 projection_dim: self.projection_dim,
283 }
284 }
285}
286
287pub fn task_post_processing_type(task: &str) -> &'static str {
290 match task {
291 "<OCR>" => "pure_text",
292 "<OCR_WITH_REGION>" => "ocr",
293 "<CAPTION>" => "pure_text",
294 "<DETAILED_CAPTION>" => "pure_text",
295 "<MORE_DETAILED_CAPTION>" => "pure_text",
296 "<OD>" => "description_with_bboxes",
297 "<DENSE_REGION_CAPTION>" => "description_with_bboxes",
298 "<CAPTION_TO_PHRASE_GROUNDING>" => "phrase_grounding",
299 "<REFERRING_EXPRESSION_SEGMENTATION>" => "polygons",
300 "<REGION_TO_SEGMENTATION>" => "polygons",
301 "<OPEN_VOCABULARY_DETECTION>" => "description_with_bboxes_or_polygons",
302 "<REGION_TO_CATEGORY>" => "pure_text",
303 "<REGION_TO_DESCRIPTION>" => "pure_text",
304 "<REGION_TO_OCR>" => "pure_text",
305 "<REGION_PROPOSAL>" => "bboxes",
306 _ => "pure_text",
307 }
308}
309
310pub fn construct_prompt(text: &str) -> String {
313 for (token, prompt) in TASK_PROMPTS_WITHOUT_INPUTS {
315 if text.contains(token) {
316 return prompt.to_string();
318 }
319 }
320 for (token, prompt) in TASK_PROMPTS_WITH_INPUT {
322 if text.contains(token) {
323 let input = text.replace(token, "");
324 return prompt.replace("{input}", &input);
325 }
326 }
327 text.to_string()
328}
329
330const TASK_PROMPTS_WITHOUT_INPUTS: &[(&str, &str)] = &[
331 ("<OCR>", "What is the text in the image?"),
332 (
333 "<OCR_WITH_REGION>",
334 "What is the text in the image, with regions?",
335 ),
336 ("<CAPTION>", "What does the image describe?"),
337 (
338 "<DETAILED_CAPTION>",
339 "Describe in detail what is shown in the image.",
340 ),
341 (
342 "<MORE_DETAILED_CAPTION>",
343 "Describe with a paragraph what is shown in the image.",
344 ),
345 (
346 "<OD>",
347 "Locate the objects with category name in the image.",
348 ),
349 (
350 "<DENSE_REGION_CAPTION>",
351 "Locate the objects in the image, with their descriptions.",
352 ),
353 (
354 "<REGION_PROPOSAL>",
355 "Locate the region proposals in the image.",
356 ),
357];
358
359const TASK_PROMPTS_WITH_INPUT: &[(&str, &str)] = &[
360 (
361 "<CAPTION_TO_PHRASE_GROUNDING>",
362 "Locate the phrases in the caption: {input}",
363 ),
364 (
365 "<REFERRING_EXPRESSION_SEGMENTATION>",
366 "Locate {input} in the image with mask",
367 ),
368 (
369 "<REGION_TO_SEGMENTATION>",
370 "What is the polygon mask of region {input}",
371 ),
372 (
373 "<OPEN_VOCABULARY_DETECTION>",
374 "Locate {input} in the image.",
375 ),
376 ("<REGION_TO_CATEGORY>", "What is the region {input}?"),
377 (
378 "<REGION_TO_DESCRIPTION>",
379 "What does the region {input} describe?",
380 ),
381 ("<REGION_TO_OCR>", "What text is in the region {input}?"),
382];