|
30 | 30 | #include "kokoro.h" |
31 | 31 | #include "kokoro-istft.h" |
32 | 32 | #include "kokoro-phonemes.h" |
| 33 | +#include "kokoro-tensor-names.h" |
33 | 34 |
|
34 | 35 | #include "ggml.h" |
35 | 36 | #include "ggml-alloc.h" |
@@ -164,6 +165,39 @@ static ggml_tensor * find_tensor(ggml_context * ctx, const std::string & name) { |
164 | 165 | return ggml_get_tensor(ctx, name.c_str()); |
165 | 166 | } |
166 | 167 |
|
| 168 | +static bool has_tensor_alias(const char * name, void * user_data) { |
| 169 | + return name && ggml_get_tensor((ggml_context *) user_data, name) != nullptr; |
| 170 | +} |
| 171 | + |
| 172 | +static ggml_tensor * find_tensor_any(ggml_context * ctx, const char * const * aliases) { |
| 173 | + const char * name = kokoro_pick_tensor_name(aliases, has_tensor_alias, ctx); |
| 174 | + return name ? ggml_get_tensor(ctx, name) : nullptr; |
| 175 | +} |
| 176 | + |
| 177 | +static std::string format_aliases(const char * const * aliases) { |
| 178 | + std::string out; |
| 179 | + for (const char * const * p = aliases; p && *p; ++p) { |
| 180 | + if (!out.empty()) out += ", "; |
| 181 | + out += "'"; |
| 182 | + out += *p; |
| 183 | + out += "'"; |
| 184 | + } |
| 185 | + return out; |
| 186 | +} |
| 187 | + |
| 188 | +static ggml_tensor * require_tensor_any( |
| 189 | + ggml_context * ctx, |
| 190 | + const char * const * aliases, |
| 191 | + const char * label, |
| 192 | + std::string & err_out) { |
| 193 | + ggml_tensor * t = find_tensor_any(ctx, aliases); |
| 194 | + if (!t) { |
| 195 | + err_out = std::string("required tensor missing for ") + label |
| 196 | + + " (accepted names: " + format_aliases(aliases) + ")"; |
| 197 | + } |
| 198 | + return t; |
| 199 | +} |
| 200 | + |
167 | 201 | } // namespace |
168 | 202 |
|
169 | 203 | // --------------------------------------------------------------------------- |
@@ -259,14 +293,38 @@ kokoro_model_ptr kokoro_load_model( |
259 | 293 | } |
260 | 294 | } |
261 | 295 |
|
262 | | - // Bind canonical tensors. Missing tensors are non-fatal during the J2 |
263 | | - // ship phase — the synthesis path treats absent tensors as zero, which |
264 | | - // produces shape-correct but acoustically degraded output. See the |
265 | | - // J2-kokoro-port-notes.md gap log. |
266 | | - model->tok_embd = find_tensor(model->ctx, "kokoro.token_embd.weight"); |
| 296 | + // Bind the published Kokoro GGUF schema, while accepting the older |
| 297 | + // unprefixed dev names from pre-publication GGUFs. Missing required |
| 298 | + // tensors are a hard load error: otherwise the synth path can appear to |
| 299 | + // work while silently skipping the real model weights. |
| 300 | + model->tok_embd = require_tensor_any( |
| 301 | + model->ctx, |
| 302 | + KOKORO_TENSOR_BERT_TOKEN_EMBD, |
| 303 | + "BERT token embedding", |
| 304 | + err_out); |
| 305 | + if (!model->tok_embd) return {nullptr, kokoro_model_deleter{}}; |
| 306 | + |
| 307 | + if (!require_tensor_any(model->ctx, KOKORO_TENSOR_BERT_ATTN_Q, "BERT attention Q", err_out)) { |
| 308 | + return {nullptr, kokoro_model_deleter{}}; |
| 309 | + } |
| 310 | + if (!require_tensor_any(model->ctx, KOKORO_TENSOR_F0_PROJ, "F0 projection", err_out)) { |
| 311 | + return {nullptr, kokoro_model_deleter{}}; |
| 312 | + } |
| 313 | + if (!require_tensor_any(model->ctx, KOKORO_TENSOR_N_PROJ, "noise projection", err_out)) { |
| 314 | + return {nullptr, kokoro_model_deleter{}}; |
| 315 | + } |
| 316 | + if (!require_tensor_any(model->ctx, KOKORO_TENSOR_GEN_CONV_POST, "generator post convolution", err_out)) { |
| 317 | + return {nullptr, kokoro_model_deleter{}}; |
| 318 | + } |
| 319 | + |
267 | 320 | model->mel_proj = find_tensor(model->ctx, "kokoro.decoder.mel_proj.weight"); |
268 | 321 | model->phase_proj = find_tensor(model->ctx, "kokoro.decoder.phase_proj.weight"); |
269 | | - model->dur_proj = find_tensor(model->ctx, "kokoro.predictor.duration.weight"); |
| 322 | + model->dur_proj = require_tensor_any( |
| 323 | + model->ctx, |
| 324 | + KOKORO_TENSOR_DURATION_PROJ, |
| 325 | + "duration projection", |
| 326 | + err_out); |
| 327 | + if (!model->dur_proj) return {nullptr, kokoro_model_deleter{}}; |
270 | 328 | model->style_proj = find_tensor(model->ctx, "kokoro.style.proj.weight"); |
271 | 329 | model->out_norm = find_tensor(model->ctx, "kokoro.text.out_norm.weight"); |
272 | 330 |
|
|
0 commit comments