以下数据处理任务是否适合GPU计算
Is the following data processing task suitable for GPU computing?
我希望升级我的显卡,以便能够并行处理以下任务。由于我没有GPU计算的经验,这个任务合适吗?在我购买之前,有可能估计处理的速度吗
我的项目是公共资助的,但预算有限,所以我需要做出正确的选择。
我有一个内部构建的相机芯片,可以以100fps的速度生成4x256x256图像。通过调用c函数来访问数据,并将指针传递给unsigned short类型的数组数据。我可以足够快地将数据读入内存缓冲区。目前,原始数据被保存到磁盘上,然后离线处理,但对于未来使用该相机的实验室实验,我希望在实验运行时访问从图像中获得的数据。我已经用c++编写了使用valarray的方法来计算导出的数据,但在我目前的硬件上,每帧大约40ms的速度太慢了。(我已经进行了优化实验,并将时间从>100ms大幅缩短)如果帧由S表示,则四个子帧(在时间上)是S1、S2、S3、S4。我必须计算以下图像和图像平均值,(S1+S2+S3+S4)/4,
Sqrt((S3-S1)^2+(S4-S2)^2),
arctan(S3-S1/S2-S4)
这似乎很适合由GPU执行操作。GPU比CPU更适合执行大量相对简单的计算。当"线程"之间存在逻辑或相互依存关系时,它们就没有那么高效了。尽管这种情况会进入"观点"领域,但我会尝试用一些数字来支持我的答案。
为了快速估计您所期望的性能,我制作了一个快速的HLSL像素着色器,它可以执行您建议的操作(未经测试-无法保证功能!):
Texture2D S[4] : register(t0);
SamplerState mySampler : register(s0);
struct PS_OUT
{
float4 average : SV_Target0;
float4 sqrt : SV_Target1;
float4 arctan : SV_Target2;
};
PS_OUT main(float2 UV: TEXCOORD0)
{
PS_OUT output;
float4 SSamples[4];
int i;
for (i = 0; i < 4; i++)
{
SSamples[i] = S[i].Sample(mySampler, UV);
}
float4 s3ms1 = SSamples[2] - SSamples[0];
float4 s4ms2 = SSamples[3] - SSamples[1];
output.average = (SSamples[0] + SSamples[1] + SSamples[2] + SSamples[3]) / 4.0;
output.sqrt = sqrt(s3ms1*s3ms1 + s4ms2*s4ms2);
output.arctan = atan(s3ms1 / s4ms2);
return output;
}
当编译这个(fxc /T ps_4_0 example.ps
)时,它给出了估计:大约使用了32个指令槽。
如果你每帧处理256x256(64k像素),那么在100fps的速度下,这大约是2.1米/帧,即210米/秒。查看GPU性能图表(例如,Nvidia:http://en.wikipedia.org/wiki/List_of_Nvidia_graphics_processing_units),他们所有超过Geforce 4(大约2005年)的GPU都有足够的速度来实现这一点。
请注意,这个着色器性能只是一个估计,列出的速率是理论上的最大值,我只考虑像素单位的工作(尽管它将完成大部分工作)。然而,对于任何足够新的视频卡,FLOPS都将远远超出您的需求,因此您应该能够在GPU上以100fps的速度轻松完成这项工作。假设你有一台比2005年更新的电脑,你可能已经有了足够强大的视频卡。
除了@MuertoExcobito已经写的内容外,您还必须考虑将数据复制到GPU和从GPU复制数据,但在您的情况下,这并不是太多数据。
我创建了一个简单的基于推力的实现,可以使用CUDA7编译和运行,如下所示:
nvcc -std=c++11 main.cu && ./a.out
在我的计算机上(Ubuntu 14.04 x64,IntelXeon@3.6Ghz、Geforce GTX 680)。
文件"helper_math.h"改编自CUDA SDK,可在以下位置找到:
https://gist.github.com/dachziegel/70e008dee7e3f0c18656
#include <thrust/device_vector.h>
#include <thrust/iterator/zip_iterator.h>
#include <thrust/transform.h>
#include <vector_types.h>
#include <iostream>
#include <chrono>
#include "helper_math.h"
template<typename T>
struct QuadVec
{
T S1, S2, S3, S4;
QuadVec(const int N) : S1(N), S2(N), S3(N), S4(N){}
};
template<typename T>
struct Result
{
T average, sqrt, arctan;
Result(const int N) : average(N), sqrt(N), arctan(N){}
};
typedef thrust::tuple<float4,float4,float4,float4> QuadInput;
typedef thrust::tuple<float4,float4,float4> TripleOutput;
struct CalcResult : public thrust::unary_function<QuadInput,TripleOutput>
{
__host__ __device__
TripleOutput operator()(const QuadInput& f) const
{
const float4 s3ms1 = thrust::get<2>(f) - thrust::get<0>(f);
const float4 s4ms2 = thrust::get<3>(f) - thrust::get<1>(f);
const float4 sqrtArg = s3ms1*s3ms1 + s4ms2*s4ms2;
const float4 atanArg = s3ms1 / s4ms2;
return thrust::make_tuple((thrust::get<0>(f) + thrust::get<1>(f) + thrust::get<2>(f) + thrust::get<3>(f)) / 4.0f,
make_float4(sqrtf(sqrtArg.x), sqrtf(sqrtArg.y), sqrtf(sqrtArg.z), sqrtf(sqrtArg.w)),
make_float4(atanf(atanArg.x), atanf(atanArg.y), atanf(atanArg.z), atanf(atanArg.w))
);
}
};
int main()
{
typedef thrust::host_vector<float4> HostVec;
typedef thrust::device_vector<float4> DevVec;
const int N = 256;
QuadVec<HostVec> hostFrame(N*N);
QuadVec<DevVec> devFrame(N*N);
Result<HostVec> hostResult(N*N);
Result<DevVec> devResult(N*N);
const int runs = 10000;
int accumulatedDuration = 0;
for (int i = 0; i < runs; ++i)
{
auto start = std::chrono::system_clock::now();
thrust::copy(hostFrame.S1.begin(), hostFrame.S1.end(), devFrame.S1.begin());
thrust::copy(hostFrame.S2.begin(), hostFrame.S2.end(), devFrame.S2.begin());
thrust::copy(hostFrame.S3.begin(), hostFrame.S3.end(), devFrame.S3.begin());
thrust::copy(hostFrame.S4.begin(), hostFrame.S4.end(), devFrame.S4.begin());
thrust::transform(thrust::make_zip_iterator(make_tuple(devFrame.S1.begin(), devFrame.S2.begin(), devFrame.S3.begin(), devFrame.S4.begin())),
thrust::make_zip_iterator(make_tuple(devFrame.S1.end(), devFrame.S2.end(), devFrame.S3.end(), devFrame.S4.end())),
thrust::make_zip_iterator(make_tuple(devResult.average.begin(), devResult.sqrt.begin(), devResult.arctan.begin())),
CalcResult() );
thrust::copy(devResult.average.begin(), devResult.average.end(), hostResult.average.begin());
thrust::copy(devResult.sqrt.begin(), devResult.sqrt.end(), hostResult.sqrt.begin());
thrust::copy(devResult.arctan.begin(), devResult.arctan.end(), hostResult.arctan.begin());
auto duration = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now() - start);
accumulatedDuration += duration.count();
}
std::cout << accumulatedDuration/runs << std::endl;
return 0;
}
- 为什么"do while"循环不断退出,即使条件计算结果为 false?
- 递归函数计算序列中的平方和(并输出过程)
- 跨平台 GPU 计算
- 在 openGL 中,模型坐标应该在我的 CPU 上计算还是在 GPU 上使用 OpenGL 调用计算?
- 如何测量 GPU 上下文从计算切换到渲染着色器
- 在 GPU 上计算积分图像真的比在 CPU 上更快吗?
- 使用GPU计算矩阵
- 在我的CUDA运行时间计划中,CPU和GPU可以异步计算,但不能合作地计算
- 如何在MACOS上的C 计算中使用双AMD FirePro D300的GPU
- 计算gpu前缓冲区中像素的平均值,而无需将前缓冲区复制回系统内存
- gpu蒙皮的矩阵计算
- 以下数据处理任务是否适合GPU计算
- 让GPU做计算的简单方法
- 在 GPU 上计算欧几里得距离矩阵的平方
- 减少 GPU 和 CPU 之间的带宽(先发送原始数据或预先计算)
- DirectX 11 - 计算着色器,将数据从 GPU 复制到 CPU
- GPU上计算特征值和特征向量的性能较差
- 通过GPU计算并行程序的一部分的可能选项
- 什么是使应用程序具有CPU和GPU计算后端的最佳方法
- glsl (GPU)矩阵/矢量计算产生的结果与CPU不同