Skip to content

LFM3 text decoder with conv-state support in LLM runners (#24687) - #24687

Open
psiddh wants to merge 1 commit into
pytorch:mainfrom
psiddh:export-D128739913
Open

psiddh wants to merge 1 commit into
pytorch:mainfrom
psiddh:export-D128739913

Conversation

@psiddh

@psiddh psiddh commented Nov 5, 2026 •

Copy link
Copy Markdown
Contributor

Summary:

Run LFM3 through shared static_llama with rolling convolution state and a converter/config shared with the generic path. Fail closed on missing state annotations and test equal input/output encodings with production Lfm3QuantRecipe before runner byte copies. Keep the checks in existing test_qnn_delegate.py; fix OSS formatting and the loop-variable capture.

Runner::reset() now resets position for all non-attention-sink QNN text models, so Android LlmModule.resetContext() starts a new conversation. With attention sink it remains a no-op. Unsupported conv-state runner modes return NotSupported.

Known limitation: a dedicated C++ ConvStateManager unit test remains a follow-up.

Originally authored with Claude Code; updated with Metamate (agentcloud).

Differential Revision: D128739913

@psiddh
psiddh requested a review from larryliu0820 as a code owner November 5, 2026 19:50
Copilot AI balanced review requested due to automatic review settings November 5, 2026 19:50
@pytorch-bot

pytorch-bot Bot commented Nov 5, 2026 •

Copy link
Copy Markdown

🔗 Helpful Links

🧪 See artifacts and rendered test results at hud.pytorch.org/pr/pytorch/executorch/24687

Note: Links to docs will display an error until the docs builds have been completed.

✅ You can merge normally! (2 Unrelated Failures)

As of commit a8af9ff with merge base 765e973 (image):

BROKEN TRUNK - The following jobs failed but were present on the merge base:

👉 Rebase onto the `viable/strict` branch to avoid these failures

This comment was automatically generated by Dr. CI and updates every 15 minutes.

@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Nov 5, 2026
@meta-codesync

meta-codesync Bot commented Nov 5, 2026

Copy link
Copy Markdown
Contributor

@psiddh has exported this pull request. If you are a Meta employee, you can view the originating Diff in D128739913.

@github-actions

github-actions Bot commented Nov 5, 2026

Copy link
Copy Markdown

This PR needs a release notes: label

If your change should be included in the release notes (i.e. would users of this library care about this change?), please use a label starting with release notes:. This helps us keep track and include your important work in the next release notes.

To add a label, you can comment to pytorchbot, for example
@pytorchbot label "release notes: none"

For more information, see
https://github.com/pytorch/pytorch/wiki/PyTorch-AutoLabel-Bot#why-categorize-for-release-notes-and-how-does-it-work.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

A stale attention-sink position shift can cause an out-of-bounds mask fill when starting a new sequence, and the Buck package omits the configuration required by both LFM3 models.

4 open issues
What changed in this PR

Adds LFM3-1.7B and LFM3-1.7B-Base support to ExecuTorch’s Qualcomm static LLM flow, including rolling convolution state shared between prefill and decode.

Changes:

  • Adds the LFM3 model, checkpoint converter, configuration, quantization recipe, and numerical tests.
  • Integrates convolution-state allocation, binding, and updates into the LLM runner.
  • Registers decoder variants and prompt formatting, updates build targets, and separates converted-checkpoint caches.
File Description
extension/​android/​CMakeLists.txt Includes convolution-state support in the Android build.
examples/​qualcomm/​oss_scripts/​llama/​wrappers/​llm_wrappers.py Integrates LFM3 construction and quantized state I/O.
examples/​qualcomm/​oss_scripts/​llama/​targets.bzl Adds LFM3 Python dependencies.
examples/​qualcomm/​oss_scripts/​llama/​static_llm_quant_recipe.py Defines the LFM3 quantization recipe.
examples/​qualcomm/​oss_scripts/​llama/​runner/​token_generator.h Adds decode-side convolution-state members.
examples/​qualcomm/​oss_scripts/​llama/​runner/​token_generator.cpp Binds and updates convolution state during decoding.
examples/​qualcomm/​oss_scripts/​llama/​runner/​runner.h Adds decoder versions, state ownership, and position reset.
examples/​qualcomm/​oss_scripts/​llama/​runner/​runner.cpp Initializes shared convolution state and checks supported modes.
examples/​qualcomm/​oss_scripts/​llama/​runner/​prompt_processor.h Adds prefill-side convolution-state members.
examples/​qualcomm/​oss_scripts/​llama/​runner/​prompt_processor.cpp Binds and updates convolution state during prefill.
examples/​qualcomm/​oss_scripts/​llama/​runner/​conv_state_manager.h Declares the rolling-state manager interface.
examples/​qualcomm/​oss_scripts/​llama/​runner/​conv_state_manager.cpp Implements state allocation, binding, and row updates.
examples/​qualcomm/​oss_scripts/​llama/​qnn_llama_runner.cpp Adds LFM3 chat and base prompt formatting.
examples/​qualcomm/​oss_scripts/​llama/​decoder_constants.py Registers LFM3 decoder identifiers.
examples/​qualcomm/​oss_scripts/​llama/​CMakeLists.txt Includes the new state manager in runner builds.
examples/​qualcomm/​oss_scripts/​llama/​__init__.py Registers LFM3 model configurations.
examples/​qualcomm/​oss_scripts/​lfm3/​test_lfm3_static.py Tests chunked inference and annotation matching.
examples/​qualcomm/​oss_scripts/​lfm3/​README.md Documents usage and unsupported modes.
examples/​qualcomm/​oss_scripts/​lfm3/​model_wrapper.py Implements the static LFM3 decoder and state I/O.
examples/​qualcomm/​oss_scripts/​lfm3/​convert_weights.py Converts Hugging Face weights to the static layout.
examples/​qualcomm/​oss_scripts/​lfm3/​config/​1_7b_config.json Supplies LFM3-1.7B architecture parameters.
examples/​qualcomm/​oss_scripts/​lfm3/​BUCK Defines LFM3 library and test targets.
examples/​models/​llama/​hf_download.py Adds converter-specific checkpoint cache suffixes.
backends/​qualcomm/​quantizer/​custom_annotation.py Shares quantization encoding across convolution-state I/O.

Review effort: Balanced

Comment on lines +97 to +98
void reset() override {
cur_pos_ = 0;
Comment on lines +128 to +132
if producer is not None:
# The new rows' producer owns the observer; it precedes the concat in
# graph order, so every user of the shared spec can reference it.
producer.output_qspec = act
shared = SharedQuantizationSpec(new_rows)
Comment thread examples/qualcomm/oss_scripts/lfm3/BUCK Outdated
"convert_weights.py",
"model_wrapper.py",
],
base_module = "executorch.examples.qualcomm.oss_scripts.lfm3",

## Text
```
python examples/qualcomm/oss_scripts/llama/llama.py -b build-android -s ${SERIAL_NUM} -m SM8750 \
@meta-codesync meta-codesync Bot changed the title LFM3 text decoder with conv-state support in LLM runners LFM3 text decoder with conv-state support in LLM runners (#24687) Nov 5, 2026
psiddh added a commit to psiddh/executorch that referenced this pull request Nov 5, 2026
Summary:

First diff of the stack that enables Liquid AI's LFM3 models on Qualcomm HTP with ExecuTorch. It runs LFM3-1.7B and LFM3-1.7B-Base through the static LLM flow (`llama.py --decoder_model lfm3-1_7b`); the next diff adds LFM3-VL-2B and LFM3-Omni-2B image + text. Generic-path (XNNPACK) support is a follow-up on top and is not needed by these diffs.

The static model (`examples/qualcomm/oss_scripts/lfm3/model_wrapper.py`) keeps the existing smart-mask KV I/O for the attention layers. Each short-conv layer takes its rolling state `[1, conv_L_cache - 1, dim]` as an extra input after the V caches and returns its new conv inputs `[1, ar_len, dim]`; state rows that precede position 0 are masked in the graph, so the runner never needs the quantized zero point. The recipe is 16a4w with 8-bit KV.

On the runner side, the new `ConvStateManager` binds the conv states and outputs as the last method I/O (validated against the method meta), shares them between the prefill and decode graphs, and keeps the last `state_len` valid rows after each step. It is created from the `get_n_conv_layers` metadata, so models without conv layers are unaffected. `PromptProcessor` and `TokenGenerator` bind and update it, and `kLfm3`/`kLfm3Base` add the decoder versions and ChatML template. Lookahead decoding, attention sink and sharding are rejected for conv-state models.

`annotate_conv_state` shares one 16-bit encoding across a conv-state input, the new rows and their concat, because the runner copies output bytes straight into the next call's state buffer. It matches only rank-3 row-wise concats, so the KV-cache concats keep `annotate_kv_8bit`'s encoding; the test covers that.

`download_and_convert_hf_checkpoint` takes a `cache_suffix` so the static converter's cached checkpoint doesn't collide with another converter's for the same repo.

Review order: `runner/conv_state_manager.{h,cpp}`, the processor/runner wiring, `lfm3/model_wrapper.py`, `custom_annotation.py`, then `llm_wrappers.py`.

This diff was authored with Claude Code.

Differential Revision: D128739913
@psiddh
psiddh force-pushed the export-D128739913 branch from 1c1dfb1 to ec5a0f6 Compare November 5, 2026 20:33
Copilot AI balanced review requested due to automatic review settings November 5, 2026 20:33

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Resetting the sequence position without clearing the attention-sink shift can produce a negative prefill position that becomes an oversized unsigned mask-fill count, causing an out-of-bounds write.

6 open issues

Review effort: Balanced

Comment on lines +211 to +212
gm = torch.export.export(model, inputs, strict=False).module()
annotate_conv_state(gm)
auto info = method_meta.input_tensor_meta(first_input + layer);
ET_CHECK_MSG(info.ok(), "Failed to get conv state input tensor meta");
ET_CHECK_MSG(
info->sizes()[1] == metadata_.state_len, "Conv state length mismatch");
@psiddh

psiddh commented Nov 5, 2026

Copy link
Copy Markdown
Contributor Author

@haowhsu-quic @shewu-quic @winskuo-quic

Would love your review on this. We're adding support for Liquid AI's LFM3 models and running them end to end on Qualcomm HTP.

There are a few fixes I still plan to make on this PR, but I'd like early thoughts on the overall direction first, especially the conv-state handling (ConvStateManager, conv state as extra graph I/O) and the annotate_conv_state quantization choice. Also since proper HF → ExecuTorch QNN flow for this model will take longer, since that design is still in flux, so this goes through the static LLM flow for now.

I've run it end to end on HTP (Galaxy S25) and the results look good.

@psiddh

psiddh commented Nov 5, 2026

Copy link
Copy Markdown
Contributor Author

@claude review the PR along with comments

@claude

claude Bot commented Nov 5, 2026 •

Copy link
Copy Markdown

Claude finished @psiddh's task in 5m 57s —— View job


PR Review: #24687

Summary: The conv-state-as-graph-I/O direction looks workable, but the new global Runner::reset() breaks attention-sink models (not just LFM3), so I'm requesting changes. A few smaller items, mostly ones Copilot also raised, should be fixed alongside it.

Detailed review

Summary

This PR adds LFM3-1.7B and LFM3-1.7B-Base to the QNN static LLM flow, with a rolling short-conv state carried as extra graph I/O and handled by a new ConvStateManager in the runner.

Three independent reviewers went through the diff, and I re-read the cited code for every finding below. I also checked each of Copilot's comments:

  • Confirmed: attention-sink reset, the Buck config resource, the README short options, the rank check in bind_io, and the gap in the annotation test.
  • Dropped: one concern that conv-state encodings aren't synced between the prefill and decode graphs. activation_override already walks every placeholder and activation in topological order (llm_wrappers.py:1053-1056), so they are synced.

Backward Compatibility

  • examples/qualcomm/oss_scripts/llama/runner/runner.h:96-99: reset() now sets cur_pos_ = 0 for every QNN model, but leaves AttentionSinkRopeRunner::position_shift_ as it is.

    • position_shift_ only grows (attention_sink_rope_runner.cpp:62), and nothing resets it.
    • Android resetContext (extension/android/jni/jni_layer_llama.cpp:578) calls runner_->reset(). Until now that call did nothing.
    • After at least one eviction, the next generate() computes shifted_pos = 0 - position_shift_ (prompt_processor.cpp:291, token_generator.cpp:258). That negative value reaches init_attention_mask, where it becomes a huge size_t fill count, which is an out-of-bounds write.
    • This regresses non-LFM3 attention-sink models. The LFM3 path doesn't need it, because the graph already masks state rows before position 0.
    • Fix: either move this into its own diff, or reset the attention-sink shift as well. A comment on why the conv state needs no reset (the in-graph mask) would also help.

    Fix this →

Infrastructure

  • examples/qualcomm/oss_scripts/lfm3/BUCK:10-24: the lfm3 library doesn't package config/1_7b_config.json.
    • _Lfm3Decoder.params_path (llama/__init__.py:543) defaults to that file, so the Buck-built llama.py fails with FileNotFoundError unless --params is passed.
    • Add it as resources, as examples/models/qwen3/targets.bzl:16-19 does.
  • examples/qualcomm/oss_scripts/llama/runner/runner.cpp:306-311: lookahead and attention sink are rejected with ET_CHECK_MSG inside Runner::load(), which returns Error.
    • This aborts the process, including the Android app through JNI, instead of returning an error.
    • Use ET_CHECK_OR_RETURN_ERROR(..., NotSupported, ...), matching the from_module check directly above it.
  • No Python-side rejection of these modes.
    • llama.py has no LFM3 guard. --model_mode lookahead or --use_attention_sink with --decoder_model lfm3-1_7b runs the whole export and compile, then fails on device.
    • Reject them in Python, next to the gemma4 check at llama.py:766.
    • The assert config.num_sharding == 1 at llm_wrappers.py:218 can never fire, because _Lfm3Decoder hard-codes num_sharding = 1.

Testing

  • examples/qualcomm/oss_scripts/lfm3/test_lfm3_static.py:197-212: test_conv_state_annotation_skips_kv_cache runs annotate_conv_state on an unannotated export, so it only exercises the producer is None branch.

    • Production runs the custom annotations after the recipe. That takes the producer.output_qspec = act / SharedQuantizationSpec(new_rows) branch, which this test never reaches.
    • Counting rank-3 concats also can't detect mismatched state/output encodings, which are exactly what would corrupt the runner's raw-byte copies.
    • Add a prepare_pt2e/calibrate/convert_pt2e test with Lfm3QuantRecipe that asserts:
      • each conv-state input, its new-rows output, and the cat share one 16-bit scale/zero-point;
      • K/V stay 8-bit.
  • No parity test against the HF reference. The numerics test only compares the static model with itself (chunked vs one shot). It can't catch errors in:

    • the partial-RoPE pairing layout;
    • where the sigmoid gate is applied;
    • the sandwich-norm order;
    • the conv tap direction after the [dim,1,K] -> [K,dim] transpose in convert_weights.py.

    A tiny-config parity test against transformers' LFM3 modeling code, skipped when it's unavailable, would cover these.

Code Quality

  • examples/qualcomm/oss_scripts/llama/runner/conv_state_manager.cpp:104-108: info->sizes()[1] is read before bind() validates that the rank is 3.
    • from_module only checks the first conv-state input of the decode method, so a malformed other layer or the prefill method reads out of bounds.
    • Check sizes().size() == 3 first.
  • examples/qualcomm/oss_scripts/lfm3/README.md:16: llama.py has no -b/-s/-m options. setup_common_args_and_variables (backends/qualcomm/export_utils.py) only registers --build_folder, --device and --soc_model, so the documented command fails to parse.
  • examples/qualcomm/oss_scripts/llama/wrappers/llm_wrappers.py:321: getattr(self.config, "converted_checkpoint_suffix", "") is the dynamic-getattr pattern CLAUDE.md asks to avoid. Declare converted_checkpoint_suffix: str = "" on LLMModelConfig and read it directly.
  • llm_wrappers.py:340-341: if self.model_args is None: break inside the per-key loop is a guard on the whole loop. Write it as if self.model_args is not None: around the loop.
  • Design (the direction you asked about): conv outputs ride in the V-cache output list (model_wrapper.py, output_v_cache + output_conv), and Python identifies conv I/O by shape (llm_wrappers.py:639-650).
    • That spreads special cases around: args_idx >= 2 * n_cache_layers: continue (llm_wrappers.py:1077), plus the LFM3 branch for get_n_self_layers.
    • The C++ side, by contrast, identifies conv I/O by position (the last n_conv inputs and outputs).
    • Using the same positional rule in get_io_type (args after 2 * n_attn), or a separate recurrent-state output group, would be sturdier. It would also stop a future (bsz, ar_len, dim) output, such as hidden states, from being silently tagged io_type.
  • examples/qualcomm/oss_scripts/lfm3/convert_weights.py:66: only model.safetensors is loaded. Sharded snapshots (model.safetensors.index.json) will fail, which is likely for the VL/Omni checkpoints in the next diff.
  • examples/qualcomm/oss_scripts/llama/runner/conv_state_manager.h:72-80: state(), output() and num_layers() have no callers in this diff.
  • examples/qualcomm/oss_scripts/llama/qnn_llama_runner.cpp:198 (low confidence): please confirm that <|im_start|>assistant\n<think></think> matches the HF chat template's non-thinking rendering byte for byte, newlines included. A mismatch shifts generation quality, and CI won't catch it.

Recommendation

Request Changes. The reset() change is a BC regression for existing attention-sink models. Beyond that, the Buck resource, the README command and the ET_CHECK_MSG abort in load() are quick fixes. The recipe-level encoding-equality test is the main thing missing to back up the annotate_conv_state design.

@winskuo-quic winskuo-quic left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@psiddh Thanks a lot for the PR to enable LFM3.
While I am still going through the runner's logic, I have first left some comments for the AoT side, mostly about the file structure since this model seems to follow a different convention.
Please have a look.

@@ -0,0 +1,225 @@
# Copyright (c) Meta Platforms, Inc. and affiliates.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of creating a testing file for this specific model, could we instead reuse https://github.com/pytorch/executorch/blob/main/backends/qualcomm/tests/test_qnn_delegate.py?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. No model-specific test file anymore. lfm3-1_7b is in TestExampleLLMScript.llm_specs, and the conv-state checks live in test_qnn_delegate.py.

@@ -0,0 +1,75 @@
# Copyright (c) Meta Platforms, Inc. and affiliates.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think convert_weights.py are usually placed under examples/models/{MODEL_NAME}.
If there's nothing that is backend specific in this file, maybe we should place it under the examples/models/{MODEL_NAME} folder

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, moved to examples/models/lfm3/.

@@ -0,0 +1,21 @@
# LFM3 on Qualcomm HTP

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think our convention is to provide each model's instruction under executorch/examples/qualcomm/oss_scripts/llama/README.md. Could we reorg this file and merge it into executorch/examples/qualcomm/oss_scripts/llama/README.md?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree! Done, merged into oss_scripts/llama/README.md as an "LFM3 1.7B" entry.

@@ -0,0 +1,56 @@
{

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto. Same issue as convert_weights.py

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, moved to examples/models/lfm3/config/.

"tie_word_embeddings": true,
"use_sandwich_norm": true,
"vocab_size": 128000
} No newline at end of file

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need new line. Thanks

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed



@dataclass(init=False, frozen=True)
class _Lfm3Decoder(LLMModelConfig):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think for consistency, we don't need a base class. We can just have a list of configs for "lfm3-1_7b" and another for "lfm3-1_7b_base"

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, replaced with flat configs.

r3 = False
quant_recipe = Lfm3QuantRecipe
# Differs from the generic-path converter for the same repo; keep caches apart.
converted_checkpoint_suffix = "_qnn_static"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am assuming that this has something to do with placing convert_weights.py under Qualcomm folder. I am curious why LFM3 is different from other models. I believe examples/models/llama/llama_transformer.py should be sharing the same weight naming as static_llama, meaning using the same converted weight cache is safe.
I saw your summary section mentioning about enabling XNNPACK as follow-up. Is this related to the follow-up task?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it was related to the XNNPACK follow-up. It's dropped now, along with the hf_download.py change. LFM3 now uses static_llama with the same weight naming as llama_transformer (og for the attention gate; B_proj/C_proj/x_proj/conv/out_proj for the short conv), so there's a single converter in examples/models/lfm3/ and one converted checkpoint. The XNNPACK follow-up reuses it.

return (h, *out[1:])


class Lfm3Model(nn.Module):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think what is in this file highly overlaps with https://github.com/pytorch/executorch/blob/main/examples/qualcomm/oss_scripts/llama/model/static_llama.py. Could we possibly identify the gaps and just use registry. For example, feed forward uses: https://github.com/pytorch/executorch/blob/main/examples/qualcomm/oss_scripts/llama/model/feed_forward.py.

For example, the following is different and some of these could be used with a registry,

  1. Attention has a sigmoid at the end (3-4 lines).
  2. Mixed layers ShortConv could be registered.
  3. Rope is different

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, model_wrapper.py is gone and LFM3 is built from static_llama pieces:

  • ShortConv: a ShortConvDecoderLayer registered in a new DECODER_LAYER_REGISTRY under "conv". LlamaModel builds each layer from layer_types, defaulting to LlamaDecoderLayer.
  • Feed forward: reuses FeedForward_REGISTRY / feed_forward.py, same as the other models.
  • Attention sigmoid gate: a headwise_attn_output_gate option on the existing LlamaAttention (sigmoid(og(x)) per head), not a separate attention class.
  • RoPE: uses the existing ROTARY_EMB_REGISTRY["partial"]. The converter permutes q/k for LFM3's partial-RoPE layout, and sliding vs full layers get their own rope_parameters.

Summary:

Run LFM3 through shared `static_llama` with rolling convolution state and a converter/config shared with the generic path. Fail closed on missing state annotations and test equal input/output encodings with production `Lfm3QuantRecipe` before runner byte copies. Keep the checks in existing `test_qnn_delegate.py`; fix OSS formatting and the loop-variable capture.

`Runner::reset()` now resets position for all non-attention-sink QNN text models, so Android `LlmModule.resetContext()` starts a new conversation. With attention sink it remains a no-op. Unsupported conv-state runner modes return `NotSupported`.

Known limitation: a dedicated C++ `ConvStateManager` unit test remains a follow-up.

Originally authored with Claude Code; updated with Metamate (agentcloud).

Differential Revision: D128739913
Copilot AI balanced review requested due to automatic review settings November 13, 2026 07:45

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota. Try requesting a review at a lower effort level.

@psiddh

psiddh commented Nov 13, 2026

Copy link
Copy Markdown
Contributor Author

Thanks @winskuo-quic . All AoT comments are addressed, and the structure changed. LFM3 now goes through the shared static_llama (a short-conv hybrid decoder layer next to the existing ones), so the standalone oss_scripts/lfm3/ folder is gone.

psiddh added a commit to psiddh/executorch that referenced this pull request Nov 13, 2026
Summary:
Pull Request resolved: pytorch#24687

Run LFM3 through shared `static_llama` with rolling convolution state and a converter/config shared with the generic path. Reject lookahead and attention sink before Python export. Select conv-state I/O by its user-argument/output position, not shape, and remove unused manager accessors.

Support single-file and indexed sharded Safetensors checkpoints. An independent tiny HF logits test exercises the shared converter, partial RoPE, gate/norm order and conv tap direction, including the export rewrites. It skips when LFM3 modeling is unavailable and runs against an explicitly selected local HF reference otherwise.

`Runner::reset()` resets position for all non-attention-sink QNN text models, so Android `LlmModule.resetContext()` starts a new conversation; attention-sink reset remains a no-op. Unsupported conv-state runner modes return `NotSupported`.

Known limitation: a dedicated C++ `ConvStateManager` unit test remains a follow-up.

Originally authored with Claude Code; updated with Metamate (agentcloud).

Differential Revision: D128739913

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. meta-exported

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants