From 6608b9979f2dffa884f3b4ec3c1c9df5a4a44ec2 Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Thu, 24 Apr 2025 10:18:18 -0400 Subject: [PATCH] add base flex.2 support Signed-off-by: Vladimir Mandic --- .pylintrc | 1 + .ruff.toml | 1 + CHANGELOG.md | 7 +- html/reference.json | 7 + models/Reference/ostris--Flex.2-preview.jpg | Bin 0 -> 59329 bytes modules/flex2/__init__.py | 435 ++++++++++++++++++++ modules/model_flex.py | 88 ++++ modules/modeldata.py | 2 +- modules/modelloader.py | 10 +- modules/sd_detect.py | 4 +- modules/sd_models.py | 3 + modules/shared_items.py | 1 + wiki | 2 +- 13 files changed, 554 insertions(+), 7 deletions(-) create mode 100644 models/Reference/ostris--Flex.2-preview.jpg create mode 100644 modules/flex2/__init__.py create mode 100644 modules/model_flex.py diff --git a/.pylintrc b/.pylintrc index b9c4e76f8..bef8906ce 100644 --- a/.pylintrc +++ b/.pylintrc @@ -21,6 +21,7 @@ ignore-paths=/usr/lib/.*$, modules/intel/ipex, modules/intel/openvino, modules/k-diffusion, + modules/flex2, modules/ldsr, modules/meissonic, modules/mod, diff --git a/.ruff.toml b/.ruff.toml index 312717ae4..96fd1323a 100644 --- a/.ruff.toml +++ b/.ruff.toml @@ -8,6 +8,7 @@ exclude = [ "modules/control/proc", "modules/control/units", "modules/freescale", + "modules/flex2", "modules/ggml", "modules/hidiffusion", "modules/hijack", diff --git a/CHANGELOG.md b/CHANGELOG.md index 83506cc98..4edd0565f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,11 @@ # Change Log for SD.Next -## Update for 2025-04-23 +## Update for 2025-04-24 - **Features** - [Nunchaku](https://github.com/mit-han-lab/nunchaku) inference engine with custom **SVDQuant** 4-bit execution highly experimental and with limited support, but when it works, its magic: **Flux.1 at 6.0 it/s** *(not sec/it)*! + basically, it can speed up supported models by 2-5x by using custom quantization and execution engine see [Nunchaku Wiki](https://github.com/vladmandic/sdnext/wiki/Nunchaku) for installation guide and list of supported models & features - [FramePack](https://github.com/vladmandic/sd-extension-framepack) based on **HunyuanVideo-I2V** full support and much more for **Lllyasviel** [FramePack](https://lllyasviel.github.io/frame_pack_gitpage/) @@ -16,6 +17,10 @@ - custom models: e.g. replace llama with one of your choice - multiple video codecs and with hw acceleration, raw export, frame export, frame interpolation - quantization support, new offloading, more configuration options, cross-platform, etc. + - [Ostris Flex.2 Preview](https://huggingface.co/ostris/Flex.2-preview) + more than a FLUX.1 finetune, FLEX.2 is created from *Flux.1 Schnell -> OpenFlux.1 -> Flex.1-alpha -> Flex.2-preview* + and it has universal control and inpainting support built in! + available via *networks -> models -> reference* - [LTXVideo 0.9.6](https://github.com/Lightricks/LTX-Video?tab=readme-ov-file) **T2V** and **I2V** in both **Standard** and **Distilled** variants available in *video tab* diff --git a/html/reference.json b/html/reference.json index 1eb29f032..822c64598 100644 --- a/html/reference.json +++ b/html/reference.json @@ -180,6 +180,13 @@ "extras": "sampler: Default, cfg_scale: 3.5" }, + "Ostris Flex.2 Preview": { + "path": "ostris/Flex.2-preview", + "preview": "ostris--Flex.2-preview.jpg", + "desc": "Open Source 8B parameter Text to Image Diffusion Model with universal control and inpainting support built in. Early access preview release. The next version of Flex.1-alpha", + "skip": true, + "extras": "sampler: Default, cfg_scale: 3.5" + }, "Ostris Flex.1 Alpha": { "path": "ostris/Flex.1-alpha", "preview": "ostris--Flex.1-alpha.jpg", diff --git a/models/Reference/ostris--Flex.2-preview.jpg b/models/Reference/ostris--Flex.2-preview.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1635f36c8b5426c428d096f0f1e63d52958fc3e9 GIT binary patch literal 59329 zcmbT61y~!w_UJbRcP|dby~W*1k>KvMI0Sbs#i6B02`Al~( z_rCW%{ZGD~{Bq{Z&N(xa-Lo_MIRCf?;48^Pb0RUB1fE@q; zbO0Gd0iYlVgg7KYl>cIR5Gw%wha3q}$O9m9fB#c+u7Qa zPJsJ4HxD18r44KYh^*{u4J~zfh>9G-1OUKRRDn9XAmIamle4G0mck1<14AP^v{A&l zF#uG62LQ}1JzQ0_<#qlx0FjfW^FS#5<$tHk*?+VOOmQh{(9!){{{KV-mague2(vX1 z+I&{l9+n6WN3f%hr|Vz&34)0&9R4yA@?UmG7>Ho9zij(Y=KP1wKUw-OTRAyfA$0!Q z>}us?^_RO5{Lb6U8o^){1V?&9t$h$YjbKJcFDEF1{~(yy$=cil0Fbf&$~~T=D@x_yW;4AO9`0NC$wX2ml~k__vHP7Xa|W0ibd0Kl~y6 zJ74TPJzYhgJ@fJL;f7jUa{uknf2IGc!oM{C_wXO>asO@aUwudS(%Qz{%h8kWZ>L(i zIJ$Vb(|Nd>TUyg`{m+y5zg+P@%=!;IIJK;8tlh1h5l!hKW*OAk7BSq;R!~o0~7*fKs8VcGyz|M z4xkqp0>*(EU=dgYwtxfR1h@ol5tmFf5Dth4L=K__F@ZQhydYtaBuEaV0@4B*g3Lg+ zAZL&l=nW_g^Z^6|Wq|TPWuO{R3#bD$0Ga^(1g(SiK&PM^Brp;-5-}1r5;M{>Bw-{O zBxNKWBvT|?BsU~~q;RA-q%@>_q)Mblqz6_It3Es@=j-y+8#XCRj% zHzIcBOap=qZMNeV+-RJlK_(i zQvy>5(;hPfGYzvEvj=kt^9&0Miylh^OA`x<6^xaJ^#!XRYaQzvn-H5FTNc{{+Y37m zy9B!(`zQ7p4h{}8jx>%DjwenWP8m)Y&I-;STq0a@d*hb2|tM*i7!be z$v2WUQZOkqDTLIKG@i7Ube8ny3H1}1C)Q8iKdF8)`Q(a>l1!S+nk<^^GuaH;4LKdT z9JvE|0(lepG6gaPJB22N4@EXb55*xRF{K!#C1o^aE#(3g5*0g@7F7UM0o5?o1vL$| z0<|l3I&~NIAq^>wG>tt?63us-Jz64KNm?jv673J#eL50489GP0G`eoOlc!Wq6`y)N z&3iif^p>85UY9)&;`s~r7Y#42 zWJP5IW!qnZUn;zeemN>fD5oozA-5t=FK;VfA%CJEpb((Yu85+jteBuU2cd>oLdqZ~ zNdM0{hdRO`{^|0zK6SnXzRteGe(Zkl{dWB2{fh#S11tkN-#mR2 z@@73yCNS?U=&i-u&LD=M@Sv?=h2YW<%n*l=k>hR!jc!WYkMI>&d zd*ob{SX9nC311+88ewL zGCyZgWxdb3`egNKGFv*kI)^&vL(WYuGwxG$%b@UJ z(~#g$HhBxB5k_erVAj;WVZz0;8Cp&7NAiCNv*`8kuh zwRx-g-Jgy>e=m41+%5($p)5r&<1eSIP_5*zvaNnz6I}bY{&IbILwjQpZV5lw^w_-H z3g5=rPT8T|Dcj}U{kkW=H@$S=baZC7b}-em$z5Zf5`uoUJGCM-RR%!-1^+1-KE{L-M2m{KP){uJw84z0 z<+XM74UJ9BEv=nh-95d1{R4xOQ`0lEbMrqJ);HjrTiZLkd;7mn&(1F{ul`)${Phcj z@bkZ?|D|692)~e!k-^AlfBga>`TTX902$>e4=SOICYre$5j}4RI`NByyqXRS20pD5 z5)1bUOj1Vvb*A5cUHgY;|8I_k{+B%amt+6-YXQIpgAjuUCIF;>Q(iUyNt$}V>SjV3 zSHoE9IT`upcm=F2Zia>YJQsEIW_s_onekZ@_76JiQNMjW=OmzpfqfYET>8n!k+=Z2 z)kom7=1U!^QILr{ZqTS5()tHMH!yo&JFc=>R#r&dy-cZfQ}>FVuA)il*eidcDam`` zT=Y*!^a*qp5MM}Q(OnCYG0qypvlnY}E}vZN$$cZ|%e^{Bi7cnR6P9THkh@rj8w zB^0>0y3wh5%2zK#Bh8D1yVK|s%I(mkJJHb#q!KA5%1}4{AaUr+{Alhi-rm0q_Q#Go3%tF6fAqJQT!-@fXQ0W z?b$~I_(HC&)N2*p(>xEJI-;qpDeIV4q%gN*RRQA57w(ORRV=fxm#iQr#dE!#-=#@T zyQMp7BWFqKRLE_Z=|wN>qRDk0gr>>3Fn( z)+mk`Pd4>6A9mED=iyIZy-}3RMUpa#h%K6V`+8fuOJ{eK4Zhrepm%}A@+GbJXRlk> z{M<`+t%{ShQKHCgKfr5jUER@J>XUIOlVTJL&Ggb)*pxt+(fqXcu{;~)XK)B4luc+w z%1HJqe)bDLC{Yb51Tac^rUaN7C2;|K)+(gI^r!p%YHahE52lXLMxGJ&swJ&T^|7oU zof2+wP{EIrE%94(Z#*TKs*@2}-Lu0);5W1-X zk~AlajrvUIcFbNKVM$zMXhqzu!xo*M8Vyv-vmLU5xSDS2E{Yl-0ll{kocjeQiP1)h zW<|M3FVH*jd6$D*F2D1U0sxU zDB`ltIr*$}QCkVl&aHn=_hF>5Wohms8>=Z;pcD2`OP~<4a*Nasl{k>xHhpjlV$cyg`%o08mBZNm`Gw(}wVTT`l?N z(g#KpyYX+7@;~Ld8=RA9xx(sW;1o%pHngHNL_aN%YLTe_rh!yZN}viarEQ|2A>T|! z7pH`J?Tq}QrcR5kYK-x$%oJe?8QgKlZIm0?GLqy=b9&*6m4#H^cLvV^8*5T@Y&*D zP^$L_G6x13D8wLvFQAMUU95cdFup$zx`e?7NUj(Md(uQbso|Y@n~a;RyWbyyooEYD z#=&_p=}lXaN8o@0Fn+fzSO=~@sru+k-TX_Db~p`&@51s~Zp-R+l()%)5$I8HITm;kVK8OdJt;^ z-lgqySuxpNbpA7K)7cv=Y4W4br4>h&8vR&4Q_IjygWP!>tQ`rSN2Gle`!dQm#$5V} zL1|J!;7g3-GFACkHmWAc^jsX4Y5G-)zO$#U$Q5U-mNP-L_MdUGCXCU$@=Oar`o982 zb|f$)bH`EZq~q%uQ2H5vPY1E*T|NR|UZrst(rA~O8JJb8313oapaj}a%2;!z%bZ1e zE{L8l;e9UUZ_SVxX&CP%c)l;QcItl{mlFYalv88Sdidvj>y_i2P<}GR`*F~FJ)U8a z80dK_5G^t|V^ffLCW4LOFQ*_qAJO9*RIol)ir z+0n{V^1|f!j7$;txJ1GskJ;MYR=Ay!hOb9HJ$XQ)P5*@{b|#a84V@QF4*ca)r7Hfc60PaQ4Lo=S+6(=3ex%V&t2q_L$cqhY+p>3Iuh zC-wlH#luQ6BzU<`X=K?>FJ7y8bFy^1WdyCXgf$n9wTuKB%syRS4{%zi0lcavjq!hK za=L`e+`qsn6VPWF&TxL+x7$PMg4jAf#CS1)JjQQz&IF-@31mOKK7u&kEegi)P~nE{ z9qEJ)TH)X$M*=(9fp%Z0Y2qsazcOO*E!a2rdxITI7HLa=nGC0#ws%^dvB!i>QSa6g z%r5O+W`xtc^dVgAA9;UB`ueMaMrJb_gYdDGngz9t?F6?|(c)!<+3)_hXGnhJH)nq` zxNJCfl|9JgwqM%XT00x2LZvhhw3ekCCkvI-Xn5#DJvy#_8PSu=%@(>zlTc|FQfYvz z9@cLrT(0nD>r!@1X~VNLL?;DFQ$C__0VFuXD_U+>nIUR(%vzdDj&o2Vrw$9zjna2N zuW293D;UtUTrAaAHR2;bcD}=t*XsLS+4F(L?qJ~qyS^9=rAW#~6l*7aLfi0eVbQX=>Ka^*(R_I${kB}|2pP^(n zm32lfX8%sX0cB))rNo;4TLteiLwzL%yF_r0?ZP6&D}T(5MyXe30gqgqM#5juVcA=h zNL^ca!YFu3rWiS8s8vhqC%M}i=%O^ge-M~`~GtX?eH!RgyU*?>F+`DDEK z@hfHi=Gf-#9EWGg&9p{CIAXiQb&A3Znj)r(BgosU!{(Gh=mN~mi=W{Px6=nQES}ck z6>Pneg7ps4T(t`Jbyjbxgj?WP8E0GGW6q?S&o2^)ISv0H)ij{xXf$&#(eEHNg*&zM z>6Hj|zKhK7SBHt$WPz7v11fr#LM1qKEfZR;(sEtQAxjqj}>q7X@Nnp6m4r z*+##qN!eB_Qal{}ew{zdNpsWXo^(JU#qTH@w$Fh(x?xQIwg0SECQ{4S{6RoGPBJ_| z5iya6j7-lHU-{wsC=D8_tK918#!j-lt73{-!w?N1f>hW$*=h<*uTC@ZvX^HS#Kc_C zSf#416H{-23nM+Ue0v9rw@06h5fux^t60C2 znfjsFSCF;lK+#22zx8Hs&GgW)I5BWrlRa=&Z&n2Zt(`#Y0W-KnxrX7>>%`5ECxLyB zKy@&!^L)A~19E9^2h2EZM1aEBlat8qqnXI-O*>E+`{D+pW5=kg%;g<)L&rdn{o`17 zj31mX=B*B>&en}2JA2Zk)HeD3>2%;R=ur3(xR~w~$(<<3n3aiG=#bvLB{&$!#mN6k z13CSfReK%Ea(f#n@dyl*e=ZhJwNS6G6cWZJCOVDZ<%tHqG2}1?=7OErC`~a?(0(*g z+b4IQ4iqX`EiiK~Mll(9_MflCe>MVIe1aV8EtnnwZ~4u6A=}+RiEjtljm_`ZN#~@K zHW`9>)A@m+iUH>?m#0aR`oe?pGDn*IgN=J+4BqgsPUm|gfWyMjj@^}7ALlz>#eILg zlRI`Ua`Ap=c*nxJTf!Vw1`ws~6S+n0%MC{BV<|m2@1dx85<1Y|yZZyLGnnsEkod&M z6WDyvjY84!8l$ZO45pF`npJmEPZTZu+WQ{?DJ5e+tk=0qWb{tRR6EhF zLHI>AwX|EyZQ03OS&aiE?ag|&R^7h4I9?2-oy+|!RL{5ba3ZO!;L$7Gy?n73T=I($ zx)V_yMF?_}$>wb74s3dHoabqn=AC|EFzkDYv9?#1F(qqZb=-f`A1+8vjCtapdo zbijV@MgO)YPWtqm|yn81y8>WewSH3oEHc$Gu9a~ zyD?aAz)FpL5tqAD955p`pK%Hypmit*h4oALR)iDjn={{#U0sP-h?maof1TlI%viAr z)$4j@*W>U5sfFxYZ zhx8mnhk?~M7iS$pLIQU}o9Y^JFuF=fT@^cgc*JXE#aBRFP7jlVoT=qEyBAoj#m}4}H z!O#DQ6NN<4zTPp^|6Q+-Omr@BAj{0PoqJ^`Js9dkf)?yHD$!gX=Ml$q4}B+}u>66~ zD!XJBmKJ-Yr6QN#>b`0Xz?;cPbQqSo<0=gpw(&hygIwC9lXFQKiLakf5lq%I5f@TX z7zRv|%}egxOyDg`8NGM*n)m~WKq{Pf&D8?g<>JJmb!z#-^im)(q!ZLFV9uR|HWy?F zl=M9^k_Ib6}ex8LmzzqW~MwAqQSEXsaKc3`NP$}xS|t9@BBUV|IWy=7=( z`_1#_jfI$7!a{w8*6t9VY=XVHL%$=x4FPuBn{o-rn(nf@K*q)(GXpeTU2^FWkTLPu z_c6|t#iYfRXbn|6?P39c^Cn<5A>>oeQ1^BiKtGJ#_qx6~5{8V^t_I=h= zaa#BNN_DU&P7m!FLD*82twj2SEQF!))76Ue@gN>NI->8_+yf{lPxFCkF{6<~ zstY49&{AxkD#hK~$F9CRAMuc%ajIWd?ta3@lvK;BOdr1R1h!I;kmVswqrwvgLrm`% z)f@8C?JSAWKnB~_<{Vtv__lMUB9=LnQs zm#rxAJqd8>4uMmm)5Xw4rb|;>XF=~X9cv+>zc+0YvuBisnaAn}7?MN42~819(q!=L z?O^Vo%2XqKX!MXRPE?3iMaV+!Mix`KDk^fYq9QwH*hjZ(4U{7_wy*EaS@V`C8`-Lqk#-T1;*mfBluI6g zzR7zWuILb6!S%$1rsgWPyO%?jCN%C)2GdR4{Wo;ISqonKxD@-t-fY5}tos^pMF zl+Bnkl`TrT#JKJ1ZPnM79-XcB_7pLRs$g}JthWyGB`9&OJU2O=_1|fh3q`*zS;eU0 z3rhxPA+Eph-homM>Sk6p$oHPxM*wfx)UMSlt8QBn1~DBx>fAhnXSwxwt~#p!QAB6t zO*%alp%x7i{k?R5Hml)Q;t}#aUSmptc&ffwNUxS<#ZU-sjRwRR z^y#lgL09r94ZeZ9^4<^NS1S;jNvjOzSd%hy0%sxkye-Xkx@(n@DCOeqLYDYdIL5-iM71WJ#g>L zd8RQp&Y6lW3ZW3%Wgq>FpE8Ro)q`Gb#JlAkh$i6aw)Pn&ENLbYV37!omXEy&3wt$e z1QVaF>~cfPPLf*gKT=(`2a-OR4A%~7YmD=DPO=p;C@VBRX>BN~*<%c*&E2`t+V$|G z7|9ANAGk*^Enf(8TPlZ&6pohkrVv6UDYAxdt3NZxf^f1zU}&2-vcDzoi=DXVaYn+# zK!*VBY;DmmZp(asJKGiL$*w;Yp_w^V-)AB%wlYCR;?Q7f1$$|4N$Lsb zLQ(5>=-Y{}imy}-@$sKm#6?xhR42+!=c{8ajxY}3$ITNo!&%7ME1ASrxG325>>+6j z5h)dc&xn!NOZZQG8~Kw zTZ>vzq3$Ky5QX8AgC%{Z4c~ePEH<;cCOQ4vKB`3B5t3(KNF^c)E8?G$%C<{dD6wZpkfviJA;nX_KGL!R2^z;!h{-fLHL9vQa0Cq~i%PXCp zjiR6UbexE}M79)%A|##0Rh~6V2<4kD@q4-N9j+N&nHXiVUF(w8X3+hc)z4^#RQ;Lf z559;cUAF<6HSC#+D2Nx9m#|d8wbt9?qE7MS9?Dp~{YB+723IRWeg_8ZDBxtCrXb^) zDWyS8od$_+6KGNDp?u_*r{@u+pvP6+@?i9{9lP!3m{$3T;Og)BtvI$XWEefvT}P;7 z3Ca#7B$J(b{L@Yc^_6wc#4kNL&?VRdPARxP+_8|<8*b}F)bov73RCGMyge3TD20>c z+u-8PF+}Z5JDoiO5*lywGi`#Va;45^@b=l1ZFB{o4E3JR*uZ5?@B5~$bh3WS>%E4Kxk)dMtkP*r`&CJ9eSk)!e%}*~@+sJs8ji z<@&mr$s~*I*(dRXeVrA^52hs!6}(Oo%`Oj^Vg-uK8{P@`pNr%omx%H^>-M4}5I0`I zTq4E|mMLrAu`fM}wvV^2%dcEt_v{B}Gj_K}6Qjpn9b${(RkyheK_k!07~^4VHF#X% zeSq$V+jN4TEY>hIv6+dGB{bpfU|t)u8nPh{K^YpuYw13z*cV+R>0b+_cop1ewIgktYAyAswl6P=T0W{}!xJ$>>@clxg7JK_9BV{vz z@$?ZO42X}B~xTuDMQ^l-eJd#BMaIMxJD!e%g`mv zrc5fNYzTOB5}P6U>(wW3s$2?MnBb;Y2rAb0V*n^rx3_co$q5}Ii>?OB2?8+2zO*xYu!Scs%g^dd0mzAF&17zC`F7*RWIw=Ek5_p>W3fl6cXiPP+_Gr0QL-)Sc~sN7p=D^KF7kEZN%0Dk;!-a6U*`PZ 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 z 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 + 1`. Higher guidance scale encourages to generate images that are closely linked to the text `prompt`, + usually at the expense of lower image quality. + num_images_per_prompt (`int`, *optional*, defaults to 1): + The number of images to generate per prompt. + generator (`torch.Generator` or `List[torch.Generator]`, *optional*): + One or a list of [torch generator(s)](https://pytorch.org/docs/stable/generated/torch.Generator.html) + to make generation deterministic. + latents (`torch.FloatTensor`, *optional*): + Pre-generated noisy latents, sampled from a Gaussian distribution, to be used as inputs for image + generation. Can be used to tweak the same generation with different prompts. If not provided, a latents + tensor will ge generated by sampling using the supplied random `generator`. + prompt_embeds (`torch.FloatTensor`, *optional*): + Pre-generated text embeddings. Can be used to easily tweak text inputs, *e.g.* prompt weighting. If not + provided, text embeddings will be generated from `prompt` input argument. + pooled_prompt_embeds (`torch.FloatTensor`, *optional*): + Pre-generated pooled text embeddings. Can be used to easily tweak text inputs, *e.g.* prompt weighting. + If not provided, pooled text embeddings will be generated from `prompt` input argument. + output_type (`str`, *optional*, defaults to `"pil"`): + The output format of the generate image. Choose between + [PIL](https://pillow.readthedocs.io/en/stable/): `PIL.Image.Image` or `np.array`. + return_dict (`bool`, *optional*, defaults to `True`): + Whether or not to return a [`~pipelines.flux.FluxPipelineOutput`] instead of a plain tuple. + joint_attention_kwargs (`dict`, *optional*): + A kwargs dictionary that if specified is passed along to the `AttentionProcessor` as defined under + `self.processor` in + [diffusers.models.attention_processor](https://github.com/huggingface/diffusers/blob/main/src/diffusers/models/attention_processor.py). + callback_on_step_end (`Callable`, *optional*): + A function that calls at the end of each denoising steps during the inference. The function is called + with the following arguments: `callback_on_step_end(self: DiffusionPipeline, step: int, timestep: int, + callback_kwargs: Dict)`. `callback_kwargs` will include a list of all tensors as specified by + `callback_on_step_end_tensor_inputs`. + callback_on_step_end_tensor_inputs (`List`, *optional*): + The list of tensor inputs for the `callback_on_step_end` function. The tensors specified in the list + will be passed as `callback_kwargs` argument. You will only be able to include variables listed in the + `._callback_tensor_inputs` attribute of your pipeline class. + max_sequence_length (`int` defaults to 512): Maximum sequence length to use with the `prompt`. + + Examples: + + Returns: + [`~pipelines.flux.FluxPipelineOutput`] or `tuple`: [`~pipelines.flux.FluxPipelineOutput`] if `return_dict` + is True, otherwise a `tuple`. When returning a tuple, the first element is a list with the generated + images. + """ + + height = height or self.default_sample_size * self.vae_scale_factor + width = width or self.default_sample_size * self.vae_scale_factor + + # 1. Check inputs. Raise error if not correct + self.check_inputs( + prompt, + prompt_2, + height, + width, + prompt_embeds=prompt_embeds, + pooled_prompt_embeds=pooled_prompt_embeds, + callback_on_step_end_tensor_inputs=callback_on_step_end_tensor_inputs, + max_sequence_length=max_sequence_length, + ) + + self._guidance_scale = guidance_scale + self._joint_attention_kwargs = joint_attention_kwargs + self._interrupt = False + + # 2. Define call parameters + if prompt is not None and isinstance(prompt, str): + batch_size = 1 + elif prompt is not None and isinstance(prompt, list): + batch_size = len(prompt) + else: + batch_size = prompt_embeds.shape[0] + + device = self._execution_device + + # 3. Prepare text embeddings + lora_scale = ( + self.joint_attention_kwargs.get("scale", None) if self.joint_attention_kwargs is not None else None + ) + ( + prompt_embeds, + pooled_prompt_embeds, + text_ids, + ) = self.encode_prompt( + prompt=prompt, + prompt_2=prompt_2, + prompt_embeds=prompt_embeds, + pooled_prompt_embeds=pooled_prompt_embeds, + device=device, + num_images_per_prompt=num_images_per_prompt, + max_sequence_length=max_sequence_length, + lora_scale=lora_scale, + ) + + # 4. Prepare latent variables + num_channels_latents = self.transformer.config.in_channels // 4 + + # only prepare latents for non controls + # (16 + 1 + 16 ) + num_control_channels = 33 + num_channels_latents = num_channels_latents - num_control_channels + + control_latents = None + inpaint_latents = None + inpaint_latents_mask = None + + latent_height = height // self.vae_scale_factor + latent_width = width // self.vae_scale_factor + + # process the control and inpaint channels + + if control_image is None: + control_latents = torch.zeros( + batch_size * num_images_per_prompt, + 16, + latent_height, + latent_width, + device=device, + dtype=self.vae.dtype, + ) + else: + control_image = self.prepare_image( + image=control_image, + width=width, + height=height, + batch_size=batch_size * num_images_per_prompt, + num_images_per_prompt=num_images_per_prompt, + device=device, + dtype=self.vae.dtype, + ) + control_image = self.vae.encode(control_image).latent_dist.sample(generator=generator) + control_latents = (control_image - self.vae.config.shift_factor) * self.vae.config.scaling_factor + + # apply control strength + control_latents = control_latents * control_strength + + if inpaint_image is None and inpaint_mask is None: + inpaint_latents = torch.zeros( + batch_size * num_images_per_prompt, + 16, + latent_height, + latent_width, + device=device, + dtype=self.vae.dtype, + ) + inpaint_latents_mask = torch.ones( + batch_size * num_images_per_prompt, + 1, + latent_height, + latent_width, + device=device, + dtype=self.vae.dtype, + ) + else: + inpaint_image = self.prepare_image( + image=inpaint_image, + width=width, + height=height, + batch_size=batch_size * num_images_per_prompt, + num_images_per_prompt=num_images_per_prompt, + device=device, + dtype=self.vae.dtype, + ) + inpaint_image = self.vae.encode(inpaint_image).latent_dist.sample(generator=generator) + inpaint_latents = (inpaint_image - self.vae.config.shift_factor) * self.vae.config.scaling_factor + height_inpaint_image, width_inpaint_image = control_image.shape[2:] + + inpaint_mask = self.prepare_image( + image=inpaint_mask, + width=width, + height=height, + batch_size=batch_size * num_images_per_prompt, + num_images_per_prompt=num_images_per_prompt, + device=device, + dtype=self.vae.dtype, + ) + # mask is 3 ch -1 to 1. make it 1ch, 0 to 1 + inpaint_mask = inpaint_mask[:, 0:1, :, :] * 0.5 + 0.5 + # resize to match height_inpaint_image and width_inpaint_image + inpaint_latents_mask = F.interpolate(inpaint_mask, size=(height_inpaint_image, width_inpaint_image), mode="bilinear", align_corners=False) + + # apply inverted mask to inpaint latents + inpaint_latents = inpaint_latents * (1 - inpaint_latents_mask) + + # concat the latent controls on the channel dimension every step + latent_controls = torch.cat([inpaint_latents, inpaint_latents_mask, control_latents], dim=1) + latent_no_controls = torch.cat([inpaint_latents, inpaint_latents_mask, torch.zeros_like(control_latents)], dim=1) + + # pack the controls + height_latent_controls, width_latent_controls = latent_controls.shape[2:] + packed_latent_controls = self._pack_latents( + latent_controls, + batch_size * num_images_per_prompt, + num_control_channels, + height_latent_controls, + width_latent_controls, + ) + packed_latent_no_controls = self._pack_latents( + latent_no_controls, + batch_size * num_images_per_prompt, + num_control_channels, + height_latent_controls, + width_latent_controls, + ) + + latents, latent_image_ids = self.prepare_latents( + batch_size * num_images_per_prompt, + num_channels_latents, + height, + width, + prompt_embeds.dtype, + device, + generator, + latents, + ) + + # 5. Prepare timesteps + sigmas = np.linspace(1.0, 1 / num_inference_steps, num_inference_steps) if sigmas is None else sigmas + image_seq_len = latents.shape[1] + mu = calculate_shift( + image_seq_len, + self.scheduler.config.get("base_image_seq_len", 256), + self.scheduler.config.get("max_image_seq_len", 4096), + self.scheduler.config.get("base_shift", 0.5), + self.scheduler.config.get("max_shift", 1.15), + ) + timesteps, num_inference_steps = retrieve_timesteps( + self.scheduler, + num_inference_steps, + device, + sigmas=sigmas, + mu=mu, + ) + num_warmup_steps = max(len(timesteps) - num_inference_steps * self.scheduler.order, 0) + self._num_timesteps = len(timesteps) + + # handle guidance + if self.transformer.config.guidance_embeds: + guidance = torch.full([1], guidance_scale, device=device, dtype=torch.float32) + guidance = guidance.expand(latents.shape[0]) + else: + guidance = None + + control_cutoff = int(len(timesteps) * control_stop) + + # 6. Denoising loop + with self.progress_bar(total=num_inference_steps) as progress_bar: + for i, t in enumerate(timesteps): + if self.interrupt: + continue + + control_latents = packed_latent_controls if i < control_cutoff else packed_latent_no_controls + + latent_model_input = torch.cat([latents, control_latents], dim=2) + + # broadcast to batch dimension in a way that's compatible with ONNX/Core ML + timestep = t.expand(latents.shape[0]).to(latents.dtype) + + noise_pred = self.transformer( + hidden_states=latent_model_input, + timestep=timestep / 1000, + guidance=guidance, + pooled_projections=pooled_prompt_embeds, + encoder_hidden_states=prompt_embeds, + txt_ids=text_ids, + img_ids=latent_image_ids, + joint_attention_kwargs=self.joint_attention_kwargs, + return_dict=False, + )[0] + + # compute the previous noisy sample x_t -> x_t-1 + latents_dtype = latents.dtype + latents = self.scheduler.step(noise_pred, t, latents, return_dict=False)[0] + + if latents.dtype != latents_dtype: + if torch.backends.mps.is_available(): + # some platforms (eg. apple mps) misbehave due to a pytorch bug: https://github.com/pytorch/pytorch/pull/99272 + latents = latents.to(latents_dtype) + + if callback_on_step_end is not None: + callback_kwargs = {} + for k in callback_on_step_end_tensor_inputs: + callback_kwargs[k] = locals()[k] + callback_outputs = callback_on_step_end(self, i, t, callback_kwargs) + + latents = callback_outputs.pop("latents", latents) + prompt_embeds = callback_outputs.pop("prompt_embeds", prompt_embeds) + + # call the callback, if provided + if i == len(timesteps) - 1 or ((i + 1) > num_warmup_steps and (i + 1) % self.scheduler.order == 0): + progress_bar.update() + + if output_type == "latent": + image = latents + else: + latents = self._unpack_latents(latents, height, width, self.vae_scale_factor) + latents = (latents / self.vae.config.scaling_factor) + self.vae.config.shift_factor + image = self.vae.decode(latents, return_dict=False)[0] + image = self.image_processor.postprocess(image, output_type=output_type) + + # Offload all models + self.maybe_free_model_hooks() + + if not return_dict: + return (image,) + + return FluxPipelineOutput(images=image) diff --git a/modules/model_flex.py b/modules/model_flex.py new file mode 100644 index 000000000..721ac785a --- /dev/null +++ b/modules/model_flex.py @@ -0,0 +1,88 @@ +import os +import transformers +import diffusers +from huggingface_hub import auth_check +from modules import shared, devices, sd_models, model_quant, modelloader, sd_hijack_te + + +def load_transformer(repo_id, diffusers_load_config={}): + load_args, quant_args = model_quant.get_dit_args(diffusers_load_config, module='Transformer', device_map=True) + fn = None + + if shared.opts.sd_unet is not None and shared.opts.sd_unet != 'Default': + from modules import sd_unet + if shared.opts.sd_unet not in list(sd_unet.unet_dict): + shared.log.error(f'Load module: type=Transformer not found: {shared.opts.sd_unet}') + return None + fn = sd_unet.unet_dict[shared.opts.sd_unet] if os.path.exists(sd_unet.unet_dict[shared.opts.sd_unet]) else None + + if fn is not None and 'gguf' in fn.lower(): + shared.log.error('Load model: type=HiDream format="gguf" unsupported') + transformer = None + from modules import ggml + transformer = ggml.load_gguf(fn, cls=diffusers.HiDreamImageTransformer2DModel, compute_dtype=devices.dtype) + elif fn is not None and 'safetensors' in fn.lower(): + shared.log.debug(f'Load model: type=FLEX transformer="{repo_id}" quant="{model_quant.get_quant(repo_id)}" args={load_args}') + transformer = diffusers.FluxTransformer2DModel.from_single_file(fn, cache_dir=shared.opts.hfcache_dir, **load_args) + # elif model_quant.check_nunchaku('Transformer'): + # shared.log.error(f'Load model: type=HiDream transformer="{repo_id}" quant="Nunchaku" unsupported') + # transformer = None + else: + shared.log.debug(f'Load model: type=FLEX transformer="{repo_id}" quant="{model_quant.get_quant_type(quant_args)}" args={load_args}') + transformer = diffusers.FluxTransformer2DModel.from_pretrained( + repo_id, + subfolder="transformer", + cache_dir=shared.opts.hfcache_dir, + **load_args, + **quant_args, + ) + if shared.opts.diffusers_offload_mode != 'none' and transformer is not None: + sd_models.move_model(transformer, devices.cpu) + return transformer + + +def load_text_encoders(repo_id, diffusers_load_config={}): + load_args, quant_args = model_quant.get_dit_args(diffusers_load_config, module='TE', device_map=True) + shared.log.debug(f'Load model: type=FLEX t5="{repo_id}" quant="{model_quant.get_quant_type(quant_args)}" args={load_args}') + text_encoder_2 = transformers.T5EncoderModel.from_pretrained( + repo_id, + subfolder="text_encoder_2", + cache_dir=shared.opts.hfcache_dir, + **load_args, + **quant_args, + ) + if shared.opts.diffusers_offload_mode != 'none' and text_encoder_2 is not None: + sd_models.move_model(text_encoder_2, devices.cpu) + return text_encoder_2 + + +def load_flex(checkpoint_info, diffusers_load_config={}): + repo_id = sd_models.path_to_repo(checkpoint_info.name) + login = modelloader.hf_login() + try: + auth_check(repo_id) + except Exception as e: + shared.log.error(f'Load model: repo="{repo_id}" login={login} {e}') + return False + + transformer = load_transformer(repo_id, diffusers_load_config) + text_encoder_2 = load_text_encoders(repo_id, diffusers_load_config) + + load_args, _quant_args = model_quant.get_dit_args(diffusers_load_config, module='Model') + shared.log.debug(f'Load model: type=FLEX model="{checkpoint_info.name}" repo="{repo_id}" offload={shared.opts.diffusers_offload_mode} dtype={devices.dtype} args={load_args}') + + from modules.flex2 import Flex2Pipeline + pipe = Flex2Pipeline.from_pretrained( + repo_id, + # custom_pipeline=repo_id, + transformer=transformer, + text_encoder_2=text_encoder_2, + cache_dir=shared.opts.diffusers_dir, + **load_args, + ) + sd_hijack_te.init_hijack(pipe) + del text_encoder_2 + del transformer + + devices.torch_gc() + return pipe diff --git a/modules/modeldata.py b/modules/modeldata.py index 6f3314644..ae3e560ad 100644 --- a/modules/modeldata.py +++ b/modules/modeldata.py @@ -27,7 +27,7 @@ def get_model_type(pipe): model_type = 'sc' elif "AuraFlow" in name: model_type = 'auraflow' - elif "Flux" in name: + elif "Flux" in name or "Flex.1" or "Flex.2": model_type = 'f1' elif "Lumina2" in name: model_type = 'lumina2' diff --git a/modules/modelloader.py b/modules/modelloader.py index 8c5932477..7bbb4f341 100644 --- a/modules/modelloader.py +++ b/modules/modelloader.py @@ -379,12 +379,16 @@ def get_reference_opts(name: str, quiet=False): model_opts = {} name = name.replace('Diffusers/', 'huggingface/') for k, v in shared.reference_models.items(): - model_name = os.path.splitext(v.get('path', '').split('@')[0])[0] + model_name = v.get('path', '') if k == name or model_name == name: model_opts = v break - model_name = model_name.replace('huggingface/', '') - if k == name or model_name == name: + model_name_split = os.path.splitext(model_name.split('@')[0])[0] + if k == name or model_name_split == name: + model_opts = v + break + model_name_replace = model_name.replace('huggingface/', '') + if k == name or model_name_replace == name: model_opts = v break if not model_opts: diff --git a/modules/sd_detect.py b/modules/sd_detect.py index 5ba1293af..4a40453cd 100644 --- a/modules/sd_detect.py +++ b/modules/sd_detect.py @@ -96,6 +96,8 @@ def detect_pipeline(f: str, op: str = 'model', warning=True, quiet=False): guess = 'FLUX' if size > 11000 and size < 16000: warn(f'Model detected as FLUX UNET model, but attempting to load a base model: {op}={f} size={size} MB') + if 'flex.2' in f.lower(): + guess = 'FLEX' # guess for diffusers index = os.path.join(f, 'model_index.json') if os.path.exists(index) and os.path.isfile(index): @@ -103,7 +105,7 @@ def detect_pipeline(f: str, op: str = 'model', warning=True, quiet=False): cls = index.get('_class_name', None) if cls is not None: pipeline = getattr(diffusers, cls) - if 'Flux' in pipeline.__name__: + if 'Flux' in pipeline.__name__ and guess != 'FLEX': guess = 'FLUX' if 'StableDiffusion3' in pipeline.__name__: guess = 'Stable Diffusion 3' diff --git a/modules/sd_models.py b/modules/sd_models.py index 510fff7ea..4e7664d6d 100644 --- a/modules/sd_models.py +++ b/modules/sd_models.py @@ -309,6 +309,9 @@ def load_diffuser_force(model_type, checkpoint_info, diffusers_load_config, op=' elif model_type in ['FLUX']: from modules.model_flux import load_flux sd_model = load_flux(checkpoint_info, diffusers_load_config) + elif model_type in ['FLEX']: + from modules.model_flex import load_flex + sd_model = load_flex(checkpoint_info, diffusers_load_config) elif model_type in ['Lumina 2']: from modules.model_lumina import load_lumina2 sd_model = load_lumina2(checkpoint_info, diffusers_load_config) diff --git a/modules/shared_items.py b/modules/shared_items.py index f51609a7d..4e818fec1 100644 --- a/modules/shared_items.py +++ b/modules/shared_items.py @@ -20,6 +20,7 @@ pipelines = { 'HunyuanDiT': getattr(diffusers, 'HunyuanDiTPipeline', None), 'DeepFloyd IF': getattr(diffusers, 'IFPipeline', None), 'FLUX': getattr(diffusers, 'FluxPipeline', None), + 'FLEX': getattr(diffusers, 'AutoPipelineForText2Image', None), 'Sana': getattr(diffusers, 'SanaPipeline', None), 'Lumina-Next': getattr(diffusers, 'LuminaText2ImgPipeline', None), 'Lumina 2': getattr(diffusers, 'Lumina2Text2ImgPipeline', None), diff --git a/wiki b/wiki index 3c26f7806..f07c96ffc 160000 --- a/wiki +++ b/wiki @@ -1 +1 @@ -Subproject commit 3c26f780697422f2fc296273d5a90416c941067a +Subproject commit f07c96ffce44bbec5b89fbd7960354fec770e64b