
    +jc                     X   d dl Z d dlZd dlZd dlZd dlZd dlmZ d dlZd dl	m
Z
 d dlmZmZmZ d dlmZ d dlZd dlZd dlZd dlZd dlZd dlmZmZ d dlmZmZ d dlZd dlZd dl Z d dl!m"Z"m#Z# d dl$m%Z% d d	l&m'Z'm(Z(m)Z) d d
lm*Z*  G d dej+        j,                  Z-d8dZ.d9dZ/ G d dej0        j1                  Z2 G d dej        j3                  Z4d Z5	 d:dej        j3        fdZ6	 d;dej3        de7de8ej3                 fdZ9 G d dej:        j;                  Z<d<dZ=d Z>d  Z?d! Z@d" ZAd# ZBd$ ZCd% ZDd& ZEd' ZFd( ZGd) ZHd* ZId+ ZJd, ZK G d- d.e(jL                  ZM G d/ d0e(jL                  ZN G d1 d2e(jL                  ZO G d3 d4e(jL                  ZP G d5 d6e'          ZQdeQfd7ZRdS )=    N)trange)Image	ImageDraw	ImageFont)override)CONDRegularCONDList)argsPerformanceFeature)adaptersadapter_maps)BypassInjectionManager)ComfyExtensionioui)ProgressBarc                   :     e Zd ZdZdd fd
Z	 	 	 	 	 ddZ xZS )TrainGuiderzB
    CFGGuider with modifications for training specific logic
    F
offloadingc                H     t                      j        |i | || _        d S N)super__init__r   )selfr   r
   kwargs	__class__s       8/home/wildlama/comfy/ComfyUI/comfy_extras/nodes_train.pyr   zTrainGuider.__init__"   s*    $)&)))$    Nc
                    t           j                            | j        |j        | j        | j        | j         | j                  \  | _        | _        | _	        t          j                                         | j        j        }
|&t           j                            ||j        |
          }|                    |
          }|                    |
          }|                    |
          }t           j                            | j        |
| j                                                   	 | j                                         |                     |||
|||||||	
  
        }| j                                         n# | j                                         w xY wt           j                            | j        | j	                   | `| `	|S )N)force_full_loadforce_offload)devicedtype)latent_shapes)comfysampler_helpersprepare_samplingmodel_patchershapecondsmodel_optionsr   inner_modelloaded_modelstorchcudaempty_cacheload_deviceprepare_masktosamplerscast_to_load_optionsmodel_dtypepre_runinner_samplecleanupcleanup_models)r   noiselatent_imagesamplersigmasdenoise_maskcallbackdisable_pbarseedr%   r#   outputs               r   outer_samplezTrainGuider.outer_sample&   s    !22"
"$(O 3"o 3   	9$*d&8 	
   #/# 0==ek6 L   #v..6""++vT5G5S5S5U5U 	, 	
 	
 	
	)&&(((&&+ '  F &&((((D&&((((,,TZ9KLLLs   (8E: :F)NNFNN)__name__
__module____qualname____doc__r   rE   __classcell__r   s   @r   r   r      sv          */ % % % % % % % 9 9 9 9 9 9 9 9r   r   c                    i }|                                  D ]\  }}t          t                    rt          ||          }n{t          t          j                  r$|                    d          |k    r|         }n=t          t          t          f          r!t                    |k    rfd|D             }|||<   |S )N	full_sizer   c                      g | ]
}|         S  rP   ).0ivs     r   
<listcomp>z0make_batch_extra_option_dict.<locals>.<listcomp>l   s    +++QAaD+++r   )
items
isinstancedictmake_batch_extra_option_dictr/   Tensorsizelisttuplelen)dindiciesrN   new_dictknewvrS   s         @r   rX   rX   b   s    H		 	 	1a 	,/8yQQQDD5<(( 	, AFF1II$:$:{D%=)) 	,c!ff	.A.A++++(+++DOr    c           
      \   t          | d          r<t          | d          s,t          |           D ]\  }}t          || d|            | S t          | d          rNt          |                                           D ]+\  }}t          |t                    rt          || d|            1t          |t          j                  r|	                                | |<   ct          |t                    rd |j        D             |_        t          |t                    r>t          |j        t          j                  r|j                                        |_        t          |t          t          f          r-t          |          D ]\  }}t          || d| d|            -| S )N__iter__rU   .c                 n    g | ]2}t          |t          j                  r|                                n|3S rP   )rV   r/   rY   detachrQ   ts     r   rT   z%process_cond_list.<locals>.<listcomp>}   s5    [[[q
1el(C(CJ!((***[[[r   )hasattr	enumerateprocess_cond_listr[   rU   rV   rW   r/   rY   cloner	   condr   rh   r\   )r^   prefixindexitemra   rS   s         r   rm   rm   q   s   q* Ega&9&9 E$Q<< 	9 	9KE4dv$7$7$7$78888	G		 EOO 	E 	EDAq!T"" E!!____5555Au|,, 	Ewwyy!Ax(( E[[TUTZ[[[A{++ Eafel33 -V]]__AFAe}-- E#,Q<< E EKE4%dv,C,C,C,CE,C,CDDDDHr   c            	       h    e Zd Zdddddej        dddf	dZd Z	 ddZd	 Zd
 Z	d Z
d Z	 	 	 ddZdS )TrainSamplerN   r   Fc                 <   || _         || _        || _        || _        || _        || _        || _        || _        |	| _        |
| _	        |rt          j                                        nd | _        |
|                     |
           d S d | _        d | _        d | _        d S r   )loss_fn	optimizerloss_callback
batch_sizetotal_stepsgrad_accrC   training_dtypereal_datasetbucket_latentsr/   amp
GradScalergrad_scaler_init_bucket_databucket_offsetsbucket_weights
num_images)r   rw   rx   ry   rz   r|   r{   rC   r}   r~   r   use_grad_scalers               r   r   zTrainSampler.__init__   s     "*$& 	,7C  	 6EN59//111$%"">22222"&D"&D"DOOOr   c                 8   dg| _         g }|D ]U}|                    |j        d                    | j                             | j         d         |j        d         z              V| j         d         | _        t	          j        |t          j                  | _        dS )z3Initialize bucket offsets and weights for sampling.r   r$   N)r   appendr*   r   r/   tensorfloat32r   )r   r   bucket_sizeslats       r   r   zTrainSampler._init_bucket_data   s     c! 	O 	OC	!---&&t':2'>1'MNNNN-b1#l<u}MMMr   Tc
                    |j         j                            |||d          }
|j         j                            t          j        |          t          j        |          |d          }fd|D             |j        d<   t          |||          }t          j        |
j        j	        | j
                  5   ||
                    d          |                    d          fi |}|                     |                                |                                          }d d d            n# 1 swxY w Y   |	rR|| j        z  }| j        -| j                            |                                           n|                                 |S )NFc                      g | ]
}|         S rP   rP   )rQ   rR   ro   s     r   rT   z(TrainSampler.fwd_bwd.<locals>.<listcomp>   s    'B'B'BAQ'B'B'Br   positiverM   r   T)r-   model_samplingnoise_scalingr/   
zeros_liker+   rX   autocastr#   typer}   requires_grad_rw   floatr|   r   scalebackward)r   
model_wrapbatch_sigmasbatch_noisebatch_latentro   r_   
extra_argsdataset_sizebwdxtx0batch_extra_argsx0_predlossbwd_losss        `          r   fwd_bwdzTrainSampler.fwd_bwd   s    #2@@+|U
 
 #2@@\**[))	
 
 (C'B'B'B'B'B'B
$7L
 
 
 ^BIN$2EFFF 	= 	= j!!$''++D11  # G
 <<<<D	= 	= 	= 	= 	= 	= 	= 	= 	= 	= 	= 	= 	= 	= 	=  	$dm+H+ &&x0099;;;;!!###s   7A+D..D25D2c                     fdt          |          D             }t          j        |                              |          S )z)Generate random sigma values for a batch.c                     g | ]E}j         j                            t          j        d                                                     FS )ru   )r-   r   percent_to_sigmar/   randrr   )rQ   _r   s     r   rT   z7TrainSampler._generate_batch_sigmas.<locals>.<listcomp>   sZ     
 
 
  "1BB
4  %%'' 
 
 
r   )ranger/   r   r4   )r   r   rz   r#   r   s    `   r   _generate_batch_sigmasz#TrainSampler._generate_batch_sigmas   sU    
 
 
 
 :&&	
 
 
 |L)),,V444r   c                    t          j        | j        d                                          }| j        |         }|j        d         }	| j        |         t          | j        |	          }
