Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generalize matrix multiply to support C = f.(A * B + x) #56

Open
Tracked by #70
chriselrod opened this issue Jan 21, 2021 · 5 comments
Open
Tracked by #70

Generalize matrix multiply to support C = f.(A * B + x) #56

chriselrod opened this issue Jan 21, 2021 · 5 comments
Labels
enhancement New feature or request

Comments

@chriselrod
Copy link
Collaborator

This is for the same of implementing dense layers for neural networks.

The reverse pass also needs
g.(Cbar) * B' and A' * g.(Cbar), but the fact that we have two instances of g.(Cbar) here means we should probably evaluate g just once per element of Cbar.

However, perhaps somewhat related to #40, we should add support for batching matrix operations of different sizes as well -- in particular, the reverse pass of

gCbar = g.(Cbar)
Abar = gCbar * B'
Bbar = A' * gCbar

should perhaps be evaluated with one function call that can minimize the (already low) threading and synchronization overhead.

Ideally, we'd have an API of doing this a little more generically, but it'd help for allocating threads to know that a lot of the array dimension here are the same.

@DilumAluthge DilumAluthge added the enhancement New feature or request label Jan 21, 2021
@DilumAluthge
Copy link
Member

I'm assuming that here g is the adjoint of f?

@chriselrod
Copy link
Collaborator Author

Yes, in the example if f === tanh then g(x) = x * muladd(-x, x, 1).

Although of course f and g would be arbitrary (so long as they're defined on numbers), it's just the primary use case and motivation would involve g = f'.

I think this is a compelling use case for Octavian. While performance is close to MKL at smallish sizes, I think we'd have a nice advantage over the current dense layer implementation which looks like this on the forward pass (x is the bias vector, normally called b):

C = A * B
@. C = f(C .+ x)

Note that the broadcast is single threaded. I imagine we could get a nice performance advantage at the sizes people would actually consider CPU-training over MKL, and definitely over the default OpenBLAS through this fusion and threading the entire operation.

@DilumAluthge
Copy link
Member

I think this is a compelling use case for Octavian. While performance is close to MKL at smallish sizes, I think we'd have a nice advantage over the current dense layer implementation which looks like this on the forward pass (x is the bias vector, normally called b):

C = A * B
@. C = f(C .+ x)

Note that the broadcast is single threaded. I imagine we could get a nice performance advantage at the sizes people would actually consider CPU-training over MKL, and definitely over the default OpenBLAS through this fusion and threading the entire operation.

This is really exciting!

@DilumAluthge
Copy link
Member

Note that the broadcast is single threaded.

Two questions:

  1. Can we vectorize the broadcast by using @avx?
  2. Would it make sense to try to multi-thread the broadcast?

@chriselrod
Copy link
Collaborator Author

chriselrod commented Jan 24, 2021

Yes and yes.

The goal would be to just launch threads once per pass (i.e., once for forward, and once for back).
This would reduce threading overhead, and also let us make sure locality is good / minimize how much data has to be move between cores.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants