Skip to content

Latest commit

 

History

History
2066 lines (1689 loc) · 88.4 KB

File metadata and controls

2066 lines (1689 loc) · 88.4 KB

HSSMP3

System.put_env("XLA_BUILD", "true")

Mix.install([
  {:nx, "~> 0.11.0"},
  {:exla, "~> 0.11.0"},
  {:jason, "~> 1.4"}
])

System.put_env("HSA_OVERRIDE_GFX_VERSION", "11.0.0")
System.put_env("XLA_TARGET", "rocm")

# ⚡ 1. Disable the buggy AMD Fusion pass
System.put_env("TF_ROCM_FUSION_ENABLE", "0")

# ⚡ 2. Disable XLA Autotuning completely
System.put_env("XLA_FLAGS", "--xla_gpu_autotune_level=0 --xla_gpu_enable_reassociation_for_converted_ar=false --xla_gpu_graph_enable_concurrent_region=false")

System.put_env("ROCM_DISABLE_CU_MEMSET", "1")

Application.put_env(:exla, :clients,
  rocm: [
    platform: :rocm,
    memory_fraction: 0.75,  # ← force total claimed under 8GB
    preallocate: false,
    num_replicas: 1
  ]
)

System.put_env("XLA_PYTHON_CLIENT_MEM_FRACTION", "0.33")

Application.put_env(:exla, :default_client, :rocm)

gpu = {EXLA.Backend, client: :rocm}
Nx.global_default_backend(gpu)
Nx.Defn.default_options(compiler: EXLA)

platforms = EXLA.Client.get_supported_platforms()
if platforms[:rocm] do
  IO.puts("✅ AMD RX 7600 online!")
else
  IO.puts("❌ GPU missing — check HSA_OVERRIDE_GFX_VERSION")
end

Helpers

defmodule DLM.Positional do
  def build(len, dim) do
    i = Nx.iota({len, 1})
    d = Nx.iota({1, dim})
    dim_f = Nx.tensor(dim, type: :f32) # 🔥 Force float math
    Nx.sin(Nx.divide(i, Nx.pow(10000.0, Nx.divide(d, dim_f))))
  end
end
{:module, DLM.Positional, <<70, 79, 82, 49, 0, 0, 8, ...>>, {:build, 2}}
defmodule DLM.Tree do
  @moduledoc """
  Recursively maps a function over nested tuples of tensors.
  Works perfectly both in standard Elixir AND inside Nx `defn`.
  """
  
  def map(tuple, func) when is_tuple(tuple) do
    tuple
    |> Tuple.to_list()
    |> Enum.map(&map(&1, func))
    |> List.to_tuple()
  end

  # The base case: When it hits a tensor (or a compile-time Expr), apply the function
  def map(tensor, func) do
    func.(tensor)
  end
end
{:module, DLM.Tree, <<70, 79, 82, 49, 0, 0, 8, ...>>, {:map, 2}}
defmodule DLM.DataStreamer do
  def stream(path, seq_len, batch_size) do
    lines = path |> File.read!() |> String.split("\n", trim: true) |> Enum.shuffle()

    lines
    |> Enum.join("\n")
    |> to_charlist()
    |> Stream.chunk_every(seq_len + 1, seq_len, :discard)
    |> Stream.map(fn chunk ->
      ins = chunk |> Enum.take(seq_len) |> Nx.tensor(type: :s32)
      tgs = chunk |> Enum.drop(1)      |> Nx.tensor(type: :s32)
      {ins, tgs}
    end)
    |> Stream.chunk_every(batch_size, batch_size, :discard)
    |> Stream.map(fn batch ->
      {ins_list, tgs_list} = Enum.unzip(batch)
      {Nx.stack(ins_list), Nx.stack(tgs_list)}
    end)
  end

  @doc """
  Takes a massive 1D tensor of dataset tokens and creates an infinite stream
  of {batch_size, seq_len} matrices for the Physics Engine.
  """
  def build_infinite_stream(dataset_1d, batch_size, seq_len) do
    chunk_size = batch_size * seq_len
    total_tokens = Nx.size(dataset_1d)
    
    # Calculate how many full batches we can make
    total_batches = div(total_tokens, chunk_size)

    0..(total_batches - 1)
    |> Stream.cycle() # ⚡ Loops infinitely!
    |> Stream.map(fn batch_idx ->
      start_idx = batch_idx * chunk_size
      
      # Slice out the flat chunk and reshape it for the batch
      dataset_1d
      |> Nx.slice_along_axis(start_idx, chunk_size, axis: 0)
      |> Nx.reshape({batch_size, seq_len})
    end)
  end
end
{:module, DLM.DataStreamer, <<70, 79, 82, 49, 0, 0, 19, ...>>, {:build_infinite_stream, 3}}
defmodule DLM.Loss do
  import Nx.Defn

  defn cross_entropy(logits, targets) do
    vocab_size = Nx.axis_size(logits, -1)
    
    # Create a 1-hot vector for the correct answer
    one_hot = Nx.equal(Nx.iota({vocab_size}), Nx.new_axis(targets, -1))
    
    # Stable Log-Softmax
    max_logits = Nx.reduce_max(logits, axes: [-1], keep_axes: true)
    safe_logits = Nx.subtract(logits, max_logits)
    log_probs = Nx.subtract(safe_logits, Nx.log(Nx.sum(Nx.exp(safe_logits), axes: [-1], keep_axes: true)))
    
    # Cross Entropy calculation
    Nx.mean(Nx.negate(Nx.sum(Nx.multiply(one_hot, log_probs), axes: [-1])))
  end

  # ⚡ Universal L2 Normalizer (Works on 2D, 3D, N-D tensors)
  defn l2_normalize(tensor) do
    # Calculate Euclidean norm across the last axis natively
    norm = Nx.sqrt(Nx.sum(Nx.pow(tensor, 2), axes: [-1], keep_axes: true))
    # Divide by norm with a tiny epsilon to prevent divide-by-zero
    Nx.divide(tensor, Nx.add(norm, 1.0e-6))
  end

  # ⚡ 1. Angular Alignment (Cosine Distance)
  defn cosine_distance(pred, target) do
    p_norm = l2_normalize(pred)
    t_norm = l2_normalize(target)

    # Dot product across the 512 dimension
    cos_sim = Nx.sum(Nx.multiply(p_norm, t_norm), axes: [-1])
    
    # Minimize distance (1.0 - similarity)
    Nx.mean(Nx.subtract(1.0, cos_sim))
  end

  # ⚡ 2. Repulsion (Memory-Safe Batched Soft-NN for Rank 2 Tensors)
  defn soft_nn_loss(pred, target, temperature \\ 0.1) do
    # pred and target are {batch_size, dim}
    p_l2 = l2_normalize(pred)
    t_l2 = l2_normalize(target)

    # 1. Batched Dot Product: {batch, dim} x {dim, batch} -> {batch, batch}
    # This creates a similarity matrix comparing every pred to every target in the batch
    sim_tensor = Nx.dot(p_l2, Nx.transpose(t_l2))
    sim_tensor = Nx.divide(sim_tensor, temperature)

    # 2. Create Identity Targets -> {batch, batch}
    batch_size = Nx.axis_size(pred, 0)
    # ⚡ THE FIX: Pass a 2D tuple {32, 32} instead of a 1D tuple {32}
    labels = Nx.eye({batch_size, batch_size}, type: :f32)

    # 3. Manual Dense Log-Softmax
    # Step A: Max trick for numerical stability
    max_sim = Nx.reduce_max(sim_tensor, axes: [-1], keep_axes: true)
    shifted_sim = Nx.subtract(sim_tensor, max_sim)
    
    # Step B: Log(Sum(Exp))ozen_w2,
    log_sum_exp = Nx.log(Nx.sum(Nx.exp(shifted_sim), axes: [-1], keep_axes: true))
    log_softmax = Nx.subtract(shifted_sim, log_sum_exp)

    # Step C: -Sum(Targets * Log_Softmax)
    Nx.multiply(labels, log_softmax)
    |> Nx.sum(axes: [-1])
    |> Nx.negate()
    |> Nx.mean()
  end
end
{:module, DLM.Loss, <<70, 79, 82, 49, 0, 0, 27, ...>>, true}
defmodule DLM.SinkhornOT do
  import Nx.Defn

  defn cost_matrix(pred, target) do
    p_exp = Nx.new_axis(pred, 1)
    t_exp = Nx.new_axis(target, 0)
    diff = Nx.subtract(p_exp, t_exp)
    Nx.sum(Nx.pow(diff, 2), axes: [-1])
  end

  # ⚡ FIX 1: Bump the default epsilon up to 10.0 to handle your 512D spatial scale
  defn compute(pred, target, epsilon \\ 10.0, max_iters \\ 5) do
    c = cost_matrix(pred, target)
    k = Nx.exp(Nx.divide(Nx.negate(c), epsilon))
    
    batch_size = Nx.axis_size(pred, 0)
    mass = 1.0 / batch_size
    mu = Nx.broadcast(mass, {batch_size})
    nu = Nx.broadcast(mass, {batch_size})

    {_final_k, u_final, v_final, _mu, _nu, _i} =
      while {k_mat = k, 
             u = Nx.broadcast(1.0, {batch_size}), 
             _v = Nx.broadcast(1.0, {batch_size}), 
             m = mu, n = nu, i = 0},
            Nx.less(i, max_iters) do
            
        # ⚡ FIX 2: Add 1.0e-8 to the denominator to mathematically prevent NaN crashes
        denom_v = Nx.add(Nx.dot(Nx.transpose(k_mat), u), 1.0e-8)
        v_new = Nx.divide(n, denom_v)
        
        denom_u = Nx.add(Nx.dot(k_mat, v_new), 1.0e-8)
        u_new = Nx.divide(m, denom_u)

        {k_mat, u_new, v_new, m, n, i + 1}
      end

    u_exp = Nx.new_axis(u_final, 1)
    v_exp = Nx.new_axis(v_final, 0)
    p = Nx.multiply(Nx.multiply(u_exp, k), v_exp)

    Nx.sum(Nx.multiply(p, c))
  end
end
{:module, DLM.SinkhornOT, <<70, 79, 82, 49, 0, 0, 25, ...>>, true}

Main SSM

defmodule DLM.Main_SSM do
  import Nx.Defn

  defn swish(x) do
    x * Nx.sigmoid(x)
  end

  defn rms_norm(x, epsilon \\ 1.0e-6) do
    variance = Nx.mean(Nx.pow(x, 2), axes: [-1], keep_axes: true)
    x * Nx.rsqrt(variance + epsilon)
  end

  defn softplus(x) do
    # ⚡ UNBREAKABLE SOFTPLUS: Guaranteed stable in forward AND backward passes
    Nx.max(x, 0.0) + Nx.log1p(Nx.exp(-Nx.abs(x)))
  end

  defn apply_svd_weight(x, u, v) do
    x |> Nx.dot(u) |> softplus() |> Nx.dot(v)
  end

  # ⚡ The core physics step (Used heavily by the new Master Loop)
  defn ssm_recurrence(x_t, x_p1, x_p2, h_prev, a, bu, bv, cu, cv, du, dv, mu1, mv1, mu2, mv2) do
    # 1. Local Mixers
    mix1 = apply_svd_weight(x_p2, mu1, mv1)
    mix2 = apply_svd_weight(x_p1, mu2, mv2)
    x_mixed = Nx.add(x_t, Nx.add(mix1, mix2))
    
    # 2. Input Force
    b_proj = apply_svd_weight(x_mixed, bu, bv)
    delta = Nx.tensor(0.1, type: :f32)
    
    # 3. Friction
    a_bar = Nx.exp(Nx.multiply(delta, -Nx.abs(a)))
    b_bar = Nx.multiply(delta, b_proj)
    
    # 4. Momentum Update
    h_new = Nx.tanh(Nx.add(Nx.multiply(a_bar, h_prev), b_bar))
    
    # 5. Output Velocity
    out_proj = apply_svd_weight(h_new, cu, cv)
    
    # 6. Skip Connection
    skip = apply_svd_weight(x_t, du, dv)
    
    y_t = Nx.add(out_proj, skip)
    
    {y_t, h_new}
  end
end
{:module, DLM.Main_SSM, <<70, 79, 82, 49, 0, 0, 31, ...>>, true}
defmodule DLM.MuonHybrid do
  import Nx.Defn

  defn newton_schulz(g, iters \\ 5) do
    frobenius_norm = Nx.sqrt(Nx.sum(Nx.pow(g, 2))) + 1.0e-7
    x = g / frobenius_norm
    
    {final_x, _} = while {curr_x = x, i = 0}, Nx.less(i, iters) do
      x_t_x = Nx.dot(Nx.transpose(curr_x), curr_x)
      next_x = 1.5 * curr_x - 0.5 * Nx.dot(curr_x, x_t_x)
      {next_x, i + 1}
    end
    final_x
  end

  defn muon_update(grad, lr) do
    Nx.subtract(0.0, Nx.multiply(lr, newton_schulz(grad)))
  end

  defn adam_update(param, grad, m, v, step, lr) do
    safe_step = step + 1.0
    beta1 = 0.9
    beta2 = 0.999
    eps = 1.0e-8
    
    new_m = beta1 * m + (1.0 - beta1) * grad
    new_v = beta2 * v + (1.0 - beta2) * Nx.pow(grad, 2)
    
    m_hat = new_m / (1.0 - Nx.pow(beta1, safe_step))
    v_hat = new_v / (1.0 - Nx.pow(beta2, safe_step))
    
    param_update = param - lr * m_hat / (Nx.sqrt(v_hat) + eps)
    {param_update, new_m, new_v}
  end

  defn step(params, grads, ms, vs, step_count, lr) do
    # ⚡ Unpack 19 elements
    {p_a, p_bu, p_bv, p_cu, p_cv, p_du, p_dv, p_mu1, p_mv1, p_mu2, p_mv2, 
     p_gw, p_gb, p_spell_w, p_spell_b, p_valve_w, p_valve_b, p_out_w, p_out_b} = params
  
    {g_a, g_bu, g_bv, g_cu, g_cv, g_du, g_dv, g_mu1, g_mv1, g_mu2, g_mv2, 
     g_gw, g_gb, g_spell_w, g_spell_b, g_valve_w, g_valve_b, g_out_w, g_out_b} = grads
  
    {m_a, m_bu, m_bv, m_cu, m_cv, m_du, m_dv, m_mu1, m_mv1, m_mu2, m_mv2, 
     m_gw, m_gb, m_spell_w, m_spell_b, m_valve_w, m_valve_b, m_out_w, m_out_b} = ms
  
    {v_a, v_bu, v_bv, v_cu, v_cv, v_du, v_dv, v_mu1, v_mv1, v_mu2, v_mv2, 
     v_gw, v_gb, v_spell_w, v_spell_b, v_valve_w, v_valve_b, v_out_w, v_out_b} = vs
  
    # ⚡ Adam for scalars, biases, and the 1D gate weight
    {up_a, nm_a, nv_a} = adam_update(p_a, g_a, m_a, v_a, step_count, lr)
    {up_gw, nm_gw, nv_gw} = adam_update(p_gw, g_gw, m_gw, v_gw, step_count, lr)
    {up_gb, nm_gb, nv_gb} = adam_update(p_gb, g_gb, m_gb, v_gb, step_count, lr)
    {up_spell_b, nm_spell_b, nv_spell_b} = adam_update(p_spell_b, g_spell_b, m_spell_b, v_spell_b, step_count, lr)
    {up_valve_b, nm_valve_b, nv_valve_b} = adam_update(p_valve_b, g_valve_b, m_valve_b, v_valve_b, step_count, lr)
    {up_out_b, nm_out_b, nv_out_b} = adam_update(p_out_b, g_out_b, m_out_b, v_out_b, step_count, lr)
    
    # ⚡ Muon for SVD and Dense 2D Matrices
    up_bu = p_bu + muon_update(g_bu, lr)
    up_bv = p_bv + muon_update(g_bv, lr)
    up_cu = p_cu + muon_update(g_cu, lr)
    up_cv = p_cv + muon_update(g_cv, lr)
    up_du = p_du + muon_update(g_du, lr)
    up_dv = p_dv + muon_update(g_dv, lr)
    up_mu1 = p_mu1 + muon_update(g_mu1, lr)
    up_mv1 = p_mv1 + muon_update(g_mv1, lr)
    up_mu2 = p_mu2 + muon_update(g_mu2, lr)
    up_mv2 = p_mv2 + muon_update(g_mv2, lr)
    up_spell_w = p_spell_w + muon_update(g_spell_w, lr)
    up_valve_w = p_valve_w + muon_update(g_valve_w, lr)
    up_out_w = p_out_w + muon_update(g_out_w, lr)
  
    # Repack
    new_params = {up_a, up_bu, up_bv, up_cu, up_cv, up_du, up_dv, up_mu1, up_mv1, up_mu2, up_mv2, 
                  up_gw, up_gb, up_spell_w, up_spell_b, up_valve_w, up_valve_b, up_out_w, up_out_b}
  
    new_ms = {nm_a, m_bu, m_bv, m_cu, m_cv, m_du, m_dv, m_mu1, m_mv1, m_mu2, m_mv2, 
              nm_gw, nm_gb, m_spell_w, nm_spell_b, m_valve_w, nm_valve_b, m_out_w, nm_out_b}
  
    new_vs = {nv_a, v_bu, v_bv, v_cu, v_cv, v_du, v_dv, v_mu1, v_mv1, v_mu2, v_mv2, 
              nv_gw, nv_gb, v_spell_w, nv_spell_b, v_valve_w, nv_valve_b, v_out_w, nv_out_b}
  
    {new_params, new_ms, new_vs}
  end
