autodiff.in.cpp 63.8 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 41
    Shape shape_a{1, 4, 4, 4}; //in CHWN
    Shape maxpool_shape{1, 4, 3, 3};
42 43 44 45

    auto A = make_shared<op::Parameter>(element::i32, shape_a);
    auto reshape = make_shared<op::Reshape>(
        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 62 63 64 65 66 67 68 69 70 71

    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};

    vector<int> expected{//delta
                         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(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 81
    Shape shape_a{1, 5, 5, 2}; //in CHWN
    Shape maxpool_shape{1, 2, 2, 2};
82 83 84 85

    auto A = make_shared<op::Parameter>(element::i32, shape_a);
    auto reshape = make_shared<op::Reshape>(
        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 101 102 103 104 105 106 107 108 109

    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};

    vector<int> expected{//delta
                         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(df, {output}, {input, ep});
111
    ASSERT_TRUE(read_vector<int>(output) == expected);
112 113
}

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

118
    Shape padding{1, 1};
119

120 121
    Shape shape_a{1, 1, 2, 2};
    Shape avgpool_shape{1, 1, 2, 2};
122 123

    auto A = make_shared<op::Parameter>(element::i32, shape_a);
124
    Shape window_shape{2, 2};
125 126
    auto window_movement_strides = Strides{2, 2};
    auto avgpool =
127
        make_shared<op::AvgPool>(A, window_shape, window_movement_strides, padding, padding, false);
128
    auto f = make_shared<Function>(avgpool, op::ParameterVector{A});
129

130
    shared_ptr<runtime::TensorView> ep = backend->create_tensor(element::i32, avgpool_shape);
131 132
    vector<int> dataEp(shape_size(avgpool_shape), 4);

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

135
    shared_ptr<runtime::TensorView> output = backend->create_tensor(element::i32, shape_a);
136 137 138 139 140 141 142 143 144 145

    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);
146
    backend->call(df, {output}, {input, ep});
147 148 149
    ASSERT_TRUE(read_vector<int>(output) == dataEp);
}

150
NGRAPH_TEST(${BACKEND_NAME}, backwards_avgpool_n1_c1_hw4x4)
151
{
152
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
153

154 155
    Shape shape_a{1, 1, 4, 4};
    Shape avgpool_shape{1, 1, 3, 3};
156 157

    auto A = make_shared<op::Parameter>(element::i32, shape_a);
158
    Shape window_shape{2, 2};
159 160
    auto window_movement_strides = Strides{1, 1};
    auto avgpool = make_shared<op::AvgPool>(A, window_shape, window_movement_strides);
161
    auto f = make_shared<Function>(avgpool, op::ParameterVector{A});
162

163
    shared_ptr<runtime::TensorView> ep = backend->create_tensor(element::i32, avgpool_shape);
164 165
    vector<int> dataEp(shape_size(avgpool_shape), 4);

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

168
    shared_ptr<runtime::TensorView> output = backend->create_tensor(element::i32, shape_a);
169 170 171 172 173 174 175 176 177 178

    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);
179
    backend->call(df, {output}, {input, ep});
180 181 182
    ASSERT_TRUE(read_vector<int>(output) == expected);
}

183
NGRAPH_TEST(${BACKEND_NAME}, backwards_avgpool_n2_c2_hw4x4)
184
{
185
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
186

187 188
    Shape shape_a{2, 2, 4, 4};
    Shape avgpool_shape{2, 2, 2, 2};
189 190

    auto A = make_shared<op::Parameter>(element::i32, shape_a);
191
    Shape window_shape{2, 2};
192 193
    auto window_movement_strides = Strides{2, 2};
    auto avgpool = make_shared<op::AvgPool>(A, window_shape, window_movement_strides);
194
    auto f = make_shared<Function>(avgpool, op::ParameterVector{A});
195

196
    shared_ptr<runtime::TensorView> ep = backend->create_tensor(element::i32, avgpool_shape);
197 198
    vector<int> dataEp(shape_size(avgpool_shape), 12);

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

201
    shared_ptr<runtime::TensorView> output = backend->create_tensor(element::i32, shape_a);
202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277

    vector<int> dataInput{//i1c1
                          1,
                          2,
                          6,
                          7,
                          3,
                          4,
                          4,
                          3,
                          19,
                          1,
                          2,
                          3,
                          18,
                          2,
                          3,
                          2,
                          //i1c2
                          4,
                          1,
                          5,
                          5,
                          1,
                          4,
                          5,
                          5,
                          12,
                          8,
                          2,
                          3,
                          15,
                          5,
                          3,
                          2,
                          //i2c1
                          2,
                          3,
                          7,
                          7,
                          3,
                          2,
                          3,
                          3,
                          13,
                          7,
                          1,
                          2,
                          7,
                          13,
                          3,
                          4,
                          //i2c2
                          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);
278
    backend->call(df, {output}, {input, ep});
279 280 281
    ASSERT_TRUE(read_vector<int>(output) == expected);
}

282
NGRAPH_TEST(${BACKEND_NAME}, backwards_avgpool_n2_c2_hw4x4_numeric)
283
{
284
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
285
    Shape shape_a{2, 2, 4, 4};
286 287 288 289
    test::Uniform<float> rng(1.0f, 10.0f);

    auto make_graph = [shape_a]() {
        auto A = make_shared<op::Parameter>(element::f32, shape_a);
290
        Shape window_shape{2, 2};
291 292
        auto window_movement_strides = Strides{2, 2};
        auto avgpool = make_shared<op::AvgPool>(A, window_shape, window_movement_strides);
293
        return make_shared<Function>(avgpool, op::ParameterVector{A});
294 295 296

    };

297
    for (auto i = 0; i < ${TEST_LOOPS}; i++)
298
    {
299 300
        auto x = rng.initialize(backend->create_tensor(element::f32, shape_a));
        EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x}, .01f, .01f));
301 302 303
    }
}

