SAVRN
Search Contact SAVRN

Open-weight model · Feature extraction

Qwen3-Voice-Embedding-12Hz-1.7B

by Markus marksverdhei/Qwen3-Voice-Embedding-12Hz-1.7B

Standalone ECAPA-TDNN voice encoder extracted from Qwen/Qwen3-TTS-12Hz-1.7B-Base. Produces 2048-dimensional x-vector speaker embeddings from audio.

Parameters12M
Context
Weights24.0 MB
Licenseapache-2.0
AccessOpen weights
Monthly Downloads10k

Runs On

What it takes to serve Qwen3-Voice-Embedding-12Hz-1.7B (12M parameters): the memory its weights need at each precision, and the cheapest way to rent enough data-center GPUs to hold them.

PrecisionWeightsMemory neededCheapest setupPer hourAlso fits
16-bit 0.0 GB 0.0 GB 1x MI300X (192 GB)
Vultr
$1.85 1x H100 $1.99 · 1x MI325X $2.00
8-bit 0.0 GB 0.0 GB 1x MI300X (192 GB)
Vultr
$1.85 1x H100 $1.99 · 1x MI325X $2.00
4-bit 0.0 GB 0.0 GB 1x MI300X (192 GB)
Vultr
$1.85 1x H100 $1.99 · 1x MI325X $2.00

Memory is the weights at that precision plus 20% for the runtime and a short context; a long context needs more. Prices are the lowest on-demand hourly rates in the SAVRN Index, read Sep 18, 2026.

Model Card

By Markus, published under apache-2.0, revision 7577f61c4273.

Standalone ECAPA-TDNN voice encoder extracted from Qwen/Qwen3-TTS-12Hz-1.7B-Base. Produces 2048-dimensional x-vector speaker embeddings from audio. The encoder follows the ECAPA-TDNN architecture (Emphasized Channel Attention, Propagation and Aggregation in TDNN Based Speaker Verification) and uses Res2Net blocks, squeeze-excitation attention, and attentive statistical pooling. Speaker embeddings can be stored and shared as SafeTensors files. These embeddings are designed to drive voice cloning in the Qwen3-TTS family. There are two main inference paths: the qwentts Python package and the vLLM-Omni serving API. The qwentts package wraps the TTS model and exposes generatevoiceclone. To…

Read Markus's full model card

ECAPA-TDNN Voice Encoder (from Qwen3-TTS 1.7B)

Standalone ECAPA-TDNN voice encoder extracted from Qwen/Qwen3-TTS-12Hz-1.7B-Base. Produces 2048-dimensional x-vector speaker embeddings from audio.

The encoder follows the ECAPA-TDNN architecture (Emphasized Channel Attention, Propagation and Aggregation in TDNN Based Speaker Verification) and uses Res2Net blocks, squeeze-excitation attention, and attentive statistical pooling.

[!WARNING] Only extracted from the *-Base model variant. The *-CustomVoice and *-VoiceDesign variants do NOT support speaker embeddings and will not work. Do not attempt to use them for speaker encoding.

Usage

Recommended: AutoProcessor + AutoModel

import librosa
import torch
from transformers import AutoModel, AutoProcessor

processor = AutoProcessor.from_pretrained(
    "marksverdhei/Qwen3-Voice-Embedding-12Hz-1.7B", trust_remote_code=True,
)
model = AutoModel.from_pretrained(
    "marksverdhei/Qwen3-Voice-Embedding-12Hz-1.7B", trust_remote_code=True,
)
model.eval()

audio, sr = librosa.load("audio.wav", sr=None, mono=True)
inputs = processor(audio, sampling_rate=sr)

with torch.no_grad():
    embedding = model(**inputs).last_hidden_state  # (1, 2048)

Pipeline API

from transformers import pipeline

pipe = pipeline(
    "feature-extraction",
    model="marksverdhei/Qwen3-Voice-Embedding-12Hz-1.7B",
    trust_remote_code=True,
)

# From file path
embedding = pipe("audio.wav")  # list, shape (1, 2048)

# From numpy array
import librosa
audio, sr = librosa.load("audio.wav", sr=None, mono=True)
embedding = pipe(audio, sampling_rate=sr)

Saving & Loading Embeddings

Speaker embeddings can be stored and shared as SafeTensors files.

Save to SafeTensors

import torch
from safetensors.torch import save_file

# embedding: torch.Tensor of shape (2048,) or (1, 2048)
embedding = embedding.squeeze()  # ensure 1D
save_file({"speaker_embedding": embedding}, "my_voice.safetensors")

Load from SafeTensors

from safetensors.torch import load_file

tensors = load_file("my_voice.safetensors")
embedding = tensors["speaker_embedding"]  # (2048,)

