## 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/lib/cuda/cwc_convnet_ext.c

    Line
    Count
    Source
    1
    #include "cwc.h"
    2
    #include "../ccv_internal.h"
    3
    #ifdef HAVE_GSL
    4
    #include <gsl/gsl_rng.h>
    5
    #include <gsl/gsl_randist.h>
    6
    #endif
    7
    #include "cwc_ext.h"
    8
    #ifdef USE_OPENMP
    9
    #include <omp.h>
    10
    #endif
    11
    #ifdef USE_DISPATCH
    12
    #include <dispatch/dispatch.h>
    13
    #endif
    14
    15
    #ifdef HAVE_GSL
    16
    static void _cwc_convnet_random_image_manipulation(gsl_rng* rng, ccv_dense_matrix_t* image, float image_manipulation)
    17
    0
    {
    18
    0
      assert(rng && CCV_GET_CHANNEL(image->type) == CCV_C3 && image_manipulation > 0 && image_manipulation <= 1);
    19
    0
      int ord[3] = {0, 1, 2};
    20
    0
      gsl_ran_shuffle(rng, ord, 3, sizeof(int));
    21
    0
      int i;
    22
    0
      for (i = 0; i < 3; i++)
    23
        // change the applying order
    24
    0
        switch (ord[i])
    25
    0
        {
    26
    0
          case 0:
    27
            // introduce some brightness changes to the original image
    28
    0
            ccv_scale(image, (ccv_matrix_t**)&image, 0, gsl_rng_uniform_pos(rng) * image_manipulation * 2 + (1 - image_manipulation));
    29
    0
            break;
    30
    0
          case 1:
    31
            // introduce some saturation changes to the original image
    32
    0
            ccv_saturation(image, &image, 0, gsl_rng_uniform_pos(rng) * image_manipulation * 2 + (1 - image_manipulation));
    33
    0
            break;
    34
    0
          case 2:
    35
            // introduce some contrast changes to the original image
    36
    0
            ccv_contrast(image, &image, 0, gsl_rng_uniform_pos(rng) * image_manipulation * 2 + (1 - image_manipulation));
    37
    0
            break;
    38
    0
        }
    39
    0
    }
    40
    41
    void cwc_convnet_batch_formation(gsl_rng* rng, ccv_array_t* categorizeds, ccv_dense_matrix_t* mean_activity, ccv_dense_matrix_t* eigenvectors, ccv_dense_matrix_t* eigenvalues, float image_manipulation, float color_gain, int* idx, ccv_size_t dim, int min_dim, int max_dim, int rows, int cols, int channels, int category_count, int symmetric, int batch, int offset, int size, float* b, int* c)
    42
    0
    {
    43
    0
      assert(size > 0 && size <= batch);
    44
    0
      assert(min_dim >= rows && min_dim >= cols);
    45
    0
      assert(max_dim >= min_dim);
    46
    0
      float* channel_gains = (float*)alloca(sizeof(float) * channels * size);
    47
    0
      memset(channel_gains, 0, sizeof(float) * channels * size);
    48
    0
      int i;
    49
    0
      gsl_rng** rngs = (gsl_rng**)alloca(sizeof(gsl_rng*) * size);
    50
    0
      memset(rngs, 0, sizeof(gsl_rng*) * size);
    51
    0
      if (rng)
    52
    0
        for (i = 0; i < size; i++)
    53
    0
        {
    54
    0
          rngs[i] = gsl_rng_alloc(gsl_rng_default);
    55
    0
          gsl_rng_set(rngs[i], gsl_rng_get(rng));
    56
    0
        }
    57
    0
      parallel_for(i, size) {
    58
    0
        int j, k;
    59
    0
        assert(offset + i < categorizeds->rnum);
    60
    0
        ccv_categorized_t* categorized = (ccv_categorized_t*)ccv_array_get(categorizeds, idx ? idx[offset + i] : offset + i);
    61
    0
        assert(categorized->c < category_count && categorized->c >= 0); // now only accept classes listed
    62
    0
        if (c)
    63
    0
          c[i] = categorized->c;
    64
    0
        ccv_dense_matrix_t* image = 0;
    65
    0
        switch (categorized->type)
    66
    0
        {
    67
    0
          case CCV_CATEGORIZED_DENSE_MATRIX:
    68
    0
            image = categorized->matrix;
    69
    0
            break;
    70
    0
          case CCV_CATEGORIZED_FILE:
    71
    0
            image = 0;
    72
    0
            ccv_read(categorized->file.filename, &image, CCV_IO_ANY_FILE | CCV_IO_RGB_COLOR);
    73
    0
            break;
    74
    0
        }
    75
    0
        if (image)
    76
    0
        {
    77
          // first resize to between min_dim and max_dim
    78
    0
          ccv_dense_matrix_t* input = 0;
    79
    0
          ccv_size_t resize = dim;
    80
    0
          if (rngs[i]) // randomize the resized dimensions
    81
    0
          {
    82
    0
            int d = gsl_rng_uniform_int(rngs[i], max_dim - min_dim + 1) + min_dim;
    83
    0
            resize = ccv_size(d, d);
    84
    0
          }
    85
          // if neither side is the same as expected, we have to resize first
    86
    0
          if (resize.height != image->rows && resize.width != image->cols)
    87
    0
            ccv_convnet_input_formation(resize, image, &input);
    88
    0
          else
    89
    0
            input = image;
    90
    0
          if (rngs[i] && image_manipulation > 0)
    91
    0
            _cwc_convnet_random_image_manipulation(rngs[i], input, image_manipulation);
    92
    0
          ccv_dense_matrix_t* patch = 0;
    93
    0
          if (input->cols != cols || input->rows != rows)
    94
    0
          {
    95
    0
            int x = rngs[i] ? gsl_rng_uniform_int(rngs[i], input->cols - cols + 1) : (input->cols - cols + 1) / 2;
    96
    0
            int y = rngs[i] ? gsl_rng_uniform_int(rngs[i], input->rows - rows + 1) : (input->rows - rows + 1) / 2;
    97
    0
            ccv_slice(input, (ccv_matrix_t**)&patch, CCV_32F, y, x, rows, cols);
    98
    0
          } else
    99
    0
            ccv_shift(input, (ccv_matrix_t**)&patch, CCV_32F, 0, 0); // converting to 32f
    100
    0
          if (input != image) // only unload if we created new input
    101
    0
            ccv_matrix_free(input);
    102
          // we loaded image in, deallocate it now
    103
    0
          if (categorized->type != CCV_CATEGORIZED_DENSE_MATRIX)
    104
    0
            ccv_matrix_free(image);
    105
          // random horizontal reflection
    106
    0
          if (symmetric && rngs[i] && gsl_rng_uniform_int(rngs[i], 2) == 0)
    107
    0
            ccv_flip(patch, &patch, 0, CCV_FLIP_X);
    108
    0
          int x = rngs[i] ? gsl_rng_uniform_int(rngs[i], mean_activity->cols - cols + 1) : (mean_activity->cols - cols + 1) / 2;
    109
    0
          int y = rngs[i] ? gsl_rng_uniform_int(rngs[i], mean_activity->rows - rows + 1) : (mean_activity->rows - rows + 1) / 2;
    110
    0
          ccv_dense_matrix_t mean_patch = ccv_reshape(mean_activity, y, x, rows, cols);
    111
    0
          ccv_subtract(patch, &mean_patch, (ccv_matrix_t**)&patch, 0);
    112
    0
          assert(channels == CCV_GET_CHANNEL(patch->type));
    113
    0
          if (color_gain > 0 && rngs[i] && eigenvectors && eigenvalues)
    114
    0
          {
    115
    0
            assert(channels == 3); // only support RGB color gain
    116
    0
            memset(channel_gains + channels * i, 0, sizeof(float) * channels);
    117
    0
            for (j = 0; j < channels; j++)
    118
    0
            {
    119
    0
              float alpha = gsl_ran_gaussian(rngs[i], color_gain) * eigenvalues->data.f64[j];
    120
    0
              for (k = 0; k < channels; k++)
    121
    0
                channel_gains[k + i * channels] += eigenvectors->data.f64[j * channels + k] * alpha;
    122
    0
            }
    123
    0
          }
    124
    0
          for (j = 0; j < channels; j++)
    125
    0
            for (k = 0; k < rows * cols; k++)
    126
    0
              b[(j * rows * cols + k) * batch + i] = patch->data.f32[k * channels + j] + channel_gains[j + i * channels];
    127
    0
          ccv_matrix_free(patch);
    128
    0
        } else
    129
    0
          PRINT(CCV_CLI_ERROR, "cannot load %s.\n", categorized->file.filename);
    130
    0
      } parallel_endfor
    131
    0
      if (rng)
    132
    0
        for (i = 0; i < size; i++)
    133
    0
          gsl_rng_free(rngs[i]);
    134
    0
    }
    135
    #endif
    136
    137
    void cwc_convnet_mean_formation(ccv_array_t* categorizeds, ccv_size_t dim, int channels, int symmetric, ccv_dense_matrix_t** b)
    138
    0
    {
    139
    0
      int i, count = 0;
    140
    0
      ccv_dense_matrix_t* c = ccv_dense_matrix_new(dim.height, dim.width, channels | CCV_64F, 0, 0);
    141
    0
      ccv_zero(c);
    142
    0
      ccv_dense_matrix_t* db = *b = ccv_dense_matrix_renew(*b, dim.height, dim.width, channels | CCV_32F, channels | CCV_32F, 0);
    143
    0
      for (i = 0; i < categorizeds->rnum; i++)
    144
    0
      {
    145
    0
        if (i % 23 == 0 || i == categorizeds->rnum - 1)
    146
    0
          FLUSH(CCV_CLI_INFO, " - compute mean activity %d / %d", i + 1, categorizeds->rnum);
    147
    0
        ccv_categorized_t* categorized = (ccv_categorized_t*)ccv_array_get(categorizeds, i);
    148
    0
        ccv_dense_matrix_t* image = 0;
    149
    0
        switch (categorized->type)
    150
    0
        {
    151
    0
          case CCV_CATEGORIZED_DENSE_MATRIX:
    152
    0
            image = categorized->matrix;
    153
    0
            break;
    154
    0
          case CCV_CATEGORIZED_FILE:
    155
    0
            ccv_read(categorized->file.filename, &image, CCV_IO_ANY_FILE | CCV_IO_RGB_COLOR);
    156
    0
            break;
    157
    0
        }
    158
    0
        if (!image)
    159
    0
        {
    160
    0
          PRINT(CCV_CLI_ERROR, "cannot load %s.\n", categorized->file.filename);
    161
    0
          continue;
    162
    0
        }
    163
    0
        ccv_dense_matrix_t* patch = 0;
    164
    0
        if (image->cols != dim.width || image->rows != dim.height)
    165
    0
        {
    166
    0
          int x = (image->cols - dim.width + 1) / 2;
    167
    0
          int y = (image->rows - dim.height + 1) / 2;
    168
    0
          assert(x == 0 || y == 0);
    169
    0
          ccv_slice(image, (ccv_matrix_t**)&patch, CCV_32F, y, x, dim.height, dim.width);
    170
    0
        } else
    171
    0
          ccv_shift(image, (ccv_matrix_t**)&patch, CCV_32F, 0, 0); // converting to 32f
    172
    0
        if (categorized->type != CCV_CATEGORIZED_DENSE_MATRIX)
    173
    0
          ccv_matrix_free(image);
    174
    0
        ccv_add(patch, c, (ccv_matrix_t**)&c, CCV_64F);
    175
    0
        ++count;
    176
    0
        ccv_matrix_free(patch);
    177
    0
      }
    178
    0
      if (symmetric)
    179
    0
      {
    180
    0
        int j, k;
    181
    0
        double p = 0.5 / count;
    182
    0
        double* cptr = c->data.f64;
    183
    0
        float* dbptr = db->data.f32;
    184
    0
        for (i = 0; i < db->rows; i++)
    185
    0
        {
    186
    0
          for (j = 0; j < db->cols; j++)
    187
    0
            for (k = 0; k < channels; k++)
    188
    0
              dbptr[j * channels + k] = p * (cptr[j * channels + k] + cptr[(c->cols - j - 1) * channels + k]);
    189
    0
          dbptr += db->cols * channels;
    190
    0
          cptr += c->cols * channels;
    191
    0
        }
    192
    0
      } else {
    193
    0
        double p = 1.0 / count;
    194
    0
        for (i = 0; i < dim.height * dim.width * channels; i++)
    195
    0
          db->data.f32[i] = p * c->data.f64[i];
    196
    0
      }
    197
    0
      ccv_matrix_free(c);
    198
    0
      PRINT(CCV_CLI_INFO, "\n");
    199
    0
    }
    200
    201
    void cwc_convnet_channel_eigen(ccv_array_t* categorizeds, ccv_dense_matrix_t* mean_activity, ccv_size_t dim, int channels, ccv_dense_matrix_t** eigenvectors, ccv_dense_matrix_t** eigenvalues)
    202
    0
    {
    203
    0
      assert(channels == 3); // this function cannot handle anything other than 3x3 covariance matrix
    204
    0
      double* mean_value = (double*)alloca(sizeof(double) * channels);
    205
    0
      memset(mean_value, 0, sizeof(double) * channels);
    206
    0
      assert(CCV_GET_CHANNEL(mean_activity->type) == channels);
    207
    0
      assert(mean_activity->rows == dim.height);
    208
    0
      assert(mean_activity->cols == dim.width);
    209
    0
      int i, j, k, c, count = 0;
    210
    0
      for (i = 0; i < dim.height * dim.width; i++)
    211
    0
        for (k = 0; k < channels; k++)
    212
    0
          mean_value[k] += mean_activity->data.f32[i * channels + k];
    213
    0
      for (i = 0; i < channels; i++)
    214
    0
        mean_value[i] = mean_value[i] / (dim.height * dim.width);
    215
    0
      double* covariance = (double*)alloca(sizeof(double) * channels * channels);
    216
    0
      memset(covariance, 0, sizeof(double) * channels * channels);
    217
    0
      for (c = 0; c < categorizeds->rnum; c++)
    218
    0
      {
    219
    0
        if (c % 23 == 0 || c == categorizeds->rnum - 1)
    220
    0
          FLUSH(CCV_CLI_INFO, " - compute covariance matrix for data augmentation (color gain) %d / %d", c + 1, categorizeds->rnum);
    221
    0
        ccv_categorized_t* categorized = (ccv_categorized_t*)ccv_array_get(categorizeds, c);
    222
    0
        ccv_dense_matrix_t* image = 0;
    223
    0
        switch (categorized->type)
    224
    0
        {
    225
    0
          case CCV_CATEGORIZED_DENSE_MATRIX:
    226
    0
            image = categorized->matrix;
    227
    0
            break;
    228
    0
          case CCV_CATEGORIZED_FILE:
    229
    0
            ccv_read(categorized->file.filename, &image, CCV_IO_ANY_FILE | CCV_IO_RGB_COLOR);
    230
    0
            break;
    231
    0
        }
    232
    0
        if (!image)
    233
    0
        {
    234
    0
          PRINT(CCV_CLI_ERROR, "cannot load %s.\n", categorized->file.filename);
    235
    0
          continue;
    236
    0
        }
    237
    0
        ccv_dense_matrix_t* patch = 0;
    238
    0
        if (image->cols != dim.width || image->rows != dim.height)
    239
    0
        {
    240
    0
          int x = (image->cols - dim.width + 1) / 2;
    241
    0
          int y = (image->rows - dim.height + 1) / 2;
    242
    0
          assert(x == 0 || y == 0);
    243
    0
          ccv_slice(image, (ccv_matrix_t**)&patch, CCV_32F, y, x, dim.height, dim.width);
    244
    0
        } else
    245
    0
          ccv_shift(image, (ccv_matrix_t**)&patch, CCV_32F, 0, 0); // converting to 32f
    246
    0
        if (categorized->type != CCV_CATEGORIZED_DENSE_MATRIX)
    247
    0
          ccv_matrix_free(image);
    248
    0
        for (i = 0; i < dim.width * dim.height; i++)
    249
    0
          for (j = 0; j < channels; j++)
    250
    0
            for (k = j; k < channels; k++)
    251
    0
              covariance[j * channels + k] += (patch->data.f32[i * channels + j] - mean_value[j]) * (patch->data.f32[i * channels + k] - mean_value[k]);
    252
    0
        ++count;
    253
    0
        ccv_matrix_free(patch);
    254
    0
      }
    255
    0
      for (i = 0; i < channels; i++)
    256
    0
        for (j = 0; j < i; j++)
    257
    0
          covariance[i * channels + j] = covariance[j * channels + i];
    258
    0
      double p = 1.0 / ((double)count * dim.height * dim.width);
    259
    0
      for (i = 0; i < channels; i++)
    260
    0
        for (j = 0; j < channels; j++)
    261
    0
          covariance[i * channels + j] *= p; // scale down
    262
    0
      ccv_dense_matrix_t covm = ccv_dense_matrix(3, 3, CCV_64F | CCV_C1, covariance, 0);
    263
    0
      ccv_eigen(&covm, eigenvectors, eigenvalues, CCV_64F, 1e-8);
    264
      PRINT(CCV_CLI_INFO, "\n");
    265
    0
    }