Chuyển đến nội dung chính

PaliGemma 2 Mix: Hướng dẫn kèm dự án demo OCR

Tìm hiểu cách dùng PaliGemma 2 Mix để xây dựng trình quét hóa đơn và bộ phân tích chi tiêu bằng AI, trích xuất và phân loại chi phí từ biên lai.
· 12 phút đọc

Khám phá cùng AI

PaliGemma 2 Mix là một mô hình AI đa phương thức do Google phát triển. Đây là phiên bản nâng cấp của mô hình ngôn ngữ thị giác (VLM) PaliGemma, tích hợp các khả năng tiên tiến từ mô hình thị giác SigLIP và các mô hình ngôn ngữ Gemma 2.

Trong hướng dẫn này, tôi sẽ giải thích cách sử dụng PaliGemma 2 Mix để xây dựng một trình quét hóa đơn và bộ phân tích chi tiêu được hỗ trợ bởi AI có khả năng:

  • Trích xuất và phân loại chi phí từ biên lai hóa đơn.
  • Thực hiện nhận dạng ký tự quang học (OCR) để lấy thông tin chính.
  • Tóm tắt chi tiêu dựa trên các hình ảnh đã cung cấp.

Mặc dù trọng tâm của chúng ta là xây dựng một công cụ tạo insight tài chính, những gì bạn học được trong bài viết này có thể áp dụng để khám phá các trường hợp sử dụng khác của PaliGemma 2 Mix, như phân đoạn ảnh, phát hiện đối tượng và hỏi đáp.

PaliGemma 2 Mix là gì?

PaliGemma 2 Mix là một mô hình ngôn ngữ-thị giác (VLM) tiên tiến xử lý cả ảnh và văn bản làm đầu vào, đồng thời tạo ra đầu ra dạng văn bản. Nó được thiết kế để xử lý đa dạng các tác vụ AI đa phương thức đồng thời hỗ trợ nhiều ngôn ngữ.

PaliGemma 2 được thiết kế cho nhiều tác vụ ngôn ngữ-thị giác, bao gồm tạo chú thích cho ảnh và video ngắn, hỏi đáp trực quan, nhận dạng ký tự quang học (OCR), phát hiện đối tượng và phân đoạn.

Nhận dạng ký tự quang học với PaliGemma 2 Mix

Nguồn ảnh dùng trong sơ đồ: Google

Mô hình PaliGemma 2 Mix được thiết kế cho:

  • Tạo chú thích cho ảnh & video ngắn: Tạo chú thích chính xác, theo ngữ cảnh cho ảnh tĩnh và video ngắn.
  • Hỏi đáp trực quan (VQA): Phân tích ảnh và trả lời câu hỏi dạng văn bản dựa trên nội dung trực quan.
  • Nhận dạng ký tự quang học (OCR): Trích xuất và diễn giải văn bản từ hình ảnh, hữu ích cho tài liệu, biên lai và tài liệu quét.
  • Phát hiện & phân đoạn đối tượng: Xác định, gán nhãn và phân đoạn các đối tượng trong ảnh để phân tích có cấu trúc.
  • Hỗ trợ đa ngôn ngữ: Mô hình cũng cho phép tạo và hiểu văn bản bằng nhiều ngôn ngữ cho các ứng dụng toàn cầu.

Bạn có thể tìm thêm thông tin về mô hình PaliGemma 2 Mix trong bài viết phát hành chính thức. 

Tổng quan dự án: Trình quét hóa đơn và phân tích chi tiêu với PaliGemma 2 Mix

Hãy phác thảo các bước chính mà chúng ta sẽ thực hiện:

  1. Tải và chuẩn bị dữ liệu: Bắt đầu bằng việc tải và chuẩn bị ảnh biên lai làm đầu vào.
  2. Khởi tạo mô hình PaliGemma 2 Mix: Cấu hình và tải mô hình để xử lý các tác vụ ngôn ngữ-thị giác.
  3. Xử lý ảnh đầu vào: Chuyển ảnh sang định dạng phù hợp (RGB) và chuẩn bị cho phân tích.
  4. Trích xuất thông tin chính: Thực hiện nhận dạng ký tự quang học (OCR) để lấy tổng số tiền.
  5. Phân loại chi phí: Phân loại các khoản mua sắm vào các nhóm như tạp hóa, quần áo, điện tử và khác.
  6. Tạo insight chi tiêu: Tóm tắt chi phí theo danh mục và tạo biểu đồ phân bổ chi tiêu.
  7. Xây dựng giao diện Gradio tương tác: Cuối cùng, tạo giao diện cho phép người dùng tải lên nhiều hóa đơn, trích xuất dữ liệu và phân tích chi tiêu trực quan.

