当前位置:   article > 正文

基于 Microsoft Phi3 视觉语言模型的文档数据提取

phi3 vision 识别图片

点击下方卡片,关注“小白玩转Python”公众号

本文使用最新版本的 Microsoft Phi3 视觉语言模型进行零样本 OCR 应用的示例,展示了如何通过将 Phi3 模型应用于相关文档图像,提取身份卡、驾驶证或健康保险卡等文档的数据。

52138cc600fbccae59eac619e4d065bf.png

Phi3 模型是 Microsoft 小型语言模型的最新版本。它有四个变种(更多信息请查看此链接:https://azure.microsoft.com/en-us/blog/new-models-added-to-the-phi-3-family-available-on-microsoft-azure/):

  • Phi-3-mini:一个包含 38 亿参数的语言模型,有两个上下文长度(128K 和 4K)

  • Phi-3-small:一个包含 70 亿参数的语言模型,有两个上下文长度(128K 和 8K)

  • Phi-3-medium:一个包含 140 亿参数的语言模型,有两个上下文长度(128K 和 4K)

  • Phi-3-vision:一个包含 42 亿参数的多模态模型,具有语言和视觉功能

在这篇文章中,我关注多模态视觉语言模型的应用。正如官方文档中所解释的,Phi-3-Vision-128K-Instruct 是一个轻量级、最先进的开放多模态模型,适用于需要视觉和文本输入能力的一般用途 AI 系统和应用程序,适用场景包括:

  1. 内存/计算受限的环境;

  2. 低延迟场景;

  3. 一般图像理解;

  4. OCR;

  5. 图表和表格理解。

在这篇文章中,我感兴趣的是在个人文档(如身份证、驾驶证和健康保险卡)上使用该模型进行 OCR 数据提取的能力。测试中使用的文档是仿制品,不是原件,也不属于真实的人。完整的代码链接如下:https://github.com/enrico310786/phi3_vision_language

模型实例 

为了在推理模式下使用该模型,我构建了如下环境:

  1. 1) conda create -n llm_images python=3.10
  2. 2) conda activate llm_images
  3. 3) pip install torch==2.3.0 torchvision==0.18.0
  4. 4) pip install packaging
  5. 5) pip install pillow==10.3.0 chardet==5.2.0 flash_attn==2.5.8 accelerate==0.30.1 bitsandbytes==0.43.1 Requests==2.31.0 transformers==4.40.2
  6. 6) pip uninstall jupyter
  7. 7) conda install -c anaconda jupyter
  8. 8) conda update jupyter
  9. 9) pip install --upgrade 'nbconvert>=7' 'mistune>=2'
  10. 10) pip install cchardet

环境可用后,我从 Huggingface 仓库下载了模型。

  1. # Import necessary libraries
  2. from PIL import Image
  3. import requests
  4. from transformers import AutoModelForCausalLM
  5. from transformers import AutoProcessor
  6. from transformers import BitsAndBytesConfig
  7. import torch
  8. from IPython.display import display
  9. import time
  10. # Define model ID
  11. model_id = "microsoft/Phi-3-vision-128k-instruct"
  12. # Load processor
  13. processor = AutoProcessor.from_pretrained(model_id, trust_remote_code=True)
  14. # Define BitsAndBytes configuration for 4-bit quantization
  15. nf4_config = BitsAndBytesConfig(
  16. load_in_4bit=True,
  17. bnb_4bit_quant_type="nf4",
  18. bnb_4bit_use_double_quant=True,
  19. bnb_4bit_compute_dtype=torch.bfloat16,
  20. )
  21. # Load model with 4-bit quantization and map to CUDA
  22. model = AutoModelForCausalLM.from_pretrained(
  23. model_id,
  24. device_map="cuda",
  25. trust_remote_code=True,
  26. torch_dtype="auto",
  27. quantization_config=nf4_config,
  28. )

