|  | """Tracing. | 
|  |  | 
|  | This module contains functionality to support the JIT's tracing frontend, notably: | 
|  | * torch.jit.trace | 
|  | * torch.jit.trace_module | 
|  |  | 
|  | This is not intended to be imported directly; please use the exposed | 
|  | functionalities in `torch.jit`. | 
|  | """ | 
|  | import contextlib | 
|  |  | 
|  | import copy | 
|  | import functools | 
|  | import inspect | 
|  | import os | 
|  | import re | 
|  | import warnings | 
|  | from typing import Any, Callable, Dict, List, Optional, Set, TypeVar | 
|  |  | 
|  | from typing_extensions import ParamSpec | 
|  |  | 
|  | import torch | 
|  | from torch._jit_internal import ( | 
|  | _qualified_name, | 
|  | get_callable_argument_names, | 
|  | is_scripting, | 
|  | ) | 
|  | from torch.autograd import function | 
|  | from torch.jit._script import _CachedForward, script, ScriptModule | 
|  |  | 
|  | from torch.jit._state import _enabled, _python_cu | 
|  | from torch.nn import Module | 
|  |  | 
|  | from torch.testing._comparison import default_tolerances | 
|  |  | 
|  | _flatten = torch._C._jit_flatten | 
|  | _unflatten = torch._C._jit_unflatten | 
|  |  | 
|  | R = TypeVar("R", covariant=True)  # return type (always covariant) | 
|  | P = ParamSpec("P") | 
|  |  | 
|  |  | 
|  | def _create_interpreter_name_lookup_fn(frames_up=1): | 
|  | def _get_interpreter_name_for_var(var): | 
|  | frame = inspect.currentframe() | 
|  | if not frame: | 
|  | raise RuntimeError("failed to inspect frame") | 
|  |  | 
|  | i = 0 | 
|  | while i < frames_up + 1: | 
|  | frame = frame.f_back | 
|  | if not frame: | 
|  | raise RuntimeError("failed to get frame") | 
|  | i += 1 | 
|  |  | 
|  | f_locals = frame.f_locals | 
|  | f_globals = frame.f_globals | 
|  |  | 
|  | for k, v in f_locals.items(): | 
|  | if isinstance(v, torch.Tensor) and var is v: | 
|  | return k if k != "self" else "" | 
|  | return "" | 
|  |  | 
|  | return _get_interpreter_name_for_var | 
|  |  | 
|  |  | 
|  | def _unique_state_dict(module, keep_vars=False): | 
|  | # since Parameter.detach() always creates a new torch.Tensor instance, | 
|  | # id(v) doesn't work with it. So we always get the Parameter or Buffer | 
|  | # as values, and deduplicate the params using Parameters and Buffers | 
|  | state_dict = module.state_dict(keep_vars=True) | 
|  | filtered_dict = type(state_dict)() | 
|  | seen_ids: Set[int] = set() | 
|  | for k, v in state_dict.items(): | 
|  | if id(v) in seen_ids: | 
|  | continue | 
|  | seen_ids.add(id(v)) | 
|  | if keep_vars: | 
|  | filtered_dict[k] = v | 
|  | else: | 
|  | filtered_dict[k] = v.detach() | 
|  | return filtered_dict | 
|  |  | 
|  |  | 
|  | class ONNXTracedModule(torch.nn.Module): | 
|  | def __init__( | 
|  | self, | 
|  | inner, | 
|  | strict=True, | 
|  | force_outplace=False, | 
|  | return_inputs=False, | 
|  | return_inputs_states=False, | 
|  | ): | 
|  | super().__init__() | 
|  | # inner may be a Module, or it may be an arbitrary callable | 
|  | # If it's a Module, we get its parameters automatically, which lets | 
|  | # us avoid a special casing functions versus modules. | 
|  | self.inner = inner | 
|  | self.strict = strict | 
|  | self._force_outplace = force_outplace | 
|  | self._return_inputs = return_inputs | 
|  | self._return_inputs_states = return_inputs_states | 
|  |  | 
|  | def forward(self, *args: torch.Tensor): | 
|  | in_vars, in_desc = _flatten(args) | 
|  | # NOTE: use full state, because we need it for BatchNorm export | 
|  | # This differs from the compiler path, which doesn't support it at the moment. | 
|  | module_state = list(_unique_state_dict(self, keep_vars=True).values()) | 
|  |  | 
|  | ret_inputs = [] | 
|  | inputs_states = [] | 
|  | outs = [] | 
|  |  | 
|  | def wrapper(*args): | 
|  | in_args: List[torch.Tensor] = [] | 
|  | for i in range(len(in_vars)): | 
|  | if not isinstance(args[i], torch.Tensor): | 
|  | raise RuntimeError("Expected Tensor argument") | 
|  | in_args.append(args[i]) | 
|  |  | 
|  | trace_inputs = _unflatten(in_args, in_desc) | 
|  |  | 
|  | if self._return_inputs: | 
|  | ret_inputs.append( | 
|  | tuple(x.clone(memory_format=torch.preserve_format) for x in args) | 
|  | ) | 
|  | if self._return_inputs_states: | 
|  | inputs_states.append(_unflatten(in_args, in_desc)) | 
|  | outs.append(self.inner(*trace_inputs)) | 
|  | if self._return_inputs_states: | 
|  | inputs_states[0] = (inputs_states[0], trace_inputs) | 
|  | out_vars, _ = _flatten(outs) | 
|  | if len(out_vars) == 1: | 
|  | return out_vars[0] | 
|  | else: | 
|  | return tuple(out_vars) | 
|  |  | 
|  | graph, out = torch._C._create_graph_by_tracing( | 
|  | wrapper, | 
|  | in_vars + module_state, | 
|  | _create_interpreter_name_lookup_fn(), | 
|  | self.strict, | 
|  | self._force_outplace, | 
|  | ) | 
|  |  | 
|  | if self._return_inputs: | 
|  | return graph, outs[0], ret_inputs[0] | 
|  | if self._return_inputs_states: | 
|  | return graph, outs[0], inputs_states[0] | 
|  | else: | 
|  | return graph, outs[0] | 
|  |  | 
|  |  | 
|  | def _clone_inputs(args): | 
|  | def clone_input(a): | 
|  | if a is None: | 
|  | return None | 
|  | elif isinstance(a, torch.Tensor): | 
|  | # TODO: figure out one liner to .clone() and set requires_grad | 
|  | v = ( | 
|  | a.detach() | 
|  | .clone(memory_format=None if a.is_mkldnn else torch.preserve_format) | 
|  | .requires_grad_(a.requires_grad) | 
|  | ) | 
|  | if a.grad is not None: | 
|  | v.grad = clone_input(v.grad) | 
|  | return v | 
|  | else: | 
|  | return a.clone(memory_format=torch.preserve_format) | 
|  |  | 
|  | return function._nested_map( | 
|  | lambda x: isinstance(x, torch.Tensor), clone_input, condition_msg="tensors" | 
|  | )(args) | 
|  |  | 
|  |  | 
|  | # This is purely for developer debugging.  We are not going to advertise it. | 
|  | _JIT_TIME = os.environ.get("PYTORCH_JIT_TIME", False)  # CUDA-only timing | 
|  | _JIT_DISABLE = os.environ.get("PYTORCH_JIT_DISABLE", False) | 
|  | _JIT_STATS = os.environ.get("PYTORCH_JIT_STATS", False) | 
|  |  | 
|  |  | 
|  | @contextlib.contextmanager | 
|  | def _time(trace_name, name, time=True): | 
|  | if (not _JIT_TIME and not time) or not torch.cuda.is_available(): | 
|  | yield | 
|  | return | 
|  | stream = torch.cuda.current_stream() | 
|  | start = torch.cuda.Event(enable_timing=True) | 
|  | end = torch.cuda.Event(enable_timing=True) | 
|  | stream.record_event(start) | 
|  | try: | 
|  | yield | 
|  | finally: | 
|  | stream.record_event(end) | 
|  | end.synchronize() | 
|  | print(f"{trace_name} {name} time: {start.elapsed_time(end)} ms") | 
|  |  | 
|  |  | 
|  | def verify(model, args, loss_fn=torch.sum, devices=None): | 
|  | """ | 
|  | Verify that a JIT compiled model has the same behavior as its uncompiled version along with its backwards pass. | 
|  |  | 
|  | If your model returns multiple outputs, | 
|  | you must also specify a `loss_fn` to produce a loss for which | 
|  | the backwards will be computed. | 
|  |  | 
|  | This function has side-effects (e.g., it executes your model / saves and loads | 
|  | parameters), so don't expect the model to come out exactly the same as what | 
|  | you passed in. | 
|  |  | 
|  | Args: | 
|  | model (compiled torch.nn.Module or function): the module/function to be | 
|  | verified.  The module/function definition MUST have been decorated with | 
|  | `@torch.jit.compile`. | 
|  | args (tuple or Tensor): the positional arguments to pass to the | 
|  | compiled function/module to be verified.  A non-tuple is assumed to | 
|  | be a single positional argument to be passed to the model. | 
|  | loss_fn (function, optional): the loss function to be applied to | 
|  | the output of the model, before backwards is invoked.  By default, | 
|  | we assume that a model returns a single result, and we :func:`torch.sum` | 
|  | before calling backwards; if this is inappropriate, you can pass your | 
|  | own loss function.  Note that if a model returns a tuple of results, | 
|  | these are passed as separate positional arguments to `loss_fn`. | 
|  | devices (iterable of device IDs, optional): the GPU devices which the | 
|  | compiled module will be run on.  This determines the RNG state we | 
|  | must save when running both compiled and uncompiled versions of the model. | 
|  | """ | 
|  | # TODO: In principle, we track device information in our trace, so it | 
|  | # should be possible to check if our execution actually obeyed the 'devices' | 
|  | # the user provided. | 
|  |  | 
|  | # TODO: Consider adding a utility function to torch.jit to test | 
|  | # for this case | 
|  | if not isinstance(model, torch._C.CompiledFunction):  # type: ignore[attr-defined] | 
|  | raise TypeError( | 
|  | "Cannot verify an uncompiled module.  Add @torch.jit.compile to compile it" | 
|  | ) | 
|  | is_module = isinstance(model, Module) | 
|  |  | 
|  | if not isinstance(args, tuple): | 
|  | args = (args,) | 
|  |  | 
|  | saved_args = _clone_inputs(args) | 
|  | if is_module: | 
|  | saved_state = copy.deepcopy(model.state_dict()) | 
|  |  | 
|  | def run_fwd_bwd(args, force_trace=False, assert_compiled=False): | 
|  | params = list(model.parameters()) if is_module else [] | 
|  | in_vars, _ = _flatten((args, params)) | 
|  | # We use a special API to reset the trace and compile it from scratch. | 
|  | compiled_fn = model | 
|  | if force_trace: | 
|  | compiled_fn.clear_cache() | 
|  | if assert_compiled: | 
|  | hits = compiled_fn.hits | 
|  | out = model(*args) | 
|  | if assert_compiled and compiled_fn.hits == hits: | 
|  | raise RuntimeError("failed to use the compiled function") | 
|  | if not isinstance(out, tuple): | 
|  | out = (out,) | 
|  | if loss_fn == torch.sum and len(out) != 1: | 
|  | raise ValueError( | 
|  | f"Model returns {len(out)} outputs, but default loss function " | 
|  | "(torch.sum) can only handle a single output" | 
|  | ) | 
|  | out_vars, _ = _flatten(out) | 
|  | saved_outs = [ | 
|  | v.detach().clone(memory_format=torch.preserve_format) for v in out_vars | 
|  | ] | 
|  | loss = loss_fn(*out) | 
|  | grads = torch.autograd.grad([loss], in_vars) | 
|  | # TODO: I'm not sure if the clone here is necessary but it is safer | 
|  | saved_grads = [ | 
|  | v.detach().clone(memory_format=torch.preserve_format) for v in grads | 
|  | ] | 
|  | return (saved_outs, saved_grads) | 
|  |  | 
|  | with torch.random.fork_rng(devices, _caller="torch.jit.verify"): | 
|  | uncompiled_outs, uncompiled_grads = run_fwd_bwd(args, force_trace=True) | 
|  | assert model.has_trace_for(*args) | 
|  |  | 
|  | if is_module: | 
|  | model.load_state_dict(saved_state) | 
|  | compiled_outs, compiled_grads = run_fwd_bwd(args, assert_compiled=True) | 
|  |  | 
|  | _verify_equal(uncompiled_outs, compiled_outs) | 
|  | _verify_equal(uncompiled_grads, compiled_grads) | 
|  |  | 
|  |  | 
|  | def _verify_equal(xs, ys): | 
|  | for x, y in zip(xs, ys): | 
|  | if x.sub(y).abs().max() > 1e-6: | 
|  | raise RuntimeError("JIT and real computation mismatch") | 
|  |  | 
|  |  | 
|  | def indent(s): | 
|  | return "\n".join(["\t" + line for line in s.splitlines()]) | 
|  |  | 
|  |  | 
|  | class TracingCheckError(Exception): | 
|  | def __init__(self, graph_diff_error, tensor_compare_error, extra_msg=None): | 
|  | self.message = "Tracing failed sanity checks!\n" | 
|  | if extra_msg is not None: | 
|  | self.message += extra_msg + "\n" | 
|  | if graph_diff_error is not None: | 
|  | self.message += "ERROR: Graphs differed across invocations!\n" | 
|  | self.message += indent(graph_diff_error) + "\n" | 
|  | if tensor_compare_error is not None: | 
|  | self.message += ( | 
|  | "ERROR: Tensor-valued Constant nodes differed in value " | 
|  | "across invocations. This often indicates that the tracer has" | 
|  | " encountered untraceable code.\n" | 
|  | ) | 
|  | self.message += indent(tensor_compare_error) + "\n" | 
|  | super().__init__(self.message) | 
|  |  | 
|  |  | 
|  | # Check the traced module against a set of user-provided validation inputs | 
|  | @torch.no_grad() | 
|  | def _check_trace( | 
|  | check_inputs, | 
|  | func, | 
|  | traced_func, | 
|  | check_tolerance, | 
|  | strict, | 
|  | force_outplace, | 
|  | is_trace_module, | 
|  | _module_class, | 
|  | example_inputs_is_kwarg=False, | 
|  | ): | 
|  | # Note: tracing is independent of optimizations, which consume the trace | 
|  | for inputs in check_inputs: | 
|  | if isinstance(inputs, torch.Tensor): | 
|  | inputs = (inputs,) | 
|  |  | 
|  | if is_trace_module: | 
|  | copied_dict = {} | 
|  | for name, data in inputs.items(): | 
|  | copied_dict[name] = _clone_inputs(data) | 
|  | check_mod = torch.jit.trace_module( | 
|  | getattr(func, "__self__", func), | 
|  | copied_dict, | 
|  | check_trace=False, | 
|  | strict=strict, | 
|  | _force_outplace=force_outplace, | 
|  | _module_class=_module_class, | 
|  | _compilation_unit=torch._C.CompilationUnit(), | 
|  | example_inputs_is_kwarg=example_inputs_is_kwarg, | 
|  | _store_inputs=False, | 
|  | ) | 
|  | check_mod_func = check_mod._c._get_method(traced_func.name) | 
|  | inputs = inputs[traced_func.name] | 
|  | if ( | 
|  | isinstance(inputs, (torch.Tensor)) | 
|  | or isinstance(inputs, dict) | 
|  | and not example_inputs_is_kwarg | 
|  | ): | 
|  | inputs = (inputs,) | 
|  | else: | 
|  | if example_inputs_is_kwarg: | 
|  | check_mod = torch.jit.trace( | 
|  | func, | 
|  | check_trace=False, | 
|  | strict=strict, | 
|  | _force_outplace=force_outplace, | 
|  | _module_class=_module_class, | 
|  | example_kwarg_inputs=_clone_inputs(inputs), | 
|  | _store_inputs=False, | 
|  | ) | 
|  | else: | 
|  | check_mod = torch.jit.trace( | 
|  | func, | 
|  | _clone_inputs(inputs), | 
|  | check_trace=False, | 
|  | strict=strict, | 
|  | _force_outplace=force_outplace, | 
|  | _module_class=_module_class, | 
|  | _store_inputs=False, | 
|  | ) | 
|  | check_mod_func = check_mod | 
|  |  | 
|  | def graph_diagnostic_info(): | 
|  | mod_canonicalized = torch._C._jit_pass_canonicalize(traced_func.graph) | 
|  | torch._C._jit_pass_inline(mod_canonicalized) | 
|  | torch._C._jit_pass_erase_shape_information(mod_canonicalized) | 
|  | mod_str = str(mod_canonicalized) | 
|  | mod_str = re.sub(r"___torch_mangle_[0-9]+\.", "", mod_str) | 
|  | check_canonicalized = torch._C._jit_pass_canonicalize(check_mod_func.graph) | 
|  | torch._C._jit_pass_inline(check_canonicalized) | 
|  | torch._C._jit_pass_erase_shape_information(check_canonicalized) | 
|  | check_str = str(check_canonicalized) | 
|  | check_str = re.sub(r"___torch_mangle_[0-9]+\.", "", check_str) | 
|  |  | 
|  | graph_diff_errors = None | 
|  | if mod_str != check_str: | 
|  | import difflib | 
|  |  | 
|  | graph_diff = difflib.ndiff( | 
|  | mod_str.splitlines(True), check_str.splitlines(True) | 
|  | ) | 
|  | graph_diff_errors = "Graph diff:\n" + indent("".join(graph_diff)) + "\n" | 
|  |  | 
|  | for n_mod, n_check in zip( | 
|  | mod_canonicalized.nodes(), check_canonicalized.nodes() | 
|  | ): | 
|  | if str(n_mod) != str(n_check): | 
|  | graph_diff_errors += "First diverging operator:\n" | 
|  | node_diff = difflib.ndiff( | 
|  | str(n_mod).splitlines(True), str(n_check).splitlines(True) | 
|  | ) | 
|  | source_printout = ( | 
|  | "Node diff:\n" + indent("".join(node_diff)) + "\n" | 
|  | ) | 
|  | mod_stack = n_mod.sourceRange() | 
|  | if mod_stack: | 
|  | source_printout += ( | 
|  | "Trace source location:\n" + indent(mod_stack) + "\n" | 
|  | ) | 
|  | check_stack = n_check.sourceRange() | 
|  | if check_stack: | 
|  | source_printout += ( | 
|  | "Check source location:\n" + indent(check_stack) + "\n" | 
|  | ) | 
|  | graph_diff_errors += source_printout | 
|  |  | 
|  | break  # For now, only print out the first pair of nodes that diverges | 
|  |  | 
|  | tensor_compare_errors = None | 
|  | # Check Tensor-valued constant nodes | 
|  | for n_mod, n_check in zip( | 
|  | mod_canonicalized.nodes(), check_canonicalized.nodes() | 
|  | ): | 
|  | if n_mod.kind() != n_check.kind(): | 
|  | break  # Graphs have already diverged | 
|  |  | 
|  | if n_mod.kind() == "prim::Constant" and not ( | 
|  | n_mod.mustBeNone() or n_check.mustBeNone() | 
|  | ): | 
|  | if not n_mod.hasAttribute("value"): | 
|  | continue | 
|  | if n_mod.kindOf("value") != "t" or n_check.kindOf("value") != "t": | 
|  | continue | 
|  |  | 
|  | mod_tensor_val = n_mod.t("value") | 
|  | check_tensor_val = n_check.t("value") | 
|  |  | 
|  | try: | 
|  | torch.testing.assert_close( | 
|  | mod_tensor_val, check_tensor_val, equal_nan=True | 
|  | ) | 
|  | except (RuntimeError, AssertionError) as e: | 
|  | if tensor_compare_errors is None: | 
|  | tensor_compare_errors = "" | 
|  | tensor_compare_errors += "Node:\n" + indent(str(n_mod)) + "\n" | 
|  | compare_stack = n_mod.sourceRange() | 
|  | if compare_stack: | 
|  | tensor_compare_errors += ( | 
|  | "Source Location:\n" + indent(compare_stack) + "\n" | 
|  | ) | 
|  | tensor_compare_errors += "Comparison exception: " + indent( | 
|  | str(e) | 
|  | ) | 
|  |  | 
|  | break  # For now, only print the first diverging pair | 
|  |  | 
|  | return graph_diff_errors, tensor_compare_errors | 
|  |  | 
|  | def wrap_retval(x): | 
|  | return x if isinstance(x, tuple) else (x,) | 
|  |  | 
|  | def run_mod_and_filter_tensor_outputs(mod, inputs, running_what): | 
|  | try: | 
|  | if isinstance(inputs, dict) and example_inputs_is_kwarg: | 
|  | outs = wrap_retval(mod(**inputs)) | 
|  | else: | 
|  | outs = wrap_retval(mod(*_clone_inputs(inputs))) | 
|  | outs = [out for out in outs if isinstance(out, torch.Tensor)] | 
|  | return outs | 
|  | except Exception as e: | 
|  | graph_diff_errors, tensor_compare_errors = graph_diagnostic_info() | 
|  | msg = f"encountered an exception while running the {running_what} with test inputs.\nException:\n{indent(str(e))}" | 
|  | raise TracingCheckError( | 
|  | graph_diff_errors, | 
|  | tensor_compare_errors, | 
|  | extra_msg=msg, | 
|  | ) from e | 
|  |  | 
|  | has_warned = [False] | 
|  |  | 
|  | def maybe_warn_nondeterministic(): | 
|  | if has_warned[0]: | 
|  | return | 
|  | has_warned[0] = True | 
|  | nondeterm_ops = [ | 
|  | op for op in traced_func.graph.nodes() if op.isNondeterministic() | 
|  | ] | 
|  | if len(nondeterm_ops) > 0: | 
|  | nondeterministic_ops_warning = "Trace had nondeterministic nodes. " | 
|  | nondeterministic_ops_warning += ( | 
|  | "Did you forget call .eval() on your model? Nodes:\n" | 
|  | ) | 
|  | nondeterministic_ops_warning += "\n".join( | 
|  | [indent(str(op)) for op in nondeterm_ops][:20] | 
|  | ) | 
|  | nondeterministic_ops_warning += ( | 
|  | "\nThis may cause errors in trace checking. To disable trace checking," | 
|  | " pass check_trace=False to torch.jit.trace()" | 
|  | ) | 
|  | warnings.warn( | 
|  | nondeterministic_ops_warning, category=TracerWarning, stacklevel=5 | 
|  | ) | 
|  |  | 
|  | def compare_outputs(original, reference, match_what): | 
|  | all_ok = True | 
|  | for i, (orig, ref) in enumerate(zip(original, reference)): | 
|  | try: | 
|  | if orig.is_quantized: | 
|  | orig = orig.dequantize() | 
|  | if ref.is_quantized: | 
|  | ref = ref.dequantize() | 
|  | if orig.is_mkldnn: | 
|  | orig = orig.to_dense() | 
|  | if ref.is_mkldnn: | 
|  | ref = ref.to_dense() | 
|  | if ref.is_complex() or orig.is_complex(): | 
|  | torch.testing.assert_close( | 
|  | orig.to(torch.cdouble), | 
|  | ref.to(torch.cdouble), | 
|  | rtol=check_tolerance, | 
|  | atol=default_tolerances(orig, ref)[1], | 
|  | equal_nan=True, | 
|  | ) | 
|  | else: | 
|  | if orig.is_mps or ref.is_mps: | 
|  | torch.testing.assert_close( | 
|  | orig.float(), | 
|  | ref.float(), | 
|  | rtol=check_tolerance, | 
|  | atol=default_tolerances(orig, ref)[1], | 
|  | equal_nan=True, | 
|  | ) | 
|  | else: | 
|  | torch.testing.assert_close( | 
|  | orig.double(), | 
|  | ref.double(), | 
|  | rtol=check_tolerance, | 
|  | atol=default_tolerances(orig, ref)[1], | 
|  | equal_nan=True, | 
|  | ) | 
|  | except AssertionError as e: | 
|  | maybe_warn_nondeterministic() | 
|  | warnings.warn( | 
|  | "Output nr " | 
|  | + str(i + 1) | 
|  | + ". of the traced function does not match " | 
|  | "the corresponding output of the " | 
|  | + match_what | 
|  | + ". Detailed error:\n" | 
|  | + str(e), | 
|  | category=TracerWarning, | 
|  | stacklevel=4, | 
|  | ) | 
|  | all_ok = False | 
|  |  | 
|  | return all_ok | 
|  |  | 
|  | traced_outs = run_mod_and_filter_tensor_outputs(traced_func, inputs, "trace") | 
|  | fn_outs = run_mod_and_filter_tensor_outputs(func, inputs, "Python function") | 
|  | if compare_outputs(traced_outs, fn_outs, "Python function"): | 
|  | check_outs = run_mod_and_filter_tensor_outputs( | 
|  | check_mod_func, inputs, "repeated trace" | 
|  | ) | 
|  | compare_outputs(traced_outs, check_outs, "repeated trace") | 
|  |  | 
|  | diag_info = graph_diagnostic_info() | 
|  | if any(info is not None for info in diag_info): | 
|  | raise TracingCheckError(*diag_info) | 
|  |  | 
|  |  | 
|  | class TracerWarning(Warning): | 
|  | @staticmethod | 
|  | def ignore_lib_warnings(): | 
|  | # We ignore warnings from all submodules excluding the JIT, because we need them e.g. for _check_trace | 
|  | warnings.filterwarnings( | 
|  | "ignore", category=TracerWarning, module="torch.(?!jit)" | 
|  | ) | 
|  | warnings.filterwarnings("ignore", "torch::jit::fuser::cuda") | 
|  |  | 
|  |  | 
|  | # We ignore the tracer warnings coming form inside the library, because all our shape | 
|  | # checks in nn will trigger them. | 
|  | TracerWarning.ignore_lib_warnings() | 
|  | torch._C._tracer_warn_use_python() | 
|  |  | 
|  |  | 
|  | def make_tuple(example_inputs): | 
|  | if isinstance(example_inputs, (torch.Tensor, dict)): | 
|  | return (example_inputs,) | 
|  | # done primarily so that weird iterables fail here and not pybind11 code | 
|  | if not isinstance(example_inputs, tuple): | 
|  | return tuple(example_inputs) | 
|  | return example_inputs | 
|  |  | 
|  |  | 
|  | def make_module(mod, _module_class, _compilation_unit): | 
|  | if isinstance(mod, ScriptModule): | 
|  | return mod | 
|  | elif torch._jit_internal.module_has_exports(mod): | 
|  | infer_methods_stubs_fn = torch.jit._recursive.make_stubs_from_exported_methods | 
|  | return torch.jit._recursive.create_script_module( | 
|  | mod, infer_methods_stubs_fn, share_types=False, is_tracing=True | 
|  | ) | 
|  | else: | 
|  | if _module_class is None: | 
|  | _module_class = TopLevelTracedModule | 
|  | return _module_class(mod, _compilation_unit=_compilation_unit) | 
|  |  | 
|  |  | 
|  | def wrap_check_inputs(check_inputs): | 
|  | if check_inputs is None: | 
|  | return None | 
|  |  | 
|  | return [{"forward": c} for c in check_inputs] | 
|  |  | 
|  |  | 
|  | def trace( | 
|  | func, | 
|  | example_inputs=None, | 
|  | optimize=None, | 
|  | check_trace=True, | 
|  | check_inputs=None, | 
|  | check_tolerance=1e-5, | 
|  | strict=True, | 
|  | _force_outplace=False, | 
|  | _module_class=None, | 
|  | _compilation_unit=_python_cu, | 
|  | example_kwarg_inputs=None, | 
|  | _store_inputs=True, | 
|  | ): | 
|  | r""" | 
|  | Trace a function and return an executable  or :class:`ScriptFunction` that will be optimized using just-in-time compilation. | 
|  |  | 
|  | Tracing is ideal for code that operates only on | 
|  | ``Tensor``\\s and lists, dictionaries, and | 
|  | tuples of ``Tensor``\\s. | 
|  |  | 
|  | Using `torch.jit.trace` and `torch.jit.trace_module`, you can turn an | 
|  | existing module or Python function into a TorchScript | 
|  | :class:`ScriptFunction` or :class:`ScriptModule`. You must provide example | 
|  | inputs, and we run the function, recording the operations performed on all | 
|  | the tensors. | 
|  |  | 
|  | * The resulting recording of a standalone function produces `ScriptFunction`. | 
|  | * The resulting recording of `nn.Module.forward` or `nn.Module` produces | 
|  | `ScriptModule`. | 
|  |  | 
|  | This module also contains any parameters that the original | 
|  | module had as well. | 
|  |  | 
|  | Warning: | 
|  | Tracing only correctly records functions and modules which are not data | 
|  | dependent (e.g., do not have conditionals on data in tensors) and do not have | 
|  | any untracked external dependencies (e.g., perform input/output or | 
|  | access global variables). Tracing only records operations done when the given | 
|  | function is run on the given tensors. Therefore, the returned | 
|  | `ScriptModule` will always run the same traced graph on any input. This | 
|  | has some important implications when your module is expected to run | 
|  | different sets of operations, depending on the input and/or the module | 
|  | state. For example, | 
|  |  | 
|  | * Tracing will not record any control-flow like if-statements or loops. | 
|  | When this control-flow is constant across your module, this is fine | 
|  | and it often inlines the control-flow decisions. But sometimes the | 
|  | control-flow is actually part of the model itself. For instance, a | 
|  | recurrent network is a loop over the (possibly dynamic) length of an | 
|  | input sequence. | 
|  | * In the returned :class:`ScriptModule`, operations that have different | 
|  | behaviors in ``training`` and ``eval`` modes will always behave as if | 
|  | it is in the mode it was in during tracing, no matter which mode the | 
|  | `ScriptModule` is in. | 
|  |  | 
|  | In cases like these, tracing would not be appropriate and | 
|  | :func:`scripting <torch.jit.script>` is a better choice. If you trace | 
|  | such models, you may silently get incorrect results on subsequent | 
|  | invocations of the model. The tracer will try to emit warnings when | 
|  | doing something that may cause an incorrect trace to be produced. | 
|  |  | 
|  | Args: | 
|  | func (callable or torch.nn.Module):  A Python function or `torch.nn.Module` | 
|  | that will be run with `example_inputs`. `func` arguments and return | 
|  | values  must be tensors or (possibly nested) tuples that contain | 
|  | tensors. When a module is passed `torch.jit.trace`, only the | 
|  | ``forward`` method is run and traced (see :func:`torch.jit.trace | 
|  | <torch.jit.trace_module>` for details). | 
|  |  | 
|  | Keyword arguments: | 
|  | example_inputs (tuple or torch.Tensor or None, optional): A tuple of example | 
|  | inputs that will be passed to the function while tracing. | 
|  | Default: ``None``. Either this argument or ``example_kwarg_inputs`` | 
|  | should be specified. The resulting trace can be run with inputs of | 
|  | different types and shapes assuming the traced operations support those | 
|  | types and shapes. `example_inputs` may also be a single Tensor in which | 
|  | case it is automatically wrapped in a tuple. When the value is None, | 
|  | ``example_kwarg_inputs`` should be specified. | 
|  |  | 
|  | check_trace (``bool``, optional): Check if the same inputs run through | 
|  | traced code produce the same outputs. Default: ``True``. You might want | 
|  | to disable this if, for example, your network contains non- | 
|  | deterministic ops or if you are sure that the network is correct despite | 
|  | a checker failure. | 
|  |  | 
|  | check_inputs (list of tuples, optional): A list of tuples of input | 
|  | arguments that should be used to check the trace against what is | 
|  | expected. Each tuple is equivalent to a set of input arguments that | 
|  | would be specified in ``example_inputs``. For best results, pass in | 
|  | a set of checking inputs representative of the space of shapes and | 
|  | types of inputs you expect the network to see.  If not specified, | 
|  | the original ``example_inputs`` are used for checking | 
|  | check_tolerance (float, optional): Floating-point comparison tolerance | 
|  | to use in the checker procedure.  This can be used to relax the | 
|  | checker strictness in the event that results diverge numerically | 
|  | for a known reason, such as operator fusion. | 
|  | strict (``bool``, optional): run the tracer in a strict mode or not | 
|  | (default: ``True``). Only turn this off when you want the tracer to | 
|  | record your mutable container types (currently ``list``/``dict``) | 
|  | and you are sure that the container you are using in your | 
|  | problem is a ``constant`` structure and does not get used as | 
|  | control flow (if, for) conditions. | 
|  | example_kwarg_inputs (dict, optional): This parameter is a pack of keyword | 
|  | arguments of example inputs that will be passed to the function while | 
|  | tracing. Default: ``None``. Either this argument or ``example_inputs`` | 
|  | should be specified. The dict will be unpacking by the arguments name | 
|  | of the traced function. If the keys of the dict don't not match with | 
|  | the traced function's arguments name, a runtime exception will be raised. | 
|  |  | 
|  | Returns: | 
|  | If `func` is `nn.Module` or ``forward`` of `nn.Module`, `trace` returns | 
|  | a :class:`ScriptModule` object with a single ``forward`` method | 
|  | containing the traced code.  The returned `ScriptModule` will | 
|  | have the same set of sub-modules and parameters as the original | 
|  | ``nn.Module``.  If ``func`` is a standalone function, ``trace`` | 
|  | returns `ScriptFunction`. | 
|  |  | 
|  | Example (tracing a function): | 
|  |  | 
|  | .. testcode:: | 
|  |  | 
|  | import torch | 
|  |  | 
|  | def foo(x, y): | 
|  | return 2 * x + y | 
|  |  | 
|  | # Run `foo` with the provided inputs and record the tensor operations | 
|  | traced_foo = torch.jit.trace(foo, (torch.rand(3), torch.rand(3))) | 
|  |  | 
|  | # `traced_foo` can now be run with the TorchScript interpreter or saved | 
|  | # and loaded in a Python-free environment | 
|  |  | 
|  | Example (tracing an existing module):: | 
|  |  | 
|  | import torch | 
|  | import torch.nn as nn | 
|  |  | 
|  | class Net(nn.Module): | 
|  | def __init__(self): | 
|  | super().__init__() | 
|  | self.conv = nn.Conv2d(1, 1, 3) | 
|  |  | 
|  | def forward(self, x): | 
|  | return self.conv(x) | 
|  |  | 
|  | n = Net() | 
|  | example_weight = torch.rand(1, 1, 3, 3) | 
|  | example_forward_input = torch.rand(1, 1, 3, 3) | 
|  |  | 
|  | # Trace a specific method and construct `ScriptModule` with | 
|  | # a single `forward` method | 
|  | module = torch.jit.trace(n.forward, example_forward_input) | 
|  |  | 
|  | # Trace a module (implicitly traces `forward`) and construct a | 
|  | # `ScriptModule` with a single `forward` method | 
|  | module = torch.jit.trace(n, example_forward_input) | 
|  |  | 
|  | """ | 
|  | if not _enabled: | 
|  | return func | 
|  | if optimize is not None: | 
|  | warnings.warn( | 
|  | "`optimize` is deprecated and has no effect. Use `with torch.jit.optimized_execution() instead" | 
|  | ) | 
|  |  | 
|  | if isinstance(func, torch.jit.ScriptModule): | 
|  | # it is hard to trace it because the forward method on ScriptModule is already defined, so it | 
|  | # would result in an error. | 
|  | warnings.warn( | 
|  | "The input to trace is already a ScriptModule, tracing it is a no-op. Returning the object as is." | 
|  | ) | 
|  | return func | 
|  |  | 
|  | if isinstance(func, torch.nn.Module): | 
|  | if example_inputs is None: | 
|  | if isinstance(example_kwarg_inputs, dict): | 
|  | example_inputs = example_kwarg_inputs | 
|  | else: | 
|  | raise RuntimeError("example_kwarg_inputs should be a dict") | 
|  | return trace_module( | 
|  | func, | 
|  | {"forward": example_inputs}, | 
|  | None, | 
|  | check_trace, | 
|  | wrap_check_inputs(check_inputs), | 
|  | check_tolerance, | 
|  | strict, | 
|  | _force_outplace, | 
|  | _module_class, | 
|  | example_inputs_is_kwarg=isinstance(example_kwarg_inputs, dict), | 
|  | _store_inputs=_store_inputs, | 
|  | ) | 
|  | if ( | 
|  | hasattr(func, "__self__") | 
|  | and isinstance(func.__self__, torch.nn.Module) | 
|  | and func.__name__ == "forward" | 
|  | ): | 
|  | if example_inputs is None: | 
|  | if isinstance(example_kwarg_inputs, dict): | 
|  | example_inputs = example_kwarg_inputs | 
|  | else: | 
|  | raise RuntimeError("example_kwarg_inputs should be a dict") | 
|  | return trace_module( | 
|  | func.__self__, | 
|  | {"forward": example_inputs}, | 
|  | None, | 
|  | check_trace, | 
|  | wrap_check_inputs(check_inputs), | 
|  | check_tolerance, | 
|  | strict, | 
|  | _force_outplace, | 
|  | _module_class, | 
|  | example_inputs_is_kwarg=isinstance(example_kwarg_inputs, dict), | 
|  | _store_inputs=_store_inputs, | 
|  | ) | 
|  |  | 
|  | # Special case for common case of passing a single Tensor | 
|  | if ( | 
|  | isinstance(example_inputs, (torch.Tensor, dict)) | 
|  | and example_kwarg_inputs is None | 
|  | ): | 
|  | example_inputs = (example_inputs,) | 
|  | # done primarily so that weird iterables fail here and not pybind11 code | 
|  | elif example_kwarg_inputs is None and not isinstance(example_inputs, tuple): | 
|  | example_inputs = tuple(example_inputs) | 
|  |  | 
|  | var_lookup_fn = _create_interpreter_name_lookup_fn(0) | 
|  |  | 
|  | if hasattr(func, "__self__") and isinstance(func.__self__, torch.nn.Module): | 
|  | raise AttributeError( | 
|  | "trace doesn't support compiling individual module's functions.\n" | 
|  | "Please use trace_module" | 
|  | ) | 
|  |  | 
|  | name = _qualified_name(func) | 
|  | if isinstance(example_kwarg_inputs, dict): | 
|  | example_inputs = example_kwarg_inputs | 
|  | traced = torch._C._create_function_from_trace_with_dict( | 
|  | name, | 
|  | func, | 
|  | example_kwarg_inputs, | 
|  | var_lookup_fn, | 
|  | strict, | 
|  | _force_outplace, | 
|  | get_callable_argument_names(func), | 
|  | ) | 
|  | else: | 
|  | traced = torch._C._create_function_from_trace( | 
|  | name, | 
|  | func, | 
|  | example_inputs, | 
|  | var_lookup_fn, | 
|  | strict, | 
|  | _force_outplace, | 
|  | get_callable_argument_names(func), | 
|  | ) | 
|  |  | 
|  | # Check the trace against new traces created from user-specified inputs | 
|  | if check_trace: | 
|  | if check_inputs is not None: | 
|  | _check_trace( | 
|  | check_inputs, | 
|  | func, | 
|  | traced, | 
|  | check_tolerance, | 
|  | strict, | 
|  | _force_outplace, | 
|  | False, | 
|  | _module_class, | 
|  | example_inputs_is_kwarg=isinstance(example_kwarg_inputs, dict), | 
|  | ) | 
|  | else: | 
|  | _check_trace( | 
|  | [example_inputs], | 
|  | func, | 
|  | traced, | 
|  | check_tolerance, | 
|  | strict, | 
|  | _force_outplace, | 
|  | False, | 
|  | _module_class, | 
|  | example_inputs_is_kwarg=isinstance(example_kwarg_inputs, dict), | 
|  | ) | 
|  |  | 
|  | # Allow torch.compile() to inline | 
|  | traced._torchdynamo_inline = func  # type: ignore[attr-defined] | 
|  | return traced | 
|  |  | 
|  |  | 
|  | _trace_module_map: Optional[Dict[Any, Any]] = None | 
|  |  | 
|  |  | 
|  | def trace_module( | 
|  | mod, | 
|  | inputs, | 
|  | optimize=None, | 
|  | check_trace=True, | 
|  | check_inputs=None, | 
|  | check_tolerance=1e-5, | 
|  | strict=True, | 
|  | _force_outplace=False, | 
|  | _module_class=None, | 
|  | _compilation_unit=_python_cu, | 
|  | example_inputs_is_kwarg=False, | 
|  | _store_inputs=True, | 
|  | ): | 
|  | """ | 
|  | Trace a module and return an executable :class:`ScriptModule` that will be optimized using just-in-time compilation. | 
|  |  | 
|  | When a module is passed to :func:`torch.jit.trace <torch.jit.trace>`, only | 
|  | the ``forward`` method is run and traced. With ``trace_module``, you can specify a dictionary of | 
|  | method names to example inputs to trace (see the ``inputs``) argument below. | 
|  |  | 
|  | See :func:`torch.jit.trace <torch.jit.trace>` for more information on tracing. | 
|  |  | 
|  | Args: | 
|  | mod (torch.nn.Module):  A ``torch.nn.Module`` containing methods whose names are | 
|  | specified in ``inputs``. The given methods will be compiled | 
|  | as a part of a single `ScriptModule`. | 
|  | inputs (dict):  A dict containing sample inputs indexed by method names in ``mod``. | 
|  | The inputs will be passed to methods whose names correspond to inputs' | 
|  | keys while tracing. | 
|  | ``{ 'forward' : example_forward_input, 'method2': example_method2_input}`` | 
|  | Keyword arguments: | 
|  | check_trace (``bool``, optional): Check if the same inputs run through | 
|  | traced code produce the same outputs. Default: ``True``. You might want | 
|  | to disable this if, for example, your network contains non- | 
|  | deterministic ops or if you are sure that the network is correct despite | 
|  | a checker failure. | 
|  |  | 
|  | check_inputs (list of dicts, optional): A list of dicts of input arguments that should be used | 
|  | to check the trace against what is expected. Each tuple | 
|  | is equivalent to a set of input arguments that would | 
|  | be specified in ``inputs``. For best results, pass in a | 
|  | set of checking inputs representative of the space of | 
|  | shapes and types of inputs you expect the network to see. | 
|  | If not specified, the original ``inputs`` are used for checking | 
|  | check_tolerance (float, optional): Floating-point comparison tolerance to use in the checker procedure. | 
|  | This can be used to relax the checker strictness in the event that | 
|  | results diverge numerically for a known reason, such as operator fusion. | 
|  | example_inputs_is_kwarg (``bool``, optional): This parameter indicate whether the example inputs is a pack | 
|  | pack of keyword arguments. Default: ``False``. | 
|  |  | 
|  | Returns: | 
|  | A :class:`ScriptModule` object with a single ``forward`` method containing the traced code. | 
|  | When ``func`` is a ``torch.nn.Module``, the returned :class:`ScriptModule` will have the same set of | 
|  | sub-modules and parameters as ``func``. | 
|  |  | 
|  | Example (tracing a module with multiple methods):: | 
|  |  | 
|  | import torch | 
|  | import torch.nn as nn | 
|  |  | 
|  | class Net(nn.Module): | 
|  | def __init__(self): | 
|  | super().__init__() | 
|  | self.conv = nn.Conv2d(1, 1, 3) | 
|  |  | 
|  | def forward(self, x): | 
|  | return self.conv(x) | 
|  |  | 
|  | def weighted_kernel_sum(self, weight): | 
|  | return weight * self.conv.weight | 
|  |  | 
|  |  | 
|  | n = Net() | 
|  | example_weight = torch.rand(1, 1, 3, 3) | 
|  | example_forward_input = torch.rand(1, 1, 3, 3) | 
|  |  | 
|  | # Trace a specific method and construct `ScriptModule` with | 
|  | # a single `forward` method | 
|  | module = torch.jit.trace(n.forward, example_forward_input) | 
|  |  | 
|  | # Trace a module (implicitly traces `forward`) and construct a | 
|  | # `ScriptModule` with a single `forward` method | 
|  | module = torch.jit.trace(n, example_forward_input) | 
|  |  | 
|  | # Trace specific methods on a module (specified in `inputs`), constructs | 
|  | # a `ScriptModule` with `forward` and `weighted_kernel_sum` methods | 
|  | inputs = {'forward' : example_forward_input, 'weighted_kernel_sum' : example_weight} | 
|  | module = torch.jit.trace_module(n, inputs) | 
|  |  | 
|  | """ | 
|  | if not _enabled: | 
|  | return mod | 
|  | if optimize is not None: | 
|  | warnings.warn( | 
|  | "`optimize` is deprecated and has no effect. Use `with torch.jit.optimized_execution() instead" | 
|  | ) | 
|  |  | 
|  | var_lookup_fn = _create_interpreter_name_lookup_fn(0) | 
|  |  | 
|  | if not isinstance(mod, torch.nn.Module): | 
|  | raise AttributeError("expected torch.nn.Module as the first argument") | 
|  |  | 
|  | if not isinstance(inputs, dict): | 
|  | raise AttributeError("expected a dictionary of (method_name, input) pairs") | 
|  |  | 
|  | old_module_map = torch.jit._trace._trace_module_map | 
|  | try: | 
|  | trace_module_map: Dict[Any, Any] = {} | 
|  |  | 
|  | def register_submods(mod, prefix): | 
|  | for name, child in mod.named_children(): | 
|  | submod_qualname = prefix + "." + name | 
|  | trace_module_map[child] = submod_qualname | 
|  | register_submods(child, submod_qualname) | 
|  |  | 
|  | trace_module_map["__module"] = mod | 
|  | torch.jit._trace._trace_module_map = trace_module_map | 
|  | register_submods(mod, "__module") | 
|  |  | 
|  | module = make_module(mod, _module_class, _compilation_unit) | 
|  |  | 
|  | for method_name, example_inputs in inputs.items(): | 
|  | if method_name == "forward": | 
|  | # "forward" is a special case because we need to trace | 
|  | # `Module.__call__`, which sets up some extra tracing, but uses | 
|  | # argument names of the real `Module.forward` method. | 
|  | func = mod | 
|  | forward_method = getattr(mod, method_name) | 
|  | argument_names = get_callable_argument_names(forward_method) | 
|  | else: | 
|  | func = getattr(mod, method_name) | 
|  | argument_names = get_callable_argument_names(func) | 
|  |  | 
|  | if isinstance(example_inputs, dict) and example_inputs_is_kwarg: | 
|  | # Raise exception when the user provided key names are not aligned with forward() method's arguments' name/ | 
|  | for key in example_inputs: | 
|  | if key not in argument_names: | 
|  | valid_arguments = "[" + ",".join(argument_names) + "]" | 
|  | raise NameError( | 
|  | f"""'{key}' is not in forward() method's arguments, | 
|  | valid arguments name are {valid_arguments}""" | 
|  | ) | 
|  | module._c._create_method_from_trace_with_dict( | 
|  | method_name, | 
|  | func, | 
|  | example_inputs, | 
|  | var_lookup_fn, | 
|  | strict, | 
|  | _force_outplace, | 
|  | argument_names, | 
|  | _store_inputs, | 
|  | ) | 
|  | else: | 
|  | example_inputs = make_tuple(example_inputs) | 
|  | module._c._create_method_from_trace( | 
|  | method_name, | 
|  | func, | 
|  | example_inputs, | 
|  | var_lookup_fn, | 
|  | strict, | 
|  | _force_outplace, | 
|  | argument_names, | 
|  | _store_inputs, | 
|  | ) | 
|  |  | 
|  | check_trace_method = module._c._get_method(method_name) | 
|  |  | 
|  | # Check the trace against new traces created from user-specified inputs | 
|  | if check_trace: | 
|  | if check_inputs is not None: | 
|  | _check_trace( | 
|  | check_inputs, | 
|  | func, | 
|  | check_trace_method, | 
|  | check_tolerance, | 
|  | strict, | 
|  | _force_outplace, | 
|  | True, | 
|  | _module_class, | 
|  | example_inputs_is_kwarg=example_inputs_is_kwarg, | 
|  | ) | 
|  | else: | 
|  | _check_trace( | 
|  | [inputs], | 
|  | func, | 
|  | check_trace_method, | 
|  | check_tolerance, | 
|  | strict, | 
|  | _force_outplace, | 
|  | True, | 
|  | _module_class, | 
|  | example_inputs_is_kwarg=example_inputs_is_kwarg, | 
|  | ) | 
|  | finally: | 
|  | torch.jit._trace._trace_module_map = old_module_map | 
|  |  | 
|  | return module | 
|  |  | 
|  |  | 
|  | def is_tracing(): | 
|  | """Return a boolean value. | 
|  |  | 
|  | Returns ``True`` in tracing (if a function is called during the | 
|  | tracing of code with ``torch.jit.trace``) and ``False`` otherwise. | 
|  | """ | 
|  | if is_scripting(): | 
|  | return False | 
|  | return torch._C._is_tracing() | 
|  |  | 
|  |  | 
|  | class TracedModule(ScriptModule): | 
|  | _disable_script_meta = True | 
|  |  | 
|  | def __init__(self, orig, id_set=None, _compilation_unit=None): | 
|  | # XXX: orig can be a nn.Module or a function! | 
|  | super().__init__() | 
|  | assert isinstance(orig, torch.nn.Module) | 
|  |  | 
|  | # Copy a subset of `orig` to a temporary nn.Module. | 
|  | # This is a way to customize what will actually get compiled by create_script_module | 
|  | id_set = set() | 
|  |  | 
|  | # This allows us to preserve the original module's qualified name by defining a new | 
|  | # type with the attribute _jit_override_qualname. In torch._jit_internal._qualified_name | 
|  | # we have a special case that will look up this attribute to override whatever qualname | 
|  | # we would get from the python type system | 
|  | class QualnameWrapper(torch.nn.Module): | 
|  | pass | 
|  |  | 
|  | QualnameWrapper._jit_override_qualname = torch._jit_internal._qualified_name(  # type: ignore[attr-defined] | 
|  | type(orig) | 
|  | ) | 
|  |  | 
|  | tmp_module = QualnameWrapper() | 
|  |  | 
|  | def check_unique(param): | 
|  | if param in id_set: | 
|  | raise ValueError( | 
|  | "TracedModules don't support parameter sharing between modules" | 
|  | ) | 
|  | id_set.add(param) | 
|  |  | 
|  | tmp_module.training = orig.training | 
|  |  | 
|  | for name, param in orig._parameters.items(): | 
|  | if param is not None: | 
|  | tmp_module._parameters[name] = param | 
|  | check_unique(param) | 
|  | for name, buf in orig._buffers.items(): | 
|  | if buf is not None: | 
|  | tmp_module._buffers[name] = buf | 
|  | check_unique(buf) | 
|  | for name, val in orig.__dict__.items(): | 
|  | if ( | 
|  | torch._C._jit_is_script_object(val) | 
|  | and name not in orig._parameters | 
|  | and name not in orig._buffers | 
|  | ): | 
|  | setattr(tmp_module, name, val) | 
|  |  | 
|  | if orig._backward_hooks: | 
|  | raise ValueError( | 
|  | "Modules that have backward hooks assigned can't be compiled: " | 
|  | + str(orig) | 
|  | ) | 
|  |  | 
|  | for name, submodule in orig._modules.items(): | 
|  | if submodule is None: | 
|  | continue | 
|  | tmp_module._modules[name] = make_module( | 
|  | submodule, TracedModule, _compilation_unit=None | 
|  | ) | 
|  |  | 
|  | script_module = torch.jit._recursive.create_script_module( | 
|  | tmp_module, lambda module: (), share_types=False, is_tracing=True | 
|  | ) | 
|  |  | 
|  | self.__dict__["_name"] = type(orig).__name__ | 
|  | self.__dict__["_actual_script_module"] = script_module | 
|  | for name in ("_parameters", "_buffers", "_modules", "training"): | 
|  | delattr(self, name) | 
|  |  | 
|  | def forward(self, *args, **kwargs): | 
|  | raise RuntimeError("Trace submodules cannot be called.") | 
|  |  | 
|  | def __getattr__(self, attr): | 
|  | if "_actual_script_module" not in self.__dict__: | 
|  | return super().__getattr__(attr) | 
|  | return getattr(self._actual_script_module, attr) | 
|  |  | 
|  | def __setattr__(self, attr, value): | 
|  | if "_actual_script_module" not in self.__dict__: | 
|  | return super().__setattr__(attr, value) | 
|  | setattr(self._actual_script_module, attr, value) | 
|  |  | 
|  | def _get_name(self): | 
|  | return self._name | 
|  |  | 
|  | def extra_repr(self): | 
|  | return f"original_name={self._name}" | 
|  |  | 
|  |  | 
|  | class TopLevelTracedModule(TracedModule): | 
|  | forward: Callable[..., Any] = _CachedForward()  # type: ignore[assignment] | 
|  |  | 
|  | def _reconstruct(self, cpp_module): | 
|  | """ | 
|  | Re-construct an instance of TopLevelTracedModule using an instance of a C++ module. | 
|  |  | 
|  | Args: | 
|  | cpp_module: The C++ module that this TopLevelTracedModule will be rebuilt around. | 
|  | """ | 
|  | self.__dict__["_actual_script_module"]._reconstruct(cpp_module) | 
|  |  | 
|  |  | 
|  | def _script_if_tracing(fn: Callable[P, R]) -> Callable[P, R]: | 
|  | @functools.wraps(fn) | 
|  | def wrapper(*args: P.args, **kwargs: P.kwargs) -> R: | 
|  | if not is_tracing(): | 
|  | # Not tracing, don't do anything | 
|  | return fn(*args, **kwargs) | 
|  |  | 
|  | compiled_fn: Callable[P, R] = script(wrapper.__original_fn)  # type: ignore[attr-defined] | 
|  | return compiled_fn(*args, **kwargs) | 
|  |  | 
|  | wrapper.__original_fn = fn  # type: ignore[attr-defined] | 
|  | wrapper.__script_if_tracing_wrapper = True  # type: ignore[attr-defined] | 
|  |  | 
|  | return wrapper | 
|  |  | 
|  |  | 
|  | def _get_trace_graph( | 
|  | f, | 
|  | args=(), | 
|  | kwargs=None, | 
|  | strict=True, | 
|  | _force_outplace=False, | 
|  | return_inputs=False, | 
|  | _return_inputs_states=False, | 
|  | ): | 
|  | """Return a tuple on tracing a function or model. | 
|  |  | 
|  | .. warning:: | 
|  | This function is internal-only and should only be used by the ONNX | 
|  | exporter. If you are trying to get a graph through tracing, please go | 
|  | through the public API instead:: | 
|  |  | 
|  | trace = torch.jit.trace(nn.LSTMCell(), (input, hidden)) | 
|  | trace_graph = trace.graph | 
|  |  | 
|  | Trace a function or model, returning a tuple consisting of the both the | 
|  | *trace* of an execution, as well as the original return value. If return_inputs, | 
|  | also returns the trace inputs as part of the tuple | 
|  |  | 
|  | Tracing is guaranteed not to change the semantics of the function/module | 
|  | that is traced. | 
|  |  | 
|  | Args: | 
|  | f (torch.nn.Module or function): the function or module | 
|  | to be traced. | 
|  | args (tuple or Tensor): the positional arguments to pass to the | 
|  | function/module to be traced.  A non-tuple is assumed to | 
|  | be a single positional argument to be passed to the model. | 
|  | kwargs (dict): the keyword arguments to pass to the function/module | 
|  | to be traced. | 
|  |  | 
|  | Example (trace a cell): | 
|  |  | 
|  | .. testcode:: | 
|  |  | 
|  | trace = torch.jit.trace(nn.LSTMCell(), (input, hidden)) | 
|  | """ | 
|  | if kwargs is None: | 
|  | kwargs = {} | 
|  | if not isinstance(args, tuple): | 
|  | args = (args,) | 
|  | outs = ONNXTracedModule( | 
|  | f, strict, _force_outplace, return_inputs, _return_inputs_states | 
|  | )(*args, **kwargs) | 
|  | return outs |