Mxnet-慢速阵列复制到GPU
mxnet
python
178
1

我的问题:我应该如何在mxnet中执行快速矩阵乘法?

我的具体问题:将阵列复制到GPU的速度很慢。该怎么办?

我创建随机数组,将它们复制到上下文中,然后相乘。

import mxnet as mx
import mxnet.ndarray as nd

from mxnet import profiler

profiler.set_config(aggregate_stats=True)

ctx = mx.cpu()

# create arrays on CPU
profiler.set_state('run')
a = nd.random.uniform(-1, 1, shape=(10000, 10000), ctx=mx.cpu())
b = nd.random.uniform(-1, 1, shape=(10000, 10000), ctx=mx.cpu())
nd.waitall()
profiler.set_state('stop')
print(profiler.dumps(reset=True))

# copy arrays to the context
profiler.set_state('run')
a_ctx = a.as_in_context(ctx)
b_ctx = b.as_in_context(ctx)
nd.waitall()
profiler.set_state('stop')
print(profiler.dumps(reset=True))

# multiply arrays
profiler.set_state('run')
c = nd.dot(a_ctx, b_ctx)
nd.waitall()
profiler.set_state('stop')
print(profiler.dumps(reset=True))

在这段代码中,我在cpu上执行了所有操作,所以我的时间是(秒):

 0.246
 ~=0
 1.727

当我使用ctx=mx.gpu() ,时间是

 0.247
22.059
 0.828

因此,瓶颈是从CPU到GPU的复制。这简直太慢了。该怎么办?

这是有关此阶段的准确信息:

Device Storage
=================
Name                          Total Count        Time (ms)    Min Time (ms)    Max Time (ms)    Avg Time (ms)
----                          -----------        ---------    -------------    -------------    -------------
Memory: gpu/0                           2      400000.0000      400000.0000      800000.0000      200000.0000

MXNET_C_API
=================
Name                          Total Count        Time (ms)    Min Time (ms)    Max Time (ms)    Avg Time (ms)
----                          -----------        ---------    -------------    -------------    -------------
MXImperativeInvokeEx                    2       22059.0703           0.0360       22059.0352       11029.5352
MXNDArrayGetShape                       2           0.0030           0.0000           0.0030           0.0015
MXNDArrayWaitAll                        1         105.9830         105.9830         105.9830         105.9830
MXNDArrayCreateEx                       2           0.0150           0.0060           0.0090           0.0075
MXNDArrayGetContext                     2           0.0020           0.0000           0.0020           0.0010
MXNet C API Concurrency                22           0.0000           0.0000           0.0010           0.0005
MXNDArrayGetDType                       2           0.0010           0.0000           0.0010           0.0005
MXNet C API Calls                      11           0.0140           0.0040           0.0140           0.0050

operator
=================
Name                          Total Count        Time (ms)    Min Time (ms)    Max Time (ms)    Avg Time (ms)
----                          -----------        ---------    -------------    -------------    -------------
CopyCPU2GPU                             4         318.4930          53.3060         105.9400          79.6233

请告诉我是否需要更多信息。

参考资料:
Stack Overflow
收藏
评论
共 1 个回答
高赞 时间 活跃

从分析结果中可以看到, CopyCPU2GPU仅花费318ms。 22秒的额外开销与GPU上下文初始化和malloc有关。如果仅在同一脚本中第二次运行GPU复制代码,则应该看到更快的结果。您可以这样修改代码:

# copy arrays to the context
a_ctx = a.as_in_context(ctx)
b_ctx = b.as_in_context(ctx)
nd.waitall()
profiler.set_state('run')
a_ctx = a.as_in_context(ctx)
b_ctx = b.as_in_context(ctx)
nd.waitall()
profiler.set_state('stop')
print(profiler.dumps(reset=True))

要考虑的另一件事是最小化CPU-> GPU内存副本。例如,在您的特定示例中,您可以在GPU而不是CPU中创建随机数组:

a = nd.random.uniform(-1, 1, shape=(10000, 10000), ctx=ctx)
b = nd.random.uniform(-1, 1, shape=(10000, 10000), ctx=ctx)

CUDA内存分配/取消分配需要一些系统同步,这使其运行缓慢。所有DL框架都将内存管理交到了他们自己的手中,但是创建了一个缓冲池,该缓冲池重用了先前分配的缓冲区,并且仅在绝对必要时才进行内存分配/释放。例如,默认情况下,tensorflow会以单个分配方式分配整个GPU内存,并在内部将其分配给张量。 MXNet和PyTorch在必要时进行分配,但在释放时保留在缓冲池中,以便以后可以重用。

MXNet / PyTorch的这种行为意味着,在第一次调用以创建特定大小的张量时,调用会变慢。但是,如果释放了该张量并创建了一个类似大小的新张量,则这次的内存来自预分配的缓冲池,而不是使用cudamalloc。您可以在此处阅读PyTorch的内存管理( https://pytorch.org/docs/stable/notes/cuda.html#cuda-memory-management ),它与MXNet有点相似。

收藏
评论
新手导航
  • 社区规范
  • 提出问题
  • 进行投票
  • 个人资料
  • 优化问题
  • 回答问题

关于我们

常见问题

内容许可

联系我们

@2020 AskGo
京ICP备20001863号