Coverage Report

Created: 2022-07-27 23:53

/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 - Add-on Functions
8
9
static int _ccv_cnnp_model_clip_grad_norm_reduce_norm2(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
2
{
11
2
  const int device_id = CCV_TENSOR_GET_DEVICE_ID(inputs[0]->info.type);
12
2
  ccv_nnc_tensor_t* const old_norm2 = outputs[1 + device_id * 2];
13
2
  ccv_nnc_tensor_t* const norm2 = outputs[1 + device_id * 2 + 1];
14
2
  const int tensor_count = ccv_nnc_tensor_count(inputs[0]->info);
15
2
  if (tensor_count == 1)
16
2
    ccv_nnc_cmd_exec(CMD_MUL_FORWARD(1), hint, flags, TENSOR_LIST(inputs[0], inputs[0]), TENSOR_LIST(norm2), stream_context);
17
0
  else {
18
0
    ccv_nnc_cmd_exec(CMD_REDUCE_NORM2_FORWARD(), hint, flags, TENSOR_LIST(inputs[0]), TENSOR_LIST(norm2), stream_context);
19
0
    ccv_nnc_cmd_exec(CMD_MUL_FORWARD(1), hint, flags, TENSOR_LIST(norm2, norm2), TENSOR_LIST(norm2), stream_context);
20
0
  }
21
2
  ccv_nnc_cmd_exec(CMD_ADD_FORWARD(1, 1), hint, flags, TENSOR_LIST(old_norm2, norm2), TENSOR_LIST(old_norm2), stream_context);
22
2
  return CCV_NNC_EXEC_SUCCESS;
23
2
}
24
25
static ccv_nnc_cmd_vtab_t clip_grad_norm_reduce_norm2_vtab = {
26
  .exec = _ccv_cnnp_model_clip_grad_norm_reduce_norm2
27
};
28
29
static int _ccv_cnnp_model_clip_grad_norm_scatter_norm2(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)
30
2
{
31
2
  const int device_id = CCV_TENSOR_GET_DEVICE_ID(inputs[0]->info.type);
32
2
  ccv_nnc_tensor_t* const norm2 = inputs[1 + device_id * 2];
33
2
  ccv_nnc_cmd_exec(CMD_MUL_FORWARD(1), hint, flags, TENSOR_LIST(inputs[0], norm2), TENSOR_LIST(outputs[0]), stream_context);
34
2
  return CCV_NNC_EXEC_SUCCESS;
35
2
}
36
37
static ccv_nnc_cmd_vtab_t clip_grad_norm_scatter_norm2_vtab = {
38
  .exec = _ccv_cnnp_model_clip_grad_norm_scatter_norm2
39
};
40
41
void ccv_cnnp_model_parameters_clip_grad_norm(ccv_cnnp_model_t* const model, const ccv_cnnp_model_io_t parameters, int norm_type, float max_norm, ccv_nnc_stream_context_t* const stream_context)
42
2
{
43
2
  assert(norm_type == 2);
44
2
  ccv_cnnp_compiled_data_t* const compiled_data = model->compiled_data;
45
2
  assert(compiled_data);
46
2
  const int parallel_count = ccv_max(model->parallel_count, 1);
47
2
  ccv_nnc_tensor_t* norm2[parallel_count * 2];
48
2
  ccv_nnc_tensor_t* max_normt[parallel_count];
49
2
  const int stream_type = model->compiled_data->stream_type;
50
2
  int i;
51
2
  if (stream_type == CCV_STREAM_CONTEXT_GPU)
52
0
  {
53
0
    for (i = 0; i < parallel_count; i++)
54
0
    {
55
0
      ccv_nnc_tensor_param_t info = {
56
0
        .type = CCV_TENSOR_GPU_MEMORY,
57
0
        .format = CCV_TENSOR_FORMAT_NHWC,
58
0
        .datatype = CCV_32F,
59
0
        .dim = {1},
60
0
      };
61
0
      CCV_TENSOR_SET_DEVICE_ID(info.type, i);
62
0
      norm2[i * 2] = ccv_nnc_tensor_new(ccv_nnc_xpu_alloc(&compiled_data->xpu_alloc, i, stream_context, ccv_nnc_tensor_data_size(info)), info, 0);
63
0
      norm2[i * 2 + 1] = ccv_nnc_tensor_new(ccv_nnc_xpu_alloc(&compiled_data->xpu_alloc, i, stream_context, ccv_nnc_tensor_data_size(info)), info, 0);
64
0
      max_normt[i] = ccv_nnc_tensor_new(ccv_nnc_xpu_alloc(&compiled_data->xpu_alloc, i, stream_context, ccv_nnc_tensor_data_size(info)), info, 0);
65
0
    }
66
2
  } else {
67
4
    for (i = 0; i < parallel_count; 
i++2
)
68
2
    {
69
2
      ccv_nnc_tensor_param_t info = {
70
2
        .type = CCV_TENSOR_CPU_MEMORY,
71
2
        .format = CCV_TENSOR_FORMAT_NHWC,
72
2
        .datatype = CCV_32F,
73
2
        .dim = {1},
74
2
      };
75
2
      norm2[i * 2] = ccv_nnc_tensor_new(0, info, 0);
76
2
      norm2[i * 2 + 1] = ccv_nnc_tensor_new(0, info, 0);
77
2
      max_normt[i] = ccv_nnc_tensor_new(0, info, 0);
78
2
    }
79
2
  }
80
  // zero out old norm2.
81
2
  if (parallel_count > 1)
82
0
  {
83
0
    ccv_nnc_stream_context_t* streams[parallel_count];
84
0
    ccv_nnc_stream_signal_t* signal;
85
0
    if (stream_context)
86
0
      signal = ccv_nnc_stream_context_emit_signal_new(stream_context);
87
0
    for (i = 0; i < parallel_count; i++)
88
0
    {
89
0
      const int stream_type = CCV_TENSOR_GET_MEMORY(norm2[i * 2]->info.type) == CCV_TENSOR_GPU_MEMORY ? CCV_STREAM_CONTEXT_GPU : CCV_STREAM_CONTEXT_CPU;
90
0
      const int device_id = CCV_TENSOR_GET_DEVICE_ID(norm2[i * 2]->info.type);
91
0
      int type = stream_type;
92
0
      CCV_STREAM_SET_DEVICE_ID(type, device_id);
93
0
      ccv_nnc_stream_context_t* const stream_0 = ccv_cnnp_compiled_data_get_stream(compiled_data, type);
94
      // Wait signal to finish.
95
0
      if (stream_context)
96
0
        ccv_nnc_stream_context_wait_signal(stream_0, signal);
97
0
      ccv_nnc_cmd_exec(CMD_SET_FORWARD(0), ccv_nnc_no_hint, 0, 0, 0, TENSOR_LIST(norm2[i * 2]), stream_0);
98
0
      if (stream_context)
99
0
      {
100
0
        ccv_nnc_stream_signal_t* const signal = ccv_nnc_stream_context_emit_signal_new(stream_0);
101
0
        ccv_nnc_stream_context_wait_signal(stream_context, signal);
102
0
      }
103
0
      streams[i] = stream_0;
104
0
    }
105
    // If this should be blocking, blocking it.
106
0
    if (!stream_context)
107
0
      for (i = 0; i < parallel_count; i++)
108
0
        if (streams[i])
109
0
          ccv_nnc_stream_context_wait(streams[i]);
110
2
  } else {
111
2
    ccv_nnc_cmd_exec(CMD_SET_FORWARD(0), ccv_nnc_no_hint, 0, 0, 0, TENSOR_LIST(norm2[0]), stream_context);
112
2
  }
113
  // Gather norm2.
114
2
  ccv_nnc_cmd_t reduce_cmd = {
115
2
    .cmd = CCV_NNC_CUSTOM_FORWARD,
116
2
    .isa = &clip_grad_norm_reduce_norm2_vtab,
117
2
  };
118
2
  ccv_cnnp_model_parameter_gradients_map(model, parameters, reduce_cmd, ccv_nnc_no_hint, 0, 0, 0, norm2, parallel_count * 2, stream_context);
119
  // Now compute max(max_norm / norm2, 1.0).
120
2
  if (parallel_count > 1)
121
0
  {
122
0
    ccv_nnc_stream_context_t* streams[parallel_count];
123
0
    ccv_nnc_stream_signal_t* signal;
124
0
    if (stream_context)
125
0
      signal = ccv_nnc_stream_context_emit_signal_new(stream_context);
126
0
    for (i = 0; i < parallel_count; i++)
127
0
    {
128
0
      const int stream_type = CCV_TENSOR_GET_MEMORY(norm2[i * 2]->info.type) == CCV_TENSOR_GPU_MEMORY ? CCV_STREAM_CONTEXT_GPU : CCV_STREAM_CONTEXT_CPU;
129
0
      const int device_id = CCV_TENSOR_GET_DEVICE_ID(norm2[i * 2]->info.type);
130
0
      int type = stream_type;
131
0
      CCV_STREAM_SET_DEVICE_ID(type, device_id);
132
0
      ccv_nnc_stream_context_t* const stream_0 = ccv_cnnp_compiled_data_get_stream(compiled_data, type);
133
      // Wait signal to finish.
134
0
      if (stream_context)
135
0
        ccv_nnc_stream_context_wait_signal(stream_0, signal);
136
0
      ccv_nnc_cmd_exec(CMD_EWSQRT_FORWARD(), ccv_nnc_no_hint, 0, TENSOR_LIST(norm2[i * 2]), TENSOR_LIST(norm2[i * 2]), stream_0);
137
0
      ccv_nnc_cmd_exec(CMD_SET_FORWARD(max_norm), ccv_nnc_no_hint, 0, 0, 0, TENSOR_LIST(max_normt[i]), stream_0);
138
0
      ccv_nnc_cmd_exec(CMD_EWDIV_FORWARD(), ccv_nnc_no_hint, 0, TENSOR_LIST(max_normt[i], norm2[i * 2]), TENSOR_LIST(norm2[i * 2]), stream_0);
139
0
      ccv_nnc_cmd_exec(CMD_CLAMP_FORWARD(NAN, 1), ccv_nnc_no_hint, 0, TENSOR_LIST(norm2[i * 2]), TENSOR_LIST(norm2[i * 2]), stream_0);
140
0
      if (stream_context)
141
0
      {
142
0
        ccv_nnc_stream_signal_t* const signal = ccv_nnc_stream_context_emit_signal_new(stream_0);
143
0
        ccv_nnc_stream_context_wait_signal(stream_context, signal);
144
0
      }
145
0
      streams[i] = stream_0;
146
0
    }
147
    // If this should be blocking, blocking it.
148
0
    if (!stream_context)
149
0
      for (i = 0; i < parallel_count; i++)
150
0
        if (streams[i])
151
0
          ccv_nnc_stream_context_wait(streams[i]);
152
2
  } else {
153
2
    ccv_nnc_cmd_exec(CMD_EWSQRT_FORWARD(), ccv_nnc_no_hint, 0, TENSOR_LIST(norm2[0]), TENSOR_LIST(norm2[0]), stream_context);
154
2
    ccv_nnc_cmd_exec(CMD_SET_FORWARD(max_norm), ccv_nnc_no_hint, 0, 0, 0, TENSOR_LIST(max_normt[0]), stream_context);
155
2
    ccv_nnc_cmd_exec(CMD_EWDIV_FORWARD(), ccv_nnc_no_hint, 0, TENSOR_LIST(max_normt[0], norm2[0]), TENSOR_LIST(norm2[0]), stream_context);
156
2
    ccv_nnc_cmd_exec(CMD_CLAMP_FORWARD(NAN, 1), ccv_nnc_no_hint, 0, TENSOR_LIST(norm2[0]), TENSOR_LIST(norm2[0]), stream_context);
157
2
  }
158
2
  ccv_nnc_cmd_t scatter_cmd = {
159
2
    .cmd = CCV_NNC_CUSTOM_FORWARD,
160
2
    .isa = &clip_grad_norm_scatter_norm2_vtab,
161
2
  };
162
2
  ccv_cnnp_model_parameter_gradients_map(model, parameters, scatter_cmd, ccv_nnc_no_hint, 0, norm2, parallel_count * 2, 0, 0, stream_context);
163
4
  for (i = 0; i < parallel_count; 
i++2
)
164
2
  {
165
2
    ccv_nnc_tensor_free(norm2[i * 2]);
166
2
    ccv_nnc_tensor_free(norm2[i * 2 + 1]);
167
2
    ccv_nnc_tensor_free(max_normt[i]);
168
2
  }
169
2
}
170
171
// MARK - Core Layers
172
173
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)
174
42
{
175
42
  assert(output_size == 1);
176
42
  outputs[0] = ccv_nnc_tensor_symbol_new(graph, ccv_nnc_tensor_symbol_params(graph, inputs[0]), 0);
177
42
  ccv_nnc_graph_exec_symbol_new(graph, CMD_EWSUM_FORWARD(), inputs, input_size, outputs, output_size, 0);
178
42
}
179
180
static ccv_cnnp_model_t* _ccv_cnnp_sum_copy(const ccv_cnnp_model_t* const self, void* const context);
181
182
static const ccv_cnnp_model_vtab_t ccv_cnnp_sum_isa = {
183
  .build = _ccv_cnnp_sum_build,
184
  .copy = _ccv_cnnp_sum_copy,
185
};
186
187
typedef struct {
188
  ccv_cnnp_model_t super;
189
  ccv_nnc_tensor_symbol_t output;
190
} ccv_cnnp_model_sum_t;
191
192
ccv_cnnp_model_t* ccv_cnnp_sum(const char* const name)
193
45
{
194
45
  ccv_cnnp_model_sum_t* const model_sum = (ccv_cnnp_model_sum_t*)cccalloc(1, sizeof(ccv_cnnp_model_sum_t));
195
45
  model_sum->super.isa = &ccv_cnnp_sum_isa;
196
45
  model_sum->super.input_size = 0;
197
45
  model_sum->super.outputs = &model_sum->output;
198
45
  model_sum->super.output_size = 1;
199
45
  ccv_cnnp_model_copy_name(&model_sum->super, name);
200
45
  return (ccv_cnnp_model_t*)model_sum;
201
45
}
202
203
static ccv_cnnp_model_t* _ccv_cnnp_sum_copy(const ccv_cnnp_model_t* const self, void* const context)
204
3
{
205
3
  return ccv_cnnp_sum(self->name);
206
3
}
207
208
typedef struct {
209
  ccv_cnnp_model_t super;
210
  int axis;
211
  ccv_nnc_tensor_symbol_t output;
212
} ccv_cnnp_model_concat_t;
213
214
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)
215
4
{
216
4
  const ccv_cnnp_model_concat_t* const self = (const ccv_cnnp_model_concat_t*)super;
217
4
  assert(output_size == 1);
218
4
  ccv_nnc_tensor_param_t output_params = ccv_nnc_tensor_symbol_params(graph, inputs[0]);
219
4
  const int nd = ccv_nnc_tensor_nd(output_params.dim);
220
4
  const int axis = self->axis;
221
4
  assert(axis < nd);
222
4
  output_params.dim[axis] = 0;
223
4
  int i, j;
224
12
  for (i = 0; i < input_size; 
i++8
)
225
8
  {
226
8
    const ccv_nnc_tensor_param_t input_params = ccv_nnc_tensor_symbol_params(graph, inputs[i]);
227
8
    const int input_nd = ccv_nnc_tensor_nd(input_params.dim);
228
8
    assert(input_nd == nd);
229
16
    
for (j = 0; 8
j < nd;
j++8
)
230
8
      if (j != axis)
231
0
        { assert(input_params.dim[j] == output_params.dim[j]); }
232
8
    output_params.dim[axis] += input_params.dim[axis];
233
8
  }
234
4
  outputs[0] = ccv_nnc_tensor_symbol_new(graph, output_params, 0);
235
4
  int ofs[CCV_NNC_MAX_DIM_ALLOC] = {};
236
4
  ccv_nnc_tensor_symbol_t aliases[input_size];
237
12
  for (i = 0; i < input_size; 
i++8
)
238
8
  {
239
8
    const ccv_nnc_tensor_param_t input_params = ccv_nnc_tensor_symbol_params(graph, inputs[i]);
240
8
    aliases[i] = ccv_nnc_tensor_symbol_alias_new(graph, outputs[0], ofs, output_params.dim, input_params, 0);
241
8
    ofs[axis] += input_params.dim[axis];
242
8
  }
243
  // Format transform is more flexible.
244
4
  ccv_nnc_graph_exec_symbol_new(graph, CMD_FORMAT_TRANSFORM_FORWARD(), inputs, input_size, aliases, input_size, 0);
245
4
}
246
247
static ccv_cnnp_model_t* _ccv_cnnp_concat_copy(const ccv_cnnp_model_t* const self, void* const context);
248
249
static const ccv_cnnp_model_vtab_t ccv_cnnp_concat_isa = {
250
  .build = _ccv_cnnp_concat_build,
251
  .copy = _ccv_cnnp_concat_copy,
252
};
253
254
ccv_cnnp_model_t* ccv_cnnp_concat(const int axis, const char* const name)
255
4
{
256
4
  ccv_cnnp_model_concat_t* const model_concat = (ccv_cnnp_model_concat_t*)cccalloc(1, sizeof(ccv_cnnp_model_concat_t));
257
4
  model_concat->super.isa = &ccv_cnnp_concat_isa;
258
4
  model_concat->super.input_size = 0;
259
4
  model_concat->super.outputs = &model_concat->output;
260
4
  model_concat->super.output_size = 1;
261
4
  model_concat->axis = axis;
262
4
  ccv_cnnp_model_copy_name(&model_concat->super, name);
263
4
  return (ccv_cnnp_model_t*)model_concat;
264
4
}
265
266
static ccv_cnnp_model_t* _ccv_cnnp_concat_copy(const ccv_cnnp_model_t* const super, void* const context)
267
0
{
268
0
  const ccv_cnnp_model_concat_t* const self = (const ccv_cnnp_model_concat_t*)super;
269
0
  return ccv_cnnp_concat(self->axis, self->super.name);
270
0
}
271
272
typedef struct {
273
  ccv_cnnp_model_t super;
274
  ccv_nnc_tensor_symbol_t output;
275
  int dim[CCV_NNC_MAX_DIM_ALLOC];
276
  int ofs[CCV_NNC_MAX_DIM_ALLOC];
277
  int inc[CCV_NNC_MAX_DIM_ALLOC];
278
} ccv_cnnp_model_reshape_t;
279
280
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)
281
1.09k
{
282
1.09k
  assert(input_size == 1);
283
1.09k
  assert(output_size == 1);
284
1.09k
  ccv_cnnp_model_reshape_t* const self = (ccv_cnnp_model_reshape_t*)super;
285
1.09k
  ccv_nnc_tensor_param_t params = ccv_nnc_tensor_symbol_params(graph, inputs[0]);
286
1.09k
  assert(ccv_nnc_dimension_count(self->dim) <= ccv_nnc_tensor_count(params));
287
1.09k
  memcpy(params.dim, self->dim, sizeof(params.dim));
288
1.09k
  outputs[0] = ccv_nnc_tensor_symbol_alias_new(graph, inputs[0], self->ofs, self->inc, params, 0);
289
1.09k
}
290
291
static ccv_cnnp_model_t* _ccv_cnnp_reshape_copy(const ccv_cnnp_model_t* const super, void* const context);
292
293
static const ccv_cnnp_model_vtab_t ccv_cnnp_reshape_isa = {
294
  .build = _ccv_cnnp_reshape_build,
295
  .copy = _ccv_cnnp_reshape_copy,
296
};
297
298
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)
299
1.09k
{
300
1.09k
  ccv_cnnp_model_reshape_t* const model_reshape = (ccv_cnnp_model_reshape_t*)cccalloc(1, sizeof(ccv_cnnp_model_reshape_t));
301
1.09k
  model_reshape->super.isa = &ccv_cnnp_reshape_isa;
302
1.09k
  model_reshape->super.input_size = 1;
303
1.09k
  model_reshape->super.outputs = &model_reshape->output;
304
1.09k
  model_reshape->super.output_size = 1;
305
1.09k
  ccv_cnnp_model_copy_name(&model_reshape->super, name);
306
1.09k
  memcpy(model_reshape->dim, dim, sizeof(model_reshape->dim));
307
1.09k
  memcpy(model_reshape->ofs, ofs, sizeof(model_reshape->ofs));
308
1.09k
  int i, flag = 0;
309
3.19k
  for (i = 0; !flag && 
i < 2.19k
CCV_NNC_MAX_DIM_ALLOC2.19k
;
i++2.10k
)
310
2.10k
    flag = (inc[i] != 0);
311
1.09k
  memcpy(model_reshape->inc, flag ? 
inc1.00k
:
dim92
, sizeof(model_reshape->inc));
312
1.09k
  return (ccv_cnnp_model_t*)model_reshape;
313
1.09k
}
314
315
static ccv_cnnp_model_t* _ccv_cnnp_reshape_copy(const ccv_cnnp_model_t* const super, void* const context)
316
1.00k
{
317
1.00k
  const ccv_cnnp_model_reshape_t* const self = (const ccv_cnnp_model_reshape_t*)super;
318
1.00k
  return ccv_cnnp_reshape(self->dim, self->ofs, self->inc, self->super.name);
319
1.00k
}
320
321
typedef struct {
322
  ccv_cnnp_model_t super;
323
  ccv_nnc_tensor_symbol_t output;
324
} ccv_cnnp_model_flatten_t;
325
326
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)
327
14
{
328
14
  assert(input_size == 1);
329
14
  assert(output_size == 1);
330
14
  const ccv_nnc_tensor_param_t params = ccv_nnc_tensor_symbol_params(graph, inputs[0]);
331
14
  ccv_nnc_tensor_param_t output_params = params;
332
14
  memset(output_params.dim, 0, sizeof(output_params.dim));
333
14
  output_params.dim[0] = ccv_nnc_tensor_get_n(params);
334
14
  assert(output_params.dim[0] > 0);
335
14
  output_params.dim[1] = ccv_nnc_tensor_count(params) / output_params.dim[0];
336
14
  outputs[0] = ccv_nnc_tensor_symbol_alias_new(graph, inputs[0], DIM_ALLOC(), output_params.dim, output_params, 0);
337
14
}
338
339
static ccv_cnnp_model_t* _ccv_cnnp_flatten_copy(const ccv_cnnp_model_t* const self, void* const context);
340
341
static const ccv_cnnp_model_vtab_t ccv_cnnp_flatten_isa = {
342
  .build = _ccv_cnnp_flatten_build,
343
  .copy = _ccv_cnnp_flatten_copy,
344
};
345
346
ccv_cnnp_model_t* ccv_cnnp_flatten(const char* const name)
347
16
{
348
16
  ccv_cnnp_model_flatten_t* const model_flatten = (ccv_cnnp_model_flatten_t*)cccalloc(1, sizeof(ccv_cnnp_model_flatten_t));
349
16
  model_flatten->super.isa = &ccv_cnnp_flatten_isa;
350
16
  model_flatten->super.input_size = 1;
351
16
  model_flatten->super.outputs = &model_flatten->output;
352
16
  model_flatten->super.output_size = 1;
353
16
  ccv_cnnp_model_copy_name(&model_flatten->super, name);
354
16
  return (ccv_cnnp_model_t*)model_flatten;
355
16
}
356
357
static ccv_cnnp_model_t* _ccv_cnnp_flatten_copy(const ccv_cnnp_model_t* const self, void* const context)
358
2
{
359
2
  return ccv_cnnp_flatten(self->name);
360
2
}
361
362
// MARK - Batch Norm Layer
363
364
typedef struct {
365
  ccv_cnnp_model_t super;
366
  ccv_nnc_tensor_symbol_t output;
367
  ccv_nnc_tensor_symbol_t bias;
368
  ccv_nnc_tensor_symbol_t scale;
369
  ccv_nnc_graph_exec_symbol_t batch_norm;
370
  ccv_nnc_cmd_param_t params;
371
  ccv_array_t* zero_inits;
372
  ccv_array_t* retainables;
373
} ccv_cnnp_model_batch_norm_t;
374
375
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)
376
75
{
377
75
  assert(input_size == 1);
378
75
  assert(output_size == 1);
379
75
  ccv_cnnp_model_batch_norm_t* const self = (ccv_cnnp_model_batch_norm_t*)super;
380
75
  const ccv_nnc_tensor_param_t params = ccv_nnc_tensor_symbol_params(graph, inputs[0]);
381
75
  const int nd = ccv_nnc_tensor_nd(params.dim);
382
75
  ccv_nnc_tensor_param_t bias_params = params;
383
75
  memset(bias_params.dim, 0, sizeof(bias_params.dim));
384
  // If the accuracy is not enough, bump it to 32-bit floating point.
385
75
  if (bias_params.datatype != CCV_32F && 
bias_params.datatype != CCV_64F16
)
386
16
    bias_params.datatype = CCV_32F;
387
75
  bias_params.dim[0] = nd > 1 ? ccv_nnc_tensor_get_c(params) : 
params.dim[0]0
;
388
75
  const ccv_nnc_tensor_symbol_t output = ccv_nnc_tensor_symbol_new(graph, params, 0);
389
  // Both scale and bias are shared between if this model is reused.
390
75
  if (!self->scale.graph)
391
75
    self->scale = ccv_nnc_tensor_symbol_new(graph, bias_params, 0);
392
75
  if (!self->bias.graph)
393
75
    self->bias = ccv_nnc_tensor_symbol_new(graph, bias_params, 0);
394
75
  const ccv_nnc_tensor_symbol_t mean = ccv_nnc_tensor_symbol_new(graph, bias_params, 0);
395
75
  const ccv_nnc_tensor_symbol_t var = ccv_nnc_tensor_symbol_new(graph, bias_params, 0);
396
  // Otherwise, notice mean, var, saved_mean, saved_inv_std are not reused.
397
75
  if (!self->zero_inits)
398
75
    self->zero_inits = ccv_array_new(sizeof(ccv_nnc_tensor_symbol_t), 0, 0);
399
75
  ccv_array_push(self->zero_inits, &mean);
400
75
  ccv_array_push(self->zero_inits, &var);
401
75
  const ccv_nnc_tensor_symbol_t out_mean = ccv_nnc_tensor_symbol_new(graph, bias_params, 0);
402
75
  const ccv_nnc_tensor_symbol_t out_var = ccv_nnc_tensor_symbol_new(graph, bias_params, 0);
403
75
  if (!self->retainables)
404
75
    self->retainables = ccv_array_new(sizeof(ccv_nnc_tensor_symbol_t), 0, 0);
405
75
  ccv_array_push(self->retainables, &out_mean);
406
75
  ccv_array_push(self->retainables, &out_var);
407
75
  const ccv_nnc_tensor_symbol_t saved_mean = ccv_nnc_tensor_symbol_new(graph, bias_params, 0);
408
75
  const ccv_nnc_tensor_symbol_t saved_inv_std = ccv_nnc_tensor_symbol_new(graph, bias_params, 0);
409
75
  const int hw = ccv_nnc_tensor_hw(params, ccv_nnc_tensor_nd(params.dim));
410
75
  ccv_nnc_cmd_param_t batch_norm = self->params;
411
75
  batch_norm.bnorm.count = hw >= 0 ? CCV_NNC_MAX_DIM + 1 : 
10
;
412
75
  int i;
413
75
  batch_norm.bnorm.axis[0] = (params.format == CCV_TENSOR_FORMAT_CHWN) ? 
30
: 0;
414
75
  if (hw >= 0)
415
225
    
for (i = 0; 75
i < CCV_NNC_MAX_DIM;
i++150
)
416
150
      batch_norm.bnorm.axis[i + 1] = i + hw;
417
75
  self->params = batch_norm;
418
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);
419
75
  outputs[0] = output;
