ZhengyangZhang commited on
Commit
498bf57
·
verified ·
1 Parent(s): 5b4e3c2

Add files using upload-large-folder tool

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. lib/python3.12/site-packages/torch/_C/_VariableFunctions.pyi +0 -0
  2. lib/python3.12/site-packages/torch/_C/__init__.pyi +0 -0
  3. lib/python3.12/site-packages/torch/_C/_aoti.pyi +24 -0
  4. lib/python3.12/site-packages/torch/_C/_autograd.pyi +135 -0
  5. lib/python3.12/site-packages/torch/_C/_cpu.pyi +14 -0
  6. lib/python3.12/site-packages/torch/_C/_cudnn.pyi +17 -0
  7. lib/python3.12/site-packages/torch/_C/_cusparselt.pyi +1 -0
  8. lib/python3.12/site-packages/torch/_C/_distributed_autograd.pyi +27 -0
  9. lib/python3.12/site-packages/torch/_C/_distributed_c10d.pyi +695 -0
  10. lib/python3.12/site-packages/torch/_C/_distributed_rpc.pyi +188 -0
  11. lib/python3.12/site-packages/torch/_C/_distributed_rpc_testing.pyi +32 -0
  12. lib/python3.12/site-packages/torch/_C/_export.pyi +10 -0
  13. lib/python3.12/site-packages/torch/_C/_functions.pyi +19 -0
  14. lib/python3.12/site-packages/torch/_C/_functorch.pyi +83 -0
  15. lib/python3.12/site-packages/torch/_C/_instruction_counter.pyi +4 -0
  16. lib/python3.12/site-packages/torch/_C/_itt.pyi +5 -0
  17. lib/python3.12/site-packages/torch/_C/_lazy.pyi +27 -0
  18. lib/python3.12/site-packages/torch/_C/_lazy_ts_backend.pyi +12 -0
  19. lib/python3.12/site-packages/torch/_C/_monitor.pyi +44 -0
  20. lib/python3.12/site-packages/torch/_C/_nn.pyi +89 -0
  21. lib/python3.12/site-packages/torch/_C/_nvtx.pyi +9 -0
  22. lib/python3.12/site-packages/torch/_C/_onnx.pyi +39 -0
  23. lib/python3.12/site-packages/torch/_C/_profiler.pyi +245 -0
  24. lib/python3.12/site-packages/torch/_C/_verbose.pyi +3 -0
  25. lib/python3.12/site-packages/torch/_custom_op/__init__.py +0 -0
  26. lib/python3.12/site-packages/torch/_custom_op/__pycache__/__init__.cpython-312.pyc +0 -0
  27. lib/python3.12/site-packages/torch/_custom_op/__pycache__/autograd.cpython-312.pyc +0 -0
  28. lib/python3.12/site-packages/torch/_custom_op/__pycache__/functional.cpython-312.pyc +0 -0
  29. lib/python3.12/site-packages/torch/_custom_op/__pycache__/impl.cpython-312.pyc +0 -0
  30. lib/python3.12/site-packages/torch/_custom_op/autograd.py +275 -0
  31. lib/python3.12/site-packages/torch/_custom_op/functional.py +188 -0
  32. lib/python3.12/site-packages/torch/_custom_op/impl.py +670 -0
  33. lib/python3.12/site-packages/torch/amp/__init__.py +9 -0
  34. lib/python3.12/site-packages/torch/amp/__pycache__/__init__.cpython-312.pyc +0 -0
  35. lib/python3.12/site-packages/torch/amp/__pycache__/autocast_mode.cpython-312.pyc +0 -0
  36. lib/python3.12/site-packages/torch/amp/__pycache__/grad_scaler.cpython-312.pyc +0 -0
  37. lib/python3.12/site-packages/torch/amp/autocast_mode.py +551 -0
  38. lib/python3.12/site-packages/torch/amp/grad_scaler.py +685 -0
  39. lib/python3.12/site-packages/torch/bin/torch_shm_manager +0 -0
  40. lib/python3.12/site-packages/torch/contrib/__init__.py +0 -0
  41. lib/python3.12/site-packages/torch/contrib/__pycache__/__init__.cpython-312.pyc +0 -0
  42. lib/python3.12/site-packages/torch/contrib/__pycache__/_tensorboard_vis.cpython-312.pyc +0 -0
  43. lib/python3.12/site-packages/torch/contrib/_tensorboard_vis.py +143 -0
  44. lib/python3.12/site-packages/torch/cuda/__init__.py +1729 -0
  45. lib/python3.12/site-packages/torch/cuda/__pycache__/__init__.cpython-312.pyc +0 -0
  46. lib/python3.12/site-packages/torch/cuda/__pycache__/_gpu_trace.cpython-312.pyc +0 -0
  47. lib/python3.12/site-packages/torch/cuda/__pycache__/_memory_viz.cpython-312.pyc +0 -0
  48. lib/python3.12/site-packages/torch/cuda/__pycache__/_sanitizer.cpython-312.pyc +0 -0
  49. lib/python3.12/site-packages/torch/cuda/__pycache__/_utils.cpython-312.pyc +0 -0
  50. lib/python3.12/site-packages/torch/cuda/__pycache__/comm.cpython-312.pyc +0 -0
lib/python3.12/site-packages/torch/_C/_VariableFunctions.pyi ADDED
The diff for this file is too large to render. See raw diff
 
lib/python3.12/site-packages/torch/_C/__init__.pyi ADDED
The diff for this file is too large to render. See raw diff
 
