From 31be051028fda68df97af1f093c2b0580859a410 Mon Sep 17 00:00:00 2001 From: lucasdelimanogueira Date: Thu, 2 May 2024 19:13:05 -0300 Subject: [PATCH 1/7] batched matmul 2D and 3D tensors --- build/cpu.o | Bin 4232 -> 4776 bytes build/cuda.cu.o | Bin 58328 -> 57656 bytes build/libtensor.so | Bin 86112 -> 86064 bytes build/tensor.o | Bin 23736 -> 24984 bytes norch/__pycache__/__init__.cpython-39.pyc | Bin 0 -> 193 bytes norch/__pycache__/tensor.cpython-38.pyc | Bin 8960 -> 9138 bytes norch/__pycache__/tensor.cpython-39.pyc | Bin 2180 -> 8960 bytes .../__pycache__/functions.cpython-39.pyc | Bin 0 -> 3473 bytes norch/csrc/cpu.cpp | 20 ++++++ norch/csrc/cpu.h | 1 + norch/csrc/cuda.cu | 3 +- norch/csrc/tensor.cpp | 66 +++++++++++++++++- norch/tensor.py | 40 +++++++---- test.py | 22 +++++- 14 files changed, 134 insertions(+), 18 deletions(-) create mode 100644 norch/__pycache__/__init__.cpython-39.pyc create mode 100644 norch/autograd/__pycache__/functions.cpython-39.pyc diff --git a/build/cpu.o b/build/cpu.o index e34690093b3e826c7c79167354e0ba47272fffe6..d681b7686f31c09521697ef680103c12a50ebd06 100644 GIT binary patch delta 1057 zcmZuuO=uHA6rR~O*(B{|Hr0BNQj^+1Dkvyu+e--Oz#jDAL8u_~Csk5GsFLETrVuNx zOQ14}y$GcTX-`pt(1U2xLz0V-V-Hd) zUWq6X^5NWYSIRIKcMWr)Y?!x7hDFPU71NFMcDJRsMIH;0?2bu~0Ndpi|IHp3X$65f zjTRcG6_Odl2o-5nW<)z=swC5oQ3_J^_9mDO)5d9?WDWqoM}BNKNPr#|X|tWdmI!4{ zl34;==;D%Xevu_vS~c?)ZQ_!#YUKA71D6{__XvHu1>&+PdSvDu!D2SFHO+!W>-g~R zM${m;^FVOput6rk0aa-rug$euEt`xUn>+t-*%Iowgv%fzb8=a3Q4(SXDUbzF8m85L z{%W<-w2EuHwo}2ikGWXaqLTaU^5O6RG=AdEV4Ltu5%ufOl&hM%YYq3R9ux%V8~f@$ z8$vt_mf(j|rA+c7#94wYpq{}ob`j1gb`#E}+(Y#Z4%@U)z~8D5ShC&VfISfxas#o> zUaBWt1CEypfyZmlyF`&a6x^u9UrYSDrS>I}0yqDh zWxHV@HwSkX8}7iJ#jbVW&SJA2xU<+(f%p6wP;j#sy?e@#%I<4dlqrp^Yf)uJh5vkt z9cdBA9rH(&S(VNBqe?<$>u|l2HIP_U*$|0(w^X5hjm?o!?}{d(Alrm!!YiT}t3kBd TBcc);(MNsn{US;t&@lKLLZl3j delta 560 zcmZ3X+Mzf>gNcK8qm~Nu=I<=|Oq)~Lxfxj%7#JA#OrFZ2%=Ca^@-7ZJMuy2ZIpi4? zCjSJI4wEH0wBhoym!u!jta+CEg%u6I5aPz&hDU(2i4p4dRW4$(@4coE_W{9>?U9K;8s) f2v1`&r;s`44o(Pf?qp9OZvqd5R{}PF4nGe7VJuq1 diff --git a/build/cuda.cu.o b/build/cuda.cu.o index 004bd903204a106adbc3e9f218ad9553aeedc80a..069d2813db595e0dd51833ecfa76af915e7acffc 100644 GIT binary patch delta 13227 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 delta 13856 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 Kn3y*l>;DfVTV>e* delta 20332 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 diff --git a/build/tensor.o b/build/tensor.o index 9a674298699400a70765c9f6a03601fee1f5a314..3dbd4caff2340dc14b78f7f8f694863588229b57 100644 GIT binary patch literal 24984 zcmeI34RBOdmd9Twh!GLu$2yJzHjZdih)D>UVZgy@bUp_6n-H0fmeLq1AI zsi0FmO{$pnqg=+a*wroB9W6(9$8i<4`Ow4_-K;Vi9d;%<9~(C~#(_~--F45o@7(VH zyZs&zaAtO@xK*KF|L(p2d+xdC-goco#~t><`2~T1rBlGV(#n0))UwW6mblAC>_(}g=7fSs))U~%Nlv>*#N+tVJb-O~TnoOws>s)Y<|9Nqyz6z!61EH?92dw0@ zQ2GSU3#F}4YTL74rOOw%X;(c4N+Fb{dg(f9pja;ZLaADHovz!Jsx2X!38i|R!d;m_ z_Byp)RY=vAQM(x{afwsEs*L2Q##`Bf)Iv|yRBo}yRx(3JWa1Z;RPnSuINRQ}mMYl? z(zR3RYv_Sc_t?8gkUDAig#x{4Yy1;^oS&+l+GP(0hF(qEyQtK*fr6|VS$m7b(4x>? znGt%c$KK2RAn~rjK*}EOT03m5x=QP%>xM&(Z-lnJUl0mxPuqJ_1!;SjZ9M~Q?Mqwf zy1nC{*q*ZYcC`-&hMvQLab0tNt4dNY3w(woJ^0spC!}w ze)jJ|=|*w7Zhy8LWUYsi)Bjoa{Fa-7{EP z2ZJ;4T$=_XJ80dN#i4F{@4pmK$!AAF@u7*14i*md?HgZA^Ym1EFJ0Jsslsfe%*~-Im2O_43;pYl#rhjv##WKB zy<}|07$U0Cn|2lj9-Hln%ZOysAzmh&jO^NzwImmCFXFP338iW2plVLMX4i|mGKrZi z8cK&Gn~NQ>tjKvSSoQ#|R0CFmCoC0Htq-_Ys$QOO_U^R3+gv?p)#+M0XeF19aP#YVU5#J_t^W`cv}7kLxF##g`=R$?hAZyDXrtuw#PKAVJOB_Sn0fJJO#fV9Bb%9<{S^?4vtRcHXNckXBm0 zu^hn=^YCUD0jlCTyzMXYy6oHp>Hd54V`{YKH=Z>-o?{O^p2wF-*km1FCY?2qZ!pJ~ zNxx}zB+KOSX?1*BsfFIPYdk)!XoGbu(~3_lJCAA$@@KMbURxEw1 zXOPY6E@#oPW10S@^7sVjYQa&2(-I^mPpur0iWDkDlb@`G-C{Zk4^q z7P5vOP|dQps>#4Tq{*-q&X3NQ+=*=qw;NaBpY$@z7j?JOVuGoJmKr zi?*eD>D<+l&FnWCPN?Nram zc6QmlfuT3k_D;V8`4K%##0L+~faf1moHq2sx^8-~n2Rww2=>vsOAer5cAY{Q)AZj( zXFqzD;6%~TDldDF;k4q>aIVo2oj_}8Wz#SbJoYj zbTyFTf4MXCSx3*YwvXZmEV_)aqI6YJs^I_0G;=(ERMU(GoBH}Em}dD6`%SYWc`$H% ztL5B}T+aiKZ?!DflXhN^>B(0zld9XAzb5xOtD)!ecRJ~0CU-N=X?-cXZGI$dK0eGg>b@Bt$tp3jLI3mm z3FFH?i+!1ol2`o^!Xo?g#PP7eU$%~ih5TwYqOed~_x#nu*=NbggSPMRhKB4@)eoLj zOx+^fi>Un!9pzGXAHPOnye{#Fe3GAiw}bZBe0QQF^K83s?G-d7xjX#irt7}~m(Zz7 zzfVDDOZ6ppw#@y=xGOO90@vhMBIt)(N5kWXD9Yhq$#N$=_gS8QXXI^X_Q3*uCB%lHz(WLR_nahXmdxbT~)inT9j;Wh{S>&&B3PDcB)HS z@hgH;NJ(0RNwUMvmW30t3;ZC}|$(qt+O$}N%TaC%4u(dc6ZOU00OmqaB zpiX0Fl7oPgV`V(po{T4gE#ccD!9+_W7!S8cf>95H$ev(0+Qc7ZdNAD7)XJUKy%n8? zNRS+n70Na3)FrDA)oz@71Pz4~!PaO~WL18n$83K**^r2Z8=Wp3&L4-f%O!SfevPz6 zC3my2BVRcPD{b24r-07Q)`Va zDu5c3u^4$G$idHZgM&&$skLjWtFH)_)HNidiDYnAX=Q2IwDP3-R{oueveL53(u#{5 z?s(0z_}A=W`r}8T*DR{D=+&bPGk);E=?v$?3aq)#3aly)oHO>sqK&kzpFo`dIK9E| zE7{|U?=Gl5Wpv>y1yn@k%~83Q^$CCK{DKcTTjej6{KsASk7V<2m;4*p7+t?`QK8m< zQ1biun32uz3F!Q-hpE5kF!`TL{>85TP0sdj0=G-)U6+0Tp0#g|>V{>=7oU$%b_O8!?|_KnNhxAidjdnEr{SN$_pebq6Kf4Ish>*FsxvM6Rm(8w&z zMw2_EP(`1c@wY-1jb8l3e5lG(KzXD>>m(1#`lIvsSR$u^{VJx3olSo{Kg?7{z>D)+ zeqMZz53ly&-|*qr`ta+0_`mt^n~8IObwAY{CD!ayzTJnf^5H4stl!JAPf5*j`n-q! zy!`V+AHIV)>m+$mqNLUW`h1=Kyma33;qUqI0t#6#o%4uuySpUh)EYw?(|pP=@Zl|@ z^Pq&HwmA^Q?IFF(h#P()7$;@+!YWj=ffarVzi=Q%oR zZKunKPx+J&w`5b%*x6}0TlRW~SoPN|yms!@3+u0)KYy{kq<+cOa~In6R%bF1x7yXV z--;)iBC(j&yfW6Bh**(TtqDT0wn&se8ar28DPiE!hs z^^GmJ*7M21N_5ma`(>;C#`1F7sn-+X3bmIlagH2{6HpnQ$tDB zMpCUAxe_kL#bx!i&D>li7RV_(`SE1CmS?TpSC^IuVQx-{GHH|SR?%NwDmjaCYY$AD+Tu+G`<&cVUk5V~#r%?G! z+V_kn%gCk$8Pu>#dQTVnw+L^F=Gl^2@k%*F<6+dBPQW z)I+)4qmWCQj+W7QX9q>6UP^APC^w;pa9MsCmoBe#lbq#_&o65C_&Gn}q4YK3w9Hw2 z>(qQ2@Kb+nm zD39a#nNfbOlve{K{lfCaY#=3Vrykd{g|i<{r$6myy}!`qJGnBYN}uxch3oR`oZ?ok zPx%{+^4(HC>{EWDQT~1@zsaZkV@CPEk@8Rbl;2^Le^AQvK8=$(j~3Iug%fAUN(KZqCP-4EfJfof0G8TlM{q%f1V-p^CICahwV-Wj_p-yQ1U?CPCGau87XZicx>>l{--K}8Up-!{K?nWW1swak z2{<3YwEa&4M>}5zj_cK@z%gzMXs}F!IbCb z+D<(mPZG{{VmwR(j`MLI@bjsTUO#UF&aTot1{}w0y>PR?KM=0%l&{ui&_RFxBXI2R zHsDjho_^qH=ZC;?KF(sJDVcUw3)gn?^Hxr^!r7lVE;j;4JCnfC{~Lvy?QRmT+tu^& zQP9D5p9GHWZUc_<@ipLlsmJjn;5Z-0@MNRJ{l)T=gq!xy5U%YPw_8_$4vz0U;AsB> zAN>X&{S}~t`rihQ`a?eYpBeh=W!#Hcl#)5_rvXR(zY?zfpy%UqD39^59yrd&9{|6Q z+SlXt6mX35SAgSq{YlX#?=MPnf?8$aI?RYgq!^>0gnBh z3;YslN89-=;Am$QIL6g)gqwDLB3#?Khc74<^1}#9=6pW|INDhP9Q|J{+-$c-xNcXk z^EZMHuJcX6vE2l49wP0ZJAvbP{T*=bx-S0;a4i2H!cF`43)lARb>krDU_2Mf3n=Eg zF-EwlKUuh`e*x&Aei?A|&qN*!O585?>r&xnyYq#c?JfWvY_|?Lw%cUr=y}=(<@r+k ze*7Vba~HLplZBh@ULst#tLN!V(7|@+0>^f* z1CH}_8E_o0JAvaoeE>L?e@wV({|@2WemzfnK?le84d7`1J3jiuKKj209n}8Cf*9H~qN*bg;ko1IPaU1Mthh z&J1w0^QXWuenwAXFXYG1X~3~xmB2B6t_6r@!yTZ5enk-V3t?R>~_msKpB;|Jra5;(g&8$ZBj0$&Ck$14dO{rO$travDNuI<$O zmWM$H`};U>>~9A6EU@!!;ArPw;22jEgH)N4xh`E4R9JEB*8<=eSIxk&{2Jk=AHFZ# z^uzt2gMQcy9R2X9kNyij`a3`e^S@e_y!ihb_Vj$R_@2TKnN~&_O@^1UUNP1>vUtPlXp4`tO1c>i-Hj>d*fg z2~g5HI<6K8H{&V_9OG&o@GD7A$JGPCalC#A9R2ycaI?R=g=;&tKi>fz?C&puV}CyZ zeihhx%K7XCCw|b*^MGSq1yyOsZ)}rJRdT_M|MdSGSZ;9rzW<#D*YEFdHn@JjK4WnG zzWji}_51JiinB`E9{oOh(BS(0^eThv_sy3ZT)$U-r@{4m;+qYw-}}xOT))RXU~v6j zwpAKm-JS?H&}Sm%e75MTSfnjnnux4QSfx$jMA#~Ah{vtcScmh4{y!T3UpT9j{$p6A zl>X1wH1)=`d|wewmUhNEIwP^fYO2FZk(T=A82txE@#L|61gScANnQiVidD%~iNux8 zknZcR7H{8q?p0-pb1_`$e1`bP3QGKQCD)ao`7JpY!$#I8Cx8H3DYx{Ls-b--(G7aSO_tI~+50kcEf6k>$eU0TNm*BVDwORH$$~uw$ zO#4fuelS;6U77aZLX;E6VzvhMj literal 23736 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 S3$-6!=QjEdwB<{){r>{T8`z5g diff --git a/norch/__pycache__/__init__.cpython-39.pyc b/norch/__pycache__/__init__.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..52180c07ced3f255bc8436730057f5d2068c82c2 GIT binary patch literal 193 zcmYe~<>g`kg4Q^LGfuMShx0Q9OD1Mada@C18Ofkp7hnMa)17O#HIe&&bbB)z8Vv(|5^FF3nBN zE6Fd`FG@`=N=+Al}pP83g5+AQuP>R#ho(f;VU(oEpcg4$f6+B*smp9tGaTAaQ2&Z5 zXZ6WO;g$rl!xu% zn*VT3`wQ2^S^sctkM}Pp9+p>sfy6(Yh>6YNW2lTENEqvAD(7>e-9@;D>WH{(nG6S( z-WXmo$D1W`J~k!~V+&vU1$#0ZBDJk5?W7uL5Jxk7-Jnxtzx7_M>ofxT&AOEZSiHH9PXc6`iF?S%hlB(n q(}T~^tUAn5E{E<#ukdmu$HhM1luyY%nNCi?kUU9tL0(=a*FFGA{e_GG delta 425 zcmX|7%}xR_5bktgsVut^0xHNVuwJ-Ij3#RIq&H(U#sdd}6i5~jQmV#ei9{ZuF90uK zBD?|zZ(ckYpT;R9G?{OHzHesQPA`WS&Yf*X37)<3e&eU~>2$W=zAz1lPdK!Uelmb% zB(f4X9l<*wN4b$E$WR_ila?WlkPB;08sm@*PgcH3rRhg}R#{sy%RH*QqRw5nV0Wsr^VF`$`eVN(h%mcQIng)*W$9kgMs|)!m d>T2k1D$6@eZLt(fP!K5;6iwl1aYNmE<$pX~UbO%K diff --git a/norch/__pycache__/tensor.cpython-39.pyc b/norch/__pycache__/tensor.cpython-39.pyc index 16c079804a3e136ea94de87632d351b1e122fa07..02bd84843a7bcf29b79937162d2b6ac1458df245 100644 GIT binary patch literal 8960 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 b?mcBMiTkepUmM?mRE&t^&;L8ZT=jkr{G*%h literal 2180 zcmZuyOOG2x5bo}Iu3y<$n{7 zFt`t2@ihoZhE$Lt6I41IS2|N~OUF#GdgR-Yb76#9{+LbNVIVv_#{>@!WLD(LxFXiE z2@0(eAq(RbNAX-5HxtQh5QQe>Jd0=|BR)>^SQ~G|lT3q=aUxSu@E1f~f(Wd5^=1DkpUHljX8nixXfczS&Wpa1BPC-k z`TRuZYIM{e=XoFcM|sxQ*5y0%6UD%agMeTrLe`=9hX2_4x6ni7`>1>u#5sC`JtKg- zBV1@96T*kq6M+b!^~H{8KpTjrXh9o_HsIDVeg)eIZJs{pNC@8p_=-P3lw?Cnx}`s| z6_WFSMBWoy*g0sRK*ZE4+WVsF}< zI3=07(-v>r`3_pN<4f3XS|9_|t1N+i_8iZy$6LCE{d`vth=>iASMJ>DA1;zq^wZ?9 zhPcS1%O)77v4#ob%@w3kA=buy@bK|te5}>`geKhpyJEvo(oAsN6}-Ow0qE*5J(lIVogyBdV{R#gsq&CJ|sU~U%90VZD-|` zY(q;(2_?t3kM|*E&X`#s6$L91Q&*ueemtMcOhmpyCx^`pB9(%tNuh^3h%3i?XE7TF z#o`bbjGJgVJHH_|WYvZJ@4{DL$OK~BqanN|?#*I7I_l{o*~`uppvFLkk~}M-wuQ~o$26YC=|VnIDp!_s z6`%0NSyHJh&@xL+VNV_6y5uoN?-zedM%; zG*{fkS>awIpOY0mz75RxY_D6=jkCoP;SUV4+24G%We`{ZZCr3uFNa~+3Y{>tD*%rzqdQNuT8#8UNm~l-+W(m|;oa)5dk-ToFykTX GhW`OZM%JSM diff --git a/norch/autograd/__pycache__/functions.cpython-39.pyc b/norch/autograd/__pycache__/functions.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7e8e38c57c1720e26c5a52289570b28c992e26bd GIT binary patch literal 3473 zcmb_e%Z}SN6eT4;H1@obxXGli1OW=vi^L7uMGFMQv}w>)21VV~pn#x=@{Ao@aw!?p zF`QNMA<5Feq+QWfexa+LL)o%Du^S<-2ITP467Rj|@LbZ{+p7sY-M=1ozOD%IH;v`T zhH;D*C+L0_N+|gX?WJ`}%ThKh8Yq7 z!`fAQu=Ze8VC|~|SO>7G>aZ=E*L-+hc`R7RXz{1$0&yypIJJ~i)+=#pD_fQDAF<%u zN?QLxsUJQ6`Gu#I&t&Eg$6V+!TD*^LA}7|FH4!e7Y>TNpnaZ@>4Tqy-YNw?*=yy{2 zXDTnJLhs=9f1b3?qe0N>_rumtkv|#)VG_kH9r!x%lE58aCXx2fTb(Fsg=XZ9lITo( zs?`~Ve$tJ?_`&cpbzHX_b`#fSFfltJ$Bm_^AIx9y&5wKm565gKd$-o8yngnJ zuG2TcTyjOQH2rCbjx8>sbEIRN86U>V!vv1e3enphJ^K)PGnBXoG?QNn*F?%Z78GRq`?0+a zXV`g?!kJJ$P~&VDHZ4u2(@JcXYuaW%>MG{+N9;@zi%f|6A)3iVNJox8ekYIu=o3t! zFM6UO&g486nYrA=K!bj{^Ps*pUJLNR6-d&Yhmz*ZRy^E%(hpcyF1m40h>UmZSb>dx z#Gq%X-&yZ*GwLMxF&AJh&QMqKHjtl3_FgSTAhAZ};ROB-ukD zI$RW@xhUmt%~GbvJ$#snl4azoD4EGUw3#Sta(p$k0#w|_0*r4#1!uORqW(*C@xN53 z@-Vsx^h$B!UcQP0i&Jx+f+L^wse(u}<*2!D z!ITMvD{MSD?&HU~R#pNkzzTKtCBL5uq@+2s9V_k8AZNwY6s*XHV>Yu@vkIM^8Tn~p zYQpT!l5NK|$HPM`k*B-lYcu}#-03|G5-`w{J*#IE{g*r>N*ui|znL*GwK4{9bu4%K zk(Z>EBnab3r;Z`kJ`XlB^i3YJHEt}2T!5j^@ajd&0V>PtP@zE7Wn<>gA!UJ<6UsD!F9zE*~ZWcJfSs9yl zTGd(X8TMt9$41;A{Z}jnu>S(zf6Fy;>^XDNbj+<)^O9vwc+FEqvz{6G7=|=oT>>b- Zshape[1] * tensor2->shape[2]; + int result_data_offset = tensor1->shape[0] * tensor2->shape[2]; + + for (int batch = 0; batch < tensor2->shape[0]; batch++) { + + for (int i = 0; i < tensor1->shape[0]; i++) { + for (int j = 0; j < tensor2->shape[2]; j++) { + float sum = 0.0; + for (int k = 0; k < tensor1->shape[1]; k++) { + sum += tensor1->data[i * tensor1->shape[1] + k] * tensor2->data[batch*tensor2_offset + (k * tensor2->shape[2] + j)]; + } + result_data[(batch * result_data_offset) + (i * tensor2->shape[2] + j)] = sum; + } + } + } +} + void pow_tensor_cpu(Tensor* tensor, float power, float* result_data) { for (int i = 0; i < tensor->size; i++) { diff --git a/norch/csrc/cpu.h b/norch/csrc/cpu.h index f50b0d9..b6275b3 100644 --- a/norch/csrc/cpu.h +++ b/norch/csrc/cpu.h @@ -8,6 +8,7 @@ void sum_tensor_cpu(Tensor* tensor1, float* result_data); void sub_tensor_cpu(Tensor* tensor1, Tensor* tensor2, float* result_data); void elementwise_mul_tensor_cpu(Tensor* tensor1, Tensor* tensor2, float* result_data); void matmul_tensor_cpu(Tensor* tensor1, Tensor* tensor2, float* result_data); +void batched_matmul_tensor_cpu(Tensor* tensor1, Tensor* tensor2, float* result_data); void pow_tensor_cpu(Tensor* tensor, float power, float* result_data); void scalar_mul_tensor_cpu(Tensor* tensor, float scalar, float* result_data); void ones_like_tensor_cpu(Tensor* tensor, float* result_data); diff --git a/norch/csrc/cuda.cu b/norch/csrc/cuda.cu index 071828f..afa9820 100644 --- a/norch/csrc/cuda.cu +++ b/norch/csrc/cuda.cu @@ -5,7 +5,6 @@ #define THREADS_PER_BLOCK 128 #define TILE_SIZE 32 -#define SHMEM_SIZE THREADS_PER_BLOCK * sizeof(float) __host__ void cpu_to_cuda(Tensor* tensor) { @@ -61,7 +60,7 @@ __host__ void add_tensor_cuda(Tensor* tensor1, Tensor* tensor2, float* result_da __global__ void sum_tensor_cuda_kernel(float* data, float* result_data, int size) { - __shared__ float partial_sum[SHMEM_SIZE]; + __shared__ float partial_sum[THREADS_PER_BLOCK * sizeof(float)]; int tid = threadIdx.x; int i = blockIdx.x * blockDim.x + threadIdx.x; diff --git a/norch/csrc/tensor.cpp b/norch/csrc/tensor.cpp index c361161..ed4eeb7 100644 --- a/norch/csrc/tensor.cpp +++ b/norch/csrc/tensor.cpp @@ -327,9 +327,10 @@ extern "C" { } Tensor* matmul_tensor(Tensor* tensor1, Tensor* tensor2) { + //MxN @ NxP = MxP // Check if tensors have compatible shapes for matrix multiplication if (tensor1->shape[1] != tensor2->shape[0]) { - fprintf(stderr, "Incompatible shapes for matrix multiplication\n"); + fprintf(stderr, "Incompatible shapes for matrix multiplication %dx%d and %dx%d\n", tensor1->shape[0], tensor1->shape[1], tensor2->shape[0], tensor2->shape[1]); exit(1); } @@ -387,6 +388,69 @@ extern "C" { } } + Tensor* batched_matmul_tensor(Tensor* tensor1, Tensor* tensor2) { + //MxN @ BATCHxNxP = BATCHxMxP + // Check if tensors have compatible shapes for matrix multiplication + if (tensor1->shape[1] != tensor2->shape[1]) { + fprintf(stderr, "Incompatible shapes for matrix multiplication %dx%d and %dx%d\n", tensor1->shape[0], tensor1->shape[1], tensor2->shape[0], tensor2->shape[1]); + exit(1); + } + + 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); + } + + char* device = (char*)malloc(strlen(tensor1->device) + 1); + if (device != NULL) { + strcpy(device, tensor1->device); + } else { + fprintf(stderr, "Memory allocation failed\n"); + exit(-1); + } + + int ndim = 3; + int* shape = (int*)malloc(ndim * sizeof(int)); + if (shape == NULL) { + fprintf(stderr, "Memory allocation failed\n"); + exit(1); + } + + shape[0] = tensor2->shape[0];; + shape[1] = tensor1->shape[0]; + shape[2] = tensor2->shape[2]; + + int size = 1; + for (int i = 0; i < ndim; i++) { + size *= shape[i]; + } + + float* result_data = (float*)malloc(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, size * sizeof(float)); + matmul_tensor_cuda(tensor1, tensor2, result_data); + return create_tensor(result_data, shape, ndim, device); + } + else { + float* result_data = (float*)malloc(size * sizeof(float)); + if (result_data == NULL) { + fprintf(stderr, "Memory allocation failed\n"); + exit(1); + } + batched_matmul_tensor_cpu(tensor1, tensor2, result_data); + return create_tensor(result_data, shape, ndim, device); + } + + } + + Tensor* pow_tensor(Tensor* tensor, float power) { char* device = (char*)malloc(strlen(tensor->device) + 1); if (device != NULL) { diff --git a/norch/tensor.py b/norch/tensor.py index 94568e1..32a5bd4 100644 --- a/norch/tensor.py +++ b/norch/tensor.py @@ -291,22 +291,38 @@ class Tensor: return self def __matmul__(self, other): - if self.ndim != 2 or other.ndim != 2: - raise ValueError("Matrix multiplication requires 2D tensors") + if other.ndim == 3: + #batched 3D matmul - if self.shape[1] != other.shape[0]: - raise ValueError("Incompatible shapes for matrix multiplication") + Tensor._C.batched_matmul_tensor.argtypes = [ctypes.POINTER(CTensor), ctypes.POINTER(CTensor)] + Tensor._C.batched_matmul_tensor.restype = ctypes.POINTER(CTensor) + + result_tensor_ptr = Tensor._C.batched_matmul_tensor(self.tensor, other.tensor) - Tensor._C.matmul_tensor.argtypes = [ctypes.POINTER(CTensor), ctypes.POINTER(CTensor)] - Tensor._C.matmul_tensor.restype = ctypes.POINTER(CTensor) + result_data = Tensor() + result_data.tensor = result_tensor_ptr + result_data.shape = [other.shape[0], self.shape[0], other.shape[2]] + result_data.ndim = 3 + result_data.device = self.device + + else: + #2D matmul + if self.ndim != 2 or other.ndim != 2: + raise ValueError("Matrix multiplication requires 2D tensors") - result_tensor_ptr = Tensor._C.matmul_tensor(self.tensor, other.tensor) + if self.shape[1] != other.shape[0]: + raise ValueError("Incompatible shapes for matrix multiplication") - result_data = Tensor() - result_data.tensor = result_tensor_ptr - result_data.shape = [self.shape[0], other.shape[1]] - result_data.ndim = 2 - result_data.device = self.device + Tensor._C.matmul_tensor.argtypes = [ctypes.POINTER(CTensor), ctypes.POINTER(CTensor)] + Tensor._C.matmul_tensor.restype = ctypes.POINTER(CTensor) + + result_tensor_ptr = Tensor._C.matmul_tensor(self.tensor, other.tensor) + + result_data = Tensor() + result_data.tensor = result_tensor_ptr + result_data.shape = [self.shape[0], other.shape[1]] + result_data.ndim = 2 + result_data.device = self.device result_data.requires_grad = self.requires_grad or other.requires_grad if result_data.requires_grad: diff --git a/test.py b/test.py index 7efccf6..a65593d 100644 --- a/test.py +++ b/test.py @@ -20,8 +20,25 @@ if __name__ == "__main__": import random import numpy as np + a = norch.Tensor([ + [[1.234, 2.123], [3.635, 4.456], [5.678, 6.789]], + [[7.890, 8.901], [9.012, 1.234], [2.345, 3.456]], + [[4.567, 5.678], [6.789, 7.890], [8.901, 9.012]], + [[1.234, 2.345], [3.456, 4.567], [5.678, 6.789]], + [[7.890, 8.901], [9.012, 1.234], [2.345, 3.456]] + ]) + + b = norch.Tensor([ + [1.234, 2.123, 1.5], + [5.678, 6.789, 1.293], + [3.635, 4.456, 1.0202], + [7.890, 8.901, 1.91], + ]) + + result = b @ a + print(result) - #a = Tensor([[1, 2, 3], [1, 2, 3], [1, 2, 3]])#.to("cuda") + #a = norch.Tensor([[1, 2, 3], [1, 2, 3], [1, 2, 3]])#.to("cuda") #b = Tensor([[1, 2, 3], [1, 2, 3], [1, 2, 3]])#.to("cuda") #c = Tensor([[1, 2, 3], [1, 2, 3], [1, 2, 3]])#.to("cuda") @@ -37,7 +54,6 @@ if __name__ == "__main__": print(a.grad)""" """#print(a) - """ N = 10 a = norch.Tensor([[1 for _ in range(N)] for _ in range(N)]) #b = norch.Tensor([[random.uniform(0, 1) for _ in range(N)] for _ in range(N)]) @@ -56,7 +72,7 @@ if __name__ == "__main__": print("\n\n") """ - + """ a = [[random.uniform(0, 1) for _ in range(N)] for _ in range(N)] b = [[random.uniform(0, 1) for _ in range(N)] for _ in range(N)] ini = time.time() From b7cf03828ecde2331e996119f06bafaa665e3ae0 Mon Sep 17 00:00:00 2001 From: lucasdelimanogueira Date: Thu, 2 May 2024 20:21:19 -0300 Subject: [PATCH 2/7] batched and broadcasted matmul --- build/cpu.o | Bin 4776 -> 5384 bytes build/libtensor.so | Bin 86064 -> 90288 bytes build/tensor.o | Bin 24984 -> 27232 bytes norch/__pycache__/tensor.cpython-38.pyc | Bin 9138 -> 9351 bytes .../__pycache__/functions.cpython-38.pyc | Bin 3473 -> 3473 bytes norch/autograd/functions.py | 2 - norch/csrc/cpu.cpp | 22 +++++- norch/csrc/cpu.h | 1 + norch/csrc/tensor.cpp | 74 +++++++++++++++++- norch/tensor.py | 20 ++++- test.py | 29 ++++++- 11 files changed, 136 insertions(+), 12 deletions(-) diff --git a/build/cpu.o b/build/cpu.o index d681b7686f31c09521697ef680103c12a50ebd06..f1d237e13074bdd24178712377b4b07ce85b0899 100644 GIT binary patch delta 1013 zcmZ9JUr19?9LLYOySaOEdhS)JBxyzpB@sxF4Qfbv;06^zL>fZ=SeEY!VSU zo)najtjNoVU#>dQJWuX%qXqaHXt_|}$v>EOmH(PAb3?3VMX9C=hekw+CoOLbHq&jK zF(=loOzmzWPcybCLASbV!b#b1Q{2r^jJv)lSs!gtpe4F!PMevWV$!8D*GZWVWbi(- zTIT)uz*Q2WM2kb!YSkN8u@-!l|9j;v99N)=bP0PUTOP>O7qRDFY$mXoK@ylz{JmMN zCUCvtXZMk##ZY$K-eGL&aJ$aMs=R*AJ|zhou@k RuL`Ho(+$rXbNfHxp?}FD|Ih#c delta 542 zcmeCsTA?~YgGqybqt;oL&6nBcGBGnSFig(p{K={SWZaqD%cac7FnJ@FJfp(oi$Kz0 z@<$+sf#dAgF^-3~ZAbdBquJKxDllBSeiZD?~B_ zs>Ti~J{2nN0~Jq%ia&&kdqBloq2iis5P`W+@fA?M?+nUvTkzY;WKO5mNWBxJ{w#6CHYTWoTLkOqvo1ISEapZo|YnZZ6; zN!X5Q3RI1-2Gb1o$%};TICrpvy}__x@=IZJ&I!B_p2B2J5p&K6P6*Foawd>BgB!v- TF?pqkIoAe02(N?z=mt3et5{Yv diff --git a/build/libtensor.so b/build/libtensor.so index 411895840f183a23fb29024bf2ed54e9d24c29e5..c430d1986fbb36dca99ac3279f2f5b53a273deee 100755 GIT binary patch delta 19288 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 QC$hI%`~;+K7%4aSUpqFR^#A|> diff --git a/build/tensor.o b/build/tensor.o index 3dbd4caff2340dc14b78f7f8f694863588229b57..6657ec4f6ab10cbdf09b24d52131444bf996f433 100644 GIT binary patch delta 4699 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 Mq)k2bQmi}YA4O@+r~m)} diff --git a/norch/__pycache__/tensor.cpython-38.pyc b/norch/__pycache__/tensor.cpython-38.pyc index f6d3f536f149a35beabf14531895fb9aaed26447..15f473bdac5e4b577e38551a4775c2a66be43b79 100644 GIT binary patch delta 414 zcmdnw-tNg4%FD~e00eX7Ow!COH}d65OT1xZV5nipVn|`kW+>{ZVFa_7ih3q@N|*Rd zV9c|CN-|AgERuprgV-gE3z$ln7c#==bfyxPEY>WZcy^cwl+OX87w}BpDXq%LGWou= zyyYsenatVD6Bvt)z-EHkMOG!eDXh(mO^iT!t`rtY2A~{Q3X>!QNM%t(3GZY>8Cgj_ zG#mKhAvW+$PL~1M&?_Tp!9Rhq-~v!Le+_dy5N84TMK4MOYJes-GXcc}YnX!>G}--L zG6O@S2p9wmFPT8B$v0*6C-cf0FbYk!la=RHOe)GxOi4~GE=f&^pByKvH#tUDVsfu+ zkiH90H3OpvvlOEMlMoXdBO9X}5c4oepows?NHB6RiEaKPTgk{6y}3-@nvth9KZRE?9=JR1>V5nitVn|`kW-4l!JXyNLByUL#15kiD zo4I%jSPIB0np47)!qUvx#0Zq*N@0}*Y2r#@l4JnN?I_`yd{IVLk~f~cgmD2=3G+h6 z5|%91EZ%qy5WRqRGP|rQBkN>cSxIBQ35*2>K)rl5%<({+1>_fbltyv=ishape[1] * tensor2->shape[2]; int result_data_offset = tensor1->shape[0] * tensor2->shape[2]; @@ -65,6 +65,26 @@ void batched_matmul_tensor_cpu(Tensor* tensor1, Tensor* tensor2, float* result_d } } +void batched_matmul_tensor_cpu(Tensor* tensor1, Tensor* tensor2, float* result_data) { + + int tensor1_offset = tensor1->shape[1] * tensor1->shape[2]; + int tensor2_offset = tensor2->shape[1] * tensor2->shape[2]; + int result_data_offset = tensor1->shape[1] * tensor2->shape[2]; + + for (int batch = 0; batch < tensor2->shape[0]; batch++) { + + for (int i = 0; i < tensor1->shape[1]; i++) { + for (int j = 0; j < tensor2->shape[2]; j++) { + float sum = 0.0; + for (int k = 0; k < tensor1->shape[2]; k++) { + sum += tensor1->data[(batch * tensor1_offset) + i * tensor1->shape[2] + k] * tensor2->data[batch*tensor2_offset + (k * tensor2->shape[2] + j)]; + } + result_data[(batch * result_data_offset) + (i * tensor2->shape[2] + j)] = sum; + } + } + } +} + void pow_tensor_cpu(Tensor* tensor, float power, float* result_data) { for (int i = 0; i < tensor->size; i++) { diff --git a/norch/csrc/cpu.h b/norch/csrc/cpu.h index b6275b3..ae3eae5 100644 --- a/norch/csrc/cpu.h +++ b/norch/csrc/cpu.h @@ -8,6 +8,7 @@ void sum_tensor_cpu(Tensor* tensor1, float* result_data); void sub_tensor_cpu(Tensor* tensor1, Tensor* tensor2, float* result_data); void elementwise_mul_tensor_cpu(Tensor* tensor1, Tensor* tensor2, float* result_data); void matmul_tensor_cpu(Tensor* tensor1, Tensor* tensor2, float* result_data); +void broadcasted_batched_matmul_tensor_cpu(Tensor* tensor1, Tensor* tensor2, float* result_data); void batched_matmul_tensor_cpu(Tensor* tensor1, Tensor* tensor2, float* result_data); void pow_tensor_cpu(Tensor* tensor, float power, float* result_data); void scalar_mul_tensor_cpu(Tensor* tensor, float scalar, float* result_data); diff --git a/norch/csrc/tensor.cpp b/norch/csrc/tensor.cpp index ed4eeb7..532798d 100644 --- a/norch/csrc/tensor.cpp +++ b/norch/csrc/tensor.cpp @@ -388,11 +388,11 @@ extern "C" { } } - Tensor* batched_matmul_tensor(Tensor* tensor1, Tensor* tensor2) { + Tensor* broadcasted_batched_matmul_tensor(Tensor* tensor1, Tensor* tensor2) { //MxN @ BATCHxNxP = BATCHxMxP // Check if tensors have compatible shapes for matrix multiplication if (tensor1->shape[1] != tensor2->shape[1]) { - fprintf(stderr, "Incompatible shapes for matrix multiplication %dx%d and %dx%d\n", tensor1->shape[0], tensor1->shape[1], tensor2->shape[0], tensor2->shape[1]); + fprintf(stderr, "Incompatible shapes for broadcasted batched matrix multiplication %dx%d and %dx%dx%d\n", tensor1->shape[0], tensor1->shape[1], tensor2->shape[0], tensor2->shape[1], tensor2->shape[2]); exit(1); } @@ -435,7 +435,75 @@ extern "C" { float* result_data; cudaMalloc((void **)&result_data, size * sizeof(float)); - matmul_tensor_cuda(tensor1, tensor2, result_data); + ////broadcasted_batched_matmul_tensor_cuda(tensor1, tensor2, result_data); + return create_tensor(result_data, shape, ndim, device); + } + else { + float* result_data = (float*)malloc(size * sizeof(float)); + if (result_data == NULL) { + fprintf(stderr, "Memory allocation failed\n"); + exit(1); + } + broadcasted_batched_matmul_tensor_cpu(tensor1, tensor2, result_data); + return create_tensor(result_data, shape, ndim, device); + } + + } + + Tensor* batched_matmul_tensor(Tensor* tensor1, Tensor* tensor2) { + //BATCHxMxN @ BATCHxNxP = BATCHxMxP + // Check if tensors have compatible shapes for matrix multiplication + + if (tensor1->shape[0] != tensor2->shape[0]) { + fprintf(stderr, "Tensors must have same batch dimension for batch matmul %d and %d\n", tensor1->shape[0], tensor2->shape[0]); + exit(1); + } + + if (tensor1->shape[2] != tensor2->shape[1]) { + fprintf(stderr, "Incompatible shapes for matrix multiplication %dx%d and %dx%d\n", tensor1->shape[0], tensor1->shape[1], tensor2->shape[0], tensor2->shape[1]); + exit(1); + } + + 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); + } + + char* device = (char*)malloc(strlen(tensor1->device) + 1); + if (device != NULL) { + strcpy(device, tensor1->device); + } else { + fprintf(stderr, "Memory allocation failed\n"); + exit(-1); + } + + int ndim = 3; + int* shape = (int*)malloc(ndim * sizeof(int)); + if (shape == NULL) { + fprintf(stderr, "Memory allocation failed\n"); + exit(1); + } + + shape[0] = tensor2->shape[0];; + shape[1] = tensor1->shape[1]; + shape[2] = tensor2->shape[2]; + + int size = 1; + for (int i = 0; i < ndim; i++) { + size *= shape[i]; + } + + float* result_data = (float*)malloc(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, size * sizeof(float)); + //batched_matmul_tensor_cuda(tensor1, tensor2, result_data); return create_tensor(result_data, shape, ndim, device); } else { diff --git a/norch/tensor.py b/norch/tensor.py index 32a5bd4..fa69bd6 100644 --- a/norch/tensor.py +++ b/norch/tensor.py @@ -291,8 +291,22 @@ class Tensor: return self def __matmul__(self, other): - if other.ndim == 3: - #batched 3D matmul + if self.ndim < 3 and other.ndim == 3: + #broadcasted 2D x 3D matmul + + Tensor._C.broadcasted_batched_matmul_tensor.argtypes = [ctypes.POINTER(CTensor), ctypes.POINTER(CTensor)] + Tensor._C.broadcasted_batched_matmul_tensor.restype = ctypes.POINTER(CTensor) + + result_tensor_ptr = Tensor._C.broadcasted_batched_matmul_tensor(self.tensor, other.tensor) + + result_data = Tensor() + result_data.tensor = result_tensor_ptr + result_data.shape = [other.shape[0], self.shape[0], other.shape[2]] + result_data.ndim = 3 + result_data.device = self.device + + elif self.ndim == 3 and other.ndim == 3: + #broadcasted 3D x 3D matmul Tensor._C.batched_matmul_tensor.argtypes = [ctypes.POINTER(CTensor), ctypes.POINTER(CTensor)] Tensor._C.batched_matmul_tensor.restype = ctypes.POINTER(CTensor) @@ -301,7 +315,7 @@ class Tensor: result_data = Tensor() result_data.tensor = result_tensor_ptr - result_data.shape = [other.shape[0], self.shape[0], other.shape[2]] + result_data.shape = [other.shape[0], self.shape[1], other.shape[2]] result_data.ndim = 3 result_data.device = self.device diff --git a/test.py b/test.py index a65593d..27f3ddf 100644 --- a/test.py +++ b/test.py @@ -26,17 +26,40 @@ if __name__ == "__main__": [[4.567, 5.678], [6.789, 7.890], [8.901, 9.012]], [[1.234, 2.345], [3.456, 4.567], [5.678, 6.789]], [[7.890, 8.901], [9.012, 1.234], [2.345, 3.456]] - ]) + ], requires_grad=True) - b = norch.Tensor([ + b = norch.Tensor([[ [1.234, 2.123, 1.5], [5.678, 6.789, 1.293], [3.635, 4.456, 1.0202], [7.890, 8.901, 1.91], - ]) + ],[ + [1.234, 2.123, 1.5], + [5.678, 6.789, 1.293], + [3.635, 4.456, 1.0202], + [7.890, 8.901, 1.91], + ],[ + [1.234, 2.123, 1.5], + [5.678, 6.789, 1.293], + [3.635, 4.456, 1.0202], + [7.890, 8.901, 1.91], + ],[ + [1.234, 2.123, 1.5], + [5.678, 6.789, 1.293], + [3.635, 4.456, 1.0202], + [7.890, 8.901, 1.91], + ],[ + [1.234, 2.123, 1.5], + [5.678, 6.789, 1.293], + [3.635, 4.456, 1.0202], + [7.890, 8.901, 5.91], + ]]) result = b @ a print(result) + #c = result.sum() + #c.backward() + #print(a.grad) #a = norch.Tensor([[1, 2, 3], [1, 2, 3], [1, 2, 3]])#.to("cuda") #b = Tensor([[1, 2, 3], [1, 2, 3], [1, 2, 3]])#.to("cuda") From a45b93007531e767e40201f4bdd1b4bb04ad2caf Mon Sep 17 00:00:00 2001 From: lucasdelimanogueira Date: Thu, 2 May 2024 21:14:26 -0300 Subject: [PATCH 3/7] transpose n dimensions cpu --- build/cpu.o | Bin 5384 -> 5864 bytes build/libtensor.so | Bin 90288 -> 90336 bytes norch/__pycache__/tensor.cpython-38.pyc | Bin 9351 -> 9278 bytes norch/csrc/cpu.cpp | 32 +++++++++++++++++++++++- norch/tensor.py | 7 ++---- test.py | 8 ++++-- 6 files changed, 39 insertions(+), 8 deletions(-) diff --git a/build/cpu.o b/build/cpu.o index f1d237e13074bdd24178712377b4b07ce85b0899..9f7b57930e478ea0ee1a31a6f42d792b6e0c7593 100644 GIT binary patch delta 811 zcmZuvO=uHA6yBMNZYEhbfA|C9At=PE2%@c}5+X7%M->ZR1WPU!8+x(OOUz-gbQyw$ zK@g7~3KgMBEg1;>;prOA;;DbWI=>`*rE&+{BQ!DRu-q3` zy7n?Cm;?Gh=2q3hJnx|HhE1CTCg}Xq3~idFGoWqLhJtO{Qby3$EbSC-fQ1f9$>LCb zPiaI4aAb&rL|tg+Rt?bxr!CYS3<;WPs%ENf%ur3xh9VnPRiJ9ujN)B0rcOQ>UoewE zhu4q=VjW)ekVRcyaJ6So1aR<7uFuO`p(_(mSY8TkqJ)mYrN^VI__lF$qK_iS^zy~9Dzr2N|0K}LRlad9c9<$NPo&6M0Qub#iDLm4dfWKO}i-w)Qk|M1i0 z&*m(`29YH86)zC^D>fB+5L0EE_DEicPvcD@?}ksvm3VsSZiD-d$aXw~-xHZiWN>Sc vlSpHi$Txs!Vc7<=9h0eKCRB+8jB9csIZc=u>sTet~emSiAnI^@gYw0Lt>Ocm30Ou-o+u;|Y%$9tR&Vc`zOV@_@oWK*Aru z!o57LAl*P+4?Gx8eC8JtVEW82$j}Vb^?GeHP|@odlh?7UPR{4Do4k%oZ}S7L6^z1j zL0Vk-1lpLKdD)nz@UU|*Y@W>%%OnJr0LtBGWMB|tU}RXtvDu3MEhATal%aWIadBpP z-ef^RvB}|rhMRW?8Za^~;+XtO=pNHQj>)Hl%{W)^gUn@MFqq6KV$Nj8Ir$)u*yIQi z4H$C4nHQ_P%e Y1uum6pK)@Rm>HLVAcR}O0JL2W0EnY|aR2}S diff --git a/build/libtensor.so b/build/libtensor.so index c430d1986fbb36dca99ac3279f2f5b53a273deee..6912a056ea71261f54a1ff237e8db51a48743418 100755 GIT binary patch delta 12490 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 delta 12297 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[0]; int cols = tensor->shape[1]; @@ -125,6 +125,36 @@ void transpose_tensor_cpu(Tensor* tensor, float* result_data) { result_data[j * rows + i] = tensor->data[i * cols + j]; } } +}*/ + +void transpose_tensor_cpu(Tensor* tensor, float* result_data) { + int* shape = tensor->shape; + int ndim = tensor->ndim; + int* strides = (int*)malloc(ndim * sizeof(int)); + int* indices = (int*)calloc(ndim, sizeof(int)); + + strides[ndim - 1] = 1; + for (int i = ndim - 2; i >= 0; i--) { + strides[i] = strides[i + 1] * shape[i + 1]; + } + + int idx_result; + for (int idx_source = 0; idx_source < tensor->size; idx_source++) { + idx_result = 0; + for (int dim = 0; dim < ndim; dim++) { + idx_result += indices[dim] * strides[dim]; + } + result_data[idx_result] = tensor->data[idx_source]; + + // Update indices + indices[ndim - 1]++; + for (int dim = ndim - 1; dim > 0; dim--) { + if (indices[dim] == shape[dim]) { + indices[dim] = 0; + indices[dim - 1]++; + } + } + } } void assign_tensor_cpu(Tensor* tensor, float* result_data) { diff --git a/norch/tensor.py b/norch/tensor.py index fa69bd6..a0323db 100644 --- a/norch/tensor.py +++ b/norch/tensor.py @@ -385,9 +385,6 @@ class Tensor: @property def T(self): - if self.ndim != 2: - raise ValueError("Transpose requires 2D tensors") - Tensor._C.transpose_tensor.argtypes = [ctypes.POINTER(CTensor)] Tensor._C.transpose_tensor.restype = ctypes.POINTER(CTensor) @@ -395,8 +392,8 @@ class Tensor: result_data = Tensor() result_data.tensor = result_tensor_ptr - result_data.shape = [self.shape[1], self.shape[0]] - result_data.ndim = 2 + result_data.shape = self.shape[::-1] + result_data.ndim = self.ndim result_data.device = self.device return result_data diff --git a/test.py b/test.py index 27f3ddf..bce55f0 100644 --- a/test.py +++ b/test.py @@ -55,8 +55,12 @@ if __name__ == "__main__": [7.890, 8.901, 5.91], ]]) - result = b @ a - print(result) + b = norch.Tensor([ + [1.234, 2.123, 1.5]]) + + print(a.shape) + result = a.T + print(result.shape) #c = result.sum() #c.backward() #print(a.grad) From 8449575e70a991990af810997c448951bb4ed856 Mon Sep 17 00:00:00 2001 From: lucasdelimanogueira Date: Fri, 3 May 2024 13:18:37 -0300 Subject: [PATCH 4/7] small fix reshape return --- norch/__pycache__/tensor.cpython-38.pyc | Bin 9278 -> 9287 bytes norch/csrc/cpu.cpp | 2 +- norch/tensor.py | 4 ++-- test.py | 6 +++--- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/norch/__pycache__/tensor.cpython-38.pyc b/norch/__pycache__/tensor.cpython-38.pyc index 3dc93adb3b4a0b5866e22a7f5480e6e1bb92a95a..f61a489316560706fe8345312b9de7e33b6ace11 100644 GIT binary patch delta 103 zcmdnzaomG9l$V!_0SJ8fOw*oh`E*QBs@yLV|ztGER}nGnB*`#WrtH>SF`|fv_9* delta 96 zcmX@^vCo4yl$V!_0SMx?P13GyK3T@u0)W-+_nOhhR diff --git a/norch/csrc/cpu.cpp b/norch/csrc/cpu.cpp index 2b70cb6..f0ad525 100644 --- a/norch/csrc/cpu.cpp +++ b/norch/csrc/cpu.cpp @@ -127,6 +127,7 @@ void zeros_like_tensor_cpu(Tensor* tensor, float* result_data) { } }*/ + void transpose_tensor_cpu(Tensor* tensor, float* result_data) { int* shape = tensor->shape; int ndim = tensor->ndim; @@ -146,7 +147,6 @@ void transpose_tensor_cpu(Tensor* tensor, float* result_data) { } result_data[idx_result] = tensor->data[idx_source]; - // Update indices indices[ndim - 1]++; for (int dim = ndim - 1; dim > 0; dim--) { if (indices[dim] == shape[dim]) { diff --git a/norch/tensor.py b/norch/tensor.py index a0323db..d22aa91 100644 --- a/norch/tensor.py +++ b/norch/tensor.py @@ -122,7 +122,7 @@ class Tensor: if requires_grad: self.grad_fn = ReshapeBackward(self) - return self + return result_data def to(self, device): self.device = device @@ -392,7 +392,7 @@ class Tensor: result_data = Tensor() result_data.tensor = result_tensor_ptr - result_data.shape = self.shape[::-1] + result_data.shape = self.shape.copy()[::-1] result_data.ndim = self.ndim result_data.device = self.device diff --git a/test.py b/test.py index bce55f0..093d5aa 100644 --- a/test.py +++ b/test.py @@ -58,9 +58,9 @@ if __name__ == "__main__": b = norch.Tensor([ [1.234, 2.123, 1.5]]) - print(a.shape) - result = a.T - print(result.shape) + #print(a.shape) + b = a.reshape([2,3,5]) + print(b.shape) #c = result.sum() #c.backward() #print(a.grad) From 18c50dbeb88b30455094307c6cb7c3c474808a97 Mon Sep 17 00:00:00 2001 From: lucasdelimanogueira Date: Fri, 3 May 2024 13:34:43 -0300 Subject: [PATCH 5/7] Small fix shape of reshape --- build/libtensor.so | Bin 90336 -> 90336 bytes build/tensor.o | Bin 27232 -> 27496 bytes norch/csrc/tensor.cpp | 21 ++++++++++++++++----- test.py | 40 ++++++++++------------------------------ 4 files changed, 26 insertions(+), 35 deletions(-) diff --git a/build/libtensor.so b/build/libtensor.so index 6912a056ea71261f54a1ff237e8db51a48743418..e6e11d3e7979d8148970629574aacdc8aea4f7d0 100755 GIT binary patch delta 7303 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≶c2?_*Zf6BFt=jUB+H zwq!cH0yimPzaX0YmGuZm?sb+Bj$HqlT&^2i9S-_lGuei4WGtV>4upfSXcoK3uN!9b zAYbMYL0rg}%qIfu>2I?52*eb>$Z?i#zNl+L2>yVB(WVm_L8*J`iGAcG^mZbfP?`iyesQiwvOB$8E?;3V< zFo_~RGp`}UL~gTQLr5~Yz!nW5?cZSB!2QL=9N(6>;lSbcW9&0d@+-TIY=6f`(_2+k zDT_%U$=w{E_xs@V;Ur@=vF!;YD%SBeNuKgMzR+OGUXai3Cy-Iv^i1~BP!csQE<;Yh z{=_^QhZN^;_Xt zImb6C`O5D2Xr3wiQ?_UrnW|;2VV@7fx?E!l?HmsCu(|B>;iNJ)qDZp#mtb(keZ!^wH%o*4 pMM<)`@&pZ3OyzlpYd#xq2cT2Ut zrCMLQ$%Ulr#D^UCXt2`le+nxyj&BcGvdj6-@q5J!)f)3pGY;KTUeuFh8sY34|2vV< zi=1@2E;Dd4}=1OmX=Jj=voFnLWE+dt93h6VhiOMI_>07R$nA=CL z2A{Ajnc=5pG+gt<g_2mB z=4SBOk}rdzG}1I}Ea|k&Eo{((G-b;rLVAAZh+DyyW(>d;;J~x(2`!bFDu68SC(*y2?9y`jU*IsWoDDx5h zl1Xp6hmxVRb4Nq^EbYEzXbQKqbybun4fZwAQ)|cH+*)#wCi(bvY5!lXluXUOErY(@ zF?7_K!q#+av<8pOkamN%5ZyKTdv8m-eIOUK1<{KV4}(w6TWs}?>~4t3s^3G?rg@tijXIr;e5eZg1p!T)Ohw(qDga;yQ}1)rlMHCQBc`(11j8LTLl$aXs5VvQ&H3{6u~PkZ>Do+^oVTH3ZHzHhb6U$ zP}xfY@78LBX`IcPRAI8_R`JB<>-1czSGOR}Ycbx(Ebi-ac|G(N?L5V6LdAO=jd&r*Jwman8)=iVA1Zvf@?G@ z#ZM`@N=s9Gydyck{hs8eh;eWGKVC`q`UF(+5OvCVUlp?Yg~I8%l{@RWQ;ca3?L1?m z%hxdSQa+|{&It4x(IiT5`b+7(nyG(+mr{F8%)o;)wwl3;n_Ri?r!RoK0hLMeBfR?7 zGw9kxPsDo}#v-Oo&xR|a=hK&wrS&}Ris*SsljylO=X2=U@}21UU_6wsqb}KVjc7ri zBAlJqa_4^T6g|J&L}w;Xa6JMmZ@RDvDt8Zqu=^gG`(d6lux5o+4OGFf!-*bowK;}y{ArdBaKU&=~@CSZ+ccE-Idm7qW7&f>ugq(aW}_myomi;-J)<)6R)||L=tcCx&pI@LwYk3 z~Y-P_w6A#Dco-J!hnU!0WD-_YF5FO-rP8a}63@%@@s&FMz!4_%rw zP*HpvH_nSwiq6m%=JgMM@k_yO6E#~rO-1_AgL#kGT-pXZcm@&LY!knv@6Gdj?)7?} z#GAz7U^$KBLqXE#*n2u#Q=O>F$oFG=`+i(lPw&kOBLARWvVuos%WO!BS++dA#C8`I zlthaPeuc!Zd{SpYX|Eu?p5|rw_0H!-@dNZ}1$~etD|krDvr?40({$W&16E&nc7MhD zOFA_>F!rNb9H3*tW-&Gw=wlN86O%0Z)Aoho1}$4gJuO+%tHTCF z+6wBh)4I|7*+bf|1sSbgY@iAAyDO_}>5TaXC9{@BWcMTI==<~i$TnIze~5DX6fZ_O zdy0F~qd~Z~D%abZbP>y>3Vl?WEN6MA?x*eXa`rKauLth8yaV z3QqXXUf$!Qh?NS*dGp;*i8f+*OHnYOjSxCDcd^p3iq2ftPsy#JPjZ7_egi4C?MQV{ z*oPFUuq)KAFdeZ{A&qxlfe>uj)|=yYm1xHGglOhLrI^>$lXOQ;-`K8|$SMYdgVq+X zNv(H7>{=rcE49Y)8SJbU^ZJtO)}GK-Y!BM9WB~bzK3Lpcxp-VC4XdUf%=eAmQh~Td zpm0zs0GCu+8EjVyJ8oBsf}pLmiYqxCDcAnm8IpP z*YA#tX;yuK}vmy&@4?UEM}DWEQfByf0~Va}yz6d1CyG&lft#q1DvK97P_}@n#>dM`+2B<~y2a4kg>^Zu4rFf1MBno;ZLCw~vUnzo!dUM~Ck{ z&Ruo3uuhKDTaUD*-f-AXO-@nQf&!Nf6@s}MdkM^gKNHN4sQ;Siu*zeS+1$~Q`QG8S z%uRINnju7`C)U(EUoRJ=XKCr$cxBijdSR_e8C_0$uZs%nDqQ$=;O0pB;9y(Q>vYvR zlM;D=x)rQ;xsUS=_r5b0DoR~^fS2kzLm2C9zqrt^@dlxb={vzJ*_nt*IyOZc81z3)DSnY>}7JbC)Q;_#n^M zpZH9aum8I!|33#L>6&(;{8QTHxOR>j<-6Ky?AXc6cdCP{w4P2_VQ8nf9Hves0}YK{ z$S?BxhJ!WAQ)6wS=8^zIt@Kq&UkA{C zrLULfdq^KZZ}}9W=}39W=kh-w-UrgJk&Ly;9}_nqTIVFct%_Wq*q4TJ#(EFpBiCfAA~(d1>`p z#4X}4&C6;7j?)ZnT$O)ANKx#>A8`(Eq|Id$+|GRr3y#bBno=6QG2X?9Mk9W?v+|Qe z`5W^)($c`vgWD!8GvA6=)ty*D|4C5QGyM5OA{c-XCRKIT>vVg71AqfZfe!d7a5m6w zw5o0Z4jzMiV9QwK11nxaJ}_pys=8y*ZwCeg{|OumjGmyXbAiKOR@Fi$omsaTU-rXr z7vAup~)UbAZdIsOl!*mSk0}03MsFsx83l(^R!RcJH$(s@fMg zZUzbk&UzI>z`RtfM&Qnw&;eGZsp>`GRp3KsGkyi6t7G zELHskm;ci9xw;E6&N)ac|bGp7VybDE`Aj5x5mN7Wn*PbP6m376N|& zHeix|M?-p%{z`B0G}Y+gxlT#w=+y3K;@-ho*9(0|;_*@>ThNF2l4n^NhX8hfgFidR zA&)~({Y8XbkzXI;YZQy{CBE^?Uqli7C-zg~!2c5Cv{-LcRq@#Csejv3|0MW5Ss7@Q zf0)=o=#qZy5-v#=d&I4qM=@_d(nmQtibZqWHHJ<0BLT|IG3-@oa zVIteb@!ZSotUoB!SJ*%K^&gX1mjK{{Bo@u_`^jut0Q~o-ux0%ERx+=pk8&fKRdU4j z4URXH*`Me~iJZpk>%rmzNqaJi83S=E)=p}|>Ie4PIV`##V*Z%J zCilbLnSFF=Kl0cK4-eT}A!L#Aue;E`>65Ek!Z0TSUrsOYYy9SfQ9-Fmi zu>G(=_-7avj)JGGRm+*{5b`RScrhw=3mj3tQ=bxK6Ie6S}rSdwNeH2A}*_r1_ zevg(iY3m|E_cE5aqU)r4SjN(0NHK|J4`N7|kK+U0CWP?^yvgkOp~Sa~{nbK8939;J z_;ogCC`lZ&Ekn{a^EHjnPR;N5>Y+iiZ^>sjhmuf|&N>ex29nGM4kIJUP_|$gY5O+d z2F@EU=J@8p6~_p-2eEUUWEQ)FY#+zRyd_$cKZ}SZBYQYLJNLqw!b!^4vyHJNbdcjK zheev-@#O&1>2`c?K{dPMOP~hL?)c8Zt&`+& zd_l$knCJ2%)(KrUC7#4b%w8so=&lv9TMKf0UvojTPiOV<*lRn=*pqk?s@%DBNg+Gh|391{L`whw diff --git a/build/tensor.o b/build/tensor.o index 6657ec4f6ab10cbdf09b24d52131444bf996f433..a4e4a4102036d1b18de9d7a98344aacbfddfbec9 100644 GIT binary patch delta 2193 zcmZ{kZD>)6Lv%6{Mv4)u!aj8E=7)e|Sf+^Gn0rpnz3kcDdf;$- zfB*A8=YO8(rVDd&<(B+eNU5Z9>%VGp$IZ;>jG1|VIx{c@j{{p@=rXg$jG5iD0iO$I z=9ZZ$R3sc(V=80J!J#KUY%3T=L5f|*-00@4Q8Z7Q6HguI5M9%zT+R*@;a=_9NKwA~ zeZeTns1%H{aFx4^snI~zDF4e<;VvmVP-?vJUB)PVYLw->H+Yt8Px}s|1gCwQ;PP{< z<~7bhtMfxFxCT_O2jT&jJOi)$_rP4xo1gZ-s^m+}Oo4KfEB{wOQ}Sx4wN{-_@N~nY zo=|o*)UGFqv5I9xazaoXz3uo2arK14X2-u|k0&{q}z4%V>8)=TE`FOD zoZqez?~N9BCedMhh$TV}*BN1wHW1g-$n5<6gg;MsitufOAA#HulP95hi0NNjYn;h1 z!Cq9ak{xKpW_eD1fvDTb{tx;7W9}A2IQShIPCM;R!ZpGpgf|dALb#Xk6NJ$(k#sLrq8eNgo- zui$mT#w3gE3y3>9I})|H3uW4oqlD9rOv3pDuY4lOrQg+qs@EM9w{vRtcFF5#v&z?3&9++>4S$lIyg7fLs5KpbGdz1gOz;P1BQ`?lYAy_=H2Fj_B z{im7^$>(54x?7%wkJ8=Bqjs?(9a5wYSWbr(Uk7v^3@i8EfsgUA{U!JYAL*^Id@x*h NC?$4(53Zz|{syJ$u-yOv delta 2105 zcmZ`(T}TvB7~PpnG}PRzrX{3R+qT5kTuiZYZL5tbuwS-^GV^D()d-UGp=7h|kG3Ju zz95Mxe2Id{WM6vlL5s+j{wQP-iLHlNs2-$x6Y9IOGkBQT3wJKxIrrS}e)rrvsc9+s zNg7-)Cp*W=AFjzepvEFoYOHS}796K%#U4*ey&Or|dfloPm{PR^n|MsAv1v8-I%VVb zI*^d`VOB)n$-d4-0|mLYT3~i-U_9dDQ5{xqF25>h)=sF>d(EZ=6H7;5!~%)Sfm!MM zN3piHy`nCVAWw;x{^V46l8{5yf=NC7LRt}OXzO(Zh5$jzVa~YikELb;@(isiURKQ zf77kV$pJT+`(o~SBH*@)CYuyTsZ$SZSv(YSH&tyk#OyhPHMQf5(z7oJ?Z9<|wQBEJ zRQJ;&+XI-tf-y7KOTdc(p9Z`Z@SkbCT;KE(AhJq0;3hVd&)rP0lKjnzW23>E#h3@- zrRZ_Ru?@6%5c_GQS&=%)-mDDt!yE8iTcJ8+GlW4B954wLdjjnO7Be=RWnEC<>x?GoVNBegeJ) z_LNn|0XJb0TDO{_Eo_m&TKBq(#+cm$TCDRheQ8lzJAvKGtDELW0LP5C07o-l0*+?B z6FaP$0~W2zTPv#i|LQquq*Za$8mxJa=GEIqADG<@TD*FVx;B(S+a-4B+U|H^A`$<*ZxSIl5LxW9{sY!CG(KKC*`t$6?UotvgPBW%@Z>{`VA`dXt{f#3VdsBk~$QJ4_LhC2dRqLc7wInc%FK=iUH7KjWHSt zDc*a)`oW_(;FxjB9iQoFmb_8pcb1gW`xbSIK5V=pJuonVkGiP)~?L!z4G TQ@-4AXL`9_@>dp7Q#kJ*$w8zx diff --git a/norch/csrc/tensor.cpp b/norch/csrc/tensor.cpp index 532798d..f85759e 100644 --- a/norch/csrc/tensor.cpp +++ b/norch/csrc/tensor.cpp @@ -565,14 +565,25 @@ extern "C" { exit(-1); } + int ndim = new_ndim; + int* shape = (int*)malloc(ndim * sizeof(int)); + if (shape == NULL) { + fprintf(stderr, "Memory allocation failed\n"); + exit(1); + } + + for (int i = 0; i < ndim; i++) { + shape[i] = new_shape[i]; + } + // Calculate the total number of elements in the new shape - int new_size = 1; + int size = 1; for (int i = 0; i < new_ndim; i++) { - new_size *= new_shape[i]; + size *= shape[i]; } // Check if the total number of elements matches the current tensor's size - if (new_size != tensor->size) { + if (size != tensor->size) { fprintf(stderr, "Cannot reshape tensor. Total number of elements in new shape does not match the current size of the tensor.\n"); exit(1); } @@ -582,7 +593,7 @@ extern "C" { float* result_data; cudaMalloc((void **)&result_data, tensor->size * sizeof(float)); assign_tensor_cuda(tensor, result_data); - return create_tensor(result_data, new_shape, new_ndim, device); + return create_tensor(result_data, shape, ndim, device); } else { float* result_data = (float*)malloc(tensor->size * sizeof(float)); @@ -591,7 +602,7 @@ extern "C" { exit(1); } assign_tensor_cpu(tensor, result_data); - return create_tensor(result_data, new_shape, new_ndim, device); + return create_tensor(result_data, shape, ndim, device); } } diff --git a/test.py b/test.py index 093d5aa..e86e5c2 100644 --- a/test.py +++ b/test.py @@ -28,39 +28,19 @@ if __name__ == "__main__": [[7.890, 8.901], [9.012, 1.234], [2.345, 3.456]] ], requires_grad=True) - b = norch.Tensor([[ - [1.234, 2.123, 1.5], - [5.678, 6.789, 1.293], - [3.635, 4.456, 1.0202], - [7.890, 8.901, 1.91], - ],[ - [1.234, 2.123, 1.5], - [5.678, 6.789, 1.293], - [3.635, 4.456, 1.0202], - [7.890, 8.901, 1.91], - ],[ - [1.234, 2.123, 1.5], - [5.678, 6.789, 1.293], - [3.635, 4.456, 1.0202], - [7.890, 8.901, 1.91], - ],[ - [1.234, 2.123, 1.5], - [5.678, 6.789, 1.293], - [3.635, 4.456, 1.0202], - [7.890, 8.901, 1.91], - ],[ - [1.234, 2.123, 1.5], - [5.678, 6.789, 1.293], - [3.635, 4.456, 1.0202], - [7.890, 8.901, 5.91], - ]]) - b = norch.Tensor([ - [1.234, 2.123, 1.5]]) + [1.234, 2.123, 1.5], + [5.678, 6.789, 1.293], + [3.635, 4.456, 1.0202], + [7.890, 8.901, 1.91], + ]) + + #b = norch.Tensor([ + # [1.234, 2.123, 1.5]]) #print(a.shape) - b = a.reshape([2,3,5]) - print(b.shape) + c = a.reshape([2,3,5]) + print(b @ c) #c = result.sum() #c.backward() #print(a.grad) From a92b99177684b18b9a848ca351d4ed0ff781c827 Mon Sep 17 00:00:00 2001 From: lucasdelimanogueira Date: Sat, 4 May 2024 13:37:18 -0300 Subject: [PATCH 6/7] Fix transpose axis and make contigous --- build/cpu.o | Bin 5864 -> 5952 bytes build/libtensor.so | Bin 90336 -> 90576 bytes build/tensor.o | Bin 27496 -> 30472 bytes norch/__pycache__/tensor.cpython-38.pyc | Bin 9287 -> 9716 bytes .../__pycache__/functions.cpython-38.pyc | Bin 3473 -> 3501 bytes norch/autograd/functions.py | 2 +- norch/csrc/cpu.cpp | 43 +++---- norch/csrc/cpu.h | 5 +- norch/csrc/tensor.cpp | 117 +++++++++++++++++- norch/csrc/tensor.h | 3 + norch/tensor.py | 22 ++++ test.py | 60 ++++++++- 12 files changed, 217 insertions(+), 35 deletions(-) diff --git a/build/cpu.o b/build/cpu.o index 9f7b57930e478ea0ee1a31a6f42d792b6e0c7593..7a91d37602354ea58213790f208f86a99f5b21a2 100644 GIT binary patch delta 852 zcmZus&ubGw7@b+P$u6n8n=}DIikE^OENu!dG>0VWz<}V*iUmmv78RitQ%|yl5EYlD zP#A??1pNd2MLZO}Br2p9gdPKeEMj15a|mP)p#CIEP z_V)Btl)aC{$EcmtY{YIW^Q8})*FJUC$-~RkYEjE{sddkxHgSc-BE7K59kEEiK{^PI zO*$FUGnX2~6Rnpaee_C|t1Bvv79ynlZ%7*s%f zbiV*M_9`+}T~m%rR||ZM9Mc|2=f}sSg;*qt&)>tkUZ{1ksgKR-hSGV;UoDRHv9!7yD5&uFj|KKf| z{fd9bdG;k?$ZvFEc!tRn1}?MwL>6ip>H}7X`k3Kl7QbV8sN1ZZ%qmSqOdyHvCeO;w gaKTL`rwrU=`BYY3QibFavr>ja6QWy3Y&S9a8^D_fga7~l delta 823 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 literal 27496 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 diff --git a/norch/autograd/__pycache__/functions.cpython-38.pyc b/norch/autograd/__pycache__/functions.cpython-38.pyc index 033c83cd1c60857fd83e6998a3a3a94772fda7bd..d4ada96281c09dfbe6efc6f96498b279b4440368 100644 GIT binary patch delta 245 zcmbOzy;hnxl$V!_0SH*UOw+tK@@{1hV+Hb@fw));NYpT7F~l&{GSxEIFxD_HU`%05 zVOq!}z)-^kW7jYWFr+gDGiWmVz5EXZFaH4vO{O9ipzd3oB}IvO#Rd7rshj_>OEEIa zO@7NNK3R{m5Xf4<87n9YRHO#73#6KZk%MLO25zU#0bKr!!ty{7JtQgSBKgS;Ob(Mj xal0}qfQ|9ziC|Qmyn?4#SRJU&3`MQ_WIbL5ZjkXsAcKn3C;M}VPcGn91OVD!IF$eZ delta 217 zcmZ20JyDuBl$V!_0SMRxP11BX@@{3fVg~Y@fw))>NYpT7F~l&{GSxEIFxD_nUPC;au2T}02ogthX4Qo diff --git a/norch/autograd/functions.py b/norch/autograd/functions.py index bd52020..7ba219f 100644 --- a/norch/autograd/functions.py +++ b/norch/autograd/functions.py @@ -33,7 +33,7 @@ class MatmulBackward: def backward(self, gradient): x, y = self.input - return [gradient @ y.T, x.T @ gradient] + return [gradient @ y.transpose(-1,-2), x.transpose(-1,-2) @ gradient] class PowBackward: def __init__(self, x, power): diff --git a/norch/csrc/cpu.cpp b/norch/csrc/cpu.cpp index f0ad525..c45a8e9 100644 --- a/norch/csrc/cpu.cpp +++ b/norch/csrc/cpu.cpp @@ -116,7 +116,14 @@ void zeros_like_tensor_cpu(Tensor* tensor, float* result_data) { } } -/*void transpose_tensor_cpu(Tensor* tensor, float* result_data) { +void transpose_1D_tensor_cpu(Tensor* tensor, float* result_data) { + + for (int i = 0; i < tensor->shape[0]; i++) { + result_data[i] = tensor->data[i]; + } +} + +void transpose_2D_tensor_cpu(Tensor* tensor, float* result_data) { int rows = tensor->shape[0]; int cols = tensor->shape[1]; @@ -125,33 +132,17 @@ void zeros_like_tensor_cpu(Tensor* tensor, float* result_data) { result_data[j * rows + i] = tensor->data[i * cols + j]; } } -}*/ +} +void transpose_3D_tensor_cpu(Tensor* tensor, float* result_data) { + int depth = tensor->shape[0]; + int rows = tensor->shape[1]; + int cols = tensor->shape[2]; -void transpose_tensor_cpu(Tensor* tensor, float* result_data) { - int* shape = tensor->shape; - int ndim = tensor->ndim; - int* strides = (int*)malloc(ndim * sizeof(int)); - int* indices = (int*)calloc(ndim, sizeof(int)); - - strides[ndim - 1] = 1; - for (int i = ndim - 2; i >= 0; i--) { - strides[i] = strides[i + 1] * shape[i + 1]; - } - - int idx_result; - for (int idx_source = 0; idx_source < tensor->size; idx_source++) { - idx_result = 0; - for (int dim = 0; dim < ndim; dim++) { - idx_result += indices[dim] * strides[dim]; - } - result_data[idx_result] = tensor->data[idx_source]; - - indices[ndim - 1]++; - for (int dim = ndim - 1; dim > 0; dim--) { - if (indices[dim] == shape[dim]) { - indices[dim] = 0; - indices[dim - 1]++; + for (int i = 0; i < depth; i++) { + for (int j = 0; j < rows; j++) { + for (int k = 0; k < cols; k++) { + result_data[k * rows * depth + j * depth + i] = tensor->data[i * rows * cols + j * cols + k]; } } } diff --git a/norch/csrc/cpu.h b/norch/csrc/cpu.h index ae3eae5..a3c5879 100644 --- a/norch/csrc/cpu.h +++ b/norch/csrc/cpu.h @@ -14,7 +14,10 @@ void pow_tensor_cpu(Tensor* tensor, float power, float* result_data); void scalar_mul_tensor_cpu(Tensor* tensor, float scalar, float* result_data); void ones_like_tensor_cpu(Tensor* tensor, float* result_data); void zeros_like_tensor_cpu(Tensor* tensor, float* result_data); -void transpose_tensor_cpu(Tensor* tensor, float* result_data); +void transpose_1D_tensor_cpu(Tensor* tensor, float* result_data); +void transpose_2D_tensor_cpu(Tensor* tensor, float* result_data); +void transpose_3D_tensor_cpu(Tensor* tensor, float* result_data); +void transpose_axes_cpu(Tensor* tensor, float* result_data, int axis1, int axis2, int* new_shape); void assign_tensor_cpu(Tensor* tensor, float* result_data); #endif /* CPU_H */ diff --git a/norch/csrc/tensor.cpp b/norch/csrc/tensor.cpp index f85759e..03cc657 100644 --- a/norch/csrc/tensor.cpp +++ b/norch/csrc/tensor.cpp @@ -60,6 +60,15 @@ extern "C" { } printf("]\n"); + printf("Strides: ["); + for (int i = 0; i < ndim; i++) { + printf("%d", tensor->strides[i]); + if (i < ndim - 1) { + printf(", "); + } + } + printf("]\n"); + /*printf("Data:\n["); for (int i = 0; i < stride; i++) { printf("%.2f", tensor->data[i]); @@ -715,8 +724,112 @@ extern "C" { fprintf(stderr, "Memory allocation failed\n"); exit(1); } - transpose_tensor_cpu(tensor, result_data); + switch (ndim) { + case 1: + transpose_1D_tensor_cpu(tensor, result_data); + break; + case 2: + transpose_2D_tensor_cpu(tensor, result_data); + break; + case 3: + transpose_3D_tensor_cpu(tensor, result_data); + break; + default: + fprintf(stderr, "Transpose only supports tensors up to 3 dimensions.\n"); + exit(-1); + } return create_tensor(result_data, shape, ndim, device); } } -} + + Tensor* transpose_axes_tensor(Tensor* tensor, int axis1, int axis2) { + char* device = (char*)malloc(strlen(tensor->device) + 1); + if (device != NULL) { + strcpy(device, tensor->device); + } else { + fprintf(stderr, "Memory allocation failed\n"); + exit(-1); + } + + int ndim = tensor->ndim; + int* shape = (int*)malloc(ndim * sizeof(int)); + if (shape == NULL) { + fprintf(stderr, "Memory allocation failed\n"); + exit(-1); + } + + for (int i = 0; i < ndim; i++) { + shape[i] = tensor->shape[i]; + } + + shape[axis1] = tensor->shape[axis2]; + shape[axis2] = tensor->shape[axis1]; + + int size = tensor->size; + + if (strcmp(tensor->device, "cuda") == 0) { + + float* result_data; + cudaMalloc((void **)&result_data, size * sizeof(float)); + //transpose_axes_cuda(tensor, result_data); + return create_tensor(result_data, shape, ndim, device); + } + else { + float* result_data = (float*)malloc(size * sizeof(float)); + if (result_data == NULL) { + fprintf(stderr, "Memory allocation failed\n"); + exit(1); + } + //transpose_axes_cpu(tensor, result_data, axis1, axis2, shape); + assign_tensor_cpu(tensor, result_data); + + Tensor* new_tensor = create_tensor(result_data, shape, ndim, device); + for (int i = 0; i < ndim; i++) { + new_tensor->strides[i] = tensor->strides[i]; + } + new_tensor->strides[axis1] = tensor->strides[axis2]; + new_tensor->strides[axis2] = tensor->strides[axis1]; + make_contiguous(new_tensor); + return new_tensor; + } + } + + void make_contiguous(Tensor* tensor) { + float* new_data = (float*)malloc(tensor->size * sizeof(float)); + if (new_data == NULL) { + // Handle memory allocation failure + return; + } + + int* new_strides = (int*)malloc(tensor->ndim * sizeof(int)); + if (new_strides == NULL) { + free(new_data); + // Handle memory allocation failure + return; + } + + // Calculate new strides assuming C-contiguous order + int stride = 1; + for (int i = tensor->ndim - 1; i >= 0; i--) { + new_strides[i] = stride; + stride *= tensor->shape[i]; + } + + // Rearrange data + for (int i = 0; i < tensor->size; i++) { + int index = 0; + int offset = i; + for (int j = 0; j < tensor->ndim; j++) { + index += (offset / new_strides[j]) * tensor->strides[j]; + offset %= new_strides[j]; + } + new_data[i] = tensor->data[index]; + } + + // Free old data and update tensor properties + free(tensor->data); + free(tensor->strides); + tensor->data = new_data; + tensor->strides = new_strides; + } + } diff --git a/norch/csrc/tensor.h b/norch/csrc/tensor.h index aa8d3e9..dab0b23 100644 --- a/norch/csrc/tensor.h +++ b/norch/csrc/tensor.h @@ -26,6 +26,9 @@ extern "C" { void to_device(Tensor* tensor, char* device); Tensor* ones_like_tensor(Tensor* tensor); Tensor* zeros_like_tensor(Tensor* tensor); + Tensor* transpose_tensor(Tensor* tensor); + Tensor* transpose_axes_tensor(Tensor* tensor, int axis1, int axis2); + void make_contiguous(Tensor* tensor); } #endif /* TENSOR_H */ diff --git a/norch/tensor.py b/norch/tensor.py index d22aa91..2b637c0 100644 --- a/norch/tensor.py +++ b/norch/tensor.py @@ -383,6 +383,28 @@ class Tensor: return result_data + def transpose(self, axis1, axis2): + if axis1 < 0: + axis1 = self.ndim + axis1 + if axis2 < 0: + axis2 = self.ndim + axis2 + + Tensor._C.transpose_axes_tensor.argtypes = [ctypes.POINTER(CTensor), ctypes.c_int, ctypes.c_int] + Tensor._C.transpose_axes_tensor.restype = ctypes.POINTER(CTensor) + + result_tensor_ptr = Tensor._C.transpose_axes_tensor(self.tensor, axis1, axis2) + + result_data = Tensor() + result_data.tensor = result_tensor_ptr + result_data.shape = self.shape.copy() + result_data.shape[axis1] = self.shape[axis2] + result_data.shape[axis2] = self.shape[axis1] + result_data.ndim = self.ndim + result_data.device = self.device + + return result_data + + @property def T(self): Tensor._C.transpose_tensor.argtypes = [ctypes.POINTER(CTensor)] diff --git a/test.py b/test.py index e86e5c2..22a0621 100644 --- a/test.py +++ b/test.py @@ -28,22 +28,72 @@ if __name__ == "__main__": [[7.890, 8.901], [9.012, 1.234], [2.345, 3.456]] ], requires_grad=True) - b = norch.Tensor([ + b = norch.Tensor([[ [1.234, 2.123, 1.5], [5.678, 6.789, 1.293], [3.635, 4.456, 1.0202], [7.890, 8.901, 1.91], - ]) + ],[ + [1.234, 2.123, 1.5], + [5.678, 6.789, 1.293], + [3.635, 4.456, 1.0202], + [7.890, 8.901, 1.91], + ],[ + [1.234, 2.123, 1.5], + [5.678, 6.789, 1.293], + [3.635, 4.456, 1.0202], + [7.890, 8.901, 1.91], + ],[ + [1.234, 2.123, 1.5], + [5.678, 6.789, 1.293], + [3.635, 4.456, 1.0202], + [7.890, 8.901, 1.91], + ],[ + [1.234, 2.123, 1.5], + [5.678, 6.789, 1.293], + [3.635, 4.456, 1.0202], + [7.890, 8.901, 1.91], + ]]) + #print(a.T) + #print(a.T.shape) + #[5, 3, 2] [4, 3] [5, 4, 2] + #print(a.shape, b.shape) #b = norch.Tensor([ # [1.234, 2.123, 1.5]]) + #result = b @ a - #print(a.shape) - c = a.reshape([2,3,5]) - print(b @ c) + + #### testar transpose axes!!!! make it contiguous + + tensor1 = norch.Tensor([[[1, 2], [3, 4], [5, 6]], + [[7, 8], [9, 10], [11, 12]], + [[13, 14], [15, 16], [17, 18]], + [[19, 20], [21, 22], [23, 24]], + [[25, 26], [27, 28], [29, 30]]]) + + # Reshape tensor1 to 2x3x5 + reshaped_tensor = tensor1.transpose(1, 0) + + # Create a 5x4 tensor + tensor2 = norch.Tensor([[1, 2, 3], + [5, 6, 7], + [9, 10, 11], + [13, 14, 15], + [17, 18, 19]]) + + tensor2 = tensor2.transpose(1,0) + + + # Multiply reshaped_tensor by tensor2 + result = tensor2 @ reshaped_tensor + print(result) + + #print(a.shape, b.shape, result.shape) #c = result.sum() #c.backward() #print(a.grad) + #print(a.transpose(2,1)) #a = norch.Tensor([[1, 2, 3], [1, 2, 3], [1, 2, 3]])#.to("cuda") #b = Tensor([[1, 2, 3], [1, 2, 3], [1, 2, 3]])#.to("cuda") From bd1e62d895308ce52b8518ccd1302ae636db4079 Mon Sep 17 00:00:00 2001 From: lucasdelimanogueira Date: Sat, 4 May 2024 13:47:20 -0300 Subject: [PATCH 7/7] Add transpose autograd --- norch/__pycache__/tensor.cpython-38.pyc | Bin 9716 -> 9779 bytes .../__pycache__/functions.cpython-38.pyc | Bin 3501 -> 3949 bytes norch/autograd/functions.py | 11 ++++++++++- norch/tensor.py | 4 ++++ test.py | 14 ++++++++++---- 5 files changed, 24 insertions(+), 5 deletions(-) diff --git a/norch/__pycache__/tensor.cpython-38.pyc b/norch/__pycache__/tensor.cpython-38.pyc index 6c43e0a5597bd7b8e29cca3bf37e72c27c0371b0..8ee1ec72baa33d99229ba9822f36b728bf824b5d 100644 GIT binary patch delta 136 zcmez3z1fE^l$V!_0SG+P%+h*nHu4=;WIQqXn&KKwhAh4smUtk};ww5*!e7Hs!&t-A z%nTG0s9_0a&}8x}Vg%~b6r9|z6d_e43uH$Lh7={{6&K_er#dAjXO|}yr4-3eexl^a is4`hiS&@~4k&TgWvzszABjcRSUMhBsj8c<3RkHyipCrWq delta 75 zcmdn&^TnGll$V!_0SH9AP1BxPZ{$0!$hcSMIaGBP0q;yyqb(!lNq_hC-?C3 RiwFQk`PhMw1B^L9Gyuf;MKu5b delta 77 zcmaDWw^o`jl$V!_0SH*UOw+vCCi2NJmQ2(xW=jzWX3!LzJdw$6W