Skip to content

Commit 66608c8

Browse files
anhappdevfreedomtanRSMNYSmohitmundhragithub
authored
feat: add new benchmark Stable Diffusion (#903)
* add scaffold of coco_gen dataset * test coco_gen * use smart ptr * minimal ProcessOutput() * support float32 output tensor * Add new benchmark stable_diffusion * Add dummy_stable_diffusion.tflite * Add clip_score.cc * Add generate_tfrecords.py * Update CaptionRecord * Add coco_gen.tfrecord * Compute accuracy * Format files * Add notebook to convert CLIP model to TFLite model with resize layer * Move score prediction from ProcessOutput() to ComputeAccuracy() * Split clip_score into .h and .cpp files * Add expected_throughput and expected_accuracy * Update file paths * Format files * refactor TFLite backend to support multiple ML pipelines * Use custom setting for selecting pipeline * Update CLIP_Model_to_TFLite.ipynb * Log record_id for debug purpose * Refactor benchmark result validity * Ignore the early-stopping condition for stable_diffusion task * feat: added stable diffusion pipeline (WIP) (#905) * feat: added stable diffusion pipeline (WIP) * - enabled stable diffusion pipeline - code formatting * style: code formatting * style: code formatting * fix: adjusted inputs and outputs for the stable_diffusion_pipeline * fix: adjusted sd flow * fix: added unconditional tokens generation * chore: adjustments * Update mode paths for stable_diffusion * Fix proto/test.cc * Remove id and image_id from tfrecord file * Clean up * Update datasets path * Delete dummy_stable_diffusion.tflite * Suggestions for few changes in coco_gen dataset (#908) * Suggestions for few changes in coco_gen dataset * Fixing a path * Update random number seeds * Format code * Fix neuron/BUILD file * Dump raw output to file for COCOGEN (#912) * Dump output of SD model to file * Add Python script to convert RGB8 to PNG * Dump raw output only in accuracy mode * Disable stable_diffusion task * Fix Windows build issue error C2039: '__fs': is not a member of 'std' * Fix build error on iOS by increasing IPHONEOS_DEPLOYMENT_TARGET to 13.1 error: 'path' is unavailable: introduced in iOS 13.0 * Fix Dart linter error * Fix build error on iOS by increasing IPHONEOS_DEPLOYMENT_TARGET to 13.1 error: 'path' is unavailable: introduced in iOS 13.0 --------- Co-authored-by: Koan-Sin Tan <[email protected]> Co-authored-by: RSMNYS <[email protected]> Co-authored-by: Mohit Mundhra <[email protected]>
1 parent 2e6931e commit 66608c8

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+2356
-101
lines changed

.bazelrc

+1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ build:ios --copt=-w
2222
build:windows --copt=/W0
2323

2424
# Build in C++ 17 mode.
25+
build --cxxopt=-std=c++17
2526
build:android --cxxopt=-std=c++17
2627
build:android --host_cxxopt=-std=c++17
2728
build:ios --cxxopt=-std=c++17

docs/result-spec.md

+1
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ If you enable Submission mode, both `performance_run` and `accuracy_run` values
104104
* `COCO`
105105
* `ADE20K`
106106
* `SQUAD`
107+
* `COCOGEN`
107108
* `data_path`: string
108109
* `groundtruth_path`: string
109110
* `accuracy_run`: map

flutter/assets/tasks.pbtxt

+33
Original file line numberDiff line numberDiff line change
@@ -289,3 +289,36 @@ task {
289289
num_classes: 1000
290290
}
291291
}
292+
293+
task {
294+
id: "stable_diffusion"
295+
name: "Stable Diffusion"
296+
min_query_count: 5
297+
min_duration: 60
298+
max_duration: 600
299+
max_throughput: 2000
300+
max_accuracy: 1.0
301+
scenario: "SingleStream"
302+
datasets {
303+
type: COCOGEN
304+
full {
305+
name: "COCO validation set for Stable Diffusion"
306+
input_path: "https://github.com/anhappdev/tmp/releases/download/5/coco_gen_test.tfrecord"
307+
groundtruth_path: "local:///mlperf_models/stable-diffusion/clip_model_512x512.tflite"
308+
}
309+
lite {
310+
name: "COCO validation set for Stable Diffusion"
311+
input_path: "https://github.com/anhappdev/tmp/releases/download/5/coco_gen_full.tfrecord"
312+
groundtruth_path: ""
313+
}
314+
tiny {
315+
name: "COCO validation set for Stable Diffusion"
316+
input_path: "https://github.com/anhappdev/tmp/releases/download/2/coco_gen.tfrecord"
317+
groundtruth_path: "local:///mlperf_models/stable-diffusion/clip_model_512x512.tflite"
318+
}
319+
}
320+
model {
321+
id: "stable_diffusion"
322+
name: "StableDiffusion"
323+
}
324+
}

flutter/cpp/binary/BUILD

+1
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ cc_binary(
5353
"//flutter/cpp/backends:external",
5454
"//flutter/cpp/datasets:ade20k",
5555
"//flutter/cpp/datasets:coco",
56+
"//flutter/cpp/datasets:coco_gen",
5657
"//flutter/cpp/datasets:imagenet",
5758
"//flutter/cpp/datasets:snu_sr",
5859
"//flutter/cpp/datasets:squad",

flutter/cpp/binary/main.cc

+28-1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ limitations under the License.
2424
#include "flutter/cpp/backends/external.h"
2525
#include "flutter/cpp/datasets/ade20k.h"
2626
#include "flutter/cpp/datasets/coco.h"
27+
#include "flutter/cpp/datasets/coco_gen.h"
2728
#include "flutter/cpp/datasets/imagenet.h"
2829
#include "flutter/cpp/datasets/snu_sr.h"
2930
#include "flutter/cpp/datasets/squad.h"
@@ -64,6 +65,8 @@ DatasetConfig::DatasetType Str2DatasetType(absl::string_view name) {
6465
return DatasetConfig::ADE20K;
6566
} else if (absl::EqualsIgnoreCase(name, "SNUSR")) {
6667
return DatasetConfig::SNUSR;
68+
} else if (absl::EqualsIgnoreCase(name, "COCOGEN")) {
69+
return DatasetConfig::COCOGEN;
6770
} else if (absl::EqualsIgnoreCase(name, "DUMMY")) {
6871
return DatasetConfig::NONE;
6972
} else {
@@ -83,6 +86,8 @@ DatasetConfig::DatasetType BenchmarkId2DatasetType(absl::string_view name) {
8386
return DatasetConfig::ADE20K;
8487
} else if (absl::StartsWith(name, "super_resolution")) {
8588
return DatasetConfig::SNUSR;
89+
} else if (absl::StartsWith(name, "stable_diffusion")) {
90+
return DatasetConfig::COCOGEN;
8691
} else {
8792
LOG(FATAL) << "Unrecognized benchmark_id: " << name;
8893
return DatasetConfig::NONE;
@@ -108,7 +113,7 @@ int Main(int argc, char *argv[]) {
108113
"Benchmark ID. One of image_classification, "
109114
"image_classification_v2, object_detection, "
110115
"natural_language_processing, "
111-
"image_segmentation_v2, super_resolution, "
116+
"image_segmentation_v2, super_resolution, stable_diffusion, "
112117
"image_classification_offline, image_classification_offline_v2",
113118
Flag::kPositional)};
114119
Flags::Parse(&argc, const_cast<const char **>(argv), flag_list);
@@ -362,6 +367,28 @@ int Main(int argc, char *argv[]) {
362367
flag_list.insert(flag_list.end(), dataset_flags.begin(),
363368
dataset_flags.end());
364369
} break;
370+
case DatasetConfig::COCOGEN: {
371+
LOG(INFO) << "Using COCO 2014 dataset for Stable Diffusion benchmark";
372+
std::string input_tfrecord, input_clip_model = "";
373+
std::vector<Flag> dataset_flags{
374+
Flag::CreateFlag(
375+
"input_tfrecord", &input_tfrecord,
376+
"Path to the tfrecord file containing inputs for the model.",
377+
Flag::kRequired),
378+
Flag::CreateFlag(
379+
"input_clip_model", &input_clip_model,
380+
"Path to the CLIP model (TFLite) file for score prediction."),
381+
};
382+
383+
if (Flags::Parse(&argc, const_cast<const char **>(argv), dataset_flags) &&
384+
backend) {
385+
dataset.reset(new CocoGen(backend.get(), input_tfrecord,
386+
input_clip_model, output_dir));
387+
}
388+
// Adds to flag_list for showing help.
389+
flag_list.insert(flag_list.end(), dataset_flags.begin(),
390+
dataset_flags.end());
391+
} break;
365392
case DatasetConfig::NONE:
366393
default:
367394
break;

flutter/cpp/datasets/BUILD

+34
Original file line numberDiff line numberDiff line change
@@ -170,3 +170,37 @@ cc_library(
170170
"@org_tensorflow//tensorflow/lite/tools/evaluation/stages:image_preprocessing_stage",
171171
],
172172
)
173+
174+
cc_library(
175+
name = "coco_gen",
176+
srcs = [
177+
"coco_gen.cc",
178+
],
179+
hdrs = [
180+
"coco_gen.h",
181+
"utils.h",
182+
],
183+
copts = tflite_copts() + select({
184+
"//flutter/android/commonlibs:use_asan": [
185+
"-fsanitize=address",
186+
"-g",
187+
"-O1",
188+
"-fno-omit-frame-pointer",
189+
],
190+
"//conditions:default": [],
191+
}),
192+
deps = [
193+
":allocator",
194+
"//flutter/cpp:mlperf_driver",
195+
"//flutter/cpp:utils",
196+
"//flutter/cpp/backends:external",
197+
"//flutter/cpp/datasets/coco_gen_utils",
198+
"//flutter/cpp/datasets/squad_utils",
199+
"@com_google_absl//absl/container:flat_hash_map",
200+
"@com_google_protobuf//:protobuf",
201+
"@org_tensorflow//tensorflow/lite/tools/evaluation:utils",
202+
"@org_tensorflow//tensorflow/lite/tools/evaluation/proto:evaluation_stages_cc_proto",
203+
"@org_tensorflow//tensorflow/lite/tools/evaluation/stages:image_preprocessing_stage",
204+
"@org_tensorflow//tensorflow/lite/tools/evaluation/stages:object_detection_average_precision_stage",
205+
],
206+
)

flutter/cpp/datasets/coco_gen.cc

+156
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
/* Copyright 2024 The MLPerf Authors. All Rights Reserved.
2+
Licensed under the Apache License, Version 2.0 (the "License");
3+
you may not use this file except in compliance with the License.
4+
You may obtain a copy of the License at
5+
http://www.apache.org/licenses/LICENSE-2.0
6+
Unless required by applicable law or agreed to in writing, software
7+
distributed under the License is distributed on an "AS IS" BASIS,
8+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9+
See the License for the specific language governing permissions and
10+
limitations under the License.
11+
==============================================================================*/
12+
13+
#include "coco_gen.h"
14+
15+
#include <filesystem>
16+
#include <fstream>
17+
#include <iomanip>
18+
19+
namespace mlperf {
20+
namespace mobile {
21+
22+
void dump_output_pixels(const std::vector<uint8_t>& output_pixels,
23+
const std::string& output_filename) {
24+
std::ofstream output_file(output_filename, std::ios::binary);
25+
if (!output_file) {
26+
LOG(ERROR) << "Could not open file for writing: " << output_filename;
27+
return;
28+
}
29+
30+
output_file.write(
31+
reinterpret_cast<const char*>(output_pixels.data()),
32+
static_cast<std::streamsize>(output_pixels.size() * sizeof(uint8_t)));
33+
34+
if (!output_file) {
35+
LOG(ERROR) << "Failed to write data to: " << output_filename;
36+
}
37+
38+
output_file.close();
39+
if (!output_file) {
40+
LOG(ERROR) << "Could not close the file " << output_filename;
41+
}
42+
LOG(INFO) << "File saved to: " << output_filename;
43+
}
44+
45+
CocoGen::CocoGen(Backend* backend, const std::string& input_tfrecord,
46+
const std::string& input_clip_model,
47+
const std::string& output_dir)
48+
: Dataset(backend),
49+
sample_reader_(input_tfrecord),
50+
samples_(sample_reader_.Size()),
51+
score_predictor_(input_clip_model) {
52+
if (input_format_.size() != 1 || output_format_.size() != 1) {
53+
LOG(FATAL) << "Coco_gen only supports 1 input and 1 output";
54+
return;
55+
}
56+
57+
isModelFound = score_predictor_.getCanPredict();
58+
59+
raw_output_dir_ = output_dir + "/cocogen_outputs";
60+
std::error_code ec;
61+
std::filesystem::create_directories(raw_output_dir_, ec);
62+
if (ec) {
63+
LOG(ERROR) << "Error: Could not create directory " << raw_output_dir_
64+
<< ": " << ec.message();
65+
return;
66+
}
67+
}
68+
69+
void CocoGen::LoadSamplesToRam(const std::vector<QuerySampleIndex>& samples) {
70+
for (QuerySampleIndex sample_idx : samples) {
71+
tensorflow::tstring record = sample_reader_.ReadRecord(sample_idx);
72+
samples_.at(sample_idx) =
73+
std::move(std::make_unique<CaptionRecord>(CaptionRecord(record)));
74+
}
75+
}
76+
77+
void CocoGen::UnloadSamplesFromRam(
78+
const std::vector<QuerySampleIndex>& samples) {
79+
for (QuerySampleIndex sample_idx : samples) {
80+
samples_.at(sample_idx).release();
81+
}
82+
}
83+
84+
#define OUTPUT_SIZE 512 * 512 * 3
85+
std::vector<uint8_t> CocoGen::ProcessOutput(const int sample_idx,
86+
const std::vector<void*>& outputs) {
87+
if (!isModelFound) return std::vector<uint8_t>();
88+
void* output = outputs.at(0);
89+
std::vector<uint8_t> output_pixels(OUTPUT_SIZE);
90+
if (output_format_[0].type == DataType::Uint8) {
91+
uint8_t* temp_data = reinterpret_cast<uint8_t*>(output);
92+
std::copy(temp_data, temp_data + output_pixels.size(),
93+
output_pixels.begin());
94+
} else if (output_format_[0].type == DataType::Float32) {
95+
float* temp_data = reinterpret_cast<float*>(output);
96+
97+
// [-1.0, 1.0] -> [0, 255]
98+
for (int i = 0; i < OUTPUT_SIZE; i++) {
99+
output_pixels[i] = (uint8_t)((*(temp_data + i) + 1) / 2 * 255);
100+
}
101+
}
102+
103+
std::string raw_output_filename =
104+
raw_output_dir_ + "/output_" + std::to_string(sample_idx) + ".rgb8";
105+
dump_output_pixels(output_pixels, raw_output_filename);
106+
107+
if (!output_pixels.empty()) {
108+
sample_ids_.insert(sample_idx);
109+
CaptionRecord* record = samples_.at(sample_idx).get();
110+
LOG(INFO) << "caption: " << record->get_caption();
111+
caption_map[sample_idx] = record->get_caption();
112+
output_pixels_map[sample_idx] = output_pixels;
113+
attention_mask_map[sample_idx] = record->get_attention_mask_vector();
114+
input_ids_map[sample_idx] = record->get_input_ids_vector();
115+
return output_pixels;
116+
} else {
117+
return std::vector<uint8_t>();
118+
}
119+
}
120+
121+
bool CocoGen::HasAccuracy() { return isModelFound; }
122+
123+
float CocoGen::ComputeAccuracy() {
124+
float total_score = 0.0f;
125+
float total_samples = static_cast<float>(sample_ids_.size());
126+
for (int sample_idx : sample_ids_) {
127+
std::string caption = caption_map[sample_idx];
128+
std::vector<int32_t> input_ids = input_ids_map[sample_idx];
129+
std::vector<int32_t> attention_mask = attention_mask_map[sample_idx];
130+
std::vector<uint8_t> output_pixels = output_pixels_map[sample_idx];
131+
std::vector<float> pixel_values(OUTPUT_SIZE);
132+
for (int i = 0; i < OUTPUT_SIZE; i++) {
133+
pixel_values[i] = static_cast<float>((output_pixels[i] / 128.0) - 1.0);
134+
}
135+
float score =
136+
score_predictor_.predict(attention_mask, input_ids, pixel_values);
137+
LOG(INFO) << "sample_idx: " << sample_idx << " caption: " << caption
138+
<< " score: " << score;
139+
total_score += score;
140+
}
141+
float avg_score = total_score / total_samples;
142+
return avg_score;
143+
}
144+
145+
std::string CocoGen::ComputeAccuracyString() {
146+
float result = ComputeAccuracy();
147+
if (result < 0.0f) {
148+
return {"N/A"};
149+
}
150+
std::stringstream stream;
151+
stream << std::fixed << std::setprecision(4) << result;
152+
return stream.str();
153+
}
154+
155+
} // namespace mobile
156+
} // namespace mlperf

0 commit comments

Comments
 (0)