53 GeneratedModelImpl(std::unique_ptr<flatbuffers::FlatBufferBuilder> &&builder)
54 : _builder{
std::move(builder)}
60 const char *
base(
void)
const override
63 return reinterpret_cast<const char *
>(_builder->GetBufferPointer());
67 size_t size(
void)
const override
70 return _builder->GetSize();
74 std::unique_ptr<flatbuffers::FlatBufferBuilder> _builder;
82struct DataChefRegistry final :
public Registry<DataChefFactory>
86DataChefRegistry &data_chef_registry(
const circlechef::TensorType &type)
88 static DataChefRegistry s32;
89 static DataChefRegistry s64;
90 static DataChefRegistry fp32;
91 static DataChefRegistry u8;
92 static DataChefRegistry u4;
93 static DataChefRegistry string;
94 static DataChefRegistry boolean;
95 static DataChefRegistry s16;
96 static DataChefRegistry s4;
100 case circlechef::INT32:
102 case circlechef::INT64:
104 case circlechef::FLOAT32:
106 case circlechef::UINT8:
108 case circlechef::UINT4:
110 case circlechef::STRING:
112 case circlechef::BOOL:
114 case circlechef::INT16:
116 case circlechef::INT4:
122 throw std::runtime_error{
"Unknown tensor type"};
125struct OpChefRegistry final :
public Registry<OpChefFactory>
129OpChefRegistry &op_chef_registry(
void)
131 static OpChefRegistry registry;
136std::map<circle::BuiltinOperator, int32_t>
137gather_builtincode_map(const ::circlechef::ModelRecipe &model_recipe)
140 std::map<circle::BuiltinOperator, int32_t> builtin_map;
142 for (
const auto &operation : model_recipe.operation())
144 if (operation.type() ==
"Custom")
147 auto op_chef = op_chef_registry().lookup(operation.type()).create(&operation);
149 if (builtin_map.find(op_chef->code()) == builtin_map.end() ||
150 builtin_map[op_chef->code()] < operation.version())
151 builtin_map[op_chef->code()] = operation.version();
155 for (
int g = 0;
g < model_recipe.graph_size(); ++
g)
157 const auto &
graph = model_recipe.graph(g);
158 for (
const auto &operation :
graph.operation())
160 if (operation.type() ==
"Custom")
163 auto op_chef = op_chef_registry().lookup(operation.type()).create(&operation);
165 if (builtin_map.find(op_chef->code()) == builtin_map.end() ||
166 builtin_map[op_chef->code()] < operation.version())
167 builtin_map[op_chef->code()] = operation.version();
175std::set<std::string> gather_customcode_set(const ::circlechef::ModelRecipe &model_recipe)
177 std::set<std::string> customcode_set;
178 for (
const auto &operation : model_recipe.operation())
180 if (operation.type() ==
"Custom")
182 assert(not operation.custom_code().empty());
183 customcode_set.insert(operation.custom_code());
188 for (
int g = 0;
g < model_recipe.graph_size(); ++
g)
190 const auto &
graph = model_recipe.graph(g);
191 for (
const auto &operation :
graph.operation())
193 if (operation.type() ==
"Custom")
195 assert(not operation.custom_code().empty());
196 customcode_set.insert(operation.custom_code());
201 return customcode_set;
211 std::vector<flatbuffers::Offset<::circle::Buffer>> &buffer_vec;
212 std::vector<flatbuffers::Offset<::circle::OperatorCode>> &code_vec;
213 std::vector<flatbuffers::Offset<::circle::SubGraph>> &subgraph_vec;
214 std::unique_ptr<flatbuffers::FlatBufferBuilder> &flatbuffer_builder;
215 std::map<circle::BuiltinOperator, int32_t> &builtin_code_map;
219template <
typename T>
void cook_graph(
const T &graph, CookParams &cp)
223 std::vector<flatbuffers::Offset<::circle::Buffer>> &buffer_vec = cp.buffer_vec;
224 std::vector<flatbuffers::Offset<::circle::OperatorCode>> &code_vec = cp.code_vec;
225 std::vector<flatbuffers::Offset<::circle::SubGraph>> &subgraph_vec = cp.subgraph_vec;
226 std::unique_ptr<flatbuffers::FlatBufferBuilder> &flatbuffer_builder = cp.flatbuffer_builder;
227 std::map<circle::BuiltinOperator, int32_t> &builtin_code_map = cp.builtin_code_map;
230 std::vector<flatbuffers::Offset<::circle::Tensor>> tensor_vec;
233 std::vector<flatbuffers::Offset<::circle::Operator>> operator_vec;
236 std::string graph_name = cp.noname;
237 if (
graph.has_name())
238 graph_name =
graph.name();
241 std::map<std::string, int32_t> symbol_table;
243 auto lookup = [&symbol_table, &graph_name](
const std::string &name) {
244 if (symbol_table.find(name) != symbol_table.end())
245 return symbol_table.at(name);
250 std::string msg =
"circlechef : input not found in " + graph_name +
" graph";
251 throw std::runtime_error(msg.c_str());
255 int32_t buffer_start = buffer_vec.size();
256 int32_t buffer_index = 0;
259 const auto size_input =
graph.input_size();
260 for (
int ci = 0; ci < size_input; ++ci)
262 circle::BufferBuilder buffer_builder{*flatbuffer_builder};
263 buffer_vec.emplace_back(buffer_builder.Finish());
266 const auto size_output =
graph.output_size();
267 for (
int co = 0; co < size_output; ++co)
269 circle::BufferBuilder buffer_builder{*flatbuffer_builder};
270 buffer_vec.emplace_back(buffer_builder.Finish());
276 for (
const auto &operand :
graph.operand())
278 assert(operand.has_name());
280 assert(operand.has_type());
283 std::vector<int32_t> dims;
284 if (operand.has_shape())
286 dims =
as_dims(operand.shape());
287 shape = flatbuffer_builder->CreateVector(dims);
290 auto name = flatbuffer_builder->CreateString(operand.name());
295 if (operand.has_filler())
297 const auto &filler = operand.filler();
299 assert(filler.has_tag());
302 auto chef = data_chef_registry(operand.type()).lookup(filler.tag()).create(args);
304 assert(chef !=
nullptr);
308 auto data_vec = chef->generate(count);
310 if (operand.type() == circlechef::TensorType::INT4)
312 uint32_t packed = (count + 1) / 2;
313 std::vector<uint8_t> data_packed(packed);
314 for (uint32_t idx = 0; idx < packed; ++idx)
316 uint32_t sidx = idx * 2;
317 data_packed[idx] = data_vec[sidx++] & 0x0f;
319 data_packed[idx] |= data_vec[sidx] << 4;
321 data_vec = data_packed;
324 else if (operand.type() == circlechef::TensorType::UINT4)
326 uint32_t packed = (count + 1) / 2;
327 std::vector<uint8_t> data_packed(packed);
328 for (uint32_t idx = 0; idx < packed; ++idx)
330 uint32_t sidx = idx * 2;
331 data_packed[idx] = data_vec[sidx++] & 0x0f;
333 data_packed[idx] |= data_vec[sidx] << 4;
335 data_vec = data_packed;
337 auto data = flatbuffer_builder->CreateVector(data_vec);
340 circle::BufferBuilder buffer_builder{*flatbuffer_builder};
341 buffer_builder.add_data(data);
342 auto buffer = buffer_builder.Finish();
345 buffer_index = buffer_vec.size();
346 buffer_vec.emplace_back(buffer);
352 for (
auto it = input_names.begin(); it != input_names.end(); ++it, ++idx)
354 if (*it == operand.name())
356 buffer_index = buffer_start + idx;
360 if (buffer_index == 0)
363 for (
auto it = output_names.begin(); it != output_names.end(); ++it, ++idx)
365 if (*it == operand.name())
367 buffer_index = buffer_start + size_input + idx;
372 if (buffer_index == 0)
375 buffer_index = buffer_vec.size();
377 circle::BufferBuilder buffer_builder{*flatbuffer_builder};
378 buffer_vec.emplace_back(buffer_builder.Finish());
381 assert(buffer_index != 0);
386 if (operand.has_quant())
388 const auto &quant = operand.quant();
392 std::vector<float> quant_max_vec(quant.max_size());
393 std::vector<float> quant_min_vec(quant.min_size());
394 std::vector<float> quant_scale_vec(quant.scale_size());
395 std::vector<int64_t> quant_zero_point_vec(quant.zero_point_size());
397 for (uint32_t i = 0; i < quant.max_size(); ++i)
398 quant_max_vec.at(i) = quant.max(i);
399 for (uint32_t i = 0; i < quant.min_size(); ++i)
400 quant_min_vec.at(i) = quant.min(i);
401 for (uint32_t i = 0; i < quant.scale_size(); ++i)
402 quant_scale_vec.at(i) = quant.scale(i);
403 for (uint32_t i = 0; i < quant.zero_point_size(); ++i)
404 quant_zero_point_vec.at(i) = quant.zero_point(i);
406 auto quant_max = flatbuffer_builder->CreateVector(quant_max_vec);
407 auto quant_min = flatbuffer_builder->CreateVector(quant_min_vec);
408 auto quant_scale = flatbuffer_builder->CreateVector(quant_scale_vec);
409 auto quant_zero_point = flatbuffer_builder->CreateVector(quant_zero_point_vec);
412 circle::QuantizationParametersBuilder quant_builder{*flatbuffer_builder};
413 quant_builder.add_max(quant_max);
414 quant_builder.add_min(quant_min);
415 quant_builder.add_scale(quant_scale);
416 quant_builder.add_zero_point(quant_zero_point);
417 quant_builder.add_quantized_dimension(quant.quantized_dimension());
420 quant_index = quant_builder.Finish();
424 if (operand.has_shape_signature())
426 auto signature =
as_dims(operand.shape_signature());
427 shape_signature = flatbuffer_builder->CreateVector(signature);
431 circle::TensorBuilder tensor_builder{*flatbuffer_builder};
433 tensor_builder.add_shape(shape);
435 tensor_builder.add_buffer(buffer_index);
436 tensor_builder.add_name(name);
437 if (operand.has_quant())
438 tensor_builder.add_quantization(quant_index);
439 if (operand.has_shape_signature())
440 tensor_builder.add_shape_signature(shape_signature);
443 tensor_vec.emplace_back(tensor_builder.Finish());
446 int32_t tensor_index = symbol_table.size();
449 INFO(l) <<
"Symbol [" <<
tensor_name <<
"] = Tensor " << tensor_index << std::endl;
455 for (
const auto &operation :
graph.operation())
457 assert(operation.has_type());
459 std::string op_type = operation.type();
460 if (not operation.custom_code().empty())
461 op_type = operation.custom_code();
463 auto op_chef = op_chef_registry().lookup(op_type).create(&operation);
466 std::vector<int32_t> input_vec =
as_dataset(operation.input()).map(lookup).vectorize();
467 auto inputs = flatbuffer_builder->CreateVector(input_vec);
470 std::vector<int32_t> output_vec =
as_dataset(operation.output()).map(lookup).vectorize();
471 auto outputs = flatbuffer_builder->CreateVector(output_vec);
474 auto options = op_chef->value(*flatbuffer_builder);
480 circle::OperatorBuilder
op_builder{*flatbuffer_builder};
484 auto op_it = builtin_code_map.find(op_chef->code());
485 assert(op_it != builtin_code_map.end());
486 uint32_t opcode_index = std::distance(builtin_code_map.begin(), op_it);
491 op_builder.add_builtin_options_type(op_chef->type());
493 op_builder.add_custom_options(circle_custom_options);
494 op_builder.add_custom_options_format(circle::CustomOptionsFormat_FLEXBUFFERS);
496 operator_vec.emplace_back(
op_builder.Finish());
500 std::vector<int32_t> input_vec =
as_dataset(
graph.input()).map(lookup).vectorize();
501 std::vector<int32_t> output_vec =
as_dataset(
graph.output()).map(lookup).vectorize();
504 auto tensors = flatbuffer_builder->CreateVector(tensor_vec);
505 auto inputs = flatbuffer_builder->CreateVector(input_vec);
506 auto outputs = flatbuffer_builder->CreateVector(output_vec);
507 auto operators = flatbuffer_builder->CreateVector(operator_vec);
508 auto name = flatbuffer_builder->CreateString(graph_name);
510 circle::SubGraphBuilder subgraph_builder{*flatbuffer_builder};
512 subgraph_builder.add_tensors(tensors);
513 subgraph_builder.add_inputs(inputs);
514 subgraph_builder.add_outputs(outputs);
515 subgraph_builder.add_operators(operators);
516 subgraph_builder.add_name(name);
518 subgraph_vec.emplace_back(subgraph_builder.Finish());
532#define OP_CHEF(NAME, FACTORY_CLASS) \
533 op_chef_registry().add(#NAME, std::unique_ptr<FACTORY_CLASS>(new FACTORY_CLASS()));
538#define DATA_CHEF(TYPE, NAME, FACTORY_CLASS) \
539 data_chef_registry(::circlechef::TYPE) \
540 .add(#NAME, std::unique_ptr<FACTORY_CLASS>(new FACTORY_CLASS()));
541#include "DataChef.def"
547 auto flatbuffer_builder =
551 std::vector<flatbuffers::Offset<::circle::Buffer>> buffer_vec;
554 std::vector<flatbuffers::Offset<::circle::OperatorCode>> code_vec;
557 std::vector<flatbuffers::Offset<::circle::SubGraph>> subgraph_vec;
560 std::map<circle::BuiltinOperator, int32_t> builtin_code_map =
561 gather_builtincode_map(model_recipe);
562 for (
auto const &opcode : builtin_code_map)
564 circle::OperatorCodeBuilder code_builder{*flatbuffer_builder};
565 int8_t dep_code = 127;
566 if (opcode.first < circle::BuiltinOperator_PLACEHOLDER_FOR_GREATER_OP_CODES)
567 dep_code =
static_cast<int8_t
>(opcode.first);
568 code_builder.add_deprecated_builtin_code(dep_code);
569 code_builder.add_builtin_code(opcode.first);
570 code_builder.add_version(opcode.second);
571 auto code = code_builder.Finish();
573 code_vec.emplace_back(code);
577 std::set<std::string> custom_code_set = gather_customcode_set(model_recipe);
578 if (custom_code_set.size() &&
579 builtin_code_map.find(circle::BuiltinOperator_CUSTOM) == builtin_code_map.end())
580 builtin_code_map[circle::BuiltinOperator_CUSTOM] = 1;
582 for (
auto opcode : custom_code_set)
584 auto custom_code = flatbuffer_builder->CreateString(opcode);
585 circle::OperatorCodeBuilder code_builder{*flatbuffer_builder};
586 code_builder.add_builtin_code(circle::BuiltinOperator_CUSTOM);
587 code_builder.add_custom_code(custom_code);
588 auto code = code_builder.Finish();
590 code_vec.emplace_back(code);
598 circle::BufferBuilder buffer_builder{*flatbuffer_builder};
599 buffer_vec.emplace_back(buffer_builder.Finish());
605 CookParams cp{buffer_vec, code_vec, subgraph_vec, flatbuffer_builder, builtin_code_map,
"main"};
607 cook_graph<::circlechef::ModelRecipe>(model_recipe, cp);
612 for (
int g = 0; g < model_recipe.graph_size(); ++g)
614 const auto &graph = model_recipe.graph(g);
616 std::ostringstream stringStream;
617 stringStream <<
"sub_" << (g + 1);
619 CookParams cp{buffer_vec, code_vec, subgraph_vec,
620 flatbuffer_builder, builtin_code_map, stringStream.str()};
622 cook_graph<::circlechef::Graph>(graph, cp);
626 auto buffers = flatbuffer_builder->CreateVector(buffer_vec);
627 auto operator_codes = flatbuffer_builder->CreateVector(code_vec);
628 auto subgraphs = flatbuffer_builder->CreateVector(subgraph_vec);
629 auto description = flatbuffer_builder->CreateString(
"Generated by circlechef");
632 circle::ModelBuilder model_builder{*flatbuffer_builder};
634 model_builder.add_version(3);
635 model_builder.add_operator_codes(operator_codes);
636 model_builder.add_subgraphs(subgraphs);
637 model_builder.add_description(description);
638 model_builder.add_buffers(buffers);
640 auto model = model_builder.Finish();
643 ::circle::FinishModelBuffer(*flatbuffer_builder, model);
647 std::unique_ptr<GeneratedModelImpl>(
new GeneratedModelImpl(std::move(flatbuffer_builder)))};
OpBuilder op_builder(coco::Module *m)
circle::TensorType as_circle_tensortype(const circlechef::TensorType &value)
Helper class to hold data needed in creation of a FlatBuffer. To serialize data, you typically call o...
GeneratedModel cook(const ModelRecipe &model_recipe)
flatbuffers::Offset< flatbuffers::Vector< uint8_t > > circle_custom_options(flatbuffers::FlatBufferBuilder &fb, const luci::CircleNode *node)
const char * tensor_name(const circle::Tensor *tensor)
This file provides string <-> number cast helpers.
Dims< int32_t > as_dims(const SHAPETYPE &shape)
Dataset< T > as_dataset(const ::google::protobuf::RepeatedPtrField< T > &field)
RangedArguments< InputIt > ranged_arguments(InputIt beg, InputIt end)
int32_t element_count(const Dims< int32_t > &dims)
virtual const char * base(void) const =0
virtual size_t size(void) const =0