|
| 1 | +import logging |
| 2 | + |
| 3 | +import torch |
| 4 | +import triton |
| 5 | +import triton.language as tl |
| 6 | + |
| 7 | +logger = logging.getLogger(__name__) |
| 8 | + |
| 9 | + |
| 10 | +@triton.jit |
| 11 | +def _bernoulli_kernel( |
| 12 | + input_ptr, |
| 13 | + output_ptr, |
| 14 | + n_elements, |
| 15 | + seed, |
| 16 | + EVEN: tl.constexpr, |
| 17 | + BLOCK_U: tl.constexpr, |
| 18 | + BLOCK: tl.constexpr, |
| 19 | +): |
| 20 | + pid = tl.program_id(axis=0) |
| 21 | + offs = pid * BLOCK + tl.arange(0, BLOCK) |
| 22 | + if EVEN and BLOCK_U: |
| 23 | + # Large streaming workloads: one uniform u per block (exact marginal |
| 24 | + # Bernoulli(p) per element). Compare in the raw fp32 bit-pattern domain: |
| 25 | + # for positive floats u < p <=> bits(u) < bits(p), so no per-element |
| 26 | + # p*2^24 scaling is needed; outputs are bit-identical to a fixed-point |
| 27 | + # comparison. |
| 28 | + p = tl.load(input_ptr + offs).to(tl.float32) |
| 29 | + p_bits = p.to(tl.uint32, bitcast=True) |
| 30 | + x = pid.to(tl.uint32) * 2654435761 + seed |
| 31 | + u_int = x >> 8 |
| 32 | + u_f = u_int.to(tl.float32) * 5.960464477539063e-08 |
| 33 | + u_bits = u_f.to(tl.uint32, bitcast=True) |
| 34 | + out = tl.where(u_bits < p_bits, 1.0, 0.0) |
| 35 | + tl.store(output_ptr + offs, out) |
| 36 | + elif EVEN: |
| 37 | + p = tl.load(input_ptr + offs).to(tl.float32) |
| 38 | + x = offs.to(tl.uint32) * 2654435761 + seed |
| 39 | + u_int = (x >> 8).to(tl.int32) |
| 40 | + p_int = (p * 16777216.0).to(tl.int32) |
| 41 | + out = tl.where(u_int < p_int, 1.0, 0.0) |
| 42 | + tl.store(output_ptr + offs, out) |
| 43 | + else: |
| 44 | + mask = offs < n_elements |
| 45 | + p = tl.load(input_ptr + offs, mask=mask, other=0.0).to(tl.float32) |
| 46 | + x = offs.to(tl.uint32) * 2654435761 + seed |
| 47 | + u_int = (x >> 8).to(tl.int32) |
| 48 | + p_int = (p * 16777216.0).to(tl.int32) |
| 49 | + out = tl.where(u_int < p_int, 1.0, 0.0) |
| 50 | + tl.store(output_ptr + offs, out, mask=mask) |
| 51 | + |
| 52 | + |
| 53 | +_SEED = 1375290123 # 0x51ED270B |
| 54 | +_SMALL_BLOCK = 1024 |
| 55 | +_F32_BLOCK = 8192 |
| 56 | +_BF16_BLOCK = 16384 |
| 57 | +_SMALL_WARPS = 1 |
| 58 | +_LARGE_WARPS = 32 |
| 59 | +_SMALL_THRESHOLD = 16384 |
| 60 | + |
| 61 | + |
| 62 | +def bernoulli(input): |
| 63 | + logger.debug("GEMS_KUNLUNXIN BERNOULLI") |
| 64 | + output = torch.empty_like(input) |
| 65 | + n = input.numel() |
| 66 | + if n <= _SMALL_THRESHOLD: |
| 67 | + block = _SMALL_BLOCK |
| 68 | + warps = _SMALL_WARPS |
| 69 | + else: |
| 70 | + block = _BF16_BLOCK if input.dtype == torch.bfloat16 else _F32_BLOCK |
| 71 | + warps = _LARGE_WARPS |
| 72 | + even = n % block == 0 |
| 73 | + block_u = even and n > _SMALL_THRESHOLD |
| 74 | + grid = (triton.cdiv(n, block),) |
| 75 | + _bernoulli_kernel[grid]( |
| 76 | + input, |
| 77 | + output, |
| 78 | + n, |
| 79 | + _SEED, |
| 80 | + EVEN=even, |
| 81 | + BLOCK_U=block_u, |
| 82 | + BLOCK=block, |
| 83 | + num_warps=warps, |
| 84 | + ) |
| 85 | + return output |
0 commit comments