compile_fail
39_GRU.py
started
2026-05-05T00:02:02Z
compile error: Error building extension 'gru_custom_coop_ext_v1': [1/3] /opt/conda/bin/x86_64-conda-linux-gnu-c++ -MMD -MF main.o.d -DTORCH_EXTENSION_NAME=gru_custom_coop_ext_v1 -DTORCH_API_INCLUDE_EXTENSION_H -isystem /scratch/abaner/KernelBench/.venv/lib/python3.10/site-packages/torch/include -isystem /scratch/abaner/KernelBench/.venv/lib/python3.10/site-packages/torch/include/torch/csrc/api/include -isystem /usr/local/cuda/include -isystem /opt/conda/include/python3.10 -fPIC -std=c++17 -O3 -c /scratch/abaner/KernelBench/runs/l123_single_gpt/original/gpt-5.5-priority/level_3_problem_39_cache/k_49994b14ead3
timingkernelbench.timing
kernel mean / median / std
—
reference PyTorch source (the prompt the agent sees)
import torch
import torch.nn as nn
import torch.nn.functional as F
class Model(nn.Module):
def __init__(self, input_size, hidden_size, num_layers=3, bias=True, batch_first=False):
"""
:param input_size: The number of expected features in the input x
:param hidden_size: The number of features in the hidden state h
:param num_layers: Number of recurrent layers (default: 1)
:param bias: If False, then the layer does not use bias weights b_ih and b_hh (default: True)
:param batch_first: If True, then the input and output tensors are provided as (batch, seq, feature) (default: False)
"""
super(Model, self).__init__()
self.gru = nn.GRU(input_size, hidden_size, num_layers, bias, batch_first, dropout=0, bidirectional=False)
def forward(self, x,h0):
"""
:param x: The input tensor, shape (seq_len, batch_size, input_size) if batch_first=False, otherwise (batch_size, seq_len, input_size)
:param h_0: The initial hidden state for the input sequence, shape (num_layers * num_directions, batch_size, hidden_size) (default: None)
:return: output, h_n
- output: The output features (h_t) from the last layer of the GRU, for each t, shape (seq_len, batch_size, num_directions * hidden_size) if batch_first=False, otherwise (batch_size, seq_len, num_directions * hidden_size)
- h_n: The hidden state for t = seq_len, shape (num_layers * num_directions, batch_size, hidden_size)
"""
output, h_n = self.gru(x, h0)
return output
# Test code
batch_size = 10
seq_len = 512
input_size = 128
hidden_size = 256
num_layers = 6
def get_inputs():
return [torch.rand(seq_len, batch_size, input_size),torch.rand((num_layers, batch_size, hidden_size))]
def get_init_inputs():
return [input_size, hidden_size, num_layers]turn 0 · FINAL · 1 tool call(s) · 209.1s turn · 209.1s LLM · 15,945 chars (click to expand)
turn 0209.1s turn · 209.1s LLM · 0.0s tools · FINAL
reasoning
**Planning GRU implementation**
I need to craft a complete Python module, implementing a GRU forward function with specific arguments like input size, hidden size, layers, and more. I should include weights from nn.GRU and ensure the ModelNew initializes correctly, likely involving the evaluation of both Model and ModelNew instances. Copying weights seems standard in these tasks. I'll define self.gru and ensure it accepts weights while subclassing nn.Module. My goal is to create a fast multi-layer GRU that surpasses PyTorch's reference performance.
**Exploring GRU equations**
I’m looking into the GRU equations involving the reset gate, update gate, and new gate calculations. I need to ensure I’m using the correct formulas and order, especially in relation to PyTorch’s implementation. Efficiency is a concern here—I’m considering whether to utilize cuBLAS for matrix multiplication. The task requires a custom CUDA kernel, but I may still leverage Torch operations. I’ll need to evaluate various dimensions and consider the performance implications of my approach, like the expected GFLOPs and execution time.
**Considering speed for GRU**
I'm wondering if using cuDNN will yield around 10ms for small batches, which would be a decent speed. I really need to prioritize performance here. I should consider how dependencies work, as I’ll have to process the recurrence sequentially across the sequence for each layer. It’s crucial that the layers are processed sequentially too for everything to work properly. So, I'll keep that in mind as I move forward.
**Analyzing Python and C++ integration**
I'm thinking about how Python can help collect the weights into a list more easily. The `load_inline` function might allow me to bind C++ with `vector<Tensor>`. I’m considering a single kernel call like `layer_process<<<B, 256>>>`, where I could have one block per batch. For each block and layer, I'd use roughly `T*H` threads, with each performing about `3*(K+H)` multiplications. This could sum up to around 786k per thread across `T`.
**Exploring computation methods**
I'm considering whether I could precompute the input-to-hidden transformations for all timesteps using a matrix multiplication approach with Torch. In C++, I could utilize functions like at::matmul or addmm on a sequence multiplied by the weight matrix for each layer. This works for the first layer, but the subsequent layers depend on the outputs. However, I can compute these after the initial layer, keeping the recurrent contributions per timestep in mind. A custom kernel could be useful for managing the recurrent and activation functions.
**Evaluating grid configuration**
I'm considering the grid setup: maybe blocking it into 128 blocks with 4 rows working 32 threads each seems too high. Instead, a layout with 16 rows and 8 threads per row might be more appropriate. At a certain moment, for each row j, a group of 8 threads can compute the dot product for r, z, n with a stride of 8 over k. It feels like a necessary adjustment to make it more efficient!
**Finalizing submission**
I’m working with cpp_sources and have decided that I don’t need to include PYBIND for now. I should use `load_inline` with the cpp_sources string that includes the generated pybind code. It's good that the function declaration in the generated binding comes after our definition. I see that C++ code successfully calls the launch_gru_layer that was declared. So, it’s time to finalize the submission through the tool!
call → submit_kernel
callsubmit_kernel
{
"kernel_code": "import torch\nimport torch.nn as nn\nfrom torch.utils.cpp_extension import load_inline\n\n_cpp_src = r'''\n#include <torch/extension.h>\n#include <vector>\n\nvoid launch_gru_layer(torch::Tensor xg, torch::Tensor h0_l, torch::Tensor whh,\n c10::optional<torch::Tensor> bhh, torch::Tensor out);\n\ntorch::Tensor gru_forward(torch::Tensor x, torch::Tensor h0,\n std::vector<torch::Tensor> w_ih,\n std::vector<torch::Tensor> w_hh,\n std::vector<torch::Tensor> b_ih,\n std::vector<torch::Tensor> b_hh,\n bool batch_first) {\n TORCH_CHECK(x.is_cuda(), \"x must be CUDA\");\n TORCH_CHECK(h0.is_cuda(), \"h0 must be CUDA\");\n TORCH_CHECK(x.scalar_type() == at::kFloat, \"only float32 is supported\");\n\n torch::Tensor xs = batch_first ? x.transpose(0, 1).contiguous() : x.contiguous();\n torch::Tensor h0c = h0.contiguous();\n\n const int64_t T = xs.size(0);\n const int64_t B = xs.size(1);\n const int64_t H = w_hh[0].size(1);\n const int64_t L = (int64_t)w_ih.size();\n const bool has_bias = (b_ih.size() == w_ih.size()) && (b_hh.size() == w_hh.size());\n\n torch::Tensor cur;\n for (int64_t l = 0; l < L; ++l) {\n torch::Tensor inp = (l == 0) ? xs : cur;\n torch::Tensor inp2 = inp.reshape({T * B, inp.size(2)});\n torch::Tensor xg;\n if (has_bias) {\n xg = at::addmm(b_ih[l], inp2, w_ih[l].t());\n } else {\n xg = at::mm(inp2, w_ih[l].t());\n }\n xg = xg.contiguous();\n torch::Tensor out = torch::empty({T, B, H}, xs.options());\n torch::Tensor h0_l = h0c.select(0, l);\n if (has_bias) {\n launch_gru_layer(xg, h0_l, w_hh[l].contiguous(), b_hh[l].contiguous(), out);\n } else {\n launch_gru_layer(xg, h0_l, w_hh[l].contiguous(), c10::nullopt, out);\n }\n cur = out;\n }\n return batch_first ? cur.transpose(0, 1) : cur;\n}\n'''\n\n_cuda_src = r'''\n#include <torch/extension.h>\n#include <ATen/cuda/CUDAContext.h>\n#include <c10/cuda/CUDAException.h>\n#include <cooperative_groups.h>\n#include <cuda_runtime.h>\n\nnamespace cg = cooperative_groups;\n\n__device__ __forceinline__ float sigmoid_f(float x) {\n return 1.0f / (1.0f + expf(-x));\n}\n\n// One cooperative grid computes one recurrent layer. Grid is (ceil(H/16), B).\n// Each block owns 16 hidden units for one batch element; 8 threads cooperate on\n// each unit's recurrent dot products. A grid-wide sync separates time steps.\n__global__ void gru_layer_kernel(const float* __restrict__ xg,\n const float* __restrict__ h0,\n const float* __restrict__ whh,\n const float* __restrict__ bhh,\n float* __restrict__ out,\n int T, int B, int H) {\n cg::grid_group grid = cg::this_grid();\n\n constexpr int ROWS_PER_BLOCK = 16;\n constexpr int LANES_PER_ROW = 8;\n int b = blockIdx.y;\n int tile = blockIdx.x;\n int tid = threadIdx.x;\n int local_row = tid / LANES_PER_ROW;\n int lane = tid & (LANES_PER_ROW - 1);\n int j = tile * ROWS_PER_BLOCK + local_row;\n\n // The output buffer doubles as the recurrent state area after the sequence;\n // use a compact state stored in the first B*H elements of out temporarily.\n // To avoid clobbering real outputs, place state at the end is impossible\n // without extra storage, so each step reads previous state from either h0 or\n // the preceding output time slice.\n grid.sync();\n\n for (int t = 0; t < T; ++t) {\n float sr = 0.0f, sz = 0.0f, sn = 0.0f;\n if (j < H) {\n const float* hprev_base = (t == 0) ? (h0 + b * H) : (out + ((t - 1) * B + b) * H);\n const float* wr = whh + j * H;\n const float* wz = whh + (H + j) * H;\n const float* wn = whh + (2 * H + j) * H;\n for (int k = lane; k < H; k += LANES_PER_ROW) {\n float hv = hprev_base[k];\n sr += wr[k] * hv;\n sz += wz[k] * hv;\n sn += wn[k] * hv;\n }\n }\n#pragma unroll\n for (int off = LANES_PER_ROW / 2; off > 0; off >>= 1) {\n sr += __shfl_down_sync(0xffffffff, sr, off, LANES_PER_ROW);\n sz += __shfl_down_sync(0xffffffff, sz, off, LANES_PER_ROW);\n sn += __shfl_down_sync(0xffffffff, sn, off, LANES_PER_ROW);\n }\n if (j < H && lane == 0) {\n const int64_t gate_base = ((int64_t)t * B + b) * (3 * H);\n const float bhr = bhh ? bhh[j] : 0.0f;\n const float bhz = bhh ? bhh[H + j] : 0.0f;\n const float bhn = bhh ? bhh[2 * H + j] : 0.0f;\n float r = sigmoid_f(xg[gate_base + j] + sr + bhr);\n float z = sigmoid_f(xg[gate_base + H + j] + sz + bhz);\n float n = tanhf(xg[gate_base + 2 * H + j] + r * (sn + bhn));\n float hp = (t == 0) ? h0[b * H + j] : out[((int64_t)(t - 1) * B + b) * H + j];\n out[((int64_t)t * B + b) * H + j] = (1.0f - z) * n + z * hp;\n }\n grid.sync();\n }\n}\n\nvoid launch_gru_layer(torch::Tensor xg, torch::Tensor h0_l, torch::Tensor whh,\n c10::optional<torch::Tensor> bhh_opt, torch::Tensor out) {\n const int T = (int)out.size(0);\n const int B = (int)out.size(1);\n const int H = (int)out.size(2);\n dim3 block(128);\n dim3 grid((H + 15) / 16, B);\n const float* bhh = bhh_opt.has_value() ? bhh_opt.value().data_ptr<float>() : nullptr;\n void* args[] = {\n (void*)&xg.data_ptr<float>(),\n (void*)&h0_l.data_ptr<float>(),\n (void*)&whh.data_ptr<float>(),\n (void*)&bhh,\n (void*)&out.data_ptr<float>(),\n (void*)&T,\n (void*)&B,\n (void*)&H\n };\n cudaStream_t stream = at::cuda::getCurrentCUDAStream();\n C10_CUDA_CHECK(cudaLaunchCooperativeKernel((void*)gru_layer_kernel, grid, block, args, 0, stream));\n C10_CUDA_KERNEL_LAUNCH_CHECK();\n}\n'''\n\n_ext = load_inline(\n name='gru_custom_coop_ext_v1',\n cpp_sources=_cpp_src,\n cuda_sources=_cuda_src,\n functions=['gru_forward'],\n extra_cflags=['-O3'],\n extra_cuda_cflags=['-O3', '--expt-relaxed-constexpr'],\n verbose=False,\n)\n\nclass ModelNew(nn.Module):\n def __init__(self, input_size, hidden_size, num_layers=3, bias=True, batch_first=False):\n super(ModelNew, self).__init__()\n self.gru = nn.GRU(input_size, hidden_size, num_layers, bias, batch_first, dropout=0, bidirectional=False)\n self.batch_first = batch_first\n self.num_layers = num_layers\n self.bias = bias\n\n def forward(self, x, h0):\n w_ih = []\n w_hh = []\n b_ih = []\n b_hh = []\n for l in range(self.num_layers):\n w_ih.append(getattr(self.gru, f'weight_ih_l{l}'))\n w_hh.append(getattr(self.gru, f'weight_hh_l{l}'))\n if self.bias:\n b_ih.append(getattr(self.gru, f'bias_ih_l{l}'))\n b_hh.append(getattr(self.gru, f'bias_hh_l{l}'))\n return _ext.gru_forward(x, h0, w_ih, w_hh, b_ih, b_hh, self.batch_first)\n"
}
result ← submit_kernel (fail)
failsubmit_kernel
submit_kernel FAILED: kernel did not compile.
Error building extension 'gru_custom_coop_ext_v1': [1/3] /opt/conda/bin/x86_64-conda-linux-gnu-c++ -MMD -MF main.o.d -DTORCH_EXTENSION_NAME=gru_custom_coop_ext_v1 -DTORCH_API_INCLUDE_EXTENSION_H -isystem /scratch/abaner/KernelBench/.venv/lib/python3.10/site-packages/torch/include -isystem /scratch/abaner/KernelBench/.venv/lib/python3.10/site-packages/torch/include/torch/csrc/api/include -isystem /usr/local/cuda/include -isystem /opt/conda/include/python3.10 -fPIC -std=c++17 -O3 -c /scratch/abaner/KernelBench/runs/l123_single_gpt/original/gpt-5.5-priority/level_3_problem_39_cache/k_49994b14ead3/gru_custom_coop_ext_v1/main.cpp -o main.o
[2/3] /usr/local/cuda/bin/nvcc -MD -MF cuda.cuda.o.d -ccbin /opt/conda/bin/x86_64-conda-linux-gnu-cc -DTORCH_EXTENSION_NAME=gru_custom_coop_ext_v1 -DTORCH_API_INCLUDE_EXTENSION_H -isystem /scratch/abaner/KernelBench/.venv/lib/python3.10/site-packages/torch/include -isystem /scratch/abaner/KernelBench/.venv/lib/python3.10/site-packages/torch/include/torch/csrc/api/include -isystem /usr/local/cuda/include -isystem /opt/conda/include/python3.10 -D__CUDA_NO_HALF_OPERATORS__ -D__CUDA_NO_HALF_CONVERSIONS__ -D__CUDA_NO_BFLOAT16_CONVERSIONS__ -D__CUDA_NO_HALF2_OPERATORS__ --expt-relaxed-constexpr -gencode=arch=compute_90,code=compute_90 -gencode=arch=compute_90,code=sm_90 --compiler-options '-fPIC' -O3 --expt-relaxed-constexpr -std=c++17 -c /scratch/abaner/KernelBench/runs/l123_single_gpt/original/gpt-5.5-priority/level_3_problem_39_cache/k_49994b14ead3/gru_custom_coop_ext_v1/cuda.cu -o cuda.cuda.o
FAILED: [code=2] cuda.cuda.o
/usr/local/cuda/bin/nvcc -MD -MF cuda.cuda.o.d -ccbin /opt/conda/bin/x86_64-conda-linux-gnu-cc -DTORCH_EXTENSION_NAME=gru_custom_coop_ext_v1 -DTORCH_API_INCLUDE_EXTENSION_H -isystem /scratch/abaner/KernelBench/.venv/lib/python3.10/site-packages/torch/include -isystem /scratch/abaner/KernelBench/.venv/lib/python3.10/site-packages/torch/include/torch/csrc/api/include -isystem /usr/local/cuda/include -isystem /opt/conda/include/python3.10 -D__CUDA_NO_HALF_OPERATORS__ -D__CUDA_NO_HALF_CONVERSIONS__ -D__CUDA_NO_BFLOAT16_CONVERSIONS__ -D__CUDA_NO_HALF2_OPERATORS__ --expt-relaxed-constexpr -gencode=arch=compute_90,code=compute_90 -gencode=arch=compute_90,code=sm_90 --compiler-options '-fPIC' -O3 --expt-relaxed-constexpr -std=c++17 -c /scratch/abaner/KernelBench/runs/l123_single_gpt/original/gpt-5.5-priority/level_3_problem_39_cache/k_49994b14ead3/gru_custom_coop_ext_v1/cuda.cu -o cuda.cuda.o
nvcc warning : incompatible redefinition for option 'compiler-bindir', the last value of this option was used
/scratch/abaner/KernelBench/runs/l123_single_gpt/original/gpt-5.5-priority/level_3_problem_39_cache/k_49994b14ead3/gru_custom_coop_ext_v1/cuda.cu(88): error: expression must be an lvalue or a function designator
(void*)&xg.data_ptr<float>(),
^
/scratch/abaner/KernelBench/runs/l123_single_gpt/original/gpt-5.5-priority/level_3_problem_39_cache/k_49994b14ead3/gru_custom_coop_ext_v1/cuda.cu(89): error: expression must be an lvalue or a function designator
(void*)&h0_l.data_ptr<float>(),
^
/scratch/abaner/KernelBench/runs/l123_single_gpt/original/gpt-5.5-priority/level_3_problem_39_cache/k_49994b14ead3/gru_custom_coop_ext_v1/cuda.cu(90): error: expression must be an lvalue or a function designator
(void*)&whh.data_ptr<float>(),
^
/scratch/abaner/KernelBench/runs/l123_single_gpt/original/gpt-5.5-priority/level_3_problem_39_cache/k_49994b14ead3/gru_custom_coop_ext_v1/cuda.cu(92): error: expression must be an lvalue or a function designator
(void*)&out.data_ptr<float>(),
^
4 errors detected in the compilation of "/scratch/abaner/KernelBench/runs/l123_single_gpt/original/gpt-5.5-priority/level_3_problem_39_cache/k_49994b14ead3/gru_custom_coop_ext_v1/cuda.cu".
ninja: build stopped: subcommand failed.
final submitted kernel (184 lines, 7,172 chars) — full source, untruncated
import torch
import torch.nn as nn
from torch.utils.cpp_extension import load_inline
_cpp_src = r'''
#include <torch/extension.h>
#include <vector>
void launch_gru_layer(torch::Tensor xg, torch::Tensor h0_l, torch::Tensor whh,
c10::optional<torch::Tensor> bhh, torch::Tensor out);
torch::Tensor gru_forward(torch::Tensor x, torch::Tensor h0,
std::vector<torch::Tensor> w_ih,
std::vector<torch::Tensor> w_hh,
std::vector<torch::Tensor> b_ih,
std::vector<torch::Tensor> b_hh,
bool batch_first) {
TORCH_CHECK(x.is_cuda(), "x must be CUDA");
TORCH_CHECK(h0.is_cuda(), "h0 must be CUDA");
TORCH_CHECK(x.scalar_type() == at::kFloat, "only float32 is supported");
torch::Tensor xs = batch_first ? x.transpose(0, 1).contiguous() : x.contiguous();
torch::Tensor h0c = h0.contiguous();
const int64_t T = xs.size(0);
const int64_t B = xs.size(1);
const int64_t H = w_hh[0].size(1);
const int64_t L = (int64_t)w_ih.size();
const bool has_bias = (b_ih.size() == w_ih.size()) && (b_hh.size() == w_hh.size());
torch::Tensor cur;
for (int64_t l = 0; l < L; ++l) {
torch::Tensor inp = (l == 0) ? xs : cur;
torch::Tensor inp2 = inp.reshape({T * B, inp.size(2)});
torch::Tensor xg;
if (has_bias) {
xg = at::addmm(b_ih[l], inp2, w_ih[l].t());
} else {
xg = at::mm(inp2, w_ih[l].t());
}
xg = xg.contiguous();
torch::Tensor out = torch::empty({T, B, H}, xs.options());
torch::Tensor h0_l = h0c.select(0, l);
if (has_bias) {
launch_gru_layer(xg, h0_l, w_hh[l].contiguous(), b_hh[l].contiguous(), out);
} else {
launch_gru_layer(xg, h0_l, w_hh[l].contiguous(), c10::nullopt, out);
}
cur = out;
}
return batch_first ? cur.transpose(0, 1) : cur;
}
'''
_cuda_src = r'''
#include <torch/extension.h>
#include <ATen/cuda/CUDAContext.h>
#include <c10/cuda/CUDAException.h>
#include <cooperative_groups.h>
#include <cuda_runtime.h>
namespace cg = cooperative_groups;
__device__ __forceinline__ float sigmoid_f(float x) {
return 1.0f / (1.0f + expf(-x));
}
// One cooperative grid computes one recurrent layer. Grid is (ceil(H/16), B).
// Each block owns 16 hidden units for one batch element; 8 threads cooperate on
// each unit's recurrent dot products. A grid-wide sync separates time steps.
__global__ void gru_layer_kernel(const float* __restrict__ xg,
const float* __restrict__ h0,
const float* __restrict__ whh,
const float* __restrict__ bhh,
float* __restrict__ out,
int T, int B, int H) {
cg::grid_group grid = cg::this_grid();
constexpr int ROWS_PER_BLOCK = 16;
constexpr int LANES_PER_ROW = 8;
int b = blockIdx.y;
int tile = blockIdx.x;
int tid = threadIdx.x;
int local_row = tid / LANES_PER_ROW;
int lane = tid & (LANES_PER_ROW - 1);
int j = tile * ROWS_PER_BLOCK + local_row;
// The output buffer doubles as the recurrent state area after the sequence;
// use a compact state stored in the first B*H elements of out temporarily.
// To avoid clobbering real outputs, place state at the end is impossible
// without extra storage, so each step reads previous state from either h0 or
// the preceding output time slice.
grid.sync();
for (int t = 0; t < T; ++t) {
float sr = 0.0f, sz = 0.0f, sn = 0.0f;
if (j < H) {
const float* hprev_base = (t == 0) ? (h0 + b * H) : (out + ((t - 1) * B + b) * H);
const float* wr = whh + j * H;
const float* wz = whh + (H + j) * H;
const float* wn = whh + (2 * H + j) * H;
for (int k = lane; k < H; k += LANES_PER_ROW) {
float hv = hprev_base[k];
sr += wr[k] * hv;
sz += wz[k] * hv;
sn += wn[k] * hv;
}
}
#pragma unroll
for (int off = LANES_PER_ROW / 2; off > 0; off >>= 1) {
sr += __shfl_down_sync(0xffffffff, sr, off, LANES_PER_ROW);
sz += __shfl_down_sync(0xffffffff, sz, off, LANES_PER_ROW);
sn += __shfl_down_sync(0xffffffff, sn, off, LANES_PER_ROW);
}
if (j < H && lane == 0) {
const int64_t gate_base = ((int64_t)t * B + b) * (3 * H);
const float bhr = bhh ? bhh[j] : 0.0f;
const float bhz = bhh ? bhh[H + j] : 0.0f;
const float bhn = bhh ? bhh[2 * H + j] : 0.0f;
float r = sigmoid_f(xg[gate_base + j] + sr + bhr);
float z = sigmoid_f(xg[gate_base + H + j] + sz + bhz);
float n = tanhf(xg[gate_base + 2 * H + j] + r * (sn + bhn));
float hp = (t == 0) ? h0[b * H + j] : out[((int64_t)(t - 1) * B + b) * H + j];
out[((int64_t)t * B + b) * H + j] = (1.0f - z) * n + z * hp;
}
grid.sync();
}
}
void launch_gru_layer(torch::Tensor xg, torch::Tensor h0_l, torch::Tensor whh,
c10::optional<torch::Tensor> bhh_opt, torch::Tensor out) {
const int T = (int)out.size(0);
const int B = (int)out.size(1);
const int H = (int)out.size(2);
dim3 block(128);
dim3 grid((H + 15) / 16, B);
const float* bhh = bhh_opt.has_value() ? bhh_opt.value().data_ptr<float>() : nullptr;
void* args[] = {
(void*)&xg.data_ptr<float>(),
(void*)&h0_l.data_ptr<float>(),
(void*)&whh.data_ptr<float>(),
(void*)&bhh,
(void*)&out.data_ptr<float>(),
(void*)&T,
(void*)&B,
(void*)&H
};
cudaStream_t stream = at::cuda::getCurrentCUDAStream();
C10_CUDA_CHECK(cudaLaunchCooperativeKernel((void*)gru_layer_kernel, grid, block, args, 0, stream));
C10_CUDA_KERNEL_LAUNCH_CHECK();
}
'''
_ext = load_inline(
name='gru_custom_coop_ext_v1',
cpp_sources=_cpp_src,
cuda_sources=_cuda_src,
functions=['gru_forward'],
extra_cflags=['-O3'],
extra_cuda_cflags=['-O3', '--expt-relaxed-constexpr'],
verbose=False,
)
class ModelNew(nn.Module):
def __init__(self, input_size, hidden_size, num_layers=3, bias=True, batch_first=False):
super(ModelNew, self).__init__()
self.gru = nn.GRU(input_size, hidden_size, num_layers, bias, batch_first, dropout=0, bidirectional=False)
self.batch_first = batch_first
self.num_layers = num_layers
self.bias = bias
def forward(self, x, h0):
w_ih = []
w_hh = []
b_ih = []
b_hh = []
for l in range(self.num_layers):
w_ih.append(getattr(self.gru, f'weight_ih_l{l}'))
w_hh.append(getattr(self.gru, f'weight_hh_l{l}'))
if self.bias:
b_ih.append(getattr(self.gru, f'bias_ih_l{l}'))
b_hh.append(getattr(self.gru, f'bias_hh_l{l}'))
return _ext.gru_forward(x, h0, w_ih, w_hh, b_ih, b_hh, self.batch_first)