Skip to content

Commit c59ddf7

Browse files
committed
Update base for kick tests on "Reapply changes reverted by #11506"
This change seems to have accidentally reverted several of my changes due to (presumably) a bad rebase. Differential Revision: [D77559984](https://our.internmc.facebook.com/intern/diff/D77559984/) [ghstack-poisoned]
2 parents 75d4b2e + bed504e commit c59ddf7

File tree

38 files changed

+1459
-261
lines changed

38 files changed

+1459
-261
lines changed

.ci/scripts/test_model.sh

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,22 @@ test_model_with_qnn() {
188188
EXPORT_SCRIPT=edsr
189189
# Additional deps for edsr
190190
pip install piq
191+
elif [[ "${MODEL_NAME}" == "cvt" ]]; then
192+
EXPORT_SCRIPT=cvt
193+
elif [[ "${MODEL_NAME}" == "dit" ]]; then
194+
EXPORT_SCRIPT=dit
195+
elif [[ "${MODEL_NAME}" == "efficientnet" ]]; then
196+
EXPORT_SCRIPT=efficientnet
197+
elif [[ "${MODEL_NAME}" == "focalnet" ]]; then
198+
EXPORT_SCRIPT=focalnet
199+
elif [[ "${MODEL_NAME}" == "mobilevit_v1" ]]; then
200+
EXPORT_SCRIPT=mobilevit_v1
201+
elif [[ "${MODEL_NAME}" == "mobilevit_v2" ]]; then
202+
EXPORT_SCRIPT=mobilevit_v2
203+
elif [[ "${MODEL_NAME}" == "pvt" ]]; then
204+
EXPORT_SCRIPT=pvt
205+
elif [[ "${MODEL_NAME}" == "swin" ]]; then
206+
EXPORT_SCRIPT=swin_transformer
191207
elif [[ "${MODEL_NAME}" == "albert" ]]; then
192208
EXPORT_SCRIPT=albert
193209
elif [[ "${MODEL_NAME}" == "bert" ]]; then
@@ -196,6 +212,8 @@ test_model_with_qnn() {
196212
EXPORT_SCRIPT=distilbert
197213
elif [[ "${MODEL_NAME}" == "eurobert" ]]; then
198214
EXPORT_SCRIPT=eurobert
215+
elif [[ "${MODEL_NAME}" == "roberta" ]]; then
216+
EXPORT_SCRIPT=roberta
199217
else
200218
echo "Unsupported model $MODEL_NAME"
201219
exit 1
@@ -210,10 +228,13 @@ test_model_with_qnn() {
210228
"dl3"|"mv3"|"mv2"|"ic4"|"ic3"|"vit"|"mb"|"w2l")
211229
SCRIPT_FOLDER=scripts
212230
;;
213-
"albert"|"bert"|"distilbert")
231+
"cvt"|"dit"|"focalnet"|"mobilevit_v2"|"pvt"|"swin")
232+
SCRIPT_FOLDER=oss_scripts
233+
;;
234+
"albert"|"bert"|"distilbert"|"roberta"|"efficientnet"|"mobilevit_v1")
214235
pip install evaluate
215236
SCRIPT_FOLDER=oss_scripts
216-
# Bert models running in 16bit will encounter op validation fail on some operations,
237+
# 16bit models will encounter op validation fail on some operations,
217238
# which requires CHIPSET >= SM8550.
218239
QNN_CHIPSET=SM8550
219240
;;

.github/workflows/apple.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ jobs:
3939
id: set_version
4040
shell: bash
4141
run: |
42-
VERSION="0.7.0.$(TZ='PST8PDT' date +%Y%m%d)"
42+
VERSION="0.8.0.$(TZ='PST8PDT' date +%Y%m%d)"
4343
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
4444
4545
build-demo-ios:

.github/workflows/trunk.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -470,7 +470,7 @@ jobs:
470470
docker-image: executorch-ubuntu-22.04-qnn-sdk
471471
submodules: 'recursive'
472472
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }}
473-
timeout: 900
473+
timeout: 90
474474
script: |
475475
# The generic Linux job chooses to use base env, not the one setup by the image
476476
CONDA_ENV=$(conda env list --json | jq -r ".envs | .[-1]")
@@ -489,14 +489,14 @@ jobs:
489489
strategy:
490490
matrix:
491491
dtype: [fp32]
492-
model: [albert, bert, distilbert] # eurobert requires transfomer >= 4.48.0, skip for now
492+
model: [cvt, dit, efficientnet, focalnet, mobilevit_v1, mobilevit_v2, pvt, swin, albert, bert, distilbert, roberta] # eurobert requires transfomer >= 4.48.0, skip for now
493493
fail-fast: false
494494
with:
495495
runner: linux.2xlarge
496496
docker-image: executorch-ubuntu-22.04-qnn-sdk
497497
submodules: 'recursive'
498498
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }}
499-
timeout: 900
499+
timeout: 90
500500
script: |
501501
# The generic Linux job chooses to use base env, not the one setup by the image
502502
CONDA_ENV=$(conda env list --json | jq -r ".envs | .[-1]")

