Write a custom CUDA kernel to optimize the AconC (Activate or Not) activation function.

The mathematical definition is:
f(x) = (p1*x - p2*x) * sigmoid(beta * (p1*x - p2*x)) + p2*x
where p1, p2, and beta are scalar parameters.

Problem Analysis:
The standard PyTorch implementation is heavily memory-bound due to the complex arithmetic chain.
1. It generates multiple intermediate tensors for terms like `p1*x`, `p2*x`, `p1*x - p2*x`, and the sigmoid result.
2. It requires multiple passes over global memory to read inputs and write intermediate results, saturating memory bandwidth.
3. The arithmetic intensity is relatively high for an activation function, involving exp, multiple multiplications, and additions.

Optimization Strategy: Fused Element-wise Kernel with Vectorized Access

1. Mathematical Simplification & Fusion: Simplify the expression in the kernel to reuse intermediate values stored in registers.
   Let diff = (p1 - p2) * x
   Result = diff * sigmoid(beta * diff) + p2 * x
   This avoids re-reading x or re-computing the difference.

2. Vectorized Memory Access: Use float4 data types to load and store 128 bits (4 floats) per instruction. This is crucial for hiding the latency of the arithmetic operations (especially exp).

3. Fast Math Intrinsics: Use `__expf` for the sigmoid calculation `1.0 / (1.0 + __expf(-val))` to speed up the transcendental part.

4. Grid-Stride Loop: Implement a robust grid-stride loop to handle any tensor size efficiently.
  
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

BATCH_SIZE = 64
CHANNELS = 128
HEIGHT = 56
WIDTH = 56
SHAPE = (BATCH_SIZE, CHANNELS, HEIGHT, WIDTH)

DTYPE = torch.float64

class AconC(nn.Module):
    """ ACON activation (activate or not).
    # AconC: (p1*x-p2*x) * sigmoid(beta*(p1*x-p2*x)) + p2*x, beta is a learnable parameter
    # according to "Activate or Not: Learning Customized Activation" <https://arxiv.org/pdf/2009.04759.pdf>.
    """
    def __init__(self, p1, p2, beta):
        super().__init__()
        self.p1 = nn.Parameter(p1)
        self.p2 = nn.Parameter(p2)
        self.beta = nn.Parameter(beta)

    def forward(self, x):
        return (self.p1 * x - self.p2 * x) * torch.sigmoid(self.beta * (self.p1 * x - self.p2 * x)) + self.p2 * x

class Model(nn.Module):
    def __init__(self, p1, p2, beta):
        super(Model, self).__init__()
        self.act = AconC(p1, p2, beta)
    
    def forward(self, x: torch.Tensor) -> torch.Tensor:
        return self.act(x)

def get_inputs():
    x = torch.randn(SHAPE, dtype=DTYPE)
    return [x.contiguous()]

def get_init_inputs():
    p1 = torch.randn(1, CHANNELS, 1, 1, dtype=DTYPE)
    p2 = torch.randn(1, CHANNELS, 1, 1, dtype=DTYPE)
    beta = torch.ones(1, CHANNELS, 1, 1, dtype=DTYPE)
    return [p1, p2, beta]