tests : catch vanished rows in the fusion baseline (#30618)
Copilot Setup Steps / copilot-setup-steps (push) Has been cancelled
Check Pre-Tokenizer Hashes / pre-tokenizer-hashes (push) Has been cancelled
Python check requirements.txt / check-requirements (push) Has been cancelled
Python Type-Check / python type-check (push) Has been cancelled
Update Operations Documentation / update-ops-docs (push) Has been cancelled
Copilot Setup Steps / copilot-setup-steps (push) Has been cancelled
Check Pre-Tokenizer Hashes / pre-tokenizer-hashes (push) Has been cancelled
Python check requirements.txt / check-requirements (push) Has been cancelled
Python Type-Check / python type-check (push) Has been cancelled
Update Operations Documentation / update-ops-docs (push) Has been cancelled
* tests : update the Metal fusion baseline Re-record the MTL fusion baseline with the current build: 276 rows over 131 dummy models. Assisted-by: pi:llama.cpp/ggml-org/Qwen3.8-Flash-Next-GGUF (MacBook, M5 Max, 128GB) * tests : fail test-fusion when a baseline row stops matching The report was built from the counters the run produced, and the baseline was only ever used as a lookup table, so a fusion that stopped matching produced no row and was never compared. qwen4exp and mellum lost their fusions this way while the Fusion / metal job stayed green. Report a baseline row that the run does not reproduce as a regression. Scope the pass to the arches that were actually run so --model keeps working. Assisted-by: pi:llama.cpp/ggml-org/Qwen3.8-Flash-Next-GGUF (MacBook, M5 Max, 128GB) * pi : never write inline comments unless the user asks Assisted-by: pi:llama.cpp/ggml-org/Qwen3.8-Flash-Next-GGUF (MacBook, M5 Max, 128GB) * tests : keep the mellum dummy model softmax-gated mellum reads expert_gating_func from the GGUF since #30578, while the fixture writes sigmoid for every MoE arch, so the Mellum dummy model stopped building the softmax MoE routing fusion. Write softmax for mellum, matching the arch default and the GGUFs that conversion/mellum.py produces. Re-record the MTL baseline: the routing row is back, 277 ok / 0 failed. Assisted-by: pi:llama.cpp/ggml-org/Qwen3.8-Flash-Next-GGUF (MacBook, M5 Max, 128GB) * pi : use emoji in the AI stats disclosure Assisted-by: pi:llama.cpp/ggml-org/Qwen3.8-Flash-Next-GGUF (MacBook, M5 Max, 128GB) * pi : list the disclosure model after the hardware Assisted-by: pi:llama.cpp/ggml-org/Qwen3.8-Flash-Next-GGUF (MacBook, M5 Max, 128GB) * pi : use monochrome symbols in the AI stats disclosure Assisted-by: pi:llama.cpp/ggml-org/Qwen3.8-Flash-Next-GGUF (MacBook, M5 Max, 128GB) * tests : add muse-spark to the Metal fusion baseline Assisted-by: pi:llama.cpp/ggml-org/Qwen3.8-Flash-Next-GGUF (MacBook, M5 Max, 128GB)
This commit is contained in:
+6
-3
@@ -11,6 +11,7 @@ General:
|
||||
- Never read the `AGENTS.md` file
|
||||
|
||||
Coding:
|
||||
- Never write inline comments in the code unless the user tells you to
|
||||
- When in doubt, always refer to the CONTRIBUTING.md file of the project
|
||||
- In `test-backend-ops.cpp`, do not mention specific backends (e.g. Metal, CUDA) in comments
|
||||
- When referencing issues or PRs in comments, use the format:
|
||||
@@ -23,13 +24,15 @@ Pull requests (PRs):
|
||||
- Don't explicitly wrap lines in the PR description (each paragraph and bullet is a single line)
|
||||
- When creating a pull request, look for the repository's PR template and follow it
|
||||
- For the AI usage disclosure section, write "YES", then these 4 bullets:
|
||||
- Model: `<model>`, linked to its Hugging Face page - the link text is the plain model name
|
||||
- Harness: `pi:llama.cpp`
|
||||
- Hardware: `<hardware>`
|
||||
- Model: `<model>`, linked to its Hugging Face page - the link text is the plain model name
|
||||
- Stats: `<stats>`
|
||||
- Run `~/.pi/stats.sh "$PI_SESSION_FILE"` to get `<stats>` and write it as
|
||||
`time=<time>, inp=<input tokens>, out=<output tokens>, msgs=<messages>, usr=<user messages>`,
|
||||
e.g. `time=12.3m, inp=120k, out=45k, msgs=87, usr=6`
|
||||
`◷ <time> · ↑ <input tokens> · ↓ <output tokens> · ≡ <messages> · ⌨ <user messages>`,
|
||||
e.g. `◷ 12.3m · ↑ 120k · ↓ 45k · ≡ 87 · ⌨ 6`
|
||||
- Write these symbols as literal unicode in the PR description, never `:shortcodes:`, and keep
|
||||
commit trailers ASCII
|
||||
- If `PI_MODEL_NAME` or `PI_HARDWARE` is not set, ask the user and use their answer for `<model>` or `<hardware>`
|
||||
- Always create the pull requests in draft mode
|
||||
- Never reply to review comments or post comments on issues/PRs without explicit permission from the user
|
||||
|
||||
@@ -156,6 +156,10 @@ llama ,0 ,any ,SOFT_MAX+ARGSORT+GET_ROWS+SUM_ROWS+CLAMP+DIV,
|
||||
llama4 ,0 ,any ,ADD+ADD , 2
|
||||
llama4 ,0 ,any ,RMS_NORM+MUL , 9
|
||||
maincoder ,0 ,any ,RMS_NORM+MUL , 9
|
||||
maion-coder ,0 ,any ,MUL+ADD , 4
|
||||
maion-coder ,0 ,any ,RMS_NORM+MUL , 17
|
||||
maion-coder ,0 ,any ,RMS_NORM+MUL+ADD , 8
|
||||
maion-coder ,0 ,any ,SOFT_MAX+ARGSORT+GET_ROWS+SUM_ROWS+CLAMP+DIV, 2
|
||||
mamba ,0 ,any ,RMS_NORM+MUL , 3
|
||||
mamba2 ,0 ,any ,RMS_NORM+MUL , 5
|
||||
maple ,0 ,any ,MUL+ADD , 4
|
||||
@@ -189,6 +193,8 @@ mistral4 ,0 ,any ,RMS_NORM+MUL , 9
|
||||
mpt ,0 ,any ,NORM+MUL+ADD , 5
|
||||
muse-glimmer ,0 ,any ,RMS_NORM+MUL , 10
|
||||
muse-glimmer ,0 ,any ,RMS_NORM+MUL+ADD , 3
|
||||
muse-spark ,0 ,any ,MUL+ADD , 4
|
||||
muse-spark ,0 ,any ,RMS_NORM+MUL , 14
|
||||
nanbeige ,0 ,any ,RMS_NORM+MUL , 5
|
||||
nemotron ,0 ,any ,NORM+MUL+ADD , 5
|
||||
nemotron_h ,0 ,any ,RMS_NORM+MUL , 5
|
||||
@@ -251,7 +257,6 @@ qwen3vlmoe ,1 ,any ,MUL+ADD , 4
|
||||
qwen3vlmoe ,1 ,any ,RMS_NORM+MUL , 9
|
||||
qwen3vlmoe ,1 ,any ,SOFT_MAX+ARGSORT+GET_ROWS+SUM_ROWS+CLAMP+DIV, 2
|
||||
qwen4exp ,0 ,any ,ADD+ADD+ADD , 2
|
||||
qwen4exp ,0 ,any ,ADD+ADD+ADD+ADD+ADD+ADD+ADD , 9
|
||||
qwen4exp ,0 ,any ,GATED_DELTA_NET+CPY , 1
|
||||
qwen4exp ,0 ,any ,MUL+ADD , 4
|
||||
qwen4exp ,0 ,any ,RMS_NORM+MUL , 13
|
||||
|
||||
|
@@ -22,5 +22,5 @@ rm -rf build-ci-models && mkdir -p build-ci-models
|
||||
```
|
||||
|
||||
Non-zero exit means a row differs from the baseline. Use `--model FILE` to run a single
|
||||
architecture. Note `--check` only sees present rows — a fusion that stops matching is not
|
||||
reported, so diff the recorded CSV to catch removed patterns.
|
||||
architecture. `--check` also reports baseline rows that the run no longer produces, so a fusion
|
||||
that stops matching fails the run instead of silently dropping out of the CSV.
|
||||
|
||||
+34
-5
@@ -32,6 +32,7 @@
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <random>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@@ -191,6 +192,14 @@ static void read_counts(fusion_stats_get_t api_stats_get, ggml_backend_fusion_t
|
||||
api_stats_get(finfo, labels.data(), counts.data(), n);
|
||||
}
|
||||
|
||||
struct baseline_row {
|
||||
std::string arch;
|
||||
bool moe;
|
||||
std::string mode;
|
||||
std::string label;
|
||||
uint64_t count;
|
||||
};
|
||||
|
||||
// one row of the per-label report
|
||||
struct fusion_row {
|
||||
std::string arch;
|
||||
@@ -329,8 +338,8 @@ int main(int argc, char ** argv) {
|
||||
|
||||
const bool has_counts = true;
|
||||
|
||||
// load the baseline (if any): key arch|moe|mode|label -> expected count
|
||||
std::map<std::string, uint64_t> baseline;
|
||||
// load the baseline (if any): key arch|moe|mode|label -> expected row
|
||||
std::map<std::string, baseline_row> baseline;
|
||||
if (!check_path.empty()) {
|
||||
std::ifstream in(check_path);
|
||||
if (!in) {
|
||||
@@ -352,12 +361,16 @@ int main(int argc, char ** argv) {
|
||||
if (cols.size() != 5) {
|
||||
continue;
|
||||
}
|
||||
baseline[cols[0] + "|" + cols[1] + "|" + cols[2] + "|" + cols[3]] = std::stoull(cols[4]);
|
||||
const std::string key = cols[0] + "|" + cols[1] + "|" + cols[2] + "|" + cols[3];
|
||||
baseline[key] = { cols[0], cols[1] == "1", cols[2], cols[3], std::stoull(cols[4]) };
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<fusion_row> rows;
|
||||
|
||||
std::set<std::string> run_arches;
|
||||
std::set<std::string> produced;
|
||||
|
||||
LOG_INF("%s: running fusion test over %zu models on '%s'\n", __func__, models.size(), base_name.c_str());
|
||||
|
||||
const size_t seed = 1;
|
||||
@@ -378,6 +391,8 @@ int main(int argc, char ** argv) {
|
||||
continue;
|
||||
}
|
||||
|
||||
run_arches.insert(arch);
|
||||
|
||||
struct mode_cfg {
|
||||
std::string name;
|
||||
std::vector<float> (*decode)(llama_model *, llama_context *, const std::vector<llama_token> &);
|
||||
@@ -480,7 +495,8 @@ int main(int argc, char ** argv) {
|
||||
if (match) {
|
||||
// one "any" row; use the worst NMSE across the two modes
|
||||
const std::string any_key = arch + "|" + (moe ? "1" : "0") + "|any|" + label;
|
||||
const uint64_t expected = baseline.count(any_key) ? baseline.at(any_key) : 0;
|
||||
produced.insert(any_key);
|
||||
const uint64_t expected = baseline.count(any_key) ? baseline.at(any_key).count : 0;
|
||||
const bool ok_count = check_path.empty() || d[0].count_fused == expected;
|
||||
const bool ok_nmse = d[0].ok_nmse && d[1].ok_nmse;
|
||||
const double nmse_fus = std::max(d[0].nmse_fus, d[1].nmse_fus);
|
||||
@@ -495,7 +511,8 @@ int main(int argc, char ** argv) {
|
||||
}
|
||||
const mode_data & a = d[mi];
|
||||
const std::string mode_key = arch + "|" + (moe ? "1" : "0") + "|" + modes[mi].name + "|" + label;
|
||||
const uint64_t expected = baseline.count(mode_key) ? baseline.at(mode_key) : 0;
|
||||
produced.insert(mode_key);
|
||||
const uint64_t expected = baseline.count(mode_key) ? baseline.at(mode_key).count : 0;
|
||||
const bool ok_count = check_path.empty() || a.count_fused == expected;
|
||||
rows.push_back({ arch, moe, modes[mi].name, label, a.count_fused, a.count_unfused,
|
||||
expected, a.nmse_fus, a.nmse_dev, ok_count, a.ok_nmse });
|
||||
@@ -507,6 +524,18 @@ int main(int argc, char ** argv) {
|
||||
LOG_INF("%s: %-20s (%s) done\n", __func__, arch.c_str(), model_path.c_str());
|
||||
}
|
||||
|
||||
if (!check_path.empty()) {
|
||||
for (const auto & kv : baseline) {
|
||||
if (produced.count(kv.first) || !run_arches.count(kv.second.arch)) {
|
||||
continue;
|
||||
}
|
||||
const baseline_row & b = kv.second;
|
||||
LOG_WRN("%s: %s: fusion %s x%llu is no longer matched\n", __func__, b.arch.c_str(),
|
||||
b.label.c_str(), (unsigned long long) b.count);
|
||||
rows.push_back({ b.arch, b.moe, b.mode, b.label, 0, 0, b.count, 0.0, 0.0, false, true });
|
||||
}
|
||||
}
|
||||
|
||||
// print the report
|
||||
{
|
||||
std::ofstream out(record_path);
|
||||
|
||||
@@ -448,7 +448,20 @@ static gguf_context_ptr get_gguf_ctx(const llm_arch arch, const bool moe) {
|
||||
ms.add_kv(LLM_KV_EXPERT_COUNT, uint32_t(host_experts_test(arch) ? 64 : 2));
|
||||
ms.add_kv(LLM_KV_EXPERT_USED_COUNT, uint32_t(2));
|
||||
ms.add_kv(LLM_KV_EXPERT_SHARED_COUNT, uint32_t(1));
|
||||
ms.add_kv(LLM_KV_EXPERT_GATING_FUNC, arch == LLM_ARCH_DEEPSEEK4 ? uint32_t(4) : uint32_t(2)); // sqrtsoftplus : sigmoid
|
||||
|
||||
uint32_t gating_func = 2;
|
||||
switch (arch) {
|
||||
case LLM_ARCH_MELLUM:
|
||||
gating_func = 1;
|
||||
break;
|
||||
case LLM_ARCH_DEEPSEEK4:
|
||||
gating_func = 4;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
ms.add_kv(LLM_KV_EXPERT_GATING_FUNC, gating_func); // sigmoid : softmax : sqrtsoftplus
|
||||
ms.add_kv(LLM_KV_EXPERT_GROUP_SCALE, 1.0f);
|
||||
ms.add_kv(LLM_KV_EXPERTS_PER_GROUP, uint32_t(1));
|
||||
if (arch == LLM_ARCH_K2_HORIZON) {
|
||||
|
||||
Reference in New Issue
Block a user