## 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/crossentropy.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
    8
    TEST_SETUP()
    9
    {
    10
      ccv_nnc_init();
    11
    }
    12
    13
    TEST_CASE("compare softmax + categorical crossentropy v.s. softmax crossentropy command")
    14
    1
    {
    15
    1
      ccv_nnc_symbolic_graph_t* const graph = ccv_nnc_symbolic_graph_new();
    16
      // batch size = 2, dim = 3.
    17
    1
      const ccv_nnc_tensor_symbol_t a = ccv_nnc_tensor_symbol_new(graph, CPU_TENSOR_NHWC(32F, 2, 3), "a");
    18
    1
      const ccv_nnc_tensor_symbol_t b0 = ccv_nnc_tensor_symbol_new(graph, CPU_TENSOR_NHWC(32F, 2, 3), "b0");
    19
    1
      ccv_nnc_graph_exec_symbol_new(graph, CMD_SOFTMAX_FORWARD(), TENSOR_SYMBOL_LIST(a), TENSOR_SYMBOL_LIST(b0), "softmax");
    20
    1
      const ccv_nnc_tensor_symbol_t label = ccv_nnc_tensor_symbol_new(graph, CPU_TENSOR_NHWC(32S, 2), "label");
    21
    1
      const ccv_nnc_tensor_symbol_t loss0 = ccv_nnc_tensor_symbol_new(graph, ccv_nnc_tensor_auto, "loss0");
    22
    1
      ccv_nnc_graph_exec_symbol_new(graph, CMD_CATEGORICAL_CROSSENTROPY_FORWARD(), TENSOR_SYMBOL_LIST(b0, label), TENSOR_SYMBOL_LIST(loss0), "categorical crossentropy");
    23
    1
      const ccv_nnc_tensor_symbol_t b1 = ccv_nnc_tensor_symbol_new(graph, CPU_TENSOR_NHWC(32F, 2, 3), "b1");
    24
    1
      const ccv_nnc_tensor_symbol_t loss1 = ccv_nnc_tensor_symbol_new(graph, ccv_nnc_tensor_auto, "loss1");
    25
    1
      ccv_nnc_graph_exec_symbol_new(graph, CMD_SOFTMAX_CROSSENTROPY_FORWARD(), TENSOR_SYMBOL_LIST(a, label), TENSOR_SYMBOL_LIST(loss1, b1), "softmax crossentropy");
    26
    1
      ccv_nnc_graph_exec_symbol_autogen(graph, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
    27
    1
      ccv_nnc_symbolic_graph_backward(graph, TENSOR_SYMBOL_LIST(loss0), TENSOR_SYMBOL_LIST(a), SYMBOLIC_GRAPH_SOURCES(graph), SYMBOLIC_GRAPH_DESTINATIONS(graph));
    28
    1
      const ccv_nnc_tensor_symbol_t dloss0 = ccv_nnc_tensor_symbol_for_backward(graph, loss0);
    29
    1
      const ccv_nnc_tensor_symbol_t da0 = ccv_nnc_tensor_symbol_for_backward(graph, a);
    30
    1
      ccv_nnc_symbolic_graph_backward(graph, TENSOR_SYMBOL_LIST(loss1), TENSOR_SYMBOL_LIST(a), SYMBOLIC_GRAPH_SOURCES(graph), SYMBOLIC_GRAPH_DESTINATIONS(graph));
    31
    1
      const ccv_nnc_tensor_symbol_t dloss1 = ccv_nnc_tensor_symbol_for_backward(graph, loss1);
    32
    1
      ccv_nnc_graph_exec_symbol_new(graph, CMD_SET_FORWARD(1), 0, 0, TENSOR_SYMBOL_LIST(dloss0, dloss1), "set 1");
    33
    1
      const ccv_nnc_tensor_symbol_t da1 = ccv_nnc_tensor_symbol_for_backward(graph, a);
    34
    1
      ccv_nnc_graph_exec_symbol_autogen(graph, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
    35
    1
      SYMBOLIC_GRAPH_GEN(graph, CCV_NNC_LONG_DOT_GRAPH);
    36
    1
      ccv_nnc_graph_t* run_graph;
    37
    1
      ccv_nnc_tensor_arena_t* tensor_arena;
    38
    1
      ccv_nnc_graph_exec_arena_t* graph_exec_arena;
    39
    1
      ccv_nnc_symbolic_graph_compile(graph, ccv_nnc_default_compile_params,
    40
    1
        0, 0,
    41
    1
        TENSOR_SYMBOL_LIST(loss0, loss1, da0, da1),
    42
    1
        SYMBOLIC_GRAPH_SOURCES(graph), SYMBOLIC_GRAPH_DESTINATIONS(graph),
    43
    1
        &run_graph, &tensor_arena, &graph_exec_arena);
    44
    1
      ccv_nnc_tensor_t* const a_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, a);
    45
    1
      a_tensor->data.f32[0] = 10;
    46
    1
      a_tensor->data.f32[1] = -1;
    47
    1
      a_tensor->data.f32[2] = -5;
    48
    1
      a_tensor->data.f32[3] = 12;
    49
    1
      a_tensor->data.f32[4] = 4;
    50
    1
      a_tensor->data.f32[5] = 24;
    51
    1
      ccv_nnc_tensor_t* const label_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, label);
    52
    1
      label_tensor->data.i32[0] = 2;
    53
    1
      label_tensor->data.i32[1] = 1;
    54
    1
      ccv_nnc_graph_run(run_graph, 0, TRAVERSE_FULL, 0, 0);
    55
    1
      ccv_nnc_tensor_t* const da0_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, da0);
    56
    1
      ccv_nnc_tensor_t* const da1_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, da1);
    57
    1
      REQUIRE_TENSOR_EQ(da0_tensor, da1_tensor, "two tensors from combined op and separate ops should be equal");
    58
    1
      ccv_nnc_tensor_t* const loss0_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, loss0);
    59
    1
      ccv_nnc_tensor_t* const loss1_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, loss1);
    60
    1
      REQUIRE_TENSOR_EQ(loss0_tensor, loss1_tensor, "two tensors from combined op and separate ops should be equal");
    61
    1
      ccv_nnc_graph_free(run_graph);
    62
    1
      ccv_nnc_tensor_arena_free(tensor_arena);
    63
    1
      ccv_nnc_graph_exec_arena_free(graph_exec_arena);
    64
    1
      ccv_nnc_symbolic_graph_free(graph);
    65
    1
    }
    66
    67
    TEST_CASE("compare label smoothing with one hot and label for categorical crossentropy command")
    68
    1
    {
    69
    1
      ccv_nnc_symbolic_graph_t* const graph = ccv_nnc_symbolic_graph_new();
    70
      // batch size = 2, dim = 3.
    71
    1
      const ccv_nnc_tensor_symbol_t a = ccv_nnc_tensor_symbol_new(graph, CPU_TENSOR_NHWC(32F, 2, 3), "a");
    72
    1
      const ccv_nnc_tensor_symbol_t oh = ccv_nnc_tensor_symbol_new(graph, CPU_TENSOR_NHWC(32F, 2, 3), "oh");
    73
    1
      const ccv_nnc_tensor_symbol_t loss0 = ccv_nnc_tensor_symbol_new(graph, ccv_nnc_tensor_auto, "loss0");
    74
    1
      ccv_nnc_graph_exec_symbol_new(graph, CMD_CATEGORICAL_CROSSENTROPY_FORWARD(0.1, 0.9), TENSOR_SYMBOL_LIST(a, oh), TENSOR_SYMBOL_LIST(loss0), "categorical with one hot");
    75
    1
      const ccv_nnc_tensor_symbol_t label = ccv_nnc_tensor_symbol_new(graph, CPU_TENSOR_NHWC(32S, 2, 1), "label");
    76
    1
      const ccv_nnc_tensor_symbol_t loss1 = ccv_nnc_tensor_symbol_new(graph, ccv_nnc_tensor_auto, "loss1");
    77
    1
      ccv_nnc_graph_exec_symbol_new(graph, CMD_CATEGORICAL_CROSSENTROPY_FORWARD(0.1, 0.9), TENSOR_SYMBOL_LIST(a, label), TENSOR_SYMBOL_LIST(loss1), "categorical with label");
    78
    1
      ccv_nnc_graph_exec_symbol_autogen(graph, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
    79
    1
      ccv_nnc_symbolic_graph_backward(graph, TENSOR_SYMBOL_LIST(loss0), TENSOR_SYMBOL_LIST(a), SYMBOLIC_GRAPH_SOURCES(graph), SYMBOLIC_GRAPH_DESTINATIONS(graph));
    80
    1
      const ccv_nnc_tensor_symbol_t dloss0 = ccv_nnc_tensor_symbol_for_backward(graph, loss0);
    81
    1
      const ccv_nnc_tensor_symbol_t da0 = ccv_nnc_tensor_symbol_for_backward(graph, a);
    82
    1
      ccv_nnc_symbolic_graph_backward(graph, TENSOR_SYMBOL_LIST(loss1), TENSOR_SYMBOL_LIST(a), SYMBOLIC_GRAPH_SOURCES(graph), SYMBOLIC_GRAPH_DESTINATIONS(graph));
    83
    1
      const ccv_nnc_tensor_symbol_t dloss1 = ccv_nnc_tensor_symbol_for_backward(graph, loss1);
    84
    1
      const ccv_nnc_tensor_symbol_t da1 = ccv_nnc_tensor_symbol_for_backward(graph, a);
    85
    1
      ccv_nnc_graph_exec_symbol_new(graph, CMD_SET_FORWARD(1), 0, 0, TENSOR_SYMBOL_LIST(dloss0, dloss1), "set 1");
    86
    1
      ccv_nnc_graph_exec_symbol_autogen(graph, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
    87
    1
      SYMBOLIC_GRAPH_GEN(graph, CCV_NNC_LONG_DOT_GRAPH);
    88
    1
      ccv_nnc_graph_t* run_graph;
    89
    1
      ccv_nnc_tensor_arena_t* tensor_arena;
    90
    1
      ccv_nnc_graph_exec_arena_t* graph_exec_arena;
    91
    1
      ccv_nnc_symbolic_graph_compile(graph, ccv_nnc_default_compile_params,
    92
    1
        0, 0,
    93
    1
        TENSOR_SYMBOL_LIST(loss0, loss1, da0, da1),
    94
    1
        SYMBOLIC_GRAPH_SOURCES(graph), SYMBOLIC_GRAPH_DESTINATIONS(graph), &run_graph, &tensor_arena, &graph_exec_arena);
    95
    1
      ccv_nnc_tensor_t* const a_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, a);
    96
    1
      a_tensor->data.f32[0] = 10;
    97
    1
      a_tensor->data.f32[1] = -2;
    98
    1
      a_tensor->data.f32[2] = -5;
    99
    1
      a_tensor->data.f32[3] = -12;
    100
    1
      a_tensor->data.f32[4] = 4;
    101
    1
      a_tensor->data.f32[5] = 24;
    102
    1
      ccv_nnc_tensor_t* const oh_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, oh);
    103
    1
      oh_tensor->data.f32[0] = 0.1;
    104
    1
      oh_tensor->data.f32[1] = 0.1;
    105
    1
      oh_tensor->data.f32[2] = 0.9;
    106
    1
      oh_tensor->data.f32[3] = 0.1;
    107
    1
      oh_tensor->data.f32[4] = 0.9;
    108
    1
      oh_tensor->data.f32[5] = 0.1;
    109
    1
      ccv_nnc_tensor_t* const label_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, label);
    110
    1
      label_tensor->data.i32[0] = 2;
    111
    1
      label_tensor->data.i32[1] = 1;
    112
    1
      ccv_nnc_graph_run(run_graph, 0, TRAVERSE_FULL, 0, 0);
    113
    1
      ccv_nnc_tensor_t* const loss0_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, loss0);
    114
    1
      ccv_nnc_tensor_t* const loss1_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, loss1);
    115
    1
      REQUIRE_TENSOR_EQ(loss0_tensor, loss1_tensor, "two tensors from one hot and label with smoothing should be equal");
    116
    1
      ccv_nnc_tensor_t* const da0_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, da0);
    117
    1
      ccv_nnc_tensor_t* const da1_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, da1);
    118
    1
      REQUIRE_TENSOR_EQ(da0_tensor, da1_tensor, "two tensors from one hot and label with smoothing should be equal");
    119
    1
      ccv_nnc_graph_free(run_graph);
    120
    1
      ccv_nnc_tensor_arena_free(tensor_arena);
    121
    1
      ccv_nnc_graph_exec_arena_free(graph_exec_arena);
    122
    1
      ccv_nnc_symbolic_graph_free(graph);
    123
    1
    }
    124
    125
    TEST_CASE("compare label smoothing with one hot and label for softmax crossentropy command")
    126
    1
    {
    127
    1
      ccv_nnc_symbolic_graph_t* const graph = ccv_nnc_symbolic_graph_new();
    128
      // batch size = 2, dim = 3.
    129
    1
      const ccv_nnc_tensor_symbol_t a = ccv_nnc_tensor_symbol_new(graph, CPU_TENSOR_NHWC(32F, 2, 3), "a");
    130
    1
      const ccv_nnc_tensor_symbol_t oh = ccv_nnc_tensor_symbol_new(graph, CPU_TENSOR_NHWC(32F, 2, 3), "oh");
    131
    1
      const ccv_nnc_tensor_symbol_t b0 = ccv_nnc_tensor_symbol_new(graph, ccv_nnc_tensor_auto, "b0");
    132
    1
      const ccv_nnc_tensor_symbol_t loss0 = ccv_nnc_tensor_symbol_new(graph, ccv_nnc_tensor_auto, "loss0");
    133
    1
      ccv_nnc_graph_exec_symbol_new(graph, CMD_SOFTMAX_CROSSENTROPY_FORWARD(0.1, 0.9), TENSOR_SYMBOL_LIST(a, oh), TENSOR_SYMBOL_LIST(loss0, b0), "softmax with one hot");
    134
    1
      const ccv_nnc_tensor_symbol_t label = ccv_nnc_tensor_symbol_new(graph, CPU_TENSOR_NHWC(32S, 2, 1), "label");
    135
    1
      const ccv_nnc_tensor_symbol_t b1 = ccv_nnc_tensor_symbol_new(graph, ccv_nnc_tensor_auto, "b1");
    136
    1
      const ccv_nnc_tensor_symbol_t loss1 = ccv_nnc_tensor_symbol_new(graph, ccv_nnc_tensor_auto, "loss1");
    137
    1
      ccv_nnc_graph_exec_symbol_new(graph, CMD_SOFTMAX_CROSSENTROPY_FORWARD(0.1, 0.9), TENSOR_SYMBOL_LIST(a, label), TENSOR_SYMBOL_LIST(loss1, b1), "softmax with label");
    138
    1
      ccv_nnc_graph_exec_symbol_autogen(graph, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
    139
    1
      ccv_nnc_symbolic_graph_backward(graph, TENSOR_SYMBOL_LIST(loss0), TENSOR_SYMBOL_LIST(a), SYMBOLIC_GRAPH_SOURCES(graph), SYMBOLIC_GRAPH_DESTINATIONS(graph));
    140
    1
      const ccv_nnc_tensor_symbol_t dloss0 = ccv_nnc_tensor_symbol_for_backward(graph, loss0);
    141
    1
      const ccv_nnc_tensor_symbol_t da0 = ccv_nnc_tensor_symbol_for_backward(graph, a);
    142
    1
      ccv_nnc_symbolic_graph_backward(graph, TENSOR_SYMBOL_LIST(loss1), TENSOR_SYMBOL_LIST(a), SYMBOLIC_GRAPH_SOURCES(graph), SYMBOLIC_GRAPH_DESTINATIONS(graph));
    143
    1
      const ccv_nnc_tensor_symbol_t dloss1 = ccv_nnc_tensor_symbol_for_backward(graph, loss1);
    144
    1
      const ccv_nnc_tensor_symbol_t da1 = ccv_nnc_tensor_symbol_for_backward(graph, a);
    145
    1
      ccv_nnc_graph_exec_symbol_new(graph, CMD_SET_FORWARD(1), 0, 0, TENSOR_SYMBOL_LIST(dloss0, dloss1), "set 1");
    146
    1
      ccv_nnc_graph_exec_symbol_autogen(graph, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
    147
    1
      SYMBOLIC_GRAPH_GEN(graph, CCV_NNC_LONG_DOT_GRAPH);
    148
    1
      ccv_nnc_graph_t* run_graph;
    149
    1
      ccv_nnc_tensor_arena_t* tensor_arena;
    150
    1
      ccv_nnc_graph_exec_arena_t* graph_exec_arena;
    151
    1
      ccv_nnc_symbolic_graph_compile(graph, ccv_nnc_default_compile_params,
    152
    1
        0, 0,
    153
    1
        TENSOR_SYMBOL_LIST(loss0, loss1, b0, b1, da0, da1),
    154
    1
        SYMBOLIC_GRAPH_SOURCES(graph), SYMBOLIC_GRAPH_DESTINATIONS(graph), &run_graph, &tensor_arena, &graph_exec_arena);
    155
    1
      ccv_nnc_tensor_t* const a_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, a);
    156
    1
      a_tensor->data.f32[0] = 10;
    157
    1
      a_tensor->data.f32[1] = -2;
    158
    1
      a_tensor->data.f32[2] = -5;
    159
    1
      a_tensor->data.f32[3] = -12;
    160
    1
      a_tensor->data.f32[4] = 4;
    161
    1
      a_tensor->data.f32[5] = 24;
    162
    1
      ccv_nnc_tensor_t* const oh_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, oh);
    163
    1
      oh_tensor->data.f32[0] = 0.1;
    164
    1
      oh_tensor->data.f32[1] = 0.1;
    165
    1
      oh_tensor->data.f32[2] = 0.9;
    166
    1
      oh_tensor->data.f32[3] = 0.1;
    167
    1
      oh_tensor->data.f32[4] = 0.9;
    168
    1
      oh_tensor->data.f32[5] = 0.1;
    169
    1
      ccv_nnc_tensor_t* const label_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, label);
    170
    1
      label_tensor->data.i32[0] = 2;
    171
    1
      label_tensor->data.i32[1] = 1;
    172
    1
      ccv_nnc_graph_run(run_graph, 0, TRAVERSE_FULL, 0, 0);
    173
    1
      ccv_nnc_tensor_t* const loss0_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, loss0);
    174
    1
      ccv_nnc_tensor_t* const loss1_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, loss1);
    175
    1
      REQUIRE_TENSOR_EQ(loss0_tensor, loss1_tensor, "two tensors from one hot and label with smoothing should be equal");
    176
    1
      ccv_nnc_tensor_t* const b0_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, b0);
    177
    1
      ccv_nnc_tensor_t* const b1_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, b1);
    178
    1
      REQUIRE_TENSOR_EQ(b0_tensor, b1_tensor, "two tensors from one hot and label with smoothing should be equal");
    179
    1
      ccv_nnc_tensor_t* const da0_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, da0);
    180
    1
      ccv_nnc_tensor_t* const da1_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, da1);
    181
    1
      REQUIRE_TENSOR_EQ(da0_tensor, da1_tensor, "two tensors from one hot and label with smoothing should be equal");
    182
    1
      ccv_nnc_graph_free(run_graph);
    183
    1
      ccv_nnc_tensor_arena_free(tensor_arena);
    184
    1
      ccv_nnc_graph_exec_arena_free(graph_exec_arena);
    185
    1
      ccv_nnc_symbolic_graph_free(graph);
    186
    1
    }
    187
    188
    TEST_CASE("compare sigmoid + binary entropy v.s. sigmoid binary entropy command")
    189
    1
    {
    190
    1
      ccv_nnc_symbolic_graph_t* const graph = ccv_nnc_symbolic_graph_new();
    191
      // batch size = 2, dim = 3.
    192
    1
      const ccv_nnc_tensor_symbol_t a = ccv_nnc_tensor_symbol_new(graph, CPU_TENSOR_NHWC(32F, 2, 3), "a");
    193
    1
      const ccv_nnc_tensor_symbol_t b0 = ccv_nnc_tensor_symbol_new(graph, CPU_TENSOR_NHWC(32F, 2, 3), "b0");
    194
    1
      ccv_nnc_graph_exec_symbol_new(graph, CMD_SIGMOID_FORWARD(), TENSOR_SYMBOL_LIST(a), TENSOR_SYMBOL_LIST(b0), "sigmoid");
    195
    1
      const ccv_nnc_tensor_symbol_t label = ccv_nnc_tensor_symbol_new(graph, CPU_TENSOR_NHWC(32F, 2, 3), "label");
    196
    1
      const ccv_nnc_tensor_symbol_t loss0 = ccv_nnc_tensor_symbol_new(graph, ccv_nnc_tensor_auto, "loss0");
    197
    1
      ccv_nnc_graph_exec_symbol_new(graph, CMD_BINARY_CROSSENTROPY_FORWARD(), TENSOR_SYMBOL_LIST(b0, label), TENSOR_SYMBOL_LIST(loss0), "binary crossentropy");
    198
    1
      const ccv_nnc_tensor_symbol_t b1 = ccv_nnc_tensor_symbol_new(graph, CPU_TENSOR_NHWC(32F, 2, 3), "b1");
    199
    1
      const ccv_nnc_tensor_symbol_t loss1 = ccv_nnc_tensor_symbol_new(graph, ccv_nnc_tensor_auto, "loss1");
    200
    1
      ccv_nnc_graph_exec_symbol_new(graph, CMD_SIGMOID_BINARY_CROSSENTROPY_FORWARD(), TENSOR_SYMBOL_LIST(a, label), TENSOR_SYMBOL_LIST(loss1, b1), "sigmoid binary crossentropy");
    201
    1
      ccv_nnc_graph_exec_symbol_autogen(graph, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
    202
    1
      ccv_nnc_symbolic_graph_backward(graph, TENSOR_SYMBOL_LIST(loss0), TENSOR_SYMBOL_LIST(a), SYMBOLIC_GRAPH_SOURCES(graph), SYMBOLIC_GRAPH_DESTINATIONS(graph));
    203
    1
      const ccv_nnc_tensor_symbol_t dloss0 = ccv_nnc_tensor_symbol_for_backward(graph, loss0);
    204
    1
      const ccv_nnc_tensor_symbol_t da0 = ccv_nnc_tensor_symbol_for_backward(graph, a);
    205
    1
      ccv_nnc_symbolic_graph_backward(graph, TENSOR_SYMBOL_LIST(loss1), TENSOR_SYMBOL_LIST(a), SYMBOLIC_GRAPH_SOURCES(graph), SYMBOLIC_GRAPH_DESTINATIONS(graph));
    206
    1
      const ccv_nnc_tensor_symbol_t dloss1 = ccv_nnc_tensor_symbol_for_backward(graph, loss1);
    207
    1
      ccv_nnc_graph_exec_symbol_new(graph, CMD_SET_FORWARD(1), 0, 0, TENSOR_SYMBOL_LIST(dloss0, dloss1), "set 1");
    208
    1
      const ccv_nnc_tensor_symbol_t da1 = ccv_nnc_tensor_symbol_for_backward(graph, a);
    209
    1
      ccv_nnc_graph_exec_symbol_autogen(graph, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
    210
    1
      SYMBOLIC_GRAPH_GEN(graph, CCV_NNC_LONG_DOT_GRAPH);
    211
    1
      ccv_nnc_graph_t* run_graph;
    212
    1
      ccv_nnc_tensor_arena_t* tensor_arena;
    213
    1
      ccv_nnc_graph_exec_arena_t* graph_exec_arena;
    214
    1
      ccv_nnc_symbolic_graph_compile(graph, ccv_nnc_default_compile_params,
    215
    1
        0, 0,
    216
    1
        TENSOR_SYMBOL_LIST(da0, da1, loss0, loss1),
    217
    1
        SYMBOLIC_GRAPH_SOURCES(graph), SYMBOLIC_GRAPH_DESTINATIONS(graph),
    218
    1
        &run_graph, &tensor_arena, &graph_exec_arena);
    219
    1
      ccv_nnc_tensor_t* const a_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, a);
    220
    1
      a_tensor->data.f32[0] = 10;
    221
    1
      a_tensor->data.f32[1] = -1;
    222
    1
      a_tensor->data.f32[2] = -5;
    223
    1
      a_tensor->data.f32[3] = 12;
    224
    1
      a_tensor->data.f32[4] = 4;
    225
    1
      a_tensor->data.f32[5] = 5;
    226
    1
      ccv_nnc_tensor_t* const label_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, label);
    227
    1
      label_tensor->data.f32[0] = 1;
    228
    1
      label_tensor->data.f32[1] = 0;
    229
    1
      label_tensor->data.f32[2] = 0;
    230
    1
      label_tensor->data.f32[3] = 1;
    231
    1
      label_tensor->data.f32[4] = 1;
    232
    1
      label_tensor->data.f32[5] = 0;
    233
    1
      ccv_nnc_graph_run(run_graph, 0, TRAVERSE_FULL, 0, 0);
    234
    1
      ccv_nnc_tensor_t* const da0_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, da0);
    235
    1
      ccv_nnc_tensor_t* const da1_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, da1);
    236
    1
      REQUIRE_TENSOR_EQ(da0_tensor, da1_tensor, "two tensors from combined op and separate ops should be equal");
    237
    1
      ccv_nnc_tensor_t* const loss0_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, loss0);
    238
    1
      ccv_nnc_tensor_t* const loss1_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, loss1);
    239
    1
      REQUIRE_TENSOR_EQ(loss0_tensor, loss1_tensor, "two tensors from combined op and separate ops should be equal");
    240
    1
      ccv_nnc_graph_free(run_graph);
    241
    1
      ccv_nnc_tensor_arena_free(tensor_arena);
    242
    1
      ccv_nnc_graph_exec_arena_free(graph_exec_arena);
    243
    1
      ccv_nnc_symbolic_graph_free(graph);
    244
    1
    }
    245
    246
    TEST_CASE("compare sigmoid + binary entropy v.s. sigmoid binary entropy command with pos_weight")
    247
    1
    {
    248
    1
      ccv_nnc_symbolic_graph_t* const graph = ccv_nnc_symbolic_graph_new();
    249
      // batch size = 2, dim = 3.
    250
    1
      const ccv_nnc_tensor_symbol_t a = ccv_nnc_tensor_symbol_new(graph, CPU_TENSOR_NHWC(32F, 2, 3), "a");
    251
    1
      const ccv_nnc_tensor_symbol_t b0 = ccv_nnc_tensor_symbol_new(graph, CPU_TENSOR_NHWC(32F, 2, 3), "b0");
    252
    1
      ccv_nnc_graph_exec_symbol_new(graph, CMD_SIGMOID_FORWARD(), TENSOR_SYMBOL_LIST(a), TENSOR_SYMBOL_LIST(b0), "sigmoid");
    253
    1
      const ccv_nnc_tensor_symbol_t label = ccv_nnc_tensor_symbol_new(graph, CPU_TENSOR_NHWC(32F, 2, 3), "label");
    254
    1
      const ccv_nnc_tensor_symbol_t loss0 = ccv_nnc_tensor_symbol_new(graph, ccv_nnc_tensor_auto, "loss0");
    255
    1
      const float pos_weight = 1.2;
    256
    1
      ccv_nnc_graph_exec_symbol_new(graph, CMD_BINARY_CROSSENTROPY_FORWARD(pos_weight), TENSOR_SYMBOL_LIST(b0, label), TENSOR_SYMBOL_LIST(loss0), "binary crossentropy");
    257
    1
      const ccv_nnc_tensor_symbol_t b1 = ccv_nnc_tensor_symbol_new(graph, CPU_TENSOR_NHWC(32F, 2, 3), "b1");
    258
    1
      const ccv_nnc_tensor_symbol_t loss1 = ccv_nnc_tensor_symbol_new(graph, ccv_nnc_tensor_auto, "loss1");
    259
    1
      ccv_nnc_graph_exec_symbol_new(graph, CMD_SIGMOID_BINARY_CROSSENTROPY_FORWARD(pos_weight), TENSOR_SYMBOL_LIST(a, label), TENSOR_SYMBOL_LIST(loss1, b1), "sigmoid binary crossentropy");
    260
    1
      ccv_nnc_graph_exec_symbol_autogen(graph, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
    261
    1
      ccv_nnc_symbolic_graph_backward(graph, TENSOR_SYMBOL_LIST(loss0), TENSOR_SYMBOL_LIST(a), SYMBOLIC_GRAPH_SOURCES(graph), SYMBOLIC_GRAPH_DESTINATIONS(graph));
    262
    1
      const ccv_nnc_tensor_symbol_t dloss0 = ccv_nnc_tensor_symbol_for_backward(graph, loss0);
    263
    1
      const ccv_nnc_tensor_symbol_t da0 = ccv_nnc_tensor_symbol_for_backward(graph, a);
    264
    1
      ccv_nnc_symbolic_graph_backward(graph, TENSOR_SYMBOL_LIST(loss1), TENSOR_SYMBOL_LIST(a), SYMBOLIC_GRAPH_SOURCES(graph), SYMBOLIC_GRAPH_DESTINATIONS(graph));
    265
    1
      const ccv_nnc_tensor_symbol_t dloss1 = ccv_nnc_tensor_symbol_for_backward(graph, loss1);
    266
    1
      ccv_nnc_graph_exec_symbol_new(graph, CMD_SET_FORWARD(1), 0, 0, TENSOR_SYMBOL_LIST(dloss0, dloss1), "set 1");
    267
    1
      const ccv_nnc_tensor_symbol_t da1 = ccv_nnc_tensor_symbol_for_backward(graph, a);
    268
    1
      ccv_nnc_graph_exec_symbol_autogen(graph, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
    269
    1
      SYMBOLIC_GRAPH_GEN(graph, CCV_NNC_LONG_DOT_GRAPH);
    270
    1
      ccv_nnc_graph_t* run_graph;
    271
    1
      ccv_nnc_tensor_arena_t* tensor_arena;
    272
    1
      ccv_nnc_graph_exec_arena_t* graph_exec_arena;
    273
    1
      ccv_nnc_symbolic_graph_compile(graph, ccv_nnc_default_compile_params,
    274
    1
        0, 0,
    275
    1
        TENSOR_SYMBOL_LIST(da0, da1, loss0, loss1),
    276
    1
        SYMBOLIC_GRAPH_SOURCES(graph), SYMBOLIC_GRAPH_DESTINATIONS(graph),
    277
    1
        &run_graph, &tensor_arena, &graph_exec_arena);
    278
    1
      ccv_nnc_tensor_t* const a_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, a);
    279
    1
      a_tensor->data.f32[0] = 10;
    280
    1
      a_tensor->data.f32[1] = -1;
    281
    1
      a_tensor->data.f32[2] = -5;
    282
    1
      a_tensor->data.f32[3] = 12;
    283
    1
      a_tensor->data.f32[4] = 4;
    284
    1
      a_tensor->data.f32[5] = 5;
    285
    1
      ccv_nnc_tensor_t* const label_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, label);
    286
    1
      label_tensor->data.f32[0] = 1;
    287
    1
      label_tensor->data.f32[1] = 0;
    288
    1
      label_tensor->data.f32[2] = 0;
    289
    1
      label_tensor->data.f32[3] = 1;
    290
    1
      label_tensor->data.f32[4] = 1;
    291
    1
      label_tensor->data.f32[5] = 0;
    292
    1
      ccv_nnc_graph_run(run_graph, 0, TRAVERSE_FULL, 0, 0);
    293
    1
      ccv_nnc_tensor_t* const da0_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, da0);
    294
    1
      ccv_nnc_tensor_t* const da1_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, da1);
    295
    1
      REQUIRE_TENSOR_EQ(da0_tensor, da1_tensor, "two tensors from combined op and separate ops should be equal");
    296
    1
      ccv_nnc_tensor_t* const loss0_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, loss0);
    297
    1
      ccv_nnc_tensor_t* const loss1_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, loss1);
    298
    1
      REQUIRE_TENSOR_EQ(loss0_tensor, loss1_tensor, "two tensors from combined op and separate ops should be equal");
    299
    1
      ccv_nnc_graph_free(run_graph);
    300
    1
      ccv_nnc_tensor_arena_free(tensor_arena);
    301
    1
      ccv_nnc_graph_exec_arena_free(graph_exec_arena);
    302
    1
      ccv_nnc_symbolic_graph_free(graph);
    303
    1
    }
    304
    305
    #include "case_main.h"