alt.freeweights.speech / moss-tts-local-transformer-4.55b-voice-acting-v2-sft3
From: laion <huggingface.co/laion>Newsgroups: alt.freeweights.speechSubject:

moss-tts-local-transformer-4.55b-voice-acting-v2-sft3

Date: 2026-11-14Commit: 9e37216Signed: 2DC28CC7B26A283B ✓

Text to speech model with 4.1B parameters. Safetensors weights, 8.28 GB in all. Published by laion under CC-BY-4.0.

4.1B params8.28GBmoss-tts-local-transformer-4.55b-voice-acting-v2-sft3safetensorspermissive
FactsParams4.1BSize8.28 GBFormatssafetensorsTasktext to speechLicenseCC-BY-4.0From sourcepermissive
$ fw get laion/moss-tts-local-transformer-4.55b-voice-acting-v2-sft3
# manifest sha256 e4701a3ace5d… · 8.28 GB · 20 files
$ fw verify ./moss-tts-local-transformer-4.55b-voice-acting-v2-sft3 laion/moss-tts-local-transformer-4.55b-voice-acting-v2-sft3
From sourceHosted (signed)laion/moss-tts-local-transformer-4.55b-voice-acting-v2-sft3Last check: 2026-11-14 21:34 UTC

Get help: custom fine-tune or private deploy. We review your setup before we quote.

Fine-tune of moss-tts-local-transformer-4.55b-voice-acting-v2.

Works with

Overview

Size
8.28 GB
Weights
8.26 GB (safetensors)
Parameters
4.1B
Formats
safetensors
Task
text to speech
License
CC-BY-4.0 (permissive)
Files
20, each with a sha256
Publisher
laion
Added
2026-11-14
Section
alt.freeweights.speech
Lineage

Original release from the publisher.

Base model: laion/moss-tts-local-transformer-4.55b-voice-acting-v2

Where these bytes come from
Publisher at the pinned commit→You

Sources are tried in order. A file counts only when its size and sha256 match the manifest. Sources are checked when you ask for them, not on a timer.

Sources
BadgeHostLast checkResult
From sourcehuggingface.co2026-11-14 21:34 UTCpassed

Model card

From the publisher at commit 9e37216. Shown as plain text with links; images open at the publisher.

MOSS voice-acting v2 — SFT round 3#

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).

What this round changed, measured#

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 2round 3
word error rate on direction-carrying prompts0.4470.099
duration error, median0.100 s0.080 s
clips within 0.5 s of the requested length92.8 %100 %
vocal-burst hit rate0.5160.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.

Inference#

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 <user_inst> 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")
Loading adapters#
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, "<dpo adapter path>", adapter_name="dpo")
model.load_adapter("<voice adapter path>", adapter_name="voice")
model.load_adapter("<emotion adapter path>", 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]
Scaling an adapter without re-merging#

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

How to prompt this model#

Every request is one <user_inst> block. The fields are fixed — none may be added or removed:

<user_inst>
- Reference(s):
{None | Speaker: <name> | <|audio|>}
- 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}
</user_inst>
FieldWhat goes in it
Reference(s)`<\audio\>when a reference recording of the target voice is attached,Speaker: <name>when only a voice name is known, otherwiseNone`.
InstructionA GENERAL: line, a SCRIPT: block, or both.
TokensTarget 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 numbers in the script must add up to it.
Quality, Sound Event, Ambient SoundAlways None. Kept so the field layout matches the base model.
LanguageEnglish or German.
TextThe rendered script, byte-identical to the SCRIPT: block.
GENERAL: — who is speaking#

Prose describing the voice and the clip: age and gender, energy and pace, tension, timbre, clarity, pitch range, breath, affect, which emotions are audible, style, recording quality.

GENERAL: A young adult masculine voice; delivery is normally alert, brisk, neutral tension;
timbre is neutral-toned, fairly smooth; average clarity, wide pitch range, light breath;
affect is mildly positive, slightly dominant; reads as bitterness, contempt; 9.5s, EN.

The phrase reads as … is where the emotion names live.

SCRIPT: — what to say, when, and how#

Four kinds of tag, told apart by their brackets:

TagMeansRule
[3.9 seconds duration]the next sentence must take this longsquare brackets, stands before the text, one per speech segment
[0.8 seconds pause]silence of this lengthsquare brackets; every gap of 0.2 s or more, including before the first word and after the last
(contented sigh, 0.2 seconds)a non-speech vocalisation of this lengthround brackets with a duration — label first, then the seconds
(clearly amused, warm and open, unguarded)how to perform the next sentenceround brackets without a duration, stands before the duration tag