420
75
}
421
422
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)
423
24
{
424
24
  ccv_cnnp_model_batch_norm_t* const self = (ccv_cnnp_model_batch_norm_t*)super;
425
24
  if (self->bias.graph)
426
24
    initializer(context, CMD_SET_FORWARD(0), ccv_nnc_no_hint, 0, 0, self->bias);
427
24
  if (self->scale.graph)
428
24
    initializer(context, CMD_RANDOM_UNIFORM_FORWARD(0, 1), ccv_nnc_no_hint, 0, 0, self->scale);
429
24
  int i;
430
24
  if (self->zero_inits)
431
72
    
for (i = 0; 24
i < self->zero_inits->rnum;
i++48
)
432
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));
433
24
}
434
435
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)
436
75
{
437
75
  ccv_cnnp_model_batch_norm_t* const self = (ccv_cnnp_model_batch_norm_t*)super;
438
75
  if (self->bias.graph)
439
75
    add_to_array(parameters, self->bias);
440
75
  if (self->scale.graph)
441
75
    add_to_array(parameters, self->scale);
442
75
}
443
444
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)
445
75
{
446
75
  ccv_cnnp_model_batch_norm_t* const self = (ccv_cnnp_model_batch_norm_t*)super;
447
75
  int i;
448
75
  if (self->retainables)
449
225
    
for (i = 0; 75
i < self->retainables->rnum;
i++150
)
450
150
    {
451
150
      const ccv_nnc_tensor_symbol_t symbol = *(ccv_nnc_tensor_symbol_t*)ccv_array_get(self->retainables, i);
452
150
      add_to_array(outputs, symbol);
453
150
    }
454
75
}
455
456
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)
457
32
{
458
32
  ccv_cnnp_model_batch_norm_t* const self = (ccv_cnnp_model_batch_norm_t*)super;
459
32
  if (self->batch_norm.graph)
460
32
  {
461
32
    self->params.bnorm.is_test = is_test;
462
32
    updater(context, self->batch_norm, ccv_nnc_cmd(CCV_NNC_BATCH_NORM_FORWARD, 0, self->params, 0), ccv_nnc_no_hint);
463
32
  }
464
32
}
465
466
static void _ccv_cnnp_batch_norm_deinit(ccv_cnnp_model_t* const super)
467
83
{
468
83
  ccv_cnnp_model_batch_norm_t* const self = (ccv_cnnp_model_batch_norm_t*)super;
469
83
  if (self->zero_inits)
470
75
    ccv_array_free(self->zero_inits);
471
83
  if (self->retainables)
472
75
    ccv_array_free(self->retainables);
473
83
}
474
475
static ccv_cnnp_model_t* _ccv_cnnp_batch_norm_copy(const ccv_cnnp_model_t* const super, void* const context);
476
477
static const ccv_cnnp_model_vtab_t ccv_cnnp_batch_norm_isa = {
478
  .build = _ccv_cnnp_batch_norm_build,
479
  .init_states = _ccv_cnnp_batch_norm_init_states,
480
  .add_to_parameter = _ccv_cnnp_batch_norm_add_to_parameter,
481
  .add_to_output = _ccv_cnnp_batch_norm_add_to_output,
482
  .copy = _ccv_cnnp_batch_norm_copy,
483
  .set_is_test = _ccv_cnnp_batch_norm_set_is_test,
484
  .deinit = _ccv_cnnp_batch_norm_deinit,
485
};
486
487
ccv_cnnp_model_t* ccv_cnnp_batch_norm(const float momentum, const float epsilon, const char* const name)
488
83
{
489
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));
490
83
  model_batch_norm->super.isa = &ccv_cnnp_batch_norm_isa;
491
83
  model_batch_norm->super.input_size = 1;
492
83
  model_batch_norm->super.outputs = &model_batch_norm->output;
493
83
  model_batch_norm->super.output_size = 1;
494
83
  ccv_cnnp_model_copy_name(&model_batch_norm->super, name);
495
83
  model_batch_norm->scale.d = CCV_NNC_NO_TENSOR_SYMBOL;
496
83
  model_batch_norm->scale.graph = 0;
497
83
  model_batch_norm->bias.d = CCV_NNC_NO_TENSOR_SYMBOL;
