2018-09-22 04:12:37 +00:00
|
|
|
#include <gtest/gtest.h>
|
2018-05-24 19:46:51 +00:00
|
|
|
|
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-24 19:46:51 +00:00
|
|
|
|
2018-09-14 22:06:12 +00:00
|
|
|
#include <algorithm>
|
2018-06-25 02:03:39 +00:00
|
|
|
#include <memory>
|
2018-05-24 19:46:51 +00:00
|
|
|
#include <vector>
|
|
|
|
|
|
2018-09-22 04:12:37 +00:00
|
|
|
#include <test/cpp/api/support.h>
|
2018-07-17 04:43:40 +00:00
|
|
|
|
2018-05-24 19:46:51 +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-09-22 04:12:37 +00:00
|
|
|
struct SequentialTest : torch::test::SeedingFixture {};
|
2018-05-24 19:46:51 +00:00
|
|
|
|
2019-10-23 20:39:33 +00:00
|
|
|
TEST_F(SequentialTest, CanContainThings) {
|
|
|
|
|
Sequential sequential(Linear(3, 4), ReLU(), BatchNorm(3));
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-22 04:12:37 +00:00
|
|
|
TEST_F(SequentialTest, ConstructsFromSharedPointer) {
|
2018-09-14 22:06:12 +00:00
|
|
|
struct M : torch::nn::Module {
|
|
|
|
|
explicit M(int value_) : value(value_) {}
|
|
|
|
|
int value;
|
|
|
|
|
int forward() {
|
|
|
|
|
return value;
|
2018-05-24 19:46:51 +00:00
|
|
|
}
|
2018-09-14 22:06:12 +00:00
|
|
|
};
|
|
|
|
|
Sequential sequential(
|
|
|
|
|
std::make_shared<M>(1), std::make_shared<M>(2), std::make_shared<M>(3));
|
2018-09-22 04:12:37 +00:00
|
|
|
ASSERT_EQ(sequential->size(), 3);
|
Add named submodule support to nn::Sequential (#17552)
Summary:
Previously, we were not able to assign names to `nn::Sequential`'s submodules. This PR adds this feature to match the Python API. Example use:
```cpp
Sequential sequential(named_submodule({
{"linear", Linear(10, 3)},
{"conv2d", Conv2d(1, 2, 3)},
{"dropout", Dropout(0.5)},
{"batchnorm", BatchNorm(5)},
{"embedding", Embedding(4, 10)},
{"lstm", LSTM(4, 5)}
}));
```
It also enables loading parameters of Python `nn.Sequential` module with custom submodules names into C++ frontend, unblocking https://github.com/pytorch/vision/pull/728#issuecomment-466661344.
Pull Request resolved: https://github.com/pytorch/pytorch/pull/17552
Differential Revision: D14246834
Pulled By: yf225
fbshipit-source-id: 3030b5c5d68f6dd5d3e37ac4b4f98dc6d6d9ba72
2019-03-29 19:59:29 +00:00
|
|
|
|
2019-10-28 19:59:27 +00:00
|
|
|
Sequential sequential_named({
|
Add named submodule support to nn::Sequential (#17552)
Summary:
Previously, we were not able to assign names to `nn::Sequential`'s submodules. This PR adds this feature to match the Python API. Example use:
```cpp
Sequential sequential(named_submodule({
{"linear", Linear(10, 3)},
{"conv2d", Conv2d(1, 2, 3)},
{"dropout", Dropout(0.5)},
{"batchnorm", BatchNorm(5)},
{"embedding", Embedding(4, 10)},
{"lstm", LSTM(4, 5)}
}));
```
It also enables loading parameters of Python `nn.Sequential` module with custom submodules names into C++ frontend, unblocking https://github.com/pytorch/vision/pull/728#issuecomment-466661344.
Pull Request resolved: https://github.com/pytorch/pytorch/pull/17552
Differential Revision: D14246834
Pulled By: yf225
fbshipit-source-id: 3030b5c5d68f6dd5d3e37ac4b4f98dc6d6d9ba72
2019-03-29 19:59:29 +00:00
|
|
|
{"m1", std::make_shared<M>(1)},
|
|
|
|
|
{std::string("m2"), std::make_shared<M>(2)},
|
|
|
|
|
{"m3", std::make_shared<M>(3)}
|
2019-10-28 19:59:27 +00:00
|
|
|
});
|
Add named submodule support to nn::Sequential (#17552)
Summary:
Previously, we were not able to assign names to `nn::Sequential`'s submodules. This PR adds this feature to match the Python API. Example use:
```cpp
Sequential sequential(named_submodule({
{"linear", Linear(10, 3)},
{"conv2d", Conv2d(1, 2, 3)},
{"dropout", Dropout(0.5)},
{"batchnorm", BatchNorm(5)},
{"embedding", Embedding(4, 10)},
{"lstm", LSTM(4, 5)}
}));
```
It also enables loading parameters of Python `nn.Sequential` module with custom submodules names into C++ frontend, unblocking https://github.com/pytorch/vision/pull/728#issuecomment-466661344.
Pull Request resolved: https://github.com/pytorch/pytorch/pull/17552
Differential Revision: D14246834
Pulled By: yf225
fbshipit-source-id: 3030b5c5d68f6dd5d3e37ac4b4f98dc6d6d9ba72
2019-03-29 19:59:29 +00:00
|
|
|
ASSERT_EQ(sequential->size(), 3);
|
2018-09-14 22:06:12 +00:00
|
|
|
}
|
2018-05-24 19:46:51 +00:00
|
|
|
|
2018-09-22 04:12:37 +00:00
|
|
|
TEST_F(SequentialTest, ConstructsFromConcreteType) {
|
Add named submodule support to nn::Sequential (#17552)
Summary:
Previously, we were not able to assign names to `nn::Sequential`'s submodules. This PR adds this feature to match the Python API. Example use:
```cpp
Sequential sequential(named_submodule({
{"linear", Linear(10, 3)},
{"conv2d", Conv2d(1, 2, 3)},
{"dropout", Dropout(0.5)},
{"batchnorm", BatchNorm(5)},
{"embedding", Embedding(4, 10)},
{"lstm", LSTM(4, 5)}
}));
```
It also enables loading parameters of Python `nn.Sequential` module with custom submodules names into C++ frontend, unblocking https://github.com/pytorch/vision/pull/728#issuecomment-466661344.
Pull Request resolved: https://github.com/pytorch/pytorch/pull/17552
Differential Revision: D14246834
Pulled By: yf225
fbshipit-source-id: 3030b5c5d68f6dd5d3e37ac4b4f98dc6d6d9ba72
2019-03-29 19:59:29 +00:00
|
|
|
static int copy_count;
|
|
|
|
|
|
2018-09-14 22:06:12 +00:00
|
|
|
struct M : torch::nn::Module {
|
|
|
|
|
explicit M(int value_) : value(value_) {}
|
Add named submodule support to nn::Sequential (#17552)
Summary:
Previously, we were not able to assign names to `nn::Sequential`'s submodules. This PR adds this feature to match the Python API. Example use:
```cpp
Sequential sequential(named_submodule({
{"linear", Linear(10, 3)},
{"conv2d", Conv2d(1, 2, 3)},
{"dropout", Dropout(0.5)},
{"batchnorm", BatchNorm(5)},
{"embedding", Embedding(4, 10)},
{"lstm", LSTM(4, 5)}
}));
```
It also enables loading parameters of Python `nn.Sequential` module with custom submodules names into C++ frontend, unblocking https://github.com/pytorch/vision/pull/728#issuecomment-466661344.
Pull Request resolved: https://github.com/pytorch/pytorch/pull/17552
Differential Revision: D14246834
Pulled By: yf225
fbshipit-source-id: 3030b5c5d68f6dd5d3e37ac4b4f98dc6d6d9ba72
2019-03-29 19:59:29 +00:00
|
|
|
M(const M& other) : torch::nn::Module(other) {
|
|
|
|
|
copy_count++;
|
|
|
|
|
}
|
2018-09-14 22:06:12 +00:00
|
|
|
int value;
|
|
|
|
|
int forward() {
|
|
|
|
|
return value;
|
2018-05-24 19:46:51 +00:00
|
|
|
}
|
2018-09-14 22:06:12 +00:00
|
|
|
};
|
|
|
|
|
|
Add named submodule support to nn::Sequential (#17552)
Summary:
Previously, we were not able to assign names to `nn::Sequential`'s submodules. This PR adds this feature to match the Python API. Example use:
```cpp
Sequential sequential(named_submodule({
{"linear", Linear(10, 3)},
{"conv2d", Conv2d(1, 2, 3)},
{"dropout", Dropout(0.5)},
{"batchnorm", BatchNorm(5)},
{"embedding", Embedding(4, 10)},
{"lstm", LSTM(4, 5)}
}));
```
It also enables loading parameters of Python `nn.Sequential` module with custom submodules names into C++ frontend, unblocking https://github.com/pytorch/vision/pull/728#issuecomment-466661344.
Pull Request resolved: https://github.com/pytorch/pytorch/pull/17552
Differential Revision: D14246834
Pulled By: yf225
fbshipit-source-id: 3030b5c5d68f6dd5d3e37ac4b4f98dc6d6d9ba72
2019-03-29 19:59:29 +00:00
|
|
|
copy_count = 0;
|
2018-09-14 22:06:12 +00:00
|
|
|
Sequential sequential(M(1), M(2), M(3));
|
2018-09-22 04:12:37 +00:00
|
|
|
ASSERT_EQ(sequential->size(), 3);
|
Add named submodule support to nn::Sequential (#17552)
Summary:
Previously, we were not able to assign names to `nn::Sequential`'s submodules. This PR adds this feature to match the Python API. Example use:
```cpp
Sequential sequential(named_submodule({
{"linear", Linear(10, 3)},
{"conv2d", Conv2d(1, 2, 3)},
{"dropout", Dropout(0.5)},
{"batchnorm", BatchNorm(5)},
{"embedding", Embedding(4, 10)},
{"lstm", LSTM(4, 5)}
}));
```
It also enables loading parameters of Python `nn.Sequential` module with custom submodules names into C++ frontend, unblocking https://github.com/pytorch/vision/pull/728#issuecomment-466661344.
Pull Request resolved: https://github.com/pytorch/pytorch/pull/17552
Differential Revision: D14246834
Pulled By: yf225
fbshipit-source-id: 3030b5c5d68f6dd5d3e37ac4b4f98dc6d6d9ba72
2019-03-29 19:59:29 +00:00
|
|
|
// NOTE: The current implementation expects each module to be copied exactly once,
|
|
|
|
|
// which happens when the module is passed into `std::make_shared<T>()`.
|
|
|
|
|
// TODO: Find a way to avoid copying, and then delete the copy constructor of `M`.
|
|
|
|
|
ASSERT_EQ(copy_count, 3);
|
|
|
|
|
|
|
|
|
|
copy_count = 0;
|
2019-10-28 19:59:27 +00:00
|
|
|
Sequential sequential_named({
|
Add named submodule support to nn::Sequential (#17552)
Summary:
Previously, we were not able to assign names to `nn::Sequential`'s submodules. This PR adds this feature to match the Python API. Example use:
```cpp
Sequential sequential(named_submodule({
{"linear", Linear(10, 3)},
{"conv2d", Conv2d(1, 2, 3)},
{"dropout", Dropout(0.5)},
{"batchnorm", BatchNorm(5)},
{"embedding", Embedding(4, 10)},
{"lstm", LSTM(4, 5)}
}));
```
It also enables loading parameters of Python `nn.Sequential` module with custom submodules names into C++ frontend, unblocking https://github.com/pytorch/vision/pull/728#issuecomment-466661344.
Pull Request resolved: https://github.com/pytorch/pytorch/pull/17552
Differential Revision: D14246834
Pulled By: yf225
fbshipit-source-id: 3030b5c5d68f6dd5d3e37ac4b4f98dc6d6d9ba72
2019-03-29 19:59:29 +00:00
|
|
|
{"m1", M(1)},
|
|
|
|
|
{std::string("m2"), M(2)},
|
|
|
|
|
{"m3", M(3)}
|
2019-10-28 19:59:27 +00:00
|
|
|
});
|
Add named submodule support to nn::Sequential (#17552)
Summary:
Previously, we were not able to assign names to `nn::Sequential`'s submodules. This PR adds this feature to match the Python API. Example use:
```cpp
Sequential sequential(named_submodule({
{"linear", Linear(10, 3)},
{"conv2d", Conv2d(1, 2, 3)},
{"dropout", Dropout(0.5)},
{"batchnorm", BatchNorm(5)},
{"embedding", Embedding(4, 10)},
{"lstm", LSTM(4, 5)}
}));
```
It also enables loading parameters of Python `nn.Sequential` module with custom submodules names into C++ frontend, unblocking https://github.com/pytorch/vision/pull/728#issuecomment-466661344.
Pull Request resolved: https://github.com/pytorch/pytorch/pull/17552
Differential Revision: D14246834
Pulled By: yf225
fbshipit-source-id: 3030b5c5d68f6dd5d3e37ac4b4f98dc6d6d9ba72
2019-03-29 19:59:29 +00:00
|
|
|
ASSERT_EQ(sequential->size(), 3);
|
|
|
|
|
ASSERT_EQ(copy_count, 3);
|
2018-09-14 22:06:12 +00:00
|
|
|
}
|
Add named submodule support to nn::Sequential (#17552)
Summary:
Previously, we were not able to assign names to `nn::Sequential`'s submodules. This PR adds this feature to match the Python API. Example use:
```cpp
Sequential sequential(named_submodule({
{"linear", Linear(10, 3)},
{"conv2d", Conv2d(1, 2, 3)},
{"dropout", Dropout(0.5)},
{"batchnorm", BatchNorm(5)},
{"embedding", Embedding(4, 10)},
{"lstm", LSTM(4, 5)}
}));
```
It also enables loading parameters of Python `nn.Sequential` module with custom submodules names into C++ frontend, unblocking https://github.com/pytorch/vision/pull/728#issuecomment-466661344.
Pull Request resolved: https://github.com/pytorch/pytorch/pull/17552
Differential Revision: D14246834
Pulled By: yf225
fbshipit-source-id: 3030b5c5d68f6dd5d3e37ac4b4f98dc6d6d9ba72
2019-03-29 19:59:29 +00:00
|
|
|
|
2018-09-22 04:12:37 +00:00
|
|
|
TEST_F(SequentialTest, ConstructsFromModuleHolder) {
|
2018-09-14 22:06:12 +00:00
|
|
|
struct MImpl : torch::nn::Module {
|
|
|
|
|
explicit MImpl(int value_) : value(value_) {}
|
|
|
|
|
int forward() {
|
|
|
|
|
return value;
|
2018-05-24 19:46:51 +00:00
|
|
|
}
|
2018-09-14 22:06:12 +00:00
|
|
|
int value;
|
|
|
|
|
};
|
2018-05-24 19:46:51 +00:00
|
|
|
|
2018-09-14 22:06:12 +00:00
|
|
|
struct M : torch::nn::ModuleHolder<MImpl> {
|
|
|
|
|
using torch::nn::ModuleHolder<MImpl>::ModuleHolder;
|
|
|
|
|
using torch::nn::ModuleHolder<MImpl>::get;
|
|
|
|
|
};
|
2018-05-24 19:46:51 +00:00
|
|
|
|
2018-09-14 22:06:12 +00:00
|
|
|
Sequential sequential(M(1), M(2), M(3));
|
2018-09-22 04:12:37 +00:00
|
|
|
ASSERT_EQ(sequential->size(), 3);
|
Add named submodule support to nn::Sequential (#17552)
Summary:
Previously, we were not able to assign names to `nn::Sequential`'s submodules. This PR adds this feature to match the Python API. Example use:
```cpp
Sequential sequential(named_submodule({
{"linear", Linear(10, 3)},
{"conv2d", Conv2d(1, 2, 3)},
{"dropout", Dropout(0.5)},
{"batchnorm", BatchNorm(5)},
{"embedding", Embedding(4, 10)},
{"lstm", LSTM(4, 5)}
}));
```
It also enables loading parameters of Python `nn.Sequential` module with custom submodules names into C++ frontend, unblocking https://github.com/pytorch/vision/pull/728#issuecomment-466661344.
Pull Request resolved: https://github.com/pytorch/pytorch/pull/17552
Differential Revision: D14246834
Pulled By: yf225
fbshipit-source-id: 3030b5c5d68f6dd5d3e37ac4b4f98dc6d6d9ba72
2019-03-29 19:59:29 +00:00
|
|
|
|
2019-10-28 19:59:27 +00:00
|
|
|
Sequential sequential_named({
|
Add named submodule support to nn::Sequential (#17552)
Summary:
Previously, we were not able to assign names to `nn::Sequential`'s submodules. This PR adds this feature to match the Python API. Example use:
```cpp
Sequential sequential(named_submodule({
{"linear", Linear(10, 3)},
{"conv2d", Conv2d(1, 2, 3)},
{"dropout", Dropout(0.5)},
{"batchnorm", BatchNorm(5)},
{"embedding", Embedding(4, 10)},
{"lstm", LSTM(4, 5)}
}));
```
It also enables loading parameters of Python `nn.Sequential` module with custom submodules names into C++ frontend, unblocking https://github.com/pytorch/vision/pull/728#issuecomment-466661344.
Pull Request resolved: https://github.com/pytorch/pytorch/pull/17552
Differential Revision: D14246834
Pulled By: yf225
fbshipit-source-id: 3030b5c5d68f6dd5d3e37ac4b4f98dc6d6d9ba72
2019-03-29 19:59:29 +00:00
|
|
|
{"m1", M(1)},
|
|
|
|
|
{std::string("m2"), M(2)},
|
|
|
|
|
{"m3", M(3)}
|
2019-10-28 19:59:27 +00:00
|
|
|
});
|
Add named submodule support to nn::Sequential (#17552)
Summary:
Previously, we were not able to assign names to `nn::Sequential`'s submodules. This PR adds this feature to match the Python API. Example use:
```cpp
Sequential sequential(named_submodule({
{"linear", Linear(10, 3)},
{"conv2d", Conv2d(1, 2, 3)},
{"dropout", Dropout(0.5)},
{"batchnorm", BatchNorm(5)},
{"embedding", Embedding(4, 10)},
{"lstm", LSTM(4, 5)}
}));
```
It also enables loading parameters of Python `nn.Sequential` module with custom submodules names into C++ frontend, unblocking https://github.com/pytorch/vision/pull/728#issuecomment-466661344.
Pull Request resolved: https://github.com/pytorch/pytorch/pull/17552
Differential Revision: D14246834
Pulled By: yf225
fbshipit-source-id: 3030b5c5d68f6dd5d3e37ac4b4f98dc6d6d9ba72
2019-03-29 19:59:29 +00:00
|
|
|
ASSERT_EQ(sequential->size(), 3);
|
2018-09-14 22:06:12 +00:00
|
|
|
}
|
2018-05-24 19:46:51 +00:00
|
|
|
|
2019-10-28 19:59:27 +00:00
|
|
|
TEST_F(SequentialTest, LegacyBuilderForOrderedDictOfNamedModules) {
|
|
|
|
|
std::stringstream buffer;
|
|
|
|
|
CerrRedirect cerr_redirect(buffer.rdbuf());
|
|
|
|
|
|
|
|
|
|
Sequential sequential_named(modules_ordered_dict({
|
|
|
|
|
{"m1", Linear(3, 4)},
|
|
|
|
|
{"m2", ReLU()},
|
|
|
|
|
{"m3", BatchNorm(3)}
|
|
|
|
|
}));
|
|
|
|
|
ASSERT_EQ(sequential_named->size(), 3);
|
|
|
|
|
|
|
|
|
|
ASSERT_EQ(
|
|
|
|
|
count_substr_occurrences(buffer.str(), "`torch::nn::modules_ordered_dict` is deprecated"),
|
|
|
|
|
1);
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-22 04:12:37 +00:00
|
|
|
TEST_F(SequentialTest, PushBackAddsAnElement) {
|
2018-09-14 22:06:12 +00:00
|
|
|
struct M : torch::nn::Module {
|
|
|
|
|
explicit M(int value_) : value(value_) {}
|
|
|
|
|
int forward() {
|
|
|
|
|
return value;
|
2018-05-24 19:46:51 +00:00
|
|
|
}
|
2018-09-14 22:06:12 +00:00
|
|
|
int value;
|
|
|
|
|
};
|
Add named submodule support to nn::Sequential (#17552)
Summary:
Previously, we were not able to assign names to `nn::Sequential`'s submodules. This PR adds this feature to match the Python API. Example use:
```cpp
Sequential sequential(named_submodule({
{"linear", Linear(10, 3)},
{"conv2d", Conv2d(1, 2, 3)},
{"dropout", Dropout(0.5)},
{"batchnorm", BatchNorm(5)},
{"embedding", Embedding(4, 10)},
{"lstm", LSTM(4, 5)}
}));
```
It also enables loading parameters of Python `nn.Sequential` module with custom submodules names into C++ frontend, unblocking https://github.com/pytorch/vision/pull/728#issuecomment-466661344.
Pull Request resolved: https://github.com/pytorch/pytorch/pull/17552
Differential Revision: D14246834
Pulled By: yf225
fbshipit-source-id: 3030b5c5d68f6dd5d3e37ac4b4f98dc6d6d9ba72
2019-03-29 19:59:29 +00:00
|
|
|
|
|
|
|
|
// Test unnamed submodules
|
2018-09-14 22:06:12 +00:00
|
|
|
Sequential sequential;
|
2018-09-22 04:12:37 +00:00
|
|
|
ASSERT_EQ(sequential->size(), 0);
|
|
|
|
|
ASSERT_TRUE(sequential->is_empty());
|
2018-09-14 22:06:12 +00:00
|
|
|
sequential->push_back(Linear(3, 4));
|
2018-09-22 04:12:37 +00:00
|
|
|
ASSERT_EQ(sequential->size(), 1);
|
2018-09-14 22:06:12 +00:00
|
|
|
sequential->push_back(std::make_shared<M>(1));
|
2018-09-22 04:12:37 +00:00
|
|
|
ASSERT_EQ(sequential->size(), 2);
|
2018-09-14 22:06:12 +00:00
|
|
|
sequential->push_back(M(2));
|
2018-09-22 04:12:37 +00:00
|
|
|
ASSERT_EQ(sequential->size(), 3);
|
Add named submodule support to nn::Sequential (#17552)
Summary:
Previously, we were not able to assign names to `nn::Sequential`'s submodules. This PR adds this feature to match the Python API. Example use:
```cpp
Sequential sequential(named_submodule({
{"linear", Linear(10, 3)},
{"conv2d", Conv2d(1, 2, 3)},
{"dropout", Dropout(0.5)},
{"batchnorm", BatchNorm(5)},
{"embedding", Embedding(4, 10)},
{"lstm", LSTM(4, 5)}
}));
```
It also enables loading parameters of Python `nn.Sequential` module with custom submodules names into C++ frontend, unblocking https://github.com/pytorch/vision/pull/728#issuecomment-466661344.
Pull Request resolved: https://github.com/pytorch/pytorch/pull/17552
Differential Revision: D14246834
Pulled By: yf225
fbshipit-source-id: 3030b5c5d68f6dd5d3e37ac4b4f98dc6d6d9ba72
2019-03-29 19:59:29 +00:00
|
|
|
|
|
|
|
|
// Mix named and unnamed submodules
|
|
|
|
|
Sequential sequential_named;
|
|
|
|
|
ASSERT_EQ(sequential_named->size(), 0);
|
|
|
|
|
ASSERT_TRUE(sequential_named->is_empty());
|
|
|
|
|
|
|
|
|
|
sequential_named->push_back(Linear(3, 4));
|
|
|
|
|
ASSERT_EQ(sequential_named->size(), 1);
|
|
|
|
|
ASSERT_EQ(sequential_named->named_children()[0].key(), "0");
|
|
|
|
|
sequential_named->push_back(std::string("linear2"), Linear(3, 4));
|
|
|
|
|
ASSERT_EQ(sequential_named->size(), 2);
|
|
|
|
|
ASSERT_EQ(sequential_named->named_children()[1].key(), "linear2");
|
|
|
|
|
|
|
|
|
|
sequential_named->push_back("shared_m1", std::make_shared<M>(1));
|
|
|
|
|
ASSERT_EQ(sequential_named->size(), 3);
|
|
|
|
|
ASSERT_EQ(sequential_named->named_children()[2].key(), "shared_m1");
|
|
|
|
|
sequential_named->push_back(std::make_shared<M>(1));
|
|
|
|
|
ASSERT_EQ(sequential_named->size(), 4);
|
|
|
|
|
ASSERT_EQ(sequential_named->named_children()[3].key(), "3");
|
|
|
|
|
|
|
|
|
|
sequential_named->push_back(M(1));
|
|
|
|
|
ASSERT_EQ(sequential_named->size(), 5);
|
|
|
|
|
ASSERT_EQ(sequential_named->named_children()[4].key(), "4");
|
|
|
|
|
sequential_named->push_back(std::string("m2"), M(1));
|
|
|
|
|
ASSERT_EQ(sequential_named->size(), 6);
|
|
|
|
|
ASSERT_EQ(sequential_named->named_children()[5].key(), "m2");
|
2018-09-14 22:06:12 +00:00
|
|
|
}
|
2018-05-24 19:46:51 +00:00
|
|
|
|
2018-09-22 04:12:37 +00:00
|
|
|
TEST_F(SequentialTest, AccessWithAt) {
|
2018-09-14 22:06:12 +00:00
|
|
|
struct M : torch::nn::Module {
|
|
|
|
|
explicit M(int value_) : value(value_) {}
|
|
|
|
|
int forward() {
|
|
|
|
|
return value;
|
2018-05-24 19:46:51 +00:00
|
|
|
}
|
2018-09-14 22:06:12 +00:00
|
|
|
int value;
|
|
|
|
|
};
|
|
|
|
|
std::vector<std::shared_ptr<M>> modules = {
|
|
|
|
|
std::make_shared<M>(1), std::make_shared<M>(2), std::make_shared<M>(3)};
|
|
|
|
|
|
|
|
|
|
Sequential sequential;
|
|
|
|
|
for (auto& module : modules) {
|
|
|
|
|
sequential->push_back(module);
|
|
|
|
|
}
|
2018-09-22 04:12:37 +00:00
|
|
|
ASSERT_EQ(sequential->size(), 3);
|
2018-05-24 19:46:51 +00:00
|
|
|
|
2018-09-14 22:06:12 +00:00
|
|
|
// returns the correct module for a given index
|
|
|
|
|
for (size_t i = 0; i < modules.size(); ++i) {
|
2018-09-22 04:12:37 +00:00
|
|
|
ASSERT_EQ(&sequential->at<M>(i), modules[i].get());
|
2018-05-24 19:46:51 +00:00
|
|
|
}
|
|
|
|
|
|
2018-09-14 22:06:12 +00:00
|
|
|
// throws for a bad index
|
2018-09-22 04:12:37 +00:00
|
|
|
ASSERT_THROWS_WITH(
|
|
|
|
|
sequential->at<M>(modules.size() + 1), "Index out of range");
|
|
|
|
|
ASSERT_THROWS_WITH(
|
|
|
|
|
sequential->at<M>(modules.size() + 1000000), "Index out of range");
|
2018-09-14 22:06:12 +00:00
|
|
|
}
|
2018-05-24 19:46:51 +00:00
|
|
|
|
2018-09-22 04:12:37 +00:00
|
|
|
TEST_F(SequentialTest, AccessWithPtr) {
|
2018-09-14 22:06:12 +00:00
|
|
|
struct M : torch::nn::Module {
|
|
|
|
|
explicit M(int value_) : value(value_) {}
|
|
|
|
|
int forward() {
|
|
|
|
|
return value;
|
|
|
|
|
}
|
|
|
|
|
int value;
|
|
|
|
|
};
|
|
|
|
|
std::vector<std::shared_ptr<M>> modules = {
|
|
|
|
|
std::make_shared<M>(1), std::make_shared<M>(2), std::make_shared<M>(3)};
|
|
|
|
|
|
|
|
|
|
Sequential sequential;
|
|
|
|
|
for (auto& module : modules) {
|
|
|
|
|
sequential->push_back(module);
|
2018-05-24 19:46:51 +00:00
|
|
|
}
|
2018-09-22 04:12:37 +00:00
|
|
|
ASSERT_EQ(sequential->size(), 3);
|
2018-06-26 20:23:16 +00:00
|
|
|
|
2018-09-14 22:06:12 +00:00
|
|
|
// returns the correct module for a given index
|
|
|
|
|
for (size_t i = 0; i < modules.size(); ++i) {
|
2018-09-22 04:12:37 +00:00
|
|
|
ASSERT_EQ(sequential->ptr(i).get(), modules[i].get());
|
|
|
|
|
ASSERT_EQ(sequential[i].get(), modules[i].get());
|
|
|
|
|
ASSERT_EQ(sequential->ptr<M>(i).get(), modules[i].get());
|
2018-06-26 20:23:16 +00:00
|
|
|
}
|
2018-06-28 13:30:36 +00:00
|
|
|
|
2018-09-14 22:06:12 +00:00
|
|
|
// throws for a bad index
|
2018-09-22 04:12:37 +00:00
|
|
|
ASSERT_THROWS_WITH(sequential->ptr(modules.size() + 1), "Index out of range");
|
|
|
|
|
ASSERT_THROWS_WITH(
|
|
|
|
|
sequential->ptr(modules.size() + 1000000), "Index out of range");
|
2018-09-14 22:06:12 +00:00
|
|
|
}
|
|
|
|
|
|
2018-09-22 04:12:37 +00:00
|
|
|
TEST_F(SequentialTest, CallingForwardOnEmptySequentialIsDisallowed) {
|
2018-09-14 22:06:12 +00:00
|
|
|
Sequential empty;
|
2018-09-22 04:12:37 +00:00
|
|
|
ASSERT_THROWS_WITH(
|
|
|
|
|
empty->forward<int>(), "Cannot call forward() on an empty Sequential");
|
2018-09-14 22:06:12 +00:00
|
|
|
}
|
|
|
|
|
|
2018-09-22 04:12:37 +00:00
|
|
|
TEST_F(SequentialTest, CallingForwardChainsCorrectly) {
|
2018-09-14 22:06:12 +00:00
|
|
|
struct MockModule : torch::nn::Module {
|
|
|
|
|
explicit MockModule(int value) : expected(value) {}
|
|
|
|
|
int expected;
|
|
|
|
|
int forward(int value) {
|
2018-09-22 04:12:37 +00:00
|
|
|
assert(value == expected);
|
2018-09-14 22:06:12 +00:00
|
|
|
return value + 1;
|
2018-07-17 04:43:40 +00:00
|
|
|
}
|
2018-09-14 22:06:12 +00:00
|
|
|
};
|
2018-07-17 04:43:40 +00:00
|
|
|
|
2018-09-14 22:06:12 +00:00
|
|
|
Sequential sequential(MockModule{1}, MockModule{2}, MockModule{3});
|
2018-07-17 04:43:40 +00:00
|
|
|
|
2018-09-22 04:12:37 +00:00
|
|
|
ASSERT_EQ(sequential->forward<int>(1), 4);
|
2018-09-14 22:06:12 +00:00
|
|
|
}
|
2018-08-16 04:09:33 +00:00
|
|
|
|
2018-09-22 04:12:37 +00:00
|
|
|
TEST_F(SequentialTest, CallingForwardWithTheWrongReturnTypeThrows) {
|
2018-09-14 22:06:12 +00:00
|
|
|
struct M : public torch::nn::Module {
|
|
|
|
|
int forward() {
|
|
|
|
|
return 5;
|
2018-07-17 04:43:40 +00:00
|
|
|
}
|
2018-09-14 22:06:12 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Sequential sequential(M{});
|
2018-09-22 04:12:37 +00:00
|
|
|
ASSERT_EQ(sequential->forward<int>(), 5);
|
|
|
|
|
ASSERT_THROWS_WITH(
|
2018-09-14 22:06:12 +00:00
|
|
|
sequential->forward<float>(),
|
2018-09-22 04:12:37 +00:00
|
|
|
"The type of the return value is int, but you asked for type float");
|
2018-09-14 22:06:12 +00:00
|
|
|
}
|
|
|
|
|
|
2018-09-22 04:12:37 +00:00
|
|
|
TEST_F(SequentialTest, TheReturnTypeOfForwardDefaultsToTensor) {
|
2018-09-14 22:06:12 +00:00
|
|
|
struct M : public torch::nn::Module {
|
|
|
|
|
torch::Tensor forward(torch::Tensor v) {
|
|
|
|
|
return v;
|
2018-07-17 04:43:40 +00:00
|
|
|
}
|
2018-09-14 22:06:12 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Sequential sequential(M{});
|
|
|
|
|
auto variable = torch::ones({3, 3}, torch::requires_grad());
|
2018-09-22 04:12:37 +00:00
|
|
|
ASSERT_TRUE(sequential->forward(variable).equal(variable));
|
2018-09-14 22:06:12 +00:00
|
|
|
}
|
|
|
|
|
|
2018-09-22 04:12:37 +00:00
|
|
|
TEST_F(SequentialTest, ForwardReturnsTheLastValue) {
|
2018-09-14 22:06:12 +00:00
|
|
|
torch::manual_seed(0);
|
|
|
|
|
Sequential sequential(Linear(10, 3), Linear(3, 5), Linear(5, 100));
|
|
|
|
|
|
|
|
|
|
auto x = torch::randn({1000, 10}, torch::requires_grad());
|
|
|
|
|
auto y = sequential->forward(x);
|
2018-09-22 04:12:37 +00:00
|
|
|
ASSERT_EQ(y.ndimension(), 2);
|
|
|
|
|
ASSERT_EQ(y.size(0), 1000);
|
|
|
|
|
ASSERT_EQ(y.size(1), 100);
|
2018-09-14 22:06:12 +00:00
|
|
|
}
|
|
|
|
|
|
2018-09-22 04:12:37 +00:00
|
|
|
TEST_F(SequentialTest, SanityCheckForHoldingStandardModules) {
|
2018-09-14 22:06:12 +00:00
|
|
|
Sequential sequential(
|
|
|
|
|
Linear(10, 3),
|
|
|
|
|
Conv2d(1, 2, 3),
|
|
|
|
|
Dropout(0.5),
|
|
|
|
|
BatchNorm(5),
|
|
|
|
|
Embedding(4, 10),
|
|
|
|
|
LSTM(4, 5));
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-22 04:12:37 +00:00
|
|
|
TEST_F(SequentialTest, ExtendPushesModulesFromOtherSequential) {
|
2018-09-14 22:06:12 +00:00
|
|
|
struct A : torch::nn::Module {
|
|
|
|
|
int forward(int x) {
|
|
|
|
|
return x;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
struct B : torch::nn::Module {
|
|
|
|
|
int forward(int x) {
|
|
|
|
|
return x;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
struct C : torch::nn::Module {
|
|
|
|
|
int forward(int x) {
|
|
|
|
|
return x;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
struct D : torch::nn::Module {
|
|
|
|
|
int forward(int x) {
|
|
|
|
|
return x;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
Sequential a(A{}, B{});
|
|
|
|
|
Sequential b(C{}, D{});
|
|
|
|
|
a->extend(*b);
|
|
|
|
|
|
2018-09-22 04:12:37 +00:00
|
|
|
ASSERT_EQ(a->size(), 4);
|
|
|
|
|
ASSERT_TRUE(a[0]->as<A>());
|
|
|
|
|
ASSERT_TRUE(a[1]->as<B>());
|
|
|
|
|
ASSERT_TRUE(a[2]->as<C>());
|
|
|
|
|
ASSERT_TRUE(a[3]->as<D>());
|
2018-09-14 22:06:12 +00:00
|
|
|
|
2018-09-22 04:12:37 +00:00
|
|
|
ASSERT_EQ(b->size(), 2);
|
|
|
|
|
ASSERT_TRUE(b[0]->as<C>());
|
|
|
|
|
ASSERT_TRUE(b[1]->as<D>());
|
2018-09-14 22:06:12 +00:00
|
|
|
|
|
|
|
|
std::vector<std::shared_ptr<A>> c = {std::make_shared<A>(),
|
|
|
|
|
std::make_shared<A>()};
|
|
|
|
|
b->extend(c);
|
|
|
|
|
|
2018-09-22 04:12:37 +00:00
|
|
|
ASSERT_EQ(b->size(), 4);
|
|
|
|
|
ASSERT_TRUE(b[0]->as<C>());
|
|
|
|
|
ASSERT_TRUE(b[1]->as<D>());
|
|
|
|
|
ASSERT_TRUE(b[2]->as<A>());
|
|
|
|
|
ASSERT_TRUE(b[3]->as<A>());
|
2018-09-14 22:06:12 +00:00
|
|
|
}
|
|
|
|
|
|
2018-09-22 04:12:37 +00:00
|
|
|
TEST_F(SequentialTest, HasReferenceSemantics) {
|
2018-09-14 22:06:12 +00:00
|
|
|
Sequential first(Linear(2, 3), Linear(4, 4), Linear(4, 5));
|
|
|
|
|
Sequential second(first);
|
|
|
|
|
|
2018-09-22 04:12:37 +00:00
|
|
|
ASSERT_EQ(first.get(), second.get());
|
|
|
|
|
ASSERT_EQ(first->size(), second->size());
|
|
|
|
|
ASSERT_TRUE(std::equal(
|
2018-09-14 22:06:12 +00:00
|
|
|
first->begin(),
|
|
|
|
|
first->end(),
|
|
|
|
|
second->begin(),
|
|
|
|
|
[](const AnyModule& first, const AnyModule& second) {
|
|
|
|
|
return &first == &second;
|
|
|
|
|
}));
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-22 04:12:37 +00:00
|
|
|
TEST_F(SequentialTest, IsCloneable) {
|
2018-09-14 22:06:12 +00:00
|
|
|
Sequential sequential(Linear(3, 4), Functional(torch::relu), BatchNorm(3));
|
|
|
|
|
Sequential clone =
|
|
|
|
|
std::dynamic_pointer_cast<SequentialImpl>(sequential->clone());
|
2018-09-22 04:12:37 +00:00
|
|
|
ASSERT_EQ(sequential->size(), clone->size());
|
2018-09-14 22:06:12 +00:00
|
|
|
|
|
|
|
|
for (size_t i = 0; i < sequential->size(); ++i) {
|
|
|
|
|
// The modules should be the same kind (type).
|
2018-09-22 04:12:37 +00:00
|
|
|
ASSERT_EQ(sequential[i]->name(), clone[i]->name());
|
2018-09-14 22:06:12 +00:00
|
|
|
// But not pointer-equal (distinct objects).
|
2018-09-22 04:12:37 +00:00
|
|
|
ASSERT_NE(sequential[i], clone[i]);
|
2018-07-17 04:43:40 +00:00
|
|
|
}
|
2018-09-14 22:06:12 +00:00
|
|
|
|
|
|
|
|
// Verify that the clone is deep, i.e. parameters of modules are cloned too.
|
|
|
|
|
|
|
|
|
|
torch::NoGradGuard no_grad;
|
|
|
|
|
|
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 params1 = sequential->named_parameters();
|
|
|
|
|
auto params2 = clone->named_parameters();
|
2018-09-22 04:12:37 +00:00
|
|
|
ASSERT_EQ(params1.size(), params2.size());
|
2018-09-14 22:06:12 +00:00
|
|
|
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_EQ(param->device(), params2[param.key()].device());
|
|
|
|
|
ASSERT_TRUE(param->allclose(params2[param.key()]));
|
2018-09-14 22:06:12 +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-14 22:06:12 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-22 04:12:37 +00:00
|
|
|
TEST_F(SequentialTest, RegistersElementsAsSubmodules) {
|
2019-11-16 04:28:58 +00:00
|
|
|
Sequential sequential(Linear(10, 3), Conv2d(1, 2, 3), Dropout2d(0.5));
|
2018-09-14 22:06:12 +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
|
|
|
auto modules = sequential->children();
|
2018-09-22 04:12:37 +00:00
|
|
|
ASSERT_TRUE(modules[0]->as<Linear>());
|
|
|
|
|
ASSERT_TRUE(modules[1]->as<Conv2d>());
|
2019-11-16 04:28:58 +00:00
|
|
|
ASSERT_TRUE(modules[2]->as<Dropout2d>());
|
2018-05-24 19:46:51 +00:00
|
|
|
}
|
2018-07-23 21:49:18 +00:00
|
|
|
|
2018-09-22 04:12:37 +00:00
|
|
|
TEST_F(SequentialTest, CloneToDevice_CUDA) {
|
2018-07-23 21:49:18 +00:00
|
|
|
Sequential sequential(Linear(3, 4), Functional(torch::relu), BatchNorm(3));
|
|
|
|
|
torch::Device device(torch::kCUDA, 0);
|
|
|
|
|
Sequential clone =
|
2018-08-13 17:11:45 +00:00
|
|
|
std::dynamic_pointer_cast<SequentialImpl>(sequential->clone(device));
|
2018-07-23 21:49:18 +00:00
|
|
|
for (const auto& p : 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(p.device(), device);
|
2018-07-23 21:49:18 +00:00
|
|
|
}
|
|
|
|
|
for (const auto& b : 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(b.device(), device);
|
2018-07-23 21:49:18 +00:00
|
|
|
}
|
|
|
|
|
}
|
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
|
|
|
|
|
|
|
|
TEST_F(SequentialTest, PrettyPrintSequential) {
|
|
|
|
|
Sequential sequential(
|
|
|
|
|
Linear(10, 3),
|
|
|
|
|
Conv2d(1, 2, 3),
|
|
|
|
|
Dropout(0.5),
|
|
|
|
|
BatchNorm(5),
|
|
|
|
|
Embedding(4, 10),
|
|
|
|
|
LSTM(4, 5));
|
|
|
|
|
ASSERT_EQ(
|
|
|
|
|
c10::str(sequential),
|
|
|
|
|
"torch::nn::Sequential(\n"
|
2019-10-24 14:09:33 +00:00
|
|
|
" (0): torch::nn::Linear(in_features=10, out_features=3, bias=true)\n"
|
C++/Python API parity for Conv{1,2,3}d layers, and add F::conv{1,2,3}d functionals (#28917)
Summary:
This PR changes the implementation of C++ Conv{1,2,3}d layers to exactly match the Python version, and add F::conv{1,2,3}d functionals. For more thorough testing, I will rely on the parity test mechanism which uses values from `common_nn.py` to generate the inputs and options that we are interested in testing.
This PR is BC-breaking in the following way:
In `Conv{1,2,3}dOptions`:
- `with_bias` is renamed to `bias`.
- `input_channels` is renamed to `in_channels`.
- `output_channels` is renamed to `out_channels`.
Pull Request resolved: https://github.com/pytorch/pytorch/pull/28917
Differential Revision: D18471526
Pulled By: yf225
fbshipit-source-id: 7a33f60654ad93cc2e043245e7ff9e0ef9da15b3
2019-11-13 20:51:25 +00:00
|
|
|
" (1): torch::nn::Conv2d(1, 2, kernel_size=[3, 3], stride=[1, 1])\n"
|
2019-11-16 04:28:58 +00:00
|
|
|
" (2): torch::nn::Dropout(p=0.5, inplace=false)\n"
|
C++ API: torch::nn::BatchNorm1d (#28176)
Summary:
Add torch::nn::BatchNorm1d function/module support for the C++ API.
torch::nn::BatchNorm{2,3}d will be added after this PR is merged.
Related Issue: https://github.com/pytorch/pytorch/issues/25883
Reviewer: yf225
I would like to discuss about below items.
* Necessity of `num_batches_tracked` in `BatchNormImplBase`
* `num_batches_tracked` is needed to calculate `momentum` when we do not feed `momentum` argument in Python API. But in C++ API, `momentum` argument has a default value.
* `num_batches_tracked` is only used for counting up `BatchNorm1d::foward()` call. I think it is no necessary for user anymore.
* The design of `BatchNorm{1,2,3}dOptions`
* We have already `BatchNormOptions` used for deprecated `BatchNorm` module. However, it is hard to use it for `BatchNorm{1,2,3}dOptions` because of the arguments disagreement of each modules.
* In this PR, I introduce `BatchNormOptionsv2` template class for the `BatchNorm{1,2,3}dOptions`. But I'm not sure this design is good or not.
Pull Request resolved: https://github.com/pytorch/pytorch/pull/28176
Differential Revision: D18196843
Pulled By: yf225
fbshipit-source-id: 667e2b5de4150d5776c41b9088c9e6c2ead24cd4
2019-10-30 00:25:56 +00:00
|
|
|
" (3): torch::nn::BatchNorm(num_features=5, eps=1e-05, momentum=0.1, affine=true, track_running_stats=true)\n"
|
2019-10-09 05:12:15 +00:00
|
|
|
" (4): torch::nn::Embedding(num_embeddings=4, embedding_dim=10)\n"
|
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
|
|
|
" (5): torch::nn::LSTM(input_size=4, hidden_size=5, layers=1, dropout=0)\n"
|
|
|
|
|
")");
|
Add named submodule support to nn::Sequential (#17552)
Summary:
Previously, we were not able to assign names to `nn::Sequential`'s submodules. This PR adds this feature to match the Python API. Example use:
```cpp
Sequential sequential(named_submodule({
{"linear", Linear(10, 3)},
{"conv2d", Conv2d(1, 2, 3)},
{"dropout", Dropout(0.5)},
{"batchnorm", BatchNorm(5)},
{"embedding", Embedding(4, 10)},
{"lstm", LSTM(4, 5)}
}));
```
It also enables loading parameters of Python `nn.Sequential` module with custom submodules names into C++ frontend, unblocking https://github.com/pytorch/vision/pull/728#issuecomment-466661344.
Pull Request resolved: https://github.com/pytorch/pytorch/pull/17552
Differential Revision: D14246834
Pulled By: yf225
fbshipit-source-id: 3030b5c5d68f6dd5d3e37ac4b4f98dc6d6d9ba72
2019-03-29 19:59:29 +00:00
|
|
|
|
2019-10-28 19:59:27 +00:00
|
|
|
Sequential sequential_named({
|
Add named submodule support to nn::Sequential (#17552)
Summary:
Previously, we were not able to assign names to `nn::Sequential`'s submodules. This PR adds this feature to match the Python API. Example use:
```cpp
Sequential sequential(named_submodule({
{"linear", Linear(10, 3)},
{"conv2d", Conv2d(1, 2, 3)},
{"dropout", Dropout(0.5)},
{"batchnorm", BatchNorm(5)},
{"embedding", Embedding(4, 10)},
{"lstm", LSTM(4, 5)}
}));
```
It also enables loading parameters of Python `nn.Sequential` module with custom submodules names into C++ frontend, unblocking https://github.com/pytorch/vision/pull/728#issuecomment-466661344.
Pull Request resolved: https://github.com/pytorch/pytorch/pull/17552
Differential Revision: D14246834
Pulled By: yf225
fbshipit-source-id: 3030b5c5d68f6dd5d3e37ac4b4f98dc6d6d9ba72
2019-03-29 19:59:29 +00:00
|
|
|
{"linear", Linear(10, 3)},
|
|
|
|
|
{"conv2d", Conv2d(1, 2, 3)},
|
|
|
|
|
{"dropout", Dropout(0.5)},
|
|
|
|
|
{"batchnorm", BatchNorm(5)},
|
|
|
|
|
{"embedding", Embedding(4, 10)},
|
|
|
|
|
{"lstm", LSTM(4, 5)}
|
2019-10-28 19:59:27 +00:00
|
|
|
});
|
Add named submodule support to nn::Sequential (#17552)
Summary:
Previously, we were not able to assign names to `nn::Sequential`'s submodules. This PR adds this feature to match the Python API. Example use:
```cpp
Sequential sequential(named_submodule({
{"linear", Linear(10, 3)},
{"conv2d", Conv2d(1, 2, 3)},
{"dropout", Dropout(0.5)},
{"batchnorm", BatchNorm(5)},
{"embedding", Embedding(4, 10)},
{"lstm", LSTM(4, 5)}
}));
```
It also enables loading parameters of Python `nn.Sequential` module with custom submodules names into C++ frontend, unblocking https://github.com/pytorch/vision/pull/728#issuecomment-466661344.
Pull Request resolved: https://github.com/pytorch/pytorch/pull/17552
Differential Revision: D14246834
Pulled By: yf225
fbshipit-source-id: 3030b5c5d68f6dd5d3e37ac4b4f98dc6d6d9ba72
2019-03-29 19:59:29 +00:00
|
|
|
ASSERT_EQ(
|
|
|
|
|
c10::str(sequential_named),
|
|
|
|
|
"torch::nn::Sequential(\n"
|
2019-10-24 14:09:33 +00:00
|
|
|
" (linear): torch::nn::Linear(in_features=10, out_features=3, bias=true)\n"
|
C++/Python API parity for Conv{1,2,3}d layers, and add F::conv{1,2,3}d functionals (#28917)
Summary:
This PR changes the implementation of C++ Conv{1,2,3}d layers to exactly match the Python version, and add F::conv{1,2,3}d functionals. For more thorough testing, I will rely on the parity test mechanism which uses values from `common_nn.py` to generate the inputs and options that we are interested in testing.
This PR is BC-breaking in the following way:
In `Conv{1,2,3}dOptions`:
- `with_bias` is renamed to `bias`.
- `input_channels` is renamed to `in_channels`.
- `output_channels` is renamed to `out_channels`.
Pull Request resolved: https://github.com/pytorch/pytorch/pull/28917
Differential Revision: D18471526
Pulled By: yf225
fbshipit-source-id: 7a33f60654ad93cc2e043245e7ff9e0ef9da15b3
2019-11-13 20:51:25 +00:00
|
|
|
" (conv2d): torch::nn::Conv2d(1, 2, kernel_size=[3, 3], stride=[1, 1])\n"
|
2019-11-16 04:28:58 +00:00
|
|
|
" (dropout): torch::nn::Dropout(p=0.5, inplace=false)\n"
|
C++ API: torch::nn::BatchNorm1d (#28176)
Summary:
Add torch::nn::BatchNorm1d function/module support for the C++ API.
torch::nn::BatchNorm{2,3}d will be added after this PR is merged.
Related Issue: https://github.com/pytorch/pytorch/issues/25883
Reviewer: yf225
I would like to discuss about below items.
* Necessity of `num_batches_tracked` in `BatchNormImplBase`
* `num_batches_tracked` is needed to calculate `momentum` when we do not feed `momentum` argument in Python API. But in C++ API, `momentum` argument has a default value.
* `num_batches_tracked` is only used for counting up `BatchNorm1d::foward()` call. I think it is no necessary for user anymore.
* The design of `BatchNorm{1,2,3}dOptions`
* We have already `BatchNormOptions` used for deprecated `BatchNorm` module. However, it is hard to use it for `BatchNorm{1,2,3}dOptions` because of the arguments disagreement of each modules.
* In this PR, I introduce `BatchNormOptionsv2` template class for the `BatchNorm{1,2,3}dOptions`. But I'm not sure this design is good or not.
Pull Request resolved: https://github.com/pytorch/pytorch/pull/28176
Differential Revision: D18196843
Pulled By: yf225
fbshipit-source-id: 667e2b5de4150d5776c41b9088c9e6c2ead24cd4
2019-10-30 00:25:56 +00:00
|
|
|
" (batchnorm): torch::nn::BatchNorm(num_features=5, eps=1e-05, momentum=0.1, affine=true, track_running_stats=true)\n"
|
2019-10-09 05:12:15 +00:00
|
|
|
" (embedding): torch::nn::Embedding(num_embeddings=4, embedding_dim=10)\n"
|
Add named submodule support to nn::Sequential (#17552)
Summary:
Previously, we were not able to assign names to `nn::Sequential`'s submodules. This PR adds this feature to match the Python API. Example use:
```cpp
Sequential sequential(named_submodule({
{"linear", Linear(10, 3)},
{"conv2d", Conv2d(1, 2, 3)},
{"dropout", Dropout(0.5)},
{"batchnorm", BatchNorm(5)},
{"embedding", Embedding(4, 10)},
{"lstm", LSTM(4, 5)}
}));
```
It also enables loading parameters of Python `nn.Sequential` module with custom submodules names into C++ frontend, unblocking https://github.com/pytorch/vision/pull/728#issuecomment-466661344.
Pull Request resolved: https://github.com/pytorch/pytorch/pull/17552
Differential Revision: D14246834
Pulled By: yf225
fbshipit-source-id: 3030b5c5d68f6dd5d3e37ac4b4f98dc6d6d9ba72
2019-03-29 19:59:29 +00:00
|
|
|
" (lstm): torch::nn::LSTM(input_size=4, hidden_size=5, layers=1, dropout=0)\n"
|
|
|
|
|
")");
|
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
|
|
|
}
|