backends/arm/test/test_arm_baremetal.sh

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -73,22 +73,32 @@ all() { # Run all tests
7373
test_pytest_ops() { # Test ops and other things
7474
echo "${TEST_SUITE_NAME}: Run pytest"
7575

76+
# Make sure to not run this tests on FVP by removing the elf builds,
77+
# as they are detected by the unit tests and used if they exists
78+
rm -Rf arm_test/arm_semihosting_executor_runner_corstone-300
79+
rm -Rf arm_test/arm_semihosting_executor_runner_corstone-320
80+
7681
# Prepare for pytest
7782
backends/arm/scripts/build_executorch.sh
7883

7984
# Run arm baremetal pytest tests without FVP
80-
pytest --verbose --color=yes --numprocesses=auto backends/arm/test/ --ignore=backends/arm/test/models
85+
pytest --verbose --color=yes --numprocesses=auto --durations=10 backends/arm/test/ --ignore=backends/arm/test/models
8186
echo "${TEST_SUITE_NAME}: PASS"
8287
}
8388

8489
test_pytest_models() { # Test ops and other things
8590
echo "${TEST_SUITE_NAME}: Run pytest"
8691

92+
# Make sure to not run this tests on FVP by removing the elf builds,
93+
# as they are detected by the unit tests and used if they exists
94+
rm -Rf arm_test/arm_semihosting_executor_runner_corstone-300
95+
rm -Rf arm_test/arm_semihosting_executor_runner_corstone-320
96+
8797
# Prepare for pytest
8898
backends/arm/scripts/build_executorch.sh
8999

90100
# Run arm baremetal pytest tests without FVP
91-
pytest --verbose --color=yes backends/arm/test/models
101+
pytest --verbose --color=yes --durations=0 backends/arm/test/models
92102
echo "${TEST_SUITE_NAME}: PASS"
93103
}
94104

@@ -105,11 +115,13 @@ test_pytest_ops_ethosu_fvp() { # Same as test_pytest but also sometime verify us
105115
# Prepare Corstone-3x0 FVP for pytest
106116
backends/arm/scripts/build_executorch.sh
107117
backends/arm/scripts/build_portable_kernels.sh
108-
# Build semihosting version of the runner used by pytest testing when
118+
# Build semihosting version of the runner used by pytest testing. This builds:
119+
# arm_test/arm_semihosting_executor_runner_corstone-300
120+
# arm_test/arm_semihosting_executor_runner_corstone-320
109121
backends/arm/test/setup_testing.sh
110122

111123
# Run arm baremetal pytest tests with FVP
112-
pytest --verbose --color=yes --numprocesses=auto backends/arm/test/ --ignore=backends/arm/test/models
124+
pytest --verbose --color=yes --numprocesses=auto --durations=10 backends/arm/test/ --ignore=backends/arm/test/models
113125
echo "${TEST_SUITE_NAME}: PASS"
114126
}
115127

@@ -119,11 +131,13 @@ test_pytest_models_ethosu_fvp() { # Same as test_pytest but also sometime verify
119131
# Prepare Corstone-3x0 FVP for pytest
120132
backends/arm/scripts/build_executorch.sh
121133
backends/arm/scripts/build_portable_kernels.sh
122-
# Build semihosting version of the runner used by pytest testing
134+
# Build semihosting version of the runner used by pytest testing. This builds:
135+
# arm_test/arm_semihosting_executor_runner_corstone-300
136+
# arm_test/arm_semihosting_executor_runner_corstone-320
123137
backends/arm/test/setup_testing.sh
124138

125139
# Run arm baremetal pytest tests with FVP
126-
pytest --verbose --color=yes backends/arm/test/models
140+
pytest --verbose --color=yes --durations=0 backends/arm/test/models
127141
echo "${TEST_SUITE_NAME}: PASS"
128142
}
129143

backends/arm/test/test_model.py

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import os
88
import subprocess
99
import sys
10+
import time
1011

1112

1213
def get_args():
@@ -199,12 +200,17 @@ def run_elf_with_fvp(script_path: str, elf_file: str, target: str, timeout: int)
199200

200201

201202
if __name__ == "__main__":
202-
203+
total_start_time = time.perf_counter()
203204
args = get_args()
204205
script_path = os.path.join("backends", "arm", "scripts")
205206

206207
if args.build_libs:
208+
start_time = time.perf_counter()
207209
build_libs(args.test_output, script_path)
210+
end_time = time.perf_counter()
211+
print(
212+
f"[Test model: {end_time - start_time:.2f} s] Build needed executorch libs"
213+
)
208214

209215
if args.model:
210216
model_name = args.model.split(" ")[0].split(";")[0]
@@ -217,6 +223,7 @@ def run_elf_with_fvp(script_path: str, elf_file: str, target: str, timeout: int)
217223
args.test_output, f"{model_name}_arm_delegate_{args.target}"
218224
)
219225