498
83
  model_batch_norm->bias.graph = 0;
499
83
  model_batch_norm->params.bnorm.momentum = momentum;
500
83
  model_batch_norm->params.bnorm.epsilon = epsilon;
501
83
  return (ccv_cnnp_model_t*)model_batch_norm;
502
83
}
503
504
static ccv_cnnp_model_t* _ccv_cnnp_batch_norm_copy(const ccv_cnnp_model_t* const super, void* const context)
505
8
{
506
8
  const ccv_cnnp_model_batch_norm_t* const self = (const ccv_cnnp_model_batch_norm_t*)super;
507
8
  return ccv_cnnp_batch_norm(self->params.bnorm.momentum, self->params.bnorm.epsilon, self->super.name);
508
8
}
509
510
// MARK - Convolution Layer
511
512
typedef struct {
513
  ccv_cnnp_model_t super;
514
  ccv_nnc_tensor_symbol_t output;
515
  ccv_nnc_tensor_symbol_t weights;
516
  ccv_nnc_tensor_symbol_t bias;
517
  int groups;
518
  int filters;
519
  int kdim[CCV_NNC_MAX_DIM_ALLOC];
520
  int no_bias;
521
  ccv_nnc_hint_t hint;
522
} ccv_cnnp_model_convolution_t;
523
524
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)
525
111
{
526
111
  assert(input_size == 1);
527
111
  assert(output_size == 1);
528
111
  ccv_cnnp_model_convolution_t* const self = (ccv_cnnp_model_convolution_t*)super;
529
111
  const ccv_nnc_tensor_param_t params = ccv_nnc_tensor_symbol_params(graph, inputs[0]);
530
111
  int i;
531
111
  const int nd = CCV_NNC_MAX_DIM + 2;
532
111
  ccv_nnc_tensor_param_t weights_params = params;
533
111
  ccv_nnc_tensor_set_n(&weights_params, self->filters);
534
111
  assert(ccv_nnc_tensor_get_c(params) % self->groups == 0);
535
111
  ccv_nnc_tensor_set_c(&weights_params, nd, ccv_nnc_tensor_get_c(params) / self->groups);
536
111
  const int hw = ccv_nnc_tensor_hw(weights_params, nd);
537
111
  assert(hw >= 0);
538
333
  
for (i = 0; 111
i < CCV_NNC_MAX_DIM;
i++222
)
539
222
    weights_params.dim[i + hw] = self->kdim[i];
540
111
  if (!self->weights.graph)
541
107
    self->weights = ccv_nnc_tensor_symbol_new(graph, weights_params, 0);
542
111
  assert(self->weights.graph == graph);
543
111
  ccv_nnc_tensor_param_t bias_params = params;
544
111
  memset(bias_params.dim, 0, sizeof(bias_params.dim));
545
111
  bias_params.dim[0] = self->filters;
546
111
  ccv_nnc_cmd_t cmd = CMD_CONVOLUTION_FORWARD(self->groups, self->filters);
547
333
  for (i = 0; i < CCV_NNC_MAX_DIM; 
i++222
)
548
222
    cmd.info.size.dim[i] = self->kdim[i];
549
111
  ccv_nnc_tensor_param_t output_params;
550
111
  ccv_nnc_hint_tensor_auto(cmd, (ccv_nnc_tensor_param_t []){
551
111
      params,
552
111
      weights_params,
553
111
      bias_params,
554
111
    }, 3, self->hint, &output_params, 1);
555
111
  const ccv_nnc_tensor_symbol_t output = ccv_nnc_tensor_symbol_new(graph, output_params, 0);
556
111
  ccv_nnc_graph_exec_symbol_t convolution;
557
111
  if (self->no_bias)
558
10
    convolution = ccv_nnc_graph_exec_symbol_new(graph, cmd, TENSOR_SYMBOL_LIST(inputs[0], self->weights), TENSOR_SYMBOL_LIST(output), 0);
559
101
  else {
560
101
    if (!self->bias.graph)
561
97
      self->bias = ccv_nnc_tensor_symbol_new(graph, bias_params, 0);
562
101
    convolution = ccv_nnc_graph_exec_symbol_new(graph, cmd, TENSOR_SYMBOL_LIST(inputs[0], self->weights, self->bias), TENSOR_SYMBOL_LIST(output), 0);
563
101
  }
564
111
  ccv_nnc_graph_exec_symbol_set_hint(graph, convolution, self->hint);
565
111
  outputs[0] = output;
566
111
}
567
568
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)
569
33
{
570
33
  ccv_cnnp_model_convolution_t* const self = (ccv_cnnp_model_convolution_t*)super;
571
33
  const ccv_nnc_tensor_param_t weight_params = ccv_nnc_tensor_symbol_params(graph, self->weights);
572
33
  const int n = ccv_max(ccv_nnc_tensor_get_n(weight_params), 1);
573
33
  const int count = ccv_nnc_tensor_count(weight_params);
574
33
  const float std = sqrtf(2) / sqrtf(count / n);
575
33
  const float bound = sqrtf(3) * std;
576
33
  initializer(context, CMD_RANDOM_UNIFORM_FORWARD(-bound, bound), ccv_nnc_no_hint, 0, 0, self->weights);
577
33
  if (self->bias.graph)
578
33
    initializer(context, CMD_SET_FORWARD(0), ccv_nnc_no_hint, 0, 0, self->bias);
579
33
}
580
581
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)
582
111
{
583
111
  ccv_cnnp_model_convolution_t* const self = (ccv_cnnp_model_convolution_t*)super;
584
111
  add_to_array(parameters, self->weights);
585
111
  if (self->bias.graph)
586
101
    add_to_array(parameters, self->bias);
587
111
}
588
589
static ccv_cnnp_model_t* _ccv_cnnp_convolution_copy(const ccv_cnnp_model_t* const super, void* const context);
590
591
static const ccv_cnnp_model_vtab_t ccv_cnnp_convolution_isa = {
592
  .build = _ccv_cnnp_convolution_build,
593
  .init_states = _ccv_cnnp_convolution_init_states,
594
  .add_to_parameter = _ccv_cnnp_convolution_add_to_parameter,
595
  .copy = _ccv_cnnp_convolution_copy,
596
};
597
598
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)
599
123
{
600
123
  ccv_cnnp_model_convolution_t* const model_convolution = (ccv_cnnp_model_convolution_t*)cccalloc(1, sizeof(ccv_cnnp_model_convolution_t));
601
123
  model_convolution->super.isa = &ccv_cnnp_convolution_isa;
602
123
  model_convolution->super.input_size = 1;
603
123
  model_convolution->super.outputs = &model_convolution->output;
604
123
  model_convolution->super.output_size = 1;
605
123
  ccv_cnnp_model_copy_name(&model_convolution->super, name);
606
123
  model_convolution->weights.d = CCV_NNC_NO_TENSOR_SYMBOL;
607
123
  model_convolution->weights.graph = 0;
608
123
  model_convolution->bias.d = CCV_NNC_NO_TENSOR_SYMBOL;
609
123
  model_convolution->bias.graph = 0;
610
123
  model_convolution->groups = groups;
611
123
  model_convolution->filters = filters;
612
123
  memcpy(model_convolution->kdim, kdim, sizeof(model_convolution->kdim));
613
123
  model_convolution->no_bias = no_bias;
614
123
  model_convolution->hint = hint;
615
123
  return (ccv_cnnp_model_t*)model_convolution;
616
123
}
617
618
static ccv_cnnp_model_t* _ccv_cnnp_convolution_copy(const ccv_cnnp_model_t* const super, void* const context)
619
16
{
620
16
  ccv_cnnp_model_convolution_t* const self = (ccv_cnnp_model_convolution_t*)super;
621
16
  return ccv_cnnp_convolution(self->groups, self->filters, self->kdim, self->no_bias, self->hint, self->super.name);
622
16
}
623
624
// MARK - Dense Layer
625
626
typedef struct {
627
  ccv_cnnp_model_t super;
628
  ccv_nnc_tensor_symbol_t output;
629
  ccv_nnc_tensor_symbol_t weights;
630
  ccv_nnc_tensor_symbol_t bias;
631
  int count;
632
  int no_bias;
633
} ccv_cnnp_model_dense_t;
634
635
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)
636
2.29k
{
637
2.29k
  assert(input_size == 1);
638
2.29k
  assert(output_size == 1);
639
2.29k
  ccv_cnnp_model_dense_t* const self = (ccv_cnnp_model_dense_t*)super;
640
2.29k
  const ccv_nnc_tensor_param_t params = ccv_nnc_tensor_symbol_params(graph, inputs[0]);
641
2.29k
  ccv_nnc_tensor_param_t weights_params = params;
642
2.29k
  memset(weights_params.dim, 0, sizeof(weights_params.dim));
643
2.29k
  weights_params.dim[0] = self->count;
644
2.29k
  weights_params.dim[1] = params.dim[ccv_nnc_tensor_nd(params.dim) - 1];
645
2.29k
  if (!self->weights.graph)
646
2.29k
    self->weights = ccv_nnc_tensor_symbol_new(graph, weights_params, 0);
647
2.29k
  assert(self->weights.graph == graph);
648
2.29k
  ccv_nnc_tensor_param_t bias_params = params;
649
2.29k
  memset(bias_params.dim, 0, sizeof(bias_params.dim));
650
2.29k
  bias_params.dim[0] = self->count;
651
2.29k
  const ccv_nnc_cmd_t cmd = CMD_GEMM_FORWARD(NO_TRANSPOSE, TRANSPOSE(0, 1));
652
2.29k
  ccv_nnc_tensor_param_t output_params;
653
2.29k
  ccv_nnc_hint_tensor_auto(cmd, (ccv_nnc_tensor_param_t []){
654
2.29k
      params,
655
2.29k
      weights_params,
656
2.29k
      bias_params,
657
2.29k
    }, 3, ccv_nnc_no_hint, &output_params, 1);
658
2.29k
  const ccv_nnc_tensor_symbol_t output = ccv_nnc_tensor_symbol_new(graph, output_params, 0);
659
2.29k
  if (self->no_bias)
660
2.04k
    ccv_nnc_graph_exec_symbol_new(graph, cmd, TENSOR_SYMBOL_LIST(inputs[0], self->weights), TENSOR_SYMBOL_LIST(output), 0);
661
256
  else {
662
256
    if (!self->bias.graph)
663
253
      self->bias = ccv_nnc_tensor_symbol_new(graph, bias_params, 0);
664
256
    ccv_nnc_graph_exec_symbol_new(graph, cmd, TENSOR_SYMBOL_LIST(inputs[0], self->weights, self->bias), TENSOR_SYMBOL_LIST(output), 0);
665
256
  }
666
2.29k
  outputs[0] = output;
667
2.29k
}
668
669
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)
670
57
{
671
57
  ccv_cnnp_model_dense_t* const self = (ccv_cnnp_model_dense_t*)super;
672
57
  const ccv_nnc_tensor_param_t weight_params = ccv_nnc_tensor_symbol_params(graph, self->weights);
673
57
  const int c = weight_params.dim[1];
674
57
  const float std = sqrtf(2) / sqrtf(c);
675
57
  const float bound = sqrtf(3) * std;
676
57
  initializer(context, CMD_RANDOM_UNIFORM_FORWARD(-bound, bound), ccv_nnc_no_hint, 0, 0, self->weights);
677
57
  if (self->bias.graph)
678
33
    initializer(context, CMD_SET_FORWARD(0), ccv_nnc_no_hint, 0, 0, self->bias);
679
57
}
680
681
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)
682
2.29k
{
683
2.29k
  ccv_cnnp_model_dense_t* const self = (ccv_cnnp_model_dense_t*)super;
684
2.29k
  add_to_array(parameters, self->weights);
685
2.29k
  if (self->bias.graph)
686
256
    add_to_array(parameters, self->bias);
687
2.29k
}
688
689
static ccv_cnnp_model_t* _ccv_cnnp_dense_copy(const ccv_cnnp_model_t* const super, void* const context);
690
691
static const ccv_cnnp_model_vtab_t ccv_cnnp_dense_isa = {
692
  .build = _ccv_cnnp_dense_build,
693
  .init_states = _ccv_cnnp_dense_init_states,
694
  .add_to_parameter = _ccv_cnnp_dense_add_to_parameter,
695
  .copy = _ccv_cnnp_dense_copy,
696
};
697
698
ccv_cnnp_model_t* ccv_cnnp_dense(const int count, const int no_bias, const char* const name)
699
2.29k
{
700
2.29k
  ccv_cnnp_model_dense_t* const model_dense = (ccv_cnnp_model_dense_t*)cccalloc(1, sizeof(ccv_cnnp_model_dense_t));
701
2.29k
  model_dense->super.isa = &ccv_cnnp_dense_isa;
702
2.29k
  model_dense->super.input_size = 1;
703
2.29k
  model_dense->super.outputs = &model_dense->output;
704
2.29k
  model_dense->super.output_size = 1;
705
2.29k
  ccv_cnnp_model_copy_name(&model_dense->super, name);
706
2.29k
  model_dense->weights.d = CCV_NNC_NO_TENSOR_SYMBOL;
707
2.29k
  model_dense->weights.graph = 0;
708
2.29k
  model_dense->bias.d = CCV_NNC_NO_TENSOR_SYMBOL;
709
2.29k
  model_dense->bias.graph = 0;
710
2.29k
  model_dense->count = count;
711
2.29k
  model_dense->no_bias = no_bias;
712
2.29k
  return (ccv_cnnp_model_t*)model_dense;
713
2.29k
}
714
715
static ccv_cnnp_model_t* _ccv_cnnp_dense_copy(const ccv_cnnp_model_t* const super, void* const context)
716
2.20k
{
717
2.20k
  const ccv_cnnp_model_dense_t* const self = (const ccv_cnnp_model_dense_t*)super;
718
2.20k
  return ccv_cnnp_dense(self->count, self->no_bias, self->super.name);
719
2.20k
}
720
721
// MARK - Pool Layers
722
723
typedef struct {
724
  ccv_cnnp_model_t super;
725
  ccv_nnc_tensor_symbol_t output;
726
  int kdim[CCV_NNC_MAX_DIM_ALLOC];
727
  ccv_nnc_hint_t hint;
728
} ccv_cnnp_model_pool_t;
729
730
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)
731
18
{
732
18
  assert(input_size == 1);
733
18
  assert(output_size == 1);
734
18
  ccv_cnnp_model_pool_t* const self = (ccv_cnnp_model_pool_t*)super;
735
18
  const ccv_nnc_tensor_param_t params = ccv_nnc_tensor_symbol_params(graph, inputs[0]);
736
18
  const int hw = ccv_nnc_tensor_hw(params, ccv_nnc_tensor_nd(params.dim));
737
18
  ccv_nnc_cmd_t cmd;
738
18
  if (hw >= 0 && self->kdim[0] == 0 && 
self->kdim[1] == 03
)
739
3
    cmd = CMD_MAX_POOL_FORWARD(params.dim[hw], params.dim[hw + 1]);
740
15
  else
741
15
    cmd = CMD_MAX_POOL_FORWARD(self->kdim[0], self->kdim[1]);
742
18
  ccv_nnc_tensor_param_t output_params;
743
18
  ccv_nnc_hint_tensor_auto(cmd, &params, 1, self->hint, &output_params, 1);
744
18
  const ccv_nnc_tensor_symbol_t pool_output = ccv_nnc_tensor_symbol_new(graph, output_params, 0);
745
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);
746
18
  ccv_nnc_graph_exec_symbol_set_hint(graph, exec, self->hint);
747
18
  outputs[0] = pool_output;
