161 std::shared_ptr<void> data(
malloc(tensor_size),
free);
164 if (tensorproto->data_location() != onnx::TensorProto::EXTERNAL) {
165 if (tensorproto->raw_data().size() > 0) {
166 if (tensorproto->raw_data().size() != tensor_size)
167 throw std::runtime_error(
"TMVA::SOFIE - Failed to read raw data of initialized tensor - actual raw size is " +
168 std::to_string(tensorproto->raw_data().size()));
172 std::memcpy(data.get(), tensorproto->raw_data().c_str(), tensor_size);
175 for (std::size_t k = 0; k < tensor_size; ++k)
176 (
reinterpret_cast<typename
RByteSwap<sizeof(uint8_t)
>::value_type *>(data.get()))[k] =
177 RByteSwap<
sizeof(T)>::bswap((
reinterpret_cast<const typename
RByteSwap<sizeof(uint8_t)
>::value_type *>(
178 tensorproto->raw_data().c_str()))[k]);
182 switch (tensor_type) {
200 throw std::runtime_error(
"TMVA::SOFIE - ExtractData from TP in BOOL not supported");
204 throw std::runtime_error(
"TMVA::SOFIE - ExtractData from TP in UINT8 not supported");
208 throw std::runtime_error(
"Data type " +
ConvertTypeToString(tensor_type) +
" in weight tensor is not supported!\n");
215 std::cout <<
"Initialized data are stored externally in file " <<
fDataFileName;
218 std::string location;
219 size_t offset = 0, buffer_size = 0;
221 for (
const auto &kv : tensorproto->external_data()) {
222 if (kv.key() ==
"location") location = kv.value();
223 else if (kv.key() ==
"offset") offset = std::stoull(kv.value());
224 else if (kv.key() ==
"length") buffer_size = std::stoull(kv.value());
227 std::cout <<
" at location " << location <<
" offset " << offset <<
" and with length " << buffer_size << std::endl;
229 if (buffer_size != tensor_size)
230 throw std::runtime_error(
"TMVA::SOFIE ONNX : invalid stored data size vs tensor size");
236 throw std::runtime_error(
"TMVA::SOFIE ONNX: error reading external weight ONNX data file " +
fDataFileName);
240 fDataFile.read(
reinterpret_cast<char *
>(data.get()), buffer_size);
609 if (graphName.empty())
610 graphName = graph.name();
613 std::cout <<
"\nParsing Graph - " << graphName << std::endl;
615 std::unordered_set<std::string> initializer_names;
616 for (
int i = 0; i < graph.initializer_size(); i++) {
617 initializer_names.insert(graph.initializer(i).name());
621 std::cout <<
"Parsing model inputs...." << std::endl;
623 for (
int i = 0; i < graph.input_size(); i++) {
625 static_cast<ETensorType>(graph.input(i).type().tensor_type().elem_type()));
628 std::cout <<
"\tgraph input " << i <<
" name " << graph.input(i).name() <<
" type "
629 << graph.input(i).type().tensor_type().elem_type() << std::endl;
631 if (initializer_names.find(graph.input(i).name()) != initializer_names.end())
635 const onnx::ValueInfoProto &valueinfoproto = graph.input(i);
636 std::string input_name = valueinfoproto.name();
640 std::vector<Dim> fShape;
641 bool existParam =
false;
642 if (!valueinfoproto.type().tensor_type().has_shape())
643 throw std::runtime_error(
"TMVA::SOFIE data node with no shape restrictions is not supported yet");
644 for (
int j = 0; j < valueinfoproto.type().tensor_type().shape().dim_size(); j++) {
646 if (valueinfoproto.type().tensor_type().shape().dim(j).value_case() ==
647 onnx::TensorShapeProto_Dimension::ValueCase::kDimValue) {
648 int dim_value = valueinfoproto.type().tensor_type().shape().dim(j).dim_value();
656 }
else if (valueinfoproto.type().tensor_type().shape().dim(j).value_case() ==
657 onnx::TensorShapeProto_Dimension::ValueCase::kDimParam) {
660 dim.param = valueinfoproto.type().tensor_type().shape().dim(j).dim_param();
662 throw std::runtime_error(
"TMVA::SOFIE ONNX file error: Valueinfoproto " + input_name +
663 " has neither dim_value nor dim_param! \n");
665 fShape.push_back(dim);
667 if (valueinfoproto.type().tensor_type().shape().dim_size() == 0) {
670 fShape.push_back(dim);
674 std::vector<size_t> fShape_sizet;
675 for (
auto &j : fShape) {
676 fShape_sizet.push_back(j.dim);
686 std::map<std::string, int> allInitializedTensors;
689 std::cout <<
"\nParsing graph initializer list and fill model initialized tensors" << std::endl;
691 for (
int i = 0; i < graph.initializer_size(); i++) {
692 onnx::TensorProto *tensorproto =
const_cast<onnx::TensorProto *
>(&graph.initializer(i));
693 std::vector<std::size_t> shape;
694 std::size_t tensor_length = 1;
695 for (
int j = 0; j < tensorproto->dims_size(); j++) {
696 shape.push_back(tensorproto->dims(j));
697 tensor_length *= tensorproto->dims(j);
701 std::string tensor_name = graph.initializer(i).name();
704 std::cout <<
"\t initializer " << i <<
" name " << tensor_name <<
" type " << graph.initializer(i).data_type()
705 <<
" and length " << tensor_length << std::endl;
709 auto tensor_type =
static_cast<ETensorType>(graph.initializer(i).data_type());
714 allInitializedTensors[tensor_name] = i;
717 std::cout <<
"add initialized tensor " << tensor_name <<
"with shape " <<
ConvertShapeToString(shape) <<
"and ";
719 std::cout <<
" float data: ";
720 for (
int j = 0; j < std::min(int(tensor_length),3); j++) std::cout << static_cast<float*>(data.get())[j] <<
" ";
723 std::cout <<
" int64 data: ";
724 for (
int j = 0; j < std::min(int(tensor_length),3); j++) std::cout << static_cast<int64_t*>(data.get())[j] <<
" ";
727 std::cout <<
" uint8 data: ";
728 for (
int j = 0; j < std::min(int(tensor_length),3); j++) std::cout << static_cast<uint8_t*>(data.get())[j] <<
" ";
731 std::cout <<
" Boolean data: ";
732 for (
int j = 0; j < std::min(int(tensor_length),3); j++) std::cout << static_cast<bool*>(data.get())[j] <<
" ";
734 std::cout << std::endl;
740 std::cout <<
"\nGraph operator list (ONNX order)\n";
741 for (
int i = 0; i < graph.node_size(); i++) {
742 std::cout <<
"\tOperator " << i <<
" : " << graph.node(i).op_type() <<
" , " << graph.node(i).input_size()
744 for (
int j = 0; j < graph.node(i).input_size(); j++) {
745 std::cout << graph.node(i).input(j);
746 if (j < graph.node(i).input_size() - 1)
749 std::cout <<
" }" << std::endl;
755 std::cout <<
"\n***********************\nRe-Order graph operator list\n*************************\n";
756 std::vector<size_t> nodesOrder;
757 nodesOrder.reserve(graph.node_size());
758 std::vector<bool> foundNodes(graph.node_size());
761 std::map<std::string, int> allInputs;
762 for (
int i = 0; i < graph.input_size(); i++) {
763 allInputs[graph.input(i).name()] = -1;
766 auto psize = nodesOrder.size();
767 for (
int i = 0; i < graph.node_size(); i++) {
771 bool existInputs =
true;
772 int input_size = graph.node(i).input_size();
775 std::cout <<
"Checking input of Node " << i <<
" : " << graph.node(i).name() << std::endl;
776 for (
int j = 0; j < input_size; j++) {
777 std::string
name = graph.node(i).input(j);
780 existInputs &= (allInputs.find(
name) != allInputs.end() ||
781 allInitializedTensors.find(
name) != allInitializedTensors.end());
783 std::cout <<
"\t\t input " <<
name <<
" "
784 <<
bool(allInputs.find(
name) != allInputs.end()) <<
" " <<
785 bool(allInitializedTensors.find(
name) != allInitializedTensors.end()) <<
" " <<
786 existInputs << std::endl;
792 std::cout <<
"skip node " << graph.node(i).op_type() <<
" " << graph.node(i).name() <<
" inputs are not existing ";
793 for (
int j = 0; j < input_size; j++) {
794 std::cout << graph.node(i).input(j) <<
" ";
796 std::cout << std::endl;
803 std::cout <<
"===> New node " << graph.node(i).op_type() <<
" " << graph.node(i).name() <<
" order " << i << std::endl;
805 nodesOrder.push_back(i);
806 foundNodes[i] =
true;
808 for (
int j = 0; j < graph.node(i).output_size(); j++) {
809 if (
fVerbose) std::cout <<
"\toutput : " << graph.node(i).output(j) << std::endl;
810 allInputs[graph.node(i).output(j)] = i;
814 if (nodesOrder.size() == psize) {
815 int ilast = nodesOrder.back();
816 std::cout <<
"cannot find a new node after " << graph.node(ilast).op_type() <<
" " << graph.node(ilast).name() << std::endl;
817 throw std::runtime_error(
"TMVA::SOFIE - cannot find a new node ");
819 }
while ((
int)nodesOrder.size() < graph.node_size());
823 std::vector<std::vector<int>> nodesChildren(graph.node_size());
825 for (
int k = 0; k < graph.node_size(); k++) {
826 int i = nodesOrder[k];
828 if (graph.node(i).output_size() > 0) nodesChildren[i].reserve(graph.node(i).output_size());
829 for (
const auto& output_name : graph.node(i).output()) {
831 for (
int l = k;
l < graph.node_size();
l++) {
832 int j = nodesOrder[
l];
833 for (
const auto& input_name : graph.node(j).input()) {
834 if (input_name == output_name)
835 nodesChildren[i].push_back(j);
843 std::cout <<
"\nGraph operator list (re-ordered)\n";
844 for (
int k = 0; k < graph.node_size(); k++) {
845 int i = nodesOrder[k];
846 std::cout <<
"\tOperator " << i <<
" : " << graph.node(i).op_type() <<
" , " << graph.node(i).name() <<
" input tensors : {";
847 for (
int j = 0; j < graph.node(i).input_size(); j++) {
848 std::cout << graph.node(i).input(j);
849 if (j < graph.node(i).input_size() - 1)
853 std::cout <<
" children : {";
854 for (
const auto & ichild : nodesChildren[i]) {
855 std::cout <<
" [ " << ichild <<
" " << graph.node(ichild).op_type() <<
" , " << graph.node(ichild).name() <<
"]";
857 std::cout <<
"}" << std::endl;
863 std::cout <<
"Fill RModel with operators...\n";
868 size_t node_order_exec = 0;
869 for (
int i = 0; i < graph.node_size(); i++) {
870 std::string op_type = graph.node(nodesOrder[i]).op_type();
873 std::cout <<
"\t" << i <<
" " << nodesOrder[i] <<
" parsing operator " << op_type << std::endl;
876 std::unique_ptr<ROperator> op =
ParseOperator(i, graph, nodesOrder, nodesChildren[nodesOrder[i]]);
879 std::cout <<
"\t\tskipping operator since it is fused with previous one" << std::endl;
884 rmodel.
AddOperator(std::move(op), node_order_exec++);
887 std::vector<std::string> outputnames;
889 std::cout <<
"\nParsing Graph output list\n";
890 for (
int i = 0; i < graph.output_size(); i++) {
892 std::cout <<
"\toutput " << i <<
" name " << graph.output(i).name() << std::endl;
893 outputnames.push_back(graph.output(i).name());