A[..., idx[mask]]
I'd hate to have to express that in serial code and then pray a compiler could lift the correct vectorized version out of it.2,144 karma · joined February 9, 2021
http://github.com/bwasti
[all posted thoughts and comments are my own]
A[..., idx[mask]]
I'd hate to have to express that in serial code and then pray a compiler could lift the correct vectorized version out of it.I find that I am not typically writing complex "language-level" logic that would be expressible in any type of language and would benefit from the performance of compilation. I am guessing APIs and quickly testing ideas in totally unrelated colab notebooks. My productivity goes up when I can quickly answer questions like "how does this transpose impact the shape of the output" or "how do I find the mean of this tensor along only these dimensions."
Compiled languages, and especially Rust, really require you to go in with a plan. I find most of the machine learning code I write is inspired by rapidly playing with ideas.
https://developer.download.nvidia.com/assets/cuda/files/redu...
That'd be a very nice feature and I'm not sure it exists in other languages.
it's funny to see it written as "basic" dependent typing, considering it's an extremely complex type system to implement.
"By hard coding the forward and backward methods at comptime we have some more comfort with the general correctness and expected errors we would receive if we passed in incorrectly shaped data at runtime."
This solves the issues of shape checking incredibly cleanly. Python libraries have been struggling with this for a decade. It seems like you could also extending comptime usage to also calculate allocations ahead of time.
Honestly, this whole thing makes me want to invest quite a bit of time into using Zig. Great post!
oh cool! will this be numpy-like or will it have autograd as well? We're looking around for a web backend for shumai[1] and the former is really all we need :)
TinyML does result in much cheaper products, though.
Triton is used in a templated way for a very specific albeit pervasive hardware (PTX compatible GPUs), which is why it works so well. Here's some of the code: https://github.com/pytorch/pytorch/blob/a66625da3bcdf1e262dd...
Generalized kernel generation (i.e. synthesis of optimal performance from non-expert user defined kernels and novel hardware) would be fantastic to have, but it just doesn't seem particularly necessary in the field.
I used to think this. And I think, in theory, it is true. But the fact of the matter is, modern ML just doesn't use that many kernels. Every framework uses the same libraries (BLAS) and every library uses the same basic idea (maximally saturate FMA-like units).
Large language models are being run natively on commodity hardware with code written from scratch within days of their release (e.g. llama.cpp).
From a conceptual standpoint, it's really easy to saturate hardware in this domain. It's been pretty easy since 2014 when convolutions were interpreted as matrix multiplications. Sure, the actual implementations can be tricky, but a single engineer (trained in it) can get that done for a specific hardware in a couple months.
Of course, the interesting problem is how to generalize kernel generation. I spent years working with folks trying to do just that. But, in retrospect, the actual value add from a system that does all this for you is quite low. It's a realization I've been struggling to accept :'(
"Commodity linked securities are investment instruments or securities that are linked to one or more commodity prices. Unlike commodities, which provide no income to the owner, commodity linked securities usually give some payout to holders."[1]
[1] https://corporatefinanceinstitute.com/resources/commodities/...
async function time_tasks(count=100) {
async function nop_task() {
return performance.now();
}
const start = performance.now()
let tasks = Array(count).map(nop_task)
await Promise.all(tasks)
const elapsed = performance.now() - start
return elapsed / 1e3
}
for (let count = 100000; count < 1000000 + 1; count += 100000) {
const ct = await time_tasks(count)
console.log(`${count}: ${1 / (ct / count)} tasks/sec`)
}
Outputs (Python 3.11, Bun 0.5.1): % bun textual.ts
100000: 3767797.000743159 tasks/sec
200000: 9001406.4697609 tasks/sec
300000: 8281002.001242148 tasks/sec
400000: 10038491.340232708 tasks/sec
500000: 8976653.913474608 tasks/sec
600000: 10437550.828698047 tasks/sec
700000: 9443895.154523576 tasks/sec
800000: 11021991.118011119 tasks/sec
900000: 9790550.215324111 tasks/sec
1000000: 10263937.143648934 tasks/sec
% python3 textual.py
100,000 tasks 303,063 tasks per/s
200,000 tasks 270,058 tasks per/s
300,000 tasks 271,621 tasks per/s
400,000 tasks 261,945 tasks per/s
500,000 tasks 251,070 tasks per/s
600,000 tasks 272,520 tasks per/s
700,000 tasks 250,977 tasks per/s
800,000 tasks 253,131 tasks per/s
900,000 tasks 244,696 tasks per/s
1,000,000 tasks 266,061 tasks per/s