Skip to content

Commit 8e9d77f

Browse files
committed
fix: correct MiniMax H3 reference audio encoding
1 parent de298c2 commit 8e9d77f

2 files changed

Lines changed: 38 additions & 17 deletions

File tree

src/model/vae/minimax_h3_audio_vae.hpp

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -154,8 +154,9 @@ namespace MiniMaxH3 {
154154
const String2TensorStorage& tensor_storage_map = {},
155155
const std::string prefix = "") override {
156156
GGMLBlock::init_params(ctx, tensor_storage_map, prefix);
157-
params["q_bias"] = ggml_new_tensor_1d(ctx, GGML_TYPE_F32, in_channels);
158-
params["v_bias"] = ggml_new_tensor_1d(ctx, GGML_TYPE_F32, in_channels);
157+
params["q_bias"] = ggml_new_tensor_1d(ctx, GGML_TYPE_F32, in_channels);
158+
params["zero_k_bias"] = ggml_new_tensor_1d(ctx, GGML_TYPE_F32, in_channels);
159+
params["v_bias"] = ggml_new_tensor_1d(ctx, GGML_TYPE_F32, in_channels);
159160
}
160161

161162
ggml_tensor* forward(GGMLRunnerContext* ctx, ggml_tensor* x) {
@@ -166,7 +167,7 @@ namespace MiniMaxH3 {
166167
return ggml_reshape_4d(ctx->ggml_ctx, bias, bias->ne[0], 1, 1, 1);
167168
};
168169
auto q = ggml_add(ctx->ggml_ctx, qkv[0], bias_shape(params["q_bias"]));
169-
auto k = qkv[1];
170+
auto k = ggml_add(ctx->ggml_ctx, qkv[1], bias_shape(params["zero_k_bias"]));
170171
auto v = ggml_add(ctx->ggml_ctx, qkv[2], bias_shape(params["v_bias"]));
171172

172173
int64_t sequence = x->ne[1];
@@ -358,22 +359,38 @@ namespace MiniMaxH3 {
358359
}
359360

360361
ggml_tensor* encode(GGMLRunnerContext* ctx, ggml_tensor* waveform) {
361-
GGML_ASSERT(waveform->ne[1] == 2);
362+
GGML_ASSERT(waveform->ne[1] * waveform->ne[2] * waveform->ne[3] == 2);
362363
auto encoder = std::dynamic_pointer_cast<AudioEncoder>(blocks["encoder"]);
363364
auto pre = std::dynamic_pointer_cast<AudioAttentionProjection>(blocks["pre_block"]);
364365
auto mean_proj = std::dynamic_pointer_cast<LTXV::Conv1D>(blocks["mean_proj"]);
365366

366-
waveform = ggml_reshape_3d(ctx->ggml_ctx, waveform, waveform->ne[0], 1, waveform->ne[1]);
367-
auto x = encoder->forward(ctx, waveform); // [B*S, 2048, T]
368-
x = ggml_cont(ctx->ggml_ctx, ggml_permute(ctx->ggml_ctx, x, 1, 0, 2, 3));
369-
x = pre->forward(ctx, x);
370-
x = ggml_cont(ctx->ggml_ctx, ggml_permute(ctx->ggml_ctx, x, 1, 0, 2, 3));
371-
auto z = mean_proj->forward(ctx, x);
372-
373-
auto mean = ggml_reshape_4d(ctx->ggml_ctx, params["latents_mean"], 1, kLatentChannels, 1, 1);
374-
auto std = ggml_reshape_4d(ctx->ggml_ctx, params["latents_std"], 1, kLatentChannels, 1, 1);
375-
z = ggml_div(ctx->ggml_ctx, ggml_sub(ctx->ggml_ctx, z, mean), std);
376-
return ggml_cont(ctx->ggml_ctx, ggml_permute(ctx->ggml_ctx, z, 0, 2, 1, 3));
367+
// GGML's batched conv1d storage interleaves the stream dimension
368+
// with output channels. Subsequent layers then read stereo samples
369+
// as adjacent feature channels. Run each mono stream independently,
370+
// matching PyTorch's reshape(B*S, 1, samples), and concatenate only
371+
// the completed normalized latents.
372+
const int64_t streams = waveform->ne[2] * waveform->ne[3];
373+
waveform = ggml_reshape_3d(ctx->ggml_ctx,
374+
waveform,
375+
waveform->ne[0],
376+
1,
377+
streams);
378+
ggml_tensor* stereo_z = nullptr;
379+
for (int64_t stream = 0; stream < streams; ++stream) {
380+
auto mono = ggml_ext_slice(ctx->ggml_ctx, waveform, 2, stream, stream + 1);
381+
auto x = encoder->forward(ctx, mono);
382+
x = ggml_cont(ctx->ggml_ctx, ggml_permute(ctx->ggml_ctx, x, 1, 0, 2, 3));
383+
x = pre->forward(ctx, x);
384+
x = ggml_cont(ctx->ggml_ctx, ggml_permute(ctx->ggml_ctx, x, 1, 0, 2, 3));
385+
auto z = mean_proj->forward(ctx, x);
386+
387+
auto mean = ggml_reshape_4d(ctx->ggml_ctx, params["latents_mean"], 1, kLatentChannels, 1, 1);
388+
auto std = ggml_reshape_4d(ctx->ggml_ctx, params["latents_std"], 1, kLatentChannels, 1, 1);
389+
z = ggml_div(ctx->ggml_ctx, ggml_sub(ctx->ggml_ctx, z, mean), std);
390+
z = ggml_cont(ctx->ggml_ctx, ggml_permute(ctx->ggml_ctx, z, 0, 2, 1, 3));
391+
stereo_z = stereo_z == nullptr ? z : ggml_concat(ctx->ggml_ctx, stereo_z, z, 1);
392+
}
393+
return stereo_z;
377394
}
378395

379396
ggml_tensor* decode(GGMLRunnerContext* ctx, ggml_tensor* latent) {

src/stable-diffusion.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4728,7 +4728,11 @@ static sd::Tensor<float> prepare_minimax_h3_reference_waveform(const sd_audio_t&
47284728
static_cast<long double>(audio.sample_count) * target_sample_rate / audio.sample_rate));
47294729
output_samples = std::max<uint64_t>(1, output_samples);
47304730
uint64_t padded_samples = (output_samples + 799) / 800 * 800;
4731-
sd::Tensor<float> waveform({static_cast<int64_t>(padded_samples), 2, 1, 1});
4731+
// Keep stereo streams planar for the mono-per-stream audio encoder:
4732+
// [samples, 1, stereo, batch]. This avoids flattening interleaved L/R
4733+
// storage into alternating samples when the encoder folds streams into
4734+
// its batch dimension.
4735+
sd::Tensor<float> waveform({static_cast<int64_t>(padded_samples), 1, 2, 1});
47324736

47334737
for (uint64_t i = 0; i < output_samples; ++i) {
47344738
long double source_pos = static_cast<long double>(i) * audio.sample_rate / target_sample_rate;
@@ -4739,7 +4743,7 @@ static sd::Tensor<float> prepare_minimax_h3_reference_waveform(const sd_audio_t&
47394743
uint32_t source_channel = audio.channels == 1 ? 0 : std::min<uint32_t>(channel, audio.channels - 1);
47404744
float a = audio.data[source0 * audio.channels + source_channel];
47414745
float b = audio.data[source1 * audio.channels + source_channel];
4742-
waveform.index(static_cast<int64_t>(i), channel, 0, 0) =
4746+
waveform.index(static_cast<int64_t>(i), 0, channel, 0) =
47434747
std::clamp(a + (b - a) * fraction, -1.f, 1.f);
47444748
}
47454749
}

0 commit comments

Comments
 (0)