Spaces:
Sleeping
Sleeping
Upload threejs_component.py
Browse files- threejs_component.py +281 -0
threejs_component.py
ADDED
|
@@ -0,0 +1,281 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Three.js 3D BDH Walkthrough β self-contained HTML for st.components.v1.html()"""
|
| 2 |
+
|
| 3 |
+
def get_threejs_html(bdh_layer_activations, tf_layer_activations):
|
| 4 |
+
import json, numpy as np
|
| 5 |
+
|
| 6 |
+
N_NEURONS = 25 # 5Γ5 grid per layer
|
| 7 |
+
def prep(stats_list, n=N_NEURONS):
|
| 8 |
+
layers = []
|
| 9 |
+
for s in stats_list:
|
| 10 |
+
acts = s["activations"].mean(0)[:n]
|
| 11 |
+
acts = (acts - acts.min()) / (acts.max() - acts.min() + 1e-8)
|
| 12 |
+
layers.append(acts.tolist())
|
| 13 |
+
return layers
|
| 14 |
+
|
| 15 |
+
bdh_data = json.dumps(prep(bdh_layer_activations))
|
| 16 |
+
tf_data = json.dumps(prep(tf_layer_activations))
|
| 17 |
+
n_layers = len(bdh_layer_activations)
|
| 18 |
+
|
| 19 |
+
return f"""<!DOCTYPE html>
|
| 20 |
+
<html>
|
| 21 |
+
<head>
|
| 22 |
+
<style>
|
| 23 |
+
body{{margin:0;background:#0d1117;overflow:hidden;font-family:monospace}}
|
| 24 |
+
canvas{{display:block}}
|
| 25 |
+
#ui{{position:absolute;top:12px;left:50%;transform:translateX(-50%);
|
| 26 |
+
display:flex;gap:10px;align-items:center;z-index:10}}
|
| 27 |
+
.btn{{background:#f97316;color:#fff;border:none;padding:7px 16px;
|
| 28 |
+
border-radius:8px;font-size:.82rem;font-weight:700;cursor:pointer}}
|
| 29 |
+
.btn:hover{{background:#fb923c}}
|
| 30 |
+
.btn.on{{background:#22c55e}}
|
| 31 |
+
#lbdh{{position:absolute;top:52px;left:25%;transform:translateX(-50%);
|
| 32 |
+
color:#f97316;font-weight:700;font-size:.95rem;pointer-events:none;
|
| 33 |
+
text-shadow:0 0 12px #f97316}}
|
| 34 |
+
#ltf{{position:absolute;top:52px;left:75%;transform:translateX(-50%);
|
| 35 |
+
color:#3b82f6;font-weight:700;font-size:.95rem;pointer-events:none;
|
| 36 |
+
text-shadow:0 0 12px #3b82f6}}
|
| 37 |
+
#info{{position:absolute;bottom:10px;left:50%;transform:translateX(-50%);
|
| 38 |
+
color:#8b949e;font-size:.75rem;text-align:center;pointer-events:none}}
|
| 39 |
+
#leg{{position:absolute;top:52px;right:14px;color:#8b949e;
|
| 40 |
+
font-size:.73rem;line-height:1.9}}
|
| 41 |
+
.dot{{display:inline-block;width:9px;height:9px;border-radius:50%;margin-right:5px}}
|
| 42 |
+
</style>
|
| 43 |
+
</head>
|
| 44 |
+
<body>
|
| 45 |
+
<div id="ui">
|
| 46 |
+
<button class="btn" id="bRot">β³ Auto-rotate</button>
|
| 47 |
+
<button class="btn" id="bPulse">β‘ Pulse Signal</button>
|
| 48 |
+
<button class="btn" id="bReset">βΊ Reset</button>
|
| 49 |
+
</div>
|
| 50 |
+
<div id="lbdh">π BDH β Sparse ReLU</div>
|
| 51 |
+
<div id="ltf">π€ Transformer β Dense GELU</div>
|
| 52 |
+
<div id="leg">
|
| 53 |
+
<div><span class="dot" style="background:#f97316"></span>BDH active</div>
|
| 54 |
+
<div><span class="dot" style="background:#4b6484;border:1px solid #5b7494"></span>BDH silent (~50%)</div>
|
| 55 |
+
<div><span class="dot" style="background:#3b82f6"></span>Transformer (always on)</div>
|
| 56 |
+
<div style="margin-top:5px;color:#6b7280">Drag Β· Scroll to zoom</div>
|
| 57 |
+
</div>
|
| 58 |
+
<div id="info">3D BDH Walkthrough β {n_layers} layers Γ {N_NEURONS} neurons (5Γ5) per side</div>
|
| 59 |
+
|
| 60 |
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
|
| 61 |
+
<script>
|
| 62 |
+
const BDH_DATA = {bdh_data};
|
| 63 |
+
const TF_DATA = {tf_data};
|
| 64 |
+
const N_LAYERS = {n_layers};
|
| 65 |
+
const N_NEURONS = {N_NEURONS};
|
| 66 |
+
const COLS = 5; // 5Γ5 grid
|
| 67 |
+
|
| 68 |
+
const scene = new THREE.Scene();
|
| 69 |
+
scene.background = new THREE.Color(0x0d1117);
|
| 70 |
+
scene.fog = new THREE.Fog(0x0d1117, 35, 95);
|
| 71 |
+
|
| 72 |
+
const W = window.innerWidth, H = window.innerHeight;
|
| 73 |
+
const camera = new THREE.PerspectiveCamera(52, W/H, 0.1, 200);
|
| 74 |
+
camera.position.set(0, 4, 30);
|
| 75 |
+
|
| 76 |
+
const renderer = new THREE.WebGLRenderer({{antialias:true}});
|
| 77 |
+
renderer.setPixelRatio(window.devicePixelRatio);
|
| 78 |
+
renderer.setSize(W, H);
|
| 79 |
+
document.body.appendChild(renderer.domElement);
|
| 80 |
+
|
| 81 |
+
scene.add(new THREE.AmbientLight(0xffffff, 0.4));
|
| 82 |
+
const pl1 = new THREE.PointLight(0xf97316, 1.8, 70);
|
| 83 |
+
pl1.position.set(-9, 9, 14); scene.add(pl1);
|
| 84 |
+
const pl2 = new THREE.PointLight(0x3b82f6, 1.8, 70);
|
| 85 |
+
pl2.position.set(9, 9, 14); scene.add(pl2);
|
| 86 |
+
|
| 87 |
+
// ββ Pivot: ALL objects go in here so rotation works ββββββββββββββββββββββββ
|
| 88 |
+
const pivot = new THREE.Group();
|
| 89 |
+
scene.add(pivot);
|
| 90 |
+
|
| 91 |
+
const SPHERE = new THREE.SphereGeometry(0.23, 10, 10);
|
| 92 |
+
const LAYER_SEP = 4.8;
|
| 93 |
+
const SIDE_OFFSET = 8.5;
|
| 94 |
+
const GRID_SCALE = 0.9;
|
| 95 |
+
|
| 96 |
+
function gridPos(idx) {{
|
| 97 |
+
const col = idx % COLS, row = Math.floor(idx / COLS);
|
| 98 |
+
const cx = (COLS-1)/2, cy = (Math.ceil(N_NEURONS/COLS)-1)/2;
|
| 99 |
+
return {{x:(col-cx)*GRID_SCALE, y:(cy-row)*GRID_SCALE}};
|
| 100 |
+
}}
|
| 101 |
+
|
| 102 |
+
const bdhMeshes=[], tfMeshes=[], bdhMats=[], tfMats=[];
|
| 103 |
+
|
| 104 |
+
for (let l=0; l<N_LAYERS; l++) {{
|
| 105 |
+
const z = -(l-(N_LAYERS-1)/2)*LAYER_SEP;
|
| 106 |
+
for (let ni=0; ni<N_NEURONS; ni++) {{
|
| 107 |
+
const gp = gridPos(ni);
|
| 108 |
+
|
| 109 |
+
// ββ BDH neuron ββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 110 |
+
const bAct = BDH_DATA[l][ni];
|
| 111 |
+
const silent = bAct < 0.08; // ReLU hard zero threshold
|
| 112 |
+
const bMat = new THREE.MeshPhongMaterial({{
|
| 113 |
+
color: silent ? 0x4b6484 : 0xf97316,
|
| 114 |
+
emissive: silent ? new THREE.Color(0x1a2535) : new THREE.Color(0xf97316).multiplyScalar(bAct*0.55),
|
| 115 |
+
transparent: true,
|
| 116 |
+
opacity: silent ? 0.55 : 0.88 + bAct*0.12,
|
| 117 |
+
shininess: silent ? 10 : 60,
|
| 118 |
+
}});
|
| 119 |
+
const bMesh = new THREE.Mesh(SPHERE, bMat);
|
| 120 |
+
bMesh.position.set(-SIDE_OFFSET+gp.x, gp.y, z);
|
| 121 |
+
bMesh.scale.setScalar(silent ? 0.58 : 0.78+bAct*0.48);
|
| 122 |
+
bMesh.userData = {{l, ni, act:bAct, silent}};
|
| 123 |
+
pivot.add(bMesh); // β pivot, not scene
|
| 124 |
+
bdhMeshes.push(bMesh); bdhMats.push(bMat);
|
| 125 |
+
|
| 126 |
+
// ββ Transformer neuron (GELU: always active) ββββββββββββββββββββββββ
|
| 127 |
+
const tAct = TF_DATA[l][ni];
|
| 128 |
+
const tMat = new THREE.MeshPhongMaterial({{
|
| 129 |
+
color: 0x3b82f6,
|
| 130 |
+
emissive:new THREE.Color(0x3b82f6).multiplyScalar(0.38+tAct*0.38),
|
| 131 |
+
transparent:true, opacity:0.80+tAct*0.18, shininess:50,
|
| 132 |
+
}});
|
| 133 |
+
const tMesh = new THREE.Mesh(SPHERE, tMat);
|
| 134 |
+
tMesh.position.set(SIDE_OFFSET+gp.x, gp.y, z);
|
| 135 |
+
tMesh.scale.setScalar(0.72+tAct*0.42);
|
| 136 |
+
tMesh.userData = {{l, ni, act:tAct, silent:false}};
|
| 137 |
+
pivot.add(tMesh); // β pivot
|
| 138 |
+
tfMeshes.push(tMesh); tfMats.push(tMat);
|
| 139 |
+
}}
|
| 140 |
+
}}
|
| 141 |
+
|
| 142 |
+
// ββ Edges β also added to pivot so they rotate with neurons βββββββββββββββ
|
| 143 |
+
const bdhEdgeMats = [], tfEdgeMats = [];
|
| 144 |
+
|
| 145 |
+
function addEdges(meshes, color, maxEdgesPerLayer, edgeMatsArr) {{
|
| 146 |
+
const pts = [];
|
| 147 |
+
for (let l=0; l<N_LAYERS-1; l++) {{
|
| 148 |
+
const base = l*N_NEURONS;
|
| 149 |
+
let count = 0;
|
| 150 |
+
// Connect neurons between current layer (l) and next layer (l+1)
|
| 151 |
+
for (let ni=0; ni<N_NEURONS; ni++) {{
|
| 152 |
+
const src = meshes[base+ni];
|
| 153 |
+
if (src.userData.silent) continue;
|
| 154 |
+
|
| 155 |
+
for (let nj=0; nj<N_NEURONS; nj+=2) {{ // nj+=2 spreads edges out visually
|
| 156 |
+
const dst = meshes[base+N_NEURONS+nj];
|
| 157 |
+
if (dst.userData.silent) continue;
|
| 158 |
+
|
| 159 |
+
if (count < maxEdgesPerLayer) {{
|
| 160 |
+
pts.push(src.position.x, src.position.y, src.position.z,
|
| 161 |
+
dst.position.x, dst.position.y, dst.position.z);
|
| 162 |
+
count++;
|
| 163 |
+
}}
|
| 164 |
+
}}
|
| 165 |
+
}}
|
| 166 |
+
}}
|
| 167 |
+
const geo = new THREE.BufferGeometry();
|
| 168 |
+
geo.setAttribute("position", new THREE.Float32BufferAttribute(pts, 3));
|
| 169 |
+
const mat = new THREE.LineBasicMaterial({{color, transparent:true, opacity:0.18}});
|
| 170 |
+
const lines = new THREE.LineSegments(geo, mat);
|
| 171 |
+
pivot.add(lines);
|
| 172 |
+
edgeMatsArr.push(mat);
|
| 173 |
+
return mat;
|
| 174 |
+
}}
|
| 175 |
+
|
| 176 |
+
// Update the function calls right below it to pass edges PER LAYER:
|
| 177 |
+
addEdges(bdhMeshes, 0xf97316, 40, bdhEdgeMats); // 40 lines max between each BDH layer
|
| 178 |
+
addEdges(tfMeshes, 0x3b82f6, 80, tfEdgeMats); // 80 lines max between each TF layer
|
| 179 |
+
|
| 180 |
+
// ββ Layer separator planes βββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 181 |
+
for (let l=0; l<N_LAYERS; l++) {{
|
| 182 |
+
const z = -(l-(N_LAYERS-1)/2)*LAYER_SEP;
|
| 183 |
+
const pl = new THREE.Mesh(
|
| 184 |
+
new THREE.PlaneGeometry(14, 0.015),
|
| 185 |
+
new THREE.MeshBasicMaterial({{color:0x374151, transparent:true, opacity:0.4}})
|
| 186 |
+
);
|
| 187 |
+
pl.position.set(0,-2.4,z);
|
| 188 |
+
pivot.add(pl); // β pivot
|
| 189 |
+
}}
|
| 190 |
+
|
| 191 |
+
// ββ Mouse orbit βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 192 |
+
let drag=false, pm={{x:0,y:0}}, rotX=0.1, rotY=0;
|
| 193 |
+
renderer.domElement.addEventListener("mousedown", e=>{{drag=true; pm={{x:e.clientX,y:e.clientY}}}});
|
| 194 |
+
renderer.domElement.addEventListener("mouseup", ()=>drag=false);
|
| 195 |
+
renderer.domElement.addEventListener("mousemove", e=>{{
|
| 196 |
+
if(!drag) return;
|
| 197 |
+
rotY+=(e.clientX-pm.x)*0.008; rotX+=(e.clientY-pm.y)*0.008;
|
| 198 |
+
pm={{x:e.clientX,y:e.clientY}};
|
| 199 |
+
}});
|
| 200 |
+
renderer.domElement.addEventListener("wheel", e=>{{
|
| 201 |
+
camera.position.z=Math.max(8,Math.min(55,camera.position.z+e.deltaY*0.04));
|
| 202 |
+
}});
|
| 203 |
+
|
| 204 |
+
// ββ State βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 205 |
+
let autoRot=false, pulseActive=false, pulseT=0;
|
| 206 |
+
const clock=new THREE.Clock();
|
| 207 |
+
|
| 208 |
+
document.getElementById("bRot").onclick=function(){{
|
| 209 |
+
autoRot=!autoRot;
|
| 210 |
+
this.textContent=autoRot?"βΈ Pause":"β³ Auto-rotate";
|
| 211 |
+
this.classList.toggle("on",autoRot);
|
| 212 |
+
}};
|
| 213 |
+
document.getElementById("bPulse").onclick=function(){{
|
| 214 |
+
pulseActive=true; pulseT=0;
|
| 215 |
+
this.textContent="β‘ Pulsing...";
|
| 216 |
+
setTimeout(()=>{{pulseActive=false; this.textContent="β‘ Pulse Signal";}},3000);
|
| 217 |
+
}};
|
| 218 |
+
document.getElementById("bReset").onclick=()=>{{
|
| 219 |
+
rotX=0.1; rotY=0; camera.position.set(0,4,30);
|
| 220 |
+
}};
|
| 221 |
+
|
| 222 |
+
// ββ Animate βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 223 |
+
function animate(){{
|
| 224 |
+
requestAnimationFrame(animate);
|
| 225 |
+
const t=clock.getElapsedTime();
|
| 226 |
+
if(autoRot) rotY+=0.005;
|
| 227 |
+
pivot.rotation.y=rotY; pivot.rotation.x=rotX;
|
| 228 |
+
|
| 229 |
+
// Idle pulse on active BDH neurons
|
| 230 |
+
for(let i=0;i<bdhMeshes.length;i++){{
|
| 231 |
+
if(!bdhMeshes[i].userData.silent){{
|
| 232 |
+
const p=1+0.07*Math.sin(t*2.4+i*0.35);
|
| 233 |
+
bdhMeshes[i].scale.setScalar((0.78+bdhMeshes[i].userData.act*0.48)*p);
|
| 234 |
+
}}
|
| 235 |
+
}}
|
| 236 |
+
|
| 237 |
+
// Signal pulse sweep β lights up neurons AND edges
|
| 238 |
+
if(pulseActive){{
|
| 239 |
+
pulseT+=0.018;
|
| 240 |
+
const waveZ=(pulseT*3.2-(N_LAYERS)*0.5)*LAYER_SEP;
|
| 241 |
+
// Neurons
|
| 242 |
+
for(let i=0;i<bdhMeshes.length;i++){{
|
| 243 |
+
const dist=Math.abs(bdhMeshes[i].position.z-waveZ);
|
| 244 |
+
const glow=Math.max(0,1-dist/2.2);
|
| 245 |
+
if(!bdhMeshes[i].userData.silent){{
|
| 246 |
+
bdhMats[i].emissive=new THREE.Color(1,0.6,0.1).multiplyScalar(glow*0.9+bdhMeshes[i].userData.act*0.35);
|
| 247 |
+
bdhMats[i].color=new THREE.Color(0xffffff).lerp(new THREE.Color(0xf97316),1-glow*0.6);
|
| 248 |
+
}} else {{
|
| 249 |
+
// Silent neurons flash dim on pulse wavefront
|
| 250 |
+
bdhMats[i].opacity=0.55+glow*0.35;
|
| 251 |
+
bdhMats[i].emissive=new THREE.Color(0x2a3d55).multiplyScalar(glow*0.5);
|
| 252 |
+
}}
|
| 253 |
+
}}
|
| 254 |
+
// Edges brighten on pulse
|
| 255 |
+
for(let m of bdhEdgeMats) m.opacity=0.18+Math.sin(pulseT*8)*0.25;
|
| 256 |
+
for(let m of tfEdgeMats) m.opacity=0.18;
|
| 257 |
+
}} else {{
|
| 258 |
+
// Reset to normal
|
| 259 |
+
for(let i=0;i<bdhMeshes.length;i++){{
|
| 260 |
+
const act=bdhMeshes[i].userData.act;
|
| 261 |
+
const sl=bdhMeshes[i].userData.silent;
|
| 262 |
+
bdhMats[i].color.set(sl?0x4b6484:0xf97316);
|
| 263 |
+
bdhMats[i].emissive=sl?new THREE.Color(0x1a2535):new THREE.Color(0xf97316).multiplyScalar(act*0.55);
|
| 264 |
+
bdhMats[i].opacity=sl?0.55:0.88+act*0.12;
|
| 265 |
+
}}
|
| 266 |
+
for(let m of bdhEdgeMats) m.opacity=0.18;
|
| 267 |
+
for(let m of tfEdgeMats) m.opacity=0.18;
|
| 268 |
+
}}
|
| 269 |
+
|
| 270 |
+
renderer.render(scene,camera);
|
| 271 |
+
}}
|
| 272 |
+
animate();
|
| 273 |
+
|
| 274 |
+
window.addEventListener("resize",()=>{{
|
| 275 |
+
camera.aspect=window.innerWidth/window.innerHeight;
|
| 276 |
+
camera.updateProjectionMatrix();
|
| 277 |
+
renderer.setSize(window.innerWidth,window.innerHeight);
|
| 278 |
+
}});
|
| 279 |
+
</script>
|
| 280 |
+
</body></html>"""
|
| 281 |
+
|