接下来,我准备了一个 Python 函数,该函数将消息和图像路径作为输入传递给模型,并输出模型结果。

  1. def model_inference(messages, path_image):
  2. start_time = time.time()
  3. image = Image.open(path_image)
  4. # Prepare prompt with image token
  5. prompt = processor.tokenizer.apply_chat_template(
  6. messages, tokenize=False, add_generation_prompt=True
  7. )
  8. # Process prompt and image for model input
  9. inputs = processor(prompt, [image], return_tensors="pt").to("cuda:0")
  10. # Generate text response using model
  11. generate_ids = model.generate(
  12. **inputs,
  13. eos_token_id=processor.tokenizer.eos_token_id,
  14. max_new_tokens=500,
  15. do_sample=False,
  16. )
  17. # Remove input tokens from generated response
  18. generate_ids = generate_ids[:, inputs["input_ids"].shape[1] :]
  19. # Decode generated IDs to text
  20. response = processor.batch_decode(
  21. generate_ids, skip_special_tokens=True, clean_up_tokenization_spaces=False
  22. )[0]
  23. display(image)
  24. end_time = time.time()
  25. print("Inference time: {}".format(end_time - start_time))
  26. # Print the generated response
  27. print(response)
'
运行

在接下来的部分中,我展示了如何从不同的文档中提取数据。根据文档的正面或背面,我准备了一个特定的提示来识别我要提取数据的字段。

身份证 OCR

正面 

对于意大利身份证的正面,我使用以下提示提取主要个人数据,并将其放入 JSON 格式输出。

  1. prompt_cie_front = [{"role": "user", "content": "<|image_1|>\nOCR the text of the image. Extract the text of the following fields and put it in a JSON format: \
  2. 'Comune Di/ Municipality', 'COGNOME /Surname', 'NOME/NAME', 'LUOGO E DATA DI NASCITA/\
  3. PLACE AND DATE OF BIRTH', 'SESSO/SEX', 'STATURA/HEIGHT', 'CITADINANZA/NATIONALITY',\
  4. 'EMISSIONE/ ISSUING', 'SCADENZA /EXPIRY'. Read the code at the top right and put it in the JSON field 'CODE'"}]
  5. # Download image from URL
  6. path_image = "/home/randellini/llm_images/resources/cie_fronte.jpg"
  7. # inference
  8. model_inference(prompt_cie_front, path_image)

6ecd240cb576b3d146cb2f89283ef67e.png

对于上述图像,我获得了以下输出。可以看到,唯一的卡片代码位于卡片的右上角,没有关联字段。为了提取其值,我在提示中指定模型要读取右上角的代码并将其放入名为 “CODE” 的 JSON 字段中。唯一的错误是唯一代码中的第一个零被交换成大写字母 O。

  1. Inference time: 9.793543815612793
  2. {
  3. "Comune Di/ Municipality": "SERENELLA MARITTIMA",
  4. "COGNOME /Surname": "ROSSI",
  5. "NOME/NAME": "BIANCA",
  6. "LUOGO E DATA DI NASCITA": "PINO SULLA SPONDA DEL LAGO MAGGIORE (VA) 30.12.1964",
  7. "SESSO/SEX": "F",
  8. "STATURA/HEIGHT": "180",
  9. "CITADINANZA/NATIONALITY": "ITA",
  10. "EMISSIONE/ ISSUING": "30.05.2022",
  11. "SCADENZA /EXPIRY": "30.12.2031",
  12. "CODE": "CAO000AA"
  13. }

背面 

要提取背面数据,我使用了以下提示:

  1. prompt_cie_back = [{"role": "user", "content": "<|image_1|>\nOCR the text of the image. Extract the text of the following fields and put it in a JSON format: \
  2. 'CODICE FISCALE/FISCAL CODE', 'ESTREMI ATTO DI NASCITA', 'INDIRIZZO DI RESIDENZA/RESIDENCE'"}]
  3. # Download image from URL
  4. path_image = "/home/randellini/llm_images/resources/cie_retro.jpg"
  5. # inference
  6. model_inference(prompt_cie_back, path_image)

e5c37ef3707446b77d13926d4f965b26.png

意大利身份证背面 我得到了以下结果。只有一个错误,即缺少税号的第三个字符,大写字母 S。

  1. Inference time: 4.082342147827148
  2. {
  3. "codice_fiscale": "RSBNC64T70G677R",
  4. "estremi_atto_di_nascita": "00000.0A00",
  5. "indirizzo_di_residenza": "Via Salaria, 712"
  6. }

