Bạn tự lấy hidden states của một Transformer rồi tính trung bình để tạo embedding câu. Với một câu đứng riêng, kết quả có vẻ hợp lý; khi ghép batch có câu dài hơn, số vị trí padding tăng và phép trung bình có thể đổi. Trước khi sửa tìm kiếm hoặc prompt, hãy kiểm tra những vị trí nào đang tham gia pooling.
Bài đối chiếu tài liệu ngày 30/10/2026. Phép tính minh họa chạy bằng Python 3.9.6, không tải model, không chạy PyTorch và không đo chất lượng tìm kiếm. Các vector hai chiều bên dưới do bài tự đặt để nhìn thấy lỗi, không phải hidden states của một câu thật.
Mask phải đi vào cả phép tính trung bình
Padding làm các chuỗi trong batch có cùng số vị trí. Nó khác truncation: truncation loại phần vượt giới hạn; padding thêm vị trí cho chuỗi ngắn. Tài liệu Transformers 4.57.1 mô tả hai thao tác này. Phiên bản được ghim để đối chiếu, không được gọi là bản mới nhất.
Giả sử encoder trả một vector cho mỗi vị trí. Mean pooling có mask cộng các vector ở vị trí được giữ, rồi chia cho số vị trí được giữ. Mẫu số không phải tổng chiều dài tensor sau padding.
Trong model card all-MiniLM-L6-v2, ví dụ dùng Transformers trực tiếp có bước mean pooling theo attention mask. Đây là bằng chứng cho cấu hình của model đó, không phải quy tắc rằng mọi model embedding đều phải lấy trung bình.
Một fixture có thể tự tính
Hai vị trí đầu là nội dung được giữ. Hai vị trí cuối đại diện padding với giá trị giả cố tình lớn và lệch về chiều đầu:
rows = [[2.0, 0.0], [0.0, 2.0], [10.0, 0.0], [10.0, 0.0]]
mask = [1, 1, 0, 0]
ordinary = [sum(row[j] for row in rows) / len(rows) for j in range(2)]
print(ordinary)
Kết quả là [5.5, 0.5]. Nếu chỉ hai vị trí đầu tham gia, trung bình phải là [1.0, 1.0]. Fixture không giả định hidden state của padding trong model thật bằng 10, cũng không giả định nó luôn bằng không. Nó chỉ kiểm tra việc loại đúng vị trí theo hợp đồng mask.
def masked_mean(rows, mask):
if not rows or len(rows) != len(mask):
raise ValueError('Rows and mask must have the same non-zero length')
width = len(rows[0])
if width == 0 or any(len(row) != width for row in rows):
raise ValueError('All rows must have the same non-zero width')
if any(flag not in (0, 1) for flag in mask):
raise ValueError('Mask must contain only 0 or 1')
count = sum(mask)
if count == 0:
raise ValueError('No position selected for pooling')
return [
sum(row[j] * keep for row, keep in zip(rows, mask)) / count
for j in range(width)
]
print(masked_mean(rows, mask))
print(masked_mean(rows[:2], [1, 1]))
Cả hai dòng in [1.0, 1.0]. Hàm này dành cho ma trận số hữu hạn trong bài, không thay thế một implementation tensor phục vụ inference. Nó kiểm tra shape và mask để không âm thầm bỏ phần tử do zip gặp hai danh sách lệch độ dài.
Kiểm tra thêm những ca dễ bị che
Thêm một hàng padding bất kỳ cùng mask 0: kết quả của hàm phải giữ nguyên khi các hàng được giữ không đổi. Đổi mask của hàng đó thành 1 thì nó phải tham gia tổng và mẫu số. Đây là hai kiểm tra khác nhau, nên giữ cả hai.
Thử mask toàn 0 và xác nhận hàm báo lỗi. Một thư viện có thể chọn chặn mẫu số bằng epsilon để tránh chia cho không; ứng dụng vẫn cần quyết định một input không còn vị trí hợp lệ có được đưa vào index hay không. Không coi vector trả về chỉ vì không có exception là dữ liệu hợp lệ.
Trong phép thử thật, so câu đứng riêng với cùng câu trong batch dài hơn, dùng tolerance phù hợp với dtype và thiết bị. Bài không tuyên bố đã thực hiện phép thử model này. Sai khác số học nhỏ cũng không đồng nghĩa lỗi pooling, nên cần quan sát cả mask, shape và cấu hình thực thi.
Pooling đúng chưa đủ để sửa encoder sai
Attention mask cũng cần được truyền đúng cho encoder theo API của model. Nếu những token nội dung đã được tính hidden states với cấu hình attention sai, loại padding ở bước cuối không thể quay lại sửa toàn bộ phép tính trước đó.
Đừng tự xóa mọi special token chỉ vì chúng không giống từ trong câu. Vị trí nào được giữ, có loại prompt không, dùng mean hay CLS/last-token đều thuộc cấu hình model. Sentence Transformers Modules liệt kê nhiều chiến lược pooling và tùy chọn về prompt.
Giới hạn và cách áp dụng
Ví dụ chỉ có một chuỗi, trong khi tensor thật thường có thêm trục batch. Khi chuyển sang tensor, xác định đúng trục token trước khi gọi sum hoặc mean. Đừng vô tình gộp cả batch thành một vector.
Model card được dẫn có nhãn ngôn ngữ English; bài không dùng nó làm khuyến nghị chất lượng tiếng Việt. Việc sửa mask không tự chứng minh Recall hoặc độ đúng câu trả lời đã tăng. Sau khi xác nhận phép tính đúng, đánh giá lại trên dữ liệu và cấu hình model được lưu rõ ràng.
Hãy giữ một fixture pooling nhỏ bên cạnh kiểm tra inference thực tế. Fixture giúp bắt lỗi shape và mẫu số; bộ đánh giá nghiệp vụ mới trả lời hệ thống tìm kiếm có hữu ích hơn hay không.


