## Coverage Report

#### Created: 2026-05-04 15:30

next uncovered line (L), next uncovered region (R), next uncovered branch (B)

    /home/liu/actions-runner/_work/ccv/ccv/test/unit/nnc/dynamic.graph.tests.c

    Line
    Count
    Source
    1
    #include "case.h"
    2
    #include "ccv_case.h"
    3
    #include "ccv_nnc_case.h"
    4
    #include <ccv.h>
    5
    #include <nnc/ccv_nnc.h>
    6
    #include <nnc/ccv_nnc_easy.h>
    7
    #include "3rdparty/dsfmt/dSFMT.h"
    8
    9
    TEST_SETUP()
    10
    {
    11
      ccv_nnc_init();
    12
    }
    13
    14
    TEST_CASE("dynamic graph to compute log(19)")
    15
    {
    16
      ccv_nnc_dynamic_graph_t* const graph = ccv_nnc_dynamic_graph_new();
    17
      ccv_nnc_tensor_variable_t a = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 1));
    18
      ccv_nnc_tensor_from_variable(graph, a)->data.f32[0] = 19;
    19
      ccv_nnc_tensor_variable_t b = ccv_nnc_tensor_variable_new(graph);
    20
      ccv_nnc_dynamic_graph_exec(graph, CMD_EWLOG_FORWARD(), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(a), TENSOR_VARIABLE_LIST(b), 0, 0);
    21
      REQUIRE_EQ_WITH_TOLERANCE(ccv_nnc_tensor_from_variable(graph, b)->data.f32[0], logf(19), 1e-5, "log(19) result should be equal.");
    22
      DYNAMIC_GRAPH_GEN(graph, CCV_NNC_LONG_DOT_GRAPH);
    23
      ccv_nnc_dynamic_graph_free(graph);
    24
    }
    25
    26
    TEST_CASE("dynamic graph to compute reciprocal")
    27
    1
    {
    28
    1
      ccv_nnc_dynamic_graph_t* const graph = ccv_nnc_dynamic_graph_new();
    29
    1
      ccv_nnc_tensor_variable_t a = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 1));
    30
    1
      ccv_nnc_tensor_from_variable(graph, a)->data.f32[0] = 19;
    31
    1
      ccv_nnc_tensor_variable_t b = ccv_nnc_tensor_variable_new(graph);
    32
    1
      ccv_nnc_dynamic_graph_exec(graph, CMD_EWDIV_FORWARD(), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(0, a), TENSOR_VARIABLE_LIST(b), 0, 0);
    33
    1
      REQUIRE_EQ_WITH_TOLERANCE(ccv_nnc_tensor_from_variable(graph, b)->data.f32[0], 1.0 / 19, 1e-5, "1.0 / 19 result should be equal.");
    34
    1
      DYNAMIC_GRAPH_GEN(graph, CCV_NNC_LONG_DOT_GRAPH);
    35
    1
      ccv_nnc_dynamic_graph_free(graph);
    36
    1
    }
    37
    38
    TEST_CASE("dynamic graph to compute power and gradients")
    39
    1
    {
    40
    1
      ccv_nnc_dynamic_graph_t* const graph = ccv_nnc_dynamic_graph_new();
    41
    1
      ccv_nnc_tensor_variable_t a = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 1));
    42
    1
      ccv_nnc_tensor_from_variable(graph, a)->data.f32[0] = 2;
    43
    1
      ccv_nnc_tensor_variable_t c = ccv_nnc_tensor_variable_new(graph);
    44
    1
      ccv_nnc_dynamic_graph_exec(graph, CMD_EWPOW_FORWARD(3), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(a), TENSOR_VARIABLE_LIST(c), 0, 0);
    45
    1
      REQUIRE_EQ_WITH_TOLERANCE(ccv_nnc_tensor_from_variable(graph, c)->data.f32[0], 8, 1e-5, "pow result should be equal.");
    46
    1
      ccv_nnc_tensor_variable_t da = ccv_nnc_tensor_variable_new(graph);
    47
    1
      ccv_nnc_dynamic_graph_backward(graph, TENSOR_VARIABLE_LIST(c), 0, TENSOR_VARIABLE_LIST(a), TENSOR_VARIABLE_LIST(da), 0);
    48
    1
      REQUIRE_EQ_WITH_TOLERANCE(ccv_nnc_tensor_from_variable(graph, da)->data.f32[0], 12, 1e-5, "d(pow(a,3))/da should be 3 * pow(a,2).");
    49
    1
      DYNAMIC_GRAPH_GEN(graph, CCV_NNC_LONG_DOT_GRAPH);
    50
    1
      ccv_nnc_dynamic_graph_free(graph);
    51
    1
    }
    52
    53
    TEST_CASE("dynamic graph to compute sin and gradient")
    54
    1
    {
    55
    1
      ccv_nnc_dynamic_graph_t* const graph = ccv_nnc_dynamic_graph_new();
    56
    1
      ccv_nnc_tensor_variable_t a = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 1));
    57
    1
      ccv_nnc_tensor_from_variable(graph, a)->data.f32[0] = 0.5;
    58
    1
      ccv_nnc_tensor_variable_t b = ccv_nnc_tensor_variable_new(graph);
    59
    1
      ccv_nnc_dynamic_graph_exec(graph, CMD_EWSIN_FORWARD(), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(a), TENSOR_VARIABLE_LIST(b), 0, 0);
    60
    1
      REQUIRE_EQ_WITH_TOLERANCE(ccv_nnc_tensor_from_variable(graph, b)->data.f32[0], sinf(0.5), 1e-5, "sin result should be equal.");
    61
    1
      ccv_nnc_tensor_variable_t da = ccv_nnc_tensor_variable_new(graph);
    62
    1
      ccv_nnc_dynamic_graph_backward(graph, TENSOR_VARIABLE_LIST(b), 0, TENSOR_VARIABLE_LIST(a), TENSOR_VARIABLE_LIST(da), 0);
    63
    1
      REQUIRE_EQ_WITH_TOLERANCE(ccv_nnc_tensor_from_variable(graph, da)->data.f32[0], cosf(0.5), 1e-5, "d(sin(x))/dx should be cos(x).");
    64
    1
      DYNAMIC_GRAPH_GEN(graph, CCV_NNC_LONG_DOT_GRAPH);
    65
    1
      ccv_nnc_dynamic_graph_free(graph);
    66
    1
    }
    67
    68
    TEST_CASE("dynamic graph to compute cos and gradient")
    69
    1
    {
    70
    1
      ccv_nnc_dynamic_graph_t* const graph = ccv_nnc_dynamic_graph_new();
    71
    1
      ccv_nnc_tensor_variable_t a = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 1));
    72
    1
      ccv_nnc_tensor_from_variable(graph, a)->data.f32[0] = 0.5;
    73
    1
      ccv_nnc_tensor_variable_t b = ccv_nnc_tensor_variable_new(graph);
    74
    1
      ccv_nnc_dynamic_graph_exec(graph, CMD_EWCOS_FORWARD(), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(a), TENSOR_VARIABLE_LIST(b), 0, 0);
    75
    1
      REQUIRE_EQ_WITH_TOLERANCE(ccv_nnc_tensor_from_variable(graph, b)->data.f32[0], cosf(0.5), 1e-5, "cos result should be equal.");
    76
    1
      ccv_nnc_tensor_variable_t da = ccv_nnc_tensor_variable_new(graph);
    77
    1
      ccv_nnc_dynamic_graph_backward(graph, TENSOR_VARIABLE_LIST(b), 0, TENSOR_VARIABLE_LIST(a), TENSOR_VARIABLE_LIST(da), 0);
    78
    1
      REQUIRE_EQ_WITH_TOLERANCE(ccv_nnc_tensor_from_variable(graph, da)->data.f32[0], -sinf(0.5), 1e-5, "d(cos(x))/dx should be -sin(x).");
    79
    1
      DYNAMIC_GRAPH_GEN(graph, CCV_NNC_LONG_DOT_GRAPH);
    80
    1
      ccv_nnc_dynamic_graph_free(graph);
    81
    1
    }
    82
    83
    TEST_CASE("dynamic graph with alias")
    84
    1
    {
    85
    1
      ccv_nnc_dynamic_graph_t* const graph = ccv_nnc_dynamic_graph_new();
    86
    1
      ccv_nnc_tensor_variable_t const a = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 2));
    87
    1
      ccv_nnc_tensor_variable_t const a0 = ccv_nnc_tensor_variable_alias_new(graph, a, DIM_ALLOC(1), DIM_ALLOC(), CPU_TENSOR_NHWC(32F, 1));
    88
    1
      ccv_nnc_tensor_variable_t const a1 = ccv_nnc_tensor_variable_alias_new(graph, a, ccv_nnc_no_ofs, DIM_ALLOC(), CPU_TENSOR_NHWC(32F, 1));
    89
    1
      ccv_nnc_tensor_t* const b0 = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2), 0);
    90
    1
      ccv_nnc_tensor_variable_set(graph, a, b0);
    91
    1
      b0->data.f32[0] = 10;
    92
    1
      b0->data.f32[1] = 11;
    93
    1
      ccv_nnc_tensor_t* const b1 = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2), 0);
    94
    1
      b1->data.f32[0] = 20;
    95
    1
      b1->data.f32[1] = 21;
    96
    1
      REQUIRE(CCV_IS_TENSOR_VIEW(ccv_nnc_tensor_from_variable(graph, a0)), "Complex vector is a tensor view");
    97
    1
      REQUIRE(!CCV_IS_TENSOR_VIEW(ccv_nnc_tensor_from_variable(graph, a1)), "Simple vector is not a tensor view");
    98
    1
      REQUIRE_EQ(ccv_nnc_tensor_from_variable(graph, a0)->data.f32[0], 11, "should be b0[1]");
    99
    1
      REQUIRE_EQ(ccv_nnc_tensor_from_variable(graph, a1)->data.f32[0], 10, "should be b0[0]");
    100
    1
      REQUIRE(!CCV_IS_TENSOR_VIEW(ccv_nnc_tensor_from_variable(graph, a1)), "no need to be a tensor view");
    101
    1
      ccv_nnc_tensor_variable_set(graph, a, b1);
    102
    1
      REQUIRE_EQ(ccv_nnc_tensor_from_variable(graph, a0)->data.f32[0], 21, "should be b1[1]");
    103
    1
      REQUIRE_EQ(ccv_nnc_tensor_from_variable(graph, a1)->data.f32[0], 20, "should be b1[0]");
    104
    1
      REQUIRE(!CCV_IS_TENSOR_VIEW(ccv_nnc_tensor_from_variable(graph, a1)), "no need to be a tensor view");
    105
    1
      ccv_nnc_dynamic_graph_free(graph);
    106
    1
      ccv_nnc_tensor_free(b0);
    107
    1
      ccv_nnc_tensor_free(b1);
    108
    1
    }
    109
    110
    TEST_CASE("dynamic graph alias an alias")
    111
    1
    {
    112
    1
      ccv_nnc_dynamic_graph_t* const graph = ccv_nnc_dynamic_graph_new();
    113
    1
      ccv_nnc_tensor_variable_t const a = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 2, 3));
    114
    1
      ccv_nnc_tensor_variable_t const a0 = ccv_nnc_tensor_variable_alias_new(graph, a, DIM_ALLOC(1, 0), DIM_ALLOC(3, 1), CPU_TENSOR_NHWC(32F, 1, 3));
    115
    1
      ccv_nnc_tensor_variable_t const a1 = ccv_nnc_tensor_variable_alias_new(graph, a0, DIM_ALLOC(1), DIM_ALLOC(1), CPU_TENSOR_NHWC(32F, 2));
    116
    1
      ccv_nnc_tensor_t* const b0 = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 3), 0);
    117
    1
      ccv_nnc_tensor_variable_set(graph, a, b0);
    118
    1
      b0->data.f32[0] = 10;
    119
    1
      b0->data.f32[1] = 11;
    120
    1
      b0->data.f32[2] = 12;
    121
    1
      b0->data.f32[3] = 13;
    122
    1
      b0->data.f32[4] = 14;
    123
    1
      b0->data.f32[5] = 15;
    124
    1
      ccv_nnc_tensor_t* const b1 = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 3), 0);
    125
    1
      b1->data.f32[0] = 20;
    126
    1
      b1->data.f32[1] = 21;
    127
    1
      b1->data.f32[2] = 22;
    128
    1
      b1->data.f32[3] = 23;
    129
    1
      b1->data.f32[4] = 24;
    130
    1
      b1->data.f32[5] = 25;
    131
    1
      REQUIRE(CCV_IS_TENSOR_VIEW(ccv_nnc_tensor_from_variable(graph, a0)), "Complex vector is a tensor view");
    132
    1
      REQUIRE(CCV_IS_TENSOR_VIEW(ccv_nnc_tensor_from_variable(graph, a1)), "Complex vector is a tensor view");
    133
    1
      REQUIRE_EQ(ccv_nnc_tensor_from_variable(graph, a0)->data.f32[0], 13, "should be b0[1, 0]");
    134
    1
      REQUIRE_EQ(ccv_nnc_tensor_from_variable(graph, a0)->data.f32[1], 14, "should be b0[1, 1]");
    135
    1
      REQUIRE_EQ(ccv_nnc_tensor_from_variable(graph, a0)->data.f32[2], 15, "should be b0[1, 2]");
    136
    1
      REQUIRE_EQ(ccv_nnc_tensor_from_variable(graph, a1)->data.f32[0], 14, "should be b0[1, 1]");
    137
    1
      REQUIRE_EQ(ccv_nnc_tensor_from_variable(graph, a1)->data.f32[1], 15, "should be b0[1, 2]");
    138
    1
      ccv_nnc_tensor_variable_set(graph, a, b1);
    139
    1
      REQUIRE_EQ(ccv_nnc_tensor_from_variable(graph, a0)->data.f32[0], 23, "should be b1[1, 0]");
    140
    1
      REQUIRE_EQ(ccv_nnc_tensor_from_variable(graph, a0)->data.f32[1], 24, "should be b1[1, 1]");
    141
    1
      REQUIRE_EQ(ccv_nnc_tensor_from_variable(graph, a0)->data.f32[2], 25, "should be b1[1, 2]");
    142
    1
      REQUIRE_EQ(ccv_nnc_tensor_from_variable(graph, a1)->data.f32[0], 24, "should be b1[1, 1]");
    143
    1
      REQUIRE_EQ(ccv_nnc_tensor_from_variable(graph, a1)->data.f32[1], 25, "should be b1[1, 2]");
    144
    1
      ccv_nnc_dynamic_graph_free(graph);
    145
    1
      ccv_nnc_tensor_free(b0);
    146
    1
      ccv_nnc_tensor_free(b1);
    147
    1
    }
    148
    149
    TEST_CASE("dynamic graph to compute f(x) = x * log(x) + 1.2 * x, f'(x) where x = 19")
    150
    1
    {
    151
    1
      ccv_nnc_dynamic_graph_t* const graph = ccv_nnc_dynamic_graph_new();
    152
    1
      ccv_nnc_tensor_variable_t x = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 1));
    153
    1
      ccv_nnc_tensor_from_variable(graph, x)->data.f32[0] = 19;
    154
    1
      ccv_nnc_tensor_variable_t f = ccv_nnc_tensor_variable_new(graph);
    155
    1
      ccv_nnc_dynamic_graph_exec(graph, CMD_EWLOG_FORWARD(), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(x), TENSOR_VARIABLE_LIST(f), 0, 0);
    156
    1
      ccv_nnc_dynamic_graph_exec(graph, CMD_EWPROD_FORWARD(), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(x, f), TENSOR_VARIABLE_LIST(f), 0, 0);
    157
    1
      ccv_nnc_tensor_variable_t y = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 1));
    158
    1
      ccv_nnc_tensor_from_variable(graph, y)->data.f32[0] = 1.2;
    159
    1
      ccv_nnc_tensor_variable_t z = ccv_nnc_tensor_variable_new(graph);
    160
    1
      ccv_nnc_dynamic_graph_exec(graph, CMD_EWPROD_FORWARD(), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(x, y), TENSOR_VARIABLE_LIST(z), 0, 0);
    161
    1
      ccv_nnc_dynamic_graph_exec(graph, CMD_EWSUM_FORWARD(), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(f, z), TENSOR_VARIABLE_LIST(f), 0, 0);
    162
    1
      REQUIRE_EQ_WITH_TOLERANCE(ccv_nnc_tensor_from_variable(graph, f)->data.f32[0], 19 * logf(19) + 1.2 * 19, 1e-5, "f(x) = 1.2 * 19 + 19 * log(19)");
    163
      // Do gradient computation multiple times.
    164
    1
      ccv_nnc_tensor_variable_t dx = ccv_nnc_tensor_variable_new(graph);
    165
    1
      ccv_nnc_dynamic_graph_backward(graph, TENSOR_VARIABLE_LIST(f), 0, TENSOR_VARIABLE_LIST(x), TENSOR_VARIABLE_LIST(dx), 0);
    166
    1
      REQUIRE_EQ_WITH_TOLERANCE(ccv_nnc_tensor_from_variable(graph, dx)->data.f32[0], logf(19) + 1 + 1.2, 1e-5, "f'(x) = 1.2 + log(19) + 19 * 1 / 19");
    167
    1
      ccv_nnc_tensor_variable_t dy = ccv_nnc_tensor_variable_new(graph);
    168
    1
      ccv_nnc_dynamic_graph_backward(graph, TENSOR_VARIABLE_LIST(f), 0, TENSOR_VARIABLE_LIST(y), TENSOR_VARIABLE_LIST(dy), 0);
    169
    1
      REQUIRE_EQ_WITH_TOLERANCE(ccv_nnc_tensor_from_variable(graph, dy)->data.f32[0], 19, 1e-5, "f'(y) = 19");
    170
    1
      ccv_nnc_tensor_variable_t dz = ccv_nnc_tensor_variable_new(graph);
    171
    1
      ccv_nnc_dynamic_graph_backward(graph, TENSOR_VARIABLE_LIST(f), 0, TENSOR_VARIABLE_LIST(z), TENSOR_VARIABLE_LIST(dz), 0);
    172
    1
      REQUIRE_EQ_WITH_TOLERANCE(ccv_nnc_tensor_from_variable(graph, dz)->data.f32[0], 1, 1e-5, "f'(z) = 1");
    173
    1
      ccv_nnc_tensor_variable_free(graph, dy);
    174
    1
      dy = ccv_nnc_tensor_variable_new(graph);
    175
    1
      ccv_nnc_dynamic_graph_exec(graph, CMD_SET_FORWARD(0), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(), TENSOR_VARIABLE_LIST(dx), 0, 0);
    176
    1
      ccv_nnc_dynamic_graph_backward(graph, TENSOR_VARIABLE_LIST(f), 0, TENSOR_VARIABLE_LIST(y, x), TENSOR_VARIABLE_LIST(dy, dx), 0);
    177
    1
      REQUIRE_EQ_WITH_TOLERANCE(ccv_nnc_tensor_from_variable(graph, dx)->data.f32[0], logf(19) + 1 + 1.2, 1e-5, "f'(x) = 1.2 + log(19) + 19 * 1 / 19");
    178
    1
      REQUIRE_EQ_WITH_TOLERANCE(ccv_nnc_tensor_from_variable(graph, dy)->data.f32[0], 19, 1e-5, "f'(y) = 19");
    179
    1
      DYNAMIC_GRAPH_GEN(graph, CCV_NNC_LONG_DOT_GRAPH);
    180
    1
      ccv_nnc_dynamic_graph_free(graph);
    181
    1
    }
    182
    183
    TEST_CASE("dynamic graph with dense net (extensive use of alias)")
    184
    1
    {
    185
    1
      ccv_nnc_dynamic_graph_t* const graph = ccv_nnc_dynamic_graph_new();
    186
    1
      ccv_nnc_tensor_variable_t x = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 1, 4));
    187
    1
      ccv_nnc_tensor_from_variable(graph, x)->data.f32[0] = 0.472;
    188
    1
      ccv_nnc_tensor_variable_t x1 = ccv_nnc_tensor_variable_alias_new(graph, x, ccv_nnc_no_ofs, DIM_ALLOC(4, 1), CPU_TENSOR_NHWC(32F, 1, 1));
    189
    1
      ccv_nnc_tensor_variable_t w1 = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 1, 1));
    190
    1
      ccv_nnc_tensor_from_variable(graph, w1)->data.f32[0] = 0.234;
    191
    1
      ccv_nnc_tensor_variable_t b1 = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 1));
    192
    1
      ccv_nnc_tensor_from_variable(graph, b1)->data.f32[0] = 0.1;
    193
    1
      ccv_nnc_tensor_variable_t x11 = ccv_nnc_tensor_variable_alias_new(graph, x, DIM_ALLOC(0, 1), DIM_ALLOC(4, 1), CPU_TENSOR_NHWC(32F, 1, 1));
    194
    1
      ccv_nnc_dynamic_graph_exec(graph, CMD_GEMM_FORWARD(NO_TRANSPOSE, TRANSPOSE(0, 1)), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(x1, w1, b1), TENSOR_VARIABLE_LIST(x11), 0, 0);
    195
    1
      ccv_nnc_tensor_variable_t x2 = ccv_nnc_tensor_variable_alias_new(graph, x, ccv_nnc_no_ofs, DIM_ALLOC(4, 1), CPU_TENSOR_NHWC(32F, 1, 2));
    196
    1
      ccv_nnc_tensor_variable_t w2 = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 1, 2));
    197
    1
      ccv_nnc_tensor_from_variable(graph, w2)->data.f32[0] = 0.374;
    198
    1
      ccv_nnc_tensor_from_variable(graph, w2)->data.f32[1] = 0.886;
    199
    1
      ccv_nnc_tensor_variable_t b2 = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 1));
    200
    1
      ccv_nnc_tensor_from_variable(graph, b2)->data.f32[0] = 0.2;
    201
    1
      ccv_nnc_tensor_variable_t x21 = ccv_nnc_tensor_variable_alias_new(graph, x, DIM_ALLOC(0, 2), DIM_ALLOC(4, 1), CPU_TENSOR_NHWC(32F, 1, 1));
    202
    1
      ccv_nnc_dynamic_graph_exec(graph, CMD_GEMM_FORWARD(NO_TRANSPOSE, TRANSPOSE(0, 1)), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(x2, w2, b2), TENSOR_VARIABLE_LIST(x21), 0, 0);
    203
    1
      ccv_nnc_tensor_variable_t x3 = ccv_nnc_tensor_variable_alias_new(graph, x, ccv_nnc_no_ofs, DIM_ALLOC(4, 1), CPU_TENSOR_NHWC(32F, 1, 3));
    204
    1
      ccv_nnc_tensor_variable_t w3 = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 1, 3));
    205
    1
      ccv_nnc_tensor_from_variable(graph, w3)->data.f32[0] = 0.484;
    206
    1
      ccv_nnc_tensor_from_variable(graph, w3)->data.f32[1] = 0.912;
    207
    1
      ccv_nnc_tensor_from_variable(graph, w3)->data.f32[2] = 0.235;
    208
    1
      ccv_nnc_tensor_variable_t b3 = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 1));
    209
    1
      ccv_nnc_tensor_from_variable(graph, b3)->data.f32[0] = 0.3;
    210
    1
      ccv_nnc_tensor_variable_t x31 = ccv_nnc_tensor_variable_alias_new(graph, x, DIM_ALLOC(0, 3), DIM_ALLOC(4, 1), CPU_TENSOR_NHWC(32F, 1, 1));
    211
    1
      ccv_nnc_dynamic_graph_exec(graph, CMD_GEMM_FORWARD(NO_TRANSPOSE, TRANSPOSE(0, 1)), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(x3, w3, b3), TENSOR_VARIABLE_LIST(x31), 0, 0);
    212
    1
      DYNAMIC_GRAPH_GEN(graph, CCV_NNC_LONG_DOT_GRAPH);
    213
    1
      ccv_nnc_tensor_t* xt = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 1, 4), 0);
    214
    1
      xt->data.f32[0] = 0.472;
    215
    1
      xt->data.f32[1] = xt->data.f32[0] * 0.234 + 0.1;
    216
    1
      xt->data.f32[2] = xt->data.f32[0] * 0.374 + xt->data.f32[1] * 0.886 + 0.2;
    217
    1
      xt->data.f32[3] = xt->data.f32[0] * 0.484 + xt->data.f32[1] * 0.912 + xt->data.f32[2] * 0.235 + 0.3;
    218
    1
      REQUIRE_MATRIX_EQ(ccv_nnc_tensor_from_variable(graph, x), xt, "1x4 matrix should be exactly the same");
    219
    1
      ccv_nnc_tensor_free(xt);
    220
    1
      ccv_nnc_tensor_variable_t dw1 = ccv_nnc_tensor_variable_new(graph);
    221
    1
      ccv_nnc_dynamic_graph_backward(graph, TENSOR_VARIABLE_LIST(x), 0, TENSOR_VARIABLE_LIST(w1), TENSOR_VARIABLE_LIST(dw1), 0);
    222
    1
      REQUIRE_EQ_WITH_TOLERANCE((0.235 * 0.886 + 0.912) * 0.472, ccv_nnc_tensor_from_variable(graph, dw1)->data.f32[0], 1e-5, "the gradient should be equal to a complicated result");
    223
    1
      ccv_nnc_dynamic_graph_free(graph);
    224
    1
    }
    225
    226
    TEST_CASE("batch norm in dynamic graph (enforce inplace)")
    227
    1
    {
    228
    1
      ccv_nnc_dynamic_graph_t* const graph = ccv_nnc_dynamic_graph_new();
    229
    1
      ccv_nnc_tensor_variable_t x = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 2, 2, 2, 10));
    230
    1
      ccv_nnc_tensor_variable_t y = ccv_nnc_tensor_variable_new(graph);
    231
    1
      ccv_nnc_tensor_variable_t scale = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 10));
    232
    1
      ccv_nnc_tensor_variable_t bias = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 10));
    233
    1
      ccv_nnc_tensor_variable_t mean = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 10));
    234
    1
      ccv_nnc_tensor_variable_t var = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 10));
    235
    1
      ccv_nnc_tensor_variable_t saved_mean = ccv_nnc_tensor_variable_new(graph);
    236
    1
      ccv_nnc_tensor_variable_t saved_inv_std = ccv_nnc_tensor_variable_new(graph);
    237
    1
      dsfmt_t dsfmt;
    238
    1
      int i;
    239
    1
      dsfmt_init_gen_rand(&dsfmt, 1);
    240
    81
      for (i = 0; i < 2 * 2 * 2 * 10; i++80)
    241
    80
        ccv_nnc_tensor_from_variable(graph, x)->data.f32[i] = dsfmt_genrand_open_close(&dsfmt);
    242
    11
      for (i = 0; i < 10; i++10)
    243
    10
        ccv_nnc_tensor_from_variable(graph, scale)->data.f32[i] = 1;
    244
    11
      for (i = 0; i < 10; i++10)
    245
    10
        ccv_nnc_tensor_from_variable(graph, bias)->data.f32[i] = 0;
    246
    11
      for (i = 0; i < 10; i++10)
    247
    10
        ccv_nnc_tensor_from_variable(graph, mean)->data.f32[i] = 0;
    248
    1
      ccv_nnc_tensor_t* mean_tensor_ptr = ccv_nnc_tensor_from_variable(graph, mean);
    249
    11
      for (i = 0; i < 10; i++10)
    250
    10
        ccv_nnc_tensor_from_variable(graph, var)->data.f32[i] = 0;
    251
    1
      ccv_nnc_tensor_t* var_tensor_ptr = ccv_nnc_tensor_from_variable(graph, var);
    252
    1
      ccv_nnc_dynamic_graph_exec(graph, CMD_BATCH_NORM_FORWARD(0, 0, 0.9, 0, 1, 2), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(x, scale, bias, mean, var), TENSOR_VARIABLE_LIST(y, mean, var, saved_mean, saved_inv_std), 0, 0);
    253
    1
      DYNAMIC_GRAPH_GEN(graph, CCV_NNC_LONG_DOT_GRAPH);
    254
    1
      REQUIRE(mean_tensor_ptr == ccv_nnc_tensor_from_variable(graph, mean), "enforced inplace, tensor view pointer unchanged");
    255
    1
      REQUIRE(var_tensor_ptr == ccv_nnc_tensor_from_variable(graph, var), "enforced inplace, tensor view pointer unchanged");
    256
    1
      ccv_nnc_tensor_t* x_tensor = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 2, 2, 10), 0);
    257
    1
      ccv_nnc_tensor_t* y_tensor = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 2, 2, 10), 0);
    258
    1
      ccv_nnc_tensor_t* scale_tensor = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 10), 0);
    259
    1
      ccv_nnc_tensor_t* bias_tensor = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 10), 0);
    260
    1
      ccv_nnc_tensor_t* mean_tensor = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 10), 0);
    261
    1
      ccv_nnc_tensor_t* var_tensor = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 10), 0);
    262
    1
      ccv_nnc_tensor_t* saved_mean_tensor = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 1, 1, 1, 10), 0);
    263
    1
      ccv_nnc_tensor_t* saved_inv_std_tensor = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 1, 1, 1, 10), 0);
    264
    1
      memcpy(x_tensor->data.f32, ccv_nnc_tensor_from_variable(graph, x)->data.f32, sizeof(float) * 2 * 2 * 2 * 10);
    265
    11
      for (i = 0; i < 10; i++10)
    266
    10
        scale_tensor->data.f32[i] = 1;
    267
    1
      memset(bias_tensor->data.f32, 0, sizeof(float) * 10);
    268
    1
      memset(mean_tensor->data.f32, 0, sizeof(float) * 10);
    269
    1
      memset(var_tensor->data.f32, 0, sizeof(float) * 10);
    270
    1
      ccv_nnc_cmd_exec(CMD_BATCH_NORM_FORWARD(0, 0, 0.9, 0, 1, 2), ccv_nnc_no_hint, 0, TENSOR_LIST(x_tensor, scale_tensor, bias_tensor, mean_tensor, var_tensor), TENSOR_LIST(y_tensor, mean_tensor, var_tensor, saved_mean_tensor, saved_inv_std_tensor), 0);
    271
    1
      REQUIRE_TENSOR_EQ(y_tensor, ccv_nnc_tensor_from_variable(graph, y), "y should be equal");
    272
    1
      REQUIRE_TENSOR_EQ(mean_tensor, ccv_nnc_tensor_from_variable(graph, mean), "mean should be equal");
    273
    1
      REQUIRE_TENSOR_EQ(var_tensor, ccv_nnc_tensor_from_variable(graph, var), "var should be equal");
    274
    1
      REQUIRE_TENSOR_EQ(saved_mean_tensor, ccv_nnc_tensor_from_variable(graph, saved_mean), "saved_mean should be equal");
    275
    1
      REQUIRE_TENSOR_EQ(saved_inv_std_tensor, ccv_nnc_tensor_from_variable(graph, saved_inv_std), "saved_inv_std should be equal");
    276
    1
      ccv_nnc_dynamic_graph_free(graph);
    277
    1
      ccv_nnc_tensor_free(x_tensor);
    278
    1
      ccv_nnc_tensor_free(y_tensor);
    279
    1
      ccv_nnc_tensor_free(scale_tensor);
    280
    1
      ccv_nnc_tensor_free(bias_tensor);
    281
    1
      ccv_nnc_tensor_free(mean_tensor);
    282
    1
      ccv_nnc_tensor_free(var_tensor);
    283
    1
      ccv_nnc_tensor_free(saved_mean_tensor);
    284
    1
      ccv_nnc_tensor_free(saved_inv_std_tensor);
    285
    1
    }
    286
    287
    TEST_CASE("empty inputs / outputs for dynamic graph")
    288
    1
    {
    289
    1
      ccv_nnc_dynamic_graph_t* const graph = ccv_nnc_dynamic_graph_new();
    290
    1
      ccv_nnc_tensor_variable_t df = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 1));
    291
    1
      ccv_nnc_tensor_variable_t x = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 1));
    292
    1
      ccv_nnc_tensor_variable_t y = ccv_nnc_tensor_variable_new(graph);
    293
    1
      ccv_nnc_tensor_from_variable(graph, df)->data.f32[0] = 1;
    294
    1
      ccv_nnc_tensor_from_variable(graph, x)->data.f32[0] = 10;
    295
    1
      ccv_nnc_dynamic_graph_exec(graph, CMD_EWDIV_BACKWARD(), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(df, 0, x), TENSOR_VARIABLE_LIST(y, 0), 0, 0);
    296
    1
      DYNAMIC_GRAPH_GEN(graph, CCV_NNC_LONG_DOT_GRAPH);
    297
    1
      REQUIRE_EQ_WITH_TOLERANCE(ccv_nnc_tensor_from_variable(graph, y)->data.f32[0], 1. / 10, 1e-5, "div backward should equal to 1 / 10");
    298
    1
      ccv_nnc_dynamic_graph_free(graph);
    299
    1
    }
    300
    301
    TEST_CASE("long dynamic graph with unused variables freed")
    302
    1
    {
    303
    1
      ccv_nnc_dynamic_graph_t* const graph = ccv_nnc_dynamic_graph_new();
    304
    1
      int i;
    305
    1
      ccv_nnc_tensor_variable_t x = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 1));
    306
    1
      ccv_nnc_tensor_variable_t y = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 1));
    307
    1
      ccv_nnc_tensor_from_variable(graph, x)->data.f32[0] = 32;
    308
    1
      ccv_nnc_tensor_from_variable(graph, y)->data.f32[0] = 0.5;
    309
    11
      for (i = 0; i < 10; i++10)
    310
    10
      {
    311
    10
        ccv_nnc_tensor_variable_t z = ccv_nnc_tensor_variable_new(graph);
    312
    10
        if (i < 7)
    313
    7
          ccv_nnc_dynamic_graph_exec(graph, CMD_EWPROD_FORWARD(), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(x, y), TENSOR_VARIABLE_LIST(z), 0, 0);
    314
    3
        else {
    315
    3
          if (i == 7)
    316
    1
            ccv_nnc_tensor_variable_free(graph, y); // No longer need y.
    317
    3
          ccv_nnc_dynamic_graph_exec(graph, CMD_EWPROD_FORWARD(), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(x, x), TENSOR_VARIABLE_LIST(z), 0, 0);
    318
    3
        }
    319
    10
        if (i < 9)
    320
    9
          ccv_nnc_tensor_variable_free(graph, x);
    321
    10
        x = z;
    322
    10
      }
    323
    1
      DYNAMIC_GRAPH_GEN(graph, CCV_NNC_LONG_DOT_GRAPH);
    324
    1
      float g = 32;
    325
    11
      for (i = 0; i < 10; i++10)
    326
    10
      {
    327
    10
        if (i < 7)
    328
    7
          g = g * 0.5;
    329
    3
        else
    330
    3
          g = g * g;
    331
    10
      }
    332
    1
      REQUIRE_EQ_WITH_TOLERANCE(ccv_nnc_tensor_from_variable(graph, x)->data.f32[0], g, 1e-5, "x should equal to the computed result");
    333
    1
      ccv_nnc_dynamic_graph_free(graph);
    334
    1
    }
    335
    336
    TEST_CASE("repeat multiple x * y with y as a constant")
    337
    1
    {
    338
    1
      ccv_nnc_dynamic_graph_t* const graph = ccv_nnc_dynamic_graph_new();
    339
    1
      int i;
    340
    1
      ccv_nnc_tensor_variable_t x = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 1));
    341
    1
      ccv_nnc_tensor_variable_t y = ccv_nnc_tensor_constant_new(graph, CPU_TENSOR_NHWC(32F, 1));
    342
    1
      ccv_nnc_tensor_from_variable(graph, x)->data.f32[0] = 32;
    343
    1
      ccv_nnc_tensor_from_variable(graph, y)->data.f32[0] = 0.5;
    344
    11
      for (i = 0; i < 10; i++10)
    345
    10
      {
    346
    10
        ccv_nnc_tensor_variable_t z = ccv_nnc_tensor_variable_new(graph);
    347
    10
        ccv_nnc_dynamic_graph_exec(graph, CMD_EWPROD_FORWARD(), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(x, y), TENSOR_VARIABLE_LIST(z), 0, 0);
    348
    10
        ccv_nnc_tensor_variable_free(graph, x);
    349
    10
        x = z;
    350
    10
      }
    351
    1
      DYNAMIC_GRAPH_GEN(graph, CCV_NNC_LONG_DOT_GRAPH);
    352
    1
      float g = 32;
    353
    11
      for (i = 0; i < 10; i++10)
    354
    10
        g = g * 0.5;
    355
    1
      REQUIRE_EQ_WITH_TOLERANCE(ccv_nnc_tensor_from_variable(graph, x)->data.f32[0], g, 1e-5, "x should equal to the computed result");
    356
    1
      ccv_nnc_dynamic_graph_free(graph);
    357
    1
    }
    358
    359
    static int _ccv_tensor_variable_freed = 0;
    360
    361
    static void _ccv_tensor_variable_hook(ccv_nnc_dynamic_graph_t* const graph, const ccv_nnc_tensor_t* const tensor, void* const context)
    362
    7
    {
    363
    7
      ++_ccv_tensor_variable_freed;
    364
    7
    }
    365
    366
    TEST_CASE("repeat multiple x * y with y as a constant, compute d(x)")
    367
    1
    {
    368
    1
      ccv_nnc_dynamic_graph_t* const graph = ccv_nnc_dynamic_graph_new();
    369
    1
      int i;
    370
    1
      _ccv_tensor_variable_freed = 0;
    371
    1
      ccv_nnc_tensor_variable_t x = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 1));
    372
    1
      ccv_nnc_tensor_variable_t y = ccv_nnc_tensor_constant_new(graph, CPU_TENSOR_NHWC(32F, 1));
    373
    1
      ccv_nnc_tensor_variable_t ox = x;
    374
    1
      ccv_nnc_tensor_variable_destructor_hook(graph, x, _ccv_tensor_variable_hook, 0);
    375
    1
      ccv_nnc_tensor_variable_destructor_hook(graph, y, _ccv_tensor_variable_hook, 0);
    376
    1
      ccv_nnc_tensor_from_variable(graph, x)->data.f32[0] = 32;
    377
    1
      ccv_nnc_tensor_from_variable(graph, y)->data.f32[0] = 0.9;
    378
    5
      for (i = 0; i < 4; i++4)
    379
    4
      {
    380
    4
        ccv_nnc_tensor_variable_t z = ccv_nnc_tensor_variable_new(graph);
    381
    4
        ccv_nnc_tensor_variable_destructor_hook(graph, z, _ccv_tensor_variable_hook, 0);
    382
    4
        ccv_nnc_dynamic_graph_exec(graph, CMD_EWPROD_FORWARD(), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(x, y), TENSOR_VARIABLE_LIST(z), 0, 0);
    383
    4
        if (i > 0)
    384
    3
          ccv_nnc_tensor_variable_free(graph, x);
    385
    4
        x = z;
    386
    4
      }
    387
    1
      REQUIRE_EQ(0, _ccv_tensor_variable_freed, "none of these are freed");
    388
    1
      ccv_nnc_tensor_variable_t dx = ccv_nnc_tensor_variable_new(graph);
    389
    1
      ccv_nnc_tensor_variable_destructor_hook(graph, dx, _ccv_tensor_variable_hook, 0);
    390
    1
      ccv_nnc_dynamic_graph_backward(graph, TENSOR_VARIABLE_LIST(x), 0, TENSOR_VARIABLE_LIST(ox), TENSOR_VARIABLE_LIST(dx), 0);
    391
    1
      ccv_nnc_tensor_variable_free(graph, ox);
    392
      // We freed all 4 x (ox, when i = 1, 2, 3).
    393
    1
      REQUIRE_EQ(4, _ccv_tensor_variable_freed, "all are freed except dx");
    394
    1
      _ccv_tensor_variable_freed = 0;
    395
    1
      DYNAMIC_GRAPH_GEN(graph, CCV_NNC_LONG_DOT_GRAPH);
    396
    1
      float g = 1;
    397
    5
      for (i = 0; i < 4; i++4)
    398
    4
        g = g * 0.9;
    399
    1
      REQUIRE_EQ_WITH_TOLERANCE(ccv_nnc_tensor_from_variable(graph, dx)->data.f32[0], g, 1e-5, "x should equal to the computed result");
    400
    1
      ccv_nnc_dynamic_graph_free(graph);
    401
      // y, dx, and z.
    402
    1
      REQUIRE_EQ(3, _ccv_tensor_variable_freed, "dx freed");
    403
    1
    }
    404
    405
    TEST_CASE("compute f(x) = x * log(x) + x, f'(x) when x = 10 (and intermediate results all freed)")
    406
    1
    {
    407
    1
      ccv_nnc_dynamic_graph_t* const graph = ccv_nnc_dynamic_graph_new();
    408
    1
      ccv_nnc_tensor_variable_t x = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 1));
    409
    1
      ccv_nnc_tensor_variable_t y = ccv_nnc_tensor_variable_new(graph);
    410
    1
      ccv_nnc_tensor_variable_t f = ccv_nnc_tensor_variable_new(graph);
    411
    1
      ccv_nnc_tensor_from_variable(graph, x)->data.f32[0] = 10;
    412
    1
      ccv_nnc_dynamic_graph_exec(graph, CMD_EWLOG_FORWARD(), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(x), TENSOR_VARIABLE_LIST(y), 0, 0);
    413
    1
      ccv_nnc_dynamic_graph_exec(graph, CMD_EWPROD_FORWARD(), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(x, y), TENSOR_VARIABLE_LIST(y), 0, 0);
    414
    1
      ccv_nnc_dynamic_graph_exec(graph, CMD_EWSUM_FORWARD(), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(y, x), TENSOR_VARIABLE_LIST(f), 0, 0);
    415
    1
      ccv_nnc_tensor_variable_t df = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 1));
    416
    1
      ccv_nnc_dynamic_graph_exec(graph, CMD_SET_FORWARD(1), ccv_nnc_no_hint, 0, 0, 0, TENSOR_VARIABLE_LIST(df), 0, 0);
    417
      // x will be accumulated on to itself.
    418
    1
      ccv_nnc_dynamic_graph_backward(graph, TENSOR_VARIABLE_LIST(f), &df, TENSOR_VARIABLE_LIST(x), TENSOR_VARIABLE_LIST(x), 0);
    419
    1
      DYNAMIC_GRAPH_GEN(graph, CCV_NNC_LONG_DOT_GRAPH);
    420
    1
      REQUIRE_EQ_WITH_TOLERANCE(ccv_nnc_tensor_from_variable(graph, x)->data.f32[0], 10 + log(10) + 1 + 1, 1e-5, "dx should equal to the computed result");
    421
    1
      ccv_nnc_dynamic_graph_free(graph);
    422
    1
    }
    423
    424
    TEST_CASE("dynamic graph with binded value")
    425
    1
    {
    426
    1
      ccv_nnc_dynamic_graph_t* const graph = ccv_nnc_dynamic_graph_new();
    427
    1
      ccv_nnc_tensor_variable_t x = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 1));
    428
    1
      ccv_nnc_tensor_t* const x_tensor = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 1), 0);
    429
    1
      x_tensor->data.f32[0] = 10;
    430
    1
      ccv_nnc_tensor_variable_set(graph, x, x_tensor);
    431
    1
      ccv_nnc_tensor_variable_t y = ccv_nnc_tensor_variable_new(graph);
    432
    1
      ccv_nnc_dynamic_graph_exec(graph, CMD_EWLOG_FORWARD(), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(x), TENSOR_VARIABLE_LIST(y), 0, 0);
    433
    1
      DYNAMIC_GRAPH_GEN(graph, CCV_NNC_LONG_DOT_GRAPH);
    434
    1
      REQUIRE_EQ_WITH_TOLERANCE(ccv_nnc_tensor_from_variable(graph, y)->data.f32[0], log(10), 1e-5, "dx should equal to the computed result");
    435
    1
      ccv_nnc_dynamic_graph_free(graph);
    436
    1
      ccv_nnc_tensor_free(x_tensor);
    437
    1
    }
    438
    439
    TEST_CASE("dynamic graph to evaluate cnnp model")
    440
    1
    {
    441
    1
      ccv_nnc_dynamic_graph_t* const graph = ccv_nnc_dynamic_graph_new();
    442
    1
      ccv_cnnp_model_t* const linear = ccv_cnnp_dense(1, 0, 0, 1, 0);
    443
    1
      ccv_nnc_tensor_variable_t z = ccv_nnc_tensor_constant_new(graph, CPU_TENSOR_NHWC(32F, 1));
    444
    1
      ccv_nnc_tensor_from_variable(graph, z)->data.f32[0] = 5;
    445
    1
      int i;
    446
    101
      for (i = 0; i < 100; i++100)
    447
    100
      {
    448
    100
        ccv_nnc_tensor_variable_t x;
    449
    100
        if (i % 2 == 1)
    450
    50
        {
    451
    50
          x = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 2, 1));
    452
    50
          ccv_nnc_tensor_from_variable(graph, x)->data.f32[0] = 10;
    453
    50
          ccv_nnc_tensor_from_variable(graph, x)->data.f32[1] = 10;
    454
    50
        } else {
    455
    50
          x = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 1));
    456
    50
          ccv_nnc_tensor_from_variable(graph, x)->data.f32[0] = 10;
    457
    50
        }
    458
    100
        ccv_nnc_tensor_variable_t y = ccv_nnc_tensor_variable_new(graph);
    459
    100
        ccv_nnc_dynamic_graph_exec(graph, CMD_EWLOG_FORWARD(), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(x), TENSOR_VARIABLE_LIST(y), 0, 0);
    460
    100
        ccv_nnc_dynamic_graph_evaluate(graph, linear, 0, TENSOR_VARIABLE_LIST(y), TENSOR_VARIABLE_LIST(y), 0, 0);
    461
    100
        ccv_nnc_dynamic_graph_exec(graph, CMD_ADD_FORWARD(1, -1), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(y, z), TENSOR_VARIABLE_LIST(y), 0, 0);
    462
    100
        ccv_nnc_tensor_variable_t f = ccv_nnc_tensor_variable_new(graph);
    463
    100
        ccv_nnc_dynamic_graph_exec(graph, CMD_EWPROD_FORWARD(), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(y, y), TENSOR_VARIABLE_LIST(f), 0, 0);
    464
    100
        ccv_nnc_tensor_variable_t dx = ccv_nnc_tensor_variable_new(graph);
    465
    100
        ccv_nnc_dynamic_graph_backward(graph, TENSOR_VARIABLE_LIST(f), 0, TENSOR_VARIABLE_LIST(x), TENSOR_VARIABLE_LIST(dx), 0);
    466
    100
        ccv_cnnp_model_set_minimizer(linear, CMD_SGD_FORWARD(0, 0.01, 1, 0.01, 0, 0), 0, 0, 0);
    467
    100
        ccv_nnc_dynamic_graph_apply_gradients(graph, CMD_SGD_FORWARD(0, 0.01, 1, 0.01, 0, 0), TENSOR_VARIABLE_LIST(), TENSOR_VARIABLE_LIST(), 0, 0, 0);
    468
    100
        ccv_nnc_tensor_variable_free(graph, x);
    469
    100
        ccv_nnc_tensor_variable_free(graph, y);
    470
    100
        ccv_nnc_tensor_variable_free(graph, f);
    471
    100
        ccv_nnc_tensor_variable_free(graph, dx);
    472
    100
      }
    473
    1
      ccv_nnc_tensor_variable_t x = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 1));
    474
    1
      ccv_nnc_tensor_from_variable(graph, x)->data.f32[0] = 10;
    475
    1
      ccv_nnc_tensor_variable_t y = ccv_nnc_tensor_variable_new(graph);
    476
    1
      ccv_nnc_dynamic_graph_exec(graph, CMD_EWLOG_FORWARD(), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(x), TENSOR_VARIABLE_LIST(y), 0, 0);
    477
    1
      ccv_nnc_dynamic_graph_evaluate(graph, linear, 1, TENSOR_VARIABLE_LIST(y), TENSOR_VARIABLE_LIST(y), 0, 0);
    478
    1
      REQUIRE_EQ_WITH_TOLERANCE(ccv_nnc_tensor_from_variable(graph, y)->data.f32[0], 5, 1e-2, "linear model should be trained to generate the same value as z");
    479
    1
      ccv_nnc_tensor_variable_t iy = ccv_nnc_tensor_constant_new(graph, CPU_TENSOR_NHWC(32F, 1));
    480
    1
      ccv_nnc_tensor_from_variable(graph, iy)->data.f32[0] = log(10);
    481
    1
      ccv_nnc_tensor_variable_t iz = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 1));
    482
    1
      ccv_nnc_dynamic_graph_evaluate(graph, linear, 1, TENSOR_VARIABLE_LIST(iy), TENSOR_VARIABLE_LIST(iz), 0, 0);
    483
    1
      REQUIRE_EQ_WITH_TOLERANCE(ccv_nnc_tensor_from_variable(graph, iz)->data.f32[0], 5, 1e-2, "linear model should be trained to generate the same value as z");
    484
    1
      DYNAMIC_GRAPH_GEN(graph, CCV_NNC_LONG_DOT_GRAPH);
    485
    1
      ccv_nnc_dynamic_graph_free(graph);
    486
    1
      ccv_cnnp_model_free(linear);
    487
    1
    }
    488
    489
    TEST_CASE("dynamic graph to evaluate cnnp model without any parameters")
    490
    1
    {
    491
    1
      ccv_nnc_dynamic_graph_t* const graph = ccv_nnc_dynamic_graph_new();
    492
    1
      ccv_nnc_tensor_variable_t a = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 1));
    493
    1
      ccv_nnc_tensor_from_variable(graph, a)->data.f32[0] = 1.23;
    494
    1
      ccv_nnc_tensor_variable_t b = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 1));
    495
    1
      ccv_nnc_tensor_from_variable(graph, b)->data.f32[0] = 2;
    496
    1
      ccv_nnc_tensor_variable_t c = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 1));
    497
    1
      ccv_cnnp_model_t* const mul = ccv_cnnp_mul(1, "mul");
    498
    1
      ccv_nnc_dynamic_graph_evaluate(graph, mul, 1, TENSOR_VARIABLE_LIST(a, b), TENSOR_VARIABLE_LIST(c), 0, 0);
    499
    1
      ccv_nnc_tensor_variable_t da = ccv_nnc_tensor_variable_new(graph);
    500
    1
      ccv_nnc_dynamic_graph_backward(graph, TENSOR_VARIABLE_LIST(c), 0, TENSOR_VARIABLE_LIST(a), TENSOR_VARIABLE_LIST(da), 0);
    501
    1
      ccv_cnnp_model_set_minimizer(mul, CMD_SGD_FORWARD(0, 0.01, 1, 0.01, 0, 0), 0, 0, 0);
    502
    1
      ccv_nnc_dynamic_graph_apply_gradients(graph, CMD_SGD_FORWARD(0, 0.01, 1, 0.01, 0, 0), TENSOR_VARIABLE_LIST(), TENSOR_VARIABLE_LIST(), 0, 0, 0);
    503
    1
      ccv_cnnp_model_free(mul);
    504
    1
      REQUIRE_EQ_WITH_TOLERANCE(ccv_nnc_tensor_from_variable(graph, c)->data.f32[0], 2.46, 1e-5, "should be equal");
    505
    1
      REQUIRE_EQ_WITH_TOLERANCE(ccv_nnc_tensor_from_variable(graph, da)->data.f32[0], 2, 1e-5, "should be equal");
    506
    1
      ccv_nnc_dynamic_graph_free(graph);
    507
    1
    }
    508
    509
    TEST_CASE("dynamic graph to evaluate cnnp model without any parameters with div")
    510
    1
    {
    511
    1
      ccv_nnc_dynamic_graph_t* const graph = ccv_nnc_dynamic_graph_new();
    512
    1
      ccv_nnc_tensor_variable_t a = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 1));
    513
    1
      ccv_nnc_tensor_from_variable(graph, a)->data.f32[0] = 1.23;
    514
    1
      ccv_nnc_tensor_variable_t b = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 1));
    515
    1
      ccv_nnc_tensor_from_variable(graph, b)->data.f32[0] = 2;
    516
    1
      ccv_nnc_tensor_variable_t c = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 1));
    517
    1
      ccv_cnnp_model_t* const div = ccv_cnnp_div(0, "div");
    518
    1
      ccv_nnc_dynamic_graph_evaluate(graph, div, 1, TENSOR_VARIABLE_LIST(a, b), TENSOR_VARIABLE_LIST(c), 0, 0);
    519
    1
      ccv_nnc_tensor_variable_t da = ccv_nnc_tensor_variable_new(graph);
    520
    1
      ccv_nnc_dynamic_graph_backward(graph, TENSOR_VARIABLE_LIST(c), 0, TENSOR_VARIABLE_LIST(a), TENSOR_VARIABLE_LIST(da), 0);
    521
    1
      ccv_cnnp_model_set_minimizer(div, CMD_SGD_FORWARD(0, 0.01, 1, 0.01, 0, 0), 0, 0, 0);
    522
    1
      ccv_nnc_dynamic_graph_apply_gradients(graph, CMD_SGD_FORWARD(0, 0.01, 1, 0.01, 0, 0), TENSOR_VARIABLE_LIST(), TENSOR_VARIABLE_LIST(), 0, 0, 0);
    523
    1
      ccv_cnnp_model_free(div);
    524
    1
      REQUIRE_EQ_WITH_TOLERANCE(ccv_nnc_tensor_from_variable(graph, c)->data.f32[0], 1.23 / 2, 1e-5, "should be equal");
    525
    1
      REQUIRE_EQ_WITH_TOLERANCE(ccv_nnc_tensor_from_variable(graph, da)->data.f32[0], 1.0 / 2, 1e-5, "should be equal");
    526
    1
      ccv_nnc_dynamic_graph_free(graph);
    527
    1
    }
    528
    529
    TEST_CASE("dynamic graph to evaluate cnnp model without any parameters with reciprocal")
    530
    1
    {
    531
    1
      ccv_nnc_dynamic_graph_t* const graph = ccv_nnc_dynamic_graph_new();
    532
    1
      ccv_nnc_tensor_variable_t a = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 1));
    533
    1
      ccv_nnc_tensor_from_variable(graph, a)->data.f32[0] = 1.23;
    534
    1
      ccv_nnc_tensor_variable_t c = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 1));
    535
    1
      ccv_cnnp_model_t* const div = ccv_cnnp_div(1, "div");
    536
    1
      ccv_nnc_dynamic_graph_evaluate(graph, div, 1, TENSOR_VARIABLE_LIST(a), TENSOR_VARIABLE_LIST(c), 0, 0);
    537
    1
      ccv_nnc_tensor_variable_t da = ccv_nnc_tensor_variable_new(graph);
    538
    1
      ccv_nnc_dynamic_graph_backward(graph, TENSOR_VARIABLE_LIST(c), 0, TENSOR_VARIABLE_LIST(a), TENSOR_VARIABLE_LIST(da), 0);
    539
    1
      ccv_cnnp_model_set_minimizer(div, CMD_SGD_FORWARD(0, 0.01, 1, 0.01, 0, 0), 0, 0, 0);
    540
    1
      ccv_nnc_dynamic_graph_apply_gradients(graph, CMD_SGD_FORWARD(0, 0.01, 1, 0.01, 0, 0), TENSOR_VARIABLE_LIST(), TENSOR_VARIABLE_LIST(), 0, 0, 0);
    541
    1
      ccv_cnnp_model_free(div);
    542
    1
      REQUIRE_EQ_WITH_TOLERANCE(ccv_nnc_tensor_from_variable(graph, c)->data.f32[0], 1 / 1.23, 1e-5, "should be equal");
    543
    1
      REQUIRE_EQ_WITH_TOLERANCE(ccv_nnc_tensor_from_variable(graph, da)->data.f32[0], -1 / (1.23 * 1.23), 1e-5, "should be equal");
    544
    1
      ccv_nnc_dynamic_graph_free(graph);
    545
    1
    }
    546
    547
    TEST_CASE("dynamic graph to evaluate cnnp model without any parameters with log")
    548
    1
    {
    549
    1
      ccv_nnc_dynamic_graph_t* const graph = ccv_nnc_dynamic_graph_new();
    550
    1
      ccv_nnc_tensor_variable_t a = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 1));
    551
    1
      ccv_nnc_tensor_from_variable(graph, a)->data.f32[0] = 1.23;
    552
    1
      ccv_nnc_tensor_variable_t c = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 1));
    553
    1
      ccv_cnnp_model_t* const log = ccv_cnnp_log("log");
    554
    1
      ccv_nnc_dynamic_graph_evaluate(graph, log, 1, TENSOR_VARIABLE_LIST(a), TENSOR_VARIABLE_LIST(c), 0, 0);
    555
    1
      ccv_cnnp_model_free(log);
    556
    1
      REQUIRE_EQ_WITH_TOLERANCE(ccv_nnc_tensor_from_variable(graph, c)->data.f32[0], logf(1.23), 1e-5, "should be equal");
    557
    1
      ccv_nnc_dynamic_graph_free(graph);
    558
    1
    }
    559
    560
    TEST_CASE("dynamic graph to evaluate cnnp model without any parameters with pow")
    561
    1
    {
    562
    1
      ccv_nnc_dynamic_graph_t* const graph = ccv_nnc_dynamic_graph_new();
    563
    1
      ccv_nnc_tensor_variable_t a = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 1));
    564
    1
      ccv_nnc_tensor_from_variable(graph, a)->data.f32[0] = 2;
    565
    1
      ccv_nnc_tensor_variable_t c = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 1));
    566
    1
      ccv_cnnp_model_t* const pow = ccv_cnnp_pow(3, "pow");
    567
    1
      ccv_nnc_dynamic_graph_evaluate(graph, pow, 1, TENSOR_VARIABLE_LIST(a), TENSOR_VARIABLE_LIST(c), 0, 0);
    568
    1
      ccv_nnc_tensor_variable_t da = ccv_nnc_tensor_variable_new(graph);
    569
    1
      ccv_nnc_dynamic_graph_backward(graph, TENSOR_VARIABLE_LIST(c), 0, TENSOR_VARIABLE_LIST(a), TENSOR_VARIABLE_LIST(da), 0);
    570
    1
      ccv_cnnp_model_set_minimizer(pow, CMD_SGD_FORWARD(0, 0.01, 1, 0.01, 0, 0), 0, 0, 0);
    571
    1
      ccv_nnc_dynamic_graph_apply_gradients(graph, CMD_SGD_FORWARD(0, 0.01, 1, 0.01, 0, 0), TENSOR_VARIABLE_LIST(), TENSOR_VARIABLE_LIST(), 0, 0, 0);
    572
    1
      ccv_cnnp_model_free(pow);
    573
    1
      REQUIRE_EQ_WITH_TOLERANCE(ccv_nnc_tensor_from_variable(graph, c)->data.f32[0], 8, 1e-5, "should be equal");
    574
    1
      REQUIRE_EQ_WITH_TOLERANCE(ccv_nnc_tensor_from_variable(graph, da)->data.f32[0], 12, 1e-5, "should be equal");
    575
    1
      ccv_nnc_dynamic_graph_free(graph);
    576
    1
    }
    577
    578
    TEST_CASE("dynamic graph to evaluate cnnp model without any parameters with sin")
    579
    1
    {
    580
    1
      ccv_nnc_dynamic_graph_t* const graph = ccv_nnc_dynamic_graph_new();
    581
    1
      ccv_nnc_tensor_variable_t a = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 1));
    582
    1
      ccv_nnc_tensor_from_variable(graph, a)->data.f32[0] = 0.5;
    583
    1
      ccv_nnc_tensor_variable_t c = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 1));
    584
    1
      ccv_cnnp_model_t* const sin = ccv_cnnp_sin("sin");
    585
    1
      ccv_nnc_dynamic_graph_evaluate(graph, sin, 1, TENSOR_VARIABLE_LIST(a), TENSOR_VARIABLE_LIST(c), 0, 0);
    586
    1
      ccv_nnc_tensor_variable_t da = ccv_nnc_tensor_variable_new(graph);
    587
    1
      ccv_nnc_dynamic_graph_backward(graph, TENSOR_VARIABLE_LIST(c), 0, TENSOR_VARIABLE_LIST(a), TENSOR_VARIABLE_LIST(da), 0);
    588
    1
      ccv_cnnp_model_set_minimizer(sin, CMD_SGD_FORWARD(0, 0.01, 1, 0.01, 0, 0), 0, 0, 0);
    589
    1
      ccv_nnc_dynamic_graph_apply_gradients(graph, CMD_SGD_FORWARD(0, 0.01, 1, 0.01, 0, 0), TENSOR_VARIABLE_LIST(), TENSOR_VARIABLE_LIST(), 0, 0, 0);
    590
    1
      ccv_cnnp_model_free(sin);
    591
    1
      REQUIRE_EQ_WITH_TOLERANCE(ccv_nnc_tensor_from_variable(graph, c)->data.f32[0], sinf(0.5), 1e-5, "should be equal");
    592
    1
      REQUIRE_EQ_WITH_TOLERANCE(ccv_nnc_tensor_from_variable(graph, da)->data.f32[0], cosf(0.5), 1e-5, "should be equal");
    593
    1
      ccv_nnc_dynamic_graph_free(graph);
    594
    1
    }
    595
    596
    TEST_CASE("dynamic graph to evaluate cnnp model without any parameters with cos")
    597
    1
    {
    598
    1
      ccv_nnc_dynamic_graph_t* const graph = ccv_nnc_dynamic_graph_new();
    599
    1
      ccv_nnc_tensor_variable_t a = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 1));
    600
    1
      ccv_nnc_tensor_from_variable(graph, a)->data.f32[0] = 0.5;
    601
    1
      ccv_nnc_tensor_variable_t c = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 1));
    602
    1
      ccv_cnnp_model_t* const cos = ccv_cnnp_cos("cos");
    603
    1
      ccv_nnc_dynamic_graph_evaluate(graph, cos, 1, TENSOR_VARIABLE_LIST(a), TENSOR_VARIABLE_LIST(c), 0, 0);
    604
    1
      ccv_nnc_tensor_variable_t da = ccv_nnc_tensor_variable_new(graph);
    605
    1
      ccv_nnc_dynamic_graph_backward(graph, TENSOR_VARIABLE_LIST(c), 0, TENSOR_VARIABLE_LIST(a), TENSOR_VARIABLE_LIST(da), 0);
    606
    1
      ccv_cnnp_model_set_minimizer(cos, CMD_SGD_FORWARD(0, 0.01, 1, 0.01, 0, 0), 0, 0, 0);
    607
    1
      ccv_nnc_dynamic_graph_apply_gradients(graph, CMD_SGD_FORWARD(0, 0.01, 1, 0.01, 0, 0), TENSOR_VARIABLE_LIST(), TENSOR_VARIABLE_LIST(), 0, 0, 0);
    608
    1
      ccv_cnnp_model_free(cos);
    609
    1
      REQUIRE_EQ_WITH_TOLERANCE(ccv_nnc_tensor_from_variable(graph, c)->data.f32[0], cosf(0.5), 1e-5, "should be equal");
    610
    1
      REQUIRE_EQ_WITH_TOLERANCE(ccv_nnc_tensor_from_variable(graph, da)->data.f32[0], -sinf(0.5), 1e-5, "should be equal");
    611
    1
      ccv_nnc_dynamic_graph_free(graph);
    612
    1
    }
    613
    614
    TEST_CASE("dynamic graph to evaluate cnnp model and simply accumulate gradients")
    615
    1
    {
    616
    1
      ccv_nnc_dynamic_graph_t* const graph = ccv_nnc_dynamic_graph_new();
    617
    1
      ccv_cnnp_model_t* const linear = ccv_cnnp_dense(1, 0, 0, 1, 0);
    618
    1
      ccv_nnc_tensor_variable_t z = ccv_nnc_tensor_constant_new(graph, CPU_TENSOR_NHWC(32F, 1));
    619
    1
      ccv_nnc_tensor_from_variable(graph, z)->data.f32[0] = 5;
    620
    1
      int i;
    621
    101
      for (i = 0; i < 100; i++100)
    622
    100
      {
    623
    100
        ccv_nnc_tensor_variable_t x;
    624
    100
        if (i % 2 == 1)
    625
    50
        {
    626
    50
          x = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 2, 1));
    627
    50
          ccv_nnc_tensor_from_variable(graph, x)->data.f32[0] = 10;
    628
    50
          ccv_nnc_tensor_from_variable(graph, x)->data.f32[1] = 10;
    629
    50
        } else {
    630
    50
          x = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 1));
    631
    50
          ccv_nnc_tensor_from_variable(graph, x)->data.f32[0] = 10;
    632
    50
        }
    633
    100
        ccv_nnc_tensor_variable_t y = ccv_nnc_tensor_variable_new(graph);
    634
    100
        ccv_nnc_dynamic_graph_exec(graph, CMD_EWLOG_FORWARD(), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(x), TENSOR_VARIABLE_LIST(y), 0, 0);
    635
    100
        ccv_nnc_dynamic_graph_evaluate(graph, linear, 0, TENSOR_VARIABLE_LIST(y), TENSOR_VARIABLE_LIST(y), 0, 0);
    636
    100
        ccv_nnc_dynamic_graph_exec(graph, CMD_ADD_FORWARD(1, -1), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(y, z), TENSOR_VARIABLE_LIST(y), 0, 0);
    637
    100
        ccv_nnc_tensor_variable_t f = ccv_nnc_tensor_variable_new(graph);
    638
    100
        ccv_nnc_dynamic_graph_exec(graph, CMD_EWPROD_FORWARD(), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(y, y), TENSOR_VARIABLE_LIST(f), 0, 0);
    639
    100
        ccv_nnc_tensor_variable_t dx = ccv_nnc_tensor_variable_new(graph);
    640
    100
        ccv_nnc_dynamic_graph_backward(graph, TENSOR_VARIABLE_LIST(f), 0, TENSOR_VARIABLE_LIST(x), TENSOR_VARIABLE_LIST(dx), 0);
    641
    100
        ccv_nnc_tensor_variable_free(graph, x);
    642
    100
        ccv_nnc_tensor_variable_free(graph, y);
    643
    100
        ccv_nnc_tensor_variable_free(graph, f);
    644
    100
        ccv_nnc_tensor_variable_free(graph, dx);
    645
    100
        if ((i % 2) == 1)
    646
    50
        {
    647
    50
          ccv_cnnp_model_set_minimizer(linear, CMD_SGD_FORWARD(0, 0.01, 1, 0.01, 0, 0), 0, 0, 0);
    648
    50
          ccv_nnc_dynamic_graph_apply_gradients(graph, CMD_SGD_FORWARD(0, 0.01, 1, 0.01, 0, 0), TENSOR_VARIABLE_LIST(), TENSOR_VARIABLE_LIST(), 0, 0, 0);
    649
    50
        }
    650
    100
      }
    651
    1
      ccv_nnc_tensor_variable_t x = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 1));
    652
    1
      ccv_nnc_tensor_from_variable(graph, x)->data.f32[0] = 10;
    653
    1
      ccv_nnc_tensor_variable_t y = ccv_nnc_tensor_variable_new(graph);
    654
    1
      ccv_nnc_dynamic_graph_exec(graph, CMD_EWLOG_FORWARD(), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(x), TENSOR_VARIABLE_LIST(y), 0, 0);
    655
    1
      ccv_nnc_dynamic_graph_evaluate(graph, linear, 1, TENSOR_VARIABLE_LIST(y), TENSOR_VARIABLE_LIST(y), 0, 0);
    656
    1
      REQUIRE_EQ_WITH_TOLERANCE(ccv_nnc_tensor_from_variable(graph, y)->data.f32[0], 5, 1e-2, "linear model should be trained to generate the same value as z");
    657
    1
      DYNAMIC_GRAPH_GEN(graph, CCV_NNC_LONG_DOT_GRAPH);
    658
    1
      ccv_nnc_dynamic_graph_free(graph);
    659
    1
      ccv_cnnp_model_free(linear);
    660
    1
    }
    661
    662
    TEST_CASE("dynamic graph to accumulate gradients cross cnnp models")
    663
    1
    {
    664
    1
      ccv_nnc_dynamic_graph_t* const graph = ccv_nnc_dynamic_graph_new();
    665
    1
      ccv_cnnp_model_t* const linear = ccv_cnnp_dense(1, 1, 0, 1, 0);
    666
    1
      ccv_nnc_tensor_variable_t a = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 1));
    667
    1
      ccv_nnc_dynamic_graph_exec(graph, CMD_SET_FORWARD(0.2485), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(), TENSOR_VARIABLE_LIST(a), 0, 0);
    668
    1
      const ccv_nnc_tensor_param_t input = CPU_TENSOR_NHWC(32F, 1);
    669
    1
      ccv_cnnp_model_compile(linear, &input, 1, CMD_NOOP(), CMD_NOOP());
    670
    1
      ccv_cnnp_model_set_parameter(linear, ccv_cnnp_model_parameters(linear, CCV_CNNP_PARAMETER_SELECT_WEIGHT, 0), ccv_nnc_tensor_from_variable(graph, a));
    671
    1
      ccv_nnc_tensor_variable_t a_grad = ccv_nnc_tensor_variable_new(graph);
    672
    1
      ccv_nnc_tensor_variable_t saved_aux = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 1));
    673
    1
      int i;
    674
    1.00k
      for (i = 0; i < 1000; i++1.00k)
    675
    1.00k
      {
    676
    1.00k
        ccv_nnc_tensor_variable_t x = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 1));
    677
    1.00k
        ccv_nnc_tensor_from_variable(graph, x)->data.f32[0] = i;
    678
    1.00k
        ccv_nnc_tensor_variable_t t = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 1));
    679
    1.00k
        ccv_nnc_tensor_from_variable(graph, t)->data.f32[0] = -i;
    680
    1.00k
        ccv_nnc_tensor_variable_t y = ccv_nnc_tensor_variable_new(graph);
    681
    1.00k
        ccv_nnc_dynamic_graph_exec(graph, CMD_MUL_FORWARD(1), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(x, a), TENSOR_VARIABLE_LIST(y), 0, 0);
    682
    1.00k
        ccv_nnc_tensor_variable_t z = ccv_nnc_tensor_variable_new(graph);
    683
    1.00k
        ccv_nnc_dynamic_graph_evaluate(graph, linear, 0, TENSOR_VARIABLE_LIST(y), TENSOR_VARIABLE_LIST(z), 0, 0);
    684
    1.00k
        ccv_nnc_tensor_variable_t n = ccv_nnc_tensor_variable_new(graph);
    685
    1.00k
        ccv_nnc_dynamic_graph_exec(graph, CMD_ADD_FORWARD(1, -1), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(z, t), TENSOR_VARIABLE_LIST(n), 0, 0);
    686
    1.00k
        ccv_nnc_tensor_variable_t f = ccv_nnc_tensor_variable_new(graph);
    687
    1.00k
        ccv_nnc_dynamic_graph_exec(graph, CMD_MUL_FORWARD(1), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(n, n), TENSOR_VARIABLE_LIST(f), 0, 0);
    688
    1.00k
        ccv_nnc_dynamic_graph_backward(graph, TENSOR_VARIABLE_LIST(f), 0, TENSOR_VARIABLE_LIST(a), TENSOR_VARIABLE_LIST(a_grad), 0);
    689
    1.00k
        ccv_nnc_tensor_variable_free(graph, n);
    690
    1.00k
        ccv_nnc_tensor_variable_free(graph, z);
    691
    1.00k
        ccv_nnc_tensor_variable_free(graph, y);
    692
    1.00k
        ccv_nnc_tensor_variable_free(graph, x);
    693
    1.00k
        ccv_nnc_tensor_variable_free(graph, t);
    694
    1.00k
        ccv_nnc_tensor_variable_free(graph, f);
    695
    1.00k
        if (((i + 1) % 5) == 0)
    696
    200
        {
    697
    200
          DYNAMIC_GRAPH_GEN(graph, CCV_NNC_LONG_DOT_GRAPH);
    698
    200
          REQUIRE_EQ(ccv_nnc_dynamic_graph_bookkeeping_count(graph, CCV_NNC_SYMBOL_GRAPH_EXEC), 0, "everything should be freed");
    699
    200
          float lr = 0.001;
    700
    200
          if (i >= 200)
    701
    160
            lr = 0.0001;
    702
    40
          else if (i >= 600)
    703
    0
            lr = 0.00001;
    704
    200
          ccv_cnnp_model_set_minimizer(linear, CMD_SGD_FORWARD(0, lr, 0.001, 0, 0, 0), 0, 0, 0);
    705
    200
          ccv_nnc_dynamic_graph_apply_gradients(graph, CMD_SGD_FORWARD(0, lr, 0.001, 0, 0, 0), TENSOR_VARIABLE_LIST(a_grad), TENSOR_VARIABLE_LIST(a), &saved_aux, 0, 0);
    706
    200
        }
    707
    1.00k
      }
    708
    1
      ccv_nnc_tensor_variable_t x = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 1));
    709
    1
      ccv_nnc_tensor_from_variable(graph, x)->data.f32[0] = 5;
    710
    1
      ccv_nnc_tensor_variable_t y = ccv_nnc_tensor_variable_new(graph);
    711
    1
      ccv_nnc_dynamic_graph_exec(graph, CMD_MUL_FORWARD(1), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(x, a), TENSOR_VARIABLE_LIST(y), 0, 0);
    712
    1
      ccv_nnc_tensor_variable_t z = ccv_nnc_tensor_variable_new(graph);
    713
    1
      ccv_nnc_dynamic_graph_evaluate(graph, linear, 0, TENSOR_VARIABLE_LIST(y), TENSOR_VARIABLE_LIST(z), 0, 0);
    714
    1
      REQUIRE_EQ_WITH_TOLERANCE(ccv_nnc_tensor_from_variable(graph, z)->data.f32[0], -5, 1e-2, "linear model should be trained to generate the same value as z");
    715
    1
      ccv_nnc_dynamic_graph_free(graph);
    716
    1
      ccv_cnnp_model_free(linear);
    717
    1
    }
    718
    719
    TEST_CASE("dynamic graph to accumulate gradients cross cnnp models with aliases")
    720
    1
    {
    721
    1
      ccv_nnc_dynamic_graph_t* const graph = ccv_nnc_dynamic_graph_new();
    722
    1
      ccv_cnnp_model_t* const linear = ccv_cnnp_sequential_new(MODEL_LIST(
    723
    1
        ccv_cnnp_dense(1, 1, 0, 1, 0),
    724
    1
        ccv_cnnp_reshape(0, DIM_ALLOC(1), DIM_ALLOC(), DIM_ALLOC(), 0),
    725
    1
      ), 1, 0);
    726
    1
      ccv_nnc_tensor_variable_t a = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 1));
    727
    1
      ccv_nnc_dynamic_graph_exec(graph, CMD_SET_FORWARD(0.2485), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(), TENSOR_VARIABLE_LIST(a), 0, 0);
    728
    1
      const ccv_nnc_tensor_param_t input = CPU_TENSOR_NHWC(32F, 1);
    729
    1
      ccv_cnnp_model_compile(linear, &input, 1, CMD_NOOP(), CMD_NOOP());
    730
    1
      ccv_cnnp_model_set_parameter(linear, ccv_cnnp_model_parameters(linear, CCV_CNNP_PARAMETER_SELECT_WEIGHT, 0), ccv_nnc_tensor_from_variable(graph, a));
    731
    1
      ccv_nnc_tensor_variable_t a_grad = ccv_nnc_tensor_variable_new(graph);
    732
    1
      ccv_nnc_tensor_variable_t saved_aux = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 1));
    733
    1
      int i;
    734
    1.00k
      for (i = 0; i < 1000; i++1.00k)
    735
    1.00k
      {
    736
    1.00k
        ccv_nnc_tensor_variable_t x = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 1));
    737
    1.00k
        ccv_nnc_tensor_from_variable(graph, x)->data.f32[0] = i;
    738
    1.00k
        ccv_nnc_tensor_variable_t t = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 1));
    739
    1.00k
        ccv_nnc_tensor_from_variable(graph, t)->data.f32[0] = -i;
    740
    1.00k
        ccv_nnc_tensor_variable_t y = ccv_nnc_tensor_variable_new(graph);
    741
    1.00k
        ccv_nnc_dynamic_graph_exec(graph, CMD_MUL_FORWARD(1), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(x, a), TENSOR_VARIABLE_LIST(y), 0, 0);
    742
    1.00k
        ccv_nnc_tensor_variable_t y_alias = ccv_nnc_tensor_variable_alias_new(graph, y, DIM_ALLOC(), DIM_ALLOC(1), CPU_TENSOR_NHWC(32F, 1));
    743
    1.00k
        ccv_nnc_tensor_variable_t z = ccv_nnc_tensor_variable_new(graph);
    744
    1.00k
        ccv_nnc_dynamic_graph_evaluate(graph, linear, 0, TENSOR_VARIABLE_LIST(y_alias), TENSOR_VARIABLE_LIST(z), 0, 0);
    745
    1.00k
        ccv_nnc_tensor_variable_t n = ccv_nnc_tensor_variable_new(graph);
    746
    1.00k
        ccv_nnc_dynamic_graph_exec(graph, CMD_ADD_FORWARD(1, -1), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(z, t), TENSOR_VARIABLE_LIST(n), 0, 0);
    747
    1.00k
        ccv_nnc_tensor_variable_t f = ccv_nnc_tensor_variable_new(graph);
    748
    1.00k
        ccv_nnc_dynamic_graph_exec(graph, CMD_MUL_FORWARD(1), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(n, n), TENSOR_VARIABLE_LIST(f), 0, 0);
    749
    1.00k
        ccv_nnc_dynamic_graph_backward(graph, TENSOR_VARIABLE_LIST(f), 0, TENSOR_VARIABLE_LIST(a), TENSOR_VARIABLE_LIST(a_grad), 0);
    750
    1.00k
        ccv_nnc_tensor_variable_free(graph, n);
    751
    1.00k
        ccv_nnc_tensor_variable_free(graph, z);
    752
    1.00k
        ccv_nnc_tensor_variable_free(graph, y);
    753
    1.00k
        ccv_nnc_tensor_variable_free(graph, y_alias);
    754
    1.00k
        ccv_nnc_tensor_variable_free(graph, x);
    755
    1.00k
        ccv_nnc_tensor_variable_free(graph, t);
    756
    1.00k
        ccv_nnc_tensor_variable_free(graph, f);
    757
    1.00k
        if (((i + 1) % 5) == 0)
    758
    200
        {
    759
    200
          REQUIRE_EQ(ccv_nnc_dynamic_graph_bookkeeping_count(graph, CCV_NNC_SYMBOL_GRAPH_EXEC), 0, "everything should be freed");
    760
    200
          DYNAMIC_GRAPH_GEN(graph, CCV_NNC_LONG_DOT_GRAPH);
    761
    200
          float lr = 0.001;
    762
    200
          if (i >= 200)
    763
    160
            lr = 0.0001;
    764
    40
          else if (i >= 600)
    765
    0
            lr = 0.00001;
    766
    200
          ccv_cnnp_model_set_minimizer(linear, CMD_SGD_FORWARD(0, lr, 0.001, 0, 0, 0), 0, 0, 0);
    767
    200
          ccv_nnc_dynamic_graph_apply_gradients(graph, CMD_SGD_FORWARD(0, lr, 0.001, 0, 0, 0), TENSOR_VARIABLE_LIST(a_grad), TENSOR_VARIABLE_LIST(a), &saved_aux, 0, 0);
    768
    200
        }
    769
    1.00k
      }
    770
    1
      ccv_nnc_tensor_variable_t x = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 1));
    771
    1
      ccv_nnc_tensor_from_variable(graph, x)->data.f32[0] = 5;
    772
    1
      ccv_nnc_tensor_variable_t y = ccv_nnc_tensor_variable_new(graph);
    773
    1
      ccv_nnc_dynamic_graph_exec(graph, CMD_MUL_FORWARD(1), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(x, a), TENSOR_VARIABLE_LIST(y), 0, 0);
    774
    1
      ccv_nnc_tensor_variable_t z = ccv_nnc_tensor_variable_new(graph);
    775
    1
      ccv_nnc_dynamic_graph_evaluate(graph, linear, 0, TENSOR_VARIABLE_LIST(y), TENSOR_VARIABLE_LIST(z), 0, 0);
    776
    1
      REQUIRE_EQ_WITH_TOLERANCE(ccv_nnc_tensor_from_variable(graph, z)->data.f32[0], -5, 1e-2, "linear model should be trained to generate the same value as z");
    777
    1
      ccv_nnc_dynamic_graph_free(graph);
    778
    1
      ccv_cnnp_model_free(linear);
    779
    1
    }
    780
    781
    TEST_CASE("dynamic graph to use cnnp model for permute and reshape")
    782
    1
    {
    783
    1
      ccv_cnnp_model_t* const sequential = ccv_cnnp_sequential_new(MODEL_LIST(
    784
    1
        ccv_cnnp_reshape(0, DIM_ALLOC(4, 3, 2), DIM_ALLOC(), DIM_ALLOC(), 0),
    785
    1
        ccv_cnnp_permute(DIM_ALLOC(2, 0, 1), 0),
    786
    1
        ccv_cnnp_reshape(0, DIM_ALLOC(2 * 4, 3), DIM_ALLOC(), DIM_ALLOC(), 0),
    787
    1
      ), 1, 0);
    788
    1
      ccv_nnc_dynamic_graph_t* const graph = ccv_nnc_dynamic_graph_new();
    789
    1
      ccv_nnc_tensor_variable_t x = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 4, 3, 2));
    790
    1
      int i;
    791
    25
      for (i = 0; i < 4 * 3 * 2; i++24)
    792
    24
        ccv_nnc_tensor_from_variable(graph, x)->data.f32[i] = i;
    793
    1
      ccv_nnc_tensor_variable_t y = ccv_nnc_tensor_variable_new(graph);
    794
    1
      ccv_nnc_dynamic_graph_evaluate(graph, sequential, 0, TENSOR_VARIABLE_LIST(x), TENSOR_VARIABLE_LIST(y), 0, 0);
    795
      // 0, 1,
    796
      // 2, 3,
    797
      // 4, 5
    798
      //
    799
      // 6, 7,
    800
      // 8, 9,
    801
      // 10, 11
    802
      //
    803
      // 12, 13,
    804
      // 14, 15,
    805
      // 16, 17
    806
      //
    807
      // 18, 19,
    808
      // 20, 21,
    809
      // 22, 23
    810
      //
    811
      // After permute:
    812
      // 0, 2, 4,
    813
      // 6, 8, 10,
    814
      // 12, 14, 16,
    815
      // 18, 20, 22
    816
      //
    817
      // 1, 3, 5,
    818
      // 7, 9, 11,
    819
      // 13, 15, 17,
    820
      // 19, 21, 23
    821
    1
      float btp[] = {
    822
    1
        0, 2, 4,
    823
    1
        6, 8, 10,
    824
    1
        12, 14, 16,
    825
    1
        18, 20, 22,
    826
    1
        1, 3, 5,
    827
    1
        7, 9, 11,
    828
    1
        13, 15, 17,
    829
    1
        19, 21, 23
    830
    1
      };
    831
    1
      ccv_nnc_tensor_t bt = ccv_nnc_tensor(btp, CPU_TENSOR_NHWC(32F, 2 * 4, 3), 0);
    832
    1
      REQUIRE_TENSOR_EQ(ccv_nnc_tensor_from_variable(graph, y), &bt, "should materialize permute before reshape");
    833
    1
      ccv_nnc_dynamic_graph_free(graph);
    834
    1
      ccv_cnnp_model_free(sequential);
    835
    1
    }
    836
    837
    TEST_CASE("dynamic graph to compute f(x) = x * log(x) + 1.2 * x, f'(x) and sum on x = 19, 10")
    838
    1
    {
    839
    1
      ccv_nnc_dynamic_graph_t* const graph = ccv_nnc_dynamic_graph_new();
    840
    1
      ccv_nnc_tensor_variable_t x = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 1));
    841
    1
      ccv_nnc_tensor_from_variable(graph, x)->data.f32[0] = 19;
    842
    1
      ccv_nnc_tensor_variable_t f = ccv_nnc_tensor_variable_new(graph);
    843
    1
      ccv_nnc_dynamic_graph_exec(graph, CMD_EWLOG_FORWARD(), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(x), TENSOR_VARIABLE_LIST(f), 0, 0);
    844
    1
      ccv_nnc_dynamic_graph_exec(graph, CMD_EWPROD_FORWARD(), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(x, f), TENSOR_VARIABLE_LIST(f), 0, 0);
    845
    1
      ccv_nnc_tensor_variable_t y = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 1));
    846
    1
      ccv_nnc_tensor_from_variable(graph, y)->data.f32[0] = 1.2;
    847
    1
      ccv_nnc_tensor_variable_t z = ccv_nnc_tensor_variable_new(graph);
    848
    1
      ccv_nnc_dynamic_graph_exec(graph, CMD_EWPROD_FORWARD(), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(x, y), TENSOR_VARIABLE_LIST(z), 0, 0);
    849
    1
      ccv_nnc_dynamic_graph_exec(graph, CMD_EWSUM_FORWARD(), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(f, z), TENSOR_VARIABLE_LIST(f), 0, 0);
    850
    1
      REQUIRE_EQ_WITH_TOLERANCE(ccv_nnc_tensor_from_variable(graph, f)->data.f32[0], 19 * logf(19) + 1.2 * 19, 1e-5, "f(x) = 1.2 * 19 + 19 * log(19)");
    851
      // Do gradient computation multiple times.
    852
    1
      ccv_nnc_tensor_variable_t dx = ccv_nnc_tensor_variable_new(graph);
    853
    1
      ccv_nnc_dynamic_graph_backward(graph, TENSOR_VARIABLE_LIST(f), 0, TENSOR_VARIABLE_LIST(x), TENSOR_VARIABLE_LIST(dx), 0);
    854
    1
      REQUIRE_EQ_WITH_TOLERANCE(ccv_nnc_tensor_from_variable(graph, dx)->data.f32[0], logf(19) + 1 + 1.2, 1e-5, "f'(x) = 1.2 + log(19) + 19 * 1 / 19");
    855
    1
      ccv_nnc_tensor_variable_free(graph, x);
    856
    1
      x = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 1));
    857
    1
      ccv_nnc_tensor_from_variable(graph, x)->data.f32[0] = 10;
    858
    1
      ccv_nnc_dynamic_graph_exec(graph, CMD_EWLOG_FORWARD(), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(x), TENSOR_VARIABLE_LIST(f), 0, 0);
    859
    1
      ccv_nnc_dynamic_graph_exec(graph, CMD_EWPROD_FORWARD(), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(x, f), TENSOR_VARIABLE_LIST(f), 0, 0);
    860
    1
      ccv_nnc_tensor_from_variable(graph, y)->data.f32[0] = 1.2;
    861
    1
      ccv_nnc_dynamic_graph_exec(graph, CMD_EWPROD_FORWARD(), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(x, y), TENSOR_VARIABLE_LIST(z), 0, 0);
    862
    1
      ccv_nnc_dynamic_graph_exec(graph, CMD_EWSUM_FORWARD(), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(f, z), TENSOR_VARIABLE_LIST(f), 0, 0);
    863
    1
      REQUIRE_EQ_WITH_TOLERANCE(ccv_nnc_tensor_from_variable(graph, f)->data.f32[0], 10 * logf(10) + 1.2 * 10, 1e-5, "f(x) = 1.2 * 10 + 10 * log(10)");
    864
    1
      ccv_nnc_dynamic_graph_backward(graph, TENSOR_VARIABLE_LIST(f), 0, TENSOR_VARIABLE_LIST(x), TENSOR_VARIABLE_LIST(dx), 0);
    865
    1
      REQUIRE_EQ_WITH_TOLERANCE(ccv_nnc_tensor_from_variable(graph, dx)->data.f32[0], logf(19) + 1 + 1.2 + logf(10) + 1 + 1.2, 1e-5, "f'(x) = 1.2 + log(19) + 19 * 1 / 19 + 1.2 + log(19) + 19 * 1 / 19");
    866
    1
      DYNAMIC_GRAPH_GEN(graph, CCV_NNC_LONG_DOT_GRAPH);
    867
    1
      ccv_nnc_dynamic_graph_free(graph);
    868
    1
    }
    869
    870
    TEST_CASE("dynamic graph to compute f(x) = x * log(x) + y' where y = 1.2 * x and y' is an alias to y")
    871
    1
    {
    872
    1
      ccv_nnc_dynamic_graph_t* const graph = ccv_nnc_dynamic_graph_new();
    873
    1
      ccv_nnc_tensor_variable_t x = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 1));
    874
    1
      ccv_nnc_tensor_from_variable(graph, x)->data.f32[0] = 19;
    875
    1
      ccv_nnc_tensor_variable_t f = ccv_nnc_tensor_variable_new(graph);
    876
    1
      ccv_nnc_dynamic_graph_exec(graph, CMD_EWLOG_FORWARD(), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(x), TENSOR_VARIABLE_LIST(f), 0, 0);
    877
    1
      ccv_nnc_dynamic_graph_exec(graph, CMD_EWPROD_FORWARD(), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(x, f), TENSOR_VARIABLE_LIST(f), 0, 0);
    878
    1
      ccv_nnc_tensor_variable_t z = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 1));
    879
    1
      ccv_nnc_tensor_from_variable(graph, z)->data.f32[0] = 1.2;
    880
    1
      ccv_nnc_tensor_variable_t y = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 1));
    881
    1
      ccv_nnc_tensor_variable_t y_hat = ccv_nnc_tensor_variable_alias_new(graph, y, ccv_nnc_no_ofs, DIM_ALLOC(), CPU_TENSOR_NHWC(32F, 1));
    882
    1
      ccv_nnc_dynamic_graph_exec(graph, CMD_EWPROD_FORWARD(), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(x, z), TENSOR_VARIABLE_LIST(y), 0, 0);
    883
    1
      ccv_nnc_dynamic_graph_exec(graph, CMD_EWSUM_FORWARD(), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(f, y_hat), TENSOR_VARIABLE_LIST(f), 0, 0);
    884
    1
      REQUIRE_EQ_WITH_TOLERANCE(ccv_nnc_tensor_from_variable(graph, f)->data.f32[0], 19 * logf(19) + 1.2 * 19, 1e-5, "f(x) = 1.2 * 19 + 19 * log(19)");
    885
    1
      ccv_nnc_tensor_variable_free(graph, y_hat);
    886
    1
      ccv_nnc_tensor_variable_free(graph, f);
    887
    1
      ccv_nnc_tensor_variable_free(graph, x);
    888
    1
      ccv_nnc_tensor_variable_free(graph, z);
    889
    1
      ccv_nnc_tensor_variable_free(graph, y);
    890
    1
      REQUIRE_EQ(ccv_nnc_dynamic_graph_bookkeeping_count(graph, CCV_NNC_SYMBOL_TENSOR), 0, "should have no tensor left");
    891
    1
      ccv_nnc_dynamic_graph_free(graph);
    892
    1
    }
    893
    894
    TEST_CASE("dynamic graph to compute f(x) = x * log(x) + y' where y'' = 1.2 * x and both y'' and y' are aliases to y")
    895
    1
    {
    896
    1
      ccv_nnc_dynamic_graph_t* const graph = ccv_nnc_dynamic_graph_new();
    897
    1
      ccv_nnc_tensor_variable_t x = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 1));
    898
    1
      ccv_nnc_tensor_from_variable(graph, x)->data.f32[0] = 19;
    899
    1
      ccv_nnc_tensor_variable_t f = ccv_nnc_tensor_variable_new(graph);
    900
    1
      ccv_nnc_dynamic_graph_exec(graph, CMD_EWLOG_FORWARD(), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(x), TENSOR_VARIABLE_LIST(f), 0, 0);
    901
    1
      ccv_nnc_dynamic_graph_exec(graph, CMD_EWPROD_FORWARD(), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(x, f), TENSOR_VARIABLE_LIST(f), 0, 0);
    902
    1
      ccv_nnc_tensor_variable_t z = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 1));
    903
    1
      ccv_nnc_tensor_from_variable(graph, z)->data.f32[0] = 1.2;
    904
    1
      ccv_nnc_tensor_variable_t y = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 1));
    905
    1
      ccv_nnc_tensor_variable_t y_hat = ccv_nnc_tensor_variable_alias_new(graph, y, ccv_nnc_no_ofs, DIM_ALLOC(), CPU_TENSOR_NHWC(32F, 1));
    906
    1
      ccv_nnc_tensor_variable_t y_double_hat = ccv_nnc_tensor_variable_alias_new(graph, y, ccv_nnc_no_ofs, DIM_ALLOC(), CPU_TENSOR_NHWC(32F, 1));
    907
    1
      ccv_nnc_dynamic_graph_exec(graph, CMD_EWPROD_FORWARD(), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(x, z), TENSOR_VARIABLE_LIST(y_double_hat), 0, 0);
    908
    1
      ccv_nnc_dynamic_graph_exec(graph, CMD_EWSUM_FORWARD(), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(f, y_hat), TENSOR_VARIABLE_LIST(f), 0, 0);
    909
    1
      REQUIRE_EQ_WITH_TOLERANCE(ccv_nnc_tensor_from_variable(graph, f)->data.f32[0], 19 * logf(19) + 1.2 * 19, 1e-5, "f(x) = 1.2 * 19 + 19 * log(19)");
    910
    1
      ccv_nnc_tensor_variable_free(graph, y_hat);
    911
    1
      ccv_nnc_tensor_variable_free(graph, y_double_hat);
    912
    1
      ccv_nnc_tensor_variable_free(graph, f);
    913
    1
      ccv_nnc_tensor_variable_free(graph, x);
    914
    1
      ccv_nnc_tensor_variable_free(graph, z);
    915
    1
      ccv_nnc_tensor_variable_free(graph, y);
    916
    1
      REQUIRE_EQ(ccv_nnc_dynamic_graph_bookkeeping_count(graph, CCV_NNC_SYMBOL_TENSOR), 0, "should have no tensor left");
    917
    1
      ccv_nnc_dynamic_graph_free(graph);
    918
    1
    }
    919
    920
    TEST_CASE("dynamic graph to compute f(x) = x * y, where y[0] = 10 * z, y[1] = 2 * z, z = [2], x = [10], should free all variables")
    921
    1
    {
    922
    1
      ccv_nnc_dynamic_graph_t* const graph = ccv_nnc_dynamic_graph_new();
    923
    1
      ccv_nnc_tensor_variable_t x = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 1));
    924
    1
      ccv_nnc_tensor_variable_t y = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 2));
    925
    1
      ccv_nnc_tensor_variable_t z = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 1));
    926
    1
      ccv_nnc_dynamic_graph_exec(graph, CMD_SET_FORWARD(2), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(), TENSOR_VARIABLE_LIST(z), 0, 0);
    927
    1
      ccv_nnc_dynamic_graph_exec(graph, CMD_SET_FORWARD(10), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(), TENSOR_VARIABLE_LIST(x), 0, 0);
    928
    1
      ccv_nnc_tensor_variable_t y_1 = ccv_nnc_tensor_variable_alias_new(graph, y, ccv_nnc_no_ofs, DIM_ALLOC(1), CPU_TENSOR_NHWC(32F, 1));
    929
    1
      ccv_nnc_tensor_variable_t y_2 = ccv_nnc_tensor_variable_alias_new(graph, y, DIM_ALLOC(1), DIM_ALLOC(1), CPU_TENSOR_NHWC(32F, 1));
    930
    1
      ccv_nnc_dynamic_graph_exec(graph, CMD_SCALAR_MUL_FORWARD(10), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(z), TENSOR_VARIABLE_LIST(y_1), 0, 0);
    931
    1
      ccv_nnc_dynamic_graph_exec(graph, CMD_SCALAR_MUL_FORWARD(2), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(z), TENSOR_VARIABLE_LIST(y_2), 0, 0);
    932
    1
      ccv_nnc_tensor_variable_t f = ccv_nnc_tensor_variable_new(graph);
    933
    1
      ccv_nnc_dynamic_graph_exec(graph, CMD_MUL_FORWARD(1), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(x, y), TENSOR_VARIABLE_LIST(f), 0, 0);
    934
    1
      float gt[] = {10 * 2 * 10, 2 * 2 * 10};
    935
    1
      REQUIRE_ARRAY_EQ_WITH_TOLERANCE(float, ccv_nnc_tensor_from_variable(graph, f)->data.f32, gt, 2, 1e-5, "should be equal");
    936
    1
      ccv_nnc_tensor_variable_free(graph, z);
    937
    1
      ccv_nnc_tensor_variable_free(graph, y_1);
    938
    1
      ccv_nnc_tensor_variable_free(graph, y_2);
    939
    1
      ccv_nnc_tensor_variable_free(graph, x);
    940
    1
      ccv_nnc_tensor_variable_free(graph, y);
    941
    1
      ccv_nnc_tensor_variable_free(graph, f);
    942
    1
      REQUIRE_EQ(ccv_nnc_dynamic_graph_bookkeeping_count(graph, CCV_NNC_SYMBOL_GRAPH_EXEC), 0, "everything should be freed");
    943
    1
      REQUIRE_EQ(ccv_nnc_dynamic_graph_bookkeeping_count(graph, CCV_NNC_SYMBOL_TENSOR), 0, "everything should be freed");
    944
    1
      ccv_nnc_dynamic_graph_free(graph);
    945
    1
    }
    946
    947
    TEST_CASE("dynamic graph to compute f(x) = x * y, where y[0] = 10 * z, y[1] = 2 * z, z = [2], x = [10], freed y[0], y[1] before use")
    948
    1
    {
    949
    1
      ccv_nnc_dynamic_graph_t* const graph = ccv_nnc_dynamic_graph_new();
    950
    1
      ccv_nnc_tensor_variable_t x = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 1));
    951
    1
      ccv_nnc_tensor_variable_t y = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 2));
    952
    1
      ccv_nnc_tensor_variable_t z = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 1));
    953
    1
      ccv_nnc_dynamic_graph_exec(graph, CMD_SET_FORWARD(2), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(), TENSOR_VARIABLE_LIST(z), 0, 0);
    954
    1
      ccv_nnc_dynamic_graph_exec(graph, CMD_SET_FORWARD(10), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(), TENSOR_VARIABLE_LIST(x), 0, 0);
    955
    1
      ccv_nnc_tensor_variable_t y_1 = ccv_nnc_tensor_variable_alias_new(graph, y, ccv_nnc_no_ofs, DIM_ALLOC(1), CPU_TENSOR_NHWC(32F, 1));
    956
    1
      ccv_nnc_tensor_variable_t y_2 = ccv_nnc_tensor_variable_alias_new(graph, y, DIM_ALLOC(1), DIM_ALLOC(1), CPU_TENSOR_NHWC(32F, 1));
    957
    1
      ccv_nnc_dynamic_graph_exec(graph, CMD_SCALAR_MUL_FORWARD(10), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(z), TENSOR_VARIABLE_LIST(y_1), 0, 0);
    958
    1
      ccv_nnc_dynamic_graph_exec(graph, CMD_SCALAR_MUL_FORWARD(2), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(z), TENSOR_VARIABLE_LIST(y_2), 0, 0);
    959
    1
      ccv_nnc_tensor_variable_free(graph, y_1);
    960
    1
      ccv_nnc_tensor_variable_free(graph, y_2);
    961
    1
      ccv_nnc_tensor_variable_t f = ccv_nnc_tensor_variable_new(graph);
    962
    1
      ccv_nnc_dynamic_graph_exec(graph, CMD_MUL_FORWARD(1), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(x, y), TENSOR_VARIABLE_LIST(f), 0, 0);
    963
    1
      REQUIRE_EQ(ccv_nnc_dynamic_graph_bookkeeping_count(graph, CCV_NNC_SYMBOL_GRAPH_EXEC), 3, "should keep 3 ops");
    964
    1
      float gt[] = {10 * 2 * 10, 2 * 2 * 10};
    965
    1
      REQUIRE_ARRAY_EQ_WITH_TOLERANCE(float, ccv_nnc_tensor_from_variable(graph, f)->data.f32, gt, 2, 1e-5, "should be equal");
    966
    1
      ccv_nnc_tensor_variable_free(graph, z);
    967
    1
      ccv_nnc_tensor_variable_free(graph, x);
    968
    1
      ccv_nnc_tensor_variable_free(graph, y);
    969
    1
      ccv_nnc_tensor_variable_free(graph, f);
    970
    1
      REQUIRE_EQ(ccv_nnc_dynamic_graph_bookkeeping_count(graph, CCV_NNC_SYMBOL_GRAPH_EXEC), 0, "everything should be freed");
    971
    1
      REQUIRE_EQ(ccv_nnc_dynamic_graph_bookkeeping_count(graph, CCV_NNC_SYMBOL_TENSOR), 0, "everything should be freed");
    972
    1
      ccv_nnc_dynamic_graph_free(graph);
    973
    1
    }
    974
    975
    TEST_CASE("dynamic graph to compute f(x) = x * y', where y[0, 0] = 2, y[0, 1] = 4, x = [10], y' = y^T, gradient against y")
    976
    1
    {
    977
    1
      ccv_nnc_dynamic_graph_t* const graph = ccv_nnc_dynamic_graph_new();
    978
    1
      ccv_nnc_tensor_variable_t x = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 1));
    979
    1
      ccv_nnc_tensor_variable_t y = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 2));
    980
    1
      ccv_nnc_tensor_from_variable(graph, y)->data.f32[0] = 2;
    981
    1
      ccv_nnc_tensor_from_variable(graph, y)->data.f32[0] = 4;
    982
    1
      ccv_nnc_dynamic_graph_exec(graph, CMD_SET_FORWARD(10), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(), TENSOR_VARIABLE_LIST(x), 0, 0);
    983
    1
      ccv_nnc_tensor_variable_t y_t = ccv_nnc_tensor_variable_alias_new(graph, y, ccv_nnc_no_ofs, DIM_ALLOC(), CPU_TENSOR_NHWC(32F, 2, 1));
    984
    1
      ccv_nnc_tensor_variable_t f = ccv_nnc_tensor_variable_new(graph);
    985
    1
      ccv_nnc_dynamic_graph_exec(graph, CMD_MUL_FORWARD(1), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(x, y_t), TENSOR_VARIABLE_LIST(f), 0, 0);
    986
    1
      ccv_nnc_tensor_variable_t dy_t = ccv_nnc_tensor_variable_new(graph);
    987
    1
      ccv_nnc_tensor_variable_free(graph, x); // Cannot free y_t, it has to be freed in lock step with y.
    988
    1
      ccv_nnc_tensor_variable_free(graph, y);
    989
    1
      ccv_nnc_dynamic_graph_backward(graph, TENSOR_VARIABLE_LIST(f), 0, TENSOR_VARIABLE_LIST(y_t), TENSOR_VARIABLE_LIST(dy_t), 0);
    990
    1
      float gt[] = {10, 10};
    991
    1
      REQUIRE_ARRAY_EQ_WITH_TOLERANCE(float, ccv_nnc_tensor_from_variable(graph, dy_t)->data.f32, gt, 2, 1e-5, "should be equal");
    992
    1
      ccv_nnc_tensor_variable_free(graph, y_t);
    993
    1
      ccv_nnc_tensor_variable_free(graph, f);
    994
    1
      REQUIRE_EQ(ccv_nnc_dynamic_graph_bookkeeping_count(graph, CCV_NNC_SYMBOL_GRAPH_EXEC), 0, "everything should be freed");
    995
    1
      REQUIRE_EQ(ccv_nnc_dynamic_graph_bookkeeping_count(graph, CCV_NNC_SYMBOL_TENSOR), 0, "everything should be freed");
    996
    1
      ccv_nnc_dynamic_graph_free(graph);
    997
    1
    }
    998
    999
    TEST_CASE("long chain to autograd, simulate random free of unused tensors due to garbage collection")
    1000
    1
    {
    1001
    1
      ccv_nnc_dynamic_graph_t* const graph = ccv_nnc_dynamic_graph_new();
    1002
    1
      ccv_nnc_tensor_variable_t x[10];
    1003
    1
      ccv_nnc_tensor_variable_t f[10];
    1004
    1
      ccv_nnc_tensor_variable_t y = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 1));
    1005
    1
      ccv_nnc_tensor_variable_t dy[3];
    1006
    1
      ccv_nnc_tensor_from_variable(graph, y)->data.f32[0] = 1.3;
    1007
    1
      int i, j;
    1008
    11
      for (i = 0; i < 10; i++10)
    1009
    10
      {
    1010
    10
        x[i] = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 1));
    1011
    10
        ccv_nnc_tensor_from_variable(graph, x[i])->data.f32[0] = i + 1;
    1012
    10
        f[i] = ccv_nnc_tensor_variable_new(graph);
    1013
    10
        ccv_nnc_dynamic_graph_exec(graph, CMD_MUL_FORWARD(1), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(x[i], y), TENSOR_VARIABLE_LIST(f[i]), 0, 0);
    1014
    10
        if (i >= 5)
    1015
    5
        {
    1016
    5
          if (i - 5 < 3)
    1017
    3
            dy[i - 5] = ccv_nnc_tensor_variable_new(graph);
    1018
    5
          ccv_nnc_dynamic_graph_backward(graph, TENSOR_VARIABLE_LIST(f[i]), 0, TENSOR_VARIABLE_LIST(y), TENSOR_VARIABLE_LIST(dy[ccv_min(2, i - 5)]), 0);
    1019
    5
        }
    1020
    10
        if (i == 7)
    1021
    6
          for (j = 0; 1j < 5; j++5)
    1022
    5
            ccv_nnc_tensor_variable_free(graph, f[j]);
    1023
    10
      }
    1024
    1
      REQUIRE_EQ_WITH_TOLERANCE(ccv_nnc_tensor_from_variable(graph, f[9])->data.f32[0], 1.3 * 10, 1e-5, "should equal to 1.3 * 10");
    1025
    1
      REQUIRE_EQ_WITH_TOLERANCE(ccv_nnc_tensor_from_variable(graph, dy[2])->data.f32[0], 8 + 9 + 10, 1e-5, "should equal to sum of the last 3");
    1026
    11
      for (i = 0; i < 10; i++10)
    1027
    10
        ccv_nnc_tensor_variable_free(graph, x[i]);
    1028
    1
      ccv_nnc_dynamic_graph_free(graph);
    1029
    1
    }
    1030
    1031
    TEST_CASE("parallel exec with a stream, focus on uma tensors")
    1032
    1
    {
    1033
    1
      ccv_nnc_dynamic_graph_t* const graph = ccv_nnc_dynamic_graph_new();
    1034
    1
      ccv_nnc_stream_context_t* const stream = ccv_nnc_stream_context_new(CCV_STREAM_CONTEXT_CPU);
    1035
    1
      ccv_nnc_tensor_variable_t x[2];
    1036
    1
      x[0] = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 1));
    1037
    1
      x[1] = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 1));
    1038
    1
      ccv_nnc_tensor_from_variable(graph, x[0])->data.f32[0] = 10;
    1039
    1
      ccv_nnc_tensor_from_variable(graph, x[1])->data.f32[0] = 9;
    1040
    1
      ccv_nnc_tensor_variable_t y[2];
    1041
    1
      y[0] = ccv_nnc_tensor_variable_new(graph);
    1042
    1
      y[1] = ccv_nnc_tensor_variable_new(graph);
    1043
    1
      ccv_nnc_dynamic_graph_exec(graph, CMD_SCALAR_MUL_FORWARD(0.4), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(x[0], x[1]), TENSOR_VARIABLE_LIST(y[0], y[1]), 2, stream);
    1044
    1
      ccv_nnc_stream_context_wait(stream);
    1045
    1
      ccv_nnc_stream_context_free(stream);
    1046
    1
      REQUIRE_EQ_WITH_TOLERANCE(ccv_nnc_tensor_from_variable(graph, y[0])->data.f32[0], 10 * 0.4, 1e-5, "should match the result");
    1047
    1
      REQUIRE_EQ_WITH_TOLERANCE(ccv_nnc_tensor_from_variable(graph, y[1])->data.f32[0], 9 * 0.4, 1e-5, "should match the result");
    1048
    1
      ccv_nnc_dynamic_graph_free(graph);
    1049
    1
    }
    1050
    1051
    TEST_CASE("parallel exec with a stream, focus on potential memory issues")
    1052
    1
    {
    1053
    1
      ccv_nnc_dynamic_graph_t* const graph = ccv_nnc_dynamic_graph_new();
    1054
    1
      ccv_nnc_stream_context_t* const stream = ccv_nnc_stream_context_new(CCV_STREAM_CONTEXT_CPU);
    1055
    1
      ccv_nnc_tensor_variable_t x[2];
    1056
    1
      x[0] = ccv_nnc_tensor_variable_new(graph, CPU_NUMA_TENSOR_NHWC(000, 32F, 1));
    1057
    1
      x[1] = ccv_nnc_tensor_variable_new(graph, CPU_NUMA_TENSOR_NHWC(000, 32F, 1));
    1058
    1
      ccv_nnc_tensor_from_variable(graph, x[0])->data.f32[0] = 10;
    1059
    1
      ccv_nnc_tensor_from_variable(graph, x[1])->data.f32[0] = 9;
    1060
    1
      ccv_nnc_tensor_variable_t y[2];
    1061
    1
      y[0] = ccv_nnc_tensor_variable_new(graph);
    1062
    1
      y[1] = ccv_nnc_tensor_variable_new(graph);
    1063
    1
      ccv_nnc_dynamic_graph_exec(graph, CMD_SCALAR_MUL_FORWARD(0.4), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(x[0], x[1]), TENSOR_VARIABLE_LIST(y[0], y[1]), 2, stream);
    1064
    1
      ccv_nnc_stream_context_wait(stream);
    1065
    1
      ccv_nnc_stream_context_free(stream);
    1066
    1
      REQUIRE_EQ_WITH_TOLERANCE(ccv_nnc_tensor_from_variable(graph, y[0])->data.f32[0], 10 * 0.4, 1e-5, "should match the result");
    1067
    1
      REQUIRE_EQ_WITH_TOLERANCE(ccv_nnc_tensor_from_variable(graph, y[1])->data.f32[0], 9 * 0.4, 1e-5, "should match the result");
    1068
    1
      ccv_nnc_dynamic_graph_free(graph);
    1069
    1
    }
    1070
    1071
    TEST_CASE("query whether a tensor variable depends on another")
    1072
    1
    {
    1073
    1
      ccv_nnc_dynamic_graph_t* const graph = ccv_nnc_dynamic_graph_new();
    1074
    1
      ccv_nnc_tensor_variable_t a = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 1));
    1075
    1
      ccv_nnc_tensor_from_variable(graph, a)->data.f32[0] = 10;
    1076
    1
      ccv_nnc_tensor_variable_t b = ccv_nnc_tensor_variable_new(graph);
    1077
    1
      ccv_nnc_dynamic_graph_exec(graph, CMD_SCALAR_MUL_FORWARD(0.5), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(a), TENSOR_VARIABLE_LIST(b), 0, 0);
    1078
    1
      ccv_nnc_tensor_variable_t c = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 1));
    1079
    1
      ccv_nnc_tensor_from_variable(graph, c)->data.f32[0] = 9;
    1080
    1
      ccv_nnc_tensor_variable_t d = ccv_nnc_tensor_variable_new(graph);
    1081
    1
      ccv_nnc_dynamic_graph_exec(graph, CMD_SCALAR_MUL_FORWARD(0.4), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(c), TENSOR_VARIABLE_LIST(d), 0, 0);
    1082
    1
      ccv_nnc_tensor_variable_t e = ccv_nnc_tensor_variable_new(graph);
    1083
    1
      ccv_nnc_dynamic_graph_exec(graph, CMD_SCALAR_MUL_FORWARD(2), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(d), TENSOR_VARIABLE_LIST(e), 0, 0);
    1084
    1
      ccv_nnc_tensor_variable_t f = ccv_nnc_tensor_variable_new(graph);
    1085
    1
      ccv_nnc_dynamic_graph_exec(graph, CMD_EWSUM_FORWARD(), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(a, c), TENSOR_VARIABLE_LIST(f), 0, 0);
    1086
    1
      ccv_nnc_tensor_variable_t g = ccv_nnc_tensor_variable_new(graph);
    1087
    1
      ccv_nnc_dynamic_graph_exec(graph, CMD_EWSUM_FORWARD(), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(e, b), TENSOR_VARIABLE_LIST(g), 0, 0);
    1088
    1
      REQUIRE_EQ_WITH_TOLERANCE(ccv_nnc_tensor_from_variable(graph, f)->data.f32[0], 10 + 9, 1e-5, "should match the result");
    1089
    1
      REQUIRE_EQ_WITH_TOLERANCE(ccv_nnc_tensor_from_variable(graph, g)->data.f32[0], 10 * 0.5 + 9 * 0.4 * 2, 1e-5, "should match the result");
    1090
    1
      uint64_t bitmask = 1;
    1091
    1
      ccv_nnc_dynamic_graph_has_effect_to_tensor_variables(graph, TENSOR_VARIABLE_LIST(a, b, f), TENSOR_VARIABLE_LIST(g), &bitmask);
    1092
    1
      REQUIRE(bitmask == 3, "a and b should be ancestors to g");
    1093
    1
      bitmask = 8;
    1094
    1
      ccv_nnc_dynamic_graph_has_effect_to_tensor_variables(graph, TENSOR_VARIABLE_LIST(a, e, c, f), TENSOR_VARIABLE_LIST(g), &bitmask);
    1095
    1
      REQUIRE(bitmask == 7, "a, e and c should be ancestors to g");
    1096
    1
      bitmask = 2;
    1097
    1
      ccv_nnc_dynamic_graph_has_effect_to_tensor_variables(graph, TENSOR_VARIABLE_LIST(a, e, c), TENSOR_VARIABLE_LIST(f), &bitmask);
    1098
    1
      REQUIRE(bitmask == 5, "a and c should be ancestors to f");
    1099
    1
      ccv_nnc_dynamic_graph_free(graph);
    1100
    1
    }
    1101
    1102
    TEST_CASE("compute f(x) = 0.5 * log(x), detach log(x) means 0.5 * y should be freed")
    1103
    1
    {
    1104
    1
      ccv_nnc_dynamic_graph_t* const graph = ccv_nnc_dynamic_graph_new();
    1105
    1
      ccv_nnc_tensor_variable_t x = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 1));
    1106
    1
      ccv_nnc_tensor_from_variable(graph, x)->data.f32[0] = 10;
    1107
    1
      ccv_nnc_tensor_variable_t y = ccv_nnc_tensor_variable_new(graph);
    1108
    1
      ccv_nnc_dynamic_graph_exec(graph, CMD_EWLOG_FORWARD(), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(x), TENSOR_VARIABLE_LIST(y), 0, 0);
    1109
    1
      REQUIRE_EQ_WITH_TOLERANCE(ccv_nnc_tensor_from_variable(graph, y)->data.f32[0], log(10), 1e-5, "should match the result");
    1110
    1
      ccv_nnc_tensor_variable_t z = ccv_nnc_tensor_variable_new(graph);
    1111
    1
      ccv_nnc_dynamic_graph_exec(graph, CMD_SCALAR_MUL_FORWARD(0.5), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(y), TENSOR_VARIABLE_LIST(z), 0, 0);
    1112
    1
      REQUIRE_EQ_WITH_TOLERANCE(ccv_nnc_tensor_from_variable(graph, z)->data.f32[0], 0.5 * log(10), 1e-5, "should match the result");
    1113
    1
      REQUIRE_EQ(ccv_nnc_dynamic_graph_bookkeeping_count(graph, CCV_NNC_SYMBOL_GRAPH_EXEC), 2, "nothing should be freed");
    1114
    1
      REQUIRE_EQ(ccv_nnc_dynamic_graph_bookkeeping_count(graph, CCV_NNC_SYMBOL_TENSOR), 3, "nothing should be freed");
    1115
    1
      uint64_t bitmask = 0;
    1116
    1
      ccv_nnc_dynamic_graph_has_effect_to_tensor_variables(graph, TENSOR_VARIABLE_LIST(x), TENSOR_VARIABLE_LIST(z), &bitmask);
    1117
    1
      REQUIRE(bitmask == 1, "before detach, it should have effect");
    1118
    1
      ccv_nnc_tensor_variable_detach(graph, y);
    1119
    1
      REQUIRE_EQ(ccv_nnc_dynamic_graph_bookkeeping_count(graph, CCV_NNC_SYMBOL_GRAPH_EXEC), 1, "0.5 * y should be freed");
    1120
    1
      REQUIRE_EQ(ccv_nnc_dynamic_graph_bookkeeping_count(graph, CCV_NNC_SYMBOL_TENSOR), 3, "nothing should be freed");
    1121
    1
      bitmask = 0;
    1122
    1
      ccv_nnc_dynamic_graph_has_effect_to_tensor_variables(graph, TENSOR_VARIABLE_LIST(x), TENSOR_VARIABLE_LIST(z), &bitmask);
    1123
    1
      REQUIRE(bitmask == 0, "after detach, it should have no effect");
    1124
    1
      ccv_nnc_tensor_variable_free(graph, x);
    1125
    1
      REQUIRE_EQ(ccv_nnc_dynamic_graph_bookkeeping_count(graph, CCV_NNC_SYMBOL_GRAPH_EXEC), 0, "everything should be freed");
    1126
    1
      REQUIRE_EQ(ccv_nnc_dynamic_graph_bookkeeping_count(graph, CCV_NNC_SYMBOL_TENSOR), 1, "x and y should be freed");
    1127
    1
      ccv_nnc_tensor_variable_free(graph, y);
    1128
    1
      ccv_nnc_tensor_variable_free(graph, z);
    1129
    1
      REQUIRE_EQ(ccv_nnc_dynamic_graph_bookkeeping_count(graph, CCV_NNC_SYMBOL_TENSOR), 0, "everything should be freed");
    1130
    1
      ccv_nnc_dynamic_graph_free(graph);
    1131
    1
    }
    1132
    1133
    TEST_CASE("compute f(x) = 0.5 * log(x), detach log(x) after freeing x means all computations on the graph should be freed")
    1134
    1
    {
    1135
    1
      ccv_nnc_dynamic_graph_t* const graph = ccv_nnc_dynamic_graph_new();
    1136
    1
      ccv_nnc_tensor_variable_t x = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 1));
    1137
    1
      ccv_nnc_tensor_from_variable(graph, x)->data.f32[0] = 10;
    1138
    1
      ccv_nnc_tensor_variable_t y = ccv_nnc_tensor_variable_new(graph);
    1139
    1
      ccv_nnc_dynamic_graph_exec(graph, CMD_EWLOG_FORWARD(), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(x), TENSOR_VARIABLE_LIST(y), 0, 0);
    1140
    1
      REQUIRE_EQ_WITH_TOLERANCE(ccv_nnc_tensor_from_variable(graph, y)->data.f32[0], log(10), 1e-5, "should match the result");
    1141
    1
      ccv_nnc_tensor_variable_t z = ccv_nnc_tensor_variable_new(graph);
    1142
    1
      ccv_nnc_dynamic_graph_exec(graph, CMD_SCALAR_MUL_FORWARD(0.5), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(y), TENSOR_VARIABLE_LIST(z), 0, 0);
    1143
    1
      REQUIRE_EQ_WITH_TOLERANCE(ccv_nnc_tensor_from_variable(graph, z)->data.f32[0], 0.5 * log(10), 1e-5, "should match the result");
    1144
    1
      REQUIRE_EQ(ccv_nnc_dynamic_graph_bookkeeping_count(graph, CCV_NNC_SYMBOL_GRAPH_EXEC), 2, "nothing should be freed");
    1145
    1
      REQUIRE_EQ(ccv_nnc_dynamic_graph_bookkeeping_count(graph, CCV_NNC_SYMBOL_TENSOR), 3, "nothing should be freed");
    1146
      // free x first before detaching y.
    1147
    1
      ccv_nnc_tensor_variable_free(graph, x);
    1148
    1
      REQUIRE_EQ(ccv_nnc_dynamic_graph_bookkeeping_count(graph, CCV_NNC_SYMBOL_GRAPH_EXEC), 1, "log(x) should be freed");
    1149
    1
      REQUIRE_EQ(ccv_nnc_dynamic_graph_bookkeeping_count(graph, CCV_NNC_SYMBOL_TENSOR), 2, "only x should be freed");
    1150
    1
      ccv_nnc_tensor_variable_detach(graph, y);
    1151
    1
      REQUIRE_EQ(ccv_nnc_dynamic_graph_bookkeeping_count(graph, CCV_NNC_SYMBOL_GRAPH_EXEC), 0, "everything should be freed");
    1152
    1
      REQUIRE_EQ(ccv_nnc_dynamic_graph_bookkeeping_count(graph, CCV_NNC_SYMBOL_TENSOR), 1, "x and y should be freed");
    1153
    1
      ccv_nnc_tensor_variable_free(graph, y);
    1154
    1
      ccv_nnc_tensor_variable_free(graph, z);
    1155
    1
      REQUIRE_EQ(ccv_nnc_dynamic_graph_bookkeeping_count(graph, CCV_NNC_SYMBOL_TENSOR), 0, "everything should be freed");
    1156
    1
      ccv_nnc_dynamic_graph_free(graph);
    1157
    1
    }
    1158
    1159
    TEST_CASE("compute f(x) = a * log(x), detach log(x) means nothing changed")
    1160
    1
    {
    1161
    1
      ccv_nnc_dynamic_graph_t* const graph = ccv_nnc_dynamic_graph_new();
    1162
    1
      ccv_nnc_tensor_variable_t x = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 1));
    1163
    1
      ccv_nnc_tensor_from_variable(graph, x)->data.f32[0] = 10;
    1164
    1
      ccv_nnc_tensor_variable_t a = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 1));
    1165
    1
      ccv_nnc_tensor_from_variable(graph, a)->data.f32[0] = 5;
    1166
    1
      ccv_nnc_tensor_variable_t y = ccv_nnc_tensor_variable_new(graph);
    1167
    1
      ccv_nnc_dynamic_graph_exec(graph, CMD_EWLOG_FORWARD(), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(x), TENSOR_VARIABLE_LIST(y), 0, 0);
    1168
    1
      REQUIRE_EQ_WITH_TOLERANCE(ccv_nnc_tensor_from_variable(graph, y)->data.f32[0], log(10), 1e-5, "should match the result");
    1169
    1
      ccv_nnc_tensor_variable_t z = ccv_nnc_tensor_variable_new(graph);
    1170
    1
      ccv_nnc_dynamic_graph_exec(graph, CMD_MUL_FORWARD(1), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(a, y), TENSOR_VARIABLE_LIST(z), 0, 0);
    1171
    1
      REQUIRE_EQ_WITH_TOLERANCE(ccv_nnc_tensor_from_variable(graph, z)->data.f32[0], 5 * log(10), 1e-5, "should match the result");
    1172
    1
      REQUIRE_EQ(ccv_nnc_dynamic_graph_bookkeeping_count(graph, CCV_NNC_SYMBOL_GRAPH_EXEC), 2, "nothing should be freed");
    1173
    1
      REQUIRE_EQ(ccv_nnc_dynamic_graph_bookkeeping_count(graph, CCV_NNC_SYMBOL_TENSOR), 4, "nothing should be freed");
    1174
    1
      uint64_t bitmask = 0;
    1175
    1
      ccv_nnc_dynamic_graph_has_effect_to_tensor_variables(graph, TENSOR_VARIABLE_LIST(x), TENSOR_VARIABLE_LIST(z), &bitmask);
    1176
    1
      REQUIRE(bitmask == 1, "before detach, it should have effect");
    1177
    1
      ccv_nnc_tensor_variable_detach(graph, y);
    1178
    1
      REQUIRE_EQ(ccv_nnc_dynamic_graph_bookkeeping_count(graph, CCV_NNC_SYMBOL_GRAPH_EXEC), 2, "nothing should be freed");
    1179
    1
      REQUIRE_EQ(ccv_nnc_dynamic_graph_bookkeeping_count(graph, CCV_NNC_SYMBOL_TENSOR), 4, "nothing should be freed");
    1180
    1
      bitmask = 0;
    1181
    1
      ccv_nnc_dynamic_graph_has_effect_to_tensor_variables(graph, TENSOR_VARIABLE_LIST(x), TENSOR_VARIABLE_LIST(z), &bitmask);
    1182
    1
      REQUIRE(bitmask == 0, "after detach, it should have no effect");
    1183
    1
      ccv_nnc_tensor_variable_free(graph, a);
    1184
    1
      REQUIRE_EQ(ccv_nnc_dynamic_graph_bookkeeping_count(graph, CCV_NNC_SYMBOL_GRAPH_EXEC), 1, "a * y should be freed");
    1185
    1
      REQUIRE_EQ(ccv_nnc_dynamic_graph_bookkeeping_count(graph, CCV_NNC_SYMBOL_TENSOR), 3, "a should be freed");
    1186
    1
      ccv_nnc_tensor_variable_free(graph, x);
    1187
    1
      REQUIRE_EQ(ccv_nnc_dynamic_graph_bookkeeping_count(graph, CCV_NNC_SYMBOL_GRAPH_EXEC), 0, "everything should be freed");
    1188
    1
      REQUIRE_EQ(ccv_nnc_dynamic_graph_bookkeeping_count(graph, CCV_NNC_SYMBOL_TENSOR), 1, "x and y should be freed");
    1189
    1
      ccv_nnc_tensor_variable_free(graph, y);
    1190
    1
      ccv_nnc_tensor_variable_free(graph, z);
    1191
    1
      REQUIRE_EQ(ccv_nnc_dynamic_graph_bookkeeping_count(graph, CCV_NNC_SYMBOL_TENSOR), 0, "everything should be freed");
    1192
    1
      ccv_nnc_dynamic_graph_free(graph);
    1193
    1
    }
    1194
    1195
    TEST_CASE("compute f(x) = exp(x) * log(x), detach log(x) means nothing changed")
    1196
    1
    {
    1197
    1
      ccv_nnc_dynamic_graph_t* const graph = ccv_nnc_dynamic_graph_new();
    1198
    1
      ccv_nnc_tensor_variable_t x = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 1));
    1199
    1
      ccv_nnc_tensor_from_variable(graph, x)->data.f32[0] = 10;
    1200
    1
      ccv_nnc_tensor_variable_t a = ccv_nnc_tensor_variable_new(graph);
    1201
    1
      ccv_nnc_dynamic_graph_exec(graph, CMD_EWEXP_FORWARD(), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(x), TENSOR_VARIABLE_LIST(a), 0, 0);
    1202
    1
      REQUIRE_EQ_WITH_TOLERANCE(ccv_nnc_tensor_from_variable(graph, a)->data.f32[0], exp(10), 1e-2, "should match the result");
    1203
    1
      ccv_nnc_tensor_variable_t y = ccv_nnc_tensor_variable_new(graph);
    1204
    1
      ccv_nnc_dynamic_graph_exec(graph, CMD_EWLOG_FORWARD(), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(x), TENSOR_VARIABLE_LIST(y), 0, 0);
    1205
    1
      REQUIRE_EQ_WITH_TOLERANCE(ccv_nnc_tensor_from_variable(graph, y)->data.f32[0], log(10), 1e-5, "should match the result");
    1206
    1
      ccv_nnc_tensor_variable_t z = ccv_nnc_tensor_variable_new(graph);
    1207
    1
      ccv_nnc_dynamic_graph_exec(graph, CMD_MUL_FORWARD(1), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(a, y), TENSOR_VARIABLE_LIST(z), 0, 0);
    1208
    1
      REQUIRE_EQ_WITH_TOLERANCE(ccv_nnc_tensor_from_variable(graph, z)->data.f32[0], exp(10) * log(10), 1e-2, "should match the result");
    1209
    1
      REQUIRE_EQ(ccv_nnc_dynamic_graph_bookkeeping_count(graph, CCV_NNC_SYMBOL_GRAPH_EXEC), 3, "nothing should be freed");
    1210
    1
      REQUIRE_EQ(ccv_nnc_dynamic_graph_bookkeeping_count(graph, CCV_NNC_SYMBOL_TENSOR), 4, "nothing should be freed");
    1211
    1
      uint64_t bitmask = 0;
    1212
    1
      ccv_nnc_dynamic_graph_has_effect_to_tensor_variables(graph, TENSOR_VARIABLE_LIST(x), TENSOR_VARIABLE_LIST(z), &bitmask);
    1213
    1
      REQUIRE(bitmask == 1, "before detach, it should have effect");
    1214
    1
      ccv_nnc_tensor_variable_detach(graph, y);
    1215
    1
      REQUIRE_EQ(ccv_nnc_dynamic_graph_bookkeeping_count(graph, CCV_NNC_SYMBOL_GRAPH_EXEC), 3, "nothing should be freed");
    1216
    1
      REQUIRE_EQ(ccv_nnc_dynamic_graph_bookkeeping_count(graph, CCV_NNC_SYMBOL_TENSOR), 4, "nothing should be freed");
    1217
    1
      bitmask = 0;
    1218
    1
      ccv_nnc_dynamic_graph_has_effect_to_tensor_variables(graph, TENSOR_VARIABLE_LIST(x), TENSOR_VARIABLE_LIST(z), &bitmask);
    1219
    1
      REQUIRE(bitmask == 1, "after detach, it should have still effect (through exp(x))");
    1220
    1
      ccv_nnc_tensor_variable_detach(graph, a);
    1221
    1
      REQUIRE_EQ(ccv_nnc_dynamic_graph_bookkeeping_count(graph, CCV_NNC_SYMBOL_GRAPH_EXEC), 2, "a * y should be freed");
    1222
    1
      REQUIRE_EQ(ccv_nnc_dynamic_graph_bookkeeping_count(graph, CCV_NNC_SYMBOL_TENSOR), 4, "nothing should be freed");
    1223
    1
      bitmask = 0;
    1224
    1
      ccv_nnc_dynamic_graph_has_effect_to_tensor_variables(graph, TENSOR_VARIABLE_LIST(x), TENSOR_VARIABLE_LIST(z), &bitmask);
    1225
    1
      REQUIRE(bitmask == 0, "after a freed, it should have no effect");
    1226
    1
      ccv_nnc_tensor_variable_free(graph, a);
    1227
    1
      REQUIRE_EQ(ccv_nnc_dynamic_graph_bookkeeping_count(graph, CCV_NNC_SYMBOL_TENSOR), 3, "a should be freed");
    1228
    1
      ccv_nnc_tensor_variable_free(graph, x);
    1229
    1
      REQUIRE_EQ(ccv_nnc_dynamic_graph_bookkeeping_count(graph, CCV_NNC_SYMBOL_GRAPH_EXEC), 0, "everything should be freed");
    1230
    1
      REQUIRE_EQ(ccv_nnc_dynamic_graph_bookkeeping_count(graph, CCV_NNC_SYMBOL_TENSOR), 1, "x and y should be freed");
    1231
    1
      ccv_nnc_tensor_variable_free(graph, y);
    1232
    1
      ccv_nnc_tensor_variable_free(graph, z);
    1233
    1
      REQUIRE_EQ(ccv_nnc_dynamic_graph_bookkeeping_count(graph, CCV_NNC_SYMBOL_TENSOR), 0, "everything should be freed");
    1234
    1
      ccv_nnc_dynamic_graph_free(graph);
    1235
    1
    }
    1236
    1237
    TEST_CASE("compute f(x) = exp(0.5 * log(x)), detach log(x) won't free exp(_)")
    1238
    1
    {
    1239
    1
      ccv_nnc_dynamic_graph_t* const graph = ccv_nnc_dynamic_graph_new();
    1240
    1
      ccv_nnc_tensor_variable_t x = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 1));
    1241
    1
      ccv_nnc_tensor_from_variable(graph, x)->data.f32[0] = 10;
    1242
    1
      ccv_nnc_tensor_variable_t y = ccv_nnc_tensor_variable_new(graph);
    1243
    1
      ccv_nnc_dynamic_graph_exec(graph, CMD_EWLOG_FORWARD(), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(x), TENSOR_VARIABLE_LIST(y), 0, 0);
    1244
    1
      REQUIRE_EQ_WITH_TOLERANCE(ccv_nnc_tensor_from_variable(graph, y)->data.f32[0], log(10), 1e-5, "should match the result");
    1245
    1
      ccv_nnc_tensor_variable_t z = ccv_nnc_tensor_variable_new(graph);
    1246
    1
      ccv_nnc_dynamic_graph_exec(graph, CMD_SCALAR_MUL_FORWARD(0.5), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(y), TENSOR_VARIABLE_LIST(z), 0, 0);
    1247
    1
      REQUIRE_EQ_WITH_TOLERANCE(ccv_nnc_tensor_from_variable(graph, z)->data.f32[0], 0.5 * log(10), 1e-5, "should match the result");
    1248
    1
      ccv_nnc_tensor_variable_t f = ccv_nnc_tensor_variable_new(graph);
    1249
    1
      ccv_nnc_dynamic_graph_exec(graph, CMD_EWEXP_FORWARD(), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(z), TENSOR_VARIABLE_LIST(f), 0, 0);
    1250
    1
      REQUIRE_EQ_WITH_TOLERANCE(ccv_nnc_tensor_from_variable(graph, f)->data.f32[0], exp(0.5 * log(10)), 1e-5, "should match the result");
    1251
    1
      uint64_t bitmask = 0;
    1252
    1
      ccv_nnc_dynamic_graph_has_effect_to_tensor_variables(graph, TENSOR_VARIABLE_LIST(x), TENSOR_VARIABLE_LIST(f), &bitmask);
    1253
    1
      REQUIRE(bitmask == 1, "before detach, it should have effect");
    1254
    1
      ccv_nnc_tensor_variable_detach(graph, y);
    1255
    1
      REQUIRE_EQ(ccv_nnc_dynamic_graph_bookkeeping_count(graph, CCV_NNC_SYMBOL_GRAPH_EXEC), 2, "0.5 * y should be freed");
    1256
    1
      REQUIRE_EQ(ccv_nnc_dynamic_graph_bookkeeping_count(graph, CCV_NNC_SYMBOL_TENSOR), 4, "nothing should be freed");
    1257
    1
      bitmask = 0;
    1258
    1
      ccv_nnc_dynamic_graph_has_effect_to_tensor_variables(graph, TENSOR_VARIABLE_LIST(x), TENSOR_VARIABLE_LIST(f), &bitmask);
    1259
    1
      REQUIRE(bitmask == 0, "after detach, it should have no effect");
    1260
    1
      ccv_nnc_tensor_variable_free(graph, f);
    1261
    1
      REQUIRE_EQ(ccv_nnc_dynamic_graph_bookkeeping_count(graph, CCV_NNC_SYMBOL_GRAPH_EXEC), 1, "exp(_) should be freed");
    1262
    1
      REQUIRE_EQ(ccv_nnc_dynamic_graph_bookkeeping_count(graph, CCV_NNC_SYMBOL_TENSOR), 3, "f should be freed");
    1263
    1
      ccv_nnc_tensor_variable_free(graph, z);
    1264
    1
      REQUIRE_EQ(ccv_nnc_dynamic_graph_bookkeeping_count(graph, CCV_NNC_SYMBOL_GRAPH_EXEC), 1, "nothing should change");
    1265
    1
      REQUIRE_EQ(ccv_nnc_dynamic_graph_bookkeeping_count(graph, CCV_NNC_SYMBOL_TENSOR), 2, "z should be freed");
    1266
    1
      ccv_nnc_tensor_variable_free(graph, y);
    1267
    1
      REQUIRE_EQ(ccv_nnc_dynamic_graph_bookkeeping_count(graph, CCV_NNC_SYMBOL_GRAPH_EXEC), 0, "log(x) should be freed");
    1268
    1
      REQUIRE_EQ(ccv_nnc_dynamic_graph_bookkeeping_count(graph, CCV_NNC_SYMBOL_TENSOR), 1, "y should be freed");
    1269
    1
      ccv_nnc_tensor_variable_free(graph, x);
    1270
    1
      REQUIRE_EQ(ccv_nnc_dynamic_graph_bookkeeping_count(graph, CCV_NNC_SYMBOL_TENSOR), 0, "x should be freed");
    1271
    1
      ccv_nnc_dynamic_graph_free(graph);
    1272
    1
    }
    1273
    1274
    TEST_CASE("cnnp reshape supports -1 dimension")
    1275
    1
    {
    1276
    1
      ccv_cnnp_model_t* const reshape = ccv_cnnp_reshape(0, DIM_ALLOC(-1, 4), DIM_ALLOC(), DIM_ALLOC(), 0);
    1277
    1
      ccv_nnc_dynamic_graph_t* const graph = ccv_nnc_dynamic_graph_new();
    1278
    1
      ccv_nnc_tensor_variable_t x = ccv_nnc_tensor_variable_new(graph, CPU_TENSOR_NHWC(32F, 2, 3, 4));
    1279
    1
      int i;
    1280
    25
      for (i = 0; i < 2 * 3 * 4; i++24)
    1281
    24
        ccv_nnc_tensor_from_variable(graph, x)->data.f32[i] = i;
    1282
    1
      const ccv_nnc_tensor_param_t input = CPU_TENSOR_NHWC(32F, 2, 3, 4);
    1283
    1
      ccv_cnnp_model_compile(reshape, &input, 1, CMD_NOOP(), CMD_NOOP());
    1284
    1
      ccv_nnc_tensor_variable_t y = ccv_nnc_tensor_variable_new(graph);
    1285
    1
      ccv_nnc_dynamic_graph_evaluate(graph, reshape, 0, TENSOR_VARIABLE_LIST(x), TENSOR_VARIABLE_LIST(y), 0, 0);
    1286
    1
      REQUIRE_EQ(ccv_nnc_tensor_from_variable(graph, y)->info.dim[0], 6, "dim inference");
    1287
    1
      REQUIRE_EQ(ccv_nnc_tensor_from_variable(graph, y)->info.dim[1], 4, "dim inference");
    1288
    1
      float btp[24];
    1289
    25
      for (i = 0; i < 24; i++24)
    1290
    24
        btp[i] = i;
    1291
    1
      ccv_nnc_tensor_t bt = ccv_nnc_tensor(btp, CPU_TENSOR_NHWC(32F, 6, 4), 0);
    1292
    1
      REQUIRE_TENSOR_EQ(ccv_nnc_tensor_from_variable(graph, y), &bt, "reshape correctness");
    1293
    1
      ccv_nnc_dynamic_graph_free(graph);
    1294
    1
      ccv_cnnp_model_free(reshape);
    1295
    1
    }
    1296
    1297
    #include "case_main.h"