已合并
rewrite_dropout_meta_and_decompose #33670
Ambi创建于 4月14日
rewrite_dropout_meta_and_decompose #33670
已合并
Ambi创建于 4月14日
已删除 :v2.10.0合入到Ascend/pytorchv2.10.0
4 个文件变更+94-62
@@ -0,0 +1,43 @@
1+import torch
2+import torch.nn.functional as F
3+from torch.testing._internal.common_utils import (
4+ run_tests,
5+ instantiate_parametrized_tests,
6+)
7+from testutils import TestUtils
8+import torch_npu
9+ 
10+torch._inductor.config.fallback_random = True
11+ 
12+ 
13+def dropout_with_backward(x):
14+ y = F.dropout(x, p=0.5, training=True)
15+ loss = y.sum()
16+ (grad_x,) = torch.autograd.grad(loss, x)
17+ return loss, grad_x
18+ 
19+ 
20+class TestDropoutCompile(TestUtils):
21+ def test_dropout_compile(self):
22+ device = "npu"
23+ 
24+ torch.manual_seed(0)
25+ eager_x = torch.randn(4, 8, device=device, requires_grad=True)
26+ compiled_x = eager_x.detach().clone().requires_grad_(True)
27+ 
28+ torch.manual_seed(42)
29+ eager_loss, eager_grad = dropout_with_backward(eager_x)
30+ 
31+ torch.manual_seed(42)
32+ compiled_fn = torch.compile(dropout_with_backward, backend="inductor")
33+ compiled_loss, compiled_grad = compiled_fn(compiled_x)
34+ 
35+ self.assertEqual(eager_loss, compiled_loss)
36+ self.assertEqual(eager_grad, compiled_grad)
37+ 
38+ 
39+instantiate_parametrized_tests(TestDropoutCompile)
40+ 
41+ 
42+if __name__ == "__main__":
43+ run_tests()
@@ -98,16 +98,4 @@ def npu_patch_meta():
98 op_overload.py_kernels.pop(DispatchKey.Meta, None)98 op_overload.py_kernels.pop(DispatchKey.Meta, None)
99 op_overload.py_impl(DispatchKey.Meta)(fn)99 op_overload.py_impl(DispatchKey.Meta)(fn)
100 100 
101- patch_torch_decomp_decompositions()101+ patch_torch_decomp_decompositions()
102- 
103- 
104-@register_meta_npu(aten.native_dropout)
105-def meta_native_dropout(tensor_input: Tensor, p: float, train: Optional[bool]):
106- if train and p != 0:
107- sizes_1 = tensor_input.shape
108- numel = reduce(operator.mul, sizes_1)
109- numel = (numel + 128 - 1) // 128 * 128
110- numel = numel // 8
111- return (torch.empty_like(tensor_input), torch.empty(numel, dtype=torch.uint8, device=tensor_input.device))
112- else:
113- return (tensor_input, torch.ones_like(tensor_input, dtype=torch.bool))
@@ -17,8 +17,6 @@ DECOMPOSITION_OVERLOAD_OP = [
17 aten.embedding_dense_backward,17 aten.embedding_dense_backward,
18 aten.addmm,18 aten.addmm,
19 aten.gelu,19 aten.gelu,
20- aten.native_dropout,
21- aten.native_dropout_backward
22]20]
23 21 
24 22 
@@ -38,26 +36,4 @@ def _register_npu_inductor_decompositons():
38 @register_decomposition([aten.erfc])36 @register_decomposition([aten.erfc])
39 def erfc(x):37 def erfc(x):
40 tensor = torch.ones_like(x) - torch.exp(x)38 tensor = torch.ones_like(x) - torch.exp(x)
41- return tensor39+ return tensor
42- 
43- @register_decomposition(aten.native_dropout)
44- @out_wrapper("out0", "out1")
45- def native_dropout(tensor_input, p, train):
46- if torch._inductor.config.fallback_random:
47- if train and p != 0:
48- return torch.ops.npu._npu_dropout(tensor_input, p)
49- return (tensor_input, torch.ones_like(tensor_input, dtype=torch.bool))
50- else:
51- from torch._decomp.decompositions import native_dropout
52- return native_dropout(tensor_input, p, train)
53- 
54- @register_decomposition(aten.native_dropout_backward)
55- @out_wrapper()
56- def native_dropout_backward(grad_output, mask, scale):
57- if torch._inductor.config.fallback_random:
58- p = 1 if scale == 0 else (1 - 1 / scale)
59- r = torch.ops.npu.npu_dropout_backward(grad_output, mask, p)
60- return r
61- else:
62- from torch._decomp.decompositions import native_dropout_backward
63- return native_dropout_backward(grad_output, mask, scale)
@@ -3,14 +3,13 @@ import sys
3import operator3import operator
4from typing import Optional4from typing import Optional
5from functools import wraps, reduce, lru_cache5from functools import wraps, reduce, lru_cache
6-from typing import Callable6+from typing import Callable, Optional
7import torch7import torch
8from torch import Tensor8from torch import Tensor
9from torch._ops import OpOverload, OpOverloadPacket9from torch._ops import OpOverload, OpOverloadPacket
10from torch._subclasses import fake_tensor as _subclasses_fake_tensor10from torch._subclasses import fake_tensor as _subclasses_fake_tensor
11from torch._C import DispatchKey11from torch._C import DispatchKey
12from torch._refs import div as refs_div, _broadcast_shapes12from torch._refs import div as refs_div, _broadcast_shapes
13-import torch._prims_common as utils
14from torch._inductor import decomposition as inductor_decompo13from torch._inductor import decomposition as inductor_decompo
15from torch._prims_common import corresponding_real_dtype, corresponding_complex_dtype14from torch._prims_common import corresponding_real_dtype, corresponding_complex_dtype
16from torch._prims_common.wrappers import out_wrapper15from torch._prims_common.wrappers import out_wrapper
@@ -58,9 +57,10 @@ def run_once(f):
58npu_meta_table = {}57npu_meta_table = {}
59break_fn_table = {}58break_fn_table = {}
60avoid_make_fallback_table = []59avoid_make_fallback_table = []
60+inductor_decomp_table = []
61 61 
62 62 
63-def _add_op_to_meta_table(op, fn, avoid_fallback_flag=False):63+def _add_op_to_meta_table(op, fn, avoid_fallback_flag=False, inductor_decomp=False):
64 overloads = []64 overloads = []
65 if isinstance(op, OpOverload):65 if isinstance(op, OpOverload):
66 overloads.append(op)66 overloads.append(op)
@@ -76,6 +76,21 @@ def _add_op_to_meta_table(op, fn, avoid_fallback_flag=False):
76 npu_meta_table[op_overload] = fn76 npu_meta_table[op_overload] = fn
77 if avoid_fallback_flag:77 if avoid_fallback_flag:
78 avoid_make_fallback_table.append(op_overload)78 avoid_make_fallback_table.append(op_overload)
79+ if inductor_decomp:
80+ inductor_decomp_table.append(op_overload)
81+ 
82+ 
83+def patch_torch_inductor_decompositions():
84+ '''
85+ TorchInductor traces compiled backward with its own decomposition table.
86+ Only patch ops that explicitly opted in via inductor_decomp=True so we
87+ don't accidentally overwrite unrelated inductor decompositions.
88+ '''
89+ import torch._inductor.decomposition as inductor_decomposition
90+
91+ for op_overload in inductor_decomp_table:
92+ if op_overload in npu_meta_table:
93+ inductor_decomposition.decompositions[op_overload] = npu_meta_table[op_overload]
79 94 
80 95 
81def patch_torch_decomp_decompositions():96def patch_torch_decomp_decompositions():
@@ -93,9 +108,9 @@ def patch_torch_decomp_decompositions():
93 _subclasses_fake_tensor.torch_decomp_decompositions = torch_decomp_decompositions_new108 _subclasses_fake_tensor.torch_decomp_decompositions = torch_decomp_decompositions_new
94 109 
95 110 
96-def register_meta_npu(op, avoid_fallback_flag=False):111+def register_meta_npu(op, avoid_fallback_flag=False, inductor_decomp=False):
97 def meta_decorator(fn: Callable):112 def meta_decorator(fn: Callable):
98- _add_op_to_meta_table(op, fn, avoid_fallback_flag)113+ _add_op_to_meta_table(op, fn, avoid_fallback_flag, inductor_decomp)
99 return fn114 return fn
100 115 
101 return meta_decorator116 return meta_decorator
@@ -131,6 +146,7 @@ def npu_patch_meta():
131 146 
132 inductor_decompo.fast_random_decomps.cache_clear()147 inductor_decompo.fast_random_decomps.cache_clear()
133 patch_torch_decomp_decompositions()148 patch_torch_decomp_decompositions()
149+ patch_torch_inductor_decompositions()
134 150 
135 151 
136@register_meta_npu(aten.index_put.default)152@register_meta_npu(aten.index_put.default)
@@ -138,28 +154,37 @@ def meta_index_put_patch(self, indices, values, accumulate=False):
138 return self.new_empty(self.shape)154 return self.new_empty(self.shape)
139 155 
140 156 
141-@register_meta_npu(aten.native_dropout)157+@register_meta_npu(aten.native_dropout, inductor_decomp=True)
142-def meta_native_dropout(tensor_input: Tensor, p: float, train: Optional[bool]):158+@out_wrapper("out0", "out1")
143- if train and p != 0:159+def meta_native_dropout_patch(tensor_input: Tensor, p: float, train: Optional[bool]):
144- sizes_1 = tensor_input.shape160+ if torch._inductor.config.fallback_random:
145- numel = reduce(operator.mul, sizes_1)161+ if train and p != 0:
146- numel = (numel + 128 - 1) // 128 * 128162+ if tensor_input.is_meta:
147- numel = numel // 8163+ numel = reduce(operator.mul, tensor_input.shape)
148- return (torch.empty_like(tensor_input), torch.empty(numel, dtype=torch.uint8, device=tensor_input.device))164+ numel = (numel + 128 - 1) // 128 * 128
149- else:165+ numel = numel // 8
166+ return (
167+ torch.empty_like(tensor_input),
168+ torch.empty(numel, dtype=torch.uint8, device=tensor_input.device),
169+ )
170+ return torch.ops.npu._npu_dropout(tensor_input, p)
150 return (tensor_input, torch.ones_like(tensor_input, dtype=torch.bool))171 return (tensor_input, torch.ones_like(tensor_input, dtype=torch.bool))
172+ else:
173+ from torch._decomp.decompositions import native_dropout
174+ return native_dropout(tensor_input, p, train)
151 175 
152 176 
153-@register_meta_npu(aten.native_dropout_backward)177+@register_meta_npu(aten.native_dropout_backward, inductor_decomp=True)
154-def meta_native_dropout_backward(178+@out_wrapper()
155- grad_output: Tensor,179+def meta_native_dropout_backward_patch(grad_output: Tensor, mask: Tensor, scale: float):
156- mask: Tensor,180+ if torch._inductor.config.fallback_random:
157- scale: float181+ if grad_output.is_meta:
158-):182+ return torch.empty_like(grad_output)
159- r = (grad_output).clone(183+ p = 1 if scale == 0 else (1 - 1 / scale)
160- memory_format=utils.suggest_memory_format(grad_output)184+ return torch.ops.npu.npu_dropout_backward(grad_output, mask, p)
161- )185+ else:
162- return r186+ from torch._decomp.decompositions import native_dropout_backward
187+ return native_dropout_backward(grad_output, mask, scale)
163 188 
164 189 
165@register_meta_npu(aten._to_copy.default)190@register_meta_npu(aten._to_copy.default)