end
{:module, DLM.MuonHybrid, <<70, 79, 82, 49, 0, 0, 45, ...>>, true}
defmodule DLM.Main_SSM_Genesis do
  @vocab_size 128
  @dim 512
  @rank 256

  def init_params(seed \\ 42) do
    key = Nx.Random.key(seed)
    
    {a_diag, key} = Nx.Random.normal(key, -0.1, 0.01, shape: {@dim})
    
    {b_u,    key} = Nx.Random.normal(key, 0.0, 0.02, shape: {@dim, @rank})
    {b_v,    key} = Nx.Random.normal(key, 0.0, 0.02, shape: {@rank, @dim})
    {c_u,    key} = Nx.Random.normal(key, 0.0, 0.02, shape: {@dim, @rank})
    {c_v,    key} = Nx.Random.normal(key, 0.0, 0.02, shape: {@rank, @dim})
    {d_u,    key} = Nx.Random.normal(key, 0.0, 0.02, shape: {@dim, @rank})
    {d_v,    key} = Nx.Random.normal(key, 0.0, 0.02, shape: {@rank, @dim})
    {mx_u1,  key} = Nx.Random.normal(key, 0.0, 0.02, shape: {@dim, @rank})
    {mx_v1,  key} = Nx.Random.normal(key, 0.0, 0.02, shape: {@rank, @dim})
    {mx_u2,  key} = Nx.Random.normal(key, 0.0, 0.02, shape: {@dim, @rank})
    {mx_v2,  key} = Nx.Random.normal(key, 0.0, 0.02, shape: {@rank, @dim})
    
    # 1. The Boundary Gate
    {gate_w, key} = Nx.Random.normal(key, 0.0, 0.02, shape: {@dim, 1})
    gate_b = Nx.tensor([-3.0], type: :f32)

    # 2. ⚡ The Spell Feature Generator
    {spell_w, key} = Nx.Random.normal(key, 0.0, 0.02, shape: {@dim, @dim})
    spell_b = Nx.broadcast(0.0, {@dim})

    # 3. ⚡ The Syntax Valve (Swish Gate)
    {valve_w, key} = Nx.Random.normal(key, 0.0, 0.02, shape: {@dim, @dim})
    valve_b = Nx.broadcast(0.0, {@dim})

    # 4. ⚡ Latent Output Projection
    {out_w, _key} = Nx.Random.normal(key, 0.0, 0.02, shape: {@dim, @dim})
    out_b = Nx.broadcast(0.0, {@dim})

    # 19 Parameters Total
    {a_diag, b_u, b_v, c_u, c_v, d_u, d_v, mx_u1, mx_v1, mx_u2, mx_v2, 
     gate_w, gate_b, spell_w, spell_b, valve_w, valve_b, out_w, out_b}
  end

  def init_optimizer(params) do
    zero_like = fn t -> Nx.broadcast(Nx.tensor(0.0, type: :f32), t) end
    ms = DLM.Tree.map(params, zero_like)
    vs = DLM.Tree.map(params, zero_like)
    {ms, vs}
  end
end
warning: module attribute @vocab_size was set but never used
└─ hssmp3.livemd#cell:albe4mvo5o252ghx:2: DLM.Main_SSM_Genesis (module)
{:module, DLM.Main_SSM_Genesis, <<70, 79, 82, 49, 0, 0, 18, ...>>, {:init_optimizer, 1}}
defmodule DLM.TinySSM do
  import Nx.Defn

  defn gelu(x) do
    cdf = Nx.multiply(
      Nx.tensor(0.7978845608, type: :f32),
      Nx.add(x, Nx.multiply(Nx.tensor(0.044715, type: :f32), Nx.pow(x, 3)))
    )
    Nx.multiply(Nx.multiply(Nx.tensor(0.5, type: :f32), x), Nx.add(Nx.tensor(1.0, type: :f32), Nx.tanh(cdf)))
  end

  defn rms_norm(x, epsilon \\ 1.0e-6) do
    variance = Nx.mean(Nx.pow(x, 2), axes: [-1], keep_axes: true)
    x * Nx.rsqrt(variance + epsilon)
  end

  defn apply_svd(x, u, v) do
    hidden = Nx.dot(x, u)
    
    # 🛡️ The Shield: normalizes variance to 1.0 BEFORE the tanh
    normed_hidden = rms_norm(hidden) 
    activated = Nx.tanh(normed_hidden)
    
    Nx.dot(activated, v)
  end

  defn softplus(x) do
    Nx.select(x > 20.0, x, Nx.log1p(Nx.exp(x)))
  end

  defn forward(x_t, h_prev, params) do
    # ⚡ Unpack the 7 parameters
    {a, bu, bv, cu, cv, du, dv} = params

    b_proj = apply_svd(x_t, bu, bv)
    
    # ⚡ The Dynamic Gate
    gate_proj = apply_svd(x_t, du, dv)

    # ⚡ Shift the projection by -3.0 so the initial delta is ~0.048
    shifted_gate = Nx.subtract(gate_proj, 3.0)
    delta = Nx.max(softplus(shifted_gate), 0.01)
    
    # Dynamic Friction & Force
    a_bar = Nx.exp(Nx.multiply(delta, -Nx.abs(a)))
    b_bar = b_proj
    
    h_new = Nx.tanh(Nx.add(Nx.multiply(a_bar, h_prev), b_bar))
    
    predicted_vector = apply_svd(h_new, cu, cv)
    
    {predicted_vector, h_new}
  end
end
{:module, DLM.TinySSM, <<70, 79, 82, 49, 0, 0, 23, ...>>, true}

Layer 2

defmodule DLM.Surgery do
  def upgrade_to_tier3(old_ckpt_path, new_prefix, gpu) do
    IO.puts("🔪 Performing Tensor Surgery on #{old_ckpt_path}...")
    ckpt = File.read!(old_ckpt_path) |> :erlang.binary_to_term()
    
    # 1. Unpack the 15 Phase 3 parameters
    {a, bu, bv, cu, cv, du, dv, mu1, mv1, mu2, mv2, _old_lmw, _old_lmb, g1_w, g1_b} = ckpt.params
    
    # 2. Re-pack the 13 parameters for the Mid Level (Discarding the old head)
    mid_p = {a, bu, bv, cu, cv, du, dv, mu1, mv1, mu2, mv2, g1_w, g1_b}
    
    # 3. Initialize a brand new Top Level (15 parameters, including g2 and the new head)
    key = Nx.Random.key(42)
    {top_p, _} = DLM.Main_SSM_Genesis.init_phase3(key) 
    # (Assuming your init function generates the a...mv2, lm_w, lm_b, g2_w, and -3.0 g2_b)
    
    # 4. Initialize fresh optimizer states for the paired {mid, top} tuple
    zero_mid = DLM.Tree.map(mid_p, fn t -> Nx.broadcast(0.0, Nx.shape(t)) end)
    zero_top = DLM.Tree.map(top_p, fn t -> Nx.broadcast(0.0, Nx.shape(t)) end)
    
    # 5. Save the new 3-Tier Genesis Checkpoint
    state = %{
      params: {mid_p, top_p},
      ms: {zero_mid, zero_top},
      vs: {zero_mid, zero_top},
      step: 0,
      h_base: Nx.broadcast(0.0, {1, 512}),
      h_mid: Nx.broadcast(0.0, {1, 512}), # The old h_top is now h_mid
      h_top: Nx.broadcast(0.0, {1, 512})  # Brand new grammatical memory
    }
    
    File.write!("#{new_prefix}_checkpoint_step_0.bin", :erlang.term_to_binary(state))
    IO.puts("✅ Surgery Complete. Ready for Phase 4.")
  end
end
gpu = {EXLA.Backend, client: :rocm}
DLM.Surgery.upgrade_to_tier3("v34_DLM_Phase_3_Top_Biased_checkpoint_step_80000.bin", "v35_level_2", gpu)

Inferece

defmodule DLM.BLiMP do
  import Nx.Defn

  # ⚡ 1. The Evaluation Forward Pass (V2 Swish Latent Architecture)
  defn eval_loss(tokens, h_base_init, h_top_init, frozen_base_p, frozen_map, top_p) do
    seq_len = Nx.axis_size(tokens, 1) - 1
    
    input_tokens = Nx.slice_along_axis(tokens, 0, seq_len, axis: 1)
    target_tokens = Nx.slice_along_axis(tokens, 1, seq_len, axis: 1)

    # Map inputs to coordinates
    clean_coords = Nx.take(frozen_map, Nx.flatten(input_tokens))
                   |> Nx.reshape({1, seq_len, 512})
    in_t = Nx.transpose(clean_coords, axes: [1, 0, 2])

    # ⚡ NEW: Map targets to continuous coordinates for Cosine Evaluation
    target_coords = Nx.take(frozen_map, Nx.flatten(target_tokens))
                    |> Nx.reshape({1, seq_len, 512})
    targ_t = Nx.transpose(target_coords, axes: [1, 0, 2])

    zero_frame = Nx.broadcast(0.0, {1, 512})

    result =
      while {i = 0, total_loss = 0.0, 
             h_base = h_base_init, h_top = h_top_init,
             xp1 = zero_frame, xp2 = zero_frame,
             x_in = in_t, y_targ = targ_t,
             b_p = frozen_base_p, t_p = top_p, f_map = frozen_map}, 
            Nx.less(i, seq_len) do
            
        x_curr = x_in[i]

        # 1. Base SSM
        {_y_base, h_base_new} = DLM.TinySSM.forward(x_curr, h_base, b_p)

        # ⚡ Unpack all 19 Params for the Swish Gate
        {a, bu, bv, cu, cv, du, dv, mu1, mv1, mu2, mv2, 
         gate_w, gate_b, spell_w, spell_b, valve_w, valve_b, out_w, out_b} = t_p

        # 2. Boundary Gate
        gate_logit = Nx.add(Nx.dot(h_base_new, gate_w), gate_b)
        g = Nx.sigmoid(gate_logit) 

        # 3. Top SSM
        {_y_top, h_top_candidate} = DLM.Main_SSM.ssm_recurrence(
          h_base_new, xp1, xp2, h_top, 
          a, bu, bv, cu, cv, du, dv, mu1, mv1, mu2, mv2
        )

        # 4. Continuous Update
        h_top_new = Nx.add(Nx.multiply(g, h_top_candidate), Nx.multiply(Nx.subtract(1.0, g), h_top))
        h_base_flushed = Nx.multiply(h_base_new, Nx.subtract(1.0, g))

        # ⚡ 5. Multiplicative Swish Fusion
        f_spell = Nx.add(Nx.dot(h_base_new, spell_w), spell_b)
        v_syntax = DLM.Main_SSM.swish(Nx.add(Nx.dot(h_top_new, valve_w), valve_b))
        
        h_fused = Nx.multiply(v_syntax, f_spell)
        h_fused_norm = DLM.Main_SSM.rms_norm(h_fused)

        # ⚡ 6. Latent Prediction & Cosine Loss
        pred_latent = Nx.add(Nx.dot(h_fused_norm, out_w), out_b)
        step_loss = DLM.Loss.cosine_distance(pred_latent, y_targ[i])

        {i + 1, total_loss + step_loss, h_base_flushed, h_top_new, h_base_new, xp1, x_in, y_targ, b_p, t_p, f_map}
      end
      
    # Return average sequence Cosine Loss
    Nx.divide(elem(result, 1), seq_len)
  end

  # ⚡ 2. The Elixir Wrapper
  def evaluate_sentence(sentence, frozen_base_p, frozen_map, top_p, gpu) do
    # Convert string to {1, seq_len} tensor
    tokens = sentence |> to_charlist() |> Nx.tensor(type: :s32) |> Nx.new_axis(0) |> Nx.backend_copy(gpu)
    
    # Initialize blank memory for a single batch
    h_base = Nx.broadcast(0.0, {1, 512}) |> Nx.backend_copy(gpu)
    h_top  = Nx.broadcast(0.0, {1, 512}) |> Nx.backend_copy(gpu)

    # Run the compiled XLA graph
    loss_tensor = eval_loss(tokens, h_base, h_top, frozen_base_p, frozen_map, top_p)
    Nx.to_number(loss_tensor)
  end
end
{:module, DLM.BLiMP, <<70, 79, 82, 49, 0, 0, 30, ...>>, {:evaluate_sentence, 5}}
gpu = {EXLA.Backend, client: :rocm}
blimp_file = "./data/determiner_noun_agreement_1.jsonl" # 👈 Change this to your specific BLiMP file

# ==============================================================================
# 1. LOAD WEIGHTS
# ==============================================================================
IO.puts("🌌 Loading Phase 1, 2, and 3 Weights...")
%{params: phase1_p} = File.read!("phase1_shape_diffusion_COMPLETE.bin") |> :erlang.binary_to_term()
frozen_map = elem(phase1_p, 0) |> Nx.backend_copy(gpu) |> DLM.Loss.l2_normalize()

frozen_base_p = File.read!("v33_DLM_Phase_2_cos_checkpoint_step_13000.bin") |> :erlang.binary_to_term()

# Load your best Phase 3 Top Level weights (Adjust filename as needed)
top_ckpt = File.read!("v34_DLM_Phase_3_Top_256_lowLR_checkpoint_step_44000.bin") |> :erlang.binary_to_term()
top_p = DLM.Tree.map(top_ckpt.params, &Nx.backend_copy(&1, gpu))

# ==============================================================================
# 2. RUN BLIMP EVALUATION
# ==============================================================================
IO.puts("📖 Reading BLiMP Dataset: #{blimp_file}")

# Parse the JSON Lines
pairs = 
  File.read!(blimp_file)
  |> String.split("\n", trim: true)
  |> Enum.map(&Jason.decode!/1)

total_pairs = length(pairs)
IO.puts("⚖️ Evaluating #{total_pairs} minimalist pairs...")