748
18
}
749
750
static ccv_cnnp_model_t* _ccv_cnnp_max_pool_copy(const ccv_cnnp_model_t* const super, void* const context);
751
752
static const ccv_cnnp_model_vtab_t ccv_cnnp_max_pool_isa = {
753
  .build = _ccv_cnnp_max_pool_build,
754
  .copy = _ccv_cnnp_max_pool_copy,
755
};
756
757
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)
758
24
{
759
24
  ccv_cnnp_model_pool_t* const model_pool = (ccv_cnnp_model_pool_t*)cccalloc(1, sizeof(ccv_cnnp_model_pool_t));
760
24
  model_pool->super.isa = &ccv_cnnp_max_pool_isa;
761
24
  model_pool->super.input_size = 1;
762
24
  model_pool->super.outputs = &model_pool->output;
763
24
  model_pool->super.output_size = 1;
764
24
  ccv_cnnp_model_copy_name(&model_pool->super, name);
765
24
  memcpy(model_pool->kdim, kdim, sizeof(model_pool->kdim));
766
24
  model_pool->hint = hint;
767
24
  return (ccv_cnnp_model_t*)model_pool;
768
24
}
769
770
static ccv_cnnp_model_t* _ccv_cnnp_max_pool_copy(const ccv_cnnp_model_t* const super, void* const context)
771
6
{
772
6
  const ccv_cnnp_model_pool_t* const self = (const ccv_cnnp_model_pool_t*)super;
773
6
  return ccv_cnnp_max_pool(self->kdim, self->hint, self->super.name);
774
6
}
775
776
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)
777
16
{
778
16
  assert(input_size == 1);
779
16
  assert(output_size == 1);
780
16
  ccv_cnnp_model_pool_t* const self = (ccv_cnnp_model_pool_t*)super;
781
16
  const ccv_nnc_tensor_param_t params = ccv_nnc_tensor_symbol_params(graph, inputs[0]);
782
16
  const int hw = ccv_nnc_tensor_hw(params, ccv_nnc_tensor_nd(params.dim));
783
16
  ccv_nnc_cmd_t cmd;
784
16
  if (hw >= 0 && self->kdim[0] == 0 && 
self->kdim[1] == 03
)
785
3
    cmd = CMD_AVERAGE_POOL_FORWARD(params.dim[hw], params.dim[hw + 1]);
786
13
  else
787
13
    cmd = CMD_AVERAGE_POOL_FORWARD(self->kdim[0], self->kdim[1]);
788
16
  ccv_nnc_tensor_param_t output_params;
789
16
  ccv_nnc_hint_tensor_auto(cmd, &params, 1, self->hint, &output_params, 1);
790
16
  const ccv_nnc_tensor_symbol_t pool_output = ccv_nnc_tensor_symbol_new(graph, output_params, 0);
791
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);
792
16
  ccv_nnc_graph_exec_symbol_set_hint(graph, exec, self->hint);
793
16
  outputs[0] = pool_output;
794
16
}
795
796
static ccv_cnnp_model_t* _ccv_cnnp_average_pool_copy(const ccv_cnnp_model_t* const super, void* const context);
797
798
static const ccv_cnnp_model_vtab_t ccv_cnnp_average_pool_isa = {
799
  .build = _ccv_cnnp_average_pool_build,
800
  .copy = _ccv_cnnp_average_pool_copy,
801
};
802
803
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)
804
18
{
805
18
  ccv_cnnp_model_pool_t* const model_pool = (ccv_cnnp_model_pool_t*)cccalloc(1, sizeof(ccv_cnnp_model_pool_t));
806
18
  model_pool->super.isa = &ccv_cnnp_average_pool_isa;
807
18
  model_pool->super.input_size = 1;
808
18
  model_pool->super.outputs = &model_pool->output;
809
18
  model_pool->super.output_size = 1;
810
18
  ccv_cnnp_model_copy_name(&model_pool->super, name);
811
18
  memcpy(model_pool->kdim, kdim, sizeof(model_pool->kdim));
812
18
  model_pool->hint = hint;
813
18
  return (ccv_cnnp_model_t*)model_pool;
814
18
}
815
816
static ccv_cnnp_model_t* _ccv_cnnp_average_pool_copy(const ccv_cnnp_model_t* const super, void* const context)
817
2
{
818
2
  const ccv_cnnp_model_pool_t* const self = (const ccv_cnnp_model_pool_t*)super;
819
2
  return ccv_cnnp_average_pool(self->kdim, self->hint, self->super.name);
820
2
}
821
822
// MARK - RELU Layer
823
824
typedef struct {
825
  ccv_cnnp_model_t super;
826
  ccv_nnc_tensor_symbol_t output;
827
} ccv_cnnp_model_relu_t;
828
829
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)
830
105
{
831
105
  assert(input_size == 1);
832
105
  assert(output_size == 1);
833
105
  ccv_nnc_tensor_param_t params = ccv_nnc_tensor_symbol_params(graph, inputs[0]);
834
105
  ccv_nnc_tensor_param_t output_params;
835
105
  const ccv_nnc_cmd_t relu = CMD_RELU_FORWARD();
836
105
  ccv_nnc_hint_tensor_auto(relu, (ccv_nnc_tensor_param_t []){
837
105
      params,
838
105
    }, 1, ccv_nnc_no_hint, &output_params, 1);
839
105
  const ccv_nnc_tensor_symbol_t relu_output = ccv_nnc_tensor_symbol_new(graph, output_params, 0);
840
105
  ccv_nnc_graph_exec_symbol_new(graph, relu, TENSOR_SYMBOL_LIST(inputs[0]), TENSOR_SYMBOL_LIST(relu_output), 0);
841
105
  outputs[0] = relu_output;
842
105
}
843
844
static ccv_cnnp_model_t* _ccv_cnnp_relu_copy(const ccv_cnnp_model_t* const self, void* const context);
845
846
static const ccv_cnnp_model_vtab_t ccv_cnnp_relu_isa = {
847
  .build = _ccv_cnnp_relu_build,
848
  .copy = _ccv_cnnp_relu_copy,
849
};
850
851
ccv_cnnp_model_t* ccv_cnnp_relu(const char* const name)
852
122
{
853
122
  ccv_cnnp_model_relu_t* const model_relu = (ccv_cnnp_model_relu_t*)cccalloc(1, sizeof(ccv_cnnp_model_relu_t));
854
122
  model_relu->super.isa = &ccv_cnnp_relu_isa;
855
122
  model_relu->super.input_size = 1;
856
122
  model_relu->super.outputs = &model_relu->output;
857
122
  model_relu->super.output_size = 1;
858
122
  ccv_cnnp_model_copy_name(&model_relu->super, name);
859
122
  return (ccv_cnnp_model_t*)model_relu;
860
122
}
861
862
static ccv_cnnp_model_t* _ccv_cnnp_relu_copy(const ccv_cnnp_model_t* const self, void* const context)
863
17
{
864
17
  return ccv_cnnp_relu(self->name);
865
17
}
866
867
// MARK - Sigmoid Layer
868
869
typedef struct {
870
  ccv_cnnp_model_t super;
871
  ccv_nnc_tensor_symbol_t output;
872
} ccv_cnnp_model_sigmoid_t;
873
874
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)
875
0
{
876
0
  assert(input_size == 1);
877
0
  assert(output_size == 1);
878
0
  ccv_nnc_tensor_param_t params = ccv_nnc_tensor_symbol_params(graph, inputs[0]);
879
0
  ccv_nnc_tensor_param_t output_params;
880
0
  const ccv_nnc_cmd_t sigmoid = CMD_SIGMOID_FORWARD();
881
0
  ccv_nnc_hint_tensor_auto(sigmoid, (ccv_nnc_tensor_param_t []){
882
0
      params,
883
0
    }, 1, ccv_nnc_no_hint, &output_params, 1);
884
0
  const ccv_nnc_tensor_symbol_t sigmoid_output = ccv_nnc_tensor_symbol_new(graph, output_params, 0);
885
0
  ccv_nnc_graph_exec_symbol_new(graph, sigmoid, TENSOR_SYMBOL_LIST(inputs[0]), TENSOR_SYMBOL_LIST(sigmoid_output), 0);
886
0
  outputs[0] = sigmoid_output;
887
0
}
888
889
static ccv_cnnp_model_t* _ccv_cnnp_sigmoid_copy(const ccv_cnnp_model_t* const self, void* const context);
890
891
static const ccv_cnnp_model_vtab_t ccv_cnnp_sigmoid_isa = {
892
  .build = _ccv_cnnp_sigmoid_build,
893
  .copy = _ccv_cnnp_sigmoid_copy,
894
};
895
896
ccv_cnnp_model_t* ccv_cnnp_sigmoid(const char* const name)
897
0
{
898
0
  ccv_cnnp_model_sigmoid_t* const model_sigmoid = (ccv_cnnp_model_sigmoid_t*)cccalloc(1, sizeof(ccv_cnnp_model_sigmoid_t));
899
0
  model_sigmoid->super.isa = &ccv_cnnp_sigmoid_isa;
900
0
  model_sigmoid->super.input_size = 1;
901
0
  model_sigmoid->super.outputs = &model_sigmoid->output;
902
0
  model_sigmoid->super.output_size = 1;
903
0
  ccv_cnnp_model_copy_name(&model_sigmoid->super, name);
904
0
  return (ccv_cnnp_model_t*)model_sigmoid;
905
0
}
906
907
static ccv_cnnp_model_t* _ccv_cnnp_sigmoid_copy(const ccv_cnnp_model_t* const self, void* const context)
908
0
{
909
0
  return ccv_cnnp_sigmoid(self->name);
910
0
}
911
912
// MARK - Tanh Layer
913
914
typedef struct {
915
  ccv_cnnp_model_t super;
916
  ccv_nnc_tensor_symbol_t output;
917
} ccv_cnnp_model_tanh_t;
918
919
static void _ccv_cnnp_tanh_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)
920
0
{
921
0
  assert(input_size == 1);
922
0
  assert(output_size == 1);
923
0
  ccv_nnc_tensor_param_t params = ccv_nnc_tensor_symbol_params(graph, inputs[0]);
924
0
  ccv_nnc_tensor_param_t output_params;
925
0
  const ccv_nnc_cmd_t tanh = CMD_TANH_FORWARD();
926
0
  ccv_nnc_hint_tensor_auto(tanh, (ccv_nnc_tensor_param_t []){
927
0
      params,
928
0
    }, 1, ccv_nnc_no_hint, &output_params, 1);
929
0
  const ccv_nnc_tensor_symbol_t tanh_output = ccv_nnc_tensor_symbol_new(graph, output_params, 0);
930
0
  ccv_nnc_graph_exec_symbol_new(graph, tanh, TENSOR_SYMBOL_LIST(inputs[0]), TENSOR_SYMBOL_LIST(tanh_output), 0);
931
0
  outputs[0] = tanh_output;
932
0
}
933
934
static ccv_cnnp_model_t* _ccv_cnnp_tanh_copy(const ccv_cnnp_model_t* const self, void* const context);
935
936
static const ccv_cnnp_model_vtab_t ccv_cnnp_tanh_isa = {
937
  .build = _ccv_cnnp_tanh_build,
938
  .copy = _ccv_cnnp_tanh_copy,
939
};
940
941
ccv_cnnp_model_t* ccv_cnnp_tanh(const char* const name)
942
0
{
943
0
  ccv_cnnp_model_tanh_t* const model_tanh = (ccv_cnnp_model_tanh_t*)cccalloc(1, sizeof(ccv_cnnp_model_tanh_t));
944
0
  model_tanh->super.isa = &ccv_cnnp_tanh_isa;
945
0
  model_tanh->super.input_size = 1;
946
0
  model_tanh->super.outputs = &model_tanh->output;
947
0
  model_tanh->super.output_size = 1;
948
0
  ccv_cnnp_model_copy_name(&model_tanh->super, name);
949
0
  return (ccv_cnnp_model_t*)model_tanh;
950
0
}
951
952
static ccv_cnnp_model_t* _ccv_cnnp_tanh_copy(const ccv_cnnp_model_t* const self, void* const context)
953
0
{
954
0
  return ccv_cnnp_tanh(self->name);
955
0
}
956
957
// MARK - Swish Layer
958
959
typedef struct {
960
  ccv_cnnp_model_t super;
961
  ccv_nnc_tensor_symbol_t output;
962
} ccv_cnnp_model_swish_t;
963
964
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)
965
0
{
966
0
  assert(input_size == 1);
967
0
  assert(output_size == 1);
968
0
  ccv_nnc_tensor_param_t params = ccv_nnc_tensor_symbol_params(graph, inputs[0]);
969
0
  ccv_nnc_tensor_param_t output_params;
970
0
  const ccv_nnc_cmd_t swish = CMD_SWISH_FORWARD();
971
0
  ccv_nnc_hint_tensor_auto(swish, (ccv_nnc_tensor_param_t []){
972
0
      params,
973
0
    }, 1, ccv_nnc_no_hint, &output_params, 1);
974
0
  const ccv_nnc_tensor_symbol_t swish_output = ccv_nnc_tensor_symbol_new(graph, output_params, 0);
975
0
  ccv_nnc_graph_exec_symbol_new(graph, swish, TENSOR_SYMBOL_LIST(inputs[0]), TENSOR_SYMBOL_LIST(swish_output), 0);
976
0
  outputs[0] = swish_output;
977
0
}
978
979
static ccv_cnnp_model_t* _ccv_cnnp_swish_copy(const ccv_cnnp_model_t* const self, void* const context);
980
981
static const ccv_cnnp_model_vtab_t ccv_cnnp_swish_isa = {
982
  .build = _ccv_cnnp_swish_build,
983
  .copy = _ccv_cnnp_swish_copy,
984
};
985
986
ccv_cnnp_model_t* ccv_cnnp_swish(const char* const name)
987
0
{
988
0
  ccv_cnnp_model_swish_t* const model_swish = (ccv_cnnp_model_swish_t*)cccalloc(1, sizeof(ccv_cnnp_model_swish_t));
989
0
  model_swish->super.isa = &ccv_cnnp_swish_isa;
990
0
  model_swish->super.input_size = 1;
991
0
  model_swish->super.outputs = &model_swish->output;
992
0
  model_swish->super.output_size = 1;
993
0
  ccv_cnnp_model_copy_name(&model_swish->super, name);
994
0
  return (ccv_cnnp_model_t*)model_swish;
995
0
}
996
997
static ccv_cnnp_model_t* _ccv_cnnp_swish_copy(const ccv_cnnp_model_t* const self, void* const context)
998
0
{
999
0
  return ccv_cnnp_swish(self->name);
1000
0
}
1001
1002
// MARK - Softmax Layer
1003
1004
typedef struct {
1005
  ccv_cnnp_model_t super;
1006
  ccv_nnc_tensor_symbol_t output;
1007
} ccv_cnnp_model_softmax_t;
1008
1009
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)
1010
10
{
1011
10
  assert(input_size == 1);
1012
10
  assert(output_size == 1);
1013
10
  ccv_nnc_tensor_param_t params = ccv_nnc_tensor_symbol_params(graph, inputs[0]);
1014
10
  ccv_nnc_tensor_param_t output_params;
1015
10
  const ccv_nnc_cmd_t softmax = CMD_SOFTMAX_FORWARD();
1016
10
  ccv_nnc_hint_tensor_auto(softmax, (ccv_nnc_tensor_param_t []){
1017
10
      params,
1018
10
    }, 1, ccv_nnc_no_hint, &output_params, 1);
1019
10
  const ccv_nnc_tensor_symbol_t softmax_output = ccv_nnc_tensor_symbol_new(graph, output_params, 0);
1020
10
  ccv_nnc_graph_exec_symbol_new(graph, softmax, TENSOR_SYMBOL_LIST(inputs[0]), TENSOR_SYMBOL_LIST(softmax_output), 0);
1021
10
  outputs[0] = softmax_output;
1022
10
}
1023
1024
static ccv_cnnp_model_t* _ccv_cnnp_softmax_copy(const ccv_cnnp_model_t* const self, void* const context);
1025
1026
static const ccv_cnnp_model_vtab_t ccv_cnnp_softmax_isa = {
1027
  .build = _ccv_cnnp_softmax_build,
1028
  .copy = _ccv_cnnp_softmax_copy,
1029
};
1030
1031
ccv_cnnp_model_t* ccv_cnnp_softmax(const char* const name)
1032
11
{
1033
11
  ccv_cnnp_model_softmax_t* const model_softmax = (ccv_cnnp_model_softmax_t*)cccalloc(1, sizeof(ccv_cnnp_model_softmax_t));
1034
11
  model_softmax->super.isa = &ccv_cnnp_softmax_isa;
1035
11
  model_softmax->super.input_size = 1;
1036
11
  model_softmax->super.outputs = &model_softmax->output;
1037
11
  model_softmax->super.output_size = 1;
1038
11
  ccv_cnnp_model_copy_name(&model_softmax->super, name);
1039
11
  return (ccv_cnnp_model_t*)model_softmax;
1040
11
}
1041
1042
static ccv_cnnp_model_t* _ccv_cnnp_softmax_copy(const ccv_cnnp_model_t* const self, void* const context)
1043
1
{
1044
1
  return ccv_cnnp_softmax(self->name);
1045
1
}
1046
1047
// MARK - Add Layer
1048
1049
typedef struct {
1050
  ccv_cnnp_model_t super;
1051
  float p;
1052
  float q;
1053
  ccv_nnc_tensor_symbol_t output;
1054
} ccv_cnnp_model_add_t;
1055
1056
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)
1057
0
{
1058
0
  const ccv_cnnp_model_add_t* const self = (const ccv_cnnp_model_add_t*)super;
1059
0
  assert(input_size == 2);
1060
0
  assert(output_size == 1);
1061
0
  ccv_nnc_tensor_param_t input_params[2];
1062
0
  int i;
1063
0
  for (i = 0; i < 2; i++)
1064
0
    input_params[i] = ccv_nnc_tensor_symbol_params(graph, inputs[i]);
1065
0
  ccv_nnc_tensor_param_t output_params;
1066
0
  const ccv_nnc_cmd_t add = CMD_ADD_FORWARD(self->p, self->q);
1067
0
  ccv_nnc_hint_tensor_auto(add, input_params, 2, ccv_nnc_no_hint, &output_params, 1);
1068
0
  outputs[0] = ccv_nnc_tensor_symbol_new(graph, output_params, 0);
1069
0
  ccv_nnc_graph_exec_symbol_new(graph, add, inputs, input_size, outputs, output_size, 0);
1070
0
}
1071
1072
static ccv_cnnp_model_t* _ccv_cnnp_add_copy(const ccv_cnnp_model_t* const self, void* const context);
1073
1074
static const ccv_cnnp_model_vtab_t ccv_cnnp_add_isa = {
1075
  .build = _ccv_cnnp_add_build,
1076
  .copy = _ccv_cnnp_add_copy,
1077
};
1078
1079
ccv_cnnp_model_t* ccv_cnnp_add(const float p, const float q, const char* const name)
1080
0
{
1081
0
  ccv_cnnp_model_add_t* const model_add = (ccv_cnnp_model_add_t*)cccalloc(1, sizeof(ccv_cnnp_model_add_t));
1082
0
  model_add->super.isa = &ccv_cnnp_add_isa;
1083
0
  model_add->super.input_size = 2;
1084
0
  model_add->super.outputs = &model_add->output;
1085
0
  model_add->super.output_size = 1;
1086
0
  model_add->p = p;
1087
0
  model_add->q = q;
1088
0
  ccv_cnnp_model_copy_name(&model_add->super, name);
1089
0
  return (ccv_cnnp_model_t*)model_add;
1090
0
}
1091
1092
static ccv_cnnp_model_t* _ccv_cnnp_add_copy(const ccv_cnnp_model_t* const super, void* const context)
1093
0
{
1094
0
  const ccv_cnnp_model_add_t* const self = (const ccv_cnnp_model_add_t*)super;
1095
0
  return ccv_cnnp_add(self->p, self->q, self->super.name);
1096
0
}
1097
1098
// MARK - Mul Layer
1099
1100
typedef struct {
1101
  ccv_cnnp_model_t super;
1102
  ccv_nnc_tensor_symbol_t output;
1103
  float p;
1104
} ccv_cnnp_model_mul_t;
1105
1106
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)
1107
1
{
1108
1
  const ccv_cnnp_model_mul_t* const self = (const ccv_cnnp_model_mul_t*)super;
1109
1
  assert(input_size == 2);
1110
1
  assert(output_size == 1);
1111
1
  ccv_nnc_tensor_param_t input_params[2];
1112
1
  int i;
1113
3
  for (i = 0; i < 2; 
i++2
)
1114
2
    input_params[i] = ccv_nnc_tensor_symbol_params(graph, inputs[i]);
1115
1
  ccv_nnc_tensor_param_t output_params;
1116
1
  const ccv_nnc_cmd_t mul = CMD_MUL_FORWARD(self->p);
1117
1
  ccv_nnc_hint_tensor_auto(mul, input_params, 2, ccv_nnc_no_hint, &output_params, 1);
1118
1
  outputs[0] = ccv_nnc_tensor_symbol_new(graph, output_params, 0);
1119
1
  ccv_nnc_graph_exec_symbol_new(graph, mul, inputs, input_size, outputs, output_size, 0);
1120
1
}
1121
1122
static ccv_cnnp_model_t* _ccv_cnnp_mul_copy(const ccv_cnnp_model_t* const self, void* const context);
1123
1124
static const ccv_cnnp_model_vtab_t ccv_cnnp_mul_isa = {
1125
  .build = _ccv_cnnp_mul_build,
1126
  .copy = _ccv_cnnp_mul_copy,
1127
};
1128
1129
ccv_cnnp_model_t* ccv_cnnp_mul(const float p, const char* const name)
1130
1
{
1131
1
  ccv_cnnp_model_mul_t* const model_mul = (ccv_cnnp_model_mul_t*)cccalloc(1, sizeof(ccv_cnnp_model_mul_t));
1132
1
  model_mul->super.isa = &ccv_cnnp_mul_isa;
1133
1
  model_mul->super.input_size = 2;
1134
1
  model_mul->super.outputs = &model_mul->output;
1135
1
  model_mul->super.output_size = 1;
1136
1
  model_mul->p = p;
1137
1
  ccv_cnnp_model_copy_name(&model_mul->super, name);
1138
1
  return (ccv_cnnp_model_t*)model_mul;
1139
1
}
1140
1141
static ccv_cnnp_model_t* _ccv_cnnp_mul_copy(const ccv_cnnp_model_t* const super, void* const context)
1142
0
{
1143
0
  const ccv_cnnp_model_mul_t* const self = (const ccv_cnnp_model_mul_t*)super;
1144
0
  return ccv_cnnp_mul(self->p, self->super.name);
1145
0
}
1146
1147
// MARK - Scalar Mul Layer
1148
1149
typedef struct {
1150
  ccv_cnnp_model_t super;
1151
  ccv_nnc_tensor_symbol_t output;
1152
  float a;
1153
} ccv_cnnp_model_scalar_mul_t;
1154
1155
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)
1156
6
{
1157
6
  assert(input_size == 1);
1158
6
  assert(output_size == 1);
1159
6
  ccv_nnc_tensor_param_t params = ccv_nnc_tensor_symbol_params(graph, inputs[0]);
1160
6
  ccv_nnc_tensor_param_t output_params;
1161
6
  ccv_cnnp_model_scalar_mul_t* const self = (ccv_cnnp_model_scalar_mul_t*)super;
1162
6
  const ccv_nnc_cmd_t scalar_mul = CMD_SCALAR_MUL_FORWARD(self->a);
1163
6
  ccv_nnc_hint_tensor_auto(scalar_mul, (ccv_nnc_tensor_param_t []){
1164
6
      params,
1165
6
    }, 1, ccv_nnc_no_hint, &output_params, 1);
1166
6
  const ccv_nnc_tensor_symbol_t scalar_mul_output = ccv_nnc_tensor_symbol_new(graph, output_params, 0);
1167
6
  ccv_nnc_graph_exec_symbol_new(graph, scalar_mul, TENSOR_SYMBOL_LIST(inputs[0]), TENSOR_SYMBOL_LIST(scalar_mul_output), 0);
1168
6
  outputs[0] = scalar_mul_output;
1169
6
}
1170
1171
static ccv_cnnp_model_t* _ccv_cnnp_scalar_mul_copy(const ccv_cnnp_model_t* const super, void* const context);
1172
1173
static const ccv_cnnp_model_vtab_t ccv_cnnp_scalar_mul_isa = {
1174
  .build = _ccv_cnnp_scalar_mul_build,
1175
  .copy = _ccv_cnnp_scalar_mul_copy,
1176
};
1177
1178
ccv_cnnp_model_t* ccv_cnnp_scalar_mul(const float a, const char* const name)
1179
6
{
1180
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));
1181
6
  model_scalar_mul->super.isa = &ccv_cnnp_scalar_mul_isa;