t          j	        |	          d|
         
                                }fd|D             }||                             |          }|                    d|i                              |j                  }|                     ||
|j                  }|                     |||||||| j        d	  	        }| j        r'|                     |                                           |                    |                                d|d	           dS )
z)Execute one training step in bucket mode.ru   r   Nc                     g | ]}|z   S rP   rP   )rQ   idxbucket_offsets     r   rT   z8TrainSampler._train_step_bucket_mode.<locals>.<listcomp>   s    LLLCMC/LLLr   samplesTr   .4f)r   bucket)r/   multinomialr   rr   r   r*   r   minrz   randpermtolistr4   generate_noiser#   r   r   r   ry   set_postfix)r   r   ro   r   noisegenr=   pbar
bucket_idxbucket_latentbucket_sizeactual_batch_sizerelative_indicesabsolute_indicesr   r   r   r   r   s                    @r   _train_step_bucket_modez$TrainSampler._train_step_bucket_mode   s    &t':A>>CCEE
+J7#)!,+J7  == >+667I8I7IJQQSSLLLL;KLLL$%5699,GG--y,.GHHKK
 
 22:?PR^Reff||O  

 

  	,tyy{{+++TYY[["6"6*MMNNNNNr   c                 X   t          j        |          d| j                                                 }t          j        fd|D                       }	|                    d|	i                              |	j                  }
|                     |t          | j        |          |	j                  }| 
                    |||
