```python
import torch
import torch.nn as nn
from torch.utils.cpp_extension import load_inline


_cuda_source = r"""
#include <torch/extension.h>
#include <c10/cuda/CUDAGuard.h>
#include <c10/cuda/CUDAStream.h>
#include <c10/cuda/CUDAException.h>
#include <cuda_runtime.h>

constexpr int TILE = 256;

__global__ __launch_bounds__(256)
void conv3d_3x3x1_vectorized(
    const float* __restrict__ input,
    const float* __restrict__ weight,
    const float* __restrict__ bias,
    float* __restrict__ output,
    int height,
    int width,
    int depth,
    int output_width,
    int spatial_size)
{
    __shared__ __align__(16) float xs[27][TILE];
    __shared__ float ws[64][27];

    const int tid = threadIdx.x;
    const int lane = tid & 31;
    const int channel_group = tid >> 5;
    const int start = blockIdx.x * TILE;
    const int position = start + tid;
    const int batch = blockIdx.y;

    const int64_t channel_stride =
        static_cast<int64_t>(height) * width * depth;
    const int output_row_stride = output_width * depth;
    const int ih = position / output_row_stride;
    const int remainder = position - ih * output_row_stride;
    const int iw = remainder / depth;
    const int iz = remainder - iw * depth;
    const int64_t base =
        static_cast<int64_t>(batch) * 3 * channel_stride
        + (static_cast<int64_t>(ih) * width + iw) * depth + iz;

    #pragma unroll
    for (int ic = 0; ic < 3; ++ic) {
        #pragma unroll
        for (int kh = 0; kh < 3; ++kh) {
            #pragma unroll
            for (int kw = 0; kw < 3; ++kw) {
                const int k = ic * 9 + kh * 3 + kw;
                xs[k][tid] = position < spatial_size
                    ? input[base + ic * channel_stride
                            + static_cast<int64_t>(kh) * width * depth
                            + kw * depth]
                    : 0.0f;
            }
        }
    }

    for (int i = tid; i < 64 * 27; i += 256) {
        ws[i / 27][i % 27] = weight[i];
    }
    __syncthreads();

    float4 accum[8][2];

    #pragma unroll
    for (int c = 0; c < 8; ++c) {
        accum[c][0] = make_float4(0.f, 0.f, 0.f, 0.f);
        accum[c][1] = make_float4(0.f, 0.f, 0.f, 0.f);
    }

    #pragma unroll 1
    for (int k = 0; k < 27; ++k) {
        const float4 x0 =
            reinterpret_cast<const float4*>(xs[k])[lane];
        const float4 x1 =
            reinterpret_cast<const float4*>(xs[k])[lane + 32];

        #pragma unroll
        for (int c = 0; c < 8; ++c) {
            const float w = ws[channel_group + c * 8][k];
            accum[c][0].x = fmaf(x0.x, w, accum[c][0].x);
            accum[c][0].y = fmaf(x0.y, w, accum[c][0].y);
            accum[c][0].z = fmaf(x0.z, w, accum[c][0].z);
            accum[c][0].w = fmaf(x0.w, w, accum[c][0].w);
            accum[c][1].x = fmaf(x1.x, w, accum[c][1].x);
            accum[c][1].y = fmaf(x1.y, w, accum[c][1].y);
            accum[c][1].z = fmaf(x1.z, w, accum[c][1].z);
            accum[c][1].w = fmaf(x1.w, w, accum[c][1].w);
        }
    }

    #pragma unroll
    for (int c = 0; c < 8; ++c) {
        const int oc = channel_group + c * 8;
        const float b = bias ? bias[oc] : 0.f;
        float* dst = output
            + (static_cast<int64_t>(batch) * 64 + oc) * spatial_size;

        #pragma unroll
        for (int p = 0; p < 2; ++p) {
            const int pos = start + lane * 4 + p * 128;
            float4 value = accum[c][p];
            value.x += b;
            value.y += b;
            value.z += b;
            value.w += b;

            if ((spatial_size & 3) == 0) {
                if (pos < spatial_size) {
                    *reinterpret_cast<float4*>(dst + pos) = value;
                }
            } else {
                if (pos < spatial_size) dst[pos] = value.x;
                if (pos + 1 < spatial_size) dst[pos + 1] = value.y;
                if (pos + 2 < spatial_size) dst[pos + 2] = value.z;
                if (pos + 3 < spatial_size) dst[pos + 3] = value.w;
            }
        }
    }
}

torch::Tensor conv3d_specialized(
    torch::Tensor input,
    torch::Tensor weight,
    torch::Tensor bias,
    bool has_bias)
{
    const c10::cuda::CUDAGuard guard(input.device());

    const int batch = input.size(0);
    const int height = input.size(2);
    const int width = input.size(3);
    const int depth = input.size(4);
    const int output_height = height - 2;
    const int output_width = width - 2;
    const int spatial_size = output_height * output_width * depth;

    auto output = torch::empty(
        {batch, 64, output_height, output_width, depth},
        input.options());

    if (output.numel() == 0) return output;

    const dim3 grid((spatial_size + TILE - 1) / TILE, batch);
    const cudaStream_t stream =
        c10::cuda::getCurrentCUDAStream(input.get_device()).stream();

    conv3d_3x3x1_vectorized<<<grid, 256, 0, stream>>>(
        input.data_ptr<float>(),
        weight.data_ptr<float>(),
        has_bias ? bias.data_ptr<float>() : nullptr,
        output.data_ptr<float>(),
        height, width, depth, output_width, spatial_size);

    C10_CUDA_KERNEL_LAUNCH_CHECK();
    return output;
}
"""

_cpp_source = r"""
#include <torch/extension.h>
torch::Tensor conv3d_specialized(
    torch::Tensor input,
    torch::Tensor weight,
    torch::Tensor bias,
    bool has_bias);
"""

_conv3d_extension = load_inline(
    name="asymmetric_conv3d_vectorized_fp32_v2",
    cpp_sources=_cpp_source,
    cuda_sources=_cuda_source,
    functions=["conv3d_specialized"],
    extra_cflags=["-O3"],
    extra_cuda_cflags=["-O3"],
    verbose=False,
)


class ModelNew(nn.Module):
    def __init__(
        self,
        in_channels: int,
        out_channels: int,
        kernel_size: int,
        stride: int = 1,
        padding: int = 0,
        dilation: int = 1,
        groups: int = 1,
        bias: bool = False,
    ):
        super().__init__()
        self.conv3d = nn.Conv3d(
            in_channels,
            out_channels,
            (kernel_size, kernel_size, 1),
            stride=stride,
            padding=padding,
            dilation=dilation,
            groups=groups,
            bias=bias,
        )

    def forward(self, x: torch.Tensor) -> torch.Tensor:
        conv = self.conv3d
        weight = conv.weight
        bias = conv.bias

        if (
            x.is_cuda
            and x.dtype == torch.float32
            and x.ndim == 5
            and x.is_contiguous()
            and x.shape[1] == 3
            and x.shape[2] >= 3
            and x.shape[3] >= 3
            and x.shape[4] > 0
            and x.shape[0] <= 65535
            and x.shape[2] * x.shape[3] * x.shape[4] < 2147483392
            and weight.device == x.device
            and weight.dtype == torch.float32
            and weight.is_contiguous()
            and conv.in_channels == 3
            and conv.out_channels == 64
            and conv.kernel_size == (3, 3, 1)
            and conv.stride == (1, 1, 1)
            and conv.padding == (0, 0, 0)
            and conv.dilation == (1, 1, 1)
            and conv.groups == 1
            and not torch.is_autocast_enabled()
            and (
                bias is None
                or (
                    bias.device == x.device
                    and bias.dtype == torch.float32
                    and bias.is_contiguous()
                )
            )
        ):
            return _conv3d_extension.conv3d_specialized(
                x, weight, weight if bias is None else bias, bias is not None
            )

        return conv(x)
```