[QST] How to use norm ops with repmat?
Hi,
I'm just trying to implement a function to normalise a dataset along the rows
I'm running the below code:
template <typename T>
inline matx::tensor_t<T, 2> normaliseDatasetMatX(matx::tensor_t<T, 2> X) {
// Normalise along the rows
auto rowNorms_op = matx::vector_norm(X, {1}, matx::NormOrder::L2);
auto res = matx::make_tensor<float>({X.Shape()[0], X.Shape()[1]});
(res = X / matx::repmat(rowNorms_op, {1, X.Shape()[1]})).run();
return res;
}
With input:
float X_data[] = {
1.0f, 2.0f, 3.0f,
4.0f, 5.0f, 6.0f,
7.0f, 8.0f, 9.0f
}; // Row-major order
auto *X_d = GsDBSCAN::utils::copyHostToDevice(X_data, 3*3);
auto X = matx::make_tensor<float>(X_d, {3, 3});
auto XNorm = GsDBSCAN::projections::normaliseDatasetMatX(X);
And I'm getting the error:
/usr/local/include/matx/operators/repmat.h(186): error: no instance of constructor "matx::detail::RepMatOp<T1, DIM>::RepMatOp [with T1=matx::detail::NormOp<matx::tensor_t<float, 2, matx::basic_storage<matx::raw_pointer_buffer<float, matx::matx_allocator<float>>>, matx::tensor_desc_t<cuda::std::__4::array<matx::index_t, 2UL>, cuda::std::__4::array<matx::index_t, 2UL>, 2>>, matx::detail::NormTypeVector>, DIM=1]" matches the argument list
argument types are: (matx::detail::NormOp<matx::tensor_t<float, 2, matx::basic_storage<matx::raw_pointer_buffer<float, matx::matx_allocator<float>>>, matx::tensor_desc_t<cuda::std::__4::array<matx::index_t, 2UL>, cuda::std::__4::array<matx::index_t, 2UL>, 2>>, matx::detail::NormTypeVector>, cuda::std::__4::array<matx::index_t, 2UL>)
return detail::RepMatOp<T1, T1::Rank()>(t, detail::to_array(reps));
I was not sure if this was a template issue, or if I'm legit doing something wrong.
Thanks
Hi @HugoPhibbs, this code is invalid because rowNorms_op is a 1D operator, but the repmat call is passing in two values for the dimensions. Something like this should work:
auto rowNorms_op = matx::vector_norm(X, {1}, matx::NormOrder::L2);
auto rowNorms_op_2 = matx::clone(rowNorms_op, {1, matx::matxKeepDim});
auto res = matx::make_tensor<float>({X.Shape()[0], X.Shape()[1]});
(res = X / matx::repmat(rowNorms_op_2, {1, X.Shape()[1]})).run();
Hi @cliffburdick
I implemented what you wrote, but now I'm getting this error:
/usr/local/include/matx/operators/norm.h(89): error: no instance of overloaded function "cuda::std::get" matches the argument list
argument types are: (std::tuple<matx::detail::tensor_impl_t<float, 1, matx::tensor_desc_t<cuda::std::__4::array<long long, 1UL>, cuda::std::__4::array<long long, 1UL>, 1>>>)
norm_impl<NormType>(cuda::std::get<0>(out), a_, order_, ex);
^
I checked the docs and all and it seems that I'm calling vector_norm correctly
Hi @HugoPhibbs, have you updated to one of the latest commits? Specifically this one may fix it:
https://github.com/NVIDIA/MatX/commit/2186ba01c95ea90fab9890cfab2f3ba12dcec20a
Hi @cliffburdick
Yep pulled and rebuilt, but don't think it fixed it. Still getting the same error
@HugoPhibbs it looks to me like you are using repmat where clone would generally be used. Repmat is used for repeating a matrix across some number of dims. It does not increase the rank. If you want to increase the rank you should use the clone<newRank> operator.
@HugoPhibbs this might be closer to what you want if I'm understanding your intent:
auto rowNorms_op = matx::vector_norm(X, {1}, matx::NormOrder::L2);
auto rowNorms_op_2 = matx::clone<2>(rowNorms_op, {matx::matxKeepDim, X.Shape(1)});
auto res = matx::make_tensor<float>(X.Shape());
(res = X / rowNorms_op_2).run();
This will expand your norm result from a 1D back to the same shape as X. Then you can divide directly by it for an element-wise divide.