I have a theano symbolic matrix
x = T.fmatrix('input')
x
will be later on populated by n
vectors of dim d
(at train time).
I would like to have the theano equivalent of pdist
(scipy.spatial.distance.pdist
of pdist
), something like
D = theano.pdist( x )
How can I achieve this?
Calling scipy.spatial.distance.pdist
on x
directly does not work as x
at this stage is only symbolic...
Update: I would very much like to be able to mimic pdist
"compact" behavior: that is, computing only ~1/2 of the n
xn
entries of the distance matrix.
I haven't worked with Theano before, but here is a solution based on pure Numpy functions (perhaps you convert it to the equivalent theano functions. Note that I'm using automatic broadcasting in the expression below, so you might have to rewrite that explicitly if Theano doesn't support it):
It is based on the fact that:
||u-v||^2 = ||u||^2 + ||v||^2 - 2*u.v
. (I showed this in previous answers of mine using MATLAB)Here is a comparison against Scipy existing functions:
The difference should be negligible, close to machine epsilon (
np.spacing(1)
):HTH
EDIT:
Here is another implementation with a single loop:
Somewhat equivalent MATLAB code:
This returns the pairwise-distances in compact form (upper triangular part of the symmetric matrix). This is the same output as
pdist
. Usesquareform
to convert it to full matrix.I will leave it to you to see if it's possible to write the equivalent loop using Theano (see
theano.scan
)!pdist
from scipy is a collection of different functions - there doesn't exist a Theano equivalent for all of them at once. However, each specific distance, being a closed form mathematical expression, can be written down in Theano as such and then compiled.Take as a example the minkowski
p
norm distance (copy+pasteable):Note that
abs
calls the built-in__abs__
, soabs
is also a theano function. We can now compare this topdist
:This yields
As you can see, the correspondence is there, but the function
f_minkowski
is slightly more general, since it compares the lines of two possibly different arrays. If twice the same array is passed as input,f_minkowski
returns a matrix, whereaspdist
returns a list without redundancy. If this behaviour is desired, it can also be implemented fully dynamically, but I will stick to the general case here.One possibility of specialization should be noted though: In the case of
p=2
, the calculations become simpler through the binomial formula, and this can be used to save precious space in memory: Whereas the general Minkowski distance, as implemented above, creates a 3D array (due to avoidance of for-loops and summing cumulatively), which is prohibitive, depending on the dimensiond
(andnX, nY
), forp=2
we can writewhich only uses
O(nX * nY)
space instead ofO(nX * nY * d)
We check for correspondence, this time on the general problem:yielding