Hãy hình dung nhật ký hoạt động của một bộ phận back-office: một tài liệu được nhập, lập chỉ mục, giao cho một nhóm rồi chuyển đi rà soát. Phần lớn hồ sơ đi theo những lộ trình khá đều đặn. Nhưng một số bỏ qua một bước, quay lại rà soát nhiều lần hoặc mất nhiều thời gian hơn hẳn để tiến triển.
Bạn có thể viết một loạt điều kiện để phát hiện chúng. Nhưng làm sao phân biệt một lộ trình thực sự bất thường với một biến thể bình thường mà các quy tắc chưa dự kiến? Và điều gì xảy ra khi nhóm thay đổi cách làm việc?
Chúng ta sẽ xây dựng một bộ phát hiện học cách dự đoán sự kiện tiếp theo và thời gian chờ của nó, rồi so sánh dự đoán ấy với điều thực sự xảy ra. Khi đủ bất ngờ, nó đánh dấu hồ sơ để kiểm tra. Nó không kết luận một người đã mắc lỗi hay một tài liệu không tuân thủ.
Quy trình rất cụ thể: nhật ký sự kiện → tiền tố đã quan sát → dự đoán → đo mức bất ngờ → ngưỡng → cảnh báo cần xem xét. Chúng ta sẽ huấn luyện một mạng hồi tiếp nhỏ, so sánh nó với hai phương pháp đơn giản và thử phản ứng của nó trước một thực hành mới nhưng vẫn chấp nhận được.
Mô hình không nhận danh tính, nhóm hồ sơ hay dấu thời gian tuyệt đối. Dữ liệu là dữ liệu tổng hợp: chúng cho phép một thí nghiệm có kiểm soát, chứ không đo tần suất sự cố trong một doanh nghiệp. Các ví dụ tính toán nhỏ trong bài có mục đích sư phạm; kết quả tham chiếu r004 được trình bày riêng.
Tải toàn bộ dự án, bản sửa đổi r004
Định nghĩa bất thường là sự bất ngờ, không phải là sự không tuân thủ
Đọc một vết chạy như nhật ký ứng dụng
Một GED, hay hệ thống quản lý tài liệu điện tử, lưu giữ tài liệu và các thao tác liên quan đến chúng. Một workflow là hành trình của chúng qua các bước khác nhau. Một vết chạy là chuỗi sự kiện có thứ tự của cùng một hồ sơ; một tiền tố là phần đầu của chuỗi ấy, đến một vị trí xác định.
Từ vựng của dự án gồm tám sự kiện: IMPORT, INDEXATION, AFFECTATION, REVUE, REVISION, APPROBATION, PUBLICATION và ARCHIVAGE. Bốn vai trò hư cấu cho biết vai trò gắn với sự kiện mà không cung cấp danh tính cá nhân.
Hãy lấy tiền tố minh họa này: IMPORT → INDEXATION → AFFECTATION → REVUE. Lúc này, ta biết việc rà soát đã diễn ra. Ta chưa biết bước tiếp theo sẽ là sửa đổi hay phê duyệt, cũng như nó sẽ mất bao lâu.
Một vết chạy bình thường của trình mô phỏng có thể gồm REVISION → REVUE và có thể bỏ qua việc xuất bản. Vì vậy, không được coi mọi vòng lặp hoặc bước vắng mặt là lỗi. Các nhiễu được chèn vào — bỏ bước, vòng lặp, hoán vị và thời gian chờ kéo dài — dùng để kiểm thử bộ phát hiện trong tập dữ liệu này. Chúng không định nghĩa một chính sách tài liệu mang tính phổ quát.
Tách biệt học, hiệu chỉnh và đo lường
Mô hình học các lộ trình bình thường trên tập huấn luyện, gọi là train. Tập xác thực ở đây dùng để đặt ngưỡng cảnh báo. Sau đó, tập kiểm thử đo lường quy tắc thu được mà không điều chỉnh lại ngưỡng để làm đẹp các con số.
Các nhóm dữ liệu được mô tả rõ trong quy trình như sau:
| Tập | Vết chạy bình thường | Vết chạy nhiễu được đếm rõ ràng |
|---|---|---|
| Huấn luyện | 840 | Không có trong quá trình học được mô tả |
| Xác thực dùng cho ngưỡng | 90 | Không dùng để chọn ngưỡng |
| Kiểm thử | 90 | 90 |
Lưu ý về tổng số. Tập dữ liệu được công bố gồm 120 nhóm, mỗi nhóm mười vết chạy, tức 1 200 vết chạy. Các số lượng được liệt kê rõ ở trên cộng lại là 1 110 vết chạy. Mô tả hiện có không nêu cách phân bổ 90 vết còn lại: điểm này vẫn cần được kiểm tra trong quá trình tạo tập dữ liệu. Chúng tôi giữ nguyên các nhóm đã công bố cho việc học, hiệu chỉnh và kiểm thử, không tự suy diễn phần phân bổ còn thiếu.
Sự tách biệt cũng tôn trọng thời gian: huấn luyện trước xác thực, rồi mới đến kiểm thử. Mỗi nhóm có cửa sổ thời gian riêng. Hồ sơ, vết chạy và cửa sổ không đi qua các tập, còn gọi là split.
Điều đó không có nghĩa các chuỗi ký hiệu hoàn toàn khác nhau. Một đoạn đầu như IMPORT → INDEXATION có thể xuất hiện ở mọi nơi. Với chỉ tám sự kiện, cấm mọi tiền tố chung sẽ tạo ra một vấn đề nhân tạo. Cần tách biệt hồ sơ và các cửa sổ của chúng, không phải vốn từ cần thiết để mô tả hoạt động.
Từ chối nguồn không hợp lệ trước khi tìm bất thường
Chương trình phân biệt dữ liệu định dạng sai với một sự kiện ít gặp. Thời lượng âm, loại sự kiện không xác định hoặc thứ tự nguồn trùng lặp sẽ làm dữ liệu đầu vào không hợp lệ trước khi tính toán thống kê.
Các dấu thời gian bằng nhau được cho phép. Thứ tự nguồn, dùng để phân định các sự kiện, khi đó xác định trình tự của chúng. Vì thế thời gian chờ bằng không là một quan sát hợp lệ, không phải bất thường tự động.
Luồng được kiểm tra là không giảm trước khi sắp xếp ổn định. Vì sao theo thứ tự xử lý này? Giả sử, để minh họa, một tệp xuất ghi 10 giờ 05 rồi 10 giờ 02. Sắp xếp dòng ngay lập tức sẽ tạo ra một trình tự có vẻ đúng, nhưng che giấu sự không nhất quán của nguồn. Quy trình ưu tiên báo vấn đề hơn là biến nó thành một bất ngờ thống kê.
Mô hình biết gì tại từng thời điểm
Tại vị trí hiện tại, mô hình nhận ba thông tin: sự kiện, vai trò của nó và thời gian chờ đã trôi qua kể từ sự kiện trước. Thời gian này được biến đổi thành log1p(délai) / 10.
log1p(x) tính logarit tự nhiên của 1 + x. Logarit nén các giá trị lớn; việc cộng 1 cũng giúp dùng được thời gian chờ bằng không. Với các thời lượng minh họa 9, 99 và 999 giây, đầu vào thời gian lần lượt xấp xỉ 0,2303, 0,4605 và 0,6908. Vì vậy mạng không nhận trực tiếp 9, 99 và 999. Tài liệu về torch.log1p mô tả phép tính này.
Chú ý độ lệch: thời gian ở đầu vào thuộc về quá khứ; thời gian cần dự đoán thuộc về bước tiếp theo. Mô hình không nhận sự kiện tiếp theo đó, vai trò của nó, loại nhiễu, ID hồ sơ, nhóm của hồ sơ hay thời gian tuyệt đối. Các sự kiện tương lai là mục tiêu học, không phải đầu vào tại cùng vị trí.
Cảnh báo về chuyển tiếp này chỉ có thể được tính sau khi sự kiện tiếp theo đến. Nếu nó đến sau một thời gian chờ dài, chương trình có thể so sánh thời gian quan sát được với dự đoán. Ngược lại, quy trình này không cung cấp một báo động sẽ kích hoạt trong khi thời gian chờ vẫn đang diễn ra. Đó sẽ là một cơ chế bổ sung cần được thiết kế và đánh giá.
Ở đây, nhân quả nghĩa là « không đọc tương lai ». Nó không có nghĩa là « có thể giải thích nguyên nhân nghiệp vụ ». Một kiểm thử sửa một hậu tố tương lai — phần cuối của vết chạy — và kiểm tra rằng các điểm thô của tiền tố không đổi không thay đổi.
Mô hình nhân quả và hai đầu ra của nó
Một trạng thái nhỏ tiến theo hồ sơ
Một LSTM, viết tắt của Long Short-Term Memory, là mạng xử lý một chuỗi theo thứ tự và cập nhật một trạng thái số tại mỗi vị trí. Hãy hình dung một hàm duyệt qua bảng sự kiện trong khi giữ bản tóm tắt những gì đã đọc. Ở đây, cách xây dựng bản tóm tắt đó được học thay vì viết thành các điều kiện.
LSTM của dự án là một chiều, với 64 đơn vị. Nó chỉ đọc về phía trước. Trạng thái của nó được khởi tạo bằng không cho mỗi hồ sơ: bản tóm tắt của hồ sơ trước không trở thành ngữ cảnh của hồ sơ sau. Các cơ chế nội bộ và trạng thái của LSTM được mô tả trong tài liệu PyTorch 2.8.
Trước khi đọc, các danh mục trở thành các vectơ. Một embedding ở đây là một hàng trong bảng số đã học: mỗi sự kiện có 16 giá trị, mỗi vai trò có 8 giá trị. Mục tiêu không phải hiểu theo ngôn ngữ từ REVUE, mà là học một biểu diễn hữu ích cho danh mục đó. Tài liệu Embedding mô tả nguyên lý bảng ánh xạ này.
Khi thêm giá trị thời gian, ta có 16 + 8 + 1 = 25 số cho mỗi vị trí. LSTM biến chúng thành trạng thái gồm 64 giá trị. Hai đầu ra, tức hai lớp đầu ra nhỏ, dùng cùng trạng thái này: một đầu dự đoán sự kiện tiếp theo, đầu kia dự đoán các tham số của thời gian chờ tiếp theo.
Theo dõi các chiều trong mã
Đây là đoạn trích đầu tiên của dự án, được giữ nguyên:
import torch
from torch import nn
import torch.nn.functional as F
from .events import make_prefix_targets
class SequenceModel(nn.Module):
def __init__(self):
super().__init__()
self.events = nn.Embedding(8, 16)
self.roles = nn.Embedding(4, 8)
self.lstm = nn.LSTM(25, 64, batch_first=True)
self.event_head = nn.Linear(64, 8)
self.delay_head = nn.Linear(64, 2)
def forward(self, event, role, previous):
x = torch.cat(
[self.events(event), self.roles(role), previous.unsqueeze(-1)], -1
)
# No state argument: every batch starts fresh, no state crosses cases.
hidden, _ = self.lstm(x)
logits = self.event_head(hidden)
parameters = self.delay_head(hidden)
return logits, parameters[..., 0], F.softplus(parameters[..., 1]) + 0.001
Một tensor là mảng số có thể có nhiều trục. Để đọc mã này, gọi B là số vết chạy trong lô và T là số vị trí sau khi đệm. Tên sự kiện và vai trò được đổi thành định danh nguyên; event, role và previous đều có dạng [B, T].
self.events(event) trả về [B, T, 16], còn self.roles(role) trả về [B, T, 8]. previous.unsqueeze(-1) thêm một trục cho thời gian chờ để được [B, T, 1]. Cuối cùng, torch.cat(..., -1) ghép ba khối này trên trục cuối: ta thu được [B, T, 25].
batch_first=True nghĩa là trục đầu chỉ lô. Sau đó hidden chứa trạng thái 64 giá trị tại mỗi vị trí, tức [B, T, 64], không chỉ là một bản tóm tắt cuối cho mỗi vết chạy. Không truyền trạng thái vào self.lstm(x) sẽ khởi tạo lại trạng thái trong lần gọi này; mô hình không tự giữ một phiên từ lần gọi này sang lần gọi khác.
Đầu event_head tạo ra [B, T, 8]: tám logit, hay điểm thô, cho tám sự kiện. Các số này chưa phải xác suất. Đầu delay_head tạo ra [B, T, 2], các thành phần của nó trở thành mu và raw_sigma.
mu mô tả tâm của phân phối dự đoán của log(1 + délai). sigma mô tả độ phân tán của nó dưới dạng độ lệch chuẩn: giá trị nhỏ biểu thị dự đoán thời gian tập trung hơn.
Dòng cuối dùng softplus(raw_sigma) + 0.001 để giữ độ phân tán dương. Softplus là biến đổi trơn dựa trên log(1 + exp(x)); nó cho mạng học mà không cho phép độ lệch chuẩn âm. Ràng buộc này áp dụng cho sigma, không áp dụng cho mu: đoạn trích không chặn trực tiếp thời gian chờ nhận được khi chuyển ngược từ mu.
Học sự kiện tiếp theo: phạt sự bất ngờ
Trong quá trình huấn luyện, chương trình biết sự kiện theo sau mỗi tiền tố bình thường. Nó yêu cầu mô hình gán cho sự kiện đó xác suất cao. Hàm mất mát, hay loss, là số mà quá trình học cố giảm.
Với phần sự kiện, chúng ta dùng entropy chéo, hay cross-entropy. Với một mục tiêu phân loại, nó tương ứng với −log(probabilité de l’événement réellement observé).
Ví dụ sư phạm: nếu mô hình gán xác suất 0,8 cho sự kiện xảy ra, mất mát của nó xấp xỉ 0,2231. Nếu chỉ gán 0,05, mất mát xấp xỉ 2,9957. Điều xảy ra càng bị coi là khó có khả năng, mức bất ngờ càng lớn.
Mã truyền trực tiếp các logit vào F.cross_entropy, hàm thực hiện phép tính phù hợp. Không cần áp dụng softmax trước đó trong đoạn trích này. Với reduction="none", ta giữ mất mát theo từng vị trí thay vì lập tức lấy trung bình toàn cục.
Học thời gian chờ mà không nhầm hai thang đo
Mục tiêu thời gian là z = log(1 + délai suivant). Mục tiêu này không bị chia cho mười. Phép chia cho mười chỉ áp dụng cho đặc trưng của thời gian chờ trước đó đưa vào đầu vào.
Mô hình xấp xỉ z bằng phân phối Gaussian, một đường cong hình chuông có tâm mu và độ lệch chuẩn sigma. Phép tính mất mát thời gian là:
NLL_délai = log(sigma) + (z − mu)² / (2 × sigma²)
NLL nghĩa là negative log-likelihood, hay đối số của logarit khả năng xảy ra. Số hạng bình phương phạt độ lệch giữa mục tiêu và tâm dự đoán, tương đối với độ phân tán đã công bố. log(sigma) ngăn việc mở rộng vô hạn độ phân tán này mà không phải trả giá. Hằng số Gaussian được lược bỏ theo quy trình. Tài liệu GaussianNLLLoss trình bày công thức chung với phương sai; ở đây phương sai là sigma² và phép tính được viết trực tiếp.
Hãy lấy một ví dụ số khác với đầu ra đã huấn luyện: mu = log(11) và sigma = 0,5. Thời gian chờ quan sát là 10 giây cho z = mu, nên mất mát xấp xỉ −0,6931. Thời gian chờ 30 giây cho giá trị xấp xỉ 1,4538. Nó xa tâm đã công bố hơn và nhận mức phạt cao hơn.
Mất mát thời gian âm không phải xác suất âm. Chúng ta làm việc với một mật độ liên tục, không phải xác suất của một danh mục; độ cao của mật độ có thể vượt 1, và hằng số ở đây bị bỏ đi. Vì vậy không được biến NLL này thành « phần trăm rủi ro ».
Mặt nạ: không học trên phần đệm
Các vết chạy không có cùng độ dài. Để xếp chúng trong một lô hình chữ nhật, ta thêm padding, hay phần đệm, bên phải. Mặt nạ Boolean chỉ các vị trí thực có mục tiêu: True cho vị trí hữu ích, False cho vị trí được thêm vào.
Việc dựng lô, nằm giữa hai đoạn trích trong tệp nguồn, chuẩn bị các tensor và mặt nạ này. Hàm sau nhận các dữ liệu đó:
def components(logits, mu, sigma, targets, z, mask):
if (
mask.dtype != torch.bool
or not mask.any(1).all()
or ((mask[:, 1:] & ~mask[:, :-1]).any())
):
raise ValueError("Nonempty real prefix mask required")
# Select before calculating: a padded NaN target cannot contaminate loss.
event = torch.zeros_like(mu)
delay = torch.zeros_like(mu)
event[mask] = F.cross_entropy(logits[mask], targets[mask], reduction="none")
delay[mask] = torch.log(sigma[mask]) + (z[mask] - mu[mask]).square() / (
2 * sigma[mask].square()
)
return event, delay
Điều kiện đầu tiên yêu cầu mặt nạ Boolean, ít nhất một vị trí thực cho mỗi vết chạy và không được quay từ False về True. Vì vậy [True, True, False, False] hợp lệ, còn [True, False, True, False] bị từ chối: nội dung thực phải tạo thành một tiền tố liên tục.
event và delay được khởi tạo bằng không. Sau đó các phép tính chỉ chạy trên phần tử được mask chọn. Điểm quan trọng là chọn trước khi tính, chứ không phải tính mọi nơi rồi nhân với không: một NaN, giá trị số không xác định, vẫn gây vấn đề ngay cả khi nhân với không. Một NaN trong mục tiêu padding không được làm nhiễm các mất mát thực.
Hàm này trả về hai mảng mất mát; nó chưa thực hiện phép lấy trung bình cuối. Vòng lặp của dự án trước hết lấy trung bình các vị trí của từng vết chạy, rồi lấy trung bình các vết chạy trong lô. Vì vậy một vết chạy dài không có trọng số lớn hơn chỉ vì có nhiều bước hơn.
Ví dụ sư phạm: một vết chạy hai vị trí có mất mát 2 ở mọi nơi và một vết chạy tám vị trí có mất mát 1 ở mọi nơi cho trung bình theo vết chạy là (2 + 1) / 2 = 1,5. Nếu lấy trung bình trực tiếp trên mười vị trí, chúng cho (2 × 2 + 8 × 1) / 10 = 1,2. Đây không phải cùng cách gán trọng số.
Các kiểm tra nhìn thấy được liên quan đến mặt nạ. Chúng tự thân không phải là xác thực đầy đủ mọi dạng, giá trị và độ phân tán có thể truyền trực tiếp vào components().
Trở lại giây: trung vị, không phải trung bình
Quy trình dùng expm1(mu), tức exp(mu) − 1, để trở về một thời lượng. Trong xấp xỉ Gaussian này của z, đó là một trung vị có điều kiện: nó chia phân phối dự đoán thành hai nửa, theo tiền tố. Đó không phải trung bình của nó.
Trong ví dụ mu = log(11) và sigma = 0,5, trung vị là 10 giây, còn trung bình của biến đã biến đổi sẽ là exp(mu + sigma² / 2) − 1, xấp xỉ 11,4646 giây. Biến đổi logarit làm hai đại lượng tóm tắt này khác nhau. Tài liệu SciPy về phân phối lognormal giúp tìm hiểu sâu hơn phép biến đổi mũ của một Gaussian; ở đây ta trừ 1 để lấy lại thời gian chờ.
Một sắc thái khác: NLL được công bố tính trong không gian z, không trực tiếp như mật độ theo giây. Đổi biến trong một mật độ sẽ cần hệ số 1 / (1 + délai), gọi là Jacobian; đối số logarit của nó cộng log(1 + délai) vào NLL, cùng hằng số Gaussian cho dạng đầy đủ. Chúng tôi không đổi biến như vậy trong điểm r004: thay đổi nó sẽ thay đổi bộ phát hiện và hiệu chỉnh của nó.
Vì sao so sánh bốn phương pháp?
Phương pháp quy tắc mã hóa các chuyển tiếp của trình mô phỏng. Đây là mốc tham chiếu rõ ràng, có kiến thức này về trình tạo dữ liệu; nó không phải chính sách nghiệp vụ phổ quát.
Bigram đếm các chuyển tiếp giữa hai sự kiện liên tiếp trong train. Nó học tần suất cục bộ mà không giữ toàn bộ tiền tố. Làm trơn cộng 1 của nó thêm một đếm giả vào các khả năng: một chuyển tiếp chưa từng thấy không tự động có xác suất bằng không. Chẳng hạn, với 12 chuyển tiếp đi ra và tám khả năng tiếp theo, một khả năng còn vắng sẽ nhận (0 + 1) / (12 + 8) = 0,05.
LSTM sự kiện chỉ tối thiểu hóa entropy chéo. LSTM liên hợp tối thiểu hóa entropy chéo cộng 0,1 lần NLL thời gian chờ. Tất cả nhận cùng các tiền tố sẵn có, dù không khai thác mọi thông tin theo cùng cách. Đáng chú ý, LSTM sự kiện vẫn giữ các đầu vào đã mô tả ở trên: tên của nó chỉ mục tiêu học, không phải việc loại bỏ thời gian chờ quá khứ ở đầu vào.
Trọng số 0,1 liên quan đến huấn luyện. Sau đây ta sẽ gặp trọng số 0,5 để xây dựng điểm cảnh báo: hai số này không cùng vai trò.
Tái tạo toàn bộ quy trình
Bước 1 — chuẩn bị và kiểm tra phép tính trong Docker
Bạn cần có thể đọc Python, thao tác với mảng và dùng terminal có Docker. Các khái niệm xác suất và tensor phục vụ các phép tính vừa trình bày. Quy trình dùng FP32 trên CUDA: số thực dấu phẩy động 32 bit, tính trên GPU NVIDIA.
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 bắt đầu từ thư mục này. Hãy giữ các phiên bản và tài nguyên mà tệp dự án quy định; các đoạn trích trong bài không thay thế môi trường đầy đủ của nó.
sh scripts/preflight.sh
sh scripts/setup.sh
docker compose config --quiet
docker compose build acquisition tutorial learning inference calibration
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
Preflight kiểm tra Docker, GPU, bộ nhớ và dung lượng đĩa. setup.sh chuẩn bị môi trường dự án; docker compose config --quiet kiểm tra cấu hình, sau đó build xây dựng các dịch vụ.
Ở đây bước acquisition không tải mô hình tiền huấn luyện nào: locks/models.lock.json không khai báo tệp bên ngoài. Mạng được khởi tạo cục bộ và huấn luyện trên các vết chạy. Bước này được giữ để kiểm soát các tài sản của quy trình, không phải để lấy một mô hình ngôn ngữ lớn.
check_environment.py thực sự chạy một LSTM và gradient của nó trong Docker. Vì vậy chỉ nhìn thấy GPU trên máy chủ là chưa đủ. Gradient chỉ cách mất mát thay đổi khi các tham số thay đổi; nhờ đó có thể điều chỉnh chúng khi học. Sau đó, kiểm thử pytest xác nhận hành vi chương trình, độc lập với các chỉ số phát hiện.
Cần quan sát: mỗi lệnh phải thành công trước lệnh tiếp theo. Đừng thay một lỗi tính toán trong container bằng việc chỉ thấy GPU trong Linux.
Bước 2 — chuẩn bị các vết chạy và xem xét cơ chế
docker compose run --rm tutorial python -m ged_anomalies_workflows.cli prepare --config configs/minimum.yaml
docker compose run --rm inference python -m ged_anomalies_workflows.cli baseline --config configs/minimum.yaml
docker compose run --rm inference python -m ged_anomalies_workflows.cli inspect-mechanism --config configs/minimum.yaml
prepare xây dựng tập dữ liệu. Hãy tìm các nhóm đã công bố, các phân vùng thời gian và kiểm tra nguồn, đặc biệt là điểm tổng số đã nêu ở trên. baseline cung cấp các mốc đơn giản; inspect-mechanism cho phép xem xét các phép tính trước khi huấn luyện đầy đủ.
Theo dõi một tiền tố: thông tin nào có sẵn, sự kiện nào là mục tiêu và thời gian chờ ứng với khoảng nào? Cách đọc này giúp tránh đến cuối mới phát hiện một cột chứa câu trả lời của tương lai.
Bước 3 — huấn luyện, chấm điểm và hiệu chỉnh
sh scripts/train_variants.sh
docker compose run --rm inference python -m ged_anomalies_workflows.cli score --config configs/minimum.yaml
docker compose run --rm calibration python -m ged_anomalies_workflows.cli calibrate --config configs/minimum.yaml
docker compose run --rm tutorial python -m ged_anomalies_workflows.cli evaluate --config configs/minimum.yaml
train_variants.sh điều phối việc huấn luyện hai LSTM. score áp dụng các mô hình vào tiền tố. calibrate đặt ngưỡng trên các vết chạy bình thường của tập xác thực. Cuối cùng, evaluate đo kết quả. Các giải thích sau trình bày ý nghĩa của các đầu ra này; hãy giữ chúng trước khi chạy bài tập.
Quá trình học dùng AdamW, với tốc độ 0,003, weight decay 0,001, cắt chuẩn 1, lô 32 vết chạy và 25 epoch. Quy trình thực hiện 27 lần cập nhật mỗi epoch. Hai LSTM cùng dùng seed 17.
Một epoch là một lượt qua tập huấn luyện; một lô, hay batch, gom nhiều vết chạy cho một phép tính. Bộ tối ưu điều chỉnh các tham số sau phép tính này. Tốc độ đặt thang của lần cập nhật, còn weight decay thêm phần co nhỏ trọng số theo quy tắc AdamW. Cắt chuẩn giới hạn chuẩn của gradient được dùng: nó không có nghĩa « mỗi trọng số phải nhỏ hơn 1 ».
Kiểm tra khả năng tiếp tục, không chỉ một điểm gần đúng
Quy trình so sánh một lần huấn luyện liên tục 25 epoch với một lần dừng sau mười epoch rồi tiếp tục mười lăm epoch. Một checkpoint là bản lưu trạng thái cần để tiếp tục: mô hình, bộ tối ưu, thứ tự lấy mẫu dữ liệu (sampler), bộ sinh ngẫu nhiên (RNG) và lịch sử.
Chỉ nạp lại trọng số không đủ để tái tạo chính xác phần tiếp theo. Tương tự, hai lần huấn luyện kết thúc với cùng recall chưa chắc giống hệt nhau. Việc tiếp tục phải khôi phục các trạng thái mà quy trình quy định. Tài liệu PyTorch về khả năng tái lập cũng nhắc rằng tính đồng nhất số không được bảo đảm sau khi đổi nền tảng hoặc phiên bản.
Các checkpoint cục bộ được coi là trạng thái đáng tin cậy. Kiểm toán công khai nạp lại trọng số JSON và đầu ra tiền tố, không nạp pickle bên ngoài. Lựa chọn này mô tả quy trình này; đừng thay các tệp đó bằng checkpoint tải xuống tùy ý.
Hiệu chỉnh một điểm có thể so sánh trước khi kiểm thử
Đưa hai thành phần về thang đo sử dụng được
Giờ chúng ta có nhiều phép đo mức bất ngờ, nhưng chưa có quy tắc cảnh báo. Phương pháp quy tắc cho 0 hoặc 1. Bigram và LSTM sự kiện dùng mức bất ngờ của sự kiện quan sát được.
Với LSTM liên hợp, cộng trực tiếp entropy chéo và NLL thời gian chờ sẽ khiến kết quả phụ thuộc vào thang số của chúng. Dự án trung tâm hóa và chuẩn hóa chúng riêng biệt, chỉ dùng trung bình và độ lệch chuẩn tính trên các tiền tố bình thường của train:
thành phần chuẩn hóa = (giá trị − trung_bình_train) / độ_lệch_chuẩn_train
Ta trừ mức thông thường, rồi chia cho độ phân tán thông thường. Kết quả 2 nghĩa là « cao hơn hai độ lệch chuẩn so với trung bình huấn luyện », không phải « nguy hiểm gấp hai lần ».
Sau đó điểm liên hợp cộng hai thành phần đã chuẩn hóa với trọng số cố định 0,5 của quy trình. Trọng số này thuộc việc xây dựng điểm, không thuộc mất mát huấn luyện có trọng số 0,1.
Ví dụ sư phạm với tham số giả định: mức bất ngờ sự kiện 1,4, trung bình 1 và độ lệch chuẩn 0,2 cho kết quả 2. NLL thời gian chờ 1,5, trung bình −0,5 và độ lệch chuẩn 1 cũng cho 2. Hai thành phần giờ được biểu diễn tương đối với độ phân tán thông thường. Áp dụng trọng số 0,5 cho thành phần 2 đưa đóng góp của nó về 1. Các phép tính này minh họa chuẩn hóa và gán trọng số; phần ghép chạy được vẫn là lệnh score của ZIP. Giá trị âm không bị xóa trước khi chuẩn hóa.
Một thành phần hằng hoặc không hữu hạn sẽ bị từ chối. Độ phân tán bằng không khiến phép chia này không thể thực hiện; âm thầm thay kết quả bằng không sẽ che giấu vấn đề. Các thống kê không được tính lại trên tập kiểm thử để làm điểm số có vẻ thuận lợi hơn.
Từ tiền tố đến vết chạy
Điểm của một vết chạy là giá trị lớn nhất trong các điểm nhân quả của nó: chỉ một chuyển tiếp rất bất ngờ cũng có thể đủ. Khi đọc dần, đó là giá trị lớn nhất trong các điểm đã tính được; điểm cuối dùng mọi tiền tố đã quan sát.
Lựa chọn này có hệ quả đơn giản: vết chạy dài có nhiều cơ hội nhận điểm cao hơn. Vì vậy đánh giá giữ các tầng độ dài, tức nhóm các vết chạy có kích thước tương đương. Một trung bình tổng thể tốt có thể che giấu nhiều dương tính giả hơn ở hồ sơ dài.
Phân vị 95 %: một hạng chính xác, không phải lời hứa
Mỗi phương pháp sắp xếp điểm của 90 vết chạy bình thường trong xác thực và giữ giá trị ở chỉ số ceil(0,95 × 90) − 1. ceil làm tròn lên: ceil(85,5) − 1 = 85. Với các chỉ số bắt đầu từ không, đó là giá trị thứ 86 theo thứ tự tăng dần.
Sau đó cảnh báo yêu cầu score > seuil. Bằng nhau thì không cảnh báo. Nếu mọi giá trị đều khác nhau, chỉ bốn giá trị sau giá trị thứ 86 vượt ngưỡng trong tập xác thực này: 4 / 90 ≈ 4,44 %. Nếu có giá trị bằng nhau, số đó có thể ít hơn.
Chi tiết này ngăn hai cách hiểu sai. Phân vị thực nghiệm 95 % không có nghĩa « chính xác 5 % dương tính giả », càng không có nghĩa « không bao giờ quá 5 % ở các hồ sơ tương lai ». Nó xác định một quy trình tái lập trên một mẫu đã cho.
Các bất thường xác thực không dùng để chọn ngưỡng này. Kiểm thử diễn ra sau đó. Hiệu chỉnh này cũng không biến điểm thành xác suất sự cố: các ngưỡng vẫn gắn với thang đo riêng của từng phương pháp. Thay đổi thực hành hoặc phụ thuộc thời gian có thể đổi hành vi của chúng.
Đọc các chỉ số trước khi xem kết quả
Precision, recall và dương tính giả: ba câu hỏi khác nhau
Một vết chạy nhiễu được báo đúng là dương tính thật. Một vết chạy bình thường kích hoạt cảnh báo là dương tính giả. Một nhiễu không được báo là âm tính giả.
Hãy lấy ví dụ nhỏ: trong mười vết chạy nhiễu, tám vết cảnh báo; một vết chạy bình thường cũng cảnh báo. Precision là 8 / 9: trong chín cảnh báo, bao nhiêu cảnh báo tương ứng với một nhiễu? Recall là 8 / 10: trong mười nhiễu, bao nhiêu đã được phát hiện?
Tỷ lệ dương tính giả chia số vết chạy bình thường bị báo cho tổng số vết chạy bình thường. Nó không bằng 1 − précision, vì mẫu số của đại lượng đó là số cảnh báo.
Các phép đo này đánh giá việc phát hiện nhiễu do trình tạo xác định. Chúng không đánh giá mức độ nghiêm trọng của một hồ sơ hay trách nhiệm của một người.
Average precision đo thứ hạng, không phải một ngưỡng duy nhất
Average precision, hay AP, xem điều gì xảy ra khi hạ ngưỡng trong bảng xếp hạng điểm. Mỗi nhóm mới được đưa vào làm thay đổi precision và recall. AP cộng các precision có trọng số theo phần tăng recall: AP = somme(gain_de_rappel × précision). Tài liệu scikit-learn đưa ra định nghĩa này; nó không thay thế bộ đánh giá của ZIP và không thêm phụ thuộc nào vào quy trình.
Ở đây các điểm bằng nhau được xử lý cùng nhau. Hãy hình dung chỉ hai vết chạy có điểm giống nhau, một bị nhiễu và một bình thường. Không ngưỡng nào cho phép lấy vết đầu mà không lấy vết kia. Tách chúng giả tạo bằng cách đặt vết nhiễu trước vết bình thường sẽ làm đẹp thứ hạng mà không có thông tin bổ sung.
AP bằng 1 và một dương tính giả tại ngưỡng đã chọn có thể cùng tồn tại. Nếu mọi nhiễu được xếp cao hơn các vết chạy bình thường, thứ hạng là hoàn hảo; nhưng ngưỡng đã đặt trước đó trên tập xác thực vẫn có thể đủ thấp để bao gồm một vết bình thường. Ta không nâng nó lên sau khi đã xem tập kiểm thử.
Hai nghĩa khác nhau của từ thời gian chờ
Lỗi dự đoán thời gian chờ ở đây được tính bằng giây. Nó so sánh thời lượng dự đoán với thời lượng thực sự quan sát.
Độ trễ phát hiện lại được biểu diễn bằng số sự kiện sau nhiễu. Trung vị bằng 0 nghĩa là, theo mốc này, ít nhất một nửa số trường hợp đã phát hiện không cần sự kiện bổ sung để phát hiện. Nó không có nghĩa không phải chờ giây nào, không mất mili giây tính toán nào, hay dự báo trước nhiễu.
Trung vị này chỉ xét các trường hợp đã phát hiện. Một phương pháp có thể phát hiện nhanh vài trường hợp nhưng bỏ sót nhiều trường hợp khác: vì vậy phải đọc nó cùng recall. Các cảnh báo trước nhiễu cũng cần được kiểm tra riêng, thay vì coi là những dự báo tốt.
Kết quả: một cải thiện tổng hợp cần được diễn giải thận trọng
Các quyết định ở ngưỡng đặt trên tập xác thực
Tập kiểm thử gồm 90 vết chạy bình thường và 90 vết chạy nhiễu. Do đó tỷ lệ nhiễu là 50 %: đây là tỷ lệ hiện mắc nhân tạo, không phải số liệu quan sát trong sản xuất.
Dưới đây là các số đếm và tỷ lệ của quy trình r004. Âm tính giả trong bảng được suy ra từ 90 nhiễu và số phát hiện đã công bố; các tỷ lệ được làm tròn đến sáu chữ số thập phân.
Trên thiết bị di động, hãy cuộn ngang bảng.
| Phương pháp | Nhiễu đã phát hiện | Nhiễu bị bỏ sót | Dương tính giả | Recall | Precision | Tỷ lệ dương tính giả |
|---|---|---|---|---|---|---|
| Quy tắc | 67/90 | 23 | 0/90 | 0,744444 | 1 | 0 |
| Bigram | 67/90 | 23 | 0/90 | 0,744444 | 1 | 0 |
| LSTM sự kiện | 67/90 | 23 | 4/90 | 0,744444 | 0,943662 | 0,044444 |
| LSTM liên hợp sự kiện+thời gian chờ | 90/90 | 0 | 1/90 | 1 | 0,989011 | 0,011111 |
Mô hình liên hợp tìm thấy mọi nhiễu trong bài kiểm thử này, với một cảnh báo sai. Precision của nó là 90 / 91 = 0,989011, trong khi tỷ lệ dương tính giả là 1 / 90 = 0,011111. LSTM sự kiện tìm thấy số nhiễu bằng các phương pháp đơn giản, nhưng thêm bốn dương tính giả: độ phức tạp của nó không mang lại lợi ích cho các quyết định này.
Trung vị độ trễ phát hiện của mô hình liên hợp là 0 sự kiện trong các trường hợp đã phát hiện. Ba phương pháp còn lại mỗi phương pháp bỏ sót 23 nhiễu sau thay đổi.
Thứ hạng và các lỗi dự đoán
Các ngưỡng và AP đã công bố như sau. Không thể so sánh các ngưỡng như một thang mức độ nghiêm trọng chung.
| Phương pháp | Ngưỡng | Average precision, xấp xỉ |
|---|---|---|
| Quy tắc | 0 | 0,872222 |
| Bigram | 1,391023 | 0,887963 |
| LSTM sự kiện | 1,386817 | 0,905482 |
| LSTM liên hợp sự kiện+thời gian chờ | 4,284417 | 1 |
Trường hợp quy tắc giúp hiểu AP của chúng. Điểm 1 gom 67 nhiễu, không có vết chạy bình thường: precision là 1 và recall đạt 67 / 90. Khi thêm nhóm điểm 0, ta gồm 23 nhiễu còn lại và 90 vết chạy bình thường: precision thành 0,5. Vì vậy AP là 67 / 90 × 1 + 23 / 90 × 0,5 ≈ 0,872222. Phép tính này được suy ra từ các số đếm đã công bố, không phải từ một lần chạy mới.
Trên 1 198 tiền tố kiểm thử, entropy chéo trung bình là 1,494473 cho mô hình sự kiện và 1,290952 cho mô hình liên hợp. Sai số tuyệt đối trung vị của thời gian chờ ở mô hình liên hợp là 8,026882 giây. Đây là các phép đo dự đoán trên tập dữ liệu này; entropy chéo 1,29 không phải tỷ lệ 129 %.
Vì thế mô hình liên hợp cải thiện phát hiện trong thí nghiệm này. Tuy nhiên bảng không nêu chi tiết 23 nhiễu mà các phương pháp khác bỏ sót: riêng nó không cho phép khẳng định mỗi nhiễu đều là thời gian chờ kéo dài.
Vì sao precision 98,9 % không thể chuyển thẳng sang sản xuất
Hãy làm một phép tính hoàn toàn minh họa, không giả định mô hình giữ nguyên hiệu năng trên hồ sơ thật. Trên 10 000 vết chạy, chỉ 100 vết bị nhiễu, hãy giả sử recall bằng 1 và cùng tỷ lệ dương tính giả 1 / 90.
Hệ thống sẽ báo 100 nhiễu, nhưng cũng báo 9 900 / 90 = 110 vết chạy bình thường. Khi đó precision sẽ là 100 / (100 + 110) ≈ 47,62 %, chứ không phải 98,9 %.
Các tỷ lệ giả định không đổi; quần thể thì đổi. Đây là lý do kết quả của bài kiểm thử cân bằng không thể một mình dự báo khối lượng của một hàng đợi rà soát con người.
Bài tập: một thực hành bình thường mới
Dự đoán trước khi chạy
Nhóm hiện chấp nhận vòng lặp kép REVISION → REVUE như thực hành bình thường. Chúng ta không huấn luyện lại mô hình và không hiệu chỉnh lại ngưỡng. Một mạng hiếm khi gặp sự lặp lại này có thể tiếp tục coi nó là đáng ngờ không? Một quy tắc chỉ kiểm tra chuyển tiếp cục bộ có nhất thiết phản ứng giống vậy không?
Hãy viết giả thuyết của bạn cho bốn phương pháp, rồi chạy bài tập. Kết quả ban đầu và hiệu chỉnh được giữ lại và kiểm soát bằng dấu vết, hay hash, để không bị thay thế âm thầm.
docker compose run --rm tutorial python -m ged_anomalies_workflows.cli exercise --config configs/minimum.yaml
So sánh với lời giải của quy trình
60 vết chạy của bài tập giờ đều bình thường. Quy tắc và bigram không báo vết nào. Cả hai LSTM báo tất cả: 60 dương tính giả trên 60, tức 100 % trong tập này.
Kết quả này không mâu thuẫn với điểm tốt của mô hình liên hợp ở kiểm thử. Bộ phát hiện đã học một tần suất nhất định của các lộ trình; thực hành thay đổi mà việc học và ngưỡng của nó không đổi. Một chuỗi có thể ít được mong đợi về mặt thống kê nhưng hoàn toàn chấp nhận được với nhóm.
Các chuyển tiếp cục bộ có thể đã được chấp nhận, trong khi sự lặp lại của chúng trong một lịch sử dài hơn vẫn bất thường với mô hình tuần tự. Đây là cách diễn giải cơ chế cần đối chiếu với đầu ra, không phải lời giải thích nhân quả hoàn chỉnh cho từng cảnh báo.
Bài tập không yêu cầu nâng ngưỡng đến khi các cảnh báo này biến mất. Nó yêu cầu xác nhận thực hành mới, tạo một bản sửa đổi mới và lập một tập kiểm soát riêng. Huấn luyện lại hoặc hiệu chỉnh lại sau quyết định này sẽ là một thí nghiệm mới, kết quả của nó không được công bố ở đây.
Sau đó tạo các hình và kiểm tra checkpoint trước khi dọn dẹp:
docker compose run --rm tutorial python lesson/figures/plot.py
docker compose run --rm tutorial python scripts/check_checkpoints.py
Khắc phục sự cố, dọn dẹp và chuẩn bị sản xuất
Giữ lại các lỗi hữu ích
Nếu Docker không làm GPU khả dụng, hãy theo chẩn đoán preflight rồi chạy lại trong một thư mục mới đã giải nén. Kiểm tra môi trường phải chạy thành công phép tính trong container; trạng thái GPU trên máy chủ không thay thế điều đó.
Nếu một vết chạy bị từ chối vì thời lượng âm, sự kiện không xác định hoặc thứ tự nguồn trùng lặp, hãy kiểm tra tệp xuất trước mô hình. Đừng né việc từ chối bằng một phép sắp xếp làm biến mất sự không nhất quán ban đầu.
Nếu việc tiếp tục khác với quy trình liên tục, hãy giữ checkpoint để kiểm tra. So sánh trạng thái đã khôi phục và các phiên bản, thay vì hài lòng với một điểm cuối gần đúng. Trước mọi xóa bỏ, hãy giữ kết quả và hình hữu ích.
Chỉ dọn dẹp những gì được dự kiến
docker compose down
docker compose run --rm tutorial python scripts/clean.py --outputs-only
docker compose down
Lệnh docker compose down đầu tiên dừng các dịch vụ dự án. Script hiển thị rồi chỉ xóa outputs; lệnh dừng cuối kết thúc quy trình. Nó không xóa mô hình, dữ liệu, volume toàn cục hay dự án khác. Không cần dọn dẹp Docker tổng quát.
Sự cô lập của quy trình có phạm vi chính xác
Các dịch vụ dùng hệ thống tệp gốc chỉ đọc, không thêm khả năng Linux, no-new-privileges, giới hạn CPU, bộ nhớ và tiến trình, cùng thư mục tạm trong tmpfs. Các vai trò huấn luyện, suy luận và hiệu chỉnh chỉ gắn các tài nguyên cần cho thao tác của chúng.
Các giới hạn này hạn chế quyền truy cập và tài nguyên sẵn có. Chúng không có nghĩa không thể ghi đầu ra nào: các vị trí cần thiết đã được dự kiến theo từng vai trò. Tương tự, không tải trọng số bên thứ ba không có nghĩa quá trình dựng ảnh không dùng mạng: nó có thể phân giải các phụ thuộc được xác định trong tệp build. Bản thân phép tính mô hình được cô lập khỏi mạng.
Sự tách biệt này đặc biệt giảm rủi ro vô tình đọc nhãn trong bài tập. Nó không phải biện pháp bảo vệ trước quản trị viên Docker, cũng không phải chứng nhận bảo mật.
Thiết kế cảnh báo mà một người có thể xử lý
Trong một ứng dụng thực tế, cần trình bày tiền tố đã quan sát, sự kiện và thời gian chờ liên quan, điểm, ngưỡng và các phiên bản của chúng. Điều đó giúp người vận hành hiểu điều gì đã kích hoạt cảnh báo, mà không tuyên bố mô hình giải thích nguyên nhân của sự chậm trễ hay lặp lại. Giao diện này là công việc sản phẩm cần bổ sung, không phải tính năng đã được chứng minh ở đây.
Một hệ thống giám sát thực tế cũng phải xử lý múi giờ, dữ liệu đến muộn, sự kiện đồng thời và danh tính hồ sơ. Một thứ tự toàn phần tiện dụng cho bảng dữ liệu không mô tả toàn bộ quan hệ nhân quả của workflow song song. Nếu hai thao tác đồng thời, sắp chúng theo quy ước không chứng minh thao tác này gây ra thao tác kia.
Vẫn cần thêm xác thực, quyền, lọc, API, hàng đợi rà soát con người, phiên bản hóa mô hình, khả năng quan sát, kiểm thử tải, sao lưu và đánh giá nghiệp vụ. Trên hết cần xác định ai nhận cảnh báo, họ được thấy ngữ cảnh nào, cách đóng cảnh báo và chi phí của cảnh báo sai hay nhiễu bị bỏ sót.
Thay đổi quy trình cần rà soát nghiệp vụ, một phiên bản quy tắc, huấn luyện mới khi hợp lý và tập kiểm soát riêng. Phân tích theo độ dài và cảnh báo trước nhiễu giúp chẩn đoán hệ thống; chúng không thay thế quyết định của con người.
Không cảnh báo nào trong hướng dẫn này tự động hóa một hành động đối với một người hay một hồ sơ. Bộ phát hiện là công cụ phân loại để xem xét các lộ trình, không phải trọng tài hành chính.
Tổng kết
Chúng ta đã xây dựng mô hình học cách dự đoán phần tiếp theo của một nhật ký bình thường, thay vì trực tiếp nhận diện một danh sách lỗi. LSTM giữ ngữ cảnh tuần tự, hai đầu ra dự đoán sự kiện và thời gian chờ, còn các mất mát đo khoảng cách với điều thực sự xảy ra.
Mặt nạ tránh học trên phần đệm. Các thống kê huấn luyện làm các thành phần điểm có thể dùng cùng nhau. Xác thực đặt ngưỡng trước kiểm thử, với quy tắc nghiêm ngặt cho các giá trị bằng nhau. Cuối cùng, precision, recall, thứ hạng và độ trễ phát hiện trả lời những câu hỏi khác nhau.
Mô hình liên hợp phát hiện 90 nhiễu của kiểm thử tổng hợp với một dương tính giả. Tuy vậy, cả hai LSTM đều báo 60 vết chạy của thực hành bình thường mới. Học điều thường gặp không phải là học điều được phép. Chính sự phân biệt này phải đi cùng cảnh báo đến giao diện và người chịu trách nhiệm xem xét nó.
Nguồn chính và tài liệu bổ sung
Các tài liệu tham chiếu của quy trình là tài liệu PyTorch về LSTM, tài liệu về cross_entropy và nghiên cứu của Brown và cộng sự về log. Nghiên cứu sau xem xét mạng hồi tiếp có attention để phát hiện bất thường trong nhật ký hệ thống; nó cung cấp bối cảnh nghiên cứu, không phải kết quả của tập dữ liệu tài liệu này hay kiến trúc attention được thêm vào mã đã trình bày.
Các liên kết bổ sung trong phần giải thích ghi lại embedding, biến đổi số, mất mát Gaussian, AdamW, khả năng tái lập và average precision. Chúng làm sáng tỏ cơ chế và các ví dụ tính toán; chúng không phải các lần chạy dự án mới. Để tái tạo r004, hãy giữ các tệp và phiên bản của ZIP.