Skip to content

Commit 99ca02f

Browse files
Qualcomm AI Engine Direct - Add test verifying LLM calib/eval limits (#20234)
### Summary Add `TestExampleLLMScript.test_static_llm_eval_limit`, which compiles a static LLM once with a fixed calibration, then evaluates the same pre-generated pte twice with different eval limits and asserts the resulting wikitext perplexity differs. ### Test plan ``` bash python backends/qualcomm/tests/test_qnn_delegate.py TestExampleLLMScript.test_static_llm_eval_limit -s ${SERIAL_NUM} -m SM8750 -b build-android -a . --executorch_root . --model_name smollm2_135m ```
1 parent caf8e03 commit 99ca02f

1 file changed

Lines changed: 92 additions & 0 deletions

File tree

backends/qualcomm/tests/test_qnn_delegate.py

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8080,6 +8080,98 @@ def test_static_llm_model(self): # noqa: C901
80808080
device_inference_speed, expected_inference_speed
80818081
)
80828082

8083+
def test_static_llm_eval_limit(self):
8084+
# Verify calib and eval are truly separate: compile once with a fixed
8085+
# calib, then eval the same pte with different eval limit.
8086+
if not self.required_envs([self.model_name]):
8087+
self.skipTest("missing required envs")
8088+
assert (
8089+
self.model_name in self.llm_specs
8090+
), f"Unable to find {self.model_name} under model_specs."
8091+
8092+
def run_llama(extra_cmds):
8093+
cmds = [
8094+
"python",
8095+
f"{self.executorch_root}/examples/qualcomm/oss_scripts/llama/llama.py",
8096+
"--artifact",
8097+
self.artifact_dir,
8098+
"--build_folder",
8099+
self.build_folder,
8100+
"--prompt",
8101+
"I would like to learn python, could you teach me with a simple example?",
8102+
"--temperature",
8103+
"0",
8104+
"--decoder_model",
8105+
self.model_name,
8106+
"--model_mode",
8107+
"kv",
8108+
"--max_seq_len",
8109+
"1024",
8110+
"--max_context_len",
8111+
"1024",
8112+
"--skip_user_prompt_calibration",
8113+
"--soc_model",
8114+
self.soc_model,
8115+
"--target",
8116+
self.target,
8117+
"--ip",
8118+
self.ip,
8119+
"--port",
8120+
str(self.port),
8121+
"--seed",
8122+
str(1126),
8123+
"--backend",
8124+
self.backend,
8125+
]
8126+
cmds.extend(extra_cmds)
8127+
if self.host:
8128+
cmds.extend(["--host", self.host])
8129+
elif self.enable_x86_64:
8130+
cmds.extend(["--enable_x86_64"])
8131+
8132+
p = subprocess.Popen(cmds, stdout=subprocess.DEVNULL)
8133+
with Listener((self.ip, self.port)) as listener:
8134+
conn = listener.accept()
8135+
p.communicate()
8136+
msg = json.loads(conn.recv())
8137+
if "Error" in msg:
8138+
self.fail(msg["Error"])
8139+
return msg
8140+
8141+
# Compile once with a fixed calibration so quantization is identical
8142+
# across the eval runs below.
8143+
run_llama(
8144+
[
8145+
"--compile_only",
8146+
"--calib_tasks",
8147+
"wikitext",
8148+
"--calib_limit",
8149+
"1",
8150+
]
8151+
)
8152+
8153+
def eval_ppl(eval_limit):
8154+
extra_cmds = [
8155+
"--pre_gen_pte",
8156+
self.artifact_dir,
8157+
"--eval_methods",
8158+
"tasks_eval",
8159+
"--eval_tasks",
8160+
"wikitext",
8161+
"--eval_limit",
8162+
str(eval_limit),
8163+
]
8164+
if self.device:
8165+
extra_cmds.extend(["--device", self.device])
8166+
return run_llama(extra_cmds)["wiki_ppl"]
8167+
8168+
ppl_eval_1 = eval_ppl(1)
8169+
ppl_eval_3 = eval_ppl(3)
8170+
logging.info(
8171+
f"wiki_ppl: eval_limit=1: {ppl_eval_1}, eval_limit=3: {ppl_eval_3}"
8172+
)
8173+
self.assertNotEqual(ppl_eval_1, ppl_eval_3)
8174+
80838175
def test_codegen2_1b(self):
80848176
if not self.required_envs():
80858177
self.skipTest("missing required envs")

0 commit comments

Comments
 (0)