You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
# ===========================================================================# HYBRID OPTIMIZER (AdamW for 1D, Muon for 2D)# ===========================================================================defmoduleDLM.HybridMuon7doimportNx.Defn# -------------------------------------------------------------------------# AdamW (For 1D Friction/Inertia vectors)# -------------------------------------------------------------------------defnadam_step(p,g,m,v,step,lr)dobeta1=0.9beta2=0.999weight_decay=0.01m_new=Nx.add(Nx.multiply(beta1,m),Nx.multiply(1.0-beta1,g))v_new=Nx.add(Nx.multiply(beta2,v),Nx.multiply(1.0-beta2,Nx.pow(g,2)))m_hat=Nx.divide(m_new,Nx.subtract(1.0,Nx.pow(beta1,step)))v_hat=Nx.divide(v_new,Nx.subtract(1.0,Nx.pow(beta2,step)))update_val=Nx.multiply(lr,Nx.divide(m_hat,Nx.add(Nx.sqrt(v_hat),1.0e-8)))p_decayed=Nx.subtract(p,Nx.multiply(Nx.multiply(lr,weight_decay),p))p_new=Nx.subtract(p_decayed,update_val){p_new,m_new,v_new}end# -------------------------------------------------------------------------# Muon Orthogonalization (Newton-Schulz Iteration)# -------------------------------------------------------------------------defnnewton_schulz(g)do# 1. Normalize the gradient matrix to stabilize the iterationnorm=Nx.sqrt(Nx.sum(Nx.pow(g,2)))x_init=Nx.divide(g,Nx.add(norm,1.0e-8))# 2. Run 5 loops of: X = 1.5*X - 0.5*X*(X^T*X){x_final,_}=while{x=x_init,i=0},Nx.less(i,5)dox_t=Nx.transpose(x)x_t_x=Nx.dot(x_t,x)term=Nx.dot(x,x_t_x)x_next=Nx.subtract(Nx.multiply(1.5,x),Nx.multiply(0.5,term)){x_next,i+1}endx_finalend# -------------------------------------------------------------------------# Muon Step (For 2D Transformation Matrices)# -------------------------------------------------------------------------defnmuon_step(p,g,m,v,lr)dobeta1=0.95# Muon standard momentumweight_decay=0.01# Update Momentumm_new=Nx.add(Nx.multiply(beta1,m),Nx.multiply(1.0-beta1,g))# ⚡ THE MAGIC: Orthogonalize the momentum!ortho_update=newton_schulz(m_new)# ⚡ THE FIX: Keep it entirely in the Nx Graphr=Nx.axis_size(p,0)c=Nx.axis_size(p,1)scale=Nx.max(r,c)|>Nx.as_type(:f32)scaled_update=Nx.multiply(ortho_update,scale)# Apply weight decay and stepp_decayed=Nx.subtract(p,Nx.multiply(Nx.multiply(lr,weight_decay),p))p_new=Nx.subtract(p_decayed,Nx.multiply(lr,scaled_update))# Note: Muon doesn't use 'v' (variance), we just pass it back to keep the tuple shapes identical{p_new,m_new,v}end# -------------------------------------------------------------------------# The 7-Parameter Router# -------------------------------------------------------------------------defnupdate(params,grads,ms,vs,step,lr)do{a,bu,bv,cu,cv,du,dv}=params{ga,gbu,gbv,gcu,gcv,gdu,gdv}=grads{ma,mbu,mbv,mcu,mcv,mdu,mdv}=ms{va,vbu,vbv,vcu,vcv,vdu,vdv}=vsnew_step=Nx.add(step,1)# ⚡ 1D Scalar: AdamW{a_new,ma_new,va_new}=adam_step(a,ga,ma,va,new_step,lr)# ⚡ 2D Matrices: Muon Orthogonal Rotations{bu_new,mbu_new,vbu_new}=muon_step(bu,gbu,mbu,vbu,lr){bv_new,mbv_new,vbv_new}=muon_step(bv,gbv,mbv,vbv,lr){cu_new,mcu_new,vcu_new}=muon_step(cu,gcu,mcu,vcu,lr){cv_new,mcv_new,vcv_new}=muon_step(cv,gcv,mcv,vcv,lr){du_new,mdu_new,vdu_new}=muon_step(du,gdu,mdu,vdu,lr){dv_new,mdv_new,vdv_new}=muon_step(dv,gdv,mdv,vdv,lr)new_params={a_new,bu_new,bv_new,cu_new,cv_new,du_new,dv_new}new_ms={ma_new,mbu_new,mbv_new,mcu_new,mcv_new,mdu_new,mdv_new}new_vs={va_new,vbu_new,vbv_new,vcu_new,vcv_new,vdu_new,vdv_new}{new_params,new_ms,new_vs,new_step}endend
warning: DLM.Tree.map/2 is undefined (module DLM.Tree is not available or is yet to be defined)
└─ lpe.livemd#cell:ix2bsm2bfbaikqjk:27: DLM.PhysicsGenesis.init_optimizer/1
defmoduleDLM.Treedo@moduledoc""" Recursively maps a function over nested tuples of tensors. Works perfectly both in standard Elixir AND inside Nx `defn`. """defmap(tuple,func)whenis_tuple(tuple)dotuple|>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 functiondefmap(tensor,func)dofunc.(tensor)endend
defmoduleDLM.ContinuousProbedoimportNx.Defn# ⚡ Find the closest Gravity Well (Token)defndecode_coordinate(predicted_coord,all_token_coords)do# predicted_coord shape: {512}# all_token_coords shape: {256, 512}# Calculate Euclidean (squared) distance to every possible ASCII tokendistances=Nx.sum(Nx.pow(Nx.subtract(all_token_coords,predicted_coord),2),axes: [-1])# Return the index of the closest coordinate (which maps 1:1 to the ASCII integer!)Nx.argmin(distances)endend
# ==============================================================================# THE CONTINUOUS PROBE (SHAPE-CORRECTED)# ==============================================================================# ⚡ UPDATE THESE FILENAMES TO MATCH YOUR SAVED WEIGHTSteacher_params=File.read!("v32_mse_geo_enc_4_checkpoint_step_1000.bin")|>:erlang.binary_to_term()IO.puts("🧊 Loading Frozen Micro-Diffusion Tokenizer..."){fw1,fw2}=File.read!("semantic_bytes_frozen_9_encoder.bin")|>:erlang.binary_to_term()frozen_w1=Nx.backend_copy(fw1,gpu)frozen_w2=Nx.backend_copy(fw2,gpu)# create byte look up tablefeature_table=DLM.CharFeaturizer.build_feature_table(range: 0..127)gpu_table=Nx.backend_copy(feature_table,gpu)# 🌌 Materialize the entire 512D Gravity Well Mapall_ascii=Nx.tensor(Enum.to_list(0..255),type: :u32)|>Nx.reshape({256,1})all_token_coords_raw=DLM.PhysicsEngine.get_coordinates(all_ascii,frozen_w1,frozen_w2,gpu_table)# Extract the flat {256, 512} lookup tableall_token_coords=all_token_coords_raw[[..,0,..]]|>Nx.backend_copy(gpu)# ⚡ THE FIX: Initialize Teacher's hidden state as a FLAT {512} vectorh_zeros=Nx.broadcast(0.0,{512})|>Nx.backend_copy(gpu)prompt_text="Hello, my na"prompt_tokens_tensor=DLM.LatentTokenizer.to_ascii_tokens(prompt_text)prompt_tokens=Nx.to_flat_list(prompt_tokens_tensor)IO.puts("🧠 Burning in the Pondering Teacher...")# ⚡ BURN-IN{final_h,last_coord}=Enum.reduce(prompt_tokens,{h_zeros,nil},fntok,{h,_}-># Get the perfect physical coordinate for this tokentok_tensor=Nx.tensor([[tok]],type: :u32)|>Nx.backend_copy(gpu)actual_coord=DLM.PhysicsEngine.get_coordinates(tok_tensor,frozen_w1,frozen_w2,gpu_table)[0][0]# ⚡ The Teacher ponders the coordinate!{_,next_h}=DLM.PhysicsEngine.predict_step(actual_coord,h,teacher_params){next_h,actual_coord}end)IO.puts("\nPrompt: \"#{prompt_text}\"\n")IO.write("Teacher: ")# ⚡ CONTINUOUS GENERATION WITH TEMPERATURE# Temperature (0.02 is a good start)temp_scale=0.05initial_key=Nx.Random.key(42)|>Nx.backend_copy(gpu)# ⚡ CONTINUOUS GENERATION WITH LANGEVIN TEMPERATUREEnum.reduce(1..150,{final_h,last_coord,initial_key},fn_step,{h,current_coord,cur_key}->{predicted_coord,next_h}=DLM.PhysicsEngine.predict_step(current_coord,h,teacher_params)# ⚡ Langevin Kick{noise,next_key}=Nx.Random.normal(cur_key,0.0,temp_scale,shape: {512})stochastic_coord=Nx.add(predicted_coord,noise)next_token_id=DLM.ContinuousProbe.decode_coordinate(stochastic_coord,all_token_coords)token_val=Nx.to_number(next_token_id)# 4. Telemetry (Void/Char logic)char_to_print=conddotoken_valin32..126-><<token_val>>token_valin[9,10,13]-><<token_val>>true->"░"endIO.write(char_to_print)# 5. Snap to the pure gravity well for the NEXT step# This prevents the noise from accumulating in the hidden statesnapped_coord=all_token_coords[next_token_id]{next_h,snapped_coord,next_key}end)IO.puts("\n\n🐑 Dream Complete.")
🧊 Loading Frozen Micro-Diffusion Tokenizer...
🧠 Burning in the Pondering Teacher...
Prompt: "Hello, my na"
Teacher: hhhhhhhhhhhxhhhhxphxxhxhhhhhxhppphhhxhhhhhhhhxhhhxhxxhhhhhhhhhhhhxhxhhhxhhhhhhhhhhhxhhhhhhhhxhhhhxhhxhhhpxhhxhhhhhxhhhhxxhphhbhhhhhhhhhhhhhxhhhhhhhxhh
🐑 Dream Complete.
:ok
Stream
defmoduleDLM.DataStreamerdodefstream(path,seq_len,batch_size)dolines=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(fnchunk->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(fnbatch->{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. """defbuild_infinite_stream(dataset_1d,batch_size,seq_len)dochunk_size=batch_size*seq_lentotal_tokens=Nx.size(dataset_1d)# Calculate how many full batches we can maketotal_batches=div(total_tokens,chunk_size)0..(total_batches-1)|>Stream.cycle()# ⚡ Loops infinitely!|>Stream.map(fnbatch_idx->start_idx=batch_idx*chunk_size# Slice out the flat chunk and reshape it for the batchdataset_1d|>Nx.slice_along_axis(start_idx,chunk_size,axis: 0)|>Nx.reshape({batch_size,seq_len})end)endend
defmoduleDLM.LatentTokenizerdoimportNx.Defn# deftransform runs pure Elixir at compile time — safe to use Tuple.append heredeftransformappend_feat_dim(token_shape,feat_dim)doTuple.insert_at(token_shape,tuple_size(token_shape),feat_dim)enddefnto_utf8_bits(tokens,table)dofeat_dim=Nx.axis_size(table,1)flat=Nx.flatten(tokens)looked_up=Nx.take(table,flat)new_shape=append_feat_dim(Nx.shape(tokens),feat_dim)Nx.reshape(looked_up,new_shape)end@doc""" Converts a standard Elixir string into a 1D tensor of ASCII integers. Example: "Cat" -> #Nx.Tensor<[67, 97, 116]> """defto_ascii_tokens(string)dostring|>String.to_charlist()|>Nx.tensor(type: :u8)# u8 matches your 0-255 ASCII setupenddefnsoftplus(x)doNx.select(x>20.0,x,Nx.log1p(Nx.exp(x)))end# ⚡ Add rms_norm to the tokenizerdefnrms_norm(x,epsilon\\1.0e-6)dovariance=Nx.mean(Nx.pow(x,2),axes: [-1],keep_axes: true)x*Nx.rsqrt(variance+epsilon)enddefnforward(tokens,params,table,key,noise_scale\\0.15)do{enc_w1,enc_w2,dec_w1,dec_w2}=paramsbits=to_utf8_bits(tokens,table)# Squeeze the middle dim: {batch, 1, 38} → {batch, 38}bits=Nx.squeeze(bits,axes: [1])hidden_enc=softplus(Nx.dot(bits,enc_w1))# ⚡ FIX: The Latent Trap! Normalize the vectors BEFORE adding noise.raw_latents=Nx.dot(hidden_enc,enc_w2)latents=rms_norm(raw_latents){noise,next_key}=Nx.Random.normal(key,0.0,1.0,shape: Nx.shape(latents))noisy_latents=latents+(noise*noise_scale)hidden_dec=softplus(Nx.dot(noisy_latents,dec_w1))logits=Nx.dot(hidden_dec,dec_w2){logits,noisy_latents,next_key}endend
defmoduleDLM.LatentRadardoimportNx.Defn# 1. Recreate the exact deterministic path from your Tokenizerdefnget_coordinates(tokens,enc_w1,enc_w2,table)dobits=DLM.LatentTokenizer.to_utf8_bits(tokens,table)hidden_enc=DLM.LatentTokenizer.softplus(Nx.dot(bits,enc_w1))raw_latents=Nx.dot(hidden_enc,enc_w2)# The crucial latents trap!DLM.LatentTokenizer.rms_norm(raw_latents)end# 2. Calculate the physical distance between all 128 points simultaneouslydefnpairwise_distances(coords)do# Expand shapes to {128, 1, 512} and {1, 128, 512}a=Nx.new_axis(coords,1)b=Nx.new_axis(coords,0)# Calculate the difference, square it, sum along the 512D axis, and take the square rootdiff=Nx.subtract(a,b)Nx.sqrt(Nx.sum(Nx.pow(diff,2),axes: [-1]))endend
defmoduleDLM.SinkhornOTdoimportNx.Defndefncost_matrix(pred,target)dop_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 scaledefncompute(pred,target,epsilon\\10.0,max_iters\\5)doc=cost_matrix(pred,target)k=Nx.exp(Nx.divide(Nx.negate(c),epsilon))batch_size=Nx.axis_size(pred,0)mass=1.0/batch_sizemu=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 crashesdenom_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}endu_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))endend
defmoduleDLM.PhysicsLossdoimportNx.Defn# ⚡ Universal L2 Normalizer (Works on 2D, 3D, N-D tensors)defnl2_normalize(tensor)do# Calculate Euclidean norm across the last axis nativelynorm=Nx.sqrt(Nx.sum(Nx.pow(tensor,2),axes: [-1],keep_axes: true))# Divide by norm with a tiny epsilon to prevent divide-by-zeroNx.divide(tensor,Nx.add(norm,1.0e-6))end# ⚡ 1. Angular Alignment (Cosine Distance)defncosine_distance(pred,target)dop_norm=l2_normalize(pred)t_norm=l2_normalize(target)# Dot product across the 512 dimensioncos_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)defnsoft_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 batchsim_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 stabilitymax_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# defn compute(pred, target) do# mse = Nx.mean(Nx.pow(Nx.subtract(pred, target), 2))# cos = cosine_distance(pred, target)# # ⚡ Update the explicit epsilon call here to 10.0# ot_loss = DLM.SinkhornOT.compute(pred, target, 5.0, 5)# Nx.add(Nx.add(mse, cos), Nx.multiply(ot_loss, 0.5))# enddefncompute(pred,target)do# Simple MSE in 512D coordinate space# The encoder's geometry makes this meaningfulNx.mean(Nx.pow(Nx.subtract(pred,target),2))endend
defmoduleDLM.CheckpointManagerdo@moduledoc""" Scans the directory for the latest checkpoint of a specific run prefix. If no checkpoints exist, it triggers a completely fresh initialization. """defget_resume_state(run_prefix)docheckpoints=Path.wildcard("#{run_prefix}_checkpoint_step_*.bin")ifEnum.empty?(checkpoints)doifFile.exists?("#{run_prefix}_final.bin")doIO.puts("✨ Found completed run: #{run_prefix}_final.bin"){"#{run_prefix}_final.bin",:completed}elseIO.puts("✨ No checkpoints found for '#{run_prefix}'. Starting FRESH from Genesis."){:fresh,0}endelse# Extract step numbers using regex and find the maximumlatest_file=Enum.max_by(checkpoints,fnfile->caseRegex.run(~r/_step_(\d+)\.bin$/,file)do[_,step_str]->String.to_integer(step_str)_->-1endend)[_,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}endendend
# ===========================================================================# THE EXECUTION LOOP (With Auto-Resume & Fresh Genesis logic)# ===========================================================================# ⚡ 1. DEFINE YOUR RUN CONFIGURATION HERErun_prefix="v32_mse_geo_enc_4"total_steps=15000# ⚡ 2. CHECK RESUME STATE (No more base_weights passed in!){load_path,start_step}=DLM.CheckpointManager.get_resume_state(run_prefix)ifstart_step==:completeddoIO.puts("✅ This run has already reached #{total_steps} steps. Exiting.")elseIO.puts("🧊 Loading Frozen Micro-Diffusion Tokenizer..."){fw1,fw2}=File.read!("semantic_bytes_frozen_9_encoder.bin")|>:erlang.binary_to_term()gpu={EXLA.Backend,client: :rocm}frozen_w1=Nx.backend_copy(fw1,gpu)frozen_w2=Nx.backend_copy(fw2,gpu)batch_size=32seq_len=128IO.puts("🧠 Loading LPSSM 128seqlen training data CPU Memory...")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)# ⚡ 3. BRANCHING WEIGHT INITIALIZATION{starting_params,initial_key}=ifload_path==:freshdoIO.puts("✨ Igniting brand new Genesis weights for #{run_prefix}...")DLM.PhysicsGenesis.ignite(Nx.Random.key(System.system_time()))elseIO.puts("✨ Loading Weights from #{load_path}...")loaded_p=File.read!(load_path)|>:erlang.binary_to_term()# Give it a fresh noise key even if resuming{loaded_p,Nx.Random.key(System.system_time())}end# Initialize the optimizer states with zeroes{m,v,step_count}=DLM.PhysicsGenesis.init_optimizer(starting_params)# Move everything to the GPUp=DLM.Tree.map(starting_params,&Nx.backend_copy(&1,gpu))m=DLM.Tree.map(m,&Nx.backend_copy(&1,gpu))v=DLM.Tree.map(v,&Nx.backend_copy(&1,gpu))step_count=Nx.tensor(start_step)|>Nx.backend_copy(gpu)# create byte look up tablefeature_table=DLM.CharFeaturizer.build_feature_table(range: 0..127)gpu_table=Nx.backend_copy(feature_table,gpu)# ⚡ 4. ZIP FROM THE START_STEP{final_p,_m,_v,_key,_step}=Enum.reduce(Enum.zip(start_step..(total_steps-1),data_stream),{p,m,v,initial_key,step_count},fn{step,cpu_batch},{cp,cm,cv,cur_key,c_step}->gpu_batch=Nx.backend_copy(cpu_batch,gpu)# ⚡ DYNAMIC LEARNING RATE SCHEDULERmax_lr=1.2e-5# Enough power to reach the canyon, slow enough to stay in itwarmup_steps=800# Give the fluid more time to build momentumcurrent_lr=ifstep<warmup_stepsdo# Linear Warmup: Gently ramp up to max_lrmax_lr*(step/warmup_steps)else# Cosine Decay: Smoothly brake as we approach total_stepsdecay_ratio=(step-warmup_steps)/(total_steps-warmup_steps)max_lr*0.5*(1.0+:math.cos(:math.pi()*decay_ratio))end# ⚡ Inject a gentle 5% Brownian motion to prevent limit cyclesnoise_scale=0.05# Change to 0.02 when testing the Drunk Driverlr_tensor=Nx.tensor(current_lr,type: :f32)|>Nx.backend_copy(gpu)noise_tensor=Nx.tensor(noise_scale,type: :f32)|>Nx.backend_copy(gpu)h_init=Nx.broadcast(0.0,{batch_size,512})|>Nx.as_type(:f32)|>Nx.backend_copy(gpu)split_keys=Nx.Random.split(cur_key)noise_key=split_keys[0]next_key=split_keys[1]{loss_tensor,h_final,grads}=DLM.PhysicsEngine.compute_grad(cp,gpu_batch,h_init,frozen_w1,frozen_w2,noise_key,noise_tensor,gpu_table)# ⚡ MEMORY FIX 1: Read the loss into Elixir BEFORE the optimizer mutates memoryloss_val=ifrem(step,50)==0,do: Nx.to_number(loss_tensor),else: 0.0{up_p,up_m,up_v,up_step}=DLM.HybridMuon7.update(cp,grads,cm,cv,c_step,lr_tensor)# ➡️ Telemetryifrem(step,50)==0do{_a,_bu,bv,_cu,_cv,_du,dv}=up_ph_norm=h_final|>Nx.pow(2)|>Nx.mean()|>Nx.sqrt()|>Nx.to_number()bv_norm=bv|>Nx.pow(2)|>Nx.sum()|>Nx.sqrt()|>Nx.to_number()dv_norm=dv|>Nx.pow(2)|>Nx.sum()|>Nx.sqrt()|>Nx.to_number()IO.puts("➡️ Step #{step} | Geometric Loss: #{Float.round(loss_val,4)} | LR: #{Float.round(current_lr,6)} | bv: #{Float.round(bv_norm,4)} | dv: #{Float.round(dv_norm,4)} | h_norm: #{h_norm}")end# 💾 DYNAMIC CHECKPOINT SAVINGifrem(step,1000)==0andstep>0doIO.puts("💾 Checkpoint reached! Saving Step #{step}...")# ⚡ MEMORY FIX 2: Use backend_copy instead of backend_transfer mid-loop!cpu_snapshot=DLM.Tree.map(up_p,&Nx.backend_copy(&1,Nx.BinaryBackend))filename="#{run_prefix}_checkpoint_step_#{step}.bin"File.write!(filename,:erlang.term_to_binary(cpu_snapshot)):erlang.garbage_collect()end{up_p,up_m,up_v,next_key,up_step}end)IO.puts("💾 Saving Final Gated Physics Engine Weights...")# It is safe to use backend_transfer here because the run is overgood_params=DLM.Tree.map(final_p,&Nx.backend_transfer(&1,Nx.BinaryBackend))File.write!("#{run_prefix}_final.bin",:erlang.term_to_binary(good_params))IO.puts("✅ Resaved with clean CPU tensors")IO.puts("✅ Physics Engine Training Complete!")end