1182
6
  model_scalar_mul->super.input_size = 1;
1183
6
  model_scalar_mul->super.outputs = &model_scalar_mul->output;
1184
6
  model_scalar_mul->super.output_size = 1;
1185
6
  model_scalar_mul->a = a;
1186
6
  ccv_cnnp_model_copy_name(&model_scalar_mul->super, name);
1187
6
  return (ccv_cnnp_model_t*)model_scalar_mul;
1188
6
}
1189
1190
static ccv_cnnp_model_t* _ccv_cnnp_scalar_mul_copy(const ccv_cnnp_model_t* const super, void* const context)
1191
0
{
1192
0
  const ccv_cnnp_model_scalar_mul_t* const self = (const ccv_cnnp_model_scalar_mul_t*)super;
1193
0
  return ccv_cnnp_scalar_mul(self->a, self->super.name);
1194
0
}
1195
1196
// MARK - Transpose Layer
1197
1198
typedef struct {
1199
  ccv_cnnp_model_t super;
1200
  ccv_nnc_tensor_symbol_t output;
1201
  int transpose[2];
1202
} ccv_cnnp_model_transpose_t;
1203
1204
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)
1205
33
{
1206
33
  assert(input_size == 1);
1207
33
  assert(output_size == 1);
1208
33
  ccv_cnnp_model_transpose_t* const self = (ccv_cnnp_model_transpose_t*)super;
1209
33
  if (self->transpose[0] == self->transpose[1])
1210
0
  {
1211
0
    outputs[0] = inputs[0];
1212
0
    return;
1213
0
  }
1214
33
  ccv_nnc_tensor_param_t params = ccv_nnc_tensor_symbol_params(graph, inputs[0]);
1215
33
  ccv_nnc_tensor_param_t output_params;
1216
33
  const ccv_nnc_cmd_t transpose = CMD_TRANSPOSE_FORWARD(self->transpose[0], self->transpose[1]);
1217
33
  ccv_nnc_hint_tensor_auto(transpose, (ccv_nnc_tensor_param_t []){
1218
33
      params,
1219
33
    }, 1, ccv_nnc_no_hint, &output_params, 1);
1220
33
  const ccv_nnc_tensor_symbol_t transpose_output = ccv_nnc_tensor_symbol_new(graph, output_params, 0);
1221
33
  ccv_nnc_graph_exec_symbol_new(graph, transpose, TENSOR_SYMBOL_LIST(inputs[0]), TENSOR_SYMBOL_LIST(transpose_output), 0);
1222
33
  outputs[0] = transpose_output;
1223
33
}
1224
1225
static ccv_cnnp_model_t* _ccv_cnnp_transpose_copy(const ccv_cnnp_model_t* const super, void* const context);
1226
1227
static const ccv_cnnp_model_vtab_t ccv_cnnp_transpose_isa = {
1228
  .build = _ccv_cnnp_transpose_build,
1229
  .copy = _ccv_cnnp_transpose_copy,
1230
};
1231
1232
ccv_cnnp_model_t* ccv_cnnp_transpose(const int axis_a, const int axis_b, const char* const name)
1233
33
{
1234
33
  ccv_cnnp_model_transpose_t* const model_transpose = (ccv_cnnp_model_transpose_t*)cccalloc(1, sizeof(ccv_cnnp_model_transpose_t));
1235
33
  model_transpose->super.isa = &ccv_cnnp_transpose_isa;
1236
33
  model_transpose->super.input_size = 1;
1237
33
  model_transpose->super.outputs = &model_transpose->output;
1238
33
  model_transpose->super.output_size = 1;
1239
33
  model_transpose->transpose[0] = axis_a;
1240
33
  model_transpose->transpose[1] = axis_b;
1241
33
  ccv_cnnp_model_copy_name(&model_transpose->super, name);
1242
33
  return (ccv_cnnp_model_t*)model_transpose;
1243
33
}
1244
1245
static ccv_cnnp_model_t* _ccv_cnnp_transpose_copy(const ccv_cnnp_model_t* const super, void* const context)
1246
0
{
1247
0
  const ccv_cnnp_model_transpose_t* const self = (const ccv_cnnp_model_transpose_t*)super;
1248
0
  return ccv_cnnp_transpose(self->transpose[0], self->transpose[1], self->super.name);
1249
0
}
1250
1251
// MARK - Layer Norm Layer
1252
1253
typedef struct {
1254
  ccv_cnnp_model_t super;
1255
  ccv_nnc_tensor_symbol_t output;
1256
  ccv_nnc_tensor_symbol_t bias;
1257
  ccv_nnc_tensor_symbol_t scale;
1258
  ccv_nnc_cmd_param_t params;
1259
} ccv_cnnp_model_layer_norm_t;
1260
1261
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)
1262
12
{
1263
12
  assert(input_size == 1);
1264
12
  assert(output_size == 1);
1265
12
  ccv_cnnp_model_layer_norm_t* const self = (ccv_cnnp_model_layer_norm_t*)super;
1266
12
  const ccv_nnc_tensor_param_t params = ccv_nnc_tensor_symbol_params(graph, inputs[0]);
1267
12
  ccv_nnc_tensor_param_t bias_params = params;
1268
  // If the accuracy is not enough, bump it to 32-bit floating point.
1269
12
  if (bias_params.datatype != CCV_32F && 
bias_params.datatype != CCV_64F0
)
1270
0
    bias_params.datatype = CCV_32F;
1271
12
  const int nd = ccv_nnc_tensor_nd(params.dim);
1272
12
  int i;
1273
48
  for (i = 0; i < nd; 
i++36
)
1274
36
    bias_params.dim[i] = 1;
1275
24
  for (i = 0; i < self->params.lnorm.count; 
i++12
)
1276
12
    bias_params.dim[self->params.lnorm.axis[i]] = params.dim[self->params.lnorm.axis[i]];
1277
  // Both scale and bias are shared between if this model is reused.
1278
12
  if (!self->scale.graph)
1279
12
    self->scale = ccv_nnc_tensor_symbol_new(graph, bias_params, 0);
1280
12
  if (!self->bias.graph)
1281
12
    self->bias = ccv_nnc_tensor_symbol_new(graph, bias_params, 0);
1282
12
  const ccv_nnc_cmd_t layer_norm = ccv_nnc_cmd(CCV_NNC_LAYER_NORM_FORWARD, 0, self->params, 0);
1283
12
  ccv_nnc_tensor_param_t output_params[3];
1284
12
  ccv_nnc_hint_tensor_auto(layer_norm, (ccv_nnc_tensor_param_t []){
1285
12
      params,
1286
12
      bias_params,
1287
12
      bias_params,
1288
12
    }, 3, ccv_nnc_no_hint, output_params, 3);
1289
12
  const ccv_nnc_tensor_symbol_t output = ccv_nnc_tensor_symbol_new(graph, output_params[0], 0);
1290
12
  const ccv_nnc_tensor_symbol_t saved_mean = ccv_nnc_tensor_symbol_new(graph, output_params[1], 0);
1291
12
  const ccv_nnc_tensor_symbol_t saved_inv_std = ccv_nnc_tensor_symbol_new(graph, output_params[2], 0);
1292
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);
1293
12
  outputs[0] = output;
