Cùng model, khác output — cái bẫy số học của MoE

Cùng model, khác output — cái bẫy số học của MoE

Kernel fusion tối ưu tốc độ nhưng lại khiến training và inference cho kết quả khác nhau. Chuyện gì đang xảy ra bên trong MoE?

Bạn có chắc model đang serve đúng cái bạn đã train?

Mình hỏi thật: lần cuối bạn so output giữa training và inference là khi nào? Cùng weight, cùng input, cùng kiến trúc — đáng lẽ phải ra cùng kết quả, đúng không? Với dense model thì thường là vậy. Nhưng với Mixture-of-Experts (MoE) — dòng kiến trúc đang chạy trong Kimi K2.5, Qwen3.5-MoE, hay DeepSeek V3 — câu trả lời là: không hẳn.

Fireworks AI vừa chia sẻ một bài post-mortem chi tiết về những bug "vô hình" họ gặp khi đưa MoE model từ training sang serving. Loại bug mà weight giống nhau y đúc, code review sạch sẽ, benchmark xanh lè — nhưng output cứ lệch dần. Hiểu nôm na: bạn xây hai căn nhà từ cùng bản vẽ, cùng vật liệu, nhưng hai đội thợ xếp gạch theo thứ tự khác nhau — và bức tường cuối cùng hơi cong so với bản gốc.

Khoan, phép cộng mà cũng sai được?

Đây là phần khiến nhiều người giật mình: với floating-point, a + b + c không nhất thiết bằng a + c + b. Trên giấy thì bằng, nhưng khi máy tính làm phép cộng với số thực có độ chính xác hữu hạn (FP16, BF16), thứ tự cộng khác nhau sẽ cho kết quả khác nhau ở những chữ số cuối. Sai số này nhỏ xíu — nhưng qua hàng trăm layer của một MoE model, nó tích lũy như nứt chân tóc trên tường chịu lực: không thấy, cho đến khi thấy thì đã muộn.

Vấn đề nằm ở chỗ: khi bạn tối ưu inference bằng kernel fusion, communication overlap, hay thay đổi all-reduce topology, bạn đang vô tình thay đổi thứ tự phép cộng. Phép toán vẫn "đúng" về mặt toán học, nhưng kết quả số học thì drift.

Ba cái bẫy mà team nào chạy MoE cũng có thể dính

Bẫy 1 — All-reduce topology lệch pha. Giả sử team bạn train model trên cluster 8 GPU với một cách chia tensor nhất định, nhưng serve trên 4 GPU với topology khác. All-reduce — phép gom kết quả từ nhiều GPU — sẽ cộng các partial sum theo thứ tự khác. Kết quả: drift.

Bẫy 2 — Fuse communication với computation. Trick phổ biến để tăng throughput: overlap tính toán với gửi/nhận data giữa GPU. Nhanh hơn đáng kể, nhưng thứ tự accumulate thay đổi. Tưởng tượng công trình mà đội điện và đội nước thi công song song cho kịp deadline — tiết kiệm thời gian thật, nhưng đường ống đôi chỗ lệch vài milimet so với bản thiết kế vì hai đội không sync từng bước.

Bẫy 3 — Multi-operation fusion trong MoE. MoE có nhiều expert chạy song song, mỗi expert xử lý một subset token. Khi bạn fuse cả chuỗi gate → expert dispatch → compute → combine thành một kernel lớn, thứ tự tính toán bên trong có thể khác hoàn toàn version "từng bước một" lúc training.

Chuyện thật: khi image token phản chủ

Fireworks kể về case Qwen3.5-MoE xử lý multimodal input. Với text token, drift nhỏ, nằm trong ngưỡng chấp nhận được. Nhưng khi model xử lý image token, drift tăng vọt. Lý do: image token phải đi qua vision encoder trước khi vào MoE backbone — thêm một lớp phép tính, thêm một chỗ để sai số tích lũy.

Ví dụ cụ thể: giả sử team bạn đang fine-tune một MoE model cho task phân loại hình ảnh sản phẩm e-commerce. Training loss giảm đẹp, eval metric ngon lành. Deploy lên inference server với kernel fusion bật full — model bắt đầu classify sai một số hình ảnh mà lúc train nó nhận đúng. Bạn debug cả tuần: check data pipeline, check weight loading, check preprocessing — mọi thứ đều sạch. Thủ phạm thật sự? Thứ tự phép cộng floating-point bị đổi khi fusion kernel chạy.

Khi drift trở thành lỗ hổng alignment

Nếu bạn đang dùng RLHF hoặc GRPO để align model, chuyện nghiêm trọng hơn nhiều. Reference model cần cho ra logprobs nhất quán giữa training và inference. Có drift nghĩa là KL penalty — cái "dây neo" giữ policy không bay quá xa — bị lỏng hoặc chặt sai chỗ. Policy có thể khai thác khoảng cách này mà không thực sự cải thiện. Nói cách khác: model học được cách gian lận điểm mà bạn không hay biết.

Bốn bước kiểm tra ngay chiều nay

Bạn không cần đợi gặp bug production mới hành động:

  1. So logprobs head-to-head: chạy cùng batch input qua training forward pass và inference server, so sánh logprobs. Max absolute difference vượt ngưỡng noise floor (~1e-3 cho BF16) là bạn có drift.
  1. Tắt fusion, chạy lại: hầu hết inference framework — vLLM, TensorRT-LLM, hay các serving stack khác — đều cho disable kernel fusion. Tắt hết, so kết quả. Drift biến mất → bạn biết thủ phạm.
  1. Test riêng từng modality: như case Qwen3.5-MoE, text và image token drift khác nhau. Đừng test mỗi text rồi kết luận "ổn rồi".
  1. Ghi lại topology: document chính xác GPU topology, tensor parallel config, all-reduce algorithm cho cả training lẫn inference. Khác nhau ở đây là nguồn drift phổ biến nhất mà ít ai kiểm tra.

Spoiler: không có silver bullet

MoE đang là kiến trúc được săn đón vì hiệu quả tính toán — model lớn nhưng chỉ activate một phần nhỏ expert cho mỗi token. Cái giá phải trả là complexity khi serving. Numerical parity không phải bug fix một lần rồi quên — nó là trade-off liên tục giữa tốc độ inference và độ trung thực với training.

Như mình đã đề cập trong các bài về agent evaluation trước: hệ thống AI không chỉ cần chạy đúng lúc demo — nó cần chạy đúng mọi lúc, kể cả sau khi bạn bật đủ loại tối ưu. Với MoE, "đúng" bao gồm cả chuyện hai con GPU có cộng số theo cùng thứ tự hay không.

Lần sau thấy model serve khác lúc train, đừng vội đổ cho data hay hyperparameter. Có khi chỉ vì phép cộng a + b + ca + c + b cho ra hai con số khác nhau — và trong thế giới floating-point, chừng đó đủ để cả tòa nhà bạn xây nghiêng mấy độ rồi.

---

Bụi Wire — nghiện đọc release notes lúc 2 giờ sáng

Nguồn tham khảo