<p dir="auto">Currently <a href="https://pytorch.org/docs/stable/nn.html?highlight=pairwise#torch.nn.functional.pairwise_distance" rel="nofollow">F.pairwise_distance</a> and <a href="https://pytorch.org/docs/stable/nn.html?highlight=pairwise#torch.nn.functional.cosine_similarity" rel="nofollow">F.cosine_similarity</a> accept two sets of vectors of the same size and compute similarity between corresponding vectors.</p>
<p dir="auto">However, it's often useful to compute pairwise similarities or distances between all points of the set (in mini-batch metric learning scenarios), or between all possible pairs of two sets (e.g. to build a bi-partite weighted graph). It's trivial to write ad-hoc functions like this, but I believe it's also a useful and a frequent primitive (for euclidean, square euclidean, etc).</p>
<p dir="auto">One way to introduce this would be modifying <code class="notranslate">pairwise_distance</code> to allow other shapes and an argument for metric type.</p>
<p dir="auto">Such a function for example exists in SciPy: <a href="https://docs.scipy.org/doc/scipy/reference/generated/scipy.spatial.distance.pdist.html" rel="nofollow">https://docs.scipy.org/doc/scipy/reference/generated/scipy.spatial.distance.pdist.html</a> (computes all pairwise distances within one set of vectors)</p>
<p dir="auto">Also exists in MatLab: <a href="https://www.mathworks.com/help/stats/pdist.html" rel="nofollow">https://www.mathworks.com/help/stats/pdist.html</a></p>
<p dir="auto">Steps to reproduce:</p>
<ol dir="auto">
<li>Build Caffe2 (e.g., with <code class="notranslate">python setup_caffe2.py develop</code>) at <a class="commit-link" data-hovercard-type="commit" data-hovercard-url="https://github.com/pytorch/pytorch/commit/def3715e82475902a4e25a7cd43866dc28bcf5a3/hovercard" href="https://github.com/pytorch/pytorch/commit/def3715e82475902a4e25a7cd43866dc28bcf5a3"><tt>def3715</tt></a></li>
<li>Apply <a class="commit-link" data-hovercard-type="commit" data-hovercard-url="https://github.com/pytorch/pytorch/commit/6a55238a3ff4ae3dfdfe5d87cf35d92fcd10bf2a/hovercard" href="https://github.com/pytorch/pytorch/commit/6a55238a3ff4ae3dfdfe5d87cf35d92fcd10bf2a"><tt>6a55238</tt></a> Grid sampler: nearest interpolation &amp; reflection padding (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="346022096" data-permission-text="Title is private" data-url="https://github.com/pytorch/pytorch/issues/10051" data-hovercard-type="pull_request" data-hovercard-url="/pytorch/pytorch/pull/10051/hovercard" href="https://github.com/pytorch/pytorch/pull/10051">#10051</a>) and rebuild</li>
</ol>
<p dir="auto">Actual result:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="./caffe2/contrib/aten/aten_op.h:8536:75: error: too few arguments to function ‘at::Tensor at::grid_sampler
(const at::Tensor&amp;, const at::Tensor&amp;, int64_t, int64_t)’
               auto the_result = at::grid_sampler(input, grid, padding_mode);
                                                                           ^
In file included from ../aten/src/ATen/ATen.h:13:0,
                 from ./caffe2/contrib/aten/aten_op.h:4,
                 from ../caffe2/contrib/aten/aten_op.cc:1:
aten/src/ATen/Functions.h:3589:22: note: declared here
 static inline Tensor grid_sampler(const Tensor &amp; input, const Tensor &amp; grid, int64_t interpolation_mode, 
int64_t padding_mode) {
                      ^
In file included from /usr/include/c++/4.8.2/memory:79:0,
                 from ../aten/src/ATen/Allocator.h:3,
                 from ../aten/src/ATen/ATen.h:4,
                 from ./caffe2/contrib/aten/aten_op.h:4,
                 from ../caffe2/contrib/aten/aten_op.cc:1:
/usr/include/c++/4.8.2/functional: In substitution of ‘template&lt;class _Res, class ... _ArgTypes&gt; template&lt;
class _Functor&gt; using _Invoke = decltype (std::__callable_functor(declval&lt;_Functor&amp;&gt;())((declval&lt;_ArgTypes
&gt;)()...)) [with _Functor = std::decay&lt;caffe2::ATenOp&lt;Context&gt;::ATenOp(const caffe2::OperatorDef&amp;, caffe2::
Workspace*) [with Context = caffe2::CPUContext]::__lambda660&gt;::type; _Res = bool; _ArgTypes = {}]’:
/usr/include/c++/4.8.2/functional:2334:2:   required by substitution of ‘template&lt;class _Functor&gt; std::fun
ction&lt;_Res(_ArgTypes ...)&gt;::_Requires&lt;std::__and_&lt;std::__not_&lt;std::is_same&lt;typename std::decay&lt;_Tp&gt;::type,
 std::function&lt;_Res(_ArgTypes ...)&gt; &gt; &gt;, std::__or_&lt;std::is_void&lt;_Tp&gt;, std::is_convertible&lt;std::function&lt;_
Res(_ArgTypes ...)&gt;::_Invoke&lt;typename std::decay&lt;_Tp&gt;::type&gt;, _Res&gt; &gt; &gt;, std::function&lt;_Res(_ArgTypes ...)
&gt;&amp;&gt; std::function&lt;_Res(_ArgTypes ...)&gt;::operator=(_Functor&amp;&amp;) [with _Functor = _Functor; _Res = bool; _Arg
Types = {}] [with _Functor = caffe2::ATenOp&lt;Context&gt;::ATenOp(const caffe2::OperatorDef&amp;, caffe2::Workspace
*) [with Context = caffe2::CPUContext]::__lambda660]’
./caffe2/contrib/aten/aten_op.h:8544:18:   required from ‘caffe2::ATenOp&lt;Context&gt;::ATenOp(const caffe2::Op
eratorDef&amp;, caffe2::Workspace*) [with Context = caffe2::CPUContext]’
../caffe2/core/registry.h:131:50:   required from ‘static ObjectPtrType caffe2::Registerer&lt;SrcType, Object
PtrType, Args&gt;::DefaultCreator(Args ...) [with DerivedType = caffe2::ATenOp&lt;caffe2::CPUContext&gt;; SrcType =
 std::basic_string&lt;char&gt;; ObjectPtrType = std::unique_ptr&lt;caffe2::OperatorBase&gt;; Args = {const caffe2::Ope
ratorDef&amp;, caffe2::Workspace*}]’
../caffe2/contrib/aten/aten_op.cc:6:1:   required from here
/usr/include/c++/4.8.2/functional:2181:71: error: use of ‘caffe2::ATenOp&lt;Context&gt;::ATenOp(const caffe2::Op
eratorDef&amp;, caffe2::Workspace*) [with Context = caffe2::CPUContext]::__lambda660’ before deduction of ‘aut
o’
  using _Invoke = decltype(__callable_functor(std::declval&lt;_Functor&amp;&gt;())
                                                                       ^
"><pre class="notranslate"><code class="notranslate">./caffe2/contrib/aten/aten_op.h:8536:75: error: too few arguments to function ‘at::Tensor at::grid_sampler
(const at::Tensor&amp;, const at::Tensor&amp;, int64_t, int64_t)’
               auto the_result = at::grid_sampler(input, grid, padding_mode);
                                                                           ^
In file included from ../aten/src/ATen/ATen.h:13:0,
                 from ./caffe2/contrib/aten/aten_op.h:4,
                 from ../caffe2/contrib/aten/aten_op.cc:1:
aten/src/ATen/Functions.h:3589:22: note: declared here
 static inline Tensor grid_sampler(const Tensor &amp; input, const Tensor &amp; grid, int64_t interpolation_mode, 
int64_t padding_mode) {
                      ^
In file included from /usr/include/c++/4.8.2/memory:79:0,
                 from ../aten/src/ATen/Allocator.h:3,
                 from ../aten/src/ATen/ATen.h:4,
                 from ./caffe2/contrib/aten/aten_op.h:4,
                 from ../caffe2/contrib/aten/aten_op.cc:1:
/usr/include/c++/4.8.2/functional: In substitution of ‘template&lt;class _Res, class ... _ArgTypes&gt; template&lt;
class _Functor&gt; using _Invoke = decltype (std::__callable_functor(declval&lt;_Functor&amp;&gt;())((declval&lt;_ArgTypes
&gt;)()...)) [with _Functor = std::decay&lt;caffe2::ATenOp&lt;Context&gt;::ATenOp(const caffe2::OperatorDef&amp;, caffe2::
Workspace*) [with Context = caffe2::CPUContext]::__lambda660&gt;::type; _Res = bool; _ArgTypes = {}]’:
/usr/include/c++/4.8.2/functional:2334:2:   required by substitution of ‘template&lt;class _Functor&gt; std::fun
ction&lt;_Res(_ArgTypes ...)&gt;::_Requires&lt;std::__and_&lt;std::__not_&lt;std::is_same&lt;typename std::decay&lt;_Tp&gt;::type,
 std::function&lt;_Res(_ArgTypes ...)&gt; &gt; &gt;, std::__or_&lt;std::is_void&lt;_Tp&gt;, std::is_convertible&lt;std::function&lt;_
Res(_ArgTypes ...)&gt;::_Invoke&lt;typename std::decay&lt;_Tp&gt;::type&gt;, _Res&gt; &gt; &gt;, std::function&lt;_Res(_ArgTypes ...)
&gt;&amp;&gt; std::function&lt;_Res(_ArgTypes ...)&gt;::operator=(_Functor&amp;&amp;) [with _Functor = _Functor; _Res = bool; _Arg
Types = {}] [with _Functor = caffe2::ATenOp&lt;Context&gt;::ATenOp(const caffe2::OperatorDef&amp;, caffe2::Workspace
*) [with Context = caffe2::CPUContext]::__lambda660]’
./caffe2/contrib/aten/aten_op.h:8544:18:   required from ‘caffe2::ATenOp&lt;Context&gt;::ATenOp(const caffe2::Op
eratorDef&amp;, caffe2::Workspace*) [with Context = caffe2::CPUContext]’
../caffe2/core/registry.h:131:50:   required from ‘static ObjectPtrType caffe2::Registerer&lt;SrcType, Object
PtrType, Args&gt;::DefaultCreator(Args ...) [with DerivedType = caffe2::ATenOp&lt;caffe2::CPUContext&gt;; SrcType =
 std::basic_string&lt;char&gt;; ObjectPtrType = std::unique_ptr&lt;caffe2::OperatorBase&gt;; Args = {const caffe2::Ope
ratorDef&amp;, caffe2::Workspace*}]’
../caffe2/contrib/aten/aten_op.cc:6:1:   required from here
/usr/include/c++/4.8.2/functional:2181:71: error: use of ‘caffe2::ATenOp&lt;Context&gt;::ATenOp(const caffe2::Op
eratorDef&amp;, caffe2::Workspace*) [with Context = caffe2::CPUContext]::__lambda660’ before deduction of ‘aut
o’
  using _Invoke = decltype(__callable_functor(std::declval&lt;_Functor&amp;&gt;())
                                                                       ^

</code></pre></div>