304
NGRAPH_TEST(${BACKEND_NAME}, backwards_avgpool_n2_c2_hw4x4_win_2x2_str_1x1_numeric)
305
{
306
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
307
    Shape shape_a{2, 2, 4, 4};
308 309 310 311
    test::Uniform<float> rng(1.0f, 10.0f);

    auto make_graph = [shape_a]() {
        auto A = make_shared<op::Parameter>(element::f32, shape_a);
312
        Shape window_shape{2, 2};
313 314
        auto window_movement_strides = Strides{1, 1};
        auto avgpool = make_shared<op::AvgPool>(A, window_shape, window_movement_strides);
315
        return make_shared<Function>(avgpool, op::ParameterVector{A});
316 317 318

    };

319
    for (auto i = 0; i < ${TEST_LOOPS}; i++)
320
    {
321 322
        auto x = rng.initialize(backend->create_tensor(element::f32, shape_a));
        EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x}, .01f, .01f));
323 324 325
    }
}

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

    auto make_graph = [shape_a]() {
        auto A = make_shared<op::Parameter>(element::f32, shape_a);
334 335
        Shape window_shape{2, 2};
        Shape padding{1, 1};
336
        auto window_movement_strides = Strides{2, 2};
337 338
        auto avgpool = make_shared<op::AvgPool>(
            A, window_shape, window_movement_strides, padding, padding, false);
339
        return make_shared<Function>(avgpool, op::ParameterVector{A});
340 341 342

    };

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

350
NGRAPH_TEST(${BACKEND_NAME}, backwards_abs)
351
{
352
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
353 354 355 356 357

    // 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);
358
    Shape shape{2, 3};
359 360

    auto make_graph = [shape]() {
361
        auto X = make_shared<op::Parameter>(element::f32, shape);
362 363
        return make_shared<Function>(make_shared<op::Abs>(X),
                                     std::vector<std::shared_ptr<op::Parameter>>{X});
364 365
    };

366
    for (auto i = 0; i < ${TEST_LOOPS}; i++)
367
    {
368
        auto x_neg = rng_neg.initialize(backend->create_tensor<float>(shape));
369

370
        EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x_neg}, .01f, .01f));
371

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

374
        EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x_pos}, .01f, .01f));
375
    }
376 377
}

378
NGRAPH_TEST(${BACKEND_NAME}, backwards_acos)
379 380 381 382 383 384 385 386 387 388 389 390 391 392 393
{
    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));
}

394
NGRAPH_TEST(${BACKEND_NAME}, backwards_add)
395
{
396
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
397

398
    test::Uniform<float> rng(-1.0f, 1.0f);
399
    Shape shape{2, 3};
400 401
    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
402

403
    auto make_graph = [shape]() {
404 405
        auto X0 = make_shared<op::Parameter>(element::f32, shape);
        auto X1 = make_shared<op::Parameter>(element::f32, shape);
406
        return make_shared<Function>(X0 + X1, std::vector<std::shared_ptr<op::Parameter>>{X0, X1});
407
    };
408
    EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x0, x1}, .01f, .01f));
409 410
}

411
NGRAPH_TEST(${BACKEND_NAME}, backwards_add_nested)
412
{
413
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
414

415
    test::Uniform<float> rng(-1.0f, 1.0f);
416
    Shape shape{2, 3};
417 418
    auto x0 = rng.initialize(backend->create_tensor<float>(shape));
    auto x1 = rng.initialize(backend->create_tensor<float>(shape));
419 420

    auto make_graph = [shape]() {
421 422
        auto X0 = make_shared<op::Parameter>(element::f32, shape);
        auto X1 = make_shared<op::Parameter>(element::f32, shape);
423 424
        return make_shared<Function>((X0 + X1) + (X1 + X0),
                                     std::vector<std::shared_ptr<op::Parameter>>{X0, X1});
425
    };
426
    EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x0, x1}, .01f, .01f));
427 428
}

429
NGRAPH_TEST(${BACKEND_NAME}, backwards_asin)
430 431 432 433 434 435 436 437 438 439 440 441 442 443 444
{
    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));
}

445
NGRAPH_TEST(${BACKEND_NAME}, backwards_atan)
446 447 448 449 450 451 452 453 454 455 456 457 458 459 460
{
    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));
}

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

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

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

477
NGRAPH_TEST(${BACKEND_NAME}, backwards_broadcast1)
478
{
479
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
480

481
    test::Uniform<float> rng(-1.0f, 1.0f);
482
    Shape shape{3};
483
    auto x0 = rng.initialize(backend->create_tensor<float>(shape));
484 485

    auto make_graph = [shape]() {
486
        auto X0 = make_shared<op::Parameter>(element::f32, shape);
487 488 489
        return make_shared<Function>(make_shared<op::Broadcast>(X0, Shape{3, 2}, AxisSet{1}),
                                     std::vector<std::shared_ptr<op::Parameter>>{X0});
    };
490
    EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x0}, .01f, .01f));
491 492
}

493
NGRAPH_TEST(${BACKEND_NAME}, backwards_concat_vector)
494
{
495
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
496 497

    test::Uniform<float> rng(-1.0f, 1.0f);
498
    Shape shape_0{3};
499
    auto x0 = rng.initialize(backend->create_tensor(element::f32, shape_0));
500
    Shape shape_1{2};
501
    auto x1 = rng.initialize(backend->create_tensor(element::f32, shape_1));
502
    Shape shape_2{1};
503
    auto x2 = rng.initialize(backend->create_tensor(element::f32, shape_2));
504 505

    auto make_graph = [shape_0, shape_1, shape_2]() {
506 507 508
        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);
509
        return make_shared<Function>(make_shared<op::Concat>(NodeVector{X0, X1, X2}, 0),
510 511
                                     std::vector<std::shared_ptr<op::Parameter>>{X0, X1, X2});
    };
512
    EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x0, x1, x2}, .01f, .01f));
513 514
}

515
NGRAPH_TEST(${BACKEND_NAME}, backwards_concat_axis_0)
516
{
517
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
518 519

    test::Uniform<float> rng(-1.0f, 1.0f);
520
    Shape shape_0{3, 2};
521
    auto x0 = rng.initialize(backend->create_tensor(element::f32, shape_0));
522
    Shape shape_1{2, 2};
523
    auto x1 = rng.initialize(backend->create_tensor(element::f32, shape_1));
524
    Shape shape_2{1, 2};
525
    auto x2 = rng.initialize(backend->create_tensor(element::f32, shape_2));
526 527

    auto make_graph = [shape_0, shape_1, shape_2]() {
528 529 530
        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);
531
        return make_shared<Function>(make_shared<op::Concat>(NodeVector{X0, X1, X2}, 0),
532 533
                                     std::vector<std::shared_ptr<op::Parameter>>{X0, X1, X2});
    };