驾驶证 OCR 

对于意大利驾驶证的正面,我使用了以下提示:

  1. prompt_ld_front = [{"role": "user", "content": "<|image_1|>\nOCR the text of the image. Extract the text of the following fields and put it in a JSON format: \
  2. '1.', '2.', '3.', '4a.', '4b.', '4c.', '5.','9.'"}]
  3. # Download image from URL
  4. path_image = "/home/randellini/llm_images/resources/patente_fronte.png"
  5. # inference
  6. model_inference(prompt_ld_front, path_image)

66fb9a6521f9060cc17d571a8fe0bf6b.png

获得的结果是:

  1. Inference time: 5.2030909061431885
  2. {
  3. "1": "ROSSI",
  4. "2": "MARIA",
  5. "3": "01/01/65",
  6. "4a": "01/03/2014",
  7. "4b": "01/01/2025",
  8. "4c": "MIT-UCO",
  9. "5": "A0A000000A",
  10. "9": "B"
  11. }

对于意大利驾驶证的背面,目前我还没有找到合适的提示来读取表格中列 '9.'、'10.'、'11.' 和 '12.' 的值。此外,‘12.’ 出现了两次。首先,作为表格列的名称,然后作为卡片左下角的一个字段。这个最后一个字段很重要,因为它警示了对司机施加的特殊义务。例如,代码 01 表示必须佩戴眼镜驾驶。

cdb6c7e1b8ce5ea4e8d98c78941891eb.png

健康保险卡 OCR

正面 

为了读取意大利健康保险卡正面的值,我使用了以下提示

  1. prompt_hic_front = [{"role": "user", "content": "<|image_1|>\nOCR the text of the image. Extract the text of the following fields and put it in a JSON format: \
  2. 'Codice Fiscale', 'Sesso', 'Cognome', 'Nome', 'Luogo di nascita', 'Provincia', 'Data di nascita', 'Data di scadenza'"}]
  3. # Download image from URL
  4. path_image = "/home/randellini/llm_images/resources/tessera_sanitaria_fronte.jpg"
  5. # inference
  6. model_inference(prompt_hic_front, path_image)

e67ef0509f8e1dcb3d95264181621022.png

我获得了以下结果

  1. Inference time: 7.003508806228638
  2. ```json
  3. {
  4. "Codice Fiscale": "RSSMRO62B25E205Y",
  5. "Sesso": "M",
  6. "Cognome": "ROSSI",
  7. "Nome": "MARIO",
  8. "Luogo di nascita": "CASSINA DE' PECCHI",
  9. "Provincia": "MI",
  10. "Data di nascita": "25/02/1962",
  11. "Data di scadenza": "10/10/2019"
  12. }
  13. ```

背面 

为了读取卡片的背面,我使用了以下提示

  1. prompt_hic_back = [{"role": "user", "content": "<|image_1|>\nOCR the text of the image. Extract the text of the following fields and put it in a JSON format: \
  2. '3 Cognome', '4 Nome', '5 Data di nascita', '6 Numero identificativo personale', '7 Numero identificazione dell'istituzione', 'Numero di identificazione della tessera', '9 Scadenza'"}]
  3. # Download image from URL
  4. path_image = "/home/randellini/llm_images/resources/tessera_sanitaria_retro.jpg"
  5. # inference
  6. model_inference(prompt_hic_back, path_image)

79e8266e58304b68c12a59b4bf69d6d3.png

获得的结果是

  1. Inference time: 7.403932809829712
  2. {
  3. "3 Cognome": "ROSSI",
  4. "4 Nome": "MARIO",
  5. "5 Data di nascita": "25/02/1962",
  6. "6 Numero identificativo personale": "RSSMRO62B25E205Y",
  7. "7 Numero identificazione dell'istituzione": "0030 - LOMBARDIA",
  8. "Numero di identificazione della tessera": "80380800301234567890",
  9. "9 Scadenza": "01/01/2006"
  10. }

·  END  ·

HAPPY LIFE

8b66af003d8fa0c060fc9ecf11594d8e.png

本文仅供学习交流使用,如有侵权请联系作者删除

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop】
推荐阅读
相关标签
  

闽ICP备14008679号