lib/python3.12/site-packages/torch/_C/_aoti.pyi ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from ctypes import c_void_p
2
+
3
+ from torch import Tensor
4
+
5
+ # Defined in torch/csrc/inductor/aoti_runner/pybind.cpp
6
+
7
+ # Tensor to AtenTensorHandle
8
+ def unsafe_alloc_void_ptrs_from_tensors(tensors: list[Tensor]) -> list[c_void_p]: ...
9
+ def unsafe_alloc_void_ptr_from_tensor(tensor: Tensor) -> c_void_p: ...
10
+
11
+ # AtenTensorHandle to Tensor
12
+ def alloc_tensors_by_stealing_from_void_ptrs(
13
+ handles: list[c_void_p],
14
+ ) -> list[Tensor]: ...
15
+ def alloc_tensor_by_stealing_from_void_ptr(
16
+ handle: c_void_p,
17
+ ) -> Tensor: ...
18
+
19
+ class AOTIModelContainerRunnerCpu: ...
20
+ class AOTIModelContainerRunnerCuda: ...
21
+ class AOTIModelContainerRunnerXpu: ...
22
+
23
+ # Defined in torch/csrc/inductor/aoti_package/pybind.cpp
24
+ class AOTIModelPackageLoader: ...
lib/python3.12/site-packages/torch/_C/_autograd.pyi ADDED
@@ -0,0 +1,135 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # mypy: allow-untyped-defs
2
+ from enum import Enum
3
+ from typing import Any, Callable
4
+
5
+ import torch
6
+ from torch._C._profiler import (
7
+ _ProfilerEvent,
8
+ ActiveProfilerType,
9
+ ProfilerActivity,
10
+ ProfilerConfig,
11
+ )
12
+
13
+ # Defined in torch/csrc/autograd/init.cpp
14
+
15
+ class DeviceType(Enum):
16
+ CPU = ...
17
+ CUDA = ...
18
+ XPU = ...
19
+ MKLDNN = ...
20
+ OPENGL = ...
21
+ OPENCL = ...
22
+ IDEEP = ...
23
+ HIP = ...
24
+ FPGA = ...
25
+ MAIA = ...
26
+ XLA = ...
27
+ MTIA = ...
28
+ MPS = ...
29
+ HPU = ...
30
+ Meta = ...
31
+ Vulkan = ...
32
+ Metal = ...
33
+ PrivateUse1 = ...
34
+
35
+ class ProfilerEvent:
36
+ def cpu_elapsed_us(self, other: ProfilerEvent) -> float: ...
37
+ def cpu_memory_usage(self) -> int: ...
38
+ def cuda_elapsed_us(self, other: ProfilerEvent) -> float: ...
39
+ def privateuse1_elapsed_us(self, other: ProfilerEvent) -> float: ...
40
+ def cuda_memory_usage(self) -> int: ...
41
+ def device(self) -> int: ...
42
+ def handle(self) -> int: ...
43
+ def has_cuda(self) -> bool: ...
44
+ def is_remote(self) -> bool: ...
45
+ def kind(self) -> int: ...
46
+ def name(self) -> str: ...
47
+ def node_id(self) -> int: ...
48
+ def sequence_nr(self) -> int: ...
49
+ def shapes(self) -> list[list[int]]: ...
50
+ def thread_id(self) -> int: ...
51
+ def flops(self) -> float: ...
52
+ def is_async(self) -> bool: ...
53
+
54
+ class _KinetoEvent:
55
+ def name(self) -> str: ...
56
+ def device_index(self) -> int: ...
57
+ def device_resource_id(self) -> int: ...
58
+ def start_ns(self) -> int: ...
59
+ def end_ns(self) -> int: ...
60
+ def duration_ns(self) -> int: ...
61
+ def is_async(self) -> bool: ...
62
+ def linked_correlation_id(self) -> int: ...
63
+ def shapes(self) -> list[list[int]]: ...
64
+ def dtypes(self) -> list[str]: ...
65
+ def concrete_inputs(self) -> list[Any]: ...
66
+ def kwinputs(self) -> dict[str, Any]: ...
67
+ def device_type(self) -> DeviceType: ...
68
+ def start_thread_id(self) -> int: ...
69
+ def end_thread_id(self) -> int: ...
70
+ def correlation_id(self) -> int: ...
71
+ def fwd_thread_id(self) -> int: ...
72
+ def stack(self) -> list[str]: ...
73
+ def scope(self) -> int: ...
74
+ def sequence_nr(self) -> int: ...
75
+ def flops(self) -> int: ...
76
+ def cuda_elapsed_us(self) -> int: ...
77
+ def privateuse1_elapsed_us(self) -> int: ...
78
+ def is_user_annotation(self) -> bool: ...
79
+
80
+ class _ProfilerResult:
81
+ def events(self) -> list[_KinetoEvent]: ...
82
+ def legacy_events(self) -> list[list[ProfilerEvent]]: ...
83
+ def save(self, path: str) -> None: ...
84
+ def experimental_event_tree(self) -> list[_ProfilerEvent]: ...
85
+ def trace_start_ns(self) -> int: ...
86
+
87
+ class SavedTensor: ...
88
+
89
+ def _enable_profiler(
90
+ config: ProfilerConfig,
91
+ activities: set[ProfilerActivity],
92
+ ) -> None: ...
93
+ def _prepare_profiler(
94
+ config: ProfilerConfig,
95
+ activities: set[ProfilerActivity],
96
+ ) -> None: ...
97
+ def _toggle_collection_dynamic(
98
+ enable: bool,
99
+ activities: set[ProfilerActivity],
100
+ ) -> None: ...
101
+ def _disable_profiler() -> _ProfilerResult: ...
102
+ def _profiler_enabled() -> bool: ...
103
+ def _add_metadata_json(key: str, value: str) -> None: ...
104
+ def _kineto_step() -> None: ...
105
+ def _get_current_graph_task_keep_graph() -> bool: ...
106
+ def _get_sequence_nr() -> int: ...
107
+ def kineto_available() -> bool: ...
108
+ def _record_function_with_args_enter(name: str, *args) -> torch.Tensor: ...
109
+ def _record_function_with_args_exit(handle: torch.Tensor) -> None: ...
110
+ def _supported_activities() -> set[ProfilerActivity]: ...
111
+ def _enable_record_function(enable: bool) -> None: ...
112
+ def _set_empty_test_observer(is_global: bool, sampling_prob: float) -> None: ...
113
+ def _push_saved_tensors_default_hooks(
114
+ pack_hook: Callable[[torch.Tensor], Any],
115
+ unpack_hook: Callable[[Any], torch.Tensor],
116
+ ) -> None: ...
117
+ def _pop_saved_tensors_default_hooks() -> None: ...
118
+ def _unsafe_set_version_counter(t: torch.Tensor, prev_version: int) -> None: ...
119
+ def _enable_profiler_legacy(config: ProfilerConfig) -> None: ...
120
+ def _disable_profiler_legacy() -> list[list[ProfilerEvent]]: ...
121
+ def _profiler_type() -> ActiveProfilerType: ...
122
+ def _saved_tensors_hooks_enable() -> None: ...
123
+ def _saved_tensors_hooks_disable(message: str) -> None: ...
124
+ def _saved_tensors_hooks_get_disabled_error_message() -> str | None: ...
125
+ def _saved_tensors_hooks_set_tracing(is_tracing: bool) -> bool: ...
126
+
127
+ class CreationMeta(Enum):
128
+ DEFAULT = ...
129
+ IN_CUSTOM_FUNCTION = ...
130
+ MULTI_OUTPUT_NODE = ...
131
+ NO_GRAD_MODE = ...
132
+ INFERENCE_MODE = ...
133
+
134
+ def _set_creation_meta(t: torch.Tensor, creation_meta: CreationMeta) -> None: ...
135
+ def _get_creation_meta(t: torch.Tensor) -> CreationMeta: ...
lib/python3.12/site-packages/torch/_C/_cpu.pyi ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from torch.types import _bool, _int
2
+
3
+ # Defined in torch/csrc/cpu/Module.cpp
4
+
5
+ def _is_avx2_supported() -> _bool: ...
6
+ def _is_avx512_supported() -> _bool: ...
7
+ def _is_avx512_vnni_supported() -> _bool: ...
8
+ def _is_avx512_bf16_supported() -> _bool: ...
9
+ def _is_amx_tile_supported() -> _bool: ...
10
+ def _is_amx_fp16_supported() -> _bool: ...
11
+ def _init_amx() -> _bool: ...
12
+ def _is_arm_sve_supported() -> _bool: ...
13
+ def _L1d_cache_size() -> _int: ...
14
+ def _L2_cache_size() -> _int: ...
lib/python3.12/site-packages/torch/_C/_cudnn.pyi ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from enum import Enum
2
+
3
+ from torch.types import _bool, Tuple
4
+
5
+ # Defined in torch/csrc/cuda/shared/cudnn.cpp
6
+ is_cuda: _bool
7
+
8
+ def getRuntimeVersion() -> Tuple[int, int, int]: ...
9
+ def getCompileVersion() -> Tuple[int, int, int]: ...
10
+ def getVersionInt() -> int: ...
11
+
12
+ class RNNMode(int, Enum):
13
+ value: int
14
+ rnn_relu = ...
15
+ rnn_tanh = ...
16
+ lstm = ...
17
+ gru = ...
lib/python3.12/site-packages/torch/_C/_cusparselt.pyi ADDED
@@ -0,0 +1 @@
 
 
1
+ def getVersionInt() -> int: ...
lib/python3.12/site-packages/torch/_C/_distributed_autograd.pyi ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # mypy: allow-untyped-defs
2
+ from typing import Any
3
+
4
+ import torch
5
+
6
+ # This module is defined in torch/csrc/distributed/autograd/init.cpp
7
+
8
+ class DistAutogradContext:
9
+ def _context_id(self) -> int: ...
10
+ def _recv_functions(self) -> dict[int, Any]: ...
11
+ def _send_functions(self) -> dict[int, Any]: ...
12
+ def _known_worker_ids(self) -> set[int]: ...
13
+
14
+ def _new_context() -> DistAutogradContext: ...
15
+ def _release_context(context_id: int) -> None: ...
16
+ def _get_max_id() -> int: ...
17
+ def _is_valid_context(worker_id: int) -> bool: ...
18
+ def _retrieve_context(context_id: int) -> DistAutogradContext: ...
19
+ def _current_context() -> DistAutogradContext: ...
20
+ def _init(worker_id: int) -> None: ...
21
+ def _get_debug_info() -> dict[str, str]: ...
22
+ def backward(
23
+ context_id: int,
24
+ roots: list[torch.Tensor],
25
+ retain_graph=False,
26
+ ) -> None: ...
27
+ def get_gradients(context_id: int) -> dict[torch.Tensor, torch.Tensor]: ...
lib/python3.12/site-packages/torch/_C/_distributed_c10d.pyi ADDED
@@ -0,0 +1,695 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # mypy: allow-untyped-defs
2
+ # mypy: disable-error-code="type-arg"
3
+ from datetime import timedelta
4
+ from enum import Enum
5
+ from typing import Any, overload
6
+
7
+ import torch
8
+ from torch import Tensor
9
+ from torch._C import ScriptObject
10
+ from torch.futures import Future
11
+
12
+ # This module is defined in torch/csrc/distributed/c10d/init.cpp
13
+
14
+ _DEFAULT_FIRST_BUCKET_BYTES: int
15
+ _DEFAULT_NO_TIMEOUT: timedelta
16
+ _DEFAULT_PG_TIMEOUT: timedelta
17
+ _DEFAULT_PG_NCCL_TIMEOUT: timedelta
18
+
19
+ class BuiltinCommHookType(Enum):
20
+ ALLREDUCE = ...
21
+ FP16_COMPRESS = ...
22
+
23
+ def _register_comm_hook(reducer: Reducer, state: Any, comm_hook: Any): ...
24
+ def _register_builtin_comm_hook(
25
+ reducer: Reducer,
26
+ comm_hook_type: BuiltinCommHookType,
27
+ ): ...
28
+ def _set_global_rank(rank: int) -> None: ...
29
+ def _hash_tensors(tensors: list[Tensor]) -> int: ...
30
+
31
+ class GradBucket:
32
+ def index(self) -> int: ...
33
+ def buffer(self) -> Tensor: ...
34
+ def gradients(self) -> list[Tensor]: ...
35
+ def is_last(self) -> bool: ...
36
+ def set_buffer(self, tensor: Tensor) -> None: ...
37
+ def parameters(self) -> list[Tensor]: ...
38
+
39
+ class Reducer:
40
+ def __init__(
41
+ self,
42
+ params: list[Tensor],
43
+ bucket_indices: list[list[int]],
44
+ per_bucket_size_limits: list[int],
45
+ process_group: ProcessGroup,
46
+ expect_sparse_gradients: list[bool] = ...,
47
+ bucket_bytes_cap: int = ..., # kDefaultBucketBytesCap in reducer.hpp
48
+ find_unused_parameters: bool = ...,
49
+ gradient_as_bucket_view: bool = ...,
50
+ param_to_name_mapping: dict[int, str] = ...,
51
+ first_bucket_types_cap: int = ..., # kDefaultFirstBucketBytes in reducer.hpp
52
+ ) -> None: ...
53
+ def prepare_for_forward(self) -> None: ...
54
+ def prepare_for_backward(self, output: list[Tensor]) -> None: ...
55
+ def get_backward_stats(self) -> list[int]: ...
56
+ def _install_post_backward_futures(self, futures: list[Future]) -> None: ...
57
+ def _rebuild_buckets(self) -> bool: ...
58
+ def _get_zeros_like_grad_buckets(self) -> list[GradBucket]: ...
59
+ def _push_all_rebuilt_params(self) -> None: ...
60
+ def _set_forward_pass_work_handle(
61
+ self,
62
+ work: Work,
63
+ use_static_world_size: bool,
64
+ ): ...
65
+ def _get_local_used_map(self) -> Tensor: ...
66
+ def _set_ddp_runtime_logging_sample_rate(self, sample_rate: int) -> None: ...
67
+ def _set_static_graph(self) -> None: ...
68
+ def _run_comm_hook(self, bucket: GradBucket) -> Future: ...
69
+ def set_logger(self, logger: Logger) -> None: ...
70
+ def _remove_autograd_hooks(self) -> None: ...
71
+ def _check_reducer_finalized(self) -> None: ...
72
+ def _set_sparse_metadata(self, global_unique_ids: dict[str, Tensor]) -> None: ...
73
+ def _reset_state(self) -> None: ...
74
+ def _update_process_group(self, new_process_group: ProcessGroup) -> None: ...
75
+
76
+ class DDPLoggingData:
77
+ strs_map: dict[str, str]
78
+ ints_map: dict[str, int]
79
+
80
+ class Logger:
81
+ def __init__(self, reducer: Reducer) -> None: ...
82
+ def set_construction_data_and_log(
83
+ self,
84
+ module_name: str,
85
+ device_ids: list[int],
86
+ output_device: int,
87
+ broadcast_buffers: bool,
88
+ has_sync_bn: bool,
89
+ static_graph: bool,
90
+ ): ...
91
+ def set_runtime_stats_and_log(self) -> None: ...
92
+ def set_error_and_log(self, error: str) -> None: ...
93
+ def _get_ddp_logging_data(self) -> DDPLoggingData: ...
94
+ def _set_comm_hook_name(self, comm_hook: str) -> None: ...
95
+ def _set_uneven_input_join(self) -> None: ...
96
+ def _set_static_graph(self) -> None: ...
97
+
98
+ class _WorkerServer:
99
+ def __init__(self, socket_path: str) -> None: ...
100
+ def shutdown(self) -> None: ...
101
+
102
+ def get_debug_level(): ...
103
+ def set_debug_level(): ...
104
+ def set_debug_level_from_env(): ...
105
+
106
+ class DebugLevel(Enum):
107
+ OFF = ...
108
+ INFO = ...
109
+ DETAIL = ...
110
+
111
+ class ReduceOp:
112
+ def __init__(self, op: RedOpType) -> None: ...
113
+
114
+ SUM: RedOpType = ...
115
+ AVG: RedOpType = ...
116
+ PRODUCT: RedOpType = ...
117
+ MIN: RedOpType = ...
118
+ MAX: RedOpType = ...
119
+ BAND: RedOpType = ...
120
+ BOR: RedOpType = ...
121
+ BXOR: RedOpType = ...
122
+ PREMUL_SUM: RedOpType = ...
123
+ UNUSED: RedOpType = ...
124
+
125
+ class RedOpType(Enum): ...
126
+
127
+ class BroadcastOptions:
128
+ rootRank: int
129
+ rootTensor: int
130
+ timeout: timedelta
131
+ asyncOp: bool
132
+
133
+ class AllreduceOptions:
134
+ reduceOp: ReduceOp
135
+ timeout: timedelta
136
+
137
+ class AllreduceCoalescedOptions(AllreduceOptions): ...
138
+
139
+ class ReduceOptions:
140
+ reduceOp: ReduceOp
141
+ rootRank: int
142
+ rootTensor: int
143
+ timeout: timedelta
144
+
145
+ class AllgatherOptions:
146
+ timeout: timedelta
147
+ asyncOp: bool
148
+
149
+ class GatherOptions:
150
+ rootRank: int
151
+ timeout: timedelta
152
+
153
+ class ScatterOptions:
154
+ rootRank: int
155
+ timeout: timedelta
156
+ asyncOp: bool
157
+
158
+ class ReduceScatterOptions:
159
+ reduceOp: ReduceOp
160
+ timeout: timedelta
161
+ asyncOp: bool
162
+
163
+ class BarrierOptions:
164
+ device_ids: list[int]
165
+ device: torch.device
166
+ timeout: timedelta
167
+
168
+ class AllToAllOptions:
169
+ timeout: timedelta
170
+
171
+ class Store:
172
+ def set(self, key: str, value: str): ...
173
+ def get(self, key: str) -> bytes: ...
174
+ def add(self, key: str, value: int) -> int: ...
175
+ def compare_set(
176
+ self,
177
+ key: str,
178
+ expected_value: str,
179
+ desired_value: str,
180
+ ) -> bytes: ...
181
+ def delete_key(self, key: str) -> bool: ...
182
+ def num_keys(self) -> int: ...
183
+ def set_timeout(self, timeout: timedelta): ...
184
+ @overload
185
+ def wait(self, keys: list[str]): ...
186
+ @overload
187
+ def wait(self, keys: list[str], timeout: timedelta): ...
188
+
189
+ class FileStore(Store):
190
+ def __init__(self, path: str, numWorkers: int = ...) -> None: ...
191
+
192
+ class HashStore(Store):
193
+ def __init__(self) -> None: ...
194
+
195
+ class TCPStore(Store):
196
+ def __init__(
197
+ self,
198
+ host_name: str,
199
+ port: int,
200
+ world_size: int | None = ...,
201
+ is_master: bool = ...,
202
+ timeout: timedelta = ...,
203
+ wait_for_workers: bool = ...,
204
+ multi_tenant: bool = ...,
205
+ master_listen_fd: int | None = ...,
206
+ use_libuv: bool | None = ...,
207
+ ) -> None: ...
208
+ @property
209
+ def host(self) -> str: ...
210
+ @property
211
+ def port(self) -> int: ...
212
+
213
+ class PrefixStore(Store):
214
+ def __init__(self, prefix: str, store: Store) -> None: ...
215
+ @property
216
+ def underlying_store(self) -> Store: ...
217
+
218
+ class _ControlCollectives:
219
+ def barrier(self, key: str, timeout: timedelta, blocking: bool) -> None: ...
220
+ def broadcast_send(self, key: str, data: str, timeout: timedelta) -> None: ...
221
+ def broadcast_recv(self, key: str, timeout: timedelta) -> str: ...
222
+ def gather_send(self, key: str, data: str, timeout: timedelta) -> None: ...
223
+ def gather_recv(self, key: str, timeout: timedelta) -> str: ...
224
+ def scatter_send(self, key: str, data: str, timeout: timedelta) -> None: ...
225
+ def scatter_recv(self, key: str, timeout: timedelta) -> str: ...
226
+ def all_gather(self, key: str, data: str, timeout: timedelta) -> str: ...
227
+ def all_sum(self, key: str, data: int, timeout: timedelta) -> int: ...
228
+
229
+ class _StoreCollectives(_ControlCollectives):
230
+ def __init__(self, store: Store, rank: int, world_size: int) -> None: ...
231
+
232
+ class _DistributedBackendOptions:
233
+ def __init__(self) -> None: ...
234
+ @property
235
+ def store(self) -> Store: ...
236
+ @store.setter
237
+ def store(self, store: Store) -> None: ...
238
+ @property
239
+ def group_rank(self) -> int: ...
240
+ @group_rank.setter
241
+ def group_rank(self, rank: int) -> None: ...
242
+ @property
243
+ def group_size(self) -> int: ...
244
+ @group_size.setter
245
+ def group_size(self, size: int) -> None: ...
246
+ @property
247
+ def timeout(self) -> timedelta: ...
248
+ @timeout.setter
249
+ def timeout(self, timeout: timedelta) -> None: ...
250
+ @property
251
+ def group_id(self) -> str: ...
252
+ @group_id.setter
253
+ def group_id(self, group_id: str) -> None: ...
254
+ @property
255
+ def global_ranks_in_group(self) -> list[int]: ...
256
+ @global_ranks_in_group.setter
257
+ def global_ranks_in_group(self, ranks: list[int]) -> None: ...
258
+
259
+ class Work:
260
+ def is_completed(self) -> bool: ...
261
+ def is_success(self) -> bool: ...
262
+ def exception(self) -> Any: ...
263
+ def wait(self, timeout: timedelta = ...) -> bool: ...
264
+ def get_future(self) -> Future: ...
265
+ def source_rank(self) -> int: ...
266
+ def _source_rank(self) -> int: ...
267
+ def result(self) -> list[Tensor]: ...
268
+ def synchronize(self): ...
269
+ def boxed(self) -> ScriptObject: ...
270
+ @staticmethod
271
+ def unbox(obj: ScriptObject) -> Work: ...
272
+
273
+ class Backend:
274
+ class Options:
275
+ def __init__(self, backend: str, timeout: timedelta = ...) -> None: ...
276
+ @property
277
+ def backend(self) -> str: ...
278
+ @property
279
+ def _timeout(self) -> timedelta: ...
280
+ @_timeout.setter
281
+ def _timeout(self, val: timedelta) -> None: ...
282
+
283
+ def __init__(
284
+ self,
285
+ rank: int,
286
+ size: int,
287
+ ) -> None: ...
288
+ @property
289
+ def supports_splitting(self) -> bool: ...
290
+ @property
291
+ def options(self) -> Options: ...
292
+ def rank(self) -> int: ...
293
+ def size(self) -> int: ...
294
+ def eager_connect_single_device(self, device: torch.device | None) -> None: ...
295
+ def _set_sequence_number_for_group(self) -> None: ...
296
+ def _set_default_timeout(self, timeout: timedelta) -> None: ...
297
+
298
+ class ProcessGroup:
299
+ class BackendType(Enum):
300
+ UNDEFINED = ...
301
+ GLOO = ...
302
+ NCCL = ...
303
+ UCC = ...
304
+ MPI = ...
305
+ XCCL = ...
306
+ CUSTOM = ...
307
+
308
+ def __init__(
309
+ self,
310
+ store: Store,
311
+ rank: int,
312
+ size: int,
313
+ ) -> None: ...
314
+ def rank(self) -> int: ...
315
+ def size(self) -> int: ...
316
+ @overload
317
+ def broadcast(
318
+ self,
319
+ tensors: list[Tensor],
320
+ opts=...,
321
+ ) -> Work: ...
322
+ @overload
323
+ def broadcast(
324
+ self,
325
+ tensor: Tensor,
326
+ root: int,
327
+ ) -> Work: ...
328
+ @overload
329
+ def allreduce(
330
+ self,
331
+ tensors: list[Tensor],
332
+ opts: AllreduceOptions = ...,
333
+ ) -> Work: ...
334
+ @overload
335
+ def allreduce(
336
+ self,
337
+ tensors: list[Tensor],
338
+ op=...,
339
+ ) -> Work: ...
340
+ @overload
341
+ def allreduce(
342
+ self,
343
+ tensor: Tensor,
344
+ op=...,
345
+ ) -> Work: ...
346
+ def allreduce_coalesced(
347
+ self,
348
+ tensors: list[Tensor],
349
+ opts=...,
350
+ ) -> Work: ...
351
+ def reduce_scatter_tensor_coalesced(
352
+ self,
353
+ outputTensors: list[Tensor],
354
+ inputTensors: list[Tensor],
355
+ opts: ReduceScatterOptions | None = None,
356
+ ) -> Work: ...
357
+ @overload
358
+ def reduce(
359
+ self,
360
+ tensors: list[Tensor],
361
+ opts=...,
362
+ ) -> Work: ...
363
+ @overload
364
+ def reduce(
365
+ self,
366
+ tensor: Tensor,
367
+ root: int,
368
+ op=...,
369
+ ) -> Work: ...
370
+ @overload
371
+ def allgather(
372
+ self,
373
+ output_tensors: list[list[Tensor]],
374
+ input_tensors: list[Tensor],
375
+ opts=...,
376
+ ) -> Work: ...
377
+ @overload
378
+ def allgather(
379
+ self,
380
+ output_tensors: list[Tensor],
381
+ input_tensor: Tensor,
382
+ ) -> Work: ...
383
+ def _allgather_base(
384
+ self,
385
+ output: Tensor,
386
+ input: Tensor,
387
+ opts=...,
388
+ ) -> Work: ...
389
+ def allgather_coalesced(
390
+ self,
391
+ output_lists: list[list[Tensor]],
392
+ input_list: list[Tensor],
393
+ opts=...,
394
+ ) -> Work: ...
395
+ def allgather_into_tensor_coalesced(
396
+ self,
397
+ output_lists: list[Tensor],
398
+ input_list: list[Tensor],
399
+ opts=...,
400
+ ) -> Work: ...
401
+ @overload
402
+ def gather(
403
+ self,
404
+ output_tensors: list[list[Tensor]],
405
+ input_tensors: list[Tensor],
406
+ opts=...,
407
+ ) -> Work: ...
408
+ @overload
409
+ def gather(
410
+ self,
411
+ output_tensors: list[Tensor],
412
+ input_tensor: Tensor,
413
+ root: int,
414
+ ) -> Work: ...
415
+ @overload
416
+ def scatter(
417
+ self,
418
+ output_tensors: list[Tensor],
419
+ input_tensors: list[list[Tensor]],
420
+ opts=...,
421
+ ) -> Work: ...
422
+ @overload
423
+ def scatter(
424
+ self,
425
+ output_tensor: Tensor,
426
+ input_tensors: list[Tensor],
427
+ root: int,
428
+ ) -> Work: ...
429
+ @overload
430
+ def reduce_scatter(
431
+ self,
432
+ output_tensors: list[Tensor],
433
+ input_tensors: list[list[Tensor]],
434
+ opts=...,
435
+ ) -> Work: ...
436
+ @overload
437
+ def reduce_scatter(
438
+ self,
439
+ output_tensors: Tensor,
440
+ input_tensor: list[Tensor],
441
+ ) -> Work: ...
442
+ def _reduce_scatter_base(
443
+ self,
444
+ outputTensor: Tensor,
445
+ inputTensor: Tensor,
446
+ opts: ReduceScatterOptions | None,
447
+ ) -> Work: ...
448
+ @overload
449
+ def alltoall_base(
450
+ self,
451
+ output_tensor: Tensor,
452
+ input_tensor: Tensor,
453
+ output_split_sizes: list[int],
454
+ input_split_sizes: list[int],
455
+ opts=...,
456
+ ) -> Work: ...
457
+ @overload
458
+ def alltoall_base(
459
+ self,
460
+ output: Tensor,
461
+ input: Tensor,
462
+ output_split_sizes: list[int],
463
+ input_split_sizes: list[int],
464
+ ) -> Work: ...
465
+ @overload
466
+ def alltoall(
467
+ self,
468
+ output_tensor: list[Tensor],
469
+ input_tensor: list[Tensor],
470
+ opts=...,
471
+ ) -> Work: ...
472
+ @overload
473
+ def alltoall(
474
+ self,
475
+ output: list[Tensor],
476
+ input: list[Tensor],
477
+ ) -> Work: ...
478
+ def send(
479
+ self,
480
+ tensors: list[Tensor],
481
+ dstRank: int,
482
+ tag: int,
483
+ ) -> Work: ...
484
+ def recv(
485
+ self,
486
+ tensors: list[Tensor],
487
+ srcRank: int,
488
+ tag: int,
489
+ ) -> Work: ...
490
+ def recv_anysource(self, tensors: list[Tensor], tag: int) -> Work: ...
491
+ def barrier(self, opts=...) -> Work: ...
492
+ def boxed(self) -> ScriptObject: ...
493
+ @staticmethod
494
+ def unbox(obj: ScriptObject) -> ProcessGroup: ...
495
+ def _start_coalescing(self, device: torch.device) -> None: ...
496
+ def _end_coalescing(self, device: torch.device) -> Work: ...
497
+ def _get_backend_name(self) -> str: ...
498
+ def _backend_id(self, backend_type: BackendType) -> int: ...
499
+ @property
500
+ def _device_types(self) -> list[torch.device]: ...
501
+ def _get_backend(self, device: torch.device) -> Backend: ...
502
+ def _set_default_backend(self, backend_type: BackendType) -> None: ...
503
+ def _register_backend(
504
+ self,
505
+ device: torch.device,
506
+ backend_type: BackendType,
507
+ backend: Backend | None,
508
+ ) -> None: ...
509
+ def _set_group_name(self, name: str) -> None: ...
510
+ def _set_group_desc(self, desc: str) -> None: ...
511
+ def name(self) -> str: ...
512
+ def _has_hooks(self) -> bool: ...
513
+ def _wait_for_pending_works(self) -> None: ...
514
+ def _set_sequence_number_for_group(self) -> None: ...
515
+ @property
516
+ def bound_device_id(self) -> torch.device | None: ...
517
+ @bound_device_id.setter
518
+ def bound_device_id(self, device: torch.device | None) -> None: ...
519
+ @property
520
+ def group_name(self) -> str: ...
521
+ @property
522
+ def group_desc(self) -> str: ...
523
+
524
+ class FakeProcessGroup(Backend):
525
+ def __init__(self, rank: int, world_size: int) -> None: ...
526
+
527
+ class ProcessGroupGloo(Backend):
528
+ class Device: ...
529
+
530
+ class Options(Backend.Options):
531
+ devices: list[ProcessGroupGloo.Device]
532
+ threads: int
533
+
534
+ def __init__(self): ...
535
+
536
+ def __init__(
537
+ self,
538
+ store: Store,
539
+ rank: int,
540
+ size: int,
541
+ timeout: timedelta,
542
+ ) -> None: ...
543
+ @staticmethod
544
+ def create_device(hostname="", interface="") -> Device: ...
545
+ @staticmethod
546
+ def create_default_device() -> Device: ...
547
+ def _set_default_timeout(self, timeout) -> None: ...
548
+
549
+ class _ProcessGroupWrapper(Backend):
550
+ def __init__(self, pg: Backend, gloo_pg: ProcessGroupGloo) -> None: ...
551
+ wrapped_pg: Backend
552
+
553
+ class ProcessGroupNCCL(Backend):
554
+ class NCCLConfig:
555
+ blocking: int
556
+ cga_cluster_size: int
557
+ min_ctas: int
558
+ max_ctas: int
559
+
560
+ class Options(Backend.Options):
561
+ config: ProcessGroupNCCL.NCCLConfig
562
+ is_high_priority_stream: bool
563
+ split_from: ProcessGroupNCCL
564
+ split_color: int
565
+ global_ranks_in_group: list[int]
566
+ group_name: str
567
+
568
+ def __init__(self, is_high_priority_stream: bool = False): ...
569
+
570
+ def __init__(
571
+ self,
572
+ store: Store,
573
+ rank: int,
574
+ size: int,
575
+ options: Options,
576
+ ) -> None: ...
577
+ def _group_start(self) -> None: ...
578
+ def _group_end(self) -> None: ...
579
+ def _set_default_timeout(self, timeout) -> None: ...
580
+ def _shutdown(self) -> None: ...
581
+ def perform_nocolor_split(self, device: torch.device) -> None: ...
582
+ def register_mem_pool(self, pool: torch.cuda.MemPool) -> None: ...
583
+ def deregister_mem_pool(self, pool: torch.cuda.MemPool) -> None: ...
584
+ def comm_split_count(self) -> int: ...
585
+ def _add_ephemeral_timeout(self, timeout: timedelta) -> None: ...
586
+ def abort(self) -> None: ...
587
+ def _is_initialized(self) -> bool: ...
588
+ @property
589
+ def uid(self) -> int: ...
590
+ @property
591
+ def options(self) -> Options: ... # type: ignore[override]
592
+
593
+ class ProcessGroupUCC(Backend):
594
+ def __init__(
595
+ self,
596
+ store: Store,
597
+ rank: int,
598
+ size: int,
599
+ timeout: timedelta,
600
+ ) -> None: ...
601
+
602
+ class ProcessGroupMPI(Backend):
603
+ def __init__(
604
+ self,
605
+ rank: int,
606
+ size: int,
607
+ pgComm: int,
608
+ ) -> None: ...
609
+ @staticmethod
610
+ def create(ranks: list[int]) -> ProcessGroupMPI: ...
611
+
612
+ def _compute_bucket_assignment_by_size(
613
+ tensors: list[Tensor],
614
+ bucket_size_limits: list[int],
615
+ expect_sparse_gradient: list[bool] = ...,
616
+ tensor_indices: list[int] = ...,
617
+ ) -> tuple[list[list[int]], list[int]]: ...
618
+ def _broadcast_coalesced(
619
+ process_group: ProcessGroup,
620
+ tensors: list[Tensor],
621
+ buffer_size: int,
622
+ src: int,
623
+ ): ...
624
+ def _test_python_store(store: Store): ...
625
+ def _verify_params_across_processes(
626
+ process_group: ProcessGroup,
627
+ params: list[Tensor],
628
+ logger: Logger | None,
629
+ ): ...
630
+ def _make_nccl_premul_sum(factor: float | list[Tensor]) -> ReduceOp: ...
631
+ def _register_process_group(
632
+ group_name: str,
633
+ process_group: ProcessGroup,
634
+ ) -> None: ...
635
+ def _resolve_process_group(group_name: str) -> ProcessGroup: ...
636
+ def _register_work(tensor: torch.Tensor, work: Work) -> ProcessGroup: ...
637
+ def _get_work_registry_size() -> int: ...
638
+ def _set_allow_inflight_collective_as_graph_input(
639
+ value: bool,
640
+ ) -> None: ...
641
+ def _allow_inflight_collective_as_graph_input() -> bool: ...
642
+ def _unregister_all_process_groups() -> None: ...
643
+ def _unregister_process_group(group_name: str) -> None: ...
644
+
645
+ class _SymmetricMemory:
646
+ @staticmethod
647
+ def set_group_info(
648
+ group_name: str,
649
+ rank: int,
650
+ world_size: int,
651
+ store: Store,
652
+ ) -> None: ...
653
+ @staticmethod
654
+ def empty_strided_p2p(
655
+ size: torch.types._size,
656
+ stride: torch.types._size,
657
+ dtype: torch.dtype,
658
+ device: torch.device,
659
+ group_name: str | None = None,
660
+ alloc_id: int | None = None,
661
+ ) -> torch.Tensor: ...
662
+ @property
663
+ def rank(self) -> int: ...
664
+ @property
665
+ def world_size(self) -> int: ...
666
+ @staticmethod
667
+ def rendezvous(
668
+ tensor: torch.Tensor, group_name: str | None = None
669
+ ) -> _SymmetricMemory: ...
670
+ def get_buffer(
671
+ self,
672
+ rank: int,
673
+ sizes: torch.types._size,
674
+ dtype: torch.dtype,
675
+ storage_offset: int | None = 0,
676
+ ) -> torch.Tensor: ...
677
+ def barrier(self, channel: int = 0) -> None: ...
678
+ def put_signal(self, dst_rank: int, channel: int = 0) -> None: ...
679
+ def wait_signal(self, src_rank: int, channel: int = 0) -> None: ...
680
+ @staticmethod
681
+ def memset32(
682
+ tensor: torch.Tensor, offset: int, val: int, count: int
683
+ ) -> torch.Tensor: ...
684
+ @staticmethod
685
+ def stream_write_value32(
686
+ tensor: torch.Tensor, offset: int, val: int
687
+ ) -> torch.Tensor: ...
688
+
689
+ class ProcessGroupXCCL(Backend):
690
+ def __init__(
691
+ self,
692
+ store: Store,
693
+ rank: int,
694
+ size: int,
695
+ ): ...
lib/python3.12/site-packages/torch/_C/_distributed_rpc.pyi ADDED
@@ -0,0 +1,188 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # mypy: allow-untyped-defs
2
+ # mypy: disable-error-code="type-arg"
3
+ from datetime import timedelta
4
+ from typing import Any, Generic, overload, TypeVar
5
+
6
+ import torch
7
+ from torch._C import Future
8
+ from torch._C._autograd import ProfilerEvent
9
+ from torch._C._distributed_c10d import Store
10
+ from torch._C._profiler import ProfilerConfig
11
+
12
+ # This module is defined in torch/csrc/distributed/rpc/init.cpp
13
+
14
+ _DEFAULT_INIT_METHOD: str
15
+ _DEFAULT_NUM_WORKER_THREADS: int
16
+ _UNSET_RPC_TIMEOUT: float
17
+ _DEFAULT_RPC_TIMEOUT_SEC: float
18
+
19
+ _T = TypeVar("_T")
20
+
21
+ class RpcBackendOptions:
22
+ rpc_timeout: float
23
+ init_method: str
24
+ def __init__(
25
+ self,
26
+ rpc_timeout: float = ...,
27
+ init_method: str = ...,
28
+ ) -> None: ...
29
+
30
+ class WorkerInfo:
31
+ def __init__(self, name: str, worker_id: int) -> None: ...
32
+ @property
33
+ def name(self) -> str: ...
34
+ @property
35
+ def id(self) -> int: ...
36
+ def __eq__(self, other: object) -> bool: ...
37
+
38
+ class RpcAgent:
39
+ def join(self, shutdown: bool = False, timeout: float = 0): ...
40
+ def sync(self): ...
41
+ def shutdown(self): ...
42
+ @overload
43
+ def get_worker_info(self) -> WorkerInfo: ...
44
+ @overload
45
+ def get_worker_info(self, workerName: str) -> WorkerInfo: ...
46
+ def get_worker_infos(self) -> list[WorkerInfo]: ...
47
+ def _get_device_map(self, dst: WorkerInfo) -> dict[torch.device, torch.device]: ...
48
+ def get_debug_info(self) -> dict[str, str]: ...
49
+ def get_metrics(self) -> dict[str, str]: ...
50
+
51
+ class PyRRef(Generic[_T]):
52
+ def __init__(self, value: _T, type_hint: Any = None) -> None: ...
53
+ def is_owner(self) -> bool: ...
54
+ def confirmed_by_owner(self) -> bool: ...
55
+ def owner(self) -> WorkerInfo: ...
56
+ def owner_name(self) -> str: ...
57
+ def to_here(self, timeout: float = ...) -> _T: ...
58
+ def local_value(self) -> Any: ...
59
+ def rpc_sync(self, timeout: float = ...) -> Any: ...
60
+ def rpc_async(self, timeout: float = ...) -> Any: ...
61
+ def remote(self, timeout: float = ...) -> Any: ...
62
+ def _serialize(self) -> tuple: ...
63
+ @staticmethod
64
+ def _deserialize(tp: tuple) -> PyRRef: ...
65
+ def _get_type(self) -> type[_T]: ...
66
+ def _get_future(self) -> Future[_T]: ...
67
+ def _get_profiling_future(self) -> Future[_T]: ...
68
+ def _set_profiling_future(self, profilingFuture: Future[_T]): ...
69
+
70
+ class _TensorPipeRpcBackendOptionsBase(RpcBackendOptions):
71
+ num_worker_threads: int
72
+ device_maps: dict[str, dict[torch.device, torch.device]]
73
+ devices: list[torch.device]
74
+ def __init__(
75
+ self,
76
+ num_worker_threads: int,
77
+ _transports: list | None,
78
+ _channels: list | None,
79
+ rpc_timeout: float = ...,
80
+ init_method: str = ...,
81
+ device_maps: dict[str, dict[torch.device, torch.device]] = {}, # noqa: B006
82
+ devices: list[torch.device] = [], # noqa: B006
83
+ ) -> None: ...
84
+ def _set_device_map(
85
+ self,
86
+ to: str,
87
+ device_map: dict[torch.device, torch.device],
88
+ ): ...
89
+
90
+ class TensorPipeAgent(RpcAgent):
91
+ def __init__(
92
+ self,
93
+ store: Store,
94
+ name: str,
95
+ worker_id: int,
96
+ world_size: int | None,
97
+ opts: _TensorPipeRpcBackendOptionsBase,
98
+ reverse_device_maps: dict[str, dict[torch.device, torch.device]],
99
+ devices: list[torch.device],
100
+ ) -> None: ...
101
+ def join(self, shutdown: bool = False, timeout: float = 0): ...
102
+ def shutdown(self): ...
103
+ @overload
104
+ def get_worker_info(self) -> WorkerInfo: ...
105
+ @overload
106
+ def get_worker_info(self, workerName: str) -> WorkerInfo: ...
107
+ @overload
108
+ def get_worker_info(self, id: int) -> WorkerInfo: ...
109
+ def get_worker_infos(self) -> list[WorkerInfo]: ...
110
+ def _get_device_map(self, dst: WorkerInfo) -> dict[torch.device, torch.device]: ...
111
+ def _update_group_membership(
112
+ self,
113
+ worker_info: WorkerInfo,
114
+ my_devices: list[torch.device],
115
+ reverse_device_map: dict[str, dict[torch.device, torch.device]],
116
+ is_join: bool,
117
+ ): ...
118
+ def _get_backend_options(self) -> _TensorPipeRpcBackendOptionsBase: ...
119
+ @property
120
+ def is_static_group(self) -> bool: ...
121
+ @property
122
+ def store(self) -> Store: ...
123
+
124
+ def _is_current_rpc_agent_set() -> bool: ...
125
+ def _get_current_rpc_agent() -> RpcAgent: ...
126
+ def _set_and_start_rpc_agent(agent: RpcAgent): ...
127
+ def _reset_current_rpc_agent(): ...
128
+ def _delete_all_user_and_unforked_owner_rrefs(timeout: timedelta = ...): ...
129
+ def _destroy_rref_context(ignoreRRefLeak: bool): ...
130
+ def _rref_context_get_debug_info() -> dict[str, str]: ...
131
+ def _cleanup_python_rpc_handler(): ...
132
+ def _invoke_rpc_builtin(
133
+ dst: WorkerInfo,
134
+ opName: str,
135
+ rpcTimeoutSeconds: float,
136
+ *args: Any,
137
+ **kwargs: Any,
138
+ ): ...
139
+ def _invoke_rpc_python_udf(
140
+ dst: WorkerInfo,
141
+ pickledPythonUDF: str,
142
+ tensors: list[torch.Tensor],
143
+ rpcTimeoutSeconds: float,
144
+ isAsyncExecution: bool,
145
+ ): ...
146
+ def _invoke_rpc_torchscript(
147
+ dstWorkerName: str,
148
+ qualifiedNameStr: str,
149
+ argsTuple: tuple,
150
+ kwargsDict: dict,
151
+ rpcTimeoutSeconds: float,
152
+ isAsyncExecution: bool,
153
+ ): ...
154
+ def _invoke_remote_builtin(
155
+ dst: WorkerInfo,
156
+ opName: str,
157
+ rpcTimeoutSeconds: float,
158
+ *args: Any,
159
+ **kwargs: Any,
160
+ ): ...
161
+ def _invoke_remote_python_udf(
162
+ dst: WorkerInfo,
163
+ pickledPythonUDF: str,
164
+ tensors: list[torch.Tensor],
165
+ rpcTimeoutSeconds: float,
166
+ isAsyncExecution: bool,
167
+ ): ...
168
+ def _invoke_remote_torchscript(
169
+ dstWorkerName: WorkerInfo,
170
+ qualifiedNameStr: str,
171
+ rpcTimeoutSeconds: float,
172
+ isAsyncExecution: bool,
173
+ *args: Any,
174
+ **kwargs: Any,
175
+ ): ...
176
+ def get_rpc_timeout() -> float: ...
177
+ def enable_gil_profiling(flag: bool): ...
178
+ def _set_rpc_timeout(rpcTimeoutSeconds: float): ...
179
+
180
+ class RemoteProfilerManager:
181
+ @staticmethod
182
+ def set_current_profiling_key(key: str): ...
183
+
184
+ def _enable_server_process_global_profiler(new_config: ProfilerConfig): ...
185
+ def _disable_server_process_global_profiler() -> list[list[list[ProfilerEvent]]]: ...
186
+ def _set_profiler_node_id(default_node_id: int): ...
187
+ def _enable_jit_rref_pickle(): ...
188
+ def _disable_jit_rref_pickle(): ...
lib/python3.12/site-packages/torch/_C/_distributed_rpc_testing.pyi ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ from torch._C._distributed_c10d import Store
3
+ from torch._C._distributed_rpc import _TensorPipeRpcBackendOptionsBase, TensorPipeAgent
4
+
5
+ # This module is defined in torch/csrc/distributed/rpc/testing/init.cpp
6
+
7
+ class FaultyTensorPipeRpcBackendOptions(_TensorPipeRpcBackendOptionsBase):
8
+ def __init__(
9
+ self,
10
+ num_worker_threads: int,
11
+ rpc_timeout: float,
12
+ init_method: str,
13
+ messages_to_fail: list[str],
14
+ messages_to_delay: dict[str, float],
15
+ num_fail_sends: int,
16
+ ) -> None: ...
17
+ num_send_recv_threads: int
18
+ messages_to_fail: list[str]
19
+ messages_to_delay: dict[str, float]
20
+ num_fail_sends: int
21
+
22
+ class FaultyTensorPipeAgent(TensorPipeAgent):
23
+ def __init__(
24
+ self,
25
+ store: Store,
26
+ name: str,
27
+ rank: int,
28
+ world_size: int,
29
+ options: FaultyTensorPipeRpcBackendOptions,
30
+ reverse_device_maps: dict[str, dict[torch.device, torch.device]],
31
+ devices: list[torch.device],
32
+ ) -> None: ...
lib/python3.12/site-packages/torch/_C/_export.pyi ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ # Defined in torch/csrc/export/pybind.cpp
2
+
3
+ class CppExportedProgram: ...
4
+
5
+ def deserialize_exported_program(
6
+ serialized_program: str,
7
+ ) -> CppExportedProgram: ...
8
+ def serialize_exported_program(
9
+ cpp_exported_program: CppExportedProgram,
10
+ ) -> str: ...
lib/python3.12/site-packages/torch/_C/_functions.pyi ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import AnyStr, overload, Tuple
2
+
3
+ from torch import Tensor
4
+
5
+ class UndefinedGrad:
6
+ def __init__(self) -> None: ...
7
+ def __call__(self, *inputs: Tensor) -> list[Tensor]: ...
8
+
9
+ class DelayedError:
10
+ def __init__(self, msg: AnyStr, num_inputs: int) -> None: ...
11
+
12
+ # __call__ should really be a higher-kinded type:
13
+ # def __call__(self, arg: Tensor) -> Tensor: ...
14
+ # def __call__(self, *args: Tensor * num_inputs) -> Tuple[Tensor * num_inputs]: ...
15
+
16
+ @overload
17
+ def __call__(self, i0: Tensor) -> Tensor: ...
18
+ @overload
19
+ def __call__(self, *args: Tensor) -> Tuple[Tensor, ...]: ...
lib/python3.12/site-packages/torch/_C/_functorch.pyi ADDED
@@ -0,0 +1,83 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # mypy: allow-untyped-defs
2
+ from enum import Enum
3
+
4
+ from torch import Tensor
5
+
6
+ # Defined in torch/csrc/functorch/init.cpp
7
+
8
+ def _set_dynamic_layer_keys_included(included: bool) -> None: ...
9
+ def get_unwrapped(tensor: Tensor) -> Tensor: ...
10
+ def is_batchedtensor(tensor: Tensor) -> bool: ...
11
+ def is_functionaltensor(tensor: Tensor) -> bool: ...
12
+ def is_functorch_wrapped_tensor(tensor: Tensor) -> bool: ...
13
+ def is_gradtrackingtensor(tensor: Tensor) -> bool: ...
14
+ def is_legacy_batchedtensor(tensor: Tensor) -> bool: ...
15
+ def maybe_get_bdim(tensor: Tensor) -> int: ...
16
+ def maybe_get_level(tensor: Tensor) -> int: ...
17
+ def maybe_current_level() -> int | None: ...
18
+ def unwrap_if_dead(tensor: Tensor) -> Tensor: ...
19
+ def _unwrap_for_grad(tensor: Tensor, level: int) -> Tensor: ...
20
+ def _wrap_for_grad(tensor: Tensor, level: int) -> Tensor: ...
21
+ def _unwrap_batched(tensor: Tensor, level: int) -> tuple[Tensor, int | None]: ...
22
+ def current_level() -> int: ...
23
+ def count_jvp_interpreters() -> int: ...
24
+ def _add_batch_dim(tensor: Tensor, bdim: int, level: int) -> Tensor: ...
25
+ def set_single_level_autograd_function_allowed(allowed: bool) -> None: ...
26
+ def get_single_level_autograd_function_allowed() -> bool: ...
27
+ def _unwrap_functional_tensor(tensor: Tensor, reapply_views: bool) -> Tensor: ...
28
+ def _wrap_functional_tensor(tensor: Tensor, level: int) -> Tensor: ...
29
+ def _vmap_increment_nesting(batch_size: int, randomness: str) -> int: ...
30
+ def _vmap_decrement_nesting() -> int: ...
31
+ def _grad_increment_nesting() -> int: ...
32
+ def _grad_decrement_nesting() -> int: ...
33
+ def _jvp_increment_nesting() -> int: ...
34
+ def _jvp_decrement_nesting() -> int: ...
35
+
36
+ # Defined in aten/src/ATen/functorch/Interpreter.h
37
+ class TransformType(Enum):
38
+ Torch: TransformType = ...
39
+ Vmap: TransformType = ...
40
+ Grad: TransformType = ...
41
+ Jvp: TransformType = ...
42
+ Functionalize: TransformType = ...
43
+
44
+ class RandomnessType(Enum):
45
+ Error: TransformType = ...
46
+ Same: TransformType = ...
47
+ Different: TransformType = ...
48
+
49
+ class CInterpreter:
50
+ def key(self) -> TransformType: ...
51
+ def level(self) -> int: ...
52
+
53
+ class CGradInterpreterPtr:
54
+ def __init__(self, interpreter: CInterpreter) -> None: ...
55
+ def lift(self, Tensor) -> Tensor: ...
56
+ def prevGradMode(self) -> bool: ...
57
+
58
+ class CJvpInterpreterPtr:
59
+ def __init__(self, interpreter: CInterpreter) -> None: ...
60
+ def lift(self, Tensor) -> Tensor: ...
61
+ def prevFwdGradMode(self) -> bool: ...
62
+
63
+ class CFunctionalizeInterpreterPtr:
64
+ def __init__(self, interpreter: CInterpreter) -> None: ...
65
+ def key(self) -> TransformType: ...
66
+ def level(self) -> int: ...
67
+ def functionalizeAddBackViews(self) -> bool: ...
68
+
69
+ class CVmapInterpreterPtr:
70
+ def __init__(self, interpreter: CInterpreter) -> None: ...
71
+ def key(self) -> TransformType: ...
72
+ def level(self) -> int: ...
73
+ def batchSize(self) -> int: ...
74
+ def randomness(self) -> RandomnessType: ...
75
+
76
+ class DynamicLayer: ...
77
+
78
+ def get_dynamic_layer_stack_depth() -> int: ...
79
+ def get_interpreter_stack() -> list[CInterpreter]: ...
80
+ def peek_interpreter_stack() -> CInterpreter: ...
81
+ def pop_dynamic_layer_stack() -> DynamicLayer: ...
82
+ def pop_dynamic_layer_stack_and_undo_to_depth(int) -> None: ...
83
+ def push_dynamic_layer_stack(dl: DynamicLayer) -> int: ...
lib/python3.12/site-packages/torch/_C/_instruction_counter.pyi ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ # Defined in torch/csrc/instruction_counter/Module.cpp
2
+
3
+ def start() -> int: ...
4
+ def end(id: int) -> int: ...
lib/python3.12/site-packages/torch/_C/_itt.pyi ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ # Defined in torch/csrc/itt.cpp
2
+ def is_available() -> None: ...
3
+ def rangePush(message: str) -> None: ...
4
+ def rangePop() -> None: ...
5
+ def mark(message: str) -> None: ...
lib/python3.12/site-packages/torch/_C/_lazy.pyi ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # mypy: allow-untyped-defs
2
+ from torch import Tensor
3
+
4
+ # defined in torch/csrc/lazy/python/init.cpp
5
+ def _mark_step(device: str, devices: list[str], wait: bool): ...
6
+ def _wait_device_ops(devices: list[str]): ...
7
+ def _reset_metrics(): ...
8
+ def _counter_names() -> list[str]: ...
9
+ def _counter_value(name: str) -> int: ...
10
+ def _metrics_report() -> str: ...
11
+ def _get_graph_hash(tensors: list[Tensor]) -> str: ...
12
+ def _sync_multi(
13
+ tensors: list[Tensor],
14
+ devices: list[str],
15
+ wait: bool = True,
16
+ sync_ltc_data: bool = True,
17
+ ): ...
18
+ def _get_tensor_id(tensor: Tensor) -> int: ...
19
+ def _get_tensors_text(tensors: list[Tensor]) -> str: ...
20
+ def _get_tensors_dot(tensors: list[Tensor]) -> str: ...
21
+ def _get_tensors_backend(tensors: list[Tensor]) -> str: ...
22
+ def _get_force_fallback() -> str: ...
23
+ def _set_force_fallback(newval: str): ...
24
+ def _clear_ir_cache(): ...
25
+ def _dump_ir_cache(filename: str): ...
26
+ def _set_reuse_ir(val: bool): ...
27
+ def _get_default_device_type(): ...
lib/python3.12/site-packages/torch/_C/_lazy_ts_backend.pyi ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # mypy: allow-untyped-defs
2
+ # defined in torch/csrc/lazy/python/init.cpp
3
+
4
+ from typing import Any
5
+
6
+ from torch import Tensor
7
+
8
+ def _init(): ...
9
+ def _get_tensors_ts_device_data_node(
10
+ tensors: list[Tensor],
11
+ ) -> tuple[list[int], list[Any]]: ...
12
+ def _run_cached_graph(hash_str: str, graph_inputs: list[Any]) -> list[Tensor]: ...
lib/python3.12/site-packages/torch/_C/_monitor.pyi ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Defined in torch/csrc/monitor/python_init.cpp
2
+
3
+ import datetime
4
+ from enum import Enum
5
+ from typing import Callable
6
+
7
+ class Aggregation(Enum):
8
+ VALUE = ...
9
+ MEAN = ...
10
+ COUNT = ...
11
+ SUM = ...
12
+ MAX = ...
13
+ MIN = ...
14
+
15
+ class Stat:
16
+ name: str
17
+ count: int
18
+ def __init__(
19
+ self,
20
+ name: str,
21
+ aggregations: list[Aggregation],
22
+ window_size: int,
23
+ max_samples: int = -1,
24
+ ) -> None: ...
25
+ def add(self, v: float) -> None: ...
26
+ def get(self) -> dict[Aggregation, float]: ...
27
+
28
+ class Event:
29
+ name: str
30
+ timestamp: datetime.datetime
31
+ data: dict[str, int | float | bool | str]
32
+ def __init__(
33
+ self,
34
+ name: str,
35
+ timestamp: datetime.datetime,
36
+ data: dict[str, int | float | bool | str],
37
+ ) -> None: ...
38
+
39
+ def log_event(e: Event) -> None: ...
40
+
41
+ class EventHandlerHandle: ...
42
+
43
+ def register_event_handler(handler: Callable[[Event], None]) -> EventHandlerHandle: ...
44
+ def unregister_event_handler(handle: EventHandlerHandle) -> None: ...
lib/python3.12/site-packages/torch/_C/_nn.pyi ADDED
@@ -0,0 +1,89 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # @generated by tools/pyi/gen_pyi.py from torch/_C/_nn.pyi.in
2
+ # mypy: disable-error-code="type-arg"
3
+
4
+ from typing import List, Literal, Optional, overload, Sequence, Tuple, Union
5
+
6
+ from torch import memory_format, Tensor
7
+ from torch.types import _bool, _device, _dtype, _int, _size
8
+
9
+ # Defined in tools/autograd/templates/python_nn_functions.cpp
10
+
11
+ def adaptive_max_pool2d(input: Tensor, output_size: Union[_int, _size]) -> Tuple[Tensor, Tensor]: ...
12
+ def adaptive_max_pool3d(input: Tensor, output_size: Union[_int, _size]) -> Tuple[Tensor, Tensor]: ...
13
+ def avg_pool2d(input: Tensor, kernel_size: Union[_int, _size], stride: Optional[Union[_int, _size]] = None, padding: Union[_int, _size] = 0, ceil_mode: bool = False, count_include_pad: bool = True, divisor_override: Optional[int] = None) -> Tensor: ...
14
+ def avg_pool3d(input: Tensor, kernel_size: Union[_int, _size], stride: Optional[Union[_int, _size]] = None, padding: Union[_int, _size] = 0, ceil_mode: bool = False, count_include_pad: bool = True, divisor_override: Optional[int] = None) -> Tensor: ...
15
+ def elu_(input: Tensor, alpha: float = ...) -> Tensor: ...
16
+ def fractional_max_pool2d(input: Tensor, kernel_size: Union[_int, _size], output_size: Union[_int, _size], _random_samples: Tensor) -> Tuple[Tensor, Tensor]: ...
17
+ def fractional_max_pool3d(input: Tensor, kernel_size: Union[_int, _size], output_size: Union[_int, _size], _random_samples: Tensor) -> Tuple[Tensor, Tensor]: ...
18
+ def gelu(input: Tensor, approximate: str = ...) -> Tensor: ...
19
+ def hardsigmoid(input: Tensor, *, out: Optional[Tensor] = None) -> Tensor: ...
20
+ def hardtanh(input: Tensor, min_val: float = ..., max_val: float = ..., *, out: Optional[Tensor] = None) -> Tensor: ...
21
+ def hardtanh_(input: Tensor, min_val: float = ..., max_val: float = ...) -> Tensor: ...
22
+ def leaky_relu(input: Tensor, negative_slope: float = ..., *, out: Optional[Tensor] = None) -> Tensor: ...
23
+ def leaky_relu_(input: Tensor, negative_slope: float = ...) -> Tensor: ...
24
+ def linear(input: Tensor, weight: Tensor, bias: Optional[Tensor] = None) -> Tensor: ...
25
+ def log_sigmoid(input: Tensor) -> Tensor: ...
26
+ def one_hot(tensor: Tensor, num_classes: int = ...) -> Tensor: ...
27
+ def pad(input: Tensor, pad: Sequence[int], mode: str = ..., value: Optional[float] = None) -> Tensor: ...
28
+ def scaled_dot_product_attention(query: Tensor, key: Tensor, value: Tensor, attn_mask: Optional[Tensor] = None, dropout_p: float = 0.0, is_causal: bool = False, scale: Optional[float] = None, enable_gqa: bool = False) -> Tensor: ...
29
+ def softplus(input: Tensor, beta: float = ..., threshold: float = ...) -> Tensor: ...
30
+ def softshrink(input: Tensor, lambd: float = ...) -> Tensor: ...
31
+
32
+ # Defined in aten/src/ATen/native/mkldnn/Linear.cpp
33
+ def mkldnn_linear(input: Tensor, weight: Tensor, bias: Optional[Tensor]) -> Tensor: ...
34
+
35
+ # Defined at aten/src/ATen/native/mkldnn/MKLDNNConversions.cpp
36
+ def mkldnn_reorder_conv2d_weight(
37
+ self: Tensor,
38
+ padding: List,
39
+ stride: List,
40
+ dilatation: List,
41
+ groups: int,
42
+ ) -> Tensor: ...
43
+ def mkldnn_reorder_conv3d_weight(
44
+ self: Tensor,
45
+ padding: List,
46
+ stride: List,
47
+ dilatation: List,
48
+ groups: int,
49
+ ) -> Tensor: ...
50
+
51
+ # Defined in aten/src/ATen/native/mkldnn/Prelu.cpp
52
+ def mkldnn_prelu(input: Tensor, weight: Tensor) -> Tensor: ...
53
+
54
+ # Defined at tools/autograd/templates/python_nn_functions.cpp
55
+ @overload
56
+ def _parse_to(
57
+ device: _device,
58
+ dtype: _dtype,
59
+ non_blocking: _bool,
60
+ copy: _bool,
61
+ *,
62
+ memory_format: memory_format,
63
+ ) -> Tuple[_device, _dtype, _bool, memory_format]: ...
64
+ @overload
65
+ def _parse_to(
66
+ dtype: _dtype,
67
+ non_blocking: _bool,
68
+ copy: _bool,
69
+ *,
70
+ memory_format: memory_format,
71
+ ) -> Tuple[_device, _dtype, _bool, memory_format]: ...
72
+ @overload
73
+ def _parse_to(
74
+ tensor: Tensor,
75
+ non_blocking: _bool,
76
+ copy: _bool,
77
+ *,
78
+ memory_format: memory_format,
79
+ ) -> Tuple[_device, _dtype, _bool, memory_format]: ...
80
+
81
+ # Defined in aten/src/ATen/native/PackedSequence.cpp
82
+ def pad_sequence(
83
+ sequences: Union[List[Tensor], Tuple[Tensor, ...]],
84
+ batch_first: bool = False,
85
+ padding_value: float = 0.0,
86
+ padding_side: Union[Literal["left", "right"], str] = "right",
87
+ ) -> Tensor: ...
88
+ def flatten_dense_tensors(tensors: List[Tensor]) -> Tensor: ...
89
+ def unflatten_dense_tensors(flat: Tensor, tensors: List[Tensor]) -> List[Tensor]: ...
lib/python3.12/site-packages/torch/_C/_nvtx.pyi ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ # mypy: allow-untyped-defs
2
+ # Defined in torch/csrc/cuda/shared/nvtx.cpp
3
+ def rangePushA(message: str) -> int: ...
4
+ def rangePop() -> int: ...
5
+ def rangeStartA(message: str) -> int: ...
6
+ def rangeEnd(int) -> None: ...
7
+ def markA(message: str) -> None: ...
8
+ def deviceRangeStart(message: str, stream: int) -> object: ...
9
+ def deviceRangeEnd(range_handle: object, stream: int) -> None: ...
lib/python3.12/site-packages/torch/_C/_onnx.pyi ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Defined in torch/csrc/onnx/init.cpp
2
+
3
+ from enum import Enum
4
+
5
+ PRODUCER_VERSION: str
6
+
7
+ class TensorProtoDataType(Enum):
8
+ UNDEFINED = ...
9
+ FLOAT = ...
10
+ UINT8 = ...
11
+ INT8 = ...
12
+ UINT16 = ...
13
+ INT16 = ...
14
+ INT32 = ...
15
+ INT64 = ...
16
+ STRING = ...
17
+ BOOL = ...
18
+ FLOAT16 = ...
19
+ DOUBLE = ...
20
+ UINT32 = ...
21
+ UINT64 = ...
22
+ COMPLEX64 = ...
23
+ COMPLEX128 = ...
24
+ BFLOAT16 = ...
25
+ FLOAT8E5M2 = ...
26
+ FLOAT8E4M3FN = ...
27
+ FLOAT8E5M2FNUZ = ...
28
+ FLOAT8E4M3FNUZ = ...
29
+
30
+ class OperatorExportTypes(Enum):
31
+ ONNX = ...
32
+ ONNX_ATEN = ...
33
+ ONNX_ATEN_FALLBACK = ...
34
+ ONNX_FALLTHROUGH = ...
35
+
36
+ class TrainingMode(Enum):
37
+ EVAL = ...
38
+ PRESERVE = ...
39
+ TRAINING = ...
lib/python3.12/site-packages/torch/_C/_profiler.pyi ADDED
@@ -0,0 +1,245 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from enum import Enum
2
+ from typing import Any, Literal, Optional
3
+ from typing_extensions import TypeAlias
4
+
5
+ from torch._C import device, dtype, layout
6
+
7
+ # defined in torch/csrc/profiler/python/init.cpp
8
+
9
+ class RecordScope(Enum):
10
+ FUNCTION = ...
11
+ BACKWARD_FUNCTION = ...
12
+ TORCHSCRIPT_FUNCTION = ...
13
+ KERNEL_FUNCTION_DTYPE = ...
14
+ CUSTOM_CLASS = ...
15
+ BUILD_FEATURE = ...
16
+ LITE_INTERPRETER = ...
17
+ USER_SCOPE = ...
18
+ STATIC_RUNTIME_OP = ...
19
+ STATIC_RUNTIME_MODEL = ...
20
+
21
+ class ProfilerState(Enum):
22
+ Disable = ...
23
+ CPU = ...
24
+ CUDA = ...
25
+ NVTX = ...
26
+ ITT = ...
27
+ KINETO = ...
28
+ KINETO_GPU_FALLBACK = ...
29
+ KINETO_PRIVATEUSE1_FALLBACK = ...
30
+ KINETO_PRIVATEUSE1 = ...
31
+
32
+ class ActiveProfilerType(Enum):
33
+ NONE = ...
34
+ LEGACY = ...
35
+ KINETO = ...
36
+ NVTX = ...
37
+ ITT = ...
38
+
39
+ class ProfilerActivity(Enum):
40
+ CPU = ...
41
+ CUDA = ...
42
+ XPU = ...
43
+ MTIA = ...
44
+ PrivateUse1 = ...
45
+
46
+ class _EventType(Enum):
47
+ TorchOp = ...
48
+ Backend = ...
49
+ Allocation = ...
50
+ OutOfMemory = ...
51
+ PyCall = ...
52
+ PyCCall = ...
53
+ Kineto = ...
54
+
55
+ class _ExperimentalConfig:
56
+ def __init__(
57
+ self,
58
+ profiler_metrics: list[str] = ...,
59
+ profiler_measure_per_kernel: bool = ...,
60
+ verbose: bool = ...,
61
+ performance_events: list[str] = ...,
62
+ enable_cuda_sync_events: bool = ...,
63
+ ) -> None: ...
64
+
65
+ class ProfilerConfig:
66
+ def __init__(
67
+ self,
68
+ state: ProfilerState,
69
+ report_input_shapes: bool,
70
+ profile_memory: bool,
71
+ with_stack: bool,
72
+ with_flops: bool,
73
+ with_modules: bool,
74
+ experimental_config: _ExperimentalConfig,
75
+ trace_id: Optional[str] = None,
76
+ ) -> None: ...
77
+
78
+ class _ProfilerEvent:
79
+ start_tid: int
80
+ start_time_ns: int
81
+ children: list[_ProfilerEvent]
82
+
83
+ # TODO(robieta): remove in favor of `self.typed`
84
+ extra_fields: (
85
+ _ExtraFields_TorchOp
86
+ | _ExtraFields_Backend
87
+ | _ExtraFields_Allocation
88
+ | _ExtraFields_OutOfMemory
89
+ | _ExtraFields_PyCall
90
+ | _ExtraFields_PyCCall
91
+ | _ExtraFields_Kineto
92
+ )
93
+
94
+ @property
95
+ def typed(
96
+ self,
97
+ ) -> (
98
+ tuple[Literal[_EventType.TorchOp], _ExtraFields_TorchOp]
99
+ | tuple[Literal[_EventType.Backend], _ExtraFields_Backend]
100
+ | tuple[Literal[_EventType.Allocation], _ExtraFields_Allocation]
101
+ | tuple[Literal[_EventType.OutOfMemory], _ExtraFields_OutOfMemory]
102
+ | tuple[Literal[_EventType.PyCall], _ExtraFields_PyCall]
103
+ | tuple[Literal[_EventType.PyCCall], _ExtraFields_PyCCall]
104
+ | tuple[Literal[_EventType.Kineto], _ExtraFields_Kineto]
105
+ ): ...
106
+ @property
107
+ def name(self) -> str: ...
108
+ @property
109
+ def tag(self) -> _EventType: ...
110
+ @property
111
+ def id(self) -> int: ...
112
+ @property
113
+ def parent(self) -> _ProfilerEvent | None: ...
114
+ @property
115
+ def correlation_id(self) -> int: ...
116
+ @property
117
+ def end_time_ns(self) -> int: ...
118
+ @property
119
+ def duration_time_ns(self) -> int: ...
120
+
121
+ class _TensorMetadata:
122
+ impl_ptr: int | None
123
+ storage_data_ptr: int | None
124
+ id: int | None
125
+
126
+ @property
127
+ def allocation_id(self) -> int | None: ...
128
+ @property
129
+ def layout(self) -> layout: ...
130
+ @property
131
+ def device(self) -> device: ...
132
+ @property
133
+ def dtype(self) -> dtype: ...
134
+ @property
135
+ def sizes(self) -> list[int]: ...
136
+ @property
137
+ def strides(self) -> list[int]: ...
138
+
139
+ Scalar: TypeAlias = int | float | bool | complex
140
+ Input: TypeAlias = _TensorMetadata | list[_TensorMetadata] | Scalar | None
141
+
142
+ class _ExtraFields_TorchOp:
143
+ name: str
144
+ sequence_number: int
145
+ allow_tf32_cublas: bool
146
+
147
+ @property
148
+ def inputs(self) -> list[Input]: ...
149
+ @property
150
+ def scope(self) -> RecordScope: ...
151
+
152
+ class _ExtraFields_Backend: ...
153
+
154
+ class _ExtraFields_Allocation:
155
+ ptr: int
156
+ id: int | None
157
+ alloc_size: int
158
+ total_allocated: int
159
+ total_reserved: int
160
+
161
+ @property
162
+ def allocation_id(self) -> int | None: ...
163
+ @property
164
+ def device(self) -> device: ...
165
+
166
+ class _ExtraFields_OutOfMemory: ...
167
+
168
+ class _PyFrameState:
169
+ line_number: int
170
+ function_name: str
171
+
172
+ @property
173
+ def file_name(self) -> str: ...
174
+
175
+ class _NNModuleInfo:
176
+ @property
177
+ def self_ptr(self) -> int: ...
178
+ @property
179
+ def cls_ptr(self) -> int: ...
180
+ @property
181
+ def cls_name(self) -> str: ...
182
+ @property
183
+ def parameters(
184
+ self,
185
+ ) -> list[tuple[str, _TensorMetadata, _TensorMetadata | None]]: ...
186
+
187
+ class _OptimizerInfo:
188
+ @property
189
+ def parameters(
190
+ self,
191
+ ) -> list[
192
+ tuple[
193
+ # Parameter
194
+ _TensorMetadata,
195
+ #
196
+ # Gradient (if present during optimizer.step())
197
+ _TensorMetadata | None,
198
+ #
199
+ # Optimizer state for Parameter as (name, tensor) pairs
200
+ list[tuple[str, _TensorMetadata]],
201
+ ]
202
+ ]: ...
203
+
204
+ class _ExtraFields_PyCCall:
205
+ @property
206
+ def caller(self) -> _PyFrameState: ...
207
+
208
+ class _ExtraFields_PyCall:
209
+ @property
210
+ def callsite(self) -> _PyFrameState: ...
211
+ @property
212
+ def caller(self) -> _PyFrameState: ...
213
+ @property
214
+ def module(self) -> _NNModuleInfo | None: ...
215
+ @property
216
+ def optimizer(self) -> _OptimizerInfo | None: ...
217
+
218
+ class _ExtraFields_Kineto: ...
219
+
220
+ def _add_execution_trace_observer(output_file_path: str) -> bool: ...
221
+ def _remove_execution_trace_observer() -> None: ...
222
+ def _enable_execution_trace_observer() -> None: ...
223
+ def _disable_execution_trace_observer() -> None: ...
224
+ def _set_record_concrete_inputs_enabled_val(val: bool) -> None: ...
225
+ def _set_fwd_bwd_enabled_val(val: bool) -> None: ...
226
+ def _set_cuda_sync_enabled_val(val: bool) -> None: ...
227
+
228
+ class CapturedTraceback: ...
229
+
230
+ def gather_traceback(python: bool, script: bool, cpp: bool) -> CapturedTraceback: ...
231
+
232
+ # The Dict has name, filename, line
233
+ def symbolize_tracebacks(
234
+ to_symbolize: list[CapturedTraceback],
235
+ ) -> list[list[dict[str, str]]]: ...
236
+
237
+ class _RecordFunctionFast:
238
+ def __init__(
239
+ self,
240
+ name: str,
241
+ input_values: list | tuple | None = None,
242
+ keyword_values: dict | None = None,
243
+ ) -> None: ...
244
+ def __enter__(self) -> None: ...
245
+ def __exit__(self, *args: Any) -> None: ...
lib/python3.12/site-packages/torch/_C/_verbose.pyi ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ # Defined in torch/csrc/utils/verbose.cpp
2
+ def mkl_set_verbose(enable: int) -> int: ...
3
+ def mkldnn_set_verbose(level: int) -> int: ...
lib/python3.12/site-packages/torch/_custom_op/__init__.py ADDED
File without changes
lib/python3.12/site-packages/torch/_custom_op/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (195 Bytes). View file
 