534
    EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x0, x1, x2}, .01f, .01f));
535 536
}

537
NGRAPH_TEST(${BACKEND_NAME}, backwards_concat_axis_1)
538
{
539
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
540 541

    test::Uniform<float> rng(-1.0f, 1.0f);
542
    Shape shape_0{2, 3};
543
    auto x0 = rng.initialize(backend->create_tensor(element::f32, shape_0));
544
    Shape shape_1{2, 2};
545
    auto x1 = rng.initialize(backend->create_tensor(element::f32, shape_1));
546
    Shape shape_2{2, 1};
547
    auto x2 = rng.initialize(backend->create_tensor(element::f32, shape_2));
548 549

    auto make_graph = [shape_0, shape_1, shape_2]() {
550 551 552
        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);
553
        return make_shared<Function>(make_shared<op::Concat>(NodeVector{X0, X1, X2}, 1),
554 555
                                     std::vector<std::shared_ptr<op::Parameter>>{X0, X1, X2});
    };
556
    EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x0, x1, x2}, .01f, .01f));
557 558
}

559
NGRAPH_TEST(${BACKEND_NAME}, backwards_ceiling)
560
{
561
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
562 563 564 565 566 567

    // 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);
568
    Shape shape{2, 3};
569 570

    auto make_graph = [shape]() {
571
        auto X = make_shared<op::Parameter>(element::f32, shape);
572 573
        return make_shared<Function>(make_shared<op::Ceiling>(X),
                                     std::vector<std::shared_ptr<op::Parameter>>{X});
574 575
    };

576
    for (auto i = 0; i < ${TEST_LOOPS}; i++)
577
    {
578
        auto x_minusone = rng_minusone.initialize(backend->create_tensor<float>(shape));
579

580
        EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x_minusone}, .01f, .01f));
581

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

584
        EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x_plusone}, .01f, .01f));
585

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

588
        EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x_plustwo}, .01f, .01f));
589 590 591
    }
}

592
NGRAPH_TEST(${BACKEND_NAME}, backwards_cos)
593
{
594
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
595 596

    test::Uniform<float> rng(-10.0f, 10.0f);
597
    Shape shape{2, 3};
598
    auto make_graph = [shape]() {
599
        auto X = make_shared<op::Parameter>(element::f32, shape);
600 601
        return make_shared<Function>(make_shared<op::Cos>(X),
                                     std::vector<std::shared_ptr<op::Parameter>>{X});
602 603
    };

604
    for (auto i = 0; i < ${TEST_LOOPS}; i++)
605
    {
606
        auto x = rng.initialize(backend->create_tensor<float>(shape));
607

608
        EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x}, .01f, .01f));
609 610 611
    }
}

612
NGRAPH_TEST(${BACKEND_NAME}, backwards_cosh)
613
{
614
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
615 616

    test::Uniform<float> rng(-10.0f, 10.0f);
617
    Shape shape{2, 3};
618
    auto make_graph = [shape]() {
619
        auto X = make_shared<op::Parameter>(element::f32, shape);
620 621
        return make_shared<Function>(make_shared<op::Cosh>(X),
                                     std::vector<std::shared_ptr<op::Parameter>>{X});
622 623
    };

624
    for (auto i = 0; i < ${TEST_LOOPS}; i++)
625
    {
626
        auto x = rng.initialize(backend->create_tensor<float>(shape));
627

628
        EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x}, .01f, .01f));
629 630 631
    }
}

632
NGRAPH_TEST(${BACKEND_NAME}, backwards_divide)
633
{
634
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
635

636 637 638
    test::Uniform<float> rng(-1.0f, 1.0f);
    test::Uniform<float> rng1(1.0f, 2.0f);
    test::Uniform<float> rng2(-2.0f, -1.0f);
639
    Shape shape{2, 3};
640 641 642
    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));
643

644
    auto make_graph = [shape]() {
645 646
        auto X0 = make_shared<op::Parameter>(element::f32, shape);
        auto X1 = make_shared<op::Parameter>(element::f32, shape);
647
        return make_shared<Function>(X0 / X1, std::vector<std::shared_ptr<op::Parameter>>{X0, X1});
648
    };
649 650
    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
651
}
652

653
NGRAPH_TEST(${BACKEND_NAME}, backwards_dot_scalar_scalar)
654
{
655
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
656

657
    test::Uniform<float> rng(-1.0f, 1.0f);
658 659
    Shape shape0{};
    Shape shape1{};
660 661
    auto x0 = rng.initialize(backend->create_tensor<float>(shape0));
    auto x1 = rng.initialize(backend->create_tensor<float>(shape1));
662 663

    auto make_graph = [shape0, shape1]() {
664 665
        auto X0 = make_shared<op::Parameter>(element::f32, shape0);
        auto X1 = make_shared<op::Parameter>(element::f32, shape1);
666 667 668
        return make_shared<Function>(make_shared<op::Dot>(X0, X1),
                                     std::vector<std::shared_ptr<op::Parameter>>{X0, X1});
    };
669
    EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x0, x1}, .01f, .01f));
670 671
}

672
NGRAPH_TEST(${BACKEND_NAME}, backwards_dot_scalar_tensor)
673
{
674
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
675

676
    test::Uniform<float> rng(-1.0f, 1.0f);
677 678
    Shape shape0{};
    Shape shape1{3, 4};
679 680
    auto x0 = rng.initialize(backend->create_tensor<float>(shape0));
    auto x1 = rng.initialize(backend->create_tensor<float>(shape1));
681 682

    auto make_graph = [shape0, shape1]() {
683 684
        auto X0 = make_shared<op::Parameter>(element::f32, shape0);
        auto X1 = make_shared<op::Parameter>(element::f32, shape1);
685 686 687
        return make_shared<Function>(make_shared<op::Dot>(X0, X1),
                                     std::vector<std::shared_ptr<op::Parameter>>{X0, X1});
    };
688
    EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x0, x1}, .01f, .01f));
