Coverage Report

Created: 2024-08-18 16:21

/home/liu/actions-runner/_work/ccv/ccv/test/unit/nnc/gradient.tests.c
Line
Count
Source
1
#include "case.h"
2
#include "ccv_case.h"
3
#include <ccv.h>
4
#include <nnc/ccv_nnc.h>
5
#include <nnc/ccv_nnc_easy.h>
6
#include "3rdparty/dsfmt/dSFMT.h"
7
8
TEST_SETUP()
9
94
{
10
94
  ccv_nnc_init();
11
94
}
12
13
// five-stencil constants
14
static double fs[4] = { 1, -8, 8, -1 };
15
static double fsh[4] = { -2, -1, 1, 2 };
16
17
TEST_CASE("numerical gradient versus analytical gradient for convolutional network")
18
1
{
19
1
  ccv_nnc_tensor_t* a = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 31, 21, 2), 0);
20
1
  ccv_nnc_tensor_t* b = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 31, 21, 4), 0);
21
1
  ccv_nnc_cmd_t forw_cmd = CMD_CONVOLUTION_FORWARD(1, 4, 5, 3, 2);
22
1
  ccv_nnc_hint_t hint = ccv_nnc_hint_auto(forw_cmd.info, a->info, b->info);
23
1
  ccv_nnc_tensor_t* w = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 4, 5, 3, 2), 0);
24
1
  ccv_nnc_tensor_t* bias = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 4), 0);
25
1
  dsfmt_t dsfmt;
26
1
  dsfmt_init_gen_rand(&dsfmt, 1);
27
1
  int i, j;
28
121
  for (i = 0; i < 2 * 3 * 5 * 4; 
i++120
)
29
120
    w->data.f32[i] = (dsfmt_genrand_open_close(&dsfmt) * 2 - 1) * 1.41421356237 / sqrtf(21 * 31 * 2 + 21 * 31 * 4);
30
1
  float denom = (21 * 31 * 2 - 1) * 21 * 31 * 2;
31
1.30k
  for (i = 0; i < 21 * 31 * 2; 
i++1.30k
)
32
1.30k
    a->data.f32[i] = (float)(i - 21 * 31) / denom;
33
5
  for (i = 0; i < 4; 
i++4
)
34
4
    bias->data.f32[i] = 0;
35
1
  ccv_nnc_cmd_exec(forw_cmd, hint, 0, TENSOR_LIST(a, w, bias), TENSOR_LIST(b), 0);
36
1
  ccv_nnc_tensor_t* ba = ccv_nnc_tensor_new(b->data.f32, CPU_TENSOR_NHWC(32F, 31 * 21 * 4), 0);
37
1
  ccv_nnc_tensor_t* m = ccv_nnc_tensor_new(0, ba->info, 0);
38
1
  ccv_nnc_cmd_exec(CMD_SOFTMAX_FORWARD(), hint, 0, TENSOR_LIST(ba), TENSOR_LIST(m), 0);
39
1
  ccv_nnc_cmd_t back_cmd = CMD_CONVOLUTION_BACKWARD(1, 4, 5, 3, 2);
40
1
  ccv_nnc_tensor_t* gw = ccv_nnc_tensor_new(0, w->info, 0);
41
1
  ccv_nnc_tensor_t* gbias = ccv_nnc_tensor_new(0, bias->info, 0);
42
1
  ccv_nnc_tensor_t* g = ccv_nnc_tensor_new(0, b->info, 0);
43
1
  ccv_nnc_tensor_t* h = ccv_nnc_tensor_new(0, a->info, 0);
44
2.60k
  for (i = 0; i < 21 * 31 * 4; 
i++2.60k
)
45
2.60k
    g->data.f32[i] = m->data.f32[i] - (i == 24);
46
1
  ccv_nnc_cmd_exec(back_cmd, hint, 0, TENSOR_LIST(g, a, w), TENSOR_LIST(h, gw, gbias), 0);
47
  // Now doing numeric gradient computation
48
1
  static const double eps = 0.001;
49
1
  float* dw = (float*)ccmalloc(sizeof(float) * 2 * 3 * 5 * 4); 
50
121
  for (i = 0; i < 2 * 3 * 5 * 4; 
i++120
)
51
120
  {
52
120
    double vw = 0;
53
600
    for (j = 0; j < 4; 
j++480
)
54
480
    {
55
480
      float old_w = w->data.f32[i];
56
480
      w->data.f32[i] += fsh[j] * eps;
57
480
      ccv_nnc_cmd_exec(forw_cmd, hint, 0, TENSOR_LIST(a, w, bias), TENSOR_LIST(b), 0);
58
480
      ccv_nnc_cmd_exec(CMD_SOFTMAX_FORWARD(), hint, 0, TENSOR_LIST(ba), TENSOR_LIST(m), 0);
59
480
      vw += -log(m->data.f32[24]) * fs[j];
60
480
      w->data.f32[i] = old_w;
61
480
    }
62
120
    dw[i] = vw / (12 * eps);
63
120
  }
64
1
  float* dbias = (float*)ccmalloc(sizeof(float) * 4);
65
5
  for (i = 0; i < 4; 
i++4
)
66
4
  {
67
4
    dbias[i] = 0;
68
20
    for (j = 0; j < 4; 
j++16
)
69
16
    {
70
16
      float old_bias = bias->data.f32[i];
71
16
      bias->data.f32[i] += fsh[j] * eps;
72
16
      ccv_nnc_cmd_exec(forw_cmd, hint, 0, TENSOR_LIST(a, w, bias), TENSOR_LIST(b), 0);
73
16
      ccv_nnc_cmd_exec(CMD_SOFTMAX_FORWARD(), hint, 0, TENSOR_LIST(ba), TENSOR_LIST(m), 0);
74
16
      dbias[i] += -logf(m->data.f32[24]) * fs[j];
75
16
      bias->data.f32[i] = old_bias;
76
16
    }
77
4
    dbias[i] *= 1.0 / (12 * eps);
78
4
  }
79
1
  REQUIRE_ARRAY_EQ_WITHIN_ANGLE_AND_MAGNITUDE(float, dw, gw->data.f32, 2 * 3 * 5 * 4, 30, 2e-1, "weight gradient from analytical method doesn't match the one from numerical method");
80
1
  REQUIRE_ARRAY_EQ_WITHIN_ANGLE_AND_MAGNITUDE(float, dbias, gbias->data.f32, 4, 30, 2e-1, "bias gradient from analytical method doesn't match the one from numerical method");
81
1
  ccfree(dw);
82
1
  ccfree(dbias);
83
1
  ccv_nnc_tensor_free(a);
84
1
  ccv_nnc_tensor_free(b);
85
1
  ccv_nnc_tensor_free(ba);
86
1
  ccv_nnc_tensor_free(m);
87
1
  ccv_nnc_tensor_free(g);
88
1
  ccv_nnc_tensor_free(h);
89
1
  ccv_nnc_tensor_free(w);
90
1
  ccv_nnc_tensor_free(bias);
91
1
  ccv_nnc_tensor_free(gw);
92
1
  ccv_nnc_tensor_free(gbias);
93
1
}
94
95
#include "case_main.h"