Skip to content

Commit cd7ab5b

Browse files
Library Interface Overhaul (#61)
* Start of new library interface * Don't always use arrow to avoid importing gobject * more testing * Tensor(T, S) implementation * better backend abstraction * more abstraction * CPU Backend nearly complete * OpenCL Backend with broadcasting * linear algebra and grad * Working through OpenCL Grad * Continue working through OpenCL grad * A lot more testing * Custom kernel is an abomination * NN Primitives * Complete OpenCL activation + reduction * Beginning NN layers * More gates and axis reductions for Tensor(T, OCL(T)) * Why is this not checked in anymore * Fixing NN * Fix tri iterator * Einsum work + various improvements * Test coverage for einsum * Einsum working with plenty of test coverage * Run reformatting on docstrings + start working with mkdocs * More docs * Update ignore to include certain doc files * More documentation * Working with last couple OpenCL NN related fns * OpenCL NN Work * Move kernels to singletons start * Actual singleton implementations for OCL methods * All OpenCL Kernels moved to singletons except custom * More Kernel work * Most kernels completed * Completely moved to OpenCL Singletons * I always do that with relu loss * Extending more functionality to OpenCL Backend * Finish documentation * Greater test coverage * Test build pipeline with mkdocs * Final commit for 1.0 * Numpy comparison * Re-enable branch check for docs
1 parent 3133fd3 commit cd7ab5b

File tree

200 files changed

+17574
-18191
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

200 files changed

+17574
-18191
lines changed

.github/workflows/crystal.yml

+4-4
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,18 @@ jobs:
88
runs-on: ubuntu-latest
99

1010
container:
11-
image: crystallang/crystal
11+
image: crystaldata/numci
1212

1313
steps:
1414
- uses: actions/checkout@v1
1515
- name: Install dependencies
1616
run: shards install --ignore-crystal-version
1717
- name: Run tests
18-
run: crystal spec
18+
run: crystal spec -v
1919
- name: Build docs
20-
run: crystal docs
20+
run: mkdocs build
2121
- uses: peaceiris/actions-gh-pages@v3
2222
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
2323
with:
2424
github_token: ${{ secrets.DOCS_TOKEN }}
25-
publish_dir: ./docs
25+
publish_dir: ./site

.gitignore

+6-11
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/lib/
2-
/docs/
32
/bin/
3+
/site/
44
/.shards/
55
*.dwarf
66
.DS_Store
@@ -10,13 +10,8 @@ debug.cr
1010
# Dependencies will be locked in applications that use them
1111
/shard.lock
1212

13-
# docs
14-
/_build
15-
/doc/_build
16-
17-
elementwise_arraymancer
18-
elementwise_num
19-
matmul_arraymancer
20-
matmul_num
21-
22-
*.o
13+
# Docs
14+
!docs
15+
docs/*
16+
!docs/gen_doc_stubs.py
17+
!docs/index.md

Makefile

-10
This file was deleted.

README.md

+42-18
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ They are:
4848
- LAPACK
4949
- OpenCL
5050
- ClBlast
51+
- NNPACK
5152

5253
While not at all required, they provide additional functionality than is
5354
provided by the basic library.
@@ -67,11 +68,11 @@ allocate a `Tensor` backed by either `CPU` or `GPU` based storage.
6768
```crystal
6869
[1, 2, 3].to_tensor
6970
Tensor.from_array [1, 2, 3]
70-
Tensor(UInt8).zeros([3, 3, 2])
71+
Tensor(UInt8, CPU(UInt8)).zeros([3, 3, 2])
7172
Tensor.random(0.0...1.0, [2, 2, 2])
7273
73-
ClTensor(Float32).zeros([3, 2, 2])
74-
ClTensor(Float64).full([3, 4, 5], 3.8)
74+
Tensor(Float32, OCL(Float32)).zeros([3, 2, 2])
75+
Tensor(Float64, OCL(Float64)).full([3, 4, 5], 3.8)
7576
```
7677

7778
### Operations
@@ -84,10 +85,7 @@ one or more `Tensor`s using sophisticated broadcasted mapping routines.
8485
a = [1, 2, 3, 4].to_tensor
8586
b = [[3, 4, 5, 6], [5, 6, 7, 8]].to_tensor
8687
87-
# Convert a Tensor to a GPU backed Tensor
88-
acl = a.astype(Float64).gpu
89-
90-
puts Num.add(a, b)
88+
puts a + b
9189
9290
# a is broadcast to b's shape
9391
# [[ 4, 6, 8, 10],
@@ -173,18 +171,44 @@ puts a.eigvals
173171
174172
# [-0.372281, 5.37228 ]
175173
176-
acl = a.opencl
177-
bcl = a.opencl
178-
179-
puts acl.gemm(bcl).cpu
174+
puts a.matmul(a)
180175
181176
# [[7 , 10],
182177
# [15, 22]]
178+
```
183179

184-
puts a.matmul(a)
180+
### Einstein Notation
185181

186-
# [[7 , 10],
187-
# [15, 22]]
182+
For representing certain complex contractions of `Tensor`s, Einstein notation
183+
can be used to simplify the operation. For example, the following matrix
184+
multiplication + summation operation:
185+
186+
```crystal
187+
a = Tensor.new([30, 40, 50]) { |i| i * 1_f32 }
188+
b = Tensor.new([40, 30, 20]) { |i| i * 1_f32 }
189+
190+
result = Float32Tensor.zeros([50, 20])
191+
ny, nx = result.shape
192+
b2 = b.swap_axes(0, 1)
193+
ny.times do |k|
194+
nx.times do |l|
195+
result[k, l] = (a[..., ..., k] * b2[..., ..., l]).sum
196+
end
197+
end
198+
```
199+
200+
Can instead be represented in Einstein notiation as the following:
201+
202+
```crystal
203+
Num::Einsum.einsum("ijk,jil->kl", a, b)
204+
```
205+
206+
This can lead to performance improvements due to optimized contractions
207+
on `Tensor`s.
208+
209+
```
210+
einsum 2.22k (450.41µs) (± 0.86%) 350kB/op fastest
211+
manual 117.52 ( 8.51ms) (± 0.98%) 5.66MB/op 18.89× slower
188212
```
189213

190214
### Machine Learning
@@ -194,10 +218,10 @@ mathematical functions. Use a `Num::Grad::Variable` with a `Num::Grad::Context`
194218
to easily compute these derivatives.
195219

196220
```crystal
197-
ctx = Num::Grad::Context(Tensor(Float64)).new
221+
ctx = Num::Grad::Context(Tensor(Float64, CPU(Float64))).new
198222
199-
x = ctx.variable([3.0])
200-
y = ctx.variable([2.0])
223+
x = ctx.variable([3.0].to_tensor)
224+
y = ctx.variable([2.0].to_tensor)
201225
202226
# f(x) = x ** y
203227
f = x ** y
@@ -214,7 +238,7 @@ interface to assist in creating neural networks. Designing and creating
214238
a network is simple using Crystal's block syntax.
215239

216240
```crystal
217-
ctx = Num::Grad::Context(Tensor(Float64)).new
241+
ctx = Num::Grad::Context(Tensor(Float64, CPU(Float64))).new
218242
219243
x_train = [[0.0, 0.0], [1.0, 0.0], [0.0, 1.0], [1.0, 1.0]].to_tensor
220244
y_train = [[0.0], [1.0], [1.0], [0.0]].to_tensor

ci/Dockerfile

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
FROM crystallang/crystal
2+
3+
RUN apt-get update && apt-get install \
4+
curl \
5+
libopenblas-dev \
6+
gnupg \
7+
clang \
8+
build-essential \
9+
git \
10+
python3 \
11+
python3-pip \
12+
-y
13+
14+
COPY requirements.txt requirements.txt
15+
RUN pip install -r requirements.txt

ci/requirements.txt

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
mkdocs==1.2.3
2+
mkdocs-autorefs==0.3.0
3+
mkdocs-gen-files==0.3.3
4+
mkdocs-literate-nav==0.4.0
5+
mkdocs-material==7.3.4
6+
mkdocs-material-extensions==1.0.3
7+
mkdocs-section-index==0.3.2
8+
mkdocstrings==0.16.2
9+
mkdocstrings-crystal==0.3.3

docs/gen_doc_stubs.py

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Generate virtual doc files for the mkdocs site.
2+
# You can also run this script directly to actually write out those files, as a preview.
3+
4+
import mkdocs_gen_files
5+
6+
# Get the documentation root object
7+
root = mkdocs_gen_files.config["plugins"]["mkdocstrings"].get_handler("crystal").collector.root
8+
9+
# For each type (e.g. "Foo::Bar")
10+
for typ in root.walk_types():
11+
# Use the file name "Foo/Bar/index.md"
12+
filename = "/".join(typ.abs_id.split("::") + ["index.md"])
13+
# Make a file with the content "# ::: Foo::Bar\n"
14+
with mkdocs_gen_files.open(filename, "w") as f:
15+
print(f"# ::: {typ.abs_id}", file=f)
16+
17+
# Link to the type itself when clicking the "edit" button on the page.
18+
if typ.locations:
19+
mkdocs_gen_files.set_edit_path(filename, typ.locations[0].url)

0 commit comments

Comments
 (0)