689 690
}

691
NGRAPH_TEST(${BACKEND_NAME}, backwards_dot_tensor_scalar)
692
{
693
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
694

695
    test::Uniform<float> rng(-1.0f, 1.0f);
696 697
    Shape shape0{3, 4};
    Shape shape1{};
698 699
    auto x0 = rng.initialize(backend->create_tensor<float>(shape0));
    auto x1 = rng.initialize(backend->create_tensor<float>(shape1));
700 701

    auto make_graph = [shape0, shape1]() {
702 703
        auto X0 = make_shared<op::Parameter>(element::f32, shape0);
        auto X1 = make_shared<op::Parameter>(element::f32, shape1);
704 705 706
        return make_shared<Function>(make_shared<op::Dot>(X0, X1),
                                     std::vector<std::shared_ptr<op::Parameter>>{X0, X1});
    };
707
    EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x0, x1}, .01f, .01f));
708 709
}

710
NGRAPH_TEST(${BACKEND_NAME}, backwards_dot_vector_vector)
711
{
712
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
713

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

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

729
NGRAPH_TEST(${BACKEND_NAME}, backwards_dot_tensor_vector)
730
{
731
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
732

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

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

748
NGRAPH_TEST(${BACKEND_NAME}, backwards_dot_tensor2_tensor2)
749
{
750
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
751

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

    auto make_graph = [shape0, shape1]() {
759 760
        auto X0 = make_shared<op::Parameter>(element::f32, shape0);
        auto X1 = make_shared<op::Parameter>(element::f32, shape1);
761 762
        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
763
    };
764
    EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x0, x1}, .01f, .01f));
Adam Procter's avatar
Adam Procter committed
765 766
}

767
NGRAPH_TEST(${BACKEND_NAME}, backwards_dot_tensor3_tensor3)
Adam Procter's avatar
Adam Procter committed
768
{
769
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
Adam Procter's avatar
Adam Procter committed
770 771

    test::Uniform<float> rng(-1.0f, 1.0f);
772 773
    Shape shape0{2, 4, 3};
    Shape shape1{4, 3, 3};
774 775
    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
776 777

    auto make_graph = [shape0, shape1]() {
778 779
        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
780 781
        return make_shared<Function>(make_shared<op::Dot>(X0, X1, 2),
                                     std::vector<std::shared_ptr<op::Parameter>>{X0, X1});
782
    };
783
    EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x0, x1}, .01f, .01f));
784 785
}

786
NGRAPH_TEST(${BACKEND_NAME}, backwards_exp)
Scott Cyphers's avatar
Scott Cyphers committed
787
{
788
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
Scott Cyphers's avatar
Scott Cyphers committed
789

790
    test::Uniform<float> rng(-1.0f, 1.0f);
791
    Shape shape{2, 3};
792
    auto x0 = rng.initialize(backend->create_tensor<float>(shape));
Scott Cyphers's avatar
Scott Cyphers committed
793 794

    auto make_graph = [shape]() {
795
        auto X0 = make_shared<op::Parameter>(element::f32, shape);
796 797
        return make_shared<Function>(make_shared<op::Exp>(X0),
                                     std::vector<std::shared_ptr<op::Parameter>>{X0});
Scott Cyphers's avatar
Scott Cyphers committed
798
    };
799
    EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x0}, .01f, .01f));
Scott Cyphers's avatar
Scott Cyphers committed
800 801
}

802
NGRAPH_TEST(${BACKEND_NAME}, backwards_floor)
803
{
804
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
805 806 807 808 809 810

    // 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);
811
    Shape shape{2, 3};
812 813

    auto make_graph = [shape]() {
814
        auto X = make_shared<op::Parameter>(element::f32, shape);
815 816
        return make_shared<Function>(make_shared<op::Floor>(X),
                                     std::vector<std::shared_ptr<op::Parameter>>{X});
817 818
    };

819
    for (auto i = 0; i < ${TEST_LOOPS}; i++)
820
    {
821
        auto x_minusone = rng_minusone.initialize(backend->create_tensor<float>(shape));
822

823
        EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x_minusone}, .01f, .01f));
824

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

827
        EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x_plusone}, .01f, .01f));
828

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

831
        EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x_plustwo}, .01f, .01f));
832 833 834
    }
}

835
NGRAPH_TEST(${BACKEND_NAME}, backwards_log)
Scott Cyphers's avatar
Scott Cyphers committed
836
{
837
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
Scott Cyphers's avatar
Scott Cyphers committed
838

839
    test::Uniform<float> rng(1.0f, 2.0f);
840
    Shape shape{2, 3};
841
    auto x0 = rng.initialize(backend->create_tensor<float>(shape));
Scott Cyphers's avatar
Scott Cyphers committed
842 843

    auto make_graph = [shape]() {
844
        auto X0 = make_shared<op::Parameter>(element::f32, shape);
845 846
        return make_shared<Function>(make_shared<op::Log>(X0),
                                     std::vector<std::shared_ptr<op::Parameter>>{X0});
Scott Cyphers's avatar
Scott Cyphers committed
847
    };
848
    EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x0}, .01f, .01f));
849 850
}

851
NGRAPH_TEST(${BACKEND_NAME}, backwards_maximum)
852
{
853
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
854

855
    test::Uniform<float> rng(-1.0f, 1.0f);
856
    Shape shape{2, 3};
857 858
    auto x0 = rng.initialize(backend->create_tensor<float>(shape));
    auto x1 = rng.initialize(backend->create_tensor<float>(shape));
859 860

    auto make_graph = [shape]() {
861 862
        auto X0 = make_shared<op::Parameter>(element::f32, shape);
        auto X1 = make_shared<op::Parameter>(element::f32, shape);
863 864 865
        return make_shared<Function>(make_shared<op::Maximum>(X0, X1),
                                     std::vector<std::shared_ptr<op::Parameter>>{X0, X1});
    };
866
    EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x0, x1}, .01f, .01f));
867 868
}

