Views
No views yet
Nanonets-OCR2-3B is based on Qwen2.5-VL-3B, which ususally performs better when quantization approaches keep the vision encoder in full precision.
My usecase involves dense table extraction; for now, I'll hypothesize Nanonet finetuning takes "pressure" off the language model component so keeping vision encoder in higher precision retains more understanding of vision tokens, which represent information differently than text tokens.
To test this, I used instructions which do not deviate so much from training data, which Nanonets reccomends in their examples.In the first phase, only the Vision Transformer (ViT) is trained to improve its alignment with the language model, laying a solid foundation for multimodal understanding. The primary data sources during this phase include image captions, visual knowledge, and OCR data. These datasets are carefully selected to foster ViT’s ability to extract meaningful visual representations that can be effectively integrated with textual information...
1from optimum.intel import OVModelForVisualCausalLM
2from optimum.intel import OVPipelineQuantizationConfig, OVQuantizationConfig, OVWeightQuantizationConfig
3
4model_id = "nanonets/Nanonets-OCR2-3B"
5model = OVModelForVisualCausalLM.from_pretrained(
6 model_id,
7 export=True,
8 trust_remote_code=True,
9 quantization_config=OVPipelineQuantizationConfig(
10 quantization_configs={
11 "lm_model": OVQuantizationConfig(bits=8),
12 "text_embeddings_model": OVWeightQuantizationConfig(bits=4),
13 },
14 dataset="contextual",
15 trust_remote_code=True,
16 )
17)
18model.save_pretrained("Nanonets-OCR2-3B-LM-INT4_ASYM-VE-FP16-ov")1import time
2from PIL import Image
3from transformers import AutoProcessor, TextStreamer
4from optimum.intel.openvino import OVModelForVisualCausalLM
5
6
7model_id = "/home/ecomm/Desktop/lochinvar_nanonets/Nanonets-OCR2-3B-LM-INT4_ASYM-VE-FP16-ov"
8
9print("Loading model...")
10start_load_time = time.time()
11model = OVModelForVisualCausalLM.from_pretrained(model_id, export=False, device="CPU")
12processor = AutoProcessor.from_pretrained(model_id)
13
14image_path = r"/home/ecomm/Desktop/lochinvar_nanonets/OpenArc-1.0.6/src/tests/dedication.png"
15image = Image.open(image_path)
16image = image.convert("RGB")
17
18conversation = [
19 {
20 "role": "user",
21 "content": [
22 {
23 "type": "image"
24 },
25 {"type": "text", "text": "Describe this image."},
26 ],
27 }
28]
29
30# Instead, just use your text prompt directly:
31text_prompt = "Convert this image to markdown code block"
32
33# Preprocess the inputs using model.preprocess_inputs
34inputs = model.preprocess_inputs(text=text_prompt, image=image, processor=processor)
35
36# Print number of tokens
37input_token_count = len(inputs["input_ids"][0])
38print(f"Input token length: {input_token_count}")
39
40# Inference: Generation of the output with performance metrics
41start_time = time.time()
42streamer = TextStreamer(processor.tokenizer, skip_prompt=True, skip_special_tokens=True)
43output_ids = model.generate(**inputs, max_new_tokens=1024, do_sample=True, streamer=streamer)
44
45generated_ids = [output_ids[len(input_ids) :] for input_ids, output_ids in zip(inputs["input_ids"], output_ids)]
46output_text = processor.batch_decode(generated_ids, clean_up_tokenization_spaces=True, skip_special_tokens=True)
47
48num_tokens_generated = len(generated_ids[0])
49load_time = time.time() - start_load_time
50generation_time = time.time() - start_time
51tokens_per_second = num_tokens_generated / generation_time
52average_token_latency = generation_time / num_tokens_generated
53
54print("\nPerformance Report:")
55print("-"*50)
56print(f"Input Tokens : {input_token_count:>9}")
57print(f"Generated Tokens : {num_tokens_generated:>9}")
58print(f"Model Load Time : {load_time:>9.2f} sec")
59print(f"Generation Time : {generation_time:>9.2f} sec")
60print(f"Throughput : {tokens_per_second:>9.2f} t/s")
61print(f"Avg Latency/Token : {average_token_latency:>9.3f} sec")
62
63print(output_text)VLMPipline or ContinuousBatchingPipeline on CPU. For now, it might not work in OpenArc.