home/ atoms/ audio-tensor-shape-sources-channels-time

Demucs' internal separation output is a 4-D tensor shaped [batch, sources, channels, time]

Internally, when Demucs applies a model to a mix, it allocates the separated output as a 4-dimensional tensor with shape [batch, sources, channels, time]: batch is the number of tracks processed together, sources is the number of stems (4 for the standard model), channels is 2 for stereo, and time is the number of audio samples. The public Python API hides this: Separator.separate_audio_file() and separate_tensor() take a (channels, time) waveform and return a (origin, dict) tuple whose dict maps each stem name to its own (channels, time) wave. So when scripting Demucs you index the returned dict by stem name, but if you drop into the lower-level apply_model you must slice the sources axis (dim 1) of the raw tensor to pick a stem. Confusing the two layouts is a common source of shape errors.

Examples

# Public API: dict keyed by stem name
origin, separated = separator.separate_audio_file('track.mp3')
vocals = separated['vocals']   # shape (channels, time)

# Low-level apply_model returns a raw tensor
# out shape == (batch, sources, channels, time); pick stem index 3
from demucs.apply import apply_model
out = apply_model(model, mix[None])   # add batch dim
vocals_raw = out[0, 3]                # (channels, time)

Assessment

The public separate_audio_file() returns a dict, but apply_model returns a 4-D tensor of shape (batch, sources, channels, time). Which axis indexes the stem in the raw tensor, and how do you get the same ‘vocals’ stem from each of the two forms?

“out = th.zeros(batch, len(model.sources), channels, length”
corpus · demucs-music-source-stem-separation · chunk 13