|	||||d	  	        }| j        r'|                     |                                           |                    d|                                di           dS )zGExecute one training step in standard (non-bucket, non-multi-res) mode.Nc                      g | ]
}|         S rP   rP   )rQ   rR   r=   s     r   rT   z:TrainSampler._train_step_standard_mode.<locals>.<listcomp>  s    #F#F#FLO#F#F#Fr   r   Tr   r   r   )r/   r   rz   r   stackr   r4   r#   r   r   r   ry   rr   r   )r   r   ro   r   r   r=   r   r   r_   r   r   r   r   s        `       r   _train_step_standard_modez&TrainSampler._train_step_standard_mode  s0   >,//0A$/0ABIIKK{#F#F#F#FX#F#F#FGG--y,.GHHKK
 
 22:s4?T`?a?acocvww||  

 

  	,tyy{{+++&TYY[["6"6788888r   c                    t          j        |          d| j                                                 }d}	|D ]}
| j        |
                             |          }|                    d|i                              |j                  }|j        j	        
                    t          j        d                                                    }t          j        |g                              |j                  }|                     ||||||
g||d	  	        }|	|z  }	|	| j        z  t!          |          z  }	| j        -| j                            |	                                           n|	                                 | j        r'|                     |	                                           |                    d|	                                di           dS )	zIExecute one training step in multi-resolution mode (real_dataset is set).Nr   r   r   Fr   r   r   )r/   r   rz   r   r~   r4   r   r#   r-   r   r   r   rr   r   r   r|   r]   r   r   r   ry   r   )r   r   ro   r   r   r=   r   r   r_   
total_lossrq   single_latentr   r   r   s                  r   _train_step_multires_modez&TrainSampler._train_step_multires_mode'  s   >,//0A$/0ABIIKK
 	 	E -e477EEM"11M* b%&&  &5FFJt$$))++  
 !<77::=;OPPL<<   
 
D $JJ$-/#h--?
'"":..779999!!! 	2z00111&Z__%6%6"<"<=>>>>>r   c	           
         t          |j                  |_        |j        d         }	|                    d          }
t          j                                         t          | j                  }t          | j        ddt          j
        j                   x}D ]}t          j                            | j        |dz  z             }| j        |                     ||	||||           n>| j        |                     ||	||||
|           n|                     ||	||||
|           |dz   | j        z  dk    r| j        | j                            | j                   | j        j        D ]H}|d         D ]=}|j        
|j        j                            |j        j                  |j        _        >I| j        9| j                            | j                   | j                                         n| j                                         | j                                          |                    d           t          j                                         t          j!        |          S )	Nr   r   zTraining LoRAg{Gz?)desc	smoothingdisablei  ru   params)"rm   r+   rZ   r/   r0   r1   r   r{   r   r&   utilsPROGRESS_BAR_ENABLEDcomfy_extrasnodes_custom_samplerNoise_RandomNoiserC   r   r   r~   r   r   r|   r   unscale_rx   param_groupsgraddatar4   r$   stepupdate	zero_gradr   )r   r   r?   r   rA   r<   r=   r@   rB   ro   r   ui_pbarr   rR   r   r   params                    r   samplezTrainSampler.sampleK  sp    -Z-=>>

+{{1~~
   d.// $!K<<	   D!	 !	A $8JJ	AH$ H ".,,Zz8Uacghhhh"*..z4XWceqswxxxx..z4XWceqswxxxA&!++#/$--dn===$(N$? O OL!-h!7 O O :-$*/*/*<*<UZ=M*N*N
O #/$))$.999$++----N'')))((***NN1
   ---r   )T)NNF)rF   rG   rH   r/   bfloat16r   r   r   r   r   r   r   r   rP   r   r   rt   rt      s        
 ~## ## ## ##J	N 	N 	N* ( ( ( (T5 5 5!O !O !OF9 9 90"? "? "?V 3. 3. 3. 3. 3. 3.r   rt   c                   0     e Zd Z fdZd Zd Zd Z xZS )BiasDiffc                 V    t                                                       || _        d S r   )r   r   bias)r   r   r   s     r   r   zBiasDiff.__init__  s$    			r   c                 z    |j         }|                    | j                  | j        z                       |          S r   )r$   r4   r   )r   b	org_dtypes      r   __call__zBiasDiff.__call__  s0    G	TY$)+//	:::r   c                 h    | j                                         | j                                         z  S r   )r   nelementelement_sizer   s    r   passive_memory_usagezBiasDiff.passive_memory_usage  s)    y!!##di&<&<&>&>>>r   c                 V    |                      |           |                                 S )N)r#   )r4   r   )r   r#   s     r   move_tozBiasDiff.move_to  s(    v((***r   )rF   rG   rH   r   r   r   r   rJ   rK   s   @r   r   r     se            ; ; ;? ? ?+ + + + + + +r   r   c                 F   d\  }}t          j        d||fd          }t          j        |          }t	          |                                           t          |                                           cfd|                                 D             }d|t          |d         |z            z
  f}t          |dd          d          D ]R\  }}	t          ||dz
  z  |z            }
|t          |	|z            z
  }|	                    ||
|fgdd	
           |
|f}S|S )N)i  i,  RGBwhitec                 &    g | ]}|z
  z
  z  S rP   rP   rQ   lmax_lossmin_losss     r   rT   z#draw_loss_graph.<locals>.<listcomp>  s'    UUUaALX%89UUUr   r   ru   startblue   fillwidth)
r   newr   Drawr   valuesmaxintrl   line)loss_mapstepsr  heightimgdrawscaled_loss
prev_pointrR   r   xyr   r   s               @@r   draw_loss_graphr    s0   ME6
)EE6?G
4
4C>#DX__..//X__5F5F1G1GHhUUUUU8??CTCTUUUKVc+a.6"9:::;J+abb/333  1UQY%'((SV__$		:1v&V1	===V

Jr   modelc                    |g }nt          | d          r|t          | t          j        j        t          j        j        t          j        j        f          s<|                    |            t          j	        d| d| j
        j         d           |S |pd}|                                 D ]\  }}t          ||| d|            |S )NforwardzFound module with forward:  ()rootrf   )rk   rV   r/   nn
ModuleList
Sequential
ModuleDictr   loggingdebugr   rF   named_children*find_all_highest_child_module_with_forward)r  resultname	next_namechilds        r   r!  r!    s     ~			"	" :#UX%8%(:MN, ,  	eWDWWEO<TWWWXXX>6D!0022 Y Y	525&TBWBWIBWBWXXXXMr   ru   depthreturnc           
         |g }|pd}t          | t          j        t          j        t          j        f          }t          | d          o| }|rJ|dz  }||k    r?|                    |            t          j        d| d| d| j	        j
         d           |S |                                 D ]\  }}t          ||||| d	|            |S )
a  
    Find modules at a specific depth level for gradient checkpointing.

    Args:
        model: The model to search
        depth: Target depth level (1 = top-level blocks, 2 = their children, etc.)
        result: Accumulator for results
        current_depth: Current recursion depth
        name: Current module name for logging

    Returns:
        List of modules at the target depth
    Nr  r  ru   zFound module at depth z: r  r  rf   )rV   r  r  r  r  rk   r   r  r  r   rF   r   find_modules_at_depth)	r  r&  r"  current_depthr#  is_containerhas_forwardr$  r%  s	            r   r)  r)    s     ~>6D ebmR]BM%RSSL%++@L0@K E!!MM%   M_5__D__EOD\___```M "0022 Z Z	5eUFMdCXCXYCXCXYYYYMr   c                   ^    e Zd ZdZedej        fd            Zedej        fd            ZdS )OffloadCheckpointFunctiona  
    Gradient checkpointing that works with weight offloading.

    Forward: no_grad -> compute -> weights can be freed
    Backward: enable_grad -> recompute -> backward -> weights can be freed

    For single input, single output modules (Linear, Conv*).
    r  c                     |                      |           || _        t          j                    5   ||          cd d d            S # 1 swxY w Y   d S r   )save_for_backward
forward_fnr/   no_grad)ctxr  r1  s      r   r  z!OffloadCheckpointFunction.forward  s    a   #]__ 	! 	!:a==	! 	! 	! 	! 	! 	! 	! 	! 	! 	! 	! 	! 	! 	! 	! 	! 	! 	!s   AAAgrad_outc                 0   | j         \  }| j        }d | _        t          j                    5  |                                                    d          } ||          }|                    |           |j        }d d d            n# 1 swxY w Y   ~~~|d fS )NT)saved_tensorsr1  r/   enable_gradrh   r   r   r   )r3  r4  r  r1  
x_detachedr  grad_xs          r   r   z"OffloadCheckpointFunction.backward  s    ^
    	% 	%22488J
