From 332aca1841a3f93391e43822718f479c26aa5e32 Mon Sep 17 00:00:00 2001 From: Muchang Bahng Date: Tue, 7 Jan 2025 15:18:22 -0500 Subject: [PATCH 1/2] updated readme with proper model scripts --- README.md | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 70cd470..81761e5 100644 --- a/README.md +++ b/README.md @@ -108,10 +108,6 @@ print(f.grad) # [165] print(g.grad) # [1] ``` -Finally, we can visualize this using the `networkx` package. (Outdated gradients, but idea is still the same.) - -![Alt text](docs/img/computational_graph.png) - ## Data ### Datasets @@ -130,25 +126,27 @@ To perform linear regression, use the `LinearRegression` model. ``` import ember -ds = ember.datasets.LinearDataset(N=20, D=14) +ds = ember.datasets.LinearDataset(N=20, D=15) dl = ember.datasets.Dataloader(ds, batch_size=2) model = ember.models.LinearRegression(15) -mse = ember.objectives.MSELoss() +mse = ember.objectives.MSELoss() +optim = ember.optimizers.SGDOptimizer(model, 1e-4) -for epoch in range(500): +for epoch in range(1000): loss = None for x, y in dl: y_ = model.forward(x) loss = mse(y, y_) loss.backprop() - model.step(1e-5) - - print(loss) + optim.step() + + if epoch % 100 == 0: + print(loss) ``` ### K Nearest Neighbors -To do a simple K Nearest Neighbors regressor, use the following model. The forward method scans over the whole dataset, so we must input it to the model during instantiation. Note that we do not need a dataloader or a backpropagation method since we aren't iteratively updating gradients, though we want to show the loss. +To do a simple K Nearest Neighbors regressor, use the following model. The forward method scans over the whole dataset, so we must input it to the model during instantiation. Note that we do not need a dataloader or a backpropagation method since we aren't iteratively updating gradients, though we want to show the loss. We simply evaluate this model over the hyperparameter $K$. ``` import ember @@ -159,16 +157,15 @@ ds = LinearDataset(N=20, D=3) model = KNearestRegressor(dataset=ds, K=1) mse = ember.objectives.MSELoss() -for k in range(1, 21): # hyperparameter tuning +for k in range(1, 21): model.K = k - print(f"{k} ===") - loss = 0 + loss = ember.Tensor(0) for i in range(len(ds)): x, y = ds[i] y_ = model.forward(x) loss = loss + mse(y, y_) - print(loss) + print(f"{k} : {float(loss)}") # type: ignore ``` ### Multilayer Perceptrons @@ -177,10 +174,11 @@ To instantiate a MLP, just call it from models. In here we make a 2-layer MLP wi ``` import ember -ds = ember.datasets.LinearDataset(N=20, D=14) +ds = ember.datasets.LinearDataset(N=20, D=15) dl = ember.datasets.Dataloader(ds, batch_size=2) model = ember.models.MultiLayerPerceptron(15, 10) mse = ember.objectives.MSELoss() +optim = ember.optimizers.SGDOptimizer(model, 1e-5) for epoch in range(500): loss = None @@ -188,9 +186,10 @@ for epoch in range(500): y_ = model.forward(x) loss = mse(y, y_) loss.backprop() - model.step(1e-5) + optim.step() - print(loss) + if epoch % 25 == 0: + print(loss) ``` ## Objectives From 5e1e7ae0b8c42021424558b7a9450dcc6fe0788f Mon Sep 17 00:00:00 2001 From: Muchang Bahng Date: Tue, 7 Jan 2025 15:18:37 -0500 Subject: [PATCH 2/2] moved all docs to separate wiki repo --- docs/img/computational_graph.png | Bin 112414 -> 0 bytes docs/installation.md | 73 ---------- docs/progress.md | 136 ------------------ docs/structure.md | 38 ----- docs/tensors.md | 234 ------------------------------- 5 files changed, 481 deletions(-) delete mode 100644 docs/img/computational_graph.png delete mode 100644 docs/installation.md delete mode 100644 docs/progress.md delete mode 100644 docs/structure.md delete mode 100644 docs/tensors.md diff --git a/docs/img/computational_graph.png b/docs/img/computational_graph.png deleted file mode 100644 index ab8e271534ff31d5dfede98874f3d3967c298d3e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 112414 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
vB;A1K_E)i%eJZOeqGs=@jpqFR|#r( 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

