Skip to content

Commit 7f788a3

Browse files
authored
Add scaled_masked_softmax_forward/backward for flagos backend (flagos-ai#52)
Add two functions for flagos backend, based on flaggems - scaled_masked_softmax_forward - scaled_masked_softmax_backend
1 parent 4f54860 commit 7f788a3

4 files changed

Lines changed: 97 additions & 0 deletions

File tree

transformer_engine/plugin/core/backends/flagos/flagos.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
multi_tensor_adam_param_remainder_fl,
1818
multi_tensor_l2_norm_fl,
1919
generic_gemm_fl,
20+
scaled_masked_softmax_forward_fl,
21+
scaled_masked_softmax_backward_fl,
2022
)
2123

2224

@@ -160,6 +162,23 @@ def rmsnorm_bwd(
160162
def get_fused_attn_backend(self, *args, **kwargs) -> int:
161163
return NVTE_Fused_Attn_Backend.NVTE_No_Backend
162164

165+
# Softmax functions
166+
def scaled_masked_softmax_forward(
167+
self,
168+
input: torch.Tensor,
169+
mask: torch.Tensor,
170+
scale_factor: Union[float, torch.Tensor],
171+
) -> torch.Tensor:
172+
return scaled_masked_softmax_forward_fl(input, mask, scale_factor)
173+
174+
def scaled_masked_softmax_backward(
175+
self,
176+
output_grad_: torch.Tensor,
177+
softmax_results_: torch.Tensor,
178+
scale_factor: float,
179+
) -> torch.Tensor:
180+
return scaled_masked_softmax_backward_fl(output_grad_, softmax_results_, scale_factor)
181+
163182
# multi-tensor functions
164183
def multi_tensor_scale(
165184
self,

transformer_engine/plugin/core/backends/flagos/impl/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@
66
from .rmsnorm import *
77
from .fused_adam import *
88
from .multi_tensor import *
9+
from .softmax import *
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import torch
2+
from typing import Union
3+
import flag_gems
4+
5+
6+
def scaled_masked_softmax_forward_fl(
7+
input: torch.Tensor,
8+
mask: torch.Tensor,
9+
scale_factor: Union[float, torch.Tensor],
10+
) -> torch.Tensor:
11+
# Ensure `mask` and 'scale_factor' is on the same device as `input`.
12+
if mask.device != input.device:
13+
mask = flag_gems.to_copy(mask, device=input.device)
14+
if isinstance(scale_factor, torch.Tensor):
15+
if scale_factor.device != input.device:
16+
scale_factor = flag_gems.to_copy(scale_factor, device=input.device)
17+
18+
# Keep semantics aligned with TE CUDA scaled_masked_softmax:
19+
# - integer/bool mask: masked iff mask == 1, masked logits set to -10000.0
20+
# - float mask: treated as additive bias in logit space
21+
if mask.dim() == 4 and mask.size(1) == 1 and input.dim() == 4:
22+
mask = mask.expand_as(input)
23+
24+
scaled = flag_gems.mul(input, scale_factor)
25+
if mask.is_floating_point():
26+
mask_f = flag_gems.to_copy(mask, device=input.device, dtype=scaled.dtype)
27+
scaled = flag_gems.add(scaled, mask_f)
28+
return flag_gems.softmax(scaled, dim=-1)
29+
30+
# Avoid using `mask == 1` (torch op) since on some devices it may fall back to CPU,
31+
# which would break Triton kernels inside flag_gems.
32+
cond = flag_gems.eq_scalar(mask, 1)
33+
scaled = flag_gems.masked_fill(scaled, cond, -10000.0)
34+
all_masked = flag_gems.all_dim(cond, dim=-1, keepdim=True)
35+
out = flag_gems.softmax(scaled, dim=-1)
36+
return flag_gems.masked_fill(out, all_masked, 0.0)
37+
38+
39+
def scaled_masked_softmax_backward_fl(
40+
output_grad_: torch.Tensor,
41+
softmax_results_: torch.Tensor,
42+
scale_factor: float,
43+
) -> torch.Tensor:
44+
orig_dtype = output_grad_.dtype
45+
# Compute in float32 for numerical stability.
46+
output_grad_f32 = flag_gems.to_copy(output_grad_, dtype=torch.float32)
47+
softmax_output_f32 = flag_gems.to_copy(
48+
softmax_results_, dtype=torch.float32, device=output_grad_.device
49+
)
50+
if isinstance(scale_factor, torch.Tensor):
51+
if scale_factor.device != output_grad_.device:
52+
scale_factor = flag_gems.to_copy(scale_factor, device=output_grad_.device)
53+
54+
# term = softmax_output_f32 * output_grad_f32
55+
term = flag_gems.mul(softmax_output_f32, output_grad_f32)
56+
# sum_term = sum(term, dim=-1, keepdim=True)
57+
sum_term = flag_gems.sum_dim(term, dim=[-1], keepdim=True)
58+
# grad_softmax = softmax_output_f32 * (output_grad_f32 - sum_term)
59+
grad_softmax = flag_gems.mul(softmax_output_f32, flag_gems.sub(output_grad_f32, sum_term))
60+
grad_scaled = flag_gems.mul(grad_softmax, scale_factor)
61+
return flag_gems.to_copy(grad_scaled, dtype=orig_dtype)

transformer_engine/plugin/core/backends/flagos/register_ops.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,22 @@ def register_builtins(registry) -> None:
132132
vendor=None,
133133
priority=150,
134134
),
135+
OpImpl(
136+
op_name="scaled_masked_softmax_forward",
137+
impl_id="default.flagos",
138+
kind=BackendImplKind.DEFAULT,
139+
fn=_bind_is_available(backend.scaled_masked_softmax_forward, is_avail),
140+
vendor=None,
141+
priority=150,
142+
),
143+
OpImpl(
144+
op_name="scaled_masked_softmax_backward",
145+
impl_id="default.flagos",
146+
kind=BackendImplKind.DEFAULT,
147+
fn=_bind_is_available(backend.scaled_masked_softmax_backward, is_avail),
148+
vendor=None,
149+
priority=150,
150+
),
135151
OpImpl(
136152
op_name="get_cudnn_version",
137153
impl_id="default.flagos",

0 commit comments

Comments
 (0)