## 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/int/nnc/graph.vgg.d.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 <inc/ccv_convnet_internal.h>
    8
    9
    TEST_SETUP()
    10
    {
    11
      ccv_nnc_init();
    12
    }
    13
    14
    static ccv_nnc_graph_t* ccv_nnc_simple_graph(ccv_convnet_t* convnet, ccv_nnc_tensor_t* input, ccv_nnc_tensor_t* output, ccv_nnc_graph_exec_t* source, ccv_nnc_graph_exec_t* dest, ccv_array_t* tensors)
    15
    1
    {
    16
    1
      int i;
    17
      // We only create the graph compute to the last fc layer.
    18
    1
      ccv_nnc_graph_t* vgg = ccv_nnc_graph_new();
    19
    1
      ccv_nnc_graph_exec_t previous_exec;
    20
    22
      for (i = 0; i < convnet->count; i++21)
    21
    21
      {
    22
    21
        ccv_convnet_layer_t* layer = convnet->layers + i;
    23
    21
        int rows, cols, partition;
    24
    21
        ccv_convnet_make_output(layer, layer->input.matrix.rows, layer->input.matrix.cols, &rows, &cols, &partition);
    25
    21
        ccv_nnc_tensor_t* tensor = output;
    26
    21
        if (i < convnet->count - 1)
    27
    20
        {
    28
    20
          if (layer->type == CCV_CONVNET_FULL_CONNECT)
    29
    2
            tensor = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, rows * cols * partition), 0);
    30
    18
          else
    31
    18
            tensor = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, rows, cols, (layer->type == CCV_CONVNET_CONVOLUTIONAL ? layer->net.convolutional.count : layer->input.matrix.channels)), 0);
    32
    20
          ccv_array_push(tensors, &tensor);
    33
    20
        }
    34
    21
        ccv_nnc_graph_exec_t exec = {0};
    35
    21
        if (layer->type == CCV_CONVNET_CONVOLUTIONAL)
    36
    13
        {
    37
    13
          ccv_nnc_tensor_t* w = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, layer->net.convolutional.count, layer->net.convolutional.rows, layer->net.convolutional.cols, layer->net.convolutional.channels), 0);
    38
    13
          memcpy(w->data.f32, layer->w, layer->wnum * sizeof(float));
    39
    13
          ccv_nnc_tensor_t* bias = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, layer->net.convolutional.count), 0);
    40
    13
          memcpy(bias->data.f32, layer->bias, layer->net.convolutional.count * sizeof(float));
    41
    13
          ccv_array_push(tensors, &w);
    42
    13
          ccv_array_push(tensors, &bias);
    43
    13
          ccv_nnc_cmd_t cmd = CMD_CONVOLUTION_FORWARD(1, layer->net.convolutional.count, layer->net.convolutional.rows, layer->net.convolutional.cols, layer->net.convolutional.channels);
    44
    13
          ccv_nnc_hint_t hint = ccv_nnc_hint_auto(cmd.info, input->info, tensor->info);
    45
    13
          cmd = ccv_nnc_cmd_autotune(cmd, 0, hint, 0, TENSOR_LIST(input, w, bias), TENSOR_LIST(tensor), 0);
    46
    13
          exec = ccv_nnc_graph_exec_new(vgg, cmd, hint, TENSOR_LIST(input, w, bias), TENSOR_LIST(tensor));
    47
    13
        } else if (8layer->type == CCV_CONVNET_MAX_POOL8) {
    48
    5
          ccv_nnc_cmd_t cmd = CMD_MAX_POOL_FORWARD(layer->net.pool.size, layer->net.pool.size);
    49
    5
          ccv_nnc_hint_t hint = ccv_nnc_hint_auto(cmd.info, input->info, tensor->info);
    50
    5
          exec = ccv_nnc_graph_exec_new(vgg, cmd, hint, TENSOR_LIST(input), TENSOR_LIST(tensor));
    51
    5
        } else if (3layer->type == CCV_CONVNET_FULL_CONNECT3) {
    52
    3
          ccv_nnc_tensor_t* w = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, layer->net.full_connect.count, layer->input.node.count), 0);
    53
    3
          memcpy(w->data.f32, layer->w, layer->wnum * sizeof(float));
    54
    3
          ccv_nnc_tensor_t* bias = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, layer->net.full_connect.count), 0);
    55
    3
          memcpy(bias->data.f32, layer->bias, layer->net.full_connect.count * sizeof(float));
    56
    3
          ccv_array_push(tensors, &w);
    57
    3
          ccv_array_push(tensors, &bias);
    58
    3
          ccv_nnc_cmd_t cmd = CMD_GEMM_FORWARD(NO_TRANSPOSE, TRANSPOSE(0, 1));
    59
          // If the input is not what I expected (array), reshape it.
    60
    3
          if (input->info.dim[0] != ccv_nnc_tensor_count(input->info))
    61
    1
          {
    62
    1
            input = ccv_nnc_tensor_new(input->data.u8, CPU_TENSOR_NHWC(32F, ccv_nnc_tensor_count(input->info)), 0);
    63
    1
            ccv_array_push(tensors, &input);
    64
    1
          }
    65
    3
          cmd = ccv_nnc_cmd_autotune(cmd, 0, ccv_nnc_no_hint, 0, TENSOR_LIST(input, w, bias), TENSOR_LIST(tensor), 0);
    66
    3
          exec = ccv_nnc_graph_exec_new(vgg, cmd, ccv_nnc_no_hint, TENSOR_LIST(input, w, bias), TENSOR_LIST(tensor));
    67
    3
        } else {
    68
    0
          assert("unreachable");
    69
    0
        }
    70
    21
        if (i != 0)
    71
    20
          ccv_nnc_graph_exec_concat(vgg, previous_exec, exec);
    72
    21
        previous_exec = exec;
    73
    21
        if (i == 0)
    74
    1
          *source = exec;
    75
    21
        if (i < convnet->count - 1 &&
    76
    21
          (20layer->type == CCV_CONVNET_CONVOLUTIONAL20 || layer->type == CCV_CONVNET_FULL_CONNECT7))
    77
    15
        {
    78
          // Create the ReLU layer.
    79
    15
          ccv_nnc_cmd_t cmd = CMD_RELU_FORWARD();
    80
    15
          exec = ccv_nnc_graph_exec_new(vgg, cmd, ccv_nnc_no_hint, TENSOR_LIST(tensor), TENSOR_LIST(tensor));
    81
    15
          ccv_nnc_graph_exec_concat(vgg, previous_exec, exec);
    82
    15
          previous_exec = exec;
    83
    15
        }
    84
    21
        if (i == convnet->count - 1)
    85
    1
          *dest = exec;
    86
        // This is the input of next layer.
    87
    21
        input = tensor;
    88
    21
      }
    89
    1
      return vgg;
    90
    1
    }
    91
    92
    #ifdef HAVE_LIBPNG
    93
    TEST_CASE("run vgg-d graph with nnc")
    94
    1
    {
    95
    1
      ccv_convnet_t* convnet = ccv_convnet_read(0, "../../../samples/image-net-2012-vgg-d.sqlite3");
    96
    1
      ccv_dense_matrix_t* image = 0;
    97
    1
      ccv_read("../../../samples/dex.png", &image, CCV_IO_ANY_FILE | CCV_IO_RGB_COLOR);
    98
    1
      ccv_dense_matrix_t* input = 0;
    99
    1
      ccv_convnet_input_formation(convnet->input, image, &input);
    100
    1
      ccv_matrix_free(image);
    101
    1
      ccv_dense_matrix_t* sliced = 0;
    102
    1
      ccv_slice(input, (ccv_matrix_t**)&sliced, 0, (input->rows - 225) / 2, (input->cols - 225) / 2, 225, 225);
    103
    1
      ccv_matrix_free(input);
    104
    1
      ccv_dense_matrix_t* b = 0;
    105
    1
      ccv_convnet_encode(convnet, &sliced, &b, 1);
    106
    1
      ccv_nnc_tensor_t* c = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 1000), 0);
    107
    1
      ccv_nnc_graph_exec_t source, dest;
    108
    1
      ccv_array_t* tensors = ccv_array_new(sizeof(ccv_nnc_tensor_t*), 1, 0);
    109
    1
      ccv_nnc_graph_t* graph = ccv_nnc_simple_graph(convnet, (ccv_nnc_tensor_t*)sliced, c, &source, &dest, tensors);
    110
    1
      GRAPH_GEN(graph, CCV_NNC_LONG_DOT_GRAPH);
    111
    1
      ccv_nnc_graph_run(graph, 0, &source, 1, &dest, 1, 0, 0);
    112
    1
      REQUIRE_ARRAY_EQ_WITH_TOLERANCE(float, b->data.f32, c->data.f32, 1000, 1e-4, "output should be the same from convnet and from the graph");
    113
    1
      ccv_nnc_tensor_free(c);
    114
    1
      ccv_matrix_free(sliced);
    115
    1
      ccv_matrix_free(b);
    116
    1
      ccv_nnc_graph_free(graph);
    117
    1
      int i;
    118
    54
      for (i = 0; i < tensors->rnum; i++53)
    119
    53
        ccv_nnc_tensor_free(*(ccv_nnc_tensor_t**)ccv_array_get(tensors, i));
    120
    1
      ccv_array_free(tensors);
    121
    1
      ccv_convnet_free(convnet);
    122
    1
    }
    123
    #endif
    124
    125
    #include "case_main.h"