Bạn đang phát triển một bảng điều khiển. Để cung cấp dữ liệu cho nó, bạn nhận được một PDF có biểu đồ nhưng không có tệp dữ liệu đã dùng để vẽ biểu đồ đó. Trên màn hình, hai đường cong, các năm và chú giải đều hiện rõ. Tuy nhiên trong ứng dụng, bạn cần thứ khác: những giá trị có thể lưu trữ, so sánh và sử dụng trong phép tính.
Hãy lấy trang hư cấu Vega Energy Summary làm ví dụ. Trang này có hai chuỗi và trục « Energy (MWh) ». Làm sao tìm lại các giá trị rồi tính mức biến thiên mà không nhầm lẫn các chuỗi hoặc đổi MWh thành kWh sai thời điểm?
Chúng ta sẽ dùng DePlot để đề xuất một bảng từ hình ảnh. Sau đó, mã Python sẽ kiểm tra các số và đơn vị trước khi thực hiện phép tính. Mô hình trích xuất; chương trình kiểm soát và tính toán. Sự phân tách này sẽ là mạch xuyên suốt của bài.
Vấn đề cụ thể
Một câu trả lời như « mức tiêu thụ đã tăng 50 % » có thể nghe rất thuyết phục. Tuy vậy, nó không cho biết mô hình đã đọc đúng các năm, giữ được cả hai chuỗi hay hiểu đúng đơn vị chưa. Như ta sẽ thấy trong một ví dụ, ngay cả một tỷ lệ phần trăm đúng cũng có thể đi kèm các lượng sai.
Với một lập trình viên web, vấn đề này giống như nhập dữ liệu: nhận được văn bản không có nghĩa là đã có dữ liệu hợp lệ. Cần nhận diện cấu trúc, kiểm tra các trường và giữ lại lỗi thay vì biến chúng thành giá trị mặc định.
Vì vậy, lộ trình của chúng ta là hình trang → bảng được đề xuất → xác thực → đổi sang kWh → tính toán → đánh giá. Một đầu ra bị từ chối vẫn là kết quả cần xem xét, chứ không phải biểu đồ có mọi giá trị bằng không.
Bộ dữ liệu là tổng hợp: các trang Vega được tạo cho thử nghiệm này. Nhờ đó có thể biết các giá trị kỳ vọng và so sánh dự đoán với một tham chiếu. Những câu trả lời tham chiếu này, đôi khi được gọi là labels hoặc gold trong mã, phục vụ việc đánh giá. Chúng không dùng để sửa một lần trích xuất sau đó.
Các khái niệm trước khi viết mã
DePlot chuyển từ pixel sang bảng như thế nào
DePlot là mô hình hình ảnh sang văn bản dựa trên kiến trúc Pix2Struct. Đầu vào của nó là một hình ảnh; đầu ra là một bảng được viết dưới dạng văn bản. Ở đây chúng ta không lấy lại tệp dữ liệu gốc ẩn phía sau đường cong: mô hình phải đề xuất một bản chép lại từ những gì nó nhìn thấy.
Bộ xử lý chuẩn bị đầu vào. Nó chia hình ảnh thành các vùng nhỏ, gọi là patches, và giữ thông tin về vị trí của chúng. Một patch không nhất thiết là một chữ cái hay một điểm trên đường cong: đó là một vùng ảnh được chuyển thành các con số.
Bộ mã hóa chuyển các số này thành những biểu diễn mà mô hình có thể dùng. Sau đó bộ giải mã tạo đầu ra từng phần. Các phần văn bản này là token: chúng không nhất thiết tương ứng với cả một từ. Prompt là chỉ dẫn nêu tác vụ cần làm, ở đây là chuyển biểu đồ thành bảng. Tài liệu DePlot của Transformers trình bày tác vụ này; tài liệu Pix2Struct mô tả chi tiết kiến trúc và việc chuẩn bị ảnh.
Mô hình vẫn được đóng băng trong suốt hướng dẫn này: các tham số, hay trọng số, của nó không được huấn luyện lại trên Vega. Chúng ta thực hiện suy luận, nghĩa là dùng một mô hình đã được huấn luyện để tạo đầu ra. Vì vậy không có quá trình học trên các trang của lộ trình, cũng không có fine-tuning ẩn trong khâu chuẩn bị.
Việc tạo token của một con số không bảo đảm con số đó đúng. DePlot có thể bỏ sót một chuỗi hoặc viết giá trị gần với giá trị kỳ vọng. Chúng ta giữ bảng thô của nó để có thể tìm lại nguồn gốc lỗi trước mọi biến đổi bằng Python.
Từ đồ thị đến dữ liệu có thể dùng
Trong Vega, một hạng mục là một năm, chẳng hạn 2020. Một chuỗi là tập các giá trị gắn với một đường cong. Để không trộn hai đường cong đi qua cùng một năm, một giá trị phải luôn gắn với chuỗi và hạng mục của nó.
Parsing, hay phân tích đầu ra, là việc chuyển văn bản do DePlot tạo thành một cấu trúc mà chương trình biết cách xử lý. Hãy nghĩ đến việc đọc một CSV: nhận ra hàng và cột không miễn cho bạn việc kiểm tra nội dung của chúng.
Đơn vị là một trường riêng. 2 MWh và 2 kWh có cùng con số nhưng không biểu thị cùng một lượng. Các tiền tố mega và kilo lần lượt tương ứng với một triệu và một nghìn; vì vậy 1 MWh bằng 1000 kWh. Bảng tiền tố của NIST nêu các hệ số này.
Dự án chọn kWh làm đơn vị chuẩn: mọi lượng được chấp nhận đều biểu diễn bằng đơn vị chung này trước các phép toán. « Chuẩn » không có nghĩa là « đúng hơn »; đơn giản đó là biểu diễn nội bộ được chọn để tránh trộn lẫn đơn vị.
Ba hàm chia nhau việc này. recognized_unit yêu cầu đúng một đơn vị được nhận diện trong văn bản nhận được. number chuyển một chuỗi đúng định dạng thành số. canonical áp dụng hệ số chuyển đổi. Không bước nào được chọn hệ số bằng cách xem giá trị kỳ vọng trong các chú thích.
Tính toán chỉ đến sau khi được chấp nhận
Khi bảng đã được chấp nhận, calculate làm việc với các giá trị số và hạng mục theo năm. Hàm sắp xếp các năm, rồi tính giá trị đầu, giá trị cuối, tổng, nhỏ nhất, lớn nhất và mức biến thiên.
Phép tính có tính xác định: với cùng dữ liệu được chấp nhận và cùng ngữ cảnh số học, các công thức tuân theo cùng quy tắc. Chúng ta không yêu cầu mô hình ứng biến một phép cộng hoặc giải thích vì sao một kết quả có vẻ hợp lý.
Chương trình dùng Decimal, một kiểu Python dành cho số học thập phân. Chúng ta sẽ xem vai trò của nó trong mã. Hiện tại, điều quan trọng là ranh giới: kiểm soát phép tính không tự động kiểm soát việc đọc biểu đồ.
Ví dụ về đơn vị và mức biến thiên
Hãy dùng lại một ví dụ đơn giản để hiểu cơ chế, không phải để đưa ra một số đo mới của bộ dữ liệu. Một chuỗi có giá trị 2 MWh năm 2020, rồi 3 MWh năm 2022.
Sau khi chuyển đổi, ta có 2000 và 3000 kWh. Chênh lệch là 1000 kWh. Mức biến thiên tương đối là (3000 - 2000) / 2000 = 0,5, tức 50 %. Mã trả về tỷ lệ 0.5; phần hiển thị phần trăm nhân tỷ lệ này với 100. Đây không phải tăng trưởng hằng năm: công thức so sánh hai đầu mút của giai đoạn.
Đây là cái bẫy: tính (3 - 2) / 2 cũng cho 0,5. Một hệ số giống nhau áp dụng cho cả hai giá trị sẽ triệt tiêu trong tỷ số. Vì thế một tỷ lệ phần trăm đúng không chứng minh các lượng tuyệt đối có đơn vị đúng.
Nếu chú giải chỉ ghi « Energy », hợp đồng của dự án sẽ từ chối phép tính vì không có đơn vị được nhận diện. Điều này không có nghĩa một tỷ số số học là bất khả thi khi không hiển thị đơn vị: nó có nghĩa chương trình của chúng ta không có thông tin cần thiết để chấp nhận bảng và các chuyển đổi của nó. Diễn giải một lượng thật sự tính bằng MWh thành kWh sẽ chia nó cho một nghìn; làm ngược lại sẽ nhân nó lên một nghìn.
Một trường hợp khác: giá trị đầu tiên bằng không. Hiệu với giá trị cuối vẫn tính được, nhưng công thức phần trăm sẽ chia cho không. Khi đó kết quả là None, với trạng thái UNDEFINED_ZERO_BASELINE. Hiển thị 0 % thay vào đó sẽ có nghĩa « không có biến thiên », tức là một thông tin khác.
Cuối cùng, cần quyết định hình nào sẽ đưa cho mô hình. Chế độ full dùng toàn bộ trang. Chế độ crop dùng một vùng cắt do chương trình cung cấp, để tập trung đầu vào vào biểu đồ thay vì tiêu đề, logo hay bảng bên cạnh. Hãy giữ hình chữ nhật này cùng kết quả: đọc một biểu đồ đã được định vị không phải là tự động phát hiện mọi biểu đồ trong báo cáo.
Mã trung tâm
Nhận diện đơn vị, đọc số, chuyển đổi
Đoạn trích sau đến từ src/pdfcharts/units.py. Nó gồm bốn hàm nhỏ. Hãy đọc chúng như các bước của một quy trình nhập dữ liệu có định dạng được chủ ý giới hạn.
"""Recognize units in the extracted text; never infer a factor from gold."""
from decimal import Decimal, InvalidOperation
import re
UNIT = re.compile(r"(?<![A-Za-z])(kWh|MWh)(?![A-Za-z])", re.I)
FACTORS = {"kwh": Decimal(1), "mwh": Decimal(1000)}
def recognized_unit(raw):
found = {m.group(1).lower() for m in UNIT.finditer(raw)}
if len(found) != 1:
raise ValueError("missing_unit" if not found else "conflicting_units")
unit = next(iter(found))
return {"unit": "kWh" if unit == "kwh" else "MWh", "factor": str(FACTORS[unit])}
def without_unit(text):
return UNIT.sub("", text).strip().strip("()[]").strip()
def number(text):
text = without_unit(text).replace("−", "-").strip()
if re.fullmatch(r"[+-]?[0-9]{1,3}(,[0-9]{3})+(\.[0-9]+)?", text):
text = text.replace(",", "")
elif re.fullmatch(r"[+-]?[0-9]{1,3}( [0-9]{3})+(\.[0-9]+)?", text):
text = text.replace(" ", "")
if not re.fullmatch(
r"[+-]?(?:[0-9]+(?:\.[0-9]*)?|\.[0-9]+)(?:[eE][+-]?[0-9]+)?", text
):
raise ValueError("unsupported_numeric_format")
try:
value = Decimal(text)
except InvalidOperation as exc:
raise ValueError("invalid_number") from exc
if not value.is_finite() or abs(value) > Decimal("1e12"):
raise ValueError("numeric_range")
return value
def canonical(value, unit):
return value * Decimal(unit["factor"])
recognized_unit: một đơn vị riêng biệt, không chỉ một lần xuất hiện
UNIT là một biểu thức chính quy tìm kWh hoặc MWh. Cờ re.I bỏ qua chữ hoa chữ thường. Các kiểm tra quanh nhóm ngăn việc nhận diện khi đơn vị dính trực tiếp với một chữ cái được bao bởi [A-Za-z]. Các thao tác của mô-đun re ghi lại các cơ chế này và việc kiểm tra toàn bộ chuỗi.
finditer() duyệt các lần xuất hiện tìm được. Cấu trúc trong ngoặc nhọn tạo một tập hợp, chỉ giữ một bản sao của mỗi đơn vị sau khi chuyển về chữ thường. Vì vậy điểm quan trọng là số đơn vị riêng biệt: hai lần nhắc MWh không tạo thành xung đột.
Với các chuỗi minh họa, hàm hoạt động như sau:
| Văn bản nhận được | Quyết định của recognized_unit |
|---|---|
Energy (MWh) |
Đơn vị MWh, hệ số "1000". |
MWh MWh |
Cùng đơn vị lặp lại: được chấp nhận. |
Energy |
Từ chối: missing_unit. |
Energy MWh / kWh |
Từ chối: conflicting_units. |
Hợp đồng ở đây chỉ bao gồm hai đơn vị. Chẳng hạn, GWh không được nhận diện: nó không tự động nhận một hệ số chỉ vì con người biết phép chuyển đổi đó.
Vẫn còn một giới hạn quan trọng: hàm này xem xét văn bản mà nó nhận được, chứ không trực tiếp xem biểu đồ. Nếu mô hình bỏ sót một đơn vị có trong ảnh, biểu thức chính quy không thể tìm lại nó. Vì vậy việc từ chối các điểm mơ hồ cũng phải được đánh giá trên các trang, không chỉ trên chuỗi kiểm thử.
without_unit và number: chấp nhận một định dạng xác định
without_unit loại bỏ các lần nhắc đơn vị được nhận diện và làm sạch hai đầu chuỗi. Sau đó number chuẩn hóa dấu trừ kiểu in − thành -.
Hai kiểm tra đầu tiên nhận diện một số cách nhóm hàng nghìn: chẳng hạn 1,234.5 và 1 234.5. Dấu phân cách chỉ bị xóa nếu toàn bộ nhóm tuân theo dạng đã định. fullmatch cuối cùng kiểm tra toàn bộ chuỗi còn lại, chứ không chỉ số đầu tiên có thể tìm thấy trong đó.
Dưới đây là các ví dụ về hàm này, độc lập với dự đoán của mô hình:
Chuỗi truyền cho number |
Giá trị hoặc từ chối |
|---|---|
2 MWh |
Số 2, chưa chuyển đổi ở bước này. |
1,234.5 kWh |
Số 1234.5. |
1 234.5 |
Số 1234.5, với dấu cách thông thường. |
1.25e3 |
Số tương đương 1250; e3 nghĩa là « nhân một nghìn ». |
−2.5 MWh |
Số -2.5. |
1,5 |
Từ chối: unsupported_numeric_format. |
1,234 |
Số 1234, không phải số thập phân kiểu Pháp 1,234. |
Lưu ý về quy ước địa phương. Mã quy định dấu chấm thập phân và một số cách viết hàng nghìn. Nó không tự động nhận diện thói quen của từng ngôn ngữ. Thay mọi dấu phẩy bằng dấu chấm sẽ không phải cải tiến trung tính: đặc biệt, điều đó sẽ thay đổi cách hiểu 1,234.
Việc chuyển sang Decimal diễn ra sau kiểm tra hình thức. NaN, tức giá trị « không phải là số », và Infinity đã bị mẫu số từ chối. Kiểm tra is_finite() bổ sung các kiểm soát đó, và một giá trị tuyệt đối lớn hơn 1e12, tức một nghìn tỷ, sẽ kích hoạt numeric_range. Hàm này không cấm số âm: sự phù hợp của chúng sau đó phụ thuộc vào hợp đồng nghiệp vụ.
Trên hết, number không thay thế recognized_unit. Chẳng hạn, loại đơn vị khỏi 2 MWh kWh có thể còn lại số 2. Chính kiểm soát đơn vị riêng biệt phải từ chối văn bản xung đột này. Chuyển đổi số thành công không đủ để chấp nhận dữ liệu.
Vì sao dùng Decimal và chuyển đổi riêng?
Tạo Decimal từ văn bản giữ nguyên biểu diễn thập phân của nó mà không đi qua số thực nhị phân trước. Ví dụ, Decimal("0.1") + Decimal("0.2") cho chính xác Decimal("0.3"). Tuy nhiên, kiểu này không cho độ chính xác vô hạn với mọi phép toán: một phép chia như một phần ba phụ thuộc vào ngữ cảnh độ chính xác và làm tròn. Tài liệu Python về Decimal giải thích sự khác biệt này.
Sau đó canonical thực hiện một phép nhân. Với 2 MWh, number trả về 2 và hệ số là 1000: ta nhận được 2000 kWh. Với 2 kWh, hệ số là 1: ta nhận được 2 kWh. Phép chuyển đổi dùng hệ số được cung cấp; nó không tìm lại đơn vị.
Giới hạn 1e12 được kiểm tra trước phép nhân này. Vì thế không nên trình bày nó là ngưỡng 1e12 kWh cho mọi giá trị đã chuyển đổi. Tương tự, hàm nhỏ này không kiểm tra văn bản nguồn có đúng sự thật không. Mỗi kiểm soát có một vai trò cụ thể, không phải là bảo đảm tổng quát.
Chỉ tính trên các giá trị được chấp nhận
Hãy chuyển sang src/pdfcharts/calculate.py. Ở giai đoạn này, các số được biểu diễn bằng kWh. Hàm không còn nhận ảnh hay bảng DePlot thô: nó nhận một cấu trúc đã được chuẩn bị ở bước trước.
def calculate(table):
result = {}
for series in table["series"]:
values = {
row["category"]: Decimal(row["canonical_kwh"])
for row in table["values"]
if row["series"] == series
}
if not all(re.fullmatch(r"[0-9]{4}", year) for year in values):
raise ValueError("unsupported_category_order")
years = sorted(values, key=int)
first, last = values[years[0]], values[years[-1]]
result[series] = {
"first_category": years[0],
"last_category": years[-1],
"first_kwh": str(first),
"last_kwh": str(last),
"sum_kwh": str(sum(values.values())),
"minimum_kwh": str(min(values.values())),
"maximum_kwh": str(max(values.values())),
"variation": str((last - first) / first) if first != 0 else None,
"variation_status": "DEFINED" if first != 0 else "UNDEFINED_ZERO_BASELINE",
}
return result
Vòng lặp xử lý từng chuỗi riêng biệt. Từ điển values liên kết một hạng mục với giá trị chuẩn của nó và chỉ giữ các hàng của chuỗi hiện tại. Các chuỗi số lại trở thành Decimal để thực hiện phép toán.
Kiểm tra [0-9]{4} sau đó yêu cầu bốn chữ số cho mỗi hạng mục. 2020 phù hợp; Q1 2020 không phù hợp. Đây là hợp đồng về các hạng mục theo năm, không phải cách sắp xếp ngày tháng phổ quát. Kiểm tra này cũng không định nghĩa một khoảng năm nghiệp vụ: nó kiểm tra hình thức.
sorted(values, key=int) sắp xếp các hạng mục này theo số. Do đó giá trị đầu và cuối là hai đầu mút theo thời gian, không phải giá trị nhỏ nhất và lớn nhất. Một đường cong tăng rồi giảm sẽ làm khác biệt này đặc biệt rõ.
Để theo dõi phép tính, đây là một đối tượng minh họa tối thiểu, được xây dựng bằng các trường mà hàm đọc. Đây không phải xuất dữ liệu thực của bộ dữ liệu, cũng không phải lược đồ hoàn chỉnh của bộ phân tích. Nó chỉ chứa một chuỗi để dễ đọc; hai chuỗi Vega được xử lý riêng bởi cùng vòng lặp.
{
"series": ["A"],
"values": [
{"category": "2022", "series": "A", "canonical_kwh": "3000"},
{"category": "2020", "series": "A", "canonical_kwh": "2000"}
]
}
Thứ tự đầu vào bị đảo, nhưng phép tính thực sự bắt đầu năm 2020. Nó tạo first_kwh = "2000", last_kwh = "3000", sum_kwh = "5000", minimum_kwh = "2000", maximum_kwh = "3000" và variation = "0.5", với trạng thái DEFINED.
Tổng chỉ bao gồm các giá trị hiện có. Nó không tạo ra một giá trị cho năm 2021 và không tính diện tích dưới đường cong. Với một chuỗi bắt đầu bằng không, variation sẽ là None, nhưng các kết quả khác vẫn được giữ.
Các lời gọi str() giữ kết quả số ở dạng chuỗi trong đầu ra. Vì vậy frontend phải phân biệt một chuỗi như "0.5", một tỷ lệ phần trăm được hiển thị và việc không có giá trị. Trạng thái đi kèm chính là để không hiển thị một mức biến thiên không xác định như số không.
Đoạn trích này không phải là trình xác thực độc lập cho mọi bảng có thể có. Nó giả định, đặc biệt, các chuỗi không rỗng và hạng mục duy nhất trong mỗi chuỗi. Với đầu vào được tạo có hai hàng cùng hạng mục, việc dựng từ điển sẽ giữ hàng cuối; ở đây nó không phát sinh lỗi trùng lặp. Những bảo đảm này phải được kiểm tra trong khâu chuẩn bị và bộ phân tích của dự án trước khi dùng lại hàm ở nơi khác. Không được gọi trực tiếp phép tính trên một cấu trúc tùy ý do mô hình tạo ra.
Điều kiện tiên quyết và lệnh
Bạn cần biết đọc Python, thao tác với từ điển và dùng terminal với Docker. Không cần biết huấn luyện mạng để theo dõi thử nghiệm này: DePlot vẫn được đóng băng.
Cấu hình tham chiếu dùng Linux, Docker Engine, Compose, trình điều khiển NVIDIA và NVIDIA Container Toolkit, trên RTX 3090 24 Gio. Khuyến nghị là 32 Gio RAM và 25 Gio dung lượng đĩa. RAM là bộ nhớ của máy; 24 Gio của card là bộ nhớ video, hay VRAM. Các chỉ dẫn này chuẩn bị môi trường, không phải mức tối thiểu được bảo đảm cho mọi cấu hình. Cấu hình CPU chưa được xác thực.
Trình điều khiển giúp Linux dùng được GPU. NVIDIA Container Toolkit cung cấp tích hợp cho phép các container truy cập GPU; nó không thay thế việc cài trình điều khiển trên máy chủ. Vì vậy, chỉ nhìn thấy card bằng nvidia-smi là chưa đủ: check_environment.py chạy mô hình trong Docker để kiểm tra tầng thứ hai này.
Giải nén ZIP và mở terminal ở thư mục gốc của nó. Mọi lệnh sau đây đều chạy từ thư mục này, theo thứ tự. Dịch vụ acquisition lấy các tài nguyên đã định; inference thực hiện dự đoán và các xử lý liên quan; tutorial chuẩn bị bộ dữ liệu và các đánh giá. Việc thu nhận được tách riêng, và các dịch vụ suy luận không tham chiếu đến các label tham chiếu.
Bước 1 — chuẩn bị
Hãy bắt đầu với các kiểm tra trước, việc chuẩn bị, xây dựng dịch vụ và thu nhận mô hình. Chúng ta sẽ kết thúc bằng một phép tính trong môi trường container và các kiểm thử của dự án.
sh scripts/preflight.sh
sh scripts/setup.sh
docker compose config --quiet
docker compose build acquisition tutorial inference
docker compose run --rm acquisition python scripts/acquire.py --config configs/minimum.yaml
docker compose run --rm tutorial python scripts/check_environment.py
docker compose run --rm tutorial python -m pytest -q
Mỗi lệnh phải kết thúc với mã trả về bằng không, tức mã thành công. Các kiểm tra bổ sung cho nhau: một cấu hình Compose hợp lệ không chứng minh mô hình đã được thu nhận; thu nhận thành công không chứng minh GPU dùng được; kiểm thử thành công không chứng minh mọi giá trị trích xuất sẽ đúng.
Hãy giữ lại các phiên bản và tệp của bản thu nhận đã khóa trong ZIP. Tài liệu được liên kết trong bài giải thích cơ chế, nhưng ví dụ cài đặt của chúng không thay thế các phụ thuộc của lộ trình r001.
Bước 2 — tạo dự đoán
Bây giờ chúng ta sẽ tạo các trang Vega, yêu cầu DePlot tạo bảng, rồi phân tích các đầu ra.
docker compose run --rm tutorial python -m pdfcharts.cli prepare --config configs/minimum.yaml
docker compose run --rm inference python -m pdfcharts.cli infer --config configs/minimum.yaml
docker compose run --rm inference python -m pdfcharts.cli parse --config configs/minimum.yaml
prepare dựng 120 trang của bộ dữ liệu và cố định các vùng. Việc dựng chuyển trang PDF thành hình ảnh. infer tạo biểu diễn dạng bảng; parse kiểm soát cấu trúc, các chuỗi và đơn vị của nó.
Trước khi đánh giá, hãy mở một hình ảnh và đầu ra văn bản của nó. Tìm các năm, tên chuỗi và đơn vị. Sau đó xem bảng đã phân tích hoặc lý do bị từ chối. Bạn cần có thể theo dấu một giá trị mà không xem câu trả lời kỳ vọng để « sửa » nó.
Việc kiểm tra này trả lời một câu hỏi hữu ích: lỗi đã có sẵn trong đầu ra DePlot, hay xuất hiện khi diễn giải nó? Thay đổi bộ phân tích để che một lần đọc sai của mô hình sẽ khiến bạn không thể biết điều đó.
Bước 3 — đo lường và kiểm soát
Hai lệnh đầu dưới đây tính thống kê trên các bảng được chấp nhận, rồi đánh giá kết quả. Lệnh thứ ba đã chạy bài tập về đơn vị, với configs/exercise.yaml.
Trước khi chạy khối này, hãy ghi lại dự đoán của bạn cho bài tập: điều gì xảy ra nếu 2 MWh được viết lại đúng thành 2000 kWh? Và nếu đơn vị biến mất? Chúng ta sẽ trình bày lời giải trong phần dành cho bài tập, sau các số đo.
docker compose run --rm inference python -m pdfcharts.cli calculate --config configs/minimum.yaml
docker compose run --rm tutorial python -m pdfcharts.cli evaluate --config configs/minimum.yaml
docker compose run --rm tutorial python -m pdfcharts.cli exercise --config configs/exercise.yaml
docker compose run --rm tutorial python lesson/figures/plot.py
docker compose run --rm tutorial python scripts/check_checkpoints.py
docker compose down
calculate chỉ dùng các giá trị được chấp nhận; evaluate có thể so sánh chúng với các tham chiếu riêng. exercise chạy kịch bản được cung cấp. Hai lệnh tiếp theo tạo các hình và chạy kiểm tra tệp của dự án. Tên check_checkpoints.py không có nghĩa là đã diễn ra huấn luyện: mô hình của lộ trình này vẫn được đóng băng.
Lệnh docker compose down cuối cùng dừng các dịch vụ của dự án. Đây không phải lệnh làm sạch các tệp xuất: hãy giữ đầu ra để đọc, rồi dùng thao tác làm sạch có mục tiêu ở cuối bài.
Các thước đo trước các con số
Đo việc trích xuất mà không nhầm các tập hợp
Một chỉ số là phép đo hành vi của chương trình. Trước khi so sánh hai con số, cần biết cái gì đã được đếm và trên những ví dụ nào.
Tỷ lệ chấp nhận là tỷ lệ biểu đồ mà các kiểm soát cho phép có một bảng và một phép tính. Chấp nhận nhiều hơn không phải lúc nào cũng tốt hơn: chấp nhận một đơn vị mơ hồ là lỗi, trong khi từ chối rõ ràng mới là hành vi mong muốn trong trường hợp đó.
MAE, viết tắt của Mean Absolute Error, là sai số tuyệt đối trung bình. Trong một ví dụ hư cấu, các giá trị kỳ vọng 1000 và 2000 kWh, được dự đoán là 990 và 2030 kWh, cho các sai số 10 và 30 kWh. Do đó MAE là (10 + 30) / 2 = 20 kWh. Dấu bị loại bỏ: một lần ước lượng thấp không bù cho một lần ước lượng cao.
Ở đây MAE này là có điều kiện: nó chỉ liên quan đến các giá trị được chấp nhận và có thể so sánh. Nó không trực tiếp phạt các giá trị không sẵn có để so sánh. Vì vậy một phương pháp từ chối các trường hợp khó có thể hiển thị MAE thấp trong khi cung cấp rất ít giá trị. Hãy đọc sai số cùng với mức chấp nhận và độ bao phủ, không bao giờ đọc riêng lẻ. Độ bao phủ ở đây chỉ các phần tử thực sự có thể được so sánh; đừng cho rằng nó hoàn hảo chỉ vì một bảng đã được chấp nhận.
Độ thu hồi chuỗi cho biết các chuỗi kỳ vọng có được tìm thấy hay không. Trong ví dụ hư cấu có bốn chuỗi kỳ vọng, tìm được ba chuỗi, độ thu hồi là 3/4 = 0,75. Các giá trị chính xác trên một đường cong không tự động bù cho việc bỏ quên đường cong kia.
Độ chính xác đơn vị đo mức đúng của đơn vị được nhận diện trong các đầu ra không mơ hồ. Điểm hoàn hảo cho chỉ số này không có nghĩa mọi trang đã được chấp nhận hay mọi con số đều đúng.
Cuối cùng, kiểm soát số học so sánh tổng, giá trị cực trị và biến thiên với các giá trị được chấp nhận sau chuyển đổi. Nó kiểm tra công việc của bộ tính toán, không kiểm tra mức độ trung thực của các giá trị đó với hình ảnh. Trong ví dụ trước, cộng 990 và 2030 cho đúng 3020, trong khi tổng giá trị kỳ vọng là 3000. Phép tính có thể chính xác trên các đầu vào không chính xác.
Xem các lệnh tạo ra gì
Lộ trình chính gồm 90 trang kiểm thử, trong đó có 12 biểu đồ mơ hồ. Bảng sau trình bày các kết quả r001 được báo cáo cho tập này, không trộn chúng với ba trang của bài tập.
| Thước đo trên tập kiểm thử | Vùng được cung cấp: chế độ crop | Toàn bộ trang: chế độ full |
|---|---|---|
| Biểu đồ được chấp nhận | 78/90 | 45/90 |
| MAE có điều kiện, tính bằng kWh | 4,9558 | 26,4075 |
| Độ thu hồi chuỗi | 0,9333 | Không định lượng ở đây |
| Độ chính xác đơn vị | 1,0000 | Không định lượng ở đây |
Một thước đo không được định lượng trong bảng này không phải là số không. Các quần thể so sánh cho MAE phụ thuộc vào đầu ra được chấp nhận của từng chế độ.
Chế độ crop chấp nhận 78 biểu đồ không mơ hồ và từ chối 12 biểu đồ mơ hồ, không quan sát thấy chấp nhận nguy hiểm nào trong các trường hợp đó. Vì vậy tỷ lệ chấp nhận của nó xấp xỉ 86,7 %, so với 50 % cho toàn bộ trang. Các tỷ lệ này chỉ được tính từ các phân số hiển thị.
Sai số có điều kiện thấp hơn của crop là một kết quả hữu ích, nhưng cần ghi nhớ hai giới hạn. Trước hết, hai chế độ không chấp nhận chính xác cùng một quần thể: so sánh MAE không thay thế so sánh từng giá trị trên một tập chung. Tiếp theo, crop đã cung cấp vùng phù hợp cho mô hình; điểm số này không đo khả năng tự tìm một biểu đồ trong trang của nó.
Độ thu hồi chuỗi 0,9333 nhắc đến một giới hạn khác. Một bảng dùng được cho các chuỗi nó chứa không nhất thiết là bản dựng lại đầy đủ mọi chuỗi kỳ vọng. Một chuỗi bị bỏ sót hoàn toàn có thể chỉ lộ ra khi so sánh với tham chiếu, vì suy luận không truy cập các câu trả lời.
Vì vậy kết luận cần giữ không phải là « mọi biểu đồ đều được đọc tốt ». Trên bộ dữ liệu tổng hợp này, vùng cắt được cung cấp giúp có nhiều bảng được chấp nhận hơn và sai số có điều kiện thấp hơn. Vẫn có các chuỗi bị thiếu, và các con số này không thiết lập hiệu năng trên PDF của riêng bạn.
Khắc phục sự cố và đưa vào vận hành
Một giá trị bị từ chối? Trước hết hãy quay lại bản xuất văn bản: đơn vị có hiện diện không? Định dạng có tuân theo quy ước số không? Các chuỗi và hạng mục có dùng được không? Đừng bắt đầu bằng cách thêm hệ số 1000 « vì trông có vẻ là MWh ».
Nếu crop cắt mất chú giải, mô hình không còn nhận đủ thông tin cần thiết. Một vùng đã sửa là đầu vào mới cần đánh giá: hãy giữ vùng cũ và mới, thay vì viết lại hồi tố kết quả của lộ trình tham chiếu.
Khi vận hành, hãy phiên bản hóa mô hình, bản dựng PDF, vùng được cung cấp, bảng thô, các chuyển đổi và lý do từ chối. Khả năng truy xuất này cho phép lần từ con số hiển thị về điều đã thực sự được xử lý. Dữ liệu dùng trong quyết định năng lượng hoặc hóa đơn cũng phải trải qua đánh giá của con người phù hợp với mức độ quan trọng.
Những gì chúng ta đã học
DePlot đề xuất một bảng từ hình ảnh, không huấn luyện lại trong lộ trình này. Bộ phân tích cho nó một dạng có thể khai thác, rồi các kiểm soát rõ ràng chấp nhận hoặc từ chối số và đơn vị. Cuối cùng, chuyển đổi chuẩn cho phép dùng cùng công thức trên các giá trị được chấp nhận.
Các bước này trả lời những câu hỏi khác nhau: tôi đã trích xuất đúng dữ liệu chưa? Nó có thể diễn giải mà không mơ hồ không? Tôi đã tính đúng từ nó chưa? Một chỉ số duy nhất không trả lời cả ba.
Chúng ta cũng thấy rằng mức biến thiên tương đối có thể vẫn đúng dù sai thang đo, một chuỗi vắng mặt có thể thoát khỏi sai số trung bình có điều kiện, và một đơn vị được nhận diện đúng không bảo đảm một con số được đọc đúng. Đây là các phân biệt cụ thể cần giữ cả trong giao diện.
Bài tập — thay đổi đơn vị hoặc làm nó mơ hồ
Hãy lấy lại các giả định đã ghi trước bước 3. Thử nghiệm được chạy bằng lệnh con exercise với configs/exercise.yaml, đã có trong chuỗi lệnh này. Nó không đòi hỏi sửa mã đã được xác thực. Các lệnh làm sạch ở phía dưới, sau khi xem kết quả.
Câu hỏi rất đơn giản: thay đổi cách viết một lượng có nhất thiết thay đổi chính lượng đó không? Trong ví dụ đơn giản của chúng ta, 2 MWh trở thành 2000 kWh. Cách biểu diễn thay đổi, nhưng giá trị chuẩn phải vẫn là 2000 kWh. Năm thứ hai, 3 MWh trở thành 3000 kWh: biến thiên vẫn là 0.5.
Hãy so sánh với một thao tác khác, hoàn toàn để minh họa: chỉ thay văn bản MWh bằng kWh mà vẫn giữ số 2. Đây không phải là chuyển đổi cùng một lượng. Bạn đã mô tả một lượng nhỏ hơn một nghìn lần. Chương trình không được đoán rằng bạn muốn giữ giá trị cũ.
Kịch bản được cung cấp gồm ba trang, trong đó một trang mơ hồ. Trong kết quả tham chiếu, chế độ crop chấp nhận hai bảng và từ chối trang mơ hồ. Hãy so sánh đơn vị nguồn, các giá trị chuẩn và lý do từ chối với dự đoán của bạn. Chuyển đổi rõ ràng giữ nguyên độ lớn; một đơn vị bị thiếu không được suy ra từ điều khiến kết quả có vẻ thỏa đáng.
Thử nghiệm nhỏ này kiểm tra các trường hợp cụ thể. Nó không chứng minh mô hình sẽ biết xử lý mọi định dạng trục, mọi chú giải hoặc mọi đơn vị của một bộ dữ liệu thực.
Quyết định hiển thị gì cho người dùng
Trong giao diện, một bảng được chấp nhận nên hiển thị chuỗi, các hạng mục, đơn vị nguồn, đơn vị chuẩn và kết quả tính toán. PDF và vùng đã xử lý phải vẫn có thể xem để người dùng kiểm soát việc đọc. Đây là yêu cầu cho một tích hợp, không phải lời thông báo về một back-office đã được hướng dẫn này cung cấp.
Với đầu ra bị từ chối, hãy hiển thị lý do: thiếu đơn vị, đơn vị xung đột, định dạng số không được hỗ trợ hoặc cấu trúc chuỗi không dùng được. Che các trường hợp này sẽ tạo ấn tượng rằng các biểu đồ bị bỏ qua chứa số không hoặc không tồn tại.
Cuối cùng, hãy phân biệt giá trị bằng không, giá trị vắng mặt và biến thiên không xác định. Một chuỗi bắt đầu bằng không vẫn có giá trị đầu tiên đã biết; chỉ mức biến thiên tương đối từ cơ sở đó là không xác định. Trạng thái UNDEFINED_ZERO_BASELINE cho phép giải thích tình huống này mà không loại bỏ cả chuỗi.
Đầu ra và lỗi thường gặp
Sau infer, hãy giữ bảng DePlot thô. Sau parse, xem các đơn vị và hạng mục được nhận diện, cũng như các chuỗi hoặc bảng bị từ chối. Sau calculate, kiểm tra hạng mục đầu và cuối cùng cùng trạng thái biến thiên.
Nếu có nhiều đơn vị, lộ trình không cung cấp cách xử lý tổng quát cho biểu đồ nhiều trục. Hãy từ chối trường hợp theo hợp đồng; chia nó thành các bảng con là một điều chỉnh cần được thiết kế và đánh giá riêng, không phải hành vi có thể ngầm gán cho nó.
Nếu ảnh dựng không tốt hoặc chú giải không đọc được, hãy kiểm tra PDF, crop và độ phân giải của nó trước khi đổ lỗi cho bộ phân tích. Bộ phân tích không thể phục hồi chi tiết không được truyền hoặc trích xuất đúng.
Vận hành, giới hạn và làm sạch
Chuyển từ thử nghiệm này sang ứng dụng đòi hỏi đo lường việc trích xuất trên các tài liệu được phép và đại diện cho cách sử dụng của bạn. Các trang Vega cung cấp môi trường có kiểm soát, không phải sự đa dạng của báo cáo khách hàng, bản quét kém chất lượng hay biểu đồ thực.
Với mỗi kết quả, hãy giữ phiên bản tài liệu, trang, vùng đầu vào, phiên bản mô hình, đơn vị, các biến đổi và quyết định chấp nhận hoặc từ chối. Nguồn gốc này giúp kiểm tra; riêng nó không chứng minh từng giá trị đều đúng. Hình chữ nhật crop định vị đầu vào, nhưng không tự động là bằng chứng chính xác cho từng số được tạo ra.
Hãy thêm quyền truy cập vào tài liệu, giám sát dịch vụ, kiểm thử trên định dạng riêng của bạn và đánh giá của con người cho các quyết định quan trọng. Một sự vắng mặt, đơn vị mơ hồ hay vùng không hợp lệ không bao giờ được âm thầm biến thành sự chắc chắn.
Làm sạch sau khi đã lưu kết quả
Sao chép các tệp xuất và hình hữu ích trước khi chạy hai lệnh sau. Lệnh đầu tiên xóa đầu ra; nó không chạy bài tập. Việc làm sạch chỉ nhắm đến outputs/, rồi lệnh dừng cuối cùng kết thúc lộ trình Docker.
docker compose run --rm tutorial python scripts/clean.py --outputs-only
docker compose down
Tài liệu tham khảo để tìm hiểu thêm
Kho lưu trữ chính của DePlot ghi lại việc chuyển một hình thành bảng dữ liệu nền. Tài liệu chính thức của NVIDIA Container Toolkit giải thích tích hợp GPU với container.
Các liên kết bổ sung tới Transformers, Python và tiền tố đơn vị làm sáng tỏ các cơ chế đã trình bày. Các ví dụ số trong bài có tính sư phạm; các số đo của bộ dữ liệu và bài tập vẫn là của lộ trình r001. Để tái tạo lộ trình này, hãy dùng các tệp và cấu hình trong ZIP thay vì thay phiên bản của chúng bằng phiên bản của một ví dụ tài liệu gần đây.
Một giá trị trở nên có thể khai thác khi ta có thể tìm lại nó đến từ đâu, đã được diễn giải như thế nào và vì sao phép tính của nó được cho phép. Đó là lộ trình chúng ta đã xây dựng, không nhầm lẫn một dự đoán dễ đọc với một bằng chứng.