# Tally the results
{passes, total_loss_diff} = 
  Enum.reduce(pairs, {0, 0.0}, fn pair, {pass_count, diff_acc} ->
    good_sentence = pair["sentence_good"]
    bad_sentence = pair["sentence_bad"]

    # Calculate losses
    good_loss = DLM.BLiMP.evaluate_sentence(good_sentence, frozen_base_p, frozen_map, top_p, gpu)
    bad_loss  = DLM.BLiMP.evaluate_sentence(bad_sentence, frozen_base_p, frozen_map, top_p, gpu)

    # Did the model assign a lower loss (higher probability) to the grammatically correct sentence?
    is_pass? = good_loss < bad_loss
    
    new_pass_count = if is_pass?, do: pass_count + 1, else: pass_count

    {new_pass_count, diff_acc + (bad_loss - good_loss)}
  end)

# Calculate final metrics
accuracy = (passes / total_pairs) * 100.0
avg_margin = total_loss_diff / total_pairs

IO.puts(String.duplicate("=", 50))
IO.puts("🏆 BLiMP EVALUATION RESULTS")
IO.puts(String.duplicate("=", 50))
IO.puts("Dataset:   #{blimp_file}")
IO.puts("Accuracy:  #{Float.round(accuracy, 2)}% (#{passes}/#{total_pairs})")
IO.puts("Margin:    #{Float.round(avg_margin, 4)} (Avg loss difference)")
IO.puts(String.duplicate("=", 50))
🌌 Loading Phase 1, 2, and 3 Weights...
📖 Reading BLiMP Dataset: ./data/determiner_noun_agreement_1.jsonl
⚖️ Evaluating 1000 minimalist pairs...
==================================================
🏆 BLiMP EVALUATION RESULTS
==================================================
Dataset:   ./data/determiner_noun_agreement_1.jsonl
Accuracy:  51.2% (512/1000)
Margin:    0.0001 (Avg loss difference)
==================================================
:ok
defmodule DLM.Generator do
  import Nx.Defn

  # ⚡ 1. The Single Forward Step
  defn step(char_idx, h_base, h_top, xp1, xp2, frozen_base_p, top_p, f_map) do
    # Unpack params
    {a, bu, bv, cu, cv, du, dv, mu1, mv1, mu2, mv2, lm_w, lm_b, gate_w, gate_b} = top_p

    # Get the continuous 512D coordinate for this discrete character
    coord = Nx.take(f_map, Nx.reshape(char_idx, {1})) |> Nx.reshape({1, 512})

    # Physics Engine Step
    {_y_b, h_b_new} = DLM.TinySSM.forward(coord, h_base, frozen_base_p)

    # The Boundary Gate
    gate_logit = Nx.add(Nx.dot(h_b_new, gate_w), gate_b)
    g = Nx.sigmoid(gate_logit)

    # Top Level Logic Step
    {y_t, h_t_cand} = DLM.Main_SSM.ssm_recurrence(
      h_b_new, xp1, xp2, h_top, 
      a, bu, bv, cu, cv, du, dv, mu1, mv1, mu2, mv2
    )

    # Continuous Interpolation & Memory Flush
    h_t_new = Nx.add(Nx.multiply(g, h_t_cand), Nx.multiply(Nx.subtract(1.0, g), h_top))
    h_b_flushed = Nx.multiply(h_b_new, Nx.subtract(1.0, g))

    # Output Head
    y_final = DLM.Main_SSM.rms_norm(y_t)
    logits = Nx.add(Nx.dot(y_final, lm_w), lm_b) |> Nx.squeeze()

    # Return logits, the updated states, the shift register (xp1/xp2), and the gate value
    {logits, h_b_flushed, h_t_new, h_b_new, xp1, Nx.squeeze(g)}
  end

  # ⚡ 2. The Gumbel Sampler
  defn sample(logits, key, temperature) do
    scaled = Nx.divide(logits, Nx.add(temperature, 1.0e-5))
    {u, next_key} = Nx.Random.uniform(key, 0.0, 1.0, shape: Nx.shape(scaled))
    
    # Gumbel noise distribution
    gumbel = Nx.negate(Nx.log(Nx.negate(Nx.log(Nx.add(u, 1.0e-7)))))
    noisy = Nx.add(scaled, gumbel)
    
    {Nx.argmax(noisy), next_key}
  end

  # ⚡ 3. The Generation Loop (Runs in standard Elixir)
  def generate(prompt, num_tokens, temp, f_base_p, t_p, f_map, gpu) do
    prompt_tokens = to_charlist(prompt)
    key = Nx.Random.key(System.system_time(:second)) |> Nx.backend_copy(gpu)
    
    # Initialize blank states
    h_b = Nx.broadcast(0.0, {1, 512}) |> Nx.backend_copy(gpu)
    h_t = Nx.broadcast(0.0, {1, 512}) |> Nx.backend_copy(gpu)
    xp1 = Nx.broadcast(0.0, {1, 512}) |> Nx.backend_copy(gpu)
    xp2 = Nx.broadcast(0.0, {1, 512}) |> Nx.backend_copy(gpu)

    # Warmup Phase (Feed the prompt in without sampling)
    IO.puts("🔥 Warming up semantic context...")
    {warm_hb, warm_ht, warm_xp1, warm_xp2} = Enum.reduce(prompt_tokens, {h_b, h_t, xp1, xp2}, 
      fn char, {cb, ct, cx1, cx2} ->
        char_tensor = Nx.tensor(char, type: :s32) |> Nx.backend_copy(gpu)
        {_logits, nb, nt, nx1, nx2, _g} = step(char_tensor, cb, ct, cx1, cx2, f_base_p, t_p, f_map)
        {nb, nt, nx1, nx2}
      end
    )

    # Generation Phase
    IO.puts("\n🚀 Generating...\n")
    IO.write(prompt)

    last_char = List.last(prompt_tokens)

    Enum.reduce(1..num_tokens, {last_char, warm_hb, warm_ht, warm_xp1, warm_xp2, key}, 
      fn _i, {curr_char, cb, ct, cx1, cx2, cur_key} ->
        
        char_tensor = Nx.tensor(curr_char, type: :s32) |> Nx.backend_copy(gpu)
        
        # Step the network
        {logits, nb, nt, nx1, nx2, g_tensor} = step(char_tensor, cb, ct, cx1, cx2, f_base_p, t_p, f_map)
        
        # Sample the next character
        {next_char_tensor, next_key} = sample(logits, cur_key, Nx.tensor(temp, type: :f32))
        next_char = Nx.to_number(next_char_tensor)
        
        # Pull the gate value for visualization
        g_val = Nx.to_number(g_tensor)
        
        # If the gate spikes above 0.5, we'll visually mark it with a pipe |
        marker = if g_val > 0.5, do: "|", else: ""
        IO.write("#{marker}#{List.to_string([next_char])}")

        {next_char, nb, nt, nx1, nx2, next_key}
      end
    )
    IO.puts("\n\n✅ Done.")
  end
end
{:module, DLM.Generator, <<70, 79, 82, 49, 0, 0, 37, ...>>, {:generate, 7}}
gpu = {EXLA.Backend, client: :rocm}
blimp_file = "./data/regular_plural_subject_verb_agreement_1.jsonl" # 👈 Change this to your specific BLiMP file

# ==============================================================================
# 1. LOAD WEIGHTS
# ==============================================================================
IO.puts("🌌 Loading Phase 1, 2, and 3 Weights...")
%{params: phase1_p} = File.read!("phase1_shape_diffusion_COMPLETE.bin") |> :erlang.binary_to_term()
frozen_map = elem(phase1_p, 0) |> Nx.backend_copy(gpu) |> DLM.Loss.l2_normalize()

frozen_base_p = File.read!("v33_DLM_Phase_2_cos_checkpoint_step_13000.bin") |> :erlang.binary_to_term()

# Load your best Phase 3 Top Level weights (Adjust filename as needed)
top_ckpt = File.read!("v34_DLM_Phase_3_Top_256_midLR_checkpoint_step_16000.bin") |> :erlang.binary_to_term()
top_p = DLM.Tree.map(top_ckpt.params, &Nx.backend_copy(&1, gpu))

# ==============================================================================
# 2. RUN BLIMP EVALUATION
# ==============================================================================
IO.puts("📖 Reading BLiMP Dataset: #{blimp_file}")

# Parse the JSON Lines
pairs = 
  File.read!(blimp_file)
  |> String.split("\n", trim: true)
  |> Enum.map(&Jason.decode!/1)

total_pairs = length(pairs)
IO.puts("⚖️ Evaluating #{total_pairs} minimalist pairs...")

# Tally the results
{passes, total_loss_diff} = 
  Enum.reduce(pairs, {0, 0.0}, fn pair, {pass_count, diff_acc} ->
    good_sentence = pair["sentence_good"]
    bad_sentence = pair["sentence_bad"]

    # Calculate losses
    good_loss = DLM.BLiMP.evaluate_sentence(good_sentence, frozen_base_p, frozen_map, top_p, gpu)
    bad_loss  = DLM.BLiMP.evaluate_sentence(bad_sentence, frozen_base_p, frozen_map, top_p, gpu)

    # Did the model assign a lower loss (higher probability) to the grammatically correct sentence?
    is_pass? = good_loss < bad_loss
    
    new_pass_count = if is_pass?, do: pass_count + 1, else: pass_count

    {new_pass_count, diff_acc + (bad_loss - good_loss)}
  end)

# Calculate final metrics
accuracy = (passes / total_pairs) * 100.0
avg_margin = total_loss_diff / total_pairs

IO.puts(String.duplicate("=", 50))
IO.puts("🏆 BLiMP EVALUATION RESULTS")
IO.puts(String.duplicate("=", 50))
IO.puts("Dataset:   #{blimp_file}")
IO.puts("Accuracy:  #{Float.round(accuracy, 2)}% (#{passes}/#{total_pairs})")
IO.puts("Margin:    #{Float.round(avg_margin, 4)} (Avg loss difference)")
IO.puts(String.duplicate("=", 50))
🌌 Loading Phase 1, 2, and 3 Weights...
📖 Reading BLiMP Dataset: ./data/regular_plural_subject_verb_agreement_1.jsonl
⚖️ Evaluating 1000 minimalist pairs...
** (MatchError) no match of right hand side value: {#Nx.Tensor<
   f32[512]
   
   Nx.Defn.Expr
   parameter a:15   f32[512]
 >, #Nx.Tensor<
   f32[512][64]
   
   Nx.Defn.Expr
   parameter a:16   f32[512][64]
 >, #Nx.Tensor<
   f32[64][512]
   
   Nx.Defn.Expr
   parameter a:17   f32[64][512]
 >, #Nx.Tensor<
   f32[512][64]
   
   Nx.Defn.Expr
   parameter a:18   f32[512][64]
 >, #Nx.Tensor<
   f32[64][512]
   
   Nx.Defn.Expr
   parameter a:19   f32[64][512]
 >, #Nx.Tensor<
   f32[512][64]
   
   Nx.Defn.Expr
   parameter a:20   f32[512][64]
 >, #Nx.Tensor<
   f32[64][512]
   
   Nx.Defn.Expr
   parameter a:21   f32[64][512]
 >, #Nx.Tensor<
   f32[512][64]
   
   Nx.Defn.Expr
   parameter a:22   f32[512][64]
 >, #Nx.Tensor<
   f32[64][512]
   
   Nx.Defn.Expr
   parameter a:23   f32[64][512]
 >, #Nx.Tensor<
   f32[512][64]
   
   Nx.Defn.Expr
   parameter a:24   f32[512][64]
 >, #Nx.Tensor<
   f32[64][512]
   
   Nx.Defn.Expr
   parameter a:25   f32[64][512]
 >, #Nx.Tensor<
   f32[512][128]
   
   Nx.Defn.Expr
   parameter a:26   f32[512][128]
 >, #Nx.Tensor<
   f32[128]
   
   Nx.Defn.Expr
   parameter a:27   f32[128]
 >, #Nx.Tensor<
   f32[512][1]
   
   Nx.Defn.Expr
   parameter a:28   f32[512][1]
 >, #Nx.Tensor<
   f32[1]
   
   Nx.Defn.Expr
   parameter a:29   f32[1]
 >}
    #cell:lfbfrue6mc255axz:35: anonymous fn/3 in DLM.BLiMP."__defn:eval_loss__"/6
    (nx 0.11.0) lib/nx/defn/expr.ex:530: Nx.Defn.Expr.while_vectorized/7
    #cell:lfbfrue6mc255axz:22: DLM.BLiMP."__defn:eval_loss__"/6
    (nx 0.11.0) lib/nx/defn/compiler.ex:190: Nx.Defn.Compiler.runtime_fun/3
    (exla 0.11.0) lib/exla/defn.ex:377: anonymous fn/4 in EXLA.Defn.compile/8
    (exla 0.11.0) lib/exla/defn/locked_cache.ex:36: EXLA.Defn.LockedCache.run/2
    (stdlib 6.2.2) timer.erl:595: :timer.tc/2
    #cell:iqhd5oaj6cbvkwag:33: (file)
# ==============================================================================
# 1. LOAD WEIGHTS
# ==============================================================================
IO.puts("🌌 Loading Phase 1, 2, and 3 Weights...")
gpu = {EXLA.Backend, client: :rocm}
%{params: phase1_p} = File.read!("phase1_shape_diffusion_COMPLETE.bin") |> :erlang.binary_to_term()
frozen_map = elem(phase1_p, 0) |> Nx.backend_copy(gpu) |> DLM.Loss.l2_normalize()

frozen_base_p = File.read!("v33_DLM_Phase_2_cos_checkpoint_step_13000.bin") |> :erlang.binary_to_term()

# Load your best Phase 3 Top Level weights (Adjust filename as needed)
top_ckpt = File.read!("v34_DLM_Phase_3_Top_Biased_checkpoint_step_16000.bin") |> :erlang.binary_to_term()
top_p = DLM.Tree.map(top_ckpt.params, &Nx.backend_copy(&1, gpu))

prompt = "Hello, my name is "

tokens_to_generate = 128 - String.length(prompt)


DLM.Generator.generate(prompt, tokens_to_generate, 0.65, frozen_base_p, top_p, frozen_map, gpu)
🌌 Loading Phase 1, 2, and 3 Weights...

10:42:32.060 [info] XLA service 0x7e08a409ab70 initialized for platform ROCM (this does not guarantee that XLA will be used). Devices:

10:42:32.062 [info]   StreamExecutor [0]: AMD Radeon RX 7600, AMDGPU ISA version: gfx1100 (Driver: 6.4.43482; Runtime: 6.4.43482; Toolkit: 6.4.43482; DNN: 0.0.0)

10:42:32.062 [info] Using BFC allocator.

10:42:32.062 [info] XLA backend will use up to 6429868032 bytes on device 0 for BFCAllocator.

10:42:32.062 [info] XLA backend will use up to 2143289344 bytes on device 0 for CollectiveBFCAllocator.
🔥 Warming up semantic context...
** (UndefinedFunctionError) function DLM.TinySSM.forward/3 is undefined (module DLM.TinySSM is not available)
    DLM.TinySSM.forward(#Nx.Tensor<
  f32[1][512]
  
  Nx.Defn.Expr
  parameter a:27           f32[128][512]
  parameter b:0            s32
  c = reshape b            s32[1]
  d = take a, c, axis: 0   f32[1][512]
>, #Nx.Tensor<
  f32[1][512]
  
  Nx.Defn.Expr
  parameter a:1   f32[1][512]
>, {#Nx.Tensor<
   f32[512]
   
   Nx.Defn.Expr
   parameter a:5   f32[512]
 >, #Nx.Tensor<
   f32[512][256]
   
   Nx.Defn.Expr
   parameter a:6   f32[512][256]
 >, #Nx.Tensor<
   f32[256][512]
   
   Nx.Defn.Expr
   parameter a:7   f32[256][512]
 >, #Nx.Tensor<
   f32[512][256]
   
   Nx.Defn.Expr
   parameter a:8   f32[512][256]
 >, #Nx.Tensor<
   f32[256][512]
   
   Nx.Defn.Expr
   parameter a:9   f32[256][512]
 >, #Nx.Tensor<
   f32[512][256]
   
   Nx.Defn.Expr
   parameter a:10   f32[512][256]
 >, #Nx.Tensor<
   f32[256][512]
   
   Nx.Defn.Expr
   parameter a:11   f32[256][512]
 >})
    #cell:jowzjq3lsg7lgi63:13: DLM.Generator."__defn:step__"/8
    (nx 0.11.0) lib/nx/defn/compiler.ex:190: Nx.Defn.Compiler.runtime_fun/3
    (exla 0.11.0) lib/exla/defn.ex:377: anonymous fn/4 in EXLA.Defn.compile/8
    (exla 0.11.0) lib/exla/defn/locked_cache.ex:36: EXLA.Defn.LockedCache.run/2
    (stdlib 6.2.2) timer.erl:595: :timer.tc/2
    #cell:a4gyninsclvsoeku:20: (file)
