nooarche/ree-base
0
1"""2Gradio demo for REE Base — Reflective-Ethical Engine scaffold.3Hosted on HuggingFace Spaces: nooarche/ree-base4 5Loads the custom REEModel (trust_remote_code=True), accepts a6batch of float embeddings, and surfaces the key architectural7outputs: E1 state, E2 prediction, candidate trajectories,8commitment score, and residue geometry.9"""10 11import json12 13import gradio as gr14import torch15 16# ---------------------------------------------------------------------------17# Model loading — cached so the Space only loads once18# ---------------------------------------------------------------------------19 20_model = None21_config = None22 23 24def _load_model():25 global _model, _config26 if _model is None:27 from transformers import AutoConfig, AutoModel28 29 _config = AutoConfig.from_pretrained(30 "nooarche/ree-base", trust_remote_code=True31 )32 _model = AutoModel.from_pretrained(33 "nooarche/ree-base", trust_remote_code=True34 )35 _model.eval()36 return _model, _config37 38 39# ---------------------------------------------------------------------------40# Core inference41# ---------------------------------------------------------------------------42 43def run_ree(44 batch_size: int,45 seq_len: int,46 seed: int,47 input_mode: str,48 raw_csv: str,49) -> tuple[str, str, str]:50 """51 Run a forward pass and return:52 - A JSON summary of scalar outputs53 - A table of per-position commitment scores54 - A short architecture legend55 """56 model, config = _load_model()57 58 # ---- build input tensor ------------------------------------------------59 gen = torch.Generator()60 gen.manual_seed(int(seed))61 62 if input_mode == "Random (Gaussian)" or not raw_csv.strip():63 x = torch.randn(int(batch_size), int(seq_len), config.input_size, generator=gen)64 elif input_mode == "Random (Uniform [0,1])":65 x = torch.rand(int(batch_size), int(seq_len), config.input_size, generator=gen)66 else:67 # parse user CSV: rows = sequence positions, cols = features68 try:69 rows = []70 for line in raw_csv.strip().splitlines():71 vals = [float(v.strip()) for v in line.split(",") if v.strip()]72 if vals:73 rows.append(vals)74 if not rows:75 raise ValueError("No numeric data found.")76 parsed = torch.tensor(rows, dtype=torch.float32) # [T, F]77 # pad or trim to input_size78 F = parsed.shape[1]79 if F < config.input_size:80 parsed = torch.cat(81 [parsed, torch.zeros(parsed.shape[0], config.input_size - F)], dim=182 )83 else:84 parsed = parsed[:, : config.input_size]85 # expand to batch86 x = parsed.unsqueeze(0).expand(int(batch_size), -1, -1)87 seq_len = parsed.shape[0]88 except Exception as e:89 return f"Input parse error: {e}", "", ""90 91 # ---- forward -----------------------------------------------------------92 with torch.no_grad():93 out = model(inputs_embeds=x, output_hidden_states=True)94 95 # ---- scalar summary ----------------------------------------------------96 commit_mean = float(out.commitment_score.mean())97 commit_max = float(out.commitment_score.max())98 committed_frac = float(out.committed_mask.float().mean())99 100 pre_err_mean = float(out.pre_commit_error.mean())101 post_err_mean = float(out.post_commit_error.mean())102 103 cand_scores = out.candidate_scores # [B, T, num_futures]104 best_cand = int(out.selected_index[0, 0].item())105 106 residue_mean = (107 float(out.residue_state.mean()) if out.residue_state is not None else None108 )109 110 summary = {111 "input_shape": list(x.shape),112 "commitment_score": {113 "mean": round(commit_mean, 4),114 "max": round(commit_max, 4),115 "fraction_committed": round(committed_frac, 4),116 },117 "prediction_error": {118 "pre_commit_mean": round(pre_err_mean, 4),119 "post_commit_mean": round(post_err_mean, 4),120 },121 "trajectory_selection": {122 "num_candidates": config.num_candidate_futures,123 "rollout_horizon": config.rollout_horizon,124 "best_candidate_at_pos0": best_cand,125 "candidate_scores_pos0": [126 round(float(v), 4) for v in cand_scores[0, 0].tolist()127 ],128 },129 "residue_geometry": {130 "enabled": config.use_residue_geometry,131 "residue_mean": round(residue_mean, 4) if residue_mean is not None else None,132 },133 "architecture": {134 "input_size": config.input_size,135 "e1_hidden_size": config.e1_hidden_size,136 "e2_hidden_size": config.e2_hidden_size,137 "e3_hidden_size": config.e3_hidden_size,138 "control_plane_size": config.control_plane_size,139 "commit_threshold": config.commit_threshold,140 "architectural_version": config.architectural_version,141 },142 }143 144 summary_str = json.dumps(summary, indent=2)145 146 # ---- per-position commitment table (batch item 0) ----------------------147 cs = out.commitment_score[0].tolist() # [T]148 cm = out.committed_mask[0].tolist() # [T]149 pre = out.pre_commit_error[0].mean(-1).tolist() # [T]150 post = out.post_commit_error[0].mean(-1).tolist() # [T]151 152 table_lines = ["| pos | commit_score | committed | pre_err | post_err |"]153 table_lines.append("|-----|-------------|-----------|---------|----------|")154 for i in range(len(cs)):155 table_lines.append(156 f"| {i:3d} | {cs[i]:.4f} | {'YES' if cm[i] else 'no ':3s} "157 f"| {pre[i]:.4f} | {post[i]:.4f} |"158 )159 table_str = "\n".join(table_lines)160 161 # ---- architecture legend -----------------------------------------------162 legend = (163 "## REE Architecture\n\n"164 "| Module | Role |\n"165 "|--------|------|\n"166 "| **E1** | Persistent associative latent state — slow world model |\n"167 "| **E2** | Fast transition predictor — motor-sensory forward model |\n"168 "| **E3** | Candidate trajectory scorer + commitment gating |\n"169 "| **Control plane** | Precision / rollout modulation |\n"170 "| **Residue** | Geometric trace of pre/post-commit error |\n\n"171 "Commitment fires when `commitment_score >= commit_threshold` "172 f"(threshold = {config.commit_threshold}). \n"173 "Pre-commit error = |E2 prediction − selected trajectory endpoint|. \n"174 "Post-commit error = |integrated hidden state − selected endpoint|. \n"175 "Residue = scalar summary of both error streams (harm geometry proxy)."176 )177 178 return summary_str, table_str, legend179 180 181# ---------------------------------------------------------------------------182# Gradio UI183# ---------------------------------------------------------------------------184 185with gr.Blocks(title="REE Base Demo") as demo:186 gr.Markdown(187 """188 # REE Base — Reflective-Ethical Engine189 **Research scaffold** | [`nooarche/ree-base`](https://huggingface.co/nooarche/ree-base)190 191 REE separates cognition into three interacting modules (E1 / E2 / E3) coordinated192 by a lightweight control plane. This demo runs a single forward pass and surfaces193 the key architectural signals: commitment score, trajectory selection, and residue194 geometry.195 196 > **Note:** No pretrained weights are included. All parameters are randomly197 > initialised — outputs reflect architectural structure, not learned behaviour.198 """199 )200 201 with gr.Row():202 with gr.Column(scale=1):203 gr.Markdown("### Input configuration")204 205 input_mode = gr.Radio(206 choices=["Random (Gaussian)", "Random (Uniform [0,1])", "Custom CSV"],207 value="Random (Gaussian)",208 label="Input mode",209 )210 batch_size = gr.Slider(211 minimum=1, maximum=8, step=1, value=1, label="Batch size"212 )213 seq_len = gr.Slider(214 minimum=1, maximum=32, step=1, value=10, label="Sequence length"215 )216 seed = gr.Number(value=42, label="Random seed", precision=0)217 218 csv_input = gr.Textbox(219 label="Custom CSV (rows = timesteps, cols = features)",220 placeholder="0.1, 0.5, -0.3, ...\n0.2, 0.4, -0.1, ...",221 lines=6,222 visible=False,223 )224 225 def toggle_csv(mode):226 return gr.update(visible=(mode == "Custom CSV"))227 228 input_mode.change(toggle_csv, inputs=input_mode, outputs=csv_input)229 230 run_btn = gr.Button("Run forward pass", variant="primary")231 232 with gr.Column(scale=2):233 gr.Markdown("### Outputs")234 summary_out = gr.Code(235 label="Scalar summary (JSON)", language="json", lines=30236 )237 238 with gr.Row():239 table_out = gr.Markdown(label="Per-position commitment (batch item 0)")240 241 with gr.Row():242 legend_out = gr.Markdown(label="Architecture legend")243 244 run_btn.click(245 fn=run_ree,246 inputs=[batch_size, seq_len, seed, input_mode, csv_input],247 outputs=[summary_out, table_out, legend_out],248 )249 250 gr.Markdown(251 """252 ---253 **Links:** [Model card](https://huggingface.co/nooarche/ree-base) ·254 [REE research](https://github.com/nooarche)255 256 *REE Base is a research scaffold — not a production system.*257 """258 )259 260if __name__ == "__main__":261 demo.launch()262 