autodiff.in.cpp 68.1 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
//*****************************************************************************
// Copyright 2017-2018 Intel Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//*****************************************************************************
16 17

#include <algorithm>
18
#include <functional>
19
#include <memory>
20
#include <tuple>
21 22 23 24

#include "gtest/gtest.h"

#include "ngraph/ngraph.hpp"
25
#include "ngraph/runtime/reference/avg_pool.hpp"
26
#include "util/autodiff/backprop_function.hpp"
adstraw's avatar
adstraw committed
27
#include "util/autodiff/numeric_compare.hpp"
28
#include "util/random.hpp"
29
#include "util/test_control.hpp"
30 31 32 33

using namespace std;
using namespace ngraph;

34 35 36
static string s_manifest = "${MANIFEST}";

NGRAPH_TEST(${BACKEND_NAME}, backwards_maxpool_n4_c1_hw4_2x2_max)
37
{
38
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
39

40
    Shape shape_a{1, 4, 4, 4}; // in CHWN
41
    Shape maxpool_shape{1, 4, 3, 3};
42 43 44

    auto A = make_shared<op::Parameter>(element::i32, shape_a);
    auto reshape = make_shared<op::Reshape>(
45
        A, AxisVector{0, 3, 1, 2}, Shape{1, 4, 4, 4}); // convert CHWN to CNHW
46
    Shape window_shape{2, 2};
47 48
    auto window_movement_strides = Strides{1, 1};
    auto maxpool = make_shared<op::MaxPool>(reshape, window_shape, window_movement_strides);
49
    auto f = make_shared<Function>(maxpool, op::ParameterVector{A});
50

51
    shared_ptr<runtime::TensorView> ep = backend->create_tensor(element::i32, maxpool_shape);
52 53
    vector<int> dataEp(shape_size(maxpool_shape), 4);

54 55
    shared_ptr<runtime::TensorView> input = backend->create_tensor(element::i32, shape_a);
    shared_ptr<runtime::TensorView> output = backend->create_tensor(element::i32, shape_a);
56 57 58 59 60 61

    vector<int> dataInput{11, 65, 44, 28, 31, 33, 21, 66, 40, 49, 69, 57, 47, 30, 24, 27,
                          13, 56, 46, 60, 61, 41, 25, 42, 48, 53, 51, 43, 59, 58, 29, 71,
                          17, 22, 72, 18, 39, 35, 15, 38, 64, 52, 73, 67, 62, 50, 10, 68,
                          45, 63, 16, 14, 55, 54, 37, 20, 36, 12, 70, 34, 19, 26, 32, 23};

62
    vector<int> expected{// delta
63 64 65 66 67 68 69 70 71
                         0, 4, 0, 0, 0, 0, 0, 8, 0, 0, 8, 0, 0, 0, 0, 0, 0, 4, 4,  4, 12, 0,
                         0, 0, 0, 8, 0, 0, 4, 8, 0, 8, 0, 0, 8, 0, 0, 0, 0, 4, 16, 4, 16, 8,
                         0, 0, 0, 4, 0, 4, 0, 0, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0};

    copy_data(ep, dataEp);
    copy_data(input, dataInput);

    auto C = make_shared<op::Parameter>(element::i32, maxpool_shape);
    auto df = autodiff::backprop_function(f);
72
    backend->call_with_validate(df, {output}, {input, ep});
73
    ASSERT_TRUE(read_vector<int>(output) == expected);
74 75
}

76
NGRAPH_TEST(${BACKEND_NAME}, backwards_maxpool_n2_c1_hw5_3x3_str2_max)
77
{
78
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
79

80
    Shape shape_a{1, 5, 5, 2}; // in CHWN
81
    Shape maxpool_shape{1, 2, 2, 2};
82 83 84

    auto A = make_shared<op::Parameter>(element::i32, shape_a);
    auto reshape = make_shared<op::Reshape>(
85
        A, AxisVector{0, 3, 1, 2}, Shape{1, 2, 5, 5}); // convert CHWN to CNHW
86
    Shape window_shape{3, 3};
87 88
    auto window_movement_strides = Strides{2, 2};
    auto maxpool = make_shared<op::MaxPool>(reshape, window_shape, window_movement_strides);
89
    auto f = make_shared<Function>(maxpool, op::ParameterVector{A});
90

91
    shared_ptr<runtime::TensorView> ep = backend->create_tensor(element::i32, maxpool_shape);
92 93
    vector<int> dataEp(shape_size(maxpool_shape), 4);

94 95
    shared_ptr<runtime::TensorView> input = backend->create_tensor(element::i32, shape_a);
    shared_ptr<runtime::TensorView> output = backend->create_tensor(element::i32, shape_a);
96 97 98 99 100

    vector<int> dataInput{58, 15, 51, 35, 18, 47, 31, 32, 52, 21, 36, 38, 57, 54, 25, 45, 23,
                          30, 16, 27, 48, 20, 41, 37, 43, 39, 22, 28, 33, 29, 12, 17, 44, 42,
                          19, 40, 10, 46, 34, 53, 26, 55, 50, 13, 24, 14, 49, 56, 59, 11};

101
    vector<int> expected{// delta
102 103 104 105 106 107 108 109
                         4, 0, 0, 0, 0, 4, 0, 0, 4, 0, 0, 0, 0, 4, 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, 0, 4, 4, 0, 0, 0, 0, 4, 4, 0};

    copy_data(ep, dataEp);
    copy_data(input, dataInput);

    auto C = make_shared<op::Parameter>(element::i32, maxpool_shape);
    auto df = autodiff::backprop_function(f);
110
    backend->call_with_validate(df, {output}, {input, ep});
111
    ASSERT_TRUE(read_vector<int>(output) == expected);
112 113
}

114 115 116 117
NGRAPH_TEST(${BACKEND_NAME}, backwards_maxpool_n2_c1_hw5_3x3_str2_max_pad1x2_2x3)
{
    auto backend = runtime::Backend::create("${BACKEND_NAME}");

118
    Shape shape_a{1, 5, 5, 2}; // in CHWN
119 120 121 122
    Shape maxpool_shape{1, 2, 4, 5};

    auto A = make_shared<op::Parameter>(element::f32, shape_a);
    auto reshape = make_shared<op::Reshape>(
123
        A, AxisVector{0, 3, 1, 2}, Shape{1, 2, 5, 5}); // convert CHWN to CNHW
124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
    Shape window_shape{3, 3};
    auto window_movement_strides = Strides{2, 2};
    Shape pad_below{1, 2};
    Shape pad_above{3, 4};
    auto maxpool = make_shared<op::MaxPool>(
        reshape, window_shape, window_movement_strides, pad_below, pad_above);
    auto f = make_shared<Function>(maxpool, op::ParameterVector{A});

    shared_ptr<runtime::TensorView> ep = backend->create_tensor(element::f32, maxpool_shape);
    vector<float> dataEp(shape_size(maxpool_shape), 4);

    shared_ptr<runtime::TensorView> input = backend->create_tensor(element::f32, shape_a);
    shared_ptr<runtime::TensorView> output = backend->create_tensor(element::f32, shape_a);

    vector<float> dataInput{58, 15, 51, 35, 18, 47, 31, 32, 52, 21, 36, 38, 57, 54, 25, 45, 23,
                            30, 16, 27, 48, 20, 41, 37, 43, 39, 22, 28, 33, 29, 12, 17, 44, 42,
                            19, 40, 10, 46, 34, 53, 26, 55, 50, 13, 24, 14, 49, 56, 59, 11};

142
    vector<float> expected{// delta
143 144 145 146 147 148 149 150 151 152 153 154
                           8, 0, 0, 0, 0, 4,  0, 0, 8, 0, 0, 8, 4, 8, 0, 0, 0,
                           0, 0, 4, 4, 0, 0,  0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                           0, 0, 0, 0, 4, 12, 4, 8, 4, 0, 0, 0, 0, 4, 8, 0};
    copy_data(ep, dataEp);
    copy_data(input, dataInput);

    auto C = make_shared<op::Parameter>(element::f32, maxpool_shape);
    auto df = autodiff::backprop_function(f);
    backend->call_with_validate(df, {output}, {input, ep});
    EXPECT_EQ(expected, read_vector<float>(output));
}

155
NGRAPH_TEST(${BACKEND_NAME}, backwards_avgpool_n1_c1_hw2x2)
156
{
157
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
158

159
    Shape padding{1, 1};
160

161 162
    Shape shape_a{1, 1, 2, 2};
    Shape avgpool_shape{1, 1, 2, 2};
163 164

    auto A = make_shared<op::Parameter>(element::i32, shape_a);
165
    Shape window_shape{2, 2};
166 167
    auto window_movement_strides = Strides{2, 2};
    auto avgpool =
168
        make_shared<op::AvgPool>(A, window_shape, window_movement_strides, padding, padding, false);
169
    auto f = make_shared<Function>(avgpool, op::ParameterVector{A});
170

171
    shared_ptr<runtime::TensorView> ep = backend->create_tensor(element::i32, avgpool_shape);
172 173
    vector<int> dataEp(shape_size(avgpool_shape), 4);

174
    shared_ptr<runtime::TensorView> input = backend->create_tensor(element::i32, shape_a);
175

176
    shared_ptr<runtime::TensorView> output = backend->create_tensor(element::i32, shape_a);
177 178 179 180 181 182 183 184 185 186

    vector<int> dataInput{4, 8, 12, 16};

    vector<int> expected{1, 2, 3, 4};

    copy_data(ep, dataEp);
    copy_data(input, dataInput);

    auto C = make_shared<op::Parameter>(element::i32, avgpool_shape);
    auto df = autodiff::backprop_function(f);
187
    backend->call_with_validate(df, {output}, {input, ep});
188 189 190
    ASSERT_TRUE(read_vector<int>(output) == dataEp);
}