226+
start_time = time.perf_counter()
220227
pte_file = build_pte(
221228
args.test_output,
222229
model_name,
@@ -226,13 +233,17 @@ def run_elf_with_fvp(script_path: str, elf_file: str, target: str, timeout: int)
226233
output,
227234
args.no_intermediate,
228235
)
229-
print(f"PTE file created: {pte_file} ")
236+
end_time = time.perf_counter()
237+
print(
238+
f"[Test model: {end_time - start_time:.2f} s] PTE file created: {pte_file}"
239+
)
230240

231241
if "ethos-u" in args.target:
232242
elf_build_path = os.path.join(
233243
output, f"{model_name}_arm_delegate_{args.target}"
234244
)
235245

246+
start_time = time.perf_counter()
236247
elf_file = build_ethosu_runtime(
237248
args.test_output,
238249
script_path,
@@ -243,7 +254,18 @@ def run_elf_with_fvp(script_path: str, elf_file: str, target: str, timeout: int)
243254
args.extra_flags,
244255
elf_build_path,
245256
)
246-
print(f"ELF file created: {elf_file} ")
257+
end_time = time.perf_counter()
258+
print(
259+
f"[Test model: {end_time - start_time:.2f} s] ELF file created: {elf_file}"
260+
)
247261

262+
start_time = time.perf_counter()
248263
run_elf_with_fvp(script_path, elf_file, args.target, args.timeout)
249-
print(f"Model: {model_name} on {args.target} -> PASS")
264+
end_time = time.perf_counter()
265+
print(
266+
f"[Test model: {end_time - start_time:.2f} s] Tested elf on FVP {elf_file}"
267+
)
268+
total_end_time = time.perf_counter()
269+
print(
270+
f"[Test model: {total_end_time - total_start_time:.2f} s total] Model: {model_name} on {args.target} -> PASS"
271+
)

backends/cadence/aot/fuse_ops.py

Lines changed: 36 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -856,19 +856,32 @@ class FuseMulTensorIntoQuantPass(ExportPass):
856856
def attempt_fusion(
857857
self, graph_module: torch.fx.GraphModule, mul_node: torch.fx.Node
858858
) -> None:
859-
full_nodes = [
860-
arg
861-
for arg in mul_node.args
862-
if isinstance(arg, torch.fx.Node)
863-
and arg.target == exir_ops.edge.aten.full.default
864-
]
859+
if len(mul_node.args) != 2 or len(mul_node.users) != 1:
860+
return
861+
862+
first_arg = cast(torch.fx.Node, mul_node.args[0])
863+
second_arg = cast(torch.fx.Node, mul_node.args[1])
864+
865+
input_node = first_arg
866+
full_node = second_arg
867+
if second_arg.target == exir_ops.edge.aten.full.default:
868+
# Most common case, nothing to change.
869+
pass
870+
elif first_arg.target == exir_ops.edge.aten.full.default:
871+
# Input and full nodes are swapped.
872+
full_node = first_arg
873+
input_node = second_arg
874+
else:
875+
# Full node is not found, skip.
876+
return
865877

866-
if len(full_nodes) != 1 or len(mul_node.users) != 1:
878+
# Ensure that the mul op does not do any broadcasting.
879+
if input_node.meta["val"].shape != mul_node.meta["val"].shape:
867880
return
868881

869-
full_node = full_nodes[0]
870882
mul_user = list(mul_node.users.keys())[0]
871883

