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 <gtest/gtest.h>
|
|
|
|
|
|
|
|
|
|
#include <torch/torch.h>
|
|
|
|
|
|
|
|
|
|
#include <test/cpp/api/support.h>
|
|
|
|
|
|
|
|
|
|
namespace F = torch::nn::functional;
|
|
|
|
|
|
|
|
|
|
using namespace torch::nn;
|
|
|
|
|
|
|
|
|
|
struct FunctionalTest : torch::test::SeedingFixture {};
|
|
|
|
|
|
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
|
|
|
TEST_F(FunctionalTest, Conv1d) {
|
|
|
|
|
auto x = torch::arange(30, torch::dtype(torch::kFloat).requires_grad(true)).reshape({2, 3, 5});
|
|
|
|
|
auto weight = torch::arange(18, torch::dtype(torch::kFloat).requires_grad(true)).reshape({2, 3, 3});
|
|
|
|
|
auto y = F::conv1d(x, weight, F::Conv1dFuncOptions().stride(1));
|
|
|
|
|
auto expected = torch::tensor({{{ 312., 348., 384.},
|
|
|
|
|
{ 798., 915., 1032.}},
|
|
|
|
|
|
|
|
|
|
{{ 852., 888., 924.},
|
|
|
|
|
{2553., 2670., 2787.}}}, torch::kFloat);
|
|
|
|
|
ASSERT_TRUE(torch::allclose(y, expected));
|
|
|
|
|
|
|
|
|
|
auto y_no_options = F::conv1d(x, weight);
|
|
|
|
|
ASSERT_TRUE(torch::allclose(y_no_options, expected));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(FunctionalTest, Conv2dEven) {
|
|
|
|
|
auto x = torch::arange(75, torch::dtype(torch::kFloat).requires_grad(true)).reshape({1, 3, 5, 5});
|
|
|
|
|
auto weight = torch::arange(54, torch::dtype(torch::kFloat).requires_grad(true)).reshape({2, 3, 3, 3});
|
|
|
|
|
auto y = F::conv2d(x, weight, F::Conv2dFuncOptions().stride(1));
|
|
|
|
|
auto expected = torch::tensor({{{{15219., 15570., 15921.},
|
|
|
|
|
{16974., 17325., 17676.},
|
|
|
|
|
{18729., 19080., 19431.}},
|
|
|
|
|
|
|
|
|
|
{{37818., 38898., 39978.},
|
|
|
|
|
{43218., 44298., 45378.},
|
|
|
|
|
{48618., 49698., 50778.}}}}, torch::kFloat);
|
|
|
|
|
ASSERT_TRUE(torch::allclose(y, expected));
|
|
|
|
|
|
|
|
|
|
auto y_no_options = F::conv2d(x, weight);
|
|
|
|
|
ASSERT_TRUE(torch::allclose(y_no_options, expected));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(FunctionalTest, Conv2dUneven) {
|
|
|
|
|
auto x = torch::arange(60, torch::dtype(torch::kFloat).requires_grad(true)).reshape({1, 3, 5, 4});
|
|
|
|
|
auto weight = torch::arange(36, torch::dtype(torch::kFloat).requires_grad(true)).reshape({2, 3, 3, 2});
|
|
|
|
|
auto y = F::conv2d(x, weight, F::Conv2dFuncOptions().stride(1));
|
|
|
|
|
auto expected = torch::tensor({{{{ 5289., 5442., 5595.},
|
|
|
|
|
{ 5901., 6054., 6207.},
|
|
|
|
|
{ 6513., 6666., 6819.}},
|
|
|
|
|
|
|
|
|
|
{{13227., 13704., 14181.},
|
|
|
|
|
{15135., 15612., 16089.},
|
|
|
|
|
{17043., 17520., 17997.}}}}, torch::kFloat);
|
|
|
|
|
ASSERT_TRUE(torch::allclose(y, expected));
|
|
|
|
|
|
|
|
|
|
auto y_no_options = F::conv2d(x, weight);
|
|
|
|
|
ASSERT_TRUE(torch::allclose(y_no_options, expected));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(FunctionalTest, Conv3d) {
|
|
|
|
|
auto x = torch::arange(375, torch::dtype(torch::kFloat).requires_grad(true)).reshape({1, 3, 5, 5, 5});
|
|
|
|
|
auto weight = torch::arange(162, torch::dtype(torch::kFloat).requires_grad(true)).reshape({2, 3, 3, 3, 3});
|
|
|
|
|
auto y = F::conv3d(x, weight, F::Conv3dFuncOptions().stride(1));
|
|
|
|
|
auto expected = torch::tensor({{{{{ 700704., 703944., 707184.},
|
|
|
|
|
{ 716904., 720144., 723384.},
|
|
|
|
|
{ 733104., 736344., 739584.}},
|
|
|
|
|
|
|
|
|
|
{{ 781704., 784944., 788184.},
|
|
|
|
|
{ 797904., 801144., 804384.},
|
|
|
|
|
{ 814104., 817344., 820584.}},
|
|
|
|
|
|
|
|
|
|
{{ 862704., 865944., 869184.},
|
|
|
|
|
{ 878904., 882144., 885384.},
|
|
|
|
|
{ 895104., 898344., 901584.}}},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{{{1724220., 1734021., 1743822.},
|
|
|
|
|
{1773225., 1783026., 1792827.},
|
|
|
|
|
{1822230., 1832031., 1841832.}},
|
|
|
|
|
|
|
|
|
|
{{1969245., 1979046., 1988847.},
|
|
|
|
|
{2018250., 2028051., 2037852.},
|
|
|
|
|
{2067255., 2077056., 2086857.}},
|
|
|
|
|
|
|
|
|
|
{{2214270., 2224071., 2233872.},
|
|
|
|
|
{2263275., 2273076., 2282877.},
|
|
|
|
|
{2312280., 2322081., 2331882.}}}}}, torch::kFloat);
|
|
|
|
|
ASSERT_TRUE(torch::allclose(y, expected));
|
|
|
|
|
|
|
|
|
|
auto y_no_options = F::conv3d(x, weight);
|
|
|
|
|
ASSERT_TRUE(torch::allclose(y_no_options, expected));
|
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
TEST_F(FunctionalTest, MaxPool1d) {
|
2019-09-24 16:08:55 +00:00
|
|
|
auto x = torch::ones({1, 1, 5});
|
Pass F::*FuncOptions instead of torch::nn::*Options to functionals, and make F::*FuncOptions a different class when necessary (#29364)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/29364
Currently, we use `torch::nn::*Options` both as module options and functional options. However, this makes it very hard to manage the parameters in `torch::nn::*Options`, because a module's constructor can take a different set of arguments than the module's equivalent functional (e.g. `torch.nn.BatchNorm1d` takes `num_features, eps=1e-5, momentum=0.1, affine=True,
track_running_stats=True`, while `F::batch_norm` takes `running_mean, running_var, weight=None, bias=None, training=False, momentum=0.1, eps=1e-5`).
This PR resolves the above problem by making `F::*FuncOptions` a different class from `torch::nn::*Options` when necessary (i.e. when a module's constructor takes a different set of arguments than the module's equivalent functional). In the rest of the cases where the module constructor takes the same set of arguments as the module's equivalent functional, `F::*FuncOptions` is an alias of `torch::nn::*Options`.
Also as part of this PR, we change all functional options to pass-by-value, to make the semantics consistent across all functionals.
Test Plan: Imported from OSS
Differential Revision: D18376977
Pulled By: yf225
fbshipit-source-id: 8d9c240d93bfd5af0165b6884fdc912476b1d06b
2019-11-09 06:36:49 +00:00
|
|
|
auto y = F::max_pool1d(x, F::MaxPool1dFuncOptions(3).stride(2));
|
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
|
|
|
|
|
|
|
|
ASSERT_EQ(y.ndimension(), 3);
|
2019-10-03 00:26:27 +00:00
|
|
|
ASSERT_TRUE(torch::allclose(y, torch::ones({1, 1, 2})));
|
2019-10-15 00:58:14 +00:00
|
|
|
ASSERT_EQ(y.sizes(), std::vector<int64_t>({1, 1, 2}));
|
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
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(FunctionalTest, MaxPool2d) {
|
2019-09-24 16:08:55 +00:00
|
|
|
auto x = torch::ones({2, 5, 5});
|
Pass F::*FuncOptions instead of torch::nn::*Options to functionals, and make F::*FuncOptions a different class when necessary (#29364)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/29364
Currently, we use `torch::nn::*Options` both as module options and functional options. However, this makes it very hard to manage the parameters in `torch::nn::*Options`, because a module's constructor can take a different set of arguments than the module's equivalent functional (e.g. `torch.nn.BatchNorm1d` takes `num_features, eps=1e-5, momentum=0.1, affine=True,
track_running_stats=True`, while `F::batch_norm` takes `running_mean, running_var, weight=None, bias=None, training=False, momentum=0.1, eps=1e-5`).
This PR resolves the above problem by making `F::*FuncOptions` a different class from `torch::nn::*Options` when necessary (i.e. when a module's constructor takes a different set of arguments than the module's equivalent functional). In the rest of the cases where the module constructor takes the same set of arguments as the module's equivalent functional, `F::*FuncOptions` is an alias of `torch::nn::*Options`.
Also as part of this PR, we change all functional options to pass-by-value, to make the semantics consistent across all functionals.
Test Plan: Imported from OSS
Differential Revision: D18376977
Pulled By: yf225
fbshipit-source-id: 8d9c240d93bfd5af0165b6884fdc912476b1d06b
2019-11-09 06:36:49 +00:00
|
|
|
auto y = F::max_pool2d(x, F::MaxPool2dFuncOptions(3).stride(2));
|
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
|
|
|
|
|
|
|
|
ASSERT_EQ(y.ndimension(), 3);
|
2019-10-03 00:26:27 +00:00
|
|
|
ASSERT_TRUE(torch::allclose(y, torch::ones({2, 2, 2})));
|
2019-10-15 00:58:14 +00:00
|
|
|
ASSERT_EQ(y.sizes(), std::vector<int64_t>({2, 2, 2}));
|
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
|
|
|
}
|
|
|
|
|
|
2020-04-04 05:45:23 +00:00
|
|
|
TEST_F(FunctionalTest, MaxPool2dBackward) {
|
|
|
|
|
auto input = torch::rand({1, 2, 4, 4}, torch::dtype(torch::kFloat).requires_grad(true));
|
|
|
|
|
auto output = F::max_pool2d(input, F::MaxPool2dFuncOptions(2));
|
|
|
|
|
auto s = output.sum();
|
|
|
|
|
s.backward();
|
|
|
|
|
ASSERT_TRUE(input.sizes() == input.grad().sizes());
|
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
TEST_F(FunctionalTest, MaxPool3d) {
|
2019-09-24 16:08:55 +00:00
|
|
|
auto x = torch::ones({2, 5, 5, 5});
|
Pass F::*FuncOptions instead of torch::nn::*Options to functionals, and make F::*FuncOptions a different class when necessary (#29364)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/29364
Currently, we use `torch::nn::*Options` both as module options and functional options. However, this makes it very hard to manage the parameters in `torch::nn::*Options`, because a module's constructor can take a different set of arguments than the module's equivalent functional (e.g. `torch.nn.BatchNorm1d` takes `num_features, eps=1e-5, momentum=0.1, affine=True,
track_running_stats=True`, while `F::batch_norm` takes `running_mean, running_var, weight=None, bias=None, training=False, momentum=0.1, eps=1e-5`).
This PR resolves the above problem by making `F::*FuncOptions` a different class from `torch::nn::*Options` when necessary (i.e. when a module's constructor takes a different set of arguments than the module's equivalent functional). In the rest of the cases where the module constructor takes the same set of arguments as the module's equivalent functional, `F::*FuncOptions` is an alias of `torch::nn::*Options`.
Also as part of this PR, we change all functional options to pass-by-value, to make the semantics consistent across all functionals.
Test Plan: Imported from OSS
Differential Revision: D18376977
Pulled By: yf225
fbshipit-source-id: 8d9c240d93bfd5af0165b6884fdc912476b1d06b
2019-11-09 06:36:49 +00:00
|
|
|
auto y = F::max_pool3d(x, F::MaxPool3dFuncOptions(3).stride(2));
|
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
|
|
|
|
|
|
|
|
ASSERT_EQ(y.ndimension(), 4);
|
|
|
|
|
ASSERT_TRUE(torch::allclose(y, torch::ones({2, 2, 2, 2})));
|
2019-10-15 00:58:14 +00:00
|
|
|
ASSERT_EQ(y.sizes(), std::vector<int64_t>({2, 2, 2, 2}));
|
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
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(FunctionalTest, AvgPool1d) {
|
2019-09-24 16:08:55 +00:00
|
|
|
auto x = torch::ones({1, 1, 5});
|
Pass F::*FuncOptions instead of torch::nn::*Options to functionals, and make F::*FuncOptions a different class when necessary (#29364)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/29364
Currently, we use `torch::nn::*Options` both as module options and functional options. However, this makes it very hard to manage the parameters in `torch::nn::*Options`, because a module's constructor can take a different set of arguments than the module's equivalent functional (e.g. `torch.nn.BatchNorm1d` takes `num_features, eps=1e-5, momentum=0.1, affine=True,
track_running_stats=True`, while `F::batch_norm` takes `running_mean, running_var, weight=None, bias=None, training=False, momentum=0.1, eps=1e-5`).
This PR resolves the above problem by making `F::*FuncOptions` a different class from `torch::nn::*Options` when necessary (i.e. when a module's constructor takes a different set of arguments than the module's equivalent functional). In the rest of the cases where the module constructor takes the same set of arguments as the module's equivalent functional, `F::*FuncOptions` is an alias of `torch::nn::*Options`.
Also as part of this PR, we change all functional options to pass-by-value, to make the semantics consistent across all functionals.
Test Plan: Imported from OSS
Differential Revision: D18376977
Pulled By: yf225
fbshipit-source-id: 8d9c240d93bfd5af0165b6884fdc912476b1d06b
2019-11-09 06:36:49 +00:00
|
|
|
auto y = F::avg_pool1d(x, F::AvgPool1dFuncOptions(3).stride(2));
|
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
|
|
|
|
|
|
|
|
ASSERT_EQ(y.ndimension(), 3);
|
|
|
|
|
ASSERT_TRUE(torch::allclose(y, torch::ones({1, 1, 2})));
|
2019-10-15 00:58:14 +00:00
|
|
|
ASSERT_EQ(y.sizes(), std::vector<int64_t>({1, 1, 2}));
|
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
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(FunctionalTest, AvgPool2d) {
|
2019-09-24 16:08:55 +00:00
|
|
|
auto x = torch::ones({2, 5, 5});
|
Pass F::*FuncOptions instead of torch::nn::*Options to functionals, and make F::*FuncOptions a different class when necessary (#29364)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/29364
Currently, we use `torch::nn::*Options` both as module options and functional options. However, this makes it very hard to manage the parameters in `torch::nn::*Options`, because a module's constructor can take a different set of arguments than the module's equivalent functional (e.g. `torch.nn.BatchNorm1d` takes `num_features, eps=1e-5, momentum=0.1, affine=True,
track_running_stats=True`, while `F::batch_norm` takes `running_mean, running_var, weight=None, bias=None, training=False, momentum=0.1, eps=1e-5`).
This PR resolves the above problem by making `F::*FuncOptions` a different class from `torch::nn::*Options` when necessary (i.e. when a module's constructor takes a different set of arguments than the module's equivalent functional). In the rest of the cases where the module constructor takes the same set of arguments as the module's equivalent functional, `F::*FuncOptions` is an alias of `torch::nn::*Options`.
Also as part of this PR, we change all functional options to pass-by-value, to make the semantics consistent across all functionals.
Test Plan: Imported from OSS
Differential Revision: D18376977
Pulled By: yf225
fbshipit-source-id: 8d9c240d93bfd5af0165b6884fdc912476b1d06b
2019-11-09 06:36:49 +00:00
|
|
|
auto y = F::avg_pool2d(x, F::AvgPool2dFuncOptions(3).stride(2));
|
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
|
|
|
|
|
|
|
|
ASSERT_EQ(y.ndimension(), 3);
|
|
|
|
|
ASSERT_TRUE(torch::allclose(y, torch::ones({2, 2, 2})));
|
2019-10-15 00:58:14 +00:00
|
|
|
ASSERT_EQ(y.sizes(), std::vector<int64_t>({2, 2, 2}));
|
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
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(FunctionalTest, AvgPool3d) {
|
2019-09-24 16:08:55 +00:00
|
|
|
auto x = torch::ones({2, 5, 5, 5});
|
Pass F::*FuncOptions instead of torch::nn::*Options to functionals, and make F::*FuncOptions a different class when necessary (#29364)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/29364
Currently, we use `torch::nn::*Options` both as module options and functional options. However, this makes it very hard to manage the parameters in `torch::nn::*Options`, because a module's constructor can take a different set of arguments than the module's equivalent functional (e.g. `torch.nn.BatchNorm1d` takes `num_features, eps=1e-5, momentum=0.1, affine=True,
track_running_stats=True`, while `F::batch_norm` takes `running_mean, running_var, weight=None, bias=None, training=False, momentum=0.1, eps=1e-5`).
This PR resolves the above problem by making `F::*FuncOptions` a different class from `torch::nn::*Options` when necessary (i.e. when a module's constructor takes a different set of arguments than the module's equivalent functional). In the rest of the cases where the module constructor takes the same set of arguments as the module's equivalent functional, `F::*FuncOptions` is an alias of `torch::nn::*Options`.
Also as part of this PR, we change all functional options to pass-by-value, to make the semantics consistent across all functionals.
Test Plan: Imported from OSS
Differential Revision: D18376977
Pulled By: yf225
fbshipit-source-id: 8d9c240d93bfd5af0165b6884fdc912476b1d06b
2019-11-09 06:36:49 +00:00
|
|
|
auto y = F::avg_pool3d(x, F::AvgPool3dFuncOptions(3).stride(2));
|
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
|
|
|
|
|
|
|
|
ASSERT_EQ(y.ndimension(), 4);
|
|
|
|
|
ASSERT_TRUE(torch::allclose(y, torch::ones({2, 2, 2, 2})));
|
2019-10-15 00:58:14 +00:00
|
|
|
ASSERT_EQ(y.sizes(), std::vector<int64_t>({2, 2, 2, 2}));
|
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
|
|
|
}
|
2019-09-24 16:08:55 +00:00
|
|
|
|
2019-11-20 01:21:34 +00:00
|
|
|
TEST_F(FunctionalTest, FractionalMaxPool2d) {
|
|
|
|
|
auto x = torch::ones({2, 5, 5});
|
|
|
|
|
auto y = F::fractional_max_pool2d(x, F::FractionalMaxPool2dFuncOptions(3).output_size(2));
|
|
|
|
|
|
|
|
|
|
ASSERT_EQ(y.ndimension(), 3);
|
|
|
|
|
ASSERT_TRUE(torch::allclose(y, torch::ones({2, 2, 2})));
|
|
|
|
|
ASSERT_EQ(y.sizes(), std::vector<int64_t>({2, 2, 2}));
|
|
|
|
|
|
|
|
|
|
auto y_with_indices = F::fractional_max_pool2d_with_indices(x, F::FractionalMaxPool2dFuncOptions(3).output_size(2));
|
|
|
|
|
ASSERT_TRUE(torch::equal(y, std::get<0>(y_with_indices)));
|
|
|
|
|
ASSERT_TRUE(torch::allclose(
|
|
|
|
|
std::get<1>(y_with_indices),
|
|
|
|
|
torch::tensor({{{ 0, 2},
|
|
|
|
|
{10, 12}},
|
|
|
|
|
{{ 0, 2},
|
|
|
|
|
{10, 12}}})));
|
|
|
|
|
ASSERT_EQ(std::get<1>(y_with_indices).sizes(), std::vector<int64_t>({2, 2, 2}));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(FunctionalTest, FractionalMaxPool3d) {
|
|
|
|
|
auto x = torch::ones({2, 5, 5, 5});
|
|
|
|
|
auto y = F::fractional_max_pool3d(x, F::FractionalMaxPool3dFuncOptions(3).output_size(2));
|
|
|
|
|
|
|
|
|
|
ASSERT_EQ(y.ndimension(), 4);
|
|
|
|
|
ASSERT_TRUE(torch::allclose(y, torch::ones({2, 2, 2, 2})));
|
|
|
|
|
ASSERT_EQ(y.sizes(), std::vector<int64_t>({2, 2, 2, 2}));
|
|
|
|
|
|
|
|
|
|
auto y_with_indices = F::fractional_max_pool3d_with_indices(x, F::FractionalMaxPool3dFuncOptions(3).output_size(2));
|
|
|
|
|
ASSERT_TRUE(torch::equal(y, std::get<0>(y_with_indices)));
|
|
|
|
|
ASSERT_TRUE(torch::allclose(
|
|
|
|
|
std::get<1>(y_with_indices),
|
|
|
|
|
torch::tensor({{{{ 0, 2},
|
|
|
|
|
{10, 12}},
|
|
|
|
|
{{50, 52},
|
|
|
|
|
{60, 62}}},
|
|
|
|
|
{{{ 0, 2},
|
|
|
|
|
{10, 12}},
|
|
|
|
|
{{50, 52},
|
|
|
|
|
{60, 62}}}})));
|
|
|
|
|
ASSERT_EQ(std::get<1>(y_with_indices).sizes(), std::vector<int64_t>({2, 2, 2, 2}));
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-21 22:32:10 +00:00
|
|
|
TEST_F(FunctionalTest, LPPool1d) {
|
|
|
|
|
int norm_type = 2;
|
|
|
|
|
int stride = 2;
|
|
|
|
|
int kernel_size = 3;
|
|
|
|
|
|
|
|
|
|
auto x = torch::ones({1, 1, 5});
|
Pass F::*FuncOptions instead of torch::nn::*Options to functionals, and make F::*FuncOptions a different class when necessary (#29364)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/29364
Currently, we use `torch::nn::*Options` both as module options and functional options. However, this makes it very hard to manage the parameters in `torch::nn::*Options`, because a module's constructor can take a different set of arguments than the module's equivalent functional (e.g. `torch.nn.BatchNorm1d` takes `num_features, eps=1e-5, momentum=0.1, affine=True,
track_running_stats=True`, while `F::batch_norm` takes `running_mean, running_var, weight=None, bias=None, training=False, momentum=0.1, eps=1e-5`).
This PR resolves the above problem by making `F::*FuncOptions` a different class from `torch::nn::*Options` when necessary (i.e. when a module's constructor takes a different set of arguments than the module's equivalent functional). In the rest of the cases where the module constructor takes the same set of arguments as the module's equivalent functional, `F::*FuncOptions` is an alias of `torch::nn::*Options`.
Also as part of this PR, we change all functional options to pass-by-value, to make the semantics consistent across all functionals.
Test Plan: Imported from OSS
Differential Revision: D18376977
Pulled By: yf225
fbshipit-source-id: 8d9c240d93bfd5af0165b6884fdc912476b1d06b
2019-11-09 06:36:49 +00:00
|
|
|
auto y = F::lp_pool1d(x, F::LPPool1dFuncOptions(norm_type, kernel_size).stride(stride));
|
2019-10-21 22:32:10 +00:00
|
|
|
auto expected = (torch::pow(torch::tensor({{{1, 1}}}, torch::kFloat), norm_type) * kernel_size).pow(1. / norm_type);
|
|
|
|
|
|
|
|
|
|
ASSERT_EQ(y.ndimension(), 3);
|
|
|
|
|
ASSERT_TRUE(torch::allclose(y, expected));
|
|
|
|
|
ASSERT_EQ(y.sizes(), torch::IntArrayRef({1, 1, 2}));
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-28 19:26:12 +00:00
|
|
|
TEST_F(FunctionalTest, LPPool2d) {
|
|
|
|
|
int norm_type = 2;
|
|
|
|
|
int stride = 2;
|
|
|
|
|
std::vector<int64_t> kernel_size({2, 3});
|
|
|
|
|
|
|
|
|
|
auto x = torch::ones({1, 2, 5});
|
Pass F::*FuncOptions instead of torch::nn::*Options to functionals, and make F::*FuncOptions a different class when necessary (#29364)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/29364
Currently, we use `torch::nn::*Options` both as module options and functional options. However, this makes it very hard to manage the parameters in `torch::nn::*Options`, because a module's constructor can take a different set of arguments than the module's equivalent functional (e.g. `torch.nn.BatchNorm1d` takes `num_features, eps=1e-5, momentum=0.1, affine=True,
track_running_stats=True`, while `F::batch_norm` takes `running_mean, running_var, weight=None, bias=None, training=False, momentum=0.1, eps=1e-5`).
This PR resolves the above problem by making `F::*FuncOptions` a different class from `torch::nn::*Options` when necessary (i.e. when a module's constructor takes a different set of arguments than the module's equivalent functional). In the rest of the cases where the module constructor takes the same set of arguments as the module's equivalent functional, `F::*FuncOptions` is an alias of `torch::nn::*Options`.
Also as part of this PR, we change all functional options to pass-by-value, to make the semantics consistent across all functionals.
Test Plan: Imported from OSS
Differential Revision: D18376977
Pulled By: yf225
fbshipit-source-id: 8d9c240d93bfd5af0165b6884fdc912476b1d06b
2019-11-09 06:36:49 +00:00
|
|
|
auto y = F::lp_pool2d(x, F::LPPool2dFuncOptions(norm_type, kernel_size).stride(stride));
|
2019-10-28 19:26:12 +00:00
|
|
|
auto expected = (torch::pow(torch::tensor({{{1, 1}}}, torch::kFloat), norm_type) * (kernel_size[0] * kernel_size[1])).pow(1. / norm_type);
|
|
|
|
|
|
|
|
|
|
ASSERT_EQ(y.ndimension(), 3);
|
|
|
|
|
ASSERT_TRUE(torch::allclose(y, expected));
|
|
|
|
|
ASSERT_EQ(y.sizes(), torch::IntArrayRef({1, 1, 2}));
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-24 16:08:55 +00:00
|
|
|
TEST_F(FunctionalTest, CosineSimilarity) {
|
|
|
|
|
auto input1 = torch::tensor({{1, 2, 3}, {4, 5, 6}}, torch::kFloat);
|
|
|
|
|
auto input2 = torch::tensor({{1, 8, 3}, {2, 1, 6}}, torch::kFloat);
|
2019-10-03 00:26:27 +00:00
|
|
|
auto output =
|
Pass F::*FuncOptions instead of torch::nn::*Options to functionals, and make F::*FuncOptions a different class when necessary (#29364)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/29364
Currently, we use `torch::nn::*Options` both as module options and functional options. However, this makes it very hard to manage the parameters in `torch::nn::*Options`, because a module's constructor can take a different set of arguments than the module's equivalent functional (e.g. `torch.nn.BatchNorm1d` takes `num_features, eps=1e-5, momentum=0.1, affine=True,
track_running_stats=True`, while `F::batch_norm` takes `running_mean, running_var, weight=None, bias=None, training=False, momentum=0.1, eps=1e-5`).
This PR resolves the above problem by making `F::*FuncOptions` a different class from `torch::nn::*Options` when necessary (i.e. when a module's constructor takes a different set of arguments than the module's equivalent functional). In the rest of the cases where the module constructor takes the same set of arguments as the module's equivalent functional, `F::*FuncOptions` is an alias of `torch::nn::*Options`.
Also as part of this PR, we change all functional options to pass-by-value, to make the semantics consistent across all functionals.
Test Plan: Imported from OSS
Differential Revision: D18376977
Pulled By: yf225
fbshipit-source-id: 8d9c240d93bfd5af0165b6884fdc912476b1d06b
2019-11-09 06:36:49 +00:00
|
|
|
F::cosine_similarity(input1, input2, F::CosineSimilarityFuncOptions().dim(1));
|
2019-09-24 16:08:55 +00:00
|
|
|
auto expected = torch::tensor({0.8078, 0.8721}, torch::kFloat);
|
|
|
|
|
ASSERT_TRUE(output.allclose(expected, 1e-04));
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-01 06:38:59 +00:00
|
|
|
TEST_F(FunctionalTest, SmoothL1LossDefaultOptions) {
|
|
|
|
|
auto input = torch::tensor({0.1, 1.2, 4.7}, torch::dtype(torch::kFloat).requires_grad(true));
|
|
|
|
|
auto target = torch::tensor({0., 1., 5.}, torch::kFloat);
|
|
|
|
|
auto output =
|
|
|
|
|
F::smooth_l1_loss(input, target);
|
|
|
|
|
auto expected = torch::tensor(0.0233335, torch::kFloat);
|
|
|
|
|
auto s = output.sum();
|
|
|
|
|
s.backward();
|
|
|
|
|
ASSERT_TRUE(output.allclose(expected));
|
|
|
|
|
ASSERT_TRUE(input.sizes() == input.grad().sizes());
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-25 23:34:24 +00:00
|
|
|
TEST_F(FunctionalTest, SmoothL1LossBeta) {
|
|
|
|
|
auto input = torch::tensor({0.1, 1.5, 10.0}, torch::dtype(torch::kFloat).requires_grad(true));
|
|
|
|
|
auto target = torch::tensor({0., 1., 5.}, torch::kFloat);
|
|
|
|
|
auto output =
|
|
|
|
|
F::smooth_l1_loss(input, target, /*reduction=*/torch::kMean, /*beta=*/0.5);
|
|
|
|
|
auto expected = torch::tensor(1.67, torch::kFloat);
|
|
|
|
|
auto s = output.sum();
|
|
|
|
|
s.backward();
|
|
|
|
|
ASSERT_TRUE(output.allclose(expected));
|
|
|
|
|
ASSERT_TRUE(input.sizes() == input.grad().sizes());
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-01 06:38:59 +00:00
|
|
|
TEST_F(FunctionalTest, SmoothL1LossNoReduction) {
|
|
|
|
|
auto input = torch::tensor({0.1, 1.2, 4.7}, torch::dtype(torch::kFloat).requires_grad(true));
|
|
|
|
|
auto target = torch::tensor({0., 1., 5.}, torch::kFloat);
|
|
|
|
|
auto output =
|
2019-11-13 00:02:38 +00:00
|
|
|
F::smooth_l1_loss(input, target, /*reduction=*/torch::kNone);
|
2019-11-01 06:38:59 +00:00
|
|
|
auto expected = torch::tensor({0.005, 0.02, 0.045}, torch::kFloat);
|
|
|
|
|
auto s = output.sum();
|
|
|
|
|
s.backward();
|
|
|
|
|
ASSERT_TRUE(output.allclose(expected));
|
|
|
|
|
ASSERT_TRUE(input.sizes() == input.grad().sizes());
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-03 01:28:41 +00:00
|
|
|
TEST_F(FunctionalTest, HuberLossDefaultOptions) {
|
|
|
|
|
auto input = torch::tensor({0.1, 1.2, 4.7}, torch::dtype(torch::kFloat).requires_grad(true));
|
|
|
|
|
auto target = torch::tensor({0., 1., 5.}, torch::kFloat);
|
|
|
|
|
auto output =
|
|
|
|
|
F::huber_loss(input, target);
|
|
|
|
|
auto expected = torch::tensor(0.0233335, torch::kFloat);
|
|
|
|
|
auto s = output.sum();
|
|
|
|
|
s.backward();
|
|
|
|
|
ASSERT_TRUE(output.allclose(expected));
|
|
|
|
|
ASSERT_TRUE(input.sizes() == input.grad().sizes());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(FunctionalTest, HuberLossDelta) {
|
|
|
|
|
auto input = torch::tensor({0.1, 1.5, 10.0}, torch::dtype(torch::kFloat).requires_grad(true));
|
|
|
|
|
auto target = torch::tensor({0., 1., 5.}, torch::kFloat);
|
|
|
|
|
auto options = F::HuberLossFuncOptions().reduction(torch::kMean).delta(0.5);
|
|
|
|
|
auto output = F::huber_loss(input, target, options);
|
|
|
|
|
auto expected = torch::tensor(1.67 * 0.5, torch::kFloat);
|
|
|
|
|
auto s = output.sum();
|
|
|
|
|
s.backward();
|
|
|
|
|
ASSERT_TRUE(output.allclose(expected));
|
|
|
|
|
ASSERT_TRUE(input.sizes() == input.grad().sizes());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(FunctionalTest, HuberLossNoReduction) {
|
|
|
|
|
auto input = torch::tensor({0.1, 1.2, 4.7}, torch::dtype(torch::kFloat).requires_grad(true));
|
|
|
|
|
auto target = torch::tensor({0., 1., 5.}, torch::kFloat);
|
|
|
|
|
auto options = F::HuberLossFuncOptions().reduction(torch::kNone);
|
|
|
|
|
auto output = F::huber_loss(input, target, options);
|
|
|
|
|
auto expected = torch::tensor({0.005, 0.02, 0.045}, torch::kFloat);
|
|
|
|
|
auto s = output.sum();
|
|
|
|
|
s.backward();
|
|
|
|
|
ASSERT_TRUE(output.allclose(expected));
|
|
|
|
|
ASSERT_TRUE(input.sizes() == input.grad().sizes());
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-16 19:02:09 +00:00
|
|
|
TEST_F(FunctionalTest, SoftMarginLossDefaultOptions) {
|
Fix bugs in torch::tensor constructor (#28523)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/28523
New features:
1. Previously, `torch::tensor({true, false, true})` throws `"tensor_cpu" not implemented for 'Bool'`. After this PR, it produces the correct bool tensor, matching the Python API behavior.
2. Tensors with zero-size dimensions are now supported, e.g. `torch::tensor({{}, {}})` produces a tensor with sizes `{2, 0}`, matching the Python API behavior.
BC-breaking bug fixes:
1. Previously, `torch::tensor({{1}, {2}})` produces a tensor of sizes `{2}`. After this PR, it produces a tensor of sizes `{2, 1}`, matching the Python API behavior.
2. Fixed semantics of `torch::tensor(1.1)`: it now returns a 0-dim tensor instead of a 1-dim tensor, matching the Python API behavior.
3. Previously, when passed a non-dtype `TensorOptions` to the `torch::tensor` constructor, it always produces a tensor of dtype `float`. After this PR, it produces tensor of different dtypes based on the dtype of the braced-init-list, matching the behavior of the no-options case.
```cpp
// Previously:
torch::tensor({1, 2, 3}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> float
torch::tensor({{1, 2, 3}}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> float
torch::tensor({1., 2., 3.}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> float
torch::tensor({{1., 2., 3.}}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> float
// Now:
torch::tensor({1, 2, 3}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> int
torch::tensor({{1, 2, 3}}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> int
torch::tensor({1., 2., 3.}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> double
torch::tensor({{1., 2., 3.}}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> double
// As comparison, currently:
torch::tensor({1, 2, 3}).dtype() -> int
torch::tensor({{1, 2, 3}}).dtype() -> int
torch::tensor({1., 2., 3.}).dtype() -> double
torch::tensor({{1., 2., 3.}}).dtype() -> double
```
Notes:
1. From now on, the behavior of `at::tensor(scalar_value)` (which produces a 1-dim tensor) would be different from `torch::tensor(scalar_value)` (which produces a 0-dim tensor). I will fix the behavior of `at::tensor(scalar_value)` in a follow-up PR.
2. From now on, the behavior of `at::tensor({1, 2, 3}, torch::TensorOptions(/*non-dtype-options*/))` (which produces a `float` tensor) would be different from `torch::tensor({1, 2, 3}, torch::TensorOptions(/*non-dtype-options*/))` (which produces a an `int` tensor). I will fix this behavior of `at::tensor` constructor in a follow-up PR.
Context for the changes in this PR:
The motivation comes from fixing the "`torch::tensor({{1}, {2}})` gives tensor of wrong sizes" bug - in order to fix it, I have to move the handling of `at::ArrayRef` and `std::vector` into `InitListTensor` (see below on why we need to do this) and renamed `InitListTensor` to `TensorDataContainer`. After such changes, support for bool values comes out of the box without extra effort, and support for tensors with zero-size dimensions only requires adding a default constructor for `TensorDataContainer`, so I added those two in this PR.
For the semantic change of `torch::tensor(1.1)`, it's actually more effort to preserve the original wrong behavior (i.e. we need to check the sizes of the tensor converted from `TensorDataContainer` and reshape any scalar tensor to a 1-D tensor). I think preserving the original wrong behavior doesn't give us much value, and since the above changes naturally fix the problem, we should just start using the right behavior instead.
For the "constructor with non-dtype options behavior" fix, the code looks simpler and easier to reason about with the fix, so I included it in this PR.
--------
Why we need to move the handling of `at::ArrayRef` and `std::vector` into `TensorDataContainer`:
`torch::tensor({{1}, {2}})` can match this function overload:
`torch::tensor(at::ArrayRef<int> values)`, because `{1}` and `{2}` can be treated as
a list-initialization of an `int` value. However, this will produce a Tensor with sizes `{2}`,
but we actually want a Tensor with sizes `{2, 1}`. In order to avoid matching this function overload,
we removed the function overload and moved the ability to convert `at::ArrayRef<T>`
(and similarly `std::vector<T>`) into `TensorDataContainer`, and since for braced-init-list the
`TensorDataContainer(std::initializer_list<TensorDataContainer>)` constructor is always preferred over all other constructors, it will take the `std::initializer_list` path, and all is good.
Test Plan: Imported from OSS
Differential Revision: D18234625
Pulled By: yf225
fbshipit-source-id: 0f3f6912e82e2117d2103e31b74e7e97baaa8693
2019-10-31 19:51:18 +00:00
|
|
|
auto input = torch::tensor({2., 4., 1., 3.}, torch::dtype(torch::kFloat).requires_grad(true));
|
2019-10-16 19:02:09 +00:00
|
|
|
auto target = torch::tensor({-1., 1., 1., -1.}, torch::kFloat);
|
|
|
|
|
auto output =
|
|
|
|
|
F::soft_margin_loss(input, target);
|
|
|
|
|
auto expected = torch::tensor({1.3767317}, torch::kFloat);
|
|
|
|
|
auto s = output.sum();
|
|
|
|
|
s.backward();
|
|
|
|
|
|
|
|
|
|
ASSERT_TRUE(output.allclose(expected));
|
|
|
|
|
ASSERT_EQ(input.sizes(), input.grad().sizes());
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-14 20:28:27 +00:00
|
|
|
TEST_F(FunctionalTest, MultiLabelSoftMarginLossDefaultOptions) {
|
Fix bugs in torch::tensor constructor (#28523)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/28523
New features:
1. Previously, `torch::tensor({true, false, true})` throws `"tensor_cpu" not implemented for 'Bool'`. After this PR, it produces the correct bool tensor, matching the Python API behavior.
2. Tensors with zero-size dimensions are now supported, e.g. `torch::tensor({{}, {}})` produces a tensor with sizes `{2, 0}`, matching the Python API behavior.
BC-breaking bug fixes:
1. Previously, `torch::tensor({{1}, {2}})` produces a tensor of sizes `{2}`. After this PR, it produces a tensor of sizes `{2, 1}`, matching the Python API behavior.
2. Fixed semantics of `torch::tensor(1.1)`: it now returns a 0-dim tensor instead of a 1-dim tensor, matching the Python API behavior.
3. Previously, when passed a non-dtype `TensorOptions` to the `torch::tensor` constructor, it always produces a tensor of dtype `float`. After this PR, it produces tensor of different dtypes based on the dtype of the braced-init-list, matching the behavior of the no-options case.
```cpp
// Previously:
torch::tensor({1, 2, 3}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> float
torch::tensor({{1, 2, 3}}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> float
torch::tensor({1., 2., 3.}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> float
torch::tensor({{1., 2., 3.}}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> float
// Now:
torch::tensor({1, 2, 3}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> int
torch::tensor({{1, 2, 3}}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> int
torch::tensor({1., 2., 3.}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> double
torch::tensor({{1., 2., 3.}}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> double
// As comparison, currently:
torch::tensor({1, 2, 3}).dtype() -> int
torch::tensor({{1, 2, 3}}).dtype() -> int
torch::tensor({1., 2., 3.}).dtype() -> double
torch::tensor({{1., 2., 3.}}).dtype() -> double
```
Notes:
1. From now on, the behavior of `at::tensor(scalar_value)` (which produces a 1-dim tensor) would be different from `torch::tensor(scalar_value)` (which produces a 0-dim tensor). I will fix the behavior of `at::tensor(scalar_value)` in a follow-up PR.
2. From now on, the behavior of `at::tensor({1, 2, 3}, torch::TensorOptions(/*non-dtype-options*/))` (which produces a `float` tensor) would be different from `torch::tensor({1, 2, 3}, torch::TensorOptions(/*non-dtype-options*/))` (which produces a an `int` tensor). I will fix this behavior of `at::tensor` constructor in a follow-up PR.
Context for the changes in this PR:
The motivation comes from fixing the "`torch::tensor({{1}, {2}})` gives tensor of wrong sizes" bug - in order to fix it, I have to move the handling of `at::ArrayRef` and `std::vector` into `InitListTensor` (see below on why we need to do this) and renamed `InitListTensor` to `TensorDataContainer`. After such changes, support for bool values comes out of the box without extra effort, and support for tensors with zero-size dimensions only requires adding a default constructor for `TensorDataContainer`, so I added those two in this PR.
For the semantic change of `torch::tensor(1.1)`, it's actually more effort to preserve the original wrong behavior (i.e. we need to check the sizes of the tensor converted from `TensorDataContainer` and reshape any scalar tensor to a 1-D tensor). I think preserving the original wrong behavior doesn't give us much value, and since the above changes naturally fix the problem, we should just start using the right behavior instead.
For the "constructor with non-dtype options behavior" fix, the code looks simpler and easier to reason about with the fix, so I included it in this PR.
--------
Why we need to move the handling of `at::ArrayRef` and `std::vector` into `TensorDataContainer`:
`torch::tensor({{1}, {2}})` can match this function overload:
`torch::tensor(at::ArrayRef<int> values)`, because `{1}` and `{2}` can be treated as
a list-initialization of an `int` value. However, this will produce a Tensor with sizes `{2}`,
but we actually want a Tensor with sizes `{2, 1}`. In order to avoid matching this function overload,
we removed the function overload and moved the ability to convert `at::ArrayRef<T>`
(and similarly `std::vector<T>`) into `TensorDataContainer`, and since for braced-init-list the
`TensorDataContainer(std::initializer_list<TensorDataContainer>)` constructor is always preferred over all other constructors, it will take the `std::initializer_list` path, and all is good.
Test Plan: Imported from OSS
Differential Revision: D18234625
Pulled By: yf225
fbshipit-source-id: 0f3f6912e82e2117d2103e31b74e7e97baaa8693
2019-10-31 19:51:18 +00:00
|
|
|
auto input = torch::tensor({{0., 2., 2., 0.}, {2., 1., 0., 1.}}, torch::dtype(torch::kFloat).requires_grad(true));
|
2019-10-14 20:28:27 +00:00
|
|
|
auto target = torch::tensor({{0., 0., 1., 0.}, {1., 0., 1., 1.}}, torch::kFloat);
|
|
|
|
|
auto output =
|
|
|
|
|
F::multilabel_soft_margin_loss(input, target);
|
|
|
|
|
auto expected = torch::tensor({0.7608436}, torch::kFloat);
|
|
|
|
|
auto s = output.sum();
|
|
|
|
|
s.backward();
|
|
|
|
|
|
|
|
|
|
ASSERT_TRUE(output.allclose(expected));
|
|
|
|
|
ASSERT_EQ(input.sizes(), input.grad().sizes());
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-16 19:02:09 +00:00
|
|
|
TEST_F(FunctionalTest, SoftMarginLossNoReduction) {
|
Fix bugs in torch::tensor constructor (#28523)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/28523
New features:
1. Previously, `torch::tensor({true, false, true})` throws `"tensor_cpu" not implemented for 'Bool'`. After this PR, it produces the correct bool tensor, matching the Python API behavior.
2. Tensors with zero-size dimensions are now supported, e.g. `torch::tensor({{}, {}})` produces a tensor with sizes `{2, 0}`, matching the Python API behavior.
BC-breaking bug fixes:
1. Previously, `torch::tensor({{1}, {2}})` produces a tensor of sizes `{2}`. After this PR, it produces a tensor of sizes `{2, 1}`, matching the Python API behavior.
2. Fixed semantics of `torch::tensor(1.1)`: it now returns a 0-dim tensor instead of a 1-dim tensor, matching the Python API behavior.
3. Previously, when passed a non-dtype `TensorOptions` to the `torch::tensor` constructor, it always produces a tensor of dtype `float`. After this PR, it produces tensor of different dtypes based on the dtype of the braced-init-list, matching the behavior of the no-options case.
```cpp
// Previously:
torch::tensor({1, 2, 3}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> float
torch::tensor({{1, 2, 3}}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> float
torch::tensor({1., 2., 3.}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> float
torch::tensor({{1., 2., 3.}}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> float
// Now:
torch::tensor({1, 2, 3}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> int
torch::tensor({{1, 2, 3}}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> int
torch::tensor({1., 2., 3.}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> double
torch::tensor({{1., 2., 3.}}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> double
// As comparison, currently:
torch::tensor({1, 2, 3}).dtype() -> int
torch::tensor({{1, 2, 3}}).dtype() -> int
torch::tensor({1., 2., 3.}).dtype() -> double
torch::tensor({{1., 2., 3.}}).dtype() -> double
```
Notes:
1. From now on, the behavior of `at::tensor(scalar_value)` (which produces a 1-dim tensor) would be different from `torch::tensor(scalar_value)` (which produces a 0-dim tensor). I will fix the behavior of `at::tensor(scalar_value)` in a follow-up PR.
2. From now on, the behavior of `at::tensor({1, 2, 3}, torch::TensorOptions(/*non-dtype-options*/))` (which produces a `float` tensor) would be different from `torch::tensor({1, 2, 3}, torch::TensorOptions(/*non-dtype-options*/))` (which produces a an `int` tensor). I will fix this behavior of `at::tensor` constructor in a follow-up PR.
Context for the changes in this PR:
The motivation comes from fixing the "`torch::tensor({{1}, {2}})` gives tensor of wrong sizes" bug - in order to fix it, I have to move the handling of `at::ArrayRef` and `std::vector` into `InitListTensor` (see below on why we need to do this) and renamed `InitListTensor` to `TensorDataContainer`. After such changes, support for bool values comes out of the box without extra effort, and support for tensors with zero-size dimensions only requires adding a default constructor for `TensorDataContainer`, so I added those two in this PR.
For the semantic change of `torch::tensor(1.1)`, it's actually more effort to preserve the original wrong behavior (i.e. we need to check the sizes of the tensor converted from `TensorDataContainer` and reshape any scalar tensor to a 1-D tensor). I think preserving the original wrong behavior doesn't give us much value, and since the above changes naturally fix the problem, we should just start using the right behavior instead.
For the "constructor with non-dtype options behavior" fix, the code looks simpler and easier to reason about with the fix, so I included it in this PR.
--------
Why we need to move the handling of `at::ArrayRef` and `std::vector` into `TensorDataContainer`:
`torch::tensor({{1}, {2}})` can match this function overload:
`torch::tensor(at::ArrayRef<int> values)`, because `{1}` and `{2}` can be treated as
a list-initialization of an `int` value. However, this will produce a Tensor with sizes `{2}`,
but we actually want a Tensor with sizes `{2, 1}`. In order to avoid matching this function overload,
we removed the function overload and moved the ability to convert `at::ArrayRef<T>`
(and similarly `std::vector<T>`) into `TensorDataContainer`, and since for braced-init-list the
`TensorDataContainer(std::initializer_list<TensorDataContainer>)` constructor is always preferred over all other constructors, it will take the `std::initializer_list` path, and all is good.
Test Plan: Imported from OSS
Differential Revision: D18234625
Pulled By: yf225
fbshipit-source-id: 0f3f6912e82e2117d2103e31b74e7e97baaa8693
2019-10-31 19:51:18 +00:00
|
|
|
auto input = torch::tensor({2., 4., 1., 3.}, torch::dtype(torch::kFloat).requires_grad(true));
|
2019-10-16 19:02:09 +00:00
|
|
|
auto target = torch::tensor({-1., 1., 1., -1.}, torch::kFloat);
|
|
|
|
|
auto output =
|
2019-10-29 21:13:37 +00:00
|
|
|
F::soft_margin_loss(input, target, torch::kNone);
|
2019-10-16 19:02:09 +00:00
|
|
|
auto expected = torch::tensor({2.1269281, 0.01814993, 0.3132617, 3.0485873}, torch::kFloat);
|
|
|
|
|
auto s = output.sum();
|
|
|
|
|
s.backward();
|
|
|
|
|
|
|
|
|
|
ASSERT_TRUE(output.allclose(expected));
|
|
|
|
|
ASSERT_EQ(input.sizes(), input.grad().sizes());
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-14 20:28:27 +00:00
|
|
|
TEST_F(FunctionalTest, MultiLabelSoftMarginLossWeightedNoReduction) {
|
Fix bugs in torch::tensor constructor (#28523)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/28523
New features:
1. Previously, `torch::tensor({true, false, true})` throws `"tensor_cpu" not implemented for 'Bool'`. After this PR, it produces the correct bool tensor, matching the Python API behavior.
2. Tensors with zero-size dimensions are now supported, e.g. `torch::tensor({{}, {}})` produces a tensor with sizes `{2, 0}`, matching the Python API behavior.
BC-breaking bug fixes:
1. Previously, `torch::tensor({{1}, {2}})` produces a tensor of sizes `{2}`. After this PR, it produces a tensor of sizes `{2, 1}`, matching the Python API behavior.
2. Fixed semantics of `torch::tensor(1.1)`: it now returns a 0-dim tensor instead of a 1-dim tensor, matching the Python API behavior.
3. Previously, when passed a non-dtype `TensorOptions` to the `torch::tensor` constructor, it always produces a tensor of dtype `float`. After this PR, it produces tensor of different dtypes based on the dtype of the braced-init-list, matching the behavior of the no-options case.
```cpp
// Previously:
torch::tensor({1, 2, 3}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> float
torch::tensor({{1, 2, 3}}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> float
torch::tensor({1., 2., 3.}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> float
torch::tensor({{1., 2., 3.}}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> float
// Now:
torch::tensor({1, 2, 3}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> int
torch::tensor({{1, 2, 3}}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> int
torch::tensor({1., 2., 3.}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> double
torch::tensor({{1., 2., 3.}}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> double
// As comparison, currently:
torch::tensor({1, 2, 3}).dtype() -> int
torch::tensor({{1, 2, 3}}).dtype() -> int
torch::tensor({1., 2., 3.}).dtype() -> double
torch::tensor({{1., 2., 3.}}).dtype() -> double
```
Notes:
1. From now on, the behavior of `at::tensor(scalar_value)` (which produces a 1-dim tensor) would be different from `torch::tensor(scalar_value)` (which produces a 0-dim tensor). I will fix the behavior of `at::tensor(scalar_value)` in a follow-up PR.
2. From now on, the behavior of `at::tensor({1, 2, 3}, torch::TensorOptions(/*non-dtype-options*/))` (which produces a `float` tensor) would be different from `torch::tensor({1, 2, 3}, torch::TensorOptions(/*non-dtype-options*/))` (which produces a an `int` tensor). I will fix this behavior of `at::tensor` constructor in a follow-up PR.
Context for the changes in this PR:
The motivation comes from fixing the "`torch::tensor({{1}, {2}})` gives tensor of wrong sizes" bug - in order to fix it, I have to move the handling of `at::ArrayRef` and `std::vector` into `InitListTensor` (see below on why we need to do this) and renamed `InitListTensor` to `TensorDataContainer`. After such changes, support for bool values comes out of the box without extra effort, and support for tensors with zero-size dimensions only requires adding a default constructor for `TensorDataContainer`, so I added those two in this PR.
For the semantic change of `torch::tensor(1.1)`, it's actually more effort to preserve the original wrong behavior (i.e. we need to check the sizes of the tensor converted from `TensorDataContainer` and reshape any scalar tensor to a 1-D tensor). I think preserving the original wrong behavior doesn't give us much value, and since the above changes naturally fix the problem, we should just start using the right behavior instead.
For the "constructor with non-dtype options behavior" fix, the code looks simpler and easier to reason about with the fix, so I included it in this PR.
--------
Why we need to move the handling of `at::ArrayRef` and `std::vector` into `TensorDataContainer`:
`torch::tensor({{1}, {2}})` can match this function overload:
`torch::tensor(at::ArrayRef<int> values)`, because `{1}` and `{2}` can be treated as
a list-initialization of an `int` value. However, this will produce a Tensor with sizes `{2}`,
but we actually want a Tensor with sizes `{2, 1}`. In order to avoid matching this function overload,
we removed the function overload and moved the ability to convert `at::ArrayRef<T>`
(and similarly `std::vector<T>`) into `TensorDataContainer`, and since for braced-init-list the
`TensorDataContainer(std::initializer_list<TensorDataContainer>)` constructor is always preferred over all other constructors, it will take the `std::initializer_list` path, and all is good.
Test Plan: Imported from OSS
Differential Revision: D18234625
Pulled By: yf225
fbshipit-source-id: 0f3f6912e82e2117d2103e31b74e7e97baaa8693
2019-10-31 19:51:18 +00:00
|
|
|
auto input = torch::tensor({{0., 2., 2., 0.}, {2., 1., 0., 1.}}, torch::dtype(torch::kFloat).requires_grad(true));
|
2019-10-14 20:28:27 +00:00
|
|
|
auto target = torch::tensor({{0., 0., 1., 0.}, {1., 0., 1., 1.}}, torch::kFloat);
|
|
|
|
|
auto weight = torch::tensor({0.1, 0.6, 0.4, 0.8}, torch::kFloat);
|
2020-03-22 01:31:07 +00:00
|
|
|
auto options = F::MultilabelSoftMarginLossFuncOptions().reduction(torch::kNone).weight(weight);
|
2019-10-14 20:28:27 +00:00
|
|
|
auto output =
|
|
|
|
|
F::multilabel_soft_margin_loss(input, target, options);
|
|
|
|
|
auto expected = torch::tensor({0.4876902, 0.3321295}, torch::kFloat);
|
|
|
|
|
auto s = output.sum();
|
|
|
|
|
s.backward();
|
|
|
|
|
|
|
|
|
|
ASSERT_TRUE(output.allclose(expected));
|
|
|
|
|
ASSERT_EQ(input.sizes(), input.grad().sizes());
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-24 16:08:55 +00:00
|
|
|
TEST_F(FunctionalTest, PairwiseDistance) {
|
|
|
|
|
auto input1 = torch::tensor({{1, 2, 3}, {4, 5, 6}}, torch::kFloat);
|
|
|
|
|
auto input2 = torch::tensor({{1, 8, 3}, {2, 1, 6}}, torch::kFloat);
|
2019-10-03 00:26:27 +00:00
|
|
|
auto output =
|
Pass F::*FuncOptions instead of torch::nn::*Options to functionals, and make F::*FuncOptions a different class when necessary (#29364)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/29364
Currently, we use `torch::nn::*Options` both as module options and functional options. However, this makes it very hard to manage the parameters in `torch::nn::*Options`, because a module's constructor can take a different set of arguments than the module's equivalent functional (e.g. `torch.nn.BatchNorm1d` takes `num_features, eps=1e-5, momentum=0.1, affine=True,
track_running_stats=True`, while `F::batch_norm` takes `running_mean, running_var, weight=None, bias=None, training=False, momentum=0.1, eps=1e-5`).
This PR resolves the above problem by making `F::*FuncOptions` a different class from `torch::nn::*Options` when necessary (i.e. when a module's constructor takes a different set of arguments than the module's equivalent functional). In the rest of the cases where the module constructor takes the same set of arguments as the module's equivalent functional, `F::*FuncOptions` is an alias of `torch::nn::*Options`.
Also as part of this PR, we change all functional options to pass-by-value, to make the semantics consistent across all functionals.
Test Plan: Imported from OSS
Differential Revision: D18376977
Pulled By: yf225
fbshipit-source-id: 8d9c240d93bfd5af0165b6884fdc912476b1d06b
2019-11-09 06:36:49 +00:00
|
|
|
F::pairwise_distance(input1, input2, F::PairwiseDistanceFuncOptions().p(1));
|
2019-09-24 16:08:55 +00:00
|
|
|
auto expected = torch::tensor({6, 6}, torch::kFloat);
|
|
|
|
|
ASSERT_TRUE(output.allclose(expected));
|
|
|
|
|
}
|
2019-09-27 16:08:59 +00:00
|
|
|
|
2019-10-01 14:03:40 +00:00
|
|
|
TEST_F(FunctionalTest, PDist) {
|
|
|
|
|
{
|
|
|
|
|
auto input = torch::tensor({{-1.0, -5.0, -1.0}, {2.0, 4.0, 6.0}});
|
|
|
|
|
auto output = F::pdist(input);
|
|
|
|
|
auto expected = torch::tensor({11.7898});
|
|
|
|
|
ASSERT_TRUE(output.allclose(expected));
|
|
|
|
|
}
|
|
|
|
|
{
|
|
|
|
|
auto input = torch::tensor({{1.0, -1.0}, {1.0, 3.0}, {3.0, 3.0}});
|
|
|
|
|
auto output = F::pdist(input, 1.5);
|
|
|
|
|
auto expected = torch::tensor({4.0, 4.8945, 2.0});
|
|
|
|
|
ASSERT_TRUE(output.allclose(expected));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-27 16:08:59 +00:00
|
|
|
TEST_F(FunctionalTest, AdaptiveMaxPool1d) {
|
|
|
|
|
auto x = torch::ones({1, 1, 5});
|
Pass F::*FuncOptions instead of torch::nn::*Options to functionals, and make F::*FuncOptions a different class when necessary (#29364)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/29364
Currently, we use `torch::nn::*Options` both as module options and functional options. However, this makes it very hard to manage the parameters in `torch::nn::*Options`, because a module's constructor can take a different set of arguments than the module's equivalent functional (e.g. `torch.nn.BatchNorm1d` takes `num_features, eps=1e-5, momentum=0.1, affine=True,
track_running_stats=True`, while `F::batch_norm` takes `running_mean, running_var, weight=None, bias=None, training=False, momentum=0.1, eps=1e-5`).
This PR resolves the above problem by making `F::*FuncOptions` a different class from `torch::nn::*Options` when necessary (i.e. when a module's constructor takes a different set of arguments than the module's equivalent functional). In the rest of the cases where the module constructor takes the same set of arguments as the module's equivalent functional, `F::*FuncOptions` is an alias of `torch::nn::*Options`.
Also as part of this PR, we change all functional options to pass-by-value, to make the semantics consistent across all functionals.
Test Plan: Imported from OSS
Differential Revision: D18376977
Pulled By: yf225
fbshipit-source-id: 8d9c240d93bfd5af0165b6884fdc912476b1d06b
2019-11-09 06:36:49 +00:00
|
|
|
auto y = F::adaptive_max_pool1d(x, F::AdaptiveMaxPool1dFuncOptions(3));
|
2019-09-27 16:08:59 +00:00
|
|
|
|
|
|
|
|
ASSERT_EQ(y.ndimension(), 3);
|
|
|
|
|
ASSERT_TRUE(torch::allclose(y, torch::ones({1, 1, 3})));
|
2019-10-15 00:58:14 +00:00
|
|
|
ASSERT_EQ(y.sizes(), std::vector<int64_t>({1, 1, 3}));
|
2019-09-27 16:08:59 +00:00
|
|
|
}
|
2019-09-27 19:39:00 +00:00
|
|
|
|
|
|
|
|
TEST_F(FunctionalTest, AdaptiveMaxPool2d) {
|
|
|
|
|
auto x = torch::ones({2, 5, 5});
|
Pass F::*FuncOptions instead of torch::nn::*Options to functionals, and make F::*FuncOptions a different class when necessary (#29364)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/29364
Currently, we use `torch::nn::*Options` both as module options and functional options. However, this makes it very hard to manage the parameters in `torch::nn::*Options`, because a module's constructor can take a different set of arguments than the module's equivalent functional (e.g. `torch.nn.BatchNorm1d` takes `num_features, eps=1e-5, momentum=0.1, affine=True,
track_running_stats=True`, while `F::batch_norm` takes `running_mean, running_var, weight=None, bias=None, training=False, momentum=0.1, eps=1e-5`).
This PR resolves the above problem by making `F::*FuncOptions` a different class from `torch::nn::*Options` when necessary (i.e. when a module's constructor takes a different set of arguments than the module's equivalent functional). In the rest of the cases where the module constructor takes the same set of arguments as the module's equivalent functional, `F::*FuncOptions` is an alias of `torch::nn::*Options`.
Also as part of this PR, we change all functional options to pass-by-value, to make the semantics consistent across all functionals.
Test Plan: Imported from OSS
Differential Revision: D18376977
Pulled By: yf225
fbshipit-source-id: 8d9c240d93bfd5af0165b6884fdc912476b1d06b
2019-11-09 06:36:49 +00:00
|
|
|
auto y = F::adaptive_max_pool2d(x, F::AdaptiveMaxPool2dFuncOptions(3));
|
2019-09-27 19:39:00 +00:00
|
|
|
|
|
|
|
|
ASSERT_EQ(y.ndimension(), 3);
|
|
|
|
|
ASSERT_TRUE(torch::allclose(y, torch::ones({2, 3, 3})));
|
2019-10-15 00:58:14 +00:00
|
|
|
ASSERT_EQ(y.sizes(), std::vector<int64_t>({2, 3, 3}));
|
2019-09-27 19:39:00 +00:00
|
|
|
}
|
2019-09-27 22:26:48 +00:00
|
|
|
|
|
|
|
|
TEST_F(FunctionalTest, AdaptiveMaxPool3d) {
|
|
|
|
|
auto x = torch::ones({2, 5, 5, 5});
|
Pass F::*FuncOptions instead of torch::nn::*Options to functionals, and make F::*FuncOptions a different class when necessary (#29364)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/29364
Currently, we use `torch::nn::*Options` both as module options and functional options. However, this makes it very hard to manage the parameters in `torch::nn::*Options`, because a module's constructor can take a different set of arguments than the module's equivalent functional (e.g. `torch.nn.BatchNorm1d` takes `num_features, eps=1e-5, momentum=0.1, affine=True,
track_running_stats=True`, while `F::batch_norm` takes `running_mean, running_var, weight=None, bias=None, training=False, momentum=0.1, eps=1e-5`).
This PR resolves the above problem by making `F::*FuncOptions` a different class from `torch::nn::*Options` when necessary (i.e. when a module's constructor takes a different set of arguments than the module's equivalent functional). In the rest of the cases where the module constructor takes the same set of arguments as the module's equivalent functional, `F::*FuncOptions` is an alias of `torch::nn::*Options`.
Also as part of this PR, we change all functional options to pass-by-value, to make the semantics consistent across all functionals.
Test Plan: Imported from OSS
Differential Revision: D18376977
Pulled By: yf225
fbshipit-source-id: 8d9c240d93bfd5af0165b6884fdc912476b1d06b
2019-11-09 06:36:49 +00:00
|
|
|
auto y = F::adaptive_max_pool3d(x, F::AdaptiveMaxPool3dFuncOptions(3));
|
2019-09-27 22:26:48 +00:00
|
|
|
|
|
|
|
|
ASSERT_EQ(y.ndimension(), 4);
|
|
|
|
|
ASSERT_TRUE(torch::allclose(y, torch::ones({2, 3, 3, 3})));
|
2019-10-15 00:58:14 +00:00
|
|
|
ASSERT_EQ(y.sizes(), std::vector<int64_t>({2, 3, 3, 3}));
|
2019-09-27 22:26:48 +00:00
|
|
|
}
|
2019-09-28 17:21:07 +00:00
|
|
|
|
|
|
|
|
TEST_F(FunctionalTest, AdaptiveAvgPool1d) {
|
|
|
|
|
auto x = torch::ones({1, 1, 5});
|
Pass F::*FuncOptions instead of torch::nn::*Options to functionals, and make F::*FuncOptions a different class when necessary (#29364)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/29364
Currently, we use `torch::nn::*Options` both as module options and functional options. However, this makes it very hard to manage the parameters in `torch::nn::*Options`, because a module's constructor can take a different set of arguments than the module's equivalent functional (e.g. `torch.nn.BatchNorm1d` takes `num_features, eps=1e-5, momentum=0.1, affine=True,
track_running_stats=True`, while `F::batch_norm` takes `running_mean, running_var, weight=None, bias=None, training=False, momentum=0.1, eps=1e-5`).
This PR resolves the above problem by making `F::*FuncOptions` a different class from `torch::nn::*Options` when necessary (i.e. when a module's constructor takes a different set of arguments than the module's equivalent functional). In the rest of the cases where the module constructor takes the same set of arguments as the module's equivalent functional, `F::*FuncOptions` is an alias of `torch::nn::*Options`.
Also as part of this PR, we change all functional options to pass-by-value, to make the semantics consistent across all functionals.
Test Plan: Imported from OSS
Differential Revision: D18376977
Pulled By: yf225
fbshipit-source-id: 8d9c240d93bfd5af0165b6884fdc912476b1d06b
2019-11-09 06:36:49 +00:00
|
|
|
auto y = F::adaptive_avg_pool1d(x, F::AdaptiveAvgPool1dFuncOptions(3));
|
2019-09-28 17:21:07 +00:00
|
|
|
|
|
|
|
|
ASSERT_EQ(y.ndimension(), 3);
|
|
|
|
|
ASSERT_TRUE(torch::allclose(y, torch::ones({1, 1, 3})));
|
2019-10-15 00:58:14 +00:00
|
|
|
ASSERT_EQ(y.sizes(), std::vector<int64_t>({1, 1, 3}));
|
2019-09-28 17:21:07 +00:00
|
|
|
}
|
2019-09-28 17:43:21 +00:00
|
|
|
|
|
|
|
|
TEST_F(FunctionalTest, AdaptiveAvgPool2d) {
|
|
|
|
|
auto x = torch::ones({2, 5, 5});
|
Pass F::*FuncOptions instead of torch::nn::*Options to functionals, and make F::*FuncOptions a different class when necessary (#29364)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/29364
Currently, we use `torch::nn::*Options` both as module options and functional options. However, this makes it very hard to manage the parameters in `torch::nn::*Options`, because a module's constructor can take a different set of arguments than the module's equivalent functional (e.g. `torch.nn.BatchNorm1d` takes `num_features, eps=1e-5, momentum=0.1, affine=True,
track_running_stats=True`, while `F::batch_norm` takes `running_mean, running_var, weight=None, bias=None, training=False, momentum=0.1, eps=1e-5`).
This PR resolves the above problem by making `F::*FuncOptions` a different class from `torch::nn::*Options` when necessary (i.e. when a module's constructor takes a different set of arguments than the module's equivalent functional). In the rest of the cases where the module constructor takes the same set of arguments as the module's equivalent functional, `F::*FuncOptions` is an alias of `torch::nn::*Options`.
Also as part of this PR, we change all functional options to pass-by-value, to make the semantics consistent across all functionals.
Test Plan: Imported from OSS
Differential Revision: D18376977
Pulled By: yf225
fbshipit-source-id: 8d9c240d93bfd5af0165b6884fdc912476b1d06b
2019-11-09 06:36:49 +00:00
|
|
|
auto y = F::adaptive_avg_pool2d(x, F::AdaptiveAvgPool2dFuncOptions(3));
|
2019-09-28 17:43:21 +00:00
|
|
|
|
|
|
|
|
ASSERT_EQ(y.ndimension(), 3);
|
|
|
|
|
ASSERT_TRUE(torch::allclose(y, torch::ones({2, 3, 3})));
|
2019-10-15 00:58:14 +00:00
|
|
|
ASSERT_EQ(y.sizes(), std::vector<int64_t>({2, 3, 3}));
|
2019-09-28 17:43:21 +00:00
|
|
|
}
|
2019-09-29 05:30:03 +00:00
|
|
|
|
|
|
|
|
TEST_F(FunctionalTest, AdaptiveAvgPool3d) {
|
|
|
|
|
auto x = torch::ones({2, 5, 5, 5});
|
Pass F::*FuncOptions instead of torch::nn::*Options to functionals, and make F::*FuncOptions a different class when necessary (#29364)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/29364
Currently, we use `torch::nn::*Options` both as module options and functional options. However, this makes it very hard to manage the parameters in `torch::nn::*Options`, because a module's constructor can take a different set of arguments than the module's equivalent functional (e.g. `torch.nn.BatchNorm1d` takes `num_features, eps=1e-5, momentum=0.1, affine=True,
track_running_stats=True`, while `F::batch_norm` takes `running_mean, running_var, weight=None, bias=None, training=False, momentum=0.1, eps=1e-5`).
This PR resolves the above problem by making `F::*FuncOptions` a different class from `torch::nn::*Options` when necessary (i.e. when a module's constructor takes a different set of arguments than the module's equivalent functional). In the rest of the cases where the module constructor takes the same set of arguments as the module's equivalent functional, `F::*FuncOptions` is an alias of `torch::nn::*Options`.
Also as part of this PR, we change all functional options to pass-by-value, to make the semantics consistent across all functionals.
Test Plan: Imported from OSS
Differential Revision: D18376977
Pulled By: yf225
fbshipit-source-id: 8d9c240d93bfd5af0165b6884fdc912476b1d06b
2019-11-09 06:36:49 +00:00
|
|
|
auto y = F::adaptive_avg_pool3d(x, F::AdaptiveAvgPool3dFuncOptions(3));
|
2019-09-29 05:30:03 +00:00
|
|
|
|
|
|
|
|
ASSERT_EQ(y.ndimension(), 4);
|
|
|
|
|
ASSERT_TRUE(torch::allclose(y, torch::ones({2, 3, 3, 3})));
|
2019-10-15 00:58:14 +00:00
|
|
|
ASSERT_EQ(y.sizes(), std::vector<int64_t>({2, 3, 3, 3}));
|
2019-09-29 05:30:03 +00:00
|
|
|
}
|
2019-10-01 02:24:45 +00:00
|
|
|
|
2019-10-18 05:05:27 +00:00
|
|
|
TEST_F(FunctionalTest, L1Loss) {
|
|
|
|
|
auto input = torch::randn({5,6}, torch::requires_grad());
|
|
|
|
|
auto target = torch::empty({5,6}).random_(2);
|
|
|
|
|
auto output = F::l1_loss(torch::sigmoid(input), target);
|
|
|
|
|
auto s = output.sum();
|
|
|
|
|
s.backward();
|
|
|
|
|
|
|
|
|
|
ASSERT_EQ(output.sizes(), torch::IntArrayRef());
|
|
|
|
|
ASSERT_EQ(input.sizes(), input.grad().sizes());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(FunctionalTest, MSELoss) {
|
|
|
|
|
auto input = torch::randn({5,6}, torch::requires_grad());
|
|
|
|
|
auto target = torch::empty({5,6}).random_(2);
|
|
|
|
|
auto output = F::mse_loss(torch::sigmoid(input), target);
|
|
|
|
|
auto s = output.sum();
|
|
|
|
|
s.backward();
|
|
|
|
|
|
|
|
|
|
ASSERT_EQ(output.sizes(), torch::IntArrayRef());
|
|
|
|
|
ASSERT_EQ(input.sizes(), input.grad().sizes());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(FunctionalTest, BCELoss) {
|
|
|
|
|
auto input = torch::randn({5,6}, torch::requires_grad());
|
|
|
|
|
auto target = torch::empty({5,6}).random_(2);
|
|
|
|
|
auto output = F::binary_cross_entropy(torch::sigmoid(input), target);
|
|
|
|
|
auto s = output.sum();
|
|
|
|
|
s.backward();
|
|
|
|
|
|
|
|
|
|
ASSERT_EQ(output.sizes(), torch::IntArrayRef());
|
|
|
|
|
ASSERT_EQ(input.sizes(), input.grad().sizes());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(FunctionalTest, KLDivLoss) {
|
|
|
|
|
KLDivLoss loss;
|
|
|
|
|
auto input = torch::randn({5,6}, torch::requires_grad());
|
|
|
|
|
auto target = torch::empty({5,6}).random_(2);
|
|
|
|
|
auto output = F::kl_div(torch::sigmoid(input), target);
|
|
|
|
|
auto s = output.sum();
|
|
|
|
|
s.backward();
|
|
|
|
|
|
|
|
|
|
ASSERT_EQ(output.sizes(), torch::IntArrayRef());
|
|
|
|
|
ASSERT_EQ(input.sizes(), input.grad().sizes());
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-01 02:24:45 +00:00
|
|
|
TEST_F(FunctionalTest, HingeEmbeddingLoss) {
|
|
|
|
|
auto input = torch::tensor({{2, 22, 4}, {20, 10, 0}}, torch::kFloat);
|
|
|
|
|
auto target = torch::tensor({{2, 6, 4}, {1, 10, 0}}, torch::kFloat);
|
|
|
|
|
auto output = F::hinge_embedding_loss(
|
Pass F::*FuncOptions instead of torch::nn::*Options to functionals, and make F::*FuncOptions a different class when necessary (#29364)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/29364
Currently, we use `torch::nn::*Options` both as module options and functional options. However, this makes it very hard to manage the parameters in `torch::nn::*Options`, because a module's constructor can take a different set of arguments than the module's equivalent functional (e.g. `torch.nn.BatchNorm1d` takes `num_features, eps=1e-5, momentum=0.1, affine=True,
track_running_stats=True`, while `F::batch_norm` takes `running_mean, running_var, weight=None, bias=None, training=False, momentum=0.1, eps=1e-5`).
This PR resolves the above problem by making `F::*FuncOptions` a different class from `torch::nn::*Options` when necessary (i.e. when a module's constructor takes a different set of arguments than the module's equivalent functional). In the rest of the cases where the module constructor takes the same set of arguments as the module's equivalent functional, `F::*FuncOptions` is an alias of `torch::nn::*Options`.
Also as part of this PR, we change all functional options to pass-by-value, to make the semantics consistent across all functionals.
Test Plan: Imported from OSS
Differential Revision: D18376977
Pulled By: yf225
fbshipit-source-id: 8d9c240d93bfd5af0165b6884fdc912476b1d06b
2019-11-09 06:36:49 +00:00
|
|
|
input, target, F::HingeEmbeddingLossFuncOptions().margin(2));
|
2019-10-01 02:24:45 +00:00
|
|
|
auto expected = torch::tensor({10}, torch::kFloat);
|
|
|
|
|
|
|
|
|
|
ASSERT_TRUE(output.allclose(expected));
|
|
|
|
|
}
|
2019-10-01 21:51:27 +00:00
|
|
|
|
2019-10-24 22:12:55 +00:00
|
|
|
TEST_F(FunctionalTest, GridSample) {
|
|
|
|
|
auto input = torch::arange(9, torch::kFloat).view(std::vector<int64_t>({1, 1, 3, 3}));
|
|
|
|
|
auto grid = torch::tensor({{
|
|
|
|
|
{{-2., -1.}, {-1., -1.}, {0., -1.}},
|
|
|
|
|
{{-1., 0.}, {0., 0.}, {1., 0.}},
|
|
|
|
|
{{0., 1.}, {1., 1.}, {2., 1.}}
|
|
|
|
|
}}, torch::kFloat);
|
|
|
|
|
|
|
|
|
|
// bilinear, zeros, true
|
Pass F::*FuncOptions instead of torch::nn::*Options to functionals, and make F::*FuncOptions a different class when necessary (#29364)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/29364
Currently, we use `torch::nn::*Options` both as module options and functional options. However, this makes it very hard to manage the parameters in `torch::nn::*Options`, because a module's constructor can take a different set of arguments than the module's equivalent functional (e.g. `torch.nn.BatchNorm1d` takes `num_features, eps=1e-5, momentum=0.1, affine=True,
track_running_stats=True`, while `F::batch_norm` takes `running_mean, running_var, weight=None, bias=None, training=False, momentum=0.1, eps=1e-5`).
This PR resolves the above problem by making `F::*FuncOptions` a different class from `torch::nn::*Options` when necessary (i.e. when a module's constructor takes a different set of arguments than the module's equivalent functional). In the rest of the cases where the module constructor takes the same set of arguments as the module's equivalent functional, `F::*FuncOptions` is an alias of `torch::nn::*Options`.
Also as part of this PR, we change all functional options to pass-by-value, to make the semantics consistent across all functionals.
Test Plan: Imported from OSS
Differential Revision: D18376977
Pulled By: yf225
fbshipit-source-id: 8d9c240d93bfd5af0165b6884fdc912476b1d06b
2019-11-09 06:36:49 +00:00
|
|
|
auto options = F::GridSampleFuncOptions()
|
2019-11-13 00:02:38 +00:00
|
|
|
.mode(torch::kBilinear)
|
|
|
|
|
.padding_mode(torch::kZeros)
|
2019-10-24 22:12:55 +00:00
|
|
|
.align_corners(true);
|
|
|
|
|
auto output = F::grid_sample(input, grid, options);
|
|
|
|
|
auto expected = torch::tensor({{{{0., 0., 1.}, {3., 4., 5.}, {7., 8., 0.}}}}, torch::kFloat);
|
|
|
|
|
|
|
|
|
|
ASSERT_TRUE(output.allclose(expected));
|
|
|
|
|
|
|
|
|
|
// bilinear, zeros, false
|
Pass F::*FuncOptions instead of torch::nn::*Options to functionals, and make F::*FuncOptions a different class when necessary (#29364)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/29364
Currently, we use `torch::nn::*Options` both as module options and functional options. However, this makes it very hard to manage the parameters in `torch::nn::*Options`, because a module's constructor can take a different set of arguments than the module's equivalent functional (e.g. `torch.nn.BatchNorm1d` takes `num_features, eps=1e-5, momentum=0.1, affine=True,
track_running_stats=True`, while `F::batch_norm` takes `running_mean, running_var, weight=None, bias=None, training=False, momentum=0.1, eps=1e-5`).
This PR resolves the above problem by making `F::*FuncOptions` a different class from `torch::nn::*Options` when necessary (i.e. when a module's constructor takes a different set of arguments than the module's equivalent functional). In the rest of the cases where the module constructor takes the same set of arguments as the module's equivalent functional, `F::*FuncOptions` is an alias of `torch::nn::*Options`.
Also as part of this PR, we change all functional options to pass-by-value, to make the semantics consistent across all functionals.
Test Plan: Imported from OSS
Differential Revision: D18376977
Pulled By: yf225
fbshipit-source-id: 8d9c240d93bfd5af0165b6884fdc912476b1d06b
2019-11-09 06:36:49 +00:00
|
|
|
options = F::GridSampleFuncOptions()
|
2019-11-13 00:02:38 +00:00
|
|
|
.mode(torch::kBilinear)
|
|
|
|
|
.padding_mode(torch::kZeros)
|
2019-10-24 22:12:55 +00:00
|
|
|
.align_corners(false);
|
|
|
|
|
output = F::grid_sample(input, grid, options);
|
|
|
|
|
expected = torch::tensor({{{{0., 0., 0.5}, {1.5, 4., 2.5}, {3.5, 2., 0.}}}}, torch::kFloat);
|
|
|
|
|
|
|
|
|
|
ASSERT_TRUE(output.allclose(expected));
|
|
|
|
|
|
|
|
|
|
// default options (bilinear, zeros, false) same result as above
|
|
|
|
|
output = F::grid_sample(input, grid);
|
|
|
|
|
|
|
|
|
|
ASSERT_TRUE(output.allclose(expected));
|
|
|
|
|
|
|
|
|
|
// nearest, zeros, true
|
Pass F::*FuncOptions instead of torch::nn::*Options to functionals, and make F::*FuncOptions a different class when necessary (#29364)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/29364
Currently, we use `torch::nn::*Options` both as module options and functional options. However, this makes it very hard to manage the parameters in `torch::nn::*Options`, because a module's constructor can take a different set of arguments than the module's equivalent functional (e.g. `torch.nn.BatchNorm1d` takes `num_features, eps=1e-5, momentum=0.1, affine=True,
track_running_stats=True`, while `F::batch_norm` takes `running_mean, running_var, weight=None, bias=None, training=False, momentum=0.1, eps=1e-5`).
This PR resolves the above problem by making `F::*FuncOptions` a different class from `torch::nn::*Options` when necessary (i.e. when a module's constructor takes a different set of arguments than the module's equivalent functional). In the rest of the cases where the module constructor takes the same set of arguments as the module's equivalent functional, `F::*FuncOptions` is an alias of `torch::nn::*Options`.
Also as part of this PR, we change all functional options to pass-by-value, to make the semantics consistent across all functionals.
Test Plan: Imported from OSS
Differential Revision: D18376977
Pulled By: yf225
fbshipit-source-id: 8d9c240d93bfd5af0165b6884fdc912476b1d06b
2019-11-09 06:36:49 +00:00
|
|
|
options = F::GridSampleFuncOptions()
|
2019-11-13 00:02:38 +00:00
|
|
|
.mode(torch::kNearest)
|
|
|
|
|
.padding_mode(torch::kZeros)
|
2019-10-24 22:12:55 +00:00
|
|
|
.align_corners(true);
|
|
|
|
|
output = F::grid_sample(input, grid, options);
|
|
|
|
|
expected = torch::tensor({{{{0., 0., 1.}, {3., 4., 5.}, {7., 8., 0.}}}}, torch::kFloat);
|
|
|
|
|
|
|
|
|
|
ASSERT_TRUE(output.allclose(expected));
|
|
|
|
|
|
|
|
|
|
// bilinear, border, true
|
Pass F::*FuncOptions instead of torch::nn::*Options to functionals, and make F::*FuncOptions a different class when necessary (#29364)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/29364
Currently, we use `torch::nn::*Options` both as module options and functional options. However, this makes it very hard to manage the parameters in `torch::nn::*Options`, because a module's constructor can take a different set of arguments than the module's equivalent functional (e.g. `torch.nn.BatchNorm1d` takes `num_features, eps=1e-5, momentum=0.1, affine=True,
track_running_stats=True`, while `F::batch_norm` takes `running_mean, running_var, weight=None, bias=None, training=False, momentum=0.1, eps=1e-5`).
This PR resolves the above problem by making `F::*FuncOptions` a different class from `torch::nn::*Options` when necessary (i.e. when a module's constructor takes a different set of arguments than the module's equivalent functional). In the rest of the cases where the module constructor takes the same set of arguments as the module's equivalent functional, `F::*FuncOptions` is an alias of `torch::nn::*Options`.
Also as part of this PR, we change all functional options to pass-by-value, to make the semantics consistent across all functionals.
Test Plan: Imported from OSS
Differential Revision: D18376977
Pulled By: yf225
fbshipit-source-id: 8d9c240d93bfd5af0165b6884fdc912476b1d06b
2019-11-09 06:36:49 +00:00
|
|
|
options = F::GridSampleFuncOptions()
|
2019-11-13 00:02:38 +00:00
|
|
|
.mode(torch::kBilinear)
|
|
|
|
|
.padding_mode(torch::kBorder)
|
2019-10-24 22:12:55 +00:00
|
|
|
.align_corners(true);
|
|
|
|
|
output = F::grid_sample(input, grid, options);
|
|
|
|
|
expected = torch::tensor({{{{0., 0., 1.}, {3., 4., 5.}, {7., 8., 8.}}}}, torch::kFloat);
|
|
|
|
|
|
|
|
|
|
ASSERT_TRUE(output.allclose(expected));
|
|
|
|
|
|
|
|
|
|
// bilinear, reflection, true
|
Pass F::*FuncOptions instead of torch::nn::*Options to functionals, and make F::*FuncOptions a different class when necessary (#29364)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/29364
Currently, we use `torch::nn::*Options` both as module options and functional options. However, this makes it very hard to manage the parameters in `torch::nn::*Options`, because a module's constructor can take a different set of arguments than the module's equivalent functional (e.g. `torch.nn.BatchNorm1d` takes `num_features, eps=1e-5, momentum=0.1, affine=True,
track_running_stats=True`, while `F::batch_norm` takes `running_mean, running_var, weight=None, bias=None, training=False, momentum=0.1, eps=1e-5`).
This PR resolves the above problem by making `F::*FuncOptions` a different class from `torch::nn::*Options` when necessary (i.e. when a module's constructor takes a different set of arguments than the module's equivalent functional). In the rest of the cases where the module constructor takes the same set of arguments as the module's equivalent functional, `F::*FuncOptions` is an alias of `torch::nn::*Options`.
Also as part of this PR, we change all functional options to pass-by-value, to make the semantics consistent across all functionals.
Test Plan: Imported from OSS
Differential Revision: D18376977
Pulled By: yf225
fbshipit-source-id: 8d9c240d93bfd5af0165b6884fdc912476b1d06b
2019-11-09 06:36:49 +00:00
|
|
|
options = F::GridSampleFuncOptions()
|
2019-11-13 00:02:38 +00:00
|
|
|
.mode(torch::kBilinear)
|
|
|
|
|
.padding_mode(torch::kReflection)
|
2019-10-24 22:12:55 +00:00
|
|
|
.align_corners(true);
|
|
|
|
|
output = F::grid_sample(input, grid, options);
|
|
|
|
|
expected = torch::tensor({{{{1., 0., 1.}, {3., 4., 5.}, {7., 8., 7.}}}}, torch::kFloat);
|
|
|
|
|
|
|
|
|
|
ASSERT_TRUE(output.allclose(expected));
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-10 06:16:11 +00:00
|
|
|
TEST_F(FunctionalTest, AffineGrid) {
|
|
|
|
|
{
|
|
|
|
|
// 2D affine.
|
2019-11-13 23:14:08 +00:00
|
|
|
auto theta = torch::arange(1., 13)
|
2019-10-15 00:58:14 +00:00
|
|
|
.view(std::vector<int64_t>({2, 2, 3}));
|
|
|
|
|
auto size = std::vector<int64_t>({2, 3, 2, 2});
|
2019-10-10 06:16:11 +00:00
|
|
|
auto align_corners = true;
|
|
|
|
|
auto output = F::affine_grid(theta, size, !align_corners);
|
|
|
|
|
auto expected = torch::tensor(
|
|
|
|
|
{{{{1.50, 1.50}, {2.50, 5.50}}, {{3.50, 6.50}, {4.50, 10.50}}},
|
|
|
|
|
{{{1.50, 1.50}, {8.50, 11.50}}, {{9.50, 12.50}, {16.50, 22.50}}}});
|
|
|
|
|
auto output_aligned = F::affine_grid(theta, size, align_corners);
|
|
|
|
|
auto expected_aligned = torch::tensor(
|
|
|
|
|
{{{{0.0, -3.0}, {2.0, 5.0}}, {{4.0, 7.0}, {6.0, 15.0}}},
|
|
|
|
|
{{{-6.0, -9.0}, {8.0, 11.0}}, {{10.0, 13.0}, {24.0, 33.0}}}});
|
|
|
|
|
|
|
|
|
|
ASSERT_TRUE(output.allclose(expected));
|
|
|
|
|
ASSERT_TRUE(output_aligned.allclose(expected_aligned));
|
|
|
|
|
}
|
|
|
|
|
{
|
|
|
|
|
// 3D affine.
|
2019-11-13 23:14:08 +00:00
|
|
|
auto theta = torch::arange(1., 13)
|
2019-10-15 00:58:14 +00:00
|
|
|
.view(std::vector<int64_t>({1, 3, 4}));
|
|
|
|
|
auto size = std::vector<int64_t>({1, 1, 3, 2, 2});
|
2019-10-10 06:16:11 +00:00
|
|
|
auto align_corners = true;
|
|
|
|
|
auto output = F::affine_grid(theta, size, !align_corners);
|
|
|
|
|
auto expected = torch::tensor(
|
|
|
|
|
{{{{{0.5000, -2.1667, -4.8333}, {1.5000, 2.8333, 4.1667}},
|
|
|
|
|
{{2.5000, 3.8333, 5.1667}, {3.5000, 8.8333, 14.1667}}},
|
|
|
|
|
{{{2.5000, 2.5000, 2.5000}, {3.5000, 7.5000, 11.5000}},
|
|
|
|
|
{{4.5000, 8.5000, 12.5000}, {5.5000, 13.5000, 21.5000}}},
|
|
|
|
|
{{{4.5000, 7.1667, 9.8333}, {5.5000, 12.1667, 18.8333}},
|
|
|
|
|
{{6.5000, 13.1667, 19.8333}, {7.5000, 18.1667, 28.8333}}}}});
|
|
|
|
|
auto output_aligned = F::affine_grid(theta, size, align_corners);
|
|
|
|
|
auto expected_aligned =
|
|
|
|
|
torch::tensor({{{{{-2.0, -10.0, -18.0}, {0.0, 0.0, 0.0}},
|
|
|
|
|
{{2.0, 2.0, 2.0}, {4.0, 12.0, 20.0}}},
|
|
|
|
|
{{{1.0, -3.0, -7.0}, {3.0, 7.0, 11.0}},
|
|
|
|
|
{{5.0, 9.0, 13.0}, {7.0, 19.0, 31.0}}},
|
|
|
|
|
{{{4.0, 4.0, 4.0}, {6.0, 14.0, 22.0}},
|
|
|
|
|
{{8.0, 16.0, 24.0}, {10.0, 26.0, 42.0}}}}});
|
|
|
|
|
|
|
|
|
|
ASSERT_TRUE(output.allclose(expected, 1e-2));
|
|
|
|
|
ASSERT_TRUE(output_aligned.allclose(expected_aligned));
|
|
|
|
|
}
|
|
|
|
|
{
|
|
|
|
|
auto theta = torch::empty({1, 2, 3}, torch::kDouble);
|
2019-10-15 00:58:14 +00:00
|
|
|
auto size = std::vector<int64_t>({1, 1, 2, 2});
|
2019-10-10 06:16:11 +00:00
|
|
|
ASSERT_THROWS_WITH(
|
|
|
|
|
F::affine_grid(torch::empty({2, 2, 3}), {-1, 1, 2, 2}),
|
|
|
|
|
"Expected non-zero, positive output size. Got [-1, 1, 2, 2]");
|
|
|
|
|
ASSERT_THROWS_WITH(
|
|
|
|
|
F::affine_grid(torch::empty({2, 2, 3}, torch::kInt), size),
|
|
|
|
|
"Expected theta to have floating point type, but got int");
|
|
|
|
|
ASSERT_THROWS_WITH(
|
|
|
|
|
F::affine_grid(theta[0], size),
|
|
|
|
|
"Expected a batch of 2D affine matrices of shape Nx2x3 for size "
|
|
|
|
|
"[1, 1, 2, 2]. Got [2, 3].");
|
|
|
|
|
ASSERT_THROWS_WITH(
|
|
|
|
|
F::affine_grid(theta.unsqueeze(0), size),
|
|
|
|
|
"Expected a batch of 2D affine matrices of shape Nx2x3 for size "
|
|
|
|
|
"[1, 1, 2, 2]. Got [1, 1, 2, 3].");
|
|
|
|
|
ASSERT_THROWS_WITH(
|
|
|
|
|
F::affine_grid(theta.repeat({1, 2, 1}), size),
|
|
|
|
|
"Expected a batch of 2D affine matrices of shape Nx2x3 for size "
|
|
|
|
|
"[1, 1, 2, 2]. Got [1, 4, 3].");
|
|
|
|
|
ASSERT_THROWS_WITH(
|
|
|
|
|
F::affine_grid(theta.repeat({1, 1, 2}), size),
|
|
|
|
|
"Expected a batch of 2D affine matrices of shape Nx2x3 for size "
|
|
|
|
|
"[1, 1, 2, 2]. Got [1, 2, 6].");
|
|
|
|
|
}
|
|
|
|
|
{
|
|
|
|
|
auto theta = torch::empty({1, 3, 4}, torch::kDouble);
|
2019-10-15 00:58:14 +00:00
|
|
|
auto size = std::vector<int64_t>({1, 1, 2, 2, 3});
|
2019-10-10 06:16:11 +00:00
|
|
|
ASSERT_THROWS_WITH(
|
|
|
|
|
F::affine_grid(theta[0], size),
|
|
|
|
|
"Expected a batch of 3D affine matrices of shape Nx3x4 for size "
|
|
|
|
|
"[1, 1, 2, 2, 3]. Got [3, 4].");
|
|
|
|
|
ASSERT_THROWS_WITH(
|
|
|
|
|
F::affine_grid(theta.unsqueeze(0), size),
|
|
|
|
|
"Expected a batch of 3D affine matrices of shape Nx3x4 for size "
|
|
|
|
|
"[1, 1, 2, 2, 3]. Got [1, 1, 3, 4].");
|
|
|
|
|
ASSERT_THROWS_WITH(
|
|
|
|
|
F::affine_grid(theta.repeat({1, 2, 1}), size),
|
|
|
|
|
"Expected a batch of 3D affine matrices of shape Nx3x4 for size "
|
|
|
|
|
"[1, 1, 2, 2, 3]. Got [1, 6, 4].");
|
|
|
|
|
ASSERT_THROWS_WITH(
|
|
|
|
|
F::affine_grid(theta.repeat({1, 1, 2}), size),
|
|
|
|
|
"Expected a batch of 3D affine matrices of shape Nx3x4 for size "
|
|
|
|
|
"[1, 1, 2, 2, 3]. Got [1, 3, 8].");
|
|
|
|
|
ASSERT_THROWS_WITH(
|
|
|
|
|
F::affine_grid(theta, {1, 1, 1, 2, 2, 3}),
|
|
|
|
|
"affine_grid only supports 4D and 5D sizes, for 2D and 3D affine "
|
|
|
|
|
"transforms, respectively. Got size [1, 1, 1, 2, 2, 3]");
|
|
|
|
|
ASSERT_THROWS_WITH(
|
|
|
|
|
F::affine_grid(theta, {1, 1}),
|
|
|
|
|
"affine_grid only supports 4D and 5D sizes, for 2D and 3D affine "
|
|
|
|
|
"transforms, respectively. Got size [1, 1]");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-09 21:43:07 +00:00
|
|
|
TEST_F(FunctionalTest, MultiMarginLoss) {
|
|
|
|
|
auto weight = torch::tensor({0.3, 0.3, 0.4}, torch::kFloat);
|
Fix bugs in torch::tensor constructor (#28523)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/28523
New features:
1. Previously, `torch::tensor({true, false, true})` throws `"tensor_cpu" not implemented for 'Bool'`. After this PR, it produces the correct bool tensor, matching the Python API behavior.
2. Tensors with zero-size dimensions are now supported, e.g. `torch::tensor({{}, {}})` produces a tensor with sizes `{2, 0}`, matching the Python API behavior.
BC-breaking bug fixes:
1. Previously, `torch::tensor({{1}, {2}})` produces a tensor of sizes `{2}`. After this PR, it produces a tensor of sizes `{2, 1}`, matching the Python API behavior.
2. Fixed semantics of `torch::tensor(1.1)`: it now returns a 0-dim tensor instead of a 1-dim tensor, matching the Python API behavior.
3. Previously, when passed a non-dtype `TensorOptions` to the `torch::tensor` constructor, it always produces a tensor of dtype `float`. After this PR, it produces tensor of different dtypes based on the dtype of the braced-init-list, matching the behavior of the no-options case.
```cpp
// Previously:
torch::tensor({1, 2, 3}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> float
torch::tensor({{1, 2, 3}}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> float
torch::tensor({1., 2., 3.}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> float
torch::tensor({{1., 2., 3.}}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> float
// Now:
torch::tensor({1, 2, 3}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> int
torch::tensor({{1, 2, 3}}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> int
torch::tensor({1., 2., 3.}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> double
torch::tensor({{1., 2., 3.}}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> double
// As comparison, currently:
torch::tensor({1, 2, 3}).dtype() -> int
torch::tensor({{1, 2, 3}}).dtype() -> int
torch::tensor({1., 2., 3.}).dtype() -> double
torch::tensor({{1., 2., 3.}}).dtype() -> double
```
Notes:
1. From now on, the behavior of `at::tensor(scalar_value)` (which produces a 1-dim tensor) would be different from `torch::tensor(scalar_value)` (which produces a 0-dim tensor). I will fix the behavior of `at::tensor(scalar_value)` in a follow-up PR.
2. From now on, the behavior of `at::tensor({1, 2, 3}, torch::TensorOptions(/*non-dtype-options*/))` (which produces a `float` tensor) would be different from `torch::tensor({1, 2, 3}, torch::TensorOptions(/*non-dtype-options*/))` (which produces a an `int` tensor). I will fix this behavior of `at::tensor` constructor in a follow-up PR.
Context for the changes in this PR:
The motivation comes from fixing the "`torch::tensor({{1}, {2}})` gives tensor of wrong sizes" bug - in order to fix it, I have to move the handling of `at::ArrayRef` and `std::vector` into `InitListTensor` (see below on why we need to do this) and renamed `InitListTensor` to `TensorDataContainer`. After such changes, support for bool values comes out of the box without extra effort, and support for tensors with zero-size dimensions only requires adding a default constructor for `TensorDataContainer`, so I added those two in this PR.
For the semantic change of `torch::tensor(1.1)`, it's actually more effort to preserve the original wrong behavior (i.e. we need to check the sizes of the tensor converted from `TensorDataContainer` and reshape any scalar tensor to a 1-D tensor). I think preserving the original wrong behavior doesn't give us much value, and since the above changes naturally fix the problem, we should just start using the right behavior instead.
For the "constructor with non-dtype options behavior" fix, the code looks simpler and easier to reason about with the fix, so I included it in this PR.
--------
Why we need to move the handling of `at::ArrayRef` and `std::vector` into `TensorDataContainer`:
`torch::tensor({{1}, {2}})` can match this function overload:
`torch::tensor(at::ArrayRef<int> values)`, because `{1}` and `{2}` can be treated as
a list-initialization of an `int` value. However, this will produce a Tensor with sizes `{2}`,
but we actually want a Tensor with sizes `{2, 1}`. In order to avoid matching this function overload,
we removed the function overload and moved the ability to convert `at::ArrayRef<T>`
(and similarly `std::vector<T>`) into `TensorDataContainer`, and since for braced-init-list the
`TensorDataContainer(std::initializer_list<TensorDataContainer>)` constructor is always preferred over all other constructors, it will take the `std::initializer_list` path, and all is good.
Test Plan: Imported from OSS
Differential Revision: D18234625
Pulled By: yf225
fbshipit-source-id: 0f3f6912e82e2117d2103e31b74e7e97baaa8693
2019-10-31 19:51:18 +00:00
|
|
|
auto input = torch::tensor(
|
|
|
|
|
{{0.2, 0.2, 0.6}, {0.1, 0.8, 0.1}, {0.9, 0.09, 0.01}},
|
|
|
|
|
torch::dtype(torch::kFloat).requires_grad(true));
|
2019-10-09 21:43:07 +00:00
|
|
|
auto target = torch::tensor({2, 1, 0}, torch::kLong);
|
|
|
|
|
auto output = F::multi_margin_loss(
|
Pass F::*FuncOptions instead of torch::nn::*Options to functionals, and make F::*FuncOptions a different class when necessary (#29364)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/29364
Currently, we use `torch::nn::*Options` both as module options and functional options. However, this makes it very hard to manage the parameters in `torch::nn::*Options`, because a module's constructor can take a different set of arguments than the module's equivalent functional (e.g. `torch.nn.BatchNorm1d` takes `num_features, eps=1e-5, momentum=0.1, affine=True,
track_running_stats=True`, while `F::batch_norm` takes `running_mean, running_var, weight=None, bias=None, training=False, momentum=0.1, eps=1e-5`).
This PR resolves the above problem by making `F::*FuncOptions` a different class from `torch::nn::*Options` when necessary (i.e. when a module's constructor takes a different set of arguments than the module's equivalent functional). In the rest of the cases where the module constructor takes the same set of arguments as the module's equivalent functional, `F::*FuncOptions` is an alias of `torch::nn::*Options`.
Also as part of this PR, we change all functional options to pass-by-value, to make the semantics consistent across all functionals.
Test Plan: Imported from OSS
Differential Revision: D18376977
Pulled By: yf225
fbshipit-source-id: 8d9c240d93bfd5af0165b6884fdc912476b1d06b
2019-11-09 06:36:49 +00:00
|
|
|
input, target, F::MultiMarginLossFuncOptions().margin(2).weight(weight));
|
2019-10-09 21:43:07 +00:00
|
|
|
auto expected = torch::tensor({0.305556}, torch::kFloat);
|
|
|
|
|
|
|
|
|
|
ASSERT_TRUE(output.allclose(expected, 1e-04));
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-08 17:47:40 +00:00
|
|
|
TEST_F(FunctionalTest, CosineEmbeddingLoss) {
|
|
|
|
|
auto input1 = torch::tensor({{2, 3, 4}, {6, 2, 4}});
|
|
|
|
|
auto input2 = torch::tensor({{2, 3, 5}, {9, 12, 0}});
|
|
|
|
|
auto target = torch::tensor({1, -1});
|
|
|
|
|
auto output = F::cosine_embedding_loss(
|
Pass F::*FuncOptions instead of torch::nn::*Options to functionals, and make F::*FuncOptions a different class when necessary (#29364)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/29364
Currently, we use `torch::nn::*Options` both as module options and functional options. However, this makes it very hard to manage the parameters in `torch::nn::*Options`, because a module's constructor can take a different set of arguments than the module's equivalent functional (e.g. `torch.nn.BatchNorm1d` takes `num_features, eps=1e-5, momentum=0.1, affine=True,
track_running_stats=True`, while `F::batch_norm` takes `running_mean, running_var, weight=None, bias=None, training=False, momentum=0.1, eps=1e-5`).
This PR resolves the above problem by making `F::*FuncOptions` a different class from `torch::nn::*Options` when necessary (i.e. when a module's constructor takes a different set of arguments than the module's equivalent functional). In the rest of the cases where the module constructor takes the same set of arguments as the module's equivalent functional, `F::*FuncOptions` is an alias of `torch::nn::*Options`.
Also as part of this PR, we change all functional options to pass-by-value, to make the semantics consistent across all functionals.
Test Plan: Imported from OSS
Differential Revision: D18376977
Pulled By: yf225
fbshipit-source-id: 8d9c240d93bfd5af0165b6884fdc912476b1d06b
2019-11-09 06:36:49 +00:00
|
|
|
input1, input2, target, F::CosineEmbeddingLossFuncOptions().margin(0.5));
|
2019-10-08 17:47:40 +00:00
|
|
|
auto expected = torch::tensor({0.1004}, torch::kFloat);
|
|
|
|
|
|
|
|
|
|
ASSERT_TRUE(output.allclose(expected, 1e-4));
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-16 22:42:53 +00:00
|
|
|
TEST_F(FunctionalTest, MultiLabelMarginLossDefaultOptions) {
|
Fix bugs in torch::tensor constructor (#28523)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/28523
New features:
1. Previously, `torch::tensor({true, false, true})` throws `"tensor_cpu" not implemented for 'Bool'`. After this PR, it produces the correct bool tensor, matching the Python API behavior.
2. Tensors with zero-size dimensions are now supported, e.g. `torch::tensor({{}, {}})` produces a tensor with sizes `{2, 0}`, matching the Python API behavior.
BC-breaking bug fixes:
1. Previously, `torch::tensor({{1}, {2}})` produces a tensor of sizes `{2}`. After this PR, it produces a tensor of sizes `{2, 1}`, matching the Python API behavior.
2. Fixed semantics of `torch::tensor(1.1)`: it now returns a 0-dim tensor instead of a 1-dim tensor, matching the Python API behavior.
3. Previously, when passed a non-dtype `TensorOptions` to the `torch::tensor` constructor, it always produces a tensor of dtype `float`. After this PR, it produces tensor of different dtypes based on the dtype of the braced-init-list, matching the behavior of the no-options case.
```cpp
// Previously:
torch::tensor({1, 2, 3}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> float
torch::tensor({{1, 2, 3}}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> float
torch::tensor({1., 2., 3.}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> float
torch::tensor({{1., 2., 3.}}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> float
// Now:
torch::tensor({1, 2, 3}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> int
torch::tensor({{1, 2, 3}}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> int
torch::tensor({1., 2., 3.}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> double
torch::tensor({{1., 2., 3.}}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> double
// As comparison, currently:
torch::tensor({1, 2, 3}).dtype() -> int
torch::tensor({{1, 2, 3}}).dtype() -> int
torch::tensor({1., 2., 3.}).dtype() -> double
torch::tensor({{1., 2., 3.}}).dtype() -> double
```
Notes:
1. From now on, the behavior of `at::tensor(scalar_value)` (which produces a 1-dim tensor) would be different from `torch::tensor(scalar_value)` (which produces a 0-dim tensor). I will fix the behavior of `at::tensor(scalar_value)` in a follow-up PR.
2. From now on, the behavior of `at::tensor({1, 2, 3}, torch::TensorOptions(/*non-dtype-options*/))` (which produces a `float` tensor) would be different from `torch::tensor({1, 2, 3}, torch::TensorOptions(/*non-dtype-options*/))` (which produces a an `int` tensor). I will fix this behavior of `at::tensor` constructor in a follow-up PR.
Context for the changes in this PR:
The motivation comes from fixing the "`torch::tensor({{1}, {2}})` gives tensor of wrong sizes" bug - in order to fix it, I have to move the handling of `at::ArrayRef` and `std::vector` into `InitListTensor` (see below on why we need to do this) and renamed `InitListTensor` to `TensorDataContainer`. After such changes, support for bool values comes out of the box without extra effort, and support for tensors with zero-size dimensions only requires adding a default constructor for `TensorDataContainer`, so I added those two in this PR.
For the semantic change of `torch::tensor(1.1)`, it's actually more effort to preserve the original wrong behavior (i.e. we need to check the sizes of the tensor converted from `TensorDataContainer` and reshape any scalar tensor to a 1-D tensor). I think preserving the original wrong behavior doesn't give us much value, and since the above changes naturally fix the problem, we should just start using the right behavior instead.
For the "constructor with non-dtype options behavior" fix, the code looks simpler and easier to reason about with the fix, so I included it in this PR.
--------
Why we need to move the handling of `at::ArrayRef` and `std::vector` into `TensorDataContainer`:
`torch::tensor({{1}, {2}})` can match this function overload:
`torch::tensor(at::ArrayRef<int> values)`, because `{1}` and `{2}` can be treated as
a list-initialization of an `int` value. However, this will produce a Tensor with sizes `{2}`,
but we actually want a Tensor with sizes `{2, 1}`. In order to avoid matching this function overload,
we removed the function overload and moved the ability to convert `at::ArrayRef<T>`
(and similarly `std::vector<T>`) into `TensorDataContainer`, and since for braced-init-list the
`TensorDataContainer(std::initializer_list<TensorDataContainer>)` constructor is always preferred over all other constructors, it will take the `std::initializer_list` path, and all is good.
Test Plan: Imported from OSS
Differential Revision: D18234625
Pulled By: yf225
fbshipit-source-id: 0f3f6912e82e2117d2103e31b74e7e97baaa8693
2019-10-31 19:51:18 +00:00
|
|
|
auto input = torch::tensor({{0.1, 0.2, 0.4, 0.8}}, torch::dtype(torch::kFloat).requires_grad(true));
|
2019-10-16 22:42:53 +00:00
|
|
|
auto target = torch::tensor({{3, 0, -1, 1}}, torch::kLong);
|
|
|
|
|
auto output = F::multilabel_margin_loss(input, target);
|
|
|
|
|
auto expected = torch::tensor({0.8500}, torch::kFloat);
|
|
|
|
|
auto s = output.sum();
|
|
|
|
|
s.backward();
|
|
|
|
|
|
|
|
|
|
ASSERT_TRUE(output.allclose(expected));
|
|
|
|
|
ASSERT_EQ(input.sizes(), input.grad().sizes());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(FunctionalTest, MultiLabelMarginLossNoReduction) {
|
Fix bugs in torch::tensor constructor (#28523)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/28523
New features:
1. Previously, `torch::tensor({true, false, true})` throws `"tensor_cpu" not implemented for 'Bool'`. After this PR, it produces the correct bool tensor, matching the Python API behavior.
2. Tensors with zero-size dimensions are now supported, e.g. `torch::tensor({{}, {}})` produces a tensor with sizes `{2, 0}`, matching the Python API behavior.
BC-breaking bug fixes:
1. Previously, `torch::tensor({{1}, {2}})` produces a tensor of sizes `{2}`. After this PR, it produces a tensor of sizes `{2, 1}`, matching the Python API behavior.
2. Fixed semantics of `torch::tensor(1.1)`: it now returns a 0-dim tensor instead of a 1-dim tensor, matching the Python API behavior.
3. Previously, when passed a non-dtype `TensorOptions` to the `torch::tensor` constructor, it always produces a tensor of dtype `float`. After this PR, it produces tensor of different dtypes based on the dtype of the braced-init-list, matching the behavior of the no-options case.
```cpp
// Previously:
torch::tensor({1, 2, 3}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> float
torch::tensor({{1, 2, 3}}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> float
torch::tensor({1., 2., 3.}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> float
torch::tensor({{1., 2., 3.}}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> float
// Now:
torch::tensor({1, 2, 3}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> int
torch::tensor({{1, 2, 3}}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> int
torch::tensor({1., 2., 3.}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> double
torch::tensor({{1., 2., 3.}}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> double
// As comparison, currently:
torch::tensor({1, 2, 3}).dtype() -> int
torch::tensor({{1, 2, 3}}).dtype() -> int
torch::tensor({1., 2., 3.}).dtype() -> double
torch::tensor({{1., 2., 3.}}).dtype() -> double
```
Notes:
1. From now on, the behavior of `at::tensor(scalar_value)` (which produces a 1-dim tensor) would be different from `torch::tensor(scalar_value)` (which produces a 0-dim tensor). I will fix the behavior of `at::tensor(scalar_value)` in a follow-up PR.
2. From now on, the behavior of `at::tensor({1, 2, 3}, torch::TensorOptions(/*non-dtype-options*/))` (which produces a `float` tensor) would be different from `torch::tensor({1, 2, 3}, torch::TensorOptions(/*non-dtype-options*/))` (which produces a an `int` tensor). I will fix this behavior of `at::tensor` constructor in a follow-up PR.
Context for the changes in this PR:
The motivation comes from fixing the "`torch::tensor({{1}, {2}})` gives tensor of wrong sizes" bug - in order to fix it, I have to move the handling of `at::ArrayRef` and `std::vector` into `InitListTensor` (see below on why we need to do this) and renamed `InitListTensor` to `TensorDataContainer`. After such changes, support for bool values comes out of the box without extra effort, and support for tensors with zero-size dimensions only requires adding a default constructor for `TensorDataContainer`, so I added those two in this PR.
For the semantic change of `torch::tensor(1.1)`, it's actually more effort to preserve the original wrong behavior (i.e. we need to check the sizes of the tensor converted from `TensorDataContainer` and reshape any scalar tensor to a 1-D tensor). I think preserving the original wrong behavior doesn't give us much value, and since the above changes naturally fix the problem, we should just start using the right behavior instead.
For the "constructor with non-dtype options behavior" fix, the code looks simpler and easier to reason about with the fix, so I included it in this PR.
--------
Why we need to move the handling of `at::ArrayRef` and `std::vector` into `TensorDataContainer`:
`torch::tensor({{1}, {2}})` can match this function overload:
`torch::tensor(at::ArrayRef<int> values)`, because `{1}` and `{2}` can be treated as
a list-initialization of an `int` value. However, this will produce a Tensor with sizes `{2}`,
but we actually want a Tensor with sizes `{2, 1}`. In order to avoid matching this function overload,
we removed the function overload and moved the ability to convert `at::ArrayRef<T>`
(and similarly `std::vector<T>`) into `TensorDataContainer`, and since for braced-init-list the
`TensorDataContainer(std::initializer_list<TensorDataContainer>)` constructor is always preferred over all other constructors, it will take the `std::initializer_list` path, and all is good.
Test Plan: Imported from OSS
Differential Revision: D18234625
Pulled By: yf225
fbshipit-source-id: 0f3f6912e82e2117d2103e31b74e7e97baaa8693
2019-10-31 19:51:18 +00:00
|
|
|
auto input = torch::tensor({{0.1, 0.2, 0.4, 0.8}}, torch::dtype(torch::kFloat).requires_grad(true));
|
2019-10-16 22:42:53 +00:00
|
|
|
auto target = torch::tensor({{3, 0, -1, 1}}, torch::kLong);
|
|
|
|
|
auto output = F::multilabel_margin_loss(
|
2019-10-29 21:13:37 +00:00
|
|
|
input, target, torch::kNone);
|
2019-10-16 22:42:53 +00:00
|
|
|
auto expected = torch::tensor({0.8500}, torch::kFloat);
|
|
|
|
|
auto s = output.sum();
|
|
|
|
|
s.backward();
|
|
|
|
|
|
|
|
|
|
ASSERT_TRUE(output.allclose(expected));
|
|
|
|
|
ASSERT_EQ(input.sizes(), input.grad().sizes());
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-13 17:56:07 +00:00
|
|
|
TEST_F(FunctionalTest, TripletMarginLoss) {
|
|
|
|
|
auto anchor = torch::tensor({{3., 3.}}, torch::kFloat);
|
|
|
|
|
auto positive = torch::tensor({{2., 2.}}, torch::kFloat);
|
|
|
|
|
auto negative = torch::tensor({{0., 0.}}, torch::kFloat);
|
|
|
|
|
auto output = F::triplet_margin_loss(
|
Pass F::*FuncOptions instead of torch::nn::*Options to functionals, and make F::*FuncOptions a different class when necessary (#29364)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/29364
Currently, we use `torch::nn::*Options` both as module options and functional options. However, this makes it very hard to manage the parameters in `torch::nn::*Options`, because a module's constructor can take a different set of arguments than the module's equivalent functional (e.g. `torch.nn.BatchNorm1d` takes `num_features, eps=1e-5, momentum=0.1, affine=True,
track_running_stats=True`, while `F::batch_norm` takes `running_mean, running_var, weight=None, bias=None, training=False, momentum=0.1, eps=1e-5`).
This PR resolves the above problem by making `F::*FuncOptions` a different class from `torch::nn::*Options` when necessary (i.e. when a module's constructor takes a different set of arguments than the module's equivalent functional). In the rest of the cases where the module constructor takes the same set of arguments as the module's equivalent functional, `F::*FuncOptions` is an alias of `torch::nn::*Options`.
Also as part of this PR, we change all functional options to pass-by-value, to make the semantics consistent across all functionals.
Test Plan: Imported from OSS
Differential Revision: D18376977
Pulled By: yf225
fbshipit-source-id: 8d9c240d93bfd5af0165b6884fdc912476b1d06b
2019-11-09 06:36:49 +00:00
|
|
|
anchor, positive, negative, F::TripletMarginLossFuncOptions().margin(1.0));
|
2019-10-13 17:56:07 +00:00
|
|
|
auto expected = torch::tensor({0.}, torch::kFloat);
|
|
|
|
|
|
|
|
|
|
ASSERT_TRUE(output.allclose(expected, 1e-04));
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-30 19:35:08 +00:00
|
|
|
TEST_F(FunctionalTest, TripletMarginWithDistanceLossDefaultParity) {
|
|
|
|
|
// Check that if we use torch::pairwise_distance with the default
|
|
|
|
|
// TripletMarginLoss options as our distance function, the outputs
|
|
|
|
|
// are equal (i.e., equal under defaults).
|
|
|
|
|
|
|
|
|
|
std::vector<TripletMarginWithDistanceLossOptions::reduction_t>
|
|
|
|
|
reductions = {torch::kSum, torch::kMean, torch::kNone};
|
|
|
|
|
std::vector<float> margins = {0.5, 1.0, 1.5};
|
|
|
|
|
std::vector<bool> swaps = {true, false};
|
|
|
|
|
|
|
|
|
|
for (auto& reduction : reductions) {
|
|
|
|
|
for (auto& margin : margins) {
|
|
|
|
|
for (const auto& swap : swaps) {
|
2021-03-06 01:19:22 +00:00
|
|
|
auto anchor =
|
2020-09-30 19:35:08 +00:00
|
|
|
torch::randn({100, 128}, torch::dtype(torch::kFloat).requires_grad(true));
|
|
|
|
|
auto positive =
|
|
|
|
|
torch::randn({100, 128}, torch::dtype(torch::kFloat).requires_grad(true));
|
|
|
|
|
auto negative =
|
|
|
|
|
torch::randn({100, 128}, torch::dtype(torch::kFloat).requires_grad(true));
|
|
|
|
|
|
|
|
|
|
auto basicOptions = F::TripletMarginLossFuncOptions()
|
|
|
|
|
.reduction(reduction)
|
|
|
|
|
.margin(margin)
|
|
|
|
|
.swap(swap);
|
|
|
|
|
auto distanceOptions =
|
|
|
|
|
F::TripletMarginWithDistanceLossFuncOptions()
|
|
|
|
|
.reduction(reduction)
|
|
|
|
|
.margin(margin)
|
|
|
|
|
.swap(swap);
|
|
|
|
|
TripletMarginLoss basicLoss(basicOptions);
|
|
|
|
|
TripletMarginWithDistanceLoss distanceLoss(distanceOptions);
|
|
|
|
|
|
|
|
|
|
auto basicOutput =
|
|
|
|
|
F::triplet_margin_loss(anchor, positive, negative, basicOptions);
|
|
|
|
|
auto distanceOutput = F::triplet_margin_with_distance_loss(
|
|
|
|
|
anchor, positive, negative, distanceOptions);
|
|
|
|
|
|
|
|
|
|
ASSERT_TRUE(distanceOutput.allclose(basicOutput, 1e-6, 1e-6));
|
|
|
|
|
|
|
|
|
|
// handle for torch::kNone reduction
|
|
|
|
|
auto sum = distanceOutput.sum();
|
|
|
|
|
sum.backward();
|
|
|
|
|
ASSERT_EQ(anchor.sizes(), anchor.grad().sizes());
|
|
|
|
|
ASSERT_EQ(positive.sizes(), positive.grad().sizes());
|
|
|
|
|
ASSERT_EQ(negative.sizes(), negative.grad().sizes());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-16 18:46:30 +00:00
|
|
|
TEST_F(FunctionalTest, NLLLoss) {
|
|
|
|
|
auto input = torch::tensor({{-0.1315, -3.1315, -2.5315},
|
|
|
|
|
{-3.7038, -0.1038, -2.6038},
|
|
|
|
|
{-2.3422, -1.3422, -0.4422}},
|
|
|
|
|
torch::kFloat);
|
2019-11-19 18:02:31 +00:00
|
|
|
auto target = torch::tensor({1, 0, 2}, torch::kLong);
|
2019-11-16 18:46:30 +00:00
|
|
|
auto output = F::nll_loss(
|
|
|
|
|
input, target, F::NLLLossFuncOptions().ignore_index(-100).reduction(torch::kMean));
|
|
|
|
|
auto expected = torch::tensor(2.4258, torch::kFloat);
|
|
|
|
|
ASSERT_TRUE(output.allclose(expected, 1e-04));
|
|
|
|
|
ASSERT_TRUE(F::nll_loss(input, target).allclose(expected, 1e-04));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(FunctionalTest, CrossEntropy) {
|
|
|
|
|
auto input = torch::tensor({{3., 3.}, {2., 2.}}, torch::kFloat);
|
|
|
|
|
auto target = torch::tensor({0, 1}, torch::kLong);
|
|
|
|
|
auto output = F::cross_entropy(
|
|
|
|
|
input, target, F::CrossEntropyFuncOptions().ignore_index(-100).reduction(torch::kMean));
|
|
|
|
|
auto expected = torch::tensor(0.6931, torch::kFloat);
|
|
|
|
|
|
|
|
|
|
ASSERT_TRUE(output.allclose(expected, 1e-04));
|
|
|
|
|
ASSERT_TRUE(F::cross_entropy(input, target).allclose(expected, 1e-04));
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-01 21:51:27 +00:00
|
|
|
TEST_F(FunctionalTest, MaxUnpool1d) {
|
Fix bugs in torch::tensor constructor (#28523)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/28523
New features:
1. Previously, `torch::tensor({true, false, true})` throws `"tensor_cpu" not implemented for 'Bool'`. After this PR, it produces the correct bool tensor, matching the Python API behavior.
2. Tensors with zero-size dimensions are now supported, e.g. `torch::tensor({{}, {}})` produces a tensor with sizes `{2, 0}`, matching the Python API behavior.
BC-breaking bug fixes:
1. Previously, `torch::tensor({{1}, {2}})` produces a tensor of sizes `{2}`. After this PR, it produces a tensor of sizes `{2, 1}`, matching the Python API behavior.
2. Fixed semantics of `torch::tensor(1.1)`: it now returns a 0-dim tensor instead of a 1-dim tensor, matching the Python API behavior.
3. Previously, when passed a non-dtype `TensorOptions` to the `torch::tensor` constructor, it always produces a tensor of dtype `float`. After this PR, it produces tensor of different dtypes based on the dtype of the braced-init-list, matching the behavior of the no-options case.
```cpp
// Previously:
torch::tensor({1, 2, 3}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> float
torch::tensor({{1, 2, 3}}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> float
torch::tensor({1., 2., 3.}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> float
torch::tensor({{1., 2., 3.}}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> float
// Now:
torch::tensor({1, 2, 3}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> int
torch::tensor({{1, 2, 3}}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> int
torch::tensor({1., 2., 3.}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> double
torch::tensor({{1., 2., 3.}}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> double
// As comparison, currently:
torch::tensor({1, 2, 3}).dtype() -> int
torch::tensor({{1, 2, 3}}).dtype() -> int
torch::tensor({1., 2., 3.}).dtype() -> double
torch::tensor({{1., 2., 3.}}).dtype() -> double
```
Notes:
1. From now on, the behavior of `at::tensor(scalar_value)` (which produces a 1-dim tensor) would be different from `torch::tensor(scalar_value)` (which produces a 0-dim tensor). I will fix the behavior of `at::tensor(scalar_value)` in a follow-up PR.
2. From now on, the behavior of `at::tensor({1, 2, 3}, torch::TensorOptions(/*non-dtype-options*/))` (which produces a `float` tensor) would be different from `torch::tensor({1, 2, 3}, torch::TensorOptions(/*non-dtype-options*/))` (which produces a an `int` tensor). I will fix this behavior of `at::tensor` constructor in a follow-up PR.
Context for the changes in this PR:
The motivation comes from fixing the "`torch::tensor({{1}, {2}})` gives tensor of wrong sizes" bug - in order to fix it, I have to move the handling of `at::ArrayRef` and `std::vector` into `InitListTensor` (see below on why we need to do this) and renamed `InitListTensor` to `TensorDataContainer`. After such changes, support for bool values comes out of the box without extra effort, and support for tensors with zero-size dimensions only requires adding a default constructor for `TensorDataContainer`, so I added those two in this PR.
For the semantic change of `torch::tensor(1.1)`, it's actually more effort to preserve the original wrong behavior (i.e. we need to check the sizes of the tensor converted from `TensorDataContainer` and reshape any scalar tensor to a 1-D tensor). I think preserving the original wrong behavior doesn't give us much value, and since the above changes naturally fix the problem, we should just start using the right behavior instead.
For the "constructor with non-dtype options behavior" fix, the code looks simpler and easier to reason about with the fix, so I included it in this PR.
--------
Why we need to move the handling of `at::ArrayRef` and `std::vector` into `TensorDataContainer`:
`torch::tensor({{1}, {2}})` can match this function overload:
`torch::tensor(at::ArrayRef<int> values)`, because `{1}` and `{2}` can be treated as
a list-initialization of an `int` value. However, this will produce a Tensor with sizes `{2}`,
but we actually want a Tensor with sizes `{2, 1}`. In order to avoid matching this function overload,
we removed the function overload and moved the ability to convert `at::ArrayRef<T>`
(and similarly `std::vector<T>`) into `TensorDataContainer`, and since for braced-init-list the
`TensorDataContainer(std::initializer_list<TensorDataContainer>)` constructor is always preferred over all other constructors, it will take the `std::initializer_list` path, and all is good.
Test Plan: Imported from OSS
Differential Revision: D18234625
Pulled By: yf225
fbshipit-source-id: 0f3f6912e82e2117d2103e31b74e7e97baaa8693
2019-10-31 19:51:18 +00:00
|
|
|
auto x = torch::tensor({{{2, 4, 5}}}, torch::dtype(torch::kFloat).requires_grad(true));
|
2019-10-01 21:51:27 +00:00
|
|
|
auto indices = torch::tensor({{{1, 3, 4}}}, torch::kLong);
|
Pass F::*FuncOptions instead of torch::nn::*Options to functionals, and make F::*FuncOptions a different class when necessary (#29364)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/29364
Currently, we use `torch::nn::*Options` both as module options and functional options. However, this makes it very hard to manage the parameters in `torch::nn::*Options`, because a module's constructor can take a different set of arguments than the module's equivalent functional (e.g. `torch.nn.BatchNorm1d` takes `num_features, eps=1e-5, momentum=0.1, affine=True,
track_running_stats=True`, while `F::batch_norm` takes `running_mean, running_var, weight=None, bias=None, training=False, momentum=0.1, eps=1e-5`).
This PR resolves the above problem by making `F::*FuncOptions` a different class from `torch::nn::*Options` when necessary (i.e. when a module's constructor takes a different set of arguments than the module's equivalent functional). In the rest of the cases where the module constructor takes the same set of arguments as the module's equivalent functional, `F::*FuncOptions` is an alias of `torch::nn::*Options`.
Also as part of this PR, we change all functional options to pass-by-value, to make the semantics consistent across all functionals.
Test Plan: Imported from OSS
Differential Revision: D18376977
Pulled By: yf225
fbshipit-source-id: 8d9c240d93bfd5af0165b6884fdc912476b1d06b
2019-11-09 06:36:49 +00:00
|
|
|
auto y = F::max_unpool1d(x, indices, F::MaxUnpool1dFuncOptions(3));
|
2019-10-01 21:51:27 +00:00
|
|
|
|
|
|
|
|
ASSERT_EQ(y.ndimension(), 3);
|
2019-10-03 00:26:27 +00:00
|
|
|
ASSERT_TRUE(torch::allclose(
|
|
|
|
|
y, torch::tensor({{{0, 2, 0, 4, 5, 0, 0, 0, 0}}}, torch::kFloat)));
|
2019-10-15 00:58:14 +00:00
|
|
|
ASSERT_EQ(y.sizes(), std::vector<int64_t>({1, 1, 9}));
|
2019-10-01 21:51:27 +00:00
|
|
|
|
Fix bugs in torch::tensor constructor (#28523)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/28523
New features:
1. Previously, `torch::tensor({true, false, true})` throws `"tensor_cpu" not implemented for 'Bool'`. After this PR, it produces the correct bool tensor, matching the Python API behavior.
2. Tensors with zero-size dimensions are now supported, e.g. `torch::tensor({{}, {}})` produces a tensor with sizes `{2, 0}`, matching the Python API behavior.
BC-breaking bug fixes:
1. Previously, `torch::tensor({{1}, {2}})` produces a tensor of sizes `{2}`. After this PR, it produces a tensor of sizes `{2, 1}`, matching the Python API behavior.
2. Fixed semantics of `torch::tensor(1.1)`: it now returns a 0-dim tensor instead of a 1-dim tensor, matching the Python API behavior.
3. Previously, when passed a non-dtype `TensorOptions` to the `torch::tensor` constructor, it always produces a tensor of dtype `float`. After this PR, it produces tensor of different dtypes based on the dtype of the braced-init-list, matching the behavior of the no-options case.
```cpp
// Previously:
torch::tensor({1, 2, 3}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> float
torch::tensor({{1, 2, 3}}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> float
torch::tensor({1., 2., 3.}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> float
torch::tensor({{1., 2., 3.}}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> float
// Now:
torch::tensor({1, 2, 3}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> int
torch::tensor({{1, 2, 3}}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> int
torch::tensor({1., 2., 3.}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> double
torch::tensor({{1., 2., 3.}}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> double
// As comparison, currently:
torch::tensor({1, 2, 3}).dtype() -> int
torch::tensor({{1, 2, 3}}).dtype() -> int
torch::tensor({1., 2., 3.}).dtype() -> double
torch::tensor({{1., 2., 3.}}).dtype() -> double
```
Notes:
1. From now on, the behavior of `at::tensor(scalar_value)` (which produces a 1-dim tensor) would be different from `torch::tensor(scalar_value)` (which produces a 0-dim tensor). I will fix the behavior of `at::tensor(scalar_value)` in a follow-up PR.
2. From now on, the behavior of `at::tensor({1, 2, 3}, torch::TensorOptions(/*non-dtype-options*/))` (which produces a `float` tensor) would be different from `torch::tensor({1, 2, 3}, torch::TensorOptions(/*non-dtype-options*/))` (which produces a an `int` tensor). I will fix this behavior of `at::tensor` constructor in a follow-up PR.
Context for the changes in this PR:
The motivation comes from fixing the "`torch::tensor({{1}, {2}})` gives tensor of wrong sizes" bug - in order to fix it, I have to move the handling of `at::ArrayRef` and `std::vector` into `InitListTensor` (see below on why we need to do this) and renamed `InitListTensor` to `TensorDataContainer`. After such changes, support for bool values comes out of the box without extra effort, and support for tensors with zero-size dimensions only requires adding a default constructor for `TensorDataContainer`, so I added those two in this PR.
For the semantic change of `torch::tensor(1.1)`, it's actually more effort to preserve the original wrong behavior (i.e. we need to check the sizes of the tensor converted from `TensorDataContainer` and reshape any scalar tensor to a 1-D tensor). I think preserving the original wrong behavior doesn't give us much value, and since the above changes naturally fix the problem, we should just start using the right behavior instead.
For the "constructor with non-dtype options behavior" fix, the code looks simpler and easier to reason about with the fix, so I included it in this PR.
--------
Why we need to move the handling of `at::ArrayRef` and `std::vector` into `TensorDataContainer`:
`torch::tensor({{1}, {2}})` can match this function overload:
`torch::tensor(at::ArrayRef<int> values)`, because `{1}` and `{2}` can be treated as
a list-initialization of an `int` value. However, this will produce a Tensor with sizes `{2}`,
but we actually want a Tensor with sizes `{2, 1}`. In order to avoid matching this function overload,
we removed the function overload and moved the ability to convert `at::ArrayRef<T>`
(and similarly `std::vector<T>`) into `TensorDataContainer`, and since for braced-init-list the
`TensorDataContainer(std::initializer_list<TensorDataContainer>)` constructor is always preferred over all other constructors, it will take the `std::initializer_list` path, and all is good.
Test Plan: Imported from OSS
Differential Revision: D18234625
Pulled By: yf225
fbshipit-source-id: 0f3f6912e82e2117d2103e31b74e7e97baaa8693
2019-10-31 19:51:18 +00:00
|
|
|
x = torch::tensor({{{2, 4, 5}}}, torch::dtype(torch::kFloat).requires_grad(true));
|
2019-10-01 21:51:27 +00:00
|
|
|
indices = torch::tensor({{{1, 3, 4}}}, torch::kLong);
|
2019-10-03 00:26:27 +00:00
|
|
|
y = F::max_unpool1d(
|
2019-11-13 00:02:38 +00:00
|
|
|
x, indices, F::MaxUnpool1dFuncOptions(3).output_size(std::vector<int64_t>({1, 1, 9})));
|
2019-10-01 21:51:27 +00:00
|
|
|
|
|
|
|
|
ASSERT_EQ(y.ndimension(), 3);
|
2019-10-03 00:26:27 +00:00
|
|
|
ASSERT_TRUE(torch::allclose(
|
|
|
|
|
y, torch::tensor({{{0, 2, 0, 4, 5, 0, 0, 0, 0}}}, torch::kFloat)));
|
2019-10-15 00:58:14 +00:00
|
|
|
ASSERT_EQ(y.sizes(), std::vector<int64_t>({1, 1, 9}));
|
2019-10-01 21:51:27 +00:00
|
|
|
|
Fix bugs in torch::tensor constructor (#28523)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/28523
New features:
1. Previously, `torch::tensor({true, false, true})` throws `"tensor_cpu" not implemented for 'Bool'`. After this PR, it produces the correct bool tensor, matching the Python API behavior.
2. Tensors with zero-size dimensions are now supported, e.g. `torch::tensor({{}, {}})` produces a tensor with sizes `{2, 0}`, matching the Python API behavior.
BC-breaking bug fixes:
1. Previously, `torch::tensor({{1}, {2}})` produces a tensor of sizes `{2}`. After this PR, it produces a tensor of sizes `{2, 1}`, matching the Python API behavior.
2. Fixed semantics of `torch::tensor(1.1)`: it now returns a 0-dim tensor instead of a 1-dim tensor, matching the Python API behavior.
3. Previously, when passed a non-dtype `TensorOptions` to the `torch::tensor` constructor, it always produces a tensor of dtype `float`. After this PR, it produces tensor of different dtypes based on the dtype of the braced-init-list, matching the behavior of the no-options case.
```cpp
// Previously:
torch::tensor({1, 2, 3}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> float
torch::tensor({{1, 2, 3}}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> float
torch::tensor({1., 2., 3.}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> float
torch::tensor({{1., 2., 3.}}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> float
// Now:
torch::tensor({1, 2, 3}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> int
torch::tensor({{1, 2, 3}}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> int
torch::tensor({1., 2., 3.}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> double
torch::tensor({{1., 2., 3.}}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> double
// As comparison, currently:
torch::tensor({1, 2, 3}).dtype() -> int
torch::tensor({{1, 2, 3}}).dtype() -> int
torch::tensor({1., 2., 3.}).dtype() -> double
torch::tensor({{1., 2., 3.}}).dtype() -> double
```
Notes:
1. From now on, the behavior of `at::tensor(scalar_value)` (which produces a 1-dim tensor) would be different from `torch::tensor(scalar_value)` (which produces a 0-dim tensor). I will fix the behavior of `at::tensor(scalar_value)` in a follow-up PR.
2. From now on, the behavior of `at::tensor({1, 2, 3}, torch::TensorOptions(/*non-dtype-options*/))` (which produces a `float` tensor) would be different from `torch::tensor({1, 2, 3}, torch::TensorOptions(/*non-dtype-options*/))` (which produces a an `int` tensor). I will fix this behavior of `at::tensor` constructor in a follow-up PR.
Context for the changes in this PR:
The motivation comes from fixing the "`torch::tensor({{1}, {2}})` gives tensor of wrong sizes" bug - in order to fix it, I have to move the handling of `at::ArrayRef` and `std::vector` into `InitListTensor` (see below on why we need to do this) and renamed `InitListTensor` to `TensorDataContainer`. After such changes, support for bool values comes out of the box without extra effort, and support for tensors with zero-size dimensions only requires adding a default constructor for `TensorDataContainer`, so I added those two in this PR.
For the semantic change of `torch::tensor(1.1)`, it's actually more effort to preserve the original wrong behavior (i.e. we need to check the sizes of the tensor converted from `TensorDataContainer` and reshape any scalar tensor to a 1-D tensor). I think preserving the original wrong behavior doesn't give us much value, and since the above changes naturally fix the problem, we should just start using the right behavior instead.
For the "constructor with non-dtype options behavior" fix, the code looks simpler and easier to reason about with the fix, so I included it in this PR.
--------
Why we need to move the handling of `at::ArrayRef` and `std::vector` into `TensorDataContainer`:
`torch::tensor({{1}, {2}})` can match this function overload:
`torch::tensor(at::ArrayRef<int> values)`, because `{1}` and `{2}` can be treated as
a list-initialization of an `int` value. However, this will produce a Tensor with sizes `{2}`,
but we actually want a Tensor with sizes `{2, 1}`. In order to avoid matching this function overload,
we removed the function overload and moved the ability to convert `at::ArrayRef<T>`
(and similarly `std::vector<T>`) into `TensorDataContainer`, and since for braced-init-list the
`TensorDataContainer(std::initializer_list<TensorDataContainer>)` constructor is always preferred over all other constructors, it will take the `std::initializer_list` path, and all is good.
Test Plan: Imported from OSS
Differential Revision: D18234625
Pulled By: yf225
fbshipit-source-id: 0f3f6912e82e2117d2103e31b74e7e97baaa8693
2019-10-31 19:51:18 +00:00
|
|
|
x = torch::tensor({{{2, 4, 5}}}, torch::dtype(torch::kFloat).requires_grad(true));
|
2019-10-01 21:51:27 +00:00
|
|
|
indices = torch::tensor({{{1, 3, 4}}}, torch::kLong);
|
Pass F::*FuncOptions instead of torch::nn::*Options to functionals, and make F::*FuncOptions a different class when necessary (#29364)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/29364
Currently, we use `torch::nn::*Options` both as module options and functional options. However, this makes it very hard to manage the parameters in `torch::nn::*Options`, because a module's constructor can take a different set of arguments than the module's equivalent functional (e.g. `torch.nn.BatchNorm1d` takes `num_features, eps=1e-5, momentum=0.1, affine=True,
track_running_stats=True`, while `F::batch_norm` takes `running_mean, running_var, weight=None, bias=None, training=False, momentum=0.1, eps=1e-5`).
This PR resolves the above problem by making `F::*FuncOptions` a different class from `torch::nn::*Options` when necessary (i.e. when a module's constructor takes a different set of arguments than the module's equivalent functional). In the rest of the cases where the module constructor takes the same set of arguments as the module's equivalent functional, `F::*FuncOptions` is an alias of `torch::nn::*Options`.
Also as part of this PR, we change all functional options to pass-by-value, to make the semantics consistent across all functionals.
Test Plan: Imported from OSS
Differential Revision: D18376977
Pulled By: yf225
fbshipit-source-id: 8d9c240d93bfd5af0165b6884fdc912476b1d06b
2019-11-09 06:36:49 +00:00
|
|
|
y = F::max_unpool1d(x, indices, F::MaxUnpool1dFuncOptions(3).stride(2).padding(1));
|
2019-10-01 21:51:27 +00:00
|
|
|
|
|
|
|
|
ASSERT_EQ(y.ndimension(), 3);
|
2019-10-03 00:26:27 +00:00
|
|
|
ASSERT_TRUE(
|
|
|
|
|
torch::allclose(y, torch::tensor({{{0, 2, 0, 4, 5}}}, torch::kFloat)));
|
2019-10-15 00:58:14 +00:00
|
|
|
ASSERT_EQ(y.sizes(), std::vector<int64_t>({1, 1, 5}));
|
2019-10-01 21:51:27 +00:00
|
|
|
}
|
2019-10-02 02:27:48 +00:00
|
|
|
|
|
|
|
|
TEST_F(FunctionalTest, MaxUnpool2d) {
|
|
|
|
|
auto indices = torch::tensor({
|
|
|
|
|
{{{ 6, 8, 9},
|
|
|
|
|
{16, 18, 19},
|
|
|
|
|
{21, 23, 24}}},
|
|
|
|
|
{{{ 6, 8, 9},
|
|
|
|
|
{16, 18, 19},
|
|
|
|
|
{21, 23, 24}}}}, torch::kLong);
|
|
|
|
|
auto x = torch::tensor({
|
|
|
|
|
{{{ 6, 8, 9},
|
|
|
|
|
{16, 18, 19},
|
|
|
|
|
{21, 23, 24}}},
|
|
|
|
|
{{{31, 33, 34},
|
|
|
|
|
{41, 43, 44},
|
Fix bugs in torch::tensor constructor (#28523)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/28523
New features:
1. Previously, `torch::tensor({true, false, true})` throws `"tensor_cpu" not implemented for 'Bool'`. After this PR, it produces the correct bool tensor, matching the Python API behavior.
2. Tensors with zero-size dimensions are now supported, e.g. `torch::tensor({{}, {}})` produces a tensor with sizes `{2, 0}`, matching the Python API behavior.
BC-breaking bug fixes:
1. Previously, `torch::tensor({{1}, {2}})` produces a tensor of sizes `{2}`. After this PR, it produces a tensor of sizes `{2, 1}`, matching the Python API behavior.
2. Fixed semantics of `torch::tensor(1.1)`: it now returns a 0-dim tensor instead of a 1-dim tensor, matching the Python API behavior.
3. Previously, when passed a non-dtype `TensorOptions` to the `torch::tensor` constructor, it always produces a tensor of dtype `float`. After this PR, it produces tensor of different dtypes based on the dtype of the braced-init-list, matching the behavior of the no-options case.
```cpp
// Previously:
torch::tensor({1, 2, 3}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> float
torch::tensor({{1, 2, 3}}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> float
torch::tensor({1., 2., 3.}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> float
torch::tensor({{1., 2., 3.}}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> float
// Now:
torch::tensor({1, 2, 3}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> int
torch::tensor({{1, 2, 3}}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> int
torch::tensor({1., 2., 3.}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> double
torch::tensor({{1., 2., 3.}}, torch::TensorOptions(/*non-dtype-options*/)).dtype() -> double
// As comparison, currently:
torch::tensor({1, 2, 3}).dtype() -> int
torch::tensor({{1, 2, 3}}).dtype() -> int
torch::tensor({1., 2., 3.}).dtype() -> double
torch::tensor({{1., 2., 3.}}).dtype() -> double
```
Notes:
1. From now on, the behavior of `at::tensor(scalar_value)` (which produces a 1-dim tensor) would be different from `torch::tensor(scalar_value)` (which produces a 0-dim tensor). I will fix the behavior of `at::tensor(scalar_value)` in a follow-up PR.
2. From now on, the behavior of `at::tensor({1, 2, 3}, torch::TensorOptions(/*non-dtype-options*/))` (which produces a `float` tensor) would be different from `torch::tensor({1, 2, 3}, torch::TensorOptions(/*non-dtype-options*/))` (which produces a an `int` tensor). I will fix this behavior of `at::tensor` constructor in a follow-up PR.
Context for the changes in this PR:
The motivation comes from fixing the "`torch::tensor({{1}, {2}})` gives tensor of wrong sizes" bug - in order to fix it, I have to move the handling of `at::ArrayRef` and `std::vector` into `InitListTensor` (see below on why we need to do this) and renamed `InitListTensor` to `TensorDataContainer`. After such changes, support for bool values comes out of the box without extra effort, and support for tensors with zero-size dimensions only requires adding a default constructor for `TensorDataContainer`, so I added those two in this PR.
For the semantic change of `torch::tensor(1.1)`, it's actually more effort to preserve the original wrong behavior (i.e. we need to check the sizes of the tensor converted from `TensorDataContainer` and reshape any scalar tensor to a 1-D tensor). I think preserving the original wrong behavior doesn't give us much value, and since the above changes naturally fix the problem, we should just start using the right behavior instead.
For the "constructor with non-dtype options behavior" fix, the code looks simpler and easier to reason about with the fix, so I included it in this PR.
--------
Why we need to move the handling of `at::ArrayRef` and `std::vector` into `TensorDataContainer`:
`torch::tensor({{1}, {2}})` can match this function overload:
`torch::tensor(at::ArrayRef<int> values)`, because `{1}` and `{2}` can be treated as
a list-initialization of an `int` value. However, this will produce a Tensor with sizes `{2}`,
but we actually want a Tensor with sizes `{2, 1}`. In order to avoid matching this function overload,
we removed the function overload and moved the ability to convert `at::ArrayRef<T>`
(and similarly `std::vector<T>`) into `TensorDataContainer`, and since for braced-init-list the
`TensorDataContainer(std::initializer_list<TensorDataContainer>)` constructor is always preferred over all other constructors, it will take the `std::initializer_list` path, and all is good.
Test Plan: Imported from OSS
Differential Revision: D18234625
Pulled By: yf225
fbshipit-source-id: 0f3f6912e82e2117d2103e31b74e7e97baaa8693
2019-10-31 19:51:18 +00:00
|
|
|
{46, 48, 49}}}}, torch::dtype(torch::kFloat).requires_grad(true));
|
Pass F::*FuncOptions instead of torch::nn::*Options to functionals, and make F::*FuncOptions a different class when necessary (#29364)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/29364
Currently, we use `torch::nn::*Options` both as module options and functional options. However, this makes it very hard to manage the parameters in `torch::nn::*Options`, because a module's constructor can take a different set of arguments than the module's equivalent functional (e.g. `torch.nn.BatchNorm1d` takes `num_features, eps=1e-5, momentum=0.1, affine=True,
track_running_stats=True`, while `F::batch_norm` takes `running_mean, running_var, weight=None, bias=None, training=False, momentum=0.1, eps=1e-5`).
This PR resolves the above problem by making `F::*FuncOptions` a different class from `torch::nn::*Options` when necessary (i.e. when a module's constructor takes a different set of arguments than the module's equivalent functional). In the rest of the cases where the module constructor takes the same set of arguments as the module's equivalent functional, `F::*FuncOptions` is an alias of `torch::nn::*Options`.
Also as part of this PR, we change all functional options to pass-by-value, to make the semantics consistent across all functionals.
Test Plan: Imported from OSS
Differential Revision: D18376977
Pulled By: yf225
fbshipit-source-id: 8d9c240d93bfd5af0165b6884fdc912476b1d06b
2019-11-09 06:36:49 +00:00
|
|
|
auto y = F::max_unpool2d(x, indices, F::MaxUnpool2dFuncOptions(3).stride(2).padding(1));
|
2019-10-02 02:27:48 +00:00
|
|
|
|
|
|
|
|
ASSERT_EQ(y.dim(), 4);
|
|
|
|
|
ASSERT_TRUE(torch::allclose(y, torch::tensor(
|
|
|
|
|
{{{{ 0, 0, 0, 0, 0},
|
|
|
|
|
{ 0, 6, 0, 8, 9},
|
|
|
|
|
{ 0, 0, 0, 0, 0},
|
|
|
|
|
{ 0, 16, 0, 18, 19},
|
|
|
|
|
{ 0, 21, 0, 23, 24}}},
|
|
|
|
|
{{{ 0, 0, 0, 0, 0},
|
|
|
|
|
{ 0, 31, 0, 33, 34},
|
|
|
|
|
{ 0, 0, 0, 0, 0},
|
|
|
|
|
{ 0, 41, 0, 43, 44},
|
|
|
|
|
{ 0, 46, 0, 48, 49}}}} , torch::kFloat)));
|
2019-10-15 00:58:14 +00:00
|
|
|
ASSERT_EQ(y.sizes(), std::vector<int64_t>({2, 1, 5, 5}));
|
2019-10-02 02:27:48 +00:00
|
|
|
}
|
2019-10-02 14:10:32 +00:00
|
|
|
|
2019-11-20 20:35:50 +00:00
|
|
|
TEST_F(FunctionalTest, MaxUnpool3d) {
|
|
|
|
|
auto indices = torch::tensor({{{{{26}}}}}, torch::kLong);
|
|
|
|
|
auto x = torch::tensor({{{{{26}}}}}, torch::dtype(torch::kFloat).requires_grad(true));
|
|
|
|
|
auto y = F::max_unpool3d(x, indices, F::MaxUnpool3dFuncOptions(3));
|
|
|
|
|
|
|
|
|
|
ASSERT_EQ(y.dim(), 5);
|
|
|
|
|
ASSERT_TRUE(torch::allclose(y, torch::tensor(
|
|
|
|
|
{{{{{ 0, 0, 0},
|
|
|
|
|
{ 0, 0, 0},
|
|
|
|
|
{ 0, 0, 0}},
|
|
|
|
|
{{ 0, 0, 0},
|
|
|
|
|
{ 0, 0, 0},
|
|
|
|
|
{ 0, 0, 0}},
|
|
|
|
|
{{ 0, 0, 0},
|
|
|
|
|
{ 0, 0, 0},
|
|
|
|
|
{ 0, 0, 26}}}}}, torch::kFloat)));
|
|
|
|
|
ASSERT_EQ(y.sizes(), std::vector<int64_t>({1, 1, 3, 3, 3}));
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-02 14:10:32 +00:00
|
|
|
TEST_F(FunctionalTest, ELU) {
|
|
|
|
|
const auto size = 3;
|
|
|
|
|
for (const auto inplace : {false, true}) {
|
|
|
|
|
for (const auto alpha : {0.0, 0.42, 1.0, 4.2, 42.42}) {
|
|
|
|
|
auto x = torch::linspace(-10.0, 10.0, size * size * size);
|
|
|
|
|
x.resize_({size, size, size});
|
|
|
|
|
auto y_exp = torch::max(torch::zeros_like(x), x) +
|
|
|
|
|
torch::min(torch::zeros_like(x), alpha * (torch::exp(x) - 1.0));
|
Pass F::*FuncOptions instead of torch::nn::*Options to functionals, and make F::*FuncOptions a different class when necessary (#29364)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/29364
Currently, we use `torch::nn::*Options` both as module options and functional options. However, this makes it very hard to manage the parameters in `torch::nn::*Options`, because a module's constructor can take a different set of arguments than the module's equivalent functional (e.g. `torch.nn.BatchNorm1d` takes `num_features, eps=1e-5, momentum=0.1, affine=True,
track_running_stats=True`, while `F::batch_norm` takes `running_mean, running_var, weight=None, bias=None, training=False, momentum=0.1, eps=1e-5`).
This PR resolves the above problem by making `F::*FuncOptions` a different class from `torch::nn::*Options` when necessary (i.e. when a module's constructor takes a different set of arguments than the module's equivalent functional). In the rest of the cases where the module constructor takes the same set of arguments as the module's equivalent functional, `F::*FuncOptions` is an alias of `torch::nn::*Options`.
Also as part of this PR, we change all functional options to pass-by-value, to make the semantics consistent across all functionals.
Test Plan: Imported from OSS
Differential Revision: D18376977
Pulled By: yf225
fbshipit-source-id: 8d9c240d93bfd5af0165b6884fdc912476b1d06b
2019-11-09 06:36:49 +00:00
|
|
|
auto y = F::elu(x, F::ELUFuncOptions().alpha(alpha).inplace(inplace));
|
2019-10-02 14:10:32 +00:00
|
|
|
|
|
|
|
|
ASSERT_EQ(y.ndimension(), 3);
|
2019-10-15 00:58:14 +00:00
|
|
|
ASSERT_EQ(y.sizes(), std::vector<int64_t>({size, size, size}));
|
2019-10-02 14:10:32 +00:00
|
|
|
ASSERT_TRUE(torch::allclose(y, y_exp));
|
|
|
|
|
if (inplace) {
|
|
|
|
|
ASSERT_TRUE(torch::allclose(x, y_exp));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-11-20 00:06:25 +00:00
|
|
|
ASSERT_TRUE(F::elu(torch::tensor(1.)).defined());
|
2019-10-02 14:10:32 +00:00
|
|
|
}
|
2019-10-02 15:28:35 +00:00
|
|
|
|
2019-10-09 21:37:27 +00:00
|
|
|
TEST_F(FunctionalTest, SELU) {
|
|
|
|
|
{
|
|
|
|
|
const double scale = 1.0507009873554804934193349852946;
|
|
|
|
|
const double alpha = 1.6732632423543772848170429916717;
|
|
|
|
|
for (const auto inplace : {false, true}) {
|
|
|
|
|
auto input = torch::randn({5, 5});
|
|
|
|
|
auto expected = scale *
|
|
|
|
|
(torch::max(torch::zeros_like(input), input) +
|
|
|
|
|
torch::min(
|
|
|
|
|
torch::zeros_like(input), alpha * (torch::exp(input) - 1)));
|
|
|
|
|
auto output = F::selu(input, inplace);
|
|
|
|
|
|
|
|
|
|
ASSERT_TRUE(output.allclose(expected));
|
|
|
|
|
if (inplace) {
|
|
|
|
|
ASSERT_TRUE(input.allclose(expected));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
{
|
|
|
|
|
auto input = torch::arange(0, 9, torch::kDouble).view({3, 3});
|
|
|
|
|
auto output = F::selu(input);
|
|
|
|
|
auto expected = F::selu(input, false);
|
|
|
|
|
ASSERT_TRUE(output.allclose(expected));
|
|
|
|
|
}
|
2019-11-20 00:06:25 +00:00
|
|
|
ASSERT_TRUE(F::selu(torch::tensor(1.)).defined());
|
2019-10-09 21:37:27 +00:00
|
|
|
}
|
|
|
|
|
|
2019-11-17 05:01:40 +00:00
|
|
|
TEST_F(FunctionalTest, GLU) {
|
|
|
|
|
int64_t dim = 1;
|
|
|
|
|
auto input = torch::randn({4, 2}, torch::requires_grad());
|
|
|
|
|
auto output = F::glu(input, dim);
|
|
|
|
|
auto input_size = input.sizes()[dim] / 2;
|
|
|
|
|
auto first_half = input.narrow(dim, 0, input_size);
|
|
|
|
|
auto second_half = input.narrow(dim, input_size, input_size);
|
|
|
|
|
auto expected = first_half * torch::sigmoid(second_half);
|
|
|
|
|
|
|
|
|
|
ASSERT_TRUE(output.allclose(expected));
|
|
|
|
|
ASSERT_TRUE(F::glu(input).allclose(expected));
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-04 05:53:32 +00:00
|
|
|
TEST_F(FunctionalTest, GELU) {
|
|
|
|
|
GELU model;
|
|
|
|
|
const auto x = torch::linspace(-3.0, 3.0, 100);
|
|
|
|
|
const auto y_exp = x * 0.5 * (1.0 + torch::erf(x / std::sqrt(2.0)));
|
|
|
|
|
const auto y = F::gelu(x);
|
|
|
|
|
ASSERT_TRUE(torch::allclose(y, y_exp));
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-02 15:28:35 +00:00
|
|
|
TEST_F(FunctionalTest, Hardshrink) {
|
|
|
|
|
const auto size = 3;
|
|
|
|
|
for (const auto lambda : {-4.2, -1.0, -0.42, 0.0, 0.42, 1.0, 4.2, 42.42}) {
|
|
|
|
|
auto x = torch::linspace(-10.0, 10.0, size * size * size);
|
|
|
|
|
x.resize_({size, size, size}).set_requires_grad(true);
|
Pass F::*FuncOptions instead of torch::nn::*Options to functionals, and make F::*FuncOptions a different class when necessary (#29364)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/29364
Currently, we use `torch::nn::*Options` both as module options and functional options. However, this makes it very hard to manage the parameters in `torch::nn::*Options`, because a module's constructor can take a different set of arguments than the module's equivalent functional (e.g. `torch.nn.BatchNorm1d` takes `num_features, eps=1e-5, momentum=0.1, affine=True,
track_running_stats=True`, while `F::batch_norm` takes `running_mean, running_var, weight=None, bias=None, training=False, momentum=0.1, eps=1e-5`).
This PR resolves the above problem by making `F::*FuncOptions` a different class from `torch::nn::*Options` when necessary (i.e. when a module's constructor takes a different set of arguments than the module's equivalent functional). In the rest of the cases where the module constructor takes the same set of arguments as the module's equivalent functional, `F::*FuncOptions` is an alias of `torch::nn::*Options`.
Also as part of this PR, we change all functional options to pass-by-value, to make the semantics consistent across all functionals.
Test Plan: Imported from OSS
Differential Revision: D18376977
Pulled By: yf225
fbshipit-source-id: 8d9c240d93bfd5af0165b6884fdc912476b1d06b
2019-11-09 06:36:49 +00:00
|
|
|
auto y = F::hardshrink(x, F::HardshrinkFuncOptions().lambda(lambda));
|
2019-10-02 15:28:35 +00:00
|
|
|
torch::Tensor s = y.sum();
|
|
|
|
|
|
|
|
|
|
s.backward();
|
|
|
|
|
ASSERT_EQ(s.ndimension(), 0);
|
|
|
|
|
|
|
|
|
|
ASSERT_EQ(y.ndimension(), 3);
|
2019-10-15 00:58:14 +00:00
|
|
|
ASSERT_EQ(y.sizes(), std::vector<int64_t>({size, size, size}));
|
2019-10-02 15:28:35 +00:00
|
|
|
auto y_exp = (x.abs() > lambda) * x;
|
|
|
|
|
ASSERT_TRUE(torch::allclose(y, y_exp));
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-10-03 00:26:27 +00:00
|
|
|
|
|
|
|
|
TEST_F(FunctionalTest, OneHot) {
|
|
|
|
|
{ // Test #1
|
|
|
|
|
auto x = torch::arange(0, 5, torch::kLong);
|
|
|
|
|
auto y = F::one_hot(x % 3);
|
|
|
|
|
auto expected = torch::tensor(
|
|
|
|
|
{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}, {1, 0, 0}, {0, 1, 0}}, torch::kLong);
|
|
|
|
|
|
|
|
|
|
ASSERT_EQ(y.ndimension(), 2);
|
|
|
|
|
ASSERT_TRUE(torch::allclose(y, expected));
|
2019-10-15 00:58:14 +00:00
|
|
|
ASSERT_EQ(y.sizes(), std::vector<int64_t>({5, 3}));
|
2019-10-03 00:26:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{ // Test #2
|
|
|
|
|
auto x = torch::arange(0, 5, torch::kLong);
|
|
|
|
|
auto y = F::one_hot(x % 3, 5);
|
|
|
|
|
auto expected = torch::tensor(
|
|
|
|
|
{{1, 0, 0, 0, 0},
|
|
|
|
|
{0, 1, 0, 0, 0},
|
|
|
|
|
{0, 0, 1, 0, 0},
|
|
|
|
|
{1, 0, 0, 0, 0},
|
|
|
|
|
{0, 1, 0, 0, 0}},
|
|
|
|
|
torch::kLong);
|
|
|
|
|
|
|
|
|
|
ASSERT_EQ(y.ndimension(), 2);
|
|
|
|
|
ASSERT_TRUE(torch::allclose(y, expected));
|
2019-10-15 00:58:14 +00:00
|
|
|
ASSERT_EQ(y.sizes(), std::vector<int64_t>({5, 5}));
|
2019-10-03 00:26:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{ // Test #3
|
|
|
|
|
auto x = torch::arange(0, 6, torch::kLong);
|
2019-10-15 00:58:14 +00:00
|
|
|
auto y = F::one_hot(x.view(std::vector<int64_t>({3, 2})) % 3);
|
2019-10-03 00:26:27 +00:00
|
|
|
auto expected = torch::tensor(
|
|
|
|
|
{{{1, 0, 0}, {0, 1, 0}},
|
|
|
|
|
{{0, 0, 1}, {1, 0, 0}},
|
|
|
|
|
{{0, 1, 0}, {0, 0, 1}}},
|
|
|
|
|
torch::kLong);
|
|
|
|
|
|
|
|
|
|
ASSERT_EQ(y.ndimension(), 3);
|
|
|
|
|
ASSERT_TRUE(torch::allclose(y, expected));
|
2019-10-15 00:58:14 +00:00
|
|
|
ASSERT_EQ(y.sizes(), std::vector<int64_t>({3, 2, 3}));
|
2019-10-03 00:26:27 +00:00
|
|
|
}
|
|
|
|
|
}
|
2019-10-04 19:51:41 +00:00
|
|
|
|
|
|
|
|
TEST_F(FunctionalTest, Hardtanh) {
|
|
|
|
|
const auto size = 3;
|
|
|
|
|
for (const auto min_val : {-4.2, -1.0, -0.42, 0.0}) {
|
|
|
|
|
for (const auto max_val : {0.0, 0.42, 1.0, 4.2}) {
|
|
|
|
|
for (const auto inplace : {false, true}) {
|
|
|
|
|
auto x = torch::linspace(-10.0, 10.0, size * size * size);
|
|
|
|
|
x.resize_({size, size, size});
|
|
|
|
|
auto y_exp = (x < min_val) * min_val +
|
|
|
|
|
((x >= min_val) * (x <= max_val)) * x +
|
|
|
|
|
(x > max_val) * max_val;
|
Pass F::*FuncOptions instead of torch::nn::*Options to functionals, and make F::*FuncOptions a different class when necessary (#29364)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/29364
Currently, we use `torch::nn::*Options` both as module options and functional options. However, this makes it very hard to manage the parameters in `torch::nn::*Options`, because a module's constructor can take a different set of arguments than the module's equivalent functional (e.g. `torch.nn.BatchNorm1d` takes `num_features, eps=1e-5, momentum=0.1, affine=True,
track_running_stats=True`, while `F::batch_norm` takes `running_mean, running_var, weight=None, bias=None, training=False, momentum=0.1, eps=1e-5`).
This PR resolves the above problem by making `F::*FuncOptions` a different class from `torch::nn::*Options` when necessary (i.e. when a module's constructor takes a different set of arguments than the module's equivalent functional). In the rest of the cases where the module constructor takes the same set of arguments as the module's equivalent functional, `F::*FuncOptions` is an alias of `torch::nn::*Options`.
Also as part of this PR, we change all functional options to pass-by-value, to make the semantics consistent across all functionals.
Test Plan: Imported from OSS
Differential Revision: D18376977
Pulled By: yf225
fbshipit-source-id: 8d9c240d93bfd5af0165b6884fdc912476b1d06b
2019-11-09 06:36:49 +00:00
|
|
|
auto y = F::hardtanh(x, F::HardtanhFuncOptions().min_val(min_val)
|
2019-10-04 19:51:41 +00:00
|
|
|
.max_val(max_val).inplace(inplace));
|
|
|
|
|
|
|
|
|
|
ASSERT_EQ(y.ndimension(), 3);
|
2019-10-15 00:58:14 +00:00
|
|
|
ASSERT_EQ(y.sizes(), std::vector<int64_t>({size, size, size}));
|
2019-10-04 19:51:41 +00:00
|
|
|
ASSERT_TRUE(torch::allclose(y, y_exp));
|
|
|
|
|
if (inplace) {
|
|
|
|
|
ASSERT_TRUE(torch::allclose(x, y_exp));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-11-20 00:06:25 +00:00
|
|
|
ASSERT_TRUE(F::hardtanh(torch::tensor(1.)).defined());
|
2019-10-04 19:51:41 +00:00
|
|
|
}
|
2019-10-04 21:14:52 +00:00
|
|
|
|
|
|
|
|
TEST_F(FunctionalTest, LeakyReLU) {
|
|
|
|
|
const auto size = 3;
|
|
|
|
|
for (const auto negative_slope : {0.0, 0.42, 1.0}) {
|
|
|
|
|
for (const auto inplace : {false, true}) {
|
|
|
|
|
auto x = torch::linspace(-10.0, 10.0, size * size * size);
|
|
|
|
|
x.resize_({size, size, size});
|
|
|
|
|
auto y_exp = (x < 0) * x * negative_slope + (x >= 0) * x;
|
Pass F::*FuncOptions instead of torch::nn::*Options to functionals, and make F::*FuncOptions a different class when necessary (#29364)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/29364
Currently, we use `torch::nn::*Options` both as module options and functional options. However, this makes it very hard to manage the parameters in `torch::nn::*Options`, because a module's constructor can take a different set of arguments than the module's equivalent functional (e.g. `torch.nn.BatchNorm1d` takes `num_features, eps=1e-5, momentum=0.1, affine=True,
track_running_stats=True`, while `F::batch_norm` takes `running_mean, running_var, weight=None, bias=None, training=False, momentum=0.1, eps=1e-5`).
This PR resolves the above problem by making `F::*FuncOptions` a different class from `torch::nn::*Options` when necessary (i.e. when a module's constructor takes a different set of arguments than the module's equivalent functional). In the rest of the cases where the module constructor takes the same set of arguments as the module's equivalent functional, `F::*FuncOptions` is an alias of `torch::nn::*Options`.
Also as part of this PR, we change all functional options to pass-by-value, to make the semantics consistent across all functionals.
Test Plan: Imported from OSS
Differential Revision: D18376977
Pulled By: yf225
fbshipit-source-id: 8d9c240d93bfd5af0165b6884fdc912476b1d06b
2019-11-09 06:36:49 +00:00
|
|
|
auto y = F::leaky_relu(x, F::LeakyReLUFuncOptions()
|
2019-10-04 21:14:52 +00:00
|
|
|
.negative_slope(negative_slope).inplace(inplace));
|
|
|
|
|
|
|
|
|
|
ASSERT_EQ(y.ndimension(), 3);
|
2019-10-15 00:58:14 +00:00
|
|
|
ASSERT_EQ(y.sizes(), std::vector<int64_t>({size, size, size}));
|
2019-10-04 21:14:52 +00:00
|
|
|
ASSERT_TRUE(torch::allclose(y, y_exp));
|
|
|
|
|
if (inplace) {
|
|
|
|
|
ASSERT_TRUE(torch::allclose(x, y_exp));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-11-20 00:06:25 +00:00
|
|
|
ASSERT_TRUE(F::leaky_relu(torch::tensor(1.)).defined());
|
2019-10-04 21:14:52 +00:00
|
|
|
}
|
2019-10-05 13:16:44 +00:00
|
|
|
|
|
|
|
|
TEST_F(FunctionalTest, LogSigmoid) {
|
|
|
|
|
const auto size = 3;
|
|
|
|
|
LogSigmoid model;
|
|
|
|
|
auto x = torch::linspace(-10.0, 10.0, size * size * size);
|
|
|
|
|
x.resize_({size, size, size});
|
|
|
|
|
auto y = F::logsigmoid(x);
|
|
|
|
|
|
|
|
|
|
ASSERT_EQ(y.ndimension(), 3);
|
2019-10-15 00:58:14 +00:00
|
|
|
ASSERT_EQ(y.sizes(), std::vector<int64_t>({size, size, size}));
|
2019-10-05 13:16:44 +00:00
|
|
|
auto y_exp = torch::log(torch::ones_like(x)/(torch::ones_like(x) + torch::exp(torch::neg(x))));
|
|
|
|
|
ASSERT_TRUE(torch::allclose(y, y_exp, 1e-4, 1e-7));
|
|
|
|
|
}
|
2019-10-09 21:17:20 +00:00
|
|
|
|
2019-10-18 16:39:00 +00:00
|
|
|
TEST_F(FunctionalTest, GumbelSoftmax) {
|
|
|
|
|
// Test 1: No-options
|
|
|
|
|
{
|
|
|
|
|
auto logits = torch::randn({5});
|
|
|
|
|
int expected_count = 1;
|
|
|
|
|
auto y_draw = F::gumbel_softmax(logits);
|
|
|
|
|
|
|
|
|
|
// All values positive
|
|
|
|
|
ASSERT_GE(y_draw.min().item<int>(), 0);
|
|
|
|
|
// Shape unchanged
|
|
|
|
|
ASSERT_TRUE(y_draw.sizes() == logits.sizes());
|
|
|
|
|
// One choice per draw
|
|
|
|
|
ASSERT_TRUE(torch::allclose(y_draw.sum(), torch::tensor(expected_count, torch::kFloat)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Test 2: 1D shape, 0 and -1 dim
|
|
|
|
|
for(const auto dim: {0, -1}) {
|
|
|
|
|
auto logits = torch::randn({5});
|
|
|
|
|
int expected_count = 1;
|
Pass F::*FuncOptions instead of torch::nn::*Options to functionals, and make F::*FuncOptions a different class when necessary (#29364)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/29364
Currently, we use `torch::nn::*Options` both as module options and functional options. However, this makes it very hard to manage the parameters in `torch::nn::*Options`, because a module's constructor can take a different set of arguments than the module's equivalent functional (e.g. `torch.nn.BatchNorm1d` takes `num_features, eps=1e-5, momentum=0.1, affine=True,
track_running_stats=True`, while `F::batch_norm` takes `running_mean, running_var, weight=None, bias=None, training=False, momentum=0.1, eps=1e-5`).
This PR resolves the above problem by making `F::*FuncOptions` a different class from `torch::nn::*Options` when necessary (i.e. when a module's constructor takes a different set of arguments than the module's equivalent functional). In the rest of the cases where the module constructor takes the same set of arguments as the module's equivalent functional, `F::*FuncOptions` is an alias of `torch::nn::*Options`.
Also as part of this PR, we change all functional options to pass-by-value, to make the semantics consistent across all functionals.
Test Plan: Imported from OSS
Differential Revision: D18376977
Pulled By: yf225
fbshipit-source-id: 8d9c240d93bfd5af0165b6884fdc912476b1d06b
2019-11-09 06:36:49 +00:00
|
|
|
auto y_draw = F::gumbel_softmax(logits, F::GumbelSoftmaxFuncOptions().hard(true).dim(dim));
|
2019-10-18 16:39:00 +00:00
|
|
|
|
|
|
|
|
// All values positive
|
|
|
|
|
ASSERT_GE(y_draw.min().item<int>(), 0);
|
|
|
|
|
// Shape unchanged
|
|
|
|
|
ASSERT_TRUE(y_draw.sizes() == logits.sizes());
|
|
|
|
|
// One choice per draw
|
|
|
|
|
ASSERT_TRUE(torch::allclose(y_draw.sum(), torch::tensor(expected_count, torch::kFloat)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{ // Test 3: 2D shape, 1 dim
|
|
|
|
|
auto logits = torch::randn({5, 4});
|
|
|
|
|
int expected_count = 5;
|
Pass F::*FuncOptions instead of torch::nn::*Options to functionals, and make F::*FuncOptions a different class when necessary (#29364)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/29364
Currently, we use `torch::nn::*Options` both as module options and functional options. However, this makes it very hard to manage the parameters in `torch::nn::*Options`, because a module's constructor can take a different set of arguments than the module's equivalent functional (e.g. `torch.nn.BatchNorm1d` takes `num_features, eps=1e-5, momentum=0.1, affine=True,
track_running_stats=True`, while `F::batch_norm` takes `running_mean, running_var, weight=None, bias=None, training=False, momentum=0.1, eps=1e-5`).
This PR resolves the above problem by making `F::*FuncOptions` a different class from `torch::nn::*Options` when necessary (i.e. when a module's constructor takes a different set of arguments than the module's equivalent functional). In the rest of the cases where the module constructor takes the same set of arguments as the module's equivalent functional, `F::*FuncOptions` is an alias of `torch::nn::*Options`.
Also as part of this PR, we change all functional options to pass-by-value, to make the semantics consistent across all functionals.
Test Plan: Imported from OSS
Differential Revision: D18376977
Pulled By: yf225
fbshipit-source-id: 8d9c240d93bfd5af0165b6884fdc912476b1d06b
2019-11-09 06:36:49 +00:00
|
|
|
auto y_draw = F::gumbel_softmax(logits, F::GumbelSoftmaxFuncOptions().hard(true).dim(1));
|
2019-10-18 16:39:00 +00:00
|
|
|
|
|
|
|
|
// All values positive
|
|
|
|
|
ASSERT_GE(y_draw.min().item<int>(), 0);
|
|
|
|
|
// Shape unchanged
|
|
|
|
|
ASSERT_TRUE(y_draw.sizes() == logits.sizes());
|
|
|
|
|
// One choice per draw
|
|
|
|
|
ASSERT_TRUE(torch::allclose(y_draw.sum(), torch::tensor(expected_count, torch::kFloat)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Test 4: 3D shape, 1 and -1 dim
|
|
|
|
|
int dims[] = {1, -1};
|
|
|
|
|
int expected[] = {5*3, 5*4};
|
|
|
|
|
for(auto i=0; i<2; i++) {
|
|
|
|
|
auto logits = torch::randn({5, 4, 3});
|
|
|
|
|
int expected_count = expected[i];
|
Pass F::*FuncOptions instead of torch::nn::*Options to functionals, and make F::*FuncOptions a different class when necessary (#29364)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/29364
Currently, we use `torch::nn::*Options` both as module options and functional options. However, this makes it very hard to manage the parameters in `torch::nn::*Options`, because a module's constructor can take a different set of arguments than the module's equivalent functional (e.g. `torch.nn.BatchNorm1d` takes `num_features, eps=1e-5, momentum=0.1, affine=True,
track_running_stats=True`, while `F::batch_norm` takes `running_mean, running_var, weight=None, bias=None, training=False, momentum=0.1, eps=1e-5`).
This PR resolves the above problem by making `F::*FuncOptions` a different class from `torch::nn::*Options` when necessary (i.e. when a module's constructor takes a different set of arguments than the module's equivalent functional). In the rest of the cases where the module constructor takes the same set of arguments as the module's equivalent functional, `F::*FuncOptions` is an alias of `torch::nn::*Options`.
Also as part of this PR, we change all functional options to pass-by-value, to make the semantics consistent across all functionals.
Test Plan: Imported from OSS
Differential Revision: D18376977
Pulled By: yf225
fbshipit-source-id: 8d9c240d93bfd5af0165b6884fdc912476b1d06b
2019-11-09 06:36:49 +00:00
|
|
|
auto y_draw = F::gumbel_softmax(logits, F::GumbelSoftmaxFuncOptions().hard(true).dim(dims[i]));
|
2019-10-18 16:39:00 +00:00
|
|
|
|
|
|
|
|
// All values positive
|
|
|
|
|
ASSERT_GE(y_draw.min().item<int>(), 0);
|
|
|
|
|
// Shape unchanged
|
|
|
|
|
ASSERT_TRUE(y_draw.sizes() == logits.sizes());
|
|
|
|
|
// One choice per draw
|
|
|
|
|
ASSERT_TRUE(torch::allclose(y_draw.sum(), torch::tensor(expected_count, torch::kFloat)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{ // Test 5: Straight through
|
|
|
|
|
int num_draws = 100;
|
|
|
|
|
auto logits = torch::tensor({{0.2, 0.8, 0.1}});
|
|
|
|
|
logits = logits.reshape({1, 3});
|
|
|
|
|
logits.requires_grad();
|
|
|
|
|
auto probs = logits.softmax(-1);
|
|
|
|
|
|
|
|
|
|
auto counts = torch::zeros_like(logits);
|
|
|
|
|
torch::Tensor y_draw;
|
|
|
|
|
for (auto i=0; i<num_draws; i++) {
|
Pass F::*FuncOptions instead of torch::nn::*Options to functionals, and make F::*FuncOptions a different class when necessary (#29364)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/29364
Currently, we use `torch::nn::*Options` both as module options and functional options. However, this makes it very hard to manage the parameters in `torch::nn::*Options`, because a module's constructor can take a different set of arguments than the module's equivalent functional (e.g. `torch.nn.BatchNorm1d` takes `num_features, eps=1e-5, momentum=0.1, affine=True,
track_running_stats=True`, while `F::batch_norm` takes `running_mean, running_var, weight=None, bias=None, training=False, momentum=0.1, eps=1e-5`).
This PR resolves the above problem by making `F::*FuncOptions` a different class from `torch::nn::*Options` when necessary (i.e. when a module's constructor takes a different set of arguments than the module's equivalent functional). In the rest of the cases where the module constructor takes the same set of arguments as the module's equivalent functional, `F::*FuncOptions` is an alias of `torch::nn::*Options`.
Also as part of this PR, we change all functional options to pass-by-value, to make the semantics consistent across all functionals.
Test Plan: Imported from OSS
Differential Revision: D18376977
Pulled By: yf225
fbshipit-source-id: 8d9c240d93bfd5af0165b6884fdc912476b1d06b
2019-11-09 06:36:49 +00:00
|
|
|
y_draw = F::gumbel_softmax(logits, F::GumbelSoftmaxFuncOptions().hard(true));
|
2019-10-18 16:39:00 +00:00
|
|
|
counts += y_draw;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// All values positive
|
|
|
|
|
ASSERT_GE(y_draw.min().item<int>(), 0);
|
|
|
|
|
// Each experiment should result in 1 draw
|
|
|
|
|
ASSERT_EQ(counts.sum().item<int>(), num_draws);
|
|
|
|
|
|
|
|
|
|
// Check results are asymptotically as expected
|
|
|
|
|
auto expected = probs * num_draws;
|
|
|
|
|
// ~z is approximately N(0,1) for unbiased count
|
|
|
|
|
auto z = (counts - expected) / (expected * (1 - probs)).sqrt();
|
|
|
|
|
// A (lazy) approximate 99% two-sided test:
|
|
|
|
|
// occurs with prob alpha~>=0.01 if unbiased
|
|
|
|
|
ASSERT_LT(z.abs().max().item<float>(), 2.58);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-09 21:17:20 +00:00
|
|
|
TEST_F(FunctionalTest, Softmax) {
|
|
|
|
|
auto input = torch::arange(10, torch::kFloat).reshape({2, 5});
|
|
|
|
|
auto output = F::softmax(input, /*dim=*/1);
|
|
|
|
|
auto sum = torch::sum(torch::exp(input), 1);
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < 2; i++) {
|
|
|
|
|
auto expected = torch::exp(input[i]) / sum[i];
|
|
|
|
|
ASSERT_TRUE(torch::allclose(output[i], expected));
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-10-09 23:30:11 +00:00
|
|
|
|
2019-10-12 06:01:37 +00:00
|
|
|
TEST_F(FunctionalTest, Softmin) {
|
|
|
|
|
auto input = torch::arange(10, torch::kFloat).reshape({2, 5});
|
|
|
|
|
auto output = F::softmin(input, /*dim=*/1);
|
|
|
|
|
auto sum = torch::sum(torch::exp(-input), 1);
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < 2; i++) {
|
|
|
|
|
auto expected = torch::exp(-input[i]) / sum[i];
|
|
|
|
|
ASSERT_TRUE(torch::allclose(output[i], expected));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-10 23:15:42 +00:00
|
|
|
TEST_F(FunctionalTest, LogSoftmax) {
|
|
|
|
|
auto input = torch::arange(10, torch::kFloat).reshape({2, 5});
|
|
|
|
|
auto output = F::log_softmax(input, /*dim=*/1);
|
|
|
|
|
auto sum = torch::sum(torch::exp(input), 1);
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < 2; i++) {
|
|
|
|
|
auto expected = torch::log(torch::exp(input[i]) / sum[i]);
|
|
|
|
|
ASSERT_TRUE(torch::allclose(output[i], expected));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-09 23:30:11 +00:00
|
|
|
TEST_F(FunctionalTest, PReLU) {
|
|
|
|
|
const auto x = torch::rand({42, 24}) * 200 - 100;
|
|
|
|
|
const auto w = torch::rand(24) * 200 - 100;
|
|
|
|
|
const auto y = F::prelu(x, w);
|
2019-10-15 00:58:14 +00:00
|
|
|
ASSERT_EQ(y.sizes(), std::vector<int64_t>({42, 24}));
|
2019-10-09 23:30:11 +00:00
|
|
|
const auto y_exp = (x < 0) * w * x + (x >= 0) * x;
|
|
|
|
|
ASSERT_TRUE(torch::allclose(y, y_exp));
|
|
|
|
|
}
|
2019-10-10 20:32:31 +00:00
|
|
|
|
2019-10-22 19:48:10 +00:00
|
|
|
TEST_F(FunctionalTest, LayerNorm) {
|
|
|
|
|
const auto input = torch::randn({2, 2});
|
Pass F::*FuncOptions instead of torch::nn::*Options to functionals, and make F::*FuncOptions a different class when necessary (#29364)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/29364
Currently, we use `torch::nn::*Options` both as module options and functional options. However, this makes it very hard to manage the parameters in `torch::nn::*Options`, because a module's constructor can take a different set of arguments than the module's equivalent functional (e.g. `torch.nn.BatchNorm1d` takes `num_features, eps=1e-5, momentum=0.1, affine=True,
track_running_stats=True`, while `F::batch_norm` takes `running_mean, running_var, weight=None, bias=None, training=False, momentum=0.1, eps=1e-5`).
This PR resolves the above problem by making `F::*FuncOptions` a different class from `torch::nn::*Options` when necessary (i.e. when a module's constructor takes a different set of arguments than the module's equivalent functional). In the rest of the cases where the module constructor takes the same set of arguments as the module's equivalent functional, `F::*FuncOptions` is an alias of `torch::nn::*Options`.
Also as part of this PR, we change all functional options to pass-by-value, to make the semantics consistent across all functionals.
Test Plan: Imported from OSS
Differential Revision: D18376977
Pulled By: yf225
fbshipit-source-id: 8d9c240d93bfd5af0165b6884fdc912476b1d06b
2019-11-09 06:36:49 +00:00
|
|
|
auto y = F::layer_norm(input, F::LayerNormFuncOptions({2, 2}).eps(2e-5));
|
2019-10-22 19:48:10 +00:00
|
|
|
auto y_exp = torch::layer_norm(input, {2, 2}, torch::Tensor(), torch::Tensor(), 2e-5);
|
|
|
|
|
ASSERT_TRUE(torch::allclose(y, y_exp));
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-17 03:19:42 +00:00
|
|
|
TEST_F(FunctionalTest, GroupNorm) {
|
|
|
|
|
const auto input = torch::randn({2, 2});
|
|
|
|
|
auto y = F::group_norm(input, F::GroupNormFuncOptions(2).eps(2e-5));
|
|
|
|
|
auto y_exp = torch::group_norm(input, 2, torch::Tensor(), torch::Tensor(), 2e-5);
|
|
|
|
|
ASSERT_TRUE(torch::allclose(y, y_exp));
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-30 18:29:07 +00:00
|
|
|
TEST_F(FunctionalTest, LocalResponseNorm) {
|
|
|
|
|
const auto x = torch::arange(100, 118).resize_({3, 3, 2});
|
Pass F::*FuncOptions instead of torch::nn::*Options to functionals, and make F::*FuncOptions a different class when necessary (#29364)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/29364
Currently, we use `torch::nn::*Options` both as module options and functional options. However, this makes it very hard to manage the parameters in `torch::nn::*Options`, because a module's constructor can take a different set of arguments than the module's equivalent functional (e.g. `torch.nn.BatchNorm1d` takes `num_features, eps=1e-5, momentum=0.1, affine=True,
track_running_stats=True`, while `F::batch_norm` takes `running_mean, running_var, weight=None, bias=None, training=False, momentum=0.1, eps=1e-5`).
This PR resolves the above problem by making `F::*FuncOptions` a different class from `torch::nn::*Options` when necessary (i.e. when a module's constructor takes a different set of arguments than the module's equivalent functional). In the rest of the cases where the module constructor takes the same set of arguments as the module's equivalent functional, `F::*FuncOptions` is an alias of `torch::nn::*Options`.
Also as part of this PR, we change all functional options to pass-by-value, to make the semantics consistent across all functionals.
Test Plan: Imported from OSS
Differential Revision: D18376977
Pulled By: yf225
fbshipit-source-id: 8d9c240d93bfd5af0165b6884fdc912476b1d06b
2019-11-09 06:36:49 +00:00
|
|
|
const auto y = F::local_response_norm(x, F::LocalResponseNormFuncOptions(2));
|
2019-10-30 18:29:07 +00:00
|
|
|
ASSERT_EQ(y.ndimension(), 3);
|
|
|
|
|
ASSERT_EQ(y.sizes(), torch::IntArrayRef({3, 3, 2}));
|
|
|
|
|
const auto y_exp = torch::tensor(
|
|
|
|
|
{{{73.7788, 74.1462},
|
|
|
|
|
{60.1942, 60.3302},
|
|
|
|
|
{60.4609, 60.5865}},
|
|
|
|
|
{{75.8729, 76.2011},
|
|
|
|
|
{60.9331, 61.0390},
|
|
|
|
|
{61.1403, 61.2370}},
|
|
|
|
|
{{77.7387, 78.0303},
|
|
|
|
|
{61.5011, 61.5807},
|
|
|
|
|
{61.6563, 61.7279}}},
|
|
|
|
|
torch::kFloat
|
|
|
|
|
);
|
|
|
|
|
ASSERT_TRUE(torch::allclose(y, y_exp, 1e-4, 1e-7));
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-24 14:09:33 +00:00
|
|
|
TEST_F(FunctionalTest, Linear) {
|
|
|
|
|
{
|
2019-11-11 19:24:43 +00:00
|
|
|
const auto x = torch::arange(100., 118).resize_({3, 3, 2});
|
|
|
|
|
const auto w = torch::arange(200., 206).resize_({3, 2});
|
|
|
|
|
const auto b = torch::arange(300., 303);
|
2019-10-24 14:09:33 +00:00
|
|
|
const auto y = F::linear(x, w, b);
|
|
|
|
|
ASSERT_EQ(y.ndimension(), 3);
|
|
|
|
|
ASSERT_EQ(y.sizes(), torch::IntArrayRef({3, 3, 3}));
|
|
|
|
|
const auto y_exp = torch::tensor(
|
|
|
|
|
{{{40601, 41004, 41407},
|
|
|
|
|
{41403, 41814, 42225},
|
|
|
|
|
{42205, 42624, 43043}},
|
|
|
|
|
{{43007, 43434, 43861},
|
|
|
|
|
{43809, 44244, 44679},
|
|
|
|
|
{44611, 45054, 45497}},
|
|
|
|
|
{{45413, 45864, 46315},
|
|
|
|
|
{46215, 46674, 47133},
|
|
|
|
|
{47017, 47484, 47951}}},
|
|
|
|
|
torch::kFloat
|
|
|
|
|
);
|
|
|
|
|
ASSERT_TRUE(torch::allclose(y, y_exp));
|
|
|
|
|
}
|
|
|
|
|
{
|
2019-11-11 19:24:43 +00:00
|
|
|
const auto x = torch::arange(100., 118).resize_({3, 3, 2});
|
|
|
|
|
const auto w = torch::arange(200., 206).resize_({3, 2});
|
2019-10-24 14:09:33 +00:00
|
|
|
const auto y = F::linear(x, w);
|
|
|
|
|
ASSERT_EQ(y.ndimension(), 3);
|
|
|
|
|
ASSERT_EQ(y.sizes(), torch::IntArrayRef({3, 3, 3}));
|
|
|
|
|
const auto y_exp = torch::tensor(
|
|
|
|
|
{{{40301, 40703, 41105},
|
|
|
|
|
{41103, 41513, 41923},
|
|
|
|
|
{41905, 42323, 42741}},
|
|
|
|
|
{{42707, 43133, 43559},
|
|
|
|
|
{43509, 43943, 44377},
|
|
|
|
|
{44311, 44753, 45195}},
|
|
|
|
|
{{45113, 45563, 46013},
|
|
|
|
|
{45915, 46373, 46831},
|
|
|
|
|
{46717, 47183, 47649}}},
|
|
|
|
|
torch::kFloat
|
|
|
|
|
);
|
|
|
|
|
ASSERT_TRUE(torch::allclose(y, y_exp));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-11 19:50:01 +00:00
|
|
|
TEST_F(FunctionalTest, Embedding) {
|
|
|
|
|
const auto input = torch::tensor({{1,2,4,5}, {4,3,2,9}}, torch::kLong);
|
|
|
|
|
auto weight = torch::empty({10, 3});
|
|
|
|
|
torch::nn::init::normal_(weight);
|
|
|
|
|
auto y = F::embedding(input, weight);
|
|
|
|
|
auto y_exp = torch::embedding(weight, input.contiguous(), -1, false, false);
|
|
|
|
|
ASSERT_TRUE(torch::allclose(y, y_exp));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(FunctionalTest, EmbeddingBag) {
|
|
|
|
|
const auto input = torch::tensor({1,2,4,5,4,3,2,9}, torch::kLong);
|
|
|
|
|
auto offsets = torch::tensor({0,4}, torch::kLong);
|
|
|
|
|
auto weight = torch::empty({10, 3});
|
|
|
|
|
torch::nn::init::normal_(weight);
|
2019-11-14 02:45:42 +00:00
|
|
|
auto y = F::embedding_bag(input, weight, F::EmbeddingBagFuncOptions().mode(torch::kSum).offsets(offsets));
|
2019-11-11 19:50:01 +00:00
|
|
|
auto y_exp = std::get<0>(torch::embedding_bag(weight, input, offsets, false, 0, false, torch::Tensor()));
|
|
|
|
|
ASSERT_TRUE(torch::allclose(y, y_exp));
|
|
|
|
|
|
|
|
|
|
// no options test
|
|
|
|
|
const auto input_ = torch::tensor({{1,2,4,5}, {4,3,2,9}}, torch::kLong);
|
|
|
|
|
auto offsets_ = torch::arange(0, input_.numel(), input_.size(1), torch::TensorOptions().dtype(torch::kLong).device(input.device()));
|
|
|
|
|
y = F::embedding_bag(input_, weight);
|
|
|
|
|
y_exp = std::get<0>(torch::embedding_bag(weight, input_.reshape(-1), offsets_, false, 1, false, torch::Tensor()));
|
|
|
|
|
ASSERT_TRUE(torch::allclose(y, y_exp));
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-16 16:47:56 +00:00
|
|
|
TEST_F(FunctionalTest, Bilinear) {
|
|
|
|
|
auto input1 = torch::tensor({{1, 2, 3}, {7, 6, 5}});
|
|
|
|
|
auto input2 = torch::tensor({{7, 4}, {8 ,9}});
|
|
|
|
|
auto weight = torch::tensor({{{2, 3}, {9, 7}, {8, 6}}});
|
|
|
|
|
auto bias = torch::tensor({1});
|
2019-10-22 19:48:10 +00:00
|
|
|
|
2019-10-16 16:47:56 +00:00
|
|
|
auto y_with_bias = F::bilinear(input1, input2, weight, bias);
|
|
|
|
|
ASSERT_EQ(y_with_bias.ndimension(), 2);
|
|
|
|
|
ASSERT_EQ(y_with_bias.sizes(), torch::IntArrayRef({2, 1}));
|
|
|
|
|
auto y_with_bias_exp = torch::tensor({{449}, {1702}}).reshape({2, 1});
|
|
|
|
|
ASSERT_TRUE(torch::allclose(y_with_bias, y_with_bias_exp, 1e-4, 1e-7));
|
|
|
|
|
|
|
|
|
|
auto y_no_bias = F::bilinear(input1, input2, weight);
|
|
|
|
|
ASSERT_EQ(y_no_bias.ndimension(), 2);
|
|
|
|
|
ASSERT_EQ(y_no_bias.sizes(), torch::IntArrayRef({2, 1}));
|
|
|
|
|
auto y_no_bias_exp = torch::tensor({{448, 1701}}).reshape({2, 1});
|
|
|
|
|
ASSERT_TRUE(torch::allclose(y_no_bias, y_no_bias_exp, 1e-4, 1e-7));
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-14 15:37:31 +00:00
|
|
|
TEST_F(FunctionalTest, Normalize) {
|
|
|
|
|
const auto expected = torch::tensor(
|
|
|
|
|
{{{0.00000000, 0.10000000, 0.2000, 0.30000000, 0.40000000},
|
|
|
|
|
{0.14285715, 0.17142858, 0.2000, 0.22857143, 0.25714287}}}, torch::requires_grad().dtype(torch::kFloat));
|
2019-10-22 19:48:10 +00:00
|
|
|
{ // Test #1
|
2019-10-14 15:37:31 +00:00
|
|
|
auto input = torch::tensor({{{0, 1, 2, 3, 4}, {5, 6, 7, 8, 9}}}, torch::dtype(torch::kFloat).requires_grad(true));
|
Pass F::*FuncOptions instead of torch::nn::*Options to functionals, and make F::*FuncOptions a different class when necessary (#29364)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/29364
Currently, we use `torch::nn::*Options` both as module options and functional options. However, this makes it very hard to manage the parameters in `torch::nn::*Options`, because a module's constructor can take a different set of arguments than the module's equivalent functional (e.g. `torch.nn.BatchNorm1d` takes `num_features, eps=1e-5, momentum=0.1, affine=True,
track_running_stats=True`, while `F::batch_norm` takes `running_mean, running_var, weight=None, bias=None, training=False, momentum=0.1, eps=1e-5`).
This PR resolves the above problem by making `F::*FuncOptions` a different class from `torch::nn::*Options` when necessary (i.e. when a module's constructor takes a different set of arguments than the module's equivalent functional). In the rest of the cases where the module constructor takes the same set of arguments as the module's equivalent functional, `F::*FuncOptions` is an alias of `torch::nn::*Options`.
Also as part of this PR, we change all functional options to pass-by-value, to make the semantics consistent across all functionals.
Test Plan: Imported from OSS
Differential Revision: D18376977
Pulled By: yf225
fbshipit-source-id: 8d9c240d93bfd5af0165b6884fdc912476b1d06b
2019-11-09 06:36:49 +00:00
|
|
|
auto norm = F::normalize(input, F::NormalizeFuncOptions().p(1).dim(-1));
|
2019-10-22 19:48:10 +00:00
|
|
|
|
2019-10-14 15:37:31 +00:00
|
|
|
// reduce to scalar to call .backward()
|
|
|
|
|
torch::Tensor s = norm.sum();
|
|
|
|
|
s.backward();
|
|
|
|
|
|
|
|
|
|
ASSERT_EQ(s.ndimension(), 0);
|
|
|
|
|
ASSERT_EQ(input.grad().numel(), 10);
|
|
|
|
|
ASSERT_TRUE(torch::allclose(norm, expected));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{ // Test #2 Check variations of optional arguments
|
|
|
|
|
auto input = torch::tensor({{{0, 1, 2, 3, 4}, {5, 6, 7, 8, 9}}}, torch::dtype(torch::kFloat));
|
|
|
|
|
auto output = torch::randn({1,2,5}, torch::dtype(torch::kFloat));
|
|
|
|
|
// non-null output argument
|
2019-11-13 00:02:38 +00:00
|
|
|
F::normalize(input, F::NormalizeFuncOptions().p(1).dim(-1).out(output));
|
2019-10-14 15:37:31 +00:00
|
|
|
// default options
|
|
|
|
|
F::normalize(input);
|
|
|
|
|
|
|
|
|
|
ASSERT_TRUE(torch::allclose(output, expected));
|
|
|
|
|
}
|
2019-10-22 19:48:10 +00:00
|
|
|
|
2019-10-14 15:37:31 +00:00
|
|
|
{ // Test #3 Base case of scalar tensor
|
|
|
|
|
auto input = torch::randn({}, torch::requires_grad());
|
Pass F::*FuncOptions instead of torch::nn::*Options to functionals, and make F::*FuncOptions a different class when necessary (#29364)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/29364
Currently, we use `torch::nn::*Options` both as module options and functional options. However, this makes it very hard to manage the parameters in `torch::nn::*Options`, because a module's constructor can take a different set of arguments than the module's equivalent functional (e.g. `torch.nn.BatchNorm1d` takes `num_features, eps=1e-5, momentum=0.1, affine=True,
track_running_stats=True`, while `F::batch_norm` takes `running_mean, running_var, weight=None, bias=None, training=False, momentum=0.1, eps=1e-5`).
This PR resolves the above problem by making `F::*FuncOptions` a different class from `torch::nn::*Options` when necessary (i.e. when a module's constructor takes a different set of arguments than the module's equivalent functional). In the rest of the cases where the module constructor takes the same set of arguments as the module's equivalent functional, `F::*FuncOptions` is an alias of `torch::nn::*Options`.
Also as part of this PR, we change all functional options to pass-by-value, to make the semantics consistent across all functionals.
Test Plan: Imported from OSS
Differential Revision: D18376977
Pulled By: yf225
fbshipit-source-id: 8d9c240d93bfd5af0165b6884fdc912476b1d06b
2019-11-09 06:36:49 +00:00
|
|
|
torch::Tensor norm = F::normalize(input, F::NormalizeFuncOptions().p(1).dim(-1));
|
2019-10-14 15:37:31 +00:00
|
|
|
norm.backward();
|
|
|
|
|
|
|
|
|
|
ASSERT_EQ(input.grad().numel(), 1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-10 20:32:31 +00:00
|
|
|
TEST_F(FunctionalTest, ReLU) {
|
|
|
|
|
const auto size = 3;
|
|
|
|
|
for (const auto inplace : {false, true}) {
|
|
|
|
|
auto x = torch::linspace(-10.0, 10.0, size * size * size);
|
|
|
|
|
x.resize_({size, size, size});
|
|
|
|
|
auto y_exp = (x < 0) * 0 + (x >= 0) * x;
|
Pass F::*FuncOptions instead of torch::nn::*Options to functionals, and make F::*FuncOptions a different class when necessary (#29364)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/29364
Currently, we use `torch::nn::*Options` both as module options and functional options. However, this makes it very hard to manage the parameters in `torch::nn::*Options`, because a module's constructor can take a different set of arguments than the module's equivalent functional (e.g. `torch.nn.BatchNorm1d` takes `num_features, eps=1e-5, momentum=0.1, affine=True,
track_running_stats=True`, while `F::batch_norm` takes `running_mean, running_var, weight=None, bias=None, training=False, momentum=0.1, eps=1e-5`).
This PR resolves the above problem by making `F::*FuncOptions` a different class from `torch::nn::*Options` when necessary (i.e. when a module's constructor takes a different set of arguments than the module's equivalent functional). In the rest of the cases where the module constructor takes the same set of arguments as the module's equivalent functional, `F::*FuncOptions` is an alias of `torch::nn::*Options`.
Also as part of this PR, we change all functional options to pass-by-value, to make the semantics consistent across all functionals.
Test Plan: Imported from OSS
Differential Revision: D18376977
Pulled By: yf225
fbshipit-source-id: 8d9c240d93bfd5af0165b6884fdc912476b1d06b
2019-11-09 06:36:49 +00:00
|
|
|
auto y = F::relu(x, F::ReLUFuncOptions().inplace(inplace));
|
2019-10-10 20:32:31 +00:00
|
|
|
|
|
|
|
|
ASSERT_EQ(y.ndimension(), 3);
|
2019-10-15 00:58:14 +00:00
|
|
|
ASSERT_EQ(y.sizes(), std::vector<int64_t>({size, size, size}));
|
2019-10-10 20:32:31 +00:00
|
|
|
ASSERT_TRUE(torch::allclose(y, y_exp));
|
|
|
|
|
if (inplace) {
|
|
|
|
|
ASSERT_TRUE(torch::allclose(x, y_exp));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
y = F::relu(x, /*inplace=*/inplace);
|
|
|
|
|
|
|
|
|
|
ASSERT_EQ(y.ndimension(), 3);
|
2019-10-15 00:58:14 +00:00
|
|
|
ASSERT_EQ(y.sizes(), std::vector<int64_t>({size, size, size}));
|
2019-10-10 20:32:31 +00:00
|
|
|
ASSERT_TRUE(torch::allclose(y, y_exp));
|
|
|
|
|
if (inplace) {
|
|
|
|
|
ASSERT_TRUE(torch::allclose(x, y_exp));
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-11-20 00:06:25 +00:00
|
|
|
ASSERT_TRUE(F::relu(torch::tensor(1.)).defined());
|
2019-10-10 20:32:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(FunctionalTest, ReLUDefaultOptions) {
|
|
|
|
|
const auto size = 3;
|
|
|
|
|
auto x = torch::linspace(-10.0, 10.0, size * size * size);
|
|
|
|
|
x.resize_({size, size, size});
|
|
|
|
|
auto y_exp = (x < 0) * 0 + (x >= 0) * x;
|
|
|
|
|
auto y = F::relu(x);
|
|
|
|
|
|
|
|
|
|
ASSERT_EQ(y.ndimension(), 3);
|
2019-10-15 00:58:14 +00:00
|
|
|
ASSERT_EQ(y.sizes(), std::vector<int64_t>({size, size, size}));
|
2019-10-10 20:32:31 +00:00
|
|
|
ASSERT_TRUE(torch::allclose(y, y_exp));
|
|
|
|
|
}
|
2019-10-11 00:09:53 +00:00
|
|
|
|
|
|
|
|
TEST_F(FunctionalTest, ReLU6) {
|
|
|
|
|
const auto size = 3;
|
|
|
|
|
for (const auto inplace : {false, true}) {
|
|
|
|
|
auto x = torch::linspace(-10.0, 10.0, size * size * size);
|
|
|
|
|
x.resize_({size, size, size});
|
|
|
|
|
auto y_exp = (x < 0) * 0 + ((x >= 0) * (x <= 6)) * x + (x > 6) * 6;
|
Pass F::*FuncOptions instead of torch::nn::*Options to functionals, and make F::*FuncOptions a different class when necessary (#29364)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/29364
Currently, we use `torch::nn::*Options` both as module options and functional options. However, this makes it very hard to manage the parameters in `torch::nn::*Options`, because a module's constructor can take a different set of arguments than the module's equivalent functional (e.g. `torch.nn.BatchNorm1d` takes `num_features, eps=1e-5, momentum=0.1, affine=True,
track_running_stats=True`, while `F::batch_norm` takes `running_mean, running_var, weight=None, bias=None, training=False, momentum=0.1, eps=1e-5`).
This PR resolves the above problem by making `F::*FuncOptions` a different class from `torch::nn::*Options` when necessary (i.e. when a module's constructor takes a different set of arguments than the module's equivalent functional). In the rest of the cases where the module constructor takes the same set of arguments as the module's equivalent functional, `F::*FuncOptions` is an alias of `torch::nn::*Options`.
Also as part of this PR, we change all functional options to pass-by-value, to make the semantics consistent across all functionals.
Test Plan: Imported from OSS
Differential Revision: D18376977
Pulled By: yf225
fbshipit-source-id: 8d9c240d93bfd5af0165b6884fdc912476b1d06b
2019-11-09 06:36:49 +00:00
|
|
|
auto y = F::relu6(x, F::ReLU6FuncOptions().inplace(inplace));
|
2019-10-11 00:09:53 +00:00
|
|
|
|
|
|
|
|
ASSERT_EQ(y.ndimension(), 3);
|
2019-10-15 00:58:14 +00:00
|
|
|
ASSERT_EQ(y.sizes(), std::vector<int64_t>({size, size, size}));
|
2019-10-11 00:09:53 +00:00
|
|
|
ASSERT_TRUE(torch::allclose(y, y_exp));
|
|
|
|
|
if (inplace) {
|
|
|
|
|
ASSERT_TRUE(torch::allclose(x, y_exp));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
y = F::relu6(x, /*inplace=*/inplace);
|
|
|
|
|
|
|
|
|
|
ASSERT_EQ(y.ndimension(), 3);
|
2019-10-15 00:58:14 +00:00
|
|
|
ASSERT_EQ(y.sizes(), std::vector<int64_t>({size, size, size}));
|
2019-10-11 00:09:53 +00:00
|
|
|
ASSERT_TRUE(torch::allclose(y, y_exp));
|
|
|
|
|
if (inplace) {
|
|
|
|
|
ASSERT_TRUE(torch::allclose(x, y_exp));
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-11-20 00:06:25 +00:00
|
|
|
ASSERT_TRUE(F::relu6(torch::tensor(1.)).defined());
|
2019-10-11 00:09:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(FunctionalTest, ReLU6DefaultOptions) {
|
|
|
|
|
const auto size = 3;
|
|
|
|
|
auto x = torch::linspace(-10.0, 10.0, size * size * size);
|
|
|
|
|
x.resize_({size, size, size});
|
|
|
|
|
auto y_exp = (x < 0) * 0 + ((x >= 0) * (x <= 6)) * x + (x > 6) * 6;
|
|
|
|
|
auto y = F::relu6(x);
|
|
|
|
|
|
|
|
|
|
ASSERT_EQ(y.ndimension(), 3);
|
2019-10-15 00:58:14 +00:00
|
|
|
ASSERT_EQ(y.sizes(), std::vector<int64_t>({size, size, size}));
|
2019-10-11 00:09:53 +00:00
|
|
|
ASSERT_TRUE(torch::allclose(y, y_exp));
|
|
|
|
|
}
|
2019-10-11 02:12:51 +00:00
|
|
|
|
|
|
|
|
TEST_F(FunctionalTest, RReLU) {
|
|
|
|
|
const auto size = 3;
|
|
|
|
|
for (const auto lower : {0.01, 0.1, 0.2}) {
|
|
|
|
|
for (const auto upper : {0.3, 0.4, 0.5}) {
|
|
|
|
|
for (const auto inplace : {false, true}) {
|
|
|
|
|
auto x = torch::linspace(-10.0, 10.0, size * size * size);
|
|
|
|
|
x.resize_({size, size, size});
|
|
|
|
|
auto x_copy = x.clone();
|
Pass F::*FuncOptions instead of torch::nn::*Options to functionals, and make F::*FuncOptions a different class when necessary (#29364)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/29364
Currently, we use `torch::nn::*Options` both as module options and functional options. However, this makes it very hard to manage the parameters in `torch::nn::*Options`, because a module's constructor can take a different set of arguments than the module's equivalent functional (e.g. `torch.nn.BatchNorm1d` takes `num_features, eps=1e-5, momentum=0.1, affine=True,
track_running_stats=True`, while `F::batch_norm` takes `running_mean, running_var, weight=None, bias=None, training=False, momentum=0.1, eps=1e-5`).
This PR resolves the above problem by making `F::*FuncOptions` a different class from `torch::nn::*Options` when necessary (i.e. when a module's constructor takes a different set of arguments than the module's equivalent functional). In the rest of the cases where the module constructor takes the same set of arguments as the module's equivalent functional, `F::*FuncOptions` is an alias of `torch::nn::*Options`.
Also as part of this PR, we change all functional options to pass-by-value, to make the semantics consistent across all functionals.
Test Plan: Imported from OSS
Differential Revision: D18376977
Pulled By: yf225
fbshipit-source-id: 8d9c240d93bfd5af0165b6884fdc912476b1d06b
2019-11-09 06:36:49 +00:00
|
|
|
auto y = F::rrelu(x, F::RReLUFuncOptions().lower(lower)
|
2019-10-11 02:12:51 +00:00
|
|
|
.upper(upper).inplace(inplace));
|
|
|
|
|
auto z = ((x_copy >= 0) * (x_copy == y) +
|
|
|
|
|
(x_copy < 0) * (y >= x_copy * upper) * (y <= lower * x_copy)) * 1.0;
|
|
|
|
|
|
|
|
|
|
ASSERT_EQ(y.ndimension(), 3);
|
2019-10-15 00:58:14 +00:00
|
|
|
ASSERT_EQ(y.sizes(), std::vector<int64_t>({size, size, size}));
|
2019-10-11 02:12:51 +00:00
|
|
|
ASSERT_TRUE(torch::allclose(z, torch::ones_like(z)));
|
|
|
|
|
if (inplace) {
|
|
|
|
|
ASSERT_TRUE(torch::allclose(x, y));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-11-20 00:06:25 +00:00
|
|
|
ASSERT_TRUE(F::rrelu(torch::tensor(1.)).defined());
|
2019-10-11 02:12:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(FunctionalTest, RReLUDefaultOptions) {
|
|
|
|
|
const auto size = 3;
|
|
|
|
|
const auto lower = 1.0 / 8.0;
|
|
|
|
|
const auto upper = 1.0 / 3.0;
|
|
|
|
|
auto x = torch::linspace(-10.0, 10.0, size * size * size);
|
|
|
|
|
x.resize_({size, size, size});
|
|
|
|
|
auto x_copy = x.clone();
|
|
|
|
|
auto y = F::rrelu(x);
|
|
|
|
|
auto z = ((x_copy >= 0) * (x_copy == y) +
|
|
|
|
|
(x_copy < 0) * (y >= x_copy * upper) * (y <= lower * x_copy)) * 1.0;
|
|
|
|
|
|
|
|
|
|
ASSERT_EQ(y.ndimension(), 3);
|
2019-10-15 00:58:14 +00:00
|
|
|
ASSERT_EQ(y.sizes(), std::vector<int64_t>({size, size, size}));
|
2019-10-11 02:12:51 +00:00
|
|
|
ASSERT_TRUE(torch::allclose(z, torch::ones_like(z)));
|
|
|
|
|
}
|
2019-10-11 13:21:06 +00:00
|
|
|
|
|
|
|
|
TEST_F(FunctionalTest, CELU) {
|
|
|
|
|
const auto size = 3;
|
|
|
|
|
for (const auto inplace : {false, true}) {
|
|
|
|
|
for (const auto alpha : {0.42, 1.0, 4.2, 42.42}) {
|
|
|
|
|
auto x = torch::linspace(-10.0, 10.0, size * size * size);
|
|
|
|
|
x.resize_({size, size, size});
|
|
|
|
|
auto y_exp = torch::max(torch::zeros_like(x), x) +
|
|
|
|
|
torch::min(torch::zeros_like(x), alpha * (torch::exp(x / alpha) - 1.0));
|
Pass F::*FuncOptions instead of torch::nn::*Options to functionals, and make F::*FuncOptions a different class when necessary (#29364)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/29364
Currently, we use `torch::nn::*Options` both as module options and functional options. However, this makes it very hard to manage the parameters in `torch::nn::*Options`, because a module's constructor can take a different set of arguments than the module's equivalent functional (e.g. `torch.nn.BatchNorm1d` takes `num_features, eps=1e-5, momentum=0.1, affine=True,
track_running_stats=True`, while `F::batch_norm` takes `running_mean, running_var, weight=None, bias=None, training=False, momentum=0.1, eps=1e-5`).
This PR resolves the above problem by making `F::*FuncOptions` a different class from `torch::nn::*Options` when necessary (i.e. when a module's constructor takes a different set of arguments than the module's equivalent functional). In the rest of the cases where the module constructor takes the same set of arguments as the module's equivalent functional, `F::*FuncOptions` is an alias of `torch::nn::*Options`.
Also as part of this PR, we change all functional options to pass-by-value, to make the semantics consistent across all functionals.
Test Plan: Imported from OSS
Differential Revision: D18376977
Pulled By: yf225
fbshipit-source-id: 8d9c240d93bfd5af0165b6884fdc912476b1d06b
2019-11-09 06:36:49 +00:00
|
|
|
auto y = F::celu(x, F::CELUFuncOptions().alpha(alpha).inplace(inplace));
|
2019-10-11 13:21:06 +00:00
|
|
|
|
|
|
|
|
ASSERT_EQ(y.ndimension(), 3);
|
2019-10-15 00:58:14 +00:00
|
|
|
ASSERT_EQ(y.sizes(), std::vector<int64_t>({size, size, size}));
|
2019-10-11 13:21:06 +00:00
|
|
|
ASSERT_TRUE(torch::allclose(y, y_exp));
|
|
|
|
|
if (inplace) {
|
|
|
|
|
ASSERT_TRUE(torch::allclose(x, y_exp));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-11-20 00:06:25 +00:00
|
|
|
ASSERT_TRUE(F::celu(torch::tensor(1.)).defined());
|
2019-10-11 13:21:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(FunctionalTest, CELUDefaultOptions) {
|
|
|
|
|
const auto size = 3;
|
|
|
|
|
const auto alpha = 1.0;
|
|
|
|
|
auto x = torch::linspace(-10.0, 10.0, size * size * size);
|
|
|
|
|
x.resize_({size, size, size});
|
|
|
|
|
auto y_exp = torch::max(torch::zeros_like(x), x) +
|
|
|
|
|
torch::min(torch::zeros_like(x), alpha * (torch::exp(x / alpha) - 1.0));
|
|
|
|
|
auto y = F::celu(x);
|
|
|
|
|
|
|
|
|
|
ASSERT_EQ(y.ndimension(), 3);
|
2019-10-15 00:58:14 +00:00
|
|
|
ASSERT_EQ(y.sizes(), std::vector<int64_t>({size, size, size}));
|
2019-10-11 13:21:06 +00:00
|
|
|
ASSERT_TRUE(torch::allclose(y, y_exp));
|
|
|
|
|
}
|
2019-10-11 15:58:40 +00:00
|
|
|
|
2019-10-18 22:52:22 +00:00
|
|
|
TEST_F(FunctionalTest, PixelShuffle) {
|
|
|
|
|
auto x = torch::tensor(
|
|
|
|
|
{{{{-17, 19}, {-1, 2}},
|
|
|
|
|
{{7, 14}, {-3, 1}},
|
|
|
|
|
{{0, -2}, {-12, 14}},
|
|
|
|
|
{{-15, 0}, {-3, 9}}}}, torch::kFloat);
|
|
|
|
|
auto y_exp = torch::tensor(
|
|
|
|
|
{{{{-17, 7, 19, 14},
|
|
|
|
|
{0, -15, -2, 0},
|
|
|
|
|
{-1, -3, 2, 1},
|
|
|
|
|
{-12, -3, 14, 9}}}}, torch::kFloat);
|
|
|
|
|
auto y = F::pixel_shuffle(x, 2);
|
|
|
|
|
|
|
|
|
|
ASSERT_EQ(y.ndimension(), 4);
|
|
|
|
|
ASSERT_EQ(y.sizes(), torch::IntArrayRef({1, 1, 4, 4}));
|
|
|
|
|
ASSERT_TRUE(y.allclose(y_exp));
|
|
|
|
|
}
|
2020-12-23 04:12:40 +00:00
|
|
|
|
|
|
|
|
TEST_F(FunctionalTest, PixelUnshuffle) {
|
|
|
|
|
auto x = torch::tensor(
|
|
|
|
|
{{{{-17, 7, 19, 14}, {0, -15, -2, 0}, {-1, -3, 2, 1}, {-12, -3, 14, 9}}}},
|
|
|
|
|
torch::kFloat);
|
|
|
|
|
auto y_exp = torch::tensor(
|
|
|
|
|
{{{{-17, 19}, {-1, 2}},
|
|
|
|
|
{{7, 14}, {-3, 1}},
|
|
|
|
|
{{0, -2}, {-12, 14}},
|
|
|
|
|
{{-15, 0}, {-3, 9}}}},
|
|
|
|
|
torch::kFloat);
|
|
|
|
|
auto y = F::pixel_unshuffle(x, 2);
|
|
|
|
|
|
|
|
|
|
ASSERT_EQ(y.ndimension(), 4);
|
|
|
|
|
ASSERT_EQ(y.sizes(), torch::IntArrayRef({1, 4, 2, 2}));
|
|
|
|
|
ASSERT_TRUE(y.allclose(y_exp));
|
|
|
|
|
}
|
2019-10-18 22:52:22 +00:00
|
|
|
|
2019-10-11 15:58:40 +00:00
|
|
|
TEST_F(FunctionalTest, Softplus) {
|
|
|
|
|
const auto size = 3;
|
|
|
|
|
for (const auto beta : {0.5, 1.0, 2.0}) {
|
|
|
|
|
for (const auto threshold : {1.0, 3.0, 5.0}) {
|
|
|
|
|
auto x = torch::linspace(-3.0, 3.0, 61);
|
|
|
|
|
x.resize_({size, size, size});
|
|
|
|
|
auto y_exp =
|
|
|
|
|
(x <= threshold) * torch::log(1 + torch::exp(x * beta)) / beta +
|
|
|
|
|
(x > threshold) * x;
|
|
|
|
|
auto y = F::softplus(x,
|
Pass F::*FuncOptions instead of torch::nn::*Options to functionals, and make F::*FuncOptions a different class when necessary (#29364)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/29364
Currently, we use `torch::nn::*Options` both as module options and functional options. However, this makes it very hard to manage the parameters in `torch::nn::*Options`, because a module's constructor can take a different set of arguments than the module's equivalent functional (e.g. `torch.nn.BatchNorm1d` takes `num_features, eps=1e-5, momentum=0.1, affine=True,
track_running_stats=True`, while `F::batch_norm` takes `running_mean, running_var, weight=None, bias=None, training=False, momentum=0.1, eps=1e-5`).
This PR resolves the above problem by making `F::*FuncOptions` a different class from `torch::nn::*Options` when necessary (i.e. when a module's constructor takes a different set of arguments than the module's equivalent functional). In the rest of the cases where the module constructor takes the same set of arguments as the module's equivalent functional, `F::*FuncOptions` is an alias of `torch::nn::*Options`.
Also as part of this PR, we change all functional options to pass-by-value, to make the semantics consistent across all functionals.
Test Plan: Imported from OSS
Differential Revision: D18376977
Pulled By: yf225
fbshipit-source-id: 8d9c240d93bfd5af0165b6884fdc912476b1d06b
2019-11-09 06:36:49 +00:00
|
|
|
F::SoftplusFuncOptions().beta(beta).threshold(threshold));
|
2019-10-11 15:58:40 +00:00
|
|
|
|
|
|
|
|
ASSERT_EQ(y.ndimension(), 3);
|
2019-10-15 00:58:14 +00:00
|
|
|
ASSERT_EQ(y.sizes(), std::vector<int64_t>({size, size, size}));
|
2019-10-11 15:58:40 +00:00
|
|
|
ASSERT_TRUE(torch::allclose(y, y_exp));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(FunctionalTest, SoftplusDefaultOptions) {
|
|
|
|
|
const auto size = 3;
|
|
|
|
|
const auto beta = 1.0;
|
|
|
|
|
const auto threshold = 20.0;
|
|
|
|
|
auto x = torch::linspace(-3.0, 3.0, 61);
|
|
|
|
|
x.resize_({size, size, size});
|
|
|
|
|
auto y_exp =
|
|
|
|
|
(x <= threshold) * torch::log(1 + torch::exp(x * beta)) / beta +
|
|
|
|
|
(x > threshold) * x;
|
|
|
|
|
auto y = F::softplus(x);
|
|
|
|
|
|
|
|
|
|
ASSERT_EQ(y.ndimension(), 3);
|
2019-10-15 00:58:14 +00:00
|
|
|
ASSERT_EQ(y.sizes(), std::vector<int64_t>({size, size, size}));
|
2019-10-11 15:58:40 +00:00
|
|
|
ASSERT_TRUE(torch::allclose(y, y_exp));
|
|
|
|
|
}
|
2019-10-12 13:34:57 +00:00
|
|
|
|
2019-10-30 18:33:54 +00:00
|
|
|
TEST_F(FunctionalTest, Fold) {
|
|
|
|
|
auto input = torch::ones({1, 3 * 2 * 2, 2}, torch::kDouble);
|
Pass F::*FuncOptions instead of torch::nn::*Options to functionals, and make F::*FuncOptions a different class when necessary (#29364)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/29364
Currently, we use `torch::nn::*Options` both as module options and functional options. However, this makes it very hard to manage the parameters in `torch::nn::*Options`, because a module's constructor can take a different set of arguments than the module's equivalent functional (e.g. `torch.nn.BatchNorm1d` takes `num_features, eps=1e-5, momentum=0.1, affine=True,
track_running_stats=True`, while `F::batch_norm` takes `running_mean, running_var, weight=None, bias=None, training=False, momentum=0.1, eps=1e-5`).
This PR resolves the above problem by making `F::*FuncOptions` a different class from `torch::nn::*Options` when necessary (i.e. when a module's constructor takes a different set of arguments than the module's equivalent functional). In the rest of the cases where the module constructor takes the same set of arguments as the module's equivalent functional, `F::*FuncOptions` is an alias of `torch::nn::*Options`.
Also as part of this PR, we change all functional options to pass-by-value, to make the semantics consistent across all functionals.
Test Plan: Imported from OSS
Differential Revision: D18376977
Pulled By: yf225
fbshipit-source-id: 8d9c240d93bfd5af0165b6884fdc912476b1d06b
2019-11-09 06:36:49 +00:00
|
|
|
auto output = F::fold(input, F::FoldFuncOptions({3, 2}, {2, 2}));
|
2019-10-30 18:33:54 +00:00
|
|
|
auto expected = torch::tensor(
|
|
|
|
|
{{{{1.0, 1.0}, {2.0, 2.0}, {1.0, 1.0}},
|
|
|
|
|
{{1.0, 1.0}, {2.0, 2.0}, {1.0, 1.0}},
|
|
|
|
|
{{1.0, 1.0}, {2.0, 2.0}, {1.0, 1.0}}}},
|
|
|
|
|
torch::kDouble);
|
|
|
|
|
|
|
|
|
|
ASSERT_EQ(output.sizes(), std::vector<int64_t>({1, 3, 3, 2}));
|
|
|
|
|
ASSERT_TRUE(output.allclose(expected));
|
|
|
|
|
}
|
2019-10-14 20:20:06 +00:00
|
|
|
|
2019-10-30 18:33:54 +00:00
|
|
|
TEST_F(FunctionalTest, Unfold) {
|
|
|
|
|
auto input = torch::arange(0, 12, torch::kDouble).view({1, 2, 2, 3});
|
Pass F::*FuncOptions instead of torch::nn::*Options to functionals, and make F::*FuncOptions a different class when necessary (#29364)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/29364
Currently, we use `torch::nn::*Options` both as module options and functional options. However, this makes it very hard to manage the parameters in `torch::nn::*Options`, because a module's constructor can take a different set of arguments than the module's equivalent functional (e.g. `torch.nn.BatchNorm1d` takes `num_features, eps=1e-5, momentum=0.1, affine=True,
track_running_stats=True`, while `F::batch_norm` takes `running_mean, running_var, weight=None, bias=None, training=False, momentum=0.1, eps=1e-5`).
This PR resolves the above problem by making `F::*FuncOptions` a different class from `torch::nn::*Options` when necessary (i.e. when a module's constructor takes a different set of arguments than the module's equivalent functional). In the rest of the cases where the module constructor takes the same set of arguments as the module's equivalent functional, `F::*FuncOptions` is an alias of `torch::nn::*Options`.
Also as part of this PR, we change all functional options to pass-by-value, to make the semantics consistent across all functionals.
Test Plan: Imported from OSS
Differential Revision: D18376977
Pulled By: yf225
fbshipit-source-id: 8d9c240d93bfd5af0165b6884fdc912476b1d06b
2019-11-09 06:36:49 +00:00
|
|
|
auto output = F::unfold(input, F::UnfoldFuncOptions({2, 2}).padding(1).stride(2));
|
2019-10-30 18:33:54 +00:00
|
|
|
auto expected = torch::tensor(
|
|
|
|
|
{{{0.0, 0.0, 0.0, 4.0},
|
|
|
|
|
{0.0, 0.0, 3.0, 5.0},
|
|
|
|
|
{0.0, 1.0, 0.0, 0.0},
|
|
|
|
|
{0.0, 2.0, 0.0, 0.0},
|
|
|
|
|
{0.0, 0.0, 0.0, 10.0},
|
|
|
|
|
{0.0, 0.0, 9.0, 11.0},
|
|
|
|
|
{0.0, 7.0, 0.0, 0.0},
|
|
|
|
|
{6.0, 8.0, 0.0, 0.0}}},
|
|
|
|
|
torch::kDouble);
|
|
|
|
|
|
|
|
|
|
ASSERT_EQ(output.sizes(), std::vector<int64_t>({1, 8, 4}));
|
|
|
|
|
ASSERT_TRUE(output.allclose(expected));
|
2019-10-14 20:20:06 +00:00
|
|
|
}
|
|
|
|
|
|
2019-10-12 13:34:57 +00:00
|
|
|
TEST_F(FunctionalTest, Softshrink) {
|
|
|
|
|
const auto size = 3;
|
|
|
|
|
for (const auto lambda : {0.0, 0.42, 1.0, 4.2, 42.42}) {
|
|
|
|
|
auto x = torch::linspace(-10.0, 10.0, size * size * size);
|
|
|
|
|
x.resize_({size, size, size}).set_requires_grad(true);
|
|
|
|
|
auto y = F::softshrink(x, /*lambda=*/lambda);
|
|
|
|
|
torch::Tensor s = y.sum();
|
|
|
|
|
|
|
|
|
|
s.backward();
|
|
|
|
|
ASSERT_EQ(s.ndimension(), 0);
|
|
|
|
|
|
|
|
|
|
ASSERT_EQ(y.ndimension(), 3);
|
2019-10-15 00:58:14 +00:00
|
|
|
ASSERT_EQ(y.sizes(), std::vector<int64_t>({size, size, size}));
|
2019-10-12 13:34:57 +00:00
|
|
|
auto y_exp = (x < -lambda) * (x + lambda) + (x > lambda) * (x - lambda);
|
|
|
|
|
ASSERT_TRUE(torch::allclose(y, y_exp));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(FunctionalTest, SoftshrinkDefaultOptions) {
|
|
|
|
|
const auto size = 3;
|
|
|
|
|
const auto lambda = 0.5;
|
|
|
|
|
auto x = torch::linspace(-10.0, 10.0, size * size * size);
|
|
|
|
|
x.resize_({size, size, size}).set_requires_grad(true);
|
|
|
|
|
auto y = F::softshrink(x);
|
|
|
|
|
torch::Tensor s = y.sum();
|
|
|
|
|
|
|
|
|
|
s.backward();
|
|
|
|
|
ASSERT_EQ(s.ndimension(), 0);
|
|
|
|
|
|
|
|
|
|
ASSERT_EQ(y.ndimension(), 3);
|
2019-10-15 00:58:14 +00:00
|
|
|
ASSERT_EQ(y.sizes(), std::vector<int64_t>({size, size, size}));
|
2019-10-12 13:34:57 +00:00
|
|
|
auto y_exp = (x < -lambda) * (x + lambda) + (x > lambda) * (x - lambda);
|
2019-10-12 14:54:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(FunctionalTest, Softsign) {
|
|
|
|
|
auto x = torch::randn(100) * 10;
|
|
|
|
|
auto y_exp = x / (1 + x.abs());
|
|
|
|
|
auto y = F::softsign(x);
|
|
|
|
|
|
2019-10-12 13:34:57 +00:00
|
|
|
ASSERT_TRUE(torch::allclose(y, y_exp));
|
|
|
|
|
}
|
2019-10-13 15:10:43 +00:00
|
|
|
|
|
|
|
|
TEST_F(FunctionalTest, Tanhshrink) {
|
|
|
|
|
auto x = torch::randn(100) * 10;
|
|
|
|
|
auto y_exp = x - x.tanh();
|
|
|
|
|
auto y = F::tanhshrink(x);
|
|
|
|
|
|
|
|
|
|
ASSERT_TRUE(torch::allclose(y, y_exp));
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-13 16:36:18 +00:00
|
|
|
TEST_F(FunctionalTest, Threshold) {
|
|
|
|
|
const auto size = 3;
|
|
|
|
|
for (const auto threshold : {0.5, 1.0, 2.0}) {
|
|
|
|
|
for (const auto value : {0.5, 1.0, 2.0}) {
|
|
|
|
|
for (const auto inplace : {false, true}) {
|
|
|
|
|
auto x = torch::linspace(-3.0, 3.0, 61);
|
|
|
|
|
x.resize_({size, size, size});
|
|
|
|
|
auto y_exp = (x <= threshold) * value + (x > threshold) * x;
|
|
|
|
|
auto y = F::threshold(x,
|
Pass F::*FuncOptions instead of torch::nn::*Options to functionals, and make F::*FuncOptions a different class when necessary (#29364)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/29364
Currently, we use `torch::nn::*Options` both as module options and functional options. However, this makes it very hard to manage the parameters in `torch::nn::*Options`, because a module's constructor can take a different set of arguments than the module's equivalent functional (e.g. `torch.nn.BatchNorm1d` takes `num_features, eps=1e-5, momentum=0.1, affine=True,
track_running_stats=True`, while `F::batch_norm` takes `running_mean, running_var, weight=None, bias=None, training=False, momentum=0.1, eps=1e-5`).
This PR resolves the above problem by making `F::*FuncOptions` a different class from `torch::nn::*Options` when necessary (i.e. when a module's constructor takes a different set of arguments than the module's equivalent functional). In the rest of the cases where the module constructor takes the same set of arguments as the module's equivalent functional, `F::*FuncOptions` is an alias of `torch::nn::*Options`.
Also as part of this PR, we change all functional options to pass-by-value, to make the semantics consistent across all functionals.
Test Plan: Imported from OSS
Differential Revision: D18376977
Pulled By: yf225
fbshipit-source-id: 8d9c240d93bfd5af0165b6884fdc912476b1d06b
2019-11-09 06:36:49 +00:00
|
|
|
F::ThresholdFuncOptions(threshold, value).inplace(inplace));
|
2019-10-13 16:36:18 +00:00
|
|
|
|
|
|
|
|
ASSERT_EQ(y.ndimension(), 3);
|
2019-10-15 00:58:14 +00:00
|
|
|
ASSERT_EQ(y.sizes(), std::vector<int64_t>({size, size, size}));
|
2019-10-13 16:36:18 +00:00
|
|
|
ASSERT_TRUE(torch::allclose(y, y_exp));
|
|
|
|
|
if (inplace) {
|
|
|
|
|
ASSERT_TRUE(torch::allclose(x, y_exp));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-11-20 00:06:25 +00:00
|
|
|
ASSERT_TRUE(F::threshold(torch::tensor(1.), F::ThresholdFuncOptions(0.5, 0.5)).defined());
|
2019-10-13 16:36:18 +00:00
|
|
|
}
|
2019-10-22 05:16:21 +00:00
|
|
|
|
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
|
|
|
TEST_F(FunctionalTest, BatchNorm1d) {
|
|
|
|
|
int num_features = 5;
|
|
|
|
|
double eps = 1e-05;
|
|
|
|
|
double momentum = 0.1;
|
|
|
|
|
|
|
|
|
|
auto input = torch::randn({2, 5});
|
|
|
|
|
auto mean = torch::randn(5);
|
|
|
|
|
auto variance = torch::rand(5);
|
|
|
|
|
auto weight = torch::ones({num_features});
|
|
|
|
|
auto bias = torch::zeros({num_features});
|
|
|
|
|
auto output = F::batch_norm(
|
|
|
|
|
input, mean, variance,
|
2019-11-13 00:02:38 +00:00
|
|
|
F::BatchNormFuncOptions().weight(weight).bias(bias).momentum(momentum).eps(eps).training(false));
|
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
|
|
|
auto expected = (input - mean) / torch::sqrt(variance + eps);
|
|
|
|
|
ASSERT_TRUE(output.allclose(expected));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(FunctionalTest, BatchNorm1dDefaultOptions) {
|
|
|
|
|
auto input = torch::randn({2, 5});
|
|
|
|
|
auto mean = torch::randn(5);
|
|
|
|
|
auto variance = torch::rand(5);
|
|
|
|
|
auto output = F::batch_norm(input, mean, variance);
|
|
|
|
|
auto expected = (input - mean) / torch::sqrt(variance + 1e-5);
|
|
|
|
|
ASSERT_TRUE(output.allclose(expected));
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-02 00:48:47 +00:00
|
|
|
TEST_F(FunctionalTest, BatchNorm2d) {
|
|
|
|
|
int num_features = 5;
|
|
|
|
|
double eps = 1e-05;
|
|
|
|
|
double momentum = 0.1;
|
|
|
|
|
|
|
|
|
|
auto input = torch::randn({2, num_features, 4, 4});
|
|
|
|
|
auto mean = torch::randn(num_features);
|
|
|
|
|
auto variance = torch::rand(num_features);
|
|
|
|
|
auto weight = torch::ones({num_features});
|
|
|
|
|
auto bias = torch::zeros({num_features});
|
|
|
|
|
auto output = F::batch_norm(
|
|
|
|
|
input, mean, variance,
|
2019-11-13 00:02:38 +00:00
|
|
|
F::BatchNormFuncOptions().weight(weight).bias(bias).momentum(momentum).eps(eps).training(false));
|
2019-11-02 00:48:47 +00:00
|
|
|
auto expected = torch::transpose((torch::transpose(input, 1, 3) - mean) / torch::sqrt(variance + eps), 1, 3);
|
|
|
|
|
ASSERT_TRUE(output.allclose(expected));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(FunctionalTest, BatchNorm2dDefaultOptions) {
|
|
|
|
|
int num_features = 5;
|
|
|
|
|
double eps = 1e-05;
|
|
|
|
|
|
|
|
|
|
auto input = torch::randn({2, num_features, 4, 4});
|
|
|
|
|
auto mean = torch::randn(num_features);
|
|
|
|
|
auto variance = torch::rand(num_features);
|
|
|
|
|
auto output = F::batch_norm(input, mean, variance);
|
|
|
|
|
auto expected = torch::transpose((torch::transpose(input, 1, 3) - mean) / torch::sqrt(variance + eps), 1, 3);
|
|
|
|
|
ASSERT_TRUE(output.allclose(expected));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(FunctionalTest, BatchNorm3d) {
|
|
|
|
|
int num_features = 5;
|
|
|
|
|
double eps = 1e-05;
|
|
|
|
|
double momentum = 0.1;
|
|
|
|
|
|
|
|
|
|
auto input = torch::randn({2, num_features, 2, 2, 2});
|
|
|
|
|
auto mean = torch::randn(num_features);
|
|
|
|
|
auto variance = torch::rand(num_features);
|
|
|
|
|
auto weight = torch::ones({num_features});
|
|
|
|
|
auto bias = torch::zeros({num_features});
|
|
|
|
|
auto output = F::batch_norm(
|
|
|
|
|
input, mean, variance,
|
2019-11-13 00:02:38 +00:00
|
|
|
F::BatchNormFuncOptions().weight(weight).bias(bias).momentum(momentum).eps(eps).training(false));
|
2019-11-02 00:48:47 +00:00
|
|
|
auto expected = torch::transpose((torch::transpose(input, 1, 4) - mean) / torch::sqrt(variance + eps), 1, 4);
|
|
|
|
|
ASSERT_TRUE(output.allclose(expected));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(FunctionalTest, BatchNorm3dDefaultOptions) {
|
|
|
|
|
int num_features = 5;
|
|
|
|
|
double eps = 1e-05;
|
|
|
|
|
|
|
|
|
|
auto input = torch::randn({2, num_features, 2, 2, 2});
|
|
|
|
|
auto mean = torch::randn(num_features);
|
|
|
|
|
auto variance = torch::rand(num_features);
|
|
|
|
|
auto output = F::batch_norm(input, mean, variance);
|
|
|
|
|
auto expected = torch::transpose((torch::transpose(input, 1, 4) - mean) / torch::sqrt(variance + eps), 1, 4);
|
|
|
|
|
ASSERT_TRUE(output.allclose(expected));
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-20 00:53:37 +00:00
|
|
|
TEST_F(FunctionalTest, InstanceNorm1d) {
|
|
|
|
|
int num_features = 5;
|
|
|
|
|
double eps = 1e-05;
|
|
|
|
|
double momentum = 0.1;
|
|
|
|
|
|
|
|
|
|
auto input = torch::arange(40.).view({2, 5, 4});
|
|
|
|
|
auto mean = torch::arange(5.);
|
|
|
|
|
auto variance = torch::arange(5.);
|
|
|
|
|
auto weight = torch::arange((double)num_features);
|
|
|
|
|
auto bias = torch::arange((double)num_features);
|
|
|
|
|
auto output = F::instance_norm(
|
|
|
|
|
input,
|
|
|
|
|
F::InstanceNormFuncOptions()
|
|
|
|
|
.running_mean(mean)
|
|
|
|
|
.running_var(variance)
|
|
|
|
|
.weight(weight)
|
|
|
|
|
.bias(bias)
|
|
|
|
|
.momentum(momentum)
|
|
|
|
|
.eps(eps));
|
|
|
|
|
auto expected = torch::tensor({{{ 0.0000, 0.0000, 0.0000, 0.0000},
|
|
|
|
|
{-0.3416, 0.5528, 1.4472, 2.3416},
|
|
|
|
|
{-0.6833, 1.1056, 2.8944, 4.6833},
|
|
|
|
|
{-1.0249, 1.6584, 4.3416, 7.0249},
|
|
|
|
|
{-1.3665, 2.2112, 5.7888, 9.3665}},
|
|
|
|
|
{{ 0.0000, 0.0000, 0.0000, 0.0000},
|
|
|
|
|
{-0.3416, 0.5528, 1.4472, 2.3416},
|
|
|
|
|
{-0.6833, 1.1056, 2.8944, 4.6833},
|
|
|
|
|
{-1.0249, 1.6584, 4.3416, 7.0249},
|
|
|
|
|
{-1.3665, 2.2112, 5.7888, 9.3665}}});
|
|
|
|
|
ASSERT_TRUE(output.allclose(expected, 2e-04));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(FunctionalTest, InstanceNorm1dDefaultOptions) {
|
|
|
|
|
auto input = torch::arange(40.).view({2, 5, 4});
|
|
|
|
|
auto output = F::instance_norm(input);
|
|
|
|
|
auto expected = torch::tensor({{{-1.3416, -0.4472, 0.4472, 1.3416},
|
|
|
|
|
{-1.3416, -0.4472, 0.4472, 1.3416},
|
|
|
|
|
{-1.3416, -0.4472, 0.4472, 1.3416},
|
|
|
|
|
{-1.3416, -0.4472, 0.4472, 1.3416},
|
|
|
|
|
{-1.3416, -0.4472, 0.4472, 1.3416}},
|
|
|
|
|
{{-1.3416, -0.4472, 0.4472, 1.3416},
|
|
|
|
|
{-1.3416, -0.4472, 0.4472, 1.3416},
|
|
|
|
|
{-1.3416, -0.4472, 0.4472, 1.3416},
|
|
|
|
|
{-1.3416, -0.4472, 0.4472, 1.3416},
|
|
|
|
|
{-1.3416, -0.4472, 0.4472, 1.3416}}});
|
|
|
|
|
ASSERT_TRUE(output.allclose(expected, 2e-04));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(FunctionalTest, InstanceNorm2d) {
|
|
|
|
|
int num_features = 5;
|
|
|
|
|
double eps = 1e-05;
|
|
|
|
|
double momentum = 0.1;
|
|
|
|
|
|
|
|
|
|
auto input = torch::arange(2. * num_features * 2 * 2).view({2, num_features, 2, 2});
|
|
|
|
|
auto mean = torch::arange((double)num_features);
|
|
|
|
|
auto variance = torch::arange((double)num_features);
|
|
|
|
|
auto weight = torch::arange((double)num_features);
|
|
|
|
|
auto bias = torch::arange((double)num_features);
|
|
|
|
|
auto output = F::instance_norm(
|
|
|
|
|
input,
|
|
|
|
|
F::InstanceNormFuncOptions()
|
|
|
|
|
.running_mean(mean)
|
|
|
|
|
.running_var(variance)
|
|
|
|
|
.weight(weight)
|
|
|
|
|
.bias(bias)
|
|
|
|
|
.momentum(momentum)
|
|
|
|
|
.eps(eps));
|
|
|
|
|
auto expected = torch::tensor({{{{ 0.0000, 0.0000},
|
|
|
|
|
{ 0.0000, 0.0000}},
|
|
|
|
|
{{-0.3416, 0.5528},
|
|
|
|
|
{ 1.4472, 2.3416}},
|
|
|
|
|
{{-0.6833, 1.1056},
|
|
|
|
|
{ 2.8944, 4.6833}},
|
|
|
|
|
{{-1.0249, 1.6584},
|
|
|
|
|
{ 4.3416, 7.0249}},
|
|
|
|
|
{{-1.3665, 2.2112},
|
|
|
|
|
{ 5.7888, 9.3665}}},
|
|
|
|
|
{{{ 0.0000, 0.0000},
|
|
|
|
|
{ 0.0000, 0.0000}},
|
|
|
|
|
{{-0.3416, 0.5528},
|
|
|
|
|
{ 1.4472, 2.3416}},
|
|
|
|
|
{{-0.6833, 1.1056},
|
|
|
|
|
{ 2.8944, 4.6833}},
|
|
|
|
|
{{-1.0249, 1.6584},
|
|
|
|
|
{ 4.3416, 7.0249}},
|
|
|
|
|
{{-1.3665, 2.2112},
|
|
|
|
|
{ 5.7888, 9.3665}}}});
|
|
|
|
|
ASSERT_TRUE(output.allclose(expected, 2e-04));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(FunctionalTest, InstanceNorm2dDefaultOptions) {
|
|
|
|
|
int num_features = 5;
|
|
|
|
|
double eps = 1e-05;
|
|
|
|
|
|
|
|
|
|
auto input = torch::arange(2. * num_features * 2 * 2).view({2, num_features, 2, 2});
|
|
|
|
|
auto output = F::instance_norm(input);
|
|
|
|
|
auto expected = torch::tensor({{{{-1.3416, -0.4472},
|
|
|
|
|
{ 0.4472, 1.3416}},
|
|
|
|
|
{{-1.3416, -0.4472},
|
|
|
|
|
{ 0.4472, 1.3416}},
|
|
|
|
|
{{-1.3416, -0.4472},
|
|
|
|
|
{ 0.4472, 1.3416}},
|
|
|
|
|
{{-1.3416, -0.4472},
|
|
|
|
|
{ 0.4472, 1.3416}},
|
|
|
|
|
{{-1.3416, -0.4472},
|
|
|
|
|
{ 0.4472, 1.3416}}},
|
|
|
|
|
{{{-1.3416, -0.4472},
|
|
|
|
|
{ 0.4472, 1.3416}},
|
|
|
|
|
{{-1.3416, -0.4472},
|
|
|
|
|
{ 0.4472, 1.3416}},
|
|
|
|
|
{{-1.3416, -0.4472},
|
|
|
|
|
{ 0.4472, 1.3416}},
|
|
|
|
|
{{-1.3416, -0.4472},
|
|
|
|
|
{ 0.4472, 1.3416}},
|
|
|
|
|
{{-1.3416, -0.4472},
|
|
|
|
|
{ 0.4472, 1.3416}}}});
|
|
|
|
|
ASSERT_TRUE(output.allclose(expected, 2e-04));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(FunctionalTest, InstanceNorm3d) {
|
|
|
|
|
int num_features = 5;
|
|
|
|
|
double eps = 1e-05;
|
|
|
|
|
double momentum = 0.1;
|
|
|
|
|
|
|
|
|
|
auto input = torch::arange(2. * num_features * 2 * 2 * 2).view({2, num_features, 2, 2, 2});
|
|
|
|
|
auto mean = torch::arange((double)num_features);
|
|
|
|
|
auto variance = torch::arange((double)num_features);
|
|
|
|
|
auto weight = torch::arange((double)num_features);
|
|
|
|
|
auto bias = torch::arange((double)num_features);
|
|
|
|
|
auto output = F::instance_norm(
|
|
|
|
|
input,
|
|
|
|
|
F::InstanceNormFuncOptions()
|
|
|
|
|
.running_mean(mean)
|
|
|
|
|
.running_var(variance)
|
|
|
|
|
.weight(weight)
|
|
|
|
|
.bias(bias)
|
|
|
|
|
.momentum(momentum)
|
|
|
|
|
.eps(eps));
|
|
|
|
|
auto expected = torch::tensor({{{{{ 0.0000, 0.0000},
|
|
|
|
|
{ 0.0000, 0.0000}},
|
|
|
|
|
{{ 0.0000, 0.0000},
|
|
|
|
|
{ 0.0000, 0.0000}}},
|
|
|
|
|
{{{-0.5275, -0.0911},
|
|
|
|
|
{ 0.3453, 0.7818}},
|
|
|
|
|
{{ 1.2182, 1.6547},
|
|
|
|
|
{ 2.0911, 2.5275}}},
|
|
|
|
|
{{{-1.0550, -0.1822},
|
|
|
|
|
{ 0.6907, 1.5636}},
|
|
|
|
|
{{ 2.4364, 3.3093},
|
|
|
|
|
{ 4.1822, 5.0550}}},
|
|
|
|
|
{{{-1.5826, -0.2733},
|
|
|
|
|
{ 1.0360, 2.3453}},
|
|
|
|
|
{{ 3.6547, 4.9640},
|
|
|
|
|
{ 6.2733, 7.5826}}},
|
|
|
|
|
{{{-2.1101, -0.3644},
|
|
|
|
|
{ 1.3814, 3.1271}},
|
|
|
|
|
{{ 4.8729, 6.6186},
|
|
|
|
|
{ 8.3644, 10.1101}}}},
|
|
|
|
|
{{{{ 0.0000, 0.0000},
|
|
|
|
|
{ 0.0000, 0.0000}},
|
|
|
|
|
{{ 0.0000, 0.0000},
|
|
|
|
|
{ 0.0000, 0.0000}}},
|
|
|
|
|
{{{-0.5275, -0.0911},
|
|
|
|
|
{ 0.3453, 0.7818}},
|
|
|
|
|
{{ 1.2182, 1.6547},
|
|
|
|
|
{ 2.0911, 2.5275}}},
|
|
|
|
|
{{{-1.0550, -0.1822},
|
|
|
|
|
{ 0.6907, 1.5636}},
|
|
|
|
|
{{ 2.4364, 3.3093},
|
|
|
|
|
{ 4.1822, 5.0550}}},
|
|
|
|
|
{{{-1.5826, -0.2733},
|
|
|
|
|
{ 1.0360, 2.3453}},
|
|
|
|
|
{{ 3.6547, 4.9640},
|
|
|
|
|
{ 6.2733, 7.5826}}},
|
|
|
|
|
{{{-2.1101, -0.3644},
|
|
|
|
|
{ 1.3814, 3.1271}},
|
|
|
|
|
{{ 4.8729, 6.6186},
|
|
|
|
|
{ 8.3644, 10.1101}}}}});
|
|
|
|
|
ASSERT_TRUE(output.allclose(expected, 2e-04));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(FunctionalTest, InstanceNorm3dDefaultOptions) {
|
|
|
|
|
int num_features = 5;
|
|
|
|
|
double eps = 1e-05;
|
|
|
|
|
|
|
|
|
|
auto input = torch::arange(2. * num_features * 2 * 2 * 2).view({2, num_features, 2, 2, 2});
|
|
|
|
|
auto output = F::instance_norm(input);
|
|
|
|
|
auto expected = torch::tensor({{{{{-1.5275, -1.0911},
|
|
|
|
|
{-0.6547, -0.2182}},
|
|
|
|
|
{{ 0.2182, 0.6547},
|
|
|
|
|
{ 1.0911, 1.5275}}},
|
|
|
|
|
{{{-1.5275, -1.0911},
|
|
|
|
|
{-0.6547, -0.2182}},
|
|
|
|
|
{{ 0.2182, 0.6547},
|
|
|
|
|
{ 1.0911, 1.5275}}},
|
|
|
|
|
{{{-1.5275, -1.0911},
|
|
|
|
|
{-0.6547, -0.2182}},
|
|
|
|
|
{{ 0.2182, 0.6547},
|
|
|
|
|
{ 1.0911, 1.5275}}},
|
|
|
|
|
{{{-1.5275, -1.0911},
|
|
|
|
|
{-0.6547, -0.2182}},
|
|
|
|
|
{{ 0.2182, 0.6547},
|
|
|
|
|
{ 1.0911, 1.5275}}},
|
|
|
|
|
{{{-1.5275, -1.0911},
|
|
|
|
|
{-0.6547, -0.2182}},
|
|
|
|
|
{{ 0.2182, 0.6547},
|
|
|
|
|
{ 1.0911, 1.5275}}}},
|
|
|
|
|
{{{{-1.5275, -1.0911},
|
|
|
|
|
{-0.6547, -0.2182}},
|
|
|
|
|
{{ 0.2182, 0.6547},
|
|
|
|
|
{ 1.0911, 1.5275}}},
|
|
|
|
|
{{{-1.5275, -1.0911},
|
|
|
|
|
{-0.6547, -0.2182}},
|
|
|
|
|
{{ 0.2182, 0.6547},
|
|
|
|
|
{ 1.0911, 1.5275}}},
|
|
|
|
|
{{{-1.5275, -1.0911},
|
|
|
|
|
{-0.6547, -0.2182}},
|
|
|
|
|
{{ 0.2182, 0.6547},
|
|
|
|
|
{ 1.0911, 1.5275}}},
|
|
|
|
|
{{{-1.5275, -1.0911},
|
|
|
|
|
{-0.6547, -0.2182}},
|
|
|
|
|
{{ 0.2182, 0.6547},
|
|
|
|
|
{ 1.0911, 1.5275}}},
|
|
|
|
|
{{{-1.5275, -1.0911},
|
|
|
|
|
{-0.6547, -0.2182}},
|
|
|
|
|
{{ 0.2182, 0.6547},
|
|
|
|
|
{ 1.0911, 1.5275}}}}});
|
|
|
|
|
ASSERT_TRUE(output.allclose(expected, 2e-04));
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-29 04:32:30 +00:00
|
|
|
TEST_F(FunctionalTest, Interpolate) {
|
|
|
|
|
{
|
|
|
|
|
// 1D interpolation
|
|
|
|
|
auto input = torch::ones({1, 1, 2});
|
Pass F::*FuncOptions instead of torch::nn::*Options to functionals, and make F::*FuncOptions a different class when necessary (#29364)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/29364
Currently, we use `torch::nn::*Options` both as module options and functional options. However, this makes it very hard to manage the parameters in `torch::nn::*Options`, because a module's constructor can take a different set of arguments than the module's equivalent functional (e.g. `torch.nn.BatchNorm1d` takes `num_features, eps=1e-5, momentum=0.1, affine=True,
track_running_stats=True`, while `F::batch_norm` takes `running_mean, running_var, weight=None, bias=None, training=False, momentum=0.1, eps=1e-5`).
This PR resolves the above problem by making `F::*FuncOptions` a different class from `torch::nn::*Options` when necessary (i.e. when a module's constructor takes a different set of arguments than the module's equivalent functional). In the rest of the cases where the module constructor takes the same set of arguments as the module's equivalent functional, `F::*FuncOptions` is an alias of `torch::nn::*Options`.
Also as part of this PR, we change all functional options to pass-by-value, to make the semantics consistent across all functionals.
Test Plan: Imported from OSS
Differential Revision: D18376977
Pulled By: yf225
fbshipit-source-id: 8d9c240d93bfd5af0165b6884fdc912476b1d06b
2019-11-09 06:36:49 +00:00
|
|
|
auto options = F::InterpolateFuncOptions()
|
2020-03-21 04:45:37 +00:00
|
|
|
.size(std::vector<int64_t>({4}))
|
2019-10-29 04:32:30 +00:00
|
|
|
.mode(torch::kNearest);
|
|
|
|
|
auto output = F::interpolate(input, options);
|
|
|
|
|
auto expected = torch::ones({1, 1, 4});
|
|
|
|
|
|
|
|
|
|
ASSERT_TRUE(output.allclose(expected));
|
|
|
|
|
}
|
|
|
|
|
{
|
|
|
|
|
// 2D interpolation
|
|
|
|
|
for (const auto align_corners : {true, false}) {
|
|
|
|
|
// test float scale factor up & down sampling
|
|
|
|
|
for (const auto scale_factor : {0.5, 1.5, 2.0}) {
|
|
|
|
|
auto input = torch::ones({1, 1, 2, 2});
|
Pass F::*FuncOptions instead of torch::nn::*Options to functionals, and make F::*FuncOptions a different class when necessary (#29364)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/29364
Currently, we use `torch::nn::*Options` both as module options and functional options. However, this makes it very hard to manage the parameters in `torch::nn::*Options`, because a module's constructor can take a different set of arguments than the module's equivalent functional (e.g. `torch.nn.BatchNorm1d` takes `num_features, eps=1e-5, momentum=0.1, affine=True,
track_running_stats=True`, while `F::batch_norm` takes `running_mean, running_var, weight=None, bias=None, training=False, momentum=0.1, eps=1e-5`).
This PR resolves the above problem by making `F::*FuncOptions` a different class from `torch::nn::*Options` when necessary (i.e. when a module's constructor takes a different set of arguments than the module's equivalent functional). In the rest of the cases where the module constructor takes the same set of arguments as the module's equivalent functional, `F::*FuncOptions` is an alias of `torch::nn::*Options`.
Also as part of this PR, we change all functional options to pass-by-value, to make the semantics consistent across all functionals.
Test Plan: Imported from OSS
Differential Revision: D18376977
Pulled By: yf225
fbshipit-source-id: 8d9c240d93bfd5af0165b6884fdc912476b1d06b
2019-11-09 06:36:49 +00:00
|
|
|
auto options = F::InterpolateFuncOptions()
|
2020-03-21 04:45:37 +00:00
|
|
|
.scale_factor(std::vector<double>({scale_factor, scale_factor}))
|
2019-10-29 04:32:30 +00:00
|
|
|
.mode(torch::kBilinear)
|
|
|
|
|
.align_corners(align_corners);
|
|
|
|
|
auto output = F::interpolate(input, options);
|
|
|
|
|
auto expected_size =
|
|
|
|
|
static_cast<int64_t>(std::floor(input.size(-1) * scale_factor));
|
|
|
|
|
auto expected = torch::ones({1, 1, expected_size, expected_size});
|
|
|
|
|
|
|
|
|
|
ASSERT_TRUE(output.allclose(expected));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
{
|
|
|
|
|
// 3D interpolation
|
|
|
|
|
for (const auto align_corners : {true, false}) {
|
|
|
|
|
for (const auto scale_factor : {0.5, 1.5, 2.0}) {
|
|
|
|
|
auto input = torch::ones({1, 1, 2, 2, 2});
|
|
|
|
|
auto options =
|
Pass F::*FuncOptions instead of torch::nn::*Options to functionals, and make F::*FuncOptions a different class when necessary (#29364)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/29364
Currently, we use `torch::nn::*Options` both as module options and functional options. However, this makes it very hard to manage the parameters in `torch::nn::*Options`, because a module's constructor can take a different set of arguments than the module's equivalent functional (e.g. `torch.nn.BatchNorm1d` takes `num_features, eps=1e-5, momentum=0.1, affine=True,
track_running_stats=True`, while `F::batch_norm` takes `running_mean, running_var, weight=None, bias=None, training=False, momentum=0.1, eps=1e-5`).
This PR resolves the above problem by making `F::*FuncOptions` a different class from `torch::nn::*Options` when necessary (i.e. when a module's constructor takes a different set of arguments than the module's equivalent functional). In the rest of the cases where the module constructor takes the same set of arguments as the module's equivalent functional, `F::*FuncOptions` is an alias of `torch::nn::*Options`.
Also as part of this PR, we change all functional options to pass-by-value, to make the semantics consistent across all functionals.
Test Plan: Imported from OSS
Differential Revision: D18376977
Pulled By: yf225
fbshipit-source-id: 8d9c240d93bfd5af0165b6884fdc912476b1d06b
2019-11-09 06:36:49 +00:00
|
|
|
F::InterpolateFuncOptions()
|
2020-03-21 04:45:37 +00:00
|
|
|
.scale_factor(std::vector<double>({scale_factor, scale_factor, scale_factor}))
|
2019-10-29 04:32:30 +00:00
|
|
|
.mode(torch::kTrilinear)
|
|
|
|
|
.align_corners(align_corners);
|
|
|
|
|
auto output = F::interpolate(input, options);
|
|
|
|
|
auto expected_size =
|
|
|
|
|
static_cast<int64_t>(std::floor(input.size(-1) * scale_factor));
|
|
|
|
|
auto expected =
|
|
|
|
|
torch::ones({1, 1, expected_size, expected_size, expected_size});
|
|
|
|
|
|
|
|
|
|
ASSERT_TRUE(output.allclose(expected));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
{
|
|
|
|
|
auto input = torch::randn({3, 2, 2});
|
|
|
|
|
ASSERT_THROWS_WITH(
|
2020-03-21 04:45:37 +00:00
|
|
|
F::interpolate(input[0], F::InterpolateFuncOptions().size(std::vector<int64_t>({4, 4}))),
|
2019-10-29 04:32:30 +00:00
|
|
|
"Input Error: Only 3D, 4D and 5D input Tensors supported (got 2D) "
|
|
|
|
|
"for the modes: nearest | linear | bilinear | bicubic | trilinear (got kNearest)");
|
|
|
|
|
ASSERT_THROWS_WITH(
|
|
|
|
|
F::interpolate(
|
|
|
|
|
torch::reshape(input, {1, 1, 1, 3, 2, 2}),
|
2020-03-21 04:45:37 +00:00
|
|
|
F::InterpolateFuncOptions().size(std::vector<int64_t>({1, 1, 1, 3, 4, 4}))),
|
2019-10-29 04:32:30 +00:00
|
|
|
"Input Error: Only 3D, 4D and 5D input Tensors supported (got 6D) "
|
|
|
|
|
"for the modes: nearest | linear | bilinear | bicubic | trilinear (got kNearest)");
|
|
|
|
|
ASSERT_THROWS_WITH(
|
Pass F::*FuncOptions instead of torch::nn::*Options to functionals, and make F::*FuncOptions a different class when necessary (#29364)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/29364
Currently, we use `torch::nn::*Options` both as module options and functional options. However, this makes it very hard to manage the parameters in `torch::nn::*Options`, because a module's constructor can take a different set of arguments than the module's equivalent functional (e.g. `torch.nn.BatchNorm1d` takes `num_features, eps=1e-5, momentum=0.1, affine=True,
track_running_stats=True`, while `F::batch_norm` takes `running_mean, running_var, weight=None, bias=None, training=False, momentum=0.1, eps=1e-5`).
This PR resolves the above problem by making `F::*FuncOptions` a different class from `torch::nn::*Options` when necessary (i.e. when a module's constructor takes a different set of arguments than the module's equivalent functional). In the rest of the cases where the module constructor takes the same set of arguments as the module's equivalent functional, `F::*FuncOptions` is an alias of `torch::nn::*Options`.
Also as part of this PR, we change all functional options to pass-by-value, to make the semantics consistent across all functionals.
Test Plan: Imported from OSS
Differential Revision: D18376977
Pulled By: yf225
fbshipit-source-id: 8d9c240d93bfd5af0165b6884fdc912476b1d06b
2019-11-09 06:36:49 +00:00
|
|
|
F::interpolate(input, F::InterpolateFuncOptions()),
|
2019-10-29 04:32:30 +00:00
|
|
|
"either size or scale_factor should be defined");
|
|
|
|
|
ASSERT_THROWS_WITH(
|
|
|
|
|
F::interpolate(
|
|
|
|
|
input,
|
2020-03-21 04:45:37 +00:00
|
|
|
F::InterpolateFuncOptions().size(std::vector<int64_t>({3, 4, 4})).scale_factor(std::vector<double>({0.5}))),
|
2019-10-29 04:32:30 +00:00
|
|
|
"only one of size or scale_factor should be defined");
|
|
|
|
|
ASSERT_THROWS_WITH(
|
2020-03-21 04:45:37 +00:00
|
|
|
F::interpolate(input, F::InterpolateFuncOptions().scale_factor(std::vector<double>({3, 2}))),
|
2019-10-29 04:32:30 +00:00
|
|
|
"scale_factor shape must match input shape. "
|
2020-03-21 04:45:37 +00:00
|
|
|
"Input is 1D, scale_factor size is [3, 2]");
|
2019-10-29 04:32:30 +00:00
|
|
|
ASSERT_THROWS_WITH(
|
|
|
|
|
F::interpolate(
|
|
|
|
|
input,
|
Pass F::*FuncOptions instead of torch::nn::*Options to functionals, and make F::*FuncOptions a different class when necessary (#29364)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/29364
Currently, we use `torch::nn::*Options` both as module options and functional options. However, this makes it very hard to manage the parameters in `torch::nn::*Options`, because a module's constructor can take a different set of arguments than the module's equivalent functional (e.g. `torch.nn.BatchNorm1d` takes `num_features, eps=1e-5, momentum=0.1, affine=True,
track_running_stats=True`, while `F::batch_norm` takes `running_mean, running_var, weight=None, bias=None, training=False, momentum=0.1, eps=1e-5`).
This PR resolves the above problem by making `F::*FuncOptions` a different class from `torch::nn::*Options` when necessary (i.e. when a module's constructor takes a different set of arguments than the module's equivalent functional). In the rest of the cases where the module constructor takes the same set of arguments as the module's equivalent functional, `F::*FuncOptions` is an alias of `torch::nn::*Options`.
Also as part of this PR, we change all functional options to pass-by-value, to make the semantics consistent across all functionals.
Test Plan: Imported from OSS
Differential Revision: D18376977
Pulled By: yf225
fbshipit-source-id: 8d9c240d93bfd5af0165b6884fdc912476b1d06b
2019-11-09 06:36:49 +00:00
|
|
|
F::InterpolateFuncOptions()
|
2019-10-29 04:32:30 +00:00
|
|
|
.mode(torch::kNearest)
|
|
|
|
|
.align_corners(true)),
|
|
|
|
|
"align_corners option can only be set with the "
|
|
|
|
|
"interpolating modes: linear | bilinear | bicubic | trilinear");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-22 05:16:21 +00:00
|
|
|
TEST_F(FunctionalTest, Pad) {
|
|
|
|
|
{
|
|
|
|
|
auto input = torch::arange(6, torch::kDouble).reshape({1, 2, 3});
|
Pass F::*FuncOptions instead of torch::nn::*Options to functionals, and make F::*FuncOptions a different class when necessary (#29364)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/29364
Currently, we use `torch::nn::*Options` both as module options and functional options. However, this makes it very hard to manage the parameters in `torch::nn::*Options`, because a module's constructor can take a different set of arguments than the module's equivalent functional (e.g. `torch.nn.BatchNorm1d` takes `num_features, eps=1e-5, momentum=0.1, affine=True,
track_running_stats=True`, while `F::batch_norm` takes `running_mean, running_var, weight=None, bias=None, training=False, momentum=0.1, eps=1e-5`).
This PR resolves the above problem by making `F::*FuncOptions` a different class from `torch::nn::*Options` when necessary (i.e. when a module's constructor takes a different set of arguments than the module's equivalent functional). In the rest of the cases where the module constructor takes the same set of arguments as the module's equivalent functional, `F::*FuncOptions` is an alias of `torch::nn::*Options`.
Also as part of this PR, we change all functional options to pass-by-value, to make the semantics consistent across all functionals.
Test Plan: Imported from OSS
Differential Revision: D18376977
Pulled By: yf225
fbshipit-source-id: 8d9c240d93bfd5af0165b6884fdc912476b1d06b
2019-11-09 06:36:49 +00:00
|
|
|
auto output = F::pad(input, F::PadFuncOptions({1, 2}).mode(torch::kCircular));
|
2019-10-22 05:16:21 +00:00
|
|
|
auto expected = torch::tensor({{{2., 0., 1., 2., 0., 1.},
|
|
|
|
|
{5., 3., 4., 5., 3., 4.}}}, torch::kDouble);
|
|
|
|
|
ASSERT_EQ(output.sizes(), std::vector<int64_t>({1, 2, 6}));
|
|
|
|
|
ASSERT_TRUE(output.allclose(expected, 1e-04));
|
|
|
|
|
}
|
|
|
|
|
{
|
|
|
|
|
auto input = torch::arange(9, torch::kDouble).reshape({1, 1, 3, 3});
|
Pass F::*FuncOptions instead of torch::nn::*Options to functionals, and make F::*FuncOptions a different class when necessary (#29364)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/29364
Currently, we use `torch::nn::*Options` both as module options and functional options. However, this makes it very hard to manage the parameters in `torch::nn::*Options`, because a module's constructor can take a different set of arguments than the module's equivalent functional (e.g. `torch.nn.BatchNorm1d` takes `num_features, eps=1e-5, momentum=0.1, affine=True,
track_running_stats=True`, while `F::batch_norm` takes `running_mean, running_var, weight=None, bias=None, training=False, momentum=0.1, eps=1e-5`).
This PR resolves the above problem by making `F::*FuncOptions` a different class from `torch::nn::*Options` when necessary (i.e. when a module's constructor takes a different set of arguments than the module's equivalent functional). In the rest of the cases where the module constructor takes the same set of arguments as the module's equivalent functional, `F::*FuncOptions` is an alias of `torch::nn::*Options`.
Also as part of this PR, we change all functional options to pass-by-value, to make the semantics consistent across all functionals.
Test Plan: Imported from OSS
Differential Revision: D18376977
Pulled By: yf225
fbshipit-source-id: 8d9c240d93bfd5af0165b6884fdc912476b1d06b
2019-11-09 06:36:49 +00:00
|
|
|
auto output = F::pad(input, F::PadFuncOptions({3, 3, 3, 1}).mode(torch::kCircular));
|
2019-10-22 05:16:21 +00:00
|
|
|
auto expected = torch::tensor(
|
|
|
|
|
{{{{0., 1., 2., 0., 1., 2., 0., 1., 2.},
|
|
|
|
|
{3., 4., 5., 3., 4., 5., 3., 4., 5.},
|
|
|
|
|
{6., 7., 8., 6., 7., 8., 6., 7., 8.},
|
|
|
|
|
{0., 1., 2., 0., 1., 2., 0., 1., 2.},
|
|
|
|
|
{3., 4., 5., 3., 4., 5., 3., 4., 5.},
|
|
|
|
|
{6., 7., 8., 6., 7., 8., 6., 7., 8.},
|
|
|
|
|
{0., 1., 2., 0., 1., 2., 0., 1., 2.}}}}, torch::kDouble);
|
|
|
|
|
ASSERT_EQ(output.sizes(), std::vector<int64_t>({1, 1, 7, 9}));
|
|
|
|
|
ASSERT_TRUE(output.allclose(expected, 1e-04));
|
|
|
|
|
}
|
|
|
|
|
{
|
|
|
|
|
auto input = torch::arange(12, torch::kDouble).reshape({1, 1, 2, 2, 3});
|
Pass F::*FuncOptions instead of torch::nn::*Options to functionals, and make F::*FuncOptions a different class when necessary (#29364)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/29364
Currently, we use `torch::nn::*Options` both as module options and functional options. However, this makes it very hard to manage the parameters in `torch::nn::*Options`, because a module's constructor can take a different set of arguments than the module's equivalent functional (e.g. `torch.nn.BatchNorm1d` takes `num_features, eps=1e-5, momentum=0.1, affine=True,
track_running_stats=True`, while `F::batch_norm` takes `running_mean, running_var, weight=None, bias=None, training=False, momentum=0.1, eps=1e-5`).
This PR resolves the above problem by making `F::*FuncOptions` a different class from `torch::nn::*Options` when necessary (i.e. when a module's constructor takes a different set of arguments than the module's equivalent functional). In the rest of the cases where the module constructor takes the same set of arguments as the module's equivalent functional, `F::*FuncOptions` is an alias of `torch::nn::*Options`.
Also as part of this PR, we change all functional options to pass-by-value, to make the semantics consistent across all functionals.
Test Plan: Imported from OSS
Differential Revision: D18376977
Pulled By: yf225
fbshipit-source-id: 8d9c240d93bfd5af0165b6884fdc912476b1d06b
2019-11-09 06:36:49 +00:00
|
|
|
auto output = F::pad(input, F::PadFuncOptions({3, 3, 2, 1, 2, 2}).mode(torch::kCircular));
|
2019-10-22 05:16:21 +00:00
|
|
|
auto expected = torch::tensor(
|
|
|
|
|
{{{{{ 0., 1., 2., 0., 1., 2., 0., 1., 2.},
|
|
|
|
|
{ 3., 4., 5., 3., 4., 5., 3., 4., 5.},
|
|
|
|
|
{ 0., 1., 2., 0., 1., 2., 0., 1., 2.},
|
|
|
|
|
{ 3., 4., 5., 3., 4., 5., 3., 4., 5.},
|
|
|
|
|
{ 0., 1., 2., 0., 1., 2., 0., 1., 2.}},
|
|
|
|
|
|
|
|
|
|
{{ 6., 7., 8., 6., 7., 8., 6., 7., 8.},
|
|
|
|
|
{ 9., 10., 11., 9., 10., 11., 9., 10., 11.},
|
|
|
|
|
{ 6., 7., 8., 6., 7., 8., 6., 7., 8.},
|
|
|
|
|
{ 9., 10., 11., 9., 10., 11., 9., 10., 11.},
|
|
|
|
|
{ 6., 7., 8., 6., 7., 8., 6., 7., 8.}},
|
|
|
|
|
|
|
|
|
|
{{ 0., 1., 2., 0., 1., 2., 0., 1., 2.},
|
|
|
|
|
{ 3., 4., 5., 3., 4., 5., 3., 4., 5.},
|
|
|
|
|
{ 0., 1., 2., 0., 1., 2., 0., 1., 2.},
|
|
|
|
|
{ 3., 4., 5., 3., 4., 5., 3., 4., 5.},
|
|
|
|
|
{ 0., 1., 2., 0., 1., 2., 0., 1., 2.}},
|
|
|
|
|
|
|
|
|
|
{{ 6., 7., 8., 6., 7., 8., 6., 7., 8.},
|
|
|
|
|
{ 9., 10., 11., 9., 10., 11., 9., 10., 11.},
|
|
|
|
|
{ 6., 7., 8., 6., 7., 8., 6., 7., 8.},
|
|
|
|
|
{ 9., 10., 11., 9., 10., 11., 9., 10., 11.},
|
|
|
|
|
{ 6., 7., 8., 6., 7., 8., 6., 7., 8.}},
|
|
|
|
|
|
|
|
|
|
{{ 0., 1., 2., 0., 1., 2., 0., 1., 2.},
|
|
|
|
|
{ 3., 4., 5., 3., 4., 5., 3., 4., 5.},
|
|
|
|
|
{ 0., 1., 2., 0., 1., 2., 0., 1., 2.},
|
|
|
|
|
{ 3., 4., 5., 3., 4., 5., 3., 4., 5.},
|
|
|
|
|
{ 0., 1., 2., 0., 1., 2., 0., 1., 2.}},
|
|
|
|
|
|
|
|
|
|
{{ 6., 7., 8., 6., 7., 8., 6., 7., 8.},
|
|
|
|
|
{ 9., 10., 11., 9., 10., 11., 9., 10., 11.},
|
|
|
|
|
{ 6., 7., 8., 6., 7., 8., 6., 7., 8.},
|
|
|
|
|
{ 9., 10., 11., 9., 10., 11., 9., 10., 11.},
|
|
|
|
|
{ 6., 7., 8., 6., 7., 8., 6., 7., 8.}}}}}, torch::kDouble);
|
|
|
|
|
ASSERT_EQ(output.sizes(), std::vector<int64_t>({1, 1, 6, 5, 9}));
|
|
|
|
|
ASSERT_TRUE(output.allclose(expected, 1e-04));
|
|
|
|
|
}
|
|
|
|
|
{
|
|
|
|
|
auto input = torch::arange(16, torch::kDouble).reshape({2, 2, 2, 2});
|
Pass F::*FuncOptions instead of torch::nn::*Options to functionals, and make F::*FuncOptions a different class when necessary (#29364)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/29364
Currently, we use `torch::nn::*Options` both as module options and functional options. However, this makes it very hard to manage the parameters in `torch::nn::*Options`, because a module's constructor can take a different set of arguments than the module's equivalent functional (e.g. `torch.nn.BatchNorm1d` takes `num_features, eps=1e-5, momentum=0.1, affine=True,
track_running_stats=True`, while `F::batch_norm` takes `running_mean, running_var, weight=None, bias=None, training=False, momentum=0.1, eps=1e-5`).
This PR resolves the above problem by making `F::*FuncOptions` a different class from `torch::nn::*Options` when necessary (i.e. when a module's constructor takes a different set of arguments than the module's equivalent functional). In the rest of the cases where the module constructor takes the same set of arguments as the module's equivalent functional, `F::*FuncOptions` is an alias of `torch::nn::*Options`.
Also as part of this PR, we change all functional options to pass-by-value, to make the semantics consistent across all functionals.
Test Plan: Imported from OSS
Differential Revision: D18376977
Pulled By: yf225
fbshipit-source-id: 8d9c240d93bfd5af0165b6884fdc912476b1d06b
2019-11-09 06:36:49 +00:00
|
|
|
auto output = F::pad(input, F::PadFuncOptions({1, 1, 1, 1}).mode(torch::kReflect));
|
2019-10-22 05:16:21 +00:00
|
|
|
auto expected = torch::tensor(
|
|
|
|
|
{{{{ 3., 2., 3., 2.},
|
|
|
|
|
{ 1., 0., 1., 0.},
|
|
|
|
|
{ 3., 2., 3., 2.},
|
|
|
|
|
{ 1., 0., 1., 0.}},
|
|
|
|
|
|
|
|
|
|
{{ 7., 6., 7., 6.},
|
|
|
|
|
{ 5., 4., 5., 4.},
|
|
|
|
|
{ 7., 6., 7., 6.},
|
|
|
|
|
{ 5., 4., 5., 4.}}},
|
|
|
|
|
|
|
|
|
|
{{{11., 10., 11., 10.},
|
|
|
|
|
{ 9., 8., 9., 8.},
|
|
|
|
|
{11., 10., 11., 10.},
|
|
|
|
|
{ 9., 8., 9., 8.}},
|
|
|
|
|
|
|
|
|
|
{{15., 14., 15., 14.},
|
|
|
|
|
{13., 12., 13., 12.},
|
|
|
|
|
{15., 14., 15., 14.},
|
|
|
|
|
{13., 12., 13., 12.}}}}, torch::kDouble);
|
|
|
|
|
ASSERT_EQ(output.sizes(), std::vector<int64_t>({2, 2, 4, 4}));
|
|
|
|
|
ASSERT_TRUE(output.allclose(expected, 1e-04));
|
|
|
|
|
}
|
|
|
|
|
{
|
|
|
|
|
auto input = torch::arange(12, torch::kDouble).reshape({1, 1, 2, 2, 3});
|
Pass F::*FuncOptions instead of torch::nn::*Options to functionals, and make F::*FuncOptions a different class when necessary (#29364)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/29364
Currently, we use `torch::nn::*Options` both as module options and functional options. However, this makes it very hard to manage the parameters in `torch::nn::*Options`, because a module's constructor can take a different set of arguments than the module's equivalent functional (e.g. `torch.nn.BatchNorm1d` takes `num_features, eps=1e-5, momentum=0.1, affine=True,
track_running_stats=True`, while `F::batch_norm` takes `running_mean, running_var, weight=None, bias=None, training=False, momentum=0.1, eps=1e-5`).
This PR resolves the above problem by making `F::*FuncOptions` a different class from `torch::nn::*Options` when necessary (i.e. when a module's constructor takes a different set of arguments than the module's equivalent functional). In the rest of the cases where the module constructor takes the same set of arguments as the module's equivalent functional, `F::*FuncOptions` is an alias of `torch::nn::*Options`.
Also as part of this PR, we change all functional options to pass-by-value, to make the semantics consistent across all functionals.
Test Plan: Imported from OSS
Differential Revision: D18376977
Pulled By: yf225
fbshipit-source-id: 8d9c240d93bfd5af0165b6884fdc912476b1d06b
2019-11-09 06:36:49 +00:00
|
|
|
auto output = F::pad(input, F::PadFuncOptions({1, 2, 2, 1, 1, 2}).mode(torch::kReplicate));
|
2019-10-22 05:16:21 +00:00
|
|
|
auto expected = torch::tensor(
|
|
|
|
|
{{{{{ 0., 0., 1., 2., 2., 2.},
|
|
|
|
|
{ 0., 0., 1., 2., 2., 2.},
|
|
|
|
|
{ 0., 0., 1., 2., 2., 2.},
|
|
|
|
|
{ 3., 3., 4., 5., 5., 5.},
|
|
|
|
|
{ 3., 3., 4., 5., 5., 5.}},
|
|
|
|
|
|
|
|
|
|
{{ 0., 0., 1., 2., 2., 2.},
|
|
|
|
|
{ 0., 0., 1., 2., 2., 2.},
|
|
|
|
|
{ 0., 0., 1., 2., 2., 2.},
|
|
|
|
|
{ 3., 3., 4., 5., 5., 5.},
|
|
|
|
|
{ 3., 3., 4., 5., 5., 5.}},
|
|
|
|
|
|
|
|
|
|
{{ 6., 6., 7., 8., 8., 8.},
|
|
|
|
|
{ 6., 6., 7., 8., 8., 8.},
|
|
|
|
|
{ 6., 6., 7., 8., 8., 8.},
|
|
|
|
|
{ 9., 9., 10., 11., 11., 11.},
|
|
|
|
|
{ 9., 9., 10., 11., 11., 11.}},
|
|
|
|
|
|
|
|
|
|
{{ 6., 6., 7., 8., 8., 8.},
|
|
|
|
|
{ 6., 6., 7., 8., 8., 8.},
|
|
|
|
|
{ 6., 6., 7., 8., 8., 8.},
|
|
|
|
|
{ 9., 9., 10., 11., 11., 11.},
|
|
|
|
|
{ 9., 9., 10., 11., 11., 11.}},
|
|
|
|
|
|
|
|
|
|
{{ 6., 6., 7., 8., 8., 8.},
|
|
|
|
|
{ 6., 6., 7., 8., 8., 8.},
|
|
|
|
|
{ 6., 6., 7., 8., 8., 8.},
|
|
|
|
|
{ 9., 9., 10., 11., 11., 11.},
|
|
|
|
|
{ 9., 9., 10., 11., 11., 11.}}}}}, torch::kDouble);
|
|
|
|
|
ASSERT_EQ(output.sizes(), std::vector<int64_t>({1, 1, 5, 5, 6}));
|
|
|
|
|
ASSERT_TRUE(output.allclose(expected, 1e-04));
|
|
|
|
|
}
|
|
|
|
|
{
|
|
|
|
|
auto input = torch::ones({1, 1, 1, 1}, torch::kDouble);
|
Pass F::*FuncOptions instead of torch::nn::*Options to functionals, and make F::*FuncOptions a different class when necessary (#29364)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/29364
Currently, we use `torch::nn::*Options` both as module options and functional options. However, this makes it very hard to manage the parameters in `torch::nn::*Options`, because a module's constructor can take a different set of arguments than the module's equivalent functional (e.g. `torch.nn.BatchNorm1d` takes `num_features, eps=1e-5, momentum=0.1, affine=True,
track_running_stats=True`, while `F::batch_norm` takes `running_mean, running_var, weight=None, bias=None, training=False, momentum=0.1, eps=1e-5`).
This PR resolves the above problem by making `F::*FuncOptions` a different class from `torch::nn::*Options` when necessary (i.e. when a module's constructor takes a different set of arguments than the module's equivalent functional). In the rest of the cases where the module constructor takes the same set of arguments as the module's equivalent functional, `F::*FuncOptions` is an alias of `torch::nn::*Options`.
Also as part of this PR, we change all functional options to pass-by-value, to make the semantics consistent across all functionals.
Test Plan: Imported from OSS
Differential Revision: D18376977
Pulled By: yf225
fbshipit-source-id: 8d9c240d93bfd5af0165b6884fdc912476b1d06b
2019-11-09 06:36:49 +00:00
|
|
|
auto output = F::pad(input, F::PadFuncOptions({1, 1}).mode(torch::kConstant).value(0));
|
2019-10-22 05:16:21 +00:00
|
|
|
ASSERT_EQ(output.sizes(), std::vector<int64_t>({1, 1, 1, 3}));
|
|
|
|
|
auto expected = torch::tensor({{{{0., 1., 0.}}}}, torch::kDouble);
|
|
|
|
|
}
|
|
|
|
|
{
|
|
|
|
|
auto input = torch::ones({1, 1, 1, 1}, torch::kDouble);
|
Pass F::*FuncOptions instead of torch::nn::*Options to functionals, and make F::*FuncOptions a different class when necessary (#29364)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/29364
Currently, we use `torch::nn::*Options` both as module options and functional options. However, this makes it very hard to manage the parameters in `torch::nn::*Options`, because a module's constructor can take a different set of arguments than the module's equivalent functional (e.g. `torch.nn.BatchNorm1d` takes `num_features, eps=1e-5, momentum=0.1, affine=True,
track_running_stats=True`, while `F::batch_norm` takes `running_mean, running_var, weight=None, bias=None, training=False, momentum=0.1, eps=1e-5`).
This PR resolves the above problem by making `F::*FuncOptions` a different class from `torch::nn::*Options` when necessary (i.e. when a module's constructor takes a different set of arguments than the module's equivalent functional). In the rest of the cases where the module constructor takes the same set of arguments as the module's equivalent functional, `F::*FuncOptions` is an alias of `torch::nn::*Options`.
Also as part of this PR, we change all functional options to pass-by-value, to make the semantics consistent across all functionals.
Test Plan: Imported from OSS
Differential Revision: D18376977
Pulled By: yf225
fbshipit-source-id: 8d9c240d93bfd5af0165b6884fdc912476b1d06b
2019-11-09 06:36:49 +00:00
|
|
|
auto output = F::pad(input, F::PadFuncOptions({1, 1}));
|
2019-10-22 05:16:21 +00:00
|
|
|
ASSERT_EQ(output.sizes(), std::vector<int64_t>({1, 1, 1, 3}));
|
|
|
|
|
auto expected = torch::tensor({{{{0., 1., 0.}}}}, torch::kDouble);
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-10-30 21:33:22 +00:00
|
|
|
|
|
|
|
|
TEST_F(FunctionalTest, CTCLoss) {
|
|
|
|
|
{ // test CTCLoss typechecks
|
|
|
|
|
const auto target_lengths = torch::tensor({30, 25, 20});
|
|
|
|
|
const auto input_lengths = torch::tensor({50, 50, 50});
|
|
|
|
|
const auto targets =
|
|
|
|
|
torch::randint(1, 15, {target_lengths.sum().item<int>()}, torch::kInt);
|
|
|
|
|
const auto log_probs = torch::randn({50, 3, 15}, torch::kFloat).log_softmax(2);
|
|
|
|
|
|
|
|
|
|
const auto _input_lengths = input_lengths.to(torch::kFloat);
|
|
|
|
|
ASSERT_THROWS_WITH(
|
|
|
|
|
F::ctc_loss(
|
|
|
|
|
log_probs, targets, _input_lengths, target_lengths),
|
|
|
|
|
"input_lengths must be integral");
|
|
|
|
|
|
|
|
|
|
const auto target_lengths_ = target_lengths.to(torch::kFloat);
|
|
|
|
|
ASSERT_THROWS_WITH(
|
|
|
|
|
F::ctc_loss(
|
|
|
|
|
log_probs, targets, input_lengths, target_lengths_),
|
|
|
|
|
"target_lengths must be integral");
|
|
|
|
|
}
|
|
|
|
|
{ // test CTCLoss length checks
|
|
|
|
|
const auto target_lengths = torch::tensor({30, 25, 20});
|
|
|
|
|
const auto input_lengths = torch::tensor({50, 50, 50});
|
|
|
|
|
const auto targets = torch::randint(1, 15, {3, 29}, torch::kInt);
|
|
|
|
|
const auto log_probs = torch::randn({50, 3, 15}, torch::kFloat)
|
|
|
|
|
.log_softmax(2);
|
|
|
|
|
ASSERT_THROWS_WITH(
|
|
|
|
|
F::ctc_loss(
|
|
|
|
|
log_probs, targets, input_lengths, target_lengths),
|
|
|
|
|
"Expected tensor to have size at least 30 at dimension 1");
|
|
|
|
|
}
|
|
|
|
|
{ // test CTCLoss empty target
|
|
|
|
|
{
|
|
|
|
|
const auto target_lengths = torch::tensor({0, 0, 0});
|
|
|
|
|
const auto input_lengths = torch::tensor({50, 50, 50});
|
|
|
|
|
const auto targets =
|
|
|
|
|
torch::randint(1, 15, at::IntArrayRef({0}), torch::kLong);
|
|
|
|
|
const auto log_probs =
|
|
|
|
|
torch::randn({50, 3, 15}, torch::kDouble).log_softmax(2);
|
|
|
|
|
const auto loss = F::ctc_loss(
|
|
|
|
|
log_probs, targets, input_lengths, target_lengths,
|
Pass F::*FuncOptions instead of torch::nn::*Options to functionals, and make F::*FuncOptions a different class when necessary (#29364)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/29364
Currently, we use `torch::nn::*Options` both as module options and functional options. However, this makes it very hard to manage the parameters in `torch::nn::*Options`, because a module's constructor can take a different set of arguments than the module's equivalent functional (e.g. `torch.nn.BatchNorm1d` takes `num_features, eps=1e-5, momentum=0.1, affine=True,
track_running_stats=True`, while `F::batch_norm` takes `running_mean, running_var, weight=None, bias=None, training=False, momentum=0.1, eps=1e-5`).
This PR resolves the above problem by making `F::*FuncOptions` a different class from `torch::nn::*Options` when necessary (i.e. when a module's constructor takes a different set of arguments than the module's equivalent functional). In the rest of the cases where the module constructor takes the same set of arguments as the module's equivalent functional, `F::*FuncOptions` is an alias of `torch::nn::*Options`.
Also as part of this PR, we change all functional options to pass-by-value, to make the semantics consistent across all functionals.
Test Plan: Imported from OSS
Differential Revision: D18376977
Pulled By: yf225
fbshipit-source-id: 8d9c240d93bfd5af0165b6884fdc912476b1d06b
2019-11-09 06:36:49 +00:00
|
|
|
F::CTCLossFuncOptions().reduction(torch::kNone));
|
2019-10-30 21:33:22 +00:00
|
|
|
ASSERT_TRUE(loss.ge(0).all().item<bool>());
|
|
|
|
|
ASSERT_TRUE(torch::allclose(
|
|
|
|
|
-log_probs.sum(0).slice(1, 0, 1).view_as(loss), loss));
|
|
|
|
|
}
|
|
|
|
|
{
|
|
|
|
|
const auto target_lengths = torch::tensor({0, 9, 0});
|
|
|
|
|
const auto input_lengths = torch::tensor({50, 50, 50});
|
|
|
|
|
const auto targets = torch::randint(1, 15, {9}, torch::kLong);
|
|
|
|
|
const auto log_probs =
|
|
|
|
|
torch::randn({50, 3, 15}, torch::kDouble).log_softmax(2);
|
|
|
|
|
const auto loss = F::ctc_loss(
|
|
|
|
|
log_probs, targets, input_lengths, target_lengths,
|
Pass F::*FuncOptions instead of torch::nn::*Options to functionals, and make F::*FuncOptions a different class when necessary (#29364)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/29364
Currently, we use `torch::nn::*Options` both as module options and functional options. However, this makes it very hard to manage the parameters in `torch::nn::*Options`, because a module's constructor can take a different set of arguments than the module's equivalent functional (e.g. `torch.nn.BatchNorm1d` takes `num_features, eps=1e-5, momentum=0.1, affine=True,
track_running_stats=True`, while `F::batch_norm` takes `running_mean, running_var, weight=None, bias=None, training=False, momentum=0.1, eps=1e-5`).
This PR resolves the above problem by making `F::*FuncOptions` a different class from `torch::nn::*Options` when necessary (i.e. when a module's constructor takes a different set of arguments than the module's equivalent functional). In the rest of the cases where the module constructor takes the same set of arguments as the module's equivalent functional, `F::*FuncOptions` is an alias of `torch::nn::*Options`.
Also as part of this PR, we change all functional options to pass-by-value, to make the semantics consistent across all functionals.
Test Plan: Imported from OSS
Differential Revision: D18376977
Pulled By: yf225
fbshipit-source-id: 8d9c240d93bfd5af0165b6884fdc912476b1d06b
2019-11-09 06:36:49 +00:00
|
|
|
F::CTCLossFuncOptions().reduction(torch::kNone));
|
2019-10-30 21:33:22 +00:00
|
|
|
ASSERT_TRUE(loss.ge(0).all().item<bool>());
|
|
|
|
|
ASSERT_TRUE(torch::allclose(
|
|
|
|
|
-log_probs.sum(0)
|
|
|
|
|
.index_select(0, torch::tensor({0, 2}, torch::kLong))
|
|
|
|
|
.slice(1, 0, 1).view({2}),
|
|
|
|
|
loss.index_select(0, torch::tensor({0, 2}, torch::kLong))
|
|
|
|
|
));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-11-01 19:33:42 +00:00
|
|
|
|
|
|
|
|
TEST_F(FunctionalTest, PoissonNLLLoss) {
|
|
|
|
|
const auto input = torch::tensor({0.5, 1.5, 2.5});
|
|
|
|
|
const auto target = torch::tensor({1., 2., 3.});
|
|
|
|
|
const auto component_wise_loss = torch::exp(input) - target * input;
|
|
|
|
|
ASSERT_TRUE(torch::allclose(torch::mean(component_wise_loss),
|
|
|
|
|
F::poisson_nll_loss(input, target)));
|
|
|
|
|
ASSERT_TRUE(torch::allclose(component_wise_loss,
|
|
|
|
|
F::poisson_nll_loss(input, target,
|
Pass F::*FuncOptions instead of torch::nn::*Options to functionals, and make F::*FuncOptions a different class when necessary (#29364)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/29364
Currently, we use `torch::nn::*Options` both as module options and functional options. However, this makes it very hard to manage the parameters in `torch::nn::*Options`, because a module's constructor can take a different set of arguments than the module's equivalent functional (e.g. `torch.nn.BatchNorm1d` takes `num_features, eps=1e-5, momentum=0.1, affine=True,
track_running_stats=True`, while `F::batch_norm` takes `running_mean, running_var, weight=None, bias=None, training=False, momentum=0.1, eps=1e-5`).
This PR resolves the above problem by making `F::*FuncOptions` a different class from `torch::nn::*Options` when necessary (i.e. when a module's constructor takes a different set of arguments than the module's equivalent functional). In the rest of the cases where the module constructor takes the same set of arguments as the module's equivalent functional, `F::*FuncOptions` is an alias of `torch::nn::*Options`.
Also as part of this PR, we change all functional options to pass-by-value, to make the semantics consistent across all functionals.
Test Plan: Imported from OSS
Differential Revision: D18376977
Pulled By: yf225
fbshipit-source-id: 8d9c240d93bfd5af0165b6884fdc912476b1d06b
2019-11-09 06:36:49 +00:00
|
|
|
F::PoissonNLLLossFuncOptions().reduction(torch::kNone))));
|
2019-11-01 19:33:42 +00:00
|
|
|
ASSERT_TRUE(torch::allclose(torch::sum(component_wise_loss),
|
|
|
|
|
F::poisson_nll_loss(input, target,
|
Pass F::*FuncOptions instead of torch::nn::*Options to functionals, and make F::*FuncOptions a different class when necessary (#29364)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/29364
Currently, we use `torch::nn::*Options` both as module options and functional options. However, this makes it very hard to manage the parameters in `torch::nn::*Options`, because a module's constructor can take a different set of arguments than the module's equivalent functional (e.g. `torch.nn.BatchNorm1d` takes `num_features, eps=1e-5, momentum=0.1, affine=True,
track_running_stats=True`, while `F::batch_norm` takes `running_mean, running_var, weight=None, bias=None, training=False, momentum=0.1, eps=1e-5`).
This PR resolves the above problem by making `F::*FuncOptions` a different class from `torch::nn::*Options` when necessary (i.e. when a module's constructor takes a different set of arguments than the module's equivalent functional). In the rest of the cases where the module constructor takes the same set of arguments as the module's equivalent functional, `F::*FuncOptions` is an alias of `torch::nn::*Options`.
Also as part of this PR, we change all functional options to pass-by-value, to make the semantics consistent across all functionals.
Test Plan: Imported from OSS
Differential Revision: D18376977
Pulled By: yf225
fbshipit-source-id: 8d9c240d93bfd5af0165b6884fdc912476b1d06b
2019-11-09 06:36:49 +00:00
|
|
|
F::PoissonNLLLossFuncOptions().reduction(torch::kSum))));
|
2019-11-01 19:33:42 +00:00
|
|
|
ASSERT_TRUE(torch::allclose(torch::mean(component_wise_loss),
|
|
|
|
|
F::poisson_nll_loss(input, target,
|
Pass F::*FuncOptions instead of torch::nn::*Options to functionals, and make F::*FuncOptions a different class when necessary (#29364)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/29364
Currently, we use `torch::nn::*Options` both as module options and functional options. However, this makes it very hard to manage the parameters in `torch::nn::*Options`, because a module's constructor can take a different set of arguments than the module's equivalent functional (e.g. `torch.nn.BatchNorm1d` takes `num_features, eps=1e-5, momentum=0.1, affine=True,
track_running_stats=True`, while `F::batch_norm` takes `running_mean, running_var, weight=None, bias=None, training=False, momentum=0.1, eps=1e-5`).
This PR resolves the above problem by making `F::*FuncOptions` a different class from `torch::nn::*Options` when necessary (i.e. when a module's constructor takes a different set of arguments than the module's equivalent functional). In the rest of the cases where the module constructor takes the same set of arguments as the module's equivalent functional, `F::*FuncOptions` is an alias of `torch::nn::*Options`.
Also as part of this PR, we change all functional options to pass-by-value, to make the semantics consistent across all functionals.
Test Plan: Imported from OSS
Differential Revision: D18376977
Pulled By: yf225
fbshipit-source-id: 8d9c240d93bfd5af0165b6884fdc912476b1d06b
2019-11-09 06:36:49 +00:00
|
|
|
F::PoissonNLLLossFuncOptions().reduction(torch::kMean))));
|
2019-11-01 19:33:42 +00:00
|
|
|
}
|
2019-11-05 13:26:26 +00:00
|
|
|
|
|
|
|
|
TEST_F(FunctionalTest, MarginRankingLoss) {
|
|
|
|
|
{
|
|
|
|
|
const auto input1 = torch::randn(15) * 10;
|
|
|
|
|
const auto input2 = torch::randn(15) * 10;
|
|
|
|
|
const auto target = torch::randn(15).sign();
|
|
|
|
|
ASSERT_TRUE(torch::allclose(
|
|
|
|
|
F::margin_ranking_loss(input1, input2, target),
|
|
|
|
|
(-target * (input1 - input2)).clamp(0).mean()
|
|
|
|
|
));
|
|
|
|
|
}
|
|
|
|
|
{
|
|
|
|
|
const auto input1 = torch::randn(15) * 10;
|
|
|
|
|
const auto input2 = torch::randn(15) * 10;
|
|
|
|
|
const auto target = torch::randn(15).sign();
|
|
|
|
|
const auto margin = 0.5;
|
|
|
|
|
ASSERT_TRUE(torch::allclose(
|
|
|
|
|
F::margin_ranking_loss(input1, input2, target,
|
Pass F::*FuncOptions instead of torch::nn::*Options to functionals, and make F::*FuncOptions a different class when necessary (#29364)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/29364
Currently, we use `torch::nn::*Options` both as module options and functional options. However, this makes it very hard to manage the parameters in `torch::nn::*Options`, because a module's constructor can take a different set of arguments than the module's equivalent functional (e.g. `torch.nn.BatchNorm1d` takes `num_features, eps=1e-5, momentum=0.1, affine=True,
track_running_stats=True`, while `F::batch_norm` takes `running_mean, running_var, weight=None, bias=None, training=False, momentum=0.1, eps=1e-5`).
This PR resolves the above problem by making `F::*FuncOptions` a different class from `torch::nn::*Options` when necessary (i.e. when a module's constructor takes a different set of arguments than the module's equivalent functional). In the rest of the cases where the module constructor takes the same set of arguments as the module's equivalent functional, `F::*FuncOptions` is an alias of `torch::nn::*Options`.
Also as part of this PR, we change all functional options to pass-by-value, to make the semantics consistent across all functionals.
Test Plan: Imported from OSS
Differential Revision: D18376977
Pulled By: yf225
fbshipit-source-id: 8d9c240d93bfd5af0165b6884fdc912476b1d06b
2019-11-09 06:36:49 +00:00
|
|
|
F::MarginRankingLossFuncOptions().margin(0.5).reduction(torch::kSum)
|
2019-11-05 13:26:26 +00:00
|
|
|
),
|
|
|
|
|
(-target * (input1 - input2) + margin).clamp(0).sum()
|
|
|
|
|
));
|
|
|
|
|
}
|
|
|
|
|
{
|
|
|
|
|
const auto input1 = torch::randn(15) * 10;
|
|
|
|
|
const auto input2 = torch::randn(15) * 10;
|
|
|
|
|
const auto target = torch::randn(15).sign();
|
|
|
|
|
const auto margin = 0.5;
|
|
|
|
|
ASSERT_TRUE(torch::allclose(
|
|
|
|
|
F::margin_ranking_loss(input1, input2, target,
|
Pass F::*FuncOptions instead of torch::nn::*Options to functionals, and make F::*FuncOptions a different class when necessary (#29364)
Summary:
Pull Request resolved: https://github.com/pytorch/pytorch/pull/29364
Currently, we use `torch::nn::*Options` both as module options and functional options. However, this makes it very hard to manage the parameters in `torch::nn::*Options`, because a module's constructor can take a different set of arguments than the module's equivalent functional (e.g. `torch.nn.BatchNorm1d` takes `num_features, eps=1e-5, momentum=0.1, affine=True,
track_running_stats=True`, while `F::batch_norm` takes `running_mean, running_var, weight=None, bias=None, training=False, momentum=0.1, eps=1e-5`).
This PR resolves the above problem by making `F::*FuncOptions` a different class from `torch::nn::*Options` when necessary (i.e. when a module's constructor takes a different set of arguments than the module's equivalent functional). In the rest of the cases where the module constructor takes the same set of arguments as the module's equivalent functional, `F::*FuncOptions` is an alias of `torch::nn::*Options`.
Also as part of this PR, we change all functional options to pass-by-value, to make the semantics consistent across all functionals.
Test Plan: Imported from OSS
Differential Revision: D18376977
Pulled By: yf225
fbshipit-source-id: 8d9c240d93bfd5af0165b6884fdc912476b1d06b
2019-11-09 06:36:49 +00:00
|
|
|
F::MarginRankingLossFuncOptions().margin(0.5).reduction(torch::kMean)
|
2019-11-05 13:26:26 +00:00
|
|
|
),
|
|
|
|
|
(-target * (input1 - input2) + margin).clamp(0).mean()
|
|
|
|
|
));
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-11-16 04:28:58 +00:00
|
|
|
|
2019-11-20 00:02:29 +00:00
|
|
|
TEST_F(FunctionalTest, ConvTranspose1d) {
|
|
|
|
|
auto x = torch::arange(20.).view({2, 2, 5});
|
|
|
|
|
auto weight = torch::arange(18.).view({2, 3, 3});
|
|
|
|
|
auto y = F::conv_transpose1d(x, weight, F::ConvTranspose1dFuncOptions().stride(1));
|
|
|
|
|
auto expected = torch::tensor({{{ 45., 104., 179., 212., 245., 188., 107.},
|
|
|
|
|
{ 60., 140., 242., 293., 344., 260., 146.},
|
|
|
|
|
{ 75., 176., 305., 374., 443., 332., 185.}},
|
|
|
|
|
{{ 135., 304., 509., 542., 575., 428., 237.},
|
|
|
|
|
{ 210., 460., 752., 803., 854., 620., 336.},
|
|
|
|
|
{ 285., 616., 995., 1064., 1133., 812., 435.}}});
|
|
|
|
|
ASSERT_TRUE(torch::allclose(y, expected));
|
|
|
|
|
|
|
|
|
|
auto y_no_options = F::conv_transpose1d(x, weight);
|
|
|
|
|
ASSERT_TRUE(torch::allclose(y_no_options, expected));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(FunctionalTest, ConvTranspose2dEven) {
|
|
|
|
|
auto x = torch::arange(50.).view({1, 2, 5, 5});
|
|
|
|
|
auto weight = torch::arange(54.).view({2, 3, 3, 3});
|
|
|
|
|
auto y = F::conv_transpose2d(x, weight, F::ConvTranspose2dFuncOptions().stride(1));
|
|
|
|
|
auto expected = torch::tensor({{{{ 675., 1402., 2183., 2270., 2357., 1634., 849.},
|
|
|
|
|
{ 1560., 3240., 5044., 5236., 5428., 3760., 1952.},
|
|
|
|
|
{ 2685., 5574., 8673., 8988., 9303., 6438., 3339.},
|
|
|
|
|
{ 3180., 6594., 10248., 10563., 10878., 7518., 3894.},
|
|
|
|
|
{ 3675., 7614., 11823., 12138., 12453., 8598., 4449.},
|
|
|
|
|
{ 2820., 5832., 9040., 9268., 9496., 6544., 3380.},
|
|
|
|
|
{ 1605., 3314., 5129., 5252., 5375., 3698., 1907.}},
|
|
|
|
|
{{ 900., 1870., 2912., 3053., 3194., 2210., 1146.},
|
|
|
|
|
{ 2100., 4356., 6772., 7072., 7372., 5092., 2636.},
|
|
|
|
|
{ 3630., 7518., 11670., 12147., 12624., 8706., 4500.},
|
|
|
|
|
{ 4395., 9078., 14055., 14532., 15009., 10326., 5325.},
|
|
|
|
|
{ 5160., 10638., 16440., 16917., 17394., 11946., 6150.},
|
|
|
|
|
{ 3900., 8028., 12388., 12724., 13060., 8956., 4604.},
|
|
|
|
|
{ 2190., 4502., 6938., 7115., 7292., 4994., 2564.}},
|
|
|
|
|
{{ 1125., 2338., 3641., 3836., 4031., 2786., 1443.},
|
|
|
|
|
{ 2640., 5472., 8500., 8908., 9316., 6424., 3320.},
|
|
|
|
|
{ 4575., 9462., 14667., 15306., 15945., 10974., 5661.},
|
|
|
|
|
{ 5610., 11562., 17862., 18501., 19140., 13134., 6756.},
|
|
|
|
|
{ 6645., 13662., 21057., 21696., 22335., 15294., 7851.},
|
|
|
|
|
{ 4980., 10224., 15736., 16180., 16624., 11368., 5828.},
|
|
|
|
|
{ 2775., 5690., 8747., 8978., 9209., 6290., 3221.}}}});
|
|
|
|
|
ASSERT_TRUE(torch::allclose(y, expected));
|
|
|
|
|
|
|
|
|
|
auto y_no_options = F::conv_transpose2d(x, weight);
|
|
|
|
|
ASSERT_TRUE(torch::allclose(y_no_options, expected));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(FunctionalTest, ConvTranspose2dUneven) {
|
|
|
|
|
auto x = torch::arange(40.).view({1, 2, 5, 4});
|
|
|
|
|
auto weight = torch::arange(36.).view({2, 3, 3, 2});
|
|
|
|
|
auto y = F::conv_transpose2d(x, weight, F::ConvTranspose2dFuncOptions().stride(1));
|
|
|
|
|
auto expected = torch::tensor({{{{ 360., 758., 796., 834., 440.},
|
|
|
|
|
{ 832., 1752., 1836., 1920., 1012.},
|
|
|
|
|
{1432., 3014., 3152., 3290., 1732.},
|
|
|
|
|
{1696., 3566., 3704., 3842., 2020.},
|
|
|
|
|
{1960., 4118., 4256., 4394., 2308.},
|
|
|
|
|
{1504., 3152., 3252., 3352., 1756.},
|
|
|
|
|
{ 856., 1790., 1844., 1898., 992.}},
|
|
|
|
|
{{ 480., 1010., 1072., 1134., 596.},
|
|
|
|
|
{1120., 2352., 2484., 2616., 1372.},
|
|
|
|
|
{1936., 4058., 4268., 4478., 2344.},
|
|
|
|
|
{2344., 4898., 5108., 5318., 2776.},
|
|
|
|
|
{2752., 5738., 5948., 6158., 3208.},
|
|
|
|
|
{2080., 4328., 4476., 4624., 2404.},
|
|
|
|
|
{1168., 2426., 2504., 2582., 1340.}},
|
|
|
|
|
{{ 600., 1262., 1348., 1434., 752.},
|
|
|
|
|
{1408., 2952., 3132., 3312., 1732.},
|
|
|
|
|
{2440., 5102., 5384., 5666., 2956.},
|
|
|
|
|
{2992., 6230., 6512., 6794., 3532.},
|
|
|
|
|
{3544., 7358., 7640., 7922., 4108.},
|
|
|
|
|
{2656., 5504., 5700., 5896., 3052.},
|
|
|
|
|
{1480., 3062., 3164., 3266., 1688.}}}});
|
|
|
|
|
ASSERT_TRUE(torch::allclose(y, expected));
|
|
|
|
|
|
|
|
|
|
auto y_no_options = F::conv_transpose2d(x, weight);
|
|
|
|
|
ASSERT_TRUE(torch::allclose(y_no_options, expected));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(FunctionalTest, ConvTranspose3d) {
|
|
|
|
|
auto x = torch::arange(16.).view({1, 2, 2, 2, 2});
|
|
|
|
|
auto weight = torch::arange(32.).view({2, 2, 2, 2, 2});
|
|
|
|
|
auto y = F::conv_transpose3d(x, weight, F::ConvTranspose3dFuncOptions().stride(1));
|
|
|
|
|
auto expected = torch::tensor({{{{{ 128., 280., 154.},
|
|
|
|
|
{ 304., 664., 364.},
|
|
|
|
|
{ 184., 400., 218.}},
|
|
|
|
|
{{ 352., 768., 420.},
|
|
|
|
|
{ 832., 1808., 984.},
|
|
|
|
|
{ 496., 1072., 580.}},
|
|
|
|
|
{{ 256., 552., 298.},
|
|
|
|
|
{ 592., 1272., 684.},
|
|
|
|
|
{ 344., 736., 394.}}},
|
|
|
|
|
{{{ 192., 424., 234.},
|
|
|
|
|
{ 464., 1016., 556.},
|
|
|
|
|
{ 280., 608., 330.}},
|
|
|
|
|
{{ 544., 1184., 644.},
|
|
|
|
|
{1280., 2768., 1496.},
|
|
|
|
|
{ 752., 1616., 868.}},
|
|
|
|
|
{{ 384., 824., 442.},
|
|
|
|
|
{ 880., 1880., 1004.},
|
|
|
|
|
{ 504., 1072., 570.}}}}});
|
|
|
|
|
ASSERT_TRUE(torch::allclose(y, expected));
|
|
|
|
|
|
|
|
|
|
auto y_no_options = F::conv_transpose3d(x, weight);
|
|
|
|
|
ASSERT_TRUE(torch::allclose(y_no_options, expected));
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-19 18:02:31 +00:00
|
|
|
TEST_F(FunctionalTest, AlphaDropout) {
|
|
|
|
|
auto input = torch::randn(5000);
|
|
|
|
|
auto input_mean = input.mean();
|
|
|
|
|
auto input_std = input.std();
|
|
|
|
|
|
|
|
|
|
for (const auto rate : {0.2, 0.5, 0.8}) {
|
2020-03-21 16:59:31 +00:00
|
|
|
for (const auto inplace : {false, true}) {
|
|
|
|
|
auto input_ = input.clone();
|
|
|
|
|
auto output = F::alpha_dropout(input_, F::AlphaDropoutFuncOptions().p(rate).training(false).inplace(inplace));
|
|
|
|
|
ASSERT_TRUE(torch::allclose(input_mean, output.mean(), 0.1));
|
|
|
|
|
ASSERT_TRUE(torch::allclose(input_std, output.std(), 0.1));
|
|
|
|
|
if (inplace) {
|
|
|
|
|
ASSERT_TRUE(torch::allclose(input_, output));
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-11-19 18:02:31 +00:00
|
|
|
}
|
|
|
|
|
auto output = F::detail::alpha_dropout(input, 0.5, false, false);
|
|
|
|
|
ASSERT_TRUE(torch::allclose(input_mean, output.mean(), 0.1));
|
|
|
|
|
ASSERT_TRUE(torch::allclose(input_std, output.std(), 0.1));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(FunctionalTest, FeatureAlphaDropout) {
|
|
|
|
|
auto input = torch::randn(5000);
|
|
|
|
|
auto input_mean = input.mean();
|
|
|
|
|
auto input_std = input.std();
|
|
|
|
|
|
|
|
|
|
for (const auto rate : {0.2, 0.5, 0.8}) {
|
2020-03-21 16:59:31 +00:00
|
|
|
for (const auto inplace : {false, true}) {
|
|
|
|
|
auto input_ = input.clone();
|
|
|
|
|
auto output = F::feature_alpha_dropout(input_, F::FeatureAlphaDropoutFuncOptions().p(rate).training(false).inplace(inplace));
|
|
|
|
|
ASSERT_TRUE(torch::allclose(input_mean, output.mean(), 0.1));
|
|
|
|
|
ASSERT_TRUE(torch::allclose(input_std, output.std(), 0.1));
|
|
|
|
|
if (inplace) {
|
|
|
|
|
ASSERT_TRUE(torch::allclose(input_, output));
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-11-19 18:02:31 +00:00
|
|
|
}
|
|
|
|
|
auto output = F::feature_alpha_dropout(input);
|
|
|
|
|
ASSERT_TRUE(torch::allclose(input_mean, output.mean(), 0.1));
|
|
|
|
|
ASSERT_TRUE(torch::allclose(input_std, output.std(), 0.1));
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-16 04:28:58 +00:00
|
|
|
TEST_F(FunctionalTest, Dropout) {
|
|
|
|
|
auto input = torch::randn(5000);
|
|
|
|
|
auto input_mean = input.mean();
|
|
|
|
|
auto input_std = input.std();
|
|
|
|
|
|
|
|
|
|
for (const auto rate : {0.2, 0.5, 0.8}) {
|
|
|
|
|
auto output = F::dropout(input, F::DropoutFuncOptions().p(rate));
|
|
|
|
|
ASSERT_TRUE(torch::allclose(input_mean, output.mean(), 0.01, 0.05));
|
|
|
|
|
ASSERT_TRUE((input_std <= output.std()).all().item<bool>());
|
|
|
|
|
}
|
|
|
|
|
auto output = F::dropout(input);
|
|
|
|
|
ASSERT_TRUE(torch::allclose(input_mean, output.mean(), 0.01, 0.05));
|
|
|
|
|
ASSERT_TRUE((input_std <= output.std()).all().item<bool>());
|
2019-11-20 00:06:25 +00:00
|
|
|
ASSERT_TRUE(F::dropout(torch::tensor(1.)).defined());
|
2019-11-16 04:28:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(FunctionalTest, Dropout2d) {
|
|
|
|
|
auto input = torch::randn({50, 100});
|
|
|
|
|
auto input_mean = input.mean();
|
|
|
|
|
auto input_std = input.std();
|
|
|
|
|
|
|
|
|
|
for (const auto rate : {0.2, 0.5, 0.8}) {
|
|
|
|
|
auto output = F::dropout2d(input, F::Dropout2dFuncOptions().p(rate));
|
|
|
|
|
ASSERT_TRUE(torch::allclose(input_mean, output.mean(), 0.01, 0.05));
|
|
|
|
|
ASSERT_TRUE((input_std <= output.std()).all().item<bool>());
|
|
|
|
|
}
|
|
|
|
|
auto output = F::dropout2d(input);
|
|
|
|
|
ASSERT_TRUE(torch::allclose(input_mean, output.mean(), 0.01, 0.05));
|
|
|
|
|
ASSERT_TRUE((input_std <= output.std()).all().item<bool>());
|
2019-11-20 00:06:25 +00:00
|
|
|
ASSERT_TRUE(F::dropout2d(torch::randn({50, 100})).defined());
|
2019-11-16 04:28:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(FunctionalTest, Dropout3d) {
|
|
|
|
|
auto input = torch::randn({50, 10, 10});
|
|
|
|
|
auto input_mean = input.mean();
|
|
|
|
|
auto input_std = input.std();
|
|
|
|
|
|
|
|
|
|
for (const auto rate : {0.2, 0.5, 0.8}) {
|
|
|
|
|
auto output = F::dropout3d(input, F::Dropout3dFuncOptions().p(rate));
|
|
|
|
|
ASSERT_TRUE(torch::allclose(input_mean, output.mean(), 0.01, 0.05));
|
|
|
|
|
ASSERT_TRUE((input_std <= output.std()).all().item<bool>());
|
|
|
|
|
}
|
|
|
|
|
auto output = F::dropout3d(input);
|
|
|
|
|
ASSERT_TRUE(torch::allclose(input_mean, output.mean(), 0.01, 0.05));
|
|
|
|
|
ASSERT_TRUE((input_std <= output.std()).all().item<bool>());
|
2019-11-20 00:06:25 +00:00
|
|
|
ASSERT_TRUE(F::dropout3d(torch::randn({50, 100})).defined());
|
2019-11-16 04:28:58 +00:00
|
|
|
}
|
2019-11-20 03:58:12 +00:00
|
|
|
|
|
|
|
|
template<c10::ScalarType S, typename T>
|
|
|
|
|
void test_isfinite(const at::Device& device) {
|
|
|
|
|
const std::vector<T> values = {
|
|
|
|
|
std::numeric_limits<T>::lowest(),
|
|
|
|
|
0, 1, 42,
|
|
|
|
|
std::numeric_limits<T>::min(),
|
|
|
|
|
std::numeric_limits<T>::max()
|
|
|
|
|
};
|
|
|
|
|
for (const auto value : values) {
|
|
|
|
|
const auto x = torch::full({3, 3}, value, torch::TensorOptions().dtype(S).device(device));
|
|
|
|
|
ASSERT_TRUE(torch::isfinite(x).all().template item<bool>());
|
|
|
|
|
}
|
|
|
|
|
if (std::numeric_limits<T>::has_infinity) {
|
|
|
|
|
const auto inf = std::numeric_limits<T>::infinity();
|
|
|
|
|
const auto x = torch::tensor({
|
|
|
|
|
-inf,
|
|
|
|
|
std::numeric_limits<T>::lowest(),
|
|
|
|
|
static_cast<T>(0),
|
|
|
|
|
static_cast<T>(1),
|
|
|
|
|
static_cast<T>(42),
|
|
|
|
|
std::numeric_limits<T>::min(),
|
|
|
|
|
std::numeric_limits<T>::max(),
|
|
|
|
|
inf
|
|
|
|
|
}, torch::TensorOptions().dtype(S).device(device));
|
|
|
|
|
ASSERT_TRUE(torch::allclose(
|
|
|
|
|
// torch::allclose does not support comparing torch::kBool
|
|
|
|
|
torch::isfinite(x).toType(torch::kInt),
|
|
|
|
|
torch::tensor(
|
|
|
|
|
{false, true, true, true, true, true, true, false},
|
|
|
|
|
torch::TensorOptions().device(device)
|
|
|
|
|
).toType(torch::kInt)
|
|
|
|
|
));
|
|
|
|
|
}
|
|
|
|
|
if (std::numeric_limits<T>::has_quiet_NaN) {
|
|
|
|
|
const auto x = torch::tensor({
|
|
|
|
|
std::numeric_limits<T>::quiet_NaN()
|
|
|
|
|
}, torch::TensorOptions().dtype(S).device(device));
|
|
|
|
|
ASSERT_FALSE(torch::isfinite(x).all().template item<bool>());
|
|
|
|
|
}
|
|
|
|
|
if (std::numeric_limits<T>::has_signaling_NaN) {
|
|
|
|
|
const auto x = torch::tensor({
|
|
|
|
|
std::numeric_limits<T>::signaling_NaN()
|
|
|
|
|
}, torch::TensorOptions().dtype(S).device(device));
|
|
|
|
|
ASSERT_FALSE(torch::isfinite(x).all().template item<bool>());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(FunctionalTest, isfinite) {
|
|
|
|
|
const at::Device device("cpu");
|
|
|
|
|
test_isfinite<torch::kUInt8, uint8_t>(device);
|
|
|
|
|
test_isfinite<torch::kInt8, int8_t>(device);
|
|
|
|
|
test_isfinite<torch::kInt16, int16_t>(device);
|
|
|
|
|
test_isfinite<torch::kInt32, int32_t>(device);
|
|
|
|
|
test_isfinite<torch::kInt64, int64_t>(device);
|
|
|
|
|
test_isfinite<torch::kFloat32, float>(device);
|
|
|
|
|
test_isfinite<torch::kFloat64, double>(device);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(FunctionalTest, isfinite_CUDA) {
|
|
|
|
|
const at::Device device("cuda");
|
|
|
|
|
test_isfinite<torch::kUInt8, uint8_t>(device);
|
|
|
|
|
test_isfinite<torch::kInt8, int8_t>(device);
|
|
|
|
|
test_isfinite<torch::kInt16, int16_t>(device);
|
|
|
|
|
test_isfinite<torch::kInt32, int32_t>(device);
|
|
|
|
|
test_isfinite<torch::kInt64, int64_t>(device);
|
|
|
|
|
test_isfinite<torch::kFloat32, float>(device);
|
|
|
|
|
test_isfinite<torch::kFloat64, double>(device);
|
|
|
|
|
test_isfinite<torch::kFloat16, c10::Half>(device);
|
|
|
|
|
}
|
2019-11-20 14:44:36 +00:00
|
|
|
|
2020-01-09 21:13:56 +00:00
|
|
|
template<c10::ScalarType S, typename T>
|
|
|
|
|
void test_isinf(const at::Device& device) {
|
|
|
|
|
const std::vector<T> values = {
|
|
|
|
|
std::numeric_limits<T>::lowest(),
|
|
|
|
|
0, 1, 42,
|
|
|
|
|
std::numeric_limits<T>::min(),
|
|
|
|
|
std::numeric_limits<T>::max()
|
|
|
|
|
};
|
|
|
|
|
for (const auto value : values) {
|
|
|
|
|
const auto x = torch::full({3, 3}, value, torch::TensorOptions().dtype(S).device(device));
|
|
|
|
|
ASSERT_FALSE(torch::isinf(x).all().template item<bool>());
|
|
|
|
|
}
|
|
|
|
|
if (std::numeric_limits<T>::has_infinity) {
|
|
|
|
|
const auto inf = std::numeric_limits<T>::infinity();
|
|
|
|
|
const auto x = torch::tensor({
|
|
|
|
|
-inf,
|
|
|
|
|
std::numeric_limits<T>::lowest(),
|
|
|
|
|
static_cast<T>(0),
|
|
|
|
|
static_cast<T>(1),
|
|
|
|
|
static_cast<T>(42),
|
|
|
|
|
std::numeric_limits<T>::min(),
|
|
|
|
|
std::numeric_limits<T>::max(),
|
|
|
|
|
inf
|
|
|
|
|
}, torch::TensorOptions().dtype(S).device(device));
|
|
|
|
|
ASSERT_TRUE(torch::allclose(
|
|
|
|
|
// torch::allclose does not support comparing torch::kBool
|
|
|
|
|
torch::isinf(x).toType(torch::kInt),
|
|
|
|
|
torch::tensor(
|
|
|
|
|
{true, false, false, false, false, false, false, true},
|
|
|
|
|
torch::TensorOptions().device(device)
|
|
|
|
|
).toType(torch::kInt)
|
|
|
|
|
));
|
|
|
|
|
}
|
|
|
|
|
if (std::numeric_limits<T>::has_quiet_NaN) {
|
|
|
|
|
const auto x = torch::tensor({
|
|
|
|
|
std::numeric_limits<T>::quiet_NaN()
|
|
|
|
|
}, torch::TensorOptions().dtype(S).device(device));
|
|
|
|
|
ASSERT_FALSE(torch::isinf(x).all().template item<bool>());
|
|
|
|
|
}
|
|
|
|
|
if (std::numeric_limits<T>::has_signaling_NaN) {
|
|
|
|
|
const auto x = torch::tensor({
|
|
|
|
|
std::numeric_limits<T>::signaling_NaN()
|
|
|
|
|
}, torch::TensorOptions().dtype(S).device(device));
|
|
|
|
|
ASSERT_FALSE(torch::isinf(x).all().template item<bool>());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(FunctionalTest, isinf) {
|
|
|
|
|
const at::Device device("cpu");
|
|
|
|
|
test_isinf<torch::kUInt8, uint8_t>(device);
|
|
|
|
|
test_isinf<torch::kInt8, int8_t>(device);
|
|
|
|
|
test_isinf<torch::kInt16, int16_t>(device);
|
|
|
|
|
test_isinf<torch::kInt32, int32_t>(device);
|
|
|
|
|
test_isinf<torch::kInt64, int64_t>(device);
|
|
|
|
|
test_isinf<torch::kFloat32, float>(device);
|
|
|
|
|
test_isinf<torch::kFloat64, double>(device);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(FunctionalTest, isinf_CUDA) {
|
|
|
|
|
const at::Device device("cuda");
|
|
|
|
|
test_isinf<torch::kUInt8, uint8_t>(device);
|
|
|
|
|
test_isinf<torch::kInt8, int8_t>(device);
|
|
|
|
|
test_isinf<torch::kInt16, int16_t>(device);
|
|
|
|
|
test_isinf<torch::kInt32, int32_t>(device);
|
|
|
|
|
test_isinf<torch::kInt64, int64_t>(device);
|
|
|
|
|
test_isinf<torch::kFloat32, float>(device);
|
|
|
|
|
test_isinf<torch::kFloat64, double>(device);
|
|
|
|
|
test_isinf<torch::kFloat16, c10::Half>(device);
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-05 03:04:26 +00:00
|
|
|
template<c10::ScalarType S, typename T>
|
|
|
|
|
void test_allclose(const at::Device& device) {
|
|
|
|
|
const std::vector<T> values = {
|
|
|
|
|
std::numeric_limits<T>::lowest(),
|
|
|
|
|
0, 1, 42,
|
|
|
|
|
std::numeric_limits<T>::min(),
|
|
|
|
|
std::numeric_limits<T>::max()
|
|
|
|
|
};
|
|
|
|
|
for (const auto value : values) {
|
|
|
|
|
const auto x = torch::full({1}, value, torch::TensorOptions().dtype(S).device(device));
|
|
|
|
|
const auto y = torch::full({1}, value, torch::TensorOptions().dtype(S).device(device));
|
|
|
|
|
ASSERT_TRUE(torch::allclose(x, x));
|
|
|
|
|
ASSERT_TRUE(torch::allclose(x, y));
|
|
|
|
|
ASSERT_TRUE(torch::allclose(y, x));
|
|
|
|
|
ASSERT_FALSE(torch::allclose(1.1 * x + 0.1, 1.0 * x));
|
|
|
|
|
ASSERT_TRUE(torch::allclose(0.99 * x + 0.1, 1.0 * x, 1.1, 0.1));
|
|
|
|
|
}
|
|
|
|
|
if (std::numeric_limits<T>::has_infinity) {
|
|
|
|
|
const auto inf = std::numeric_limits<T>::infinity();
|
|
|
|
|
const auto x = torch::tensor({-inf, inf},
|
|
|
|
|
torch::TensorOptions().dtype(S).device(device));
|
|
|
|
|
const auto y = torch::tensor({-inf, inf},
|
|
|
|
|
torch::TensorOptions().dtype(S).device(device));
|
|
|
|
|
ASSERT_TRUE(torch::allclose(x, x));
|
|
|
|
|
ASSERT_TRUE(torch::allclose(x, y));
|
|
|
|
|
ASSERT_TRUE(torch::allclose(y, x));
|
|
|
|
|
}
|
|
|
|
|
if (std::numeric_limits<T>::has_quiet_NaN) {
|
|
|
|
|
const auto x = torch::tensor({
|
|
|
|
|
std::numeric_limits<T>::quiet_NaN()
|
|
|
|
|
}, torch::TensorOptions().dtype(S).device(device));
|
|
|
|
|
const auto y = torch::tensor({
|
|
|
|
|
std::numeric_limits<T>::quiet_NaN()
|
|
|
|
|
}, torch::TensorOptions().dtype(S).device(device));
|
|
|
|
|
ASSERT_TRUE(torch::allclose(x, x, 1.0, 0.0, /*equal_nan=*/true));
|
|
|
|
|
ASSERT_TRUE(torch::allclose(x, y, 1.0, 0.0, /*equal_nan=*/true));
|
|
|
|
|
ASSERT_TRUE(torch::allclose(y, x, 1.0, 0.0, /*equal_nan=*/true));
|
|
|
|
|
}
|
|
|
|
|
if (std::numeric_limits<T>::has_signaling_NaN) {
|
|
|
|
|
const auto x = torch::tensor({
|
|
|
|
|
std::numeric_limits<T>::signaling_NaN()
|
|
|
|
|
}, torch::TensorOptions().dtype(S).device(device));
|
|
|
|
|
const auto y = torch::tensor({
|
|
|
|
|
std::numeric_limits<T>::signaling_NaN()
|
|
|
|
|
}, torch::TensorOptions().dtype(S).device(device));
|
|
|
|
|
ASSERT_TRUE(torch::allclose(x, x, 1.0, 0.0, /*equal_nan=*/true));
|
|
|
|
|
ASSERT_TRUE(torch::allclose(x, y, 1.0, 0.0, /*equal_nan=*/true));
|
|
|
|
|
ASSERT_TRUE(torch::allclose(y, x, 1.0, 0.0, /*equal_nan=*/true));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(FunctionalTest, AllClose) {
|
|
|
|
|
const at::Device device("cpu");
|
|
|
|
|
test_allclose<torch::kUInt8, uint8_t>(device);
|
|
|
|
|
test_allclose<torch::kInt8, int8_t>(device);
|
|
|
|
|
test_allclose<torch::kInt16, int16_t>(device);
|
|
|
|
|
test_allclose<torch::kInt32, int32_t>(device);
|
|
|
|
|
test_allclose<torch::kInt64, int64_t>(device);
|
|
|
|
|
test_allclose<torch::kFloat32, float>(device);
|
|
|
|
|
test_allclose<torch::kFloat64, double>(device);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(FunctionalTest, AllClose_CUDA) {
|
|
|
|
|
const at::Device device("cuda");
|
|
|
|
|
test_allclose<torch::kUInt8, uint8_t>(device);
|
|
|
|
|
test_allclose<torch::kInt8, int8_t>(device);
|
|
|
|
|
test_allclose<torch::kInt16, int16_t>(device);
|
|
|
|
|
test_allclose<torch::kInt32, int32_t>(device);
|
|
|
|
|
test_allclose<torch::kInt64, int64_t>(device);
|
|
|
|
|
test_allclose<torch::kFloat32, float>(device);
|
|
|
|
|
test_allclose<torch::kFloat64, double>(device);
|
|
|
|
|
test_allclose<torch::kFloat16, c10::Half>(device);
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-20 14:44:36 +00:00
|
|
|
TEST_F(FunctionalTest, BCEWithLogitsLoss) {
|
|
|
|
|
{ // test BCE with logits raises if target and input are different size
|
|
|
|
|
{
|
|
|
|
|
const auto target = torch::rand(5);
|
|
|
|
|
const auto input = torch::rand({5, 1});
|
|
|
|
|
ASSERT_THROWS_WITH(
|
|
|
|
|
F::binary_cross_entropy_with_logits(input, target),
|
|
|
|
|
"must be the same as input size"
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
{
|
|
|
|
|
const auto target = torch::rand({5, 1});
|
|
|
|
|
const auto input = torch::rand(5);
|
|
|
|
|
ASSERT_THROWS_WITH(
|
|
|
|
|
F::binary_cross_entropy_with_logits(input, target),
|
|
|
|
|
"must be the same as input size"
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
{ // test BCE with logits gives same result as sigmoid and bce loss
|
|
|
|
|
auto sigmoid = Sigmoid();
|
|
|
|
|
|
|
|
|
|
auto target = torch::rand({64, 4});
|
|
|
|
|
auto output = torch::rand({64, 4}) - 0.5;
|
|
|
|
|
|
|
|
|
|
ASSERT_TRUE(torch::allclose(
|
|
|
|
|
F::binary_cross_entropy_with_logits(output, target),
|
|
|
|
|
F::binary_cross_entropy(sigmoid(output), target)
|
|
|
|
|
));
|
|
|
|
|
|
|
|
|
|
auto weight = torch::rand(4);
|
|
|
|
|
ASSERT_TRUE(torch::allclose(
|
|
|
|
|
F::binary_cross_entropy_with_logits(output, target,
|
|
|
|
|
F::BinaryCrossEntropyWithLogitsFuncOptions().weight(weight)
|
|
|
|
|
),
|
|
|
|
|
F::binary_cross_entropy(sigmoid(output), target,
|
2019-11-20 20:12:29 +00:00
|
|
|
F::BinaryCrossEntropyFuncOptions().weight(weight)
|
2019-11-20 14:44:36 +00:00
|
|
|
)
|
|
|
|
|
));
|
|
|
|
|
|
|
|
|
|
target = torch::zeros({4, 1}, torch::kFloat);
|
|
|
|
|
output = torch::empty({4, 1}, torch::kFloat).fill_(-100);
|
|
|
|
|
|
|
|
|
|
ASSERT_TRUE(torch::allclose(
|
|
|
|
|
F::binary_cross_entropy_with_logits(output, target),
|
|
|
|
|
F::binary_cross_entropy(sigmoid(output), target)
|
|
|
|
|
));
|
|
|
|
|
|
|
|
|
|
ASSERT_TRUE(torch::allclose(
|
|
|
|
|
F::binary_cross_entropy_with_logits(output, target,
|
|
|
|
|
F::BinaryCrossEntropyWithLogitsFuncOptions().reduction(torch::kNone)
|
|
|
|
|
),
|
|
|
|
|
F::binary_cross_entropy(sigmoid(output), target,
|
2019-11-20 20:12:29 +00:00
|
|
|
F::BinaryCrossEntropyFuncOptions().reduction(torch::kNone)
|
2019-11-20 14:44:36 +00:00
|
|
|
)
|
|
|
|
|
));
|
|
|
|
|
|
|
|
|
|
weight = torch::rand({1}, torch::kFloat);
|
|
|
|
|
ASSERT_TRUE(torch::allclose(
|
|
|
|
|
F::binary_cross_entropy_with_logits(output, target,
|
|
|
|
|
F::BinaryCrossEntropyWithLogitsFuncOptions().weight(weight)
|
|
|
|
|
),
|
|
|
|
|
F::binary_cross_entropy(sigmoid(output), target,
|
2019-11-20 20:12:29 +00:00
|
|
|
F::BinaryCrossEntropyFuncOptions().weight(weight)
|
2019-11-20 14:44:36 +00:00
|
|
|
)
|
|
|
|
|
));
|
|
|
|
|
}
|
|
|
|
|
{ // test BCE with logits has correct grad at zero
|
|
|
|
|
const auto output = torch::zeros({3, 1}, torch::requires_grad());
|
|
|
|
|
const auto target = torch::zeros({3, 1});
|
|
|
|
|
F::binary_cross_entropy_with_logits(output, target,
|
|
|
|
|
F::BinaryCrossEntropyWithLogitsFuncOptions().reduction(torch::kSum)
|
|
|
|
|
).backward();
|
|
|
|
|
const auto expected_grad = torch::empty({3, 1}).fill_(0.5);
|
|
|
|
|
ASSERT_TRUE(torch::allclose(output.grad(), expected_grad));
|
|
|
|
|
}
|
|
|
|
|
{ // test BCE with logits broadcasts weights
|
|
|
|
|
const auto target = torch::rand({16, 4});
|
|
|
|
|
const auto output = torch::rand({16, 4}) - 0.5;
|
|
|
|
|
|
|
|
|
|
auto weight = torch::rand(4);
|
|
|
|
|
auto out1 = F::binary_cross_entropy_with_logits(output, target,
|
|
|
|
|
F::BinaryCrossEntropyWithLogitsFuncOptions().weight(weight)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
weight = weight.expand({16, 4}).contiguous();
|
|
|
|
|
auto out2 = F::binary_cross_entropy_with_logits(output, target,
|
|
|
|
|
F::BinaryCrossEntropyWithLogitsFuncOptions().weight(weight)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
ASSERT_TRUE(torch::allclose(out1, out2));
|
|
|
|
|
|
|
|
|
|
weight = torch::rand({16, 1});
|
|
|
|
|
out1 = F::binary_cross_entropy_with_logits(output, target,
|
|
|
|
|
F::BinaryCrossEntropyWithLogitsFuncOptions().weight(weight)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
weight = weight.expand({16, 4}).contiguous();
|
|
|
|
|
out2 = F::binary_cross_entropy_with_logits(output, target,
|
|
|
|
|
F::BinaryCrossEntropyWithLogitsFuncOptions().weight(weight)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
ASSERT_TRUE(torch::allclose(out1, out2));
|
|
|
|
|
}
|
|
|
|
|
{ // test BCE with logits ones in pos weights are the same as none
|
|
|
|
|
const auto target = torch::rand({64, 4});
|
|
|
|
|
const auto output = torch::rand({64, 4}) - 0.5;
|
|
|
|
|
const auto pos_weight = torch::ones({64, 4});
|
|
|
|
|
|
|
|
|
|
ASSERT_TRUE(torch::allclose(
|
|
|
|
|
F::binary_cross_entropy_with_logits(output, target),
|
|
|
|
|
F::binary_cross_entropy_with_logits(output, target,
|
|
|
|
|
F::BinaryCrossEntropyWithLogitsFuncOptions().pos_weight(pos_weight)
|
|
|
|
|
)
|
|
|
|
|
));
|
|
|
|
|
}
|
|
|
|
|
{ // test BCE with logits broadcasts pos weights
|
|
|
|
|
const auto target = torch::rand({64, 4});
|
|
|
|
|
const auto output = torch::rand({64, 4}) - 0.5;
|
|
|
|
|
const auto pos_weight = torch::rand(4);
|
|
|
|
|
const auto out1 = F::binary_cross_entropy_with_logits(output, target,
|
|
|
|
|
F::BinaryCrossEntropyWithLogitsFuncOptions().pos_weight(pos_weight)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const auto pos_weight1 = pos_weight.expand({1, 4});
|
|
|
|
|
const auto out2 = F::binary_cross_entropy_with_logits(output, target,
|
|
|
|
|
F::BinaryCrossEntropyWithLogitsFuncOptions().pos_weight(pos_weight)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const auto pos_weight2 = pos_weight.expand({64, 4});
|
|
|
|
|
const auto out3 = F::binary_cross_entropy_with_logits(output, target,
|
|
|
|
|
F::BinaryCrossEntropyWithLogitsFuncOptions().pos_weight(pos_weight)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
ASSERT_TRUE(torch::allclose(out1, out2));
|
|
|
|
|
ASSERT_TRUE(torch::allclose(out1, out3));
|
|
|
|
|
}
|
|
|
|
|
{ // test BCE with logits with pos weight has correct grad at zero
|
|
|
|
|
const auto output = torch::zeros({3, 1}, torch::requires_grad());
|
|
|
|
|
const auto target = torch::zeros({3, 1});
|
|
|
|
|
const auto pos_weight = torch::ones({3, 1});
|
|
|
|
|
F::binary_cross_entropy_with_logits(output, target,
|
|
|
|
|
F::BinaryCrossEntropyWithLogitsFuncOptions().pos_weight(pos_weight).reduction(torch::kSum)
|
|
|
|
|
).backward();
|
|
|
|
|
const auto expected_grad = torch::empty({3, 1}).fill_(0.5);
|
|
|
|
|
const auto grad = output.grad();
|
|
|
|
|
ASSERT_TRUE(torch::allclose(grad, expected_grad));
|
|
|
|
|
}
|
|
|
|
|
{ // test BCE with logits stability
|
|
|
|
|
const auto output = torch::tensor({0., -120.});
|
|
|
|
|
const auto target = torch::tensor({0., 1.});
|
|
|
|
|
const auto pos_weight = torch::tensor({1., 1.});
|
|
|
|
|
|
|
|
|
|
const auto out1 = F::binary_cross_entropy_with_logits(output, target);
|
|
|
|
|
ASSERT_TRUE(torch::isfinite(out1).all().item<bool>());
|
|
|
|
|
|
|
|
|
|
const auto out2 = F::binary_cross_entropy_with_logits(output, target,
|
|
|
|
|
F::BinaryCrossEntropyWithLogitsFuncOptions().pos_weight(pos_weight)
|
|
|
|
|
);
|
|
|
|
|
ASSERT_TRUE(torch::isfinite(out2).all().item<bool>());
|
|
|
|
|
}
|
|
|
|
|
}
|