191
NGRAPH_TEST(${BACKEND_NAME}, backwards_avgpool_n1_c1_hw4x4)
192
{
193
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
194

195 196
    Shape shape_a{1, 1, 4, 4};
    Shape avgpool_shape{1, 1, 3, 3};
197 198

    auto A = make_shared<op::Parameter>(element::i32, shape_a);
199
    Shape window_shape{2, 2};
200 201
    auto window_movement_strides = Strides{1, 1};
    auto avgpool = make_shared<op::AvgPool>(A, window_shape, window_movement_strides);
202
    auto f = make_shared<Function>(avgpool, op::ParameterVector{A});
203

204
    shared_ptr<runtime::TensorView> ep = backend->create_tensor(element::i32, avgpool_shape);
205 206
    vector<int> dataEp(shape_size(avgpool_shape), 4);

207
    shared_ptr<runtime::TensorView> input = backend->create_tensor(element::i32, shape_a);
208

209
    shared_ptr<runtime::TensorView> output = backend->create_tensor(element::i32, shape_a);
210 211 212 213 214 215 216 217 218 219

    vector<int> dataInput{1, 3, 1, 3, 1, 3, 1, 3, 3, 5, 3, 5, 3, 5, 3, 5};

    vector<int> expected{1, 2, 2, 1, 2, 4, 4, 2, 2, 4, 4, 2, 1, 2, 2, 1};

    copy_data(ep, dataEp);
    copy_data(input, dataInput);

    auto C = make_shared<op::Parameter>(element::i32, avgpool_shape);
    auto df = autodiff::backprop_function(f);
220
    backend->call_with_validate(df, {output}, {input, ep});
221 222 223
    ASSERT_TRUE(read_vector<int>(output) == expected);
}

224
NGRAPH_TEST(${BACKEND_NAME}, backwards_avgpool_n2_c2_hw4x4)
225
{
226
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
227

228 229
    Shape shape_a{2, 2, 4, 4};
    Shape avgpool_shape{2, 2, 2, 2};
230 231

    auto A = make_shared<op::Parameter>(element::i32, shape_a);
232
    Shape window_shape{2, 2};
233 234
    auto window_movement_strides = Strides{2, 2};
    auto avgpool = make_shared<op::AvgPool>(A, window_shape, window_movement_strides);
235
    auto f = make_shared<Function>(avgpool, op::ParameterVector{A});
236

237
    shared_ptr<runtime::TensorView> ep = backend->create_tensor(element::i32, avgpool_shape);
238 239
    vector<int> dataEp(shape_size(avgpool_shape), 12);

240
    shared_ptr<runtime::TensorView> input = backend->create_tensor(element::i32, shape_a);
241

242
    shared_ptr<runtime::TensorView> output = backend->create_tensor(element::i32, shape_a);
243

244
    vector<int> dataInput{// i1c1
245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260
                          1,
                          2,
                          6,
                          7,
                          3,
                          4,
                          4,
                          3,
                          19,
                          1,
                          2,
                          3,
                          18,
                          2,
                          3,
                          2,
261
                          // i1c2
262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277
                          4,
                          1,
                          5,
                          5,
                          1,
                          4,
                          5,
                          5,
                          12,
                          8,
                          2,
                          3,
                          15,
                          5,
                          3,
                          2,
278
                          // i2c1
279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294
                          2,
                          3,
                          7,
                          7,
                          3,
                          2,
                          3,
                          3,
                          13,
                          7,
                          1,
                          2,
                          7,
                          13,
                          3,
                          4,
295
                          // i2c2
296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318
                          1,
                          1,
                          2,
                          2,
                          7,
                          1,
                          2,
                          14,
                          6,
                          16,
                          4,
                          1,
                          14,
                          4,
                          4,
                          1};

    vector<int> expected(shape_size(shape_a), 3);
    copy_data(ep, dataEp);
    copy_data(input, dataInput);

    auto C = make_shared<op::Parameter>(element::i32, avgpool_shape);
    auto df = autodiff::backprop_function(f);
319
    backend->call_with_validate(df, {output}, {input, ep});
320 321 322
    ASSERT_TRUE(read_vector<int>(output) == expected);
}

323
NGRAPH_TEST(${BACKEND_NAME}, backwards_avgpool_n2_c2_hw4x4_numeric)
324
{
325
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
326
    Shape shape_a{2, 2, 4, 4};
327 328 329 330
    test::Uniform<float> rng(1.0f, 10.0f);

    auto make_graph = [shape_a]() {
        auto A = make_shared<op::Parameter>(element::f32, shape_a);
331
        Shape window_shape{2, 2};
332 333
        auto window_movement_strides = Strides{2, 2};
        auto avgpool = make_shared<op::AvgPool>(A, window_shape, window_movement_strides);
334
        return make_shared<Function>(avgpool, op::ParameterVector{A});
335 336 337

    };

338 339
    auto f = make_graph();
    auto g = make_graph();
340
    for (auto i = 0; i < ${TEST_LOOPS}; i++)
341
    {
342
        auto x = rng.initialize(backend->create_tensor(element::f32, shape_a));
343
        EXPECT_TRUE(autodiff_numeric_compare<float>(backend, f, g, {x}, .01f, .01f));
344 345 346
    }
}

347
NGRAPH_TEST(${BACKEND_NAME}, backwards_avgpool_n2_c2_hw4x4_win_2x2_str_1x1_numeric)
348
{
349
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
350
    Shape shape_a{2, 2, 4, 4};
351 352 353 354
    test::Uniform<float> rng(1.0f, 10.0f);

    auto make_graph = [shape_a]() {
        auto A = make_shared<op::Parameter>(element::f32, shape_a);
355
        Shape window_shape{2, 2};
356 357
        auto window_movement_strides = Strides{1, 1};
        auto avgpool = make_shared<op::AvgPool>(A, window_shape, window_movement_strides);
358
        return make_shared<Function>(avgpool, op::ParameterVector{A});
359 360 361

    };

362 363
    auto f = make_graph();
    auto g = make_graph();
364
    for (auto i = 0; i < ${TEST_LOOPS}; i++)
365
    {
366
        auto x = rng.initialize(backend->create_tensor(element::f32, shape_a));
367
        EXPECT_TRUE(autodiff_numeric_compare<float>(backend, f, g, {x}, .01f, .01f));
368 369 370
    }
}

371
NGRAPH_TEST(${BACKEND_NAME}, backwards_avgpool_n2_c2_hw2x2_win_2x2_str_1x1_padding_numeric)
372
{
373
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
374
    Shape shape_a{2, 2, 4, 4};
375 376 377 378
    test::Uniform<float> rng(1.0f, 10.0f);

    auto make_graph = [shape_a]() {
        auto A = make_shared<op::Parameter>(element::f32, shape_a);
379 380
        Shape window_shape{2, 2};
        Shape padding{1, 1};
381
        auto window_movement_strides = Strides{2, 2};
382 383
        auto avgpool = make_shared<op::AvgPool>(
            A, window_shape, window_movement_strides, padding, padding, false);
384
        return make_shared<Function>(avgpool, op::ParameterVector{A});
385 386 387

    };

388 389
    auto f = make_graph();
    auto g = make_graph();
390
    for (auto i = 0; i < ${TEST_LOOPS}; i++)
391
    {
392
        auto x = rng.initialize(backend->create_tensor(element::f32, shape_a));
393
        EXPECT_TRUE(autodiff_numeric_compare<float>(backend, f, g, {x}, .01f, .01f));
394 395 396
    }
}

397
NGRAPH_TEST(${BACKEND_NAME}, backwards_abs)
398
{
399
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
400 401 402 403 404

    // The numeric derivative and the symbolic one may disagree around 0, so we will dance around
    // that point by skipping (-0.01,0.01).
    test::Uniform<float> rng_neg(-1.0f, -0.01f);
    test::Uniform<float> rng_pos(0.01f, 1.0f);
405
    Shape shape{2, 3};
406 407

    auto make_graph = [shape]() {
408
        auto X = make_shared<op::Parameter>(element::f32, shape);
409 410
        return make_shared<Function>(make_shared<op::Abs>(X),
                                     std::vector<std::shared_ptr<op::Parameter>>{X});
411 412
    };

413 414
    auto f = make_graph();
    auto g = make_graph();
415
    for (auto i = 0; i < ${TEST_LOOPS}; i++)
416
    {
417
        auto x_neg = rng_neg.initialize(backend->create_tensor<float>(shape));
418

419
        EXPECT_TRUE(autodiff_numeric_compare<float>(backend, f, g, {x_neg}, .01f, .01f));
420

421
        auto x_pos = rng_pos.initialize(backend->create_tensor<float>(shape));
422

423
        EXPECT_TRUE(autodiff_numeric_compare<float>(backend, f, g, {x_pos}, .01f, .01f));
424
    }
425 426
}

427
NGRAPH_TEST(${BACKEND_NAME}, backwards_acos)
428 429 430 431 432 433 434 435 436 437 438 439 440 441 442
{
    auto backend = runtime::Backend::create("${BACKEND_NAME}");

    test::Uniform<float> rng(-0.9f, 0.9f);
    Shape shape{2, 3};
    auto x0 = rng.initialize(backend->create_tensor<float>(shape));

    auto make_graph = [shape]() {
        auto X0 = make_shared<op::Parameter>(element::f32, shape);
        return make_shared<Function>(make_shared<op::Acos>(X0),
                                     std::vector<std::shared_ptr<op::Parameter>>{X0});
    };
    EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x0}, .01f, .01f));
}

443
NGRAPH_TEST(${BACKEND_NAME}, backwards_add)
444
{
445
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
446

447
    test::Uniform<float> rng(-1.0f, 1.0f);
448
    Shape shape{2, 3};
449 450
    auto x0 = rng.initialize(backend->create_tensor<float>(shape));
    auto x1 = rng.initialize(backend->create_tensor<float>(shape));
Scott Cyphers's avatar
Scott Cyphers committed
451

452
    auto make_graph = [shape]() {
453 454
        auto X0 = make_shared<op::Parameter>(element::f32, shape);
        auto X1 = make_shared<op::Parameter>(element::f32, shape);
455
        return make_shared<Function>(X0 + X1, std::vector<std::shared_ptr<op::Parameter>>{X0, X1});
456
    };
457
    EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x0, x1}, .01f, .01f));
458 459
}

460
NGRAPH_TEST(${BACKEND_NAME}, backwards_add_nested)
461
{
462
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
463

464
    test::Uniform<float> rng(-1.0f, 1.0f);
465
    Shape shape{2, 3};
466 467
    auto x0 = rng.initialize(backend->create_tensor<float>(shape));
    auto x1 = rng.initialize(backend->create_tensor<float>(shape));
468 469

    auto make_graph = [shape]() {
470 471
        auto X0 = make_shared<op::Parameter>(element::f32, shape);
        auto X1 = make_shared<op::Parameter>(element::f32, shape);
472 473
        return make_shared<Function>((X0 + X1) + (X1 + X0),
                                     std::vector<std::shared_ptr<op::Parameter>>{X0, X1});
474
    };
475
    EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x0, x1}, .01f, .01f));
476 477
}

