Đánh giá thế cờ và NNUE
Đánh giá trả lời “thế cờ này có vẻ ra sao”, còn tìm kiếm trả lời “điều gì sẽ xảy ra nếu hai bên tiếp tục đi”. NNUE cung cấp nhận định nhanh cho tìm kiếm của engine (động cơ cờ), không trực tiếp đưa ra nước tốt nhất và cũng không thay thế việc xét sát cục, lặp lại hay luật cờ.
Bài viết được đối chiếu với official Pikafish tại commit 1c66b9b. Phần dưới giải thích cách bản mã này thực sự sử dụng mạng; không thể chỉ dựa vào mã suy luận để kết luận nguồn dữ liệu, quy mô hay quy trình huấn luyện.
Từ bàn cờ đến điểm số: từng phần làm gì?
Một lần đánh giá tĩnh thông thường đại thể đi qua các bước sau:
- Mã hóa vị trí quân và một số quan hệ giữa các quân thành đặc trưng đầu vào của mạng.
- Dùng lại và cập nhật bộ tích lũy, rồi tính các lớp mạng phía sau để có điểm NNUE thô.
evaluate.cppđiều chỉnh điểm theo lực lượng quân, xu hướng tìm kiếm, bộ đếm luật 60 nước và các thông tin khác.- Tìm kiếm bổ sung hiệu chỉnh đánh giá khi cần, rồi so sánh các biến tiếp theo để đưa ra kết quả tìm kiếm.
Không thể dùng lẫn các loại điểm này. Điểm hiển thị trên giao diện còn qua bước chuyển đổi đầu ra; xem Vận hành engine và xuất điểm. Để biết tìm kiếm dùng đánh giá thế nào, xem Thuật toán tìm kiếm.
Mã nguồn: Tính giá trị mạng, Điểm vào đánh giá và điều chỉnh thang điểm, Hiệu chỉnh đánh giá trong tìm kiếm.
evaluate.cpp: không chỉ gọi mạng một lần
Eval::evaluate() hiện tại gọi NNUE trước, rồi điều chỉnh thang điểm. Hàm yêu cầu thế cờ không bị chiếu; các nút đang bị chiếu được xử lý theo quy trình tương ứng trong tìm kiếm. Không thể coi một điểm tĩnh thông thường là kết quả của việc tìm nước thoát chiếu.
simple_eval() tính chênh lệch lực lượng quân một cách sơ bộ để so sánh với nhận định của NNUE, không phải bộ đánh giá dự phòng khi nạp mạng thất bại. Quá trình xử lý chủ yếu làm bốn việc:
- So sánh chênh lệch lực lượng và điểm NNUE có cùng chiều hay không: chẳng hạn, thế cờ kém quân nhưng được mạng đánh giá tốt khác với ưu thế đơn thuần do hơn quân.
- Điều chỉnh kết quả theo
optimismdo tìm kiếm truyền vào; giá trị này đến từ điểm của ứng viên ở gốc, không phải cộng điểm ngẫu nhiên hay hệ số Elo của người dùng. - Điều chỉnh thang điểm theo tổng lực lượng trên bàn và kéo điểm về gần 0 khi bộ đếm luật 60 nước tăng.
- Giữ đánh giá thông thường nằm ngoài vùng điểm sát cục, tránh diễn đạt nhầm “ưu thế rất lớn” thành “đã tính ra sát cục”.
Vì vậy, điểm NNUE thô có thể khác với đánh giá tĩnh mà engine thực sự dùng trong tìm kiếm. Điều chỉnh theo luật 60 nước cũng chỉ thay đổi ước lượng điểm; có thực sự phát sinh phán định hòa hay quy định khác hay không vẫn do mã xử lý luật quyết định.
Mã nguồn: So sánh lực lượng và điều chỉnh thang điểm, Nguồn của optimism.
NNUE xem những thông tin nào?
Bản mã này dùng đồng thời hai loại đầu vào:
| Đặc trưng | Có thể hiểu thế nào? |
|---|---|
HalfKAv2_hm | Ghi nhận “quân gì ở điểm nào”, đồng thời chọn nhóm đặc trưng theo vị trí Tướng, phép phản chiếu trái phải và tổ hợp Xe, Mã, Pháo của bên mình. |
FullThreats | Lấy các quan hệ tấn công / bảo vệ đã qua chọn lọc giữa các quân trên bàn hiện tại, bổ sung thông tin “các quân tác động lên nhau ra sao”. |
Loại đầu không phải bảng điểm vị trí quân cố định: vị trí được mã hóa thành đầu vào, rồi các trọng số cùng tham gia tính toán. Loại sau tuy mang tên FullThreats nhưng không có nghĩa đã nhận ra mọi đe dọa chiến thuật. Mã tạo các quan hệ từ phạm vi tấn công hiện tại và những điểm có quân, đồng thời lọc bớt một số tổ hợp và quan hệ trùng lặp. Nó không đi thử cả chuỗi biến cho hai bên, cũng không tương đương với việc xét đầy đủ “đuổi quân” theo luật cờ. Thí quân có hiệu quả không, tấn công có dẫn đến sát cục không vẫn cần tìm kiếm.
Đỏ và Đen mỗi bên giữ góc nhìn riêng. Khi truyền vào các lớp sau, chúng được xếp theo thứ tự “bên đang đến lượt đi trước, đối thủ sau”. Cuối cùng, mạng đưa ra một điểm thế cờ từ góc nhìn của bên đang đến lượt đi.
Mã nguồn: Đặc trưng vị trí và cách chia nhóm, Lọc và trích xuất đặc trưng quan hệ, Chuyển đổi hai góc nhìn.
Cấu trúc mạng hiện tại: dùng chung phần đầu, chọn lớp sau theo lực lượng
Mỗi đối tượng Network chứa một bộ biến đổi đặc trưng và 16 bộ tham số cho các lớp sau. Khi tính giá trị thông thường, mạng chọn một bộ theo số Xe, tổng số Mã và Pháo của hai bên cùng các yếu tố về lực lượng; không phải chạy cả 16 mạng hoàn chỉnh rồi bỏ phiếu cho mỗi thế cờ.
Sau bước biến đổi đặc trưng, đầu vào cho các lớp sau có 1024 chiều; hai lớp biến đổi affine trung gian mỗi lớp cho ra 32 giá trị, cuối cùng tạo thành một điểm duy nhất. Tuy nhiên, cách viết đơn giản “1024→32→32→1” bỏ sót một phần cấu trúc: mã còn ghép các kết quả kích hoạt cắt ngưỡng và bình phương, đồng thời giữ một kết nối từ lớp trước tới đầu ra.
Các giá trị trung gian này là những kênh tính toán của mạng, không phải “biến ở nước thứ mấy” hay các điểm “Xe, an toàn của Tướng” do con người gán sẵn. Phép tính thông thường trong phiên bản này trả về một điểm; không thể áp dụng cách giải thích về mạng kép hoặc hai đầu ra đánh giá độc lập của phiên bản khác.
Mã nguồn: Cấu trúc lớp và lan truyền trong mạng, Chọn một trong 16 bộ tham số lớp sau, Điểm vào tính giá trị thông thường.
Cập nhật tăng dần: chỉ tính bù phần đã thay đổi
Hai thế cờ liền nhau thường chỉ khác một nước. Nếu mỗi nước đều cộng lại toàn bộ đầu vào thì rất tốn công. Bộ tích lũy của NNUE giữ kết quả tính phần đầu: khi đi quân, trừ đóng góp ở vị trí cũ và cộng đóng góp ở vị trí mới; khi bắt quân thì bỏ thêm đóng góp của quân bị bắt. Các quan hệ tấn công thay đổi cũng được cập nhật cùng lúc.
Cập nhật tăng dần dùng lại kết quả phần đầu, không bỏ qua toàn bộ mạng. Các lớp sau vẫn phải được tính. Ngăn xếp tìm kiếm ghi lại thay đổi; chỉ khi thực sự cần đánh giá, mã mới tìm bộ tích lũy có thể dùng lại và tính bù. Hoàn tác nước đi cũng đưa về trạng thái tương ứng. Cách làm này khác với việc bảng chuyển vị lưu kết quả tìm kiếm.
Không phải nước nào cũng dùng tiếp được bộ tích lũy trước đó. Chẳng hạn, khi Tướng bên mình di chuyển, việc bắt quân làm đổi nhóm lực lượng dùng cho đặc trưng, hoặc lựa chọn phản chiếu thay đổi, góc nhìn tương ứng sẽ yêu cầu làm mới. Việc làm mới vẫn có thể dùng bộ nhớ đệm tổ chức theo vị trí Tướng và các thông tin khác, so sánh chênh lệch quân để cập nhật đặc trưng vị trí rồi thêm lại các đặc trưng quan hệ hiện tại, thay vì lần nào cũng tính lại toàn bộ từ đầu.
Mã nguồn: Ngăn xếp bộ tích lũy và cập nhật khi cần, Cập nhật phần đặc trưng thay đổi, Điều kiện yêu cầu làm mới, Bộ nhớ đệm khi làm mới.
Lượng tử hóa và SIMD: giảm chi phí mỗi lần đánh giá
Suy luận hiện tại chủ yếu dùng phép tính số nguyên: trọng số đặc trưng dùng số nguyên 8 bit, bộ tích lũy dùng số nguyên 16 bit, kết quả nhân cộng ở các lớp sau dùng số nguyên 32 bit, kết hợp với cắt ngưỡng, dịch bit và điều chỉnh thang giá trị. Đó là ý nghĩa của lượng tử hóa ở đây: biểu diễn các giá trị mạng bằng số nguyên theo thang quy định.
Mã còn có các nhánh SIMD cho CPU khác nhau, dùng một lệnh để xử lý nhiều số cùng lúc, chẳng hạn họ SSE / AVX trên x86 và NEON trên ARM. Một số lớp tận dụng việc đầu vào có nhiều giá trị 0 để giảm công việc. Chúng tăng tốc cùng một phép đánh giá, không khiến một phiên bản “hiểu thêm một nguyên lý cờ”. Tốc độ thực tế phụ thuộc vào CPU, nhánh biên dịch và toàn bộ khối lượng công việc tìm kiếm.
Mã nguồn: Kiểu số nguyên và thang giá trị, Biến đổi đặc trưng, Cách nhân cộng ở các lớp sau, Lớp đầu vào thưa.
Tệp mạng: cùng tên chưa chắc tương thích
EvalFile chỉ định tệp mạng; tên mặc định hiện tại là pikafish.nnue. Bộ nạp thử các đường dẫn tương ứng, đọc phiên bản định dạng, mã nhận dạng cấu trúc mạng và tham số từng lớp, rồi kiểm tra đã đọc đầy đủ chưa. Nếu bước xác minh phát hiện mạng cần dùng chưa được nạp thành công, chương trình thông báo vấn đề về tương thích và đường dẫn rồi dừng, không âm thầm chuyển sang chấm điểm lực lượng đơn giản để tiếp tục chơi.
Vì thế, mạng thay thế phải khớp với kiến trúc engine; chỉ đổi tệp về cùng một tên không thể biến kiến trúc cũ thành mới. Mã nhận dạng cấu trúc ở đây dùng để kiểm tra tương thích định dạng, cũng không phải phép xác thực thật giả bằng mật mã cho mọi tệp bất kỳ.
Mã nguồn: Tên tệp mặc định, Tìm và nạp tệp, Kiểm tra định dạng và tham số, Xác minh tải mạng và xử lý lỗi.
Hiểu đầu ra gỡ lỗi của eval
Lệnh eval của engine dùng để xem chi tiết đánh giá thế cờ hiện tại, không thực hiện thay bạn một lượt tìm kiếm chọn nước thông thường. Đầu ra hiện tại vừa có đơn vị nội bộ NNUE nhìn từ bên đến lượt đi, vừa có điểm hiển thị đã đổi sang góc nhìn của Đỏ. Nhãn white side được giữ lại từ trước tương ứng với Đỏ trong bản cờ tướng.
Điểm tĩnh cuối cùng trong đầu ra gỡ lỗi này dùng optimism bằng 0, và cũng không khôi phục lịch sử hiệu chỉnh đánh giá của một nút tìm kiếm cụ thể. Vì thế, nó không nhất thiết bằng điểm sau khi tìm kiếm bằng go. Khi đang bị chiếu, phần gỡ lỗi sẽ nói rõ rằng không có đánh giá tĩnh cuối cùng theo cách thông thường.
Mã nguồn: Điểm vào lệnh eval, Đầu ra đánh giá để gỡ lỗi. Để phân biệt điểm tìm kiếm thông thường, cp, mate và WDL trong UCI, xem Xuất điểm.
