From 65dc86aaa465f6701795f3eb8c9d246e6f004746 Mon Sep 17 00:00:00 2001 From: lucasdelimanogueira Date: Wed, 22 May 2024 19:20:54 -0300 Subject: [PATCH] broadcasted batched matmul cuda --- build/cpu.o | Bin 15616 -> 15536 bytes build/cuda.cu.o | Bin 153512 -> 161632 bytes norch/__pycache__/__init__.cpython-38.pyc | Bin 365 -> 365 bytes norch/csrc/cpu.cpp | 16 +++----- norch/csrc/cuda.cu | 38 ++++++++++++++++++- norch/csrc/cuda.h | 3 ++ norch/csrc/tensor.cpp | 6 +-- norch/libtensor.so | Bin 199352 -> 216136 bytes tests/test_operations.py | 44 +++++++++++----------- 9 files changed, 71 insertions(+), 36 deletions(-) diff --git a/build/cpu.o b/build/cpu.o index 9e6ddf72119849b4fa9e352ed8e0ba963aa216fd..2ee4a6fbffdf99db5f658e321d6bd26a92b6e34c 100644 GIT binary patch delta 1878 zcmb_bZAesE7(VBkHZ?QenJ{nHG%bq8sWi2mMr9_ci_^!CK6crVC9NL?5mdh_kv=dj zcXrC<-L(vsC8(f3Wz3HX3Y?&A?BmdESrn zKIgnA+WL?7_>}&@O@GV@t?pbHaL#S{FlZzRj!4uPibU6Xq9kY})mWGkGH9d(Ga{Lk z8Y?!LwACllG2mc+X*Kp1@jdG6feF=XOb!|u7D7y|#Tzua{D7HcI&zNbrB=g!ONq^_9`QjE}DhU2*U8UJVepGBRy<)#yo#R?&FNDg`8 zGHtmr9-9Q-4kvw;`n!D29^)J773^Vn?5k9gD!lhq=+C{J-Gn3?G>3;?0gdIFex#72 zJ$xhU1?zxA<=TexMI7EN*b9PvA@GR6?+Sd`d=9h-{JFq?fnm(Gl$DR;CErNJ41NhG`E43uCv94vAzP8oSE{D!^}c!TTDkifOwT(6kO z9rN52U%2WVrBC4IYVCNte13Kd9BgA#ete$|KP*1PW*eRq_O89b{G(RrXZgq25&p}8SMw?JP*coqpTH3+!|yMm>k0LU}y Aa{vGU delta 2043 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 F|9|wt(nSCO diff --git a/norch/__pycache__/__init__.cpython-38.pyc b/norch/__pycache__/__init__.cpython-38.pyc index a6e6d0577b50002818d787ef454614ae8dfa38b8..176d505192d006a204e01bbdff5524e7ed201c38 100644 GIT binary patch delta 102 zcmaFM^p=S$l$V!_0SHpHCvr718c*yo@`_^3FDS{(y~SEul9^K+#hsU5l$=qPS)7@l ycZ)kdzAUu}#Eg%>#T6f)SXz>iUj$?WC6bF$Q!-16^n8^u~$l9^L{i#spBC^@4nvp6$9 zFN!-pzAUu}#Eg%>#T6f)SXz>iUlbn?l1MH}P01`Nj*nl-P{au|vWRms2V*J#*fJtp diff --git a/norch/csrc/cpu.cpp b/norch/csrc/cpu.cpp index 7c96f58..4e27010 100644 --- a/norch/csrc/cpu.cpp +++ b/norch/csrc/cpu.cpp @@ -148,8 +148,7 @@ void matmul_tensor_cpu(Tensor* tensor1, Tensor* tensor2, float* result_data) { void broadcasted_batched_matmul_tensor_cpu(Tensor* tensor1, Tensor* tensor2, float* result_data) { - int tensor2_offset = tensor2->shape[1] * tensor2->shape[2]; - int result_data_offset = tensor1->shape[0] * tensor2->shape[2]; + int result_data_stride = tensor1->shape[0] * tensor2->shape[2]; for (int batch = 0; batch < tensor2->shape[0]; batch++) { @@ -157,19 +156,16 @@ void broadcasted_batched_matmul_tensor_cpu(Tensor* tensor1, Tensor* tensor2, flo 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)]; + sum += tensor1->data[i * tensor1->shape[1] + k] * tensor2->data[batch*tensor2->strides[0] + (k * tensor2->shape[2] + j)]; } - result_data[(batch * result_data_offset) + (i * tensor2->shape[2] + j)] = sum; + result_data[(batch * result_data_stride) + (i * tensor2->shape[2] + j)] = sum; } } } } 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]; + int result_data_stride = tensor1->shape[1] * tensor2->shape[2]; for (int batch = 0; batch < tensor2->shape[0]; batch++) { @@ -177,9 +173,9 @@ void batched_matmul_tensor_cpu(Tensor* tensor1, Tensor* tensor2, float* result_d 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)]; + sum += tensor1->data[(batch * tensor1->strides[0]) + i * tensor1->shape[2] + k] * tensor2->data[batch*tensor2->strides[0] + (k * tensor2->shape[2] + j)]; } - result_data[(batch * result_data_offset) + (i * tensor2->shape[2] + j)] = sum; + result_data[(batch * result_data_stride) + (i * tensor2->shape[2] + j)] = sum; } } } diff --git a/norch/csrc/cuda.cu b/norch/csrc/cuda.cu index da241e4..a2bb8e0 100644 --- a/norch/csrc/cuda.cu +++ b/norch/csrc/cuda.cu @@ -456,7 +456,7 @@ __global__ void batched_matmul_tensor_cuda_kernel(float* data1, float* data2, fl } __host__ void batched_matmul_tensor_cuda(Tensor* tensor1, Tensor* tensor2, float* result_data) { - + int batch_size = tensor2->shape[0]; int rows1 = tensor1->shape[1]; int cols1 = tensor1->shape[2]; @@ -476,6 +476,42 @@ __host__ void batched_matmul_tensor_cuda(Tensor* tensor1, Tensor* tensor2, float cudaDeviceSynchronize(); } +__global__ void broadcasted_batched_matmul_tensor_cuda_kernel(float* data1, float* data2, float* result_data, int batch_size, int rows1, int cols1, int cols2) { + int batch = blockIdx.z; + int row = blockIdx.y * blockDim.y + threadIdx.y; + int col = blockIdx.x * blockDim.x + threadIdx.x; + + if (row < rows1 && col < cols2) { + float sum = 0.0f; + for (int k = 0; k < cols1; ++k) { + sum += data1[row * cols1 + k] * + data2[batch * cols1 * cols2 + k * cols2 + col]; + } + result_data[batch * rows1 * cols2 + row * cols2 + col] = sum; + } +} + +__host__ void broadcasted_batched_matmul_tensor_cuda(Tensor* tensor1, Tensor* tensor2, float* result_data) { + + int batch_size = tensor2->shape[0]; + int rows1 = tensor1->shape[0]; + int cols1 = tensor1->shape[1]; + int cols2 = tensor2->shape[2]; + + dim3 threadsPerBlock(16, 16); + dim3 number_of_blocks((cols2 + threadsPerBlock.x - 1) / threadsPerBlock.x, (rows1 + threadsPerBlock.y - 1) / threadsPerBlock.y, batch_size); + broadcasted_batched_matmul_tensor_cuda_kernel<<>>(tensor1->data, tensor2->data, result_data, batch_size, rows1, cols1, cols2); + + + cudaError_t error = cudaGetLastError(); + if (error != cudaSuccess) { + printf("CUDA error: %s\n", cudaGetErrorString(error)); + exit(-1); + } + + cudaDeviceSynchronize(); +} + __global__ void tensor_pow_scalar_cuda_kernel(float* data, float exponent, 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 7f0f49f..38a6977 100644 --- a/norch/csrc/cuda.h +++ b/norch/csrc/cuda.h @@ -40,6 +40,9 @@ __global__ void batched_matmul_tensor_cuda_kernel(float* data1, float* data2, float* result_data, int batch_size, int rows1, int cols1, int cols2); __host__ void batched_matmul_tensor_cuda(Tensor* tensor1, Tensor* tensor2, float* result_data); + __global__ void broadcasted_batched_matmul_tensor_cuda_kernel(float* data1, float* data2, float* result_data, int batch_size, int rows1, int cols1, int cols2); + __host__ void broadcasted_batched_matmul_tensor_cuda(Tensor* tensor1, Tensor* tensor2, 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); diff --git a/norch/csrc/tensor.cpp b/norch/csrc/tensor.cpp index 6ac29e2..4d4d2fb 100644 --- a/norch/csrc/tensor.cpp +++ b/norch/csrc/tensor.cpp @@ -751,7 +751,7 @@ extern "C" { } Tensor* broadcasted_batched_matmul_tensor(Tensor* tensor1, Tensor* tensor2) { - //MxN @ BATCHxNxP = BATCHxMxP + //BATCHxMxP = MxN @ BATCHxNxP // Check if tensors have compatible shapes for matrix multiplication if (tensor1->shape[1] != 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]); @@ -797,7 +797,7 @@ extern "C" { float* result_data; cudaMalloc((void **)&result_data, size * sizeof(float)); - ////broadcasted_batched_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 { @@ -813,7 +813,7 @@ extern "C" { } Tensor* batched_matmul_tensor(Tensor* tensor1, Tensor* tensor2) { - //BATCHxMxN @ BATCHxNxP = BATCHxMxP + //BATCHxMxP = BATCHxMxN @ BATCHxNxP // Check if tensors have compatible shapes for matrix multiplication if (tensor1->shape[0] != tensor2->shape[0]) { diff --git a/norch/libtensor.so b/norch/libtensor.so index 921564db54ba97b36ed57e04105c92944aee76ca..d9dcf12333e94be3825ce394ac6f583141d9232c 100755 GIT binary patch delta 53175 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 z85≪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

>d?iXl#D@uof>I^lQ}DN*`3vB=f0|0f z2qXUQHT?NtzaB%nabu^};TZ>A4Qedi2nB9AV+2=cOpWn}5$8EjSC7*FLuh%n22Qz! zJ}(>HcxRV3+~uT%RMuZaggfl&m4RaLJOlF&3eR>1@D!rZPxsQtM=*u{TGLaXe+CJU zC#lwmr?#Y=eIjy}#Cmx-Y61hE@P2aChV;cc8T>Wk#Yzt{b>^!7Aa(o9#nKg|oaEpN z87*>@#4^1SUP1}KL-Rc~MEpwn*@yR$t?*EJz|7sx8=Ym=d z=EYwpp2fR(NqxTL=OKsq4%g(d*#AQGt$AAm z<6R#?+7ebZ)FpJ0N^Ch3Vui_=xTy)F;lw9yksij7qc@4aAU^UUzgfgZ zD~V6wzjKM8Dxiw^)4Mr~TACxTf95yuau!=_^mr7|2PIi9+nY5x>z2ITb_t+mb{C_jFtkG z!*9vp+k$%+m))W^i&*;GQQeWKIb0GdW3G!c- z0@X$bbDmdHQa)+?aY|~a>Mv3nu1`rLgG5fL$i5@~L)|koe$g^B+iInvsz$$f$^W}Z z^5PaYqHRfk)2otKwUr|IDAt``=2TbkE5_CX=uW4ST@0VdBB%@hed2c~%6zHL=YTMC z{Yhdcm7zMFSj>!h85UfZ?o_3w5bvVPSv8KK#IK+_%9m!$MSLXn@&kz9Ao(a(y8mz~UtbkT4wnH$y3d-ZpPL_XlU6ajw_R5ao-+M{%jI&F^!{SGW=!%4`sq^ z^iC2_q4VRr<2?9d6~N7A-6088p?48qO2xHTsHbp8n`6(5B{G$~P@!CdOjR5vt=c-JVY z|DFW)BJrVgA$KAEed33R5f0C562DpUce9e4l2O-U4H-DTki4q!^TxPpExwCI;-}U~ zvFHX7?bul6H*J}x8UIv$q!_9OkjBZjvH(<{F^l*cbn%Pl1>j@_@pw&Gxa9Yvc(_cw zgC;(zZX>Z@&g*>6e5t3Jb}PX%>eKzixrlS4I7- zrGaV`KN0`)Wyz~X6rCh9H2sF;RUIc2Kjf_B`_TyuBEGMfCSf|nZ({PW+~|H3{pS{v zXa6l}<*$bL%1Ei-M~YcMGnsyPlH`@Uk;H%fi&Rwo@El_tl1W|#@$IJL+sMrSH))nj zxw|gR@Vg`bI;O?rlcO9G8&TIVc7{|IPlF+vEwx+%dVkzp=FoLWYE?>L>xdsr7wtIW z4-x-TwIozY`x|c@N6uS1q`Pk{DOM*unfPtwzn2uVkBrMaujM4(_=e2 z55`ChH3(cIey&R0sanbA3~jDK}xj{0qddFkyO<)59@{KM#n6Y#4Cjmww) zuK5M)LsPoWb2e*X)c&DGmzUnumgsRgL;s7T7W2k6ja~hm9-ZmrZU4b&4O>`if9BvEbr5Qvo3o_ICBA;$xy> WWeg40?+KptusrVL!@pG5?EeAfD|!?F delta 48963 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

e3e+1zKe32OZ($2+*xSo4pSmfffL* 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 diff --git a/tests/test_operations.py b/tests/test_operations.py index ad11717..d443260 100644 --- a/tests/test_operations.py +++ b/tests/test_operations.py @@ -153,13 +153,13 @@ class TestTensorOperations(unittest.TestCase): """ Test matrix multiplication: tensor1 @ tensor2 """ - norch_tensor1 = norch.Tensor([[[1, 2], [3, 4]], [[5, 6], [7, 8]]]).to(self.device) - norch_tensor2 = norch.Tensor([[[1, 0], [0, 1]], [[-1, 0], [0, -1]]]).to(self.device) + norch_tensor1 = norch.Tensor([[[1., 2], [3, 4]], [[5, 6], [7, 8]]]).to(self.device) + norch_tensor2 = norch.Tensor([[[1., 0], [0, 1]], [[-1, 0], [0, -1]]]).to(self.device) norch_result = norch_tensor1 @ norch_tensor2 torch_result = utils.to_torch(norch_result).to(self.device) - torch_tensor1 = torch.tensor([[[1, 2], [3, 4]], [[5, 6], [7, 8]]]).to(self.device) - torch_tensor2 = torch.tensor([[[1, 0], [0, 1]], [[-1, 0], [0, -1]]]).to(self.device) + torch_tensor1 = torch.tensor([[[1., 2], [3, 4]], [[5, 6], [7, 8]]]).to(self.device) + torch_tensor2 = torch.tensor([[[1., 0], [0, 1]], [[-1, 0], [0, -1]]]).to(self.device) torch_expected = torch_tensor1 @ torch_tensor2 self.assertTrue(utils.compare_torch(torch_result, torch_expected)) @@ -490,15 +490,15 @@ class TestTensorOperations(unittest.TestCase): Test matrix multiplication: MxP = NxM @ MxP """ # Creating batched tensors for Norch - norch_tensor1 = norch.Tensor([[1, 2], [3, -4], [5, 6], [7, 8]]).to(self.device) - norch_tensor2 = norch.Tensor([[2, 3, 1, 0, 4], [5, -1, 2, 3, 0]]).to(self.device) + norch_tensor1 = norch.Tensor([[1., 2], [3, -4], [5, 6], [7, 8]]).to(self.device) + norch_tensor2 = norch.Tensor([[2., 3, 1, 0, 4], [5, -1, 2, 3, 0]]).to(self.device) norch_result = norch_tensor1 @ norch_tensor2 torch_result = utils.to_torch(norch_result).to(self.device) # Converting to PyTorch tensors for comparison - torch_tensor1 = torch.tensor([[1, 2], [3, -4], [5, 6], [7, 8]]).to(self.device) - torch_tensor2 = torch.tensor([[2, 3, 1, 0, 4], [5, -1, 2, 3, 0]]).to(self.device) + torch_tensor1 = torch.tensor([[1., 2], [3, -4], [5, 6], [7, 8]]).to(self.device) + torch_tensor2 = torch.tensor([[2., 3, 1, 0, 4], [5, -1, 2, 3, 0]]).to(self.device) torch_expected = torch.matmul(torch_tensor1, torch_tensor2) @@ -509,14 +509,14 @@ class TestTensorOperations(unittest.TestCase): """ Test reshaping a tensor followed by matrix multiplication: (tensor.reshape(shape) @ other_tensor) """ - norch_tensor = norch.Tensor([[1, 2], [3, -4], [5, 6], [7, 8]]).to(self.device) + norch_tensor = norch.Tensor([[1., 2], [3, -4], [5, 6], [7, 8]]).to(self.device) new_shape = [2, 4] norch_reshaped = norch_tensor.reshape(new_shape) norch_result = norch_reshaped @ norch_tensor torch_result = utils.to_torch(norch_result).to(self.device) - torch_tensor = torch.tensor([[1, 2], [3, -4], [5, 6], [7, 8]]).to(self.device) + torch_tensor = torch.tensor([[1., 2], [3, -4], [5, 6], [7, 8]]).to(self.device) torch_expected = torch_tensor.reshape(new_shape) @ torch_tensor self.assertTrue(utils.compare_torch(torch_result, torch_expected)) @@ -528,15 +528,15 @@ class TestTensorOperations(unittest.TestCase): B = 3 # Batch size # Creating batched tensors for Norch - norch_tensor1 = norch.Tensor([[[1, 2], [3, -4], [5, 6], [7, 8]] for _ in range(B)]).to(self.device) - norch_tensor2 = norch.Tensor([[[2, 3, 1, 0, 4], [5, -1, 2, 3, 0]] for _ in range(B)]).to(self.device) + norch_tensor1 = norch.Tensor([[[1., 2], [3, -4], [5, 6], [7, 8]] for _ in range(B)]).to(self.device) + norch_tensor2 = norch.Tensor([[[2., 3, 1, 0, 4], [5, -1, 2, 3, 0]] for _ in range(B)]).to(self.device) norch_result = norch_tensor1 @ norch_tensor2 torch_result = utils.to_torch(norch_result).to(self.device) # Converting to PyTorch tensors for comparison - torch_tensor1 = torch.tensor([[[1, 2], [3, -4], [5, 6], [7, 8]] for _ in range(B)]).to(self.device) - torch_tensor2 = torch.tensor([[[2, 3, 1, 0, 4], [5, -1, 2, 3, 0]] for _ in range(B)]).to(self.device) + torch_tensor1 = torch.tensor([[[1., 2], [3, -4], [5, 6], [7, 8]] for _ in range(B)]).to(self.device) + torch_tensor2 = torch.tensor([[[2., 3, 1, 0, 4], [5, -1, 2, 3, 0]] for _ in range(B)]).to(self.device) torch_expected = torch.matmul(torch_tensor1, torch_tensor2) @@ -551,15 +551,15 @@ class TestTensorOperations(unittest.TestCase): B = 3 # Batch size # Creating batched tensors for Norch - norch_tensor1 = norch.Tensor([[1, 2], [3, -4], [5, 6], [7, 8]]).to(self.device) - norch_tensor2 = norch.Tensor([[[2, 3, 1, 0, 4], [5, -1, 2, 3, 0]] for _ in range(B)]).to(self.device) + norch_tensor1 = norch.Tensor([[1., 2], [3, -4], [5, 6], [7, 8]]).to(self.device) + norch_tensor2 = norch.Tensor([[[2., 3, 1, 0, 4], [5, -1, 2, 3, 0]] for _ in range(B)]).to(self.device) norch_result = norch_tensor1 @ norch_tensor2 torch_result = utils.to_torch(norch_result).to(self.device) # Converting to PyTorch tensors for comparison - torch_tensor1 = torch.tensor([[1, 2], [3, -4], [5, 6], [7, 8]]).to(self.device) - torch_tensor2 = torch.tensor([[[2, 3, 1, 0, 4], [5, -1, 2, 3, 0]] for _ in range(B)]).to(self.device) + torch_tensor1 = torch.tensor([[1., 2], [3, -4], [5, 6], [7, 8]]).to(self.device) + torch_tensor2 = torch.tensor([[[2., 3, 1, 0, 4], [5, -1, 2, 3, 0]] for _ in range(B)]).to(self.device) torch_expected = torch.matmul(torch_tensor1, torch_tensor2) @@ -572,12 +572,12 @@ class TestTensorOperations(unittest.TestCase): """ Test transposing a tensor followed by matrix multiplication: (tensor.transpose(dim1, dim2) @ other_tensor) """ - norch_tensor = norch.Tensor([[[1, 2], [3, 4]], [[5, 6], [7, 8]]]).to(self.device) + norch_tensor = norch.Tensor([[[1., 2], [3, 4]], [[5, 6], [7, 8]]]).to(self.device) dim1, dim2 = 0, 2 norch_result = norch_tensor.transpose(dim1, dim2) @ norch_tensor torch_result = utils.to_torch(norch_result).to(self.device) - torch_tensor = torch.tensor([[[1, 2], [3, 4]], [[5, 6], [7, 8]]]).to(self.device) + torch_tensor = torch.tensor([[[1., 2], [3, 4]], [[5, 6], [7, 8]]]).to(self.device) torch_expected = torch_tensor.transpose(dim1, dim2) @ torch_tensor self.assertTrue(utils.compare_torch(torch_result, torch_expected)) @@ -587,7 +587,7 @@ class TestTensorOperations(unittest.TestCase): Test a combination of operations: (tensor.sum() + other_tensor) / scalar @ another_tensor followed by reshape """ norch_tensor1 = norch.Tensor([[[1., 2], [3, -4]], [[5, 6], [7, 8]]]).to(self.device) - norch_tensor2 = norch.Tensor([[[1, 1], [1, 1]], [[1, 1], [1, 1]]]).to(self.device) + norch_tensor2 = norch.Tensor([[[1., 1], [1, 1]], [[1, 1], [1, 1]]]).to(self.device) scalar = 2 new_shape = [2, 4] norch_result = ((norch_tensor1 + norch_tensor2) / scalar) @ norch_tensor1 @@ -595,7 +595,7 @@ class TestTensorOperations(unittest.TestCase): torch_result = utils.to_torch(norch_result).to(self.device) torch_tensor1 = torch.tensor([[[1., 2], [3, -4]], [[5, 6], [7, 8]]]).to(self.device) - torch_tensor2 = torch.tensor([[[1, 1], [1, 1]], [[1, 1], [1, 1]]]).to(self.device) + torch_tensor2 = torch.tensor([[[1., 1], [1, 1]], [[1, 1], [1, 1]]]).to(self.device) torch_expected = ((torch_tensor1 + torch_tensor2) / scalar) @ torch_tensor1 torch_expected = torch_expected.reshape(new_shape)