:&&AJJx   _F		% 	% 	% 	% 	% 	% 	% 	% 	% 	% 	% 	% 	% 	% 	% z:t|s   ABB
B
N)	rF   rG   rH   rI   staticmethodr/   rY   r  r   rP   r   r   r.  r.    sp          ! ! ! ! \!     \  r   r.  Fc                     t          | d          sd S | j        |rBt          | t          j        t          j        t          j        t          j        f          rfd}n
fdfd}| _        || _        d S )Nr  c                 :    t                               |           S r   )r.  apply)r  org_forwards    r   checkpointing_fwdz patch.<locals>.checkpointing_fwd  s    ,221kBBBr   c                      | i |S r   rP   )r
   r   r>  s     r   fwdzpatch.<locals>.fwd  s    ;////r   c                  T    t           j        j                            | |d          S )NF)use_reentrant)r/   r   
checkpoint)r
   r   rA  s     r   r?  z patch.<locals>.checkpointing_fwd  s&    ;)44S$V[4\\\r   )	rk   r  rV   r  LinearConv1dConv2dConv3dr>  )mr   r?  rA  r>  s      @@r   patchrJ     s    1i   )K  	]jRY	29bi$PQQ 	]	C 	C 	C 	C 	C 	C	0 	0 	0 	0 	0	] 	] 	] 	] 	]  AM!AIIIr   c                 F    t          | d          r| j        | _        | `d S d S )Nr>  )rk   r>  r  )rI  s    r   unpatchrL    s0    q-   M	MMM r   c                 J    g }| D ]}|                     |d                    |S )zProcess latents for bucket mode training.

    Args:
        latents: list[{"samples": tensor}] where each tensor is (Bi, C, Hi, Wi)

    Returns:
        list of latent tensors
    r   r   )latentsr   latent_dicts      r   _process_latents_bucket_moderQ    s:     N 6 6k)45555r   c                     t          |           dk    r| d         d         S g }| D ]S}|d         }|j        d         }|dk    r!|D ]}|                    |d                    >|                    |           T|S )zProcess latents for standard (non-bucket) mode training.

    Args:
        latents: list of latent dicts or single latent dict

    Returns:
        Processed latents (tensor or list of tensors)
    ru   r   r   N)r]   r*   r   )rO  latent_listlatentbs
sub_latents        r   _process_latents_standard_moderW  *  s     7||qqz)$$K ' '	"\!_77$ 5 5
"":d#344445 v&&&&r   c                     t          |           dk    r| d         S g }| D ]B}t          |t                    r|                    |           -|                    |           C|S )zProcess conditioning - either single list or list of lists.

    Args:
        positive: list of conditioning

    Returns:
        Flattened conditioning list
    ru   r   )r]   rV   r[   extendr   )r   flat_positivero   s      r   _process_conditioningr[  B  s{     8}}{ M ' 'dD!! 	'  &&&&  &&&&r   c                 B   |rfd| D             } t          |           }t          d | D                       }d}t          j        d| d| d           t	          |           D ]$\  }}t          j        d| d|j                    %| ||fS t          | t                    rt                      }fd	| D             } | D ]}	|	                    |	j                   t          j        d
|            t          |          dk    rd}nd}t          j        | d          } t          |           }ngt          | t          j                  r%|                               } | j        d         }d}n(t          j        dt          |                       d}d}| ||fS )a  Convert latents to dtype and compute image counts.

    Args:
        latents: Latents (tensor, list of tensors, or bucket list)
        dtype: Target dtype
        bucket_mode: Whether bucket mode is enabled

    Returns:
        tuple: (processed_latents, num_images, multi_res)
    c                 :    g | ]}|                               S rP   r4   rQ   rj   r$   s     r   rT   z._prepare_latents_and_count.<locals>.<listcomp>e  #    0001144;;000r   c              3   0   K   | ]}|j         d          V  dS )r   N)r*   ri   s     r   	<genexpr>z-_prepare_latents_and_count.<locals>.<genexpr>g  s(      55555555r   FzBucket mode: z
 buckets, z total samplesz	  Bucket z: shape c                 :    g | ]}|                               S rP   r^  r_  s     r   rT   z._prepare_latents_and_count.<locals>.<listcomp>r  r`  r   zLatent shapes: ru   Tr   )dimzInvalid latents type: )r]   sumr  r  rl   r*   rV   r[   setaddr/   catrY   r4   errorr   )
rO  r$   bucket_modenum_bucketsr   	multi_resrR   r   
all_shapesrT  s
    `        r   _prepare_latents_and_countrn  X  s     
.0000000'll55W55555
	WkWWZWWWXXX(( 	> 	>FAsM<a<<<<====
I-- '4   UU
0000000 	) 	)FNN6<((((4
44555z??QIIIiQ///G\\

	GU\	*	* **U##]1%
		>tG}}>>???
	J	))r   c                    |r| S t          j        d| dt          |                       t          |           dk    r|dk    r| |z  S t          |           |k    r#t          dt          |            d| d          | S )a[  Validate conditioning count matches image count, expand if needed.

    Args:
        positive: Conditioning list
        num_images: Number of images
        bucket_mode: Whether bucket mode is enabled

    Returns:
        Validated/expanded conditioning list

    Raises:
        ValueError: If conditioning count doesn't match image count
    zTotal Images: z, Total Captions: ru   zNumber of positive conditions (z#) does not match number of images (z).)r  r  r]   
ValueError)r   r   rj  s      r   !_validate_and_expand_conditioningrq    s      MP:PPXPPQQQ
8}}j1nn*$$	X*	$	$nc(mmnn`jnnn
 
 	
 Or   c                    | dk    ri dfS t          j        d|           }t          |                     d          d                             d          d                   }i }|rt          j                            |          }||fS )zLoad existing LoRA weights if provided.

    Args:
        existing_lora: LoRA filename or "[None]"

    Returns:
        tuple: (existing_weights dict, existing_steps int)
    [None]r   loras_steps_r   r   )folder_pathsget_full_path_or_raiser  splitr&   r   load_torch_file)existing_lora	lora_pathexisting_stepsexisting_weightss       r   _load_existing_lorar~    s       1u3G]KKI,,Y77:@@EEbIJJN B ;66yAA^++r   c                    | d}| j         j        }i }t          j        d| d|            t	          |          dk    rt          |                    | dd                    }	|                    | dd          }
