Source code for LION.reconstructors.diffusion.data_consistency

"""Shared adjoint data-consistency updates for diffusion reconstructors."""

from __future__ import annotations

import torch


[docs] class AdjointDataConsistency: """Apply adjoint measurement updates shared by diffusion samplers."""
[docs] def apply_adjoint_correction( self, x: torch.Tensor, residual: torch.Tensor, step_size: torch.Tensor, params, sigma: torch.Tensor, ) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor, float, float]: """Apply one scheduled adjoint correction to a padded sampler state.""" raw_correction = self.adjoint_project(residual).unsqueeze(0) data_normalizer = self.data_consistency_normalizer( params, raw_correction.device ) data_scale = self.scheduled_adjoint_data_consistency_scale( params, sigma, raw_correction.device ) correction = data_scale * raw_correction / data_normalizer if bool(params.disable_data_consistency): return x, correction, raw_correction, data_normalizer, data_scale pad = int(params.pad_width) if pad == 0: x = x + step_size * correction else: x = x.clone() x[:, :, pad:-pad, pad:-pad] += step_size * correction return x, correction, raw_correction, data_normalizer, data_scale
[docs] def adjoint_data_step_size( self, residual: torch.Tensor, sigma: torch.Tensor, params, *, public_repo_multiplier: bool, ) -> torch.Tensor: """Compute the paper or public-repository adjoint step size.""" if getattr(params, "data_consistency_gradient", "norm") == "least_squares": return torch.as_tensor( float(params.zeta), device=residual.device, dtype=residual.dtype ) residual_norm = torch.linalg.norm(residual).clamp_min(1e-12) step_size = float(params.zeta) / residual_norm schedule = getattr(params, "adjoint_data_step_schedule", "public_repo") if schedule == "paper": return step_size if schedule == "public_repo": if public_repo_multiplier: step_size = step_size * min(40.0, float(sigma.item()) * 200.0) return step_size raise ValueError("adjoint_data_step_schedule must be 'paper' or 'public_repo'.")