pdist для тензора аана

У меня есть анано-матричная матрица

x = T.fmatrix('input') 

x будет позже заполнен n векторами dim d (в поездах).

Я хотел бы иметь аналог pdist ( scipy.spatial.distance.pdist pdist ), что-то вроде

 D = theano.pdist( x ) 

Как я могу это достичь?

Вызов scipy.spatial.distance.pdist на x напрямую не работает, так как x на этом этапе является только символическим …

Обновление: мне очень хотелось бы подражать «компактному» поведению pdist то есть вычислять только ~ 1/2 из n x n записей матрицы расстояния.

2 Solutions collect form web for “pdist для тензора аана”

pdist from scipy – это набор различных функций – не существует эквивалента Theano для всех из них сразу. Однако каждое конкретное расстояние, являющееся математическим выражением замкнутой формы, может быть записано в Theano как таковое, а затем скомпилировано.

Возьмем, к примеру, норковую дистанцию ​​Минковски (копировать + вставляем):

 import theano import theano.tensor as T X = T.fmatrix('X') Y = T.fmatrix('Y') P = T.scalar('P') translation_vectors = X.reshape((X.shape[0], 1, -1)) - Y.reshape((1, Y.shape[0], -1)) minkowski_distances = (abs(translation_vectors) ** P).sum(2) ** (1. / P) f_minkowski = theano.function([X, Y, P], minkowski_distances) 

Обратите внимание, что abs вызывает встроенный __abs__ , поэтому abs также является функцией anano. Теперь мы можем сравнить это с pdist :

 import numpy as np from scipy.spatial.distance import pdist rng = np.random.RandomState(42) d = 20 # dimension nX = 10 nY = 30 x = rng.randn(nX, d).astype(np.float32) y = rng.randn(nY, d).astype(np.float32) ps = [1., 3., 2.] for p in ps: d_theano = f_minkowski(x, x, p)[np.triu_indices(nX, 1)] d_scipy = pdist(x, p=p, metric='minkowski') print "Testing p=%1.2f, discrepancy %1.3e" % (p, np.sqrt(((d_theano - d_scipy) ** 2).sum())) 

Это дает

 Testing p=1.00, discrepancy 1.322e-06 Testing p=3.00, discrepancy 4.277e-07 Testing p=2.00, discrepancy 4.789e-07 

Как вы можете видеть, соответствие существует, но функция f_minkowski несколько более общая, так как она сравнивает строки двух возможных разных массивов. Если в качестве входа f_minkowski дважды тот же массив, f_minkowski возвращает матрицу, тогда как pdist возвращает список без избыточности. Если это поведение желательно, оно также может быть реализовано полностью динамически, но я буду придерживаться общего случая.

Следует отметить еще одну возможность специализации: в случае p=2 вычисления упрощаются с помощью биномиальной формулы, и это можно использовать для сохранения драгоценного пространства в памяти: если общее расстояние Минковского, как было реализовано выше, создает 3D-массив (из-за избегания for-loops и суммирования кумулятивно), что является запретительным, в зависимости от размера dnX, nY ), для p=2 мы можем написать

 squared_euclidean_distances = (X ** 2).sum(1).reshape((X.shape[0], 1)) + (Y ** 2).sum(1).reshape((1, Y.shape[0])) - 2 * X.dot(YT) f_euclidean = theano.function([X, Y], T.sqrt(squared_euclidean_distances)) 

который использует O(nX * nY) пространство вместо O(nX * nY * d) Проверяем соответствие, на этот раз на общую задачу:

 d_eucl = f_euclidean(x, y) d_minkowski2 = f_minkowski(x, y, 2.) print "Comparing f_minkowski, p=2 and f_euclidean: l2-discrepancy %1.3e" % ((d_eucl - d_minkowski2) ** 2).sum() 

получая

 Comparing f_minkowski, p=2 and f_euclidean: l2-discrepancy 1.464e-11 

Я не работал с Theano раньше, но вот решение, основанное на чистых функциях Numpy (возможно, вы преобразуете его в эквивалентные функции anano. Обратите внимание, что я использую автоматическое вещание в приведенном ниже выражении, поэтому вам, возможно, придется переписать это явно, если Theano его не поддерживает):

 # X is an m-by-n matrix (rows are examples, columns are dimensions) # D is an m-by-m symmetric matrix of pairwise Euclidean distances a = np.sum(X**2, axis=1) D = np.sqrt((a + a[np.newaxis].T) - 2*np.dot(X, XT)) 

Он основан на том, что: ||uv||^2 = ||u||^2 + ||v||^2 - 2*uv . (Я показал это в предыдущих моих ответах, используя MATLAB)

Вот сравнение с существующими функциями Scipy:

 import numpy as np from scipy.spatial.distance import pdist, squareform def my_pdist(X): a = np.sum(X**2, axis=1) D = np.sqrt((a + a[np.newaxis].T) - 2*np.dot(X, XT)) return D def scipy_pdist(X): D = squareform(pdist(X, metric='euclidean')) return DX = np.random.rand(5, 3) D1 = my_pdist(X) D2 = scipy_pdist(X) 

Разница должна быть незначительной, близкой к машинной эпсилон ( np.spacing(1) ):

 >>> np.linalg.norm(D1-D2) 8.5368137554718277e-16 

НТН


РЕДАКТИРОВАТЬ:

Вот еще одна реализация с одним циклом:

 def my_pdist_compact(X): D = np.empty(shape=[0,0], dtype=X.dtype) for i in range(X.shape[0]-1): D = np.append(D, np.sqrt(np.sum((X[i,] - X[i+1:,])**2, axis=1))) return D 

Несколько эквивалентный код MATLAB:

 function D = my_pdist_compact(X) n = size(X,1); D = cell(n-1,1); for i=1:n-1 D{i} = sqrt(sum(bsxfun(@minus, X(i,:), X(i+1:end,:)).^2, 2)); end D = vertcat(D{:}); end 

Это возвращает парные расстояния в компактной форме (верхняя треугольная часть симметричной матрицы). Это тот же результат, что и pdist . Используйте squareform чтобы преобразовать его в полную матрицу.

 >>> d1 = my_pdist_compact(X) >>> d2 = pdist(X) # from scipy.spatial.distance >>> (d1 == d2).all() True 

Я оставлю его вам, чтобы увидеть, можно ли написать эквивалентный цикл с помощью Theano (см. theano.scan )!

  • Использование глубокого обучения для прогнозирования подпоследовательности из последовательности
  • Использование PYMC3 в Windows 10 - theano не может импортировать имя 'floatX'
  • Что такое тип данных для пакета глубокого обучения Python Keras?
  • Нужно ли нам использовать сглаживание и преобразование в Theano, если мы используем матрицу индексов?
  • Импорт keras.datasets не работает
  • Theano: Почему в этом случае ошибка индексации?
  • Работа с фрагментацией памяти графических процессоров в Theano
  • Как реализовать взвешенную двоичную кросс-энтропию на анано?
  • Python - лучший язык программирования в мире.