Skip to content

Commit 8f0a7cb

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 ffd4044 commit 8f0a7cb

1 file changed

Lines changed: 161 additions & 49 deletions

File tree

  • examples/espressif/idf_component_template

‎examples/espressif/idf_component_template/README.md‎

Lines changed: 161 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,70 @@ 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
1010

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.
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 the model's intermediate tensors live in
24+
memory, so the device keeps them in an arena whose size is known before
25+
it starts.
26+
27+
On the device, the runtime reads the `.pte` in place from flash and runs
28+
it: each operator with a kernel from a kernel library, and each
29+
delegated part with its backend.
30+
31+
[How ExecuTorch works](https://docs.pytorch.org/executorch/stable/intro-how-it-works.html)
32+
and [Model export and lowering](https://docs.pytorch.org/executorch/stable/using-executorch-export.html)
33+
cover this in more depth.
34+
35+
## What the component provides
36+
37+
- The ExecuTorch runtime, and `et_model.h`, a small C API that runs a
38+
`.pte` from flash.
39+
- Kernel libraries: portable (reference kernels for the core ATen
40+
operators), quantized, and the Cadence backend's generic kernels.
41+
- The ESP-NN delegate, `EspNNBackend`, which runs the int8 parts of a
42+
model lowered for it with Espressif's
43+
[ESP-NN](https://github.com/espressif/esp-nn) kernels. ESP-NN has SIMD
44+
kernels for the ESP32-S3 and portable C kernels for the other chips.
45+
The delegate is a prototype under active development.
46+
- `tools/gen_kernels.py`, which makes the kernel bundle that registers
47+
the kernels your models use.
48+
- `examples/hello_executorch`, a complete project.
49+
50+
## Try it
51+
52+
`hello_executorch` runs a small model and checks its outputs. Its `.pte`
53+
and kernel bundle are already made, so it needs only ESP-IDF:
54+
55+
```sh
56+
idf.py create-project-from-example "pytorch/executorch==@ET_COMPONENT_VERSION@:hello_executorch"
57+
cd hello_executorch
58+
idf.py set-target esp32s3
59+
idf.py build flash monitor
60+
```
61+
62+
It prints `ET_COMPONENT_SMOKE: PASS` when every output matches. A
63+
release candidate is on the staging registry only, so for one, set
64+
`IDF_COMPONENT_REGISTRY_URL=https://components-staging.espressif.com`
65+
first. In a copy of this component you generated yourself, build
66+
`examples/hello_executorch` in place instead, if the generator included
67+
it, which it does when it runs with the executorch package built from
68+
the same commit.
1469

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.
70+
## Using it in your project
2071

21-
## Using it
72+
### Add the dependency
2273

2374
Depend on one exact version and commit `dependencies.lock`:
2475

@@ -27,38 +78,26 @@ dependencies:
2778
pytorch/executorch: "==@ET_COMPONENT_VERSION@"
2879
```
2980
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`.
81+
A release candidate's dependency also needs
82+
`registry_url: https://components-staging.espressif.com`.
3383

3484
A kernel bundle is made for one component version, a `~N` respin
3585
included, and the build refuses a bundle made for another version, or
3686
for the same version from another commit. With a range, the build
3787
breaks once the lock is re-solved to a newer version (for example by
3888
`idf.py update-dependencies`), until the bundle is regenerated.
3989

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:
90+
The component depends on `espressif/esp-nn`, which the component manager
91+
fetches from the production registry, components.espressif.com, even
92+
for a project that names another registry. A project that builds
93+
without the component manager provides it as `components/esp-nn`.
5394

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

58-
The Python environment you export models and run `gen_kernels.py` with
59-
needs the executorch this component was built from, and the torch that
60-
`VERSION` names as `torch_requirement`, from its `torch_index`, since
61-
ExecuTorch's wheels declare no torch:
97+
Exporting models and making kernel bundles need the executorch this
98+
component was built from, and the torch that `VERSION` names as
99+
`torch_requirement`, from its `torch_index`, since ExecuTorch's wheels
100+
declare no torch:
62101

63102
```sh
64103
@ET_INSTALL@
@@ -68,10 +107,48 @@ A dev version's executorch comes from the nightly index, which keeps
68107
about 60 days of wheels, so move to a newer version before yours ages
69108
out.
70109

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

76153
```cmake
77154
idf_component_register(SRCS "main.c" PRIV_REQUIRES executorch)
@@ -106,18 +183,37 @@ With a bundle that registers kernels, the build compiles every vendored
106183
kernel source, and the link keeps only the ones the bundle registers.
107184
The extra kernels cost clean-build time, not flash.
108185

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.
186+
### Run the model
187+
188+
`et_model.h` loads a `.pte` and runs it:
189+
190+
```c
191+
#include <et_model.h>
192+
193+
et_model_config_t cfg = ET_MODEL_CONFIG_DEFAULT(model_pte, model_pte_size);
194+
cfg.planned_location = ET_MEM_INTERNAL; // planned tensors in internal SRAM
195+
et_model_t *m = et_model_create(&cfg);
196+
if (!m || !et_model_load_method(m, NULL)) { /* handle the error */ }
197+
if (!et_model_set_input(m, 0, frame, sizeof(frame)) || !et_model_execute(m)) {
198+
/* et_model_last_error(m) says why */
199+
}
200+
size_t n;
201+
const void *out = et_model_output_data(m, 0, &n);
202+
```
203+
204+
`model_pte` and `model_pte_size` are the `.pte` bytes, read in place,
205+
typically from flash. They must be 16-byte aligned, and
206+
`et_model_create` rejects misaligned data. ESP-IDF's `EMBED_FILES` does
207+
not align what it embeds, so `examples/hello_executorch/main/CMakeLists.txt`
208+
embeds its `.pte` with an assembler `.balign 16` and `.incbin` instead.
209+
The method, planned and optional scratch arenas are either passed in or
210+
allocated with heap_caps in internal RAM or PSRAM. Application pipelines
211+
built on it (audio front ends, detectors, wake word logic) live with the
212+
application, not in this component.
213+
214+
For the core C++ runtime (`Program`/`Method`) and `BufferDataLoader`,
215+
`#include <executorch/...>`. `extension::Module`, the file and mmap data
216+
loaders, and external `.ptd` data maps are not included.
121217

122218
## Size and debug options
123219

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

0 commit comments

Comments
 (0)