From 065c6a0f2941b8ef78fd55ca53ae12332ed3bb66 Mon Sep 17 00:00:00 2001 From: lucasdelimanogueira Date: Mon, 6 May 2024 10:18:12 -0300 Subject: [PATCH] fix pow, div, log operations --- build/cpu.o | Bin 6944 -> 7192 bytes build/cuda.cu.o | Bin 81040 -> 87776 bytes build/libtensor.so | Bin 116928 -> 125568 bytes build/tensor.o | Bin 35952 -> 37944 bytes norch/__pycache__/tensor.cpython-38.pyc | Bin 11155 -> 11598 bytes .../__pycache__/functions.cpython-38.pyc | Bin 5006 -> 4983 bytes norch/autograd/functions.py | 7 +- norch/csrc/cpu.cpp | 7 ++ norch/csrc/cpu.h | 1 + norch/csrc/cuda.cu | 22 ++++ norch/csrc/cuda.h | 3 + norch/csrc/tensor.cpp | 51 ++++++++ norch/csrc/tensor.h | 1 + norch/tensor.py | 114 +++++++++++------- test.py | 5 +- 15 files changed, 160 insertions(+), 51 deletions(-) diff --git a/build/cpu.o b/build/cpu.o index 62896863668b1029f33c162bb08ca4203ec8c0a9..9b48aff98fbcbc203d68fea79ed9a7639f36ee59 100644 GIT binary patch delta 970 zcmZ{jO=#3W6vyXHEjDek?Pl3zvXy4BMS>Q^qSnPqDqgCHpa>#}Rj|;4T0e>htJZ=C z4_Nms1q+H)i#oIO1|;Bvd71ZnFO!$|XRfas zUtf&)xVXFgEywK;js08&`^Ij!-K#lj)iB0NgLW<8eOtf+9(F>$1n`p60$q5^31Kh3 za$4aW&Pjg*v#C~ifrV5EpK(trUiu5A`P3a4I4zG?)&PvT z4A?UDJ!$PSR<@G(&P6)DNxYBvuUgGN5HAvcw^;Kt`oSJxI_<+t<=2*}W>=j~o~4@a z#NQA{umPW4m88sbyLw-Mh>{0H$K;={z_dJTGsPY}OG{3`M1 znm4lz4VrwU#20!Yw6Wg(W_PR}>N|2`@ObaRfs?o~(_H%Pa=w*y(GRH^dU7rN(e~&+ zdVtpkKjD__>k%VSo<=TPU}_nOx)a<;v_HX(MCTLS$TFGWBnw{l(t#0RHc>N$ z&pbac<8D`NNi!YBIOq8tX1IqESu@*<2`*>5)Sq#NZGBkPoEI@X#X=DCS*i#k_=?j(Y&ALhxJiUur`4@wkygP?GJ4pkBY~s2&TQG$ WkwaIb8dV#pQDQ_f+Z}|G`vRWtBkw?-DB}DH`8e{SV$K)&MphwJuFzdw{rU`j z<^%RDVb2Znff5d4$UpQ`i7ZyHu{ws;GJ#KP5jp5V-ikbqJc_&@`6cpUSXC+&?KOPfD?B>^eQ}^fpfV6>@NF19EFED diff --git a/build/cuda.cu.o b/build/cuda.cu.o index 6d729b8e0fae6c5726b45d13dea810a6dc41b4d1..3ddee86b8e7ccbe0aaaca907a0382b222dde92f1 100644 GIT binary patch delta 19758 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 M?8@hk{|kWiPL|r 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 D-lQF% delta 17218 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 X{lhmp%23x$gW%6c_4M;Fc;Ej6AbTKB diff --git a/build/libtensor.so b/build/libtensor.so index 2bb1564f478c6be5123ab717a2b0fa50fe8944f5..dacb48e0bb022859616833926ef2ebc1b0eab7bf 100755 GIT binary patch delta 32895 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 R@HBj@d|w5_+7r)A{|DAta*Y50 delta 30405 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 F{(rm+Z-oE= diff --git a/build/tensor.o b/build/tensor.o index 49c51f648ba115371e063717793bc5971b67210b..549b3053d74c85182c4d2542e31123de91538a6b 100644 GIT binary patch delta 7681 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 nK3b4I~2 zJzE_lD5l^(J1nf{6MA@Ssk~9V7af0Sp-4&p%9$=O25?cR>a}hp&yDoLG_Ss)RKO6$$GSHY8LD zdRm>=>dRbQAJBP>ydj!fv-rzc{A65HHA71hCTNV3lw(@6Y2+|HJ^(c=j$ix> D(0EQr delta 1158 zcmc&y&2Jl35Z`$lyBpiPUVkOjsqw~+^U)e;DQTUiD5$Ec3aJRG>6Z&ER@QE_aboNF zg`}_+sE&}R+NxqW1PLLVQzcYHwKpVGwH%OosKhlKN)McR0r4SvV_sa4_zT#l_xrs! zyYrjbnR!sgGsY=h4=MCqE0<~~j^8$Z1qgl2N^lTo*l42U=#H@g<){;N%nhY%Iy1P; zZp5p3XWBWip>&`;=CG5>)FFRZeKZKy@k!*Z{1s1e1KpqpJ!mtrL*87?V;y!>c{Bb7 zYpd-6+|WQ?a)pD+*e4=DBW;R@l;!CM2I8A zITx^3^m_{cJ3@q>{C$PuReCnGuaY48`aVJP5i z_7WV%Yq`zL7lP_6s3$dQ{te)J1@mZT+KN!!ARfz4zAsdo6Qu`K_(+e*Y3V3!)srQU zkWKFz+wIcn93@+n*p%%cjuF##VaSupZ`XyF0k?IeHr_yM$*WR6&udcKj+!75- z^iR#kT9sRinU=NE5LRoo*=%r8b*6^+xU9h$31{(9GC>6z##QUZVmbVJW9>*~VQH1upzb@<#*JKcxLH|1=Ld_9;wdyRs zW80g4bo@BLE&uGqG{7DI`s96pAN+H>p9l6B@S{EZsYT!JSr49)0;h4dn3<}|;{^#9 zB`ivCB`gtaX-(c}R=K#u>-b@D^wkm>=|A9E78=)LnyHzgloq0`Y7s3>n4&dFEY|@# X$$OkungLId^Hh)i<;C94Jt`|sWGXe=3PTt5S!0QX@(`~Uy| delta 375 zcmeya)~C)J%FD~e00hTvEz%}#K$#{z=Gq0euB)%jy zuQ5Nb#iqwFz znk*1~d=Sl|JR1CLKqdnt8xsdpm55J%`s4?^I+M$ICQt6+R$%m-tjwFhx{}GSh;ec& zuQy}hKZ( z1P3DrbCLdJc|M29xB2tgjDbQ$CU65{CuazxvzdSdjVEtplVMDn{7Jx3*a#>P1H>>B zSc{CnCbS7AFs4m@F1Uj+bMgWqH(^ttnp7lp%tfY?e+n6MgIrJqG6cwf$R$46Pgsea Ln~#H!osSa$f!9zh diff --git a/norch/autograd/functions.py b/norch/autograd/functions.py index 3cdf8df..0761d0d 100644 --- a/norch/autograd/functions.py +++ b/norch/autograd/functions.py @@ -64,13 +64,12 @@ class PowBackward: class LogBackward: - def __init__(self, input_tensor): - self.input_tensor = input_tensor + def __init__(self, x): + self.input = [x] def backward(self, gradient): - input_tensor = self.input_tensor - grad_input = gradient / input_tensor + grad_input = gradient / self.input[0] return [grad_input] diff --git a/norch/csrc/cpu.cpp b/norch/csrc/cpu.cpp index 13a658f..ff5995d 100644 --- a/norch/csrc/cpu.cpp +++ b/norch/csrc/cpu.cpp @@ -47,6 +47,13 @@ void tensor_div_scalar_cpu(Tensor* tensor, float scalar, float* result_data) { } } +void tensor_div_tensor_cpu(Tensor* tensor1, Tensor* tensor2, float* result_data) { + + for (int i = 0; i < tensor1->size; i++) { + result_data[i] = tensor1->data[i] / tensor2->data[i]; + } +} + void matmul_tensor_cpu(Tensor* tensor1, Tensor* tensor2, float* result_data) { for (int i = 0; i < tensor1->shape[0]; i++) { diff --git a/norch/csrc/cpu.h b/norch/csrc/cpu.h index 1cc52fb..6e0e2a3 100644 --- a/norch/csrc/cpu.h +++ b/norch/csrc/cpu.h @@ -9,6 +9,7 @@ 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 tensor_div_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); diff --git a/norch/csrc/cuda.cu b/norch/csrc/cuda.cu index 67dc8a0..73efdd2 100644 --- a/norch/csrc/cuda.cu +++ b/norch/csrc/cuda.cu @@ -217,6 +217,28 @@ __host__ void tensor_div_scalar_cuda(Tensor* tensor, float scalar, float* result cudaDeviceSynchronize(); } +__global__ void tensor_div_tensor_cuda_kernel(float* data1, float* data2, float* result_data, int size) { + + int i = blockIdx.x * blockDim.x + threadIdx.x; + if (i < size) { + result_data[i] = data1[i] / data2[i]; + } +} + +__host__ void tensor_div_tensor_cuda(Tensor* tensor1, Tensor* tensor2, float* result_data) { + + int number_of_blocks = (tensor1->size + THREADS_PER_BLOCK - 1) / THREADS_PER_BLOCK; + tensor_div_tensor_cuda_kernel<<>>(tensor1->data, tensor2->data, result_data, tensor1->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; diff --git a/norch/csrc/cuda.h b/norch/csrc/cuda.h index 87ef884..d21beef 100644 --- a/norch/csrc/cuda.h +++ b/norch/csrc/cuda.h @@ -25,6 +25,9 @@ __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 tensor_div_tensor_cuda_kernel(float* data1, float* data2, float* result_data, int size); + __host__ void tensor_div_tensor_cuda(Tensor* tensor1, Tensor* tensor2, 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); diff --git a/norch/csrc/tensor.cpp b/norch/csrc/tensor.cpp index 05232d0..741662e 100644 --- a/norch/csrc/tensor.cpp +++ b/norch/csrc/tensor.cpp @@ -411,6 +411,57 @@ extern "C" { } } + Tensor* tensor_div_tensor(Tensor* tensor1, Tensor* tensor2) { + if (tensor1->ndim != tensor2->ndim) { + fprintf(stderr, "Tensors must have the same number of dimensions %d and %d for element-wise multiplication\n", tensor1->ndim, tensor2->ndim); + 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 = tensor1->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++) { + if (tensor1->shape[i] != tensor2->shape[i]) { + fprintf(stderr, "Tensors must have the same shape %d and %d at index %d for subtraction\n", tensor1->shape[i], tensor2->shape[i], i); + exit(1); + } + shape[i] = tensor1->shape[i]; + } + + if (strcmp(tensor1->device, "cuda") == 0) { + + float* result_data; + cudaMalloc((void **)&result_data, tensor1->size * sizeof(float)); + tensor_div_tensor_cuda(tensor1, tensor2, result_data); + return create_tensor(result_data, shape, ndim, device); + } + else { + float* result_data = (float*)malloc(tensor1->size * sizeof(float)); + if (result_data == NULL) { + fprintf(stderr, "Memory allocation failed\n"); + exit(1); + } + tensor_div_tensor_cpu(tensor1, tensor2, 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 diff --git a/norch/csrc/tensor.h b/norch/csrc/tensor.h index a9b8f8e..90b4d0d 100644 --- a/norch/csrc/tensor.h +++ b/norch/csrc/tensor.h @@ -22,6 +22,7 @@ extern "C" { 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* tensor_div_tensor(Tensor* tensor1, Tensor* tensor2); Tensor* reshape_tensor(Tensor* tensor, int* new_shape, int new_ndim); Tensor* matmul_tensor(Tensor* tensor1, Tensor* tensor2); Tensor* tensor_pow_scalar(Tensor* tensor, float exponent); diff --git a/norch/tensor.py b/norch/tensor.py index 31c5258..633b8ae 100644 --- a/norch/tensor.py +++ b/norch/tensor.py @@ -153,7 +153,8 @@ class Tensor: if self.grad_fn is not None: # not a leaf grads = self.grad_fn.backward(gradient) for tensor, grad in zip(self.grad_fn.input, grads): - tensor.backward(grad) + if isinstance(tensor, Tensor): + tensor.backward(grad) def zero_grad(self): self.grad = None @@ -200,6 +201,9 @@ class Tensor: return self.__str__() def __add__(self, other): + if isinstance(other, (int, float)): + other = other * self.ones_like() + if self.shape != other.shape: raise ValueError("Tensors must have the same shape for addition") @@ -221,6 +225,9 @@ class Tensor: return result_data def __sub__(self, other): + if isinstance(other, (int, float)): + other = other * self.ones_like() + if self.shape != other.shape: raise ValueError("Tensors must have the same shape for subtraction") @@ -345,51 +352,11 @@ class Tensor: return result_data 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) - - else: - raise ValueError("Tensor to tensor power is not supported") - - return result_data - - 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) + 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_div_scalar(other.tensor, ctypes.c_float(self)) + result_tensor_ptr = Tensor._C.tensor_pow_scalar(self.tensor, ctypes.c_float(other)) result_data = Tensor() result_data.tensor = result_tensor_ptr @@ -399,7 +366,62 @@ class Tensor: result_data.requires_grad = self.requires_grad if result_data.requires_grad: - result_data.grad_fn = DivisionBackward(self, other) + result_data.grad_fn = PowBackward(self, other) + + return result_data + + def __rpow__(self, other): + other = float(other) + 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(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 = PowBackward(other, self) + + return result_data + + def __truediv__(self, other): + if isinstance(other, (int, float)): + 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.tensor_div_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 = DivisionBackward(self, other) + + elif isinstance(self, Tensor) and isinstance(other, Tensor): + Tensor._C.tensor_div_tensor.argtypes = [ctypes.POINTER(CTensor), ctypes.POINTER(CTensor)] + Tensor._C.tensor_div_tensor.restype = ctypes.POINTER(CTensor) + + result_tensor_ptr = Tensor._C.tensor_div_tensor(self.tensor, other.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 or other.requires_grad + if result_data.requires_grad: + result_data.grad_fn = DivisionBackward(self, other) return result_data @@ -418,7 +440,7 @@ class Tensor: 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) diff --git a/test.py b/test.py index b905f25..e473a71 100644 --- a/test.py +++ b/test.py @@ -75,7 +75,10 @@ if __name__ == "__main__": [[19, 20], [21, 22], [23, 24]], [[25, 26], [27, 28], [29, 30]]], requires_grad=True) - print(tensor1 / 1) + result = 2 ** tensor1 + result = result.sum() + result.backward() + print(tensor1.grad) exit() # Reshape tensor1 to 2x3x5