pytorch/torch/csrc
Edward Z. Yang f7365eca90 Add unbacked symints support; item works now (#90624)
The big idea is to add `create_unbacked_symfloat` and `create_unbacked_symint` to ShapeEnv, allowing you to allocate symbolic floats/ints corresponding to data you don't know about at compile time. Then, instead of immediately erroring out when you try to call local_scalar_dense on a FakeTensor, we instead create a fresh symint/symfloat and return that.

There a bunch of odds and ends that need to be handled:

* A number of `numel` calls converted to `sym_numel`
* When we finally return from item(), we need to ensure we actually produce a SymInt/SymFloat when appropriate. The previous binding code assumed that you would have to get a normal Python item. I add a pybind11 binding for Scalar (to PyObject only) and refactor the code to use that. There is some trickiness where you are NOT allowed to go through c10::SymInt if there isn't actually any SymInt involved. See comment.
* One of our unit tests tripped an implicit data dependent access which occurs when you pass a Tensor as an argument to a sizes parameter. This is also converted to support symbolic shapes
* We now support tracking bare SymInt/SymFloat returns in proxy tensor mode (this was already in symbolic-shapes branch)
* Whenever we allocate an unbacked symint, we record the stack trace it was allocated at. These get printed when you attempt data dependent access on the symint (e.g., you try to guard on it)
* Subtlety: unbacked symints are not necessarily > 1. I added a test for this.

These unbacked symints are not very useful right now as you will almost always immediately raise an error later when you try to guard on them. The next logical step is adding an assertion refinement system that lets ShapeEnv learn facts about unbacked symints so it can do a better job eliding guards that are unnecessary.

Signed-off-by: Edward Z. Yang <ezyang@fb.com>
Pull Request resolved: https://github.com/pytorch/pytorch/pull/90624
Approved by: https://github.com/Skylion007, https://github.com/voznesenskym
2022-12-12 13:33:07 +00:00
..
api Fix typos in messages under torch (#88961) 2022-11-14 19:06:41 +00:00
autograd SymIntify resize_ and deduplicate memory format logic (#90442) 2022-12-11 14:38:38 +00:00
cuda Reserve space for std::vector output in extract_tensors for nccl python bindings (#88203) 2022-12-10 20:28:19 +00:00
deploy Delete torch::deploy from pytorch core (#85953) 2022-10-06 07:20:16 +00:00
distributed Fix a static initialization order fiasco in c10d (#90149) 2022-12-12 08:21:54 +00:00
dynamo Most recently used cache management for TorchDynamo (#88076) 2022-11-08 18:46:59 +00:00
functorch functorch.grad support for autograd.Function (#89860) 2022-12-08 19:31:04 +00:00
jit Clean up dependancy for flatbuffer_loader (#86041) 2022-12-08 03:48:04 +00:00
lazy Add unbacked symints support; item works now (#90624) 2022-12-12 13:33:07 +00:00
monitor
multiprocessing
onnx [ONNX] Improve diagnostic message formatting (#87830) 2022-11-10 21:42:17 +00:00
profiler Remove deprecated usage of is_pod/is_pod_v (#88918) 2022-12-05 16:50:00 +00:00
tensor Updated invalid type error message to explicitly say only float types… (#83170) 2022-09-12 21:15:04 +00:00
utils Add unbacked symints support; item works now (#90624) 2022-12-12 13:33:07 +00:00
copy_utils.h
CudaIPCTypes.cpp Check all CUDA API calls for errors in torch/ (#81560) 2022-10-28 00:40:48 +00:00
CudaIPCTypes.h
DataLoader.cpp
DataLoader.h
Device.cpp
Device.h
Dtype.cpp
Dtype.h
DynamicTypes.cpp first draft of input mutation handling for aot autograd (#88817) 2022-11-23 19:20:11 +00:00
DynamicTypes.h Add tests for custom pybind type_casters (#89897) 2022-12-02 07:02:09 +00:00
empty.c
Exceptions.cpp Add torch.distributed.DistBackendError exception type, thrown from C10D_NCCL_CHECK (#88134) 2022-11-08 13:26:42 +00:00
Exceptions.h wrap_pybind_function: support member function pointers (#88932) 2022-11-14 18:47:34 +00:00
Export.h
Generator.cpp
Generator.h
init_flatbuffer_module.cpp Clean up dependancy for flatbuffer_loader (#86041) 2022-12-08 03:48:04 +00:00
itt_wrapper.cpp [Profiler][Minor] Group and consolidate stub APIs (#85510) 2022-10-14 05:38:46 +00:00
itt_wrapper.h Fix ITT unit-tests if PyTorch is compiled with USE_ITT=OFF (#86199) 2022-10-04 21:57:05 +00:00
itt.cpp Fix ITT unit-tests if PyTorch is compiled with USE_ITT=OFF (#86199) 2022-10-04 21:57:05 +00:00
Layout.cpp
Layout.h
MemoryFormat.cpp
MemoryFormat.h
Module.cpp [vmap] Prepend "legacy" to files for old vmap implementation (#90324) 2022-12-07 18:46:15 +00:00
Module.h
python_dimname.cpp
python_dimname.h
python_headers.h
PythonTypes.h
QScheme.cpp
QScheme.h
README.md
serialization.cpp add XPU backend to support torch.save and torch.load (#89679) 2022-11-30 20:38:02 +00:00
serialization.h
Size.cpp Unify SymIntNode and SymFloatNode into SymNode (#87817) 2022-10-27 20:56:02 +00:00
Size.h
Storage.cpp
Storage.h
StorageMethods.cpp Reland 2 Many symintifications (#87604) (#87980) 2022-10-28 13:40:11 +00:00
StorageMethods.h
StorageSharing.cpp Release GIL when doing shared memory copies on Tensors (#85389) 2022-09-29 14:17:05 +00:00
StorageSharing.h
Stream.cpp
Stream.h
stub_with_flatbuffer.c
stub.c
THConcat.h
THP.h
TypeInfo.cpp
TypeInfo.h
Types.h
utils.cpp SymIntArrayRef type caster (#89074) 2022-11-16 14:02:39 +00:00
utils.h

csrc

The csrc directory contains all of the code concerned with integration with Python. This is in contrast to lib, which contains the Torch libraries that are Python agnostic. csrc depends on lib, but not vice versa.

There are a number of utilities for easing integration with Python which are worth knowing about, which we briefly describe here. But the most important gotchas:

  • DO NOT forget to take out the GIL with pybind11::gil_scoped_acquire before calling Python API or bringing a THPObjectPtr into scope.

  • Make sure you include Python.h first in your header files, before any system headers; otherwise, you will get error: "_XOPEN_SOURCE" redefined error. If you pay attention to warnings, you will see where you need to do this.

Notes

Note [Storage is not nullptr]

Historically, Torch supported nullptr storage, as a minor optimization to avoid having to allocate a storage object when it would be empty. However, this is actually a confusing special case to deal with, so by-in-large, PyTorch assumes that, in fact, storage is never nullptr.

One important case where this assumption is important is when tracking the CUDA device a tensor is stored in: this information is stored solely in the storage, so if a storage is nullptr, we lose this information.

Although storage is never nullptr, the data field of c10::StorageImpl may be nullptr. This mostly occurs when we want to pre-allocate an output tensor struct, but then have it be resized and filled with data by some operator: there's no point in allocating data for it in this case!

Files

Exceptions.h

Frequently when working with the Python API, you may call a function which returns an error. In this case, we want to return directly to the Python interpreter, so that this exception can be propagated accordingly; however, because the Python API is C-based, what actually will happen is it will return control to whatever C++ code called it. Similarly, if we raise a C++ exception, prior to returning to the Python interpreter, we must set the Python error flags, so it turns into a C++ exception.

Moreover, when using the following macros, the generated warnings will be converted into python warnings that can be caught by the user.

Exceptions define helpers for two main cases:

  • For code where you write the python binding by hand, HANDLE_TH_ERRORS, END_HANDLE_TH_ERRORS and an exception class python_error. You call them like this:
// Entry point from Python interpreter
PyObject* run(PyObject* arg) {
  HANDLE_TH_ERRORS
  ...
  if (!x) throw python_error();
  // From c10/Exception.h
  TORCH_CHECK(cond, "cond was false here");
  TORCH_WARN("Warning message");
  ...
  END_HANDLE_TH_ERRORS
}

The HANDLE_TH_ERRORS macro will catch all exceptions and convert them into an appropriate Python signal. python_error is a special exception which doesn't contain any info, instead it says, "An error occurred in the Python API; if you return to the interpreter, Python will raise that exception, nothing else needs to be done."

  • For code that you bind using pybind, HANDLE_TH_ERRORS and END_HANDLE_TH_ERRORS_PYBIND can be used. They will work jointly with pybind error handling to raise pytorch errors and warnings natively and let pybind handle other errors. It can be used as:
// Function given to the pybind binding
at::Tensor foo(at::Tensor x) {
  HANDLE_TH_ERRORS
  ...
  if (!x) throw python_error();
  // pybind native error
  if (!x) throw py::value_error();
  // From c10/Exception.h
  TORCH_CHECK(cond, "cond was false here");
  TORCH_WARN("Warning message");
  ...
  END_HANDLE_TH_ERRORS_PYBIND
}

GIL

Whenever you make any calls to the Python API, you must have taken out the Python GIL, as none of these calls are thread safe. pybind11::gil_scoped_acquire is a RAII struct which handles taking and releasing the GIL. Use it like this:

void iWantToUsePython() {
  pybind11::gil_scoped_acquire gil;
  ...
}

In general, the compiler will NOT warn you if you use Python functionality without taking out the GIL, so DO NOT FORGET this call.

utils/object_ptr.h

THPPointer is a smart pointer class analogous to std::shared_ptr, but which is overloaded to handle reference counting scheme of various objects which are not based on shared_ptr. The most important overloads are:

  • PyObject (so important we've aliased it as THPObjectPtr), which hooks into Python reference counting. (By the way, that means you MUST take out the GIL before bringing one of these into scope!)

  • The various TH tensor and storage types (e.g., THTensor), which hook into TH's reference counting. (TH's reference counting IS thread safe, no locks necessary.)