Skip to content

Commit c880246

Browse files
committed
Add ONNX Runtime, statistics visualization
1 parent 4e0d4ae commit c880246

File tree

5 files changed

+102
-59
lines changed

5 files changed

+102
-59
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
*.lock
2-
*.pt
2+
*.pt
3+
*.onnx

Pipfile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ name = "pypi"
77
transformers = {extras = ["torch"], version = "*"}
88
scipy = "*"
99
matplotlib = "*"
10+
seaborn = "*"
11+
pandas = "*"
12+
onnxruntime = "*"
13+
onnx = "*"
1014

1115
[dev-packages]
1216

inference.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import numpy as np
2+
# https://stackoverflow.com/questions/7370801/how-to-measure-elapsed-time-in-python
3+
from timeit import default_timer as timer
4+
5+
6+
class PythonInference:
7+
def __init__(self, model):
8+
self.model = model
9+
10+
def check_inference_time(self, tokenized_input: dict):
11+
t = timer()
12+
output = self.model(**tokenized_input)
13+
elapsed_time = timer()-t
14+
return elapsed_time
15+
16+
def check_inference_time_all(self, tokenized_inputs: list, num_experiments=1):
17+
time_measurements = []
18+
for i in range(num_experiments):
19+
time_measurements.append([self.check_inference_time(x) for x in tokenized_inputs])
20+
return np.array(time_measurements)
21+
# t = timer()
22+
# output = self.model(**tokenized_input)
23+
# elapsed_time = timer()-t
24+
# return elapsed_time
25+
26+
27+
class OnxxInference:
28+
def __init__(self, session):
29+
self.session = session
30+
31+
def check_inference_time(self, tokenized_input):
32+
t = timer()
33+
output = self.session.run(None, tokenized_input)
34+
elapsed_time = timer()-t
35+
return elapsed_time
36+
37+
def check_inference_time_all(self, tokenized_inputs: list, num_experiments=1):
38+
time_measurements = []
39+
for i in range(num_experiments):
40+
time_measurements.append(
41+
[self.check_inference_time({name: np.atleast_2d(value) for name, value in x.items()}) for x in tokenized_inputs])
42+
return np.array(time_measurements)
43+

run_sentiment_classifier.py

Lines changed: 39 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,88 +1,71 @@
1-
import numpy as np
21
import matplotlib.pyplot as plt
3-
# https://stackoverflow.com/questions/7370801/how-to-measure-elapsed-time-in-python
4-
from timeit import default_timer as timer
2+
import numpy as np
3+
import pandas as pd
4+
import seaborn as sns
55

66
import torch
77
from transformers import AutoTokenizer
88
from transformers import AutoModelForSequenceClassification
99

10-
from utils import preprocess, download_label_mapping, output_vector_to_labels
10+
from onnxruntime import ExecutionMode, InferenceSession, SessionOptions
1111

12+
from inference import PythonInference, OnxxInference
13+
from utils import preprocess, download_label_mapping, output_vector_to_labels, measurements_to_dataframe
1214

1315
def read_test_sequences(path: str):
1416
with open(path, 'r') as f:
1517
sequences = [x.rstrip() for x in f.readlines()]
1618
return sequences
1719

18-
19-
def run_model(model, tokenized_input):
20-
output = model(**tokenized_input)
21-
return output_vector_to_labels(output, download_label_mapping())
22-
23-
24-
def check_inference_time(model, tokenized_input):
25-
t = timer()
26-
scores = run_model(model, tokenized_input)
27-
elapsed_time = timer()-t
28-
return elapsed_time
29-
30-
3120
if __name__ == "__main__":
3221
tokenizer = AutoTokenizer.from_pretrained("cardiffnlp/twitter-roberta-base-sentiment", torchscript=True)
3322
clf = AutoModelForSequenceClassification.from_pretrained("cardiffnlp/twitter-roberta-base-sentiment", torchscript=True)
3423

35-
n_experiments = 5
3624
input_texts = [preprocess(x) for x in read_test_sequences("test_sequences.txt")]
37-
38-
# 1. Eager
39-
eager_measurements = np.zeros((n_experiments, len(input_texts)))
4025
tokenized_inputs = [tokenizer(x, return_tensors='pt') for x in input_texts]
26+
27+
n_experiments = 2
28+
indices = np.tile(np.arange(len(input_texts)), n_experiments)
4129

42-
for i in range(n_experiments):
43-
# outputs = [run_model(clf, x) for x in tokenized_inputs]
44-
eager_measurements[i] = [check_inference_time(clf, x) for x in tokenized_inputs]
45-
# for inp, out in zip(input_texts, outputs):
46-
# print(inp, '\n', out, '\n')
47-
# print(output_times)
30+
31+
# 1. Eager
32+
eager_model = PythonInference(clf)
33+
eager_measurements = eager_model.check_inference_time_all(tokenized_inputs, n_experiments)
34+
df_eager = measurements_to_dataframe(eager_measurements.flatten(), indices)
35+
df_eager['Mode'] = 'Eager'
4836

