0.0.1 • Published 2 years ago

@shumai/shumai_cpu v0.0.1

Weekly downloads
-
License
-
Repository
-
Last release
2 years ago

Fast machine learning in JavaScript with bun + flashlight. ⚠️ This is experimental software! ⚠️

build Discord npm GitHub GitHub contributors

GitHub commit activity

Why build this?

Here are some of the areas that shumai hopes to tackle:

  • Creating datasets
    • JavaScript, with native typed arrays and a JIT compiler, is perfect for twiddling with data before it can be made into a big flat GPU-compatible array
  • Training small models
    • FFI bindings in Bun are crazy fast (~3ns), so JS gets out of the way when training small models
  • Advanced/fine-grained training/inference logic
    • Bun uses the JSC JIT compiler, meaning you can confidently write complex training logic without needing a native C++ implementation
  • Building applications
    • JavaScript has a large HUGE ecosystem, which makes application development a lot easier

Usage

shumai will always attempt to use an attached GPU or accelerator, so it should be quite fast. If it seems slow, please file an issue!

Standard array utilities:

import * as sm from "@shumai/shumai"

// create a 1024 by 1024 tensor, randomly filled with normal distribution
let X = sm.randn([1024, 1024])
let W = sm.identity(1024)
let Y = X.matmul(W)
console.log(Y.shape)

Conversion to and from JavaScript native arrays:

const data : Float32Array = new Float32Array(128)
for (let i = 0; i < 128; ++i) {
  data = Math.random()
}

const X : Tensor = sm.tensor(data)
const pi = sm.scalar(3.14)
const Y = X.mul(pi)

// tensors can be converted back to native JavaScript
const Y_data = Y.toFloat32Array()

// scalar tensors can be converted to JavaScript numbers
const total : number = X.sum().toFloat32()

Gradients:

const W = sm.randn([128, 128])
W.requires_grad = true

const X = sm.randn([128, 128])
const diff = X.sub(W)
const mse = diff.mul(diff).sum()
mse.backward()

W.grad // this gradient is now populated

// copy W without allowing gradient updates
const Y = W.detach()
Y.sum().backward() // nothing changes

Some more examples can be found here.

Supported operators can be found here.

Install

This is a current work in progress! If you have any problems building or installing, we would greatly appreciate filed issues.

