2018-12-12 04:40:32 +00:00
|
|
|
#include <c10/core/TensorImpl.h>
|
2018-05-25 00:31:41 +00:00
|
|
|
|
2018-12-04 05:48:46 +00:00
|
|
|
#include <c10/core/Backend.h>
|
2018-12-10 23:06:30 +00:00
|
|
|
#include <c10/core/WrapDimMinimal.h>
|
2020-01-15 19:12:17 +00:00
|
|
|
#include <c10/core/impl/LocalDispatchKeySet.h>
|
2018-12-08 00:18:20 +00:00
|
|
|
#include <c10/util/Optional.h>
|
2018-04-28 19:54:05 +00:00
|
|
|
|
2018-12-12 04:40:32 +00:00
|
|
|
C10_DEFINE_bool(
|
|
|
|
|
caffe2_keep_on_shrink,
|
|
|
|
|
true,
|
|
|
|
|
"If set, keeps memory when a tensor is shrinking its size.");
|
2018-08-04 01:20:19 +00:00
|
|
|
|
2018-12-12 04:40:32 +00:00
|
|
|
C10_DEFINE_int64(
|
|
|
|
|
caffe2_max_keep_on_shrink_memory,
|
|
|
|
|
LLONG_MAX,
|
|
|
|
|
"The maximum memory in bytes to keep on shrink, if the difference between "
|
|
|
|
|
"tensor sizes is bigger than this then tensor will be reset.");
|
|
|
|
|
|
|
|
|
|
namespace c10 {
|
|
|
|
|
|
2019-07-30 05:21:40 +00:00
|
|
|
const char * const TensorImpl::err_msg_tensor_metadata_change_not_allowed =
|
|
|
|
|
"is not allowed on a Tensor created from .data or .detach().\n"
|
|
|
|
|
"If your intent is to change the metadata of a Tensor (such as sizes / strides / storage / storage_offset)\n"
|
|
|
|
|
"without autograd tracking the change, remove the .data / .detach() call and wrap the change in a `with torch.no_grad():` block.\n"
|
|
|
|
|
"For example, change:\n"
|
|
|
|
|
" x.data.set_(y)\n"
|
|
|
|
|
"to:\n"
|
|
|
|
|
" with torch.no_grad():\n"
|
|
|
|
|
" x.set_(y)";
|
|
|
|
|
|
2020-07-16 16:09:19 +00:00
|
|
|
at::Tensor& TensorImpl::mutable_grad() {
|
2019-11-08 17:09:43 +00:00
|
|
|
if (!autograd_meta_) autograd_meta_ = impl::GetAutogradMetaFactory()->make();
|
2020-07-16 16:09:19 +00:00
|
|
|
return autograd_meta_->mutable_grad();
|
2018-04-28 19:54:05 +00:00
|
|
|
}
|
|
|
|
|
|
2018-12-12 04:40:32 +00:00
|
|
|
const at::Tensor& TensorImpl::grad() const {
|
2019-11-08 17:09:43 +00:00
|
|
|
// Yes, I know this looks really weird. But I don't really have a choice as
|
|
|
|
|
// long as this function returns a const reference to Tensor. I'm not
|
|
|
|
|
// really sure how I would have designed this API differently, but it
|
|
|
|
|
// is not so easy to fix right now because the mutable counterpart of
|
|
|
|
|
// this function must keep working so that "x.grad() = ..." keeps working
|
|
|
|
|
// (part of public API).
|
|
|
|
|
if (!autograd_meta_) return impl::GetAutogradMetaFactory()->undefined_tensor();
|
|
|
|
|
return autograd_meta_->grad();
|
2018-04-28 19:54:05 +00:00
|
|
|
}
|
|
|
|
|
|
Reland: Add base forward grad logic (#49734)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/49734
RFC: https://github.com/pytorch/rfcs/pull/11
This PR add the basic logic to handle forward grad as dual Tensors.
It contains the following:
- Mechanism to save dual state on a Tensor and clear it up when the dual level ends
- C++ and python user facing API
- Updated view system that is able to track both forward and backward views
The current PR has the following limitations:
- Extensive tests are in the next PR in the stack as formulas are needed to write full tests.
- Only the manual formulas have been audited and no other formula is actually implemented here (they are in the next PR in the stack)
- Only level 0 is allowed for now. This was discussed and agreed that it is not needed for the first version of this PR.
- We can save one ViewInfo creation when both the forward and backward views have the same base. This can be done by adding a boolean flag to the DifferentiableViewMeta and extra logic in the `as_view` method. This is left out to keep this PR concise.
- We can skip tracking forward views if the base has a forward grad. This can be done by adding extra logic in the `as_view` method. This is left out to keep this PR concise.
Reading guide:
- Updated view handling in [gen_variable_type.py](https://github.com/pytorch/pytorch/pull/49097/files#diff-f6553cec68caeaea36f6c8b14ff76a6d39dfd774e0ea9ef2f76e8d81fd9af5df), [VariableTypeUtils.h](https://github.com/pytorch/pytorch/pull/49097/files#diff-ec71cfa45954dece1236c661d170e6341879c5be637f4abf52e826d61b40695a), [variable.cpp](https://github.com/pytorch/pytorch/pull/49097/files#diff-60e3bfe444e89efc7149f25b38e472710525984789934ab83f1bd5671b8ff285) (skip code below "[Forward Grad View]" for now), [variable.h](https://github.com/pytorch/pytorch/pull/49097/files#diff-1604bcd0e4350ed99ec45e437cee7ac9ebe337392c9ea16a236247aeeb35b02bR266-R542) and [custom_function.cpp](https://github.com/pytorch/pytorch/pull/49097/files#diff-dd85f452082b5bb6612bbc12adb496f8827defa228509f7b493de1d517522d5d). This introduces the new ViewInfo to hold view informations shared for forward and backward. It also updates the differentiable view meta to use this. And it updates the as_view function to handle both forward and backward view.
- New forward grad class that handle storing gradients and tracking at each level [forward_grad.h](https://github.com/pytorch/pytorch/pull/49097/files#diff-c6c5b9ab2d7e5dde4102495faa1b6bbbfc23aa3e47deb7359c0bfe1eb004c0cb), [forward_grad.cpp](https://github.com/pytorch/pytorch/pull/49097/files#diff-de2ab54ade7312701850d71a119a4f4ee4b9fc5a9c42a467cdd4e73c033531dd) and [build_variables.bzl](https://github.com/pytorch/pytorch/pull/49097/files#diff-dfdfa2efb17beddfd9094524f95351fd197db6c8857e96b436fb599870359325). EDIT: These files also contain the new flag to globally disable forward AD that allows us to reduce performance issues while this is in development.
- Lowest level API and binding between Tensor and AutogradMeta in [TensorBody.h](https://github.com/pytorch/pytorch/pull/49097/files#diff-7554853205392fa743357bf845ecc350a974ec049383248c12daaf2f4de04911), [TensorImpl.cpp](https://github.com/pytorch/pytorch/pull/49097/files#diff-052bd9150ef8e09289ddf644b5a6830ede49207201cd41728f6d7cc6d9cead94), [TensorImpl.h](https://github.com/pytorch/pytorch/pull/49097/files#diff-a15aae4cf23da44970db7cece62ff981265575c798c62f7b52d87c8809dfe2e1) and the rest of [variable.cpp](https://github.com/pytorch/pytorch/pull/49097/files#diff-60e3bfe444e89efc7149f25b38e472710525984789934ab83f1bd5671b8ff285R557-R677)
- API to access the forward primal that needs to be a differentiable function (and so in native_functions.yaml) [native_functions.yaml](https://github.com/pytorch/pytorch/pull/49097/files#diff-2f3dbd85efb9b5172f2264eedd3be47dd765e6ab7cc8bf3ade5e62c28ae35991) [NamedRegistrations.cpp](https://github.com/pytorch/pytorch/pull/49097/files#diff-69bd3bea510c9b64e1633fa18c3ea63d4b8348dbad3a78ad9de844ab3e43dc1d), [VariableMethodsStub.cpp](https://github.com/pytorch/pytorch/pull/49097/files#diff-23f5fcb737a2b289811fe0f4b65aef775e7c824b2e629ecd343df51405cd434f), [derivatives.yaml](https://github.com/pytorch/pytorch/pull/49097/files#diff-e4c2f99a2404e98c3586e07425da73008f36b1bada790648a7297af141d37f8c), [gen_python_functions.py](https://github.com/pytorch/pytorch/pull/49097/files#diff-e4c2f99a2404e98c3586e07425da73008f36b1bada790648a7297af141d37f8c), [gen_trace_type.py](https://github.com/pytorch/pytorch/pull/49097/files#diff-54e0b976027bf8debefb959ff360b89ae93466970c843365b1b3a03806d868ce), [TraceTypeManual.cpp](https://github.com/pytorch/pytorch/pull/49097/files#diff-f34636741ad4a23d018e0c289bc750c3bad887b45660e1d6eaf440d234a78fbf) and [part of VariableTypeManual.cpp](https://github.com/pytorch/pytorch/pull/49097/files#diff-6e19a1bce8cbdba8714b6e2c794a76bc0864b64a49cfa757cb0b5afdc937d1a4R198-R243)
- c++ API [autograd.h](https://github.com/pytorch/pytorch/pull/49097/files#diff-349028fbe8291a965a7a263c323b208fe071c35c66179ee997ef84fa81aa4b1e), [autograd.cpp](https://github.com/pytorch/pytorch/pull/49097/files#diff-a3fe908d67dfec16a1fcde300de68b0701bf68b88db7451f29f2bee255cf30c9)
- python binding [init.cpp](https://github.com/pytorch/pytorch/pull/49097/files#diff-c58a67c85191c22c9b3bb439117d8053edfd9dea839fa010cf967d404c3c630d)
- python API [forward_ad.py](https://github.com/pytorch/pytorch/pull/49097/files#diff-a4efad4ba18fffdfb264c21e5475997a24a743089a899f8ec1a5ff962c6738d9), [autograd/__init__.py](https://github.com/pytorch/pytorch/pull/49097/files#diff-743abcafd32ad0e69f39ac5a91df4197b7e1921c135cacee7ef6dc829a8a7af8)
- c++ and python printing [Formatting.cpp](https://github.com/pytorch/pytorch/pull/49097/files#diff-881dba501e71662e2e4818b4b016f739b344c8aed2f5edc6b871eda47a2aced0), [_tensor_str.py](https://github.com/pytorch/pytorch/pull/49097/files#diff-a7911f8d5e73adbff914d99fd7818ace2a7030b6a3748abe06ec6fc6e3df9cc3)
- Utility for formulas and updated manual functions to respect new view system as well as forward grad [FunctionsManual.h](https://github.com/pytorch/pytorch/pull/49097/files#diff-6378bb6dc81a64dab676d61731341fa5d1088418f32a1473a33a0ccfc2357dc1), [FunctionsManual.cpp](https://github.com/pytorch/pytorch/pull/49097/files#diff-4adbd88239afcd60e8198aab65d4f5e43b62314e34b80551e997a1ea503adea5) [rest of VariableTypeManual.cpp](https://github.com/pytorch/pytorch/pull/49097/files#diff-6e19a1bce8cbdba8714b6e2c794a76bc0864b64a49cfa757cb0b5afdc937d1a4R264-R433)
- Ensure SavedVariable save forward grad properly [saved_variable.h](https://github.com/pytorch/pytorch/pull/49097/files#diff-c1b8039d776241abe177d5aa99b79dd9489a9b3e529da8ab24c2e386c1238ae2), [saved_variable.cpp](https://github.com/pytorch/pytorch/pull/49097/files#diff-cc9fba479b5beae06b2eea2e390d17796e0341c5b037a20b5bcaccbb0c341030)
Test Plan: Imported from OSS
Reviewed By: gchanan
Differential Revision: D25678797
Pulled By: albanD
fbshipit-source-id: 3d58550c11b5f58b9b73fd30596d042b857fb9dd
2020-12-22 20:07:00 +00:00
|
|
|
const at::Tensor& TensorImpl::fw_grad(uint64_t level, const at::Tensor& self) const {
|
|
|
|
|
// See TensorImpl::grad() above for explanation about the line below
|
|
|
|
|
if (!autograd_meta_) return impl::GetAutogradMetaFactory()->undefined_tensor();
|
|
|
|
|
return autograd_meta_->fw_grad(level, self);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TensorImpl::set_fw_grad(const at::Tensor& new_grad, const at::Tensor& self, uint64_t level, bool is_inplace_op) {
|
|
|
|
|
if (!autograd_meta_) autograd_meta_ = impl::GetAutogradMetaFactory()->make();
|
|
|
|
|
autograd_meta_->set_fw_grad(new_grad, self, level, is_inplace_op);
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-21 22:21:23 +00:00
|
|
|
TensorImpl::TensorImpl(
|
|
|
|
|
Storage&& storage,
|
|
|
|
|
DispatchKeySet key_set,
|
2020-10-30 17:11:22 +00:00
|
|
|
const caffe2::TypeMeta data_type)
|
2020-05-21 22:21:23 +00:00
|
|
|
: TensorImpl(std::move(storage), key_set, data_type, storage.device()) {}
|
2019-04-05 14:18:38 +00:00
|
|
|
|
2020-10-30 17:11:22 +00:00
|
|
|
TensorImpl::TensorImpl(DispatchKeySet key_set, const caffe2::TypeMeta data_type, c10::optional<c10::Device> device_opt)
|
2020-01-15 19:12:17 +00:00
|
|
|
: TensorImpl({}, key_set, data_type, std::move(device_opt)) {}
|
2018-09-13 23:26:34 +00:00
|
|
|
|
2020-10-30 17:11:22 +00:00
|
|
|
TensorImpl::TensorImpl(Storage&& storage, DispatchKeySet key_set, const caffe2::TypeMeta data_type,
|
2019-04-11 20:32:45 +00:00
|
|
|
c10::optional<c10::Device> device_opt)
|
2018-09-13 23:26:34 +00:00
|
|
|
: storage_(std::move(storage)),
|
|
|
|
|
sizes_{0},
|
2018-10-03 21:12:15 +00:00
|
|
|
storage_offset_(0),
|
2018-09-13 23:26:34 +00:00
|
|
|
numel_(0),
|
2018-09-17 16:08:34 +00:00
|
|
|
data_type_(data_type),
|
2020-09-01 16:03:45 +00:00
|
|
|
device_opt_(device_opt) {
|
2020-10-30 17:11:22 +00:00
|
|
|
|
|
|
|
|
init_bitfields();
|
|
|
|
|
|
2020-01-15 19:12:17 +00:00
|
|
|
if (!key_set.empty()) {
|
2020-10-29 21:04:54 +00:00
|
|
|
TORCH_INTERNAL_ASSERT(data_type == ScalarType::Undefined || device_opt_.has_value());
|
2019-05-24 06:14:48 +00:00
|
|
|
// UndefinedTensorImpl is a singleton, so we skip logging it
|
|
|
|
|
C10_LOG_API_USAGE_ONCE("tensor.create");
|
|
|
|
|
}
|
2020-09-01 16:03:45 +00:00
|
|
|
// After we removed Autograd keys from globally enabled set, every Tensor must be created with
|
|
|
|
|
// a backend DispatchKey and an AutogradBackend key.
|
|
|
|
|
// We automatically add the corresponding autograd key to key_set_ so that backends can stay
|
|
|
|
|
// in the old way of only registering with backend key like DispatchKey::CPU.
|
|
|
|
|
// TODO: Ideally this logic fits best in Variable/Autograd layer so that we only
|
|
|
|
|
// add AutogradBackend key when the tensor requires grad.
|
|
|
|
|
DispatchKey k = key_set.highestPriorityBackendTypeId();
|
|
|
|
|
key_set_ = key_set.add(getAutogradKeyFromBackend(k));
|
|
|
|
|
|
2019-04-05 14:18:38 +00:00
|
|
|
// we would also like to check that non-cpu devices have an index, but some Caffe2 operators create
|
|
|
|
|
// Storages with default devices.
|
2018-11-12 18:38:24 +00:00
|
|
|
strides_.push_back(1);
|
2018-10-03 21:12:15 +00:00
|
|
|
}
|
2018-08-16 15:08:43 +00:00
|
|
|
|
Rename IntList to IntArrayRef. (#16751)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/16751
This was made more complicated by the fact that ivalue::IntList
is a thing. So I had to fix all of the sites where we referring
to IValue post facto.
The following codemods were run, in this order:
```
codemod -m -d . --extensions cc,cpp,cu,cuh,h,hpp,py,cwrap,yaml,in IntList IntArrayRef
codemod -m -d . --extensions cc,cpp,cu,cuh,h,hpp,py,cwrap,yaml,in IntArrayRef::create IntList::create
codemod -m -d . --extensions cc,cpp,cu,cuh,h,hpp,py,cwrap,yaml,in ivalue::IntArrayRef ivalue::IntList
codemod -m -d . --extensions cc,cpp,cu,cuh,h,hpp,py,cwrap,yaml,in Tag::IntArrayRef Tag::IntList
codemod -m -d . --extensions cc,cpp,cu,cuh,h,hpp,py,cwrap,yaml,in isIntArrayRef isIntList
codemod -m -d . --extensions cc,cpp,cu,cuh,h,hpp,py,cwrap,yaml,in toIntArrayRef toIntList
codemod -m -d . --extensions cc,cpp,cu,cuh,h,hpp,py,cwrap,yaml,in 'Shared<IntArrayRef>' 'Shared<IntList>'
codemod -m -d . --extensions cc,cpp,cu,cuh,h,hpp,py,cwrap,yaml,in 'intrusive_ptr<IntArrayRef>' 'intrusive_ptr<IntList>'
```
Some manual fixups were done afterwards; they can be reviewed separately
at https://github.com/pytorch/pytorch/pull/16752
Reviewed By: dzhulgakov
Differential Revision: D13954363
fbshipit-source-id: b5c40aacba042402155a2f5a229fa6db7992ac64
2019-02-05 22:39:43 +00:00
|
|
|
IntArrayRef TensorImpl::sizes() const {
|
2018-08-16 15:08:43 +00:00
|
|
|
return sizes_;
|
Tensor merge PRs from July 20 (#9713)
Summary:
Constituent PRs:
- [x] #9553 Remove unnecessary functions from StorageDerived.h (by cpuhrsch, reviewed by ezyang)
- [x] #9588 Use THTensor/Storage for THVoidTensor/Storage (by cpuhrsch , reviewed by gchanan)
- [x] #9627 Delete context from tensor (by ezyang, reviewed by gchanan)
- [x] #9641 Tensor reorganization (by ezyang, reviewed by gchanan )
- [x] #9647 Remove dim_ from THTensor (by cpuhrsch, reviewed by ezyang)
- [x] #9650 Remove context (by cpuhrsch, reviewed by gchanan and ezyang)
- [x] #9715 Fix Windows build in tensor merge PR (by ezyang, reviewed by gchanan and SsnL)
Upcoming PRs which didn't make this cut:
- [x] #9644 Stride move to TensorImpl, and nits (by ezyang, reviewed by gchanan)
- [ ] #9652 Native localScalar (by ezyang, **UNREVIEWED AND FAILING TESTS**)
- [x] #9710 Devirtualize TensorImpl::toString (by ezyang, reviewed by gchanan)
- [ ] #9654 Use int64_t instead of ptrdiff_t for size / Rename flag to resizable_ (by cpuhrsch, **CHANGES REQUESTED AND FAILING TESTS**)
Pull Request resolved: https://github.com/pytorch/pytorch/pull/9713
Reviewed By: gchanan
Differential Revision: D8960882
Pulled By: ezyang
fbshipit-source-id: 99747b2c5462c7ff6809b67aacb4197626408204
2018-07-24 00:40:19 +00:00
|
|
|
}
|
|
|
|
|
|
Rename IntList to IntArrayRef. (#16751)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/16751
This was made more complicated by the fact that ivalue::IntList
is a thing. So I had to fix all of the sites where we referring
to IValue post facto.
The following codemods were run, in this order:
```
codemod -m -d . --extensions cc,cpp,cu,cuh,h,hpp,py,cwrap,yaml,in IntList IntArrayRef
codemod -m -d . --extensions cc,cpp,cu,cuh,h,hpp,py,cwrap,yaml,in IntArrayRef::create IntList::create
codemod -m -d . --extensions cc,cpp,cu,cuh,h,hpp,py,cwrap,yaml,in ivalue::IntArrayRef ivalue::IntList
codemod -m -d . --extensions cc,cpp,cu,cuh,h,hpp,py,cwrap,yaml,in Tag::IntArrayRef Tag::IntList
codemod -m -d . --extensions cc,cpp,cu,cuh,h,hpp,py,cwrap,yaml,in isIntArrayRef isIntList
codemod -m -d . --extensions cc,cpp,cu,cuh,h,hpp,py,cwrap,yaml,in toIntArrayRef toIntList
codemod -m -d . --extensions cc,cpp,cu,cuh,h,hpp,py,cwrap,yaml,in 'Shared<IntArrayRef>' 'Shared<IntList>'
codemod -m -d . --extensions cc,cpp,cu,cuh,h,hpp,py,cwrap,yaml,in 'intrusive_ptr<IntArrayRef>' 'intrusive_ptr<IntList>'
```
Some manual fixups were done afterwards; they can be reviewed separately
at https://github.com/pytorch/pytorch/pull/16752
Reviewed By: dzhulgakov
Differential Revision: D13954363
fbshipit-source-id: b5c40aacba042402155a2f5a229fa6db7992ac64
2019-02-05 22:39:43 +00:00
|
|
|
IntArrayRef TensorImpl::strides() const {
|
2018-11-12 18:38:24 +00:00
|
|
|
return strides_;
|
2018-07-24 05:17:59 +00:00
|
|
|
}
|
|
|
|
|
|
2018-08-25 05:29:37 +00:00
|
|
|
bool TensorImpl::compute_contiguous() const {
|
|
|
|
|
bool is_contiguous = true;
|
|
|
|
|
if (is_empty())
|
|
|
|
|
return is_contiguous;
|
|
|
|
|
int64_t z = 1;
|
|
|
|
|
for (int64_t d = dim() - 1; d >= 0; d--) {
|
2019-12-03 19:32:10 +00:00
|
|
|
if (sizes_[d] != 1) {
|
|
|
|
|
if (strides_[d] == z) {
|
|
|
|
|
z *= sizes_[d];
|
2018-08-25 05:29:37 +00:00
|
|
|
} else {
|
|
|
|
|
is_contiguous = false;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return is_contiguous;
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-06 13:59:20 +00:00
|
|
|
bool TensorImpl::compute_channels_last_contiguous_2d() const {
|
|
|
|
|
// Please don't combine these code, constant array is used here to let
|
|
|
|
|
// compiler fully unroll the loop to get better performance
|
|
|
|
|
switch (sizes_.size()) {
|
|
|
|
|
case 4:
|
|
|
|
|
{
|
|
|
|
|
int64_t expected = 1;
|
|
|
|
|
for (auto& d : {1, 3, 2, 0}) {
|
|
|
|
|
if (sizes_[d] != 1) {
|
|
|
|
|
if (strides_[d] != expected) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
expected *= sizes_[d];
|
|
|
|
|
}
|
2019-08-05 18:42:48 +00:00
|
|
|
}
|
2020-03-06 13:59:20 +00:00
|
|
|
return true;
|
2019-08-05 18:42:48 +00:00
|
|
|
}
|
2020-03-06 13:59:20 +00:00
|
|
|
case 3:
|
|
|
|
|
// TODO dim == 3 case will be enabled once it is fully tested
|
|
|
|
|
return false;
|
|
|
|
|
default:
|
|
|
|
|
return false;
|
2019-08-05 18:42:48 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-06 13:59:20 +00:00
|
|
|
bool TensorImpl::compute_channels_last_contiguous_3d() const {
|
|
|
|
|
// Please don't combine these code, constant array is used here to let
|
|
|
|
|
// compiler fully unroll the loop to get better performance
|
|
|
|
|
switch (sizes_.size()) {
|
|
|
|
|
case 5:
|
|
|
|
|
{
|
|
|
|
|
int64_t expected = 1;
|
|
|
|
|
for (auto& d : {1, 4, 3, 2, 0}) {
|
|
|
|
|
if (sizes_[d] != 1) {
|
|
|
|
|
if (strides_[d] != expected) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
expected *= sizes_[d];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
case 4:
|
|
|
|
|
// TODO dim == 4 case will be enabled once it is fully tested
|
|
|
|
|
return false;
|
|
|
|
|
default:
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool TensorImpl::compute_strides_like_channels_last_2d() const {
|
|
|
|
|
return is_channels_last_strides_2d(sizes_, strides_);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool TensorImpl::compute_strides_like_channels_last_3d() const {
|
|
|
|
|
return is_channels_last_strides_3d(sizes_, strides_);
|
2019-08-05 18:42:48 +00:00
|
|
|
}
|
|
|
|
|
|
2019-10-03 19:04:42 +00:00
|
|
|
bool TensorImpl::compute_non_overlapping_and_dense() const {
|
|
|
|
|
if (dim() == 1) {
|
2019-12-03 19:32:10 +00:00
|
|
|
return sizes_[0] < 2 || strides_[0] == 1;
|
2019-10-03 19:04:42 +00:00
|
|
|
}
|
|
|
|
|
SmallVector<int64_t,5> perm;
|
|
|
|
|
perm.resize(dim());
|
|
|
|
|
for (int64_t i = 0; i < dim(); i ++) {
|
|
|
|
|
perm[i] = i;
|
|
|
|
|
}
|
|
|
|
|
// Sort by strides, leaving 0 and 1 sized dims at the end of the array
|
|
|
|
|
std::sort(perm.begin(), perm.end(), [&](int64_t a, int64_t b) {
|
|
|
|
|
if (sizes_[a] < 2) {
|
|
|
|
|
return false;
|
2019-10-24 18:42:49 +00:00
|
|
|
} else if (sizes_[b] < 2) {
|
|
|
|
|
return true;
|
2019-10-03 19:04:42 +00:00
|
|
|
}
|
|
|
|
|
return strides_[a] < strides_[b];
|
|
|
|
|
});
|
|
|
|
|
auto require_stride = 1;
|
|
|
|
|
for (int64_t i = 0; i < dim(); i ++) {
|
|
|
|
|
if (sizes_[perm[i]] < 2) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
if (strides_[perm[i]] != require_stride) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
require_stride *= sizes_[perm[i]];
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
Tensor merge PRs from July 20 (#9713)
Summary:
Constituent PRs:
- [x] #9553 Remove unnecessary functions from StorageDerived.h (by cpuhrsch, reviewed by ezyang)
- [x] #9588 Use THTensor/Storage for THVoidTensor/Storage (by cpuhrsch , reviewed by gchanan)
- [x] #9627 Delete context from tensor (by ezyang, reviewed by gchanan)
- [x] #9641 Tensor reorganization (by ezyang, reviewed by gchanan )
- [x] #9647 Remove dim_ from THTensor (by cpuhrsch, reviewed by ezyang)
- [x] #9650 Remove context (by cpuhrsch, reviewed by gchanan and ezyang)
- [x] #9715 Fix Windows build in tensor merge PR (by ezyang, reviewed by gchanan and SsnL)
Upcoming PRs which didn't make this cut:
- [x] #9644 Stride move to TensorImpl, and nits (by ezyang, reviewed by gchanan)
- [ ] #9652 Native localScalar (by ezyang, **UNREVIEWED AND FAILING TESTS**)
- [x] #9710 Devirtualize TensorImpl::toString (by ezyang, reviewed by gchanan)
- [ ] #9654 Use int64_t instead of ptrdiff_t for size / Rename flag to resizable_ (by cpuhrsch, **CHANGES REQUESTED AND FAILING TESTS**)
Pull Request resolved: https://github.com/pytorch/pytorch/pull/9713
Reviewed By: gchanan
Differential Revision: D8960882
Pulled By: ezyang
fbshipit-source-id: 99747b2c5462c7ff6809b67aacb4197626408204
2018-07-24 00:40:19 +00:00
|
|
|
void TensorImpl::release_resources() {
|
Remove Variable::Impl and DifferentiableViewImpl (#17072)
Summary:
As part of the Variable/Tensor merge work: https://github.com/pytorch/pytorch/issues/13638, we make the following changes in this PR:
1. Remove the `Variable::Impl` class and the `DifferentiableViewImpl` class
2. Change all `Variable.data()` call sites to either use `Variable` directly, or use `Variable.tensor_data()`
3. Remove `Variable.data()` API
3. Add `Variable.variable_data()` that matches `tensor.data` in Python API, which creates a new `Variable` that shares the same storage and tensor metadata with the original `Variable`, but with a completely new autograd history.
After this PR, Variable doesn't wrap a Tensor internally anymore, and both Variable and Tensor use the same TensorImpl class as its `impl_`. The only difference is that Variable always has AutogradMeta in its TensorImpl, but Tensor doesn't.
**Note that this PR is BC-breaking in the following use cases:**
**Use Case 1:**
Previously, `x.data = y` works even if `x` and `y` are of different TensorImpl type (e.g. `x` is a CPU dense tensor whose impl is of type TensorImpl, while `y` is a CPU sparse tensor whose impl is of type SparseTensorImpl). However, after this PR, `x.data = y` doesn't work anymore if `x` and `y` are of different TensorImpl type, because the underlying implementation `variable.set_data(tensor)` no longer works if `variable` and `tensor` have different TensorImpl type.
**Use Case 2:**
If a tensor `x`'s `grad` is sparse, accumulating dense gradients to `x` will change the tensor that `x.grad` is pointing to. This is better illustrated with the following example:
```python
params = torch.tensor([1.5, 1.5]).requires_grad_()
with torch.no_grad():
# Change gradient to a sparse tensor
params.grad = torch.sparse_coo_tensor(torch.tensor([[1, 1]]).long(), torch.tensor([1., 1.]))
grad_saved = params.grad
params.backward(torch.tensor([1.5, 1.5]))
assert id(grad_saved) == id(params.grad) # This will fail after this PR
```
The assertion in the last line will fail after this PR, because adding dense gradients to sparse gradients will change the `params.grad` tensor reference.
Pull Request resolved: https://github.com/pytorch/pytorch/pull/17072
Differential Revision: D14075257
Pulled By: yf225
fbshipit-source-id: 0e681df641270dea586042dd26db59f2e76b5957
2019-05-24 04:03:29 +00:00
|
|
|
autograd_meta_.reset();
|
2018-08-16 15:08:43 +00:00
|
|
|
if (storage_) {
|
Use intrusive_ptr in Storage; replace unique_ptr<Storage> with Storage (#10488)
Summary:
```
Use intrusive_ptr in Storage; replace unique_ptr<Storage> with Storage
This patch does two major changes:
- It replaces the use of Retainable in Storage with a new implementation
based on intrusive_ptr. This will be necessary because Caffe2 will
be using this class to implement intrusive_ptrs, and we need to
line these up for the merge. One good thing about the new implementation is
that the default copy/move constructors/assignment operators and destructor
work automatically, instead of needing to be hardcoded into Storage/Tensor.
- It replaces all places where we returned std::unique_ptr<Storage> with
Storage, collapsing an unnecessary double indirection that is no longer
necessary now that we have correctly working copy/move constructors.
I didn't initially want to do step (2), but it was very important to
eliminate all bare uses of new Storage and new StorageImpl, and this making
the API change was the most straightforward way to do this.
HOW TO FIX YOUR CODE IN THE NEW API
- You no longer need to dereference the result of tensor.storage() to pass
it to set. So, instead of:
x.set_(*y.storage());
just write:
x.set_(y.storage());
- If you were accessing methods on StorageImpl via the pImpl() method, you
must use the dot operator to run pImpl(). Even better; just drop pImpl,
we now have method forwarding. So, instead of:
storage->pImpl()->data();
just do:
storage->data();
// storage.pImpl()->data() works too but is not as recommended
- storage->getDevice() is no more; instead use storage->device().index()
MISC CODE UPDATES
- retain, release, weak_retain, weak_release and weak_lock are now
reimplemented using the "blessed API", and renamed to make it
clearer that their use is discouraged.
- nvcc OS X and general OS X portability improvements to intrusive_ptr
- A new comment in intrusive_ptr describing how stack allocated
intrusive_ptr_targets work differently than heap allocated ones
from c10::make_intrusive
CAVEAT EMPTOR
- THStorage_weakRetain used to work on strong pointers, but it NO LONGER
works with intrusive_ptr. You must reclaim the strong pointer into a
real strong pointer, construct a weak pointer from it, and then release
the strong and weak pointers. See StorageSharing.cpp for an example.
```
Pull Request resolved: https://github.com/pytorch/pytorch/pull/10488
Reviewed By: gchanan
Differential Revision: D9306134
Pulled By: ezyang
fbshipit-source-id: 02d58ef62dab8e4da6131e1a24834a65c21048e2
2018-08-22 04:29:30 +00:00
|
|
|
storage_ = {};
|
Tensor merge PRs from July 20 (#9713)
Summary:
Constituent PRs:
- [x] #9553 Remove unnecessary functions from StorageDerived.h (by cpuhrsch, reviewed by ezyang)
- [x] #9588 Use THTensor/Storage for THVoidTensor/Storage (by cpuhrsch , reviewed by gchanan)
- [x] #9627 Delete context from tensor (by ezyang, reviewed by gchanan)
- [x] #9641 Tensor reorganization (by ezyang, reviewed by gchanan )
- [x] #9647 Remove dim_ from THTensor (by cpuhrsch, reviewed by ezyang)
- [x] #9650 Remove context (by cpuhrsch, reviewed by gchanan and ezyang)
- [x] #9715 Fix Windows build in tensor merge PR (by ezyang, reviewed by gchanan and SsnL)
Upcoming PRs which didn't make this cut:
- [x] #9644 Stride move to TensorImpl, and nits (by ezyang, reviewed by gchanan)
- [ ] #9652 Native localScalar (by ezyang, **UNREVIEWED AND FAILING TESTS**)
- [x] #9710 Devirtualize TensorImpl::toString (by ezyang, reviewed by gchanan)
- [ ] #9654 Use int64_t instead of ptrdiff_t for size / Rename flag to resizable_ (by cpuhrsch, **CHANGES REQUESTED AND FAILING TESTS**)
Pull Request resolved: https://github.com/pytorch/pytorch/pull/9713
Reviewed By: gchanan
Differential Revision: D8960882
Pulled By: ezyang
fbshipit-source-id: 99747b2c5462c7ff6809b67aacb4197626408204
2018-07-24 00:40:19 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-08 02:58:29 +00:00
|
|
|
#ifndef C10_DISABLE_TENSORIMPL_EXTENSIBILITY
|
Tensor merge PRs from July 20 (#9713)
Summary:
Constituent PRs:
- [x] #9553 Remove unnecessary functions from StorageDerived.h (by cpuhrsch, reviewed by ezyang)
- [x] #9588 Use THTensor/Storage for THVoidTensor/Storage (by cpuhrsch , reviewed by gchanan)
- [x] #9627 Delete context from tensor (by ezyang, reviewed by gchanan)
- [x] #9641 Tensor reorganization (by ezyang, reviewed by gchanan )
- [x] #9647 Remove dim_ from THTensor (by cpuhrsch, reviewed by ezyang)
- [x] #9650 Remove context (by cpuhrsch, reviewed by gchanan and ezyang)
- [x] #9715 Fix Windows build in tensor merge PR (by ezyang, reviewed by gchanan and SsnL)
Upcoming PRs which didn't make this cut:
- [x] #9644 Stride move to TensorImpl, and nits (by ezyang, reviewed by gchanan)
- [ ] #9652 Native localScalar (by ezyang, **UNREVIEWED AND FAILING TESTS**)
- [x] #9710 Devirtualize TensorImpl::toString (by ezyang, reviewed by gchanan)
- [ ] #9654 Use int64_t instead of ptrdiff_t for size / Rename flag to resizable_ (by cpuhrsch, **CHANGES REQUESTED AND FAILING TESTS**)
Pull Request resolved: https://github.com/pytorch/pytorch/pull/9713
Reviewed By: gchanan
Differential Revision: D8960882
Pulled By: ezyang
fbshipit-source-id: 99747b2c5462c7ff6809b67aacb4197626408204
2018-07-24 00:40:19 +00:00
|
|
|
int64_t TensorImpl::dim() const {
|
2018-08-16 15:08:43 +00:00
|
|
|
return sizes_.size();
|
Tensor merge PRs from July 20 (#9713)
Summary:
Constituent PRs:
- [x] #9553 Remove unnecessary functions from StorageDerived.h (by cpuhrsch, reviewed by ezyang)
- [x] #9588 Use THTensor/Storage for THVoidTensor/Storage (by cpuhrsch , reviewed by gchanan)
- [x] #9627 Delete context from tensor (by ezyang, reviewed by gchanan)
- [x] #9641 Tensor reorganization (by ezyang, reviewed by gchanan )
- [x] #9647 Remove dim_ from THTensor (by cpuhrsch, reviewed by ezyang)
- [x] #9650 Remove context (by cpuhrsch, reviewed by gchanan and ezyang)
- [x] #9715 Fix Windows build in tensor merge PR (by ezyang, reviewed by gchanan and SsnL)
Upcoming PRs which didn't make this cut:
- [x] #9644 Stride move to TensorImpl, and nits (by ezyang, reviewed by gchanan)
- [ ] #9652 Native localScalar (by ezyang, **UNREVIEWED AND FAILING TESTS**)
- [x] #9710 Devirtualize TensorImpl::toString (by ezyang, reviewed by gchanan)
- [ ] #9654 Use int64_t instead of ptrdiff_t for size / Rename flag to resizable_ (by cpuhrsch, **CHANGES REQUESTED AND FAILING TESTS**)
Pull Request resolved: https://github.com/pytorch/pytorch/pull/9713
Reviewed By: gchanan
Differential Revision: D8960882
Pulled By: ezyang
fbshipit-source-id: 99747b2c5462c7ff6809b67aacb4197626408204
2018-07-24 00:40:19 +00:00
|
|
|
}
|
2021-01-08 02:58:29 +00:00
|
|
|
#endif
|
Tensor merge PRs from July 20 (#9713)
Summary:
Constituent PRs:
- [x] #9553 Remove unnecessary functions from StorageDerived.h (by cpuhrsch, reviewed by ezyang)
- [x] #9588 Use THTensor/Storage for THVoidTensor/Storage (by cpuhrsch , reviewed by gchanan)
- [x] #9627 Delete context from tensor (by ezyang, reviewed by gchanan)
- [x] #9641 Tensor reorganization (by ezyang, reviewed by gchanan )
- [x] #9647 Remove dim_ from THTensor (by cpuhrsch, reviewed by ezyang)
- [x] #9650 Remove context (by cpuhrsch, reviewed by gchanan and ezyang)
- [x] #9715 Fix Windows build in tensor merge PR (by ezyang, reviewed by gchanan and SsnL)
Upcoming PRs which didn't make this cut:
- [x] #9644 Stride move to TensorImpl, and nits (by ezyang, reviewed by gchanan)
- [ ] #9652 Native localScalar (by ezyang, **UNREVIEWED AND FAILING TESTS**)
- [x] #9710 Devirtualize TensorImpl::toString (by ezyang, reviewed by gchanan)
- [ ] #9654 Use int64_t instead of ptrdiff_t for size / Rename flag to resizable_ (by cpuhrsch, **CHANGES REQUESTED AND FAILING TESTS**)
Pull Request resolved: https://github.com/pytorch/pytorch/pull/9713
Reviewed By: gchanan
Differential Revision: D8960882
Pulled By: ezyang
fbshipit-source-id: 99747b2c5462c7ff6809b67aacb4197626408204
2018-07-24 00:40:19 +00:00
|
|
|
|
2018-08-16 15:08:43 +00:00
|
|
|
int64_t TensorImpl::size(int64_t d) const {
|
|
|
|
|
d = at::maybe_wrap_dim(d, dim(), false);
|
|
|
|
|
return sizes_[d];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int64_t TensorImpl::stride(int64_t d) const {
|
|
|
|
|
d = at::maybe_wrap_dim(d, dim(), false);
|
|
|
|
|
return strides_[d];
|
2018-07-25 16:14:22 +00:00
|
|
|
}
|
|
|
|
|
|
2019-02-11 20:48:17 +00:00
|
|
|
bool TensorImpl::has_storage() const {
|
|
|
|
|
return storage_;
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-16 14:15:34 +00:00
|
|
|
bool TensorImpl::is_contiguous(at::MemoryFormat memory_format) const {
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
|
AT_ASSERT(compute_contiguous() == is_contiguous_);
|
|
|
|
|
#endif
|
|
|
|
|
if (memory_format == at::MemoryFormat::ChannelsLast) {
|
2019-08-05 18:42:48 +00:00
|
|
|
return is_channels_last_contiguous_;
|
2019-05-16 14:15:34 +00:00
|
|
|
}
|
2020-03-06 13:59:20 +00:00
|
|
|
else if (memory_format == at::MemoryFormat::ChannelsLast3d) {
|
|
|
|
|
return is_channels_last_3d_contiguous_;
|
|
|
|
|
}
|
2019-05-16 14:15:34 +00:00
|
|
|
return is_contiguous_;
|
|
|
|
|
}
|
|
|
|
|
|
Change Tensor/TensorImpl to use c10::intrusive_ptr (#10824)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/10824
API additions:
- Tensor(c10::intrusive_ptr<TensorImpl,UndefinedTensor>&&)
- Tensor(const c10::intrusive_ptr<TensorImpl,UndefinedTensor>&)
- Tensor::operator=(Tensor&&) && (for completeness sake)
- TensorBase::unsafeGetTensorImpl()
- TensorBase::unsafeReleaseTensorImpl()
- TensorBase::getIntrusivePtr()
- TensorImpl::type_id()
- Tensor::set_data()
- Tensor::is_same(Tensor)
- Tensor::use_count()
- Tensor::type_id()
- Tensor::scalar_type()
- WeakTensor::is_same(WeakTensor)
- intrusive_ptr::weak_use_count()
- weak_intrusive_ptr::weak_use_count()
- c10::raw::intrusive_ptr::{incref,decref,make_weak}
- c10::raw::weak_intrusive_ptr::{incref,decref,lock}
API changes:
- Tensor::pImpl is no longer public (and now named tensor_impl_)
- Most methods accessed this way are now accessible on Tensor
maybe_zero_dim() and set_wrapped_number() being prominent exceptions
(they are now accessed through unsafeGetTensorImpl())
- Type is no longer friend of Tensor
- TensorBase::reset(TensorImpl*) is deleted
- TensorBase::reset(TensorImpl*, bool should_retain) is deleted
- TensorBase::swap(TensorBaseImpl&) is deleted; use std::swap instead
- TensorBase::get() is deleted; use unsafeGetTensorImpl() instead
- TensorBase::detach() is deleted; use unsafeReleaseTensorImpl() instead
- TensorBase::retain() is deleted; use _raw_incref() instead
- TensorBase::release() is deleted; use _raw_decref() instead
- WeakTensor lost most of its methods (it no longer inherits from
TensorBase)
- TensorImpl::storage() is now a const method
- Tensor(TensorBase) constructor removed, instead
we go through getIntrusivePtr(). I'm not sure about
this change; I happened to have accidentally removed the
TensorBase constructor and decided to fix call sites,
but I could go the other way.
- detail::set_data() is deleted; use Tensor::set_data() instead
- c10::raw_intrusive_ptr_target removed; use the functions in c10::raw instead.
(The reason for this change, is that it is invalid to cast an intrusive_ptr_target*
to a raw_intrusive_ptr_target* to take advantage of the methods. But there is
no reason the incref/decref methods shouldn't also work on intrusive_ptr_target;
it is primarily an API consideration. We can be more standards compliant by
keeping them as functions, which are universally applicable.)
- intrusive_ptr::reclaim() and weak_intrusive_ptr::reclaim() now work on
pointers of the NullType. (This counts as a bug fix, because the documentation
specified that pointers produced by release() are valid to reclaim(), and
a release() on a null intrusive_ptr produces the NullType::singleton())
Bug fixes:
- Dispatch code for mutable references incorrectly returned
a reference to a value argument (which would immediately
go out of scope). They now correctly return a tensor by
value.
- intrusive_ptr copy/move assignment did not work correctly when
an object was assigned to itself. We now check for this case and
no-op if so. (This bug manifested itself as a Tensor mysteriously
becoming an UndefinedTensor after lines of code like
'x = x.mul_(y)')
Other changes:
- The checked cast functions in Utils.h have now been
renamed and detemplatized into checked unwrap functions.
- Added type_id() and scalar_type() methods to Tensor
- pImpl is no longer public
- Documented what the && overloads are doing
- All occurrences of 'new TensorImpl' (and similar spellings, like 'new THTensor')
have been expunged. This is NO LONGER a valid way to create a new
tensor, and if you do this, upon your first incref, you will catch an ASSERT
failure saying that only tensors created by intrusive_ptr::release() are valid
to reclaim(). Use c10::make_intrusive instead in this situation.
- IValue is adjusted to use intrusive_ptr instead of Retainable, and all
other sub-classes of Retainable were modified to use intrusive_ptr.
When doing this, I had to make the constructors of sub-classes like
ConstantList public, so that c10::make_intrusive could invoke them. Fortunately,
if you incorrectly stack allocate a ConstantList, and then try to get an
intrusive_ptr to it, it will fail, as stack allocated ConstantLists have refcount 0.
- IValue very narrowly sidesteps the problem of handling NullType, as it
considers intrusive_ptr<TensorImpl> identical to intrusive_ptr<TensorImpl, UndefinedTensor>
which is not always true. This was always the case, but there's now a comment
explaining what's going on.
Some MSVC bugs were uncovered during the preparation of this patch.
They are documented as comments in the code.
Reviewed By: gchanan
Differential Revision: D9481140
fbshipit-source-id: 14a8ea0c231ed88b5715fb86d92730926f9f92fc
2018-08-27 23:00:16 +00:00
|
|
|
const Storage& TensorImpl::storage() const {
|
Use intrusive_ptr in Storage; replace unique_ptr<Storage> with Storage (#10488)
Summary:
```
Use intrusive_ptr in Storage; replace unique_ptr<Storage> with Storage
This patch does two major changes:
- It replaces the use of Retainable in Storage with a new implementation
based on intrusive_ptr. This will be necessary because Caffe2 will
be using this class to implement intrusive_ptrs, and we need to
line these up for the merge. One good thing about the new implementation is
that the default copy/move constructors/assignment operators and destructor
work automatically, instead of needing to be hardcoded into Storage/Tensor.
- It replaces all places where we returned std::unique_ptr<Storage> with
Storage, collapsing an unnecessary double indirection that is no longer
necessary now that we have correctly working copy/move constructors.
I didn't initially want to do step (2), but it was very important to
eliminate all bare uses of new Storage and new StorageImpl, and this making
the API change was the most straightforward way to do this.
HOW TO FIX YOUR CODE IN THE NEW API
- You no longer need to dereference the result of tensor.storage() to pass
it to set. So, instead of:
x.set_(*y.storage());
just write:
x.set_(y.storage());
- If you were accessing methods on StorageImpl via the pImpl() method, you
must use the dot operator to run pImpl(). Even better; just drop pImpl,
we now have method forwarding. So, instead of:
storage->pImpl()->data();
just do:
storage->data();
// storage.pImpl()->data() works too but is not as recommended
- storage->getDevice() is no more; instead use storage->device().index()
MISC CODE UPDATES
- retain, release, weak_retain, weak_release and weak_lock are now
reimplemented using the "blessed API", and renamed to make it
clearer that their use is discouraged.
- nvcc OS X and general OS X portability improvements to intrusive_ptr
- A new comment in intrusive_ptr describing how stack allocated
intrusive_ptr_targets work differently than heap allocated ones
from c10::make_intrusive
CAVEAT EMPTOR
- THStorage_weakRetain used to work on strong pointers, but it NO LONGER
works with intrusive_ptr. You must reclaim the strong pointer into a
real strong pointer, construct a weak pointer from it, and then release
the strong and weak pointers. See StorageSharing.cpp for an example.
```
Pull Request resolved: https://github.com/pytorch/pytorch/pull/10488
Reviewed By: gchanan
Differential Revision: D9306134
Pulled By: ezyang
fbshipit-source-id: 02d58ef62dab8e4da6131e1a24834a65c21048e2
2018-08-22 04:29:30 +00:00
|
|
|
return storage_;
|
2018-08-07 22:01:23 +00:00
|
|
|
}
|
|
|
|
|
|
2018-10-04 02:06:54 +00:00
|
|
|
static void deletePlacementDeleteContext(void* ptr) {
|
|
|
|
|
delete static_cast<PlacementDeleteContext*>(ptr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
at::DataPtr PlacementDeleteContext::makeDataPtr(
|
|
|
|
|
at::DataPtr&& data_ptr,
|
|
|
|
|
PlacementDtor placement_dtor,
|
|
|
|
|
size_t size,
|
|
|
|
|
at::Device device) {
|
|
|
|
|
auto* ptr = data_ptr.get();
|
|
|
|
|
return {ptr,
|
|
|
|
|
new PlacementDeleteContext(std::move(data_ptr), placement_dtor, size),
|
|
|
|
|
&deletePlacementDeleteContext,
|
|
|
|
|
device};
|
|
|
|
|
}
|
|
|
|
|
|
2018-12-27 00:31:47 +00:00
|
|
|
AutogradMetaInterface::~AutogradMetaInterface() {}
|
|
|
|
|
|
2019-10-31 18:18:47 +00:00
|
|
|
void TensorImpl::set_requires_grad(bool requires_grad) {
|
Null AutogradMeta optimization (#28610)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/28610
The basic idea is, in some cases where we stored a pointer to a full AutogradMeta object, instead store a nullptr. We let a nullptr represent a default-constructed AutogradMeta object, and simply populate it with a real AutogradMeta if there is ever a situation where we need to modify it.
The primary technical contrivance in this diff is I have to use AutogradMetaFactory to lazily initialize the AutogradMeta, as it is not available in the dynamic library that TensorImpl is in. (I spent a while trying to put them in the same compilation unit, but gave up in the end as it pushed us over the Windows linking binary size limit. Eep.)
Some other notes:
- `set_autograd_meta` now unconditionally turns a tensor into a variable. I audited all call sites and observed there are no occurrences where nullptr is passed (after this patch, there are now!)
- `copy_tensor_metadata` is updated to unconditionally preserve the VariableTensorId-ness of the destination tensor. I think this is the more correct semantics; we can't do the old semantics anymore.
- There's a bunch of places in the API where we return const references to objects. This is pretty weird to me, but I didn't feel like cleaning it up. But sometimes I don't conveniently have something that's the right lifetime, so I introduced a number of singletons to handle this correctly.
You might wonder why I'm doing the optimization before the variable-tensor dynamic merge. The reason is simple: this change is semantics preserving, while variable-tensor dynamic merge is not. So it is easier to get right, and prevents us from regressing performance if we do it the other way.
Signed-off-by: Edward Z. Yang <ezyang@fb.com>
Test Plan: Imported from OSS
Differential Revision: D18171162
Pulled By: ezyang
fbshipit-source-id: 580df729e4d04881b2b9caa0f0c00785b3afbb92
2019-10-31 18:18:47 +00:00
|
|
|
if (!requires_grad && !autograd_meta_) return;
|
|
|
|
|
if (!autograd_meta_) autograd_meta_ = impl::GetAutogradMetaFactory()->make();
|
|
|
|
|
// NB: In principle, setting requires_grad to false could result in
|
|
|
|
|
// the AutogradMeta becoming equal to a default constructed state,
|
|
|
|
|
// in which case we could apply the nullptr AutogradMeta optimization
|
|
|
|
|
// (see autograd_meta_ docs). But we don't do this right now. Note
|
|
|
|
|
// that it is unsound to unconditionally set AutogradMeta to false
|
|
|
|
|
// when you set requires_grad to False, as there may be nontrivial
|
|
|
|
|
// information content in the other fields; for example, we may
|
|
|
|
|
// have set the string name for a Variable, or there may be hooks
|
|
|
|
|
// registered for it.
|
|
|
|
|
autograd_meta_->set_requires_grad(requires_grad, this);
|
2019-10-31 18:18:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool TensorImpl::requires_grad() const {
|
Null AutogradMeta optimization (#28610)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/28610
The basic idea is, in some cases where we stored a pointer to a full AutogradMeta object, instead store a nullptr. We let a nullptr represent a default-constructed AutogradMeta object, and simply populate it with a real AutogradMeta if there is ever a situation where we need to modify it.
The primary technical contrivance in this diff is I have to use AutogradMetaFactory to lazily initialize the AutogradMeta, as it is not available in the dynamic library that TensorImpl is in. (I spent a while trying to put them in the same compilation unit, but gave up in the end as it pushed us over the Windows linking binary size limit. Eep.)
Some other notes:
- `set_autograd_meta` now unconditionally turns a tensor into a variable. I audited all call sites and observed there are no occurrences where nullptr is passed (after this patch, there are now!)
- `copy_tensor_metadata` is updated to unconditionally preserve the VariableTensorId-ness of the destination tensor. I think this is the more correct semantics; we can't do the old semantics anymore.
- There's a bunch of places in the API where we return const references to objects. This is pretty weird to me, but I didn't feel like cleaning it up. But sometimes I don't conveniently have something that's the right lifetime, so I introduced a number of singletons to handle this correctly.
You might wonder why I'm doing the optimization before the variable-tensor dynamic merge. The reason is simple: this change is semantics preserving, while variable-tensor dynamic merge is not. So it is easier to get right, and prevents us from regressing performance if we do it the other way.
Signed-off-by: Edward Z. Yang <ezyang@fb.com>
Test Plan: Imported from OSS
Differential Revision: D18171162
Pulled By: ezyang
fbshipit-source-id: 580df729e4d04881b2b9caa0f0c00785b3afbb92
2019-10-31 18:18:47 +00:00
|
|
|
if (!autograd_meta_) return false;
|
|
|
|
|
return autograd_meta_->requires_grad();
|
2019-10-31 18:18:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TensorImpl::set_autograd_meta(std::unique_ptr<c10::AutogradMetaInterface> autograd_meta) {
|
Null AutogradMeta optimization (#28610)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/28610
The basic idea is, in some cases where we stored a pointer to a full AutogradMeta object, instead store a nullptr. We let a nullptr represent a default-constructed AutogradMeta object, and simply populate it with a real AutogradMeta if there is ever a situation where we need to modify it.
The primary technical contrivance in this diff is I have to use AutogradMetaFactory to lazily initialize the AutogradMeta, as it is not available in the dynamic library that TensorImpl is in. (I spent a while trying to put them in the same compilation unit, but gave up in the end as it pushed us over the Windows linking binary size limit. Eep.)
Some other notes:
- `set_autograd_meta` now unconditionally turns a tensor into a variable. I audited all call sites and observed there are no occurrences where nullptr is passed (after this patch, there are now!)
- `copy_tensor_metadata` is updated to unconditionally preserve the VariableTensorId-ness of the destination tensor. I think this is the more correct semantics; we can't do the old semantics anymore.
- There's a bunch of places in the API where we return const references to objects. This is pretty weird to me, but I didn't feel like cleaning it up. But sometimes I don't conveniently have something that's the right lifetime, so I introduced a number of singletons to handle this correctly.
You might wonder why I'm doing the optimization before the variable-tensor dynamic merge. The reason is simple: this change is semantics preserving, while variable-tensor dynamic merge is not. So it is easier to get right, and prevents us from regressing performance if we do it the other way.
Signed-off-by: Edward Z. Yang <ezyang@fb.com>
Test Plan: Imported from OSS
Differential Revision: D18171162
Pulled By: ezyang
fbshipit-source-id: 580df729e4d04881b2b9caa0f0c00785b3afbb92
2019-10-31 18:18:47 +00:00
|
|
|
// NB: autograd_meta may be null! That just means it's the default
|
|
|
|
|
// constructor
|
2019-10-31 18:18:47 +00:00
|
|
|
autograd_meta_ = std::move(autograd_meta);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
c10::AutogradMetaInterface* TensorImpl::autograd_meta() const {
|
Null AutogradMeta optimization (#28610)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/28610
The basic idea is, in some cases where we stored a pointer to a full AutogradMeta object, instead store a nullptr. We let a nullptr represent a default-constructed AutogradMeta object, and simply populate it with a real AutogradMeta if there is ever a situation where we need to modify it.
The primary technical contrivance in this diff is I have to use AutogradMetaFactory to lazily initialize the AutogradMeta, as it is not available in the dynamic library that TensorImpl is in. (I spent a while trying to put them in the same compilation unit, but gave up in the end as it pushed us over the Windows linking binary size limit. Eep.)
Some other notes:
- `set_autograd_meta` now unconditionally turns a tensor into a variable. I audited all call sites and observed there are no occurrences where nullptr is passed (after this patch, there are now!)
- `copy_tensor_metadata` is updated to unconditionally preserve the VariableTensorId-ness of the destination tensor. I think this is the more correct semantics; we can't do the old semantics anymore.
- There's a bunch of places in the API where we return const references to objects. This is pretty weird to me, but I didn't feel like cleaning it up. But sometimes I don't conveniently have something that's the right lifetime, so I introduced a number of singletons to handle this correctly.
You might wonder why I'm doing the optimization before the variable-tensor dynamic merge. The reason is simple: this change is semantics preserving, while variable-tensor dynamic merge is not. So it is easier to get right, and prevents us from regressing performance if we do it the other way.
Signed-off-by: Edward Z. Yang <ezyang@fb.com>
Test Plan: Imported from OSS
Differential Revision: D18171162
Pulled By: ezyang
fbshipit-source-id: 580df729e4d04881b2b9caa0f0c00785b3afbb92
2019-10-31 18:18:47 +00:00
|
|
|
// NB: Might return null!
|
2019-10-31 18:18:47 +00:00
|
|
|
return autograd_meta_.get();
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-05 02:33:16 +00:00
|
|
|
c10::intrusive_ptr<TensorImpl> TensorImpl::shallow_copy_and_detach(
|
|
|
|
|
const c10::VariableVersion& version_counter,
|
|
|
|
|
bool allow_tensor_metadata_change) const {
|
|
|
|
|
auto impl = c10::make_intrusive<TensorImpl>(
|
2020-12-10 01:43:51 +00:00
|
|
|
// No need to populate Storage; copy_tensor_metadata will do it for us.
|
|
|
|
|
key_set_, data_type_, device_opt_);
|
2020-12-05 02:33:16 +00:00
|
|
|
copy_tensor_metadata(
|
|
|
|
|
/*src_impl=*/this,
|
|
|
|
|
/*dest_impl=*/impl.get(),
|
|
|
|
|
/*version_counter=*/version_counter,
|
|
|
|
|
/*allow_tensor_metadata_change=*/allow_tensor_metadata_change);
|
|
|
|
|
impl->refresh_numel();
|
|
|
|
|
impl->refresh_contiguous();
|
|
|
|
|
return impl;
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-05 02:33:16 +00:00
|
|
|
c10::intrusive_ptr<TensorImpl> TensorImpl::shallow_copy_and_detach(
|
|
|
|
|
c10::VariableVersion&& version_counter,
|
|
|
|
|
bool allow_tensor_metadata_change) const {
|
|
|
|
|
auto impl = c10::make_intrusive<TensorImpl>(
|
2020-12-10 01:43:51 +00:00
|
|
|
// No need to populate Storage; copy_tensor_metadata will do it for us.
|
|
|
|
|
key_set_, data_type_, device_opt_);
|
2020-12-05 02:33:16 +00:00
|
|
|
copy_tensor_metadata(
|
|
|
|
|
/*src_impl=*/this,
|
|
|
|
|
/*dest_impl=*/impl.get(),
|
|
|
|
|
/*version_counter=*/std::move(version_counter),
|
|
|
|
|
/*allow_tensor_metadata_change=*/allow_tensor_metadata_change);
|
|
|
|
|
impl->refresh_numel();
|
|
|
|
|
impl->refresh_contiguous();
|
|
|
|
|
return impl;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TensorImpl::copy_tensor_metadata_except_version_counter(
|
2019-10-31 18:18:47 +00:00
|
|
|
const TensorImpl* src_impl,
|
|
|
|
|
TensorImpl* dest_impl,
|
|
|
|
|
bool allow_tensor_metadata_change) {
|
|
|
|
|
dest_impl->storage_ = src_impl->storage_;
|
|
|
|
|
dest_impl->sizes_ = src_impl->sizes_;
|
|
|
|
|
dest_impl->strides_ = src_impl->strides_;
|
|
|
|
|
dest_impl->storage_offset_ = src_impl->storage_offset_;
|
|
|
|
|
dest_impl->data_type_ = src_impl->data_type_;
|
|
|
|
|
dest_impl->device_opt_ = src_impl->device_opt_;
|
2020-01-15 19:12:17 +00:00
|
|
|
dest_impl->key_set_ = src_impl->key_set_;
|
2019-10-31 18:18:47 +00:00
|
|
|
dest_impl->is_contiguous_ = src_impl->is_contiguous_;
|
|
|
|
|
dest_impl->is_channels_last_contiguous_ = src_impl->is_channels_last_contiguous_;
|
2020-03-06 13:59:20 +00:00
|
|
|
dest_impl->is_channels_last_3d_contiguous_ = src_impl->is_channels_last_3d_contiguous_;
|
2019-10-31 18:18:47 +00:00
|
|
|
dest_impl->is_channels_last_ = src_impl->is_channels_last_;
|
2020-03-06 13:59:20 +00:00
|
|
|
dest_impl->is_channels_last_3d_ = src_impl->is_channels_last_3d_;
|
2019-10-31 18:18:47 +00:00
|
|
|
dest_impl->is_non_overlapping_and_dense_ = src_impl->is_non_overlapping_and_dense_;
|
|
|
|
|
dest_impl->is_wrapped_number_ = src_impl->is_wrapped_number_;
|
|
|
|
|
dest_impl->reserved_ = src_impl->reserved_;
|
|
|
|
|
dest_impl->set_allow_tensor_metadata_change(allow_tensor_metadata_change);
|
|
|
|
|
if (src_impl->named_tensor_meta_ != nullptr) {
|
|
|
|
|
dest_impl->named_tensor_meta_ = src_impl->named_tensor_meta_->clone();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-05 02:33:16 +00:00
|
|
|
void TensorImpl::copy_tensor_metadata(
|
|
|
|
|
const TensorImpl* src_impl,
|
|
|
|
|
TensorImpl* dest_impl,
|
|
|
|
|
const c10::VariableVersion& version_counter,
|
|
|
|
|
bool allow_tensor_metadata_change) {
|
|
|
|
|
copy_tensor_metadata_except_version_counter(src_impl, dest_impl, allow_tensor_metadata_change);
|
|
|
|
|
dest_impl->set_version_counter(version_counter);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TensorImpl::copy_tensor_metadata(
|
|
|
|
|
const TensorImpl* src_impl,
|
|
|
|
|
TensorImpl* dest_impl,
|
|
|
|
|
c10::VariableVersion&& version_counter,
|
|
|
|
|
bool allow_tensor_metadata_change) {
|
|
|
|
|
copy_tensor_metadata_except_version_counter(src_impl, dest_impl, allow_tensor_metadata_change);
|
|
|
|
|
dest_impl->set_version_counter(std::move(version_counter));
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-31 18:18:47 +00:00
|
|
|
namespace impl {
|
|
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
AutogradMetaFactory* meta_factory = nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SetAutogradMetaFactory(AutogradMetaFactory* factory) {
|
|
|
|
|
meta_factory = factory;
|
|
|
|
|
}
|
|
|
|
|
AutogradMetaFactory* GetAutogradMetaFactory() {
|
|
|
|
|
TORCH_CHECK(meta_factory, "Support for autograd has not been loaded; have you linked against libtorch.so?")
|
|
|
|
|
return meta_factory;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace impl
|
|
|
|
|
|
2018-12-12 04:40:32 +00:00
|
|
|
} // namespace c10
|