Skip to content

Commit 6bb1c25

Browse files
xadupresdpythonTomWildenhain-Microsoft
authored
Add script to benchmark bert and mobilenet (#1594)
* Add script for bert and mobilenet Signed-off-by: xavier dupré <[email protected]> * add script to convert tfhub models Signed-off-by: xavier dupré <[email protected]> * add more scripts Signed-off-by: xavier dupré <[email protected]> * add all scripts Signed-off-by: xavier dupré <[email protected]> Co-authored-by: xavier dupré <[email protected]> Co-authored-by: TomWildenhain-Microsoft <[email protected]>
1 parent aacfa26 commit 6bb1c25

19 files changed

+513
-19
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,7 @@ __pycache__
1313
.eggs
1414
*.egg-info
1515
run.sh
16+
tests/tfhub/*/*.onnx
17+
tests/tfhub/*/*.tar.gz
18+
tests/tfhub/*/*.tflite
19+
tests/tfhub/*/**

tests/tfhub/_tools.py

Lines changed: 107 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,21 +11,60 @@
1111
import zipfile
1212
import subprocess
1313
import datetime
14+
from collections import OrderedDict
1415
import numpy
1516
from tqdm import tqdm
1617
import onnxruntime
1718

1819

19-
def generate_random_images(shape=(1, 100, 100, 3), n=10, dtype=numpy.float32):
20+
def generate_random_images(shape=(1, 100, 100, 3), n=10, dtype=numpy.float32, scale=255):
2021
imgs = []
2122
for i in range(n):
2223
sh = shape
23-
img = numpy.clip(numpy.abs(numpy.random.randn(*sh)), 0, 1) * 255
24+
img = numpy.clip(numpy.abs(numpy.random.randn(*sh)), 0, 1) * scale
2425
img = img.astype(dtype)
2526
imgs.append(img)
2627
return imgs
2728

2829

30+
def generate_text_inputs():
31+
"""
32+
preprocessor = hub.load("http://tfhub.dev/tensorflow/albert_en_preprocess/3")
33+
encoder = hub.load("https://tfhub.dev/tensorflow/albert_en_xlarge/3")
34+
sentences = tf.constant(["Hi I'm some text"])
35+
embedded_inputs = {k: v.numpy() for k, v in preprocessor(sentences).items()}
36+
"""
37+
one = OrderedDict([
38+
('input_word_ids', numpy.array([[
39+
2, 4148, 31, 22, 79, 109, 1854, 3, 0, 0, 0,
40+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
41+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
42+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
43+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
44+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
45+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
46+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
47+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
48+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
49+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
50+
0, 0, 0, 0, 0, 0,0]]).reshape((1, -1))),
51+
('input_type_ids', numpy.array([[
52+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
53+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
54+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
55+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
56+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
57+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]).reshape((1, -1))),
58+
('input_mask', numpy.array([[
59+
1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
60+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
61+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
62+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
63+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
64+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]).reshape((1, -1)))])
65+
return [one for i in range(10)]
66+
67+
2968
def measure_time(fct, imgs, n=50, timeout=15):
3069
"""
3170
Runs *n* times the same function taking one parameter
@@ -89,16 +128,22 @@ def download_tflite(url, dest, verbose=True):
89128
return fpath
90129

91130

92-
def convert_model(model_name, output_path, opset=13, verbose=True):
131+
def convert_model(model_name, output_path, opset=13, tag=None, verbose=True):
93132
"""
94133
Converts the downloaded model into ONNX.
95134
"""
135+
ext = os.path.splitext(output_path)[-1]
136+
large_model = ext == ".zip"
96137
if not os.path.exists(output_path):
97138
begin = datetime.datetime.now()
98139
cmdl = ['-m', 'tf2onnx.convert', '--saved-model',
99140
'"%s"' % os.path.abspath(model_name).replace("\\", "/"),
100141
'--output', '"%s"' % os.path.abspath(output_path).replace("\\", "/"),
101142
'--opset', "%d" % opset]
143+
if tag is not None:
144+
cmdl.append('--tag="%s"' % tag)
145+
if large_model:
146+
cmdl.append('--large_model')
102147
if verbose:
103148
print("cmd: python %s" % " ".join(cmdl))
104149
pproc = subprocess.Popen(
@@ -151,7 +196,7 @@ def check_discrepencies(out1, out2, threshold=1e-3):
151196

152197

153198
def benchmark(url, dest, onnx_name, opset, imgs, verbose=True, threshold=1e-3,
154-
signature=None):
199+
signature=None, tag=None, output_name=None, ort_name=None):
155200
"""
156201
Runs a simple benchmark.
157202
Goes through every steps (download, convert).
@@ -164,10 +209,21 @@ def benchmark(url, dest, onnx_name, opset, imgs, verbose=True, threshold=1e-3,
164209
# Converts the model.
165210
if verbose:
166211
print("Convert model in %r." % dest)
167-
convert_model(tname, onnx_name, opset)
212+
convert_model(tname, onnx_name, opset, tag=tag)
168213
if verbose:
169214
print("Created %r." % onnx_name)
170215

216+
# unzip large_model
217+
ext = os.path.splitext(onnx_name)[-1]
218+
if ext == ".zip":
219+
onnx_name_unzipped = os.path.join(dest, "large_model", "__MODEL_PROTO.onnx")
220+
if not os.path.exists(onnx_name_unzipped):
221+
if verbose:
222+
print("Unzip model in %r." % os.path.join(dest, "large_model"))
223+
with zipfile.ZipFile(onnx_name, 'r') as z:
224+
z.extractall(os.path.join(dest, "large_model"))
225+
onnx_name = onnx_name_unzipped
226+
171227
# Benchmarks both models.
172228
ort = onnxruntime.InferenceSession(onnx_name)
173229

@@ -180,19 +236,37 @@ def benchmark(url, dest, onnx_name, opset, imgs, verbose=True, threshold=1e-3,
180236
print(" {}: {}, {}".format(a.name, a.type, a.shape))
181237

182238
# onnxruntime
183-
input_name = ort.get_inputs()[0].name
184-
fct_ort = lambda img: ort.run(None, {input_name: img})[0]
239+
if output_name is None or ort_name is None:
240+
index = 0
241+
else:
242+
output_names = [o.name for o in ort.get_outputs()]
243+
if output_name in output_names:
244+
index = output_names.index(output_name)
245+
elif ort_name in output_names:
246+
index = output_names.index(ort_name)
247+
else:
248+
index = 0
249+
if isinstance(imgs[0], dict):
250+
fct_ort = lambda img: ort.run(None, img)[index]
251+
else:
252+
input_name = ort.get_inputs()[0].name
253+
fct_ort = lambda img: ort.run(None, {input_name: img})[index]
185254
results_ort, duration_ort = measure_time(fct_ort, imgs)
186255
if verbose:
187256
print("ORT", len(imgs), duration_ort)
188257

189258
# tensorflow
190259
import tensorflow_hub as hub
191260
from tensorflow import convert_to_tensor
261+
if isinstance(imgs[0], OrderedDict):
262+
imgs_tf = [
263+
OrderedDict((k, convert_to_tensor(v)) for k, v in img.items())
264+
for img in imgs]
265+
else:
266+
imgs_tf = [convert_to_tensor(img) for img in imgs]
192267
model = hub.load(url.split("?")[0])
193268
if signature is not None:
194-
model = model.signatures['serving_default']
195-
imgs_tf = [convert_to_tensor(img) for img in imgs]
269+
model = model.signatures[signature]
196270
results_tf, duration_tf = measure_time(model, imgs_tf)
197271

198272
if verbose:
@@ -204,13 +278,27 @@ def benchmark(url, dest, onnx_name, opset, imgs, verbose=True, threshold=1e-3,
204278
# checks discrepencies
205279
res = model(imgs_tf[0])
206280
if isinstance(res, dict):
207-
if len(res) != 1:
208-
raise NotImplementedError("TF output contains more than one output: %r." % res)
209-
output_name = ort.get_outputs()[0].name
281+
if output_name is None:
282+
if len(res) != 1:
283+
raise NotImplementedError(
284+
"TF output contains more than one output=%r and output names=%r." % (
285+
list(res), [o.name for o in ort.get_outputs()]))
286+
else:
287+
output_name = ort.get_outputs()[0].name
210288
if output_name not in res:
211289
raise AssertionError("Unable to find output %r in %r." % (output_name, list(sorted(res))))
212290
res = res[output_name]
213-
check_discrepencies(fct_ort(imgs[0]), res.numpy(), threshold)
291+
try:
292+
check_discrepencies(fct_ort(imgs[0]), res.numpy(), threshold)
293+
except AttributeError as e:
294+
raise AssertionError(
295+
"Unable to check discrepencies for res=%r." % res) from e
296+
except AssertionError as e:
297+
output_names = [o.name for o in ort.get_outputs()]
298+
res = ort.run(None, imgs[0])
299+
for i, r in enumerate(res):
300+
print("ORT %d: %s: %r: %r" % (i, output_names[i], r.dtype, r.shape))
301+
raise e
214302
return duration_ort, duration_tf
215303

216304

@@ -252,10 +340,15 @@ def benchmark_tflite(url, dest, onnx_name, opset, imgs, verbose=True, threshold=
252340
# tensorflow
253341
import tensorflow_hub as hub
254342
from tensorflow import convert_to_tensor
343+
if isinstance(imgs[0], OrderedDict):
344+
imgs_tf = [
345+
OrderedDict((k, convert_to_tensor(v)) for k, v in img.items())
346+
for img in imgs]
347+
else:
348+
imgs_tf = [convert_to_tensor(img) for img in imgs]
255349
model = hub.load(url.split("?")[0])
256350
if signature is not None:
257351
model = model.signatures['serving_default']
258-
imgs_tf = [convert_to_tensor(img) for img in imgs]
259352
results_tf, duration_tf = measure_time(model, imgs_tf)
260353

261354
if verbose:

tests/tfhub/tfhub_albert_en_xlarge.py

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,27 @@
11
# SPDX-License-Identifier: Apache-2.0
22
import os
33
import numpy
4-
from _tools import generate_random_images, benchmark
4+
import numpy.random as rnd
5+
from collections import OrderedDict
6+
from _tools import generate_text_inputs, benchmark
57

68

79
def main(opset=13):
810
url = "https://tfhub.dev/tensorflow/albert_en_xlarge/3?tf-hub-format=compressed"
911
dest = "tf-albert-en-xlarge"
1012
name = "albert-en-xlarge"
11-
onnx_name = os.path.join(dest, "%s-%d.onnx" % (name, opset))
13+
onnx_name = os.path.join(dest, "%s-%d.zip" % (name, opset))
1214

13-
imgs = generate_random_images(shape=(1, 256, 256, 3), dtype=numpy.int32)
15+
inputs = generate_text_inputs()
16+
benchmark(url, dest, onnx_name, opset, inputs, output_name="pooled_output")
1417

15-
benchmark(url, dest, onnx_name, opset, imgs,
16-
signature='serving_default')
18+
inputs = [OrderedDict([
19+
('input_word_ids', numpy.array([rnd.randint(0, 1000) for i in range(0, 128)], dtype=numpy.int32).reshape((1, -1))),
20+
('input_mask', numpy.array([rnd.randint(0, 1) for i in range(0, 128)], dtype=numpy.int32).reshape((1, -1))),
21+
('input_type_ids', numpy.array([i//5 for i in range(0, 128)], dtype=numpy.int32).reshape((1, -1)))
22+
]) for i in range(0, 10)]
23+
24+
benchmark(url, dest, onnx_name, opset, inputs, output_name="pooled_output")
1725

1826

1927
if __name__ == "__main__":
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# Adapted the sample code on https://tfhub.dev/tensorflow/albert_en_xlarge/3
2+
import tensorflow_text as text
3+
import tensorflow as tf
4+
import tensorflow_hub as hub
5+
6+
# Using hub.load instead of KerasLayer lets us easily intercept the results of the
7+
# preprocessor before passing it to the encoder
8+
preprocessor = hub.load("http://tfhub.dev/tensorflow/albert_en_preprocess/3")
9+
encoder = hub.load("https://tfhub.dev/tensorflow/albert_en_xlarge/3")
10+
sentences = tf.constant(["Hi I'm some text"])
11+
12+
embedded_inputs = {k: v.numpy() for k, v in preprocessor(sentences).items()}
13+
print("Inputs")
14+
print(embedded_inputs)
15+
expected_output = encoder(embedded_inputs)["pooled_output"].numpy()
16+
17+
# Now make an actual keras layer for the part we want to convert
18+
encoder = hub.KerasLayer(
19+
"https://tfhub.dev/tensorflow/albert_en_xlarge/3",
20+
trainable=True)
21+
22+
# To convert it to a model, we need the input shapes/types. These can be
23+
# determined from the types/shapes/names of embedded_inputs. Remove the batch dim from the shapes.
24+
encoder_inputs = {
25+
"input_word_ids": tf.keras.Input(shape=[None], dtype="int32", name="input_word_ids"),
26+
"input_mask": tf.keras.Input(shape=[None], dtype="int32", name="input_mask"),
27+
"input_type_ids": tf.keras.Input(shape=[None], dtype="int32", name="input_type_ids"),
28+
}
29+
encoder_outputs = encoder(encoder_inputs)["pooled_output"]
30+
encoding_model = tf.keras.Model(encoder_inputs, encoder_outputs)
31+
32+
33+
import tf2onnx
34+
import onnxruntime as ort
35+
import zipfile
36+
import os
37+
print("Converting")
38+
39+
dest = "tf-albert-en-xlarge"
40+
if not os.path.exists(dest):
41+
os.makedirs(dest)
42+
dest_name = os.path.join(dest, "albert_en_xlarge.zip")
43+
44+
# This model is a large model.
45+
tf2onnx.convert.from_keras(encoding_model, opset=13, large_model=True, output_path=dest_name)
46+
# To run the model in ORT we need to unzip it.
47+
with zipfile.ZipFile(dest_name, 'r') as z:
48+
z.extractall(os.path.join(dest, "albert_en_xlarge"))
49+
sess = ort.InferenceSession(os.path.join(dest, "albert_en_xlarge", "__MODEL_PROTO.onnx"))
50+
ort_output = sess.run(None, embedded_inputs)
51+
print("Actual")
52+
print(ort_output[0])
53+
print("Expected")
54+
print(expected_output)
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# SPDX-License-Identifier: Apache-2.0
2+
import os
3+
from collections import OrderedDict
4+
import numpy
5+
import numpy.random as rnd
6+
from _tools import generate_random_images, benchmark
7+
8+
9+
def main(opset=13):
10+
url = "https://tfhub.dev/tensorflow/bert_en_wwm_uncased_L-24_H-1024_A-16/4?tf-hub-format=compressed"
11+
dest = "tf-bert-en-wwm-uncased-L-24-H-1024-A-16"
12+
name = "bert-en-wwm-uncased-L-24-H-1024-A-16"
13+
onnx_name = os.path.join(dest, "%s-%d.onnx" % (name, opset))
14+
15+
inputs = [OrderedDict([
16+
('input_word_ids', numpy.array([rnd.randint(0, 1000) for i in range(0, 32)], dtype=numpy.int32).reshape((1, -1))),
17+
('input_mask', numpy.array([rnd.randint(0, 1) for i in range(0, 32)], dtype=numpy.int32).reshape((1, -1))),
18+
('input_type_ids', numpy.array([i//5 for i in range(0, 32)], dtype=numpy.int32).reshape((1, -1)))
19+
]) for i in range(0, 10)]
20+
21+
benchmark(url, dest, onnx_name, opset, inputs, output_name="pooled_output")
22+
23+
24+
if __name__ == "__main__":
25+
main()
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# SPDX-License-Identifier: Apache-2.0
2+
import os
3+
import numpy
4+
from _tools import generate_random_images, benchmark
5+
6+
7+
def main(opset=13):
8+
url = "https://tfhub.dev/mediapipe/tfjs-model/blazeposedetector/1/default/1?tfjs-format=compressed"
9+
dest = "tf-blazeposedetector"
10+
name = "blazeposedetector"
11+
onnx_name = os.path.join(dest, "%s-%d.onnx" % (name, opset))
12+
13+
imgs = generate_random_images(shape=(1, 513, 513, 3), scale=1.)
14+
15+
benchmark(url, dest, onnx_name, opset, imgs)
16+
17+
18+
if __name__ == "__main__":
19+
main()

tests/tfhub/tfhub_enformer.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# SPDX-License-Identifier: Apache-2.0
2+
import os
3+
import numpy
4+
from _tools import generate_random_images, benchmark
5+
6+
7+
def main(opset=13):
8+
url = "https://tfhub.dev/deepmind/enformer/1?tf-hub-format=compressed"
9+
dest = "tf-enformer"
10+
name = "enformer"
11+
onnx_name = os.path.join(dest, "%s-%d.zip" % (name, opset))
12+
13+
imgs = generate_random_images(shape=(1, 224, 224, 3))
14+
15+
benchmark(url, dest, onnx_name, opset, imgs)
16+
17+
18+
if __name__ == "__main__":
19+
main()

tests/tfhub/tfhub_humpback_whale.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# SPDX-License-Identifier: Apache-2.0
2+
import os
3+
import numpy
4+
from _tools import generate_random_images, benchmark
5+
6+
7+
def main(opset=13):
8+
url = "https://tfhub.dev/google/humpback_whale/1?tf-hub-format=compressed"
9+
dest = "tf-humpback-whale"
10+
name = "humpback-whale"
11+
onnx_name = os.path.join(dest, "%s-%d.onnx" % (name, opset))
12+
13+
imgs = generate_random_images(shape=(1, 331, 331, 3))
14+
15+
benchmark(url, dest, onnx_name, opset, imgs)
16+
17+
18+
if __name__ == "__main__":
19+
main()

0 commit comments

Comments
 (0)