[!TIP] Use the key "speaker_embedding" by convention — this matches the field name used by Qwen3-TTS and vLLM-Omni.

Using Embeddings with Qwen3-TTS

These embeddings are designed to drive voice cloning in the Qwen3-TTS family. There are two main inference paths: the qwen_tts Python package and the vLLM-Omni serving API.

qwen_tts (offline)

The qwen_tts package wraps the TTS model and exposes generate_voice_clone. To inject a pre-computed embedding without needing the original reference audio on disk, construct a VoiceClonePromptItem directly:

import torch
import soundfile as sf
from dataclasses import dataclass
from typing import Optional
from safetensors.torch import load_file

# The prompt item dataclass (mirrors qwen_tts.inference.qwen3_tts_model)
@dataclass
class VoiceClonePromptItem:
    ref_code: Optional[torch.Tensor]       # None when using x-vector only
    ref_spk_embedding: torch.Tensor        # (2048,)
    x_vector_only_mode: bool
    icl_mode: bool
    ref_text: Optional[str] = None

# 1. Load a saved embedding
embedding = load_file("my_voice.safetensors")["speaker_embedding"]  # (2048,)

# 2. Build the prompt item — no reference audio needed
prompt = VoiceClonePromptItem(
    ref_code=None,
    ref_spk_embedding=embedding,
    x_vector_only_mode=True,
    icl_mode=False,
)

# 3. Load the TTS model
from qwen_tts import Qwen3TTSModel

tts = Qwen3TTSModel.from_pretrained(
    "Qwen/Qwen3-TTS-12Hz-1.7B-Base", device_map="cuda:0",
)

# 4. Generate speech — reusable across any text
wavs, sr = tts.generate_voice_clone(
    text="Hello from a stored embedding!",
    language="English",
    voice_clone_prompt=prompt,
)
sf.write("output.wav", wavs[0], sr)

[!NOTE] x_vector_only_mode=True skips the text encoder and uses only the speaker embedding. Quality may be slightly reduced compared to full voice cloning with a reference transcript, but it lets you synthesize from stored embeddings without any audio files.

vLLM-Omni (online serving)

When serving Qwen3-TTS with vLLM-Omni, you can pass a pre-computed embedding directly via the speaker_embedding field in the API request.

[!NOTE] The speaker_embedding field requires the ht branch of our vLLM-Omni fork. There is an upstream PR pending — use the fork until it is merged.

import httpx
from safetensors.torch import load_file

embedding = load_file("my_voice.safetensors")["speaker_embedding"]

response = httpx.post(
    "http://localhost:8000/v1/audio/speech",
    json={
        "model": "qwen3-tts-1.7b-base",
        "input": "Hello from a stored voice embedding.",
        "task_type": "Base",
        "speaker_embedding": embedding.tolist(),  # flat list of 2048 floats
        "response_format": "wav",
        "language": "Auto",
    },
    headers={"Authorization": "Bearer EMPTY"},
)

with open("output.wav", "wb") as f:
    f.write(response.content)

Embedding Arithmetic

Interpolate between voices using SLERP or weighted averaging:

import numpy as np

def slerp(v0, v1, t):
    """Spherical linear interpolation between two embeddings."""
    v0_n = v0 / (np.linalg.norm(v0) + 1e-8)
    v1_n = v1 / (np.linalg.norm(v1) + 1e-8)
    omega = np.arccos(np.clip(np.dot(v0_n, v1_n), -1, 1))
    if omega < 1e-6:
        return (1 - t) * v0 + t * v1
    return (np.sin((1 - t) * omega) / np.sin(omega)) * v0 + \
           (np.sin(t * omega) / np.sin(omega)) * v1

blended = slerp(embedding_a.numpy(), embedding_b.numpy(), t=0.5)

Model Details

Property Value
Architecture ECAPA-TDNN
Embedding dimension 2048
Input 128-bin log-mel spectrogram
Sample rate 24000 Hz
Parameters ~12.2M
Source model Qwen/Qwen3-TTS-12Hz-1.7B-Base
License Apache 2.0

Architecture

Input mel (batch, time, 128)
  → TDNN (128 → 512, k=5, d=1)
  → SE-Res2Net (512 → 512, k=3, d=2)
  → SE-Res2Net (512 → 512, k=3, d=3)
  → SE-Res2Net (512 → 512, k=3, d=4)
  → Multi-layer Feature Aggregation (1536 → 1536, k=1, d=1)
  → Attentive Statistics Pooling
  → Linear (3072 → 2048)
  → Output embedding (batch, 2048)

Audio Preprocessing

The model expects log-mel spectrograms with these parameters:

