Hãy hình dung một trang back-office hiển thị các ghi chú bảo trì. Bạn muốn tự động nhận ra mã tham chiếu thiết bị, địa điểm và thời hạn, rồi đưa các yếu tố đó cho người phụ trách kiểm tra. Vấn đề không chỉ là xây dựng mô hình: trước hết cần cung cấp cho nó các ví dụ được gán nhãn đúng cách.
Trong một GED, tức hệ thống quản lý tài liệu điện tử, một nhóm không nhất thiết có thể đọc lại và gán nhãn toàn bộ bộ sưu tập. Nên bắt đầu từ những ghi chú nào? Những ghi chú đầu danh sách? Một mẫu ngẫu nhiên? Hay những ghi chú khiến mô hình do dự?
Đó là câu hỏi của gán nhãn chủ động: huấn luyện mô hình đầu tiên với một tập nhỏ đã gán nhãn, cho nó xem các văn bản còn lại, rồi chọn những tài liệu tiếp theo cần gán nhãn. Ta hy vọng các nhãn mới sẽ hữu ích hơn cho việc học. Nhưng ích lợi này phải được đo lường, chứ không thể suy ra từ tên phương pháp.
Chúng ta sẽ xây dựng vòng lặp này trên các ghi chú hư cấu. Một BiLSTM-CRF phát hiện thực thể trong văn bản, một hàng đợi lựa chọn chọn ghi chú trong giới hạn ngân sách, rồi một oracle tách biệt chỉ tiết lộ các nhãn được yêu cầu. Chúng tôi sẽ giải thích các thuật ngữ này trước khi chạy dự án: đây không phải là yêu cầu câu trả lời từ chatbot, cũng không phải phát triển một giao diện rà soát hoàn chỉnh.
Quy trình này là một minh họa có thể tái lập, không phải phép đo năng suất của con người. Oracle là chương trình đã có sẵn đáp án đúng của corpus tổng hợp. Không quan sát người gán nhãn, thời hạn, việc bỏ dở hay thời gian làm việc. Chi phí là quy tắc công bố: 5 + nombre de tokens cho mỗi ghi chú. Chúng ta sẽ giữ rõ sự phân biệt này khi đọc kết quả.
Tải toàn bộ dự án, bản sửa đổi r001
Dữ liệu và quy tắc không rò rỉ
Nhận diện thực thể là tìm một đoạn văn bản chính xác
Ở đây, một thực thể là phần văn bản được gán một kiểu: REFERENCE, SITE hoặc ECHEANCE. Một nhãn chú thích cho biết cả kiểu đó lẫn các ký tự liên quan. Mô hình phải học cách đề xuất cùng thông tin trên một ghi chú mà nó chưa biết nhãn.
Hãy lấy câu sau, chỉ được thêm vào để giải thích cơ chế:
Prévoir AX-14 à Lyon Nord avant le 18 octobre.
Ta muốn nhận ra AX-14 là mã tham chiếu, Lyon Nord là địa điểm và 18 octobre là thời hạn. Một đoạn như vậy được gọi là span. Offset là vị trí của nó trong văn bản gốc: chúng cho phép tô sáng đúng lần xuất hiện, ngay cả khi cùng một giá trị xuất hiện nhiều lần.
Trong ví dụ sư phạm này, đếm ký tự từ 0 và không tính cận cuối, AX-14 chiếm [8, 13), Lyon Nord chiếm [16, 25) và 18 octobre chiếm [35, 45). Ký hiệu [8, 13) có nghĩa là “từ ký tự 8 (bao gồm) đến ký tự 13 (không bao gồm)”. Đây là các vị trí của chính câu minh họa bằng tiếng Pháp, không phải đầu ra mới của dự án.
Corpus giữ lại các offset, kể cả với dấu, dấu câu và mã tham chiếu có gạch nối. Với một giao diện sau này, hãy nhớ điểm cốt lõi: các vị trí phải luôn chỉ cùng một phiên bản văn bản. Sửa khoảng trắng hoặc ký tự sau khi tính offset có thể làm lệch phần tô sáng.
Chia các ghi chú trước khi học
Corpus có 1.800 ghi chú tổng hợp, được tổ chức thành 120 họ, mỗi họ 15 ghi chú. Nó được chia thành 1.260 ghi chú huấn luyện, 270 ghi chú xác thực và 270 ghi chú kiểm thử. Mỗi ghi chú có thể chứa mã tham chiếu, địa điểm và thời hạn; sự hiện diện của chúng không bắt buộc.
Ba tập này, thường gọi là split, có vai trò khác nhau. Tập huấn luyện cung cấp các ví dụ để mô hình học. Tập xác thực là một tập riêng cho các kiểm tra trong quá trình phát triển. Tập kiểm thử dùng để đo kết quả, không cung cấp cho các yêu cầu gán nhãn từ pool.
Một họ nằm hoàn toàn trong một tập duy nhất. Nhờ đó không phân tán các biến thể của cùng một họ giữa huấn luyện và kiểm thử. Điều này không khiến corpus đại diện cho một doanh nghiệp: từ vựng và ngữ pháp của nó vẫn là của một bộ sinh sư phạm có kiểm soát.
Chuyển span thành nhãn BIO
Mạng không nhận trực tiếp các chuỗi cần tô sáng. Văn bản được chia thành token, tức các đơn vị mà chương trình thao tác, rồi mỗi token nhận một nhãn. Token không nhất thiết là một từ hoàn chỉnh; cách tách chính xác là của dự án.
Chúng ta dùng quy ước BIO: B- đánh dấu đầu một thực thể, I- phần tiếp nối và O vị trí nằm ngoài các thực thể cần tìm. Với ba kiểu, ta có bảy nhãn: O, B-REFERENCE, I-REFERENCE, B-SITE, I-SITE, B-ECHEANCE và I-ECHEANCE.
Để hiểu quy ước này, giả sử Lyon và Nord là hai token liên tiếp. Ta gán Lyon là B-SITE, rồi Nord là I-SITE. I- có nghĩa là « tôi tiếp tục một thực thể đã bắt đầu », không phải « tôi bắt đầu một nhóm khác ».
Vì vậy, I-SITE chỉ có thể theo sau B-SITE hoặc I-SITE. Sau O, phải mở địa điểm bằng B-SITE. Sau B-REFERENCE, không thể tiếp tục ngay bằng I-SITE: kiểu sẽ đổi ngay giữa thực thể.
Từ vựng chỉ được xây dựng từ các văn bản huấn luyện. Các câu tạo thành các cửa sổ tối đa 128 token, không chồng lấp. Việc tách không xem nhãn ẩn để chọn ranh giới thuận tiện: nếu một thực thể cắt qua ranh giới, corpus bị xem là không hợp lệ. Hạn chế này thuộc về quy trình được trình bày; đây không phải giải pháp chung cho tài liệu có độ dài bất kỳ.
Oracle chỉ được can thiệp sau lựa chọn
Hạt ngẫu nhiên, hay seed, có giá trị 17. Ở đây nó chọn 60 ghi chú huấn luyện ban đầu, để lại 1.200 ghi chú trong pool. Pool là kho ghi chú có văn bản sẵn có, nhưng nhãn chưa được tiết lộ cho quy trình học.
Với một lập trình viên web, hãy hình dung hai dịch vụ có quyền khác nhau. Dịch vụ đầu biết lập danh sách các định danh cần xử lý. Dịch vụ thứ hai có các nhãn và chỉ trả chúng cho một yêu cầu được phép.
Dự án hiện thực hóa sự tách biệt này: tiến trình xếp hạng pool không mount oracle cũng không mount tệp nhãn ẩn. Nó ghi một yêu cầu ID và tính dấu vân tay, hay hash, để nhận diện yêu cầu đã lưu. Sau đó oracle chỉ mở các tệp được yêu cầu, từ chối bản trùng, ghi chú ngoài tập huấn luyện hoặc chi phí không nhất quán, rồi trả về các span.
Hash nhận diện yêu cầu; việc không có quyền truy cập nhãn ngăn đọc chúng trong lúc lựa chọn. Đây là hai vai trò khác nhau. Một quy ước đơn giản « không nhìn đáp án » khó kiểm chứng hơn một tiến trình không hề có các tệp đó.
Nếu không tách biệt như vậy, ta có thể chọn ghi chú khi đã biết lỗi của mô hình trên nhãn thật của chúng. Khi đó ta không còn đo một chiến lược khám phá đáp án dần dần, mà là chiến lược được đáp án hỗ trợ trước khi yêu cầu.
BiLSTM-CRF: từ token đến một chuỗi hợp lệ
Tên gọi kết hợp hai cơ chế. BiLSTM cung cấp ngữ cảnh cho mỗi token. CRF đánh giá các chuỗi nhãn để tạo ra một chuỗi tuân thủ quy tắc BIO. Hãy tách hành trình này thay vì xem toàn bộ như hộp đen.
Từ định danh đến điểm nhãn
Một embedding là vector, tức danh sách số, gắn với một token trong từ vựng. Ở đây mỗi vector có 64 giá trị, được học từ đầu cùng phần còn lại của mô hình. Đây không phải các biểu diễn lấy từ một mô hình lớn đã tiền huấn luyện. Tài liệu torch.nn.Embedding mô tả bảng ánh xạ này giữa định danh và vector.
LSTM, viết tắt của Long Short-Term Memory, là mạng duyệt một chuỗi và giữ lại trạng thái. Phiên bản hai chiều thực hiện việc duyệt theo cả hai hướng. Vì vậy một token hưởng ngữ cảnh đứng trước và đứng sau nó. Với 64 đơn vị mỗi chiều, hai đầu ra ghép lại tạo 128 giá trị mỗi token, đúng như cơ chế mô tả trong tài liệu LSTM 2.8.
Hai lớp dropout 0,25 bao quanh LSTM. Dropout tạm thời đặt về 0 các thành phần số được chọn ngẫu nhiên; nó không bỏ các từ khỏi ghi chú và cũng không xóa vĩnh viễn tham số. Vai trò của cơ chế này trong phép đo độ bất định sẽ đến ở phần sau.
Cuối cùng, một phép chiếu biến 128 giá trị thành bảy điểm phát xạ, một điểm cho mỗi nhãn BIO. Phát xạ cho biết mức độ mô hình ưu tiên một nhãn tại vị trí này. Điểm thô đó chưa phải xác suất hay span hoàn chỉnh.
Với cửa sổ minh họa mười token, luồng xử lý là: mười định danh, rồi bảng 10 × 64, bảng có ngữ cảnh 10 × 128 và cuối cùng là 10 × 7 điểm. Tensor đơn giản là bảng số mang các giá trị đó.
Vì sao không chọn nhãn tốt nhất ở từng vị trí?
Vì một dãy lựa chọn cục bộ tốt có thể tạo thành chuỗi bị cấm. Đây là phép tính sư phạm nhỏ trên Lyon Nord, rút còn ba nhãn để dễ đọc. Các điểm này được tạo ra để giải thích, không lấy từ quá trình huấn luyện.
| Token | Điểm O |
Điểm B-SITE |
Điểm I-SITE |
|---|---|---|---|
| Lyon | 3 | 2 | 0 |
| Nord | 0 | 1 | 4 |
Chọn số lớn nhất ở mỗi hàng cho O → I-SITE, tổng 3 + 4 = 7. Nhưng chuỗi này thông báo một phần tiếp nối mà chưa mở địa điểm.
Giả sử trong phép tính này mọi điểm bắt đầu, kết thúc và chuyển tiếp được phép đều bằng 0. Chuỗi hợp lệ tốt nhất trở thành B-SITE → I-SITE, với điểm 2 + 4 = 6. Vì vậy lựa chọn toàn cục không nhất thiết là chuỗi các cực đại cục bộ.
CRF, viết tắt của Conditional Random Field hay trường ngẫu nhiên có điều kiện, chính xác là gán điểm cho cả một đường đi. Nó kết hợp phát xạ, điểm bắt đầu, điểm kết thúc và các chuyển tiếp giữa nhãn liên tiếp. Trong dự án này, một chuyển tiếp được lập chỉ mục theo hướng trước sang hiện tại.
Đưa quy tắc BIO vào phép tính
Đoạn mã sau xây dựng các điều kiện cho phép bắt đầu và chuyển tiếp. TAGS là danh sách nhãn của dự án; đoạn trích dùng trong môi trường của nó, được cung cấp trong ZIP.
def bio_constraints(tags=TAGS):
start = torch.tensor([not t.startswith("I-") for t in tags])
transitions = torch.ones((len(tags), len(tags)), dtype=torch.bool)
for previous, a in enumerate(tags):
for current, b in enumerate(tags):
if b.startswith("I-"):
transitions[previous, current] = a in ["B-" + b[2:], "I-" + b[2:]]
return start, transitions
start là mảng boolean: giá trị đúng cho phép nhãn bắt đầu chuỗi. Do đó ba nhãn I- bị cấm ở đầu.
transitions là ma trận 7 × 7, ban đầu chứa các giá trị đúng. Vòng lặp xét từng cặp. Nếu nhãn hiện tại b bắt đầu bằng I-, b[2:] lấy kiểu của nó, chẳng hạn SITE. Chuyển tiếp chỉ được giữ nếu nhãn trước là B-SITE hoặc I-SITE.
Ngược lại, B- có thể mở một thực thể mới và O có thể thoát khỏi thực thể. Hàm xác định điều được phép, không phải điểm học được của từng chuyển tiếp. Sau đó CRF khai thác các ràng buộc này khi huấn luyện và giải mã.
Sắc thái này rất quan trọng: dự án không tạo chuỗi bất hợp lệ rồi sửa sau. Các đường đi bị cấm được loại khỏi phép tính dự kiến. Một chuỗi hợp lệ vẫn có thể sai: không gì ngăn mô hình chọn sai địa điểm trong khi vẫn tuân thủ BIO hoàn hảo.
Học với mọi đường đi, dự đoán bằng đường tốt nhất
Hai phép tính dùng cùng một tập đường đi được phép, nhưng trả lời hai câu hỏi khác nhau.
Viterbi tìm đường đi tốt nhất. Nó giữ các điểm trung gian tốt nhất và tiền nhiệm tương ứng, rồi lần ngược các lựa chọn ấy ở cuối. Những bước truy vết này tái dựng toàn bộ chuỗi. Nhờ vậy ta không cần liệt kê tường minh mọi tổ hợp nhãn.
Chuẩn hóa logZ cộng trọng số của mọi đường đi được phép. Mỗi điểm trở thành trọng số dương nhờ lũy thừa. Z là tổng của chúng và logZ là logarit của tổng đó. Xác suất của một đường đi khi ấy là exp(score_du_chemin - logZ).
Hàm mất mát, gọi là NLL cho negative log-likelihood, bằng logZ - score_gold. Ở đây gold là chuỗi tham chiếu được tiết lộ để huấn luyện. Giảm mất mát này khiến mô hình gán xác suất cao hơn cho chuỗi đúng, tương đối với các đường hợp lệ khác. Hướng dẫn BiLSTM-CRF của PyTorch giải thích chi tiết khác biệt giữa chuẩn hóa và giải mã.
Trong ví dụ hai token của chúng ta, năm đường hợp lệ có các điểm 3, 4, 2, 3 và 6. Ta có logZ ≈ 6,2257. Nếu tham chiếu là B-SITE → I-SITE, mất mát của nó xấp xỉ 0,2257, và xác suất xấp xỉ 0,7979. Là đường tốt nhất không có nghĩa xác suất bằng 1.
Phép tính được thực hiện trong log-space, tức không gian logarit, để giảm khó khăn số học. Phép log-sum-exp tính ổn định logarit của tổng các số mũ. Nó không thay tổng bằng cực đại: làm vậy sẽ đổi bài toán.
Có xác suất theo token mà không quên ngữ cảnh
Để chọn các ghi chú cần gán nhãn, ta cần biên CRF: xác suất của mỗi nhãn ở mỗi vị trí, có xét các đường đi hoàn chỉnh. Từ « biên » nghĩa là gộp các khả năng ở vị trí khác để tập trung vào vị trí này.
Đó không phải softmax đơn giản áp dụng độc lập cho bảy phát xạ. Phép tính xuôi-ngược kết hợp đóng góp đi tới một vị trí và rời khỏi nó. Với quy ước của dự án, công thức là exp(alpha + beta - logZ). Ở mỗi token thực, tổng bảy xác suất phải bằng 1.
Trong quy trình, phép tính này dùng độ chính xác FP64 từ các phát xạ FP32, để hạn chế lỗi làm tròn. Huấn luyện GPU vẫn ở FP32: không chuyển toàn bộ mạng sang độ chính xác kép. Lưới nhỏ dùng giải thích đường đi có ba nhãn; mô hình của hướng dẫn thực sự dùng bảy nhãn.
Độ bất định: BALD thực sự xấp xỉ điều gì
Giờ ta biết dự đoán thực thể. Còn phải chọn những ghi chú tiếp theo để gán nhãn, mà không nhìn đáp án của chúng. Chiến lược được nghiên cứu so sánh nhiều dự đoán từ cùng một mạng với dropout đang hoạt động.
Làm thay đổi phép tính mà không huấn luyện lại tám mô hình
Quy trình thực hiện tám lượt với dropout. Các tham số đã học giữ nguyên, nhưng mặt nạ dropout thay đổi và tạo tám phân phối biên cho mỗi token. Sự lặp lại này gọi là Monte Carlo dropout: nhiều phép tính ngẫu nhiên dùng để xấp xỉ một đại lượng không tính chính xác trực tiếp.
Dropout chuẩn của PyTorch hoạt động khi huấn luyện và bị tắt ở chế độ đánh giá. Vì vậy để ước lượng bất đồng, cần giữ biến thiên này trong các lượt được dành cho nó. Đây không phải tám lần huấn luyện mới, cũng không phải tám nhóm người gán nhãn độc lập.
BALD là tiêu chí học chủ động dựa trên sự bất đồng. Trong khuôn khổ Bayes, nó nhắm tới thông tin mà một câu trả lời có thể mang lại về tham số mô hình. Bài báo về BALD với dropout trình bày phép xấp xỉ bằng các lượt ngẫu nhiên. Ở đây, chúng ta áp dụng phép tính kiểu đó cho các biên token của CRF, chứ không trực tiếp cho mọi chuỗi có thể.
Do dự giống nhau không phải là mâu thuẫn
Entropy đo mức độ một phân phối trải trên nhiều khả năng. Với hai xác suất 0,5 và 0,5, entropy cao hơn so với 0,9 và 0,1. Phép tính của dự án dùng logarit tự nhiên; vì thế các giá trị entropy không phải phần trăm.
Với một token, ta tính: entropy của phân phối trung bình, trừ trung bình các entropy. Vế đầu xem toàn bộ dự đoán cùng nhau; vế sau xem từng lượt do dự bao nhiêu.
Hãy lấy hai lượt và hai nhãn, chỉ để có thể tính bằng tay. Dự án dùng tám lượt và bảy nhãn, nhưng phép trừ không đổi.
Trường hợp thứ nhất: cả hai lượt trả lời [0,5 ; 0,5]. Trung bình của chúng là [0,5 ; 0,5]. Entropy của trung bình xấp xỉ 0,6931, giống entropy trung bình. Vì thế độ bất đồng tính được bằng 0. Các lượt do dự, nhưng do dự giống nhau.
Trường hợp thứ hai: một lượt trả lời [0,9 ; 0,1], lượt kia [0,1 ; 0,9]. Trung bình vẫn là [0,5 ; 0,5], nên entropy vẫn là 0,6931. Tuy nhiên mỗi lượt quyết đoán hơn: entropy xấp xỉ 0,3251. Hiệu số đạt khoảng 0,3681.
Phân phối trung bình giống nhau trong hai trường hợp, nhưng độ bất đồng thì không. Đây là điều phép trừ này phân biệt được. Ngược lại, nhiều lượt có thể rất chắc chắn về cùng một đáp án sai: điểm thấp không đảm bảo nhãn đúng.
Từ bất đồng của token đến mức ưu tiên của ghi chú
Chương trình cộng đóng góp của các token thực trên các cửa sổ của một ghi chú, rồi chia cho chi phí: 5 + nombre de tokens. Padding, tức phần đệm thêm để gom các chuỗi có độ dài khác nhau, bị loại bằng mặt nạ. Phần đệm giúp tính theo lô; nó không được tạo thông tin hư cấu.
Do đó điểm là một xấp xỉ BALD biên theo token, có tính đến chi phí. Các token liên hệ với nhau qua CRF; cộng đóng góp của chúng không tính thông tin tương hỗ có điều kiện chính xác của toàn bộ chuỗi và có thể đếm các tín hiệu phụ thuộc. Kết quả không phải xác suất lỗi, cũng không đo lợi ích con người của một nhãn chú thích.
Đây là hàm nguồn. probabilities có dạng M × T × K: số lượt, số vị trí, số nhãn. Trong quy trình, M = 8 và K = 7.
import math
import torch
def marginal_bald_score(probabilities, mask, cost):
# M x T x K; sum token-wise proxy, not joint-sequence mutual information.
if (
probabilities.ndim != 3
or probabilities.shape[1] != len(mask)
or probabilities.shape[0] < 2
or cost <= 0
or not torch.isfinite(probabilities).all()
or (probabilities < 0).any()
):
raise ValueError("Invalid dropout marginals/cost")
if not torch.allclose(
probabilities[:, mask].sum(-1),
torch.ones_like(probabilities[:, mask, 0]),
atol=1e-5,
):
raise ValueError("Real-token marginals must normalize")
entropy = lambda p: -(
torch.where(p > 0, p * torch.log(p.clamp_min(1e-30)), torch.zeros_like(p))
).sum(-1)
values = entropy(probabilities.mean(0)) - entropy(probabilities).mean(0)
if values[mask].min() < -1e-5:
raise ValueError("Negative information proxy beyond rounding tolerance")
return float(values[mask].clamp_min(0).sum() / cost), values.masked_fill(~mask, 0)
Khối đầu tiên kiểm tra, trong đó có, ba chiều, sự khớp giữa số vị trí và độ dài mặt nạ, ít nhất hai lượt, giá trị không hữu hạn hoặc âm, và chi phí nhỏ hơn hoặc bằng 0. Khối tiếp theo kiểm tra mỗi phân phối token thực có tổng bằng 1. Chỉ có một bảng số dương chưa đủ để có các xác suất nhất quán.
Hàm nhỏ entropy cộng theo chiều cuối, chiều các nhãn. Cách xử lý số 0 tránh để chúng đóng góp log(0); clamp_min(1e-30) bảo vệ đối số logarit. Sau đó probabilities.mean(0) lấy trung bình các lượt trước khi tính entropy, còn entropy(probabilities).mean(0) lấy trung bình các entropy đã tính.
Trong số học chính xác, hiệu này không âm với các phân phối hợp lệ. Ngưỡng -1e-5 chấp nhận sai lệch làm tròn rất nhỏ; giá trị âm hơn sẽ gây lỗi. clamp_min(0) loại các phần dư âm nhỏ đó khỏi điểm được cộng.
Hàm trả về hai đối tượng: một điểm vô hướng đã chia chi phí và một vector đóng góp có các vị trí padding được đặt về 0. Đối tượng thứ hai giữ các giá trị trước clamp_min(0) của điểm; vì vậy các phần dư âm rất nhỏ vẫn có thể xuất hiện ở đó.
Đoạn trích giả định mặt nạ boolean có ít nhất một token thực và chi phí vô hướng hữu hạn. Bản thân nó không kiểm tra toàn bộ điều kiện tiên quyết này và không tính lại chi phí từ văn bản. Kiểm tra tính nhất quán của chi phí bằng giao thức và oracle vẫn là bước riêng. Âm thầm sửa phân phối hoặc chi phí để tránh bị từ chối sẽ làm thay đổi thí nghiệm.
Chi ngân sách, không phải lấp đủ một hạn ngạch tài liệu
Theo quy tắc của chúng ta, một ghi chú hai mươi token tốn 25 đơn vị. Đó không phải hai mươi lăm giây. 5 là thành phần cố định của chi phí mô phỏng, còn số token là thành phần biến đổi.
Ví dụ sư phạm khác: một ghi chú có tổng đóng góp 0,6 và chi phí 100 nhận ưu tiên 0,006. Một ghi chú khác có tổng 0,4 và chi phí 40 nhận 0,01. Ghi chú thứ hai xếp trước, dù đóng góp thô thấp hơn, vì xếp hạng diễn ra theo đơn vị chi phí.
Mốc tham chiếu, hay baseline, là lựa chọn ngẫu nhiên với độ ưu tiên xác định và không hoàn lại: đã chọn thì ghi chú không quay lại kho chờ gán nhãn. « Xác định » ở đây nghĩa cùng quy trình có thể tìm lại thứ tự dự kiến, không phải thứ tự đó khai thác độ bất định của mô hình.
Ngẫu nhiên và BALD dùng chung 60 ghi chú ban đầu, các ngưỡng, kiến trúc và tập kiểm thử. Mỗi chu kỳ thêm tối đa 4.000 đơn vị. Ghi chú không vừa ngân sách còn lại bị bỏ qua, rồi hàng đợi tiếp tục. Với 30 đơn vị còn lại, một ghi chú tốn 35 có thể bị loại trong khi ghi chú sau tốn 20 vẫn vào chu kỳ: ví dụ này minh họa quy tắc, không thêm một phép đo cho quy trình.
Ta có một xếp hạng kiểm soát ngân sách, không phải bằng chứng tập được chọn là tối ưu. Hai chiến lược có thể kết thúc cùng số chu kỳ nhưng mức chi khác nhau. Vì vậy ta sẽ so sánh F1 theo chi phí tích lũy thực sự đã dùng, không chỉ theo số chu kỳ.
Thực hiện 21 lệnh được xác nhận
Chuẩn bị môi trường và kiểm tra các phép tính
Bạn cần đọc được Python và dùng terminal với Docker. Các khái niệm hữu ích là tensor, xác suất, chuỗi và gradient. Các ví dụ trước cung cấp mốc để đọc; khối mã được chèn vào dự án hoàn chỉnh, không phải một script tách biệt để tự tái dựng.
Cấu hình tham chiếu dùng Linux và RTX 3090 24 Gio, với 16 Gio RAM và 10 Gio đĩa làm việc, ngoài dung lượng Docker. Đây là khuyến nghị chuẩn bị, không phải mức tối thiểu được đo trên mọi cấu hình. RAM là bộ nhớ máy; 24 Gio của card là bộ nhớ video.
Tích hợp giữa Docker và GPU NVIDIA phải hoạt động. Tài liệu NVIDIA Container Toolkit mô tả tích hợp này. GPU hiện trên máy chủ là chưa đủ: check_environment.py thực hiện forward và backward của BiLSTM-CRF trong container. Forward tạo điểm từ đầu vào; backward tính gradient cần cho học.
Giải nén ZIP vào một thư mục mới và đặt terminal ở thư mục gốc. Mọi lệnh sau đều chạy từ thư mục này. Chúng ta sẽ nối 15 lệnh của quy trình chính, một lệnh bài tập và năm lệnh cuối, thành 21 lệnh của quy trình cung cấp.
sh scripts/preflight.sh
sh scripts/setup.sh
docker compose config --quiet
docker compose build acquisition tutorial learning inference initialization oracle
docker compose run --rm --no-deps acquisition python scripts/acquire.py --config configs/minimum.yaml
docker compose run --rm --no-deps tutorial python scripts/check_environment.py
docker compose run --rm --no-deps tutorial python -m pytest -q
Preflight kiểm tra môi trường; setup chuẩn bị dự án; Compose kiểm tra cấu hình rồi xây các dịch vụ. Acquisition kiểm tra một registry trống: không cần mô hình đã tiền huấn luyện. Vì vậy bước này không phải tải LLM hay embedding bên ngoài.
Kiểm tra môi trường sau đó xác minh việc tính trong Docker, rồi pytest chạy các kiểm thử dự án. Mã trả về bằng 0 báo mỗi lệnh thành công. Kiểm thử chương trình không thay thế phép đo chất lượng thực thể, sẽ đến sau.
Tạo corpus và tiết lộ các nhãn đầu tiên
Các dịch vụ không cùng vai trò. initialization khởi chạy các thao tác khởi tạo; oracle tiết lộ nhãn được phép; vai trò học và suy luận vẫn tách biệt. Các mount trong tệp Compose thể hiện quyền truy cập dự kiến. Việc tính bị cô lập khỏi mạng và oracle không dành GPU.
docker compose run --rm --no-deps tutorial python -m ged_annotation_active_entites.cli prepare --config configs/minimum.yaml
docker compose run --rm --no-deps initialization python -m ged_annotation_active_entites.cli request-initial --config configs/minimum.yaml
docker compose run --rm --no-deps oracle python -m ged_annotation_active_entites.cli reveal --config configs/minimum.yaml
docker compose run --rm --no-deps initialization python -m ged_annotation_active_entites.cli baseline --config configs/minimum.yaml
docker compose run --rm --no-deps initialization python -m ged_annotation_active_entites.cli predict --config configs/minimum.yaml --cycle 0
prepare xây corpus và các phân vùng. Hãy kiểm tra các số 1.260 / 270 / 270 và sự tách các họ trước khi diễn giải một chỉ số.
request-initial yêu cầu 60 ghi chú đầu tiên, rồi reveal cung cấp span của chúng. Hai thao tác vẫn tách biệt: yêu cầu tồn tại trước khi nhãn được trả về. Lệnh baseline tạo điểm khởi đầu và predict --cycle 0 sinh dự đoán của chu kỳ đầu.
Chu kỳ 0 không phải mô hình chưa huấn luyện. Đó là điểm so sánh sau khi học từ nhãn ban đầu, trước bốn chu kỳ gán nhãn bổ sung. Nhầm hai trạng thái này sẽ thay đổi hoàn toàn cách diễn giải kết quả.
Kiểm tra cơ chế trước khi nhân số chu kỳ
docker compose run --rm --no-deps tutorial python -m ged_annotation_active_entites.cli inspect-mechanism --config configs/minimum.yaml
Bước này liên kết các phép tính với biểu diễn của chúng. Trên một chuỗi, hãy phân biệt đường BIO được chọn với các phân phối biên. Kiểm tra mỗi token thực có phân phối tổng khối lượng bằng 1 và các vị trí đệm không đóng góp vào điểm lựa chọn.
Lưới đơn giản hóa ba nhãn giúp đọc cơ chế; nó không mô tả việc giảm mô hình thật xuống ba nhãn. Tương tự, các ví dụ số nhỏ trong bài này là giải thích, không phải kết quả huấn luyện mới.
Chạy bốn chu kỳ, rồi đánh giá
sh scripts/run_all.sh
docker compose run --rm --no-deps tutorial python -m ged_annotation_active_entites.cli evaluate --config configs/minimum.yaml
run_all.sh nối lựa chọn, tiết lộ và học trong bốn chu kỳ. Các nhãn nhận được dần làm giàu tập huấn luyện. Mỗi chiến lược tôn trọng các ngưỡng, nhưng không nhất thiết yêu cầu cùng ghi chú.
Ở mỗi chu kỳ, mô hình quay về cùng tham số chưa huấn luyện, rồi học tám epoch trên các nhãn hiện có. Một epoch là một lượt qua các ví dụ huấn luyện; một chu kỳ gán nhãn gồm chọn ghi chú mới và học sau đó. Tám epoch không có nghĩa tám yêu cầu gán nhãn mới.
Lựa chọn này không phải fine-tuning liên tục mô hình của chu kỳ trước. Nhãn được tích lũy, nhưng trọng số quay về cùng trạng thái ban đầu ở mỗi chu kỳ. Điều đó cố định điều kiện so sánh chiến lược; tái sử dụng trọng số chu kỳ trước sẽ là một thí nghiệm khác.
Bộ tối ưu là AdamW, với lr=0,003, weight_decay=0,001, batch 16 và clipping 1. Batch là lô ví dụ được xử lý khi học. Gradient mô tả mất mát thay đổi theo tham số ra sao; bộ tối ưu dùng chúng để điều chỉnh. Tốc độ lr điều chỉnh biên độ cập nhật, còn weight decay áp dụng điều chuẩn trọng số. Tài liệu AdamW nêu rõ cơ chế này.
Clipping giới hạn biên độ gradient theo quy tắc dự án. Nó không giới hạn điểm F1 hay số ghi chú được chọn. Để hiểu nguyên tắc giới hạn chuẩn, tài liệu clip_grad_norm_ cung cấp thêm thông tin.
Tiếp tục sau gián đoạn không phải bắt đầu lại một chu kỳ
Quy trình cũng kiểm tra một gián đoạn sau epoch 4 của chu kỳ 2. Lần này cần tiếp tục việc học đã bắt đầu, không quay về tham số khởi tạo của chu kỳ.
Checkpoint, hay điểm lưu, phải khôi phục mô hình, bộ tối ưu, sampler tổ chức lấy mẫu, RNG hay bộ sinh giả ngẫu nhiên, pool, yêu cầu và nhãn. Chỉ khôi phục trọng số là chưa đủ: hàng đợi khác hoặc các lần rút dropout mới có thể làm phần tiếp theo thay đổi.
Kiểm tra yêu cầu các lựa chọn và dự đoán tương lai vẫn giống hệt quy trình không gián đoạn. Điều này khắt khe hơn việc có cùng F1 cuối: hai mô hình có thể cùng điểm nhưng không đi qua cùng thí nghiệm.
Việc xác minh này áp dụng cho môi trường được tái lập. Tài liệu PyTorch về khả năng tái lập nhắc rằng cùng một seed không đảm bảo kết quả giống nhau sau khi đổi phiên bản hay nền tảng.
Đọc F1 và chi phí bằng một ví dụ
Ranh giới gần đúng vẫn là lỗi trích xuất
Phép đo dựa trên span chính xác: các ranh giới ký tự và kiểu phải khớp tham chiếu. Nó không chỉ kiểm tra một số từ có chồng lấn hay không.
Nếu tham chiếu chờ AX-14 nhưng mô hình chỉ dự đoán AX, nó bỏ sót thực thể chính xác cần có: đó là âm tính giả. Nó cũng phát ra một thực thể không khớp tham chiếu: đó là dương tính giả. Hai số đếm không đại diện cho hai ghi chú sai; chúng mô tả hai mặt của cùng một lần trích xuất sai.
Độ chính xác đo tỷ lệ span dự đoán là đúng. Độ bao phủ đo tỷ lệ span cần có đã được tìm lại. F1 kết hợp hai đại lượng bằng trung bình điều hòa, để độ chính xác tốt không che đi độ bao phủ kém, hoặc ngược lại.
Hãy lấy lại ví dụ quy trình: 8 span đúng, 2 dự đoán thừa và 2 span bị quên. Độ chính xác là 8 / (8 + 2) = 0,8, độ bao phủ cũng 0,8, và F1 là 2 × précision × rappel / (précision + rappel) = 0,8.
Báo cáo giữ các kiểu thực thể, support của chúng, tức số lượng tham chiếu, và chẩn đoán ranh giới. Các chi tiết này giúp hiểu lỗi; chúng không biến một khớp một phần thành thành công cho F1 chính xác.
Đặt ngân sách, chứ không phải chu kỳ, trên trục ngang
Đường cong đặt F1 trên trục tung và đơn vị gán nhãn thực sự đã tiêu thụ trên trục hoành. Số chu kỳ là chưa đủ: hai hàng đợi có thể yêu cầu ghi chú dài khác nhau và chi các mức khác nhau.
Ví dụ, so sánh một phương pháp sau 3.000 đơn vị và phương pháp khác sau 4.000 đơn vị không trực tiếp đo chất lượng ở cùng ngân sách. Cần có các điểm tương ứng. Quy trình không tạo lợi ích bằng nội suy giữa các ngân sách khác nhau.
Cuối cùng, chỉ một seed được chạy. Không có trung bình trên ba seed, cũng không có dải bất định quanh các đường cong. Tái tạo chính xác một quy trình kiểm tra khả năng tái lập; nó không đo biến thiên có thể thấy với các lần rút ban đầu khác.
Kết quả của quy trình chính
Trên 270 tài liệu kiểm thử, F1 chính xác đã bằng 1 sau 60 nhãn ban đầu. Nó vẫn là 1 sau bốn chu kỳ bổ sung, cho hai chiến lược chính: ngẫu nhiên và BALD.
Chi phí cuối được công bố là 18.661 đơn vị cho ngẫu nhiên và 18.620 cho BALD. Chênh lệch 41 đơn vị đến từ thứ tự lựa chọn và chi phí các ghi chú. Nó không tương ứng với số phút làm việc được tiết kiệm.
Có thể kết luận gì? Mô hình đã vượt qua kiểm thử ngay tại điểm bắt đầu của phép so sánh này. Thêm nhãn không thể làm F1 đã bằng 1 tăng lên. Vì vậy corpus và điểm khởi đầu không còn cho phép phân biệt các chiến lược bằng phép đo này.
Kết quả này không chứng minh BALD có lợi, cũng không chứng minh nó vô ích nói chung. Nó cũng không chứng minh 60 nhãn là mức tối thiểu cần thiết: chúng ta chưa đo mọi ngân sách nhỏ hơn. Thành công chỉ áp dụng cho các ghi chú tổng hợp này và bài kiểm thử này, không phải tài liệu của một GED thực tế.
Dù vậy vòng lặp vẫn có giá trị sư phạm: yêu cầu được phép, chi phí được kiểm soát, các lựa chọn khác biệt, việc học và tiếp tục đều quan sát được. Ta học cách kiểm tra cơ chế mà không biến một điểm đã chạm trần thành bằng chứng lợi nhuận.
Giả thuyết rồi bài tập về tính dư thừa
Dự đoán trước khi chạy kịch bản
Hãy hình dung các ghi chú đầu tiên được BALD/chi phí xếp hạng có nhiều cách diễn đạt rất gần nhau. Mô hình có thể cho chúng điểm cao mà từng ghi chú không mang lại nhiều điều mới bằng một ghi chú thực sự khác biệt.
Trước khi chạy bài tập, hãy viết giả thuyết của bạn: hai bản sao gần nhau của mỗi trong mười ghi chú ban đầu được xếp hạng cao nhất có làm lựa chọn tập trung vào thông tin lặp lại không? Bộ lọc đa dạng có thể tránh điều đó không, và đồng thời có nguy cơ loại điều gì? Hãy phân biệt dự đoán về chi phí với dự đoán về F1: chúng không bắt buộc thay đổi cùng nhau.
Bộ lọc được cung cấp dùng độ tương đồng Jaccard với ngưỡng 0,85. Để hiểu công thức, lấy hai tập phần tử: độ tương đồng của chúng là số phần tử chung chia cho số phần tử có trong ít nhất một tập. Đồng nhất cho 1; không có phần tử chung cho 0.
Trong ví dụ toán học, 9 phần tử chung trên hợp 10 cho 0,9, cao hơn 0,85. Tám phần tử chung trên hợp mười cho 0,8, thấp hơn. Các tập nhỏ này minh họa ngưỡng; chúng không thay biểu diễn và quy tắc so sánh của mã bài tập. Tài liệu SciPy về Jaccard mô tả phiên bản khoảng cách, bằng 1 - similarité: đừng nhầm hai hướng của điểm.
Tương tự cao không nhất thiết là dư thừa vô ích. Hai câu có thể gần như giống hệt nhau trong khi một mã tham chiếu hoặc thời hạn quan trọng đã đổi. Bộ lọc giới hạn một dạng gần nhau; về nguyên tắc nó không biết nhãn nào sẽ hữu ích nhất.
Chạy, rồi so với giả thuyết
sh scripts/run_exercise.sh
Kịch bản tạo hai bản sao gần cho mỗi ghi chú liên quan, rồi chạy lại bốn chu kỳ chỉ BALD và bốn chu kỳ BALD có bộ lọc. Tập kiểm thử, từ vựng và 60 nhãn ban đầu giữ nguyên. Thí nghiệm không áp đặt lợi ích F1 hay tiết kiệm nào.
Phần đáp án là so sánh chi phí, các kiểu được bao phủ và F1, không sửa tập kiểm thử sau khi đã thấy kết quả. Các kiểu được bao phủ đặc biệt giúp kiểm tra lựa chọn không dồn toàn bộ chú ý vào một loại thực thể.
Trong kết quả được cung cấp, F1 cuối vẫn bằng 1 ở cả hai biến thể. Chi phí là 18.645 đơn vị với các bản trùng và 18.617 với bộ lọc đa dạng, chênh 28 đơn vị. Các giá trị này thuộc bài tập; chúng không thay chi phí của quy trình chính.
Bộ lọc thay đổi lựa chọn và khoản chi mô phỏng, nhưng phép đo ở mức trần không cho thấy chất lượng cải thiện. Vì vậy không thể tuyên bố đa dạng luôn hữu ích, cũng không thể đổi chênh lệch này thành thời gian gán nhãn tiết kiệm.
Tạo hình và dọn dẹp
Sau khi so bài tập với giả thuyết, hãy tạo các hình và kiểm tra checkpoint. Giữ các đầu ra hữu ích sau hai lệnh đầu và trước khi dọn dẹp, vì clean.py --outputs-only sẽ xóa kết quả.
docker compose run --rm --no-deps tutorial python lesson/figures/plot.py
docker compose run --rm --no-deps tutorial python scripts/check_checkpoints.py
docker compose down
docker compose run --rm --no-deps tutorial python scripts/clean.py --outputs-only
docker compose down
plot.py tạo hình từ các đầu ra. check_checkpoints.py kiểm tra tệp lưu. Các lệnh docker compose down sau đó bao quanh bước dọn dẹp dự án.
Script dọn dẹp hiển thị và chỉ xóa outputs. Nó không xóa corpus, checkpoint hay tệp của các dự án Docker khác. Đây cũng là lý do cần giữ checkpoint bị lệch để kiểm tra, thay vì xóa nó trước khi hiểu khác biệt.
Khắc phục sự cố, dọn dẹp và giới hạn sản phẩm
Tìm nguyên nhân của sai khác
Docker không thấy GPU. Hãy theo chẩn đoán của preflight và làm lại trong một thư mục mới vừa giải nén. Phân biệt việc card hiển thị trong Linux với việc tính thành công trong container; check_environment.py kiểm tra điều thứ hai.
Một phân phối biên bị từ chối. Hãy kiểm tra kích thước, giá trị không hữu hạn hoặc âm, việc chuẩn hóa trên token thực và mặt nạ. Chi phí dương cũng chưa đủ để chứng minh nó khớp ghi chú được yêu cầu: oracle kiểm soát tính nhất quán này riêng. Đừng thay xác suất bằng số tùy ý để có điểm.
Một nhãn chú thích cắt qua cửa sổ. Corpus không còn tuân thủ hợp đồng tách của quy trình. Dời ranh giới bằng cách xem nhãn ẩn sẽ lách đúng quy tắc đang được học. Với corpus mới, cần xác định và đánh giá một chiến lược tách phù hợp, thay vì che lỗi này.
Việc tiếp tục bị lệch. Hãy giữ checkpoint và kiểm tra mô hình, bộ tối ưu, thứ tự lấy mẫu, trạng thái ngẫu nhiên và hàng đợi gán nhãn. Đầu ra cuối khác nhau có thể đến từ trạng thái khôi phục không đầy đủ, không chỉ từ mô hình tệ. Dọn dẹp có mục tiêu vẫn là bước của phần trước.
Những gì còn thiếu cho một nhóm gán nhãn thực
Hướng dẫn thay con người bằng oracle hoàn hảo. Trái lại, một ứng dụng thực phải cùng nghiệp vụ định nghĩa thực thể, đào tạo người gán nhãn và đo thời gian, chi phí, lỗi và việc bỏ dở. Một mã tham chiếu mơ hồ, thời hạn không chính xác hay bất đồng giữa hai người không thể rút gọn thành số token.
Nhóm phải có sự đồng ý và quyền truy cập cần thiết cho tài liệu họ dùng. Họ phải lưu văn bản, offset và các bản sửa đổi, chuẩn bị kiểu thực thể mới và quản lý lỗi của oracle thực — dù đó là một người hay một quy trình xác thực.
Lớp sản phẩm còn cần xác thực, API, nhật ký, giám sát, kiểm thử tải, sao lưu, khôi phục và rà soát của con người. Đây là công việc cần dự kiến, không phải chức năng đã được vòng lặp học này chứng minh.
Cuối cùng, mô hình đề xuất các span cần sửa; nó không xác nhận bất cứ trạng thái, con người hay quyền truy cập nào. Phát hiện một ngày trong ghi chú không chứng nhận thời hạn đã được phê duyệt. Vai trò giao diện là trình bày một đề xuất và nguồn của nó, không nhầm chúng với quyết định nghiệp vụ.
Tổng kết
Chúng ta bắt đầu từ câu hỏi thực tế: nên gán nhãn những ghi chú nào tiếp theo? BiLSTM biến token thành điểm có ngữ cảnh; CRF tổ chức các điểm này thành đường BIO được phép và cung cấp các biên. Các lượt với dropout sau đó cho phép tạo điểm bất đồng, quy về chi phí rõ ràng.
Lựa chọn chỉ có ý nghĩa nếu nó chưa biết đáp án. Sự tách biệt giữa nhãn ẩn, yêu cầu và oracle khiến điều kiện này kiểm chứng được. Kiểm soát ngân sách và khôi phục trạng thái cho phép theo dõi chính xác điều đã được yêu cầu và học.
Còn ba phân biệt cần nhớ: tính hợp lệ BIO và độ đúng của span; bất đồng mô hình và xác suất lỗi; chi phí mô phỏng và công việc con người. Một phép đo không thể thay thế phép đo khác.
Trên corpus này, mọi chiến lược trình bày đều đạt F1 = 1. Không quan sát được lợi ích là kết quả cần ghi nhớ, không phải khiếm khuyết để che giấu. Quy trình dạy ta xây dựng và xem xét một vòng lặp gán nhãn chủ động; nó không chứng minh vòng lặp đó cải thiện năng suất của một nhóm.
Nguồn chính và tài liệu bổ sung
Dữ liệu, tham số, lệnh và kết quả trình bày là của dự án r001 được liên kết ở đầu bài. Các câu, lưới nhỏ và phép tính thêm để giải thích là ví dụ sư phạm, tách biệt với phép đo của quy trình này.
Các tham chiếu chính là hướng dẫn BiLSTM-CRF của PyTorch, tài liệu torch.nn.LSTM 2.8 và bài báo BALD với dropout. Các liên kết bổ sung xuyên suốt bài giải thích embedding, dropout, tính toán số, tối ưu hóa, khả năng tái lập, Jaccard và quyền truy cập GPU.
Các tài liệu này làm sáng tỏ cơ chế; chúng không thay thế các tệp và dependency của ZIP để tái tạo bản sửa đổi r001.