Skip to content

Commit b4bdc20

Browse files
committed
[EIEX-947] Add profiling tests for MLPerfTiny models
1 parent 539bda2 commit b4bdc20

2 files changed

Lines changed: 207 additions & 8 deletions

File tree

backends/nxp/backend/neutron_map.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -345,16 +345,16 @@ def get_tflite_to_neutron_map(self) -> dict[int, tuple[int, ...]]:
345345
tflite_to_neutron_dict = {}
346346
for tf_idx, tf_node in enumerate(self.tflite_nodes):
347347
subgraph_idxs = []
348+
location_shift = 0
348349
for subgraph in self.neutron_subgraphs:
349-
if (
350-
subgraph.num in self.neutron_graphs
351-
or subgraph.location in subgraph_idxs
352-
):
350+
if subgraph.num in self.neutron_graphs:
353351
continue
354352
for neutron_node in subgraph.nodes:
355353
if self._nodes_match_by_io(tf_node, neutron_node):
356-
subgraph_idxs.append(subgraph.location)
354+
for kernel in range(subgraph.kernels):
355+
subgraph_idxs.append(subgraph.location + location_shift + kernel)
357356
break
357+
location_shift += max(subgraph.kernels - 1, 0)
358358
# Filter subgraph_idxs to avoid mapping multiple parallel single-input nodes that consume the
359359
# same input tensor into the same TFLite node.
360360
subgraph_idxs = self._filter_single_input_nodes(tf_node.name, subgraph_idxs)

backends/nxp/tests/generic_tests/test_profiling.py

Lines changed: 202 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@
1919

2020
from executorch.examples.nxp.experimental.cifar_net.cifar_net import CifarNetModel
2121

22+
from executorch.examples.models.mlperf_tiny.resnet8 import ResNet8
23+
from executorch.examples.models.mlperf_tiny import DSCNNKWS
24+
from executorch.examples.models.mlperf_tiny import MobileNetV1025
25+
from executorch.examples.models.mlperf_tiny import DeepAutoEncoder
2226

2327
@pytest.fixture(autouse=True)
2428
def reseed_model_per_test_run():
@@ -39,7 +43,7 @@ def extract_map_from_logs(caplog):
3943
return None
4044

4145

42-
class ParallelPoolModel(torch.nn.Module):
46+
class SimpleParallelPoolModel(torch.nn.Module):
4347
def __init__(self, channels: int):
4448
super().__init__()
4549
self.conv_in = torch.nn.Conv2d(channels, channels, kernel_size=3, padding=1)
@@ -53,6 +57,27 @@ def forward(self, x):
5357
x = self.conv_out(x)
5458
return x
5559

60+
class ParallelPoolModel(torch.nn.Module):
61+
def __init__(self, ch=16):
62+
super().__init__()
63+
self.conv1 = torch.nn.Conv2d(ch, ch, 3, padding=1)
64+
self.bn1 = torch.nn.BatchNorm2d(ch)
65+
self.conv2 = torch.nn.Conv2d(ch, ch, 3, padding=1)
66+
self.maxpool = torch.nn.MaxPool2d(2)
67+
self.avgpool = torch.nn.AvgPool2d(2)
68+
self.conv_out = torch.nn.Conv2d(2 * ch, ch, 1)
69+
70+
def forward(self, x):
71+
residual = x
72+
x = self.conv1(x)
73+
x = self.bn1(x)
74+
x = torch.relu(x)
75+
x = self.conv2(x)
76+
x = x + residual # residual connection
77+
x = torch.cat((self.maxpool(x), self.avgpool(x)), dim=1) # parallel merge
78+
x = self.conv_out(x)
79+
return torch.relu(x)
80+
5681

5782
class TestProfiling:
5883
@pytest.mark.xfail(reason="SoftMax support PR is not merged so far.", strict=True)
@@ -78,10 +103,10 @@ def test__softmax(self, caplog, request):
78103
3: (), # Neutron Dump
79104
}
80105

