/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 | } |