
    3jZ                        S SK r S SKrS SKrS SKrS SKrS SKJr  S SKrS SK	J
r
  S SKJrJrJr  S SKJr  S SKrS SKrS SKrS SKrS SKrS SKJrJr  S SKJrJr  S SKrS SKrS SK r S SK!J"r"J#r#  S SK$J%r%  S S	K&J'r'J(r(J)r)  S S
KJ*r*   " S S\RV                  RX                  5      r-S5S jr.S6S jr/ " S S\R`                  Rb                  5      r2 " S S\R                  Rf                  5      r4S r5 S7S\R                  Rf                  4S jjr6 S8S\Rf                  S\7S\8\Rf                     4S jjr9 " S S\Rt                  Rv                  5      r<S9S jr=S r>S r?S r@S rAS  rBS! rCS" rDS# rES$ rFS% rGS& rHS' rIS( rJS) rK " S* S+\(R                  5      rM " S, S-\(R                  5      rN " S. S/\(R                  5      rO " S0 S1\(R                  5      rP " S2 S3\'5      rQS\Q4S4 jrRg):    N)trange)Image	ImageDraw	ImageFont)override)CONDRegularCONDList)argsPerformanceFeature)adaptersadapter_maps)BypassInjectionManager)ComfyExtensionioui)ProgressBarc                   H   ^  \ rS rSrSrSS.U 4S jjr     SS jrSrU =r$ )	TrainGuider   z:
CFGGuider with modifications for training specific logic
F
offloadingc                2   > [         TU ]  " U0 UD6  Xl        g N)super__init__r   )selfr   r
   kwargs	__class__s       8/home/wildlama/comfy/ComfyUI/comfy_extras/nodes_train.pyr   TrainGuider.__init__"   s    $)&)$    c
                    [         R                  R                  U R                  UR                  U R
                  U R                  U R                  (       + U R                  S9u  U l        U l        U l	        [        R                  R                  5         U R                  R                  n
Ub*  [         R                  R                  XQR                  U
5      nUR                  U
5      nUR                  U
5      nUR                  U
5      n[         R                   R#                  U R                  XR                  R%                  5       S9   U R                  R'                  5         U R)                  UUU
UUUUUUU	S9
nU R                  R+                  5         [         R                  R-                  U R
                  U R                  5        U ?U ?	U$ ! U R                  R+                  5         f = f)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_sampleTrainGuider.outer_sample&   s    !!22""

""$(OO 3"oo 3  	9$*d&8 	

 ##//# 00==kk6L  #v.6"++v5G5G5S5S5U 	, 	
	)&&(&&+ ' F &&(,,TZZ9K9KL &&(s   2G G.)r-   r/   r0   r   )NNFNN)	__name__
__module____qualname____firstlineno____doc__r   rG   __static_attributes____classcell__r   s   @r   r   r      s2     */ % % 9 9r!   r   c                    0 nU R                  5        H  u  pEUn[        U[        5      (       a  [        XQUS9nOz[        U[        R
                  5      (       a  Ub  UR                  S5      U:X  a  XQ   nO>[        U[        [        45      (       a#  [        U5      U:X  a  U Vs/ s H  ouU   PM	     nnXcU'   M     U$ s  snf )N	full_sizer   )
items
isinstancedictmake_batch_extra_option_dictr1   Tensorsizelisttuplelen)dindiciesrS   new_dictkvnewvis           r   rW   rW   b   s    H	a/yQD5<<(( AFF1I$:{D%=))c!f	.A"*+(QaD(D+  O ,s   $B>c           
         [        U S5      (       a7  [        U S5      (       d&  [        U 5       H  u  p#[        X1 SU 35        M     U $ [        U S5      (       Ga  [        U R	                  5       5       GHp  u  pE[        U[        5      (       a  [        XQ SU 35        M-  [        U[        R                  5      (       a  UR                  5       X'   M`  [        U[        5      (       aS  UR                   Vs/ s H4  n[        U[        R                  5      (       a  UR                  5       OUPM6     snUl        M  [        U[        5      (       aN  [        UR                  [        R                  5      (       a"  UR                  R                  5       Ul        GM(  GM+  [        U[        [        45      (       d  GMI  [        U5       H  u  p#[        X1 SU SU 35        M     GMs     U $ s  snf )N__iter__rT   .)hasattr	enumerateprocess_cond_listrZ   rT   rU   rV   r1   rX   cloner	   conddetachr   r[   )r]   prefixindexitemr`   ra   ts          r   ri   ri   q   sh   q*ga&9&9$Q<KEdhaw$78 (	G		ODA!T""!!xq_5Au||,,wwyAx((TUTZTZ[TZq
1ell(C(C!((*JTZ[A{++affell33VV]]_AF 4Ae}--#,Q<KE%dhas!E7,CD $0 $ H \s   7;G+c            	       ~    \ rS rSrSSSSS\R
                  SSS4	S jrS r SS jrS	 r	S
 r
S rS r   SS jrSrg)TrainSampler   N   r   Fc                 *   Xl         X l        X0l        X@l        X`l        XPl        Xpl        Xl        Xl        U
U l	        U(       a  [        R                  R                  5       OS U l        U
b  U R                  U
5        g S U l        S U l        S U l        g r   )loss_fn	optimizerloss_callback
batch_sizetotal_stepsgrad_accrE   training_dtypereal_datasetbucket_latentsr1   amp
GradScalergrad_scaler_init_bucket_databucket_offsetsbucket_weights
num_images)r   rv   rw   rx   ry   r{   rz   rE   r|   r}   r~   use_grad_scalers               r   r   TrainSampler.__init__   s     "*$& 	,7C  	 6E599//1$%"">2"&D"&D"DOr!   c                 N   S/U l         / nU HY  nUR                  UR                  S   5        U R                   R                  U R                   S   UR                  S   -   5        M[     U R                   S   U l        [        R
                  " U[        R                  S9U l        g)z3Initialize bucket offsets and weights for sampling.r   r&   N)r   appendr,   r   r1   tensorfloat32r   )r   r~   bucket_sizeslats       r   r   TrainSampler._init_bucket_data   s     c!C		!-&&t':':2'>1'MN " --b1#ll<u}}Mr!   c
                 X   UR                   R                  R                  X#US5      n
UR                   R                  R                  [        R                  " U5      [        R                  " U5      US5      nU Vs/ s H  oU   PM	     snUR
                  S'   [        XvUS9n[        R                  " U
R                  R                  U R                  S9   U" U
R                  S5      UR                  S5      40 UD6nU R                  UR                  5       UR                  5       5      nS S S 5        U	(       aW  WU R                  -  nU R                  b+  U R                  R!                  U5      R#                  5         U$ UR#                  5         W$ s  snf ! , (       d  f       Ns= f)NFpositiverR   r   T)r/   model_samplingnoise_scalingr1   
zeros_liker-   rW   autocastr%   typer|   requires_grad_rv   floatr{   r   scalebackward)r   
model_wrapbatch_sigmasbatch_noisebatch_latentrk   r^   
extra_argsdataset_sizebwdxtx0rc   batch_extra_argsx0_predlossbwd_losss                    r   fwd_bwdTrainSampler.fwd_bwd   ss    ##22@@|U
 ##22@@\*[)	
 :B'BAQ'B
$7L
 ^^BIINN$2E2EF !!$'++D1 #G
 <<<D G dmm+H+  &&x099;  !!#% (C
 GFs   <FAF
F)c                    [        U5       Vs/ s HJ  nUR                  R                  R                  [        R
                  " S5      R                  5       5      PML     nn[        R                  " U5      R                  U5      $ s  snf )z)Generate random sigma values for a batch.rt   )	ranger/   r   percent_to_sigmar1   randro   r   r6   )r   r   ry   r%   _r   s         r   _generate_batch_sigmas#TrainSampler._generate_batch_sigmas   sz     :&	
 ' ""11BB

4 %%' '	 	 
 ||L),,V44
s   ABc                    [         R                  " U R                  S5      R                  5       nU R                  U   nUR
                  S   n	U R                  U   n
[        U R                  U	5      n[         R                  " U	5      SU R                  5       nU Vs/ s H  oU-   PM	     nnX   R                  U5      nUR                  SU05      R                  UR                  5      nU R                  XUR                  5      nU R                  UUUUUUUU R                   SS9	nU R"                  (       a  U R#                  UR                  5       5        UR%                  UR                  5       S US.5        gs  snf )	z)Execute one training step in bucket mode.rt   r   NsamplesTr   .4f)r   bucket)r1   multinomialr   ro   r~   r,   r   minry   randpermtolistr6   generate_noiser%   r   r   r   rx   set_postfix)r   r   rk   r   noisegenr?   pbar
bucket_idxbucket_latentbucket_sizebucket_offsetactual_batch_sizerelative_indicesidxabsolute_indicesr   r   r   r   s                      r   _train_step_bucket_mode$TrainSampler._train_step_bucket_mode   so    &&t':':A>CCE
++J7#))!,++J7  = >>+67I8IJQQS;KL;KCC/;KL$699,G--y,.GHKK
 22:R^ReRef||OO  

 tyy{+TYY[$5*MN+ Ms   E?c                 P   [         R                  " U5      SU R                   R                  5       n[         R                  " U V	s/ s H  oU	   PM	     sn	5      n
UR                  SU
05      R                  U
R                  5      nU R                  U[        U R                  U5      U
R                  5      nU R                  UUUU
UUUUSS9	nU R                  (       a  U R                  UR                  5       5        UR                  SUR                  5       S 05        gs  sn	f )zGExecute one training step in standard (non-bucket, non-multi-res) mode.Nr   Tr   r   r   )r1   r   ry   r   stackr   r6   r%   r   r   r   rx   ro   r   )r   r   rk   r   r   r?   r   r   r^   rc   r   r   r   r   s                 r   _train_step_standard_mode&TrainSampler._train_step_standard_mode  s   >>,/0A$//BIIK{{X#FXOX#FG--y,.GHKK
 22:s4??T`?acocvcvw||  

 tyy{+&TYY[$578' $Gs   D#c                    [         R                  " U5      SU R                   R                  5       nSn	U H  n
U R                  U
   R                  U5      nUR                  SU05      R                  UR                  5      nUR                  R                  R                  [         R                  " S5      R                  5       5      n[         R                  " U/5      R                  UR                  5      nU R                  UUUUUU
/UUSS9	nX-  n	M     XR                  -  [!        U5      -  n	U R"                  b*  U R"                  R%                  U	5      R'                  5         OU	R'                  5         U R(                  (       a  U R)                  U	R                  5       5        UR+                  SU	R                  5       S 05        g)	zIExecute one training step in multi-resolution mode (real_dataset is set).Nr   r   r   Fr   r   r   )r1   r   ry   r   r}   r6   r   r%   r/   r   r   r   ro   r   r   r{   r\   r   r   r   rx   r   )r   r   rk   r   r   r?   r   r   r^   
total_lossrn   single_latentr   r   r   s                  r   _train_step_multires_mode&TrainSampler._train_step_multires_mode'  s   >>,/0A$//BIIK
E --e477EM"11M*b%%&  &&55FFJJt$))+ 
 !<<7::=;O;OPL<<   
D J- .  --/#h-?
'"":.779!z01&Z__%6s$;=>r!   c	           
         [        UR                  5      Ul        UR                  S   n	UR                  S5      n
[        R                  R                  5         [        U R                  5      n[        U R                  SS[        R                  R                  (       + S9=n GH  n[        R                  R                  U R                  US-  -   5      nU R                   b  U R#                  XX>Xl5        O6U R$                  c  U R'                  XX>XjU5        OU R)                  XX>XjU5        US-   U R*                  -  S:X  Ga3  U R,                  b%  U R,                  R/                  U R0                  5        U R0                  R2                   Hf  nUS    HZ  nUR4                  c  M  UR4                  R6                  R9                  UR6                  R:                  5      UR4                  l        M\     Mh     U R,                  b@  U R,                  R=                  U R0                  5        U R,                  R?                  5         OU R0                  R=                  5         U R0                  RA                  5         UR?                  S5        GM     [        R                  R                  5         [        RB                  " U5      $ )	Nr   r   zTraining LoRAg{Gz?)desc	smoothingdisablei  rt   params)"ri   r-   rY   r1   r2   r3   r   rz   r   r(   utilsPROGRESS_BAR_ENABLEDcomfy_extrasnodes_custom_samplerNoise_RandomNoiserE   r~   r   r}   r   r   r{   r   unscale_rw   param_groupsgraddatar6   r&   stepupdate	zero_gradr   )r   r   rA   r   rC   r>   r?   rB   rD   rk   r   ui_pbarr   rc   r   r   params                    r   sampleTrainSampler.sampleK  s-    -Z-=-=>

+{{1~

 d../  $!KK<<<	 D   $88JJ		AH$H "".,,ZzUah""*..zWcswx..zWcswxA&!+##/$$--dnn=$(NN$?$?L!-h!7 ::-$*/**//*<*<UZZ=M=M*N

 "8 %@
 ##/$$))$..9$$++-NN'')((*NN1AB 	

 --r!   )ry   r~   r   r   r{   r   rx   rv   r   rw   r}   rE   rz   r|   )T)NNF)rI   rJ   rK   rL   r1   bfloat16r   r   r   r   r   r   r   r   rN    r!   r   rr   rr      sa    
 ~~##J	N* (T5!OF90"?V 3.r!   rr   c                   :   ^  \ rS rSrU 4S jrS rS rS rSrU =r	$ )BiasDiffi  c                 .   > [         TU ]  5         Xl        g r   )r   r   bias)r   r   r   s     r   r   BiasDiff.__init__  s    	r!   c                     UR                   nUR                  U R                  5      U R                  -   R                  U5      $ r   )r&   r6   r   )r   b	org_dtypes      r   __call__BiasDiff.__call__  s1    GG	TYY$))+//	::r!   c                 l    U R                   R                  5       U R                   R                  5       -  $ r   )r   nelementelement_sizer   s    r   passive_memory_usageBiasDiff.passive_memory_usage  s'    yy!!#dii&<&<&>>>r!   c                 @    U R                  US9  U R                  5       $ )N)r%   )r6   r   )r   r%   s     r   move_toBiasDiff.move_to  s    v((**r!   )r   )
rI   rJ   rK   rL   r   r   r   r   rN   rO   rP   s   @r   r   r     s    ;?+ +r!   r   c                    Su  p#[         R                  " SX#4S5      n[        R                  " U5      n[	        U R                  5       5      [        U R                  5       5      pvU R                  5        Vs/ s H  oU-
  Xv-
  -  PM     n	nSU[        U	S   U-  5      -
  4n
[        U	SS  SS9 H?  u  p[        XS-
  -  U-  5      nU[        X-  5      -
  nUR                  XU4/SSS	9  X4n
MA     U$ s  snf )
N)i  i,  RGBwhiter   rt   startblue   fillwidth)
r   newr   Drawr   valuesmaxintrh   line)loss_mapstepsr  heightimgdrawmin_lossmax_losslscaled_loss
prev_pointrc   xys                 r   draw_loss_graphr    s    ME
))EE?G
4C>>#DX__./X__5F1GhCK??CTUCTaLX%89CTKUVc+a.6"9::;J+ab/3QY%'(S_$		:1v&V1	=V
	 4 J Vs   7C4modelc                    Uc  / nO[        U S5      (       a  [        U [        R                  R                  [        R                  R
                  [        R                  R                  45      (       dD  UR                  U 5        [        R                  " SU SU R                  R                   S35        U$ U=(       d    SnU R                  5        H  u  p4[        XAU SU 35        M     U$ )NforwardzFound module with forward:  ()rootrf   )rg   rU   r1   nn
ModuleList
Sequential
ModuleDictr   loggingdebugr   rI   named_children*find_all_highest_child_module_with_forward)r  resultname	next_namechilds        r   r'  r'    s     ~			"	":##UXX%8%8%((:M:MN, , 	e3D6EOO<T<T;UUVWX>6D!002	25TF!I;BWX 3Mr!   depthreturnc           
         Uc  / nU=(       d    Sn[        U [        R                  [        R                  [        R                  45      n[        U S5      =(       a    U(       + nU(       aQ  US-  nX1:X  aG  UR                  U 5        [        R                  " SU SU SU R                  R                   S35        U$ U R                  5        H  u  px[        XX#U SU 35        M     U$ )	ad  
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
r  r  rt   zFound module at depth z: r  r  rf   )rU   r   r!  r"  r#  rg   r   r$  r%  r   rI   r&  find_modules_at_depth)	r  r,  r(  current_depthr)  is_containerhas_forwardr*  r+  s	            r   r/  r/    s      ~>6D ebmmR]]BMM%RSL%+@L0@K!MM% MM25'D6EOOD\D\C]]^_`M "002	eFdV1YKCXY 3 Mr!   c                   p    \ rS rSrSr\S\R                  4S j5       r\S\R                  4S j5       r	Sr
g)	OffloadCheckpointFunctioni  z
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                     U R                  U5        X l        [        R                  " 5          U" U5      sS S S 5        $ ! , (       d  f       g = fr   )save_for_backward
forward_fnr1   no_grad)ctxr  r7  s      r   r  !OffloadCheckpointFunction.forward  s/    a #]]_a= __s	   ?
Agrad_outc                 8   U R                   u  nU R                  nS U l        [        R                  " 5          UR	                  5       R                  S5      nU" U5      nUR                  U5        UR                  nS S S 5        AAAWS 4$ ! , (       d  f       N= f)NT)saved_tensorsr7  r1   enable_gradrl   r   r   r   )r9  r;  r  r7  
x_detachedr  grad_xs          r   r   "OffloadCheckpointFunction.backward  s    ^^
  2248J:&AJJx __F	 ! z:t| ! s   AB
Br   N)rI   rJ   rK   rL   rM   staticmethodr1   rX   r  r   rN   r   r!   r   r4  r4    sE     ! ! !   r!   r4  c                 ,  ^^ [        U S5      (       d  g U R                  mU(       aT  [        U [        R                  [        R
                  [        R                  [        R                  45      (       a  U4S jnOU4S jmU4S jnTU l        X l        g )Nr  c                 0   > [         R                  U T5      $ r   )r4  apply)r  org_forwards    r   checkpointing_fwd patch.<locals>.checkpointing_fwd  s    ,221kBBr!   c                    > T" U 0 UD6$ r   r   )r
   r   rF  s     r   fwdpatch.<locals>.fwd  s    ///r!   c                  V   > [         R                  R                  R                  TXSS9$ )NF)use_reentrant)r1   r   
checkpoint)r
   r   rJ  s     r   rG  rH    s&    ;;))44S$V[4\\r!   )	rg   r  rU   r   LinearConv1dConv2dConv3drF  )mr   rG  rJ  rF  s      @@r   patchrT     se    1i  ))K jRYY		299bii$PQQ	C	0	]  AM!Ir!   c                 N    [        U S5      (       a  U R                  U l        U ?g g )NrF  )rg   rF  r  )rS  s    r   unpatchrV    s$    q-  MM	M !r!   c                 D    / nU  H  nUR                  US   5        M     U$ )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_moder[    s,     Nk)45 r!   c                     [        U 5      S:X  a  U S   S   $ / nU  HM  nUS   nUR                  S   nUS:w  a  U H  nUR                  US   5        M     M<  UR                  U5        MO     U$ )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)
rt   r   r   N)r\   r,   r   )rY  latent_listlatentbs
sub_latents        r   _process_latents_standard_modera  *  s     7|qqz)$$K	"\\!_7$
"":d#34 % v&  r!   c                     [        U 5      S:X  a  U S   $ / nU  H<  n[        U[        5      (       a  UR                  U5        M+  UR	                  U5        M>     U$ )zProcess conditioning - either single list or list of lists.

Args:
    positive: list of conditioning

Returns:
    Flattened conditioning list
rt   r   )r\   rU   rZ   extendr   )r   flat_positiverk   s      r   _process_conditioningre  B  s\     8}{ MdD!!  &  &	 
 r!   c                    U(       a  U  Vs/ s H  o3R                  U5      PM     n n[        U 5      n[        S U  5       5      nSn[        R                  " SU SU S35        [        U 5       H+  u  px[        R                  " SU SUR                   35        M-     XU4$ [        U [        5      (       a  [        5       n	U  Vs/ s H  o3R                  U5      PM     n nU  H  n
U	R                  U
R                  5        M      [        R                  " SU	 35        [        U	5      S	:  a  S
nOSn[        R                  " U SS9n [        U 5      nOh[        U [        R                  5      (       a#  U R                  U5      n U R                  S   nSnO&[        R                  " S[        U 5       35        SnSnXU4$ s  snf s  snf )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              3   >   #    U  H  oR                   S    v   M     g7f)r   N)r,   ).0rp   s     r   	<genexpr>-_prepare_latents_and_count.<locals>.<genexpr>g  s     5WWs   FzBucket mode: z
 buckets, z total samplesz	  Bucket z: shape zLatent shapes: rt   Tr   )dimzInvalid latents type: )r6   r\   sumr$  r%  rh   r,   rU   rZ   setaddr1   catrX   errorr   )rY  r&   bucket_moderp   num_bucketsr   	multi_resrc   r   
all_shapesr^  s              r   _prepare_latents_and_countru  X  s    (/0144;0'l5W55
	k]*ZLWX(FAMMIaS<= )I-- '4  U
(/0144;0FNN6<<( 
|45z?QIIiiQ/G\
	GU\\	*	***U#]]1%
	.tG}o>?
		))A 1 1s   F?Gc                     U(       a  U $ [         R                  " SU S[        U 5       35        [        U 5      S:X  a
  US:  a  X-  $ [        U 5      U:w  a  [        S[        U 5       SU S35      eU $ )a7  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: rt   zNumber of positive conditions (z#) does not match number of images (z).)r$  r%  r\   
ValueError)r   r   rq  s      r   !_validate_and_expand_conditioningrx    s     MMN:,.@XPQ
8}j1n$$	X*	$-c(m_<_`j_kkmn
 	
 Or!   c                     U S:X  a  0 S4$ [         R                  " SU 5      n[        U R                  S5      S   R                  S5      S   5      n0 nU(       a  [        R
                  R                  U5      nX24$ )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    sx      1u33G]KI,,Y7:@@EbIJN ;;66yA++r!   c                 p   U S3nU R                   R                  n0 n[        R                  " SU SU 35        [	        U5      S:  a  [        UR                  U S3S5      5      n	UR                  U S3S5      n
Sn[         H  nUR                  XX5      nUc  M    O   Uc	  [        U   nUb   UR                  5       R                  U5      nO*WR                  U R                   USS	9R                  U5      nUR                  5        H  u  pXU S
U 3'   M     UR                  5       R                  S5      U4$ [         R"                  R%                  [         R&                  " U R                   R                  USS95      n[)        U5      R                  5       R                  S5      nUX S3'   UU4$ )ap  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_trainr6   create_trainnamed_parameterstrainr   r1   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     M
!CMMEKMM0\%IJ
5zQ&**cU&>3?@%))SE*=tD
  #K*//u   + $ #&y1K',557:::FM (44D 5 bn   -==?OD3<;-q/0  @ ""$33D9;FF xx!!KK++:TR
 tn**,;;DA-1m5)*K''r!   c                     [         R                  R                  [         R                  " U R                  R
                  USS95      n[        U5      R                  5       R                  S5      nU S3U0nXE4$ )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)	r1   r   r  r  r   r,   r   r  r   )r  r  r  r   bias_moduler  s         r   _create_bias_adapterr    sk     88FKK%%ZtLD 4.&&(77=K!]'*D1K##r!   c           	         0 n/ nU R                   R                  5        H  u  px[        US5      (       d  M  UR                  bG  [	        XXX45      u  pUR                  U
5        U S3nU R                  X5        UR                  U	5        [        US5      (       d  M  UR                  c  M  [        XU5      u  pUR                  U5        U S3nU R                  X5        UR                  U5        M     XV4$ )a0  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_functionr  r   .bias)
r  named_modulesrg   r  r  r   add_weight_wrapperr   r   r  )mpr  r  r  r  lora_sdall_weight_adaptersnrS  adapterr   r  bias_adapterbias_paramss                 r   _setup_lora_adaptersr    s     G&&(1'((xx#"8*z# v&7m%%c3#**73q&!!aff&8,@z,R){+5k%%c8#**<8! )$ ''r!   c           	         0 n/ n[        5       nU R                  R                  5        GHF  u  p[        U	S5      (       d  M  U	R                  b  [        XXX45      u  pUR                  U5        UR                  U
5        U S3n[        U
[        5      (       a+  U R                  X5        [        R                  " SU 35        O)UR                  XSS9  [        R                  " SU 35        [        U	S5      (       d  M  U	R                  c  M  [        XU5      u  pUR                  U5        U S3nU R                  X5        UR                  U5        [        R                  " S	U 35        GMI     XVU4$ )
aG  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  r  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  rg   r  r  r   r   rU   r   r  r$  r%  add_adapterr   r  )r  r  r  r  r  r  r  bypass_managerr  rS  r  r   r  r  r  s                  r   _setup_lora_adapters_bypassr  ,  sZ   ( G+-N&&(1'((xx#"8*z# v&#**737m gx00))#7MM$^_b^c"de"..sc.JMM$STWSX"YZq&!!aff&8,@z,R){+5k%%c8#**<8 UVYUZ[\5 )8 77r!   c                    U S:X  a  [         R                  R                  XS9$ U S:X  a  [         R                  R                  XS9$ U S:X  a  [         R                  R	                  XS9$ U S:X  a  [         R                  R                  XS9$ g)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)r1   optimr  r  r  r  )optimizer_name
parameterslearning_rates      r   _create_optimizerr  c  s     {{
==	7	"{{   >>	5	 {{z<<	9	${{"":"@@ 
%r!   c                 $   U S:X  a  [         R                  R                  5       $ U S:X  a  [         R                  R                  5       $ U S:X  a  [         R                  R	                  5       $ U S:X  a  [         R                  R                  5       $ g)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)r1   r   MSELossL1Loss	HuberLossSmoothL1Loss)loss_function_names    r   _create_loss_functionr  x  ss     U"xx!!	t	#xx  	w	&xx!!##	z	)xx$$&& 
*r!   c                    [         R                  " [        U5      5      n[        R                  R                  U5      nU(       aI  US   SS R                  USSS5      n	U R                  UR                  SU	05      U	UUUR                  S9  gU(       aF  US   R                  USSS5      nU R                  UR                  SU05      UUUUR                  S9  gU R                  UR                  SU05      UUUUR                  S9  g)a#  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   Nrt   r   )rE   )
r1   r   r   r   r   r   repeatr   r   rE   )
guidertrain_samplerrY  r   rE   rq  rs  rA   r>   dummy_latents
             r   _run_training_loopr    s    \\%
+,F--??EEqz"1~,,ZAqA  )\!:; 	 	
 
!*##J1a8  )W!56 	 	
 	  )W!56 	 	
r!   c                   4    \ rS rSr\S 5       r\S 5       rSrg)TrainLoraNodei  c           !         [         R                  " SSSSS[         R                  R                  SSS9[         R                  R                  SS	S9[         R
                  R                  S
SS9[         R                  R                  SSSSSS9[         R                  R                  SSSSSS9[         R                  R                  SSSSSS9[         R                  R                  SSSSSSS9[         R                  R                  SSSS S!S9[         R                  R                  S"/ S#QS$S%S&9[         R                  R                  S'/ S(QS)S*S&9[         R                  R                  S+S,S,S-S.S9[         R                  R                  S// S0QS1S2S&9[         R                  R                  S3S1S4/S1S5S&9[         R                  R                  S6S7S8S99[         R                  R                  S:[        [        R                  " 5       5      [        [        R                  " 5       5      S,   S;S&9[         R                  R                  S<SS=S99[         R                  R                  S>SSS?S@S9[         R                  R                  SAS7SBS99[         R                  R                  SC[        R                  " SD5      SE/-   SESFS&9[         R                  R                  SGS7SHS99[         R                  R                  SIS7SJS99/[         R                  " SK5      R!                  SLSMSN9[         R                  " SO5      R!                  SPSQSN9[         R                  R!                  SSRSN9/SS9$ )TNr  z
Train LoRAmodel/trainingTr  zThe model to train the LoRA on.tooltiprY  zEThe Latents to use for training, serve as dataset/input of the model.r   z.The positive conditioning to use for training.ry   rt   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.rw   )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.rE   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.r  r{  rz  z9The existing LoRA to append to. Set to None for new LoRA.rq  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BooleanrZ   r   keysr}  get_filename_listCustomOutputclss    r   define_schemaTrainLoraNode.define_schema  s   yy#%% w0QR		c    %%(X &   A   -\   H   #"!"D   :   ?#@	   #>!D	   * A   $4" 	    #V,"8	   

  (! S ! 
  !2!2!45 !2!2!45a8@	   

  , F ! 
 &E   

   !^ ! 
 #(::7CxjP$W	   

  !! D ! 
 

  !! [ ! gxt 		,'..!' /  		*%,,!+^ -  7<RSH
 H	
r!   c                 "  ^. US   nUS   nUS   nUS   nUS   nUS   nU	S   nU
S   nUS   nUS   nUS   nUS   nUS   nUS   nUS   nUS   nUS   nUS   nUS   nU[         R                  l        U(       a  [        U5      nO[	        U5      n[        U5      n[        R                  " S5         UR                  SS9nSn[        R                  " U5      nUS:w  a(  [        R                  " U5      nUR                  U5        OUR                  R                  5       nU[        R                  :X  a_  [        R                  nU[        R                  :w  a  Sn[         R"                  [$        R&                  ;   a  [(        R*                  " S5        O[        R                  nUS;  a  UO[        R                  n[-        UUU5      u  nnn[/        UUU5      nUR                  R1                  S5      R3                  5         [5        U5      u  nn S n!U(       a)  [(        R6                  " S5        [9        UUXU5      u  n"n#n!O[;        UUXU5      u  n"n#[=        UU"R?                  5       U5      n	[A        U5      n$U(       aV  [C        UR                  RD                  US	9n%[(        RF                  " S
[I        U%5       SU 35        U% H  n&[K        U&US9  M     [        RL                  RO                  5         [         R                  RQ                  U/SU(       + S9  [        RL                  RO                  5         S/ 0m.U.4S jn'U(       a  [S        U$U	U'UUXV-  UUUUS9
n(O[S        U$U	U'UUXV-  UUU(       a  UOS US9
n([U        UUS9n)U)RW                  U5        S n*U!b]  U!RY                  UR                  5      n*U* H  n+U+R[                  U5        M     [(        R6                  " SU!R]                  5        S35         S[         R                  l/        [a        U)U(UUUUU5        S[         R                  l/        U*b0  U* H  n+U+Rc                  U5        M     [(        R6                  " S5        UR                  Re                  5        H  n&[g        U&5        M     A(A	U" H(  n,U"U,   Ri                  U5      Rk                  5       U"U,'   M*     U# H  n-U-R1                  S5        A-M     A#[l        Rn                  " U"T.UU -   5      sS S S 5        $ ! S[         R                  l/        U*b0  U* H  n+U+Rc                  U5        M     [(        R6                  " S5        UR                  Re                  5        H  n&[g        U&5        M     f = f! , (       d  f       g = f)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                 .   > TS   R                  U 5        g )Nr   rX  )r   r  s    r   rx   ,TrainLoraNode.execute.<locals>.loss_callback  s     ''-r!   )rx   ry   r{   rz   rE   r|   r~   r   )rx   ry   r{   rz   rE   r|   r}   r   z[BypassMode] Injected z bypass hooksz![BypassMode] Ejected bypass hooks)8r(   model_managementtraining_fp8_bwdr[  ra  re  r1   inference_moderj   node_helpersstring_to_torch_dtypeset_model_compute_dtyper  	get_dtypefloat16r   r   Fp16Accumulationr
   fastr$  warningru  rx  r   r  r  r%  r  r  r  r	  r  r/  diffusion_modelinfor\   rT  r2   r3   load_models_gpurr   r   	set_condscreate_injectionsinjectget_hook_countin_trainingr  ejectmodulesrV  r6   rl   r   
NodeOutput)/r  r  rY  r   ry   r  r  r  r  rw   r  rE   r|   r  r  r  r  r  r   r  rq  r  r  r  r  r   r&   r9   latents_dtyper   rs  r  r  r  r  r  	criterionmodules_to_patchrS  rx   r  r  bypass_injections	injectionr   r  r  s/                                                 @r   executeTrainLoraNode.executeG  s   4 a]
a"9!"<%a(Aw"1*1-Aw'*]
/2aL	!7!:]
+A.%a(!!n!!n2D/ 27;G4W=G )2!!%(D1B#O%;;JGJ'$::>J**51 !hh002%--/!MME "U^^3*.)::diiGL "NNE &+'%9Eu~~M-G.*GZ
 9:{[H HH##E*002 0C=/Q,n "N>??Z()@<,n 0D()0,,
 * 0-I ..@AI &#8HH,,4D$  @EUAV@WWijzi{|})A!
3 * JJ""$ ""22d
N 3  JJ""$ |H.  ,"/)4 % ?#(#*$3! !-"/)4 % ?#(,54$3! !
;FX& !%)$2$D$DRXX$N!!2I$$R( "3 6~7T7T7V6WWdef59&&2"! 6;&&2$0%6	!+ &7MM"EF))+AAJ ,y !(!2!2:!>!E!E!G ! /&&u- / $ ==(EN4JK{ )(R 6;&&2$0%6	!+ &7MM"EF))+AAJ ,_ )(s'   5MV =&T#CV A6U==V  
Vr   NrI   rJ   rK   rL   classmethodr  r(  rN   r   r!   r   r  r    s/    I
 I
V UL ULr!   r  c                   8    \ rS rSr\S 5       r\SS j5       rSrg)LoraModelLoaderi   c                 j   [         R                  " SSSS[         R                  R                  SSS9[         R                  " S5      R                  S	S
S9[         R
                  R                  SSSSSS9[         R                  R                  SSSS9/[         R                  R                  SSS9/S9$ )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  LoraModelLoader.define_schema!  s    yy%*$ %W   		,'--$U .  $e   

  ! h ! * !(2Q   3
 	
r!   c                    US:X  a  [         R                  " U5      $ U(       a%  [        R                  R	                  US X#S5      u  pVO$[        R                  R                  US X#S5      u  pV[         R                  " U5      $ )Nr   )r   r"  r(   sdload_bypass_lora_for_modelsload_lora_for_models)r  r  r  r/  r0  
model_lorar   s          r   r(  LoraModelLoader.executeC  so    Q==''!HH@@tT1MJ "HH99tT1MJ }}Z((r!   r   NFr*  r   r!   r   r-  r-     s)    
 
B ) )r!   r-  c                   8    \ rS rSr\S 5       r\SS j5       rSrg)SaveLoRAiS  c                     [         R                  " SS/SSSS[         R                  " S5      R                  SSS	9[         R                  R                  S
SSS9[         R
                  R                  SSSS9// S9$ )Nr:  zexport lorazSave LoRA Weightszmodel/mergingTr  r  z>The LoRA model to save. Do not use the model with LoRA layers.r  rm   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  SaveLoRA.define_schemaT  s    yy)?,$ 		,'--\ .  		8H   
 !w    /
 	
r!   Nc                 8   [         R                  " 5       n[         R                  " X$5      u  pVpxn	Uc
  U SUS S3n
OU SU SUS S3n
[        R                  R                  XZ5      n
[        R                  R                  X5        [        R                  " 5       $ )Nr   05z_.safetensorsr|  )r}  get_output_directoryget_save_image_pathospathjoinsafetensorsr1   	save_filer   r"  )r  r  rm   r  
output_dirfull_output_folderfilenamecounter	subfolderfilename_prefixoutput_checkpoints              r   r(  SaveLoRA.executep  s    !668
,,V@ 	Jg/ =#+*Agb\ G#+*AeWGGB<} UGGLL);O##D<}}r!   r   r   r*  r   r!   r   r:  r:  S  s(    
 
6  r!   r:  c                   8    \ rS rSr\S 5       r\SS j5       rSrg)LossGraphNodei  c                 $   [         R                  " S/ SQSSSS[         R                  " S5      R                  SSS	9[         R                  R                  S
SSS9// [         R
                  R                  [         R
                  R                  /S9	$ )NrS  )ztraining chartztraining visualizationz	plot losszPlot Loss Graphr  Tr  r   zLoss map from training node.r  rO  
loss_graphz&Prefix for the saved loss graph image.r  )	r  r=  r  r  r  r>  r  r  hidden)r   r  r  r  r?  Hiddenpromptextra_pnginfor  s    r   r  LossGraphNode.define_schema  s    yy#T*% 		*%++$B ,  		%(D   		 II$$bii&=&=>%
 	
r!   Nc                 b   US   nSu  pgSn[         R                  " SXh-   Xx-   4S5      n	[        R                  " U	5      n
[	        U5      [        U5      pU Vs/ s H  oU-
  X-
  -  PM     nn[        U5      nX[        US   U-  5      -
  4n[        USS  SS9 HC  u  nnU[        UU-  U-  5      -   nU[        X-  5      -
  nU
R                  UUU4/S	S
S9  UU4nME     U
R                  US4X4/SS
S9  U
R                  X4Xh-   U4/SS
S9  S n [        R                  " SS5      nU
R                  SUS
-  4SUSS9  U
R                  US
-  US-   4SUSS9  U
R                  US-
  S4US USS9  U
R                  US-
  US-
  4US USS9  [        R                   " U	5      R#                  [        R$                  5      S-  n[&        R(                  " U5      S   n[*        R,                  " [.        R0                  " UU S9S9$ s  snf ! [         a    [        R                  " 5       n GNf = f)Nr   )i   i  (   r   r   r   rt   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  rh   r  r   truetypeIOErrorload_defaulttextnparrayastyper   r1   
from_numpyr   r"  r   PreviewImage)r  r   rO  rX  rY  loss_valuesr  r  marginr  r  r  r  r  r  r  r  rc   r  r  r`  	img_array
img_tensors                          r   r(  LossGraphNode.execute  sm   6l iiENFO4g
 ~~c" -s;/?(GRS{!H)<={SK s;q>F+B'CCD
k!"oQ7DAqQY.//AQZ(AIIzAq6*qIAQJ	 8 			FA; 01q	I		78wa 	 	
 	,%%k26D
 			1fk"FG	D		5A:v{+W4g	N 			6B;"xnDw	O		b[&2+&8C.7 	 	

 HHSM((4u<	%%i07
 }}
 DEEK T&  	,))+D	,s   HH H.-H.r   NNr*  r   r!   r   rS  rS    s*    
 
, 0F 0Fr!   rS  c                   L    \ rS rSr\S\\\R                        4S j5       r	Sr
g)TrainingExtensioni  r-  c                 6   #    [         [        [        [        /$ 7fr   )r  r-  r:  rS  r   s    r   get_node_listTrainingExtension.get_node_list  s      	
 	
s   r   N)rI   rJ   rK   rL   r   rZ   r   r   	ComfyNoderv  rN   r   r!   r   rt  rt    s)    
T$r||*<%= 
 
r!   rt  c                     #    [        5       $ 7fr   )rt  r   r!   r   comfy_entrypointrz    s     s   r   ) rr  )rt   Nr   Nr8  )Sr$  rE  numpyrh  rH  r1   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   r}  r  comfy.weight_adapterr   r   comfy.weight_adapter.bypassr   comfy_api.latestr   r   r   r   r   Guider_Basicr   rW   ri   r7   Samplerrr   Moduler   r  r'  r  rZ   r/  autogradFunctionr4  rT  rV  r[  ra  re  ru  rx  r  r  r  r  r  r  r  r  rx  r  r-  r:  rS  rt  rz  r   r!   r   <module>r     s    	       + + &      - 3 (   7 > 3 3 #B,33@@ BJ,w.5>>)) w.t+uxx +"& /388??$ JN#99# #	"))_#L" 7 7 "J"*0,-*`6,*9(x$&"(J48nA*'&,
^cLBLL cLL0)bll 0)f)r|| )XIFBLL IF^
 
 1 r!   