Coverage Report

Created: 2024-12-10 23:11

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
}