【问题标题】:Python theano with index computed inside the loop在循环内计算索引的 Python theano
【发布时间】:2015-07-10 09:36:05
【问题描述】:

我已经安装了 Theano 库来提高计算速度,这样我就可以使用 GPU 的强大功能。

但是,在计算的内部循环中,会根据循环索引和几个数组的相应值计算新索引。

该计算出的索引随后用于访问另一个数组的元素,该元素又用于另一个计算。

这是否太复杂以至于无法期望 Theano 有任何显着的加速?

所以让我重新表述我的问题,反过来。 这是 GPU 代码 sn-p 的示例。为简洁起见,省略了一些初始化。我可以在不显着增加计算时间的情况下将其转换为 Python/Theano 吗?

__global__ void SomeKernel(const cuComplex* __restrict__  data,
                                 float* __restrict__ voxels)

{

unsigned int idx = blockIdx.x * blockDim.x + threadIdx.x;

unsigned int idy = blockIdx.y * blockDim.y + threadIdx.y;

unsigned int pos = (idy * NX + idx);

unsigned int ind1 = pos * 3;
float x = voxels[ind1];
float y = voxels[ind1 + 1];
float z = voxels[ind1 + 2];

int m;

for (m = 0; m < M; ++m)
{
    unsigned int ind2 = 3 * m;

    float diff_x = x - some_pos[ind2];
    float diff_y = y - some_pos[ind2 + 1];
    float diff_z = z - some_pos[ind2 + 2];

    float distance = sqrtf(diff_x * diff_x
                         + diff_y * diff_y
                         + diff_z * diff_z);

    unsigned int dist = rintf(distance/some_factor);
    ind3 = m * another_factor + dist;

    cuComplex some_element = data[ind3];

    Main calculation starts, involving some_element.

【问题讨论】:

  • 请更具体一些,最好提供一些简单的代码示例。在“内部循环”中“计算”一个“新索引”留下了很大的想象空间,因此您的直接问题至少有两个答案('这是否太复杂......?'):是的。没有。
  • 如果没有(理想情况下可复制+可粘贴的)代码示例来说明您正在尝试做什么,就无法知道您真正想要做什么。查看theano.scan 的文档。
  • some_pos 从未初始化,所以我看不出这段代码如何运行,即使放在上下文中。什么是some_element??不如你在 Theano 中写一些东西,然后问问有没有更好的方法?看起来您正在计算位置网格到某个点的距离。这在 Theano 中只需要很少的几行代码。
  • 所以你有一个en.wikipedia.org/wiki/Sequential_algorithm 通常 GPU 不是为此目的而构建的。如果您可以将其并行化(例如,通过该空间运行 1024 条独立跟踪),那么 GPU 将是值得的。

标签: python loops theano


【解决方案1】:

不,我没有看到使用张量而不是 for 循环无法完成的事情。这应该意味着您可能会看到速度有所提高,但这实际上取决于应用程序。你也有 python+theano 的开销,尤其是来自类似 c 的代码。

所以,而不是

for (m = 0; m < M; ++m)
{
    unsigned int ind2 = 3 * m;

    float diff_x = x - some_pos[ind2];
    float diff_y = y - some_pos[ind2 + 1];
    float diff_z = z - some_pos[ind2 + 2];

    float distance = sqrtf(diff_x * diff_x
                         + diff_y * diff_y
                         + diff_z * diff_z);

    unsigned int dist = rintf(distance/some_factor);
    ind3 = m * another_factor + dist;

    cuComplex some_element = data[ind3];
}

你可以做类似的事情(我的头顶)

diff_xyz = T.Tensor([x,y,z]).dimshuffle('x',0) - some_pos.reshape(-1,3)
distance = T.norm(diff_xyz)
dist = T.round(distance/some_factor)
data = data.reshape(another_factor,-1)
some_elements = data[:,dist]

看到了吗?没有更多的循环,因此 GPU 可以将其并行化。

但是,在计算的内部循环中,会根据循环索引和几个数组的相应值计算新索引。 (...) 这是否太复杂以至于无法期待 Theano 有任何显着的加速?

一般来说:只要循环索引与所需索引具有线性关系,就可以通过使用张量而不是循环来优化。然而,它需要一点创造力和按摩才能正确。

使用Tensor.take() 也可以实现非线性关系,但我不敢保证它在 GPU 上的速度。我的直觉总是告诉我要远离它,因为它可能太灵活而无法很好地优化。但是,在没有替代品的情况下可以使用。

【讨论】:

    【解决方案2】:

    GPU 在使用全局内存时并不擅长随机存取内存。我以前没有使用过 Theano,但如果你的数组都适合本地内存 - 这会很快,因为随机访问在那里不成问题。如果它是全局内存,虽然很难预测性能会如何,但它与它的全部功能相去甚远。另一方面,这种计算是否可以并行化? GPU 只有在同时发生大量这些事情时才能真正发挥出色。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-01-27
      • 1970-01-01
      • 2013-06-11
      • 2012-11-23
      • 1970-01-01
      • 2023-04-05
      • 2021-09-29
      相关资源
      最近更新 更多