lib/python3.12/site-packages/torch/_custom_op/__pycache__/autograd.cpython-312.pyc ADDED
Binary file (13.5 kB). View file
 
lib/python3.12/site-packages/torch/_custom_op/__pycache__/functional.cpython-312.pyc ADDED
Binary file (9.23 kB). View file
 
lib/python3.12/site-packages/torch/_custom_op/__pycache__/impl.cpython-312.pyc ADDED
Binary file (32.3 kB). View file
 
lib/python3.12/site-packages/torch/_custom_op/autograd.py ADDED
@@ -0,0 +1,275 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # mypy: allow-untyped-defs
2
+ import torch
3
+ import torch.utils._pytree as pytree
4
+ from collections import namedtuple
5
+ import functools
6
+
7
+
8
+ # NOTE [CustomOp autograd kernel indirection]
9
+ # We register `inner` as the autograd kernel for this custom_op.
10
+ # `inner` either calls the autograd formula registered by the user,
11
+ # or goes into an `autograd_not_implemented` kernel.
12
+ #
13
+ # The reason why this indirection exists is
14
+ # so that we can swap out the autograd kernel (the PyTorch dispatcher
15
+ # doesn't actually allow us to do this). By default, we want
16
+ # the `autograd_not_implemented` behavior, but then the user may come
17
+ # and register something that is actually a backward formula
18
+ def autograd_kernel_indirection(custom_op):
19
+ autograd_fallback = autograd_not_implemented(custom_op)
20
+
21
+ def inner(*args, **kwargs):
22
+ if custom_op._has_impl('autograd'):
23
+ kernel = custom_op._get_impl('autograd').func
24
+ return kernel(*args, **kwargs)
25
+ # As explained in NOTE ["backward", "save_for_backward", and "autograd"],
26
+ # after the user gives us "backward" and "save_for_backward", we generate
27
+ # the "autograd" impl. If the user only provided one, then we tell
28
+ # the user they've done something wrong.
29
+ if custom_op._has_impl('save_for_backward') or custom_op._has_impl('backward'):
30
+ missing = (
31
+ 'save_for_backward' if custom_op._has_impl('backward')
32
+ else 'backward'
33
+ )
34
+ found = 'save_for_backward' if missing == 'backward' else 'backward'
35
+ loc = custom_op._get_impl(found).location
36
+ raise RuntimeError(
37
+ f"We found a '{found}' registration for {custom_op} at "
38
+ f"{loc} but were unable to find a '{missing}' registration. "
39
+ f"To use the CustomOp API to register a backward formula, "
40
+ f"please provide us both a backward function and a "
41
+ f"'save for backward' function via `impl_backward` and "
42
+ f"`impl_save_for_backward` respectively.")
43
+ return autograd_fallback(*args, **kwargs)
44
+ return inner
45
+
46
+
47
+ # TODO(#101191): Use the actual C++ autograd not implemented fallback,
48
+ # or change the default autograd fallback to the autograd not implemented fallback.
49
+ def autograd_not_implemented(custom_op):
50
+ def kernel(*args, **kwargs):
51
+ if torch.is_grad_enabled() and pytree.tree_any(
52
+ lambda x: isinstance(x, torch.Tensor) and x.requires_grad, (args, kwargs)
53
+ ):
54
+ raise RuntimeError("Autograd has not been implemented for operator")
55
+ with torch._C._AutoDispatchBelowAutograd():
56
+ return custom_op(*args, **kwargs)
57
+ return kernel
58
+
59
+
60
+ def mark_non_differentiable(ctx, output, output_differentiability):
61
+ # Output types are restricted to be:
62
+ # - Tensor
63
+ # - Tensor[]
64
+ # - int, bool, Scalar, float
65
+ # See _check_can_register_backward
66
+ if output_differentiability is not None:
67
+ if not isinstance(output, tuple):
68
+ tuple_output = (output,)
69
+ else:
70
+ tuple_output = output # type: ignore[assignment]
71
+ assert len(output_differentiability) == len(tuple_output)
72
+ non_differentiable_tensors = []
73
+ for idx, (differentiable, out) in enumerate(zip(output_differentiability, tuple_output)):
74
+ if isinstance(out, torch.Tensor):
75
+ if not differentiable:
76
+ non_differentiable_tensors.append(out)
77
+ continue
78
+ if isinstance(out, list):
79
+ if not differentiable:
80
+ non_differentiable_tensors.extend(out)
81
+ continue
82
+ if differentiable:
83
+ raise RuntimeError(
84
+ f"With output_differentiability={output_differentiability}. "
85
+ f"At idx {idx}, we received an object of type {type(out)} that "
86
+ f"is not a Tensor, so it cannot have be marked as differentiable in "
87
+ f"output_differentiability.")
88
+ if non_differentiable_tensors:
89
+ ctx.mark_non_differentiable(*non_differentiable_tensors)
90
+
91
+
92
+ def construct_autograd_kernel(
93
+ schema,
94
+ output_differentiability,
95
+ custom_op,
96
+ op_overload,
97
+ save_for_backward_fn,
98
+ backward_fn):
99
+
100
+ def apply(*args):
101
+ flat_args, spec = pytree.tree_flatten(args)
102
+ out_spec = None
103
+
104
+ def forward(ctx, *flat_args):
105
+ ctx.set_materialize_grads(True)
106
+ args = pytree.tree_unflatten(list(flat_args), spec)
107
+ with torch._C._AutoDispatchBelowAutograd():
108
+ output = op_overload(*args)
109
+
110
+ # We use the info about args to give better error messages in backward
111
+ args_info = namedtuple_args(
112
+ schema, pytree.tree_map(type, args))
113
+
114
+ save_for_backward_fn_inputs = namedtuple_args(schema, args)
115
+ to_save = save_for_backward_fn(save_for_backward_fn_inputs, output)
116
+
117
+ save_pytree_for_backward(ctx, (to_save, args_info))
118
+ mark_non_differentiable(ctx, output, output_differentiability)
119
+
120
+ nonlocal out_spec
121
+ flat_output, out_spec = pytree.tree_flatten(output)
122
+ return tuple(flat_output)
123
+
124
+ def backward(ctx, *flat_grad_output):
125
+ assert out_spec is not None
126
+ grads = pytree.tree_unflatten(list(flat_grad_output), out_spec)
127
+ saved, args_info = unpack_saved(ctx)
128
+ # There is nothing on the ctx object for now, it is just there so
129
+ # that we can add additional things in the future.
130
+ inner_ctx = object()
131
+ if not isinstance(grads, tuple):
132
+ grads = (grads,)
133
+ grad_inputs_dict = backward_fn(inner_ctx, saved, *grads)
134
+
135
+ # Massage the grad_inputs_dict to a form acceptable by
136
+ # autograd.Function.
137
+ validate_grad_inputs_dict(grad_inputs_dict, custom_op, args_info)
138
+ return grad_inputs_dict_to_flat_tuple(grad_inputs_dict, args_info)
139
+
140
+ generated_cls = gen_autograd_function(
141
+ custom_op._opname + '_customop', forward, backward)
142
+
143
+ flat_output = generated_cls.apply(*flat_args)
144
+ assert out_spec is not None
145
+ return pytree.tree_unflatten(list(flat_output), out_spec)
146
+ return apply
147
+
148
+
149
+ def gen_autograd_function(name, forward, backward):
150
+ generated_cls = type(
151
+ name,
152
+ (torch.autograd.Function,),
153
+ {
154
+ 'forward': staticmethod(forward),
155
+ 'backward': staticmethod(backward),
156
+ }
157
+ )
158
+ return generated_cls
159
+
160
+
161
+ @functools.lru_cache
162
+ def namedtuple_args_cls(schema):
163
+ attribs = [arg.name for arg in schema.arguments.flat_all]
164
+ name = str(schema.name) + "_args"
165
+ # mypy doesn't support dynamic namedtuple name
166
+ tuple_cls = namedtuple(name, attribs) # type: ignore[misc]
167
+ return tuple_cls
168
+
169
+
170
+ def namedtuple_args(schema, args):
171
+ assert isinstance(args, tuple)
172
+ tuple_cls = namedtuple_args_cls(schema)
173
+ return tuple_cls(*args)
174
+
175
+
176
+ def validate_grad_inputs_dict(grad_inputs_dict, forward_op, args_info):
177
+ def error(what):
178
+ backward = forward_op._get_impl('backward')
179
+ raise RuntimeError(
180
+ f"In the backward function defined for {forward_op} at "
181
+ f"{backward.location} using the CustomOp API, {what}")
182
+
183
+ if not isinstance(grad_inputs_dict, dict):
184
+ error(f"expected the output of the backward function to be a dict but "
185
+ f"got {type(grad_inputs_dict)}")
186
+
187
+ expected_keys = {arg.name for arg in forward_op._schema.arguments.flat_all
188
+ if arg.type.is_tensor_like()}
189
+ actual_keys = grad_inputs_dict.keys()
190
+ if expected_keys != actual_keys:
191
+ error(f"expected the returned grad_input dict to have keys "
192
+ f"{expected_keys} but got {actual_keys}. The backward "
193
+ f"function must return a gradient (can be None) for each arg "
194
+ f"to the CustomOp that may be a Tensor or Sequence[Tensor]. "
195
+ f"Args declared to be non-Tensor-like types should not appear "
196
+ f"in the grad_input dict")
197
+
198
+ for name, grad in grad_inputs_dict.items():
199
+ arg_info = getattr(args_info, name)
200
+
201
+ if isinstance(arg_info, list):
202
+ if not isinstance(grad, (tuple, list)):
203
+ error(f"for input '{name}' expected the grad_input dict to "
204
+ f"hold a list of gradients but got object of type "
205
+ f"{type(grad)}.")
206
+ if not len(grad) == len(arg_info):
207
+ error(f"for input '{name}' expected the grad_input dict to "
208
+ f"hold a list of {len(arg_info)} gradients but got "
209
+ f"{len(grad)}")
210
+ for idx, (g, info) in enumerate(zip(grad, arg_info)):
211
+ if g is None:
212
+ continue
213
+ if not isinstance(g, torch.Tensor):
214
+ error(f"for input '{name}' expected the grad_input dict to "
215
+ f"hold a list of None or Tensor gradients but got "
216
+ f"object of {type(g)} at index {idx}")
217
+ if not issubclass(info, torch.Tensor):
218
+ error(f"for input '{name}', got a Tensor as the gradient "
219
+ f"for the {idx}-th value but expected None because "
220
+ f"the {idx}-th value was not a Tensor (it was "
221
+ f"type {arg_info}")
222
+ continue
223
+
224
+ if grad is None:
225
+ continue
226
+ if not isinstance(grad, torch.Tensor):
227
+ error(f"got object of type {type(grad)} as the gradient for input "
228
+ f"'{name}', "
229
+ f"but expected the gradient to be either None or a Tensor")
230
+ if not issubclass(arg_info, torch.Tensor):
231
+ error(f"got a Tensor as the gradient for input '{name}' but "
232
+ f"expected None as the gradient because input '{name}' "
233
+ f"was not a Tensor (it was type {arg_info}).")
234
+
235
+
236
+ def grad_inputs_dict_to_flat_tuple(grad_inputs_dict, args_info):
237
+ result = []
238
+ for name, arg_info in args_info._asdict().items():
239
+ if name not in grad_inputs_dict:
240
+ result.append(pytree.tree_map(lambda x: None, arg_info))
241
+ continue
242
+ result.append(grad_inputs_dict[name])
243
+ return tuple(pytree.tree_leaves(result))
244
+
245
+ # Saves "stuff" (a pytree) onto the ctx object. Use unpack_saved to unpack it.
246
+ # autograd.Function prefers that users use ctx.save_for_backward to
247
+ # save Tensors (to avoid reference cycles) and for non-Tensors to go onto the
248
+ # ctx object.
249
+ def save_pytree_for_backward(ctx, stuff):
250
+ flat_stuff, spec = pytree.tree_flatten(stuff)
251
+ num_elts = len(flat_stuff)
252
+ tensor_idxs = [idx for idx, thing in enumerate(flat_stuff)
253
+ if isinstance(thing, torch.Tensor)]
254
+ non_tensor_idxs = [idx for idx, thing in enumerate(flat_stuff)
255
+ if not isinstance(thing, torch.Tensor)]
256
+ tensors = [thing for thing in flat_stuff if isinstance(thing, torch.Tensor)]
257
+ non_tensors = [thing for thing in flat_stuff if not isinstance(thing, torch.Tensor)]
258
+
259
+ ctx.spec = spec
260
+ ctx.num_elts = num_elts
261
+ ctx.save_for_backward(*tensors)
262
+ ctx.tensor_idxs = tensor_idxs
263
+ ctx.saved_non_tensors = non_tensors
264
+ ctx.non_tensor_idxs = non_tensor_idxs
265
+
266
+
267
+ # Inverse operation to save_pytree_for_backward
268
+ def unpack_saved(ctx):
269
+ flat_stuff = [None] * ctx.num_elts
270
+ for tensor, idx in zip(ctx.saved_tensors, ctx.tensor_idxs):
271
+ flat_stuff[idx] = tensor
272
+ for non_tensor, idx in zip(ctx.saved_non_tensors, ctx.non_tensor_idxs):
273
+ flat_stuff[idx] = non_tensor
274
+ stuff = pytree.tree_unflatten(flat_stuff, ctx.spec)
275
+ return stuff
lib/python3.12/site-packages/torch/_custom_op/functional.py ADDED
@@ -0,0 +1,188 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # mypy: allow-untyped-defs
2
+ import weakref
3
+
4
+ import torch
5
+ import torch.utils._pytree as pytree
6
+ from torch._C import _ExcludeDispatchKeyGuard, DispatchKey, DispatchKeySet
7
+ from torch._ops import OpOverload
8
+ from torch.library import Library
9
+ from torchgen.model import (
10
+ BaseTy,
11
+ BaseType,
12
+ FunctionSchema,
13
+ OperatorName,
14
+ OptionalType,
15
+ SchemaKind,
16
+ )
17
+
18
+ from .autograd import autograd_not_implemented
19
+
20
+
21
+ def register_functional_op(
22
+ lib: Library,
23
+ new_op_name: str,
24
+ mutable_op: OpOverload,
25
+ ) -> None:
26
+ """Given a mutable operator, registers the functional variant.
27
+
28
+ This API also correctly links the functional variant with the mutable
29
+ operator for the purposes of functionalization.
30
+
31
+ All of the new registrations are performed on the ``lib`` passed in.
32
+
33
+ Arguments:
34
+ lib (Library): Should be a torch.library.Library object that has
35
+ the same namespace as ``mutable_op``'s namespace.
36
+ lib will be used to register the new functional op as well
37
+ as a functionalization kernel for the ``mutable_op``
38
+ If you don't have a library handy, use
39
+ ``torch.library.Library(ns, 'FRAGMENT')`` to construct one.
40
+ new_op_name (str): The name of the functional operator (without the
41
+ namespace). If no namespace, the new functional variant will be
42
+ accessible under ``torch.ops.{lib.ns}.new_op_name``.
43
+ mutable_op (OpOverload): The mutable custom operator. Note
44
+ that you may need to add a `.default` to it, like
45
+ `torch.ops.aten.abs_.default`.
46
+
47
+ """
48
+ validate(mutable_op)
49
+ schema = functional_schema(new_op_name, mutable_op)
50
+ lib.define(schema)
51
+
52
+ functional_impl = construct_functional_impl(mutable_op)
53
+ lib.impl(new_op_name, functional_impl, 'CompositeExplicitAutograd')
54
+
55
+ functional_op = getattr(getattr(torch.ops, lib.ns), new_op_name).default
56
+
57
+ # There's no easy way for us to generate the autograd kernel, so we
58
+ # use autograd_not_implemented. Also, this makes it so that the user
59
+ # is unable to register an autograd formula themselves. This shouldn't
60
+ # be a problem if the user doesn't use the functional op direclty
61
+ # in their program, but we may need to revist this in the future.
62
+ lib.impl(new_op_name, autograd_not_implemented(functional_op), 'Autograd')
63
+
64
+ f_kernel = construct_functionalization_kernel(weakref.proxy(mutable_op), functional_op)
65
+
66
+ lib.impl(mutable_op, f_kernel, 'Functionalize')
67
+
68
+
69
+ def construct_functional_impl(mutable_op):
70
+ def functional_impl(*args):
71
+ # Strategy:
72
+ # - clone args that would have been mutated
73
+ # - run mutable_op
74
+ # - return the cloned args as additional outputs
75
+ new_args = []
76
+ extra_rets = []
77
+ for is_write, arg in zip(mutable_args(mutable_op), args):
78
+ if is_write:
79
+ cloned = arg.clone() if arg is not None else None
80
+ new_args.append(cloned)
81
+ extra_rets.append(cloned)
82
+ else:
83
+ new_args.append(arg)
84
+ result = mutable_op(*new_args)
85
+ if result is None:
86
+ return tuple(extra_rets)
87
+ if isinstance(result, tuple):
88
+ return (*result, *extra_rets)
89
+ return (result, *extra_rets)
90
+ return functional_impl
91
+
92
+
93
+ def construct_functionalization_kernel(mutable_op, functional_op):
94
+ def kernel(*args):
95
+ # There's nothing to be functionalized!
96
+ # We can still end up here because DispatchKey::Functionalize is a mode key
97
+ if pytree.tree_all_only(torch.Tensor, lambda x: not torch._is_functional_tensor(x), args):
98
+ with _ExcludeDispatchKeyGuard(DispatchKeySet(DispatchKey.Functionalize)):
99
+ return mutable_op(*args)
100
+
101
+ # NB: This differs from the codegen -- codegen handles cases where there
102
+ # are mixed FunctionalTensorWrapper and non-FunctionalTensorWrapper.
103
+ # This only really matters for XLA (mixed CPU-XLA tensors) and
104
+ # running functionalization without the PT2 stack (which guarantees to us that
105
+ # all tensors are FunctionalTensorWrapper).
106
+ if not pytree.tree_all_only(torch.Tensor, torch._is_functional_tensor, args):
107
+ raise RuntimeError("{mutable_op}: expected all args to be FunctionalTensorWrapper")
108
+
109
+ unwrapped_args = []
110
+ for arg in args:
111
+ if isinstance(arg, torch.Tensor) and torch._is_functional_tensor(arg):
112
+ torch._sync(arg)
113
+ unwrapped = torch._from_functional_tensor(arg)
114
+ unwrapped_args.append(unwrapped)
115
+ else:
116
+ unwrapped_args.append(arg)
117
+
118
+ with _ExcludeDispatchKeyGuard(DispatchKeySet(DispatchKey.Functionalize)):
119
+ output = functional_op(*unwrapped_args)
120
+
121
+ num_actual_output = len(mutable_op._schema.returns)
122
+ actual_output = pytree.tree_map(
123
+ torch._to_functional_tensor, output[:num_actual_output])
124
+
125
+ new_values_to_propagate = output[num_actual_output:]
126
+ inputs_to_replace = [arg for is_write, arg in zip(mutable_args(mutable_op), args)
127
+ if is_write]
128
+ assert len(new_values_to_propagate) == len(inputs_to_replace)
129
+ for new_value, arg in zip(new_values_to_propagate, inputs_to_replace):
130
+ if (arg is None and new_value is None) or (arg is not None and new_value is not None):
131
+ continue
132
+ torch._C._propagate_xla_data(arg, new_value)
133
+ torch._C._replace_(arg, new_value)
134
+ torch._C._commit_update(arg)
135
+ torch._sync(arg)
136
+
137
+ if len(actual_output) == 1:
138
+ return actual_output[0]
139
+ elif len(actual_output) == 0:
140
+ return None
141
+ return actual_output
142
+
143
+ return kernel
144
+
145
+
146
+ def validate(mutable_op: OpOverload):
147
+ if not isinstance(mutable_op, OpOverload):
148
+ raise TypeError(
149
+ f"register_functional_op(mutable_op): expected mutable_op to be instance of "
150
+ f"OpOverload but got {type(mutable_op)}")
151
+
152
+ # There are generally three types of "in-place" or "mutable" ops.
153
+ # Each of them have their own conventions:
154
+ # - inplace (first input modified in-place and returned as only output)
155
+ # - out= (some args modified in-place and returned as outputs)
156
+ # - mutable (some args modified in-place but none of those returned as outputs)
157
+ # In theory we can support all three, but we'll just support the last
158
+ # option right now for simplicity.
159
+ schema = FunctionSchema.parse(str(mutable_op._schema))
160
+ if not schema.kind() == SchemaKind.mutable:
161
+ raise RuntimeError("Expected op to be mutable (as opposed to functional, inplace or out)")
162
+ for ret in schema.returns:
163
+ # construct_functionalization_kernel assumes this for simplicity
164
+ if ret.annotation is not None:
165
+ raise NotImplementedError(
166
+ "NYI: register_functional_op(op) where op returns a mutated or aliased value. "
167
+ "Please file an issue (and as a workaround, modify your operator to "
168
+ "not return the mutated value or aliases)")
169
+ for arg in schema.arguments.flat_all:
170
+ # construct_functionalization_kernel assumes this for simplicity
171
+ if arg.type.is_tensor_like() and (
172
+ arg.type != BaseType(BaseTy.Tensor)
173
+ and arg.type != OptionalType(BaseType(BaseTy.Tensor))
174
+ ):
175
+ raise NotImplementedError(
176
+ "NYI: register_functional_op(op) where op has a List[Tensor] input."
177
+ "Please file an issue.")
178
+
179
+
180
+ def functional_schema(new_op_name, op: OpOverload):
181
+ schema = FunctionSchema.parse(str(op._schema))
182
+ schema = schema.signature().with_name(OperatorName.parse(new_op_name))
183
+ return str(schema)
184
+
185
+
186
+ def mutable_args(op: OpOverload):
187
+ return tuple(False if arg.alias_info is None else arg.alias_info.is_write
188
+ for arg in op._schema.arguments)
lib/python3.12/site-packages/torch/_custom_op/impl.py ADDED
@@ -0,0 +1,670 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # mypy: allow-untyped-defs
2
+ import dataclasses
3
+ import functools
4
+ import inspect
5
+ import sys
6
+ import typing
7
+ import weakref
8
+ import warnings
9
+
10
+ from torchgen.model import FunctionSchema, OperatorName, SchemaKind, BaseType, ListType, BaseTy
11
+
12
+ import torch
13
+ import torch._C as _C
14
+ import torch.library as library
15
+ from torch.library import get_ctx
16
+
17
+ from .autograd import autograd_kernel_indirection, construct_autograd_kernel
18
+ import torch._library.infer_schema
19
+ from torch._library.infer_schema import infer_schema
20
+
21
+ """
22
+ torch._custom_op is deprecated. We shipped a production-ready version of it into torch.library.
23
+ Please use those APIs instead.
24
+ """
25
+
26
+ __all__ = ["custom_op", "CustomOp", "get_ctx"]
27
+
28
+
29
+ SUPPORTED_DEVICE_TYPE_TO_KEY = {
30
+ "cpu": "CPU",
31
+ "cuda": "CUDA",
32
+ }
33
+
34
+ # We will not let users register CustomOps with anything that could look like
35
+ # PyTorch internals to avoid confusion.
36
+ RESERVED_NS = {
37
+ "prim",
38
+ "prims",
39
+ "aten",
40
+ "at",
41
+ "torch",
42
+ "pytorch",
43
+ }
44
+
45
+ def warn_deprecated():
46
+ warnings.warn(
47
+ "torch._custom_op is deprecated and will be removed in PyTorch 2.6, please "
48
+ "use the equivalent torch.library API instead.", DeprecationWarning)
49
+
50
+
51
+ def custom_op(
52
+ qualname: str, manual_schema: typing.Optional[str] = None
53
+ ) -> typing.Callable:
54
+ r"""
55
+ This API is deprecated, please use torch.library.custom_op instead
56
+ """
57
+ warn_deprecated()
58
+
59
+ def inner(func):
60
+ if not inspect.isfunction(func):
61
+ raise ValueError(
62
+ f"custom_op(...)(func): Expected `func` to be a Python "
63
+ f"function, got: {type(func)}"
64
+ )
65
+
66
+ ns, name = parse_qualname(qualname)
67
+ validate_namespace(ns)
68
+ if func.__name__ != name:
69
+ raise ValueError(
70
+ f"custom_op(qualname='{qualname}', ...)(func): expected `func` "
71
+ f"to have name '{name}' but got '{func.__name__}'. "
72
+ f"Please either change the name of `func` or the qualname that "
73
+ f"is passed to `custom_op`"
74
+ )
75
+
76
+ schema = infer_schema(func, mutates_args=()) if manual_schema is None else manual_schema
77
+ schema_str = f"{name}{schema}"
78
+ function_schema = FunctionSchema.parse(schema_str)
79
+ validate_schema(function_schema)
80
+ if manual_schema is not None:
81
+ validate_function_matches_schema(function_schema, func)
82
+
83
+ lib = library.Library(ns, "FRAGMENT")
84
+ lib.define(schema_str)
85
+ ophandle = find_ophandle_or_throw(ns, function_schema.name)
86
+ result = CustomOp(lib, ns, function_schema, name, ophandle, _private_access=True)
87
+
88
+ result.__name__ = func.__name__
89
+ result.__module__ = func.__module__
90
+ result.__doc__ = func.__doc__
91
+
92
+ library.impl(lib, result._opname, "Autograd")(
93
+ autograd_kernel_indirection(weakref.proxy(result))
94
+ )
95
+
96
+ torch._C._dispatch_set_report_error_callback(
97
+ ophandle, functools.partial(report_error_callback, weakref.proxy(result))
98
+ )
99
+
100
+ return result
101
+
102
+ return inner
103
+
104
+
105
+ # Global dictionary holding references to all CustomOp objects
106
+ # Yes, it keeps all CustomOps alive (see NOTE [CustomOp lifetime])
107
+ # Used to query the CustomOp associated with a specific C++ dispatcher operator.
108
+ # An example usage is FakeTensor: FakeTensor checks if a specific operator
109
+ # has an implementation registered via the CustomOp API.
110
+ # Indexed by qualname (e.g. aten::foo)
111
+ global_registry: typing.Dict[str, "CustomOp"] = {}
112
+
113
+
114
+ class CustomOp:
115
+ r"""
116
+ This API is deprecated, please use torch.library.custom_op instead
117
+ """
118
+
119
+ def __init__(self, lib, cpp_ns, schema, operator_name, ophandle, *, _private_access=False):
120
+ super().__init__()
121
+ warn_deprecated()
122
+ if not _private_access:
123
+ raise RuntimeError(
124
+ "The CustomOp constructor is private and we do not guarantee "
125
+ "BC for it. Please use custom_op(...) to create a CustomOp object"
126
+ )
127
+ name = f"{cpp_ns}::{operator_name}"
128
+ self._schema = schema
129
+ self._cpp_ns = cpp_ns
130
+ self._lib: library.Library = lib
131
+ self._ophandle: _C._DispatchOperatorHandle = ophandle
132
+ # Has the name of the op, e.g. "foo". We cache here for convenience.
133
+ self._opname: str = operator_name
134
+ # this is _opname but with namespace. e.g. "custom::foo"
135
+ self._qualname: str = name
136
+ self.__name__ = None # mypy requires this
137
+ # NB: Some of these impls are registered as kernels to DispatchKeys.
138
+ # Modifying the _impls dict directly won't do anything in that case.
139
+ self._impls: typing.Dict[str, typing.Optional[FuncAndLocation]] = {}
140
+ # See NOTE [CustomOp autograd kernel indirection]
141
+ self._registered_autograd_kernel_indirection = False
142
+
143
+ global_registry[self._qualname] = self
144
+
145
+ def _register_autograd_kernel_indirection(self):
146
+ assert not self._registered_autograd_kernel_indirection
147
+ self._lib.impl(self._opname, autograd_kernel_indirection(weakref.proxy(self)), "Autograd")
148
+ self._registered_autograd_kernel_indirection = True
149
+
150
+ # Records the impl and the source location in self._impls
151
+ # Note that this doesn't cause torch.library to use the impl, that
152
+ # needs to be done in a separate self._lib.impl call.
153
+ def _register_impl(self, kind, func, stacklevel=2):
154
+ if self._has_impl(kind):
155
+ func_and_location = self._impls[kind]
156
+ assert func_and_location is not None # Pacify mypy
157
+ location = func_and_location.location
158
+ raise RuntimeError(
159
+ f"Attempting to register a {kind} impl for operator {self._qualname} "
160
+ f"that already has a {kind} impl registered from Python at "
161
+ f"{location}. This is not supported."
162
+ )
163
+ frame = inspect.getframeinfo(sys._getframe(stacklevel))
164
+ location = f"{frame.filename}:{frame.lineno}"
165
+ self._impls[kind] = FuncAndLocation(func, location)
166
+
167
+ def _get_impl(self, kind):
168
+ return self._impls[kind]
169
+
170
+ def _has_impl(self, kind):
171
+ return kind in self._impls
172
+
173
+ def _destroy(self):
174
+ # NOTE: [CustomOp lifetime]
175
+ # A CustomOp, once created, lives forever. The mechanism is that the
176
+ # global registry holds a reference to it. However, to make testing
177
+ # easier, we want to be able to destroy CustomOp objects.
178
+ # CustomOp._destroy does the job, though it leaves the CustomOp
179
+ # in a garbage state.
180
+ del self._lib
181
+
182
+ opnamespace = getattr(torch.ops, self._cpp_ns)
183
+ if hasattr(opnamespace, self._opname):
184
+ delattr(opnamespace, self._opname)
185
+
186
+ del global_registry[self._qualname]
187
+
188
+ def __repr__(self):
189
+ return f'<CustomOp(op="{self._qualname}")>'
190
+
191
+ def __call__(self, *args, **kwargs):
192
+ # Bypass torch.ops.* and directly do OperatorHandle::callBoxed.
193
+ # Using torch.ops.* is a bit of a pain (it can be slow and it has lifetime
194
+ # issues from caching operators that make testing CustomOp difficult).
195
+ result = _C._dispatch_call_boxed(self._ophandle, *args, **kwargs)
196
+ return result
197
+
198
+ def impl(
199
+ self, device_types: typing.Union[str, typing.Iterable[str]], _stacklevel=2,
200
+ ) -> typing.Callable:
201
+ r"""
202
+ This API is deprecated, please use torch.library.custom_op instead
203
+ """
204
+ if isinstance(device_types, str):
205
+ device_types = [device_types]
206
+ for device_type in device_types:
207
+ validate_device_type(device_type)
208
+
209
+ def inner(f):
210
+ for device_type in set(device_types):
211
+ self._check_doesnt_have_library_impl(device_type)
212
+ self._register_impl(device_type, f, stacklevel=_stacklevel)
213
+ dispatch_key = SUPPORTED_DEVICE_TYPE_TO_KEY[device_type]
214
+ library.impl(self._lib, self._opname, dispatch_key)(f)
215
+ return f
216
+
217
+ return inner
218
+
219
+ def _check_doesnt_have_library_impl(self, device_type):
220
+ if self._has_impl(device_type):
221
+ return
222
+ key = SUPPORTED_DEVICE_TYPE_TO_KEY[device_type]
223
+ if _C._dispatch_has_computed_kernel_for_dispatch_key(self._qualname, key):
224
+ raise RuntimeError(
225
+ f"impl(..., device_types={device_type}): the operator {self._qualname} "
226
+ f"already has an implementation for this device type via a "
227
+ f"pre-existing torch.library or TORCH_LIBRARY registration.")
228
+
229
+ def impl_factory(self) -> typing.Callable:
230
+ r"""Register an implementation for a factory function."""
231
+
232
+ def inner(f):
233
+ self._register_impl("factory", f)
234
+ library.impl(self._lib, self._opname, "BackendSelect")(f)
235
+ return f
236
+
237
+ return inner
238
+
239
+ def impl_abstract(self, _stacklevel=2) -> typing.Callable:
240
+ r"""
241
+ This API is deprecated, please use torch.library.custom_op instead
242
+ """
243
+
244
+ def inner(f):
245
+ self._check_doesnt_have_library_meta_impl()
246
+ self._register_impl("abstract", f, stacklevel=_stacklevel)
247
+ location = self._get_impl("abstract").location
248
+
249
+ qualname = self._qualname
250
+
251
+ # Handle DispatchKey.Meta registration
252
+ @functools.wraps(f)
253
+ def f_with_ctx(*args, **kwargs):
254
+ def error_on_ctx():
255
+ raise RuntimeError(
256
+ f"Attempted to call get_ctx() for the meta implementation "
257
+ f"for {qualname}."
258
+ f"You have presumably called get_ctx() because the operator "
259
+ f"has a data-dependent output shape; if so, there is no "
260
+ f"such meta implementation and this error is the correct "
261
+ f"behavior. Otherwise, please remove the call to get_ctx() "
262
+ f"in the implementation registered with impl_abstract "
263
+ f"at {location}"
264
+ )
265
+
266
+ with torch._library.fake_impl.set_ctx_getter(error_on_ctx):
267
+ return f(*args, **kwargs)
268
+
269
+ self._lib.impl(self._opname, f_with_ctx, "Meta")
270
+ return f
271
+
272
+ return inner
273
+
274
+ def _check_can_register_backward(self):
275
+ def error(detail):
276
+ raise RuntimeError(
277
+ f"Cannot use torch._custom_ops APIs to register backward "
278
+ f"formula for {detail}. Got operator "
279
+ f"{self._qualname} with schema: {schema}"
280
+ )
281
+
282
+ schema = self._schema
283
+ if schema.kind() != SchemaKind.functional:
284
+ error("non-functional operator")
285
+
286
+ rets = schema.returns
287
+ if not schema.returns:
288
+ error("operator with no returns")
289
+
290
+ assert len(rets) > 0
291
+ is_non_mutating_view = any(
292
+ r.annotation is not None and not r.annotation.is_write for r in rets
293
+ )
294
+ if is_non_mutating_view:
295
+ error("operator that returns views")
296
+
297
+ # We make assumptions about the schema's return types.
298
+ allowed_return_types = {
299
+ BaseType(BaseTy.int): "int",
300
+ BaseType(BaseTy.SymInt): "SymInt",
301
+ BaseType(BaseTy.bool): "bool",
302
+ BaseType(BaseTy.float): "float",
303
+ BaseType(BaseTy.Tensor): "Tensor",
304
+ ListType(BaseType(BaseTy.Tensor), None): "List[Tensor]",
305
+ }
306
+ for ret in schema.returns:
307
+ if ret.type in allowed_return_types:
308
+ continue
309
+ error(f"operator with return not in {list(allowed_return_types.values())} (got {ret.type})")
310
+
311
+ def _check_doesnt_have_library_autograd_impl(self):
312
+ if self._registered_autograd_kernel_indirection:
313
+ return
314
+
315
+ if _C._dispatch_has_kernel_for_dispatch_key(self._qualname, "CompositeImplicitAutograd"):
316
+ raise RuntimeError(
317
+ f"impl_backward/impl_save_for_backward: the operator {self._qualname} "
318
+ f"already has an implementation for this device type via a "
319
+ f"pre-existing registration to DispatchKey::CompositeImplicitAutograd."
320
+ f"CompositeImplicitAutograd operators do not need an autograd formula; "
321
+ f"instead, the operator will decompose into its constituents and those "
322
+ f"can have autograd formulas defined on them.")
323
+
324
+ # We can improve this by adding "all Autograd<BACKEND> keys", but
325
+ # realistically people will just be using this API for CPU/CUDA for now.
326
+ for key in ["Autograd", "AutogradCPU", "AutogradCUDA"]:
327
+ if _C._dispatch_has_kernel_for_dispatch_key(self._qualname, key):
328
+ raise RuntimeError(
329
+ f"impl_backward/impl_save_for_backward: "
330
+ f"the operator {self._qualname} already has an Autograd kernel "
331
+ f"registered to DispatchKey::{key} vi a pre-existing "
332
+ f"torch.library or TORCH_LIBRARY registration. Please either "
333
+ f"remove those registrations or don't use the torch._custom_ops APIs")
334
+
335
+ def _check_doesnt_have_library_meta_impl(self):
336
+ if self._has_impl("abstract"):
337
+ return
338
+
339
+ # If the user's operator is CompositeExplicitAutograd,
340
+ # allow them to impl_abstract. This is being pragmatic
341
+ # (existing custom ops may have CompositeExplicitAutograd
342
+ # registration that don't work with Meta kernels, so this
343
+ # gives them an escape hatch).
344
+ if (
345
+ _C._dispatch_has_kernel_for_dispatch_key(self._qualname, "CompositeExplicitAutograd")
346
+ and not _C._dispatch_has_kernel_for_dispatch_key(self._qualname, "Meta")
347
+ ):
348
+ return
349
+
350
+ # Otherwise, if the user's already has a Meta kernel or their
351
+ # op is CompositeImplicitAutograd or some other alias dispatch key,
352
+ # raise.
353
+
354
+ # Special case for CompositeImplicitAutograd
355
+ if _C._dispatch_has_kernel_for_dispatch_key(self._qualname, "CompositeImplicitAutograd"):
356
+ raise RuntimeError(
357
+ f"impl_abstract(...): the operator {self._qualname} "
358
+ f"already has an implementation for this device type via a "
359
+ f"pre-existing registration to DispatchKey::CompositeImplicitAutograd."
360
+ f"CompositeImplicitAutograd operators do not need an abstract impl; "
361
+ f"instead, the operator will decompose into its constituents and those "
362
+ f"can have abstract impls defined on them.")
363
+
364
+ if _C._dispatch_has_kernel_for_dispatch_key(self._qualname, "Meta"):
365
+ raise RuntimeError(
366
+ f"impl_abstract(...): the operator {self._qualname} "
367
+ f"already has an DispatchKey::Meta implementation via a "
368
+ f"pre-existing torch.library or TORCH_LIBRARY registration. "
369
+ f"Please either remove that registration or don't call impl_abstract.")
370
+
371
+ # NOTE ["backward", "save_for_backward", and "autograd"]
372
+ # As a part of the explicit autograd API, a user must provide us
373
+ # a "save_for_backward" function and a "backward" function.
374
+ # When both of these have been provided, then we automatically
375
+ # construct the "autograd" kernel.
376
+ def _register_autograd_kernel(self):
377
+ assert self._has_impl("backward")
378
+ assert self._has_impl("save_for_backward")
379
+ kernel = construct_autograd_kernel(
380
+ self._schema,
381
+ self._output_differentiability,
382
+ self,
383
+ get_op(self._qualname),
384
+ self._get_impl("save_for_backward").func,
385
+ self._get_impl("backward").func)
386
+ self._register_impl("autograd", kernel)
387
+
388
+ def impl_save_for_backward(self, _stacklevel=2):
389
+ r"""Register a function that tells us what to save for backward.
390
+
391
+ Please see impl_backward for more details.
392
+ """
393
+ def inner(f):
394
+ self._check_can_register_backward()
395
+ self._check_doesnt_have_library_autograd_impl()
396
+ if not self._registered_autograd_kernel_indirection:
397
+ self._register_autograd_kernel_indirection()
398
+ self._register_impl("save_for_backward", f, stacklevel=_stacklevel)
399
+ if self._has_impl("backward"):
400
+ self._register_autograd_kernel()
401
+ return inner
402
+
403
+ def impl_backward(self, output_differentiability=None, _stacklevel=2):
404
+ r"""
405
+ This API is deprecated, please use torch.library.custom_op instead
406
+ """
407
+ if output_differentiability is not None:
408
+ def yell():
409
+ raise RuntimeError(
410
+ f"impl_backward(output_differentiability): expected "
411
+ f"output_differentiability to be a list of bools with "
412
+ f"length equal to the number of outputs of this CustomOp "
413
+ f"got: {output_differentiability}")
414
+
415
+ if not isinstance(output_differentiability, list):
416
+ yell()
417
+ for diff in output_differentiability:
418
+ if not isinstance(diff, bool):
419
+ yell()
420
+ if len(self._schema.returns) != len(output_differentiability):
421
+ yell()
422
+
423
+ def inner(f):
424
+ self._check_can_register_backward()
425
+ self._check_doesnt_have_library_autograd_impl()
426
+ if not self._registered_autograd_kernel_indirection:
427
+ self._register_autograd_kernel_indirection()
428
+ self._register_impl("backward", f, stacklevel=_stacklevel)
429
+ self._output_differentiability = output_differentiability
430
+ if self._has_impl("save_for_backward"):
431
+ self._register_autograd_kernel()
432
+ return inner
433
+
434
+
435
+ @dataclasses.dataclass
436
+ class FuncAndLocation:
437
+ func: typing.Callable
438
+ location: str
439
+
440
+
441
+ def find_ophandle_or_throw(cpp_ns: str, operator_name: OperatorName):
442
+ overload_name = (
443
+ "" if operator_name.overload_name is None else operator_name.overload_name
444
+ )
445
+ return _C._dispatch_find_schema_or_throw(
446
+ f"{cpp_ns}::{str(operator_name.name)}", overload_name
447
+ )
448
+
449
+
450
+ def validate_namespace(ns: str) -> None:
451
+ if "." in ns:
452
+ raise ValueError(
453
+ f'custom_op(..., ns="{ns}"): expected ns to not contain any . (and be a '
454
+ f"valid variable name)"
455
+ )
456
+ if ns in RESERVED_NS:
457
+ raise ValueError(
458
+ f"custom_op(..., ns='{ns}'): '{ns}' is a reserved namespace, "
459
+ f"please choose something else. "
460
+ )
461
+
462
+ def validate_schema(schema: FunctionSchema) -> None:
463
+ if not torch._library.utils.is_functional_schema(schema):
464
+ raise ValueError(
465
+ f"custom_op only supports functional operators "
466
+ f"(ops that do not mutate any inputs, do not return "
467
+ f"views of the inputs, and has at least one return). "
468
+ f"Got the following non-functional schema: {schema}"
469
+ )
470
+
471
+ # For simplicity: don't allow self arguments
472
+ if schema.arguments.self_arg is not None:
473
+ raise ValueError(
474
+ f"custom_op does not support arguments named 'self'. Please "
475
+ f"rename your argument. Got: {schema}"
476
+ )
477
+
478
+
479
+ def parse_qualname(qualname: str) -> typing.Tuple[str, str]:
480
+ names = qualname.split("::", 1)
481
+ if len(names) != 2:
482
+ raise ValueError(f"Expected there to be a namespace in {qualname}, i.e. The "
483
+ f"operator name should look something like ns::foo")
484
+ if '.' in names[1]:
485
+ raise ValueError(f"The torch.custom_ops APIs do not handle overloads, "
486
+ f"i.e. operator names with '.' in them. "
487
+ f"Please name your operator something like ns::foo. "
488
+ f"Got: {qualname}")
489
+ return names[0], names[1]
490
+
491
+
492
+ def validate_device_type(device_type: str) -> None:
493
+ if device_type not in SUPPORTED_DEVICE_TYPE_TO_KEY:
494
+ raise ValueError(
495
+ f"CustomOp.impl(device_types=[{device_type}, ...]): we only support device_type "
496
+ f"in {SUPPORTED_DEVICE_TYPE_TO_KEY.keys()}."
497
+ )
498
+
499
+
500
+ def supported_param(param: inspect.Parameter) -> bool:
501
+ return param.kind in (
502
+ inspect.Parameter.POSITIONAL_OR_KEYWORD,
503
+ inspect.Parameter.KEYWORD_ONLY,
504
+ )
505
+
506
+
507
+ def validate_function_matches_schema(
508
+ schema: FunctionSchema, func: typing.Callable
509
+ ) -> None:
510
+ sig = inspect.signature(func)
511
+
512
+ if not all(supported_param(p) for _, p in sig.parameters.items()):
513
+ raise ValueError(
514
+ f"custom_op(..., manual_schema)(func): positional-only args, "
515
+ f"varargs, and kwargs are not supported. Please rewrite `func` "
516
+ f"to not have them. Got `func` with signature: {sig}"
517
+ )
518
+
519
+ if (
520
+ any(
521
+ p.annotation is not inspect.Parameter.empty
522
+ for _, p in sig.parameters.items()
523
+ )
524
+ or sig.return_annotation is not inspect.Signature.empty
525
+ ):
526
+ raise ValueError(
527
+ f"custom_op(..., manual_schema)(func): When passing in a manual "
528
+ f"schema, we expect `func` to have no type annotations to avoid "
529
+ f"ambiguity. Got `func` with signature: {sig}"
530
+ )
531
+
532
+ positional = [
533
+ (name, param)
534
+ for name, param in sig.parameters.items()
535
+ if param.kind == inspect.Parameter.POSITIONAL_OR_KEYWORD
536
+ ]
537
+ kwargonly = [
538
+ (name, param)
539
+ for name, param in sig.parameters.items()
540
+ if param.kind == inspect.Parameter.KEYWORD_ONLY
541
+ ]
542
+
543
+ def error():
544
+ raise ValueError(
545
+ f"custom_op(..., manual_schema)(func): When passing in a manual "
546
+ f"schema, we expect `func`'s signature to match `manual_schema` "
547
+ f"(aside from type annotations). "
548
+ f"func's signature: {sig}, manual_schema: {schema}"
549
+ )
550
+
551
+ def error_default_args():
552
+ raise ValueError(
553
+ f"custom_op(..., manual_schema)(func): "
554
+ f"neither func nor manual_schema should have default "
555
+ f"arguments. Got "
556
+ f"func's signature: {sig}, manual_schema: {schema}"
557
+ )
558
+
559
+ def compare(sig_args, schema_args):
560
+ if len(sig_args) != len(schema_args):
561
+ error()
562
+ for (name, param), arg in zip(sig_args, schema_args):
563
+ if name != arg.name:
564
+ error()
565
+ if param.default is not inspect.Parameter.empty or arg.default is not None:
566
+ error_default_args()
567
+
568
+ compare(positional, schema.arguments.flat_positional)
569
+ compare(kwargonly, schema.arguments.flat_kwarg_only)
570
+
571
+
572
+ def report_error_callback(custom_op: typing.Any, key: str) -> None:
573
+ if key == "Undefined":
574
+ raise NotImplementedError(
575
+ f"{custom_op}: There were no Tensor inputs to this operator "
576
+ f"(e.g. you passed an empty list of Tensors). If your operator is a "
577
+ f"factory function (that is, it takes no Tensors and constructs "
578
+ f"a new one), then please use CustomOp.impl_factory to register "
579
+ f"an implementation for it"
580
+ )
581
+ if key == "Meta":
582
+ raise NotImplementedError(
583
+ f"{custom_op}: when running with device='Meta' tensors: there is no "
584
+ f"abstract impl registered for this CustomOp. Please register one via "
585
+ f"CustomOp.impl_abstract to get this CustomOp to work with Meta tensors"
586
+ )
587
+ if key in ("CPU", "CUDA"):
588
+ device = key.lower()
589
+ raise NotImplementedError(
590
+ f"{custom_op}: when running with device='{device}' tensors: there is no "
591
+ f"{device} impl registered for this CustomOp. Please register one via "
592
+ f"CustomOp.impl(device_type='{device}')"
593
+ )
594
+ raise NotImplementedError(
595
+ f"{custom_op}: No implementation for dispatch key {key}. It is likely "
596
+ f"that we have not added this functionality yet, please either open an "
597
+ f"issue or if you're feeling adventurous, use the low-level "
598
+ f"torch.library API"
599
+ )
600
+
601
+
602
+ def custom_op_from_existing(op):
603
+ ns = op.namespace
604
+ lib = torch.library.Library(ns, "FRAGMENT")
605
+ name = op.name().split("::")[-1]
606
+ schema_str = str(op._schema)
607
+ # CustomOp expects the schema string without the namespace
608
+ schema_str = schema_str.split("::")[-1]
609
+ schema = FunctionSchema.parse(schema_str)
610
+ return CustomOp(lib, ns, schema, name, op, _private_access=True)
611
+
612
+
613
+ def get_op(qualname):
614
+ def error_not_found():
615
+ raise ValueError(
616
+ f"Could not find the operator {qualname}. Please make sure you have "
617
+ f"already registered the operator and (if registered from C++) "
618
+ f"loaded it via torch.ops.load_library.")
619
+
620
+ ns, name = parse_qualname(qualname)
621
+ if not hasattr(torch.ops, ns):
622
+ error_not_found()
623
+ opnamespace = getattr(torch.ops, ns)
624
+ if not hasattr(opnamespace, name):
625
+ error_not_found()
626
+ packet = getattr(opnamespace, name)
627
+ if not hasattr(packet, 'default'):
628
+ error_not_found()
629
+ return packet.default
630
+
631
+
632
+ def _find_custom_op(qualname, also_check_torch_library=False):
633
+ if qualname in global_registry:
634
+ return global_registry[qualname]
635
+ if not also_check_torch_library:
636
+ raise RuntimeError(
637
+ f'Could not find custom op "{qualname}". Did you register it via '
638
+ f"the torch._custom_ops API?")
639
+ overload = get_op(qualname)
640
+ result = custom_op_from_existing(overload)
641
+ return result
642
+
643
+
644
+ def get_abstract_impl(qualname):
645
+ if qualname not in torch._custom_op.impl.global_registry:
646
+ return None
647
+ custom_op = torch._custom_op.impl.global_registry[qualname]
648
+ if custom_op is None:
649
+ return None
650
+ if not custom_op._has_impl("abstract"):
651
+ return None
652
+ return custom_op._get_impl("abstract").func
653
+
654
+
655
+ def _custom_op_with_schema(qualname, schema, needs_fixed_stride_order=True):
656
+ ns, name = qualname.split("::")
657
+ schema_str = f"{name}{schema}"
658
+ function_schema = FunctionSchema.parse(schema_str)
659
+ validate_schema(function_schema)
660
+ tags = [torch._C.Tag.needs_fixed_stride_order] if needs_fixed_stride_order else []
661
+ lib = library.Library(ns, "FRAGMENT")
662
+ lib.define(schema_str, tags=tags)
663
+ ophandle = find_ophandle_or_throw(ns, function_schema.name)
664
+ result = CustomOp(lib, ns, function_schema, name, ophandle, _private_access=True)
665
+ result._register_autograd_kernel_indirection()
666
+
667
+ torch._C._dispatch_set_report_error_callback(
668
+ ophandle, functools.partial(report_error_callback, weakref.proxy(result))
669
+ )
670
+ return get_op(qualname)
lib/python3.12/site-packages/torch/amp/__init__.py ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ from .autocast_mode import (
2
+ _enter_autocast,
3
+ _exit_autocast,
4
+ autocast,
5
+ custom_bwd,
6
+ custom_fwd,
7
+ is_autocast_available,
8
+ )
9
+ from .grad_scaler import GradScaler
lib/python3.12/site-packages/torch/amp/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (418 Bytes). View file
 
