Skip to content

Commit 5309a25

Browse files
author
Github Executorch
committed
Summary: Add Statefull FC Cortex-m linearOps
Integrate with CMSIS-NN with per-channel quantization support Test Plan: Run e2e test on FVP simulator ./examples/arm/run_mcu_models_fvp.sh --target=cortex-m55 --models=qlinear Reviewers: Subscribers: Tasks: Tags:
1 parent 0e9d871 commit 5309a25

File tree

9 files changed

+1188
-38
lines changed

9 files changed

+1188
-38
lines changed

backends/cortex_m/CMakeLists.txt

Lines changed: 49 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -21,31 +21,59 @@ include(${EXECUTORCH_ROOT}/tools/cmake/Utils.cmake)
2121
include(${EXECUTORCH_ROOT}/tools/cmake/Codegen.cmake)
2222
include(FetchContent)
2323

24-
# CMSIS-NN version to download
25-
set(CMSIS_NN_VERSION
26-
"v4.1.0"
27-
CACHE STRING "CMSIS-NN version to download"
28-
)
29-
30-
# Declare CMSIS-NN as a FetchContent project
31-
FetchContent_Declare(
32-
cmsis_nn
33-
GIT_REPOSITORY https://github.com/ARM-software/CMSIS-NN.git
34-
GIT_TAG ${CMSIS_NN_VERSION}
35-
)
36-
37-
# Download and make CMSIS-NN available
38-
FetchContent_MakeAvailable(cmsis_nn)
39-
40-
# Print paths for debugging
41-
message(STATUS "CMSIS-NN source dir: ${cmsis_nn_SOURCE_DIR}")
42-
message(STATUS "CMSIS-NN binary dir: ${cmsis_nn_BINARY_DIR}")
24+
set(USE_LOCAL_CMSIS_NN OFF)
25+
26+
if(USE_LOCAL_CMSIS_NN)
27+
if(NOT EXISTS ${CMSIS_NN_LOCAL_PATH})
28+
message(
29+
FATAL_ERROR "CMSIS-NN local path does not exist: ${CMSIS_NN_LOCAL_PATH}"
30+
)
31+
endif()
32+
if(NOT EXISTS ${CMSIS_NN_LOCAL_LIB})
33+
message(
34+
FATAL_ERROR "CMSIS-NN local lib does not exist: ${CMSIS_NN_LOCAL_LIB}"
35+
)
36+
endif()
37+
message(STATUS "Using CMSIS-NN from: ${CMSIS_NN_LOCAL_PATH}")
38+
add_subdirectory(${CMSIS_NN_LOCAL_PATH} cmsis_nn_build)
39+
# Add MVEI define to cmsis-nn target
40+
target_compile_definitions(cmsis-nn PUBLIC ARM_MATH_MVEI=1)
41+
42+
set(CMSIS_NN_INCLUDE_DIR "${CMSIS_NN_LOCAL_PATH}/Include")
43+
set(CMSIS_NN_LIB "${CMSIS_NN_LOCAL_LIB}/libcmsis-nn.a")
44+
45+
else()
46+
message(STATUS "Using CMSIS-NN from via : FetchContent")
47+
set(CMSIS_NN_VERSION
48+
"v7.0.0"
49+
CACHE STRING "CMSIS-NN version to download"
50+
)
51+
FetchContent_Declare(
52+
cmsis_nn
53+
GIT_REPOSITORY https://github.com/ARM-software/CMSIS-NN.git
54+
GIT_TAG ${CMSIS_NN_VERSION}
55+
)
56+
FetchContent_MakeAvailable(cmsis_nn)
57+
# Add MVEI define to cmsis-nn target
58+
target_compile_definitions(cmsis-nn PUBLIC ARM_MATH_MVEI=1)
59+
# Get the correct source and binary dirs
60+
FetchContent_GetProperties(
61+
cmsis_nn
62+
SOURCE_DIR CMSIS_NN_SOURCE_DIR
63+
BINARY_DIR CMSIS_NN_BINARY_DIR
64+
)
65+
set(CMSIS_NN_INCLUDE_DIR "${CMSIS_NN_SOURCE_DIR}/Include")
66+
set(CMSIS_NN_LIB "${CMSIS_NN_BINARY_DIR}/libcmsis-nn.a")
67+
message(STATUS " ${CMSIS_NN_SOURCE_DIR}")
68+
message(STATUS "CMSIS-NN binary dir: ${CMSIS_NN_BINARY_DIR}")
69+
endif()
4370

