use ndarray::{Array1, Array4, ArrayBase, ArrayView1, ArrayView4};
use num_traits::ToPrimitive;
use rand::Rng;
cfg_if::cfg_if! {
if #[cfg(feature = "scheduler-lms")] {
mod lms_discrete;
pub use self::lms_discrete::*;
}
}
cfg_if::cfg_if! {
if #[cfg(feature = "scheduler-euler")] {
mod euler_discrete;
pub use self::euler_discrete::*;
}
}
cfg_if::cfg_if! {
if #[cfg(feature = "scheduler-euler-ancestral")] {
mod euler_ancestral_discrete;
pub use self::euler_ancestral_discrete::*;
}
}
cfg_if::cfg_if! {
if #[cfg(feature = "scheduler-ddim")] {
mod ddim;
pub use self::ddim::*;
}
}
cfg_if::cfg_if! {
if #[cfg(feature = "scheduler-ddpm")] {
mod ddpm;
pub use self::ddpm::*;
}
}
cfg_if::cfg_if! {
if #[cfg(feature = "scheduler-dpm-solver")] {
mod dpm_solver_multistep;
pub use self::dpm_solver_multistep::*;
}
}
pub(crate) fn betas_for_alpha_bar(num_diffusion_timesteps: usize, max_beta: f32) -> Array1<f32> {
let alpha_bar = |time_step: usize| f32::cos((time_step as f32 + 0.008) / 1.008 * std::f32::consts::FRAC_PI_2).powi(2);
let mut betas = Vec::with_capacity(num_diffusion_timesteps);
for i in 0..num_diffusion_timesteps {
let t1 = i / num_diffusion_timesteps;
let t2 = (i + 1) / num_diffusion_timesteps;
betas.push((1.0 - alpha_bar(t2) / alpha_bar(t1)).min(max_beta));
}
Array1::from_vec(betas)
}
#[derive(Debug, Clone, PartialEq)]
pub enum BetaSchedule {
Linear,
ScaledLinear,
SquaredcosCapV2,
Sigmoid,
TrainedBetas(Array1<f32>)
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SchedulerPredictionType {
Epsilon,
Sample,
VPrediction
}
#[derive(Clone)]
pub struct SchedulerStepOutput {
pub(crate) prev_sample: Array4<f32>,
pub(crate) pred_original_sample: Option<Array4<f32>>,
pub(crate) prev_sample_mean: Option<Array4<f32>>,
pub(crate) derivative: Option<Array4<f32>>
}
#[doc(hidden)]
impl Default for SchedulerStepOutput {
fn default() -> Self {
Self {
prev_sample: Array4::zeros((1, 1, 1, 1)),
pred_original_sample: None,
prev_sample_mean: None,
derivative: None
}
}
}
impl SchedulerStepOutput {
pub fn prev_sample(&self) -> ArrayView4<'_, f32> {
self.prev_sample.view()
}
pub fn pred_original_sample(&self) -> Option<ArrayView4<'_, f32>> {
self.pred_original_sample.as_ref().map(ArrayBase::view)
}
pub fn prev_sample_mean(&self) -> Option<ArrayView4<'_, f32>> {
self.prev_sample_mean.as_ref().map(ArrayBase::view)
}
pub fn derivative(&self) -> Option<ArrayView4<'_, f32>> {
self.derivative.as_ref().map(ArrayBase::view)
}
}
#[allow(clippy::len_without_is_empty)]
pub trait DiffusionScheduler: Default + Clone {
type TimestepType: Copy + Clone + ToPrimitive;
fn order() -> usize;
fn scale_model_input(&mut self, sample: ArrayView4<'_, f32>, timestep: Self::TimestepType) -> Array4<f32>;
fn set_timesteps(&mut self, num_inference_steps: usize);
fn step<R: Rng + ?Sized>(
&mut self,
model_output: ArrayView4<'_, f32>,
timestep: Self::TimestepType,
sample: ArrayView4<'_, f32>,
rng: &mut R
) -> SchedulerStepOutput;
fn add_noise(&mut self, original_samples: ArrayView4<'_, f32>, noise: ArrayView4<'_, f32>, timestep: Self::TimestepType) -> Array4<f32>;
fn timesteps(&self) -> ArrayView1<'_, Self::TimestepType>;
fn init_noise_sigma(&self) -> f32;
fn len(&self) -> usize;
}
pub trait SchedulerOptimizedDefaults: DiffusionScheduler {
fn stable_diffusion_v1_optimized_default() -> anyhow::Result<Self>
where
Self: Sized;
}