478
NGRAPH_TEST(${BACKEND_NAME}, backwards_asin)
479 480 481 482 483 484 485 486 487 488 489 490 491 492 493
{
    auto backend = runtime::Backend::create("${BACKEND_NAME}");

    test::Uniform<float> rng(-0.9f, 0.9f);
    Shape shape{2, 3};
    auto x0 = rng.initialize(backend->create_tensor<float>(shape));

    auto make_graph = [shape]() {
        auto X0 = make_shared<op::Parameter>(element::f32, shape);
        return make_shared<Function>(make_shared<op::Asin>(X0),
                                     std::vector<std::shared_ptr<op::Parameter>>{X0});
    };
    EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x0}, .01f, .01f));
}

494
NGRAPH_TEST(${BACKEND_NAME}, backwards_atan)
495 496 497 498 499 500 501 502 503 504 505 506 507 508 509
{
    auto backend = runtime::Backend::create("${BACKEND_NAME}");

    test::Uniform<float> rng(-10.0f, 10.0f);
    Shape shape{2, 3};
    auto x0 = rng.initialize(backend->create_tensor<float>(shape));

    auto make_graph = [shape]() {
        auto X0 = make_shared<op::Parameter>(element::f32, shape);
        return make_shared<Function>(make_shared<op::Atan>(X0),
                                     std::vector<std::shared_ptr<op::Parameter>>{X0});
    };
    EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x0}, .01f, .01f));
}

510
NGRAPH_TEST(${BACKEND_NAME}, backwards_broadcast0)
511
{
512
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
513

514
    test::Uniform<float> rng(-1.0f, 1.0f);
515
    Shape shape{3};
516
    auto x0 = rng.initialize(backend->create_tensor<float>(shape));
517 518

    auto make_graph = [shape]() {
519
        auto X0 = make_shared<op::Parameter>(element::f32, shape);
520 521 522
        return make_shared<Function>(make_shared<op::Broadcast>(X0, Shape{2, 3}, AxisSet{0}),
                                     std::vector<std::shared_ptr<op::Parameter>>{X0});
    };
523
    EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x0}, .01f, .01f));
524 525
}

526
NGRAPH_TEST(${BACKEND_NAME}, backwards_broadcast1)
527
{
528
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
529

530
    test::Uniform<float> rng(-1.0f, 1.0f);
531
    Shape shape{3};
532
    auto x0 = rng.initialize(backend->create_tensor<float>(shape));
533 534

    auto make_graph = [shape]() {
535
        auto X0 = make_shared<op::Parameter>(element::f32, shape);
536 537 538
        return make_shared<Function>(make_shared<op::Broadcast>(X0, Shape{3, 2}, AxisSet{1}),
                                     std::vector<std::shared_ptr<op::Parameter>>{X0});
    };
539
    EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x0}, .01f, .01f));
540 541
}

542
NGRAPH_TEST(${BACKEND_NAME}, backwards_concat_vector)
543
{
544
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
545 546

    test::Uniform<float> rng(-1.0f, 1.0f);
547
    Shape shape_0{3};
548
    auto x0 = rng.initialize(backend->create_tensor(element::f32, shape_0));
549
    Shape shape_1{2};
550
    auto x1 = rng.initialize(backend->create_tensor(element::f32, shape_1));
551
    Shape shape_2{1};
552
    auto x2 = rng.initialize(backend->create_tensor(element::f32, shape_2));
553 554

    auto make_graph = [shape_0, shape_1, shape_2]() {
555 556 557
        auto X0 = make_shared<op::Parameter>(element::f32, shape_0);
        auto X1 = make_shared<op::Parameter>(element::f32, shape_1);
        auto X2 = make_shared<op::Parameter>(element::f32, shape_2);
558
        return make_shared<Function>(make_shared<op::Concat>(NodeVector{X0, X1, X2}, 0),
559 560
                                     std::vector<std::shared_ptr<op::Parameter>>{X0, X1, X2});
    };
561
    EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x0, x1, x2}, .01f, .01f));
562 563
}

564
NGRAPH_TEST(${BACKEND_NAME}, backwards_concat_axis_0)
565
{
566
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
567 568

    test::Uniform<float> rng(-1.0f, 1.0f);
569
    Shape shape_0{3, 2};
570
    auto x0 = rng.initialize(backend->create_tensor(element::f32, shape_0));
571
    Shape shape_1{2, 2};
572
    auto x1 = rng.initialize(backend->create_tensor(element::f32, shape_1));
573
    Shape shape_2{1, 2};
574
    auto x2 = rng.initialize(backend->create_tensor(element::f32, shape_2));
575 576

    auto make_graph = [shape_0, shape_1, shape_2]() {
577 578 579
        auto X0 = make_shared<op::Parameter>(element::f32, shape_0);
        auto X1 = make_shared<op::Parameter>(element::f32, shape_1);
        auto X2 = make_shared<op::Parameter>(element::f32, shape_2);
580
        return make_shared<Function>(make_shared<op::Concat>(NodeVector{X0, X1, X2}, 0),
581 582
                                     std::vector<std::shared_ptr<op::Parameter>>{X0, X1, X2});
    };
583
    EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x0, x1, x2}, .01f, .01f));
584 585
}

586
NGRAPH_TEST(${BACKEND_NAME}, backwards_concat_axis_1)
587
{
588
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
589 590

    test::Uniform<float> rng(-1.0f, 1.0f);
591
    Shape shape_0{2, 3};
592
    auto x0 = rng.initialize(backend->create_tensor(element::f32, shape_0));
593
    Shape shape_1{2, 2};
594
    auto x1 = rng.initialize(backend->create_tensor(element::f32, shape_1));
595
    Shape shape_2{2, 1};
596
    auto x2 = rng.initialize(backend->create_tensor(element::f32, shape_2));
597 598

    auto make_graph = [shape_0, shape_1, shape_2]() {
599 600 601
        auto X0 = make_shared<op::Parameter>(element::f32, shape_0);
        auto X1 = make_shared<op::Parameter>(element::f32, shape_1);
        auto X2 = make_shared<op::Parameter>(element::f32, shape_2);
602
        return make_shared<Function>(make_shared<op::Concat>(NodeVector{X0, X1, X2}, 1),
603 604
                                     std::vector<std::shared_ptr<op::Parameter>>{X0, X1, X2});
    };
605
    EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x0, x1, x2}, .01f, .01f));
606 607
}

608
NGRAPH_TEST(${BACKEND_NAME}, backwards_ceiling)
609
{
610
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
611 612 613 614 615 616

    // The numeric derivative and the symbolic one may disagree near integers, so we will dance around
    // them.
    test::Uniform<float> rng_minusone(-0.95f, -0.05f);
    test::Uniform<float> rng_plusone(0.05f, 0.95f);
    test::Uniform<float> rng_plustwo(1.05f, 1.95f);
617
    Shape shape{2, 3};
618 619

    auto make_graph = [shape]() {
620
        auto X = make_shared<op::Parameter>(element::f32, shape);
621 622
        return make_shared<Function>(make_shared<op::Ceiling>(X),
                                     std::vector<std::shared_ptr<op::Parameter>>{X});
623 624
    };

625 626
    auto f = make_graph();
    auto g = make_graph();
627
    for (auto i = 0; i < ${TEST_LOOPS}; i++)
628
    {
629
        auto x_minusone = rng_minusone.initialize(backend->create_tensor<float>(shape));
630

631
        EXPECT_TRUE(autodiff_numeric_compare<float>(backend, f, g, {x_minusone}, .01f, .01f));
632

633
        auto x_plusone = rng_plusone.initialize(backend->create_tensor<float>(shape));
634

635
        EXPECT_TRUE(autodiff_numeric_compare<float>(backend, f, g, {x_plusone}, .01f, .01f));
636

637
        auto x_plustwo = rng_plustwo.initialize(backend->create_tensor<float>(shape));
638

639
        EXPECT_TRUE(autodiff_numeric_compare<float>(backend, f, g, {x_plustwo}, .01f, .01f));
640 641 642
    }
}

643
NGRAPH_TEST(${BACKEND_NAME}, backwards_cos)
644
{
645
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
646 647

    test::Uniform<float> rng(-10.0f, 10.0f);
648
    Shape shape{2, 3};
649
    auto make_graph = [shape]() {
650
        auto X = make_shared<op::Parameter>(element::f32, shape);
651 652
        return make_shared<Function>(make_shared<op::Cos>(X),
                                     std::vector<std::shared_ptr<op::Parameter>>{X});
653 654
    };

655 656
    auto f = make_graph();
    auto g = make_graph();
657
    for (auto i = 0; i < ${TEST_LOOPS}; i++)
658
    {
659
        auto x = rng.initialize(backend->create_tensor<float>(shape));
660

661
        EXPECT_TRUE(autodiff_numeric_compare<float>(backend, f, g, {x}, .01f, .01f));
662 663 664
    }
}

665
NGRAPH_TEST(${BACKEND_NAME}, backwards_cosh)
666
{
667
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
668 669

    test::Uniform<float> rng(-10.0f, 10.0f);
670
    Shape shape{2, 3};
671
    auto make_graph = [shape]() {
672
        auto X = make_shared<op::Parameter>(element::f32, shape);
673 674
        return make_shared<Function>(make_shared<op::Cosh>(X),
                                     std::vector<std::shared_ptr<op::Parameter>>{X});
675 676
    };

677 678
    auto f = make_graph();
    auto g = make_graph();
679
    for (auto i = 0; i < ${TEST_LOOPS}; i++)
680
    {
681
        auto x = rng.initialize(backend->create_tensor<float>(shape));
682

683
        EXPECT_TRUE(autodiff_numeric_compare<float>(backend, f, g, {x}, .01f, .01f));
684 685 686
    }
}

687
NGRAPH_TEST(${BACKEND_NAME}, backwards_divide)
688
{
689
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
690

691 692 693
    test::Uniform<float> rng(-1.0f, 1.0f);
    test::Uniform<float> rng1(1.0f, 2.0f);
    test::Uniform<float> rng2(-2.0f, -1.0f);
694
    Shape shape{2, 3};
695 696 697
    auto x0 = rng.initialize(backend->create_tensor<float>(shape));
    auto x1 = rng1.initialize(backend->create_tensor<float>(shape));
    auto x2 = rng2.initialize(backend->create_tensor<float>(shape));
698

699
    auto make_graph = [shape]() {
700 701
        auto X0 = make_shared<op::Parameter>(element::f32, shape);
        auto X1 = make_shared<op::Parameter>(element::f32, shape);
702
        return make_shared<Function>(X0 / X1, std::vector<std::shared_ptr<op::Parameter>>{X0, X1});
703
    };
704 705
    EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x0, x1}, .01f, .01f));
    EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x0, x2}, .01f, .01f));
Scott Cyphers's avatar
Scott Cyphers committed
706
}
707