Ensure you have bun installed (https://bun.sh).

On MacOS:

brew install arrayfire
bun install @shumai/shumai

On Linux (Ubuntu/Debian):

sudo apt install arrayfire-cuda3-cuda-11-6
bun install @shumai/shumai

Installing local build from source

Note: not required when developing the library locally

This process will require building the FFI for bun and then running npm pack to generate a @shumai/shumai_*.tgz package. You can then use npm install $PATH_TO_SOURCE/@shumai/shumai-*.tgz to install the package where you'd like.

MacOS from source

Install flashlight

mkdir -p $HOME/usr/ # installing flashlight here
brew install arrayfire
git clone --recursive --depth 1 https://github.com/bwasti/flashlight.git
cd flashlight
mkdir -p build
cd build
cmake .. -DFL_ARRAYFIRE_USE_CPU=ON -DFL_BUILD_DISTRIBUTED=OFF -DFL_USE_ONEDNN=OFF -DFL_BUILD_TESTS=OFF -DFL_BUILD_EXAMPLES=OFF -DFL_BUILD_SCRIPTS=OFF -DCMAKE_INSTALL_PREFIX=$HOME/usr/
make -j$(nproc)
make install

Build bindings for shumai

cd shumai
mkdir -p build
cd build
cmake .. -Dflashlight_DIR=$HOME/usr/share/flashlight/cmake/
make -j$(nproc)

(you can record perf stuff with xcrun xctrace record --template "Time Profiler" --launch $(which bun) train.js)

Linux from source

First, install flashlight.

Then, build bindings for shumai:

mkdir -p build && cd build
cmake .. \
    -DBUILD_SHARED_LIBS=ON \
    -DCMAKE_BUILD_TYPE=RelWithDebInfo \ # or as specified
    -Dflashlight_DIR=${FLASHLIGHT_INSTALL_PREFIX}/share/flashlight/cmake \
    -DArrayFire_DIR=${ARRAYFIRE_INSTALL_PREFIX}/share/ArrayFire/cmake
make -j$(nproc)

Contributing

If you'd like to make changes to the code, first build from source.

All files ending in *.inl or *_gen.ts are generated. These can be modified by editing scripts/gen_binding.py and running ./scripts/gen_all_binding.sh.

See the CONTRIBUTING file for style guidance and more info on how to help out. 😁

Supported operations

Some operations are supported as both static functions and methods on existing tensors.

OperationFunctionTensor Method (t : Tensor)
randrand(shape: number[]) : Tensor
randnrandn(shape: number[]) : Tensor
fullfull(shape: number[], val: number) : Tensor
identityidentity(dim: number) : Tensor
arangearange(start: number, end: number, step: number = 1) : Tensor
iotaiota(dims: number[], tileDims: number[] = [1]) : Tensor
reshapereshape(tensor: Tensor, shape: number[]) : Tensort.reshape(shape: number[]) : Tensor
transposetranspose(tensor: Tensor, axes: number[]) : Tensort.transpose(axes: number[]) : Tensor
tiletile(tensor: Tensor, shape: number[]) : Tensort.tile(shape: number[]) : Tensor
nonzerononzero(tensor: Tensor) : Tensort.nonzero() : Tensor
negativenegative(tensor: Tensor) : Tensort.negative() : Tensor
logicalNotlogicalNot(tensor: Tensor) : Tensort.logicalNot() : Tensor
expexp(tensor: Tensor) : Tensort.exp() : Tensor
loglog(tensor: Tensor) : Tensort.log() : Tensor
log1plog1p(tensor: Tensor) : Tensort.log1p() : Tensor
sinsin(tensor: Tensor) : Tensort.sin() : Tensor
coscos(tensor: Tensor) : Tensort.cos() : Tensor
sqrtsqrt(tensor: Tensor) : Tensort.sqrt() : Tensor
tanhtanh(tensor: Tensor) : Tensort.tanh() : Tensor
floorfloor(tensor: Tensor) : Tensort.floor() : Tensor
ceilceil(tensor: Tensor) : Tensort.ceil() : Tensor
rintrint(tensor: Tensor) : Tensort.rint() : Tensor
absoluteabsolute(tensor: Tensor) : Tensort.absolute() : Tensor
absabs(tensor: Tensor) : Tensort.abs() : Tensor
sigmoidsigmoid(tensor: Tensor) : Tensort.sigmoid() : Tensor
erferf(tensor: Tensor) : Tensort.erf() : Tensor
flipflip(tensor: Tensor, dim: number) : Tensort.flip(dim: number) : Tensor
clipclip(tensor: Tensor, low: Tensor, high: Tensor) : Tensort.clip(low: Tensor, high: Tensor) : Tensor
rollroll(tensor: Tensor, shift: number, axis: number) : Tensort.roll(shift: number, axis: number) : Tensor
isnanisnan(tensor: Tensor) : Tensort.isnan() : Tensor
isinfisinf(tensor: Tensor) : Tensort.isinf() : Tensor
signsign(tensor: Tensor) : Tensort.sign() : Tensor
triltril(tensor: Tensor) : Tensort.tril() : Tensor
triutriu(tensor: Tensor) : Tensort.triu() : Tensor
wherewhere(cond: Tensor, x: Tensor, y: Tensor) : Tensort.where(x: Tensor, y: Tensor) : Tensor
sortsort(tensor: Tensor, dim: number) : Tensort.sort(dim: number) : Tensor
addadd(tensor: Tensor, other: Tensor) : Tensort.add(other: Tensor) : Tensor
subsub(tensor: Tensor, other: Tensor) : Tensort.sub(other: Tensor) : Tensor
mulmul(tensor: Tensor, other: Tensor) : Tensort.mul(other: Tensor) : Tensor
divdiv(tensor: Tensor, other: Tensor) : Tensort.div(other: Tensor) : Tensor
eqeq(tensor: Tensor, other: Tensor) : Tensort.eq(other: Tensor) : Tensor
neqneq(tensor: Tensor, other: Tensor) : Tensort.neq(other: Tensor) : Tensor
lessThanlessThan(tensor: Tensor, other: Tensor) : Tensort.lessThan(other: Tensor) : Tensor
lessThanEquallessThanEqual(tensor: Tensor, other: Tensor) : Tensort.lessThanEqual(other: Tensor) : Tensor
greaterThangreaterThan(tensor: Tensor, other: Tensor) : Tensort.greaterThan(other: Tensor) : Tensor
greaterThanEqualgreaterThanEqual(tensor: Tensor, other: Tensor) : Tensort.greaterThanEqual(other: Tensor) : Tensor
logicalOrlogicalOr(tensor: Tensor, other: Tensor) : Tensort.logicalOr(other: Tensor) : Tensor
logicalAndlogicalAnd(tensor: Tensor, other: Tensor) : Tensort.logicalAnd(other: Tensor) : Tensor
modmod(tensor: Tensor, other: Tensor) : Tensort.mod(other: Tensor) : Tensor
bitwiseAndbitwiseAnd(tensor: Tensor, other: Tensor) : Tensort.bitwiseAnd(other: Tensor) : Tensor
bitwiseOrbitwiseOr(tensor: Tensor, other: Tensor) : Tensort.bitwiseOr(other: Tensor) : Tensor
bitwiseXorbitwiseXor(tensor: Tensor, other: Tensor) : Tensort.bitwiseXor(other: Tensor) : Tensor
lShiftlShift(tensor: Tensor, other: Tensor) : Tensort.lShift(other: Tensor) : Tensor
rShiftrShift(tensor: Tensor, other: Tensor) : Tensort.rShift(other: Tensor) : Tensor
minimumminimum(tensor: Tensor, other: Tensor) : Tensort.minimum(other: Tensor) : Tensor
maximummaximum(tensor: Tensor, other: Tensor) : Tensort.maximum(other: Tensor) : Tensor
powerpower(tensor: Tensor, other: Tensor) : Tensort.power(other: Tensor) : Tensor
matmulmatmul(tensor: Tensor, other: Tensor) : Tensort.matmul(other: Tensor) : Tensor
aminamin(tensor: Tensor, axes: number[] = [], keep_dims: boolean = false) : Tensort.amin(axes: number[] = [], keep_dims: boolean = false) : Tensor
amaxamax(tensor: Tensor, axes: number[] = [], keep_dims: boolean = false) : Tensort.amax(axes: number[] = [], keep_dims: boolean = false) : Tensor
argminargmin(tensor: Tensor, axis: number, keep_dims: boolean = false) : Tensort.argmin(axis: number, keep_dims: boolean = false) : Tensor
argmaxargmax(tensor: Tensor, axis: number, keep_dims: boolean = false) : Tensort.argmax(axis: number, keep_dims: boolean = false) : Tensor
sumsum(tensor: Tensor, axes: number[] = [], keep_dims: boolean = false) : Tensort.sum(axes: number[] = [], keep_dims: boolean = false) : Tensor
cumsumcumsum(tensor: Tensor, axis: number) : Tensort.cumsum(axis: number) : Tensor
meanmean(tensor: Tensor, axes: number[] = [], keep_dims: boolean = false) : Tensort.mean(axes: number[] = [], keep_dims: boolean = false) : Tensor
medianmedian(tensor: Tensor, axes: number[] = [], keep_dims: boolean = false) : Tensort.median(axes: number[] = [], keep_dims: boolean = false) : Tensor
varvar(tensor: Tensor, axes: number[] = [], bias: boolean = false, keep_dims: boolean = false) : Tensort.var(axes: number[] = [], bias: boolean = false, keep_dims: boolean = false) : Tensor
stdstd(tensor: Tensor, axes: number[] = [], keep_dims: boolean = false) : Tensort.std(axes: number[] = [], keep_dims: boolean = false) : Tensor
normnorm(tensor: Tensor, axes: number[] = [], p: number = 2, keep_dims: boolean = false) : Tensort.norm(axes: number[] = [], p: number = 2, keep_dims: boolean = false) : Tensor
countNonzerocountNonzero(tensor: Tensor, axes: number[] = [], keep_dims: boolean = false) : Tensort.countNonzero(axes: number[] = [], keep_dims: boolean = false) : Tensor
anyany(tensor: Tensor, axes: number[] = [], keep_dims: boolean = false) : Tensort.any(axes: number[] = [], keep_dims: boolean = false) : Tensor
allall(tensor: Tensor, axes: number[] = [], keep_dims: boolean = false) : Tensort.all(axes: number[] = [], keep_dims: boolean = false) : Tensor

License

shumai is MIT licensed, as found in the LICENSE file.