869
NGRAPH_TEST(${BACKEND_NAME}, backwards_minimum)
870
{
871
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
872

873
    test::Uniform<float> rng(-1.0f, 1.0f);
874
    Shape shape{2, 3};
875 876
    auto x0 = rng.initialize(backend->create_tensor<float>(shape));
    auto x1 = rng.initialize(backend->create_tensor<float>(shape));
877 878

    auto make_graph = [shape]() {
879 880
        auto X0 = make_shared<op::Parameter>(element::f32, shape);
        auto X1 = make_shared<op::Parameter>(element::f32, shape);
881 882 883
        return make_shared<Function>(make_shared<op::Minimum>(X0, X1),
                                     std::vector<std::shared_ptr<op::Parameter>>{X0, X1});
    };
884
    EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x0, x1}, .01f, .01f));
885 886
}

887
NGRAPH_TEST(${BACKEND_NAME}, backwards_multiply)
888
{
889
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
890

891
    test::Uniform<float> rng(-1.0f, 1.0f);
892
    Shape shape{2, 3};
893 894
    auto x0 = rng.initialize(backend->create_tensor<float>(shape));
    auto x1 = rng.initialize(backend->create_tensor<float>(shape));
895

896
    auto make_graph = [shape]() {
897 898
        auto X0 = make_shared<op::Parameter>(element::f32, shape);
        auto X1 = make_shared<op::Parameter>(element::f32, shape);
899
        return make_shared<Function>(X0 * X1, std::vector<std::shared_ptr<op::Parameter>>{X0, X1});
900
    };
901
    EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x0, x1}, .01f, .01f));
902
}
Scott Cyphers's avatar
Scott Cyphers committed
903

904
NGRAPH_TEST(${BACKEND_NAME}, backwards_negative)
Scott Cyphers's avatar
Scott Cyphers committed
905
{
906
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
Scott Cyphers's avatar
Scott Cyphers committed
907

908
    test::Uniform<float> rng(-1.0f, 1.0f);
909
    Shape shape{2, 3};
910
    auto x0 = rng.initialize(backend->create_tensor<float>(shape));
Scott Cyphers's avatar
Scott Cyphers committed
911 912

    auto make_graph = [shape]() {
913
        auto X0 = make_shared<op::Parameter>(element::f32, shape);
914
        return make_shared<Function>(-X0, std::vector<std::shared_ptr<op::Parameter>>{X0});
Scott Cyphers's avatar
Scott Cyphers committed
915
    };
916
    EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x0}, .01f, .01f));
Scott Cyphers's avatar
Scott Cyphers committed
917 918
}

919
NGRAPH_TEST(${BACKEND_NAME}, backwards_parameter)
Scott Cyphers's avatar
Scott Cyphers committed
920
{
921
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
Scott Cyphers's avatar
Scott Cyphers committed
922

923
    test::Uniform<float> rng(-1.0f, 1.0f);
924
    Shape shape{2, 3};
925
    auto x0 = rng.initialize(backend->create_tensor<float>(shape));
Scott Cyphers's avatar
Scott Cyphers committed
926
    auto make_graph = [shape]() {
927
        auto X0 = make_shared<op::Parameter>(element::f32, shape);
928
        return make_shared<Function>(X0, std::vector<std::shared_ptr<op::Parameter>>{X0});
Scott Cyphers's avatar
Scott Cyphers committed
929
    };
930
    EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x0}, .01f, .01f));
931 932
}

933
NGRAPH_TEST(${BACKEND_NAME}, backwards_power)
934
{
935
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
936 937 938

    test::Uniform<float> rng_neg(-5.0f, -0.5f);
    test::Uniform<float> rng_pos(0.5f, 5.0f);
939
    Shape shape{2, 3};
940 941

    auto make_graph = [shape]() {
942 943
        auto X0 = make_shared<op::Parameter>(element::f32, shape);
        auto X1 = make_shared<op::Parameter>(element::f32, shape);
944 945 946 947
        return make_shared<Function>(std::make_shared<op::Power>(X0, X1),
                                     std::vector<std::shared_ptr<op::Parameter>>{X0, X1});
    };

948 949
    auto x0 = rng_neg.initialize(backend->create_tensor<float>(shape));
    auto x1 = rng_pos.initialize(backend->create_tensor<float>(shape));
950

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

953 954
    x0 = rng_pos.initialize(backend->create_tensor<float>(shape));
    x1 = rng_neg.initialize(backend->create_tensor<float>(shape));
955

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

958 959
    x0 = rng_pos.initialize(backend->create_tensor<float>(shape));
    x1 = rng_pos.initialize(backend->create_tensor<float>(shape));
960

961
    EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x0, x1}, .01f, .01f));
962 963
}

964
NGRAPH_TEST(${BACKEND_NAME}, backwards_relu)
965
{
966
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
967 968 969 970

    test::Uniform<float> rng_neg(-1.0f, -0.01f);
    test::Uniform<float> rng_pos(0.01f, 1.0f);
    Shape shape{2, 3};
971 972
    auto x0 = rng_neg.initialize(backend->create_tensor<float>(shape));
    auto x1 = rng_pos.initialize(backend->create_tensor<float>(shape));
973 974 975 976 977 978 979 980 981

    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});
    };

    for (auto i = 0; i < ${TEST_LOOPS}; i++)
    {
982
        auto x_neg = rng_neg.initialize(backend->create_tensor<float>(shape));
983

984
        EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x_neg}, .01f, .01f));
985

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

988
        EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x_pos}, .01f, .01f));
989 990 991
    }
}

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

    test::Uniform<float> rng(-10.0f, 10.0f);
997 998
    Shape shape_x{5, 5};
    Shape shape_y{2, 2};
999
    auto make_graph = [shape_x, shape_y]() {
1000 1001
        auto X = make_shared<op::Parameter>(element::f32, shape_x);
        auto Y = make_shared<op::Parameter>(element::f32, shape_y);
1002 1003 1004 1005 1006
        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});
    };

1007
    for (auto i = 0; i < ${TEST_LOOPS}; i++)
1008
    {
1009 1010
        auto x = rng.initialize(backend->create_tensor<float>(shape_x));
        auto y = rng.initialize(backend->create_tensor<float>(shape_y));
1011

1012
        EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x, y}, .01f, .01f));
1013 1014 1015
    }
}