lib/python3.12/site-packages/torch/amp/__pycache__/autocast_mode.cpython-312.pyc ADDED
Binary file (27 kB). View file
 
lib/python3.12/site-packages/torch/amp/__pycache__/grad_scaler.cpython-312.pyc ADDED
Binary file (32 kB). View file
 
lib/python3.12/site-packages/torch/amp/autocast_mode.py ADDED
@@ -0,0 +1,551 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # mypy: allow-untyped-defs
2
+ import collections
3
+ import functools
4
+ import warnings
5
+ from typing import Any, Optional
6
+
7
+ import torch
8
+ from torch.types import _dtype
9
+
10
+
11
+ try:
12
+ import numpy as np
13
+
14
+ HAS_NUMPY = True
15
+ except ModuleNotFoundError:
16
+ HAS_NUMPY = False
17
+ np = None # type: ignore[assignment]
18
+
19
+ __all__ = [
20
+ "autocast_decorator",
21
+ "autocast",
22
+ "is_autocast_available",
23
+ "custom_fwd",
24
+ "custom_bwd",
25
+ ]
26
+
27
+
28
+ def is_autocast_available(device_type: str) -> bool:
29
+ r"""
30
+ Return a bool indicating if autocast is available on :attr:`device_type`.
31
+
32
+ Args:
33
+ device_type(str): Device type to use. Possible values are: 'cuda', 'cpu', 'xpu' and so on.
34
+ The type is the same as the `type` attribute of a :class:`torch.device`.
35
+ Thus, you may obtain the device type of a tensor using `Tensor.device.type`.
36
+ """
37
+ return torch._C._is_autocast_available(device_type)
38
+
39
+
40
+ def autocast_decorator(autocast_instance, func):
41
+ @functools.wraps(func)
42
+ def decorate_autocast(*args, **kwargs):
43
+ with autocast_instance:
44
+ return func(*args, **kwargs)
45
+
46
+ decorate_autocast.__script_unsupported = "@autocast() decorator is not supported in script mode" # type: ignore[attr-defined]
47
+ return decorate_autocast
48
+
49
+
50
+ class autocast:
51
+ r"""
52
+ Instances of :class:`autocast` serve as context managers or decorators that
53
+ allow regions of your script to run in mixed precision.
54
+
55
+ In these regions, ops run in an op-specific dtype chosen by autocast
56
+ to improve performance while maintaining accuracy.
57
+ See the :ref:`Autocast Op Reference<autocast-op-reference>` for details.
58
+
59
+ When entering an autocast-enabled region, Tensors may be any type.
60
+ You should not call ``half()`` or ``bfloat16()`` on your model(s) or inputs when using autocasting.
61
+
62
+ :class:`autocast` should wrap only the forward pass(es) of your network, including the loss
63
+ computation(s). Backward passes under autocast are not recommended.
64
+ Backward ops run in the same type that autocast used for corresponding forward ops.
65
+
66
+ Example for CUDA Devices::
67
+
68
+ # Creates model and optimizer in default precision
69
+ model = Net().cuda()
70
+ optimizer = optim.SGD(model.parameters(), ...)
71
+
72
+ for input, target in data:
73
+ optimizer.zero_grad()
74
+
75
+ # Enables autocasting for the forward pass (model + loss)
76
+ with torch.autocast(device_type="cuda"):
77
+ output = model(input)
78
+ loss = loss_fn(output, target)
79
+
80
+ # Exits the context manager before backward()
81
+ loss.backward()
82
+ optimizer.step()
83
+
84
+ See the :ref:`Automatic Mixed Precision examples<amp-examples>` for usage (along with gradient scaling)
85
+ in more complex scenarios (e.g., gradient penalty, multiple models/losses, custom autograd functions).
86
+
87
+ :class:`autocast` can also be used as a decorator, e.g., on the ``forward`` method of your model::
88
+
89
+ class AutocastModel(nn.Module):
90
+ ...
91
+ @torch.autocast(device_type="cuda")
92
+ def forward(self, input):
93
+ ...
94
+
95
+ Floating-point Tensors produced in an autocast-enabled region may be ``float16``.
96
+ After returning to an autocast-disabled region, using them with floating-point
97
+ Tensors of different dtypes may cause type mismatch errors. If so, cast the Tensor(s)
98
+ produced in the autocast region back to ``float32`` (or other dtype if desired).
99
+ If a Tensor from the autocast region is already ``float32``, the cast is a no-op,
100
+ and incurs no additional overhead.
101
+ CUDA Example::
102
+
103
+ # Creates some tensors in default dtype (here assumed to be float32)
104
+ a_float32 = torch.rand((8, 8), device="cuda")
105
+ b_float32 = torch.rand((8, 8), device="cuda")
106
+ c_float32 = torch.rand((8, 8), device="cuda")
107
+ d_float32 = torch.rand((8, 8), device="cuda")
108
+
109
+ with torch.autocast(device_type="cuda"):
110
+ # torch.mm is on autocast's list of ops that should run in float16.
111
+ # Inputs are float32, but the op runs in float16 and produces float16 output.
112
+ # No manual casts are required.
113
+ e_float16 = torch.mm(a_float32, b_float32)
114
+ # Also handles mixed input types
115
+ f_float16 = torch.mm(d_float32, e_float16)
116
+
117
+ # After exiting autocast, calls f_float16.float() to use with d_float32
118
+ g_float32 = torch.mm(d_float32, f_float16.float())
119
+
120
+ CPU Training Example::
121
+
122
+ # Creates model and optimizer in default precision
123
+ model = Net()
124
+ optimizer = optim.SGD(model.parameters(), ...)
125
+
126
+ for epoch in epochs:
127
+ for input, target in data:
128
+ optimizer.zero_grad()
129
+
130
+ # Runs the forward pass with autocasting.
131
+ with torch.autocast(device_type="cpu", dtype=torch.bfloat16):
132
+ output = model(input)
133
+ loss = loss_fn(output, target)
134
+
135
+ loss.backward()
136
+ optimizer.step()
137
+
138
+
139
+ CPU Inference Example::
140
+
141
+ # Creates model in default precision
142
+ model = Net().eval()
143
+
144
+ with torch.autocast(device_type="cpu", dtype=torch.bfloat16):
145
+ for input in data:
146
+ # Runs the forward pass with autocasting.
147
+ output = model(input)
148
+
149
+ CPU Inference Example with Jit Trace::
150
+
151
+ class TestModel(nn.Module):
152
+ def __init__(self, input_size, num_classes):
153
+ super().__init__()
154
+ self.fc1 = nn.Linear(input_size, num_classes)
155
+ def forward(self, x):
156
+ return self.fc1(x)
157
+
158
+ input_size = 2
159
+ num_classes = 2
160
+ model = TestModel(input_size, num_classes).eval()
161
+
162
+ # For now, we suggest to disable the Jit Autocast Pass,
163
+ # As the issue: https://github.com/pytorch/pytorch/issues/75956
164
+ torch._C._jit_set_autocast_mode(False)
165
+
166
+ with torch.cpu.amp.autocast(cache_enabled=False):
167
+ model = torch.jit.trace(model, torch.randn(1, input_size))
168
+ model = torch.jit.freeze(model)
169
+ # Models Run
170
+ for _ in range(3):
171
+ model(torch.randn(1, input_size))
172
+
173
+ Type mismatch errors *in* an autocast-enabled region are a bug; if this is what you observe,
174
+ please file an issue.
175
+
176
+ ``autocast(enabled=False)`` subregions can be nested in autocast-enabled regions.
177
+ Locally disabling autocast can be useful, for example, if you want to force a subregion
178
+ to run in a particular ``dtype``. Disabling autocast gives you explicit control over
179
+ the execution type. In the subregion, inputs from the surrounding region
180
+ should be cast to ``dtype`` before use::
181
+
182
+ # Creates some tensors in default dtype (here assumed to be float32)
183
+ a_float32 = torch.rand((8, 8), device="cuda")
184
+ b_float32 = torch.rand((8, 8), device="cuda")
185
+ c_float32 = torch.rand((8, 8), device="cuda")
186
+ d_float32 = torch.rand((8, 8), device="cuda")
187
+
188
+ with torch.autocast(device_type="cuda"):
189
+ e_float16 = torch.mm(a_float32, b_float32)
190
+ with torch.autocast(device_type="cuda", enabled=False):
191
+ # Calls e_float16.float() to ensure float32 execution
192
+ # (necessary because e_float16 was created in an autocasted region)
193
+ f_float32 = torch.mm(c_float32, e_float16.float())
194
+
195
+ # No manual casts are required when re-entering the autocast-enabled region.
196
+ # torch.mm again runs in float16 and produces float16 output, regardless of input types.
197
+ g_float16 = torch.mm(d_float32, f_float32)
198
+
199
+ The autocast state is thread-local. If you want it enabled in a new thread, the context manager or decorator
200
+ must be invoked in that thread. This affects :class:`torch.nn.DataParallel` and
201
+ :class:`torch.nn.parallel.DistributedDataParallel` when used with more than one GPU per process
202
+ (see :ref:`Working with Multiple GPUs<amp-multigpu>`).
203
+
204
+ Args:
205
+ device_type(str, required): Device type to use. Possible values are: 'cuda', 'cpu', 'xpu' and 'hpu'.
206
+ The type is the same as the `type` attribute of a :class:`torch.device`.
207
+ Thus, you may obtain the device type of a tensor using `Tensor.device.type`.
208
+ enabled(bool, optional): Whether autocasting should be enabled in the region.
209
+ Default: ``True``
210
+ dtype(torch_dtype, optional): Data type for ops run in autocast. It uses the default value
211
+ (``torch.float16`` for CUDA and ``torch.bfloat16`` for CPU), given by
212
+ :func:`~torch.get_autocast_dtype`, if :attr:`dtype` is ``None``.
213
+ Default: ``None``
214
+ cache_enabled(bool, optional): Whether the weight cache inside autocast should be enabled.
215
+ Default: ``True``
216
+ """
217
+
218
+ def __init__(
219
+ self,
220
+ device_type: str,
221
+ dtype: Optional[_dtype] = None,
222
+ enabled: bool = True,
223
+ cache_enabled: Optional[bool] = None,
224
+ ):
225
+ if not isinstance(device_type, str):
226
+ raise ValueError(
227
+ f"Expected `device_type` of type `str`, got: `{type(device_type)}`"
228
+ )
229
+ if dtype is None:
230
+ dtype = torch.get_autocast_dtype(device_type)
231
+ if torch._jit_internal.is_scripting():
232
+ self._enabled = enabled
233
+ self.device = device_type
234
+ self.fast_dtype = dtype
235
+ assert dtype is not None
236
+ return
237
+ self.device = device_type
238
+ if not is_autocast_available(self.device):
239
+ raise RuntimeError(
240
+ f"User specified an unsupported autocast device_type '{self.device}'"
241
+ )
242
+ self.custom_backend_name = torch._C._get_privateuse1_backend_name()
243
+ self.fast_dtype = torch.get_autocast_dtype(self.device)
244
+ if self.device == self.custom_backend_name:
245
+ necessary_funcs = [
246
+ "get_amp_supported_dtype",
247
+ ]
248
+ message = f"Tried to use AMP with the `{self.custom_backend_name}` backend, but the backend has not "
249
+ message += "registered a module or the module miss some necessary funcs. The backend should register "
250
+ message += "a module by `torch._register_device_module`, and the module must have these funcs: \n"
251
+ message += "`get_amp_supported_dtype() -> List[torch.dtype]`. \n"
252
+
253
+ assert hasattr(torch, self.custom_backend_name), message
254
+ self.custom_device_mod = getattr(torch, self.custom_backend_name)
255
+ for func in necessary_funcs:
256
+ assert hasattr(self.custom_device_mod, func), (
257
+ message + f"But the func `{func}` is missing. \n"
258
+ )
259
+
260
+ self._cache_enabled = torch.is_autocast_cache_enabled()
261
+ if (
262
+ enabled
263
+ and torch.cuda.amp.common.amp_definitely_not_available()
264
+ and self.device == "cuda"
265
+ ):
266
+ warnings.warn(
267
+ "User provided device_type of 'cuda', but CUDA is not available. Disabling"
268
+ )
269
+ enabled = False
270
+ if dtype is not None:
271
+ self.fast_dtype = dtype
272
+ if cache_enabled is not None:
273
+ self._cache_enabled = cache_enabled
274
+
275
+ if self.device == "cpu":
276
+ supported_dtype = [torch.bfloat16, torch.float16]
277
+ if self.fast_dtype not in supported_dtype and enabled:
278
+ error_message = "In CPU autocast, but the target dtype is not supported. Disabling autocast.\n"
279
+ error_message += "CPU Autocast only supports dtype of "
280
+ error_message += (
281
+ ", ".join(str(dtype) for dtype in supported_dtype) + " currently."
282
+ )
283
+ warnings.warn(error_message)
284
+ enabled = False
285
+ elif self.device == "xpu":
286
+ supported_dtype = [torch.bfloat16, torch.float16]
287
+ if self.fast_dtype not in supported_dtype:
288
+ error_message = "In XPU autocast, but the target dtype is not supported. Disabling autocast.\n"
289
+ error_message += "XPU Autocast only supports dtypes of torch.bfloat16 and torch.float16 currently."
290
+ warnings.warn(error_message)
291
+ enabled = False
292
+ elif self.device == "ipu":
293
+ supported_dtypes = [torch.bfloat16, torch.float16]
294
+ if self.fast_dtype not in supported_dtypes:
295
+ error_message = "In IPU autocast, but the target dtype is not supported. Disabling autocast.\n"
296
+ error_message += "IPU Autocast only supports dtypes of torch.bfloat16 and torch.float16 currently."
297
+ warnings.warn(error_message)
298
+ enabled = False
299
+ elif self.device == "hpu":
300
+ supported_dtype = [torch.bfloat16, torch.float16]
301
+ if self.fast_dtype not in supported_dtype:
302
+ error_message = "In HPU autocast, but the target dtype is not supported. Disabling autocast.\n"
303
+ error_message += "HPU Autocast only supports dtypes of torch.bfloat16 and torch.float16 currently."
304
+ warnings.warn(error_message)
305
+ enabled = False
306
+ elif self.device == self.custom_backend_name:
307
+ supported_dtype = self.custom_device_mod.get_amp_supported_dtype()
308
+ if self.fast_dtype not in supported_dtype:
309
+ error_message = f"In {self.custom_backend_name} autocast, but the target dtype is not supported. "
310
+ error_message += f"Disabling autocast.\n {self.custom_backend_name} Autocast only supports dtypes of "
311
+ error_message += (
312
+ ", ".join(str(dtype) for dtype in supported_dtype) + " currently."
313
+ )
314
+ warnings.warn(error_message)
315
+ enabled = False
316
+ elif self.device == "cuda":
317
+ if (
318
+ enabled
319
+ and self.fast_dtype == torch.bfloat16
320
+ and not torch.cuda.is_bf16_supported()
321
+ ):
322
+ raise RuntimeError(
323
+ "Current CUDA Device does not support bfloat16. Please switch dtype to float16."
324
+ )
325
+ elif self.device == "mps":
326
+ supported_dtype = [torch.bfloat16, torch.float16]
327
+ if self.fast_dtype not in supported_dtype:
328
+ error_message = (
329
+ "In MPS autocast, but the target dtype is not supported. Disabling autocast.\n"
330
+ "MPS Autocast only supports dtype of torch.bfloat16 and torch.float16 currently."
331
+ )
332
+ warnings.warn(error_message)
333
+ enabled = False
334
+ elif self.fast_dtype == torch.bfloat16:
335
+ if not torch.backends.mps.is_macos_or_newer(14, 0):
336
+ error_message = (
337
+ "In MPS autocast, but the target dtype torch.bfloat16 is not supported "
338
+ "on macOS versions below 14. Disabling autocast."
339
+ )
340
+ warnings.warn(error_message)
341
+ enabled = False
342
+ elif self.device == "xla":
343
+ supported_dtype = [torch.float16, torch.bfloat16]
344
+ if self.fast_dtype not in supported_dtype:
345
+ error_message = "In XLA autocast, but the target dtype is not supported. Disabling autocast.\n"
346
+ error_message += (
347
+ "XLA Autocast only supports dtype of torch.bfloat16 currently."
348
+ )
349
+ warnings.warn(error_message)
350
+ enabled = False
351
+ self._enabled = enabled
352
+
353
+ def __enter__(self):
354
+ if torch._jit_internal.is_scripting():
355
+ assert self.fast_dtype is not None
356
+ return self
357
+
358
+ self.prev_cache_enabled = torch.is_autocast_cache_enabled()
359
+ self.prev = torch.is_autocast_enabled(self.device)
360
+ self.prev_fastdtype = torch.get_autocast_dtype(self.device)
361
+ torch.set_autocast_enabled(self.device, self._enabled)
362
+ torch.set_autocast_dtype(self.device, self.fast_dtype) # type: ignore[arg-type]
363
+ torch.autocast_increment_nesting()
364
+ torch.set_autocast_cache_enabled(self._cache_enabled)
365
+
366
+ # only dispatch to PreDispatchTorchFunctionMode to avoid exposing this
367
+ # API to other functional modes. We only expose to PreDispatchTorchFunctionMode
368
+ # for preserving autocast in torch.export.export.
369
+ if torch._C._is_torch_function_mode_enabled():
370
+ stacks = torch.overrides._get_current_function_mode_stack()
371
+ for mode in stacks:
372
+ if isinstance(
373
+ mode,
374
+ torch.fx.experimental.proxy_tensor.PreDispatchTorchFunctionMode,
375
+ ):
376
+ args = (
377
+ self.device,
378
+ self.fast_dtype,
379
+ self._enabled,
380
+ self._cache_enabled,
381
+ )
382
+ return mode.__torch_function__(torch.amp._enter_autocast, (), args)
383
+
384
+ def __exit__(self, exc_type: Any, exc_val: Any, exc_tb: Any): # type: ignore[override]
385
+ if torch._jit_internal.is_scripting():
386
+ return
387
+
388
+ # Drop the cache when we exit to a nesting level that's outside any instance of autocast.
389
+ if torch.autocast_decrement_nesting() == 0:
390
+ torch.clear_autocast_cache()
391
+ torch.set_autocast_enabled(self.device, self.prev)
392
+ torch.set_autocast_dtype(self.device, self.prev_fastdtype)
393
+ torch.set_autocast_cache_enabled(self.prev_cache_enabled)
394
+
395
+ # only dispatch to PreDispatchTorchFunctionMode to avoid exposing this
396
+ # API to other functional modes. We only expose to PreDispatchTorchFunctionMode
397
+ # for preserving autocast in torch.export.export.
398
+ if torch._C._is_torch_function_mode_enabled():
399
+ stacks = torch.overrides._get_current_function_mode_stack()
400
+ for mode in stacks:
401
+ if isinstance(
402
+ mode,
403
+ torch.fx.experimental.proxy_tensor.PreDispatchTorchFunctionMode,
404
+ ):
405
+ return mode.__torch_function__(torch.amp._exit_autocast, (), ())
406
+ return False
407
+
408
+ def __call__(self, func):
409
+ if torch._jit_internal.is_scripting():
410
+ return func
411
+ return autocast_decorator(self, func)
412
+
413
+
414
+ # These functions aren't meant for public usage.
415
+ # They are what we trace into a graph during pre_dispatch tracing
416
+ # when we encounter an autocast context manager.
417
+ def _enter_autocast(*vals):
418
+ # For pre-dispatch tracing, if a TorchFunction mode is active, we'll want to trace this into a graph.
419
+ if torch._C._is_torch_function_mode_enabled():
420
+ return torch.overrides.handle_torch_function(
421
+ torch.amp._enter_autocast, [], *vals
422
+ )
423
+ mode = torch.amp.autocast(*vals)
424
+ mode.__enter__()
425
+ return mode
426
+
427
+
428
+ def _exit_autocast(mode):
429
+ if torch._C._is_torch_function_mode_enabled():
430
+ return torch.overrides.handle_torch_function(torch.amp._exit_autocast, [], mode)
431
+ mode.__exit__(None, None, None)
432
+
433
+
434
+ # Casts Tensors and containers of Tensors. Special-cases passthroughs for strings and np.ndarrays, which
435
+ # may be falsely detected as "Iterables."
436
+ def _cast(value, device_type: str, dtype: _dtype):
437
+ if isinstance(value, torch.Tensor):
438
+ is_eligible = (
439
+ value.is_floating_point()
440
+ and value.device.type == device_type
441
+ and (value.dtype is not torch.float64)
442
+ )
443
+ return value.to(dtype) if is_eligible else value
444
+ elif isinstance(value, (str, bytes)):
445
+ return value
446
+ elif HAS_NUMPY and isinstance(value, np.ndarray):
447
+ return value
448
+ elif isinstance(value, collections.abc.Mapping):
449
+ return {
450
+ _cast(k, device_type, dtype): _cast(v, device_type, dtype)
451
+ for k, v in value.items()
452
+ }
453
+ elif isinstance(value, collections.abc.Iterable):
454
+ iterable = (_cast(v, device_type, dtype) for v in value)
455
+ if isinstance(value, (list, tuple)):
456
+ return type(value)(iterable)
457
+ else:
458
+ return iterable
459
+ else:
460
+ return value
461
+
462
+
463
+ def custom_fwd(
464
+ fwd=None,
465
+ *,
466
+ device_type: str,
467
+ cast_inputs: Optional[_dtype] = None,
468
+ ):
469
+ """
470
+ Create a helper decorator for ``forward`` methods of custom autograd functions.
471
+
472
+ Autograd functions are subclasses of :class:`torch.autograd.Function`.
473
+ See the :ref:`example page<amp-custom-examples>` for more detail.
474
+
475
+ Args:
476
+ device_type(str): Device type to use. 'cuda', 'cpu', 'xpu' and so on.
477
+ The type is the same as the `type` attribute of a :class:`torch.device`.
478
+ Thus, you may obtain the device type of a tensor using `Tensor.device.type`.
479
+ cast_inputs (:class:`torch.dtype` or None, optional, default=None): If not ``None``,
480
+ when ``forward`` runs in an autocast-enabled region, casts incoming
481
+ floating-point Tensors to the target dtype (non-floating-point Tensors are not affected),
482
+ then executes ``forward`` with autocast disabled.
483
+ If ``None``, ``forward``'s internal ops execute with the current autocast state.
484
+
485
+ .. note::
486
+ If the decorated ``forward`` is called outside an autocast-enabled region,
487
+ :func:`custom_fwd<custom_fwd>` is a no-op and ``cast_inputs`` has no effect.
488
+ """
489
+ if not isinstance(device_type, str):
490
+ raise ValueError(
491
+ f"Expected `device_type` of type `str`, got: `{type(device_type)}`"
492
+ )
493
+ if fwd is None:
494
+ return functools.partial(
495
+ custom_fwd, device_type=device_type, cast_inputs=cast_inputs
496
+ )
497
+
498
+ @functools.wraps(fwd)
499
+ def decorate_fwd(*args, **kwargs):
500
+ args[0]._dtype = torch.get_autocast_dtype(device_type)
501
+ if cast_inputs is None:
502
+ args[0]._fwd_used_autocast = torch.is_autocast_enabled(device_type)
503
+ return fwd(*args, **kwargs)
504
+ else:
505
+ autocast_context = torch.is_autocast_enabled(device_type)
506
+ args[0]._fwd_used_autocast = False
507
+ if autocast_context:
508
+ with autocast(device_type=device_type, enabled=False):
509
+ return fwd(
510
+ *_cast(args, device_type, cast_inputs),
511
+ **_cast(kwargs, device_type, cast_inputs),
512
+ )
513
+ else:
514
+ return fwd(*args, **kwargs)
515
+
516
+ return decorate_fwd
517
+
518
+
519
+ # Autograd ensures incoming gradients are the same type as forward outputs. Allowing a separate
520
+ # cast_inputs argument on custom_bwd is unnecessary and could cause errors if it doesn't match
521
+ # cast_inputs supplied to custom_fwd.
522
+ def custom_bwd(bwd=None, *, device_type: str):
523
+ """Create a helper decorator for backward methods of custom autograd functions.
524
+
525
+ Autograd functions are subclasses of :class:`torch.autograd.Function`.
526
+ Ensures that ``backward`` executes with the same autocast state as ``forward``.
527
+ See the :ref:`example page<amp-custom-examples>` for more detail.
528
+
529
+ Args:
530
+ device_type(str): Device type to use. 'cuda', 'cpu', 'xpu' and so on.
531
+ The type is the same as the `type` attribute of a :class:`torch.device`.
532
+ Thus, you may obtain the device type of a tensor using `Tensor.device.type`.
533
+ """
534
+
535
+ if not isinstance(device_type, str):
536
+ raise ValueError(
537
+ f"Expected `device_type` of type `str`, got: `{type(device_type)}`"
538
+ )
539
+ if bwd is None:
540
+ return functools.partial(custom_bwd, device_type=device_type)
541
+
542
+ @functools.wraps(bwd)
543
+ def decorate_bwd(*args, **kwargs):
544
+ with autocast(
545
+ device_type=device_type,
546
+ enabled=args[0]._fwd_used_autocast,
547
+ dtype=args[0]._dtype,
548
+ ):
549
+ return bwd(*args, **kwargs)
550
+
551
+ return decorate_bwd
lib/python3.12/site-packages/torch/amp/grad_scaler.py ADDED
@@ -0,0 +1,685 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # mypy: allow-untyped-defs
2
+ from __future__ import annotations
3
+
4
+ import inspect
5
+ import warnings
6
+ from collections import abc, defaultdict
7
+ from enum import Enum
8
+ from typing import Any, cast, Dict, Iterable, List, Optional, overload, Tuple, Union
9
+
10
+ import torch
11
+
12
+
13
+ __all__ = ["OptState", "GradScaler"]
14
+
15
+
16
+ class _MultiDeviceReplicator:
17
+ """Lazily serves copies of a tensor to requested devices.
18
+
19
+ Copies are cached per-device.
20
+ """
21
+
22
+ def __init__(self, master_tensor: torch.Tensor) -> None:
23
+ self.master = master_tensor
24
+ self._per_device_tensors: Dict[torch.device, torch.Tensor] = {}
25
+
26
+ def get(self, device: torch.device) -> torch.Tensor:
27
+ retval = self._per_device_tensors.get(device, None)
28
+ if retval is None:
29
+ retval = self.master.to(device=device, non_blocking=True, copy=True)
30
+ self._per_device_tensors[device] = retval
31
+ return retval
32
+
33
+
34
+ # Defines default_factory for GradScaler's _per_optimizer_states defaultdict,
35
+ # as well as associated "enum" values. Prefers defining these at top level because
36
+ # - Lambdas can't be pickled, so we don't want to supply a lambda as the factory.
37
+ # - Defining READY, UNSCALED, STEPPED and _refresh_per_optimizer_state within GradScaler
38
+ # causes a circular reference, which we'd rather avoid.
39
+ class OptState(Enum):
40
+ READY = 0
41
+ UNSCALED = 1
42
+ STEPPED = 2
43
+
44
+
45
+ def _refresh_per_optimizer_state() -> Dict[str, Any]:
46
+ return {"stage": OptState.READY, "found_inf_per_device": {}}
47
+
48
+
49
+ class GradScaler:
50
+ """An instance ``scaler`` of :class:`GradScaler`.
51
+
52
+ Helps perform the steps of gradient scaling
53
+ conveniently.
54
+
55
+ * ``scaler.scale(loss)`` multiplies a given loss by ``scaler``'s current scale factor.
56
+ * ``scaler.step(optimizer)`` safely unscales gradients and calls ``optimizer.step()``.
57
+ * ``scaler.update()`` updates ``scaler``'s scale factor.
58
+
59
+ Example::
60
+
61
+ # Creates a GradScaler once at the beginning of training.
62
+ scaler = GradScaler()
63
+
64
+ for epoch in epochs:
65
+ for input, target in data:
66
+ optimizer.zero_grad()
67
+ output = model(input)
68
+ loss = loss_fn(output, target)
69
+
70
+ # Scales loss. Calls backward() on scaled loss to create scaled gradients.
71
+ scaler.scale(loss).backward()
72
+
73
+ # scaler.step() first unscales gradients of the optimizer's params.
74
+ # If gradients don't contain infs/NaNs, optimizer.step() is then called,
75
+ # otherwise, optimizer.step() is skipped.
76
+ scaler.step(optimizer)
77
+
78
+ # Updates the scale for next iteration.
79
+ scaler.update()
80
+
81
+ See the :ref:`Automatic Mixed Precision examples<amp-examples>` for usage
82
+ (along with autocasting) in more complex cases like gradient clipping, gradient accumulation, gradient penalty,
83
+ and multiple losses/optimizers.
84
+
85
+ ``scaler`` dynamically estimates the scale factor each iteration. To minimize gradient underflow,
86
+ a large scale factor should be used. However, ``float16`` values can "overflow" (become inf or NaN) if
87
+ the scale factor is too large. Therefore, the optimal scale factor is the largest factor that can be used
88
+ without incurring inf or NaN gradient values.
89
+ ``scaler`` approximates the optimal scale factor over time by checking the gradients for infs and NaNs during every
90
+ ``scaler.step(optimizer)`` (or optional separate ``scaler.unscale_(optimizer)``, see :meth:`unscale_`).
91
+
92
+ * If infs/NaNs are found, ``scaler.step(optimizer)`` skips the underlying ``optimizer.step()`` (so the params
93
+ themselves remain uncorrupted) and ``update()`` multiplies the scale by ``backoff_factor``.
94
+
95
+ * If no infs/NaNs are found, ``scaler.step(optimizer)`` runs the underlying ``optimizer.step()`` as usual.
96
+ If ``growth_interval`` unskipped iterations occur consecutively, ``update()`` multiplies the scale by
97
+ ``growth_factor``.
98
+
99
+ The scale factor often causes infs/NaNs to appear in gradients for the first few iterations as its
100
+ value calibrates. ``scaler.step`` will skip the underlying ``optimizer.step()`` for these
101
+ iterations. After that, step skipping should occur rarely (once every few hundred or thousand iterations).
102
+
103
+ Args:
104
+ device (str, optional, default="cuda"): Device type to use. Possible values are: 'cuda' and 'cpu'.
105
+ The type is the same as the `type` attribute of a :class:`torch.device`.
106
+ Thus, you may obtain the device type of a tensor using `Tensor.device.type`.
107
+ init_scale (float, optional, default=2.**16): Initial scale factor.
108
+ growth_factor (float, optional, default=2.0): Factor by which the scale is multiplied during
109
+ :meth:`update` if no inf/NaN gradients occur for ``growth_interval`` consecutive iterations.
110
+ backoff_factor (float, optional, default=0.5): Factor by which the scale is multiplied during
111
+ :meth:`update` if inf/NaN gradients occur in an iteration.
112
+ growth_interval (int, optional, default=2000): Number of consecutive iterations without inf/NaN gradients
113
+ that must occur for the scale to be multiplied by ``growth_factor``.
114
+ enabled (bool, optional): If ``False``, disables gradient scaling. :meth:`step` simply
115
+ invokes the underlying ``optimizer.step()``, and other methods become no-ops.
116
+ Default: ``True``
117
+ """
118
+
119
+ def __init__(
120
+ self,
121
+ device: str = "cuda",
122
+ init_scale: float = 2.0**16,
123
+ growth_factor: float = 2.0,
124
+ backoff_factor: float = 0.5,
125
+ growth_interval: int = 2000,
126
+ enabled: bool = True,
127
+ ) -> None:
128
+ self._device = device
129
+ self._enabled = enabled
130
+ if self._device == "cuda":
131
+ if enabled and torch.cuda.amp.common.amp_definitely_not_available():
132
+ warnings.warn(
133
+ "torch.cuda.amp.GradScaler is enabled, but CUDA is not available. Disabling."
134
+ )
135
+ self._enabled = False
136
+
137
+ if self._enabled:
138
+ assert growth_factor > 1.0, "The growth factor must be > 1.0."
139
+ assert backoff_factor < 1.0, "The backoff factor must be < 1.0."
140
+
141
+ self._init_scale = init_scale
142
+ # self._scale will be lazily initialized during the first call to scale()
143
+ self._scale: Optional[torch.Tensor] = None
144
+ self._growth_factor = growth_factor
145
+ self._backoff_factor = backoff_factor
146
+ self._growth_interval = growth_interval
147
+ self._init_growth_tracker = 0
148
+ # self._growth_tracker will be lazily initialized during the first call to scale()
149
+ self._growth_tracker: Optional[torch.Tensor] = None
150
+ self._per_optimizer_states: Dict[int, Dict[str, Any]] = defaultdict(
151
+ _refresh_per_optimizer_state
152
+ )
153
+
154
+ def _check_scale_growth_tracker(
155
+ self, funcname: str
156
+ ) -> Tuple[torch.Tensor, torch.Tensor]:
157
+ fix = "This may indicate your script did not use scaler.scale(loss or outputs) earlier in the iteration."
158
+ assert self._scale is not None, (
159
+ f"Attempted {funcname} but _scale is None. " + fix
160
+ )
161
+ assert self._growth_tracker is not None, (
162
+ f"Attempted {funcname} but _growth_tracker is None. " + fix
163
+ )
164
+ return (self._scale, self._growth_tracker)
165
+
166
+ def _lazy_init_scale_growth_tracker(self, dev: torch.device) -> None:
167
+ assert self._growth_tracker is None, "_growth_tracker initialized before _scale"
168
+ self._scale = torch.full((), self._init_scale, dtype=torch.float32, device=dev)
169
+ self._growth_tracker = torch.full(
170
+ (), self._init_growth_tracker, dtype=torch.int32, device=dev
171
+ )
172
+
173
+ @overload
174
+ def scale(self, outputs: torch.Tensor) -> torch.Tensor:
175
+ ...
176
+
177
+ @overload
178
+ def scale(self, outputs: List[torch.Tensor]) -> List[torch.Tensor]:
179
+ ...
180
+
181
+ @overload
182
+ def scale(self, outputs: Tuple[torch.Tensor, ...]) -> Tuple[torch.Tensor, ...]:
183
+ ...
184
+
185
+ @overload
186
+ def scale(self, outputs: Iterable[torch.Tensor]) -> Iterable[torch.Tensor]:
187
+ ...
188
+
189
+ def scale(
190
+ self,
191
+ outputs: Union[torch.Tensor, Iterable[torch.Tensor]],
192
+ ) -> Union[torch.Tensor, Iterable[torch.Tensor]]:
193
+ """
194
+ Multiplies ('scales') a tensor or list of tensors by the scale factor.
195
+
196
+ Returns scaled outputs. If this instance of :class:`GradScaler` is not enabled, outputs are returned
197
+ unmodified.
198
+
199
+ Args:
200
+ outputs (Tensor or iterable of Tensors): Outputs to scale.
201
+ """
202
+ if not self._enabled:
203
+ return outputs
204
+
205
+ # Short-circuit for the common case.
206
+ if isinstance(outputs, torch.Tensor):
207
+ if self._scale is None:
208
+ self._lazy_init_scale_growth_tracker(outputs.device)
209
+ assert self._scale is not None
210
+ return outputs * self._scale.to(device=outputs.device, non_blocking=True)
211
+
212
+ # Invoke the more complex machinery only if we're treating multiple outputs.
213
+ stash: List[
214
+ _MultiDeviceReplicator
215
+ ] = [] # holds a reference that can be overwritten by apply_scale
216
+
217
+ def apply_scale(val: Union[torch.Tensor, Iterable[torch.Tensor]]):
218
+ if isinstance(val, torch.Tensor):
219
+ if len(stash) == 0:
220
+ if self._scale is None:
221
+ self._lazy_init_scale_growth_tracker(val.device)
222
+ assert self._scale is not None
223
+ stash.append(_MultiDeviceReplicator(self._scale))
224
+ return val * stash[0].get(val.device)
225
+ if isinstance(val, abc.Iterable):
226
+ iterable = map(apply_scale, val)
227
+ if isinstance(val, (list, tuple)):
228
+ return type(val)(iterable)
229
+ return iterable
230
+ raise ValueError("outputs must be a Tensor or an iterable of Tensors")
231
+
232
+ return apply_scale(outputs)
233
+
234
+ def _unscale_grads_(
235
+ self,
236
+ optimizer: torch.optim.Optimizer,
237
+ inv_scale: torch.Tensor,
238
+ found_inf: torch.Tensor,
239
+ allow_fp16: bool,
240
+ ) -> Dict[torch.device, torch.Tensor]:
241
+ per_device_inv_scale = _MultiDeviceReplicator(inv_scale)
242
+ per_device_found_inf = _MultiDeviceReplicator(found_inf)
243
+
244
+ # To set up _amp_foreach_non_finite_check_and_unscale_, split grads by device and dtype.
245
+ # There could be hundreds of grads, so we'd like to iterate through them just once.
246
+ # However, we don't know their devices or dtypes in advance.
247
+
248
+ # https://stackoverflow.com/questions/5029934/defaultdict-of-defaultdict
249
+ # Google says mypy struggles with defaultdicts type annotations.
250
+ per_device_and_dtype_grads: Dict[
251
+ torch.device, Dict[torch.dtype, List[torch.Tensor]]
252
+ ] = defaultdict(lambda: defaultdict(list))
253
+ with torch.no_grad():
254
+ for group in optimizer.param_groups:
255
+ for param in group["params"]:
256
+ assert isinstance(param, torch.Tensor)
257
+ if param.grad is None:
258
+ continue
259
+ if (not allow_fp16) and param.grad.dtype == torch.float16:
260
+ raise ValueError("Attempting to unscale FP16 gradients.")
261
+ if param.grad.is_sparse:
262
+ # is_coalesced() == False means the sparse grad has values with duplicate indices.
263
+ # coalesce() deduplicates indices and adds all values that have the same index.
264
+ # For scaled fp16 values, there's a good chance coalescing will cause overflow,
265
+ # so we should check the coalesced _values().
266
+ if param.grad.dtype is torch.float16:
267
+ param.grad = param.grad.coalesce()
268
+ to_unscale = param.grad._values()
269
+ else:
270
+ to_unscale = param.grad
271
+
272
+ # TODO: is there a way to split by device and dtype without appending in the inner loop?
273
+ per_device_and_dtype_grads[to_unscale.device][
274
+ to_unscale.dtype
275
+ ].append(to_unscale)
276
+
277
+ for device, per_dtype_grads in per_device_and_dtype_grads.items():
278
+ for grads in per_dtype_grads.values():
279
+ torch._amp_foreach_non_finite_check_and_unscale_(
280
+ grads,
281
+ per_device_found_inf.get(device),
282
+ per_device_inv_scale.get(device),
283
+ )
284
+
285
+ return per_device_found_inf._per_device_tensors
286
+
287
+ def unscale_(self, optimizer: torch.optim.Optimizer) -> None:
288
+ """
289
+ Divides ("unscales") the optimizer's gradient tensors by the scale factor.
290
+
291
+ :meth:`unscale_` is optional, serving cases where you need to
292
+ :ref:`modify or inspect gradients<working-with-unscaled-gradients>`
293
+ between the backward pass(es) and :meth:`step`.
294
+ If :meth:`unscale_` is not called explicitly, gradients will be unscaled automatically during :meth:`step`.
295
+
296
+ Simple example, using :meth:`unscale_` to enable clipping of unscaled gradients::
297
+
298
+ ...
299
+ scaler.scale(loss).backward()
300
+ scaler.unscale_(optimizer)
301
+ torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm)
302
+ scaler.step(optimizer)
303
+ scaler.update()
304
+
305
+ Args:
306
+ optimizer (torch.optim.Optimizer): Optimizer that owns the gradients to be unscaled.
307
+
308
+ .. note::
309
+ :meth:`unscale_` does not incur a CPU-GPU sync.
310
+
311
+ .. warning::
312
+ :meth:`unscale_` should only be called once per optimizer per :meth:`step` call,
313
+ and only after all gradients for that optimizer's assigned parameters have been accumulated.
314
+ Calling :meth:`unscale_` twice for a given optimizer between each :meth:`step` triggers a RuntimeError.
315
+
316
+ .. warning::
317
+ :meth:`unscale_` may unscale sparse gradients out of place, replacing the ``.grad`` attribute.
318
+ """
319
+ if not self._enabled:
320
+ return
321
+
322
+ self._check_scale_growth_tracker("unscale_")
323
+
324
+ optimizer_state = self._per_optimizer_states[id(optimizer)]
325
+
326
+ if optimizer_state["stage"] is OptState.UNSCALED:
327
+ raise RuntimeError(
328
+ "unscale_() has already been called on this optimizer since the last update()."
329
+ )
330
+ elif optimizer_state["stage"] is OptState.STEPPED:
331
+ raise RuntimeError("unscale_() is being called after step().")
332
+
333
+ # FP32 division can be imprecise for certain compile options, so we carry out the reciprocal in FP64.
334
+ assert self._scale is not None
335
+ inv_scale = self._scale.double().reciprocal().float()
336
+ found_inf = torch.full((), 0.0, dtype=torch.float32, device=self._scale.device)
337
+
338
+ optimizer_state["found_inf_per_device"] = self._unscale_grads_(
339
+ optimizer, inv_scale, found_inf, False
340
+ )
341
+ optimizer_state["stage"] = OptState.UNSCALED
342
+
343
+ def _maybe_opt_step(
344
+ self,
345
+ optimizer: torch.optim.Optimizer,
346
+ optimizer_state: Dict[str, Any],
347
+ *args: Any,
348
+ **kwargs: Any,
349
+ ) -> Optional[float]:
350
+ retval: Optional[float] = None
351
+ if not sum(v.item() for v in optimizer_state["found_inf_per_device"].values()):
352
+ retval = optimizer.step(*args, **kwargs)
353
+ return retval
354
+
355
+ def step(
356
+ self, optimizer: torch.optim.Optimizer, *args: Any, **kwargs: Any
357
+ ) -> Optional[float]:
358
+ """Invoke ``unscale_(optimizer)`` followed by parameter update, if gradients are not infs/NaN.
359
+
360
+ :meth:`step` carries out the following two operations:
361
+
362
+ 1. Internally invokes ``unscale_(optimizer)`` (unless :meth:`unscale_` was explicitly called for ``optimizer``
363
+ earlier in the iteration). As part of the :meth:`unscale_`, gradients are checked for infs/NaNs.
364
+ 2. If no inf/NaN gradients are found, invokes ``optimizer.step()`` using the unscaled
365
+ gradients. Otherwise, ``optimizer.step()`` is skipped to avoid corrupting the params.
366
+
367
+ ``*args`` and ``**kwargs`` are forwarded to ``optimizer.step()``.
368
+
369
+ Returns the return value of ``optimizer.step(*args, **kwargs)``.
370
+
371
+ Args:
372
+ optimizer (torch.optim.Optimizer): Optimizer that applies the gradients.
373
+ args: Any arguments.
374
+ kwargs: Any keyword arguments.
375
+
376
+ .. warning::
377
+ Closure use is not currently supported.
378
+ """
379
+ if not self._enabled:
380
+ return optimizer.step(*args, **kwargs)
381
+
382
+ if "closure" in kwargs:
383
+ raise RuntimeError(
384
+ "Closure use is not currently supported if GradScaler is enabled."
385
+ )
386
+
387
+ self._check_scale_growth_tracker("step")
388
+
389
+ optimizer_state = self._per_optimizer_states[id(optimizer)]
390
+
391
+ if optimizer_state["stage"] is OptState.STEPPED:
392
+ raise RuntimeError(
393
+ "step() has already been called since the last update()."
394
+ )
395
+
396
+ retval: Optional[float] = None
397
+
398
+ if getattr(optimizer, "_step_supports_amp_scaling", False):
399
+ # This optimizer has customized scale-handling logic, so we can call optimizer.step() directly.
400
+ # The contract with custom optimizers is that their step() should accept an additional,
401
+ # optional grad_scaler kwarg. We append self to the kwargs so the custom optimizer has full information:
402
+ # it can query its own state, invoke unscale_ on itself, etc
403
+ # The contract above is being deprecated to avoid introducing `grad_scaler: GradScaler` argument
404
+ # to `Optimizer.step`. The new behavior is going to add two Tensor attributes of `grad_scale`
405
+ # and `found_inf` to the passed optimizer so that the optimizer can utilize those
406
+ # to skip the parameter updates or unscale gradients before updating parameters in
407
+ # the fused kernel, e.g. `FusedAdamMathFunctor`.
408
+ # In this behavior, `GradScaler._check_inf_per_device` is called if `OptState.READY`,
409
+ # while the method is expected to be called by users side, i.e. their optimizers.
410
+ kwargs_ = kwargs
411
+ has_grad_scaler_kwarg = (
412
+ "grad_scaler" in inspect.signature(optimizer.step).parameters
413
+ )
414
+ if has_grad_scaler_kwarg:
415
+ warnings.warn(
416
+ "GradScaler is going to stop passing itself as a keyword argument to the passed "
417
+ "optimizer. In the near future GradScaler registers `grad_scale: Tensor` and "
418
+ "`found_inf: Tensor` to the passed optimizer and let the optimizer use them directly.",
419
+ FutureWarning,
420
+ )
421
+ kwargs_.update({"grad_scaler": self})
422
+ else:
423
+ if optimizer_state["stage"] is OptState.READY:
424
+ self._check_inf_per_device(optimizer)
425
+ scaler = self._get_scale_async()
426
+ assert scaler is not None
427
+ found_inf = cast(
428
+ torch.Tensor,
429
+ sum(
430
+ [ # noqa: C419
431
+ t.to(scaler.device, non_blocking=True)
432
+ for t in optimizer_state["found_inf_per_device"].values()
433
+ ]
434
+ ),
435
+ )
436
+ # Take the product of the scales, if the user has already set `optimizer.grad_scale`.
437
+ optimizer.grad_scale = ( # type: ignore[attr-defined]
438
+ getattr(optimizer, "grad_scale", None)
439
+ if optimizer_state["stage"] == OptState.UNSCALED
440
+ else scaler * getattr(optimizer, "grad_scale", 1)
441
+ )
442
+ optimizer.found_inf = found_inf # type: ignore[attr-defined]
443
+ retval = optimizer.step(*args, **kwargs_)
444
+ optimizer_state["stage"] = OptState.STEPPED
445
+ if not has_grad_scaler_kwarg:
446
+ del optimizer.grad_scale # type: ignore[attr-defined]
447
+ del optimizer.found_inf # type: ignore[attr-defined]
448
+ return retval
449
+
450
+ if optimizer_state["stage"] is OptState.READY:
451
+ self.unscale_(optimizer)
452
+
453
+ assert (
454
+ len(optimizer_state["found_inf_per_device"]) > 0
455
+ ), "No inf checks were recorded for this optimizer."
456
+
457
+ retval = self._maybe_opt_step(optimizer, optimizer_state, *args, **kwargs)
458
+
459
+ optimizer_state["stage"] = OptState.STEPPED
460
+
461
+ return retval
462
+
463
+ def update(self, new_scale: Optional[Union[float, torch.Tensor]] = None) -> None:
464
+ """Update the scale factor.
465
+
466
+ If any optimizer steps were skipped the scale is multiplied by ``backoff_factor``
467
+ to reduce it. If ``growth_interval`` unskipped iterations occurred consecutively,
468
+ the scale is multiplied by ``growth_factor`` to increase it.
469
+
470
+ Passing ``new_scale`` sets the new scale value manually. (``new_scale`` is not
471
+ used directly, it's used to fill GradScaler's internal scale tensor. So if
472
+ ``new_scale`` was a tensor, later in-place changes to that tensor will not further
473
+ affect the scale GradScaler uses internally.)
474
+
475
+ Args:
476
+ new_scale (float or :class:`torch.Tensor`, optional, default=None): New scale factor.
477
+
478
+ .. warning::
479
+ :meth:`update` should only be called at the end of the iteration, after ``scaler.step(optimizer)`` has
480
+ been invoked for all optimizers used this iteration.
481
+
482
+ .. warning::
483
+ For performance reasons, we do not check the scale factor value to avoid synchronizations,
484
+ so the scale factor is not guaranteed to be above 1. If the scale falls below 1 and/or
485
+ you are seeing NaNs in your gradients or loss, something is likely wrong. For example,
486
+ bf16-pretrained models are often incompatible with AMP/fp16 due to differing dynamic ranges.
487
+ """
488
+ if not self._enabled:
489
+ return
490
+
491
+ _scale, _growth_tracker = self._check_scale_growth_tracker("update")
492
+
493
+ if new_scale is not None:
494
+ assert self._scale is not None
495
+ # Accept a new user-defined scale.
496
+ if isinstance(new_scale, float):
497
+ self._scale.fill_(new_scale)
498
+ else:
499
+ reason = "new_scale should be a float or a 1-element torch.cuda.FloatTensor or \
500
+ torch.FloatTensor with requires_grad=False."
501
+ assert new_scale.device.type == self._device, reason
502
+ assert new_scale.numel() == 1, reason
503
+ assert new_scale.requires_grad is False, reason
504
+ self._scale.copy_(new_scale)
505
+ else:
506
+ # Consume shared inf/nan data collected from optimizers to update the scale.
507
+ # If all found_inf tensors are on the same device as self._scale, this operation is asynchronous.
508
+ found_infs = [
509
+ found_inf.to(device=_scale.device, non_blocking=True)
510
+ for state in self._per_optimizer_states.values()
511
+ for found_inf in state["found_inf_per_device"].values()
512
+ ]
513
+
514
+ assert len(found_infs) > 0, "No inf checks were recorded prior to update."
515
+
516
+ found_inf_combined = found_infs[0]
517
+ if len(found_infs) > 1:
518
+ for i in range(1, len(found_infs)):
519
+ found_inf_combined += found_infs[i]
520
+
521
+ torch._amp_update_scale_(
522
+ _scale,
523
+ _growth_tracker,
524
+ found_inf_combined,
525
+ self._growth_factor,
526
+ self._backoff_factor,
527
+ self._growth_interval,
528
+ )
529
+
530
+ # To prepare for next iteration, clear the data collected from optimizers this iteration.
531
+ self._per_optimizer_states = defaultdict(_refresh_per_optimizer_state)
532
+
533
+ def _get_scale_async(self) -> Optional[torch.Tensor]:
534
+ return self._scale
535
+
536
+ def get_scale(self) -> float:
537
+ """Return a Python float containing the current scale, or 1.0 if scaling is disabled.
538
+
539
+ .. warning::
540
+ :meth:`get_scale` incurs a CPU-GPU sync.
541
+ """
542
+ if self._enabled:
543
+ return (
544
+ self._init_scale
545
+ if (scale := self._get_scale_async()) is None
546
+ else cast(float, scale.item())
547
+ )
548
+ return 1.0
549
+
550
+ def get_growth_factor(self) -> float:
551
+ r"""Return a Python float containing the scale growth factor."""
552
+ return self._growth_factor
553
+
554
+ def set_growth_factor(self, new_factor: float) -> None:
555
+ r"""Set a new scale growth factor.
556
+
557
+ Args:
558
+ new_scale (float): Value to use as the new scale growth factor.
559
+ """
560
+ self._growth_factor = new_factor
561
+
562
+ def get_backoff_factor(self) -> float:
563
+ r"""Return a Python float containing the scale backoff factor."""
564
+ return self._backoff_factor
565
+
566
+ def set_backoff_factor(self, new_factor: float) -> None:
567
+ r"""Set a new scale backoff factor.
568
+
569
+ Args:
570
+ new_scale (float): Value to use as the new scale backoff factor.
571
+ """
572
+ self._backoff_factor = new_factor
573
+
574
+ def get_growth_interval(self) -> int:
575
+ r"""Return a Python int containing the growth interval."""
576
+ return self._growth_interval
577
+
578
+ def set_growth_interval(self, new_interval: int) -> None:
579
+ r"""Set a new growth interval.
580
+
581
+ Args:
582
+ new_interval (int): Value to use as the new growth interval.
583
+ """
584
+ self._growth_interval = new_interval
585
+
586
+ def _get_growth_tracker(self) -> int:
587
+ if self._enabled:
588
+ return (
589
+ self._init_growth_tracker
590
+ if self._growth_tracker is None
591
+ else cast(int, self._growth_tracker.item())
592
+ )
593
+ return 0
594
+
595
+ def is_enabled(self) -> bool:
596
+ r"""Return a bool indicating whether this instance is enabled."""
597
+ return self._enabled
598
+
599
+ def state_dict(self) -> Dict[str, Any]:
600
+ r"""Return the state of the scaler as a :class:`dict`.
601
+
602
+ It contains five entries:
603
+
604
+ * ``"scale"`` - a Python float containing the current scale
605
+ * ``"growth_factor"`` - a Python float containing the current growth factor
606
+ * ``"backoff_factor"`` - a Python float containing the current backoff factor
607
+ * ``"growth_interval"`` - a Python int containing the current growth interval
608
+ * ``"_growth_tracker"`` - a Python int containing the number of recent consecutive unskipped steps.
609
+
610
+ If this instance is not enabled, returns an empty dict.
611
+
612
+ .. note::
613
+ If you wish to checkpoint the scaler's state after a particular iteration, :meth:`state_dict`
614
+ should be called after :meth:`update`.
615
+ """
616
+ if self._enabled:
617
+ return {
618
+ "scale": self.get_scale(),
619
+ "growth_factor": self._growth_factor,
620
+ "backoff_factor": self._backoff_factor,
621
+ "growth_interval": self._growth_interval,
622
+ "_growth_tracker": self._get_growth_tracker(),
623
+ }
624
+ return {}
625
+
626
+ def load_state_dict(self, state_dict: Dict[str, Any]) -> None:
627
+ r"""Load the scaler state.
628
+
629
+ If this instance is disabled, :meth:`load_state_dict` is a no-op.
630
+
631
+ Args:
632
+ state_dict(dict): scaler state. Should be an object returned from a call to :meth:`state_dict`.
633
+ """
634
+ if not self._enabled:
635
+ return
636
+
637
+ if len(state_dict) == 0:
638
+ raise RuntimeError(
639
+ "The source state dict is empty, possibly because it was saved "
640
+ "from a disabled instance of GradScaler."
641
+ )
642
+
643
+ self._init_scale = cast(float, state_dict["scale"])
644
+ if self._scale is not None:
645
+ self._scale.fill_(state_dict["scale"])
646
+ self._growth_factor = cast(float, state_dict["growth_factor"])
647
+ self._backoff_factor = cast(float, state_dict["backoff_factor"])
648
+ self._growth_interval = cast(int, state_dict["growth_interval"])
649
+ self._init_growth_tracker = cast(int, state_dict["_growth_tracker"])
650
+ if self._growth_tracker is not None:
651
+ self._growth_tracker.fill_(state_dict["_growth_tracker"])
652
+
653
+ def __getstate__(self) -> Dict[str, Any]:
654
+ state = self.__dict__.copy()
655
+ if self._enabled:
656
+ assert len(self._per_optimizer_states) == 0, (
657
+ "A GradScaler instance may only be pickled at the beginning "
658
+ "of an iteration, or at the end after scaler.update()."
659
+ )
660
+ # Pickling _scale and _growth_tracker Tensors directly triggers
661
+ # "warnings.warn("pickle support for Storage will be removed in 1.5..."
662
+ # so instead, we set the unpickled instance up to reinitialize them lazily.
663
+ state["_init_scale"] = self.get_scale()
664
+ state["_init_growth_tracker"] = self._get_growth_tracker()
665
+ state["_scale"] = None
666
+ state["_growth_tracker"] = None
667
+ return state
668
+
669
+ def __setstate__(self, state: Dict[str, Any]) -> None:
670
+ self.__dict__.update(state)
671
+
672
+ def _check_inf_per_device(self, optimizer: torch.optim.Optimizer) -> Dict[str, Any]:
673
+ _scale, _ = self._check_scale_growth_tracker("_check_inf_per_device")
674
+
675
+ dummy_inv_scale = torch.full((), 1.0, dtype=torch.float32, device=_scale.device)
676
+ found_inf = torch.full((), 0.0, dtype=torch.float32, device=_scale.device)
677
+
678
+ self._per_optimizer_states[id(optimizer)][
679
+ "found_inf_per_device"
680
+ ] = self._unscale_grads_(optimizer, dummy_inv_scale, found_inf, True)
681
+
682
+ return self._per_optimizer_states[id(optimizer)]["found_inf_per_device"]
683
+
684
+ def _found_inf_per_device(self, optimizer: torch.optim.Optimizer) -> Dict[str, Any]:
685
+ return self._per_optimizer_states[id(optimizer)]["found_inf_per_device"]
lib/python3.12/site-packages/torch/bin/torch_shm_manager ADDED
Binary file (80.5 kB). View file
 
