burt-imma / lean4 /SmoothLeakyActivation.lean
SNAPKITTYWEST's picture
push from SNAPKITTYWEST/burt-imma
b88c26d verified
Raw History Blame Contribute Delete
6.92 kB
/-
SmoothLeakyActivation
Smooth leaky activation function with bounded gradient properties
-/
import Mathlib
import Mathlib.Analysis.SpecialFunctions.Log.Basic
import Mathlib.Analysis.SpecialFunctions.Trigonometric.Basic
import Mathlib.Analysis.Calculus.Deriv.Basic
noncomputable section
open Real
-- ============================================================
-- Parameters
-- ============================================================
structure Params where
alpha : ℝ
beta : ℝ
h_alpha_pos : 0 < alpha
h_alpha_lt_one : alpha < 1
h_beta_pos : 0 < beta
-- ============================================================
-- Activation Function
-- Standard smooth leaky ReLU: f(x) = (1+Ξ±)/2 * x + (1-Ξ±)/2 * (1/Ξ²) * log(cosh(Ξ²x))
-- Derivative: f'(x) = (1+α)/2 + (1-α)/2 * tanh(βx) ∈ (α, 1)
-- ============================================================
/-- The smooth leaky activation function -/
def f (p : Params) (x : ℝ) : ℝ :=
(1 + p.alpha) / 2 * x + (1 - p.alpha) / 2 * (1 / p.beta) * Real.log (Real.cosh (p.beta * x))
/-- The derivative of the smooth leaky activation -/
def f' (p : Params) (x : ℝ) : ℝ :=
(1 + p.alpha) / 2 + (1 - p.alpha) / 2 * Real.tanh (p.beta * x)
-- ============================================================
-- Properties
-- ============================================================
/-- The gradient is always strictly positive -/
theorem deriv_pos (p : Params) : βˆ€ x : ℝ, f' p x > 0 := by
intro x
have h₁ : f' p x = (1 + p.alpha) / 2 + (1 - p.alpha) / 2 * Real.tanh (p.beta * x) := rfl
rw [h₁]
have hβ‚‚ : Real.tanh (p.beta * x) > -1 := Real.neg_one_lt_tanh (p.beta * x)
have hβ‚„ : 0 < p.alpha := p.h_alpha_pos
have hβ‚… : p.alpha < 1 := p.h_alpha_lt_one
have h₇ : 0 < 1 - p.alpha := by linarith
have hβ‚ˆ : 0 < 1 + p.alpha := by linarith
have h₁₀ : (1 + p.alpha) / 2 + (1 - p.alpha) / 2 * Real.tanh (p.beta * x) β‰₯
(1 + p.alpha) / 2 + (1 - p.alpha) / 2 * (-1) := by
have h₁₁ : Real.tanh (p.beta * x) β‰₯ -1 := by linarith
nlinarith
have h₁₁ : (1 + p.alpha) / 2 + (1 - p.alpha) / 2 * (-1 : ℝ) = p.alpha := by ring
linarith [p.h_alpha_pos]
/-- The gradient is bounded below 1 -/
theorem deriv_bounded (p : Params) : βˆ€ x : ℝ, f' p x < 1 := by
intro x
have h₁ : f' p x = (1 + p.alpha) / 2 + (1 - p.alpha) / 2 * Real.tanh (p.beta * x) := rfl
rw [h₁]
have hβ‚‚ : Real.tanh (p.beta * x) < 1 := Real.tanh_lt_one (p.beta * x)
have hβ‚… : p.alpha < 1 := p.h_alpha_lt_one
have h₇ : 0 < 1 - p.alpha := by linarith
have h₁₀ : (1 + p.alpha) / 2 + (1 - p.alpha) / 2 * Real.tanh (p.beta * x) <
(1 + p.alpha) / 2 + (1 - p.alpha) / 2 * (1 : ℝ) := by nlinarith
have h₁₁ : (1 + p.alpha) / 2 + (1 - p.alpha) / 2 * (1 : ℝ) = 1 := by ring
linarith
/-- As x β†’ +∞, f'(x) β†’ 1 -/
theorem deriv_limit_pos_inf (p : Params) :
Filter.Tendsto (f' p) Filter.atTop (nhds 1) := by
have htanh : Filter.Tendsto (fun x : ℝ => Real.tanh (p.beta * x)) Filter.atTop (nhds 1) := by
have hbeta : Filter.Tendsto (fun x : ℝ => p.beta * x) Filter.atTop Filter.atTop :=
Filter.Tendsto.atTop_mul_atTop (by linarith [p.h_beta_pos]) Filter.tendsto_id
exact Real.tendsto_tanh_atTop.comp hbeta
have : Filter.Tendsto (fun x : ℝ => (1 + p.alpha) / 2 + (1 - p.alpha) / 2 * Real.tanh (p.beta * x))
Filter.atTop (nhds ((1 + p.alpha) / 2 + (1 - p.alpha) / 2 * 1)) :=
Filter.Tendsto.const_add _ (Filter.Tendsto.const_mul _ htanh)
have heq : (1 + p.alpha) / 2 + (1 - p.alpha) / 2 * 1 = 1 := by ring
simp only [f']
rwa [heq] at this
/-- As x β†’ -∞, f'(x) β†’ alpha -/
theorem deriv_limit_neg_inf (p : Params) :
Filter.Tendsto (f' p) Filter.atBot (nhds p.alpha) := by
have htanh : Filter.Tendsto (fun x : ℝ => Real.tanh (p.beta * x)) Filter.atBot (nhds (-1)) := by
have hbeta : Filter.Tendsto (fun x : ℝ => p.beta * x) Filter.atBot Filter.atBot :=
Filter.Tendsto.atBot_mul_atBot (by linarith [p.h_beta_pos]) Filter.tendsto_id
exact Real.tendsto_tanh_atBot.comp hbeta
have : Filter.Tendsto (fun x : ℝ => (1 + p.alpha) / 2 + (1 - p.alpha) / 2 * Real.tanh (p.beta * x))
Filter.atBot (nhds ((1 + p.alpha) / 2 + (1 - p.alpha) / 2 * (-1))) :=
Filter.Tendsto.const_add _ (Filter.Tendsto.const_mul _ htanh)
have heq : (1 + p.alpha) / 2 + (1 - p.alpha) / 2 * (-1) = p.alpha := by ring
simp only [f']
rwa [heq] at this
/-- f is C^∞ (infinitely differentiable) -/
theorem smooth (p : Params) : ContDiff ℝ ⊀ (f p) := by
have h_lin : ContDiff ℝ ⊀ (fun x : ℝ => (1 + p.alpha) / 2 * x) :=
(contDiff_const.mul contDiff_id)
have h_cosh : ContDiff ℝ ⊀ (fun x : ℝ => Real.cosh (p.beta * x)) :=
Real.contDiff_cosh.comp (contDiff_const.mul contDiff_id)
have h_pos : βˆ€ x : ℝ, Real.cosh (p.beta * x) > 0 := fun x => Real.cosh_pos _
have h_log : ContDiff ℝ ⊀ (fun x : ℝ => Real.log (Real.cosh (p.beta * x))) :=
h_cosh.log (fun x => ne_of_gt (h_pos x))
have h_scaled : ContDiff ℝ ⊀ (fun x : ℝ => (1 - p.alpha) / 2 * (1 / p.beta) * Real.log (Real.cosh (p.beta * x))) :=
contDiff_const.mul h_log
simp only [f]
exact h_lin.add h_scaled
/-- f(x) < 0 for all x < 0 -/
theorem neg_range (p : Params) : βˆ€ x : ℝ, x < 0 β†’ f p x < 0 := by
intro x hx
simp only [f]
have hβ‚„ : 0 < p.beta := p.h_beta_pos
have hβ‚… : 0 < 1 + p.alpha := by linarith [p.h_alpha_pos]
have h₆ : 0 < 1 - p.alpha := by linarith [p.h_alpha_lt_one]
have h₇ : (0 : ℝ) < 1 / p.beta := by positivity
have hβ‚ˆ : Real.log (Real.cosh (p.beta * x)) β‰₯ 0 :=
Real.log_nonneg (Real.one_le_cosh _)
have h₉ : (1 + p.alpha) / 2 * x < 0 := by nlinarith
have h₁₂ : Real.log (Real.cosh (p.beta * x)) ≀ p.beta * |x| := by
have hle : Real.cosh (p.beta * x) ≀ Real.exp (p.beta * |x|) := by
calc Real.cosh (p.beta * x)
≀ Real.cosh (|p.beta * x|) := Real.cosh_abs _ β–Έ le_refl _
_ = Real.cosh (p.beta * |x|) := by
rw [abs_mul, abs_of_pos hβ‚„]
_ ≀ Real.exp (p.beta * |x|) := Real.cosh_le_exp _
linarith [Real.log_le_log (Real.cosh_pos _) hle,
Real.log_exp (p.beta * |x|)]
have h₁₃ : |x| = -x := abs_of_neg hx
rw [h₁₃] at h₁₂
have h₁₄ : (1 - p.alpha) / 2 * (1 / p.beta) * Real.log (Real.cosh (p.beta * x))
≀ (1 - p.alpha) / 2 * (-x) := by
have : (1 - p.alpha) / 2 * (1 / p.beta) * (p.beta * (-x)) = (1 - p.alpha) / 2 * (-x) := by
field_simp
nlinarith
have h₁₅ : (1 + p.alpha) / 2 * x + (1 - p.alpha) / 2 * (-x) = p.alpha * x := by ring
linarith [mul_neg_of_pos_of_neg p.h_alpha_pos hx]
/-- f(0) = 0 -/
theorem f_zero (p : Params) : f p 0 = 0 := by
simp [f, Real.cosh_zero, Real.log_one]
end