# defmodule DLM.Probe do
#   import Nx.Defn

#   # Run the sequence and extract ONLY the gate values
#   defn extract_gates(tokens, h_base_init, h_top_init, frozen_base_p, frozen_map, top_p) do
#     seq_len = Nx.axis_size(tokens, 1)
#     clean_coords = Nx.take(frozen_map, Nx.flatten(tokens)) |> Nx.reshape({1, seq_len, 512})
#     x_in = Nx.transpose(clean_coords, axes: [1, 0, 2])
#     zero_frame = Nx.broadcast(0.0, {1, 512})
#     g_out_init = Nx.broadcast(0.0, {seq_len})

#     result =
#       while {i = 0, h_b = h_base_init, h_t = h_top_init, xp1 = zero_frame, xp2 = zero_frame, 
#              gates = g_out_init, x_t = x_in, b_p = frozen_base_p, t_p = top_p}, 
#             Nx.less(i, seq_len) do
            
#         x_curr = x_t[i]
#         {_y_base, h_b_new} = DLM.TinySSM.forward(x_curr, h_b, b_p)
#         {a, bu, bv, cu, cv, du, dv, mu1, mv1, mu2, mv2, _lmw, _lmb, gate_w} = t_p

#         # ⚡ Calculate the Gate
#         gate_logit = Nx.dot(h_b_new, gate_w)
#         g = Nx.sigmoid(gate_logit) |> Nx.squeeze()

#         # Step the top layer to keep the math accurate
#         {_y_top, h_t_cand} = DLM.Main_SSM.ssm_recurrence(h_b_new, xp1, xp2, h_t, a, bu, bv, cu, cv, du, dv, mu1, mv1, mu2, mv2)
#         h_t_new = Nx.add(Nx.multiply(g, h_t_cand), Nx.multiply(Nx.subtract(1.0, g), h_t))
#         h_b_flushed = Nx.multiply(h_b_new, Nx.subtract(1.0, g))

#         updated_gates = Nx.put_slice(gates, [i], Nx.new_axis(g, 0))

#         {i + 1, h_b_flushed, h_t_new, h_b_new, xp1, updated_gates, x_t, b_p, t_p}
#       end
      
#     elem(result, 5)
#   end

#   def watch_the_heartbeat(sentence, frozen_base_p, frozen_map, top_p, gpu) do
#     chars = String.graphemes(sentence)
#     tokens = sentence |> to_charlist() |> Nx.tensor(type: :s32) |> Nx.new_axis(0) |> Nx.backend_copy(gpu)
    
#     h_b = Nx.broadcast(0.0, {1, 512}) |> Nx.backend_copy(gpu)
#     h_t = Nx.broadcast(0.0, {1, 512}) |> Nx.backend_copy(gpu)

#     gates = extract_gates(tokens, h_b, h_t, frozen_base_p, frozen_map, top_p) 
#             |> Nx.backend_transfer() 
#             |> Nx.to_flat_list()

#     IO.puts("🌊 BOUNDARY GATE RHYTHM")
#     IO.puts("-----------------------")
#     Enum.zip(chars, gates)
#     |> Enum.each(fn {char, g} -> 
#       # Create a simple visual bar based on the gate value
#       bar_length = trunc(g * 20)
#       bar = String.duplicate("█", bar_length)
#       display_char = if char == " ", do: "[space]", else: char
#       IO.puts("#{String.pad_trailing(display_char, 7)} | #{Float.round(g, 3)} | #{bar}")
#     end)
#   end
# end
{:module, DLM.Probe, <<70, 79, 82, 49, 0, 0, 31, ...>>, {:watch_the_heartbeat, 5}}

Train

defmodule DLM.HierarchyBridge do
  import Nx.Defn

  # Assume we have the base state and the previous top state
  defn bridge_step(h_base, h_top_prev, top_params, boundary_weights) do
    # 1. ⚡ Calculate the Boundary Gate (g)
    # Project 512D -> 1D, then Sigmoid to force it between 0.0 and 1.0
    boundary_logit = Nx.dot(h_base, boundary_weights)
    g = Nx.sigmoid(boundary_logit) 

    # 2. ⚡ Calculate the potential next state for the Top Level
    # We feed the Base's 512D summary into the Top Level as its "input"
    {_predicted_chunk, h_top_candidate} = DLM.TinySSM.forward(h_base, h_top_prev, top_params)

    # 3. ⚡ The Continuous Update (Linear Interpolation)
    # If g=0 (mid-word), it ignores the input and keeps h_top_prev.
    # If g=1 (word end), it fully updates to h_top_candidate.
    h_top_new = Nx.add(
      Nx.multiply(g, h_top_candidate),
      Nx.multiply(Nx.subtract(1.0, g), h_top_prev)
    )

    # 4. ⚡ The Soft Reset (Crucial)
    # If the base layer just passed a completed concept up to the top, 
    # it needs to flush its own memory to start building the next concept.
    h_base_flushed = Nx.multiply(h_base, Nx.subtract(1.0, g))

    {h_top_new, h_base_flushed, g}
  end
end
{:module, DLM.HierarchyBridge, <<70, 79, 82, 49, 0, 0, 13, ...>>, true}
defmodule DLM.Main_SSM_Trainer do
  import Nx.Defn

  # 1. Maps discrete tokens to their perfect 512D spatial coordinates
  defn get_real_coordinates(batch_tokens, frozen_embeds) do
    Nx.take(frozen_embeds, Nx.flatten(batch_tokens))
      |> Nx.reshape({Nx.axis_size(batch_tokens, 0), Nx.axis_size(batch_tokens, 1), 512})
      |> stop_grad()
  end

  # 2. THE MASTER SEQUENCE LOOP (Now with Gate Tracking!)
  defn compute_sequence_loss(input_tokens, target_tokens, h_base_init, h_top_init, frozen_base_p, frozen_map, top_p) do
    seq_len = Nx.axis_size(input_tokens, 1)
 
    clean_coords = get_real_coordinates(input_tokens, frozen_map)
    inputs_time = Nx.transpose(clean_coords, axes: [1, 0, 2])
    
    # ⚡ NEW: Convert discrete targets into continuous targets BEFORE the loop
    target_coords = get_real_coordinates(target_tokens, frozen_map)
    targets_time = Nx.transpose(target_coords, axes: [1, 0, 2])

    zero_frame = Nx.broadcast(0.0, Nx.shape(h_top_init))

    result =
      while {i = 0, total_loss = 0.0, total_g = 0.0, 
             h_base = h_base_init, h_top = h_top_init,
             xp1 = zero_frame, xp2 = zero_frame,
             in_t = inputs_time, targ_t = targets_time,
             b_p = frozen_base_p, t_p = top_p, f_map = frozen_map}, 
            Nx.less(i, seq_len) do
            
        x_curr = in_t[i]
        {_y_base, h_base_new} = DLM.TinySSM.forward(x_curr, h_base, b_p)

        # ⚡ Unpack 19 params
        {a, bu, bv, cu, cv, du, dv, mu1, mv1, mu2, mv2, 
         gate_w, gate_b, spell_w, spell_b, valve_w, valve_b, out_w, out_b} = t_p

        gate_logit = Nx.add(Nx.dot(h_base_new, gate_w), gate_b)
        g = Nx.sigmoid(gate_logit) 
        batch_avg_g = Nx.mean(g)

        {_y_top, h_top_candidate} = DLM.Main_SSM.ssm_recurrence(
          h_base_new, xp1, xp2, h_top, 
          a, bu, bv, cu, cv, du, dv, mu1, mv1, mu2, mv2
        )

        h_top_new = Nx.add(Nx.multiply(g, h_top_candidate), Nx.multiply(Nx.subtract(1.0, g), h_top))
        h_base_flushed = Nx.multiply(h_base_new, Nx.subtract(1.0, g))

        # ⚡ 4. MULTIPLICATIVE SWISH FUSION
        f_spell = Nx.add(Nx.dot(h_base_new, spell_w), spell_b)
        v_syntax = DLM.Main_SSM.swish(Nx.add(Nx.dot(h_top_new, valve_w), valve_b))
        
        h_fused = Nx.multiply(v_syntax, f_spell)
        h_fused_norm = DLM.Main_SSM.rms_norm(h_fused)

        # ⚡ 5. LATENT PREDICTION & CONTRASTIVE LOSS
        pred_latent = Nx.add(Nx.dot(h_fused_norm, out_w), out_b)
        
        # ⚡ Swap from purely attractive to push/pull
        # step_loss = DLM.Loss.cosine_distance(pred_latent, targ_t[i])
        step_loss = DLM.Loss.soft_nn_loss(pred_latent, targ_t[i], 0.1)

        {i + 1, total_loss + step_loss, total_g + batch_avg_g, h_base_flushed, h_top_new, h_base_new, xp1, in_t, targ_t, b_p, t_p, f_map}
      end
      
    {Nx.divide(elem(result, 1), seq_len), elem(result, 3), elem(result, 4), Nx.divide(elem(result, 2), seq_len)}
  end

  # 3. GRADIENT TAPE
  defn compute_grad_and_step(batch_tokens, h_base_init, h_top_init, frozen_base_p, frozen_map, top_p) do
    seq_len = Nx.axis_size(batch_tokens, 1) - 1
    input_tokens = Nx.slice_along_axis(batch_tokens, 0, seq_len, axis: 1)
    target_tokens = Nx.slice_along_axis(batch_tokens, 1, seq_len, axis: 1)

    {loss, raw_grads} = value_and_grad(top_p, fn p ->
      {avg_loss, _h_base_final, _h_top_final, avg_g} = 
        compute_sequence_loss(input_tokens, target_tokens, h_base_init, h_top_init, frozen_base_p, frozen_map, p)
      
      # ⚡ THE "GENTLE PRESSURE" L1 SPARSITY PENALTY
      # We no longer force a specific rhythm. We just apply a tiny "energy cost" to opening the gate.
      # The Swish fusion will naturally pull the gate open when it needs linguistic features.
      energy_cost = Nx.tensor(0.005, type: :f32) 
      
      # Penalty = energy_cost * avg_g
      gentle_penalty = Nx.multiply(energy_cost, avg_g)

      # The optimizer must now balance minimizing Cosine Distance against conserving gate energy.
      Nx.add(avg_loss, gentle_penalty)
    end)
    
    # Run a clean pass to get states AND the average gate value for telemetry
    {_loss, final_h_base, final_h_top, avg_g} = 
        compute_sequence_loss(input_tokens, target_tokens, h_base_init, h_top_init, frozen_base_p, frozen_map, top_p)

    {loss, raw_grads, final_h_base, final_h_top, avg_g}
  end

  # ⚡ 4. TELEMETRY HELPER (Unpacks all 19 Phase 3 Params)
  def grad_norms(grads) do
    {g_a, g_bu, g_bv, g_cu, g_cv, g_du, g_dv, g_mu1, g_mv1, g_mu2, g_mv2, 
     g_gw, g_gb, g_spell_w, g_spell_b, g_valve_w, g_valve_b, g_out_w, g_out_b} = grads
    
    calc = fn g -> g |> Nx.pow(2) |> Nx.sum() |> Nx.sqrt() |> Nx.to_number() |> Float.round(4) end
    
    [
      a_diag: calc.(g_a), b_u: calc.(g_bu), b_v: calc.(g_bv),
      c_u: calc.(g_cu), c_v: calc.(g_cv), d_u: calc.(g_du), d_v: calc.(g_dv),
      mx_u1: calc.(g_mu1), mx_v1: calc.(g_mv1), mx_u2: calc.(g_mu2), mx_v2: calc.(g_mv2),
      gate_w: calc.(g_gw), gate_b: calc.(g_gb), 
      spell_w: calc.(g_spell_w), spell_b: calc.(g_spell_b), 
      valve_w: calc.(g_valve_w), valve_b: calc.(g_valve_b), 
      out_w: calc.(g_out_w), out_b: calc.(g_out_b)
    ]
  end
end
{:module, DLM.Main_SSM_Trainer, <<70, 79, 82, 49, 0, 0, 51, ...>>, {:grad_norms, 1}}
defmodule DLM.CheckpointManager do
  @moduledoc """
  Handles resuming and saving states for the Hierarchical DLM.
  """
  def get_resume_state(run_prefix) do
    checkpoints = Path.wildcard("#{run_prefix}_checkpoint_step_*.bin")

    if Enum.empty?(checkpoints) do
      if File.exists?("#{run_prefix}_final.bin") do
        IO.puts("✨ Found completed run: #{run_prefix}_final.bin")
        {"#{run_prefix}_final.bin", :completed}
      else
        IO.puts("✨ No checkpoints found for '#{run_prefix}'. Starting FRESH.")
        {:fresh, 0}
      end
    else
      latest_file = Enum.max_by(checkpoints, fn file ->
        case Regex.run(~r/_step_(\d+)\.bin$/, file) do
          [_, step_str] -> String.to_integer(step_str)
          _ -> -1
        end
      end)

      [_, step_str] = Regex.run(~r/_step_(\d+)\.bin$/, latest_file)
      step = String.to_integer(step_str)
      
      IO.puts("🚀 Auto-Resuming '#{run_prefix}' from Step #{step}...")
      {latest_file, step}
    end
  end

  # ⚡ NEW: Clean, centralized saving logic
  def save_checkpoint(prefix, step, p, m, v, h_base, h_top) do
    IO.puts("💾 Auto-Saving Checkpoint Step #{step}...")
    
    state = %{
      params: DLM.Tree.map(p, &Nx.backend_copy(&1, Nx.BinaryBackend)),
      ms: DLM.Tree.map(m, &Nx.backend_copy(&1, Nx.BinaryBackend)),
      vs: DLM.Tree.map(v, &Nx.backend_copy(&1, Nx.BinaryBackend)),
      step: step,
      h_base: Nx.backend_copy(h_base, Nx.BinaryBackend),
      h_top: Nx.backend_copy(h_top, Nx.BinaryBackend)
    }
    
    File.write!("#{prefix}_checkpoint_step_#{step}.bin", :erlang.term_to_binary(state))
  end
end
{:module, DLM.CheckpointManager, <<70, 79, 82, 49, 0, 0, 23, ...>>, {:save_checkpoint, 7}}
run_prefix  = "v37_DLM_Phase_3_softnn"  
total_steps = 100000
batch_size = 32
seq_len = 128
save_interval = 1000

# ==============================================================================
# 1. LOAD FROZEN FOUNDATIONS (Manifold + Physics Engine)
# ==============================================================================
IO.puts("🌌 Loading Phase 1 Frozen Manifold...")
%{params: phase1_p} = File.read!("phase1_shape_diffusion_COMPLETE.bin") |> :erlang.binary_to_term()
{cpu_embeds, _w1, _w2, _key} = phase1_p
frozen_map = cpu_embeds |> Nx.backend_copy(gpu) |> DLM.Loss.l2_normalize()

