Transformers documentation
Trả lời câu hỏi từ tài liệu
Trả lời câu hỏi từ tài liệu
Document Question Answering, còn được gọi là Document Visual Question Answering, là một tác vụ liên quan đến việc cung cấp câu trả lời cho các câu hỏi được đặt ra về hình ảnh tài liệu. Đầu vào của các mô hình hỗ trợ tác vụ này thường là sự kết hợp giữa một hình ảnh và một câu hỏi, và đầu ra là một câu trả lời được diễn đạt bằng ngôn ngữ tự nhiên. Các mô hình này sử dụng nhiều phương thức (modalities), bao gồm văn bản, vị trí của các từ (bounding boxes) và chính hình ảnh.
Hướng dẫn này minh họa cách:
- Tinh chỉnh LayoutLMv2 trên dataset DocVQA.
- Sử dụng mô hình đã tinh chỉnh của bạn để suy luận.
Để xem tất cả các kiến trúc và checkpoint tương thích với tác vụ này, chúng tôi khuyến nghị bạn kiểm tra trang tác vụ
LayoutLMv2 giải quyết tác vụ trả lời câu hỏi trên tài liệu bằng cách thêm một đầu trả lời câu hỏi (question-answering head) trên các trạng thái ẩn cuối cùng của các token, để dự đoán vị trí của token bắt đầu và token kết thúc của câu trả lời. Nói cách khác, bài toán được xử lý như một bài toán trả lời câu hỏi trích xuất (extractive question answering): cho ngữ cảnh, trích xuất phần thông tin nào trả lời cho câu hỏi. Ngữ cảnh đến từ đầu ra của một bộ máy OCR, ở đây là Tesseract của Google.
Trước khi bắt đầu, hãy đảm bảo bạn đã cài đặt tất cả các thư viện cần thiết. LayoutLMv2 phụ thuộc vào detectron2, torchvision và tesseract.
pip install -q transformers datasets
pip install 'git+https://github.com/facebookresearch/detectron2.git'
pip install torchvisionsudo apt install tesseract-ocr
pip install -q pytesseractSau khi bạn đã cài đặt tất cả các phụ thuộc, hãy khởi động lại môi trường chạy của bạn.
Chúng tôi khuyến khích bạn chia sẻ mô hình của mình với cộng đồng. Đăng nhập vào tài khoản Hugging Face của bạn để tải nó lên 🤗 Hub. Khi được yêu cầu, hãy nhập token của bạn để đăng nhập:
>>> from huggingface_hub import notebook_login
>>> notebook_login()Hãy định nghĩa một số biến toàn cục.
>>> model_checkpoint = "microsoft/layoutlmv2-base-uncased"
>>> batch_size = 4Tải dữ liệu
Trong hướng dẫn này, chúng ta sử dụng một mẫu nhỏ của DocVQA đã được tiền xử lý, có sẵn trên 🤗 Hub. Nếu bạn muốn sử dụng bộ dữ liệu DocVQA đầy đủ, bạn có thể đăng ký và tải xuống tại trang chủ DocVQA. Nếu bạn làm như vậy, để tiếp tục với hướng dẫn này, hãy xem cách tải tệp vào một bộ dữ liệu 🤗.
>>> from datasets import load_dataset
>>> dataset = load_dataset("nielsr/docvqa_1200_examples")
>>> dataset
DatasetDict({
train: Dataset({
features: ['id', 'image', 'query', 'answers', 'words', 'bounding_boxes', 'answer'],
num_rows: 1000
})
test: Dataset({
features: ['id', 'image', 'query', 'answers', 'words', 'bounding_boxes', 'answer'],
num_rows: 200
})
})Như bạn có thể thấy, tập dữ liệu đã được chia thành tập huấn luyện và tập kiểm tra. Hãy xem một ví dụ ngẫu nhiên để làm quen với các đặc trưng.
>>> dataset["train"].featuresDưới đây là ý nghĩa của từng trường riêng lẻ:
id: id của ví dụimage: một đối tượng PIL.Image.Image chứa hình ảnh tài liệuquery: chuỗi câu hỏi - câu hỏi được hỏi bằng ngôn ngữ tự nhiên, bằng một số ngôn ngữanswers: một danh sách các câu trả lời đúng do người đánh dấu cung cấpwordsvàbounding_boxes: kết quả của OCR, chúng ta sẽ không sử dụng ở đâyanswer: một câu trả lời khớp với một mô hình khác mà chúng ta sẽ không sử dụng ở đây
Hãy chỉ giữ lại các câu hỏi bằng tiếng Anh và bỏ qua tính năng answer vì nó dường như chứa các dự đoán từ một mô hình khác.
Chúng ta cũng sẽ lấy câu trả lời đầu tiên từ bộ dữ liệu do các người chú thích cung cấp. Ngoài ra, bạn có thể lấy mẫu ngẫu nhiên.
>>> updated_dataset = dataset.map(lambda example: {"question": example["query"]["en"]}, remove_columns=["query"])
>>> updated_dataset = updated_dataset.map(
... lambda example: {"answer": example["answers"][0]}, remove_columns=["answer", "answers"]
... )Lưu ý rằng checkpoint LayoutLMv2 mà chúng ta sử dụng trong hướng dẫn này được huấn luyện với max_position_embeddings = 512 (bạn có thể
tìm thấy thông tin này trong tệp config.json của checkpoint).
Chúng ta có thể cắt ngắn các ví dụ, nhưng để tránh tình huống câu trả lời có thể nằm ở cuối một tài liệu lớn và bị cắt mất,
ở đây chúng ta sẽ loại bỏ một vài ví dụ mà embedding có khả năng dài hơn 512.
Nếu phần lớn các tài liệu trong tập dữ liệu của bạn là dài, bạn có thể triển khai chiến lược cửa sổ trượt - xem notebook này để biết thêm chi tiết.
>>> updated_dataset = updated_dataset.filter(lambda x: len(x["words"]) + len(x["question"].split()) < 512)Tại thời điểm này, hãy cũng loại bỏ các tính năng OCR khỏi bộ dữ liệu này. Chúng là kết quả của OCR để tinh chỉnh một mô hình khác. Chúng vẫn sẽ cần một số xử lý nếu chúng ta muốn sử dụng chúng, vì chúng không khớp với yêu cầu đầu vào của mô hình mà chúng ta sử dụng trong hướng dẫn này. Thay vào đó, chúng ta có thể sử dụng LayoutLMv2Processor trên dữ liệu gốc cho cả OCR và tokenization. Bằng cách này, chúng ta sẽ có được các đầu vào khớp với đầu vào mong đợi của mô hình. Nếu bạn muốn xử lý hình ảnh thủ công, hãy xem tài liệu mô hình LayoutLMv2 để tìm hiểu định dạng đầu vào mà mô hình mong đợi.
>>> updated_dataset = updated_dataset.remove_columns("words")
>>> updated_dataset = updated_dataset.remove_columns("bounding_boxes")Cuối cùng, việc khám phá dữ liệu sẽ không hoàn chỉnh nếu chúng ta không xem một ví dụ hình ảnh.
>>> updated_dataset["train"][11]["image"]
Tiền xử lý dữ liệu
Nhiệm vụ Trả lời Câu hỏi từ Tài liệu là một nhiệm vụ đa phương thức, và bạn cần đảm bảo rằng đầu vào từ mỗi phương thức được tiền xử lý theo kỳ vọng của mô hình. Hãy bắt đầu bằng cách nạp LayoutLMv2Processor, thành phần này kết hợp bên trong một bộ xử lý ảnh có thể xử lý dữ liệu ảnh và một bộ mã hóa có thể mã hóa dữ liệu văn bản.
>>> from transformers import AutoProcessor
>>> processor = AutoProcessor.from_pretrained(model_checkpoint)Tiền xử lý ảnh tài liệu
Đầu tiên, hãy chuẩn bị các hình ảnh tài liệu cho mô hình với sự hỗ trợ của image_processor từ processor.
Mặc định, image processor sẽ thay đổi kích thước ảnh thành 224x224, đảm bảo chúng có thứ tự kênh màu đúng,
và áp dụng OCR bằng tesseract để lấy các từ cùng các hộp giới hạn đã được chuẩn hóa. Trong hướng dẫn này, tất cả các mặc định này chính xác là những gì chúng ta cần.
Viết một hàm áp dụng xử lý ảnh mặc định cho một lô ảnh và trả về kết quả của OCR.
>>> image_processor = processor.image_processor
>>> def get_ocr_words_and_boxes(examples):
... images = [image.convert("RGB") for image in examples["image"]]
... encoded_inputs = image_processor(images)
... examples["image"] = encoded_inputs.pixel_values
... examples["words"] = encoded_inputs.words
... examples["boxes"] = encoded_inputs.boxes
... return examplesĐể áp dụng tiền xử lý này cho toàn bộ bộ dữ liệu một cách nhanh chóng, hãy sử dụng map.
>>> dataset_with_ocr = updated_dataset.map(get_ocr_words_and_boxes, batched=True, batch_size=2)Tiền xử lý dữ liệu văn bản
Sau khi đã áp dụng OCR vào các hình ảnh, chúng ta cần mã hóa phần văn bản của bộ dữ liệu để chuẩn bị cho mô hình.
Điều này bao gồm việc chuyển đổi các từ và hộp mà chúng ta có được ở bước trước thành input_ids, attention_mask, token_type_ids và bbox ở cấp độ token. Để tiền xử lý văn bản, chúng ta sẽ cần tokenizer từ bộ xử lý.
>>> tokenizer = processor.tokenizerNgoài các bước tiền xử lý đã đề cập ở trên, chúng ta cũng cần thêm nhãn cho mô hình. Đối với các mô hình xxxForQuestionAnswering trong 🤗 Transformers, nhãn bao gồm start_positions và end_positions, chỉ ra token nào nằm ở vị trí bắt đầu và token nào nằm ở vị trí kết thúc của câu trả lời.
Hãy bắt đầu với điều đó. Định nghĩa một hàm trợ giúp có thể tìm một danh sách con (câu trả lời được tách thành các từ) trong một danh sách lớn hơn (danh sách các từ).
Hàm này sẽ nhận vào hai danh sách, words_list và answer_list. Sau đó, nó sẽ lặp qua words_list và kiểm tra xem từ hiện tại trong words_list (words_list[i]) có bằng từ đầu tiên của answer_list (answer_list[0]) và danh sách con của words_list bắt đầu từ từ hiện tại và có cùng độ dài với answer_list có bằng to answer_list hay không.
Nếu điều kiện này đúng, điều đó có nghĩa là đã tìm thấy một sự khớp, và hàm sẽ ghi lại sự khớp đó, chỉ số bắt đầu (idx) và chỉ số kết thúc (idx + len(answer_list) - 1). Nếu tìm thấy nhiều hơn một sự khớp, hàm sẽ chỉ trả về sự khớp đầu tiên.
Nếu không tìm thấy sự khớp nào, hàm sẽ trả về (None, 0 và 0).
>>> def subfinder(words_list, answer_list):
... matches = []
... start_indices = []
... end_indices = []
... for idx, i in enumerate(range(len(words_list))):
... if words_list[i] == answer_list[0] and words_list[i : i + len(answer_list)] == answer_list:
... matches.append(answer_list)
... start_indices.append(idx)
... end_indices.append(idx + len(answer_list) - 1)
... if matches:
... return matches[0], start_indices[0], end_indices[0]
... else:
... return None, 0, 0Để minh họa cách hàm này tìm vị trí của câu trả lời, hãy sử dụng nó trên một ví dụ:
>>> example = dataset_with_ocr["train"][1]
>>> words = [word.lower() for word in example["words"]]
>>> match, word_idx_start, word_idx_end = subfinder(words, example["answer"].lower().split())
>>> print("Question: ", example["question"])
>>> print("Words:", words)
>>> print("Answer: ", example["answer"])
>>> print("start_index", word_idx_start)
>>> print("end_index", word_idx_end)
Question: Who is in cc in this letter?
Words: ['wie', 'baw', 'brown', '&', 'williamson', 'tobacco', 'corporation', 'research', '&', 'development', 'internal', 'correspondence', 'to:', 'r.', 'h.', 'honeycutt', 'ce:', 't.f.', 'riehl', 'from:', '.', 'c.j.', 'cook', 'date:', 'may', '8,', '1995', 'subject:', 'review', 'of', 'existing', 'brainstorming', 'ideas/483', 'the', 'major', 'function', 'of', 'the', 'product', 'innovation', 'graup', 'is', 'to', 'develop', 'marketable', 'nove!', 'products', 'that', 'would', 'be', 'profitable', 'to', 'manufacture', 'and', 'sell.', 'novel', 'is', 'defined', 'as:', 'of', 'a', 'new', 'kind,', 'or', 'different', 'from', 'anything', 'seen', 'or', 'known', 'before.', 'innovation', 'is', 'defined', 'as:', 'something', 'new', 'or', 'different', 'introduced;', 'act', 'of', 'innovating;', 'introduction', 'of', 'new', 'things', 'or', 'methods.', 'the', 'products', 'may', 'incorporate', 'the', 'latest', 'technologies,', 'materials', 'and', 'know-how', 'available', 'to', 'give', 'then', 'a', 'unique', 'taste', 'or', 'look.', 'the', 'first', 'task', 'of', 'the', 'product', 'innovation', 'group', 'was', 'to', 'assemble,', 'review', 'and', 'categorize', 'a', 'list', 'of', 'existing', 'brainstorming', 'ideas.', 'ideas', 'were', 'grouped', 'into', 'two', 'major', 'categories', 'labeled', 'appearance', 'and', 'taste/aroma.', 'these', 'categories', 'are', 'used', 'for', 'novel', 'products', 'that', 'may', 'differ', 'from', 'a', 'visual', 'and/or', 'taste/aroma', 'point', 'of', 'view', 'compared', 'to', 'canventional', 'cigarettes.', 'other', 'categories', 'include', 'a', 'combination', 'of', 'the', 'above,', 'filters,', 'packaging', 'and', 'brand', 'extensions.', 'appearance', 'this', 'category', 'is', 'used', 'for', 'novel', 'cigarette', 'constructions', 'that', 'yield', 'visually', 'different', 'products', 'with', 'minimal', 'changes', 'in', 'smoke', 'chemistry', 'two', 'cigarettes', 'in', 'cne.', 'emulti-plug', 'te', 'build', 'yaur', 'awn', 'cigarette.', 'eswitchable', 'menthol', 'or', 'non', 'menthol', 'cigarette.', '*cigarettes', 'with', 'interspaced', 'perforations', 'to', 'enable', 'smoker', 'to', 'separate', 'unburned', 'section', 'for', 'future', 'smoking.', '«short', 'cigarette,', 'tobacco', 'section', '30', 'mm.', '«extremely', 'fast', 'buming', 'cigarette.', '«novel', 'cigarette', 'constructions', 'that', 'permit', 'a', 'significant', 'reduction', 'iretobacco', 'weight', 'while', 'maintaining', 'smoking', 'mechanics', 'and', 'visual', 'characteristics.', 'higher', 'basis', 'weight', 'paper:', 'potential', 'reduction', 'in', 'tobacco', 'weight.', '«more', 'rigid', 'tobacco', 'column;', 'stiffing', 'agent', 'for', 'tobacco;', 'e.g.', 'starch', '*colored', 'tow', 'and', 'cigarette', 'papers;', 'seasonal', 'promotions,', 'e.g.', 'pastel', 'colored', 'cigarettes', 'for', 'easter', 'or', 'in', 'an', 'ebony', 'and', 'ivory', 'brand', 'containing', 'a', 'mixture', 'of', 'all', 'black', '(black', 'paper', 'and', 'tow)', 'and', 'ail', 'white', 'cigarettes.', '499150498']
Answer: T.F. Riehl
start_index 17
end_index 18Tuy nhiên, sau khi các ví dụ được mã hóa, chúng sẽ trông như sau:
>>> encoding = tokenizer(example["question"], example["words"], example["boxes"])
>>> tokenizer.decode(encoding["input_ids"])
[CLS] who is in cc in this letter? [SEP] wie baw brown & williamson tobacco corporation research & development ...Chúng ta sẽ cần tìm vị trí của câu trả lời trong đầu vào đã mã hóa.
token_type_idscho biết token nào thuộc về câu hỏi và token nào thuộc về từ trong tài liệu.tokenizer.cls_token_idsẽ giúp tìm token đặc biệt ở đầu đầu vào.word_idssẽ giúp khớp câu trả lời tìm thấy trongwordsgốc với cùng câu trả lời trong đầu vào mã hóa đầy đủ và xác định vị trí bắt đầu/kết thúc của câu trả lời trong đầu vào mã hóa.
Với điều đó trong tâm trí, hãy tạo một hàm để mã hóa một lô các ví dụ trong bộ dữ liệu:
>>> def encode_dataset(examples, max_length=512):
... questions = examples["question"]
... words = examples["words"]
... boxes = examples["boxes"]
... answers = examples["answer"]
... # encode the batch of examples and initialize the start_positions and end_positions
... encoding = tokenizer(questions, words, boxes, max_length=max_length, padding="max_length", truncation=True)
... start_positions = []
... end_positions = []
... # loop through the examples in the batch
... for i in range(len(questions)):
... cls_index = encoding["input_ids"][i].index(tokenizer.cls_token_id)
... # find the position of the answer in example's words
... words_example = [word.lower() for word in words[i]]
... answer = answers[i]
... match, word_idx_start, word_idx_end = subfinder(words_example, answer.lower().split())
... if match:
... # if match is found, use `token_type_ids` to find where words start in the encoding
... token_type_ids = encoding["token_type_ids"][i]
... token_start_index = 0
... while token_type_ids[token_start_index] != 1:
... token_start_index += 1
... token_end_index = len(encoding["input_ids"][i]) - 1
... while token_type_ids[token_end_index] != 1:
... token_end_index -= 1
... word_ids = encoding.word_ids(i)[token_start_index : token_end_index + 1]
... start_position = cls_index
... end_position = cls_index
... # loop over word_ids and increase `token_start_index` until it matches the answer position in words
... # once it matches, save the `token_start_index` as the `start_position` of the answer in the encoding
... for id in word_ids:
... if id == word_idx_start:
... start_position = token_start_index
... else:
... token_start_index += 1
... # similarly loop over `word_ids` starting from the end to find the `end_position` of the answer
... for id in word_ids[::-1]:
... if id == word_idx_end:
... end_position = token_end_index
... else:
... token_end_index -= 1
... start_positions.append(start_position)
... end_positions.append(end_position)
... else:
... start_positions.append(cls_index)
... end_positions.append(cls_index)
... encoding["image"] = examples["image"]
... encoding["start_positions"] = start_positions
... encoding["end_positions"] = end_positions
... return encodingBây giờ khi đã có hàm tiền xử lý này, chúng ta có thể mã hóa toàn bộ bộ dữ liệu:
>>> encoded_train_dataset = dataset_with_ocr["train"].map(
... encode_dataset, batched=True, batch_size=2, remove_columns=dataset_with_ocr["train"].column_names
... )
>>> encoded_test_dataset = dataset_with_ocr["test"].map(
... encode_dataset, batched=True, batch_size=2, remove_columns=dataset_with_ocr["test"].column_names
... )Hãy kiểm tra xem các đặc trưng của bộ dữ liệu đã mã hóa trông như thế nào:
>>> encoded_train_dataset.features
{'image': Sequence(feature=Sequence(feature=Sequence(feature=Value(dtype='uint8', id=None), length=-1, id=None), length=-1, id=None), length=-1, id=None),
'input_ids': Sequence(feature=Value(dtype='int32', id=None), length=-1, id=None),
'token_type_ids': Sequence(feature=Value(dtype='int8', id=None), length=-1, id=None),
'attention_mask': Sequence(feature=Value(dtype='int8', id=None), length=-1, id=None),
'bbox': Sequence(feature=Sequence(feature=Value(dtype='int64', id=None), length=-1, id=None), length=-1, id=None),
'start_positions': Value(dtype='int64', id=None),
'end_positions': Value(dtype='int64', id=None)}Đánh giá
Đánh giá cho câu hỏi trả lời tài liệu đòi hỏi một lượng đáng kể tiền xử lý sau. Để không chiếm quá nhiều thời gian của bạn, hướng dẫn này bỏ qua bước đánh giá. Trainer vẫn tính toán tổn thất đánh giá trong quá trình huấn luyện nên bạn không hoàn toàn mù mờ về hiệu suất của mô hình. Câu hỏi trả lời trích xuất thường được đánh giá bằng F1/trùng khớp chính xác. Nếu bạn muốn tự triển khai, hãy xem chương Question Answering của khóa học Hugging Face để lấy cảm hứng.
Huấn luyện
Chúc mừng! Bạn đã vượt qua phần khó nhất của hướng dẫn này và giờ đã sẵn sàng để huấn luyện mô hình của riêng mình. Quá trình huấn luyện bao gồm các bước sau:
- Tải mô hình bằng AutoModelForDocumentQuestionAnswering sử dụng cùng checkpoint như trong tiền xử lý.
- Định nghĩa các siêu tham số huấn luyện của bạn trong TrainingArguments.
- Định nghĩa một hàm để nhóm các ví dụ lại với nhau, ở đây DefaultDataCollator sẽ hoạt động tốt
- Truyền các đối số huấn luyện vào Trainer cùng với mô hình, tập dữ liệu và bộ tổng hợp dữ liệu.
- Gọi train() để tinh chỉnh mô hình của bạn.
>>> from transformers import AutoModelForDocumentQuestionAnswering
>>> model = AutoModelForDocumentQuestionAnswering.from_pretrained(model_checkpoint)Trong TrainingArguments, hãy dùng output_dir để chỉ định nơi lưu mô hình của bạn và cấu hình các siêu tham số theo ý bạn.
Nếu bạn muốn chia sẻ mô hình của mình với cộng đồng, hãy đặt push_to_hub thành True (bạn phải đăng nhập vào Hugging Face để tải mô hình lên).
Trong trường hợp này, output_dir cũng sẽ là tên của kho mà điểm kiểm tra mô hình của bạn sẽ được đẩy lên.
>>> from transformers import TrainingArguments
>>> # REPLACE THIS WITH YOUR REPO ID
>>> repo_id = "MariaK/layoutlmv2-base-uncased_finetuned_docvqa"
>>> training_args = TrainingArguments(
... output_dir=repo_id,
... per_device_train_batch_size=4,
... num_train_epochs=20,
... save_steps=200,
... logging_steps=50,
... eval_strategy="steps",
... learning_rate=5e-5,
... save_total_limit=2,
... remove_unused_columns=False,
... push_to_hub=True,
... )Định nghĩa một bộ tổng hợp dữ liệu đơn giản để nhóm các ví dụ thành một lô.
>>> from transformers import DefaultDataCollator
>>> data_collator = DefaultDataCollator()Cuối cùng, hãy kết hợp tất cả lại và gọi train():
>>> from transformers import Trainer
>>> trainer = Trainer(
... model=model,
... args=training_args,
... data_collator=data_collator,
... train_dataset=encoded_train_dataset,
... eval_dataset=encoded_test_dataset,
... processing_class=processor,
... )
>>> trainer.train()Để thêm mô hình cuối cùng vào 🤗 Hub, hãy tạo thẻ mô hình và gọi push_to_hub:
>>> trainer.create_model_card()
>>> trainer.push_to_hub()Suy luận
Bây giờ bạn đã tinh chỉnh một mô hình LayoutLMv2 và tải nó lên 🤗 Hub, bạn có thể sử dụng nó để suy luận. Cách đơn giản nhất để thử mô hình đã tinh chỉnh của bạn cho suy luận là sử dụng nó trong một Pipeline.
Hãy xem một ví dụ:
>>> example = dataset["test"][2]
>>> question = example["query"]["en"]
>>> image = example["image"]
>>> print(question)
>>> print(example["answers"])
'Who is ‘presiding’ TRRF GENERAL SESSION (PART 1)?'
['TRRF Vice President', 'lee a. waller']Tiếp theo, khởi tạo một pipeline cho trả lời câu hỏi từ tài liệu bằng mô hình của bạn, và truyền kết hợp ảnh + câu hỏi vào pipeline đó.
>>> from transformers import pipeline
>>> qa_pipeline = pipeline("document-question-answering", model="MariaK/layoutlmv2-base-uncased_finetuned_docvqa")
>>> qa_pipeline(image, question)
[{'score': 0.9949808120727539,
'answer': 'Lee A. Waller',
'start': 55,
'end': 57}]Bạn cũng có thể tự động tái tạo kết quả của pipeline nếu muốn:
- Nhận một hình ảnh và một câu hỏi, chuẩn bị chúng cho mô hình bằng cách sử dụng processor từ mô hình của bạn.
- Truyền kết quả hoặc tiền xử lý qua mô hình.
- Mô hình trả về
start_logitsvàend_logits, cho biết token nào nằm ở đầu câu trả lời và token nào nằm ở cuối câu trả lời. Cả hai đều có shape (batch_size, sequence_length). - Thực hiện argmax trên chiều cuối của cả
start_logitsvàend_logitsđể lấystart_idxvàend_idxdự đoán. - Giải mã câu trả lời bằng tokenizer.
>>> import torch
>>> from transformers import AutoProcessor
>>> from transformers import AutoModelForDocumentQuestionAnswering
>>> processor = AutoProcessor.from_pretrained("MariaK/layoutlmv2-base-uncased_finetuned_docvqa")
>>> model = AutoModelForDocumentQuestionAnswering.from_pretrained("MariaK/layoutlmv2-base-uncased_finetuned_docvqa")
>>> with torch.no_grad():
... encoding = processor(image.convert("RGB"), question, return_tensors="pt")
... outputs = model(**encoding)
... start_logits = outputs.start_logits
... end_logits = outputs.end_logits
... predicted_start_idx = start_logits.argmax(-1).item()
... predicted_end_idx = end_logits.argmax(-1).item()
>>> processor.tokenizer.decode(encoding.input_ids.squeeze()[predicted_start_idx : predicted_end_idx + 1])
'lee a. waller'