o
    Gi,                     @   s   d dl mZ d dlZd dlmZ d dlmZ ddlm	Z	m
Z
 ddlmZ ddlmZmZmZmZmZ eeZejjG d	d
 d
ZeG dd deZG dd dee	ZdS )    )	dataclassN)	integrate   )ConfigMixinregister_to_config)logging   )CommonSchedulerStateFlaxKarrasDiffusionSchedulersFlaxSchedulerMixinFlaxSchedulerOutputbroadcast_to_shape_from_leftc                	   @   sv   e Zd ZU eed< ejed< ejed< ejed< dZeed< dZ	ejdB ed< e
dedejdejdejfdd	ZdS )
LMSDiscreteSchedulerStatecommoninit_noise_sigma	timestepssigmasNnum_inference_stepsderivativesc                 C   s   | ||||dS )Nr   r   r   r    )clsr   r   r   r   r   r   e/home/ubuntu/.local/lib/python3.10/site-packages/diffusers/schedulers/scheduling_lms_discrete_flax.pycreate0   s   z LMSDiscreteSchedulerState.create)__name__
__module____qualname__r	   __annotations__jnpndarrayr   intr   classmethodr   r   r   r   r   r   #   s"   
 


r   c                   @   s   e Zd ZU eed< dS )FlaxLMSSchedulerOutputstateN)r   r   r   r   r   r   r   r   r   r"   @   s   
 r"   c                   @   s>  e Zd ZU dZdd eD Zejed< e	dd Z
