Skip to content

Commit 3b2e850

Browse files
authored
[KernelGen][Kunlunxin] Add bernoulli operator (#289)
Co-authored-by: NineAnnAnn <NineAnnAnn@users.noreply.github.com>
1 parent 4500b7e commit 3b2e850

2 files changed

Lines changed: 87 additions & 0 deletions

File tree

src/flag_gems/runtime/backend/_kunlunxin/ops/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
from .avg_pool2d import avg_pool2d, avg_pool2d_backward
5757
from .baddbmm import baddbmm
5858
from .batch_norm import batch_norm, batch_norm_backward
59+
from .bernoulli import bernoulli
5960
from .bernoulli_ import bernoulli_
6061
from .bitwise_and import (
6162
bitwise_and_scalar,
@@ -781,4 +782,5 @@
781782
"zero_out",
782783
"zeros",
783784
"zeros_like",
785+
"bernoulli",
784786
]
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
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

Comments
 (0)