chantier BigVGAN HMX Phase 2b: refactor sched-friendly + limite backend découverte
Refactor stage_bigvgan en variante stage_bigvgan_sched :
- ggml_init(no_alloc=true) + mem_size réduit 12 GB -> 16 MB
- ggml_set_input/output sur input/output
- causal_conv1d_TC : ggml_pad_ext au lieu de memset zeros + concat
- apply_snake_TC : lookup d.snake_consts pré-calculé (au lieu de host exp() per-frame)
- Pattern sched_reset + alloc_graph + tensor_set + compute + tensor_get
- Switch dans Decoder::forward : sched ? stage_bigvgan_sched : stage_bigvgan
Snake constants pré-calculées au load_with_backends :
- 29 paires (a_eff, inv_b) stockées dans ctx_const + buf_const sur le même
backend que buf_w. exp() host-side une fois au load au lieu de chaque frame.
- buf_const ~0.1 MB sur HTP0 (29 × 2 × C × f32 avec C de 96 à 1536).
Mesure tablette (KZTTS_DECODER_HTP=1 KZTTS_DECODER_SCHED=1 GGML_HEXAGON_USE_HMX=1) :
baseline CPU pur : decoder 3.34s, bigvgan 3.19s
sched HTP path neuf : decoder 3.95s, bigvgan 3.76s -> REGRESSION 18%
Cause : GGML_SCHED_DEBUG=2 révèle que TOUS les MUL_MAT tombent sur CPU.
ggml_hexagon_supported_mul_mat rejette ggml_nrows(src1) > 1024 (commentaire
'no huge batches (for now)'). BigVGAN block 3 résiduels : conv1d k=7 sur
T=59520, im2col_output [672, 59520] -> 59520 rows >> 1024. Tous les
MUL_MAT BigVGAN sont rejetés -> fallback CPU + copies inutiles -> régression.
PHASE 2b STATUT : refactor fait et stable, mais le gain HMX nécessite
soit (a) modifier ggml-hexagon pour gros batches, (b) splitter MUL_MAT
en chunks ≤ 1024, (c) reprendre via étape F (CP HMX) qui n'a pas ce
problème (nrows ≤ 16 par sub-forward).
Snapshots updatés dans dist/decoder_patches/.
Le path activé seulement si KZTTS_DECODER_SCHED=1 (opt-in, désactivé par
défaut). En mode KZTTS_DECODER_HTP=1 sans SCHED : path legacy CPU pur, perf
inchangée vs baseline (poids juste relogés sur HTP buffer via opt_hostbuf=1).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
9de6b76838
commit
bdd528ed25
|
|
@ -37,26 +37,42 @@ Phase 2 du chantier BigVGAN HMX.
|
|||
| `KZTTS_DECODER_HTP=1` | poids alloués sur HTP buffer, compute CPU pur via `opt_hostbuf=1` (HTP buffer CPU-mappable). Pas de gain HMX mais valide la chaîne. |
|
||||
| `KZTTS_DECODER_HTP=1 KZTTS_DECODER_SCHED=1` | sched créé, mais stages encore en compute_with_ctx → assertion `buffer_id >= 0` au premier compute. **NE FONCTIONNE PAS** sans refactor stages. |
|
||||
|
||||
## Reste à faire (Phase 2 session suivante)
|
||||
## Phase 2b livrée — mais bloquée par limite backend
|
||||
|
||||
Refactor de `stage_bigvgan` (et causal_conv1d_TC, apply_snake_TC,
|
||||
precompute_snake) pour le pattern sched :
|
||||
Refactor stage_bigvgan en pattern sched-friendly **fait** :
|
||||
1. ✅ snake constants pré-calculées au load (`ctx_const` + `buf_const`)
|
||||
2. ✅ `stage_bigvgan_sched` (variante du stage_bigvgan legacy)
|
||||
3. ✅ `ggml_init(no_alloc=true)` + `ggml_set_input/output`
|
||||
4. ✅ `memset zeros + concat` remplacé par `ggml_pad_ext`
|
||||
5. ✅ Wrapping sched_reset + alloc + tensor_set + compute + tensor_get
|
||||
6. ✅ Switch dans `Decoder::forward` : `d.sched ? stage_bigvgan_sched : stage_bigvgan`
|
||||
|
||||
1. `ggml_init(no_alloc=true)` avec mem_size réduit (metadata only)
|
||||
2. `ggml_set_input(input_tensor)` sur l'input host
|
||||
3. `ggml_set_output(output_tensor)` sur l'output final
|
||||
4. Remplacer `memset(zeros->data)` + `ggml_concat` par `ggml_pad_ext`
|
||||
5. Remplacer `precompute_snake` host (exp, 1/x) par ops in-graph
|
||||
`ggml_exp + ggml_div`
|
||||
6. Wrapping `sched_reset` + `sched_alloc_graph` +
|
||||
`ggml_backend_tensor_set(input)` + `sched_graph_compute` +
|
||||
`ggml_backend_tensor_get(output)`
|
||||
**MAIS** : mesure montre que TOUS les nœuds tombent sur CPU malgré le sched.
|
||||
Le sched_debug (`GGML_SCHED_DEBUG=2`) confirme :
|
||||
- poids decoder bien sur HTP0 (buf_w 325 MB + buf_const 0.1 MB)
|
||||
- MUL_MAT/IM2COL/PAD/ADD assignés à CPU
|
||||
- decoder time = 3.95s (régression vs baseline 3.34s due aux copies inutiles)
|
||||
|
||||
Snake `sin` n'est pas supporté HTP → sched fallback automatique vers CPU
|
||||
pour cette op. Le ping-pong est borné (snake = 0.4 Gops total sur 115).
|
||||
**Cause** : `ggml_hexagon_supported_mul_mat` rejette les MUL_MAT avec
|
||||
`ggml_nrows(src1) > 1024` (commentaire "no huge batches (for now)").
|
||||
|
||||
Estimation : ~70 lignes propres, ~1 session focalisée. Cibles : decoder
|
||||
3.2s → ~0.5-0.8s (gain ×4-6 réaliste avec HMX sur MUL_MAT).
|
||||
BigVGAN block 3 résiduels font conv1d k=7 sur T=59520 → im2col output a 59520
|
||||
rows × 672 cols → `ggml_nrows(src1) >> 1024`. Tous les MUL_MAT BigVGAN sont
|
||||
au-dessus de la limite, donc rejetés par HTP, fallback CPU.
|
||||
|
||||
## Reprise Phase 2b plus tard
|
||||
|
||||
Trois options pour débloquer :
|
||||
|
||||
**(a) Modifier ggml-hexagon** pour supporter les gros batches MUL_MAT.
|
||||
Sous-chantier kernel hexagon (VTCM tiling, copies multiples). Semaines.
|
||||
|
||||
**(b) Split BigVGAN MUL_MAT en chunks ≤ 1024 rows** côté graphe decoder.
|
||||
Refactor + copies CPU↔HTP par chunk. Gain incertain.
|
||||
|
||||
**(c) Reprendre via étape F (CP HMX)** d'abord. CP a des MUL_MAT
|
||||
nrows(src1) ≤ 16 (1 prefill 2 tokens + 14 decode 1 token), largement
|
||||
sous la limite. Pattern identique au talker Qwen3.5 déjà validé.
|
||||
|
||||
## Rebuild
|
||||
|
||||
|
|
|
|||
|
|
@ -514,6 +514,159 @@ static std::vector<float> stage_bigvgan(Decoder & d, const std::vector<float> &
|
|||
return wav;
|
||||
}
|
||||
|
||||
// ============== Variante sched (Phase 2b BigVGAN HMX) ==============
|
||||
// stage_bigvgan_sched : pattern sched-friendly pour activer le routage MUL_MAT
|
||||
// vers HTP HMX. Diffs avec stage_bigvgan :
|
||||
// - ggml_init no_alloc=true + mem_size réduit (~4 MB)
|
||||
// - ggml_set_input/output sur entrée/sortie
|
||||
// - causal_conv1d_TC : ggml_pad_ext au lieu de memset zeros + ggml_concat
|
||||
// - precompute_snake : lookup dans d.snake_consts (précalculé au load)
|
||||
// - exécution : sched_reset + sched_alloc_graph + tensor_set + sched_compute + tensor_get
|
||||
// Le sched split automatiquement : MUL_MAT/ADD/MUL/PAD -> HTP HMX,
|
||||
// IM2COL/SIN/CONV_TRANSPOSE_1D -> CPU. Copies CPU<->HTP gérées par sched.
|
||||
static std::vector<float> stage_bigvgan_sched(Decoder & d, const std::vector<float> & us_out, int T_in_us) {
|
||||
const int latent = d.cfg.latent_dim; // 1024
|
||||
const int decoder_dim = d.cfg.decoder_dim; // 1536
|
||||
const std::vector<int> & up_rates = d.cfg.upsample_rates;
|
||||
|
||||
// mem_size : juste métadonnées tensors (no_alloc=true). BigVGAN a ~30 snake + 26 conv1d
|
||||
// + 4 convtr + adds → ~1000 nœuds max. ~256 octets/nœud → ~256 KB ; on prend 16 MB safe.
|
||||
size_t mem_size = 16ULL * 1024 * 1024;
|
||||
struct ggml_init_params p = { mem_size, nullptr, /*no_alloc=*/true };
|
||||
struct ggml_context * ctx = ggml_init(p);
|
||||
|
||||
auto get = [&](const std::string & key) { return d.tensors[key]; };
|
||||
|
||||
auto apply_snake_TC = [&](ggml_tensor * x_TC, const std::string & prefix) -> ggml_tensor * {
|
||||
auto it = d.snake_consts.find(prefix);
|
||||
if (it == d.snake_consts.end()) {
|
||||
fprintf(stderr, "bigvgan_sched: snake const not found for %s\n", prefix.c_str());
|
||||
return x_TC;
|
||||
}
|
||||
ggml_tensor * a_eff = it->second.first; // [C], précalculé exp(α)
|
||||
ggml_tensor * inv_b = it->second.second; // [C], précalculé 1/(exp(β)+eps)
|
||||
const int C = (int)a_eff->ne[0];
|
||||
ggml_tensor * a2 = ggml_reshape_2d(ctx, a_eff, 1, C);
|
||||
ggml_tensor * b2 = ggml_reshape_2d(ctx, inv_b, 1, C);
|
||||
ggml_tensor * xa = ggml_mul(ctx, x_TC, a2);
|
||||
ggml_tensor * s = ggml_sin(ctx, xa); // SIN -> CPU fallback via sched
|
||||
ggml_tensor * s2 = ggml_mul(ctx, s, s);
|
||||
ggml_tensor * mod = ggml_mul(ctx, s2, b2);
|
||||
return ggml_add(ctx, x_TC, mod);
|
||||
};
|
||||
|
||||
auto causal_conv1d_TC = [&](ggml_tensor * x_TC, const std::string & w_key, const std::string & b_key,
|
||||
int K, int dilation) -> ggml_tensor * {
|
||||
ggml_tensor * w = get(w_key);
|
||||
ggml_tensor * b = get(b_key);
|
||||
const int C_out = (int)w->ne[2];
|
||||
const int T_cur = (int)x_TC->ne[0];
|
||||
ggml_tensor * x_pad;
|
||||
if (K == 1) {
|
||||
x_pad = x_TC;
|
||||
} else {
|
||||
const int pad_left = (K - 1) * dilation;
|
||||
// Pad gauche sur dim 0 (T) par pad_left zéros — équivalent à concat(zeros, x_TC)
|
||||
// mais en pur graphe (compatible no_alloc=true).
|
||||
x_pad = ggml_pad_ext(ctx, x_TC, pad_left, 0, 0, 0, 0, 0, 0, 0);
|
||||
}
|
||||
ggml_tensor * y = ggml_conv_1d(ctx, w, x_pad, 1, 0, dilation);
|
||||
const int T_out_y = (int)y->ne[0];
|
||||
if (T_out_y > T_cur) {
|
||||
y = ggml_view_2d(ctx, y, T_cur, C_out, y->nb[1], 0);
|
||||
}
|
||||
ggml_tensor * b2 = ggml_reshape_2d(ctx, b, 1, C_out);
|
||||
return ggml_add(ctx, y, b2);
|
||||
};
|
||||
|
||||
auto causal_convtr1d_TC = [&](ggml_tensor * x_TC, const std::string & w_key, const std::string & b_key,
|
||||
int s) -> ggml_tensor * {
|
||||
ggml_tensor * w = get(w_key);
|
||||
ggml_tensor * b = get(b_key);
|
||||
const int C_out = (int)w->ne[1];
|
||||
const int T_cur = (int)x_TC->ne[0];
|
||||
ggml_tensor * y = ggml_conv_transpose_1d(ctx, w, x_TC, s, 0, 1);
|
||||
const int T_full = (int)y->ne[0];
|
||||
const int T_target = T_cur * s;
|
||||
if (T_full > T_target) {
|
||||
y = ggml_view_2d(ctx, y, T_target, C_out, y->nb[1], 0);
|
||||
}
|
||||
ggml_tensor * b2 = ggml_reshape_2d(ctx, b, 1, C_out);
|
||||
return ggml_add(ctx, y, b2);
|
||||
};
|
||||
|
||||
// --- Input ---
|
||||
ggml_tensor * x = ggml_new_tensor_2d(ctx, GGML_TYPE_F32, latent, T_in_us);
|
||||
ggml_set_name(x, "bigvgan_input");
|
||||
ggml_set_input(x); // CRITIQUE : marque comme input pour sched_alloc_graph
|
||||
|
||||
// Switch to TC layout
|
||||
ggml_tensor * x_TC = ggml_cont(ctx, ggml_transpose(ctx, x));
|
||||
|
||||
// initial Conv k=7
|
||||
x_TC = causal_conv1d_TC(x_TC, "decoder.initial.weight", "decoder.initial.bias", 7, 1);
|
||||
|
||||
// 4 DecoderBlocks
|
||||
for (int B = 0; B < 4; B++) {
|
||||
char prefix[64]; snprintf(prefix, sizeof(prefix), "decoder.block.%d", B);
|
||||
const int up = up_rates[B];
|
||||
|
||||
x_TC = apply_snake_TC(x_TC, std::string(prefix) + ".block.0");
|
||||
x_TC = causal_convtr1d_TC(x_TC,
|
||||
std::string(prefix) + ".block.1.conv.weight",
|
||||
std::string(prefix) + ".block.1.conv.bias", up);
|
||||
|
||||
const int dilations[3] = {1, 3, 9};
|
||||
for (int R = 0; R < 3; R++) {
|
||||
char rprefix[80]; snprintf(rprefix, sizeof(rprefix), "%s.block.%d", prefix, 2 + R);
|
||||
ggml_tensor * res = x_TC;
|
||||
x_TC = apply_snake_TC(x_TC, std::string(rprefix) + ".act1");
|
||||
x_TC = causal_conv1d_TC(x_TC, std::string(rprefix) + ".conv1.conv.weight",
|
||||
std::string(rprefix) + ".conv1.conv.bias", 7, dilations[R]);
|
||||
x_TC = apply_snake_TC(x_TC, std::string(rprefix) + ".act2");
|
||||
x_TC = causal_conv1d_TC(x_TC, std::string(rprefix) + ".conv2.conv.weight",
|
||||
std::string(rprefix) + ".conv2.conv.bias", 1, 1);
|
||||
x_TC = ggml_add(ctx, res, x_TC);
|
||||
}
|
||||
}
|
||||
|
||||
// final SnakeBeta + Conv k=7
|
||||
x_TC = apply_snake_TC(x_TC, "decoder.final_act");
|
||||
x_TC = causal_conv1d_TC(x_TC, "decoder.final_conv.weight", "decoder.final_conv.bias", 7, 1);
|
||||
|
||||
ggml_set_name(x_TC, "bigvgan_output");
|
||||
ggml_set_output(x_TC);
|
||||
|
||||
struct ggml_cgraph * gf = ggml_new_graph_custom(ctx, 16384, false);
|
||||
ggml_build_forward_expand(gf, x_TC);
|
||||
|
||||
// --- Sched execution ---
|
||||
ggml_backend_sched_reset(d.sched);
|
||||
if (!ggml_backend_sched_alloc_graph(d.sched, gf)) {
|
||||
fprintf(stderr, "bigvgan_sched: sched_alloc_graph FAIL\n");
|
||||
ggml_free(ctx); return {};
|
||||
}
|
||||
// Set input data AFTER alloc (le tensor a maintenant un backend buffer)
|
||||
ggml_backend_tensor_set(x, us_out.data(), 0, (size_t)latent * T_in_us * sizeof(float));
|
||||
if (ggml_backend_sched_graph_compute(d.sched, gf) != GGML_STATUS_SUCCESS) {
|
||||
fprintf(stderr, "bigvgan_sched: sched_graph_compute FAIL\n");
|
||||
ggml_free(ctx); return {};
|
||||
}
|
||||
// Get output
|
||||
const int T_final = (int)x_TC->ne[0];
|
||||
std::vector<float> wav(T_final);
|
||||
ggml_backend_tensor_get(x_TC, wav.data(), 0, (size_t)T_final * sizeof(float));
|
||||
// Clamp [-1, 1]
|
||||
for (int t = 0; t < T_final; t++) {
|
||||
if (wav[t] > 1.0f) wav[t] = 1.0f;
|
||||
if (wav[t] < -1.0f) wav[t] = -1.0f;
|
||||
}
|
||||
|
||||
ggml_free(ctx);
|
||||
(void)decoder_dim;
|
||||
return wav;
|
||||
}
|
||||
|
||||
// ============== Forward complet : chaîne staging strict ==============
|
||||
|
||||
// Dump an array of floats to disk if env var DECODER_DEBUG_DUMP_DIR is set.
|
||||
|
|
@ -554,7 +707,11 @@ std::vector<float> Decoder::forward(const std::vector<int32_t>& codes_flat, int
|
|||
auto us_out = stage_upsample(*this, pt_out, T); // [1024, T*4]
|
||||
t4 = nows();
|
||||
debug_dump("stage4_upsample", us_out);
|
||||
auto wav = stage_bigvgan(*this, us_out, T * 4); // T*1920 samples
|
||||
// BigVGAN : si sched actif (KZTTS_DECODER_SCHED=1), variante sched-friendly
|
||||
// qui route les MUL_MAT sur HTP HMX. Sinon, path legacy CPU pur.
|
||||
std::vector<float> wav = sched
|
||||
? stage_bigvgan_sched(*this, us_out, T * 4)
|
||||
: stage_bigvgan (*this, us_out, T * 4);
|
||||
t5 = nows();
|
||||
debug_dump("stage5_wav", wav);
|
||||
|
||||
|
|
|
|||
|
|
@ -50,6 +50,15 @@ struct Decoder {
|
|||
struct ggml_backend_sched * sched = nullptr;
|
||||
bool owns_backends = false; // si true, unload() libère aussi backends[]
|
||||
|
||||
// Snake constants pré-calculées au load_with_backends pour rendre
|
||||
// stage_bigvgan sched-friendly. Sans ça, precompute_snake host-side ne
|
||||
// marche pas avec ctx no_alloc=true. Map clé "{prefix}.alpha" -> (a_eff, inv_b)
|
||||
// avec a_eff = exp(α), inv_b = 1 / (exp(β) + eps).
|
||||
// Alloués dans ctx_const + buf_const sur le même backend que buf_w.
|
||||
struct ggml_context * ctx_const = nullptr;
|
||||
struct ggml_backend_buffer * buf_const = nullptr;
|
||||
std::unordered_map<std::string, std::pair<struct ggml_tensor*, struct ggml_tensor*>> snake_consts;
|
||||
|
||||
// load() utilise le backend CPU par défaut. Pour Hexagon/Vulkan, passer
|
||||
// un buft explicite via load_with_buft(), OU une liste de backends via
|
||||
// load_with_backends() (recommandé pour HTP : crée le sched + buft auto).
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
#include "decoder.h"
|
||||
#include <ggml-backend.h>
|
||||
#include <ggml-cpu.h>
|
||||
#include <cmath>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
|
|
@ -123,6 +124,73 @@ bool Decoder::load_with_backends(const std::string & path,
|
|||
ggml_backend_buffer_type_t buft_w = ggml_backend_get_default_buffer_type(backends[0]);
|
||||
if (!load_with_buft(path, buft_w)) return false;
|
||||
|
||||
// --- Précalcul snake constants (Phase 2b) ---
|
||||
// Snake activation = x + sin²(α*x)/β. Le code historique faisait host-side
|
||||
// exp() à chaque frame dans precompute_snake (incompatible avec sched
|
||||
// no_alloc=true). On précalcule a_eff = exp(α), inv_b = 1/(exp(β)+eps) UNE FOIS
|
||||
// ici, stockés dans ctx_const + buf_const sur le même backend que buf_w.
|
||||
// Le forward stage_bigvgan les utilise comme des poids normaux.
|
||||
{
|
||||
const float SNAKE_EPS = 1e-9f;
|
||||
// 1. Recenser tous les (alpha_key, beta_key) en parcourant les tensors.
|
||||
struct SnakePair { std::string prefix; ggml_tensor * alpha; ggml_tensor * beta; };
|
||||
std::vector<SnakePair> pairs;
|
||||
for (auto & kv : tensors) {
|
||||
const std::string & name = kv.first;
|
||||
const std::string suf = ".alpha";
|
||||
if (name.size() > suf.size() && name.compare(name.size()-suf.size(), suf.size(), suf) == 0) {
|
||||
std::string prefix = name.substr(0, name.size() - suf.size());
|
||||
std::string beta_name = prefix + ".beta";
|
||||
auto bit = tensors.find(beta_name);
|
||||
if (bit != tensors.end()) {
|
||||
pairs.push_back({prefix, kv.second, bit->second});
|
||||
}
|
||||
}
|
||||
}
|
||||
// 2. Allouer ctx_const : 2 tensors par paire (a_eff, inv_b), tous f32 [C].
|
||||
size_t mem_meta = (2 * pairs.size() + 4) * ggml_tensor_overhead();
|
||||
ggml_init_params pc{mem_meta, nullptr, /*no_alloc=*/true};
|
||||
ctx_const = ggml_init(pc);
|
||||
std::vector<std::pair<ggml_tensor*, ggml_tensor*>> created;
|
||||
created.reserve(pairs.size());
|
||||
for (auto & p : pairs) {
|
||||
const int C = (int)p.alpha->ne[0];
|
||||
ggml_tensor * a_eff = ggml_new_tensor_1d(ctx_const, GGML_TYPE_F32, C);
|
||||
ggml_tensor * inv_b = ggml_new_tensor_1d(ctx_const, GGML_TYPE_F32, C);
|
||||
ggml_set_name(a_eff, (p.prefix + ".a_eff").c_str());
|
||||
ggml_set_name(inv_b, (p.prefix + ".inv_b").c_str());
|
||||
created.push_back({a_eff, inv_b});
|
||||
}
|
||||
// 3. Allouer buf_const sur le même backend que buf_w.
|
||||
buf_const = ggml_backend_alloc_ctx_tensors_from_buft(ctx_const, buft_w);
|
||||
if (!buf_const) {
|
||||
fprintf(stderr, "load_with_backends: snake buf_const alloc FAIL\n");
|
||||
return false;
|
||||
}
|
||||
ggml_backend_buffer_set_usage(buf_const, GGML_BACKEND_BUFFER_USAGE_WEIGHTS);
|
||||
// 4. Calculer host-side puis tensor_set.
|
||||
std::vector<float> tmp_a, tmp_b;
|
||||
for (size_t i = 0; i < pairs.size(); ++i) {
|
||||
const int C = (int)pairs[i].alpha->ne[0];
|
||||
// Lire α et β depuis leur backend buffer (opt_hostbuf=1 -> mappable CPU).
|
||||
tmp_a.resize(C); tmp_b.resize(C);
|
||||
ggml_backend_tensor_get(pairs[i].alpha, tmp_a.data(), 0, C * sizeof(float));
|
||||
ggml_backend_tensor_get(pairs[i].beta, tmp_b.data(), 0, C * sizeof(float));
|
||||
std::vector<float> a_eff(C), inv_b(C);
|
||||
for (int c = 0; c < C; ++c) {
|
||||
a_eff[c] = std::exp(tmp_a[c]);
|
||||
inv_b[c] = 1.0f / (std::exp(tmp_b[c]) + SNAKE_EPS);
|
||||
}
|
||||
ggml_backend_tensor_set(created[i].first, a_eff.data(), 0, C * sizeof(float));
|
||||
ggml_backend_tensor_set(created[i].second, inv_b.data(), 0, C * sizeof(float));
|
||||
snake_consts[pairs[i].prefix] = created[i];
|
||||
}
|
||||
fprintf(stderr, "Decoder: %zu snake constants pré-calculées (buf_const %.1f MB sur %s)\n",
|
||||
pairs.size(),
|
||||
ggml_backend_buffer_get_size(buf_const) / 1048576.0,
|
||||
ggml_backend_buffer_name(buf_const));
|
||||
}
|
||||
|
||||
// Mode minimal d'essai : KZTTS_DECODER_SCHED=1 active un vrai sched (refactor stages requis).
|
||||
// Par défaut : pas de sched, on profite juste de opt_hostbuf=1 (HTP buffer CPU-mappé)
|
||||
// pour que ggml_graph_compute_with_ctx CPU pur lise directement les poids HTP.
|
||||
|
|
@ -164,7 +232,10 @@ void Decoder::compute_graph(struct ggml_context * ctx, struct ggml_cgraph * gf,
|
|||
}
|
||||
|
||||
void Decoder::unload() {
|
||||
if (sched) { ggml_backend_sched_free(sched); sched = nullptr; }
|
||||
if (sched) { ggml_backend_sched_free(sched); sched = nullptr; }
|
||||
if (buf_const) { ggml_backend_buffer_free(buf_const); buf_const = nullptr; }
|
||||
if (ctx_const) { ggml_free(ctx_const); ctx_const = nullptr; }
|
||||
snake_consts.clear();
|
||||
if (buf_w) { ggml_backend_buffer_free(buf_w); buf_w = nullptr; }
|
||||
if (ctx_w) { ggml_free(ctx_w); ctx_w = nullptr; }
|
||||
if (ctx_g) { ggml_free(ctx_g); ctx_g = nullptr; }
|
||||
|
|
|
|||
Loading…
Reference in New Issue