Skip to content

Commit d711ec1

Browse files
authored
LLM custom ops tutorial should direct to general custom ops (#10139)
Instead of having two pages using the same custom example, consolidate into one. Also move Source-to-source transformation to kernel-library-custom-aten-kernel.md
1 parent d28670b commit d711ec1

File tree

2 files changed

+23
-89
lines changed

2 files changed

+23
-89
lines changed

docs/source/kernel-library-custom-aten-kernel.md

+20
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,26 @@ torch.ops.load_library("libcustom_linear.so/dylib")
299299
op = torch.ops.myop.custom_linear.default
300300
```
301301

302+
#### Using a Custom Operator in a Model
303+
304+
The custom operator can explicitly used in the PyTorch model, or you can write a transformation to replace instances of a core operator with the custom variant. For this example, you could find
305+
all instances of `torch.nn.Linear` and replace them with `CustomLinear`.
306+
307+
```python
308+
def replace_linear_with_custom_linear(module):
309+
for name, child in module.named_children():
310+
if isinstance(child, nn.Linear):
311+
setattr(
312+
module,
313+
name,
314+
CustomLinear(child.in_features, child.out_features, child.bias),
315+
)
316+
else:
317+
replace_linear_with_custom_linear(child)
318+
```
319+
320+
The remaining steps are the same as the normal flow. Now you can run this module in eager mode as well as export to ExecuTorch.
321+
302322
### Custom Ops API Best Practices
303323

304324
Given that we have 2 kernel registration APIs for custom ops, which API should we use? Here are some pros and cons for each API:

docs/source/llm/getting-started.md

+3-89
Original file line numberDiff line numberDiff line change
@@ -855,99 +855,13 @@ With the ExecuTorch custom operator APIs, custom operator and kernel authors can
855855

856856
There are three steps to use custom kernels in ExecuTorch:
857857

858-
1. Write the custom kernel using ExecuTorch types.
859-
2. Compile and link the custom kernel to both AOT Python environment as well as the runtime binary.
860-
3. Source-to-source transformation to swap an operator with a custom op.
861-
862-
### Writing a Custom Kernel
863-
864-
Define your custom operator schema for both functional variant (used in AOT compilation) and out variant (used in ExecuTorch runtime). The schema needs to follow PyTorch ATen convention (see [native_functions.yaml](https://github.com/pytorch/pytorch/blob/main/aten/src/ATen/native/native_functions.yaml)).
865-
866-
```
867-
custom_linear(Tensor weight, Tensor input, Tensor(?) bias) -> Tensor
868-
869-
custom_linear.out(Tensor weight, Tensor input, Tensor(?) bias, *, Tensor(a!) out) -> Tensor(a!)
870-
```
871-
872-
Write your custom kernel according to the schema defined above. Use the `EXECUTORCH_LIBRARY` macro to make the kernel available to the ExecuTorch runtime.
873-
874-
```cpp
875-
// custom_linear.h / custom_linear.cpp
876-
#include <executorch/runtime/kernel/kernel_includes.h>
877-
878-
Tensor& custom_linear_out(const Tensor& weight, const Tensor& input, optional<Tensor> bias, Tensor& out) {
879-
// calculation
880-
return out;
881-
}
882-
883-
// Register as myop::custom_linear.out
884-
EXECUTORCH_LIBRARY(myop, "custom_linear.out", custom_linear_out);
885-
```
886-
887-
To make this operator available in PyTorch, you can define a wrapper around the ExecuTorch custom kernel. Note that the ExecuTorch
888-
implementation uses ExecuTorch tensor types, while the PyTorch wrapper uses ATen tensors.
889-
890-
```cpp
891-
// custom_linear_pytorch.cpp
892-
893-
#include "custom_linear.h"
894-
#include <torch/library.h>
895-
896-
at::Tensor custom_linear(const at::Tensor& weight, const at::Tensor& input, std::optional<at::Tensor> bias) {
897-
898-
// initialize out
899-
at::Tensor out = at::empty({weight.size(1), input.size(1)});
900-
901-
// wrap kernel in custom_linear.cpp into ATen kernel
902-
WRAP_TO_ATEN(custom_linear_out, 3)(weight, input, bias, out);
903-
904-
return out;
905-
}
906-
907-
// Register the operator with PyTorch.
908-
TORCH_LIBRARY(myop, m) {
909-
m.def("custom_linear(Tensor weight, Tensor input, Tensor(?) bias) -> Tensor", custom_linear);
910-
m.def("custom_linear.out(Tensor weight, Tensor input, Tensor(?) bias, *, Tensor(a!) out) -> Tensor(a!)", WRAP_TO_ATEN(custom_linear_out, 3));
911-
}
912-
```
913-
914-
### Compile and Link the Custom Kernel
915-
916-
To make it available to the ExecuTorch runtime, compile custom_linear.h/cpp into the binary target. You can also build the kernel as a dynamically loaded library (.so or .dylib) and link it as well.
917-
918-
To make it available to PyTorch, package custom_linear.h, custom_linear.cpp and custom_linear_pytorch.cpp into a dynamically loaded library (.so or .dylib) and load it into the python environment.
919-
This is needed to make PyTorch aware of the custom operator at the time of export.
920-
921-
```python
922-
import torch
923-
torch.ops.load_library("libcustom_linear.so")
924-
```
925-
926-
Once loaded, you can use the custom operator in PyTorch code.
858+
1. [Write the custom kernel](../kernel-library-custom-aten-kernel.md#c-api-for-custom-ops) using ExecuTorch types.
859+
2. [Compile and link the custom kernel](../kernel-library-custom-aten-kernel.md#compile-and-link-the-custom-kernel) to both AOT Python environment as well as the runtime binary.
860+
3. [Source-to-source transformation](../kernel-library-custom-aten-kernel.md#using-a-custom-operator-in-a-model) to swap an operator with a custom op.
927861

928862
For more information, see [PyTorch Custom Operators](https://pytorch.org/tutorials/advanced/torch_script_custom_ops.html) and
929863
and [ExecuTorch Kernel Registration](../kernel-library-custom-aten-kernel.md).
930864

931-
### Using a Custom Operator in a Model
932-
933-
The custom operator can explicitly used in the PyTorch model, or you can write a transformation to replace instances of a core operator with the custom variant. For this example, you could find
934-
all instances of `torch.nn.Linear` and replace them with `CustomLinear`.
935-
936-
```python
937-
def replace_linear_with_custom_linear(module):
938-
for name, child in module.named_children():
939-
if isinstance(child, nn.Linear):
940-
setattr(
941-
module,
942-
name,
943-
CustomLinear(child.in_features, child.out_features, child.bias),
944-
)
945-
else:
946-
replace_linear_with_custom_linear(child)
947-
```
948-
949-
The remaining steps are the same as the normal flow. Now you can run this module in eager mode as well as export to ExecuTorch.
950-
951865
## How to Build Mobile Apps
952866
See the instructions for building and running LLMs using ExecuTorch on iOS and Android.
953867

0 commit comments

Comments
 (0)