Files
kantsche f7086236d2 Version 2
Lots of new stuff
2025-04-29 10:05:35 +02:00

649 lines
25 KiB
Python

import torch
def mix_teamfft(pred, weights, cfgs):
# First, get shape information from the first model's predictions
_, _, h, w = pred[0][0].shape
# Initialize an empty tensor in frequency domain for the result
fft_mix = torch.zeros_like(torch.fft.rfft2(pred[0][1]))
postuncond = None
# First loop: mix the unconditioned predictions in frequency domain
for i in range(len(pred)):
# Convert unconditional prediction to frequency domain
fft_u_pred = torch.fft.rfft2(pred[i][1])
# Add weighted contribution
fft_mix = fft_mix + fft_u_pred * weights[i]
postuncond = torch.fft.irfft2(fft_mix, s=(h, w))
# Second loop: apply the guidance in frequency domain
for i in range(len(pred)):
# Convert conditional and unconditional predictions to frequency domain
fft_c_pred = torch.fft.rfft2(pred[i][0])
fft_u_pred = torch.fft.rfft2(pred[i][1])
# Apply the CFG formula in frequency domain
fft_mix = fft_mix + (fft_c_pred - fft_u_pred) * cfgs[i]
# Convert the final result back to spatial domain
mix = torch.fft.irfft2(fft_mix, s=(h, w))
return mix, postuncond
def mix_teamfft4freq(pred, weights, cfgs):
# Get shape information from the first model's predictions
_, _, h, w = pred[0][0].shape
# Initialize an empty tensor in frequency domain for the result
fft_mix = torch.zeros_like(torch.fft.rfft2(pred[0][1]))
# Get frequency domain dimensions
freq_h, freq_w = fft_mix.shape[2], fft_mix.shape[3]
# Create frequency band masks - dividing into 4 frequency bands
# Low, low-mid, high-mid, and high frequencies
masks = []
# Calculate coordinates for frequency space
h_coords = torch.linspace(0, 1, freq_h, device=fft_mix.device)
w_coords = torch.linspace(0, 1, freq_w, device=fft_mix.device)
h_grid, w_grid = torch.meshgrid(h_coords, w_coords, indexing='ij')
# Calculate frequency magnitude (distance from DC component)
freq_magnitude = torch.sqrt(h_grid**2 + w_grid**2)
# Normalize to [0,1] range
max_freq = torch.sqrt(torch.tensor(2.0, device=fft_mix.device))
normalized_freq = freq_magnitude / max_freq
# Define frequency band boundaries
band_boundaries = [0.0, 0.25, 0.5, 0.75, 1.0]
# Create masks for each frequency band with smooth transitions
transition_width = 0.05 # 5% transition width
for i in range(4): # 4 frequency bands
band_start = band_boundaries[i]
band_end = band_boundaries[i+1]
# Calculate transition regions
trans_start = max(0.0, band_start - transition_width/2)
trans_end = min(1.0, band_end + transition_width/2)
# Create mask
mask = torch.zeros_like(normalized_freq)
# Full strength in the main band region
main_region = (normalized_freq >= band_start) & (normalized_freq <= band_end)
mask = torch.where(main_region, torch.ones_like(mask), mask)
# Smooth transition at the start of the band
if band_start > 0:
start_trans = (normalized_freq >= trans_start) & (normalized_freq < band_start)
mask = torch.where(
start_trans,
(normalized_freq - trans_start) / (band_start - trans_start),
mask
)
# Smooth transition at the end of the band
if band_end < 1.0:
end_trans = (normalized_freq > band_end) & (normalized_freq <= trans_end)
mask = torch.where(
end_trans,
1.0 - (normalized_freq - band_end) / (trans_end - band_end),
mask
)
masks.append(mask)
# Ensure masks sum to 1.0 at each point for perfect reconstruction
mask_sum = sum(masks)
masks = [m / (mask_sum + 1e-8) for m in masks] # Add small epsilon to avoid division by zero
uncondresult = torch.zeros_like(fft_mix)
postuncond = None
# Process each frequency band separately
for band_idx in range(4):
band_mix = torch.zeros_like(fft_mix)
# First loop: mix the unconditioned predictions in this frequency band
for i in range(len(pred)):
# Convert unconditional prediction to frequency domain
fft_u_pred = torch.fft.rfft2(pred[i][1])
# Add weighted contribution for this frequency band
band_mix = band_mix + fft_u_pred * weights[i] * masks[band_idx]
uncondresult = uncondresult + band_mix
# Second loop: apply the guidance in this frequency band
for i in range(len(pred)):
# Convert conditional and unconditional predictions to frequency domain
fft_c_pred = torch.fft.rfft2(pred[i][0])
fft_u_pred = torch.fft.rfft2(pred[i][1])
# Apply the CFG formula in this frequency band
band_mix = band_mix + (fft_c_pred - fft_u_pred) * cfgs[i] * masks[band_idx]
# Add this band's contribution to the final mix
fft_mix = fft_mix + band_mix
postuncond = torch.fft.irfft2(uncondresult, s=(h, w))
# Convert the final result back to spatial domain
mix = torch.fft.irfft2(fft_mix, s=(h, w))
return mix, postuncond
def mix_bandfft(pred, weights, cfgs, bands=2):
# Get shape information from the first model's predictions
_, _, h, w = pred[0][0].shape
# Initialize an empty tensor in frequency domain for the result
fft_mix = torch.zeros_like(torch.fft.rfft2(pred[0][1]))
# Get frequency domain dimensions
freq_h, freq_w = fft_mix.shape[2], fft_mix.shape[3]
# Create frequency band masks - dividing into 4 frequency bands
# Low, low-mid, high-mid, and high frequencies
masks = []
# Calculate coordinates for frequency space
h_coords = torch.linspace(0, 1, freq_h, device=fft_mix.device)
w_coords = torch.linspace(0, 1, freq_w, device=fft_mix.device)
h_grid, w_grid = torch.meshgrid(h_coords, w_coords, indexing='ij')
# Calculate frequency magnitude (distance from DC component)
freq_magnitude = torch.sqrt(h_grid**2 + w_grid**2)
# Normalize to [0,1] range
max_freq = torch.sqrt(torch.tensor(2.0, device=fft_mix.device))
normalized_freq = freq_magnitude / max_freq
#calculate the number of bands boundaries from bands size
band_boundaries = [0.0]
for i in range(bands-1):
band_boundaries.append(band_boundaries[-1] + 1.0 / bands)
band_boundaries.append(1.0)
# Create masks for each frequency band with smooth transitions
transition_width = 0.01 # 1% transition width
for i in range(bands): # 4 frequency bands
band_start = band_boundaries[i]
band_end = band_boundaries[i+1]
# Calculate transition regions
trans_start = max(0.0, band_start - transition_width/2)
trans_end = min(1.0, band_end + transition_width/2)
# Create mask
mask = torch.zeros_like(normalized_freq)
# Full strength in the main band region
main_region = (normalized_freq >= band_start) & (normalized_freq <= band_end)
mask = torch.where(main_region, torch.ones_like(mask), mask)
# Smooth transition at the start of the band
if band_start > 0:
start_trans = (normalized_freq >= trans_start) & (normalized_freq < band_start)
mask = torch.where(
start_trans,
(normalized_freq - trans_start) / (band_start - trans_start),
mask
)
# Smooth transition at the end of the band
if band_end < 1.0:
end_trans = (normalized_freq > band_end) & (normalized_freq <= trans_end)
mask = torch.where(
end_trans,
1.0 - (normalized_freq - band_end) / (trans_end - band_end),
mask
)
masks.append(mask)
# Ensure masks sum to 1.0 at each point for perfect reconstruction
mask_sum = sum(masks)
masks = [m / (mask_sum + 1e-8) for m in masks] # Add small epsilon to avoid division by zero
uncondresult = torch.zeros_like(fft_mix)
postuncond = None
# Process each frequency band separately
for band_idx in range(bands):
band_mix = torch.zeros_like(fft_mix)
# First loop: mix the unconditioned predictions in this frequency band
for i in range(len(pred)):
# Convert unconditional prediction to frequency domain
fft_u_pred = torch.fft.rfft2(pred[i][1])
# Add weighted contribution for this frequency band
band_mix = band_mix + fft_u_pred * weights[i] * masks[band_idx]
uncondresult = uncondresult + band_mix
# Second loop: apply the guidance in this frequency band
for i in range(len(pred)):
# Convert conditional and unconditional predictions to frequency domain
fft_c_pred = torch.fft.rfft2(pred[i][0])
fft_u_pred = torch.fft.rfft2(pred[i][1])
# Apply the CFG formula in this frequency band
band_mix = band_mix + (fft_c_pred - fft_u_pred) * cfgs[i] * masks[band_idx]
# Add this band's contribution to the final mix
fft_mix = fft_mix + band_mix
postuncond = torch.fft.irfft2(uncondresult, s=(h, w))
# Convert the final result back to spatial domain
mix = torch.fft.irfft2(fft_mix, s=(h, w))
return mix, postuncond
def mix_2model_fft(pred, weights, cfgs, ratio):
# Apply FFT-based frequency splitting
# Need at least 2 models for FFT mode
if len(pred) < 2:
mix = pred[0][0] * cfgs[0] + pred[0][1] * (1 - cfgs[0])
return mix, None # Return properly conditioned prediction
# Get shapes from first prediction
_, _, h, w = pred[0][0].shape
# Use the first model for low frequencies and second model for high frequencies
# Extract predictions from first model
c_pred_1 = pred[0][0] # Conditioned prediction
u_pred_1 = pred[0][1] # Unconditioned prediction
# Extract predictions from second model
c_pred_2 = pred[1][0] # Conditioned prediction
u_pred_2 = pred[1][1] # Unconditioned prediction
# Convert to frequency domain
fft_u_pred_1 = torch.fft.rfft2(u_pred_1)
fft_c_pred_1 = torch.fft.rfft2(c_pred_1)
fft_u_pred_2 = torch.fft.rfft2(u_pred_2)
fft_c_pred_2 = torch.fft.rfft2(c_pred_2)
# Use weight of first model as frequency split ratio
# Ensure ratio is between 0.05 and 0.95 to guarantee some frequency coverage for both models
split_ratio = max(0.05, min(0.95, abs(ratio)))
# Calculate frequency split point
split_h = int(h * split_ratio)
split_w = int(w * split_ratio / 2) # rfft2 returns half the width in frequency domain
# Create masks for low and high frequencies
mask_low = torch.ones_like(fft_u_pred_1, dtype=torch.float32)
mask_high = torch.ones_like(fft_u_pred_1, dtype=torch.float32)
# Create transition area for smooth blending
transition_h = max(1, int(h * 0.05)) # 5% transition zone
transition_w = max(1, int(w * 0.05 / 2)) # 5% transition zone
# Set high frequencies to zero in low mask with smooth transition
for i in range(mask_low.shape[2]):
for j in range(mask_low.shape[3]):
if i >= split_h + transition_h or j >= split_w + transition_w:
mask_low[:, :, i, j] = 0.0
elif i >= split_h or j >= split_w:
# Calculate smooth transition value
fade_h = 1.0 - min(1.0, (i - split_h) / transition_h) if i >= split_h else 1.0
fade_w = 1.0 - min(1.0, (j - split_w) / transition_w) if j >= split_w else 1.0
mask_low[:, :, i, j] = fade_h * fade_w
# Set low frequencies to zero in high mask with inverse smooth transition
for i in range(mask_high.shape[2]):
for j in range(mask_high.shape[3]):
if i <= split_h - transition_h and j <= split_w - transition_w:
mask_high[:, :, i, j] = 0.0
elif i <= split_h or j <= split_w:
# Calculate smooth transition value - inverse of the low mask
fade_h = min(1.0, (split_h - i) / transition_h) if i <= split_h else 0.0
fade_w = min(1.0, (split_w - j) / transition_w) if j <= split_w else 0.0
mask_high[:, :, i, j] = 1.0 - (fade_h * fade_w)
# Ensure masks sum to 1.0 at each point for full spectrum coverage
mask_sum = mask_low + mask_high
mask_low = mask_low / mask_sum
mask_high = mask_high / mask_sum
result = fft_u_pred_1 * mask_low + fft_u_pred_2 * mask_high
postuncond = torch.fft.irfft2(result, s=(h, w))
# Apply masks and compute CFG in frequency domain using the corresponding CFG values
fft_result_low = (fft_u_pred_1 * mask_low) + ((fft_c_pred_1 - fft_u_pred_1) * cfgs[0] * mask_low)
fft_result_high = (fft_u_pred_2 * mask_high) + ((fft_c_pred_2 - fft_u_pred_2) * cfgs[1] * mask_high)
# Combine low and high frequency results
fft_result = fft_result_low + fft_result_high
# Convert back to spatial domain
mix = torch.fft.irfft2(fft_result, s=(h, w))
return mix, postuncond
def create_low_freq_mask(shape, radius):
rows, cols = shape
crow, ccol = rows // 2, cols // 2 # center
# Create coordinate grids
y, x = torch.meshgrid(torch.arange(rows), torch.arange(cols), indexing='ij')
# Distance from center
dist_from_center = torch.sqrt((x - ccol)**2 + (y - crow)**2)
# Create mask: 1 inside radius, 0 outside
mask = torch.zeros((rows, cols))
mask[dist_from_center <= radius] = 1
return mask
def mix_2m2f(pred, weights, cfgs, ratio):
# Split the prediction into low frequency and high frequency components
# ratio controls the cutoff frequency between low and high
# Need at least 2 models for this mode
if len(pred) < 2:
mix = pred[0][0] * cfgs[0] + pred[0][1] * (1 - cfgs[0])
return mix, None # Return properly conditioned prediction
# Get shapes from first prediction
_, _, h, w = pred[0][0].shape
# Extract predictions from first model (handles low frequencies)
c_pred_low = pred[0][0] # Conditioned prediction for low frequencies
u_pred_low = pred[0][1] # Unconditioned prediction for low frequencies
# Extract predictions from second model (handles high frequencies)
c_pred_high = pred[1][0] # Conditioned prediction for high frequencies
u_pred_high = pred[1][1] # Unconditioned prediction for high frequencies
# Convert to frequency domain
fft_c_low = torch.fft.rfft2(c_pred_low)
fft_u_low = torch.fft.rfft2(u_pred_low)
fft_c_high = torch.fft.rfft2(c_pred_high)
fft_u_high = torch.fft.rfft2(u_pred_high)
# Get frequency domain dimensions
freq_h, freq_w = fft_c_low.shape[2], fft_c_low.shape[3]
# Create normalized coordinate grids
h_coords = torch.linspace(0, 1, freq_h, device=fft_c_low.device)
w_coords = torch.linspace(0, 1, freq_w, device=fft_c_low.device)
h_grid, w_grid = torch.meshgrid(h_coords, w_coords, indexing='ij')
# Calculate frequency magnitude (normalized distance from DC component)
freq_magnitude = torch.sqrt(h_grid**2 + w_grid**2)
max_freq = torch.sqrt(torch.tensor(2.0, device=fft_c_low.device))
normalized_freq = freq_magnitude / max_freq
# Create frequency masks with smooth transition around cutoff
cutoff = ratio # Frequency cutoff point (normalized)
transition_width = 0.05 # Width of transition band for smooth blending
# Create low frequency mask (1 for low frequencies, 0 for high)
low_mask = torch.ones_like(normalized_freq)
# Create smooth transition where freq > (cutoff - transition_width/2)
transition_start = cutoff - transition_width/2
transition_end = cutoff + transition_width/2
# Apply smooth transition
transition_region = (normalized_freq >= transition_start) & (normalized_freq <= transition_end)
low_mask[transition_region] = 0.5 - 0.5 * torch.sin(
torch.pi * (normalized_freq[transition_region] - cutoff) / transition_width
)
low_mask[normalized_freq > transition_end] = 0.0
# High frequency mask is complement of low frequency mask
high_mask = 1.0 - low_mask
# Add batch and channel dimensions to masks
low_mask = low_mask.unsqueeze(0).unsqueeze(0)
high_mask = high_mask.unsqueeze(0).unsqueeze(0)
# Separate frequency components
# Low frequency unconditioned prediction
fft_u_result = fft_u_low * low_mask + fft_u_high * high_mask
# Convert unconditioned result back to spatial domain for returning
postuncond = torch.fft.irfft2(fft_u_result, s=(h, w))
# Apply CFG separately to low and high frequency components
fft_low_result = fft_u_low * low_mask + (fft_c_low - fft_u_low) * cfgs[0] * low_mask
fft_high_result = fft_u_high * high_mask + (fft_c_high - fft_u_high) * cfgs[1] * high_mask
# Combine frequency components
fft_result = fft_low_result + fft_high_result
# Convert back to spatial domain
mix = torch.fft.irfft2(fft_result, s=(h, w))
return mix, postuncond
def mix_fft_overlap(pred, weights, cfgs, ratio):
# Split each model into its own frequency band with overlap - optimized version
_, _, h, w = pred[0][0].shape
# Initialize result in frequency domain
fft_result = torch.zeros_like(torch.fft.rfft2(pred[0][0]))
# Convert all predictions to frequency domain
fft_c_preds = []
fft_u_preds = []
valid_weights = []
valid_cfgs = []
for i in range(len(pred)):
if weights[i] <= 0:
continue
# Extract predictions for this model
c_pred = pred[i][0]
u_pred = pred[i][1]
# Convert to frequency domain
fft_c_preds.append(torch.fft.rfft2(c_pred))
fft_u_preds.append(torch.fft.rfft2(u_pred))
valid_weights.append(weights[i])
valid_cfgs.append(cfgs[i])
# Get number of valid models
num_models = len(valid_weights)
if num_models == 0:
# Handle edge case with no valid models
default_mix = pred[0][0] * cfgs[0] + pred[0][1] * (1 - cfgs[0])
return default_mix, None # Return first model's conditioned output
elif num_models == 1:
# With only one model, use it for the full spectrum
mix = pred[0][0] * valid_cfgs[0] + pred[0][1] * (1 - valid_cfgs[0])
return mix, None
# Calculate frequency coordinates
freq_h, freq_w = fft_result.shape[2], fft_result.shape[3]
# Create normalized coordinate grids - vectorized
h_coords = torch.linspace(0, 1, freq_h, device=fft_result.device)
w_coords = torch.linspace(0, 1, freq_w, device=fft_result.device)
# Create meshgrid of coordinates
h_grid, w_grid = torch.meshgrid(h_coords, w_coords, indexing='ij')
# Calculate frequency magnitude for all points
freq_magnitude = torch.sqrt(h_grid**2 + w_grid**2)
# Normalize frequency magnitude to range [0, 1]
max_freq = torch.sqrt(torch.tensor(2.0, device=fft_result.device)) # Maximum possible frequency magnitude
normalized_freq = freq_magnitude / max_freq
# Define overlap ratio (0.2 means 20% overlap between bands)
overlap_ratio = ratio
# Calculate band width for each model, accounting for overlap
band_width = (1.0 + overlap_ratio) / num_models
# Calculate frequency masks for each model - vectorized
model_masks = []
for i in range(num_models):
# Calculate band start and end points
band_start = max(0.0, i * band_width - (overlap_ratio * band_width / 2))
band_end = min(1.0, (i + 1) * band_width + (overlap_ratio * band_width / 2))
# Create initial mask where freq is within the band
mask = torch.zeros_like(normalized_freq)
in_band = (normalized_freq >= band_start) & (normalized_freq <= band_end)
# Define transition regions
start_trans = band_start + (overlap_ratio * band_width / 2)
end_trans = band_end - (overlap_ratio * band_width / 2)
# Create mask for different regions
full_region = (normalized_freq >= start_trans) & (normalized_freq <= end_trans)
start_region = (normalized_freq >= band_start) & (normalized_freq < start_trans)
end_region = (normalized_freq > end_trans) & (normalized_freq <= band_end)
# Set full strength in middle region
mask[full_region] = 1.0
# Calculate and set smooth transitions at edges
if torch.any(start_region):
trans_width = start_trans - band_start
mask[start_region] = (normalized_freq[start_region] - band_start) / trans_width
if torch.any(end_region):
trans_width = band_end - end_trans
mask[end_region] = (band_end - normalized_freq[end_region]) / trans_width
model_masks.append(mask)
# Stack masks for easier normalization
stacked_masks = torch.stack(model_masks)
# Normalize masks to ensure they sum to 1.0 across all models
sum_masks = torch.sum(stacked_masks, dim=0)
sum_masks = torch.clamp(sum_masks, min=1e-10)
# Normalize each mask
normalized_stacked_masks = stacked_masks / sum_masks
uncondresult = torch.zeros_like(fft_result)
# Apply CFG to each frequency band and combine - vectorized
for i in range(num_models):
# Get mask, add batch and channel dimensions
mask = normalized_stacked_masks[i].unsqueeze(0).unsqueeze(0)
# Apply CFG formula with frequency band mask
fft_u = fft_u_preds[i]
uncondresult = uncondresult + fft_u
fft_c = fft_c_preds[i]
cfg_scale = valid_cfgs[i]
# Add weighted contribution to result
fft_result += (fft_u + (fft_c - fft_u) * cfg_scale) * mask
postuncond = torch.fft.irfft2(uncondresult, s=(h, w))
# Convert back to spatial domain
mix = torch.fft.irfft2(fft_result, s=(h, w))
return mix, postuncond
def mix_fft_full(pred, weights, cfgs):
# Full spectrum frequency mixing implementation - optimized version
_, _, h, w = pred[0][0].shape
# Initialize result in frequency domain
fft_result = torch.zeros_like(torch.fft.rfft2(pred[0][0]))
# First, convert all predictions to frequency domain
fft_c_preds = []
fft_u_preds = []
valid_model_indices = []
for i in range(len(pred)):
if weights[i] <= 0:
# Add placeholders for zero-weight models
fft_c_preds.append(None)
fft_u_preds.append(None)
continue
# Extract predictions for this model
c_pred = pred[i][0]
u_pred = pred[i][1]
# Convert to frequency domain
fft_c_preds.append(torch.fft.rfft2(c_pred))
fft_u_preds.append(torch.fft.rfft2(u_pred))
valid_model_indices.append(i)
# Calculate frequency coordinates
frequency_h, frequency_w = fft_result.shape[2], fft_result.shape[3]
# Create normalized coordinate grids (vectorized)
h_coords = torch.arange(frequency_h, device=fft_result.device).float() / frequency_h
w_coords = torch.arange(frequency_w, device=fft_result.device).float() / frequency_w
# Create meshgrid of coordinates
h_grid, w_grid = torch.meshgrid(h_coords, w_coords, indexing='ij')
# Calculate frequency magnitude for all points at once
freq_magnitude = torch.sqrt(h_grid**2 + w_grid**2)
uncondresult = torch.zeros_like(fft_result)
# Process each valid model
if valid_model_indices:
# Pre-calculate model weights for all frequency points
all_model_weights = []
for i in valid_model_indices:
# Calculate model influence: higher weights → lower frequencies, lower weights → higher frequencies
model_weight = weights[i] * (1.0 - freq_magnitude) + (1.0 - weights[i]) * freq_magnitude
all_model_weights.append(model_weight)
# Convert to tensor for easier operations
all_model_weights = torch.stack(all_model_weights)
# Normalize weights along model dimension
weight_sum = all_model_weights.sum(dim=0, keepdim=True)
# Avoid division by zero
weight_sum = torch.clamp(weight_sum, min=1e-10)
normalized_weights = all_model_weights / weight_sum
# Apply weights and CFG to each frequency component
for idx, i in enumerate(valid_model_indices):
# Get model weights for this model
model_weights = normalized_weights[idx]
# Apply weights to each frequency point (broadcasting)
model_weights = model_weights.unsqueeze(0).unsqueeze(0) # Add batch and channel dimensions
# Get unconditioned and conditioned predictions
fft_u = fft_u_preds[i]
uncondresult = uncondresult + fft_u
fft_c = fft_c_preds[i]
# Apply CFG with model-specific weight
contrib = fft_u * model_weights + (fft_c - fft_u) * cfgs[i] * model_weights
# Add to result
fft_result += contrib
postuncond = torch.fft.irfft2(uncondresult, s=(h, w))
# Convert back to spatial domain
mix = torch.fft.irfft2(fft_result, s=(h, w))
return mix, postuncond