给定一个std::vector<Eigen::Triplet<double>>
,它可以使用setFromTriplets
函数创建一个Eigen::SparseMatrix<double>
。默认情况下,此函数累加重复的三重奏。
我正在尝试将我的模拟器代码移到CUDA,并且我必须构建我的稀疏矩阵。我有一个内核,它计算三胞胎并在三个设备指针(int*、int*、double*)中返回它们。但是,我不知道如何从这个指针中组装矩阵。cuSparse COO格式没有提到重复的三胞胎,它实际上说行应该排序。
如果有多个(i,j)条目的i、j和值指针,那么是否无论如何都要用CUDA/cuSparse创建COO (或者更好的是直接创建CSR )。
发布于 2022-12-04 16:04:04
下面的代码使用作为CUDA工具包一部分的推力库对GPU执行所需的操作。如果这个操作完成得足够频繁,以至于您关心如何获得最好的性能,那么您可以直接使用由Thrust使用的CUB库作为后端。这样,您应该能够避免多个不必要的复制操作。对此感兴趣的API将是cub::DeviceMergeSort
(可能还可以使用cub::DeviceRadixSort
和类型双关转换迭代器)和cub::DeviceSegmentedReduce
。
避免临时向量不必要初始化的一种方法可以在uninitialized_vector.cu
推力示例中找到。
另一种在不放弃推力的情况下可能提高性能的方法是使用thrust::cuda::par_nosync
执行策略。它还没有实现在CUDA工具包11.18版本的推力(1.15),所以你将需要一个更近期的版本(1.16或更高版本) 来自吉突布。这可以帮助隐藏内核启动开销,因为它使推力算法在可能的情况下是异步的(分段缩减必须是同步的,因为它返回新的结束迭代器)。您还可以向API中添加显式CUDA流和池内存资源,以更好地处理异步行为,并分别避免重复分配开销。有关更多信息,请参见cuda/explicit_cuda_stream.cu
、cuda/custom_temporary_allocation.cu
和mr_basic.cu
推力示例。
#include <thrust/device_ptr.h>
#include <thrust/device_vector.h>
#include <thrust/distance.h>
#include <thrust/iterator/zip_iterator.h>
#include <thrust/reduce.h>
#include <thrust/sort.h>
#include <thrust/tuple.h>
// Transforms triplets into COO sparse marix format in-place and
// returns the number of non-zero entries (nnz).
auto triplets2coo(int *d_rows,
int *d_cols,
float *d_vals,
int num_triplets) {
// thrust::device_ptr is a lightweight wrapper that lets Thrust algorithms
// know which memory the pointer points to. thrust::device_pointer_cast is
// the preferred way of creating them. While an API directly taking
// wrapped pointers as arguments would be preferable, I chose it this way
// to show how to wrap the pointers.
auto const coord_iter = thrust::make_zip_iterator(
thrust::make_tuple(
thrust::device_pointer_cast(d_rows),
thrust::device_pointer_cast(d_cols)
));
auto const vals = thrust::device_pointer_cast(d_vals);
// Sort in-place.
thrust::sort_by_key(coord_iter, coord_iter + num_triplets,
vals);
// Segmented reduction can only be done out-of-place,
// so allocate more memory.
thrust::device_vector<int> tmp_rows(num_triplets);
thrust::device_vector<int> tmp_cols(num_triplets);
thrust::device_vector<float> tmp_vals(num_triplets);
// Caution: These vectors are unnecessarily initialized to zero!
auto const tmp_coord_iter = thrust::make_zip_iterator(
thrust::make_tuple(
tmp_rows.begin(),
tmp_cols.begin()
));
auto const new_ends =
thrust::reduce_by_key(coord_iter, coord_iter + num_triplets,
vals,
tmp_coord_iter,
tmp_vals.begin());
auto const nnz = thrust::distance(tmp_vals.begin(), new_ends.second);
thrust::copy_n(tmp_coord_iter, nnz, coord_iter);
thrust::copy_n(tmp_vals.cbegin(), nnz, vals);
return nnz;
}
https://stackoverflow.com/questions/74349633
复制相似问题