From ca4a0f0dbcf6d11c10551b09eb17a1d35730098b Mon Sep 17 00:00:00 2001 From: lucasdelimanogueira Date: Mon, 6 May 2024 01:21:18 -0300 Subject: [PATCH] nn module, log, div, pow --- build/cpu.o | Bin 5952 -> 6944 bytes build/cuda.cu.o | Bin 57656 -> 81040 bytes build/libtensor.so | Bin 90576 -> 116928 bytes build/tensor.o | Bin 30472 -> 35952 bytes norch/__pycache__/tensor.cpython-38.pyc | Bin 9779 -> 11155 bytes .../__pycache__/functions.cpython-38.pyc | Bin 3949 -> 5006 bytes norch/autograd/functions.py | 46 +++++- norch/csrc/cpu.cpp | 32 +++- norch/csrc/cpu.h | 6 +- norch/csrc/cuda.cu | 100 ++++++++++- norch/csrc/cuda.h | 16 +- norch/csrc/tensor.cpp | 156 +++++++++++++++++- norch/csrc/tensor.h | 6 +- norch/nn/__init__.py | 2 + norch/nn/activation.py | 20 +++ norch/nn/module.py | 81 +++++++++ norch/nn/modules/linear.py | 18 ++ norch/nn/parameter.py | 14 ++ norch/tensor.py | 91 +++++++++- test.py | 3 + 20 files changed, 567 insertions(+), 24 deletions(-) create mode 100644 norch/nn/__init__.py create mode 100644 norch/nn/activation.py create mode 100644 norch/nn/module.py create mode 100644 norch/nn/modules/linear.py create mode 100644 norch/nn/parameter.py diff --git a/build/cpu.o b/build/cpu.o index 7a91d37602354ea58213790f208f86a99f5b21a2..62896863668b1029f33c162bb08ca4203ec8c0a9 100644 GIT binary patch delta 1543 zcmZvaT}V_x6oBW>mbUJ-yXyXEiM#bsn@DAZKOn39+_*#!Q5mGp)qb zj}Ew>75|pJ^Gc4I(xTn7TC`(oLQNACEvC-KYDy~Aba(a5up4qEcaB|6%_|L~=uRSP zTAF(f&!l5gL)=E+uL`pyGngcaNfHxkiYH0xNmAV!CQNEE601#VO&_($u7T5?XH|jj1z=FA-ACj{IOar1XqLEfF;(%?`*X9_a^E${xCgLY-VheH6M-X%udwIz{8J z1+$IQMfNUTyFh&QEh*pJ{OY zj|rjV1`MusOApvu%9608Q{1V?@FgEOKZ^IsME`%(b1W+Si(4nS^_1>INH(_2vTd^( z-~i{_IlsiY#`zJ>$2bpg-o^RGECbx(e8AxA$uKvtyJGT&2i&*8A?0!Tj?(s~U`z0P zp!xL0z=acM+gr~En%X)-2g{D=hl3#!sM}G>EzC*xho4HncPX~5wR5FdxNY|qFU2w^ zUJDC|{2{$S>CTqclQ3*|S(tudU)VpwZ+R8A?8GmWWEj?T;iNoJbwZ796rVX delta 871 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 Ta{leZalU2SF$K$`!TbLg)@8Jr diff --git a/build/libtensor.so b/build/libtensor.so index 5722336207b325f0f2c2a58803f5a41f4af3ac46..2bb1564f478c6be5123ab717a2b0fa50fe8944f5 100755 GIT binary patch literal 116928 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 S(D5B#QinS!{gVH0AOC;a4o=+w delta 5625 zcmZ`-3vg8B72dl7gBccBF#NfId1%ytG;#q$Mv_QSbRq=`c*!4&pf2_WZB<^)mOL+1=dl zJKuTy=lpkX_McCLyU#k0mV~=gnVFHvgS{de89ZJxd;H+U`KL$IyvjVMf@&)ZoRt)> zEC_cv^jSrI_$i0ZR^~fz(_v4yuzLSmz2{N(X5m$h);?=zX!}A_-Q5O{&(ip(j{dBds=?-4I>Yp0 z&7sB3iMG{S);FaREuqyv_OAcoa`n2c^|3q3?p9pG9SxG6hjjDS|FMIqCC8n?Wwldt zYwn+{!_4H5@%*~*AHA9kF00|pLZ?kx+YQcDho*!5!xUX7V*7#31@^6gC?EQwOgBXz z0Y4b!n2h3{0X7OzzNOB!!ku~)lLVy@(`1JAsa`6STR0 zocmya=1Hk>pFs`88=x4od*wFplG#M~WwUvKiq;GF_lC8*JWiVOdY|gni<-lroye%w z9`mUVC=K@r?B$=a6_xUukfEK8p-4tC+wqJ9SF|#|-cD`LWZxPUDNzQNdRI9307; zz76mzz;gh9S(WjQVf|%%VQ_yLN5LDG@fF}$#s$DjK)gLH<;WSISDrN zod);kmNvM}t;3A?KJbIX*H6ht;e8w6ZR|7-$;*1PxA0ubZWL~TVP$Su*9}y(NjUe= z5ZkQwd9a6Jv-Gf|HNZm`;CLAJ0FH;@b-?k4Jq$S7f2nc$cw^K%Z)|Lh_K;ivEp~GZ zb#4-FL~bH4|Na+KbhB`07}h_~bEVdKlQQh#P=JS%%ER9SJYiPtZ8+i$`4#Y_Qi$sV^>^HB{FmoHiQb{pkQp>|hsV*>bnCd`?*&2(TQKmhNct z3~2Yn-fkikO^6!Lu(AuXEL-~$z~=$J7I55?cIrz*zdv&M?&_ zMa^GyY;QTF)| zu-LmdsG8X!U@@Ollw|hb0qi8orug1U zY1ap6e@8Kn`wp;pH#=PE_toI^H<4AF8)qgNXf1Icx~8G zY=PO{PSwob8=#FVZA*Z*Luo%VtnIkHzkNX?yi4DK7VmEn^WUn>r;=Z`BgHh-D!c{2 z;sn+j+~1LUit!FKf(mO)Q6IBiz*a%Tr)5MM+cqwOC*c%j87*(i^P<_sD4%-XDQo1aZ#*eiPv5WJGV= z42F2wi1TDqcts8FpYCatZ5K6jfW=yF1sr?-Gr;i_rm3%8xGw>V^YF1^j~doLp%CE$+Z;g5N^F;t!F#Q{EuFT@KT_~E_VTr-#<^wh&yhd^+P_3`A<7_8vw_S{1R}? z@U;N^Q^0Ql|6}B@0HIL6ItEBg(S*inRoA~__NT!$j*_U6lUrba6x`{RqKX`xkkaPE2W(AMkn# F{tIg3dpiIC diff --git a/norch/__pycache__/tensor.cpython-38.pyc b/norch/__pycache__/tensor.cpython-38.pyc index 8ee1ec72baa33d99229ba9822f36b728bf824b5d..343e53b02b9c13f12ae89187268440238e91e313 100644 GIT binary patch delta 1487 zcmbtUO>Y}T7~Xf*cD8GKcjK=j7sxt^3+W*ZP^gQFdH^I2ZB;3)TDgZ+={TvEG`7am z0?|eW93c@2QE32i!{&|z%AMYOLA_P|2UQOhr(Stx*Kv|I2PAg2@5g*T^SsaO&Utm! zxsuP@2A=PmjgPhpP?z7O&B&XQqBBO*zXt*`+T zKT8(TfHp~*!<0;q;KR%+lT)D;9trG8Ym#Sm`|wC)ggNwNA{x<%ZDRDm*fb*+nL!SH z`Jpp15a$uQeFQE758i{HhQ}99iyvhn0+fNCR$TuLu#8<;_ed-O7|yb3Xh6F##=uH1 z04oIvuu=@l7*RxFZVaryhm7_iqtK0k(HI!*0mJ4EKqG9QK(l0-gQIUKGC?c5xbep2 z)_SiaeA)435_LPDw}jvB`Rg6&_wIDN9U)tMp(2id0NTY>ZLVqKXya<5>modD%G&ra z&FN&h0Lulvn>W^OsB^W7dNxz9HmBoU#9hfKaaPY;R)1G3>Vj|g8%Pau$f62)tim#s zp&T-cS%@6w9ol1&V_Iy(NshD_#2W-RnO-i_@p3a=!$P8lrmNZw6bi7SFr0s;XhDV zm~hD3cMot_v>$sPwePlj?asQ|uFUqcK_JDQmL3-ja4&jQecnS!0+DQ^FrjEN?IoJh zSRuY>2Wbi!I5A~vL{M-#%!E^cg(h{cT>2C}xPs8E5!(NYv0cHw#F+YHW+uC<9~@VW zN=MbDS{lMCro{>%tFK^eK2ZY>>@PA5b>M75vrtG!O>ONFu^E~ofwYep<|E`hf`WsY$uALWjZLozsiPxZxPZ(3!%1-w;8@pWCuBsclCdQ`vuFJK#5S^xk5 delta 426 zcmXAjyG|QX5Qfi;*JizVFEKI~+eMrNw=B-ukQlT3_^_S@N+V+}g-a6pGa(@6uSi ztj;AjB?b_~5W2_?RbmKAgs_iF3zK2Wn^J=Q78btY5W5Mb^+Z>T6S3x{V-XsI>7ih6 zu+K0vOp|FcEha0p_arNvAC$? zi;obE?w9TWE=ITI3cwBhb8GO9(#wNfYkbB&w|hO3?I@7yR36ZemAPq|5FOmI55vO5QE4x9nbax35} z;7Z`CZVg-woC$8;T>!TLt_*I`T>`fRZVp`CT?V%d&H{JNJrC|YxC*$2djZ@9a8+jgUR0Dd-kjxQK2b2KtUZ&}^7zQ#%zKry@4H{y{%FHR4j}^|oVi7>lD* zP14l=+-dCw`(CTp^INxrPJiF?qabWauOmGt^6Z17D3G1q)^-rId__6^DA}aB)j{8aKOYK4))e@GWMmk_d9!|S~RtVnB{?_Zjn^=i@$TGVZ>MBin4idRhhPEky z2c;2@nl_4vT$r#I%|-v4xK|EB^OuewFOA~M7a;U^L4dsuL-YQqvO|Uw}sgr2J62}+MC{n=s1P|8N_Oyn! zgFK?JZi-~fX$VlC41o!|7Qo>GBrIpz!@En8BQxQ!a;N7puRQ98ULi2f=CJ~fesSpN zmnZKy-RcaXTNJ=toLJoz>#%%E>!cY4O=IJ^z#OSM6?xOJc$4y&1&|4+DO3QERR~z8 zs65?pWF|ls?>W(ak*IhrAl{*}>A6=&cbW_U55@>n0DKIBPX9nZ(N7GR-*_r`DL&Kd z2+WKghpw5023j4 zI}@UA1&+)FQ|lFRb1L~LNB(w!-K#-dxNU`?izJZQELosJQ*_HHiS(< zHUL4$7%}P>(V}aFFG4XA>5;LmKi1`4fT<4*S6|c4BbrW12~RpIJv9gVGl5alze3Ov zc~j=X3Cw3)Zw^WWGmXh49M_;ovz%n>YB%iqVdVH7FE+Y<6r0<2b_uLJ3a_>>VLLwj1YzjMu0_>fZiz>~cV4PP4qaAsE7)XSbveQSHIvzT_q?DY@ zbA~pZ>^VGOzB{jYdd!JVU$~?p;EnvQlON*kNCZ=Zc2$9*6dc!vhQ7{HHNa+F9VVMaJk^$itZh!`%2%ZX#eRwwX5MqylXoybW7uYwd4 z+P&^WZ)%!e{A6FWhwwyjd`kO=vOhj|Asu>Y9SH zHn!1pfOt3skctrTlu?3fa9!I&mQ)eKd$MW7b28CAvAwCzG1czByiAt@wr^qmeagsf z&yksIzx-2nSLfEJ@a!Q?<0)G(y^q%D0|S{$&!Yv`ovPGL=dc@Ii`CEdEQ6?e{ZojL zOxly6`W548>aau^W&0W33ILXTNF;y(G}JA5LW6oNFO&V1CeupCEozcF%>*q9Ky@7w z9#BdOl_@zg6IAuv-QRJk27Zo|0g>55I!EedHObU3)on<~4!u6U*JR5x&+~xFJ+6Y_ zW%8nO#D#)PHb7ayVuD4*rP0Cxd5xb9D$9{T%Bom=zL@KP+ n>LGR2#lcVQ*!nX0zsJ}7h6(w}Xz7b{__NUJi{}<=imLn%2zOx9 literal 3949 zcmb_f%Wm676y=bjL|J~uZesV9G>aB$3k%I61&TIsng(6PD5`d26d)K4Wy_IBbx6Un zp=_Fbh`rP=aod%Dp^LWX3`JV9rG|()#*FVBlJ|Ay-nsg9Wo600IBGv^Kdu4)lmB1~@8n_xb z8{D#70k;CK3~p7ffm;Jt0k|Mj$S6!!c^w;MEm2wQ`mAH-qQP<~7KUhKR5(>PSEqeeRn z8-b?0K^z_`Pd3_vpcQw*AlmJpCXVZNf==wZG$!I=h_kH;t9P>(TKXYhz#z@3&38b+ zd~s+t4aHq;;mA~F(1}B(9hj$g(}hPMah{I@V}qNiI(uP%WYf^V>-nymEV*tkl!Gqm zW!L?E;C0g{sz%)m=7cH+OHrQ^SU95+7DqUi-f4lE8gyU}vk<(^!Si>4H;od{fTHsg z=4wmn2kp*-GNGmb9+W{mYQ{7oYI%k(hKu_%b>#r4wdqfoN+pGSqFW2pDIXeX{bVbs?#wI_yf z#M%2d3@H$O1{2XYj*TtjP-M1+VBD-@1rGW)jUKyxcecj)Q76DpD1fy%jk**&i2Rr~Niz%T*8U}v{}R(sI`igX z@d4g=n?VHtxeYOQC@L>E+*t^a)n{JZE0PuO1jOA5zwbE(UQ zal$T%v+HITfN2K;KF);bTY)n2@5cyPiaQG-wDz+f9eI6!5tP(DSTQR>zNW1j zc5$|SP0@Ua@)Y4^Iuz$j3!NUv<^{SA-0q*?LETC!Dz!b0y{-M28~1Pi%a#JMXR<$} zj6C+-St#}!zht#Hk3NNGgLIxFECbU$*U&=eW#;*Uip38S+k4rGzDoZ+$ZERozgQd8 zmt1CK(j)9g{O!P6Rz^c~!?pr|rHx?<7(l~4bk&SmitR$GUt2P-70@MNd}wA^Q2;7l zi{D{pP}zz*`}L~+@uAo&>qbqnIZ(WMbfweDq=>41esize; i++) { @@ -32,6 +33,20 @@ void scalar_mul_tensor_cpu(Tensor* tensor, float scalar, float* result_data) { } } +void scalar_div_tensor_cpu(float scalar, Tensor* tensor, float* result_data) { + + for (int i = 0; i < tensor->size; i++) { + result_data[i] = scalar / tensor->data[i]; + } +} + +void tensor_div_scalar_cpu(Tensor* tensor, float scalar, float* result_data) { + + for (int i = 0; i < tensor->size; i++) { + result_data[i] = tensor->data[i] / scalar; + } +} + void matmul_tensor_cpu(Tensor* tensor1, Tensor* tensor2, float* result_data) { for (int i = 0; i < tensor1->shape[0]; i++) { @@ -85,10 +100,23 @@ void batched_matmul_tensor_cpu(Tensor* tensor1, Tensor* tensor2, float* result_d } } -void pow_tensor_cpu(Tensor* tensor, float power, float* result_data) { +void scalar_pow_tensor_cpu(float base, Tensor* tensor, float* result_data) { for (int i = 0; i < tensor->size; i++) { - result_data[i] = powf(tensor->data[i], power); + result_data[i] = powf(base, tensor->data[i]); + } +} + +void tensor_pow_scalar_cpu(Tensor* tensor, float exponent, float* result_data) { + + for (int i = 0; i < tensor->size; i++) { + result_data[i] = powf(tensor->data[i], exponent); + } +} + +void log_tensor_cpu(Tensor* tensor, float* result_data) { + for (int i = 0; i < tensor->size; i++) { + result_data[i] = logf(tensor->data[i]); } } diff --git a/norch/csrc/cpu.h b/norch/csrc/cpu.h index a3c5879..1cc52fb 100644 --- a/norch/csrc/cpu.h +++ b/norch/csrc/cpu.h @@ -7,10 +7,14 @@ void add_tensor_cpu(Tensor* tensor1, Tensor* tensor2, float* result_data); 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 scalar_div_tensor_cpu(float scalar, Tensor* tensor, float* result_data); +void tensor_div_scalar_cpu(Tensor* tensor, float scalar, 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_pow_tensor_cpu(float base, Tensor* tensor, float* result_data); +void tensor_pow_scalar_cpu(Tensor* tensor, float exponent, float* result_data); +void log_tensor_cpu(Tensor* tensor, 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); diff --git a/norch/csrc/cuda.cu b/norch/csrc/cuda.cu index afa9820..67dc8a0 100644 --- a/norch/csrc/cuda.cu +++ b/norch/csrc/cuda.cu @@ -107,9 +107,6 @@ __host__ void sum_tensor_cuda(Tensor* tensor, float* result_data) { cudaDeviceSynchronize(); } - - - __global__ void sub_tensor_cuda_kernel(float* data1, float* data2, float* result_data, int size) { int i = blockIdx.x * blockDim.x + threadIdx.x; @@ -176,6 +173,50 @@ __host__ void scalar_mul_tensor_cuda(Tensor* tensor, float scalar, float* result cudaDeviceSynchronize(); } +__global__ void scalar_div_tensor_cuda_kernel(float scalar, float* data, float* result_data, int size) { + + int i = blockIdx.x * blockDim.x + threadIdx.x; + if (i < size) { + result_data[i] = scalar / data[i]; + } +} + +__host__ void scalar_div_tensor_cuda(float scalar, Tensor* tensor, float* result_data) { + + int number_of_blocks = (tensor->size + THREADS_PER_BLOCK - 1) / THREADS_PER_BLOCK; + scalar_div_tensor_cuda_kernel<<>>(scalar, tensor->data, result_data, tensor->size); + + cudaError_t error = cudaGetLastError(); + if (error != cudaSuccess) { + printf("CUDA error: %s\n", cudaGetErrorString(error)); + exit(-1); + } + + cudaDeviceSynchronize(); +} + +__global__ void tensor_div_scalar_cuda_kernel(float* data, float scalar, float* result_data, int size) { + + int i = blockIdx.x * blockDim.x + threadIdx.x; + if (i < size) { + result_data[i] = data[i] / scalar; + } +} + +__host__ void tensor_div_scalar_cuda(Tensor* tensor, float scalar, float* result_data) { + + int number_of_blocks = (tensor->size + THREADS_PER_BLOCK - 1) / THREADS_PER_BLOCK; + tensor_div_scalar_cuda_kernel<<>>(tensor->data, scalar, result_data, tensor->size); + + cudaError_t error = cudaGetLastError(); + if (error != cudaSuccess) { + printf("CUDA error: %s\n", cudaGetErrorString(error)); + exit(-1); + } + + cudaDeviceSynchronize(); +} + /*__global__ void matmul_tensor_cuda_kernel(float* data1, float* data2, float* result_data, int rows1, int cols1, int cols2) { int row = blockIdx.y * blockDim.y + threadIdx.y; @@ -258,18 +299,18 @@ __host__ void matmul_tensor_cuda(Tensor* tensor1, Tensor* tensor2, float* result cudaDeviceSynchronize(); } -__global__ void pow_tensor_cuda_kernel(float* data, float power, float* result_data, int size) { +__global__ void tensor_pow_scalar_cuda_kernel(float* data, float exponent, float* result_data, int size) { int i = blockIdx.x * blockDim.x + threadIdx.x; if (i < size) { - result_data[i] = powf(data[i], power); + result_data[i] = powf(data[i], exponent); } } -__host__ void pow_tensor_cuda(Tensor* tensor, float power, float* result_data) { +__host__ void tensor_pow_scalar_cuda(Tensor* tensor, float exponent, float* result_data) { int number_of_blocks = (tensor->size + THREADS_PER_BLOCK - 1) / THREADS_PER_BLOCK; - pow_tensor_cuda_kernel<<>>(tensor->data, power, result_data, tensor->size); + tensor_pow_scalar_cuda_kernel<<>>(tensor->data, exponent, result_data, tensor->size); cudaError_t error = cudaGetLastError(); if (error != cudaSuccess) { @@ -280,6 +321,51 @@ __host__ void pow_tensor_cuda(Tensor* tensor, float power, float* result_data) { cudaDeviceSynchronize(); } +__global__ void scalar_pow_tensor_cuda_kernel(float base, float* data, float* result_data, int size) { + + int i = blockIdx.x * blockDim.x + threadIdx.x; + if (i < size) { + result_data[i] = powf(base, data[i]); + } +} + +__host__ void scalar_pow_tensor_cuda(float base, Tensor* tensor, float* result_data) { + + int number_of_blocks = (tensor->size + THREADS_PER_BLOCK - 1) / THREADS_PER_BLOCK; + scalar_pow_tensor_cuda_kernel<<>>(base, tensor->data, result_data, tensor->size); + + cudaError_t error = cudaGetLastError(); + if (error != cudaSuccess) { + printf("CUDA error: %s\n", cudaGetErrorString(error)); + exit(-1); + } + + cudaDeviceSynchronize(); +} + +__global__ void log_tensor_cuda_kernel(float* data, float* result_data, int size) { + + int i = blockIdx.x * blockDim.x + threadIdx.x; + if (i < size) { + result_data[i] = logf(data[i]); + } +} + +__host__ void log_tensor_cuda(Tensor* tensor, float* result_data) { + + int number_of_blocks = (tensor->size + THREADS_PER_BLOCK - 1) / THREADS_PER_BLOCK; + log_tensor_cuda_kernel<<>>(tensor->data, result_data, tensor->size); + + cudaError_t error = cudaGetLastError(); + if (error != cudaSuccess) { + printf("CUDA error: %s\n", cudaGetErrorString(error)); + exit(-1); + } + + cudaDeviceSynchronize(); +} + + __global__ void ones_like_tensor_cuda_kernel(float* data, float* result_data, int size) { int i = blockIdx.x * blockDim.x + threadIdx.x; diff --git a/norch/csrc/cuda.h b/norch/csrc/cuda.h index 48c87b8..87ef884 100644 --- a/norch/csrc/cuda.h +++ b/norch/csrc/cuda.h @@ -19,11 +19,23 @@ __global__ void scalar_mul_tensor_cuda_kernel(float* data, float scalar, float* result_data, int size); __host__ void scalar_mul_tensor_cuda(Tensor* tensor, float scalar, float* result_data); + __global__ void scalar_div_tensor_cuda_kernel(float scalar, float* data, float* result_data, int size); + __host__ void scalar_div_tensor_cuda(float scalar, Tensor* tensor, float* result_data); + + __global__ void tensor_div_scalar_cuda_kernel(float* data, float scalar, float* result_data, int size); + __host__ void tensor_div_scalar_cuda(Tensor* tensor, float scalar, float* result_data); + __global__ void matmul_tensor_cuda_kernel(float* data1, float* data2, float* result_data, int rows1, int cols1, int cols2); __host__ void matmul_tensor_cuda(Tensor* tensor1, Tensor* tensor2, float* result_data); - __global__ void pow_tensor_cuda_kernel(float* data, float power, float* result_data, int size); - __host__ void pow_tensor_cuda(Tensor* tensor, float power, float* result_data); + __global__ void tensor_pow_scalar_cuda_kernel(float* data, float exponent, float* result_data, int size); + __host__ void tensor_pow_scalar_cuda(Tensor* tensor, float exponent, float* result_data); + + __global__ void scalar_pow_tensor_cuda_kernel(float base, float* data, float* result_data, int size); + __host__ void scalar_pow_tensor_cuda(float base, Tensor* tensor, float* result_data); + + __global__ void log_tensor_cuda_kernel(float* data, float* result_data, int size); + __host__ void log_tensor_cuda(Tensor* tensor, float* result_data); __global__ void ones_like_tensor_cuda_kernel(float* data, float* result_data, int size); __host__ void ones_like_tensor_cuda(Tensor* tensor, float* result_data); diff --git a/norch/csrc/tensor.cpp b/norch/csrc/tensor.cpp index 03cc657..05232d0 100644 --- a/norch/csrc/tensor.cpp +++ b/norch/csrc/tensor.cpp @@ -335,6 +335,82 @@ extern "C" { } } + Tensor* scalar_div_tensor(float scalar, Tensor* tensor) { + + 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]; + } + + if (strcmp(tensor->device, "cuda") == 0) { + + float* result_data; + cudaMalloc((void **)&result_data, tensor->size * sizeof(float)); + scalar_div_tensor_cuda(scalar, tensor, result_data); + return create_tensor(result_data, shape, ndim, device); + } + else { + float* result_data = (float*)malloc(tensor->size * sizeof(float)); + if (result_data == NULL) { + fprintf(stderr, "Memory allocation failed\n"); + exit(1); + } + scalar_div_tensor_cpu(scalar, tensor, result_data); + return create_tensor(result_data, shape, ndim, device); + } + } + + Tensor* tensor_div_scalar(Tensor* tensor, float scalar) { + + 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]; + } + + if (strcmp(tensor->device, "cuda") == 0) { + + float* result_data; + cudaMalloc((void **)&result_data, tensor->size * sizeof(float)); + tensor_div_scalar_cuda(tensor, scalar, result_data); + return create_tensor(result_data, shape, ndim, device); + } + else { + float* result_data = (float*)malloc(tensor->size * sizeof(float)); + if (result_data == NULL) { + fprintf(stderr, "Memory allocation failed\n"); + exit(1); + } + tensor_div_scalar_cpu(tensor, scalar, result_data); + return create_tensor(result_data, shape, ndim, device); + } + } + Tensor* matmul_tensor(Tensor* tensor1, Tensor* tensor2) { //MxN @ NxP = MxP // Check if tensors have compatible shapes for matrix multiplication @@ -528,7 +604,7 @@ extern "C" { } - Tensor* pow_tensor(Tensor* tensor, float power) { + Tensor* tensor_pow_scalar(Tensor* tensor, float exponent) { char* device = (char*)malloc(strlen(tensor->device) + 1); if (device != NULL) { strcpy(device, tensor->device); @@ -551,7 +627,7 @@ extern "C" { float* result_data; cudaMalloc((void **)&result_data, tensor->size * sizeof(float)); - pow_tensor_cuda(tensor, power, result_data); + tensor_pow_scalar_cuda(tensor, exponent, result_data); return create_tensor(result_data, shape, ndim, device); } else { @@ -560,7 +636,81 @@ extern "C" { fprintf(stderr, "Memory allocation failed\n"); exit(1); } - pow_tensor_cpu(tensor, power, result_data); + tensor_pow_scalar_cpu(tensor, exponent, result_data); + return create_tensor(result_data, shape, ndim, device); + } + } + + Tensor* scalar_pow_tensor(float base, Tensor* tensor) { + 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]; + } + + if (strcmp(tensor->device, "cuda") == 0) { + + float* result_data; + cudaMalloc((void **)&result_data, tensor->size * sizeof(float)); + scalar_pow_tensor_cuda(base, tensor, result_data); + return create_tensor(result_data, shape, ndim, device); + } + else { + float* result_data = (float*)malloc(tensor->size * sizeof(float)); + if (result_data == NULL) { + fprintf(stderr, "Memory allocation failed\n"); + exit(1); + } + scalar_pow_tensor_cpu(base, tensor, result_data); + return create_tensor(result_data, shape, ndim, device); + } + } + + Tensor* log_tensor(Tensor* tensor) { + 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]; + } + + if (strcmp(tensor->device, "cuda") == 0) { + + float* result_data; + cudaMalloc((void **)&result_data, tensor->size * sizeof(float)); + log_tensor_cuda(tensor, result_data); + return create_tensor(result_data, shape, ndim, device); + } + else { + float* result_data = (float*)malloc(tensor->size * sizeof(float)); + if (result_data == NULL) { + fprintf(stderr, "Memory allocation failed\n"); + exit(1); + } + log_tensor_cpu(tensor, result_data); return create_tensor(result_data, shape, ndim, device); } } diff --git a/norch/csrc/tensor.h b/norch/csrc/tensor.h index dab0b23..a9b8f8e 100644 --- a/norch/csrc/tensor.h +++ b/norch/csrc/tensor.h @@ -20,9 +20,13 @@ extern "C" { Tensor* sub_tensor(Tensor* tensor1, Tensor* tensor2); Tensor* elementwise_mul_tensor(Tensor* tensor1, Tensor* tensor2); Tensor* scalar_mul_tensor(Tensor* tensor, float scalar); + Tensor* scalar_div_tensor(float scalar, Tensor* tensor); + Tensor* tensor_div_scalar(Tensor* tensor, float scalar); Tensor* reshape_tensor(Tensor* tensor, int* new_shape, int new_ndim); Tensor* matmul_tensor(Tensor* tensor1, Tensor* tensor2); - Tensor* pow_tensor(Tensor* tensor, float power); + Tensor* tensor_pow_scalar(Tensor* tensor, float exponent); + Tensor* scalar_pow_tensor(float base, Tensor* tensor); + Tensor* log_tensor(Tensor* tensor); void to_device(Tensor* tensor, char* device); Tensor* ones_like_tensor(Tensor* tensor); Tensor* zeros_like_tensor(Tensor* tensor); diff --git a/norch/nn/__init__.py b/norch/nn/__init__.py new file mode 100644 index 0000000..fc6fa1a --- /dev/null +++ b/norch/nn/__init__.py @@ -0,0 +1,2 @@ +from .modules import * +from .activations import * \ No newline at end of file diff --git a/norch/nn/activation.py b/norch/nn/activation.py new file mode 100644 index 0000000..1ab272f --- /dev/null +++ b/norch/nn/activation.py @@ -0,0 +1,20 @@ +from module import Module +import math + +class Activation(Module): + """ + Abstract classes for activations + """ + def __init__(self): + super(Activation, self).__init__() + + def forward(self, x): + raise NotImplementedError + + +class Sigmoid(Activation): + def __init__(self): + super().__init__() + + def forward(self, x): + return 1.0 / (1.0 + (math.e) ** (-x)) \ No newline at end of file diff --git a/norch/nn/module.py b/norch/nn/module.py new file mode 100644 index 0000000..88b408a --- /dev/null +++ b/norch/nn/module.py @@ -0,0 +1,81 @@ +from parameter import Parameter +from collections import OrderedDict +from abc import ABC +import pickle +import json +import inspect +import warnings + +class Module(ABC): + """ + Abstract class for modules + """ + def __init__(self): + self._modules = OrderedDict() + self._params = OrderedDict() + self._grads = OrderedDict() + self.training = True + + def __call__(self, *inputs, **kwargs): + return self.forward(*inputs, **kwargs) + + def train(self): + self.training = True + for param in self.parameters(): + param.requires_grad = True + + def eval(self): + self.training = False + for param in self.parameters(): + param.requires_grad = False + + def parameters(self): + for name, value in inspect.getmembers(self): + if isinstance(value, Parameter): + yield value + elif isinstance(value, Module): + yield from value.parameters() + + def to(self, device): + for parameter in self.parameters(): + parameter.to(device) + + def state_dict(self): + state = OrderedDict() + for i, param in enumerate(self.parameters()): + state[f'param{i}'] = param.tolist() + return state + + def load_state(self, state_dict): + for i, param in self.parameters(): + data = state_dict[f'param{i}'] + if param.shape != data.shape: + warnings.warn(f"The 'state_dict' shape does not match model's parameter shape. " + f"Got {data.shape}, expected {param.shape}.") + param.data = Parameter(data=data) + + def save(self, filename='model.pickle'): + with open(filename, 'wb') as f: + pickle.dump(self, f) + + def save_dict(self, filename='state_dict.json'): + state = self.state_dict() + with open(filename, 'w') as f: + json.dump(state, f) + + def inner_repr(self): + return "" + + def __repr__(self): + string = f"{self.get_name()}(" + tab = " " + modules = self._modules + if modules == {}: + string += f'\n{tab}(parameters): {self.inner_repr()}' + else: + for key, module in modules.items(): + string += f"\n{tab}({key}): {module.get_name()}({module.inner_repr()})" + return f'{string}\n)' + + def get_name(self): + return self.__class__.__name__ \ No newline at end of file diff --git a/norch/nn/modules/linear.py b/norch/nn/modules/linear.py new file mode 100644 index 0000000..032670e --- /dev/null +++ b/norch/nn/modules/linear.py @@ -0,0 +1,18 @@ +from module import Module +from parameter import Parameter + +class Linear(Module): + def __init__(self, input_dim, output_dim): + super().__init__() + self.input_dim = input_dim + self.output_dim = output_dim + self.weight = Parameter(shape=[self.input_dim, self.output_dim]) + self.bias = Parameter(shape=[self.output_dim, 1]) + + def forward(self, x): + z = self.weight @ x + self.bias + return z + + def inner_repr(self): + return f"input_dim={self.input_dim}, output_dim={self.output_dim}, " \ + f"bias={True if self.bias is not None else False}" \ No newline at end of file diff --git a/norch/nn/parameter.py b/norch/nn/parameter.py new file mode 100644 index 0000000..152d951 --- /dev/null +++ b/norch/nn/parameter.py @@ -0,0 +1,14 @@ +from tensor import Tensor +import random + +class Parameter(Tensor): + """ + A parameter is a trainable tensor. + """ + def __init__(self, shape): + data = [] + for dim_size in reversed(shape): + random_dim = [random.random() for _ in range(dim_size)] + data.insert(0, random_dim) + + super().__init__(data, requires_grad=True) \ No newline at end of file diff --git a/norch/tensor.py b/norch/tensor.py index b2844e3..31c5258 100644 --- a/norch/tensor.py +++ b/norch/tensor.py @@ -344,14 +344,93 @@ class Tensor: return result_data - def __pow__(self, power): + def __pow__(self, other): + if isinstance(other, (int, float)): + other = float(other) + Tensor._C.tensor_pow_scalar.argtypes = [ctypes.POINTER(CTensor), ctypes.c_float] + Tensor._C.tensor_pow_scalar.restype = ctypes.POINTER(CTensor) + + result_tensor_ptr = Tensor._C.tensor_pow_scalar(self.tensor, ctypes.c_float(other)) + + result_data = Tensor() + result_data.tensor = result_tensor_ptr + result_data.shape = self.shape.copy() + result_data.ndim = self.ndim + result_data.device = self.device + + result_data.requires_grad = self.requires_grad + if result_data.requires_grad: + result_data.grad_fn = PowBackward(self, other) + + elif isinstance(self, (int, float)): + self = float(self) + Tensor._C.scalar_pow_tensor.argtypes = [ctypes.c_float, ctypes.POINTER(CTensor)] + Tensor._C.scalar_pow_tensor.restype = ctypes.POINTER(CTensor) + + result_tensor_ptr = Tensor._C.scalar_pow_tensor(ctypes.c_float(self), other.tensor) + + result_data = Tensor() + result_data.tensor = result_tensor_ptr + result_data.shape = other.shape.copy() + result_data.ndim = other.ndim + result_data.device = other.device + + result_data.requires_grad = other.requires_grad + if result_data.requires_grad: + result_data.grad_fn = PowBackward(other, self) - power_ctypes = ctypes.c_float(power) + else: + raise ValueError("Tensor to tensor power is not supported") + + return result_data - Tensor._C.pow_tensor.argtypes = [ctypes.POINTER(CTensor), ctypes.c_float] - Tensor._C.pow_tensor.restype = ctypes.POINTER(CTensor) + def __truediv__(self, other): + other = float(other) + Tensor._C.tensor_div_scalar.argtypes = [ctypes.POINTER(CTensor), ctypes.c_float] + Tensor._C.tensor_div_scalar.restype = ctypes.POINTER(CTensor) - result_tensor_ptr = Tensor._C.pow_tensor(self.tensor, power_ctypes) + result_tensor_ptr = Tensor._C.tensor_div_scalar(other.tensor, ctypes.c_float(self)) + + result_data = Tensor() + result_data.tensor = result_tensor_ptr + result_data.shape = self.shape.copy() + result_data.ndim = self.ndim + result_data.device = self.device + + result_data.requires_grad = self.requires_grad + if result_data.requires_grad: + result_data.grad_fn = DivisionBackward(self, other) + + return result_data + + + + def __rtruediv__(self, other): + other = float(other) + + Tensor._C.scalar_div_tensor.argtypes = [ctypes.c_float, ctypes.POINTER(CTensor)] + Tensor._C.scalar_div_tensor.restype = ctypes.POINTER(CTensor) + + result_tensor_ptr = Tensor._C.scalar_div_tensor(ctypes.c_float(other), self.tensor) + + result_data = Tensor() + result_data.tensor = result_tensor_ptr + result_data.shape = self.shape.copy() + result_data.ndim = self.ndim + result_data.device = self.device + + result_data.requires_grad = self.requires_grad + if result_data.requires_grad: + result_data.grad_fn = DivisionBackward(other, self) + + return result_data + + + def log(self): + Tensor._C.log_tensor.argtypes = [ctypes.POINTER(CTensor)] + Tensor._C.log_tensor.restype = ctypes.POINTER(CTensor) + + result_tensor_ptr = Tensor._C.log_tensor(self.tensor) result_data = Tensor() result_data.tensor = result_tensor_ptr @@ -361,7 +440,7 @@ class Tensor: result_data.requires_grad = self.requires_grad if result_data.requires_grad: - result_data.grad_fn = PowBackward(self, power) + result_data.grad_fn = LogBackward(self) return result_data diff --git a/test.py b/test.py index 185fc29..b905f25 100644 --- a/test.py +++ b/test.py @@ -74,6 +74,9 @@ if __name__ == "__main__": [[13, 14], [15, 16], [17, 18]], [[19, 20], [21, 22], [23, 24]], [[25, 26], [27, 28], [29, 30]]], requires_grad=True) + + print(tensor1 / 1) + exit() # Reshape tensor1 to 2x3x5 reshaped_tensor = tensor1.transpose(1, 0)