Rust_circuit is a library for expressing and manipulating tensor computations for neural network interpretability, written in Rust and used in Python notebooks. It includes support for causal scrubbing.
Linux and M1 Mac are supported - Windows has not been tested and probably does not work.
This repository is mainly intended for REMIX participants and former Redwood staff that want to continue using rust_circuit. Other people are welcome to try and use it, but it's likely to be a rough time especially if you don't know Rust.
If you're just getting started with mechanistic interpretability, Neel Nanda's TransformerLens may be a gentler introduction.
Note: the pip
version of rust_circuit
depends on Redwood's internal code, so you won't be able to use that directly - you have to build the Rust code in this repository from source.
rustup
from https://rustup.rs. Do the default installation.clang
: sudo apt install clang
conda create -n circ python=3.11 -y
conda activate circ
pip install -f https://download.pytorch.org/whl/torch_stable.html torch==1.13.1+cu116
pip install maturin[patchelf] attrs cattrs blake3 numpy msgpack websockets
maturin develop --features static-z3
import rust_circuit
.rustup
from https://rustup.rs. Do the default installation.conda create -n circ python=3.11 -y
conda activate circ
conda install pytorch -c pytorch
pip install maturin[patchelf] attrs cattrs blake3 numpy msgpack websockets
Homebrew
package manager from https://brew.sh/brew install z3
sudo ln -s /opt/homebrew/lib/libz3.dylib /usr/local/lib
)sudo ln -s /opt/homebrew/include/z3*.h /usr/local/include
)maturin develop --features extension-module
import rust_circuit
.The REMIX curriculum is open source and is the best way to learn about how to use this library. Participants spent about 6 days of full time work to learn the library; it is extremely powerful and full-featured but also not easy to use.
The next best thing is to learn the Rust language and just read the source code directly.
Unfortunately, many of the demo notebooks in python/rust_circuit/demos
and unit tests in python/tests
don't run without internal Redwood code.
do what this comment says/read issue more generally
If you see an error about not being able to find libpython
, you'll need to find it on your system and then add the containing folder to the LD_LIBRARY_PATH
environment variable. On my machine, it was in /home/ubuntu/miniconda3/envs/circ/lib/
. If you don't know where it is, try the find_libpython tool.
This can be caused by omitting the --features extension-module
flag when you build. In this case you might see a warning during build like "Warning: You're building a library without activating pyo3's extension-module
feature....
You can debug into Rust by running the Python interpreter under a debugger of your choice. For example, with LLDB: lldb -- /path/to/python -c "import rust_circuit"
Also, you can set the environment variable RUST_BACKTRACE=1 to see more information about errors.
The below is only useful if you're going to be modifying and frequently compiling Circuits.
Maturin spends a few seconds compressing your crate when you run maturin dev
or maturin build
. To turn this off, clone maturin locally and run cargo run -- build --release -b bin -o dist --features faster-tests
in maturin and then install the maturin wheel. (this should really be a runtime option not compile time flag!)
Also you can stop maturin from installing rust_circuit's deps by changing maturin source code. todo: publish maturin branch with compression and deps flags
If you do this, you can dynamically link against z3 and don't have to specify --features static-z3
.
Option 1: brew install z3
sudo ln -s /opt/homebrew/lib/libz3.dylib /usr/local/lib
)sudo ln -s /opt/homebrew/include/z3*.h /usr/local/include
)Option 2: Build z3
from source yourself
git clone https://github.com/Z3Prover/z3 && cd z3
)sudo cp build/libz3.dylib /usr/local/lib
)sudo cp src/api/z3*.h /usr/local/include
)Highly optimized linkers exist, and can speed up compile times by like 3 seconds. Either lld
(2nd fastest linker) or mold
(fastest linker) should mostly get link time down to being basically negligible.
Linkers can be configured with the env var RUSTFLAGS="-C link-arg=-fuse-ld=/PATH/TO/MY/LINKER"
.
You might need to add "rust-analyzer.checkOnSave.extraEnv": {"RUSTFLAGS": "-C link-arg=-fuse-ld=/PATH/TO/MY/LINKER"},
to vscode settings (Tao had to do this to make rust-analyzer work)
You can instead add this to your global cargo config at ~/.cargo/config
or ~/.cargo/config.toml
(This is what Ryan uses):
[target.x86_64-unknown-linux-gnu]
linker = "clang"
rustflags = ["-C", "link-arg=-fuse-ld=/PATH/TO/MY/LINKER"]
To use lld in particular, sudo apt install lld
and then configure using one
of the above approaches with /PATH/TO/MY/LINKER
replace with lld
(or the absolute path
to the binary).
The mold linker is maybe annoying to install on ubuntu, but I (Ryan) had no issues installing on Arch.
To benchmark code, write tests in benches/benches.rs
, add your new tests to criterion_group!
inside benches.rs
, then run cargo bench --no-default-features
.
Currently only simp is benchmarked.
To profile code, use
cargo bench --no-default-features --no-run; flamegraph -o flamegraph.svg -- target/release/deps/benches-36e0a557364e8efa --nocapture
or generally cargo bench --no-run then an executable profiler.
We filter Rust tracebacks shown to Python to get rid of lots of boilerplate, set the environment variable PYO3_NO_TRACEBACK_FILTER
to disable.