Parameter Value
Sample rate 24000 Hz
FFT size 1024
Hop length 256
Window length 1024
Mel bins 128
Frequency range 0–12000 Hz
Mel scale Slaney
Compression log(clamp(x, min=1e-5))

Dependencies

  • torch
  • transformers
  • librosa (for audio loading and mel filterbank computation)
  • numpy

Related Models

[!IMPORTANT] The 0.6B and 1.7B encoders produce embeddings of different dimensions (1024 vs 2048). They are not interchangeable — do not mix embeddings from different model sizes.

Alternative: Manual Mel Preprocessing

If you need full control over the mel spectrogram computation (e.g. for integration into a custom pipeline), you can bypass the feature extractor:

import torch
import librosa
from librosa.filters import mel as librosa_mel_fn
from transformers import AutoModel

model = AutoModel.from_pretrained(
    "marksverdhei/Qwen3-Voice-Embedding-12Hz-1.7B", trust_remote_code=True,
)
model.eval()

audio, sr = librosa.load("audio.wav", sr=None, mono=True)
if sr != 24000:
    audio = librosa.resample(audio, orig_sr=sr, target_sr=24000)

y = torch.from_numpy(audio).unsqueeze(0).float()
mel_basis = torch.from_numpy(
    librosa_mel_fn(sr=24000, n_fft=1024, n_mels=128, fmin=0, fmax=12000)
).float()
padding = (1024 - 256) // 2
y = torch.nn.functional.pad(y.unsqueeze(1), (padding, padding), mode="reflect").squeeze(1)
spec = torch.stft(
    y, 1024, hop_length=256, win_length=1024,
    window=torch.hann_window(1024), center=False, return_complex=True,
)
mel = torch.log(torch.clamp(torch.matmul(mel_basis, torch.abs(spec)), min=1e-5))
mel = mel.transpose(1, 2)  # (1, time, 128)

with torch.no_grad():
    embedding = model(input_values=mel).last_hidden_state  # (1, 2048)

Citation

@article{Qwen3-TTS,
  title={Qwen3-TTS Technical Report},
  author={Hangrui Hu and Xinfa Zhu and Ting He and Dake Guo and Bin Zhang and Xiong Wang and Zhifang Guo and Ziyue Jiang and Hongkun Hao and Zishan Guo and Xinyu Zhang and Pei Zhang and Baosong Yang and Jin Xu and Jingren Zhou and Junyang Lin},
  journal={arXiv preprint arXiv:2601.15621},
  year={2026}
}
@article{ecapa-tdnn,
  title={ECAPA-TDNN: Emphasized Channel Attention, Propagation and Aggregation in TDNN Based Speaker Verification},
  author={Desplanques, Brecht and Thienpondt, Jenthe and Demuynck, Kris},
  journal={Proc. Interspeech},
  year={2020}
}

Configuration

Architecture
EcapaTdnnSpeakerEncoder
Stored precision
float32
Model type
ecapa_tdnn_speaker_encoder

Identity and Version

Repository
marksverdhei/Qwen3-Voice-Embedding-12Hz-1.7B
Publisher
Markus
Task
Feature extraction
Modality
Text
Library
transformers
Parameters
12M parameters
Languages
Not stated by the source
Revision
7577f61c42737fc8064bba773e2a18602df92803
First published
2026-02-09
Last updated
2026-02-23

Files and Weights

10 files, 24.0 MB in total. The weights are 1 file totalling 24.0 MB in safetensors.

Weights1 file · 24.0 MB
Configuration5 files · 19.3 KB
Tokenizer2 files · 2.8 KB
Documentation1 file · 9.7 KB
Repository1 file · 1.5 KB
Every file
FileTypeSizeSHA-256
model.safetensorsWeights24.0 MB df60a638e7f4
config.jsonConfiguration968 B
configuration_ecapa_tdnn.pyConfiguration2.9 KB
feature_extraction_ecapa_tdnn.pyConfiguration4.8 KB
modeling_ecapa_tdnn.pyConfiguration10.3 KB
preprocessor_config.jsonConfiguration275 B
README.mdDocumentation9.7 KB
.gitattributesRepository1.5 KB
tokenizer_config.jsonTokenizer165 B
tokenizer_ecapa_tdnn.pyTokenizer2.6 KB

License and Download

License
apache-2.0
Access
Open weights, no gate
Download size
24.0 MB
Download from Markus

Released by Markus through its official repository on Hugging Face. Read the license.

Built From

Memory Requirements

PrecisionWeights in memory
As published24.0 MB
16-bit0.0 GB
8-bit0.0 GB
4-bit0.0 GB

Weights only, from the published parameter count; the key-value cache and runtime add to this.

Questions About Qwen3-Voice-Embedding-12Hz-1.7B

How much GPU memory does Qwen3-Voice-Embedding-12Hz-1.7B need?

