Skip to content

Commit 30faa6d

Browse files
gcarranza-1copybara-github
authored andcommitted
Modify gpu_numerics_check to accept multiple models.
LiteRT-PiperOrigin-RevId: 826195884
1 parent fccdeae commit 30faa6d

File tree

5 files changed

+128
-22
lines changed

5 files changed

+128
-22
lines changed

litert/core/filesystem.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,10 @@ std::string Join(const std::vector<absl::string_view>& paths) {
7373
return std_path.generic_string();
7474
}
7575

76+
std::string Stem(absl::string_view path) {
77+
return MakeStdPath(path).stem().generic_string();
78+
}
79+
7680
bool Exists(absl::string_view path) { return StdExists(MakeStdPath(path)); }
7781

7882
Expected<size_t> Size(absl::string_view path) {

litert/core/filesystem.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ namespace litert::internal {
3232
// Append all given subpaths together (e.g. os.path.join).
3333
std::string Join(const std::vector<absl::string_view>& paths);
3434

35+
// Returns the stem of the given path.
36+
std::string Stem(absl::string_view path);
37+
3538
// Make a new empty file at the given path.
3639
void Touch(absl::string_view path);
3740

litert/core/filesystem_test.cc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ namespace {
2424
static constexpr absl::string_view kPrefix = "a/prefix";
2525
static constexpr absl::string_view kInfix = "an/infix";
2626
static constexpr absl::string_view kSuffix = "suffix.ext";
27+
static constexpr absl::string_view kPath = "a/prefix.ext";
28+
static constexpr absl::string_view kStem = "prefix";
2729

2830
TEST(FilesystemTest, JoinTwo) {
2931
const auto path = Join({kPrefix, kSuffix});
@@ -35,5 +37,10 @@ TEST(FilesystemTest, JoinMany) {
3537
EXPECT_EQ(path, absl::StrFormat("%s/%s/%s", kPrefix, kInfix, kSuffix));
3638
}
3739

40+
TEST(FilesystemTest, Stem){
41+
const auto stem = Stem(kPath);
42+
EXPECT_EQ(stem, kStem);
43+
}
44+
3845
} // namespace
3946
} // namespace litert::internal

litert/tools/BUILD

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -511,6 +511,7 @@ cc_binary(
511511
srcs = ["gpu_numerics_check.cc"],
512512
deps = NUMERICS_CHECK_DEPS + [
513513
"//litert/cc/options:litert_gpu_options",
514+
"//litert/core:filesystem",
514515
] + GPU_ACCELERATOR_DEPS,
515516
)
516517

@@ -519,6 +520,7 @@ cc_binary(
519520
srcs = ["gpu_numerics_check.cc"],
520521
deps = NUMERICS_CHECK_DEPS + [
521522
"//litert/cc/options:litert_gpu_options",
523+
"//litert/core:filesystem",
522524
# copybara:uncomment_begin(google-only)
523525
# "//litert/runtime/accelerators/gpu:ml_drift_cl_gl_accelerator", # buildcleaner: keep
524526
# copybara:uncomment_end
@@ -531,6 +533,7 @@ cc_binary(
531533
tags = ["requires-gpu-nvidia"],
532534
deps = NUMERICS_CHECK_DEPS + [
533535
"//litert/cc/options:litert_gpu_options",
536+
"//litert/core:filesystem",
534537
# copybara:uncomment_begin(google-only)
535538
# "//litert/runtime/accelerators/gpu:ml_drift_vulkan_accelerator", # buildcleaner: keep
536539
# "//third_party/vulkan_loader",
@@ -548,6 +551,7 @@ cc_binary(
548551
],
549552
deps = NUMERICS_CHECK_DEPS + [
550553
"//litert/cc/options:litert_gpu_options",
554+
"//litert/core:filesystem",
551555
# copybara:uncomment_begin(google-only)
552556
# "//litert/runtime/accelerators/gpu/google:jet_gpu_accelerator", # buildcleaner: keep
553557
# copybara:uncomment_end

litert/tools/gpu_numerics_check.cc

Lines changed: 110 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include "absl/flags/parse.h" // from @com_google_absl
3030
#include "absl/log/absl_log.h" // from @com_google_absl
3131
#include "absl/strings/str_format.h" // from @com_google_absl
32+
#include "absl/strings/string_view.h" // from @com_google_absl
3233
#include "absl/types/span.h" // from @com_google_absl
3334
#include "litert/c/litert_common.h"
3435
#include "litert/cc/litert_compiled_model.h"
@@ -40,8 +41,14 @@
4041
#include "litert/cc/litert_options.h"
4142
#include "litert/cc/litert_tensor_buffer.h"
4243
#include "litert/cc/options/litert_gpu_options.h"
43-
44-
ABSL_FLAG(std::string, graph, "", "Model filename to use for testing.");
44+
#include "litert/core/filesystem.h"
45+
46+
ABSL_FLAG(bool, print_diff_stats, false,
47+
"Whether to print the diff stats CSV.");
48+
ABSL_FLAG(std::string, model_dir, "",
49+
"Optional base directory to prepend to models provide in --graph.");
50+
ABSL_FLAG(std::vector<std::string>, graph, {},
51+
"Model file(s) to use for testing.");
4552
ABSL_FLAG(size_t, signature_index, 0, "Index of the signature to run.");
4653
ABSL_FLAG(float, epsilon, 1e-4f,
4754
"Threshold value for gpu / cpu inference comparison");
@@ -56,8 +63,33 @@ ABSL_FLAG(bool, enable_constant_tensors_sharing, false,
5663
"Whether to enable constant tensors sharing.");
5764

5865
namespace litert {
66+
5967
namespace {
6068

69+
struct BufferDiffStats {
70+
// Index of output buffer.
71+
size_t buffer_idx;
72+
// Total number of elements in the buffer.
73+
size_t total_elements;
74+
// Number of elements with absolute difference greater than epsilon.
75+
size_t diff_elements;
76+
// Epsilon value used for comparison.
77+
double epsilon;
78+
// Maximum absolute difference between CPU and GPU values.
79+
double max_diff;
80+
// Minimum absolute difference between CPU and GPU values.
81+
double min_diff;
82+
// Mean absolute difference between CPU and GPU values.
83+
double mean_diff;
84+
// Mean squared error between CPU and GPU values.
85+
double mse;
86+
};
87+
88+
struct ModelRunResult {
89+
std::string model_name;
90+
std::vector<BufferDiffStats> diff_stats;
91+
};
92+
6193
Expected<Environment> GetEnvironment() {
6294
std::vector<litert::Environment::Option> environment_options = {};
6395

@@ -154,13 +186,14 @@ Expected<std::vector<TensorBuffer>> CreateOutputBuffers(
154186
}
155187

156188
// Compares a single pair of output buffers and prints the results.
157-
Expected<void> CompareSingleOutputBuffer(TensorBuffer& cpu_buffer,
158-
TensorBuffer& gpu_buffer,
159-
size_t buffer_index, float epsilon) {
189+
Expected<BufferDiffStats> CompareSingleOutputBuffer(TensorBuffer& cpu_buffer,
190+
TensorBuffer& gpu_buffer,
191+
size_t buffer_index,
192+
float epsilon) {
160193
std::vector<std::pair<float, int>> all_diffs;
161194
const int kMaxPrint = 20;
162195
int printed = 0;
163-
int total_different = 0;
196+
size_t total_different = 0;
164197
double mean_squared_error = 0;
165198
float mean_diff = 0;
166199

@@ -299,10 +332,19 @@ Expected<void> CompareSingleOutputBuffer(TensorBuffer& cpu_buffer,
299332
std::cout << "Total " << total_different << " out of " << total_elements
300333
<< " are different elements, for output #" << buffer_index
301334
<< ", threshold - " << epsilon << std::endl;
302-
return {};
335+
return BufferDiffStats{
336+
.buffer_idx = buffer_index,
337+
.total_elements = total_elements,
338+
.diff_elements = total_different,
339+
.epsilon = epsilon,
340+
.max_diff = all_diffs.back().first,
341+
.min_diff = all_diffs.front().first,
342+
.mean_diff = mean_diff / all_diffs.size(),
343+
.mse = mean_squared_error / total_elements,
344+
};
303345
}
304346

305-
Expected<void> CompareOutputBuffers(
347+
Expected<std::vector<BufferDiffStats>> CompareOutputBuffers(
306348
std::vector<TensorBuffer>& cpu_output_buffers,
307349
std::vector<TensorBuffer>& gpu_output_buffers) {
308350
if (cpu_output_buffers.size() != gpu_output_buffers.size()) {
@@ -312,26 +354,24 @@ Expected<void> CompareOutputBuffers(
312354

313355
float epsilon = absl::GetFlag(FLAGS_epsilon);
314356
size_t num_output_buffers = cpu_output_buffers.size();
357+
std::vector<BufferDiffStats> diff_stats;
315358
for (size_t i = 0; i < num_output_buffers; ++i) {
316359
auto& cpu_buffer = cpu_output_buffers[i];
317360
auto& gpu_buffer = gpu_output_buffers[i];
318-
LITERT_RETURN_IF_ERROR(
361+
LITERT_ASSIGN_OR_RETURN(
362+
auto diff_stat,
319363
CompareSingleOutputBuffer(cpu_buffer, gpu_buffer, i, epsilon));
364+
diff_stats.push_back(std::move(diff_stat));
320365
}
321-
return {};
366+
return diff_stats;
322367
}
323368

324-
Expected<void> RunModel() {
325-
if (absl::GetFlag(FLAGS_graph).empty()) {
326-
return Error(kLiteRtStatusErrorInvalidArgument,
327-
"model filename is empty. Use --graph to provide it.");
328-
}
329-
330-
ABSL_LOG(INFO) << "Model: " << absl::GetFlag(FLAGS_graph);
369+
Expected<std::vector<BufferDiffStats>> RunModel(absl::string_view model_path) {
370+
ABSL_LOG(INFO) << "Model: " << model_path;
331371
LITERT_ASSIGN_OR_RETURN(auto cpu_model,
332-
Model::CreateFromFile(absl::GetFlag(FLAGS_graph)));
372+
Model::CreateFromFile(std::string(model_path)));
333373
LITERT_ASSIGN_OR_RETURN(auto gpu_model,
334-
Model::CreateFromFile(absl::GetFlag(FLAGS_graph)));
374+
Model::CreateFromFile(std::string(model_path)));
335375

336376
LITERT_ASSIGN_OR_RETURN(auto env, GetEnvironment());
337377

@@ -373,10 +413,53 @@ Expected<void> RunModel() {
373413
signature_index, gpu_input_buffers, gpu_output_buffers));
374414

375415
// Compare output buffers
376-
LITERT_RETURN_IF_ERROR(
416+
LITERT_ASSIGN_OR_RETURN(
417+
auto diff_stats,
377418
CompareOutputBuffers(cpu_output_buffers, gpu_output_buffers));
419+
return diff_stats;
420+
}
421+
422+
Expected<std::vector<ModelRunResult>> RunModels() {
423+
std::vector<std::string> relative_model_paths = absl::GetFlag(FLAGS_graph);
424+
if (relative_model_paths.empty()) {
425+
return Error(kLiteRtStatusErrorInvalidArgument,
426+
"No model provided. Use --graph to provide it.");
427+
}
378428

379-
return {};
429+
std::string model_dir = absl::GetFlag(FLAGS_model_dir);
430+
std::vector<std::string> full_model_paths;
431+
full_model_paths.reserve(relative_model_paths.size());
432+
for (auto& model_path : relative_model_paths) {
433+
full_model_paths.push_back(internal::Join({model_dir, model_path}));
434+
}
435+
436+
std::vector<ModelRunResult> results;
437+
for (const auto& model_path : full_model_paths) {
438+
LITERT_ASSIGN_OR_RETURN(std::vector<BufferDiffStats> diff_stats,
439+
RunModel(model_path));
440+
results.push_back(ModelRunResult{
441+
.model_name = internal::Stem(model_path),
442+
.diff_stats = std::move(diff_stats),
443+
});
444+
}
445+
446+
return results;
447+
}
448+
449+
void PrintDiffStats(const std::vector<litert::ModelRunResult>& results) {
450+
// Print CSV header
451+
std::cout << "model_name, buffer_idx, total_elements, diff_elements, "
452+
"epsilon, max_diff, min_diff, mean_diff, mse"
453+
<< std::endl;
454+
for (const auto& result : results) {
455+
for (const auto& diff_stat : result.diff_stats) {
456+
std::cout << result.model_name << ", " << diff_stat.buffer_idx << ", "
457+
<< diff_stat.total_elements << ", " << diff_stat.diff_elements
458+
<< ", " << diff_stat.epsilon << ", " << diff_stat.max_diff
459+
<< ", " << diff_stat.min_diff << ", " << diff_stat.mean_diff
460+
<< ", " << diff_stat.mse << std::endl;
461+
}
462+
}
380463
}
381464

382465
} // namespace
@@ -385,10 +468,15 @@ Expected<void> RunModel() {
385468
int main(int argc, char** argv) {
386469
absl::ParseCommandLine(argc, argv);
387470

388-
auto res = litert::RunModel();
471+
auto res = litert::RunModels();
389472
if (!res) {
390473
ABSL_LOG(ERROR) << res.Error().Message();
391474
return EXIT_FAILURE;
392475
}
476+
477+
if (absl::GetFlag(FLAGS_print_diff_stats)) {
478+
litert::PrintDiffStats(*res);
479+
}
480+
393481
return EXIT_SUCCESS;
394482
}

0 commit comments

Comments
 (0)