708
NGRAPH_TEST(${BACKEND_NAME}, backwards_dot_scalar_scalar)
709
{
710
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
711

712
    test::Uniform<float> rng(-1.0f, 1.0f);
713 714
    Shape shape0{};
    Shape shape1{};
715 716
    auto x0 = rng.initialize(backend->create_tensor<float>(shape0));
    auto x1 = rng.initialize(backend->create_tensor<float>(shape1));
717 718

    auto make_graph = [shape0, shape1]() {
719 720
        auto X0 = make_shared<op::Parameter>(element::f32, shape0);
        auto X1 = make_shared<op::Parameter>(element::f32, shape1);
721 722 723
        return make_shared<Function>(make_shared<op::Dot>(X0, X1),
                                     std::vector<std::shared_ptr<op::Parameter>>{X0, X1});
    };
724
    EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x0, x1}, .01f, .01f));
725 726
}

727
NGRAPH_TEST(${BACKEND_NAME}, backwards_dot_scalar_tensor)
728
{
729
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
730

731
    test::Uniform<float> rng(-1.0f, 1.0f);
732 733
    Shape shape0{};
    Shape shape1{3, 4};
734 735
    auto x0 = rng.initialize(backend->create_tensor<float>(shape0));
    auto x1 = rng.initialize(backend->create_tensor<float>(shape1));
736 737

    auto make_graph = [shape0, shape1]() {
738 739
        auto X0 = make_shared<op::Parameter>(element::f32, shape0);
        auto X1 = make_shared<op::Parameter>(element::f32, shape1);
740 741 742
        return make_shared<Function>(make_shared<op::Dot>(X0, X1),
                                     std::vector<std::shared_ptr<op::Parameter>>{X0, X1});
    };
743
    EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x0, x1}, .01f, .01f));
744 745
}

746
NGRAPH_TEST(${BACKEND_NAME}, backwards_dot_tensor_scalar)
747
{
748
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
749

750
    test::Uniform<float> rng(-1.0f, 1.0f);
751 752
    Shape shape0{3, 4};
    Shape shape1{};
753 754
    auto x0 = rng.initialize(backend->create_tensor<float>(shape0));
    auto x1 = rng.initialize(backend->create_tensor<float>(shape1));
755 756

    auto make_graph = [shape0, shape1]() {
757 758
        auto X0 = make_shared<op::Parameter>(element::f32, shape0);
        auto X1 = make_shared<op::Parameter>(element::f32, shape1);
759 760 761
        return make_shared<Function>(make_shared<op::Dot>(X0, X1),
                                     std::vector<std::shared_ptr<op::Parameter>>{X0, X1});
    };
762
    EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x0, x1}, .01f, .01f));
763 764
}

765
NGRAPH_TEST(${BACKEND_NAME}, backwards_dot_vector_vector)
766
{
767
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
768

769
    test::Uniform<float> rng(-1.0f, 1.0f);
770 771
    Shape shape0{3};
    Shape shape1{3};
772 773
    auto x0 = rng.initialize(backend->create_tensor<float>(shape0));
    auto x1 = rng.initialize(backend->create_tensor<float>(shape1));
774 775

    auto make_graph = [shape0, shape1]() {
776 777
        auto X0 = make_shared<op::Parameter>(element::f32, shape0);
        auto X1 = make_shared<op::Parameter>(element::f32, shape1);
778 779 780
        return make_shared<Function>(make_shared<op::Dot>(X0, X1),
                                     std::vector<std::shared_ptr<op::Parameter>>{X0, X1});
    };
781
    EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x0, x1}, .01f, .01f));
782 783
}

784
NGRAPH_TEST(${BACKEND_NAME}, backwards_dot_tensor_vector)
785
{
786
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
787

788
    test::Uniform<float> rng(-1.0f, 1.0f);
789 790
    Shape shape0{4, 3};
    Shape shape1{3};
791 792
    auto x0 = rng.initialize(backend->create_tensor<float>(shape0));
    auto x1 = rng.initialize(backend->create_tensor<float>(shape1));
793 794

    auto make_graph = [shape0, shape1]() {
795 796
        auto X0 = make_shared<op::Parameter>(element::f32, shape0);
        auto X1 = make_shared<op::Parameter>(element::f32, shape1);
797 798 799
        return make_shared<Function>(make_shared<op::Dot>(X0, X1),
                                     std::vector<std::shared_ptr<op::Parameter>>{X0, X1});
    };
800
    EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x0, x1}, .01f, .01f));
801 802
}

803
NGRAPH_TEST(${BACKEND_NAME}, backwards_dot_tensor2_tensor2)
804
{
805
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
806

807
    test::Uniform<float> rng(-1.0f, 1.0f);
808 809
    Shape shape0{4, 3};
    Shape shape1{3, 5};
810 811
    auto x0 = rng.initialize(backend->create_tensor<float>(shape0));
    auto x1 = rng.initialize(backend->create_tensor<float>(shape1));
812 813

    auto make_graph = [shape0, shape1]() {
814 815
        auto X0 = make_shared<op::Parameter>(element::f32, shape0);
        auto X1 = make_shared<op::Parameter>(element::f32, shape1);
816 817
        return make_shared<Function>(make_shared<op::Dot>(X0, X1),
                                     std::vector<std::shared_ptr<op::Parameter>>{X0, X1});
Adam Procter's avatar
Adam Procter committed
818
    };
819
    EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x0, x1}, .01f, .01f));
Adam Procter's avatar
Adam Procter committed
820 821
}

822
NGRAPH_TEST(${BACKEND_NAME}, backwards_dot_tensor3_tensor3)
Adam Procter's avatar
Adam Procter committed
823
{
824
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
Adam Procter's avatar
Adam Procter committed
825 826

    test::Uniform<float> rng(-1.0f, 1.0f);
827 828
    Shape shape0{2, 4, 3};
    Shape shape1{4, 3, 3};
829 830
    auto x0 = rng.initialize(backend->create_tensor<float>(shape0));
    auto x1 = rng.initialize(backend->create_tensor<float>(shape1));
Adam Procter's avatar
Adam Procter committed
831 832

    auto make_graph = [shape0, shape1]() {
833 834
        auto X0 = make_shared<op::Parameter>(element::f32, shape0);
        auto X1 = make_shared<op::Parameter>(element::f32, shape1);
Adam Procter's avatar
Adam Procter committed
835 836
        return make_shared<Function>(make_shared<op::Dot>(X0, X1, 2),
                                     std::vector<std::shared_ptr<op::Parameter>>{X0, X1});
837
    };
838
    EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x0, x1}, .01f, .01f));
839 840
}

841
NGRAPH_TEST(${BACKEND_NAME}, backwards_exp)
Scott Cyphers's avatar
Scott Cyphers committed
842
{
843
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
Scott Cyphers's avatar
Scott Cyphers committed
844

845
    test::Uniform<float> rng(-1.0f, 1.0f);
846
    Shape shape{2, 3};
847
    auto x0 = rng.initialize(backend->create_tensor<float>(shape));
Scott Cyphers's avatar
Scott Cyphers committed
848 849

    auto make_graph = [shape]() {
850
        auto X0 = make_shared<op::Parameter>(element::f32, shape);
851 852
        return make_shared<Function>(make_shared<op::Exp>(X0),
                                     std::vector<std::shared_ptr<op::Parameter>>{X0});
Scott Cyphers's avatar
Scott Cyphers committed
853
    };
854
    EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x0}, .01f, .01f));
Scott Cyphers's avatar
Scott Cyphers committed
855 856
}

857
NGRAPH_TEST(${BACKEND_NAME}, backwards_floor)
858
{
859
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
860 861 862 863 864 865

    // The numeric derivative and the symbolic one may disagree near integers, so we will dance around
    // them.
    test::Uniform<float> rng_minusone(-0.95f, -0.05f);
    test::Uniform<float> rng_plusone(0.05f, 0.95f);
    test::Uniform<float> rng_plustwo(1.05f, 1.95f);
866
    Shape shape{2, 3};
867 868

    auto make_graph = [shape]() {
869
        auto X = make_shared<op::Parameter>(element::f32, shape);
870 871
        return make_shared<Function>(make_shared<op::Floor>(X),
                                     std::vector<std::shared_ptr<op::Parameter>>{X});
872 873
    };

874 875
    auto f = make_graph();
    auto g = make_graph();
876
    for (auto i = 0; i < ${TEST_LOOPS}; i++)
877
    {
878
        auto x_minusone = rng_minusone.initialize(backend->create_tensor<float>(shape));
879

880
        EXPECT_TRUE(autodiff_numeric_compare<float>(backend, f, g, {x_minusone}, .01f, .01f));
881

882
        auto x_plusone = rng_plusone.initialize(backend->create_tensor<float>(shape));
883

884
        EXPECT_TRUE(autodiff_numeric_compare<float>(backend, f, g, {x_plusone}, .01f, .01f));
885

886
        auto x_plustwo = rng_plustwo.initialize(backend->create_tensor<float>(shape));
887

888
        EXPECT_TRUE(autodiff_numeric_compare<float>(backend, f, g, {x_plustwo}, .01f, .01f));
889 890 891
    }
}

892
NGRAPH_TEST(${BACKEND_NAME}, backwards_log)
Scott Cyphers's avatar
Scott Cyphers committed
893
{
894
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
Scott Cyphers's avatar
Scott Cyphers committed
895

896
    test::Uniform<float> rng(1.0f, 2.0f);
897
    Shape shape{2, 3};
898
    auto x0 = rng.initialize(backend->create_tensor<float>(shape));
Scott Cyphers's avatar
Scott Cyphers committed
899 900

    auto make_graph = [shape]() {
901
        auto X0 = make_shared<op::Parameter>(element::f32, shape);
902 903
        return make_shared<Function>(make_shared<op::Log>(X0),
                                     std::vector<std::shared_ptr<op::Parameter>>{X0});
Scott Cyphers's avatar
Scott Cyphers committed
904
    };
905
    EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x0}, .01f, .01f));
906 907
}

908
NGRAPH_TEST(${BACKEND_NAME}, backwards_maximum)
909
{
910
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
911

912
    test::Uniform<float> rng(-1.0f, 1.0f);
913
    Shape shape{2, 3};
914 915
    auto x0 = rng.initialize(backend->create_tensor<float>(shape));
    auto x1 = rng.initialize(backend->create_tensor<float>(shape));
916 917

    auto make_graph = [shape]() {
918 919
        auto X0 = make_shared<op::Parameter>(element::f32, shape);
        auto X1 = make_shared<op::Parameter>(element::f32, shape);
920 921 922
        return make_shared<Function>(make_shared<op::Maximum>(X0, X1),
                                     std::vector<std::shared_ptr<op::Parameter>>{X0, X1});
    };
923
    EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x0, x1}, .01f, .01f));
