Accera - An optimizing cross-compiler for compute-intensive code
Project description
Problem at Hand
Writing highly optimized compute-intensive code in a traditional programming language is strenuous and time-consuming. Not only does it require advanced engineering skills such as fluency in Assembly language, but a deep understanding of computer architecture is also indispensable. Manual optimization of even the simplest numerical algorithms demands a significant engineering effort. Needless to say, a highly optimized numerical code is often prone to bugs, lacks readability, and offers little to no usability. Code maintenance becomes a nightmare resulting in the reimplementation of the same logic every time an architecture level change is introduced.
Accera: An Optimized Solution
Accera is a compiler that enables you to experiment with loop optimizations without hand-writing Assembly code. With Accera, these problems and impediments can be addressed in an optimized way. It is available as a Python library and supports cross-compiling to a wide range of processor targets.
Accera has THREE primary goals:
- Performance: To guarantee the fastest implementation for any compute-intensive algorithm.
- Readability: To ensure effective implementation of algorithms without sacrificing the readability of code.
- Writability: To provide a user-friendly programming model, designed for agility and maintainability.
Install
To install for Linux, macOS, or Windows (requires Python 3.7-3.10):
pip install accera
See the Install Instructions for more details on installing pre-built Python 3 packages and how to build Accera from the source.
Quickstart
In this example, we will:
- Implement matrix multiplication with a ReLU activation (matmul + ReLU), commonly used in machine learning algorithms.
- Generate two implementations: a naive algorithm and loop-based transformations.
- Compare the execution time of both implementations.
Run in your browser
No installation is required. This will launch a Jupyter notebook with the quickstart example running in the cloud.
Run on your machine
-
Create a Python 3 script called
quickstart.py
:import accera as acc # define placeholder inputs/output A = acc.Array(role=acc.Role.INPUT, shape=(512, 512)) B = acc.Array(role=acc.Role.INPUT, shape=(512, 512)) C = acc.Array(role=acc.Role.INPUT_OUTPUT, shape=(512, 512)) # implement the logic for matmul and relu matmul = acc.Nest(shape=(512, 512, 512)) i1, j1, k1 = matmul.get_indices() @matmul.iteration_logic def _(): C[i1, j1] += A[i1, k1] * B[k1, j1] relu = acc.Nest(shape=(512, 512)) i2, j2 = relu.get_indices() @relu.iteration_logic def _(): C[i2, j2] = acc.max(C[i2, j2], 0.0) package = acc.Package() # fuse the i and j indices of matmul and relu, add to the package schedule = acc.fuse(matmul.create_schedule(), relu.create_schedule(), partial=2) package.add(schedule, args=(A, B, C), base_name="matmul_relu_fusion_naive") # transform the schedule, add to the package i, j, f, k = schedule.get_indices() ii, jj = schedule.tile({ i: 16, j: 16 }) # loop tiling schedule.reorder(j, i, f, k, jj, ii) # loop reordering plan = schedule.create_plan() plan.unroll(ii) # loop unrolling package.add(plan, args=(A, B, C), base_name="matmul_relu_fusion_transformed") # build a dynamically-linked package (a .dll or .so) that exports both functions print(package.build(name="hello_accera", format=acc.Package.Format.HAT_DYNAMIC))
-
Ensure that you have a compiler in your PATH:
- Windows: Install Microsoft Visual Studio and run
vcvars64.bat
to setup the command prompt. - Linux/macOS: Install gcc
Don't have a compiler handy? We recommend trying Accera in your browser instead
- Windows: Install Microsoft Visual Studio and run
-
Install Accera:
pip install accera
-
Generate the library that implements two versions of matmul + ReLU:
python quickstart.py
-
To consume and compare the library functions, create a file called
benchmark.py
in the same location:import hatlib as hat import numpy as np # load the package _, functions = hat.load("hello_accera.hat") # call one of the functions with test inputs A_test = np.random.rand(512, 512).astype(np.float32) B_test = np.random.rand(512, 512).astype(np.float32) C_test = np.zeros((512, 512)).astype(np.float32) C_numpy = np.maximum(C_test + A_test @ B_test, 0.0) matmul_relu = functions["matmul_relu_fusion_transformed"] matmul_relu(A_test, B_test, C_test) # check correctness np.testing.assert_allclose(C_test, C_numpy, atol=1e-3) # benchmark all functions hat.run_benchmark("hello_accera.hat", batch_size=5, min_time_in_sec=5)
-
Run the benchmark to get the execution time results:
python benchmark.py
Next Steps
The Manual is the best introductory resource for the Accera Python programming model.
In particular, the schedule transformations describe how you can experiment with different loop transformations with just a few lines of Python code.
Finally, the .hat
format is just a C header file containing the metadata. Learn more about the HAT format and benchmarking.
How it works
In a nutshell, Accera takes the Python code that defines the loop schedule and algorithm while converting it into MLIR intermediate representation (IR). Accera's compiler then takes this IR through a series of MLIR pipelines to perform transformations. The result is a binary library with a C header file. The library implements the algorithms that are defined in Python and it is compatible with the target.
To peek into the stages of IR transformation that Accera does, try replacing format=acc.Package.Format.HAT_DYNAMIC
with format=acc.Package.Format.MLIR_DYNAMIC
in quickstart.py
, re-run the script, and search the _tmp
subfolder for the intermediate *.mlir
files. We plan to document these IR constructs in the future.
Documentation
Get familiar with Accera's concepts and Python constructs in the Documentation page.
Tutorials
Step-by-step examples are available on the Tutorials page. We're working on adding more complementary examples and tutorials.
Contributions
Accera is a research platform-in-progress that can certainly benefit from your contributions. We would love your feedback, recommendations, and feature requests. Not to mention that we are excited to answer your questions. Let’s collaborate! Please file a Github issue or send us a pull request. Please review the Microsoft Code of Conduct to learn more.
Credits
Accera is built using several open source libraries, including: LLVM, pybind11, toml++, tomlkit, vcpkg, pyyaml, and HAT. For testing, we used numpy and catch2.
License
This project is released under the MIT License.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distributions
Hashes for accera-1.2.29-cp310-cp310-win_amd64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | c9efc46ea3420cca9c2d71ce873ec8ea7239993a7a1f1f490ceaa4f8731507ff |
|
MD5 | 68523a1ccfd547b0817694d2004e0bd5 |
|
BLAKE2b-256 | 3d23fa89b0deaa8364cd372fb426653071f4046129049dd274156056e61a1a9a |
Hashes for accera-1.2.29-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | af4990dd901b4c3da8b1e2a0de79138409a76328e45cd6690279946760960792 |
|
MD5 | 226f645782ea8c98d16b22c3883a0432 |
|
BLAKE2b-256 | 46f9a76c3a276a4e48c7c8a3661ee27a00eecc0fbaf79970f2fe65daff867df6 |
Hashes for accera-1.2.29-cp39-cp39-win_amd64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | f359e08b850f2132e8ece437c0ac73e1c4a3d955ff971d0fb4da8a90bc32e01d |
|
MD5 | d13f85c7289942ad71c487498852a032 |
|
BLAKE2b-256 | b8fef9f0debd6557cc5ecf561e22125c149704e5fe4ce905615e89f194a22412 |
Hashes for accera-1.2.29-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | da0a05a4cb3bef962c431d81a3d206b6812b593fe6761927aa33837c0b9cd6f6 |
|
MD5 | 21da8604da9670b06e400db5d845bf75 |
|
BLAKE2b-256 | da06a88115f6d8ba743ef7767198ea6f9974267cbb464d5baddc381114172c7c |
Hashes for accera-1.2.29-cp38-cp38-win_amd64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 97b77bf7f366534093bc1b2cf95f558ac566858a0a7be7993f47e3ef8340d74d |
|
MD5 | 37c33d367172800eedf6fafc5bda0d93 |
|
BLAKE2b-256 | 0614ece60c667c23087275992e1efcb852368978730d0766aae1bc70ff9560a0 |
Hashes for accera-1.2.29-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | d12b54fd53bd20e8a6e00d94621dd13fa155f52925aa04728c1ba62bd9def015 |
|
MD5 | 880679ccb0e2d9bdcb70a2ea299fd077 |
|
BLAKE2b-256 | 8601414fcf080b6bf11721215b148a9bf06fe68a637d1a7f1e84c489ed85623e |
Hashes for accera-1.2.29-cp37-cp37m-win_amd64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 8081535dc6a88d431f8c4f138cf91e52dc7d8bdb650f2dda15447f0ec5606b96 |
|
MD5 | ad64b85bb802042bea0fe07f6b51138a |
|
BLAKE2b-256 | 0f57c3183c87418578ae9af57ddd1456455d5c63213648b3f82576aed7e3b7dc |
Hashes for accera-1.2.29-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 34b13afc58f90196e5221d38c292bc786a0c9129738a6262eb476eb2b9eb90bb |
|
MD5 | 6963a7fc547e262b33d34a09c6a47a6f |
|
BLAKE2b-256 | f7ca24487544f9477159fee02e4cc52b189af30e17887b74cba842c13eb5543b |