diff options
| author | YurenHao0426 <Blackhao0426@gmail.com> | 2026-08-10 11:13:26 -0500 |
|---|---|---|
| committer | YurenHao0426 <Blackhao0426@gmail.com> | 2026-08-10 11:13:26 -0500 |
| commit | db21295addcfeb830ae72b330a8e7784c75c5232 (patch) | |
| tree | 0b55abaaef2a1ee568c29d429569b567afd801c0 | |
| parent | 52a734aa8736cd8edf95f3fbf595014f7559e6f5 (diff) | |
docs: simplify SDIL deck around real figures
| -rw-r--r-- | slides/SDIL_project_intro.pptx | bin | 519129 -> 1122788 bytes | |||
| -rw-r--r-- | slides/SDIL_project_intro.py | 764 | ||||
| -rw-r--r-- | slides/qa-ledger.md | 3 | ||||
| -rw-r--r-- | slides/rendered/.gitignore | 1 | ||||
| -rw-r--r-- | slides/rendered/SDIL_project_intro.pdf | bin | 843127 -> 1077946 bytes | |||
| -rw-r--r-- | slides/rendered/contact_sheet.png | bin | 761169 -> 754124 bytes | |||
| -rw-r--r-- | slides/visual-contract.md | 19 |
7 files changed, 262 insertions, 525 deletions
diff --git a/slides/SDIL_project_intro.pptx b/slides/SDIL_project_intro.pptx Binary files differindex 5efde76..7544f97 100644 --- a/slides/SDIL_project_intro.pptx +++ b/slides/SDIL_project_intro.pptx diff --git a/slides/SDIL_project_intro.py b/slides/SDIL_project_intro.py index 19e49c5..357f3db 100644 --- a/slides/SDIL_project_intro.py +++ b/slides/SDIL_project_intro.py @@ -1,55 +1,34 @@ #!/usr/bin/env python3 -"""Build the context-free SDIL project introduction deck. - -All quantitative claims come from tracked project result files. The deck uses -only completed full-method experiments: the controlled traffic panel, the -standard ResNet-20/32/56 panel, and the calibrated synthetic BCI confirmation. -""" +"""Build a plain, evidence-first English introduction to the SDIL project.""" from pathlib import Path -from typing import Iterable, Sequence from PIL import Image from pptx import Presentation from pptx.dml.color import RGBColor -from pptx.enum.shapes import MSO_CONNECTOR, MSO_SHAPE from pptx.enum.text import MSO_ANCHOR, PP_ALIGN from pptx.util import Inches, Pt ROOT = Path(__file__).resolve().parents[1] -OUT_DIR = ROOT / "slides" -ASSET_DIR = OUT_DIR / "assets" -OUT_PATH = OUT_DIR / "SDIL_project_intro.pptx" +SLIDES = ROOT / "slides" +ASSETS = SLIDES / "assets" +OUTPUT = SLIDES / "SDIL_project_intro.pptx" FIG3 = ROOT / "results/figs/figure3_innovation.png" +FIG4 = ROOT / "results/figs/figure4_resnet_confirmation.png" FIG5 = ROOT / "results/figs/figure5_bci_v2.png" +FIG6 = ROOT / "results/figs/figure6_standard_depth_scaling.png" -SLIDE_W = 13.333 -SLIDE_H = 7.5 - -FONT = "Noto Sans CJK SC" -FONT_LATIN = "DejaVu Sans" +FONT = "DejaVu Sans" +BLACK = "111111" +GRAY = "111111" +LIGHT_GRAY = "B5B5B5" +WHITE = "FFFFFF" -BG = "F7F9FB" -PAPER = "FFFFFF" -INK = "17212B" -MUTED = "5D6975" -LIGHT = "DDE4EA" -GRID = "D9E0E6" -BLUE = "0072B2" -BLUE_LIGHT = "DCEFF9" -GREEN = "009E73" -GREEN_LIGHT = "DDF3EC" -ORANGE = "E69F00" -ORANGE_LIGHT = "FBEBC9" -RED = "D55E00" -GRAY = "777777" -DARK_GRAY = "3F4850" - -def rgb(hex_color: str) -> RGBColor: - return RGBColor.from_string(hex_color) +def rgb(value: str) -> RGBColor: + return RGBColor.from_string(value) def add_text( @@ -61,27 +40,25 @@ def add_text( h: float, *, size: float = 18, - color: str = INK, bold: bool = False, + color: str = BLACK, align=PP_ALIGN.LEFT, valign=MSO_ANCHOR.TOP, - margin: float = 0.03, + margin: float = 0.02, font: str = FONT, - line_spacing: float = 1.0, ): box = slide.shapes.add_textbox(Inches(x), Inches(y), Inches(w), Inches(h)) - tf = box.text_frame - tf.clear() - tf.word_wrap = True - tf.margin_left = Inches(margin) - tf.margin_right = Inches(margin) - tf.margin_top = Inches(margin) - tf.margin_bottom = Inches(margin) - tf.vertical_anchor = valign - p = tf.paragraphs[0] - p.alignment = align - p.line_spacing = line_spacing - run = p.add_run() + frame = box.text_frame + frame.clear() + frame.word_wrap = True + frame.margin_left = Inches(margin) + frame.margin_right = Inches(margin) + frame.margin_top = Inches(margin) + frame.margin_bottom = Inches(margin) + frame.vertical_anchor = valign + paragraph = frame.paragraphs[0] + paragraph.alignment = align + run = paragraph.add_run() run.text = text run.font.name = font run.font.size = Pt(size) @@ -90,72 +67,26 @@ def add_text( return box -def add_rich_text( - slide, - runs: Sequence[tuple[str, float, str, bool]], - x: float, - y: float, - w: float, - h: float, - *, - align=PP_ALIGN.LEFT, - valign=MSO_ANCHOR.TOP, - margin: float = 0.03, -): +def add_bullets(slide, items, x, y, w, h, *, size=18, gap=7, color=BLACK): box = slide.shapes.add_textbox(Inches(x), Inches(y), Inches(w), Inches(h)) - tf = box.text_frame - tf.clear() - tf.word_wrap = True - tf.margin_left = Inches(margin) - tf.margin_right = Inches(margin) - tf.margin_top = Inches(margin) - tf.margin_bottom = Inches(margin) - tf.vertical_anchor = valign - p = tf.paragraphs[0] - p.alignment = align - for text, size, color, bold in runs: - run = p.add_run() - run.text = text - run.font.name = FONT - run.font.size = Pt(size) - run.font.bold = bold - run.font.color.rgb = rgb(color) - return box - - -def add_bullets( - slide, - items: Iterable[str], - x: float, - y: float, - w: float, - h: float, - *, - size: float = 17, - color: str = INK, - bullet_color: str = BLUE, - gap: float = 7, -): - box = slide.shapes.add_textbox(Inches(x), Inches(y), Inches(w), Inches(h)) - tf = box.text_frame - tf.clear() - tf.word_wrap = True - tf.margin_left = Inches(0.03) - tf.margin_right = Inches(0.03) - tf.margin_top = Inches(0.02) - tf.margin_bottom = Inches(0.02) - for idx, item in enumerate(items): - p = tf.paragraphs[0] if idx == 0 else tf.add_paragraph() - p.level = 0 - p.space_after = Pt(gap) - p.line_spacing = 1.05 - p.text = "" - marker = p.add_run() - marker.text = "● " - marker.font.name = FONT - marker.font.size = Pt(max(size - 4, 10)) - marker.font.color.rgb = rgb(bullet_color) - body = p.add_run() + frame = box.text_frame + frame.clear() + frame.word_wrap = True + frame.margin_left = Inches(0.02) + frame.margin_right = Inches(0.02) + frame.margin_top = Inches(0.01) + frame.margin_bottom = Inches(0.01) + for index, item in enumerate(items): + paragraph = frame.paragraphs[0] if index == 0 else frame.add_paragraph() + paragraph.space_after = Pt(gap) + paragraph.line_spacing = 1.05 + paragraph.text = "" + bullet = paragraph.add_run() + bullet.text = "• " + bullet.font.name = FONT + bullet.font.size = Pt(size) + bullet.font.color.rgb = rgb(color) + body = paragraph.add_run() body.text = item body.font.name = FONT body.font.size = Pt(size) @@ -163,470 +94,273 @@ def add_bullets( return box -def add_rect( - slide, - x: float, - y: float, - w: float, - h: float, - *, - fill: str = PAPER, - line: str = LIGHT, - radius: bool = True, - line_width: float = 1.0, -): - kind = MSO_SHAPE.ROUNDED_RECTANGLE if radius else MSO_SHAPE.RECTANGLE - shape = slide.shapes.add_shape(kind, Inches(x), Inches(y), Inches(w), Inches(h)) - shape.fill.solid() - shape.fill.fore_color.rgb = rgb(fill) - shape.line.color.rgb = rgb(line) - shape.line.width = Pt(line_width) - return shape - - -def add_line( - slide, - x1: float, - y1: float, - x2: float, - y2: float, - *, - color: str = MUTED, - width: float = 1.5, - dash=None, -): - line = slide.shapes.add_connector( - MSO_CONNECTOR.STRAIGHT, - Inches(x1), - Inches(y1), - Inches(x2), - Inches(y2), - ) - line.line.color.rgb = rgb(color) - line.line.width = Pt(width) - if dash is not None: - line.line.dash_style = dash - return line - - -def add_arrow(slide, x1, y1, x2, y2, *, color=MUTED, width=2.0): - line = add_line(slide, x1, y1, x2, y2, color=color, width=width) - line.line.end_arrowhead = True - return line - - -def add_circle(slide, cx, cy, r, *, fill=BLUE, line=PAPER, line_width=1.0): - shape = slide.shapes.add_shape( - MSO_SHAPE.OVAL, - Inches(cx - r), - Inches(cy - r), - Inches(2 * r), - Inches(2 * r), - ) - shape.fill.solid() - shape.fill.fore_color.rgb = rgb(fill) - shape.line.color.rgb = rgb(line) - shape.line.width = Pt(line_width) - return shape - - def add_title(slide, title: str, number: int, subtitle: str | None = None): - add_text(slide, title, 0.55, 0.28, 11.9, 0.54, size=26, bold=True) - add_text(slide, f"{number:02d}", 12.35, 0.34, 0.45, 0.3, size=11, color=MUTED, align=PP_ALIGN.RIGHT) - add_line(slide, 0.55, 0.91, 12.78, 0.91, color=LIGHT, width=1.0) + add_text(slide, title, 0.52, 0.28, 11.95, 0.55, size=27, bold=True) + add_text(slide, str(number), 12.35, 0.35, 0.42, 0.25, size=10, color=GRAY, align=PP_ALIGN.RIGHT) if subtitle: - add_text(slide, subtitle, 0.58, 1.00, 12.0, 0.35, size=13.5, color=MUTED) + add_text(slide, subtitle, 0.55, 0.92, 12.10, 0.36, size=13.5, color=GRAY) def add_footer(slide, text: str): - add_text(slide, text, 0.58, 7.18, 12.15, 0.2, size=8.5, color=MUTED, valign=MSO_ANCHOR.MIDDLE) + add_text(slide, text, 0.55, 7.17, 12.20, 0.18, size=8.5, color=GRAY) -def add_badge(slide, text, x, y, w, *, fill=BLUE_LIGHT, color=BLUE, size=13): - add_rect(slide, x, y, w, 0.43, fill=fill, line=fill, radius=True) - add_text(slide, text, x + 0.05, y + 0.02, w - 0.1, 0.35, size=size, color=color, bold=True, align=PP_ALIGN.CENTER, valign=MSO_ANCHOR.MIDDLE) +def add_takeaway(slide, text: str, y: float = 6.55): + add_text(slide, text, 0.70, y, 11.93, 0.40, size=16, bold=True, align=PP_ALIGN.CENTER, valign=MSO_ANCHOR.MIDDLE) def prepare_crops(): - ASSET_DIR.mkdir(parents=True, exist_ok=True) - img = Image.open(FIG5) - w, h = img.size - crops = { - "figure5a_actor_critic.png": (0, 0, w // 2, h // 2), - "figure5d_outcome.png": (w // 2, h // 2, w, h), - } - for name, box in crops.items(): - img.crop(box).save(ASSET_DIR / name) - - -def add_custom_line_chart( - slide, - x: float, - y: float, - w: float, - h: float, - categories: Sequence[str], - series: Sequence[tuple[str, Sequence[float], str]], - *, - ymin: float, - ymax: float, - yticks: Sequence[float], - title: str, - show_legend: bool = True, -): - add_rect(slide, x, y, w, h, fill=PAPER, line=LIGHT, radius=True) - add_text(slide, title, x + 0.25, y + 0.12, w - 0.5, 0.35, size=15, bold=True) - left = x + 0.60 - right = x + w - 0.25 - top = y + 0.72 - bottom = y + h - 0.65 - - def px(i): - if len(categories) == 1: - return (left + right) / 2 - return left + i * (right - left) / (len(categories) - 1) - - def py(v): - return bottom - (v - ymin) * (bottom - top) / (ymax - ymin) - - for tick in yticks: - yy = py(tick) - add_line(slide, left, yy, right, yy, color=GRID, width=0.8) - add_text(slide, f"{tick:g}", x + 0.08, yy - 0.12, 0.42, 0.24, size=9.5, color=MUTED, align=PP_ALIGN.RIGHT, valign=MSO_ANCHOR.MIDDLE) - - add_line(slide, left, top, left, bottom, color=DARK_GRAY, width=1.1) - add_line(slide, left, bottom, right, bottom, color=DARK_GRAY, width=1.1) - for i, cat in enumerate(categories): - xx = px(i) - add_line(slide, xx, bottom, xx, bottom + 0.07, color=DARK_GRAY, width=1.0) - add_text(slide, cat, xx - 0.38, bottom + 0.10, 0.76, 0.28, size=9.5, align=PP_ALIGN.CENTER) - - for name, values, color in series: - points = [(px(i), py(v)) for i, v in enumerate(values)] - for (x1, y1), (x2, y2) in zip(points, points[1:]): - add_line(slide, x1, y1, x2, y2, color=color, width=2.3) - for xx, yy in points: - add_circle(slide, xx, yy, 0.065, fill=color, line=PAPER, line_width=0.8) - - if show_legend: - legend_y = y + h - 0.27 - total = len(series) - slot = (w - 0.55) / total - for i, (name, _, color) in enumerate(series): - lx = x + 0.30 + i * slot - add_line(slide, lx, legend_y + 0.08, lx + 0.26, legend_y + 0.08, color=color, width=2.3) - add_circle(slide, lx + 0.13, legend_y + 0.08, 0.04, fill=color, line=color) - add_text(slide, name, lx + 0.32, legend_y - 0.04, slot - 0.34, 0.25, size=9.2, color=INK, valign=MSO_ANCHOR.MIDDLE) + ASSETS.mkdir(parents=True, exist_ok=True) + + image5 = Image.open(FIG5) + w5, h5 = image5.size + image5.crop((0, 0, w5 // 2, h5 // 2)).save(ASSETS / "figure5a_actor_critic.png") + image5.crop((w5 // 2, h5 // 2, w5, h5)).save(ASSETS / "figure5d_outcome.png") + + image6 = Image.open(FIG6) + w6, h6 = image6.size + image6.crop((0, 0, w6, h6 // 2)).save(ASSETS / "figure6_top_row.png") def build_deck(): prepare_crops() - prs = Presentation() - prs.slide_width = Inches(SLIDE_W) - prs.slide_height = Inches(SLIDE_H) - blank = prs.slide_layouts[6] + + presentation = Presentation() + presentation.slide_width = Inches(13.333) + presentation.slide_height = Inches(7.5) + blank = presentation.slide_layouts[6] def new_slide(): - slide = prs.slides.add_slide(blank) - background = slide.background - background.fill.solid() - background.fill.fore_color.rgb = rgb(BG) + slide = presentation.slides.add_slide(blank) + slide.background.fill.solid() + slide.background.fill.fore_color.rgb = rgb(WHITE) return slide - # Slide 1: title and one-minute summary. + # 1. Title. slide = new_slide() - add_text(slide, "SDIL", 0.62, 0.60, 3.0, 0.72, size=38, color=BLUE, bold=True) - add_text(slide, "让局部学习使用意外的反馈", 0.62, 1.28, 7.1, 0.70, size=29, bold=True) + add_text(slide, "Somato-Dendritic Innovation Learning", 0.70, 1.02, 11.95, 0.75, size=34, bold=True) + add_text(slide, "Local credit assignment from soma-unpredicted dendritic signals", 0.72, 1.96, 11.75, 0.52, size=22) add_text( slide, - "Somato-Dendritic Innovation Learning\n受 Francioni et al.(Harnett lab)Nature 2026 启发", - 0.65, - 2.10, - 6.5, - 0.88, + "Inspired by the neuron-specific somato-dendritic residuals reported by Francioni et al., Nature 2026", + 0.72, + 2.70, + 11.50, + 0.55, size=16, - color=MUTED, - line_spacing=1.08, + color=GRAY, + ) + add_text( + slide, + "Question: should a local learner use apical activity itself, or the component that is unexpected from the same neuron's somatic state?", + 0.72, + 4.35, + 11.60, + 1.00, + size=23, + bold=True, ) + add_text(slide, "Project overview · August 2026", 0.72, 6.80, 4.0, 0.30, size=11, color=GRAY) - add_rect(slide, 7.55, 0.72, 5.05, 2.42, fill=PAPER, line=LIGHT, radius=True, line_width=1.2) - add_text(slide, "核心操作", 7.90, 1.02, 1.4, 0.35, size=14, color=MUTED, bold=True) - add_text(slide, "teaching signal", 7.92, 1.48, 1.75, 0.34, size=16, color=DARK_GRAY, align=PP_ALIGN.RIGHT) - add_text(slide, "=", 9.76, 1.45, 0.35, 0.40, size=22, color=MUTED, bold=True, align=PP_ALIGN.CENTER) - add_text(slide, "apical feedback", 10.12, 1.31, 2.05, 0.33, size=15.5, color=INK, bold=True, align=PP_ALIGN.CENTER) - add_text(slide, "− expected from soma", 10.12, 1.75, 2.05, 0.33, size=15.5, color=BLUE, bold=True, align=PP_ALIGN.CENTER) - add_text(slide, "每个神经元各自减去正常 soma–dendrite 耦合", 7.90, 2.43, 4.25, 0.38, size=13.5, color=MUTED, align=PP_ALIGN.CENTER) - - cards = [ - ("BP-free", "学习器内无反向计算图", BLUE_LIGHT, BLUE), - ("92.76%", "ResNet-56 + 4× predictable traffic", GREEN_LIGHT, GREEN), - ("1.33×", "BP MAC estimate", ORANGE_LIGHT, RED), - ] - for i, (big, small, fill, color) in enumerate(cards): - x = 0.65 + i * 4.12 - add_rect(slide, x, 4.17, 3.75, 1.47, fill=fill, line=fill, radius=True) - add_text(slide, big, x + 0.18, 4.36, 3.39, 0.48, size=25, color=color, bold=True, align=PP_ALIGN.CENTER) - add_text(slide, small, x + 0.18, 4.91, 3.39, 0.38, size=12.3, color=INK, align=PP_ALIGN.CENTER) + # 2. Biological observation and learning rule. + slide = new_slide() + add_title(slide, "From the biological observation to a local learning rule", 2) add_text( slide, - "一句话:可扩展的局部信用路径负责把方向送到各层;SDIL 负责从混合反馈中提取可用于学习的部分。", - 0.82, - 6.30, - 11.7, - 0.50, + "The Harnett-lab study fits each neuron's normal soma–dendrite relationship. The residual is decorrelated from soma and carries outcome and signed task information.", + 0.72, + 1.18, + 11.75, + 0.76, size=18, - color=INK, + ) + add_text(slide, "aₗ = sₗ + nₗ", 1.08, 2.25, 3.10, 0.52, size=25, bold=True, align=PP_ALIGN.CENTER) + add_text(slide, "mixed apical activity", 1.08, 2.78, 3.10, 0.32, size=13, color=GRAY, align=PP_ALIGN.CENTER) + add_text(slide, "âₗ = Pₗ(hₗ)", 5.10, 2.25, 3.10, 0.52, size=25, bold=True, align=PP_ALIGN.CENTER) + add_text(slide, "neutral-period prediction", 5.10, 2.78, 3.10, 0.32, size=13, color=GRAY, align=PP_ALIGN.CENTER) + add_text(slide, "rₗ = aₗ − âₗ", 9.13, 2.25, 3.10, 0.52, size=25, bold=True, align=PP_ALIGN.CENTER) + add_text(slide, "somato-dendritic innovation", 9.13, 2.78, 3.10, 0.32, size=13, color=GRAY, align=PP_ALIGN.CENTER) + add_text( + slide, + "ΔWₗ = η (rₗ ⊙ φ′(uₗ)) hₗ₋₁ᵀ", + 2.63, + 3.66, + 8.10, + 0.68, + size=29, bold=True, align=PP_ALIGN.CENTER, ) - add_footer(slide, "Project introduction · ICLR 2027 work in progress · headline values use completed full experiments") - - # Slide 2: scientific origin and problem. - slide = new_slide() - add_title(slide, "问题:反馈通道不只传教学信号", 2, "把全部 apical activity 当作 error,会把正常状态与上下文一起写入权重。") - - add_rect(slide, 0.62, 1.52, 5.70, 4.88, fill=PAPER, line=LIGHT) - add_text(slide, "局部学习常见假设", 0.95, 1.78, 2.6, 0.38, size=17, bold=True) - add_rect(slide, 0.98, 2.42, 1.55, 0.76, fill=BLUE_LIGHT, line=BLUE) - add_text(slide, "teaching\nsignal", 1.10, 2.52, 1.31, 0.50, size=14, color=BLUE, bold=True, align=PP_ALIGN.CENTER, valign=MSO_ANCHOR.MIDDLE) - add_rect(slide, 0.98, 3.62, 1.55, 0.76, fill="EFF1F3", line=GRAY) - add_text(slide, "ordinary\ntraffic", 1.10, 3.72, 1.31, 0.50, size=14, color=DARK_GRAY, bold=True, align=PP_ALIGN.CENTER, valign=MSO_ANCHOR.MIDDLE) - add_arrow(slide, 2.55, 2.80, 3.55, 3.25, color=BLUE, width=2.1) - add_arrow(slide, 2.55, 4.00, 3.55, 3.55, color=GRAY, width=2.1) - add_rect(slide, 3.58, 2.72, 2.10, 1.36, fill="F3F5F6", line=DARK_GRAY) - add_text(slide, "raw apical\nfeedback", 3.76, 2.93, 1.74, 0.72, size=18, bold=True, align=PP_ALIGN.CENTER, valign=MSO_ANCHOR.MIDDLE) - add_arrow(slide, 4.63, 4.10, 4.63, 4.85, color=RED, width=2.4) - add_rect(slide, 3.48, 4.90, 2.30, 0.84, fill="F8E6DE", line=RED) - add_text(slide, "update direction\nmay rotate", 3.65, 5.04, 1.96, 0.52, size=14.2, color=RED, bold=True, align=PP_ALIGN.CENTER, valign=MSO_ANCHOR.MIDDLE) - - add_rect(slide, 6.58, 1.52, 6.12, 4.88, fill=PAPER, line=LIGHT) - add_text(slide, "Nature 2026 提供了更具体的对象", 6.92, 1.78, 4.8, 0.38, size=17, bold=True) - # Simple soma-dendrite regression sketch. - plot_x, plot_y, plot_w, plot_h = 7.08, 2.60, 2.35, 2.30 - add_line(slide, plot_x, plot_y + plot_h, plot_x + plot_w, plot_y + plot_h, color=DARK_GRAY, width=1.2) - add_line(slide, plot_x, plot_y + plot_h, plot_x, plot_y, color=DARK_GRAY, width=1.2) - add_line(slide, plot_x + 0.20, plot_y + 1.97, plot_x + 2.12, plot_y + 0.35, color=GRAY, width=2.0) - points = [(0.35, 1.74), (0.72, 1.41), (1.03, 1.29), (1.42, 0.88), (1.82, 0.61)] - for dx, dy in points: - add_circle(slide, plot_x + dx, plot_y + dy, 0.055, fill=GRAY, line=PAPER) - expected_x = plot_x + 1.45 - expected_y = plot_y + 0.90 - observed_y = plot_y + 0.35 - add_circle(slide, expected_x, observed_y, 0.075, fill=BLUE, line=PAPER) - add_line(slide, expected_x, expected_y, expected_x, observed_y, color=BLUE, width=2.8) - add_text(slide, "residual", expected_x + 0.12, observed_y + 0.10, 0.80, 0.25, size=11.5, color=BLUE, bold=True) - add_text(slide, "soma", plot_x + 0.88, plot_y + plot_h + 0.18, 0.80, 0.25, size=10.5, color=MUTED, align=PP_ALIGN.CENTER) - add_text(slide, "dendrite", plot_x - 0.68, plot_y + 0.93, 0.70, 0.25, size=10.5, color=MUTED, align=PP_ALIGN.CENTER) - + add_text(slide, "presynaptic activity × local postsynaptic gain × dendritic innovation", 2.62, 4.38, 8.12, 0.36, size=15, color=GRAY, align=PP_ALIGN.CENTER) add_bullets( slide, [ - "先拟合每个神经元正常的 soma–dendrite 关系", - "残差与 soma 明显去相关", - "残差携带 outcome 与神经元特异的有符号任务信息", + "Training uses locally available quantities, forward observations, and manual synaptic updates.", + "Node-perturbation feedback supports the small-network experiments; reciprocal Kolen–Pollack plasticity supports the standard ResNets.", + "The inherited credit path transports layer-specific directions. SDIL removes soma-predictable traffic from those directions.", ], - 9.75, - 2.56, - 2.62, - 2.60, - size=14.3, - gap=8, + 1.02, + 5.05, + 11.15, + 1.45, + size=15.5, + gap=4, ) - add_rect(slide, 6.93, 5.34, 5.42, 0.68, fill=BLUE_LIGHT, line=BLUE_LIGHT) - add_text(slide, "算法问题:学习是否也应使用 residual,而不是 raw activity?", 7.10, 5.50, 5.08, 0.33, size=15.2, color=BLUE, bold=True, align=PP_ALIGN.CENTER) - add_footer(slide, "Source: Francioni et al., “Vectorized instructive signals in cortical dendrites,” Nature (2026).") + add_footer(slide, "Sources: Francioni et al. (Nature 2026); Lansdell et al. (ICLR 2020); Akrout et al. (NeurIPS 2019).") - # Slide 3: method. + # 3. Controlled ablation. slide = new_slide() - add_title(slide, "方法:预测正常耦合,再用残差完成局部更新", 3, "SDIL 改变教学变量;它不要求重新发明整条反馈传播路径。") - - steps = [ - ("1", "Neutral observation", "âₗ = Pₗ(hₗ)", "估计同一神经元的正常耦合", "EFF1F3", DARK_GRAY), - ("2", "Innovation", "rₗ = aₗ − âₗ", "只保留 soma 无法预测的部分", BLUE_LIGHT, BLUE), - ("3", "Local plasticity", "ΔWₗ = η(rₗ ⊙ φ′(uₗ))hₗ₋₁ᵀ", "pre × post gain × dendritic residual", GREEN_LIGHT, GREEN), - ] - for i, (num, label, eq, desc, fill, color) in enumerate(steps): - x = 0.67 + i * 4.18 - add_rect(slide, x, 1.70, 3.76, 2.38, fill=fill, line=color, radius=True, line_width=1.4) - add_circle(slide, x + 0.35, 2.04, 0.20, fill=color, line=color) - add_text(slide, num, x + 0.23, 1.90, 0.24, 0.28, size=13, color=PAPER, bold=True, align=PP_ALIGN.CENTER, valign=MSO_ANCHOR.MIDDLE) - add_text(slide, label, x + 0.68, 1.83, 2.72, 0.36, size=16, color=color, bold=True) - add_text(slide, eq, x + 0.22, 2.48, 3.32, 0.53, size=19, color=INK, bold=True, align=PP_ALIGN.CENTER, valign=MSO_ANCHOR.MIDDLE, font=FONT_LATIN) - add_text(slide, desc, x + 0.30, 3.34, 3.16, 0.43, size=13.5, color=MUTED, align=PP_ALIGN.CENTER) - if i < 2: - add_arrow(slide, x + 3.82, 2.86, x + 4.10, 2.86, color=MUTED, width=2.0) - - add_rect(slide, 0.67, 4.42, 5.96, 2.02, fill=PAPER, line=LIGHT) - add_text(slide, "学习器内部为什么是 BP-free", 0.98, 4.68, 3.2, 0.35, size=17, bold=True) - add_bullets( + add_title( slide, - [ - "更新只读取 pre-synaptic activity、local gain 和本细胞 residual", - "无 reverse-mode autograd;不复制 forward-weight transpose", - ], - 0.98, - 5.12, - 5.25, - 1.12, - size=13.5, - gap=5, + "Residualization is load-bearing under predictable traffic", + 3, + "Controlled MNIST intervention · depth 3 · width 256 · five paired seeds", ) + slide.shapes.add_picture(str(FIG3), Inches(0.42), Inches(1.37), width=Inches(12.48), height=Inches(4.87)) + add_takeaway(slide, "At traffic strength ρ = 0.5: raw 10.38%, norm-matched raw 10.31%, innovation 97.35%.") + add_footer(slide, "Norm matching equalizes per-example update magnitude. The remaining difference comes from teaching direction.") - add_rect(slide, 6.88, 4.42, 5.78, 2.02, fill=PAPER, line=LIGHT) - add_text(slide, "信用路径是可替换的已有组件", 7.19, 4.68, 3.8, 0.35, size=17, bold=True) + # 4. Standard ResNet-20 confirmation. + slide = new_slide() + add_title( + slide, + "Dynamic innovation survives a standard ResNet-20 test", + 4, + "CIFAR-10 · 200 epochs · five untouched paired seeds · four-times-RMS soma-predictable traffic", + ) + slide.shapes.add_picture(str(FIG4), Inches(0.43), Inches(1.47), width=Inches(12.46), height=Inches(3.82)) add_bullets( slide, [ - "Small nets: node-perturbation feedback vectorizer", - "ResNet: reciprocal KP plasticity", - "两者均为已有组件;SDIL 的贡献是 residualization", + "Dynamic SDIL under traffic: 91.584% mean test accuracy; clean reciprocal KP: 91.388%.", + "Mean early-layer teaching-signal cosine: 0.999687.", + "Cost: 1.326× the matched BP MAC estimate, zero task-loss queries, and one neutral observation per example.", ], - 7.19, - 5.10, - 5.06, - 1.18, - size=13.2, - bullet_color=GREEN, + 1.20, + 5.56, + 10.95, + 1.08, + size=15.5, gap=3, ) - add_footer(slide, "Credit substrates: Lansdell et al. (ICLR 2020); reciprocal plasticity: Akrout et al. (NeurIPS 2019).") + add_footer(slide, "Exact gradients serve diagnostic measurement; local signals drive every learning update.") - # Slide 4: controlled causal evidence. + # 5. Standard-depth scaling. slide = new_slide() - add_title(slide, "关键消融:减法改变了方向,不只是信号大小", 4, "强 soma-predictable traffic 下,raw 与 norm-matched raw 都失效;innovation 保留学习方向。") - slide.shapes.add_picture(str(FIG3), Inches(0.40), Inches(1.38), width=Inches(12.52), height=Inches(4.89)) - add_rect(slide, 1.02, 6.36, 11.25, 0.57, fill=BLUE_LIGHT, line=BLUE_LIGHT) - add_rich_text( + add_title( slide, - [ - ("ρ = 0.5:", 15, INK, True), - ("raw 10.38%", 15, DARK_GRAY, True), - (" · norm-matched raw 10.31%", 15, ORANGE, True), - (" · innovation 97.35%", 15, BLUE, True), - (" (5 seeds)", 13, MUTED, False), - ], - 1.18, - 6.47, - 10.92, - 0.33, + "Scaling from ResNet-20 to ResNet-56", + 5, + "Complete 60-endpoint CIFAR-10 panel · five seeds per method and depth · shared hyperparameters", + ) + figure6_top = ASSETS / "figure6_top_row.png" + slide.shapes.add_picture(str(figure6_top), Inches(0.56), Inches(1.42), width=Inches(12.22), height=Inches(4.38)) + add_text( + slide, + "SDIL under 4× traffic: 91.584% → 92.254% → 92.760%; all five R20/R56 pairs improve.", + 0.73, + 6.01, + 11.90, + 0.40, + size=14.8, + bold=True, + align=PP_ALIGN.CENTER, + ) + add_text( + slide, + "Reciprocal KP provides the scalable credit path. SDIL preserves this path under mixed apical traffic.", + 0.73, + 6.48, + 11.90, + 0.34, + size=14.5, align=PP_ALIGN.CENTER, - valign=MSO_ANCHOR.MIDDLE, ) - add_footer(slide, "Controlled MNIST traffic intervention. Norm matching uses the same per-example update magnitude as innovation.") + add_footer(slide, "BP and clean reciprocal KP follow the same depth trend; fixed DFA remains near 31%.") - # Slide 5: standard-scale evidence. + # 6. Dynamical task. slide = new_slide() - add_title(slide, "标准 ResNet:扩展性来自 KP,抗混合流量来自 SDIL", 5, "60 个 CIFAR-10 endpoints;每个深度 5 seeds,200 epochs,无 depth-specific tuning。") - - categories = ["R20", "R32", "R56"] - bp = [91.624, 92.302, 92.632] - dfa = [31.878, 32.684, 30.850] - kp = [91.388, 92.332, 92.670] - sdil = [91.584, 92.254, 92.760] - add_custom_line_chart( + add_title( slide, - 0.62, - 1.48, - 5.92, - 4.82, - categories, - [("BP", bp, DARK_GRAY), ("DFA", dfa, ORANGE), ("clean KP", kp, GREEN), ("SDIL + traffic", sdil, BLUE)], - ymin=25, - ymax=95, - yticks=[30, 50, 70, 90], - title="完整尺度:固定 DFA 随深度仍处于约 31%", + "A local actor–critic produces temporal outcome signals", + 6, + "Synthetic BCI task · six task clusters × five model seeds · manual local updates", ) - add_custom_line_chart( + panel_a = ASSETS / "figure5a_actor_critic.png" + panel_d = ASSETS / "figure5d_outcome.png" + slide.shapes.add_picture(str(panel_a), Inches(0.58), Inches(1.42), width=Inches(5.96), height=Inches(4.43)) + slide.shapes.add_picture(str(panel_d), Inches(6.80), Inches(1.42), width=Inches(5.96), height=Inches(4.43)) + add_text( + slide, + "Final success: 100% · terminal outcome decoding: 99.83% · outcome-lesion effect: 0.400.", + 0.68, + 6.06, + 11.98, + 0.36, + size=14.8, + bold=True, + align=PP_ALIGN.CENTER, + ) + add_text( slide, - 6.80, - 1.48, - 5.92, - 4.82, - categories, - [("BP", bp, DARK_GRAY), ("clean KP", kp, GREEN), ("SDIL + 4× traffic", sdil, BLUE)], - ymin=91.0, - ymax=93.0, - yticks=[91.0, 91.5, 92.0, 92.5, 93.0], - title="近 BP 放大:SDIL 在 4× traffic 下跟随 clean KP", + "The synthetic task supplies terminal reward and tests neuron-specific outcome surprise with causal lesions.", + 0.68, + 6.52, + 11.98, + 0.32, + size=14.0, + align=PP_ALIGN.CENTER, ) - add_badge(slide, "SDIL: 91.58 → 92.76%", 0.88, 6.45, 3.42, fill=BLUE_LIGHT, color=BLUE) - add_badge(slide, "1.31–1.33× BP MAC", 4.48, 6.45, 3.42, fill=ORANGE_LIGHT, color=RED) - add_badge(slide, "0 loss queries · 1 neutral obs/example", 8.08, 6.45, 4.25, fill=GREEN_LIGHT, color=GREEN, size=12.2) - add_footer(slide, "Source: complete 60-record ResNet panel. SDIL-specific claim is robustness under traffic, not clean superiority over KP.") + add_footer(slide, "Outcome labels and exact causal roles serve evaluation.") - # Slide 6: dynamical task evidence. - slide = new_slide() - add_title(slide, "动态任务:residual 携带 outcome surprise,而不只是分类误差", 6, "独立的 synthetic BCI actor–critic:6 task clusters × 5 models,所有学习更新均为手写局部规则。") - p_a = ASSET_DIR / "figure5a_actor_critic.png" - p_d = ASSET_DIR / "figure5d_outcome.png" - slide.shapes.add_picture(str(p_a), Inches(0.57), Inches(1.46), width=Inches(5.95), height=Inches(4.42)) - slide.shapes.add_picture(str(p_d), Inches(6.80), Inches(1.46), width=Inches(5.95), height=Inches(4.42)) - add_badge(slide, "100% final task success", 0.93, 6.07, 3.44, fill=BLUE_LIGHT, color=BLUE) - add_badge(slide, "99.83% terminal outcome decoding", 4.73, 6.07, 3.82, fill=GREEN_LIGHT, color=GREEN, size=12.4) - add_badge(slide, "outcome lesion: −0.400 separation", 8.92, 6.07, 3.50, fill=ORANGE_LIGHT, color=RED, size=12.0) - add_text(slide, "范围:这是机制验证用的合成任务;terminal reward 被直接提供,不是皮层数据。", 0.82, 6.66, 11.70, 0.32, size=13.5, color=MUTED, align=PP_ALIGN.CENTER) - add_footer(slide, "Source: complete untouched calibrated BCI confirmation; outcome labels and exact roles are diagnostic-only.") - - # Slide 7: positioning and next decisive evidence. + # 7. Current scientific position. slide = new_slide() - add_title(slide, "当前最准确的定位:可扩展 local credit 的混合信号分离模块", 7) - - # Pipeline strip. - pipeline = [ - ("existing credit path", "KP / learned feedback", "EFF1F3", DARK_GRAY, 0.66, 2.28), - ("mixed apical channel", "instruction + ordinary traffic", ORANGE_LIGHT, RED, 3.33, 2.76), - ("SDIL", "subtract soma-predictable part", BLUE_LIGHT, BLUE, 6.52, 2.52), - ("local update", "eligibility × innovation", GREEN_LIGHT, GREEN, 9.48, 2.80), - ] - for i, (head, sub, fill, color, x, w) in enumerate(pipeline): - add_rect(slide, x, 1.35, w, 0.98, fill=fill, line=color, radius=True, line_width=1.2) - add_text(slide, head, x + 0.12, 1.51, w - 0.24, 0.28, size=14.2, color=color, bold=True, align=PP_ALIGN.CENTER) - add_text(slide, sub, x + 0.12, 1.87, w - 0.24, 0.24, size=10.8, color=INK, align=PP_ALIGN.CENTER) - if i < len(pipeline) - 1: - next_x = pipeline[i + 1][4] - add_arrow(slide, x + w + 0.06, 1.84, next_x - 0.07, 1.84, color=MUTED, width=1.8) - - columns = [ - (0.66, 3.05, 3.80, "已经建立", BLUE, BLUE_LIGHT, [ - "可预测 traffic 会旋转 raw local update", - "per-neuron residualization 在受控干扰下是 load-bearing 的", - "组合方法在 ResNet-20/32/56 上保持近 BP accuracy", - ]), - (4.76, 3.05, 3.80, "真正的新东西", GREEN, GREEN_LIGHT, [ - "把 Harnett residual 直接定义成 teaching variable", - "neutral-period predictor + dynamic local projection", - "机制、方向、成本和动态 outcome 的联合证据", - ]), - (8.86, 3.05, 3.80, "仍然缺少", RED, ORANGE_LIGHT, [ - "自然任务中不可预先测量的 mixed feedback", - "真实硬件或真实神经数据上的必要性", - "证明 SDIL 的价值不能由 clean KP 单独解释", - ]), - ] - for x, y, w, head, color, fill, items in columns: - add_rect(slide, x, y, w, 2.68, fill=PAPER, line=LIGHT) - add_rect(slide, x, y, w, 0.56, fill=fill, line=fill) - add_text(slide, head, x + 0.18, y + 0.10, w - 0.36, 0.32, size=16, color=color, bold=True, align=PP_ALIGN.CENTER) - add_bullets(slide, items, x + 0.25, y + 0.78, w - 0.50, 1.70, size=13.2, bullet_color=color, gap=7) - - add_rect(slide, 1.06, 6.10, 11.20, 0.67, fill=BLUE_LIGHT, line=BLUE_LIGHT) + add_title(slide, "Current scientific position", 7) + add_text(slide, "Established", 0.78, 1.30, 3.30, 0.38, size=20, bold=True) + add_bullets( + slide, + [ + "Soma-predictable apical traffic can rotate a raw local teaching signal.", + "Per-neuron innovation preserves learning direction under controlled traffic.", + "Dynamic innovation works with a scalable BP-free reciprocal credit path on ResNet-20/32/56.", + "A separate local actor–critic reproduces neuron-specific outcome signaling in a controlled dynamical task.", + ], + 0.82, + 1.82, + 11.50, + 2.15, + size=17, + gap=7, + ) + add_text(slide, "Attribution", 0.78, 4.15, 3.30, 0.38, size=20, bold=True) + add_bullets( + slide, + [ + "Reciprocal KP provides clean-setting scale and feedback tracking.", + "SDIL provides soma-conditioned traffic removal and the associated mechanism tests.", + ], + 0.82, + 4.66, + 11.50, + 0.92, + size=17, + gap=7, + ) + add_text(slide, "Next decisive experiment", 0.78, 5.82, 4.20, 0.38, size=20, bold=True) add_text( slide, - "下一项决定性证据:在自然或硬件产生的 state-dependent mixed traffic 中,raw credit 失败,而 SDIL 无需 oracle calibration 即可恢复。", - 1.27, - 6.25, - 10.78, - 0.34, - size=14.6, - color=BLUE, - bold=True, - align=PP_ALIGN.CENTER, + "Evaluate raw reciprocal credit and SDIL under naturally generated, state-dependent mixed traffic with component-level bias hidden from the learner.", + 0.82, + 6.30, + 11.45, + 0.58, + size=18, ) - add_footer(slide, "Bounded conclusion: strong controlled mechanism + standard-scale compatibility; natural mixed-traffic necessity remains open.") + add_footer(slide, "Target claim: scalable local credit assignment with adaptive removal of predictable feedback contamination.") - OUT_DIR.mkdir(parents=True, exist_ok=True) - prs.save(OUT_PATH) - print(OUT_PATH) + SLIDES.mkdir(parents=True, exist_ok=True) + presentation.save(OUTPUT) + print(OUTPUT) if __name__ == "__main__": diff --git a/slides/qa-ledger.md b/slides/qa-ledger.md index 3375b35..33fa5c2 100644 --- a/slides/qa-ledger.md +++ b/slides/qa-ledger.md @@ -6,3 +6,6 @@ | Method title and three-stage visual used inconsistent step counts | PPTX/PDF | 3 | medium | Removed the numeric step count from the title | resolved | | Chinese font, formula glyph, chart and image rendering | PPTX/PDF | all | high | Exported through LibreOffice and inspected all seven rendered slides | resolved | | Claim attribution | PPTX/PDF | 5 and 7 | high | States that clean scaling comes from reciprocal KP and SDIL-specific evidence is traffic robustness | resolved | +| First deck used decorative cards and redrawn charts | PPTX/PDF | all | high | Rebuilt the deck in English with white background, black text, and tracked experimental figures | resolved | +| Rebuttal-style negative sentences | PPTX/PDF | all | medium | Rephrased attribution and scope as direct affirmative statements | resolved | +| Long title and summary lines wrapped into adjacent content | PPTX/PDF | 5 and 6 | high | Shortened the title and summary statements while preserving every reported value | resolved | diff --git a/slides/rendered/.gitignore b/slides/rendered/.gitignore index 82ae779..d73e6f7 100644 --- a/slides/rendered/.gitignore +++ b/slides/rendered/.gitignore @@ -1,2 +1,3 @@ slide-[0-9]*.png slide3_check.png +qa-*.png diff --git a/slides/rendered/SDIL_project_intro.pdf b/slides/rendered/SDIL_project_intro.pdf Binary files differindex 0378cdb..38406c0 100644 --- a/slides/rendered/SDIL_project_intro.pdf +++ b/slides/rendered/SDIL_project_intro.pdf diff --git a/slides/rendered/contact_sheet.png b/slides/rendered/contact_sheet.png Binary files differindex ad0ddc2..0b17b1f 100644 --- a/slides/rendered/contact_sheet.png +++ b/slides/rendered/contact_sheet.png diff --git a/slides/visual-contract.md b/slides/visual-contract.md index 86a7ffc..26fd3d6 100644 --- a/slides/visual-contract.md +++ b/slides/visual-contract.md @@ -1,14 +1,13 @@ # SDIL project introduction deck: visual contract -- **Artifact:** Seven-slide, 16:9 project introduction deck. -- **Audience:** Machine-learning researchers with no prior SDIL context. -- **Core claim:** A local learner should use the soma-unpredicted component of a mixed apical signal; this residualization protects an inherited scalable credit path from predictable traffic. -- **Reader questions:** Why is raw feedback insufficient? What exactly is new? Is the update BP-free? Is residualization necessary? Does the combined method scale? Which evidence is controlled or synthetic? -- **Evidence layers:** problem and mechanism (slides 2–3), causal ablation (slide 4), standard-depth scaling and cost (slide 5), dynamical-task evidence (slide 6), attribution and boundary (slide 7). -- **Source data:** `results/figs/figure3_innovation.png`, `results/figs/figure5_bci_v2.png`, `results/oral_a_dynamic_scaling_v2_gate.json`, and the evidence-bound manuscript. -- **Statistics:** Five seeds for the controlled traffic and ResNet panels; six task clusters by five model seeds for the synthetic BCI panel. Values shown are audited means or paired outcomes already reported in the manuscript. -- **Visual grammar:** Direct mechanism diagrams, two result figures, and editable line charts. SDIL is blue, reciprocal KP is green, DFA is orange, BP is dark gray. +- **Artifact:** Seven-slide, 16:9 English project introduction deck. +- **Audience:** Machine-learning researchers new to SDIL. +- **Core claim:** A local learner can use the soma-unpredicted component of a mixed apical signal; residualization protects an inherited scalable credit path from predictable traffic. +- **Reader questions:** What problem does mixed feedback create? How does the learning rule work? Is residualization load-bearing? Does the combined system scale? Which component supplies each capability? +- **Evidence layers:** biological motivation and rule (slide 2), causal ablation (slide 3), standard-ResNet confirmation (slide 4), standard-depth scaling (slide 5), dynamical-task evidence (slide 6), attribution and next experiment (slide 7). +- **Source figures:** `results/figs/figure3_innovation.png`, `results/figs/figure4_resnet_confirmation.png`, `results/figs/figure5_bci_v2.png`, and `results/figs/figure6_standard_depth_scaling.png`. +- **Statistics:** Five seeds for the controlled traffic and ResNet panels; six task clusters by five model seeds for the synthetic BCI panel. +- **Visual grammar:** White background, black text, plain typography, full experimental figures, and cropped experimental panels. One equation slide carries the method. The deck adds zero process diagrams and zero redrawn result charts. - **Exact method labels:** SDIL, raw apical signal, somatic prediction, innovation, reciprocal KP, BP, DFA, local update, neutral observation. - **Output:** Editable PPTX, PDF export, generation source, and rendered QA contact sheet. -- **Claim boundary:** Clean scaling is attributed to reciprocal KP; SDIL-specific evidence is robustness under predictable mixed traffic and the synthetic BCI mechanism test. - +- **Attribution:** Reciprocal KP supplies clean-setting scale. SDIL supplies soma-conditioned traffic removal and the associated mechanism evidence. |