The disambiguation rule in one line: square bracket = a number of seconds; round bracket with a number = a vocal burst; round bracket without a number = a delivery direction. That is the only thing separating a burst from a direction, which is why directions never carry a number.

A complete example:

<user_inst>
- Reference(s):
None
- Instruction:
GENERAL: A young adult feminine voice, warm and conversational; reads as amusement; 6.0s, EN.
SCRIPT:
[0.4 seconds pause] (intensely amused: letting it out / not hiding it, warm and open,
unguarded; bright, relaxed) [2.4 seconds duration] You are not going to believe this.
[0.3 seconds pause] (breathy giggle, 0.4 seconds) [0.2 seconds pause] (still intensely amused)
[2.3 seconds duration] He actually wore it to the wedding.
- Tokens:
75
- Quality:
None
- Sound Event:
None
- Ambient Sound:
None
- Language:
English
- Text:
[0.4 seconds pause] (intensely amused: letting it out / not hiding it, warm and open,
unguarded; bright, relaxed) [2.4 seconds duration] You are not going to believe this.
[0.3 seconds pause] (breathy giggle, 0.4 seconds) [0.2 seconds pause] (still intensely amused)
[2.3 seconds duration] He actually wore it to the wedding.
</user_inst>

0.4 + 2.4 + 0.3 + 0.4 + 0.2 + 2.3 = 6.0 s = 75 frames. If the numbers do not add up to the token budget the model has to choose which to honour, and length control is the thing it honours best.

Segmentation rules the training data followed#
  • split at sentence ends (. ! ? …) and at every vocal burst;
  • any segment still longer than 12 s is split again at its largest internal gap;
  • a duration is measured from the first word onset to the last word offset of that segment, so two sentences of 12 s and 8 s produce [12.0 seconds duration] and [8.0 seconds duration], never a single [20.0 seconds duration];
  • gaps below 0.20 s are folded into the neighbouring speech instead of being printed, so the printed numbers still add up;
  • a burst that overlaps speech prints only the part that does not overlap.
Vocal-burst labels that actually occur in training#

low mumble, ahem, contented sigh, surprised gasp, chuckle, breathy giggle, childlike giggle, wistful sigh, exhausted groan, sharp inhale, resonant hum, scream, yawn, deep breath, soft hum, exasperated sigh, cackle, shriek, coughing, mournful wail, growl, purr.

Realistic lengths: median 0.28 s, 10th percentile 0.14 s, 90th percentile 0.48 s, longest observed 2.46 s. A sigh requested at 3 s is outside anything in the data.

Intensity bands#

Delivery directions carry an intensity adverb drawn from the percentile band of the requested emotion. The same cutoffs are used by the training data, the reward and the evaluation:

bandpercentileadverbs
faint0.40 – 0.70barely, faintly, only slightly, just a little
moderate0.70 – 0.90clearly, plainly, noticeably, unmistakably
intense0.90 – 0.98strongly, intensely, very, deeply
extreme0.98 – 1.00overwhelmingly, extremely, utterly, completely

The family#

🧩 Base model (required by every adapter here)laion/moss-tts-local-transformer-4.55b-voice-acting-v2-sft3
🎚️ Preference-tuning adapterlaion/moss-va-sft3-dpo-lora
🎭 40 emotion adapterslaion/moss-va-sft3-emotion-loras
🗣️ 500 voice adapterslaion/moss-va-sft3-voice-loras
🔊 Listening page — nine models on the same 80 prompts, with ASR transcriptslaion/moss-va-sft3-samples
🔬 Emotion adapters vs baseline, matched and neutral promptslaion/moss-va-emotion-loras
🧪 Four-factor study — what actually drives the emotion scorelaion/moss-va-four-factor-study
📄 Technical reportlaion/moss-va-technical-report
📖 Voice-acting manual (v2 model)projects.laion.ai/moss-voiceacting-manual
⬅️ Predecessorsvoice-acting-v2 · -sft · -sft-dpo

Citation and provenance#

Derived from MOSS-TTSD / MOSS local-transformer 1.5. Training data: LAION voice profiles plus public real-speech corpora (EmoLia, Kartoffelphon, MLS). Released CC-BY-4.0.

Recipes, prompting and the rest of the stack#

This is the base model the adapter sets below are trained against. What you can ask it for, and at what weight, is written down rather than left to trial and error.