IO.puts("⚙️ Loading Phase 2 Base SSM (Physics Engine)...")
base_checkpoint = File.read!("v33_DLM_Phase_2_cos_checkpoint_step_13000.bin") |> :erlang.binary_to_term()
frozen_base_p = DLM.Tree.map(base_checkpoint, &Nx.backend_copy(&1, gpu))

# ==============================================================================
# 2. INITIALIZE / RESUME TOP LEVEL
# ==============================================================================
{load_path, start_step} = DLM.CheckpointManager.get_resume_state(run_prefix)

{starting_p, starting_m, starting_v, start_h_base, start_h_top} =
  if load_path == :fresh do
    IO.puts("✨ Igniting brand new Phase 3 Genesis weights...")
    raw_p = DLM.Main_SSM_Genesis.init_params(42)
    {raw_m, raw_v} = DLM.Main_SSM_Genesis.init_optimizer(raw_p)
    
    blank_h = Nx.broadcast(0.0, {batch_size, 512}) |> Nx.backend_copy(gpu)
    
    {raw_p, raw_m, raw_v, blank_h, blank_h}
  else
    ckpt = File.read!(load_path) |> :erlang.binary_to_term()
    blank_h = Nx.broadcast(0.0, {batch_size, 512}) |> Nx.backend_copy(gpu)
    
    {
      ckpt.params, 
      ckpt.ms, 
      ckpt.vs, 
      Map.get(ckpt, :h_base, blank_h), 
      Map.get(ckpt, :h_top, blank_h)
    }
  end

# Push standard optimizer states to GPU
p = DLM.Tree.map(starting_p, &Nx.backend_copy(&1, gpu))
m = DLM.Tree.map(starting_m, &Nx.backend_copy(&1, gpu))
v = DLM.Tree.map(starting_v, &Nx.backend_copy(&1, gpu))
h_base = Nx.backend_copy(start_h_base, gpu)
h_top = Nx.backend_copy(start_h_top, gpu)

# ==============================================================================
# 3. DATA STREAM
# ==============================================================================
IO.puts("🧠 Loading Curriculum...")
dataset_2d = File.read!("scholar_full_mixed_128.bin") |> :erlang.binary_to_term()
dataset = Nx.flatten(dataset_2d)
data_stream = DLM.DataStreamer.build_infinite_stream(dataset, batch_size, seq_len)

# ==============================================================================
# 4. THE MASTER LOOP
# ==============================================================================
if start_step != :completed do
  IO.puts("🚀 Entering Continuous Hierarchy Loop...")

  {final_p, _m, _v, _hb, _ht} =
    Enum.reduce(Enum.zip(start_step..(total_steps - 1), data_stream), {p, m, v, h_base, h_top}, 
      fn {step, cpu_batch}, {cp, cm, cv, ch_base, ch_top} ->
        
        gpu_batch = Nx.backend_copy(cpu_batch, gpu)

        # ⚡ 1. Learning Rate Schedule
        base_lr = 1.5e-4
        min_lr = 1.5e-5
        warmup_steps = 1000
        
        current_lr = 
          if step < warmup_steps do
            base_lr * (step / warmup_steps)
          else
            progress = min(max((step - warmup_steps) / (total_steps - warmup_steps), 0.0), 1.0)
            min_lr + 0.5 * (base_lr - min_lr) * (1.0 + :math.cos(:math.pi() * progress))
          end

        # ⚡ 2. The Unified Gradient Tape
        {loss_tensor, grads, next_h_base, next_h_top, avg_g_tensor} = 
          DLM.Main_SSM_Trainer.compute_grad_and_step(
            gpu_batch, ch_base, ch_top, frozen_base_p, frozen_map, cp
          )

        loss_val = Nx.to_number(loss_tensor)
        g_val = Nx.to_number(avg_g_tensor)

        # ⚡ 3. Safety Check
        if loss_val == :nan or loss_val > 20.0 do
          IO.puts("⚠️ Step #{step}: NaN/Spike detected! Flushing Hidden States.")
          clean_h = Nx.broadcast(0.0, {batch_size, 512}) |> Nx.backend_copy(gpu)
          {cp, cm, cv, clean_h, clean_h} # Skip update, flush memory
        else
          # ⚡ 4. Optimizer Step
          lr_tensor = Nx.tensor(current_lr, type: :f32) |> Nx.backend_copy(gpu)
          step_tensor = Nx.tensor(step, type: :f32) |> Nx.backend_copy(gpu)
          
          {up_p, up_m, up_v} = DLM.MuonHybrid.step(cp, grads, cm, cv, step_tensor, lr_tensor)

          # ⚡ 5. Telemetry
          if rem(step, 50) == 0 do
            # Note: Since we use Cosine Distance now, loss is roughly between 0.0 (perfect) and 1.0 (orthogonal)
            mem = :erlang.memory(:total) |> div(1024 * 1024)
            
            # Transfer grads to CPU for inspection to avoid slowing down the GPU tape
            cpu_grads = DLM.Tree.map(grads, &Nx.backend_copy(&1, Nx.BinaryBackend))
            norms = DLM.Main_SSM_Trainer.grad_norms(cpu_grads)
            
            # Sort to find the hottest gradients
            sorted_norms = Enum.sort_by(norms, fn {_k, v} -> v end, :desc)
            {max_name, max_norm} = hd(sorted_norms)
            
            # Specifically check on our critical temporal and gating parameters
            a_norm = Keyword.get(norms, :a_diag)
            gb_norm = Keyword.get(norms, :gate_b)
            valve_norm = Keyword.get(norms, :valve_w) # Watch the Swish syntax valve!

            IO.puts("➡️  Step #{step} | Soft-NN Loss: #{Float.round(loss_val, 4)} | Gate Openness: #{Float.round(g_val * 100, 2)}% | LR: #{Float.round(current_lr, 6)}")
            IO.puts("   📐 GRADS -> Max: [#{max_name}: #{max_norm}] | Valve: #{valve_norm} | Gate Bias: #{gb_norm} | RAM: #{mem}MB")
          end

          # ⚡ 6. Auto-Save
          if rem(step, save_interval) == 0 and step > 0 do
            DLM.CheckpointManager.save_checkpoint(run_prefix, step, up_p, up_m, up_v, next_h_base, next_h_top)
            :erlang.garbage_collect(self())
          end

          {up_p, up_m, up_v, next_h_base, next_h_top}
        end
    end)

  IO.puts("🎉 THE OVERNIGHT BAKE IS COMPLETE!")
  DLM.CheckpointManager.save_checkpoint("#{run_prefix}_final", total_steps, final_p, m, v, h_base, h_top)
end
warning: variable "a_norm" is unused (if the variable is not meant to be used, prefix it with an underscore)
└─ hssmp3.livemd#cell:axsluod5fswd3qcb:121

🌌 Loading Phase 1 Frozen Manifold...

14:58:09.010 [info] XLA service 0x7320d402ffc0 initialized for platform ROCM (this does not guarantee that XLA will be used). Devices:

14:58:09.012 [info]   StreamExecutor [0]: AMD Radeon RX 7600, AMDGPU ISA version: gfx1100 (Driver: 6.4.43482; Runtime: 6.4.43482; Toolkit: 6.4.43482; DNN: 0.0.0)

14:58:09.012 [info] Using BFC allocator.

14:58:09.012 [info] XLA backend will use up to 6429868032 bytes on device 0 for BFCAllocator.

14:58:09.012 [info] XLA backend will use up to 2143289344 bytes on device 0 for CollectiveBFCAllocator.
⚙️ Loading Phase 2 Base SSM (Physics Engine)...
🚀 Auto-Resuming 'v34_DLM_Phase_3_Top_256_midLR' from Step 27000...
🧠 Loading Curriculum...
🚀 Entering Continuous Hierarchy Loop...

14:58:09.488 [info] Merging Dots in computation: region_0.7

14:58:09.488 [info] Merging Dots in computation: region_8.27.clone

14:58:09.488 [info] Merging Dots in computation: region_28.35.clone.clone

15:00:19.930 [info] Merging Dots in computation: region_1.2

15:00:19.930 [info] Merging Dots in computation: region_4.5

15:00:19.930 [info] Merging Dots in computation: region_7.8

15:00:19.930 [info] Merging Dots in computation: region_10.11

15:00:19.930 [info] Merging Dots in computation: region_13.14

15:00:19.930 [info] Merging Dots in computation: region_16.17

15:00:19.930 [info] Merging Dots in computation: region_19.20

15:00:19.930 [info] Merging Dots in computation: region_22.23

15:00:19.930 [info] Merging Dots in computation: region_25.26

15:00:19.930 [info] Merging Dots in computation: region_28.29

15:00:19.930 [info] Merging Dots in computation: region_31.32

15:00:19.930 [info] Merging Dots in computation: region_34.35

15:00:19.930 [info] Merging Dots in computation: region_37.38
➡️  Step 27000 | Cosine Loss: 0.5245 | Gate Openness: 53.49% | LR: 1.28e-4
   📐 GRADS -> Max: [spell_w: 0.4047] | Valve: 0.0241 | Gate Bias: 0.0 | RAM: 230MB
💾 Auto-Saving Checkpoint Step 27000...
➡️  Step 27050 | Cosine Loss: 0.5182 | Gate Openness: 52.91% | LR: 1.28e-4
   📐 GRADS -> Max: [spell_w: 0.3148] | Valve: 0.0252 | Gate Bias: 0.0001 | RAM: 230MB
➡️  Step 27100 | Cosine Loss: 0.5294 | Gate Openness: 54.61% | LR: 1.28e-4
   📐 GRADS -> Max: [spell_w: 0.3007] | Valve: 0.023 | Gate Bias: 0.0001 | RAM: 231MB
➡️  Step 27150 | Cosine Loss: 0.5182 | Gate Openness: 52.99% | LR: 1.28e-4
   📐 GRADS -> Max: [spell_w: 0.276] | Valve: 0.0212 | Gate Bias: 0.0 | RAM: 239MB
➡️  Step 27200 | Cosine Loss: 0.5169 | Gate Openness: 53.0% | LR: 1.28e-4
   📐 GRADS -> Max: [spell_w: 0.3075] | Valve: 0.0263 | Gate Bias: 0.0001 | RAM: 248MB
➡️  Step 27250 | Cosine Loss: 0.5155 | Gate Openness: 55.17% | LR: 1.28e-4
   📐 GRADS -> Max: [spell_w: 0.1925] | Valve: 0.0227 | Gate Bias: 0.0 | RAM: 256MB
➡️  Step 27300 | Cosine Loss: 0.5218 | Gate Openness: 54.4% | LR: 1.28e-4
   📐 GRADS -> Max: [spell_w: 0.4617] | Valve: 0.0213 | Gate Bias: 0.0 | RAM: 240MB
➡️  Step 27350 | Cosine Loss: 0.5256 | Gate Openness: 54.32% | LR: 1.28e-4
   📐 GRADS -> Max: [spell_w: 0.2823] | Valve: 0.0223 | Gate Bias: 0.0 | RAM: 230MB
➡️  Step 27400 | Cosine Loss: 0.508 | Gate Openness: 55.15% | LR: 1.28e-4
   📐 GRADS -> Max: [spell_w: 0.2668] | Valve: 0.0239 | Gate Bias: 0.0 | RAM: 230MB
➡️  Step 27450 | Cosine Loss: 0.5072 | Gate Openness: 54.58% | LR: 1.28e-4
   📐 GRADS -> Max: [spell_w: 0.291] | Valve: 0.022 | Gate Bias: 0.0001 | RAM: 249MB
➡️  Step 27500 | Cosine Loss: 0.5172 | Gate Openness: 54.14% | LR: 1.28e-4
   📐 GRADS -> Max: [spell_w: 0.2232] | Valve: 0.025 | Gate Bias: 0.0001 | RAM: 249MB
➡️  Step 27550 | Cosine Loss: 0.505 | Gate Openness: 55.17% | LR: 1.27e-4
   📐 GRADS -> Max: [spell_w: 0.3234] | Valve: 0.0236 | Gate Bias: 0.0 | RAM: 231MB
➡️  Step 27600 | Cosine Loss: 0.5184 | Gate Openness: 53.78% | LR: 1.27e-4
   📐 GRADS -> Max: [spell_w: 0.2803] | Valve: 0.0222 | Gate Bias: 0.0 | RAM: 231MB
➡️  Step 27650 | Cosine Loss: 0.5212 | Gate Openness: 53.48% | LR: 1.27e-4
   📐 GRADS -> Max: [spell_w: 0.2597] | Valve: 0.0229 | Gate Bias: 0.0 | RAM: 250MB
➡️  Step 27700 | Cosine Loss: 0.5223 | Gate Openness: 54.07% | LR: 1.27e-4
   📐 GRADS -> Max: [spell_w: 0.2741] | Valve: 0.0274 | Gate Bias: 0.0001 | RAM: 244MB
➡️  Step 27750 | Cosine Loss: 0.5041 | Gate Openness: 53.85% | LR: 1.27e-4
   📐 GRADS -> Max: [spell_w: 0.5327] | Valve: 0.0252 | Gate Bias: 0.0 | RAM: 233MB
➡️  Step 27800 | Cosine Loss: 0.5183 | Gate Openness: 53.72% | LR: 1.27e-4
   📐 GRADS -> Max: [spell_w: 0.3677] | Valve: 0.0211 | Gate Bias: 0.0 | RAM: 234MB
➡️  Step 27850 | Cosine Loss: 0.4971 | Gate Openness: 54.1% | LR: 1.27e-4
   📐 GRADS -> Max: [spell_w: 0.2551] | Valve: 0.0225 | Gate Bias: 0.0001 | RAM: 253MB
➡️  Step 27900 | Cosine Loss: 0.5334 | Gate Openness: 53.72% | LR: 1.27e-4
   📐 GRADS -> Max: [spell_w: 0.2377] | Valve: 0.0218 | Gate Bias: 0.0 | RAM: 253MB
➡️  Step 27950 | Cosine Loss: 0.5106 | Gate Openness: 54.1% | LR: 1.27e-4
   📐 GRADS -> Max: [spell_w: 0.2328] | Valve: 0.0214 | Gate Bias: 0.0 | RAM: 235MB
➡️  Step 28000 | Cosine Loss: 0.4978 | Gate Openness: 54.6% | LR: 1.27e-4
   📐 GRADS -> Max: [spell_w: 0.3468] | Valve: 0.0223 | Gate Bias: 0.0 | RAM: 236MB
💾 Auto-Saving Checkpoint Step 28000...
➡️  Step 28050 | Cosine Loss: 0.5127 | Gate Openness: 54.83% | LR: 1.27e-4
   📐 GRADS -> Max: [spell_w: 0.3043] | Valve: 0.0218 | Gate Bias: 0.0 | RAM: 248MB
➡️  Step 28100 | Cosine Loss: 0.5302 | Gate Openness: 54.4% | LR: 1.27e-4
   📐 GRADS -> Max: [spell_w: 0.2488] | Valve: 0.0218 | Gate Bias: 0.0 | RAM: 249MB
➡️  Step 28150 | Cosine Loss: 0.5186 | Gate Openness: 54.22% | LR: 1.26e-4
   📐 GRADS -> Max: [spell_w: 0.2551] | Valve: 0.0218 | Gate Bias: 0.0 | RAM: 249MB
➡️  Step 28200 | Cosine Loss: 0.5136 | Gate Openness: 55.07% | LR: 1.26e-4
   📐 GRADS -> Max: [spell_w: 0.3177] | Valve: 0.0219 | Gate Bias: 0.0 | RAM: 249MB
➡️  Step 28250 | Cosine Loss: 0.5264 | Gate Openness: 52.88% | LR: 1.26e-4
   📐 GRADS -> Max: [spell_w: 0.3352] | Valve: 0.0246 | Gate Bias: 0.0001 | RAM: 257MB
