Coverage Report

Created: 2021-09-21 22:26

/home/liu/buildslave/linux-x64-runtests/build/lib/nnc/ccv_cnnp_model_addons.c
Line
Count
Source (jump to first uncovered line)
1
#include "ccv_nnc.h"
2
#include "ccv_nnc_easy.h"
3
#include "ccv_nnc_internal.h"
4
#include "ccv_internal.h"
5
#include "_ccv_cnnp_model.h"
6
7
// MARK - Core Layers
8
9
static void _ccv_cnnp_sum_build(ccv_cnnp_model_t* const self, ccv_nnc_symbolic_graph_t* const graph, const ccv_nnc_tensor_symbol_t* const inputs, const int input_size, ccv_nnc_tensor_symbol_t* const outputs, const int output_size)
10
42
{
11
42
  assert(output_size == 1);
12
42
  outputs[0] = ccv_nnc_tensor_symbol_new(graph, ccv_nnc_tensor_symbol_params(graph, inputs[0]), 0);
13
42
  ccv_nnc_graph_exec_symbol_new(graph, CMD_EWSUM_FORWARD(), inputs, input_size, outputs, output_size, 0);
14
42
}
15
16
static ccv_cnnp_model_t* _ccv_cnnp_sum_copy(const ccv_cnnp_model_t* const self, void* const context);
17
18
static const ccv_cnnp_model_vtab_t ccv_cnnp_sum_isa = {
19
  .build = _ccv_cnnp_sum_build,
20
  .copy = _ccv_cnnp_sum_copy,
21
};
22
23
typedef struct {
24
  ccv_cnnp_model_t super;
25
  ccv_nnc_tensor_symbol_t output;
26
} ccv_cnnp_model_sum_t;
27
28
ccv_cnnp_model_t* ccv_cnnp_sum(const char* const name)
29
45
{
30
45
  ccv_cnnp_model_sum_t* const model_sum = (ccv_cnnp_model_sum_t*)cccalloc(1, sizeof(ccv_cnnp_model_sum_t));
31
45
  model_sum->super.isa = &ccv_cnnp_sum_isa;
32
45
  model_sum->super.input_size = 0;
33
45
  model_sum->super.outputs = &model_sum->output;
34
45
  model_sum->super.output_size = 1;
35
45
  ccv_cnnp_model_copy_name(&model_sum->super, name);
36
45
  return (ccv_cnnp_model_t*)model_sum;
37
45
}
38
39
static ccv_cnnp_model_t* _ccv_cnnp_sum_copy(const ccv_cnnp_model_t* const self, void* const context)
40
3
{
41
3
  return ccv_cnnp_sum(self->name);
42
3
}
43
44
typedef struct {
45
  ccv_cnnp_model_t super;
46
  int axis;
47
  ccv_nnc_tensor_symbol_t output;
48
} ccv_cnnp_model_concat_t;
49
50
static void _ccv_cnnp_concat_build(ccv_cnnp_model_t* const super, ccv_nnc_symbolic_graph_t* const graph, const ccv_nnc_tensor_symbol_t* const inputs, const int input_size, ccv_nnc_tensor_symbol_t* const outputs, const int output_size)
51
4
{
52
4
  const ccv_cnnp_model_concat_t* const self = (const ccv_cnnp_model_concat_t*)super;
53
4
  assert(output_size == 1);
54
4
  ccv_nnc_tensor_param_t output_params = ccv_nnc_tensor_symbol_params(graph, inputs[0]);
55
4
  const int nd = ccv_nnc_tensor_nd(output_params.dim);
56
4
  const int axis = self->axis;
57
4
  assert(axis < nd);
58
4
  output_params.dim[axis] = 0;
59
4
  int i, j;
60
12
  for (i = 0; i < input_size; 
i++8
)
61
8
  {
62
8
    const ccv_nnc_tensor_param_t input_params = ccv_nnc_tensor_symbol_params(graph, inputs[i]);
63
8
    const int input_nd = ccv_nnc_tensor_nd(input_params.dim);
64
8
    assert(input_nd == nd);
65
16
    
for (j = 0; 8
j < nd;
j++8
)
66
8
      if (j != axis)
67
0
        { assert(input_params.dim[j] == output_params.dim[j]); }
68
8
    output_params.dim[axis] += input_params.dim[axis];
69
8
  }
70
4
  outputs[0] = ccv_nnc_tensor_symbol_new(graph, output_params, 0);
71
4
  int ofs[CCV_NNC_MAX_DIM_ALLOC] = {};
72
4
  ccv_nnc_tensor_symbol_t aliases[input_size];
73
12
  for (i = 0; i < input_size; 
i++8
)
74
8
  {
75
8
    const ccv_nnc_tensor_param_t input_params = ccv_nnc_tensor_symbol_params(graph, inputs[i]);
76
8
    aliases[i] = ccv_nnc_tensor_symbol_alias_new(graph, outputs[0], ofs, output_params.dim, input_params, 0);
77
8
    ofs[axis] += input_params.dim[axis];
78
8
  }
79
4
  // Format transform is more flexible.
80
4
  ccv_nnc_graph_exec_symbol_new(graph, CMD_FORMAT_TRANSFORM_FORWARD(), inputs, input_size, aliases, input_size, 0);
81
4
}
82
83
static ccv_cnnp_model_t* _ccv_cnnp_concat_copy(const ccv_cnnp_model_t* const self, void* const context);
84
85
static const ccv_cnnp_model_vtab_t ccv_cnnp_concat_isa = {
86
  .build = _ccv_cnnp_concat_build,
87
  .copy = _ccv_cnnp_concat_copy,
88
};
89
90
ccv_cnnp_model_t* ccv_cnnp_concat(const int axis, const char* const name)
91
4
{
92
4
  ccv_cnnp_model_concat_t* const model_concat = (ccv_cnnp_model_concat_t*)cccalloc(1, sizeof(ccv_cnnp_model_concat_t));
93
4
  model_concat->super.isa = &ccv_cnnp_concat_isa;
94
4
  model_concat->super.input_size = 0;
95
4
  model_concat->super.outputs = &model_concat->output;
96
4
  model_concat->super.output_size = 1;
97
4
  model_concat->axis = axis;
98
4
  ccv_cnnp_model_copy_name(&model_concat->super, name);
99
4
  return (ccv_cnnp_model_t*)model_concat;
100
4
}
101
102
static ccv_cnnp_model_t* _ccv_cnnp_concat_copy(const ccv_cnnp_model_t* const super, void* const context)
103
0
{
104
0
  const ccv_cnnp_model_concat_t* const self = (const ccv_cnnp_model_concat_t*)super;
105
0
  return ccv_cnnp_concat(self->axis, self->super.name);
106
0
}
107
108
typedef struct {
109
  ccv_cnnp_model_t super;
110
  ccv_nnc_tensor_symbol_t output;
111
  int dim[CCV_NNC_MAX_DIM_ALLOC];
112
  int ofs[CCV_NNC_MAX_DIM_ALLOC];
113
  int inc[CCV_NNC_MAX_DIM_ALLOC];
114
} ccv_cnnp_model_reshape_t;
115
116
static void _ccv_cnnp_reshape_build(ccv_cnnp_model_t* const super, ccv_nnc_symbolic_graph_t* const graph, const ccv_nnc_tensor_symbol_t* const inputs, const int input_size, ccv_nnc_tensor_symbol_t* const outputs, const int output_size)
117
1.08k
{
118
1.08k
  assert(input_size == 1);
119
1.08k
  assert(output_size == 1);
120
1.08k
  ccv_cnnp_model_reshape_t* const self = (ccv_cnnp_model_reshape_t*)super;
121
1.08k
  ccv_nnc_tensor_param_t params = ccv_nnc_tensor_symbol_params(graph, inputs[0]);
122
1.08k
  assert(ccv_nnc_dimension_count(self->dim) <= ccv_nnc_tensor_count(params));
123
1.08k
  memcpy(params.dim, self->dim, sizeof(params.dim));
124
1.08k
  outputs[0] = ccv_nnc_tensor_symbol_alias_new(graph, inputs[0], self->ofs, self->inc, params, 0);
125
1.08k
}
126
127
static ccv_cnnp_model_t* _ccv_cnnp_reshape_copy(const ccv_cnnp_model_t* const super, void* const context);
128
129
static const ccv_cnnp_model_vtab_t ccv_cnnp_reshape_isa = {
130
  .build = _ccv_cnnp_reshape_build,
131
  .copy = _ccv_cnnp_reshape_copy,
132
};
133
134
ccv_cnnp_model_t* ccv_cnnp_reshape(const int dim[CCV_NNC_MAX_DIM_ALLOC], const int ofs[CCV_NNC_MAX_DIM_ALLOC], const int inc[CCV_NNC_MAX_DIM_ALLOC], const char* const name)
135
1.08k
{
136
1.08k
  ccv_cnnp_model_reshape_t* const model_reshape = (ccv_cnnp_model_reshape_t*)cccalloc(1, sizeof(ccv_cnnp_model_reshape_t));
137
1.08k
  model_reshape->super.isa = &ccv_cnnp_reshape_isa;
138
1.08k
  model_reshape->super.input_size = 1;
139
1.08k
  model_reshape->super.outputs = &model_reshape->output;
140
1.08k
  model_reshape->super.output_size = 1;
141
1.08k
  ccv_cnnp_model_copy_name(&model_reshape->super, name);
142
1.08k
  memcpy(model_reshape->dim, dim, sizeof(model_reshape->dim));
143
1.08k
  memcpy(model_reshape->ofs, ofs, sizeof(model_reshape->ofs));
144
1.08k
  int i, flag = 0;
145
3.14k
  for (i = 0; !flag && 
i < 2.14k
CCV_NNC_MAX_DIM_ALLOC2.14k
;
i++2.05k
)
146
2.05k
    flag = (inc[i] != 0);
147
1.08k
  memcpy(model_reshape->inc, flag ? 
inc1.00k
:
dim88
, sizeof(model_reshape->inc));
148
1.08k
  return (ccv_cnnp_model_t*)model_reshape;
149
1.08k
}
150
151
static ccv_cnnp_model_t* _ccv_cnnp_reshape_copy(const ccv_cnnp_model_t* const super, void* const context)
152
1.00k
{
153
1.00k
  const ccv_cnnp_model_reshape_t* const self = (const ccv_cnnp_model_reshape_t*)super;
154
1.00k
  return ccv_cnnp_reshape(self->dim, self->ofs, self->inc, self->super.name);
155
1.00k
}
156
157
typedef struct {
158
  ccv_cnnp_model_t super;
159
  ccv_nnc_tensor_symbol_t output;
160
} ccv_cnnp_model_flatten_t;
161
162
static void _ccv_cnnp_flatten_build(ccv_cnnp_model_t* const super, ccv_nnc_symbolic_graph_t* const graph, const ccv_nnc_tensor_symbol_t* const inputs, const int input_size, ccv_nnc_tensor_symbol_t* const outputs, const int output_size)
163
10
{
164
10
  assert(input_size == 1);
165
10
  assert(output_size == 1);
166
10
  const ccv_nnc_tensor_param_t params = ccv_nnc_tensor_symbol_params(graph, inputs[0]);
167
10
  ccv_nnc_tensor_param_t output_params = params;
168
10
  memset(output_params.dim, 0, sizeof(output_params.dim));
169
10
  output_params.dim[0] = ccv_nnc_tensor_get_n(params);
170
10
  assert(output_params.dim[0] > 0);
171
10
  output_params.dim[1] = ccv_nnc_tensor_count(params) / output_params.dim[0];
172
10
  outputs[0] = ccv_nnc_tensor_symbol_alias_new(graph, inputs[0], DIM_ALLOC(), output_params.dim, output_params, 0);
173
10
}
174
175
static ccv_cnnp_model_t* _ccv_cnnp_flatten_copy(const ccv_cnnp_model_t* const self, void* const context);
176
177
static const ccv_cnnp_model_vtab_t ccv_cnnp_flatten_isa = {
178
  .build = _ccv_cnnp_flatten_build,
179
  .copy = _ccv_cnnp_flatten_copy,
180
};
181
182
ccv_cnnp_model_t* ccv_cnnp_flatten(const char* const name)
183
12
{
184
12
  ccv_cnnp_model_flatten_t* const model_flatten = (ccv_cnnp_model_flatten_t*)cccalloc(1, sizeof(ccv_cnnp_model_flatten_t));
185
12
  model_flatten->super.isa = &ccv_cnnp_flatten_isa;
186
12
  model_flatten->super.input_size = 1;
187
12
  model_flatten->super.outputs = &model_flatten->output;
188
12
  model_flatten->super.output_size = 1;
189
12
  ccv_cnnp_model_copy_name(&model_flatten->super, name);
190
12
  return (ccv_cnnp_model_t*)model_flatten;
191
12
}
192
193
static ccv_cnnp_model_t* _ccv_cnnp_flatten_copy(const ccv_cnnp_model_t* const self, void* const context)
194
2
{
195
2
  return ccv_cnnp_flatten(self->name);
196
2
}
197
198
// MARK - Batch Norm Layer
199
200
typedef struct {
201
  ccv_cnnp_model_t super;
202
  ccv_nnc_tensor_symbol_t output;
203
  ccv_nnc_tensor_symbol_t bias;
204
  ccv_nnc_tensor_symbol_t scale;
205
  ccv_nnc_graph_exec_symbol_t batch_norm;
206
  ccv_nnc_cmd_param_t params;
207
  ccv_array_t* zero_inits;
208
  ccv_array_t* retainables;
209
} ccv_cnnp_model_batch_norm_t;
210
211
static void _ccv_cnnp_batch_norm_build(ccv_cnnp_model_t* const super, ccv_nnc_symbolic_graph_t* const graph, const ccv_nnc_tensor_symbol_t* const inputs, const int input_size, ccv_nnc_tensor_symbol_t* const outputs, const int output_size)
212
75
{
213
75
  assert(input_size == 1);
214
75
  assert(output_size == 1);
215
75
  ccv_cnnp_model_batch_norm_t* const self = (ccv_cnnp_model_batch_norm_t*)super;
216
75
  const ccv_nnc_tensor_param_t params = ccv_nnc_tensor_symbol_params(graph, inputs[0]);
217
75
  ccv_nnc_tensor_param_t bias_params = params;
218
75
  memset(bias_params.dim, 0, sizeof(bias_params.dim));
219
75
  // If the accuracy is not enough, bump it to 32-bit floating point.
220
75
  if (bias_params.datatype != CCV_32F && 
bias_params.datatype != CCV_64F16
)
221
16
    bias_params.datatype = CCV_32F;
222
75
  bias_params.dim[0] = ccv_nnc_tensor_get_c(params);
223
75
  const ccv_nnc_tensor_symbol_t output = ccv_nnc_tensor_symbol_new(graph, params, 0);
224
75
  // Both scale and bias are shared between if this model is reused.
225
75
  if (!self->scale.graph)
226
75
    self->scale = ccv_nnc_tensor_symbol_new(graph, bias_params, 0);
227
75
  if (!self->bias.graph)
228
75
    self->bias = ccv_nnc_tensor_symbol_new(graph, bias_params, 0);
229
75
  const ccv_nnc_tensor_symbol_t mean = ccv_nnc_tensor_symbol_new(graph, bias_params, 0);
230
75
  const ccv_nnc_tensor_symbol_t var = ccv_nnc_tensor_symbol_new(graph, bias_params, 0);
231
75
  // Otherwise, notice mean, var, saved_mean, saved_inv_std are not reused.
232
75
  if (!self->zero_inits)
233
75
    self->zero_inits = ccv_array_new(sizeof(ccv_nnc_tensor_symbol_t), 0, 0);
234
75
  ccv_array_push(self->zero_inits, &mean);
235
75
  ccv_array_push(self->zero_inits, &var);
236
75
  const ccv_nnc_tensor_symbol_t out_mean = ccv_nnc_tensor_symbol_new(graph, bias_params, 0);
237
75
  const ccv_nnc_tensor_symbol_t out_var = ccv_nnc_tensor_symbol_new(graph, bias_params, 0);
238
75
  if (!self->retainables)
239
75
    self->retainables = ccv_array_new(sizeof(ccv_nnc_tensor_symbol_t), 0, 0);
240
75
  ccv_array_push(self->retainables, &out_mean);
241
75
  ccv_array_push(self->retainables, &out_var);
242
75
  const ccv_nnc_tensor_symbol_t saved_mean = ccv_nnc_tensor_symbol_new(graph, bias_params, 0);
243
75
  const ccv_nnc_tensor_symbol_t saved_inv_std = ccv_nnc_tensor_symbol_new(graph, bias_params, 0);
244
75
  const int hw = ccv_nnc_tensor_hw(params, ccv_nnc_tensor_nd(params.dim));
245
75
  ccv_nnc_cmd_param_t batch_norm = self->params;
246
75
  batch_norm.bnorm.count = hw >= 0 ? CCV_NNC_MAX_DIM + 1 : 
10
;
247
75
  int i;
248
75
  batch_norm.bnorm.axis[0] = (params.format == CCV_TENSOR_FORMAT_CHWN) ? 
30
: 0;
249
75
  if (hw >= 0)
250
225
    
for (i = 0; 75
i < CCV_NNC_MAX_DIM;
i++150
)
251
150
      batch_norm.bnorm.axis[i + 1] = i + hw;
252
75
  self->params = batch_norm;
253
75
  self->batch_norm = ccv_nnc_graph_exec_symbol_new(graph, ccv_nnc_cmd(CCV_NNC_BATCH_NORM_FORWARD, 0, batch_norm, 0), TENSOR_SYMBOL_LIST(inputs[0], self->scale, self->bias, mean, var), TENSOR_SYMBOL_LIST(output, out_mean, out_var, saved_mean, saved_inv_std), 0);
254
75
  outputs[0] = output;
255
75
}
256
257
static void _ccv_cnnp_batch_norm_init_states(ccv_cnnp_model_t* const super, ccv_nnc_symbolic_graph_t* const graph, const ccv_cnnp_state_initializer_f initializer, void* const context)
258
24
{
259
24
  ccv_cnnp_model_batch_norm_t* const self = (ccv_cnnp_model_batch_norm_t*)super;
260
24
  if (self->bias.graph)
261
24
    initializer(context, CMD_SET_FORWARD(0), ccv_nnc_no_hint, 0, 0, self->bias);
262
24
  if (self->scale.graph)
263
24
    initializer(context, CMD_RANDOM_UNIFORM_FORWARD(0, 1), ccv_nnc_no_hint, 0, 0, self->scale);
264
24
  int i;
265
24
  if (self->zero_inits)
266
72
    
for (i = 0; 24
i < self->zero_inits->rnum;
i++48
)
267
48
      initializer(context, CMD_SET_FORWARD(0), ccv_nnc_no_hint, 0, 0, *(ccv_nnc_tensor_symbol_t*)ccv_array_get(self->zero_inits, i));
268
24
}
269
270
static void _ccv_cnnp_batch_norm_add_to_parameter(ccv_cnnp_model_t* const super, const ccv_cnnp_add_to_array_f add_to_array, void* const parameters)
271
75
{
272
75
  ccv_cnnp_model_batch_norm_t* const self = (ccv_cnnp_model_batch_norm_t*)super;
273
75
  if (self->bias.graph)
274
75
    add_to_array(parameters, self->bias);
275
75
  if (self->scale.graph)
276
75
    add_to_array(parameters, self->scale);
277
75
}
278
279
static void _ccv_cnnp_batch_norm_add_to_output(ccv_cnnp_model_t* const super, const ccv_cnnp_add_to_array_f add_to_array, void* const outputs)
280
75
{
281
75
  ccv_cnnp_model_batch_norm_t* const self = (ccv_cnnp_model_batch_norm_t*)super;
282
75
  int i;
283
75
  if (self->retainables)
284
225
    
for (i = 0; 75
i < self->retainables->rnum;
i++150
)
285
150
    {
286
150
      const ccv_nnc_tensor_symbol_t symbol = *(ccv_nnc_tensor_symbol_t*)ccv_array_get(self->retainables, i);
287
150
      add_to_array(outputs, symbol);
288
150
    }
289
75
}
290
291
static void _ccv_cnnp_batch_norm_set_is_test(ccv_cnnp_model_t* const super, const int is_test, const ccv_cnnp_cmd_updater_f updater, void* const context)
292
32
{
293
32
  ccv_cnnp_model_batch_norm_t* const self = (ccv_cnnp_model_batch_norm_t*)super;
294
32
  if (self->batch_norm.graph)
295
32
  {
296
32
    self->params.bnorm.is_test = is_test;
297
32
    updater(context, self->batch_norm, ccv_nnc_cmd(CCV_NNC_BATCH_NORM_FORWARD, 0, self->params, 0), ccv_nnc_no_hint);
298
32
  }
299
32
}
300
301
static void _ccv_cnnp_batch_norm_deinit(ccv_cnnp_model_t* const super)
302
83
{
303
83
  ccv_cnnp_model_batch_norm_t* const self = (ccv_cnnp_model_batch_norm_t*)super;
304
83
  if (self->zero_inits)
305
75
    ccv_array_free(self->zero_inits);
306
83
  if (self->retainables)
307
75
    ccv_array_free(self->retainables);
308
83
}
309
310
static ccv_cnnp_model_t* _ccv_cnnp_batch_norm_copy(const ccv_cnnp_model_t* const super, void* const context);
311
312
static const ccv_cnnp_model_vtab_t ccv_cnnp_batch_norm_isa = {
313
  .build = _ccv_cnnp_batch_norm_build,
314
  .init_states = _ccv_cnnp_batch_norm_init_states,
315
  .add_to_parameter = _ccv_cnnp_batch_norm_add_to_parameter,
316
  .add_to_output = _ccv_cnnp_batch_norm_add_to_output,
317
  .copy = _ccv_cnnp_batch_norm_copy,
318
  .set_is_test = _ccv_cnnp_batch_norm_set_is_test,
319
  .deinit = _ccv_cnnp_batch_norm_deinit,
320
};
321
322
ccv_cnnp_model_t* ccv_cnnp_batch_norm(const float momentum, const float epsilon, const char* const name)
323
83
{
324
83
  ccv_cnnp_model_batch_norm_t* const model_batch_norm = (ccv_cnnp_model_batch_norm_t*)cccalloc(1, sizeof(ccv_cnnp_model_batch_norm_t));
325
83
  model_batch_norm->super.isa = &ccv_cnnp_batch_norm_isa;
326
83
  model_batch_norm->super.input_size = 1;
327
83
  model_batch_norm->super.outputs = &model_batch_norm->output;
328
83
  model_batch_norm->super.output_size = 1;
329
83
  ccv_cnnp_model_copy_name(&model_batch_norm->super, name);
330
83
  model_batch_norm->scale.d = CCV_NNC_NO_TENSOR_SYMBOL;
331
83
  model_batch_norm->scale.graph = 0;
332
83
  model_batch_norm->bias.d = CCV_NNC_NO_TENSOR_SYMBOL;
333
83
  model_batch_norm->bias.graph = 0;
334
83
  model_batch_norm->params.bnorm.momentum = momentum;
335
83
  model_batch_norm->params.bnorm.epsilon = epsilon;
336
83
  return (ccv_cnnp_model_t*)model_batch_norm;
337
83
}
338
339
static ccv_cnnp_model_t* _ccv_cnnp_batch_norm_copy(const ccv_cnnp_model_t* const super, void* const context)
340
8
{
341
8
  const ccv_cnnp_model_batch_norm_t* const self = (const ccv_cnnp_model_batch_norm_t*)super;
342
8
  return ccv_cnnp_batch_norm(self->params.bnorm.momentum, self->params.bnorm.epsilon, self->super.name);
343
8
}
344
345
// MARK - Convolution Layer
346
347
typedef struct {
348
  ccv_cnnp_model_t super;
349
  ccv_nnc_tensor_symbol_t output;
350
  ccv_nnc_tensor_symbol_t weights;
351
  ccv_nnc_tensor_symbol_t bias;
352
  int groups;
353
  int filters;
354
  int kdim[CCV_NNC_MAX_DIM_ALLOC];
355
  int no_bias;
356
  ccv_nnc_hint_t hint;
357
} ccv_cnnp_model_convolution_t;
358
359
static void _ccv_cnnp_convolution_build(ccv_cnnp_model_t* const super, ccv_nnc_symbolic_graph_t* const graph, const ccv_nnc_tensor_symbol_t* const inputs, const int input_size, ccv_nnc_tensor_symbol_t* const outputs, const int output_size)
360
111
{
361
111
  assert(input_size == 1);
362
111
  assert(output_size == 1);
363
111
  ccv_cnnp_model_convolution_t* const self = (ccv_cnnp_model_convolution_t*)super;
364
111
  const ccv_nnc_tensor_param_t params = ccv_nnc_tensor_symbol_params(graph, inputs[0]);
365
111
  int i;
366
111
  const int nd = CCV_NNC_MAX_DIM + 2;
367
111
  ccv_nnc_tensor_param_t weights_params = params;
368
111
  ccv_nnc_tensor_set_n(&weights_params, self->filters);
369
111
  assert(ccv_nnc_tensor_get_c(params) % self->groups == 0);
370
111
  ccv_nnc_tensor_set_c(&weights_params, nd, ccv_nnc_tensor_get_c(params) / self->groups);
371
111
  const int hw = ccv_nnc_tensor_hw(weights_params, nd);
372
111
  assert(hw >= 0);
373
333
  
for (i = 0; 111
i < CCV_NNC_MAX_DIM;
i++222
)
374
222
    weights_params.dim[i + hw] = self->kdim[i];
375
111
  if (!self->weights.graph)
376
107
    self->weights = ccv_nnc_tensor_symbol_new(graph, weights_params, 0);
377
111
  assert(self->weights.graph == graph);
378
111
  ccv_nnc_tensor_param_t bias_params = params;
379
111
  memset(bias_params.dim, 0, sizeof(bias_params.dim));
380
111
  bias_params.dim[0] = self->filters;
381
111
  ccv_nnc_cmd_t cmd = CMD_CONVOLUTION_FORWARD(self->groups, self->filters);
382
333
  for (i = 0; i < CCV_NNC_MAX_DIM; 
i++222
)
383
222
    cmd.info.size.dim[i] = self->kdim[i];
384
111
  ccv_nnc_tensor_param_t output_params;
385
111
  ccv_nnc_hint_tensor_auto(cmd, (ccv_nnc_tensor_param_t []){
386
111
      params,
387
111
      weights_params,
388
111
      bias_params,
389
111
    }, 3, self->hint, &output_params, 1);
390
111
  const ccv_nnc_tensor_symbol_t output = ccv_nnc_tensor_symbol_new(graph, output_params, 0);
391
111
  ccv_nnc_graph_exec_symbol_t convolution;
392
111
  if (self->no_bias)
393
10
    convolution = ccv_nnc_graph_exec_symbol_new(graph, cmd, TENSOR_SYMBOL_LIST(inputs[0], self->weights), TENSOR_SYMBOL_LIST(output), 0);
394
101
  else {
395
101
    if (!self->bias.graph)
396
97
      self->bias = ccv_nnc_tensor_symbol_new(graph, bias_params, 0);
397
101
    convolution = ccv_nnc_graph_exec_symbol_new(graph, cmd, TENSOR_SYMBOL_LIST(inputs[0], self->weights, self->bias), TENSOR_SYMBOL_LIST(output), 0);
398
101
  }
399
111
  ccv_nnc_graph_exec_symbol_set_hint(graph, convolution, self->hint);
400
111
  outputs[0] = output;
401
111
}
402
403
static void _ccv_cnnp_convolution_init_states(ccv_cnnp_model_t* const super, ccv_nnc_symbolic_graph_t* const graph, const ccv_cnnp_state_initializer_f initializer, void* const context)
404
33
{
405
33
  ccv_cnnp_model_convolution_t* const self = (ccv_cnnp_model_convolution_t*)super;
406
33
  const ccv_nnc_tensor_param_t weight_params = ccv_nnc_tensor_symbol_params(graph, self->weights);
407
33
  const int n = ccv_max(ccv_nnc_tensor_get_n(weight_params), 1);
408
33
  const int count = ccv_nnc_tensor_count(weight_params);
409
33
  const float std = sqrtf(2) / sqrtf(count / n);
410
33
  const float bound = sqrtf(3) * std;
411
33
  initializer(context, CMD_RANDOM_UNIFORM_FORWARD(-bound, bound), ccv_nnc_no_hint, 0, 0, self->weights);
412
33
  if (self->bias.graph)
413
33
    initializer(context, CMD_SET_FORWARD(0), ccv_nnc_no_hint, 0, 0, self->bias);
414
33
}
415
416
static void _ccv_cnnp_convolution_add_to_parameter(ccv_cnnp_model_t* const super, const ccv_cnnp_add_to_array_f add_to_array, void* const parameters)
417
111
{
418
111
  ccv_cnnp_model_convolution_t* const self = (ccv_cnnp_model_convolution_t*)super;
419
111
  add_to_array(parameters, self->weights);
420
111
  if (self->bias.graph)
421
101
    add_to_array(parameters, self->bias);
422
111
}
423
424
static ccv_cnnp_model_t* _ccv_cnnp_convolution_copy(const ccv_cnnp_model_t* const super, void* const context);
425
426
static const ccv_cnnp_model_vtab_t ccv_cnnp_convolution_isa = {
427
  .build = _ccv_cnnp_convolution_build,
428
  .init_states = _ccv_cnnp_convolution_init_states,
429
  .add_to_parameter = _ccv_cnnp_convolution_add_to_parameter,
430
  .copy = _ccv_cnnp_convolution_copy,
431
};
432
433
ccv_cnnp_model_t* ccv_cnnp_convolution(const int groups, const int filters, const int kdim[CCV_NNC_MAX_DIM_ALLOC], const int no_bias, ccv_nnc_hint_t hint, const char* const name)
434
123
{
435
123
  ccv_cnnp_model_convolution_t* const model_convolution = (ccv_cnnp_model_convolution_t*)cccalloc(1, sizeof(ccv_cnnp_model_convolution_t));
436
123
  model_convolution->super.isa = &ccv_cnnp_convolution_isa;
437
123
  model_convolution->super.input_size = 1;
438
123
  model_convolution->super.outputs = &model_convolution->output;
439
123
  model_convolution->super.output_size = 1;
440
123
  ccv_cnnp_model_copy_name(&model_convolution->super, name);
441
123
  model_convolution->weights.d = CCV_NNC_NO_TENSOR_SYMBOL;
442
123
  model_convolution->weights.graph = 0;
443
123
  model_convolution->bias.d = CCV_NNC_NO_TENSOR_SYMBOL;
444
123
  model_convolution->bias.graph = 0;
445
123
  model_convolution->groups = groups;
446
123
  model_convolution->filters = filters;
447
123
  memcpy(model_convolution->kdim, kdim, sizeof(model_convolution->kdim));
448
123
  model_convolution->no_bias = no_bias;
449
123
  model_convolution->hint = hint;
450
123
  return (ccv_cnnp_model_t*)model_convolution;
451
123
}
452
453
static ccv_cnnp_model_t* _ccv_cnnp_convolution_copy(const ccv_cnnp_model_t* const super, void* const context)
454
16
{
455
16
  ccv_cnnp_model_convolution_t* const self = (ccv_cnnp_model_convolution_t*)super;
456
16
  return ccv_cnnp_convolution(self->groups, self->filters, self->kdim, self->no_bias, self->hint, self->super.name);
457
16
}
458
459
// MARK - Dense Layer
460
461
typedef struct {
462
  ccv_cnnp_model_t super;
463
  ccv_nnc_tensor_symbol_t output;
464
  ccv_nnc_tensor_symbol_t weights;
465
  ccv_nnc_tensor_symbol_t bias;
466
  int count;
467
  int no_bias;
468
} ccv_cnnp_model_dense_t;
469
470
static void _ccv_cnnp_dense_build(ccv_cnnp_model_t* const super, ccv_nnc_symbolic_graph_t* const graph, const ccv_nnc_tensor_symbol_t* const inputs, const int input_size, ccv_nnc_tensor_symbol_t* const outputs, const int output_size)
471
2.29k
{
472
2.29k
  assert(input_size == 1);
473
2.29k
  assert(output_size == 1);
474
2.29k
  ccv_cnnp_model_dense_t* const self = (ccv_cnnp_model_dense_t*)super;
475
2.29k
  const ccv_nnc_tensor_param_t params = ccv_nnc_tensor_symbol_params(graph, inputs[0]);
476
2.29k
  ccv_nnc_tensor_param_t weights_params = params;
477
2.29k
  memset(weights_params.dim, 0, sizeof(weights_params.dim));
478
2.29k
  weights_params.dim[0] = self->count;
479
2.29k
  weights_params.dim[1] = params.dim[ccv_nnc_tensor_nd(params.dim) - 1];
480
2.29k
  if (!self->weights.graph)
481
2.28k
    self->weights = ccv_nnc_tensor_symbol_new(graph, weights_params, 0);
482
2.29k
  assert(self->weights.graph == graph);
483
2.29k
  ccv_nnc_tensor_param_t bias_params = params;
484
2.29k
  memset(bias_params.dim, 0, sizeof(bias_params.dim));
485
2.29k
  bias_params.dim[0] = self->count;
486
2.29k
  const ccv_nnc_cmd_t cmd = CMD_GEMM_FORWARD(NO_TRANSPOSE, TRANSPOSE(0, 1));
487
2.29k
  ccv_nnc_tensor_param_t output_params;
488
2.29k
  ccv_nnc_hint_tensor_auto(cmd, (ccv_nnc_tensor_param_t []){
489
2.29k
      params,
490
2.29k
      weights_params,
491
2.29k
      bias_params,
492
2.29k
    }, 3, ccv_nnc_no_hint, &output_params, 1);
493
2.29k
  const ccv_nnc_tensor_symbol_t output = ccv_nnc_tensor_symbol_new(graph, output_params, 0);
494
2.29k
  if (self->no_bias)
495
2.04k
    ccv_nnc_graph_exec_symbol_new(graph, cmd, TENSOR_SYMBOL_LIST(inputs[0], self->weights), TENSOR_SYMBOL_LIST(output), 0);
496
252
  else {
497
252
    if (!self->bias.graph)
498
249
      self->bias = ccv_nnc_tensor_symbol_new(graph, bias_params, 0);
499
252
    ccv_nnc_graph_exec_symbol_new(graph, cmd, TENSOR_SYMBOL_LIST(inputs[0], self->weights, self->bias), TENSOR_SYMBOL_LIST(output), 0);
500
252
  }
501
2.29k
  outputs[0] = output;
502
2.29k
}
503
504
static void _ccv_cnnp_dense_init_states(ccv_cnnp_model_t* const super, ccv_nnc_symbolic_graph_t* const graph, const ccv_cnnp_state_initializer_f initializer, void* const context)
505
56
{
506
56
  ccv_cnnp_model_dense_t* const self = (ccv_cnnp_model_dense_t*)super;
507
56
  const ccv_nnc_tensor_param_t weight_params = ccv_nnc_tensor_symbol_params(graph, self->weights);
508
56
  const int c = weight_params.dim[1];
509
56
  const float std = sqrtf(2) / sqrtf(c);
510
56
  const float bound = sqrtf(3) * std;
511
56
  initializer(context, CMD_RANDOM_UNIFORM_FORWARD(-bound, bound), ccv_nnc_no_hint, 0, 0, self->weights);
512
56
  if (self->bias.graph)
513
32
    initializer(context, CMD_SET_FORWARD(0), ccv_nnc_no_hint, 0, 0, self->bias);
514
56
}
515
516
static void _ccv_cnnp_dense_add_to_parameter(ccv_cnnp_model_t* const super, const ccv_cnnp_add_to_array_f add_to_array, void* const parameters)
517
2.29k
{
518
2.29k
  ccv_cnnp_model_dense_t* const self = (ccv_cnnp_model_dense_t*)super;
519
2.29k
  add_to_array(parameters, self->weights);
520
2.29k
  if (self->bias.graph)
521
252
    add_to_array(parameters, self->bias);
522
2.29k
}
523
524
static ccv_cnnp_model_t* _ccv_cnnp_dense_copy(const ccv_cnnp_model_t* const super, void* const context);
525
526
static const ccv_cnnp_model_vtab_t ccv_cnnp_dense_isa = {
527
  .build = _ccv_cnnp_dense_build,
528
  .init_states = _ccv_cnnp_dense_init_states,
529
  .add_to_parameter = _ccv_cnnp_dense_add_to_parameter,
530
  .copy = _ccv_cnnp_dense_copy,
531
};
532
533
ccv_cnnp_model_t* ccv_cnnp_dense(const int count, const int no_bias, const char* const name)
534
2.29k
{
535
2.29k
  ccv_cnnp_model_dense_t* const model_dense = (ccv_cnnp_model_dense_t*)cccalloc(1, sizeof(ccv_cnnp_model_dense_t));
536
2.29k
  model_dense->super.isa = &ccv_cnnp_dense_isa;
537
2.29k
  model_dense->super.input_size = 1;
538
2.29k
  model_dense->super.outputs = &model_dense->output;
539
2.29k
  model_dense->super.output_size = 1;
540
2.29k
  ccv_cnnp_model_copy_name(&model_dense->super, name);
541
2.29k
  model_dense->weights.d = CCV_NNC_NO_TENSOR_SYMBOL;
542
2.29k
  model_dense->weights.graph = 0;
543
2.29k
  model_dense->bias.d = CCV_NNC_NO_TENSOR_SYMBOL;
544
2.29k
  model_dense->bias.graph = 0;
545
2.29k
  model_dense->count = count;
546
2.29k
  model_dense->no_bias = no_bias;
547
2.29k
  return (ccv_cnnp_model_t*)model_dense;
548
2.29k
}
549
550
static ccv_cnnp_model_t* _ccv_cnnp_dense_copy(const ccv_cnnp_model_t* const super, void* const context)
551
2.20k
{
552
2.20k
  const ccv_cnnp_model_dense_t* const self = (const ccv_cnnp_model_dense_t*)super;
553
2.20k
  return ccv_cnnp_dense(self->count, self->no_bias, self->super.name);
554
2.20k
}
555
556
// MARK - Pool Layers
557
558
typedef struct {
559
  ccv_cnnp_model_t super;
560
  ccv_nnc_tensor_symbol_t output;
561
  int kdim[CCV_NNC_MAX_DIM_ALLOC];
562
  ccv_nnc_hint_t hint;
563
} ccv_cnnp_model_pool_t;
564
565
static void _ccv_cnnp_max_pool_build(ccv_cnnp_model_t* const super, ccv_nnc_symbolic_graph_t* const graph, const ccv_nnc_tensor_symbol_t* const inputs, const int input_size, ccv_nnc_tensor_symbol_t* const outputs, const int output_size)
566
18
{
567
18
  assert(input_size == 1);
568
18
  assert(output_size == 1);
569
18
  ccv_cnnp_model_pool_t* const self = (ccv_cnnp_model_pool_t*)super;
570
18
  const ccv_nnc_tensor_param_t params = ccv_nnc_tensor_symbol_params(graph, inputs[0]);
571
18
  const int hw = ccv_nnc_tensor_hw(params, ccv_nnc_tensor_nd(params.dim));
572
18
  ccv_nnc_cmd_t cmd;
573
18
  if (hw >= 0 && self->kdim[0] == 0 && 
self->kdim[1] == 03
)
574
3
    cmd = CMD_MAX_POOL_FORWARD(params.dim[hw], params.dim[hw + 1]);
575
18
  else
576
18
    
cmd = 15
CMD_MAX_POOL_FORWARD15
(self->kdim[0], self->kdim[1]);
577
18
  ccv_nnc_tensor_param_t output_params;
578
18
  ccv_nnc_hint_tensor_auto(cmd, &params, 1, self->hint, &output_params, 1);
579
18
  const ccv_nnc_tensor_symbol_t pool_output = ccv_nnc_tensor_symbol_new(graph, output_params, 0);
580
18
  const ccv_nnc_graph_exec_symbol_t exec = ccv_nnc_graph_exec_symbol_new(graph, cmd, TENSOR_SYMBOL_LIST(inputs[0]), TENSOR_SYMBOL_LIST(pool_output), 0);
581
18
  ccv_nnc_graph_exec_symbol_set_hint(graph, exec, self->hint);
582
18
  outputs[0] = pool_output;
583
18
}
584
585
static ccv_cnnp_model_t* _ccv_cnnp_max_pool_copy(const ccv_cnnp_model_t* const super, void* const context);
586
587
static const ccv_cnnp_model_vtab_t ccv_cnnp_max_pool_isa = {
588
  .build = _ccv_cnnp_max_pool_build,
589
  .copy = _ccv_cnnp_max_pool_copy,
590
};
591
592
ccv_cnnp_model_t* ccv_cnnp_max_pool(const int kdim[CCV_NNC_MAX_DIM_ALLOC], const ccv_nnc_hint_t hint, const char* const name)
593
24
{
594
24
  ccv_cnnp_model_pool_t* const model_pool = (ccv_cnnp_model_pool_t*)cccalloc(1, sizeof(ccv_cnnp_model_pool_t));
595
24
  model_pool->super.isa = &ccv_cnnp_max_pool_isa;
596
24
  model_pool->super.input_size = 1;
597
24
  model_pool->super.outputs = &model_pool->output;
598
24
  model_pool->super.output_size = 1;
599
24
  ccv_cnnp_model_copy_name(&model_pool->super, name);
600
24
  memcpy(model_pool->kdim, kdim, sizeof(model_pool->kdim));
601
24
  model_pool->hint = hint;
602
24
  return (ccv_cnnp_model_t*)model_pool;
603
24
}
604
605
static ccv_cnnp_model_t* _ccv_cnnp_max_pool_copy(const ccv_cnnp_model_t* const super, void* const context)
606
6
{
607
6
  const ccv_cnnp_model_pool_t* const self = (const ccv_cnnp_model_pool_t*)super;
608
6
  return ccv_cnnp_max_pool(self->kdim, self->hint, self->super.name);
609
6
}
610
611
static void _ccv_cnnp_average_pool_build(ccv_cnnp_model_t* const super, ccv_nnc_symbolic_graph_t* const graph, const ccv_nnc_tensor_symbol_t* const inputs, const int input_size, ccv_nnc_tensor_symbol_t* const outputs, const int output_size)
612
16
{
613
16
  assert(input_size == 1);
614
16
  assert(output_size == 1);
615
16
  ccv_cnnp_model_pool_t* const self = (ccv_cnnp_model_pool_t*)super;
616
16
  const ccv_nnc_tensor_param_t params = ccv_nnc_tensor_symbol_params(graph, inputs[0]);
617
16
  const int hw = ccv_nnc_tensor_hw(params, ccv_nnc_tensor_nd(params.dim));
618
16
  ccv_nnc_cmd_t cmd;
619
16
  if (hw >= 0 && self->kdim[0] == 0 && 
self->kdim[1] == 03
)
620
3
    cmd = CMD_AVERAGE_POOL_FORWARD(params.dim[hw], params.dim[hw + 1]);
621
16
  else
622
16
    
cmd = 13
CMD_AVERAGE_POOL_FORWARD13
(self->kdim[0], self->kdim[1]);
623
16
  ccv_nnc_tensor_param_t output_params;
624
16
  ccv_nnc_hint_tensor_auto(cmd, &params, 1, self->hint, &output_params, 1);
625
16
  const ccv_nnc_tensor_symbol_t pool_output = ccv_nnc_tensor_symbol_new(graph, output_params, 0);
626
16
  const ccv_nnc_graph_exec_symbol_t exec = ccv_nnc_graph_exec_symbol_new(graph, cmd, TENSOR_SYMBOL_LIST(inputs[0]), TENSOR_SYMBOL_LIST(pool_output), 0);
627
16
  ccv_nnc_graph_exec_symbol_set_hint(graph, exec, self->hint);
628
16
  outputs[0] = pool_output;
629
16
}
630
631
static ccv_cnnp_model_t* _ccv_cnnp_average_pool_copy(const ccv_cnnp_model_t* const super, void* const context);
632
633
static const ccv_cnnp_model_vtab_t ccv_cnnp_average_pool_isa = {
634
  .build = _ccv_cnnp_average_pool_build,
635
  .copy = _ccv_cnnp_average_pool_copy,
636
};
637
638
ccv_cnnp_model_t* ccv_cnnp_average_pool(const int kdim[CCV_NNC_MAX_DIM_ALLOC], const ccv_nnc_hint_t hint, const char* const name)
639
18
{
640
18
  ccv_cnnp_model_pool_t* const model_pool = (ccv_cnnp_model_pool_t*)cccalloc(1, sizeof(ccv_cnnp_model_pool_t));
641
18
  model_pool->super.isa = &ccv_cnnp_average_pool_isa;
642
18
  model_pool->super.input_size = 1;
643
18
  model_pool->super.outputs = &model_pool->output;
644
18
  model_pool->super.output_size = 1;
645
18
  ccv_cnnp_model_copy_name(&model_pool->super, name);
646
18
  memcpy(model_pool->kdim, kdim, sizeof(model_pool->kdim));
647
18
  model_pool->hint = hint;
648
18
  return (ccv_cnnp_model_t*)model_pool;
649
18
}
650
651
static ccv_cnnp_model_t* _ccv_cnnp_average_pool_copy(const ccv_cnnp_model_t* const super, void* const context)
652
2
{
653
2
  const ccv_cnnp_model_pool_t* const self = (const ccv_cnnp_model_pool_t*)super;
654
2
  return ccv_cnnp_average_pool(self->kdim, self->hint, self->super.name);
655
2
}
656
657
// MARK - RELU Layer
658
659
typedef struct {
660
  ccv_cnnp_model_t super;
661
  ccv_nnc_tensor_symbol_t output;
662
} ccv_cnnp_model_relu_t;
663
664
static void _ccv_cnnp_relu_build(ccv_cnnp_model_t* const super, ccv_nnc_symbolic_graph_t* const graph, const ccv_nnc_tensor_symbol_t* const inputs, const int input_size, ccv_nnc_tensor_symbol_t* const outputs, const int output_size)
665
105
{
666
105
  assert(input_size == 1);
667
105
  assert(output_size == 1);
668
105
  ccv_nnc_tensor_param_t params = ccv_nnc_tensor_symbol_params(graph, inputs[0]);
669
105
  ccv_nnc_tensor_param_t output_params;
670
105
  const ccv_nnc_cmd_t relu = CMD_RELU_FORWARD();
671
105
  ccv_nnc_hint_tensor_auto(relu, (ccv_nnc_tensor_param_t []){
672
105
      params,
673
105
    }, 1, ccv_nnc_no_hint, &output_params, 1);
674
105
  const ccv_nnc_tensor_symbol_t relu_output = ccv_nnc_tensor_symbol_new(graph, output_params, 0);
675
105
  ccv_nnc_graph_exec_symbol_new(graph, relu, TENSOR_SYMBOL_LIST(inputs[0]), TENSOR_SYMBOL_LIST(relu_output), 0);
676
105
  outputs[0] = relu_output;
677
105
}
678
679
static ccv_cnnp_model_t* _ccv_cnnp_relu_copy(const ccv_cnnp_model_t* const self, void* const context);
680
681
static const ccv_cnnp_model_vtab_t ccv_cnnp_relu_isa = {
682
  .build = _ccv_cnnp_relu_build,
683
  .copy = _ccv_cnnp_relu_copy,
684
};
685
686
ccv_cnnp_model_t* ccv_cnnp_relu(const char* const name)
687
122
{
688
122
  ccv_cnnp_model_relu_t* const model_relu = (ccv_cnnp_model_relu_t*)cccalloc(1, sizeof(ccv_cnnp_model_relu_t));
689
122
  model_relu->super.isa = &ccv_cnnp_relu_isa;
690
122
  model_relu->super.input_size = 1;
691
122
  model_relu->super.outputs = &model_relu->output;
692
122
  model_relu->super.output_size = 1;
693
122
  ccv_cnnp_model_copy_name(&model_relu->super, name);
694
122
  return (ccv_cnnp_model_t*)model_relu;
695
122
}
696
697
static ccv_cnnp_model_t* _ccv_cnnp_relu_copy(const ccv_cnnp_model_t* const self, void* const context)
698
17
{
699
17
  return ccv_cnnp_relu(self->name);
700
17
}
701
702
// MARK - Sigmoid Layer
703
704
typedef struct {
705
  ccv_cnnp_model_t super;
706
  ccv_nnc_tensor_symbol_t output;
707
} ccv_cnnp_model_sigmoid_t;
708
709
static void _ccv_cnnp_sigmoid_build(ccv_cnnp_model_t* const super, ccv_nnc_symbolic_graph_t* const graph, const ccv_nnc_tensor_symbol_t* const inputs, const int input_size, ccv_nnc_tensor_symbol_t* const outputs, const int output_size)
710
0
{
711
0
  assert(input_size == 1);
712
0
  assert(output_size == 1);
713
0
  ccv_nnc_tensor_param_t params = ccv_nnc_tensor_symbol_params(graph, inputs[0]);
714
0
  ccv_nnc_tensor_param_t output_params;
715
0
  const ccv_nnc_cmd_t sigmoid = CMD_SIGMOID_FORWARD();
716
0
  ccv_nnc_hint_tensor_auto(sigmoid, (ccv_nnc_tensor_param_t []){
717
0
      params,
718
0
    }, 1, ccv_nnc_no_hint, &output_params, 1);
719
0
  const ccv_nnc_tensor_symbol_t sigmoid_output = ccv_nnc_tensor_symbol_new(graph, output_params, 0);
720
0
  ccv_nnc_graph_exec_symbol_new(graph, sigmoid, TENSOR_SYMBOL_LIST(inputs[0]), TENSOR_SYMBOL_LIST(sigmoid_output), 0);
721
0
  outputs[0] = sigmoid_output;
722
0
}
723
724
static ccv_cnnp_model_t* _ccv_cnnp_sigmoid_copy(const ccv_cnnp_model_t* const self, void* const context);
725
726
static const ccv_cnnp_model_vtab_t ccv_cnnp_sigmoid_isa = {
727
  .build = _ccv_cnnp_sigmoid_build,
728
  .copy = _ccv_cnnp_sigmoid_copy,
729
};
730
731
ccv_cnnp_model_t* ccv_cnnp_sigmoid(const char* const name)
732
0
{
733
0
  ccv_cnnp_model_sigmoid_t* const model_sigmoid = (ccv_cnnp_model_sigmoid_t*)cccalloc(1, sizeof(ccv_cnnp_model_sigmoid_t));
734
0
  model_sigmoid->super.isa = &ccv_cnnp_sigmoid_isa;
735
0
  model_sigmoid->super.input_size = 1;
736
0
  model_sigmoid->super.outputs = &model_sigmoid->output;
737
0
  model_sigmoid->super.output_size = 1;
738
0
  ccv_cnnp_model_copy_name(&model_sigmoid->super, name);
739
0
  return (ccv_cnnp_model_t*)model_sigmoid;
740
0
}
741
742
static ccv_cnnp_model_t* _ccv_cnnp_sigmoid_copy(const ccv_cnnp_model_t* const self, void* const context)
743
0
{
744
0
  return ccv_cnnp_sigmoid(self->name);
745
0
}
746
747
// MARK - Swish Layer
748
749
typedef struct {
750
  ccv_cnnp_model_t super;
751
  ccv_nnc_tensor_symbol_t output;
752
} ccv_cnnp_model_swish_t;
753
754
static void _ccv_cnnp_swish_build(ccv_cnnp_model_t* const super, ccv_nnc_symbolic_graph_t* const graph, const ccv_nnc_tensor_symbol_t* const inputs, const int input_size, ccv_nnc_tensor_symbol_t* const outputs, const int output_size)
755
0
{
756
0
  assert(input_size == 1);
757
0
  assert(output_size == 1);
758
0
  ccv_nnc_tensor_param_t params = ccv_nnc_tensor_symbol_params(graph, inputs[0]);
759
0
  ccv_nnc_tensor_param_t output_params;
760
0
  const ccv_nnc_cmd_t swish = CMD_SWISH_FORWARD();
761
0
  ccv_nnc_hint_tensor_auto(swish, (ccv_nnc_tensor_param_t []){
762
0
      params,
763
0
    }, 1, ccv_nnc_no_hint, &output_params, 1);
764
0
  const ccv_nnc_tensor_symbol_t swish_output = ccv_nnc_tensor_symbol_new(graph, output_params, 0);
765
0
  ccv_nnc_graph_exec_symbol_new(graph, swish, TENSOR_SYMBOL_LIST(inputs[0]), TENSOR_SYMBOL_LIST(swish_output), 0);
766
0
  outputs[0] = swish_output;
767
0
}
768
769
static ccv_cnnp_model_t* _ccv_cnnp_swish_copy(const ccv_cnnp_model_t* const self, void* const context);
770
771
static const ccv_cnnp_model_vtab_t ccv_cnnp_swish_isa = {
772
  .build = _ccv_cnnp_swish_build,
773
  .copy = _ccv_cnnp_swish_copy,
774
};
775
776
ccv_cnnp_model_t* ccv_cnnp_swish(const char* const name)
777
0
{
778
0
  ccv_cnnp_model_swish_t* const model_swish = (ccv_cnnp_model_swish_t*)cccalloc(1, sizeof(ccv_cnnp_model_swish_t));
779
0
  model_swish->super.isa = &ccv_cnnp_swish_isa;
780
0
  model_swish->super.input_size = 1;
781
0
  model_swish->super.outputs = &model_swish->output;
782
0
  model_swish->super.output_size = 1;
783
0
  ccv_cnnp_model_copy_name(&model_swish->super, name);
784
0
  return (ccv_cnnp_model_t*)model_swish;
785
0
}
786
787
static ccv_cnnp_model_t* _ccv_cnnp_swish_copy(const ccv_cnnp_model_t* const self, void* const context)
788
0
{
789
0
  return ccv_cnnp_swish(self->name);
790
0
}
791
792
// MARK - Softmax Layer
793
794
typedef struct {
795
  ccv_cnnp_model_t super;
796
  ccv_nnc_tensor_symbol_t output;
797
} ccv_cnnp_model_softmax_t;
798
799
static void _ccv_cnnp_softmax_build(ccv_cnnp_model_t* const super, ccv_nnc_symbolic_graph_t* const graph, const ccv_nnc_tensor_symbol_t* const inputs, const int input_size, ccv_nnc_tensor_symbol_t* const outputs, const int output_size)
800
10
{
801
10
  assert(input_size == 1);
802
10
  assert(output_size == 1);
803
10
  ccv_nnc_tensor_param_t params = ccv_nnc_tensor_symbol_params(graph, inputs[0]);
804
10
  ccv_nnc_tensor_param_t output_params;
805
10
  const ccv_nnc_cmd_t softmax = CMD_SOFTMAX_FORWARD();
806
10
  ccv_nnc_hint_tensor_auto(softmax, (ccv_nnc_tensor_param_t []){
807
10
      params,
808
10
    }, 1, ccv_nnc_no_hint, &output_params, 1);
809
10
  const ccv_nnc_tensor_symbol_t softmax_output = ccv_nnc_tensor_symbol_new(graph, output_params, 0);
810
10
  ccv_nnc_graph_exec_symbol_new(graph, softmax, TENSOR_SYMBOL_LIST(inputs[0]), TENSOR_SYMBOL_LIST(softmax_output), 0);
811
10
  outputs[0] = softmax_output;
812
10
}
813
814
static ccv_cnnp_model_t* _ccv_cnnp_softmax_copy(const ccv_cnnp_model_t* const self, void* const context);
815
816
static const ccv_cnnp_model_vtab_t ccv_cnnp_softmax_isa = {
817
  .build = _ccv_cnnp_softmax_build,
818
  .copy = _ccv_cnnp_softmax_copy,
819
};
820
821
ccv_cnnp_model_t* ccv_cnnp_softmax(const char* const name)
822
11
{
823
11
  ccv_cnnp_model_softmax_t* const model_softmax = (ccv_cnnp_model_softmax_t*)cccalloc(1, sizeof(ccv_cnnp_model_softmax_t));
824
11
  model_softmax->super.isa = &ccv_cnnp_softmax_isa;
825
11
  model_softmax->super.input_size = 1;
826
11
  model_softmax->super.outputs = &model_softmax->output;
827
11
  model_softmax->super.output_size = 1;
828
11
  ccv_cnnp_model_copy_name(&model_softmax->super, name);
829
11
  return (ccv_cnnp_model_t*)model_softmax;
830
11
}
831
832
static ccv_cnnp_model_t* _ccv_cnnp_softmax_copy(const ccv_cnnp_model_t* const self, void* const context)
833
1
{
834
1
  return ccv_cnnp_softmax(self->name);
835
1
}
836
837
// MARK - Add Layer
838
839
typedef struct {
840
  ccv_cnnp_model_t super;
841
  float p;
842
  float q;
843
  ccv_nnc_tensor_symbol_t output;
844
} ccv_cnnp_model_add_t;
845
846
static void _ccv_cnnp_add_build(ccv_cnnp_model_t* const super, ccv_nnc_symbolic_graph_t* const graph, const ccv_nnc_tensor_symbol_t* const inputs, const int input_size, ccv_nnc_tensor_symbol_t* const outputs, const int output_size)
847
0
{
848
0
  const ccv_cnnp_model_add_t* const self = (const ccv_cnnp_model_add_t*)super;
849
0
  assert(input_size == 2);
850
0
  assert(output_size == 1);
851
0
  ccv_nnc_tensor_param_t input_params[2];
852
0
  int i;
853
0
  for (i = 0; i < 2; i++)
854
0
    input_params[i] = ccv_nnc_tensor_symbol_params(graph, inputs[i]);
855
0
  ccv_nnc_tensor_param_t output_params;
856
0
  const ccv_nnc_cmd_t add = CMD_ADD_FORWARD(self->p, self->q);
857
0
  ccv_nnc_hint_tensor_auto(add, input_params, 2, ccv_nnc_no_hint, &output_params, 1);
858
0
  outputs[0] = ccv_nnc_tensor_symbol_new(graph, output_params, 0);
859
0
  ccv_nnc_graph_exec_symbol_new(graph, add, inputs, input_size, outputs, output_size, 0);
860
0
}
861
862
static ccv_cnnp_model_t* _ccv_cnnp_add_copy(const ccv_cnnp_model_t* const self, void* const context);
863
864
static const ccv_cnnp_model_vtab_t ccv_cnnp_add_isa = {
865
  .build = _ccv_cnnp_add_build,
866
  .copy = _ccv_cnnp_add_copy,
867
};
868
869
ccv_cnnp_model_t* ccv_cnnp_add(const float p, const float q, const char* const name)
870
0
{
871
0
  ccv_cnnp_model_add_t* const model_add = (ccv_cnnp_model_add_t*)cccalloc(1, sizeof(ccv_cnnp_model_add_t));
872
0
  model_add->super.isa = &ccv_cnnp_add_isa;
873
0
  model_add->super.input_size = 2;
874
0
  model_add->super.outputs = &model_add->output;
875
0
  model_add->super.output_size = 1;
876
0
  model_add->p = p;
877
0
  model_add->q = q;
878
0
  ccv_cnnp_model_copy_name(&model_add->super, name);
879
0
  return (ccv_cnnp_model_t*)model_add;
880
0
}
881
882
static ccv_cnnp_model_t* _ccv_cnnp_add_copy(const ccv_cnnp_model_t* const super, void* const context)
883
0
{
884
0
  const ccv_cnnp_model_add_t* const self = (const ccv_cnnp_model_add_t*)super;
885
0
  return ccv_cnnp_add(self->p, self->q, self->super.name);
886
0
}
887
888
// MARK - Mul Layer
889
890
typedef struct {
891
  ccv_cnnp_model_t super;
892
  ccv_nnc_tensor_symbol_t output;
893
  float p;
894
} ccv_cnnp_model_mul_t;
895
896
static void _ccv_cnnp_mul_build(ccv_cnnp_model_t* const super, ccv_nnc_symbolic_graph_t* const graph, const ccv_nnc_tensor_symbol_t* const inputs, const int input_size, ccv_nnc_tensor_symbol_t* const outputs, const int output_size)
897
1
{
898
1
  const ccv_cnnp_model_mul_t* const self = (const ccv_cnnp_model_mul_t*)super;
899
1
  assert(input_size == 2);
900
1
  assert(output_size == 1);
901
1
  ccv_nnc_tensor_param_t input_params[2];
902
1
  int i;
903
3
  for (i = 0; i < 2; 
i++2
)
904
2
    input_params[i] = ccv_nnc_tensor_symbol_params(graph, inputs[i]);
905
1
  ccv_nnc_tensor_param_t output_params;
906
1
  const ccv_nnc_cmd_t mul = CMD_MUL_FORWARD(self->p);
907
1
  ccv_nnc_hint_tensor_auto(mul, input_params, 2, ccv_nnc_no_hint, &output_params, 1);
908
1
  outputs[0] = ccv_nnc_tensor_symbol_new(graph, output_params, 0);
909
1
  ccv_nnc_graph_exec_symbol_new(graph, mul, inputs, input_size, outputs, output_size, 0);
910
1
}
911
912
static ccv_cnnp_model_t* _ccv_cnnp_mul_copy(const ccv_cnnp_model_t* const self, void* const context);
913
914
static const ccv_cnnp_model_vtab_t ccv_cnnp_mul_isa = {
915
  .build = _ccv_cnnp_mul_build,
916
  .copy = _ccv_cnnp_mul_copy,
917
};
918
919
ccv_cnnp_model_t* ccv_cnnp_mul(const float p, const char* const name)
920
1
{
921
1
  ccv_cnnp_model_mul_t* const model_mul = (ccv_cnnp_model_mul_t*)cccalloc(1, sizeof(ccv_cnnp_model_mul_t));
922
1
  model_mul->super.isa = &ccv_cnnp_mul_isa;
923
1
  model_mul->super.input_size = 2;
924
1
  model_mul->super.outputs = &model_mul->output;
925
1
  model_mul->super.output_size = 1;
926
1
  model_mul->p = p;
927
1
  ccv_cnnp_model_copy_name(&model_mul->super, name);
928
1
  return (ccv_cnnp_model_t*)model_mul;
929
1
}
930
931
static ccv_cnnp_model_t* _ccv_cnnp_mul_copy(const ccv_cnnp_model_t* const super, void* const context)
932
0
{
933
0
  const ccv_cnnp_model_mul_t* const self = (const ccv_cnnp_model_mul_t*)super;
934
0
  return ccv_cnnp_mul(self->p, self->super.name);
935
0
}
936
937
// MARK - Scalar Mul Layer
938
939
typedef struct {
940
  ccv_cnnp_model_t super;
941
  ccv_nnc_tensor_symbol_t output;
942
  float a;
943
} ccv_cnnp_model_scalar_mul_t;
944
945
static void _ccv_cnnp_scalar_mul_build(ccv_cnnp_model_t* const super, ccv_nnc_symbolic_graph_t* const graph, const ccv_nnc_tensor_symbol_t* const inputs, const int input_size, ccv_nnc_tensor_symbol_t* const outputs, const int output_size)
946
6
{
947
6
  assert(input_size == 1);
948
6
  assert(output_size == 1);
949
6
  ccv_nnc_tensor_param_t params = ccv_nnc_tensor_symbol_params(graph, inputs[0]);
950
6
  ccv_nnc_tensor_param_t output_params;
951
6
  ccv_cnnp_model_scalar_mul_t* const self = (ccv_cnnp_model_scalar_mul_t*)super;
952
6
  const ccv_nnc_cmd_t scalar_mul = CMD_SCALAR_MUL_FORWARD(self->a);
953
6
  ccv_nnc_hint_tensor_auto(scalar_mul, (ccv_nnc_tensor_param_t []){
954
6
      params,
955
6
    }, 1, ccv_nnc_no_hint, &output_params, 1);
956
6
  const ccv_nnc_tensor_symbol_t scalar_mul_output = ccv_nnc_tensor_symbol_new(graph, output_params, 0);
957
6
  ccv_nnc_graph_exec_symbol_new(graph, scalar_mul, TENSOR_SYMBOL_LIST(inputs[0]), TENSOR_SYMBOL_LIST(scalar_mul_output), 0);
958
6
  outputs[0] = scalar_mul_output;
959
6
}
960
961
static ccv_cnnp_model_t* _ccv_cnnp_scalar_mul_copy(const ccv_cnnp_model_t* const super, void* const context);
962
963
static const ccv_cnnp_model_vtab_t ccv_cnnp_scalar_mul_isa = {
964
  .build = _ccv_cnnp_scalar_mul_build,
965
  .copy = _ccv_cnnp_scalar_mul_copy,
966
};
967
968
ccv_cnnp_model_t* ccv_cnnp_scalar_mul(const float a, const char* const name)
969
6
{
970
6
  ccv_cnnp_model_scalar_mul_t* const model_scalar_mul = (ccv_cnnp_model_scalar_mul_t*)cccalloc(1, sizeof(ccv_cnnp_model_scalar_mul_t));
971
6
  model_scalar_mul->super.isa = &ccv_cnnp_scalar_mul_isa;
972
6
  model_scalar_mul->super.input_size = 1;
973
6
  model_scalar_mul->super.outputs = &model_scalar_mul->output;
974
6
  model_scalar_mul->super.output_size = 1;
975
6
  model_scalar_mul->a = a;
976
6
  ccv_cnnp_model_copy_name(&model_scalar_mul->super, name);
977
6
  return (ccv_cnnp_model_t*)model_scalar_mul;
978
6
}
979
980
static ccv_cnnp_model_t* _ccv_cnnp_scalar_mul_copy(const ccv_cnnp_model_t* const super, void* const context)
981
0
{
982
0
  const ccv_cnnp_model_scalar_mul_t* const self = (const ccv_cnnp_model_scalar_mul_t*)super;
983
0
  return ccv_cnnp_scalar_mul(self->a, self->super.name);
984
0
}
985
986
// MARK - Transpose Layer
987
988
typedef struct {
989
  ccv_cnnp_model_t super;
990
  ccv_nnc_tensor_symbol_t output;
991
  int transpose[2];
992
} ccv_cnnp_model_transpose_t;
993
994
static void _ccv_cnnp_transpose_build(ccv_cnnp_model_t* const super, ccv_nnc_symbolic_graph_t* const graph, const ccv_nnc_tensor_symbol_t* const inputs, const int input_size, ccv_nnc_tensor_symbol_t* const outputs, const int output_size)
995
33
{
996
33
  assert(input_size == 1);
997
33
  assert(output_size == 1);
998
33
  ccv_cnnp_model_transpose_t* const self = (ccv_cnnp_model_transpose_t*)super;
999
33
  if (self->transpose[0] == self->transpose[1])
1000
0
  {
1001
0
    outputs[0] = inputs[0];
1002
0
    return;
1003
0
  }
1004
33
  ccv_nnc_tensor_param_t params = ccv_nnc_tensor_symbol_params(graph, inputs[0]);
1005
33
  ccv_nnc_tensor_param_t output_params;
1006
33
  const ccv_nnc_cmd_t transpose = CMD_TRANSPOSE_FORWARD(self->transpose[0], self->transpose[1]);
1007
33
  ccv_nnc_hint_tensor_auto(transpose, (ccv_nnc_tensor_param_t []){
1008
33
      params,
1009
33
    }, 1, ccv_nnc_no_hint, &output_params, 1);
1010
33
  const ccv_nnc_tensor_symbol_t transpose_output = ccv_nnc_tensor_symbol_new(graph, output_params, 0);
1011
33
  ccv_nnc_graph_exec_symbol_new(graph, transpose, TENSOR_SYMBOL_LIST(inputs[0]), TENSOR_SYMBOL_LIST(transpose_output), 0);
1012
33
  outputs[0] = transpose_output;
1013
33
}
1014
1015
static ccv_cnnp_model_t* _ccv_cnnp_transpose_copy(const ccv_cnnp_model_t* const super, void* const context);
1016
1017
static const ccv_cnnp_model_vtab_t ccv_cnnp_transpose_isa = {
1018
  .build = _ccv_cnnp_transpose_build,
1019
  .copy = _ccv_cnnp_transpose_copy,
1020
};
1021
1022
ccv_cnnp_model_t* ccv_cnnp_transpose(const int axis_a, const int axis_b, const char* const name)
1023
33
{
1024
33
  ccv_cnnp_model_transpose_t* const model_transpose = (ccv_cnnp_model_transpose_t*)cccalloc(1, sizeof(ccv_cnnp_model_transpose_t));
1025
33
  model_transpose->super.isa = &ccv_cnnp_transpose_isa;
1026
33
  model_transpose->super.input_size = 1;
1027
33
  model_transpose->super.outputs = &model_transpose->output;
1028
33
  model_transpose->super.output_size = 1;
1029
33
  model_transpose->transpose[0] = axis_a;
1030
33
  model_transpose->transpose[1] = axis_b;
1031
33
  ccv_cnnp_model_copy_name(&model_transpose->super, name);
1032
33
  return (ccv_cnnp_model_t*)model_transpose;
1033
33
}
1034
1035
static ccv_cnnp_model_t* _ccv_cnnp_transpose_copy(const ccv_cnnp_model_t* const super, void* const context)
1036
0
{
1037
0
  const ccv_cnnp_model_transpose_t* const self = (const ccv_cnnp_model_transpose_t*)super;
1038
0
  return ccv_cnnp_transpose(self->transpose[0], self->transpose[1], self->super.name);
1039
0
}
1040
1041
// MARK - Layer Norm Layer
1042
1043
typedef struct {
1044
  ccv_cnnp_model_t super;
1045
  ccv_nnc_tensor_symbol_t output;
1046
  ccv_nnc_tensor_symbol_t bias;
1047
  ccv_nnc_tensor_symbol_t scale;
1048
  ccv_nnc_cmd_param_t params;
1049
} ccv_cnnp_model_layer_norm_t;
1050
1051
static void _ccv_cnnp_layer_norm_build(ccv_cnnp_model_t* const super, ccv_nnc_symbolic_graph_t* const graph, const ccv_nnc_tensor_symbol_t* const inputs, const int input_size, ccv_nnc_tensor_symbol_t* const outputs, const int output_size)
1052
12
{
1053
12
  assert(input_size == 1);
1054
12
  assert(output_size == 1);
1055
12
  ccv_cnnp_model_layer_norm_t* const self = (ccv_cnnp_model_layer_norm_t*)super;
1056
12
  const ccv_nnc_tensor_param_t params = ccv_nnc_tensor_symbol_params(graph, inputs[0]);
1057
12
  ccv_nnc_tensor_param_t bias_params = params;
1058
12
  // If the accuracy is not enough, bump it to 32-bit floating point.
1059
12
  if (bias_params.datatype != CCV_32F && 
bias_params.datatype != CCV_64F0
)
1060
0
    bias_params.datatype = CCV_32F;
1061
12
  const int nd = ccv_nnc_tensor_nd(params.dim);
1062
12
  int i;
1063
48
  for (i = 0; i < nd; 
i++36
)
1064
36
    bias_params.dim[i] = 1;
1065
24
  for (i = 0; i < self->params.lnorm.count; 
i++12
)
1066
12
    bias_params.dim[self->params.lnorm.axis[i]] = params.dim[self->params.lnorm.axis[i]];
1067
12
  // Both scale and bias are shared between if this model is reused.
1068
12
  if (!self->scale.graph)
1069
12
    self->scale = ccv_nnc_tensor_symbol_new(graph, bias_params, 0);
1070
12
  if (!self->bias.graph)
1071
12
    self->bias = ccv_nnc_tensor_symbol_new(graph, bias_params, 0);
1072
12
  const ccv_nnc_cmd_t layer_norm = ccv_nnc_cmd(CCV_NNC_LAYER_NORM_FORWARD, 0, self->params, 0);
1073
12
  ccv_nnc_tensor_param_t output_params[3];
1074
12
  ccv_nnc_hint_tensor_auto(layer_norm, (ccv_nnc_tensor_param_t []){
1075
12
      params,
1076
12
      bias_params,
1077
12
      bias_params,
1078
12
    }, 3, ccv_nnc_no_hint, output_params, 3);
1079
12
  const ccv_nnc_tensor_symbol_t output = ccv_nnc_tensor_symbol_new(graph, output_params[0], 0);
1080
12
  const ccv_nnc_tensor_symbol_t saved_mean = ccv_nnc_tensor_symbol_new(graph, output_params[1], 0);
1081
12
  const ccv_nnc_tensor_symbol_t saved_inv_std = ccv_nnc_tensor_symbol_new(graph, output_params[2], 0);
1082
12
  ccv_nnc_graph_exec_symbol_new(graph, layer_norm, TENSOR_SYMBOL_LIST(inputs[0], self->scale, self->bias), TENSOR_SYMBOL_LIST(output, saved_mean, saved_inv_std), 0);
1083
12
  outputs[0] = output;
1084
12
}
1085
1086
static void _ccv_cnnp_layer_norm_init_states(ccv_cnnp_model_t* const super, ccv_nnc_symbolic_graph_t* const graph, const ccv_cnnp_state_initializer_f initializer, void* const context)
1087
8
{
1088
8
  ccv_cnnp_model_layer_norm_t* const self = (ccv_cnnp_model_layer_norm_t*)super;
1089
8
  if (self->bias.graph)
1090
8
    initializer(context, CMD_SET_FORWARD(0), ccv_nnc_no_hint, 0, 0, self->bias);
1091
8
  if (self->scale.graph)
1092
8
    initializer(context, CMD_RANDOM_UNIFORM_FORWARD(0, 1), ccv_nnc_no_hint, 0, 0, self->scale);
1093
8
}
1094
1095
static void _ccv_cnnp_layer_norm_add_to_parameter(ccv_cnnp_model_t* const super, const ccv_cnnp_add_to_array_f add_to_array, void* const parameters)
1096
12
{
1097
12
  ccv_cnnp_model_layer_norm_t* const self = (ccv_cnnp_model_layer_norm_t*)super;
1098
12
  if (self->bias.graph)
1099
12
    add_to_array(parameters, self->bias);
1100
12
  if (self->scale.graph)
1101
12
    add_to_array(parameters, self->scale);
1102
12
}
1103
1104
static ccv_cnnp_model_t* _ccv_cnnp_layer_norm_copy(const ccv_cnnp_model_t* const super, void* const context);
1105
1106
static const ccv_cnnp_model_vtab_t ccv_cnnp_layer_norm_isa = {
1107
  .build = _ccv_cnnp_layer_norm_build,
1108
  .init_states = _ccv_cnnp_layer_norm_init_states,
1109
  .add_to_parameter = _ccv_cnnp_layer_norm_add_to_parameter,
1110
  .copy = _ccv_cnnp_layer_norm_copy,
1111
};
1112
1113
ccv_cnnp_model_t* ccv_cnnp_layer_norm(const float epsilon, const int axis[CCV_NNC_MAX_DIM_ALLOC], const int axis_count, const char* const name)
1114
12
{
1115
12
  ccv_cnnp_model_layer_norm_t* const model_layer_norm = (ccv_cnnp_model_layer_norm_t*)cccalloc(1, sizeof(ccv_cnnp_model_layer_norm_t));
1116
12
  model_layer_norm->super.isa = &ccv_cnnp_layer_norm_isa;
1117
12
  model_layer_norm->super.input_size = 1;
1118
12
  model_layer_norm->super.outputs = &model_layer_norm->output;
1119
12
  model_layer_norm->super.output_size = 1;
1120
12
  ccv_cnnp_model_copy_name(&model_layer_norm->super, name);
1121
12
  model_layer_norm->scale.d = CCV_NNC_NO_TENSOR_SYMBOL;
1122
12
  model_layer_norm->scale.graph = 0;
1123
12
  model_layer_norm->bias.d = CCV_NNC_NO_TENSOR_SYMBOL;
1124
12
  model_layer_norm->bias.graph = 0;
1125
12
  model_layer_norm->params.lnorm.epsilon = epsilon;
1126
12
  model_layer_norm->params.lnorm.count = axis_count;
1127
12
  memcpy(model_layer_norm->params.lnorm.axis, axis, sizeof(model_layer_norm->params.lnorm.axis));
1128
12
  return (ccv_cnnp_model_t*)model_layer_norm;
1129
12
}
1130
1131
static ccv_cnnp_model_t* _ccv_cnnp_layer_norm_copy(const ccv_cnnp_model_t* const super, void* const context)
1132
0
{
1133
0
  const ccv_cnnp_model_layer_norm_t* const self = (const ccv_cnnp_model_layer_norm_t*)super;
1134
0
  return ccv_cnnp_layer_norm(self->params.lnorm.epsilon, self->params.lnorm.axis, self->params.lnorm.count, self->super.name);
1135
0
}
1136
1137
// MARK - Batched Matrix Mul Layer
1138
1139
typedef struct {
1140
  ccv_cnnp_model_t super;
1141
  ccv_nnc_tensor_symbol_t output;
1142
  int transpose_a[2];
1143
  int transpose_b[2];
1144
} ccv_cnnp_model_matmul_t;
1145
1146
static void _ccv_cnnp_matmul_build(ccv_cnnp_model_t* const super, ccv_nnc_symbolic_graph_t* const graph, const ccv_nnc_tensor_symbol_t* const inputs, const int input_size, ccv_nnc_tensor_symbol_t* const outputs, const int output_size)
1147
14
{
1148
14
  assert(input_size == 2);
1149
14
  assert(output_size == 1);
1150
14
  ccv_cnnp_model_matmul_t* const self = (ccv_cnnp_model_matmul_t*)super;
1151
14
  ccv_nnc_tensor_param_t a_params = ccv_nnc_tensor_symbol_params(graph, inputs[0]);
1152
14
  ccv_nnc_tensor_param_t b_params = ccv_nnc_tensor_symbol_params(graph, inputs[1]);
1153
14
  ccv_nnc_tensor_param_t output_params;
1154
14
  const ccv_nnc_cmd_t matmul = CMD_GEMM_FORWARD(self->transpose_a, self->transpose_b);
1155
14
  ccv_nnc_hint_tensor_auto(matmul, (ccv_nnc_tensor_param_t []){
1156
14
      a_params,
1157
14
      b_params,
1158
14
    }, 2, ccv_nnc_no_hint, &output_params, 1);
1159
14
  const ccv_nnc_tensor_symbol_t matmul_output = ccv_nnc_tensor_symbol_new(graph, output_params, 0);
1160
14
  ccv_nnc_graph_exec_symbol_new(graph, matmul, inputs, input_size, TENSOR_SYMBOL_LIST(matmul_output), 0);
1161
14
  outputs[0] = matmul_output;
1162
14
}
1163
1164
static ccv_cnnp_model_t* _ccv_cnnp_matmul_copy(const ccv_cnnp_model_t* const super, void* const context);
1165
1166
static const ccv_cnnp_model_vtab_t ccv_cnnp_matmul_isa = {
1167
  .build = _ccv_cnnp_matmul_build,
1168
  .copy = _ccv_cnnp_matmul_copy,
1169
};
1170
1171
ccv_cnnp_model_t* ccv_cnnp_matmul(const int transpose_a[2], const int transpose_b[2], const char* const name)
1172
14
{
1173
14
  ccv_cnnp_model_matmul_t* const model_matmul = (ccv_cnnp_model_matmul_t*)cccalloc(1, sizeof(ccv_cnnp_model_matmul_t));
1174
14
  model_matmul->super.isa = &ccv_cnnp_matmul_isa;
1175
14
  model_matmul->super.input_size = 2;
1176
14
  model_matmul->super.outputs = &model_matmul->output;
1177
14
  model_matmul->super.output_size = 1;
1178
14
  model_matmul->transpose_a[0] = transpose_a[0];
1179
14
  model_matmul->transpose_a[1] = transpose_a[1];
1180
14
  model_matmul->transpose_b[0] = transpose_b[0];
1181
14
  model_matmul->transpose_b[1] = transpose_b[1];
1182
14
  ccv_cnnp_model_copy_name(&model_matmul->super, name);
1183
14
  return (ccv_cnnp_model_t*)model_matmul;
1184
14
}
1185
1186
static ccv_cnnp_model_t* _ccv_cnnp_matmul_copy(const ccv_cnnp_model_t* const super, void* const context)
1187
1
{
1188
1
  const ccv_cnnp_model_matmul_t* const self = (const ccv_cnnp_model_matmul_t*)super;
1189
1
  return ccv_cnnp_matmul(self->transpose_a, self->transpose_b, self->super.name);
1190
1
}
1191
1192
// MARK - Dropout Layer
1193
1194
typedef struct {
1195
  ccv_cnnp_model_t super;
1196
  ccv_nnc_tensor_symbol_t output;
1197
  ccv_nnc_graph_exec_symbol_t dropout;
1198
  float p;
1199
  int entirety;
1200
} ccv_cnnp_model_dropout_t;
1201
1202
static void _ccv_cnnp_dropout_build(ccv_cnnp_model_t* const super, ccv_nnc_symbolic_graph_t* const graph, const ccv_nnc_tensor_symbol_t* const inputs, const int input_size, ccv_nnc_tensor_symbol_t* const outputs, const int output_size)
1203
18
{
1204
18
  assert(input_size == 1);
1205
18
  assert(output_size == 1);
1206
18
  ccv_nnc_tensor_param_t params = ccv_nnc_tensor_symbol_params(graph, inputs[0]);
1207
18
  ccv_nnc_tensor_param_t output_params[2];
1208
18
  ccv_cnnp_model_dropout_t* const self = (ccv_cnnp_model_dropout_t*)super;
1209
18
  const ccv_nnc_cmd_t dropout = CMD_DROPOUT_FORWARD(self->p, self->entirety);
1210
18
  ccv_nnc_hint_tensor_auto(dropout, (ccv_nnc_tensor_param_t []){
1211
18
      params,
1212
18
    }, 1, ccv_nnc_no_hint, output_params, 2);
1213
18
  const ccv_nnc_tensor_symbol_t dropout_output = ccv_nnc_tensor_symbol_new(graph, output_params[0], 0);
1214
18
  const ccv_nnc_tensor_symbol_t mask = ccv_nnc_tensor_symbol_new(graph, output_params[1], 0);
1215
18
  self->dropout = ccv_nnc_graph_exec_symbol_new(graph, dropout, TENSOR_SYMBOL_LIST(inputs[0]), TENSOR_SYMBOL_LIST(dropout_output, mask), 0);
1216
18
  outputs[0] = dropout_output;
1217
18
}
1218
1219
static void _ccv_cnnp_dropout_set_is_test(ccv_cnnp_model_t* const super, const int is_test, const ccv_cnnp_cmd_updater_f updater, void* const context)
1220
24
{
1221
24
  ccv_cnnp_model_dropout_t* const self = (ccv_cnnp_model_dropout_t*)super;
1222
24
  if (self->dropout.graph)
1223
24
  {
1224
24
    if (is_test)
1225
12
      // During test, the dropout is not applied. Data transfer is perfect because if these are the same tensor, it will skip.
1226
12
      updater(context, self->dropout, CMD_DATA_TRANSFER_FORWARD(), ccv_nnc_no_hint);
1227
12
    else
1228
12
      updater(context, self->dropout, CMD_DROPOUT_FORWARD(self->p, self->entirety), ccv_nnc_no_hint);
1229
24
  }
1230
24
}
1231
1232
static ccv_cnnp_model_t* _ccv_cnnp_dropout_copy(const ccv_cnnp_model_t* const super, void* const context);
1233
1234
static const ccv_cnnp_model_vtab_t ccv_cnnp_dropout_isa = {
1235
  .build = _ccv_cnnp_dropout_build,
1236
  .set_is_test = _ccv_cnnp_dropout_set_is_test,
1237
  .copy = _ccv_cnnp_dropout_copy,
1238
};
1239
1240
ccv_cnnp_model_t* ccv_cnnp_dropout(const float p, const int entirety, const char* const name)
1241
18
{
1242
18
  ccv_cnnp_model_dropout_t* const model_dropout = (ccv_cnnp_model_dropout_t*)cccalloc(1, sizeof(ccv_cnnp_model_dropout_t));
1243
18
  model_dropout->super.isa = &ccv_cnnp_dropout_isa;
1244
18
  model_dropout->super.input_size = 1;
1245
18
  model_dropout->super.outputs = &model_dropout->output;
1246
18
  model_dropout->super.output_size = 1;
1247
18
  model_dropout->p = p;
1248
18
  model_dropout->entirety = entirety;
1249
18
  ccv_cnnp_model_copy_name(&model_dropout->super, name);
1250
18
  return (ccv_cnnp_model_t*)model_dropout;
1251
18
}
1252
1253
static ccv_cnnp_model_t* _ccv_cnnp_dropout_copy(const ccv_cnnp_model_t* const super, void* const context)
1254
0
{
1255
0
  const ccv_cnnp_model_dropout_t* const self = (const ccv_cnnp_model_dropout_t*)super;
1256
0
  return ccv_cnnp_dropout(self->p, self->entirety, self->super.name);
1257
0
}
1258
1259
// MARK - Masked Fill Layer
1260
1261
typedef struct {
1262
  ccv_cnnp_model_t super;
1263
  ccv_nnc_tensor_symbol_t output;
1264
  float eq;
1265
  float fill;
1266
} ccv_cnnp_model_masked_fill_t;
1267
1268
static void _ccv_cnnp_masked_fill_build(ccv_cnnp_model_t* const super, ccv_nnc_symbolic_graph_t* const graph, const ccv_nnc_tensor_symbol_t* const inputs, const int input_size, ccv_nnc_tensor_symbol_t* const outputs, const int output_size)
1269
6
{
1270
6
  assert(input_size == 2);
1271
6
  assert(output_size == 1);
1272
6
  ccv_nnc_tensor_param_t params = ccv_nnc_tensor_symbol_params(graph, inputs[0]);
1273
6
  ccv_cnnp_model_masked_fill_t* const self = (ccv_cnnp_model_masked_fill_t*)super;
1274
6
  const ccv_nnc_tensor_symbol_t masked_fill_output = ccv_nnc_tensor_symbol_new(graph, params, 0);
1275
6
  ccv_nnc_graph_exec_symbol_new(graph, CMD_MASKED_FILL_FORWARD(self->eq, self->fill), TENSOR_SYMBOL_LIST(inputs[0], inputs[1]), TENSOR_SYMBOL_LIST(masked_fill_output), 0);
1276
6
  outputs[0] = masked_fill_output;
1277
6
}
1278
1279
static ccv_cnnp_model_t* _ccv_cnnp_masked_fill_copy(const ccv_cnnp_model_t* const super, void* const context);
1280
1281
static const ccv_cnnp_model_vtab_t ccv_cnnp_masked_fill_isa = {
1282
  .build = _ccv_cnnp_masked_fill_build,
1283
  .copy = _ccv_cnnp_masked_fill_copy,
1284
};
1285
1286
ccv_cnnp_model_t* ccv_cnnp_masked_fill(const float eq, const float fill, const char* const name)
1287
6
{
1288
6
  ccv_cnnp_model_masked_fill_t* const model_masked_fill = (ccv_cnnp_model_masked_fill_t*)cccalloc(1, sizeof(ccv_cnnp_model_masked_fill_t));
1289
6
  model_masked_fill->super.isa = &ccv_cnnp_masked_fill_isa;
1290
6
  model_masked_fill->super.input_size = 2;
1291
6
  model_masked_fill->super.outputs = &model_masked_fill->output;
1292
6
  model_masked_fill->super.output_size = 1;
1293
6
  model_masked_fill->eq = eq;
1294
6
  model_masked_fill->fill = fill;
1295
6
  ccv_cnnp_model_copy_name(&model_masked_fill->super, name);
1296
6
  return (ccv_cnnp_model_t*)model_masked_fill;
1297
6
}
1298
1299
static ccv_cnnp_model_t* _ccv_cnnp_masked_fill_copy(const ccv_cnnp_model_t* const super, void* const context)
1300
0
{
1301
0
  const ccv_cnnp_model_masked_fill_t* const self = (const ccv_cnnp_model_masked_fill_t*)super;
1302
0
  return ccv_cnnp_masked_fill(self->eq, self->fill, self->super.name);
1303
0
}
1304
1305
// MARK - Index Select Layer
1306
1307
typedef struct {
1308
  ccv_cnnp_model_t super;
1309
  ccv_nnc_tensor_symbol_t output;
1310
  ccv_nnc_tensor_symbol_t vocab;
1311
  int datatype;
1312
  int vocab_size;
1313
  int embed_size;
1314
} ccv_cnnp_model_index_select_t;
1315
1316
static void _ccv_cnnp_index_select_build(ccv_cnnp_model_t* const super, ccv_nnc_symbolic_graph_t* const graph, const ccv_nnc_tensor_symbol_t* const inputs, const int input_size, ccv_nnc_tensor_symbol_t* const outputs, const int output_size)
1317
1
{
1318
1
  assert(input_size == 1);
1319
1
  assert(output_size == 1);
1320
1
  ccv_cnnp_model_index_select_t* const self = (ccv_cnnp_model_index_select_t*)super;
1321
1
  const ccv_nnc_tensor_param_t params = ccv_nnc_tensor_symbol_params(graph, inputs[0]);
1322
1
  ccv_nnc_tensor_param_t vocab_params = params;
1323
1
  memset(vocab_params.dim, 0, sizeof(vocab_params.dim));
1324
1
  vocab_params.datatype = self->datatype;
1325
1
  vocab_params.dim[0] = self->vocab_size;
1326
1
  vocab_params.dim[1] = self->embed_size;
1327
1
  if (!self->vocab.graph)
1328
1
    self->vocab = ccv_nnc_tensor_symbol_new(graph, vocab_params, 0);
1329
1
  assert(self->vocab.graph == graph);
1330
1
  ccv_nnc_tensor_param_t output_params;
1331
1
  const ccv_nnc_cmd_t index_select = CMD_INDEX_SELECT_FORWARD();
1332
1
  ccv_nnc_hint_tensor_auto(index_select, (ccv_nnc_tensor_param_t []){
1333
1
      vocab_params,
1334
1
      params,
1335
1
    }, 2, ccv_nnc_no_hint, &output_params, 1);
1336
1
  const ccv_nnc_tensor_symbol_t output = ccv_nnc_tensor_symbol_new(graph, output_params, 0);
1337
1
  ccv_nnc_graph_exec_symbol_new(graph, index_select, TENSOR_SYMBOL_LIST(self->vocab, inputs[0]), TENSOR_SYMBOL_LIST(output), 0);
1338
1
  outputs[0] = output;
1339
1
}
1340
1341
static void _ccv_cnnp_index_select_init_states(ccv_cnnp_model_t* const super, ccv_nnc_symbolic_graph_t* const graph, const ccv_cnnp_state_initializer_f initializer, void* const context)
1342
1
{
1343
1
  ccv_cnnp_model_index_select_t* const self = (ccv_cnnp_model_index_select_t*)super;
1344
1
  const float std = sqrtf(2) / sqrtf(self->vocab_size + self->embed_size);
1345
1
  const float bound = sqrtf(3) * std;
1346
1
  initializer(context, CMD_RANDOM_UNIFORM_FORWARD(-bound, bound), ccv_nnc_no_hint, 0, 0, self->vocab);
1347
1
}
1348
1349
static void _ccv_cnnp_index_select_add_to_parameter(ccv_cnnp_model_t* const super, const ccv_cnnp_add_to_array_f add_to_array, void* const parameters)
1350
1
{
1351
1
  ccv_cnnp_model_index_select_t* const self = (ccv_cnnp_model_index_select_t*)super;
1352
1
  add_to_array(parameters, self->vocab);
1353
1
}
1354
1355
static ccv_cnnp_model_t* _ccv_cnnp_index_select_copy(const ccv_cnnp_model_t* const super, void* const context);
1356
1357
static const ccv_cnnp_model_vtab_t ccv_cnnp_index_select_isa = {
1358
  .build = _ccv_cnnp_index_select_build,
1359
  .init_states = _ccv_cnnp_index_select_init_states,
1360
  .add_to_parameter = _ccv_cnnp_index_select_add_to_parameter,
1361
  .copy = _ccv_cnnp_index_select_copy,
1362
};
1363
1364
ccv_cnnp_model_t* ccv_cnnp_index_select(const int datatype, const int vocab_size, const int embed_size, const char* const name)
1365
1
{
1366
1
  ccv_cnnp_model_index_select_t* const model_index_select = (ccv_cnnp_model_index_select_t*)cccalloc(1, sizeof(ccv_cnnp_model_index_select_t));
1367
1
  model_index_select->super.isa = &ccv_cnnp_index_select_isa;
1368
1
  model_index_select->super.input_size = 1;
1369
1
  model_index_select->super.outputs = &model_index_select->output;
1370
1
  model_index_select->super.output_size = 1;
1371
1
  ccv_cnnp_model_copy_name(&model_index_select->super, name);
1372
1
  model_index_select->vocab.d = CCV_NNC_NO_TENSOR_SYMBOL;
1373
1
  model_index_select->vocab.graph = 0;
1374
1
  assert(datatype == CCV_32F || datatype == CCV_16F);
1375
1
  model_index_select->datatype = datatype;
1376
1
  assert(vocab_size > 0);
1377
1
  model_index_select->vocab_size = vocab_size;
1378
1
  assert(embed_size > 0);
1379
1
  model_index_select->embed_size = embed_size;
1380
1
  return (ccv_cnnp_model_t*)model_index_select;
1381
1
}
1382
1383
static ccv_cnnp_model_t* _ccv_cnnp_index_select_copy(const ccv_cnnp_model_t* const super, void* const context)
1384
0
{
1385
0
  ccv_cnnp_model_index_select_t* const self = (ccv_cnnp_model_index_select_t*)super;
1386
0
  return ccv_cnnp_index_select(self->datatype, self->vocab_size, self->embed_size, self->super.name);
1387
0
}
1388
1389
// MARK - Pool Layers
1390
1391
typedef struct {
1392
  ccv_cnnp_model_t super;
1393
  ccv_nnc_tensor_symbol_t output;
1394
  float width_scale;
1395
  float height_scale;
1396
} ccv_cnnp_model_upsample_t;
1397
1398
static void _ccv_cnnp_upsample_build(ccv_cnnp_model_t* const super, ccv_nnc_symbolic_graph_t* const graph, const ccv_nnc_tensor_symbol_t* const inputs, const int input_size, ccv_nnc_tensor_symbol_t* const outputs, const int output_size)
1399
3
{
1400
3
  assert(input_size == 1);
1401
3
  assert(output_size == 1);
1402
3
  ccv_cnnp_model_upsample_t* const self = (ccv_cnnp_model_upsample_t*)super;
1403
3
  const ccv_nnc_tensor_param_t params = ccv_nnc_tensor_symbol_params(graph, inputs[0]);
1404
3
  ccv_nnc_cmd_t cmd = CMD_UPSAMPLE_BILINEAR_FORWARD(self->width_scale, self->height_scale);
1405
3
  ccv_nnc_tensor_param_t output_params;
1406
3
  ccv_nnc_hint_tensor_auto(cmd, &params, 1, ccv_nnc_no_hint, &output_params, 1);
1407
3
  const ccv_nnc_tensor_symbol_t output = ccv_nnc_tensor_symbol_new(graph, output_params, 0);
1408
3
  ccv_nnc_graph_exec_symbol_new(graph, cmd, TENSOR_SYMBOL_LIST(inputs[0]), TENSOR_SYMBOL_LIST(output), 0);
1409
3
  outputs[0] = output;
1410
3
}
1411
1412
static ccv_cnnp_model_t* _ccv_cnnp_upsample_copy(const ccv_cnnp_model_t* const super, void* const context);
1413
1414
static const ccv_cnnp_model_vtab_t ccv_cnnp_upsample_isa = {
1415
  .build = _ccv_cnnp_upsample_build,
1416
  .copy = _ccv_cnnp_upsample_copy,
1417
};
1418
1419
ccv_cnnp_model_t* ccv_cnnp_upsample(const float width_scale, const float height_scale, const char* const name)
1420
3
{
1421
3
  ccv_cnnp_model_upsample_t* const model_upsample = (ccv_cnnp_model_upsample_t*)cccalloc(1, sizeof(ccv_cnnp_model_upsample_t));
1422
3
  model_upsample->super.isa = &ccv_cnnp_upsample_isa;
1423
3
  model_upsample->super.input_size = 1;
1424
3
  model_upsample->super.outputs = &model_upsample->output;
1425
3
  model_upsample->super.output_size = 1;
1426
3
  ccv_cnnp_model_copy_name(&model_upsample->super, name);
1427
3
  model_upsample->width_scale = width_scale;
1428
3
  model_upsample->height_scale = height_scale;
1429
3
  return (ccv_cnnp_model_t*)model_upsample;
1430
3
}
1431
1432
static ccv_cnnp_model_t* _ccv_cnnp_upsample_copy(const ccv_cnnp_model_t* const super, void* const context)
1433
0
{
1434
0
  const ccv_cnnp_model_upsample_t* const self = (const ccv_cnnp_model_upsample_t*)super;
1435
0
  return ccv_cnnp_upsample(self->width_scale, self->height_scale, self->super.name);
1436
0
}
1437
1438
// MARK - Reduce Sum Layer
1439
1440
typedef struct {
1441
  ccv_cnnp_model_t super;
1442
  int axis[CCV_NNC_MAX_DIM_ALLOC];
1443
  int count;
1444
  ccv_nnc_tensor_symbol_t output;
1445
} ccv_cnnp_model_reduce_sum_t;
1446
1447
static void _ccv_cnnp_reduce_sum_build(ccv_cnnp_model_t* const super, ccv_nnc_symbolic_graph_t* const graph, const ccv_nnc_tensor_symbol_t* const inputs, const int input_size, ccv_nnc_tensor_symbol_t* const outputs, const int output_size)
1448
1
{
1449
1
  const ccv_cnnp_model_reduce_sum_t* const self = (const ccv_cnnp_model_reduce_sum_t*)super;
1450
1
  assert(input_size == 1);
1451
1
  assert(output_size == 1);
1452
1
  ccv_nnc_tensor_param_t input_params = ccv_nnc_tensor_symbol_params(graph, inputs[0]);
1453
1
  ccv_nnc_tensor_param_t output_params;
1454
1
  ccv_nnc_cmd_t reduce_sum = CMD_REDUCE_SUM_FORWARD();
1455
1
  int i;
1456
2
  for (i = 0; i < self->count; 
i++1
)
1457
1
    reduce_sum.info.reduce.axis[i] = self->axis[i];
1458
1
  reduce_sum.info.reduce.count = self->count;
1459
1
  ccv_nnc_hint_tensor_auto(reduce_sum, &input_params, 1, ccv_nnc_no_hint, &output_params, 1);
1460
1
  outputs[0] = ccv_nnc_tensor_symbol_new(graph, output_params, 0);
1461
1
  ccv_nnc_graph_exec_symbol_new(graph, reduce_sum, inputs, input_size, outputs, output_size, 0);
1462
1
}
1463
1464
static ccv_cnnp_model_t* _ccv_cnnp_reduce_sum_copy(const ccv_cnnp_model_t* const self, void* const context);
1465
1466
static const ccv_cnnp_model_vtab_t ccv_cnnp_reduce_sum_isa = {
1467
  .build = _ccv_cnnp_reduce_sum_build,
1468
  .copy = _ccv_cnnp_reduce_sum_copy,
1469
};
1470
1471
ccv_cnnp_model_t* ccv_cnnp_reduce_sum(const int* const axis, const int axis_count, const char* const name)
1472
1
{
1473
1
  ccv_cnnp_model_reduce_sum_t* const model_reduce_sum = (ccv_cnnp_model_reduce_sum_t*)cccalloc(1, sizeof(ccv_cnnp_model_reduce_sum_t));
1474
1
  model_reduce_sum->super.isa = &ccv_cnnp_reduce_sum_isa;
1475
1
  model_reduce_sum->super.input_size = 1;
1476
1
  model_reduce_sum->super.outputs = &model_reduce_sum->output;
1477
1
  model_reduce_sum->super.output_size = 1;
1478
1
  ccv_cnnp_model_copy_name(&model_reduce_sum->super, name);
1479
1
  assert(axis_count <= CCV_NNC_MAX_DIM_ALLOC);
1480
1
  int i;
1481
2
  for (i = 0; i < axis_count; 
i++1
)
1482
1
    model_reduce_sum->axis[i] = axis[i];
1483
1
  model_reduce_sum->count = axis_count;
1484
1
  return (ccv_cnnp_model_t*)model_reduce_sum;
1485
1
}
1486
1487
static ccv_cnnp_model_t* _ccv_cnnp_reduce_sum_copy(const ccv_cnnp_model_t* const super, void* const context)
1488
0
{
1489
0
  const ccv_cnnp_model_reduce_sum_t* const self = (const ccv_cnnp_model_reduce_sum_t*)super;
1490
0
  return ccv_cnnp_reduce_sum(self->axis, self->count, self->super.name);
1491
0
}
1492
1493
// MARK - Reduce Max Layer
1494
1495
typedef struct {
1496
  ccv_cnnp_model_t super;
1497
  int axis[CCV_NNC_MAX_DIM_ALLOC];
1498
  int count;
1499
  ccv_nnc_tensor_symbol_t output;
1500
} ccv_cnnp_model_reduce_max_t;
1501
1502
static void _ccv_cnnp_reduce_max_build(ccv_cnnp_model_t* const super, ccv_nnc_symbolic_graph_t* const graph, const ccv_nnc_tensor_symbol_t* const inputs, const int input_size, ccv_nnc_tensor_symbol_t* const outputs, const int output_size)
1503
1
{
1504
1
  const ccv_cnnp_model_reduce_sum_t* const self = (const ccv_cnnp_model_reduce_sum_t*)super;
1505
1
  assert(input_size == 1);
1506
1
  assert(output_size == 1);
1507
1
  ccv_nnc_tensor_param_t input_params = ccv_nnc_tensor_symbol_params(graph, inputs[0]);
1508
1
  ccv_nnc_tensor_param_t output_params;
1509
1
  ccv_nnc_cmd_t reduce_max = CMD_REDUCE_MAX_FORWARD();
1510
1
  int i;
1511
2
  for (i = 0; i < self->count; 
i++1
)
1512
1
    reduce_max.info.reduce.axis[i] = self->axis[i];
1513
1
  reduce_max.info.reduce.count = self->count;
1514
1
  ccv_nnc_hint_tensor_auto(reduce_max, &input_params, 1, ccv_nnc_no_hint, &output_params, 1);
1515
1
  outputs[0] = ccv_nnc_tensor_symbol_new(graph, output_params, 0);
1516
1
  ccv_nnc_graph_exec_symbol_new(graph, reduce_max, inputs, input_size, outputs, output_size, 0);
1517
1
}
1518
1519
static ccv_cnnp_model_t* _ccv_cnnp_reduce_max_copy(const ccv_cnnp_model_t* const self, void* const context);
1520
1521
static const ccv_cnnp_model_vtab_t ccv_cnnp_reduce_max_isa = {
1522
  .build = _ccv_cnnp_reduce_max_build,
1523
  .copy = _ccv_cnnp_reduce_max_copy,
1524
};
1525
1526
ccv_cnnp_model_t* ccv_cnnp_reduce_max(const int* const axis, const int axis_count, const char* const name)
1527
1
{
1528
1
  ccv_cnnp_model_reduce_max_t* const model_reduce_max = (ccv_cnnp_model_reduce_max_t*)cccalloc(1, sizeof(ccv_cnnp_model_reduce_max_t));
1529
1
  model_reduce_max->super.isa = &ccv_cnnp_reduce_max_isa;
1530
1
  model_reduce_max->super.input_size = 1;
1531
1
  model_reduce_max->super.outputs = &model_reduce_max->output;
1532
1
  model_reduce_max->super.output_size = 1;
1533
1
  ccv_cnnp_model_copy_name(&model_reduce_max->super, name);
1534
1
  assert(axis_count <= CCV_NNC_MAX_DIM_ALLOC);
1535
1
  int i;
1536
2
  for (i = 0; i < axis_count; 
i++1
)
1537
1
    model_reduce_max->axis[i] = axis[i];
1538
1
  model_reduce_max->count = axis_count;
1539
1
  return (ccv_cnnp_model_t*)model_reduce_max;
1540
1
}
1541
1542
static ccv_cnnp_model_t* _ccv_cnnp_reduce_max_copy(const ccv_cnnp_model_t* const super, void* const context)
1543
0
{
1544
0
  const ccv_cnnp_model_reduce_sum_t* const self = (const ccv_cnnp_model_reduce_sum_t*)super;
1545
0
  return ccv_cnnp_reduce_max(self->axis, self->count, self->super.name);
1546
0
}
1547
1548
// MARK - Min Layer
1549
1550
typedef struct {
1551
  ccv_cnnp_model_t super;
1552
  ccv_nnc_tensor_symbol_t output;
1553
} ccv_cnnp_model_min_t;
1554
1555
static void _ccv_cnnp_min_build(ccv_cnnp_model_t* const super, ccv_nnc_symbolic_graph_t* const graph, const ccv_nnc_tensor_symbol_t* const inputs, const int input_size, ccv_nnc_tensor_symbol_t* const outputs, const int output_size)
1556
1
{
1557
1
  assert(input_size == 2);
1558
1
  assert(output_size == 1);
1559
1
  ccv_nnc_tensor_param_t input_params[2];
1560
1
  int i;
1561
3
  for (i = 0; i < 2; 
i++2
)
1562
2
    input_params[i] = ccv_nnc_tensor_symbol_params(graph, inputs[i]);
1563
1
  ccv_nnc_tensor_param_t output_params;
1564
1
  const ccv_nnc_cmd_t min = CMD_MIN_FORWARD();
1565
1
  ccv_nnc_hint_tensor_auto(min, input_params, 2, ccv_nnc_no_hint, &output_params, 1);
1566
1
  outputs[0] = ccv_nnc_tensor_symbol_new(graph, output_params, 0);
1567
1
  ccv_nnc_graph_exec_symbol_new(graph, min, inputs, input_size, outputs, output_size, 0);
1568
1
}
1569
1570
static ccv_cnnp_model_t* _ccv_cnnp_min_copy(const ccv_cnnp_model_t* const self, void* const context);
1571
1572
static const ccv_cnnp_model_vtab_t ccv_cnnp_min_isa = {
1573
  .build = _ccv_cnnp_min_build,
1574
  .copy = _ccv_cnnp_min_copy,
1575
};
1576
1577
ccv_cnnp_model_t* ccv_cnnp_min(const char* const name)
1578
1
{
1579
1
  ccv_cnnp_model_min_t* const model_min = (ccv_cnnp_model_min_t*)cccalloc(1, sizeof(ccv_cnnp_model_min_t));
1580
1
  model_min->super.isa = &ccv_cnnp_min_isa;
1581
1
  model_min->super.input_size = 2;
1582
1
  model_min->super.outputs = &model_min->output;
1583
1
  model_min->super.output_size = 1;
1584
1
  ccv_cnnp_model_copy_name(&model_min->super, name);
1585
1
  return (ccv_cnnp_model_t*)model_min;
1586
1
}
1587
1588
static ccv_cnnp_model_t* _ccv_cnnp_min_copy(const ccv_cnnp_model_t* const super, void* const context)
1589
0
{
1590
0
  const ccv_cnnp_model_min_t* const self = (const ccv_cnnp_model_min_t*)super;
1591
0
  return ccv_cnnp_min(self->super.name);
1592
0
}
1593
1594
// MARK - Max Layer
1595
1596
typedef struct {
1597
  ccv_cnnp_model_t super;
1598
  ccv_nnc_tensor_symbol_t output;
1599
} ccv_cnnp_model_max_t;
1600
1601
static void _ccv_cnnp_max_build(ccv_cnnp_model_t* const super, ccv_nnc_symbolic_graph_t* const graph, const ccv_nnc_tensor_symbol_t* const inputs, const int input_size, ccv_nnc_tensor_symbol_t* const outputs, const int output_size)
1602
1
{
1603
1
  assert(input_size == 2);
1604
1
  assert(output_size == 1);
1605
1
  ccv_nnc_tensor_param_t input_params[2];
1606
1
  int i;
1607
3
  for (i = 0; i < 2; 
i++2
)
1608
2
    input_params[i] = ccv_nnc_tensor_symbol_params(graph, inputs[i]);
1609
1
  ccv_nnc_tensor_param_t output_params;
1610
1
  const ccv_nnc_cmd_t max = CMD_MAX_FORWARD();
1611
1
  ccv_nnc_hint_tensor_auto(max, input_params, 2, ccv_nnc_no_hint, &output_params, 1);
1612
1
  outputs[0] = ccv_nnc_tensor_symbol_new(graph, output_params, 0);
1613
1
  ccv_nnc_graph_exec_symbol_new(graph, max, inputs, input_size, outputs, output_size, 0);
1614
1
}
1615
1616
static ccv_cnnp_model_t* _ccv_cnnp_max_copy(const ccv_cnnp_model_t* const self, void* const context);
1617
1618
static const ccv_cnnp_model_vtab_t ccv_cnnp_max_isa = {
1619
  .build = _ccv_cnnp_max_build,
1620
  .copy = _ccv_cnnp_max_copy,
1621
};
1622
1623
ccv_cnnp_model_t* ccv_cnnp_max(const char* const name)
1624
1
{
1625
1
  ccv_cnnp_model_max_t* const model_max = (ccv_cnnp_model_max_t*)cccalloc(1, sizeof(ccv_cnnp_model_max_t));
1626
1
  model_max->super.isa = &ccv_cnnp_max_isa;
1627
1
  model_max->super.input_size = 2;
1628
1
  model_max->super.outputs = &model_max->output;
1629
1
  model_max->super.output_size = 1;
1630
1
  ccv_cnnp_model_copy_name(&model_max->super, name);
1631
1
  return (ccv_cnnp_model_t*)model_max;
1632
1
}
1633
1634
static ccv_cnnp_model_t* _ccv_cnnp_max_copy(const ccv_cnnp_model_t* const super, void* const context)
1635
0
{
1636
0
  const ccv_cnnp_model_max_t* const self = (const ccv_cnnp_model_max_t*)super;
1637
0
  return ccv_cnnp_max(self->super.name);
1638
0
}