@@ -563,6 +563,65 @@ inline float flux_time_shift(float mu, float sigma, float t) {
563563 return ::expf (mu) / (::expf (mu) + ::powf ((1 .0f / t - 1 .0f ), sigma));
564564}
565565
566+ // https://github.com/black-forest-labs/flux/blob/main/src/flux/sampling.py#L289
567+ struct FluxScheduler : SigmaScheduler {
568+ int image_seq_len = 0 ;
569+ float base_shift = 0 .5f ;
570+ float max_shift = 1 .15f ;
571+
572+ explicit FluxScheduler (int image_seq_len, const char * extra_sample_args = nullptr )
573+ : image_seq_len(image_seq_len) {
574+ parse_extra_sample_args (extra_sample_args);
575+ }
576+
577+ void parse_extra_sample_args (const char * extra_sample_args) {
578+ for (const auto & [key, value] : parse_key_value_args (extra_sample_args, " flux scheduler arg" )) {
579+ if (key == " base_shift" ) {
580+ if (!parse_strict_float (value, base_shift)) {
581+ LOG_WARN (" ignoring invalid flux scheduler arg '%s=%s'" , key.c_str (), value.c_str ());
582+ }
583+ } else if (key == " max_shift" ) {
584+ if (!parse_strict_float (value, max_shift)) {
585+ LOG_WARN (" ignoring invalid flux scheduler arg '%s=%s'" , key.c_str (), value.c_str ());
586+ }
587+ }
588+ }
589+ }
590+
591+ float compute_mu () const {
592+ constexpr float base_shift_anchor = 256 .0f ;
593+ constexpr float max_shift_anchor = 4096 .0f ;
594+ float m = (max_shift - base_shift) / (max_shift_anchor - base_shift_anchor);
595+ float b = base_shift - m * base_shift_anchor;
596+ return static_cast <float >(image_seq_len) * m + b;
597+ }
598+
599+ std::vector<float > get_sigmas (uint32_t n, float /* sigma_min*/ , float /* sigma_max*/ , t_to_sigma_t /* t_to_sigma*/ ) override {
600+ std::vector<float > sigmas;
601+ sigmas.reserve (n + 1 );
602+
603+ float mu = compute_mu ();
604+ LOG_DEBUG (" Flux scheduler: image_seq_len=%d, steps=%u, mu=%.3f" , image_seq_len, n, mu);
605+
606+ if (n == 0 ) {
607+ sigmas.push_back (1 .0f );
608+ return sigmas;
609+ }
610+
611+ for (uint32_t i = 0 ; i <= n; ++i) {
612+ float t = 1 .0f - static_cast <float >(i) / static_cast <float >(n);
613+ if (t <= 0 .0f ) {
614+ sigmas.push_back (0 .0f );
615+ } else {
616+ sigmas.push_back (flux_time_shift (mu, 1 .0f , t));
617+ }
618+ }
619+
620+ sigmas[n] = 0 .0f ;
621+ return sigmas;
622+ }
623+ };
624+
566625// https://github.com/black-forest-labs/flux2/blob/main/src/flux2/sampling.py#L244
567626struct Flux2Scheduler : SigmaScheduler {
568627 int image_seq_len = 0 ;
@@ -886,6 +945,11 @@ struct Denoiser {
886945 scheduler = std::make_shared<Flux2Scheduler>(image_seq_len);
887946 break ;
888947 }
948+ case FLUX_SCHEDULER : {
949+ LOG_INFO (" get_sigmas with Flux scheduler" );
950+ scheduler = std::make_shared<FluxScheduler>(image_seq_len, extra_sample_args);
951+ break ;
952+ }
889953 default :
890954 LOG_INFO (" get_sigmas with discrete scheduler (default)" );
891955 scheduler = std::make_shared<DiscreteScheduler>();
0 commit comments