This sample shows how to
Steps 1-2 are performed in Python via the pytorch_dynamic_shapes.ipynb
or tensorflow_dynamic_shapes.ipynb
Colab notebooks:
[!WARNING] The PyTorch sample code below is outdated, as the
@aot.jittable
API is unstable.
Framework | Notebook |
---|---|
PyTorch | |
TensorFlow |
Step 3 should be performed on your development host machine
Steps 4-5 are in main.c
The program used to demonstrate includes functions with varying uses of dynamic shapes:
import torch import iree.turbine.aot as aot class DynamicShapesModule(aot.CompiledModule, export_name="module"): # reduce_sum_1d (dynamic input size, static output size) # tensor<?xi32> -> tensor<i32> # e.g. [1, 2, 3] -> 6 def reduce_sum_1d(self, values=aot.AbstractTensor(None, dtype=torch.int32)): return self.compute_reduce_sum_1d(values) @aot.jittable def compute_reduce_sum_1d(values): return torch.sum(values, dtype=torch.int32) # reduce_sum_2d (partially dynamic input size, static output size) # tensor<?x3xi32> -> tensor<3xi32> # e.g. [[1, 2, 3], [10, 20, 30]] -> [11, 22, 33] def reduce_sum_2d(self, values=aot.AbstractTensor(None, 3, dtype=torch.int32)): return self.compute_reduce_sum_2d(values) @aot.jittable def compute_reduce_sum_2d(values): return torch.sum(values, 0, dtype=torch.int32) # add_one (dynamic input size, dynamic output size) # tensor<?xi32>) -> tensor<?xi32> # e.g. [1, 2, 3] -> [2, 3, 4] def add_one(self, values=aot.AbstractTensor(None, dtype=torch.int32)): return self.compute_add_one(values) @aot.jittable def compute_add_one(values): return values + 1
Tensors are multi-dimensional arrays with a uniform type (e.g. int32, float32) and a shape. Shapes consist of a rank and a list of dimensions and may be static (i.e. fully known and fixed) or varying degrees of dynamic. For more information, see these references:
torch.Tensor
Dynamic shapes are useful for passing variable sized batches as input, receiving variable length sentences of text as output, etc.
NOTE: as in other domains, providing more information to a compiler allows it to generate more efficient code. As a general rule, the slowest varying dimensions of program data like batch index or timestep are safer to treat as dynamic than faster varying dimensions like image x/y/channel. See this paper for a discussion of the challenges imposed by dynamic shapes and one project's approach to addressing them.
Run either Colab notebook and download the dynamic_shapes.mlir
file it generates
Get iree-compile
either by building from source or by installing from pip.
python -m pip install iree-base-compiler
Compile the dynamic_shapes.mlir
file using iree-compile
. The CPU configuration has the best support for dynamic shapes:
iree-compile \ --iree-hal-target-backends=llvm-cpu \ dynamic_shapes.mlir -o dynamic_shapes_cpu.vmfb
Build the iree_samples_dynamic_shapes
CMake target
cmake -B ../iree-build/ -G Ninja -DCMAKE_BUILD_TYPE=RelWithDebInfo -DIREE_BUILD_COMPILER=OFF . cmake --build ../iree-build/ --target iree_samples_dynamic_shapes
Alternatively if using a non-CMake build system the Makefile
provided can be used as a reference of how to use the IREE runtime in an external project.
Run the sample binary:
../iree-build/samples/dynamic_shapes/dynamic-shapes \ /path/to/dynamic_shapes_cpu.vmfb local-task