647 lines
20 KiB
Rust
647 lines
20 KiB
Rust
use anyhow::Result;
|
|
use candle_core::{D, IndexOp, Tensor};
|
|
use candle_nn::{Conv1d, LayerNorm, Linear, Module, VarBuilder, linear, ops::softmax_last_dim};
|
|
|
|
use crate::{
|
|
models::{
|
|
common::{
|
|
NaiveAttention, TwoLinearMLP, eager_attention_forward, get_conv1d, get_layer_norm,
|
|
},
|
|
fun_asr_nano::config::FunASRNanoConfig,
|
|
qwen3::{config::Qwen3Config, model::Qwen3Model},
|
|
},
|
|
position_embed::sinusoidal_pe::SinusoidalPositionEncoderCat,
|
|
utils::tensor_utils::{get_equal_mask, mask_filled, masked_scatter_dim0},
|
|
};
|
|
|
|
pub struct MultiHeadedAttentionSANM {
|
|
head_dim: usize,
|
|
n_head: usize,
|
|
linear_out: Linear,
|
|
linear_q_k_v: Linear,
|
|
fsmn_block: Conv1d,
|
|
left_padding: usize,
|
|
right_padding: usize,
|
|
scaling: f64,
|
|
}
|
|
|
|
impl MultiHeadedAttentionSANM {
|
|
pub fn new(
|
|
vb: VarBuilder,
|
|
n_head: usize,
|
|
in_dim: usize,
|
|
hidden_dim: usize,
|
|
kernel_size: usize,
|
|
sanm_shfit: usize,
|
|
) -> Result<Self> {
|
|
let head_dim = hidden_dim / n_head;
|
|
let linear_out = linear(hidden_dim, hidden_dim, vb.pp("linear_out"))?;
|
|
let linear_q_k_v = linear(in_dim, hidden_dim * 3, vb.pp("linear_q_k_v"))?;
|
|
let fsmn_block = get_conv1d(
|
|
vb.pp("fsmn_block"),
|
|
hidden_dim,
|
|
hidden_dim,
|
|
kernel_size,
|
|
0,
|
|
1,
|
|
1,
|
|
hidden_dim,
|
|
false,
|
|
)?;
|
|
let mut left_padding = (kernel_size - 1) / 2;
|
|
if sanm_shfit > 0 {
|
|
left_padding += sanm_shfit;
|
|
}
|
|
let right_padding = kernel_size - 1 - left_padding;
|
|
let scaling = (head_dim as f64).powf(-0.5);
|
|
Ok(Self {
|
|
head_dim,
|
|
n_head,
|
|
linear_out,
|
|
linear_q_k_v,
|
|
fsmn_block,
|
|
left_padding,
|
|
right_padding,
|
|
scaling,
|
|
})
|
|
}
|
|
|
|
pub fn forward_fsmn(
|
|
&self,
|
|
inputs: &Tensor,
|
|
mask: Option<&Tensor>,
|
|
mask_shfit_chunk: Option<&Tensor>,
|
|
) -> Result<Tensor> {
|
|
let mut inputs = inputs.clone();
|
|
let mask = if let Some(mask) = mask {
|
|
let mut mask = mask.unsqueeze(D::Minus1)?.unsqueeze(0)?;
|
|
if let Some(mask_shfit_chunk) = mask_shfit_chunk {
|
|
mask = mask.broadcast_mul(mask_shfit_chunk)?;
|
|
}
|
|
inputs = inputs.broadcast_mul(&mask)?;
|
|
Some(mask)
|
|
} else {
|
|
None
|
|
};
|
|
let xs = inputs.transpose(1, 2)?;
|
|
let xs = xs.pad_with_zeros(D::Minus1, self.left_padding, self.right_padding)?;
|
|
let xs = self.fsmn_block.forward(&xs)?;
|
|
let xs = xs.transpose(1, 2)?;
|
|
let mut xs = xs.add(&inputs)?;
|
|
if let Some(mask) = mask {
|
|
xs = xs.broadcast_mul(&mask)?;
|
|
}
|
|
Ok(xs)
|
|
}
|
|
pub fn forward_qkv(&self, xs: &Tensor) -> Result<(Tensor, Tensor, Tensor, Tensor)> {
|
|
let (b, t, _) = xs.dims3()?;
|
|
let q_k_v = self
|
|
.linear_q_k_v
|
|
.forward(xs)?
|
|
.reshape((b, t, 3, self.n_head, ()))?
|
|
.permute((2, 0, 3, 1, 4))?
|
|
.contiguous()?;
|
|
let q_h = q_k_v.i(0)?.contiguous()?;
|
|
let k_h = q_k_v.i(1)?.contiguous()?;
|
|
let v_h = q_k_v.i(2)?.contiguous()?;
|
|
let v = v_h.transpose(1, 2)?.reshape((b, t, ()))?;
|
|
Ok((q_h, k_h, v_h, v))
|
|
}
|
|
|
|
pub fn forward_attention(
|
|
&self,
|
|
values: &Tensor,
|
|
scores: &Tensor,
|
|
mask: Option<&Tensor>,
|
|
mask_att_chunk_encoder: Option<&Tensor>,
|
|
) -> Result<Tensor> {
|
|
let bs = scores.dim(0)?;
|
|
let attn = if let Some(mask) = mask {
|
|
let mask = if let Some(mask_att_chunk_encoder) = mask_att_chunk_encoder {
|
|
mask.mul(mask_att_chunk_encoder)?
|
|
} else {
|
|
mask.clone()
|
|
};
|
|
// mask: rank = 2
|
|
let mask = get_equal_mask(&mask, 0)?;
|
|
let scores = mask_filled(scores, &mask, f32::NEG_INFINITY)?;
|
|
let attn = softmax_last_dim(&scores)?;
|
|
mask_filled(&attn, &mask, 0.0)?
|
|
} else {
|
|
softmax_last_dim(scores)?
|
|
};
|
|
let xs = attn.matmul(values)?;
|
|
let xs =
|
|
xs.transpose(1, 2)?
|
|
.contiguous()?
|
|
.reshape((bs, (), self.n_head * self.head_dim))?;
|
|
let xs = self.linear_out.forward(&xs)?;
|
|
Ok(xs)
|
|
}
|
|
|
|
pub fn forward_simple(&self, xs: &Tensor) -> Result<Tensor> {
|
|
let (b, t, _) = xs.dims3()?;
|
|
let q_k_v = self.linear_q_k_v.forward(xs)?;
|
|
let dim = self.head_dim * self.n_head;
|
|
let q_h = q_k_v
|
|
.narrow(D::Minus1, 0, dim)?
|
|
.reshape((b, t, self.n_head, ()))?
|
|
.permute((0, 2, 1, 3))?;
|
|
let k_h = q_k_v
|
|
.narrow(D::Minus1, dim, dim)?
|
|
.reshape((b, t, self.n_head, ()))?
|
|
.permute((0, 2, 1, 3))?;
|
|
let v = q_k_v.narrow(D::Minus1, dim * 2, dim)?;
|
|
let v_h = v.reshape((b, t, self.n_head, ()))?.permute((0, 2, 1, 3))?;
|
|
let fsmn_memory = v.transpose(1, 2)?;
|
|
let fsmn_memory = fsmn_memory
|
|
.pad_with_zeros(D::Minus1, self.left_padding, self.right_padding)?
|
|
.contiguous()?;
|
|
let fsmn_memory = self.fsmn_block.forward(&fsmn_memory)?;
|
|
// let fsmn_memory = conv1d_group_parallel(&fsmn_memory, &self.fsmn_block)?;
|
|
|
|
let fsmn_memory = fsmn_memory.transpose(1, 2)?;
|
|
let fsmn_memory = fsmn_memory.add(&v)?;
|
|
let att_outs = eager_attention_forward(&q_h, &k_h, &v_h, None, None, self.scaling)?;
|
|
let att_outs = att_outs.reshape((b, t, ()))?;
|
|
let att_outs = self.linear_out.forward(&att_outs)?;
|
|
let att_outs = att_outs.add(&fsmn_memory)?;
|
|
Ok(att_outs)
|
|
}
|
|
|
|
pub fn forward(
|
|
&self,
|
|
xs: &Tensor,
|
|
mask: Option<&Tensor>,
|
|
mask_shfit_chunk: Option<&Tensor>,
|
|
mask_att_chunk_encoder: Option<&Tensor>,
|
|
) -> Result<Tensor> {
|
|
let (q_h, k_h, v_h, v) = self.forward_qkv(xs)?;
|
|
let fsmn_memory = self.forward_fsmn(&v, mask, mask_shfit_chunk)?;
|
|
let q_h = q_h.affine(self.scaling, 0.0)?;
|
|
let scores = q_h.matmul(&k_h.transpose(D::Minus2, D::Minus1)?)?;
|
|
let attn_outs = self.forward_attention(&v_h, &scores, mask, mask_att_chunk_encoder)?;
|
|
let att_outs = attn_outs.add(&fsmn_memory)?;
|
|
Ok(att_outs)
|
|
}
|
|
}
|
|
|
|
pub struct EncoderLayerSANM {
|
|
self_attn: MultiHeadedAttentionSANM,
|
|
feed_forward: TwoLinearMLP,
|
|
norm1: LayerNorm,
|
|
norm2: LayerNorm,
|
|
concat_linear: Option<Linear>,
|
|
normalize_before: bool,
|
|
in_dim: usize,
|
|
hidden_dim: usize,
|
|
}
|
|
|
|
impl EncoderLayerSANM {
|
|
pub fn new(
|
|
vb: VarBuilder,
|
|
in_dim: usize,
|
|
hidden_dim: usize,
|
|
n_head: usize,
|
|
kernel_size: usize,
|
|
sanm_shfit: usize,
|
|
hidden_units: usize,
|
|
normalize_before: bool,
|
|
concat_after: bool,
|
|
) -> Result<Self> {
|
|
let self_attn = MultiHeadedAttentionSANM::new(
|
|
vb.pp("self_attn"),
|
|
n_head,
|
|
in_dim,
|
|
hidden_dim,
|
|
kernel_size,
|
|
sanm_shfit,
|
|
)?;
|
|
let feed_forward = TwoLinearMLP::new(
|
|
vb.pp("feed_forward"),
|
|
hidden_dim,
|
|
hidden_units,
|
|
hidden_dim,
|
|
candle_nn::Activation::Relu,
|
|
true,
|
|
"w_1",
|
|
"w_2",
|
|
)?;
|
|
let norm1 = get_layer_norm(vb.pp("norm1"), 1e-5, in_dim)?;
|
|
let norm2 = get_layer_norm(vb.pp("norm2"), 1e-5, hidden_dim)?;
|
|
let concat_linear = if concat_after {
|
|
let lin = linear(hidden_dim * 2, hidden_dim, vb.pp("concat_linear"))?;
|
|
Some(lin)
|
|
} else {
|
|
None
|
|
};
|
|
Ok(Self {
|
|
self_attn,
|
|
feed_forward,
|
|
norm1,
|
|
norm2,
|
|
concat_linear,
|
|
normalize_before,
|
|
in_dim,
|
|
hidden_dim,
|
|
})
|
|
}
|
|
|
|
pub fn forward(
|
|
&self,
|
|
xs: &Tensor,
|
|
mask: Option<&Tensor>,
|
|
mask_shfit_chunk: Option<&Tensor>,
|
|
mask_att_chunk_encoder: Option<&Tensor>,
|
|
) -> Result<Tensor> {
|
|
let stoch_layer_coeff = 1.0f64;
|
|
let residual = xs.clone();
|
|
let mut xs = if self.normalize_before {
|
|
self.norm1.forward(xs)?
|
|
} else {
|
|
xs.clone()
|
|
};
|
|
if self.concat_linear.is_some() {
|
|
let attn =
|
|
self.self_attn
|
|
.forward(&xs, mask, mask_shfit_chunk, mask_att_chunk_encoder)?;
|
|
let x_concat = Tensor::cat(&[&xs, &attn], D::Minus1)?;
|
|
if self.in_dim == self.hidden_dim {
|
|
let x_concat = self
|
|
.concat_linear
|
|
.as_ref()
|
|
.unwrap()
|
|
.forward(&x_concat)?
|
|
.affine(stoch_layer_coeff, 0.0)?;
|
|
xs = residual.add(&x_concat)?;
|
|
} else {
|
|
xs = self
|
|
.concat_linear
|
|
.as_ref()
|
|
.unwrap()
|
|
.forward(&x_concat)?
|
|
.affine(stoch_layer_coeff, 0.0)?;
|
|
}
|
|
} else if self.in_dim == self.hidden_dim {
|
|
let attn = self
|
|
.self_attn
|
|
.forward(&xs, mask, mask_shfit_chunk, mask_att_chunk_encoder)?
|
|
.affine(stoch_layer_coeff, 0.0)?;
|
|
xs = residual.add(&attn)?;
|
|
} else {
|
|
xs = self
|
|
.self_attn
|
|
.forward(&xs, mask, mask_shfit_chunk, mask_att_chunk_encoder)?
|
|
.affine(stoch_layer_coeff, 0.0)?;
|
|
}
|
|
|
|
if !self.normalize_before {
|
|
xs = self.norm1.forward(&xs)?;
|
|
}
|
|
let residual = xs.clone();
|
|
if self.normalize_before {
|
|
xs = self.norm2.forward(&xs)?;
|
|
}
|
|
xs = self
|
|
.feed_forward
|
|
.forward(&xs)?
|
|
.affine(stoch_layer_coeff, 0.0)?;
|
|
xs = residual.add(&xs)?;
|
|
if !self.normalize_before {
|
|
xs = self.norm2.forward(&xs)?;
|
|
}
|
|
Ok(xs)
|
|
}
|
|
|
|
pub fn forward_simple(&self, xs: &Tensor) -> Result<Tensor> {
|
|
let residual = xs.clone();
|
|
let mut xs = self.norm1.forward(xs)?;
|
|
if self.in_dim == self.hidden_dim {
|
|
let attn = self.self_attn.forward_simple(&xs)?;
|
|
xs = residual.add(&attn)?;
|
|
} else {
|
|
xs = self.self_attn.forward_simple(&xs)?;
|
|
}
|
|
|
|
let residual = xs.clone();
|
|
let xs = self.norm2.forward(&xs)?;
|
|
|
|
let xs = self.feed_forward.forward(&xs)?;
|
|
let xs = residual.add(&xs)?;
|
|
Ok(xs)
|
|
}
|
|
}
|
|
|
|
pub struct SenseVoiceEncoderSmall {
|
|
embed: SinusoidalPositionEncoderCat,
|
|
encoders0: EncoderLayerSANM,
|
|
encoders: Vec<EncoderLayerSANM>,
|
|
tp_encoders: Vec<EncoderLayerSANM>,
|
|
after_norm: LayerNorm,
|
|
tp_norm: LayerNorm,
|
|
scaling: f64,
|
|
}
|
|
|
|
impl SenseVoiceEncoderSmall {
|
|
pub fn new(
|
|
vb: VarBuilder,
|
|
input_size: usize,
|
|
output_size: usize,
|
|
attention_heads: usize,
|
|
linear_units: usize,
|
|
num_blocks: usize,
|
|
tp_blocks: usize,
|
|
normalize_before: bool,
|
|
kernel_size: usize,
|
|
sanm_shfit: usize,
|
|
) -> Result<Self> {
|
|
let embed = SinusoidalPositionEncoderCat::new(Some(input_size), true, vb.device())?;
|
|
|
|
let encoders0 = EncoderLayerSANM::new(
|
|
vb.pp("encoders0.0"),
|
|
input_size,
|
|
output_size,
|
|
attention_heads,
|
|
kernel_size,
|
|
sanm_shfit,
|
|
linear_units,
|
|
normalize_before,
|
|
false,
|
|
)?;
|
|
let mut encoders = vec![];
|
|
let vb_encoders = vb.pp("encoders");
|
|
for i in 0..(num_blocks - 1) {
|
|
let encoder_i = EncoderLayerSANM::new(
|
|
vb_encoders.pp(i),
|
|
output_size,
|
|
output_size,
|
|
attention_heads,
|
|
kernel_size,
|
|
sanm_shfit,
|
|
linear_units,
|
|
normalize_before,
|
|
false,
|
|
)?;
|
|
encoders.push(encoder_i);
|
|
}
|
|
let vb_tp_encoders = vb.pp("tp_encoders");
|
|
let mut tp_encoders = vec![];
|
|
for i in 0..tp_blocks {
|
|
let tp_blocks_i = EncoderLayerSANM::new(
|
|
vb_tp_encoders.pp(i),
|
|
output_size,
|
|
output_size,
|
|
attention_heads,
|
|
kernel_size,
|
|
sanm_shfit,
|
|
linear_units,
|
|
normalize_before,
|
|
false,
|
|
)?;
|
|
tp_encoders.push(tp_blocks_i);
|
|
}
|
|
let after_norm = get_layer_norm(vb.pp("after_norm"), 1e-5, output_size)?;
|
|
let tp_norm = get_layer_norm(vb.pp("tp_norm"), 1e-5, output_size)?;
|
|
let scaling = (output_size as f64).powf(0.5);
|
|
Ok(Self {
|
|
embed,
|
|
encoders0,
|
|
encoders,
|
|
tp_encoders,
|
|
after_norm,
|
|
tp_norm,
|
|
scaling,
|
|
})
|
|
}
|
|
pub fn forward(&self, xs: &Tensor) -> Result<Tensor> {
|
|
let xs = xs.affine(self.scaling, 0.0)?;
|
|
let xs = self.embed.forward(&xs, 0)?;
|
|
let mut xs = self.encoders0.forward_simple(&xs)?;
|
|
for encoder_layer in &self.encoders {
|
|
xs = encoder_layer.forward_simple(&xs)?;
|
|
}
|
|
xs = self.after_norm.forward(&xs)?;
|
|
for tp_layer in &self.tp_encoders {
|
|
xs = tp_layer.forward_simple(&xs)?;
|
|
}
|
|
xs = self.tp_norm.forward(&xs)?;
|
|
Ok(xs)
|
|
}
|
|
}
|
|
|
|
pub struct AdaptorEncoderLayer {
|
|
self_attn: NaiveAttention,
|
|
feed_forward: TwoLinearMLP,
|
|
norm1: LayerNorm,
|
|
norm2: LayerNorm,
|
|
concat_linear: Option<Linear>,
|
|
normalize_before: bool,
|
|
}
|
|
|
|
impl AdaptorEncoderLayer {
|
|
pub fn new(
|
|
vb: VarBuilder,
|
|
llm_dim: usize,
|
|
n_head: usize,
|
|
normalize_before: bool,
|
|
concat_after: bool,
|
|
) -> Result<Self> {
|
|
let self_attn = NaiveAttention::new(
|
|
vb.pp("self_attn"),
|
|
llm_dim,
|
|
n_head,
|
|
n_head,
|
|
None,
|
|
true,
|
|
Some("linear_q"),
|
|
Some("linear_k"),
|
|
Some("linear_v"),
|
|
Some("linear_out"),
|
|
)?;
|
|
let feed_forward = TwoLinearMLP::new(
|
|
vb.pp("feed_forward"),
|
|
llm_dim,
|
|
llm_dim / 4,
|
|
llm_dim,
|
|
candle_nn::Activation::Relu,
|
|
true,
|
|
"w_1",
|
|
"w_2",
|
|
)?;
|
|
let norm1 = get_layer_norm(vb.pp("norm1"), 1e-5, llm_dim)?;
|
|
let norm2 = get_layer_norm(vb.pp("norm2"), 1e-5, llm_dim)?;
|
|
let concat_linear = if concat_after {
|
|
let lin = linear(llm_dim * 2, llm_dim, vb.pp("concat_linear"))?;
|
|
Some(lin)
|
|
} else {
|
|
None
|
|
};
|
|
Ok(Self {
|
|
self_attn,
|
|
feed_forward,
|
|
norm1,
|
|
norm2,
|
|
concat_linear,
|
|
normalize_before,
|
|
})
|
|
}
|
|
|
|
pub fn forward(&self, xs: &Tensor, mask: Option<&Tensor>) -> Result<Tensor> {
|
|
let stoch_layer_coeff = 1.0f64;
|
|
let residual = xs.clone();
|
|
let mut xs = if self.normalize_before {
|
|
self.norm1.forward(xs)?
|
|
} else {
|
|
xs.clone()
|
|
};
|
|
if self.concat_linear.is_some() {
|
|
let attn = self.self_attn.forward(&xs, None, None, mask, false)?;
|
|
let x_concat = Tensor::cat(&[&xs, &attn], D::Minus1)?;
|
|
let x_concat = self
|
|
.concat_linear
|
|
.as_ref()
|
|
.unwrap()
|
|
.forward(&x_concat)?
|
|
.affine(stoch_layer_coeff, 0.0)?;
|
|
xs = residual.add(&x_concat)?;
|
|
} else {
|
|
let attn = self
|
|
.self_attn
|
|
.forward(&xs, None, None, mask, false)?
|
|
.affine(stoch_layer_coeff, 0.0)?;
|
|
xs = residual.add(&attn)?;
|
|
}
|
|
if !self.normalize_before {
|
|
xs = self.norm1.forward(&xs)?;
|
|
}
|
|
let residual = xs.clone();
|
|
if self.normalize_before {
|
|
xs = self.norm2.forward(&xs)?;
|
|
}
|
|
xs = self
|
|
.feed_forward
|
|
.forward(&xs)?
|
|
.affine(stoch_layer_coeff, 0.0)?;
|
|
xs = residual.add(&xs)?;
|
|
if !self.normalize_before {
|
|
xs = self.norm2.forward(&xs)?;
|
|
}
|
|
Ok(xs)
|
|
}
|
|
}
|
|
|
|
pub struct AudioAdaptor {
|
|
k: usize,
|
|
linear1: Linear,
|
|
linear2: Linear,
|
|
blocks: Vec<AdaptorEncoderLayer>,
|
|
}
|
|
|
|
impl AudioAdaptor {
|
|
pub fn new(
|
|
vb: VarBuilder,
|
|
downsample_rate: usize,
|
|
encoder_dim: usize,
|
|
llm_dim: usize,
|
|
ffn_dim: usize,
|
|
n_layer: usize,
|
|
attention_heads: usize,
|
|
) -> Result<Self> {
|
|
let linear1 = linear(encoder_dim * downsample_rate, ffn_dim, vb.pp("linear1"))?;
|
|
let linear2 = linear(ffn_dim, llm_dim, vb.pp("linear2"))?;
|
|
let mut blocks = vec![];
|
|
let vb_blocks = vb.pp("blocks");
|
|
for i in 0..n_layer {
|
|
let layer =
|
|
AdaptorEncoderLayer::new(vb_blocks.pp(i), llm_dim, attention_heads, true, false)?;
|
|
blocks.push(layer);
|
|
}
|
|
Ok(Self {
|
|
k: downsample_rate,
|
|
linear1,
|
|
linear2,
|
|
blocks,
|
|
})
|
|
}
|
|
pub fn forward(&self, xs: &Tensor) -> Result<Tensor> {
|
|
let (bs, seq_len, dim) = xs.dims3()?;
|
|
let chunk_num = (seq_len - 1) / self.k + 1;
|
|
let pad_num = chunk_num * self.k - seq_len;
|
|
let xs = xs.pad_with_zeros(1, 0, pad_num)?;
|
|
let xs = xs.contiguous()?.reshape((bs, chunk_num, dim * self.k))?;
|
|
let xs = self.linear1.forward(&xs)?.relu()?;
|
|
let mut xs = self.linear2.forward(&xs)?;
|
|
for block in &self.blocks {
|
|
xs = block.forward(&xs, None)?;
|
|
}
|
|
Ok(xs)
|
|
}
|
|
}
|
|
|
|
pub struct FunAsrNanoModel {
|
|
audio_encoder: SenseVoiceEncoderSmall,
|
|
audio_adaptor: AudioAdaptor,
|
|
llm: Qwen3Model,
|
|
}
|
|
impl FunAsrNanoModel {
|
|
pub fn new(vb: VarBuilder, config: &FunASRNanoConfig, llm_cfg: &Qwen3Config) -> Result<Self> {
|
|
let input_size = config.frontend_conf.lfr_m * config.frontend_conf.n_mels;
|
|
let audio_encoder = SenseVoiceEncoderSmall::new(
|
|
vb.pp("audio_encoder"),
|
|
input_size,
|
|
config.audio_encoder_conf.output_size,
|
|
config.audio_encoder_conf.attention_heads,
|
|
config.audio_encoder_conf.linear_units,
|
|
config.audio_encoder_conf.num_blocks,
|
|
config.audio_encoder_conf.tp_blocks,
|
|
config.audio_encoder_conf.normalize_before,
|
|
config.audio_encoder_conf.kernel_size,
|
|
config.audio_encoder_conf.sanm_shfit,
|
|
)?;
|
|
let audio_adaptor = AudioAdaptor::new(
|
|
vb.pp("audio_adaptor"),
|
|
config.audio_adaptor_conf.downsample_rate,
|
|
config.audio_adaptor_conf.encoder_dim,
|
|
config.audio_adaptor_conf.llm_dim,
|
|
config.audio_adaptor_conf.ffn_dim,
|
|
config.audio_adaptor_conf.n_layer,
|
|
8,
|
|
)?;
|
|
let llm = Qwen3Model::new(llm_cfg, vb.pp("llm"))?;
|
|
Ok(Self {
|
|
audio_encoder,
|
|
audio_adaptor,
|
|
llm,
|
|
})
|
|
}
|
|
|
|
pub fn forward(
|
|
&mut self,
|
|
input_ids: &Tensor,
|
|
speech: Option<&Tensor>,
|
|
fbank_mask: Option<&Tensor>,
|
|
seqlen_offset: usize,
|
|
) -> Result<Tensor> {
|
|
let mut inputs_embeds = self.llm.embedding_token_id(input_ids)?;
|
|
if let Some(speech) = speech
|
|
&& let Some(fbank_mask) = fbank_mask
|
|
{
|
|
let speech = self.audio_encoder.forward(speech)?;
|
|
let encoder_out = self.audio_adaptor.forward(&speech)?;
|
|
let speech_token_len = fbank_mask.sum_all()?.to_scalar::<u32>()?;
|
|
let audio_embed = encoder_out
|
|
.squeeze(0)?
|
|
.narrow(0, 0, speech_token_len as usize)?;
|
|
inputs_embeds = masked_scatter_dim0(&inputs_embeds, &audio_embed, fbank_mask)?;
|
|
}
|
|
let logits = self
|
|
.llm
|
|
.forward(None, Some(&inputs_embeds), seqlen_offset)?;
|
|
Ok(logits)
|
|
}
|
|
|
|
pub fn clear_kv_cache(&mut self) {
|
|
self.llm.clear_kv_cache();
|
|
}
|
|
}
|