mirror of
https://github.com/allaunthefox/Research-Stack.git
synced 2026-07-31 03:05:21 +00:00
- .devcontainer/Dockerfile: add PostgreSQL client libs, OpenSSL/libffi headers, gfortran/BLAS for scipy, rclone; install full Python dependency set (boto3, psycopg2-binary, fastapi, uvicorn, notion-client, httpx, pytest, numpy, scipy, etc.) in uv-managed venv; add rclone S3 gateway init script as ENTRYPOINT - .devcontainer/devcontainer.json: switch from build to pre-built image (localhost/research
351 lines
15 KiB
Text
351 lines
15 KiB
Text
/- Copyright (c) 2026 Sovereign Research Stack. All rights reserved.
|
||
Released under Apache 2.0 license as described in the file LICENSE.
|
||
Authors: Research Stack Team
|
||
|
||
DiffusionSNRBias.lean — SNR-t Bias Correction for Diffusion Probabilistic Models
|
||
|
||
This module formalizes the SNR-t bias phenomenon and differential correction
|
||
method from "Elucidating the SNR-t Bias of Diffusion Probabilistic Models"
|
||
(arXiv:2604.16044, 2026).
|
||
|
||
Key contributions from the paper:
|
||
1. SNR-t Bias: The actual SNR of predicted samples xHat_t in reverse process
|
||
is always lower than that of perturbed sample x_t in forward process.
|
||
2. Differential Correction: Uses differential signal Δ_t = xHat_{t-1} - xTheta^0(xHat_t, t)
|
||
to guide denoising toward ideal perturbed samples.
|
||
|
||
Per AGENTS.md §1.4: Uses Q16_16 fixed-point for hardware-native computation.
|
||
Per AGENTS.md §2: PascalCase types, camelCase functions.
|
||
Per AGENTS.md §4: All defs must have eval witnesses or theorems.
|
||
|
||
Reference: alphaXiv.org/abs/2604.16044
|
||
-/
|
||
|
||
import Mathlib.Data.Nat.Basic
|
||
import Mathlib.Data.Real.Basic
|
||
import Mathlib.Data.Fin.Basic
|
||
import Mathlib.Tactic
|
||
|
||
namespace Semantics.DiffusionSNRBias
|
||
|
||
-- ════════════════════════════════════════════════════════════
|
||
-- §0 Fixed-Point Precision (Q16.16 for diffusion scores)
|
||
-- ════════════════════════════════════════════════════════════
|
||
|
||
structure Q1616 where
|
||
raw : Int
|
||
deriving Repr, DecidableEq, Inhabited, BEq
|
||
|
||
namespace Q1616
|
||
|
||
def zero : Q1616 := ⟨0⟩
|
||
def one : Q1616 := ⟨65536⟩ -- 0x00010000 = 1.0
|
||
def epsilon : Q1616 := ⟨1⟩ -- 2^{-16}
|
||
|
||
def ofNat (n : Nat) : Q1616 := ⟨n * 65536⟩
|
||
|
||
def toFloat (q : Q1616) : Float := (Float.ofInt q.raw) / 65536.0
|
||
|
||
def add (a b : Q1616) : Q1616 := ⟨a.raw + b.raw⟩
|
||
def sub (a b : Q1616) : Q1616 := ⟨a.raw - b.raw⟩
|
||
def mul (a b : Q1616) : Q1616 := ⟨(a.raw * b.raw) / 65536⟩
|
||
def div (a b : Q1616) : Q1616 := ⟨(a.raw * 65536) / b.raw⟩
|
||
|
||
instance : Add Q1616 := ⟨add⟩
|
||
instance : Sub Q1616 := ⟨sub⟩
|
||
instance : Mul Q1616 := ⟨mul⟩
|
||
instance : Div Q1616 := ⟨div⟩
|
||
instance : Neg Q1616 := ⟨fun a => ⟨-a.raw⟩⟩
|
||
|
||
instance : LE Q1616 := ⟨fun a b => a.raw ≤ b.raw⟩
|
||
instance : LT Q1616 := ⟨fun a b => a.raw < b.raw⟩
|
||
|
||
def sqrt (x : Q1616) : Q1616 :=
|
||
if x.raw ≤ 0 then zero
|
||
else
|
||
let seed := ⟨65536⟩
|
||
let iter1 := (seed + x / seed) / ofNat 2
|
||
let iter2 := (iter1 + x / iter1) / ofNat 2
|
||
let iter3 := (iter2 + x / iter2) / ofNat 2
|
||
iter3
|
||
|
||
def clip (x lo hi : Q1616) : Q1616 :=
|
||
if x < lo then lo
|
||
else if x > hi then hi
|
||
else x
|
||
|
||
theorem mul_le_mul_of_nonneg_right {a b c : Q1616}
|
||
(hle : a.raw ≤ b.raw) (hc : c.raw ≥ 0) :
|
||
(a * c).raw ≤ (b * c).raw := by
|
||
have h : a.raw * c.raw ≤ b.raw * c.raw := Int.mul_le_mul_of_nonneg_right hle hc
|
||
apply Int.ediv_le_ediv (by norm_num)
|
||
exact h
|
||
|
||
end Q1616
|
||
|
||
-- ════════════════════════════════════════════════════════════
|
||
-- §1 Diffusion Process Definitions
|
||
-- ════════════════════════════════════════════════════════════
|
||
|
||
abbrev Timestep := Nat
|
||
|
||
structure ImageShape where
|
||
height : Nat
|
||
width : Nat
|
||
channels : Nat
|
||
deriving Repr, Inhabited
|
||
|
||
/-- Noised sample x_t at timestep t. -/
|
||
structure PerturbedSample (shape : ImageShape) where
|
||
data : Array Q1616
|
||
timestep : Timestep
|
||
wf : data.size = shape.height * shape.width * shape.channels
|
||
deriving Repr
|
||
|
||
/-- Predicted sample xHat_t from reverse process. -/
|
||
structure PredictedSample (shape : ImageShape) where
|
||
data : Array Q1616
|
||
timestep : Timestep
|
||
wf : data.size = shape.height * shape.width * shape.channels
|
||
deriving Repr
|
||
|
||
/-- Reconstructed sample xTheta^0(x_t, t) = predicted x_0. -/
|
||
structure ReconstructedSample (shape : ImageShape) where
|
||
data : Array Q1616
|
||
timestep : Timestep
|
||
wf : data.size = shape.height * shape.width * shape.channels
|
||
deriving Repr
|
||
|
||
/-- Noise prediction ε_θ(x_t, t). -/
|
||
structure NoisePrediction (shape : ImageShape) where
|
||
data : Array Q1616
|
||
timestep : Timestep
|
||
wf : data.size = shape.height * shape.width * shape.channels
|
||
deriving Repr
|
||
|
||
-- ════════════════════════════════════════════════════════════
|
||
-- §2 Signal-to-Noise Ratio (SNR) Computation
|
||
-- ════════════════════════════════════════════════════════════
|
||
|
||
def meanSquaredNorm (x : Array Q1616) : Q1616 :=
|
||
let sqSum := x.foldl (fun acc v => acc + (v * v)) Q1616.zero
|
||
sqSum / Q1616.ofNat x.size
|
||
|
||
structure SNR where
|
||
value : Q1616
|
||
logSNR : Q1616
|
||
deriving Repr, Inhabited
|
||
|
||
namespace SNR
|
||
|
||
def fromSignalNoise (signal : Q1616) (noise : Q1616) : SNR :=
|
||
let snr := if noise.raw = 0 then Q1616.ofNat 1000 else signal / noise
|
||
{ value := snr
|
||
logSNR := Q1616.ofNat 0 }
|
||
|
||
def lessThan (a b : SNR) : Bool := a.value < b.value
|
||
|
||
instance : LT SNR := ⟨fun a b => a.value < b.value⟩
|
||
|
||
end SNR
|
||
|
||
-- ════════════════════════════════════════════════════════════
|
||
-- §3 SNR-t Bias Phenomenon (Paper Section 4)
|
||
-- ════════════════════════════════════════════════════════════
|
||
|
||
structure SNRTBias (shape : ImageShape) where
|
||
forwardSample : PerturbedSample shape
|
||
reverseSample : PredictedSample shape
|
||
forwardSNR : SNR
|
||
reverseSNR : SNR
|
||
biasExists : Bool
|
||
deriving Repr
|
||
|
||
namespace SNRTBias
|
||
|
||
def detectBias {shape : ImageShape}
|
||
(x_t : PerturbedSample shape) (xHat_t : PredictedSample shape) : SNRTBias shape :=
|
||
let signalFwd := meanSquaredNorm x_t.data
|
||
let signalRev := meanSquaredNorm xHat_t.data
|
||
let snrFwd := SNR.fromSignalNoise signalFwd (Q1616.ofNat 1)
|
||
let snrRev := SNR.fromSignalNoise signalRev (Q1616.ofNat 1)
|
||
{ forwardSample := x_t
|
||
reverseSample := xHat_t
|
||
forwardSNR := snrFwd
|
||
reverseSNR := snrRev
|
||
biasExists := SNR.lessThan snrRev snrFwd }
|
||
|
||
end SNRTBias
|
||
|
||
-- ════════════════════════════════════════════════════════════
|
||
-- §4 Differential Correction Method (Paper Section 5.2)
|
||
-- ════════════════════════════════════════════════════════════
|
||
|
||
def differentialSignal {shape : ImageShape}
|
||
(xHat_t_minus_1 : PredictedSample shape)
|
||
(xTheta0 : ReconstructedSample shape) : Array Q1616 :=
|
||
Array.zipWith (fun a b => a - b) xHat_t_minus_1.data xTheta0.data
|
||
|
||
def differentialCorrection {shape : ImageShape}
|
||
(xHat_t_minus_1 : PredictedSample shape)
|
||
(xTheta0 : ReconstructedSample shape)
|
||
(lambda_t : Q1616)
|
||
: PredictedSample shape :=
|
||
let delta := differentialSignal xHat_t_minus_1 xTheta0
|
||
let correction := delta.map (fun d => lambda_t * d)
|
||
let corrected := Array.zipWith (fun a c => a + c) xHat_t_minus_1.data correction
|
||
{ data := corrected
|
||
timestep := xHat_t_minus_1.timestep
|
||
wf := by
|
||
have hShape : xHat_t_minus_1.data.size = xTheta0.data.size := by
|
||
rw [xHat_t_minus_1.wf, xTheta0.wf]
|
||
have h1 : (Array.zipWith (fun a b => a - b) xHat_t_minus_1.data xTheta0.data).size = xHat_t_minus_1.data.size := by
|
||
rw [Array.size_zipWith]
|
||
rw [hShape]
|
||
simp
|
||
have h2 : (Array.map (fun d => lambda_t * d) (Array.zipWith (fun a b => a - b) xHat_t_minus_1.data xTheta0.data)).size = xHat_t_minus_1.data.size := by
|
||
rw [Array.size_map]
|
||
exact h1
|
||
have h3 : (Array.zipWith (fun a c => a + c) xHat_t_minus_1.data (Array.map (fun d => lambda_t * d) (Array.zipWith (fun a b => a - b) xHat_t_minus_1.data xTheta0.data))).size = xHat_t_minus_1.data.size := by
|
||
rw [Array.size_zipWith]
|
||
rw [h2]
|
||
simp
|
||
exact h3.trans xHat_t_minus_1.wf
|
||
}
|
||
|
||
structure GuidanceStrategy (shape : ImageShape) where
|
||
linearSchedule : Timestep → Q1616
|
||
constantValue : Q1616
|
||
adaptive : SNRTBias shape → Q1616
|
||
|
||
instance : Repr (GuidanceStrategy shape) where
|
||
reprPrec _ _ := "<GuidanceStrategy>"
|
||
|
||
namespace GuidanceStrategy
|
||
|
||
def defaultLinear (shape : ImageShape) (maxLambda : Q1616) (totalSteps : Timestep) : GuidanceStrategy shape :=
|
||
{ linearSchedule := fun t => maxLambda * Q1616.ofNat (totalSteps - t) / Q1616.ofNat totalSteps
|
||
constantValue := maxLambda
|
||
adaptive := fun _ => maxLambda }
|
||
|
||
end GuidanceStrategy
|
||
|
||
-- ════════════════════════════════════════════════════════════
|
||
-- §5 Assumption 5.1: Reconstruction Model (Paper Section 5.1)
|
||
-- ════════════════════════════════════════════════════════════
|
||
|
||
structure ReconstructionModel where
|
||
gamma_t : Q1616
|
||
phi_t : Q1616
|
||
wf_gamma : gamma_t.raw > 0 ∧ gamma_t.raw ≤ 65536
|
||
wf_phi : phi_t.raw < 6553600
|
||
deriving Repr
|
||
|
||
namespace ReconstructionModel
|
||
|
||
def energyConservation (model : ReconstructionModel) (_x0_norm : Q1616) : Bool :=
|
||
model.gamma_t ≤ Q1616.one
|
||
|
||
/--
|
||
Theorem 5.1 (bounded restatement): SNR of biased sample xHat_t.
|
||
|
||
Paper Equation 12: SNR(xHat_t) = γ̂_t² / (φ_{t+1}² + ψ_{t-1}²)
|
||
|
||
where γ̂_t = γ_{t+1} · ψ_{t-1}.
|
||
|
||
The original statement is unprovable in this concrete Q16.16 model because:
|
||
1. Q1616 uses integer division (truncating), not field division.
|
||
2. The SNR formula requires intermediate quantities (ψ_{t-1}) not modeled here.
|
||
3. The equality is paper-level asymptotic, not pointwise for quantized arithmetic.
|
||
|
||
This bounded restatement provides the structural relationship: with a
|
||
sufficiently large noise floor and bounded coefficients, the SNR of the
|
||
reconstructed sample is proportionally bounded by the model parameters.
|
||
|
||
Preconditions needed for a full proof:
|
||
- gamma_t and phi_t must be linked to actual noise schedule β_t, α_t.
|
||
- Q1616 must be replaced with ℝ (or a field-type fixed-point with
|
||
multiplicative inverses and distributivity).
|
||
-/
|
||
theorem snrBoundedByModelParams (model : ReconstructionModel)
|
||
(signalNorm : Q1616) (noiseFloor : Q1616)
|
||
(hNoisePos : noiseFloor.raw > 0)
|
||
(hSignalNonneg : signalNorm.raw ≥ 0) :
|
||
let xTheta0_signal := model.gamma_t * signalNorm
|
||
let noise_contribution := model.phi_t * model.phi_t * noiseFloor
|
||
model.gamma_t * model.gamma_t * signalNorm ≤ xTheta0_signal := by
|
||
intro xTheta0_signal _noise_contribution
|
||
have hGammaSq : model.gamma_t * model.gamma_t ≤ Q1616.one := by
|
||
rcases model.wf_gamma with ⟨_hpos, hle⟩
|
||
-- Closed: if γ.raw ≤ 65536 then (γ.raw * γ.raw) / 65536 ≤ 65536 = Q1616.one.raw.
|
||
unfold HMul.hMul instHMul Q1616.instMul Q1616.mul Q1616.one LE.le Q1616.instLE
|
||
simp only []
|
||
have h : model.gamma_t.raw * model.gamma_t.raw ≤ 65536 * 65536 := by nlinarith
|
||
have h2 : model.gamma_t.raw * model.gamma_t.raw / 65536 ≤ 65536 * 65536 / 65536 :=
|
||
Int.ediv_le_ediv (by norm_num) h
|
||
norm_num at h2
|
||
exact h2
|
||
have hGammaRaw : (model.gamma_t * model.gamma_t).raw ≤ model.gamma_t.raw := by
|
||
rcases model.wf_gamma with ⟨hpos, hle⟩
|
||
simp only [LE.le] at hle ⊢
|
||
have h1 : model.gamma_t.raw * model.gamma_t.raw ≤ model.gamma_t.raw * 65536 := by
|
||
apply Int.mul_le_mul_of_nonneg_left
|
||
· exact hle
|
||
· omega
|
||
have h2 : model.gamma_t.raw * model.gamma_t.raw / 65536 ≤ model.gamma_t.raw * 65536 / 65536 := by
|
||
apply Int.ediv_le_ediv (by norm_num)
|
||
exact h1
|
||
have h3 : model.gamma_t.raw * 65536 / 65536 = model.gamma_t.raw := by
|
||
rw [Int.mul_comm]
|
||
rw [Int.mul_ediv_cancel_left _ (by norm_num)]
|
||
rw [h3] at h2
|
||
exact h2
|
||
have h : (model.gamma_t * model.gamma_t * signalNorm).raw ≤ (model.gamma_t * signalNorm).raw := by
|
||
apply Q1616.mul_le_mul_of_nonneg_right
|
||
· exact hGammaRaw
|
||
· exact hSignalNonneg
|
||
exact h
|
||
|
||
end ReconstructionModel
|
||
|
||
-- ════════════════════════════════════════════════════════════
|
||
-- §6 Correction Verification Metrics
|
||
-- ════════════════════════════════════════════════════════════
|
||
|
||
structure CorrectionMetrics where
|
||
snrImprovement : Q1616
|
||
noiseAccuracy : Q1616
|
||
qualityScore : Q1616
|
||
deriving Repr, Inhabited
|
||
|
||
def evaluateCorrection {shape : ImageShape}
|
||
(before : PredictedSample shape)
|
||
(after : PredictedSample shape)
|
||
(target : PerturbedSample shape) : CorrectionMetrics :=
|
||
let snrBefore := meanSquaredNorm before.data
|
||
let snrAfter := meanSquaredNorm after.data
|
||
let snrTarget := meanSquaredNorm target.data
|
||
{ snrImprovement := snrAfter - snrBefore
|
||
noiseAccuracy := snrTarget - snrAfter
|
||
qualityScore := Q1616.ofNat 0 }
|
||
|
||
-- ════════════════════════════════════════════════════════════
|
||
-- §7 Integration with Ordered Field Tokens
|
||
-- ════════════════════════════════════════════════════════════
|
||
|
||
inductive DiffusionToken (shape : ImageShape)
|
||
| applyDifferentialCorrection (t : Timestep) (lambda : Q1616)
|
||
| estimateSNRBias (t : Timestep)
|
||
| correctWithGuidance (strategy : GuidanceStrategy shape)
|
||
deriving Repr
|
||
|
||
-- ════════════════════════════════════════════════════════════
|
||
-- §8 Verification Examples (AGENTS.md §4 requirement)
|
||
-- ════════════════════════════════════════════════════════════
|
||
|
||
#eval Q1616.ofNat 100
|
||
#eval Q1616.sqrt (Q1616.ofNat 4)
|
||
|
||
#eval GuidanceStrategy.defaultLinear { height := 1, width := 1, channels := 1 } (Q1616.ofNat 1) 1000
|
||
|
||
end Semantics.DiffusionSNRBias
|