Coverage Report

Created: 2024-12-10 23:11

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/home/liu/actions-runner/_work/ccv/ccv/lib/nnc/_ccv_cnnp_model.h
Line
Count
Source
1
/**********************************************************
2
 * C-based/Cached/Core Computer Vision Library
3
 * Liu Liu, 2010-02-01
4
 **********************************************************/
5
6
/**********************************************************
7
 * CCV - Neural Network Collection
8
 **********************************************************/
9
10
#ifndef GUARD_ccv_cnnp_model_internal_h
11
#define GUARD_ccv_cnnp_model_internal_h
12
13
#include "ccv_nnc.h"
14
#include "_ccv_nnc_stream.h"
15
#include "_ccv_nnc_xpu_alloc.h"
16
#include "3rdparty/khash/khash.h"
17
18
typedef void(*ccv_cnnp_cmd_updater_f)(void* const context, const ccv_nnc_graph_exec_symbol_t symbol, const ccv_nnc_cmd_t cmd, const ccv_nnc_hint_t hint);
19
typedef void(*ccv_cnnp_add_to_array_f)(void* const context, const ccv_nnc_tensor_symbol_t symbol, const int is_trainable);
20
/**
21
 * This is the virtual table of the model.
22
 */
23
typedef struct {
24
  void (*deinit)(ccv_cnnp_model_t* const self); /**< It can be nil. */
25
  void (*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); /**< Call this graph to build computation. No need to specify input size or output size, as it is defined along in the model already. */
26
  void (*init_states)(ccv_cnnp_model_t* const self, ccv_nnc_symbolic_graph_t* const graph, const ccv_cnnp_state_initializer_f initializer, void* const context); /**< This is called to init ccv_nnc_tensor_symbol_t with a exec. */
27
  void (*add_to_parameter)(ccv_cnnp_model_t* const self, const ccv_cnnp_add_to_array_f add_to_array, void* const parameters, const int is_trainable); /**< This is called to add ccv_nnc_tensor_symbol_t to as list of parameters. */
28
  void (*add_to_output)(ccv_cnnp_model_t* const self, const ccv_cnnp_add_to_array_f add_to_array, void* const outputs); /**< This is called to add ccv_nnc_tensor_symbol_t to as list of outputs for retention. The final outputs are already added. This method is optional for any additional values we want to retain. */
29
  ccv_cnnp_model_t* (*copy)(const ccv_cnnp_model_t* const self, void* const context); /**< This is called to make a deep copy of itself. */
30
  void (*set_is_test)(ccv_cnnp_model_t* const self, const int is_test, const ccv_cnnp_cmd_updater_f updater, void* const context); /**< This is called when it is switched between test or training. */
31
  void (*add_to_parameter_indices)(ccv_cnnp_model_t* const self, const int index, ccv_array_t* const parameter_indices); /**< This is called when we try to get parameter indices out of a given model */
32
  void (*notify)(const ccv_cnnp_model_t* const self, const int tag, void* const payload); /**< This is called when we want to notify something to this model. */
33
} ccv_cnnp_model_vtab_t;
34
35
struct ccv_cnnp_model_io_s {
36
  int param_ref; // Reference to parameter in the model, starts with 1. 0 means no such thing.
37
  int param_sel; // Selector to parameter in the model, starts with 1. 0 means no selector.
38
  int visit; // Temporary bits stored in the ccv_cnnp_model_io_t object, whoever uses it should clean it up.
39
  ccv_cnnp_model_t* model; // Reference back to the model who holds it. This is required because the model is the one whole holds the io.
40
  ccv_array_t* incomings; // Array of ccv_cnnp_model_io_t. The order is important because it impacts the order of symbols.
41
  ccv_array_t* dependencies; // Array of ccv_cnnp_model_io_t.
42
  int dependents; // Number of dependents.
43
  ccv_array_t* outgoings; // Array of ccv_cnnp_model_io_t.
44
  ccv_nnc_tensor_symbol_t* outputs; // This is different from the outputs from a model. A model could be reused, causing the outputs on that model to be the most recent one. This keeps the outputs of each.
45
};
46
47
enum {
48
  CCV_CNNP_MODEL_GRAPH_FIT_MODE, // This mode computes loss, backprop, and then apply gradients.
49
  CCV_CNNP_MODEL_GRAPH_MULTISTAGE_MODE_NO_GRAD, // This mode allows you to only use ccv_cnnp_model_evaluate (others require gradient).
50
  CCV_CNNP_MODEL_GRAPH_MULTISTAGE_MODE, // This mode allows you to use ccv_cnnp_model_evaluate, ccv_cnnp_model_backward, ccv_cnnp_model_apply_gradients separately.
51
};
52
53
enum {
54
  CCV_CNNP_COMPILED_DATA_GRADIENT_NONE,
55
  CCV_CNNP_COMPILED_DATA_GRADIENT_TRAINABLES,
56
  CCV_CNNP_COMPILED_DATA_GRADIENT_TRAINABLES_AND_INPUTS,
57
};
58
59
enum {
60
  CCV_CNNP_REWIND_GRAPH_EXEC,
61
  CCV_CNNP_REWIND_TENSOR,
62
};
63
64
typedef struct {
65
  int type;
66
  union {
67
    ccv_nnc_tensor_symbol_t tensor;
68
    ccv_nnc_graph_exec_symbol_t graph_exec;
69
  };
70
} ccv_cnnp_rewind_symbol_t;
71
72
1.49k
#define CCV_NNC_TENSOR(tv) ((ccv_nnc_tensor_t*)((uintptr_t)(tv) & ~(uintptr_t)1))
73
819
#define CCV_NNC_INIT_V(v) ((uint32_t*)((uintptr_t)(v) & ~(uintptr_t)1))
74
75
// This contains relevant information after model compilation.
76
typedef struct {
77
  int graph_mode;
78
  int gradient_mode; // Have init gradient graph.
79
  int is_test;
80
  int stream_type;
81
  int outgrad_size;
82
  uint64_t disable_outgrad;
83
  ccv_nnc_symbolic_graph_compile_param_t compile_params;
84
  ccv_nnc_xpu_alloc_t xpu_alloc;
85
  ccv_nnc_graph_t* graph;
86
  ccv_nnc_tensor_arena_t* tensor_arena;
87
  ccv_nnc_graph_exec_arena_t* graph_exec_arena;
88
  khash_t(stream_map)* stream_map; // Keeps track of streams on both GPU / CPU and devices so it can be used properly during execution.
89
  ccv_array_t* parameters;
90
  uint64_t* parameter_flags;
91
  ccv_array_t* internals; // Additional symbols need to retain.
92
  ccv_nnc_tensor_symbol_t* gradients;
93
  ccv_nnc_tensor_symbol_t* outgrads;
94
  ccv_nnc_tensor_symbol_t* updated_parameters;
95
  ccv_nnc_graph_exec_symbol_t* update_nodes;
96
  ccv_nnc_tensor_symbol_map_t* saved_aux;
97
  ccv_array_t* rewindables;
98
  ccv_array_t* gradient_checkpoints;
99
  struct {
100
    int size;
101
    uint32_t* v; // If the last is 1, we know it is incomplete (thus, the tensors_init_1 hasn't been called yet. This is to save RAM usage.
102
  } tensors_init;
103
  struct {
104
    ccv_nnc_tensor_t** internals; // Additional need to retained tensors.
105
    ccv_nnc_tensor_t** parameters;
106
    ccv_nnc_tensor_t** gradients;
107
    ccv_nnc_tensor_t** accum_gradients;
108
  } tensors;
109
  struct {
110
    ccv_array_t* parameters;
111
    ccv_array_t* internals;
112
  } ids;
113
  struct {
114
    int to_op_size;
115
    int to_size;
116
    ccv_nnc_graph_exec_t* to_ops;
117
    ccv_nnc_graph_exec_symbol_t* tos;
118
    ccv_nnc_graph_static_schedule_t* schedule; // The partial schedule for running evaluate step.
119
  } evaluate; // Data related to ccv_cnnp_model_evaluate
120
  struct {
121
    int count; // Called backward how many times. Starting with 0.
122
    int from_op_size;
123
    ccv_nnc_graph_exec_t* from_ops; // These are the ops in the main graph.
124
    int to_size;
125
    ccv_nnc_graph_exec_symbol_t* tos;
126
    ccv_nnc_graph_t* accum; // The graph to accumulate gradients.
127
    ccv_nnc_tensor_arena_t* tensor_arena;
128
    ccv_nnc_graph_exec_arena_t* graph_exec_arena;
129
    ccv_nnc_tensor_symbol_t* gradients; // The new gradients.
130
    ccv_nnc_tensor_symbol_t* accum_gradients; // The old accumulate gradients.
131
    ccv_nnc_tensor_symbol_t* updated_accum_gradients; // The new accumulate gradients.
132
    ccv_nnc_graph_static_schedule_t* schedule; // The partial schedule for running backward step.
133
  } backward;
134
  struct {
135
    ccv_nnc_graph_t* graph;
136
    ccv_nnc_tensor_arena_t* tensor_arena;
137
    ccv_nnc_graph_exec_arena_t* graph_exec_arena;
138
  } apply_gradients;
139
  struct {
140
    ccv_nnc_cmd_t minimizer;
141
    ccv_array_t* parameters;
142
    int max_saved_aux_size;
143
  } minimize;
144
  ccv_nnc_cmd_t loss;
145
  ccv_nnc_tensor_symbol_t* f;
146
  ccv_nnc_tensor_symbol_t fits[1];
147
} ccv_cnnp_compiled_data_t;
148
149
struct ccv_cnnp_model_s {
150
  const ccv_cnnp_model_vtab_t* isa;
151
  int input_size; // This is the best effort number, mostly just for subclass to use.
152
  int output_size;
153
  int max_stream_count;
154
  ccv_array_t* io; // The opaque io that can be nil.
155
  ccv_array_t* parameter_indices; // The indexes for parameters in the final model.
156
  ccv_nnc_symbolic_graph_t* graph;
157
  ccv_nnc_tensor_symbol_t* inputs; // Unlike outputs, which is not dynamically allocated, inputs is dynamically allocated, and may be 0.
158
  ccv_nnc_tensor_symbol_t* outputs;
159
  char* name;
160
  struct {
161
    ccv_cnnp_model_notify_f func;
162
    void* context;
163
  } notify_hook;
164
  ccv_cnnp_compiled_data_t* compiled_data;
165
  int parallel_count; // How many parallel devices.
166
  int memory_compression; // Whether to enable memory compression for training phase.
167
  int gradient_checkpointing; // Whether to enable gradient checkpointing for training phase.
168
  int is_trainable; // Whether this model can be trained or not.
169
  int memory_reduction; // Whether to enable memory reduction techniques for training phase.
170
  size_t workspace_size; // Set the default workspace size.
171
  struct {
172
    ccv_cnnp_model_io_reader_f reader;
173
    ccv_cnnp_model_io_writer_f writer;
174
  } rw;
175
  void* data; // Temporary storage for some internal functions.
176
};
177
178
KHASH_MAP_INIT_STR(ccv_cnnp_model_name_bank, int)
179
180
typedef struct {
181
  int sequence;
182
  khash_t(ccv_cnnp_model_name_bank)* bank;
183
  const char* name;
184
} ccv_cnnp_model_name_t;
185
186
typedef struct {
187
  int it;
188
  ccv_cnnp_model_t* model;
189
  khash_t(ccv_cnnp_model_name_bank)* bank;
190
  ccv_array_t* sequences;
191
} ccv_cnnp_model_sequence_t;
192
193
static inline void ccv_cnnp_model_push(ccv_cnnp_model_t* const self, ccv_cnnp_model_sequence_t* const model_sequence)
194
2.71k
{
195
  // Reset to 0.
196
2.71k
  if (!model_sequence->sequences)
197
2.28k
    model_sequence->sequences = ccv_array_new(sizeof(ccv_cnnp_model_name_t), 1, 0);
198
2.71k
  khash_t(ccv_cnnp_model_name_bank)* bank = model_sequence->sequences->rnum > 0 ? 
((ccv_cnnp_model_name_t*)180
ccv_array_get180
(model_sequence->sequences, model_sequence->sequences->rnum - 1))->bank :
model_sequence->bank2.53k
;
199
2.71k
  int ret;
200
2.71k
  khiter_t k = kh_put(ccv_cnnp_model_name_bank, bank, self->name ? self->name : "", &ret);
201
2.71k
  int sequence;
202
2.71k
  if (ret != 0)
203
2.46k
    sequence = kh_val(bank, k) = 0;
204
256
  else
205
256
    sequence = ++kh_val(bank, k);
206
2.71k
  ccv_cnnp_model_name_t name = {
207
2.71k
    .bank = kh_init(ccv_cnnp_model_name_bank),
208
2.71k
    .name = self->name,
209
2.71k
    .sequence = sequence,
210
2.71k
  };
211
2.71k
  ccv_array_push(model_sequence->sequences, &name);
212
2.71k
  model_sequence->model = self;
213
2.71k
}
Unexecuted instantiation: ccv_nnc_dynamic_graph_evaluate.c:ccv_cnnp_model_push
ccv_cnnp_model.c:ccv_cnnp_model_push
Line
Count
Source
194
1.23k
{
195
  // Reset to 0.
196
1.23k
  if (!model_sequence->sequences)
197
1.23k
    model_sequence->sequences = ccv_array_new(sizeof(ccv_cnnp_model_name_t), 1, 0);
198
1.23k
  khash_t(ccv_cnnp_model_name_bank)* bank = model_sequence->sequences->rnum > 0 ? 
((ccv_cnnp_model_name_t*)0
ccv_array_get0
(model_sequence->sequences, model_sequence->sequences->rnum - 1))->bank : model_sequence->bank;
199
1.23k
  int ret;
200
1.23k
  khiter_t k = kh_put(ccv_cnnp_model_name_bank, bank, self->name ? self->name : "", &ret);
201
1.23k
  int sequence;
202
1.23k
  if (ret != 0)
203
1.23k
    sequence = kh_val(bank, k) = 0;
204
0
  else
205
0
    sequence = ++kh_val(bank, k);
206
1.23k
  ccv_cnnp_model_name_t name = {
207
1.23k
    .bank = kh_init(ccv_cnnp_model_name_bank),
208
1.23k
    .name = self->name,
209
1.23k
    .sequence = sequence,
210
1.23k
  };
211
1.23k
  ccv_array_push(model_sequence->sequences, &name);
212
1.23k
  model_sequence->model = self;
213
1.23k
}
Unexecuted instantiation: ccv_cnnp_model_io.c:ccv_cnnp_model_push
ccv_cnnp_model_core.c:ccv_cnnp_model_push
Line
Count
Source
194
1.48k
{
195
  // Reset to 0.
196
1.48k
  if (!model_sequence->sequences)
197
1.04k
    model_sequence->sequences = ccv_array_new(sizeof(ccv_cnnp_model_name_t), 1, 0);
198
1.48k
  khash_t(ccv_cnnp_model_name_bank)* bank = model_sequence->sequences->rnum > 0 ? 
((ccv_cnnp_model_name_t*)180
ccv_array_get180
(model_sequence->sequences, model_sequence->sequences->rnum - 1))->bank :
model_sequence->bank1.30k
;
199
1.48k
  int ret;
200
1.48k
  khiter_t k = kh_put(ccv_cnnp_model_name_bank, bank, self->name ? self->name : "", &ret);
201
1.48k
  int sequence;
202
1.48k
  if (ret != 0)
203
1.22k
    sequence = kh_val(bank, k) = 0;
204
256
  else
205
256
    sequence = ++kh_val(bank, k);
206
1.48k
  ccv_cnnp_model_name_t name = {
207
1.48k
    .bank = kh_init(ccv_cnnp_model_name_bank),
208
1.48k
    .name = self->name,
209
1.48k
    .sequence = sequence,
210
1.48k
  };
211
1.48k
  ccv_array_push(model_sequence->sequences, &name);
212
1.48k
  model_sequence->model = self;
213
1.48k
}
Unexecuted instantiation: ccv_cnnp_model_addons.c:ccv_cnnp_model_push
Unexecuted instantiation: ccv_cnnp_model_gradient_checkpointing.c:ccv_cnnp_model_push
214
215
static inline void ccv_cnnp_model_pop(const ccv_cnnp_model_t* const self, ccv_cnnp_model_sequence_t* const model_sequence)
216
2.71k
{
217
2.71k
  khash_t(ccv_cnnp_model_name_bank)* const bank = ((ccv_cnnp_model_name_t*)ccv_array_get(model_sequence->sequences, model_sequence->sequences->rnum - 1))->bank;
218
2.71k
  kh_destroy(ccv_cnnp_model_name_bank, bank);
219
2.71k
  --model_sequence->sequences->rnum;
220
2.71k
  assert(model_sequence->sequences->rnum >= 0);
221
2.71k
  model_sequence->model = 0;
222
2.71k
}
Unexecuted instantiation: ccv_nnc_dynamic_graph_evaluate.c:ccv_cnnp_model_pop
ccv_cnnp_model.c:ccv_cnnp_model_pop
Line
Count
Source
216
1.23k
{
217
1.23k
  khash_t(ccv_cnnp_model_name_bank)* const bank = ((ccv_cnnp_model_name_t*)ccv_array_get(model_sequence->sequences, model_sequence->sequences->rnum - 1))->bank;
218
1.23k
  kh_destroy(ccv_cnnp_model_name_bank, bank);
219
1.23k
  --model_sequence->sequences->rnum;
220
1.23k
  assert(model_sequence->sequences->rnum >= 0);
221
1.23k
  model_sequence->model = 0;
222
1.23k
}
Unexecuted instantiation: ccv_cnnp_model_io.c:ccv_cnnp_model_pop
ccv_cnnp_model_core.c:ccv_cnnp_model_pop
Line
Count
Source
216
1.48k
{
217
1.48k
  khash_t(ccv_cnnp_model_name_bank)* const bank = ((ccv_cnnp_model_name_t*)ccv_array_get(model_sequence->sequences, model_sequence->sequences->rnum - 1))->bank;
218
1.48k
  kh_destroy(ccv_cnnp_model_name_bank, bank);
219
1.48k
  --model_sequence->sequences->rnum;
220
1.48k
  assert(model_sequence->sequences->rnum >= 0);
221
1.48k
  model_sequence->model = 0;
222
1.48k
}
Unexecuted instantiation: ccv_cnnp_model_addons.c:ccv_cnnp_model_pop
Unexecuted instantiation: ccv_cnnp_model_gradient_checkpointing.c:ccv_cnnp_model_pop
223
224
static inline ccv_cnnp_model_t* _ccv_cnnp_model_copy(const ccv_cnnp_model_t* const model, void* const context)
225
4.30k
{
226
4.30k
  assert(model->isa->copy);
227
4.30k
  ccv_cnnp_model_t* const copy = model->isa->copy(model, context);
228
4.30k
  copy->parallel_count = model->parallel_count;
229
4.30k
  copy->memory_compression = model->memory_compression;
230
4.30k
  copy->memory_reduction = model->memory_reduction;
231
4.30k
  copy->max_stream_count = model->max_stream_count;
232
4.30k
  copy->gradient_checkpointing = model->gradient_checkpointing;
233
4.30k
  return copy;
234
4.30k
}
Unexecuted instantiation: ccv_nnc_dynamic_graph_evaluate.c:_ccv_cnnp_model_copy
ccv_cnnp_model.c:_ccv_cnnp_model_copy
Line
Count
Source
225
2.20k
{
226
2.20k
  assert(model->isa->copy);
227
2.20k
  ccv_cnnp_model_t* const copy = model->isa->copy(model, context);
228
2.20k
  copy->parallel_count = model->parallel_count;
229
2.20k
  copy->memory_compression = model->memory_compression;
230
2.20k
  copy->memory_reduction = model->memory_reduction;
231
2.20k
  copy->max_stream_count = model->max_stream_count;
232
2.20k
  copy->gradient_checkpointing = model->gradient_checkpointing;
233
2.20k
  return copy;
234
2.20k
}
Unexecuted instantiation: ccv_cnnp_model_io.c:_ccv_cnnp_model_copy
ccv_cnnp_model_core.c:_ccv_cnnp_model_copy
Line
Count
Source
225
2.09k
{
226
2.09k
  assert(model->isa->copy);
227
2.09k
  ccv_cnnp_model_t* const copy = model->isa->copy(model, context);
228
2.09k
  copy->parallel_count = model->parallel_count;
229
2.09k
  copy->memory_compression = model->memory_compression;
230
2.09k
  copy->memory_reduction = model->memory_reduction;
231
2.09k
  copy->max_stream_count = model->max_stream_count;
232
2.09k
  copy->gradient_checkpointing = model->gradient_checkpointing;
233
2.09k
  return copy;
234
2.09k
}
Unexecuted instantiation: ccv_cnnp_model_addons.c:_ccv_cnnp_model_copy
Unexecuted instantiation: ccv_cnnp_model_gradient_checkpointing.c:_ccv_cnnp_model_copy
235
236
static inline void ccv_cnnp_model_copy_name(ccv_cnnp_model_t* const self, const char* const name)
237
5.24k
{
238
5.24k
  if (name)
239
198
  {
240
198
    const size_t len = strnlen(name, 63);
241
198
    const size_t n = len + 1;
242
198
    self->name = (char*)ccmalloc(n);
243
    // Don't use strndup because this way I can have custom allocator (for ccmalloc).
244
198
    memcpy(self->name, name, n);
245
198
    self->name[len] = 0;
246
198
  }
247
5.24k
}
Unexecuted instantiation: ccv_nnc_dynamic_graph_evaluate.c:ccv_cnnp_model_copy_name
Unexecuted instantiation: ccv_cnnp_model.c:ccv_cnnp_model_copy_name
Unexecuted instantiation: ccv_cnnp_model_io.c:ccv_cnnp_model_copy_name
ccv_cnnp_model_core.c:ccv_cnnp_model_copy_name
Line
Count
Source
237
1.28k
{
238
1.28k
  if (name)
239
72
  {
240
72
    const size_t len = strnlen(name, 63);
241
72
    const size_t n = len + 1;
242
72
    self->name = (char*)ccmalloc(n);
243
    // Don't use strndup because this way I can have custom allocator (for ccmalloc).
244
72
    memcpy(self->name, name, n);
245
72
    self->name[len] = 0;
246
72
  }
247
1.28k
}
ccv_cnnp_model_addons.c:ccv_cnnp_model_copy_name
Line
Count
Source
237
3.95k
{
238
3.95k
  if (name)
239
126
  {
240
126
    const size_t len = strnlen(name, 63);
241
126
    const size_t n = len + 1;
242
126
    self->name = (char*)ccmalloc(n);
243
    // Don't use strndup because this way I can have custom allocator (for ccmalloc).
244
126
    memcpy(self->name, name, n);
245
126
    self->name[len] = 0;
246
126
  }
247
3.95k
}
Unexecuted instantiation: ccv_cnnp_model_gradient_checkpointing.c:ccv_cnnp_model_copy_name
248
249
static inline void ccv_cnnp_model_add_to_parameter(ccv_cnnp_model_t* const self, const ccv_cnnp_add_to_array_f add_to_array, void* const parameters, const int is_trainable)
250
2.61k
{
251
2.61k
  if (self->isa->add_to_parameter)
252
2.61k
    self->isa->add_to_parameter(self, add_to_array, parameters, is_trainable);
253
2.61k
}
Unexecuted instantiation: ccv_nnc_dynamic_graph_evaluate.c:ccv_cnnp_model_add_to_parameter
ccv_cnnp_model.c:ccv_cnnp_model_add_to_parameter
Line
Count
Source
250
1.20k
{
251
1.20k
  if (self->isa->add_to_parameter)
252
1.20k
    self->isa->add_to_parameter(self, add_to_array, parameters, is_trainable);
253
1.20k
}
Unexecuted instantiation: ccv_cnnp_model_io.c:ccv_cnnp_model_add_to_parameter
ccv_cnnp_model_core.c:ccv_cnnp_model_add_to_parameter
Line
Count
Source
250
1.40k
{
251
1.40k
  if (self->isa->add_to_parameter)
252
1.40k
    self->isa->add_to_parameter(self, add_to_array, parameters, is_trainable);
253
1.40k
}
Unexecuted instantiation: ccv_cnnp_model_addons.c:ccv_cnnp_model_add_to_parameter
Unexecuted instantiation: ccv_cnnp_model_gradient_checkpointing.c:ccv_cnnp_model_add_to_parameter
254
255
static inline void ccv_cnnp_model_add_to_output(ccv_cnnp_model_t* const self, const ccv_cnnp_add_to_array_f add_to_array, void* const outputs)
256
2.61k
{
257
2.61k
  if (self->isa->add_to_output)
258
156
    self->isa->add_to_output(self, add_to_array, outputs);
259
2.61k
}
Unexecuted instantiation: ccv_nnc_dynamic_graph_evaluate.c:ccv_cnnp_model_add_to_output
ccv_cnnp_model.c:ccv_cnnp_model_add_to_output
Line
Count
Source
256
1.20k
{
257
1.20k
  if (self->isa->add_to_output)
258
0
    self->isa->add_to_output(self, add_to_array, outputs);
259
1.20k
}
Unexecuted instantiation: ccv_cnnp_model_io.c:ccv_cnnp_model_add_to_output
ccv_cnnp_model_core.c:ccv_cnnp_model_add_to_output
Line
Count
Source
256
1.40k
{
257
1.40k
  if (self->isa->add_to_output)
258
156
    self->isa->add_to_output(self, add_to_array, outputs);
259
1.40k
}
Unexecuted instantiation: ccv_cnnp_model_addons.c:ccv_cnnp_model_add_to_output
Unexecuted instantiation: ccv_cnnp_model_gradient_checkpointing.c:ccv_cnnp_model_add_to_output
260
261
typedef struct {
262
  int is_trainable;
263
  int is_gradient_checkpointing;
264
  ccv_cnnp_model_sequence_t* model_sequence;
265
  ccv_cnnp_add_to_array_f add_to_array;
266
  ccv_array_t* parameters;
267
  struct {
268
    void* add_to_parameter;
269
    void* add_to_output;
270
  } context;
271
  ccv_array_t* gradient_checkpoints;
272
} ccv_cnnp_model_build_data_t; // Host temporary data for building models.
273
274
typedef struct {
275
  int input_size;
276
  int output_size;
277
  int is_trainable;
278
  ccv_cnnp_model_t* model;
279
  void (*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);
280
  ccv_array_t* tensor_symbols;
281
  ccv_nnc_tensor_symbol_t* inputs;
282
  ccv_nnc_tensor_symbol_t* outputs;
283
} ccv_cnnp_model_gradient_checkpoint_t;
284
285
static inline ccv_nnc_tensor_symbol_t ccv_cnnp_parameter_from_indice(ccv_cnnp_model_t* const self, const int indice)
286
2
{
287
2
  assert(self->data);
288
2
  ccv_cnnp_model_build_data_t* const build_data = (ccv_cnnp_model_build_data_t*)self->data;
289
2
  assert(indice < build_data->parameters->rnum);
290
2
  return *(ccv_nnc_tensor_symbol_t*)ccv_array_get(build_data->parameters, indice);
291
2
}
Unexecuted instantiation: ccv_nnc_dynamic_graph_evaluate.c:ccv_cnnp_parameter_from_indice
Unexecuted instantiation: ccv_cnnp_model.c:ccv_cnnp_parameter_from_indice
Unexecuted instantiation: ccv_cnnp_model_io.c:ccv_cnnp_parameter_from_indice
ccv_cnnp_model_core.c:ccv_cnnp_parameter_from_indice
Line
Count
Source
286
2
{
287
2
  assert(self->data);
288
2
  ccv_cnnp_model_build_data_t* const build_data = (ccv_cnnp_model_build_data_t*)self->data;
289
2
  assert(indice < build_data->parameters->rnum);
290
2
  return *(ccv_nnc_tensor_symbol_t*)ccv_array_get(build_data->parameters, indice);
291
2
}
Unexecuted instantiation: ccv_cnnp_model_addons.c:ccv_cnnp_parameter_from_indice
Unexecuted instantiation: ccv_cnnp_model_gradient_checkpointing.c:ccv_cnnp_parameter_from_indice
292
293
typedef struct {
294
  int record;
295
  ccv_array_t* tensor_symbols;
296
  void* old_tensor_symbol_new_hook_context;
297
  ccv_nnc_tensor_symbol_new_hook_f old_tensor_symbol_new_hook;
298
  void* old_tensor_symbol_alias_new_hook_context;
299
  ccv_nnc_tensor_symbol_alias_new_hook_f old_tensor_symbol_alias_new_hook;
300
} ccv_cnnp_model_gradient_checkpoint_build_context_t;
301
302
static void _ccv_cnnp_model_gradient_checkpoint_tensor_symbol_new_hook(void* context, const ccv_nnc_tensor_symbol_t symbol, const ccv_nnc_tensor_param_t info, const char* const name)
303
30
{
304
30
  ccv_cnnp_model_gradient_checkpoint_build_context_t* const build_context = (ccv_cnnp_model_gradient_checkpoint_build_context_t*)context;
305
30
  if (build_context->record)
306
30
    ccv_array_push(build_context->tensor_symbols, &symbol);
307
30
  if (build_context->old_tensor_symbol_new_hook)
308
0
    build_context->old_tensor_symbol_new_hook(build_context->old_tensor_symbol_new_hook_context, symbol, info, name);
309
30
}
Unexecuted instantiation: ccv_nnc_dynamic_graph_evaluate.c:_ccv_cnnp_model_gradient_checkpoint_tensor_symbol_new_hook
ccv_cnnp_model.c:_ccv_cnnp_model_gradient_checkpoint_tensor_symbol_new_hook
Line
Count
Source
303
30
{
304
30
  ccv_cnnp_model_gradient_checkpoint_build_context_t* const build_context = (ccv_cnnp_model_gradient_checkpoint_build_context_t*)context;
305
30
  if (build_context->record)
306
30
    ccv_array_push(build_context->tensor_symbols, &symbol);
307
30
  if (build_context->old_tensor_symbol_new_hook)
308
0
    build_context->old_tensor_symbol_new_hook(build_context->old_tensor_symbol_new_hook_context, symbol, info, name);
309
30
}
Unexecuted instantiation: ccv_cnnp_model_io.c:_ccv_cnnp_model_gradient_checkpoint_tensor_symbol_new_hook
Unexecuted instantiation: ccv_cnnp_model_core.c:_ccv_cnnp_model_gradient_checkpoint_tensor_symbol_new_hook
Unexecuted instantiation: ccv_cnnp_model_addons.c:_ccv_cnnp_model_gradient_checkpoint_tensor_symbol_new_hook
Unexecuted instantiation: ccv_cnnp_model_gradient_checkpointing.c:_ccv_cnnp_model_gradient_checkpoint_tensor_symbol_new_hook
310
311
static void _ccv_cnnp_model_gradient_checkpoint_tensor_symbol_alias_new_hook(void* context, const ccv_nnc_tensor_symbol_t symbol, const ccv_nnc_tensor_symbol_t from_symbol, const int ofs[CCV_NNC_MAX_DIM_ALLOC], const int inc[CCV_NNC_MAX_DIM_ALLOC], const ccv_nnc_tensor_param_t info, const char* const name)
312
0
{
313
0
  ccv_cnnp_model_gradient_checkpoint_build_context_t* const build_context = (ccv_cnnp_model_gradient_checkpoint_build_context_t*)context;
314
0
  if (build_context->record)
315
0
    ccv_array_push(build_context->tensor_symbols, &symbol);
316
0
  if (build_context->old_tensor_symbol_alias_new_hook)
317
0
    build_context->old_tensor_symbol_alias_new_hook(build_context->old_tensor_symbol_alias_new_hook_context, symbol, from_symbol, ofs, inc, info, name);
318
0
}
Unexecuted instantiation: ccv_nnc_dynamic_graph_evaluate.c:_ccv_cnnp_model_gradient_checkpoint_tensor_symbol_alias_new_hook
Unexecuted instantiation: ccv_cnnp_model.c:_ccv_cnnp_model_gradient_checkpoint_tensor_symbol_alias_new_hook
Unexecuted instantiation: ccv_cnnp_model_io.c:_ccv_cnnp_model_gradient_checkpoint_tensor_symbol_alias_new_hook
Unexecuted instantiation: ccv_cnnp_model_core.c:_ccv_cnnp_model_gradient_checkpoint_tensor_symbol_alias_new_hook
Unexecuted instantiation: ccv_cnnp_model_addons.c:_ccv_cnnp_model_gradient_checkpoint_tensor_symbol_alias_new_hook
Unexecuted instantiation: ccv_cnnp_model_gradient_checkpointing.c:_ccv_cnnp_model_gradient_checkpoint_tensor_symbol_alias_new_hook
319
320
static inline void ccv_cnnp_model_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)
321
5.20k
{
322
5.20k
  assert(self->data);
323
5.20k
  ccv_cnnp_model_build_data_t* const build_data = (ccv_cnnp_model_build_data_t*)self->data;
324
5.20k
  const int old_is_trainable = build_data->is_trainable;
325
5.20k
  if (self->is_trainable >= 0)
326
5.19k
    build_data->is_trainable = self->is_trainable;
327
5.20k
  if (self->name && 
self->name[0] != '\0'230
)
328
230
    ccv_cnnp_model_push(self, build_data->model_sequence);
329
5.20k
  if (self->gradient_checkpointing == 1 && 
!build_data->is_gradient_checkpointing2
)
330
2
  {
331
2
    build_data->is_gradient_checkpointing = 1;
332
    // Prepare to record gradient checkpoint. We will log the build function, inputs, what are the tensors / graph execs we created.
333
2
    if (!build_data->gradient_checkpoints)
334
2
      build_data->gradient_checkpoints = ccv_array_new(sizeof(ccv_cnnp_model_gradient_checkpoint_t), 0, 0);
335
2
    ccv_cnnp_model_gradient_checkpoint_build_context_t build_context = {
336
2
      .record = 1,
337
2
      .tensor_symbols = ccv_array_new(sizeof(ccv_nnc_tensor_symbol_t), 0, 0),
338
2
    };
339
2
    build_context.old_tensor_symbol_new_hook_context = ccv_nnc_tensor_symbol_new_hook(graph, _ccv_cnnp_model_gradient_checkpoint_tensor_symbol_new_hook, &build_context, &build_context.old_tensor_symbol_new_hook);
340
2
    build_context.old_tensor_symbol_alias_new_hook_context = ccv_nnc_tensor_symbol_alias_new_hook(graph, _ccv_cnnp_model_gradient_checkpoint_tensor_symbol_alias_new_hook, &build_context, &build_context.old_tensor_symbol_alias_new_hook);
341
2
    if (outputs && 
output_size0
)
342
0
    {
343
0
      assert(output_size == self->output_size);
344
0
      self->isa->build(self, graph, inputs, input_size, outputs, output_size);
345
0
      memcpy(self->outputs, outputs, sizeof(ccv_nnc_tensor_symbol_t) * output_size);
346
0
    } else
347
2
      self->isa->build(self, graph, inputs, input_size, self->outputs, self->output_size);
348
2
    ccv_nnc_tensor_symbol_new_hook(graph, build_context.old_tensor_symbol_new_hook, build_context.old_tensor_symbol_new_hook_context, 0);
349
2
    ccv_nnc_tensor_symbol_alias_new_hook(graph, build_context.old_tensor_symbol_alias_new_hook, build_context.old_tensor_symbol_alias_new_hook_context, 0);
350
2
    ccv_cnnp_model_gradient_checkpoint_t checkpoint = {
351
2
      .input_size = input_size,
352
2
      .output_size = (outputs && 
output_size > 00
) ?
output_size0
: self->output_size,
353
2
      .is_trainable = build_data->is_trainable,
354
2
      .model = self,
355
2
      .build = self->isa->build,
356
2
      .tensor_symbols = build_context.tensor_symbols,
357
2
      .inputs = ccmalloc(sizeof(ccv_nnc_tensor_symbol_t) * (input_size + ((outputs && 
output_size > 00
) ?
output_size0
: self->output_size))),
358
2
    };
359
2
    checkpoint.outputs = checkpoint.inputs + input_size;
360
2
    if (input_size > 0)
361
2
      memcpy(checkpoint.inputs, inputs, sizeof(ccv_nnc_tensor_symbol_t) * input_size);
362
2
    if (outputs && 
output_size > 00
)
363
0
      memcpy(checkpoint.outputs, outputs, sizeof(ccv_nnc_tensor_symbol_t) * output_size);
364
2
    else if (self->outputs && self->output_size > 0)
365
2
      memcpy(checkpoint.outputs, self->outputs, sizeof(ccv_nnc_tensor_symbol_t) * self->output_size);
366
2
    ccv_array_push(build_data->gradient_checkpoints, &checkpoint);
367
2
    build_data->is_gradient_checkpointing = 0;
368
5.20k
  } else {
369
    // If we want to disable gradient checkpointing for this model, we simply not log any new tensors created here so there is no mapping for these.
370
5.20k
    int old_record;
371
5.20k
    ccv_cnnp_model_gradient_checkpoint_build_context_t* build_context = 0;
372
5.20k
    if (build_data->is_gradient_checkpointing)
373
36
    {
374
36
      if (self->gradient_checkpointing == -1)
375
0
      {
376
0
        ccv_nnc_tensor_symbol_new_hook_f old_tensor_symbol_new_hook;
377
0
        build_context = ccv_nnc_tensor_symbol_new_hook(graph, 0, 0, &old_tensor_symbol_new_hook);
378
        // Set back the build_context.
379
0
        ccv_nnc_tensor_symbol_new_hook(graph, old_tensor_symbol_new_hook, build_context, 0);
380
0
        old_record = build_context->record;
381
0
        build_context->record = 0;
382
36
      } else if (self->gradient_checkpointing == 1) { // Force to turn on gradient checkpointing if it is inside a gradient checkpointing = -1.
383
0
        ccv_nnc_tensor_symbol_new_hook_f old_tensor_symbol_new_hook;
384
0
        build_context = ccv_nnc_tensor_symbol_new_hook(graph, 0, 0, &old_tensor_symbol_new_hook);
385
        // Set back the build_context.
386
0
        ccv_nnc_tensor_symbol_new_hook(graph, old_tensor_symbol_new_hook, build_context, 0);
387
0
        old_record = build_context->record;
388
0
        build_context->record = 1;
389
0
      }
390
36
    }
391
    // No push checkpoint, easy.
392
5.20k
    if (outputs && 
output_size2.91k
)
393
2.91k
    {
394
2.91k
      assert(output_size == self->output_size);
395
2.91k
      self->isa->build(self, graph, inputs, input_size, outputs, output_size);
396
2.91k
      memcpy(self->outputs, outputs, sizeof(ccv_nnc_tensor_symbol_t) * output_size);
397
2.91k
    } else
398
2.29k
      self->isa->build(self, graph, inputs, input_size, self->outputs, self->output_size);
399
5.20k
    if (build_context) // Restore previous state even if our gradient checkpointing controlled whether to turn on recording or not.
400
0
      build_context->record = old_record;
401
5.20k
  }
402
  // Skip if there is none. This helps to load parameters to a different model when only changes non-parameterized settings (add reshapes, permutations etc).
403
  // If it is named, we have to push too.
404
5.20k
  if (self->isa->add_to_parameter || 
self->isa->add_to_output2.59k
)
405
2.61k
  {
406
    // If we already pushed, no need to push again.
407
2.61k
    if (!(self->name && 
self->name[0] != '\0'124
))
408
2.48k
      ccv_cnnp_model_push(self, build_data->model_sequence);
409
2.61k
    build_data->model_sequence->it = 0;
410
2.61k
    ccv_cnnp_model_add_to_parameter(self, build_data->add_to_array, build_data->context.add_to_parameter, build_data->is_trainable);
411
2.61k
    build_data->model_sequence->it = 0;
412
2.61k
    ccv_cnnp_model_add_to_output(self, build_data->add_to_array, build_data->context.add_to_output);
413
2.61k
    ccv_cnnp_model_pop(self, build_data->model_sequence);
414
2.61k
  } else 
if (2.59k
self->name2.59k
&&
self->name[0] != '\0'106
)
415
106
    ccv_cnnp_model_pop(self, build_data->model_sequence);
416
5.20k
  build_data->is_trainable = old_is_trainable;
417
5.20k
}
Unexecuted instantiation: ccv_nnc_dynamic_graph_evaluate.c:ccv_cnnp_model_build
ccv_cnnp_model.c:ccv_cnnp_model_build
Line
Count
Source
321
2.29k
{
322
2.29k
  assert(self->data);
323
2.29k
  ccv_cnnp_model_build_data_t* const build_data = (ccv_cnnp_model_build_data_t*)self->data;
324
2.29k
  const int old_is_trainable = build_data->is_trainable;
325
2.29k
  if (self->is_trainable >= 0)
326
2.28k
    build_data->is_trainable = self->is_trainable;
327
2.29k
  if (self->name && 
self->name[0] != '\0'33
)
328
33
    ccv_cnnp_model_push(self, build_data->model_sequence);
329
2.29k
  if (self->gradient_checkpointing == 1 && 
!build_data->is_gradient_checkpointing2
)
330
2
  {
331
2
    build_data->is_gradient_checkpointing = 1;
332
    // Prepare to record gradient checkpoint. We will log the build function, inputs, what are the tensors / graph execs we created.
333
2
    if (!build_data->gradient_checkpoints)
334
2
      build_data->gradient_checkpoints = ccv_array_new(sizeof(ccv_cnnp_model_gradient_checkpoint_t), 0, 0);
335
2
    ccv_cnnp_model_gradient_checkpoint_build_context_t build_context = {
336
2
      .record = 1,
337
2
      .tensor_symbols = ccv_array_new(sizeof(ccv_nnc_tensor_symbol_t), 0, 0),
338
2
    };
339
2
    build_context.old_tensor_symbol_new_hook_context = ccv_nnc_tensor_symbol_new_hook(graph, _ccv_cnnp_model_gradient_checkpoint_tensor_symbol_new_hook, &build_context, &build_context.old_tensor_symbol_new_hook);
340
2
    build_context.old_tensor_symbol_alias_new_hook_context = ccv_nnc_tensor_symbol_alias_new_hook(graph, _ccv_cnnp_model_gradient_checkpoint_tensor_symbol_alias_new_hook, &build_context, &build_context.old_tensor_symbol_alias_new_hook);
341
2
    if (outputs && 
output_size0
)
342
0
    {
343
0
      assert(output_size == self->output_size);
344
0
      self->isa->build(self, graph, inputs, input_size, outputs, output_size);
345
0
      memcpy(self->outputs, outputs, sizeof(ccv_nnc_tensor_symbol_t) * output_size);
346
0
    } else
347
2
      self->isa->build(self, graph, inputs, input_size, self->outputs, self->output_size);
348
2
    ccv_nnc_tensor_symbol_new_hook(graph, build_context.old_tensor_symbol_new_hook, build_context.old_tensor_symbol_new_hook_context, 0);
349
2
    ccv_nnc_tensor_symbol_alias_new_hook(graph, build_context.old_tensor_symbol_alias_new_hook, build_context.old_tensor_symbol_alias_new_hook_context, 0);
350
2
    ccv_cnnp_model_gradient_checkpoint_t checkpoint = {
351
2
      .input_size = input_size,
352
2
      .output_size = (outputs && 
output_size > 00
) ?
output_size0
: self->output_size,
353
2
      .is_trainable = build_data->is_trainable,
354
2
      .model = self,
355
2
      .build = self->isa->build,
356
2
      .tensor_symbols = build_context.tensor_symbols,
357
2
      .inputs = ccmalloc(sizeof(ccv_nnc_tensor_symbol_t) * (input_size + ((outputs && 
output_size > 00
) ?
output_size0
: self->output_size))),
358
2
    };
359
2
    checkpoint.outputs = checkpoint.inputs + input_size;
360
2
    if (input_size > 0)
361
2
      memcpy(checkpoint.inputs, inputs, sizeof(ccv_nnc_tensor_symbol_t) * input_size);
362
2
    if (outputs && 
output_size > 00
)
363
0
      memcpy(checkpoint.outputs, outputs, sizeof(ccv_nnc_tensor_symbol_t) * output_size);
364
2
    else if (self->outputs && self->output_size > 0)
365
2
      memcpy(checkpoint.outputs, self->outputs, sizeof(ccv_nnc_tensor_symbol_t) * self->output_size);
366
2
    ccv_array_push(build_data->gradient_checkpoints, &checkpoint);
367
2
    build_data->is_gradient_checkpointing = 0;
368
2.29k
  } else {
369
    // If we want to disable gradient checkpointing for this model, we simply not log any new tensors created here so there is no mapping for these.
370
2.29k
    int old_record;
371
2.29k
    ccv_cnnp_model_gradient_checkpoint_build_context_t* build_context = 0;
372
2.29k
    if (build_data->is_gradient_checkpointing)
373
0
    {
374
0
      if (self->gradient_checkpointing == -1)
375
0
      {
376
0
        ccv_nnc_tensor_symbol_new_hook_f old_tensor_symbol_new_hook;
377
0
        build_context = ccv_nnc_tensor_symbol_new_hook(graph, 0, 0, &old_tensor_symbol_new_hook);
378
        // Set back the build_context.
379
0
        ccv_nnc_tensor_symbol_new_hook(graph, old_tensor_symbol_new_hook, build_context, 0);
380
0
        old_record = build_context->record;
381
0
        build_context->record = 0;
382
0
      } else if (self->gradient_checkpointing == 1) { // Force to turn on gradient checkpointing if it is inside a gradient checkpointing = -1.
383
0
        ccv_nnc_tensor_symbol_new_hook_f old_tensor_symbol_new_hook;
384
0
        build_context = ccv_nnc_tensor_symbol_new_hook(graph, 0, 0, &old_tensor_symbol_new_hook);
385
        // Set back the build_context.
386
0
        ccv_nnc_tensor_symbol_new_hook(graph, old_tensor_symbol_new_hook, build_context, 0);
387
0
        old_record = build_context->record;
388
0
        build_context->record = 1;
389
0
      }
390
0
    }
391
    // No push checkpoint, easy.
392
2.29k
    if (outputs && 
output_size0
)
393
0
    {
394
0
      assert(output_size == self->output_size);
395
0
      self->isa->build(self, graph, inputs, input_size, outputs, output_size);
396
0
      memcpy(self->outputs, outputs, sizeof(ccv_nnc_tensor_symbol_t) * output_size);
397
0
    } else
398
2.29k
      self->isa->build(self, graph, inputs, input_size, self->outputs, self->output_size);
399
2.29k
    if (build_context) // Restore previous state even if our gradient checkpointing controlled whether to turn on recording or not.
400
0
      build_context->record = old_record;
401
2.29k
  }
402
  // Skip if there is none. This helps to load parameters to a different model when only changes non-parameterized settings (add reshapes, permutations etc).
403
  // If it is named, we have to push too.
404
2.29k
  if (self->isa->add_to_parameter || 
self->isa->add_to_output1.08k
)
405
1.20k
  {
406
    // If we already pushed, no need to push again.
407
1.20k
    if (!(self->name && 
self->name[0] != '\0'1
))
408
1.20k
      ccv_cnnp_model_push(self, build_data->model_sequence);
409
1.20k
    build_data->model_sequence->it = 0;
410
1.20k
    ccv_cnnp_model_add_to_parameter(self, build_data->add_to_array, build_data->context.add_to_parameter, build_data->is_trainable);
411
1.20k
    build_data->model_sequence->it = 0;
412
1.20k
    ccv_cnnp_model_add_to_output(self, build_data->add_to_array, build_data->context.add_to_output);
413
1.20k
    ccv_cnnp_model_pop(self, build_data->model_sequence);
414
1.20k
  } else 
if (1.08k
self->name1.08k
&&
self->name[0] != '\0'32
)
415
32
    ccv_cnnp_model_pop(self, build_data->model_sequence);
416
2.29k
  build_data->is_trainable = old_is_trainable;
417
2.29k
}
Unexecuted instantiation: ccv_cnnp_model_io.c:ccv_cnnp_model_build
ccv_cnnp_model_core.c:ccv_cnnp_model_build
Line
Count
Source
321
2.91k
{
322
2.91k
  assert(self->data);
323
2.91k
  ccv_cnnp_model_build_data_t* const build_data = (ccv_cnnp_model_build_data_t*)self->data;
324
2.91k
  const int old_is_trainable = build_data->is_trainable;
325
2.91k
  if (self->is_trainable >= 0)
326
2.90k
    build_data->is_trainable = self->is_trainable;
327
2.91k
  if (self->name && 
self->name[0] != '\0'197
)
328
197
    ccv_cnnp_model_push(self, build_data->model_sequence);
329
2.91k
  if (self->gradient_checkpointing == 1 && 
!build_data->is_gradient_checkpointing0
)
330
0
  {
331
0
    build_data->is_gradient_checkpointing = 1;
332
    // Prepare to record gradient checkpoint. We will log the build function, inputs, what are the tensors / graph execs we created.
333
0
    if (!build_data->gradient_checkpoints)
334
0
      build_data->gradient_checkpoints = ccv_array_new(sizeof(ccv_cnnp_model_gradient_checkpoint_t), 0, 0);
335
0
    ccv_cnnp_model_gradient_checkpoint_build_context_t build_context = {
336
0
      .record = 1,
337
0
      .tensor_symbols = ccv_array_new(sizeof(ccv_nnc_tensor_symbol_t), 0, 0),
338
0
    };
339
0
    build_context.old_tensor_symbol_new_hook_context = ccv_nnc_tensor_symbol_new_hook(graph, _ccv_cnnp_model_gradient_checkpoint_tensor_symbol_new_hook, &build_context, &build_context.old_tensor_symbol_new_hook);
340
0
    build_context.old_tensor_symbol_alias_new_hook_context = ccv_nnc_tensor_symbol_alias_new_hook(graph, _ccv_cnnp_model_gradient_checkpoint_tensor_symbol_alias_new_hook, &build_context, &build_context.old_tensor_symbol_alias_new_hook);
341
0
    if (outputs && output_size)
342
0
    {
343
0
      assert(output_size == self->output_size);
344
0
      self->isa->build(self, graph, inputs, input_size, outputs, output_size);
345
0
      memcpy(self->outputs, outputs, sizeof(ccv_nnc_tensor_symbol_t) * output_size);
346
0
    } else
347
0
      self->isa->build(self, graph, inputs, input_size, self->outputs, self->output_size);
348
0
    ccv_nnc_tensor_symbol_new_hook(graph, build_context.old_tensor_symbol_new_hook, build_context.old_tensor_symbol_new_hook_context, 0);
349
0
    ccv_nnc_tensor_symbol_alias_new_hook(graph, build_context.old_tensor_symbol_alias_new_hook, build_context.old_tensor_symbol_alias_new_hook_context, 0);
350
0
    ccv_cnnp_model_gradient_checkpoint_t checkpoint = {
351
0
      .input_size = input_size,
352
0
      .output_size = (outputs && output_size > 0) ? output_size : self->output_size,
353
0
      .is_trainable = build_data->is_trainable,
354
0
      .model = self,
355
0
      .build = self->isa->build,
356
0
      .tensor_symbols = build_context.tensor_symbols,
357
0
      .inputs = ccmalloc(sizeof(ccv_nnc_tensor_symbol_t) * (input_size + ((outputs && output_size > 0) ? output_size : self->output_size))),
358
0
    };
359
0
    checkpoint.outputs = checkpoint.inputs + input_size;
360
0
    if (input_size > 0)
361
0
      memcpy(checkpoint.inputs, inputs, sizeof(ccv_nnc_tensor_symbol_t) * input_size);
362
0
    if (outputs && output_size > 0)
363
0
      memcpy(checkpoint.outputs, outputs, sizeof(ccv_nnc_tensor_symbol_t) * output_size);
364
0
    else if (self->outputs && self->output_size > 0)
365
0
      memcpy(checkpoint.outputs, self->outputs, sizeof(ccv_nnc_tensor_symbol_t) * self->output_size);
366
0
    ccv_array_push(build_data->gradient_checkpoints, &checkpoint);
367
0
    build_data->is_gradient_checkpointing = 0;
368
2.91k
  } else {
369
    // If we want to disable gradient checkpointing for this model, we simply not log any new tensors created here so there is no mapping for these.
370
2.91k
    int old_record;
371
2.91k
    ccv_cnnp_model_gradient_checkpoint_build_context_t* build_context = 0;
372
2.91k
    if (build_data->is_gradient_checkpointing)
373
36
    {
374
36
      if (self->gradient_checkpointing == -1)
375
0
      {
376
0
        ccv_nnc_tensor_symbol_new_hook_f old_tensor_symbol_new_hook;
377
0
        build_context = ccv_nnc_tensor_symbol_new_hook(graph, 0, 0, &old_tensor_symbol_new_hook);
378
        // Set back the build_context.
379
0
        ccv_nnc_tensor_symbol_new_hook(graph, old_tensor_symbol_new_hook, build_context, 0);
380
0
        old_record = build_context->record;
381
0
        build_context->record = 0;
382
36
      } else if (self->gradient_checkpointing == 1) { // Force to turn on gradient checkpointing if it is inside a gradient checkpointing = -1.
383
0
        ccv_nnc_tensor_symbol_new_hook_f old_tensor_symbol_new_hook;
384
0
        build_context = ccv_nnc_tensor_symbol_new_hook(graph, 0, 0, &old_tensor_symbol_new_hook);
385
        // Set back the build_context.
386
0
        ccv_nnc_tensor_symbol_new_hook(graph, old_tensor_symbol_new_hook, build_context, 0);
387
0
        old_record = build_context->record;
388
0
        build_context->record = 1;
389
0
      }
390
36
    }
391
    // No push checkpoint, easy.
392
2.91k
    if (outputs && 
output_size2.91k
)
393
2.91k
    {
394
2.91k
      assert(output_size == self->output_size);
395
2.91k
      self->isa->build(self, graph, inputs, input_size, outputs, output_size);
396
2.91k
      memcpy(self->outputs, outputs, sizeof(ccv_nnc_tensor_symbol_t) * output_size);
397
2.91k
    } else
398
4
      self->isa->build(self, graph, inputs, input_size, self->outputs, self->output_size);
399
2.91k
    if (build_context) // Restore previous state even if our gradient checkpointing controlled whether to turn on recording or not.
400
0
      build_context->record = old_record;
401
2.91k
  }
402
  // Skip if there is none. This helps to load parameters to a different model when only changes non-parameterized settings (add reshapes, permutations etc).
403
  // If it is named, we have to push too.
404
2.91k
  if (self->isa->add_to_parameter || 
self->isa->add_to_output1.50k
)
405
1.40k
  {
406
    // If we already pushed, no need to push again.
407
1.40k
    if (!(self->name && 
self->name[0] != '\0'123
))
408
1.28k
      ccv_cnnp_model_push(self, build_data->model_sequence);
409
1.40k
    build_data->model_sequence->it = 0;
410
1.40k
    ccv_cnnp_model_add_to_parameter(self, build_data->add_to_array, build_data->context.add_to_parameter, build_data->is_trainable);
411
1.40k
    build_data->model_sequence->it = 0;
412
1.40k
    ccv_cnnp_model_add_to_output(self, build_data->add_to_array, build_data->context.add_to_output);
413
1.40k
    ccv_cnnp_model_pop(self, build_data->model_sequence);
414
1.50k
  } else if (self->name && 
self->name[0] != '\0'74
)
415
74
    ccv_cnnp_model_pop(self, build_data->model_sequence);
416
2.91k
  build_data->is_trainable = old_is_trainable;
417
2.91k
}
Unexecuted instantiation: ccv_cnnp_model_addons.c:ccv_cnnp_model_build
Unexecuted instantiation: ccv_cnnp_model_gradient_checkpointing.c:ccv_cnnp_model_build
418
419
static inline void ccv_cnnp_model_init_states(ccv_cnnp_model_t* const self, ccv_nnc_symbolic_graph_t* const graph, const ccv_cnnp_state_initializer_f initializer, void* const context)
420
524
{
421
524
  if (self->isa->init_states)
422
305
    self->isa->init_states(self, graph, initializer, context);
423
524
}
Unexecuted instantiation: ccv_nnc_dynamic_graph_evaluate.c:ccv_cnnp_model_init_states
ccv_cnnp_model.c:ccv_cnnp_model_init_states
Line
Count
Source
420
41
{
421
41
  if (self->isa->init_states)
422
41
    self->isa->init_states(self, graph, initializer, context);
423
41
}
Unexecuted instantiation: ccv_cnnp_model_io.c:ccv_cnnp_model_init_states
ccv_cnnp_model_core.c:ccv_cnnp_model_init_states
Line
Count
Source
420
483
{
421
483
  if (self->isa->init_states)
422
264
    self->isa->init_states(self, graph, initializer, context);
423
483
}
Unexecuted instantiation: ccv_cnnp_model_addons.c:ccv_cnnp_model_init_states
Unexecuted instantiation: ccv_cnnp_model_gradient_checkpointing.c:ccv_cnnp_model_init_states
424
425
static inline void ccv_cnnp_model_set_is_test(ccv_cnnp_model_t* const self, const int is_test, const ccv_cnnp_cmd_updater_f updater, void* const context)
426
1.12k
{
427
1.12k
  if (self->isa->set_is_test)
428
241
    self->isa->set_is_test(self, is_test, updater, context);
429
1.12k
}
Unexecuted instantiation: ccv_nnc_dynamic_graph_evaluate.c:ccv_cnnp_model_set_is_test
ccv_cnnp_model.c:ccv_cnnp_model_set_is_test
Line
Count
Source
426
139
{
427
139
  if (self->isa->set_is_test)
428
101
    self->isa->set_is_test(self, is_test, updater, context);
429
139
}
Unexecuted instantiation: ccv_cnnp_model_io.c:ccv_cnnp_model_set_is_test
ccv_cnnp_model_core.c:ccv_cnnp_model_set_is_test
Line
Count
Source
426
986
{
427
986
  if (self->isa->set_is_test)
428
140
    self->isa->set_is_test(self, is_test, updater, context);
429
986
}
Unexecuted instantiation: ccv_cnnp_model_addons.c:ccv_cnnp_model_set_is_test
Unexecuted instantiation: ccv_cnnp_model_gradient_checkpointing.c:ccv_cnnp_model_set_is_test
430
431
static inline void ccv_cnnp_model_add_to_parameter_indices(ccv_cnnp_model_t* const self, const int index, ccv_array_t* const parameter_indices)
432
13.3k
{
433
13.3k
  if (self->isa->add_to_parameter_indices)
434
3.59k
    self->isa->add_to_parameter_indices(self, index, parameter_indices);
435
9.73k
  else {
436
9.73k
    int i;
437
9.73k
    if (!self->parameter_indices)
438
4.63k
      return;
439
5.10k
    if (index == -1)
440
178
      
for (i = 0; 89
i < self->parameter_indices->rnum;
i++89
)
441
89
        ccv_array_push(parameter_indices, ccv_array_get(self->parameter_indices, i));
442
5.01k
    else if (index < self->parameter_indices->rnum)
443
5.01k
      ccv_array_push(parameter_indices, ccv_array_get(self->parameter_indices, index));
444
5.10k
  }
445
13.3k
}
Unexecuted instantiation: ccv_nnc_dynamic_graph_evaluate.c:ccv_cnnp_model_add_to_parameter_indices
ccv_cnnp_model.c:ccv_cnnp_model_add_to_parameter_indices
Line
Count
Source
432
390
{
433
390
  if (self->isa->add_to_parameter_indices)
434
343
    self->isa->add_to_parameter_indices(self, index, parameter_indices);
435
47
  else {
436
47
    int i;
437
47
    if (!self->parameter_indices)
438
0
      return;
439
47
    if (index == -1)
440
74
      
for (i = 0; 37
i < self->parameter_indices->rnum;
i++37
)
441
37
        ccv_array_push(parameter_indices, ccv_array_get(self->parameter_indices, i));
442
10
    else if (index < self->parameter_indices->rnum)
443
10
      ccv_array_push(parameter_indices, ccv_array_get(self->parameter_indices, index));
444
47
  }
445
390
}
Unexecuted instantiation: ccv_cnnp_model_io.c:ccv_cnnp_model_add_to_parameter_indices
ccv_cnnp_model_core.c:ccv_cnnp_model_add_to_parameter_indices
Line
Count
Source
432
12.9k
{
433
12.9k
  if (self->isa->add_to_parameter_indices)
434
3.25k
    self->isa->add_to_parameter_indices(self, index, parameter_indices);
435
9.69k
  else {
436
9.69k
    int i;
437
9.69k
    if (!self->parameter_indices)
438
4.63k
      return;
439
5.05k
    if (index == -1)
440
104
      
for (i = 0; 52
i < self->parameter_indices->rnum;
i++52
)
441
52
        ccv_array_push(parameter_indices, ccv_array_get(self->parameter_indices, i));
442
5.00k
    else if (index < self->parameter_indices->rnum)
443
5.00k
      ccv_array_push(parameter_indices, ccv_array_get(self->parameter_indices, index));
444
5.05k
  }
445
12.9k
}
Unexecuted instantiation: ccv_cnnp_model_addons.c:ccv_cnnp_model_add_to_parameter_indices
Unexecuted instantiation: ccv_cnnp_model_gradient_checkpointing.c:ccv_cnnp_model_add_to_parameter_indices
446
447
typedef struct {
448
  uint8_t add_parameter_indices;
449
  char prefix;
450
  ccv_cnnp_model_sequence_t* sequence;
451
  ccv_array_t* symbols;
452
  ccv_array_t* ids;
453
  ccv_array_t* trainables;
454
} ccv_cnnp_model_add_to_array_context_t;
455
456
void ccv_cnnp_model_tensors_init_0(const ccv_cnnp_model_t* const model, ccv_cnnp_compiled_data_t* const compiled_data);
457
void ccv_cnnp_model_tensors_init_1(const ccv_cnnp_model_t* const model, ccv_cnnp_compiled_data_t* const compiled_data);
458
int ccv_cnnp_model_tensors_any_to_alloc(const ccv_cnnp_model_t* const model, ccv_cnnp_compiled_data_t* const compiled_data);
459
ccv_nnc_stream_context_t* ccv_cnnp_compiled_data_get_stream(ccv_cnnp_compiled_data_t* const compiled_data, const int type);
460
void ccv_cnnp_model_gradient_checkpoints_cleanup_after_build(ccv_cnnp_compiled_data_t* const compiled_data, ccv_nnc_symbolic_graph_t* const graph);
461
void ccv_cnnp_model_apply_gradient_checkpoints(ccv_cnnp_compiled_data_t* const compiled_data, ccv_nnc_symbolic_graph_t* const graph);
462
void ccv_cnnp_model_add_to_array(void* const context, const ccv_nnc_tensor_symbol_t symbol, const int is_trainable);
463
464
#endif