Write a custom CUDA kernel to replace PyTorch's Focal Loss implementation for binary classification.

You are given the following PyTorch architecture:

python
import torch
import torch.nn as nn
import torch.nn.functional as F

class Model(nn.Module):
“”"
Focal Loss implementation for binary classification.
Focal Loss = -α * (1-pt)^γ * log(pt)
where pt = p if target=1, else (1-p)
“”"
def init(self, alpha=0.25, gamma=2.0, reduction=‘mean’):
super(Model, self).init()
self.alpha = alpha
self.gamma = gamma
self.reduction = reduction

def forward(self, inputs: torch.Tensor, targets: torch.Tensor) -> torch.Tensor:
    """
    Compute Focal Loss between inputs and targets.
    
    Args:
        inputs (torch.Tensor): Predicted logits of shape (batch_size, num_classes)
        targets (torch.Tensor): Ground truth labels of shape (batch_size,)
    
    Returns:
        torch.Tensor: Computed focal loss
    """
    # Convert logits to probabilities
    probs = torch.sigmoid(inputs)
    
    # Compute pt
    pt = torch.where(targets == 1, probs, 1 - probs)
    
    # Compute focal weight
    focal_weight = self.alpha * torch.pow(1 - pt, self.gamma)
    
    # Compute binary cross entropy
    bce = F.binary_cross_entropy_with_logits(inputs, targets.float(), reduction='none')
    
    # Apply focal weight
    focal_loss = focal_weight * bce
    
    if self.reduction == 'mean':
        return focal_loss.mean()
    elif self.reduction == 'sum':
        return focal_loss.sum()
    else:
        return focal_loss
batch_size = 32
num_classes = 1

def get_inputs():
inputs = torch.randn(batch_size, num_classes, dtype=torch.float32)
targets = torch.randint(0, 2, (batch_size,), dtype=torch.float32)
return [inputs, targets]

def get_init_inputs():
return []




Your task is to optimize this Focal Loss implementation by:

1. **Operator Fusion**: Combine the multiple PyTorch operations (sigmoid, where, pow, binary_cross_entropy_with_logits, multiplication) into a single CUDA kernel to eliminate intermediate tensor storage and memory bandwidth overhead.

2. **Numerical Stability**: Implement numerically stable sigmoid computation to avoid overflow/underflow issues, and add proper bounds checking to prevent log(0) errors.

3. **Memory Access Optimization**: Minimize global memory access by keeping intermediate computations in registers, and ensure coalesced memory access patterns.

4. **Thread Configuration**: Use optimal block size (e.g., 256 threads) and compute grid dimensions dynamically based on input size.

5. **Type Consistency**: Ensure all tensors use float32 for consistency and performance.

The optimized CUDA kernel should:
- Take logits and targets as input (both float32)
- Compute sigmoid, pt, focal weight, and BCE loss in a single kernel
- Output the focal loss values
- Support both 'mean' and 'sum' reduction modes
- Maintain numerical stability with proper epsilon handling
- Achieve significant speedup over the PyTorch implementation

Follow the inline CUDA extension syntax example provided in the reference. The kernel should be optimized for GPU architectures and demonstrate performance improvements through reduced memory access and fused computation.