➡️  Step 28300 | Cosine Loss: 0.5163 | Gate Openness: 54.97% | LR: 1.26e-4
   📐 GRADS -> Max: [spell_w: 0.3535] | Valve: 0.0269 | Gate Bias: 0.0001 | RAM: 266MB
➡️  Step 28350 | Cosine Loss: 0.5078 | Gate Openness: 52.83% | LR: 1.26e-4
   📐 GRADS -> Max: [spell_w: 0.3336] | Valve: 0.0249 | Gate Bias: 0.0001 | RAM: 274MB
➡️  Step 28400 | Cosine Loss: 0.5088 | Gate Openness: 54.05% | LR: 1.26e-4
   📐 GRADS -> Max: [spell_w: 0.2233] | Valve: 0.0225 | Gate Bias: 0.0 | RAM: 283MB
➡️  Step 28450 | Cosine Loss: 0.5108 | Gate Openness: 55.02% | LR: 1.26e-4
   📐 GRADS -> Max: [spell_w: 0.2851] | Valve: 0.0226 | Gate Bias: 0.0 | RAM: 291MB
➡️  Step 28500 | Cosine Loss: 0.5322 | Gate Openness: 52.91% | LR: 1.26e-4
   📐 GRADS -> Max: [spell_w: 0.2366] | Valve: 0.0217 | Gate Bias: 0.0001 | RAM: 300MB
➡️  Step 28550 | Cosine Loss: 0.515 | Gate Openness: 54.52% | LR: 1.26e-4
   📐 GRADS -> Max: [spell_w: 0.2988] | Valve: 0.0224 | Gate Bias: 0.0 | RAM: 308MB
➡️  Step 28600 | Cosine Loss: 0.5248 | Gate Openness: 55.39% | LR: 1.26e-4
   📐 GRADS -> Max: [spell_w: 0.31] | Valve: 0.0213 | Gate Bias: 0.0001 | RAM: 317MB
➡️  Step 28650 | Cosine Loss: 0.5247 | Gate Openness: 54.12% | LR: 1.26e-4
   📐 GRADS -> Max: [spell_w: 0.3149] | Valve: 0.023 | Gate Bias: 0.0 | RAM: 325MB
➡️  Step 28700 | Cosine Loss: 0.4996 | Gate Openness: 53.41% | LR: 1.26e-4
   📐 GRADS -> Max: [spell_w: 0.3816] | Valve: 0.0228 | Gate Bias: 0.0001 | RAM: 334MB
➡️  Step 28750 | Cosine Loss: 0.5122 | Gate Openness: 54.38% | LR: 1.25e-4
   📐 GRADS -> Max: [spell_w: 0.3702] | Valve: 0.0248 | Gate Bias: 0.0001 | RAM: 342MB
➡️  Step 28800 | Cosine Loss: 0.5112 | Gate Openness: 53.08% | LR: 1.25e-4
   📐 GRADS -> Max: [spell_w: 0.3293] | Valve: 0.0236 | Gate Bias: 0.0 | RAM: 351MB
➡️  Step 28850 | Cosine Loss: 0.5226 | Gate Openness: 51.22% | LR: 1.25e-4
   📐 GRADS -> Max: [spell_w: 0.4798] | Valve: 0.0246 | Gate Bias: 0.0002 | RAM: 360MB
➡️  Step 28900 | Cosine Loss: 0.5089 | Gate Openness: 54.72% | LR: 1.25e-4
   📐 GRADS -> Max: [spell_w: 0.3496] | Valve: 0.023 | Gate Bias: 0.0 | RAM: 368MB
➡️  Step 28950 | Cosine Loss: 0.5309 | Gate Openness: 54.01% | LR: 1.25e-4
   📐 GRADS -> Max: [spell_w: 0.3386] | Valve: 0.0219 | Gate Bias: 0.0 | RAM: 376MB
➡️  Step 29000 | Cosine Loss: 0.5226 | Gate Openness: 54.52% | LR: 1.25e-4
   📐 GRADS -> Max: [spell_w: 0.3742] | Valve: 0.0225 | Gate Bias: 0.0 | RAM: 386MB
💾 Auto-Saving Checkpoint Step 29000...
➡️  Step 29050 | Cosine Loss: 0.51 | Gate Openness: 53.56% | LR: 1.25e-4
   📐 GRADS -> Max: [spell_w: 0.1987] | Valve: 0.0205 | Gate Bias: 0.0001 | RAM: 199MB
➡️  Step 29100 | Cosine Loss: 0.5143 | Gate Openness: 53.91% | LR: 1.25e-4
   📐 GRADS -> Max: [spell_w: 0.2351] | Valve: 0.0234 | Gate Bias: 0.0 | RAM: 199MB
➡️  Step 29150 | Cosine Loss: 0.5315 | Gate Openness: 53.6% | LR: 1.25e-4
   📐 GRADS -> Max: [spell_w: 0.2556] | Valve: 0.022 | Gate Bias: 0.0001 | RAM: 199MB
➡️  Step 29200 | Cosine Loss: 0.531 | Gate Openness: 52.13% | LR: 1.25e-4
   📐 GRADS -> Max: [spell_w: 0.2524] | Valve: 0.0235 | Gate Bias: 0.0001 | RAM: 208MB
➡️  Step 29250 | Cosine Loss: 0.5299 | Gate Openness: 52.33% | LR: 1.25e-4
   📐 GRADS -> Max: [spell_w: 0.2124] | Valve: 0.0229 | Gate Bias: 0.0002 | RAM: 216MB
➡️  Step 29300 | Cosine Loss: 0.5002 | Gate Openness: 54.6% | LR: 1.25e-4
   📐 GRADS -> Max: [spell_w: 0.3087] | Valve: 0.0235 | Gate Bias: 0.0001 | RAM: 225MB
➡️  Step 29350 | Cosine Loss: 0.5194 | Gate Openness: 53.63% | LR: 1.24e-4
   📐 GRADS -> Max: [spell_w: 0.3127] | Valve: 0.0232 | Gate Bias: 0.0 | RAM: 233MB
➡️  Step 29400 | Cosine Loss: 0.5108 | Gate Openness: 54.18% | LR: 1.24e-4
   📐 GRADS -> Max: [spell_w: 0.3603] | Valve: 0.0269 | Gate Bias: 0.0001 | RAM: 242MB
➡️  Step 29450 | Cosine Loss: 0.5064 | Gate Openness: 55.63% | LR: 1.24e-4
   📐 GRADS -> Max: [spell_w: 0.2499] | Valve: 0.0212 | Gate Bias: 0.0 | RAM: 250MB
➡️  Step 29500 | Cosine Loss: 0.52 | Gate Openness: 52.26% | LR: 1.24e-4
   📐 GRADS -> Max: [spell_w: 0.2451] | Valve: 0.0221 | Gate Bias: 0.0001 | RAM: 259MB
➡️  Step 29550 | Cosine Loss: 0.5155 | Gate Openness: 54.15% | LR: 1.24e-4
   📐 GRADS -> Max: [spell_w: 0.25] | Valve: 0.0221 | Gate Bias: 0.0 | RAM: 267MB
➡️  Step 29600 | Cosine Loss: 0.5098 | Gate Openness: 52.87% | LR: 1.24e-4
   📐 GRADS -> Max: [spell_w: 0.3066] | Valve: 0.0228 | Gate Bias: 0.0001 | RAM: 275MB
➡️  Step 29650 | Cosine Loss: 0.5088 | Gate Openness: 54.24% | LR: 1.24e-4
   📐 GRADS -> Max: [spell_w: 0.2974] | Valve: 0.0245 | Gate Bias: 0.0 | RAM: 284MB
➡️  Step 29700 | Cosine Loss: 0.5021 | Gate Openness: 54.66% | LR: 1.24e-4
   📐 GRADS -> Max: [spell_w: 0.394] | Valve: 0.0251 | Gate Bias: 0.0 | RAM: 293MB
➡️  Step 29750 | Cosine Loss: 0.5089 | Gate Openness: 53.55% | LR: 1.24e-4
   📐 GRADS -> Max: [spell_w: 0.2378] | Valve: 0.0221 | Gate Bias: 0.0 | RAM: 301MB
➡️  Step 29800 | Cosine Loss: 0.5131 | Gate Openness: 54.63% | LR: 1.24e-4
   📐 GRADS -> Max: [spell_w: 0.2927] | Valve: 0.023 | Gate Bias: 0.0 | RAM: 310MB
➡️  Step 29850 | Cosine Loss: 0.5158 | Gate Openness: 53.85% | LR: 1.24e-4
   📐 GRADS -> Max: [spell_w: 0.3016] | Valve: 0.0225 | Gate Bias: 0.0001 | RAM: 318MB
➡️  Step 29900 | Cosine Loss: 0.5268 | Gate Openness: 52.52% | LR: 1.24e-4
   📐 GRADS -> Max: [spell_w: 0.2998] | Valve: 0.0238 | Gate Bias: 0.0001 | RAM: 326MB
➡️  Step 29950 | Cosine Loss: 0.5207 | Gate Openness: 53.4% | LR: 1.23e-4
   📐 GRADS -> Max: [spell_w: 0.2368] | Valve: 0.0212 | Gate Bias: 0.0001 | RAM: 335MB
➡️  Step 30000 | Cosine Loss: 0.5096 | Gate Openness: 55.06% | LR: 1.23e-4
   📐 GRADS -> Max: [spell_w: 0.2396] | Valve: 0.0251 | Gate Bias: 0.0 | RAM: 343MB
💾 Auto-Saving Checkpoint Step 30000...
➡️  Step 30050 | Cosine Loss: 0.5075 | Gate Openness: 54.02% | LR: 1.23e-4
   📐 GRADS -> Max: [spell_w: 0.3743] | Valve: 0.0251 | Gate Bias: 0.0001 | RAM: 203MB
➡️  Step 30100 | Cosine Loss: 0.5252 | Gate Openness: 53.63% | LR: 1.23e-4
   📐 GRADS -> Max: [spell_w: 0.2405] | Valve: 0.0227 | Gate Bias: 0.0001 | RAM: 203MB
➡️  Step 30150 | Cosine Loss: 0.5299 | Gate Openness: 52.86% | LR: 1.23e-4
   📐 GRADS -> Max: [spell_w: 0.4157] | Valve: 0.0245 | Gate Bias: 0.0 | RAM: 212MB
➡️  Step 30200 | Cosine Loss: 0.5139 | Gate Openness: 53.92% | LR: 1.23e-4
   📐 GRADS -> Max: [spell_w: 0.2107] | Valve: 0.0221 | Gate Bias: 0.0 | RAM: 220MB
➡️  Step 30250 | Cosine Loss: 0.5242 | Gate Openness: 54.76% | LR: 1.23e-4
   📐 GRADS -> Max: [spell_w: 0.3045] | Valve: 0.0219 | Gate Bias: 0.0 | RAM: 228MB
➡️  Step 30300 | Cosine Loss: 0.5181 | Gate Openness: 55.53% | LR: 1.23e-4
   📐 GRADS -> Max: [spell_w: 0.345] | Valve: 0.0233 | Gate Bias: 0.0001 | RAM: 237MB
➡️  Step 30350 | Cosine Loss: 0.5291 | Gate Openness: 53.76% | LR: 1.23e-4
   📐 GRADS -> Max: [spell_w: 0.2627] | Valve: 0.0251 | Gate Bias: 0.0 | RAM: 245MB
➡️  Step 30400 | Cosine Loss: 0.5244 | Gate Openness: 54.97% | LR: 1.23e-4
   📐 GRADS -> Max: [spell_w: 0.2903] | Valve: 0.0226 | Gate Bias: 0.0001 | RAM: 254MB
➡️  Step 30450 | Cosine Loss: 0.5288 | Gate Openness: 53.07% | LR: 1.23e-4
   📐 GRADS -> Max: [spell_w: 0.2763] | Valve: 0.0226 | Gate Bias: 0.0001 | RAM: 262MB
➡️  Step 30500 | Cosine Loss: 0.5162 | Gate Openness: 52.76% | LR: 1.23e-4
   📐 GRADS -> Max: [spell_w: 0.2008] | Valve: 0.022 | Gate Bias: 0.0001 | RAM: 203MB
➡️  Step 30550 | Cosine Loss: 0.5233 | Gate Openness: 54.74% | LR: 1.22e-4
   📐 GRADS -> Max: [spell_w: 0.2214] | Valve: 0.0248 | Gate Bias: 0.0 | RAM: 219MB
➡️  Step 30600 | Cosine Loss: 0.5178 | Gate Openness: 55.15% | LR: 1.22e-4
   📐 GRADS -> Max: [spell_w: 0.2858] | Valve: 0.0262 | Gate Bias: 0.0 | RAM: 208MB
➡️  Step 30650 | Cosine Loss: 0.5237 | Gate Openness: 53.23% | LR: 1.22e-4
   📐 GRADS -> Max: [spell_w: 0.2803] | Valve: 0.0231 | Gate Bias: 0.0 | RAM: 208MB
➡️  Step 30700 | Cosine Loss: 0.5075 | Gate Openness: 54.91% | LR: 1.22e-4
   📐 GRADS -> Max: [spell_w: 0.4332] | Valve: 0.0248 | Gate Bias: 0.0 | RAM: 227MB
➡️  Step 30750 | Cosine Loss: 0.5003 | Gate Openness: 53.83% | LR: 1.22e-4
   📐 GRADS -> Max: [spell_w: 0.247] | Valve: 0.0233 | Gate Bias: 0.0 | RAM: 228MB
➡️  Step 30800 | Cosine Loss: 0.5155 | Gate Openness: 54.19% | LR: 1.22e-4
   📐 GRADS -> Max: [spell_w: 0.2458] | Valve: 0.0236 | Gate Bias: 0.0001 | RAM: 210MB
➡️  Step 30850 | Cosine Loss: 0.5109 | Gate Openness: 54.19% | LR: 1.22e-4
   📐 GRADS -> Max: [spell_w: 0.3589] | Valve: 0.0238 | Gate Bias: 0.0 | RAM: 210MB
➡️  Step 30900 | Cosine Loss: 0.5389 | Gate Openness: 53.97% | LR: 1.22e-4
   📐 GRADS -> Max: [spell_w: 0.2994] | Valve: 0.0231 | Gate Bias: 0.0002 | RAM: 223MB
➡️  Step 30950 | Cosine Loss: 0.5131 | Gate Openness: 54.12% | LR: 1.22e-4
   📐 GRADS -> Max: [spell_w: 0.298] | Valve: 0.0224 | Gate Bias: 0.0001 | RAM: 211MB
➡️  Step 31000 | Cosine Loss: 0.5247 | Gate Openness: 53.69% | LR: 1.22e-4
   📐 GRADS -> Max: [spell_w: 0.2951] | Valve: 0.0257 | Gate Bias: 0.0 | RAM: 212MB
💾 Auto-Saving Checkpoint Step 31000...
➡️  Step 31050 | Cosine Loss: 0.4953 | Gate Openness: 53.62% | LR: 1.22e-4
   📐 GRADS -> Max: [spell_w: 0.2286] | Valve: 0.0262 | Gate Bias: 0.0001 | RAM: 224MB
➡️  Step 31100 | Cosine Loss: 0.5187 | Gate Openness: 53.72% | LR: 1.21e-4
   📐 GRADS -> Max: [spell_w: 0.6145] | Valve: 0.0253 | Gate Bias: 0.0001 | RAM: 224MB
➡️  Step 31150 | Cosine Loss: 0.5146 | Gate Openness: 52.73% | LR: 1.21e-4
   📐 GRADS -> Max: [spell_w: 0.2059] | Valve: 0.022 | Gate Bias: 0.0 | RAM: 225MB
➡️  Step 31200 | Cosine Loss: 0.5047 | Gate Openness: 55.18% | LR: 1.21e-4
   📐 GRADS -> Max: [spell_w: 0.2345] | Valve: 0.0223 | Gate Bias: 0.0 | RAM: 225MB