924 925
}

926
NGRAPH_TEST(${BACKEND_NAME}, backwards_minimum)
927
{
928
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
929

930
    test::Uniform<float> rng(-1.0f, 1.0f);
931
    Shape shape{2, 3};
932 933
    auto x0 = rng.initialize(backend->create_tensor<float>(shape));
    auto x1 = rng.initialize(backend->create_tensor<float>(shape));
934 935

    auto make_graph = [shape]() {
936 937
        auto X0 = make_shared<op::Parameter>(element::f32, shape);
        auto X1 = make_shared<op::Parameter>(element::f32, shape);
938 939 940
        return make_shared<Function>(make_shared<op::Minimum>(X0, X1),
                                     std::vector<std::shared_ptr<op::Parameter>>{X0, X1});
    };
941
    EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x0, x1}, .01f, .01f));
942 943
}

944
NGRAPH_TEST(${BACKEND_NAME}, backwards_multiply)
945
{
946
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
947

948
    test::Uniform<float> rng(-1.0f, 1.0f);
949
    Shape shape{2, 3};
950 951
    auto x0 = rng.initialize(backend->create_tensor<float>(shape));
    auto x1 = rng.initialize(backend->create_tensor<float>(shape));
952

953
    auto make_graph = [shape]() {
954 955
        auto X0 = make_shared<op::Parameter>(element::f32, shape);
        auto X1 = make_shared<op::Parameter>(element::f32, shape);
956
        return make_shared<Function>(X0 * X1, std::vector<std::shared_ptr<op::Parameter>>{X0, X1});
957
    };
958
    EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x0, x1}, .01f, .01f));
959
}
Scott Cyphers's avatar
Scott Cyphers committed
960

961
NGRAPH_TEST(${BACKEND_NAME}, backwards_negative)
Scott Cyphers's avatar
Scott Cyphers committed
962
{
963
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
Scott Cyphers's avatar
Scott Cyphers committed
964

965
    test::Uniform<float> rng(-1.0f, 1.0f);
966
    Shape shape{2, 3};
967
    auto x0 = rng.initialize(backend->create_tensor<float>(shape));
Scott Cyphers's avatar
Scott Cyphers committed
968 969

    auto make_graph = [shape]() {
970
        auto X0 = make_shared<op::Parameter>(element::f32, shape);
971
        return make_shared<Function>(-X0, std::vector<std::shared_ptr<op::Parameter>>{X0});
Scott Cyphers's avatar
Scott Cyphers committed
972
    };
973
    EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x0}, .01f, .01f));
Scott Cyphers's avatar
Scott Cyphers committed
974 975
}

976
NGRAPH_TEST(${BACKEND_NAME}, backwards_parameter)
Scott Cyphers's avatar
Scott Cyphers committed
977
{
978
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
Scott Cyphers's avatar
Scott Cyphers committed
979

980
    test::Uniform<float> rng(-1.0f, 1.0f);
981
    Shape shape{2, 3};
982
    auto x0 = rng.initialize(backend->create_tensor<float>(shape));
Scott Cyphers's avatar
Scott Cyphers committed
983
    auto make_graph = [shape]() {
984
        auto X0 = make_shared<op::Parameter>(element::f32, shape);
985
        return make_shared<Function>(X0, std::vector<std::shared_ptr<op::Parameter>>{X0});
Scott Cyphers's avatar
Scott Cyphers committed
986
    };
987
    EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x0}, .01f, .01f));
988 989
}

990
NGRAPH_TEST(${BACKEND_NAME}, backwards_power)
991
{
992
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
993 994 995

    test::Uniform<float> rng_neg(-5.0f, -0.5f);
    test::Uniform<float> rng_pos(0.5f, 5.0f);
996
    Shape shape{2, 3};
997 998

    auto make_graph = [shape]() {
999 1000
        auto X0 = make_shared<op::Parameter>(element::f32, shape);
        auto X1 = make_shared<op::Parameter>(element::f32, shape);
1001 1002 1003 1004
        return make_shared<Function>(std::make_shared<op::Power>(X0, X1),
                                     std::vector<std::shared_ptr<op::Parameter>>{X0, X1});
    };

1005 1006
    auto x0 = rng_neg.initialize(backend->create_tensor<float>(shape));
    auto x1 = rng_pos.initialize(backend->create_tensor<float>(shape));
1007

1008
    EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x0, x1}, .01f, .01f));
1009

1010 1011
    x0 = rng_pos.initialize(backend->create_tensor<float>(shape));
    x1 = rng_neg.initialize(backend->create_tensor<float>(shape));
1012

1013
    EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x0, x1}, .01f, .01f));
1014

1015 1016
    x0 = rng_pos.initialize(backend->create_tensor<float>(shape));
    x1 = rng_pos.initialize(backend->create_tensor<float>(shape));
1017

1018
    EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x0, x1}, .01f, .01f));
1019 1020
}

1021
NGRAPH_TEST(${BACKEND_NAME}, backwards_relu)
1022
{
1023
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
1024 1025 1026 1027

    test::Uniform<float> rng_neg(-1.0f, -0.01f);
    test::Uniform<float> rng_pos(0.01f, 1.0f);
    Shape shape{2, 3};
1028 1029
    auto x0 = rng_neg.initialize(backend->create_tensor<float>(shape));
    auto x1 = rng_pos.initialize(backend->create_tensor<float>(shape));
1030 1031 1032 1033 1034 1035 1036

    auto make_graph = [shape]() {
        auto X = make_shared<op::Parameter>(element::f32, shape);
        return make_shared<Function>(make_shared<op::Relu>(X),
                                     std::vector<std::shared_ptr<op::Parameter>>{X});
    };

1037 1038
    auto f = make_graph();
    auto g = make_graph();
1039 1040
    for (auto i = 0; i < ${TEST_LOOPS}; i++)
    {
1041
        auto x_neg = rng_neg.initialize(backend->create_tensor<float>(shape));
1042

1043
        EXPECT_TRUE(autodiff_numeric_compare<float>(backend, f, g, {x_neg}, .01f, .01f));
1044

1045
        auto x_pos = rng_pos.initialize(backend->create_tensor<float>(shape));
1046

1047
        EXPECT_TRUE(autodiff_numeric_compare<float>(backend, f, g, {x_pos}, .01f, .01f));
1048 1049 1050
    }
}

1051
NGRAPH_TEST(${BACKEND_NAME}, backwards_replace_slice)
1052
{
1053
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
1054 1055

    test::Uniform<float> rng(-10.0f, 10.0f);
1056 1057
    Shape shape_x{5, 5};
    Shape shape_y{2, 2};
1058
    auto make_graph = [shape_x, shape_y]() {
1059 1060
        auto X = make_shared<op::Parameter>(element::f32, shape_x);
        auto Y = make_shared<op::Parameter>(element::f32, shape_y);
1061 1062 1063 1064 1065
        return make_shared<Function>(
            make_shared<op::ReplaceSlice>(X, Y, Coordinate{2, 3}, Coordinate{4, 5}),
            std::vector<std::shared_ptr<op::Parameter>>{X, Y});
    };

1066 1067
    auto f = make_graph();
    auto g = make_graph();
1068
    for (auto i = 0; i < ${TEST_LOOPS}; i++)
1069
    {
1070 1071
        auto x = rng.initialize(backend->create_tensor<float>(shape_x));
        auto y = rng.initialize(backend->create_tensor<float>(shape_y));
1072

1073
        EXPECT_TRUE(autodiff_numeric_compare<float>(backend, f, g, {x, y}, .01f, .01f));
1074 1075 1076
    }
}

1077
NGRAPH_TEST(${BACKEND_NAME}, backwards_reshape)
1078
{
1079
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
1080

1081
    test::Uniform<float> rng(-1.0f, 1.0f);
1082
    Shape shape{3, 4};
1083
    auto x0 = rng.initialize(backend->create_tensor<float>(shape));
1084 1085

    auto make_graph = [shape]() {
1086
        auto X0 = make_shared<op::Parameter>(element::f32, shape);
1087 1088 1089
        return make_shared<Function>(make_shared<op::Reshape>(X0, AxisVector{1, 0}, Shape{4, 3}),
                                     std::vector<std::shared_ptr<op::Parameter>>{X0});
    };
1090
    EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x0}, .01f, .01f));
Scott Cyphers's avatar
Scott Cyphers committed
1091 1092
}

1093
NGRAPH_TEST(${BACKEND_NAME}, backwards_select)
1094
{
1095
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
1096 1097

    test::Uniform<float> rng(-10.0f, 10.0f);
1098
    Shape shape{2, 3};
1099
    auto make_graph = [shape]() {
1100 1101 1102
        auto X0 = make_shared<op::Parameter>(element::boolean, shape);
        auto X1 = make_shared<op::Parameter>(element::f32, shape);
        auto X2 = make_shared<op::Parameter>(element::f32, shape);
1103 1104 1105 1106
        return make_shared<Function>(make_shared<op::Select>(X0, X1, X2),
                                     std::vector<std::shared_ptr<op::Parameter>>{X0, X1, X2});
    };

1107 1108
    auto f = make_graph();
    auto g = make_graph();
1109
    for (auto i = 0; i < ${TEST_LOOPS}; i++)
1110
    {
1111
        auto x0 = backend->create_tensor(element::boolean, shape);
1112
        write_vector(x0, vector<char>{0, 1, 0, 1, 0, 1});
1113 1114 1115 1116
        auto x1 = rng.initialize(backend->create_tensor<float>(shape));
        auto x2 = rng.initialize(backend->create_tensor<float>(shape));

        EXPECT_TRUE(autodiff_numeric_compare_selective<float>(
1117
            backend, f, g, {x0, x1, x2}, .01f, .01f, std::vector<bool>{false, true, true}));
1118 1119 1120
    }
}