1016
NGRAPH_TEST(${BACKEND_NAME}, backwards_reshape)
1017
{
1018
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
1019

1020
    test::Uniform<float> rng(-1.0f, 1.0f);
1021
    Shape shape{3, 4};
1022
    auto x0 = rng.initialize(backend->create_tensor<float>(shape));
1023 1024

    auto make_graph = [shape]() {
1025
        auto X0 = make_shared<op::Parameter>(element::f32, shape);
1026 1027 1028
        return make_shared<Function>(make_shared<op::Reshape>(X0, AxisVector{1, 0}, Shape{4, 3}),
                                     std::vector<std::shared_ptr<op::Parameter>>{X0});
    };
1029
    EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x0}, .01f, .01f));
Scott Cyphers's avatar
Scott Cyphers committed
1030 1031
}

1032
NGRAPH_TEST(${BACKEND_NAME}, backwards_select)
1033
{
1034
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
1035 1036

    test::Uniform<float> rng(-10.0f, 10.0f);
1037
    Shape shape{2, 3};
1038
    auto make_graph = [shape]() {
1039 1040 1041
        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);
1042 1043 1044 1045
        return make_shared<Function>(make_shared<op::Select>(X0, X1, X2),
                                     std::vector<std::shared_ptr<op::Parameter>>{X0, X1, X2});
    };

1046
    for (auto i = 0; i < ${TEST_LOOPS}; i++)
1047
    {
1048
        auto x0 = backend->create_tensor(element::boolean, shape);
1049
        write_vector(x0, vector<char>{0, 1, 0, 1, 0, 1});
1050 1051 1052 1053 1054
        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>(
            backend, make_graph, {x0, x1, x2}, .01f, .01f, std::vector<bool>{false, true, true}));
1055 1056 1057
    }
}

1058
NGRAPH_TEST(${BACKEND_NAME}, backwards_select_nested)
1059
{
1060
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
1061 1062

    test::Uniform<float> rng(-10.0f, 10.0f);
1063
    Shape shape{2, 3};
1064
    auto make_graph = [shape]() {
1065 1066 1067
        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);
1068 1069 1070 1071
        return make_shared<Function>(make_shared<op::Select>(X0, X1 + X2, X2 - X1),
                                     std::vector<std::shared_ptr<op::Parameter>>{X0, X1, X2});
    };

1072
    for (auto i = 0; i < ${TEST_LOOPS}; i++)
1073
    {
1074
        auto x0 = backend->create_tensor(element::boolean, shape);
1075
        write_vector(x0, vector<char>{0, 1, 0, 1, 0, 1});
1076 1077 1078 1079 1080
        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>(
            backend, make_graph, {x0, x1, x2}, .01f, .01f, std::vector<bool>{false, true, true}));
1081 1082 1083
    }
}

1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111
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});
    };

    for (auto i = 0; i < ${TEST_LOOPS}; i++)
    {
        auto x_neg = rng_neg.initialize(backend->create_tensor<float>(shape));

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

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

        EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x_pos}, .01f, .01f));
    }
}

1112
NGRAPH_TEST(${BACKEND_NAME}, backwards_sign)
1113
{
1114
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
1115 1116 1117 1118 1119

    // 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);
1120
    Shape shape{2, 3};
1121 1122

    auto make_graph = [shape]() {
1123
        auto X = make_shared<op::Parameter>(element::f32, shape);
1124 1125
        return make_shared<Function>(make_shared<op::Sign>(X),
                                     std::vector<std::shared_ptr<op::Parameter>>{X});
1126 1127
    };

1128
    for (auto i = 0; i < ${TEST_LOOPS}; i++)
1129
    {
1130
        auto x_neg = rng_neg.initialize(backend->create_tensor<float>(shape));
1131

1132
        EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x_neg}, .01f, .01f));
1133

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

1136
        EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x_pos}, .01f, .01f));
1137 1138 1139
    }
}

1140
NGRAPH_TEST(${BACKEND_NAME}, backwards_sin)
1141
{
1142
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
1143 1144

    test::Uniform<float> rng(-10.0f, 10.0f);
1145
    Shape shape{2, 3};
1146
    auto make_graph = [shape]() {
1147
        auto X = make_shared<op::Parameter>(element::f32, shape);
1148 1149
        return make_shared<Function>(make_shared<op::Sin>(X),
                                     std::vector<std::shared_ptr<op::Parameter>>{X});
1150 1151
    };

1152
    for (auto i = 0; i < ${TEST_LOOPS}; i++)
1153
    {
1154
        auto x = rng.initialize(backend->create_tensor<float>(shape));
1155

1156
        EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x}, .01f, .01f));
1157 1158 1159
    }
}

1160
NGRAPH_TEST(${BACKEND_NAME}, backwards_sinh)
1161
{
1162
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
1163 1164

    test::Uniform<float> rng(-10.0f, 10.0f);
1165
    Shape shape{2, 3};
1166
    auto make_graph = [shape]() {
1167
        auto X = make_shared<op::Parameter>(element::f32, shape);
1168 1169
        return make_shared<Function>(make_shared<op::Sinh>(X),
                                     std::vector<std::shared_ptr<op::Parameter>>{X});
1170 1171
    };

1172
    for (auto i = 0; i < ${TEST_LOOPS}; i++)
1173
    {
1174
        auto x = rng.initialize(backend->create_tensor<float>(shape));
1175

1176
        EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x}, .01f, .01f));
1177 1178 1179
    }
}

1180
NGRAPH_TEST(${BACKEND_NAME}, backwards_slice)
1181
{
1182
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
1183
    test::Uniform<float> rng(-10.0f, 10.0f);
1184
    Shape shape{5, 5};
1185
    auto make_graph = [shape]() {
1186
        auto X = make_shared<op::Parameter>(element::f32, shape);
1187 1188 1189 1190
        return make_shared<Function>(make_shared<op::Slice>(X, Coordinate{2, 3}, Coordinate{4, 5}),
                                     std::vector<std::shared_ptr<op::Parameter>>{X});
    };

1191
    for (auto i = 0; i < ${TEST_LOOPS}; i++)
1192
    {
1193
        auto x = rng.initialize(backend->create_tensor<float>(shape));
1194

1195
        EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x}, .01f, .01f));
1196 1197 1198
    }
}