Bước 1: Điều kiện tiên quyết

Trước khi bắt đầu, hãy đảm bảo rằng bạn đã cài đặt các công cụ và thư viện sau:

  • Python 3.8+
  • torch
  • Transformers
  • PIL
  • Matplotlib
  • Gradio

Chạy các lệnh sau để cài đặt các phụ thuộc cần thiết:

pip install gradio -U bitsandbytes -U transformers -q

Sau khi cài đặt xong các phụ thuộc trên, hãy chạy các lệnh import sau:

import gradio as gr
import torch
import pandas as pd
import matplotlib.pyplot as plt
from transformers import PaliGemmaForConditionalGeneration, PaliGemmaProcessor, BitsAndBytesConfig
from transformers import BitsAndBytesConfig
from PIL import Image
import re

Bước 2: Khởi tạo mô hình

Chúng ta cấu hình và tải mô hình PaliGemma 2 Mix với lượng tử hóa để tối ưu hiệu năng. Trong demo này, chúng ta sẽ dùng mô hình 10 tỷ tham số với độ phân giải ảnh đầu vào 448 x 448. Bạn cần tối thiểu GPU T4 với 40GB bộ nhớ (cấu hình Colab) để chạy mô hình này. 

device = "cuda" if torch.cuda.is_available() else "cpu"
# Model setup
model_id = "google/paligemma2-10b-mix-448" 
bnb_config = BitsAndBytesConfig(
    load_in_8bit=True,  # Change to load_in_4bit=True for even lower memory usage
    llm_int8_threshold=6.0,
)

# Load model with quantization
model = PaliGemmaForConditionalGeneration.from_pretrained(
    model_id, quantization_config=bnb_config
).eval()

# Load processor
processor = PaliGemmaProcessor.from_pretrained(model_id)
# Print success message
print("Model and processor loaded successfully!")

Lượng tử hóa BitsAndBytes giúp giảm sử dụng bộ nhớ mà vẫn duy trì hiệu năng, cho phép chạy các mô hình lớn trên tài nguyên GPU hạn chế. Trong triển khai này, chúng ta dùng lượng tử hóa 4-bit để tối ưu bộ nhớ hơn nữa.

Chúng ta tải mô hình bằng lớp PaliGemmaForConditionalGeneration từ thư viện transformers bằng cách truyền ID mô hình và cấu hình lượng tử hóa. Tương tự, chúng ta tải processor, bộ tiền xử lý đầu vào thành tensor trước khi truyền vào mô hình.

Bước 3: Xử lý ảnh 

Sau khi tải các shard mô hình, chúng ta xử lý ảnh trước khi đưa vào mô hình để đảm bảo tương thích định dạng và tính thống nhất. Chúng ta chuyển ảnh sang định dạng RGB:

def ensure_rgb(image: Image.Image) -> Image.Image:
    if image.mode != "RGB":
        image = image.convert("RGB")
    return image

Giờ đây, ảnh đã sẵn sàng để suy luận.

Bước 4: Suy luận với PaliGemma

Bây giờ, chúng ta thiết lập hàm chính để chạy suy luận với mô hình. Hàm này nhận ảnh đầu vào và câu hỏi, ghép chúng thành prompt và truyền qua processor vào mô hình để suy luận.

def ask_model(image: Image.Image, question: str) -> str:
    prompt = f"<image> answer en {question}"
    inputs = processor(text=prompt, images=image, return_tensors="pt").to(device)
    with torch.inference_mode():
        generated_ids = model.generate(
            **inputs,
            max_new_tokens=50,
            do_sample=False
        )
    result = processor.batch_decode(generated_ids, skip_special_tokens=True)
    return result[0].strip()

Bước 5: Trích xuất thông tin chính