1121
NGRAPH_TEST(${BACKEND_NAME}, backwards_select_nested)
1122
{
1123
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
1124 1125

    test::Uniform<float> rng(-10.0f, 10.0f);
1126
    Shape shape{2, 3};
1127
    auto make_graph = [shape]() {
1128 1129 1130
        auto X0 = make_shared<op::Parameter>(element::boolean, shape);
        auto X1 = make_shared<op::Parameter>(element::f32, shape);
        auto X2 = make_shared<op::Parameter>(element::f32, shape);
1131
        return make_shared<Function>(make_shared<op::Select>(X0, X2 + X1, X2 - X1),
1132 1133 1134
                                     std::vector<std::shared_ptr<op::Parameter>>{X0, X1, X2});
    };

1135 1136
    auto f = make_graph();
    auto g = make_graph();
1137
    for (auto i = 0; i < ${TEST_LOOPS}; i++)
1138
    {
1139
        auto x0 = backend->create_tensor(element::boolean, shape);
1140
        write_vector(x0, vector<char>{0, 1, 0, 1, 0, 1});
1141 1142 1143 1144
        auto x1 = rng.initialize(backend->create_tensor<float>(shape));
        auto x2 = rng.initialize(backend->create_tensor<float>(shape));

        EXPECT_TRUE(autodiff_numeric_compare_selective<float>(
1145
            backend, f, g, {x0, x1, x2}, .01f, .01f, std::vector<bool>{false, true, true}));
1146 1147 1148
    }
}

1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164
NGRAPH_TEST(${BACKEND_NAME}, backwards_sigmoid)
{
    auto backend = runtime::Backend::create("${BACKEND_NAME}");

    test::Uniform<float> rng_neg(-1.0f, -0.01f);
    test::Uniform<float> rng_pos(0.01f, 1.0f);
    Shape shape{2, 3};
    auto x0 = rng_neg.initialize(backend->create_tensor<float>(shape));
    auto x1 = rng_pos.initialize(backend->create_tensor<float>(shape));

    auto make_graph = [shape]() {
        auto X = make_shared<op::Parameter>(element::f32, shape);
        return make_shared<Function>(make_shared<op::Sigmoid>(X),
                                     std::vector<std::shared_ptr<op::Parameter>>{X});
    };

1165 1166
    auto f = make_graph();
    auto g = make_graph();
1167 1168 1169 1170
    for (auto i = 0; i < ${TEST_LOOPS}; i++)
    {
        auto x_neg = rng_neg.initialize(backend->create_tensor<float>(shape));

1171
        EXPECT_TRUE(autodiff_numeric_compare<float>(backend, f, g, {x_neg}, .01f, .01f));
1172 1173 1174

        auto x_pos = rng_pos.initialize(backend->create_tensor<float>(shape));

1175
        EXPECT_TRUE(autodiff_numeric_compare<float>(backend, f, g, {x_pos}, .01f, .01f));
1176 1177 1178
    }
}

1179
NGRAPH_TEST(${BACKEND_NAME}, backwards_sign)
1180
{
1181
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
1182 1183 1184 1185 1186

    // The numeric derivative and the symbolic one may disagree around 0, so we will dance around
    // that point by skipping (-0.01,0.01).
    test::Uniform<float> rng_neg(-1.0f, -0.01f);
    test::Uniform<float> rng_pos(0.01f, 1.0f);
1187
    Shape shape{2, 3};
1188 1189

    auto make_graph = [shape]() {
1190
        auto X = make_shared<op::Parameter>(element::f32, shape);
1191 1192
        return make_shared<Function>(make_shared<op::Sign>(X),
                                     std::vector<std::shared_ptr<op::Parameter>>{X});
1193 1194
    };

1195 1196
    auto f = make_graph();
    auto g = make_graph();
1197
    for (auto i = 0; i < ${TEST_LOOPS}; i++)
1198
    {
1199
        auto x_neg = rng_neg.initialize(backend->create_tensor<float>(shape));
1200

1201
        EXPECT_TRUE(autodiff_numeric_compare<float>(backend, f, g, {x_neg}, .01f, .01f));
1202

1203
        auto x_pos = rng_pos.initialize(backend->create_tensor<float>(shape));
1204

1205
        EXPECT_TRUE(autodiff_numeric_compare<float>(backend, f, g, {x_pos}, .01f, .01f));
1206 1207 1208
    }
}

1209
NGRAPH_TEST(${BACKEND_NAME}, backwards_sin)
1210
{
1211
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
1212 1213

    test::Uniform<float> rng(-10.0f, 10.0f);
1214
    Shape shape{2, 3};
1215
    auto make_graph = [shape]() {
1216
        auto X = make_shared<op::Parameter>(element::f32, shape);
1217 1218
        return make_shared<Function>(make_shared<op::Sin>(X),
                                     std::vector<std::shared_ptr<op::Parameter>>{X});
1219 1220
    };

1221 1222
    auto f = make_graph();
    auto g = make_graph();
1223
    for (auto i = 0; i < ${TEST_LOOPS}; i++)
1224
    {
1225
        auto x = rng.initialize(backend->create_tensor<float>(shape));
1226

1227
        EXPECT_TRUE(autodiff_numeric_compare<float>(backend, f, g, {x}, .01f, .01f));
1228 1229 1230
    }
}

1231
NGRAPH_TEST(${BACKEND_NAME}, backwards_sinh)
1232
{
1233
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
1234 1235

    test::Uniform<float> rng(-10.0f, 10.0f);
1236
    Shape shape{2, 3};
1237
    auto make_graph = [shape]() {
1238
        auto X = make_shared<op::Parameter>(element::f32, shape);
1239 1240
        return make_shared<Function>(make_shared<op::Sinh>(X),
                                     std::vector<std::shared_ptr<op::Parameter>>{X});
1241 1242
    };

1243 1244
    auto f = make_graph();
    auto g = make_graph();
1245
    for (auto i = 0; i < ${TEST_LOOPS}; i++)
1246
    {
1247
        auto x = rng.initialize(backend->create_tensor<float>(shape));
1248

1249
        EXPECT_TRUE(autodiff_numeric_compare<float>(backend, f, g, {x}, .01f, .01f));
1250 1251 1252
    }
}

1253
NGRAPH_TEST(${BACKEND_NAME}, backwards_slice)
1254
{
1255
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
1256
    test::Uniform<float> rng(-10.0f, 10.0f);
1257
    Shape shape{5, 5};
1258
    auto make_graph = [shape]() {
1259
        auto X = make_shared<op::Parameter>(element::f32, shape);
1260 1261 1262 1263
        return make_shared<Function>(make_shared<op::Slice>(X, Coordinate{2, 3}, Coordinate{4, 5}),
                                     std::vector<std::shared_ptr<op::Parameter>>{X});
    };

1264 1265
    auto f = make_graph();
    auto g = make_graph();
1266
    for (auto i = 0; i < ${TEST_LOOPS}; i++)
1267
    {
1268
        auto x = rng.initialize(backend->create_tensor<float>(shape));
1269

1270
        EXPECT_TRUE(autodiff_numeric_compare<float>(backend, f, g, {x}, .01f, .01f));
1271 1272 1273
    }
}

1274
NGRAPH_TEST(${BACKEND_NAME}, backwards_softmax_all)
1275
{
1276
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
1277

adstraw's avatar
adstraw committed
1278
    test::Uniform<float> rng(-1.0f, 1.0f);
1279
    Shape shape{2, 3};
1280
    auto x0 = rng.initialize(backend->create_tensor<float>(shape));
adstraw's avatar
adstraw committed
1281

1282
    auto make_graph = [shape]() {
adstraw's avatar
adstraw committed
1283 1284 1285
        auto X0 = make_shared<op::Parameter>(element::f32, shape);
        return make_shared<Function>(make_shared<op::Softmax>(X0, AxisSet{0, 1}),
                                     std::vector<std::shared_ptr<op::Parameter>>{X0});
1286
    };
1287
    EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x0}, .01f, .01f));
adstraw's avatar
adstraw committed
1288
}
1289

1290
NGRAPH_TEST(${BACKEND_NAME}, backwards_softmax_axis)
adstraw's avatar
adstraw committed
1291
{
1292
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
1293

adstraw's avatar
adstraw committed
1294 1295
    test::Uniform<float> rng(-1.0f, 1.0f);
    Shape shape{2, 3};
1296
    auto x0 = rng.initialize(backend->create_tensor<float>(shape));
adstraw's avatar
adstraw committed
1297 1298 1299 1300 1301 1302

    auto make_graph = [shape]() {
        auto X0 = make_shared<op::Parameter>(element::f32, shape);
        return make_shared<Function>(make_shared<op::Softmax>(X0, AxisSet{1}),
                                     std::vector<std::shared_ptr<op::Parameter>>{X0});
    };
1303
    EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x0}, .01f, .01f));
adstraw's avatar
adstraw committed
1304 1305
}

1306
NGRAPH_TEST(${BACKEND_NAME}, backwards_softmax_underflow)
adstraw's avatar
adstraw committed
1307
{
1308
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
adstraw's avatar
adstraw committed
1309 1310 1311 1312

    auto low = std::numeric_limits<float>::lowest();

    Shape shape{2, 3};
1313
    auto x0 = backend->create_tensor(element::f32, shape);
adstraw's avatar
adstraw committed
1314 1315 1316 1317 1318 1319 1320
    copy_data(x0, vector<float>{low, 1, 2, 3, 4, 5});

    auto make_graph = [shape]() {
        auto X0 = make_shared<op::Parameter>(element::f32, shape);
        return make_shared<Function>(make_shared<op::Softmax>(X0, AxisSet{0, 1}),
                                     std::vector<std::shared_ptr<op::Parameter>>{X0});
    };
1321
    EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x0}, .01f, .01f));
adstraw's avatar
adstraw committed
1322 1323
}

1324
NGRAPH_TEST(${BACKEND_NAME}, backwards_softmax_3d)
adstraw's avatar
adstraw committed
1325
{
1326
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
adstraw's avatar
adstraw committed
1327 1328 1329

    test::Uniform<float> rng(-1.0f, 1.0f);
    Shape shape{2, 3, 4};
1330
    auto x0 = rng.initialize(backend->create_tensor<float>(shape));
adstraw's avatar
adstraw committed
1331 1332 1333 1334 1335 1336

    auto make_graph0 = [shape]() {
        auto X0 = make_shared<op::Parameter>(element::f32, shape);
        return make_shared<Function>(make_shared<op::Softmax>(X0, AxisSet{0}),
                                     std::vector<std::shared_ptr<op::Parameter>>{X0});
    };
1337
    EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph0, {x0}, .01f, .01f));
adstraw's avatar
adstraw committed
1338 1339 1340 1341 1342 1343

    auto make_graph1 = [shape]() {
        auto X0 = make_shared<op::Parameter>(element::f32, shape);
        return make_shared<Function>(make_shared<op::Softmax>(X0, AxisSet{1}),
                                     std::vector<std::shared_ptr<op::Parameter>>{X0});
    };
1344
    EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph1, {x0}, .01f, .01f));
adstraw's avatar
adstraw committed
1345 1346 1347 1348 1349 1350

    auto make_graph2 = [shape]() {
        auto X0 = make_shared<op::Parameter>(element::f32, shape);
        return make_shared<Function>(make_shared<op::Softmax>(X0, AxisSet{2}),
                                     std::vector<std::shared_ptr<op::Parameter>>{X0});
    };