eddd	d
ddejfdededededejdB dedejfddZd3dedB defddZdedejdedejfddZdefddZ	 d4ded!ed"edefd#d$Z	%	&d5ded'ejdedejd(ed)edeeB fd*d+Zded,ejd-ejd.ejdejf
d/d0Zd1d2 ZdS )6FlaxLMSDiscreteSchedulera  
    Linear Multistep Scheduler for discrete beta schedules. Based on the original k-diffusion implementation by
    Katherine Crowson:
    https://github.com/crowsonkb/k-diffusion/blob/481677d114f6ea445aa009cf5bd7a9cdee909e47/k_diffusion/sampling.py#L181

    [`~ConfigMixin`] takes care of storing all config attributes that are passed in the scheduler's `__init__`
    function, such as `num_train_timesteps`. They can be accessed via `scheduler.config.num_train_timesteps`.
    [`SchedulerMixin`] provides general loading and saving functionality via the [`SchedulerMixin.save_pretrained`] and
    [`~SchedulerMixin.from_pretrained`] functions.

    Args:
        num_train_timesteps (`int`): number of diffusion steps used to train the model.
        beta_start (`float`): the starting `beta` value of inference.
        beta_end (`float`): the final `beta` value.
        beta_schedule (`str`):
            the beta schedule, a mapping from a beta range to a sequence of betas for stepping the model. Choose from
            `linear` or `scaled_linear`.
        trained_betas (`jnp.ndarray`, optional):
            option to pass an array of betas directly to the constructor to bypass `beta_start`, `beta_end` etc.
        prediction_type (`str`, default `epsilon`, optional):
            prediction type of the scheduler function, one of `epsilon` (predicting the noise of the diffusion
            process), `sample` (directly predicting the noisy sample`) or `v_prediction` (see section 2.4
            https://huggingface.co/papers/2210.02303)
        dtype (`jnp.dtype`, *optional*, defaults to `jnp.float32`):
            the `dtype` used for params and computation.
    c                 C   s   g | ]}|j qS r   )name).0er   r   r   
<listcomp>a   s    z#FlaxLMSDiscreteScheduler.<listcomp>dtypec                 C   s   dS )NTr   selfr   r   r   	has_statee   s   z"FlaxLMSDiscreteScheduler.has_statei  -C6?g{Gz?linearNepsilonnum_train_timesteps
beta_startbeta_endbeta_scheduletrained_betasprediction_typec                 C   s   t d || _d S )NzFlax classes are deprecated and will be removed in Diffusers v1.0.0. We recommend migrating to PyTorch classes or pinning your version of Diffusers.)loggerwarningr)   )r+   r0   r1   r2   r3   r4   r5   r)   r   r   r   __init__i   s   
z!FlaxLMSDiscreteScheduler.__init__r   returnc                 C   s^   |d u r	t | }td| jj d d d }d|j |j d }| }t	j||||dS )Nr   r         ?r   )
r	   r   r   arangeconfigr0   roundalphas_cumprodmaxr   )r+   r   r   r   r   r   r   r   create_statez   s   
z%FlaxLMSDiscreteScheduler.create_stater#   sampletimestepc                 C   s@   t j|j|kdd\}|d }|j| }||d d d  }|S )a	  
        Scales the denoising model input by `(sigma**2 + 1) ** 0.5` to match the K-LMS algorithm.

        Args:
            state (`LMSDiscreteSchedulerState`):
                the `FlaxLMSDiscreteScheduler` state data class instance.
            sample (`jnp.ndarray`):
                current instance of sample being created by diffusion process.
            timestep (`int`):
                current discrete timestep in the diffusion chain.

        Returns:
            `jnp.ndarray`: scaled input sample
        r   )sizer   r   r;   )r   wherer   r   )r+   r#   rB   rC   
step_indexsigmar   r   r   scale_model_input   s
   
z*FlaxLMSDiscreteScheduler.scale_model_inputc                    s<    fdd}t j|j jd  ddd }|S )z
        Compute a linear multistep coefficient.

        Args:
            order (TODO):
            t (TODO):
            current_order (TODO):
        c                    sR   d}t D ] } |krq|| j|   j   j|    9 }q|S )N      ?)ranger   )tauprodkcurrent_orderorderr#   tr   r   lms_derivative   s   4zDFlaxLMSDiscreteScheduler.get_lms_coefficient.<locals>.lms_derivativer   r-   )epsrelr   )r   quadr   )r+   r#   rP   rQ   rO   rR   integrated_coeffr   rN   r   get_lms_coefficient   s   
&z,FlaxLMSDiscreteScheduler.get_lms_coefficientr   r   shapec           
      C   s   t j| jjd d|| jd}t |t j}t |t j}t 	|d}d|j
j |j
j d }d| ||  |||   }t |t jdg| jdg}|t j}t jd| | jd}	|j||||	dS )	a  
        Sets the timesteps used for the diffusion chain. Supporting function to be run before inference.

        Args:
            state (`LMSDiscreteSchedulerState`):
                the `FlaxLMSDiscreteScheduler` state data class instance.
            num_inference_steps (`int`):
                the number of diffusion steps used when generating samples with a pre-trained model.
        r   r   )r)   rI   r;   g        )r   )r   r   r   r   )r   linspacer=   r0   r)   floorastypeint32ceilmodr   r?   concatenatearrayzerosreplace)
r+   r#   r   rW   r   low_idxhigh_idxfracr   r   r   r   r   set_timesteps   s(   
z&FlaxLMSDiscreteScheduler.set_timesteps   Tmodel_outputrP   return_dictc                    s,  j du r	tdj }jjdkr|||  }n&jjdkr7|| |d d d   ||d d   }n
tdjj d	|| | }	jtj|	d
t	j krdjt
jdd
td    fddt D }
|tdd t|
tjD  }|s|fS t|dS )a  
        Predict the sample at the previous timestep by reversing the SDE. Core function to propagate the diffusion
        process from the learned model outputs (most often the predicted noise).

        Args:
            state (`LMSDiscreteSchedulerState`): the `FlaxLMSDiscreteScheduler` state data class instance.
            model_output (`jnp.ndarray`): direct output from learned diffusion model.
            timestep (`int`): current discrete timestep in the diffusion chain.
            sample (`jnp.ndarray`):
                current instance of sample being created by diffusion process.
            order: coefficient for multi-step inference.
            return_dict (`bool`): option for returning tuple rather than FlaxLMSSchedulerOutput class

        Returns:
            [`FlaxLMSSchedulerOutput`] or `tuple`: [`FlaxLMSSchedulerOutput`] if `return_dict` is True, otherwise a
            `tuple`. When returning a tuple, the first element is the sample tensor.

        NzaNumber of inference steps is 'None', you need to run 'set_timesteps' after creating the schedulerr/   v_predictionr   r   r;   zprediction_type given as z, must be one of `epsilon`, or `v_prediction`)r   r   c                    s   g | ]
}  |qS r   )rV   )r&   
curr_orderrP   r+   r#   rC   r   r   r(     s    z1FlaxLMSDiscreteScheduler.step.<locals>.<listcomp>c                 s   s    | ]	\}}|| V  qd S Nr   )r&   coeff
derivativer   r   r   	<genexpr>  s    
z0FlaxLMSDiscreteScheduler.step.<locals>.<genexpr>)prev_sampler#   )r   
ValueErrorr   r=   r5   ra   r   appendr   lendeleteminrJ   sumzipreversedr"   )r+   r#   rg   rC   rB   rP   rh   rG   pred_original_samplern   
lms_coeffsrp   r   rk   r   step   s0   

,

zFlaxLMSDiscreteScheduler.steporiginal_samplesnoiser   c                 C   s*   |j |  }t||j}|||  }|S rl   )r   flattenr   rW   )r+   r#   r|   r}   r   rG   noisy_samplesr   r   r   	add_noise$  s   z"FlaxLMSDiscreteScheduler.add_noisec                 C   s   | j jS rl   )r=   r0   r*   r   r   r   __len__2  s   z FlaxLMSDiscreteScheduler.__len__rl   )r   )rf   T)r   r   r   __doc__r
   _compatiblesr   r)   r   propertyr,   r   float32r    floatstrr   r8   r	   r   rA   rH   rV   tuplere   boolr"   r{   r   r   r   r   r   r   r$   E   s   
 


2
A
r$   )dataclassesr   flax	jax.numpynumpyr   scipyr   configuration_utilsr   r   utilsr   scheduling_utils_flaxr	   r
   r   r   r   
get_loggerr   r6   structr   r"   r$   r   r   r   r   <module>   s   
	