1 static foreach (op; ["+", "*"]) { 2 foreach (j; [1, 2]) { 3 import std.typecons : tuple; 4 import numir : uniform, approxEqual; 5 import mir.ndslice : slice; 6 import grain.testing; 7 8 auto a = uniform!float(3, 2).slice.variable; 9 auto b = uniform!float(3, j).slice.variable; 10 auto gc = uniform!float(3, 2).slice.variable; 11 auto func = OpBinary!(float, 2, op)(1, 2); 12 gradCheck(func, tuple(a, b), gc); 13 14 auto c = func.forward(a, b); 15 auto gab = func.backward(gc); 16 version (grain_cuda) { 17 auto dfunc = OpBinary!(float, 2, op)(1, 2); 18 auto dc = dfunc.forward(a.to!DeviceStorage, b.to!DeviceStorage); 19 assert(approxEqual(dc.to!HostStorage.sliced, c.sliced)); 20 auto dgab = dfunc.backward(gc.to!DeviceStorage); 21 assert(approxEqual(dgab[0].to!HostStorage.sliced, gab[0].sliced)); 22 assert(approxEqual(dgab[1].to!HostStorage.sliced, gab[1].sliced)); 23 } 24 } 25 }
1 foreach (i; [1, 2]) { 2 foreach (j; [1, 2]) { 3 import std.typecons : tuple; 4 import numir : uniform; 5 import mir.ndslice : slice; 6 import grain.testing; 7 8 auto a = uniform!float(i, 2).slice.variable; 9 auto b = uniform!float(2, j).slice.variable; 10 auto gc = uniform!float(2, 2).slice.variable; 11 auto func = OpBinary!(float, 2, "*")(1, 2); 12 gradCheck(func, tuple(a, b), gc); 13 } 14 }
a and b have the same shape
1 import mir.ndslice; 2 3 auto plus = OpBinary!(float, 2, "+")(1.0f, 2.0f); 4 auto a = [[1.0f, 2.0f, 3.0f], [4.0f, 5.0f, 3.0f]].variable; 5 auto b = [[-1.0f, 4.0f, 0.0f], [1.0f, 2.0f, 3.0f]].variable; 6 auto hc = plus.forward(a, b); 7 assert(hc.sliced == [[-1.0f, 10.0f, 3.0f], [6.0f, 9.0f, 9.0f]]); 8 9 version (grain_cuda) { 10 auto dplus = OpBinary!(float, 2, "+")(1.0f, 2.0f); 11 auto dc = dplus.forward(a.to!DeviceStorage, b.to!DeviceStorage); 12 assert(dc.to!HostStorage.sliced == [[-1.0f, 10.0f, 3.0f], [6.0f, 9.0f, 9.0f]]); 13 }
a and b have different shapes
1 import mir.ndslice; 2 3 auto plus = OpBinary!(float, 2, "+")(1.0f, 2.0f); 4 auto a = [[1.0f, 2.0f, 3.0f], [4.0f, 5.0f, 3.0f]].variable; 5 auto b = [[-1.0f, 4.0f, 0.0f]].variable; 6 auto hc = plus.forward(a, b); 7 assert(hc.sliced == [[-1.0f, 10.0f, 3.0f], [2.0f, 13.0f, 3.0f]]); 8 9 version (grain_cuda) { 10 auto dc = plus.forward(a.to!DeviceStorage, b.to!DeviceStorage); 11 assert(dc.to!HostStorage.sliced == [[-1.0f, 10.0f, 3.0f], [2.0f, 13.0f, 3.0f]]); 12 }
a and b have different shapes
1 import mir.ndslice; 2 3 auto plus = OpBinary!(float, 2, "*")(1.0f, 2.0f); 4 auto a = [[1.0f, 2.0f, 3.0f], [4.0f, 5.0f, 3.0f]].variable; 5 auto b = [[-1.0f, 4.0f, 0.0f]].variable; 6 auto hc = plus.forward(a, b); 7 assert(hc.sliced == [[1*2*-1, 2*2*4, 0], [4*2*-1, 5*2*4, 0]]); 8 9 version (grain_cuda) { 10 auto dc = plus.forward(a.to!DeviceStorage, b.to!DeviceStorage); 11 assert(dc.to!HostStorage.sliced ==[[1*2*-1, 2*2*4, 0], [4*2*-1, 5*2*4, 0]]); 12 }
c = op(alpha1 * a + alpha2 * b) + beta * c;