1294
12
}
1295
1296
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)
1297
8
{
1298
8
  ccv_cnnp_model_layer_norm_t* const self = (ccv_cnnp_model_layer_norm_t*)super;
1299
8
  if (self->bias.graph)
1300
8
    initializer(context, CMD_SET_FORWARD(0), ccv_nnc_no_hint, 0, 0, self->bias);
1301
8
  if (self->scale.graph)
1302
8
    initializer(context, CMD_RANDOM_UNIFORM_FORWARD(0, 1), ccv_nnc_no_hint, 0, 0, self->scale);
1303
8
}
1304
1305
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)
1306
12
{
1307
12
  ccv_cnnp_model_layer_norm_t* const self = (ccv_cnnp_model_layer_norm_t*)super;
1308
12
  if (self->bias.graph)
1309
12
    add_to_array(parameters, self->bias);
1310
12
  if (self->scale.graph)
1311
12
    add_to_array(parameters, self->scale);
1312
12
}
1313
1314
static ccv_cnnp_model_t* _ccv_cnnp_layer_norm_copy(const ccv_cnnp_model_t* const super, void* const context);
1315
1316
static const ccv_cnnp_model_vtab_t ccv_cnnp_layer_norm_isa = {
1317
  .build = _ccv_cnnp_layer_norm_build,
1318
  .init_states = _ccv_cnnp_layer_norm_init_states,
1319
  .add_to_parameter = _ccv_cnnp_layer_norm_add_to_parameter,
1320
  .copy = _ccv_cnnp_layer_norm_copy,
1321
};
1322
1323
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)
1324
12
{
1325
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));
1326
12
  model_layer_norm->super.isa = &ccv_cnnp_layer_norm_isa;
1327
12
  model_layer_norm->super.input_size = 1;
1328
12
  model_layer_norm->super.outputs = &model_layer_norm->output;
1329
12
  model_layer_norm->super.output_size = 1;
1330
12
  ccv_cnnp_model_copy_name(&model_layer_norm->super, name);
1331
12
  model_layer_norm->scale.d = CCV_NNC_NO_TENSOR_SYMBOL;
1332
12
  model_layer_norm->scale.graph = 0;
1333
12
  model_layer_norm->bias.d = CCV_NNC_NO_TENSOR_SYMBOL;
1334
12
  model_layer_norm->bias.graph = 0;
1335
12
  model_layer_norm->params.lnorm.epsilon = epsilon;
1336
12
  model_layer_norm->params.lnorm.count = axis_count;
1337
12
  memcpy(model_layer_norm->params.lnorm.axis, axis, sizeof(model_layer_norm->params.lnorm.axis));
1338
12
  return (ccv_cnnp_model_t*)model_layer_norm;
1339
12
}
1340
1341
static ccv_cnnp_model_t* _ccv_cnnp_layer_norm_copy(const ccv_cnnp_model_t* const super, void* const context)
1342
0
{
1343
0
  const ccv_cnnp_model_layer_norm_t* const self = (const ccv_cnnp_model_layer_norm_t*)super;
1344
0
  return ccv_cnnp_layer_norm(self->params.lnorm.epsilon, self->params.lnorm.axis, self->params.lnorm.count, self->super.name);
1345
0
}
1346
1347
// MARK - Batched Matrix Mul Layer
1348
1349
typedef struct {
1350
  ccv_cnnp_model_t super;
1351
  ccv_nnc_tensor_symbol_t output;
1352
  int transpose_a[2];
1353
  int transpose_b[2];
1354
} ccv_cnnp_model_matmul_t;
1355
1356
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)
1357
14
{
1358
14
  assert(input_size == 2);
1359
14
  assert(output_size == 1);
1360
14
  ccv_cnnp_model_matmul_t* const self = (ccv_cnnp_model_matmul_t*)super;
1361
14
  ccv_nnc_tensor_param_t a_params = ccv_nnc_tensor_symbol_params(graph, inputs[0]);
1362
14
  ccv_nnc_tensor_param_t b_params = ccv_nnc_tensor_symbol_params(graph, inputs[1]);
1363
14
  ccv_nnc_tensor_param_t output_params;
1364
14
  const ccv_nnc_cmd_t matmul = CMD_GEMM_FORWARD(self->transpose_a, self->transpose_b);
1365
14
  ccv_nnc_hint_tensor_auto(matmul, (ccv_nnc_tensor_param_t []){
1366
14
      a_params,
1367
14
      b_params,
1368
14
    }, 2, ccv_nnc_no_hint, &output_params, 1);
1369
14
  const ccv_nnc_tensor_symbol_t matmul_output = ccv_nnc_tensor_symbol_new(graph, output_params, 0);
1370
14
  ccv_nnc_graph_exec_symbol_new(graph, matmul, inputs, input_size, TENSOR_SYMBOL_LIST(matmul_output), 0);
1371
14
  outputs[0] = matmul_output;
1372
14
}
1373
1374
static ccv_cnnp_model_t* _ccv_cnnp_matmul_copy(const ccv_cnnp_model_t* const super, void* const context);
1375
1376
static const ccv_cnnp_model_vtab_t ccv_cnnp_matmul_isa = {
1377
  .build = _ccv_cnnp_matmul_build,
1378
  .copy = _ccv_cnnp_matmul_copy,
1379
};
1380
1381
ccv_cnnp_model_t* ccv_cnnp_matmul(const int transpose_a[2], const int transpose_b[2], const char* const name)
1382
14
{
1383
14
  ccv_cnnp_model_matmul_t* const model_matmul = (ccv_cnnp_model_matmul_t*)cccalloc(1, sizeof(ccv_cnnp_model_matmul_t));
1384
14
  model_matmul->super.isa = &ccv_cnnp_matmul_isa;
1385
14
  model_matmul->super.input_size = 2;
1386
14
  model_matmul->super.outputs = &model_matmul->output;
1387
14
  model_matmul->super.output_size = 1;
1388
14
  model_matmul->transpose_a[0] = transpose_a[0];
1389
14
  model_matmul->transpose_a[1] = transpose_a[1];
1390
14
  model_matmul->transpose_b[0] = transpose_b[0];
1391
14
  model_matmul->transpose_b[1] = transpose_b[1];
1392
14
  ccv_cnnp_model_copy_name(&model_matmul->super, name);
1393
14
  return (ccv_cnnp_model_t*)model_matmul;
1394
14
}
1395
1396
static ccv_cnnp_model_t* _ccv_cnnp_matmul_copy(const ccv_cnnp_model_t* const super, void* const context)
1397
1
{
1398
1
  const ccv_cnnp_model_matmul_t* const self = (const ccv_cnnp_model_matmul_t*)super;
1399
1
  return ccv_cnnp_matmul(self->transpose_a, self->transpose_b, self->super.name);
1400
1
}
1401
1402
// MARK - Dropout Layer
1403
1404
typedef struct {
1405
  ccv_cnnp_model_t super;
1406
  ccv_nnc_tensor_symbol_t output;
1407
  ccv_nnc_graph_exec_symbol_t dropout;
1408
  float p;
1409
  int entirety;
1410
} ccv_cnnp_model_dropout_t;
1411
1412
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)
1413
18
{
1414
18
  assert(input_size == 1);
1415
18
  assert(output_size == 1);
1416
18
  ccv_nnc_tensor_param_t params = ccv_nnc_tensor_symbol_params(graph, inputs[0]);
1417
18
  ccv_nnc_tensor_param_t output_params[2];
1418
18
  ccv_cnnp_model_dropout_t* const self = (ccv_cnnp_model_dropout_t*)super;
1419
18
  const ccv_nnc_cmd_t dropout = CMD_DROPOUT_FORWARD(self->p, self->entirety);
1420
18
  ccv_nnc_hint_tensor_auto(dropout, (ccv_nnc_tensor_param_t []){
1421
18
      params,
1422
18
    }, 1, ccv_nnc_no_hint, output_params, 2);
1423
18
  const ccv_nnc_tensor_symbol_t dropout_output = ccv_nnc_tensor_symbol_new(graph, output_params[0], 0);
1424
18
  const ccv_nnc_tensor_symbol_t mask = ccv_nnc_tensor_symbol_new(graph, output_params[1], 0);
1425
18
  self->dropout = ccv_nnc_graph_exec_symbol_new(graph, dropout, TENSOR_SYMBOL_LIST(inputs[0]), TENSOR_SYMBOL_LIST(dropout_output, mask), 0);
1426
18
  outputs[0] = dropout_output;
1427
18
}
1428
1429
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)
1430
24
{
1431
24
  ccv_cnnp_model_dropout_t* const self = (ccv_cnnp_model_dropout_t*)super;
1432
24
  if (self->dropout.graph)
1433
24
  {
1434
24
    if (is_test)
1435
      // During test, the dropout is not applied. Data transfer is perfect because if these are the same tensor, it will skip.
1436
12
      updater(context, self->dropout, CMD_DATA_TRANSFER_FORWARD(), ccv_nnc_no_hint);
1437
12
    else
1438
12
      updater(context, self->dropout, CMD_DROPOUT_FORWARD(self->p, self->entirety), ccv_nnc_no_hint);
1439
24
  }
1440
24
}
1441
1442
static ccv_cnnp_model_t* _ccv_cnnp_dropout_copy(const ccv_cnnp_model_t* const super, void* const context);
1443
1444
static const ccv_cnnp_model_vtab_t ccv_cnnp_dropout_isa = {
1445
  .build = _ccv_cnnp_dropout_build,
1446
  .set_is_test = _ccv_cnnp_dropout_set_is_test,
1447
  .copy = _ccv_cnnp_dropout_copy,
1448
};
1449
1450
ccv_cnnp_model_t* ccv_cnnp_dropout(const float p, const int entirety, const char* const name)
1451
18
{
1452
18
  ccv_cnnp_model_dropout_t* const model_dropout = (ccv_cnnp_model_dropout_t*)cccalloc(1, sizeof(ccv_cnnp_model_dropout_t));
1453
18
  model_dropout->super.isa = &ccv_cnnp_dropout_isa;
1454
18
  model_dropout->super.input_size = 1;
1455
18
  model_dropout->super.outputs = &model_dropout->output;
1456
18
  model_dropout->super.output_size = 1;
1457
18
  model_dropout->p = p;
1458
18
  model_dropout->entirety = entirety;
1459
18
  ccv_cnnp_model_copy_name(&model_dropout->super, name);
1460
18
  return (ccv_cnnp_model_t*)model_dropout;
1461
18
}
1462
1463
static ccv_cnnp_model_t* _ccv_cnnp_dropout_copy(const ccv_cnnp_model_t* const super, void* const context)
1464
0
{
1465
0
  const ccv_cnnp_model_dropout_t* const self = (const ccv_cnnp_model_dropout_t*)super;
1466
0
  return ccv_cnnp_dropout(self->p, self->entirety, self->super.name);
1467
0
}
1468
1469
// MARK - Masked Fill Layer
1470
1471
typedef struct {
1472
  ccv_cnnp_model_t super;
1473
  ccv_nnc_tensor_symbol_t output;
1474
  float eq;
1475
  float fill;
1476
} ccv_cnnp_model_masked_fill_t;
1477
1478
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)
1479
6
{
1480
6
  assert(input_size == 2);
1481
6
  assert(output_size == 1);
1482
6
  ccv_nnc_tensor_param_t params = ccv_nnc_tensor_symbol_params(graph, inputs[0]);
1483
6
  ccv_cnnp_model_masked_fill_t* const self = (ccv_cnnp_model_masked_fill_t*)super;
1484
6
  const ccv_nnc_tensor_symbol_t masked_fill_output = ccv_nnc_tensor_symbol_new(graph, params, 0);
1485
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);
1486
6
  outputs[0] = masked_fill_output;
1487
6
}
1488
1489
static ccv_cnnp_model_t* _ccv_cnnp_masked_fill_copy(const ccv_cnnp_model_t* const super, void* const context);
1490
1491
static const ccv_cnnp_model_vtab_t ccv_cnnp_masked_fill_isa = {
1492
  .build = _ccv_cnnp_masked_fill_build,
1493
  .copy = _ccv_cnnp_masked_fill_copy,
1494
};
1495
1496
ccv_cnnp_model_t* ccv_cnnp_masked_fill(const float eq, const float fill, const char* const name)
1497
6
{
1498
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));
1499
6
  model_masked_fill->super.isa = &ccv_cnnp_masked_fill_isa;
1500
6
  model_masked_fill->super.input_size = 2;
1501
6
  model_masked_fill->super.outputs = &model_masked_fill->output;
1502
6
  model_masked_fill->super.output_size = 1;
1503
6
  model_masked_fill->eq = eq;
1504
6
  model_masked_fill->fill = fill;
1505
6
  ccv_cnnp_model_copy_name(&model_masked_fill->super, name);
1506
6
  return (ccv_cnnp_model_t*)model_masked_fill;
1507
6
}
1508
1509
static ccv_cnnp_model_t* _ccv_cnnp_masked_fill_copy(const ccv_cnnp_model_t* const super, void* const context)
1510
0
{
1511
0
  const ccv_cnnp_model_masked_fill_t* const self = (const ccv_cnnp_model_masked_fill_t*)super;
1512
0
  return ccv_cnnp_masked_fill(self->eq, self->fill, self->super.name);
1513
0
}
1514
1515
// MARK - Index Select Layer
1516
1517
typedef struct {
1518
  ccv_cnnp_model_t super;
1519
  ccv_nnc_tensor_symbol_t output;
1520
} ccv_cnnp_model_index_select_t;
1521
1522
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)
1523
5
{
1524
5
  assert(input_size == 2);
1525
5
  assert(output_size == 1);
1526
5
  const ccv_nnc_tensor_param_t vocab_params = ccv_nnc_tensor_symbol_params(graph, inputs[0]);
1527
5
  const ccv_nnc_tensor_param_t index_params = ccv_nnc_tensor_symbol_params(graph, inputs[1]);
1528
5
  ccv_nnc_tensor_param_t output_params;
1529
5
  const ccv_nnc_cmd_t index_select = CMD_INDEX_SELECT_FORWARD();
1530
5
  ccv_nnc_hint_tensor_auto(index_select, (ccv_nnc_tensor_param_t []){
1531
5
      vocab_params,
1532
5
      index_params,
1533
5
    }, 2, ccv_nnc_no_hint, &output_params, 1);
1534
5
  const ccv_nnc_tensor_symbol_t output = ccv_nnc_tensor_symbol_new(graph, output_params, 0);
1535
5
  ccv_nnc_graph_exec_symbol_new(graph, index_select, TENSOR_SYMBOL_LIST(inputs[0], inputs[1]), TENSOR_SYMBOL_LIST(output), 0);
1536
5
  outputs[0] = output;
1537
5
}
1538
1539
static ccv_cnnp_model_t* _ccv_cnnp_index_select_copy(const ccv_cnnp_model_t* const super, void* const context);
1540
1541
static const ccv_cnnp_model_vtab_t ccv_cnnp_index_select_isa = {
1542
  .build = _ccv_cnnp_index_select_build,
1543
  .copy = _ccv_cnnp_index_select_copy,
1544
};
1545
1546
ccv_cnnp_model_t* ccv_cnnp_index_select(const char* const name)
1547
5
{
1548
5
  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));
1549
5
  model_index_select->super.isa = &ccv_cnnp_index_select_isa;
1550
5
  model_index_select->super.input_size = 2;
1551
5
  model_index_select->super.outputs = &model_index_select->output;
1552
5
  model_index_select->super.output_size = 1;
1553
5
  ccv_cnnp_model_copy_name(&model_index_select->super, name);
1554
5
  return (ccv_cnnp_model_t*)model_index_select;
