1. 簡要介紹
在數位化時代,我們每天都會接觸到大量的文件,包括掃描件、表格、收據等。如何讓計算機理解這些 包含文字和佈局資訊的文件,一直是人工智慧領域的研究重點。傳統的自然語言處理(NLP)模型主要關注文字內容,而忽略了文件的佈局和視覺資訊,這在處理文件影象時會遇到瓶頸. 為了解決這個問題,微軟在2020年6月推出了 LayoutLM 模型.
- 背景歷史:
- 在LayoutLM之前,NLP模型主要關注文字輸入,而計算機視覺模型主要關注影象輸入.
- LayoutLM的出現,首次將 影象、文字和2D位置 資訊作為輸入,實現了 多模態 資訊處理.
- 開發團隊: LayoutLM由 Yiheng Xu, Minghao Li, Lei Cui, Shaohan Huang, Furu Wei, 和 Ming Zhou 共同開發.
- 功能:
- LayoutLM旨在 理解文件影象,從而實現 資訊提取、表單理解、收據理解和文件分類 等任務.
- 它透過同時建模文字和佈局資訊之間的互動,從而 顯著提高 了文件影象理解的效能.
- LayoutLM 可以從 掃描文件或影象 中提取特定的、重點資訊.
2. 架構設計
LayoutLM 的架構基於 BERT (Bidirectional Encoder Representations from Transformers). 它在 BERT 的基礎上增加了 兩種新的輸入嵌入:
- 2D 位置嵌入 (2D Position Embeddings): 用於表示文件中 文字的空間位置. 與傳統的只考慮單詞順序的位置嵌入不同,2D 位置嵌入使用每個單詞的 邊界框座標 (x0, y0, x1, y1) 來定義其在頁面上的位置. 文件的左上角被視為座標系的原點 (0, 0). 這些座標被歸一化到 0-1000 的範圍內,然後嵌入到模型可以理解的數值表示中.
- 影象嵌入 (Image Embeddings): 用於 整合視覺資訊. LayoutLM 將影象分割成與 OCR 文字對應的區域,並利用這些區域的視覺特徵生成影象嵌入. 影象嵌入有助於模型理解文件的視覺風格,從而增強文件理解能力.
預訓練 (Pre-training):
- LayoutLM 使用 Masked Visual-Language Model (MVLM) 進行預訓練. MVLM 是受掩碼語言模型啟發的技術,但它同時考慮文字和2D位置嵌入作為輸入. 模型學習預測被掩碼的單詞,透過上下文的文字和空間位置資訊進行預測.
- LayoutLM 還使用 Multi-label Document Classification (MDC) 進行預訓練. 該任務訓練 LayoutLM 處理帶有多個標籤的掃描文件,使其能夠從多個領域聚合知識並生成更好的文件級別表示,儘管它不是大型模型預訓練的必要條件.
- LayoutLM的預訓練使用了 IIT-CDIP Test Collection 1.0 資料集,該資料集包含超過600萬份文件和1100萬份掃描文件影象.
3. 能處理的文件型別
LayoutLM 擅長處理那些 佈局和視覺資訊對於理解內容至關重要 的文件. 包括以下型別:
- 表單 (Forms): LayoutLM 在表單理解任務上取得了非常好的效果,能夠準確地處理具有特定欄位和佈局的結構化文件. FUNSD 資料集 通常用於訓練和評估 LayoutLM 的表單理解能力.
- 收據 (Receipts): LayoutLM 在收據理解任務中也表現出色. 它可以從收據中提取資料,並利用文字和佈局資訊. SROIE 資料集 用於微調 LayoutLM 的收據資料.
- 掃描文件 (Scanned documents): LayoutLM 能夠有效地處理掃描文件,同時建模文字和佈局資訊之間的互動.
- 商務文件 (Business Documents): LayoutLM 可應用於各種商務文件,包括:
- 採購訂單 (Purchase orders)
- 財務報告 (Financial reports)
- 商務郵件 (Business emails)
- 銷售協議 (Sales agreements)
- 供應商合同 (Vendor contracts)
- 信件 (Letters)
- 發票 (Invoices)
- 簡歷 (Resumes)
- 其他視覺豐富的文件 (Other Visually Rich Documents): LayoutLM 適用於任何視覺豐富的文件,在這些文件中,佈局顯著增強了語言表示.
4. 使用技巧
- OCR 引擎: 使用 OCR (Optical Character Recognition) 引擎 (例如 Tesseract)從文件影象中提取文字及其對應的邊界框.
- 邊界框歸一化: 在將邊界框座標輸入 LayoutLM 之前,將它們歸一化到 0-1000 範圍. 透過將邊界框座標除以文件影象的原始寬度和高度,然後乘以 1000 進行歸一化.
- 特殊標記: LayoutLM 使用特殊標記來處理文字,包括:
- [CLS]: 分類標記,用於序列分類,並且是序列的第一個標記.
- [SEP]: 分隔符標記,用於分隔多個序列.
- [PAD]: 填充標記,用於填充不同長度的序列.
- [MASK]: 掩碼標記,用於掩碼語言建模.
- [UNK]: 未知標記,用於表示詞彙表中未知的單詞.
- 選擇合適的 Tokenizer: 使用 LayoutLMTokenizer 或 LayoutLMTokenizerFast 進行分詞. LayoutLMTokenizerFast 是一個更快的版本,基於 Hugging Face 的 tokenizers 庫.
5. 執行環境要求
LayoutLM的執行環境要求主要包括以下幾個方面:
- 程式語言和框架:LayoutLM可以使用 PyTorch 或 TensorFlow 框架進行實現和訓練。
- PyTorch 是一個開源的機器學習庫,常用於實現神經網路和深度學習模型。
- TensorFlow 是另一個流行的開源機器學習庫,也用於實現神經網路和深度學習模型。
- Hugging Face Transformers 庫:這是使用LayoutLM的核心庫,提供了預訓練模型、tokenizer 以及其他工具。
- 這個庫提供了LayoutLM模型的各種實現,包括用於不同任務的變體,例如LayoutLMModel, LayoutLMForMaskedLM, LayoutLMForSequenceClassification, LayoutLMForTokenClassification 和 LayoutLMForQuestionAnswering。
- OCR引擎:需要一個 OCR (光學字元識別) 引擎 從文件影象中提取文字及其對應的邊界框。
- 常用的OCR引擎是 Tesseract。
- OCR引擎將影象中的文字轉換為機器可讀的文字,並提供位置嵌入所需的座標。
- 影象處理庫:需要影象處理庫來處理文件影象,例如 Pillow (PIL)。
- 資料處理庫:需要使用資料處理庫,例如 NumPy 和 Pandas 進行資料處理。
- 硬體要求: 如果要進行模型的訓練,GPU 可以顯著加快訓練速度。
- Python 環境: 需要 Python 程式設計環境,並安裝所需的庫。
- Tokenizer:需要使用 LayoutLMTokenizer 或 LayoutLMTokenizerFast 進行分詞。 LayoutLMTokenizerFast 是一個更快的版本,基於Hugging Face的tokenizers庫。
- Tokenizer負責將文字分割成模型可以理解的token。
- 資料集: 不同的任務需要不同的資料集。例如,FUNSD資料集用於表單理解,SROIE資料集用於收據理解,RVL-CDIP資料集用於文件影象分類。
總而言之,使用LayoutLM需要一個配置了適當庫(如 Transformers, PyTorch 或 Tensorflow,以及OCR引擎)的Python環境,以及一個能夠進行資料預處理和模型訓練的平臺。
6. 程式碼範例
以下是一個使用 LayoutLM 進行序列分類的 PyTorch 程式碼範例:
import os
import numpy as np
import pandas as pd
from tqdm.auto import tqdm
from sklearn.model_selection import train_test_split
import pytesseract
from PIL import Image, ImageDraw, ImageFont
import torch
from datasets import Dataset, Features, Sequence, ClassLabel, Value, Array2D
from transformers import LayoutLMTokenizer, LayoutLMForSequenceClassification, AdamW
# Load the dataset
# Assuming you have a dataframe named 'df' with columns 'image_path', 'words', 'bbox', 'label'
# The bounding box coordinates should be normalized
# Create a dictionary for label to index mapping
labels = df['label'].unique().tolist()
label2idx = {label: idx for idx, label in enumerate(labels)}
# Load the tokenizer and model
tokenizer = LayoutLMTokenizer.from_pretrained("microsoft/layoutlm-base-uncased")
# Define a function to encode training examples
def encode_training_example(example, max_seq_length=512, pad_token_box=):
words = example['words']
normalized_word_boxes = example['bbox']
assert len(words) == len(normalized_word_boxes)
token_boxes = []
for word, box in zip(words, normalized_word_boxes):
word_tokens = tokenizer.tokenize(word)
token_boxes.extend([box] * len(word_tokens))
special_tokens_count = 2
if len(token_boxes) > max_seq_length - special_tokens_count:
token_boxes = token_boxes[: (max_seq_length - special_tokens_count)]
token_boxes = [] + token_boxes + []
encoding = tokenizer(' '.join(words), padding='max_length', truncation=True)
input_ids = tokenizer(' '.join(words), truncation=True)["input_ids"]
padding_length = max_seq_length - len(input_ids)
token_boxes += [pad_token_box] * padding_length
encoding['bbox'] = token_boxes
encoding['label'] = label2idx[example['label']]
assert len(encoding['input_ids']) == max_seq_length
assert len(encoding['attention_mask']) == max_seq_length
assert len(encoding['token_type_ids']) == max_seq_length
assert len(encoding['bbox']) == max_seq_length
return encoding
# Function to prepare data loaders from dataframe
def training_dataloader_from_df(data_df):
dataset = Dataset.from_pandas(data_df)
features = Features({
'words': Sequence(Value('string')),
'bbox': Sequence(Sequence(Value('int64'))),
'label': Value('string'),
})
encoded_dataset = dataset.map(encode_training_example, features=features, remove_columns=dataset.column_names)
encoded_dataset.set_format(type='torch', columns=['input_ids','bbox', 'attention_mask', 'token_type_ids', 'label'])
dataloader = torch.utils.data.DataLoader(encoded_dataset, batch_size=4, shuffle=True)
return dataloader
# Split train and validation datasets
train_data, valid_data = train_test_split(df, test_size=0.2, random_state=42)
# Create dataloaders
train_dataloader = training_dataloader_from_df(train_data)
valid_dataloader = training_dataloader_from_df(valid_data)
# Define the device to train on
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
# Load the model
model = LayoutLMForSequenceClassification.from_pretrained(
"microsoft/layoutlm-base-uncased", num_labels=len(label2idx)
)
model.to(device);
# Define optimizer
optimizer = AdamW(model.parameters(), lr=4e-5)
# Training loop
num_epochs = 3
for epoch in range(num_epochs):
print("Epoch:", epoch)
training_loss = 0.0
training_correct = 0
model.train()
for batch in tqdm(train_dataloader):
labels = batch["label"].to(device)
outputs = model(
input_ids=batch["input_ids"].to(device), bbox=batch["bbox"].to(device),
attention_mask=batch["attention_mask"].to(device),
token_type_ids=batch["token_type_ids"].to(device), labels=labels
)
loss = outputs.loss
training_loss += loss.item()
predictions = outputs.logits.argmax(-1)
training_correct += (predictions == labels).float().sum()
loss.backward()
optimizer.step()
optimizer.zero_grad()
print("Training Loss:", training_loss / batch["input_ids"].shape)
training_accuracy = 100 * training_correct / len(train_data)
print("Training accuracy:", training_accuracy.item())
validation_loss = 0.0
validation_correct = 0
model.eval()
with torch.no_grad():
for batch in tqdm(valid_dataloader):
labels = batch["label"].to(device)
outputs = model(
input_ids=batch["input_ids"].to(device), bbox=batch["bbox"].to(device),
attention_mask=batch["attention_mask"].to(device),
token_type_ids=batch["token_type_ids"].to(device), labels=labels
)
loss = outputs.loss
validation_loss += loss.item()
predictions = outputs.logits.argmax(-1)
validation_correct += (predictions == labels).float().sum()
print("Validation Loss:", validation_loss / batch["input_ids"].shape)
validation_accuracy = 100 * validation_correct / len(valid_data)
print("Validation accuracy:", validation_accuracy.item())
這個範例程式碼展示了如何使用 LayoutLM 進行文件分類. 其中,需要注意的是,輸入資料需要包含文字內容(words),對應的邊界框座標(bbox),以及類別標籤(label),且邊界框座標需要歸一化到 0-1000 的範圍內.
7. 常見問題
- LayoutLM 和 BERT 的區別是什麼?
- BERT 主要處理文字資訊,而 LayoutLM 同時處理文字、佈局和視覺資訊.
- LayoutLM 透過 2D位置嵌入 和 影象嵌入 來整合佈局和視覺資訊,使其能夠更好地理解文件影象.
- 如何處理不同大小的文件影象?
- 透過 歸一化邊界框座標,使 LayoutLM 能夠處理各種大小的文件影象.
- LayoutLM 可以處理中文文件嗎?
- LayoutLM 可以處理多語言文件,包括中文,前提是使用合適的 tokenizer 和預訓練模型.
- 如何選擇合適的預訓練模型?
- Hugging Face Transformers 庫提供了各種預訓練的 LayoutLM 模型。您可以根據自己的任務和資料選擇合適的模型.
- 如何提高 LayoutLM 的效能?
- 使用高質量的 OCR 結果.
- 使用與任務相關的 微調資料.
- 調整模型 引數,例如學習率和訓練輪數.