English · Español
Lab 00 — Esqueleto de Value¶
Objetivo: escribir el esqueleto de la clase
Value: constructor, repr, la fontanería_prev/_op/_backward, y el recorridobackward(). Sin operaciones aún. Este lab hace explícita la topología antes de que corra ninguna matemática.Tiempo estimado: 90–120 minutos.
Prerrequisitos: lee
theory/00..04. Las utilidades de la Fase 6 existen.
Lo que produces¶
src/minigrad/scalar.pyconteniendo el esqueleto de la claseValue:__init__(self, data: float, _prev: tuple = (), _op: str = "") -> None__repr__data: float,grad: float,_prev: tuple[Value, ...],_op: str,_backward: Callable[[], None]backward(self) -> None— topo-sort + recorrido inversosrc/minigrad/scalar/BLUEPRINT.md— ya pre-escrito por Claude. Léelo ahora. Ábrelo en split conscalar.py.tests/test_scalar_skeleton.py— tres tests que pasan incluso sin operaciones implementadas:Value(2.5).data == 2.5repr(Value(2.5))contiene "2.5"Value(2.5).backward()se ejecuta sin error y fijagrada 1.0- Aún sin directorio
experiments/— los labs 01 y 02 producen experimentos.
TODOs¶
Bloque A — leer BLUEPRINT primero¶
- Abre
src/minigrad/scalar/BLUEPRINT.md. Lee las secciones "API surface" y "anti-goals" completas. ¿Desacuerdos? Indícalos en tu/phase-checkpoint; no diverjas silenciosamente.
Bloque B — esqueleto de la clase¶
- Crea
src/minigrad/__init__.py(vacío o con__all__ = ["Value"]después del paso C). - Crea
src/minigrad/scalar.py. Añade la claseValue. - El constructor toma
data: float,_prev: tuple[Value, ...] = (),_op: str = "". Inicializaself.data = float(data),self.grad = 0.0,self._prev = _prev,self._op = _op,self._backward = lambda: None. -
__repr__devuelvef"Value(data={self.data:.4f}, grad={self.grad:.4f})"o similar — tu elección, pero hazlo informativo. - Añade type hints en todos los atributos y métodos.
mypy --strictdebe pasar. - Aún sin operaciones. Resiste la tentación.
Bloque C — backward()¶
- Implementa
backward(self): - Construye el orden topológico. Usa un helper recursivo o una pila iterativa — tu elección. Documenta la elección.
- Fija
self.grad = 1.0(semilla). - Recorre el topo invertido, llamando
v._backward()para cadav. - Defensivo: assert
self._backward is callable. (Siempre lo es, pero el assert documenta el invariante.) - Decide y documenta: ¿
backward()resetea gradientes primero, o asume que el llamador los ha puesto a cero? Default de la Fase 7: NO resetea. El llamador (eventualmente el optimizador de la Fase 9) es responsable dezero_grad(). Anótalo en el docstring.
Bloque D — type y lint¶
-
mypy --strict src/minigrad/scalar.py— verde. -
ruff check src/minigrad/scalar.py— verde. -
ruff format src/minigrad/scalar.py— aplicado.
Bloque E — tests del esqueleto¶
-
tests/test_scalar_skeleton.py:
Restricciones¶
- Sin NumPy.
scalar.pyopera solo sobrefloatde Python. Se permiteimport mathparaexp,log,tanhen labs posteriores. - Sin PyTorch en
src/. PyTorch es dependencia solo-de-test. Callable[[], None]es el tipo correcto para_backward. Usafrom collections.abc import Callable._prevcomo tupla, no lista. Las tuplas son hashables y señalan "fijado en construcción".- Sin mutación de
_prevtras construcción. Hazlo_prev: tuple[Value, ...](inmutable).
Condiciones de parada¶
Hecho cuando:
mypy --strictyruffambos verdes enscalar.py.- Los tres tests del esqueleto pasan.
- Puedes hacer
from minigrad.scalar import Valueen un shell de Python e instanciarValue(2.0).
Escollos¶
- Referencia hacia adelante para type hint.
_prev: tuple["Value", ...](entrecomillado como string) porque la clase está a medio definir cuando se lee la anotación. O usafrom __future__ import annotationsal inicio del archivo. - Argumento default mutable. No escribas
_prev: tuple = ()y luego lo mutes. Las tuplas son inmutables así que está bien, pero si accidentalmente lo haces unalist, has reproducido el bug de "default mutable arg" de Python. self.grad: float = 0.0. Usa0.0, no0. De lo contrario la promoción int de NumPy/Python podría sorprenderte en tests.- Profundidad de recursión del topo-sort. El límite de recursión por defecto de Python es ~1000. Para los grafos de la Fase 7 (decenas de nodos), sin problema. Los bucles de entrenamiento de la Fase 18+ necesitarán un topo-sort iterativo o
sys.setrecursionlimit(...). Documenta pero no optimices aún.
Cuándo consultar solutions/¶
Después de que los tres tests del esqueleto pasen. Luego solutions/00-value-skeleton-ref.md (en la apertura de fase) muestra la estructura de referencia y cualquier elección de estilo a considerar antes del lab 01.
Siguiente lab: lab/01-implement-ops.md.