# Python bindings (Linux only) New in version 2.3.0. Python bindings for Halide provide a way to build and compile Halide pipelines from Python. We ship a Halide Python library that is available at `Halide/lib/python3/site-packages` in your Halide installation. Note Currently, we support this library on Linux only, and the library is compatible with Python version 3.8.x. ## Dependencies and setup Because this library depends on `libHalide.so` (available at `Halide/lib`), the path to this file must be added to `LD_LIBRARY_PATH`. To import this library in Python, you must also add `Halide/lib/python3/site-packages` and `Halide/tools` to the `PYTHONPATH` environment variable. ## Defining a Halide pipeline in Python A Halide pipeline written in Python follows the same ahead-of-time compilation approach described in ([Ahead-of-time compilation](https://docs.qualcomm.com/doc/80-PD002-1/topic/halide.html#aheadoftimecompilation)). However, we do not use generators ([Generators](https://docs.qualcomm.com/doc/80-PD002-1/topic/halide.html#generators)). The following example shows a 3x3 dilate filter written as a Halide pipeline in Python: 1import halide as hl 2input_img = hl.ImageParam(hl.UInt(8), 2) 3x, y, yo = hl.Var("x"), hl.Var("y"), hl.Var("yo") 4bounded_input, max_y, output = hl.Func("bounded_input"), hl.Func("max_y"), hl.Func("output") 5 6# Algorithm 7height = input_img.height() 8width = input_img.dim(0).extent() 9x_min = input_img.dim(0).min() 10 11bounded_input[x, y] = hl.BoundaryConditions.repeat_edge( 12 input_img, [(x_min, width), (hl.Expr(), hl.Expr())])[x, y] 13 14max_y[x, y] = hl.max(bounded_input[x, hl.clamp(y - 1, 0, height - 1)], 15 bounded_input[x, hl.clamp(y, 0, height - 1)], 16 bounded_input[x, hl.clamp(y + 1, 0, height - 1)]) 17 18output[x, y] = hl.max(max_y[x - 1, y], max_y[x, y], max_y[x + 1, y]) 19 20# Schedule 21output.hexagon() 22 23# Compile the pipeline to an executable 24target = hl.Target() 25target.os = hl.TargetOS.Android 26target.arch = hl.TargetArch.ARM 27target.bits = 64 28target.set_features([hl.TargetFeature.HVX]) 29args = [input_img] 30output.compile_to_file("dilate3x3", args, "dilate3x3", target) Copy to clipboard The algorithm and schedule are written in a similar way to the algorithm and schedule in C++. However, as seen in this example, `Func` is accessed using `[]` in Python instead of `()` in C++. For example, `max_y[x, y]` in Python instead of `max_y(x, y)` in C++. For cross-compilation, define a `target` to compile the pipeline and a list of inputs (`ImageParam` or `Param`), and pass it to `Func.compile_to_file()` with the name of the pipeline and output file. Running this Python program generates a host object file of the Halide pipeline, which is same as the output produced by AOT compilation of Halide in C++. Note This document is simply an introduction to getting started writing Halide pipelines in Python. More resources can be found at [https://halide-lang.org/docs](https://halide-lang.org/docs) and [https://github.com/halide/Halide/tree/master/python_bindings/tutorial](https://github.com/halide/Halide/tree/master/python_bindings/tutorial). ### Generators in Python Generators ([Generators](https://docs.qualcomm.com/doc/80-PD002-1/topic/halide.html#generators)), which are used to define a Halide pipeline in C++, are not available when writing a Halide pipeline in Python. However, we provide a utility called `pygen`, which gives you some of the conveniences of generators. The following example shows how the dilate filter is modified to use `pygen`. 1import Halide as hl 2import pygen 3 4params = pygen.get_params() 5target = params["target"] 6 7input_img = hl.ImageParam(hl.UInt(8), 2) 8x, y, yo = hl.Var("x"), hl.Var("y"), hl.Var("yo") 9bounded_input, max_y, output = hl.Func("bounded_input"), hl.Func("max_y"), hl.Func("output") 10 11# Algorithm 12height = input_img.height() 13width = input_img.dim(0).extent() 14x_min = input_img.dim(0).min() 15 16bounded_input[x, y] = hl.BoundaryConditions.repeat_edge( 17 input_img, [(x_min, width), (hl.Expr(), hl.Expr())])[x, y] 18 19max_y[x, y] = hl.max(bounded_input[x, hl.clamp(y - 1, 0, height - 1)], 20 bounded_input[x, hl.clamp(y, 0, height - 1)], 21 bounded_input[x, hl.clamp(y + 1, 0, height - 1)]) 22 23output[x, y] = hl.max(max_y[x - 1, y], max_y[x, y], max_y[x + 1, y]) 24 25# Schedule 26if target.has_feature(hl.TargetFeature.HVX): 27 output.hexagon() 28 29# Compile 30pygen.compile(output, [input_img]) Copy to clipboard Note `pygen` is located at `Halide/tools`. To import this utility, add this location to the `PYTHONPATH` environment variable. The `pygen` utility enables the pipeline to be used as a command-line program that is similar to a C++ generator, which takes target and other user-defined parameters as arguments and generates object code for the host. This utility supports flags exposed by a C++ generator with their typical meanings. For example: - Use `-o` to specify the location of the output files. - Use `-e` to specify the type of output files to be generated. The `pygen.get_params()` method returns a dictionary of parameters as received from the command line. The `pygen.add_params()` method can be used to add user-defined parameters, as shown in the following example. pygen.add_param("use_parallel_sched", bool, True) Copy to clipboard This method adds a Halide parameter called `use_parallel_sched`, which is a Boolean with a default value of `True`. The target string supplied at the command line can be queried as one of the parameters to make target-dependent choices in the pipeline. The `pygen.compile()` method takes the output `Func` to be compiled and a list of inputs to the pipeline as arguments, and it generates an object file for the target obtained from command line. Run this Python program as follows: dilate3x3.py -g dilate3x3 -o ./dilate3x3.o -e o,h -f dilate3x3 target=arm-64-android-hvx Copy to clipboard ## Differences between Python bindings and the C++ API The Python bindings attempt to mimic the Halide C++ API as closely as possible, with some differences where the C++ idiom is either inappropriate or impossible. - Most APIs that take a variadic argument list of integers in C++ take an explicit list in Python. For example, the typical version of the `Buffer` constructor in C++ offers variadic and list versions: `Buffer<>(Type t, int extent_dim_0, int extent_dim_1, ...., extent_dim_N, string name = "")` `Buffer<>(Type t, vector extents, string name = "")` In Python, only the second variant is provided. - `Func` and `Buffer` access is performed using `[]` rather than `()`. - Some classes in the Halide API are not provided because they are wrapped with standard Python idioms: - `Halide::Tuple` does not exist in the Python bindings; an ordinary Python tuple of `Halide::Expr` is used instead. - `Halide::Realization` does not exist in the Python bindings; an ordinary Python tuple of `Halide::Buffer` is used instead. - `Halide::Error` and others do not exist; standard Python error handling is used instead. - Static and instance method overloads with the same name in the same class are not allowed. Thus, some convenience methods are missing from `Halide::Var`. - Templated types (notably `Halide::Buffer<>` and `Halide::Param<>`) are not provided, for obvious reasons. Only the equivalents of `Halide::Buffer` and `Halide::Param` are supported. - Only symbols in the `Halide` namespace are supported. Classes and methods that involve using the `Halide::Internal` namespace are not provided. - The functions in `Halide::ConciseCasts` are present in the top-level Halide module in Python, rather than a submodule. For example, use `hl.i8_sat()`, not `hl.ConciseCasts.i8_sat()`. - No mechanism is provided for overriding any runtime functions from Python. - No mechanism is provided for supporting `Func::define_extern`. - `Buffer::for_each_value()` is hard to implement well in Python; it is omitted entirely for now. - `Func::in` becomes `Func.in_` because `in` is a Python keyword. ### Enhancements to the C++ API The `Buffer` class supports the Python Buffer Protocol ([https://www.python.org/dev/peps/pep-3118/](https://www.python.org/dev/peps/pep-3118/)), and thus it is easily and cheaply converted to and from other compatible objects (such as NumPy’s `ndarray`), with storage being shared. ## Halide Python examples Example Halide pipelines written in Python can be found at `Examples/offload/apps/hexagon_benchmarks` along with their C++ counterparts. Before running the examples, ensure that correct Python version is installed (currently supported Python 3.8.x). Also, if multiple Python v3 versions are present, set the `PYTHON` environment variable to point to the location of the Python version to be used. Set up the environment as described in ([Setup](https://docs.qualcomm.com/doc/80-PD002-1/topic/examples.html#examplessetup)). Then, set `USE_PYTHON` to 1 for running the Python examples: USE_PYTHON=1 make run Copy to clipboard Last Published: Jul 08, 2024 [Previous Topic Halide with UBWCDMA](https://docs.qualcomm.com/bundle/publicresource/80-PD002-1/topics/ubwcdma.md) [Next Topic Halide examples](https://docs.qualcomm.com/bundle/publicresource/80-PD002-1/topics/examples.md)