CoolFace
Apppublic

nooarche/ree-base

sourceHugging Faceupdated 6mo agoView on Hugging Face
0likes
app.py262 linesDownload Raw Back to root
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