From 27a866d7217c504541b6d2902b8d7939acd3c589 Mon Sep 17 00:00:00 2001 From: lucasdelimanogueira Date: Thu, 16 May 2024 16:43:11 -0300 Subject: [PATCH 1/4] add broadcasting autograd --- .../__pycache__/functions.cpython-38.pyc | Bin 6274 -> 6883 bytes norch/autograd/functions.py | 21 +++++++++++++++++- tests/test_operations.py | 6 ++--- 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/norch/autograd/__pycache__/functions.cpython-38.pyc b/norch/autograd/__pycache__/functions.cpython-38.pyc index 1b23177b4713a178051ab9e043380440add257da..54c57547c44ec2850e55584cfcd938fa09da50fc 100644 GIT binary patch delta 1335 zcmZWp-ES0C6rVF+JNq@e-Pw;;Y74feELE_r8fn?=_5*l;ENO^oAVM>A)}>wO$C*|P znWn~SBxy{<6B8vVDK8|(C!YBW`~!TM7mPmnralm2V)UHp7FpcQIdkthzu!Ig{_dIi zbmZ4}?Dx~@gu=gF_soYUvXAV)RCrC7rUsGt*|)hc~iLJdJC?< z-tcJ8oI8|crmqSgZuh^G|0CT;tBLfbc-(sgg0&M=jypJh& zp>@ke@Ax%(VCJ`UMv6_d`E_>dN&ri+4g6HMp{3(to~s^s>X)zyYs$K|pV@{P2w zL0Jtm;tI5v>~^GtRQ64F7Fe2P(wer*jgZk>FvPx_evAz`eViT;oQNnm?4wz;MsZ^S z4%5$O35Mx&|oNiNBDagzfBdQk0+N~XRIu;|zd=si^!d8tS^19Et+sCL&@$kGdwEaSnXMcCZ5j$DE4GkA7PL1(*J27ASLoD} zvd{rt8Z}GQuT{XJJuRTO+8DU34LBJFqy@4;B6S5bj4jf$*fi~Wt}2cVD6Ut)rv*C; zSz6Ugj>lI2P*ekYGAa|Fg&eKKm!m&`cH^g^joK3fT+D?9ikk*Ye+EK<}D{UEFFi5|Ri%yOW{dIvk4txQZ z=%={>Wm-uMsUqcO8Ud9Aa04i*kyX{m-bUXq& z3^@fxJ>YdvjDiK(o96I<%*S*uylP8IqW_stYIApRKsNXZ{RxMvgPh<|T@qo*r?H)X zC`J~=0Hc^q6r+Y>fKbc@=7bPUM9~}+jG|x&#kEmf0!58D$nU_X4@ZJfGh?Q1#?7>8 Mn+euptm{Ji2OkozRsaA1 diff --git a/norch/autograd/functions.py b/norch/autograd/functions.py index b114534..46b5b36 100644 --- a/norch/autograd/functions.py +++ b/norch/autograd/functions.py @@ -8,7 +8,26 @@ class AddBackward: return [gradient, gradient] class AddBroadcastedBackward: - pass + 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 diff --git a/tests/test_operations.py b/tests/test_operations.py index 3eeb8b1..ed4ee46 100644 --- a/tests/test_operations.py +++ b/tests/test_operations.py @@ -192,7 +192,7 @@ class TestTensorOperations(unittest.TestCase): self.assertTrue(utils.compare_torch(torch_result, torch_expected)) - def test_sum_axis_no_keepdims(self): + def test_sum_axis(self): """ Test summation of a tensor along a specific axis without keeping the dimensions """ @@ -202,9 +202,7 @@ class TestTensorOperations(unittest.TestCase): torch_tensor = torch.tensor([[[1, 2], [3, -4]], [[5, 6], [7, 8]]]).to(self.device) torch_expected = torch.sum(torch_tensor, dim=1) - - print(torch_result) - print("\n\n", torch_expected) + self.assertTrue(utils.compare_torch(torch_result, torch_expected)) def test_transpose_T(self): From ddf04363d1d0acf92a8a83fbef244f297b78be1b Mon Sep 17 00:00:00 2001 From: lucasdelimanogueira Date: Thu, 16 May 2024 17:03:09 -0300 Subject: [PATCH 2/4] 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 zcmai72V4}#_upGN1Y!ZDTCsOUBeqDyf?iY<6E()(d++`1iikm1UAtIgEK#FTV*?9{ zii#au0*S`6C72jRO}PK}&CH(5kl*LOpIqL~_tkmxW_E55cOCaV9RGU61s3WVsjwrQ z6J=nXC6()V#(&J4@k<8Pu)o~M8wORpdD{ZwMyHv)Ez_qeNhpdz&3f*@L;mIbko+o> zGiXI(;>hAu3$PR_Bt&gO6jb}fayj@uw~#5(lsw!*idIRDGIR~|pjwO?>07G)R||$r z>Gy0))hbilXIdVVd)+9n_FN70T^YQ%v8pz)BsO2UOqpZp?CTMJQVYzpJu;MARqBH_ z5a$gA{S>s3IByCXflqUMTHs^Dhtk{zpD29V;nPuTtOnRS;f#*X_;kUi8$P}8>5Y$Z z^ubAA(dZ945T8N#48dm@K6DJnX9PP_l#!sL@fk1L6F?`5^GTpn#Q9W3>CR5431B+t z3~^3mjyRtu=zP#^@>yf#a`HY#s`Wf%LuzgEgKKo8Duanr`;^|j>FH>zrYWjt#$Bk<6&CBsun>kLSO~+UvpKy}5 zLpV|PVa|~KZZuFh2Ik@PEM@_4yYjov0Spj3nhFOcj`4ONFM6dcC>g5pEysfeK8U&r zJn1&a#avbv3&+J)bG)jMukX#}gYOY;N3{t?Jep)ED2f=0@|qLnrEt9GD-L`qdeFkk z<=YFC>T2#T7Q}|CW{`-6akH)`o?iy;C=Ip+}b9g&Ir1T3Bsd|p%Mxgz~ zSQZnGyK=TNSKz&8}?Mr$DsqgLJt+^!wu3}c#Y5sXnkaNID|M2uxIkvd~6=L^TF zE4ln&PLzXUJqS$VfKk-Hqe+?Qv7O;|B~>Vt6l1(*3kTK-e6YxnWj_bnh}5+bV|iE< zmodiIMWA!;b9p1s6C%)ry&UHq!}u2#V;m_WHOBacsOpZQh>WU!C=4}N#SQi6L>VSB z*Kz{~=mJAWps0ytfg96u2Mwhisc8Kr7wjX(@~tSwh9VO^I9pi-KBcb9ZVnhLAk9X? z3%29N z2%3o=yC3DaQCrDk$g;#z4SD1rM`e-H!J>$aluj2t_+}nAWK7FHMWEmH=D1PSVFGuj zodphKc03RPO`64V!_LjT@J~Is_akRi5ydq`6yp~$91li-bQBfEn6ZzyjUl)$YG~*M zjvFhfyGZpGF*L@tqnGILI{O~3U`(?WBGR3QIBukFmrzg#aNOu|0g=+O*Ewzsftwhb zT_-qh1hfwwD~%2>%HX)&n3stX!@&O#ReeHiq>R)x6`6<^v%sj8+M-r!iA)%?<{yE- zy2c%gY5BQwT^O>h;f!y^5X=%|`K2g-BX!ZDCh8pL@ve z3402>>L89AdA%Tdc4Vm-~gyT5^ND>cuUalN&@et|^w6TWH%J>FL>vVVjB z{sQ~kl`Cb@_Lg&FliH$Klvl_){!@bSi7Gz{mOPXoA8w!c_e}ijdxju_yhq232&r{b>bm4D%0(`3XAVo>`wNpJ4+F`iMNt)1C{x>a&>+lO ztI{-wLDgl@_y&cE!4B^>oYoWH$_zX`o#WvyoG)rhY9wa_7UsocC>ZS!2@ifF97y;; z(Y8r=+FLGfE6D95J^V|V@UKLf7z?>9`+p}BUfzWFG~pFY_&^h0$AphG;TSvDVV`JX z)OEr5zGcFV%OkNDnDEa{@^L2I=oGP6n(#^{`FM`oQ6`Gg)x_9tQZQy9vGX{T486ar5 z2_I>~Z6;hSzKk1X!o@X-;hjFa4hPsW3S!BFs|doJ#4~1c8M!W zq6w#&V;spQJjwt;Q%!iR2~QKaoyOi~Vx*fCs+e$x2^Tvp#?3V0WXm|RO!yE3BNg(Y^l z3ID<*Z!_WDO?Z?E$Ii-ibRwMUkJ47n1uIHVlfn`cKG1~Y`s_MJnsDrGT*pKc-qD3( zX*c0^TvuJk0uw`AK^ZU3gb#E{V{JF#1x$Fn32$h^x0~qs`?{aq+#feFXH!*!(j*gsUG*qktCx=G;^m$;%hOn4y^o@v5snD8tU9%jOo zLc%Zg-`B+OFc`r6Ot`lR_c!5zCOp7|2b=JgCcL5v?+2XcA15Iu#$1y^Jri!+tR;51 z37=$=x0&!+COpc7fB6BoE1gV?+8-E7PZJ(!!Uvl0K_+~p3GZ#fCz|je6F!6C=s!)r zq9(=ylR_~Q9%sUfoA8w;yn_jkH{q>K_;wTC!@_heniLM3@RBAx(S!$^@MIG{ z+k~f@@KOS2{?km1(k6v;6W-Z`J4|?e6P{_pJDKn-6W+pvD}`0Q!=oV>Y+`tboe$yT zO}MuSFSp%(kdS!o=@V8d`z#hQ= zeDd$bJx*#5liK~Hb~mZr z!7c%jQaeIwhe_>Fsa;KKmy_DXrMBHq0`g03tJMBCDQCw1mfA0*_9LnNAZOcN?q*J) z+$E`ee72ad^1vO@Sx%>;uhZ!~YweJv zrAL#p+t#L{iO=v26)8 zm`k)HiM9V4R!eJZ+Wzc0bpr)`&aqIN9aUX@|5n={Rmbv$_B1NE@ALJX^$w2bCXTCQ zi$SO{;UP%EEy4PkvkEX4tkgjJ*{5h_LTH~5I>Lo2nDmzj)&^~OyRKy}97k4SD7hgV zXE&)GU7*Jka5YP7+bu|Sf2%bb5Y%XlOT3g>+|4CE8F`1ZWEL!r1fwGy7yySduIn=zf=97X~--Y(6&@^h}E=o>A&OX;Bbf02U@ zX||ZiL>7DWWg3>azqO1$ep=J^0lu@S7tzS<>}i?2S}Go;P<_5ygJ`y(E8KqN*V=}z ze(L_$TCcu-T4H-Y%K+_G`;ahq=wpjn57tv{F}4s;c#8tHjyYlsKq=UA#q0(RZgaBM zv_q(G-@oMuypFKi`(!mDnCI$YK5buzRTWzP$c;vyJVG~NPEe{akNS}8S(oM3+Nh2# zeM`M!mQ6F^++ng@F>58Ho4TaWvn)ksB2y^Eap(v7fHe7N`MzwEzt&4w5i?}GHsH%r zeslhGI%iKi;4CeS3%uSF22h$Du=fy1a*A0^QYe_>ha}h;*bmou~N_)9`la z;C@URY|wwy+&WdW?9^&?n&R~tSQN&We`-F{O8cJv9VXaVMjW<9-y%*=?M0{3zLzM# z978zfAWPtu6|nsWJagOQG}~8=)%}^;$-Pyz0^LfKNx(1qe1`aOSG=gAV2^8@&15s= zeI}bB16|_&Fzg!7x0#0c2%NDhqv?$BYEZ-?b7L}ThNv_D&|dZp@~=aZ(iFLSfPxPE zXgPxJNQq-B&iy~grgb-CdjGTx%u2*$+1jHO=rXBd{sTE@$ZlA0MYj_AT)2R?r%QyV z3JVmQxAt$BGM1@YsjmL&xaVv-wCNh)JAp#Zk;~%ySuWdX@Vv^^)sotJC^}xS*>DjP zqw5RpcKaHizJKvQr^CSSjcohFmMg%w(BJ`%c%e1xP}}z_069Z&?xPTVLU6O*F~!v% z%M0!M4l64*+V`Imq7w-pMQ^z6#?Q6U9Y6E+f6i>1X2h|*WV_OfIEdGCiJy2zSnagQNB9L`+g?OfvLo|4lK z3+#Lc+M;|eK4s-|=LsvH#Uv?}Ppv(yeENKij(mr1^75(8Y+9|v^!Fy-OyaTX$@`Qo zu>HPcak&=Q-R9^rpBU2ppRfhCGj4WM{S17<7T6n)DCS%XZ2qUHD1XaSEvlLhS-ue*Mr}$0M!Rgy5R5A5!oU zi80|7qa$v_MBMn`e<$TeDv!21SO#X`Cq&0Zc;Xpo$A-^ZnlXL8Am(~vvid0dNc*f$ zlvh5W)T<(ov>p>n7n_$sej{;_>yQ`|kz%7O>h1mohbKDj|H6{e0ljBQL1?C=Os9Br zR6*HqDWobLa8KV64<+ukJnI*mdb#bRGAuW>js1Pqp1-tQ1myVWlvW z(k3OM+;(lr2>*ZuaJmt_=Xt0=f-%;tZ`d$ZBIa0PvOK)|g;l~YxY$u1GJj!}(Di3l z38NpfPFF$H|4|9;e~~-=ZX0t^1;!lXp~PMMlR=eW8Ledu@(HmQS~I zmd_taQp#tyt*o#X^=dk;JihO!Cpl^^eltt|Rowk_6mw-@(@$*a zY4w0j#P)EVEB`+~&j5sKa7ZhCR@NhXkur?rTkkl=Cl3lCHfK z-)|>xWTWzSCi>azXV`S&a9p@gHmz$I(yeD*17ZG40*Q$CIs! z-^_scpRV{OvH=kB#fEMMmuAPlds@C>C4x$&k*5x+SSiqRNb!w#k^5TISicH?A&zGg zV;`h%{ta$WIhwfKCf{X-GbO_r4312T>5zhpMmk((QZ$p{DA!P0 z?`lz_YG?t&J4aqy&*#SM=N=s+qE9xC&ccA~MqXS4(uoYuKI6@Ebm0zpkJ!rx5&KX! zIBYNKyrZ2M9@J>4uoxR!1cAHE{0l{HVhlGSRL?m+zD*AJ7tjfJv?HT~tItL9&PA|) z5kM=f>$(y~s?tDbtYZURXgadg4LRfk{VPkq^#Eh~Ji?EZju2w9fj*d~bs1AeyE~$% zZ#$C9G1za`vcaxMDr3-huJV?Gj1m2f4J`{UrMFg^7BaSky6FZR)fj{)jp||2%P|4F zGyCnoo(lVST}kQ5?02A1MQ&+-&%UQc-ypZSMzs+1FshNXH^^t~4c6VlsCF!~ZjG_p z-9t)T`L7NKyenI7Y3E0EXjYEPxh8TF?-E~1_uew3%j4{S40xAYY`~LO8xF@$F**Fo zW#YHsBfP=YI|ODpHjOJZv=^@Zpn@z#pksnAlE7Bj&{F&6qxo ziMhztSrn15Q4GyKj zF3jzlrtps|$$tB%6JbBpW&bE8ASTyfm%U1GuE8D#N4W+&>zeE8Ux?I1Iy+uxSF66) z*wreC{J8qd*Tv&H%iix35K(W_b#NXs$eMxy&k~#;l?RPE&xQGV)$wmEng`!`JT%ltn2o!!?$d4Py|* zQ)GkZWh6<)SQ|5@&uC&ECnl?mrk7b|Q~^qPsef5(G_$nd)(fOUI}>cF__+XKAniUnV2jq zl~S~3Qx`WH701^_+^8CgZ*Rtps;88~7w8EW9)nPj5Pmg`4P8Hyr*hXty5-{+n9O=i zsWfi+M6lXYe^1eRO!M;%AoUy*?D*F#b-#~*oBA#{34Ba4O@?+QvmzRYuH;Ica=|E~ z{3R&_k-k1!_>5BOsPn9b%9BYcTNf6yY`q^2=gnc5XDj7A^}@Q2F?}u*Gl-ZhTN}<( z4SCK7N;R}x`*da*Kg(It$WcPWc?sQy*Z(LXgU@qRq9ECn60v^~OT{^NMHz!?`kXEy~}fCa#@f z(U_K%iP0<*-{OyB9Iv3n-AyLBoXg65UK1gZ$(4ztr(K!2OCgC&lsLmOQS~%s!Y_kz zB-O-RZQlg{fP(|!oa&n=Vm=#RYbWCQL=*1@Qo{r5e46E<2~f&I)M=K7V^Eax@GZ~7 zQgq}$@^JJNi^Y_OUh`QVmJWcs2T$4Jex8U-XJ5_6IY@H^`u*fF zmgpS!kX9wKC{0;wgaO3XWn@2uK{@4FYn-T6T~NjD3)|1W6zMb8>PG0svnCR_gFyOP z`Qsed1){d;0?!*r>OI!e$7A2IlC4t|0XwAwLyiv%2F zQDn+H&OeS~qWcw+cPj&rY2_A`4r)ePu3uSw;EjFZesFYu&qbeD3dQrTp-|uCNmew-Ql9lVZ+6@Kfpy#wLN|vqVM`j zOotn`KG$p~e^G6g)V~UPd*mEZy1zkq*OPx0^igI z-Iu!ORgdh_`mdU*Hr%B>Ts1;Hx=S0sv4l2e_3C_8zQCV(Q>{3@*|tAu%@m8eW83}} zYa3WRPi!Mo-LlSWk@01;f7S)5HKX8~^G8@~eMd-AWns=zSabvieKVJKF zV}+1cn@E$DMVc+z8^6)lYE4y&VG~35eLN(@jCs9DYp^N!V>hNmD+b+zI*Z>KpSChW zvu$8AFoM2>yBS}?^K8;$H*UuYW4M6;~nMI-!^Hxc9jX6 zxfb(v5llu$+@C$|zB0CAOvHVvdy0egreRB?H{;eB6Z|OB;PBt1H9k}vX;5rxKV4gwWJ!qM(eq?t~y{X3#Sd^^>#-W zunhQ974hGp6UF_Fd~0YUo`#M1lU`1^+Jz{jVC&PUuwc8|j9`~TEdlaQ$30}gQ72w& zu&r33iIAkfZk*9MlE){u1MU8fb?)mbgNnt4!HvrHUW&yxRWB?NjRP|3v$7~%c#Zf>~v z4B;f8J5I;fG-OZLF&9;-Z;#h#FLrcM->qaWGFCDdtJY~TJIjXU(IN0D!joKFgc0uI zcl>P`pGXxD4tFsOF*%YkGKY$}dr^;)wDo(ss%bj&kf5_PP0$+dEfVtqKcf;?E(X*Ks%P&=$)T`0L6{C7~5Jj{m; z?qNq0!^5wT?<(eD8+q%cYc+OnQ!6dgHXJCgVjP^itA1XFY)?m6lI@S6&23i? zH*61pERTLSWz_>BahTURR*%9fSfa{nY$)<;tRG1_%T%K!&>D;YC0}n~jr%In$nf>W zQp49O%I~WctRHo#TwbCBd%CD@OPPyjOPGtzE3~k^Wy5yILBNJMB^NhgguBQJGhEa} zIJ`R(5R>B?a*o09rLJAkuwHajAIC8lm*bd=dCO^iXgKa`2!tR!$;ELP;V#k}8ZLqm z4tLRm@_a-KKU6&LKjiJuQs&{x*UZDgubGG8%g966rC10AB09;#R@mSkl0Pv#SP%{O z&;lVjHX-5Y#6$A7VF`0_XfboKelc^=QDZJb$%TUGBp0zT!d>ibV7Pb!S?;0+4dBA1 z%tZ>hn;!=kRkZHAJ+y`gda1o)skBA}frZ5~2(^LDgTi(#ST@ID$vo$nx(Isb7U%NZ z9=5sX3HYmXaSs==-1BQndOL{ZD!8s+vtEu}#Cq9f5$k2)C9IdVVxV;#;Y+=2iH>t$ z!|EBnwn3KrdXC^6EimRtWHi-Nv&GCs*BIuaX$*7m{%hui zu^6)4#SKb-4GcP5jH0epjb$#HEo3gLEMzWzUCdncj)p)i!joJSL7d!0SRKQ~c*t@W z$0*MM81zHMntw$-@&$1IG+kXf;BWD4(bKYM?%JZQMLSrOxNaXfv0*+y9M_yMA7i!R zoW||%Xzl3X;%?gzxmNPnbkBxSgj>6{*G8NUSC8U;z-gQMZCmY+A45Y%x8*twN?~t+ zA6}m2GcIaz2!h<2HyjNYYCX^RYCDgYP&>tF?Jf=RypCr}z;?>#TFsPjwRDU&;)cyD zoPp;YX(hFjH>#6+MH6l7xlpxO6Yc)FK>xeba~qmBRr5-2q5eCSb$nkqGg3K%1sFb!1y~|n z8+<-gecVXfcs|hLr)|7kSUowJ^(%P-OM0_LOl?|IrWP}WsqOnzD|sV_4Ap>u|%L zc(9;obLQ-Mt&zEH|1`{HyDk1& z?p86iU0uz2t5RTpn$59(J&44FX4c|HLxyXO@01FRVkQK zGs|#hG0vo~KHV7?y0e6HclWt?dh%;TK7 zkTYjeac=0fSL5v(E&_nRXPjpW~K9SR}^H5jY6!Xlpc$VXXDL_tc_4k@uTG z2-|kt#y{wbu?`TU{LK)E#D>*-fQ<_N&{~0Awo93^dk}x&f84T(_1Nxu?Wgqa1#2Uolj*u z`+}x{E&%=PbhdMs9Vds+W;;_s-Ogn@GeKK}dV49#PS6lgTXMED3bg9^Z0AVO1)y=D zZ$S@$4#vOkNCTY%8u$^OFL^QBSr4>PO15(%Xpc+T&b6Set{_m*A*tEUhoCW6vz>Mi zT!VIB%XU@;y>cCnKwsX-c8&%0xs~l)3EJa!w(~IP%(QIhebCK!&_nz~`J;EUon=9< z-^+H|K%d>ub`Ayg|0&zK2(3l5CW8-wM>o{MA^Fqt?me*mU*b1^))C#El zN_{Y~U*Wv?YJDM{`(i0uxK_VFqBGa)Pl-;9*S&6lj@ZQImqDig7QONf$REJ@y={6+ zI=?~Z-|B<1xi6Nt^qu++In(4B z-)X;I`6k%~wrRiaMdz<@?$|HvV%2MQKwn6BZJbB_pzomb_Bg+DP`^OuV{yLxu>KVG z+*jiK_rrRDTR1<4bK8%4_uG~tUcnebT0xipsCOiu8-_Ujm_GRy^vmKr-*J64ozpY! zY9H5+(0N~+k2$X2rSmyB&pfWbqw_5|KX5`X0=w>K2tV<`hXd`f1ZtOX&xZwbVFHy+ zk>*u#z7~ZZia3;r0^ak~rup56=F5vUQK1rR4SwH*Z09pGU;Tv%5PvB6H4^n-Zd)n^ zBvr;k2#SIghx!Qyvn)OdiF)ZYOKJ7!NxeDI*{AivMD1tv#h@QeNy>JXhP+#T5B=vf zi=UpFW^q#|oz-uV)P!^TJEG%~^%8e1C90<&u2EP*@g?~~xOpNh6c2f%=d5kOlFBTu z(tk>``0F$7z~H)z`n)?Zv?fL0LGeqO?@V;?HGMj8_o|r7-LLa}w#IoUEXn1e>$2DFLq3Nx*=%PCGrt4p zQ@ZHEnq9B!>OD(oce+k|cSEmy557;|&|4Bl&$V;j)EE9_DN=yuLP0F|lPP|S?sX62 z-VE1>Ubpolq%;1uewTC>0ZUFJJE$qt@PjnH^nKtrfQQ`GTi%Ck%e(qu!iwQivF;vW zMG72%>>*qxrjY$odSzhleZlv7px-5(vJdokq_Ydy_@B7_W~k+upY$dVfWHD>HeDb5 z0J3e;^@W5r#HD0o2D4xA24s)oD#GkHcGIiew*?IH@mIabPf$t$*7qUn zG%NnG5B1)J`{MGl_YvVG)Wk>n4#K(u`{y?<`wB&$@3Hq(J0`in`BMGXgW8nA1C99KJUv0|_5dS{-E5UD1{KjHN3O=rGg_VCG;Eih? zU3vJSzf8CI9$K1iX_L=xJT@*po%4*R!l7I2pl8<6VYKO)c;+@e1JB&1XX=^T^hi58 zFt+>%=LADUM{VU{20shpL@}OgS5&lxJ=fE~@Ekk+*B6#*rDo8j4hIH}9f!pUDxMvY zdd=T0!QtYWOt^0F0~3@Ep{!sS*@5p$?1-<-sevEXm;8<|23h*a-z_CAmk(vYrp1z9 zKlzuX@FBlU%X_s!aC5F=JUEZHu(4>`yE(Zv9-L=9D35STXWCo6$zPVUK}O()9??9C zRhgledSwX+x?Il8;OBV|cb49c*oQ0p7u!>b*Jr-6vf-}SiUEr8e8Zf0pkh3wJ|`Ze*u)d)a^kpMNCgvNMsc18Ps@>qmqhYl zidGa4XfdngQHm>_3hTXJTbc*SDaInAsCW`+oPP4PC7_Qn;SBY)lhtNtbFmj^RUb1hrvJ*95zbCIw)Wt0Dgv6U#l+ z*-W1DpkH`n>24n>{1|}`#|hb+DEX%yB>C_BO-}!(g!~Li-XY}MoX9EfjyzdDlp3D; z!1>B17Fcm*fn=yC6v**FVW_;2Zz%A^0xuzOqvOT{Ed{J(GyBDqaA7}?G4O4(AB(8C z5+^y{CLGku;3n9Tjnm(R{7Ol_3@+G|xp)chEAZ_SzK?J_6!uDtH$vgCgoojpLkpkIt65dDuuHHC3LOWq%q^IkZ z-&?AyDVcib_m&#Hq;>EevzvQSA$1EDn_#J)#|vD%3ZshattZKXAwTi`g}?`$))!`5s<+JXW(UO54SOP9Fel~Plfy)oK?j>;fspNFqiR_EF8gy|zLYMAC z5kr1g$6n_x?O&{dIMa!$&LIN_#OgZw}-o-FOzi4 z6}bFPf?Wdt<0O}(?_+e-z@#So;*r>e6yurLkA=dX<5H|^o(=mhQQ@ln*1qn`5Ed#*ang(`JD=%3S54}Kp%!H+U>kPy~YU{ z`86pk1TMdy<)Faj$9~h-5Q;&5`#~Q5mYU*>)NGC~A0#Eev|*^gn@s|j-(rz0aQW%?cLgp#*Z;Y|yCib^^c|9pGQ0r%bG?lwf*5QJdx;tuvzV)# z7pkKK{^8XjoWED#^2=4O3tWDc$uoh=uQKt$eMqqMLvE^1P#M-JpvW&`XsYjXQv>uU zH`T*OegnuyEVaGH3sw1@F2@Bfza-+Ez~%RJ{4H?#)eDNg@gGZo)fZpyd?;bPD&mYv zKz`3oD}l=|i-{F@=3Sn^5Kffc0+-)ZlE55Vu5> zl@n#4z~vVKY!JBoo`W3%mtU~(nB$!l`3(!D@rxA&B)^{^T;TG1O!^93eqGQ~y_dTh z@Y!a;mfxjuM&R;0Ii3kzeo086{u1Vb8scksX+$S)23j$;Whj@bD~eQpE6qwSmB2`3 z25eDJ#j9LgZ*qAn@cQvQ=f=Bh0swSfmyEd@mhiCiz2(lhcR_(g&(zxZf9 zXI~WTkK1s+zlo`Phq0|z+yG&7yq758-YkF-8>tGk)EN_wHgv58fdC!fvSj-o={9>j( z0+-)1a-DD*39rXOV$S_T7d+L^3yRl1`0LjStG-%h=~9Qj2vV=P=k3wCRvqI_5QoYI zt9jh@a^=;{mSp{Wd9{X*ap%RL$+~9+z{Z^=gGTC~5p3LuF=%-`8n9JoT0p)#(;*{d`3z8@FddbW0^j_iVv!8B}rCTUJu5yIu@v z+)J3XOkW7x%eZ-l?f)t0duDQVB~w=`qxpt6gWu>)(DWAHL5zDc1+|k;0`&OGYLLM( zUfq|XpRcUeD3qAaOVps=-nv&6cr|X#q-N?(s=%)J(qX(p(3{(>0=t3}{x3J=!8qyQ zcnXf~UtO&V6XIr!&B+B1Gr^u!VM5%$qiRKaejK;*o zuCZe5HDD!H?AMNo{U5pScV=cU%aHfI@2%hE%>2%oQ)g%QE;#Fa=k2`WJv+2ubezVI zXhAe***TT!_;}Y6UGF(xR(F(KDmo_B{6*ge;z`X6`hg>Z|8&#EI!S1nNv-3&fJZzQ z{D^lsX*e-)WD3ecYy}HS(O4-8${N~Eho2N9GZnhqLulB|D(dm(Sc@5!sK*7?OZj>I zhj$PDTd~ygdY7yG{9cU#Kl`vpdT8LZ@EJ{Yy_qeg<-&Q|BwMFI@96O?)MIU2ZJ|}G z2U=gY8%i1l+E})mfwsUW2A`Jryob*R_)w}p#3vq~4y>sj;`jtDIzGjx6Fyz=>48sA ze9YrBG5ET4eEQ>K9s^`!Am|``hRFU<&|$Lu9q0(z9%(u}N&=%n$I3R5 z39>y&(#fDx@tKBC0zT7ON#8>GXP`9`A3A0+o4u~*im-jdS+xB&tKgNsprG!>yz+Fi zb!I*DgxJ2|KhyZn&-l+H%m%y}{bZSWB5WV9lHS#AfAW4`?^s)9&Yw=QEW-fS~(+X;S+Sy~m;|79gANmM< z$sPejO8igEL6R@`y#Qh*UR}yR+a-VqiTB3|LGq7eHTue#I9}(tLkpiPBq`Z+WJv?@ z+eAN9%xJ9)C@Jc>O5oupo>$wPCB$-;zwkSfBQqon{(x&3}EMJft!ZgNImzZ{3xmC0>sGfk1Htu zI3Dt!_#so&Z@B<&OZ+n#agh}QFe9GpClvj0Lf~d8TgV!ZO%?bEY4{&mni3NP9-<5T znxFKv_I|-IJ*AbGJZ+OKa9WP&h?e-XF`^$LOS2V*NPhee0)He8kCT(JAgxh2F3CA` z)*%OcwOBB|mW)0UzuaEnZKZ*Ipk!eET7jFBE>2Fy(zKxAFz3ovi67b^aPw^HE^)`I z-vq-{^iI~YjZB?c%Vu&i>P*PXK(ueO zlat7t)yt)#{xagvg+8rCrepHUfX)fQf{G4IFO=&aw+XD z4YZdvPFf=XbEP|pE~WHoyujy6d527C+!TpR12NL@i6nuWD{L{T|A#qz{nIp)5iK*} zcT@~$Ee!<8)FsK4%PfIQMqF>J5Hu&(L|L**X9RA_-;suw$|WBeMgDQrml4#NBnFtL z(|S1|s)xYMS-nu6e%|A9%FmX1@^2A%WjTk+$#v!CG=Yc9v+RNg>{Ch${URB1z)ZOw ze1A~j=91|pQ#z@wz|CtxQ8`!s{7K;Eq-!f3y}D80W`@3y@^c)$1;dQ&m|W35J|%E7 zb^GLOzqUi*rbGP^St$gt_p-pv({I%O1z#si7AJ3d9A>Jsq(^7uY&Yk`Q+a;(mYFcm zj_q=;l#`B{r{7FZkkF zPhvyEzC;c^wZGl+Hf;*=$bL9Jr7r)2>UwYxU6|9gJ#sMh1Hb$dC#+q|%ArtqD>T39 z;H2P3W}Kk)Q%Fc6{OJ!C&x!PD;x`B;~j zY)B7%d6M}@C*H!CCS>`~juyO}1@B?O%Ukfi7TjDbh&{-HqjvIu{oxiy9TNu~XTi<2 zg4ok6xLhRpsM!`=-ZXK1p#`tV5%D9LaEhN&(b>XSYZ*}Af^V?kA6f7n7QB!JPqE;$ zE%;Fj?)cooNVPDETkv!XUfP0ZSnz5V+-bqfSnx~>9wl&5|JN2qN6UavIf-b>gjsQ% z9duw}<=?D%2S36s_#hJmtzf~MS?~zWk*!F~OTn#Y88F>4AliZtwBWH8Txb-`cndDC zN1V~o#3}wBLYDvRVKUH@iyp`OTJQ*q{2&Y7#DWjE;A1WLI15gTsmMPX(=3b$mI1RZ z_zVla(1K5~;K>$TUI;mNtp&%bZXOP8gN0Gsgh6*$@LCo;#e&nBV;)B>_=hG4nrgul zEqFS|5kF0$_biMI%Ye!j+-boREO@2`Ctc?8+Jg5pL87+oIXBpyf8gF0##GAye+%Bp zf`?jgbGasVxCL)+k*{FEaW&!xw;y3)RIv=GXTjwy1m{Lu@OBpYSPS0Og2!8M+*G-b zjyC!2l+sq!4daZk447rX`&w{ZpWVkG3yymj_c7dpcW|Rv+TA$f$92_xOmj2DqdSu^ z+k$^#f}jg6IKR=5ykraB&?3Lqg0~>ttp5fJBib@xhXrqH!BZ?aZXDdlQ48M3jp8h@ z;JAfwAC7bjBft&gfvyEN@Aru9wBQ9T@|hOAx&?o2!5dj{P3LEUgP(qZ7KXQAa6HI@ z`&;l}3m$60Lo9f>1#e}+D_HQ}?)*a_!orwn8BouH53}IW7W_L49&5qJS@3uZ{;`Qu z{X1G1p(X>ghXwCz!TVb9o)&zN1utyDhg7JM9VKL6(i)LJ+ zHZ68?$`IX^8awfz_W>^Aio6N|1xMX zz~xtG8|3|E?!H5$e7+kH{UoJ7S?P~a`a_le0HxnY>322z4q5XKCLsH9NA%~i%mJnUSn1zU`d7E%QI6Gt^NPSJrGH52?@{_&mHv9A zzgp=p+vdm_!F)v^N$F2k`eT&-P^CXW>Gx6kT^$P0LFvaS{TQVmrSv0}epRJkR_Qy6 zDL|0Y&#(0DO8*^xw`48h3#I>9>EFrO|GezgoIu(0O8=DEk4=jD3+>n>`xzqjUk?e2 zO|%c&B(AbPu8aaD#?dwQfTWQBiOWZ>+{%{571851vESp0Rhkb_8(O(T?8K;b8_|qS zxHBYQY+_Vn;Lb&_T`p&Dm&un7PH9 zTEzq1;?t3K7(2?Hg;%X#W@m0DbF?dITgq0n3kz;batSd`aUzGoFVzr?^8Z%F;S4D&G&k1R<>n z`*&7G_4ZP3aMDa9*~4ztUD%wDTL;#7&NW*m{=Kz4xKKP*aW;2L|Md?G?;dO`$*O$P zCV#VM7$oQa6gKsfl0ozScDW{w+2SfNc`A(Y@)hQKs0Jca)uk3%=&)XR6mf(W^Jp&9NmkT zzP{S5Or)?WW={|36C*BU@)IHNGddBPOmmCZfns+deca-XO!6@ML})@D%M?z`WaHX} z>vNtmzg~rdTau)5D!l!HoDQu#8BTwU*hMZMJtdv?Q=I9aH3`g$#N-j}W7Rs3s8IEX zoTtJmXmESC7UP9*arS5D7@tzmK&cC7#k!QX&0tNt1nZL@@$+C{myp1z@tCJ|%VVC_8gB9H zcns=xeA8o7yaHO*v^pQ4FVkA(F;8oQM?9@hA93$TPK*h4!@7P+k%hI>^A$Dib z1D5r9ZNKWy>|6|fz;iMFKF>uR%91k09(>PpQ3N;c&XyDa&&8GdJQsU7GvEmxUONlB zqxB%v7_A%SH!2y~0 z-HfvcLKpek=wvf7_TpV0Ts+*&72LynZ1#xSe)hZB!L@R-;6CBrpWGu~V^Y|&Nri&* zQSeHLDNA{X&+z*rXHn=DA#UQs?2I%04-)e!ycG^jX0v()vD1AT`HlgDq8xRPrH(9B z^xiEp7Kat5LrP-I$=HO`u?ZJHFEB908FdGN2UmjqhYoTlF}h0Z!r1*8I*qTS>wJbm!tPX(ON`6>PxVyzauCgxoBelq;V+YK@+2s6mlwY39bWjGcewc+ zC&7ZnJS#^=!hye$3z3y+B$;Uck~0Gq6Y~%;`P$O?4ln#iKq;uUcX;9V+~9>jaF-W; z^j#`^;MUvRqGeitwTSEmEX8kNoJSC*P}%i1ul(5?yz>9Tdame*bOTYMSm;uiOXRk$p~uOd%E{3Bk??A5u@jqD75a*Hx(>%)3}5f&Uq zg37cyZSVxT@YvB=366^drrhKST)~+EXNdXE?H;?yR}q_$a}`-J+~VD6C=lNLeS@ze zFY&yS(*67fUqyOc28L>&H?U#J#O$-FaFHfN=fFHMV&`+2F|}>ArmscZ~Jt z@k;c=vpeT}WI|M;GS_L($C&|9#OzB6KaNS*-!$PhZjy^5FBmM&jNh-ouZai!h4sqRON`kdiikTbUL1ax z)#D1Q{!QT~S7)1bO~mg>-D zH&K<`=P=c}?<`*HMPFmcLATGHcr|6XNs;rxrR=gxY{jtRy2nLc)GM&56t%F>Z&~vG zoJsndXr!N#DO}o5IY{J1MQZ8BmCu$37YNQ()Lxfa+wThLS?MU_$EE#dnhF2Fn($dr zDU{p)Vhx6LXt5xP%el|oI>?H8@3!O& zIVl>~*#o*oj4$~x`^Bl;A#Y;VA|{XV*crqa$Zy{Ee<9-BcZT1* zRsNH#{nyRg#?usf{#2fwe$byQ zJN7izZCrJ~GUS}Becv=*`(dfP_LWJkl9%g~d0zZKhXW0vRpcctl^n2d;>>_s_}#P9 zkC;3!Kcw>7F9k}qU!2M|Oe_`Tb&7`Yuh2*3SLlCE@noEY*@weXoufH!W$k1mM>2Lz zB45fp>J4)tNR=?Ro+q2m1KeMU@8*@#C=2>WX?)H*~N~ff<_#7C(nHTuz=4by~&>} z)e#gpoQCH}R<#K{S=~Q_ndt~f_!KUxK*=%{$ z1fL{RPjX8+Zt)wA=gH~c6SfSbL?ovwNhaF;I5VILG5ZmdPZI4UpCqq)h&W%K;FILD zqckMPB-tk>Nd-9mACsi#3GR($@dz15zLbuIV&`BC66SnJj$aGiljKKMV_dNQ+er%B z)|z!47vc9MnU_(oKhC4xb&N+ni1MLKi82lzb%*Y-G!C(fsDpW_?61ZWGoS)7KO!cN z`u;H<^$q-foT_{M7?1k>!`!)a%M2cl|2BnnA^>jxN7Sv4ac?Y9YusF!8c^))f!!}V%f5x+9zgp9rKLH24| zc#UBP$gh|kiP04jVp8c*vilCXGHF)waeX+?hd=&)!r2gxi+rSUCH7668E~s3n0{{N z4+q$igdT-v0Hu6Phb*44zK^AsmHa%Y{adJzi7}U^iyWe-*>M^CYtK+8jZA?*_wVuh zc+0B&mSW10rw!kcj{!IEHyh4;$fC&8%0Jk$>6INrq5I({a!oJ|ChrH>Oab#kF@NG* z={xsIUfZ&g7os^a1wM%!6y*iZc36ICI*)K?BM^F$mal9D*6lkleb9bhkzR=nL6L+{KzL2Fu6Z;s&n8FkY;o_(LRT zGW-yZ)*;D6dkAL+#1eC`o9VNk)tRx)cM1NGj#9oTg}t0nys6I~Za0-~ZW24-w=Vcn z2<}a2x?d5KKF1fUqU5A|+R*o)GegLah8|GrtcEnniA$j;c5w1IMSL5%oopM4_{|OM z^xMx?Cv6BDzL$G}nV$2xWc*(C^~|#RvAt};%uGyIJwsPW_YJ?8dx8db8cE*qjjk*&sfH3X;Qd&?g+ewQF;iIX~)td4K1A zyr$u<9n62;boOpl9=2gowarx)dgamkZeq2UkJcY-WSf?Mt$(?Rl}_G~?@cWIwJQ#1 zpIiym}`58{%94ev9X*! zZ!H_SsdQA6m3VyK8Y&ZFu1p+rMH^BfG3E-a93i)OM80lSwN{z)d;|;{hlsZ?+3>e z|L;+jxc`+Jo2mF{h3WqyB*l4qHS_+ZXrXd2Lx1-|UWHLycUEBuDa0~2zNf!Q<_={f zb7!Zm<|!+^972r|m|}7llnRqsjZBl};i*^}2Ea$>jvsi+-jex4E8S-PTF%X+EaztW z{=m(w`W`~X;j&_82^0x4*BY8;^1vlwCXVX4a1}RmiA=6u!OfiB5UcO_o|{?zJvZ~- zD)#BdGEw`NLg-(NSImrnB4K8C1Jlf%Wu}?R@XI-DB{#E!OioN@1GaY77cAo@#w_C| zP|v*E%0w+E6PFN4BN?)ko9VoioAFq| zBe}X5LObB1VkQ!bgqh*>OfxH%m}c%#nrkL=GegK^lkeSi`Dh6@(_jfVb8|Vb%lbtS zS_n54GeO9qFw?QFX=XfJ644xiU(SNdxtaEmbe34g&G>I-`n^SLz|L~|tnb;W%~jgn zSO{(-_^0Uq9U6rGe*GEpeyq_Cg-diG@6#!OM8s-Yvk$ z3UE}hw;CFSJtr>BVtoyOZ^GUuaL~DODUati+5T-Yp8$Ut+{8}?H_>(}p8#Kx2`~7n zn3xD9!o*?x4+UZ3DP)C-NUGjgE9ejweywR*xCmKcp%|62?_zFY9a$T?kXuNa&n*mLZ8w$Ii!SCC5*hdx;G7b} zN6;ZGET~~x*f-C#V5efnFX9&FlC`b|w=i@bPg9q9JWZa9xQTz}LSQevQ%p335@BL& zglS?8+z~-MrsURJ$W4qSb1@5GqB5(p*_-+9?5USvG`k!}kQ}V0g)u#Ff!6rl2G-S~ zSW}NU8<6G6@LI8~W00^MQ{A*Y5VFGZ7D~Dc=5x)tFmR3?pjEX4{-h^%;-hG`d|OMs z=3E|i;ki8O{R?>1nX{o~6v9z#zlIKByJ0occJDc+?R9Y0`C>kgx-MlvpT`p$Hiw(A z&EY0~n$JzVo&|wk@LMsF0VTpj>8hrQ58#dn56-%rSLbmPB`DMfbGZq9HaBs97MXyd zCOg8T!pXw>@J_LC6gq^3yj4sKwIM4kjHI+5Vq~FZ9t!9TG+6SMFy=L#&9Mpg8?9~H z?5^1vO^Uh*#CgUA^@;WqXj2(C&teICi+Q$(QTBNMSRdb(gxgEEW;OOj>tD`gj$^U< zcQI_wzQ~AZ{NHb0`jWUHFTJKxl&cc05C>wJiOb?#JN}T=5XGIIH zdu}XqrA6zhvsu$KvA%vBJmO3*!Dd~ms$Xo*lJE z;mC+7jfL)oVXE$>iMe%mOn~k{mVUUjUSJw~cX)zNLq6XAyeZdRa60MsT^l8oh81RM z$ErqrBfGakRU7vba@$xnm5n%BR}aH}H1IvR5%>MQXs*BOH17MvhV0m}Nd1F`bB~7x z*PNDH$CJr!Kl@B{=eSb?u4_qSuIr~MT-TBMY|M$sh}rdp%OitSAIDC~t-rw}ca9f~ zXTc|r`fRDkb+2#4?wyR*H&0>}PsQpb>#@P7A|oEu6}l%CQgu(8lv{U;2`v58d-|>k zJbp(Vt~av*`D}Z_#vW_s`zTWAdl^9K)wf2num21UJ}@D-F2^``9;S@p^(x56+MCzs zIjBFL=fF{$Jx+~`h^;O3`ueMW`i;-6`}kO1r}3ltIoG=u_j7$+e$Fj%&^f24)ntih zA|n>p6ngvnsd@)Fa_g-!20n|^FTc<|tp?X!vJTgsXDrwKB7&7T7a6fPLg-Gi@%H((x$eQE`C74}x==bQFRc|3{baXAUe!kI=-f6uN18TlLs|Ig zVAkcrS3b9@@erQZFy{$ol3;!;ndJm?qF{~|%p}Qt z{0+DHtzdp7n4XfkMKHe<%+Cb#Y+2#$D8cL~m~92qSB`8ZnC}T@v|!edBYgz3j$l?7 z%#M7-1I>?4_F2VuTUJQzOP za<4M+5uTYu6+*?G7Y2fzVE>S+pJe~_f7GKteh!Kvgx}Cy#DBy}v{#k$qr*24Ns6j> z6}Lc(@PGh%#eE}de4~Zlw?CV7qg4R^&nZx1M-6Mdynk)L=8PMe9-A_sKXTCCb@*c$ zEn;w%D;@2K5m_#57NPYRndJ%v^%p0ZbzU1box<@ z2d#y_n@nIXALgeL*+h%yP{D zJ%0-kfOaiDKNcYqFgg>j(2g3|sf72aSRXjjl!(Bl7dU?3WO|A$(F-uf2< zL5sb^*#NpQ3j+f*?F?u*XdMk_8|deteL;`g@C^?1E$9Z&ZXPaII_ON$*PwaqE>}4I zt8xR-XwdJyFb?!I=rqupjl3}sjn6<+K@a<2Am~fbP~47{@^iWBfsO?22znZHEo$vw zz~vfl{GMSeZ;$^PJ{os2Y-MT;#Z0BAgz^Xk#V@0@=wXy8r-lI z*H4T#IuV^S))-0j3x~0o=oN>tlW3ud#wDUHCL3>wPMvCm-2~k`o%ms1_%k={MUv6! zmaT{#P1h`AB(Z(w8jFb*nnz+q?7F74HjKA7F`_owo=c3dTWHgUTpxUIG@$knw9{75 zaA-yQ@+#6=T)(s0SWNtLz^<$@c2fH}+O5_JJP<2a^e@IGlCArz@s?<{4Mx~)(6XD1 zPPa)PWEO8RMpAnVwYM9KseKOZ=D!;|sr?-7<-Z%3s2zw^?8|DSByCa?C@UW67ip-eP*BWmfC@+MCbiR*j==1qaAX< zXmHn7+^ZwngAN$os686(;|Gji@7cn9!%?kdk~?VpNW6n+e|E$;PUCN*J@bh1fZCo| z^tK%_d@;tW4B9V_7?r5q0_|^)8m+0_8|^yBjDFOfMEJ368*9t$f$PT7Hp)F!V(vZ3#6#nMdK~efOMny16!$bb}XZzWIhIgxD^)Q3MsxGShC;z zWqkeswfDSiOu-oa^<`rn(MMN|)4;tRK_=s>$Y(yBzL&0MxyoUzTVL1gd{zNJ1N`Dv zeh0y)ba`TqUb||vduS`=H3YH|*Nu@6VLRr!v6!&kz{Y17m!89Vouwy~IGPu@0m5=NJf z5_bs;^VA#B#{78CX#E&t`U89I6#83W&gQ>w%q4sa z@E;!-J4rV6fpLkje}R>L#Pt_A2id4cQh!rVW7H#CVXqc+X?bk4eu6>k9vl6hV9*R; zcc1W}`6Pe&#MngmIp8%j2`{cU%QW5+Ruor~vCo9;b4>1;&x~eIf%gV}{coe+Q^@}P zw=tctUw~D6&SeWsLj4=#N<%Zq^Od=bix`r9DZ4X4Gi#Z@$fPb+nGxKjaFCzZCp1T(Q~{zo|SUB_9{9 zLfUQ!%!U9iB=RttKC=aGznN)kL;tTo-eK<1W$wvkZo!4n_(2+%49ksQz%D?$ymCo;XvW| zLHB-iVAk`)+o+Lc3y+o?;NTj;4=1fwIOJfy!w2<4=m(DQN`j)q{HSNl$+A_q4L9~@ z*-F^rx8HzHn~rUuo9aPZL-p5sO>=WHIY8Uk{Iiy1&D@;K+>DHH%3}I`qqT>A*tWq4 z@YF*Jn_-y4iFzQYc%vz?hx66J$|Sb8R?qkbY+JaI;Hkd{l19Su@8uK}y8N_g!)C{> z&t|HvLLPKGlwn0g+XHtyW&~EQ2X+h0IBCv?Y>o$Jo4Fl!HcGw*Y8z6yeD)+H0S_%m z8)wY1>p?w(-9^tiGDI_Xh|7tGYUY02Iq||;tn0r#3uDh-2i5V=ifC%BXuJnbwQ#uu zMoxXjw0IArpO@a!7Hw?wLVgFuSp{(UKv&1+ejAJ%V80)4*(rnL=XSuuA5lbt7pKln=L;O@S(v<elIBOMK*fV`qLitZb*NU6*`y zcijBACFX%17g;eA5GQeUv)kbkf14uY8wjE$OI*G#pt5E%j!K5QTlQm#FWF^n8-&O7y@-x#5?43Z z{ZQiS_P{+QKFQcvKo9w>O)}TQA68I{?&isi`u2hy63^aYUW_{+adk6bde}sIdLJ|@ z`J1 z{+767pP>in)dJM5_eU840l1@EhHE3~Rkw#WcWGAN?r>SktJ_cOxCtaZ>bCRcC9ZD5 z{sG4|mM2d@&u&siePe_};_9m^mP_2aKQblzpv2V;;_=_b@wN>wwm(lujp}%mMt;g| z?cKZDcaXTcH~Z%_$}v)M)z=6lN?hILf1||b^cJ(q+{^la#J$G}+}zaryu{Uw+w+O4 z2j_Y#M>S&L8$=;TYdJC0cSCfNxcX{^MG{wEKCxTkc-I3z9txtJleqe-hqoNpSaUs~ zSUx;Xq@>bD^>mCDM5{tLd09ACN~o_%cuu7;q62mBuIgJaew0JhUGz6dTz!$jHHoWx z)88kYoUp$`D}Y)(1MuaI99G{sQd{Ec3pIvGywrISS%eI5fyC9fIjrTEGTUxJZVQsd ziK7sH?M}AUS5MTCxcU}=wh~wOOP?ljbBB0yE-{I#JJY8MyrrgYO`kVdIHYduUQy!e ziyq<#r!>ZOlM?EC1soDr-%s$P#MKujoHaETeuY*kBuBlzdl^kb@MX0;Cxyf1oK)Y^ z@sW@k$w}N&d?Tks&siy|l`4z2MdIqKJkCg5eJ{jQ;NcW+vAnpUCylw@sY5uIcuz`v z@tH7Yp7@`-C8kJ;LT!Y^U3uM`XG+*p%vPT?DXYGb;)=x8H{jfnxcW+sym&N1ey>Xw zHop->s{ouw*0ZjZP+!i|P2%cHJ(fybeGkhOiK}mv2sXwS))NnP4`cbjj^2E9z&wwy%uPJ-m#yb@XIg ziqWdBUOm8k!ei2fMgqa+6BLtr8^;KaFDtw>X(_{}o?hL@e4sMiXj)IN>r=11kg8{l zN4KE)_{XG9Z{v79eXLD0TGhwk@RmY4+!$XU(&qCPlV;kDlAL#nauNUUimI7@5n-C+sp`pjUFDABzFroYMmwAIXV* zY)ohb74k7l>{B7Qg9~Pm3iInlrr`J+K2fNJzx?Xs|Br-)<|sWhAY8J-B`bonl8F^B zS@DvUD$GRb;XWqRhRu16q%;PUET!rhts3ifebar!7o9)CjOmT_I=+j`h< Date: Thu, 16 May 2024 17:23:38 -0300 Subject: [PATCH 3/4] add broadcasted cuda --- norch/csrc/cuda.cu | 63 +++++++++++++++++++++++++++++++++++++++++++ norch/csrc/cuda.h | 5 +++- norch/csrc/tensor.cpp | 25 ++++++++++------- 3 files changed, 83 insertions(+), 10 deletions(-) diff --git a/norch/csrc/cuda.cu b/norch/csrc/cuda.cu index beae140..8922346 100644 --- a/norch/csrc/cuda.cu +++ b/norch/csrc/cuda.cu @@ -58,6 +58,69 @@ __host__ void add_tensor_cuda(Tensor* tensor1, Tensor* tensor2, float* result_da cudaDeviceSynchronize(); } +__global__ void add_broadcasted_tensor_cuda_kernel(float* data1, float* data2, float* result_data, int* shape1, int* shape2, int* broadcasted_shape, int ndim1, int ndim2, int size) { + int i = blockIdx.x * blockDim.x + threadIdx.x; + if (i >= size) return; + + int idx1 = 0, idx2 = 0; + int stride1 = 1, stride2 = 1; + int linear_idx = i; + + for (int j = max(ndim1, ndim2) - 1; j >= 0; j--) { + int dim1 = j < ndim1 ? shape1[ndim1 - 1 - j] : 1; + int dim2 = j < ndim2 ? shape2[ndim2 - 1 - j] : 1; + int broadcasted_dim = broadcasted_shape[j]; + + int pos = linear_idx % broadcasted_dim; + linear_idx /= broadcasted_dim; + + if (dim1 > 1) { + idx1 += pos * stride1; + } + if (dim2 > 1) { + idx2 += pos * stride2; + } + + stride1 *= dim1; + stride2 *= dim2; + } + + result_data[i] = data1[idx1] + data2[idx2]; +} + +__host__ void add_broadcasted_tensor_cuda(Tensor* tensor1, Tensor* tensor2, float* result_data, int* broadcasted_shape) { + int size = tensor1->size; + + // Copy the shapes to device memory + int* d_shape1; + int* d_shape2; + int* d_broadcasted_shape; + int ndim1 = tensor1->ndim; + int ndim2 = tensor2->ndim; + + cudaMalloc((void**)&d_shape1, ndim1 * sizeof(int)); + cudaMalloc((void**)&d_shape2, ndim2 * sizeof(int)); + cudaMalloc((void**)&d_broadcasted_shape, max(ndim1, ndim2) * sizeof(int)); + + cudaMemcpy(d_shape1, tensor1->shape, ndim1 * sizeof(int), cudaMemcpyHostToDevice); + cudaMemcpy(d_shape2, tensor2->shape, ndim2 * sizeof(int), cudaMemcpyHostToDevice); + cudaMemcpy(d_broadcasted_shape, broadcasted_shape, max(ndim1, ndim2) * sizeof(int), cudaMemcpyHostToDevice); + + int number_of_blocks = (size + THREADS_PER_BLOCK - 1) / THREADS_PER_BLOCK; + add_broadcasted_tensor_cuda_kernel<<>>(tensor1->data, tensor2->data, result_data, d_shape1, d_shape2, d_broadcasted_shape, ndim1, ndim2, size); + + cudaError_t error = cudaGetLastError(); + if (error != cudaSuccess) { + printf("CUDA error: %s\n", cudaGetErrorString(error)); + exit(-1); + } + + cudaDeviceSynchronize(); + + cudaFree(d_shape1); + cudaFree(d_shape2); + cudaFree(d_broadcasted_shape); +} __global__ void sum_tensor_cuda_kernel(float* data, float* result_data, int size) { __shared__ float partial_sum[THREADS_PER_BLOCK * sizeof(float)]; diff --git a/norch/csrc/cuda.h b/norch/csrc/cuda.h index c92cfb1..aeafc4e 100644 --- a/norch/csrc/cuda.h +++ b/norch/csrc/cuda.h @@ -6,7 +6,10 @@ __global__ void add_tensor_cuda_kernel(float* data1, float* data2, float* result_data, int size); __host__ void add_tensor_cuda(Tensor* tensor1, Tensor* tensor2, float* result_data); - + + __global__ void add_broadcasted_tensor_cuda_kernel(float* data1, float* data2, float* result_data, int* shape1, int* shape2, int* broadcasted_shape, int ndim1, int ndim2, int size); + __host__ void add_broadcasted_tensor_cuda(Tensor* tensor1, Tensor* tensor2, float* result_data, int* broadcasted_shape); + __global__ void sum_tensor_cuda_kernel(float* data, float* result_data); __host__ void sum_tensor_cuda(Tensor* tensor, float* result_data); diff --git a/norch/csrc/tensor.cpp b/norch/csrc/tensor.cpp index ad56c94..4118e95 100644 --- a/norch/csrc/tensor.cpp +++ b/norch/csrc/tensor.cpp @@ -149,16 +149,23 @@ extern "C" { 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); + if (strcmp(tensor1->device, "cuda") == 0) { + + float* result_data; + cudaMalloc((void **)&result_data, tensor1->size * sizeof(float)); + add_broadcasted_tensor_cuda(tensor1, tensor2, result_data); + return create_tensor(result_data, shape, ndim, device); + } + else { + float* result_data = (float*)malloc(tensor1->size * sizeof(float)); + if (result_data == NULL) { + fprintf(stderr, "Memory allocation failed\n"); + exit(1); + } + + add_broadcasted_tensor_cpu(tensor1, tensor2, result_data, broadcasted_shape); + return create_tensor(result_data, broadcasted_shape, max_ndim, tensor1->device); } - - add_broadcasted_tensor_cpu(tensor1, tensor2, result_data, broadcasted_shape); - - return create_tensor(result_data, broadcasted_shape, max_ndim, tensor1->device); } Tensor* sum_tensor(Tensor* tensor, int axis) { From 0d789aa4169e91691df517b5a77259c4815ffaeb Mon Sep 17 00:00:00 2001 From: lucasdelimanogueira Date: Thu, 16 May 2024 17:25:16 -0300 Subject: [PATCH 4/4] add broadcasted operation cuda --- build/cuda.cu.o | Bin 100448 -> 114816 bytes build/tensor.o | Bin 42040 -> 42400 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/build/cuda.cu.o b/build/cuda.cu.o index 873464451c193e2adf31fcc40a8e33f8b023fd65..87633ae3a2723d424144d14593cd6f12a57de6d5 100644 GIT binary patch literal 114816 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 UuW9^_k1W+kq|AZx*N*@H0?(mB?*IS*