跳到正文
DEV Community· Rahul Kumar·· 3 小時前AI 評分59

Keras 模型為何無法轉換至 TFLite:11 種已知情況與 5 個陷阱

Why a Keras model fails to convert to TFLite: 11 known cases, 5 traps

AI 導讀

KerasHub 的測試將 11 個模型列為預期無法匯出至 LiteRT(TensorFlow Lite 的新名稱),文章並歸納相關問題為 5 類陷阱。

正文

KerasHub, the Keras library of pretrained models, expects 11 of its own models to fail the export to LiteRT (the new
name of TensorFlow Lite), and its tests say why in one line each. Here are all 11, the five traps they fall into, and
what to write instead.

I contribute to Keras and KerasHub. The change that switched these export tests back on for the PyTorch backend,
keras-hub#2698, is mine.

The 11, in KerasHub's own words

An expected failure is a test marked to fail until an upstream fix lands; when the fix lands, the test turns loud
instead of silently passing. Each name links to its line in the tests:

Model Trap The test's own reason
D-Fine 2. One shape "D-FINE's multi-scale features hit a torch.export shape guard."
Flux 2. One shape "torch.export guard from Flux's dynamic num_heads reshape."
F-Net 3. No lowering "litert-torch has no lowering for aten.complex (from ops.fft2)."
GPT-OSS 3. No lowering "litert-torch NHWC rewriter has no lowering for aten.amax."
Mixtral 3. No lowering "litert-torch cannot lower aten._assert_async from MoE routing."
Qwen3-MoE 3. No lowering "litert-torch cannot lower aten._assert_async from MoE routing."
Qwen-MoE 3. No lowering "litert-torch cannot lower aten._assert_async from MoE routing."
SAM3 3. No lowering "torchvision::nms is not registered in the torch.export op set."
SegFormer 3. No lowering "Unsupported ops during SegFormer's torch export decomposition."
StableDiffusion3 3. No lowering "AdjustablePositionEmbedding cannot be lowered by torch.export."
VAE 3. No lowering "VAE's pow ops fail TFLite legalization (tfl.pow)."

At the commit that merged it, KerasHub has 75 export tests in 67 model folders: 63 carry no mark, 11 are expected
failures and 1 is skipped. I counted the marks in the code; I did not run the tests. The pull request names 7 models
that now pass on PyTorch: VGG, Moonshine, SAM, GPTNeoX and BASNet, plus ViTDet and Whisper within a tolerance rather
than an exact match.

The export stages from the keras.io guide's own log, with the five traps: in the model code (Python if, x.shape), at Torch export (one fixed shape), at lowering and the converter passes (ops with no lowering, tfl.pow), in the model.tflite file (inputs named args_0), and under every stage (versions).

1. "symbolic tf.Tensor used as a Python bool"

Export turns your Python into a graph. A Python if on a tensor, or a size read with x.shape, can break that step
or freeze one case into the graph. KerasHub still skips its DeepLabV3 export test with exactly this message
(test).

Fix: keep sizes and branches inside the graph. One merged change, before and after
(keras-hub#2466):

# Before: x.shape is read once, while the graph is built
t = ops.arange(x.shape[position], dtype=x.dtype)

# After: "for dynamic shape compatibility with TFLite"
t = ops.arange(ops.shape(x)[position], dtype=x.dtype)

For a Python if, keras-hub#2467 removed the branch instead: it
builds the tensor so that one token gives an empty tensor, "avoiding the need for a Python conditional".

2. A torch.export shape guard

On the PyTorch backend the input shape is fixed when you export. In my words from
keras#22996, the issue I filed:

The only viable workaround is to export with a fixed static shape matching the runtime maximum.

D-Fine and Flux are this trap in the table.

Fix: give the export one shape, the largest you will feed it:

# Fails (keras#22996, shortened): the sequence length is left
# open, traced at 1, and the file breaks on longer input.
lm = keras_hub.models.Gemma3CausalLM.from_preset(
    "gemma3_270m_it")
lm.export("lm.tflite", format="litert")

# Works: one fixed shape at export (an image model here).
m.export("m.tflite", format="litert",
         input_signature=[torch.randn(1, 224, 224, 3)])

The working half ran on 22 October 2026, on a computer's CPU, for my demo app's MobileNetV3.

To feed a different batch size later, resize the input at run time with resize_tensor_input(), as the
keras.io guide shows.

3. "no lowering for aten.complex"

The export stops at the name of one operation. Lowering is the step that turns each PyTorch operation into a LiteRT
one, and litert-torch, the converter, has no rule for some of them. Seven of the 11 in the table name such an
operation (aten.complex, aten.amax, aten._assert_async, torchvision::nms, tfl.pow); SegFormer and StableDiffusion3 give
a vaguer reason.

Check, then a fallback with a cost: find your model in the table before you start. The keras.io guide's fallback
is the TensorFlow backend, but its flex ops, TensorFlow operations carried into the file, "are not supported by the
new LiteRT Android runtime". The app then needs the legacy runtime, org.tensorflow:tensorflow-lite, plus
tensorflow-lite-select-tf-ops.

4. Inputs named args_0

Your app asks for an input by name, and the file calls it args_0. litert-torch flattened dict inputs to generic names
(litert-torch#1022, closed 4 June 2026).

Fix: use litert-torch newer than 0.9.1, which keeps the original keys
(keras#23053), and print the names before you write app code. For
my MobileNetV3 file, with litert-torch 0.10.0, it printed this:

print("Signatures:", interpreter.get_signature_list())
# {'serving_default': {'inputs': ['args_0'],
#                      'outputs': ['output_0']}}

A single image input is still called args_0; the fix keeps the keys of dict inputs.

5. tf.lite is deprecated, and the toolchain moves

KerasHub switched all its export tests off in February 2026, when TensorFlow 2.20 deprecated tf.lite
(keras-hub#2573), and back on in July for PyTorch only, with
Keras 3.15 or newer. Keras 3 with TensorFlow 2.20 and Python 3.13 crashed during export until
keras#22816.

It moved again on 22 October 2026. Installed from the main branches, the way the keras.io guide does it, the export
above failed in the converter with 'tfl.batch_matmul' op found invalid output rank, expected 3 but got 4. The
released versions of the day before exported it: keras 3.15.1, keras-hub 0.32.0, litert-torch 0.10.0 and
ai-edge-litert 2.3.0.

Check, not a fix: record the versions that worked, next to the exported file:

pip freeze | grep -iE "keras|litert" > export-versions.txt

The one I cannot close

KerasHub's DeepLabV3 export test is still skipped, while my demo app exports a DeepLabV3 preset on the same PyTorch
backend. One of the two is out of date; my 22 October run covered MobileNetV3 only. If you have run that export recently, which one is it? And which trap did you
hit that is not on this list?

New here? Start with part 1: one model on a phone →


This article was written with the help of AI, from my own repository and the public records it links.

來源:DEV Community · dev.to