Vykos's picture
Release Barbados looped MoE research prototype
d5147ba verified
Raw History Blame Contribute Delete
7.85 kB
"""README animation A: every loop weaves a new row through the experts (real routing, routing.json).
Drawn as a weave draft. Columns are the 30 routed experts of one layer (the warp), rows are
loops (the weft). Where a loop's router picks an expert, the weft floats over the warp (a
coloured horizontal float); everywhere else the warp stays on top (a dark vertical float).
The camera then pulls back to the same weave for the first 48 tokens of the sentence.
python tools/animations/weave.py # writes assets/weave.gif and tools/animations/out/weave.mp4
"""
import json
from pathlib import Path
import numpy as np
from matplotlib.collections import LineCollection
from style import TEXT, W, Recorder, ease, glow_dot, loop_color, new_frame
HERE = Path(__file__).resolve().parent
ROOT = HERE.parent.parent
d = json.loads((HERE / "routing.json").read_text())
LAYER = 7 # layer 8 of 15
NTOK = 48
SEL = np.array(d["example_layer_loop_sets"])[LAYER, :, :NTOK] # [loop, token, k]
NL, _, K = SEL.shape
NE = d["n_routed"]
TOKENS = d["example_tokens"][:NTOK]
FOCUS = 2 # " guitar"
COLS, PX, PY = 8, 32.0, 12.2 # cloth: 6 rows x 8 tokens
WARP_CELL = "#D3D9E3"
WARP_LINE = "#E6EAF0"
VIEW0_W = 42.0
PT_PER_UNIT0 = W * 72 / VIEW0_W # points per data unit at the start
def origin(k):
r, c = divmod(k, COLS)
return c * PX, -r * PY
def floats(k, rows, head=None, grow=1.2):
"""Segments for weft floats (over) and warp floats (under) of token k, loops in rows.
With head set, the last row is only woven up to x = head; floats near the head grow in."""
cx, cy = origin(k)
over, over_c, over_scale, under = [], [], [], []
for t in rows:
chosen = set(SEL[t, k].tolist())
for e in range(NE):
x, y = cx + e, cy - t
g = 1.0
if head is not None and t == rows[-1]:
if x > head:
continue
g = min(1.0, (head - x) / grow + 0.15)
if e in chosen:
half = 0.21 * g
over.append([(x - half, y), (x + half, y)])
over_c.append(loop_color(t, NL))
over_scale.append(g)
else:
half = 0.24 * g
under.append([(x, y - half), (x, y + half)])
return over, over_c, over_scale, under
def draw_token(ax, k, rows, u, alpha=1.0, head=None, glow=False, warp_alpha=1.0):
"""u: points per data unit."""
if not rows:
return
cx, cy = origin(k)
# threads underneath: warp columns and the weft of every finished row
top, bot = cy + 0.55, cy - rows[-1] - 0.55
ax.add_collection(LineCollection([[(cx + e, top), (cx + e, bot)] for e in range(NE)],
colors=WARP_LINE, linewidths=0.16 * u, alpha=alpha * warp_alpha, zorder=1))
for t in rows:
x_end = cx + NE - 0.5 if (head is None or t != rows[-1]) else min(head, cx + NE - 0.5)
ax.plot([cx - 0.5, x_end], [cy - t, cy - t], color=loop_color(t, NL), lw=0.10 * u,
alpha=0.55 * alpha, zorder=2, solid_capstyle="butt")
over, over_c, over_s, under = floats(k, rows, head)
if under:
ax.add_collection(LineCollection(under, colors=WARP_CELL, linewidths=0.40 * u, alpha=alpha,
zorder=3, capstyle="round"))
if over:
if glow:
ax.add_collection(LineCollection(over, colors=over_c, linewidths=[1.0 * u * s for s in over_s],
alpha=0.10 * alpha, zorder=3.5, capstyle="round"))
ax.add_collection(LineCollection(over, colors=over_c, linewidths=[0.50 * u * s for s in over_s],
alpha=alpha, zorder=4, capstyle="round"))
def render(rec):
fcx, fcy = origin(FOCUS)
c0 = np.array([fcx + NE / 2 + 2.0, fcy - (NL - 1) / 2 - 0.6])
nrow = NTOK // COLS
cloth_w = (COLS - 1) * PX + NE
c1 = np.array([cloth_w / 2 - 0.5, -(nrow - 1) * PY / 2 - (NL - 1) / 2 - 0.9])
w1 = cloth_w * 1.07
def frame(loop, p, ui=1.0, zoom=0.0, cloth=0.0, tokens=0.0, intro=1.0):
fig, ax = new_frame()
z = ease(zoom)
w = VIEW0_W * (w1 / VIEW0_W) ** z
cx, cy = c0 + (c1 - c0) * z
ax.set_xlim(cx - w / 2, cx + w / 2)
ax.set_ylim(cy - w / 4, cy + w / 4)
u = W * 72 / w
s = VIEW0_W / w
if cloth > 0:
for k in range(NTOK):
if k != FOCUS:
draw_token(ax, k, list(range(NL)), u, alpha=cloth)
head = None
rows = list(range(min(loop + 1, NL)))
if loop < NL:
head = fcx - 0.6 + p * (NE + 0.2)
if intro < 1: # warp only, fading in
ax.add_collection(LineCollection(
[[(fcx + e, fcy + 0.55), (fcx + e, fcy + 0.55 - (NL + 0.1) * ease(intro * 1.4 - e * 0.012))]
for e in range(NE)], colors=WARP_LINE, linewidths=0.16 * u, zorder=1))
else:
draw_token(ax, FOCUS, rows, u, head=head, glow=True)
if head is not None and 0 < p < 1 and intro >= 1:
glow_dot(ax, head, fcy - loop, TEXT, 0.20 * u)
# distinct experts touched so far
seen = set()
for t in rows:
for e in SEL[t, FOCUS]:
if head is None or t != rows[-1] or fcx + e <= head:
seen.add(int(e))
if ui > 0:
ax.text(fcx + NE + 0.8, fcy + 0.5, f"{len(seen)}", fontsize=58 * s, weight="bold", color=TEXT,
ha="left", va="top", alpha=ui, zorder=6)
ax.text(fcx + NE + 0.9, fcy - 3.6, "experts\nused", fontsize=18 * s, color=TEXT, ha="left", va="top",
alpha=ui, linespacing=1.25, zorder=6)
for t in rows if intro >= 1 else []:
ax.text(fcx - 1.4, fcy - t, f"{t + 1}", color=loop_color(t, NL), fontsize=17 * s, ha="right",
va="center", family="DejaVu Sans Mono", alpha=ui, zorder=6)
ax.text(fcx - 1.4, fcy + 1.3, "loop", fontsize=16 * s, color=TEXT, ha="right", va="center",
alpha=ui, zorder=6)
ax.text(fcx + (NE - 1) / 2, fcy - (NL - 1) - 1.6, f"{NE} experts · layer {LAYER + 1} · token "
f"“{TOKENS[FOCUS].strip()}”", fontsize=17 * s, color=TEXT, ha="center", va="top",
alpha=ui, zorder=6)
if tokens > 0:
for k in range(NTOK):
x, y = origin(k)
tok = TOKENS[k].replace("\n", "↵").strip() or "␣"
ax.text(x + (NE - 1) / 2, y - (NL - 1) - 0.9, tok, fontsize=2.9 * u, ha="center", va="top",
color=TEXT, alpha=tokens,
weight="bold" if k == FOCUS else "normal")
rec.add(fig)
for i in range(1, 31): # warp threads drop in
frame(0, 0.0, intro=i / 30, ui=ease(i / 30))
for loop in range(NL): # nine passes of the shuttle
for i in range(1, 21):
frame(loop, ease(i / 20))
for _ in range(4):
frame(loop, 1.0)
for _ in range(20):
frame(NL, 1.0)
for i in range(1, 61): # pull back to the whole sentence
z = i / 60
frame(NL, 1.0, ui=1 - ease(z * 4), zoom=z, cloth=ease(z * 2.5), tokens=ease((z - 0.6) / 0.4))
for _ in range(96):
frame(NL, 1.0, ui=0, zoom=1.0, cloth=1.0, tokens=1.0)
def main():
rec = Recorder(HERE / "frames_weave")
render(rec)
size = rec.encode(ROOT / "assets" / "weave.gif", HERE / "out" / "weave.mp4")
print(f"weave.gif {size:.2f} MB, {rec.n} frames")
if __name__ == "__main__":
main()