test variable.backward
/* pytorch equivalent >>> x = torch.tensor([[0.1, 0.2], [0.3, 0.4], [0.5, 0.6]], requires_grad=True) >>> t = torch.tensor([1, 0, -100], dtype=torch.long) >>> l = torch.nn.functional.cross_entropy(x, t) >>> l tensor(0.6944) >>> l.backward() >>> x.grad tensor([[ 0.2375, -0.2375], [-0.2625, 0.2625], [ 0.0000, 0.0000]]) */ import std.stdio; import std.typecons; import mir.ndslice; import grain.autograd; import numir; static import grain.config; grain.config.backprop = true; auto hx = [[0.1f, 0.2f], [0.3f, 0.4f], [0.5f, 0.6f]].variable(true); auto ht = [1, 0, -100].variable; auto hl = crossEntropy(hx, ht); hl.backward(); assert(approxEqual(hx.gradSliced, [[0.2375, -0.2375], [-0.2625, 0.2625], [0.0000, 0.0000]].nparray)); version (grain_cuda) { auto dx = hx.to!DeviceStorage; dx.grad.zero_(); auto dt = ht.to!DeviceStorage; auto dl = crossEntropy(dx, dt); assert(approxEqual(hl.sliced, dl.to!HostStorage.sliced)); dl.backward(); assert(approxEqual(dx.to!HostStorage.gradSliced, hx.gradSliced)); }
cross entropy loss (logsoftmax -> negative loglikelihood function)