1199
NGRAPH_TEST(${BACKEND_NAME}, backwards_softmax_all)
1200
{
1201
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
1202

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

1207
    auto make_graph = [shape]() {
adstraw's avatar
adstraw committed
1208 1209 1210
        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});
1211
    };
1212
    EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x0}, .01f, .01f));
adstraw's avatar
adstraw committed
1213
}
1214

1215
NGRAPH_TEST(${BACKEND_NAME}, backwards_softmax_axis)
adstraw's avatar
adstraw committed
1216
{
1217
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
1218

adstraw's avatar
adstraw committed
1219 1220
    test::Uniform<float> rng(-1.0f, 1.0f);
    Shape shape{2, 3};
1221
    auto x0 = rng.initialize(backend->create_tensor<float>(shape));
adstraw's avatar
adstraw committed
1222 1223 1224 1225 1226 1227

    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});
    };
1228
    EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x0}, .01f, .01f));
adstraw's avatar
adstraw committed
1229 1230
}

1231
NGRAPH_TEST(${BACKEND_NAME}, backwards_softmax_underflow)
adstraw's avatar
adstraw committed
1232
{
1233
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
adstraw's avatar
adstraw committed
1234 1235 1236 1237

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

    Shape shape{2, 3};
1238
    auto x0 = backend->create_tensor(element::f32, shape);
adstraw's avatar
adstraw committed
1239 1240 1241 1242 1243 1244 1245
    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});
    };
1246
    EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x0}, .01f, .01f));
adstraw's avatar
adstraw committed
1247 1248
}

1249
NGRAPH_TEST(${BACKEND_NAME}, backwards_softmax_3d)
adstraw's avatar
adstraw committed
1250
{
1251
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
adstraw's avatar
adstraw committed
1252 1253 1254

    test::Uniform<float> rng(-1.0f, 1.0f);
    Shape shape{2, 3, 4};
1255
    auto x0 = rng.initialize(backend->create_tensor<float>(shape));
adstraw's avatar
adstraw committed
1256 1257 1258 1259 1260 1261

    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});
    };
1262
    EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph0, {x0}, .01f, .01f));
adstraw's avatar
adstraw committed
1263 1264 1265 1266 1267 1268

    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});
    };
1269
    EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph1, {x0}, .01f, .01f));
adstraw's avatar
adstraw committed
1270 1271 1272 1273 1274 1275

    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});
    };
1276
    EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph2, {x0}, .01f, .01f));
adstraw's avatar
adstraw committed
1277 1278 1279 1280 1281 1282

    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});
    };
1283
    EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph01, {x0}, .01f, .01f));
adstraw's avatar
adstraw committed
1284 1285 1286 1287 1288 1289

    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});
    };
1290
    EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph02, {x0}, .01f, .01f));
adstraw's avatar
adstraw committed
1291 1292 1293 1294 1295 1296

    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});
    };
1297
    EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph12, {x0}, .01f, .01f));
adstraw's avatar
adstraw committed
1298 1299 1300 1301 1302 1303

    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});
    };
1304
    EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph012, {x0}, .01f, .01f));
1305 1306
}

1307
NGRAPH_TEST(${BACKEND_NAME}, backwards_subtract)
Scott Cyphers's avatar
Scott Cyphers committed
1308
{
1309
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
Scott Cyphers's avatar
Scott Cyphers committed
1310

1311
    test::Uniform<float> rng(-1.0f, 1.0f);
1312
    Shape shape{2, 3};
1313 1314
    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
1315 1316

    auto make_graph = [shape]() {
1317 1318
        auto X0 = make_shared<op::Parameter>(element::f32, shape);
        auto X1 = make_shared<op::Parameter>(element::f32, shape);
1319
        return make_shared<Function>(X0 - X1, std::vector<std::shared_ptr<op::Parameter>>{X0, X1});
Scott Cyphers's avatar
Scott Cyphers committed
1320
    };
1321
    EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x0, x1}, .01f, .01f));
Scott Cyphers's avatar
Scott Cyphers committed
1322
}
Scott Cyphers's avatar
Scott Cyphers committed
1323

1324
NGRAPH_TEST(${BACKEND_NAME}, backwards_sum_v2s)
1325
{
1326
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
1327 1328

    test::Uniform<float> rng(-1.0f, 1.0f);
1329
    Shape shape{8};
1330
    auto x = rng.initialize(backend->create_tensor<float>(shape));
1331 1332

    auto make_graph = [shape]() {
1333
        auto X = make_shared<op::Parameter>(element::f32, shape);
1334 1335 1336
        return make_shared<Function>(make_shared<op::Sum>(X, AxisSet{0}),
                                     std::vector<std::shared_ptr<op::Parameter>>{X});
    };
1337
    EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x}, .01f, .01f));
1338 1339
}

1340
NGRAPH_TEST(${BACKEND_NAME}, backwards_sum_m2s)
1341
{
1342
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
1343 1344

    test::Uniform<float> rng(-1.0f, 1.0f);
1345
    Shape shape{8, 9};
1346
    auto x = rng.initialize(backend->create_tensor<float>(shape));
1347 1348

    auto make_graph = [shape]() {
1349
        auto X = make_shared<op::Parameter>(element::f32, shape);
1350 1351 1352
        return make_shared<Function>(make_shared<op::Sum>(X, AxisSet{0, 1}),
                                     std::vector<std::shared_ptr<op::Parameter>>{X});
    };
1353
    EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x}, .01f, .01f));
1354 1355
}

1356
NGRAPH_TEST(${BACKEND_NAME}, backwards_sum_m2v_0)
1357
{
1358
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
1359 1360

    test::Uniform<float> rng(-1.0f, 1.0f);
1361
    Shape shape{8, 9};
1362
    auto x = rng.initialize(backend->create_tensor<float>(shape));
1363 1364

    auto make_graph = [shape]() {
1365
        auto X = make_shared<op::Parameter>(element::f32, shape);
1366 1367 1368
        return make_shared<Function>(make_shared<op::Sum>(X, AxisSet{0}),
                                     std::vector<std::shared_ptr<op::Parameter>>{X});
    };
1369
    EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x}, .01f, .01f));
1370 1371
}

