Я видел еще один поток StackOverflow, рассказывающий о различных реализациях для вычисления евклидовой нормы, и у меня возникают проблемы с тем, почему/как работает конкретная реализация.
Код найден в реализации метрики MMD: https://github.com/josipd/torch-two-sample/blob/master/torch_two_sample/statistics_diff.py
Вот несколько исходных шаблонов:
import torch
sample_1, sample_2 = torch.ones((10,2)), torch.zeros((10,2))
Затем следующая часть - это то, где мы берем код выше. Я не уверен, что образцы объединяются вместе.
sample_12 = torch.cat((sample_1, sample_2), 0)
distances = pdist(sample_12, sample_12, norm=2)
и затем передаются в функцию pdist:
def pdist(sample_1, sample_2, norm=2, eps=1e-5):
r"""Compute the matrix of all squared pairwise distances.
Arguments
---------
sample_1 : torch.Tensor or Variable
The first sample, should be of shape ''(n_1, d)''.
sample_2 : torch.Tensor or Variable
The second sample, should be of shape ''(n_2, d)''.
norm : float
The l_p norm to be used.
Returns
-------
torch.Tensor or Variable
Matrix of shape (n_1, n_2). The [i, j]-th entry is equal to
''|| sample_1[i, :] - sample_2[j, :] ||_p''."""
здесь мы добираемся до мяса расчета
n_1, n_2 = sample_1.size(0), sample_2.size(0)
norm = float(norm)
if norm == 2.:
norms_1 = torch.sum(sample_1**2, dim=1, keepdim=True)
norms_2 = torch.sum(sample_2**2, dim=1, keepdim=True)
norms = (norms_1.expand(n_1, n_2) +
norms_2.transpose(0, 1).expand(n_1, n_2))
distances_squared = norms - 2 * sample_1.mm(sample_2.t())
return torch.sqrt(eps + torch.abs(distances_squared))
Я в недоумении, почему эвклидовы нормы будут рассчитаны таким образом. Любое понимание было бы весьма полезным
Пройдите через этот блок кода шаг за шагом. Определение евклидова расстояния, т.е. Норма Л2,
Рассмотрим простейший случай. У нас есть два образца,
Образец a
имеет два вектора [a00, a01]
и [a10, a11]
. То же самое для образца b
. Пусть сначала вычислим norm
n1, n2 = a.size(0), b.size(0) # here both n1 and n2 have the value 2
norm1 = torch.sum(a**2, dim=1)
norm2 = torch.sum(b**2, dim=1)
Теперь мы получаем
Затем у нас есть norms_1.expand(n_1, n_2)
и norms_2.transpose(0, 1).expand(n_1, n_2)
Заметим, что b
транспонируется. Сумма двух дает norm
sample_1.mm(sample_2.t())
, что умножение двух матриц.
Поэтому после операции
distances_squared = norms - 2 * sample_1.mm(sample_2.t())
ты получаешь
В конце концов, последний шаг принимает квадратный корень от каждого элемента в матрице.