delete index-ttss
This commit is contained in:
Generated
-2
@@ -50,10 +50,8 @@ dependencies = [
|
|||||||
"minijinja",
|
"minijinja",
|
||||||
"modelscope",
|
"modelscope",
|
||||||
"num",
|
"num",
|
||||||
"rand 0.9.2",
|
|
||||||
"rayon",
|
"rayon",
|
||||||
"realfft",
|
"realfft",
|
||||||
"regex",
|
|
||||||
"reqwest 0.12.24",
|
"reqwest 0.12.24",
|
||||||
"rocket",
|
"rocket",
|
||||||
"sentencepiece",
|
"sentencepiece",
|
||||||
|
|||||||
@@ -41,8 +41,6 @@ zip = "7.2.0"
|
|||||||
half = "2.7.1"
|
half = "2.7.1"
|
||||||
byteorder = "1.5.0"
|
byteorder = "1.5.0"
|
||||||
sentencepiece = "0.13.1"
|
sentencepiece = "0.13.1"
|
||||||
regex = "1.12.3"
|
|
||||||
rand = "0.9.2"
|
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
flash-attn = ["candle-flash-attn"]
|
flash-attn = ["candle-flash-attn"]
|
||||||
|
|||||||
+3
-236
@@ -2,9 +2,9 @@ use anyhow::{Result, anyhow};
|
|||||||
use candle_core::{D, IndexOp, Tensor};
|
use candle_core::{D, IndexOp, Tensor};
|
||||||
use candle_nn::{
|
use candle_nn::{
|
||||||
Activation, BatchNorm, BatchNormConfig, Conv1d, Conv1dConfig, Conv2d, Conv2dConfig,
|
Activation, BatchNorm, BatchNormConfig, Conv1d, Conv1dConfig, Conv2d, Conv2dConfig,
|
||||||
ConvTranspose1d, ConvTranspose1dConfig, Embedding, Init, LayerNorm, LayerNormConfig, Linear,
|
ConvTranspose1d, ConvTranspose1dConfig, Embedding, LayerNorm, LayerNormConfig, Linear, Module,
|
||||||
Module, ModuleT, RmsNorm, VarBuilder, batch_norm, conv1d, conv1d_no_bias, conv2d,
|
ModuleT, RmsNorm, VarBuilder, batch_norm, conv1d, conv1d_no_bias, conv2d, conv2d_no_bias,
|
||||||
conv2d_no_bias, embedding, layer_norm, linear_b, linear_no_bias, ops::sigmoid, rms_norm,
|
embedding, layer_norm, linear_b, linear_no_bias, ops::sigmoid, rms_norm,
|
||||||
};
|
};
|
||||||
use rayon::iter::{IndexedParallelIterator, IntoParallelRefIterator, ParallelIterator};
|
use rayon::iter::{IndexedParallelIterator, IntoParallelRefIterator, ParallelIterator};
|
||||||
|
|
||||||
@@ -1194,236 +1194,3 @@ pub fn mish(xs: &Tensor) -> Result<Tensor> {
|
|||||||
let xs = xs.mul(&tanh)?;
|
let xs = xs.mul(&tanh)?;
|
||||||
Ok(xs)
|
Ok(xs)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct GPT2Attention {
|
|
||||||
num_heads: usize,
|
|
||||||
head_dim: usize,
|
|
||||||
c_attn: Linear,
|
|
||||||
c_proj: Linear,
|
|
||||||
kv_cache: Option<(Tensor, Tensor)>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl GPT2Attention {
|
|
||||||
pub fn new(vb: VarBuilder, hidden_size: usize, num_heads: usize) -> Result<Self> {
|
|
||||||
let c_attn_weight = vb
|
|
||||||
.get_with_hints(
|
|
||||||
(hidden_size, 3 * hidden_size),
|
|
||||||
"c_attn.weight",
|
|
||||||
Init::Const(1.0),
|
|
||||||
)?
|
|
||||||
.t()?;
|
|
||||||
let c_attn_bias = vb.get_with_hints(3 * hidden_size, "c_attn.bias", Init::Const(0.0))?;
|
|
||||||
let c_attn = Linear::new(c_attn_weight, Some(c_attn_bias));
|
|
||||||
// let c_attn = linear_b(3 * hidden_size, hidden_size, true, vb.pp("c_attn"))?;
|
|
||||||
let c_proj_weight = vb
|
|
||||||
.get_with_hints(
|
|
||||||
(hidden_size, hidden_size),
|
|
||||||
"c_proj.weight",
|
|
||||||
Init::Const(1.0),
|
|
||||||
)?
|
|
||||||
.t()?;
|
|
||||||
let c_proj_bias = vb.get_with_hints(hidden_size, "c_proj.bias", Init::Const(0.0))?;
|
|
||||||
let c_proj = Linear::new(c_proj_weight, Some(c_proj_bias));
|
|
||||||
// let c_proj = linear_b(hidden_size, hidden_size, true, vb.pp("c_proj"))?;
|
|
||||||
let head_dim = hidden_size / num_heads;
|
|
||||||
Ok(Self {
|
|
||||||
num_heads,
|
|
||||||
head_dim,
|
|
||||||
c_attn,
|
|
||||||
c_proj,
|
|
||||||
kv_cache: None,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn forward(&mut self, xs: &Tensor, attention_mask: Option<&Tensor>) -> Result<Tensor> {
|
|
||||||
let (b, seq_len, _) = xs.dims3()?;
|
|
||||||
let xs = self.c_attn.forward(xs)?;
|
|
||||||
let xs_splits = xs.chunk(3, 2)?;
|
|
||||||
let query_states = xs_splits[0]
|
|
||||||
.as_ref()
|
|
||||||
.reshape((b, seq_len, self.num_heads, self.head_dim))?
|
|
||||||
.transpose(1, 2)?;
|
|
||||||
let key_states = xs_splits[1]
|
|
||||||
.as_ref()
|
|
||||||
.reshape((b, seq_len, self.num_heads, self.head_dim))?
|
|
||||||
.transpose(1, 2)?;
|
|
||||||
let value_states = xs_splits[2]
|
|
||||||
.as_ref()
|
|
||||||
.reshape((b, seq_len, self.num_heads, self.head_dim))?
|
|
||||||
.transpose(1, 2)?;
|
|
||||||
let (key_states, value_states) = match &self.kv_cache {
|
|
||||||
None => (key_states, value_states),
|
|
||||||
Some((prev_k, prev_v)) => {
|
|
||||||
let key_states = Tensor::cat(&[prev_k, &key_states], 2)?;
|
|
||||||
let value_states = Tensor::cat(&[prev_v, &value_states], 2)?;
|
|
||||||
(key_states, value_states)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
self.kv_cache = Some((key_states.clone(), value_states.clone()));
|
|
||||||
let scale = 1f64 / f64::sqrt(self.head_dim as f64);
|
|
||||||
let attn_output = eager_attention_forward(
|
|
||||||
&query_states,
|
|
||||||
&key_states,
|
|
||||||
&value_states,
|
|
||||||
None,
|
|
||||||
attention_mask,
|
|
||||||
scale,
|
|
||||||
)?;
|
|
||||||
let attn_output = attn_output.reshape((b, seq_len, self.num_heads * self.head_dim))?;
|
|
||||||
let attn_output = attn_output.apply(&self.c_proj)?;
|
|
||||||
Ok(attn_output)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn clear_kv_cache(&mut self) {
|
|
||||||
self.kv_cache = None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct GPT2MLP {
|
|
||||||
linear1: Linear,
|
|
||||||
linear2: Linear,
|
|
||||||
act: Activation,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl GPT2MLP {
|
|
||||||
pub fn new(
|
|
||||||
vb: VarBuilder,
|
|
||||||
in_dim: usize,
|
|
||||||
middle_dim: usize,
|
|
||||||
out_dim: usize,
|
|
||||||
act: Activation,
|
|
||||||
) -> Result<Self> {
|
|
||||||
let c_fc_weight = vb
|
|
||||||
.get_with_hints((in_dim, middle_dim), "c_fc.weight", Init::Const(1.0))?
|
|
||||||
.t()?;
|
|
||||||
let c_fc_bias = vb.get_with_hints(middle_dim, "c_fc.bias", Init::Const(0.0))?;
|
|
||||||
let c_fc = Linear::new(c_fc_weight, Some(c_fc_bias));
|
|
||||||
|
|
||||||
let c_proj_weight = vb
|
|
||||||
.get_with_hints((middle_dim, out_dim), "c_proj.weight", Init::Const(1.0))?
|
|
||||||
.t()?;
|
|
||||||
let c_proj_bias = vb.get_with_hints(out_dim, "c_proj.bias", Init::Const(0.0))?;
|
|
||||||
let c_proj = Linear::new(c_proj_weight, Some(c_proj_bias));
|
|
||||||
|
|
||||||
Ok(Self {
|
|
||||||
linear1: c_fc,
|
|
||||||
linear2: c_proj,
|
|
||||||
act,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
pub fn forward(&self, xs: &Tensor) -> Result<Tensor> {
|
|
||||||
let xs = xs
|
|
||||||
.apply(&self.linear1)?
|
|
||||||
.apply(&self.act)?
|
|
||||||
.apply(&self.linear2)?;
|
|
||||||
Ok(xs)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct GPT2Block {
|
|
||||||
ln_1: LayerNorm,
|
|
||||||
attn: GPT2Attention,
|
|
||||||
ln_2: LayerNorm,
|
|
||||||
mlp: GPT2MLP,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl GPT2Block {
|
|
||||||
pub fn new(
|
|
||||||
vb: VarBuilder,
|
|
||||||
hidden_size: usize,
|
|
||||||
num_heads: usize,
|
|
||||||
inner_dim: Option<usize>,
|
|
||||||
) -> Result<Self> {
|
|
||||||
let inner_dim = inner_dim.unwrap_or(4 * hidden_size);
|
|
||||||
let ln_1 = get_layer_norm(vb.pp("ln_1"), 1e-5, hidden_size, true)?;
|
|
||||||
let attn = GPT2Attention::new(vb.pp("attn"), hidden_size, num_heads)?;
|
|
||||||
let ln_2 = get_layer_norm(vb.pp("ln_2"), 1e-5, hidden_size, true)?;
|
|
||||||
let mlp = GPT2MLP::new(
|
|
||||||
vb.pp("mlp"),
|
|
||||||
hidden_size,
|
|
||||||
inner_dim,
|
|
||||||
hidden_size,
|
|
||||||
Activation::NewGelu,
|
|
||||||
)?;
|
|
||||||
Ok(Self {
|
|
||||||
ln_1,
|
|
||||||
attn,
|
|
||||||
ln_2,
|
|
||||||
mlp,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn forward(&mut self, xs: &Tensor, attention_mask: Option<&Tensor>) -> Result<Tensor> {
|
|
||||||
let residual = xs.clone();
|
|
||||||
let xs = self.ln_1.forward(xs)?;
|
|
||||||
let xs = self.attn.forward(&xs, attention_mask)?;
|
|
||||||
let residual = xs.add(&residual)?;
|
|
||||||
let xs = self.ln_2.forward(&residual)?;
|
|
||||||
let xs = self.mlp.forward(&xs)?;
|
|
||||||
let xs = xs.add(&residual)?;
|
|
||||||
Ok(xs)
|
|
||||||
}
|
|
||||||
pub fn clear_kv_cache(&mut self) {
|
|
||||||
self.attn.clear_kv_cache()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(unused)]
|
|
||||||
pub struct GPT2Model {
|
|
||||||
wte: Embedding,
|
|
||||||
// wpe: Embedding,
|
|
||||||
h: Vec<GPT2Block>,
|
|
||||||
ln_f: LayerNorm,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(unused)]
|
|
||||||
impl GPT2Model {
|
|
||||||
pub fn new(
|
|
||||||
vb: VarBuilder,
|
|
||||||
hidden_size: usize,
|
|
||||||
num_heads: usize,
|
|
||||||
num_hidden_layers: usize,
|
|
||||||
wte_embeddings: &Tensor,
|
|
||||||
) -> Result<Self> {
|
|
||||||
// let wte = embedding(vocab_size, hidden_size, vb.pp("wte"))?;
|
|
||||||
let wte = Embedding::new(wte_embeddings.clone(), hidden_size);
|
|
||||||
// let wpe = embedding(max_position_embeddings, hidden_size, vb.pp("wpe"))?;
|
|
||||||
let vb_layers = vb.pp("h");
|
|
||||||
let mut h = vec![];
|
|
||||||
for i in 0..num_hidden_layers {
|
|
||||||
let block = GPT2Block::new(vb_layers.pp(i), hidden_size, num_heads, None)?;
|
|
||||||
h.push(block);
|
|
||||||
}
|
|
||||||
let ln_f = get_layer_norm(vb.pp("ln_f"), 1e-5, hidden_size, true)?;
|
|
||||||
Ok(Self { wte, h, ln_f })
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn forward(&mut self, inputs_embeds: &Tensor) -> Result<Tensor> {
|
|
||||||
let (b_size, seq_len, _) = inputs_embeds.dims3()?;
|
|
||||||
let mut xs = inputs_embeds.clone();
|
|
||||||
let attention_mask: Option<Tensor> = {
|
|
||||||
if seq_len <= 1 {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(prepare_causal_attention_mask(
|
|
||||||
b_size,
|
|
||||||
seq_len,
|
|
||||||
0,
|
|
||||||
xs.device(),
|
|
||||||
)?)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
for block in &mut self.h {
|
|
||||||
xs = block.forward(&xs, attention_mask.as_ref())?;
|
|
||||||
}
|
|
||||||
xs = self.ln_f.forward(&xs)?;
|
|
||||||
Ok(xs)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn clear_kv_cache(&mut self) {
|
|
||||||
for layer in self.h.iter_mut() {
|
|
||||||
layer.clear_kv_cache()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,228 +0,0 @@
|
|||||||
use serde::{Deserialize, Deserializer};
|
|
||||||
|
|
||||||
use crate::models::mask_gct::config::SemanticCodec;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Deserialize)]
|
|
||||||
pub struct IndexTTS2Config {
|
|
||||||
pub dataset: Dataset,
|
|
||||||
pub gpt: GptConfig,
|
|
||||||
pub semantic_codec: SemanticCodec,
|
|
||||||
pub s2mel: S2MelConfig,
|
|
||||||
pub gpt_checkpoint: String,
|
|
||||||
pub w2v_stat: String,
|
|
||||||
pub s2mel_checkpoint: String,
|
|
||||||
pub emo_matrix: String,
|
|
||||||
pub spk_matrix: String,
|
|
||||||
pub emo_num: Vec<usize>,
|
|
||||||
pub qwen_emo_path: String,
|
|
||||||
pub vocoder: Vocoder,
|
|
||||||
pub version: f32,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Deserialize)]
|
|
||||||
pub struct Dataset {
|
|
||||||
pub bpe_model: String,
|
|
||||||
pub sample_rate: usize,
|
|
||||||
pub squeeze: bool,
|
|
||||||
pub mel: Mel,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Deserialize)]
|
|
||||||
pub struct Mel {
|
|
||||||
pub sample_rate: usize,
|
|
||||||
pub n_fft: usize,
|
|
||||||
pub hop_length: usize,
|
|
||||||
pub win_length: usize,
|
|
||||||
pub n_mels: usize,
|
|
||||||
pub mel_fmin: usize,
|
|
||||||
pub normalize: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Deserialize)]
|
|
||||||
pub struct GptConfig {
|
|
||||||
pub model_dim: usize,
|
|
||||||
pub max_mel_tokens: usize,
|
|
||||||
pub max_text_tokens: usize,
|
|
||||||
pub heads: usize,
|
|
||||||
pub use_mel_codes_as_input: bool,
|
|
||||||
pub mel_length_compression: usize,
|
|
||||||
pub layers: usize,
|
|
||||||
pub number_text_tokens: usize,
|
|
||||||
pub number_mel_codes: usize,
|
|
||||||
pub start_mel_token: usize,
|
|
||||||
pub stop_mel_token: usize,
|
|
||||||
pub start_text_token: usize,
|
|
||||||
pub stop_text_token: usize,
|
|
||||||
pub train_solo_embeddings: bool,
|
|
||||||
pub condition_type: String,
|
|
||||||
pub condition_module: ConditionModule,
|
|
||||||
pub emo_condition_module: EmoConditionModule,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Deserialize)]
|
|
||||||
pub struct ConditionModule {
|
|
||||||
pub output_size: usize,
|
|
||||||
pub linear_units: usize,
|
|
||||||
pub attention_heads: usize,
|
|
||||||
pub num_blocks: usize,
|
|
||||||
pub input_layer: String,
|
|
||||||
pub perceiver_mult: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Deserialize)]
|
|
||||||
pub struct EmoConditionModule {
|
|
||||||
pub output_size: usize,
|
|
||||||
pub linear_units: usize,
|
|
||||||
pub attention_heads: usize,
|
|
||||||
pub num_blocks: usize,
|
|
||||||
pub input_layer: String,
|
|
||||||
pub perceiver_mult: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Deserialize)]
|
|
||||||
pub struct S2MelConfig {
|
|
||||||
pub preprocess_params: PreprocessParams,
|
|
||||||
pub dit_type: String,
|
|
||||||
pub reg_loss_type: String,
|
|
||||||
pub style_encoder: StyleEncoder,
|
|
||||||
pub length_regulator: LengthRegulator,
|
|
||||||
#[serde(rename = "DiT")]
|
|
||||||
pub di_t: DiTConfig,
|
|
||||||
pub wavenet: WavenetConfig,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Deserialize)]
|
|
||||||
pub struct PreprocessParams {
|
|
||||||
pub sr: usize,
|
|
||||||
pub spect_params: SpectParams,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Deserialize)]
|
|
||||||
pub struct SpectParams {
|
|
||||||
pub n_fft: usize,
|
|
||||||
pub win_length: usize,
|
|
||||||
pub hop_length: usize,
|
|
||||||
pub n_mels: usize,
|
|
||||||
pub fmin: usize,
|
|
||||||
#[serde(deserialize_with = "deserialize_optional_fmax")]
|
|
||||||
pub fmax: Option<usize>,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn deserialize_optional_fmax<'de, D>(deserializer: D) -> Result<Option<usize>, D::Error>
|
|
||||||
where D: Deserializer<'de> {
|
|
||||||
let opt: Option<serde_json::Value> = Option::deserialize(deserializer)?;
|
|
||||||
match opt {
|
|
||||||
Some(serde_json::Value::String(s)) if s == "None" || s == "null" => Ok(None),
|
|
||||||
Some(serde_json::Value::Number(n)) => {
|
|
||||||
if let Some(n) = n.as_u64() {
|
|
||||||
Ok(Some(n as usize))
|
|
||||||
} else {
|
|
||||||
Err(serde::de::Error::custom("Expected positive integer"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Some(_) => Err(serde::de::Error::custom("Expected number or 'None' string")),
|
|
||||||
None => Ok(None),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Deserialize)]
|
|
||||||
pub struct StyleEncoder {
|
|
||||||
pub dim: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Deserialize)]
|
|
||||||
pub struct LengthRegulator {
|
|
||||||
pub channels: usize,
|
|
||||||
pub is_discrete: bool,
|
|
||||||
pub in_channels: usize,
|
|
||||||
pub content_codebook_size: usize,
|
|
||||||
pub sampling_ratios: Vec<usize>,
|
|
||||||
pub vector_quantize: bool,
|
|
||||||
pub n_codebooks: usize,
|
|
||||||
pub quantizer_dropout: f32,
|
|
||||||
pub f0_condition: bool,
|
|
||||||
pub n_f0_bins: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Deserialize)]
|
|
||||||
pub struct DiTConfig {
|
|
||||||
pub hidden_dim: usize,
|
|
||||||
pub num_heads: usize,
|
|
||||||
pub depth: usize,
|
|
||||||
pub class_dropout_prob: f32,
|
|
||||||
pub block_size: usize,
|
|
||||||
pub in_channels: usize,
|
|
||||||
pub style_condition: bool,
|
|
||||||
pub final_layer_type: String,
|
|
||||||
pub target: String,
|
|
||||||
pub content_dim: usize,
|
|
||||||
pub content_codebook_size: usize,
|
|
||||||
pub content_type: String,
|
|
||||||
pub f0_condition: bool,
|
|
||||||
pub n_f0_bins: usize,
|
|
||||||
pub content_codebooks: usize,
|
|
||||||
pub is_causal: bool,
|
|
||||||
pub long_skip_connection: bool,
|
|
||||||
pub zero_prompt_speech_token: bool,
|
|
||||||
pub time_as_token: bool,
|
|
||||||
pub style_as_token: bool,
|
|
||||||
pub uvit_skip_connection: bool,
|
|
||||||
pub add_resblock_in_transformer: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct DiTModelArgs {
|
|
||||||
pub block_size: usize,
|
|
||||||
pub vocab_size: usize,
|
|
||||||
pub n_layer: usize,
|
|
||||||
pub n_head: usize,
|
|
||||||
pub dim: usize,
|
|
||||||
pub intermediate_size: usize,
|
|
||||||
pub n_local_heads: usize,
|
|
||||||
pub head_dim: usize,
|
|
||||||
pub rope_base: f32,
|
|
||||||
pub norm_eps: f64,
|
|
||||||
pub has_cross_attention: bool,
|
|
||||||
pub context_dim: usize,
|
|
||||||
pub uvit_skip_connection: bool,
|
|
||||||
pub time_as_token: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DiTModelArgs {
|
|
||||||
pub fn new_from_dit_config(config: &DiTConfig) -> Self {
|
|
||||||
let hidden_dim = 4 * config.hidden_dim;
|
|
||||||
let n_hidden = 2 * hidden_dim / 3;
|
|
||||||
let intermediate_size = n_hidden + (256 - n_hidden % 256) % 256;
|
|
||||||
Self {
|
|
||||||
block_size: config.block_size,
|
|
||||||
vocab_size: 1024,
|
|
||||||
n_layer: config.depth,
|
|
||||||
n_head: config.num_heads,
|
|
||||||
dim: config.hidden_dim,
|
|
||||||
intermediate_size,
|
|
||||||
n_local_heads: config.num_heads,
|
|
||||||
head_dim: config.hidden_dim / config.num_heads,
|
|
||||||
rope_base: 10000.0,
|
|
||||||
norm_eps: 1e-5,
|
|
||||||
has_cross_attention: false,
|
|
||||||
context_dim: 0,
|
|
||||||
uvit_skip_connection: config.uvit_skip_connection,
|
|
||||||
time_as_token: config.time_as_token,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Deserialize)]
|
|
||||||
pub struct WavenetConfig {
|
|
||||||
pub hidden_dim: usize,
|
|
||||||
pub num_layers: usize,
|
|
||||||
pub kernel_size: usize,
|
|
||||||
pub dilation_rate: usize,
|
|
||||||
pub p_dropout: f32,
|
|
||||||
pub style_condition: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Deserialize)]
|
|
||||||
pub struct Vocoder {
|
|
||||||
pub r#type: String,
|
|
||||||
pub name: String,
|
|
||||||
}
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
use aha_openai_dive::v1::resources::chat::{ChatCompletionParameters, ChatCompletionResponse};
|
|
||||||
use anyhow::{Result, anyhow};
|
|
||||||
use base64::{Engine, prelude::BASE64_STANDARD};
|
|
||||||
use candle_core::{DType, Device};
|
|
||||||
use sentencepiece::SentencePieceProcessor;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
models::index_tts2::{
|
|
||||||
config::IndexTTS2Config, model::IndexTTS2Model, utils::tokenize_by_cjk_char,
|
|
||||||
},
|
|
||||||
tokenizer::sentencepiece_encode,
|
|
||||||
utils::{
|
|
||||||
audio_utils::get_audio_wav_u8, build_audio_completion_response, extract_user_text,
|
|
||||||
get_default_save_dir, get_device,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
pub struct IndexTTS2Generate {
|
|
||||||
tokenizer: SentencePieceProcessor,
|
|
||||||
// config: IndexTTS2Config,
|
|
||||||
model: IndexTTS2Model,
|
|
||||||
device: Device,
|
|
||||||
sample_rate: u32,
|
|
||||||
model_name: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(unused)]
|
|
||||||
impl IndexTTS2Generate {
|
|
||||||
pub fn init(path: &str, device: Option<&Device>, dtype: Option<DType>) -> Result<Self> {
|
|
||||||
let config_path = path.to_string() + "/config.yaml";
|
|
||||||
let save_dir = get_default_save_dir().ok_or(anyhow::anyhow!("Failed to get save dir"))?;
|
|
||||||
let config: IndexTTS2Config = serde_yaml::from_slice(&std::fs::read(config_path)?)?;
|
|
||||||
let device = get_device(device);
|
|
||||||
let bpe_path = path.to_string() + "/bpe.model";
|
|
||||||
let tokenizer = SentencePieceProcessor::open(bpe_path)
|
|
||||||
.map_err(|e| anyhow!(format!("load bpe,model file error:{}", e)))?;
|
|
||||||
let model = IndexTTS2Model::new(path, &save_dir, &config, &device)?;
|
|
||||||
Ok(Self {
|
|
||||||
tokenizer,
|
|
||||||
// config,
|
|
||||||
model,
|
|
||||||
device,
|
|
||||||
sample_rate: 22050,
|
|
||||||
model_name: "index-tts2".to_string(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn generate(&mut self, mes: ChatCompletionParameters) -> Result<ChatCompletionResponse> {
|
|
||||||
let text = extract_user_text(&mes)?;
|
|
||||||
let text = tokenize_by_cjk_char(&text, true);
|
|
||||||
let input_ids = sentencepiece_encode(&text, &self.tokenizer, &self.device)?;
|
|
||||||
|
|
||||||
let audio = self.model.forward(&input_ids, &mes)?;
|
|
||||||
let wav_u8 = get_audio_wav_u8(&audio, self.sample_rate)?;
|
|
||||||
let base64_audio = BASE64_STANDARD.encode(wav_u8);
|
|
||||||
let response = build_audio_completion_response(&base64_audio, &self.model_name);
|
|
||||||
Ok(response)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
pub mod config;
|
|
||||||
pub mod generate;
|
|
||||||
pub mod model;
|
|
||||||
// pub mod processor;
|
|
||||||
pub mod utils;
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,172 +0,0 @@
|
|||||||
use anyhow::{Result, anyhow};
|
|
||||||
use regex::Regex;
|
|
||||||
|
|
||||||
use crate::utils::{download_model, get_default_save_dir};
|
|
||||||
|
|
||||||
pub async fn download_index_tts2_need_model(save_dir: Option<&str>) -> Result<()> {
|
|
||||||
let save_dir = match save_dir {
|
|
||||||
Some(dir) => dir.to_string(),
|
|
||||||
None => get_default_save_dir().expect("Failed to get home directory"),
|
|
||||||
};
|
|
||||||
|
|
||||||
let w2v_bert2_0 = "facebook/w2v-bert-2.0";
|
|
||||||
let mask_gct = "amphion/MaskGCT";
|
|
||||||
// let campplus= "funasr/campplus"; // huggingface
|
|
||||||
let campplus = "iic/speech_campplus_sv_zh-cn_16k-common"; // modelscope
|
|
||||||
// let bigvgan = "nvidia/bigvgan_v2_22khz_80band_256x"; // huggingface
|
|
||||||
let bigvgan = "nv-community/bigvgan_v2_22khz_80band_256x"; // modelscope
|
|
||||||
download_model(w2v_bert2_0, &save_dir, 3).await?;
|
|
||||||
download_model(mask_gct, &save_dir, 3).await?;
|
|
||||||
download_model(campplus, &save_dir, 3).await?;
|
|
||||||
download_model(bigvgan, &save_dir, 3).await?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct TextNormalizer {
|
|
||||||
// char_rep_map: HashMap<String, String>,
|
|
||||||
// zh_char_rep_map: HashMap<String, String>,
|
|
||||||
pinyin_tone_pattern: Regex,
|
|
||||||
// name_pattern: Regex,
|
|
||||||
// tech_term_pattern: Regex,
|
|
||||||
// english_contraction_pattern: Regex,
|
|
||||||
email_pattern: Regex,
|
|
||||||
cjk_range_pattern: Regex,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TextNormalizer {
|
|
||||||
pub fn new() -> Result<Self> {
|
|
||||||
let pinyin_tone_pattern: Regex = Regex::new(
|
|
||||||
// r"(?i)(?<![a-z])((?:[bpmfdtnlgkhjqxzcsryw]|[zcs]h)?(?:[aeiouüvAEIOUV]|[aeAE]i|u[aiouAIUO]|aoAO|ouOU|i[aeuAEU]|[uüvUÜV]e|[uvüUVÜ]ang?|uaiUAI|[aeiuvAEIUV]n|[aeioAEIO]ng|ia[noNAO]|i[aA][oO]ng)|ngNG|erER)([1-5])"
|
|
||||||
r"(?i)((?:[bpmfdtnlgkhjqxzcsryw]|[zcs]h)?(?:[aeiouüvAEIOUV]|[aeAE]i|u[aiouAIUO]|aoAO|ouOU|i[aeuAEU]|[uüvUÜV]e|[uvüUVÜ]ang?|uaiUAI|[aeiuvAEIUV]n|[aeioAEIO]ng|ia[noNAO]|i[aA][oO]ng)|ngNG|erER)([1-5])"
|
|
||||||
).map_err(|e| anyhow!(format!("new pinyin_tone_pattern regex error:{}", e)))?;
|
|
||||||
// let name_pattern: Regex =
|
|
||||||
// Regex::new(r"[\u{4e00}-\u{9fff}]+(?:[-·—][\u{4e00}-\u{9fff}]+){1,2}")
|
|
||||||
// .map_err(|e| anyhow!(format!("new name_pattern regex error:{}", e)))?;
|
|
||||||
// let tech_term_pattern: Regex = Regex::new(r"[A-Za-z][A-Za-z0-9]*(?:-[A-Za-z0-9]+)+")
|
|
||||||
// .map_err(|e| anyhow!(format!("new tech_term_pattern regex error:{}", e)))?;
|
|
||||||
// let english_contraction_pattern: Regex = Regex::new(
|
|
||||||
// r"(?i)(what|where|who|which|how|t?here|it|s?he|that|this)'s",
|
|
||||||
// )
|
|
||||||
// .map_err(|e| anyhow!(format!("new english_contraction_pattern regex error:{}", e)))?;
|
|
||||||
let email_pattern: Regex = Regex::new(r"^[a-zA-Z0-9]+@[a-zA-Z0-9]+\.[a-zA-Z]+$")
|
|
||||||
.map_err(|e| anyhow!(format!("new email_pattern regex error:{}", e)))?;
|
|
||||||
let cjk_range_pattern: Regex = Regex::new(r"([\u{1100}-\u{11ff}\u{2e80}-\u{a4cf}\u{a840}-\u{d7af}\u{f900}-\u{faff}\u{fe30}-\u{fe4f}\u{ff65}-\u{ffdc}\u{20000}-\u{2ffff}])")
|
|
||||||
.map_err(|e| anyhow!(format!("new cjk_range_pattern regex error:{}", e)))?;
|
|
||||||
// let mut char_rep_map = HashMap::new();
|
|
||||||
// char_rep_map.insert(":".to_string(), ",".to_string());
|
|
||||||
// char_rep_map.insert(";".to_string(), ",".to_string());
|
|
||||||
// char_rep_map.insert(";".to_string(), ",".to_string());
|
|
||||||
// char_rep_map.insert(",".to_string(), ",".to_string());
|
|
||||||
// char_rep_map.insert("。".to_string(), ".".to_string());
|
|
||||||
// char_rep_map.insert("!".to_string(), "!".to_string());
|
|
||||||
// char_rep_map.insert("?".to_string(), "?".to_string());
|
|
||||||
// char_rep_map.insert("\n".to_string(), " ".to_string());
|
|
||||||
// char_rep_map.insert("·".to_string(), "-".to_string());
|
|
||||||
// char_rep_map.insert("、".to_string(), ",".to_string());
|
|
||||||
// char_rep_map.insert("...".to_string(), "…".to_string());
|
|
||||||
// char_rep_map.insert(",,,".to_string(), "…".to_string());
|
|
||||||
// char_rep_map.insert(",,,".to_string(), "…".to_string());
|
|
||||||
// char_rep_map.insert("……".to_string(), "…".to_string());
|
|
||||||
// char_rep_map.insert("“".to_string(), "'".to_string());
|
|
||||||
// char_rep_map.insert("”".to_string(), "'".to_string());
|
|
||||||
// char_rep_map.insert("\"".to_string(), "'".to_string());
|
|
||||||
// char_rep_map.insert("‘".to_string(), "'".to_string());
|
|
||||||
// char_rep_map.insert("’".to_string(), "'".to_string());
|
|
||||||
// char_rep_map.insert("(".to_string(), "'".to_string());
|
|
||||||
// char_rep_map.insert(")".to_string(), "'".to_string());
|
|
||||||
// char_rep_map.insert("(".to_string(), "'".to_string());
|
|
||||||
// char_rep_map.insert(")".to_string(), "'".to_string());
|
|
||||||
// char_rep_map.insert("《".to_string(), "'".to_string());
|
|
||||||
// char_rep_map.insert("》".to_string(), "'".to_string());
|
|
||||||
// char_rep_map.insert("【".to_string(), "'".to_string());
|
|
||||||
// char_rep_map.insert("】".to_string(), "'".to_string());
|
|
||||||
// char_rep_map.insert("[".to_string(), "'".to_string());
|
|
||||||
// char_rep_map.insert("]".to_string(), "'".to_string());
|
|
||||||
// char_rep_map.insert("—".to_string(), "-".to_string());
|
|
||||||
// char_rep_map.insert("~".to_string(), "-".to_string());
|
|
||||||
// char_rep_map.insert("~".to_string(), "-".to_string());
|
|
||||||
// char_rep_map.insert("「".to_string(), "'".to_string());
|
|
||||||
// char_rep_map.insert("」".to_string(), "'".to_string());
|
|
||||||
// char_rep_map.insert(":".to_string(), ",".to_string());
|
|
||||||
|
|
||||||
// let mut zh_char_rep_map = char_rep_map.clone();
|
|
||||||
// zh_char_rep_map.insert("$".to_string(), ".".to_string());
|
|
||||||
Ok(Self {
|
|
||||||
// char_rep_map,
|
|
||||||
// zh_char_rep_map,
|
|
||||||
pinyin_tone_pattern,
|
|
||||||
// name_pattern,
|
|
||||||
// tech_term_pattern,
|
|
||||||
// english_contraction_pattern,
|
|
||||||
email_pattern,
|
|
||||||
cjk_range_pattern,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn match_email(&self, email: &str) -> bool {
|
|
||||||
self.email_pattern.is_match(email)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn use_chinese(&self, s: &str) -> bool {
|
|
||||||
let has_chinese = s.chars().any(|c| ('\u{4e00}'..='\u{9fff}').contains(&c));
|
|
||||||
let has_alpha = s.chars().any(|c| c.is_alphabetic());
|
|
||||||
let is_email = self.match_email(s);
|
|
||||||
|
|
||||||
if has_chinese || !has_alpha || is_email {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.pinyin_tone_pattern.is_match(s)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn tokenize_by_cjk_char(&self, line: &str, do_upper_case: bool) -> String {
|
|
||||||
// Split the line by CJK characters
|
|
||||||
let parts: Vec<&str> = self.cjk_range_pattern.split(line.trim()).collect();
|
|
||||||
// Process each part and join with spaces
|
|
||||||
let mut result_parts = Vec::new();
|
|
||||||
for part in parts {
|
|
||||||
if !part.trim().is_empty() {
|
|
||||||
if do_upper_case {
|
|
||||||
result_parts.push(part.trim().to_uppercase());
|
|
||||||
} else {
|
|
||||||
result_parts.push(part.trim().to_string());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Join the parts with spaces
|
|
||||||
result_parts.join(" ")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn tokenize_by_cjk_char(line: &str, do_upper_case: bool) -> String {
|
|
||||||
let mut result_parts = Vec::new();
|
|
||||||
for ch in line.chars() {
|
|
||||||
if ('\u{1100}'..='\u{11ff}').contains(&ch)
|
|
||||||
|| ('\u{2e80}'..='\u{a4cf}').contains(&ch)
|
|
||||||
|| ('\u{a840}'..='\u{d7af}').contains(&ch)
|
|
||||||
|| ('\u{f900}'..='\u{faff}').contains(&ch)
|
|
||||||
|| ('\u{fe30}'..='\u{fe4f}').contains(&ch)
|
|
||||||
|| ('\u{ff65}'..='\u{ffdc}').contains(&ch)
|
|
||||||
|| ('\u{20000}'..='\u{2ffff}').contains(&ch)
|
|
||||||
|| ('\u{4e00}'..='\u{9fff}').contains(&ch)
|
|
||||||
{
|
|
||||||
// CJK 字符
|
|
||||||
if do_upper_case {
|
|
||||||
result_parts.push(ch.to_uppercase().collect::<String>());
|
|
||||||
} else {
|
|
||||||
result_parts.push(ch.to_string());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// 非 CJK 字符,保持在一起
|
|
||||||
if do_upper_case {
|
|
||||||
result_parts.push(ch.to_uppercase().to_string());
|
|
||||||
} else {
|
|
||||||
result_parts.push(ch.to_string());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
result_parts.join(" ")
|
|
||||||
}
|
|
||||||
@@ -6,7 +6,6 @@ pub mod feature_extractor;
|
|||||||
pub mod fun_asr_nano;
|
pub mod fun_asr_nano;
|
||||||
pub mod glm_asr_nano;
|
pub mod glm_asr_nano;
|
||||||
pub mod hunyuan_ocr;
|
pub mod hunyuan_ocr;
|
||||||
pub mod index_tts2;
|
|
||||||
pub mod mask_gct;
|
pub mod mask_gct;
|
||||||
pub mod minicpm4;
|
pub mod minicpm4;
|
||||||
pub mod paddleocr_vl;
|
pub mod paddleocr_vl;
|
||||||
|
|||||||
@@ -1,55 +0,0 @@
|
|||||||
use std::time::Instant;
|
|
||||||
|
|
||||||
use aha::{
|
|
||||||
models::index_tts2::{generate::IndexTTS2Generate, utils::download_index_tts2_need_model},
|
|
||||||
utils::audio_utils::extract_and_save_audio_from_response,
|
|
||||||
};
|
|
||||||
use aha_openai_dive::v1::resources::chat::ChatCompletionParameters;
|
|
||||||
use anyhow::Result;
|
|
||||||
|
|
||||||
#[tokio::test]
|
|
||||||
async fn index_tts2_generate() -> Result<()> {
|
|
||||||
// RUST_BACKTRACE=1 cargo test -F cuda index_tts2_generate -r -- --nocapture
|
|
||||||
let save_dir =
|
|
||||||
aha::utils::get_default_save_dir().ok_or(anyhow::anyhow!("Failed to get save dir"))?;
|
|
||||||
let _ = download_index_tts2_need_model(Some(&save_dir)).await?;
|
|
||||||
let model_path = format!("{}/IndexTeam/IndexTTS-2", save_dir);
|
|
||||||
let message = r#"
|
|
||||||
{
|
|
||||||
"model": "index-tts2",
|
|
||||||
"messages": [
|
|
||||||
{
|
|
||||||
"role": "user",
|
|
||||||
"content": [
|
|
||||||
{
|
|
||||||
"type": "audio",
|
|
||||||
"audio_url":
|
|
||||||
{
|
|
||||||
"url": "file:///home/jhq/Videos/voice_01.wav"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "text",
|
|
||||||
"text": "你好啊,吃饭了吗"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
"#;
|
|
||||||
let mes: ChatCompletionParameters = serde_json::from_str(message)?;
|
|
||||||
let i_start = Instant::now();
|
|
||||||
let mut voxcpm_generate = IndexTTS2Generate::init(&model_path, None, None)?;
|
|
||||||
let i_duration = i_start.elapsed();
|
|
||||||
println!("Time elapsed in load model is: {:?}", i_duration);
|
|
||||||
|
|
||||||
let i_start = Instant::now();
|
|
||||||
let generate = voxcpm_generate.generate(mes)?;
|
|
||||||
let save_path = extract_and_save_audio_from_response(&generate, "./")?;
|
|
||||||
for path in save_path {
|
|
||||||
println!("save audio: {}", path);
|
|
||||||
}
|
|
||||||
let i_duration = i_start.elapsed();
|
|
||||||
println!("Time elapsed in generate is: {:?}", i_duration);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user