Where the recipes live#
Recipes — per class: which adapter, what weight, which prompt form, measured hit rate, how many candidates to drawwikiskills/ · summary table in VOCAL_BURSTS.md
Prompting guide — the contract the directing language model followsdocs/DIRECTOR.md
How adapters are merged — and why not through PEFT at batch 1docs/ADAPTERS.md
How the whole system fits togetherdocs/ENSEMBLE.md
Writing the cue#

Brackets carry meaning in this format, and two rules catch nearly everyone out.

you writethe model hears
(chuckle)a sound — a vocal burst, given its own slot in the timing
(clearly amused, warm and open)an instruction for how to say the next sentence
(clearly amused, with a small chuckle)an instruction, and no chuckle happens
(quietly, 2 seconds)a sound, not an instruction — a round bracket containing a number stops being a direction
[pause]a beat of silence

Cues are always written in English, even when the spoken line is German. This is how the training corpus is written — German rows read Das zerreißt einen einfach, weißt du? (relief sigh) — so a German cue is out of distribution.

Never write a number inside a bracket. The durations are computed for you and inserted afterwards: [N.N seconds duration] before each speech segment, [N.N seconds pause] for gaps, (label, N.N seconds) for each burst, summed at 12.5 frames per second.

Files

20 files · 8.28 GBWeights 8.26 GB (safetensors). Sizes and sha256 from the signed manifest.
Hide all 20 files with their sha256
FileSizesha256
.gitattributes1.57 KB34448b82c17d60fec9b65b1f093c115ddbaadc04beb1b0140b6bfed2e012a930
README.md15.4 KB979055e1a8975b71a6dd4f5cf91fce02985a84e011c4a6955f741cc3a69ef320
__init__.py254 Bfa22d925207c64e6701f9c5f97c3e14a9bad4db5c37060c6e5f1362c02bc8040
added_tokens.json790 B39bb49db6acfb8e7510b1640f575bdc183f511d85c94ce3ee967f2a6195c4a8a
chat_template.jinja4.17 KBa55ee1b1660128b7098723e0abcd92caa0788061051c62d51cbe87d9cf1974d8
config.json6.99 KBced0e41ba4ea840212721e3b25f1ca857c2939901be7564f1c9060c9a955790f
configuration_moss_tts.py7.16 KBab6debcb92032cb9dc91ae80aed77dbadd2e59848208baef2b062bd6def3f3be
generation_config.json95 B2272170751602ba1a917710468548e6c4102325f85277fe5fcc5936f56c42f48
gpt2_decoder.py30.9 KBf2e877104669f1e6c7cd34680f0da1a8a159e032123ee56b660b63929b6c8989
merges.txt1.67 MB8831e4f1a044471340f7c0a83d7bd71306a5b867e95fd870f74d0c5308a904d5
model.safetensors8.26 GBf22ebff9360adb06672c22e7f45a34b8abec75fdc43c7f77423912edb57b4808
modeling_moss_tts.py26.4 KBb0a66211943ae580b087f3e71495fea2f455701a4f6c29b6d3562218f7668c5f
processing_moss_tts.py37.5 KB059637b92e7eb9a67df531fe9578e9554d456195828b223eb81f21117c58e8f8
processor_config.json209 Bfac7289af2a37d988d708d813c92960e5e91c59d348c17b72c6aa6b86859f2b7
provenance.json1.47 KB56b343cc9989420b6a41e916bf4aed8d9589471617c8dc32450839494323ed9b
qwen3_decoder.py25.5 KB100163bd7ecf31a59bafacc0b032ace9339edc992a3eb4cc80662502e04e46f0
special_tokens_map.json394 B02a153514db64e5378c53ef164c960409882649de6f4aac8f81f66218e7f8797
tokenizer.json11.4 MB06902d1fb775216338802205886a24bc715ccc606bd872a892e3d3c83ca1b9e2
tokenizer_config.json5.73 KBec2869dd4c9c7155b3460c291a6fb2b955e5068013ba7efbcaafd1c61e02abce
vocab.json2.78 MBca10d7e9fb3ed18575dd1e277a2579c16d108e32f27439684afa0e10b1440910
VersionsEach time the pinned upstream commit or file list changed in this repo. Newest first.
Upstream commitDateContents
9e372160fd pinned now manifest updated, same commit2026-11-14 21:34 UTC20 files · 8.28 GB
9e372160fd2026-11-14 21:34 UTC20 files · 8.28 GB

Use it

