Model reference · open weights
moss-tts-local-transformer-voice-acting-sft3 is an open-weight audio or speech model from laion. AxForge deploys and operates it for you on dedicated EU-owned hardware — with the licence handled where one is required.
Available as managed deployment — configured and operated for you on dedicated EU hardware, quoted per deployment.
What it is
| Released by | laion |
|---|---|
| Type | Audio & music |
| Task | Text→speech |
| Parameters (lead) | 4.1B |
| Runs with | transformers |
| Based on | laion/moss-tts-local-transformer-4.55b-voice-acting-v2 |
| Released | 2026-08-26 |
| Popularity | 722 downloads / month |
| Licence | Open weights |
About
A supervised fine-tune of
laion/moss-tts-local-transformer-4.55b-voice-acting-v2
that adds explicit control over timing — per-sentence durations, pauses, and vocal bursts with
their lengths — and inline delivery directions that say how to perform each line.
4.13 B trainable parameters: a ~4 B semantic transformer (36 layers), a ~550 M local "talker" transformer, and 12 audio LM heads over a 12-codebook audio tokenizer at 12.5 frames per second (one frame = 80 ms).
Trained on 398,282 rows selected as the strongest examples of each of 40 emotions and each VoiceNet dimension, 2 epochs, 712 steps on 32 nodes. Evaluated by generating 320 clips and scoring them, not by validation loss — this project has repeatedly seen training metrics point the wrong way.
| round 2 | round 3 | |
|---|---|---|
| word error rate on direction-carrying prompts | 0.447 | 0.099 |
| duration error, median | 0.100 s | 0.080 s |
| clips within 0.5 s of the requested length | 92.8 % | 100 % |
| vocal-burst hit rate | 0.516 | 0.666 |
Round 2 had accidentally dropped the delivery directions its predecessor was trained with, and a model that has never seen a direction falls apart when given one — word error rate 0.48–0.51 on such prompts, for every round-2 model. Round 3 trained them back in. Timing control is solved.
Emotional intensity is not. Asked for percentile 0.90–0.98 of a named emotion, this model reaches about 0.35. Several objectives were tried against that — GRPO with a group-relative reward, DPO with contrastive pairs, DPO with symmetric instruction-conditioned pairs — and none moved it. The emotion adapters below are the only thing that has, and even they are not selective enough to merge in blindly. This is documented honestly in the technical report.
import torch, torchaudio
from transformers import AutoProcessor, AutoModel
BASE = "laion/moss-tts-local-transformer-4.55b-voice-acting-v2-sft3"
proc = AutoProcessor.from_pretrained(BASE, trust_remote_code=True)
model = AutoModel.from_pretrained(BASE, trust_remote_code=True,
dtype=torch.bfloat16, attn_implementation="sdpa").cuda().eval()
prompt = open("prompt.txt").read() # the block, see "How to prompt" below
um = {"role": "user", "content": prompt, "audio_codes_list": []}
b = proc([[um]], mode="generation")
with torch.no_grad():
out = model.generate(input_ids=b["input_ids"].cuda(),
attention_mask=b["attention_mask"].cuda(),
max_new_frames=340, do_sample=True,
audio_temperature=1.0, audio_top_p=0.95, audio_top_k=50,
audio_repetition_penalty=1.0)
# codes -> waveform. Use the processor's own decoder: calling the audio tokenizer directly, or
# reshaping its output, yields a two-channel result that flattens into audio at HALF SPEED and
# still sounds like speech. This project lost a whole corpus to that once.
wav = proc.decode_audio_codes([out_codes], return_stereo=False)[0].reshape(-1).float().cpu()
torchaudio.save("out.flac", wav[None], int(proc.model_config.sampling_rate), format="flac")
from peft import PeftModel
# one adapter
model = PeftModel.from_pretrained(model, "laion/moss-va-sft3-dpo-lora")
# several, each with its own weight -- the usual case: identity from a voice adapter,
# affect from an emotion adapter, general quality from the DPO adapter.
#
# NOTE: `add_weighted_adapter(..., combination_type="linear")` does NOT work here. It raises
# `ValueError: All adapters must have the same r value`, because the DPO adapter is rank 64 and
# the voice / emotion adapters are rank 16. Activate them together instead and scale each one.
model = PeftModel.from_pretrained(model, "", adapter_name="dpo")
model.load_adapter("", adapter_name="voice")
model.load_adapter("", adapter_name="emo")
names = ["dpo", "voice", "emo"]
weights = {"dpo": 1.0, "voice": 1.0, "emo": 1.5} # 1.5 for emotion is the measured optimum
model.base_model.set_adapter(names) # the TUNER takes a list; PeftModel does not
model.active_adapter = names[0] # must stay a str or generate() indexes a list
for mod in model.modules():
sc = getattr(mod, "scaling", None)
if isinstance(sc, dict):
if not hasattr(mod, "_base_scaling"):
mod._base_scaling = dict(sc)
for k in sc:
if k in weights:
sc[k] = mod._base_scaling[k] * weights[k]
A LoRA layer computes h + scaling · B(A(x)), so multiplying the stored scaling is the merge
weight — exact and reversible:
def set_lora_scale(model, w):
for mod in model.modules():
sc = getattr(mod, "scaling", None)
if isinstance(sc, dict):
if not hasattr(mod, "_base_scaling"):
mod._base_scaling = dict(sc)
for k in sc:
sc[k] = mod._base_scaling[k] * w
Every request is one `` block. The fields are fixed — none may be added or removed:
- Reference(s):
{None | Speaker: | }
- Instruction:
{GENERAL: ... and/or SCRIPT: ...}
- Tokens:
{target length in audio frames}
- Quality:
None
- Sound Event:
None
- Ambient Sound:
None
- Language:
{English | German}
- Text:
{the same script as under SCRIPT:, character for character}
| Field | What goes in it |
|---|---|
Reference(s) | `` when a reference recording of the target voice is attached, Speaker: when only a voice name is known, otherwise None. |
Instruction | A GENERAL: line, a SCRIPT: block, or both. |
Tokens | Target length in audio frames. The tokenizer runs at 12.5 frames per second, so 12.8 s = 160 frames. This is the length budget and the numbe |
From the published model card. Full card on the HuggingFace links in the sidebar.
Using it via the API
Once AxForge deploys moss-tts-local-transformer-voice-acting-sft3 for you, it answers on the OpenAI-compatible API — the same base URL and keys as every other model. (moss-tts-local-transformer-voice-acting-sft3 below is illustrative; you get the exact model name on deployment.)
$ curl -sS https://api.axforge.ai/v1/audio/transcriptions \ -H "Authorization: Bearer $AXFORGE_API_KEY" \ -F model="moss-tts-local-transformer-voice-acting-sft3" -F file=@audio.mp3
Create an account — your API key is available in the console. 3M free tokens every 30 days with every new account.