Skip to content

feat: add LFM 3 (1.7B, VL 2B, Audio 2B) - #1582

Open
msluszniak wants to merge 3 commits into
mainfrom
@ms/lfm3
Open

msluszniak wants to merge 3 commits into
mainfrom
@ms/lfm3

Conversation

@msluszniak

@msluszniak msluszniak commented Oct 28, 2026 •

Copy link
Copy Markdown
Member

Description

  • Adds LFM 3 1.7B, LFM 3 VL 2B and LFM 3 Audio 2B (XNNPACK 8da4w, MLX int4/int8), 8K context.
  • The multimodal runner accepts an audio_encoder model (LLM_AUDIO_SPEC) in place of vision_encoder.
  • nlp app: LFM 3 entries, LFM 3 tool-call parser, hides the draft LFM 3 writes before </think> with thinking off.

Introduces a breaking change?

  • Yes
  • No

Type of change

  • Bug fix (change which fixes an issue)
  • New feature (change which adds functionality)
  • Documentation update (improves or adds clarity to existing documentation)
  • Other (chores, tests, code style improvements etc.)

Tested on

  • iOS
  • Android

Testing instructions

  • nlp app, LLM screen: LFM 3 1.7B (chat, tool calling), LFM 3 VL 2B (image), LFM 3 Audio 2B (attach a WAV URL).

Screenshots

Related issues

Checklist

  • I have performed a self-review of my code
  • I have commented my code, particularly in hard-to-understand areas
  • I have updated the documentation accordingly
  • My changes generate no new warnings

Additional notes

  • Vulkan variants follow separately; they need an ExecuTorch Vulkan SDPA fix in the libs.

@msluszniak msluszniak self-assigned this Oct 28, 2026
@msluszniak msluszniak added the feature PRs that implement a new feature label Oct 28, 2026
@msluszniak
msluszniak marked this pull request as draft October 28, 2026 12:10
@msluszniak
msluszniak marked this pull request as ready for review October 28, 2026 13:40
@msluszniak
msluszniak requested a review from barhanc October 28, 2026 13:41
Comment thread packages/react-native-executorch/src/extensions/llm/llmRunner.ts Outdated
Comment on lines +349 to +353
const stats = prefillEmbeddings(embedding, numAudioTokens, prefillLen);
const numTokens = totStats.numTokens + stats.numTokens;
const durationMs = totStats.durationMs + stats.durationMs;
const tokensPerSecond = durationMs > 0 ? (numTokens / durationMs) * 1000 : 0;
totStats = { numTokens, durationMs, tokensPerSecond };

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

You can use the combineStats helper here as in gemma example.

Comment on lines +335 to +340
const chunkSamples = Math.min(numSamples - offset, chunkStride);
// Right-pad to window + k * hop samples, as the feature extractor does.
const padded =
chunkSamples <= window ? window : window + Math.ceil((chunkSamples - window) / hop) * hop;
const numFrames = 1 + (padded - window) / hop;
const numAudioTokens = Math.ceil(numFrames / framesPerToken);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
const chunkSamples = Math.min(numSamples - offset, chunkStride);
// Right-pad to window + k * hop samples, as the feature extractor does.
const padded =
chunkSamples <= window ? window : window + Math.ceil((chunkSamples - window) / hop) * hop;
const numFrames = 1 + (padded - window) / hop;
const numAudioTokens = Math.ceil(numFrames / framesPerToken);
const chunkSamples = Math.min(numSamples - offset, chunkStride);
// Right-pad to window + k * hop samples, as the feature extractor does.
const k = Math.ceil((chunkSamples - window) / hop);
const padded = chunkSamples <= window ? window : window + k * hop;
const numFrames = 1 + (padded - window) / hop;
const numAudioTokens = Math.ceil(numFrames / framesPerToken);

Comment on lines +88 to 95
const modality: Modality = variant === 'vision' ? 'image' : 'audio';

if (!modalities?.includes(modality)) {
throw RnExecuTorchError(
'INVALID_ARGUMENT',
`Multimodal vision-language model requires 'image' in modalities.`
`Multimodal model with an ${modality} encoder requires '${modality}' in modalities.`
);
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Maybe something like

  const specModalities = {
    vision: ['image'],
    audio: ['audio'],
    omni: ['image', 'audio'],
  }[variant];

  if (
    modalities?.length !== specModalities.length ||
    modalities.some((m) => !specModalities.includes(m))
  ) {
    throw RnExecuTorchError(
      'INVALID_ARGUMENT',
      `Multimodal model requires [${specModalities}] modalities.`
    );
  }

// ...

  let imgShape: readonly [1, 3, number, number];
  let numVisualTokens: number;
  if (modalities.includes('image')) {
    imgShape = [1, 3, ...dims.constant('imgH', 'imgW')];
    numVisualTokens = dim('visualTokens', 'constant');
  }

  let audioSamples: Range;
  let framesPerToken: number;
  if (modalities.includes('audio')) {
    [audioSamples] = dims.range('audioSamples');
    [framesPerToken] = model.execute('get_audio_frames_per_token', [], []) as [number];
  }

with checks changed to

    if (!modalities.includes('image')) {
      throw RnExecuTorchError('INVALID_ARGUMENT', 'prefill: This model has no vision encoder.');
    }

would allow better extensibility also for omni model.

@barhanc

barhanc commented Oct 28, 2026

Copy link
Copy Markdown
Member

I tested the new models in example app and they work great. I'm super impressed by the audio model---the prefill and decode speed and accuracy of the transcription are incredible (especially compared to Gemma) 🤯. I don't have iOS device to test the MLX versions so that will have to wait for tomorrow.

@msluszniak

Copy link
Copy Markdown
Member Author

@kfaracik could you check the MLX and XNNPACK variants of these models on iOS since you have told me you have been adding these models.

@msluszniak msluszniak linked an issue Oct 28, 2026 that may be closed by this pull request

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

feature PRs that implement a new feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add LFM 3 models

2 participants