1372
NGRAPH_TEST(${BACKEND_NAME}, backwards_sum_m2v_1)
1373
{
1374
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
1375 1376

    test::Uniform<float> rng(-1.0f, 1.0f);
1377
    Shape shape{8, 9};
1378
    auto x = rng.initialize(backend->create_tensor<float>(shape));
1379 1380

    auto make_graph = [shape]() {
1381
        auto X = make_shared<op::Parameter>(element::f32, shape);
1382 1383 1384
        return make_shared<Function>(make_shared<op::Sum>(X, AxisSet{1}),
                                     std::vector<std::shared_ptr<op::Parameter>>{X});
    };
1385
    EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x}, .01f, .01f));
1386 1387
}

1388
NGRAPH_TEST(${BACKEND_NAME}, backwards_tan)
1389
{
1390
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
1391 1392 1393 1394

    auto pi = 3.14159f;

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

1399
    Shape shape{2, 3};
1400 1401

    auto make_graph = [shape]() {
1402
        auto X = make_shared<op::Parameter>(element::f32, shape);
1403 1404
        return make_shared<Function>(make_shared<op::Tan>(X),
                                     std::vector<std::shared_ptr<op::Parameter>>{X});
1405 1406
    };

1407
    for (auto i = 0; i < ${TEST_LOOPS}; i++)
1408
    {
1409
        auto x_r = rng_r.initialize(backend->create_tensor<float>(shape));
1410

1411
        EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x_r}, .01f, .01f));
1412

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

1415
        EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x_l}, .01f, .01f));
1416 1417 1418
    }
}

1419
NGRAPH_TEST(${BACKEND_NAME}, backwards_tanh)
1420
{
1421
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
1422 1423

    test::Uniform<float> rng(-10.0f, 10.0f);
1424
    Shape shape{2, 3};
1425
    auto make_graph = [shape]() {
1426
        auto X = make_shared<op::Parameter>(element::f32, shape);
1427 1428
        return make_shared<Function>(make_shared<op::Tanh>(X),
                                     std::vector<std::shared_ptr<op::Parameter>>{X});
1429 1430
    };

1431
    for (auto i = 0; i < ${TEST_LOOPS}; i++)
1432
    {
1433
        auto x = rng.initialize(backend->create_tensor<float>(shape));
1434

1435
        EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x}, .01f, .01f));
1436 1437 1438
    }
}

1439
NGRAPH_TEST(${BACKEND_NAME}, backwards_abc)
Scott Cyphers's avatar
Scott Cyphers committed
1440
{
1441
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
Scott Cyphers's avatar
Scott Cyphers committed
1442

1443
    test::Uniform<float> rng(-1.0f, 1.0f);
1444
    Shape shape{2, 3};
1445 1446 1447
    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
1448 1449

    auto make_graph = [shape]() {
1450 1451 1452
        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);
1453 1454
        return make_shared<Function>((X0 + X1) * X2,
                                     std::vector<std::shared_ptr<op::Parameter>>{X0, X1, X2});
Scott Cyphers's avatar
Scott Cyphers committed
1455
    };
1456
    EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x0, x1, x2}, .01f, .01f));
Scott Cyphers's avatar
Scott Cyphers committed
1457
}
1458

1459
NGRAPH_TEST(${BACKEND_NAME}, backwards_reverse_3d_02)
1460
{
1461
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
1462 1463

    test::Uniform<float> rng(-1.0f, 1.0f);
1464
    Shape shape{2, 4, 5};
1465
    auto x = rng.initialize(backend->create_tensor(element::f32, shape));
1466 1467 1468 1469 1470 1471

    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});
    };
1472
    EXPECT_TRUE(autodiff_numeric_compare<float>(backend, make_graph, {x}, .01f, .01f));
1473
}
1474

1475
NGRAPH_TEST(${BACKEND_NAME}, backwards_maxpool_n4c1h4w4_kh2kw2_sh1sw1)
1476
{
1477
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
1478
    Shape shape_a{4, 1, 4, 4}; //in NCHW
1479 1480 1481 1482 1483
    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};
1484
    auto maxpool = make_shared<op::MaxPool>(A, window_shape, window_movement_strides);
1485
    auto f = make_shared<Function>(maxpool, op::ParameterVector{A});
1486
    shared_ptr<runtime::TensorView> ep = backend->create_tensor(element::f32, maxpool_shape);
1487 1488
    vector<float> dataEp(shape_size(maxpool_shape), 4);

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

    vector<float> dataInput{11, 65, 44, 28, 31, 33, 21, 66, 40, 49, 69, 57, 47, 30, 24, 27,
pthoreho's avatar
pthoreho committed
1493 1494 1495
                            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};
1496 1497

    vector<float> expected{//delta
1498 1499 1500
                           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};
1501 1502 1503 1504 1505 1506

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

    auto C = make_shared<op::Parameter>(element::f32, maxpool_shape);
    auto df = autodiff::backprop_function(f);
1507
    backend->call(df, {output}, {input, ep});
1508 1509 1510
    ASSERT_TRUE(read_vector<float>(output) == expected);
}

1511
NGRAPH_TEST(${BACKEND_NAME}, backwards_maxpool_n2c1h5w5_kh3kw3_sh2sw2)
1512
{
1513
    auto backend = runtime::Backend::create("${BACKEND_NAME}");
1514

1515
    Shape shape_a{1, 2, 5, 5}; //in NCHW
1516 1517 1518 1519 1520
    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};
1521
    auto maxpool = make_shared<op::MaxPool>(A, window_shape, window_movement_strides);
1522
    auto f = make_shared<Function>(maxpool, op::ParameterVector{A});
1523

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

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

    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
1531 1532
                            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};
1533 1534

    vector<float> expected{//delta
1535 1536 1537
                           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};
1538 1539 1540 1541 1542 1543

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

    auto C = make_shared<op::Parameter>(element::f32, maxpool_shape);
    auto df = autodiff::backprop_function(f);
1544
    backend->call(df, {output}, {input, ep});
1545
    ASSERT_TRUE(read_vector<float>(output) == expected);
1546
}
1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635

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);

    //input values don't matter
    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);
    backend->call(df, {da, db}, {a, b, c});
    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);

    //input values don't matter
    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);
    backend->call(df, {da, db}, {a, b, c});
    ASSERT_EQ(read_vector<int>(da), expected);
}