---
license: cc-by-nc-nd-4.0
language:
- en
- ar
pipeline_tag: image-to-video
tags:
- audio-to-video
- talking-head
- portrait-animation
- lip-sync
- flow-matching
- motion-generation
- video-generation
- wav2vec2
- pytorch
- real-time
- onnx
- tensorrt
---
# [ICCV 2025] FLOAT: Generative Motion Latent Flow Matching for Audio-driven Talking Portrait
Official PyTorch implementation of **FLOAT** — *Flow Matching for Audio-driven Talking Portrait Video Generation* — plus the
**pre-converted ONNX / TensorRT graphs** used by the [FLOAT Fast](https://github.com/mohamed-em2m/float-fast) serving stack.

**FLOAT: Generative Motion Latent Flow Matching for Audio-driven Talking Portrait**
[Taekyung Ki](https://taekyungki.github.io), [Dongchan Min](https://kevinmin95.github.io), [Gyeongsu Chae](https://www.aistudios.com/ko)
Project page: [deepbrainai-research.github.io/float](https://deepbrainai-research.github.io/float/) · Serving stack: [github.com/mohamed-em2m/float-fast](https://github.com/mohamed-em2m/float-fast)
**Abstract**: *With the rapid advancement of diffusion-based generative models, portrait image animation has achieved remarkable results. However, it still faces challenges in temporally consistent video generation and fast sampling due to its iterative sampling nature. This paper presents FLOAT, an audio-driven talking portrait video generation method based on flow matching generative model. Instead of a pixel-based latent space, we take advantage of a learned orthogonal motion latent space, enabling efficient generation and editing of temporally consistent motion. To achieve this, we introduce a transformer-based vector field predictor with an effective frame-wise conditioning mechanism. Additionally, our method supports speech-driven emotion enhancement, enabling a natural incorporation of expressive motions. Extensive experiments demonstrate that our method outperforms state-of-the-art audio-driven talking portrait methods in terms of visual quality, motion fidelity, and efficiency.*
**TL;DR**: FLOAT is a flow-matching based audio-driven talking portrait video generation method, which can enhance the
speech-driven emotional motion.
---
## Repository layout
```
mohamedemam/float/
├── float.pth # the main model checkpoint (827 MB)
├── wav2vec2-base-960h/ # audio encoder (facebook/wav2vec2-base-960h)
├── wav2vec-english-speech-emotion-recognition/ # emotion encoder (r-f/wav2vec-…-recognition)
├── assets/ # figures used by this card
└── onnx/ # pre-converted ONNX graphs (see below)
├── fmt_step_v1.onnx 628 MB # FMT vector-field step (the ODE inner loop)
├── emotion_v1.onnx 1.27 GB # speech-emotion classifier
├── wav2vec_v1.onnx 380 MB # audio encoder + projection head
├── decoder_v1.onnx 94 MB # frame decoder (StyleGAN-style synthesis)
├── refenc_v1.onnx 91 MB # reference-image encoder
├── direction_v1.onnx 42 KB # motion direction basis
├── decoder_v1.onnx.no_trt # sidecar: the runtime must not use TensorRT here
├── backends.generated.yaml # measured per-component backend plan
└── .build_manifest.json # build provenance for the artifacts
```
## ONNX / TensorRT accelerated inference
The `onnx/` folder holds the **same six components**, exported to ONNX and ready to run on
TensorRT / CUDA / CPU. They are produced by
[`float-fast`](https://github.com/mohamed-em2m/float-fast)'s `scripts/convert_to_onnx.sh` and are
**drop-in replacements for the torch modules** — the ODE loop, the CFG combine and the chunk
autoregression stay in Python, only the hot inner steps move into the graph.
Every artifact is **gated before it is published**: the converter compares the exported graph against
the *deployed* torch model and refuses to pass a graph that does not reproduce it. Two rules make
that gate meaningful, and both are easy to get wrong:
- the reference is the **deployed** model, never the module that was traced;
- both sides run **the same computation** (fp32 on both sides — TF32 alone moves a 22-conv stack
by tens of uint8 levels, which would drown the graph's own error).
Measured for the graphs in this folder:
| artifact | provider | fidelity vs the torch model |
|---|---|---|
| `fmt_step_v1.onnx` | TensorRT FP16 | cosine 0.999996 (per ODE step) |
| `decoder_v1.onnx` | CUDA (fp32) | max 1 / mean 0.002 uint8 level on a 512×512 frame |
| `emotion_v1.onnx`, `wav2vec_v1.onnx`, `refenc_v1.onnx`, `direction_v1.onnx` | TensorRT FP16 | cosine ≥ 0.99999 |
`backends.generated.yaml` is the **measured** plan for the machine the conversion ran on (an
RTX A6000): `emotion`, `audio` and `fmt` on `onnx/trt`, `refenc` compiled, `direction` and
`decoder` eager. Re-run the selector on your own box to re-measure — the choices are per-GPU:
```bash
git clone https://github.com/mohamed-em2m/float-fast && cd float-fast
uv run --frozen --no-sync python -m fast_float.onnx.select_backends \
--onnx-dir ./onnx --out ./onnx/backends.generated.yaml --ckpt ./checkpoints/float.pth
```
Two things are deliberately **not** in this folder:
- **the TensorRT engine cache** — engines are tied to the GPU and the TensorRT/CUDA versions, so
the target box builds its own on first use (and caches them under `onnx/trt_cache/`);
- **a runtime config you can trust blindly** — see the selector above.
### Using the graphs with FLOAT Fast
```bash
# 1. fetch the checkpoints and the ONNX graphs
huggingface-cli download mohamedemam/float --include "onnx/*" --local-dir ./hf
huggingface-cli download mohamedemam/float --include "float.pth" --local-dir ./checkpoints
huggingface-cli download mohamedemam/float --include "wav2vec2-base-960h/*" --local-dir ./checkpoints
huggingface-cli download mohamedemam/float --include "wav2vec-english-speech-emotion-recognition/*" --local-dir ./checkpoints
cp -r hf/onnx ./onnx
# 2. build the environment (uv venv, deps, ONNX stack, TensorRT 10.9)
./scripts/setup.sh
# 3. re-measure the backends for this box, then serve
uv run --frozen --no-sync python -m fast_float.onnx.select_backends \
--onnx-dir ./onnx --out ./onnx/backends.generated.yaml --ckpt ./checkpoints/float.pth
./scripts/run_all.sh # backend :8000 + Studio frontend :3000
```
FLOAT Fast then serves the model over HTTP:
```bash
curl -X POST http://localhost:8000/generate \
-H 'Content-Type: application/json' \
-d '{"audio_base64": "'"$(base64 -w0 audio.wav)"'",
"audio_format": "wav",
"image_base64": "'"$(base64 -w0 portrait.jpg)"'"}'
```
It also streams the frames live over a WebSocket (`/ws/stream/{request_id}`) and over WebRTC
(`/offer`), so a browser can play the portrait while the MP4 is still being written.
---
## Generation Results
| Result 1 | Result 2 |
|-------------|-------------|
| | |
| Result 3 | Result 4 |
|---|---|
| | |
Our method runs faster than current diffusion-based methods with fewer sampling steps and lower memory cost. For more details, please refer to the paper.