• UID162
  • 注册2016-05-04
  • 登录2018-11-30
  • 粉丝7
  • 发帖46
  • 科研点数1点
优异服役勋章
OODLL 发布于2018-03-18 23:42
2/1470

[媒体技术]体验GPU计算带来的乐趣

楼层直达
首先,字没打错,是G P U,没打错,我要打的字就是 G P U
下面开始——GPU计算的简单实现我们知道,CPU一般用于处理数据。计算方面,它叫做ALU,也就是算术逻辑单元。

图片:gpu_cpu.jpg

而GPU因为常年去做图像处理,它自己也变得越来越适合浮点数计算了——成百上千个内核在同一时间一起计算。
就这样看来,GPU计算的速度一定很棒:大量数据一次性便计算完成了。
换句话说,比如我要执行下面的代码:
buff[0] *= 0.5;
buff[1] *= 0.5;
...
buff[10000000000000] *= 0.5;
想到怎么写了吗?或许你是这样做的:
int i = 10000000000001;
while(i--)
    buff[i - 1] *= 0.5;
那么假如没有 任何优化的话,CPU是不是就像这样执行的?
          步骤           执行内容
          1           buff[0] *= 0.5;
          2           buff[1] *= 0.5;
          ......           buff[..] *= 0.5;
          n           buff[n] *= 0.5;
需要很久,对吧?因为它是进行一次次的去乘,所以需要从第一个乘到最后。
那么仔细的观察可以看到,每一次它都是取乘以0.5。要是能一次性计算一大堆,比如一次性计算100个,那就好了。如此一来,一次性计算100的步骤就变成了
          步骤           执行内容
          1 buff[0 * 100 + 0]   *= 0.5;
 buff[0 * 100 + 1]   *= 0.5;
 .......
 buff[0 * 100 + 99] *= 0.5;
          2 buff[1 * 100 + 0]   *= 0.5;
 buff[0 * 100 + 1]   *= 0.5;
 ......
 buff[0 * 100 + 99] *= 0.5;
          ...... buff[.. * 100 + 0]   *= 0.5;
 buff[.. * 100 + 1]   *= 0.5;
 ......
 buff[.. * 100 + 99] *= 0.5;
          k = n / 100 buff[k * 100 + 0]   *= 0.5;
 buff[k * 100 + 1]   *= 0.5;
 .......
 buff[k * 100 + 99] *= 0.5;

这样一来,我最起码可以把原来计算一百次的时间压缩到执行一次的时间——很明显,运算的次数没变,但是花费的时间大大的减少了。这个就是并行计算。
早在CPU的Intel Pentium III出现时,就已经出现了一个很小的并行计算指令集——SSE,在更早的时候也有MMX指令集。这些指令集在现在的CPU上依然存在。在M$的VC++编译器中,很多运算可能就会被优化成SSE或者SSE2指令集来操作——更快、占用更低。
我们知道,GPU本身是用于图像处理的。举一个最简单的例子,我们在Windows上使用的Direct 3D这玩意,它就会把数据丢给GPU去运算。那么这个运算量有多大呢?我们不妨来想一下:一个像素点有4个数据:R,G,B,透明度(RGBA),那么一个屏幕是1920*1080,它计算的时候就需要1920*1080*4=8,294,400次运算,大约是2的23次方次。如此大的运算量,CPU做看起来会把桌面什么的fps刷到1帧。那么GPU又是怎么处理的呢?这个时候其实就和并行计算类似了——一次性处理一大堆,那么就可以降低运算花费的时间了。
说了这么些,估计你也想知道GPU这样有什么鸟用对吧?只能绘图看起来并无它用。但是随着时代的发展,GPU开始用于计算领域——矩阵乘法、二维离散傅里叶变换等。因为这些算法有一个共同的特点:计算量非常大,因而,它们被弄到GPU上尝试实现,结果也是显而易见的——它们的执行速度无一都不变得更快了。
那么,我们就来实现一下GPU计算

在这之前,先简单的介绍一下GPU编程可能会用到的语言。最为大家所知晓的应该是Nvidia的CUDA,非常强大,包含了各种各样的库,又因为是开发商给自己的硬件开发的玩意,所以效率也是出奇的高。但是缺点很明显,只能用在Nvidia的显卡上。第二个叫做OpenC,是业界第一个跨平台的异构编程框架,也是最通用的一个框架。作为一个开放的标准,OpenCL并不局限于某个特定的GPU厂商。最后,就是Visual Studio自己带的C++ AMP,它降低了程序的编写难度(其实看着还是头大的......),不过只有MS做了实现,基于DirectX。因为吧,我的电脑太不争气了,安装个CUDA告诉我C盘空间不足......所以只好去找C++ AMP的事情了。下面,我们就用C++ AMP来实现GPU计算。
MS很赞的送了介绍、参考等等。这都不是最重要的,最重要的是,它是中文的:[msdn]基于代码的 C++ AMP 简介
按照里面的内容,我们需要做三件事:
  1. 把数据提交到GPU,也就是array_view这个模板类
  2. 进行GPU计算,也就是用parallel_for_each
  3. 把数据弄回来
然后,开始实战:

#include <stdio.h>
#include <amp.h>
using namespace Concurrency;
double xin[1000] = { 0.0 };
int main()
{
    array_view<double, 1> doubleMul(1000, xin);
    parallel_for_each(doubleMul.extent, [=](index<1> idx) __GPU_ONLY
    {
        doubleMul[idx] += 5;
        doubleMul[idx] *= 10;
    });
    for (int i = 0; i < 1000; i++)
    {
        xin = static_cast<double>(doubleMul);
        if (xin != 50.0)
            printf("%lf\r\n", xin);
    }
    system("pause");
    return 0;
}
好了,GPU计算的实现就告一段落了。要是,有写的不足,的,地方,麻烦,指,出。
桂棹兮兰桨,击空明兮溯流光。渺渺兮予怀,望美人兮天一方。[url=http://www.arcll.cn/]我的个人网页[/url]欢迎您去看看(论坛不支持UBB???)声明:本人发帖,未注明转载的均为原创。转载务必保留来源
  • UID1801
  • 注册2017-12-20
  • 登录2018-11-07
  • 粉丝2
  • 发帖23
  • 科研点数0点
优异服役勋章
Harriet_Li 发布于2018-03-29 16:49
沙发F
如果只是单次的科学计算,可以尝试使用Matlab,可以使用GPU加速矩阵运算。
  • UID372
  • 注册2016-06-11
  • 登录2018-11-11
  • 粉丝15
  • 发帖83
  • 科研点数0点
优异服役勋章
科学狂人2046 发布于2018-03-31 00:43
板凳F
我差点以为你要和老黄抢饭吃
您需要登录后才可以回帖
发表回复

杩斿洖椤堕儴