➡️  Step 31250 | Cosine Loss: 0.5025 | Gate Openness: 53.67% | LR: 1.21e-4
   📐 GRADS -> Max: [spell_w: 0.4153] | Valve: 0.0251 | Gate Bias: 0.0 | RAM: 233MB
➡️  Step 31300 | Cosine Loss: 0.5217 | Gate Openness: 53.33% | LR: 1.21e-4
   📐 GRADS -> Max: [spell_w: 0.312] | Valve: 0.0224 | Gate Bias: 0.0 | RAM: 242MB
➡️  Step 31350 | Cosine Loss: 0.4958 | Gate Openness: 54.66% | LR: 1.21e-4
   📐 GRADS -> Max: [spell_w: 0.3892] | Valve: 0.0258 | Gate Bias: 0.0 | RAM: 250MB
➡️  Step 31400 | Cosine Loss: 0.5224 | Gate Openness: 53.93% | LR: 1.21e-4
   📐 GRADS -> Max: [spell_w: 0.3001] | Valve: 0.0243 | Gate Bias: 0.0001 | RAM: 259MB
➡️  Step 31450 | Cosine Loss: 0.5217 | Gate Openness: 54.36% | LR: 1.21e-4
   📐 GRADS -> Max: [spell_w: 0.2301] | Valve: 0.024 | Gate Bias: 0.0001 | RAM: 267MB
➡️  Step 31500 | Cosine Loss: 0.4943 | Gate Openness: 54.7% | LR: 1.21e-4
   📐 GRADS -> Max: [spell_w: 0.2082] | Valve: 0.0228 | Gate Bias: 0.0 | RAM: 276MB
➡️  Step 31550 | Cosine Loss: 0.5096 | Gate Openness: 54.62% | LR: 1.21e-4
   📐 GRADS -> Max: [spell_w: 0.4255] | Valve: 0.0239 | Gate Bias: 0.0 | RAM: 284MB
➡️  Step 31600 | Cosine Loss: 0.5083 | Gate Openness: 53.48% | LR: 1.21e-4
   📐 GRADS -> Max: [spell_w: 0.2523] | Valve: 0.0238 | Gate Bias: 0.0 | RAM: 293MB
➡️  Step 31650 | Cosine Loss: 0.5471 | Gate Openness: 52.22% | LR: 1.21e-4
   📐 GRADS -> Max: [spell_w: 0.7386] | Valve: 0.0463 | Gate Bias: 0.0001 | RAM: 301MB
➡️  Step 31700 | Cosine Loss: 0.5123 | Gate Openness: 54.55% | LR: 1.2e-4
   📐 GRADS -> Max: [spell_w: 0.3778] | Valve: 0.026 | Gate Bias: 0.0001 | RAM: 309MB
➡️  Step 31750 | Cosine Loss: 0.5314 | Gate Openness: 52.99% | LR: 1.2e-4
   📐 GRADS -> Max: [spell_w: 0.2671] | Valve: 0.0229 | Gate Bias: 0.0 | RAM: 318MB
➡️  Step 31800 | Cosine Loss: 0.527 | Gate Openness: 53.73% | LR: 1.2e-4
   📐 GRADS -> Max: [spell_w: 0.3512] | Valve: 0.0251 | Gate Bias: 0.0 | RAM: 328MB
➡️  Step 31850 | Cosine Loss: 0.5245 | Gate Openness: 55.01% | LR: 1.2e-4
   📐 GRADS -> Max: [spell_w: 0.4611] | Valve: 0.0243 | Gate Bias: 0.0001 | RAM: 336MB
➡️  Step 31900 | Cosine Loss: 0.5201 | Gate Openness: 53.63% | LR: 1.2e-4
   📐 GRADS -> Max: [spell_w: 0.2768] | Valve: 0.0261 | Gate Bias: 0.0 | RAM: 344MB
➡️  Step 31950 | Cosine Loss: 0.5239 | Gate Openness: 54.09% | LR: 1.2e-4
   📐 GRADS -> Max: [spell_w: 0.3984] | Valve: 0.0239 | Gate Bias: 0.0 | RAM: 353MB
➡️  Step 32000 | Cosine Loss: 0.5308 | Gate Openness: 54.26% | LR: 1.2e-4
   📐 GRADS -> Max: [spell_w: 0.2697] | Valve: 0.0241 | Gate Bias: 0.0 | RAM: 361MB
💾 Auto-Saving Checkpoint Step 32000...
➡️  Step 32050 | Cosine Loss: 0.5215 | Gate Openness: 54.34% | LR: 1.2e-4
   📐 GRADS -> Max: [spell_w: 0.4252] | Valve: 0.0245 | Gate Bias: 0.0001 | RAM: 225MB
➡️  Step 32100 | Cosine Loss: 0.5276 | Gate Openness: 52.32% | LR: 1.2e-4
   📐 GRADS -> Max: [spell_w: 0.5711] | Valve: 0.0252 | Gate Bias: 0.0 | RAM: 226MB
➡️  Step 32150 | Cosine Loss: 0.5278 | Gate Openness: 55.95% | LR: 1.2e-4
   📐 GRADS -> Max: [spell_w: 0.2698] | Valve: 0.0251 | Gate Bias: 0.0001 | RAM: 234MB
➡️  Step 32200 | Cosine Loss: 0.5042 | Gate Openness: 53.24% | LR: 1.2e-4
   📐 GRADS -> Max: [spell_w: 0.4644] | Valve: 0.0298 | Gate Bias: 0.0001 | RAM: 246MB
➡️  Step 32250 | Cosine Loss: 0.5157 | Gate Openness: 55.82% | LR: 1.19e-4
   📐 GRADS -> Max: [spell_w: 0.2443] | Valve: 0.0233 | Gate Bias: 0.0 | RAM: 255MB
➡️  Step 32300 | Cosine Loss: 0.5276 | Gate Openness: 53.05% | LR: 1.19e-4
   📐 GRADS -> Max: [spell_w: 0.2662] | Valve: 0.0232 | Gate Bias: 0.0 | RAM: 263MB
➡️  Step 32350 | Cosine Loss: 0.5145 | Gate Openness: 54.01% | LR: 1.19e-4
   📐 GRADS -> Max: [spell_w: 0.4754] | Valve: 0.0247 | Gate Bias: 0.0 | RAM: 272MB
➡️  Step 32400 | Cosine Loss: 0.5125 | Gate Openness: 54.61% | LR: 1.19e-4
   📐 GRADS -> Max: [spell_w: 0.7697] | Valve: 0.0271 | Gate Bias: 0.0 | RAM: 280MB
➡️  Step 32450 | Cosine Loss: 0.522 | Gate Openness: 54.88% | LR: 1.19e-4
   📐 GRADS -> Max: [spell_w: 0.3686] | Valve: 0.026 | Gate Bias: 0.0001 | RAM: 224MB
➡️  Step 32500 | Cosine Loss: 0.5165 | Gate Openness: 54.34% | LR: 1.19e-4
   📐 GRADS -> Max: [spell_w: 0.2627] | Valve: 0.0253 | Gate Bias: 0.0001 | RAM: 224MB
➡️  Step 32550 | Cosine Loss: 0.5075 | Gate Openness: 55.99% | LR: 1.19e-4
   📐 GRADS -> Max: [spell_w: 0.3201] | Valve: 0.0245 | Gate Bias: 0.0001 | RAM: 225MB
➡️  Step 32600 | Cosine Loss: 0.5189 | Gate Openness: 53.87% | LR: 1.19e-4
   📐 GRADS -> Max: [spell_w: 0.3482] | Valve: 0.0238 | Gate Bias: 0.0 | RAM: 225MB
➡️  Step 32650 | Cosine Loss: 0.507 | Gate Openness: 53.77% | LR: 1.19e-4
   📐 GRADS -> Max: [spell_w: 0.2367] | Valve: 0.0229 | Gate Bias: 0.0 | RAM: 225MB
➡️  Step 32700 | Cosine Loss: 0.5005 | Gate Openness: 53.22% | LR: 1.19e-4
   📐 GRADS -> Max: [spell_w: 0.3354] | Valve: 0.0261 | Gate Bias: 0.0001 | RAM: 226MB
➡️  Step 32750 | Cosine Loss: 0.5003 | Gate Openness: 54.9% | LR: 1.19e-4
   📐 GRADS -> Max: [spell_w: 0.3323] | Valve: 0.0268 | Gate Bias: 0.0001 | RAM: 226MB
➡️  Step 32800 | Cosine Loss: 0.5032 | Gate Openness: 54.82% | LR: 1.18e-4
   📐 GRADS -> Max: [spell_w: 0.2336] | Valve: 0.0251 | Gate Bias: 0.0001 | RAM: 227MB
➡️  Step 32850 | Cosine Loss: 0.5133 | Gate Openness: 53.15% | LR: 1.18e-4
   📐 GRADS -> Max: [spell_w: 0.1942] | Valve: 0.0246 | Gate Bias: 0.0 | RAM: 227MB
➡️  Step 32900 | Cosine Loss: 0.5261 | Gate Openness: 54.59% | LR: 1.18e-4
   📐 GRADS -> Max: [spell_w: 0.4725] | Valve: 0.0243 | Gate Bias: 0.0001 | RAM: 228MB
➡️  Step 32950 | Cosine Loss: 0.5173 | Gate Openness: 53.61% | LR: 1.18e-4
   📐 GRADS -> Max: [spell_w: 0.3252] | Valve: 0.0254 | Gate Bias: 0.0 | RAM: 228MB
➡️  Step 33000 | Cosine Loss: 0.519 | Gate Openness: 54.23% | LR: 1.18e-4
   📐 GRADS -> Max: [spell_w: 0.5215] | Valve: 0.0251 | Gate Bias: 0.0 | RAM: 229MB
💾 Auto-Saving Checkpoint Step 33000...
➡️  Step 33050 | Cosine Loss: 0.5153 | Gate Openness: 54.01% | LR: 1.18e-4
   📐 GRADS -> Max: [spell_w: 0.2513] | Valve: 0.0246 | Gate Bias: 0.0001 | RAM: 237MB
➡️  Step 33100 | Cosine Loss: 0.519 | Gate Openness: 54.62% | LR: 1.18e-4
   📐 GRADS -> Max: [spell_w: 0.3115] | Valve: 0.0236 | Gate Bias: 0.0001 | RAM: 238MB
➡️  Step 33150 | Cosine Loss: 0.5058 | Gate Openness: 52.85% | LR: 1.18e-4
   📐 GRADS -> Max: [spell_w: 0.4407] | Valve: 0.0251 | Gate Bias: 0.0 | RAM: 246MB
➡️  Step 33200 | Cosine Loss: 0.5201 | Gate Openness: 54.85% | LR: 1.18e-4
   📐 GRADS -> Max: [spell_w: 0.3544] | Valve: 0.0263 | Gate Bias: 0.0001 | RAM: 255MB
➡️  Step 33250 | Cosine Loss: 0.508 | Gate Openness: 53.52% | LR: 1.18e-4
   📐 GRADS -> Max: [spell_w: 0.3135] | Valve: 0.0232 | Gate Bias: 0.0 | RAM: 263MB
➡️  Step 33300 | Cosine Loss: 0.4998 | Gate Openness: 56.07% | LR: 1.18e-4
   📐 GRADS -> Max: [spell_w: 0.3748] | Valve: 0.0235 | Gate Bias: 0.0 | RAM: 272MB
➡️  Step 33350 | Cosine Loss: 0.503 | Gate Openness: 53.48% | LR: 1.17e-4
   📐 GRADS -> Max: [spell_w: 0.2723] | Valve: 0.0276 | Gate Bias: 0.0001 | RAM: 280MB
➡️  Step 33400 | Cosine Loss: 0.5276 | Gate Openness: 53.47% | LR: 1.17e-4
   📐 GRADS -> Max: [spell_w: 0.2936] | Valve: 0.0238 | Gate Bias: 0.0 | RAM: 289MB
➡️  Step 33450 | Cosine Loss: 0.5076 | Gate Openness: 54.11% | LR: 1.17e-4
   📐 GRADS -> Max: [spell_w: 0.2399] | Valve: 0.0236 | Gate Bias: 0.0 | RAM: 297MB
➡️  Step 33500 | Cosine Loss: 0.5121 | Gate Openness: 54.36% | LR: 1.17e-4
   📐 GRADS -> Max: [spell_w: 0.2761] | Valve: 0.0247 | Gate Bias: 0.0001 | RAM: 305MB
➡️  Step 33550 | Cosine Loss: 0.5077 | Gate Openness: 54.8% | LR: 1.17e-4
   📐 GRADS -> Max: [spell_w: 0.337] | Valve: 0.024 | Gate Bias: 0.0001 | RAM: 314MB
➡️  Step 33600 | Cosine Loss: 0.5094 | Gate Openness: 53.88% | LR: 1.17e-4
   📐 GRADS -> Max: [spell_w: 0.2443] | Valve: 0.0246 | Gate Bias: 0.0 | RAM: 322MB
➡️  Step 33650 | Cosine Loss: 0.5086 | Gate Openness: 54.89% | LR: 1.17e-4
   📐 GRADS -> Max: [spell_w: 0.2831] | Valve: 0.025 | Gate Bias: 0.0001 | RAM: 331MB
➡️  Step 33700 | Cosine Loss: 0.494 | Gate Openness: 55.47% | LR: 1.17e-4
   📐 GRADS -> Max: [spell_w: 0.5495] | Valve: 0.0267 | Gate Bias: 0.0 | RAM: 339MB
➡️  Step 33750 | Cosine Loss: 0.5186 | Gate Openness: 53.05% | LR: 1.17e-4
   📐 GRADS -> Max: [spell_w: 0.3156] | Valve: 0.0259 | Gate Bias: 0.0 | RAM: 348MB
➡️  Step 33800 | Cosine Loss: 0.5001 | Gate Openness: 53.83% | LR: 1.17e-4
   📐 GRADS -> Max: [spell_w: 0.3515] | Valve: 0.0289 | Gate Bias: 0.0 | RAM: 356MB
➡️  Step 33850 | Cosine Loss: 0.5141 | Gate Openness: 54.56% | LR: 1.17e-4
   📐 GRADS -> Max: [spell_w: 0.3255] | Valve: 0.0259 | Gate Bias: 0.0 | RAM: 365MB
➡️  Step 33900 | Cosine Loss: 0.512 | Gate Openness: 53.76% | LR: 1.16e-4
   📐 GRADS -> Max: [spell_w: 0.301] | Valve: 0.026 | Gate Bias: 0.0 | RAM: 373MB
➡️  Step 33950 | Cosine Loss: 0.5435 | Gate Openness: 55.32% | LR: 1.16e-4
   📐 GRADS -> Max: [spell_w: 0.2562] | Valve: 0.0259 | Gate Bias: 0.0 | RAM: 382MB
➡️  Step 34000 | Cosine Loss: 0.5108 | Gate Openness: 53.74% | LR: 1.16e-4
   📐 GRADS -> Max: [spell_w: 0.2846] | Valve: 0.0242 | Gate Bias: 0.0 | RAM: 390MB
💾 Auto-Saving Checkpoint Step 34000...
➡️  Step 34050 | Cosine Loss: 0.5093 | Gate Openness: 54.22% | LR: 1.16e-4
   📐 GRADS -> Max: [spell_w: 0.2494] | Valve: 0.0237 | Gate Bias: 0.0 | RAM: 246MB
➡️  Step 34100 | Cosine Loss: 0.5083 | Gate Openness: 54.08% | LR: 1.16e-4
   📐 GRADS -> Max: [spell_w: 0.4403] | Valve: 0.0248 | Gate Bias: 0.0001 | RAM: 246MB