1555
5
}
1556
1557
static ccv_cnnp_model_t* _ccv_cnnp_index_select_copy(const ccv_cnnp_model_t* const super, void* const context)
1558
0
{
1559
0
  ccv_cnnp_model_index_select_t* const self = (ccv_cnnp_model_index_select_t*)super;
1560
0
  return ccv_cnnp_index_select(self->super.name);
1561
0
}
1562
1563
// MARK - Embedding Layer
1564
1565
typedef struct {
1566
  ccv_cnnp_model_t super;
1567
  ccv_nnc_tensor_symbol_t output;
1568
  ccv_nnc_tensor_symbol_t vocab;
1569
  int datatype;
1570
  int vocab_size;
1571
  int embed_size;
1572
} ccv_cnnp_model_embedding_t;
1573
1574
static void _ccv_cnnp_embedding_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)
1575
1
{
1576
1
  assert(input_size == 1);
1577
1
  assert(output_size == 1);
1578
1
  ccv_cnnp_model_embedding_t* const self = (ccv_cnnp_model_embedding_t*)super;
1579
1
  const ccv_nnc_tensor_param_t params = ccv_nnc_tensor_symbol_params(graph, inputs[0]);
1580
1
  ccv_nnc_tensor_param_t vocab_params = params;
1581
1
  memset(vocab_params.dim, 0, sizeof(vocab_params.dim));
1582
1
  vocab_params.datatype = self->datatype;
1583
1
  vocab_params.dim[0] = self->vocab_size;
1584
1
  vocab_params.dim[1] = self->embed_size;
1585
1
  if (!self->vocab.graph)
1586
1
    self->vocab = ccv_nnc_tensor_symbol_new(graph, vocab_params, 0);
1587
1
  assert(self->vocab.graph == graph);
1588
1
  ccv_nnc_tensor_param_t output_params;
1589
1
  const ccv_nnc_cmd_t embedding = CMD_INDEX_SELECT_FORWARD();
1590
1
  ccv_nnc_hint_tensor_auto(embedding, (ccv_nnc_tensor_param_t []){
1591
1
      vocab_params,
1592
1
      params,
1593
1
    }, 2, ccv_nnc_no_hint, &output_params, 1);
1594
1
  const ccv_nnc_tensor_symbol_t output = ccv_nnc_tensor_symbol_new(graph, output_params, 0);
1595
1
  ccv_nnc_graph_exec_symbol_new(graph, embedding, TENSOR_SYMBOL_LIST(self->vocab, inputs[0]), TENSOR_SYMBOL_LIST(output), 0);
1596
1
  outputs[0] = output;
1597
1
}
1598
1599
static void _ccv_cnnp_embedding_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)
1600
1
{
1601
1
  ccv_cnnp_model_embedding_t* const self = (ccv_cnnp_model_embedding_t*)super;
1602
1
  const float std = sqrtf(2) / sqrtf(self->vocab_size + self->embed_size);
1603
1
  const float bound = sqrtf(3) * std;
1604
1
  initializer(context, CMD_RANDOM_UNIFORM_FORWARD(-bound, bound), ccv_nnc_no_hint, 0, 0, self->vocab);
1605
1
}
1606
1607
static void _ccv_cnnp_embedding_add_to_parameter(ccv_cnnp_model_t* const super, const ccv_cnnp_add_to_array_f add_to_array, void* const parameters)
1608
1
{
1609
1
  ccv_cnnp_model_embedding_t* const self = (ccv_cnnp_model_embedding_t*)super;
1610
1
  add_to_array(parameters, self->vocab);
1611
1
}
1612
1613
static ccv_cnnp_model_t* _ccv_cnnp_embedding_copy(const ccv_cnnp_model_t* const super, void* const context);
1614
1615
static const ccv_cnnp_model_vtab_t ccv_cnnp_embedding_isa = {
1616
  .build = _ccv_cnnp_embedding_build,
1617
  .init_states = _ccv_cnnp_embedding_init_states,
1618
  .add_to_parameter = _ccv_cnnp_embedding_add_to_parameter,
1619
  .copy = _ccv_cnnp_embedding_copy,
1620
};
1621
1622
ccv_cnnp_model_t* ccv_cnnp_embedding(const int datatype, const int vocab_size, const int embed_size, const char* const name)
1623
1
{
1624
1
  ccv_cnnp_model_embedding_t* const model_embedding = (ccv_cnnp_model_embedding_t*)cccalloc(1, sizeof(ccv_cnnp_model_embedding_t));
1625
1
  model_embedding->super.isa = &ccv_cnnp_embedding_isa;
1626
1
  model_embedding->super.input_size = 1;
1627
1
  model_embedding->super.outputs = &model_embedding->output;
1628
1
  model_embedding->super.output_size = 1;
1629
1
  ccv_cnnp_model_copy_name(&model_embedding->super, name);
1630
1
  model_embedding->vocab.d = CCV_NNC_NO_TENSOR_SYMBOL;
1631
1
  model_embedding->vocab.graph = 0;
1632
1
  assert(datatype == CCV_32F || datatype == CCV_16F);
1633
1
  model_embedding->datatype = datatype;
1634
1
  assert(vocab_size > 0);
1635
1
  model_embedding->vocab_size = vocab_size;
1636
1
  assert(embed_size > 0);
1637
1
  model_embedding->embed_size = embed_size;
1638
1
  return (ccv_cnnp_model_t*)model_embedding;
1639
1
}
1640
1641
static ccv_cnnp_model_t* _ccv_cnnp_embedding_copy(const ccv_cnnp_model_t* const super, void* const context)
1642
0
{
1643
0
  ccv_cnnp_model_embedding_t* const self = (ccv_cnnp_model_embedding_t*)super;
1644
0
  return ccv_cnnp_embedding(self->datatype, self->vocab_size, self->embed_size, self->super.name);
1645
0
}
1646
1647
// MARK - Pool Layers
1648
1649
typedef struct {
1650
  ccv_cnnp_model_t super;
1651
  ccv_nnc_tensor_symbol_t output;
1652
  float width_scale;
1653
  float height_scale;
1654
} ccv_cnnp_model_upsample_t;
1655
1656
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)
1657
3
{
1658
3
  assert(input_size == 1);
1659
3
  assert(output_size == 1);
1660
3
  ccv_cnnp_model_upsample_t* const self = (ccv_cnnp_model_upsample_t*)super;
1661
3
  const ccv_nnc_tensor_param_t params = ccv_nnc_tensor_symbol_params(graph, inputs[0]);
1662
3
  ccv_nnc_cmd_t cmd = CMD_UPSAMPLE_BILINEAR_FORWARD(self->width_scale, self->height_scale);
1663
3
  ccv_nnc_tensor_param_t output_params;
1664
3
  ccv_nnc_hint_tensor_auto(cmd, &params, 1, ccv_nnc_no_hint, &output_params, 1);
1665
3
  const ccv_nnc_tensor_symbol_t output = ccv_nnc_tensor_symbol_new(graph, output_params, 0);
1666
3
  ccv_nnc_graph_exec_symbol_new(graph, cmd, TENSOR_SYMBOL_LIST(inputs[0]), TENSOR_SYMBOL_LIST(output), 0);
1667
3
  outputs[0] = output;
1668
3
}
1669
1670
static ccv_cnnp_model_t* _ccv_cnnp_upsample_copy(const ccv_cnnp_model_t* const super, void* const context);
1671
1672
static const ccv_cnnp_model_vtab_t ccv_cnnp_upsample_isa = {
1673
  .build = _ccv_cnnp_upsample_build,
1674
  .copy = _ccv_cnnp_upsample_copy,
1675
};
1676
1677
ccv_cnnp_model_t* ccv_cnnp_upsample(const float width_scale, const float height_scale, const char* const name)
1678
3
{
1679
3
  ccv_cnnp_model_upsample_t* const model_upsample = (ccv_cnnp_model_upsample_t*)cccalloc(1, sizeof(ccv_cnnp_model_upsample_t));
1680
3
  model_upsample->super.isa = &ccv_cnnp_upsample_isa;
1681
3
  model_upsample->super.input_size = 1;
1682
3
  model_upsample->super.outputs = &model_upsample->output;
1683
3
  model_upsample->super.output_size = 1;
1684
3
  ccv_cnnp_model_copy_name(&model_upsample->super, name);
1685
3
  model_upsample->width_scale = width_scale;
1686
3
  model_upsample->height_scale = height_scale;
1687
3
  return (ccv_cnnp_model_t*)model_upsample;
1688
3
}
1689
1690
static ccv_cnnp_model_t* _ccv_cnnp_upsample_copy(const ccv_cnnp_model_t* const super, void* const context)
1691
0
{
1692
0
  const ccv_cnnp_model_upsample_t* const self = (const ccv_cnnp_model_upsample_t*)super;
1693
0
  return ccv_cnnp_upsample(self->width_scale, self->height_scale, self->super.name);
1694
0
}
1695
1696
// MARK - Reduce Sum Layer
1697
1698
typedef struct {
1699
  ccv_cnnp_model_t super;
1700
  int axis[CCV_NNC_MAX_DIM_ALLOC];
1701
  int count;
1702
  ccv_nnc_tensor_symbol_t output;
1703
} ccv_cnnp_model_reduce_sum_t;
1704
1705
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)
1706
1
{
1707
1
  const ccv_cnnp_model_reduce_sum_t* const self = (const ccv_cnnp_model_reduce_sum_t*)super;
1708
1
  assert(input_size == 1);
1709
1
  assert(output_size == 1);
1710
1
  ccv_nnc_tensor_param_t input_params = ccv_nnc_tensor_symbol_params(graph, inputs[0]);
1711
1
  ccv_nnc_tensor_param_t output_params;
1712
1
  ccv_nnc_cmd_t reduce_sum = CMD_REDUCE_SUM_FORWARD();
1713
1
  int i;
1714
2
  for (i = 0; i < self->count; 
i++1
)
1715
1
    reduce_sum.info.reduce.axis[i] = self->axis[i];
1716
1
  reduce_sum.info.reduce.count = self->count;
1717
1
  ccv_nnc_hint_tensor_auto(reduce_sum, &input_params, 1, ccv_nnc_no_hint, &output_params, 1);
1718
1
  outputs[0] = ccv_nnc_tensor_symbol_new(graph, output_params, 0);
1719
1
  ccv_nnc_graph_exec_symbol_new(graph, reduce_sum, inputs, input_size, outputs, output_size, 0);
1720
1
}
1721
1722
static ccv_cnnp_model_t* _ccv_cnnp_reduce_sum_copy(const ccv_cnnp_model_t* const self, void* const context);
1723
1724
static const ccv_cnnp_model_vtab_t ccv_cnnp_reduce_sum_isa = {
1725
  .build = _ccv_cnnp_reduce_sum_build,
1726
  .copy = _ccv_cnnp_reduce_sum_copy,
1727
};
1728
1729
ccv_cnnp_model_t* ccv_cnnp_reduce_sum(const int* const axis, const int axis_count, const char* const name)
1730
1
{
1731
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));
1732
1
  model_reduce_sum->super.isa = &ccv_cnnp_reduce_sum_isa;
1733
1
  model_reduce_sum->super.input_size = 1;
1734
1
  model_reduce_sum->super.outputs = &model_reduce_sum->output;
1735
1
  model_reduce_sum->super.output_size = 1;
1736
1
  ccv_cnnp_model_copy_name(&model_reduce_sum->super, name);
1737
1
  assert(axis_count <= CCV_NNC_MAX_DIM_ALLOC);
1738
1
  int i;
1739
2
  for (i = 0; i < axis_count; 
i++1
)
1740
1
    model_reduce_sum->axis[i] = axis[i];
1741
1
  model_reduce_sum->count = axis_count;
1742
1
  return (ccv_cnnp_model_t*)model_reduce_sum;
1743
1
}
1744
1745
static ccv_cnnp_model_t* _ccv_cnnp_reduce_sum_copy(const ccv_cnnp_model_t* const super, void* const context)
1746
0
{
1747
0
  const ccv_cnnp_model_reduce_sum_t* const self = (const ccv_cnnp_model_reduce_sum_t*)super;
1748
0
  return ccv_cnnp_reduce_sum(self->axis, self->count, self->super.name);
1749
0
}
1750
1751
// MARK - Reduce Max Layer
1752
1753
typedef struct {
1754
  ccv_cnnp_model_t super;
1755
  int axis[CCV_NNC_MAX_DIM_ALLOC];
1756
  int count;
1757
  ccv_nnc_tensor_symbol_t output;
1758
} ccv_cnnp_model_reduce_max_t;
1759
1760
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)
1761
1
{
1762
1
  const ccv_cnnp_model_reduce_max_t* const self = (const ccv_cnnp_model_reduce_max_t*)super;
1763
1
  assert(input_size == 1);
1764
1
  assert(output_size == 1);
1765
1
  ccv_nnc_tensor_param_t input_params = ccv_nnc_tensor_symbol_params(graph, inputs[0]);
1766
1
  ccv_nnc_tensor_param_t output_params;
1767
1
  ccv_nnc_cmd_t reduce_max = CMD_REDUCE_MAX_FORWARD();
1768
1
  int i;
1769
2
  for (i = 0; i < self->count; 
i++1
)
1770
1
    reduce_max.info.reduce.axis[i] = self->axis[i];
1771
1
  reduce_max.info.reduce.count = self->count;
1772
1
  ccv_nnc_hint_tensor_auto(reduce_max, &input_params, 1, ccv_nnc_no_hint, &output_params, 1);
1773
1
  outputs[0] = ccv_nnc_tensor_symbol_new(graph, output_params, 0);
1774
1
  ccv_nnc_graph_exec_symbol_new(graph, reduce_max, inputs, input_size, outputs, output_size, 0);
1775
1
}
1776
1777
static ccv_cnnp_model_t* _ccv_cnnp_reduce_max_copy(const ccv_cnnp_model_t* const self, void* const context);
1778
1779
static const ccv_cnnp_model_vtab_t ccv_cnnp_reduce_max_isa = {
1780
  .build = _ccv_cnnp_reduce_max_build,
1781
  .copy = _ccv_cnnp_reduce_max_copy,
1782
};
1783
1784
ccv_cnnp_model_t* ccv_cnnp_reduce_max(const int* const axis, const int axis_count, const char* const name)
1785
1
{
1786
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));
1787
1
  model_reduce_max->super.isa = &ccv_cnnp_reduce_max_isa;
1788
1
  model_reduce_max->super.input_size = 1;
1789
1
  model_reduce_max->super.outputs = &model_reduce_max->output;
1790
1
  model_reduce_max->super.output_size = 1;
1791
1
  ccv_cnnp_model_copy_name(&model_reduce_max->super, name);
1792
1
  assert(axis_count <= CCV_NNC_MAX_DIM_ALLOC);
1793
1
  int i;
1794
2
  for (i = 0; i < axis_count; 
i++1
)
1795
1
    model_reduce_max->axis[i] = axis[i];
1796
1
  model_reduce_max->count = axis_count;
1797
1
  return (ccv_cnnp_model_t*)model_reduce_max;
