将二维vector类型的数据合并为一重指针传入cudaMemcpy()函数

本文探讨如何处理二维vector,其每行列数不一致的情况,以适应cudaMemcpy()函数。通过将每一行转化为指针并拼接,实现非标准N*M矩阵数据的传输。在转换过程中,需要注意内存大小的计算,以及数据类型与指针之间的转换。对于标准的n*m矩阵形式的二维vector,可以先转换为Mat类型再进行操作。
部署运行你感兴趣的模型镜像

若二维vector每行的列数不同,不是标准的N*M矩阵形式

cudaMemcpy()函数在传输数据时,参数需要为指针类型,因为实际数据的限制,初始数据是通过vector<vector<Vec4f>>的形式存储的,难点在于此二维vector每行的列数并不相同,并不是一个完美矩阵形式,在此记录一下自己的实现方式

首先说一下最终的实现方案:
首先将二维vector中的每行转换为指针,可见理解为每行一块小内存。然后通过函数memcpy()将每块小内存拼接在一起。

//将此二维vector转化为一维指针
vector<vector<Vec4f>> Match_Lines_L; 
//最后的结果指针
float* ans = new float[40000]; 

int newstride = 0;
for (int i = 0; i < Match_Lines_L.size(); i++)
{
	//所需copy的字节大小
	int copysize = 4 * Match_Lines_L[i].size() * sizeof(float);
	memcpy(ans + newstride, (Match_Lines_L[i]).data(), copysize);
	//更新ans中所需插入的位置
	newstride += 4 * Match_Lines_L[i].size();
}

1、使用vector.data()方法获取指向二维vector第 i 行第一个元素的指针
2、确定函数memcpy()所需传输的小内存size
3、通过for循环遍历每行数据,将小内存拼接到ans中
注意:copysize大小为字节大小,应sizeof(DataType),同时,因为本文数据类型为Vec4f类型,转换为指针类型后,原本的一个数据被扩充为4个float类型的数据,因此还需*4。同时newstride即ans中所需插入数据的位置,无需sizeof(float),具体可参考函数memcpy()的用法。

若二维vector为一个标准的n*m矩阵形式

则可通过构造Mat形式间接的先将二维vector转换为Mat类型,然后通过Mat.data获取头指针,作为参数传入cudaMemcpy()

	//此时的二维数组B为N*M的矩阵
	vector<vector<Vec4f>> B;
	Mat ANS = Mat::zeros(0, 4 * B[0].size(), CV_32FC1);
	for (int i = 0; i < B.size(); i++)
	{
		cv::Mat temp(1, 4 * B[0].size(), cv::DataType<float>::type, B[i].data());
		ANS.push_back(temp);
	}

您可能感兴趣的与本文相关的镜像

PyTorch 2.5

PyTorch 2.5

PyTorch
Cuda

PyTorch 是一个开源的 Python 机器学习库,基于 Torch 库,底层由 C++ 实现,应用于人工智能领域,如计算机视觉和自然语言处理

### 如何使用 `cudaMemcpy` 处理二维数组 在 CUDA 编程中,处理二维数组通常涉及内存对齐以及数据传输的方式。为了高效地管理 GPU 上的二维数组存储结构,可以利用 `cudaMallocPitch` 和 `cudaMemcpy2D` 函数来完成这些操作。 #### 使用 `cudaMallocPitch` 分配设备端内存 当分配二维数组时,推荐使用 `cudaMallocPitch` 来获取经过优化的行间距(pitch)。这种方式能够确保每一行的数据按照硬件友好的方式进行对齐,从而提升访存性能[^2]。 以下是通过 `cudaMallocPitch` 分配二维数组的一个示例: ```cpp size_t pitch; float* d_A; // 假设宽度为 width,高度为 height int width = 1024; // 列数 int height = 768; // 行数 // 调用 cudaMallocPitch 进行内存分配 cudaMallocPitch((void**)&d_A, &pitch, width * sizeof(float), height); ``` 在这里,变量 `pitch` 是实际分配给每行字节数,可能大于理论上的 `width * sizeof(float)`,这是由于硬件对齐需求所致。 #### 数据复制到设备上 一旦完成了设备端内存分配,就可以借助 `cudaMemcpy2D` 将主机中的二维数组拷贝至设备端。假设主机上有如下定义的二维数组: ```cpp float h_A[height][width]; for(int i=0;i<height;i++) { for(int j=0;j<width;j++) { h_A[i][j] = static_cast<float>(i+j); // 初始化一些值 } } ``` 接着调用 `cudaMemcpy2D` 完成从主机向设备的数据传递过程: ```cpp cudaMemcpy2D(d_A, pitch, h_A, width * sizeof(float), width * sizeof(float), height, cudaMemcpyHostToDevice); ``` 上述代码片段表明了如何将主机上的二维数组逐行传送到具有特定 pitch 的设备端缓冲区中去。 #### 设备端访问调整后的索引方法 需要注意的是,在设备端编程时,考虑到可能存在填充的情况,因此对于原始逻辑地址 `(rowIndex,colIndex)` 需要转换成为物理偏移量形式才能正确读写元素。具体做法如下所示[^3]: ```cpp __global__ void kernelExample(float* A, size_t pitch){ int colIdx = blockIdx.x * blockDim.x + threadIdx.x; int rowIdx = blockIdx.y * blockDim.y + threadIdx.y; if(colIdx < WIDTH && rowIdx < HEIGHT){ float element = *( (float*)((char*)A + rowIdx*pitch) + colIdx ); // 对element执行某些计算... } } ``` 这里的关键在于理解 `pitch` 实际代表的是以字节计的一整行长度,而不仅仅是以浮点型数量度量的结果。所以在定位某个具体的行列组合对应的数值前,先将其转化为字符指针再加回原基础类型指针即可实现精确寻址。 #### 总结说明 综上所述,采用 `cudaMallocPitch` 及其配套工具链能有效简化复杂形状张量的操作流程,并且兼顾底层架构特性带来的潜在优势。这不仅限于简单的二维情况扩展到更高维度同样适用[^1]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值