d}t          D ]}|                    |||	|
          }| n|t          |         }|(|
                                                    |          }n0|                    | j         |d	                              |          }|                                D ]\  }}||| d
| <   |                                                    d          |fS t           j                            t!          j        | j         j        |d                    }t)          |                                                              d          }||| d<   ||fS )a  Create a weight adapter for a module with weight.

    Args:
        module: The module to create adapter for
        module_name: Name of the module
        existing_weights: Dict of existing LoRA weights
        algorithm: Algorithm name for new adapters
        lora_dtype: dtype for LoRA weights
        rank: Rank for new LoRA adapters

    Returns:
        tuple: (train_adapter, lora_params dict)
    .weightzCreating weight adapter for z with shape r   z.alpha      ?z.dora_scaleN)rankalpharf   Tr$   requires_gradz.diff)weightr*   r  r  r]   r   getr   loadr   to_trainr4   create_trainnamed_parameterstrainr   r/   r  	Parameterzerosr   )modulemodule_namer}  	algorithm
lora_dtyper  keyr*   lora_paramsr  
dora_scaleexisting_adapteradapter_clstrain_adapterr#  	parameterdiffdiff_modules                     r   _create_weight_adapterr    s      
!
!
!CMEKMIII%IIJJJ
5zzQ&**c>>>3??@@%))S*=*=*=tDD
  # 	 	K*//-uj     + , #&y1K',5577:::FFMM (44D 5  bnn   -==?? 	= 	=OD)3<K;////00""$$33D99;FF x!!K+:TRRR
 
 tnn**,,;;DAA-1{)))*K''r   c                     t           j                            t          j        | j        j        |d                    }t          |                                                              d          }| d|i}||fS )zCreate a bias adapter for a module with bias.

    Args:
        module: The module with bias
        module_name: Name of the module
        lora_dtype: dtype for LoRA weights

    Returns:
        tuple: (bias_module, lora_params dict)
    Tr  z.diff_b)	r/   r  r  r  r   r*   r   r  r   )r  r  r  r   bias_moduler  s         r   _create_bias_adapterr    sy     8FK%ZtLLL D 4..&&((77==K!***D1K##r   c           	         i }g }| j                                         D ]\  }}t          |d          r|j        \t	          ||||||          \  }	}
|                    |
           | d}|                     ||	           |                    |	           t          |d          r`|j        Yt          |||          \  }}|                    |           | d}|                     ||           |                    |           ||fS )aT  Setup all LoRA adapters on the model.

    Args:
        mp: Model patcher
        existing_weights: Dict of existing LoRA weights
        algorithm: Algorithm name for new adapters
        lora_dtype: dtype for LoRA weights
        rank: Rank for new LoRA adapters

    Returns:
        tuple: (lora_sd dict, all_weight_adapters list)
    weight_functionNr  r   .bias)
r  named_modulesrk   r  r  r   add_weight_wrapperr   r   r  )mpr}  r  r  r  lora_sdall_weight_adaptersnrI  adapterr   r  bias_adapterbias_paramss                 r   _setup_lora_adaptersr    s8    G&&(( 9 911'(( 	9x#"8q*Iz4# # v&&&mmm%%c7333#**7333q&!! 9af&8,@Az,R,R)k{+++kkk%%c<888#**<888'''r   c           	          i }g }t                      }| j                                        D ]]\  }}	t          |	d          rF|	j        t          |	|||||          \  }
}|                    |           |                    |
           | d}t          |
t                    r.| 
                    ||
           t          j        d|            n/|                    ||
d           t          j        d|            t          |	d          rw|	j        pt          |	||          \  }}|                    |           | d	}| 
                    ||           |                    |           t          j        d
|            _|||fS )a  Setup LoRA adapters in bypass mode.

    In bypass mode:
        - Weight adapters (lora/lokr/oft) use bypass injection (forward hook)
        - Bias/norm adapters (BiasDiff) still use weight wrapper (direct modification)

    This is useful when the base model weights are quantized and cannot be
    directly modified.

    Args:
        mp: Model patcher
        existing_weights: Dict of existing LoRA weights
        algorithm: Algorithm name for new adapters
        lora_dtype: dtype for LoRA weights
        rank: Rank for new LoRA adapters

    Returns:
        tuple: (lora_sd dict, all_weight_adapters list, bypass_manager)
    r  Nr  z:[BypassMode] Added 1D weight adapter (weight wrapper) for r  )strengthz/[BypassMode] Added weight adapter (bypass) for r   r  z5[BypassMode] Added bias adapter (weight wrapper) for )r   r  r  rk   r  r  r   r   rV   r   r  r  r  add_adapterr   r  )r  r}  r  r  r  r  r  bypass_managerr  rI  r  r   r  r  r  s                  r   _setup_lora_adapters_bypassr  ,  s   ( G+--N&&(( ] ]11'(( 	]x#"8q*Iz4# # v&&&#**7333mmm gx00 [))#w777M"d_b"d"deeee"..sGc.JJJM"YTW"Y"YZZZq&!! ]af&8,@Az,R,R)k{+++kkk%%c<888#**<888[VY[[\\\'77r   c                 >   | dk    r!t           j                            ||          S | dk    r!t           j                            ||          S | dk    r!t           j                            ||          S | dk    r!t           j                            ||          S dS )zCreate optimizer based on name.

    Args:
        optimizer_name: Name of optimizer ("Adam", "AdamW", "SGD", "RMSprop")
        parameters: Parameters to optimize
        learning_rate: Learning rate

    Returns:
        Optimizer instance
    Adam)lrAdamWSGDRMSpropN)r/   optimr  r  r  r  )optimizer_name
parameterslearning_rates      r   _create_optimizerr  c  s     {
}===	7	"	"{   >>>	5	 	 {zm<<<	9	$	${"":-"@@@ 
%	$r   c                 &   | dk    rt           j                                        S | dk    rt           j                                        S | dk    rt           j                                        S | dk    rt           j                                        S dS )zCreate loss function based on name.

    Args:
        loss_function_name: Name of loss function ("MSE", "L1", "Huber", "SmoothL1")

    Returns:
        Loss function instance
    MSEL1HuberSmoothL1N)r/   r  MSELossL1Loss	HuberLossSmoothL1Loss)loss_function_names    r   _create_loss_functionr  x  s     U""x!!!	t	#	#x   	w	&	&x!!###	z	)	)x$$&&& 
*	)r   c                 V   t          j        t          |                    }t          j                            |          }|r\|d         dd                             |ddd          }	|                     |                    d|	i          |	|||j	                   dS |rT|d                             |ddd          }|                     |                    d|i          ||||j	                   dS |                     |                    d|i          ||||j	                   dS )aG  Execute the training loop.

    Args:
        guider: The guider object
        train_sampler: The training sampler
        latents: Latent tensors
        num_images: Number of images
        seed: Random seed
        bucket_mode: Whether bucket mode is enabled
        multi_res: Whether multi-resolution mode is enabled
    r   Nru   r   )rC   )
r/   r   r   r   r   r   repeatr   r   rC   )
guidertrain_samplerrO  r   rC   rj  rl  r?   r<   dummy_latents
             r   _run_training_loopr    sb    \%
++,,F-??EEE 
qz"1"~,,ZAqAA  )\!:;; 	 	
 	
 	
 	
 	
 
 
!*##J1a88  )W!566 	 	
 	
 	
 	
 	
 	  )W!566 	 	
 	
 	
 	
 	
r   c                   :    e Zd Zed             Zed             ZdS )TrainLoraNodec                  f   t          j        dddddt           j                            dd          t           j                            dd	          t           j                            d
d          t           j                            ddddd          t           j                            ddddd          t           j                            ddddd          t           j                            dddddd          t           j                            dddd d!          t           j                            d"g d#d$d%&          t           j                            d'g d(d)d*&          t           j                            d+d,d,d-d.          t           j                            d/g d0d1d2&          t           j                            d3d1d4gd1d5&          t           j	                            d6d7d89          t           j                            d:t          t          j                              t          t          j                              d,         d;&          t           j	                            d<dd=9          t           j                            d>ddd?d@          t           j	                            dAd7dB9          t           j                            dCt          j        dD          dEgz   dEdF&          t           j	                            dGd7dH9          t           j	                            dId7dJ9          gt          j        dK                              dLdMN          t          j        dO                              dPdQN          t           j                            ddRN          gS          S )TNr  z
Train LoRAmodel/trainingTr  zThe model to train the LoRA on.tooltiprO  zEThe Latents to use for training, serve as dataset/input of the model.r   z.The positive conditioning to use for training.rz   ru   i'  z#The batch size to use for training.defaultr   r  r  grad_accumulation_stepsi   z>The number of gradient accumulation steps to use for training.r     i z*The number of steps to train the LoRA for.r  gMb@?gHz>r  z&The learning rate to use for training.)r  r   r  r   r  r        zThe rank of the LoRA layers.rx   )r  r  r  r  r  z"The optimizer to use for training.)optionsr  r  loss_function)r  r  r  r  r  z&The loss function to use for training.rC   r   l    zbThe seed to use for training (used in generator for LoRA weight initialization and noise sampling)r}   )bf16fp32noner  zThe dtype to use for training. 'none' preserves the model's native compute dtype instead of overriding it. For fp16 models, GradScaler is automatically enabled.r  r  zThe dtype to use for lora.quantized_backwardFztWhen using training_dtype 'none' and training on quantized model, doing backward with quantized matmul when enabled.r  r  r  z"The algorithm to use for training.gradient_checkpointingz(Use gradient checkpointing for training.checkpoint_depth   z'Depth level for gradient checkpointing.r   z@Offload model weights to CPU during training to save GPU memory.rz  rt  rs  z9The existing LoRA to append to. Set to None for new LoRA.rj  zeEnable resolution bucket mode. When enabled, expects pre-bucketed latents from ResolutionBucket node.bypass_modezEnable bypass mode for training. When enabled, adapters are applied via forward hooks instead of weight modification. Useful for quantized models where weights cannot be directly modified.
LORA_MODELlorazLoRA weightsdisplay_namer  LOSS_MAPr
  zLoss historyzTotal training steps)node_idr  categoryis_experimentalis_input_listinputsoutputs)r   SchemaModelInputLatentConditioningIntFloatComboBooleanr[   r   keysrv  get_filename_listCustomOutputclss    r   define_schemazTrainLoraNode.define_schema  s   y#%% w0QRR	c     %%(X &    A    -\    H    #"!"D    :    ???#@	    #>>>!D	    * A    $444" 	     #V,"8	    
  (! S !  
  !2!4!455 !2!4!455a8@	    
  , F !  
 &E    
   !^ !  
 #(:7CCxjP$W	    
  !! D !  
 
  !! [ !  gxt 	,''..!' /   	*%%,,!+^ -   7<RSSH
 H
 H
 H	
r   c                   . |d         }|d         }|d         }|d         }|d         }|d         }|	d         }|
d         }|d         }|d         }|d         }|d         }|d         }|d         }|d         }|d         }|d         }|d         }|d         }|t           j        _        |rt          |          }nt	          |          }t          |          }t          j        d          5  |                    d          }d}t          j
        |          }|dk    r*t          j
        |          }|                    |           n|j                                        }|t          j        k    rKt          j        }|t          j        k    rd}t           j        t$          j        v rt)          j        d           nt          j        }|dvr|nt          j        }t-          |||          \  }}}t/          |||          }|j                            d                                           t5          |          \  }} d }!|r,t)          j        d           t9          |||||          \  }"}#}!nt;          |||||          \  }"}#t=          ||"                                |          }	tA          |          }$|rXtC          |j        j"        |	          }%t)          j#        d
tI          |%           d|            |%D ]}&tK          |&|           t          j&        '                                 t           j        (                    |gd|            t          j&        '                                 dg i..fd}'|rtS          |$|	|'||||z  ||||
  
        }(n tS          |$|	|'||||z  |||r|nd |
  
        }(tU          ||          })|)+                    |           d }*|!^|!,                    |j                  }*|*D ]}+|+-                    |           t)          j        d|!.                                 d           	 dt           j        _/        ta          |)|(|||||           dt           j        _/        |*.|*D ]}+|+1                    |           t)          j        d           |j        2                                D ]}&tg          |&           nq# dt           j        _/        |*.|*D ]}+|+1                    |           t)          j        d           |j        2                                D ]}&tg          |&           w xY w~(~	|"D ]2},|"|,         4                    |          5                                |"|,<   3|#D ]}-|-                    d           ~-~#tm          j7        |".|| z             cd d d            S # 1 swxY w Y   d S )Nr   FT)force_deepcopyr  a  WARNING: FP16 model detected with fp16_accumulation enabled. This combination can be numerically unstable during training and may cause NaN values. Suggested fixes: 1) Set training_dtype to 'bf16', or 2) Disable fp16_accumulation (remove from --fast flags).r   zUsing bypass mode for training)r&  z!Gradient checkpointing: patching z modules at depth r   g@xD)memory_requiredr!   r   c                 >    d                              |            d S )Nr   rN  )r   r
  s    r   ry   z,TrainLoraNode.execute.<locals>.loss_callback  s"     ''-----r   )ry   rz   r|   r{   rC   r}   r   r   )ry   rz   r|   r{   rC   r}   r~   r   z[BypassMode] Injected z bypass hooksz![BypassMode] Ejected bypass hooks)8r&   model_managementtraining_fp8_bwdrQ  rW  r[  r/   inference_modern   node_helpersstring_to_torch_dtypeset_model_compute_dtyper  	get_dtypefloat16r   r   Fp16Accumulationr
   fastr  warningrn  rq  r   r  r~  r  r  r  r  r  r  r)  diffusion_modelinfor]   rJ  r0   r1   load_models_gpurt   r   	set_condscreate_injectionsinjectget_hook_countin_trainingr  ejectmodulesrL  r4   rh   r   
NodeOutput)/r  r  rO  r   rz   r  r  r  r  rx   r  rC   r}   r  r  r  r  r  r   rz  rj  r  r  r  r  r   r$   r7   latents_dtyper   rl  r}  r|  r  r  r  	criterionmodules_to_patchrI  ry   r  r  bypass_injections	injectionr   r  r
  s/                                                 @r   executezTrainLoraNode.executeG  sG   4 a]
a"9!"<%a(Aw"1*1-Aw'*]
/2aL	!7!:]
+A.%a(!!n!!n2D/  	>27;;GG4W==G )22!%(( ]	L ]	LD11B#O%;JGGJ''$:>JJ**51111 !h0022%-//!ME "U^33*.):diGGL   "NE &+'%9%9EEu~M-G. .*GZ
 9:{[[H H##E**00222 0C=/Q/Q,n "N >????Z()Z@ @<,nn 0D()Z0 0,,
 * 0 0- I ..@AAI & 4#8H,4D$ $ $  |EUAVAV||jz||}}}) 4 4A!
33333J""$$$ "22d
N 3    J""$$$ |H. . . . .   ,"/)4 %(? ?#(#*$3! ! ! !-"/)4 %(? ?#(,5!?4$3! ! ! !
;;;FX&&& !%)$2$D$DRX$N$N!!2 ) )I$$R((((e~7T7T7V7Veeefff59&2"!   6;&2$0%6 , ,	!++++M"EFFF))++  AAJJJJ 6;&2$0%6 , ,	!++++M"EFFF))++  AAJJJJy  H H!(!2!2:!>!>!E!E!G!G.  &&u---G# =(EN4JKK{]	L ]	L ]	L ]	L ]	L ]	L ]	L ]	L ]	L ]	L ]	L ]	L ]	L ]	L ]	L ]	L ]	L ]	Ls.   /MW&S+A-WA.UA.WWWNrF   rG   rH   classmethodr  r  rP   r   r   r  r    sV        I
 I
 [I
V UL UL [UL UL ULr   r  c                   <    e Zd Zed             Zedd            ZdS )LoraModelLoaderc                    t          j        ddddt           j                            dd          t          j        d                              d	d
          t           j                            ddddd          t           j                            ddd          gt           j                            dd          g          S )Nr#  zLoad LoRA Modelzmodel/loadersTr  z0The diffusion model the LoRA will be applied to.r  r  r  z/The LoRA model to apply to the diffusion model.strength_modelr  g      Yg      Y@zGHow strongly to modify the diffusion model. This value can be negative.r  bypassFzWhen enabled, applies LoRA in bypass mode without modifying base model weights. Useful for training and when model weights are offloaded.r  zThe modified diffusion model.r  )r  r  r  r  r  r  )r   r  r  r  r  r  r  r  r  s    r   r  zLoraModelLoader.define_schema!  s    y%*$ %W    	,''--$U .   $e    
  ! h !  * !(2Q    3
 
 
 	
r   Fc                     |dk    rt          j        |          S |r't          j                            |d ||d          \  }}n&t          j                            |d ||d          \  }}t          j        |          S )Nr   )r   r  r&   sdload_bypass_lora_for_modelsload_lora_for_models)r  r  r  r%  r&  
model_lorar   s          r   r  zLoraModelLoader.executeC  s    Q=''' 	!H@@tT>1 MJ "H99tT>1 MJ }Z(((r   NFr   rP   r   r   r#  r#     sN        
 
 [
B ) ) ) [) ) )r   r#  c                   <    e Zd Zed             Zedd            ZdS )SaveLoRAc                    t          j        ddgddddt          j        d                              dd	          t           j                            d
dd          t           j                            ddd          gg           S )Nr.  zexport lorazSave LoRA Weightszadvanced/model_mergingTr  r  z>The LoRA model to save. Do not use the model with LoRA layers.r  rp   zloras/ComfyUI_trained_loraz*The prefix to use for the saved LoRA file.r  r  zYOptional: The number of steps the LoRA has been trained for, used to name the saved file.)optionalr  )r  search_aliasesr  r  r  is_output_noder  r  )r   r  r  r  Stringr  r  s    r   r  zSaveLoRA.define_schemaT  s    y)?,- 	,''--\ .   	8H    
 !w     /
 
 
 	
r   Nc                 4   t          j                    }t          j        ||          \  }}}}}	|
| d|dd}
n| d| d|dd}
t          j                            ||
          }
t          j                            ||
           t          j
                    S )Nr   05z_.safetensorsru  )rv  get_output_directoryget_save_image_pathospathjoinsafetensorsr/   	save_filer   r  )r  r  rp   r  
output_dirfull_output_folderfilenamecounter	subfolderfilename_prefixoutput_checkpoints              r   r  zSaveLoRA.executep  s    !688
,VZ@@ 	JHgy/ =#+ G Gg G G G G#+ U Ue U UG U U U UGLL);=NOO##D*;<<<}r   r   r   rP   r   r   r.  r.  S  sM        
 
 [
6    [  r   r.  c                   <    e Zd Zed             Zedd            ZdS )LossGraphNodec                    t          j        dg dddddt          j        d                              dd	          t           j                            d
dd          gg t           j        j        t           j        j        g	  	        S )NrE  )ztraining chartztraining visualizationz	plot losszPlot Loss Graphr  Tr  r   zLoss map from training node.r  rB  
loss_graphz&Prefix for the saved loss graph image.r  )	r  r1  r  r  r  r2  r  r  hidden)r   r  r  r  r3  Hiddenpromptextra_pnginfor  s    r   r  zLossGraphNode.define_schema  s    y#TTT*% 	*%%++$B ,   	%(D    		 I$bi&=>%
 
 
 	
r   Nc                    |d         }d\  }}d}t          j        d||z   ||z   fd          }	t          j        |	          }
t	          |          t          |          cfd|D             }t          |          }||t          |d         |z            z
  f}t          |dd          d	          D ]R\  }}|t          ||z  |z            z   }|t          ||z            z
  }|
	                    |||fgd
d           ||f}S|
	                    |df||fgdd           |
	                    ||f||z   |fgdd           d }	 t          j        dd          }n## t          $ r t          j                    }Y nw xY w|
                    d|dz  fd|d           |
                    |dz  |dz   fd|d           |
                    |dz
  dfd|d           |
                    |dz
  |dz
  fd|d           t          j        |	                              t          j                  dz  }t'          j        |          d         }t+          j        t/          j        ||                     S )Nr   )i   i  (   r   r   c                 &    g | ]}|z
  z
  z  S rP   rP   r   s     r   rT   z)LossGraphNode.execute.<locals>.<listcomp>  s'    SSS!HH)<=SSSr   r   ru   r   r   r   r  blackz	arial.ttf   r  Loss)fontr  
   Steps   z.2fg     o@r   r  )r   )r   r  r   r  r   r  r]   r  rl   r	  r   truetypeIOErrorload_defaulttextnparrayastyper   r/   
from_numpyr   r  r   PreviewImage)r  r   rB  rJ  rK  loss_valuesr  r  marginr  r  r  r  r  rR   r   r  r  rR  	img_array
img_tensorr   r   s                        @@r   r  zLossGraphNode.execute  s   6l viEFNFVO4g
 
 ~c"" --s;/?/?(SSSSS{SSSK  fs;q>F+B'C'CCD
k!""oQ777 	  	 DAqQY.///AQZ(AIIzAq6*qIAAAQJJ		FA; 01q	III		f78wa 	 	
 	
 	
 	,%k266DD 	, 	, 	,)++DDD	, 			1fk"FG	DDD		5A:v{+W4g	NNN 			6B;"x$5$5Dw	OOO		b[&2+&8(9(97 	 	
 	
 	

 HSMM((44u<	%i007
 }
 D D DEEEEs   E" "FFNNr   rP   r   r   rE  rE    sS        
 
 [
, 0F 0F 0F [0F 0F 0Fr   rE  c                   L    e Zd Zedeeej                          fd            ZdS )TrainingExtensionr'  c                 :   K   t           t          t          t          gS r   )r  r#  r.  rE  r   s    r   get_node_listzTrainingExtension.get_node_list  s       	
 	
r   N)	rF   rG   rH   r   r[   r   r   	ComfyNoderg  rP   r   r   re  re    sE        
T$r|*<%= 
 
 
 X
 
 
r   re  c                  "   K   t                      S r   )re  rP   r   r   comfy_entrypointrj    s      r   r   )rc   rc  )ru   Nr   Nr,  )Sr  r8  numpyrZ  r;  r/   torch.nnr  torch.utils.checkpoint	tqdm.autor   PILr   r   r   typing_extensionsr   comfy.samplersr&   comfy.sampler_helperscomfy.sdcomfy.utilscomfy.model_managementcomfy.condsr   r	   comfy.cli_argsr
   r   !comfy_extras.nodes_custom_samplerr   rv  r  comfy.weight_adapterr   r   comfy.weight_adapter.bypassr   comfy_api.latestr   r   r   r   r   Guider_Basicr   rX   rm   r5   Samplerrt   Moduler   r  r!  r  r[   r)  autogradFunctionr.  rJ  rL  rQ  rW  r[  rn  rq  r~  r  r  r  r  r  r  r  rh  r  r#  r.  rE  re  rj  rP   r   r   <module>r     s    				                          + + + + + + + + + + & & & & & &                  - - - - - - - - 3 3 3 3 3 3 3 3 ( ( ( (         7 7 7 7 7 7 7 7 > > > > > > 3 3 3 3 3 3 3 3 3 3 # # # # # #B B B B B,3@ B B BJ      ,w. w. w. w. w.5>) w. w. w.t+ + + + +ux + + +"  & /3 8?   $ JN# #9# #	")_# # # #L" " " " " 7 " " "J" " " "*      0  ,-* -* -*`  6, , ,*9( 9( 9(x$ $ $&"( "( "(J48 48 48nA A A*' ' '&,
 ,
 ,
^cL cL cL cL cLBL cL cL cLL0) 0) 0) 0) 0)bl 0) 0) 0)f) ) ) ) )r| ) ) )XIF IF IF IF IFBL IF IF IF^
 
 
 
 
 
 
 
 1      r   