Skip to content

Commit 71ff610

Browse files
committed
Merge branch 'main' into try-r5-instances
2 parents 6cc16d9 + 5b4d9bb commit 71ff610

File tree

78 files changed

+827209
-938
lines changed

Some content is hidden

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

78 files changed

+827209
-938
lines changed

backends/arm/TARGETS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ python_library(
99
typing = True,
1010
deps = [
1111
":arm_backend",
12+
"//executorch/backends/arm/operator_support:operator_support",
1213
"//executorch/backends/arm/_passes:passes",
1314
"//executorch/exir:lib",
1415
],
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
load("@fbcode_macros//build_defs:python_library.bzl", "python_library")
2+
3+
python_library(
4+
name = "operator_support",
5+
srcs = glob(["*.py"]),
6+
typing = True,
7+
deps = [
8+
"//executorch/backends/xnnpack/_passes:xnnpack_passes",
9+
"//executorch/exir:lib",
10+
"//executorch/backends/arm:tosa_specification"
11+
],
12+
)

backends/arm/operator_support/tosa_supported_operators.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
# pyre-unsafe
77

88
import operator
9+
from typing import Type
910

1011
import torch.fx as fx
1112
from executorch.backends.arm.tosa_specification import TosaSpecification
@@ -31,7 +32,9 @@ def is_node_supported(self, node: fx.Node, tosa_spec: TosaSpecification) -> bool
3132

3233

3334
# container for all SupportedTosaOperatorCheck classes
34-
_tosa_spec_dicts: dict[TosaSpecification, dict[str, SupportedTOSAOperatorCheck]] = {
35+
_tosa_spec_dicts: dict[
36+
TosaSpecification, dict[str, Type[SupportedTOSAOperatorCheck]]
37+
] = {
3538
TosaSpecification.create_from_string("TOSA-0.80.0+BI"): {},
3639
TosaSpecification.create_from_string("TOSA-0.80.0+MI"): {},
3740
}

backends/arm/test/misc/test_model_evaluator.py

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,14 @@
44
# This source code is licensed under the BSD-style license found in the
55
# LICENSE file in the root directory of this source tree.
66

7-
import random
87
import tempfile
98
import unittest
109

1110
import torch
1211
from executorch.backends.arm.util.arm_model_evaluator import GenericModelEvaluator
1312

14-
random.seed(0)
15-
1613
# Create an input that is hard to compress
17-
COMPRESSION_RATIO_TEST = bytearray(random.getrandbits(8) for _ in range(1000000))
14+
COMPRESSION_RATIO_TEST = torch.rand([1024, 1024])
1815

1916

2017
def mocked_model_1(input: torch.Tensor) -> torch.Tensor:
@@ -47,20 +44,16 @@ def test_get_model_error(self):
4744

4845
def test_get_compression_ratio(self):
4946
with tempfile.NamedTemporaryFile(delete=True) as temp_bin:
50-
temp_bin.write(COMPRESSION_RATIO_TEST)
51-
52-
# As the size of the file is quite small we need to call flush()
53-
temp_bin.flush()
54-
temp_bin_name = temp_bin.name
47+
torch.save(COMPRESSION_RATIO_TEST, temp_bin)
5548

5649
example_input = torch.tensor([[1.0, 2.0, 3.0, 4.0]])
5750
evaluator = GenericModelEvaluator(
5851
"dummy_model",
5952
mocked_model_1,
6053
mocked_model_2,
6154
example_input,
62-
temp_bin_name,
55+
temp_bin.name,
6356
)
6457

6558
ratio = evaluator.get_compression_ratio()
66-
self.assertAlmostEqual(ratio, 1.0, places=2)
59+
self.assertAlmostEqual(ratio, 1.1, places=1)

backends/arm/util/arm_model_evaluator.py

Lines changed: 106 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,25 @@
44
# This source code is licensed under the BSD-style license found in the
55
# LICENSE file in the root directory of this source tree.
66

7+
import logging
78
import os
9+
import random
810
import tempfile
911
import zipfile
12+
1013
from collections import defaultdict
11-
from typing import Optional, Tuple
14+
from pathlib import Path
15+
from typing import Any, Optional, Tuple
1216

1317
import torch
18+
from torch.nn.modules import Module
19+
from torch.utils.data import DataLoader
20+
from torchvision import datasets, transforms
21+
22+
23+
# Logger for outputting progress for longer running evaluation
24+
logger = logging.getLogger(__name__)
25+
logger.setLevel(logging.INFO)
1426

1527

1628
def flatten_args(args) -> tuple | list:
@@ -28,6 +40,8 @@ def flatten_args(args) -> tuple | list:
2840

2941

3042
class GenericModelEvaluator:
43+
REQUIRES_CONFIG = False
44+
3145
def __init__(
3246
self,
3347
model_name: str,
@@ -90,7 +104,7 @@ def get_compression_ratio(self) -> float:
90104

91105
return compression_ratio
92106

93-
def evaluate(self) -> dict[any]:
107+
def evaluate(self) -> dict[Any]:
94108
model_error_dict = self.get_model_error()
95109

96110
output_metrics = {"name": self.model_name, "metrics": dict(model_error_dict)}
@@ -103,3 +117,93 @@ def evaluate(self) -> dict[any]:
103117
] = self.get_compression_ratio()
104118

105119
return output_metrics
120+
121+
122+
class MobileNetV2Evaluator(GenericModelEvaluator):
123+
REQUIRES_CONFIG = True
124+
125+
def __init__(
126+
self,
127+
model_name: str,
128+
fp32_model: Module,
129+
int8_model: Module,
130+
example_input: Tuple[torch.Tensor],
131+
tosa_output_path: str | None,
132+
batch_size: int,
133+
validation_dataset_path: str,
134+
) -> None:
135+
super().__init__(
136+
model_name, fp32_model, int8_model, example_input, tosa_output_path
137+
)
138+
139+
self.__batch_size = batch_size
140+
self.__validation_set_path = validation_dataset_path
141+
142+
@staticmethod
143+
def __load_dataset(directory: str) -> datasets.ImageFolder:
144+
directory_path = Path(directory)
145+
if not directory_path.exists():
146+
raise FileNotFoundError(f"Directory: {directory} does not exist.")
147+
148+
transform = transforms.Compose(
149+
[
150+
transforms.Resize(256),
151+
transforms.CenterCrop(224),
152+
transforms.ToTensor(),
153+
transforms.Normalize(
154+
mean=[0.484, 0.454, 0.403], std=[0.225, 0.220, 0.220]
155+
),
156+
]
157+
)
158+
return datasets.ImageFolder(directory_path, transform=transform)
159+
160+
@staticmethod
161+
def get_calibrator(training_dataset_path: str) -> DataLoader:
162+
dataset = MobileNetV2Evaluator.__load_dataset(training_dataset_path)
163+
rand_indices = random.sample(range(len(dataset)), k=1000)
164+
165+
# Return a subset of the dataset to be used for calibration
166+
return torch.utils.data.DataLoader(
167+
torch.utils.data.Subset(dataset, rand_indices),
168+
batch_size=1,
169+
shuffle=False,
170+
)
171+
172+
def __evaluate_mobilenet(self) -> Tuple[float, float]:
173+
dataset = MobileNetV2Evaluator.__load_dataset(self.__validation_set_path)
174+
loaded_dataset = DataLoader(
175+
dataset,
176+
batch_size=self.__batch_size,
177+
shuffle=False,
178+
)
179+
180+
top1_correct = 0
181+
top5_correct = 0
182+
183+
for i, (image, target) in enumerate(loaded_dataset):
184+
prediction = self.int8_model(image)
185+
top1_prediction = torch.topk(prediction, k=1, dim=1).indices
186+
top5_prediction = torch.topk(prediction, k=5, dim=1).indices
187+
188+
top1_correct += (top1_prediction == target.view(-1, 1)).sum().item()
189+
top5_correct += (top5_prediction == target.view(-1, 1)).sum().item()
190+
191+
logger.info("Iteration: {}".format((i + 1) * self.__batch_size))
192+
logger.info(
193+
"Top 1: {}".format(top1_correct / ((i + 1) * self.__batch_size))
194+
)
195+
logger.info(
196+
"Top 5: {}".format(top5_correct / ((i + 1) * self.__batch_size))
197+
)
198+
199+
top1_accuracy = top1_correct / len(dataset)
200+
top5_accuracy = top5_correct / len(dataset)
201+
202+
return top1_accuracy, top5_accuracy
203+
204+
def evaluate(self) -> dict[str, Any]:
205+
top1_correct, top5_correct = self.__evaluate_mobilenet()
206+
output = super().evaluate()
207+
208+
output["metrics"]["accuracy"] = {"top-1": top1_correct, "top-5": top5_correct}
209+
return output

backends/cadence/hifi/operators/dequantize_per_tensor.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,9 @@ void dequantize_per_tensor_out(
4141
} else if (input.scalar_type() == ScalarType::Short) {
4242
const int16_t* input_data = input.const_data_ptr<int16_t>();
4343
dequantize<int16_t>(out_data, input_data, scale, zero_point, numel);
44-
} else if (input.scalar_type() == ScalarType::Bits16) {
44+
} else if (
45+
input.scalar_type() == ScalarType::Bits16 ||
46+
input.scalar_type() == ScalarType::UInt16) {
4547
const uint16_t* input_data = input.const_data_ptr<uint16_t>();
4648
dequantize<uint16_t>(out_data, input_data, scale, zero_point, numel);
4749
} else if (input.scalar_type() == ScalarType::Int) {

backends/cadence/hifi/operators/quantize_per_tensor.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,9 @@ void quantize_per_tensor_out(
4444
int16_t* out_data = out.mutable_data_ptr<int16_t>();
4545
cadence::impl::HiFi::kernels::quantize<int16_t>(
4646
out_data, input_data, 1. / scale, zero_point, numel);
47-
} else if (out.scalar_type() == ScalarType::Bits16) {
47+
} else if (
48+
out.scalar_type() == ScalarType::Bits16 ||
49+
out.scalar_type() == ScalarType::UInt16) {
4850
uint16_t* out_data = out.mutable_data_ptr<uint16_t>();
4951
cadence::impl::HiFi::kernels::quantize<uint16_t>(
5052
out_data, input_data, 1. / scale, zero_point, numel);

backends/cadence/reference/operators/dequantize_per_tensor.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,9 @@ void dequantize_per_tensor_out(
3737
const int8_t* input_data = input.const_data_ptr<int8_t>();
3838
impl::reference::kernels::dequantize<int8_t>(
3939
out_data, input_data, scale, zero_point, numel);
40-
} else if (input.scalar_type() == ScalarType::Bits16) {
40+
} else if (
41+
input.scalar_type() == ScalarType::Bits16 ||
42+
input.scalar_type() == ScalarType::UInt16) {
4143
const uint16_t* input_data = input.const_data_ptr<uint16_t>();
4244
impl::reference::kernels::dequantize<uint16_t>(
4345
out_data, input_data, scale, zero_point, numel);

backends/cadence/reference/operators/quantize_per_tensor.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,9 @@ void quantize_per_tensor_out(
3939
int8_t* out_data = out.mutable_data_ptr<int8_t>();
4040
impl::reference::kernels::quantize<int8_t>(
4141
out_data, input_data, 1. / scale, zero_point, numel);
42-
} else if (out.scalar_type() == ScalarType::Bits16) {
42+
} else if (
43+
out.scalar_type() == ScalarType::Bits16 ||
44+
out.scalar_type() == ScalarType::UInt16) {
4345
uint16_t* out_data = out.mutable_data_ptr<uint16_t>();
4446
impl::reference::kernels::quantize<uint16_t>(
4547
out_data, input_data, 1. / scale, zero_point, numel);

0 commit comments

Comments
 (0)