Với hàm chính đã sẵn sàng, tiếp theo chúng ta sẽ trích xuất các tham số chính từ ảnh — trong trường hợp này là tổng số tiền và danh mục hàng hóa.

 def extract_total_amount(image: Image.Image) -> float:
    question = "ocr\n what is the total amount? in numbers only" 
    answer = ask_model(image, question)
    print(f"Answer from model: {answer}")
    try:
        amounts = re.findall(r'\d+\.\d+|\d+', answer)  # Capture both integer and decimal values
        if amounts:
            return float(amounts[-1])  # Get the last valid amount as the total
    except ValueError:
        pass
    return 0.0

Hàm extract_total_amount() xử lý ảnh để trích xuất tổng số tiền từ biên lai bằng OCR. Nó tạo một truy vấn (câu hỏi) yêu cầu mô hình chỉ trích xuất giá trị số, sau đó gọi hàm ask_model() để nhận phản hồi từ mô hình. 

def categorize_goods(image: Image.Image) -> str:
    question = "what is the category of goods in the image - Grocery/ Clothing/ Electronics/ Other?"
    answer = ask_model(image, question)
    print(f"Category from model: {answer}")
    answer = answer.split("\n")[-1].strip().capitalize()
    valid_categories = ["Grocery", "Clothing", "Electronics", "Other"]
    return answer if answer in valid_categories else "Other"

Hàm categorize_goods() phân loại loại hàng hóa trong ảnh bằng cách nhắc mô hình với câu hỏi định sẵn gồm các danh mục: tạp hóa, quần áo, điện tử hoặc khác. Hàm ask_model() xử lý ảnh và trả về phản hồi dạng văn bản. Nếu phản hồi khớp với một trong các danh mục hợp lệ đã định, hàm sẽ trả về danh mục đó — nếu không sẽ mặc định là "Other".

Bước 6: Phân tích thông tin

Chúng ta đã có đầy đủ các hàm chính, giờ hãy phân tích đầu ra.

def generate_spending_chart(categories: dict):
    filtered_categories = {k: v for k, v in categories.items() if v > 0}  # Remove zero-value categories
    labels = list(filtered_categories.keys())
    values = list(filtered_categories.values())
    if not values or sum(values) == 0:
        fig, ax = plt.subplots()
        ax.text(0.5, 0.5, "No Spending Data", ha="center", va="center", fontsize=12)
        ax.axis("off")
        return fig
    fig, ax = plt.subplots()
    ax.pie(values, labels=labels, autopct='%1.1f%%', startangle=90)
    ax.axis('equal')
    plt.title("Spending Distribution")  
    return fig

Hàm trên tạo biểu đồ tròn để trực quan hóa phân bổ chi tiêu theo các danh mục. Nếu không có dữ liệu chi tiêu hợp lệ, hàm sẽ tạo một hình trống với thông điệp "No Spending Data". Ngược lại, biểu đồ tròn sẽ hiển thị nhãn danh mục và giá trị phần trăm, đảm bảo trực quan cân đối và thẳng hàng.

Bước 6: Phân tích đồng thời nhiều hóa đơn

Thông thường, chúng ta có nhiều hóa đơn cần phân tích, vì vậy hãy tạo một hàm để xử lý tất cả hóa đơn cùng lúc.

def process_multiple_bills(files: list):
    results = []
    images = []
    total_spending = 0
    category_totals = {"Grocery": 0, "Clothing": 0, "Electronics": 0, "Other": 0}
    for file in files:
        image = Image.open(file)
        image = ensure_rgb(image)
        images.append(image)
        total_amount = extract_total_amount(image)
        category = categorize_goods(image)
        total_spending += total_amount
        category_totals[category] += total_amount
        results.append({"Bill": len(results) + 1, "Category": category, "Total Amount": f"₹{total_amount:.2f}"})
    pie_chart = generate_spending_chart(category_totals)
    summary_text = f"**Total Spending Across All Bills:** ₹{total_spending:.2f}"
    return images, pd.DataFrame(results), summary_text, pie_chart