81-
def test__parallel_pool(self, caplog, request):
106+
def test__simple_parallel_pool(self, caplog, request):
82107
caplog.set_level(logging.INFO)
83108
input_shape = (1, 3, 32, 32)
84-
model = ParallelPoolModel(input_shape[1])
109+
model = SimpleParallelPoolModel(input_shape[1])
85110
lower_run_compare(
86111
model,
87112
input_shape,
@@ -156,3 +181,177 @@ def test__avg_pool(self, caplog, request):
156181
2: (2,), # Slice
157182
3: (), # Neutron Dump
158183
}
184+
185+
186+
def test__parallel_pool(self, caplog, request):
187+
caplog.set_level(logging.INFO)
188+
input_shape = (1, 16, 32, 32)
189+
model = ParallelPoolModel(input_shape[1])
190+
lower_run_compare(
191+
model,
192+
input_shape,
193+
dlg_model_verifier=BaseGraphVerifier(1, []),
194+
request=request,
195+
output_comparator=NumericalStatsOutputComparator(),
196+
use_neutron_for_format_conversion=False,
197+
use_profiling=True,
198+
)
199+
neutron_map = extract_map_from_logs(caplog)
200+
assert neutron_map == {
201+
0: (8, 9), # Conv2DStandardV1 (Pad + Conv2d)
202+
1: (10,), # Conv2DStandardV1
203+
2: (11,), # Add
204+
3: (), # Conv2DDepthwiseV2 (AvgPool)
205+
4: (12,), # MaxPool
206+
5: (14,), # StridedSliceConcat
207+
6: (15, 16), # Conv2DPointwise (Conv2D + Relu)
208+
7: () # Neutron Dump
209+
}
210+
211+
212+
def test__resnet8(self, caplog, request):
213+
# Three-stage residual network for the MLPerf Tiny image-classification.
214+
caplog.set_level(logging.INFO)
215+
model = ResNet8()
216+
input_shape = (1, 3, 32, 32)
217+
218+
lower_run_compare(model,
219+
input_shape,
220+
dlg_model_verifier=BaseGraphVerifier(1, []),
221+
request=request,
222+
output_comparator=NumericalStatsOutputComparator(),
223+
use_neutron_for_format_conversion=False,
224+
use_profiling=True,
225+
)
226+
neutron_map = extract_map_from_logs(caplog)
227+
assert neutron_map == {
228+
0: (14, 15), # Conv2DStandardV2 (Pad + Conv)
229+
1: (17, 18), # Conv2DStandardV1 (Pad + Conv)
230+
2: (20,), # Conv2DStandardV1
231+
3: (21,), # Add
232+
4: (22,), # GlobalBiasScale (Relu)
233+
5: (28,), # Conv2DStandardV1
234+
6: (24, 25), #Conv2DStandardV1 (Pad + Conv)
235+
7: (27,), # Conv2DStandardV1
236+
8: (29,), # Add
237+
9: (30,), # GlobalBiasScale (Relu)
238+
10: (36,), # Conv2DStandardV1
239+
11: (32, 33), # Conv2DStandardV1 (Pad + Conv)
240+
12: (35,), # Conv2DStandardV1
241+
13: (37,), # Add
242+
14: (38,), # GlobalBiasScale (Relu)
243+
15: (), # GlobalAvgPool (Mean)
244+
16: (41,), # FullyConnected
245+
17: () # Neutron Dump
246+
}
247+
248+
249+
def test__ds_cnn(self, caplog, request):
250+
# Depthwise Separable CNN used for keyword spotting in MLCommons Tiny.
251+
caplog.set_level(logging.INFO)
252+
model = DSCNNKWS()
253+
input_shape = (1, 1, 49, 10)
254+
255+
lower_run_compare(model,
256+
input_shape,
257+
dlg_model_verifier=BaseGraphVerifier(1, []),
258+
request=request,
259+
output_comparator=NumericalStatsOutputComparator(),
260+
use_neutron_for_format_conversion=False,
261+
use_profiling=True,
262+
)
263+
neutron_map = extract_map_from_logs(caplog)
264+
assert neutron_map == {
265+
0: (14, 15), # Pad (Conv + Relu)
266+
1: (14, 15), # Conv2DStandardV2 (Conv + Relu)
267+
2: (18, 19), # Conv2DDepthwiseV1 (DepthwiseConv + Relu)
268+
3: (21, 22), # Conv2DPointwise (Conv + Relu)
269+
4: (24, 25), # Conv2DDepthwiseV1 (DepthwiseConv + Relu)
270+
5: (27, 28), # Conv2DDepthwiseV1 (Conv + Relu)
271+
6: (30, 31), # Conv2DDepthwiseV1 (DepthwiseConv + Relu)
272+
7: (33, 34), # Conv2DPointwise (Conv + Relu)
273+
8: (36, 37), # Conv2DDepthwiseV1 (DepthwiseConv + Relu)
274+
9: (39, 40), # Conv2DPointwise (Conv + Relu)
275+
10: (42,), # Conv2DDepthwiseDense (AvgPool)
276+
11: (44,), # FullyConnected
277+
12: () # Neutron Dump
278+
}
279+
280+
281+
def test__mobilenet_v1_025(self, caplog, request):
282+
# MobileNetV1 with width multiplier 0.25 for the Visual Wake Words.
283+
caplog.set_level(logging.INFO)
284+
model = MobileNetV1025()
285+
input_shape = (1, 3, 96, 96)
286+
287+
lower_run_compare(model,
288+
input_shape,
289+
dlg_model_verifier=BaseGraphVerifier(1, []),
290+
request=request,
291+
output_comparator=NumericalStatsOutputComparator(),
292+
use_neutron_for_format_conversion=False,
293+
use_profiling=True,
294+
)
295+
neutron_map = extract_map_from_logs(caplog)
296+
assert neutron_map == {
297+
0: (32, 33), # Conv2DStandardV2 (Conv + Relu)
298+
1: (35, 36), # Conv2DDepthwiseV1 (DepthwiseConv + Relu)
299+
2: (38, 39), # Conv2DPointwise (Conv + Relu)
300+
3: (41, 42), # Conv2DDepthwiseV1 (DepthwiseConv + Relu)
301+
4: (44, 45), # Conv2DPointwise (Conv + Relu)
302+
5: (47, 48), # Conv2DDepthwiseV1 (DepthwiseConv + Relu)
303+
6: (50, 51), # Conv2DPointwise (Conv + Relu)
304+
7: (53, 54), # Conv2DDepthwiseV1 (DepthwiseConv + Relu)
305+
8: (56, 57), # Conv2DPointwise (Conv + Relu)
306+
9: (59, 60), # Conv2DDepthwiseV1 (DepthwiseConv + Relu)
307+
10: (62, 63), # Conv2DPointwise (Conv + Relu)
308+
11: (65, 66), # Conv2DDepthwiseV1 (DepthwiseConv + Relu)
309+
12: (68, 69), # Conv2DPointwise (Conv + Relu)
310+
13: (71, 72), # Conv2DDepthwiseV1 (DepthwiseConv + Relu)
311+
14: (74, 75), # Conv2DPointwise (Conv + Relu)
312+
15: (77, 78), # Conv2DDepthwiseV1 (DepthwiseConv + Relu)
313+
16: (80, 81), # Conv2DPointwise (Conv + Relu)
314+
17: (83, 84), # Conv2DDepthwiseV1 (DepthwiseConv + Relu)
315+
18: (86, 87), # Conv2DPointwise (Conv + Relu)
316+
19: (89, 90), # Conv2DDepthwiseV1 (DepthwiseConv + Relu)
317+
20: (92, 93), # Conv2DPointwise (Conv + Relu)
318+
21: (95, 96), # Conv2DDepthwiseV1 (DepthwiseConv + Relu)
319+
22: (98, 99), # Conv2DPointwise (Conv + Relu)
320+
23: (101, 102), # Conv2DDepthwiseDense (DepthwiseConv + Relu)
321+
24: (104, 105), # Conv2DPointwise (Conv + Relu)
322+
25: (107, 108), # Conv2DDepthwiseDense (DepthwiseConv + Relu)
323+
26: (110, 111), # Conv2DPointwise (Conv + Relu)
324+
27: (), # Mean (GlobalAvgPool)
325+
28: (114,), # FullyConnected
326+
29: () # Neutron Dump
327+
}
328+
329+
330+
def test__deep_autoencoder(self, caplog, request):
331+
# MLPerf Tiny anomaly detection deep autoencoder.
332+
caplog.set_level(logging.INFO)
333+
model = DeepAutoEncoder()
334+
input_shape = (1, 640)
335+
336+
lower_run_compare(model,
337+
input_shape,
338+
dlg_model_verifier=BaseGraphVerifier(1, []),
339+
request=request,
340+
output_comparator=NumericalStatsOutputComparator(),
341+
use_neutron_for_format_conversion=False,
342+
use_profiling=True,
343+
)
344+
neutron_map = extract_map_from_logs(caplog)
345+
assert neutron_map == {
346+
0: (22, 23), # FullyConnected (FullyConnected + Relu)
347+
1: (24, 25), # FullyConnected (FullyConnected + Relu)
348+
2: (26, 27), # FullyConnected (FullyConnected + Relu)
349+
3: (28, 29), # FullyConnected (FullyConnected + Relu)
350+
4: (30, 31), # FullyConnected (FullyConnected + Relu)
351+
5: (32, 33), # FullyConnected (FullyConnected + Relu)
352+
6: (34, 35), # FullyConnected (FullyConnected + Relu)
353+
7: (36, 37), # FullyConnected (FullyConnected + Relu)
354+
8: (38, 39), # FullyConnected (FullyConnected + Relu)
355+
9: (40,), # FullyConnected
356+
10: () # Neutron Dump
357+
}

0 commit comments

Comments
 (0)