lib/python3.12/site-packages/torch/contrib/__init__.py ADDED
File without changes
lib/python3.12/site-packages/torch/contrib/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (192 Bytes). View file
 
lib/python3.12/site-packages/torch/contrib/__pycache__/_tensorboard_vis.cpython-312.pyc ADDED
Binary file (8.33 kB). View file
 
lib/python3.12/site-packages/torch/contrib/_tensorboard_vis.py ADDED
@@ -0,0 +1,143 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # mypy: allow-untyped-defs
2
+ import time
3
+ from collections import defaultdict
4
+ from functools import partial
5
+ from typing import DefaultDict
6
+
7
+ import torch
8
+
9
+
10
+ # Unfortunately it doesn't seem as if there was any way to get TensorBoard to do
11
+ # anything without having TF installed, and so this file has a hard dependency on it
12
+ # as well. It really is a debugging tool, so it doesn't matter.
13
+ try:
14
+ from tensorflow.core.util import event_pb2
15
+ from tensorflow.core.framework import graph_pb2
16
+ from tensorflow.python.summary.writer.writer import FileWriter
17
+ except ImportError:
18
+ raise ImportError("TensorBoard visualization of GraphExecutors requires having "
19
+ "TensorFlow installed") from None
20
+
21
+
22
+ def dump_tensorboard_summary(graph_executor, logdir):
23
+ with FileWriter(logdir) as w:
24
+ pb_graph = visualize(graph_executor)
25
+ evt = event_pb2.Event(wall_time=time.time(), graph_def=pb_graph.SerializeToString())
26
+ w.add_event(evt)
27
+
28
+
29
+ def visualize(graph, name_prefix='', pb_graph=None, executors_it=None):
30
+ """Visualizes an independent graph, or a graph executor."""
31
+ value_map = {}
32
+ pb_graph = pb_graph or graph_pb2.GraphDef()
33
+
34
+ if isinstance(graph, torch._C.GraphExecutorState):
35
+ visualize_graph_executor(graph, name_prefix, pb_graph,
36
+ partial(visualize, pb_graph=pb_graph))
37
+ return pb_graph
38
+
39
+ # Set up an input node
40
+ pb_graph.node.add(op='input', name=name_prefix + 'input')
41
+ for i, value in enumerate(graph.param_node().outputs()):
42
+ value_map[value.unique()] = name_prefix + 'input:' + str(i)
43
+
44
+ visualize_rec(graph, value_map, name_prefix, pb_graph, executors_it)
45
+
46
+ # Gather all outputs
47
+ return_node = pb_graph.node.add(op='output', name=name_prefix + 'output')
48
+ for value in graph.return_node().inputs():
49
+ return_node.input.append(value_map[value.unique()])
50
+
51
+ return pb_graph
52
+
53
+
54
+ def visualize_graph_executor(state, name_prefix, pb_graph, inline_graph):
55
+ """Append the state of a given GraphExecutor to the graph protobuf.
56
+
57
+ Args:
58
+ state (GraphExecutor or GraphExecutorState): GraphExecutor to display.
59
+ name_prefix (str): Name prefix of the containing subgraph.
60
+ pb_graph (GraphDef): graph to append to.
61
+ inline_graph (Callable): a function that handles setting up a value_map,
62
+ so that some graphs in here can be inlined. This is necessary, because
63
+ this will simply be `visualize` for the top-level GraphExecutor,
64
+ or `inline_graph` for all nested ones.
65
+
66
+ The signature should look like (Graph, name_prefix) -> ().
67
+ It will be called exactly once.
68
+
69
+ The strategy is to embed all different configurations as independent subgraphs,
70
+ while inlining the original graph as the one that actually produces the values.
71
+ """
72
+ if state.autograd_fallback_graph is not None:
73
+ visualize(graph=state.autograd_fallback_graph,
74
+ name_prefix=name_prefix + 'autograd_fallback/',
75
+ pb_graph=pb_graph,
76
+ executors_it=iter(state.autograd_fallback.executors()))
77
+
78
+ for i, (arg_spec, plan) in enumerate(state.execution_plans.items()):
79
+ subgraph_name = name_prefix + f'plan{i}/'
80
+
81
+ # Create a disconnected node that will keep information regarding the input
82
+ # types of this trace. This is unfortunately a bit too verbose to be included
83
+ # in the subgraph name.
84
+ input_kinds = pb_graph.node.add(op='INPUT_KIND', name=subgraph_name)
85
+ input_kinds.attr['inputs'].s = repr(arg_spec).encode('ascii')
86
+
87
+ visualize(plan.graph, subgraph_name, pb_graph, iter(plan.code.executors()))
88
+
89
+ # Show gradient as an independent subgraph of this plan
90
+ if plan.grad_executor is not None:
91
+ grad_subgraph_name = subgraph_name + 'grad/'
92
+ visualize(plan.grad_executor, grad_subgraph_name, pb_graph)
93
+
94
+ return inline_graph(state.graph, name_prefix + 'original/')
95
+
96
+
97
+ def visualize_rec(graph, value_map, name_prefix, pb_graph, executors_it=None):
98
+ """Recursive part of visualize (basically skips setting up the input and output nodes)."""
99
+ def inline_graph(subgraph, name, node):
100
+ rec_value_map = {inp.unique(): value_map[val.unique()]
101
+ for inp, val in zip(subgraph.inputs(), node.inputs())}
102
+ visualize_rec(graph=subgraph,
103
+ value_map=rec_value_map,
104
+ name_prefix=name,
105
+ pb_graph=pb_graph)
106
+ for out, val in zip(subgraph.outputs(), node.outputs()):
107
+ value_map[val.unique()] = rec_value_map[out.unique()]
108
+
109
+ op_id_counter: DefaultDict[str, int] = defaultdict(int)
110
+
111
+ def name_for(node):
112
+ kind = node.kind()[node.kind().index('::') + 2:]
113
+ op_id_counter[kind] += 1
114
+ return kind, name_prefix + kind + '_' + str(op_id_counter[kind])
115
+
116
+ def add_fusion_group(node):
117
+ op, name = name_for(node)
118
+ inline_graph(node.g('Subgraph'), name + '/', node)
119
+
120
+ def add_graph_executor(node):
121
+ op, name = name_for(node)
122
+ if executors_it is None:
123
+ add_node(node)
124
+ else:
125
+ ge = next(executors_it)
126
+ visualize_graph_executor(ge, name + '/', pb_graph,
127
+ partial(inline_graph, node=node))
128
+
129
+ def add_node(node):
130
+ if node.kind() == 'prim::FusionGroup':
131
+ return add_fusion_group(node)
132
+ elif node.kind() == 'prim::GraphExecutor':
133
+ return add_graph_executor(node)
134
+ op, name = name_for(node)
135
+ pb_node = pb_graph.node.add(op=op, name=name)
136
+ for value in node.inputs():
137
+ pb_node.input.append(value_map[value.unique()])
138
+ # TODO: handle attrs
139
+ for i, value in enumerate(node.outputs()):
140
+ value_map[value.unique()] = name + ':' + str(i)
141
+
142
+ for node in graph.nodes():
143
+ add_node(node)
lib/python3.12/site-packages/torch/cuda/__init__.py ADDED
@@ -0,0 +1,1729 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # mypy: allow-untyped-defs
2
+ r"""
3
+ This package adds support for CUDA tensor types.
4
+
5
+ It implements the same function as CPU tensors, but they utilize
6
+ GPUs for computation.
7
+
8
+ It is lazily initialized, so you can always import it, and use
9
+ :func:`is_available()` to determine if your system supports CUDA.
10
+
11
+ :ref:`cuda-semantics` has more details about working with CUDA.
12
+ """
13
+
14
+ import importlib
15
+ import os
16
+ import threading
17
+ import traceback
18
+ import warnings
19
+ from functools import lru_cache
20
+ from typing import Any, Callable, cast, List, Optional, Tuple, Union
21
+
22
+ import torch
23
+ import torch._C
24
+ from torch import device as _device
25
+ from torch._utils import _dummy_type, _LazySeedTracker, classproperty
26
+ from torch.types import Device
27
+
28
+ from . import gds
29
+ from ._utils import _get_device_index
30
+ from .graphs import (
31
+ CUDAGraph,
32
+ graph,
33
+ graph_pool_handle,
34
+ is_current_stream_capturing,
35
+ make_graphed_callables,
36
+ )
37
+ from .streams import Event, ExternalStream, Stream
38
+
39
+
40
+ try:
41
+ from torch._C import _cudart # type: ignore[attr-defined]
42
+ except ImportError:
43
+ _cudart = None
44
+
45
+ _initialized = False
46
+ _tls = threading.local()
47
+ _initialization_lock = threading.Lock()
48
+ _queued_calls: List[
49
+ Tuple[Callable[[], None], List[str]]
50
+ ] = [] # don't invoke these until initialization occurs
51
+ _is_in_bad_fork = getattr(torch._C, "_cuda_isInBadFork", lambda: False)
52
+ _device_t = Union[_device, str, int, None]
53
+
54
+ _HAS_PYNVML = False
55
+ _PYNVML_ERR = None
56
+ try:
57
+ from torch import version as _version
58
+
59
+ try:
60
+ if not _version.hip:
61
+ import pynvml # type: ignore[import]
62
+ else:
63
+ import amdsmi # type: ignore[import]
64
+
65
+ _HAS_PYNVML = True
66
+ except ModuleNotFoundError:
67
+ pass
68
+ finally:
69
+ del _version
70
+ except ImportError as err:
71
+ _PYNVML_ERR = err # sometimes a lib is installed but the import fails for some other reason, so we log the error for later
72
+
73
+ _lazy_seed_tracker = _LazySeedTracker()
74
+
75
+ # Define dummy _CudaDeviceProperties type if PyTorch was compiled without CUDA
76
+ if hasattr(torch._C, "_CudaDeviceProperties"):
77
+ _CudaDeviceProperties = torch._C._CudaDeviceProperties
78
+ else:
79
+ _CudaDeviceProperties = _dummy_type("_CudaDeviceProperties") # type: ignore[assignment, misc]
80
+
81
+ if hasattr(torch._C, "_cuda_exchangeDevice"):
82
+ _exchange_device = torch._C._cuda_exchangeDevice
83
+ else:
84
+
85
+ def _exchange_device(device: int) -> int:
86
+ if device < 0:
87
+ return -1
88
+ raise RuntimeError("PyTorch was compiled without CUDA support")
89
+
90
+
91
+ if hasattr(torch._C, "_cuda_maybeExchangeDevice"):
92
+ _maybe_exchange_device = torch._C._cuda_maybeExchangeDevice
93
+ else:
94
+
95
+ def _maybe_exchange_device(device: int) -> int:
96
+ if device < 0:
97
+ return -1
98
+ raise RuntimeError("PyTorch was compiled without CUDA support")
99
+
100
+
101
+ has_half: bool = True
102
+ has_magma: bool = torch._C._has_magma
103
+
104
+ default_generators: Tuple[torch._C.Generator] = () # type: ignore[assignment]
105
+
106
+
107
+ def _is_compiled() -> bool:
108
+ r"""Return true if compile with CUDA support."""
109
+ return hasattr(torch._C, "_cuda_getDeviceCount")
110
+
111
+
112
+ def _nvml_based_avail() -> bool:
113
+ return os.getenv("PYTORCH_NVML_BASED_CUDA_CHECK") == "1"
114
+
115
+
116
+ def is_available() -> bool:
117
+ r"""Return a bool indicating if CUDA is currently available."""
118
+ if not _is_compiled():
119
+ return False
120
+ if _nvml_based_avail():
121
+ # The user has set an env variable to request this availability check that attempts to avoid fork poisoning by
122
+ # using NVML at the cost of a weaker CUDA availability assessment. Note that if NVML discovery/initialization
123
+ # fails, this assessment falls back to the default CUDA Runtime API assessment (`cudaGetDeviceCount`)
124
+ return device_count() > 0
125
+ else:
126
+ # The default availability inspection never throws and returns 0 if the driver is missing or can't
127
+ # be initialized. This uses the CUDA Runtime API `cudaGetDeviceCount` which in turn initializes the CUDA Driver
128
+ # API via `cuInit`
129
+ return torch._C._cuda_getDeviceCount() > 0
130
+
131
+
132
+ def is_bf16_supported(including_emulation: bool = True):
133
+ r"""Return a bool indicating if the current CUDA/ROCm device supports dtype bfloat16."""
134
+ # Check for ROCm, if true return true, no ROCM_VERSION check required,
135
+ # since it is supported on AMD GPU archs.
136
+ if torch.version.hip:
137
+ return True
138
+
139
+ # If CUDA is not available, than it does not support bf16 either
140
+ if not is_available():
141
+ return False
142
+
143
+ device = torch.cuda.current_device()
144
+
145
+ # Check for CUDA version and device compute capability.
146
+ # This is a fast way to check for it.
147
+ cuda_version = torch.version.cuda
148
+ if (
149
+ cuda_version is not None
150
+ and int(cuda_version.split(".")[0]) >= 11
151
+ and torch.cuda.get_device_properties(device).major >= 8
152
+ ):
153
+ return True
154
+
155
+ if not including_emulation:
156
+ return False
157
+
158
+ # Finally try to create a bfloat16 device.
159
+ return _check_bf16_tensor_supported(device)
160
+
161
+
162
+ @lru_cache(maxsize=16)
163
+ def _check_bf16_tensor_supported(device: _device_t):
164
+ try:
165
+ torch.tensor([1.0], dtype=torch.bfloat16, device=device)
166
+ return True
167
+ except Exception:
168
+ return False
169
+
170
+
171
+ def _sleep(cycles):
172
+ torch._C._cuda_sleep(cycles)
173
+
174
+
175
+ def _extract_arch_version(arch_string: str):
176
+ """Extracts the architecture string from a CUDA version"""
177
+ base = arch_string.split("_")[1]
178
+ if base.endswith("a"):
179
+ base = base[:-1]
180
+ return int(base)
181
+
182
+
183
+ def _check_capability():
184
+ incorrect_binary_warn = """
185
+ Found GPU%d %s which requires CUDA_VERSION >= %d to
186
+ work properly, but your PyTorch was compiled
187
+ with CUDA_VERSION %d. Please install the correct PyTorch binary
188
+ using instructions from https://pytorch.org
189
+ """ # noqa: F841
190
+
191
+ old_gpu_warn = """
192
+ Found GPU%d %s which is of cuda capability %d.%d.
193
+ PyTorch no longer supports this GPU because it is too old.
194
+ The minimum cuda capability supported by this library is %d.%d.
195
+ """
196
+
197
+ if torch.version.cuda is not None: # on ROCm we don't want this check
198
+ CUDA_VERSION = torch._C._cuda_getCompiledVersion() # noqa: F841
199
+ for d in range(device_count()):
200
+ capability = get_device_capability(d)
201
+ major = capability[0]
202
+ minor = capability[1]
203
+ name = get_device_name(d)
204
+ current_arch = major * 10 + minor
205
+ min_arch = min(
206
+ (_extract_arch_version(arch) for arch in torch.cuda.get_arch_list()),
207
+ default=35,
208
+ )
209
+ if current_arch < min_arch:
210
+ warnings.warn(
211
+ old_gpu_warn
212
+ % (d, name, major, minor, min_arch // 10, min_arch % 10)
213
+ )
214
+
215
+
216
+ def _check_cubins():
217
+ incompatible_device_warn = """
218
+ {} with CUDA capability sm_{} is not compatible with the current PyTorch installation.
219
+ The current PyTorch install supports CUDA capabilities {}.
220
+ If you want to use the {} GPU with PyTorch, please check the instructions at https://pytorch.org/get-started/locally/
221
+ """
222
+ if torch.version.cuda is None: # on ROCm we don't want this check
223
+ return
224
+ arch_list = get_arch_list()
225
+ if len(arch_list) == 0:
226
+ return
227
+ supported_sm = [_extract_arch_version(arch) for arch in arch_list if "sm_" in arch]
228
+ for idx in range(device_count()):
229
+ cap_major, cap_minor = get_device_capability(idx)
230
+ # NVIDIA GPU compute architectures are backward compatible within major version
231
+ supported = any(sm // 10 == cap_major for sm in supported_sm)
232
+ if not supported:
233
+ device_name = get_device_name(idx)
234
+ capability = cap_major * 10 + cap_minor
235
+ warnings.warn(
236
+ incompatible_device_warn.format(
237
+ device_name, capability, " ".join(arch_list), device_name
238
+ )
239
+ )
240
+
241
+
242
+ def is_initialized():
243
+ r"""Return whether PyTorch's CUDA state has been initialized."""
244
+ return _initialized and not _is_in_bad_fork()
245
+
246
+
247
+ def _lazy_call(callable, **kwargs):
248
+ if is_initialized():
249
+ callable()
250
+ else:
251
+ # TODO(torch_deploy): this accesses linecache, which attempts to read the
252
+ # file system to get traceback info. Patch linecache or do something
253
+ # else here if this ends up being important.
254
+ global _lazy_seed_tracker
255
+ if kwargs.get("seed_all", False):
256
+ _lazy_seed_tracker.queue_seed_all(callable, traceback.format_stack())
257
+ elif kwargs.get("seed", False):
258
+ _lazy_seed_tracker.queue_seed(callable, traceback.format_stack())
259
+ else:
260
+ # Don't store the actual traceback to avoid memory cycle
261
+ _queued_calls.append((callable, traceback.format_stack()))
262
+
263
+
264
+ _lazy_call(_check_capability)
265
+ _lazy_call(_check_cubins)
266
+
267
+
268
+ class DeferredCudaCallError(Exception):
269
+ pass
270
+
271
+
272
+ OutOfMemoryError = torch._C.OutOfMemoryError
273
+
274
+
275
+ def init():
276
+ r"""Initialize PyTorch's CUDA state.
277
+
278
+ You may need to call this explicitly if you are interacting with
279
+ PyTorch via its C API, as Python bindings for CUDA functionality
280
+ will not be available until this initialization takes place.
281
+ Ordinary users should not need this, as all of PyTorch's CUDA methods
282
+ automatically initialize CUDA state on-demand.
283
+
284
+ Does nothing if the CUDA state is already initialized.
285
+ """
286
+ _lazy_init()
287
+
288
+
289
+ def _lazy_init():
290
+ global _initialized, _queued_calls
291
+ if is_initialized() or hasattr(_tls, "is_initializing"):
292
+ return
293
+ with _initialization_lock:
294
+ # We be double-checked locking, boys! This is OK because
295
+ # the above test was GIL protected anyway. The inner test
296
+ # is for when a thread blocked on some other thread which was
297
+ # doing the initialization; when they get the lock, they will
298
+ # find there is nothing left to do.
299
+ if is_initialized():
300
+ return
301
+ # It is important to prevent other threads from entering _lazy_init
302
+ # immediately, while we are still guaranteed to have the GIL, because some
303
+ # of the C calls we make below will release the GIL
304
+ if _is_in_bad_fork():
305
+ raise RuntimeError(
306
+ "Cannot re-initialize CUDA in forked subprocess. To use CUDA with "
307
+ "multiprocessing, you must use the 'spawn' start method"
308
+ )
309
+ if not hasattr(torch._C, "_cuda_getDeviceCount"):
310
+ raise AssertionError("Torch not compiled with CUDA enabled")
311
+ if _cudart is None:
312
+ raise AssertionError(
313
+ "libcudart functions unavailable. It looks like you have a broken build?"
314
+ )
315
+ # This function throws if there's a driver initialization error, no GPUs
316
+ # are found or any other error occurs
317
+ if "CUDA_MODULE_LOADING" not in os.environ:
318
+ os.environ["CUDA_MODULE_LOADING"] = "LAZY"
319
+ torch._C._cuda_init()
320
+ # Some of the queued calls may reentrantly call _lazy_init();
321
+ # we need to just return without initializing in that case.
322
+ # However, we must not let any *other* threads in!
323
+ _tls.is_initializing = True
324
+
325
+ _queued_calls.extend(calls for calls in _lazy_seed_tracker.get_calls() if calls)
326
+
327
+ try:
328
+ for queued_call, orig_traceback in _queued_calls:
329
+ try:
330
+ queued_call()
331
+ except Exception as e:
332
+ msg = (
333
+ f"CUDA call failed lazily at initialization with error: {str(e)}\n\n"
334
+ f"CUDA call was originally invoked at:\n\n{''.join(orig_traceback)}"
335
+ )
336
+ raise DeferredCudaCallError(msg) from e
337
+ finally:
338
+ delattr(_tls, "is_initializing")
339
+ _initialized = True
340
+
341
+
342
+ def cudart():
343
+ r"""Retrieves the CUDA runtime API module.
344
+
345
+
346
+ This function initializes the CUDA runtime environment if it is not already
347
+ initialized and returns the CUDA runtime API module (_cudart). The CUDA
348
+ runtime API module provides access to various CUDA runtime functions.
349
+
350
+ Args:
351
+ ``None``
352
+
353
+ Returns:
354
+ module: The CUDA runtime API module (_cudart).
355
+
356
+ Raises:
357
+ RuntimeError: If CUDA cannot be re-initialized in a forked subprocess.
358
+ AssertionError: If PyTorch is not compiled with CUDA support or if libcudart functions are unavailable.
359
+
360
+ Example of CUDA operations with profiling:
361
+ >>> import torch
362
+ >>> from torch.cuda import cudart, check_error
363
+ >>> import os
364
+ >>>
365
+ >>> os.environ['CUDA_PROFILE'] = '1'
366
+ >>>
367
+ >>> def perform_cuda_operations_with_streams():
368
+ >>> stream = torch.cuda.Stream()
369
+ >>> with torch.cuda.stream(stream):
370
+ >>> x = torch.randn(100, 100, device='cuda')
371
+ >>> y = torch.randn(100, 100, device='cuda')
372
+ >>> z = torch.mul(x, y)
373
+ >>> return z
374
+ >>>
375
+ >>> torch.cuda.synchronize()
376
+ >>> print("====== Start nsys profiling ======")
377
+ >>> check_error(cudart().cudaProfilerStart())
378
+ >>> with torch.autograd.profiler.emit_nvtx():
379
+ >>> result = perform_cuda_operations_with_streams()
380
+ >>> print("CUDA operations completed.")
381
+ >>> check_error(torch.cuda.cudart().cudaProfilerStop())
382
+ >>> print("====== End nsys profiling ======")
383
+
384
+ To run this example and save the profiling information, execute:
385
+ >>> $ nvprof --profile-from-start off --csv --print-summary -o trace_name.prof -f -- python cudart_test.py
386
+
387
+ This command profiles the CUDA operations in the provided script and saves
388
+ the profiling information to a file named `trace_name.prof`.
389
+ The `--profile-from-start off` option ensures that profiling starts only
390
+ after the `cudaProfilerStart` call in the script.
391
+ The `--csv` and `--print-summary` options format the profiling output as a
392
+ CSV file and print a summary, respectively.
393
+ The `-o` option specifies the output file name, and the `-f` option forces the
394
+ overwrite of the output file if it already exists.
395
+ """
396
+ _lazy_init()
397
+ return _cudart
398
+
399
+
400
+ class cudaStatus:
401
+ SUCCESS: int = 0
402
+ ERROR_NOT_READY: int = 34
403
+
404
+
405
+ class CudaError(RuntimeError):
406
+ def __init__(self, code: int) -> None:
407
+ msg = _cudart.cudaGetErrorString(_cudart.cudaError(code))
408
+ super().__init__(f"{msg} ({code})")
409
+
410
+
411
+ def check_error(res: int) -> None:
412
+ if res != _cudart.cudaError.success:
413
+ raise CudaError(res)
414
+
415
+
416
+ class _DeviceGuard:
417
+ def __init__(self, index: int):
418
+ self.idx = index
419
+ self.prev_idx = -1
420
+
421
+ def __enter__(self):
422
+ self.prev_idx = torch.cuda._exchange_device(self.idx)
423
+
424
+ def __exit__(self, type: Any, value: Any, traceback: Any):
425
+ self.idx = torch.cuda._maybe_exchange_device(self.prev_idx)
426
+ return False
427
+
428
+
429
+ class device:
430
+ r"""Context-manager that changes the selected device.
431
+
432
+ Args:
433
+ device (torch.device or int): device index to select. It's a no-op if
434
+ this argument is a negative integer or ``None``.
435
+ """
436
+
437
+ def __init__(self, device: Any):
438
+ self.idx = _get_device_index(device, optional=True)
439
+ self.prev_idx = -1
440
+
441
+ def __enter__(self):
442
+ self.prev_idx = torch.cuda._exchange_device(self.idx)
443
+
444
+ def __exit__(self, type: Any, value: Any, traceback: Any):
445
+ self.idx = torch.cuda._maybe_exchange_device(self.prev_idx)
446
+ return False
447
+
448
+
449
+ class device_of(device):
450
+ r"""Context-manager that changes the current device to that of given object.
451
+
452
+ You can use both tensors and storages as arguments. If a given object is
453
+ not allocated on a GPU, this is a no-op.
454
+
455
+ Args:
456
+ obj (Tensor or Storage): object allocated on the selected device.
457
+ """
458
+
459
+ def __init__(self, obj):
460
+ idx = obj.get_device() if obj.is_cuda else -1
461
+ super().__init__(idx)
462
+
463
+
464
+ def set_device(device: _device_t) -> None:
465
+ r"""Set the current device.
466
+
467
+ Usage of this function is discouraged in favor of :any:`device`. In most
468
+ cases it's better to use ``CUDA_VISIBLE_DEVICES`` environmental variable.
469
+
470
+ Args:
471
+ device (torch.device or int): selected device. This function is a no-op
472
+ if this argument is negative.
473
+ """
474
+ device = _get_device_index(device)
475
+ if device >= 0:
476
+ torch._C._cuda_setDevice(device)
477
+
478
+
479
+ def get_device_name(device: Optional[_device_t] = None) -> str:
480
+ r"""Get the name of a device.
481
+
482
+ Args:
483
+ device (torch.device or int or str, optional): device for which to return the
484
+ name. This function is a no-op if this argument is a negative
485
+ integer. It uses the current device, given by :func:`~torch.cuda.current_device`,
486
+ if :attr:`device` is ``None`` (default).
487
+
488
+ Returns:
489
+ str: the name of the device
490
+ """
491
+ return get_device_properties(device).name
492
+
493
+
494
+ def get_device_capability(device: Optional[_device_t] = None) -> Tuple[int, int]:
495
+ r"""Get the cuda capability of a device.
496
+
497
+ Args:
498
+ device (torch.device or int or str, optional): device for which to return the
499
+ device capability. This function is a no-op if this argument is
500
+ a negative integer. It uses the current device, given by
501
+ :func:`~torch.cuda.current_device`, if :attr:`device` is ``None``
502
+ (default).
503
+
504
+ Returns:
505
+ tuple(int, int): the major and minor cuda capability of the device
506
+ """
507
+ prop = get_device_properties(device)
508
+ return prop.major, prop.minor
509
+
510
+
511
+ def get_device_properties(device: Optional[_device_t] = None) -> _CudaDeviceProperties:
512
+ r"""Get the properties of a device.
513
+
514
+ Args:
515
+ device (torch.device or int or str, optional): device for which to return the
516
+ properties of the device. It uses the current device, given by
517
+ :func:`~torch.cuda.current_device`, if :attr:`device` is ``None``
518
+ (default).
519
+
520
+ Returns:
521
+ _CudaDeviceProperties: the properties of the device
522
+ """
523
+ _lazy_init() # will define _get_device_properties
524
+ device = _get_device_index(device, optional=True)
525
+ if device < 0 or device >= device_count():
526
+ raise AssertionError("Invalid device id")
527
+ return _get_device_properties(device) # type: ignore[name-defined]
528
+
529
+
530
+ def can_device_access_peer(device: _device_t, peer_device: _device_t) -> bool:
531
+ r"""Check if peer access between two devices is possible."""
532
+ _lazy_init()
533
+ device = _get_device_index(device, optional=True)
534
+ peer_device = _get_device_index(peer_device)
535
+ if device < 0 or device >= device_count():
536
+ raise AssertionError("Invalid device id")
537
+ if peer_device < 0 or peer_device >= device_count():
538
+ raise AssertionError("Invalid peer device id")
539
+ return torch._C._cuda_canDeviceAccessPeer(device, peer_device)
540
+
541
+
542
+ class StreamContext:
543
+ r"""Context-manager that selects a given stream.
544
+
545
+ All CUDA kernels queued within its context will be enqueued on a selected
546
+ stream.
547
+
548
+ Args:
549
+ Stream (Stream): selected stream. This manager is a no-op if it's
550
+ ``None``.
551
+ .. note:: Streams are per-device.
552
+ """
553
+ cur_stream: Optional["torch.cuda.Stream"]
554
+
555
+ def __init__(self, stream: Optional["torch.cuda.Stream"]):
556
+ self.stream = stream
557
+ self.idx = _get_device_index(None, True)
558
+ if not torch.jit.is_scripting():
559
+ if self.idx is None:
560
+ self.idx = -1
561
+
562
+ self.src_prev_stream = (
563
+ None if not torch.jit.is_scripting() else torch.cuda.default_stream(None)
564
+ )
565
+ self.dst_prev_stream = (
566
+ None if not torch.jit.is_scripting() else torch.cuda.default_stream(None)
567
+ )
568
+
569
+ def __enter__(self):
570
+ # Local cur_stream variable for type refinement
571
+ cur_stream = self.stream
572
+ # Return if stream is None or CUDA device not available
573
+ if cur_stream is None or self.idx == -1:
574
+ return
575
+ self.src_prev_stream = torch.cuda.current_stream(None)
576
+
577
+ # If the stream is not on the current device, then
578
+ # set the current stream on the device
579
+ if self.src_prev_stream.device != cur_stream.device:
580
+ with device(cur_stream.device):
581
+ self.dst_prev_stream = torch.cuda.current_stream(cur_stream.device)
582
+ torch.cuda.set_stream(cur_stream)
583
+
584
+ def __exit__(self, type: Any, value: Any, traceback: Any):
585
+ # Local cur_stream variable for type refinement
586
+ cur_stream = self.stream
587
+ # If stream is None or no CUDA device available, return
588
+ if cur_stream is None or self.idx == -1:
589
+ return
590
+
591
+ # Reset the stream on the original device
592
+ # and destination device
593
+ if self.src_prev_stream.device != cur_stream.device: # type: ignore[union-attr]
594
+ torch.cuda.set_stream(self.dst_prev_stream) # type: ignore[arg-type]
595
+ torch.cuda.set_stream(self.src_prev_stream) # type: ignore[arg-type]
596
+
597
+
598
+ def stream(stream: Optional["torch.cuda.Stream"]) -> StreamContext:
599
+ r"""Wrap around the Context-manager StreamContext that selects a given stream.
600
+
601
+ Arguments:
602
+ stream (Stream): selected stream. This manager is a no-op if it's
603
+ ``None``.
604
+ ..Note:: In eager mode stream is of type Stream class while in JIT it is
605
+ an object of the custom class ``torch.classes.cuda.Stream``.
606
+ """
607
+ return StreamContext(stream)
608
+
609
+
610
+ def _set_stream_by_id(stream_id, device_index, device_type):
611
+ r"""set stream specified by the stream id, device index and
612
+ device type
613
+
614
+ Args: stream_id (int): stream id in stream pool
615
+ device_index (int): device index in topo
616
+ device_type (int): enum device type
617
+ """
618
+ torch._C._cuda_setStream(
619
+ stream_id=stream_id,
620
+ device_index=device_index,
621
+ device_type=device_type,
622
+ )
623
+
624
+
625
+ def set_stream(stream: Stream):
626
+ r"""Set the current stream.This is a wrapper API to set the stream.
627
+ Usage of this function is discouraged in favor of the ``stream``
628
+ context manager.
629
+
630
+ Args:
631
+ stream (Stream): selected stream. This function is a no-op
632
+ if this argument is ``None``.
633
+ """
634
+ if stream is None:
635
+ return
636
+ _set_stream_by_id(
637
+ stream_id=stream.stream_id,
638
+ device_index=stream.device_index,
639
+ device_type=stream.device_type,
640
+ )
641
+
642
+
643
+ def _parse_visible_devices() -> Union[List[int], List[str]]:
644
+ r"""Parse CUDA_VISIBLE_DEVICES environment variable."""
645
+ var = os.getenv("CUDA_VISIBLE_DEVICES")
646
+
647
+ if torch.version.hip:
648
+ hip_devices = os.getenv("HIP_VISIBLE_DEVICES")
649
+ rocr_devices = os.getenv("ROCR_VISIBLE_DEVICES")
650
+
651
+ # You must take care if both HIP and ROCR env vars are set as they have
652
+ # different meanings. Both env vars accept either a list of ints or a
653
+ # list of UUIDs. The ROCR env var is processed first which then reduces
654
+ # the number of GPUs that HIP can select from.
655
+ if rocr_devices is not None:
656
+ rocr_count = len(rocr_devices.split(","))
657
+ if hip_devices is not None:
658
+ # sanity check if both env vars are set
659
+ if len(hip_devices.split(",")) > rocr_count:
660
+ raise RuntimeError(
661
+ "HIP_VISIBLE_DEVICES contains more devices than ROCR_VISIBLE_DEVICES"
662
+ )
663
+ # HIP_VISIBLE_DEVICES is preferred over ROCR_VISIBLE_DEVICES
664
+ var = hip_devices
665
+ else:
666
+ return list(range(rocr_count))
667
+ elif hip_devices is not None:
668
+ var = hip_devices
669
+
670
+ if var is None:
671
+ return list(range(64))
672
+
673
+ def _strtoul(s: str) -> int:
674
+ """Return -1 or positive integer sequence string starts with."""
675
+ if not s:
676
+ return -1
677
+ for idx, c in enumerate(s):
678
+ if not (c.isdigit() or (idx == 0 and c in "+-")):
679
+ break
680
+ if idx + 1 == len(s):
681
+ idx += 1
682
+ return int(s[:idx]) if idx > 0 else -1
683
+
684
+ def parse_list_with_prefix(lst: str, prefix: str) -> List[str]:
685
+ rcs: List[str] = []
686
+ for elem in lst.split(","):
687
+ # Repeated id results in empty set
688
+ if elem in rcs:
689
+ return cast(List[str], [])
690
+ # Anything other but prefix is ignored
691
+ if not elem.startswith(prefix):
692
+ break
693
+ rcs.append(elem)
694
+ return rcs
695
+
696
+ if var.startswith("GPU-"):
697
+ return parse_list_with_prefix(var, "GPU-")
698
+ if var.startswith("MIG-"):
699
+ return parse_list_with_prefix(var, "MIG-")
700
+ # CUDA_VISIBLE_DEVICES uses something like strtoul
701
+ # which makes `1gpu2,2ampere` is equivalent to `1,2`
702
+ rc: List[int] = []
703
+ for elem in var.split(","):
704
+ x = _strtoul(elem.strip())
705
+ # Repeated ordinal results in empty set
706
+ if x in rc:
707
+ return cast(List[int], [])
708
+ # Negative value aborts the sequence
709
+ if x < 0:
710
+ break
711
+ rc.append(x)
712
+ return rc
713
+
714
+
715
+ def _raw_device_count_amdsmi() -> int:
716
+ if not _HAS_PYNVML: # If amdsmi is not available
717
+ return -1
718
+ try:
719
+ amdsmi.amdsmi_init()
720
+ except amdsmi.AmdSmiException as e:
721
+ warnings.warn(f"Can't initialize amdsmi - Error code: {e.err_code}")
722
+ return -1
723
+ socket_handles = amdsmi.amdsmi_get_processor_handles()
724
+ return len(socket_handles)
725
+
726
+
727
+ def _raw_device_count_nvml() -> int:
728
+ r"""Return number of devices as reported by NVML or negative value if NVML discovery/initialization failed."""
729
+ from ctypes import byref, c_int, CDLL
730
+
731
+ nvml_h = CDLL("libnvidia-ml.so.1")
732
+ rc = nvml_h.nvmlInit()
733
+ if rc != 0:
734
+ warnings.warn("Can't initialize NVML")
735
+ return -1
736
+ dev_count = c_int(-1)
737
+ rc = nvml_h.nvmlDeviceGetCount_v2(byref(dev_count))
738
+ if rc != 0:
739
+ warnings.warn("Can't get nvml device count")
740
+ return -1
741
+ del nvml_h
742
+ return dev_count.value
743
+
744
+
745
+ def _raw_device_uuid_amdsmi() -> Optional[List[str]]:
746
+ from ctypes import byref, c_int, c_void_p, CDLL, create_string_buffer
747
+
748
+ if not _HAS_PYNVML: # If amdsmi is not available
749
+ return None
750
+ try:
751
+ amdsmi.amdsmi_init()
752
+ except amdsmi.AmdSmiException:
753
+ warnings.warn("Can't initialize amdsmi")
754
+ return None
755
+ try:
756
+ socket_handles = amdsmi.amdsmi_get_processor_handles()
757
+ dev_count = len(socket_handles)
758
+ except amdsmi.AmdSmiException:
759
+ warnings.warn("Can't get amdsmi device count")
760
+ return None
761
+ uuids: List[str] = []
762
+ for idx in range(dev_count):
763
+ try:
764
+ handler = amdsmi.amdsmi_get_processor_handles()[idx]
765
+ except amdsmi.AmdSmiException:
766
+ warnings.warn("Cannot get amd device handler")
767
+ return None
768
+ try:
769
+ uuid = amdsmi.amdsmi_get_gpu_asic_info(handler)["asic_serial"][
770
+ 2:
771
+ ] # Removes 0x prefix from serial
772
+ except amdsmi.AmdSmiException:
773
+ warnings.warn("Cannot get uuid for amd device")
774
+ return None
775
+ uuids.append(
776
+ str(uuid).lower()
777
+ ) # Lower-case to match expected HIP_VISIBLE_DEVICES uuid input
778
+ return uuids
779
+
780
+
781
+ def _raw_device_uuid_nvml() -> Optional[List[str]]:
782
+ r"""Return list of device UUID as reported by NVML or None if NVM discovery/initialization failed."""
783
+ from ctypes import byref, c_int, c_void_p, CDLL, create_string_buffer
784
+
785
+ nvml_h = CDLL("libnvidia-ml.so.1")
786
+ rc = nvml_h.nvmlInit()
787
+ if rc != 0:
788
+ warnings.warn("Can't initialize NVML")
789
+ return None
790
+ dev_count = c_int(-1)
791
+ rc = nvml_h.nvmlDeviceGetCount_v2(byref(dev_count))
792
+ if rc != 0:
793
+ warnings.warn("Can't get nvml device count")
794
+ return None
795
+ uuids: List[str] = []
796
+ for idx in range(dev_count.value):
797
+ dev_id = c_void_p()
798
+ rc = nvml_h.nvmlDeviceGetHandleByIndex_v2(idx, byref(dev_id))
799
+ if rc != 0:
800
+ warnings.warn("Can't get device handle")
801
+ return None
802
+ buf_len = 96
803
+ buf = create_string_buffer(buf_len)
804
+ rc = nvml_h.nvmlDeviceGetUUID(dev_id, buf, buf_len)
805
+ if rc != 0:
806
+ warnings.warn("Can't get device UUID")
807
+ return None
808
+ uuids.append(buf.raw.decode("ascii").strip("\0"))
809
+ del nvml_h
810
+ return uuids
811
+
812
+
813
+ def _transform_uuid_to_ordinals(candidates: List[str], uuids: List[str]) -> List[int]:
814
+ r"""Given the set of partial uuids and list of known uuids builds a set of ordinals excluding ambiguous partials IDs."""
815
+
816
+ def uuid_to_ordinal(candidate: str, uuids: List[str]) -> int:
817
+ best_match = -1
818
+ for idx, uuid in enumerate(uuids):
819
+ if not uuid.startswith(candidate):
820
+ continue
821
+ # Ambiguous candidate
822
+ if best_match != -1:
823
+ return -1
824
+ best_match = idx
825
+ return best_match
826
+
827
+ rc: List[int] = []
828
+ for candidate in candidates:
829
+ if torch.version.hip:
830
+ candidate = candidate.replace(
831
+ "GPU-", "", 1
832
+ ) # Remove GPU-prefix to match amdsmi asic serial
833
+ idx = uuid_to_ordinal(candidate, uuids)
834
+ # First invalid ordinal stops parsing
835
+ if idx < 0:
836
+ break
837
+ # Duplicates result in empty set
838
+ if idx in rc:
839
+ return cast(List[int], [])
840
+ rc.append(idx)
841
+ return rc
842
+
843
+
844
+ def _device_count_amdsmi() -> int:
845
+ visible_devices = _parse_visible_devices()
846
+ if not visible_devices:
847
+ return 0
848
+ try:
849
+ if type(visible_devices[0]) is str:
850
+ uuids = _raw_device_uuid_amdsmi()
851
+ if uuids is None:
852
+ return -1
853
+ # Create string version of visible devices to avoid mypy warnings
854
+ visible_device_str = cast(List[str], visible_devices)
855
+ visible_devices = _transform_uuid_to_ordinals(visible_device_str, uuids)
856
+ else:
857
+ raw_cnt = _raw_device_count_amdsmi()
858
+ if raw_cnt <= 0:
859
+ return raw_cnt
860
+ # Trim the list up to a maximum available device
861
+ for idx, val in enumerate(visible_devices):
862
+ if cast(int, val) >= raw_cnt:
863
+ return idx
864
+ except OSError:
865
+ return -1
866
+ except AttributeError:
867
+ return -1
868
+ return len(visible_devices)
869
+
870
+
871
+ def _device_count_nvml() -> int:
872
+ r"""Return number of devices as reported by NVML taking CUDA_VISIBLE_DEVICES into account.
873
+
874
+ Negative value is returned if NVML discovery or initialization has failed.
875
+ """
876
+ visible_devices = _parse_visible_devices()
877
+ if not visible_devices:
878
+ return 0
879
+ try:
880
+ if type(visible_devices[0]) is str:
881
+ # Skip MIG parsing
882
+ if visible_devices[0].startswith("MIG-"):
883
+ return -1
884
+ uuids = _raw_device_uuid_nvml()
885
+ if uuids is None:
886
+ return -1
887
+ visible_devices = _transform_uuid_to_ordinals(
888
+ cast(List[str], visible_devices), uuids
889
+ )
890
+ else:
891
+ raw_cnt = _raw_device_count_nvml()
892
+ if raw_cnt <= 0:
893
+ return raw_cnt
894
+ # Trim the list up to a maximum available device
895
+ for idx, val in enumerate(visible_devices):
896
+ if cast(int, val) >= raw_cnt:
897
+ return idx
898
+ except OSError:
899
+ return -1
900
+ except AttributeError:
901
+ return -1
902
+ return len(visible_devices)
903
+
904
+
905
+ def _get_nvml_device_index(device: Optional[Union[int, Device]]) -> int:
906
+ r"""Return the NVML index of the device, taking CUDA_VISIBLE_DEVICES into account."""
907
+ idx = _get_device_index(device, optional=True)
908
+ visible_devices = _parse_visible_devices()
909
+ if type(visible_devices[0]) is str:
910
+ uuids = _raw_device_uuid_nvml()
911
+ if uuids is None:
912
+ raise RuntimeError("Can't get device UUIDs")
913
+ visible_devices = _transform_uuid_to_ordinals(
914
+ cast(List[str], visible_devices), uuids
915
+ )
916
+ visible_devices = cast(List[int], visible_devices)
917
+ if idx < 0 or idx >= len(visible_devices):
918
+ raise RuntimeError(
919
+ f"device {idx} is not visible (CUDA_VISIBLE_DEVICES={visible_devices})"
920
+ )
921
+ return visible_devices[idx]
922
+
923
+
924
+ _cached_device_count: Optional[int] = None
925
+
926
+
927
+ def device_count() -> int:
928
+ r"""Return the number of GPUs available."""
929
+ global _cached_device_count
930
+ if not _is_compiled():
931
+ return 0
932
+ if _cached_device_count is not None:
933
+ return _cached_device_count
934
+ # bypass _device_count_nvml() if rocm (not supported)
935
+ nvml_count = _device_count_amdsmi() if torch.version.hip else _device_count_nvml()
936
+ r = torch._C._cuda_getDeviceCount() if nvml_count < 0 else nvml_count
937
+ # NB: Do not cache the device count prior to CUDA initialization, because
938
+ # the number of devices can change due to changes to CUDA_VISIBLE_DEVICES
939
+ # setting prior to CUDA initialization.
940
+ if _initialized:
941
+ _cached_device_count = r
942
+ return r
943
+
944
+
945
+ def get_arch_list() -> List[str]:
946
+ r"""Return list CUDA architectures this library was compiled for."""
947
+ if not is_available():
948
+ return []
949
+ arch_flags = torch._C._cuda_getArchFlags()
950
+ if arch_flags is None:
951
+ return []
952
+ return arch_flags.split()
953
+
954
+
955
+ def get_gencode_flags() -> str:
956
+ r"""Return NVCC gencode flags this library was compiled with."""
957
+ arch_list = get_arch_list()
958
+ if len(arch_list) == 0:
959
+ return ""
960
+ arch_list_ = [arch.split("_") for arch in arch_list]
961
+ return " ".join(
962
+ [
963
+ f"-gencode compute=compute_{arch},code={kind}_{arch}"
964
+ for (kind, arch) in arch_list_
965
+ ]
966
+ )
967
+
968
+
969
+ def current_device() -> int:
970
+ r"""Return the index of a currently selected device."""
971
+ _lazy_init()
972
+ return torch._C._cuda_getDevice()
973
+
974
+
975
+ def synchronize(device: _device_t = None) -> None:
976
+ r"""Wait for all kernels in all streams on a CUDA device to complete.
977
+
978
+ Args:
979
+ device (torch.device or int, optional): device for which to synchronize.
980
+ It uses the current device, given by :func:`~torch.cuda.current_device`,
981
+ if :attr:`device` is ``None`` (default).
982
+ """
983
+ _lazy_init()
984
+ with torch.cuda.device(device):
985
+ return torch._C._cuda_synchronize()
986
+
987
+
988
+ def ipc_collect():
989
+ r"""Force collects GPU memory after it has been released by CUDA IPC.
990
+
991
+ .. note::
992
+ Checks if any sent CUDA tensors could be cleaned from the memory. Force
993
+ closes shared memory file used for reference counting if there is no
994
+ active counters. Useful when the producer process stopped actively sending
995
+ tensors and want to release unused memory.
996
+ """
997
+ _lazy_init()
998
+ return torch._C._cuda_ipc_collect()
999
+
1000
+
1001
+ def current_stream(device: Optional[_device_t] = None) -> Stream:
1002
+ r"""Return the currently selected :class:`Stream` for a given device.
1003
+
1004
+ Args:
1005
+ device (torch.device or int, optional): selected device. Returns
1006
+ the currently selected :class:`Stream` for the current device, given
1007
+ by :func:`~torch.cuda.current_device`, if :attr:`device` is ``None``
1008
+ (default).
1009
+ """
1010
+ _lazy_init()
1011
+ streamdata = torch._C._cuda_getCurrentStream(
1012
+ _get_device_index(device, optional=True)
1013
+ )
1014
+ return Stream(
1015
+ stream_id=streamdata[0], device_index=streamdata[1], device_type=streamdata[2]
1016
+ )
1017
+
1018
+
1019
+ def default_stream(device: Optional[_device_t] = None) -> Stream:
1020
+ r"""Return the default :class:`Stream` for a given device.
1021
+
1022
+ Args:
1023
+ device (torch.device or int, optional): selected device. Returns
1024
+ the default :class:`Stream` for the current device, given by
1025
+ :func:`~torch.cuda.current_device`, if :attr:`device` is ``None``
1026
+ (default).
1027
+ """
1028
+ _lazy_init()
1029
+ streamdata = torch._C._cuda_getDefaultStream(
1030
+ _get_device_index(device, optional=True)
1031
+ )
1032
+ return Stream(
1033
+ stream_id=streamdata[0], device_index=streamdata[1], device_type=streamdata[2]
1034
+ )
1035
+
1036
+
1037
+ def current_blas_handle():
1038
+ r"""Return cublasHandle_t pointer to current cuBLAS handle"""
1039
+ _lazy_init()
1040
+ return torch._C._cuda_getCurrentBlasHandle()
1041
+
1042
+
1043
+ def set_sync_debug_mode(debug_mode: Union[int, str]) -> None:
1044
+ r"""Set the debug mode for cuda synchronizing operations.
1045
+
1046
+ Args:
1047
+ debug_mode(str or int): if "default" or 0, don't error or warn on synchronizing operations,
1048
+ if "warn" or 1, warn on synchronizing operations, if "error" or 2, error out synchronizing operations.
1049
+
1050
+ Warning:
1051
+ This is an experimental feature, and not all synchronizing operations will trigger warning or error. In
1052
+ particular, operations in torch.distributed and torch.sparse namespaces are not covered yet.
1053
+ """
1054
+ _lazy_init()
1055
+ if isinstance(debug_mode, str):
1056
+ if debug_mode == "default":
1057
+ debug_mode = 0
1058
+ elif debug_mode == "warn":
1059
+ debug_mode = 1
1060
+ elif debug_mode == "error":
1061
+ debug_mode = 2
1062
+ else:
1063
+ raise RuntimeError(
1064
+ "invalid value of debug_mode, expected one of `default`, `warn`, `error`"
1065
+ )
1066
+
1067
+ torch._C._cuda_set_sync_debug_mode(debug_mode)
1068
+
1069
+
1070
+ def get_sync_debug_mode() -> int:
1071
+ r"""Return current value of debug mode for cuda synchronizing operations."""
1072
+ _lazy_init()
1073
+ return torch._C._cuda_get_sync_debug_mode()
1074
+
1075
+
1076
+ def _get_pynvml_handler(device: Optional[Union[Device, int]] = None):
1077
+ if not _HAS_PYNVML:
1078
+ raise ModuleNotFoundError(
1079
+ "pynvml does not seem to be installed or it can't be imported."
1080
+ ) from _PYNVML_ERR
1081
+ from pynvml import NVMLError_DriverNotLoaded
1082
+
1083
+ try:
1084
+ pynvml.nvmlInit()
1085
+ except NVMLError_DriverNotLoaded as e:
1086
+ raise RuntimeError("cuda driver can't be loaded, is cuda enabled?") from e
1087
+
1088
+ device = _get_nvml_device_index(device)
1089
+ handle = pynvml.nvmlDeviceGetHandleByIndex(device)
1090
+ return handle
1091
+
1092
+
1093
+ def _get_amdsmi_handler(device: Optional[Union[Device, int]] = None):
1094
+ if not _HAS_PYNVML:
1095
+ raise ModuleNotFoundError(
1096
+ "amdsmi does not seem to be installed or it can't be imported."
1097
+ ) from _PYNVML_ERR
1098
+ try:
1099
+ amdsmi.amdsmi_init()
1100
+ except amdsmi.AmdSmiException as e:
1101
+ raise RuntimeError(
1102
+ "amdsmi driver can't be loaded, requires >=ROCm5.6 installation"
1103
+ ) from e
1104
+ device = _get_amdsmi_device_index(device)
1105
+ handle = amdsmi.amdsmi_get_processor_handles()[device]
1106
+ return handle
1107
+
1108
+
1109
+ def _get_amdsmi_device_index(device: Optional[Union[int, Device]]) -> int:
1110
+ r"""Return the amdsmi index of the device, taking visible_devices into account."""
1111
+ idx = _get_device_index(device, optional=True)
1112
+ visible_devices = _parse_visible_devices()
1113
+ if type(visible_devices[0]) is str:
1114
+ uuids = _raw_device_uuid_amdsmi()
1115
+ if uuids is None:
1116
+ raise RuntimeError("Can't get device UUIDs")
1117
+ visible_devices_str = cast(
1118
+ List[str], visible_devices
1119
+ ) # Create str variable for mypy
1120
+ visible_devices = _transform_uuid_to_ordinals(visible_devices_str, uuids)
1121
+ idx_map = dict(enumerate(cast(List[int], visible_devices)))
1122
+ if idx not in idx_map:
1123
+ raise RuntimeError(
1124
+ f"device {idx} is not visible (HIP_VISIBLE_DEVICES={visible_devices})"
1125
+ )
1126
+ return idx_map[idx]
1127
+
1128
+
1129
+ def _get_amdsmi_device_memory_used(device: Optional[Union[Device, int]] = None) -> int:
1130
+ handle = _get_amdsmi_handler()
1131
+ device = _get_amdsmi_device_index(device)
1132
+ # amdsmi_get_gpu_vram_usage returns mem usage in megabytes
1133
+ mem_mega_bytes = amdsmi.amdsmi_get_gpu_vram_usage(handle)["vram_used"]
1134
+ mem_bytes = mem_mega_bytes * 1024 * 1024
1135
+ return mem_bytes
1136
+
1137
+
1138
+ def _get_amdsmi_memory_usage(device: Optional[Union[Device, int]] = None) -> int:
1139
+ handle = _get_amdsmi_handler()
1140
+ device = _get_amdsmi_device_index(device)
1141
+ handle = amdsmi.amdsmi_get_processor_handles()[device]
1142
+ return amdsmi.amdsmi_get_gpu_activity(handle)["umc_activity"]
1143
+
1144
+
1145
+ def _get_amdsmi_utilization(device: Optional[Union[Device, int]] = None) -> int:
1146
+ handle = _get_amdsmi_handler()
1147
+ device = _get_amdsmi_device_index(device)
1148
+ handle = amdsmi.amdsmi_get_processor_handles()[device]
1149
+ return amdsmi.amdsmi_get_gpu_activity(handle)["gfx_activity"]
1150
+
1151
+
1152
+ def _get_amdsmi_temperature(device: Optional[Union[Device, int]] = None) -> int:
1153
+ handle = _get_amdsmi_handler(device)
1154
+ return amdsmi.amdsmi_get_temp_metric(
1155
+ handle,
1156
+ amdsmi.AmdSmiTemperatureType.JUNCTION,
1157
+ amdsmi.AmdSmiTemperatureMetric.CURRENT,
1158
+ )
1159
+
1160
+
1161
+ def _get_amdsmi_power_draw(device: Optional[Union[Device, int]] = None) -> int:
1162
+ handle = _get_amdsmi_handler(device)
1163
+ socket_power = amdsmi.amdsmi_get_power_info(handle)["average_socket_power"]
1164
+ if socket_power != "N/A":
1165
+ return socket_power
1166
+ else:
1167
+ return amdsmi.amdsmi_get_power_info(handle)["current_socket_power"]
1168
+
1169
+
1170
+ def _get_amdsmi_clock_rate(device: Optional[Union[Device, int]] = None) -> int:
1171
+ handle = _get_amdsmi_handler(device)
1172
+ clock_info = amdsmi.amdsmi_get_clock_info(handle, amdsmi.AmdSmiClkType.GFX)
1173
+ if "cur_clk" in clock_info: # ROCm 6.2 deprecation
1174
+ return clock_info["cur_clk"]
1175
+ else:
1176
+ return clock_info["clk"]
1177
+
1178
+
1179
+ def device_memory_used(device: Optional[Union[Device, int]] = None) -> int:
1180
+ r"""Return used global (device) memory in bytes as given by `nvidia-smi` or `amd-smi`.
1181
+
1182
+ Args:
1183
+ device (torch.device or int, optional): selected device. Returns
1184
+ statistic for the current device, given by :func:`~torch.cuda.current_device`,
1185
+ if :attr:`device` is ``None`` (default).
1186
+
1187
+ """
1188
+ if not torch.version.hip:
1189
+ handle = _get_pynvml_handler()
1190
+ device = _get_nvml_device_index(device)
1191
+ handle = pynvml.nvmlDeviceGetHandleByIndex(device)
1192
+ return pynvml.nvmlDeviceGetMemoryInfo(handle).used
1193
+ else:
1194
+ return _get_amdsmi_device_memory_used(device)
1195
+
1196
+
1197
+ def memory_usage(device: Optional[Union[Device, int]] = None) -> int:
1198
+ r"""Return the percent of time over the past sample period during which global (device)
1199
+ memory was being read or written as given by `nvidia-smi`.
1200
+
1201
+ Args:
1202
+ device (torch.device or int, optional): selected device. Returns
1203
+ statistic for the current device, given by :func:`~torch.cuda.current_device`,
1204
+ if :attr:`device` is ``None`` (default).
1205
+
1206
+ Warning: Each sample period may be between 1 second and 1/6 second,
1207
+ depending on the product being queried.
1208
+ """
1209
+ if not torch.version.hip:
1210
+ handle = _get_pynvml_handler()
1211
+ device = _get_nvml_device_index(device)
1212
+ handle = pynvml.nvmlDeviceGetHandleByIndex(device)
1213
+ return pynvml.nvmlDeviceGetUtilizationRates(handle).memory
1214
+ else:
1215
+ return _get_amdsmi_memory_usage(device)
1216
+
1217
+
1218
+ def utilization(device: Optional[Union[Device, int]] = None) -> int:
1219
+ r"""Return the percent of time over the past sample period during which one or
1220
+ more kernels was executing on the GPU as given by `nvidia-smi`.
1221
+
1222
+ Args:
1223
+ device (torch.device or int, optional): selected device. Returns
1224
+ statistic for the current device, given by :func:`~torch.cuda.current_device`,
1225
+ if :attr:`device` is ``None`` (default).
1226
+
1227
+ Warning: Each sample period may be between 1 second and 1/6 second,
1228
+ depending on the product being queried.
1229
+ """
1230
+ if not torch.version.hip:
1231
+ handle = _get_pynvml_handler(device)
1232
+ device = _get_nvml_device_index(device)
1233
+ handle = pynvml.nvmlDeviceGetHandleByIndex(device)
1234
+ return pynvml.nvmlDeviceGetUtilizationRates(handle).gpu
1235
+ else:
1236
+ return _get_amdsmi_utilization(device)
1237
+
1238
+
1239
+ def temperature(device: Optional[Union[Device, int]] = None) -> int:
1240
+ r"""Return the average temperature of the GPU sensor in Degrees C (Centigrades).
1241
+
1242
+ The average temperature is computed based on past sample period as given by `nvidia-smi`.
1243
+
1244
+ Args:
1245
+ device (torch.device or int, optional): selected device. Returns
1246
+ statistic for the current device, given by :func:`~torch.cuda.current_device`,
1247
+ if :attr:`device` is ``None`` (default).
1248
+
1249
+ Warning: Each sample period may be between 1 second and 1/6 second,
1250
+ depending on the product being queried.
1251
+ """
1252
+ if not torch.version.hip:
1253
+ handle = _get_pynvml_handler(device)
1254
+ # 0 refers to the temperature sensor for the GPU die.
1255
+ return pynvml.nvmlDeviceGetTemperature(handle, 0)
1256
+ else:
1257
+ return _get_amdsmi_temperature(device)
1258
+
1259
+
1260
+ def power_draw(device: Optional[Union[Device, int]] = None) -> int:
1261
+ r"""Return the average power draw of the GPU sensor in mW (MilliWatts)
1262
+ over the past sample period as given by `nvidia-smi` for Fermi or newer fully supported devices.
1263
+
1264
+ Args:
1265
+ device (torch.device or int, optional): selected device. Returns
1266
+ statistic for the current device, given by :func:`~torch.cuda.current_device`,
1267
+ if :attr:`device` is ``None`` (default).
1268
+
1269
+ Warning: Each sample period may be between 1 second and 1/6 second,
1270
+ depending on the product being queried.
1271
+ """
1272
+ if not torch.version.hip:
1273
+ handle = _get_pynvml_handler(device)
1274
+ return pynvml.nvmlDeviceGetPowerUsage(handle)
1275
+ else:
1276
+ return _get_amdsmi_power_draw(device)
1277
+
1278
+
1279
+ def clock_rate(device: Optional[Union[Device, int]] = None) -> int:
1280
+ r"""Return the clock speed of the GPU SM in Hz Hertz over the past sample period as given by `nvidia-smi`.
1281
+
1282
+ Args:
1283
+ device (torch.device or int, optional): selected device. Returns
1284
+ statistic for the current device, given by :func:`~torch.cuda.current_device`,
1285
+ if :attr:`device` is ``None`` (default).
1286
+
1287
+ Warning: Each sample period may be between 1 second and 1/6 second,
1288
+ depending on the product being queried.
1289
+ """
1290
+ if not torch.version.hip:
1291
+ handle = _get_pynvml_handler(device)
1292
+ return pynvml.nvmlDeviceGetClockInfo(handle, 1)
1293
+ else:
1294
+ return _get_amdsmi_clock_rate(device)
1295
+
1296
+
1297
+ def _get_device(device: Union[int, str, torch.device]) -> torch.device:
1298
+ r"""Return the torch.device type object from the passed in device.
1299
+
1300
+ Args:
1301
+ device (torch.device or int): selected device.
1302
+ """
1303
+ if isinstance(device, str):
1304
+ device = torch.device(device)
1305
+ elif isinstance(device, int):
1306
+ device = torch.device("cuda", device)
1307
+ return device
1308
+
1309
+
1310
+ def _get_generator(device: torch.device) -> torch._C.Generator:
1311
+ r"""Return the CUDA Generator object for the given device.
1312
+
1313
+ Args:
1314
+ device (torch.device): selected device.
1315
+ """
1316
+ idx = device.index
1317
+ if idx is None:
1318
+ idx = current_device()
1319
+ return torch.cuda.default_generators[idx]
1320
+
1321
+
1322
+ def _set_rng_state_offset(
1323
+ offset: int, device: Union[int, str, torch.device] = "cuda"
1324
+ ) -> None:
1325
+ r"""Set the random number generator state offset of the specified GPU.
1326
+
1327
+ Args:
1328
+ offset (int): The desired offset
1329
+ device (torch.device or int, optional): The device to set the RNG state.
1330
+ Default: ``'cuda'`` (i.e., ``torch.device('cuda')``, the current CUDA device).
1331
+ """
1332
+ final_device = _get_device(device)
1333
+
1334
+ def cb():
1335
+ default_generator = _get_generator(final_device)
1336
+ default_generator.set_offset(offset)
1337
+
1338
+ _lazy_call(cb)
1339
+
1340
+
1341
+ def _get_rng_state_offset(device: Union[int, str, torch.device] = "cuda") -> int:
1342
+ r"""Return the random number generator state offset of the specified GPU.
1343
+
1344
+ Args:
1345
+ device (torch.device or int, optional): The device to return the RNG state offset of.
1346
+ Default: ``'cuda'`` (i.e., ``torch.device('cuda')``, the current CUDA device).
1347
+
1348
+ .. warning::
1349
+ This function eagerly initializes CUDA.
1350
+ """
1351
+ _lazy_init()
1352
+ final_device = _get_device(device)
1353
+ default_generator = _get_generator(final_device)
1354
+ return default_generator.get_offset()
1355
+
1356
+
1357
+ from .memory import * # noqa: F403
1358
+ from .random import * # noqa: F403
1359
+
1360
+
1361
+ ################################################################################
1362
+ # Define Storage and Tensor classes
1363
+ ################################################################################
1364
+
1365
+
1366
+ @staticmethod # type: ignore[misc]
1367
+ def _lazy_new(cls, *args, **kwargs):
1368
+ _lazy_init()
1369
+ # We may need to call lazy init again if we are a forked child
1370
+ # del _CudaBase.__new__
1371
+ return super(_CudaBase, cls).__new__(cls, *args, **kwargs)
1372
+
1373
+
1374
+ class _CudaBase:
1375
+ is_cuda = True
1376
+ is_sparse = False
1377
+
1378
+ def type(self, *args, **kwargs):
1379
+ # We could use a Protocol here to tell mypy that self has `get_device` method
1380
+ # but it is only available in the typing module on Python >= 3.8
1381
+ # or on typing_extensions module on Python >= 3.6
1382
+ with device(self.get_device()): # type: ignore[attr-defined]
1383
+ return super().type(*args, **kwargs) # type: ignore[misc]
1384
+
1385
+ __new__ = _lazy_new
1386
+
1387
+
1388
+ from torch.storage import _LegacyStorage, _warn_typed_storage_removal
1389
+
1390
+
1391
+ class _CudaLegacyStorage(_LegacyStorage):
1392
+ @classmethod
1393
+ def from_buffer(cls, *args, **kwargs):
1394
+ _warn_typed_storage_removal()
1395
+ raise RuntimeError("from_buffer: Not available for CUDA storage")
1396
+
1397
+ @classmethod
1398
+ def _new_with_weak_ptr(cls, *args, **kwargs):
1399
+ raise RuntimeError("_new_with_weak_ptr: Not available for CUDA storage")
1400
+
1401
+ @classmethod
1402
+ def _new_shared_filename(cls, manager, obj, size, *, device=None, dtype=None):
1403
+ raise RuntimeError("_new_shared_filename: Not available for CUDA storage")
1404
+
1405
+
1406
+ class ByteStorage(_CudaLegacyStorage):
1407
+ @classproperty
1408
+ def dtype(self):
1409
+ _warn_typed_storage_removal()
1410
+ return self._dtype
1411
+
1412
+ @classproperty
1413
+ def _dtype(self):
1414
+ return torch.uint8
1415
+
1416
+
1417
+ class DoubleStorage(_CudaLegacyStorage):
1418
+ @classproperty
1419
+ def dtype(self):
1420
+ _warn_typed_storage_removal()
1421
+ return self._dtype
1422
+
1423
+ @classproperty
1424
+ def _dtype(self):
1425
+ return torch.double
1426
+
1427
+
1428
+ class FloatStorage(_CudaLegacyStorage):
1429
+ @classproperty
1430
+ def dtype(self):
1431
+ _warn_typed_storage_removal()
1432
+ return self._dtype
1433
+
1434
+ @classproperty
1435
+ def _dtype(self):
1436
+ return torch.float
1437
+
1438
+
1439
+ class HalfStorage(_CudaLegacyStorage):
1440
+ @classproperty
1441
+ def dtype(self):
1442
+ _warn_typed_storage_removal()
1443
+ return self._dtype
1444
+
1445
+ @classproperty
1446
+ def _dtype(self):
1447
+ return torch.half
1448
+
1449
+
1450
+ class LongStorage(_CudaLegacyStorage):
1451
+ @classproperty
1452
+ def dtype(self):
1453
+ _warn_typed_storage_removal()
1454
+ return self._dtype
1455
+
1456
+ @classproperty
1457
+ def _dtype(self):
1458
+ return torch.long
1459
+
1460
+
1461
+ class IntStorage(_CudaLegacyStorage):
1462
+ @classproperty
1463
+ def dtype(self):
1464
+ _warn_typed_storage_removal()
1465
+ return self._dtype
1466
+
1467
+ @classproperty
1468
+ def _dtype(self):
1469
+ return torch.int
1470
+
1471
+
1472
+ class ShortStorage(_CudaLegacyStorage):
1473
+ @classproperty
1474
+ def dtype(self):
1475
+ _warn_typed_storage_removal()
1476
+ return self._dtype
1477
+
1478
+ @classproperty
1479
+ def _dtype(self):
1480
+ return torch.short
1481
+
1482
+
1483
+ class CharStorage(_CudaLegacyStorage):
1484
+ @classproperty
1485
+ def dtype(self):
1486
+ _warn_typed_storage_removal()
1487
+ return self._dtype
1488
+
1489
+ @classproperty
1490
+ def _dtype(self):
1491
+ return torch.int8
1492
+
1493
+
1494
+ class BoolStorage(_CudaLegacyStorage):
1495
+ @classproperty
1496
+ def dtype(self):
1497
+ _warn_typed_storage_removal()
1498
+ return self._dtype
1499
+
1500
+ @classproperty
1501
+ def _dtype(self):
1502
+ return torch.bool
1503
+
1504
+
1505
+ class BFloat16Storage(_CudaLegacyStorage):
1506
+ @classproperty
1507
+ def dtype(self):
1508
+ _warn_typed_storage_removal()
1509
+ return self._dtype
1510
+
1511
+ @classproperty
1512
+ def _dtype(self):
1513
+ return torch.bfloat16
1514
+
1515
+
1516
+ class ComplexDoubleStorage(_CudaLegacyStorage):
1517
+ @classproperty
1518
+ def dtype(self):
1519
+ _warn_typed_storage_removal()
1520
+ return self._dtype
1521
+
1522
+ @classproperty
1523
+ def _dtype(self):
1524
+ return torch.cdouble
1525
+
1526
+
1527
+ class ComplexFloatStorage(_CudaLegacyStorage):
1528
+ @classproperty
1529
+ def dtype(self):
1530
+ _warn_typed_storage_removal()
1531
+ return self._dtype
1532
+
1533
+ @classproperty
1534
+ def _dtype(self):
1535
+ return torch.cfloat
1536
+
1537
+
1538
+ del _LegacyStorage
1539
+ del _CudaLegacyStorage
1540
+
1541
+ torch._storage_classes.add(DoubleStorage)
1542
+ torch._storage_classes.add(FloatStorage)
1543
+ torch._storage_classes.add(LongStorage)
1544
+ torch._storage_classes.add(IntStorage)
1545
+ torch._storage_classes.add(ShortStorage)
1546
+ torch._storage_classes.add(CharStorage)
1547
+ torch._storage_classes.add(ByteStorage)
1548
+ torch._storage_classes.add(HalfStorage)
1549
+ torch._storage_classes.add(BoolStorage)
1550
+ torch._storage_classes.add(BFloat16Storage)
1551
+ torch._storage_classes.add(ComplexDoubleStorage)
1552
+ torch._storage_classes.add(ComplexFloatStorage)
1553
+
1554
+
1555
+ class _WrappedTritonKernel:
1556
+ """Just a simple wrapper to store some metadata for testing purposes."""
1557
+
1558
+ def __init__(self, kernel):
1559
+ self.kernel = kernel
1560
+ self.kernel_invoked = False
1561
+
1562
+ def __call__(self, *args, **kwargs):
1563
+ res = self.kernel(*args, **kwargs)
1564
+ self.kernel_invoked = True
1565
+ return res
1566
+
1567
+
1568
+ def _register_triton_kernels():
1569
+ if torch._running_with_deploy():
1570
+ return
1571
+
1572
+ @_WrappedTritonKernel
1573
+ def kernel_impl(*args, **kwargs):
1574
+ from torch.sparse._triton_ops import bsr_dense_mm
1575
+
1576
+ return bsr_dense_mm(*args, skip_checks=True, **kwargs)
1577
+
1578
+ @_WrappedTritonKernel
1579
+ def addmm_kernel_impl(*args, **kwargs):
1580
+ from torch.sparse._triton_ops import bsr_dense_addmm
1581
+
1582
+ return bsr_dense_addmm(*args, skip_checks=True, **kwargs)
1583
+
1584
+ has_triton = importlib.util.find_spec("triton") is not None
1585
+ if has_triton:
1586
+ torch._TritonLibrary.registerOp(
1587
+ "_triton_bsr_dense_mm_out",
1588
+ "_triton_bsr_dense_mm_out(Tensor bsr, Tensor dense, *, Tensor(a!) out) -> Tensor(a!)",
1589
+ kernel_impl,
1590
+ "SparseCsrCUDA",
1591
+ )
1592
+
1593
+ torch._TritonLibrary.registerOp(
1594
+ "_triton_bsr_dense_addmm_out",
1595
+ (
1596
+ "_triton_bsr_dense_addmm_out(Tensor input, Tensor bsr, Tensor dense,"
1597
+ " *, Scalar beta, Scalar alpha, Tensor(a!) out) -> Tensor(a!)"
1598
+ ),
1599
+ addmm_kernel_impl,
1600
+ "SparseCsrCUDA",
1601
+ )
1602
+
1603
+
1604
+ _lazy_call(_register_triton_kernels)
1605
+
1606
+
1607
+ from . import amp, jiterator, nvtx, profiler, sparse, tunable
1608
+
1609
+
1610
+ __all__ = [
1611
+ # Typed storage and tensors
1612
+ "BFloat16Storage",
1613
+ "BFloat16Tensor",
1614
+ "BoolStorage",
1615
+ "BoolTensor",
1616
+ "ByteStorage",
1617
+ "ByteTensor",
1618
+ "CharStorage",
1619
+ "CharTensor",
1620
+ "ComplexDoubleStorage",
1621
+ "ComplexFloatStorage",
1622
+ "DoubleStorage",
1623
+ "DoubleTensor",
1624
+ "FloatStorage",
1625
+ "FloatTensor",
1626
+ "HalfStorage",
1627
+ "HalfTensor",
1628
+ "IntStorage",
1629
+ "IntTensor",
1630
+ "LongStorage",
1631
+ "LongTensor",
1632
+ "ShortStorage",
1633
+ "ShortTensor",
1634
+ "CUDAGraph",
1635
+ "CudaError",
1636
+ "DeferredCudaCallError",
1637
+ "Event",
1638
+ "ExternalStream",
1639
+ "Stream",
1640
+ "StreamContext",
1641
+ "amp",
1642
+ "caching_allocator_alloc",
1643
+ "caching_allocator_delete",
1644
+ "caching_allocator_enable",
1645
+ "can_device_access_peer",
1646
+ "check_error",
1647
+ "cudaStatus",
1648
+ "cudart",
1649
+ "current_blas_handle",
1650
+ "current_device",
1651
+ "current_stream",
1652
+ "default_generators",
1653
+ "default_stream",
1654
+ "device",
1655
+ "device_count",
1656
+ "device_memory_used",
1657
+ "device_of",
1658
+ "empty_cache",
1659
+ "get_allocator_backend",
1660
+ "CUDAPluggableAllocator",
1661
+ "change_current_allocator",
1662
+ "get_arch_list",
1663
+ "get_device_capability",
1664
+ "get_device_name",
1665
+ "get_device_properties",
1666
+ "get_gencode_flags",
1667
+ "get_per_process_memory_fraction",
1668
+ "get_rng_state",
1669
+ "get_rng_state_all",
1670
+ "get_sync_debug_mode",
1671
+ "graph",
1672
+ "graph_pool_handle",
1673
+ "graphs",
1674
+ "has_half",
1675
+ "has_magma",
1676
+ "init",
1677
+ "initial_seed",
1678
+ "ipc_collect",
1679
+ "is_available",
1680
+ "is_bf16_supported",
1681
+ "is_current_stream_capturing",
1682
+ "is_initialized",
1683
+ "jiterator",
1684
+ "list_gpu_processes",
1685
+ "make_graphed_callables",
1686
+ "manual_seed",
1687
+ "manual_seed_all",
1688
+ "max_memory_allocated",
1689
+ "max_memory_cached",
1690
+ "max_memory_reserved",
1691
+ "mem_get_info",
1692
+ "memory",
1693
+ "memory_allocated",
1694
+ "memory_cached",
1695
+ "memory_reserved",
1696
+ "memory_snapshot",
1697
+ "memory_stats",
1698
+ "memory_stats_as_nested_dict",
1699
+ "memory_summary",
1700
+ "memory_usage",
1701
+ "MemPool",
1702
+ "MemPoolContext",
1703
+ "use_mem_pool",
1704
+ "temperature",
1705
+ "power_draw",
1706
+ "clock_rate",
1707
+ "nccl",
1708
+ "nvtx",
1709
+ "profiler",
1710
+ "random",
1711
+ "reset_accumulated_memory_stats",
1712
+ "reset_max_memory_allocated",
1713
+ "reset_max_memory_cached",
1714
+ "reset_peak_memory_stats",
1715
+ "seed",
1716
+ "seed_all",
1717
+ "set_device",
1718
+ "set_per_process_memory_fraction",
1719
+ "set_rng_state",
1720
+ "set_rng_state_all",
1721
+ "set_stream",
1722
+ "set_sync_debug_mode",
1723
+ "sparse",
1724
+ "stream",
1725
+ "streams",
1726
+ "synchronize",
1727
+ "tunable",
1728
+ "utilization",
1729
+ ]
lib/python3.12/site-packages/torch/cuda/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (71.2 kB). View file
 
lib/python3.12/site-packages/torch/cuda/__pycache__/_gpu_trace.cpython-312.pyc ADDED
Binary file (3.88 kB). View file
 
lib/python3.12/site-packages/torch/cuda/__pycache__/_memory_viz.cpython-312.pyc ADDED
Binary file (31.8 kB). View file
 
lib/python3.12/site-packages/torch/cuda/__pycache__/_sanitizer.cpython-312.pyc ADDED
Binary file (35.1 kB). View file
 
lib/python3.12/site-packages/torch/cuda/__pycache__/_utils.cpython-312.pyc ADDED
Binary file (2.06 kB). View file
 
lib/python3.12/site-packages/torch/cuda/__pycache__/comm.cpython-312.pyc ADDED
Binary file (424 Bytes). View file