➡️  Step 34150 | Cosine Loss: 0.4943 | Gate Openness: 55.53% | LR: 1.16e-4
   📐 GRADS -> Max: [spell_w: 0.457] | Valve: 0.0283 | Gate Bias: 0.0001 | RAM: 255MB
➡️  Step 34200 | Cosine Loss: 0.5143 | Gate Openness: 54.46% | LR: 1.16e-4
   📐 GRADS -> Max: [spell_w: 0.3412] | Valve: 0.0241 | Gate Bias: 0.0 | RAM: 263MB
➡️  Step 34250 | Cosine Loss: 0.5167 | Gate Openness: 55.09% | LR: 1.16e-4
   📐 GRADS -> Max: [spell_w: 0.2819] | Valve: 0.0269 | Gate Bias: 0.0 | RAM: 272MB
➡️  Step 34300 | Cosine Loss: 0.5149 | Gate Openness: 54.47% | LR: 1.16e-4
   📐 GRADS -> Max: [spell_w: 0.4307] | Valve: 0.0252 | Gate Bias: 0.0001 | RAM: 280MB
➡️  Step 34350 | Cosine Loss: 0.4989 | Gate Openness: 54.56% | LR: 1.16e-4
   📐 GRADS -> Max: [spell_w: 0.2705] | Valve: 0.0233 | Gate Bias: 0.0 | RAM: 289MB
➡️  Step 34400 | Cosine Loss: 0.5227 | Gate Openness: 55.7% | LR: 1.16e-4
   📐 GRADS -> Max: [spell_w: 0.5889] | Valve: 0.0243 | Gate Bias: 0.0001 | RAM: 297MB
➡️  Step 34450 | Cosine Loss: 0.4952 | Gate Openness: 53.88% | LR: 1.15e-4
   📐 GRADS -> Max: [spell_w: 0.285] | Valve: 0.026 | Gate Bias: 0.0 | RAM: 241MB
➡️  Step 34500 | Cosine Loss: 0.4992 | Gate Openness: 54.97% | LR: 1.15e-4
   📐 GRADS -> Max: [spell_w: 0.2465] | Valve: 0.0261 | Gate Bias: 0.0001 | RAM: 241MB
➡️  Step 34550 | Cosine Loss: 0.5151 | Gate Openness: 54.24% | LR: 1.15e-4
   📐 GRADS -> Max: [spell_w: 0.3054] | Valve: 0.0274 | Gate Bias: 0.0001 | RAM: 242MB
➡️  Step 34600 | Cosine Loss: 0.4944 | Gate Openness: 54.74% | LR: 1.15e-4
   📐 GRADS -> Max: [spell_w: 0.3247] | Valve: 0.0271 | Gate Bias: 0.0001 | RAM: 242MB
➡️  Step 34650 | Cosine Loss: 0.5066 | Gate Openness: 54.26% | LR: 1.15e-4
   📐 GRADS -> Max: [spell_w: 0.2901] | Valve: 0.025 | Gate Bias: 0.0001 | RAM: 243MB
➡️  Step 34700 | Cosine Loss: 0.5131 | Gate Openness: 54.96% | LR: 1.15e-4
   📐 GRADS -> Max: [spell_w: 0.2294] | Valve: 0.0238 | Gate Bias: 0.0 | RAM: 243MB
➡️  Step 34750 | Cosine Loss: 0.5119 | Gate Openness: 53.51% | LR: 1.15e-4
   📐 GRADS -> Max: [spell_w: 0.2381] | Valve: 0.0255 | Gate Bias: 0.0001 | RAM: 244MB
➡️  Step 34800 | Cosine Loss: 0.5195 | Gate Openness: 53.83% | LR: 1.15e-4
   📐 GRADS -> Max: [spell_w: 0.2804] | Valve: 0.0251 | Gate Bias: 0.0001 | RAM: 244MB
➡️  Step 34850 | Cosine Loss: 0.491 | Gate Openness: 54.72% | LR: 1.15e-4
   📐 GRADS -> Max: [spell_w: 0.2649] | Valve: 0.0244 | Gate Bias: 0.0001 | RAM: 244MB
➡️  Step 34900 | Cosine Loss: 0.5166 | Gate Openness: 54.32% | LR: 1.15e-4
   📐 GRADS -> Max: [spell_w: 0.3305] | Valve: 0.0236 | Gate Bias: 0.0001 | RAM: 245MB
➡️  Step 34950 | Cosine Loss: 0.5043 | Gate Openness: 53.9% | LR: 1.14e-4
   📐 GRADS -> Max: [spell_w: 0.3088] | Valve: 0.0255 | Gate Bias: 0.0 | RAM: 245MB
➡️  Step 35000 | Cosine Loss: 0.5194 | Gate Openness: 56.14% | LR: 1.14e-4
   📐 GRADS -> Max: [spell_w: 0.253] | Valve: 0.0237 | Gate Bias: 0.0 | RAM: 246MB
💾 Auto-Saving Checkpoint Step 35000...
➡️  Step 35050 | Cosine Loss: 0.5218 | Gate Openness: 54.43% | LR: 1.14e-4
   📐 GRADS -> Max: [spell_w: 0.332] | Valve: 0.0242 | Gate Bias: 0.0001 | RAM: 246MB
➡️  Step 35100 | Cosine Loss: 0.5087 | Gate Openness: 53.0% | LR: 1.14e-4
   📐 GRADS -> Max: [spell_w: 0.2165] | Valve: 0.0232 | Gate Bias: 0.0001 | RAM: 246MB
➡️  Step 35150 | Cosine Loss: 0.5202 | Gate Openness: 54.6% | LR: 1.14e-4
   📐 GRADS -> Max: [spell_w: 0.4291] | Valve: 0.0277 | Gate Bias: 0.0001 | RAM: 264MB
➡️  Step 35200 | Cosine Loss: 0.5095 | Gate Openness: 52.7% | LR: 1.14e-4
   📐 GRADS -> Max: [spell_w: 0.4989] | Valve: 0.0268 | Gate Bias: 0.0001 | RAM: 264MB
➡️  Step 35250 | Cosine Loss: 0.5077 | Gate Openness: 53.35% | LR: 1.14e-4
   📐 GRADS -> Max: [spell_w: 0.6926] | Valve: 0.0285 | Gate Bias: 0.0 | RAM: 264MB
➡️  Step 35300 | Cosine Loss: 0.5029 | Gate Openness: 55.2% | LR: 1.14e-4
   📐 GRADS -> Max: [spell_w: 0.2776] | Valve: 0.0265 | Gate Bias: 0.0 | RAM: 265MB
➡️  Step 35350 | Cosine Loss: 0.5095 | Gate Openness: 53.74% | LR: 1.14e-4
   📐 GRADS -> Max: [spell_w: 0.3353] | Valve: 0.0271 | Gate Bias: 0.0 | RAM: 265MB
➡️  Step 35400 | Cosine Loss: 0.5133 | Gate Openness: 54.55% | LR: 1.14e-4
   📐 GRADS -> Max: [spell_w: 0.4828] | Valve: 0.0278 | Gate Bias: 0.0001 | RAM: 249MB
➡️  Step 35450 | Cosine Loss: 0.4997 | Gate Openness: 55.04% | LR: 1.14e-4
   📐 GRADS -> Max: [spell_w: 0.2736] | Valve: 0.0255 | Gate Bias: 0.0002 | RAM: 250MB
➡️  Step 35500 | Cosine Loss: 0.5166 | Gate Openness: 54.1% | LR: 1.13e-4
   📐 GRADS -> Max: [spell_w: 0.2253] | Valve: 0.0263 | Gate Bias: 0.0 | RAM: 250MB
➡️  Step 35550 | Cosine Loss: 0.5152 | Gate Openness: 55.46% | LR: 1.13e-4
   📐 GRADS -> Max: [spell_w: 0.258] | Valve: 0.0242 | Gate Bias: 0.0 | RAM: 250MB
➡️  Step 35600 | Cosine Loss: 0.4998 | Gate Openness: 54.87% | LR: 1.13e-4
   📐 GRADS -> Max: [spell_w: 0.4468] | Valve: 0.0291 | Gate Bias: 0.0 | RAM: 251MB
➡️  Step 35650 | Cosine Loss: 0.516 | Gate Openness: 53.84% | LR: 1.13e-4
   📐 GRADS -> Max: [spell_w: 0.3027] | Valve: 0.0276 | Gate Bias: 0.0001 | RAM: 251MB
➡️  Step 35700 | Cosine Loss: 0.5021 | Gate Openness: 54.96% | LR: 1.13e-4
   📐 GRADS -> Max: [spell_w: 0.3628] | Valve: 0.0254 | Gate Bias: 0.0 | RAM: 252MB
➡️  Step 35750 | Cosine Loss: 0.5172 | Gate Openness: 52.83% | LR: 1.13e-4
   📐 GRADS -> Max: [spell_w: 0.276] | Valve: 0.0247 | Gate Bias: 0.0002 | RAM: 252MB
➡️  Step 35800 | Cosine Loss: 0.517 | Gate Openness: 54.43% | LR: 1.13e-4
   📐 GRADS -> Max: [spell_w: 0.2985] | Valve: 0.0234 | Gate Bias: 0.0001 | RAM: 253MB
➡️  Step 35850 | Cosine Loss: 0.5118 | Gate Openness: 53.48% | LR: 1.13e-4
   📐 GRADS -> Max: [spell_w: 0.343] | Valve: 0.0272 | Gate Bias: 0.0001 | RAM: 270MB
➡️  Step 35900 | Cosine Loss: 0.5103 | Gate Openness: 55.27% | LR: 1.13e-4
   📐 GRADS -> Max: [spell_w: 0.3489] | Valve: 0.0259 | Gate Bias: 0.0 | RAM: 270MB
➡️  Step 35950 | Cosine Loss: 0.5098 | Gate Openness: 54.39% | LR: 1.13e-4
   📐 GRADS -> Max: [spell_w: 0.3101] | Valve: 0.0271 | Gate Bias: 0.0 | RAM: 270MB
➡️  Step 36000 | Cosine Loss: 0.5063 | Gate Openness: 54.31% | LR: 1.12e-4
   📐 GRADS -> Max: [spell_w: 0.2405] | Valve: 0.0245 | Gate Bias: 0.0 | RAM: 271MB
💾 Auto-Saving Checkpoint Step 36000...
➡️  Step 36050 | Cosine Loss: 0.5065 | Gate Openness: 53.98% | LR: 1.12e-4
   📐 GRADS -> Max: [spell_w: 0.5392] | Valve: 0.0268 | Gate Bias: 0.0 | RAM: 263MB
➡️  Step 36100 | Cosine Loss: 0.5076 | Gate Openness: 55.75% | LR: 1.12e-4
   📐 GRADS -> Max: [spell_w: 0.5903] | Valve: 0.0274 | Gate Bias: 0.0001 | RAM: 264MB
➡️  Step 36150 | Cosine Loss: 0.5045 | Gate Openness: 54.6% | LR: 1.12e-4
   📐 GRADS -> Max: [spell_w: 0.3422] | Valve: 0.0272 | Gate Bias: 0.0002 | RAM: 273MB
➡️  Step 36200 | Cosine Loss: 0.5098 | Gate Openness: 54.78% | LR: 1.12e-4
   📐 GRADS -> Max: [spell_w: 0.3326] | Valve: 0.0275 | Gate Bias: 0.0001 | RAM: 281MB
➡️  Step 36250 | Cosine Loss: 0.5137 | Gate Openness: 55.14% | LR: 1.12e-4
   📐 GRADS -> Max: [spell_w: 0.3523] | Valve: 0.0271 | Gate Bias: 0.0 | RAM: 289MB
➡️  Step 36300 | Cosine Loss: 0.5002 | Gate Openness: 54.38% | LR: 1.12e-4
   📐 GRADS -> Max: [spell_w: 0.305] | Valve: 0.0283 | Gate Bias: 0.0001 | RAM: 257MB
➡️  Step 36350 | Cosine Loss: 0.5024 | Gate Openness: 55.43% | LR: 1.12e-4
   📐 GRADS -> Max: [spell_w: 0.4106] | Valve: 0.0279 | Gate Bias: 0.0001 | RAM: 257MB
➡️  Step 36400 | Cosine Loss: 0.5111 | Gate Openness: 54.49% | LR: 1.12e-4
   📐 GRADS -> Max: [spell_w: 0.3456] | Valve: 0.025 | Gate Bias: 0.0001 | RAM: 258MB
➡️  Step 36450 | Cosine Loss: 0.5321 | Gate Openness: 55.08% | LR: 1.12e-4
   📐 GRADS -> Max: [spell_w: 0.22] | Valve: 0.0247 | Gate Bias: 0.0002 | RAM: 275MB
➡️  Step 36500 | Cosine Loss: 0.4885 | Gate Openness: 54.61% | LR: 1.12e-4
   📐 GRADS -> Max: [spell_w: 0.3394] | Valve: 0.0273 | Gate Bias: 0.0 | RAM: 275MB
➡️  Step 36550 | Cosine Loss: 0.5002 | Gate Openness: 55.49% | LR: 1.11e-4
   📐 GRADS -> Max: [spell_w: 0.5683] | Valve: 0.0333 | Gate Bias: 0.0 | RAM: 276MB
➡️  Step 36600 | Cosine Loss: 0.4974 | Gate Openness: 52.24% | LR: 1.11e-4
   📐 GRADS -> Max: [spell_w: 0.3453] | Valve: 0.026 | Gate Bias: 0.0 | RAM: 276MB
➡️  Step 36650 | Cosine Loss: 0.511 | Gate Openness: 55.67% | LR: 1.11e-4
   📐 GRADS -> Max: [spell_w: 0.5279] | Valve: 0.0269 | Gate Bias: 0.0 | RAM: 260MB
➡️  Step 36700 | Cosine Loss: 0.5125 | Gate Openness: 56.59% | LR: 1.11e-4
   📐 GRADS -> Max: [spell_w: 0.2659] | Valve: 0.0261 | Gate Bias: 0.0001 | RAM: 261MB
➡️  Step 36750 | Cosine Loss: 0.4937 | Gate Openness: 55.48% | LR: 1.11e-4
   📐 GRADS -> Max: [spell_w: 0.4547] | Valve: 0.0288 | Gate Bias: 0.0 | RAM: 261MB
➡️  Step 36800 | Cosine Loss: 0.5174 | Gate Openness: 53.19% | LR: 1.11e-4
   📐 GRADS -> Max: [spell_w: 0.3762] | Valve: 0.0258 | Gate Bias: 0.0001 | RAM: 262MB
➡️  Step 36850 | Cosine Loss: 0.5164 | Gate Openness: 53.51% | LR: 1.11e-4
   📐 GRADS -> Max: [spell_w: 0.3736] | Valve: 0.0267 | Gate Bias: 0.0001 | RAM: 262MB
➡️  Step 36900 | Cosine Loss: 0.4958 | Gate Openness: 53.2% | LR: 1.11e-4
   📐 GRADS -> Max: [spell_w: 0.2553] | Valve: 0.0279 | Gate Bias: 0.0 | RAM: 258MB
➡️  Step 36950 | Cosine Loss: 0.5065 | Gate Openness: 54.83% | LR: 1.11e-4
   📐 GRADS -> Max: [spell_w: 0.3626] | Valve: 0.0225 | Gate Bias: 0.0 | RAM: 267MB
➡️  Step 37000 | Cosine Loss: 0.5029 | Gate Openness: 55.35% | LR: 1.11e-4
   📐 GRADS -> Max: [spell_w: 0.3627] | Valve: 0.0261 | Gate Bias: 0.0001 | RAM: 259MB
💾 Auto-Saving Checkpoint Step 37000...
➡️  Step 37050 | Cosine Loss: 0.5188 | Gate Openness: 52.96% | LR: 1.1e-4
   📐 GRADS -> Max: [spell_w: 0.3412] | Valve: 0.0296 | Gate Bias: 0.0001 | RAM: 280MB