kgQim|{x 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

+p-@A48rB2IOu*`;3J_+j36BvCj-XW6*#5k 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 diff --git a/docs/installation.md b/docs/installation.md deleted file mode 100644 index 2cc6782..0000000 --- a/docs/installation.md +++ /dev/null @@ -1,73 +0,0 @@ -# Installation - -## System Support - -This library supports both x86_64/amd64 and arm64/aarch64. Check if your system is supported out of the box in the table below. The library requires very few dependencies, so as long as your machine supports a C++ compiler and python, you should be able to get it working by fiddling with the CMake and setuptools files. - -| OS + Arch | Python | Latest Release Directly Tested | -|-|-|-| -|Ubuntu 24.04 AMD64 | Python 3.9+ || -|Ubuntu 22.04 AMD64 | Python 3.9+ || -|Ubuntu 20.04 AMD64 | Python 3.9+ || -|Ubuntu 24.04 ARM64 | TBD | | -|Ubuntu 22.04 ARM64 | TBD | | -|Ubuntu 20.04 ARM64 | TBD | | -|ArchLinux 6.6.68 LTS | Python 3.9+ || -|MacOS 15 ARM64 | Python 3.9+ || -|MacOS 14 ARM64 | Python 3.9+ | v0.0.16 | -|MacOS 13 ARM64 | Python 3.9+ || -|MacOS 12 ARM64 | Python 3.9+ || -|MacOS 11 ARM64 | Python 3.9+ || -|Windows 11 | Python 3.9+ | v0.0.17 | -|Windows 10 | Python 3.9+ || -|Debian 13 | Python 3.9+ || -|Debian 12 | Python 3.9+ || -|LinuxMint 22 | Python 3.9+ || -|LinuxMint 21 | Python 3.9+ || - -## Compiling the `aten` Library - -Your machine will need system dependencies such as CMake, a C++ compiler, and pybind11. The library uses C++17. Preferably you will have git and conda installed already. For more specific instructions on installing these on your system, refer to the more detailed installation guide. - -Git clone the repo, then pip install, which will run `setup.py`. - -``` -git clone git@github.com:mbahng/pyember.git -cd pyember -pip install . -``` - -This runs `cmake` on `aten/CMakeLists.txt`, which calls the following. -1. It always calls `aten/src/CMakeLists.txt` that compiles and links the source files in the C++ tensor library. -2. If `BUILD_PYTHON_BINDINGS=ON` (always on by default), it further calls `aten/bindings/CMakeLists.txt` to further generate a `.so` file that can be imported into `ember`. -3. If `BUILD_DEV=ON`, it calls `aten/test/CMakeLists.txt` to further compile the C++ unit testing suite. - -If there are problems with building, you should check, in order, -1. Whether `build/` has been created. This is the first step in `setup.py` -2. Whether the compiled `main.cpp` and, if `BUILD_DEV=ON`, the C++ unit test files have been compiled, i.e. if `build/src/main` and `build/test/tests` executables exist. -3. Whether `build/*/aten.cpython-3**-darwin.so` exists (somewhere in the build directory, depending on the machine). The Makefile generated by `aten/bindings/CMakeLists.txt` will produce `build/*/aten.cpython-3**-darwin.so`. -4. The `setup()` function will immediately copy this `.so` file to `ember/aten.cpython-3**-darwin.so`. You should see a success message saying that it has been moved or an error. The `.so` file must live within `ember`, the actual library, since `ember/__init__.py` must access it within the same directory level. - -## Testing and Development - -The pip install comes with two more environment variable parameters. Note that the following command is whitespace-sensitive. -``` -CMAKE_DEBUG=1 CMAKE_DEV=1 pip install . -``` -1. Setting `CMAKE_DEBUG=1` compiles the `aten` library with debug mode (`-g`) on, which I use when using gdb/lldb on the compiled code. -2. Setting `CMAKE_DEV=1` compiles the C++ testing suite as well. If you want to do this, you will also need to install google-tests. A code snippet for Ubuntu and Debian is shown below. -``` -sudo apt-get install libgtest-dev -cd /usr/src/gtest -cmake CMakeLists.txt -make -cp lib/*.a /usr/lib -rm -rf /var/lib/apt/lists/* -``` - -If you would like to run tests and/or develop the package yourself, you can run the script `./run_tests.sh all` (args `python` to run just python tests and `cpp` to run just C++ tests), which will -1. Run all C++ unit tests for `aten`, ensuring that all functions work correctly. -2. Run all Python unit tests for `ember`, ensuring that additional functions work correctly and that the C++ functions are bound correctly. - -The stub (`.pyi`) files for `aten` are located in `ember/aten`. - diff --git a/docs/progress.md b/docs/progress.md deleted file mode 100644 index 79c2f72..0000000 --- a/docs/progress.md +++ /dev/null @@ -1,136 +0,0 @@ -# Progress - - To do: - 1. Add a template argument for Tensor dtype. - 2. Store all tensors in heap to preserve them after stack is destroyed. - - ✅ - Done - ❌ - Not implemented - 🪧 - Don't need, either should not be accessed or is not necessary (e.g. due to inheritance) - 🚧 - In progress - - ## Aten BaseTensor - - | C++ Method | PyBind Method | Status | C++ Tests | Python Tests | Stubs | - |----------------------------------------------------------------------|----------------------|--------|-----------|--------------|--------| - | `std::string type() const` | `type()` | ✅ | 🪧 | 🪧 | ✅ | - | `std::string dtype() const` | `dtype()` | ✅ | 🪧 | 🪧 | ✅ | - | `bool operator==(BaseTensor&)` | `__eq__()` | ✅ | 🪧 | 🪧 | ✅ | - | `bool operator!=(BaseTensor&)` | `__ne__()` | ✅ | 🪧 | 🪧 | ✅ | - | `double at(const std::vector&) const` | `__getitem__()` | ✅ | 🪧 | 🪧 | ✅ | - | `double at(const std::vector&)` | `__setitem__()` | ✅ | 🪧 | 🪧 | ✅ | - | `std::unique_ptr slice(const std::vector&) const` | `__getitem__()` | ✅ | 🪧 | 🪧 | ✅ | - | `operator std::string() const` | `__str__()` | ✅ | 🪧 | 🪧 | ✅ | - | `operator std::string() const` | `__repr__()` | ✅ | 🪧 | 🪧 | ✅ | - | `BaseTensor& reshape(std::vector)` | `reshape(List[int])` | ✅ | 🪧 | 🪧 | ✅ | - - ## Aten GradTensor - - | C++ Method | PyBind Method | Status | C++ Tests | Python Tests | Stubs | - |----------------------------------------------------------------------|--------------------------------------------|--------|-----------|--------------|--------| - | `std::string type() const` | `type()` | ✅ | ✅ | ✅ | ✅ | - | `std::string dtype() const` | `dtype()` | ✅ | ✅ | ✅ | ✅ | - | `bool operator==(GradTensor&)` | `__eq__()` | ✅ | ✅ | ✅ | 🪧 | - | `bool operator!=(GradTensor&)` | `__ne__()` | ✅ | ✅ | ✅ | 🪧 | - | `double at(const std::vector&) const` | `__getitem__()` | ✅ | ✅ | ✅ | ✅ | - | `double at(const std::vector&)` | `__setitem__()` | ✅ | ✅ | ✅ | ✅ | - | `std::unique_ptr slice(const std::vector&) const` | `__getitem__()` | ✅ | ✅ | ✅ | ✅ | - | `BaseTensor::operator std::string() const` | `__str__()` | ✅ | ❌ | ✅ | ✅ | - | `BaseTensor::operator std::string() const` | `__repr__()` | ✅ | ❌ | ✅ | ✅ | - | `size_t pivot() const` | `pivot()` | ✅ | ✅ | ✅ | ✅ | - | `GradTensor()` | `GradTensor()` | ✅ | ✅ | ✅ | ✅ | - | `GradTensor(std::vector, std::vector, size_t)` | `GradTensor(List[double], List[int], int)` | ✅ | ✅ | ✅ | ✅ | - | `GradTensor(std::vector, size_t)` | `GradTensor(List[int], int)` | ✅ | ✅ | ✅ | ✅ | - | `GradTensor::eye(size_t, size_t)` | | ✅ | ✅ | ✅ | ✅ | - | `transpose()` | `transpose()` | ✅ | ✅ | ✅ | ✅ | - | `GradTensor copy() const` | `copy()` | ✅ | ✅ | ✅ | ✅ | - | | `__neg__()` | ✅ | 🪧 | ✅ | ✅ | - | `Tensor add(Tensor&)` | `__add__(Tensor)` | ✅ | ✅ | ✅ | ✅ | - | | `__radd__(Tensor)` | ✅ | 🪧 | ✅ | | - | `GradTensor add(GradTensor&)` | `__add__(GradTensor)` | ✅ | ✅ | ✅ | ✅ | - | | `__radd__(GradTensor)` | ✅ | 🪧 | ✅ | | - | `GradTensor add(double&)` | `__add__(float)` | ✅ | ✅ | ✅ | ✅ | - | | `__radd__(float)` | ✅ | 🪧 | ✅ | | - | `Tensor sub(Tensor&)` | `__sub__(Tensor)` | ✅ | ✅ | ✅ | ✅ | - | | `__rsub__(Tensor)` | ✅ | 🪧 | ✅ | | - | `GradTensor sub(GradTensor&)` | `__sub__(GradTensor)` | ✅ | ✅ | ✅ | ✅ | - | | `__rsub__(GradTensor)` | ✅ | 🪧 | ✅ | | - | `GradTensor sub(double&)` | `__sub__(float)` | ✅ | ✅ | ✅ | ✅ | - | | `__rsub__(float)` | ✅ | 🪧 | ✅ | | - | `Tensor mul(Tensor&)` | `__mul__(Tensor)` | ✅ | ✅ | ✅ | ✅ | - | | `__rmul__(Tensor)` | ✅ | 🪧 | ✅ | | - | `GradTensor mul(GradTensor&)` | `__mul__(GradTensor)` | ✅ | ✅ | ✅ | ✅ | - | | `__rmul__(GradTensor)` | ✅ | 🪧 | ✅ | | - | `GradTensor mul(double&)` | `__mul__(float)` | ✅ | ✅ | ✅ | ✅ | - | | `__rmul__(float)` | ✅ | 🪧 | ✅ | | - | `GradTensor matmul(GradTensor&)` | `__matmul__(GradTensor)` | ✅ | ✅ | ✅ | ✅ | - - ## Aten Tensor - - | C++ Method | PyBind Method | Status | C++ Tests | Python Tests | Stubs | - |-------------------------------------------------------------------------|-----------------------------------------------|--------|-----------|--------------|--------| - | `std::string type() const` | `type()` | ✅ | ✅ | ✅ | ✅ | - | `std::string dtype() const` | `dtype()` | ✅ | ✅ | ✅ | ✅ | - | `bool operator==(Tensor&)` | `__eq__()` | ✅ | ✅ | ✅ | 🪧 | - | `bool operator!=(Tensor&)` | `__ne__()` | ✅ | ✅ | ✅ | 🪧 | - | `double at(const std::vector&) const` | `__getitem__()` | ✅ | ✅ | ✅ | ✅ | - | `double at(const std::vector&)` | `__setitem__()` | ✅ | ✅ | ✅ | ✅ | - | `std::unique_ptr slice(const std::vector&) const` | `__getitem__()` | ✅ | ✅ | ✅ | ✅ | - | `BaseTensor::operator std::string() const` | `__str__()` | ✅ | ✅ | ✅ | ✅ | - | `BaseTensor::operator std::string() const` | `__repr__()` | ✅ | ✅ | ✅ | ✅ | - | `Tensor(std::vector, std::vector)` | `Tensor(List[float], List[int])` | ✅ | ✅ | ✅ | ✅ | - | `Tensor(std::vector)` | `Tensor(List[float])` | ✅ | ✅ | ✅ | ✅ | - | `Tensor(std::vector>)` | `Tensor(List[List[float]])` | ✅ | ✅ | ✅ | ✅ | - | `Tensor(std::vector>>)` | `Tensor(List[List[List[float]]])` | ✅ | ✅ | ✅ | ✅ | - | `static Tensor arange(int, int, int)` | `Tensor.arange(int, int, int)` | ✅ | ✅ | ✅ | ✅ | - | `static Tensor linspace(double, double, int)` | `Tensor.linspace(float, float, int)` | ✅ | ✅ | ✅ | ✅ | - | `static Tensor gaussian(std::vector, double, double)` | `Tensor.gaussian(List[int], float, float)` | ✅ | ✅ | ✅ | ✅ | - | `static Tensor uniform(std::vector, double, double)` | `Tensor.uniform(List[int], int, int)` | ✅ | ✅ | ✅ | ✅ | - | `static Tensor ones(std::vector)` | `Tensor.ones(List[int])` | ✅ | ✅ | ✅ | ✅ | - | `static Tensor zeros(std::vector)` | `Tensor.zeros(List[int])` | ✅ | ✅ | ✅ | ✅ | - | `void build_topo(Tensor* v, std::set&, std::vector&)` | 🪧 | ✅ | ❌ | 🪧 | 🪧 | - | `prev_` | `prev` | ✅ | | | | - | `std::vector backprop(bool)` | `backprop(bool)` | ✅ | ✅ | ✅ | ✅ | - | `Tensor& reshape(std::vector)` | `reshape(List[int])` | ✅ | ✅ | ✅ | ✅ | - | `Tensor copy() const` | `copy()` | ✅ | ❌ | ✅ | ✅ | - | `Tensor neg()` | `__neg__()` | ✅ | 🪧 | ✅ | ✅ | - | `Tensor add(Tensor&)` | `__add__(Tensor)` | ✅ | ✅ | ✅ | ✅ | - | | `__radd__(Tensor)` | ✅ | 🪧 | ✅ | | - | `Tensor add(GradTensor&)` | `__add__(GradTensor)` | ✅ | ❌ | ✅ | ✅ | - | | `__radd__(GradTensor)` | ✅ | 🪧 | ✅ | | - | `Tensor add(double&)` | `__add__(float)` | ✅ | ❌ | ✅ | ✅ | - | | `__radd__(float)` | ✅ | 🪧 | ✅ | | - | `Tensor sub(Tensor&)` | `__sub__(Tensor)` | ✅ | ✅ | ✅ | ✅ | - | | `__rsub__(Tensor)` | ✅ | 🪧 | ✅ | | - | `Tensor sub(GradTensor&)` | `__sub__(GradTensor)` | ✅ | ❌ | ✅ | ✅ | - | | `__rsub__(GradTensor)` | ✅ | 🪧 | ✅ | | - | `Tensor sub(double&)` | `__sub__(float)` | ✅ | ❌ | ✅ | ✅ | - | | `__rsub__(float)` | ✅ | 🪧 | ✅ | | - | `Tensor mul(Tensor&)` | `__mul__(Tensor)` | ✅ | ❌ | ✅ | ✅ | - | | `__rmul__(Tensor)` | ✅ | 🪧 | ✅ | | - | `Tensor mul(GradTensor&)` | `__mul__(GradTensor)` | ✅ | ❌ | ✅ | ✅ | - | | `__rmul__(GradTensor)` | ✅ | 🪧 | ✅ | | - | `Tensor mul(double&)` | `__mul__(float)` | ✅ | ❌ | ✅ | ✅ | - | | `__rmul__(float)` | ✅ | 🪧 | ✅ | | - | `Tensor exp(double&)` | `__pow__(float)` | ❌ | ❌ | ❌ | ❌ | - | `Tensor exp(double&)` | `exp(float)` | ❌ | ❌ | ❌ | ❌ | - | `Tensor log(double&)` | `log(float)` | ❌ | ❌ | ❌ | ❌ | - | `Tensor matmul(Tensor&)` | `matmul(Tensor)` | ✅ | ❌ | ❌ | ✅ | - | `Tensor matmul(Tensor&)` | `__matmul__(Tensor)` | ✅ | ❌ | ✅ | ✅ | - | `Tensor tranpose(const std::vector&) const` | `transpose(List[int])` | ✅ | ❌ | ✅ | ✅ | - | `Tensor concat(Tensor&, size_t)` | `concat(Tensor)` | ❌ | ❌ | ❌ | ❌ | - | `Tensor sin()` | `sin()` | ❌ | ❌ | ❌ | ❌ | - | `Tensor cos()` | `cos()` | ❌ | ❌ | ❌ | ❌ | - | `Tensor tan()` | `tan()` | ❌ | ❌ | ❌ | ❌ | - | `Tensor arcsin()` | `arcsin()` | ❌ | ❌ | ❌ | ❌ | - | `Tensor arccos()` | `arccos()` | ❌ | ❌ | ❌ | ❌ | - | `Tensor arctan()` | `arctan()` | ❌ | ❌ | ❌ | ❌ | - | `Tensor relu()` | `relu()` | ❌ | ❌ | ❌ | ❌ | - | `Tensor sigmoid()` | `sigmoid()` | ❌ | ❌ | ❌ | ❌ | - | `Tensor leaky_relu()` | `leaky_relu()` | ❌ | ❌ | ❌ | ❌ | - | `Tensor sum()` | `sum()` | ❌ | ❌ | ❌ | ❌ | - | `Tensor mean()` | `mean()` | ❌ | ❌ | ❌ | ❌ | - | `Tensor norm()` | `norm()` | ❌ | ❌ | ❌ | ❌ | - - ## Models - diff --git a/docs/structure.md b/docs/structure.md deleted file mode 100644 index 597f96c..0000000 --- a/docs/structure.md +++ /dev/null @@ -1,38 +0,0 @@ -# Repository - -I've thought for a few weeks on how to structure this whole library, getting inspiration from the pytorch and tinygrad repositories. At a high level, the actual package repository is in `pyember/ember`, which uses functions pybinded from `pyember/aten` for fast computations. - -I tried to model a lot of the structure from Pytorch and TinyGrad. Very briefly, - -1. `aten/` contains the header and source files for the C++ low-level tensor library, such as basic operations and an autograd engine. - 1. `aten/src` contains all the source files and definitions. - 2. `aten/bindings` contains the pybindings. - 3. `aten/test` contains all the C++ testing modules for aten. -2. `ember/` contains the actual library, supporting high level models, objectives, optimizers, dataloaders, and samplers. - 1. `ember/aten` contains the stub files. - 2. `ember/datasets` contains all preprocessing tools, such as datasets/loaders, standardizing, cross validation checks. - 3. `ember/models` contains all machine learning models. - 4. `ember/objectives` contain all loss functions and regularizers. - 5. `ember/optimizers` contain all the optimizers/solvers, such as iterative (e.g. SGD), greedy (e.g. decision tree splitting), and one-shot (e.g. least-squares solution). - 6. `ember/samplers` contain all samplers (e.g. MCMC, SGLD). -3. `docs/` contains detailed documentation about each function. -4. `examples/` are example python scripts on training models. -5. `tests/` are python testing modules for the `ember` library. -6. `docker/` contains docker images of all the operating systems and architectures I tested ember on. General workflows on setting up the environment can be found there for supported machines. -7. `setup.py` allows you to pip install this as a package. -8. `run_tests.sh` which is the main test running script. - -For a more detailed explanation, look [here](docs/structure.md). - - -## ATen - - Aten, short for "a tensor" library (got the name from PyTorch), is a C++ library that provides low level functionality for Tensors. This includes the basic vector and matrix operations like addition, scalar/matrix multiplication, dot products, transpose, etc, which are used everywhere in model training and inference and must be fast. - -### Compiling and PyBinding - - Let's look at `aten/CMakeLists.txt` and `aten/binding/CMakeLists.txt`. - - - `aten/CMakeLists.txt` contains the instructions to generate a Makefile for compiling and linking the `aten` library. It has an optional argument `BUILD_PYTHON_BINDINGS` when set `ON`, will generate the `.so` file through `aten/binding/CMakeLists.txt`. The executables compiled with `aten/main.cpp` are compiled to `aten/build/main`. Same for the test files which are compiled to `aten/build/tests`. - - - `aten/binding/CMakeLists.txt` contains the instructions to generate the `.so` file and saves it to `pyember/ember/_C.cpython-312-darwin.so`. It must be contained within the Python package directory, since `ember`cannot access libraries outside of its base directory. diff --git a/docs/tensors.md b/docs/tensors.md deleted file mode 100644 index 050ecb9..0000000 --- a/docs/tensors.md +++ /dev/null @@ -1,234 +0,0 @@ -Tensors are $N$-dimensional arrays that are used to represent tabular data or model parameters. They are both derived from the `BaseTensor` abstract class, which support the very minimal functionalities that all tensors should have. - -The hierarchy is - - ``` - BaseTensor - Tensor - ScalarTensor (TBI) - DenseTensor (TBI) - SparseTensor (TBI) - GradTensor - ``` - -All the attributes and methods that are supported by all classes can be found in `aten/src/Tensor.h`. - -# BaseTensor - -### Attributes - -`std::vector storage_` -- A contiguous vector of doubles that store the state of the tensor. - -`std::vector shape_` -- The shape of the tensor, where the product of the shape elements should match the length of `storage_`. - -### Methods - - -`virtual std::string type() const { return "BaseTensor"; }` -- outputs the string representing the instance of the class. -- It is a virtual function, which must be overwritten. The `const` indicates that it doesn't a - -`virtual std::string dtype() const { return "double"; }` -- outputs the type of the elements in the tensor -- not sure if this needs to be virtual - -`virtual ~BaseTensor() = default;` -- a destructor. Not sure if this is needed - -`const std::vector& shape() const { return shape_; }` -- getter function for the shape - -`const std::vector& data() const { return storage_; }` -- getter function for the data, or storage - -`BaseTensor& reshape(std::vector new_shape);` -- simply reshapes by changing the `shape` attribute and does nothing else. - -`virtual bool operator==(BaseTensor& other) const;` -- equality operator that minimally checks the attributes `storage_` and `shape_`. -- Is a virtual function since it must be overwritten by `GradTensor`s which have additional `pivot` attributes. - -`virtual bool operator!=(BaseTensor& other) const;` -- Just negation of equality operator (see above). - -`operator std::string() const;` -- Returns a string so we can actually print tensors. Prints the type, plus the `storage_` and `shape_` so that we can see array structure. - -`virtual double at(const std::vector& indices) const;` -- Similar to `__getitem__`, where you return a copy of an element by its index. - -`virtual double& at(const std::vector& indices);` -- Similar to `__setitem__`, where you return a reference to the element for modification. - - -`virtual std::unique_ptr slice(const std::vector& slices) const;` -- Used to get a slice of a `Tensor` with the strides stored in `BaseTensor::Slice` struct. -- Returns a copy, not a reference/view of the Tensor! - - ``` - struct Slice { - size_t start; - size_t stop; - size_t step; - - Slice(size_t start_ = 0, - size_t stop_ = std::numeric_limits::max(), - size_t step_ = 1) - : start(start_), stop(stop_), step(step_) {} - }; - ``` - -### Notes - -- I'm not sure whether to include strides as PyTorch does, as this is directly in the `shape`. This would certainly make viewing easier, but would require a lot of modification in the `std::string` function of `BaseTensor` to use the strides to push into a stringstream. - -- I've tried virtualizing the transpose function from `BaseTensor`, but I wanted it to return a reference for `GradTensor` while a copy for `Tensor`, so I made two separate implementations in both subclasses. - - -## GradTensors - -Gradient Tensor, or `GradTensor`s, are tensors that store the total derivative of an elementary operation (not precisely the gradient, but in $\mathbb{R}^n$ one can be transposed to get the other). These operations can have 1 or more arguments. It is represented as an $N$-tensor of size - -$$ - (D_1, D_2, \ldots, D_N) -$$ - -Let's look at a regular gradient of a function $f: \mathbb{R}^n \rightarrow \mathbb{R}^m$, which is a $m \times n$ matrix. However, if we have another function $g: \mathbb{R}^{n \times m} \rightarrow \mathbb{R}$, then this also is a matrix of shape $m \times n$. Clearly there is some ambiguity here, so we must store another attribute which I call the *pivot dimension*, that captures this information. Say that we have $f: \mathbb{R}^{\mathbf{n}} \rightarrow \mathbb{R}^{\mathbf{m}}$, where the superscripts are now vectors of length $d_n, d_m$. Then, the total derivative has shape -$$ - \mathbf{m} \times \mathbf{n} -$$ -with the pivot being $d_m + 1$, the first dimension index of the input. - -Essentially, we are approaching matrix multiplication in a more general way by [contracting tensors](https://en.wikipedia.org/wiki/Tensor_contraction). Note that by including this pivot parameter, we can support both batching and higher-dimensional multiplication. - -### Attributes - -`std::vector storage_` -- A contiguous vector of doubles that store the state of the tensor. - -`std::vector shape_` -- The shape of the tensor, where the product of the shape elements should match the length of `storage_`. - -`size_t pivot_` -- The pivot index that marks the start hyperdimension of the input. - -### Constructors - -`GradTensor();` -- Default constructor that is called when initializing a tensor without any gradients. Stores empty vectors and `pivot_ = 0`. - -`GradTensor(std::vector data, std::vector shape, size_t pivot);` -- Full constructor that sets all attributes. - -`GradTensor(std::vector shape, size_t pivot);` -- Initializes a GradTensor of shape shape and pivot but with all $0$ entries. - -`static GradTensor eye(size_t n, size_t pivot = 1);` -- Creates an identity matrix gradient, which is a good default initialization when calling `backprop()` on a tensor. - - -### Methods - -`std::string type() const override { return "GradTensor"; }` -- overrides type - -`size_t pivot() const { return pivot_; }` -- getter method for pivot index - -`bool operator==(GradTensor& other) const;` -- equality operator that also checks equality in pivot - -`bool operator!=(GradTensor& other) const;` -- negation of equality. - -`GradTensor copy() const;` -- returns a new GradTensor copy - -`GradTensor add(GradTensor& other);` -- For adding gradients together of the same shape and pivot. - -`Tensor add(Tensor& other);` -- For adding gradients to parameters for updating. - -`GradTensor sub(GradTensor& other);` -- For subtracting gradients together of the same shape and pivot. - -`Tensor sub(Tensor& other);` -- For subtracting gradients to parameters for updating. - -`GradTensor mul(GradTensor& other);` -- Elementwise multiplication, which doesn't really make sense to do at all but included. -`Tensor mul(Tensor& other); ` -- Elementwise multiplication, which doesn't really make sense to do at all but included. -`GradTensor matmul(GradTensor& other); ` -- Right matrix multiplication or tensor contraction, used for chain rule. - -`GradTensor& transpose(const std::vector& axes = {});` -- Modifies the gradient tensor in place and returns itself. -- It doesn't return a copy like in `Tensor` since I don't think it makes sense reuse the old one. If you must, you can just copy it and then transpose it. - -### Notes - -- The most natural operations on gradients/Jacobians are addition, subtraction, and multiplication (composition). Operations like taking the dot product or element-wise multiplication doesn't make sense, so I did not implement them on purpose. - -- Might need to check whether addition checks if pivots are the same. - -## Tensor - -Regular tensors, or `Tensor`s, store either tabular data or the state of a parameter. - -### Attributes - -`std::vector storage_` -- A contiguous vector of doubles that store the state of the tensor. - -`std::vector shape_` -- The shape of the tensor, where the product of the shape elements should match the length of `storage_`. - -`GradTensor grad = GradTensor();` -- the Jacobian (if being precise, rather than gradient) of some tensor further down the computation graph with respect to this tensor. - -`std::vector prev = std::vector();` -- previous nodes used to compute this tensor, if any - -`std::function backward;` -- function for filling in gradients of this tensor - -### Constructors - -`Tensor(std::vector data, std::vector shape);` -- The full constructor, which sets the storage and shape, whilst setting the gradients to null. - -`Tensor(std::vector data);` -- Constructor for 1D arrays. - -`Tensor(std::vector> data);` -- Constructor for 2D arrays. - -`Tensor(std::vector>> data);` -- Constructor for 3D arrays. - -`static Tensor arange(int start, int stop, int step = 1);` -- Arange constructor, returning a 1D array. - -`static Tensor linspace(double start, double stop, int numsteps);` -- Linspace constructor (like in numpy), returning a 1D array. - -`static Tensor gaussian(std::vector shape, double mean = 0.0, double stddev = 1.0);` -- Returns a Tensor of shape `shape` of Gaussian random variables. - -`static Tensor uniform(std::vector shape, double min = 0.0, double max = 1.0);` -- Returns a Tensor of shape `shape` of Uniform random variables. - -`static Tensor ones(std::vector shape);` -- Returns a Tensor of shape `shape` of all $1$. - -`static Tensor zeros(std::vector shape);` -- Returns a Tensor of shape `shape` of all $0$. - - -### Methods - -