1351
    EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph2, {x0}, .01f, .01f));
adstraw's avatar
adstraw committed
1352 1353 1354 1355 1356 1357

    auto make_graph01 = [shape]() {
        auto X0 = make_shared<op::Parameter>(element::f32, shape);
        return make_shared<Function>(make_shared<op::Softmax>(X0, AxisSet{0, 1}),
                                     std::vector<std::shared_ptr<op::Parameter>>{X0});
    };
1358
    EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph01, {x0}, .01f, .01f));
adstraw's avatar
adstraw committed
1359 1360 1361 1362 1363 1364

    auto make_graph02 = [shape]() {
        auto X0 = make_shared<op::Parameter>(element::f32, shape);
        return make_shared<Function>(make_shared<op::Softmax>(X0, AxisSet{0, 2}),
                                     std::vector<std::shared_ptr<op::Parameter>>{X0});
    };
1365
    EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph02, {x0}, .01f, .01f));
adstraw's avatar
adstraw committed
1366 1367 1368 1369 1370 1371

    auto make_graph12 = [shape]() {
        auto X0 = make_shared<op::Parameter>(element::f32, shape);
        return make_shared<Function>(make_shared<op::Softmax>(X0, AxisSet{1, 2}),
                                     std::vector<std::shared_ptr<op::Parameter>>{X0});
    };
1372
    EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph12, {x0}, .01f, .01f));
adstraw's avatar
adstraw committed
1373 1374 1375 1376 1377 1378

    auto make_graph012 = [shape]() {
        auto X0 = make_shared<op::Parameter>(element::f32, shape);
        return make_shared<Function>(make_shared<op::Softmax>(X0, AxisSet{0, 1, 2}),
                                     std::vector<std::shared_ptr<op::Parameter>>{X0});
    };
1379
    EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph012, {x0}, .01f, .01f));
1380 1381
}

1382
NGRAPH_TEST(${BACKEND_NAME}, backwards_subtract)
Scott Cyphers's avatar
Scott Cyphers committed
1383
{
1384
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
Scott Cyphers's avatar
Scott Cyphers committed
1385

1386
    test::Uniform<float> rng(-1.0f, 1.0f);
1387
    Shape shape{2, 3};
1388 1389
    auto x0 = rng.initialize(backend->create_tensor<float>(shape));
    auto x1 = rng.initialize(backend->create_tensor<float>(shape));
Scott Cyphers's avatar
Scott Cyphers committed
1390 1391

    auto make_graph = [shape]() {
1392 1393
        auto X0 = make_shared<op::Parameter>(element::f32, shape);
        auto X1 = make_shared<op::Parameter>(element::f32, shape);
1394
        return make_shared<Function>(X0 - X1, std::vector<std::shared_ptr<op::Parameter>>{X0, X1});
Scott Cyphers's avatar
Scott Cyphers committed
1395
    };
1396
    EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x0, x1}, .01f, .01f));
Scott Cyphers's avatar
Scott Cyphers committed
1397
}
Scott Cyphers's avatar
Scott Cyphers committed
1398

1399
NGRAPH_TEST(${BACKEND_NAME}, backwards_sum_v2s)
1400
{
1401
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
1402 1403

    test::Uniform<float> rng(-1.0f, 1.0f);
1404
    Shape shape{8};
1405
    auto x = rng.initialize(backend->create_tensor<float>(shape));
1406 1407

    auto make_graph = [shape]() {
1408
        auto X = make_shared<op::Parameter>(element::f32, shape);
1409 1410 1411
        return make_shared<Function>(make_shared<op::Sum>(X, AxisSet{0}),
                                     std::vector<std::shared_ptr<op::Parameter>>{X});
    };
1412
    EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x}, .01f, .01f));
1413 1414
}

1415
NGRAPH_TEST(${BACKEND_NAME}, backwards_sum_m2s)
1416
{
1417
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
1418 1419

    test::Uniform<float> rng(-1.0f, 1.0f);
1420
    Shape shape{8, 9};
1421
    auto x = rng.initialize(backend->create_tensor<float>(shape));
1422 1423

    auto make_graph = [shape]() {
1424
        auto X = make_shared<op::Parameter>(element::f32, shape);
1425 1426 1427
        return make_shared<Function>(make_shared<op::Sum>(X, AxisSet{0, 1}),
                                     std::vector<std::shared_ptr<op::Parameter>>{X});
    };
1428
    EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x}, .01f, .01f));
1429 1430
}

1431
NGRAPH_TEST(${BACKEND_NAME}, backwards_sum_m2v_0)
1432
{
1433
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
1434 1435

    test::Uniform<float> rng(-1.0f, 1.0f);
1436
    Shape shape{8, 9};
1437
    auto x = rng.initialize(backend->create_tensor<float>(shape));
1438 1439

    auto make_graph = [shape]() {
1440
        auto X = make_shared<op::Parameter>(element::f32, shape);
1441 1442 1443
        return make_shared<Function>(make_shared<op::Sum>(X, AxisSet{0}),
                                     std::vector<std::shared_ptr<op::Parameter>>{X});
    };
1444
    EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x}, .01f, .01f));
1445 1446
}

1447
NGRAPH_TEST(${BACKEND_NAME}, backwards_sum_m2v_1)
1448
{
1449
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
1450 1451

    test::Uniform<float> rng(-1.0f, 1.0f);
1452
    Shape shape{8, 9};
1453
    auto x = rng.initialize(backend->create_tensor<float>(shape));
1454 1455

    auto make_graph = [shape]() {
1456
        auto X = make_shared<op::Parameter>(element::f32, shape);
1457 1458 1459
        return make_shared<Function>(make_shared<op::Sum>(X, AxisSet{1}),
                                     std::vector<std::shared_ptr<op::Parameter>>{X});
    };
1460
    EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x}, .01f, .01f));
1461 1462
}

1463
NGRAPH_TEST(${BACKEND_NAME}, backwards_tan)
1464
{
1465
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
1466 1467 1468 1469

    auto pi = 3.14159f;

    // Stay away from the asymptotes at 6 and 12 o'clock.
1470
    auto slop = 0.2f;
1471 1472 1473
    test::Uniform<float> rng_r(-pi / 2 + slop, pi / 2 - slop);
    test::Uniform<float> rng_l(pi / 2 + slop, (3 * pi) / 2 - slop);

1474
    Shape shape{2, 3};
1475 1476

    auto make_graph = [shape]() {
1477
        auto X = make_shared<op::Parameter>(element::f32, shape);
1478 1479
        return make_shared<Function>(make_shared<op::Tan>(X),
                                     std::vector<std::shared_ptr<op::Parameter>>{X});
1480 1481
    };

1482 1483
    auto f = make_graph();
    auto g = make_graph();
1484
    for (auto i = 0; i < ${TEST_LOOPS}; i++)
1485
    {
1486
        auto x_r = rng_r.initialize(backend->create_tensor<float>(shape));
1487

1488
        EXPECT_TRUE(autodiff_numeric_compare<float>(backend, f, g, {x_r}, .01f, .01f));
1489

1490
        auto x_l = rng_l.initialize(backend->create_tensor<float>(shape));
1491

1492
        EXPECT_TRUE(autodiff_numeric_compare<float>(backend, f, g, {x_l}, .01f, .01f));
1493 1494 1495
    }
}

1496
NGRAPH_TEST(${BACKEND_NAME}, backwards_tanh)
1497
{
1498
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
1499 1500

    test::Uniform<float> rng(-10.0f, 10.0f);
1501
    Shape shape{2, 3};
1502
    auto make_graph = [shape]() {
1503
        auto X = make_shared<op::Parameter>(element::f32, shape);
1504 1505
        return make_shared<Function>(make_shared<op::Tanh>(X),
                                     std::vector<std::shared_ptr<op::Parameter>>{X});
1506 1507
    };

1508 1509
    auto f = make_graph();
    auto g = make_graph();
1510
    for (auto i = 0; i < ${TEST_LOOPS}; i++)
1511
    {
1512
        auto x = rng.initialize(backend->create_tensor<float>(shape));
1513

1514
        EXPECT_TRUE(autodiff_numeric_compare<float>(backend, f, g, {x}, .01f, .01f));
1515 1516 1517
    }
}

1518
NGRAPH_TEST(${BACKEND_NAME}, backwards_abc)
Scott Cyphers's avatar
Scott Cyphers committed
1519
{
1520
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
Scott Cyphers's avatar
Scott Cyphers committed
1521

1522
    test::Uniform<float> rng(-1.0f, 1.0f);
1523
    Shape shape{2, 3};
1524 1525 1526
    auto x0 = rng.initialize(backend->create_tensor<float>(shape));
    auto x1 = rng.initialize(backend->create_tensor<float>(shape));
    auto x2 = rng.initialize(backend->create_tensor<float>(shape));
Scott Cyphers's avatar
Scott Cyphers committed
1527 1528

    auto make_graph = [shape]() {
1529 1530 1531
        auto X0 = make_shared<op::Parameter>(element::f32, shape);
        auto X1 = make_shared<op::Parameter>(element::f32, shape);
        auto X2 = make_shared<op::Parameter>(element::f32, shape);
1532 1533
        return make_shared<Function>((X0 + X1) * X2,
                                     std::vector<std::shared_ptr<op::Parameter>>{X0, X1, X2});
Scott Cyphers's avatar
Scott Cyphers committed
1534
    };
1535

1536
    EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x0, x1, x2}, .01f, .01f));
Scott Cyphers's avatar
Scott Cyphers committed
1537
}
1538

1539
NGRAPH_TEST(${BACKEND_NAME}, backwards_reverse_3d_02)
1540
{
1541
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
1542 1543

    test::Uniform<float> rng(-1.0f, 1.0f);
1544
    Shape shape{2, 4, 5};
1545
    auto x = rng.initialize(backend->create_tensor(element::f32, shape));
1546 1547 1548 1549 1550 1551

    auto make_graph = [shape]() {
        auto X = make_shared<op::Parameter>(element::f32, shape);
        return make_shared<Function>(make_shared<op::Reverse>(X, AxisSet{0, 2}),
                                     std::vector<std::shared_ptr<op::Parameter>>{X});
    };
1552
    EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x}, .01f, .01f));
1553
}
1554