Để phân tích nhiều hóa đơn cùng lúc, chúng ta thực hiện các bước sau:

  1. Khởi tạo bộ nhớ tạm: Tạo danh sách để lưu kết quả và ảnh, đặt total_spending về 0 và định nghĩa từ điển cho tổng theo danh mục.
  2. Xử lý từng hóa đơn:
  • Mở và chuyển ảnh sang RGB.
  • Thêm ảnh vào danh sách.
  • Trích xuất tổng số tiền từ biên lai.
  • Phân loại hàng hóa trong biên lai.
  • Cập nhật tổng chi tiêu và tổng theo danh mục.
  • Lưu dữ liệu đã trích xuất vào danh sách kết quả.
  1. Tạo insight: Tạo biểu đồ tròn phân bổ chi tiêu kèm phần tóm tắt tổng chi tiêu.
  2. Trả về kết quả: Cuối cùng trả về danh sách ảnh, một DataFrame tóm tắt hóa đơn, phần tóm tắt tổng chi tiêu và biểu đồ chi tiêu.

Bước 7: Xây dựng giao diện Gradio

Giờ chúng ta đã có đầy đủ các hàm logic chính. Tiếp theo, xây dựng giao diện tương tác với Gradio.

def gradio_demo():
    with gr.Blocks() as demo:
        gr.Markdown("## PaliGemma 2 Mix Powered- Multiple Bill Scanner\nUpload multiple bill images, and this demo will extract text, categorize spending, and generate insights.")
        with gr.Row():
            with gr.Column():
                image_input = gr.File(file_count="multiple", file_types=["image"], label="Upload Bill Images")
                submit_button = gr.Button("Process Bills")
            with gr.Column():
                image_output = gr.Gallery(label="Uploaded Bills")
                table_output = gr.Dataframe(label="Bill Summary")
                summary_output = gr.Text(label="Total Spending Summary")
                chart_output = gr.Plot(label="Aggregated Spending Distribution")
        submit_button.click(
            fn=process_multiple_bills,
            inputs=image_input,
            outputs=[image_output, table_output, summary_output, chart_output]
        )
    demo.launch(debug=True)

if __name__ == "__main__":
    gradio_demo()

Đoạn mã trên tạo UI Gradio có cấu trúc với bộ tải tệp cho nhiều ảnh và nút gửi để kích hoạt xử lý. Sau khi gửi, ảnh hóa đơn được hiển thị trong thư viện, dữ liệu trích xuất hiển thị trong bảng, tổng chi tiêu được tóm tắt dạng văn bản và biểu đồ tròn phân bổ chi tiêu được tạo. 

Hàm này kết nối đầu vào của người dùng với hàm process_multiple_bills(), đảm bảo trích xuất dữ liệu và trực quan hóa liền mạch. Cuối cùng, demo.launch() khởi chạy ứng dụng Gradio để tương tác thời gian thực.

Suy luận PaliGemma 2 Mix trên hóa đơn chỉ có văn bản

Tôi cũng đã thử demo này với hai hóa đơn dạng hình ảnh (hóa đơn mua hàng Amazon) và nhận được kết quả như sau.

Lưu ý: Các VLM gặp khó khăn khi trích xuất con số, đôi khi dẫn đến kết quả sai. Ví dụ, nó đã trích xuất sai tổng số tiền cho hóa đơn thứ hai bên dưới. Có thể khắc phục bằng cách dùng mô hình lớn hơn hoặc đơn giản là fine-tune các mô hình hiện có.

Suy luận PaliGemma 2 Mix trên hóa đơn có văn bản + hình ảnh

Suy luận PaliGemma 2 Mix trên hóa đơn có văn bản + hình ảnh

Kết luận

Trong hướng dẫn này, chúng ta đã xây dựng một trình quét nhiều hóa đơn được hỗ trợ AI bằng PaliGemma 2 Mix, giúp trích xuất và phân loại chi phí từ biên lai. Chúng ta sử dụng khả năng ngôn ngữ-thị giác của PaliGemma 2 Mix cho OCR và phân loại để phân tích insight chi tiêu một cách dễ dàng. Tôi khuyến khích bạn điều chỉnh hướng dẫn này cho trường hợp sử dụng của riêng mình. 

Aashi Dutt

Tác giả

Aashi Dutt

Tôi là Chuyên gia Google Developers trong lĩnh vực ML (Gen AI), Chuyên gia Kaggle 3x và Đại sứ Women Techmakers với hơn 3 năm kinh nghiệm trong ngành công nghệ. Tôi đồng sáng lập một startup công nghệ y tế vào năm 2020 và hiện đang theo học thạc sĩ khoa học máy tính tại Georgia Tech, chuyên sâu về học máy.

Chủ đề

Liên quan