About 0 GB at 16-bit and 0 GB at 4-bit: the weights (12M parameters) plus a working margin. A long context needs more.

What is the cheapest GPU to run Qwen3-Voice-Embedding-12Hz-1.7B on?

At 16-bit, 1x MI300X from $1.85 an hour; at 4-bit, 1x MI300X from $1.85 an hour, at the lowest on-demand prices the SAVRN Index lists.

Can I use Qwen3-Voice-Embedding-12Hz-1.7B commercially?

Yes. Qwen3-Voice-Embedding-12Hz-1.7B is released under Apache License 2.0. The Apache License 2.0 is a permissive open-source license. It permits commercial use, modification and redistribution. It requires keeping the license and copyright notices and any NOTICE file, stating significant changes, and it includes an express patent grant from contributors.

Similar Models

More details please refer to our Github: FlagEmbedding. FlagEmbedding can map any text to a low-dimensional dense vector which can be used for tasks like retrieval, classification, clustering, or semantic search. And it also can be used in vector databases for LLMs. Updates - 10/12/2023: Release LLM-Embedder, a unified embedding model to support diverse retrieval augmentation needs for LLMs. Paper:fire: - 09/15/2023: The technical report of BGE has been released - 09/15/2023: The masive training data of BGE has been released - 09/12/2023: New models: - 09/07/2023: Update fine-tune code: Add script to mine hard negatives and support adding instruction during fine-tuning. - 08/09/2023: BGE…

Open weights mit 24M parameters 512 tokens transformers

Model · Feature extraction

all-MiniLM-L6-v2

Joshua

https://huggingface.co/sentence-transformers/all-MiniLM-L6-v2 with ONNX weights to be compatible with Transformers.js. If you haven't already, you can install the Transformers.js JavaScript library from NPM using: You can then use the model to compute embeddings like this: You can convert this Tensor to a nested JavaScript array using.tolist(): Note: Having a separate repo for ONNX weights is intended to be a temporary solution until WebML gains more traction. If you would like to make your models web-ready, we recommend converting to ONNX using Optimum and structuring your repo like this one (with ONNX weights located in a subfolder named onnx).

Open weights apache-2.0 512 tokens transformers.js

Model · Feature extraction

bge-base-en-v1.5

Joshua

https://huggingface.co/BAAI/bge-base-en-v1.5 with ONNX weights to be compatible with Transformers.js. If you haven't already, you can install the Transformers.js JavaScript library from NPM using: You can then use the model to compute embeddings, as follows: You can also use the model for retrieval. For example: Note: Having a separate repo for ONNX weights is intended to be a temporary solution until WebML gains more traction. If you would like to make your models web-ready, we recommend converting to ONNX using Optimum and structuring your repo like this one (with ONNX weights located in a subfolder named onnx).

Open weights mit 512 tokens transformers.js

Model · Feature extraction

clap-htsat-unfused

LAION eV

The abstract of the paper states that: You can use this model for zero shot audio classification or extracting audio and/or textual features. You can also get the audio and text embeddings using ClapModel If you are using this model for your work, please consider citing the original paper

Open weights apache-2.0 514 tokens transformers

Model · Feature extraction

wavlm-large

Microsoft

The large model pretrained on 16kHz sampled speech audio. When using the model, make sure that your speech input is also sampled at 16kHz. Note: This model does not have a tokenizer as it was pretrained on audio alone. In order to use this model speech recognition, a tokenizer should be created and the model should be fine-tuned on labeled text data. Check out this blog for more in-detail explanation of how to fine-tune the model. - 60,000 hours of Libri-Light - 10,000 hours of GigaSpeech - 24,000 hours of VoxPopuli Authors: Sanyuan Chen, Chengyi Wang, Zhengyang Chen, Yu Wu, Shujie Liu, Zhuo Chen, Jinyu Li, Naoyuki Kanda, Takuya Yoshioka, Xiong Xiao, Jian Wu, Long Zhou, Shuo Ren, Yanmin…

Open weights transformers

For more details please refer to our Github: FlagEmbedding. If you are looking for a model that supports more languages, longer texts, and other retrieval methods, you can try using bge-m3. FlagEmbedding focuses on retrieval-augmented LLMs, consisting of the following projects currently: - 1/30/2024: Release BGE-M3, a new member to BGE model series! M3 stands for Multi-linguality (100+ languages), Multi-granularities (input length up to 8192), Multi-Functionality (unification of dense, lexical, multi-vec/colbert retrieval). It is the first embedding model which supports all three retrieval methods, achieving new SOTA on multi-lingual (MIRACL) and cross-lingual (MKQA) benchmarks. Technical…

Open weights mit 512 tokens sentence-transformers