• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright 2017 The TensorFlow Authors. All Rights Reserved.
2 
3 Licensed under the Apache License, Version 2.0 (the "License");
4 you may not use this file except in compliance with the License.
5 You may obtain a copy of the License at
6 
7     http://www.apache.org/licenses/LICENSE-2.0
8 
9 Unless required by applicable law or agreed to in writing, software
10 distributed under the License is distributed on an "AS IS" BASIS,
11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 See the License for the specific language governing permissions and
13 limitations under the License.
14 ==============================================================================*/
15 #include "tensorflow/lite/toco/tensorflow_util.h"
16 
17 #include <string.h>
18 #include <memory>
19 #include <set>
20 
21 #ifdef GOOGLE_PLATFORM
22 #include "file/logging/log_lines.h"
23 #endif
24 #include "google/protobuf/map.h"
25 #include "absl/strings/str_split.h"
26 #include "absl/strings/string_view.h"
27 #include "tensorflow/lite/toco/toco_port.h"
28 #include "tensorflow/lite/toco/tooling_util.h"
29 #include "tensorflow/core/framework/attr_value.pb.h"
30 #include "tensorflow/core/framework/node_def.pb.h"
31 #include "tensorflow/core/framework/tensor.pb.h"
32 #include "tensorflow/core/framework/types.pb.h"
33 #include "tensorflow/core/platform/logging.h"
34 
35 namespace toco {
36 
37 using tensorflow::AttrValue;
38 using tensorflow::GraphDef;
39 
LogDumpGraphDef(int log_level,const string & message,const GraphDef & tf_graph)40 void LogDumpGraphDef(int log_level, const string& message,
41                      const GraphDef& tf_graph) {
42   if (!VLOG_IS_ON(log_level)) {
43     return;
44   }
45   std::set<string> ops;
46   for (const auto& node : tf_graph.node()) {
47     ops.insert(node.op());
48   }
49   string dump;
50   toco::port::AppendF(&dump, R"MSG(
51 BEGIN DUMP OF TENSORFLOW GRAPHDEF (%s)
52 There are %d nodes.
53 There are %zu different op types:
54 )MSG",
55                       message, tf_graph.node_size(), ops.size());
56   for (const auto& op : ops) {
57     toco::port::AppendF(&dump, "  %s\n", op);
58   }
59   dump.append(R"MSG(
60 PROTO DUMP
61 )MSG");
62   for (const auto& node : tf_graph.node()) {
63     toco::port::AppendF(&dump, R"MSG(
64 BEGIN NODE: name = %s
65   op = %s
66   inputs = [
67 )MSG",
68                         node.name(), node.op());
69     for (const auto& input : node.input()) {
70       toco::port::AppendF(&dump, "    %s\n", input);
71     }
72     dump.append("  ]\n");
73     for (const auto& attr : node.attr()) {
74       toco::port::AppendF(&dump, "  ATTR: name = %s\n", attr.first);
75       if (attr.second.value_case() == AttrValue::kFunc) {
76         dump.append("    func\n");
77       } else if (attr.second.value_case() == AttrValue::kPlaceholder) {
78         toco::port::AppendF(&dump, "    placeholder: %s\n",
79                             attr.second.placeholder());
80       } else if (attr.second.value_case() == AttrValue::kS) {
81         dump.append("    string:\n");
82         dump.append(R"MSG(
83       BEGIN EMBEDDED STRING
84 )MSG");
85         const auto& lines = absl::StrSplit(attr.second.s(), '\n');
86         for (const auto& line : lines) {
87           toco::port::AppendF(&dump, "      %s\n", line);
88         }
89         dump.append(R"MSG(
90       END EMBEDDED STRING
91 )MSG");
92       } else if (attr.second.value_case() == AttrValue::kI) {
93         toco::port::AppendF(&dump, "    int: %lld\n", attr.second.i());
94       } else if (attr.second.value_case() == AttrValue::kF) {
95         toco::port::AppendF(&dump, "    float: %g\n", attr.second.f());
96       } else if (attr.second.value_case() == AttrValue::kB) {
97         toco::port::AppendF(&dump, "    bool: %s\n",
98                             attr.second.b() ? "true" : "false");
99       } else if (attr.second.value_case() == AttrValue::kType) {
100         toco::port::AppendF(&dump, "    type: %s\n",
101                             tensorflow::DataType_Name(attr.second.type()));
102       } else if (attr.second.value_case() == AttrValue::kShape) {
103         dump.append("    shape: [ ");
104         const auto& shape = attr.second.shape();
105         for (int i = 0; i < shape.dim_size(); i++) {
106           toco::port::AppendF(&dump, "%lld ", shape.dim(i).size());
107         }
108         dump.append("]\n");
109       } else if (attr.second.value_case() == AttrValue::kTensor) {
110         const auto& tensor = attr.second.tensor();
111         dump.append("    TENSOR:\n");
112         toco::port::AppendF(&dump, "      type: %s\n",
113                             tensorflow::DataType_Name(tensor.dtype()));
114         const auto& shape = tensor.tensor_shape();
115         dump.append("      shape: [ ");
116         for (int i = 0; i < shape.dim_size(); i++) {
117           toco::port::AppendF(&dump, "%lld ", shape.dim(i).size());
118         }
119         dump.append("]\n");
120         if (!tensor.tensor_content().empty()) {
121           toco::port::AppendF(&dump, "      tensor_content: %zu bytes\n",
122                               tensor.tensor_content().size());
123         }
124         if (tensor.dtype() == tensorflow::DT_INT32) {
125           CHECK_EQ(0, tensor.tensor_content().size() % sizeof(int32));
126           const int size = tensor.tensor_content().size() / sizeof(int32);
127           std::vector<int32> data(size);
128           toco::port::CopyToBuffer(tensor.tensor_content(),
129                                    reinterpret_cast<char*>(data.data()));
130           const int kMaxValsToPrint = 4;
131           dump.append("        tensor_content as ints: [ ");
132           for (int i = 0; i < kMaxValsToPrint && i < size; i++) {
133             toco::port::AppendF(&dump, "%d ", data[i]);
134           }
135           if (size > kMaxValsToPrint) {
136             dump.append("... ");
137           }
138           dump.append("]\n");
139         }
140         if (tensor.dtype() == tensorflow::DT_FLOAT) {
141           CHECK_EQ(0, tensor.tensor_content().size() % sizeof(float));
142           const int size = tensor.tensor_content().size() / sizeof(float);
143           std::vector<float> data(size);
144           toco::port::CopyToBuffer(tensor.tensor_content(),
145                                    reinterpret_cast<char*>(data.data()));
146           const int kMaxValsToPrint = 4;
147           dump.append("        tensor_content as floats: [ ");
148           for (int i = 0; i < kMaxValsToPrint && i < size; i++) {
149             toco::port::AppendF(&dump, "%g ", data[i]);
150           }
151           if (size > kMaxValsToPrint) {
152             dump.append("... ");
153           }
154           dump.append("]\n");
155         }
156         if (tensor.int_val_size()) {
157           toco::port::AppendF(&dump, "      int_val: %d ints: [ ",
158                               tensor.int_val_size());
159           const int kMaxValsToPrint = 4;
160           for (int i = 0; i < kMaxValsToPrint && i < tensor.int_val_size();
161                i++) {
162             toco::port::AppendF(&dump, "%d ", tensor.int_val(i));
163           }
164           if (tensor.int_val_size() > kMaxValsToPrint) {
165             dump.append("... ");
166           }
167           dump.append("]\n");
168         }
169         if (tensor.float_val_size()) {
170           toco::port::AppendF(&dump, "      float_val: %d floats: [ ",
171                               tensor.float_val_size());
172           const int kMaxValsToPrint = 4;
173           for (int i = 0; i < kMaxValsToPrint && i < tensor.float_val_size();
174                i++) {
175             toco::port::AppendF(&dump, "%g ", tensor.float_val(i));
176           }
177           if (tensor.float_val_size() > kMaxValsToPrint) {
178             dump.append("... ");
179           }
180           dump.append("]\n");
181         }
182         if (tensor.string_val_size()) {
183           toco::port::AppendF(&dump, "      string_val: %d strings\n",
184                               tensor.string_val_size());
185         }
186       } else if (attr.second.value_case() == AttrValue::kList) {
187         dump.append("  LIST\n");
188       }
189     }
190     dump.append("END NODE\n");
191   }
192   toco::port::AppendF(&dump, "END DUMP OF TENSORFLOW GRAPHDEF (%s)\n", message);
193 #if defined(GOOGLE_PLATFORM)
194   VLOG_LINES(log_level, dump);
195 #else
196   VLOG(log_level) << dump;
197 #endif
198 }
199 }  // namespace toco
200