From ddf04363d1d0acf92a8a83fbef244f297b78be1b Mon Sep 17 00:00:00 2001 From: lucasdelimanogueira Date: Thu, 16 May 2024 17:03:09 -0300 Subject: [PATCH] sub broadcasted cpu autograd --- build/cpu.o | Bin 10096 -> 11272 bytes build/tensor.o | Bin 40768 -> 42040 bytes norch/__pycache__/tensor.cpython-38.pyc | Bin 14781 -> 15407 bytes .../__pycache__/functions.cpython-38.pyc | Bin 6883 -> 7539 bytes norch/autograd/functions.py | 24 ++++++- norch/csrc/cpu.cpp | 39 +++++++++++ norch/csrc/cpu.h | 1 + norch/csrc/tensor.cpp | 37 ++++++++++ norch/libtensor.so | Bin 142952 -> 147176 bytes norch/tensor.py | 65 ++++++++++++++---- tests/test_autograd.py | 22 ++++++ tests/test_operations.py | 20 +++++- 12 files changed, 190 insertions(+), 18 deletions(-) diff --git a/build/cpu.o b/build/cpu.o index 7792721b854377d160348303da3404e4dfab3305..6228ac23853271c276dd0881ed9552fffc806dde 100644 GIT binary patch delta 1820 zcmZ{kO-NKx6vyv-qvn_&qdw@hAgQ39 zf);)R1t}$I61nKZLN{TgI|&N|BNqx%V2iXm$9pb59(drM`|j_Yd**)qXS24ezAvbE z1t*KzVkYPQ=$e3cE;BQ}yLvu!Kh$g77HFaF>d}z4@GGSOHeHwdJC9H4v04hm81)b~ z9>J`UsSU!AVQH@*C&SW~;UxNP`qr~G7&a^zLeK!O(RaWX^n`hcy!l!&^m;9=2FB4h!$NA(L=y?~d zRfx~n(u5|SAJ`p=4%vw~P4bd>2`(`|%KR?#Cgyd_|2p#9nO}6vM6MqZgB)1lKrxQV z-ZD=-D92;Wx0t_3lzf?ao-P;KpDg)J*@;t7cGxUC!_njvi90#k!n}uhEAw8Ob!dR2 zI~={rhc!V_?d7h2Lq7V6Gn><8ff}y!lle6B5OXh9qT?2Z1dYrqm^U&XVjf|>&3u)4 zm*gd4B}0-14vg}I3agE*Q4n zM<2$>g488p+x{nQdLO>Xya;pYYE=Fjb37msYvUWXI&|zR|F`5(LA}Qo7~vO7Jk`dZ z?8CSCflz*qEx(N~*~!1#xKBj)Ry0DZKvO&5a};CDsZc&PwS&Sm$`-pD@MEudgx?0` z2We=(PgQfDG8VE2KKlTY@LHE z!O|ZDnX01%+vng)uoHHE7AGpjF4zOem0&j=TnW}d8In<$+PD|4`M)OR@*Pu1z+^!> zv;;B}!t|cdT67o)oX{_rsBkZ=1cK_*R}j?0CY&y))O$?0gWWXeU;sZ83M<`9T)Gs_ o6_&df3S`MD=*LlfmKgLpB}5@2vk9yOB`PSQ5)2}&kt8r^ zF>;6yjI?qg6e*ke+|=Bmhs7e zrEtvHRnwt`!pOSJ4B=}iTgOo@r1;`eg&3ie$DUcNmRm0jd`rb(62R5>U~l>h#xK1 zV1Rg^S{1%T>LjT*)z3kDpj7$D@mb|FQ3BN605{75I;kFhxkk4eZ))f1a;j; znFh~@HxYkM{2TG}njaA(<(l-8aF-T*CC(rA6nOwnMuIgHl#veVC7kiz$r!UkFksCt zbVmbu&>vsUjML4jI;h5x`=`yMyYcc-7q?vb9S8JrcmYDyNQDkX7jd;uEe_uQV~LZH z5lV=;gnYU>#p5pCNt_R;LrvLn`c9SKfP)X1aq+`09>r&6Y9B+uX8pwsH^H*vXj&42 zn_$bKdz_m9f2d=e&rJ~ZaBhMV9!@=w5&a&4n_$?(xd~o*IG4X_B4zwST>d{joC`mo z5=CZj0oQrT5%xIOdD_Fd&Tn}**Ll{%xz6X@ycyqt>-@7@K+bjk+r!gAD6%(=l_31E zTZ$%CC8EtqNG4hg8G%(+FjeAhadxj9%9=4Esay wBH8XArn~@rPqzBgwR)8eiH25x*3?lNu41$m(a{pjV01?nFWR89f6gxc4~5U@1^@s6 diff --git a/build/tensor.o b/build/tensor.o index f5f937d2733b7287bdda826638b5b1d23b3a67c6..877b650e54948ad91c31d851964afd087a2197a4 100644 GIT binary patch literal 42040 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 UuW9^_k1W+kq|AZx*N*@H0?(mB?*IS* literal 40768 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 E7uSiqjsO4v diff --git a/norch/__pycache__/tensor.cpython-38.pyc b/norch/__pycache__/tensor.cpython-38.pyc index d2c4826f08c24079dbe2962ca745e3bdc22edbf9..5a33b4a3b38d8766ef05b6c52cb3729e188a2a2f 100644 GIT binary patch delta 733 zcmY+A&u>ye5XU=!f;_+j0J%rZ)-s|Aq5uda}8 zoZnzmu%Sh?T3McS4@XODN|j860)? zn^=y7C_#_QZc%3^<)QO{_6*-woUU$uma1~GQetd3PiqTYIFimz)YI%DyM)7LD<(xV z7P>}pPF#TiUUNq+0Xy@P=TXA%Ule(``3n;(k>DXrl7-PANsKBdn-ig~CVkuB6;At(!!$mRJB)3; zBo*axNm{^FUl!gf$(@h1P{578L3pop_XlX+%Wf-<`O~0wg`fQfO@{_k!Cm;%|AEV| z2ZOi~NC;P{1rI?@6sY}jsV+&K8YLB+|L5euU?}s)tr;?bUwO)@I%S0G|GVJ6Av2s( zl0)Ztg3=5x0W_4{@Hv3{*bEOSKO$a$$7&dh@*0b{8v712D297*ZLbX9@ML@z*6~yP zWnhA=rwC=jWdey46~ZjONr*jj6y7ABKyN(4Q%AVwp!$dJtslQt!BlC)M+ zQR)xyqVPaedK5}Tt9B1Uz=H?9c+`Vb@Fog9_!kK7+t7n^_%OTg^S<+DUSE6P^js80 zx6NG2<+J54<+q-a1Twaygvl4u7|6y)={$JlAs#lR9cR5&DRHiwd(I5i*99ox?Vt)p z+zP7uOY}czqB~&uyo?!t9dBs^_}N!;+7>(=z>{OM9$N?2?Hvd6b{tt-7pH^AJ>7%+ z2(_OfP^jXZb2r;M=Hn8+5uE7vj~MJri#d+Jt4oD&Yp9L%4~7^!UEJ=61)` c;Ppm{w^sQ*{F|1Lr(@v5=V=Y@W-Z|9$Xc0Vou-f3pB$i|MnrAR2UyxbrU5#4s+9 zpbtsMp2K0uU~oYIO#V*m&-pMZv=n{uC3Ks^Hk#0FbxU!-sYl(|B-O;5d9jhNl9#~% zLo>YCOk2$?b$AD$i~e{M^vIis9*(;7*-YxBVBHqFVXK;0PZp*M9eVJ@8tb$S;u2N%<;&=MG?AEEWuLQV|T2p6*O zE|lr3c>xa7(HY&=3SK{0!&#xsL*WdpRGU3c!{I@rgE?t0w$t12IygzONSC#WQ^#tg ztJE&;NBaIr&t8r8+e)cbeON5*9XwD(oh9g~-krZ1O;OTpwt6^srpBsAS*5J~UTG_? zRi#{}iZv8mpb`RE}&ri zH0)Ih%iaxl=%8H=w(%;;iB3%)+^0GxXZ3O7c8#u&by<4gOt-8;f1G~kp#H=%cuW@) z-BynI4{J0zrJ0qS);yy_$(>QvEVt?rKX#)NxIqoV3;LDp-X|mTw8lg-=?E_4AC%__ zV*)bZD07Q4mMGJPGDIi?fpX#~XNS^t%m_#;Q1*pVC~oBE#A&Y@tH<{j%45YIc_Wk> a7!0@RGaWO@XqbL8Y(~uhM?Q`XiT(oQ@bta_ delta 947 zcmY*Y%}*0i5NGIa*?ukCZo6%1<*OK2hn&CdSj_nUcd-t6zx_e1JApU+*z z&sK48qDxy>Allnb0|TaK~6_0c+&_!-fUTWF6hT#nzr<`-pkOWP1X)H8XPR;Bx2oT!q;b{LY5~Hetu#xtZRGV70}H%% zZ%D=zY2oEc@fFe{2E7lTf&1(o(KF0k-otia#wz$Uas^iDZ)D!HpQ9*l8^gPOU!%?F zpq^#yflZoa=>T=tWh=!tXthq9^lRNg*rZS_qvx2vZqwvglc!g)Tt)MQ{>3f^tj1QO z%v2uVsaYJ@t-VF};+gRR2Oit<2*lK|lV4aZOi&mxt|;aY#aN*j6%<2&;)YS&6^fRl rXc~%Mpg0xggemaP5T@L|+GdeOsa9*$C@)2IshS#4-R#w{uL$oyn0CQ1 diff --git a/norch/autograd/functions.py b/norch/autograd/functions.py index 46b5b36..8ce8625 100644 --- a/norch/autograd/functions.py +++ b/norch/autograd/functions.py @@ -28,10 +28,30 @@ class AddBroadcastedBackward: gradient = gradient.sum(axis=i) return gradient - - + +class SubBroadcastedBackward: + def __init__(self, x, y): + self.input = [x, y] + + def backward(self, gradient): + x, y = self.input + grad_x = self._reshape_gradient(gradient, x.shape) + grad_y = self._reshape_gradient(gradient, y.shape) + return [grad_x, -grad_y] + def _reshape_gradient(self, gradient, shape): + # Reduce gradient dimensions to match the target shape dimensions + while len(gradient.shape) > len(shape): + gradient = gradient.sum(axis=0) + + # Sum along axes where the target shape dimension is 1 + for i in range(len(shape)): + if shape[i] == 1: + gradient = gradient.sum(axis=i) + + return gradient + class SubBackward: def __init__(self, x, y): self.input = [x, y] diff --git a/norch/csrc/cpu.cpp b/norch/csrc/cpu.cpp index 5a0cb29..bde7b0c 100644 --- a/norch/csrc/cpu.cpp +++ b/norch/csrc/cpu.cpp @@ -58,6 +58,45 @@ void sub_tensor_cpu(Tensor* tensor1, Tensor* tensor2, float* result_data) { } } +void sub_broadcasted_tensor_cpu(Tensor* tensor1, Tensor* tensor2, float* result_data, int* broadcasted_shape) { + int max_ndim = tensor1->ndim > tensor2->ndim ? tensor1->ndim : tensor2->ndim; + + // Calculate strides for broadcasting + int* strides1 = (int*)malloc(max_ndim * sizeof(int)); + int* strides2 = (int*)malloc(max_ndim * sizeof(int)); + if (strides1 == NULL || strides2 == NULL) { + fprintf(stderr, "Memory allocation failed\n"); + exit(1); + } + + int stride1 = 1, stride2 = 1; + for (int i = max_ndim - 1; i >= 0; i--) { + int dim1 = i < tensor1->ndim ? tensor1->shape[tensor1->ndim - max_ndim + i] : 1; + int dim2 = i < tensor2->ndim ? tensor2->shape[tensor2->ndim - max_ndim + i] : 1; + strides1[i] = dim1 == broadcasted_shape[i] ? stride1 : 0; + strides2[i] = dim2 == broadcasted_shape[i] ? stride2 : 0; + stride1 *= broadcasted_shape[i]; + stride2 *= broadcasted_shape[i]; + } + + // Perform element-wise addition with broadcasting + for (int i = 0; i < tensor1->size; i++) { + int index1 = 0, index2 = 0; + int linear_index = i; + for (int j = max_ndim - 1; j >= 0; j--) { + int pos = linear_index % broadcasted_shape[j]; + linear_index /= broadcasted_shape[j]; + if (strides1[j] != 0) index1 += pos * strides1[j]; + if (strides2[j] != 0) index2 += pos * strides2[j]; + } + result_data[i] = tensor1->data[index1] - tensor2->data[index2]; + } + + // Free strides + free(strides1); + free(strides2); +} + void elementwise_mul_tensor_cpu(Tensor* tensor1, Tensor* tensor2, float* result_data) { for (int i = 0; i < tensor1->size; i++) { diff --git a/norch/csrc/cpu.h b/norch/csrc/cpu.h index 5e64293..fad467c 100644 --- a/norch/csrc/cpu.h +++ b/norch/csrc/cpu.h @@ -7,6 +7,7 @@ void add_tensor_cpu(Tensor* tensor1, Tensor* tensor2, float* result_data); void add_broadcasted_tensor_cpu(Tensor* tensor1, Tensor* tensor2, float* result_data, int* broadcasted_shape); void sum_tensor_cpu(Tensor* tensor, float* result_data, int axis); void sub_tensor_cpu(Tensor* tensor1, Tensor* tensor2, float* result_data); +void sub_broadcasted_tensor_cpu(Tensor* tensor1, Tensor* tensor2, float* result_data, int* broadcasted_shape); void elementwise_mul_tensor_cpu(Tensor* tensor1, Tensor* tensor2, float* result_data); void scalar_div_tensor_cpu(float scalar, Tensor* tensor, float* result_data); void tensor_div_scalar_cpu(Tensor* tensor, float scalar, float* result_data); diff --git a/norch/csrc/tensor.cpp b/norch/csrc/tensor.cpp index 28501d2..ad56c94 100644 --- a/norch/csrc/tensor.cpp +++ b/norch/csrc/tensor.cpp @@ -259,6 +259,43 @@ extern "C" { } } + Tensor* sub_broadcasted_tensor(Tensor* tensor1, Tensor* tensor2) { + + if (strcmp(tensor1->device, tensor2->device) != 0) { + fprintf(stderr, "Tensors must be on the same device: %s and %s\n", tensor1->device, tensor2->device); + exit(1); + } + + int max_ndim = tensor1->ndim > tensor2->ndim ? tensor1->ndim : tensor2->ndim; + + // Determine the broadcasted shape + int* broadcasted_shape = (int*)malloc(max_ndim * sizeof(int)); + if (broadcasted_shape == NULL) { + fprintf(stderr, "Memory allocation failed\n"); + exit(1); + } + for (int i = 0; i < max_ndim; i++) { + int dim1 = i < tensor1->ndim ? tensor1->shape[tensor1->ndim - 1 - i] : 1; + int dim2 = i < tensor2->ndim ? tensor2->shape[tensor2->ndim - 1 - i] : 1; + if (dim1 != dim2 && dim1 != 1 && dim2 != 1) { + fprintf(stderr, "Shapes are not compatible for broadcasting\n"); + exit(1); + } + broadcasted_shape[max_ndim - 1 - i] = dim1 > dim2 ? dim1 : dim2; + } + + // Allocate memory for result tensor + float* result_data = (float*)malloc(tensor1->size * sizeof(float)); + if (result_data == NULL) { + fprintf(stderr, "Memory allocation failed\n"); + exit(1); + } + + sub_broadcasted_tensor_cpu(tensor1, tensor2, result_data, broadcasted_shape); + + return create_tensor(result_data, broadcasted_shape, max_ndim, tensor1->device); + } + Tensor* elementwise_mul_tensor(Tensor* tensor1, Tensor* tensor2) { if (tensor1->ndim != tensor2->ndim) { fprintf(stderr, "Tensors must have the same number of dimensions %d and %d for element-wise multiplication\n", tensor1->ndim, tensor2->ndim); diff --git a/norch/libtensor.so b/norch/libtensor.so index aa08bb848b39f33912083477f58b75a773fd9af2..dd541411409203c335b805a6b165023a0035897d 100755 GIT binary patch delta 29125 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