4937

5038
# 2. TorchScript (JIT)
51-
script_measurements = np.zeros((n_experiments, len(input_texts)))
52-
tokenized_inputs = [tokenizer(x, return_tensors='pt') for x in input_texts]
53-
traced_model = torch.jit.trace(clf, (tokenized_inputs[0]['input_ids'], tokenized_inputs[0]['attention_mask']))
54-
# torch.jit.save(traced_model, "traced_twitter_roberta_base_sentiment.pt")
55-
# loaded_model = torch.jit.load("traced_twitter_roberta_base_sentiment.pt")
56-
57-
for i in range(n_experiments):
58-
# outputs = [run_model(traced_model, x) for x in tokenized_inputs]
59-
script_measurements[i] = [check_inference_time(traced_model, x) for x in tokenized_inputs]
60-
# for inp, out in zip(input_texts, outputs):
61-
# print(inp, '\n', out, '\n')
62-
# print(output_times)
39+
traced_model = PythonInference(model=torch.jit.trace(clf, (tokenized_inputs[0]['input_ids'], tokenized_inputs[0]['attention_mask'])))
40+
script_measurements = traced_model.check_inference_time_all(tokenized_inputs, n_experiments)
41+
df_script = measurements_to_dataframe(script_measurements.flatten(), indices)
42+
df_script['Mode'] = 'Script'
6343

64-
print(eager_measurements)
65-
print(script_measurements)
66-
67-
# Box Plot
6844

69-
eager_avgs = np.mean(eager_measurements, axis=0)
70-
script_avgs = np.mean(script_measurements, axis=0)
71-
print(eager_avgs)
72-
print(script_avgs)
73-
74-
# Scatter Plot
45+
# 3. ONNX Runtime
46+
model = OnxxInference(session=InferenceSession("onnx_model/twitter-roberta-base-sentiment-optimized-quantized.onnx"))
47+
onnx_measurements = model.check_inference_time_all(tokenized_inputs, n_experiments)
48+
df_onnx = measurements_to_dataframe(onnx_measurements.flatten(), indices)
49+
df_onnx['Mode'] = 'ONNX'
7550

76-
indices = np.tile(np.arange(len(input_texts)), n_experiments)
77-
eager_measurements = eager_measurements.flatten()
78-
script_measurements = script_measurements.flatten()
79-
print(indices)
80-
print(eager_measurements)
8151

52+
# Statistics
8253
plt.style.use('seaborn')
83-
plt.scatter(indices, eager_measurements, label='Eager mode')
84-
plt.scatter(indices, script_measurements, label='Script mode')
54+
plt.figure()
55+
plt.scatter(x=df_eager['SequenceId'], y=df_eager['TimeInSeconds'], label='Eager mode')
56+
plt.scatter(x=df_script['SequenceId'], y=df_script['TimeInSeconds'], label='Script mode')
57+
plt.scatter(x=df_onnx['SequenceId'], y=df_onnx['TimeInSeconds'], label='ONNX mode')
8558
plt.xlabel('Sequence ID')
8659
plt.ylabel('Inference time [s]')
8760
plt.legend()
8861
plt.show()
62+
63+
64+
plt.figure()
65+
df_all = pd.concat([df_eager, df_script, df_onnx])
66+
df_all.groupby('Mode').mean().TimeInSeconds.plot(kind='bar')
67+
plt.title('Avg. inference time in seconds')
68+
plt.ylabel('Inference time [s]')
69+
plt.show()
70+
71+
# Box plots

utils.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import csv
22
import numpy as np
3+
import pandas as pd
34
import urllib.request
45
from scipy.special import softmax
56

@@ -22,7 +23,10 @@ def download_label_mapping():
2223
return labels
2324

2425
def output_vector_to_labels(output, labels_map):
25-
scores = output[0][0].detach().numpy()
26+
if isinstance(output[0][0], np.ndarray):
27+
scores = output[0][0]
28+
else:
29+
scores = output[0][0].detach().numpy()
2630
scores = softmax(scores)
2731

2832
scores_map = {}
@@ -33,4 +37,12 @@ def output_vector_to_labels(output, labels_map):
3337
s = scores[ranking[i]]
3438
scores_map[l] = np.round(float(s), 4)
3539
# print(f"{i+1}) {l} {np.round(float(s), 4)}")
36-
return scores_map
40+
return scores_map
41+
42+
def measurements_to_dataframe(measurements, indices):
43+
data = []
44+
for seq_id, time in zip(indices, measurements):
45+
data.append([seq_id, time, 'Unknown'])
46+
df = pd.DataFrame(data, columns=['SequenceId', 'TimeInSeconds', 'Mode'])
47+
print(df)
48+
return df

0 commit comments

Comments
 (0)