assert to prepare for grad uop [pr] (#8280)

* assert to prepare for grad uop [pr]

* fix test_nn

* fix most of test_tensor

* few more tests

* fix multi

* uniform gradient

* acc_dtype

* any for multi

* fix typing

* fix assert, CAST_BEFORE_VIEW is still the issue

* explict test for CAST_BEFORE_VIEW

---------

Co-authored-by: qazal <[email protected]>
This commit is contained in:
George Hotz
2025-01-14 13:26:56 -08:00
committed by GitHub
co-authored by qazal
parent fdd46c9f28
commit c85737c200
5 changed files with 20 additions and 2 deletions
+2 -1
View File
@@ -781,7 +781,8 @@ class TestAutoCastType(unittest.TestCase):
if DEBUG >= 2:
print(f"testing {default_dtype=}, {dtype=}")
a = Tensor([1, 2, 3], dtype=dtype, requires_grad=True)
b = (a * 5).sum()
# NOTE: this is broken without default_dtype because of CAST_BEFORE_VIEW
b = (a * 5).sum(acc_dtype=default_dtype)
b.backward() # if there is dtype mismatch, lazy should assert
assert a.grad.dtype == a.dtype
np.testing.assert_allclose(a.grad.numpy(), [5, 5, 5])
+1 -1
View File
@@ -464,7 +464,7 @@ class TestTinygrad(unittest.TestCase):
def test_repr_with_grad(self):
a = Tensor([1], requires_grad=True)
b = Tensor([1])
c = (a + b).mean().backward()
c = (a + b).sum().backward()
print(a)
print(c)
+12
View File
@@ -93,6 +93,12 @@ class TestTensorGradient(unittest.TestCase):
dx = z.gradient(x, gradient=dz)[0]
self.assertListEqual(dx.tolist(), [2.0, 4.0, 6.0])
def test_cast_before_view(self):
x = Tensor([1.0, 1, 1, 1])
x_reshaped = x.reshape(2,2)
x_casted = x_reshaped.cast(dtypes.float16)
x_casted.mean().gradient(x_reshaped)
class TestRealizeMeansRealize(unittest.TestCase):
def test_randn_realizes(self):
x = Tensor.randn(2, 3, 64, 64, requires_grad=True).realize()
@@ -104,5 +110,11 @@ class TestRealizeMeansRealize(unittest.TestCase):
print(x.lazydata)
self.assertEqual(x.lazydata.op, Ops.VIEW)
# NOTE: even though it doesn't realize, this seems fine
def test_uniform_gradient(self):
x = Tensor.uniform(16, 3, 3, 3, requires_grad=True).realize()
y = x * 2
y.sum().gradient(x)[0].realize()
if __name__ == '__main__':
unittest.main()
+2
View File
@@ -97,6 +97,8 @@ class MultiLazyBuffer(MathTrait):
def contiguous(self): return MultiLazyBuffer([x.contiguous() for x in self.lbs], self.axis, self.real)
def clone(self) -> MultiLazyBuffer: return MultiLazyBuffer([lb.clone() for lb in self.lbs], self.axis, self.real)
def detach(self) -> MultiLazyBuffer: return MultiLazyBuffer([lb.detach() for lb in self.lbs], self.axis, self.real)
@property
def toposort(self) -> dict[UOp, None]: return {l:None for x in self.lbs for l in x.toposort}
# elementwise is simple
def alu(self, op:Ops, *in_srcs:MultiLazyBuffer) -> MultiLazyBuffer:
+3
View File
@@ -946,6 +946,7 @@ class Tensor(SimpleMathTrait):
# this is "implicit gradient creation"
gradient = Tensor(1.0, dtype=self.dtype, device=self.device, requires_grad=False)
toposort_uop = self.lazydata.toposort
assert self.shape == gradient.shape, f"grad shape must match tensor shape, {gradient.shape!r} != {self.shape!r}"
self.grad = gradient
for t0 in reversed(toposorted):
@@ -958,6 +959,8 @@ class Tensor(SimpleMathTrait):
for t, g in zip(t0._ctx.parents, grads):
if g is not None and t.requires_grad:
assert g.shape == t.shape, f"grad shape must match tensor shape, {g.shape!r} != {t.shape!r}"
assert t.lazydata in toposort_uop or (isinstance(t.lazydata, MultiLazyBuffer) and any(x in toposort_uop for x in t.lazydata.lbs)), \
f"grad uop must have a path from self\ngrad uop: {t.lazydata}"
t.grad = g if t.grad is None else (t.grad + g)
if not retain_graph: del t0._ctx
return self