compile_fail
10_SampledDenseDenseMatmulEdges.py
started
2026-05-11T12:39:27Z
compile error: Syntax error in custom generated code or ModelNew not found
timingkernelbench.timing
kernel mean / median / std
—
reference PyTorch source (the prompt the agent sees)
import torch
import torch.nn as nn
class Model(nn.Module):
"""
Edge-only sampled dense-dense matmul.
For each graph edge (src, dst), compute a dot product between source and
destination node embeddings. This pattern appears in link prediction,
sampled attention, and graph contrastive learning.
"""
def __init__(self):
super().__init__()
def forward(
self,
src_idx: torch.Tensor,
dst_idx: torch.Tensor,
src_feat: torch.Tensor,
dst_feat: torch.Tensor,
) -> torch.Tensor:
src = src_feat[src_idx.long()]
dst = dst_feat[dst_idx.long()]
return (src * dst).sum(dim=-1)
num_src_nodes = 1024
num_dst_nodes = 768
num_edges = 16384
feat_dim = 128
def get_inputs():
p = popcorn_pri
n_edges = p.jitter_int(num_edges)
fd = p.jitter_int(feat_dim, align=8)
ns = p.jitter_int(num_src_nodes)
nd = p.jitter_int(num_dst_nodes)
src_idx = torch.randint(0, ns, (n_edges,), dtype=torch.int32)
dst_idx = torch.randint(0, nd, (n_edges,), dtype=torch.int32)
src_feat = torch.randn(ns, fd, dtype=torch.float32)
dst_feat = torch.randn(nd, fd, dtype=torch.float32)
return [src_idx, dst_idx, src_feat, dst_feat]
def get_init_inputs():
return []
turn 0483.5s turn · 3.5s LLM · 480.1s tools · tokens in=1,521 · out=6 · total=1,771
reasoning
The task is to replace the forward computation with a custom CUDA kernel for an edge-only sampled dense-dense matmul. It gathers src and dst features using indices and computes dot products per edge.
...
call → get_gpu_specs
callget_gpu_specs
{}
result ← get_gpu_specs (ok)
okget_gpu_specs
GPU specs for NVIDIA H100 80GB HBM3:
total memory (runtime): 79.1 GB
spec entry: H100
GPU Architecture: Hopper
GPU Memory: 80GB
Memory Bandwidth: 3.35 TB/s
FP64 TFLOPS: 34
FP64 Tensor Core TFLOPS: 67
FP32 TFLOPS: 67
TF32 Tensor Core TFLOPS: 989 with sparsity
BFLOAT16 Tensore Core TFLOPS: 1979 with sparsity
FP16 Tensor Core TFLOPS: 1979 with sparsity
FP8 Tensor Core TFLOPS: 3958 with sparsity
INT8 Tensor Core TOPS: 3958 with sparsity
Register File Size: 64K 32-bit registers per SM
Maximum number of registers per thread: 255
Maximum number of thread blocks per SM: 32
Shared memory capacity per SM: 228 KB
Maximum shared memory per thread block: 227 KB
turn 17.1s turn · 7.1s LLM · 0.0s tools · tokens in=2,004 · out=586 · total=2,678
reasoning
H100, good bandwidth.
Now, I need to implement the kernel.
assistant```python
import torch
import torch.nn as nn
from torch.utils.cpp_extension import load_inline
cuda_source = '''
#include <torch/extension.h>
#include <cuda.h>
#include <cuda_runtime.h>
__global__ void edge_dot_product_kernel(
const int32_t* __restrict__ src_idx,
const int32_t* __restrict__ dst_idx,
const float* __restrict__ src_feat,
const float* __restrict__ dst_feat,
float* __restrict__ output,
int num_edges,
int feat_dim
) {
int edge = blockIdx.x * blockDim.x + threadIdx.x;
if (edge >= num_edges) return;
int32_t src = src_idx[edge];
int32_t dst = dst_idx[edge];
float sum = 0.0f;
const float* src_ptr = src_feat + (int64_t)src * feat_dim;
const float* dst_ptr = dst_feat + (int64_t)dst * feat_dim;
for (int f = 0; f < feat_dim; ++f) {
sum += src_ptr[f] * dst_ptr[f];
}
output[edge] = sum;
}
torch::Tensor edge_dot_product_cuda(
torch::Tensor src_idx,
torch::Tensor dst_idx,
torch::Tensor src_feat,
torch::Tensor dst_feat
) {
int num_edges = src_idx.size(0);
int feat_dim = src_feat.size(1);
auto output = torch::empty({num_edges}, src_feat.options());
const int threads = 256;
const int blocks = (num_edges + threads - 1) / threads;
edge_dot_product_kernel<<<blocks, threads>>>(
src_idx.data_ptr<int32_t>(),
dst_idx.data_ptr<int32_t>(),
src_feat.data_ptr<float>(),
dst_feat.data_ptr<float>(),
output.data_ptr<float>(),
num_edges,
feat_dim
);
return output;
}
'''
cpp_source = '''
torch::Tensor edge_dot_product_cuda(
torch::Tensor src_idx,
torch::Tensor dst_idx,
torch::Tensor src_feat,
torch::Tensor dst_feat
);
'''
module = load_inline(
name='edge_dot_product',
cpp_sources=cpp_source,
cuda_sources=cuda_source,
functions=['edge_dot_product_cuda'],
verbose=False
)
class ModelNew(nn.Module):
def __init__(self):
super().__init__()
self.module = module
def forward(
self,
src_idx: torch.Tensor,
dst_idx: torch.Tensor,
src_feat: torch.Tensor,
dst_feat: torch.Tensor,
) -> torch.Tensor:
return self.module.edge_dot_product_cuda(src_idx, dst_idx, src_feat, dst_feat)
```
turn 2390.1s turn · 5.4s LLM · 384.7s tools · tokens in=2,746 · out=593 · total=3,351
reasoning
I need to test it. Let's compile and check correctness.
call → compile_kernel
callcompile_kernel
{
"kernel_code": "import torch\nimport torch.nn as nn\nfrom torch.utils.cpp_extension import load_inline\n\ncuda_source = '''\n#include <torch/extension.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n\n__global__ void edge_dot_product_kernel(\n const int32_t* __restrict__ src_idx,\n const int32_t* __restrict__ dst_idx,\n const float* __restrict__ src_feat,\n const float* __restrict__ dst_feat,\n float* __restrict__ output,\n int num_edges,\n int feat_dim\n) {\n int edge = blockIdx.x * blockDim.x + threadIdx.x;\n if (edge >= num_edges) return;\n\n int32_t src = src_idx[edge];\n int32_t dst = dst_idx[edge];\n\n float sum = 0.0f;\n const float* src_ptr = src_feat + (int64_t)src * feat_dim;\n const float* dst_ptr = dst_feat + (int64_t)dst * feat_dim;\n\n for (int f = 0; f < feat_dim; ++f) {\n sum += src_ptr[f] * dst_ptr[f];\n }\n\n output[edge] = sum;\n}\n\ntorch::Tensor edge_dot_product_cuda(\n torch::Tensor src_idx,\n torch::Tensor dst_idx,\n torch::Tensor src_feat,\n torch::Tensor dst_feat\n) {\n int num_edges = src_idx.size(0);\n int feat_dim = src_feat.size(1);\n\n auto output = torch::empty({num_edges}, src_feat.options());\n\n const int threads = 256;\n const int blocks = (num_edges + threads - 1) / threads;\n\n edge_dot_product_kernel<<<blocks, threads>>>(\n src_idx.data_ptr<int32_t>(),\n dst_idx.data_ptr<int32_t>(),\n src_feat.data_ptr<float>(),\n dst_feat.data_ptr<float>(),\n output.data_ptr<float>(),\n num_edges,\n feat_dim\n );\n\n return output;\n}\n'''\n\ncpp_source = '''\ntorch::Tensor edge_dot_product_cuda(\n torch::Tensor src_idx,\n torch::Tensor dst_idx,\n torch::Tensor src_feat,\n torch::Tensor dst_feat\n);\n'''\n\nmodule = load_inline(\n name='edge_dot_product',\n cpp_sources=cpp_source,\n cuda_sources=cuda_source,\n functions=['edge_dot_product_cuda'],\n verbose=False\n)\n\nclass ModelNew(nn.Module):\n def __init__(self):\n super().__init__()\n self.module = module\n\n def forward(\n self,\n src_idx: torch.Tensor,\n dst_idx: torch.Tensor,\n src_feat: torch.Tensor,\n dst_feat: torch.Tensor,\n ) -> torch.Tensor:\n return self.module.edge_dot_product_cuda(src_idx, dst_idx, src_feat, dst_feat)\n"
}
result ← compile_kernel (ok)
okcompile_kernel
compile_kernel PASSED: kernel compiled without errors.
turn 3219.4s turn · 10.4s LLM · 209.0s tools · tokens in=3,368 · out=594 · total=3,969
reasoning
Compiled successfully. Now check correctness.
call → run_correctness
callrun_correctness
{
"kernel_code": "import torch\nimport torch.nn as nn\nfrom torch.utils.cpp_extension import load_inline\n\ncuda_source = '''\n#include <torch/extension.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n\n__global__ void edge_dot_product_kernel(\n const int32_t* __restrict__ src_idx,\n const int32_t* __restrict__ dst_idx,\n const float* __restrict__ src_feat,\n const float* __restrict__ dst_feat,\n float* __restrict__ output,\n int num_edges,\n int feat_dim\n) {\n int edge = blockIdx.x * blockDim.x + threadIdx.x;\n if (edge >= num_edges) return;\n\n int32_t src = src_idx[edge];\n int32_t dst = dst_idx[edge];\n\n float sum = 0.0f;\n const float* src_ptr = src_feat + (int64_t)src * feat_dim;\n const float* dst_ptr = dst_feat + (int64_t)dst * feat_dim;\n\n for (int f = 0; f < feat_dim; ++f) {\n sum += src_ptr[f] * dst_ptr[f];\n }\n\n output[edge] = sum;\n}\n\ntorch::Tensor edge_dot_product_cuda(\n torch::Tensor src_idx,\n torch::Tensor dst_idx,\n torch::Tensor src_feat,\n torch::Tensor dst_feat\n) {\n int num_edges = src_idx.size(0);\n int feat_dim = src_feat.size(1);\n\n auto output = torch::empty({num_edges}, src_feat.options());\n\n const int threads = 256;\n const int blocks = (num_edges + threads - 1) / threads;\n\n edge_dot_product_kernel<<<blocks, threads>>>(\n src_idx.data_ptr<int32_t>(),\n dst_idx.data_ptr<int32_t>(),\n src_feat.data_ptr<float>(),\n dst_feat.data_ptr<float>(),\n output.data_ptr<float>(),\n num_edges,\n feat_dim\n );\n\n return output;\n}\n'''\n\ncpp_source = '''\ntorch::Tensor edge_dot_product_cuda(\n torch::Tensor src_idx,\n torch::Tensor dst_idx,\n torch::Tensor src_feat,\n torch::Tensor dst_feat\n);\n'''\n\nmodule = load_inline(\n name='edge_dot_product',\n cpp_sources=cpp_source,\n cuda_sources=cuda_source,\n functions=['edge_dot_product_cuda'],\n verbose=False\n)\n\nclass ModelNew(nn.Module):\n def __init__(self):\n super().__init__()\n self.module = module\n\n def forward(\n self,\n src_idx: torch.Tensor,\n dst_idx: torch.Tensor,\n src_feat: torch.Tensor,\n dst_feat: torch.Tensor,\n ) -> torch.Tensor:\n return self.module.edge_dot_product_cuda(src_idx, dst_idx, src_feat, dst_feat)\n"
}
result ← run_correctness (fail)
failrun_correctness
run_correctness FAILED: ? trials did not all match.
runtime_error: expected scalar type Int but found Float
turn 4558.1s turn · 17.4s LLM · 540.7s tools · tokens in=3,998 · out=685 · total=5,437
reasoning
Error: expected scalar type Int but found Float. Probably in the indices or something. No, the inputs are int32 for indices, float for feats.
I encountered an error where it expected a scalar type Int but found Float. The indices are int32, and the features are float. The issue is probably with the tensor types or device placement. The indices are int32, matching CUDA's preference for uniformity. The reference uses .long(), which is int64, but inputs are int32. The error occurs at runtime, possibly from a type mismatch in the extension or test. The inputs are CPU tensors initially, and the test moves them to CUDA. The kernel assumes GPU tensors, but there's a mismatch. To fix it, I need to ensure contiguous tensors and correct device placement.
call → compile_kernel
callcompile_kernel
{
"kernel_code": "import torch\nimport torch.nn as nn\nfrom torch.utils.cpp_extension import load_inline\n\ncuda_source = '''\n#include <torch/extension.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n\n__global__ void edge_dot_product_kernel(\n const int32_t* __restrict__ src_idx,\n const int32_t* __restrict__ dst_idx,\n const float* __restrict__ src_feat,\n const float* __restrict__ dst_feat,\n float* __restrict__ output,\n int num_edges,\n int feat_dim\n) {\n int edge = blockIdx.x * blockDim.x + threadIdx.x;\n if (edge >= num_edges) return;\n\n int32_t src = src_idx[edge];\n int32_t dst = dst_idx[edge];\n\n float sum = 0.0f;\n const float* src_ptr = src_feat + (int64_t)src * feat_dim;\n const float* dst_ptr = dst_feat + (int64_t)dst * feat_dim;\n\n for (int f = 0; f < feat_dim; ++f) {\n sum += src_ptr[f] * dst_ptr[f];\n }\n\n output[edge] = sum;\n}\n\ntorch::Tensor edge_dot_product_cuda(\n torch::Tensor src_idx,\n torch::Tensor dst_idx,\n torch::Tensor src_feat,\n torch::Tensor dst_feat\n) {\n TORCH_CHECK(src_idx.is_cuda(), \"src_idx must be CUDA\");\n TORCH_CHECK(dst_idx.is_cuda(), \"dst_idx must be CUDA\");\n TORCH_CHECK(src_feat.is_cuda(), \"src_feat must be CUDA\");\n TORCH_CHECK(dst_feat.is_cuda(), \"dst_feat must be CUDA\");\n\n int num_edges = src_idx.size(0);\n int feat_dim = src_feat.size(1);\n\n auto output = torch::empty({num_edges}, src_feat.options());\n\n const int threads = 256;\n const int blocks = (num_edges + threads - 1) / threads;\n\n edge_dot_product_kernel<<<blocks, threads>>>(\n src_idx.data_ptr<int32_t>(),\n dst_idx.data_ptr<int32_t>(),\n src_feat.data_ptr<float>(),\n dst_feat.data_ptr<float>(),\n output.data_ptr<float>(),\n num_edges,\n feat_dim\n );\n\n return output;\n}\n'''\n\ncpp_source = '''\ntorch::Tensor edge_dot_product_cuda(\n torch::Tensor src_idx,\n torch::Tensor dst_idx,\n torch::Tensor src_feat,\n torch::Tensor dst_feat\n);\n'''\n\nmodule = load_inline(\n name='edge_dot_product',\n cpp_sources=cpp_source,\n cuda_sources=cuda_source,\n functions=['edge_dot_product_cuda'],\n verbose=False\n)\n\nclass ModelNew(nn.Module):\n def __init__(self):\n super().__init__()\n self.module = module\n\n def forward(\n self,\n src_idx: torch.Tensor,\n dst_idx: torch.Tensor,\n src_feat: torch.Tensor,\n dst_feat: torch.Tensor,\n ) -> torch.Tensor:\n src_idx = src_idx.contiguous().to(torch.int32)\n dst_idx = dst_idx.contiguous().to(torch.int32)\n return self.module.edge_dot_product_cuda(src_idx, dst_idx, src_feat, dst_feat)\n"
}
result ← compile_kernel (ok)
okcompile_kernel
compile_kernel PASSED: kernel compiled without errors.
turn 5287.9s turn · 10.4s LLM · 277.5s tools · tokens in=5,454 · out=686 · total=6,145
reasoning
Now test correctness again.
call → run_correctness
callrun_correctness
{
"kernel_code": "import torch\nimport torch.nn as nn\nfrom torch.utils.cpp_extension import load_inline\n\ncuda_source = '''\n#include <torch/extension.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n\n__global__ void edge_dot_product_kernel(\n const int32_t* __restrict__ src_idx,\n const int32_t* __restrict__ dst_idx,\n const float* __restrict__ src_feat,\n const float* __restrict__ dst_feat,\n float* __restrict__ output,\n int num_edges,\n int feat_dim\n) {\n int edge = blockIdx.x * blockDim.x + threadIdx.x;\n if (edge >= num_edges) return;\n\n int32_t src = src_idx[edge];\n int32_t dst = dst_idx[edge];\n\n float sum = 0.0f;\n const float* src_ptr = src_feat + (int64_t)src * feat_dim;\n const float* dst_ptr = dst_feat + (int64_t)dst * feat_dim;\n\n for (int f = 0; f < feat_dim; ++f) {\n sum += src_ptr[f] * dst_ptr[f];\n }\n\n output[edge] = sum;\n}\n\ntorch::Tensor edge_dot_product_cuda(\n torch::Tensor src_idx,\n torch::Tensor dst_idx,\n torch::Tensor src_feat,\n torch::Tensor dst_feat\n) {\n TORCH_CHECK(src_idx.is_cuda(), \"src_idx must be CUDA\");\n TORCH_CHECK(dst_idx.is_cuda(), \"dst_idx must be CUDA\");\n TORCH_CHECK(src_feat.is_cuda(), \"src_feat must be CUDA\");\n TORCH_CHECK(dst_feat.is_cuda(), \"dst_feat must be CUDA\");\n\n int num_edges = src_idx.size(0);\n int feat_dim = src_feat.size(1);\n\n auto output = torch::empty({num_edges}, src_feat.options());\n\n const int threads = 256;\n const int blocks = (num_edges + threads - 1) / threads;\n\n edge_dot_product_kernel<<<blocks, threads>>>(\n src_idx.data_ptr<int32_t>(),\n dst_idx.data_ptr<int32_t>(),\n src_feat.data_ptr<float>(),\n dst_feat.data_ptr<float>(),\n output.data_ptr<float>(),\n num_edges,\n feat_dim\n );\n\n return output;\n}\n'''\n\ncpp_source = '''\ntorch::Tensor edge_dot_product_cuda(\n torch::Tensor src_idx,\n torch::Tensor dst_idx,\n torch::Tensor src_feat,\n torch::Tensor dst_feat\n);\n'''\n\nmodule = load_inline(\n name='edge_dot_product',\n cpp_sources=cpp_source,\n cuda_sources=cuda_source,\n functions=['edge_dot_product_cuda'],\n verbose=False\n)\n\nclass ModelNew(nn.Module):\n def __init__(self):\n super().__init__()\n self.module = module\n\n def forward(\n self,\n src_idx: torch.Tensor,\n dst_idx: torch.Tensor,\n src_feat: torch.Tensor,\n dst_feat: torch.Tensor,\n ) -> torch.Tensor:\n src_idx = src_idx.contiguous().to(torch.int32)\n dst_idx = dst_idx.contiguous().to(torch.int32)\n return self.module.edge_dot_product_cuda(src_idx, dst_idx, src_feat, dst_feat)\n"
}
result ← run_correctness (ok)
okrun_correctness
run_correctness PASSED: (5 / 5) trials all matched the reference.
Numerical precision: max_abs_err=1.91e-05 mean_abs_err=1.75e-06 max_rel_err=6.39e-03
turn 6654.8s turn · 8.0s LLM · 646.8s tools · tokens in=6,205 · out=686 · total=6,967 · FINAL
reasoning
Correct! Now it's good. I can submit this, as it's faster than reference likely, simple kernel should be.
call → submit_kernel
callsubmit_kernel
{
"kernel_code": "import torch\nimport torch.nn as nn\nfrom torch.utils.cpp_extension import load_inline\n\ncuda_source = '''\n#include <torch/extension.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n\n__global__ void edge_dot_product_kernel(\n const int32_t* __restrict__ src_idx,\n const int32_t* __restrict__ dst_idx,\n const float* __restrict__ src_feat,\n const float* __restrict__ dst_feat,\n float* __restrict__ output,\n int num_edges,\n int feat_dim\n) {\n int edge = blockIdx.x * blockDim.x + threadIdx.x;\n if (edge >= num_edges) return;\n\n int32_t src = src_idx[edge];\n int32_t dst = dst_idx[edge];\n\n float sum = 0.0f;\n const float* src_ptr = src_feat + (int64_t)src * feat_dim;\n const float* dst_ptr = dst_feat + (int64_t)dst * feat_dim;\n\n for (int f = 0; f < feat_dim; ++f) {\n sum += src_ptr[f] * dst_ptr[f];\n }\n\n output[edge] = sum;\n}\n\ntorch::Tensor edge_dot_product_cuda(\n torch::Tensor src_idx,\n torch::Tensor dst_idx,\n torch::Tensor src_feat,\n torch::Tensor dst_feat\n) {\n TORCH_CHECK(src_idx.is_cuda(), \"src_idx must be CUDA\");\n TORCH_CHECK(dst_idx.is_cuda(), \"dst_idx must be CUDA\");\n TORCH_CHECK(src_feat.is_cuda(), \"src_feat must be CUDA\");\n TORCH_CHECK(dst_feat.is_cuda(), \"dst_feat must be CUDA\");\n\n int num_edges = src_idx.size(0);\n int feat_dim = src_feat.size(1);\n\n auto output = torch::empty({num_edges}, src_feat.options());\n\n const int threads = 256;\n const int blocks = (num_edges + threads - 1) / threads;\n\n edge_dot_product_kernel<<<blocks, threads>>>(\n src_idx.data_ptr<int32_t>(),\n dst_idx.data_ptr<int32_t>(),\n src_feat.data_ptr<float>(),\n dst_feat.data_ptr<float>(),\n output.data_ptr<float>(),\n num_edges,\n feat_dim\n );\n\n return output;\n}\n'''\n\ncpp_source = '''\ntorch::Tensor edge_dot_product_cuda(\n torch::Tensor src_idx,\n torch::Tensor dst_idx,\n torch::Tensor src_feat,\n torch::Tensor dst_feat\n);\n'''\n\nmodule = load_inline(\n name='edge_dot_product',\n cpp_sources=cpp_source,\n cuda_sources=cuda_source,\n functions=['edge_dot_product_cuda'],\n verbose=False\n)\n\nclass ModelNew(nn.Module):\n def __init__(self):\n super().__init__()\n self.module = module\n\n def forward(\n self,\n src_idx: torch.Tensor,\n dst_idx: torch.Tensor,\n src_feat: torch.Tensor,\n dst_feat: torch.Tensor,\n ) -> torch.Tensor:\n src_idx = src_idx.contiguous().to(torch.int32);\n dst_idx = dst_idx.contiguous().to(torch.int32);\n return self.module.edge_dot_product_cuda(src_idx, dst_idx, src_feat, dst_feat);\n```"
}
result ← submit_kernel (fail)
failsubmit_kernel
submit_kernel FAILED: kernel did not compile.
Syntax error in custom generated code or ModelNew not found
final submitted kernel (101 lines, 2,633 chars) — full source, untruncated
import torch
import torch.nn as nn
from torch.utils.cpp_extension import load_inline
cuda_source = '''
#include <torch/extension.h>
#include <cuda.h>
#include <cuda_runtime.h>
__global__ void edge_dot_product_kernel(
const int32_t* __restrict__ src_idx,
const int32_t* __restrict__ dst_idx,
const float* __restrict__ src_feat,
const float* __restrict__ dst_feat,
float* __restrict__ output,
int num_edges,
int feat_dim
) {
int edge = blockIdx.x * blockDim.x + threadIdx.x;
if (edge >= num_edges) return;
int32_t src = src_idx[edge];
int32_t dst = dst_idx[edge];
float sum = 0.0f;
const float* src_ptr = src_feat + (int64_t)src * feat_dim;
const float* dst_ptr = dst_feat + (int64_t)dst * feat_dim;
for (int f = 0; f < feat_dim; ++f) {
sum += src_ptr[f] * dst_ptr[f];
}
output[edge] = sum;
}
torch::Tensor edge_dot_product_cuda(
torch::Tensor src_idx,
torch::Tensor dst_idx,
torch::Tensor src_feat,
torch::Tensor dst_feat
) {
TORCH_CHECK(src_idx.is_cuda(), "src_idx must be CUDA");
TORCH_CHECK(dst_idx.is_cuda(), "dst_idx must be CUDA");
TORCH_CHECK(src_feat.is_cuda(), "src_feat must be CUDA");
TORCH_CHECK(dst_feat.is_cuda(), "dst_feat must be CUDA");
int num_edges = src_idx.size(0);
int feat_dim = src_feat.size(1);
auto output = torch::empty({num_edges}, src_feat.options());
const int threads = 256;
const int blocks = (num_edges + threads - 1) / threads;
edge_dot_product_kernel<<<blocks, threads>>>(
src_idx.data_ptr<int32_t>(),
dst_idx.data_ptr<int32_t>(),
src_feat.data_ptr<float>(),
dst_feat.data_ptr<float>(),
output.data_ptr<float>(),
num_edges,
feat_dim
);
return output;
}
'''
cpp_source = '''
torch::Tensor edge_dot_product_cuda(
torch::Tensor src_idx,
torch::Tensor dst_idx,
torch::Tensor src_feat,
torch::Tensor dst_feat
);
'''
module = load_inline(
name='edge_dot_product',
cpp_sources=cpp_source,
cuda_sources=cuda_source,
functions=['edge_dot_product_cuda'],
verbose=False
)
class ModelNew(nn.Module):
def __init__(self):
super().__init__()
self.module = module
def forward(
self,
src_idx: torch.Tensor,
dst_idx: torch.Tensor,
src_feat: torch.Tensor,
dst_feat: torch.Tensor,
) -> torch.Tensor:
src_idx = src_idx.contiguous().to(torch.int32);
dst_idx = dst_idx.contiguous().to(torch.int32);
return self.module.edge_dot_product_cuda(src_idx, dst_idx, src_feat, dst_feat);
```