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/nnc/cmd/gated_delta/ccv_nnc_gated_delta_cpu_ref.c
Line
Count
Source
1
#include "ccv.h"
2
#include "ccv_internal.h"
3
#include "nnc/ccv_nnc.h"
4
#include "nnc/ccv_nnc_easy.h"
5
#include "nnc/ccv_nnc_internal.h"
6
#include <math.h>
7
#include <string.h>
8
9
static int _ccv_nnc_gated_delta_forw(const ccv_nnc_cmd_t cmd, const ccv_nnc_hint_t hint, const int flags, ccv_nnc_tensor_t* const* const inputs, const int input_size, ccv_nnc_tensor_t* const* const outputs, const int output_size, ccv_nnc_stream_context_t* const stream_context)
10
0
{
11
0
  assert(input_size == 6);
12
0
  assert(output_size == 2);
13
0
  const ccv_nnc_tensor_t* const q = inputs[0];
14
0
  const ccv_nnc_tensor_t* const k = inputs[1];
15
0
  const ccv_nnc_tensor_t* const v = inputs[2];
16
0
  const ccv_nnc_tensor_t* const log_decay = inputs[3];
17
0
  const ccv_nnc_tensor_t* const beta = inputs[4];
18
0
  const ccv_nnc_tensor_t* const state_in = inputs[5];
19
0
  ccv_nnc_tensor_t* const y = outputs[0];
20
0
  ccv_nnc_tensor_t* const state_out = outputs[1];
21
0
  assert(CCV_IS_TENSOR_CONTIGUOUS(q));
22
0
  assert(CCV_IS_TENSOR_CONTIGUOUS(k));
23
0
  assert(CCV_IS_TENSOR_CONTIGUOUS(v));
24
0
  assert(CCV_IS_TENSOR_CONTIGUOUS(log_decay));
25
0
  assert(CCV_IS_TENSOR_CONTIGUOUS(beta));
26
0
  assert(CCV_IS_TENSOR_CONTIGUOUS(state_in));
27
0
  assert(CCV_IS_TENSOR_CONTIGUOUS(y));
28
0
  assert(CCV_IS_TENSOR_CONTIGUOUS(state_out));
29
0
  assert(q->info.datatype == CCV_32F);
30
0
  assert(k->info.datatype == CCV_32F);
31
0
  assert(v->info.datatype == CCV_32F);
32
0
  assert(log_decay->info.datatype == CCV_32F);
33
0
  assert(beta->info.datatype == CCV_32F);
34
0
  assert(state_in->info.datatype == CCV_32F);
35
0
  assert(y->info.datatype == CCV_32F);
36
0
  assert(state_out->info.datatype == CCV_32F);
37
0
  const int q_nd = ccv_nnc_tensor_nd(q->info.dim);
38
0
  const int k_nd = ccv_nnc_tensor_nd(k->info.dim);
39
0
  const int v_nd = ccv_nnc_tensor_nd(v->info.dim);
40
0
  const int log_decay_nd = ccv_nnc_tensor_nd(log_decay->info.dim);
41
0
  const int beta_nd = ccv_nnc_tensor_nd(beta->info.dim);
42
0
  const int state_in_nd = ccv_nnc_tensor_nd(state_in->info.dim);
43
0
  const int y_nd = ccv_nnc_tensor_nd(y->info.dim);
44
0
  const int state_out_nd = ccv_nnc_tensor_nd(state_out->info.dim);
45
0
  assert(q_nd == 4);
46
0
  assert(k_nd == 4);
47
0
  assert(v_nd == 4);
48
0
  assert(log_decay_nd == 3);
49
0
  assert(beta_nd == 3);
50
0
  assert(state_in_nd == 4);
51
0
  assert(y_nd == 4);
52
0
  assert(state_out_nd == 4);
53
0
  const int B = q->info.dim[0];
54
0
  const int T = q->info.dim[1];
55
0
  const int Hk = q->info.dim[2];
56
0
  const int Dk = q->info.dim[3];
57
0
  const int Hv = v->info.dim[2];
58
0
  const int Dv = v->info.dim[3];
59
0
  assert(B > 0);
60
0
  assert(T > 0);
61
0
  assert(Hk > 0);
62
0
  assert(Dk > 0);
63
0
  assert(Hv > 0);
64
0
  assert(Dv > 0);
65
0
  assert(k->info.dim[0] == B);
66
0
  assert(k->info.dim[1] == T);
67
0
  assert(k->info.dim[2] == Hk);
68
0
  assert(k->info.dim[3] == Dk);
69
0
  assert(v->info.dim[0] == B);
70
0
  assert(v->info.dim[1] == T);
71
0
  assert(log_decay->info.dim[0] == B);
72
0
  assert(log_decay->info.dim[1] == T);
73
0
  assert(log_decay->info.dim[2] == Hv);
74
0
  assert(beta->info.dim[0] == B);
75
0
  assert(beta->info.dim[1] == T);
76
0
  assert(beta->info.dim[2] == Hv);
77
0
  assert(state_in->info.dim[0] == B);
78
0
  assert(state_in->info.dim[1] == Hv);
79
0
  assert(state_in->info.dim[2] == Dv);
80
0
  assert(state_in->info.dim[3] == Dk);
81
0
  assert(y->info.dim[0] == B);
82
0
  assert(y->info.dim[1] == T);
83
0
  assert(y->info.dim[2] == Hv);
84
0
  assert(y->info.dim[3] == Dv);
85
0
  assert(state_out->info.dim[0] == B);
86
0
  assert(state_out->info.dim[1] == Hv);
87
0
  assert(state_out->info.dim[2] == Dv);
88
0
  assert(state_out->info.dim[3] == Dk);
89
0
  assert(Hv % Hk == 0);
90
0
  const int log_decay_input = cmd.info.gated_delta.log_decay;
91
0
  const int hv_per_hk = Hv / Hk;
92
0
  const float* const qp = q->data.f32;
93
0
  const float* const kp = k->data.f32;
94
0
  const float* const vp = v->data.f32;
95
0
  const float* const gp = log_decay->data.f32;
96
0
  const float* const betap = beta->data.f32;
97
0
  const float* const state_inp = state_in->data.f32;
98
0
  float* const yp = y->data.f32;
99
0
  float* const state_outp = state_out->data.f32;
100
0
  int b, hv, dv, t, dk;
101
0
  for (b = 0; b < B; b++)
102
0
    for (hv = 0; hv < Hv; hv++)
103
0
    {
104
0
      const int hk = hv / hv_per_hk;
105
0
      for (dv = 0; dv < Dv; dv++)
106
0
      {
107
0
        const size_t state_offset = (((size_t)b * Hv + hv) * Dv + dv) * Dk;
108
0
        if (state_inp != state_outp)
109
0
          memcpy(state_outp + state_offset, state_inp + state_offset, sizeof(float) * Dk);
110
0
        float* const state_row = state_outp + state_offset;
111
0
        for (t = 0; t < T; t++)
112
0
        {
113
0
          const size_t qk_offset = (((size_t)b * T + t) * Hk + hk) * Dk;
114
0
          const float* const q_row = qp + qk_offset;
115
0
          const float* const k_row = kp + qk_offset;
116
0
          const size_t gate_offset = ((size_t)b * T + t) * Hv + hv;
117
0
          const float decay = log_decay_input ? expf(gp[gate_offset]) : gp[gate_offset];
118
0
          float memory = 0;
119
0
          for (dk = 0; dk < Dk; dk++)
120
0
          {
121
0
            const float decayed = state_row[dk] * decay;
122
0
            state_row[dk] = decayed;
123
0
            memory += decayed * k_row[dk];
124
0
          }
125
0
          const size_t v_offset = (((size_t)b * T + t) * Hv + hv) * Dv + dv;
126
0
          const float delta = (vp[v_offset] - memory) * betap[gate_offset];
127
0
          float out = 0;
128
0
          for (dk = 0; dk < Dk; dk++)
129
0
          {
130
0
            const float next = state_row[dk] + delta * k_row[dk];
131
0
            state_row[dk] = next;
132
0
            out += next * q_row[dk];
133
0
          }
134
0
          yp[v_offset] = out;
135
0
        }
136
0
      }
137
0
    }
138
0
  return CCV_NNC_EXEC_SUCCESS;
139
0
}
140
141
REGISTER_COMMAND_BACKEND(CCV_NNC_GATED_DELTA_FORWARD, CCV_NNC_BACKEND_CPU_REF)(ccv_nnc_cmd_backend_registry_t* const registry)
142
1
{
143
1
  registry->tensor_formats = CCV_TENSOR_FORMAT_NHWC | CCV_TENSOR_FORMAT_NCHW | CCV_TENSOR_FORMAT_CHWN;
144
1
  registry->tensor_datatypes = CCV_32F;
145
1
  registry->tensor_memory = CCV_TENSOR_CPU_MEMORY;
146
1
  registry->algorithms = 1;
147
1
  registry->exec = _ccv_nnc_gated_delta_forw;
148
1
}