1 /* Copyright 2019 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
16 #include "tensorflow/lite/tools/evaluation/utils.h"
17
18 #if !defined(_WIN32)
19 #include <dirent.h>
20 #endif
21 #include <sys/stat.h>
22
23 #include <algorithm>
24 #include <fstream>
25 #include <memory>
26 #include <string>
27
28 namespace tflite {
29 namespace evaluation {
30
31 namespace {
32
CreateNullDelegate()33 TfLiteDelegatePtr CreateNullDelegate() {
34 return TfLiteDelegatePtr(nullptr, [](TfLiteDelegate*) {});
35 }
36
37 } // namespace
38
StripTrailingSlashes(const std::string & path)39 std::string StripTrailingSlashes(const std::string& path) {
40 int end = path.size();
41 while (end > 0 && path[end - 1] == '/') {
42 end--;
43 }
44 return path.substr(0, end);
45 }
46
ReadFileLines(const std::string & file_path,std::vector<std::string> * lines_output)47 bool ReadFileLines(const std::string& file_path,
48 std::vector<std::string>* lines_output) {
49 if (!lines_output) {
50 return false;
51 }
52 std::ifstream stream(file_path.c_str());
53 if (!stream) {
54 return false;
55 }
56 std::string line;
57 while (std::getline(stream, line)) {
58 lines_output->push_back(line);
59 }
60 return true;
61 }
62
63 #if !defined(_WIN32)
GetSortedFileNames(const std::string & directory,std::vector<std::string> * result,const std::unordered_set<std::string> & extensions)64 TfLiteStatus GetSortedFileNames(
65 const std::string& directory, std::vector<std::string>* result,
66 const std::unordered_set<std::string>& extensions) {
67 DIR* dir;
68 struct dirent* ent;
69 if (result == nullptr) {
70 return kTfLiteError;
71 }
72 result->clear();
73 std::string dir_path = StripTrailingSlashes(directory);
74 if ((dir = opendir(dir_path.c_str())) != nullptr) {
75 while ((ent = readdir(dir)) != nullptr) {
76 if (ent->d_type == DT_DIR) continue;
77 std::string filename(std::string(ent->d_name));
78 size_t lastdot = filename.find_last_of('.');
79 std::string ext = lastdot != std::string::npos ? filename.substr(lastdot)
80 : std::string();
81 std::transform(ext.begin(), ext.end(), ext.begin(), ::tolower);
82 if (!extensions.empty() && extensions.find(ext) == extensions.end()) {
83 continue;
84 }
85 result->emplace_back(dir_path + "/" + filename);
86 }
87 closedir(dir);
88 } else {
89 return kTfLiteError;
90 }
91 std::sort(result->begin(), result->end());
92 return kTfLiteOk;
93 }
94 #endif
95
96 // TODO(b/138448769): Migrate delegate helper APIs to lite/testing.
CreateNNAPIDelegate()97 TfLiteDelegatePtr CreateNNAPIDelegate() {
98 #if defined(__ANDROID__)
99 return TfLiteDelegatePtr(
100 NnApiDelegate(),
101 // NnApiDelegate() returns a singleton, so provide a no-op deleter.
102 [](TfLiteDelegate*) {});
103 #else
104 return CreateNullDelegate();
105 #endif // defined(__ANDROID__)
106 }
107
CreateNNAPIDelegate(StatefulNnApiDelegate::Options options)108 TfLiteDelegatePtr CreateNNAPIDelegate(StatefulNnApiDelegate::Options options) {
109 #if defined(__ANDROID__)
110 return TfLiteDelegatePtr(
111 new StatefulNnApiDelegate(options), [](TfLiteDelegate* delegate) {
112 delete reinterpret_cast<StatefulNnApiDelegate*>(delegate);
113 });
114 #else
115 return CreateNullDelegate();
116 #endif // defined(__ANDROID__)
117 }
118
119 #if TFLITE_SUPPORTS_GPU_DELEGATE
CreateGPUDelegate(TfLiteGpuDelegateOptionsV2 * options)120 TfLiteDelegatePtr CreateGPUDelegate(TfLiteGpuDelegateOptionsV2* options) {
121 return TfLiteDelegatePtr(TfLiteGpuDelegateV2Create(options),
122 &TfLiteGpuDelegateV2Delete);
123 }
124 #endif // TFLITE_SUPPORTS_GPU_DELEGATE
125
CreateGPUDelegate()126 TfLiteDelegatePtr CreateGPUDelegate() {
127 #if TFLITE_SUPPORTS_GPU_DELEGATE
128 TfLiteGpuDelegateOptionsV2 options = TfLiteGpuDelegateOptionsV2Default();
129 options.inference_priority1 = TFLITE_GPU_INFERENCE_PRIORITY_MIN_LATENCY;
130 options.inference_preference =
131 TFLITE_GPU_INFERENCE_PREFERENCE_SUSTAINED_SPEED;
132
133 return CreateGPUDelegate(&options);
134 #else
135 return CreateNullDelegate();
136 #endif // TFLITE_SUPPORTS_GPU_DELEGATE
137 }
138
CreateHexagonDelegate(const std::string & library_directory_path,bool profiling)139 TfLiteDelegatePtr CreateHexagonDelegate(
140 const std::string& library_directory_path, bool profiling) {
141 #if defined(__ANDROID__) && (defined(__arm__) || defined(__aarch64__))
142 TfLiteHexagonDelegateOptions options = {0};
143 options.print_graph_profile = profiling;
144 return CreateHexagonDelegate(&options, library_directory_path);
145 #else
146 return CreateNullDelegate();
147 #endif // defined(__ANDROID__)
148 }
149
150 #if defined(__ANDROID__) && (defined(__arm__) || defined(__aarch64__))
CreateHexagonDelegate(const TfLiteHexagonDelegateOptions * options,const std::string & library_directory_path)151 TfLiteDelegatePtr CreateHexagonDelegate(
152 const TfLiteHexagonDelegateOptions* options,
153 const std::string& library_directory_path) {
154 if (library_directory_path.empty()) {
155 TfLiteHexagonInit();
156 } else {
157 TfLiteHexagonInitWithPath(library_directory_path.c_str());
158 }
159
160 TfLiteDelegate* delegate = TfLiteHexagonDelegateCreate(options);
161 if (!delegate) {
162 TfLiteHexagonTearDown();
163 return CreateNullDelegate();
164 }
165 return TfLiteDelegatePtr(delegate, [](TfLiteDelegate* delegate) {
166 TfLiteHexagonDelegateDelete(delegate);
167 TfLiteHexagonTearDown();
168 });
169 }
170 #endif
171
172 // TODO(b/149248802): include XNNPACK delegate when the issue is resolved.
173 #if defined(__Fuchsia__) || defined(TFLITE_WITHOUT_XNNPACK)
CreateXNNPACKDelegate(int num_threads)174 TfLiteDelegatePtr CreateXNNPACKDelegate(int num_threads) {
175 return CreateNullDelegate();
176 }
177 #else
CreateXNNPACKDelegate()178 TfLiteDelegatePtr CreateXNNPACKDelegate() {
179 TfLiteXNNPackDelegateOptions xnnpack_options =
180 TfLiteXNNPackDelegateOptionsDefault();
181 return CreateXNNPACKDelegate(&xnnpack_options);
182 }
183
CreateXNNPACKDelegate(const TfLiteXNNPackDelegateOptions * xnnpack_options)184 TfLiteDelegatePtr CreateXNNPACKDelegate(
185 const TfLiteXNNPackDelegateOptions* xnnpack_options) {
186 auto xnnpack_delegate = TfLiteXNNPackDelegateCreate(xnnpack_options);
187 return TfLiteDelegatePtr(xnnpack_delegate, [](TfLiteDelegate* delegate) {
188 TfLiteXNNPackDelegateDelete(delegate);
189 });
190 }
191
CreateXNNPACKDelegate(int num_threads)192 TfLiteDelegatePtr CreateXNNPACKDelegate(int num_threads) {
193 auto opts = TfLiteXNNPackDelegateOptionsDefault();
194 // Note that we don't want to use the thread pool for num_threads == 1.
195 opts.num_threads = num_threads > 1 ? num_threads : 0;
196 return CreateXNNPACKDelegate(&opts);
197 }
198 #endif
199 } // namespace evaluation
200 } // namespace tflite
201