4471
# Cortex-M ops kernel sources
4572
set(_cortex_m_kernels__srcs
4673
${CMAKE_CURRENT_SOURCE_DIR}/ops/op_quantize_per_tensor.cpp
4774
${CMAKE_CURRENT_SOURCE_DIR}/ops/op_dequantize_per_tensor.cpp
4875
${CMAKE_CURRENT_SOURCE_DIR}/ops/op_quantized_add.cpp
76+
${CMAKE_CURRENT_SOURCE_DIR}/ops/op_quantized_linear.cpp
4977
)
5078

5179
# Generate C++ bindings to register kernels into Executorch (for runtime)
@@ -66,13 +94,11 @@ target_include_directories(
6694
cortex_m_kernels
6795
PRIVATE ${EXECUTORCH_ROOT}/..
6896
${EXECUTORCH_ROOT}/runtime/core/portable_type/c10
69-
${cmsis_nn_SOURCE_DIR}/Include
97+
${CMSIS_NN_INCLUDE_DIR}
7098
)
7199

72100
# Link directly to the CMSIS-NN static library file
73-
target_link_libraries(
74-
cortex_m_kernels PUBLIC ${cmsis_nn_BINARY_DIR}/libcmsis-nn.a executorch
75-
)
101+
target_link_libraries(cortex_m_kernels PUBLIC ${CMSIS_NN_LIB} executorch)
76102

77103
# Add dependency to ensure CMSIS-NN builds before we try to link. Use the actual
78104
# CMSIS-NN target name (usually 'cmsis-nn')

backends/cortex_m/ops/cortex_m_ops_common.h

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,16 +32,19 @@ inline void validate_cmsis_nn_tensor_requirements(
3232
// Basic dtype validation
3333
ET_CHECK_MSG(
3434
input1.scalar_type() == expected_dtype,
35-
"Input1 dtype must be %hhd",
36-
expected_dtype);
35+
"Input1 dtype must be %hhd, got %hhd",
36+
expected_dtype,
37+
input1.scalar_type());
3738
ET_CHECK_MSG(
3839
input2.scalar_type() == expected_dtype,
39-
"Input2 dtype must be %hhd",
40-
expected_dtype);
40+
"Input2 dtype must be %hhd, got %hhd",
41+
expected_dtype,
42+
input2.scalar_type());
4143
ET_CHECK_MSG(
4244
output.scalar_type() == expected_dtype,
43-
"Output dtype must be %hhd",
44-
expected_dtype);
45+
"Output dtype must be %hhd, got %hhd",
46+
expected_dtype,
47+
output.scalar_type());
4548

4649
// Dim order consistency
4750
ET_CHECK_MSG(
@@ -114,6 +117,27 @@ inline void validate_quantization_params(
114117
"Single quant Output");
115118
}
116119

120+
inline bool validate_per_channel_quant_params(
121+
const int32_t* multipliers,
122+
const int32_t* shifts,
123+
int num_channels) {
124+
for (int i = 0; i < num_channels; ++i) {
125+
if (multipliers[i] < (1LL << 30) || multipliers[i] > ((1LL << 31) - 1)) {
126+
ET_LOG(
127+
Error,
128+
"weight_multiplier[%d] out of CMSIS-NN range: %d",
129+
i,
130+
multipliers[i]);
131+
return false;
132+
}
133+
if (shifts[i] < 0 || shifts[i] > 31) {
134+
ET_LOG(Error, "weight_shift[%d] out of range: %d", i, shifts[i]);
135+
return false;
136+
}
137+
}
138+
return true;
139+
}
140+
117141
inline Error resize_to_broadcast_target_size(
118142
const Tensor& input1,
119143
const Tensor& input2,

0 commit comments

Comments
 (0)