884+
# Ensure only the expected quant ops are using the current mul op.
872885
if mul_user.target not in {
873886
exir_ops.edge.quantized_decomposed.quantize_per_tensor.default,
874887
exir_ops.edge.cadence.quantize_per_tensor.default,
@@ -878,33 +891,28 @@ def attempt_fusion(
878891
quant_node = mul_user
879892

880893
# Calculate the new scale value.
881-
prev_scale = quant_node.args[1]
882-
assert isinstance(prev_scale, (int, float))
894+
old_scale = quant_node.args[1]
895+
assert isinstance(old_scale, (int, float))
883896
mul_scalar = full_node.args[1]
884897
assert isinstance(mul_scalar, (int, float))
885-
new_scale = float(prev_scale) * float(mul_scalar)
898+
""" The reason why we divide old scale by the mul value to get a new scale:
899+
y = x * mul_scalar
900+
q = zp + y / old_scale
901+
q = zp + x * mul_scalar / old_scale
902+
new_scale = old_scale / mul_scalar
903+
q = zp + x / new_scale
904+
"""
905+
new_scale = float(old_scale) / float(mul_scalar)
886906

887907
logging.debug(
888908
f"Fused {mul_node} and {full_node} into {quant_node}. Updated scale from {quant_node.args[1]} to {new_scale}"
889909
)
890910

891-
# Replace the input first
892-
quant_node.replace_input_with(
893-
cast(torch.fx.Node, quant_node.args[0]),
894-
cast(torch.fx.Node, mul_node.args[0]),
895-
)
896-
897-
# Now update the scale in the args
898-
new_quant_args = list(quant_node.args)
899-
new_quant_args[1] = new_scale
900-
quant_node.args = tuple(new_quant_args)
901-
902-
# Clean up the mul_node
903-
mul_node.args = ()
904-
mul_node.users = {}
905-
906-
graph_module.graph.erase_node(mul_node)
907-
graph_module.graph.erase_node(full_node)
911+
# Update quant node input and scale.
912+
old_quant_input = cast(torch.fx.Node, quant_node.args[0])
913+
new_quant_input = cast(torch.fx.Node, mul_node.args[0])
914+
quant_node.replace_input_with(old_quant_input, new_quant_input)
915+
quant_node.update_arg(1, new_scale)
908916

909917
def call(self, graph_module: torch.fx.GraphModule) -> PassResult:
910918
for node in graph_module.graph.find_nodes(

backends/cadence/aot/tests/test_fusion_ops_passes.py

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -598,7 +598,7 @@ def test_fuse_mul_scalar_into_dequant(self) -> None:
598598
self.assertEqual(deq_scale, dequant_scale * mul_value)
599599

600600
def test_fuse_mul_into_quant(self) -> None:
601-
quant_scale = 1.5
601+
quant_scale = 5
602602
mul_value = 10
603603

604604
builder = GraphBuilder()
@@ -613,7 +613,7 @@ def test_fuse_mul_into_quant(self) -> None:
613613
)
614614
quant = builder.call_operator(
615615
op=exir_ops.edge.quantized_decomposed.quantize_per_tensor.default,
616-
args=(mul, quant_scale, 0, 0, 255, torch.uint8),
616+
args=(mul, quant_scale, 7, 0, 255, torch.uint8),
617617
)
618618
builder.output([quant])
619619
original_graph = builder.get_graph_module()
@@ -631,14 +631,18 @@ def test_fuse_mul_into_quant(self) -> None:
631631
)
632632

633633
# verify that the quant scale value was updated correctly
634-
deq_scale = -1
635-
for node in converted_graph.graph.nodes:
636-
if (
637-
node.target
638-
== exir_ops.edge.quantized_decomposed.quantize_per_tensor.default
639-
):
640-
deq_scale = node.args[1]
641-
self.assertEqual(deq_scale, quant_scale * mul_value)
634+
for node in converted_graph.graph.find_nodes(
635+
op="call_function",
636+
target=exir_ops.edge.quantized_decomposed.quantize_per_tensor.default,
637+
):
638+
new_quant_scale = node.args[1]
639+
self.assertEqual(new_quant_scale, quant_scale / mul_value)
640+
641+
# verify the math is correct
642+
inp = torch.randn(4, 32, dtype=torch.float32)
643+
original_out = original_graph(inp)[0]
644+
new_out = converted_graph(inp)[0]
645+
assert torch.equal(original_out, new_out)
642646

643647
def test_fuse_then_transpose_pass(self) -> None:
644648
# Create a graph with full -> transpose.

backends/qualcomm/builders/op_slice_copy.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ def define_node(
5656
if start < 0:
5757
start = start % input_tensor.shape[dim]
5858

59-
if len(node.args) > 3:
59+
if len(node.args) > 3 and node.args[3] is not None:
6060
end = min(cast(int, node.args[3]), input_tensor.shape[dim])
6161
if end < 0:
6262
end = end % input_tensor.shape[dim]

0 commit comments

Comments
 (0)