You are an expert CUDA optimization engineer. I need you to write custom CUDA kernels to replace the PyTorch operators in the given architecture to get speedups.

You have complete freedom to choose the set of operators you want to replace. You may make the decision to replace some operators with custom CUDA kernels and leave others unchanged. You may replace multiple operators with custom implementations, consider operator fusion opportunities (combining multiple operators into a single kernel, for example, combining matmul+relu), or algorithmic changes (such as online softmax). You are only limited by your imagination.

Here's an example to show you the syntax of inline embedding custom CUDA operators in torch:

The example given architecture is:
python
import torch
import torch.nn as nn
import torch.nn.functional as F

class Model(nn.Module):
def init(self) -> None:
super().init()

def forward(self, a, b):
    return a + b
def get_inputs():
# randomly generate input tensors based on the model architecture
a = torch.randn(1, 128).cuda()
b = torch.randn(1, 128).cuda()
return [a, b]

def get_init_inputs():
# randomly generate tensors required for initialization based on the model architecture
return []



The example new arch with custom CUDA kernels looks like this:
python
import torch
import torch.nn as nn
import torch.nn.functional as F

class Model(nn.Module):
def init(self) -> None:
super().init()

def forward(self, a, b):
    return a + b
def get_inputs():
# randomly generate input tensors based on the model architecture
a = torch.randn(1, 128).cuda()
b = torch.randn(1, 128).cuda()
return [a, b]

def get_init_inputs():
# randomly generate tensors required for initialization based on the model architecture
return []



You are given the following architecture:
python
import torch
import torch.nn as nn

class Model(nn.Module):
“”"
Sigmoid Derivative operator implementation.
“”"
def init(self):
super(Model, self).init()

def forward(self, x: torch.Tensor) -> torch.Tensor:
    """
    Computes the derivative of sigmoid function: sigmoid'(x) = sigmoid(x) * (1 - sigmoid(x))

    Args:
        x (torch.Tensor): Input tensor of any shape.

    Returns:
        torch.Tensor: Output tensor with sigmoid derivative applied, same shape as input.
    """
    sigmoid_x = torch.sigmoid(x)
    return sigmoid_x * (1 - sigmoid_x)
batch_size = 16
channels = 64
height = 32
width = 32

def get_inputs():
x = torch.randn(batch_size, channels, height, width).cuda() * 2.0
return [x]

def get_init_inputs():
return []



Requirements for the CUDA implementation:
1. Use VECTORIZED optimization strategy with the following key techniques:
   - 4-element vectorized processing (each thread processes 4 consecutive elements)
   - Batch computation to reduce branch prediction failures
   - Coalesced memory access patterns for optimal bandwidth utilization
   - Numerically stable sigmoid computation to avoid overflow
   - Optimized thread configuration (block_size=256, grid_size optimization)
   - Memory access optimization with __restrict__ pointers
   - CUDA compilation flags: -O3, --use_fast_math, -std=c++17, -maxrregcount=64

2. The CUDA kernel should implement:
cpp
global void sigmoid_derivative_vectorized4_kernel(
const float* restrict x,
float* restrict y,
int size
)



3. Vectorized processing requirements:
   - Each thread should load 4 consecutive elements: x0, x1, x2, x3
   - Compute sigmoid for all 4 elements in batch
   - Store 4 results: y0, y1, y2, y3
   - Handle remainder elements (size % 4) separately
   - Use stride-based loop for parallel processing

4. Performance targets:
   - Achieve 8-10x speedup for small-scale data (1M elements)
   - Achieve 3-4x speedup for medium/large-scale data (16M+ elements)
   - Maintain numerical precision (max difference < 1e-7)
   - Optimize for memory bandwidth utilization (400+ GB/s)
   - Handle various tensor sizes efficiently

5. The implementation should follow the exact structure of the VECTORIZED version that achieved 9.72x speedup, with proper handling of:
   - Vectorized load/store operations
   - Batch sigmoid computation
   - Remainder element processing
   - Thread synchronization

6. Expected performance results:
   - Small scale (1M elements): 9.72x speedup, 438.38 GB/s memory bandwidth
   - Medium scale (16M elements): 3.19x speedup, 1316.66 GB/s memory bandwidth
   - Large scale (256M elements): 3.44x speedup, 1464.11 GB/s memory bandwidth
   - Perfect precision alignment (max difference < 1e-7)
Please generate the complete CUDA-optimized version following these VECTORIZED specifications.