fix(cuda+csm): P0 rtx-backend-cuda compile fix + P2 rtx-csm clippy cleanup (#9)
Co-authored-by: Omar Sobh <[email protected]> Co-committed-by: Omar Sobh <[email protected]>
This commit is contained in:
committed by
redclawsystems
parent
8045ba79d4
commit
6a03aeba61
@@ -49,3 +49,7 @@ path = "src/lib.rs"
|
|||||||
|
|
||||||
[lints]
|
[lints]
|
||||||
workspace = true
|
workspace = true
|
||||||
|
|
||||||
|
[[test]]
|
||||||
|
name = "backend_parity_tests"
|
||||||
|
required-features = ["cuda"]
|
||||||
|
|||||||
@@ -6,6 +6,18 @@
|
|||||||
use cudarc::cublas::CudaBlas;
|
use cudarc::cublas::CudaBlas;
|
||||||
#[cfg(feature = "cuda")]
|
#[cfg(feature = "cuda")]
|
||||||
use cudarc::driver::{CudaContext, CudaStream};
|
use cudarc::driver::{CudaContext, CudaStream};
|
||||||
|
#[cfg(feature = "cuda")]
|
||||||
|
use crate::CudaBackend;
|
||||||
|
#[cfg(feature = "cuda")]
|
||||||
|
use rtx_backend::{DeviceId, DeviceOps};
|
||||||
|
#[cfg(feature = "cuda")]
|
||||||
|
use once_cell::sync::{Lazy, OnceCell};
|
||||||
|
#[cfg(feature = "cuda")]
|
||||||
|
use parking_lot::RwLock;
|
||||||
|
#[cfg(feature = "cuda")]
|
||||||
|
use std::collections::HashMap;
|
||||||
|
#[cfg(feature = "cuda")]
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
use crate::{CudaError, CudaResult};
|
use crate::{CudaError, CudaResult};
|
||||||
|
|
||||||
|
|||||||
@@ -104,6 +104,8 @@ pub use device::CudaDevice;
|
|||||||
pub use error::{CudaError, CudaResult};
|
pub use error::{CudaError, CudaResult};
|
||||||
pub use tensor::CudaTensorPrimitive;
|
pub use tensor::CudaTensorPrimitive;
|
||||||
|
|
||||||
|
#[cfg(feature = "cuda")]
|
||||||
|
use rtx_backend::{Backend, BoolU8, DeviceId, DeviceOps};
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
|
||||||
/// CUDA backend for RustyTorch++.
|
/// CUDA backend for RustyTorch++.
|
||||||
|
|||||||
@@ -5,6 +5,8 @@
|
|||||||
use crate::CudaDevice;
|
use crate::CudaDevice;
|
||||||
#[cfg(feature = "cuda")]
|
#[cfg(feature = "cuda")]
|
||||||
use cudarc::driver::CudaSlice;
|
use cudarc::driver::CudaSlice;
|
||||||
|
#[cfg(feature = "cuda")]
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
#[cfg(feature = "cuda")]
|
#[cfg(feature = "cuda")]
|
||||||
/// CUDA tensor primitive - GPU memory storage for tensors.
|
/// CUDA tensor primitive - GPU memory storage for tensors.
|
||||||
|
|||||||
@@ -448,7 +448,7 @@ impl MsgProcessor {
|
|||||||
debug_assert_eq!(c, self.hidden);
|
debug_assert_eq!(c, self.hidden);
|
||||||
let mut indices = Vec::with_capacity(self.nbits);
|
let mut indices = Vec::with_capacity(self.nbits);
|
||||||
for k in 0..self.nbits {
|
for k in 0..self.nbits {
|
||||||
let bit = ((message >> k) & 1) as u32;
|
let bit = (message >> k) & 1;
|
||||||
indices.push(2 * k as u32 + bit);
|
indices.push(2 * k as u32 + bit);
|
||||||
}
|
}
|
||||||
let idx = Tensor::from_vec(indices, (self.nbits,), device)?;
|
let idx = Tensor::from_vec(indices, (self.nbits,), device)?;
|
||||||
|
|||||||
@@ -923,6 +923,7 @@ impl Model {
|
|||||||
|
|
||||||
self.decoder.clear_kv_cache();
|
self.decoder.clear_kv_cache();
|
||||||
let mut decoder_pos = 0;
|
let mut decoder_pos = 0;
|
||||||
|
#[allow(clippy::needless_range_loop)]
|
||||||
for i in 1..self.config.audio_num_codebooks {
|
for i in 1..self.config.audio_num_codebooks {
|
||||||
let proj_h = curr_h.apply(&self.projection)?;
|
let proj_h = curr_h.apply(&self.projection)?;
|
||||||
let decoder_h = self.decoder.forward(&proj_h, decoder_pos)?;
|
let decoder_h = self.decoder.forward(&proj_h, decoder_pos)?;
|
||||||
@@ -1019,6 +1020,7 @@ impl Model {
|
|||||||
let mut curr_h = Tensor::cat(&[h, c0_embed], 1)?;
|
let mut curr_h = Tensor::cat(&[h, c0_embed], 1)?;
|
||||||
self.decoder.clear_kv_cache();
|
self.decoder.clear_kv_cache();
|
||||||
let mut decoder_pos = 0usize;
|
let mut decoder_pos = 0usize;
|
||||||
|
#[allow(clippy::needless_range_loop)]
|
||||||
for i in 1..self.config.audio_num_codebooks {
|
for i in 1..self.config.audio_num_codebooks {
|
||||||
let proj_h = curr_h.apply(&self.projection)?;
|
let proj_h = curr_h.apply(&self.projection)?;
|
||||||
let decoder_h = self.decoder.forward(&proj_h, decoder_pos)?;
|
let decoder_h = self.decoder.forward(&proj_h, decoder_pos)?;
|
||||||
@@ -1054,6 +1056,7 @@ impl Model {
|
|||||||
/// respectively).
|
/// respectively).
|
||||||
///
|
///
|
||||||
/// Reference: Koel-TTS (NVIDIA, arXiv 2502.05236), `cfg_scale ∈ [1.5, 3.0]`.
|
/// Reference: Koel-TTS (NVIDIA, arXiv 2502.05236), `cfg_scale ∈ [1.5, 3.0]`.
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub fn generate_frame_cfg(
|
pub fn generate_frame_cfg(
|
||||||
&mut self,
|
&mut self,
|
||||||
cond_tokens: &Tensor,
|
cond_tokens: &Tensor,
|
||||||
|
|||||||
@@ -406,9 +406,9 @@ impl Layer {
|
|||||||
let xs = xs.apply(&self.mlp_norm)?.apply(&self.mlp)?;
|
let xs = xs.apply(&self.mlp_norm)?.apply(&self.mlp)?;
|
||||||
let out = (residual + xs)?;
|
let out = (residual + xs)?;
|
||||||
// Optional layer-by-layer dump for qmatmul bisection.
|
// Optional layer-by-layer dump for qmatmul bisection.
|
||||||
if std::env::var("CSM_DUMP_LAYERS").is_ok() {
|
if std::env::var("CSM_DUMP_LAYERS").is_ok()
|
||||||
if let Some(idx) = dbg_idx {
|
&& let Some(idx) = dbg_idx
|
||||||
if seqlen_offset == 0 {
|
&& seqlen_offset == 0 {
|
||||||
let f = out.flatten_all()?.to_vec1::<f32>().unwrap_or_default();
|
let f = out.flatten_all()?.to_vec1::<f32>().unwrap_or_default();
|
||||||
let n: f32 = f.iter().map(|x| x * x).sum::<f32>().sqrt();
|
let n: f32 = f.iter().map(|x| x * x).sum::<f32>().sqrt();
|
||||||
eprintln!(
|
eprintln!(
|
||||||
@@ -419,8 +419,6 @@ impl Layer {
|
|||||||
&f[..8.min(f.len())]
|
&f[..8.min(f.len())]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(out)
|
Ok(out)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -761,6 +759,7 @@ impl Model {
|
|||||||
self.run_decoder(h, c0_sample, lp)
|
self.run_decoder(h, c0_sample, lp)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub fn generate_frame_cfg(
|
pub fn generate_frame_cfg(
|
||||||
&mut self,
|
&mut self,
|
||||||
cond_tokens: &Tensor,
|
cond_tokens: &Tensor,
|
||||||
|
|||||||
@@ -231,12 +231,9 @@ fn vad_intervals(probs: &[f32], cfg: &DiarizationConfig) -> Vec<(usize, usize)>
|
|||||||
let mut last_speech: Option<usize> = None;
|
let mut last_speech: Option<usize> = None;
|
||||||
for i in 0..active.len() {
|
for i in 0..active.len() {
|
||||||
if active[i] {
|
if active[i] {
|
||||||
if let Some(prev) = last_speech {
|
if let Some(prev) = last_speech
|
||||||
if i - prev <= max_silence_chunks + 1 {
|
&& i - prev <= max_silence_chunks + 1 {
|
||||||
for j in (prev + 1)..i {
|
active[(prev + 1)..i].fill(true);
|
||||||
active[j] = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
last_speech = Some(i);
|
last_speech = Some(i);
|
||||||
}
|
}
|
||||||
@@ -308,11 +305,10 @@ fn agglomerative_cluster(
|
|||||||
if clusters.len() == 1 {
|
if clusters.len() == 1 {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if let Some(k) = n_speakers {
|
if let Some(k) = n_speakers
|
||||||
if clusters.len() <= k {
|
&& clusters.len() <= k {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
// Find the closest pair using average linkage.
|
// Find the closest pair using average linkage.
|
||||||
let mut best: Option<(usize, usize, f32)> = None;
|
let mut best: Option<(usize, usize, f32)> = None;
|
||||||
for i in 0..clusters.len() {
|
for i in 0..clusters.len() {
|
||||||
|
|||||||
@@ -504,7 +504,7 @@ impl RelativePositionalEncoder {
|
|||||||
groups: usize,
|
groups: usize,
|
||||||
vb: VarBuilder,
|
vb: VarBuilder,
|
||||||
) -> CsmResult<Self> {
|
) -> CsmResult<Self> {
|
||||||
if kernel % 2 == 0 {
|
if kernel.is_multiple_of(2) {
|
||||||
return Err(crate::CsmError::Config(format!(
|
return Err(crate::CsmError::Config(format!(
|
||||||
"relative_positional_encoder kernel must be odd for same-padding, got {kernel}"
|
"relative_positional_encoder kernel must be odd for same-padding, got {kernel}"
|
||||||
)));
|
)));
|
||||||
|
|||||||
@@ -392,14 +392,13 @@ impl Generator {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(g) = rep_guard.as_mut() {
|
if let Some(g) = rep_guard.as_mut()
|
||||||
if g.observe(&sampled) {
|
&& g.observe(&sampled) {
|
||||||
tracing::warn!(
|
tracing::warn!(
|
||||||
"loop-escape: repetition guard tripped at frame {frame_idx}; ending generation"
|
"loop-escape: repetition guard tripped at frame {frame_idx}; ending generation"
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
all_frames.push(sampled.clone());
|
all_frames.push(sampled.clone());
|
||||||
|
|
||||||
@@ -502,14 +501,13 @@ impl Generator {
|
|||||||
tracing::info!("EOT detected at frame {frame_idx}");
|
tracing::info!("EOT detected at frame {frame_idx}");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if let Some(g) = rep_guard.as_mut() {
|
if let Some(g) = rep_guard.as_mut()
|
||||||
if g.observe(&sampled) {
|
&& g.observe(&sampled) {
|
||||||
tracing::warn!(
|
tracing::warn!(
|
||||||
"loop-escape: repetition guard tripped at frame {frame_idx}; ending"
|
"loop-escape: repetition guard tripped at frame {frame_idx}; ending"
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pending.push(sampled.clone());
|
pending.push(sampled.clone());
|
||||||
|
|
||||||
@@ -541,12 +539,11 @@ impl Generator {
|
|||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
// Drain any internal Mimi buffering by feeding a `None` step.
|
// Drain any internal Mimi buffering by feeding a `None` step.
|
||||||
if let Some(tail) = self.mimi.decode_step(None)? {
|
if let Some(tail) = self.mimi.decode_step(None)?
|
||||||
if !tail.is_empty() {
|
&& !tail.is_empty() {
|
||||||
on_chunk(&tail)?;
|
on_chunk(&tail)?;
|
||||||
full_pcm.extend_from_slice(&tail);
|
full_pcm.extend_from_slice(&tail);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
tracing::info!(
|
tracing::info!(
|
||||||
"streaming generation finished: {} samples (~{:.2}s)",
|
"streaming generation finished: {} samples (~{:.2}s)",
|
||||||
@@ -630,12 +627,11 @@ where
|
|||||||
}
|
}
|
||||||
let codes = Tensor::from_vec(flat, (1, num_codebooks, k), device)?.to_dtype(DType::U32)?;
|
let codes = Tensor::from_vec(flat, (1, num_codebooks, k), device)?.to_dtype(DType::U32)?;
|
||||||
pending.clear();
|
pending.clear();
|
||||||
if let Some(samples) = mimi.decode_step(Some(&codes))? {
|
if let Some(samples) = mimi.decode_step(Some(&codes))?
|
||||||
if !samples.is_empty() {
|
&& !samples.is_empty() {
|
||||||
on_chunk(&samples)?;
|
on_chunk(&samples)?;
|
||||||
full_pcm.extend_from_slice(&samples);
|
full_pcm.extend_from_slice(&samples);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -239,13 +239,12 @@ impl LlmClient for OpenAiCompatibleClient {
|
|||||||
// default case so this is a no-op.
|
// default case so this is a no-op.
|
||||||
let mut body = serde_json::to_value(&req)
|
let mut body = serde_json::to_value(&req)
|
||||||
.map_err(|e| CsmError::Config(format!("LLM serialize: {e}")))?;
|
.map_err(|e| CsmError::Config(format!("LLM serialize: {e}")))?;
|
||||||
if !config.extra_body.is_empty() {
|
if !config.extra_body.is_empty()
|
||||||
if let Some(obj) = body.as_object_mut() {
|
&& let Some(obj) = body.as_object_mut() {
|
||||||
for (k, v) in config.extra_body.iter() {
|
for (k, v) in config.extra_body.iter() {
|
||||||
obj.insert(k.clone(), v.clone());
|
obj.insert(k.clone(), v.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
let response = self
|
let response = self
|
||||||
.http
|
.http
|
||||||
.post(&url)
|
.post(&url)
|
||||||
|
|||||||
@@ -106,9 +106,9 @@ fn split_on_sentence_boundaries(text: &str) -> Vec<String> {
|
|||||||
|
|
||||||
impl Generator {
|
impl Generator {
|
||||||
/// Generate audio for arbitrarily long text by chunking on sentence
|
/// Generate audio for arbitrarily long text by chunking on sentence
|
||||||
/// boundaries with a rolling context. The previous generated chunk's audio
|
/// boundaries with a rolling context. The previous generated chunk's
|
||||||
/// + transcript becomes context for the next call. Returns the full
|
/// audio + transcript becomes context for the next call. Returns the
|
||||||
/// concatenated PCM.
|
/// full concatenated PCM.
|
||||||
pub fn generate_long(
|
pub fn generate_long(
|
||||||
&mut self,
|
&mut self,
|
||||||
text: &str,
|
text: &str,
|
||||||
@@ -185,6 +185,7 @@ impl Generator {
|
|||||||
///
|
///
|
||||||
/// Order matches `generate_to_wav` exactly so installing a watermarker
|
/// Order matches `generate_to_wav` exactly so installing a watermarker
|
||||||
/// applies uniformly to short-form and long-form output.
|
/// applies uniformly to short-form and long-form output.
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub fn generate_long_to_wav(
|
pub fn generate_long_to_wav(
|
||||||
&mut self,
|
&mut self,
|
||||||
text: &str,
|
text: &str,
|
||||||
|
|||||||
@@ -78,6 +78,7 @@ pub struct LoraDelta {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl LoraDelta {
|
impl LoraDelta {
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub fn new(
|
pub fn new(
|
||||||
rank: usize,
|
rank: usize,
|
||||||
alpha: f64,
|
alpha: f64,
|
||||||
@@ -169,6 +170,7 @@ impl LoraLinear {
|
|||||||
/// Wrap an existing frozen `Linear` with a trainable rank-r LoRA adapter.
|
/// Wrap an existing frozen `Linear` with a trainable rank-r LoRA adapter.
|
||||||
/// The A/B params get registered into `vm` under `<prefix>.lora_a` /
|
/// The A/B params get registered into `vm` under `<prefix>.lora_a` /
|
||||||
/// `<prefix>.lora_b` so AdamW (or any optimizer) can find and update them.
|
/// `<prefix>.lora_b` so AdamW (or any optimizer) can find and update them.
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub fn wrap(
|
pub fn wrap(
|
||||||
base: Linear,
|
base: Linear,
|
||||||
rank: usize,
|
rank: usize,
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ impl ModelBackend {
|
|||||||
Self::Quantized(m) => m.generate_frame(tokens, mask, input_pos, lp),
|
Self::Quantized(m) => m.generate_frame(tokens, mask, input_pos, lp),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub fn generate_frame_cfg(
|
pub fn generate_frame_cfg(
|
||||||
&mut self,
|
&mut self,
|
||||||
cond_tokens: &Tensor,
|
cond_tokens: &Tensor,
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ impl MoonshineConfig {
|
|||||||
pub fn padded_head_dim(&self, num_heads: usize) -> usize {
|
pub fn padded_head_dim(&self, num_heads: usize) -> usize {
|
||||||
let raw = self.hidden_size / num_heads;
|
let raw = self.hidden_size / num_heads;
|
||||||
let pad = self.pad_head_dim_to_multiple_of;
|
let pad = self.pad_head_dim_to_multiple_of;
|
||||||
((raw + pad - 1) / pad) * pad
|
raw.div_ceil(pad) * pad
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -191,7 +191,7 @@ struct RotaryCache {
|
|||||||
|
|
||||||
impl RotaryCache {
|
impl RotaryCache {
|
||||||
fn new(rotary_dim: usize, max_seq: usize, theta: f64, dtype: DType, dev: &Device) -> Result<Self> {
|
fn new(rotary_dim: usize, max_seq: usize, theta: f64, dtype: DType, dev: &Device) -> Result<Self> {
|
||||||
assert!(rotary_dim % 2 == 0, "rotary_dim must be even");
|
assert!(rotary_dim.is_multiple_of(2), "rotary_dim must be even");
|
||||||
let inv_freq: Vec<f32> = (0..rotary_dim)
|
let inv_freq: Vec<f32> = (0..rotary_dim)
|
||||||
.step_by(2)
|
.step_by(2)
|
||||||
.map(|i| (1.0 / theta.powf(i as f64 / rotary_dim as f64)) as f32)
|
.map(|i| (1.0 / theta.powf(i as f64 / rotary_dim as f64)) as f32)
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ impl PostProcess {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn apply(&self, samples: &mut Vec<f32>, sample_rate: u32) -> Result<()> {
|
pub fn apply(&self, samples: &mut [f32], sample_rate: u32) -> Result<()> {
|
||||||
if samples.is_empty() {
|
if samples.is_empty() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,8 +2,10 @@
|
|||||||
//! that CSM's dual-transformer expects.
|
//! that CSM's dual-transformer expects.
|
||||||
//!
|
//!
|
||||||
//! Slot layout per row of the (S, cb+1) tensor:
|
//! Slot layout per row of the (S, cb+1) tensor:
|
||||||
|
//!
|
||||||
//! - slots [0..cb): per-codebook audio token id (or 0 if unused)
|
//! - slots [0..cb): per-codebook audio token id (or 0 if unused)
|
||||||
//! - slot cb: Llama text token id (or 0 if unused)
|
//! - slot cb: Llama text token id (or 0 if unused)
|
||||||
|
//!
|
||||||
//! The mask (S, cb+1) u8 says which slots actually carry data.
|
//! The mask (S, cb+1) u8 says which slots actually carry data.
|
||||||
//!
|
//!
|
||||||
//! We delegate per-step tensor construction to candle's
|
//! We delegate per-step tensor construction to candle's
|
||||||
|
|||||||
@@ -178,11 +178,10 @@ impl ProsodyDetector {
|
|||||||
min_lag,
|
min_lag,
|
||||||
max_lag,
|
max_lag,
|
||||||
self.voiced_threshold,
|
self.voiced_threshold,
|
||||||
) {
|
)
|
||||||
if voiced && f0 >= self.min_f0_hz && f0 <= self.max_f0_hz {
|
&& voiced && f0 >= self.min_f0_hz && f0 <= self.max_f0_hz {
|
||||||
voiced_f0s.push(f0);
|
voiced_f0s.push(f0);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
total_frames += 1;
|
total_frames += 1;
|
||||||
t += self.hop_samples;
|
t += self.hop_samples;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -516,7 +516,7 @@ pub fn vb_from_ckpt(
|
|||||||
|
|
||||||
/// VCTK average power baseline used by the original to pre-condition
|
/// VCTK average power baseline used by the original to pre-condition
|
||||||
/// audio energy before watermarking. Source: `server.py:60` constant.
|
/// audio energy before watermarking. Source: `server.py:60` constant.
|
||||||
const AVERAGE_ENERGY_VCTK: f32 = 0.002837200844477648;
|
const AVERAGE_ENERGY_VCTK: f32 = 0.002_837_200_9;
|
||||||
|
|
||||||
/// SilentCipher watermarker holding all three networks + an STFT
|
/// SilentCipher watermarker holding all three networks + an STFT
|
||||||
/// helper. Loads from the three released `.ckpt` files (`enc_c`,
|
/// helper. Loads from the three released `.ckpt` files (`enc_c`,
|
||||||
|
|||||||
@@ -290,7 +290,7 @@ impl SileroVad {
|
|||||||
padded.extend_from_slice(samples);
|
padded.extend_from_slice(samples);
|
||||||
// Tail-pad to whole-chunk multiple.
|
// Tail-pad to whole-chunk multiple.
|
||||||
let extra = (CHUNK_SAMPLES - (samples.len() % CHUNK_SAMPLES)) % CHUNK_SAMPLES;
|
let extra = (CHUNK_SAMPLES - (samples.len() % CHUNK_SAMPLES)) % CHUNK_SAMPLES;
|
||||||
padded.extend(std::iter::repeat(0.0).take(extra));
|
padded.extend(std::iter::repeat_n(0.0, extra));
|
||||||
|
|
||||||
let mut probs = Vec::new();
|
let mut probs = Vec::new();
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
|
|||||||
@@ -385,7 +385,7 @@ impl<'a> Trainer<'a> {
|
|||||||
self.generator.model.inner.refresh_lora(self.vm)?;
|
self.generator.model.inner.refresh_lora(self.vm)?;
|
||||||
|
|
||||||
step += 1;
|
step += 1;
|
||||||
if step % 10 == 0 || step == total_steps - 1 {
|
if step.is_multiple_of(10) || step == total_steps - 1 {
|
||||||
tracing::info!(
|
tracing::info!(
|
||||||
" step {step:>4}/{total_steps} epoch {epoch} ex {idx} frame {frame_idx} \
|
" step {step:>4}/{total_steps} epoch {epoch} ex {idx} frame {frame_idx} \
|
||||||
prompt_len={prompt_len} lr={lr:.2e} loss={loss_val:.4}"
|
prompt_len={prompt_len} lr={lr:.2e} loss={loss_val:.4}"
|
||||||
@@ -407,9 +407,11 @@ impl<'a> Trainer<'a> {
|
|||||||
/// - any other string matches `ex.stage == Some(label)` exactly
|
/// - any other string matches `ex.stage == Some(label)` exactly
|
||||||
///
|
///
|
||||||
/// Per `personal_voice_training_guide.md` §4 the canonical 3-stage recipe is:
|
/// Per `personal_voice_training_guide.md` §4 the canonical 3-stage recipe is:
|
||||||
|
///
|
||||||
/// - audiobook: 3 epochs, peak_lr 1e-4
|
/// - audiobook: 3 epochs, peak_lr 1e-4
|
||||||
/// - podcast: 1 epoch, peak_lr 3e-5
|
/// - podcast: 1 epoch, peak_lr 3e-5
|
||||||
/// - va: 1 epoch, peak_lr 1e-5
|
/// - va: 1 epoch, peak_lr 1e-5
|
||||||
|
///
|
||||||
/// each over a growing pool. The `CurriculumTrainer` enforces the pool growth
|
/// each over a growing pool. The `CurriculumTrainer` enforces the pool growth
|
||||||
/// implicitly by virtue of how you label your manifest (a podcast example
|
/// implicitly by virtue of how you label your manifest (a podcast example
|
||||||
/// labeled `stage: "podcast"` is only matched by the podcast stage; if you
|
/// labeled `stage: "podcast"` is only matched by the podcast stage; if you
|
||||||
|
|||||||
@@ -291,7 +291,7 @@ impl ConvPosEmbedding {
|
|||||||
/// Even kernels need asymmetric handling: pad symmetrically by k/2 and
|
/// Even kernels need asymmetric handling: pad symmetrically by k/2 and
|
||||||
/// trim the trailing extra frame.
|
/// trim the trailing extra frame.
|
||||||
fn pad_for(kernel: usize) -> (usize, bool) {
|
fn pad_for(kernel: usize) -> (usize, bool) {
|
||||||
if kernel % 2 == 0 {
|
if kernel.is_multiple_of(2) {
|
||||||
(kernel / 2, true)
|
(kernel / 2, true)
|
||||||
} else {
|
} else {
|
||||||
((kernel - 1) / 2, false)
|
((kernel - 1) / 2, false)
|
||||||
@@ -595,15 +595,14 @@ pub fn ctc_greedy_decode(logits: &Tensor, vocab: &[&str]) -> CsmResult<String> {
|
|||||||
if id_i == prev {
|
if id_i == prev {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (id as usize) != CTC_BLANK_ID {
|
if (id as usize) != CTC_BLANK_ID
|
||||||
if let Some(tok) = vocab.get(id as usize) {
|
&& let Some(tok) = vocab.get(id as usize) {
|
||||||
if *tok == "|" {
|
if *tok == "|" {
|
||||||
out.push(' ');
|
out.push(' ');
|
||||||
} else if !tok.starts_with('<') {
|
} else if !tok.starts_with('<') {
|
||||||
out.push_str(tok);
|
out.push_str(tok);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
prev = id_i;
|
prev = id_i;
|
||||||
}
|
}
|
||||||
Ok(out)
|
Ok(out)
|
||||||
|
|||||||
@@ -232,7 +232,7 @@ impl Module for PosConv {
|
|||||||
let h = xs_bct.apply(&self.conv)?;
|
let h = xs_bct.apply(&self.conv)?;
|
||||||
// SamePad strips 1 trailing frame because kernel=128 is even.
|
// SamePad strips 1 trailing frame because kernel=128 is even.
|
||||||
let out_len = h.dim(D::Minus1)?;
|
let out_len = h.dim(D::Minus1)?;
|
||||||
let h = if self.kernel % 2 == 0 && out_len > in_len {
|
let h = if self.kernel.is_multiple_of(2) && out_len > in_len {
|
||||||
h.narrow(D::Minus1, 0, in_len)?
|
h.narrow(D::Minus1, 0, in_len)?
|
||||||
} else {
|
} else {
|
||||||
h
|
h
|
||||||
|
|||||||
@@ -79,6 +79,7 @@ fn lev_align(r: &[&str], h: &[&str]) -> (usize, usize, usize) {
|
|||||||
}
|
}
|
||||||
let mut prev = vec![Cell::new(); m + 1];
|
let mut prev = vec![Cell::new(); m + 1];
|
||||||
let mut curr = vec![Cell::new(); m + 1];
|
let mut curr = vec![Cell::new(); m + 1];
|
||||||
|
#[allow(clippy::needless_range_loop)]
|
||||||
for j in 0..=m {
|
for j in 0..=m {
|
||||||
prev[j] = Cell { cost: j, s: 0, d: 0, i: j };
|
prev[j] = Cell { cost: j, s: 0, d: 0, i: j };
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user