From 31be051028fda68df97af1f093c2b0580859a410 Mon Sep 17 00:00:00 2001 From: lucasdelimanogueira Date: Thu, 2 May 2024 19:13:05 -0300 Subject: [PATCH] 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 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 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()