$ fw get laion/moss-tts-local-transformer-4.55b-voice-acting-v2-sft3
# manifest sha256 e4701a3ace5d… · 8.28 GB · 20 files
$ fw verify ./moss-tts-local-transformer-4.55b-voice-acting-v2-sft3 laion/moss-tts-local-transformer-4.55b-voice-acting-v2-sft3
fw.pyChecks the signature and every sha256, tries each source in order, resumes.
$ python3 fw.py get https://freeweights.allternit.com/manifests/laion/moss-tts-local-transformer-4.55b-voice-acting-v2-sft3.json --dir ./moss-tts-local-transformer-4.55b-voice-acting-v2-sft3 $ python3 fw.py verify ./moss-tts-local-transformer-4.55b-voice-acting-v2-sft3 ./laion__moss-tts-local-transformer-4.55b-voice-acting-v2-sft3.json
hfThe Hugging Face CLI with one setting. Same repo id.
$ HF_ENDPOINT=https://freeweights.allternit.com hf download laion/moss-tts-local-transformer-4.55b-voice-acting-v2-sft3 --revision 9e372160fda2ca90aa6e407849fd82914d0cfe73 --local-dir ./moss-tts-local-transformer-4.55b-voice-acting-v2-sft3

License

Name
Creative Commons Attribution 4.0
Id
CC-BY-4.0
Class
Permissive
Redistribution
yes
Listing
Hosted (signed)
Decided
License as declared by the publisher. No person read it. 2026-11-14
Text in
README.md
Text sha256
979055e1a8975b71a6dd4f5cf91fce02985a84e011c4a6955f741cc3a69ef320
Terms gate
No extra terms beyond the license.

Read the license text

Licenses are checked against the license table. A custom license passes only after a person reads it.

Provenance

From: laion <huggingface.co/laion>Newsgroups: alt.freeweights.speechSubject: moss-tts-local-transformer-4.55b-voice-acting-v2-sft3Date: 2026-11-14Commit: 9e37216Signed: 2DC28CC7B26A283B ✓
Upstream
laion/moss-tts-local-transformer-4.55b-voice-acting-v2-sft3
Pinned commit
9e372160fda2ca90aa6e407849fd82914d0cfe73
Manifest
moss-tts-local-transformer-4.55b-voice-acting-v2-sft3.json · .minisig
Manifest sha256
e4701a3ace5d542f8b0f434c124074241d7d9793cf6ecd68ba2bf8611f433b19
Signature
minisign, Ed25519, key 2DC28CC7B26A283B
Created
2026-11-14 21:34 UTC
Generator
freeweights-manifest/0.1.0
Takedowns
None.

How to verify

$ curl -O https://freeweights.allternit.com/manifests/laion/moss-tts-local-transformer-4.55b-voice-acting-v2-sft3.json $ curl -O https://freeweights.allternit.com/manifests/laion/moss-tts-local-transformer-4.55b-voice-acting-v2-sft3.json.minisig $ minisign -Vm moss-tts-local-transformer-4.55b-voice-acting-v2-sft3.json -P RWQ7KGqyx4zCLXtUFOqvfv8L3g+8fpKJ1FsuxPyOYMF+4KufbUxKq1Oq $ shasum -a 256 <file> # compare with the Files tab

A manifest whose signature fails must be rejected. A file whose size or sha256 does not match must be discarded. Verify a download

Model tree

Parent

laion/moss-tts-local-transformer-4.55b-voice-acting-v2 · this model is a finetune of it

7 models in the catalog name this one as their parent.

Fine-tunes
1
Adapters
6
Get it
Download
$ HF_ENDPOINT=https://freeweights.allternit.com hf download laion/moss-tts-local-transformer-4.55b-voice-acting-v2-sft3
Open in Freeweights Studio

Pull, verify and run it in the Allternit app on Desktop, web or phone.

Signed manifest
minisign, key 2DC28CC7B26A283B. moss-tts-local-transformer-4.55b-voice-acting-v2-sft3.json. Provenance. Takedown history: none.

Variants

6 quantized or adapter builds of moss-tts-local-transformer-4.55b-voice-acting-v2-sft3. Each has its own license check and page.

From: MIT <huggingface.co/MIT>Subject: ast-finetuned-audioset-10-10-0.4593
From: onnx-community <huggingface.co/onnx-community>Subject: ast-finetuned-audioset-10-10-0.4593-ONNX
From: Edge0 <huggingface.co/Edge0>Subject: Audio8-TTS-Preview-0.6b
From: Edge0 <huggingface.co/Edge0>Subject: Audio8-TTS-Realistic-Air
From: facebook <huggingface.co/facebook>Subject: audiobox-aesthetics
From: mlx-community <huggingface.co/mlx-community>Subject: chatterbox-4bit