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


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

__global__ void expand_sparse_3d_kernel(
    const float* __restrict__ input,
    const float* __restrict__ bias,
    float* __restrict__ output,
    int64_t count,
    int channels,
    int depth,
    int height,
    int width)
{
    const int64_t out_d = 2LL * depth + 1;
    const int64_t out_h = 2LL * height + 1;
    const int64_t out_w = 2LL * width + 1;

    for (int64_t index =
             static_cast<int64_t>(blockIdx.x) * blockDim.x + threadIdx.x;
         index < count;
         index += static_cast<int64_t>(blockDim.x) * gridDim.x)
    {
        int64_t position = index;
        const int64_t w = position % out_w;
        position /= out_w;
        const int64_t h = position % out_h;
        position /= out_h;
        const int64_t d = position % out_d;
        const int64_t nc = position / out_d;

        float value = bias ? bias[nc % channels] : 0.0f;

        if ((d & 1) && (h & 1) && (w & 1)) {
            const int64_t source =
                ((nc * depth + (d >> 1)) * height + (h >> 1))
                * width + (w >> 1);
            value += input[source];
        }

        output[index] = value;
    }
}

torch::Tensor expand_sparse_3d_cuda(
    torch::Tensor input,
    c10::optional<torch::Tensor> bias)
{
    TORCH_CHECK(input.is_cuda(), "input must be a CUDA tensor");
    TORCH_CHECK(input.scalar_type() == torch::kFloat32,
                "input must have dtype float32");
    TORCH_CHECK(input.dim() == 5 && input.is_contiguous(),
                "input must be contiguous NCDHW");

    const c10::cuda::CUDAGuard device_guard(input.device());

    const int channels = input.size(1);
    const int depth = input.size(2);
    const int height = input.size(3);
    const int width = input.size(4);

    const float* bias_ptr = nullptr;
    if (bias.has_value()) {
        const auto& b = bias.value();
        TORCH_CHECK(b.device() == input.device(),
                    "bias and input must be on the same device");
        TORCH_CHECK(b.scalar_type() == torch::kFloat32 &&
                    b.is_contiguous() && b.numel() == channels,
                    "invalid bias");
        bias_ptr = b.data_ptr<float>();
    }

    auto output = torch::empty(
        {input.size(0), input.size(1),
         2LL * depth + 1, 2LL * height + 1, 2LL * width + 1},
        input.options());

    const int64_t count = output.numel();
    if (count != 0) {
        constexpr int threads = 256;
        const int blocks = static_cast<int>(
            std::min<int64_t>((count + threads - 1) / threads, 65535));

        expand_sparse_3d_kernel<<<
            blocks, threads, 0, at::cuda::getCurrentCUDAStream()>>>(
                input.data_ptr<float>(), bias_ptr,
                output.data_ptr<float>(), count,
                channels, depth, height, width);

        C10_CUDA_KERNEL_LAUNCH_CHECK();
    }

    return output;
}
"""

_cpp_source = r"""
#include <torch/extension.h>

torch::Tensor expand_sparse_3d_cuda(
    torch::Tensor input,
    c10::optional<torch::Tensor> bias);
"""

_sparse_ops = load_inline(
    name="sparse_conv_transpose3d_expand_v1",
    cpp_sources=_cpp_source,
    cuda_sources=_cuda_source,
    functions=["expand_sparse_3d_cuda"],
    extra_cflags=["-O3"],
    extra_cuda_cflags=["-O3"],
    verbose=False,
)


class _ExpandSparse3D(torch.autograd.Function):
    @staticmethod
    def forward(ctx, x, bias):
        ctx.has_bias = bias is not None
        return _sparse_ops.expand_sparse_3d_cuda(x, bias)

    @staticmethod
    def backward(ctx, grad_output):
        grad_x = grad_output[:, :, 1::2, 1::2, 1::2].contiguous()
        grad_bias = (
            grad_output.sum(dim=(0, 2, 3, 4))
            if ctx.has_bias and ctx.needs_input_grad[1]
            else None
        )
        return grad_x, grad_bias


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,
        bias: bool = False,
    ):
        super().__init__()
        self.conv_transpose3d = nn.ConvTranspose3d(
            in_channels,
            out_channels,
            kernel_size=(kernel_size, kernel_size, kernel_size),
            stride=stride,
            padding=padding,
            dilation=dilation,
            bias=bias,
        )

    def forward(self, x: torch.Tensor) -> torch.Tensor:
        conv = self.conv_transpose3d

        if (
            x.is_cuda
            and x.dtype == torch.float32
            and conv.weight.dtype == torch.float32
            and conv.kernel_size == (3, 3, 3)
            and conv.stride == (2, 2, 2)
            and conv.padding == (1, 1, 1)
            and conv.dilation == (2, 2, 2)
            and conv.output_padding == (0, 0, 0)
            and not torch.is_autocast_enabled()
        ):
            # All nonzero convolution contributions occupy odd coordinates.
            # Compute that subvolume directly, then expand and fuse the bias.
            compact = F.conv_transpose3d(
                x,
                conv.weight,
                bias=None,
                stride=1,
                padding=1,
                output_padding=0,
                groups=conv.groups,
                dilation=1,
            )
            return _ExpandSparse3D.apply(compact.contiguous(), conv.bias)

        return conv(x)
```