2018-09-22 04:12:37 +00:00
|
|
|
#include <gtest/gtest.h>
|
2018-05-09 21:01:19 +00:00
|
|
|
|
2021-12-09 17:44:04 +00:00
|
|
|
#include <c10/util/irange.h>
|
Re-organize C++ API `torch::nn` folder structure (#26262)
Summary:
This PR aims to re-organize C++ API `torch::nn` folder structure in the following way:
- Every module in `torch/csrc/api/include/torch/nn/modules/` (except `any.h`, `named_any.h`, `modulelist.h`, `sequential.h`, `embedding.h`) has a strictly equivalent Python file in `torch/nn/modules/`. For example:
`torch/csrc/api/include/torch/nn/modules/pooling.h` -> `torch/nn/modules/pooling.py`
`torch/csrc/api/include/torch/nn/modules/conv.h` -> `torch/nn/modules/conv.py`
`torch/csrc/api/include/torch/nn/modules/batchnorm.h` -> `torch/nn/modules/batchnorm.py`
`torch/csrc/api/include/torch/nn/modules/sparse.h` -> `torch/nn/modules/sparse.py`
- Containers such as `any.h`, `named_any.h`, `modulelist.h`, `sequential.h` are moved into `torch/csrc/api/include/torch/nn/modules/container/`, because their implementations are too long to be combined into one file (like `torch/nn/modules/container.py` in Python API)
- `embedding.h` is not renamed to `sparse.h` yet, because we have another work stream that works on API parity for Embedding and EmbeddingBag, and renaming the file would cause conflict. After the embedding API parity work is done, we will rename `embedding.h` to `sparse.h` to match the Python file name, and move the embedding options out to options/ folder.
- `torch/csrc/api/include/torch/nn/functional/` is added, and the folder structure mirrors that of `torch/csrc/api/include/torch/nn/modules/`. For example, `torch/csrc/api/include/torch/nn/functional/pooling.h` contains the functions for pooling, which are then used by the pooling modules in `torch/csrc/api/include/torch/nn/modules/pooling.h`.
- `torch/csrc/api/include/torch/nn/options/` is added, and the folder structure mirrors that of `torch/csrc/api/include/torch/nn/modules/`. For example, `torch/csrc/api/include/torch/nn/options/pooling.h` contains MaxPoolOptions, which is used by both MaxPool modules in `torch/csrc/api/include/torch/nn/modules/pooling.h`, and max_pool functions in `torch/csrc/api/include/torch/nn/functional/pooling.h`.
Pull Request resolved: https://github.com/pytorch/pytorch/pull/26262
Differential Revision: D17422426
Pulled By: yf225
fbshipit-source-id: c413d2a374ba716dac81db31516619bbd879db7f
2019-09-17 17:05:11 +00:00
|
|
|
#include <torch/torch.h>
|
2018-05-09 21:01:19 +00:00
|
|
|
|
2018-09-22 04:12:37 +00:00
|
|
|
#include <test/cpp/api/support.h>
|
2018-07-17 04:43:40 +00:00
|
|
|
|
2018-05-09 21:01:19 +00:00
|
|
|
using namespace torch::nn;
|
2018-07-17 04:43:40 +00:00
|
|
|
using namespace torch::test;
|
2018-05-24 19:46:51 +00:00
|
|
|
|
2018-06-25 02:03:39 +00:00
|
|
|
struct AGIUnit : torch::nn::Module {};
|
2018-05-10 15:52:38 +00:00
|
|
|
|
|
|
|
|
namespace test {
|
2018-06-25 02:03:39 +00:00
|
|
|
struct AGIUnit : torch::nn::Module {};
|
|
|
|
|
struct AGIUnit2 : torch::nn::Module {
|
|
|
|
|
AGIUnit2() : torch::nn::Module("Foo") {}
|
2018-05-10 15:52:38 +00:00
|
|
|
};
|
|
|
|
|
} // namespace test
|
|
|
|
|
|
2018-09-22 04:12:37 +00:00
|
|
|
struct ModuleTest : torch::test::SeedingFixture {};
|
|
|
|
|
|
|
|
|
|
TEST_F(ModuleTest, CanEnableAndDisableTrainingMode) {
|
2018-06-19 02:45:53 +00:00
|
|
|
Linear module(3, 4);
|
2018-09-22 04:12:37 +00:00
|
|
|
ASSERT_TRUE(module->is_training());
|
|
|
|
|
|
|
|
|
|
module->eval();
|
|
|
|
|
ASSERT_FALSE(module->is_training());
|
|
|
|
|
|
|
|
|
|
module->train();
|
|
|
|
|
ASSERT_TRUE(module->is_training());
|
2018-05-09 21:01:19 +00:00
|
|
|
}
|
|
|
|
|
|
2018-09-22 04:12:37 +00:00
|
|
|
TEST_F(ModuleTest, ZeroGrad) {
|
2018-06-19 02:45:53 +00:00
|
|
|
Linear module(3, 4);
|
2018-06-27 21:34:06 +00:00
|
|
|
auto weight = torch::ones({8, 3}, torch::requires_grad());
|
2019-01-14 22:32:32 +00:00
|
|
|
auto loss = module(weight).sum();
|
2018-05-25 00:31:41 +00:00
|
|
|
loss.backward();
|
2018-05-24 05:11:32 +00:00
|
|
|
for (auto& parameter : module->parameters()) {
|
Make PyTorch code-base clang-tidy compliant (#56892)
Summary:
This is an automatic change generated by the following script:
```
#!/usr/bin/env python3
from subprocess import check_output, check_call
import os
def get_compiled_files_list():
import json
with open("build/compile_commands.json") as f:
data = json.load(f)
files = [os.path.relpath(node['file']) for node in data]
for idx, fname in enumerate(files):
if fname.startswith('build/') and fname.endswith('.DEFAULT.cpp'):
files[idx] = fname[len('build/'):-len('.DEFAULT.cpp')]
return files
def run_clang_tidy(fname):
check_call(["python3", "tools/clang_tidy.py", "-c", "build", "-x", fname,"-s"])
changes = check_output(["git", "ls-files", "-m"])
if len(changes) == 0:
return
check_call(["git", "commit","--all", "-m", f"NOLINT stubs for {fname}"])
def main():
git_files = check_output(["git", "ls-files"]).decode("ascii").split("\n")
compiled_files = get_compiled_files_list()
for idx, fname in enumerate(git_files):
if fname not in compiled_files:
continue
if fname.startswith("caffe2/contrib/aten/"):
continue
print(f"[{idx}/{len(git_files)}] Processing {fname}")
run_clang_tidy(fname)
if __name__ == "__main__":
main()
```
Pull Request resolved: https://github.com/pytorch/pytorch/pull/56892
Reviewed By: H-Huang
Differential Revision: D27991944
Pulled By: malfet
fbshipit-source-id: 5415e1eb2c1b34319a4f03024bfaa087007d7179
2021-04-28 21:09:06 +00:00
|
|
|
// NOLINTNEXTLINE(performance-unnecessary-copy-initialization)
|
Replace cursors with OrderedDict (#13427)
Summary:
This is a pre-cursor diff to Python <-> C++ frontend integration -- I have a follow-up PR coming for that. This PR changes the C++ frontend module interface to replace the custom "cursor"s I introduced some time ago with `OrderedDict`. I introduced cursors at the time as a convenient way of applying functions and query operations on a modules' parameters, buffers and modules, allowing things like `module.parameters().map(my_func)`. However, I noticed that (1) this functionality is easily implement-able on top of a regular data structure and (2) more importantly, using OrderedDicts is much, much easier for Python integration. This is especially true given that ScriptModule today also uses OrderedDict. Since C++ frontend modules and ScriptModules will soon too share as many implementation details as possible, it is overall the best move to ditch the custom cursor datastructure and pervasively use OrderedDict everywhere.
For this I did:
1. Changed the C++ frontend module interface to more closely match the Python one by providing `parameters()`, `named_parameters()` and other methods Python provides. This is very important for the following diff which binds these into Python for inter-op with Python modules.
2. In lieu of the `Cursor::apply()` method I added `nn::Module::apply`. This again is one more unifying step between Python and C++, since Python modules have an apply function too.
3. Deleted all uses of Cursor.
4. Tidied and beefed up the `OrderedDict` class. In particular, I made `OrderedDict::Item` store an `std::pair` under the hood, because that is trivial to bind into Python and saved me a lot of headaches. `key` and `value` become methods instead of fields, which they should have been from the very start anyway because it allows exactly these kinds of changes, as per usual good software engineering principle of encapsulation.
5. Added many tests for the OrderedDict use in `nn::Module`.
ebetica ezyang
Pull Request resolved: https://github.com/pytorch/pytorch/pull/13427
Differential Revision: D12894092
Pulled By: goldsborough
fbshipit-source-id: 715770c95a9643753a1db26d7f9da9a78619a15d
2018-11-07 18:53:07 +00:00
|
|
|
auto grad = parameter.grad();
|
2018-09-22 04:12:37 +00:00
|
|
|
ASSERT_TRUE(grad.defined());
|
Remove caffe2::Tensor::capacity_nbytes, at::Tensor::to##name##Data, (#11876)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/11876
Modern C++ api instead of macros, item() is aligned with Python frontend. caffe2::Tensor::capacity_nbytes is effecitvely unused and confusing w.r.t. caffe2::Tensor::nbytes().
codemod -d caffe2 --extensions cc,cpp,cu,cuh,h,py,hpp,mm toCByte "item<uint8_t>"
codemod -d caffe2 --extensions cc,cpp,cu,cuh,h,py,hpp,mm toCLong "item<int64_t>"
codemod -d caffe2 --extensions cc,cpp,cu,cuh,h,py,hpp,mm toCInt "item<int32_t>"
codemod -d caffe2 --extensions cc,cpp,cu,cuh,h,py,hpp,mm toCDouble "item<double>"
codemod -d caffe2 --extensions cc,cpp,cu,cuh,h,py,hpp,mm toCFloat "item<float>"
codemod -d caffe2 --extensions cc,cpp,cu,cuh,h,py,hpp,mm toByteData "data<uint8_t>"
codemod -d caffe2 --extensions cc,cpp,cu,cuh,h,py,hpp,mm toLongData "data<int64_t>"
codemod -d caffe2 --extensions cc,cpp,cu,cuh,h,py,hpp,mm toIntData "data<int32_t>"
codemod -d caffe2 --extensions cc,cpp,cu,cuh,h,py,hpp,mm toDoubleData "data<double>"
codemod -d caffe2 --extensions cc,cpp,cu,cuh,h,py,hpp,mm toFloatData "data<float>"
codemod -d hphp --extensions cc,cpp,cu,cuh,h,py,hpp,mm toCByte "item<uint8_t>"
codemod -d hphp --extensions cc,cpp,cu,cuh,h,py,hpp,mm toCLong "item<int64_t>"
codemod -d hphp --extensions cc,cpp,cu,cuh,h,py,hpp,mm toCInt "item<int32_t>"
codemod -d hphp --extensions cc,cpp,cu,cuh,h,py,hpp,mm toCDouble "item<double>"
codemod -d hphp --extensions cc,cpp,cu,cuh,h,py,hpp,mm toCFloat "item<float>"
codemod -d hphp --extensions cc,cpp,cu,cuh,h,py,hpp,mm toByteData "data<uint8_t>"
codemod -d hphp --extensions cc,cpp,cu,cuh,h,py,hpp,mm toLongData "data<int64_t>"
codemod -d hphp --extensions cc,cpp,cu,cuh,h,py,hpp,mm toIntData "data<int32_t>"
codemod -d hphp --extensions cc,cpp,cu,cuh,h,py,hpp,mm toDoubleData "data<double>"
codemod -d hphp --extensions cc,cpp,cu,cuh,h,py,hpp,mm toFloatData "data<float>"
codemod -d caffe2 --extensions cc,cpp,cu,cuh,h,py,hpp,mm toCComplexDouble "item<std::complex<double>>"
codemod -d tc --extensions cc,cpp,cu,cuh,h,py,hpp,mm toCFloat "item<float>"
Reviewed By: ezyang
Differential Revision: D9948572
fbshipit-source-id: 70c9f5390d92b82c85fdd5f8a5aebca338ab413c
2018-09-24 17:39:10 +00:00
|
|
|
ASSERT_NE(grad.sum().item<float>(), 0);
|
2018-05-09 21:01:19 +00:00
|
|
|
}
|
2018-05-24 05:11:32 +00:00
|
|
|
module->zero_grad();
|
|
|
|
|
for (auto& parameter : module->parameters()) {
|
Make PyTorch code-base clang-tidy compliant (#56892)
Summary:
This is an automatic change generated by the following script:
```
#!/usr/bin/env python3
from subprocess import check_output, check_call
import os
def get_compiled_files_list():
import json
with open("build/compile_commands.json") as f:
data = json.load(f)
files = [os.path.relpath(node['file']) for node in data]
for idx, fname in enumerate(files):
if fname.startswith('build/') and fname.endswith('.DEFAULT.cpp'):
files[idx] = fname[len('build/'):-len('.DEFAULT.cpp')]
return files
def run_clang_tidy(fname):
check_call(["python3", "tools/clang_tidy.py", "-c", "build", "-x", fname,"-s"])
changes = check_output(["git", "ls-files", "-m"])
if len(changes) == 0:
return
check_call(["git", "commit","--all", "-m", f"NOLINT stubs for {fname}"])
def main():
git_files = check_output(["git", "ls-files"]).decode("ascii").split("\n")
compiled_files = get_compiled_files_list()
for idx, fname in enumerate(git_files):
if fname not in compiled_files:
continue
if fname.startswith("caffe2/contrib/aten/"):
continue
print(f"[{idx}/{len(git_files)}] Processing {fname}")
run_clang_tidy(fname)
if __name__ == "__main__":
main()
```
Pull Request resolved: https://github.com/pytorch/pytorch/pull/56892
Reviewed By: H-Huang
Differential Revision: D27991944
Pulled By: malfet
fbshipit-source-id: 5415e1eb2c1b34319a4f03024bfaa087007d7179
2021-04-28 21:09:06 +00:00
|
|
|
// NOLINTNEXTLINE(performance-unnecessary-copy-initialization)
|
Replace cursors with OrderedDict (#13427)
Summary:
This is a pre-cursor diff to Python <-> C++ frontend integration -- I have a follow-up PR coming for that. This PR changes the C++ frontend module interface to replace the custom "cursor"s I introduced some time ago with `OrderedDict`. I introduced cursors at the time as a convenient way of applying functions and query operations on a modules' parameters, buffers and modules, allowing things like `module.parameters().map(my_func)`. However, I noticed that (1) this functionality is easily implement-able on top of a regular data structure and (2) more importantly, using OrderedDicts is much, much easier for Python integration. This is especially true given that ScriptModule today also uses OrderedDict. Since C++ frontend modules and ScriptModules will soon too share as many implementation details as possible, it is overall the best move to ditch the custom cursor datastructure and pervasively use OrderedDict everywhere.
For this I did:
1. Changed the C++ frontend module interface to more closely match the Python one by providing `parameters()`, `named_parameters()` and other methods Python provides. This is very important for the following diff which binds these into Python for inter-op with Python modules.
2. In lieu of the `Cursor::apply()` method I added `nn::Module::apply`. This again is one more unifying step between Python and C++, since Python modules have an apply function too.
3. Deleted all uses of Cursor.
4. Tidied and beefed up the `OrderedDict` class. In particular, I made `OrderedDict::Item` store an `std::pair` under the hood, because that is trivial to bind into Python and saved me a lot of headaches. `key` and `value` become methods instead of fields, which they should have been from the very start anyway because it allows exactly these kinds of changes, as per usual good software engineering principle of encapsulation.
5. Added many tests for the OrderedDict use in `nn::Module`.
ebetica ezyang
Pull Request resolved: https://github.com/pytorch/pytorch/pull/13427
Differential Revision: D12894092
Pulled By: goldsborough
fbshipit-source-id: 715770c95a9643753a1db26d7f9da9a78619a15d
2018-11-07 18:53:07 +00:00
|
|
|
auto grad = parameter.grad();
|
2018-09-22 04:12:37 +00:00
|
|
|
ASSERT_TRUE(grad.defined());
|
Remove caffe2::Tensor::capacity_nbytes, at::Tensor::to##name##Data, (#11876)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/11876
Modern C++ api instead of macros, item() is aligned with Python frontend. caffe2::Tensor::capacity_nbytes is effecitvely unused and confusing w.r.t. caffe2::Tensor::nbytes().
codemod -d caffe2 --extensions cc,cpp,cu,cuh,h,py,hpp,mm toCByte "item<uint8_t>"
codemod -d caffe2 --extensions cc,cpp,cu,cuh,h,py,hpp,mm toCLong "item<int64_t>"
codemod -d caffe2 --extensions cc,cpp,cu,cuh,h,py,hpp,mm toCInt "item<int32_t>"
codemod -d caffe2 --extensions cc,cpp,cu,cuh,h,py,hpp,mm toCDouble "item<double>"
codemod -d caffe2 --extensions cc,cpp,cu,cuh,h,py,hpp,mm toCFloat "item<float>"
codemod -d caffe2 --extensions cc,cpp,cu,cuh,h,py,hpp,mm toByteData "data<uint8_t>"
codemod -d caffe2 --extensions cc,cpp,cu,cuh,h,py,hpp,mm toLongData "data<int64_t>"
codemod -d caffe2 --extensions cc,cpp,cu,cuh,h,py,hpp,mm toIntData "data<int32_t>"
codemod -d caffe2 --extensions cc,cpp,cu,cuh,h,py,hpp,mm toDoubleData "data<double>"
codemod -d caffe2 --extensions cc,cpp,cu,cuh,h,py,hpp,mm toFloatData "data<float>"
codemod -d hphp --extensions cc,cpp,cu,cuh,h,py,hpp,mm toCByte "item<uint8_t>"
codemod -d hphp --extensions cc,cpp,cu,cuh,h,py,hpp,mm toCLong "item<int64_t>"
codemod -d hphp --extensions cc,cpp,cu,cuh,h,py,hpp,mm toCInt "item<int32_t>"
codemod -d hphp --extensions cc,cpp,cu,cuh,h,py,hpp,mm toCDouble "item<double>"
codemod -d hphp --extensions cc,cpp,cu,cuh,h,py,hpp,mm toCFloat "item<float>"
codemod -d hphp --extensions cc,cpp,cu,cuh,h,py,hpp,mm toByteData "data<uint8_t>"
codemod -d hphp --extensions cc,cpp,cu,cuh,h,py,hpp,mm toLongData "data<int64_t>"
codemod -d hphp --extensions cc,cpp,cu,cuh,h,py,hpp,mm toIntData "data<int32_t>"
codemod -d hphp --extensions cc,cpp,cu,cuh,h,py,hpp,mm toDoubleData "data<double>"
codemod -d hphp --extensions cc,cpp,cu,cuh,h,py,hpp,mm toFloatData "data<float>"
codemod -d caffe2 --extensions cc,cpp,cu,cuh,h,py,hpp,mm toCComplexDouble "item<std::complex<double>>"
codemod -d tc --extensions cc,cpp,cu,cuh,h,py,hpp,mm toCFloat "item<float>"
Reviewed By: ezyang
Differential Revision: D9948572
fbshipit-source-id: 70c9f5390d92b82c85fdd5f8a5aebca338ab413c
2018-09-24 17:39:10 +00:00
|
|
|
ASSERT_EQ(grad.sum().item<float>(), 0);
|
2018-05-09 21:01:19 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-22 04:12:37 +00:00
|
|
|
TEST_F(ModuleTest, ZeroGradWithUndefined) {
|
2018-06-28 17:20:58 +00:00
|
|
|
struct TestModule : torch::nn::Module {
|
|
|
|
|
TestModule() {
|
2018-11-06 22:28:20 +00:00
|
|
|
x = register_parameter("x", torch::ones(5, torch::requires_grad()));
|
|
|
|
|
y = register_parameter("y", torch::ones(5, torch::requires_grad()));
|
2018-06-28 17:20:58 +00:00
|
|
|
}
|
|
|
|
|
torch::Tensor x, y;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
TestModule module;
|
|
|
|
|
auto z = module.x * 2;
|
|
|
|
|
z.sum().backward();
|
|
|
|
|
|
2018-09-22 04:12:37 +00:00
|
|
|
ASSERT_TRUE(module.x.grad().defined());
|
|
|
|
|
ASSERT_FALSE(module.y.grad().defined());
|
2018-06-28 17:20:58 +00:00
|
|
|
|
|
|
|
|
module.zero_grad();
|
|
|
|
|
|
2018-09-22 04:12:37 +00:00
|
|
|
ASSERT_TRUE(module.x.grad().defined());
|
|
|
|
|
ASSERT_FALSE(module.y.grad().defined());
|
2018-06-28 17:20:58 +00:00
|
|
|
|
Remove caffe2::Tensor::capacity_nbytes, at::Tensor::to##name##Data, (#11876)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/11876
Modern C++ api instead of macros, item() is aligned with Python frontend. caffe2::Tensor::capacity_nbytes is effecitvely unused and confusing w.r.t. caffe2::Tensor::nbytes().
codemod -d caffe2 --extensions cc,cpp,cu,cuh,h,py,hpp,mm toCByte "item<uint8_t>"
codemod -d caffe2 --extensions cc,cpp,cu,cuh,h,py,hpp,mm toCLong "item<int64_t>"
codemod -d caffe2 --extensions cc,cpp,cu,cuh,h,py,hpp,mm toCInt "item<int32_t>"
codemod -d caffe2 --extensions cc,cpp,cu,cuh,h,py,hpp,mm toCDouble "item<double>"
codemod -d caffe2 --extensions cc,cpp,cu,cuh,h,py,hpp,mm toCFloat "item<float>"
codemod -d caffe2 --extensions cc,cpp,cu,cuh,h,py,hpp,mm toByteData "data<uint8_t>"
codemod -d caffe2 --extensions cc,cpp,cu,cuh,h,py,hpp,mm toLongData "data<int64_t>"
codemod -d caffe2 --extensions cc,cpp,cu,cuh,h,py,hpp,mm toIntData "data<int32_t>"
codemod -d caffe2 --extensions cc,cpp,cu,cuh,h,py,hpp,mm toDoubleData "data<double>"
codemod -d caffe2 --extensions cc,cpp,cu,cuh,h,py,hpp,mm toFloatData "data<float>"
codemod -d hphp --extensions cc,cpp,cu,cuh,h,py,hpp,mm toCByte "item<uint8_t>"
codemod -d hphp --extensions cc,cpp,cu,cuh,h,py,hpp,mm toCLong "item<int64_t>"
codemod -d hphp --extensions cc,cpp,cu,cuh,h,py,hpp,mm toCInt "item<int32_t>"
codemod -d hphp --extensions cc,cpp,cu,cuh,h,py,hpp,mm toCDouble "item<double>"
codemod -d hphp --extensions cc,cpp,cu,cuh,h,py,hpp,mm toCFloat "item<float>"
codemod -d hphp --extensions cc,cpp,cu,cuh,h,py,hpp,mm toByteData "data<uint8_t>"
codemod -d hphp --extensions cc,cpp,cu,cuh,h,py,hpp,mm toLongData "data<int64_t>"
codemod -d hphp --extensions cc,cpp,cu,cuh,h,py,hpp,mm toIntData "data<int32_t>"
codemod -d hphp --extensions cc,cpp,cu,cuh,h,py,hpp,mm toDoubleData "data<double>"
codemod -d hphp --extensions cc,cpp,cu,cuh,h,py,hpp,mm toFloatData "data<float>"
codemod -d caffe2 --extensions cc,cpp,cu,cuh,h,py,hpp,mm toCComplexDouble "item<std::complex<double>>"
codemod -d tc --extensions cc,cpp,cu,cuh,h,py,hpp,mm toCFloat "item<float>"
Reviewed By: ezyang
Differential Revision: D9948572
fbshipit-source-id: 70c9f5390d92b82c85fdd5f8a5aebca338ab413c
2018-09-24 17:39:10 +00:00
|
|
|
ASSERT_EQ(module.x.grad().sum().item<float>(), 0);
|
2021-11-29 16:35:19 +00:00
|
|
|
|
|
|
|
|
module.zero_grad(true); // set_to_none = true
|
|
|
|
|
|
|
|
|
|
ASSERT_FALSE(module.x.grad().defined());
|
|
|
|
|
ASSERT_FALSE(module.y.grad().defined());
|
2018-06-28 17:20:58 +00:00
|
|
|
}
|
|
|
|
|
|
2018-10-25 20:50:06 +00:00
|
|
|
TEST_F(ModuleTest, RegisterModuleThrowsForEmptyOrDottedName) {
|
2019-07-24 03:58:54 +00:00
|
|
|
struct TestModel : public torch::nn::Module {};
|
2018-10-25 20:50:06 +00:00
|
|
|
ASSERT_THROWS_WITH(
|
|
|
|
|
TestModel{}.register_module("name.with.dot", torch::nn::Linear(3, 4)),
|
|
|
|
|
"Submodule name must not contain a dot (got 'name.with.dot')");
|
|
|
|
|
ASSERT_THROWS_WITH(
|
|
|
|
|
TestModel{}.register_module("", torch::nn::Linear(3, 4)),
|
|
|
|
|
"Submodule name must not be empty");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(ModuleTest, RegisterModuleThrowsForDuplicateModuleName) {
|
2019-07-24 03:58:54 +00:00
|
|
|
struct TestModel : public torch::nn::Module {};
|
2018-10-25 20:50:06 +00:00
|
|
|
TestModel model;
|
|
|
|
|
model.register_module("linear", torch::nn::Linear(3, 4));
|
|
|
|
|
ASSERT_THROWS_WITH(
|
|
|
|
|
model.register_module("linear", torch::nn::Linear(3, 4)),
|
|
|
|
|
"Submodule 'linear' already defined");
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-23 18:45:33 +00:00
|
|
|
TEST_F(ModuleTest, ReplaceModuleThrowsForUnknownModuleName) {
|
|
|
|
|
torch::nn::Module model;
|
|
|
|
|
ASSERT_THROWS_WITH(
|
|
|
|
|
model.replace_module("linear", torch::nn::Linear(3, 4)),
|
|
|
|
|
"Submodule 'linear' is not defined");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(ModuleTest, ReplaceModule) {
|
|
|
|
|
struct TestModel : public torch::nn::Module {
|
|
|
|
|
torch::nn::Linear l1{nullptr};
|
|
|
|
|
TestModel() {
|
|
|
|
|
l1 = register_module("l1", torch::nn::Linear(3, 4));
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
auto model = std::make_shared<TestModel>();
|
|
|
|
|
model->l1 = model->replace_module("l1", torch::nn::Linear(5, 6));
|
|
|
|
|
ASSERT_EQ(model->named_parameters()["l1.weight"].size(0), 6);
|
|
|
|
|
ASSERT_EQ(model->l1.get(), model->named_modules()["l1"]->as<Linear>());
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-13 01:23:25 +00:00
|
|
|
TEST_F(ModuleTest, UnregisterModule) {
|
|
|
|
|
struct TestModel : public torch::nn::Module {};
|
|
|
|
|
TestModel model;
|
|
|
|
|
ASSERT_THROWS_WITH(
|
|
|
|
|
model.unregister_module("linear"),
|
|
|
|
|
"No Module with name `linear` is registered");
|
|
|
|
|
model.register_module("linear", torch::nn::Linear(3, 4));
|
|
|
|
|
model.unregister_module("linear");
|
|
|
|
|
ASSERT_TRUE(model.children().empty());
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-25 20:50:06 +00:00
|
|
|
TEST_F(ModuleTest, RegisterParameterThrowsForEmptyOrDottedName) {
|
2019-07-24 03:58:54 +00:00
|
|
|
struct TestModel : public torch::nn::Module {};
|
2018-10-25 20:50:06 +00:00
|
|
|
ASSERT_THROWS_WITH(
|
|
|
|
|
TestModel{}.register_parameter("name.with.dot", torch::ones(5)),
|
|
|
|
|
"Parameter name must not contain a dot (got 'name.with.dot')");
|
|
|
|
|
ASSERT_THROWS_WITH(
|
|
|
|
|
TestModel{}.register_parameter("", torch::ones(5)),
|
|
|
|
|
"Parameter name must not be empty");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(ModuleTest, RegisterParameterThrowsForDuplicateModuleName) {
|
2019-07-24 03:58:54 +00:00
|
|
|
struct TestModel : public torch::nn::Module {};
|
2018-10-25 20:50:06 +00:00
|
|
|
TestModel model;
|
|
|
|
|
model.register_parameter("p", torch::ones(5));
|
|
|
|
|
ASSERT_THROWS_WITH(
|
|
|
|
|
model.register_parameter("p", torch::ones(5)),
|
|
|
|
|
"Parameter 'p' already defined");
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-15 17:05:00 +00:00
|
|
|
TEST_F(ModuleTest, RegisterParameterUndefinedTensor) {
|
|
|
|
|
struct TestModel : public torch::nn::Module {};
|
|
|
|
|
{
|
|
|
|
|
TestModel model;
|
|
|
|
|
model.register_parameter(
|
|
|
|
|
"undefined_tensor", torch::Tensor(), /*requires_grad=*/false);
|
2019-12-03 05:57:28 +00:00
|
|
|
ASSERT_EQ(model.parameters().size(), 0);
|
2019-10-15 17:05:00 +00:00
|
|
|
}
|
|
|
|
|
{
|
2020-04-23 08:05:31 +00:00
|
|
|
WarningCapture warnings;
|
2019-10-15 17:05:00 +00:00
|
|
|
|
|
|
|
|
TestModel model;
|
|
|
|
|
model.register_parameter("undefined_tensor", torch::Tensor());
|
2019-12-03 05:57:28 +00:00
|
|
|
ASSERT_EQ(model.parameters().size(), 0);
|
2019-10-15 17:05:00 +00:00
|
|
|
|
|
|
|
|
ASSERT_EQ(
|
|
|
|
|
count_substr_occurrences(
|
2020-04-23 08:05:31 +00:00
|
|
|
warnings.str(),
|
2019-10-15 17:05:00 +00:00
|
|
|
"Ignoring the `requires_grad=true` function parameter"),
|
|
|
|
|
1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-25 20:50:06 +00:00
|
|
|
TEST_F(ModuleTest, RegisterBufferThrowsForEmptyOrDottedName) {
|
2019-07-24 03:58:54 +00:00
|
|
|
struct TestModel : public torch::nn::Module {};
|
2018-10-25 20:50:06 +00:00
|
|
|
ASSERT_THROWS_WITH(
|
|
|
|
|
TestModel{}.register_buffer("name.with.dot", torch::ones(5)),
|
|
|
|
|
"Buffer name must not contain a dot (got 'name.with.dot')");
|
|
|
|
|
ASSERT_THROWS_WITH(
|
|
|
|
|
TestModel{}.register_buffer("", torch::ones(5)),
|
|
|
|
|
"Buffer name must not be empty");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(ModuleTest, RegisterBufferThrowsForDuplicateModuleName) {
|
2019-07-24 03:58:54 +00:00
|
|
|
struct TestModel : public torch::nn::Module {};
|
2018-10-25 20:50:06 +00:00
|
|
|
TestModel model;
|
|
|
|
|
model.register_buffer("p", torch::ones(5));
|
|
|
|
|
ASSERT_THROWS_WITH(
|
|
|
|
|
model.register_buffer("p", torch::ones(5)), "Buffer 'p' already defined");
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-22 04:12:37 +00:00
|
|
|
TEST_F(ModuleTest, CanGetName) {
|
2018-05-12 01:56:53 +00:00
|
|
|
// CHECK instead of REQUIRE because demangling may fail.
|
2018-05-10 15:52:38 +00:00
|
|
|
AGIUnit agi;
|
|
|
|
|
// Call it twice just to make sure there are no bugs in the lazy
|
|
|
|
|
// initialization semantics.
|
2018-11-14 00:30:05 +00:00
|
|
|
EXPECT_EQ(agi.name(), "AGIUnit");
|
|
|
|
|
EXPECT_EQ(agi.name(), "AGIUnit");
|
|
|
|
|
EXPECT_EQ(test::AGIUnit().name(), "test::AGIUnit");
|
|
|
|
|
EXPECT_EQ(test::AGIUnit2().name(), "Foo");
|
2018-05-10 15:52:38 +00:00
|
|
|
}
|
|
|
|
|
|
Replace cursors with OrderedDict (#13427)
Summary:
This is a pre-cursor diff to Python <-> C++ frontend integration -- I have a follow-up PR coming for that. This PR changes the C++ frontend module interface to replace the custom "cursor"s I introduced some time ago with `OrderedDict`. I introduced cursors at the time as a convenient way of applying functions and query operations on a modules' parameters, buffers and modules, allowing things like `module.parameters().map(my_func)`. However, I noticed that (1) this functionality is easily implement-able on top of a regular data structure and (2) more importantly, using OrderedDicts is much, much easier for Python integration. This is especially true given that ScriptModule today also uses OrderedDict. Since C++ frontend modules and ScriptModules will soon too share as many implementation details as possible, it is overall the best move to ditch the custom cursor datastructure and pervasively use OrderedDict everywhere.
For this I did:
1. Changed the C++ frontend module interface to more closely match the Python one by providing `parameters()`, `named_parameters()` and other methods Python provides. This is very important for the following diff which binds these into Python for inter-op with Python modules.
2. In lieu of the `Cursor::apply()` method I added `nn::Module::apply`. This again is one more unifying step between Python and C++, since Python modules have an apply function too.
3. Deleted all uses of Cursor.
4. Tidied and beefed up the `OrderedDict` class. In particular, I made `OrderedDict::Item` store an `std::pair` under the hood, because that is trivial to bind into Python and saved me a lot of headaches. `key` and `value` become methods instead of fields, which they should have been from the very start anyway because it allows exactly these kinds of changes, as per usual good software engineering principle of encapsulation.
5. Added many tests for the OrderedDict use in `nn::Module`.
ebetica ezyang
Pull Request resolved: https://github.com/pytorch/pytorch/pull/13427
Differential Revision: D12894092
Pulled By: goldsborough
fbshipit-source-id: 715770c95a9643753a1db26d7f9da9a78619a15d
2018-11-07 18:53:07 +00:00
|
|
|
TEST_F(ModuleTest, AsCastsModulesCorrectly) {
|
2018-06-28 22:56:42 +00:00
|
|
|
Linear module(3, 4);
|
2018-09-22 04:12:37 +00:00
|
|
|
ASSERT_EQ(module->as<Linear>(), module.get());
|
|
|
|
|
ASSERT_EQ(module->as<LinearImpl>(), module.get());
|
|
|
|
|
ASSERT_EQ(module->as<Module>(), module.get());
|
|
|
|
|
ASSERT_EQ(module->as<AGIUnit>(), nullptr);
|
2018-07-06 17:55:18 +00:00
|
|
|
|
|
|
|
|
std::shared_ptr<Module> raw = module.ptr();
|
2018-09-22 04:12:37 +00:00
|
|
|
ASSERT_EQ(raw->as<Linear>(), module.get());
|
|
|
|
|
ASSERT_EQ(raw->as<LinearImpl>(), module.get());
|
|
|
|
|
ASSERT_EQ(raw->as<Module>(), module.get());
|
|
|
|
|
ASSERT_EQ(raw->as<AGIUnit>(), nullptr);
|
2018-07-06 17:55:18 +00:00
|
|
|
|
|
|
|
|
Module& raw_ref = *raw.get();
|
2018-09-22 04:12:37 +00:00
|
|
|
ASSERT_EQ(raw_ref.as<Linear>(), module.get());
|
|
|
|
|
ASSERT_EQ(raw_ref.as<LinearImpl>(), module.get());
|
|
|
|
|
ASSERT_EQ(raw_ref.as<Module>(), module.get());
|
|
|
|
|
ASSERT_EQ(raw_ref.as<AGIUnit>(), nullptr);
|
2018-07-06 17:55:18 +00:00
|
|
|
if (auto* linear = raw_ref.as<Linear>()) {
|
2018-09-22 04:12:37 +00:00
|
|
|
ASSERT_EQ(linear->weight.ndimension(), 2);
|
2018-07-06 17:55:18 +00:00
|
|
|
}
|
2018-06-28 22:56:42 +00:00
|
|
|
|
|
|
|
|
AGIUnit unit;
|
2018-09-22 04:12:37 +00:00
|
|
|
ASSERT_EQ(unit.as<Linear>(), nullptr);
|
|
|
|
|
ASSERT_EQ(unit.as<LinearImpl>(), nullptr);
|
|
|
|
|
ASSERT_EQ(unit.as<AGIUnit>(), &unit);
|
2018-06-28 22:56:42 +00:00
|
|
|
}
|
|
|
|
|
|
2019-11-28 05:18:45 +00:00
|
|
|
void test_DeviceOrDtypeConversionSkipsUndefinedTensor(
|
|
|
|
|
torch::Device to_device,
|
|
|
|
|
torch::Dtype to_dtype) {
|
|
|
|
|
{
|
|
|
|
|
// Case 1: Undefined tensors as parameters
|
|
|
|
|
Linear module(LinearOptions(10, 20).bias(false));
|
|
|
|
|
ASSERT_TRUE(module->weight.defined());
|
|
|
|
|
ASSERT_FALSE(module->bias.defined());
|
|
|
|
|
|
|
|
|
|
module->to(to_device);
|
|
|
|
|
ASSERT_TRUE(module->weight.defined());
|
|
|
|
|
ASSERT_EQ(module->weight.device().type(), to_device.type());
|
|
|
|
|
ASSERT_FALSE(module->bias.defined());
|
|
|
|
|
|
|
|
|
|
module->to(to_dtype);
|
|
|
|
|
ASSERT_TRUE(module->weight.defined());
|
|
|
|
|
ASSERT_EQ(module->weight.dtype(), to_dtype);
|
|
|
|
|
ASSERT_FALSE(module->bias.defined());
|
|
|
|
|
}
|
|
|
|
|
{
|
|
|
|
|
// Case 2: Undefined tensors as buffers
|
|
|
|
|
BatchNorm1d module(
|
|
|
|
|
BatchNorm1dOptions(5).track_running_stats(false).affine(true));
|
|
|
|
|
ASSERT_TRUE(module->weight.defined());
|
|
|
|
|
ASSERT_FALSE(module->running_mean.defined());
|
|
|
|
|
|
|
|
|
|
module->to(to_device);
|
|
|
|
|
ASSERT_TRUE(module->weight.defined());
|
|
|
|
|
ASSERT_EQ(module->weight.device().type(), to_device.type());
|
|
|
|
|
ASSERT_FALSE(module->running_mean.defined());
|
|
|
|
|
|
|
|
|
|
module->to(to_dtype);
|
|
|
|
|
ASSERT_TRUE(module->weight.defined());
|
|
|
|
|
ASSERT_EQ(module->weight.dtype(), to_dtype);
|
|
|
|
|
ASSERT_FALSE(module->running_mean.defined());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(ModuleTest, DeviceOrDtypeConversionSkipsUndefinedTensor) {
|
|
|
|
|
test_DeviceOrDtypeConversionSkipsUndefinedTensor(torch::kCPU, torch::kDouble);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(ModuleTest, DeviceOrDtypeConversionSkipsUndefinedTensor_CUDA) {
|
|
|
|
|
test_DeviceOrDtypeConversionSkipsUndefinedTensor(
|
|
|
|
|
torch::kCUDA, torch::kDouble);
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-03 05:57:28 +00:00
|
|
|
TEST_F(ModuleTest, ParametersAndBuffersAccessorSkipsUndefinedTensor) {
|
|
|
|
|
{
|
|
|
|
|
Linear module(LinearOptions(10, 20).bias(false));
|
|
|
|
|
|
|
|
|
|
auto params = module->parameters();
|
|
|
|
|
ASSERT_EQ(params.size(), 1);
|
|
|
|
|
auto named_params = module->named_parameters();
|
|
|
|
|
ASSERT_EQ(named_params.size(), 1);
|
|
|
|
|
|
|
|
|
|
ASSERT_TRUE(pointer_equal(params[0], named_params["weight"]));
|
|
|
|
|
ASSERT_TRUE(pointer_equal(named_params["weight"], module->weight));
|
|
|
|
|
}
|
|
|
|
|
{
|
|
|
|
|
BatchNorm1d module(
|
|
|
|
|
BatchNorm1dOptions(5).track_running_stats(false).affine(false));
|
|
|
|
|
|
|
|
|
|
auto buffers = module->buffers();
|
|
|
|
|
ASSERT_EQ(buffers.size(), 0);
|
|
|
|
|
auto named_buffers = module->named_buffers();
|
|
|
|
|
ASSERT_EQ(named_buffers.size(), 0);
|
|
|
|
|
}
|
|
|
|
|
{
|
|
|
|
|
BatchNorm1d module(
|
|
|
|
|
BatchNorm1dOptions(5).track_running_stats(true).affine(false));
|
|
|
|
|
|
|
|
|
|
auto buffers = module->buffers();
|
|
|
|
|
ASSERT_EQ(buffers.size(), 3);
|
|
|
|
|
auto named_buffers = module->named_buffers();
|
|
|
|
|
ASSERT_EQ(named_buffers.size(), 3);
|
|
|
|
|
|
|
|
|
|
ASSERT_TRUE(pointer_equal(buffers[0], named_buffers["running_mean"]));
|
|
|
|
|
ASSERT_TRUE(
|
|
|
|
|
pointer_equal(named_buffers["running_mean"], module->running_mean));
|
|
|
|
|
ASSERT_TRUE(pointer_equal(buffers[1], named_buffers["running_var"]));
|
|
|
|
|
ASSERT_TRUE(
|
|
|
|
|
pointer_equal(named_buffers["running_var"], module->running_var));
|
|
|
|
|
ASSERT_TRUE(
|
|
|
|
|
pointer_equal(buffers[2], named_buffers["num_batches_tracked"]));
|
|
|
|
|
ASSERT_TRUE(pointer_equal(
|
|
|
|
|
named_buffers["num_batches_tracked"], module->num_batches_tracked));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-22 04:12:37 +00:00
|
|
|
TEST_F(ModuleTest, Conversion_MultiCUDA) {
|
2018-06-26 04:11:49 +00:00
|
|
|
Linear module(128, 64);
|
2018-09-22 04:12:37 +00:00
|
|
|
for (auto& parameter : module->parameters()) {
|
Replace cursors with OrderedDict (#13427)
Summary:
This is a pre-cursor diff to Python <-> C++ frontend integration -- I have a follow-up PR coming for that. This PR changes the C++ frontend module interface to replace the custom "cursor"s I introduced some time ago with `OrderedDict`. I introduced cursors at the time as a convenient way of applying functions and query operations on a modules' parameters, buffers and modules, allowing things like `module.parameters().map(my_func)`. However, I noticed that (1) this functionality is easily implement-able on top of a regular data structure and (2) more importantly, using OrderedDicts is much, much easier for Python integration. This is especially true given that ScriptModule today also uses OrderedDict. Since C++ frontend modules and ScriptModules will soon too share as many implementation details as possible, it is overall the best move to ditch the custom cursor datastructure and pervasively use OrderedDict everywhere.
For this I did:
1. Changed the C++ frontend module interface to more closely match the Python one by providing `parameters()`, `named_parameters()` and other methods Python provides. This is very important for the following diff which binds these into Python for inter-op with Python modules.
2. In lieu of the `Cursor::apply()` method I added `nn::Module::apply`. This again is one more unifying step between Python and C++, since Python modules have an apply function too.
3. Deleted all uses of Cursor.
4. Tidied and beefed up the `OrderedDict` class. In particular, I made `OrderedDict::Item` store an `std::pair` under the hood, because that is trivial to bind into Python and saved me a lot of headaches. `key` and `value` become methods instead of fields, which they should have been from the very start anyway because it allows exactly these kinds of changes, as per usual good software engineering principle of encapsulation.
5. Added many tests for the OrderedDict use in `nn::Module`.
ebetica ezyang
Pull Request resolved: https://github.com/pytorch/pytorch/pull/13427
Differential Revision: D12894092
Pulled By: goldsborough
fbshipit-source-id: 715770c95a9643753a1db26d7f9da9a78619a15d
2018-11-07 18:53:07 +00:00
|
|
|
ASSERT_EQ(parameter.device(), torch::Device(torch::kCPU));
|
|
|
|
|
ASSERT_EQ(parameter.dtype(), torch::kFloat32);
|
2018-05-09 21:01:19 +00:00
|
|
|
}
|
2018-09-22 04:12:37 +00:00
|
|
|
{
|
2018-06-27 21:34:06 +00:00
|
|
|
module->to({torch::kCUDA, 0});
|
2018-05-24 05:11:32 +00:00
|
|
|
for (auto& parameter : module->parameters()) {
|
Replace cursors with OrderedDict (#13427)
Summary:
This is a pre-cursor diff to Python <-> C++ frontend integration -- I have a follow-up PR coming for that. This PR changes the C++ frontend module interface to replace the custom "cursor"s I introduced some time ago with `OrderedDict`. I introduced cursors at the time as a convenient way of applying functions and query operations on a modules' parameters, buffers and modules, allowing things like `module.parameters().map(my_func)`. However, I noticed that (1) this functionality is easily implement-able on top of a regular data structure and (2) more importantly, using OrderedDicts is much, much easier for Python integration. This is especially true given that ScriptModule today also uses OrderedDict. Since C++ frontend modules and ScriptModules will soon too share as many implementation details as possible, it is overall the best move to ditch the custom cursor datastructure and pervasively use OrderedDict everywhere.
For this I did:
1. Changed the C++ frontend module interface to more closely match the Python one by providing `parameters()`, `named_parameters()` and other methods Python provides. This is very important for the following diff which binds these into Python for inter-op with Python modules.
2. In lieu of the `Cursor::apply()` method I added `nn::Module::apply`. This again is one more unifying step between Python and C++, since Python modules have an apply function too.
3. Deleted all uses of Cursor.
4. Tidied and beefed up the `OrderedDict` class. In particular, I made `OrderedDict::Item` store an `std::pair` under the hood, because that is trivial to bind into Python and saved me a lot of headaches. `key` and `value` become methods instead of fields, which they should have been from the very start anyway because it allows exactly these kinds of changes, as per usual good software engineering principle of encapsulation.
5. Added many tests for the OrderedDict use in `nn::Module`.
ebetica ezyang
Pull Request resolved: https://github.com/pytorch/pytorch/pull/13427
Differential Revision: D12894092
Pulled By: goldsborough
fbshipit-source-id: 715770c95a9643753a1db26d7f9da9a78619a15d
2018-11-07 18:53:07 +00:00
|
|
|
ASSERT_EQ(parameter.device().type(), torch::Device::Type::CUDA);
|
|
|
|
|
ASSERT_EQ(parameter.device().index(), 0);
|
2018-06-26 04:11:49 +00:00
|
|
|
}
|
2018-11-06 22:28:20 +00:00
|
|
|
module->to({torch::kCUDA, 1});
|
2018-06-26 04:11:49 +00:00
|
|
|
for (auto& parameter : module->parameters()) {
|
Replace cursors with OrderedDict (#13427)
Summary:
This is a pre-cursor diff to Python <-> C++ frontend integration -- I have a follow-up PR coming for that. This PR changes the C++ frontend module interface to replace the custom "cursor"s I introduced some time ago with `OrderedDict`. I introduced cursors at the time as a convenient way of applying functions and query operations on a modules' parameters, buffers and modules, allowing things like `module.parameters().map(my_func)`. However, I noticed that (1) this functionality is easily implement-able on top of a regular data structure and (2) more importantly, using OrderedDicts is much, much easier for Python integration. This is especially true given that ScriptModule today also uses OrderedDict. Since C++ frontend modules and ScriptModules will soon too share as many implementation details as possible, it is overall the best move to ditch the custom cursor datastructure and pervasively use OrderedDict everywhere.
For this I did:
1. Changed the C++ frontend module interface to more closely match the Python one by providing `parameters()`, `named_parameters()` and other methods Python provides. This is very important for the following diff which binds these into Python for inter-op with Python modules.
2. In lieu of the `Cursor::apply()` method I added `nn::Module::apply`. This again is one more unifying step between Python and C++, since Python modules have an apply function too.
3. Deleted all uses of Cursor.
4. Tidied and beefed up the `OrderedDict` class. In particular, I made `OrderedDict::Item` store an `std::pair` under the hood, because that is trivial to bind into Python and saved me a lot of headaches. `key` and `value` become methods instead of fields, which they should have been from the very start anyway because it allows exactly these kinds of changes, as per usual good software engineering principle of encapsulation.
5. Added many tests for the OrderedDict use in `nn::Module`.
ebetica ezyang
Pull Request resolved: https://github.com/pytorch/pytorch/pull/13427
Differential Revision: D12894092
Pulled By: goldsborough
fbshipit-source-id: 715770c95a9643753a1db26d7f9da9a78619a15d
2018-11-07 18:53:07 +00:00
|
|
|
ASSERT_EQ(parameter.device().type(), torch::Device::Type::CUDA);
|
|
|
|
|
ASSERT_EQ(parameter.device().index(), 1);
|
2018-05-09 21:01:19 +00:00
|
|
|
}
|
|
|
|
|
}
|
2018-09-22 04:12:37 +00:00
|
|
|
{
|
2018-06-27 21:34:06 +00:00
|
|
|
module->to(torch::Device(torch::kCPU));
|
2018-05-24 05:11:32 +00:00
|
|
|
for (auto& parameter : module->parameters()) {
|
Replace cursors with OrderedDict (#13427)
Summary:
This is a pre-cursor diff to Python <-> C++ frontend integration -- I have a follow-up PR coming for that. This PR changes the C++ frontend module interface to replace the custom "cursor"s I introduced some time ago with `OrderedDict`. I introduced cursors at the time as a convenient way of applying functions and query operations on a modules' parameters, buffers and modules, allowing things like `module.parameters().map(my_func)`. However, I noticed that (1) this functionality is easily implement-able on top of a regular data structure and (2) more importantly, using OrderedDicts is much, much easier for Python integration. This is especially true given that ScriptModule today also uses OrderedDict. Since C++ frontend modules and ScriptModules will soon too share as many implementation details as possible, it is overall the best move to ditch the custom cursor datastructure and pervasively use OrderedDict everywhere.
For this I did:
1. Changed the C++ frontend module interface to more closely match the Python one by providing `parameters()`, `named_parameters()` and other methods Python provides. This is very important for the following diff which binds these into Python for inter-op with Python modules.
2. In lieu of the `Cursor::apply()` method I added `nn::Module::apply`. This again is one more unifying step between Python and C++, since Python modules have an apply function too.
3. Deleted all uses of Cursor.
4. Tidied and beefed up the `OrderedDict` class. In particular, I made `OrderedDict::Item` store an `std::pair` under the hood, because that is trivial to bind into Python and saved me a lot of headaches. `key` and `value` become methods instead of fields, which they should have been from the very start anyway because it allows exactly these kinds of changes, as per usual good software engineering principle of encapsulation.
5. Added many tests for the OrderedDict use in `nn::Module`.
ebetica ezyang
Pull Request resolved: https://github.com/pytorch/pytorch/pull/13427
Differential Revision: D12894092
Pulled By: goldsborough
fbshipit-source-id: 715770c95a9643753a1db26d7f9da9a78619a15d
2018-11-07 18:53:07 +00:00
|
|
|
ASSERT_EQ(parameter.device().type(), torch::Device::Type::CPU);
|
2018-05-09 21:01:19 +00:00
|
|
|
}
|
|
|
|
|
}
|
2018-09-22 04:12:37 +00:00
|
|
|
{
|
2022-06-21 23:32:16 +00:00
|
|
|
module->to(torch::kFloat64);
|
2018-05-24 05:11:32 +00:00
|
|
|
for (auto& parameter : module->parameters()) {
|
2022-06-21 23:32:16 +00:00
|
|
|
ASSERT_EQ(parameter.dtype(), torch::kFloat64);
|
2018-05-09 21:01:19 +00:00
|
|
|
}
|
|
|
|
|
}
|
2022-06-21 23:32:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(ModuleTest, Conversion_NoGrad_MultiCUDA) {
|
|
|
|
|
Linear module(128, 64);
|
|
|
|
|
for (auto& parameter : module->parameters()) {
|
|
|
|
|
parameter.requires_grad_(false);
|
|
|
|
|
}
|
2018-09-22 04:12:37 +00:00
|
|
|
{
|
2022-06-21 23:32:16 +00:00
|
|
|
module->to(torch::kInt32);
|
2018-05-24 05:11:32 +00:00
|
|
|
for (auto& parameter : module->parameters()) {
|
2022-06-21 23:32:16 +00:00
|
|
|
ASSERT_EQ(parameter.dtype(), torch::kInt32);
|
2018-05-09 21:01:19 +00:00
|
|
|
}
|
|
|
|
|
}
|
2018-09-22 04:12:37 +00:00
|
|
|
{
|
2018-06-27 21:34:06 +00:00
|
|
|
module->to(torch::Device(torch::kCUDA, 1), torch::kUInt8);
|
2018-06-26 04:11:49 +00:00
|
|
|
for (auto& parameter : module->parameters()) {
|
Replace cursors with OrderedDict (#13427)
Summary:
This is a pre-cursor diff to Python <-> C++ frontend integration -- I have a follow-up PR coming for that. This PR changes the C++ frontend module interface to replace the custom "cursor"s I introduced some time ago with `OrderedDict`. I introduced cursors at the time as a convenient way of applying functions and query operations on a modules' parameters, buffers and modules, allowing things like `module.parameters().map(my_func)`. However, I noticed that (1) this functionality is easily implement-able on top of a regular data structure and (2) more importantly, using OrderedDicts is much, much easier for Python integration. This is especially true given that ScriptModule today also uses OrderedDict. Since C++ frontend modules and ScriptModules will soon too share as many implementation details as possible, it is overall the best move to ditch the custom cursor datastructure and pervasively use OrderedDict everywhere.
For this I did:
1. Changed the C++ frontend module interface to more closely match the Python one by providing `parameters()`, `named_parameters()` and other methods Python provides. This is very important for the following diff which binds these into Python for inter-op with Python modules.
2. In lieu of the `Cursor::apply()` method I added `nn::Module::apply`. This again is one more unifying step between Python and C++, since Python modules have an apply function too.
3. Deleted all uses of Cursor.
4. Tidied and beefed up the `OrderedDict` class. In particular, I made `OrderedDict::Item` store an `std::pair` under the hood, because that is trivial to bind into Python and saved me a lot of headaches. `key` and `value` become methods instead of fields, which they should have been from the very start anyway because it allows exactly these kinds of changes, as per usual good software engineering principle of encapsulation.
5. Added many tests for the OrderedDict use in `nn::Module`.
ebetica ezyang
Pull Request resolved: https://github.com/pytorch/pytorch/pull/13427
Differential Revision: D12894092
Pulled By: goldsborough
fbshipit-source-id: 715770c95a9643753a1db26d7f9da9a78619a15d
2018-11-07 18:53:07 +00:00
|
|
|
ASSERT_EQ(parameter.device().type(), torch::Device::Type::CUDA);
|
|
|
|
|
ASSERT_EQ(parameter.device().index(), 1);
|
2018-06-26 04:11:49 +00:00
|
|
|
}
|
2018-05-24 05:11:32 +00:00
|
|
|
for (auto& parameter : module->parameters()) {
|
Replace cursors with OrderedDict (#13427)
Summary:
This is a pre-cursor diff to Python <-> C++ frontend integration -- I have a follow-up PR coming for that. This PR changes the C++ frontend module interface to replace the custom "cursor"s I introduced some time ago with `OrderedDict`. I introduced cursors at the time as a convenient way of applying functions and query operations on a modules' parameters, buffers and modules, allowing things like `module.parameters().map(my_func)`. However, I noticed that (1) this functionality is easily implement-able on top of a regular data structure and (2) more importantly, using OrderedDicts is much, much easier for Python integration. This is especially true given that ScriptModule today also uses OrderedDict. Since C++ frontend modules and ScriptModules will soon too share as many implementation details as possible, it is overall the best move to ditch the custom cursor datastructure and pervasively use OrderedDict everywhere.
For this I did:
1. Changed the C++ frontend module interface to more closely match the Python one by providing `parameters()`, `named_parameters()` and other methods Python provides. This is very important for the following diff which binds these into Python for inter-op with Python modules.
2. In lieu of the `Cursor::apply()` method I added `nn::Module::apply`. This again is one more unifying step between Python and C++, since Python modules have an apply function too.
3. Deleted all uses of Cursor.
4. Tidied and beefed up the `OrderedDict` class. In particular, I made `OrderedDict::Item` store an `std::pair` under the hood, because that is trivial to bind into Python and saved me a lot of headaches. `key` and `value` become methods instead of fields, which they should have been from the very start anyway because it allows exactly these kinds of changes, as per usual good software engineering principle of encapsulation.
5. Added many tests for the OrderedDict use in `nn::Module`.
ebetica ezyang
Pull Request resolved: https://github.com/pytorch/pytorch/pull/13427
Differential Revision: D12894092
Pulled By: goldsborough
fbshipit-source-id: 715770c95a9643753a1db26d7f9da9a78619a15d
2018-11-07 18:53:07 +00:00
|
|
|
ASSERT_EQ(parameter.dtype(), torch::kUInt8);
|
2018-05-09 21:01:19 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-05-10 07:49:29 +00:00
|
|
|
|
2018-09-22 04:12:37 +00:00
|
|
|
TEST_F(ModuleTest, CallingCloneOnModuleThatDoesNotOverrideCloneThrows) {
|
|
|
|
|
struct UnCloneable : Module {};
|
|
|
|
|
UnCloneable module;
|
|
|
|
|
ASSERT_THROWS_WITH(module.clone(), "clone() has not been implemented");
|
|
|
|
|
}
|
2018-05-10 07:49:29 +00:00
|
|
|
|
2018-09-22 04:12:37 +00:00
|
|
|
TEST_F(ModuleTest, CallingCloneOnModuleThatDoesOverrideCloneDoesNotThrow) {
|
|
|
|
|
struct Cloneable : Module {
|
|
|
|
|
std::shared_ptr<Module> clone(
|
2018-12-14 00:09:08 +00:00
|
|
|
const torch::optional<torch::Device>& device =
|
|
|
|
|
torch::nullopt) const override {
|
2018-09-22 04:12:37 +00:00
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
Cloneable module;
|
Make PyTorch code-base clang-tidy compliant (#56892)
Summary:
This is an automatic change generated by the following script:
```
#!/usr/bin/env python3
from subprocess import check_output, check_call
import os
def get_compiled_files_list():
import json
with open("build/compile_commands.json") as f:
data = json.load(f)
files = [os.path.relpath(node['file']) for node in data]
for idx, fname in enumerate(files):
if fname.startswith('build/') and fname.endswith('.DEFAULT.cpp'):
files[idx] = fname[len('build/'):-len('.DEFAULT.cpp')]
return files
def run_clang_tidy(fname):
check_call(["python3", "tools/clang_tidy.py", "-c", "build", "-x", fname,"-s"])
changes = check_output(["git", "ls-files", "-m"])
if len(changes) == 0:
return
check_call(["git", "commit","--all", "-m", f"NOLINT stubs for {fname}"])
def main():
git_files = check_output(["git", "ls-files"]).decode("ascii").split("\n")
compiled_files = get_compiled_files_list()
for idx, fname in enumerate(git_files):
if fname not in compiled_files:
continue
if fname.startswith("caffe2/contrib/aten/"):
continue
print(f"[{idx}/{len(git_files)}] Processing {fname}")
run_clang_tidy(fname)
if __name__ == "__main__":
main()
```
Pull Request resolved: https://github.com/pytorch/pytorch/pull/56892
Reviewed By: H-Huang
Differential Revision: D27991944
Pulled By: malfet
fbshipit-source-id: 5415e1eb2c1b34319a4f03024bfaa087007d7179
2021-04-28 21:09:06 +00:00
|
|
|
// NOLINTNEXTLINE(hicpp-avoid-goto,cppcoreguidelines-avoid-goto)
|
2018-09-22 04:12:37 +00:00
|
|
|
ASSERT_NO_THROW({ module.clone(); });
|
|
|
|
|
}
|
2018-05-15 01:24:58 +00:00
|
|
|
|
Make PyTorch code-base clang-tidy compliant (#56892)
Summary:
This is an automatic change generated by the following script:
```
#!/usr/bin/env python3
from subprocess import check_output, check_call
import os
def get_compiled_files_list():
import json
with open("build/compile_commands.json") as f:
data = json.load(f)
files = [os.path.relpath(node['file']) for node in data]
for idx, fname in enumerate(files):
if fname.startswith('build/') and fname.endswith('.DEFAULT.cpp'):
files[idx] = fname[len('build/'):-len('.DEFAULT.cpp')]
return files
def run_clang_tidy(fname):
check_call(["python3", "tools/clang_tidy.py", "-c", "build", "-x", fname,"-s"])
changes = check_output(["git", "ls-files", "-m"])
if len(changes) == 0:
return
check_call(["git", "commit","--all", "-m", f"NOLINT stubs for {fname}"])
def main():
git_files = check_output(["git", "ls-files"]).decode("ascii").split("\n")
compiled_files = get_compiled_files_list()
for idx, fname in enumerate(git_files):
if fname not in compiled_files:
continue
if fname.startswith("caffe2/contrib/aten/"):
continue
print(f"[{idx}/{len(git_files)}] Processing {fname}")
run_clang_tidy(fname)
if __name__ == "__main__":
main()
```
Pull Request resolved: https://github.com/pytorch/pytorch/pull/56892
Reviewed By: H-Huang
Differential Revision: D27991944
Pulled By: malfet
fbshipit-source-id: 5415e1eb2c1b34319a4f03024bfaa087007d7179
2021-04-28 21:09:06 +00:00
|
|
|
// NOLINTNEXTLINE(bugprone-exception-escape)
|
2019-07-26 19:42:04 +00:00
|
|
|
struct TestDistinctParametersModule
|
|
|
|
|
: public Cloneable<TestDistinctParametersModule> {
|
|
|
|
|
TestDistinctParametersModule() {
|
Make PyTorch code-base clang-tidy compliant (#56892)
Summary:
This is an automatic change generated by the following script:
```
#!/usr/bin/env python3
from subprocess import check_output, check_call
import os
def get_compiled_files_list():
import json
with open("build/compile_commands.json") as f:
data = json.load(f)
files = [os.path.relpath(node['file']) for node in data]
for idx, fname in enumerate(files):
if fname.startswith('build/') and fname.endswith('.DEFAULT.cpp'):
files[idx] = fname[len('build/'):-len('.DEFAULT.cpp')]
return files
def run_clang_tidy(fname):
check_call(["python3", "tools/clang_tidy.py", "-c", "build", "-x", fname,"-s"])
changes = check_output(["git", "ls-files", "-m"])
if len(changes) == 0:
return
check_call(["git", "commit","--all", "-m", f"NOLINT stubs for {fname}"])
def main():
git_files = check_output(["git", "ls-files"]).decode("ascii").split("\n")
compiled_files = get_compiled_files_list()
for idx, fname in enumerate(git_files):
if fname not in compiled_files:
continue
if fname.startswith("caffe2/contrib/aten/"):
continue
print(f"[{idx}/{len(git_files)}] Processing {fname}")
run_clang_tidy(fname)
if __name__ == "__main__":
main()
```
Pull Request resolved: https://github.com/pytorch/pytorch/pull/56892
Reviewed By: H-Huang
Differential Revision: D27991944
Pulled By: malfet
fbshipit-source-id: 5415e1eb2c1b34319a4f03024bfaa087007d7179
2021-04-28 21:09:06 +00:00
|
|
|
// NOLINTNEXTLINE(clang-analyzer-optin.cplusplus.VirtualCall)
|
2019-07-26 19:42:04 +00:00
|
|
|
reset();
|
|
|
|
|
}
|
|
|
|
|
void reset() override {
|
|
|
|
|
l1 = register_module("l1", Linear(10, 3));
|
|
|
|
|
l2 = register_module("l2", Linear(3, 5));
|
|
|
|
|
l3 = register_module("l3", Linear(5, 100));
|
|
|
|
|
buffer = register_buffer("buf", torch::ones({2, 2}));
|
|
|
|
|
}
|
2018-05-15 01:24:58 +00:00
|
|
|
|
2019-07-26 19:42:04 +00:00
|
|
|
Linear l1{nullptr}, l2{nullptr}, l3{nullptr};
|
|
|
|
|
torch::Tensor buffer;
|
|
|
|
|
};
|
2018-08-16 04:09:33 +00:00
|
|
|
|
2019-07-26 19:42:04 +00:00
|
|
|
void testDistinctParameters(
|
|
|
|
|
std::shared_ptr<Module> m1,
|
|
|
|
|
std::shared_ptr<Module> m2) {
|
|
|
|
|
auto params1 = m1->named_parameters();
|
|
|
|
|
auto params2 = m2->named_parameters();
|
2018-09-22 04:12:37 +00:00
|
|
|
ASSERT_EQ(params1.size(), 6);
|
|
|
|
|
ASSERT_EQ(params2.size(), 6);
|
|
|
|
|
for (auto& param : params1) {
|
Replace cursors with OrderedDict (#13427)
Summary:
This is a pre-cursor diff to Python <-> C++ frontend integration -- I have a follow-up PR coming for that. This PR changes the C++ frontend module interface to replace the custom "cursor"s I introduced some time ago with `OrderedDict`. I introduced cursors at the time as a convenient way of applying functions and query operations on a modules' parameters, buffers and modules, allowing things like `module.parameters().map(my_func)`. However, I noticed that (1) this functionality is easily implement-able on top of a regular data structure and (2) more importantly, using OrderedDicts is much, much easier for Python integration. This is especially true given that ScriptModule today also uses OrderedDict. Since C++ frontend modules and ScriptModules will soon too share as many implementation details as possible, it is overall the best move to ditch the custom cursor datastructure and pervasively use OrderedDict everywhere.
For this I did:
1. Changed the C++ frontend module interface to more closely match the Python one by providing `parameters()`, `named_parameters()` and other methods Python provides. This is very important for the following diff which binds these into Python for inter-op with Python modules.
2. In lieu of the `Cursor::apply()` method I added `nn::Module::apply`. This again is one more unifying step between Python and C++, since Python modules have an apply function too.
3. Deleted all uses of Cursor.
4. Tidied and beefed up the `OrderedDict` class. In particular, I made `OrderedDict::Item` store an `std::pair` under the hood, because that is trivial to bind into Python and saved me a lot of headaches. `key` and `value` become methods instead of fields, which they should have been from the very start anyway because it allows exactly these kinds of changes, as per usual good software engineering principle of encapsulation.
5. Added many tests for the OrderedDict use in `nn::Module`.
ebetica ezyang
Pull Request resolved: https://github.com/pytorch/pytorch/pull/13427
Differential Revision: D12894092
Pulled By: goldsborough
fbshipit-source-id: 715770c95a9643753a1db26d7f9da9a78619a15d
2018-11-07 18:53:07 +00:00
|
|
|
ASSERT_FALSE(pointer_equal(param.value(), params2[param.key()]));
|
|
|
|
|
ASSERT_TRUE(param->allclose(params2[param.key()]));
|
2018-09-22 04:12:37 +00:00
|
|
|
param->add_(2);
|
|
|
|
|
}
|
|
|
|
|
for (auto& param : params1) {
|
Replace cursors with OrderedDict (#13427)
Summary:
This is a pre-cursor diff to Python <-> C++ frontend integration -- I have a follow-up PR coming for that. This PR changes the C++ frontend module interface to replace the custom "cursor"s I introduced some time ago with `OrderedDict`. I introduced cursors at the time as a convenient way of applying functions and query operations on a modules' parameters, buffers and modules, allowing things like `module.parameters().map(my_func)`. However, I noticed that (1) this functionality is easily implement-able on top of a regular data structure and (2) more importantly, using OrderedDicts is much, much easier for Python integration. This is especially true given that ScriptModule today also uses OrderedDict. Since C++ frontend modules and ScriptModules will soon too share as many implementation details as possible, it is overall the best move to ditch the custom cursor datastructure and pervasively use OrderedDict everywhere.
For this I did:
1. Changed the C++ frontend module interface to more closely match the Python one by providing `parameters()`, `named_parameters()` and other methods Python provides. This is very important for the following diff which binds these into Python for inter-op with Python modules.
2. In lieu of the `Cursor::apply()` method I added `nn::Module::apply`. This again is one more unifying step between Python and C++, since Python modules have an apply function too.
3. Deleted all uses of Cursor.
4. Tidied and beefed up the `OrderedDict` class. In particular, I made `OrderedDict::Item` store an `std::pair` under the hood, because that is trivial to bind into Python and saved me a lot of headaches. `key` and `value` become methods instead of fields, which they should have been from the very start anyway because it allows exactly these kinds of changes, as per usual good software engineering principle of encapsulation.
5. Added many tests for the OrderedDict use in `nn::Module`.
ebetica ezyang
Pull Request resolved: https://github.com/pytorch/pytorch/pull/13427
Differential Revision: D12894092
Pulled By: goldsborough
fbshipit-source-id: 715770c95a9643753a1db26d7f9da9a78619a15d
2018-11-07 18:53:07 +00:00
|
|
|
ASSERT_FALSE(param->allclose(params2[param.key()]));
|
2018-09-22 04:12:37 +00:00
|
|
|
}
|
2018-06-26 04:11:49 +00:00
|
|
|
|
2019-07-26 19:42:04 +00:00
|
|
|
auto buffers1 = m1->named_buffers();
|
|
|
|
|
auto buffers2 = m2->named_buffers();
|
2018-09-22 04:12:37 +00:00
|
|
|
ASSERT_EQ(buffers1.size(), 1);
|
|
|
|
|
ASSERT_EQ(buffers2.size(), 1);
|
|
|
|
|
for (auto& buffer : buffers1) {
|
Replace cursors with OrderedDict (#13427)
Summary:
This is a pre-cursor diff to Python <-> C++ frontend integration -- I have a follow-up PR coming for that. This PR changes the C++ frontend module interface to replace the custom "cursor"s I introduced some time ago with `OrderedDict`. I introduced cursors at the time as a convenient way of applying functions and query operations on a modules' parameters, buffers and modules, allowing things like `module.parameters().map(my_func)`. However, I noticed that (1) this functionality is easily implement-able on top of a regular data structure and (2) more importantly, using OrderedDicts is much, much easier for Python integration. This is especially true given that ScriptModule today also uses OrderedDict. Since C++ frontend modules and ScriptModules will soon too share as many implementation details as possible, it is overall the best move to ditch the custom cursor datastructure and pervasively use OrderedDict everywhere.
For this I did:
1. Changed the C++ frontend module interface to more closely match the Python one by providing `parameters()`, `named_parameters()` and other methods Python provides. This is very important for the following diff which binds these into Python for inter-op with Python modules.
2. In lieu of the `Cursor::apply()` method I added `nn::Module::apply`. This again is one more unifying step between Python and C++, since Python modules have an apply function too.
3. Deleted all uses of Cursor.
4. Tidied and beefed up the `OrderedDict` class. In particular, I made `OrderedDict::Item` store an `std::pair` under the hood, because that is trivial to bind into Python and saved me a lot of headaches. `key` and `value` become methods instead of fields, which they should have been from the very start anyway because it allows exactly these kinds of changes, as per usual good software engineering principle of encapsulation.
5. Added many tests for the OrderedDict use in `nn::Module`.
ebetica ezyang
Pull Request resolved: https://github.com/pytorch/pytorch/pull/13427
Differential Revision: D12894092
Pulled By: goldsborough
fbshipit-source-id: 715770c95a9643753a1db26d7f9da9a78619a15d
2018-11-07 18:53:07 +00:00
|
|
|
ASSERT_FALSE(pointer_equal(buffer.value(), buffers2[buffer.key()]));
|
|
|
|
|
ASSERT_TRUE(buffer->allclose(buffers2[buffer.key()]));
|
2018-09-22 04:12:37 +00:00
|
|
|
buffer->add_(2);
|
|
|
|
|
}
|
|
|
|
|
for (auto& buffer : buffers1) {
|
Replace cursors with OrderedDict (#13427)
Summary:
This is a pre-cursor diff to Python <-> C++ frontend integration -- I have a follow-up PR coming for that. This PR changes the C++ frontend module interface to replace the custom "cursor"s I introduced some time ago with `OrderedDict`. I introduced cursors at the time as a convenient way of applying functions and query operations on a modules' parameters, buffers and modules, allowing things like `module.parameters().map(my_func)`. However, I noticed that (1) this functionality is easily implement-able on top of a regular data structure and (2) more importantly, using OrderedDicts is much, much easier for Python integration. This is especially true given that ScriptModule today also uses OrderedDict. Since C++ frontend modules and ScriptModules will soon too share as many implementation details as possible, it is overall the best move to ditch the custom cursor datastructure and pervasively use OrderedDict everywhere.
For this I did:
1. Changed the C++ frontend module interface to more closely match the Python one by providing `parameters()`, `named_parameters()` and other methods Python provides. This is very important for the following diff which binds these into Python for inter-op with Python modules.
2. In lieu of the `Cursor::apply()` method I added `nn::Module::apply`. This again is one more unifying step between Python and C++, since Python modules have an apply function too.
3. Deleted all uses of Cursor.
4. Tidied and beefed up the `OrderedDict` class. In particular, I made `OrderedDict::Item` store an `std::pair` under the hood, because that is trivial to bind into Python and saved me a lot of headaches. `key` and `value` become methods instead of fields, which they should have been from the very start anyway because it allows exactly these kinds of changes, as per usual good software engineering principle of encapsulation.
5. Added many tests for the OrderedDict use in `nn::Module`.
ebetica ezyang
Pull Request resolved: https://github.com/pytorch/pytorch/pull/13427
Differential Revision: D12894092
Pulled By: goldsborough
fbshipit-source-id: 715770c95a9643753a1db26d7f9da9a78619a15d
2018-11-07 18:53:07 +00:00
|
|
|
ASSERT_FALSE(buffer->allclose(buffers2[buffer.key()]));
|
2018-05-15 01:24:58 +00:00
|
|
|
}
|
2018-09-22 04:12:37 +00:00
|
|
|
}
|
2018-05-17 21:10:15 +00:00
|
|
|
|
2019-07-26 19:42:04 +00:00
|
|
|
TEST_F(ModuleTest, CloneCreatesDistinctParameters) {
|
|
|
|
|
auto module = std::make_shared<TestDistinctParametersModule>();
|
|
|
|
|
torch::NoGradGuard no_grad;
|
|
|
|
|
auto module2 = module->clone();
|
|
|
|
|
testDistinctParameters(module, module2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(ModuleTest, CloneCreatesDistinctParametersExplicitDevice_CUDA) {
|
|
|
|
|
auto module = std::make_shared<TestDistinctParametersModule>();
|
|
|
|
|
torch::NoGradGuard no_grad;
|
|
|
|
|
torch::Device device(torch::kCUDA, 0);
|
|
|
|
|
module->to(device);
|
|
|
|
|
auto module2 = module->clone(device);
|
|
|
|
|
testDistinctParameters(module, module2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(ModuleTest, CloneCreatesDistinctParametersExplicitDevice_MultiCUDA) {
|
|
|
|
|
auto module = std::make_shared<TestDistinctParametersModule>();
|
|
|
|
|
torch::NoGradGuard no_grad;
|
|
|
|
|
torch::Device d0(torch::kCUDA, 0);
|
|
|
|
|
torch::Device d1(torch::kCUDA, 1);
|
|
|
|
|
module->to(d0);
|
|
|
|
|
auto module2 = module->clone(d1);
|
|
|
|
|
|
|
|
|
|
for (auto& param : module->parameters()) {
|
|
|
|
|
ASSERT_EQ(param.device(), d0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (auto& param : module2->parameters()) {
|
|
|
|
|
ASSERT_EQ(param.device(), d1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// need to move the module back to d0 as allclose expects two tensors on
|
|
|
|
|
// the same device.
|
|
|
|
|
module2->to(d0);
|
|
|
|
|
testDistinctParameters(module, module2);
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-22 04:12:37 +00:00
|
|
|
TEST_F(ModuleTest, ClonePreservesExternalReferences) {
|
Make PyTorch code-base clang-tidy compliant (#56892)
Summary:
This is an automatic change generated by the following script:
```
#!/usr/bin/env python3
from subprocess import check_output, check_call
import os
def get_compiled_files_list():
import json
with open("build/compile_commands.json") as f:
data = json.load(f)
files = [os.path.relpath(node['file']) for node in data]
for idx, fname in enumerate(files):
if fname.startswith('build/') and fname.endswith('.DEFAULT.cpp'):
files[idx] = fname[len('build/'):-len('.DEFAULT.cpp')]
return files
def run_clang_tidy(fname):
check_call(["python3", "tools/clang_tidy.py", "-c", "build", "-x", fname,"-s"])
changes = check_output(["git", "ls-files", "-m"])
if len(changes) == 0:
return
check_call(["git", "commit","--all", "-m", f"NOLINT stubs for {fname}"])
def main():
git_files = check_output(["git", "ls-files"]).decode("ascii").split("\n")
compiled_files = get_compiled_files_list()
for idx, fname in enumerate(git_files):
if fname not in compiled_files:
continue
if fname.startswith("caffe2/contrib/aten/"):
continue
print(f"[{idx}/{len(git_files)}] Processing {fname}")
run_clang_tidy(fname)
if __name__ == "__main__":
main()
```
Pull Request resolved: https://github.com/pytorch/pytorch/pull/56892
Reviewed By: H-Huang
Differential Revision: D27991944
Pulled By: malfet
fbshipit-source-id: 5415e1eb2c1b34319a4f03024bfaa087007d7179
2021-04-28 21:09:06 +00:00
|
|
|
// NOLINTNEXTLINE(bugprone-exception-escape)
|
2018-09-22 04:12:37 +00:00
|
|
|
struct TestModule : public Cloneable<TestModule> {
|
|
|
|
|
TestModule() {
|
Make PyTorch code-base clang-tidy compliant (#56892)
Summary:
This is an automatic change generated by the following script:
```
#!/usr/bin/env python3
from subprocess import check_output, check_call
import os
def get_compiled_files_list():
import json
with open("build/compile_commands.json") as f:
data = json.load(f)
files = [os.path.relpath(node['file']) for node in data]
for idx, fname in enumerate(files):
if fname.startswith('build/') and fname.endswith('.DEFAULT.cpp'):
files[idx] = fname[len('build/'):-len('.DEFAULT.cpp')]
return files
def run_clang_tidy(fname):
check_call(["python3", "tools/clang_tidy.py", "-c", "build", "-x", fname,"-s"])
changes = check_output(["git", "ls-files", "-m"])
if len(changes) == 0:
return
check_call(["git", "commit","--all", "-m", f"NOLINT stubs for {fname}"])
def main():
git_files = check_output(["git", "ls-files"]).decode("ascii").split("\n")
compiled_files = get_compiled_files_list()
for idx, fname in enumerate(git_files):
if fname not in compiled_files:
continue
if fname.startswith("caffe2/contrib/aten/"):
continue
print(f"[{idx}/{len(git_files)}] Processing {fname}")
run_clang_tidy(fname)
if __name__ == "__main__":
main()
```
Pull Request resolved: https://github.com/pytorch/pytorch/pull/56892
Reviewed By: H-Huang
Differential Revision: D27991944
Pulled By: malfet
fbshipit-source-id: 5415e1eb2c1b34319a4f03024bfaa087007d7179
2021-04-28 21:09:06 +00:00
|
|
|
// NOLINTNEXTLINE(clang-analyzer-optin.cplusplus.VirtualCall)
|
2018-09-22 04:12:37 +00:00
|
|
|
reset();
|
2018-08-16 04:09:33 +00:00
|
|
|
}
|
2018-09-22 04:12:37 +00:00
|
|
|
void reset() override {
|
|
|
|
|
weight = register_parameter("weight", torch::ones({4, 4}));
|
|
|
|
|
}
|
|
|
|
|
torch::Tensor weight;
|
|
|
|
|
};
|
|
|
|
|
auto module = std::make_shared<TestModule>();
|
|
|
|
|
{
|
|
|
|
|
torch::NoGradGuard no_grad;
|
|
|
|
|
module->weight += 1;
|
2018-05-24 05:11:32 +00:00
|
|
|
}
|
Replace cursors with OrderedDict (#13427)
Summary:
This is a pre-cursor diff to Python <-> C++ frontend integration -- I have a follow-up PR coming for that. This PR changes the C++ frontend module interface to replace the custom "cursor"s I introduced some time ago with `OrderedDict`. I introduced cursors at the time as a convenient way of applying functions and query operations on a modules' parameters, buffers and modules, allowing things like `module.parameters().map(my_func)`. However, I noticed that (1) this functionality is easily implement-able on top of a regular data structure and (2) more importantly, using OrderedDicts is much, much easier for Python integration. This is especially true given that ScriptModule today also uses OrderedDict. Since C++ frontend modules and ScriptModules will soon too share as many implementation details as possible, it is overall the best move to ditch the custom cursor datastructure and pervasively use OrderedDict everywhere.
For this I did:
1. Changed the C++ frontend module interface to more closely match the Python one by providing `parameters()`, `named_parameters()` and other methods Python provides. This is very important for the following diff which binds these into Python for inter-op with Python modules.
2. In lieu of the `Cursor::apply()` method I added `nn::Module::apply`. This again is one more unifying step between Python and C++, since Python modules have an apply function too.
3. Deleted all uses of Cursor.
4. Tidied and beefed up the `OrderedDict` class. In particular, I made `OrderedDict::Item` store an `std::pair` under the hood, because that is trivial to bind into Python and saved me a lot of headaches. `key` and `value` become methods instead of fields, which they should have been from the very start anyway because it allows exactly these kinds of changes, as per usual good software engineering principle of encapsulation.
5. Added many tests for the OrderedDict use in `nn::Module`.
ebetica ezyang
Pull Request resolved: https://github.com/pytorch/pytorch/pull/13427
Differential Revision: D12894092
Pulled By: goldsborough
fbshipit-source-id: 715770c95a9643753a1db26d7f9da9a78619a15d
2018-11-07 18:53:07 +00:00
|
|
|
ASSERT_TRUE(
|
|
|
|
|
pointer_equal(module->weight, module->named_parameters()["weight"]));
|
|
|
|
|
ASSERT_TRUE(module->weight.allclose(module->named_parameters()["weight"]));
|
2018-09-22 04:12:37 +00:00
|
|
|
|
|
|
|
|
auto module2 = std::dynamic_pointer_cast<TestModule>(
|
|
|
|
|
std::shared_ptr<Module>(module->clone()));
|
|
|
|
|
ASSERT_FALSE(pointer_equal(module2->weight, module->weight));
|
Replace cursors with OrderedDict (#13427)
Summary:
This is a pre-cursor diff to Python <-> C++ frontend integration -- I have a follow-up PR coming for that. This PR changes the C++ frontend module interface to replace the custom "cursor"s I introduced some time ago with `OrderedDict`. I introduced cursors at the time as a convenient way of applying functions and query operations on a modules' parameters, buffers and modules, allowing things like `module.parameters().map(my_func)`. However, I noticed that (1) this functionality is easily implement-able on top of a regular data structure and (2) more importantly, using OrderedDicts is much, much easier for Python integration. This is especially true given that ScriptModule today also uses OrderedDict. Since C++ frontend modules and ScriptModules will soon too share as many implementation details as possible, it is overall the best move to ditch the custom cursor datastructure and pervasively use OrderedDict everywhere.
For this I did:
1. Changed the C++ frontend module interface to more closely match the Python one by providing `parameters()`, `named_parameters()` and other methods Python provides. This is very important for the following diff which binds these into Python for inter-op with Python modules.
2. In lieu of the `Cursor::apply()` method I added `nn::Module::apply`. This again is one more unifying step between Python and C++, since Python modules have an apply function too.
3. Deleted all uses of Cursor.
4. Tidied and beefed up the `OrderedDict` class. In particular, I made `OrderedDict::Item` store an `std::pair` under the hood, because that is trivial to bind into Python and saved me a lot of headaches. `key` and `value` become methods instead of fields, which they should have been from the very start anyway because it allows exactly these kinds of changes, as per usual good software engineering principle of encapsulation.
5. Added many tests for the OrderedDict use in `nn::Module`.
ebetica ezyang
Pull Request resolved: https://github.com/pytorch/pytorch/pull/13427
Differential Revision: D12894092
Pulled By: goldsborough
fbshipit-source-id: 715770c95a9643753a1db26d7f9da9a78619a15d
2018-11-07 18:53:07 +00:00
|
|
|
ASSERT_TRUE(
|
|
|
|
|
pointer_equal(module2->weight, module2->named_parameters()["weight"]));
|
|
|
|
|
ASSERT_TRUE(module2->weight.allclose(module2->named_parameters()["weight"]));
|
2018-09-22 04:12:37 +00:00
|
|
|
ASSERT_TRUE(module2->weight.allclose(module->weight));
|
Replace cursors with OrderedDict (#13427)
Summary:
This is a pre-cursor diff to Python <-> C++ frontend integration -- I have a follow-up PR coming for that. This PR changes the C++ frontend module interface to replace the custom "cursor"s I introduced some time ago with `OrderedDict`. I introduced cursors at the time as a convenient way of applying functions and query operations on a modules' parameters, buffers and modules, allowing things like `module.parameters().map(my_func)`. However, I noticed that (1) this functionality is easily implement-able on top of a regular data structure and (2) more importantly, using OrderedDicts is much, much easier for Python integration. This is especially true given that ScriptModule today also uses OrderedDict. Since C++ frontend modules and ScriptModules will soon too share as many implementation details as possible, it is overall the best move to ditch the custom cursor datastructure and pervasively use OrderedDict everywhere.
For this I did:
1. Changed the C++ frontend module interface to more closely match the Python one by providing `parameters()`, `named_parameters()` and other methods Python provides. This is very important for the following diff which binds these into Python for inter-op with Python modules.
2. In lieu of the `Cursor::apply()` method I added `nn::Module::apply`. This again is one more unifying step between Python and C++, since Python modules have an apply function too.
3. Deleted all uses of Cursor.
4. Tidied and beefed up the `OrderedDict` class. In particular, I made `OrderedDict::Item` store an `std::pair` under the hood, because that is trivial to bind into Python and saved me a lot of headaches. `key` and `value` become methods instead of fields, which they should have been from the very start anyway because it allows exactly these kinds of changes, as per usual good software engineering principle of encapsulation.
5. Added many tests for the OrderedDict use in `nn::Module`.
ebetica ezyang
Pull Request resolved: https://github.com/pytorch/pytorch/pull/13427
Differential Revision: D12894092
Pulled By: goldsborough
fbshipit-source-id: 715770c95a9643753a1db26d7f9da9a78619a15d
2018-11-07 18:53:07 +00:00
|
|
|
ASSERT_FALSE(
|
|
|
|
|
pointer_equal(module2->weight, module->named_parameters()["weight"]));
|
2018-09-22 04:12:37 +00:00
|
|
|
}
|
2018-05-17 21:10:15 +00:00
|
|
|
|
2018-09-22 04:12:37 +00:00
|
|
|
TEST_F(ModuleTest, CloneCopiesTheValuesOfVariablesOfSubmodules) {
|
Make PyTorch code-base clang-tidy compliant (#56892)
Summary:
This is an automatic change generated by the following script:
```
#!/usr/bin/env python3
from subprocess import check_output, check_call
import os
def get_compiled_files_list():
import json
with open("build/compile_commands.json") as f:
data = json.load(f)
files = [os.path.relpath(node['file']) for node in data]
for idx, fname in enumerate(files):
if fname.startswith('build/') and fname.endswith('.DEFAULT.cpp'):
files[idx] = fname[len('build/'):-len('.DEFAULT.cpp')]
return files
def run_clang_tidy(fname):
check_call(["python3", "tools/clang_tidy.py", "-c", "build", "-x", fname,"-s"])
changes = check_output(["git", "ls-files", "-m"])
if len(changes) == 0:
return
check_call(["git", "commit","--all", "-m", f"NOLINT stubs for {fname}"])
def main():
git_files = check_output(["git", "ls-files"]).decode("ascii").split("\n")
compiled_files = get_compiled_files_list()
for idx, fname in enumerate(git_files):
if fname not in compiled_files:
continue
if fname.startswith("caffe2/contrib/aten/"):
continue
print(f"[{idx}/{len(git_files)}] Processing {fname}")
run_clang_tidy(fname)
if __name__ == "__main__":
main()
```
Pull Request resolved: https://github.com/pytorch/pytorch/pull/56892
Reviewed By: H-Huang
Differential Revision: D27991944
Pulled By: malfet
fbshipit-source-id: 5415e1eb2c1b34319a4f03024bfaa087007d7179
2021-04-28 21:09:06 +00:00
|
|
|
// NOLINTNEXTLINE(bugprone-exception-escape)
|
2018-09-22 04:12:37 +00:00
|
|
|
struct TestModule : public Cloneable<TestModule> {
|
|
|
|
|
TestModule() {
|
Make PyTorch code-base clang-tidy compliant (#56892)
Summary:
This is an automatic change generated by the following script:
```
#!/usr/bin/env python3
from subprocess import check_output, check_call
import os
def get_compiled_files_list():
import json
with open("build/compile_commands.json") as f:
data = json.load(f)
files = [os.path.relpath(node['file']) for node in data]
for idx, fname in enumerate(files):
if fname.startswith('build/') and fname.endswith('.DEFAULT.cpp'):
files[idx] = fname[len('build/'):-len('.DEFAULT.cpp')]
return files
def run_clang_tidy(fname):
check_call(["python3", "tools/clang_tidy.py", "-c", "build", "-x", fname,"-s"])
changes = check_output(["git", "ls-files", "-m"])
if len(changes) == 0:
return
check_call(["git", "commit","--all", "-m", f"NOLINT stubs for {fname}"])
def main():
git_files = check_output(["git", "ls-files"]).decode("ascii").split("\n")
compiled_files = get_compiled_files_list()
for idx, fname in enumerate(git_files):
if fname not in compiled_files:
continue
if fname.startswith("caffe2/contrib/aten/"):
continue
print(f"[{idx}/{len(git_files)}] Processing {fname}")
run_clang_tidy(fname)
if __name__ == "__main__":
main()
```
Pull Request resolved: https://github.com/pytorch/pytorch/pull/56892
Reviewed By: H-Huang
Differential Revision: D27991944
Pulled By: malfet
fbshipit-source-id: 5415e1eb2c1b34319a4f03024bfaa087007d7179
2021-04-28 21:09:06 +00:00
|
|
|
// NOLINTNEXTLINE(clang-analyzer-optin.cplusplus.VirtualCall)
|
2018-09-22 04:12:37 +00:00
|
|
|
reset();
|
|
|
|
|
}
|
|
|
|
|
void reset() override {
|
|
|
|
|
weight = register_parameter("weight", torch::ones({4, 4}));
|
2018-08-16 04:09:33 +00:00
|
|
|
}
|
2018-05-24 05:11:32 +00:00
|
|
|
|
2018-09-22 04:12:37 +00:00
|
|
|
torch::Tensor weight;
|
|
|
|
|
int value = 0;
|
|
|
|
|
};
|
Make PyTorch code-base clang-tidy compliant (#56892)
Summary:
This is an automatic change generated by the following script:
```
#!/usr/bin/env python3
from subprocess import check_output, check_call
import os
def get_compiled_files_list():
import json
with open("build/compile_commands.json") as f:
data = json.load(f)
files = [os.path.relpath(node['file']) for node in data]
for idx, fname in enumerate(files):
if fname.startswith('build/') and fname.endswith('.DEFAULT.cpp'):
files[idx] = fname[len('build/'):-len('.DEFAULT.cpp')]
return files
def run_clang_tidy(fname):
check_call(["python3", "tools/clang_tidy.py", "-c", "build", "-x", fname,"-s"])
changes = check_output(["git", "ls-files", "-m"])
if len(changes) == 0:
return
check_call(["git", "commit","--all", "-m", f"NOLINT stubs for {fname}"])
def main():
git_files = check_output(["git", "ls-files"]).decode("ascii").split("\n")
compiled_files = get_compiled_files_list()
for idx, fname in enumerate(git_files):
if fname not in compiled_files:
continue
if fname.startswith("caffe2/contrib/aten/"):
continue
print(f"[{idx}/{len(git_files)}] Processing {fname}")
run_clang_tidy(fname)
if __name__ == "__main__":
main()
```
Pull Request resolved: https://github.com/pytorch/pytorch/pull/56892
Reviewed By: H-Huang
Differential Revision: D27991944
Pulled By: malfet
fbshipit-source-id: 5415e1eb2c1b34319a4f03024bfaa087007d7179
2021-04-28 21:09:06 +00:00
|
|
|
// NOLINTNEXTLINE(bugprone-exception-escape)
|
2018-09-22 04:12:37 +00:00
|
|
|
struct NestedModule : public Cloneable<NestedModule> {
|
|
|
|
|
NestedModule() {
|
Make PyTorch code-base clang-tidy compliant (#56892)
Summary:
This is an automatic change generated by the following script:
```
#!/usr/bin/env python3
from subprocess import check_output, check_call
import os
def get_compiled_files_list():
import json
with open("build/compile_commands.json") as f:
data = json.load(f)
files = [os.path.relpath(node['file']) for node in data]
for idx, fname in enumerate(files):
if fname.startswith('build/') and fname.endswith('.DEFAULT.cpp'):
files[idx] = fname[len('build/'):-len('.DEFAULT.cpp')]
return files
def run_clang_tidy(fname):
check_call(["python3", "tools/clang_tidy.py", "-c", "build", "-x", fname,"-s"])
changes = check_output(["git", "ls-files", "-m"])
if len(changes) == 0:
return
check_call(["git", "commit","--all", "-m", f"NOLINT stubs for {fname}"])
def main():
git_files = check_output(["git", "ls-files"]).decode("ascii").split("\n")
compiled_files = get_compiled_files_list()
for idx, fname in enumerate(git_files):
if fname not in compiled_files:
continue
if fname.startswith("caffe2/contrib/aten/"):
continue
print(f"[{idx}/{len(git_files)}] Processing {fname}")
run_clang_tidy(fname)
if __name__ == "__main__":
main()
```
Pull Request resolved: https://github.com/pytorch/pytorch/pull/56892
Reviewed By: H-Huang
Differential Revision: D27991944
Pulled By: malfet
fbshipit-source-id: 5415e1eb2c1b34319a4f03024bfaa087007d7179
2021-04-28 21:09:06 +00:00
|
|
|
// NOLINTNEXTLINE(clang-analyzer-optin.cplusplus.VirtualCall)
|
2018-09-22 04:12:37 +00:00
|
|
|
reset();
|
|
|
|
|
}
|
|
|
|
|
void reset() override {
|
|
|
|
|
module = register_module("module", std::make_shared<TestModule>());
|
|
|
|
|
}
|
|
|
|
|
std::shared_ptr<TestModule> module;
|
|
|
|
|
};
|
2018-05-17 21:10:15 +00:00
|
|
|
|
2018-09-22 04:12:37 +00:00
|
|
|
auto a = std::make_shared<NestedModule>();
|
|
|
|
|
{
|
|
|
|
|
torch::NoGradGuard no_grad;
|
|
|
|
|
a->module->weight += 1;
|
|
|
|
|
a->module->value = 123;
|
2018-05-22 00:59:21 +00:00
|
|
|
}
|
2018-09-22 04:12:37 +00:00
|
|
|
|
|
|
|
|
auto b = std::dynamic_pointer_cast<NestedModule>(a->clone());
|
|
|
|
|
|
|
|
|
|
ASSERT_FALSE(pointer_equal(b->module->weight, a->module->weight));
|
Replace cursors with OrderedDict (#13427)
Summary:
This is a pre-cursor diff to Python <-> C++ frontend integration -- I have a follow-up PR coming for that. This PR changes the C++ frontend module interface to replace the custom "cursor"s I introduced some time ago with `OrderedDict`. I introduced cursors at the time as a convenient way of applying functions and query operations on a modules' parameters, buffers and modules, allowing things like `module.parameters().map(my_func)`. However, I noticed that (1) this functionality is easily implement-able on top of a regular data structure and (2) more importantly, using OrderedDicts is much, much easier for Python integration. This is especially true given that ScriptModule today also uses OrderedDict. Since C++ frontend modules and ScriptModules will soon too share as many implementation details as possible, it is overall the best move to ditch the custom cursor datastructure and pervasively use OrderedDict everywhere.
For this I did:
1. Changed the C++ frontend module interface to more closely match the Python one by providing `parameters()`, `named_parameters()` and other methods Python provides. This is very important for the following diff which binds these into Python for inter-op with Python modules.
2. In lieu of the `Cursor::apply()` method I added `nn::Module::apply`. This again is one more unifying step between Python and C++, since Python modules have an apply function too.
3. Deleted all uses of Cursor.
4. Tidied and beefed up the `OrderedDict` class. In particular, I made `OrderedDict::Item` store an `std::pair` under the hood, because that is trivial to bind into Python and saved me a lot of headaches. `key` and `value` become methods instead of fields, which they should have been from the very start anyway because it allows exactly these kinds of changes, as per usual good software engineering principle of encapsulation.
5. Added many tests for the OrderedDict use in `nn::Module`.
ebetica ezyang
Pull Request resolved: https://github.com/pytorch/pytorch/pull/13427
Differential Revision: D12894092
Pulled By: goldsborough
fbshipit-source-id: 715770c95a9643753a1db26d7f9da9a78619a15d
2018-11-07 18:53:07 +00:00
|
|
|
ASSERT_TRUE(pointer_equal(
|
|
|
|
|
b->module->weight, b->module->named_parameters()["weight"]));
|
2018-09-22 04:12:37 +00:00
|
|
|
ASSERT_TRUE(
|
Replace cursors with OrderedDict (#13427)
Summary:
This is a pre-cursor diff to Python <-> C++ frontend integration -- I have a follow-up PR coming for that. This PR changes the C++ frontend module interface to replace the custom "cursor"s I introduced some time ago with `OrderedDict`. I introduced cursors at the time as a convenient way of applying functions and query operations on a modules' parameters, buffers and modules, allowing things like `module.parameters().map(my_func)`. However, I noticed that (1) this functionality is easily implement-able on top of a regular data structure and (2) more importantly, using OrderedDicts is much, much easier for Python integration. This is especially true given that ScriptModule today also uses OrderedDict. Since C++ frontend modules and ScriptModules will soon too share as many implementation details as possible, it is overall the best move to ditch the custom cursor datastructure and pervasively use OrderedDict everywhere.
For this I did:
1. Changed the C++ frontend module interface to more closely match the Python one by providing `parameters()`, `named_parameters()` and other methods Python provides. This is very important for the following diff which binds these into Python for inter-op with Python modules.
2. In lieu of the `Cursor::apply()` method I added `nn::Module::apply`. This again is one more unifying step between Python and C++, since Python modules have an apply function too.
3. Deleted all uses of Cursor.
4. Tidied and beefed up the `OrderedDict` class. In particular, I made `OrderedDict::Item` store an `std::pair` under the hood, because that is trivial to bind into Python and saved me a lot of headaches. `key` and `value` become methods instead of fields, which they should have been from the very start anyway because it allows exactly these kinds of changes, as per usual good software engineering principle of encapsulation.
5. Added many tests for the OrderedDict use in `nn::Module`.
ebetica ezyang
Pull Request resolved: https://github.com/pytorch/pytorch/pull/13427
Differential Revision: D12894092
Pulled By: goldsborough
fbshipit-source-id: 715770c95a9643753a1db26d7f9da9a78619a15d
2018-11-07 18:53:07 +00:00
|
|
|
b->module->named_parameters()["weight"].allclose(a->module->weight));
|
2018-09-22 04:12:37 +00:00
|
|
|
ASSERT_TRUE(b->module->weight.allclose(a->module->weight));
|
|
|
|
|
ASSERT_EQ(b->module->value, a->module->value);
|
2018-05-22 00:59:21 +00:00
|
|
|
}
|
|
|
|
|
|
2018-09-22 04:12:37 +00:00
|
|
|
TEST_F(ModuleTest, CloneToDevicePreservesTheDeviceOfParameters_CUDA) {
|
Make PyTorch code-base clang-tidy compliant (#56892)
Summary:
This is an automatic change generated by the following script:
```
#!/usr/bin/env python3
from subprocess import check_output, check_call
import os
def get_compiled_files_list():
import json
with open("build/compile_commands.json") as f:
data = json.load(f)
files = [os.path.relpath(node['file']) for node in data]
for idx, fname in enumerate(files):
if fname.startswith('build/') and fname.endswith('.DEFAULT.cpp'):
files[idx] = fname[len('build/'):-len('.DEFAULT.cpp')]
return files
def run_clang_tidy(fname):
check_call(["python3", "tools/clang_tidy.py", "-c", "build", "-x", fname,"-s"])
changes = check_output(["git", "ls-files", "-m"])
if len(changes) == 0:
return
check_call(["git", "commit","--all", "-m", f"NOLINT stubs for {fname}"])
def main():
git_files = check_output(["git", "ls-files"]).decode("ascii").split("\n")
compiled_files = get_compiled_files_list()
for idx, fname in enumerate(git_files):
if fname not in compiled_files:
continue
if fname.startswith("caffe2/contrib/aten/"):
continue
print(f"[{idx}/{len(git_files)}] Processing {fname}")
run_clang_tidy(fname)
if __name__ == "__main__":
main()
```
Pull Request resolved: https://github.com/pytorch/pytorch/pull/56892
Reviewed By: H-Huang
Differential Revision: D27991944
Pulled By: malfet
fbshipit-source-id: 5415e1eb2c1b34319a4f03024bfaa087007d7179
2021-04-28 21:09:06 +00:00
|
|
|
// NOLINTNEXTLINE(bugprone-exception-escape)
|
2018-07-23 21:49:18 +00:00
|
|
|
struct TestModule : public Cloneable<TestModule> {
|
|
|
|
|
TestModule() {
|
Make PyTorch code-base clang-tidy compliant (#56892)
Summary:
This is an automatic change generated by the following script:
```
#!/usr/bin/env python3
from subprocess import check_output, check_call
import os
def get_compiled_files_list():
import json
with open("build/compile_commands.json") as f:
data = json.load(f)
files = [os.path.relpath(node['file']) for node in data]
for idx, fname in enumerate(files):
if fname.startswith('build/') and fname.endswith('.DEFAULT.cpp'):
files[idx] = fname[len('build/'):-len('.DEFAULT.cpp')]
return files
def run_clang_tidy(fname):
check_call(["python3", "tools/clang_tidy.py", "-c", "build", "-x", fname,"-s"])
changes = check_output(["git", "ls-files", "-m"])
if len(changes) == 0:
return
check_call(["git", "commit","--all", "-m", f"NOLINT stubs for {fname}"])
def main():
git_files = check_output(["git", "ls-files"]).decode("ascii").split("\n")
compiled_files = get_compiled_files_list()
for idx, fname in enumerate(git_files):
if fname not in compiled_files:
continue
if fname.startswith("caffe2/contrib/aten/"):
continue
print(f"[{idx}/{len(git_files)}] Processing {fname}")
run_clang_tidy(fname)
if __name__ == "__main__":
main()
```
Pull Request resolved: https://github.com/pytorch/pytorch/pull/56892
Reviewed By: H-Huang
Differential Revision: D27991944
Pulled By: malfet
fbshipit-source-id: 5415e1eb2c1b34319a4f03024bfaa087007d7179
2021-04-28 21:09:06 +00:00
|
|
|
// NOLINTNEXTLINE(clang-analyzer-optin.cplusplus.VirtualCall)
|
2018-07-23 21:49:18 +00:00
|
|
|
reset();
|
|
|
|
|
}
|
|
|
|
|
void reset() override {
|
|
|
|
|
l1 = register_module("l1", Linear(10, 3));
|
|
|
|
|
l2 = register_module("l2", Linear(3, 5));
|
|
|
|
|
l3 = register_module("l3", Linear(5, 100));
|
|
|
|
|
buffer = register_buffer("buf", torch::ones({2, 2}));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Linear l1{nullptr}, l2{nullptr}, l3{nullptr};
|
|
|
|
|
torch::Tensor buffer;
|
|
|
|
|
};
|
|
|
|
|
|
2018-09-22 04:12:37 +00:00
|
|
|
TestModule m;
|
|
|
|
|
torch::Device device(torch::kCUDA, 0);
|
2018-07-23 21:49:18 +00:00
|
|
|
|
2018-09-22 04:12:37 +00:00
|
|
|
m.to(device);
|
2018-07-23 21:49:18 +00:00
|
|
|
|
2018-09-22 04:12:37 +00:00
|
|
|
auto clone = m.clone();
|
|
|
|
|
for (const auto& parameter : clone->parameters()) {
|
Replace cursors with OrderedDict (#13427)
Summary:
This is a pre-cursor diff to Python <-> C++ frontend integration -- I have a follow-up PR coming for that. This PR changes the C++ frontend module interface to replace the custom "cursor"s I introduced some time ago with `OrderedDict`. I introduced cursors at the time as a convenient way of applying functions and query operations on a modules' parameters, buffers and modules, allowing things like `module.parameters().map(my_func)`. However, I noticed that (1) this functionality is easily implement-able on top of a regular data structure and (2) more importantly, using OrderedDicts is much, much easier for Python integration. This is especially true given that ScriptModule today also uses OrderedDict. Since C++ frontend modules and ScriptModules will soon too share as many implementation details as possible, it is overall the best move to ditch the custom cursor datastructure and pervasively use OrderedDict everywhere.
For this I did:
1. Changed the C++ frontend module interface to more closely match the Python one by providing `parameters()`, `named_parameters()` and other methods Python provides. This is very important for the following diff which binds these into Python for inter-op with Python modules.
2. In lieu of the `Cursor::apply()` method I added `nn::Module::apply`. This again is one more unifying step between Python and C++, since Python modules have an apply function too.
3. Deleted all uses of Cursor.
4. Tidied and beefed up the `OrderedDict` class. In particular, I made `OrderedDict::Item` store an `std::pair` under the hood, because that is trivial to bind into Python and saved me a lot of headaches. `key` and `value` become methods instead of fields, which they should have been from the very start anyway because it allows exactly these kinds of changes, as per usual good software engineering principle of encapsulation.
5. Added many tests for the OrderedDict use in `nn::Module`.
ebetica ezyang
Pull Request resolved: https://github.com/pytorch/pytorch/pull/13427
Differential Revision: D12894092
Pulled By: goldsborough
fbshipit-source-id: 715770c95a9643753a1db26d7f9da9a78619a15d
2018-11-07 18:53:07 +00:00
|
|
|
ASSERT_EQ(parameter.device().type(), device.type());
|
|
|
|
|
ASSERT_EQ(parameter.device().index(), device.index());
|
2018-07-23 21:49:18 +00:00
|
|
|
}
|
2018-09-22 04:12:37 +00:00
|
|
|
for (const auto& buffer : clone->buffers()) {
|
Replace cursors with OrderedDict (#13427)
Summary:
This is a pre-cursor diff to Python <-> C++ frontend integration -- I have a follow-up PR coming for that. This PR changes the C++ frontend module interface to replace the custom "cursor"s I introduced some time ago with `OrderedDict`. I introduced cursors at the time as a convenient way of applying functions and query operations on a modules' parameters, buffers and modules, allowing things like `module.parameters().map(my_func)`. However, I noticed that (1) this functionality is easily implement-able on top of a regular data structure and (2) more importantly, using OrderedDicts is much, much easier for Python integration. This is especially true given that ScriptModule today also uses OrderedDict. Since C++ frontend modules and ScriptModules will soon too share as many implementation details as possible, it is overall the best move to ditch the custom cursor datastructure and pervasively use OrderedDict everywhere.
For this I did:
1. Changed the C++ frontend module interface to more closely match the Python one by providing `parameters()`, `named_parameters()` and other methods Python provides. This is very important for the following diff which binds these into Python for inter-op with Python modules.
2. In lieu of the `Cursor::apply()` method I added `nn::Module::apply`. This again is one more unifying step between Python and C++, since Python modules have an apply function too.
3. Deleted all uses of Cursor.
4. Tidied and beefed up the `OrderedDict` class. In particular, I made `OrderedDict::Item` store an `std::pair` under the hood, because that is trivial to bind into Python and saved me a lot of headaches. `key` and `value` become methods instead of fields, which they should have been from the very start anyway because it allows exactly these kinds of changes, as per usual good software engineering principle of encapsulation.
5. Added many tests for the OrderedDict use in `nn::Module`.
ebetica ezyang
Pull Request resolved: https://github.com/pytorch/pytorch/pull/13427
Differential Revision: D12894092
Pulled By: goldsborough
fbshipit-source-id: 715770c95a9643753a1db26d7f9da9a78619a15d
2018-11-07 18:53:07 +00:00
|
|
|
ASSERT_EQ(buffer.device().type(), device.type());
|
|
|
|
|
ASSERT_EQ(buffer.device().index(), device.index());
|
2018-07-23 21:49:18 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-14 00:30:05 +00:00
|
|
|
TEST_F(
|
|
|
|
|
ModuleTest,
|
|
|
|
|
CloningToAParticularDevicePlacesAllParametersThere_MultiCUDA) {
|
Make PyTorch code-base clang-tidy compliant (#56892)
Summary:
This is an automatic change generated by the following script:
```
#!/usr/bin/env python3
from subprocess import check_output, check_call
import os
def get_compiled_files_list():
import json
with open("build/compile_commands.json") as f:
data = json.load(f)
files = [os.path.relpath(node['file']) for node in data]
for idx, fname in enumerate(files):
if fname.startswith('build/') and fname.endswith('.DEFAULT.cpp'):
files[idx] = fname[len('build/'):-len('.DEFAULT.cpp')]
return files
def run_clang_tidy(fname):
check_call(["python3", "tools/clang_tidy.py", "-c", "build", "-x", fname,"-s"])
changes = check_output(["git", "ls-files", "-m"])
if len(changes) == 0:
return
check_call(["git", "commit","--all", "-m", f"NOLINT stubs for {fname}"])
def main():
git_files = check_output(["git", "ls-files"]).decode("ascii").split("\n")
compiled_files = get_compiled_files_list()
for idx, fname in enumerate(git_files):
if fname not in compiled_files:
continue
if fname.startswith("caffe2/contrib/aten/"):
continue
print(f"[{idx}/{len(git_files)}] Processing {fname}")
run_clang_tidy(fname)
if __name__ == "__main__":
main()
```
Pull Request resolved: https://github.com/pytorch/pytorch/pull/56892
Reviewed By: H-Huang
Differential Revision: D27991944
Pulled By: malfet
fbshipit-source-id: 5415e1eb2c1b34319a4f03024bfaa087007d7179
2021-04-28 21:09:06 +00:00
|
|
|
// NOLINTNEXTLINE(bugprone-exception-escape)
|
2018-09-22 04:12:37 +00:00
|
|
|
struct TestModule : public Cloneable<TestModule> {
|
2018-05-22 00:59:21 +00:00
|
|
|
TestModule() {
|
Make PyTorch code-base clang-tidy compliant (#56892)
Summary:
This is an automatic change generated by the following script:
```
#!/usr/bin/env python3
from subprocess import check_output, check_call
import os
def get_compiled_files_list():
import json
with open("build/compile_commands.json") as f:
data = json.load(f)
files = [os.path.relpath(node['file']) for node in data]
for idx, fname in enumerate(files):
if fname.startswith('build/') and fname.endswith('.DEFAULT.cpp'):
files[idx] = fname[len('build/'):-len('.DEFAULT.cpp')]
return files
def run_clang_tidy(fname):
check_call(["python3", "tools/clang_tidy.py", "-c", "build", "-x", fname,"-s"])
changes = check_output(["git", "ls-files", "-m"])
if len(changes) == 0:
return
check_call(["git", "commit","--all", "-m", f"NOLINT stubs for {fname}"])
def main():
git_files = check_output(["git", "ls-files"]).decode("ascii").split("\n")
compiled_files = get_compiled_files_list()
for idx, fname in enumerate(git_files):
if fname not in compiled_files:
continue
if fname.startswith("caffe2/contrib/aten/"):
continue
print(f"[{idx}/{len(git_files)}] Processing {fname}")
run_clang_tidy(fname)
if __name__ == "__main__":
main()
```
Pull Request resolved: https://github.com/pytorch/pytorch/pull/56892
Reviewed By: H-Huang
Differential Revision: D27991944
Pulled By: malfet
fbshipit-source-id: 5415e1eb2c1b34319a4f03024bfaa087007d7179
2021-04-28 21:09:06 +00:00
|
|
|
// NOLINTNEXTLINE(clang-analyzer-optin.cplusplus.VirtualCall)
|
2018-09-22 04:12:37 +00:00
|
|
|
reset();
|
|
|
|
|
}
|
|
|
|
|
void reset() override {
|
|
|
|
|
l1 = register_module("l1", Linear(10, 3));
|
|
|
|
|
l2 = register_module("l2", Linear(3, 5));
|
|
|
|
|
l3 = register_module("l3", Linear(5, 100));
|
|
|
|
|
buffer = register_buffer("buf", torch::ones({2, 2}));
|
2018-05-22 00:59:21 +00:00
|
|
|
}
|
|
|
|
|
|
2018-09-22 04:12:37 +00:00
|
|
|
Linear l1{nullptr}, l2{nullptr}, l3{nullptr};
|
|
|
|
|
torch::Tensor buffer;
|
2018-05-22 00:59:21 +00:00
|
|
|
};
|
|
|
|
|
|
2018-09-22 04:12:37 +00:00
|
|
|
TestModule m;
|
|
|
|
|
torch::Device device(torch::kCUDA, 1);
|
|
|
|
|
// everything is on CPU here
|
|
|
|
|
auto clone = m.clone(device);
|
|
|
|
|
for (const auto& parameter : clone->parameters()) {
|
Replace cursors with OrderedDict (#13427)
Summary:
This is a pre-cursor diff to Python <-> C++ frontend integration -- I have a follow-up PR coming for that. This PR changes the C++ frontend module interface to replace the custom "cursor"s I introduced some time ago with `OrderedDict`. I introduced cursors at the time as a convenient way of applying functions and query operations on a modules' parameters, buffers and modules, allowing things like `module.parameters().map(my_func)`. However, I noticed that (1) this functionality is easily implement-able on top of a regular data structure and (2) more importantly, using OrderedDicts is much, much easier for Python integration. This is especially true given that ScriptModule today also uses OrderedDict. Since C++ frontend modules and ScriptModules will soon too share as many implementation details as possible, it is overall the best move to ditch the custom cursor datastructure and pervasively use OrderedDict everywhere.
For this I did:
1. Changed the C++ frontend module interface to more closely match the Python one by providing `parameters()`, `named_parameters()` and other methods Python provides. This is very important for the following diff which binds these into Python for inter-op with Python modules.
2. In lieu of the `Cursor::apply()` method I added `nn::Module::apply`. This again is one more unifying step between Python and C++, since Python modules have an apply function too.
3. Deleted all uses of Cursor.
4. Tidied and beefed up the `OrderedDict` class. In particular, I made `OrderedDict::Item` store an `std::pair` under the hood, because that is trivial to bind into Python and saved me a lot of headaches. `key` and `value` become methods instead of fields, which they should have been from the very start anyway because it allows exactly these kinds of changes, as per usual good software engineering principle of encapsulation.
5. Added many tests for the OrderedDict use in `nn::Module`.
ebetica ezyang
Pull Request resolved: https://github.com/pytorch/pytorch/pull/13427
Differential Revision: D12894092
Pulled By: goldsborough
fbshipit-source-id: 715770c95a9643753a1db26d7f9da9a78619a15d
2018-11-07 18:53:07 +00:00
|
|
|
ASSERT_EQ(parameter.device().type(), device.type());
|
|
|
|
|
ASSERT_EQ(parameter.device().index(), device.index());
|
2018-05-22 00:59:21 +00:00
|
|
|
}
|
2018-09-22 04:12:37 +00:00
|
|
|
for (const auto& buffer : clone->buffers()) {
|
Replace cursors with OrderedDict (#13427)
Summary:
This is a pre-cursor diff to Python <-> C++ frontend integration -- I have a follow-up PR coming for that. This PR changes the C++ frontend module interface to replace the custom "cursor"s I introduced some time ago with `OrderedDict`. I introduced cursors at the time as a convenient way of applying functions and query operations on a modules' parameters, buffers and modules, allowing things like `module.parameters().map(my_func)`. However, I noticed that (1) this functionality is easily implement-able on top of a regular data structure and (2) more importantly, using OrderedDicts is much, much easier for Python integration. This is especially true given that ScriptModule today also uses OrderedDict. Since C++ frontend modules and ScriptModules will soon too share as many implementation details as possible, it is overall the best move to ditch the custom cursor datastructure and pervasively use OrderedDict everywhere.
For this I did:
1. Changed the C++ frontend module interface to more closely match the Python one by providing `parameters()`, `named_parameters()` and other methods Python provides. This is very important for the following diff which binds these into Python for inter-op with Python modules.
2. In lieu of the `Cursor::apply()` method I added `nn::Module::apply`. This again is one more unifying step between Python and C++, since Python modules have an apply function too.
3. Deleted all uses of Cursor.
4. Tidied and beefed up the `OrderedDict` class. In particular, I made `OrderedDict::Item` store an `std::pair` under the hood, because that is trivial to bind into Python and saved me a lot of headaches. `key` and `value` become methods instead of fields, which they should have been from the very start anyway because it allows exactly these kinds of changes, as per usual good software engineering principle of encapsulation.
5. Added many tests for the OrderedDict use in `nn::Module`.
ebetica ezyang
Pull Request resolved: https://github.com/pytorch/pytorch/pull/13427
Differential Revision: D12894092
Pulled By: goldsborough
fbshipit-source-id: 715770c95a9643753a1db26d7f9da9a78619a15d
2018-11-07 18:53:07 +00:00
|
|
|
ASSERT_EQ(buffer.device().type(), device.type());
|
|
|
|
|
ASSERT_EQ(buffer.device().index(), device.index());
|
2018-05-17 21:10:15 +00:00
|
|
|
}
|
2018-05-10 07:49:29 +00:00
|
|
|
}
|
2018-06-26 04:11:49 +00:00
|
|
|
|
2018-09-22 04:12:37 +00:00
|
|
|
struct ParameterTestModule : Module {
|
|
|
|
|
ParameterTestModule() {
|
|
|
|
|
a = register_parameter("a", torch::zeros({2, 2}));
|
|
|
|
|
b = register_parameter("b", torch::ones({2, 2}));
|
|
|
|
|
c = register_parameter("c", torch::ones({2, 2}) * 2);
|
|
|
|
|
}
|
2018-06-26 04:11:49 +00:00
|
|
|
|
2018-09-22 04:12:37 +00:00
|
|
|
torch::Tensor a, b, c;
|
|
|
|
|
};
|
2018-06-26 04:11:49 +00:00
|
|
|
|
2018-09-22 04:12:37 +00:00
|
|
|
TEST_F(ModuleTest, HasCorrectNumberOfParameters) {
|
|
|
|
|
ParameterTestModule module;
|
|
|
|
|
ASSERT_EQ(module.parameters().size(), 3);
|
Replace cursors with OrderedDict (#13427)
Summary:
This is a pre-cursor diff to Python <-> C++ frontend integration -- I have a follow-up PR coming for that. This PR changes the C++ frontend module interface to replace the custom "cursor"s I introduced some time ago with `OrderedDict`. I introduced cursors at the time as a convenient way of applying functions and query operations on a modules' parameters, buffers and modules, allowing things like `module.parameters().map(my_func)`. However, I noticed that (1) this functionality is easily implement-able on top of a regular data structure and (2) more importantly, using OrderedDicts is much, much easier for Python integration. This is especially true given that ScriptModule today also uses OrderedDict. Since C++ frontend modules and ScriptModules will soon too share as many implementation details as possible, it is overall the best move to ditch the custom cursor datastructure and pervasively use OrderedDict everywhere.
For this I did:
1. Changed the C++ frontend module interface to more closely match the Python one by providing `parameters()`, `named_parameters()` and other methods Python provides. This is very important for the following diff which binds these into Python for inter-op with Python modules.
2. In lieu of the `Cursor::apply()` method I added `nn::Module::apply`. This again is one more unifying step between Python and C++, since Python modules have an apply function too.
3. Deleted all uses of Cursor.
4. Tidied and beefed up the `OrderedDict` class. In particular, I made `OrderedDict::Item` store an `std::pair` under the hood, because that is trivial to bind into Python and saved me a lot of headaches. `key` and `value` become methods instead of fields, which they should have been from the very start anyway because it allows exactly these kinds of changes, as per usual good software engineering principle of encapsulation.
5. Added many tests for the OrderedDict use in `nn::Module`.
ebetica ezyang
Pull Request resolved: https://github.com/pytorch/pytorch/pull/13427
Differential Revision: D12894092
Pulled By: goldsborough
fbshipit-source-id: 715770c95a9643753a1db26d7f9da9a78619a15d
2018-11-07 18:53:07 +00:00
|
|
|
ASSERT_EQ(module.named_parameters().size(), 3);
|
2018-09-22 04:12:37 +00:00
|
|
|
}
|
2018-06-26 04:11:49 +00:00
|
|
|
|
2018-09-22 04:12:37 +00:00
|
|
|
TEST_F(ModuleTest, ContainsParametersWithTheCorrectName) {
|
|
|
|
|
ParameterTestModule module;
|
Replace cursors with OrderedDict (#13427)
Summary:
This is a pre-cursor diff to Python <-> C++ frontend integration -- I have a follow-up PR coming for that. This PR changes the C++ frontend module interface to replace the custom "cursor"s I introduced some time ago with `OrderedDict`. I introduced cursors at the time as a convenient way of applying functions and query operations on a modules' parameters, buffers and modules, allowing things like `module.parameters().map(my_func)`. However, I noticed that (1) this functionality is easily implement-able on top of a regular data structure and (2) more importantly, using OrderedDicts is much, much easier for Python integration. This is especially true given that ScriptModule today also uses OrderedDict. Since C++ frontend modules and ScriptModules will soon too share as many implementation details as possible, it is overall the best move to ditch the custom cursor datastructure and pervasively use OrderedDict everywhere.
For this I did:
1. Changed the C++ frontend module interface to more closely match the Python one by providing `parameters()`, `named_parameters()` and other methods Python provides. This is very important for the following diff which binds these into Python for inter-op with Python modules.
2. In lieu of the `Cursor::apply()` method I added `nn::Module::apply`. This again is one more unifying step between Python and C++, since Python modules have an apply function too.
3. Deleted all uses of Cursor.
4. Tidied and beefed up the `OrderedDict` class. In particular, I made `OrderedDict::Item` store an `std::pair` under the hood, because that is trivial to bind into Python and saved me a lot of headaches. `key` and `value` become methods instead of fields, which they should have been from the very start anyway because it allows exactly these kinds of changes, as per usual good software engineering principle of encapsulation.
5. Added many tests for the OrderedDict use in `nn::Module`.
ebetica ezyang
Pull Request resolved: https://github.com/pytorch/pytorch/pull/13427
Differential Revision: D12894092
Pulled By: goldsborough
fbshipit-source-id: 715770c95a9643753a1db26d7f9da9a78619a15d
2018-11-07 18:53:07 +00:00
|
|
|
auto parameters = module.named_parameters();
|
2018-09-22 04:12:37 +00:00
|
|
|
ASSERT_TRUE(parameters.contains("a"));
|
|
|
|
|
ASSERT_TRUE(parameters.contains("b"));
|
|
|
|
|
ASSERT_TRUE(parameters.contains("c"));
|
|
|
|
|
}
|
2018-06-26 04:11:49 +00:00
|
|
|
|
2018-09-22 04:12:37 +00:00
|
|
|
struct BufferTestModule : Module {
|
|
|
|
|
BufferTestModule() {
|
|
|
|
|
a = register_buffer("a", torch::zeros({2, 2}));
|
|
|
|
|
b = register_buffer("b", torch::ones({2, 2}));
|
|
|
|
|
c = register_buffer("c", torch::ones({2, 2}) * 2);
|
2018-06-26 04:11:49 +00:00
|
|
|
}
|
2018-09-22 04:12:37 +00:00
|
|
|
|
|
|
|
|
torch::Tensor a, b, c;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
TEST_F(ModuleTest, HasCorrectNumberOfBuffers) {
|
|
|
|
|
BufferTestModule module;
|
|
|
|
|
ASSERT_EQ(module.buffers().size(), 3);
|
Replace cursors with OrderedDict (#13427)
Summary:
This is a pre-cursor diff to Python <-> C++ frontend integration -- I have a follow-up PR coming for that. This PR changes the C++ frontend module interface to replace the custom "cursor"s I introduced some time ago with `OrderedDict`. I introduced cursors at the time as a convenient way of applying functions and query operations on a modules' parameters, buffers and modules, allowing things like `module.parameters().map(my_func)`. However, I noticed that (1) this functionality is easily implement-able on top of a regular data structure and (2) more importantly, using OrderedDicts is much, much easier for Python integration. This is especially true given that ScriptModule today also uses OrderedDict. Since C++ frontend modules and ScriptModules will soon too share as many implementation details as possible, it is overall the best move to ditch the custom cursor datastructure and pervasively use OrderedDict everywhere.
For this I did:
1. Changed the C++ frontend module interface to more closely match the Python one by providing `parameters()`, `named_parameters()` and other methods Python provides. This is very important for the following diff which binds these into Python for inter-op with Python modules.
2. In lieu of the `Cursor::apply()` method I added `nn::Module::apply`. This again is one more unifying step between Python and C++, since Python modules have an apply function too.
3. Deleted all uses of Cursor.
4. Tidied and beefed up the `OrderedDict` class. In particular, I made `OrderedDict::Item` store an `std::pair` under the hood, because that is trivial to bind into Python and saved me a lot of headaches. `key` and `value` become methods instead of fields, which they should have been from the very start anyway because it allows exactly these kinds of changes, as per usual good software engineering principle of encapsulation.
5. Added many tests for the OrderedDict use in `nn::Module`.
ebetica ezyang
Pull Request resolved: https://github.com/pytorch/pytorch/pull/13427
Differential Revision: D12894092
Pulled By: goldsborough
fbshipit-source-id: 715770c95a9643753a1db26d7f9da9a78619a15d
2018-11-07 18:53:07 +00:00
|
|
|
ASSERT_EQ(module.named_buffers().size(), 3);
|
2018-06-26 04:11:49 +00:00
|
|
|
}
|
2018-07-19 22:55:51 +00:00
|
|
|
|
2018-09-22 04:12:37 +00:00
|
|
|
TEST_F(ModuleTest, ContainsBuffersWithTheCorrectName) {
|
|
|
|
|
BufferTestModule module;
|
Replace cursors with OrderedDict (#13427)
Summary:
This is a pre-cursor diff to Python <-> C++ frontend integration -- I have a follow-up PR coming for that. This PR changes the C++ frontend module interface to replace the custom "cursor"s I introduced some time ago with `OrderedDict`. I introduced cursors at the time as a convenient way of applying functions and query operations on a modules' parameters, buffers and modules, allowing things like `module.parameters().map(my_func)`. However, I noticed that (1) this functionality is easily implement-able on top of a regular data structure and (2) more importantly, using OrderedDicts is much, much easier for Python integration. This is especially true given that ScriptModule today also uses OrderedDict. Since C++ frontend modules and ScriptModules will soon too share as many implementation details as possible, it is overall the best move to ditch the custom cursor datastructure and pervasively use OrderedDict everywhere.
For this I did:
1. Changed the C++ frontend module interface to more closely match the Python one by providing `parameters()`, `named_parameters()` and other methods Python provides. This is very important for the following diff which binds these into Python for inter-op with Python modules.
2. In lieu of the `Cursor::apply()` method I added `nn::Module::apply`. This again is one more unifying step between Python and C++, since Python modules have an apply function too.
3. Deleted all uses of Cursor.
4. Tidied and beefed up the `OrderedDict` class. In particular, I made `OrderedDict::Item` store an `std::pair` under the hood, because that is trivial to bind into Python and saved me a lot of headaches. `key` and `value` become methods instead of fields, which they should have been from the very start anyway because it allows exactly these kinds of changes, as per usual good software engineering principle of encapsulation.
5. Added many tests for the OrderedDict use in `nn::Module`.
ebetica ezyang
Pull Request resolved: https://github.com/pytorch/pytorch/pull/13427
Differential Revision: D12894092
Pulled By: goldsborough
fbshipit-source-id: 715770c95a9643753a1db26d7f9da9a78619a15d
2018-11-07 18:53:07 +00:00
|
|
|
auto buffers = module.named_buffers();
|
2018-09-22 04:12:37 +00:00
|
|
|
ASSERT_TRUE(buffers.contains("a"));
|
|
|
|
|
ASSERT_TRUE(buffers.contains("b"));
|
|
|
|
|
ASSERT_TRUE(buffers.contains("c"));
|
|
|
|
|
}
|
2018-07-19 22:55:51 +00:00
|
|
|
|
2018-09-22 04:12:37 +00:00
|
|
|
struct AImpl : torch::nn::Module {
|
|
|
|
|
AImpl() : x_(123) {}
|
|
|
|
|
AImpl(int x) : x_(x) {}
|
|
|
|
|
int x_;
|
|
|
|
|
};
|
|
|
|
|
TORCH_MODULE(A);
|
|
|
|
|
|
|
|
|
|
TEST_F(
|
|
|
|
|
ModuleTest,
|
|
|
|
|
DefaultConstructorOfModuleHolderCallsDefaultConstructorOfImpl) {
|
|
|
|
|
A a;
|
|
|
|
|
ASSERT_TRUE(a);
|
|
|
|
|
ASSERT_FALSE(a.is_empty());
|
|
|
|
|
ASSERT_EQ(a->x_, 123);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(
|
|
|
|
|
ModuleTest,
|
|
|
|
|
ValueConstructorOfModuleHolderCallsCorrectConstructorInImpl) {
|
|
|
|
|
A a(5);
|
|
|
|
|
ASSERT_TRUE(a);
|
|
|
|
|
ASSERT_FALSE(a.is_empty());
|
|
|
|
|
ASSERT_EQ(a->x_, 5);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(ModuleTest, NullptrConstructorLeavesTheModuleHolderInEmptyState) {
|
|
|
|
|
A a = nullptr;
|
|
|
|
|
ASSERT_FALSE(a);
|
|
|
|
|
ASSERT_TRUE(a.is_empty());
|
|
|
|
|
ASSERT_THROWS_WITH(a->x_, "Accessing empty ModuleHolder");
|
2018-07-19 22:55:51 +00:00
|
|
|
}
|
Replace cursors with OrderedDict (#13427)
Summary:
This is a pre-cursor diff to Python <-> C++ frontend integration -- I have a follow-up PR coming for that. This PR changes the C++ frontend module interface to replace the custom "cursor"s I introduced some time ago with `OrderedDict`. I introduced cursors at the time as a convenient way of applying functions and query operations on a modules' parameters, buffers and modules, allowing things like `module.parameters().map(my_func)`. However, I noticed that (1) this functionality is easily implement-able on top of a regular data structure and (2) more importantly, using OrderedDicts is much, much easier for Python integration. This is especially true given that ScriptModule today also uses OrderedDict. Since C++ frontend modules and ScriptModules will soon too share as many implementation details as possible, it is overall the best move to ditch the custom cursor datastructure and pervasively use OrderedDict everywhere.
For this I did:
1. Changed the C++ frontend module interface to more closely match the Python one by providing `parameters()`, `named_parameters()` and other methods Python provides. This is very important for the following diff which binds these into Python for inter-op with Python modules.
2. In lieu of the `Cursor::apply()` method I added `nn::Module::apply`. This again is one more unifying step between Python and C++, since Python modules have an apply function too.
3. Deleted all uses of Cursor.
4. Tidied and beefed up the `OrderedDict` class. In particular, I made `OrderedDict::Item` store an `std::pair` under the hood, because that is trivial to bind into Python and saved me a lot of headaches. `key` and `value` become methods instead of fields, which they should have been from the very start anyway because it allows exactly these kinds of changes, as per usual good software engineering principle of encapsulation.
5. Added many tests for the OrderedDict use in `nn::Module`.
ebetica ezyang
Pull Request resolved: https://github.com/pytorch/pytorch/pull/13427
Differential Revision: D12894092
Pulled By: goldsborough
fbshipit-source-id: 715770c95a9643753a1db26d7f9da9a78619a15d
2018-11-07 18:53:07 +00:00
|
|
|
|
|
|
|
|
struct TestModule : public torch::nn::Module {
|
|
|
|
|
TestModule(int64_t size) {
|
|
|
|
|
p1 = register_parameter("p1", torch::randn({size}));
|
|
|
|
|
p2 = register_parameter("p2", torch::randn({size}));
|
|
|
|
|
b1 = register_buffer("b1", torch::randn({size}));
|
|
|
|
|
b2 = register_buffer("b2", torch::randn({size}));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
torch::Tensor forward(torch::Tensor input) {
|
|
|
|
|
return input;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
torch::Tensor p1, p2, b1, b2;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
TEST_F(ModuleTest, ModulesReturnsExpectedSubmodulesForFlatModel) {
|
|
|
|
|
torch::nn::Sequential model(TestModule(1), TestModule(2), TestModule(3));
|
|
|
|
|
std::vector<std::shared_ptr<torch::nn::Module>> modules = model->modules();
|
|
|
|
|
std::vector<std::shared_ptr<torch::nn::Module>> expected = {
|
|
|
|
|
model.ptr(), model[0], model[1], model[2]};
|
|
|
|
|
ASSERT_EQ(modules.size(), expected.size());
|
2021-12-09 17:44:04 +00:00
|
|
|
for (const auto i : c10::irange(expected.size())) {
|
Replace cursors with OrderedDict (#13427)
Summary:
This is a pre-cursor diff to Python <-> C++ frontend integration -- I have a follow-up PR coming for that. This PR changes the C++ frontend module interface to replace the custom "cursor"s I introduced some time ago with `OrderedDict`. I introduced cursors at the time as a convenient way of applying functions and query operations on a modules' parameters, buffers and modules, allowing things like `module.parameters().map(my_func)`. However, I noticed that (1) this functionality is easily implement-able on top of a regular data structure and (2) more importantly, using OrderedDicts is much, much easier for Python integration. This is especially true given that ScriptModule today also uses OrderedDict. Since C++ frontend modules and ScriptModules will soon too share as many implementation details as possible, it is overall the best move to ditch the custom cursor datastructure and pervasively use OrderedDict everywhere.
For this I did:
1. Changed the C++ frontend module interface to more closely match the Python one by providing `parameters()`, `named_parameters()` and other methods Python provides. This is very important for the following diff which binds these into Python for inter-op with Python modules.
2. In lieu of the `Cursor::apply()` method I added `nn::Module::apply`. This again is one more unifying step between Python and C++, since Python modules have an apply function too.
3. Deleted all uses of Cursor.
4. Tidied and beefed up the `OrderedDict` class. In particular, I made `OrderedDict::Item` store an `std::pair` under the hood, because that is trivial to bind into Python and saved me a lot of headaches. `key` and `value` become methods instead of fields, which they should have been from the very start anyway because it allows exactly these kinds of changes, as per usual good software engineering principle of encapsulation.
5. Added many tests for the OrderedDict use in `nn::Module`.
ebetica ezyang
Pull Request resolved: https://github.com/pytorch/pytorch/pull/13427
Differential Revision: D12894092
Pulled By: goldsborough
fbshipit-source-id: 715770c95a9643753a1db26d7f9da9a78619a15d
2018-11-07 18:53:07 +00:00
|
|
|
// Assert pointer equality.
|
|
|
|
|
ASSERT_EQ(modules[i].get(), expected[i].get());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(ModuleTest, ModulesExcludesSelfWhenIncludeSelfSetToFalse) {
|
|
|
|
|
torch::nn::Sequential model(TestModule(1), TestModule(2), TestModule(3));
|
|
|
|
|
std::vector<std::shared_ptr<torch::nn::Module>> modules =
|
|
|
|
|
model->modules(/*include_self=*/false);
|
|
|
|
|
std::vector<std::shared_ptr<torch::nn::Module>> expected = {
|
|
|
|
|
model[0], model[1], model[2]};
|
|
|
|
|
ASSERT_EQ(modules.size(), expected.size());
|
2021-12-09 17:44:04 +00:00
|
|
|
for (const auto i : c10::irange(expected.size())) {
|
Replace cursors with OrderedDict (#13427)
Summary:
This is a pre-cursor diff to Python <-> C++ frontend integration -- I have a follow-up PR coming for that. This PR changes the C++ frontend module interface to replace the custom "cursor"s I introduced some time ago with `OrderedDict`. I introduced cursors at the time as a convenient way of applying functions and query operations on a modules' parameters, buffers and modules, allowing things like `module.parameters().map(my_func)`. However, I noticed that (1) this functionality is easily implement-able on top of a regular data structure and (2) more importantly, using OrderedDicts is much, much easier for Python integration. This is especially true given that ScriptModule today also uses OrderedDict. Since C++ frontend modules and ScriptModules will soon too share as many implementation details as possible, it is overall the best move to ditch the custom cursor datastructure and pervasively use OrderedDict everywhere.
For this I did:
1. Changed the C++ frontend module interface to more closely match the Python one by providing `parameters()`, `named_parameters()` and other methods Python provides. This is very important for the following diff which binds these into Python for inter-op with Python modules.
2. In lieu of the `Cursor::apply()` method I added `nn::Module::apply`. This again is one more unifying step between Python and C++, since Python modules have an apply function too.
3. Deleted all uses of Cursor.
4. Tidied and beefed up the `OrderedDict` class. In particular, I made `OrderedDict::Item` store an `std::pair` under the hood, because that is trivial to bind into Python and saved me a lot of headaches. `key` and `value` become methods instead of fields, which they should have been from the very start anyway because it allows exactly these kinds of changes, as per usual good software engineering principle of encapsulation.
5. Added many tests for the OrderedDict use in `nn::Module`.
ebetica ezyang
Pull Request resolved: https://github.com/pytorch/pytorch/pull/13427
Differential Revision: D12894092
Pulled By: goldsborough
fbshipit-source-id: 715770c95a9643753a1db26d7f9da9a78619a15d
2018-11-07 18:53:07 +00:00
|
|
|
// Assert pointer equality.
|
|
|
|
|
ASSERT_EQ(modules[i].get(), expected[i].get());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(ModuleTest, NamedModulesReturnsExpectedNamedSubmodulesForFlatModel) {
|
|
|
|
|
torch::nn::Sequential model(TestModule(1), TestModule(2), TestModule(3));
|
|
|
|
|
torch::OrderedDict<std::string, std::shared_ptr<torch::nn::Module>> modules =
|
|
|
|
|
model->named_modules();
|
|
|
|
|
std::vector<std::shared_ptr<torch::nn::Module>> expected = {
|
|
|
|
|
model.ptr(), model[0], model[1], model[2]};
|
|
|
|
|
ASSERT_EQ(modules.size(), expected.size());
|
2021-12-09 17:44:04 +00:00
|
|
|
for (const auto i : c10::irange(expected.size())) {
|
Replace cursors with OrderedDict (#13427)
Summary:
This is a pre-cursor diff to Python <-> C++ frontend integration -- I have a follow-up PR coming for that. This PR changes the C++ frontend module interface to replace the custom "cursor"s I introduced some time ago with `OrderedDict`. I introduced cursors at the time as a convenient way of applying functions and query operations on a modules' parameters, buffers and modules, allowing things like `module.parameters().map(my_func)`. However, I noticed that (1) this functionality is easily implement-able on top of a regular data structure and (2) more importantly, using OrderedDicts is much, much easier for Python integration. This is especially true given that ScriptModule today also uses OrderedDict. Since C++ frontend modules and ScriptModules will soon too share as many implementation details as possible, it is overall the best move to ditch the custom cursor datastructure and pervasively use OrderedDict everywhere.
For this I did:
1. Changed the C++ frontend module interface to more closely match the Python one by providing `parameters()`, `named_parameters()` and other methods Python provides. This is very important for the following diff which binds these into Python for inter-op with Python modules.
2. In lieu of the `Cursor::apply()` method I added `nn::Module::apply`. This again is one more unifying step between Python and C++, since Python modules have an apply function too.
3. Deleted all uses of Cursor.
4. Tidied and beefed up the `OrderedDict` class. In particular, I made `OrderedDict::Item` store an `std::pair` under the hood, because that is trivial to bind into Python and saved me a lot of headaches. `key` and `value` become methods instead of fields, which they should have been from the very start anyway because it allows exactly these kinds of changes, as per usual good software engineering principle of encapsulation.
5. Added many tests for the OrderedDict use in `nn::Module`.
ebetica ezyang
Pull Request resolved: https://github.com/pytorch/pytorch/pull/13427
Differential Revision: D12894092
Pulled By: goldsborough
fbshipit-source-id: 715770c95a9643753a1db26d7f9da9a78619a15d
2018-11-07 18:53:07 +00:00
|
|
|
// Assert pointer equality.
|
|
|
|
|
ASSERT_EQ(modules[i].key(), i ? std::to_string(i - 1) : std::string());
|
|
|
|
|
ASSERT_EQ(modules[i].value().get(), expected[i].get());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(ModuleTest, NamedModulesExcludesSelfWhenIncludeSelfSetToFalse) {
|
|
|
|
|
torch::nn::Sequential model(TestModule(1), TestModule(2), TestModule(3));
|
|
|
|
|
torch::OrderedDict<std::string, std::shared_ptr<torch::nn::Module>> modules =
|
|
|
|
|
model->named_modules(
|
|
|
|
|
/*name_prefix=*/std::string(), /*include_self=*/false);
|
|
|
|
|
std::vector<std::shared_ptr<torch::nn::Module>> expected = {
|
|
|
|
|
model[0], model[1], model[2]};
|
|
|
|
|
ASSERT_EQ(modules.size(), expected.size());
|
2021-12-09 17:44:04 +00:00
|
|
|
for (const auto i : c10::irange(expected.size())) {
|
Replace cursors with OrderedDict (#13427)
Summary:
This is a pre-cursor diff to Python <-> C++ frontend integration -- I have a follow-up PR coming for that. This PR changes the C++ frontend module interface to replace the custom "cursor"s I introduced some time ago with `OrderedDict`. I introduced cursors at the time as a convenient way of applying functions and query operations on a modules' parameters, buffers and modules, allowing things like `module.parameters().map(my_func)`. However, I noticed that (1) this functionality is easily implement-able on top of a regular data structure and (2) more importantly, using OrderedDicts is much, much easier for Python integration. This is especially true given that ScriptModule today also uses OrderedDict. Since C++ frontend modules and ScriptModules will soon too share as many implementation details as possible, it is overall the best move to ditch the custom cursor datastructure and pervasively use OrderedDict everywhere.
For this I did:
1. Changed the C++ frontend module interface to more closely match the Python one by providing `parameters()`, `named_parameters()` and other methods Python provides. This is very important for the following diff which binds these into Python for inter-op with Python modules.
2. In lieu of the `Cursor::apply()` method I added `nn::Module::apply`. This again is one more unifying step between Python and C++, since Python modules have an apply function too.
3. Deleted all uses of Cursor.
4. Tidied and beefed up the `OrderedDict` class. In particular, I made `OrderedDict::Item` store an `std::pair` under the hood, because that is trivial to bind into Python and saved me a lot of headaches. `key` and `value` become methods instead of fields, which they should have been from the very start anyway because it allows exactly these kinds of changes, as per usual good software engineering principle of encapsulation.
5. Added many tests for the OrderedDict use in `nn::Module`.
ebetica ezyang
Pull Request resolved: https://github.com/pytorch/pytorch/pull/13427
Differential Revision: D12894092
Pulled By: goldsborough
fbshipit-source-id: 715770c95a9643753a1db26d7f9da9a78619a15d
2018-11-07 18:53:07 +00:00
|
|
|
// Assert pointer equality.
|
|
|
|
|
ASSERT_EQ(modules[i].key(), std::to_string(i));
|
|
|
|
|
ASSERT_EQ(modules[i].value().get(), expected[i].get());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(ModuleTest, ChildrenReturnsExpectedSubmodulesForFlatModel) {
|
|
|
|
|
torch::nn::Sequential model(TestModule(1), TestModule(2), TestModule(3));
|
|
|
|
|
std::vector<std::shared_ptr<torch::nn::Module>> modules = model->children();
|
|
|
|
|
std::vector<std::shared_ptr<torch::nn::Module>> expected = {
|
|
|
|
|
model[0], model[1], model[2]};
|
|
|
|
|
ASSERT_EQ(modules.size(), expected.size());
|
2021-12-09 17:44:04 +00:00
|
|
|
for (const auto i : c10::irange(expected.size())) {
|
Replace cursors with OrderedDict (#13427)
Summary:
This is a pre-cursor diff to Python <-> C++ frontend integration -- I have a follow-up PR coming for that. This PR changes the C++ frontend module interface to replace the custom "cursor"s I introduced some time ago with `OrderedDict`. I introduced cursors at the time as a convenient way of applying functions and query operations on a modules' parameters, buffers and modules, allowing things like `module.parameters().map(my_func)`. However, I noticed that (1) this functionality is easily implement-able on top of a regular data structure and (2) more importantly, using OrderedDicts is much, much easier for Python integration. This is especially true given that ScriptModule today also uses OrderedDict. Since C++ frontend modules and ScriptModules will soon too share as many implementation details as possible, it is overall the best move to ditch the custom cursor datastructure and pervasively use OrderedDict everywhere.
For this I did:
1. Changed the C++ frontend module interface to more closely match the Python one by providing `parameters()`, `named_parameters()` and other methods Python provides. This is very important for the following diff which binds these into Python for inter-op with Python modules.
2. In lieu of the `Cursor::apply()` method I added `nn::Module::apply`. This again is one more unifying step between Python and C++, since Python modules have an apply function too.
3. Deleted all uses of Cursor.
4. Tidied and beefed up the `OrderedDict` class. In particular, I made `OrderedDict::Item` store an `std::pair` under the hood, because that is trivial to bind into Python and saved me a lot of headaches. `key` and `value` become methods instead of fields, which they should have been from the very start anyway because it allows exactly these kinds of changes, as per usual good software engineering principle of encapsulation.
5. Added many tests for the OrderedDict use in `nn::Module`.
ebetica ezyang
Pull Request resolved: https://github.com/pytorch/pytorch/pull/13427
Differential Revision: D12894092
Pulled By: goldsborough
fbshipit-source-id: 715770c95a9643753a1db26d7f9da9a78619a15d
2018-11-07 18:53:07 +00:00
|
|
|
// Assert pointer equality.
|
|
|
|
|
ASSERT_EQ(modules[i].get(), expected[i].get());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// For this flat model, this should be true.
|
|
|
|
|
ASSERT_EQ(modules, model->modules(/*include_self=*/false));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(ModuleTest, NamedChildrenReturnsExpectedNamedSubmodulesForFlatModel) {
|
|
|
|
|
torch::nn::Sequential model(TestModule(1), TestModule(2), TestModule(3));
|
|
|
|
|
torch::OrderedDict<std::string, std::shared_ptr<torch::nn::Module>> modules =
|
|
|
|
|
model->named_children();
|
|
|
|
|
std::vector<std::shared_ptr<torch::nn::Module>> expected = {
|
|
|
|
|
model[0], model[1], model[2]};
|
|
|
|
|
ASSERT_EQ(modules.size(), expected.size());
|
2021-12-09 17:44:04 +00:00
|
|
|
for (const auto i : c10::irange(expected.size())) {
|
Replace cursors with OrderedDict (#13427)
Summary:
This is a pre-cursor diff to Python <-> C++ frontend integration -- I have a follow-up PR coming for that. This PR changes the C++ frontend module interface to replace the custom "cursor"s I introduced some time ago with `OrderedDict`. I introduced cursors at the time as a convenient way of applying functions and query operations on a modules' parameters, buffers and modules, allowing things like `module.parameters().map(my_func)`. However, I noticed that (1) this functionality is easily implement-able on top of a regular data structure and (2) more importantly, using OrderedDicts is much, much easier for Python integration. This is especially true given that ScriptModule today also uses OrderedDict. Since C++ frontend modules and ScriptModules will soon too share as many implementation details as possible, it is overall the best move to ditch the custom cursor datastructure and pervasively use OrderedDict everywhere.
For this I did:
1. Changed the C++ frontend module interface to more closely match the Python one by providing `parameters()`, `named_parameters()` and other methods Python provides. This is very important for the following diff which binds these into Python for inter-op with Python modules.
2. In lieu of the `Cursor::apply()` method I added `nn::Module::apply`. This again is one more unifying step between Python and C++, since Python modules have an apply function too.
3. Deleted all uses of Cursor.
4. Tidied and beefed up the `OrderedDict` class. In particular, I made `OrderedDict::Item` store an `std::pair` under the hood, because that is trivial to bind into Python and saved me a lot of headaches. `key` and `value` become methods instead of fields, which they should have been from the very start anyway because it allows exactly these kinds of changes, as per usual good software engineering principle of encapsulation.
5. Added many tests for the OrderedDict use in `nn::Module`.
ebetica ezyang
Pull Request resolved: https://github.com/pytorch/pytorch/pull/13427
Differential Revision: D12894092
Pulled By: goldsborough
fbshipit-source-id: 715770c95a9643753a1db26d7f9da9a78619a15d
2018-11-07 18:53:07 +00:00
|
|
|
// Assert pointer equality.
|
|
|
|
|
ASSERT_EQ(modules[i].key(), std::to_string(i));
|
|
|
|
|
ASSERT_EQ(modules[i].value().get(), expected[i].get());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(ModuleTest, ParametersReturnsExpectedTensorsForFlatModel) {
|
|
|
|
|
TestModule module(1);
|
|
|
|
|
std::vector<torch::Tensor> parameters = module.parameters();
|
|
|
|
|
ASSERT_EQ(parameters.size(), 2);
|
2019-08-22 03:09:37 +00:00
|
|
|
ASSERT_EQ(parameters[0].data_ptr<float>(), module.p1.data_ptr<float>());
|
|
|
|
|
ASSERT_EQ(parameters[1].data_ptr<float>(), module.p2.data_ptr<float>());
|
Replace cursors with OrderedDict (#13427)
Summary:
This is a pre-cursor diff to Python <-> C++ frontend integration -- I have a follow-up PR coming for that. This PR changes the C++ frontend module interface to replace the custom "cursor"s I introduced some time ago with `OrderedDict`. I introduced cursors at the time as a convenient way of applying functions and query operations on a modules' parameters, buffers and modules, allowing things like `module.parameters().map(my_func)`. However, I noticed that (1) this functionality is easily implement-able on top of a regular data structure and (2) more importantly, using OrderedDicts is much, much easier for Python integration. This is especially true given that ScriptModule today also uses OrderedDict. Since C++ frontend modules and ScriptModules will soon too share as many implementation details as possible, it is overall the best move to ditch the custom cursor datastructure and pervasively use OrderedDict everywhere.
For this I did:
1. Changed the C++ frontend module interface to more closely match the Python one by providing `parameters()`, `named_parameters()` and other methods Python provides. This is very important for the following diff which binds these into Python for inter-op with Python modules.
2. In lieu of the `Cursor::apply()` method I added `nn::Module::apply`. This again is one more unifying step between Python and C++, since Python modules have an apply function too.
3. Deleted all uses of Cursor.
4. Tidied and beefed up the `OrderedDict` class. In particular, I made `OrderedDict::Item` store an `std::pair` under the hood, because that is trivial to bind into Python and saved me a lot of headaches. `key` and `value` become methods instead of fields, which they should have been from the very start anyway because it allows exactly these kinds of changes, as per usual good software engineering principle of encapsulation.
5. Added many tests for the OrderedDict use in `nn::Module`.
ebetica ezyang
Pull Request resolved: https://github.com/pytorch/pytorch/pull/13427
Differential Revision: D12894092
Pulled By: goldsborough
fbshipit-source-id: 715770c95a9643753a1db26d7f9da9a78619a15d
2018-11-07 18:53:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(ModuleTest, NamedParametersReturnsExpectedTensorsForFlatModel) {
|
|
|
|
|
TestModule module(1);
|
|
|
|
|
torch::OrderedDict<std::string, torch::Tensor> parameters =
|
|
|
|
|
module.named_parameters();
|
|
|
|
|
ASSERT_EQ(parameters.size(), 2);
|
|
|
|
|
ASSERT_EQ(parameters[0].key(), "p1");
|
2019-08-22 03:09:37 +00:00
|
|
|
ASSERT_EQ(parameters[0]->data_ptr<float>(), module.p1.data_ptr<float>());
|
Replace cursors with OrderedDict (#13427)
Summary:
This is a pre-cursor diff to Python <-> C++ frontend integration -- I have a follow-up PR coming for that. This PR changes the C++ frontend module interface to replace the custom "cursor"s I introduced some time ago with `OrderedDict`. I introduced cursors at the time as a convenient way of applying functions and query operations on a modules' parameters, buffers and modules, allowing things like `module.parameters().map(my_func)`. However, I noticed that (1) this functionality is easily implement-able on top of a regular data structure and (2) more importantly, using OrderedDicts is much, much easier for Python integration. This is especially true given that ScriptModule today also uses OrderedDict. Since C++ frontend modules and ScriptModules will soon too share as many implementation details as possible, it is overall the best move to ditch the custom cursor datastructure and pervasively use OrderedDict everywhere.
For this I did:
1. Changed the C++ frontend module interface to more closely match the Python one by providing `parameters()`, `named_parameters()` and other methods Python provides. This is very important for the following diff which binds these into Python for inter-op with Python modules.
2. In lieu of the `Cursor::apply()` method I added `nn::Module::apply`. This again is one more unifying step between Python and C++, since Python modules have an apply function too.
3. Deleted all uses of Cursor.
4. Tidied and beefed up the `OrderedDict` class. In particular, I made `OrderedDict::Item` store an `std::pair` under the hood, because that is trivial to bind into Python and saved me a lot of headaches. `key` and `value` become methods instead of fields, which they should have been from the very start anyway because it allows exactly these kinds of changes, as per usual good software engineering principle of encapsulation.
5. Added many tests for the OrderedDict use in `nn::Module`.
ebetica ezyang
Pull Request resolved: https://github.com/pytorch/pytorch/pull/13427
Differential Revision: D12894092
Pulled By: goldsborough
fbshipit-source-id: 715770c95a9643753a1db26d7f9da9a78619a15d
2018-11-07 18:53:07 +00:00
|
|
|
ASSERT_EQ(parameters[1].key(), "p2");
|
2019-08-22 03:09:37 +00:00
|
|
|
ASSERT_EQ(parameters[1]->data_ptr<float>(), module.p2.data_ptr<float>());
|
Replace cursors with OrderedDict (#13427)
Summary:
This is a pre-cursor diff to Python <-> C++ frontend integration -- I have a follow-up PR coming for that. This PR changes the C++ frontend module interface to replace the custom "cursor"s I introduced some time ago with `OrderedDict`. I introduced cursors at the time as a convenient way of applying functions and query operations on a modules' parameters, buffers and modules, allowing things like `module.parameters().map(my_func)`. However, I noticed that (1) this functionality is easily implement-able on top of a regular data structure and (2) more importantly, using OrderedDicts is much, much easier for Python integration. This is especially true given that ScriptModule today also uses OrderedDict. Since C++ frontend modules and ScriptModules will soon too share as many implementation details as possible, it is overall the best move to ditch the custom cursor datastructure and pervasively use OrderedDict everywhere.
For this I did:
1. Changed the C++ frontend module interface to more closely match the Python one by providing `parameters()`, `named_parameters()` and other methods Python provides. This is very important for the following diff which binds these into Python for inter-op with Python modules.
2. In lieu of the `Cursor::apply()` method I added `nn::Module::apply`. This again is one more unifying step between Python and C++, since Python modules have an apply function too.
3. Deleted all uses of Cursor.
4. Tidied and beefed up the `OrderedDict` class. In particular, I made `OrderedDict::Item` store an `std::pair` under the hood, because that is trivial to bind into Python and saved me a lot of headaches. `key` and `value` become methods instead of fields, which they should have been from the very start anyway because it allows exactly these kinds of changes, as per usual good software engineering principle of encapsulation.
5. Added many tests for the OrderedDict use in `nn::Module`.
ebetica ezyang
Pull Request resolved: https://github.com/pytorch/pytorch/pull/13427
Differential Revision: D12894092
Pulled By: goldsborough
fbshipit-source-id: 715770c95a9643753a1db26d7f9da9a78619a15d
2018-11-07 18:53:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(ModuleTest, BuffersReturnsExpectedTensorsForFlatModel) {
|
|
|
|
|
TestModule module(1);
|
|
|
|
|
std::vector<torch::Tensor> buffers = module.buffers();
|
|
|
|
|
ASSERT_EQ(buffers.size(), 2);
|
2019-08-22 03:09:37 +00:00
|
|
|
ASSERT_EQ(buffers[0].data_ptr<float>(), module.b1.data_ptr<float>());
|
|
|
|
|
ASSERT_EQ(buffers[1].data_ptr<float>(), module.b2.data_ptr<float>());
|
Replace cursors with OrderedDict (#13427)
Summary:
This is a pre-cursor diff to Python <-> C++ frontend integration -- I have a follow-up PR coming for that. This PR changes the C++ frontend module interface to replace the custom "cursor"s I introduced some time ago with `OrderedDict`. I introduced cursors at the time as a convenient way of applying functions and query operations on a modules' parameters, buffers and modules, allowing things like `module.parameters().map(my_func)`. However, I noticed that (1) this functionality is easily implement-able on top of a regular data structure and (2) more importantly, using OrderedDicts is much, much easier for Python integration. This is especially true given that ScriptModule today also uses OrderedDict. Since C++ frontend modules and ScriptModules will soon too share as many implementation details as possible, it is overall the best move to ditch the custom cursor datastructure and pervasively use OrderedDict everywhere.
For this I did:
1. Changed the C++ frontend module interface to more closely match the Python one by providing `parameters()`, `named_parameters()` and other methods Python provides. This is very important for the following diff which binds these into Python for inter-op with Python modules.
2. In lieu of the `Cursor::apply()` method I added `nn::Module::apply`. This again is one more unifying step between Python and C++, since Python modules have an apply function too.
3. Deleted all uses of Cursor.
4. Tidied and beefed up the `OrderedDict` class. In particular, I made `OrderedDict::Item` store an `std::pair` under the hood, because that is trivial to bind into Python and saved me a lot of headaches. `key` and `value` become methods instead of fields, which they should have been from the very start anyway because it allows exactly these kinds of changes, as per usual good software engineering principle of encapsulation.
5. Added many tests for the OrderedDict use in `nn::Module`.
ebetica ezyang
Pull Request resolved: https://github.com/pytorch/pytorch/pull/13427
Differential Revision: D12894092
Pulled By: goldsborough
fbshipit-source-id: 715770c95a9643753a1db26d7f9da9a78619a15d
2018-11-07 18:53:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(ModuleTest, NamedBuffersReturnsExpectedTensorsForFlatModel) {
|
|
|
|
|
TestModule module(1);
|
|
|
|
|
torch::OrderedDict<std::string, torch::Tensor> buffers =
|
|
|
|
|
module.named_buffers();
|
|
|
|
|
ASSERT_EQ(buffers.size(), 2);
|
|
|
|
|
ASSERT_EQ(buffers[0].key(), "b1");
|
2019-08-22 03:09:37 +00:00
|
|
|
ASSERT_EQ(buffers[0]->data_ptr<float>(), module.b1.data_ptr<float>());
|
Replace cursors with OrderedDict (#13427)
Summary:
This is a pre-cursor diff to Python <-> C++ frontend integration -- I have a follow-up PR coming for that. This PR changes the C++ frontend module interface to replace the custom "cursor"s I introduced some time ago with `OrderedDict`. I introduced cursors at the time as a convenient way of applying functions and query operations on a modules' parameters, buffers and modules, allowing things like `module.parameters().map(my_func)`. However, I noticed that (1) this functionality is easily implement-able on top of a regular data structure and (2) more importantly, using OrderedDicts is much, much easier for Python integration. This is especially true given that ScriptModule today also uses OrderedDict. Since C++ frontend modules and ScriptModules will soon too share as many implementation details as possible, it is overall the best move to ditch the custom cursor datastructure and pervasively use OrderedDict everywhere.
For this I did:
1. Changed the C++ frontend module interface to more closely match the Python one by providing `parameters()`, `named_parameters()` and other methods Python provides. This is very important for the following diff which binds these into Python for inter-op with Python modules.
2. In lieu of the `Cursor::apply()` method I added `nn::Module::apply`. This again is one more unifying step between Python and C++, since Python modules have an apply function too.
3. Deleted all uses of Cursor.
4. Tidied and beefed up the `OrderedDict` class. In particular, I made `OrderedDict::Item` store an `std::pair` under the hood, because that is trivial to bind into Python and saved me a lot of headaches. `key` and `value` become methods instead of fields, which they should have been from the very start anyway because it allows exactly these kinds of changes, as per usual good software engineering principle of encapsulation.
5. Added many tests for the OrderedDict use in `nn::Module`.
ebetica ezyang
Pull Request resolved: https://github.com/pytorch/pytorch/pull/13427
Differential Revision: D12894092
Pulled By: goldsborough
fbshipit-source-id: 715770c95a9643753a1db26d7f9da9a78619a15d
2018-11-07 18:53:07 +00:00
|
|
|
ASSERT_EQ(buffers[1].key(), "b2");
|
2019-08-22 03:09:37 +00:00
|
|
|
ASSERT_EQ(buffers[1]->data_ptr<float>(), module.b2.data_ptr<float>());
|
Replace cursors with OrderedDict (#13427)
Summary:
This is a pre-cursor diff to Python <-> C++ frontend integration -- I have a follow-up PR coming for that. This PR changes the C++ frontend module interface to replace the custom "cursor"s I introduced some time ago with `OrderedDict`. I introduced cursors at the time as a convenient way of applying functions and query operations on a modules' parameters, buffers and modules, allowing things like `module.parameters().map(my_func)`. However, I noticed that (1) this functionality is easily implement-able on top of a regular data structure and (2) more importantly, using OrderedDicts is much, much easier for Python integration. This is especially true given that ScriptModule today also uses OrderedDict. Since C++ frontend modules and ScriptModules will soon too share as many implementation details as possible, it is overall the best move to ditch the custom cursor datastructure and pervasively use OrderedDict everywhere.
For this I did:
1. Changed the C++ frontend module interface to more closely match the Python one by providing `parameters()`, `named_parameters()` and other methods Python provides. This is very important for the following diff which binds these into Python for inter-op with Python modules.
2. In lieu of the `Cursor::apply()` method I added `nn::Module::apply`. This again is one more unifying step between Python and C++, since Python modules have an apply function too.
3. Deleted all uses of Cursor.
4. Tidied and beefed up the `OrderedDict` class. In particular, I made `OrderedDict::Item` store an `std::pair` under the hood, because that is trivial to bind into Python and saved me a lot of headaches. `key` and `value` become methods instead of fields, which they should have been from the very start anyway because it allows exactly these kinds of changes, as per usual good software engineering principle of encapsulation.
5. Added many tests for the OrderedDict use in `nn::Module`.
ebetica ezyang
Pull Request resolved: https://github.com/pytorch/pytorch/pull/13427
Differential Revision: D12894092
Pulled By: goldsborough
fbshipit-source-id: 715770c95a9643753a1db26d7f9da9a78619a15d
2018-11-07 18:53:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct TestContainer : torch::nn::Module {
|
|
|
|
|
TestContainer(int64_t number, std::vector<TestContainer> modules = {})
|
|
|
|
|
: tensor(torch::tensor(number)) {
|
2021-12-09 17:44:04 +00:00
|
|
|
for (const auto i : c10::irange(modules.size())) {
|
Replace cursors with OrderedDict (#13427)
Summary:
This is a pre-cursor diff to Python <-> C++ frontend integration -- I have a follow-up PR coming for that. This PR changes the C++ frontend module interface to replace the custom "cursor"s I introduced some time ago with `OrderedDict`. I introduced cursors at the time as a convenient way of applying functions and query operations on a modules' parameters, buffers and modules, allowing things like `module.parameters().map(my_func)`. However, I noticed that (1) this functionality is easily implement-able on top of a regular data structure and (2) more importantly, using OrderedDicts is much, much easier for Python integration. This is especially true given that ScriptModule today also uses OrderedDict. Since C++ frontend modules and ScriptModules will soon too share as many implementation details as possible, it is overall the best move to ditch the custom cursor datastructure and pervasively use OrderedDict everywhere.
For this I did:
1. Changed the C++ frontend module interface to more closely match the Python one by providing `parameters()`, `named_parameters()` and other methods Python provides. This is very important for the following diff which binds these into Python for inter-op with Python modules.
2. In lieu of the `Cursor::apply()` method I added `nn::Module::apply`. This again is one more unifying step between Python and C++, since Python modules have an apply function too.
3. Deleted all uses of Cursor.
4. Tidied and beefed up the `OrderedDict` class. In particular, I made `OrderedDict::Item` store an `std::pair` under the hood, because that is trivial to bind into Python and saved me a lot of headaches. `key` and `value` become methods instead of fields, which they should have been from the very start anyway because it allows exactly these kinds of changes, as per usual good software engineering principle of encapsulation.
5. Added many tests for the OrderedDict use in `nn::Module`.
ebetica ezyang
Pull Request resolved: https://github.com/pytorch/pytorch/pull/13427
Differential Revision: D12894092
Pulled By: goldsborough
fbshipit-source-id: 715770c95a9643753a1db26d7f9da9a78619a15d
2018-11-07 18:53:07 +00:00
|
|
|
register_module(
|
|
|
|
|
std::to_string(i),
|
|
|
|
|
std::make_shared<TestContainer>(std::move(modules[i])));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
torch::Tensor tensor;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
int64_t get_test_container_item(std::shared_ptr<torch::nn::Module> module) {
|
|
|
|
|
return std::dynamic_pointer_cast<TestContainer>(module)
|
|
|
|
|
->tensor.item<int64_t>();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::shared_ptr<TestContainer> make_deeply_nested_test_container() {
|
|
|
|
|
return std::make_shared<TestContainer>(TestContainer(
|
|
|
|
|
0,
|
|
|
|
|
{TestContainer(1, {TestContainer(2), TestContainer(3)}),
|
|
|
|
|
TestContainer(4),
|
|
|
|
|
TestContainer(
|
|
|
|
|
5,
|
|
|
|
|
{TestContainer(6),
|
|
|
|
|
TestContainer(7, {TestContainer(8), TestContainer(9)})})}));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::vector<std::pair<std::string, int64_t>>
|
|
|
|
|
make_key_value_pairs_for_deeply_nested_container() {
|
|
|
|
|
return {
|
|
|
|
|
{"test_prefix", 0},
|
|
|
|
|
{"test_prefix.0", 1},
|
|
|
|
|
{"test_prefix.0.0", 2},
|
|
|
|
|
{"test_prefix.0.1", 3},
|
|
|
|
|
{"test_prefix.1", 4},
|
|
|
|
|
{"test_prefix.2", 5},
|
|
|
|
|
{"test_prefix.2.0", 6},
|
|
|
|
|
{"test_prefix.2.1", 7},
|
|
|
|
|
{"test_prefix.2.1.0", 8},
|
|
|
|
|
{"test_prefix.2.1.1", 9}};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(ModuleTest, ModulesReturnsExpectedSubmodulesForDeepModel) {
|
|
|
|
|
auto model = make_deeply_nested_test_container();
|
|
|
|
|
std::vector<std::shared_ptr<torch::nn::Module>> modules = model->modules();
|
|
|
|
|
|
|
|
|
|
ASSERT_EQ(modules.size(), 10);
|
2021-12-09 17:44:04 +00:00
|
|
|
for (const auto i : c10::irange(modules.size())) {
|
Replace cursors with OrderedDict (#13427)
Summary:
This is a pre-cursor diff to Python <-> C++ frontend integration -- I have a follow-up PR coming for that. This PR changes the C++ frontend module interface to replace the custom "cursor"s I introduced some time ago with `OrderedDict`. I introduced cursors at the time as a convenient way of applying functions and query operations on a modules' parameters, buffers and modules, allowing things like `module.parameters().map(my_func)`. However, I noticed that (1) this functionality is easily implement-able on top of a regular data structure and (2) more importantly, using OrderedDicts is much, much easier for Python integration. This is especially true given that ScriptModule today also uses OrderedDict. Since C++ frontend modules and ScriptModules will soon too share as many implementation details as possible, it is overall the best move to ditch the custom cursor datastructure and pervasively use OrderedDict everywhere.
For this I did:
1. Changed the C++ frontend module interface to more closely match the Python one by providing `parameters()`, `named_parameters()` and other methods Python provides. This is very important for the following diff which binds these into Python for inter-op with Python modules.
2. In lieu of the `Cursor::apply()` method I added `nn::Module::apply`. This again is one more unifying step between Python and C++, since Python modules have an apply function too.
3. Deleted all uses of Cursor.
4. Tidied and beefed up the `OrderedDict` class. In particular, I made `OrderedDict::Item` store an `std::pair` under the hood, because that is trivial to bind into Python and saved me a lot of headaches. `key` and `value` become methods instead of fields, which they should have been from the very start anyway because it allows exactly these kinds of changes, as per usual good software engineering principle of encapsulation.
5. Added many tests for the OrderedDict use in `nn::Module`.
ebetica ezyang
Pull Request resolved: https://github.com/pytorch/pytorch/pull/13427
Differential Revision: D12894092
Pulled By: goldsborough
fbshipit-source-id: 715770c95a9643753a1db26d7f9da9a78619a15d
2018-11-07 18:53:07 +00:00
|
|
|
ASSERT_EQ(get_test_container_item(modules[i]), i);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(ModuleTest, NamedModulesReturnsExpectedNamedSubmodulesForDeepModel) {
|
|
|
|
|
auto model = make_deeply_nested_test_container();
|
|
|
|
|
torch::OrderedDict<std::string, std::shared_ptr<torch::nn::Module>> modules =
|
|
|
|
|
model->named_modules(/*name_prefix=*/"test_prefix");
|
|
|
|
|
auto expected = make_key_value_pairs_for_deeply_nested_container();
|
|
|
|
|
|
|
|
|
|
ASSERT_EQ(modules.size(), expected.size());
|
|
|
|
|
|
2021-12-09 17:44:04 +00:00
|
|
|
for (const auto i : c10::irange(expected.size())) {
|
Replace cursors with OrderedDict (#13427)
Summary:
This is a pre-cursor diff to Python <-> C++ frontend integration -- I have a follow-up PR coming for that. This PR changes the C++ frontend module interface to replace the custom "cursor"s I introduced some time ago with `OrderedDict`. I introduced cursors at the time as a convenient way of applying functions and query operations on a modules' parameters, buffers and modules, allowing things like `module.parameters().map(my_func)`. However, I noticed that (1) this functionality is easily implement-able on top of a regular data structure and (2) more importantly, using OrderedDicts is much, much easier for Python integration. This is especially true given that ScriptModule today also uses OrderedDict. Since C++ frontend modules and ScriptModules will soon too share as many implementation details as possible, it is overall the best move to ditch the custom cursor datastructure and pervasively use OrderedDict everywhere.
For this I did:
1. Changed the C++ frontend module interface to more closely match the Python one by providing `parameters()`, `named_parameters()` and other methods Python provides. This is very important for the following diff which binds these into Python for inter-op with Python modules.
2. In lieu of the `Cursor::apply()` method I added `nn::Module::apply`. This again is one more unifying step between Python and C++, since Python modules have an apply function too.
3. Deleted all uses of Cursor.
4. Tidied and beefed up the `OrderedDict` class. In particular, I made `OrderedDict::Item` store an `std::pair` under the hood, because that is trivial to bind into Python and saved me a lot of headaches. `key` and `value` become methods instead of fields, which they should have been from the very start anyway because it allows exactly these kinds of changes, as per usual good software engineering principle of encapsulation.
5. Added many tests for the OrderedDict use in `nn::Module`.
ebetica ezyang
Pull Request resolved: https://github.com/pytorch/pytorch/pull/13427
Differential Revision: D12894092
Pulled By: goldsborough
fbshipit-source-id: 715770c95a9643753a1db26d7f9da9a78619a15d
2018-11-07 18:53:07 +00:00
|
|
|
ASSERT_EQ(modules[i].key(), expected[i].first);
|
|
|
|
|
ASSERT_EQ(get_test_container_item(modules[i].value()), expected[i].second);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(ModuleTest, ChildrensReturnsExpectedSubmodulesForDeepModel) {
|
|
|
|
|
auto model = make_deeply_nested_test_container();
|
|
|
|
|
std::vector<std::shared_ptr<torch::nn::Module>> modules = model->children();
|
|
|
|
|
|
|
|
|
|
ASSERT_EQ(modules.size(), 3);
|
|
|
|
|
ASSERT_EQ(get_test_container_item(modules[0]), 1);
|
|
|
|
|
ASSERT_EQ(get_test_container_item(modules[1]), 4);
|
|
|
|
|
ASSERT_EQ(get_test_container_item(modules[2]), 5);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(ModuleTest, NamedChildrensReturnsExpectedNamedSubmodulesForDeepModel) {
|
|
|
|
|
auto model = make_deeply_nested_test_container();
|
|
|
|
|
torch::OrderedDict<std::string, std::shared_ptr<torch::nn::Module>> modules =
|
|
|
|
|
model->named_children();
|
|
|
|
|
|
|
|
|
|
ASSERT_EQ(modules.size(), 3);
|
|
|
|
|
|
|
|
|
|
ASSERT_EQ(get_test_container_item(modules[0].value()), 1);
|
|
|
|
|
ASSERT_EQ(modules[0].key(), "0");
|
|
|
|
|
|
|
|
|
|
ASSERT_EQ(get_test_container_item(modules[1].value()), 4);
|
|
|
|
|
ASSERT_EQ(modules[1].key(), "1");
|
|
|
|
|
|
|
|
|
|
ASSERT_EQ(get_test_container_item(modules[2].value()), 5);
|
|
|
|
|
ASSERT_EQ(modules[2].key(), "2");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(ModuleTest, ModuleApplyIteratesCorreclty) {
|
|
|
|
|
auto model = make_deeply_nested_test_container();
|
|
|
|
|
int64_t index = 0;
|
|
|
|
|
model->apply([&index](torch::nn::Module& module) {
|
|
|
|
|
ASSERT_EQ(module.as<TestContainer>()->tensor.item<int64_t>(), index++);
|
|
|
|
|
});
|
|
|
|
|
ASSERT_EQ(index, 10);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(ModuleTest, ConstModuleApplyIteratesCorreclty) {
|
|
|
|
|
std::shared_ptr<const TestContainer> model =
|
|
|
|
|
make_deeply_nested_test_container();
|
|
|
|
|
int64_t index = 0;
|
|
|
|
|
model->apply([&index](const torch::nn::Module& module) {
|
|
|
|
|
ASSERT_EQ(module.as<TestContainer>()->tensor.item<int64_t>(), index++);
|
|
|
|
|
});
|
|
|
|
|
ASSERT_EQ(index, 10);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(ModuleTest, NamedModuleApplyIteratesCorreclty) {
|
|
|
|
|
auto model = make_deeply_nested_test_container();
|
|
|
|
|
auto expected = make_key_value_pairs_for_deeply_nested_container();
|
|
|
|
|
int64_t index = 0;
|
|
|
|
|
model->apply(
|
|
|
|
|
[&index, expected](const std::string& name, torch::nn::Module& module) {
|
|
|
|
|
ASSERT_EQ(name, expected[index].first);
|
|
|
|
|
ASSERT_EQ(
|
|
|
|
|
module.as<TestContainer>()->tensor.item<int64_t>(),
|
|
|
|
|
expected[index++].second);
|
|
|
|
|
},
|
|
|
|
|
/*name_prefix=*/"test_prefix");
|
|
|
|
|
ASSERT_EQ(index, 10);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(ModuleTest, ConstNamedModuleApplyIteratesCorreclty) {
|
|
|
|
|
std::shared_ptr<const TestContainer> model =
|
|
|
|
|
make_deeply_nested_test_container();
|
|
|
|
|
auto expected = make_key_value_pairs_for_deeply_nested_container();
|
|
|
|
|
int64_t index = 0;
|
|
|
|
|
model->apply(
|
|
|
|
|
[&index, &expected](
|
|
|
|
|
const std::string& name, const torch::nn::Module& module) {
|
|
|
|
|
ASSERT_EQ(name, expected[index].first);
|
|
|
|
|
ASSERT_EQ(
|
|
|
|
|
module.as<const TestContainer>()->tensor.item<int64_t>(),
|
|
|
|
|
expected[index++].second);
|
|
|
|
|
},
|
|
|
|
|
/*name_prefix=*/"test_prefix");
|
|
|
|
|
ASSERT_EQ(index, 10);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(ModuleTest, ModulePointerApplyIteratesCorreclty) {
|
|
|
|
|
auto model = make_deeply_nested_test_container();
|
|
|
|
|
int64_t index = 0;
|
|
|
|
|
model->apply([&index](const std::shared_ptr<torch::nn::Module>& module) {
|
|
|
|
|
ASSERT_EQ(get_test_container_item(module), index++);
|
|
|
|
|
});
|
|
|
|
|
ASSERT_EQ(index, 10);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(ModuleTest, NamedModulePointerApplyIteratesCorreclty) {
|
|
|
|
|
auto model = make_deeply_nested_test_container();
|
|
|
|
|
auto expected = make_key_value_pairs_for_deeply_nested_container();
|
|
|
|
|
int64_t index = 0;
|
|
|
|
|
model->apply(
|
|
|
|
|
[&index, &expected](
|
|
|
|
|
const std::string& name,
|
|
|
|
|
const std::shared_ptr<torch::nn::Module>& module) {
|
|
|
|
|
ASSERT_EQ(name, expected[index].first);
|
|
|
|
|
ASSERT_EQ(get_test_container_item(module), expected[index++].second);
|
|
|
|
|
},
|
|
|
|
|
/*name_prefix=*/"test_prefix");
|
|
|
|
|
ASSERT_EQ(index, 10);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(ModuleTest, ThrowsWhenAttemptingtoGetTopLevelModuleAsSharedPtr) {
|
|
|
|
|
{
|
|
|
|
|
TestModule module(1);
|
|
|
|
|
ASSERT_THROWS_WITH(
|
|
|
|
|
module.modules(),
|
|
|
|
|
"It looks like you attempted to retrieve "
|
|
|
|
|
"your top-level module as a shared_ptr")
|
|
|
|
|
}
|
|
|
|
|
{
|
|
|
|
|
TestModule module(1);
|
Make PyTorch code-base clang-tidy compliant (#56892)
Summary:
This is an automatic change generated by the following script:
```
#!/usr/bin/env python3
from subprocess import check_output, check_call
import os
def get_compiled_files_list():
import json
with open("build/compile_commands.json") as f:
data = json.load(f)
files = [os.path.relpath(node['file']) for node in data]
for idx, fname in enumerate(files):
if fname.startswith('build/') and fname.endswith('.DEFAULT.cpp'):
files[idx] = fname[len('build/'):-len('.DEFAULT.cpp')]
return files
def run_clang_tidy(fname):
check_call(["python3", "tools/clang_tidy.py", "-c", "build", "-x", fname,"-s"])
changes = check_output(["git", "ls-files", "-m"])
if len(changes) == 0:
return
check_call(["git", "commit","--all", "-m", f"NOLINT stubs for {fname}"])
def main():
git_files = check_output(["git", "ls-files"]).decode("ascii").split("\n")
compiled_files = get_compiled_files_list()
for idx, fname in enumerate(git_files):
if fname not in compiled_files:
continue
if fname.startswith("caffe2/contrib/aten/"):
continue
print(f"[{idx}/{len(git_files)}] Processing {fname}")
run_clang_tidy(fname)
if __name__ == "__main__":
main()
```
Pull Request resolved: https://github.com/pytorch/pytorch/pull/56892
Reviewed By: H-Huang
Differential Revision: D27991944
Pulled By: malfet
fbshipit-source-id: 5415e1eb2c1b34319a4f03024bfaa087007d7179
2021-04-28 21:09:06 +00:00
|
|
|
// NOLINTNEXTLINE(hicpp-avoid-goto,cppcoreguidelines-avoid-goto)
|
Replace cursors with OrderedDict (#13427)
Summary:
This is a pre-cursor diff to Python <-> C++ frontend integration -- I have a follow-up PR coming for that. This PR changes the C++ frontend module interface to replace the custom "cursor"s I introduced some time ago with `OrderedDict`. I introduced cursors at the time as a convenient way of applying functions and query operations on a modules' parameters, buffers and modules, allowing things like `module.parameters().map(my_func)`. However, I noticed that (1) this functionality is easily implement-able on top of a regular data structure and (2) more importantly, using OrderedDicts is much, much easier for Python integration. This is especially true given that ScriptModule today also uses OrderedDict. Since C++ frontend modules and ScriptModules will soon too share as many implementation details as possible, it is overall the best move to ditch the custom cursor datastructure and pervasively use OrderedDict everywhere.
For this I did:
1. Changed the C++ frontend module interface to more closely match the Python one by providing `parameters()`, `named_parameters()` and other methods Python provides. This is very important for the following diff which binds these into Python for inter-op with Python modules.
2. In lieu of the `Cursor::apply()` method I added `nn::Module::apply`. This again is one more unifying step between Python and C++, since Python modules have an apply function too.
3. Deleted all uses of Cursor.
4. Tidied and beefed up the `OrderedDict` class. In particular, I made `OrderedDict::Item` store an `std::pair` under the hood, because that is trivial to bind into Python and saved me a lot of headaches. `key` and `value` become methods instead of fields, which they should have been from the very start anyway because it allows exactly these kinds of changes, as per usual good software engineering principle of encapsulation.
5. Added many tests for the OrderedDict use in `nn::Module`.
ebetica ezyang
Pull Request resolved: https://github.com/pytorch/pytorch/pull/13427
Differential Revision: D12894092
Pulled By: goldsborough
fbshipit-source-id: 715770c95a9643753a1db26d7f9da9a78619a15d
2018-11-07 18:53:07 +00:00
|
|
|
ASSERT_NO_THROW(module.modules(/*include_self=*/false));
|
|
|
|
|
}
|
|
|
|
|
{
|
|
|
|
|
auto module = std::make_shared<TestModule>(1);
|
Make PyTorch code-base clang-tidy compliant (#56892)
Summary:
This is an automatic change generated by the following script:
```
#!/usr/bin/env python3
from subprocess import check_output, check_call
import os
def get_compiled_files_list():
import json
with open("build/compile_commands.json") as f:
data = json.load(f)
files = [os.path.relpath(node['file']) for node in data]
for idx, fname in enumerate(files):
if fname.startswith('build/') and fname.endswith('.DEFAULT.cpp'):
files[idx] = fname[len('build/'):-len('.DEFAULT.cpp')]
return files
def run_clang_tidy(fname):
check_call(["python3", "tools/clang_tidy.py", "-c", "build", "-x", fname,"-s"])
changes = check_output(["git", "ls-files", "-m"])
if len(changes) == 0:
return
check_call(["git", "commit","--all", "-m", f"NOLINT stubs for {fname}"])
def main():
git_files = check_output(["git", "ls-files"]).decode("ascii").split("\n")
compiled_files = get_compiled_files_list()
for idx, fname in enumerate(git_files):
if fname not in compiled_files:
continue
if fname.startswith("caffe2/contrib/aten/"):
continue
print(f"[{idx}/{len(git_files)}] Processing {fname}")
run_clang_tidy(fname)
if __name__ == "__main__":
main()
```
Pull Request resolved: https://github.com/pytorch/pytorch/pull/56892
Reviewed By: H-Huang
Differential Revision: D27991944
Pulled By: malfet
fbshipit-source-id: 5415e1eb2c1b34319a4f03024bfaa087007d7179
2021-04-28 21:09:06 +00:00
|
|
|
// NOLINTNEXTLINE(hicpp-avoid-goto,cppcoreguidelines-avoid-goto)
|
Replace cursors with OrderedDict (#13427)
Summary:
This is a pre-cursor diff to Python <-> C++ frontend integration -- I have a follow-up PR coming for that. This PR changes the C++ frontend module interface to replace the custom "cursor"s I introduced some time ago with `OrderedDict`. I introduced cursors at the time as a convenient way of applying functions and query operations on a modules' parameters, buffers and modules, allowing things like `module.parameters().map(my_func)`. However, I noticed that (1) this functionality is easily implement-able on top of a regular data structure and (2) more importantly, using OrderedDicts is much, much easier for Python integration. This is especially true given that ScriptModule today also uses OrderedDict. Since C++ frontend modules and ScriptModules will soon too share as many implementation details as possible, it is overall the best move to ditch the custom cursor datastructure and pervasively use OrderedDict everywhere.
For this I did:
1. Changed the C++ frontend module interface to more closely match the Python one by providing `parameters()`, `named_parameters()` and other methods Python provides. This is very important for the following diff which binds these into Python for inter-op with Python modules.
2. In lieu of the `Cursor::apply()` method I added `nn::Module::apply`. This again is one more unifying step between Python and C++, since Python modules have an apply function too.
3. Deleted all uses of Cursor.
4. Tidied and beefed up the `OrderedDict` class. In particular, I made `OrderedDict::Item` store an `std::pair` under the hood, because that is trivial to bind into Python and saved me a lot of headaches. `key` and `value` become methods instead of fields, which they should have been from the very start anyway because it allows exactly these kinds of changes, as per usual good software engineering principle of encapsulation.
5. Added many tests for the OrderedDict use in `nn::Module`.
ebetica ezyang
Pull Request resolved: https://github.com/pytorch/pytorch/pull/13427
Differential Revision: D12894092
Pulled By: goldsborough
fbshipit-source-id: 715770c95a9643753a1db26d7f9da9a78619a15d
2018-11-07 18:53:07 +00:00
|
|
|
ASSERT_NO_THROW(module->modules());
|
|
|
|
|
}
|
|
|
|
|
}
|
Pretty printing of C++ modules (#15326)
Summary:
A long outstanding nicety: pretty printing of C++ modules. E.g.
```
Sequential sequential(
Linear(10, 3),
Conv2d(1, 2, 3),
Dropout(0.5),
BatchNorm(5),
Embedding(4, 10),
LSTM(4, 5));
std::cout << sequential;
```
prints
```
torch::nn::Sequential(
(0): torch::nn::Linear(in=10, out=3, with_bias=true)
(1): torch::nn::Conv2d(input_channels=1, output_channels=2, kernel_size=[3, 3], stride=[1, 1])
(2): torch::nn::Dropout(rate=0.5)
(3): torch::nn::BatchNorm(features=5, eps=1e-05, momentum=0.1, affine=true, stateful=true)
(4): torch::nn::Embedding(count=4, dimension=10)
(5): torch::nn::LSTM(input_size=4, hidden_size=5, layers=1, dropout=0)
)
```
apaszke ebetica ezyang
Pull Request resolved: https://github.com/pytorch/pytorch/pull/15326
Differential Revision: D13518986
Pulled By: goldsborough
fbshipit-source-id: 63bf753672f0e348951de3645208f263581de5fb
2018-12-20 05:38:00 +00:00
|
|
|
|
|
|
|
|
struct EmptyModule : torch::nn::Module {};
|
|
|
|
|
|
|
|
|
|
TEST_F(ModuleTest, PrettyPrint) {
|
|
|
|
|
struct TestModule : torch::nn::Module {
|
|
|
|
|
TestModule(int x, float y) : x_(x), y_(y) {}
|
|
|
|
|
|
2019-02-14 04:51:55 +00:00
|
|
|
void pretty_print(std::ostream& stream) const override {
|
Pretty printing of C++ modules (#15326)
Summary:
A long outstanding nicety: pretty printing of C++ modules. E.g.
```
Sequential sequential(
Linear(10, 3),
Conv2d(1, 2, 3),
Dropout(0.5),
BatchNorm(5),
Embedding(4, 10),
LSTM(4, 5));
std::cout << sequential;
```
prints
```
torch::nn::Sequential(
(0): torch::nn::Linear(in=10, out=3, with_bias=true)
(1): torch::nn::Conv2d(input_channels=1, output_channels=2, kernel_size=[3, 3], stride=[1, 1])
(2): torch::nn::Dropout(rate=0.5)
(3): torch::nn::BatchNorm(features=5, eps=1e-05, momentum=0.1, affine=true, stateful=true)
(4): torch::nn::Embedding(count=4, dimension=10)
(5): torch::nn::LSTM(input_size=4, hidden_size=5, layers=1, dropout=0)
)
```
apaszke ebetica ezyang
Pull Request resolved: https://github.com/pytorch/pytorch/pull/15326
Differential Revision: D13518986
Pulled By: goldsborough
fbshipit-source-id: 63bf753672f0e348951de3645208f263581de5fb
2018-12-20 05:38:00 +00:00
|
|
|
stream << "TestModule(x=" << x_ << ", y=" << y_ << ")";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int x_;
|
|
|
|
|
float y_;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
ASSERT_EQ(c10::str(EmptyModule{}), "EmptyModule");
|
|
|
|
|
ASSERT_EQ(c10::str(TestModule(1, 3.14)), "TestModule(x=1, y=3.14)");
|
|
|
|
|
}
|
2019-01-14 22:32:32 +00:00
|
|
|
|
|
|
|
|
struct ModuleWithNonTensorForwardImpl : torch::nn::Module {
|
|
|
|
|
int64_t forward(torch::Tensor x) {
|
|
|
|
|
return x.numel();
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
TORCH_MODULE(ModuleWithNonTensorForward);
|
|
|
|
|
|
|
|
|
|
TEST_F(ModuleTest, CanCallForwardOnNonTensorForwardThroughPimpl) {
|
|
|
|
|
ModuleWithNonTensorForward m;
|
|
|
|
|
ASSERT_EQ(m(torch::ones(123)), 123);
|
|
|
|
|
}
|