1798
1
}
1799
1800
static ccv_cnnp_model_t* _ccv_cnnp_reduce_max_copy(const ccv_cnnp_model_t* const super, void* const context)
1801
0
{
1802
0
  const ccv_cnnp_model_reduce_max_t* const self = (const ccv_cnnp_model_reduce_max_t*)super;
1803
0
  return ccv_cnnp_reduce_max(self->axis, self->count, self->super.name);
1804
0
}
1805
1806
// MARK - Reduce Norm2 Layer
1807
1808
typedef struct {
1809
  ccv_cnnp_model_t super;
1810
  int axis[CCV_NNC_MAX_DIM_ALLOC];
1811
  int count;
1812
  ccv_nnc_tensor_symbol_t output;
1813
} ccv_cnnp_model_reduce_norm2_t;
1814
1815
static void _ccv_cnnp_reduce_norm2_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)
1816
1
{
1817
1
  const ccv_cnnp_model_reduce_norm2_t* const self = (const ccv_cnnp_model_reduce_norm2_t*)super;
1818
1
  assert(input_size == 1);
1819
1
  assert(output_size == 1);
1820
1
  ccv_nnc_tensor_param_t input_params = ccv_nnc_tensor_symbol_params(graph, inputs[0]);
1821
1
  ccv_nnc_tensor_param_t output_params;
1822
1
  ccv_nnc_cmd_t reduce_norm2 = CMD_REDUCE_NORM2_FORWARD();
1823
1
  int i;
1824
2
  for (i = 0; i < self->count; 
i++1
)
1825
1
    reduce_norm2.info.reduce.axis[i] = self->axis[i];
1826
1
  reduce_norm2.info.reduce.count = self->count;
1827
1
  ccv_nnc_hint_tensor_auto(reduce_norm2, &input_params, 1, ccv_nnc_no_hint, &output_params, 1);
1828
1
  outputs[0] = ccv_nnc_tensor_symbol_new(graph, output_params, 0);
1829
1
  ccv_nnc_graph_exec_symbol_new(graph, reduce_norm2, inputs, input_size, outputs, output_size, 0);
1830
1
}
1831
1832
static ccv_cnnp_model_t* _ccv_cnnp_reduce_norm2_copy(const ccv_cnnp_model_t* const self, void* const context);
1833
1834
static const ccv_cnnp_model_vtab_t ccv_cnnp_reduce_norm2_isa = {
1835
  .build = _ccv_cnnp_reduce_norm2_build,
1836
  .copy = _ccv_cnnp_reduce_norm2_copy,
1837
};
1838
1839
ccv_cnnp_model_t* ccv_cnnp_reduce_norm2(const int* const axis, const int axis_count, const char* const name)
1840
1
{
1841
1
  ccv_cnnp_model_reduce_norm2_t* const model_reduce_norm2 = (ccv_cnnp_model_reduce_norm2_t*)cccalloc(1, sizeof(ccv_cnnp_model_reduce_norm2_t));
1842
1
  model_reduce_norm2->super.isa = &ccv_cnnp_reduce_norm2_isa;
1843
1
  model_reduce_norm2->super.input_size = 1;
1844
1
  model_reduce_norm2->super.outputs = &model_reduce_norm2->output;
1845
1
  model_reduce_norm2->super.output_size = 1;
1846
1
  ccv_cnnp_model_copy_name(&model_reduce_norm2->super, name);
1847
1
  assert(axis_count <= CCV_NNC_MAX_DIM_ALLOC);
1848
1
  int i;
1849
2
  for (i = 0; i < axis_count; 
i++1
)
1850
1
    model_reduce_norm2->axis[i] = axis[i];
1851
1
  model_reduce_norm2->count = axis_count;
1852
1
  return (ccv_cnnp_model_t*)model_reduce_norm2;
1853
1
}
1854
1855
static ccv_cnnp_model_t* _ccv_cnnp_reduce_norm2_copy(const ccv_cnnp_model_t* const super, void* const context)
1856
0
{
1857
0
  const ccv_cnnp_model_reduce_norm2_t* const self = (const ccv_cnnp_model_reduce_norm2_t*)super;
1858
0
  return ccv_cnnp_reduce_norm2(self->axis, self->count, self->super.name);
1859
0
}
1860
1861
// MARK - Min Layer
1862
1863
typedef struct {
1864
  ccv_cnnp_model_t super;
1865
  ccv_nnc_tensor_symbol_t output;
1866
} ccv_cnnp_model_min_t;
1867
1868
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)
1869
1
{
1870
1
  assert(input_size == 2);
1871
1
  assert(output_size == 1);
1872
1
  ccv_nnc_tensor_param_t input_params[2];
1873
1
  int i;
1874
3
  for (i = 0; i < 2; 
i++2
)
1875
2
    input_params[i] = ccv_nnc_tensor_symbol_params(graph, inputs[i]);
1876
1
  ccv_nnc_tensor_param_t output_params;
1877
1
  const ccv_nnc_cmd_t min = CMD_MIN_FORWARD();
1878
1
  ccv_nnc_hint_tensor_auto(min, input_params, 2, ccv_nnc_no_hint, &output_params, 1);
1879
1
  outputs[0] = ccv_nnc_tensor_symbol_new(graph, output_params, 0);
1880
1
  ccv_nnc_graph_exec_symbol_new(graph, min, inputs, input_size, outputs, output_size, 0);
1881
1
}
1882
1883
static ccv_cnnp_model_t* _ccv_cnnp_min_copy(const ccv_cnnp_model_t* const self, void* const context);
1884
1885
static const ccv_cnnp_model_vtab_t ccv_cnnp_min_isa = {
1886
  .build = _ccv_cnnp_min_build,
1887
  .copy = _ccv_cnnp_min_copy,
1888
};
1889
1890
ccv_cnnp_model_t* ccv_cnnp_min(const char* const name)
1891
1
{
1892
1
  ccv_cnnp_model_min_t* const model_min = (ccv_cnnp_model_min_t*)cccalloc(1, sizeof(ccv_cnnp_model_min_t));
1893
1
  model_min->super.isa = &ccv_cnnp_min_isa;
1894
1
  model_min->super.input_size = 2;
1895
1
  model_min->super.outputs = &model_min->output;
1896
1
  model_min->super.output_size = 1;
1897
1
  ccv_cnnp_model_copy_name(&model_min->super, name);
1898
1
  return (ccv_cnnp_model_t*)model_min;
1899
1
}
1900
1901
static ccv_cnnp_model_t* _ccv_cnnp_min_copy(const ccv_cnnp_model_t* const super, void* const context)
1902
0
{
1903
0
  const ccv_cnnp_model_min_t* const self = (const ccv_cnnp_model_min_t*)super;
1904
0
  return ccv_cnnp_min(self->super.name);
1905
0
}
1906
1907
// MARK - Max Layer
1908
1909
typedef struct {
1910
  ccv_cnnp_model_t super;
1911
  ccv_nnc_tensor_symbol_t output;
1912
} ccv_cnnp_model_max_t;
1913
1914
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)
1915
1
{
1916
1
  assert(input_size == 2);
1917
1
  assert(output_size == 1);
1918
1
  ccv_nnc_tensor_param_t input_params[2];
1919
1
  int i;
1920
3
  for (i = 0; i < 2; 
i++2
)
1921
2
    input_params[i] = ccv_nnc_tensor_symbol_params(graph, inputs[i]);
1922
1
  ccv_nnc_tensor_param_t output_params;
1923
1
  const ccv_nnc_cmd_t max = CMD_MAX_FORWARD();
1924
1
  ccv_nnc_hint_tensor_auto(max, input_params, 2, ccv_nnc_no_hint, &output_params, 1);
1925
1
  outputs[0] = ccv_nnc_tensor_symbol_new(graph, output_params, 0);
1926
1
  ccv_nnc_graph_exec_symbol_new(graph, max, inputs, input_size, outputs, output_size, 0);
1927
1
}
1928
1929
static ccv_cnnp_model_t* _ccv_cnnp_max_copy(const ccv_cnnp_model_t* const self, void* const context);
1930
1931
static const ccv_cnnp_model_vtab_t ccv_cnnp_max_isa = {
1932
  .build = _ccv_cnnp_max_build,
1933
  .copy = _ccv_cnnp_max_copy,
1934
};
1935
1936
ccv_cnnp_model_t* ccv_cnnp_max(const char* const name)
1937
1
{
1938
1
  ccv_cnnp_model_max_t* const model_max = (ccv_cnnp_model_max_t*)cccalloc(1, sizeof(ccv_cnnp_model_max_t));
1939
1
  model_max->super.isa = &ccv_cnnp_max_isa;
1940
1
  model_max->super.input_size = 2;
1941
1
  model_max->super.outputs = &model_max->output;
1942
1
  model_max->super.output_size = 1;
1943
1
  ccv_cnnp_model_copy_name(&model_max->super, name);
1944
1
  return (ccv_cnnp_model_t*)model_max;
1945
1
}
1946
1947
static ccv_cnnp_model_t* _ccv_cnnp_max_copy(const ccv_cnnp_model_t* const super, void* const context)
1948
0
{
1949
0
  const ccv_cnnp_model_max_t* const self = (const ccv_cnnp_model_max_t*)super;
1950
0
  return ccv_cnnp_max(self->super.name);
1951
0
}
1952
1953
// MARK - LSTM Layer
1954
1955
typedef struct {
1956
  ccv_cnnp_model_t super;
1957
  int masked;
1958
  ccv_nnc_tensor_symbol_t output;
1959
  ccv_nnc_tensor_symbol_t weights;
1960
  ccv_nnc_tensor_symbol_t reserves;
1961
  ccv_nnc_cmd_param_t params;
1962
  ccv_nnc_graph_exec_symbol_t lstm;
1963
} ccv_cnnp_model_lstm_t;
1964
1965
static int _ccv_cnnp_lstm_weight_dim(int bidirectional, int num_layers, int input_size, int hidden_size, int proj_size, int bias)
1966
4
{
1967
4
  const int D = !!bidirectional + 1;
1968
4
  if (hidden_size == proj_size)
1969
4
    return (num_layers * (bias ? 8 : 
00
) + (num_layers - 1) * (hidden_size * 4 * D + hidden_size * 4) + input_size * 4 + hidden_size * 4) * D;
1970
0
  else
1971
0
    return (num_layers * (bias ? 8 : 0) + (num_layers - 1) * (proj_size * 4 * D + proj_size * 4) + (proj_size * 4 + input_size * 4) + num_layers * proj_size) * D;
1972
4
}
1973
1974
static void _ccv_cnnp_lstm_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)
1975
4
{
1976
4
  ccv_cnnp_model_lstm_t* const self = (ccv_cnnp_model_lstm_t*)super;
1977
4
  assert(input_size == self->super.input_size);
1978
4
  assert(output_size == 1);
1979
4
  const int proj_size = self->params.rnn.proj_size == 0 ? self->params.rnn.hidden_size : 
self->params.rnn.proj_size0
;
1980
4
  ccv_nnc_tensor_param_t input_params[5];
1981
4
  input_params[0]= ccv_nnc_tensor_symbol_params(graph, inputs[0]);
1982
4
  if (input_size == 2)
1983
4
    input_params[1] = ccv_nnc_tensor_symbol_params(graph, inputs[1]);
1984
4
  input_params[4] = input_params[0];
1985
4
  memset(input_params[4].dim, 0, sizeof(input_params[4].dim));
1986
4
  const int x_nd = ccv_nnc_tensor_nd(input_params[0].dim);
1987
4
  const int feature_count = input_params[0].dim[x_nd - 1];
1988
4
  input_params[4].dim[0] = _ccv_cnnp_lstm_weight_dim(self->params.rnn.bidirectional, self->params.rnn.num_layers, feature_count, self->params.rnn.hidden_size, proj_size, self->params.rnn.bias);
1989
4
  input_params[4].dim[1] = self->params.rnn.hidden_size;
1990
4
  const ccv_nnc_cmd_t lstm = ccv_nnc_cmd(CCV_NNC_LSTM_FORWARD, 0, self->params, 0);
1991
4
  ccv_nnc_tensor_param_t output_params[4];
1992
4
  ccv_nnc_hint_tensor_auto(lstm, input_params, 5, ccv_nnc_no_hint, output_params, 4);
1993
4
  outputs[0] = ccv_nnc_tensor_symbol_new(graph, output_params[0], 0);
1994
4
  self->weights = ccv_nnc_tensor_symbol_new(graph, input_params[4], 0);
1995
4
  self->reserves = ccv_nnc_tensor_symbol_new(graph, output_params[3], 0);
1996
4
  const ccv_nnc_tensor_symbol_t mask = input_size == 2 ? inputs[1] : 
NO_TENSOR_SYMBOL0
;
1997
4
  self->lstm = ccv_nnc_graph_exec_symbol_new(graph, lstm, TENSOR_SYMBOL_LIST(inputs[0], mask, NO_TENSOR_SYMBOL, NO_TENSOR_SYMBOL, self->weights), TENSOR_SYMBOL_LIST(outputs[0], NO_TENSOR_SYMBOL, NO_TENSOR_SYMBOL, self->reserves), 0);
1998
4
}
1999
2000
static void _ccv_cnnp_lstm_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)
2001
1
{
2002
1
  ccv_cnnp_model_lstm_t* const self = (ccv_cnnp_model_lstm_t*)super;
2003
1
  if (self->weights.graph)
2004
1
  {
2005
1
    const float stdv = 1.0 / sqrt(self->params.rnn.hidden_size);
2006
1
    initializer(context, CMD_RANDOM_UNIFORM_FORWARD(-stdv, stdv), ccv_nnc_no_hint, 0, 0, self->weights);
2007
1
  }
2008
1
}
2009
2010
static void _ccv_cnnp_lstm_add_to_parameter(ccv_cnnp_model_t* const super, const ccv_cnnp_add_to_array_f add_to_array, void* const parameters)
2011
4
{
2012
4
  ccv_cnnp_model_lstm_t* const self = (ccv_cnnp_model_lstm_t*)super;
2013
4
  if (self->weights.graph)
2014
4
    add_to_array(parameters, self->weights);
2015
4
}
2016
2017
static void _ccv_cnnp_lstm_set_is_test(ccv_cnnp_model_t* const super, const int is_test, const ccv_cnnp_cmd_updater_f updater, void* const context)
2018
4
{
2019
4
  ccv_cnnp_model_lstm_t* const self = (ccv_cnnp_model_lstm_t*)super;
2020
4
  if (self->lstm.graph)
2021
4
  {
2022
4
    self->params.rnn.is_test = is_test;
2023
4
    updater(context, self->lstm, ccv_nnc_cmd(CCV_NNC_LSTM_FORWARD, 0, self->params, 0), ccv_nnc_no_hint);
2024
4
  }
2025
4
}
2026
2027
static ccv_cnnp_model_t* _ccv_cnnp_lstm_copy(const ccv_cnnp_model_t* const self, void* const context);
2028
2029
static const ccv_cnnp_model_vtab_t ccv_cnnp_lstm_isa = {
2030
  .build = _ccv_cnnp_lstm_build,
2031
  .init_states = _ccv_cnnp_lstm_init_states,
2032
  .add_to_parameter = _ccv_cnnp_lstm_add_to_parameter,
2033
  .copy = _ccv_cnnp_lstm_copy,
2034
  .set_is_test = _ccv_cnnp_lstm_set_is_test,
2035
};
2036
2037
ccv_cnnp_model_t* ccv_cnnp_lstm(const int masked, const int hidden_size, const int proj_size, const int num_layers, const int bias, const int batch_first, const int bidirectional, const float dropout, const char* const name)
2038
4
{
2039
4
  ccv_cnnp_model_lstm_t* const model_lstm = (ccv_cnnp_model_lstm_t*)cccalloc(1, sizeof(ccv_cnnp_model_lstm_t));
2040
4
  model_lstm->super.isa = &ccv_cnnp_lstm_isa;
2041
4
  model_lstm->super.input_size = masked ? 2 : 
10
;
2042
4
  model_lstm->super.outputs = &model_lstm->output;
2043
4
  model_lstm->super.output_size = 1;
2044
4
  ccv_cnnp_model_copy_name(&model_lstm->super, name);
2045
4
  model_lstm->masked = masked;
2046
4
  model_lstm->weights.d = CCV_NNC_NO_TENSOR_SYMBOL;
2047
4
  model_lstm->weights.graph = 0;
2048
4
  model_lstm->params.rnn.hidden_size = hidden_size;
2049
4
  model_lstm->params.rnn.proj_size = proj_size;
2050
4
  model_lstm->params.rnn.num_layers = num_layers;
2051
4
  model_lstm->params.rnn.bias = bias;
2052
4
  model_lstm->params.rnn.batch_first = batch_first;
2053
4
  model_lstm->params.rnn.bidirectional = bidirectional;
2054
4
  model_lstm->params.rnn.dropout = dropout;
2055
4
  return (ccv_cnnp_model_t*)model_lstm;
2056
4
}
2057
2058
static ccv_cnnp_model_t* _ccv_cnnp_lstm_copy(const ccv_cnnp_model_t* const super, void* const context)
2059
0
{
2060
0
  const ccv_cnnp_model_lstm_t* const self = (const ccv_cnnp_model_lstm_t*)super;
2061
0
  return ccv_cnnp_lstm(self->masked, self->params.rnn.hidden_size, self->params.rnn.proj_size, self->params.rnn.num_layers, self->params.rnn.bias, self->params.rnn.batch_first, self->params.rnn.bidirectional, self->params.rnn.dropout, self->super.name);
2062
0
}