Spaces:
Running on Zero
Running on Zero
eclipse-senpai commited on
Commit ·
fce6c24
1
Parent(s): 6bbbc02
Fix streaming display bug + deep-blue Minima Labs UI
Browse files- run_generate double-accumulated cumulative yields (t1+t1t2+t1t2t3);
generate() now yields per-token chunks, accumulated once
- effort is a real gr.Radio input (API/MCP-settable, no gr.State)
- restyle to Minima Labs deep blue; hide Gradio chrome; drop MCP flag
app.py
CHANGED
|
@@ -2,7 +2,7 @@
|
|
| 2 |
|
| 3 |
A 5.76M-parameter looped-hybrid language model. The signature mechanic: one
|
| 4 |
weight-shared body block runs `K` times per token (the "effort"). More passes
|
| 5 |
-
sharpen grammar; fewer favor commonsense.
|
| 6 |
|
| 7 |
Runs on ZeroGPU (free for the creator; visitors consume their own quota). The
|
| 8 |
model is tiny so cold-start weight streaming is near-instant.
|
|
@@ -24,54 +24,10 @@ TOKENIZER = load_tokenizer()
|
|
| 24 |
_PARAMS = sum(p.numel() for p in MODEL.parameters())
|
| 25 |
print(f" {round(_PARAMS/1e6, 2)}M params ready on {DEVICE}")
|
| 26 |
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
]
|
| 32 |
-
EFFORT_K = {e["id"]: e["k"] for e in EFFORTS}
|
| 33 |
-
_MAX_K = max(e["k"] for e in EFFORTS)
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
# ── the effort rail (signature) ─────────────────────────────────────────────
|
| 37 |
-
def effort_html(selected_id: str = "med") -> str:
|
| 38 |
-
cards = []
|
| 39 |
-
for e in EFFORTS:
|
| 40 |
-
sel = "selected" if e["id"] == selected_id else ""
|
| 41 |
-
dots = "".join(
|
| 42 |
-
f'<span class="dot {"lit" if i < e["k"] else ""}"></span>'
|
| 43 |
-
for i in range(_MAX_K)
|
| 44 |
-
)
|
| 45 |
-
cards.append(f"""
|
| 46 |
-
<button class="effort-card {sel}" data-id="{e['id']}" type="button">
|
| 47 |
-
<span class="eff-label">{e['name']}</span>
|
| 48 |
-
<span class="eff-k">K={e['k']}</span>
|
| 49 |
-
<span class="eff-dots">{dots}</span>
|
| 50 |
-
<span class="eff-tag">{e['tag']}</span>
|
| 51 |
-
</button>""")
|
| 52 |
-
return f'<div id="effort-rail" max-k="{_MAX_K}">{"".join(cards)}</div>'
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
# On load: attach click listeners to the cards; track selection in window.__effort.
|
| 56 |
-
ATTACH_JS = """
|
| 57 |
-
() => {
|
| 58 |
-
window.__effort = "med";
|
| 59 |
-
const rail = document.getElementById('effort-rail');
|
| 60 |
-
if (!rail) return;
|
| 61 |
-
rail.querySelectorAll('.effort-card').forEach(btn => {
|
| 62 |
-
btn.addEventListener('click', () => {
|
| 63 |
-
rail.querySelectorAll('.effort-card').forEach(b => b.classList.remove('selected'));
|
| 64 |
-
btn.classList.add('selected');
|
| 65 |
-
window.__effort = btn.dataset.id;
|
| 66 |
-
});
|
| 67 |
-
});
|
| 68 |
-
}
|
| 69 |
-
"""
|
| 70 |
-
|
| 71 |
-
# Generate-click preamble: override the effort slot with the JS-tracked selection.
|
| 72 |
-
READ_EFFORT_JS = """
|
| 73 |
-
(prompt, eff, mx, t, k) => [prompt, window.__effort || eff || "med", mx, t, k]
|
| 74 |
-
"""
|
| 75 |
|
| 76 |
|
| 77 |
def _estimate_duration(prompt, effort, max_new, temperature, top_k):
|
|
@@ -81,111 +37,117 @@ def _estimate_duration(prompt, effort, max_new, temperature, top_k):
|
|
| 81 |
|
| 82 |
|
| 83 |
@spaces.GPU(duration=_estimate_duration)
|
| 84 |
-
def run_generate(prompt: str, effort:
|
| 85 |
temperature: float, top_k: int):
|
| 86 |
-
"""Generate text from a prompt. `effort`
|
| 87 |
-
|
| 88 |
-
|
| 89 |
if not str(prompt).strip():
|
| 90 |
-
yield
|
| 91 |
-
"<div class='status'><span class='empty'>Type a prompt to start.</span></div>")
|
| 92 |
return
|
| 93 |
-
|
| 94 |
-
|
| 95 |
-
|
| 96 |
-
for
|
| 97 |
-
MODEL, TOKENIZER, prompt, loops=
|
| 98 |
temperature=float(temperature), top_k=int(top_k), device=DEVICE):
|
| 99 |
-
|
| 100 |
-
|
| 101 |
-
|
| 102 |
-
f"<span class='k-chip'>K={picked}</span>"
|
| 103 |
-
f"<span class='stat'>{last_count} tok</span>"
|
| 104 |
-
f"<span class='stat'>{last_tps:.1f} tok/s</span>"
|
| 105 |
-
f"<span class='stat'>ZeroGPU</span></div>")
|
| 106 |
-
yield f"<div class='outbox' id='specimen'>{''.join(outs)}</div>", status
|
| 107 |
-
status = (f"<div class='status'>"
|
| 108 |
-
f"<span class='k-chip'>K={picked}</span>"
|
| 109 |
-
f"<span class='stat'>{last_count} tok</span>"
|
| 110 |
-
f"<span class='stat'>{last_tps:.1f} tok/s</span>"
|
| 111 |
-
f"<span class='done'>done</span></div>")
|
| 112 |
-
yield f"<div class='outbox' id='specimen'>{''.join(outs)}</div>", status
|
| 113 |
|
| 114 |
|
| 115 |
CSS = """
|
| 116 |
-
@import url('https://fonts.googleapis.com/css2?family=
|
| 117 |
|
| 118 |
:root{
|
| 119 |
-
--bg:#
|
| 120 |
-
--hair:#
|
| 121 |
-
--
|
| 122 |
--r:10px;
|
| 123 |
}
|
| 124 |
*{box-sizing:border-box;}
|
| 125 |
-
body, .gradio-container
|
| 126 |
-
.gradio-container{
|
| 127 |
-
|
| 128 |
-
|
| 129 |
-
|
| 130 |
-
|
| 131 |
-
|
| 132 |
-
|
| 133 |
-
.
|
| 134 |
-
|
| 135 |
-
.
|
| 136 |
-
|
| 137 |
-
.
|
| 138 |
-
.
|
| 139 |
-
|
| 140 |
-
|
| 141 |
-
.
|
| 142 |
-
|
| 143 |
-
|
| 144 |
-
|
| 145 |
-
.
|
| 146 |
-
|
| 147 |
-
|
| 148 |
-
|
| 149 |
-
|
| 150 |
-
|
| 151 |
-
|
| 152 |
-
|
| 153 |
-
|
| 154 |
-
|
| 155 |
-
|
| 156 |
-
|
| 157 |
-
|
| 158 |
-
|
| 159 |
-
|
| 160 |
-
|
| 161 |
-
|
| 162 |
-
|
| 163 |
-
|
| 164 |
-
|
| 165 |
-
|
| 166 |
-
|
| 167 |
-
|
| 168 |
-
.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 169 |
.foot a{ color:var(--muted); text-decoration:none; border-bottom:1px dotted var(--hair); }
|
| 170 |
.foot a:hover{ color:var(--text); }
|
| 171 |
"""
|
| 172 |
|
| 173 |
HEADER_HTML = """
|
| 174 |
<div class="head">
|
| 175 |
-
<div class="
|
| 176 |
-
<div class="
|
| 177 |
-
</div>
|
| 178 |
-
<div class="lede">
|
| 179 |
-
A research demo of a small language model trained from scratch on ten billion tokens.
|
| 180 |
-
Its one mechanic: a single weight-shared block runs <b>K times per token</b> — that is the
|
| 181 |
-
“effort.” More passes sharpen grammar; fewer favor commonsense. Pick a pass count
|
| 182 |
-
and prompt it.
|
| 183 |
</div>
|
| 184 |
"""
|
| 185 |
|
| 186 |
FOOTER_HTML = """
|
| 187 |
<div class="foot">
|
| 188 |
-
<span>ZeroGPU ·
|
| 189 |
<span><a href="https://github.com/eclipse-senpai/PICO" target="_blank" rel="noopener">PICO on GitHub</a></span>
|
| 190 |
</div>
|
| 191 |
"""
|
|
@@ -193,34 +155,32 @@ FOOTER_HTML = """
|
|
| 193 |
with gr.Blocks(css=CSS, title="min-spark · Meiosis preview") as demo:
|
| 194 |
gr.HTML(HEADER_HTML)
|
| 195 |
|
| 196 |
-
gr.HTML('<div class="
|
| 197 |
-
|
|
|
|
| 198 |
|
| 199 |
-
gr.HTML('<div class="
|
| 200 |
-
prompt = gr.Textbox(value="", placeholder="Once upon a time
|
| 201 |
-
|
| 202 |
|
| 203 |
with gr.Row():
|
| 204 |
max_new = gr.Slider(8, 256, value=128, step=8, label="Max tokens")
|
| 205 |
temperature = gr.Slider(0.1, 1.6, value=0.8, step=0.05, label="Temperature")
|
| 206 |
-
top_k = gr.Slider(0, 200, value=50, step=5, label="Top-k
|
| 207 |
|
| 208 |
gen_btn = gr.Button("Generate", elem_id="gen", variant="primary")
|
| 209 |
|
| 210 |
-
out = gr.
|
|
|
|
| 211 |
status = gr.HTML(value='<div class="status"></div>')
|
| 212 |
|
| 213 |
gr.HTML(FOOTER_HTML)
|
| 214 |
|
| 215 |
-
effort_state = gr.State("med") # default; overridden by READ_EFFORT_JS preamble
|
| 216 |
-
|
| 217 |
-
demo.load(fn=None, js=ATTACH_JS)
|
| 218 |
gen_btn.click(
|
| 219 |
fn=run_generate,
|
| 220 |
-
|
| 221 |
-
inputs=[prompt, effort_state, max_new, temperature, top_k],
|
| 222 |
outputs=[out, status],
|
| 223 |
)
|
| 224 |
|
| 225 |
if __name__ == "__main__":
|
| 226 |
-
demo.queue().launch(
|
|
|
|
| 2 |
|
| 3 |
A 5.76M-parameter looped-hybrid language model. The signature mechanic: one
|
| 4 |
weight-shared body block runs `K` times per token (the "effort"). More passes
|
| 5 |
+
sharpen grammar; fewer favor commonsense.
|
| 6 |
|
| 7 |
Runs on ZeroGPU (free for the creator; visitors consume their own quota). The
|
| 8 |
model is tiny so cold-start weight streaming is near-instant.
|
|
|
|
| 24 |
_PARAMS = sum(p.numel() for p in MODEL.parameters())
|
| 25 |
print(f" {round(_PARAMS/1e6, 2)}M params ready on {DEVICE}")
|
| 26 |
|
| 27 |
+
# effort label → loop count. The Radio VALUES are what the API/MCP sees.
|
| 28 |
+
EFFORT_CHOICES = [("Low · K=2 — commonsense", 2),
|
| 29 |
+
("Medium · K=3 — grammar", 3),
|
| 30 |
+
("High · K=4 — deeper grammar", 4)]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 31 |
|
| 32 |
|
| 33 |
def _estimate_duration(prompt, effort, max_new, temperature, top_k):
|
|
|
|
| 37 |
|
| 38 |
|
| 39 |
@spaces.GPU(duration=_estimate_duration)
|
| 40 |
+
def run_generate(prompt: str, effort: int, max_new: int,
|
| 41 |
temperature: float, top_k: int):
|
| 42 |
+
"""Generate text from a prompt. `effort` is the loop count K (2/3/4): more
|
| 43 |
+
passes sharpen grammar, fewer favor commonsense. Streams token-by-token."""
|
| 44 |
+
k = int(effort) if effort in (2, 3, 4) else 3
|
| 45 |
if not str(prompt).strip():
|
| 46 |
+
yield "", "<div class='status'>Type a prompt to start.</div>"
|
|
|
|
| 47 |
return
|
| 48 |
+
text = ""
|
| 49 |
+
count = 0
|
| 50 |
+
tps = 0.0
|
| 51 |
+
for chunk, count, tps in generate(
|
| 52 |
+
MODEL, TOKENIZER, prompt, loops=k, max_new=int(max_new),
|
| 53 |
temperature=float(temperature), top_k=int(top_k), device=DEVICE):
|
| 54 |
+
text += chunk
|
| 55 |
+
yield text, f"<div class='status'>K={k} · {count} tok · {tps:.1f} tok/s</div>"
|
| 56 |
+
yield text, f"<div class='status'>K={k} · {count} tok · {tps:.1f} tok/s · done</div>"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 57 |
|
| 58 |
|
| 59 |
CSS = """
|
| 60 |
+
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&family=IBM+Plex+Mono:wght@400;500&display=swap');
|
| 61 |
|
| 62 |
:root{
|
| 63 |
+
--bg:#0A1128; --surface:#101A3A; --surface2:#16224A;
|
| 64 |
+
--hair:#22315E; --text:#E8EDF7; --muted:#7D8DB0;
|
| 65 |
+
--blue:#3E7BFA; --blue-bright:#5E96FF; --blue-dim:#2A4A8F;
|
| 66 |
--r:10px;
|
| 67 |
}
|
| 68 |
*{box-sizing:border-box;}
|
| 69 |
+
body, .gradio-container{ background:var(--bg) !important; }
|
| 70 |
+
.gradio-container{
|
| 71 |
+
max-width:820px !important; margin:0 auto !important;
|
| 72 |
+
padding:32px 20px 40px !important;
|
| 73 |
+
font-family:'Inter',system-ui,sans-serif !important; color:var(--text) !important;
|
| 74 |
+
}
|
| 75 |
+
|
| 76 |
+
/* hide Gradio chrome: footer, settings, API/MCP links */
|
| 77 |
+
footer, .gradio-container footer, #footer{ display:none !important; }
|
| 78 |
+
|
| 79 |
+
.head{ margin-bottom:20px; }
|
| 80 |
+
.title{ font-weight:600; font-size:26px; letter-spacing:-0.01em; color:var(--text); }
|
| 81 |
+
.title em{ font-style:normal; color:var(--blue-bright); }
|
| 82 |
+
.sub{ font-family:'IBM Plex Mono',monospace; font-size:11px; letter-spacing:0.16em;
|
| 83 |
+
text-transform:uppercase; color:var(--muted); margin-top:6px; }
|
| 84 |
+
|
| 85 |
+
.field-h{ font-family:'IBM Plex Mono',monospace; font-size:10.5px; letter-spacing:0.16em;
|
| 86 |
+
text-transform:uppercase; color:var(--muted); margin:18px 0 8px; }
|
| 87 |
+
|
| 88 |
+
/* prompt */
|
| 89 |
+
.gradio-container textarea{
|
| 90 |
+
background:var(--surface) !important; border:1px solid var(--hair) !important;
|
| 91 |
+
border-radius:var(--r) !important; color:var(--text) !important;
|
| 92 |
+
font-family:'Inter' !important; font-size:15px !important; line-height:1.5 !important;
|
| 93 |
+
}
|
| 94 |
+
.gradio-container textarea:focus{ border-color:var(--blue) !important; box-shadow:none !important; }
|
| 95 |
+
|
| 96 |
+
/* effort radio — pill row */
|
| 97 |
+
#effort .wrap{ display:flex !important; gap:8px !important; }
|
| 98 |
+
#effort label{
|
| 99 |
+
flex:1; background:var(--surface) !important; border:1px solid var(--hair) !important;
|
| 100 |
+
border-radius:var(--r) !important; padding:10px 12px !important; cursor:pointer;
|
| 101 |
+
font-size:13px !important; color:var(--muted) !important; text-align:center;
|
| 102 |
+
transition:border-color .15s, background .15s, color .15s;
|
| 103 |
+
}
|
| 104 |
+
#effort label:hover{ border-color:#33508f !important; }
|
| 105 |
+
#effort label.selected{
|
| 106 |
+
background:var(--surface2) !important; border-color:var(--blue) !important;
|
| 107 |
+
color:var(--blue-bright) !important; box-shadow:0 0 0 1px var(--blue) inset !important;
|
| 108 |
+
}
|
| 109 |
+
#effort input{ display:none !important; }
|
| 110 |
+
|
| 111 |
+
/* sliders */
|
| 112 |
+
.gradio-container .form label, .label-wrap label{
|
| 113 |
+
color:var(--muted) !important; font-size:12px !important; letter-spacing:0.02em !important;
|
| 114 |
+
}
|
| 115 |
+
input[type=range]{ accent-color:var(--blue); }
|
| 116 |
+
|
| 117 |
+
/* generate button */
|
| 118 |
+
button#gen{
|
| 119 |
+
background:var(--blue) !important; color:#fff !important; border:none !important;
|
| 120 |
+
border-radius:var(--r) !important; font-weight:600 !important; font-size:14px !important;
|
| 121 |
+
margin-top:6px;
|
| 122 |
+
}
|
| 123 |
+
button#gen:hover{ background:var(--blue-bright) !important; }
|
| 124 |
+
|
| 125 |
+
/* output */
|
| 126 |
+
#out textarea, #out{
|
| 127 |
+
background:var(--surface) !important; border:1px solid var(--hair) !important;
|
| 128 |
+
border-radius:var(--r) !important; color:var(--text) !important;
|
| 129 |
+
font-size:15.5px !important; line-height:1.6 !important;
|
| 130 |
+
}
|
| 131 |
+
.status{ font-family:'IBM Plex Mono',monospace; font-size:11.5px; color:var(--muted);
|
| 132 |
+
margin-top:8px; min-height:16px; }
|
| 133 |
+
|
| 134 |
+
.foot{ margin-top:26px; border-top:1px solid var(--hair); padding-top:12px;
|
| 135 |
+
font-family:'IBM Plex Mono',monospace; font-size:10.5px; color:#54648c;
|
| 136 |
+
display:flex; justify-content:space-between; flex-wrap:wrap; gap:8px; }
|
| 137 |
.foot a{ color:var(--muted); text-decoration:none; border-bottom:1px dotted var(--hair); }
|
| 138 |
.foot a:hover{ color:var(--text); }
|
| 139 |
"""
|
| 140 |
|
| 141 |
HEADER_HTML = """
|
| 142 |
<div class="head">
|
| 143 |
+
<div class="title">min-spark <em>preview</em></div>
|
| 144 |
+
<div class="sub">Minima Labs · PICO release 01 · Meiosis · looped hybrid · 5.76M params</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 145 |
</div>
|
| 146 |
"""
|
| 147 |
|
| 148 |
FOOTER_HTML = """
|
| 149 |
<div class="foot">
|
| 150 |
+
<span>ZeroGPU · stops early on <eos> · visitors use their own quota</span>
|
| 151 |
<span><a href="https://github.com/eclipse-senpai/PICO" target="_blank" rel="noopener">PICO on GitHub</a></span>
|
| 152 |
</div>
|
| 153 |
"""
|
|
|
|
| 155 |
with gr.Blocks(css=CSS, title="min-spark · Meiosis preview") as demo:
|
| 156 |
gr.HTML(HEADER_HTML)
|
| 157 |
|
| 158 |
+
gr.HTML('<div class="field-h">Effort — loops per token</div>')
|
| 159 |
+
effort = gr.Radio(choices=EFFORT_CHOICES, value=3, elem_id="effort",
|
| 160 |
+
show_label=False, container=False)
|
| 161 |
|
| 162 |
+
gr.HTML('<div class="field-h">Prompt</div>')
|
| 163 |
+
prompt = gr.Textbox(value="", placeholder="Once upon a time",
|
| 164 |
+
lines=2, show_label=False, container=False)
|
| 165 |
|
| 166 |
with gr.Row():
|
| 167 |
max_new = gr.Slider(8, 256, value=128, step=8, label="Max tokens")
|
| 168 |
temperature = gr.Slider(0.1, 1.6, value=0.8, step=0.05, label="Temperature")
|
| 169 |
+
top_k = gr.Slider(0, 200, value=50, step=5, label="Top-k (0 = off)")
|
| 170 |
|
| 171 |
gen_btn = gr.Button("Generate", elem_id="gen", variant="primary")
|
| 172 |
|
| 173 |
+
out = gr.Textbox(value="", elem_id="out", show_label=False, container=False,
|
| 174 |
+
lines=10, interactive=False, autoscroll=True)
|
| 175 |
status = gr.HTML(value='<div class="status"></div>')
|
| 176 |
|
| 177 |
gr.HTML(FOOTER_HTML)
|
| 178 |
|
|
|
|
|
|
|
|
|
|
| 179 |
gen_btn.click(
|
| 180 |
fn=run_generate,
|
| 181 |
+
inputs=[prompt, effort, max_new, temperature, top_k],
|
|
|
|
| 182 |
outputs=[out, status],
|
| 183 |
)
|
| 184 |
|
| 185 |
if __name__ == "__main__":
|
| 186 |
+
demo.queue().launch()
|
loader.py
CHANGED
|
@@ -44,13 +44,13 @@ def load_model(device: str = "cpu") -> Meiosis:
|
|
| 44 |
@torch.no_grad()
|
| 45 |
def generate(model, tokenizer, prompt: str, *, loops: int, max_new: int,
|
| 46 |
temperature: float, top_k: int, device: str):
|
| 47 |
-
"""Token-by-token sampling. Yields (
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
|
|
|
|
| 51 |
import time
|
| 52 |
ids = [EOS_ID] + tokenizer.encode(prompt).ids
|
| 53 |
-
out_text = ""
|
| 54 |
t0 = None
|
| 55 |
count = 0
|
| 56 |
for _ in range(max_new):
|
|
@@ -68,7 +68,6 @@ def generate(model, tokenizer, prompt: str, *, loops: int, max_new: int,
|
|
| 68 |
if next_id == EOS_ID:
|
| 69 |
break
|
| 70 |
ids.append(next_id)
|
| 71 |
-
out_text += tokenizer.decode([next_id])
|
| 72 |
count += 1
|
| 73 |
elapsed = time.perf_counter() - t0
|
| 74 |
-
yield
|
|
|
|
| 44 |
@torch.no_grad()
|
| 45 |
def generate(model, tokenizer, prompt: str, *, loops: int, max_new: int,
|
| 46 |
temperature: float, top_k: int, device: str):
|
| 47 |
+
"""Token-by-token sampling, mirroring infer.py. Yields (chunk, count, tps)
|
| 48 |
+
where `chunk` is THIS step's decoded token (not cumulative) so the caller
|
| 49 |
+
can stream a typewriter effect. Per-token decode joins byte-exactly for
|
| 50 |
+
this byte-level BPE (verified against cumulative decode). Runs on the GPU
|
| 51 |
+
worker under @spaces.GPU; yields only CPU-safe Python objects."""
|
| 52 |
import time
|
| 53 |
ids = [EOS_ID] + tokenizer.encode(prompt).ids
|
|
|
|
| 54 |
t0 = None
|
| 55 |
count = 0
|
| 56 |
for _ in range(max_new):
|
|
|
|
| 68 |
if next_id == EOS_ID:
|
| 69 |
break
|
| 70 |
ids.append(next_id)
|
|
|
|
| 71 |
count += 1
|
| 72 |
elapsed = time.perf_counter() - t0
|
| 73 |
+
yield tokenizer.decode([next_id]), count, (count / elapsed if elapsed > 0 else 0.0)
|