1555
NGRAPH_TEST(${BACKEND_NAME}, backwards_maxpool_n4c1h4w4_kh2kw2_sh1sw1)
1556
{
1557
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
1558
    Shape shape_a{4, 1, 4, 4}; // in NCHW
1559 1560 1561 1562 1563
    Shape maxpool_shape{4, 1, 3, 3};

    auto A = make_shared<op::Parameter>(element::f32, shape_a);
    Shape window_shape{2, 2};
    auto window_movement_strides = Strides{1, 1};
1564
    auto maxpool = make_shared<op::MaxPool>(A, window_shape, window_movement_strides);
1565
    auto f = make_shared<Function>(maxpool, op::ParameterVector{A});
1566
    shared_ptr<runtime::TensorView> ep = backend->create_tensor(element::f32, maxpool_shape);
1567 1568
    vector<float> dataEp(shape_size(maxpool_shape), 4);

1569 1570
    shared_ptr<runtime::TensorView> input = backend->create_tensor(element::f32, shape_a);
    shared_ptr<runtime::TensorView> output = backend->create_tensor(element::f32, shape_a);
1571 1572

    vector<float> dataInput{11, 65, 44, 28, 31, 33, 21, 66, 40, 49, 69, 57, 47, 30, 24, 27,
pthoreho's avatar
pthoreho committed
1573 1574 1575
                            13, 56, 46, 60, 61, 41, 25, 42, 48, 53, 51, 43, 59, 58, 29, 71,
                            17, 22, 72, 18, 39, 35, 15, 38, 64, 52, 73, 67, 62, 50, 10, 68,
                            45, 63, 16, 14, 55, 54, 37, 20, 36, 12, 70, 34, 19, 26, 32, 23};
1576

1577
    vector<float> expected{// delta
1578 1579 1580
                           0, 8, 0, 0, 0, 0, 0, 4, 0, 8, 16, 0, 0, 0, 0,  0, 0, 4, 0, 4, 8,  0,
                           0, 0, 0, 4, 4, 0, 4, 4, 0, 4, 0,  0, 8, 0, 4,  0, 0, 0, 8, 0, 16, 0,
                           0, 0, 0, 0, 0, 8, 0, 0, 4, 0, 4,  0, 4, 0, 16, 0, 0, 0, 0, 0};
1581 1582 1583 1584 1585 1586

    copy_data(ep, dataEp);
    copy_data(input, dataInput);

    auto C = make_shared<op::Parameter>(element::f32, maxpool_shape);
    auto df = autodiff::backprop_function(f);
1587
    backend->call_with_validate(df, {output}, {input, ep});
1588 1589 1590
    ASSERT_TRUE(read_vector<float>(output) == expected);
}

1591
NGRAPH_TEST(${BACKEND_NAME}, backwards_maxpool_n2c1h5w5_kh3kw3_sh2sw2)
1592
{
1593
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
1594

1595
    Shape shape_a{1, 2, 5, 5}; // in NCHW
1596 1597 1598 1599 1600
    Shape maxpool_shape{1, 2, 2, 2};

    auto A = make_shared<op::Parameter>(element::f32, shape_a);
    Shape window_shape{3, 3};
    auto window_movement_strides = Strides{2, 2};
1601
    auto maxpool = make_shared<op::MaxPool>(A, window_shape, window_movement_strides);
1602
    auto f = make_shared<Function>(maxpool, op::ParameterVector{A});
1603

1604
    shared_ptr<runtime::TensorView> ep = backend->create_tensor(element::f32, maxpool_shape);
1605 1606
    vector<float> dataEp(shape_size(maxpool_shape), 4);

1607 1608
    shared_ptr<runtime::TensorView> input = backend->create_tensor(element::f32, shape_a);
    shared_ptr<runtime::TensorView> output = backend->create_tensor(element::f32, shape_a);
1609 1610

    vector<float> dataInput{58, 15, 51, 35, 18, 47, 31, 32, 52, 21, 36, 38, 57, 54, 25, 45, 23,
pthoreho's avatar
pthoreho committed
1611 1612
                            30, 16, 27, 48, 20, 41, 37, 43, 39, 22, 28, 33, 29, 12, 17, 44, 42,
                            19, 40, 10, 46, 34, 53, 26, 55, 50, 13, 24, 14, 49, 56, 59, 11};
1613

1614
    vector<float> expected{// delta
1615 1616 1617
                           4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0,
                           0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0,
                           0, 0, 0, 4, 0, 4, 0, 0, 0, 0, 0, 0, 0,  4, 4, 0};
1618 1619 1620 1621 1622 1623

    copy_data(ep, dataEp);
    copy_data(input, dataInput);

    auto C = make_shared<op::Parameter>(element::f32, maxpool_shape);
    auto df = autodiff::backprop_function(f);
1624
    backend->call_with_validate(df, {output}, {input, ep});
1625
    ASSERT_TRUE(read_vector<float>(output) == expected);
1626
}
1627

1628 1629 1630 1631 1632
NGRAPH_TEST(${BACKEND_NAME}, backwards_batch_norm_three_outputs)
{
    auto shape_in = Shape{2, 3, 1, 1};
    auto shape_mean = Shape{3};

1633 1634 1635
    // we need to keep GOEs for mean and variance alive
    // even though those aren't used as outputs for fprop
    // they are needed for a bprop pass
1636 1637 1638
    NodeVector goes;

    auto make_graph = [&goes, shape_in, shape_mean] {
1639 1640 1641 1642 1643
        auto A = make_shared<op::Parameter>(element::f64, shape_in);
        auto B = make_shared<op::Parameter>(element::f64, shape_mean);
        auto C = make_shared<op::Parameter>(element::f64, shape_mean);

        auto BN = make_shared<op::BatchNorm>(1e-3, B, C, A);
1644
        // make sure we create GOEs for mean and variance needed for bprop
1645 1646
        goes.push_back(make_shared<op::GetOutputElement>(BN, 1));
        goes.push_back(make_shared<op::GetOutputElement>(BN, 2));
1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661

        auto f = make_shared<Function>(make_shared<op::GetOutputElement>(BN, 0),
                                       op::ParameterVector{A, B, C});
        return f;
    };

    auto backend = runtime::Backend::create("${BACKEND_NAME}");
    test::Uniform<double> rng(-1.0, 1.0);
    auto x0 = rng.initialize(backend->create_tensor<double>(shape_in));
    auto x1 = rng.initialize(backend->create_tensor<double>(shape_mean));
    auto x2 = rng.initialize(backend->create_tensor<double>(shape_mean));

    EXPECT_TRUE(autodiff_numeric_compare<double>(backend, make_graph, {x0, x1, x2}, .01, .01));
}

1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682
NGRAPH_TEST(${BACKEND_NAME}, backwards_reverse_sequence_n3_c2_h3)
{
    auto backend = runtime::Backend::create("${BACKEND_NAME}");

    Shape shape{3, 2, 3};
    auto A = make_shared<op::Parameter>(element::i32, shape);
    Shape seq_len_shape{2};
    auto B = make_shared<op::Parameter>(element::i32, seq_len_shape);

    size_t batch_axis = 1;
    size_t sequence_axis = 0;

    auto rs = std::make_shared<op::ReverseSequence>(A, B, batch_axis, sequence_axis);
    auto f = make_shared<Function>(rs, op::ParameterVector{A, B});

    shared_ptr<runtime::TensorView> a = backend->create_tensor(element::i32, shape);
    shared_ptr<runtime::TensorView> b = backend->create_tensor(element::i32, seq_len_shape);
    shared_ptr<runtime::TensorView> c = backend->create_tensor(element::i32, shape);
    shared_ptr<runtime::TensorView> da = backend->create_tensor(element::i32, shape);
    shared_ptr<runtime::TensorView> db = backend->create_tensor(element::i32, seq_len_shape);

1683
    // input values don't matter
1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696
    vector<int> va(shape_size(shape), 0);

    vector<int> vc{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18};
    vector<int> expected{13, 14, 15, 16, 17, 18, 7, 8, 9, 10, 11, 12, 1, 2, 3, 4, 5, 6};

    copy_data(c, vc);
    copy_data(a, va);

    std::vector<int> seq_lenghts{3, 3};
    copy_data(b, seq_lenghts);

    auto C = make_shared<op::Parameter>(element::i32, shape);
    auto df = autodiff::backprop_function(f);
1697
    backend->call_with_validate(df, {da, db}, {a, b, c});
1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721
    ASSERT_EQ(read_vector<int>(da), expected);
}

NGRAPH_TEST(${BACKEND_NAME}, backwards_reverse_sequence_n4d2c3h2w2)
{
    auto backend = runtime::Backend::create("${BACKEND_NAME}");

    Shape shape{4, 2, 3, 2, 2};
    auto A = make_shared<op::Parameter>(element::i32, shape);
    Shape seq_len_shape{4};
    auto B = make_shared<op::Parameter>(element::i32, seq_len_shape);

    size_t batch_axis = 0;
    size_t sequence_axis = 2;

    auto rs = std::make_shared<op::ReverseSequence>(A, B, batch_axis, sequence_axis);
    auto f = make_shared<Function>(rs, op::ParameterVector{A, B});

    shared_ptr<runtime::TensorView> a = backend->create_tensor(element::i32, shape);
    shared_ptr<runtime::TensorView> b = backend->create_tensor(element::i32, seq_len_shape);
    shared_ptr<runtime::TensorView> c = backend->create_tensor(element::i32, shape);
    shared_ptr<runtime::TensorView> da = backend->create_tensor(element::i32, shape);
    shared_ptr<runtime::TensorView> db = backend->create_tensor(element::i32, seq_len_shape);

1722
    // input values don't matter
1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746
    vector<int> va(shape_size(shape), 0);

    std::vector<int> vc{0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  10, 11, 12, 13, 14, 15,
                        16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
                        32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
                        48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
                        64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
                        80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95};

    std::vector<int> expected{0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  10, 11, 12, 13, 14, 15,
                              16, 17, 18, 19, 20, 21, 22, 23, 28, 29, 30, 31, 24, 25, 26, 27,
                              32, 33, 34, 35, 40, 41, 42, 43, 36, 37, 38, 39, 44, 45, 46, 47,
                              48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
                              64, 65, 66, 67, 68, 69, 70, 71, 76, 77, 78, 79, 72, 73, 74, 75,
                              80, 81, 82, 83, 88, 89, 90, 91, 84, 85, 86, 87, 92, 93, 94, 95};

    copy_data(c, vc);
    copy_data(a, va);

    std::vector<int> seq_lenghts{1, 2, 1, 2};
    copy_data(b, seq_lenghts);

    auto C = make_shared<op::Parameter>(element::i32, shape);
    auto df = autodiff::backprop_function(f);
1747
    backend->call_with_validate(df, {da, db}, {a, b, c});
1748 1749
    ASSERT_EQ(read_vector<int>(da), expected);
}