Skip to content

Commit e90c718

Browse files
committed
Explain ExecuTorch in the ESP-IDF component's README
The component's README is its page on the ESP Component Registry, and it opened with how the tree is generated and versioned, which tells a newcomer nothing about what ExecuTorch is or where to start. It now introduces ExecuTorch and how a model goes from torch.export to a .pte that the runtime runs from flash, lists what the component carries, and gives the command that creates the hello_executorch project from the registry. The usage notes become steps in the order a project takes them, with an export example for the ESP-NN delegate, run against the current package, and the et_model example from its header. How the tree is generated and versioned moves to the end. Authored with Claude Code.
1 parent edb4d5b commit e90c718

1 file changed

Lines changed: 151 additions & 50 deletions

File tree

  • examples/espressif/idf_component_template

‎examples/espressif/idf_component_template/README.md‎

Lines changed: 151 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,65 @@ This source code is licensed under the BSD-style license found in the
66
LICENSE file in the root directory of this source tree.
77
-->
88

9-
# ExecuTorch for ESP-IDF (`executorch` component)
9+
# ExecuTorch for ESP-IDF
10+
11+
[ExecuTorch](https://github.com/pytorch/executorch) is PyTorch's open
12+
source stack for running AI locally on phones, wearables, laptops,
13+
browsers, embedded systems and microcontrollers. This component brings
14+
its runtime to ESP-IDF 6.0 and later, for any ESP target, as source that
15+
builds with your project.
16+
17+
## How ExecuTorch works
18+
19+
A model is prepared ahead of time, on your computer, with the
20+
`executorch` Python package. You export it with `torch.export`,
21+
optionally quantize it, and lower it to a `.pte` program. Lowering can
22+
hand the parts of the model that a backend supports to that backend's
23+
delegate, and it plans where every tensor lives in memory, so the
24+
device runs the model in arenas whose sizes are known before it starts.
25+
26+
On the device, the runtime reads the `.pte` in place from flash and runs
27+
it: each operator with a kernel from a kernel library, and each
28+
delegated part with its backend.
29+
30+
[How ExecuTorch works](https://docs.pytorch.org/executorch/stable/intro-how-it-works.html)
31+
and [Model export and lowering](https://docs.pytorch.org/executorch/stable/using-executorch-export.html)
32+
cover this in more depth.
33+
34+
## What the component provides
35+
36+
- The ExecuTorch runtime, and `et_model.h`, a small C API that runs a
37+
`.pte` from flash.
38+
- Kernel libraries: portable (reference kernels for the core ATen
39+
operators), quantized, and the Cadence backend's generic kernels.
40+
- The ESP-NN delegate, `EspNNBackend`, which runs the int8 parts of a
41+
model lowered for it with Espressif's
42+
[ESP-NN](https://github.com/espressif/esp-nn) kernels. ESP-NN has SIMD
43+
kernels for the ESP32-S3 and portable C kernels for the other chips.
44+
The delegate is a prototype under active development.
45+
- `tools/gen_kernels.py`, which makes the kernel bundle that registers
46+
the kernels your models use.
47+
- `examples/hello_executorch`, a complete project.
48+
49+
## Try it
50+
51+
`hello_executorch` runs a small model and checks its outputs. Its `.pte`
52+
and kernel bundle are already made, so it needs only ESP-IDF:
1053

11-
**This tree is generated. Do not edit it by hand.** It is produced by
12-
`examples/espressif/build_idf_component.sh` in the
13-
[ExecuTorch](https://github.com/pytorch/executorch) repository.
54+
```sh
55+
idf.py create-project-from-example "pytorch/executorch==@ET_COMPONENT_VERSION@:hello_executorch"
56+
cd hello_executorch
57+
idf.py set-target esp32s3
58+
idf.py build flash monitor
59+
```
60+
61+
It prints `ET_COMPONENT_SMOKE: PASS` when every output matches. In a
62+
copy of this component you generated yourself, build
63+
`examples/hello_executorch` in place instead.
1464

15-
`VERSION` in this directory records the ExecuTorch commit, the generator's
16-
options, the kernel libraries the component ships and the torch to
17-
install with executorch. `examples/hello_executorch` is a complete
18-
project that runs a small model with its kernel bundle; its README says
19-
how they were made.
65+
## Using it in your project
2066

21-
## Using it
67+
### Add the dependency
2268

2369
Depend on one exact version and commit `dependencies.lock`:
2470

@@ -27,38 +73,23 @@ dependencies:
2773
pytorch/executorch: "==@ET_COMPONENT_VERSION@"
2874
```
2975
30-
The registry's dev versions, `X.Y.Z-dev.YYYYMMDD`, come from the
31-
`nightly` branch. A copy you generate yourself is not published; use it
32-
from your project's `components/` or through `override_path`.
33-
3476
A kernel bundle is made for one component version, a `~N` respin
3577
included, and the build refuses a bundle made for another version, or
3678
for the same version from another commit. With a range, the build
3779
breaks once the lock is re-solved to a newer version (for example by
3880
`idf.py update-dependencies`), until the bundle is regenerated.
3981

40-
The component carries the runtime, every kernel of its kernel
41-
libraries (portable, quantized, the Cadence backend's generic kernels
42-
and the `esp_nn::` op library) and the ESP-NN delegate
43-
(`EspNNBackend`), but registers only the kernels your models use and
44-
links the delegate only when one of them uses it. It depends on
45-
`espressif/esp-nn`, which the component manager fetches from the
46-
production registry, components.espressif.com, even for a project that
47-
names another registry; a project that builds without the component
48-
manager provides it as `components/esp-nn`. The kernels come
49-
from a kernel bundle that `tools/gen_kernels.py` makes from your
50-
`.pte` files. Run it with the Python environment you exported the
51-
models with, after every export, ExecuTorch upgrade or update of this
52-
component, and keep the bundle in your project:
82+
The component depends on `espressif/esp-nn`, which the component manager
83+
fetches from the production registry, components.espressif.com, even
84+
for a project that names another registry. A project that builds
85+
without the component manager provides it as `components/esp-nn`.
5386

54-
```sh
55-
python <this directory>/tools/gen_kernels.py --pte main/model.pte --out main/et_kernels
56-
```
87+
### Set up Python
5788

58-
That environment (Python 3.11 to 3.15) needs the executorch this
59-
component was built from, and the torch that `VERSION` names as
60-
`torch_requirement`, from its `torch_index`, since ExecuTorch's wheels
61-
declare no torch:
89+
Exporting models and making kernel bundles need Python 3.11 to 3.15 with
90+
the executorch this component was built from, and the torch that
91+
`VERSION` names as `torch_requirement`, from its `torch_index`, since
92+
ExecuTorch's wheels declare no torch:
6293

6394
```sh
6495
@ET_INSTALL@
@@ -68,10 +99,48 @@ A dev version's executorch comes from the nightly index, which keeps
6899
about 60 days of wheels, so move to a newer version before yours ages
69100
out.
70101

71-
Then declare the models and the bundle, from a component's
72-
`CMakeLists.txt` after its `idf_component_register()` or from the
73-
project's after `project()`, and add `executorch` to the requirements
74-
of the components that use it:
102+
### Export a model
103+
104+
To run a model with ESP-NN, quantize it with `EspNNQuantizer` and lower
105+
it with `to_espnn_edge`, which delegates the int8 regions ESP-NN
106+
supports and leaves the rest to the CPU kernels:
107+
108+
```python
109+
import torch
110+
from executorch.backends.espressif import EspNNQuantizer, to_espnn_edge
111+
from torchao.quantization.pt2e.quantize_pt2e import convert_pt2e, prepare_pt2e
112+
113+
model = MyModel().eval()
114+
example_inputs = (torch.randn(1, 3, 96, 96),)
115+
116+
prepared = prepare_pt2e(
117+
torch.export.export(model, example_inputs).module(), EspNNQuantizer()
118+
)
119+
for inputs in calibration_inputs: # representative inputs set the int8 scales
120+
prepared(*inputs)
121+
quantized = torch.export.export(convert_pt2e(prepared), example_inputs)
122+
edge, report = to_espnn_edge(quantized)
123+
with open("main/model.pte", "wb") as f:
124+
f.write(edge.to_executorch().buffer)
125+
```
126+
127+
### Make the kernel bundle
128+
129+
`tools/gen_kernels.py` makes the kernel bundle from your `.pte` files.
130+
Run it with the Python environment you exported the models with, after
131+
every export, ExecuTorch upgrade or update of this component, and keep
132+
the bundle in your project:
133+
134+
```sh
135+
python <this directory>/tools/gen_kernels.py --pte main/model.pte --out main/et_kernels
136+
```
137+
138+
### Declare the models and the bundle
139+
140+
From a component's `CMakeLists.txt` after its `idf_component_register()`,
141+
or from the project's after `project()`, declare the models and the
142+
bundle, and add `executorch` to the requirements of the components that
143+
use it:
75144

76145
```cmake
77146
idf_component_register(SRCS "main.c" PRIV_REQUIRES executorch)
@@ -106,18 +175,34 @@ With a bundle that registers kernels, the build compiles every vendored
106175
kernel source, and the link keeps only the ones the bundle registers.
107176
The extra kernels cost clean-build time, not flash.
108177

109-
- `#include <et_model.h>` for the small C inference API (flash XIP
110-
model bytes; method, planned and optional scratch arenas either
111-
passed in or allocated with heap_caps internal/PSRAM placement). This
112-
is what most applications should use. The `.pte` bytes must be
113-
16-byte aligned; `et_model_create` rejects misaligned data. Application pipelines built on it (audio
114-
front ends, detectors, wake word logic) live with the application,
115-
not in this runtime component.
116-
- `#include <executorch/...>` for the core C++ runtime
117-
(`Program`/`Method`) and `BufferDataLoader`. `extension::Module`, the
118-
file and mmap data loaders, and external `.ptd` data maps are not
119-
included. Runtime logging goes through ESP_LOG under the
120-
`executorch` tag.
178+
### Run the model
179+
180+
`et_model.h` loads a `.pte` and runs it:
181+
182+
```c
183+
#include <et_model.h>
184+
185+
et_model_config_t cfg = ET_MODEL_CONFIG_DEFAULT(model_pte, model_pte_size);
186+
cfg.planned_location = ET_MEM_INTERNAL; // activations in internal SRAM
187+
et_model_t *m = et_model_create(&cfg);
188+
if (!m || !et_model_load_method(m, NULL)) { /* handle the error */ }
189+
et_model_set_input(m, 0, frame, sizeof(frame));
190+
et_model_execute(m);
191+
size_t n;
192+
const void *out = et_model_output_data(m, 0, &n);
193+
```
194+
195+
The model bytes are read in place, typically from flash, and must be
196+
16-byte aligned; `et_model_create` rejects misaligned data.
197+
`examples/hello_executorch/main/CMakeLists.txt` embeds a `.pte` that way.
198+
The method, planned and optional scratch arenas are either passed in or
199+
allocated with heap_caps in internal RAM or PSRAM. Application pipelines
200+
built on it (audio front ends, detectors, wake word logic) live with the
201+
application, not in this component.
202+
203+
For the core C++ runtime (`Program`/`Method`) and `BufferDataLoader`,
204+
`#include <executorch/...>`. `extension::Module`, the file and mmap data
205+
loaders, and external `.ptd` data maps are not included.
121206

122207
## Size and debug options
123208

@@ -152,3 +237,19 @@ Projects moving from the op profiles of earlier versions remove
152237
`CONFIG_ET_ENABLE` and `CONFIG_ET_OP_PROFILE_*` from their sdkconfig,
153238
which no longer do anything, and declare their models and a kernel
154239
bundle as above.
240+
241+
## About this component
242+
243+
**This tree is generated. Do not edit it by hand.** It is produced by
244+
`examples/espressif/build_idf_component.sh` in the ExecuTorch
245+
repository. Releases are versioned as ExecuTorch's, `X.Y.Z`, with
246+
`X.Y.Z-rc.N` for release candidates and `X.Y.Z~N` for respins of this
247+
component. The registry's dev versions, `X.Y.Z-dev.YYYYMMDD`, come from
248+
the `nightly` branch. A copy you generate yourself is not published; use
249+
it from your project's `components/` or through `override_path`.
250+
251+
`VERSION` records the ExecuTorch commit, the generator's options, the
252+
kernel libraries the component ships and the torch to install with
253+
executorch. The README of `examples/hello_executorch` says how its model
254+
and kernel bundle were made. Vendored third-party code is listed in
255+
`THIRD_PARTY_LICENSES` and the `sbom*.yml` files.

0 commit comments

Comments
 (0)