mirror of
https://github.com/LostRuins/koboldcpp.git
synced 2026-09-19 09:15:18 +02:00
builds but crashes
This commit is contained in:
@@ -0,0 +1,164 @@
|
||||
#include "ttsargs.h"
|
||||
|
||||
std::string arg::help_text() {
|
||||
std::string htxt = full_name;
|
||||
if (abbreviation != "") {
|
||||
htxt += " (" + abbreviation + ")";
|
||||
}
|
||||
htxt += ":\n ";
|
||||
if (description != "") {
|
||||
htxt += description + "\n";
|
||||
} else {
|
||||
htxt += "is a " + (std::string)(required ? "required " : "optional ") + "parameter.\n";
|
||||
}
|
||||
return htxt;
|
||||
}
|
||||
|
||||
int string_arg::parse(int argc, const char ** argv) {
|
||||
required = false;
|
||||
value.assign(argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int int_arg::parse(int argc, const char ** argv) {
|
||||
if (required) {
|
||||
required = false;
|
||||
}
|
||||
int val = atoi(argv[0]);
|
||||
*value = val;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int float_arg::parse(int argc, const char ** argv) {
|
||||
if (required) {
|
||||
required = false;
|
||||
}
|
||||
float val = strtof(argv[0], nullptr);
|
||||
*value = val;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void arg_list::help() {
|
||||
std::string help_text = "";
|
||||
for (auto arg : fargs) {
|
||||
help_text += arg.help_text();
|
||||
}
|
||||
for (auto arg : iargs) {
|
||||
help_text += arg.help_text();
|
||||
|
||||
}
|
||||
for (auto arg : bargs) {
|
||||
help_text += arg.help_text();
|
||||
|
||||
}
|
||||
for (auto arg : sargs) {
|
||||
help_text += arg.help_text();
|
||||
|
||||
}
|
||||
fprintf(stdout, "%s", help_text.c_str());
|
||||
}
|
||||
|
||||
void arg_list::validate() {
|
||||
for (auto arg : fargs) {
|
||||
if (arg.required) {
|
||||
fprintf(stderr, "argument '%s' is required.\n", arg.full_name.c_str());
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
for (auto arg : iargs) {
|
||||
if (arg.required) {
|
||||
fprintf(stderr, "argument '%s' is required.\n", arg.full_name.c_str());
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
for (auto arg : bargs) {
|
||||
if (arg.required) {
|
||||
fprintf(stderr, "argument '%s' is required.\n", arg.full_name.c_str());
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
for (auto arg : sargs) {
|
||||
if (arg.required) {
|
||||
fprintf(stderr, "argument '%s' is required.\n", arg.full_name.c_str());
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void arg_list::parse(int argc, const char ** argv) {
|
||||
int current_arg = 1;
|
||||
while (current_arg < argc) {
|
||||
std::string name(argv[current_arg]);
|
||||
if (name == "--help") {
|
||||
for_help = true;
|
||||
return;
|
||||
}
|
||||
current_arg += 1;
|
||||
current_arg += find_and_parse(name, argc - current_arg, argv + current_arg);
|
||||
}
|
||||
}
|
||||
|
||||
int arg_list::find_and_parse(std::string name, int argc, const char ** argv) {
|
||||
for (int i = 0; i < fargs.size(); i++) {
|
||||
if (fargs[i].full_name == name || fargs[i].abbreviation == name) {
|
||||
return fargs[i].parse(argc, argv);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < iargs.size(); i++) {
|
||||
if (iargs[i].full_name == name || iargs[i].abbreviation == name) {
|
||||
return iargs[i].parse(argc, argv);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < bargs.size(); i++) {
|
||||
if (bargs[i].full_name == name || bargs[i].abbreviation == name) {
|
||||
bargs[i].value = !bargs[i].value;
|
||||
bargs[i].required = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
for (int i = 0; i < sargs.size(); i++) {
|
||||
if (sargs[i].full_name == name || sargs[i].abbreviation == name) {
|
||||
return sargs[i].parse(argc, argv);
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "argument '%s' is not a valid argument. Call '--help' for information on all valid arguments.\n", name.c_str());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
std::string arg_list::get_string_param(std::string full_name) {
|
||||
for (auto arg : sargs) {
|
||||
if (arg.full_name == full_name) {
|
||||
return arg.value;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
int * arg_list::get_int_param(std::string full_name) {
|
||||
for (auto arg : iargs) {
|
||||
if (arg.full_name == full_name) {
|
||||
return arg.value;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
float * arg_list::get_float_param(std::string full_name) {
|
||||
for (auto arg : fargs) {
|
||||
if (arg.full_name == full_name) {
|
||||
return arg.value;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool arg_list::get_bool_param(std::string full_name) {
|
||||
for (auto arg : bargs) {
|
||||
if (arg.full_name == full_name) {
|
||||
return arg.value;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,212 @@
|
||||
#include "dac_model.h"
|
||||
#include <algorithm>
|
||||
#include <stdexcept>
|
||||
|
||||
// For loading DAC model from gguf file.
|
||||
static const std::map<std::string, dac_tensor> DAC_TENSOR_GGUF_LOOKUP = {
|
||||
{"initial.bias", DAC_ENCODER_IN_BIAS},
|
||||
{"initial.weight", DAC_ENCODER_IN_KERNEL},
|
||||
{"final.bias", DAC_ENCODER_OUT_BIAS},
|
||||
{"final.weight", DAC_ENCODER_OUT_KERNEL},
|
||||
{"final.alpha", DAC_ENCODER_SNAKE_ALPHA},
|
||||
};
|
||||
|
||||
void dac_model::prep_constants(gguf_context * meta) {
|
||||
int output_heads_key = search_for_gguf_keys(meta, {"parler-tts.decoder.output_heads", "output_heads", "dia.decoder.output_heads"});
|
||||
if (output_heads_key != -1) {
|
||||
n_heads = gguf_get_val_u32(meta, output_heads_key);
|
||||
}
|
||||
|
||||
int sampling_factor_key = search_for_gguf_keys(meta, {"dac.up_sampling_factor", "up_sampling_factor"});
|
||||
if (sampling_factor_key != -1) {
|
||||
up_sampling_factor = gguf_get_val_u32(meta, sampling_factor_key);
|
||||
}
|
||||
|
||||
int max_gen_key = search_for_gguf_keys(meta, {"parler-tts.decoder.max_generation", "max_generation", "dia.decoder.max_generation"});
|
||||
if (max_gen_key != -1) {
|
||||
max_generation_size = gguf_get_val_u32(meta, max_gen_key);
|
||||
}
|
||||
}
|
||||
|
||||
void dac_model::prep_layers(gguf_context * meta) {
|
||||
for (int i = 0; i < n_heads; i++) {
|
||||
quantizer_layers.push_back(general_neural_audio_codec::residual_vector_quantize_layer{});
|
||||
}
|
||||
|
||||
for (int i = 0; i < n_layers; i++) {
|
||||
std::string stride_key = "dac_layer_stride_" + std::to_string(i);
|
||||
std::string padding_key = "dac_layer_padding_" + std::to_string(i);
|
||||
int layer_stride_key = search_for_gguf_keys(meta, {"dac." + stride_key, stride_key});
|
||||
if (layer_stride_key == -1) {
|
||||
TTS_ABORT("key %s must be specified in gguf file inorder to initialize the DAC audio decoder.", stride_key.c_str());
|
||||
}
|
||||
int layer_padding_key = search_for_gguf_keys(meta, {"dac." + padding_key, padding_key});
|
||||
if (layer_padding_key == -1) {
|
||||
TTS_ABORT("key %s must be specified in gguf file inorder to initialize the DAC audio decoder.", padding_key.c_str());
|
||||
}
|
||||
layers.push_back(
|
||||
general_neural_audio_codec::layer{
|
||||
gguf_get_val_u32(meta, layer_padding_key),
|
||||
gguf_get_val_u32(meta, layer_stride_key),
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void dac_model::assign_weight(std::string name, ggml_tensor * tensor) {
|
||||
assign_to_audio_encoder(this, name, tensor);
|
||||
}
|
||||
|
||||
void assign_to_audio_encoder(dac_model * model, std::string name, ggml_tensor * tensor) {
|
||||
if (DAC_TENSOR_GGUF_LOOKUP.find(name) != DAC_TENSOR_GGUF_LOOKUP.end()) {
|
||||
switch(DAC_TENSOR_GGUF_LOOKUP.at(name)) {
|
||||
case DAC_ENCODER_IN_BIAS:
|
||||
model->in_conv_bias = ggml_dup_tensor(model->ctx, ggml_transpose(model->ctx, tensor));
|
||||
model->set_tensor(model->in_conv_bias, tensor);
|
||||
break;
|
||||
case DAC_ENCODER_IN_KERNEL:
|
||||
model->in_conv_kernel = ggml_dup_tensor(model->ctx, tensor);
|
||||
model->set_tensor(model->in_conv_kernel, tensor);
|
||||
break;
|
||||
case DAC_ENCODER_OUT_BIAS:
|
||||
model->out_conv_bias = ggml_dup_tensor(model->ctx, ggml_transpose(model->ctx, tensor));
|
||||
model->set_tensor(model->out_conv_bias, tensor);
|
||||
break;
|
||||
case DAC_ENCODER_OUT_KERNEL:
|
||||
model->out_conv_kernel = ggml_dup_tensor(model->ctx, tensor);
|
||||
model->set_tensor(model->out_conv_kernel, tensor);
|
||||
break;
|
||||
case DAC_ENCODER_SNAKE_ALPHA:
|
||||
model->snake_alpha = ggml_dup_tensor(model->ctx, tensor);
|
||||
model->set_tensor(model->snake_alpha, tensor);
|
||||
break;
|
||||
default:
|
||||
fprintf(stdout, "unassigned tensor %s\n", name.c_str());
|
||||
break;
|
||||
}
|
||||
} else if (std::find_if(name.begin(), name.end(), ::isdigit) != name.end()) {
|
||||
auto pair = parse_layer_count(name);
|
||||
int l = pair.first;
|
||||
std::string lt_name = pair.second;
|
||||
if (name.find("quantizers") != std::string::npos) {
|
||||
general_neural_audio_codec::assign_to_quantize_layer((tts_model *) model, model->quantizer_layers[l], lt_name, tensor);
|
||||
} else {
|
||||
general_neural_audio_codec::assign_to_layer((tts_model *) model, model->layers[l - 1], lt_name, tensor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static struct ggml_tensor * dac_build_audio_inputs(struct ggml_context * ctx, struct dac_context * dctx, const dac_ubatch & batch, std::vector<general_neural_audio_codec::residual_vector_quantize_layer> layers) {
|
||||
struct ggml_tensor * embd;
|
||||
|
||||
dctx->inp_tokens = ggml_new_tensor_1d(ctx, GGML_TYPE_I32, batch.sequence_length*dctx->model->n_heads);
|
||||
ggml_set_input(dctx->inp_tokens);
|
||||
|
||||
if (dctx->backend) {
|
||||
ggml_backend_sched_set_tensor_backend(dctx->sched, dctx->inp_tokens, dctx->backend);
|
||||
}
|
||||
|
||||
for(int i = 0; i < dctx->model->n_heads; i++) {
|
||||
auto quantize_layer = dctx->model->quantizer_layers[i];
|
||||
struct ggml_tensor * code = ggml_cont(ctx, ggml_view_2d(ctx, dctx->inp_tokens, 1, batch.sequence_length, dctx->model->n_heads*ggml_type_size(GGML_TYPE_I32), i*ggml_type_size(GGML_TYPE_I32)));
|
||||
code = ggml_reshape_1d(ctx, code, batch.sequence_length);
|
||||
code = general_neural_audio_codec::build_quantize_layer(ctx, code, quantize_layer);
|
||||
|
||||
if (i == 0) {
|
||||
embd = code;
|
||||
} else {
|
||||
embd = ggml_add(ctx, embd, code);
|
||||
}
|
||||
}
|
||||
return embd;
|
||||
}
|
||||
|
||||
struct dac_context * build_new_dac_context(struct dac_model * model, int n_threads, bool use_cpu) {
|
||||
dac_context * dctx = new dac_context(model, n_threads);
|
||||
if (!use_cpu) {
|
||||
#ifdef GGML_USE_METAL
|
||||
dctx->backend = ggml_backend_metal_init();
|
||||
#endif
|
||||
}
|
||||
dctx->backend_cpu = ggml_backend_cpu_init();
|
||||
dctx->set_threads();
|
||||
dctx->build_schedule();
|
||||
dctx->buf_compute_meta.resize(ggml_tensor_overhead()*model->max_nodes() + ggml_graph_overhead_custom(model->max_nodes(), false));
|
||||
return dctx;
|
||||
}
|
||||
|
||||
void dac_runner::prepare_post_load() {
|
||||
dac_ubatch batch;
|
||||
batch.sequence_length = model->max_generation_size;
|
||||
ggml_cgraph * gf = build_dac_graph(batch);
|
||||
dctx->prep_schedule(gf);
|
||||
}
|
||||
|
||||
struct ggml_cgraph * dac_runner::build_dac_graph(dac_ubatch & batch) {
|
||||
init_build();
|
||||
// splitting this out from the primary graph so that we can better manage streaming (i.e. sentence chunks are better performed this way)
|
||||
struct ggml_cgraph * gf = ggml_new_graph_custom(ctx, 8192, false);
|
||||
|
||||
struct ggml_tensor * cur;
|
||||
struct ggml_tensor * inputs;
|
||||
|
||||
inputs = dac_build_audio_inputs(ctx, dctx, batch, model->quantizer_layers);
|
||||
ggml_set_name(inputs, "quanitzed_inputs");
|
||||
|
||||
// everything besides the inputs is just a forward pass
|
||||
cur = ggml_conv_1d_tts(ctx, model->in_conv_kernel, inputs, 1, 3, 1);
|
||||
cur = ggml_add(ctx, cur, model->in_conv_bias);
|
||||
for (auto l : model->layers) {
|
||||
cur = general_neural_audio_codec::build_layer(ctx, cur, l);
|
||||
}
|
||||
cur = snake_1d(ctx, model->snake_alpha, cur);
|
||||
cur = ggml_conv_1d_tts(ctx, model->out_conv_kernel, cur, 1, 3, 1);
|
||||
cur = ggml_add(ctx, cur, model->out_conv_bias);
|
||||
cur = ggml_tanh(ctx, cur);
|
||||
ggml_build_forward_expand(gf, cur);
|
||||
free_build();
|
||||
return gf;
|
||||
}
|
||||
|
||||
void dac_runner::run(uint32_t * input_tokens, uint32_t sequence_length, struct tts_response * outputs) {
|
||||
dac_ubatch batch;
|
||||
batch.input_tokens = input_tokens;
|
||||
batch.sequence_length = sequence_length;
|
||||
ggml_backend_sched_reset(dctx->sched);
|
||||
|
||||
const size_t prev_size = dctx->buf_output ? ggml_backend_buffer_get_size(dctx->buf_output) : 0;
|
||||
const size_t new_size = model->max_generation_size * model->up_sampling_factor * sizeof(float);
|
||||
|
||||
if (!dctx->buf_output || prev_size < new_size) {
|
||||
if (dctx->buf_output) {
|
||||
ggml_backend_buffer_free(dctx->buf_output);
|
||||
dctx->buf_output = nullptr;
|
||||
dctx->logits = nullptr;
|
||||
}
|
||||
|
||||
dctx->buf_output = ggml_backend_buft_alloc_buffer(dctx->backend_cpu_buffer, new_size);
|
||||
}
|
||||
|
||||
outputs->data = (float *) ggml_backend_buffer_get_base(dctx->buf_output);
|
||||
ggml_backend_buffer_clear(dctx->buf_output, 0);
|
||||
|
||||
struct ggml_cgraph * gf = NULL;
|
||||
gf = build_dac_graph(batch);
|
||||
|
||||
// the output is always the last tensor in the graph
|
||||
struct ggml_tensor * result = gf->nodes[gf->n_nodes - 1];
|
||||
ggml_backend_sched_alloc_graph(dctx->sched, gf);
|
||||
|
||||
ggml_backend_tensor_set(dctx->inp_tokens, batch.input_tokens, 0, batch.sequence_length*model->n_heads*ggml_element_size(dctx->inp_tokens));
|
||||
|
||||
ggml_backend_sched_graph_compute_async(dctx->sched, gf);
|
||||
|
||||
dctx->get_ggml_node_data(result, outputs->data, batch.sequence_length*sizeof(float)*model->up_sampling_factor);
|
||||
|
||||
// Reset state for the next token before backend sync, to allow the CPU activities in the reset to
|
||||
// overlap with device computation.
|
||||
ggml_backend_sched_reset(dctx->sched);
|
||||
outputs->n_outputs = sequence_length * model->up_sampling_factor;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
#ifndef dac_model_h
|
||||
#define dac_model_h
|
||||
|
||||
#include "general_neural_audio_codec.h"
|
||||
#include <map>
|
||||
|
||||
enum dac_tensor {
|
||||
DAC_ENCODER_IN_KERNEL,
|
||||
DAC_ENCODER_IN_BIAS,
|
||||
DAC_ENCODER_OUT_KERNEL,
|
||||
DAC_ENCODER_OUT_BIAS,
|
||||
DAC_ENCODER_SNAKE_ALPHA,
|
||||
};
|
||||
|
||||
struct dac_quantize_layer {
|
||||
struct ggml_tensor * out_proj_kernel;
|
||||
struct ggml_tensor * out_proj_bias;
|
||||
struct ggml_tensor * codebook;
|
||||
};
|
||||
|
||||
// DAC, Descript Audio Codec, is a channel token to audio autoencoder model (though we only use its decoder functionality).
|
||||
// this struct maintains the static tensors for the dac audio decoder graph.
|
||||
// As such, this is designed to contain basic configuration and ggml tensor support for DAC.
|
||||
// The dac_runner describes how the graph is built and run.
|
||||
struct dac_model : tts_model {
|
||||
// These configs are essentially built for the 44khZ 8kbps standard DAC model audio encoder and decoder
|
||||
uint32_t n_layers = 4;
|
||||
uint32_t n_heads = 9;
|
||||
uint32_t up_sampling_factor = 512;
|
||||
uint32_t max_generation_size = 2580;
|
||||
|
||||
struct ggml_tensor * in_conv_kernel;
|
||||
struct ggml_tensor * in_conv_bias;
|
||||
struct ggml_tensor * out_conv_kernel;
|
||||
struct ggml_tensor * out_conv_bias;
|
||||
struct ggml_tensor * snake_alpha;
|
||||
std::vector<general_neural_audio_codec::layer> layers;
|
||||
std::vector<general_neural_audio_codec::residual_vector_quantize_layer> quantizer_layers;
|
||||
|
||||
void assign_weight(std::string name, ggml_tensor * weight);
|
||||
void prep_constants(gguf_context * meta);
|
||||
void prep_layers(gguf_context * meta);
|
||||
void setup_from_file(gguf_context * meta_ctx, ggml_context * load_context, bool cpu_only) {
|
||||
prep_layers(meta_ctx);
|
||||
prep_constants(meta_ctx);
|
||||
tts_model::setup_from_file(meta_ctx, load_context, cpu_only, "audio_encoder");
|
||||
}
|
||||
};
|
||||
|
||||
// for loading DAC model from gguf file
|
||||
void assign_to_audio_encoder(dac_model * model, std::string name, ggml_tensor * tensor);
|
||||
|
||||
// the context used for running the dac model
|
||||
struct dac_context : runner_context {
|
||||
dac_context(dac_model * model, int n_threads): runner_context(n_threads), model(model) {};
|
||||
|
||||
struct dac_model * model;
|
||||
|
||||
struct ggml_tensor * inp_tokens;
|
||||
|
||||
void build_schedule() {
|
||||
runner_context::build_schedule(model->max_nodes());
|
||||
}
|
||||
};
|
||||
|
||||
struct dac_context * build_new_dac_context(struct dac_model * model, int n_threads, bool use_cpu = true);
|
||||
|
||||
struct dac_ubatch {
|
||||
uint32_t * input_tokens;
|
||||
uint32_t sequence_length;
|
||||
};
|
||||
|
||||
static struct ggml_tensor * dac_build_audio_inputs(struct ggml_context * ctx, struct dac_context * dctx, const dac_ubatch & batch, std::vector<general_neural_audio_codec::residual_vector_quantize_layer> layers);
|
||||
|
||||
// This struct is intended to manage the dac model's graph compilation and compute function.
|
||||
struct dac_runner : tts_runner {
|
||||
dac_runner(dac_model * model, dac_context * context): model(model), dctx(context) {};
|
||||
~dac_runner() {
|
||||
if (ctx) {
|
||||
ggml_free(ctx);
|
||||
}
|
||||
model->free();
|
||||
delete model;
|
||||
delete dctx;
|
||||
}
|
||||
dac_model * model;
|
||||
dac_context * dctx;
|
||||
|
||||
void init_build() {
|
||||
tts_runner::init_build(&dctx->buf_compute_meta);
|
||||
}
|
||||
|
||||
void prepare_post_load();
|
||||
struct ggml_cgraph * build_dac_graph(dac_ubatch & batch);
|
||||
void run(uint32_t * input_tokens, uint32_t sequence_length, struct tts_response * outputs);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,911 @@
|
||||
#include "dia_model.h"
|
||||
|
||||
void dia_model::assign_weight(std::string name, struct ggml_tensor * tensor) {
|
||||
std::vector<std::string> parts = split(name, ".");
|
||||
TTS_ASSERT(parts.size() >= 3);
|
||||
|
||||
if (parts[1] == "encoder") {
|
||||
assign_to_encoder(parts, tensor, name);
|
||||
} else if (parts[1] == "decoder"){
|
||||
assign_to_decoder(parts, tensor, name);
|
||||
} else {
|
||||
TTS_ABORT("Unrecognized tensor '%s' when loading Dia from GGUF file.", name.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void dia_model::assign_to_encoder(std::vector<std::string> parts, struct ggml_tensor * tensor, std::string name) {
|
||||
if (parts[2] == "embedding") {
|
||||
encoder->embedding = ggml_dup_tensor(ctx, tensor);
|
||||
set_tensor(encoder->embedding, tensor);
|
||||
} else if (parts[2] == "norm") {
|
||||
encoder->norm = ggml_dup_tensor(ctx, tensor);
|
||||
set_tensor(encoder->norm, tensor);
|
||||
} else if (parts[2] == "layers") {
|
||||
TTS_ASSERT(parts.size() >= 4);
|
||||
int index = std::stoi(parts[3]);
|
||||
TTS_ASSERT(index < decoder->layers.size());
|
||||
assign_to_encoder_layer(parts[4], encoder->layers[index], tensor);
|
||||
} else {
|
||||
TTS_ABORT("Unrecognized tensor '%s' when loading Dia from GGUF file.", name.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void dia_model::assign_to_decoder(std::vector<std::string> parts, struct ggml_tensor * tensor, std::string name) {
|
||||
if (parts[2] == "embeddings") {
|
||||
TTS_ASSERT(parts.size() > 2);
|
||||
int index = std::stoi(parts[3]);
|
||||
TTS_ASSERT(index < decoder->embds.size());
|
||||
decoder->embds[index] = ggml_dup_tensor(ctx, tensor);
|
||||
set_tensor(decoder->embds[index], tensor);
|
||||
} else if (parts[2] == "norm") {
|
||||
decoder->norm = ggml_dup_tensor(ctx, tensor);
|
||||
set_tensor(decoder->norm, tensor);
|
||||
} else if (parts[2] == "heads") {
|
||||
TTS_ASSERT(parts.size() > 2);
|
||||
int index = std::stoi(parts[3]);
|
||||
TTS_ASSERT(index < decoder->heads.size());
|
||||
decoder->heads[index] = ggml_dup_tensor(ctx, tensor);
|
||||
set_tensor(decoder->heads[index], tensor);
|
||||
} else if (parts[2] == "layers") {
|
||||
TTS_ASSERT(parts.size() >= 4);
|
||||
int index = std::stoi(parts[3]);
|
||||
TTS_ASSERT(index < decoder->layers.size());
|
||||
assign_to_decoder_layer(parts[4], decoder->layers[index], tensor);
|
||||
} else {
|
||||
TTS_ABORT("Unrecognized tensor '%s' when loading Dia from GGUF file.", name.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void dia_model::assign_to_encoder_layer(std::string part, dia_encoder_layer * layer, struct ggml_tensor * tensor) {
|
||||
if (part == "q_proj") {
|
||||
layer->q = ggml_dup_tensor(ctx, tensor);
|
||||
set_tensor(layer->q, tensor);
|
||||
} else if (part == "k_proj") {
|
||||
layer->k = ggml_dup_tensor(ctx, tensor);
|
||||
set_tensor(layer->k, tensor);
|
||||
} else if (part == "v_proj") {
|
||||
layer->v = ggml_dup_tensor(ctx, tensor);
|
||||
set_tensor(layer->v, tensor);
|
||||
} else if (part == "o_proj") {
|
||||
layer->o = ggml_dup_tensor(ctx, tensor);
|
||||
set_tensor(layer->o, tensor);
|
||||
} else if (part == "pre_sa_norm") {
|
||||
layer->self_attn_norm = ggml_dup_tensor(ctx, tensor);
|
||||
set_tensor(layer->self_attn_norm, tensor);
|
||||
} else if (part == "post_sa_norm") {
|
||||
layer->mlp_norm = ggml_dup_tensor(ctx, tensor);
|
||||
set_tensor(layer->mlp_norm, tensor);
|
||||
} else if (part == "gate") {
|
||||
layer->gate = ggml_dup_tensor(ctx, tensor);
|
||||
set_tensor(layer->gate, tensor);
|
||||
} else if (part == "up") {
|
||||
layer->up = ggml_dup_tensor(ctx, tensor);
|
||||
set_tensor(layer->up, tensor);
|
||||
} else if (part == "wo") {
|
||||
layer->out = ggml_dup_tensor(ctx, tensor);
|
||||
set_tensor(layer->out, tensor);
|
||||
} else {
|
||||
TTS_ABORT("Unrecognized tensor '%s' for encoder layer when loading Dia from GGUF file.", part.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void dia_model::assign_to_decoder_layer(std::string part, dia_decoder_layer * layer, struct ggml_tensor * tensor) {
|
||||
if (part == "self_q_proj") {
|
||||
layer->self_attn_q = ggml_dup_tensor(ctx, tensor);
|
||||
set_tensor(layer->self_attn_q, tensor);
|
||||
} else if (part == "self_k_proj") {
|
||||
layer->self_attn_k = ggml_dup_tensor(ctx, tensor);
|
||||
set_tensor(layer->self_attn_k, tensor);
|
||||
} else if (part == "self_v_proj") {
|
||||
layer->self_attn_v = ggml_dup_tensor(ctx, tensor);
|
||||
set_tensor(layer->self_attn_v, tensor);
|
||||
} else if (part == "self_o_proj") {
|
||||
layer->self_attn_o = ggml_dup_tensor(ctx, tensor);
|
||||
set_tensor(layer->self_attn_o, tensor);
|
||||
} else if (part == "cross_q_proj") {
|
||||
layer->cross_attn_q = ggml_dup_tensor(ctx, tensor);
|
||||
set_tensor(layer->cross_attn_q, tensor);
|
||||
} else if (part == "cross_k_proj") {
|
||||
layer->cross_attn_k = ggml_dup_tensor(ctx, tensor);
|
||||
set_tensor(layer->cross_attn_k, tensor);
|
||||
} else if (part == "cross_v_proj") {
|
||||
layer->cross_attn_v = ggml_dup_tensor(ctx, tensor);
|
||||
set_tensor(layer->cross_attn_v, tensor);
|
||||
} else if (part == "cross_o_proj") {
|
||||
layer->cross_attn_o = ggml_dup_tensor(ctx, tensor);
|
||||
set_tensor(layer->cross_attn_o, tensor);
|
||||
} else if (part == "pre_sa_norm") {
|
||||
layer->self_attn_norm = ggml_dup_tensor(ctx, tensor);
|
||||
set_tensor(layer->self_attn_norm, tensor);
|
||||
} else if (part == "pre_mlp_norm") {
|
||||
layer->mlp_norm = ggml_dup_tensor(ctx, tensor);
|
||||
set_tensor(layer->mlp_norm, tensor);
|
||||
} else if (part == "pre_ca_norm") {
|
||||
layer->cross_attn_norm = ggml_dup_tensor(ctx, tensor);
|
||||
set_tensor(layer->cross_attn_norm, tensor);
|
||||
} else if (part == "gate") {
|
||||
layer->gate = ggml_dup_tensor(ctx, tensor);
|
||||
set_tensor(layer->gate, tensor);
|
||||
} else if (part == "up") {
|
||||
layer->up = ggml_dup_tensor(ctx, tensor);
|
||||
set_tensor(layer->up, tensor);
|
||||
} else if (part == "wo") {
|
||||
layer->out = ggml_dup_tensor(ctx, tensor);
|
||||
set_tensor(layer->out, tensor);
|
||||
} else {
|
||||
TTS_ABORT("Unrecognized tensor '%s' for encoder layer when loading Dia from GGUF file.", part.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void dia_model::prep_layers() {
|
||||
encoder = new dia_encoder;
|
||||
decoder = new dia_decoder;
|
||||
encoder->layers.reserve((size_t) n_encoder_layers);
|
||||
for (int i = 0; i < (int) n_encoder_layers; i++) {
|
||||
dia_encoder_layer * l = new dia_encoder_layer;
|
||||
encoder->layers.push_back(l);
|
||||
}
|
||||
|
||||
decoder->layers.reserve((size_t) n_decoder_layers);
|
||||
for (int i = 0; i < (int) n_decoder_layers; i++) {
|
||||
dia_decoder_layer * l = new dia_decoder_layer;
|
||||
decoder->layers.push_back(l);
|
||||
}
|
||||
|
||||
decoder->embds.reserve((size_t) n_output_heads);
|
||||
decoder->heads.reserve((size_t) n_output_heads);
|
||||
for (int i = 0; i < n_output_heads; i++) {
|
||||
struct ggml_tensor * h = nullptr;
|
||||
struct ggml_tensor * embd = nullptr;
|
||||
decoder->embds.push_back(embd);
|
||||
decoder->heads.push_back(h);
|
||||
}
|
||||
}
|
||||
|
||||
void dia_model::prep_constants(gguf_context * meta) {
|
||||
int output_heads_key = gguf_find_key(meta, "dia.decoder.output_heads");
|
||||
if (output_heads_key != -1) {
|
||||
n_output_heads = gguf_get_val_u32(meta, output_heads_key);
|
||||
}
|
||||
|
||||
int decoder_layers_key = gguf_find_key(meta, "dia.decoder.layers");
|
||||
if (decoder_layers_key != -1) {
|
||||
n_decoder_layers = gguf_get_val_u32(meta, decoder_layers_key);
|
||||
}
|
||||
|
||||
int encoder_layers_key = gguf_find_key(meta, "dia.encoder.layers");
|
||||
if (encoder_layers_key != -1) {
|
||||
n_encoder_layers = gguf_get_val_u32(meta, encoder_layers_key);
|
||||
}
|
||||
|
||||
int decoder_hidden_size_key = gguf_find_key(meta, "dia.decoder.hidden_size");
|
||||
if (decoder_hidden_size_key != -1) {
|
||||
decoder_hidden_size = gguf_get_val_u32(meta, decoder_hidden_size_key);
|
||||
}
|
||||
|
||||
int decoder_attn_heads_key = gguf_find_key(meta, "dia.decoder.attn_heads");
|
||||
if (decoder_attn_heads_key != -1) {
|
||||
decoder_attn_heads = gguf_get_val_u32(meta, decoder_attn_heads_key);
|
||||
}
|
||||
|
||||
int decoder_query_heads_key = gguf_find_key(meta, "dia.decoder.query_heads");
|
||||
if (decoder_query_heads_key != -1) {
|
||||
decoder_query_heads = gguf_get_val_u32(meta, decoder_query_heads_key);
|
||||
}
|
||||
|
||||
int encoder_attn_heads_key = gguf_find_key(meta, "dia.encoder.attn_heads");
|
||||
if (encoder_attn_heads_key != -1) {
|
||||
encoder_attn_heads = gguf_get_val_u32(meta, encoder_attn_heads_key);
|
||||
}
|
||||
|
||||
int head_size_key = gguf_find_key(meta, "dia.attn_head_size");
|
||||
if (head_size_key != -1) {
|
||||
head_size = gguf_get_val_u32(meta, head_size_key);
|
||||
}
|
||||
|
||||
int eos_token_id_key = gguf_find_key(meta, "dia.eos_token_id");
|
||||
if (eos_token_id_key != -1) {
|
||||
eos_token_id = gguf_get_val_u32(meta, eos_token_id_key);
|
||||
}
|
||||
|
||||
int bos_token_id_key = gguf_find_key(meta, "dia.bos_token_id");
|
||||
if (bos_token_id_key != -1) {
|
||||
bos_token_id = gguf_get_val_u32(meta, bos_token_id_key);
|
||||
}
|
||||
|
||||
int pad_token_id_key = gguf_find_key(meta, "dia.pad_token_id");
|
||||
if (pad_token_id_key != -1) {
|
||||
pad_token_id = gguf_get_val_u32(meta, pad_token_id_key);
|
||||
}
|
||||
|
||||
int max_context_key = gguf_find_key(meta, "dia.encoder.max_context_length");
|
||||
if (max_context_key != -1) {
|
||||
max_encoder_context_length = gguf_get_val_u32(meta, max_context_key);
|
||||
}
|
||||
|
||||
int output_vocab_size_key = gguf_find_key(meta, "dia.decoder.output_vocab_size");
|
||||
if (output_vocab_size_key != -1) {
|
||||
output_vocab_size = gguf_get_val_u32(meta, output_vocab_size_key);
|
||||
}
|
||||
|
||||
int audio_vocab_size_key = gguf_find_key(meta, "dia.decoder.audio_vocab_size");
|
||||
if (audio_vocab_size_key != -1) {
|
||||
audio_vocab_size = gguf_get_val_u32(meta, audio_vocab_size_key);
|
||||
}
|
||||
|
||||
int max_generation_size_key = gguf_find_key(meta, "dia.decoder.max_generation_size");
|
||||
if (max_generation_size_key != -1) {
|
||||
max_generation_size = gguf_get_val_u32(meta, max_generation_size_key);
|
||||
}
|
||||
int max_delay_key = gguf_find_key(meta, "dia.max_delay");
|
||||
if (max_delay_key != -1) {
|
||||
max_delay = gguf_get_val_u32(meta, max_delay_key);
|
||||
}
|
||||
|
||||
// please note that this value is not currently set in the gguf encoder as it effectively only exists as a default
|
||||
// python parameter (rather than an attribute in the model config) for the python Dia model.
|
||||
int cfg_scale_key = gguf_find_key(meta, "dia.cfg_scale");
|
||||
if (cfg_scale_key != -1) {
|
||||
cfg_scale_data[0] = gguf_get_val_f32(meta, cfg_scale_key);
|
||||
}
|
||||
}
|
||||
|
||||
void dia_context::reset() {
|
||||
current_position = 0;
|
||||
prompt_size = 0;
|
||||
output_tokens.clear();
|
||||
delay_steps = -1;
|
||||
}
|
||||
|
||||
struct dia_context * build_new_dia_context(struct dia_model * model, int n_threads, bool use_cpu) {
|
||||
dia_context * dctx = new dia_context(model, n_threads);
|
||||
if (!use_cpu) {
|
||||
#ifdef GGML_USE_METAL
|
||||
dctx->backend = ggml_backend_metal_init();
|
||||
#endif
|
||||
}
|
||||
dctx->backend_cpu = ggml_backend_cpu_init();
|
||||
dctx->set_threads();
|
||||
dctx->build_schedule();
|
||||
dctx->buf_compute_meta.resize(ggml_tensor_overhead()*model->max_nodes() + ggml_graph_overhead_custom(model->max_nodes(), false));
|
||||
return dctx;
|
||||
}
|
||||
|
||||
static bool dia_kv_cache_init(struct dia_kv_cache * cache, dia_model * model, dia_context * dctx) {
|
||||
ggml_backend_buffer_type_t buft = nullptr;
|
||||
// this will only really support cpu or metal for the time being;
|
||||
if (dctx->backend != nullptr) {
|
||||
#ifdef GGML_USE_METAL
|
||||
buft = ggml_backend_metal_buffer_type();
|
||||
#endif
|
||||
} else {
|
||||
buft = ggml_backend_cpu_buffer_type();
|
||||
}
|
||||
|
||||
struct ggml_init_params params = {
|
||||
/*.mem_size =*/ (4u * model->n_decoder_layers + 1) * ggml_tensor_overhead(),
|
||||
/*.mem_buffer =*/ NULL,
|
||||
/*.no_alloc =*/ true,
|
||||
};
|
||||
ggml_context * ctx = ggml_init(params);
|
||||
if (!ctx) {
|
||||
return false;
|
||||
}
|
||||
cache->ctx = ctx;
|
||||
|
||||
cache->k_l.reserve(model->n_decoder_layers);
|
||||
cache->v_l.reserve(model->n_decoder_layers);
|
||||
cache->cross_k_l.reserve(model->n_decoder_layers);
|
||||
cache->cross_v_l.reserve(model->n_decoder_layers);
|
||||
|
||||
for (int i = 0; i < (int) model->n_decoder_layers; i++) {
|
||||
struct ggml_tensor * k = ggml_new_tensor_1d(cache->ctx, cache->tensor_type, model->head_size * model->decoder_attn_heads * model->max_generation_size * 2);
|
||||
struct ggml_tensor * v = ggml_new_tensor_1d(cache->ctx, cache->tensor_type, model->head_size * model->decoder_attn_heads * model->max_generation_size * 2);
|
||||
struct ggml_tensor * cross_k = ggml_new_tensor_1d(cache->ctx, cache->tensor_type, model->head_size * model->decoder_attn_heads * model->max_encoder_context_length * 2);
|
||||
struct ggml_tensor * cross_v = ggml_new_tensor_1d(cache->ctx, cache->tensor_type, model->head_size * model->decoder_attn_heads * model->max_encoder_context_length * 2);
|
||||
ggml_format_name(k, "cache_k_l%d", i);
|
||||
ggml_format_name(v, "cache_v_l%d", i);
|
||||
ggml_format_name(cross_k, "cache_cross_k_l%d", i);
|
||||
ggml_format_name(cross_v, "cache_cross_v_l%d", i);
|
||||
cache->k_l.push_back(k);
|
||||
cache->v_l.push_back(v);
|
||||
cache->cross_k_l.push_back(cross_k);
|
||||
cache->cross_v_l.push_back(cross_v);
|
||||
}
|
||||
|
||||
// allocate tensors and initialize the buffers to avoid NaNs in the padding
|
||||
ggml_backend_buffer_t buf = ggml_backend_alloc_ctx_tensors_from_buft(cache->ctx, buft);
|
||||
if (!buf) {
|
||||
return false;
|
||||
}
|
||||
ggml_backend_buffer_clear(buf, 0);
|
||||
cache->buf = buf;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static struct ggml_tensor * build_dia_decoder_inp_embd(struct ggml_context * ctx, dia_context *dctx, dia_decoder * decoder, dia_ubatch & batch, uint32_t n_output_heads) {
|
||||
struct ggml_tensor * input_embs;
|
||||
|
||||
dctx->audio_inp_tokens = ggml_new_tensor_1d(ctx, GGML_TYPE_I32, n_output_heads * 2);
|
||||
ggml_set_input(dctx->audio_inp_tokens);
|
||||
for (int i = 0; i < n_output_heads; i++) {
|
||||
struct ggml_tensor * view = ggml_view_1d(ctx, dctx->audio_inp_tokens, 2, i * ggml_element_size(dctx->audio_inp_tokens));
|
||||
view->nb[0] = n_output_heads * ggml_element_size(dctx->audio_inp_tokens);
|
||||
if (i == 0) {
|
||||
input_embs = ggml_get_rows(ctx, decoder->embds[i], view);
|
||||
} else {
|
||||
input_embs = ggml_add(ctx, ggml_get_rows(ctx, decoder->embds[i], view), input_embs);
|
||||
}
|
||||
}
|
||||
return input_embs;
|
||||
}
|
||||
|
||||
static struct ggml_tensor * dia_layer_norm(struct ggml_context * ctx, struct ggml_tensor * inputs, struct ggml_tensor * weight) {
|
||||
// dia always uses 1e-5 as the default eps
|
||||
float eps = 0.00001;
|
||||
inputs = ggml_rms_norm(ctx, inputs, eps);
|
||||
return ggml_mul(ctx, inputs, weight);
|
||||
}
|
||||
|
||||
static struct ggml_tensor * build_dia_encoder_attn_mask(ggml_context * ctx, struct dia_context * dctx, dia_model * model) {
|
||||
dctx->encode_attn_mask = ggml_new_tensor_2d(ctx, GGML_TYPE_F32, (int64_t) model->max_encoder_context_length, (int64_t) model->max_encoder_context_length);
|
||||
ggml_set_input(dctx->encode_attn_mask);
|
||||
|
||||
return dctx->encode_attn_mask;
|
||||
}
|
||||
|
||||
static struct ggml_tensor * build_dia_head_outputs(struct ggml_context * ctx, dia_model * model, struct ggml_tensor * cur) {
|
||||
// going to cat the heads together and then reshape them
|
||||
struct ggml_tensor * out;
|
||||
for (int i = 0; i < model->n_output_heads; i++) {
|
||||
if (i == 0) {
|
||||
out = ggml_mul_mat(ctx, model->decoder->heads[i], cur);
|
||||
} else {
|
||||
out = ggml_concat(ctx, out, ggml_mul_mat(ctx, model->decoder->heads[i], cur), 2);
|
||||
}
|
||||
}
|
||||
struct ggml_tensor * cond = ggml_cont(ctx, ggml_view_2d(ctx, out, out->ne[0], out->ne[2], out->nb[2], 0));
|
||||
struct ggml_tensor * uncond = ggml_cont(ctx, ggml_view_2d(ctx, out, out->ne[0], out->ne[2], out->nb[2], out->nb[1]));
|
||||
return ggml_map_custom2(ctx, cond, uncond, &cfg_scale, out->ne[0], &model->cfg_scale_data);
|
||||
}
|
||||
|
||||
static struct ggml_tensor * build_dia_encoder(ggml_context * ctx, dia_model * model, dia_context * dctx, dia_ubatch & batch) {
|
||||
dctx->inp_tokens = ggml_new_tensor_1d(ctx, GGML_TYPE_I32, model->max_encoder_context_length*2);
|
||||
ggml_set_input(dctx->inp_tokens);
|
||||
|
||||
dctx->encode_positions = ggml_new_tensor_1d(ctx, GGML_TYPE_I32, model->max_encoder_context_length);
|
||||
ggml_set_input(dctx->encode_positions);
|
||||
|
||||
struct ggml_tensor * attn_mask = build_dia_encoder_attn_mask(ctx, dctx, model);
|
||||
|
||||
struct ggml_tensor * cur = ggml_reshape_3d(ctx, ggml_get_rows(ctx, model->encoder->embedding, dctx->inp_tokens), model->encoder_hidden_size, model->max_encoder_context_length, 2);
|
||||
for (auto layer : model->encoder->layers) {
|
||||
struct ggml_tensor * residual = cur;
|
||||
|
||||
cur = dia_layer_norm(ctx, cur, layer->self_attn_norm);
|
||||
// self-attention
|
||||
{
|
||||
struct ggml_tensor * Qcur = ggml_mul_mat(ctx, layer->q, cur);
|
||||
struct ggml_tensor * Kcur = ggml_mul_mat(ctx, layer->k, cur);
|
||||
struct ggml_tensor * Vcur = ggml_mul_mat(ctx, layer->v, cur);
|
||||
|
||||
// Strangely Dia follows the neoX Rotary Positional Embeddings Protocol
|
||||
Qcur = ggml_rope(ctx, ggml_cont(ctx, ggml_reshape_4d(ctx, Qcur, model->head_size, model->encoder_attn_heads, model->max_encoder_context_length, 2)), dctx->encode_positions, model->head_size, 2);
|
||||
Kcur = ggml_rope(ctx, ggml_cont(ctx, ggml_reshape_4d(ctx, Kcur, model->head_size, model->encoder_attn_heads, model->max_encoder_context_length, 2)), dctx->encode_positions, model->head_size, 2);
|
||||
struct ggml_tensor * q = ggml_cont(ctx, ggml_permute(ctx, Qcur, 0, 2, 1, 3));
|
||||
struct ggml_tensor * k = ggml_cont(ctx, ggml_permute(ctx, Kcur, 0, 2, 1, 3));
|
||||
struct ggml_tensor * kq = ggml_mul_mat(ctx, k, q);
|
||||
kq = ggml_soft_max_ext(ctx, kq, attn_mask, 1.0f, 0.0f);
|
||||
struct ggml_tensor * v = ggml_cont_4d(ctx, ggml_transpose(ctx, Vcur), model->max_encoder_context_length, model->head_size, model->encoder_attn_heads, 2);
|
||||
struct ggml_tensor * kqv = ggml_mul_mat(ctx, kq, v);
|
||||
struct ggml_tensor * kqv_merged = ggml_permute(ctx, kqv, 2, 0, 1, 3);
|
||||
|
||||
// It is unclear why the attention ops in Dia's encoder don't project to the embedding dimension size as is standard. Instead they up project to the decoder's embedding dimension
|
||||
// then down project back the the encoder embedding dimension.
|
||||
cur = ggml_cont_3d(ctx, kqv_merged, model->decoder_hidden_size, model->max_encoder_context_length, 2);
|
||||
cur = ggml_mul_mat(ctx, layer->o, cur);
|
||||
}
|
||||
|
||||
cur = ggml_add(ctx, cur, residual);
|
||||
struct ggml_tensor * residual_mlp = cur;
|
||||
|
||||
cur = dia_layer_norm(ctx, cur, layer->mlp_norm);
|
||||
// mlp
|
||||
{
|
||||
cur = ggml_mul(ctx, ggml_silu(ctx, ggml_mul_mat(ctx, layer->gate, cur)), ggml_mul_mat(ctx, layer->up, cur));
|
||||
cur = ggml_mul_mat(ctx, layer->out, cur);
|
||||
}
|
||||
|
||||
cur = ggml_add(ctx, cur, residual_mlp);
|
||||
}
|
||||
|
||||
cur = dia_layer_norm(ctx, cur, model->encoder->norm);
|
||||
return cur;
|
||||
}
|
||||
|
||||
static struct ggml_tensor * repeat_interleave_dim1(ggml_context * ctx, struct ggml_tensor * a, int repeat) {
|
||||
//return ggml_repeat(ctx, a, ggml_new_tensor_4d(ctx, GGML_TYPE_F32, a->ne[0], 4*a->ne[1], a->ne[2], a->ne[3]));
|
||||
struct ggml_tensor * running;
|
||||
for (int i = 0; i < a->ne[1]; i++) {
|
||||
int offset = i * a->nb[1];
|
||||
struct ggml_tensor * t = ggml_cont(ctx, ggml_view_4d(ctx, a, a->ne[0], 1, a->ne[2], a->ne[3], a->nb[1], a->nb[2], a->nb[3], offset));
|
||||
t = ggml_repeat(ctx, t, ggml_new_tensor_4d(ctx, GGML_TYPE_F32, a->ne[0], repeat, a->ne[2], a->ne[3]));
|
||||
if (i == 0) {
|
||||
running = t;
|
||||
} else {
|
||||
running = ggml_concat(ctx, running, t, 1);
|
||||
}
|
||||
}
|
||||
return running;
|
||||
}
|
||||
|
||||
static void build_dia_self_kv_store(ggml_context * ctx, dia_context * dctx, dia_model * model, dia_kv_cache * kv, ggml_cgraph * gf, struct ggml_tensor * k, struct ggml_tensor * v, dia_ubatch & batch, int layer_index) {
|
||||
int64_t attn_size = model->head_size * model->decoder_attn_heads;
|
||||
|
||||
struct ggml_tensor * k_cache_view =
|
||||
ggml_view_2d(
|
||||
ctx, kv->k_l[layer_index], attn_size, 2,
|
||||
attn_size * model->max_generation_size * ggml_element_size(kv->k_l[layer_index]),
|
||||
attn_size*dctx->current_position*ggml_element_size(kv->k_l[layer_index]));
|
||||
|
||||
k = ggml_rope(ctx, ggml_cont(ctx, ggml_reshape_4d(ctx, k, model->head_size, model->decoder_attn_heads / model->decoder_query_heads, batch.sequence_length, 2)), dctx->positions, model->head_size, 2);
|
||||
// Since the sequence length should always be 1 here this is the most pertinent time to repeat the heads for grouped query attention.
|
||||
// If GGML supported a repeat_interleave op then it would be more optimal to store just the groups in the cache and interleave the attention heads after recalling
|
||||
// from the cache
|
||||
k = repeat_interleave_dim1(ctx, ggml_cont(ctx, ggml_reshape_4d(ctx, k, model->head_size, model->decoder_attn_heads / model->decoder_query_heads, batch.sequence_length, 2)), model->decoder_query_heads);
|
||||
k = ggml_cont(ctx, ggml_reshape_2d(ctx, k, attn_size, 2));
|
||||
|
||||
ggml_build_forward_expand(gf, ggml_cpy(ctx, k, k_cache_view));
|
||||
|
||||
struct ggml_tensor * v_cache_view = nullptr;
|
||||
|
||||
v_cache_view = ggml_view_2d(
|
||||
ctx, kv->v_l[layer_index], attn_size, 2,
|
||||
attn_size * model->max_generation_size * ggml_element_size(kv->v_l[layer_index]),
|
||||
attn_size*dctx->current_position*ggml_element_size(kv->v_l[layer_index]));
|
||||
|
||||
// Since the sequence length should always be 1 here this is the most pertinent time to repeat the heads for grouped query attention.
|
||||
// If GGML supported a repeat_interleave op then it would be more optimal to store just the groups in the cache and interleave the attention heads after recalling
|
||||
// from the cache
|
||||
v = repeat_interleave_dim1(ctx, ggml_cont(ctx, ggml_reshape_4d(ctx, v, model->head_size, model->decoder_attn_heads / model->decoder_query_heads, batch.sequence_length, 2)), model->decoder_query_heads);
|
||||
|
||||
ggml_build_forward_expand(gf, ggml_cpy(ctx, v, v_cache_view));
|
||||
}
|
||||
|
||||
static void build_dia_cross_kv_store(ggml_context * ctx, dia_context * dctx, dia_model * model, dia_kv_cache * kv, ggml_cgraph * gf, struct ggml_tensor * encoder_hidden_states, int layer_index) {
|
||||
dia_decoder_layer * layer = model->decoder->layers[layer_index];
|
||||
struct ggml_tensor * encoder_states_key_view = ggml_cont(ctx, ggml_view_3d(
|
||||
ctx,
|
||||
encoder_hidden_states,
|
||||
model->encoder_hidden_size,
|
||||
dctx->prompt_size,
|
||||
2,
|
||||
model->encoder_hidden_size * ggml_element_size(encoder_hidden_states), model->encoder_hidden_size * model->max_encoder_context_length * ggml_element_size(encoder_hidden_states), 0));
|
||||
|
||||
struct ggml_tensor * k = ggml_mul_mat(ctx, layer->cross_attn_k, encoder_states_key_view);
|
||||
struct ggml_tensor * positions_view = ggml_view_1d(ctx, dctx->encode_positions, dctx->prompt_size, 0);
|
||||
|
||||
k = ggml_rope(ctx, ggml_cont(ctx, ggml_reshape_4d(ctx, k, model->head_size, model->decoder_attn_heads, dctx->prompt_size, 2)), positions_view, model->head_size, 2);
|
||||
k = ggml_cont(ctx, ggml_permute(ctx, k, 0, 1, 3, 2));
|
||||
|
||||
struct ggml_tensor * k_cache_view =
|
||||
ggml_view_4d(
|
||||
ctx, kv->cross_k_l[layer_index], model->head_size, model->decoder_attn_heads, 2, dctx->prompt_size,
|
||||
model->head_size*ggml_element_size(kv->cross_k_l[layer_index]),
|
||||
model->head_size*model->decoder_attn_heads*ggml_element_size(kv->cross_k_l[layer_index]),
|
||||
model->head_size*model->decoder_attn_heads*2*ggml_element_size(kv->cross_k_l[layer_index]),
|
||||
0);
|
||||
|
||||
ggml_build_forward_expand(gf, ggml_cpy(ctx, k, k_cache_view));
|
||||
|
||||
struct ggml_tensor * v = ggml_cont(ctx, ggml_transpose(ctx, ggml_mul_mat(ctx, layer->cross_attn_v, encoder_hidden_states)));
|
||||
v = ggml_cont_4d(ctx, v, model->max_encoder_context_length, model->head_size, model->decoder_attn_heads, 2);
|
||||
|
||||
struct ggml_tensor * v_cache_view =
|
||||
ggml_view_4d(
|
||||
ctx, kv->cross_v_l[layer_index], model->max_encoder_context_length, model->head_size, model->decoder_attn_heads, 2,
|
||||
model->max_encoder_context_length*ggml_element_size(kv->cross_v_l[layer_index]),
|
||||
model->head_size*model->max_encoder_context_length*ggml_element_size(kv->cross_v_l[layer_index]),
|
||||
model->head_size*model->max_encoder_context_length*model->decoder_attn_heads*ggml_element_size(kv->cross_v_l[layer_index]),
|
||||
0);
|
||||
|
||||
ggml_build_forward_expand(gf, ggml_cpy(ctx, v, v_cache_view));
|
||||
}
|
||||
|
||||
static struct ggml_tensor * build_dia_decoder(
|
||||
ggml_cgraph * gf,
|
||||
ggml_context * ctx,
|
||||
dia_model * model,
|
||||
dia_context * dctx,
|
||||
dia_kv_cache * cache,
|
||||
dia_ubatch & batch,
|
||||
struct ggml_tensor * encoder_hidden_states) {
|
||||
dctx->positions = ggml_new_tensor_1d(ctx, GGML_TYPE_I32, batch.sequence_length);
|
||||
ggml_set_input(dctx->positions);
|
||||
struct ggml_tensor * cur = build_dia_decoder_inp_embd(ctx, dctx, model->decoder, batch, model->n_output_heads);
|
||||
|
||||
for (int l = 0; l < model->decoder->layers.size(); l++){
|
||||
dia_decoder_layer * layer = model->decoder->layers[l];
|
||||
struct ggml_tensor * residual = cur;
|
||||
|
||||
cur = dia_layer_norm(ctx, cur, layer->self_attn_norm);
|
||||
// self-attention
|
||||
{
|
||||
struct ggml_tensor * Qcur = ggml_mul_mat(ctx, layer->self_attn_q, cur);
|
||||
struct ggml_tensor * Kcur = ggml_mul_mat(ctx, layer->self_attn_k, cur);
|
||||
struct ggml_tensor * Vcur = ggml_mul_mat(ctx, layer->self_attn_v, cur);
|
||||
|
||||
build_dia_self_kv_store(ctx, dctx, model, cache, gf, Kcur, Vcur, batch, l);
|
||||
struct ggml_tensor * k =
|
||||
ggml_view_4d(ctx, cache->k_l[l],
|
||||
model->head_size, model->decoder_attn_heads, dctx->current_position + 1, 2,
|
||||
ggml_element_size(cache->k_l[l]) * model->head_size,
|
||||
ggml_element_size(cache->k_l[l]) * model->decoder_attn_heads * model->head_size,
|
||||
ggml_element_size(cache->k_l[l]) * model->decoder_attn_heads * model->head_size * model->max_generation_size,
|
||||
0);
|
||||
k = ggml_cont(ctx, ggml_permute(ctx, k, 0, 2, 1, 3));
|
||||
|
||||
struct ggml_tensor * v =
|
||||
ggml_view_3d(ctx, cache->v_l[l],
|
||||
model->head_size * model->decoder_attn_heads, dctx->current_position + 1, 2,
|
||||
ggml_element_size(cache->v_l[l]) * model->decoder_attn_heads * model->head_size,
|
||||
ggml_element_size(cache->v_l[l]) * model->decoder_attn_heads * model->head_size * model->max_generation_size,
|
||||
0);
|
||||
v = ggml_cont_4d(ctx, ggml_transpose(ctx, v), dctx->current_position + 1, model->head_size, model->decoder_attn_heads, 2);
|
||||
|
||||
// As noted in the encoder Dia uses the Neo-X protocol for RoPE.
|
||||
Qcur = ggml_rope(ctx, ggml_cont(ctx, ggml_reshape_4d(ctx, Qcur, model->head_size, model->decoder_attn_heads, batch.sequence_length, 2)), dctx->positions, model->head_size, 2);
|
||||
struct ggml_tensor * q = ggml_cont(ctx, ggml_permute(ctx, Qcur, 0, 2, 1, 3));
|
||||
struct ggml_tensor * kq = ggml_mul_mat(ctx, ggml_cont(ctx, k), q);
|
||||
|
||||
// given that attention bias, scaling and masking are not used for decoding, it might be faster to prefer the #ggml_soft_max op here,
|
||||
kq = ggml_soft_max_ext(ctx, kq, nullptr, 1.0f, 0.0f);
|
||||
struct ggml_tensor * kqv = ggml_mul_mat(ctx, kq, v);
|
||||
struct ggml_tensor * kqv_merged = ggml_cont(ctx, ggml_permute(ctx, kqv, 2, 0, 1, 3));
|
||||
cur = ggml_cont_3d(ctx, kqv_merged, model->decoder_hidden_size, batch.sequence_length, 2);
|
||||
cur = ggml_mul_mat(ctx, layer->self_attn_o, cur);
|
||||
}
|
||||
|
||||
|
||||
// if we ever need to support multiple step decoder runs then this reshape will need to be replaced with permutation.
|
||||
cur = ggml_cont_2d(ctx, cur, cur->ne[0], 2);
|
||||
cur = ggml_add(ctx, cur, residual);
|
||||
struct ggml_tensor * residual_cross = cur;
|
||||
|
||||
cur = dia_layer_norm(ctx, cur, layer->cross_attn_norm);
|
||||
// cross-attention
|
||||
{
|
||||
struct ggml_tensor * cross_Qcur = ggml_mul_mat(ctx, layer->cross_attn_q, cur);
|
||||
|
||||
// only load the cross attention kv store when performing the encoding step
|
||||
if (batch.encoder_step) {
|
||||
build_dia_cross_kv_store(ctx, dctx, model, cache, gf, encoder_hidden_states, l);
|
||||
}
|
||||
|
||||
struct ggml_tensor * cross_k =
|
||||
ggml_view_4d(
|
||||
ctx, cache->cross_k_l[l], model->head_size, model->decoder_attn_heads, 2,
|
||||
model->max_encoder_context_length, model->head_size*ggml_element_size(cache->cross_k_l[l]),
|
||||
model->head_size*model->decoder_attn_heads*ggml_element_size(cache->cross_k_l[l]),
|
||||
model->head_size*model->decoder_attn_heads*2*ggml_element_size(cache->cross_k_l[l]),
|
||||
0);
|
||||
// the double permute operation shouldn't be necessary here, but it seems that currently ggml permute only currently alows for a single
|
||||
// axis pair to be transposed.
|
||||
cross_k = ggml_cont(ctx, ggml_permute(ctx, ggml_permute(ctx, cross_k, 0, 1, 3, 2), 0, 2, 1, 3));
|
||||
|
||||
struct ggml_tensor * cross_v =
|
||||
ggml_cont(ctx, ggml_view_4d(
|
||||
ctx, cache->cross_v_l[l], model->max_encoder_context_length, model->head_size, model->decoder_attn_heads, 2,
|
||||
model->max_encoder_context_length*ggml_element_size(cache->cross_v_l[l]),
|
||||
model->head_size*model->max_encoder_context_length*ggml_element_size(cache->cross_v_l[l]),
|
||||
model->head_size*model->max_encoder_context_length*model->decoder_attn_heads*ggml_element_size(cache->cross_v_l[l]),
|
||||
0));
|
||||
|
||||
// As noted in the encoder Dia uses the Neo-X protocol for RoPE.
|
||||
cross_Qcur = ggml_rope(ctx, ggml_cont(ctx, ggml_reshape_4d(ctx, cross_Qcur, model->head_size, model->decoder_attn_heads, batch.sequence_length, 2)), dctx->positions, model->head_size, 2);
|
||||
struct ggml_tensor * cross_q = ggml_cont(ctx, ggml_permute(ctx, cross_Qcur, 0, 2, 1, 3));
|
||||
struct ggml_tensor * cross_kq = ggml_mul_mat(ctx, cross_k, cross_q);
|
||||
|
||||
// given that attention bias, scaling and masking are not used for decoding, it might be faster to prefer the #ggml_soft_max op here,
|
||||
cross_kq = ggml_soft_max_ext(ctx, cross_kq, nullptr, 1.0f, 0.0f);
|
||||
struct ggml_tensor * cross_kqv = ggml_mul_mat(ctx, cross_kq, cross_v);
|
||||
struct ggml_tensor * cross_kqv_merged = ggml_cont(ctx, ggml_permute(ctx, cross_kqv, 2, 0, 1, 3));
|
||||
cur = ggml_cont_3d(ctx, cross_kqv_merged, model->decoder_hidden_size, batch.sequence_length, 2);
|
||||
cur = ggml_mul_mat(ctx, layer->cross_attn_o, cur);
|
||||
}
|
||||
|
||||
|
||||
// if we ever need to support multiple step decoder runs then this reshape will need to be replaced with permutation.
|
||||
cur = ggml_cont_2d(ctx, cur, cur->ne[0], 2);
|
||||
cur = ggml_add(ctx, cur, residual_cross);
|
||||
struct ggml_tensor * residual_mlp = cur;
|
||||
|
||||
cur = dia_layer_norm(ctx, cur, layer->mlp_norm);
|
||||
// mlp
|
||||
{
|
||||
cur = ggml_mul(ctx, ggml_silu(ctx, ggml_mul_mat(ctx, layer->gate, cur)), ggml_mul_mat(ctx, layer->up, cur));
|
||||
cur = ggml_mul_mat(ctx, layer->out, cur);
|
||||
}
|
||||
|
||||
cur = ggml_add(ctx, cur, residual_mlp);
|
||||
}
|
||||
|
||||
cur = dia_layer_norm(ctx, cur, model->decoder->norm);
|
||||
cur = build_dia_head_outputs(ctx, model, cur);
|
||||
return cur;
|
||||
}
|
||||
|
||||
void dia_runner::tokenize_sentence(std::string sentence, dia_ubatch & batch) {
|
||||
// Dia's tokenization process is unusual. Essentially Dia takes the byte value for each character and uses that as
|
||||
// a token array. Additionally, because Dia performs a cfg-scale adjustment before sampling tokens, it is necessary to
|
||||
// generate with a conditioned context (i.e. with the text) and an unconditioned context (i.e. without any text) so that
|
||||
// proper adjustments can be perfored at each generation step. This means that we need to pad the end of our tokens to the
|
||||
// max context size for both the conditional and unconditional sequence.
|
||||
|
||||
// if the sentence isn't prepended by dialogue start tokens, [S1] or [S2], then append one.
|
||||
sentence = strip(sentence);
|
||||
std::string start = sentence.substr(0, 4);
|
||||
if (start != "[S1]" && start != "[S2]") {
|
||||
sentence = "[S1] " + sentence;
|
||||
}
|
||||
if (sentence[sentence.size() - 1] != '.') {
|
||||
sentence += ".";
|
||||
}
|
||||
|
||||
// [S1] and [S2] are special character sequences that are replaced with the special tokens 0x01 and 0x02 respectively.
|
||||
std::string r1(1, 1);
|
||||
std::string r2(1, 2);
|
||||
while (sentence.find("[S1]") != std::string::npos) {
|
||||
size_t pos = sentence.find("[S1]");
|
||||
sentence.replace(pos, 4, r1);
|
||||
}
|
||||
while (sentence.find("[S2]") != std::string::npos) {
|
||||
size_t pos = sentence.find("[S2]");
|
||||
sentence.replace(pos, 4, r2);
|
||||
}
|
||||
|
||||
if (sentence.size() > model->max_encoder_context_length) {
|
||||
TTS_ABORT("Dia currently only supports a max of %d characters and received an input of %d characters.", model->max_encoder_context_length, sentence.size());
|
||||
}
|
||||
batch.tokens.reserve(model->max_encoder_context_length * 2);
|
||||
for (auto character : sentence) {
|
||||
batch.tokens.push_back((uint32_t) character);
|
||||
}
|
||||
batch.sentence_length = batch.tokens.size();
|
||||
// this 100 token warning is arbitrarily chosen based on spot checking small prompt performance
|
||||
if (batch.sentence_length <= 100) {
|
||||
fprintf(stdout, "Your prompt has fewer than 100 tokens. Please note that Dia's generation with prompts that are fewer than 100 tokens is highly inconsistent.\n");
|
||||
}
|
||||
|
||||
for (int i = (int) batch.tokens.size(); i < model->max_encoder_context_length * 2; i++) {
|
||||
batch.tokens.push_back(0u);
|
||||
}
|
||||
}
|
||||
|
||||
dia_ubatch dia_runner::batch_from_sentence(std::string sentence) {
|
||||
// if we are generating a new batch from tokens then we need to run the encoder step;
|
||||
struct dia_ubatch batch{ 1, true};
|
||||
tokenize_sentence(sentence, batch);
|
||||
batch.audio_tokens.reserve(model->n_output_heads);
|
||||
for (int i = 0; i < model->n_output_heads; i++) {
|
||||
batch.audio_tokens.push_back(model->bos_token_id);
|
||||
}
|
||||
return batch;
|
||||
}
|
||||
|
||||
/*
|
||||
* There are two unique features of Dia's model architecture:
|
||||
* 1. Dia cleans its output generation by adding the difference between its text based output (its conditional output) and its unconditional output
|
||||
* to the conditional ouput before sampling. This is why the batch is set to two throughout the graph.
|
||||
*
|
||||
* 2. Dia's decoder attends across the entire encoded space including the pad buffer which receives a unique attention mask. This is why the
|
||||
* encoder sequence is always max length.
|
||||
*/
|
||||
struct ggml_cgraph * dia_runner::build_dia_graph(dia_ubatch & batch) {
|
||||
init_build();
|
||||
struct ggml_cgraph * gf = ggml_new_graph_custom(ctx, 8192, false);
|
||||
struct ggml_tensor * encoded_states = nullptr;
|
||||
|
||||
if (batch.encoder_step) {
|
||||
encoded_states = build_dia_encoder(ctx, model, dctx, batch);
|
||||
ggml_build_forward_expand(gf, encoded_states);
|
||||
}
|
||||
|
||||
struct ggml_tensor * cur = build_dia_decoder(gf, ctx, model, dctx, kv_cross_self, batch, encoded_states);
|
||||
ggml_set_name(cur, "decoder_output");
|
||||
ggml_build_forward_expand(gf, cur);
|
||||
free_build();
|
||||
|
||||
return gf;
|
||||
}
|
||||
|
||||
void dia_runner::configure_generation(generation_configuration * config) {
|
||||
GGML_ASSERT(config->max_tokens == 0 || config->max_tokens > model->max_delay);
|
||||
decode_sampler->temperature = config->temperature;
|
||||
decode_sampler->repetition_penalty = config->repetition_penalty;
|
||||
decode_sampler->do_sample = config->sample;
|
||||
decode_sampler->top_k = config->top_k;
|
||||
decode_sampler->top_p = config->top_p;
|
||||
dctx->max_generation_size = config->max_tokens > model->max_delay ? config->max_tokens : model->max_generation_size;
|
||||
}
|
||||
|
||||
void dia_runner::set_inputs(dia_ubatch & batch) {
|
||||
if (batch.encoder_step) {
|
||||
ggml_backend_tensor_set(dctx->inp_tokens, batch.tokens.data(), 0, batch.tokens.size()*ggml_element_size(dctx->inp_tokens));
|
||||
int32_t * ep = (int32_t*) dctx->encode_positions->data;
|
||||
float * mask = (float*) dctx->encode_attn_mask->data;
|
||||
for (int i = 0; i < model->max_encoder_context_length; i++) {
|
||||
ep[i] = (int32_t) i;
|
||||
for (int ii = 0; ii < model->max_encoder_context_length; ii++) {
|
||||
if (i < batch.sentence_length) {
|
||||
mask[i*model->max_encoder_context_length + ii] = ii < batch.sentence_length ? 0.0 : -INFINITY;
|
||||
} else {
|
||||
mask[i*model->max_encoder_context_length + ii] = ii >= batch.sentence_length ? 0.0 : -INFINITY;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// The audio tokens need to be repeated in the input in order to support cfg-scaling. I.E we need duplicate inputs for conditional and unconditional logits.
|
||||
ggml_backend_tensor_set(dctx->audio_inp_tokens, batch.audio_tokens.data(), 0, batch.audio_tokens.size()*ggml_element_size(dctx->audio_inp_tokens));
|
||||
ggml_backend_tensor_set(dctx->audio_inp_tokens, batch.audio_tokens.data(), batch.audio_tokens.size()*ggml_element_size(dctx->audio_inp_tokens), batch.audio_tokens.size()*ggml_element_size(dctx->audio_inp_tokens));
|
||||
((int32_t*) dctx->positions->data)[0] = dctx->current_position;
|
||||
}
|
||||
|
||||
int dia_runner::decode(dia_ubatch & batch) {
|
||||
if (batch.encoder_step) {
|
||||
dctx->prompt_size = batch.sentence_length;
|
||||
dctx->output_tokens.reserve(dctx->max_generation_size * model->n_output_heads);
|
||||
}
|
||||
ggml_backend_sched_reset(dctx->sched);
|
||||
|
||||
const size_t logits_size = model->output_vocab_size * dctx->max_generation_size * model->n_output_heads;
|
||||
const size_t prev_size = dctx->buf_output ? ggml_backend_buffer_get_size(dctx->buf_output) : 0;
|
||||
const size_t new_size = logits_size * sizeof(float);
|
||||
|
||||
if (!dctx->buf_output || prev_size < new_size) {
|
||||
if (dctx->buf_output) {
|
||||
ggml_backend_buffer_free(dctx->buf_output);
|
||||
dctx->buf_output = nullptr;
|
||||
dctx->logits = nullptr;
|
||||
}
|
||||
|
||||
dctx->buf_output = ggml_backend_buft_alloc_buffer(dctx->backend_cpu_buffer, new_size);
|
||||
}
|
||||
|
||||
dctx->logits = (float *) ggml_backend_buffer_get_base(dctx->buf_output);
|
||||
|
||||
ggml_cgraph * gf = build_dia_graph(batch);
|
||||
|
||||
// the output is always the last tensor in the graph
|
||||
struct ggml_tensor * res = gf->nodes[gf->n_nodes - 1];
|
||||
std::string resname = ggml_get_name(res);
|
||||
ggml_backend_sched_alloc_graph(dctx->sched, gf);
|
||||
|
||||
set_inputs(batch);
|
||||
|
||||
ggml_backend_sched_graph_compute_async(dctx->sched, gf);
|
||||
|
||||
float * logits_out = dctx->logits + dctx->current_position * model->output_vocab_size * model->n_output_heads;
|
||||
dctx->get_ggml_node_data(res, logits_out, model->output_vocab_size * model->n_output_heads * sizeof(float));
|
||||
|
||||
// Reset state for the next token before backend sync, to allow the CPU activities in the reset to
|
||||
// overlap with device computation.
|
||||
ggml_backend_sched_reset(dctx->sched);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
dia_ubatch dia_runner::build_worst_case_batch() {
|
||||
struct dia_ubatch batch{ 1, true };
|
||||
batch.tokens.resize(model->max_encoder_context_length * 2);
|
||||
batch.audio_tokens.resize(model->n_output_heads);
|
||||
return batch;
|
||||
}
|
||||
|
||||
void dia_runner::prepare_post_load() {
|
||||
dac_runner->prepare_post_load();
|
||||
dia_kv_cache_init(kv_cross_self, model, dctx);
|
||||
auto batch = build_worst_case_batch();
|
||||
batch.sentence_length = model->max_encoder_context_length;
|
||||
dctx->prompt_size = model->max_encoder_context_length;
|
||||
auto gf = build_dia_graph(batch);
|
||||
dctx->prep_schedule(gf);
|
||||
}
|
||||
|
||||
bool dia_runner::check_stopping(dia_ubatch & batch) {
|
||||
if (dctx->delay_steps == -1 && (batch.audio_tokens[0] == model->eos_token_id || dctx->current_position >= dctx->max_generation_size - model->max_delay)) {
|
||||
dctx->delay_steps = model->max_delay;
|
||||
}
|
||||
|
||||
if (dctx->delay_steps > 0) {
|
||||
int step_after_eos = model->max_delay - dctx->delay_steps;
|
||||
for (int i = 0; i < model->delay_pattern.size(); i++) {
|
||||
if (step_after_eos == model->delay_pattern[i]) {
|
||||
batch.audio_tokens[i] = model->eos_token_id;
|
||||
} else if (step_after_eos > model->delay_pattern[i]) {
|
||||
batch.audio_tokens[i] = model->pad_token_id;
|
||||
}
|
||||
}
|
||||
dctx->delay_steps -= 1;
|
||||
}
|
||||
return dctx->delay_steps == 0;
|
||||
}
|
||||
|
||||
void dia_runner::adjust_output_tokens(std::vector<uint32_t> & output_tokens, std::vector<uint32_t> & filtered) {
|
||||
// currently this is applying sliding window over the heads and filtering out bad tokens.
|
||||
// If we convert the DAC model's quantizer layers to support by row + column embeddings then we will need to transpose
|
||||
// the heads and the sequence here, but right now simplying using a strided view is more peformant.
|
||||
size_t size = output_tokens.size();
|
||||
filtered.reserve(size);
|
||||
for (int i = 0; i < (size / model->n_output_heads) - model->max_delay; i++) {
|
||||
bool skip_step = false;
|
||||
for (int ii = 0; ii < model->n_output_heads; ii++) {
|
||||
int next_index = i*model->n_output_heads+model->delay_pattern[ii]*model->n_output_heads+ii;
|
||||
if (next_index > size || output_tokens[next_index] >= model->audio_vocab_size) {
|
||||
skip_step = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!skip_step) {
|
||||
for (int ii = 0; ii < model->n_output_heads; ii++) {
|
||||
int next_index = i*model->n_output_heads+model->delay_pattern[ii]*model->n_output_heads+ii;
|
||||
filtered.push_back(output_tokens[next_index]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int dia_runner::generate_from_batch(dia_ubatch & batch, struct tts_response * output) {
|
||||
while (!check_stopping(batch)) {
|
||||
int state = decode(batch);
|
||||
if (state != 0) {
|
||||
return state;
|
||||
}
|
||||
decode_sampler->sample(dctx->logits + dctx->current_position * model->n_output_heads * model->output_vocab_size, dctx->output_tokens);
|
||||
dctx->current_position += batch.sequence_length;
|
||||
batch = dia_ubatch{ 1 };
|
||||
uint32_t * last_outputs = (dctx->output_tokens.data() + (int) dctx->output_tokens.size() - model->n_output_heads);
|
||||
batch.audio_tokens.reserve(model->n_output_heads);
|
||||
for (int i = 0; i < model->n_output_heads; i++) {
|
||||
batch.audio_tokens.push_back(dctx->current_position > i ? last_outputs[i] : model->bos_token_id);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<uint32_t> filtered_output_tokens;
|
||||
adjust_output_tokens(dctx->output_tokens, filtered_output_tokens);
|
||||
|
||||
dac_runner->run(filtered_output_tokens.data(), (int32_t) filtered_output_tokens.size() / model->n_output_heads, output);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dia_runner::generate(std::string sentence, struct tts_response * output) {
|
||||
dia_ubatch batch = batch_from_sentence(sentence);
|
||||
dctx->reset();
|
||||
decode_sampler->reset();
|
||||
dctx->current_position = 0;
|
||||
if (!kv_cross_self) {
|
||||
kv_cross_self = new dia_kv_cache;
|
||||
if (!dia_kv_cache_init(kv_cross_self, model, dctx)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return generate_from_batch(batch, output);
|
||||
}
|
||||
|
||||
void dia_runner::assign_weight(std::string name, ggml_tensor * tensor) {
|
||||
if (tensor->data == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (name.size() == 0) {
|
||||
// handles the top level meta tensor
|
||||
return;
|
||||
}
|
||||
|
||||
if (name.size() > 14 && name.substr(0, 14) == "audio_encoder.") {
|
||||
dac_runner->model->assign_weight(name.substr(14), tensor);
|
||||
} else {
|
||||
model->assign_weight(name, tensor);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,206 @@
|
||||
#pragma once
|
||||
|
||||
#include "dac_model.h"
|
||||
#include "sampler.h"
|
||||
|
||||
struct dia_encoder_layer {
|
||||
struct ggml_tensor * k;
|
||||
struct ggml_tensor * q;
|
||||
struct ggml_tensor * v;
|
||||
struct ggml_tensor * o;
|
||||
struct ggml_tensor * self_attn_norm;
|
||||
|
||||
struct ggml_tensor * gate;
|
||||
struct ggml_tensor * up;
|
||||
struct ggml_tensor * out;
|
||||
struct ggml_tensor * mlp_norm;
|
||||
};
|
||||
|
||||
struct dia_decoder_layer {
|
||||
struct ggml_tensor * self_attn_k;
|
||||
struct ggml_tensor * self_attn_q;
|
||||
struct ggml_tensor * self_attn_v;
|
||||
struct ggml_tensor * self_attn_o;
|
||||
struct ggml_tensor * self_attn_norm;
|
||||
|
||||
struct ggml_tensor * cross_attn_k;
|
||||
struct ggml_tensor * cross_attn_q;
|
||||
struct ggml_tensor * cross_attn_v;
|
||||
struct ggml_tensor * cross_attn_o;
|
||||
struct ggml_tensor * cross_attn_norm;
|
||||
|
||||
struct ggml_tensor * gate;
|
||||
struct ggml_tensor * up;
|
||||
struct ggml_tensor * out;
|
||||
struct ggml_tensor * mlp_norm;
|
||||
|
||||
struct ggml_tensor * pad_attn_values;
|
||||
};
|
||||
|
||||
struct dia_encoder {
|
||||
struct ggml_tensor * norm;
|
||||
struct ggml_tensor * embedding;
|
||||
std::vector<dia_encoder_layer*> layers;
|
||||
};
|
||||
|
||||
struct dia_decoder {
|
||||
struct ggml_tensor * norm;
|
||||
std::vector<struct ggml_tensor*> embds;
|
||||
std::vector<struct ggml_tensor*> heads;
|
||||
std::vector<dia_decoder_layer*> layers;
|
||||
};
|
||||
|
||||
struct dia_model : tts_model {
|
||||
// These default configurations are based on the default configuration for the Dia 1.68b param model.
|
||||
uint32_t n_output_heads = 9;
|
||||
uint32_t n_encoder_layers = 12;
|
||||
uint32_t n_decoder_layers = 18;
|
||||
uint32_t encoder_hidden_size = 1024;
|
||||
uint32_t decoder_hidden_size = 2048;
|
||||
uint32_t encoder_attn_heads = 16;
|
||||
uint32_t decoder_attn_heads = 16;
|
||||
uint32_t decoder_query_heads = 4;
|
||||
uint32_t head_size = 128;
|
||||
uint32_t eos_token_id = 1024;
|
||||
uint32_t pad_token_id = 1025;
|
||||
uint32_t bos_token_id = 1026;
|
||||
uint32_t output_vocab_size = 1028;
|
||||
uint32_t audio_vocab_size = 1024;
|
||||
uint32_t max_generation_size = 3072;
|
||||
uint32_t max_encoder_context_length = 1024;
|
||||
|
||||
|
||||
float cfg_scale_data[2] = {3.0, 1024.0};
|
||||
uint32_t max_delay = 15;
|
||||
std::vector<uint32_t> delay_pattern = {0, 8, 9, 10, 11, 12, 13, 14, 15};
|
||||
|
||||
dia_encoder * encoder;
|
||||
dia_decoder * decoder;
|
||||
|
||||
void assign_weight(std::string name, ggml_tensor * tensor);
|
||||
void assign_to_encoder(std::vector<std::string> parts, struct ggml_tensor * tensor, std::string name);
|
||||
void assign_to_decoder(std::vector<std::string> parts, struct ggml_tensor * tensor, std::string name);
|
||||
void assign_to_encoder_layer(std::string part, dia_encoder_layer * layer, struct ggml_tensor * tensor);
|
||||
void assign_to_decoder_layer(std::string part, dia_decoder_layer * layer, struct ggml_tensor * tensor);
|
||||
void prep_constants(gguf_context * meta);
|
||||
void prep_layers();
|
||||
void setup_from_file(gguf_context * meta_ctx, ggml_context * load_context, bool cpu_only) {
|
||||
prep_constants(meta_ctx);
|
||||
prep_layers();
|
||||
tts_model::setup_from_file(meta_ctx, load_context, cpu_only, "dia", 1.30);
|
||||
}
|
||||
};
|
||||
|
||||
struct dia_context : runner_context {
|
||||
dia_context(dia_model * model, int n_threads): runner_context(n_threads), model(model) {
|
||||
max_generation_size = model->max_generation_size;
|
||||
};
|
||||
|
||||
uint32_t current_position = 0; // current position in the active sequence
|
||||
int delay_steps = -1; // the max remaining steps to take before terminating; is set after an eos token is seen on the first output channel
|
||||
size_t prompt_size = 0;
|
||||
|
||||
uint32_t max_generation_size; // this is set by the generation context or defaults to the config set on dia model.
|
||||
|
||||
std::vector<uint32_t> output_tokens;
|
||||
struct dia_model * model;
|
||||
|
||||
struct ggml_tensor * inp_tokens;
|
||||
struct ggml_tensor * audio_inp_tokens;
|
||||
struct ggml_tensor * positions;
|
||||
struct ggml_tensor * encode_positions;
|
||||
struct ggml_tensor * encode_attn_mask;
|
||||
struct ggml_tensor * cross_attn_mask;
|
||||
|
||||
void build_schedule() {
|
||||
runner_context::build_schedule(model->max_nodes());
|
||||
}
|
||||
void reset();
|
||||
};
|
||||
|
||||
struct dia_kv_cache {
|
||||
ggml_type tensor_type = GGML_TYPE_F32;
|
||||
|
||||
std::vector<struct ggml_tensor *> cross_k_l;
|
||||
std::vector<struct ggml_tensor *> cross_v_l;
|
||||
|
||||
std::vector<struct ggml_tensor *> k_l;
|
||||
std::vector<struct ggml_tensor *> v_l;
|
||||
|
||||
struct ggml_context * ctx;
|
||||
ggml_backend_buffer_type_t buft;
|
||||
ggml_backend_buffer_t buf;
|
||||
|
||||
void free() {
|
||||
ggml_free(ctx);
|
||||
ggml_backend_buffer_free(buf);
|
||||
}
|
||||
|
||||
~dia_kv_cache() {
|
||||
free();
|
||||
}
|
||||
};
|
||||
|
||||
struct dia_ubatch {
|
||||
dia_ubatch(size_t sequence_length, bool encoder_step = false): sequence_length(sequence_length), encoder_step(encoder_step) {};
|
||||
bool encoder_step; // whether we are performing the prompt encoding in this step.
|
||||
size_t sequence_length; // for just audio tokens the sequence length should be the total_tokens / num_heads; for normal generation this should always be 1.
|
||||
size_t sentence_length; // the number of non padded tokens in the conditional context
|
||||
std::vector<uint32_t> tokens; // character tokens for the encoder
|
||||
std::vector<uint32_t> audio_tokens; // audio tokens from the last generation
|
||||
};
|
||||
|
||||
struct dia_context * build_new_dia_context(struct dia_model * model, int n_threads, bool use_cpu = true);
|
||||
static bool dia_kv_cache_init(struct dia_kv_cache * cache, dia_model * model, dia_context * dctx) ;
|
||||
static struct ggml_tensor * build_dia_decoder_inp_embd(struct ggml_context * ctx, dia_context *dctx, dia_decoder * decoder, dia_ubatch & batch, uint32_t n_output_heads);
|
||||
static struct ggml_tensor * dia_layer_norm(struct ggml_context * ctx, struct ggml_tensor * inputs, struct ggml_tensor * weight);
|
||||
static struct ggml_tensor * build_dia_encoder_attn_mask(ggml_context * ctx, struct dia_context * dctx, dia_model * model);
|
||||
static struct ggml_tensor * build_dia_decoder_attn_mask(ggml_context * ctx, struct dia_context * dctx, dia_ubatch & batch);
|
||||
static struct ggml_tensor * build_dia_decoder_cross_attn_mask(ggml_context * ctx, struct dia_context * dctx, dia_ubatch & batch);
|
||||
static struct ggml_tensor * build_dia_head_outputs(struct ggml_context * ctx, dia_model * model, struct ggml_tensor * cur);
|
||||
static struct ggml_tensor * build_dia_encoder(ggml_context * ctx, dia_model * model, dia_context * dctx, dia_ubatch & batch);
|
||||
static void build_dia_self_kv_store(ggml_context * ctx, dia_context * dctx, dia_model * model, dia_kv_cache * kv, ggml_cgraph * gf, struct ggml_tensor * k, struct ggml_tensor * v, dia_ubatch & batch, int layer_index);
|
||||
static void build_dia_cross_kv_store(ggml_context * ctx, dia_context * dctx, dia_model * model, dia_kv_cache * kv, ggml_cgraph * gf, struct ggml_tensor * encoder_hidden_states, int layer_index);
|
||||
static struct ggml_tensor * build_dia_decoder( ggml_cgraph * gf, ggml_context * ctx, dia_model * model, dia_context * dctx, dia_kv_cache * cache, dia_ubatch & batch, struct ggml_tensor * encoder_hidden_states);
|
||||
|
||||
// This struct is intended to support end-to-end TTS generation for the Dia model. As such, it manages Dia's model compilation, compute, generation,
|
||||
// tokenizationm and sampling process, and uses the dac_runner struct to encode audio outputs.
|
||||
struct dia_runner : tts_runner {
|
||||
dia_runner(dia_model * model, dac_runner * audio_decoder, dia_context * dctx, sampler * samp, dia_kv_cache * cache): model(model), dac_runner(audio_decoder), dctx(dctx), decode_sampler(samp), kv_cross_self(cache) {
|
||||
decode_sampler->vocab_size = model->output_vocab_size;
|
||||
};
|
||||
~dia_runner() {
|
||||
if (ctx) {
|
||||
ggml_free(ctx);
|
||||
}
|
||||
model->free();
|
||||
delete model;
|
||||
delete kv_cross_self;
|
||||
delete dac_runner;
|
||||
delete dctx;
|
||||
delete decode_sampler;
|
||||
}
|
||||
struct dia_model * model;
|
||||
struct dac_runner * dac_runner;
|
||||
struct dia_context * dctx;
|
||||
struct dia_kv_cache * kv_cross_self = nullptr;
|
||||
struct sampler * decode_sampler;
|
||||
|
||||
void init_build() {
|
||||
tts_runner::init_build(&dctx->buf_compute_meta);
|
||||
}
|
||||
|
||||
void tokenize_sentence(std::string sentence, dia_ubatch & tokens);
|
||||
dia_ubatch batch_from_sentence(std::string sentence);
|
||||
void configure_generation(generation_configuration * config);
|
||||
void assign_weight(std::string name, ggml_tensor * tensor);
|
||||
dia_ubatch build_worst_case_batch();
|
||||
struct ggml_cgraph * build_dia_graph(dia_ubatch & batch);
|
||||
void set_inputs(dia_ubatch & batch);
|
||||
int decode(dia_ubatch & batch);
|
||||
void prepare_post_load();
|
||||
int generate(std::string sentence, struct tts_response * response);
|
||||
bool check_stopping(dia_ubatch & batch);
|
||||
void adjust_output_tokens(std::vector<uint32_t> & output_tokens, std::vector<uint32_t> & filtered);
|
||||
int generate_from_batch(dia_ubatch & batch, struct tts_response * output);
|
||||
};
|
||||
@@ -0,0 +1,172 @@
|
||||
#include "general_neural_audio_codec.h"
|
||||
#include <algorithm>
|
||||
#include <stdexcept>
|
||||
#include <map>
|
||||
|
||||
namespace general_neural_audio_codec {
|
||||
// This contains a mapping between string names and gguf_tensor enum values for the purposes of assigning the weights from a gguf file
|
||||
// to the general_neural_audio_codec::layer.
|
||||
// Please note that some gguf_tensor values have multiple keys; this is to support backwards compatibility with original DAC settings.
|
||||
static const std::map<std::string, gguf_tensor> GENERAL_NEURAL_AUDIO_CODEC_TENSOR_LOOKUP = {
|
||||
{".final.alpha", LAYER_ALPHA},
|
||||
{".final.bias", LAYER_INPUT_BIAS},
|
||||
{".final.weight", LAYER_INPUT_KERNEL},
|
||||
{".alpha", LAYER_ALPHA},
|
||||
{".bias", LAYER_INPUT_BIAS},
|
||||
{".weight", LAYER_INPUT_KERNEL},
|
||||
{".noise_weight", LAYER_NOISE_KERNEL},
|
||||
{".res.initial.alpha", RESIDUAL_UNIT_INPUT_ALPHA},
|
||||
{".res.initial.bias", RESIDUAL_UNIT_INPUT_BIAS},
|
||||
{".res.initial.weight", RESIDUAL_UNIT_INPUT_KERNEL},
|
||||
{".res.final.alpha", RESIDUAL_UNIT_OUTPUT_ALPHA},
|
||||
{".res.final.bias", RESIDUAL_UNIT_OUTPUT_BIAS},
|
||||
{".res.final.weight", RESIDUAL_UNIT_OUTPUT_KERNEL},
|
||||
{".in_alpha", RESIDUAL_UNIT_INPUT_ALPHA},
|
||||
{".in_bias", RESIDUAL_UNIT_INPUT_BIAS},
|
||||
{".in_weight", RESIDUAL_UNIT_INPUT_KERNEL},
|
||||
{".out_alpha", RESIDUAL_UNIT_OUTPUT_ALPHA},
|
||||
{".out_bias", RESIDUAL_UNIT_OUTPUT_BIAS},
|
||||
{".out_weight", RESIDUAL_UNIT_OUTPUT_KERNEL},
|
||||
{".out_proj.bias", QUANTIZER_LAYER_OUT_BIAS},
|
||||
{".out_proj.weight", QUANTIZER_LAYER_OUT_KERNEL},
|
||||
{".codebook.weight", QUANTIZER_LAYER_CODEBOOK},
|
||||
};
|
||||
|
||||
void assign_to_residual_unit(tts_model * model, residual_unit & unit, std::string name, struct ggml_tensor * tensor) {
|
||||
try {
|
||||
gguf_tensor tensor_type = GENERAL_NEURAL_AUDIO_CODEC_TENSOR_LOOKUP.at(name);
|
||||
switch (tensor_type) {
|
||||
case RESIDUAL_UNIT_INPUT_ALPHA:
|
||||
unit.in_alpha = ggml_dup_tensor(model->ctx, tensor);
|
||||
model->set_tensor(unit.in_alpha, tensor);
|
||||
break;
|
||||
case RESIDUAL_UNIT_OUTPUT_ALPHA:
|
||||
unit.out_alpha = ggml_dup_tensor(model->ctx, tensor);
|
||||
model->set_tensor(unit.out_alpha, tensor);
|
||||
break;
|
||||
case RESIDUAL_UNIT_INPUT_KERNEL:
|
||||
unit.in_conv_kernel = ggml_dup_tensor(model->ctx, tensor);
|
||||
model->set_tensor(unit.in_conv_kernel, tensor);
|
||||
break;
|
||||
case RESIDUAL_UNIT_OUTPUT_KERNEL:
|
||||
unit.out_conv_kernel = ggml_dup_tensor(model->ctx, tensor);
|
||||
model->set_tensor(unit.out_conv_kernel, tensor);
|
||||
break;
|
||||
case RESIDUAL_UNIT_INPUT_BIAS:
|
||||
unit.in_conv_bias = ggml_dup_tensor(model->ctx, ggml_transpose(model->ctx, tensor));
|
||||
model->set_tensor(unit.in_conv_bias, tensor);
|
||||
break;
|
||||
case RESIDUAL_UNIT_OUTPUT_BIAS:
|
||||
unit.out_conv_bias = ggml_dup_tensor(model->ctx, ggml_transpose(model->ctx, tensor));
|
||||
model->set_tensor(unit.out_conv_bias, tensor);
|
||||
break;
|
||||
default:
|
||||
fprintf(stdout, "residual unit unassigned tensor %s\n", name.c_str());
|
||||
break;
|
||||
}
|
||||
} catch (const std::out_of_range& e) {
|
||||
TTS_ABORT("Tensor, '%s', is not a valid tensor general_neural_audio_codec::residual_unit tensor.", name.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void assign_to_layer(tts_model * model, layer & l, std::string name, struct ggml_tensor * tensor) {
|
||||
if (GENERAL_NEURAL_AUDIO_CODEC_TENSOR_LOOKUP.find(name) != GENERAL_NEURAL_AUDIO_CODEC_TENSOR_LOOKUP.end()) {
|
||||
switch(GENERAL_NEURAL_AUDIO_CODEC_TENSOR_LOOKUP.at(name)) {
|
||||
case LAYER_ALPHA:
|
||||
l.in_alpha = ggml_dup_tensor(model->ctx, tensor);
|
||||
model->set_tensor(l.in_alpha, tensor);
|
||||
break;
|
||||
case LAYER_INPUT_KERNEL:
|
||||
l.in_conv_kernel = ggml_dup_tensor(model->ctx, tensor);
|
||||
model->set_tensor(l.in_conv_kernel, tensor);
|
||||
break;
|
||||
case LAYER_INPUT_BIAS:
|
||||
l.in_conv_bias = ggml_dup_tensor(model->ctx, ggml_transpose(model->ctx, tensor));
|
||||
model->set_tensor(l.in_conv_bias, tensor);
|
||||
break;
|
||||
case LAYER_NOISE_KERNEL:
|
||||
l.noise_conv_kernel = ggml_dup_tensor(model->ctx, tensor);
|
||||
model->set_tensor(l.noise_conv_kernel, tensor);
|
||||
break;
|
||||
default:
|
||||
fprintf(stdout, "layer unassigned tensor %s\n", name.c_str());
|
||||
break;
|
||||
}
|
||||
} else if (std::find_if(name.begin(), name.end(), ::isdigit) != name.end()) {
|
||||
auto pair = parse_layer_count(name);
|
||||
int i = pair.first;
|
||||
std::string lt_name = pair.second;
|
||||
assign_to_residual_unit(model, l.residual_blocks[i], lt_name, tensor);
|
||||
} else {
|
||||
TTS_ABORT("Tensor, '%s', is not a valid tensor general_neural_audio_codec::layer tensor.", name.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void assign_to_quantize_layer(tts_model * model, residual_vector_quantize_layer & l, std::string name, struct ggml_tensor * tensor) {
|
||||
try {
|
||||
switch(GENERAL_NEURAL_AUDIO_CODEC_TENSOR_LOOKUP.at(name)) {
|
||||
case QUANTIZER_LAYER_OUT_KERNEL:
|
||||
l.out_proj_kernel = ggml_dup_tensor(model->ctx, tensor);
|
||||
model->set_tensor(l.out_proj_kernel, tensor);
|
||||
break;
|
||||
case QUANTIZER_LAYER_OUT_BIAS:
|
||||
l.out_proj_bias = ggml_dup_tensor(model->ctx, ggml_transpose(model->ctx, tensor));
|
||||
model->set_tensor(l.out_proj_bias, tensor);
|
||||
break;
|
||||
case QUANTIZER_LAYER_CODEBOOK:
|
||||
l.codebook = ggml_dup_tensor(model->ctx, tensor);
|
||||
model->set_tensor(l.codebook, tensor);
|
||||
break;
|
||||
default:
|
||||
fprintf(stdout, "quantized layer unassigned tensor %s\n", name.c_str());
|
||||
break;
|
||||
}
|
||||
} catch (const std::out_of_range& e) {
|
||||
// older GGUF files still have the unused in_proj convolutional layer, so ignore it if we find it.
|
||||
if (!has_prefix(name, ".in_proj")) {
|
||||
TTS_ABORT("Error: %s\nTensor, '%s', is not a valid tensor.", e.what(), name.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ggml_tensor * build_residual_unit(ggml_context * ctx, struct ggml_tensor * cur, residual_unit & unit) {
|
||||
struct ggml_tensor * residual = cur;
|
||||
cur = snake_1d(ctx, unit.in_alpha, cur);
|
||||
if (unit.groups > 1) {
|
||||
// depthwise 1d convolution is equivalent to convolution in which grouping is equal to filter size.
|
||||
// If there is a divergence between filter size and grouping then the kernel's output filters will not be zero.
|
||||
TTS_ASSERT(unit.in_conv_kernel->ne[1] == 1);
|
||||
cur = ggml_conv_1d_dw_tts(ctx, unit.in_conv_kernel, cur, 1, unit.padding, unit.dilation);
|
||||
} else {
|
||||
cur = ggml_conv_1d_tts(ctx, unit.in_conv_kernel, cur, 1, unit.padding, unit.dilation);
|
||||
}
|
||||
cur = ggml_add(ctx, cur, unit.in_conv_bias);
|
||||
cur = snake_1d(ctx, unit.out_alpha, cur);
|
||||
cur = ggml_conv_1d_tts(ctx, unit.out_conv_kernel, cur, 1, 0, 1);
|
||||
cur = ggml_add(ctx, cur, unit.out_conv_bias);
|
||||
return ggml_add(ctx, cur, residual);
|
||||
}
|
||||
|
||||
struct ggml_tensor * build_layer(ggml_context * ctx, struct ggml_tensor * cur, layer & l, struct ggml_tensor * noise) {
|
||||
cur = snake_1d(ctx, l.in_alpha, cur);
|
||||
cur = ggml_conv_transpose_1d_tts(ctx, l.in_conv_kernel, cur, l.stride, l.padding, 1, 0, 1);
|
||||
cur = ggml_add(ctx, cur, l.in_conv_bias);
|
||||
if (l.noise_conv_kernel && noise) {
|
||||
struct ggml_tensor * x = ggml_conv_1d_tts(ctx, l.noise_conv_kernel, cur, 1, 0, 1);
|
||||
x = ggml_mul(ctx, x, noise);
|
||||
cur = ggml_add(ctx, cur, x);
|
||||
}
|
||||
for (int i = 0; i < l.residual_blocks.size(); i++) {
|
||||
cur = build_residual_unit(ctx, cur, l.residual_blocks[i]);
|
||||
}
|
||||
return cur;
|
||||
}
|
||||
|
||||
struct ggml_tensor * build_quantize_layer(ggml_context * ctx, struct ggml_tensor * cur, residual_vector_quantize_layer & l) {
|
||||
cur = ggml_get_rows(ctx, l.codebook, cur);
|
||||
cur = ggml_cont(ctx, ggml_transpose(ctx, cur));
|
||||
cur = ggml_conv_1d_tts(ctx, l.out_proj_kernel, cur, 1, 0, 1);
|
||||
cur = ggml_add(ctx, cur, l.out_proj_bias);
|
||||
return cur;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
#pragma once
|
||||
|
||||
#include "tts_model.h"
|
||||
|
||||
// This namespace implements a general abstraction of the core functionality used in common neural audio codecs like DAC and SNAC.
|
||||
namespace general_neural_audio_codec {
|
||||
enum gguf_tensor {
|
||||
LAYER_ALPHA,
|
||||
LAYER_INPUT_KERNEL,
|
||||
LAYER_INPUT_BIAS,
|
||||
LAYER_NOISE_KERNEL,
|
||||
RESIDUAL_UNIT_INPUT_ALPHA,
|
||||
RESIDUAL_UNIT_OUTPUT_ALPHA,
|
||||
RESIDUAL_UNIT_INPUT_KERNEL,
|
||||
RESIDUAL_UNIT_OUTPUT_KERNEL,
|
||||
RESIDUAL_UNIT_INPUT_BIAS,
|
||||
RESIDUAL_UNIT_OUTPUT_BIAS,
|
||||
QUANTIZER_LAYER_OUT_KERNEL,
|
||||
QUANTIZER_LAYER_OUT_BIAS,
|
||||
QUANTIZER_LAYER_CODEBOOK
|
||||
};
|
||||
|
||||
struct residual_vector_quantize_layer {
|
||||
struct ggml_tensor * out_proj_kernel;
|
||||
struct ggml_tensor * out_proj_bias;
|
||||
struct ggml_tensor * codebook;
|
||||
};
|
||||
|
||||
struct residual_unit {
|
||||
residual_unit(uint32_t padding, uint32_t dilation, uint32_t groups = 1): padding(padding), dilation(dilation), groups(groups) {}
|
||||
struct ggml_tensor * in_alpha;
|
||||
struct ggml_tensor * in_conv_kernel;
|
||||
struct ggml_tensor * in_conv_bias;
|
||||
struct ggml_tensor * out_alpha;
|
||||
struct ggml_tensor * out_conv_kernel;
|
||||
struct ggml_tensor * out_conv_bias;
|
||||
|
||||
uint32_t padding;
|
||||
uint32_t dilation;
|
||||
uint32_t groups;
|
||||
};
|
||||
|
||||
struct layer {
|
||||
layer(uint32_t padding, uint32_t stride, uint32_t groups = 1): padding(padding), stride(stride) {
|
||||
for (int i = 0; i < 3; i++) {
|
||||
residual_blocks.push_back(residual_unit{(uint32_t) pow(3, (i + 1)), (uint32_t) pow(3, i), groups});
|
||||
}
|
||||
}
|
||||
struct ggml_tensor * in_alpha;
|
||||
struct ggml_tensor * in_conv_kernel;
|
||||
struct ggml_tensor * in_conv_bias;
|
||||
struct ggml_tensor * noise_conv_kernel = nullptr;
|
||||
|
||||
uint32_t padding;
|
||||
uint32_t stride;
|
||||
|
||||
std::vector<residual_unit> residual_blocks;
|
||||
};
|
||||
|
||||
void assign_to_residual_unit(tts_model * model, residual_unit & unit, std::string name, struct ggml_tensor * tensor);
|
||||
void assign_to_layer(tts_model * model, layer & l, std::string name, struct ggml_tensor * tensor);
|
||||
void assign_to_quantize_layer(tts_model * model, residual_vector_quantize_layer & l, std::string name, struct ggml_tensor * tensor);
|
||||
|
||||
struct ggml_tensor * build_residual_unit(ggml_context * ctx, struct ggml_tensor * cur, residual_unit & unit);
|
||||
struct ggml_tensor * build_layer(ggml_context * ctx, struct ggml_tensor * cur, layer & l, struct ggml_tensor * noise = nullptr);
|
||||
struct ggml_tensor * build_quantize_layer(ggml_context * ctx, struct ggml_tensor * cur, residual_vector_quantize_layer & l);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,462 @@
|
||||
#ifndef kokoro_model_h
|
||||
#define kokoro_model_h
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "tts_model.h"
|
||||
#include "tokenizer.h"
|
||||
#include "phonemizer.h"
|
||||
|
||||
// Rather than using ISO 639-2 language codes, Kokoro voice pack specify their corresponding language via their first letter.
|
||||
// Below is a map that describes the relationship between those designations and espeak-ng's voice identifiers so that the
|
||||
// appropriate phonemization protocol can inferred from the Kokoro voice.
|
||||
static std::map<char, std::string> KOKORO_LANG_TO_ESPEAK_ID = {
|
||||
{'a', "gmw/en-US"},
|
||||
{'b', "gmw/en"},
|
||||
{'e', "roa/es"},
|
||||
{'f', "roa/fr"},
|
||||
{'h', "inc/hi"},
|
||||
{'i', "roa/it"},
|
||||
{'j', "jpx/ja"},
|
||||
{'p', "roa/pt-BR"},
|
||||
{'z', "sit/cmn"}
|
||||
};
|
||||
|
||||
struct lstm_cell {
|
||||
std::vector<ggml_tensor*> weights;
|
||||
std::vector<ggml_tensor*> biases;
|
||||
std::vector<ggml_tensor*> reverse_weights;
|
||||
std::vector<ggml_tensor*> reverse_biases;
|
||||
};
|
||||
|
||||
struct lstm {
|
||||
std::vector<ggml_tensor*> hidden;
|
||||
std::vector<ggml_tensor*> states;
|
||||
|
||||
bool bidirectional = false;
|
||||
std::vector<lstm_cell*> cells;
|
||||
};
|
||||
|
||||
struct duration_predictor_layer {
|
||||
lstm * rnn;
|
||||
struct ggml_tensor * ada_norm_gamma_weight;
|
||||
struct ggml_tensor * ada_norm_gamma_bias;
|
||||
struct ggml_tensor * ada_norm_beta_weight;
|
||||
struct ggml_tensor * ada_norm_beta_bias;
|
||||
};
|
||||
|
||||
struct ada_residual_conv_block {
|
||||
struct ggml_tensor * conv1;
|
||||
struct ggml_tensor * conv1_bias;
|
||||
struct ggml_tensor * conv2;
|
||||
struct ggml_tensor * conv2_bias;
|
||||
struct ggml_tensor * norm1_gamma;
|
||||
struct ggml_tensor * norm1_gamma_bias;
|
||||
struct ggml_tensor * norm1_beta;
|
||||
struct ggml_tensor * norm1_beta_bias;
|
||||
struct ggml_tensor * norm2_gamma;
|
||||
struct ggml_tensor * norm2_gamma_bias;
|
||||
struct ggml_tensor * norm2_beta;
|
||||
struct ggml_tensor * norm2_beta_bias;
|
||||
struct ggml_tensor * pool = nullptr;
|
||||
struct ggml_tensor * pool_bias = nullptr;
|
||||
struct ggml_tensor * upsample = nullptr;
|
||||
struct ggml_tensor * upsample_bias = nullptr;
|
||||
};
|
||||
|
||||
struct duration_predictor {
|
||||
struct ggml_tensor * albert_encode;
|
||||
struct ggml_tensor * albert_encode_bias;
|
||||
std::vector<duration_predictor_layer*> layers;
|
||||
lstm * duration_proj_lstm;
|
||||
struct ggml_tensor * duration_proj;
|
||||
struct ggml_tensor * duration_proj_bias;
|
||||
struct ggml_tensor * n_proj_kernel;
|
||||
struct ggml_tensor * n_proj_bias;
|
||||
struct ggml_tensor * f0_proj_kernel;
|
||||
struct ggml_tensor * f0_proj_bias;
|
||||
lstm * shared_lstm;
|
||||
std::vector<ada_residual_conv_block*> f0_blocks;
|
||||
std::vector<ada_residual_conv_block*> n_blocks;
|
||||
};
|
||||
|
||||
struct kokoro_text_encoder_conv_layer {
|
||||
struct ggml_tensor * norm_gamma;
|
||||
struct ggml_tensor * norm_beta;
|
||||
struct ggml_tensor * conv_weight;
|
||||
struct ggml_tensor * conv_bias;
|
||||
};
|
||||
|
||||
struct kokoro_text_encoder {
|
||||
struct ggml_tensor * embd;
|
||||
std::vector<kokoro_text_encoder_conv_layer*> conv_layers;
|
||||
lstm * out_lstm;
|
||||
};
|
||||
|
||||
struct kokoro_generator_residual_block {
|
||||
std::vector<uint32_t> conv1_dilations;
|
||||
std::vector<uint32_t> conv1_paddings;
|
||||
|
||||
std::vector<ggml_tensor*> adain1d_1_gamma_weights;
|
||||
std::vector<ggml_tensor*> adain1d_2_gamma_weights;
|
||||
std::vector<ggml_tensor*> adain1d_1_gamma_biases;
|
||||
std::vector<ggml_tensor*> adain1d_2_gamma_biases;
|
||||
std::vector<ggml_tensor*> adain1d_1_beta_weights;
|
||||
std::vector<ggml_tensor*> adain1d_2_beta_weights;
|
||||
std::vector<ggml_tensor*> adain1d_1_beta_biases;
|
||||
std::vector<ggml_tensor*> adain1d_2_beta_biases;
|
||||
std::vector<ggml_tensor*> input_alphas;
|
||||
std::vector<ggml_tensor*> output_alphas;
|
||||
std::vector<ggml_tensor*> convs1_weights;
|
||||
std::vector<ggml_tensor*> convs1_biases;
|
||||
std::vector<ggml_tensor*> convs2_weights;
|
||||
std::vector<ggml_tensor*> convs2_biases;
|
||||
};
|
||||
|
||||
struct kokoro_noise_residual_block {
|
||||
uint32_t input_conv_stride;
|
||||
uint32_t input_conv_padding;
|
||||
|
||||
struct ggml_tensor * input_conv;
|
||||
struct ggml_tensor * input_conv_bias;
|
||||
struct kokoro_generator_residual_block * res_block;
|
||||
};
|
||||
|
||||
struct kokoro_generator_upsample_block {
|
||||
uint32_t padding;
|
||||
uint32_t stride;
|
||||
|
||||
// these are just conv transpose layers
|
||||
struct ggml_tensor * upsample_weight;
|
||||
struct ggml_tensor * upsample_bias;
|
||||
};
|
||||
|
||||
struct kokoro_generator {
|
||||
// unfortunately the squared sum of the windows needs to be computed dynamically per run because it is dependent
|
||||
// on the sequence size of the generation and the hop is typically less than half the size of our window.
|
||||
struct ggml_tensor * window;
|
||||
|
||||
struct ggml_tensor * m_source_weight;
|
||||
struct ggml_tensor * m_source_bias;
|
||||
struct ggml_tensor * out_conv_weight;
|
||||
struct ggml_tensor * out_conv_bias;
|
||||
std::vector<kokoro_noise_residual_block*> noise_blocks;
|
||||
std::vector<kokoro_generator_residual_block*> res_blocks;
|
||||
std::vector<kokoro_generator_upsample_block*> ups;
|
||||
};
|
||||
|
||||
struct kokoro_decoder {
|
||||
struct ggml_tensor * f0_conv;
|
||||
struct ggml_tensor * f0_conv_bias;
|
||||
struct ggml_tensor * n_conv;
|
||||
struct ggml_tensor * n_conv_bias;
|
||||
struct ggml_tensor * asr_conv;
|
||||
struct ggml_tensor * asr_conv_bias;
|
||||
std::vector<ada_residual_conv_block*> decoder_blocks;
|
||||
ada_residual_conv_block* encoder_block;
|
||||
kokoro_generator * generator;
|
||||
};
|
||||
|
||||
struct albert_layer {
|
||||
struct ggml_tensor * ffn;
|
||||
struct ggml_tensor * ffn_out;
|
||||
struct ggml_tensor * ffn_bias;
|
||||
struct ggml_tensor * ffn_out_bias;
|
||||
struct ggml_tensor * layer_output_norm_weight;
|
||||
struct ggml_tensor * layer_output_norm_bias;
|
||||
struct ggml_tensor * q;
|
||||
struct ggml_tensor * k;
|
||||
struct ggml_tensor * v;
|
||||
struct ggml_tensor * o;
|
||||
struct ggml_tensor * q_bias;
|
||||
struct ggml_tensor * k_bias;
|
||||
struct ggml_tensor * v_bias;
|
||||
struct ggml_tensor * o_bias;
|
||||
struct ggml_tensor * attn_norm_weight;
|
||||
struct ggml_tensor * attn_norm_bias;
|
||||
};
|
||||
|
||||
struct kokoro_model : tts_model {
|
||||
// standard configruation for Kokoro's Albert model
|
||||
// tokenization
|
||||
uint32_t bos_token_id = 0;
|
||||
uint32_t eos_token_id = 0;
|
||||
uint32_t space_token_id = 16;
|
||||
// duration prediction
|
||||
uint32_t max_context_length = 512;
|
||||
uint32_t vocab_size = 178;
|
||||
uint32_t hidden_size = 768;
|
||||
uint32_t n_attn_heads = 12;
|
||||
uint32_t n_layers = 1;
|
||||
uint32_t n_recurrence = 12;
|
||||
uint32_t head_size = 64;
|
||||
uint32_t duration_hidden_size = 512;
|
||||
uint32_t up_sampling_factor;
|
||||
float upsample_scale = 300.0f;
|
||||
float scale = 0.125f;
|
||||
|
||||
// standard configuration for duration prediction
|
||||
uint32_t f0_n_blocks = 3;
|
||||
uint32_t n_duration_prediction_layers = 3;
|
||||
// while it is technically possible for the duration predictor to assign 50 values per token there is no practical need to
|
||||
// allocate that many items to the sequence as it is impossible for all tokens to require such long durations and each
|
||||
// allocation increases node allocation size by O(N)
|
||||
uint32_t max_duration_per_token = 20;
|
||||
uint32_t style_half_size = 128;
|
||||
|
||||
// standard text encoding configuration
|
||||
uint32_t n_conv_layers = 3;
|
||||
|
||||
// standard decoder configuration
|
||||
uint32_t n_kernels = 3;
|
||||
uint32_t n_upsamples = 2;
|
||||
uint32_t n_decoder_blocks = 4;
|
||||
uint32_t n_res_blocks = 6;
|
||||
uint32_t n_noise_blocks = 2;
|
||||
uint32_t out_conv_padding = 3;
|
||||
uint32_t post_n_fft = 11;
|
||||
uint32_t true_n_fft = 20;
|
||||
uint32_t stft_hop = 5;
|
||||
uint32_t harmonic_num = 8;
|
||||
float sin_amp = 0.1f;
|
||||
float noise_std = 0.003f;
|
||||
float voice_threshold = 10.0f;
|
||||
float sample_rate = 24000.0f;
|
||||
std::string window = "hann";
|
||||
|
||||
// It is really annoying that ggml doesn't allow using non ggml tensors as the operator for simple math ops.
|
||||
// This is just the constant defined above as a tensor.
|
||||
struct ggml_tensor * n_kernels_tensor;
|
||||
|
||||
// Kokoro loads albert with use_pooling = true but doesn't use the pooling outputs.
|
||||
bool uses_pooling = false;
|
||||
bool static_token_types = true;
|
||||
|
||||
std::map<std::string, struct ggml_tensor *> voices;
|
||||
|
||||
// Albert portion of the model
|
||||
struct ggml_tensor * embd_hidden;
|
||||
struct ggml_tensor * embd_hidden_bias;
|
||||
struct ggml_tensor * token_type_embd = nullptr;
|
||||
struct ggml_tensor * token_embd;
|
||||
struct ggml_tensor * position_embd;
|
||||
struct ggml_tensor * input_norm_weight;
|
||||
struct ggml_tensor * input_norm_bias;
|
||||
struct ggml_tensor * static_token_type_values = nullptr;
|
||||
struct ggml_tensor * pool = nullptr;
|
||||
struct ggml_tensor * pool_bias = nullptr;
|
||||
std::vector<albert_layer*> layers;
|
||||
|
||||
struct ggml_tensor * harmonic_sampling_norm = nullptr; // a static 1x9 harmonic multiplier
|
||||
struct ggml_tensor * sampling_factor_scalar = nullptr; // a static scalar
|
||||
struct ggml_tensor * sqrt_tensor = nullptr; // static tensor for constant division
|
||||
|
||||
// Prosody Predictor portion of the model
|
||||
struct duration_predictor * prosody_pred;
|
||||
|
||||
// Text encoding portion of the model
|
||||
struct kokoro_text_encoder * text_encoder;
|
||||
|
||||
// Decoding and Generation portion of the model
|
||||
struct kokoro_decoder * decoder;
|
||||
|
||||
// the default hidden states need to be initialized
|
||||
std::vector<lstm*> lstms;
|
||||
|
||||
size_t duration_node_counter = 0;
|
||||
size_t generation_node_counter = 0;
|
||||
// setting this is likely unnecessary as it is precomputed by the post load function.
|
||||
uint32_t post_load_tensor_bytes = 13000;
|
||||
|
||||
size_t max_gen_nodes();
|
||||
size_t max_duration_nodes();
|
||||
|
||||
lstm * prep_lstm();
|
||||
// helper functions for assigning tensors to substructs
|
||||
void assign_lstm(lstm * rnn, std::string name, ggml_tensor * tensor);
|
||||
void assign_generator_weight(kokoro_generator * generator, std::string name, ggml_tensor * tensor);
|
||||
void assign_gen_resblock(kokoro_generator_residual_block * block, std::string name, ggml_tensor * tensor);
|
||||
void assign_ada_res_block(ada_residual_conv_block * block, std::string name, ggml_tensor * tensor);
|
||||
void assign_decoder_weight(std::string name, ggml_tensor * tensor);
|
||||
void assign_duration_weight(std::string name, ggml_tensor * tensor);
|
||||
void assign_text_encoder_weight(std::string name, ggml_tensor * tensor);
|
||||
void assign_albert_weight(std::string name, ggml_tensor * tensor);
|
||||
|
||||
|
||||
void post_load_assign();
|
||||
void assign_weight(std::string name, ggml_tensor * tensor);
|
||||
void prep_layers(gguf_context * meta);
|
||||
void prep_constants(gguf_context * meta);
|
||||
void setup_from_file(gguf_context * meta_ctx, ggml_context * load_context, bool cpu_only = true) {
|
||||
std::function<void (ggml_tensor *)> fn = ([&](ggml_tensor* cur) {
|
||||
std::string name = ggml_get_name(cur);
|
||||
size_t increment = 1;
|
||||
if (name.find("lstm") != std::string::npos) {
|
||||
increment = max_context_length;
|
||||
}
|
||||
if (name.find("duration_predictor") != std::string::npos) {
|
||||
duration_node_counter += increment;
|
||||
} else {
|
||||
generation_node_counter += increment;
|
||||
}
|
||||
});
|
||||
compute_tensor_meta_cb = &fn;
|
||||
prep_constants(meta_ctx);
|
||||
prep_layers(meta_ctx);
|
||||
tts_model::setup_from_file(meta_ctx, load_context, cpu_only, "kokoro", 1.6, post_load_tensor_bytes);
|
||||
}
|
||||
};
|
||||
|
||||
struct kokoro_ubatch {
|
||||
size_t n_tokens; // the number of tokens in our encoded sequence
|
||||
uint32_t * input_tokens; // [n_tokens]
|
||||
struct kokoro_duration_response * resp = nullptr;
|
||||
};
|
||||
|
||||
struct kokoro_duration_context : runner_context {
|
||||
kokoro_duration_context(kokoro_model * model, int n_threads): runner_context(n_threads), model(model) {};
|
||||
~kokoro_duration_context() {
|
||||
ggml_backend_buffer_free(buf_len_output);
|
||||
}
|
||||
|
||||
std::string voice = "af_alloy";
|
||||
struct kokoro_model * model;
|
||||
ggml_backend_buffer_t buf_len_output = nullptr;
|
||||
|
||||
|
||||
size_t logits_size = 0; // capacity (of floats) for logits
|
||||
float * lens = nullptr;
|
||||
|
||||
struct ggml_tensor * inp_tokens;
|
||||
struct ggml_tensor * positions;
|
||||
struct ggml_tensor * attn_mask;
|
||||
struct ggml_tensor * token_types = nullptr;
|
||||
|
||||
void build_schedule() {
|
||||
runner_context::build_schedule(model->max_duration_nodes()*5);
|
||||
}
|
||||
};
|
||||
|
||||
static struct ggml_tensor * build_albert_attn_mask(ggml_context * ctx, struct kokoro_duration_context *kctx, const kokoro_ubatch & batch);
|
||||
static struct ggml_tensor * build_albert_inputs(ggml_context * ctx, kokoro_model * model, ggml_tensor * input_tokens, ggml_tensor * positions, ggml_tensor * token_types);
|
||||
static struct ggml_tensor * build_albert_norm(ggml_context * ctx, ggml_tensor * cur, ggml_tensor * weight, ggml_tensor * bias);
|
||||
static struct ggml_tensor * build_ada_residual_conv(ggml_context * ctx, struct ggml_tensor * x, ada_residual_conv_block * block, struct ggml_tensor * style, struct ggml_tensor * sqrt_tensor);
|
||||
static struct ggml_tensor * build_kokoro_generator_res_block(ggml_context * ctx, struct ggml_tensor * x, struct ggml_tensor * style, kokoro_generator_residual_block * block);
|
||||
static struct ggml_tensor * build_noise_block(ggml_context * ctx, kokoro_noise_residual_block * block, struct ggml_tensor * x, struct ggml_tensor * style);
|
||||
static kokoro_generator_residual_block * build_res_block_from_file(gguf_context * meta, std::string base_config_key);
|
||||
static kokoro_noise_residual_block * build_noise_block_from_file(gguf_context * meta, int index);
|
||||
static kokoro_generator_upsample_block* kokoro_generator_upsample_block(gguf_context * meta, int index);
|
||||
|
||||
std::string get_espeak_id_from_kokoro_voice(std::string voice);
|
||||
struct kokoro_duration_context * build_new_duration_kokoro_context(struct kokoro_model * model, int n_threads, bool use_cpu = true);
|
||||
|
||||
struct kokoro_duration_response {
|
||||
size_t n_outputs;
|
||||
float * lengths;
|
||||
float * hidden_states;
|
||||
};
|
||||
|
||||
// This struct is intended to manage graph and compute for the duration prediction portion of the kokoro model.
|
||||
// Duration computation and speech generation are separated into distinct graphs because the precomputed graph structure of ggml doesn't
|
||||
// support the tensor dependent views that would otherwise be necessary.
|
||||
struct kokoro_duration_runner : tts_runner {
|
||||
kokoro_duration_runner(kokoro_model * model, kokoro_duration_context * context, single_pass_tokenizer * tokenizer): model(model), kctx(context), tokenizer(tokenizer) {};
|
||||
~kokoro_duration_runner() {
|
||||
if (ctx) {
|
||||
ggml_free(ctx);
|
||||
}
|
||||
model->free();
|
||||
delete model;
|
||||
delete kctx;
|
||||
}
|
||||
struct single_pass_tokenizer * tokenizer;
|
||||
kokoro_model * model;
|
||||
kokoro_duration_context * kctx;
|
||||
|
||||
void init_build() {
|
||||
tts_runner::init_build(&kctx->buf_compute_meta);
|
||||
}
|
||||
|
||||
void prepare_post_load();
|
||||
struct kokoro_ubatch build_worst_case_batch();
|
||||
void set_inputs(kokoro_ubatch & batch);
|
||||
struct ggml_cgraph * build_kokoro_duration_graph(kokoro_ubatch & batch);
|
||||
void run(kokoro_ubatch & ubatch);
|
||||
};
|
||||
|
||||
struct kokoro_context : runner_context {
|
||||
kokoro_context(kokoro_model * model, int n_threads): runner_context(n_threads), model(model) {};
|
||||
~kokoro_context() {
|
||||
ggml_backend_sched_free(sched);
|
||||
ggml_backend_free(backend_cpu);
|
||||
if (backend) {
|
||||
ggml_backend_free(backend);
|
||||
}
|
||||
if (buf_output) {
|
||||
ggml_backend_buffer_free(buf_output);
|
||||
}
|
||||
}
|
||||
|
||||
std::string voice = "af_alloy";
|
||||
|
||||
struct kokoro_model * model;
|
||||
|
||||
uint32_t total_duration;
|
||||
uint32_t sequence_length;
|
||||
|
||||
struct ggml_tensor * inp_tokens;
|
||||
struct ggml_tensor * duration_pred;
|
||||
struct ggml_tensor * duration_mask;
|
||||
struct ggml_tensor * window_sq_sum; // needs to be calculatd from the generator window.
|
||||
struct ggml_tensor * uv_noise_data;
|
||||
|
||||
void build_schedule() {
|
||||
runner_context::build_schedule(model->max_gen_nodes()*30);
|
||||
}
|
||||
};
|
||||
|
||||
// TODO: now that we are passing the context down to these methods we should clean up their parameters
|
||||
static struct ggml_tensor * build_generator(ggml_context * ctx, kokoro_model * model, kokoro_context * kctx, struct ggml_tensor * x, struct ggml_tensor * style, struct ggml_tensor * f0_curve, kokoro_generator* generator, int sequence_length, struct ggml_tensor * window_sq_sum, ggml_cgraph * gf);
|
||||
static struct ggml_tensor * build_sin_gen(ggml_context * ctx, kokoro_model * model, kokoro_context * kctx, struct ggml_tensor * x, int harmonic_num, int sequence_length, float voice_threshold, float sin_amp, float noise_std);
|
||||
|
||||
struct kokoro_context * build_new_kokoro_context(struct kokoro_model * model, int n_threads, bool use_cpu = true);
|
||||
|
||||
// This manages the graph compilation of computation for the Kokoro model.
|
||||
struct kokoro_runner : tts_runner {
|
||||
kokoro_runner(kokoro_model * model, kokoro_context * context, single_pass_tokenizer * tokenizer, kokoro_duration_runner * drunner, phonemizer * phmzr): model(model), kctx(context), tokenizer(tokenizer), drunner(drunner), phmzr(phmzr) {
|
||||
tts_runner::sampling_rate = 24000.0f;
|
||||
tts_runner::supports_voices = true;
|
||||
};
|
||||
~kokoro_runner() {
|
||||
if (ctx) {
|
||||
ggml_free(ctx);
|
||||
}
|
||||
delete drunner;
|
||||
model->free();
|
||||
delete model;
|
||||
delete kctx;
|
||||
delete phmzr;
|
||||
}
|
||||
struct single_pass_tokenizer * tokenizer;
|
||||
kokoro_model * model;
|
||||
kokoro_context * kctx;
|
||||
kokoro_duration_runner * drunner;
|
||||
phonemizer * phmzr;
|
||||
|
||||
std::string default_voice = "af_alloy";
|
||||
|
||||
void init_build() {
|
||||
tts_runner::init_build(&kctx->buf_compute_meta);
|
||||
}
|
||||
|
||||
std::vector<std::string> list_voices();
|
||||
std::vector<std::vector<uint32_t>> tokenize_chunks(std::vector<std::string> clauses);
|
||||
void assign_weight(std::string name, ggml_tensor * tensor);
|
||||
void prepare_post_load();
|
||||
kokoro_ubatch build_worst_case_batch();
|
||||
void set_inputs(kokoro_ubatch & batch, uint32_t total_size);
|
||||
struct ggml_cgraph * build_kokoro_graph(kokoro_ubatch & batch);
|
||||
void run(kokoro_ubatch & batch, struct tts_response * outputs);
|
||||
int generate(std::string prompt, struct tts_response * response, std::string voice, std::string voice_code = "");
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,475 @@
|
||||
#include "orpheus_model.h"
|
||||
|
||||
#include <array>
|
||||
|
||||
// These tokens and variables aren't defined in the Orpheus' model configuration but instead are defined inline in various python functions.
|
||||
// As such, they are not discoverable so defining them as unconfigurable constants should be fine.
|
||||
static constexpr std::array<const char *, 7> orpheus_voices{"zoe", "zac","jess", "leo", "mia", "julia", "leah"};
|
||||
static constexpr std::array<uint32_t, 2> orpheus_prepended_tokens = { 128259, 128000 };
|
||||
static constexpr std::array<uint32_t, 4> orpheus_appended_tokens = { 128009, 128260, 128261, 128257 };
|
||||
|
||||
void orpheus_model::assign_weight(std::string name, struct ggml_tensor * tensor) {
|
||||
if (name == "norm") {
|
||||
output_norm = ggml_dup_tensor(ctx, tensor);
|
||||
set_tensor(output_norm, tensor);
|
||||
} else if (name == "lm_head") {
|
||||
head = ggml_dup_tensor(ctx, tensor);
|
||||
set_tensor(head, tensor);
|
||||
} else if (name == "embed_tokens") {
|
||||
embd = ggml_dup_tensor(ctx, tensor);
|
||||
set_tensor(embd, tensor);
|
||||
} else if (name == "rope_frequencies") {
|
||||
rope_frequencies = ggml_dup_tensor(ctx, tensor);
|
||||
set_tensor(rope_frequencies, tensor);
|
||||
} else if (has_prefix(name, "layers")) {
|
||||
auto lpair = parse_layer_count(name);
|
||||
int l = lpair.first;
|
||||
std::string lt_name = lpair.second;
|
||||
assign_to_layer(lt_name, layers[l], tensor);
|
||||
}
|
||||
}
|
||||
|
||||
void orpheus_model::assign_to_layer(std::string part, orpheus_layer & layer, struct ggml_tensor * tensor) {
|
||||
if (part == ".self_attn.k_proj") {
|
||||
layer.k = ggml_dup_tensor(ctx, tensor);
|
||||
set_tensor(layer.k, tensor);
|
||||
} else if (part == ".self_attn.q_proj") {
|
||||
layer.q = ggml_dup_tensor(ctx, tensor);
|
||||
set_tensor(layer.q, tensor);
|
||||
} else if (part == ".self_attn.v_proj") {
|
||||
layer.v = ggml_dup_tensor(ctx, tensor);
|
||||
set_tensor(layer.v, tensor);
|
||||
} else if (part == ".self_attn.o_proj") {
|
||||
layer.o = ggml_dup_tensor(ctx, tensor);
|
||||
set_tensor(layer.o, tensor);
|
||||
} else if (part == ".mlp.gate_proj") {
|
||||
layer.gate = ggml_dup_tensor(ctx, tensor);
|
||||
set_tensor(layer.gate, tensor);
|
||||
} else if (part == ".mlp.up_proj") {
|
||||
layer.up = ggml_dup_tensor(ctx, tensor);
|
||||
set_tensor(layer.up, tensor);
|
||||
} else if (part == ".mlp.down_proj") {
|
||||
layer.down = ggml_dup_tensor(ctx, tensor);
|
||||
set_tensor(layer.down, tensor);
|
||||
} else if (part == ".input_layernorm") {
|
||||
layer.input_norm = ggml_dup_tensor(ctx, tensor);
|
||||
set_tensor(layer.input_norm, tensor);
|
||||
} else if (part == ".post_attention_layernorm") {
|
||||
layer.post_attention_norm = ggml_dup_tensor(ctx, tensor);
|
||||
set_tensor(layer.post_attention_norm, tensor);
|
||||
}
|
||||
}
|
||||
|
||||
void orpheus_model::prep_constants(gguf_context * meta) {
|
||||
// get constants for orpheus
|
||||
int vocab_size_key = gguf_find_key(meta, "orpheus.vocab_size");
|
||||
if (vocab_size_key != -1) {
|
||||
vocab_size = gguf_get_val_u32(meta, vocab_size_key);
|
||||
}
|
||||
|
||||
int attn_heads_key = gguf_find_key(meta, "orpheus.attn_heads");
|
||||
if (attn_heads_key != -1) {
|
||||
n_attn_heads = gguf_get_val_u32(meta, attn_heads_key);
|
||||
}
|
||||
|
||||
int kv_attn_heads_key = gguf_find_key(meta, "orpheus.kv_attn_heads");
|
||||
if (kv_attn_heads_key != -1) {
|
||||
n_kv_attn_heads = gguf_get_val_u32(meta, kv_attn_heads_key);
|
||||
}
|
||||
|
||||
int head_size_key = gguf_find_key(meta, "orpheus.head_dim");
|
||||
if (head_size_key != -1) {
|
||||
head_size = gguf_get_val_u32(meta, head_size_key);
|
||||
}
|
||||
|
||||
int stopping_token_key = gguf_find_key(meta, "orpheus.stopping_token_id");
|
||||
if (stopping_token_key != -1) {
|
||||
stopping_token_id = gguf_get_val_u32(meta, stopping_token_key);;
|
||||
}
|
||||
|
||||
int eos_token_id_key = gguf_find_key(meta, "tokenizer.ggml.eos_token_id");
|
||||
if (eos_token_id_key != -1) {
|
||||
eos_token_id = gguf_get_val_u32(meta, eos_token_id_key);
|
||||
}
|
||||
|
||||
int bos_token_id_key = gguf_find_key(meta, "tokenizer.ggml.bos_token_id");
|
||||
if (bos_token_id_key != -1) {
|
||||
bos_token_id = gguf_get_val_u32(meta, bos_token_id_key);
|
||||
}
|
||||
|
||||
int hidden_size_key = gguf_find_key(meta, "orpheus.hidden_size");
|
||||
if (hidden_size_key != -1) {
|
||||
hidden_size = gguf_get_val_u32(meta, hidden_size_key);
|
||||
}
|
||||
|
||||
int kv_hidden_size_key = gguf_find_key(meta, "orpheus.kv_hidden_size");
|
||||
if (kv_hidden_size_key != -1) {
|
||||
kv_hidden_size = gguf_get_val_u32(meta, kv_hidden_size_key);
|
||||
}
|
||||
}
|
||||
|
||||
void orpheus_model::prep_layers(gguf_context * meta) {
|
||||
int n_layers_key = gguf_find_key(meta, "orpheus.layers");
|
||||
if (n_layers_key == -1) {
|
||||
TTS_ABORT("the 'orpheus.layers' must be specified in the GGUF file.");
|
||||
}
|
||||
n_layers = (int) gguf_get_val_u32(meta, n_layers_key);
|
||||
for (int i = 0; i < n_layers; i++) {
|
||||
layers.push_back(orpheus_layer{});
|
||||
}
|
||||
}
|
||||
|
||||
struct ggml_tensor * orpheus_build_layer_norm(ggml_context * ctx, struct ggml_tensor * x, struct ggml_tensor * weight) {
|
||||
float eps = 0.00001;
|
||||
return ggml_mul(ctx, ggml_rms_norm(ctx, x, eps), weight);
|
||||
}
|
||||
|
||||
struct ggml_tensor * build_attn_mask(ggml_context * ctx, orpheus_context * octx, orpheus_ubatch & batch) {
|
||||
octx->attn_mask = ggml_new_tensor_2d(ctx, GGML_TYPE_F32, (int64_t) octx->current_position + batch.n_tokens, (int64_t) octx->current_position + batch.n_tokens);
|
||||
ggml_set_input(octx->attn_mask);
|
||||
return octx->attn_mask;
|
||||
}
|
||||
|
||||
void orpheus_context::reset() {
|
||||
output_tokens.clear();
|
||||
current_position = 0;
|
||||
n_outputs = 0;
|
||||
}
|
||||
|
||||
orpheus_context * build_new_orpheus_context(orpheus_model * model, int n_threads, bool use_cpu) {
|
||||
orpheus_context * octx = new orpheus_context(model, n_threads);
|
||||
if (!use_cpu) {
|
||||
#ifdef GGML_USE_METAL
|
||||
octx->backend = ggml_backend_metal_init();
|
||||
#endif
|
||||
}
|
||||
octx->backend_cpu = ggml_backend_cpu_init();
|
||||
octx->set_threads();
|
||||
octx->build_schedule();
|
||||
octx->buf_compute_meta.resize(ggml_tensor_overhead()*model->max_nodes() + ggml_graph_overhead_custom(model->max_nodes(), false));
|
||||
return octx;
|
||||
}
|
||||
|
||||
void orpheus_runner::orpheus_kv_cache_init() {
|
||||
ggml_backend_buffer_type_t buft = nullptr;
|
||||
if (octx->backend != nullptr) {
|
||||
#ifdef GGML_USE_METAL
|
||||
buft = ggml_backend_metal_buffer_type();
|
||||
#endif
|
||||
} else {
|
||||
buft = ggml_backend_cpu_buffer_type();
|
||||
}
|
||||
|
||||
struct ggml_init_params params = {
|
||||
/*.mem_size =*/ (2u * model->layers.size() + 1)*ggml_tensor_overhead(),
|
||||
/*.mem_buffer =*/ NULL,
|
||||
/*.no_alloc =*/ true,
|
||||
};
|
||||
ggml_context * ctx = ggml_init(params);
|
||||
if (!ctx) {
|
||||
TTS_ABORT("%s: failed to initialze ggml context for key value cache.\n", __func__);
|
||||
}
|
||||
if (!kv_self) {
|
||||
kv_self = new orpheus_kv_cache;
|
||||
}
|
||||
kv_self->ctx = ctx;
|
||||
kv_self->k_l.reserve(model->layers.size());
|
||||
kv_self->v_l.reserve(model->layers.size());
|
||||
|
||||
for (int i = 0; i < (int) model->layers.size(); i++) {
|
||||
ggml_tensor * k = ggml_new_tensor_1d(kv_self->ctx, kv_self->cache_type, model->hidden_size * (model->max_context_length + model->max_generation_size));
|
||||
ggml_tensor * v = ggml_new_tensor_1d(kv_self->ctx, kv_self->cache_type, model->hidden_size * (model->max_context_length + model->max_generation_size));
|
||||
ggml_format_name(k, "cache_k_l%d", i);
|
||||
ggml_format_name(v, "cache_v_l%d", i);
|
||||
kv_self->k_l.push_back(k);
|
||||
kv_self->v_l.push_back(v);
|
||||
}
|
||||
|
||||
// allocate tensors and initialize the buffers to avoid NaNs in the padding
|
||||
ggml_backend_buffer_t buf = ggml_backend_alloc_ctx_tensors_from_buft(kv_self->ctx, buft);
|
||||
ggml_backend_buffer_clear(buf, 0);
|
||||
kv_self->buf = buf;
|
||||
}
|
||||
|
||||
void orpheus_runner::orpheus_build_kv_store(struct ggml_context * ctx, struct ggml_cgraph * graph, struct ggml_tensor * k_cur, struct ggml_tensor * v_cur, int index, uint32_t n_tokens, int repeat) {
|
||||
k_cur = ggml_rope_ext(ctx, ggml_cont(ctx, ggml_reshape_3d(ctx, k_cur, model->head_size, model->n_kv_attn_heads, n_tokens)), octx->positions, model->rope_frequencies,
|
||||
model->head_size, 2,0, 500000.0f,
|
||||
1.0f, 0.0f, 1.0f, 0.0f, 0.0f);
|
||||
|
||||
// A performance comparison between this method, i.e. performing 3 incremental copy operations in order to achieve repeat_interleave,
|
||||
// and performing the repeat operation upfront before performign a single copy needs to be performed in order to better optimize this function.
|
||||
// Additionally, it might be more performant for the values transposition to be performed prior to appending it to the cache, as it would save us
|
||||
// from incrementally larger transpositions with generation.
|
||||
for (int i = 0; i < repeat; i++) {
|
||||
struct ggml_tensor * k_cache_view = ggml_view_3d(
|
||||
ctx,
|
||||
kv_self->k_l[index],
|
||||
model->head_size,
|
||||
model->n_kv_attn_heads,
|
||||
n_tokens,
|
||||
ggml_element_size(kv_self->k_l[index]) * model->head_size * repeat,
|
||||
ggml_element_size(kv_self->k_l[index]) * model->n_attn_heads * model->head_size,
|
||||
ggml_element_size(kv_self->k_l[index]) * model->n_attn_heads * model->head_size * octx->current_position + i * ggml_element_size(kv_self->k_l[index]) * model->head_size
|
||||
);
|
||||
ggml_build_forward_expand(graph, ggml_cpy(ctx, k_cur, k_cache_view));
|
||||
|
||||
struct ggml_tensor * v_cache_view = ggml_view_3d(
|
||||
ctx,
|
||||
kv_self->v_l[index],
|
||||
model->head_size,
|
||||
model->n_kv_attn_heads,
|
||||
n_tokens,
|
||||
ggml_element_size(kv_self->k_l[index]) * model->head_size * repeat,
|
||||
ggml_element_size(kv_self->k_l[index]) * model->n_attn_heads * model->head_size,
|
||||
ggml_element_size(kv_self->k_l[index]) * model->n_attn_heads * model->head_size * octx->current_position + i * ggml_element_size(kv_self->k_l[index]) * model->head_size
|
||||
);
|
||||
ggml_build_forward_expand(graph, ggml_cpy(ctx, v_cur, v_cache_view));
|
||||
}
|
||||
}
|
||||
|
||||
struct ggml_cgraph * orpheus_runner::build_orpheus_graph(orpheus_ubatch & batch) {
|
||||
init_build();
|
||||
struct ggml_cgraph * gf = ggml_new_graph_custom(ctx, 8192, false);
|
||||
|
||||
struct ggml_tensor * cur;
|
||||
struct ggml_tensor * inpL;
|
||||
|
||||
const int32_t full_sequence_length = octx->current_position + (uint32_t) batch.n_tokens;
|
||||
octx->positions = ggml_new_tensor_1d(ctx, GGML_TYPE_I32, batch.n_tokens);
|
||||
ggml_set_input(octx->positions);
|
||||
octx->inp_tokens = ggml_new_tensor_1d(ctx, GGML_TYPE_I32, batch.n_tokens);
|
||||
ggml_set_input(octx->inp_tokens);
|
||||
inpL = ggml_get_rows(ctx, model->embd, octx->inp_tokens);
|
||||
|
||||
struct ggml_tensor * KQ_mask_dec = build_attn_mask(ctx, octx, batch);
|
||||
|
||||
for (int l = 0; l < model->n_layers; l++) {
|
||||
struct ggml_tensor * residual = inpL;
|
||||
cur = orpheus_build_layer_norm(ctx, inpL, model->layers[l].input_norm);
|
||||
|
||||
struct ggml_tensor * attn_out;
|
||||
|
||||
// self-attention
|
||||
{
|
||||
struct ggml_tensor * Qcur = ggml_mul_mat(ctx, model->layers[l].q, cur);
|
||||
struct ggml_tensor * Kcur = ggml_mul_mat(ctx, model->layers[l].k, cur);
|
||||
struct ggml_tensor * Vcur = ggml_mul_mat(ctx, model->layers[l].v, cur);
|
||||
|
||||
orpheus_build_kv_store(ctx, gf, Kcur, Vcur, l, batch.n_tokens, 3);
|
||||
struct ggml_tensor * k =
|
||||
ggml_cont(ctx, ggml_view_3d(ctx, kv_self->k_l[l],
|
||||
model->head_size, full_sequence_length, model->n_attn_heads,
|
||||
ggml_element_size(kv_self->k_l[l]) * model->n_attn_heads * model->head_size,
|
||||
ggml_element_size(kv_self->k_l[l]) * model->head_size,
|
||||
0));
|
||||
|
||||
struct ggml_tensor * v =
|
||||
ggml_view_2d(ctx, kv_self->v_l[l],
|
||||
model->hidden_size, full_sequence_length,
|
||||
ggml_element_size(kv_self->k_l[l]) * model->hidden_size,
|
||||
0);
|
||||
|
||||
v = ggml_cont_3d(ctx, ggml_transpose(ctx, v), full_sequence_length, model->head_size, model->n_attn_heads);
|
||||
|
||||
Qcur = ggml_rope_ext(
|
||||
ctx, ggml_cont(ctx, ggml_reshape_3d(ctx, Qcur, model->head_size, model->n_attn_heads, batch.n_tokens)),
|
||||
octx->positions, model->rope_frequencies, model->head_size, 2, 0, 500000.0f, // rope theta
|
||||
1.0f, 0.0f, 1.0f, 0.0f, 0.0f);
|
||||
|
||||
struct ggml_tensor * q = ggml_cont(ctx, ggml_permute(ctx, Qcur, 0, 2, 1, 3));
|
||||
struct ggml_tensor * kq = ggml_mul_mat(ctx, k, q);
|
||||
kq = ggml_soft_max_ext(ctx, kq, KQ_mask_dec, 1.0f/sqrtf(model->head_size), 0.0f);
|
||||
struct ggml_tensor * kqv = ggml_mul_mat(ctx, kq, v);
|
||||
struct ggml_tensor * kqv_merged = ggml_permute(ctx, kqv, 2, 0, 1, 3);
|
||||
attn_out = ggml_cont_2d(ctx, kqv_merged, model->hidden_size, batch.n_tokens);
|
||||
attn_out = ggml_mul_mat(ctx, model->layers[l].o, attn_out);
|
||||
}
|
||||
|
||||
cur = ggml_add(ctx, attn_out, residual);
|
||||
|
||||
struct ggml_tensor * residualffn = cur;
|
||||
|
||||
// mlp
|
||||
{
|
||||
cur = orpheus_build_layer_norm(ctx, cur, model->layers[l].post_attention_norm);
|
||||
cur = ggml_mul(ctx, ggml_silu(ctx, ggml_mul_mat(ctx, model->layers[l].gate, cur)), ggml_mul_mat(ctx, model->layers[l].up, cur));
|
||||
cur = ggml_mul_mat(ctx, model->layers[l].down, cur);
|
||||
}
|
||||
cur = ggml_add(ctx, cur, residualffn);
|
||||
inpL = cur;
|
||||
}
|
||||
|
||||
cur = orpheus_build_layer_norm(ctx, cur, model->output_norm);
|
||||
// only about 40k of the output head is actually uses for generation purposes. Ideally the head tensor should be shrunk and sampled tokens should be incremented.
|
||||
cur = ggml_mul_mat(ctx, model->head, cur);
|
||||
if (batch.n_tokens > 1) {
|
||||
cur = ggml_cont(ctx, ggml_view_1d(ctx, cur, model->vocab_size, ggml_element_size(cur) * (cur->ne[1] - 1) * model->vocab_size));
|
||||
}
|
||||
ggml_build_forward_expand(gf, cur);
|
||||
free_build();
|
||||
|
||||
return gf;
|
||||
}
|
||||
|
||||
void orpheus_runner::decode(orpheus_ubatch & batch) {
|
||||
ggml_backend_sched_reset(octx->sched);
|
||||
|
||||
octx->output_tokens.reserve(model->max_generation_size);
|
||||
|
||||
const size_t new_size = model->vocab_size * model->max_generation_size * sizeof(float);
|
||||
octx->prep_output_buffer(new_size);
|
||||
|
||||
ggml_cgraph * gf = build_orpheus_graph(batch);
|
||||
|
||||
// the output is always the last tensor in the graph
|
||||
struct ggml_tensor * res = gf->nodes[gf->n_nodes - 1];
|
||||
ggml_backend_sched_alloc_graph(octx->sched, gf);
|
||||
|
||||
set_inputs(batch);
|
||||
ggml_backend_sched_graph_compute_async(octx->sched, gf);
|
||||
|
||||
float * logits_out = octx->logits + octx->n_outputs * model->vocab_size;
|
||||
octx->get_ggml_node_data(res, logits_out, model->vocab_size * sizeof(float));
|
||||
|
||||
// update the total number of outputs retrieved and the current position
|
||||
octx->current_position += batch.n_tokens;
|
||||
|
||||
// Reset state for the next token before backend sync, to allow the CPU activities in the reset to
|
||||
// overlap with device computation.
|
||||
ggml_backend_sched_reset(octx->sched);
|
||||
}
|
||||
|
||||
void orpheus_runner::set_inputs(orpheus_ubatch & batch) {
|
||||
ggml_backend_tensor_set(octx->inp_tokens, batch.tokens.data(), 0, batch.tokens.size()*ggml_element_size(octx->inp_tokens));
|
||||
int32_t * pos = (int32_t*) octx->positions->data;
|
||||
float * mask = (float*) octx->attn_mask->data;
|
||||
uint32_t max_pos = octx->current_position + batch.n_tokens;
|
||||
for (int i = 0; i < batch.n_tokens; i++) {
|
||||
pos[i] = (int32_t) octx->current_position + i;
|
||||
for (int ii = 0; ii < max_pos; ii++) {
|
||||
mask[i*max_pos + ii] = ii > pos[i] ? -INFINITY : 0.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
orpheus_ubatch orpheus_runner::batch_from_sentence(std::string sentence) {
|
||||
struct orpheus_ubatch batch;
|
||||
for (auto t : orpheus_prepended_tokens) {
|
||||
batch.tokens.push_back(t);
|
||||
}
|
||||
if (!octx->voice.empty()) {
|
||||
sentence = octx->voice + ": " + sentence;
|
||||
}
|
||||
tokenizer->tokenize(sentence, batch.tokens);
|
||||
for (auto t : orpheus_appended_tokens) {
|
||||
batch.tokens.push_back(t);
|
||||
}
|
||||
batch.n_tokens = batch.tokens.size();
|
||||
return batch;
|
||||
}
|
||||
|
||||
std::vector<std::vector<uint32_t>> orpheus_runner::prepare_output_tokens() {
|
||||
size_t chunks = octx->output_tokens.size() / 7;
|
||||
std::vector<std::vector<uint32_t>> output_tokens;
|
||||
for (int i = 0; i < model->audio_heads; i++) {
|
||||
output_tokens.push_back(std::vector<uint32_t>{});
|
||||
}
|
||||
for (int i = 0; i < chunks; i++) {
|
||||
for (int ii = 0; ii < 7; ii++) {
|
||||
uint32_t thead = model->heads[ii];
|
||||
// the manipulations below are not configured because they are performed inline via undocumented constants in the Orpheus codebase.
|
||||
// Essentially this is how Orpheus converts discrete samples from the output shape to the audio input shape.
|
||||
uint32_t t = octx->output_tokens[i*7 + ii] - 128266 - ((ii % 7) * 4096);
|
||||
output_tokens[thead].push_back(t);
|
||||
}
|
||||
}
|
||||
return output_tokens;
|
||||
}
|
||||
|
||||
void orpheus_runner::generate_from_batch(orpheus_ubatch & batch, struct tts_response * output) {
|
||||
while ((octx->output_tokens.size() == 0 || octx->output_tokens.back() != model->stopping_token_id) && octx->output_tokens.size() < model->max_generation_size) {
|
||||
decode(batch);
|
||||
generation_sampler->sample(octx->logits + octx->n_outputs * model->vocab_size, octx->output_tokens);
|
||||
// only increment the output count after sampling
|
||||
octx->n_outputs++;
|
||||
batch = orpheus_ubatch{
|
||||
1, {octx->output_tokens.back()}
|
||||
};
|
||||
}
|
||||
// this case could be better addressed by adding spliting to the generation process.
|
||||
if (octx->output_tokens.size() >= model->max_generation_size) {
|
||||
fprintf(stdout, "Warning: generation hit its max default length. The generated audio may not contain the entire prompt.\n");
|
||||
}
|
||||
std::vector<std::vector<uint32_t>> processed_output_tokens = prepare_output_tokens();
|
||||
srunner->run(processed_output_tokens, output);
|
||||
}
|
||||
|
||||
int orpheus_runner::generate(std::string sentence, struct tts_response * response) {
|
||||
orpheus_ubatch batch = batch_from_sentence(sentence);
|
||||
// it should be possible to update the max context window size, but currently it is extremely unlikely that a single prompt will
|
||||
// surpass the default size.
|
||||
if (batch.tokens.size() > model->max_context_length) {
|
||||
TTS_ABORT("The prompt was too large for the default context window. Try splitting up or shortenning the prompt.");
|
||||
}
|
||||
octx->reset();
|
||||
generation_sampler->reset();
|
||||
if (!kv_self) {
|
||||
orpheus_kv_cache_init();
|
||||
}
|
||||
generate_from_batch(batch, response);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void orpheus_runner::configure_generation(generation_configuration * config) {
|
||||
generation_sampler->temperature = config->temperature;
|
||||
generation_sampler->repetition_penalty = config->repetition_penalty;
|
||||
generation_sampler->do_sample = config->sample;
|
||||
generation_sampler->top_k = config->top_k;
|
||||
generation_sampler->top_p = config->top_p;
|
||||
if (std::find(orpheus_voices.begin(), orpheus_voices.end(), config->voice) == orpheus_voices.end() && !config->voice.empty()) {
|
||||
TTS_ABORT("Voice '%s' is not a valid voice for Orpheus.", config->voice.c_str());
|
||||
}
|
||||
octx->voice = config->voice;
|
||||
}
|
||||
|
||||
orpheus_ubatch orpheus_runner::build_worst_case_batch() {
|
||||
orpheus_ubatch batch;
|
||||
batch.n_tokens = model->max_context_length;
|
||||
return batch;
|
||||
}
|
||||
|
||||
void orpheus_runner::assign_weight(std::string name, ggml_tensor * tensor) {
|
||||
if (tensor->data == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (name.size() == 0) {
|
||||
// handles the top level meta tensor
|
||||
return;
|
||||
}
|
||||
|
||||
if (name.size() > 5 && name.substr(0, 5) == "snac.") {
|
||||
srunner->model->assign_weight(name.substr(5), tensor);
|
||||
} else if (name.size() > 8 && name.substr(0, 8) == "orpheus.") {
|
||||
model->assign_weight(name.substr(8), tensor);
|
||||
} else {
|
||||
fprintf(stdout, "Warning: function %s encountered an unhandled tensor named '%s'.\n", __func__, name.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void orpheus_runner::prepare_post_load() {
|
||||
srunner->prepare_post_load();
|
||||
orpheus_kv_cache_init();
|
||||
auto batch = build_worst_case_batch();
|
||||
auto gf = build_orpheus_graph(batch);
|
||||
octx->prep_schedule(gf);
|
||||
}
|
||||
|
||||
std::vector<std::string> list_voices() {
|
||||
std::vector<std::string> voices;
|
||||
voices.reserve(orpheus_voices.size());
|
||||
for (auto voice : orpheus_voices) {
|
||||
voices.push_back(voice);
|
||||
}
|
||||
return voices;
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
#pragma once
|
||||
|
||||
#include "sampler.h"
|
||||
#include "tokenizer.h"
|
||||
#include "snac_model.h"
|
||||
|
||||
// Orpheus uses vLLM with a llama-3 architecture. The only critical difference from the normal llama architecture is the use of kv heads.
|
||||
|
||||
struct orpheus_layer {
|
||||
struct ggml_tensor * input_norm;
|
||||
struct ggml_tensor * post_attention_norm;
|
||||
struct ggml_tensor * q;
|
||||
struct ggml_tensor * k;
|
||||
struct ggml_tensor * v;
|
||||
struct ggml_tensor * o;
|
||||
struct ggml_tensor * gate;
|
||||
struct ggml_tensor * up;
|
||||
struct ggml_tensor * down;
|
||||
};
|
||||
|
||||
struct orpheus_model : tts_model {
|
||||
uint32_t vocab_size = 156940;
|
||||
uint32_t n_attn_heads = 24;
|
||||
uint32_t n_kv_attn_heads = 8;
|
||||
uint32_t head_size = 128;
|
||||
uint32_t max_context_length = 1024;
|
||||
// the generation size is technically arbitrary as the model can handle a large context. This size comes out to being 25.6 seconds.
|
||||
uint32_t max_generation_size = 2100;
|
||||
uint32_t stopping_token_id = 128258;
|
||||
uint32_t eos_token_id = 128001;
|
||||
uint32_t bos_token_id = 128000;
|
||||
uint32_t hidden_size = 3072;
|
||||
uint32_t kv_hidden_size = 1024;
|
||||
uint32_t audio_heads = 3;
|
||||
uint32_t heads[7] = {0, 1, 2, 2, 1, 2, 2};
|
||||
|
||||
int n_layers = 28;
|
||||
|
||||
struct std::vector<orpheus_layer> layers;
|
||||
struct ggml_tensor * head;
|
||||
struct ggml_tensor * embd;
|
||||
struct ggml_tensor * output_norm;
|
||||
struct ggml_tensor * rope_frequencies;
|
||||
|
||||
void assign_weight(std::string name, ggml_tensor * tensor);
|
||||
void assign_to_layer(std::string part, orpheus_layer & layer, struct ggml_tensor * tensor);
|
||||
void prep_constants(gguf_context * meta);
|
||||
void prep_layers(gguf_context * meta);
|
||||
void setup_from_file(gguf_context * meta_ctx, ggml_context * load_context, bool cpu_only) {
|
||||
prep_constants(meta_ctx);
|
||||
prep_layers(meta_ctx);
|
||||
tts_model::setup_from_file(meta_ctx, load_context, cpu_only, "orpheus", 1.30);
|
||||
}
|
||||
};
|
||||
|
||||
struct orpheus_context : runner_context {
|
||||
orpheus_context(orpheus_model * model, int n_threads): runner_context(n_threads), model(model) {};
|
||||
struct orpheus_model * model;
|
||||
|
||||
uint32_t current_position = 0; // current position in the active sequence
|
||||
uint32_t n_outputs = 0; // the position of the text prompt termination (used for adjusting the cache when incrementally generating)
|
||||
std::string voice;
|
||||
|
||||
std::vector<uint32_t> output_tokens;
|
||||
|
||||
void reset();
|
||||
void build_schedule() {
|
||||
runner_context::build_schedule(model->max_nodes());
|
||||
}
|
||||
|
||||
struct ggml_tensor * inp_tokens;
|
||||
struct ggml_tensor * attn_mask;
|
||||
struct ggml_tensor * positions;
|
||||
};
|
||||
|
||||
struct orpheus_kv_cache {
|
||||
ggml_type cache_type = GGML_TYPE_F32;
|
||||
|
||||
std::vector<struct ggml_tensor *> k_l;
|
||||
std::vector<struct ggml_tensor *> v_l;
|
||||
|
||||
struct ggml_context * ctx;
|
||||
ggml_backend_buffer_type_t buft;
|
||||
ggml_backend_buffer_t buf;
|
||||
|
||||
void free() {
|
||||
ggml_free(ctx);
|
||||
ggml_backend_buffer_free(buf);
|
||||
}
|
||||
|
||||
~orpheus_kv_cache() {
|
||||
free();
|
||||
}
|
||||
};
|
||||
|
||||
struct orpheus_context * build_new_orpheus_context(struct orpheus_model * model, int n_threads, bool use_cpu = true);
|
||||
|
||||
struct orpheus_ubatch {
|
||||
orpheus_ubatch() = default;
|
||||
orpheus_ubatch(size_t n_tokens, std::vector<uint32_t> tokens): n_tokens(n_tokens), tokens(tokens) {};
|
||||
size_t n_tokens; // total sentence tokens
|
||||
std::vector<uint32_t> tokens; // [n_tokens]
|
||||
};
|
||||
|
||||
struct orpheus_runner : tts_runner {
|
||||
orpheus_runner(
|
||||
orpheus_model * model,
|
||||
snac_runner * audio_decoder,
|
||||
orpheus_context * octx,
|
||||
bpe_tokenizer * bt,
|
||||
sampler * samp,
|
||||
orpheus_kv_cache * cache): model(model), srunner(audio_decoder), octx(octx), tokenizer(bt), generation_sampler(samp), kv_self(cache) {
|
||||
tts_runner::sampling_rate = 24000.0f;
|
||||
generation_sampler->n_output_heads = 1;
|
||||
generation_sampler->vocab_size = model->vocab_size;
|
||||
generation_sampler->eos_token_id = model->eos_token_id;
|
||||
}
|
||||
orpheus_model * model;
|
||||
snac_runner * srunner;
|
||||
orpheus_context * octx;
|
||||
bpe_tokenizer * tokenizer;
|
||||
orpheus_kv_cache * kv_self;
|
||||
sampler * generation_sampler;
|
||||
|
||||
void init_build() {
|
||||
tts_runner::init_build(&octx->buf_compute_meta);
|
||||
}
|
||||
|
||||
std::vector<std::string> list_voices();
|
||||
struct ggml_cgraph * build_orpheus_graph(orpheus_ubatch & batch);
|
||||
void orpheus_kv_cache_init();
|
||||
void orpheus_build_kv_store(struct ggml_context * ctx, struct ggml_cgraph * graph, struct ggml_tensor * k_cur, struct ggml_tensor * v_cur, int index, uint32_t n_tokens, int repeat);
|
||||
void configure_generation(generation_configuration * config);
|
||||
void assign_weight(std::string name, ggml_tensor * tensor);
|
||||
std::vector<std::vector<uint32_t>> prepare_output_tokens();
|
||||
orpheus_ubatch build_worst_case_batch();
|
||||
orpheus_ubatch batch_from_sentence(std::string sentence);
|
||||
void set_inputs(orpheus_ubatch & batch);
|
||||
void decode(orpheus_ubatch & batch);
|
||||
void prepare_post_load();
|
||||
int generate(std::string sentence, struct tts_response * response);
|
||||
void generate_from_batch(orpheus_ubatch & batch, struct tts_response * output);
|
||||
};
|
||||
|
||||
static struct ggml_tensor * orpheus_build_layer_norm(ggml_context * ctx, struct ggml_tensor * x, struct ggml_tensor * weight);
|
||||
static struct ggml_tensor * build_attn_mask(ggml_context * ctx, orpheus_context * octx, orpheus_ubatch & batch);
|
||||
@@ -0,0 +1,874 @@
|
||||
#include "parler_model.h"
|
||||
|
||||
// For loading parler model from gguf file.
|
||||
static const std::map<std::string, parler_tensor> PARLER_TENSOR_GGUF_LOOKUP = {
|
||||
{"layer_norm.weight", PARLER_NORM},
|
||||
{"layer_norm.bias", PARLER_NORM_BIAS},
|
||||
{"embed_prompts", PARLER_EMBD_PROMPTS},
|
||||
{"text_encoding", PARLER_TEXT_ENCODING},
|
||||
{"positional_embed", PARLER_POSITIONAL_EMBD},
|
||||
{".self_attn.q_proj.weight", PARLER_LAYER_SELF_ATTN_Q},
|
||||
{".self_attn.k_proj.weight", PARLER_LAYER_SELF_ATTN_K},
|
||||
{".self_attn.v_proj.weight", PARLER_LAYER_SELF_ATTN_V},
|
||||
{".self_attn.out_proj.weight", PARLER_LAYER_SELF_ATTN_O},
|
||||
{".self_attn_layer_norm.weight", PARLER_LAYER_SELF_ATTN_NORM},
|
||||
{".self_attn_layer_norm.bias", PARLER_LAYER_SELF_ATTN_NORM_BIAS},
|
||||
{".encoder_attn.q_proj.weight", PARLER_LAYER_ATTN_Q},
|
||||
{".encoder_attn.k_proj.weight", PARLER_LAYER_ATTN_K},
|
||||
{".encoder_attn.v_proj.weight", PARLER_LAYER_ATTN_V},
|
||||
{".encoder_attn.out_proj.weight", PARLER_LAYER_ATTN_O},
|
||||
{".encoder_attn_layer_norm.weight", PARLER_LAYER_ATTN_NORM},
|
||||
{".encoder_attn_layer_norm.bias", PARLER_LAYER_ATTN_NORM_BIAS},
|
||||
{".fc1.weight", PARLER_LAYER_FC1},
|
||||
{".fc2.weight", PARLER_LAYER_FC2},
|
||||
{".final_layer_norm.weight", PARLER_LAYER_OUT_NORM},
|
||||
{".final_layer_norm.bias", PARLER_LAYER_OUT_NORM_BIAS},
|
||||
{".weight", PARLER_EMBD},
|
||||
{".weight.head", PARLER_HEAD}
|
||||
};
|
||||
|
||||
void parler_tts_model::assign_weight(std::string name, ggml_tensor * tensor) {
|
||||
assign_to_decoder(this, name, tensor);
|
||||
}
|
||||
|
||||
void parler_tts_model::prep_layers(gguf_context * meta_ctx) {
|
||||
layers.reserve((size_t) n_layers);
|
||||
for (int i = 0; i < (int) n_layers; i++) {
|
||||
parler_layer * l = new parler_layer{};
|
||||
layers.push_back(l);
|
||||
}
|
||||
|
||||
embds.reserve((size_t) n_output_heads);
|
||||
heads.reserve((size_t) n_output_heads);
|
||||
for (int i = 0; i < n_output_heads; i++) {
|
||||
struct ggml_tensor * h = nullptr;
|
||||
struct ggml_tensor * embd = nullptr;
|
||||
embds.push_back(embd);
|
||||
heads.push_back(h);
|
||||
}
|
||||
}
|
||||
|
||||
void parler_tts_model::prep_constants(gguf_context * meta) {
|
||||
int encode_length_key = search_for_gguf_keys(meta, {"parler-tts.decoder.encode_length", "encode_length"});
|
||||
if (encode_length_key == -1) {
|
||||
TTS_ABORT("key 'parler-tts.decoder.encode_length' must be specified in gguf file.");
|
||||
}
|
||||
n_encode_length = gguf_get_val_u32(meta, encode_length_key);
|
||||
|
||||
int hidden_size_key = search_for_gguf_keys(meta, {"parler-tts.decoder.hidden_size", "hidden_size"});
|
||||
if (hidden_size_key != -1) {
|
||||
hidden_size = gguf_get_val_u32(meta, hidden_size_key);
|
||||
}
|
||||
|
||||
int output_heads_key = search_for_gguf_keys(meta, {"parler-tts.decoder.output_heads", "output_heads"});
|
||||
if (output_heads_key != -1) {
|
||||
n_output_heads = gguf_get_val_u32(meta, output_heads_key);
|
||||
}
|
||||
int ctx_length_key = search_for_gguf_keys(meta, {"parler-tts.decoder.context_length", "ctx_length"});
|
||||
if (ctx_length_key != -1) {
|
||||
max_ctx_length = gguf_get_val_u32(meta, ctx_length_key);
|
||||
}
|
||||
|
||||
int attn_heads_key = search_for_gguf_keys(meta, {"parler-tts.decoder.attention.head_count", "attn_heads"});
|
||||
if (attn_heads_key != -1) {
|
||||
n_attn_heads = gguf_get_val_u32(meta, attn_heads_key);
|
||||
}
|
||||
head_size = hidden_size / n_attn_heads;
|
||||
max_cross_nodes = n_attn_heads * 2;
|
||||
|
||||
int output_vocab_size_key = search_for_gguf_keys(meta, {"parler-tts.decoder.out_vocab_size", "out_vocab_size"});
|
||||
if (output_vocab_size_key != -1) {
|
||||
output_vocab_size = gguf_get_val_u32(meta, output_vocab_size_key);
|
||||
}
|
||||
|
||||
int audio_vocab_size_key = search_for_gguf_keys(meta, {"parler-tts.decoder.audio_vocab_size", "audio_vocab_size"});
|
||||
if (audio_vocab_size_key != -1) {
|
||||
audio_vocab_size = gguf_get_val_u32(meta, audio_vocab_size_key);
|
||||
}
|
||||
|
||||
int max_gen_key = search_for_gguf_keys(meta, {"parler-tts.decoder.max_generation", "max_generation"});
|
||||
if (max_gen_key != -1) {
|
||||
max_generation_size = gguf_get_val_u32(meta, max_gen_key);
|
||||
}
|
||||
|
||||
int n_layers_key = search_for_gguf_keys(meta, {"parler-tts.decoder.num_hidden_layers", "num_hidden_layers"});
|
||||
if (n_layers_key != -1) {
|
||||
n_layers = gguf_get_val_u32(meta, n_layers_key);
|
||||
}
|
||||
|
||||
int bos_token_id_key = search_for_gguf_keys(meta, {"audio.bos_token_id", "bos_token_id"});
|
||||
if (bos_token_id_key != -1) {
|
||||
bos_token_id = gguf_get_val_u32(meta, bos_token_id_key);
|
||||
}
|
||||
|
||||
int eos_token_id_key = search_for_gguf_keys(meta, {"audio.eos_token_id", "eos_token_id"});
|
||||
if (eos_token_id_key != -1) {
|
||||
eos_token_id = gguf_get_val_u32(meta, eos_token_id_key);
|
||||
}
|
||||
}
|
||||
|
||||
void parler_tts_model::prep_cross_key_values(int n_threads, struct tts_response * conditional_prompt) {
|
||||
ggml_backend_t backend_cpu = ggml_backend_cpu_init();
|
||||
ggml_backend_buffer_type_t backend_cpu_buffer = ggml_backend_cpu_buffer_type();
|
||||
// Let it create a disposable threadpool just this once
|
||||
ggml_backend_cpu_set_n_threads(backend_cpu, n_threads);
|
||||
std::vector<ggml_backend_buffer_type_t> bufs = {backend_cpu_buffer};
|
||||
std::vector<ggml_backend_t> backs = {backend_cpu};
|
||||
ggml_backend_sched_t sched = ggml_backend_sched_new(backs.data(), bufs.data(), 1, max_cross_nodes*n_layers, false, false);
|
||||
|
||||
std::vector<uint8_t> buf_compute_meta;
|
||||
buf_compute_meta.resize(max_cross_nodes*n_layers*ggml_tensor_overhead() + ggml_graph_overhead_custom(max_cross_nodes*n_layers, false));
|
||||
|
||||
struct ggml_init_params params = {
|
||||
/*.mem_size =*/ buf_compute_meta.size(),
|
||||
/*.mem_buffer =*/ buf_compute_meta.data(),
|
||||
/*.no_alloc =*/ true,
|
||||
};
|
||||
struct ggml_context * cctx = ggml_init(params);
|
||||
struct ggml_cgraph * gf = ggml_new_graph_custom(cctx, 4096, false);
|
||||
if (conditional_prompt) {
|
||||
// If we are updating the conditional prompt then we have to reset the tensor offsets into the ggml_context otherwise we could overflow the assigned buffer and lose our prompt.
|
||||
// These offsets are assigned by #set_tensor below.
|
||||
offset -= n_encode_length*hidden_size*sizeof(float)*n_layers*2;
|
||||
precomputed_input_emb = ggml_new_tensor_2d(cctx, GGML_TYPE_F32, conditional_prompt->hidden_size, conditional_prompt->n_outputs);
|
||||
ggml_set_input(precomputed_input_emb);
|
||||
n_encode_length = conditional_prompt->n_outputs;
|
||||
}
|
||||
|
||||
for (int i = 0; i < layers.size(); i++) {
|
||||
struct ggml_tensor * Kcur = ggml_mul_mat(cctx, layers[i]->attn_k_proj, precomputed_input_emb);
|
||||
struct ggml_tensor * Vcur = ggml_mul_mat(cctx, layers[i]->attn_v_proj, precomputed_input_emb);
|
||||
|
||||
Kcur = ggml_reshape_3d(cctx, Kcur, head_size, n_attn_heads, n_encode_length);
|
||||
Vcur = ggml_transpose(cctx, Vcur);
|
||||
|
||||
struct ggml_tensor * k = ggml_cont(cctx, ggml_permute(cctx, Kcur, 0, 2, 1, 3));
|
||||
ggml_set_name(k, ("cross_key_" + std::to_string(i)).c_str());
|
||||
ggml_build_forward_expand(gf, k);
|
||||
|
||||
struct ggml_tensor * v = ggml_cont_3d(cctx, Vcur, n_encode_length, head_size, n_attn_heads);
|
||||
ggml_set_name(v, ("cross_value_" + std::to_string(i)).c_str());
|
||||
ggml_build_forward_expand(gf, v);
|
||||
}
|
||||
|
||||
ggml_free(cctx);
|
||||
ggml_backend_sched_reserve(sched, gf);
|
||||
ggml_backend_sched_alloc_graph(sched, gf);
|
||||
if (conditional_prompt) {
|
||||
ggml_backend_tensor_set(precomputed_input_emb, conditional_prompt->data, 0, conditional_prompt->n_outputs*conditional_prompt->hidden_size*ggml_element_size(precomputed_input_emb));
|
||||
}
|
||||
|
||||
ggml_backend_sched_graph_compute_async(sched, gf);
|
||||
|
||||
for (int i = 0; i < layers.size(); i++) {
|
||||
struct ggml_tensor * k = ggml_graph_get_tensor(gf, ("cross_key_" + std::to_string(i)).c_str());
|
||||
layers[i]->cross_k = ggml_dup_tensor(ctx, k);
|
||||
set_tensor(layers[i]->cross_k, k);
|
||||
struct ggml_tensor * v = ggml_graph_get_tensor(gf, ("cross_value_" + std::to_string(i)).c_str());
|
||||
layers[i]->cross_v = ggml_dup_tensor(ctx, v);
|
||||
set_tensor(layers[i]->cross_v, v);
|
||||
}
|
||||
ggml_backend_sched_free(sched);
|
||||
ggml_backend_free(backend_cpu);
|
||||
}
|
||||
|
||||
void assign_parler_layer(parler_tts_model * model, parler_layer * layer, std::string name, ggml_tensor * tensor) {
|
||||
try {
|
||||
switch(PARLER_TENSOR_GGUF_LOOKUP.at(name)) {
|
||||
case PARLER_LAYER_SELF_ATTN_Q:
|
||||
layer->self_attn_q_proj = ggml_dup_tensor(model->ctx, tensor);
|
||||
model->set_tensor(layer->self_attn_q_proj, tensor);
|
||||
break;
|
||||
case PARLER_LAYER_SELF_ATTN_K:
|
||||
layer->self_attn_k_proj = ggml_dup_tensor(model->ctx, tensor);
|
||||
model->set_tensor(layer->self_attn_k_proj, tensor);
|
||||
break;
|
||||
case PARLER_LAYER_SELF_ATTN_V:
|
||||
layer->self_attn_v_proj = ggml_dup_tensor(model->ctx, tensor);
|
||||
model->set_tensor(layer->self_attn_v_proj, tensor);
|
||||
break;
|
||||
case PARLER_LAYER_SELF_ATTN_O:
|
||||
layer->self_attn_o_proj = ggml_dup_tensor(model->ctx, tensor);
|
||||
model->set_tensor(layer->self_attn_o_proj, tensor);
|
||||
break;
|
||||
case PARLER_LAYER_SELF_ATTN_NORM:
|
||||
layer->self_attn_norm = ggml_dup_tensor(model->ctx, tensor);
|
||||
model->set_tensor(layer->self_attn_norm, tensor);
|
||||
break;
|
||||
case PARLER_LAYER_SELF_ATTN_NORM_BIAS:
|
||||
layer->self_attn_norm_bias = ggml_dup_tensor(model->ctx, tensor);
|
||||
model->set_tensor(layer->self_attn_norm_bias, tensor);
|
||||
break;
|
||||
case PARLER_LAYER_ATTN_Q:
|
||||
if (model->use_cross_attn) {
|
||||
layer->attn_q_proj = ggml_dup_tensor(model->ctx, tensor);
|
||||
model->set_tensor(layer->attn_q_proj, tensor);
|
||||
}
|
||||
break;
|
||||
case PARLER_LAYER_ATTN_K:
|
||||
if (model->use_cross_attn) {
|
||||
layer->attn_k_proj = ggml_dup_tensor(model->ctx, tensor);
|
||||
model->set_tensor(layer->attn_k_proj, tensor);
|
||||
}
|
||||
break;
|
||||
case PARLER_LAYER_ATTN_V:
|
||||
if (model->use_cross_attn) {
|
||||
layer->attn_v_proj = ggml_dup_tensor(model->ctx, tensor);
|
||||
model->set_tensor(layer->attn_v_proj, tensor);
|
||||
}
|
||||
break;
|
||||
case PARLER_LAYER_ATTN_O:
|
||||
if (model->use_cross_attn) {
|
||||
layer->attn_o_proj = ggml_dup_tensor(model->ctx, tensor);
|
||||
model->set_tensor(layer->attn_o_proj, tensor);
|
||||
}
|
||||
break;
|
||||
case PARLER_LAYER_ATTN_NORM:
|
||||
if (model->use_cross_attn) {
|
||||
layer->attn_norm = ggml_dup_tensor(model->ctx, tensor);
|
||||
model->set_tensor(layer->attn_norm, tensor);
|
||||
}
|
||||
break;
|
||||
case PARLER_LAYER_ATTN_NORM_BIAS:
|
||||
if (model->use_cross_attn) {
|
||||
layer->attn_norm_bias = ggml_dup_tensor(model->ctx, tensor);
|
||||
model->set_tensor(layer->attn_norm_bias, tensor);
|
||||
}
|
||||
break;
|
||||
case PARLER_LAYER_FC1:
|
||||
layer->fc1 = ggml_dup_tensor(model->ctx, tensor);
|
||||
model->set_tensor(layer->fc1, tensor);
|
||||
break;
|
||||
case PARLER_LAYER_FC2:
|
||||
layer->fc2 = ggml_dup_tensor(model->ctx, tensor);
|
||||
model->set_tensor(layer->fc2, tensor);
|
||||
break;
|
||||
case PARLER_LAYER_OUT_NORM:
|
||||
layer->final_norm = ggml_dup_tensor(model->ctx, tensor);
|
||||
model->set_tensor(layer->final_norm, tensor);
|
||||
break;
|
||||
case PARLER_LAYER_OUT_NORM_BIAS:
|
||||
layer->final_norm_bias = ggml_dup_tensor(model->ctx, tensor);
|
||||
model->set_tensor(layer->final_norm_bias, tensor);
|
||||
break;
|
||||
default:
|
||||
fprintf(stdout, "unassigned tensor %s\n", name.c_str());
|
||||
break;
|
||||
}
|
||||
} catch (const std::out_of_range& e) {
|
||||
TTS_ABORT("Error: %s\nTensor, '%s', is not a valid tensor.", e.what(), name.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void assign_to_decoder(parler_tts_model * model, const std::string name, ggml_tensor * tensor) {
|
||||
if (PARLER_TENSOR_GGUF_LOOKUP.find(name) != PARLER_TENSOR_GGUF_LOOKUP.end()) {
|
||||
try {
|
||||
switch (PARLER_TENSOR_GGUF_LOOKUP.at(name)) {
|
||||
case PARLER_NORM:
|
||||
model->layer_norm = ggml_dup_tensor(model->ctx, tensor);
|
||||
model->set_tensor(model->layer_norm, tensor);
|
||||
break;
|
||||
case PARLER_NORM_BIAS:
|
||||
model->layer_norm_bias = ggml_dup_tensor(model->ctx, tensor);
|
||||
model->set_tensor(model->layer_norm_bias, tensor);
|
||||
break;
|
||||
case PARLER_EMBD_PROMPTS:
|
||||
model->prompt_embd = ggml_dup_tensor(model->ctx, tensor);
|
||||
model->set_tensor(model->prompt_embd, tensor);
|
||||
break;
|
||||
case PARLER_TEXT_ENCODING:
|
||||
if (model->use_cross_attn) {
|
||||
model->precomputed_input_emb = ggml_dup_tensor(model->ctx, tensor);
|
||||
model->set_tensor(model->precomputed_input_emb, tensor);
|
||||
}
|
||||
break;
|
||||
case PARLER_POSITIONAL_EMBD:
|
||||
model->precomputed_positional_embds = ggml_dup_tensor(model->ctx, tensor);
|
||||
model->set_tensor(model->precomputed_positional_embds, tensor);
|
||||
break;
|
||||
default:
|
||||
fprintf(stdout, "unassigned tensor %s\n", name.c_str());
|
||||
break;
|
||||
}
|
||||
} catch (const std::out_of_range& e) {
|
||||
TTS_ABORT("Error: %s\nTensor, '%s', is not a valid tensor.", e.what(), name.c_str());
|
||||
}
|
||||
} else if (std::find_if(name.begin(), name.end(), ::isdigit) != name.end()) {
|
||||
auto pair = parse_layer_count(name);
|
||||
int layer = pair.first;
|
||||
std::string lt_name = pair.second;
|
||||
if (name.find("embed_tokens") != std::string::npos) {
|
||||
model->embds[layer] = ggml_dup_tensor(model->ctx, tensor);
|
||||
model->set_tensor(model->embds[layer], tensor);
|
||||
} else if (name.find("lm_heads") != std::string::npos) {
|
||||
model->heads[layer] = ggml_dup_tensor(model->ctx, tensor);
|
||||
model->set_tensor(model->heads[layer], tensor);
|
||||
} else {
|
||||
assign_parler_layer(model, model->layers[layer], lt_name, tensor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void parler_context::reset(int32_t n_output_heads) {
|
||||
n_outputs = 0;
|
||||
prompt_end_position = 0;
|
||||
current_position = 0;
|
||||
output_size = 0;
|
||||
output_tokens.clear();
|
||||
eos_seen.clear();
|
||||
for (int i = 0; i < (int) n_output_heads; i++) {
|
||||
eos_seen.push_back(false);
|
||||
}
|
||||
}
|
||||
|
||||
struct parler_context * build_new_parler_context(struct parler_tts_model * model, int n_threads, bool use_cpu) {
|
||||
parler_context * pctx = new parler_context(model, n_threads);
|
||||
if (!use_cpu) {
|
||||
#ifdef GGML_USE_METAL
|
||||
pctx->backend = ggml_backend_metal_init();
|
||||
#endif
|
||||
}
|
||||
pctx->eos_seen.reserve(model->n_output_heads);
|
||||
pctx->backend_cpu = ggml_backend_cpu_init();
|
||||
pctx->set_threads();
|
||||
pctx->build_schedule();
|
||||
pctx->buf_compute_meta.resize(ggml_tensor_overhead()*model->max_nodes() + ggml_graph_overhead_custom(model->max_nodes(), false));
|
||||
return pctx;
|
||||
}
|
||||
|
||||
static bool parler_kv_cache_init(struct parler_kv_cache * cache, parler_tts_model * model, parler_context * pctx, int32_t seq_id) {
|
||||
const int64_t n_layer = (int64_t) model->layers.size();
|
||||
cache->seq_id = seq_id;
|
||||
|
||||
ggml_backend_buffer_type_t buft = nullptr;
|
||||
// this will only really support cpu or metal for the time being;
|
||||
if (pctx->backend != nullptr) {
|
||||
#ifdef GGML_USE_METAL
|
||||
buft = ggml_backend_metal_buffer_type();
|
||||
#endif
|
||||
} else {
|
||||
buft = ggml_backend_cpu_buffer_type();
|
||||
}
|
||||
|
||||
struct ggml_init_params params = {
|
||||
/*.mem_size =*/ (2u*model->n_layers+1)*ggml_tensor_overhead(),
|
||||
/*.mem_buffer =*/ NULL,
|
||||
/*.no_alloc =*/ true,
|
||||
};
|
||||
ggml_context * ctx = ggml_init(params);
|
||||
if (!ctx) {
|
||||
return false;
|
||||
}
|
||||
cache->ctx = ctx;
|
||||
|
||||
|
||||
cache->k_l.reserve(n_layer);
|
||||
cache->v_l.reserve(n_layer);
|
||||
|
||||
for (int i = 0; i < (int) n_layer; i++) {
|
||||
ggml_tensor * k = ggml_new_tensor_1d(cache->ctx, cache->type_k, model->hidden_size*model->max_ctx_length);
|
||||
ggml_tensor * v = ggml_new_tensor_1d(cache->ctx, cache->type_v, model->hidden_size*model->max_ctx_length);
|
||||
ggml_format_name(k, "cache_k_l%d", i);
|
||||
ggml_format_name(v, "cache_v_l%d", i);
|
||||
cache->k_l.push_back(k);
|
||||
cache->v_l.push_back(v);
|
||||
}
|
||||
|
||||
// allocate tensors and initialize the buffers to avoid NaNs in the padding
|
||||
ggml_backend_buffer_t buf = ggml_backend_alloc_ctx_tensors_from_buft(cache->ctx, buft);
|
||||
if (!buf) {
|
||||
return false;
|
||||
}
|
||||
ggml_backend_buffer_clear(buf, 0);
|
||||
cache->buf = buf;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
struct ggml_tensor * parler_build_inp_embd(struct ggml_context * ctx, struct parler_context * pctx, parler_tts_model * model, parler_ubatch & batch) {
|
||||
// Parler has two embedding schemas one for the text input and one for generative audio tokens. These two schemas have effectively distinct shapes (i.e. [batch_size, sequence_length] and [batch_size, sequence_lenghth, num_codebooks] respectively).
|
||||
// This means that depending on where we are in generation we need to follow a distinct pattern
|
||||
struct ggml_tensor * input_embs;
|
||||
pctx->positions = ggml_new_tensor_1d(ctx, GGML_TYPE_I32, batch.sequence_length);
|
||||
ggml_set_input(pctx->positions);
|
||||
if (batch.audio_generation) {
|
||||
pctx->audio_inp_tokens = ggml_reshape_2d(ctx, ggml_new_tensor_1d(ctx, GGML_TYPE_I32, batch.n_audio_tokens), batch.n_audio_tokens / model->n_output_heads, model->n_output_heads);
|
||||
ggml_set_input(pctx->audio_inp_tokens);
|
||||
struct ggml_tensor * audio_tokens = ggml_reshape_2d(ctx, pctx->audio_inp_tokens, batch.n_audio_tokens / model->n_output_heads, model->n_output_heads);
|
||||
for (int i = 0; i < model->n_output_heads; i++) {
|
||||
if (i == 0) {
|
||||
input_embs = ggml_get_rows(ctx, model->embds[i], ggml_view_2d(ctx, audio_tokens, 1, batch.n_audio_tokens / model->n_output_heads, audio_tokens->nb[1], i*sizeof(int32_t)));
|
||||
} else {
|
||||
input_embs = ggml_add(ctx, ggml_get_rows(ctx, model->embds[i], ggml_view_2d(ctx, audio_tokens, 1, batch.n_audio_tokens / model->n_output_heads, audio_tokens->nb[1], i*sizeof(int32_t))), input_embs);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
pctx->inp_tokens = ggml_new_tensor_1d(ctx, GGML_TYPE_I32, batch.n_tokens);
|
||||
ggml_set_input(pctx->inp_tokens);
|
||||
input_embs = ggml_get_rows(ctx, model->prompt_embd, pctx->inp_tokens);
|
||||
}
|
||||
return ggml_add(ctx, input_embs, ggml_get_rows(ctx, model->precomputed_positional_embds, pctx->positions));
|
||||
}
|
||||
|
||||
struct ggml_tensor * parler_build_layer_norm(struct ggml_context * ctx, struct ggml_tensor * inputs, struct ggml_tensor * weight, struct ggml_tensor * bias) {
|
||||
// parler always uses default eps
|
||||
float eps = 0.00001;
|
||||
inputs = ggml_norm(ctx, inputs, eps);
|
||||
inputs = ggml_mul(ctx, inputs, weight);
|
||||
return ggml_add(ctx, inputs, bias);
|
||||
}
|
||||
|
||||
void parler_build_kv_store(struct ggml_context * ctx, parler_kv_cache * kv, struct ggml_cgraph * graph, struct ggml_tensor * k_cur, struct ggml_tensor * v_cur, int32_t n_tokens, int32_t kv_head, int32_t index, int32_t n_embd_gqa) {
|
||||
// this is the max context size;
|
||||
const int64_t n_ctx = 4096;
|
||||
|
||||
struct ggml_tensor * k_cache_view = ggml_view_1d(ctx, kv->k_l[index], n_tokens*n_embd_gqa, ggml_row_size(kv->k_l[index]->type, n_embd_gqa)*kv_head);
|
||||
|
||||
ggml_build_forward_expand(graph, ggml_cpy(ctx, k_cur, k_cache_view));
|
||||
|
||||
assert(v_cur->ne[0] == n_embd_gqa && v_cur->ne[1] == n_tokens);
|
||||
|
||||
struct ggml_tensor * v_cache_view = nullptr;
|
||||
|
||||
v_cache_view = ggml_view_2d(ctx, kv->v_l[index], n_tokens, n_embd_gqa,
|
||||
( n_ctx)*ggml_element_size(kv->v_l[index]),
|
||||
(kv_head)*ggml_element_size(kv->v_l[index]));
|
||||
|
||||
v_cur = ggml_cont(ctx, ggml_transpose(ctx, v_cur));
|
||||
|
||||
ggml_build_forward_expand(graph, ggml_cpy(ctx, v_cur, v_cache_view));
|
||||
}
|
||||
|
||||
struct ggml_tensor * parler_build_head_outputs(struct ggml_context * ctx, parler_tts_model * model, struct ggml_tensor * cur) {
|
||||
// going to cat the heads together and then reshape them;
|
||||
// honestly ggml doesn't provide good support for stacking and discrete tensor access
|
||||
struct ggml_tensor * out;
|
||||
for (int i = 0; i < model->n_output_heads; i++) {
|
||||
if (i == 0) {
|
||||
out = ggml_mul_mat(ctx, model->heads[i], cur);
|
||||
} else {
|
||||
out = ggml_concat(ctx, out, ggml_mul_mat(ctx, model->heads[i], cur), 1);
|
||||
}
|
||||
}
|
||||
ggml_set_name(out, "final_out");
|
||||
//out = ggml_cont(ctx, ggml_transpose(ctx, out));
|
||||
|
||||
int32_t sql_len = (int32_t) (ggml_nelements(out) / (model->output_vocab_size * model->n_output_heads));
|
||||
return ggml_cont_3d(ctx, out, model->output_vocab_size, sql_len, model->n_output_heads);
|
||||
}
|
||||
|
||||
struct ggml_tensor * build_attn_mask(ggml_context * ctx, parler_context * pctx, parler_ubatch & batch) {
|
||||
pctx->attn_mask = ggml_new_tensor_2d(ctx, GGML_TYPE_F32, (int64_t) pctx->current_position + batch.sequence_length, (int64_t) pctx->current_position + batch.sequence_length);
|
||||
ggml_set_input(pctx->attn_mask);
|
||||
|
||||
return pctx->attn_mask;
|
||||
}
|
||||
|
||||
struct ggml_tensor * build_attn_mask_cross(ggml_context * ctx, parler_context * pctx, parler_tts_model * model, parler_ubatch & batch) {
|
||||
pctx->attn_mask_cross = ggml_new_tensor_2d(ctx, GGML_TYPE_F32, (int64_t) model->n_encode_length, (int64_t) batch.sequence_length);
|
||||
ggml_set_input(pctx->attn_mask_cross);
|
||||
|
||||
return pctx->attn_mask_cross;
|
||||
}
|
||||
|
||||
static struct parler_ubatch batch_from_sentence(std::string sentence, parler_tts_model * model, unigram_tokenizer * tokenizer) {
|
||||
struct parler_ubatch batch;
|
||||
batch.audio_generation = false;
|
||||
std::vector<uint32_t>* token_ids = new std::vector<uint32_t>;
|
||||
tokenizer->tokenize(sentence, *token_ids);
|
||||
token_ids->push_back(tokenizer->eos_token);
|
||||
batch.current_step = 0;
|
||||
batch.n_tokens = token_ids->size();
|
||||
batch.n_audio_tokens = 0;
|
||||
batch.sequence_length = batch.n_tokens; // sequence_length is equal to the number of tokens for non-audio generation
|
||||
std::vector<uint32_t>* position = new std::vector<uint32_t>;
|
||||
for (uint32_t i = 0; i < batch.sequence_length; i++) {
|
||||
position->push_back(i);
|
||||
}
|
||||
std::vector<uint32_t>* order = new std::vector<uint32_t>;
|
||||
for (int i = 0; i < batch.sequence_length; i++) {
|
||||
if (i >= batch.sequence_length - 1) {
|
||||
order->push_back(0);
|
||||
} else {
|
||||
order->push_back(i+1);
|
||||
}
|
||||
}
|
||||
batch.positions = position->data();
|
||||
batch.tokens = token_ids->data();
|
||||
return batch;
|
||||
}
|
||||
|
||||
void parler_tts_runner::assign_weight(std::string name, ggml_tensor * tensor) {
|
||||
std::string::size_type pos = name.find(".", 0);
|
||||
std::string top_level(name.substr(0, pos));
|
||||
std::string value(name.substr(pos + 1));
|
||||
if (tensor->data == NULL) {
|
||||
return;
|
||||
}
|
||||
if (top_level == "audio_encoder") {
|
||||
dac_runner->model->assign_weight(value, tensor);
|
||||
} else if (top_level == "decoder") {
|
||||
model->assign_weight(value, tensor);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void parler_tts_runner::update_conditional_prompt(const std::string file_path, const std::string prompt, int n_threads, bool cpu_only) {
|
||||
t5_runner * text_encoder = text_encoder_from_file(file_path, n_threads, tokenizer, cpu_only);
|
||||
tts_response* response;
|
||||
text_encoder->generate(prompt, response);
|
||||
model->prep_cross_key_values(n_threads, response);
|
||||
delete text_encoder;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
struct ggml_cgraph * parler_tts_runner::build_parler_graph(parler_ubatch & batch) {
|
||||
init_build();
|
||||
struct ggml_cgraph * gf = ggml_new_graph_custom(ctx, 8192, false);
|
||||
|
||||
struct ggml_tensor * cur;
|
||||
struct ggml_tensor * inpL;
|
||||
|
||||
const int32_t full_sequence_length = pctx->current_position + (uint32_t) batch.sequence_length;
|
||||
|
||||
inpL = parler_build_inp_embd(ctx, pctx, model, batch);
|
||||
|
||||
struct ggml_tensor * KQ_mask_dec = build_attn_mask(ctx, pctx, batch);
|
||||
struct ggml_tensor * KQ_mask_cross = build_attn_mask_cross(ctx, pctx, model, batch);
|
||||
|
||||
for (int l = 0; l < model->n_layers; l++) {
|
||||
struct ggml_tensor * residual = inpL;
|
||||
ggml_set_name(inpL, ("layer_" + std::to_string(l) + "_input").c_str());
|
||||
|
||||
cur = parler_build_layer_norm(ctx, inpL, model->layers[l]->self_attn_norm, model->layers[l]->self_attn_norm_bias);
|
||||
|
||||
struct ggml_tensor * attn_out;
|
||||
|
||||
// self-attention
|
||||
{
|
||||
struct ggml_tensor * Qcur = ggml_mul_mat(ctx, model->layers[l]->self_attn_q_proj, cur);
|
||||
struct ggml_tensor * Kcur = ggml_mul_mat(ctx, model->layers[l]->self_attn_k_proj, cur);
|
||||
struct ggml_tensor * Vcur = ggml_mul_mat(ctx, model->layers[l]->self_attn_v_proj, cur);
|
||||
|
||||
parler_build_kv_store(ctx, kv_self, gf, Kcur, Vcur, (int32_t) batch.sequence_length, pctx->current_position, l, model->hidden_size);
|
||||
struct ggml_tensor * k =
|
||||
ggml_view_3d(ctx, kv_self->k_l[l],
|
||||
model->head_size, full_sequence_length, model->n_attn_heads,
|
||||
ggml_row_size(kv_self->k_l[l]->type, model->hidden_size),
|
||||
ggml_row_size(kv_self->k_l[l]->type, model->head_size),
|
||||
0);
|
||||
|
||||
|
||||
struct ggml_tensor * v =
|
||||
ggml_view_3d(ctx, kv_self->v_l[l],
|
||||
full_sequence_length, model->head_size, model->n_attn_heads,
|
||||
ggml_element_size(kv_self->v_l[l])*model->max_ctx_length,
|
||||
ggml_element_size(kv_self->v_l[l])*model->max_ctx_length*model->head_size,
|
||||
0);
|
||||
|
||||
Qcur = ggml_reshape_3d(ctx, Qcur, model->head_size, model->n_attn_heads, batch.sequence_length);
|
||||
struct ggml_tensor * q = ggml_cont(ctx, ggml_permute(ctx, Qcur, 0, 2, 1, 3));
|
||||
struct ggml_tensor * kq = ggml_mul_mat(ctx, ggml_cont(ctx, k), q);
|
||||
kq = ggml_soft_max_ext(ctx, kq, KQ_mask_dec, 1.0f/sqrtf(model->head_size), 0.0f);
|
||||
struct ggml_tensor * kqv = ggml_mul_mat(ctx, kq, v);
|
||||
struct ggml_tensor * kqv_merged = ggml_permute(ctx, kqv, 2, 0, 1, 3);
|
||||
attn_out = ggml_cont_2d(ctx, kqv_merged, model->hidden_size, batch.sequence_length);
|
||||
attn_out = ggml_mul_mat(ctx, model->layers[l]->self_attn_o_proj, attn_out);
|
||||
}
|
||||
|
||||
cur = ggml_add(ctx, attn_out, residual);
|
||||
|
||||
if (model->use_cross_attn) {
|
||||
struct ggml_tensor * residuala = cur;
|
||||
|
||||
// norm
|
||||
cur = parler_build_layer_norm(ctx, cur, model->layers[l]->attn_norm, model->layers[l]->attn_norm_bias);
|
||||
|
||||
//cross-attention
|
||||
struct ggml_tensor * Qcur = ggml_mul_mat(ctx, model->layers[l]->attn_q_proj, cur);
|
||||
Qcur = ggml_reshape_3d(ctx, Qcur, model->head_size, model->n_attn_heads, batch.sequence_length);
|
||||
|
||||
struct ggml_tensor * q = ggml_cont(ctx, ggml_permute(ctx, Qcur, 0, 2, 1, 3));
|
||||
|
||||
struct ggml_tensor * kq = ggml_mul_mat(ctx, model->layers[l]->cross_k, q);
|
||||
kq = ggml_soft_max_ext(ctx, kq, KQ_mask_cross, 1.0f/sqrtf(model->head_size), 0.0f);
|
||||
|
||||
struct ggml_tensor * kqv = ggml_mul_mat(ctx, kq, model->layers[l]->cross_v);
|
||||
struct ggml_tensor * kqv_merged = ggml_permute(ctx, kqv, 2, 0, 1, 3);
|
||||
cur = ggml_cont_2d(ctx, kqv_merged, model->hidden_size, batch.sequence_length);
|
||||
cur = ggml_mul_mat(ctx, model->layers[l]->attn_o_proj, cur);
|
||||
cur = ggml_add(ctx, cur, residuala);
|
||||
}
|
||||
|
||||
struct ggml_tensor * residualffn = cur;
|
||||
|
||||
cur = parler_build_layer_norm(ctx, cur, model->layers[l]->final_norm, model->layers[l]->final_norm_bias);
|
||||
cur = ggml_mul_mat(ctx, model->layers[l]->fc1, cur);
|
||||
cur = ggml_gelu(ctx, cur);
|
||||
cur = ggml_mul_mat(ctx, model->layers[l]->fc2, cur);
|
||||
cur = ggml_add(ctx, cur, residualffn);
|
||||
inpL = cur;
|
||||
}
|
||||
|
||||
cur = parler_build_layer_norm(ctx, cur, model->layer_norm, model->layer_norm_bias);
|
||||
cur = parler_build_head_outputs(ctx, model, cur);
|
||||
ggml_build_forward_expand(gf, cur);
|
||||
free_build();
|
||||
|
||||
return gf;
|
||||
}
|
||||
|
||||
void parler_tts_runner::configure_generation(generation_configuration * config) {
|
||||
sampler->temperature = config->temperature;
|
||||
sampler->repetition_penalty = config->repetition_penalty;
|
||||
sampler->do_sample = config->sample;
|
||||
sampler->top_k = config->top_k;
|
||||
sampler->top_p = config->top_p;
|
||||
model->use_cross_attn = config->use_cross_attn;
|
||||
}
|
||||
|
||||
void parler_tts_runner::set_inputs(parler_ubatch & batch) {
|
||||
if (batch.audio_generation) {
|
||||
ggml_backend_tensor_set(pctx->audio_inp_tokens, batch.audio_tokens, 0, batch.n_audio_tokens*ggml_element_size(pctx->audio_inp_tokens));
|
||||
} else {
|
||||
ggml_backend_tensor_set(pctx->inp_tokens, batch.tokens, 0, batch.n_tokens*ggml_element_size(pctx->inp_tokens));
|
||||
}
|
||||
ggml_backend_tensor_set(pctx->positions, batch.positions, 0, batch.sequence_length*ggml_element_size(pctx->positions));
|
||||
float * d = nullptr;
|
||||
d = (float *) pctx->attn_mask->data;
|
||||
uint32_t max_pos = pctx->current_position + batch.sequence_length;
|
||||
for (int i = 0; i < batch.sequence_length; i++) {
|
||||
uint32_t pos = batch.positions[i];
|
||||
for (int ii = 0; ii < max_pos; ii++) {
|
||||
d[i*max_pos + ii] = ii > pos ? -INFINITY : 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
if (model->use_cross_attn) {
|
||||
float * d2 = nullptr;
|
||||
d2 = (float *) pctx->attn_mask_cross->data;
|
||||
for (int i = 0; i < model->n_encode_length; i++) {
|
||||
for (int ii = 0; ii < batch.sequence_length; ii++) {
|
||||
d2[i*batch.sequence_length + ii] = 0.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
void parler_tts_runner::parler_graph_compute(ggml_cgraph * gf) {
|
||||
ggml_backend_sched_graph_compute_async(pctx->sched, gf);
|
||||
}
|
||||
|
||||
int parler_tts_runner::decode(parler_ubatch & batch) {
|
||||
ggml_backend_sched_reset(pctx->sched);
|
||||
|
||||
pctx->output_tokens.reserve(model->max_generation_size);
|
||||
|
||||
const size_t logits_size = model->output_vocab_size*model->max_generation_size*model->n_output_heads;
|
||||
const size_t prev_size = pctx->buf_output ? ggml_backend_buffer_get_size(pctx->buf_output) : 0;
|
||||
const size_t new_size = logits_size * sizeof(float);
|
||||
|
||||
if (!pctx->buf_output || prev_size < new_size) {
|
||||
if (pctx->buf_output) {
|
||||
ggml_backend_buffer_free(pctx->buf_output);
|
||||
pctx->buf_output = nullptr;
|
||||
pctx->logits = nullptr;
|
||||
}
|
||||
|
||||
pctx->buf_output = ggml_backend_buft_alloc_buffer(pctx->backend_cpu_buffer, new_size);
|
||||
}
|
||||
|
||||
pctx->logits = (float *) ggml_backend_buffer_get_base(pctx->buf_output);
|
||||
//ggml_backend_buffer_clear(pctx->buf_output, 0);
|
||||
|
||||
ggml_cgraph * gf = build_parler_graph(batch);
|
||||
|
||||
// the output is always the last tensor in the graph
|
||||
struct ggml_tensor * res = gf->nodes[gf->n_nodes - 1];
|
||||
ggml_backend_sched_alloc_graph(pctx->sched, gf);
|
||||
|
||||
// use the sequence_length variable here so that audio input tokens are handled correctly.
|
||||
size_t n_outputs_new = batch.sequence_length;
|
||||
|
||||
set_inputs(batch);
|
||||
parler_graph_compute(gf);
|
||||
|
||||
float * logits_out = pctx->logits + pctx->n_outputs * model->output_vocab_size * model->n_output_heads;
|
||||
pctx->get_ggml_node_data(res, logits_out, n_outputs_new*model->output_vocab_size*model->n_output_heads*sizeof(float));
|
||||
|
||||
// set to total number of outputs in the batch*/
|
||||
pctx->n_outputs += n_outputs_new;
|
||||
|
||||
// Reset state for the next token before backend sync, to allow the CPU activities in the reset to
|
||||
// overlap with device computation.
|
||||
ggml_backend_sched_reset(pctx->sched);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
parler_ubatch parler_tts_runner::build_worst_case_batch() {
|
||||
struct parler_ubatch batch;
|
||||
batch.audio_generation = false;
|
||||
batch.n_tokens = model->max_ctx_length;
|
||||
batch.n_audio_tokens = 0;
|
||||
batch.sequence_length = model->max_ctx_length;
|
||||
return batch;
|
||||
}
|
||||
|
||||
void parler_tts_runner::prepare_post_load() {
|
||||
dac_runner->prepare_post_load();
|
||||
parler_kv_cache_init(kv_self, model, pctx, std::mt19937(std::random_device{}())());
|
||||
auto batch = build_worst_case_batch();
|
||||
auto gf = build_parler_graph(batch);
|
||||
pctx->prep_schedule(gf);
|
||||
}
|
||||
|
||||
bool parler_tts_runner::adjust_for_sequence_continuation(struct parler_ubatch & batch) {
|
||||
return false; // not implemneted
|
||||
}
|
||||
|
||||
bool parler_tts_runner::check_stopping() {
|
||||
int32_t token_position = (int32_t) pctx->output_tokens.size() - (int32_t) model->n_output_heads;
|
||||
if (token_position < 0) {
|
||||
return false;
|
||||
}
|
||||
if (pctx->current_position >= model->max_generation_size) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool channels_complete = true;
|
||||
for (int i = 0; i < model->n_output_heads; i++) {
|
||||
pctx->eos_seen[i] = pctx->eos_seen[i] || pctx->output_tokens[token_position+i] == model->eos_token_id;
|
||||
if (channels_complete) {
|
||||
channels_complete = pctx->eos_seen[i];
|
||||
}
|
||||
}
|
||||
return channels_complete;
|
||||
}
|
||||
|
||||
void parler_tts_runner::adjust_output_tokens(std::vector<uint32_t> & output_tokens, std::vector<uint32_t> & filtered) {
|
||||
// currently this is applying sliding window over the heads and filtering out bad tokens.
|
||||
// If we convert the DAC model's quantizer layers to support by row + column embeddings then we will need to transpose
|
||||
// the heads and the sequence here, but right now simplying using a strided view is more peformant.
|
||||
size_t size = output_tokens.size();
|
||||
filtered.reserve(size);
|
||||
for (int i = 0; i < size / model->n_output_heads; i++) {
|
||||
bool remove = false;
|
||||
for (int ii = 0; ii < model->n_output_heads; ii++) {
|
||||
int next_index = i*model->n_output_heads+ii*model->n_output_heads+ii;
|
||||
if (next_index > size || output_tokens[next_index] >= model->audio_vocab_size) {
|
||||
remove = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!remove) {
|
||||
for (int ii = 0; ii < model->n_output_heads; ii++) {
|
||||
int next_index = i*model->n_output_heads+ii*model->n_output_heads+ii;
|
||||
if (next_index > size) {
|
||||
filtered.push_back(model->eos_token_id);
|
||||
} else {
|
||||
filtered.push_back(output_tokens[next_index]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int parler_tts_runner::generate_from_batch(parler_ubatch & batch, struct tts_response * output) {
|
||||
std::vector<uint32_t> next_decoder_token_ids;
|
||||
next_decoder_token_ids.reserve(model->n_output_heads);
|
||||
|
||||
while (!check_stopping()) {
|
||||
int state = decode(batch);
|
||||
if (state != 0) {
|
||||
return state;
|
||||
}
|
||||
if (!batch.audio_generation) {
|
||||
pctx->prompt_end_position += batch.sequence_length;
|
||||
}
|
||||
if (batch.audio_generation) {
|
||||
sampler->sample(pctx->logits + pctx->current_position * model->n_output_heads * model->output_vocab_size, pctx->output_tokens);
|
||||
}
|
||||
pctx->current_position += batch.sequence_length;
|
||||
next_decoder_token_ids.clear();
|
||||
uint32_t * last_outputs = (pctx->output_tokens.data() + (int) pctx->output_tokens.size() - model->n_output_heads);
|
||||
for (int i = 0; i < model->n_output_heads; i++) {
|
||||
next_decoder_token_ids.push_back(batch.current_step > i ? pctx->eos_seen[i] ? model->eos_token_id : last_outputs[i] : model->bos_token_id);
|
||||
}
|
||||
batch = parler_ubatch{
|
||||
true, 0, 9, 1, nullptr, next_decoder_token_ids.data(), &pctx->current_position, nullptr, batch.current_step+1
|
||||
};
|
||||
}
|
||||
|
||||
std::vector<uint32_t> filtered_output_tokens;
|
||||
adjust_output_tokens(pctx->output_tokens, filtered_output_tokens);
|
||||
dac_runner->run(filtered_output_tokens.data(), (int32_t) filtered_output_tokens.size() / model->n_output_heads, output);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int parler_tts_runner::generate_audio_tokens(std::string sentence) {
|
||||
parler_ubatch batch = batch_from_sentence(sentence, model, tokenizer);
|
||||
pctx->reset(model->n_output_heads);
|
||||
sampler->reset();
|
||||
int32_t seq_id = std::mt19937(std::random_device{}())();
|
||||
if (!kv_self) {
|
||||
kv_self = new parler_kv_cache;
|
||||
if (!parler_kv_cache_init(kv_self, model, pctx, seq_id)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<uint32_t> next_decoder_token_ids;
|
||||
next_decoder_token_ids.reserve(model->n_output_heads);
|
||||
|
||||
while (!check_stopping()) {
|
||||
int state = decode(batch);
|
||||
if (state != 0) {
|
||||
return state;
|
||||
}
|
||||
if (!batch.audio_generation) {
|
||||
pctx->prompt_end_position += batch.sequence_length;
|
||||
}
|
||||
if (batch.audio_generation) {
|
||||
sampler->sample(pctx->logits + pctx->current_position * model->n_output_heads * model->output_vocab_size, pctx->output_tokens);
|
||||
}
|
||||
pctx->current_position += batch.sequence_length;
|
||||
next_decoder_token_ids.clear();
|
||||
uint32_t * last_outputs = (pctx->output_tokens.data() + (int) pctx->output_tokens.size() - model->n_output_heads);
|
||||
for (int i = 0; i < model->n_output_heads; i++) {
|
||||
next_decoder_token_ids.push_back(batch.current_step > i ? pctx->eos_seen[i] ? model->eos_token_id : last_outputs[i] : model->bos_token_id);
|
||||
}
|
||||
batch = parler_ubatch{
|
||||
true, 0, 9, 1, nullptr, next_decoder_token_ids.data(), &pctx->current_position, nullptr, batch.current_step+1
|
||||
};
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void parler_tts_runner::just_audio_token_decode(uint32_t * tokens, int32_t sq_len, struct tts_response * outputs) {
|
||||
dac_runner->run(tokens, sq_len, outputs);
|
||||
}
|
||||
|
||||
int parler_tts_runner::generate(std::string sentence, struct tts_response * output, int32_t seq_id) {
|
||||
parler_ubatch batch = batch_from_sentence(sentence, model, tokenizer);
|
||||
pctx->reset(model->n_output_heads);
|
||||
sampler->reset();
|
||||
if (pctx->seq_id != seq_id || seq_id == -1) {
|
||||
seq_id = std::mt19937(std::random_device{}())();
|
||||
pctx->current_position = 0;
|
||||
if (!kv_self) {
|
||||
kv_self = new parler_kv_cache;
|
||||
if (!parler_kv_cache_init(kv_self, model, pctx, seq_id)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!adjust_for_sequence_continuation(batch)) {
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
return generate_from_batch(batch, output);
|
||||
}
|
||||
@@ -0,0 +1,225 @@
|
||||
#ifndef parler_model_h
|
||||
#define parler_model_h
|
||||
|
||||
#include "dac_model.h"
|
||||
#include "t5_encoder_model.h"
|
||||
#include "sampler.h"
|
||||
|
||||
enum parler_tensor {
|
||||
PARLER_EMBD,
|
||||
PARLER_EMBD_PROMPTS,
|
||||
PARLER_TEXT_ENCODING,
|
||||
PARLER_POSITIONAL_EMBD,
|
||||
PARLER_HEAD,
|
||||
PARLER_NORM,
|
||||
PARLER_NORM_BIAS,
|
||||
PARLER_LAYER_SELF_ATTN_Q,
|
||||
PARLER_LAYER_SELF_ATTN_K,
|
||||
PARLER_LAYER_SELF_ATTN_V,
|
||||
PARLER_LAYER_SELF_ATTN_O,
|
||||
PARLER_LAYER_SELF_ATTN_NORM,
|
||||
PARLER_LAYER_SELF_ATTN_NORM_BIAS,
|
||||
PARLER_LAYER_ATTN_Q,
|
||||
PARLER_LAYER_ATTN_K,
|
||||
PARLER_LAYER_ATTN_V,
|
||||
PARLER_LAYER_ATTN_O,
|
||||
PARLER_LAYER_ATTN_NORM,
|
||||
PARLER_LAYER_ATTN_NORM_BIAS,
|
||||
PARLER_LAYER_FC1,
|
||||
PARLER_LAYER_FC2,
|
||||
PARLER_LAYER_OUT_NORM,
|
||||
PARLER_LAYER_OUT_NORM_BIAS,
|
||||
};
|
||||
|
||||
struct parler_layer {
|
||||
struct ggml_tensor * self_attn_k_proj;
|
||||
struct ggml_tensor * self_attn_q_proj;
|
||||
struct ggml_tensor * self_attn_v_proj;
|
||||
struct ggml_tensor * self_attn_o_proj;
|
||||
struct ggml_tensor * self_attn_norm;
|
||||
struct ggml_tensor * self_attn_norm_bias;
|
||||
|
||||
struct ggml_tensor * attn_k_proj;
|
||||
struct ggml_tensor * attn_q_proj;
|
||||
struct ggml_tensor * attn_v_proj;
|
||||
struct ggml_tensor * attn_o_proj;
|
||||
struct ggml_tensor * attn_norm;
|
||||
struct ggml_tensor * attn_norm_bias;
|
||||
|
||||
struct ggml_tensor * cross_k;
|
||||
struct ggml_tensor * cross_v;
|
||||
|
||||
struct ggml_tensor * fc1;
|
||||
struct ggml_tensor * fc2;
|
||||
struct ggml_tensor * final_norm;
|
||||
struct ggml_tensor * final_norm_bias;
|
||||
};
|
||||
|
||||
struct parler_tts_model : tts_model {
|
||||
// These default configurations are based on the configuration of Parler TTS Mini (version 1.0)
|
||||
uint32_t n_output_heads = 9;
|
||||
uint32_t n_encode_length;
|
||||
uint32_t max_encode_length = 512; // This corresponds with the max token length of the conditional prompt
|
||||
uint32_t hidden_size = 1024;
|
||||
uint32_t max_ctx_length = 4096;
|
||||
uint32_t n_attn_heads = 16;
|
||||
uint32_t head_size = 64;
|
||||
uint32_t output_vocab_size = 1088;
|
||||
uint32_t eos_token_id = 1024;
|
||||
uint32_t audio_vocab_size = 1024;
|
||||
uint32_t max_generation_size = 2580;
|
||||
uint32_t n_layers = 24;
|
||||
uint32_t bos_token_id = 1025;
|
||||
uint32_t max_cross_nodes = 32;
|
||||
uint32_t prompt_vocab_size;
|
||||
|
||||
bool use_cross_attn = true;
|
||||
|
||||
std::vector<struct ggml_tensor*> embds;
|
||||
std::vector<parler_layer*> layers;
|
||||
std::vector<struct ggml_tensor*> heads;
|
||||
|
||||
struct ggml_tensor * precomputed_input_emb;
|
||||
struct ggml_tensor * precomputed_positional_embds;
|
||||
|
||||
struct ggml_tensor * layer_norm;
|
||||
struct ggml_tensor * layer_norm_bias;
|
||||
struct ggml_tensor * prompt_embd;
|
||||
|
||||
void assign_weight(std::string name, ggml_tensor * tensor);
|
||||
void prep_constants(gguf_context * meta);
|
||||
void prep_layers(gguf_context * meta);
|
||||
void prep_cross_key_values(int n_threads, struct tts_response * conditional_prompt = nullptr);
|
||||
void setup_from_file(gguf_context * meta_ctx, ggml_context * load_context, bool cpu_only) {
|
||||
prep_constants(meta_ctx);
|
||||
prep_layers(meta_ctx);
|
||||
tts_model::setup_from_file(meta_ctx, load_context, cpu_only, "decoder", 1.30, max_encode_length*hidden_size*sizeof(float)*n_layers*2);
|
||||
}
|
||||
};
|
||||
|
||||
// For assigning weights to the parler model from a gguf file.
|
||||
void assign_parler_layer(parler_tts_model * model, parler_layer & layer, std::string name, ggml_tensor * tensor);
|
||||
void assign_to_decoder(parler_tts_model * model, const std::string name, ggml_tensor * tensor);
|
||||
|
||||
struct parler_context : runner_context {
|
||||
parler_context(parler_tts_model * model, int n_threads): runner_context(n_threads), model(model) {};
|
||||
struct parler_tts_model * model;
|
||||
std::vector<bool> eos_seen;
|
||||
|
||||
bool use_cache = true;
|
||||
|
||||
size_t output_size = 0; // capacity (of tokens positions) for the output buffers
|
||||
int32_t n_outputs = 0; // number of actually-used outputs in the current ubatch or last logical batch
|
||||
uint32_t current_position = 0; // current position in the active sequence
|
||||
uint32_t prompt_end_position = 0; // the position of the text prompt termination (used for adjusting the cache when incrementally generating)
|
||||
int32_t seq_id; // a unique identifier associated with the active sequence.
|
||||
|
||||
std::vector<uint32_t> output_tokens;
|
||||
|
||||
struct ggml_tensor * inp_tokens;
|
||||
struct ggml_tensor * audio_inp_tokens;
|
||||
struct ggml_tensor * positions;
|
||||
struct ggml_tensor * attn_mask;
|
||||
struct ggml_tensor * attn_mask_cross;
|
||||
|
||||
void build_schedule() {
|
||||
runner_context::build_schedule(model->max_nodes());
|
||||
}
|
||||
void reset(int32_t n_output_heads);
|
||||
};
|
||||
|
||||
struct parler_kv_cache {
|
||||
int32_t seq_id;
|
||||
|
||||
ggml_type type_k = GGML_TYPE_F32;
|
||||
ggml_type type_v = GGML_TYPE_F32;
|
||||
|
||||
std::vector<struct ggml_tensor *> k_l;
|
||||
std::vector<struct ggml_tensor *> v_l;
|
||||
|
||||
struct ggml_context * ctx;
|
||||
ggml_backend_buffer_type_t buft;
|
||||
ggml_backend_buffer_t buf;
|
||||
|
||||
void free() {
|
||||
ggml_free(ctx);
|
||||
ggml_backend_buffer_free(buf);
|
||||
}
|
||||
|
||||
~parler_kv_cache() {
|
||||
free();
|
||||
}
|
||||
};
|
||||
|
||||
struct parler_ubatch {
|
||||
parler_ubatch(bool audio_generation, size_t n_tokens, size_t n_audio_tokens, size_t sequence_length,
|
||||
uint32_t * tokens, uint32_t * audio_tokens, uint32_t * positions, uint32_t * true_order,
|
||||
int current_step): audio_generation(audio_generation), n_tokens(n_tokens), n_audio_tokens(n_audio_tokens), sequence_length(sequence_length), tokens(tokens), audio_tokens(audio_tokens), positions(positions), true_order(true_order), current_step(current_step) {};
|
||||
parler_ubatch() {};
|
||||
bool audio_generation; // whether we are receiving codebook decoded tokens or text tokens
|
||||
size_t n_tokens; // total sentence tokens
|
||||
size_t n_audio_tokens; // total audio tokens
|
||||
size_t sequence_length; // for just audio tokens the sequence length should be the total_tokens / num_heads; in general this should be n_tokens + n_audio_tokens / num_heads
|
||||
uint32_t * tokens; // [n_tokens]
|
||||
uint32_t * audio_tokens; // [n_audio_tokens]
|
||||
uint32_t * positions; // [sequence_length]
|
||||
uint32_t * true_order;
|
||||
int current_step = 0; // total_generations
|
||||
};
|
||||
|
||||
struct parler_context * build_new_parler_context(struct parler_tts_model * model, int n_threads, bool use_cpu = true);
|
||||
static bool parler_kv_cache_init(struct parler_kv_cache * cache, parler_tts_model * model, parler_context * pctx, int32_t seq_id);
|
||||
|
||||
struct ggml_tensor * parler_build_inp_embd(struct ggml_context * ctx, struct parler_context * pctx, parler_tts_model * model, const parler_ubatch & batch);
|
||||
struct ggml_tensor * parler_build_layer_norm(struct ggml_context * ctx, struct ggml_tensor * inputs, struct ggml_tensor * weight, struct ggml_tensor * bias);
|
||||
void parler_build_kv_store(struct ggml_context * ctx, const parler_kv_cache * kv, struct ggml_cgraph * graph, struct ggml_tensor * k_cur, struct ggml_tensor * v_cur, int32_t n_tokens, int32_t kv_head, int32_t index, int32_t n_embd_gqa);
|
||||
struct ggml_tensor * parler_build_head_outputs(struct ggml_context * ctx, parler_tts_model * model, struct ggml_tensor * cur);
|
||||
struct ggml_tensor * build_attn_mask(ggml_context * ctx, parler_context * pctx, parler_ubatch & batch);
|
||||
struct ggml_tensor * build_attn_mask_cross(ggml_context * ctx, parler_context * pctx, parler_tts_model * model, parler_ubatch & batch);
|
||||
static struct parler_ubatch batch_from_sentence(std::string sentence, parler_tts_model * model, unigram_tokenizer * tokenizer);
|
||||
|
||||
// This struct is intended to support end-to-end TTS generation. As such, it manages the parler tts model compilation, compute and generation process,
|
||||
// the tokenization and sampling process, and uses the dac_runner struct to encode audio outputs.
|
||||
struct parler_tts_runner : tts_runner {
|
||||
parler_tts_runner(parler_tts_model * model, dac_runner * audio_decoder, parler_context * pctx, unigram_tokenizer * ut, sampler * samp, parler_kv_cache * cache): model(model), dac_runner(audio_decoder), pctx(pctx), tokenizer(ut), sampler(samp), kv_self(cache) {};
|
||||
~parler_tts_runner() {
|
||||
if (ctx) {
|
||||
ggml_free(ctx);
|
||||
}
|
||||
model->free();
|
||||
delete model;
|
||||
delete kv_self;
|
||||
delete dac_runner;
|
||||
delete pctx;
|
||||
delete sampler;
|
||||
}
|
||||
struct parler_tts_model * model;
|
||||
struct dac_runner * dac_runner;
|
||||
struct parler_context * pctx;
|
||||
struct unigram_tokenizer * tokenizer;
|
||||
struct parler_kv_cache * kv_self = nullptr;
|
||||
struct sampler * sampler;
|
||||
|
||||
void init_build() {
|
||||
tts_runner::init_build(&pctx->buf_compute_meta);
|
||||
}
|
||||
|
||||
void configure_generation(generation_configuration * config);
|
||||
void assign_weight(std::string name, ggml_tensor * tensor);
|
||||
parler_ubatch build_worst_case_batch();
|
||||
struct ggml_cgraph * build_parler_graph(parler_ubatch & batch);
|
||||
void set_inputs(parler_ubatch & batch);
|
||||
int decode(parler_ubatch & batch);
|
||||
void prepare_post_load();
|
||||
bool adjust_for_sequence_continuation(struct parler_ubatch & batch);
|
||||
int generate(std::string sentence, struct tts_response * response, int32_t seq_id = -1);
|
||||
bool check_stopping();
|
||||
void adjust_output_tokens(std::vector<uint32_t> & output_tokens, std::vector<uint32_t> & filtered);
|
||||
int generate_from_batch(parler_ubatch & batch, struct tts_response * output);
|
||||
void parler_graph_compute(ggml_cgraph * gf);
|
||||
void just_audio_token_decode(uint32_t * tokens, int32_t sq_len, struct tts_response * output);
|
||||
int generate_audio_tokens(std::string sentence);
|
||||
void update_conditional_prompt(const std::string file_path, const std::string prompt, int n_threads, bool cpu_only = true);
|
||||
};
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,204 @@
|
||||
#include "sampler.h"
|
||||
|
||||
void sampler::sample(float * logits, std::vector<uint32_t> & output_tokens) {
|
||||
// assume that we are pointing to the start of the first token output;
|
||||
if (!do_sample) {
|
||||
return max(logits, output_tokens);
|
||||
}
|
||||
std::vector<uint32_t> max_vals;
|
||||
// the max_head_probs variable is used when top-p is applied but exists to address the case in which top-k and top-p cause the cumulative probability of the nucleus to beless than or
|
||||
// equal to top_p;
|
||||
std::vector<float> max_head_probs;
|
||||
|
||||
// This allows us to perform an effective softmax without logarithms or big number calculations.
|
||||
// Additionally by avoiding large number division we drastically improve the stability of
|
||||
// our softmax implementation;
|
||||
max(logits, max_vals);
|
||||
|
||||
std::vector<std::vector<size_t>> picks;
|
||||
bool use_nucleus_sampling = false;
|
||||
bool performed_softmax = false;
|
||||
|
||||
if (top_p < 1.0) {
|
||||
// if we are nucleus sampling via top-p then we need to perform softmax over the samples before getting top_k samples, so that we don't trim beyond top_p.
|
||||
// Otherwise, if we are not performing top-p sampling then it is more efficient to perform softmax after getting the top_k nucleus.
|
||||
softmax(logits, picks, max_vals);
|
||||
performed_softmax = true;
|
||||
}
|
||||
if (top_k > 0 && top_k < vocab_size) {
|
||||
picks = topk(logits, performed_softmax);
|
||||
use_nucleus_sampling = true;
|
||||
}
|
||||
|
||||
if (top_p >= 1.0) {
|
||||
softmax(logits, picks, max_vals);
|
||||
performed_softmax = true;
|
||||
}
|
||||
|
||||
if (top_p < 1.0) {
|
||||
topp(logits, picks, max_head_probs);
|
||||
use_nucleus_sampling = true;
|
||||
}
|
||||
|
||||
bool has_repetition_penalty = repetition_penalty != 1.0;
|
||||
if (has_repetition_penalty && (last_token_ids.size() == 0 || repetition_counts.size() == 0)) {
|
||||
reset();
|
||||
}
|
||||
std::minstd_rand gen(std::random_device{}());
|
||||
std::uniform_real_distribution<float> dist(0.0f, 1.0f);
|
||||
for (int i = 0; i < n_output_heads; i++) {
|
||||
float assignment = top_p < 1.0 ? dist(gen) * max_head_probs[i] : dist(gen);
|
||||
float cumulative = 0.0f;
|
||||
for (uint32_t j = 0; j < (use_nucleus_sampling ? picks[i].size() : vocab_size); j++) {
|
||||
int ii = use_nucleus_sampling ? (int) picks[i][j] : j;
|
||||
cumulative += *(logits+(i*vocab_size+ii));
|
||||
// with top_k and top_p it is possible for the assignment to be greater than the cumulative value
|
||||
if (assignment <= cumulative || ii >= vocab_size + 1 || j >= picks[i].size() - 1) {
|
||||
if (has_repetition_penalty) {
|
||||
if (last_token_ids[i] != ii) {
|
||||
repetition_counts[i] = 0;
|
||||
}
|
||||
last_token_ids[i] = ii;
|
||||
repetition_counts[i] += 1;
|
||||
}
|
||||
output_tokens.push_back(ii);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void sampler::reset() {
|
||||
if (repetition_penalty != 1.0) {
|
||||
last_token_ids.clear();
|
||||
repetition_counts.clear();
|
||||
for (int i = 0; i < n_output_heads; i++) {
|
||||
last_token_ids.push_back(-1);
|
||||
repetition_counts.push_back(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void sampler::softmax(float * logits, std::vector<std::vector<size_t>> picks, std::vector<uint32_t> max_indices) {
|
||||
bool use_nucleus_sampling = picks.size() > 0;
|
||||
bool has_repetition_penalty = repetition_penalty != 1.0f;
|
||||
bool has_temperature = temperature != 1.0f;
|
||||
for (int i = 0; i < n_output_heads; i++) {
|
||||
float cumsum = 0.0;
|
||||
float max_val = logits[i*vocab_size + max_indices[i]];
|
||||
if (has_repetition_penalty && last_token_ids[i] == max_indices[i]) {
|
||||
max_val /= (pow(repetition_penalty, repetition_counts[i]));
|
||||
}
|
||||
if (has_temperature) {
|
||||
max_val /= temperature;
|
||||
}
|
||||
for (int j = 0; j < (use_nucleus_sampling ? picks[i].size() : vocab_size); j++) {
|
||||
int ii = use_nucleus_sampling ? (int) picks[i][j] : j;
|
||||
int index = i * vocab_size + ii;
|
||||
float v = *(logits + index);
|
||||
if (has_repetition_penalty && last_token_ids[i] == ii) {
|
||||
v /= (pow(repetition_penalty, repetition_counts[i]));
|
||||
}
|
||||
if (has_temperature) {
|
||||
v /= temperature;
|
||||
}
|
||||
v = expf(v - max_val);
|
||||
cumsum += v;
|
||||
logits[index] = v;
|
||||
}
|
||||
for (int j = 0; j < (use_nucleus_sampling ? picks[i].size() : vocab_size); j++) {
|
||||
int ii = use_nucleus_sampling ? picks[i][j] : j;
|
||||
int index = i * vocab_size + ii;
|
||||
float v = *(logits + index);
|
||||
logits[index] = v / cumsum;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void sampler::topp(float * logits, std::vector<std::vector<size_t>> & picks, std::vector<float> & max_head_probs) {
|
||||
if (picks.empty()) {
|
||||
// we need to get the softmaxed logits ordered
|
||||
for (int i = 0; i < n_output_heads; i++) {
|
||||
std::vector<size_t> head_picks(vocab_size);
|
||||
iota(head_picks.begin(), head_picks.end(), 0);
|
||||
// have to sort with repetition penalty applied so not to inavertently trim our nucleus size.
|
||||
std::sort(head_picks.begin(), head_picks.end(), [&logits, &i, this](size_t s1, size_t s2) {
|
||||
float v1 = logits[i*vocab_size+s1];
|
||||
float v2 = logits[i*vocab_size+s2];
|
||||
return v1 > v2;
|
||||
});
|
||||
|
||||
picks.push_back(head_picks);
|
||||
}
|
||||
}
|
||||
// if we didn't already perform topk or if the probable sum of topk logits is greater than top_p then we need to trim.
|
||||
for (int i = 0; i < n_output_heads; i++) {
|
||||
float prob_sum = 0.0f;
|
||||
int trim_to = -1;
|
||||
for (int ii = 0; ii < picks[i].size(); ii++) {
|
||||
prob_sum += logits[i*vocab_size+picks[i][ii]];
|
||||
if (prob_sum >= top_p) {
|
||||
trim_to = ii+1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
max_head_probs.push_back(std::min(prob_sum, top_p));
|
||||
if (trim_to > 0) {
|
||||
picks[i] = std::vector<size_t>(picks[i].begin(), picks[i].begin()+trim_to);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::vector<size_t>> sampler::topk(float * logits, bool performed_softmax) {
|
||||
bool has_repetition_penalty = repetition_penalty != 1.0f;
|
||||
std::vector<std::vector<size_t>> head_picks;
|
||||
if (vocab_size < top_k) {
|
||||
// technically we should never get here, but lets be protective.
|
||||
for (int i = 0; i < n_output_heads; i++) {
|
||||
std::vector<size_t> picks(vocab_size);
|
||||
iota(picks.begin(), picks.end(), 0);
|
||||
head_picks.push_back(picks);
|
||||
}
|
||||
return head_picks;
|
||||
}
|
||||
for (int i = 0; i < n_output_heads; i++) {
|
||||
std::vector<size_t> picks(vocab_size);
|
||||
iota(picks.begin(), picks.end(), 0);
|
||||
// have to sort with repetition penalty applied so not to inavertently trim our nucleus size.
|
||||
std::sort(picks.begin(), picks.end(), [&logits, &i, &has_repetition_penalty, &performed_softmax, this](size_t s1, size_t s2) {
|
||||
float v1 = logits[i*vocab_size+s1];
|
||||
float v2 = logits[i*vocab_size+s2];
|
||||
if (!performed_softmax) {
|
||||
if (has_repetition_penalty && last_token_ids[i] == s1) {
|
||||
v1 /= (pow(repetition_penalty, repetition_counts[i]));
|
||||
} else if (has_repetition_penalty && last_token_ids[i] == s2) {
|
||||
v2 /= (pow(repetition_penalty, repetition_counts[i]));
|
||||
}
|
||||
}
|
||||
return v1 > v2;
|
||||
});
|
||||
head_picks.push_back(std::vector<size_t>(picks.begin(), picks.begin() + top_k));
|
||||
}
|
||||
return head_picks;
|
||||
}
|
||||
|
||||
void sampler::max(float * logits, std::vector<uint32_t> & output_tokens) {
|
||||
bool has_repetition_penalty = repetition_penalty != 1.0f;
|
||||
for (int i = 0; i < n_output_heads; i++) {
|
||||
float max = -INFINITY;
|
||||
uint32_t token_id = 0;
|
||||
for (uint32_t ii = 0; ii < vocab_size; ii++) {
|
||||
float v = *(logits+i*vocab_size+ii);
|
||||
// while repetition penalty will never be used for maximum token selection, it is used for the logarithmic stabilization of
|
||||
// the softmax function in which case it is possible for repetition counts to be set.
|
||||
if (has_repetition_penalty && last_token_ids[i] == ii) {
|
||||
v /= (pow(repetition_penalty, repetition_counts[i]));
|
||||
}
|
||||
if (v > max) {
|
||||
max = v;
|
||||
token_id = ii;
|
||||
}
|
||||
}
|
||||
output_tokens.push_back(token_id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
#ifndef sampler_h
|
||||
#define sampler_h
|
||||
|
||||
#include <stdint.h>
|
||||
#include <vector>
|
||||
#include <random>
|
||||
#include <numeric>
|
||||
#include <algorithm>
|
||||
|
||||
// currently this is only built to support single sequence output sampling without beam search.
|
||||
struct sampler {
|
||||
// These default configurations are based on the generation configuration for Parler TTS Mini (version 1.0)
|
||||
uint32_t n_output_heads = 9;
|
||||
uint32_t eos_token_id = 1024;
|
||||
uint32_t vocab_size = 1088;
|
||||
float temperature = 1.0f;
|
||||
uint32_t top_k = 0;
|
||||
float top_p = 1.0f;
|
||||
float repetition_penalty = 1.0f;
|
||||
std::vector<int32_t> last_token_ids;
|
||||
std::vector<uint32_t> repetition_counts;
|
||||
bool do_sample = true;
|
||||
bool apply_softmax = true;
|
||||
|
||||
void sample(float * logits, std::vector<uint32_t> & output_tokens);
|
||||
void softmax(float * logits, std::vector<std::vector<size_t>> picks, std::vector<uint32_t> max_indices);
|
||||
void max(float * logits, std::vector<uint32_t> & output_tokens);
|
||||
std::vector<std::vector<size_t>> topk(float * logits, bool performed_softmax);
|
||||
void topp(float * logits, std::vector<std::vector<size_t>> & picks, std::vector<float> & max_head_probs);
|
||||
void reset();
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,209 @@
|
||||
#include "snac_model.h"
|
||||
|
||||
void snac_model::prep_constants(gguf_context * meta) {
|
||||
int heads_key = gguf_find_key(meta, "snac.audio_token_channels");
|
||||
if (heads_key != -1) {
|
||||
n_heads = gguf_get_val_u32(meta, heads_key);
|
||||
}
|
||||
|
||||
int sampling_factor_key = gguf_find_key(meta, "snac.up_sampling_factor");
|
||||
if (sampling_factor_key != -1) {
|
||||
up_sampling_factor = gguf_get_val_u32(meta, sampling_factor_key);
|
||||
}
|
||||
|
||||
int max_gen_key = gguf_find_key(meta, "snac.max_generation_size");
|
||||
if (max_gen_key != -1) {
|
||||
max_generation_size = gguf_get_val_u32(meta, max_gen_key);
|
||||
}
|
||||
}
|
||||
|
||||
void snac_model::prep_layers(gguf_context * meta) {
|
||||
for (int i = 0; i < n_heads; i++) {
|
||||
quantizer_layers.push_back(general_neural_audio_codec::residual_vector_quantize_layer{});
|
||||
}
|
||||
|
||||
for (int i = 0; i < n_layers; i++) {
|
||||
std::string stride_key = "snac.snac_layer_stride_" + std::to_string(i);
|
||||
std::string padding_key = "snac.snac_layer_padding_" + std::to_string(i);
|
||||
std::string grouping_key = "snac.snac_layer_grouping_" + std::to_string(i);
|
||||
int layer_stride_key = gguf_find_key(meta, stride_key.c_str());
|
||||
if (layer_stride_key == -1) {
|
||||
TTS_ABORT("key %s must be specified in gguf file inorder to initialize the SNAC audio decoder.", stride_key.c_str());
|
||||
}
|
||||
int layer_padding_key = gguf_find_key(meta, padding_key.c_str());
|
||||
if (layer_padding_key == -1) {
|
||||
TTS_ABORT("key %s must be specified in gguf file inorder to initialize the SNAC audio decoder.", padding_key.c_str());
|
||||
}
|
||||
int layer_grouping_key = gguf_find_key(meta, grouping_key.c_str());
|
||||
if (layer_grouping_key == -1) {
|
||||
TTS_ABORT("key %s must be specified in gguf file inorder to initialize the SNAC audio decoder.", grouping_key.c_str());
|
||||
}
|
||||
layers.push_back(
|
||||
general_neural_audio_codec::layer{
|
||||
gguf_get_val_u32(meta, layer_padding_key),
|
||||
gguf_get_val_u32(meta, layer_stride_key),
|
||||
gguf_get_val_u32(meta, layer_grouping_key)
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void snac_model::assign_weight(std::string name, ggml_tensor * tensor) {
|
||||
if (name == "alpha_out") {
|
||||
snake_alpha = ggml_dup_tensor(ctx, tensor);
|
||||
set_tensor(snake_alpha, tensor);
|
||||
} else if (name == "in.weight") {
|
||||
in_conv_kernel = ggml_dup_tensor(ctx, tensor);
|
||||
set_tensor(in_conv_kernel, tensor);
|
||||
} else if (name == "in.bias") {
|
||||
in_conv_bias = ggml_dup_tensor(ctx, ggml_transpose(ctx, tensor));
|
||||
set_tensor(in_conv_bias, tensor);
|
||||
} else if (name == "up.weight") {
|
||||
up_conv_kernel = ggml_dup_tensor(ctx, tensor);
|
||||
set_tensor(up_conv_kernel, tensor);
|
||||
} else if (name == "up.bias") {
|
||||
up_conv_bias = ggml_dup_tensor(ctx, ggml_transpose(ctx, tensor));
|
||||
set_tensor(up_conv_bias, tensor);
|
||||
} else if (name == "final.weight") {
|
||||
out_conv_kernel = ggml_dup_tensor(ctx, tensor);
|
||||
set_tensor(out_conv_kernel, tensor);
|
||||
} else if (name == "final.bias") {
|
||||
out_conv_bias = ggml_dup_tensor(ctx, ggml_transpose(ctx, tensor));
|
||||
set_tensor(out_conv_bias, tensor);
|
||||
} else if (has_prefix(name, "layers")) {
|
||||
auto pair = parse_layer_count(name);
|
||||
int l = pair.first;
|
||||
std::string lt_name = pair.second;
|
||||
general_neural_audio_codec::assign_to_layer((tts_model *) this, layers[l], lt_name, tensor);
|
||||
} else if (has_prefix(name, "quantizers")) {
|
||||
auto pair = parse_layer_count(name);
|
||||
int l = pair.first;
|
||||
std::string lt_name = pair.second;
|
||||
general_neural_audio_codec::assign_to_quantize_layer((tts_model *) this, quantizer_layers[l], lt_name, tensor);
|
||||
}
|
||||
}
|
||||
|
||||
static struct ggml_tensor * snac_build_audio_inputs(struct ggml_context * ctx, struct snac_context * sctx, size_t sequence_length, std::vector<general_neural_audio_codec::residual_vector_quantize_layer> layers) {
|
||||
struct ggml_tensor * embd;
|
||||
// these devisors represent the discreate repeats performed against each of the three input heads.
|
||||
sctx->inp_tokens = ggml_new_tensor_1d(ctx, GGML_TYPE_I32, sequence_length / 4 + sequence_length / 2 + sequence_length);
|
||||
ggml_set_input(sctx->inp_tokens);
|
||||
size_t last_stride = 0;
|
||||
for(int i = 0; i < sctx->model->n_heads; i++) {
|
||||
auto quantize_layer = sctx->model->quantizer_layers[i];
|
||||
struct ggml_tensor * inp_head = ggml_cont(ctx, ggml_view_1d(ctx, sctx->inp_tokens, sequence_length / sctx->model->repeats[i], last_stride));
|
||||
last_stride += (sequence_length / sctx->model->repeats[i]) * ggml_element_size(sctx->inp_tokens);
|
||||
struct ggml_tensor * code = general_neural_audio_codec::build_quantize_layer(ctx, inp_head, quantize_layer);
|
||||
if (sctx->model->repeats[i] > 1) {
|
||||
// this manipulation is equivalent to repeat_interleave against the first dimension of the tensor
|
||||
code = ggml_repeat(ctx, ggml_cont_3d(ctx, code, 1, code->ne[0], code->ne[1]), ggml_new_tensor_3d(ctx, GGML_TYPE_F32, sctx->model->repeats[i], code->ne[0], sctx->model->embd));
|
||||
code = ggml_cont_2d(ctx, code, sequence_length, code->ne[2]);
|
||||
}
|
||||
if (i == 0) {
|
||||
embd = code;
|
||||
} else {
|
||||
embd = ggml_add(ctx, embd, code);
|
||||
}
|
||||
}
|
||||
return embd;
|
||||
}
|
||||
|
||||
snac_context * build_new_snac_context(struct snac_model * model, int n_threads, bool use_cpu) {
|
||||
snac_context * sctx = new snac_context(model, n_threads);
|
||||
if (!use_cpu) {
|
||||
#ifdef GGML_USE_METAL
|
||||
sctx->backend = ggml_backend_metal_init();
|
||||
#endif
|
||||
}
|
||||
sctx->backend_cpu = ggml_backend_cpu_init();
|
||||
sctx->set_threads();
|
||||
sctx->build_schedule();
|
||||
sctx->buf_compute_meta.resize(ggml_tensor_overhead()*model->max_nodes() + ggml_graph_overhead_custom(model->max_nodes(), false));
|
||||
return sctx;
|
||||
}
|
||||
|
||||
void snac_runner::prepare_post_load() {
|
||||
ggml_cgraph * gf = build_snac_graph(model->max_generation_size);
|
||||
sctx->prep_schedule(gf);
|
||||
}
|
||||
|
||||
struct ggml_cgraph * snac_runner::build_snac_graph(size_t sequence_length) {
|
||||
init_build();
|
||||
struct ggml_cgraph * gf = ggml_new_graph_custom(ctx, 8192, false);
|
||||
|
||||
struct ggml_tensor * cur;
|
||||
struct ggml_tensor * inputs;
|
||||
|
||||
sctx->noise = ggml_new_tensor_1d(ctx, GGML_TYPE_F32, model->noise_steps_sum * sequence_length);
|
||||
ggml_set_input(sctx->noise);
|
||||
|
||||
inputs = snac_build_audio_inputs(ctx, sctx, sequence_length, model->quantizer_layers);
|
||||
cur = ggml_conv_1d_dw_tts(ctx, model->in_conv_kernel, inputs, 1, 3, 1);
|
||||
cur = ggml_add(ctx, cur, model->in_conv_bias);
|
||||
cur = ggml_conv_1d_tts(ctx, model->up_conv_kernel, cur, 1, 0, 1);
|
||||
cur = ggml_add(ctx, cur, model->up_conv_bias);
|
||||
size_t noise_offset = 0;
|
||||
for (int l = 0; l < model->layers.size(); l++) {
|
||||
auto layer = model->layers[l];
|
||||
struct ggml_tensor * noise = ggml_cont(ctx, ggml_view_1d(ctx, sctx->noise, model->noise_steps[l] * sequence_length, noise_offset));
|
||||
noise_offset += model->noise_steps[l] * sequence_length * sizeof(float);
|
||||
cur = general_neural_audio_codec::build_layer(ctx, cur, layer, noise);
|
||||
}
|
||||
cur = snake_1d(ctx, model->snake_alpha, cur);
|
||||
cur = ggml_conv_1d_tts(ctx, model->out_conv_kernel, cur, 1, 3, 1);
|
||||
cur = ggml_add(ctx, cur, model->out_conv_bias);
|
||||
cur = ggml_tanh(ctx, cur);
|
||||
ggml_build_forward_expand(gf, cur);
|
||||
free_build();
|
||||
return gf;
|
||||
}
|
||||
|
||||
void snac_runner::set_inputs(std::vector<std::vector<uint32_t>> & tokens) {
|
||||
ggml_backend_tensor_set(
|
||||
sctx->inp_tokens, tokens[0].data(), 0,
|
||||
tokens[0].size()*ggml_element_size(sctx->inp_tokens)
|
||||
);
|
||||
|
||||
ggml_backend_tensor_set(
|
||||
sctx->inp_tokens, tokens[1].data(), tokens[0].size() * ggml_element_size(sctx->inp_tokens),
|
||||
tokens[1].size() * ggml_element_size(sctx->inp_tokens)
|
||||
);
|
||||
|
||||
ggml_backend_tensor_set(
|
||||
sctx->inp_tokens, tokens[2].data(),
|
||||
tokens[1].size()*ggml_element_size(sctx->inp_tokens)+tokens[0].size()*ggml_element_size(sctx->inp_tokens),
|
||||
tokens[2].size()*ggml_element_size(sctx->inp_tokens)
|
||||
);
|
||||
size_t sequence_length = tokens[2].size();
|
||||
random_normal_gen(model->noise_steps_sum * sequence_length, (float*) sctx->noise->data);
|
||||
}
|
||||
|
||||
void snac_runner::run(std::vector<std::vector<uint32_t>> & tokens, struct tts_response * outputs) {
|
||||
size_t sequence_length = tokens[2].size();
|
||||
ggml_backend_sched_reset(sctx->sched);
|
||||
|
||||
sctx->prep_output_buffer(model->max_generation_size * model->up_sampling_factor * sizeof(float));
|
||||
|
||||
outputs->data = sctx->logits;
|
||||
ggml_backend_buffer_clear(sctx->buf_output, 0);
|
||||
|
||||
struct ggml_cgraph * gf = NULL;
|
||||
gf = build_snac_graph(sequence_length);
|
||||
|
||||
// the output is always the last tensor in the graph
|
||||
struct ggml_tensor * result = gf->nodes[gf->n_nodes - 1];
|
||||
ggml_backend_sched_alloc_graph(sctx->sched, gf);
|
||||
|
||||
set_inputs(tokens);
|
||||
|
||||
ggml_backend_sched_graph_compute_async(sctx->sched, gf);
|
||||
|
||||
sctx->get_ggml_node_data(result, outputs->data, sequence_length*sizeof(float)*model->up_sampling_factor);
|
||||
|
||||
// Reset state for the next token before backend sync, to allow the CPU activities in the reset to
|
||||
// overlap with device computation.
|
||||
ggml_backend_sched_reset(sctx->sched);
|
||||
outputs->n_outputs = sequence_length * model->up_sampling_factor;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
#pragma once
|
||||
|
||||
#include "general_neural_audio_codec.h"
|
||||
|
||||
// SNAC, Scale Neural Audio Codec, is another neural audio codec much like DAC.
|
||||
// The key differences are that it uses grouping in the residual units of its layers,
|
||||
// performs a repeat_interleave over the second and third input channels, applies
|
||||
// a noise convolutional layer after input encoding for each layer, and applies
|
||||
// an extra convolutional layer before residual layers are applied.
|
||||
struct snac_model : tts_model {
|
||||
// general configuration from SNAC as used by Orpheus
|
||||
uint32_t n_layers = 4;
|
||||
uint32_t n_heads = 3;
|
||||
uint32_t up_sampling_factor = 512;
|
||||
uint32_t embd = 768;
|
||||
size_t max_generation_size = 2580;
|
||||
uint32_t repeats[3] = {4, 2, 1};
|
||||
// configuration for adding noise
|
||||
uint32_t noise_steps[4] = {8, 64, 256, 512};
|
||||
uint32_t noise_steps_sum = 840;
|
||||
bool use_noise = true;
|
||||
|
||||
struct ggml_tensor * repeat_interleave_buffer;
|
||||
|
||||
struct ggml_tensor * in_conv_kernel;
|
||||
struct ggml_tensor * in_conv_bias;
|
||||
struct ggml_tensor * up_conv_kernel;
|
||||
struct ggml_tensor * up_conv_bias;
|
||||
struct ggml_tensor * out_conv_kernel;
|
||||
struct ggml_tensor * out_conv_bias;
|
||||
struct ggml_tensor * snake_alpha;
|
||||
std::vector<general_neural_audio_codec::layer> layers;
|
||||
std::vector<general_neural_audio_codec::residual_vector_quantize_layer> quantizer_layers;
|
||||
|
||||
void assign_weight(std::string name, ggml_tensor * weight);
|
||||
void prep_constants(gguf_context * meta);
|
||||
void prep_layers(gguf_context * meta);
|
||||
void post_load_assign();
|
||||
void setup_from_file(gguf_context * meta_ctx, ggml_context * load_context, bool cpu_only) {
|
||||
prep_layers(meta_ctx);
|
||||
prep_constants(meta_ctx);
|
||||
tts_model::setup_from_file(meta_ctx, load_context, cpu_only, "snac");
|
||||
}
|
||||
};
|
||||
|
||||
// the context used for running the snac model
|
||||
struct snac_context : runner_context {
|
||||
snac_context(snac_model * model, int n_threads): runner_context(n_threads), model(model) {};
|
||||
|
||||
struct snac_model * model;
|
||||
|
||||
struct ggml_tensor * inp_tokens;
|
||||
struct ggml_tensor * noise;
|
||||
|
||||
void build_schedule() {
|
||||
runner_context::build_schedule(model->max_nodes());
|
||||
}
|
||||
};
|
||||
|
||||
snac_context * build_new_snac_context(struct snac_model * model, int n_threads, bool use_cpu = true);
|
||||
|
||||
static struct ggml_tensor * snac_build_audio_inputs(struct ggml_context * ctx, struct snac_context * sctx, size_t sequence_length, std::vector<general_neural_audio_codec::residual_vector_quantize_layer> layers);
|
||||
|
||||
// This struct is intended to manage the snac model's graph compilation and compute function.
|
||||
struct snac_runner : tts_runner {
|
||||
snac_runner(snac_model * model, snac_context * context): model(model), sctx(context) {};
|
||||
~snac_runner() {
|
||||
if (ctx) {
|
||||
ggml_free(ctx);
|
||||
}
|
||||
model->free();
|
||||
delete model;
|
||||
delete sctx;
|
||||
}
|
||||
snac_model * model;
|
||||
snac_context * sctx;
|
||||
|
||||
void init_build() {
|
||||
tts_runner::init_build(&sctx->buf_compute_meta);
|
||||
}
|
||||
|
||||
void set_inputs(std::vector<std::vector<uint32_t>> & tokens);
|
||||
void prepare_post_load();
|
||||
struct ggml_cgraph * build_snac_graph(size_t sequence_length);
|
||||
void run(std::vector<std::vector<uint32_t>> & tokens, struct tts_response * outputs);
|
||||
};
|
||||
@@ -0,0 +1,402 @@
|
||||
#include "t5_encoder_model.h"
|
||||
|
||||
static const std::map<std::string, t5_tensor> T5_TENSOR_GGUF_LOOKUP = {
|
||||
{"t5encoder.token_embd", T5_EMBD},
|
||||
{"t5encoder.enc.final_layer_norm", T5_NORM},
|
||||
{"t5encoder.down_proj", T5_DOWN_PROJ},
|
||||
{"t5encoder.down_proj_bias", T5_DOWN_PROJ_BIAS},
|
||||
{".attn_norm", T5_LAYER_ATTN_NORM},
|
||||
{".attn_q", T5_LAYER_ATTN_Q},
|
||||
{".attn_k", T5_LAYER_ATTN_K},
|
||||
{".attn_v", T5_LAYER_ATTN_V},
|
||||
{".attn_o", T5_LAYER_ATTN_O},
|
||||
{".attn_rel_b", T5_RELATIVE_BIAS},
|
||||
{".ffn_norm", T5_LAYER_OUT_NORM},
|
||||
{".ffn_gate", T5_LAYER_WI_1},
|
||||
{".ffn_down", T5_LAYER_WO},
|
||||
{".ffn_up", T5_LAYER_WI_0},
|
||||
};
|
||||
|
||||
void assign_to_t5_layer(t5_encoder * model, t5_layer & layer, std::string name, ggml_tensor * tensor) {
|
||||
try {
|
||||
switch(T5_TENSOR_GGUF_LOOKUP.at(name)) {
|
||||
case T5_LAYER_ATTN_NORM:
|
||||
layer.attn_norm = ggml_dup_tensor(model->ctx, tensor);
|
||||
model->set_tensor(layer.attn_norm, tensor);
|
||||
break;
|
||||
case T5_LAYER_ATTN_Q:
|
||||
layer.q = ggml_dup_tensor(model->ctx, tensor);
|
||||
model->set_tensor(layer.q, tensor);
|
||||
break;
|
||||
case T5_LAYER_ATTN_K:
|
||||
layer.k = ggml_dup_tensor(model->ctx, tensor);
|
||||
model->set_tensor(layer.k, tensor);
|
||||
break;
|
||||
case T5_LAYER_ATTN_V:
|
||||
layer.v = ggml_dup_tensor(model->ctx, tensor);
|
||||
model->set_tensor(layer.v, tensor);
|
||||
break;
|
||||
case T5_LAYER_ATTN_O:
|
||||
layer.o = ggml_dup_tensor(model->ctx, tensor);
|
||||
model->set_tensor(layer.o, tensor);
|
||||
break;
|
||||
case T5_LAYER_OUT_NORM:
|
||||
layer.mlp_norm = ggml_dup_tensor(model->ctx, tensor);
|
||||
model->set_tensor(layer.mlp_norm, tensor);
|
||||
break;
|
||||
case T5_LAYER_WI_1:
|
||||
layer.wi_1 = ggml_dup_tensor(model->ctx, tensor);
|
||||
model->set_tensor(layer.wi_1, tensor);
|
||||
break;
|
||||
case T5_LAYER_WI_0:
|
||||
layer.wi_0 = ggml_dup_tensor(model->ctx, tensor);
|
||||
model->set_tensor(layer.wi_0, tensor);
|
||||
break;
|
||||
case T5_LAYER_WO:
|
||||
layer.wo = ggml_dup_tensor(model->ctx, tensor);
|
||||
model->set_tensor(layer.wo, tensor);
|
||||
break;
|
||||
case T5_RELATIVE_BIAS:
|
||||
model->relative_attn_bias = ggml_dup_tensor(model->ctx, tensor);
|
||||
model->set_tensor(model->relative_attn_bias, tensor);
|
||||
break;
|
||||
default:
|
||||
fprintf(stdout, "unassigned tensor %s\n", name.c_str());
|
||||
break;
|
||||
}
|
||||
} catch (const std::out_of_range& e) {
|
||||
TTS_ABORT("Error: %s\nTensor, '%s', is not a valid tensor.", e.what(), name.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void assign_to_t5_encoder(t5_encoder * model, const std::string name, ggml_tensor * tensor) {
|
||||
if (tensor->data == NULL) {
|
||||
return;
|
||||
}
|
||||
std::string::size_type pos = name.find(".", 0);
|
||||
std::string top_level(name.substr(0, pos));
|
||||
if (T5_TENSOR_GGUF_LOOKUP.find(name) != T5_TENSOR_GGUF_LOOKUP.end()) {
|
||||
switch (T5_TENSOR_GGUF_LOOKUP.at(name)) {
|
||||
case T5_EMBD:
|
||||
model->embd = ggml_dup_tensor(model->ctx, tensor);
|
||||
model->set_tensor(model->embd, tensor);
|
||||
break;
|
||||
case T5_NORM:
|
||||
model->out_norm = ggml_dup_tensor(model->ctx, tensor);
|
||||
model->set_tensor(model->out_norm, tensor);
|
||||
break;
|
||||
case T5_DOWN_PROJ:
|
||||
model->down_proj = ggml_dup_tensor(model->ctx, tensor);
|
||||
model->set_tensor(model->down_proj, tensor);
|
||||
break;
|
||||
case T5_DOWN_PROJ_BIAS:
|
||||
model->down_proj_bias = ggml_dup_tensor(model->ctx, tensor);
|
||||
model->set_tensor(model->down_proj_bias, tensor);
|
||||
break;
|
||||
default:
|
||||
fprintf(stdout, "unassigned tensor %s\n", name.c_str());
|
||||
break;
|
||||
}
|
||||
} else if (top_level == "t5encoder") {
|
||||
auto pair = parse_layer_count(name, 2);
|
||||
int l = pair.first;
|
||||
std::string lt_name = pair.second;
|
||||
|
||||
assign_to_t5_layer(model, model->layers[l], lt_name, tensor);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void t5_encoder::prep_layers(gguf_context * meta) {
|
||||
for (uint32_t i = 0; i < n_layers; i++) {
|
||||
t5_layer l;
|
||||
layers.push_back(l);
|
||||
}
|
||||
}
|
||||
|
||||
void t5_encoder::prep_constants(gguf_context * meta) {
|
||||
int n_layers_key = gguf_find_key(meta, "t5encoder.block_count");
|
||||
if (n_layers_key != -1) {
|
||||
n_layers = gguf_get_val_u32(meta, n_layers_key);
|
||||
}
|
||||
|
||||
int hidden_size_key = gguf_find_key(meta, "t5encoder.embedding_length");
|
||||
if (hidden_size_key != -1) {
|
||||
hidden_size = gguf_get_val_u32(meta, hidden_size_key);
|
||||
}
|
||||
|
||||
int attn_heads_key = gguf_find_key(meta, "t5encoder.attention.head_count");
|
||||
if (attn_heads_key != -1) {
|
||||
n_attn_heads = gguf_get_val_u32(meta, attn_heads_key);
|
||||
}
|
||||
|
||||
int context_size_key = gguf_find_key(meta, "t5encoder.context_length");
|
||||
if (context_size_key != -1) {
|
||||
max_context_length = gguf_get_val_u32(meta, context_size_key);
|
||||
}
|
||||
|
||||
int bos_token_id_key = gguf_find_key(meta, "tokenizer.ggml.bos_token_id");
|
||||
if (bos_token_id_key != -1) {
|
||||
bos_token_id = gguf_get_val_u32(meta, bos_token_id_key);
|
||||
}
|
||||
|
||||
int eos_token_id_key = gguf_find_key(meta, "tokenizer.ggml.eos_token_id");
|
||||
if (eos_token_id_key != -1) {
|
||||
eos_token_id = gguf_get_val_u32(meta, eos_token_id_key);
|
||||
}
|
||||
|
||||
int vocab_size_key = gguf_find_key(meta, "t5encoder.vocab_size");
|
||||
if (vocab_size_key == -1) {
|
||||
TTS_ABORT("key 't5encoder.vocab_size' must be specified in gguf file.");
|
||||
}
|
||||
vocab_size = gguf_get_val_u32(meta, vocab_size_key);
|
||||
|
||||
int output_size_key = gguf_find_key(meta, "t5encoder.output_size");
|
||||
if (output_size_key != -1) {
|
||||
output_size = gguf_get_val_u32(meta, output_size_key);
|
||||
}
|
||||
}
|
||||
|
||||
void t5_encoder::assign_weight(std::string name, ggml_tensor * tensor) {
|
||||
assign_to_t5_encoder(this, name, tensor);
|
||||
}
|
||||
|
||||
struct t5_context * build_new_t5_context(struct t5_encoder * model, int n_threads, bool use_cpu) {
|
||||
t5_context * t5ctx = new t5_context(model, n_threads);
|
||||
if (!use_cpu) {
|
||||
#ifdef GGML_USE_METAL
|
||||
t5ctx->backend = ggml_backend_metal_init();
|
||||
#endif
|
||||
}
|
||||
t5ctx->backend_cpu = ggml_backend_cpu_init();
|
||||
t5ctx->set_threads();
|
||||
t5ctx->build_schedule();
|
||||
t5ctx->buf_compute_meta.resize(ggml_tensor_overhead()*model->max_nodes() + ggml_graph_overhead_custom(model->max_nodes(), false));
|
||||
return t5ctx;
|
||||
}
|
||||
|
||||
static struct ggml_tensor * build_t5_norm(struct ggml_context * ctx, struct ggml_tensor * cur, struct ggml_tensor * weight) {
|
||||
// this is static for all versions of t5 flan
|
||||
float eps = 0.000001;
|
||||
cur = ggml_rms_norm(ctx, cur, eps);
|
||||
cur = ggml_mul(ctx, cur, weight);
|
||||
return cur;
|
||||
}
|
||||
|
||||
static struct ggml_tensor * build_t5_attn_mask(ggml_context * ctx, struct t5_context *t5ctx, const t5_ubatch & batch) {
|
||||
t5ctx->attn_mask = ggml_new_tensor_2d(ctx, GGML_TYPE_F32, (int64_t) batch.n_tokens, (int64_t) batch.n_tokens);
|
||||
ggml_set_input(t5ctx->attn_mask);
|
||||
|
||||
return t5ctx->attn_mask;
|
||||
}
|
||||
|
||||
static struct ggml_tensor * build_t5_pos_bias(ggml_context * ctx, struct ggml_tensor * pos_bucket, struct ggml_tensor * relative_attn_bias) {
|
||||
struct ggml_tensor * pos_bucket_1d = ggml_view_1d(ctx, pos_bucket, pos_bucket->ne[0] * pos_bucket->ne[1], 0);
|
||||
struct ggml_tensor * pos_bias = ggml_get_rows(ctx, relative_attn_bias, pos_bucket_1d);
|
||||
|
||||
pos_bias = ggml_view_3d(ctx, pos_bias, pos_bias->ne[0], pos_bucket->ne[0], pos_bucket->ne[1], ggml_element_size(pos_bias) * pos_bias->ne[0], ggml_element_size(pos_bias) * pos_bias->ne[0] * pos_bucket->ne[0], 0);
|
||||
pos_bias = ggml_permute(ctx, pos_bias, 2, 1, 0, 3);
|
||||
pos_bias = ggml_cont(ctx, pos_bias);
|
||||
return pos_bias;
|
||||
}
|
||||
|
||||
t5_ubatch t5_runner::build_worst_case_batch() {
|
||||
struct t5_ubatch batch;
|
||||
batch.n_tokens = model->max_context_length;
|
||||
return batch;
|
||||
}
|
||||
|
||||
void t5_runner::prepare_post_load() {
|
||||
auto batch = build_worst_case_batch();
|
||||
auto gf = build_t5_graph(batch);
|
||||
t5ctx->prep_schedule(gf);
|
||||
}
|
||||
|
||||
struct ggml_cgraph * t5_runner::build_t5_graph(t5_ubatch & batch) {
|
||||
init_build();
|
||||
struct ggml_cgraph * gf = ggml_new_graph_custom(ctx, 8192, false);
|
||||
|
||||
struct ggml_tensor * cur;
|
||||
struct ggml_tensor * inpL;
|
||||
|
||||
//t5ctx->positions = ggml_new_tensor_1d(ctx, GGML_TYPE_I32, batch.n_tokens);
|
||||
//ggml_set_input(t5ctx->positions);
|
||||
|
||||
t5ctx->inp_pos_bucket = ggml_new_tensor_2d(ctx, GGML_TYPE_I32, batch.n_tokens, batch.n_tokens);
|
||||
ggml_set_input(t5ctx->inp_pos_bucket);
|
||||
|
||||
t5ctx->inp_tokens = ggml_new_tensor_1d(ctx, GGML_TYPE_I32, batch.n_tokens);
|
||||
ggml_set_input(t5ctx->inp_tokens);
|
||||
|
||||
inpL = ggml_get_rows(ctx, model->embd, t5ctx->inp_tokens);
|
||||
|
||||
struct ggml_tensor * KQ_mask_dec = build_t5_attn_mask(ctx, t5ctx, batch);
|
||||
struct ggml_tensor * pos_bias = build_t5_pos_bias(ctx, t5ctx->inp_pos_bucket, model->relative_attn_bias);
|
||||
|
||||
for (int l = 0; l < model->n_layers; l++) {
|
||||
struct ggml_tensor * residual = inpL;
|
||||
|
||||
cur = build_t5_norm(ctx, inpL, model->layers[l].attn_norm);
|
||||
|
||||
struct ggml_tensor * attn_out;
|
||||
|
||||
// self-attention
|
||||
{
|
||||
struct ggml_tensor * Qcur = ggml_mul_mat(ctx, model->layers[l].q, cur);
|
||||
struct ggml_tensor * Kcur = ggml_mul_mat(ctx, model->layers[l].k, cur);
|
||||
struct ggml_tensor * Vcur = ggml_mul_mat(ctx, model->layers[l].v, cur);
|
||||
|
||||
Qcur = ggml_reshape_3d(ctx, Qcur, model->head_size, model->n_attn_heads, batch.n_tokens);
|
||||
Kcur = ggml_reshape_3d(ctx, Kcur, model->head_size, model->n_attn_heads, batch.n_tokens);
|
||||
|
||||
struct ggml_tensor * q = ggml_permute(ctx, Qcur, 0, 2, 1, 3);
|
||||
struct ggml_tensor * k = ggml_cont(ctx, ggml_permute(ctx, Kcur, 0, 2, 1, 3));
|
||||
|
||||
struct ggml_tensor * kq = ggml_mul_mat(ctx, k, q);
|
||||
kq = ggml_add(ctx, kq, pos_bias);
|
||||
|
||||
kq = ggml_soft_max_ext(ctx, kq, KQ_mask_dec, 1.0f, 0.0f);
|
||||
|
||||
struct ggml_tensor * v = ggml_cont_3d(ctx, ggml_transpose(ctx, Vcur), batch.n_tokens, model->head_size, model->n_attn_heads);
|
||||
struct ggml_tensor * kqv = ggml_mul_mat(ctx, kq, v);
|
||||
struct ggml_tensor * kqv_merged = ggml_permute(ctx, kqv, 2, 0, 1, 3);
|
||||
attn_out = ggml_cont_2d(ctx, kqv_merged, model->hidden_size, batch.n_tokens);
|
||||
attn_out = ggml_mul_mat(ctx, model->layers[l].o, attn_out);
|
||||
}
|
||||
|
||||
cur = ggml_add(ctx, attn_out, residual);
|
||||
struct ggml_tensor * residualmlp = cur;
|
||||
|
||||
// mlp
|
||||
{
|
||||
cur = build_t5_norm(ctx, cur, model->layers[l].mlp_norm);
|
||||
struct ggml_tensor * gate_proj = ggml_mul_mat(ctx, model->layers[l].wi_1, cur);
|
||||
cur = ggml_mul(ctx, ggml_gelu(ctx, ggml_mul_mat(ctx, model->layers[l].wi_0, cur)), gate_proj);
|
||||
cur = ggml_mul_mat(ctx, model->layers[l].wo, cur);
|
||||
}
|
||||
|
||||
cur = ggml_add(ctx, cur, residualmlp);
|
||||
inpL = cur;
|
||||
}
|
||||
|
||||
cur = build_t5_norm(ctx, cur, model->out_norm);
|
||||
|
||||
if (model->down_proj) {
|
||||
cur = ggml_mul_mat(ctx, model->down_proj, cur);
|
||||
}
|
||||
|
||||
if (model->down_proj_bias) {
|
||||
cur = ggml_add(ctx, cur, model->down_proj_bias);
|
||||
}
|
||||
|
||||
ggml_build_forward_expand(gf, cur);
|
||||
|
||||
free_build();
|
||||
|
||||
return gf;
|
||||
}
|
||||
|
||||
void t5_runner::set_inputs(t5_ubatch & batch) {
|
||||
ggml_backend_tensor_set(t5ctx->inp_tokens, batch.input_tokens, 0, batch.n_tokens*ggml_element_size(t5ctx->inp_tokens));
|
||||
float * attn_mask = nullptr;
|
||||
uint32_t * positions = nullptr;
|
||||
uint32_t * pos_bucket = nullptr;
|
||||
attn_mask = (float *) t5ctx->attn_mask->data;
|
||||
positions = (uint32_t *) t5ctx->positions->data;
|
||||
pos_bucket = (uint32_t *) t5ctx->inp_pos_bucket->data;
|
||||
int n_buckets = (int) model->relative_attn_buckets / 2;
|
||||
int max_exact = (int) n_buckets / 2;
|
||||
float logarithmic_denominator = log(128.0 / max_exact);
|
||||
for (int i = 0; i < batch.n_tokens; i++) {
|
||||
for (int ii = 0; ii < batch.n_tokens; ii++) {
|
||||
int ab_rpos = abs(i - ii);
|
||||
int rpos = i - ii;
|
||||
attn_mask[i*batch.n_tokens + ii] = 0.0f; //ii > i ? -INFINITY : 0.0f;
|
||||
pos_bucket[i*batch.n_tokens + ii] = (uint32_t) (rpos > 0 ? n_buckets : 0) + (ab_rpos < max_exact ? ab_rpos : std::min((n_buckets - 1), (max_exact + (int)((log((ab_rpos / max_exact)) / logarithmic_denominator) * max_exact))));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void t5_runner::run(uint32_t * input_tokens, uint32_t sequence_length, struct tts_response * outputs) {
|
||||
t5_ubatch batch;
|
||||
batch.input_tokens = input_tokens;
|
||||
batch.n_tokens = sequence_length;
|
||||
ggml_backend_sched_reset(t5ctx->sched);
|
||||
|
||||
const size_t prev_size = t5ctx->buf_output ? ggml_backend_buffer_get_size(t5ctx->buf_output) : 0;
|
||||
const size_t new_size = model->max_context_length * model->output_size * sizeof(float);
|
||||
|
||||
if (!t5ctx->buf_output || prev_size < new_size) {
|
||||
if (t5ctx->buf_output) {
|
||||
ggml_backend_buffer_free(t5ctx->buf_output);
|
||||
t5ctx->buf_output = nullptr;
|
||||
t5ctx->logits = nullptr;
|
||||
}
|
||||
|
||||
t5ctx->buf_output = ggml_backend_buft_alloc_buffer(t5ctx->backend_cpu_buffer, new_size);
|
||||
}
|
||||
|
||||
outputs->data = (float *) ggml_backend_buffer_get_base(t5ctx->buf_output);
|
||||
ggml_backend_buffer_clear(t5ctx->buf_output, 0);
|
||||
struct ggml_cgraph * gf = NULL;
|
||||
gf = build_t5_graph(batch);
|
||||
// the output is always the last tensor in the graph
|
||||
struct ggml_tensor * result = gf->nodes[gf->n_nodes - 1];
|
||||
ggml_backend_sched_alloc_graph(t5ctx->sched, gf);
|
||||
set_inputs(batch);
|
||||
|
||||
ggml_backend_sched_graph_compute_async(t5ctx->sched, gf);
|
||||
|
||||
t5ctx->get_ggml_node_data(result, outputs->data, batch.n_tokens*sizeof(float)*model->output_size);
|
||||
|
||||
// Reset state for the next token before backend sync, to allow the CPU activities in the reset to
|
||||
// overlap with device computation.
|
||||
ggml_backend_sched_reset(t5ctx->sched);
|
||||
outputs->n_outputs = sequence_length;
|
||||
outputs->hidden_size = model->output_size;
|
||||
return;
|
||||
}
|
||||
|
||||
int t5_runner::generate(std::string prompt, tts_response *response) {
|
||||
std::vector<uint32_t> tokens;
|
||||
tokenizer->tokenize(prompt, tokens);
|
||||
tokens.push_back(model->eos_token_id);
|
||||
run(tokens.data(), (uint32_t) tokens.size(), response);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct t5_runner * text_encoder_from_file(std::string file_path, int n_threads, unigram_tokenizer * tokenizer, bool cpu_only) {
|
||||
t5_encoder * model = new t5_encoder;
|
||||
ggml_context * weight_ctx = NULL;
|
||||
|
||||
struct gguf_init_params params = {
|
||||
/*.no_alloc =*/ false,
|
||||
/*.ctx =*/ &weight_ctx,
|
||||
};
|
||||
gguf_context * meta_ctx = gguf_init_from_file(file_path.c_str(), params);
|
||||
if (!meta_ctx) {
|
||||
TTS_ABORT("%s failed for file %s\n", __func__, file_path.c_str());
|
||||
}
|
||||
if (!tokenizer) {
|
||||
tokenizer = unigram_tokenizer_from_gguf(meta_ctx);
|
||||
}
|
||||
if (!tokenizer->init) {
|
||||
tokenizer->initialize_tokenizer();
|
||||
}
|
||||
model->setup_from_file(meta_ctx, weight_ctx, cpu_only);
|
||||
|
||||
// TODO: change this weight assignment pattern to mirror llama.cpp
|
||||
for (ggml_tensor * cur = ggml_get_first_tensor(weight_ctx); cur; cur = ggml_get_next_tensor(weight_ctx, cur)) {
|
||||
model->assign_weight(cur->name, cur);
|
||||
}
|
||||
|
||||
struct t5_context * t5ctx = build_new_t5_context(model, n_threads, cpu_only);
|
||||
struct t5_runner * runner = new t5_runner(model, t5ctx, tokenizer);
|
||||
runner->prepare_post_load();
|
||||
gguf_free(meta_ctx);
|
||||
ggml_free(weight_ctx);
|
||||
|
||||
return runner;
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
#ifndef t5_encoder_model_h
|
||||
#define t5_encoder_model_h
|
||||
|
||||
#include "tts_model.h"
|
||||
#include "tokenizer.h"
|
||||
|
||||
|
||||
enum t5_tensor {
|
||||
T5_EMBD,
|
||||
T5_NORM,
|
||||
T5_DOWN_PROJ,
|
||||
T5_DOWN_PROJ_BIAS,
|
||||
T5_RELATIVE_BIAS,
|
||||
T5_LAYER_ATTN_Q,
|
||||
T5_LAYER_ATTN_K,
|
||||
T5_LAYER_ATTN_V,
|
||||
T5_LAYER_ATTN_O,
|
||||
T5_LAYER_ATTN_NORM,
|
||||
T5_LAYER_WI_0,
|
||||
T5_LAYER_WI_1,
|
||||
T5_LAYER_WO,
|
||||
T5_LAYER_OUT_NORM,
|
||||
};
|
||||
|
||||
struct t5_layer {
|
||||
struct ggml_tensor * q;
|
||||
struct ggml_tensor * k;
|
||||
struct ggml_tensor * v;
|
||||
struct ggml_tensor * o;
|
||||
struct ggml_tensor * attn_norm;
|
||||
struct ggml_tensor * wi_0;
|
||||
struct ggml_tensor * wi_1;
|
||||
struct ggml_tensor * wo;
|
||||
struct ggml_tensor * mlp_norm;
|
||||
};
|
||||
|
||||
// this struct maintains the static tensors for a t5_encoder model
|
||||
// the defautl configuration is form copied from standard configuration for
|
||||
// flan-t5-xl. Note this model is slightly different from a standard t5 encoder.
|
||||
// Specifically this model has a down projection which converts the text encoder's
|
||||
// hidden size to the hidden size of the parler decoder.
|
||||
struct t5_encoder : tts_model {
|
||||
// These configs are essentially built for the 44khZ 8kbps standard DAC model audio encoder and decoder
|
||||
uint32_t n_layers = 24;
|
||||
uint32_t n_attn_heads = 32;
|
||||
uint32_t head_size = 64;
|
||||
uint32_t hidden_size = 2048;
|
||||
uint32_t relative_attn_buckets = 32;
|
||||
uint32_t eos_token_id = 1;
|
||||
uint32_t bos_token_id = 0;
|
||||
uint32_t max_context_length = 512;
|
||||
uint32_t output_size = 1536;
|
||||
uint32_t vocab_size;
|
||||
|
||||
struct ggml_tensor * embd;
|
||||
struct ggml_tensor * relative_attn_bias;
|
||||
struct ggml_tensor * out_norm;
|
||||
struct ggml_tensor * down_proj = nullptr;
|
||||
struct ggml_tensor * down_proj_bias = nullptr;
|
||||
std::vector<t5_layer> layers;
|
||||
|
||||
void assign_weight(std::string name, ggml_tensor * tensor);
|
||||
void prep_layers(gguf_context * meta);
|
||||
void prep_constants(gguf_context * meta);
|
||||
void setup_from_file(gguf_context * meta_ctx, ggml_context * load_context, bool cpu_only = true) {
|
||||
prep_constants(meta_ctx);
|
||||
prep_layers(meta_ctx);
|
||||
tts_model::setup_from_file(meta_ctx, load_context, cpu_only, "t5encoder", 1.25);
|
||||
}
|
||||
};
|
||||
|
||||
// For assigning weights from gguf file to local model.
|
||||
void assign_to_t5_encoder(t5_encoder * model, const std::string name, ggml_tensor * tensor);
|
||||
void assign_to_t5_layer(t5_encoder * model, t5_layer & layer, std::string name, ggml_tensor * tensor);
|
||||
|
||||
struct t5_context : runner_context {
|
||||
t5_context(t5_encoder * model, int n_threads): runner_context(n_threads), model(model) {};
|
||||
|
||||
struct t5_encoder * model;
|
||||
|
||||
struct ggml_tensor * inp_tokens;
|
||||
struct ggml_tensor * positions;
|
||||
struct ggml_tensor * attn_mask;
|
||||
struct ggml_tensor * inp_pos_bucket;
|
||||
|
||||
void build_schedule() {
|
||||
runner_context::build_schedule(model->max_nodes());
|
||||
}
|
||||
};
|
||||
|
||||
struct t5_context * build_new_t5_context(struct t5_encoder * model, int n_threads, bool use_cpu = true);
|
||||
|
||||
struct t5_ubatch {
|
||||
size_t n_tokens; // the number of tokens in our encoded sequence
|
||||
uint32_t * input_tokens; // [n_tokens]
|
||||
};
|
||||
|
||||
static struct ggml_tensor * build_t5_norm(struct ggml_context * ctx, struct ggml_tensor * cur, struct ggml_tensor * weight);
|
||||
static struct ggml_tensor * build_t5_attn_mask(ggml_context * ctx, struct t5_context *t5ctx, const t5_ubatch & batch);
|
||||
|
||||
// This struct is intended to manage the t5 encoder model's graph compilation and compute function.
|
||||
struct t5_runner : tts_runner {
|
||||
t5_runner(t5_encoder * model, t5_context * context, unigram_tokenizer * tokenizer): model(model), t5ctx(context), tokenizer(tokenizer) {};
|
||||
~t5_runner() {
|
||||
if (ctx) {
|
||||
ggml_free(ctx);
|
||||
}
|
||||
model->free();
|
||||
delete model;
|
||||
delete t5ctx;
|
||||
}
|
||||
struct unigram_tokenizer * tokenizer;
|
||||
t5_encoder * model;
|
||||
t5_context * t5ctx;
|
||||
|
||||
void init_build() {
|
||||
tts_runner::init_build(&t5ctx->buf_compute_meta);
|
||||
}
|
||||
|
||||
void prepare_post_load();
|
||||
struct t5_ubatch build_worst_case_batch();
|
||||
void set_inputs(t5_ubatch & batch);
|
||||
struct ggml_cgraph * build_t5_graph(t5_ubatch & batch);
|
||||
void run(uint32_t * input_tokens, uint32_t sequence_length, struct tts_response * outputs);
|
||||
int generate(std::string prompt, struct tts_response * response);
|
||||
};
|
||||
|
||||
struct t5_runner * text_encoder_from_file(std::string file_path, int n_threads, unigram_tokenizer * tokenizer, bool cpu_only = true);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,331 @@
|
||||
#include "tokenizer.h"
|
||||
|
||||
void token_trie::add(const std::string & gram, uint32_t token) {
|
||||
_add(gram, token, 0);
|
||||
}
|
||||
|
||||
void token_trie::_add(const std::string & gram, uint32_t new_token, size_t index) {
|
||||
if (index >= gram.size()) {
|
||||
has_value = true;
|
||||
token = new_token;
|
||||
return;
|
||||
}
|
||||
const char c = gram[index];
|
||||
auto res = children.find(c);
|
||||
if (res != children.end()) {
|
||||
res->second._add(gram, new_token, index + 1);
|
||||
} else {
|
||||
struct token_trie nt{};
|
||||
nt._add(gram, new_token, index + 1);
|
||||
children[c] = nt;
|
||||
}
|
||||
}
|
||||
|
||||
const struct token_trie * token_trie::traverse(const char c) const {
|
||||
auto res = children.find(c);
|
||||
if (res != children.end()) {
|
||||
return &res->second;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t unicode_len_utf8_tts(char src) {
|
||||
const size_t lookup[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 3, 4 };
|
||||
uint8_t highbits = static_cast<uint8_t>(src) >> 4;
|
||||
return lookup[highbits];
|
||||
}
|
||||
|
||||
void unigram_tokenizer::initialize_tokenizer() {
|
||||
for (const auto it : vocab) {
|
||||
root_trie.add(it.first, it.second);
|
||||
}
|
||||
init = true;
|
||||
}
|
||||
|
||||
// the general approach here is to find the character grams that sum to the max possible value over the entire text sequence.
|
||||
// The particular algorithm used here effectively works by walking the text and at each index storing the max value of all possible gram combinations
|
||||
// we can then reverse that sequence to pick the best possible tokens.
|
||||
void unigram_tokenizer::tokenize(const std::string & text, std::vector<uint32_t> & tokens) {
|
||||
if (!init) {
|
||||
TTS_ABORT("Error: %s\nTokenizer must be initialized before #tokenize is called.");
|
||||
}
|
||||
// the parler tokenizer's normalizer (i.e. the bert normalizer implemented by huggingface tokenizers libs) only deduplicates and strips extra spaces and
|
||||
// optionally handles chinese characters and accents (neither of which are currently supported here).
|
||||
std::string normalized = text;
|
||||
if (dedupe_spaces) {
|
||||
normalized = " " + std::regex_replace(text, duped_spaces, " ");
|
||||
}
|
||||
|
||||
size_t text_length = normalized.size();
|
||||
|
||||
// initialize score_sum to neg infinity so it will be always lower than sums of token scores
|
||||
std::vector<struct result> results(text_length + 1, {unk_token, 0, -INFINITY});
|
||||
results[0] = { unk_token, 0, 0 };
|
||||
|
||||
size_t offset = 0;
|
||||
|
||||
while (offset < text_length) {
|
||||
size_t current_offset = offset;
|
||||
// pulled this directly from llama.cpp; I suspect that this is for handling of non-utf8 steps (to be marked as unknown tokens)
|
||||
size_t n_utf8_code_units = std::min<size_t>(unicode_len_utf8_tts(normalized[offset]), text_length - offset);
|
||||
|
||||
bool found_unknown = true;
|
||||
const struct result & current_best = results[offset];
|
||||
|
||||
// find the current branch in the trie
|
||||
const struct token_trie * node = root_trie.traverse(normalized[current_offset++]);
|
||||
// search for the next token
|
||||
while (current_offset <= text_length && node != NULL) {
|
||||
// check if this is a complete token (it could just be an unkown step between two tokens).
|
||||
if (node->has_value) {
|
||||
// check if it corresponds to the whole utf8 step
|
||||
if (current_offset - offset == n_utf8_code_units) {
|
||||
found_unknown = false;
|
||||
}
|
||||
float score = current_best.score + scores[node->token];
|
||||
struct result & current_champ = results[current_offset];
|
||||
if (score > current_champ.score) {
|
||||
struct result challenger = { node->token, offset, score };
|
||||
current_champ = challenger;
|
||||
}
|
||||
}
|
||||
node = node->traverse(normalized[current_offset++]);
|
||||
}
|
||||
|
||||
// if we found an unknown token, process it
|
||||
if (found_unknown) {
|
||||
current_offset = offset + n_utf8_code_units;
|
||||
struct result & current_champ = results[current_offset];
|
||||
float score = current_best.score + unk_token_score;
|
||||
if (score > current_champ.score) {
|
||||
struct result challenger = { unk_token, offset, score };
|
||||
current_champ = challenger;
|
||||
}
|
||||
}
|
||||
|
||||
// move one utf8 step
|
||||
offset += n_utf8_code_units;
|
||||
}
|
||||
|
||||
// if we have more than on unknown token in a row, we can join them.
|
||||
bool is_prev_unknown = false;
|
||||
// iterate from the last result backwards and get the best performing tokens
|
||||
for (struct result & result = results[text_length]; ; result = results[result.offset]) {
|
||||
bool is_unknown = result.token == unk_token;
|
||||
if (!(is_prev_unknown && is_unknown)) {
|
||||
tokens.push_back(result.token);
|
||||
}
|
||||
if (result.offset == 0) {
|
||||
break;
|
||||
}
|
||||
is_prev_unknown = is_unknown;
|
||||
}
|
||||
|
||||
// reverse the tokens since we added tokens starting from the end of the input
|
||||
std::reverse(tokens.begin(), tokens.end());
|
||||
}
|
||||
|
||||
// loading the vocab to the tokenizer from gguf file.
|
||||
unigram_tokenizer * unigram_tokenizer_from_gguf(gguf_context * meta) {
|
||||
std::unordered_map<std::string, uint32_t> vocab;
|
||||
std::vector<float> scores;
|
||||
int vocab_key = gguf_find_key(meta, "tokenizer.ggml.tokens");
|
||||
int vocab_size = gguf_get_arr_n(meta, vocab_key);
|
||||
scores.reserve(vocab_size);
|
||||
for (int i = 0; i < vocab_size; i++) {
|
||||
std::string val = gguf_get_arr_str(meta, vocab_key, i);
|
||||
vocab[val] = (uint32_t) i;
|
||||
}
|
||||
int scores_key = gguf_find_key(meta, "tokenizer.ggml.scores");
|
||||
int scores_size = gguf_get_arr_n(meta, scores_key);
|
||||
assert(scores_size == vocab_size);
|
||||
float * data = (float*) gguf_get_arr_data(meta, scores_key);
|
||||
for (int i = 0; i < scores_size; i++) {
|
||||
scores.push_back(data[i]);
|
||||
}
|
||||
int unkown_token_key = gguf_find_key(meta, "tokenizer.ggml.unknown_token_id");
|
||||
uint32_t token = gguf_get_val_u32(meta, unkown_token_key);
|
||||
|
||||
auto tokenizer = new unigram_tokenizer(vocab, token, scores[token], scores);
|
||||
|
||||
uint32_t eos_token_key = gguf_find_key(meta, "tokenizer.ggml.eos_token_id");
|
||||
if (eos_token_key != -1) {
|
||||
tokenizer->eos_token = gguf_get_val_u32(meta, eos_token_key);
|
||||
}
|
||||
return tokenizer;
|
||||
}
|
||||
|
||||
void single_pass_tokenizer::tokenize(const std::string & text, std::vector<uint32_t> & token_ids) {
|
||||
std::string remaining = text;
|
||||
while (remaining.size() > 0) {
|
||||
uint32_t token_id = unknown_id;
|
||||
for (int i = 1; i < std::min(remaining.size()+1, max_size+1); i++) {
|
||||
std::string part = remaining.substr(0, i);
|
||||
ptrdiff_t pos = std::distance(tokens.begin(), std::find(tokens.begin(), tokens.end(), part));
|
||||
if (pos < tokens.size()) {
|
||||
token_id = (uint32_t) pos;
|
||||
remaining = remaining.substr(part.size(), remaining.size() - part.size());
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (token_id == unknown_id) {
|
||||
remaining = remaining.substr(1, remaining.size() - 1);
|
||||
}
|
||||
token_ids.push_back(token_id);
|
||||
}
|
||||
}
|
||||
|
||||
void single_pass_tokenizer::token_split(const std::string & text, std::vector<std::string> & tokens) {
|
||||
std::string remaining = text;
|
||||
while (remaining.size() > 0) {
|
||||
// String copying is much slower than using a std::string_view, but the former is simpler to implement for now.
|
||||
std::string token = remaining.substr(0, 1);
|
||||
for (int i = 1; i < remaining.size(); i++) {
|
||||
std::string part = remaining.substr(0, i+1);
|
||||
if (token_vocab.find(part) == token_vocab.end()) {
|
||||
break;
|
||||
}
|
||||
token = part;
|
||||
}
|
||||
tokens.push_back(token);
|
||||
remaining = remaining.substr(token.size(), remaining.size() - token.size());
|
||||
}
|
||||
}
|
||||
|
||||
struct single_pass_tokenizer * single_pass_tokenizer_from_gguf(gguf_context * meta, std::string key_name) {
|
||||
int tokens_key = gguf_find_key(meta, key_name.c_str());
|
||||
if (tokens_key == -1) {
|
||||
TTS_ABORT("The '%s' key must be set in order to support single pass tokenization.", key_name.c_str());
|
||||
}
|
||||
std::vector<std::string> tokens;
|
||||
int token_count = gguf_get_arr_n(meta, tokens_key);
|
||||
for (int i = 0; i < token_count; i++) {
|
||||
tokens.push_back(gguf_get_arr_str(meta, tokens_key, i));
|
||||
}
|
||||
return new single_pass_tokenizer(tokens);
|
||||
}
|
||||
|
||||
void bpe_symbol::add_merges(std::priority_queue<bpe_merge, std::vector<bpe_merge>, bpe_merge_comp> & merges, std::unordered_map<std::pair<std::string, std::string>, int, pair_hash> & rank_map, bool only_forward) {
|
||||
if (!only_forward && last) {
|
||||
auto rid = std::make_pair<std::string, std::string>(last->as_str(), as_str());
|
||||
if (rank_map.find(rid) != rank_map.end()) {
|
||||
bpe_merge m{last, this, rank_map[rid], last->size + size};
|
||||
merges.push(m);
|
||||
}
|
||||
}
|
||||
|
||||
if (next) {
|
||||
auto rid = std::make_pair<std::string, std::string>(as_str(), next->as_str());
|
||||
if (rank_map.find(rid) != rank_map.end()) {
|
||||
bpe_merge m{this, next, rank_map[rid], size + next->size};
|
||||
merges.push(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string bpe_symbol::as_str() {
|
||||
return std::string(token, size);
|
||||
}
|
||||
|
||||
bool bpe_merge_comp::operator() (const bpe_merge & a, const bpe_merge & b) {
|
||||
return a.rank > b.rank || (a.rank == b.rank && a.a && b.a && a.a->pos > b.a->pos);
|
||||
}
|
||||
|
||||
size_t pair_hash::operator() (const std::pair<std::string, std::string> & p) const {
|
||||
return std::hash<std::string>{}(p.first) ^ (std::hash<std::string>{}(p.second) << 1);
|
||||
}
|
||||
|
||||
bpe_symbol * bpe_merge::merge() {
|
||||
a->size += b->size;
|
||||
b->size = -1;
|
||||
a->next = b->next;
|
||||
if (a->next) {
|
||||
a->next->last = a;
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
void pair_builder::join_pairs(std::unordered_map<std::pair<std::string, std::string>, int, pair_hash> & rank_map) {
|
||||
std::priority_queue<bpe_merge, std::vector<bpe_merge>, bpe_merge_comp> merges;
|
||||
for (auto part : parts) {
|
||||
part->add_merges(merges, rank_map, true);
|
||||
}
|
||||
while (!merges.empty()) {
|
||||
auto m = merges.top();
|
||||
merges.pop();
|
||||
if (m.a->size > 0 && m.b->size > 0 && m.new_size == m.a->size + m.b->size) {
|
||||
m.merge();
|
||||
m.a->add_merges(merges, rank_map);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void bpe_tokenizer::tokenize(const std::string & text, std::vector<uint32_t> & token_ids) {
|
||||
std::vector<std::string> chunks = split(text, " ", true);
|
||||
bool space_prior = false;
|
||||
for (auto chunk : chunks) {
|
||||
if (chunk != " ") {
|
||||
bpe_tokenize(space_prior ? "Ġ" + chunk : chunk, token_ids);
|
||||
} else {
|
||||
space_prior = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void bpe_tokenizer::bpe_tokenize(std::string chunk, std::vector<uint32_t> & token_ids) {
|
||||
if (tokens_to_ids.find(chunk) != tokens_to_ids.end()) {
|
||||
token_ids.push_back(tokens_to_ids[chunk]);
|
||||
return;
|
||||
}
|
||||
auto pb = pair_builder{chunk};
|
||||
pb.join_pairs(ranks);
|
||||
bpe_symbol * next = pb.parts[0];
|
||||
while (next) {
|
||||
token_ids.push_back(tokens_to_ids[next->as_str()]);
|
||||
next = next->next;
|
||||
}
|
||||
}
|
||||
|
||||
bpe_tokenizer * bpe_tokenizer_from_gguf(gguf_context * meta, std::string base_name) {
|
||||
int vocab_key = gguf_find_key(meta, (base_name + ".tokens").c_str());
|
||||
if (vocab_key == -1) {
|
||||
TTS_ABORT("The '%s' key must be set in order to support BPE tokenization.", (base_name + ".tokens").c_str());
|
||||
}
|
||||
int merges_key = gguf_find_key(meta, (base_name + ".merges").c_str());
|
||||
if (merges_key == -1) {
|
||||
TTS_ABORT("The '%s' key must be set in order to support BPE tokenization.", (base_name + ".merges").c_str());
|
||||
}
|
||||
int eos_token_id_key = gguf_find_key(meta, (base_name + ".eos_token_id").c_str());
|
||||
if (eos_token_id_key == -1) {
|
||||
TTS_ABORT("The '%s' key must be set in order to support BPE tokenization.", (base_name + ".eos_token_id").c_str());
|
||||
}
|
||||
int bos_token_id_key = gguf_find_key(meta, (base_name + ".bos_token_id").c_str());
|
||||
if (bos_token_id_key == -1) {
|
||||
TTS_ABORT("The '%s' key must be set in order to support BPE tokenization.", (base_name + ".bos_token_id").c_str());
|
||||
}
|
||||
|
||||
uint32_t bos_token_id = gguf_get_val_u32(meta, bos_token_id_key);
|
||||
uint32_t eos_token_id = gguf_get_val_u32(meta, eos_token_id_key);
|
||||
|
||||
std::unordered_map<std::string, uint32_t> vocab;
|
||||
int token_count = gguf_get_arr_n(meta, vocab_key);
|
||||
for (int i = 0; i < token_count; i++) {
|
||||
vocab[gguf_get_arr_str(meta, vocab_key, i)] = (uint32_t) i;
|
||||
}
|
||||
|
||||
std::unordered_map<std::pair<std::string, std::string>, int, pair_hash> ranks;
|
||||
int merge_count = gguf_get_arr_n(meta, merges_key);
|
||||
|
||||
for (int i = 0; i < merge_count; i++) {
|
||||
auto raw_merge = gguf_get_arr_str(meta, merges_key, i);
|
||||
std::vector<std::string> pair = split(raw_merge, " ");
|
||||
if (pair.size() != 2) {
|
||||
TTS_ABORT("Invalid pair, '%s', found in BPE merges, '%s', at index %d.", raw_merge, (base_name + ".merges").c_str(), i);
|
||||
}
|
||||
ranks[std::make_pair<>(pair[0], pair[1])] = i;
|
||||
}
|
||||
|
||||
return new bpe_tokenizer(vocab, ranks, bos_token_id, eos_token_id);
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
#ifndef tokenizer_h
|
||||
#define tokenizer_h
|
||||
|
||||
#include <unordered_map>
|
||||
#include <stdint.h>
|
||||
#include <map>
|
||||
#include <unordered_set>
|
||||
#include <regex>
|
||||
#include <queue>
|
||||
#include "ttsutil.h"
|
||||
|
||||
struct token_trie {
|
||||
bool has_value = false;
|
||||
uint32_t token;
|
||||
std::map<char, struct token_trie> children;
|
||||
|
||||
void add(const std::string & gram, uint32_t token);
|
||||
void _add(const std::string & gram, uint32_t new_token, size_t index);
|
||||
const struct token_trie * traverse(const char c) const;
|
||||
};
|
||||
|
||||
static std::regex duped_spaces("\\s{2,}");
|
||||
static std::regex spaces("\\s");
|
||||
|
||||
struct result {
|
||||
uint32_t token;
|
||||
size_t offset;
|
||||
float score;
|
||||
};
|
||||
|
||||
// much of this is implemented in llama.cpp, but in order to simplify this for my use case, I reimplementing here.
|
||||
// There are several important simplifications here:
|
||||
// 1. I only implement unigram tokenization
|
||||
// 2. I don't need to support detokenization
|
||||
struct unigram_tokenizer {
|
||||
unigram_tokenizer(std::unordered_map<std::string, uint32_t> vocab, uint32_t unk_token, float unk_token_score, std::vector<float> scores): vocab(vocab), unk_token(unk_token), unk_token_score(unk_token_score), scores(scores) {};
|
||||
~unigram_tokenizer() = default;
|
||||
|
||||
std::unordered_map<std::string, uint32_t> vocab;
|
||||
std::vector<float> scores;
|
||||
struct token_trie root_trie;
|
||||
uint32_t unk_token;
|
||||
float unk_token_score;
|
||||
uint32_t eos_token = 1;
|
||||
bool dedupe_spaces = true;
|
||||
bool init = false;
|
||||
|
||||
void initialize_tokenizer();
|
||||
void tokenize(const std::string & text, std::vector<uint32_t> & tokens);
|
||||
};
|
||||
|
||||
// For intializing a new tokenizer from a gguf file meta
|
||||
unigram_tokenizer * unigram_tokenizer_from_gguf(gguf_context * meta);
|
||||
|
||||
// While this functions like a tokenizer, no token ids are assigned as the token ids never need to be used in the context in which this is
|
||||
// currently being used. This tokenizer pattern is currently being used by the phonemizer to break up a word into its relevant graphemes.
|
||||
// As such, only the graphemes need to be returned.
|
||||
struct single_pass_tokenizer {
|
||||
single_pass_tokenizer(std::vector<std::string> tkns): tokens(tkns) {
|
||||
max_size = 0;
|
||||
for (auto token : tkns) {
|
||||
token_vocab.insert(token);
|
||||
if (token.size() > max_size) {
|
||||
max_size = token.size();
|
||||
}
|
||||
}
|
||||
}
|
||||
size_t max_size;
|
||||
uint32_t unknown_id = 0;
|
||||
std::vector<std::string> tokens;
|
||||
std::unordered_set<std::string> token_vocab;
|
||||
void tokenize(const std::string & text, std::vector<uint32_t> & token_ids);
|
||||
void token_split(const std::string & text, std::vector<std::string> & tokens);
|
||||
};
|
||||
|
||||
single_pass_tokenizer * single_pass_tokenizer_from_gguf(gguf_context * meta, std::string key_name = "phonemizer.graphemes");
|
||||
|
||||
struct bpe_symbol;
|
||||
|
||||
struct bpe_merge {
|
||||
bpe_symbol * a;
|
||||
bpe_symbol * b;
|
||||
int rank;
|
||||
int new_size;
|
||||
|
||||
bpe_symbol * merge();
|
||||
};
|
||||
|
||||
struct bpe_merge_comp{
|
||||
bool operator() (const bpe_merge & a, const bpe_merge & b);
|
||||
};
|
||||
|
||||
struct pair_hash {
|
||||
size_t operator() (const std::pair<std::string, std::string> & p) const;
|
||||
};
|
||||
|
||||
struct bpe_symbol {
|
||||
bpe_symbol(const char * token): token(token) {};
|
||||
const char* token;
|
||||
int size = 1;
|
||||
int pos;
|
||||
bpe_symbol * next = nullptr;
|
||||
bpe_symbol * last = nullptr;
|
||||
|
||||
void add_merges(std::priority_queue<bpe_merge, std::vector<bpe_merge>, bpe_merge_comp> & merges, std::unordered_map<std::pair<std::string, std::string>, int, pair_hash> & rank_map, bool only_forward = false);
|
||||
std::string as_str();
|
||||
};
|
||||
|
||||
struct pair_builder {
|
||||
pair_builder(std::string word) {
|
||||
bpe_symbol * last = nullptr;
|
||||
for (int i = 0; i < word.size(); i++) {
|
||||
int increment = 0;
|
||||
// make sure we process each utf-8 character.
|
||||
while(i + increment + 1 < word.size() && (word[i+increment+1] & 0b11000000) == 0b10000000) {
|
||||
++increment;
|
||||
}
|
||||
bpe_symbol * part = new bpe_symbol(word.data()+i);
|
||||
part->pos = i;
|
||||
part->size += increment;
|
||||
i += increment;
|
||||
if (last) {
|
||||
last->next = part;
|
||||
part->last = last;
|
||||
}
|
||||
last = part;
|
||||
parts.push_back(part);
|
||||
}
|
||||
}
|
||||
|
||||
~pair_builder() {
|
||||
for (auto p : parts) {
|
||||
delete p;
|
||||
}
|
||||
}
|
||||
|
||||
void join_pairs(std::unordered_map<std::pair<std::string, std::string>, int, pair_hash> & rank_map);
|
||||
std::vector<bpe_symbol*> parts;
|
||||
};
|
||||
|
||||
struct bpe_tokenizer {
|
||||
bpe_tokenizer(std::unordered_map<std::string, uint32_t> & tokens_to_ids, std::unordered_map<std::pair<std::string, std::string>, int, pair_hash> & ranks, uint32_t bos, uint32_t eos): tokens_to_ids(tokens_to_ids), ranks(ranks), eos_token_id(eos), bos_token_id(bos) {};
|
||||
std::unordered_map<std::string, uint32_t> tokens_to_ids;
|
||||
std::unordered_map<std::pair<std::string, std::string>, int, pair_hash> ranks;
|
||||
uint32_t eos_token_id;
|
||||
uint32_t bos_token_id;
|
||||
|
||||
void tokenize(const std::string & text, std::vector<uint32_t> & token_ids);
|
||||
void bpe_tokenize(std::string chunk, std::vector<uint32_t> & token_ids);
|
||||
};
|
||||
|
||||
bpe_tokenizer * bpe_tokenizer_from_gguf(gguf_context * meta, std::string base_name = "tokenizer.ggml");
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,445 @@
|
||||
#include "tts.h"
|
||||
#include <mutex>
|
||||
|
||||
// A list of all of the top level GGUF names under kokoro.duration_predictor that have quantization compatible tensors.
|
||||
static constexpr std::array<const char *, 5> DURATION_PREDICTOR_QUANTIZATION_COMPATIBLE_PARTS = {
|
||||
"duration_proj",
|
||||
"encode",
|
||||
"shared_lstm",
|
||||
"duration_lstm",
|
||||
"layers"
|
||||
};
|
||||
|
||||
struct tts_runner * orpheus_from_file(gguf_context * meta_ctx, ggml_context * weight_ctx, int n_threads, generation_configuration * config, tts_arch arch, bool cpu_only) {
|
||||
orpheus_model * model = new orpheus_model;
|
||||
snac_model * audio_model = new snac_model;
|
||||
bpe_tokenizer * bt = bpe_tokenizer_from_gguf(meta_ctx);
|
||||
model->setup_from_file(meta_ctx, weight_ctx, cpu_only);
|
||||
audio_model->setup_from_file(meta_ctx, weight_ctx, cpu_only);
|
||||
sampler * samp = new sampler;
|
||||
snac_context * sctx = build_new_snac_context(audio_model, n_threads, cpu_only);
|
||||
snac_runner * audio_decoder = new snac_runner(audio_model, sctx);
|
||||
orpheus_context * octx = build_new_orpheus_context(model, n_threads, cpu_only);
|
||||
orpheus_kv_cache * cache = new orpheus_kv_cache;
|
||||
orpheus_runner * runner = new orpheus_runner(model, audio_decoder, octx, bt, samp, cache);
|
||||
|
||||
for (ggml_tensor * cur = ggml_get_first_tensor(weight_ctx); cur; cur = ggml_get_next_tensor(weight_ctx, cur)) {
|
||||
runner->assign_weight(cur->name, cur);
|
||||
}
|
||||
|
||||
runner->prepare_post_load();
|
||||
|
||||
gguf_free(meta_ctx);
|
||||
ggml_free(weight_ctx);
|
||||
runner->arch = arch;
|
||||
|
||||
return (tts_runner*)runner;
|
||||
}
|
||||
|
||||
struct tts_runner * parler_tts_from_file(gguf_context * meta_ctx, ggml_context * weight_ctx, int n_threads, generation_configuration * config, tts_arch arch, bool cpu_only) {
|
||||
parler_tts_model * model = new parler_tts_model;
|
||||
dac_model * audio_model = new dac_model;
|
||||
unigram_tokenizer * ut = unigram_tokenizer_from_gguf(meta_ctx);
|
||||
ut->initialize_tokenizer();
|
||||
model->use_cross_attn = config->use_cross_attn;
|
||||
model->setup_from_file(meta_ctx, weight_ctx, cpu_only);
|
||||
audio_model->setup_from_file(meta_ctx, weight_ctx, cpu_only);
|
||||
struct sampler * samp = new sampler;
|
||||
struct dac_context * dctx = build_new_dac_context(audio_model, n_threads, cpu_only);
|
||||
struct dac_runner * audio_decoder = new dac_runner(audio_model, dctx);
|
||||
struct parler_context * pctx = build_new_parler_context(model, n_threads, cpu_only);
|
||||
struct parler_kv_cache * cache = new parler_kv_cache;
|
||||
struct parler_tts_runner * runner = new parler_tts_runner(model, audio_decoder, pctx, ut, samp, cache);
|
||||
|
||||
// TODO: change this weight assignment pattern to mirror llama.cpp
|
||||
for (ggml_tensor * cur = ggml_get_first_tensor(weight_ctx); cur; cur = ggml_get_next_tensor(weight_ctx, cur)) {
|
||||
runner->assign_weight(cur->name, cur);
|
||||
}
|
||||
|
||||
if (config->use_cross_attn) {
|
||||
runner->model->prep_cross_key_values(n_threads);
|
||||
}
|
||||
|
||||
runner->prepare_post_load();
|
||||
|
||||
gguf_free(meta_ctx);
|
||||
ggml_free(weight_ctx);
|
||||
runner->arch = arch;
|
||||
|
||||
return (tts_runner*)runner;
|
||||
}
|
||||
|
||||
struct tts_runner * kokoro_from_file(gguf_context * meta_ctx, ggml_context * weight_ctx, int n_threads, generation_configuration * config, tts_arch arch, bool cpu_only) {
|
||||
kokoro_model * model = new kokoro_model;
|
||||
single_pass_tokenizer * spt = single_pass_tokenizer_from_gguf(meta_ctx, "tokenizer.ggml.tokens");
|
||||
model->setup_from_file(meta_ctx, weight_ctx, cpu_only);
|
||||
struct kokoro_duration_context * kdctx = build_new_duration_kokoro_context(model, n_threads, cpu_only);
|
||||
struct kokoro_duration_runner * duration_runner = new kokoro_duration_runner(model, kdctx, spt);
|
||||
struct kokoro_context * kctx = build_new_kokoro_context(model, n_threads, cpu_only);
|
||||
// if an espeak voice id wasn't specifically set infer it from the kokoro voice, if it was override it, otherwise fallback to American English.
|
||||
std::string espeak_voice_id = config->espeak_voice_id;
|
||||
if (espeak_voice_id.empty()) {
|
||||
espeak_voice_id = !config->voice.empty() && KOKORO_LANG_TO_ESPEAK_ID.find(config->voice.at(0)) != KOKORO_LANG_TO_ESPEAK_ID.end() ? KOKORO_LANG_TO_ESPEAK_ID[config->voice.at(0)] : "gmw/en-US";
|
||||
}
|
||||
struct phonemizer * phmzr = phonemizer_from_gguf(meta_ctx, espeak_voice_id);
|
||||
struct kokoro_runner * runner = new kokoro_runner(model, kctx, spt, duration_runner, phmzr);
|
||||
|
||||
// TODO: change this weight assignment pattern to mirror llama.cpp
|
||||
for (ggml_tensor * cur = ggml_get_first_tensor(weight_ctx); cur; cur = ggml_get_next_tensor(weight_ctx, cur)) {
|
||||
runner->assign_weight(cur->name, cur);
|
||||
}
|
||||
|
||||
runner->prepare_post_load();
|
||||
|
||||
gguf_free(meta_ctx);
|
||||
ggml_free(weight_ctx);
|
||||
runner->arch = arch;
|
||||
|
||||
return (tts_runner*)runner;
|
||||
}
|
||||
|
||||
struct tts_runner * dia_from_file(gguf_context * meta_ctx, ggml_context * weight_ctx, int n_threads, generation_configuration * config, tts_arch arch, bool cpu_only) {
|
||||
dia_model * model = new dia_model;
|
||||
dac_model * audio_model = new dac_model;
|
||||
model->setup_from_file(meta_ctx, weight_ctx, cpu_only);
|
||||
audio_model->setup_from_file(meta_ctx, weight_ctx, cpu_only);
|
||||
struct sampler * samp = new sampler;
|
||||
struct dac_context * dctx = build_new_dac_context(audio_model, n_threads, cpu_only);
|
||||
struct dac_runner * audio_decoder = new dac_runner(audio_model, dctx);
|
||||
struct dia_context * diactx = build_new_dia_context(model, n_threads, cpu_only);
|
||||
struct dia_kv_cache * cache = new dia_kv_cache;
|
||||
struct dia_runner * runner = new dia_runner(model, audio_decoder, diactx, samp, cache);
|
||||
|
||||
for (ggml_tensor * cur = ggml_get_first_tensor(weight_ctx); cur; cur = ggml_get_next_tensor(weight_ctx, cur)) {
|
||||
runner->assign_weight(cur->name, cur);
|
||||
}
|
||||
|
||||
runner->prepare_post_load();
|
||||
|
||||
gguf_free(meta_ctx);
|
||||
ggml_free(weight_ctx);
|
||||
runner->arch = arch;
|
||||
|
||||
return (tts_runner*)runner;
|
||||
}
|
||||
|
||||
// currently only metal and cpu devices are supported, so cpu_only only describes whether or not to try to load and run on metal.
|
||||
struct tts_runner * runner_from_file(const std::string & fname, int n_threads, generation_configuration * config, bool cpu_only) {
|
||||
ggml_context * weight_ctx = NULL;
|
||||
|
||||
struct gguf_init_params params = {
|
||||
/*.no_alloc =*/ false,
|
||||
/*.ctx =*/ &weight_ctx,
|
||||
};
|
||||
gguf_context * meta_ctx = gguf_init_from_file(fname.c_str(), params);
|
||||
if (!meta_ctx) {
|
||||
TTS_ABORT("%s failed for file %s\n", __func__, fname.c_str());
|
||||
}
|
||||
int arch_key = gguf_find_key(meta_ctx, "general.architecture");
|
||||
if (arch_key == -1) {
|
||||
TTS_ABORT("%s failed for file %s. No architecture is set.\n", __func__, fname.c_str());
|
||||
}
|
||||
std::string arch = std::string(gguf_get_val_str(meta_ctx, arch_key));
|
||||
if (SUPPORTED_ARCHITECTURES.find(arch) == SUPPORTED_ARCHITECTURES.end()) {
|
||||
TTS_ABORT("%s failed for file %s. The architecture '%s' is not supported.", __func__, fname.c_str(), arch.c_str());
|
||||
}
|
||||
tts_arch arch_type = SUPPORTED_ARCHITECTURES.at(arch);
|
||||
switch(arch_type) {
|
||||
case PARLER_TTS_ARCH:
|
||||
return parler_tts_from_file(meta_ctx, weight_ctx, n_threads, config, arch_type, cpu_only);
|
||||
case KOKORO_ARCH:
|
||||
return kokoro_from_file(meta_ctx, weight_ctx, n_threads, config, arch_type, cpu_only);
|
||||
case DIA_ARCH:
|
||||
return dia_from_file(meta_ctx, weight_ctx, n_threads, config, arch_type, cpu_only);
|
||||
case ORPHEUS_ARCH:
|
||||
return orpheus_from_file(meta_ctx, weight_ctx, n_threads, config, arch_type, cpu_only);
|
||||
default:
|
||||
TTS_ABORT("%s failed for file %s. The architecture '%s' is not supported.", __func__, fname.c_str(), arch.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
int generate(tts_runner * runner, std::string sentence, struct tts_response * response, generation_configuration * config) {
|
||||
switch(runner->arch) {
|
||||
case PARLER_TTS_ARCH:
|
||||
((parler_tts_runner*)runner)->configure_generation(config);
|
||||
return ((parler_tts_runner*)runner)->generate(sentence, response);
|
||||
case KOKORO_ARCH:
|
||||
return ((kokoro_runner*)runner)->generate(sentence, response, config->voice, config->espeak_voice_id);
|
||||
case DIA_ARCH:
|
||||
((dia_runner*)runner)->configure_generation(config);
|
||||
return ((dia_runner*)runner)->generate(sentence, response);
|
||||
case ORPHEUS_ARCH:
|
||||
((orpheus_runner*)runner)->configure_generation(config);
|
||||
return ((orpheus_runner*)runner)->generate(sentence, response);
|
||||
default:
|
||||
TTS_ABORT("%s failed. The architecture '%d' is not supported.", __func__, runner->arch);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::string> list_voices(tts_runner * runner) {
|
||||
switch(runner->arch) {
|
||||
case KOKORO_ARCH:
|
||||
return ((kokoro_runner*)runner)->list_voices();
|
||||
default:
|
||||
TTS_ABORT("%s failed. The architecture '%d' does not support #list_voices supported.", __func__, runner->arch);
|
||||
}
|
||||
}
|
||||
|
||||
void update_conditional_prompt(tts_runner * runner, const std::string file_path, const std::string prompt, bool cpu_only) {
|
||||
int n_threads = ((parler_tts_runner*)runner)->pctx->n_threads;
|
||||
((parler_tts_runner*)runner)->update_conditional_prompt(file_path, prompt, n_threads, cpu_only);
|
||||
}
|
||||
|
||||
bool kokoro_is_f16_compatible(std::string name) {
|
||||
return name.find("voice_tensors") == std::string::npos &&
|
||||
name.find("bias") == std::string::npos &&
|
||||
name.find("gamma") == std::string::npos &&
|
||||
name.find("beta") == std::string::npos &&
|
||||
name.find("alpha") == std::string::npos &&
|
||||
!has_suffix(name, "embd") &&
|
||||
!has_suffix(name, "norm");
|
||||
}
|
||||
|
||||
bool kokoro_is_quantizable(std::string name, struct quantization_params * params) {
|
||||
if (kokoro_is_f16_compatible(name)) {
|
||||
if (has_prefix(name, "kokoro.albert") || has_prefix(name, "kokoro.text_encoder.lstm")) {
|
||||
return true;
|
||||
} else if (has_prefix(name, "kokoro.duration_predictor.")) {
|
||||
std::vector<std::string> parts = split(name, ".");
|
||||
for (std::string part : DURATION_PREDICTOR_QUANTIZATION_COMPATIBLE_PARTS) {
|
||||
if (part == parts[2]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool dia_is_quantizable(std::string name, struct quantization_params * params) {
|
||||
// The DAC audio encoder / decoder is not compatible with quantization and normalization tensors should not be quantized.
|
||||
bool quantizable = !has_prefix(name, "audio_encoder") && !has_suffix(name, "norm");
|
||||
if (!params->quantize_output_heads) {
|
||||
quantizable = quantizable && !has_prefix(name, "dia.decoder.heads");
|
||||
}
|
||||
return quantizable;
|
||||
}
|
||||
|
||||
bool parler_is_quanitizable(std::string name, struct quantization_params * params) {
|
||||
// the DAC audio encoder / decoder is not compatible with quantization, normalization weight shouldn't be quantized, and the text encoding shouldn't be normalized.
|
||||
bool quantizable = !has_prefix(name, "audio_encoder") && !has_suffix(name, "norm.weight") && !has_suffix(name, "text_encoding") && !has_suffix(name, "positional_embed") && !has_suffix(name, "norm.bias");
|
||||
if (!params->quantize_output_heads) {
|
||||
quantizable = quantizable && !has_suffix(name, "weight.head");
|
||||
}
|
||||
if (!params->quantize_text_embeddings) {
|
||||
quantizable = quantizable && !has_suffix(name, "embed_prompts");
|
||||
}
|
||||
if (!params->quantize_cross_attn_kv) {
|
||||
quantizable = quantizable && !has_suffix(name, "encoder_attn.k_proj.weight") && !has_suffix(name, "encoder_attn.v_proj.weight");
|
||||
}
|
||||
return quantizable;
|
||||
}
|
||||
|
||||
bool is_quantizable(tts_arch arch, std::string name, struct quantization_params * params) {
|
||||
switch(arch) {
|
||||
case PARLER_TTS_ARCH:
|
||||
return parler_is_quanitizable(name, params);
|
||||
case DIA_ARCH:
|
||||
return dia_is_quantizable(name, params);
|
||||
case KOKORO_ARCH:
|
||||
return kokoro_is_quantizable(name, params);
|
||||
default:
|
||||
TTS_ABORT("%s failed. The architecture '%d' is not supported.", __func__, arch);
|
||||
}
|
||||
}
|
||||
|
||||
size_t quantize_tensor(void * new_data, struct ggml_tensor * tensor, const float * imatrix, enum ggml_type qtype, uint32_t n_threads) {
|
||||
// much of this is form copied from llama.cpp
|
||||
int chunk_size_multiplier = 1;
|
||||
if (qtype == GGML_TYPE_Q4_0_4_4 || qtype == GGML_TYPE_Q4_0_4_8 || qtype == GGML_TYPE_Q4_0_8_8) {
|
||||
if ((qtype == GGML_TYPE_Q4_0_8_8) && (tensor->ne[1] % 8 != 0)) qtype = GGML_TYPE_Q4_0;
|
||||
else if (tensor->ne[1] % 4 != 0) qtype = GGML_TYPE_Q4_0;
|
||||
if (qtype == GGML_TYPE_Q4_0_8_8) chunk_size_multiplier = 8;
|
||||
else if (qtype == GGML_TYPE_Q4_0_4_4 || qtype == GGML_TYPE_Q4_0_4_8) chunk_size_multiplier = 4;
|
||||
}
|
||||
size_t out_size = 0;
|
||||
const int32_t d3_step = tensor->ne[0] * tensor->ne[1];
|
||||
const int32_t n_per_row = tensor->ne[0];
|
||||
const int32_t nrows = tensor->ne[1];
|
||||
static const int32_t min_chunk_size = 32 * 512;
|
||||
const int32_t chunk_size = (n_per_row >= min_chunk_size ? n_per_row : n_per_row * ((min_chunk_size + n_per_row - 1)/n_per_row)) * chunk_size_multiplier;
|
||||
uint32_t thread_count = std::max(1, std::min((int)n_threads, (int)(d3_step + chunk_size - 1) / chunk_size));
|
||||
std::mutex mutex;
|
||||
|
||||
for (int32_t d3_index = 0; d3_index < tensor->ne[2]; d3_index++) {
|
||||
const float * f32_data_d3 = ((float *) tensor->data) + d3_index * d3_step;
|
||||
void * new_data_d3 = (char *)new_data + ggml_row_size(qtype, tensor->ne[0]) * d3_index * nrows;
|
||||
const float * imatrix_03 = imatrix ? imatrix + d3_index * tensor->ne[0] : nullptr;
|
||||
if (thread_count <= 1) {
|
||||
// not threaded
|
||||
out_size += ggml_quantize_chunk(qtype, f32_data_d3, new_data_d3, 0, nrows, n_per_row, imatrix);
|
||||
} else {
|
||||
std::vector <std::thread> threads;
|
||||
int64_t counter = 0;
|
||||
size_t new_size = 0;
|
||||
bool valid = true;
|
||||
for (uint32_t t = 0; t < thread_count; t++) {
|
||||
auto func = [&mutex, &counter, &new_size, &valid, qtype, f32_data_d3, new_data_d3, chunk_size, nrows, n_per_row, imatrix]() {
|
||||
const int64_t nrows_per_chunk = chunk_size / n_per_row;
|
||||
size_t local_size = 0;
|
||||
while (true) {
|
||||
std::unique_lock<std::mutex> lock(mutex);
|
||||
int64_t first_row = counter;
|
||||
counter += nrows_per_chunk;
|
||||
if (first_row >= nrows) {
|
||||
if (local_size > 0) {
|
||||
new_size += local_size;
|
||||
}
|
||||
break;
|
||||
}
|
||||
lock.unlock();
|
||||
const int64_t this_nrow = std::min(nrows - first_row, nrows_per_chunk);
|
||||
size_t this_size = ggml_quantize_chunk(qtype, f32_data_d3, new_data_d3, first_row * n_per_row, this_nrow, n_per_row, imatrix);
|
||||
local_size += this_size;
|
||||
|
||||
// validate the quantized data; I am not sure how this would occur, but there is always the safe fallback on doing this single threaded.
|
||||
const size_t row_size = ggml_row_size(qtype, n_per_row);
|
||||
void * this_data = (char *) new_data_d3 + first_row * row_size;
|
||||
if (!ggml_validate_row_data(qtype, this_data, this_size)) {
|
||||
std::unique_lock<std::mutex> lock(mutex);
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
threads.push_back(std::thread(func));
|
||||
}
|
||||
for (auto & t : threads) t.join();
|
||||
|
||||
if (!valid) {
|
||||
TTS_ABORT("Validation of quantized data failed. Please try again and/or switch to single thread quantization.\n");
|
||||
}
|
||||
out_size += new_size;
|
||||
}
|
||||
}
|
||||
return out_size;
|
||||
}
|
||||
|
||||
static void zeros(std::ofstream & file, size_t n) {
|
||||
char zero = 0;
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
file.write(&zero, 1);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
struct no_init {
|
||||
T value;
|
||||
no_init() { /* do nothing */ }
|
||||
};
|
||||
|
||||
void quantize_gguf(const std::string & ifile, const std::string & ofile, struct quantization_params * params) {
|
||||
ggml_context * weight_ctx = NULL;
|
||||
struct gguf_init_params gguf_params = {
|
||||
/*.no_alloc =*/ false,
|
||||
/*.ctx =*/ &weight_ctx,
|
||||
};
|
||||
gguf_context * meta_ctx = gguf_init_from_file(ifile.c_str(), gguf_params);
|
||||
std::string arch = "parler-tts"; // only parler-tts gguf files should lack an explicit architecture.
|
||||
|
||||
int arch_key = gguf_find_key(meta_ctx, "general.architecture");
|
||||
if (arch_key != -1) {
|
||||
arch = std::string(gguf_get_val_str(meta_ctx, arch_key));
|
||||
}
|
||||
tts_arch arch_type = SUPPORTED_ARCHITECTURES.at(arch);
|
||||
|
||||
if (params->quantize_type != GGML_TYPE_Q5_0 && params->quantize_type != GGML_TYPE_Q8_0 && params->quantize_type != GGML_TYPE_F16 && params->quantize_type != GGML_TYPE_Q4_0) {
|
||||
fprintf(stdout, "Warning, %s is untested for quantization type '%d'. Use at your own risk.\n", arch.c_str(), params->quantize_type);
|
||||
}
|
||||
|
||||
const size_t align = GGUF_DEFAULT_ALIGNMENT;
|
||||
gguf_context_ptr ctx_out { gguf_init_empty() };
|
||||
|
||||
// copy the KV pairs from the input file
|
||||
gguf_set_kv(ctx_out.get(), meta_ctx);
|
||||
gguf_set_val_u32(ctx_out.get(), "general.quantization_version", GGML_QNT_VERSION);
|
||||
gguf_set_val_u32(ctx_out.get(), "general.quantization_type", params->quantize_type);
|
||||
for (ggml_tensor * tensor = ggml_get_first_tensor(weight_ctx); tensor; tensor = ggml_get_next_tensor(weight_ctx, tensor)) {
|
||||
std::string name = ggml_get_name(tensor);
|
||||
if (name.size() != 0) {
|
||||
gguf_add_tensor(ctx_out.get(), tensor);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<no_init<uint8_t>> work;
|
||||
|
||||
std::ofstream fout;
|
||||
auto close_ofstream = [&]() {
|
||||
// Write metadata and close file handler
|
||||
if (fout.is_open()) {
|
||||
fout.seekp(0);
|
||||
std::vector<uint8_t> data(gguf_get_meta_size(ctx_out.get()));
|
||||
gguf_get_meta_data(ctx_out.get(), data.data());
|
||||
fout.write((const char *) data.data(), data.size());
|
||||
fout.close();
|
||||
}
|
||||
};
|
||||
auto new_ofstream = [&]() {
|
||||
std::string fname = ofile;
|
||||
fout = std::ofstream(fname, std::ios::binary);
|
||||
fout.exceptions(std::ofstream::failbit); // fail fast on write errors
|
||||
const size_t meta_size = gguf_get_meta_size(ctx_out.get());
|
||||
// placeholder for the meta data
|
||||
::zeros(fout, meta_size);
|
||||
};
|
||||
new_ofstream();
|
||||
for (ggml_tensor * cur = ggml_get_first_tensor(weight_ctx); cur; cur = ggml_get_next_tensor(weight_ctx, cur)) {
|
||||
enum ggml_type new_type;
|
||||
void * new_data;
|
||||
size_t new_size;
|
||||
std::string name = ggml_get_name(cur);
|
||||
|
||||
if (name.size() == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (is_quantizable(arch_type, name, params)) {
|
||||
if ((cur->type) != GGML_TYPE_F32) {
|
||||
TTS_ABORT("ERROR: All quantized tensors must be transformed from 32bit floats. Tensor, '%s', has improper type, '%d'\n", cur->name, cur->type);
|
||||
}
|
||||
new_type = params->quantize_type;
|
||||
if ((new_type >= GGML_TYPE_IQ2_XXS && new_type <= GGML_TYPE_IQ4_XS)) {
|
||||
TTS_ABORT("ERROR: Quantization type '%d' requires an importance matrix.\n", new_type);
|
||||
}
|
||||
const int64_t nelement_size = ggml_nelements(cur) * 4;
|
||||
if (work.size() < (size_t)nelement_size) {
|
||||
work.resize(nelement_size); // upper bound on size
|
||||
}
|
||||
new_data = work.data();
|
||||
new_size = quantize_tensor(new_data, cur, nullptr, new_type, params->n_threads);
|
||||
} else if ((params->convert_non_quantizable_to_f16 && kokoro_is_f16_compatible(name)) || (params->convert_dac_to_f16 && has_prefix(name, "audio_encoder") && !has_suffix(name, "alpha"))) {
|
||||
if ((cur->type) != GGML_TYPE_F32) {
|
||||
TTS_ABORT("ERROR: All converted tensors must be transformed from 32bit floats. Tensor, '%s', has improper type, '%d'\n", cur->name, cur->type);
|
||||
}
|
||||
new_type = GGML_TYPE_F16;
|
||||
const int64_t nelement_size = ggml_nelements(cur) * 4;
|
||||
if (work.size() < (size_t)nelement_size) {
|
||||
work.resize(nelement_size); // upper bound on size
|
||||
}
|
||||
new_data = work.data();
|
||||
new_size = quantize_tensor(new_data, cur, nullptr, new_type, params->n_threads);
|
||||
} else {
|
||||
new_type = cur->type;
|
||||
new_data = cur->data;
|
||||
new_size = ggml_nbytes(cur);
|
||||
}
|
||||
|
||||
gguf_set_tensor_type(ctx_out.get(), name.c_str(), new_type);
|
||||
gguf_set_tensor_data(ctx_out.get(), name.c_str(), new_data);
|
||||
fprintf(stdout, "At tensor: '%s' with new size: %zu bytes\n", name.c_str(), new_size);
|
||||
// write tensor data + padding
|
||||
fout.write((const char *) new_data, new_size);
|
||||
zeros(fout, GGML_PAD(new_size, align) - new_size);
|
||||
}
|
||||
close_ofstream();
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
#include "tts_model.h"
|
||||
#include "ggml-backend.h"
|
||||
#include "ggml-cpu.h"
|
||||
|
||||
void append_to_response(struct tts_response * response, struct tts_response * to_append) {
|
||||
float * new_data = (float *) malloc((response->n_outputs + to_append->n_outputs) * sizeof(float));
|
||||
if (response->n_outputs > 0) {
|
||||
std::memcpy(new_data, response->data, response->n_outputs*sizeof(float));
|
||||
}
|
||||
if (to_append->n_outputs > 0) {
|
||||
float * next_loc = new_data + response->n_outputs;
|
||||
std::memcpy(next_loc, to_append->data, to_append->n_outputs*sizeof(float));
|
||||
}
|
||||
response->data = new_data;
|
||||
response->n_outputs += to_append->n_outputs;
|
||||
}
|
||||
|
||||
/*
|
||||
* Pulls output_size to prepped buffer 'output' from 'output_node' tensor. If no buffer is passed will default to the existing output buffer present
|
||||
* on runner_context.
|
||||
*/
|
||||
void runner_context::get_ggml_node_data(struct ggml_tensor * output_node, float * output, size_t output_size, ggml_backend_buffer_t buffer) {
|
||||
if (buffer == nullptr) {
|
||||
buffer = buf_output;
|
||||
}
|
||||
if (ggml_backend_buffer_get_size(buffer) < output_size) {
|
||||
TTS_ABORT("Output buffer overflow of %d / %d for output node '%s'\n", output_size, ggml_backend_buffer_get_size(buffer), ggml_get_name(output_node));
|
||||
} else if (ggml_nbytes(output_node) < output_size) {
|
||||
TTS_ABORT("Output node, '%s', with %d bytes is too small for #ggml_backend_tensor_get_async with size of %d.\n", ggml_get_name(output_node), ggml_nbytes(output_node), output_size);
|
||||
}
|
||||
ggml_backend_t backend_res = ggml_backend_sched_get_tensor_backend(sched, output_node);
|
||||
ggml_backend_tensor_get_async(backend_res, output_node, output, 0, output_size);
|
||||
}
|
||||
|
||||
void runner_context::set_threads() {
|
||||
if (backend != nullptr) {
|
||||
#ifdef GGML_USE_METAL
|
||||
// this is form copied from llama.cpp, but has since been removed. I don't know if this should be tuned.
|
||||
ggml_backend_metal_set_n_cb(backend, 1);
|
||||
#endif
|
||||
}
|
||||
if (backend_cpu != nullptr) {
|
||||
ggml_backend_cpu_set_n_threads(backend_cpu, n_threads);
|
||||
struct ggml_threadpool_params ttp = ggml_threadpool_params_default(n_threads);
|
||||
threadpool = ggml_threadpool_new(&ttp);
|
||||
ggml_backend_cpu_set_threadpool(backend_cpu, threadpool);
|
||||
}
|
||||
}
|
||||
|
||||
void runner_context::build_schedule(size_t max_nodes) {
|
||||
backend_cpu_buffer = ggml_backend_cpu_buffer_type();
|
||||
if (backend != nullptr) {
|
||||
#ifdef GGML_USE_METAL
|
||||
backend_buffer = ggml_backend_metal_buffer_type();
|
||||
#endif
|
||||
std::vector<ggml_backend_buffer_type_t> bufs = {backend_buffer, backend_cpu_buffer};
|
||||
std::vector<ggml_backend_t> backs = {backend, backend_cpu};
|
||||
sched = ggml_backend_sched_new(backs.data(), bufs.data(), 2, max_nodes, false, false);
|
||||
} else {
|
||||
std::vector<ggml_backend_buffer_type_t> bufs = {backend_cpu_buffer};
|
||||
std::vector<ggml_backend_t> backs = {backend_cpu};
|
||||
sched = ggml_backend_sched_new(backs.data(), bufs.data(), 1, max_nodes, false, false);
|
||||
}
|
||||
}
|
||||
|
||||
bool runner_context::prep_schedule(struct ggml_cgraph * gf) {
|
||||
return ggml_backend_sched_reserve(sched, gf);
|
||||
}
|
||||
|
||||
void runner_context::prep_output_buffer(size_t new_size) {
|
||||
const size_t prev_size = buf_output ? ggml_backend_buffer_get_size(buf_output) : 0;
|
||||
if (!buf_output || prev_size < new_size) {
|
||||
if (buf_output) {
|
||||
ggml_backend_buffer_free(buf_output);
|
||||
buf_output = nullptr;
|
||||
logits = nullptr;
|
||||
}
|
||||
buf_output = ggml_backend_buft_alloc_buffer(backend_cpu_buffer, new_size);
|
||||
}
|
||||
logits = (float *) ggml_backend_buffer_get_base(buf_output);
|
||||
}
|
||||
|
||||
void tts_runner::init_build(std::vector<uint8_t>* buf_compute_meta) {
|
||||
struct ggml_init_params params = {
|
||||
/*.mem_size =*/ buf_compute_meta->size(),
|
||||
/*.mem_buffer =*/ buf_compute_meta->data(),
|
||||
/*.no_alloc =*/ true,
|
||||
};
|
||||
|
||||
ctx = ggml_init(params);
|
||||
}
|
||||
|
||||
void tts_runner::free_build() {
|
||||
if (ctx) {
|
||||
ggml_free(ctx);
|
||||
ctx = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void tts_model::prep_buffers_and_context(bool cpu_only, float size_offset, uint32_t dedicated_add_on_size) {
|
||||
// currently DAC is only supported on cpu because the ops are not implemented on other devices;
|
||||
if (cpu_only) {
|
||||
backend = ggml_backend_cpu_init();
|
||||
buffer = ggml_backend_cpu_buffer_type();
|
||||
} else {
|
||||
#ifdef GGML_USE_METAL
|
||||
backend = ggml_backend_metal_init();
|
||||
buffer = ggml_backend_metal_buffer_type();
|
||||
#endif
|
||||
// if use metal is not installed then we need to warn here
|
||||
if (!backend || !buffer) {
|
||||
TTS_ABORT("'GGML_USE_METAL' is not defined either set the model to use CPU only or install ggml with metal support.");
|
||||
}
|
||||
}
|
||||
size_t ctx_size = ggml_tensor_overhead() * (tensor_meta.n_tensors * size_offset);
|
||||
struct ggml_init_params params = {
|
||||
/*.mem_size =*/ ctx_size,
|
||||
/*.mem_buffer =*/ NULL,
|
||||
/*.no_alloc =*/ true,
|
||||
};
|
||||
ctx = ggml_init(params);
|
||||
buf = ggml_backend_buft_alloc_buffer(buffer, tensor_meta.n_bytes + dedicated_add_on_size);
|
||||
}
|
||||
|
||||
void tts_model::assign_weight(std::string name, ggml_tensor * tensor) {
|
||||
TTS_ABORT("%s received name, %s, tensor without being defined. %s must be defined for all implementations of tts_model. \n", __func__, name.c_str(), __func__);
|
||||
}
|
||||
|
||||
void tts_model::set_tensor(struct ggml_tensor * tensor, struct ggml_tensor * target) {
|
||||
tensor->buffer = buf;
|
||||
tensor->data = (void *)((uint8_t *) ggml_backend_buffer_get_base(buf) + offset);
|
||||
size_t size = ggml_nbytes(target);
|
||||
ggml_backend_tensor_set(tensor, target->data, 0, size);
|
||||
ggml_set_name(tensor, target->name);
|
||||
offset += size;
|
||||
}
|
||||
|
||||
void tts_model::setup_from_file(gguf_context * meta_ctx, ggml_context * load_context, bool cpu_only, std::string model_prefix, float size_offset, uint32_t dedicated_add_on_size) {
|
||||
tensor_meta = compute_tensor_meta(model_prefix, load_context, compute_tensor_meta_cb);
|
||||
prep_buffers_and_context(cpu_only, size_offset, dedicated_add_on_size);
|
||||
}
|
||||
|
||||
size_t tts_model::max_nodes() {
|
||||
return std::max<size_t>(8192, tensor_meta.n_tensors*5);
|
||||
}
|
||||
|
||||
void tts_model::free() {
|
||||
if (ctx) {
|
||||
ggml_free(ctx);
|
||||
}
|
||||
if (buf) {
|
||||
ggml_backend_buffer_free(buf);
|
||||
}
|
||||
if (backend) {
|
||||
ggml_backend_free(backend);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
#ifndef tts_model_h
|
||||
#define tts_model_h
|
||||
|
||||
#include <cstring>
|
||||
#include <functional>
|
||||
#include "ttsutil.h"
|
||||
#include "ttscommon.h"
|
||||
|
||||
void append_to_response(struct tts_response * response, struct tts_response * to_append);
|
||||
|
||||
using tensor_meta_callback = std::function<void(ggml_tensor*)>*;
|
||||
|
||||
struct runner_context {
|
||||
runner_context(int n_threads): n_threads(n_threads) {};
|
||||
virtual ~runner_context() {
|
||||
ggml_backend_sched_free(sched);
|
||||
ggml_threadpool_free(threadpool);
|
||||
ggml_backend_free(backend_cpu);
|
||||
ggml_backend_free(backend);
|
||||
ggml_backend_buffer_free(buf_output);
|
||||
}
|
||||
// TODO: extend the backend and buffer support out to all devices
|
||||
ggml_backend_t backend = nullptr;
|
||||
ggml_backend_buffer_type_t backend_buffer = nullptr;
|
||||
|
||||
ggml_backend_t backend_cpu = nullptr;
|
||||
ggml_backend_buffer_type_t backend_cpu_buffer = nullptr;
|
||||
|
||||
std::vector<uint8_t> buf_compute_meta;
|
||||
ggml_backend_buffer_t buf_output = nullptr;
|
||||
ggml_backend_sched_t sched = nullptr;
|
||||
ggml_threadpool_t threadpool = nullptr;
|
||||
float * logits = nullptr;
|
||||
int n_threads;
|
||||
|
||||
void get_ggml_node_data(struct ggml_tensor * output_tensor, float * output, size_t output_size, ggml_backend_buffer_t buffer = nullptr);
|
||||
void set_threads();
|
||||
void build_schedule(size_t max_nodes);
|
||||
bool prep_schedule(ggml_cgraph * gf);
|
||||
void prep_output_buffer(size_t new_size);
|
||||
};
|
||||
|
||||
struct tts_model {
|
||||
struct model_tensor_meta tensor_meta;
|
||||
|
||||
// this is the current byte offset into the model's buffer.
|
||||
size_t offset = 0;
|
||||
|
||||
bool use_cross_attn = true;
|
||||
|
||||
ggml_backend_buffer_type_t buffer = nullptr;
|
||||
ggml_backend_t backend = nullptr;
|
||||
ggml_backend_buffer_t buf = nullptr;
|
||||
|
||||
// it is quite common for implementations of tts_model to need to update attributes or perform distinct operations
|
||||
// when computing the tensor meta of the loaded model. This callback allows this as it will receive each processed tensor.
|
||||
tensor_meta_callback compute_tensor_meta_cb = nullptr;
|
||||
|
||||
struct ggml_context * ctx;
|
||||
|
||||
void prep_buffers_and_context(bool cpu_only, float size_offset, uint32_t dedicated_add_on_size);
|
||||
void setup_from_file(gguf_context * meta_ctx, ggml_context * load_context, bool cpu_only, std::string model_prefix, float size_offset = 1.4, uint32_t dedicated_add_on_size = 0);
|
||||
void set_tensor(struct ggml_tensor * tensor, struct ggml_tensor * target);
|
||||
size_t max_nodes();
|
||||
void assign_weight(std::string name, ggml_tensor * tensor);
|
||||
void free();
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,308 @@
|
||||
#include "ttsutil.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdio>
|
||||
#include <stdarg.h>
|
||||
#ifdef __APPLE__
|
||||
#include <sys/sysctl.h>
|
||||
#elif __linux__
|
||||
#include <unistd.h>
|
||||
#else
|
||||
// windows stuff
|
||||
#endif
|
||||
|
||||
void tts_abort(const char * file, int line, const char * fmt, ...) {
|
||||
fflush(stdout);
|
||||
fprintf(stderr, "%s:%d: ", file, line);
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vfprintf(stderr, fmt, args);
|
||||
va_end(args);
|
||||
abort();
|
||||
}
|
||||
|
||||
// Simple helper function for getting layer count from tensor name
|
||||
std::pair<int, std::string> parse_layer_count(std::string name, int skip) {
|
||||
bool found = false;
|
||||
bool after_layer = false;
|
||||
std::string digit_chars = "";
|
||||
std::string after_layer_name = "";
|
||||
int count = 0;
|
||||
for (char& c : name) {
|
||||
if (count < skip) {
|
||||
count += 1;
|
||||
continue;
|
||||
}
|
||||
count += 1;
|
||||
if (after_layer) {
|
||||
after_layer_name += c;
|
||||
} else if (std::isdigit(c)) {
|
||||
found = true;
|
||||
digit_chars += c;
|
||||
} else if (!found) {
|
||||
|
||||
} else {
|
||||
after_layer = true;
|
||||
after_layer_name += c;
|
||||
}
|
||||
}
|
||||
if (digit_chars.size() == 0) {
|
||||
return std::make_pair(-1, name);
|
||||
}
|
||||
return std::make_pair(std::stoi(digit_chars), after_layer_name);
|
||||
}
|
||||
|
||||
int search_for_gguf_keys(gguf_context * meta, std::vector<std::string> possible_keys) {
|
||||
int gguf_key = -1;
|
||||
for (auto key : possible_keys) {
|
||||
gguf_key = gguf_find_key(meta, key.c_str());
|
||||
if (gguf_key != -1) {
|
||||
return gguf_key;
|
||||
}
|
||||
}
|
||||
return gguf_key;
|
||||
}
|
||||
|
||||
void random_uniform_gen(int count, float * tgt, float min, float max) {
|
||||
static std::default_random_engine e;
|
||||
static std::uniform_real_distribution<float> dis(min, max);
|
||||
for (int i = 0; i < count; i++) {
|
||||
tgt[i] = dis(e);
|
||||
}
|
||||
}
|
||||
|
||||
void random_normal_gen(int count, float * tgt, float mean, float std) {
|
||||
static std::default_random_engine e;
|
||||
static std::normal_distribution<float> dis(mean, std);
|
||||
for (int i = 0; i < count; i++) {
|
||||
tgt[i] = dis(e);
|
||||
}
|
||||
}
|
||||
|
||||
float round_to_float(double v) {
|
||||
return roundf(v * powl(10, 6)) / powl(10, 6);
|
||||
}
|
||||
|
||||
struct ggml_tensor * reciprocal(ggml_context * ctx, struct ggml_tensor * x) {
|
||||
TTS_ASSERT(x->ne[0] == 1);
|
||||
static constexpr float one = 1.0f;
|
||||
ggml_tensor * numerator = ggml_new_tensor_2d(ctx, GGML_TYPE_F32, 1, x->ne[1]);
|
||||
// stride trick so that the scalar numerator can be divided by x.
|
||||
numerator->nb[1] = 0;
|
||||
numerator->data = const_cast<float *>(&one);
|
||||
return ggml_div(ctx, numerator, x);
|
||||
}
|
||||
|
||||
// Described in https://arxiv.org/abs/2006.08195
|
||||
// Snake1d is a common tunable activation function used in the DAC model.
|
||||
struct ggml_tensor * snake_1d(ggml_context * ctx, struct ggml_tensor * alpha, struct ggml_tensor * a) {
|
||||
assert(a->ne[2] == 1 && a->ne[3] == 1);
|
||||
return ggml_add(ctx, a, ggml_mul(ctx, ggml_sqr(ctx, ggml_sin(ctx, ggml_mul(ctx, a, alpha))), reciprocal(ctx, alpha)));
|
||||
}
|
||||
|
||||
bool has_suffix(std::string value, std::string suffix) {
|
||||
return value.size() >= suffix.size() && value.compare(value.size()-suffix.size(), suffix.size(), suffix) == 0;
|
||||
}
|
||||
|
||||
bool has_prefix(std::string value, std::string prefix) {
|
||||
return value.size() >= prefix.size() && value.compare(0, prefix.size(), prefix) == 0;
|
||||
}
|
||||
|
||||
struct ggml_tensor * stft(ggml_context * ctx, struct ggml_tensor * a, struct ggml_tensor * window, size_t n_fft, size_t hop, bool abs_and_angle, bool one_sided) {
|
||||
if (window->ne[0] != n_fft) {
|
||||
TTS_ABORT("For #stft the window_size, %d, must be either equal to n_fft, %d, or, when one sided, n_fft / 2 + 1, %d.\n", a->ne[0], n_fft, n_fft/2+1);
|
||||
}
|
||||
struct ggml_tensor * cur = ggml_stft(ctx, a, window, n_fft, hop, abs_and_angle);
|
||||
if (one_sided) {
|
||||
cur = ggml_cont(ctx, ggml_view_4d(ctx, cur, ((int64_t) n_fft / 2) + 1, cur->ne[1], cur->ne[2], cur->ne[3], cur->nb[1], cur->nb[2], cur->nb[3], 0));
|
||||
}
|
||||
|
||||
return cur;
|
||||
}
|
||||
|
||||
struct ggml_tensor * istft(ggml_context * ctx, struct ggml_tensor * a, struct ggml_tensor * window_squared_sum, struct ggml_tensor * window, size_t n_fft, size_t hop, bool abs_and_angle, bool one_sided) {
|
||||
if ((!one_sided && a->ne[0] != n_fft) || (one_sided && a->ne[0] != n_fft / 2 + 1)) {
|
||||
TTS_ABORT("For #istft the window_size, %d, must be either equal to n_fft, %d, or, when one sided, n_fft / 2 + 1, %d.\n", a->ne[0], n_fft, n_fft/2+1);
|
||||
}
|
||||
struct ggml_tensor * cur = ggml_istft(ctx, a, window, n_fft, hop, abs_and_angle);
|
||||
cur = ggml_div(ctx, cur, window_squared_sum);
|
||||
return cur;
|
||||
}
|
||||
|
||||
void hann_window(size_t n_fft, std::vector<float> & tgt) {
|
||||
for (int i = 0; i < n_fft; i++) {
|
||||
float v = pow(sin(M_PI * (double)i / (double) n_fft), 2.0);
|
||||
tgt.push_back(v);
|
||||
}
|
||||
}
|
||||
|
||||
// This is a custom map op for computing noise and relevant voiced sections.
|
||||
void uv_noise_compute(struct ggml_tensor * dst, const struct ggml_tensor * a, const struct ggml_tensor * b, const struct ggml_tensor * c, int ith, int nth, void * userdata) {
|
||||
float voice_threshold = ((float *) c->data)[0];
|
||||
float noise_std = ((float *) c->data)[1];
|
||||
float sin_amp = ((float *) c->data)[2];
|
||||
float sin_amp_div = ((float *) c->data)[3];
|
||||
float * rand_init = ((float *) c->data) + 4;
|
||||
|
||||
const int rpt = (b->ne[0] + nth - 1)/nth;
|
||||
const int start = ith * rpt;
|
||||
const int end = MIN((ith + 1) * rpt, b->ne[0]);
|
||||
|
||||
float * uv_dst = (float *) dst->data;
|
||||
float * noise_dst = (float *)((char*)dst->data + dst->nb[2]);
|
||||
float * tgt = (float *) b->data;
|
||||
|
||||
for(int bt = 0; bt < b->ne[2]; bt++) {
|
||||
for(int r = start; r < end; r++) {
|
||||
if (tgt[r] > voice_threshold) {
|
||||
for (int h = 0; h < a->ne[1]; h++) {
|
||||
int index = h*dst->ne[0]+r;
|
||||
uv_dst[index] = sin_amp;
|
||||
noise_dst[index] = noise_std * rand_init[index];
|
||||
}
|
||||
} else {
|
||||
for (int h = 0; h < a->ne[1]; h++) {
|
||||
int index = h*dst->ne[0]+r;
|
||||
uv_dst[index] = 0.0f;
|
||||
noise_dst[index] = sin_amp_div * rand_init[index];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This is a custom map op for applying cfg scale. It is used at the terminus of logit generation in Dia.
|
||||
void cfg_scale(struct ggml_tensor * dst, const struct ggml_tensor * a, const struct ggml_tensor * b, int ith, int nth, void * userdata) {
|
||||
const float scale = ((float *) userdata)[0];
|
||||
const float max_output = ((float*) userdata)[1];
|
||||
const int rpt = (b->ne[0] + nth - 1)/nth;
|
||||
const int start = ith * rpt;
|
||||
const int end = MIN((ith + 1) * rpt, b->ne[0]);
|
||||
|
||||
float * output = (float *) dst->data;
|
||||
float * cond = (float *) a->data;
|
||||
float * uncond = (float *) b->data;
|
||||
|
||||
for(int bt = 0; bt < b->ne[2]; bt++) {
|
||||
for (int h = 0; h < b->ne[1]; h++) {
|
||||
int i = (h * b->ne[0]) + (bt * b->ne[0] * b->ne[1]);
|
||||
for(int r = start; r < end; r++) {
|
||||
// only let the output heads yield tokens up to EOS
|
||||
if (r > max_output) {
|
||||
output[i+r] = -INFINITY;
|
||||
}
|
||||
const float cr = cond[i+r];
|
||||
const float ur = uncond[i+r];
|
||||
output[i+r] = cr + scale * (cr - ur);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// currently this assumes a center view in which the output vector is reflectively padded by n_fft / 2 on each side.
|
||||
void compute_window_squared_sum(size_t n_fft, size_t hop, size_t n_frames, float * tgt, float * window) {
|
||||
size_t cutoff = n_frames * hop;
|
||||
size_t half = n_fft / 2;
|
||||
std::memset(tgt, 0, cutoff*sizeof(float));
|
||||
// istft applies half / hop steps before the beginning of the sequence. We need to account for these accumulated windows.
|
||||
for (int i = 0; i < n_frames + (half / hop); i++) {
|
||||
for (int ii = 0; ii < n_fft; ii++) {
|
||||
int index = ii + i*hop - half;
|
||||
if (index < 0 || index >= cutoff) {
|
||||
continue;
|
||||
}
|
||||
tgt[index] += powf(window[ii], 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::string> split(std::string target, std::string split_on, bool include_split_characters) {
|
||||
std::vector<std::string> output;
|
||||
size_t last = 0;
|
||||
|
||||
for (int i = 0; i < target.size(); i++) {
|
||||
if (i > last && split_on.find(target[i]) != std::string::npos) {
|
||||
std::string part(target.substr(last, i - last));
|
||||
output.push_back(part);
|
||||
if (include_split_characters) {
|
||||
output.push_back(target.substr(i, 1));
|
||||
}
|
||||
last = i+1;
|
||||
} else if (i == last && split_on.find(target[i]) != std::string::npos) {
|
||||
if (include_split_characters) {
|
||||
output.push_back(target.substr(i, 1));
|
||||
}
|
||||
last = i+1;
|
||||
}
|
||||
}
|
||||
if (last < target.size()) {
|
||||
std::string part(target.substr(last));
|
||||
output.push_back(part);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
std::vector<std::string> split(std::string target, const char split_on, bool include_split_characters) {
|
||||
std::vector<std::string> output;
|
||||
size_t last = 0;
|
||||
|
||||
for (int i = 0; i < target.size(); i++) {
|
||||
if (i > last && split_on == target[i]) {
|
||||
std::string part(target.substr(last, i - last));
|
||||
output.push_back(part);
|
||||
if (include_split_characters) {
|
||||
output.push_back(target.substr(i, 1));
|
||||
}
|
||||
last = i+1;
|
||||
} else if (i == last && split_on == target[i]) {
|
||||
if (include_split_characters) {
|
||||
output.push_back(target.substr(i, 1));
|
||||
}
|
||||
last = i+1;
|
||||
}
|
||||
}
|
||||
if (last < target.size()) {
|
||||
std::string part(target.substr(last));
|
||||
output.push_back(part);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
std::string strip(std::string target, std::string vals) {
|
||||
target.erase(target.begin(), std::find_if(target.begin(), target.end(), [&vals](unsigned char ch) {
|
||||
return vals.find(ch) == std::string::npos;
|
||||
}));
|
||||
target.erase(std::find_if(target.rbegin(), target.rend(), [&vals](unsigned char ch) {
|
||||
return vals.find(ch) == std::string::npos;
|
||||
}).base(), target.end());
|
||||
return target;
|
||||
}
|
||||
|
||||
std::string replace_any(std::string target, std::string to_replace, std::string replacement) {
|
||||
for (int i = 0; i < to_replace.size(); i++) {
|
||||
size_t position = target.find(to_replace[i]);
|
||||
while (position != std::string::npos) {
|
||||
target.replace(position, 1, replacement);
|
||||
position = target.find(to_replace[i]);
|
||||
}
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
struct model_tensor_meta compute_tensor_meta(std::string name_prefix, ggml_context * weight_ctx, std::function<void(ggml_tensor*)>* callback) {
|
||||
model_tensor_meta meta;
|
||||
for (ggml_tensor * cur = ggml_get_first_tensor(weight_ctx); cur; cur = ggml_get_next_tensor(weight_ctx, cur)) {
|
||||
if (callback) {
|
||||
(*callback)(cur);
|
||||
}
|
||||
std::string::size_type pos = std::string(cur->name).find(".", 0);
|
||||
std::string top_level(std::string(cur->name).substr(0, pos));
|
||||
if (top_level == name_prefix) {
|
||||
meta.n_tensors += 1;
|
||||
meta.n_bytes += ggml_nbytes_pad(cur);
|
||||
}
|
||||
}
|
||||
return meta;
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
#ifndef util_h
|
||||
#define util_h
|
||||
|
||||
#define _USE_MATH_DEFINES
|
||||
#include <cmath>
|
||||
#include <functional>
|
||||
#include <random>
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
#include "ggml-metal.h"
|
||||
#include "ggml-backend.h"
|
||||
#include "ggml-alloc.h"
|
||||
#include "ggml-cpu.h"
|
||||
#include "ggml.h"
|
||||
#include "ggml-impl.h"
|
||||
#include "ggml-cpp.h"
|
||||
|
||||
#define TTS_ABORT(...) tts_abort(__FILE__, __LINE__, __VA_ARGS__)
|
||||
#define TTS_ASSERT(x) if (!(x)) TTS_ABORT("TTS_ASSERT(%s) failed", #x)
|
||||
|
||||
struct model_tensor_meta {
|
||||
uint32_t n_tensors = 0;
|
||||
size_t n_bytes = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Both of these random fill the tgt array with count random floating point values.
|
||||
* the default parameter values are consistent with pytorch random function defaults.
|
||||
*/
|
||||
void random_uniform_gen(int count, float * tgt, float min = 0.0f, float max = 1.0f);
|
||||
void random_normal_gen(int count, float * tgt, float mean = 0.0f, float std = 1.0f);
|
||||
|
||||
std::pair<int, std::string> parse_layer_count(std::string name, int skip = 0);
|
||||
|
||||
struct model_tensor_meta compute_tensor_meta(std::string name_prefix, ggml_context * weight_ctx, std::function<void(ggml_tensor*)>* callback = nullptr);
|
||||
struct ggml_tensor * snake_1d(ggml_context * ctx, struct ggml_tensor * alpha, struct ggml_tensor * a);
|
||||
int search_for_gguf_keys(gguf_context * meta, std::vector<std::string> possible_keys);
|
||||
|
||||
// a simple window function for stft
|
||||
void hann_window(size_t n_fft, std::vector<float>& tgt);
|
||||
|
||||
// currently this assumes a center view in which the output vector is reflectively padded by n_fft / 2 on each side.
|
||||
void compute_window_squared_sum(size_t n_fft, size_t hop, size_t n_frames, float * tgt, float * window);
|
||||
|
||||
// these functions wrap the stft and istft ggml ops and compute the necessary view and division ops for their indepentent settings.
|
||||
struct ggml_tensor * stft(ggml_context * ctx, struct ggml_tensor * a, struct ggml_tensor * window, size_t n_fft, size_t hop, bool abs_and_angle, bool one_sided);
|
||||
struct ggml_tensor * istft(ggml_context * ctx, struct ggml_tensor * a, struct ggml_tensor * window_squared_sum, struct ggml_tensor * window, size_t n_fft, size_t hop, bool abs_and_angle, bool one_sided);
|
||||
|
||||
// This is a custom op for sine_generation in the Kokoro model.
|
||||
void uv_noise_compute(struct ggml_tensor * dst, const struct ggml_tensor * a, const struct ggml_tensor * b, const struct ggml_tensor * c, int ith, int nth, void * userdata);
|
||||
|
||||
// This is a custom op for logit correction in the Dia model.
|
||||
void cfg_scale(struct ggml_tensor * dst, const struct ggml_tensor * a, const struct ggml_tensor * b, int ith, int nth, void * userdata);
|
||||
|
||||
struct ggml_tensor * reciprocal(ggml_context * ctx, struct ggml_tensor * x);
|
||||
|
||||
bool has_suffix(std::string value, std::string suffix);
|
||||
bool has_prefix(std::string value, std::string prefix);
|
||||
|
||||
std::vector<std::string> split(std::string target, std::string split_on, bool include_split_characters = false);
|
||||
std::vector<std::string> split(std::string target, const char split_on, bool include_split_characters = false);
|
||||
std::string strip(std::string target, std::string vals = " ");
|
||||
std::string replace_any(std::string target, std::string to_replace, std::string replacement);
|
||||
|
||||
[[noreturn]] void tts_abort(const char * file, int line, const char * fmt, ...);
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user