forked from flagos-ai/TransformerEngine-FL
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathper_tensor_scaling.py
More file actions
138 lines (112 loc) · 4.31 KB
/
Copy pathper_tensor_scaling.py
File metadata and controls
138 lines (112 loc) · 4.31 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# Copyright (c) 2022-2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#
# See LICENSE for license information.
"""PerTensorScaling Feature support for nvidia-dlframework-inspect"""
from typing import Optional
import torch
import nvdlfw_inspect.api as debug_api
from nvdlfw_inspect.registry import Registry, api_method
import transformer_engine_torch as tex
from transformer_engine import te_device_type
from transformer_engine.pytorch.tensor import Quantizer
from transformer_engine.pytorch.tensor.float8_tensor import (
Float8Tensor,
Float8Quantizer,
Float8CurrentScalingQuantizer,
)
from transformer_engine.debug.features.api import TEConfigAPIMapper
def per_tensor_cast(
tensor: torch.Tensor, fp8_dtype: tex.DType, out: Float8Tensor = None
) -> Float8Tensor:
"""
This function computes the scaling factors based on the tensor amax and then casts it to the fp8
"""
assert tensor.dtype in (
torch.float,
torch.float16,
torch.bfloat16,
), "[NVTORCH INSPECT ERROR] Unsupported tensor type for per tensor current scaling"
assert (
tensor.device.type == te_device_type()
), f"[NVTORCH INSPECT ERROR] Must be a {te_device_type()} tensor."
assert fp8_dtype in {
tex.DType.kFloat8E4M3,
tex.DType.kFloat8E5M2,
}, "[NVTORCH INSPECT ERROR] Only 2 FP8 types: E4M3 and E5M2 are supported in TE."
tensor = tensor.contiguous()
quantizer = Float8CurrentScalingQuantizer(fp8_dtype, device=tensor.device)
if out is not None:
quantizer.update_quantized(tensor, out)
return None
return quantizer(tensor)
@Registry.register_feature(namespace="transformer_engine")
class PerTensorScaling(TEConfigAPIMapper):
"""
Allows using per-tensor current scaling for the specific tensors.
Can be used only within `DelayedScaling` recipe autocast.
Parameters
----------
gemms/gemms_struct: List[str]
list of gemms to enable per-tensor current scaling for
- fprop
- dgrad
- wgrad
tensors/tensors_struct: List[str]
list of tensors to enable per-tensor current scaling for
- activation
- gradient
- weight
Example
-------
.. code-block:: yaml
example_per_tensor_scaling:
enabled: True
layers:
layer_types: [transformer_layer.self_attn.layernorm_q]
transformer_engine:
PerTensorScaling:
enabled: True
gemms: [dgrad]
tensors: [weight, activation]
"""
@api_method
def fp8_gemm(
self, config, layer_name: str, gemm: str, iteration: int
): # pylint: disable=unused-argument
"""API call responsible for selecting between high-precision and FP8 GEMM execution."""
return False, None
@api_method
def modify_tensor_enabled(
self, config, layer_name: str, tensor_name: str, gemm: str, iteration: int
): # pylint: disable=unused-argument
"""API call used to determine whether to run process_tensor() in the forward."""
return True, iteration + 1
@api_method
def modify_tensor(
self,
config,
layer_name: str,
gemm: str,
tensor_name: str,
tensor: torch.Tensor,
iteration: int,
default_quantizer: Quantizer,
out: Optional[Float8Tensor] = None,
dtype: Optional[torch.dtype] = None,
): # pylint: disable=unused-argument
"""API call used to process the tensor."""
for key in config.keys():
if key not in ["gemm", "tensor"]:
raise ValueError(f'[NVTORCH INSPECT ERROR] Unexpected key in config: "{key}".')
assert isinstance(default_quantizer, Float8Quantizer), (
f"[NVTORCH INSPECT ERROR] Feature={self.__class__.__name__}, API=process_tensor: "
"Per-tensor current scaling can be used only within `DelayedScaling` recipe autocast."
f" {layer_name}"
)
debug_api.log_message(
f"Feature={self.__class__.__name__}, API=process_tensor: {gemm}, {tensor_name}",
layer_name,
extra_cachable_args=(gemm, tensor_name),
)
fp8_tensor = per_tensor_cast(tensor, default_quantizer.dtype, out=out)
return fp8_tensor