From de72cd67ba3db2f66f33c19575ff3685755e9db2 Mon Sep 17 00:00:00 2001 From: lucasdelimanogueira Date: Fri, 17 May 2024 13:15:33 -0300 Subject: [PATCH] sub broadcasted cuda --- build/cpu.o | Bin 11192 -> 11248 bytes build/cuda.cu.o | Bin 120000 -> 130552 bytes build/tensor.o | Bin 42624 -> 43056 bytes norch/__pycache__/tensor.cpython-38.pyc | Bin 15409 -> 15409 bytes .../__pycache__/functions.cpython-38.pyc | Bin 7881 -> 7881 bytes norch/autograd/functions.py | 14 ++-- norch/csrc/cpu.cpp | 8 +- norch/csrc/cpu.h | 2 +- norch/csrc/cuda.cu | 71 ++++++++++++++++-- norch/csrc/cuda.h | 5 +- norch/csrc/tensor.cpp | 27 +++++-- norch/libtensor.so | Bin 160224 -> 172912 bytes tests/test_autograd.py | 21 +++++- tests/test_operations.py | 10 ++- 14 files changed, 128 insertions(+), 30 deletions(-) diff --git a/build/cpu.o b/build/cpu.o index 054ce2e8e0f1664781c7f4b704e9d4f88cb3fc9e..0b75e023751f2236eacd5535a5a69885d1d11141 100644 GIT binary patch delta 1565 zcmbW0Ur19?9LLYun%gY5nc8XQQgga3HMAE~0+ASKMx%lVlY%s&!b&8F!iOBc zUiMH;B1kZrjZCqJ3?*MI_tqc7!akr zAID!B7HRnHtN+fnQizxv;FmEJud%G#poX2ccN+;Iew*W#;XqE7u?rrtT0M&|uop(! z4UruWdsc;=w`;N^PkFzUP;zmT1exXda1QyBS#ssK@N)`(heh%;vLn^VXOVXxKa9M= zngKmTC0s@!Dus;=JwRTREmx@GbI~S{H*c2nLF8-5SGGt#hrG-nH#%dJ{CcM2r*DQ{ z7prYW`Ji3OH)Kb;kWVA;M1EIfIq#ub?~r(b&qaGKR5~VN&ujD)Spx2h^O}A*ATfbjVJaGUW(sG_)9eYDdcKzcwX`z!fxhFYqD}Q zS-)Yz%~}d_IpR&_s(ltB*PqL+;o5V}Luom42JvgF)!cG%;)g&vqa$#(JV;kzf;&}Z zM$sWM#Ipn|Tvc`WRj1BEX$5m))sYe`3Y8m$09RFsoz$tkLb$35DymawV3@0_Zc;jR z8opJq7F8cr;)T4a_iogLj;oqDr{ghb@-U~WfFYea1f5(}zk6DzreVOtXb8qU^Yk4= zymd4M32!5{LGEr3?DK8M(G@;&K*Go1iO);-^HC#h=N=IQJl=*dkE4*t#N5h8tEE_; P>I<}0*3mTxS9<;e>Dnk_ delta 1640 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 diff --git a/build/tensor.o b/build/tensor.o index 5df78192dbfd694f7baea9d517a107fdcdcef5fc..b8560d82b24a628ce8cc4ff6e0ead48af48ba712 100644 GIT binary patch literal 43056 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 AyZ`_I literal 42624 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 delta 405 zcmX|&Pbhw?gw`5`P*Tdl39a2YP+U0p6D}U5a3Ist z{Amp(5$&X0+~nZu;Oydn-%7sqeV(W9_wziqKelVbnx+(p$t1cbHZqzivC}ks;e;X{wIThKE&Jm@#P-tvrwt zXcOvVgR|Bh5@1WdQS{fC3jOnzGKWrXDl>>uamLWWLFWa!S*#wThv#ZPy7;Z0U@)83 zyuc81dLIVpD!IW#_Nk-^i1W+Ui*a_9o?(`srE8euf)T+Cb4Ct}*=6?_u*7%I02bI{ zrm@Ai737Z@$F@jOkf+uwcDdqR#Xb#R3_Be09U;kY-y~8(EzXzKFdB6ndim > tensor2->ndim ? tensor1->ndim : tensor2->ndim; // Calculate strides for broadcasting @@ -75,12 +75,12 @@ void sub_broadcasted_tensor_cpu(Tensor* tensor1, Tensor* tensor2, float* result_ int dim2 = i < tensor2->ndim ? tensor2->shape[tensor2->ndim - max_ndim + i] : 1; strides1[i] = dim1 == broadcasted_shape[i] ? stride1 : 0; strides2[i] = dim2 == broadcasted_shape[i] ? stride2 : 0; - stride1 *= broadcasted_shape[i]; - stride2 *= broadcasted_shape[i]; + stride1 *= (dim1 == broadcasted_shape[i]) ? dim1 : 1; + stride2 *= (dim2 == broadcasted_shape[i]) ? dim2 : 1; } // Perform element-wise addition with broadcasting - for (int i = 0; i < tensor1->size; i++) { + for (int i = 0; i < broadcasted_size; i++) { int index1 = 0, index2 = 0; int linear_index = i; for (int j = max_ndim - 1; j >= 0; j--) { diff --git a/norch/csrc/cpu.h b/norch/csrc/cpu.h index 2a97fd2..be875ed 100644 --- a/norch/csrc/cpu.h +++ b/norch/csrc/cpu.h @@ -7,7 +7,7 @@ void add_tensor_cpu(Tensor* tensor1, Tensor* tensor2, float* result_data); void add_broadcasted_tensor_cpu(Tensor* tensor1, Tensor* tensor2, float* result_data, int* broadcasted_shape, int broadcasted_size); void sum_tensor_cpu(Tensor* tensor, float* result_data, int axis); void sub_tensor_cpu(Tensor* tensor1, Tensor* tensor2, float* result_data); -void sub_broadcasted_tensor_cpu(Tensor* tensor1, Tensor* tensor2, float* result_data, int* broadcasted_shape); +void sub_broadcasted_tensor_cpu(Tensor* tensor1, Tensor* tensor2, float* result_data, int* broadcasted_shape, int broadcasted_size); void elementwise_mul_tensor_cpu(Tensor* tensor1, Tensor* tensor2, float* result_data); void scalar_div_tensor_cpu(float scalar, Tensor* tensor, float* result_data); void tensor_div_scalar_cpu(Tensor* tensor, float scalar, float* result_data); diff --git a/norch/csrc/cuda.cu b/norch/csrc/cuda.cu index 9ebe6d3..467b8cc 100644 --- a/norch/csrc/cuda.cu +++ b/norch/csrc/cuda.cu @@ -71,7 +71,7 @@ __global__ void add_broadcasted_tensor_cuda_kernel(float* data1, float* data2, f result_data[i] = data1[index1] + data2[index2]; } -__host__ void add_broadcasted_tensor_cuda(Tensor* tensor1, Tensor* tensor2, float* result_data, int* broadcasted_shape) { +__host__ void add_broadcasted_tensor_cuda(Tensor* tensor1, Tensor* tensor2, float* result_data, int* broadcasted_shape, int broadcasted_size) { int max_ndim = tensor1->ndim > tensor2->ndim ? tensor1->ndim : tensor2->ndim; int* strides1 = (int*)malloc(max_ndim * sizeof(int)); @@ -87,8 +87,8 @@ __host__ void add_broadcasted_tensor_cuda(Tensor* tensor1, Tensor* tensor2, floa int dim2 = i < tensor2->ndim ? tensor2->shape[tensor2->ndim - max_ndim + i] : 1; strides1[i] = dim1 == broadcasted_shape[i] ? stride1 : 0; strides2[i] = dim2 == broadcasted_shape[i] ? stride2 : 0; - stride1 *= broadcasted_shape[i]; - stride2 *= broadcasted_shape[i]; + stride1 *= (dim1 == broadcasted_shape[i]) ? dim1 : 1; + stride2 *= (dim2 == broadcasted_shape[i]) ? dim2 : 1; } int* d_broadcasted_shape; @@ -104,8 +104,8 @@ __host__ void add_broadcasted_tensor_cuda(Tensor* tensor1, Tensor* tensor2, floa cudaMalloc((void**)&d_strides2, max_ndim * sizeof(int)); cudaMemcpy(d_strides2, strides2, max_ndim * sizeof(int), cudaMemcpyHostToDevice); - int number_of_blocks = (tensor1->size + THREADS_PER_BLOCK - 1) / THREADS_PER_BLOCK; - add_broadcasted_tensor_cuda_kernel<<>>(tensor1->data, tensor2->data, result_data, d_broadcasted_shape, d_strides1, d_strides2, max_ndim, tensor1->size); + int number_of_blocks = (broadcasted_size + THREADS_PER_BLOCK - 1) / THREADS_PER_BLOCK; + add_broadcasted_tensor_cuda_kernel<<>>(tensor1->data, tensor2->data, result_data, d_broadcasted_shape, d_strides1, d_strides2, max_ndim, broadcasted_size); cudaError_t error = cudaGetLastError(); if (error != cudaSuccess) { @@ -187,6 +187,67 @@ __host__ void sub_tensor_cuda(Tensor* tensor1, Tensor* tensor2, float* result_da cudaDeviceSynchronize(); } +__global__ void sub_broadcasted_tensor_cuda_kernel(float* data1, float* data2, float* result_data, int* broadcasted_shape, int* strides1, int*strides2, int max_ndim, int size) { + int i = blockIdx.x * blockDim.x + threadIdx.x; + if (i >= size) return; + + int index1 = 0, index2 = 0; + int linear_index = i; + for (int j = max_ndim - 1; j >= 0; j--) { + int pos = linear_index % broadcasted_shape[j]; + linear_index /= broadcasted_shape[j]; + if (strides1[j] != 0) index1 += pos * strides1[j]; + if (strides2[j] != 0) index2 += pos * strides2[j]; + } + result_data[i] = data1[index1] - data2[index2]; +} + +__host__ void sub_broadcasted_tensor_cuda(Tensor* tensor1, Tensor* tensor2, float* result_data, int* broadcasted_shape, int broadcasted_size) { + int max_ndim = tensor1->ndim > tensor2->ndim ? tensor1->ndim : tensor2->ndim; + + int* strides1 = (int*)malloc(max_ndim * sizeof(int)); + int* strides2 = (int*)malloc(max_ndim * sizeof(int)); + if (strides1 == NULL || strides2 == NULL) { + fprintf(stderr, "Memory allocation failed\n"); + exit(1); + } + + int stride1 = 1, stride2 = 1; + for (int i = max_ndim - 1; i >= 0; i--) { + int dim1 = i < tensor1->ndim ? tensor1->shape[tensor1->ndim - max_ndim + i] : 1; + int dim2 = i < tensor2->ndim ? tensor2->shape[tensor2->ndim - max_ndim + i] : 1; + strides1[i] = dim1 == broadcasted_shape[i] ? stride1 : 0; + strides2[i] = dim2 == broadcasted_shape[i] ? stride2 : 0; + stride1 *= (dim1 == broadcasted_shape[i]) ? dim1 : 1; + stride2 *= (dim2 == broadcasted_shape[i]) ? dim2 : 1; + } + + int* d_broadcasted_shape; + int* d_strides1; + int* d_strides2; + + cudaMalloc((void**)&d_broadcasted_shape, max_ndim * sizeof(int)); + cudaMemcpy(d_broadcasted_shape, broadcasted_shape, max_ndim * sizeof(int), cudaMemcpyHostToDevice); + + cudaMalloc((void**)&d_strides1, max_ndim * sizeof(int)); + cudaMemcpy(d_strides1, strides1, max_ndim * sizeof(int), cudaMemcpyHostToDevice); + + cudaMalloc((void**)&d_strides2, max_ndim * sizeof(int)); + cudaMemcpy(d_strides2, strides2, max_ndim * sizeof(int), cudaMemcpyHostToDevice); + + int number_of_blocks = (broadcasted_size + THREADS_PER_BLOCK - 1) / THREADS_PER_BLOCK; + sub_broadcasted_tensor_cuda_kernel<<>>(tensor1->data, tensor2->data, result_data, d_broadcasted_shape, d_strides1, d_strides2, max_ndim, broadcasted_size); + + cudaError_t error = cudaGetLastError(); + if (error != cudaSuccess) { + printf("CUDA error: %s\n", cudaGetErrorString(error)); + exit(-1); + } + + cudaDeviceSynchronize(); + cudaFree(d_broadcasted_shape); +} + __global__ void elementwise_mul_tensor_cuda_kernel(float* data1, float* data2, 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 5d5e353..f7a883b 100644 --- a/norch/csrc/cuda.h +++ b/norch/csrc/cuda.h @@ -8,7 +8,10 @@ __host__ void add_tensor_cuda(Tensor* tensor1, Tensor* tensor2, float* result_data); __global__ void add_broadcasted_tensor_cuda_kernel(float* data1, float* data2, float* result_data, int* broadcasted_shape, int* strides1, int*strides2, int max_ndim, int size); - __host__ void add_broadcasted_tensor_cuda(Tensor* tensor1, Tensor* tensor2, float* result_data, int* broadcasted_shape); + __host__ void add_broadcasted_tensor_cuda(Tensor* tensor1, Tensor* tensor2, float* result_data, int* broadcasted_shape, int broadcasted_size); + + __global__ void sub_broadcasted_tensor_cuda_kernel(float* data1, float* data2, float* result_data, int* broadcasted_shape, int* strides1, int*strides2, int max_ndim, int size); + __host__ void sub_broadcasted_tensor_cuda(Tensor* tensor1, Tensor* tensor2, float* result_data, int* broadcasted_shape, int broadcasted_size); __global__ void sum_tensor_cuda_kernel(float* data, float* result_data); __host__ void sum_tensor_cuda(Tensor* tensor, float* result_data); diff --git a/norch/csrc/tensor.cpp b/norch/csrc/tensor.cpp index 730d204..824737d 100644 --- a/norch/csrc/tensor.cpp +++ b/norch/csrc/tensor.cpp @@ -157,7 +157,7 @@ extern "C" { if (strcmp(tensor1->device, "cuda") == 0) { float* result_data; cudaMalloc((void **)&result_data, broadcasted_size * sizeof(float)); - add_broadcasted_tensor_cuda(tensor1, tensor2, result_data, broadcasted_shape); + add_broadcasted_tensor_cuda(tensor1, tensor2, result_data, broadcasted_shape, broadcasted_size); return create_tensor(result_data, broadcasted_shape, max_ndim, tensor1->device); } else { @@ -295,16 +295,27 @@ extern "C" { broadcasted_shape[max_ndim - 1 - i] = dim1 > dim2 ? dim1 : dim2; } - // Allocate memory for result tensor - float* result_data = (float*)malloc(tensor1->size * sizeof(float)); - if (result_data == NULL) { - fprintf(stderr, "Memory allocation failed\n"); - exit(1); + int broadcasted_size = 1; + for (int i = 0; i < max_ndim; i++) { + broadcasted_size *= broadcasted_shape[i]; } - sub_broadcasted_tensor_cpu(tensor1, tensor2, result_data, broadcasted_shape); + if (strcmp(tensor1->device, "cuda") == 0) { + float* result_data; + cudaMalloc((void **)&result_data, broadcasted_size * sizeof(float)); + sub_broadcasted_tensor_cuda(tensor1, tensor2, result_data, broadcasted_shape, broadcasted_size); + return create_tensor(result_data, broadcasted_shape, max_ndim, tensor1->device); + } + else { + float* result_data = (float*)malloc(broadcasted_size * sizeof(float)); + if (result_data == NULL) { + fprintf(stderr, "Memory allocation failed\n"); + exit(1); + } - return create_tensor(result_data, broadcasted_shape, max_ndim, tensor1->device); + sub_broadcasted_tensor_cpu(tensor1, tensor2, result_data, broadcasted_shape, broadcasted_size); + return create_tensor(result_data, broadcasted_shape, max_ndim, tensor1->device); + } } Tensor* elementwise_mul_tensor(Tensor* tensor1, Tensor* tensor2) { diff --git a/norch/libtensor.so b/norch/libtensor.so index 9f15e450bdefc73779a4026e40a6c89dcbd07b43..a125f3cf42d7df3c5d394600b7016cafea233f0f 100755 GIT binary patch delta 42610 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 diff --git a/tests/test_autograd.py b/tests/test_autograd.py index 7635e58..8cd105e 100644 --- a/tests/test_autograd.py +++ b/tests/test_autograd.py @@ -58,7 +58,7 @@ class TestTensorAutograd(unittest.TestCase): self.assertTrue(utils.compare_torch(norch_tensor2_grad, torch_tensor2_grad)) - def test_broadcasting_addition_autograd(self): + def test_broadcasted_addition_autograd(self): """ Test autograd for broadcasting addition: tensor1 + tensor2 """ @@ -115,7 +115,7 @@ class TestTensorAutograd(unittest.TestCase): self.assertTrue(utils.compare_torch(norch_tensor1_grad_sub, torch_tensor1_grad_sub)) self.assertTrue(utils.compare_torch(norch_tensor2_grad_sub, torch_tensor2_grad_sub)) - def test_broadcasting_subtraction_autograd(self): + def test_broadcasted_subtraction_autograd(self): """ Test autograd for broadcasting subtraction: tensor1 - tensor2 """ @@ -135,6 +135,23 @@ class TestTensorAutograd(unittest.TestCase): self.assertTrue(utils.compare_torch(norch_tensor1_grad, torch_tensor1_grad)) self.assertTrue(utils.compare_torch(norch_tensor2_grad, torch_tensor2_grad)) + + # reversed order broadcasting + + norch_result = (norch_tensor2 - norch_tensor1).sum() + norch_result.backward() + norch_tensor1_grad = utils.to_torch(norch_tensor1.grad).to(self.device) + norch_tensor2_grad = utils.to_torch(norch_tensor2.grad).to(self.device) + + torch_tensor1 = torch.tensor([[[1., 2, 3], [4, 5, 6]]], requires_grad=True).to(self.device) # Shape (1, 2, 3) + torch_tensor2 = torch.tensor([1.5, -1, 0], requires_grad=True).to(self.device) # Shape (3) + torch_result = (torch_tensor2 - torch_tensor1).sum() + torch_result.backward() + torch_tensor1_grad = torch_tensor1.grad + torch_tensor2_grad = torch_tensor2.grad + + self.assertTrue(utils.compare_torch(norch_tensor1_grad, torch_tensor1_grad)) + self.assertTrue(utils.compare_torch(norch_tensor2_grad, torch_tensor2_grad)) def test_division(self): diff --git a/tests/test_operations.py b/tests/test_operations.py index e7dd833..d6552a6 100644 --- a/tests/test_operations.py +++ b/tests/test_operations.py @@ -52,6 +52,7 @@ class TestTensorOperations(unittest.TestCase): self.assertTrue(utils.compare_torch(torch_result, torch_expected)) + # reversed order broadcasting norch_tensor1 = norch.Tensor([[0, 2]]).to(self.device) norch_tensor2 = norch.Tensor([[3, 4], [5, -1]]).to(self.device) norch_result = norch_tensor1 + norch_tensor2 @@ -61,7 +62,6 @@ class TestTensorOperations(unittest.TestCase): torch_tensor2 = torch.tensor([[3, 4], [5, -1]]).to(self.device) torch_expected = torch_tensor1 + torch_tensor2 - print(torch_result, torch_expected) self.assertTrue(utils.compare_torch(torch_result, torch_expected)) norch_result = norch_tensor2 + norch_tensor1 @@ -101,6 +101,14 @@ class TestTensorOperations(unittest.TestCase): self.assertTrue(utils.compare_torch(torch_result, torch_expected)) + # reversed order broadcasting + norch_result = norch_tensor2 - norch_tensor1 + torch_result = utils.to_torch(norch_result).to(self.device) + + torch_expected = torch_tensor2 - torch_tensor1 + + self.assertTrue(utils.compare_torch(torch_result, torch_expected)) + def test_division_by_scalar(self): """