1

次のように配列を正規化しようとしています。

  1. 配列の最初の 2 つの要素を選択し、合計を見つけて、その合計を使用してそれらを割ります。
  2. 残りの要素についても同じことを行います。

それは正常に動作します。しかし、配列の次元を増やすと、時間の複雑さが明らかになります。以下にコードを示します。

import pycuda.driver as drv
import pycuda.autoinit
from pycuda.compiler import SourceModule
import numpy as np

mod=SourceModule("""
__global__ void addition(float* a,float* c,float* d)
{
int i=blockIdx.y*blockDim.y+threadIdx.y;
for (i=0;i<=4;++i)
{
    int sum=0.0;
    for (int j=0;j<=1;++j)
    {
        sum+=a[2*i+j];
    }
c[i]=sum;
}
for (i=0;i<=4;i++)
{
    for (int j=0;j<=1;++j)
    {
        d[2*i+j]=a[2*i+j]/c[i];
    }
}
}
""")

addition=mod.get_function("addition")
a=np.array([1,2,3,1,2,3,2,1]).astype(np.float32)
c=np.zeros_like(a)
d=np.zeros_like(a)
addition(drv.In(a),drv.InOut(c),drv.InOut(d),block=(1,8,1))
print d

d の結果は [0.33333334 0.66666669 0.75 0.25 0.40000001 0.60000002 0.666666669 0.33333334] です。コードを最適化するためのアイデアを提案できる人はいますか?

4

1 に答える 1

1

実際のアプリケーションが からの値のペアをa合計し、その合計を に保存し、そのc値のペアを合計で正規化して に保存するだけのd場合、次のようなものが合理的です。

__global__ void addition(float* a, float* c, float* d)
{
    int idx = threadIdx.x + blockDim.x*blockIdx.x;

    float2* avec = reinterpret_cast<float2*>(a);
    float2* dvec = reinterpret_cast<float2*>(d);

    float2 val = avec[idx];
    float sum = val.x + val.y;
    val.x \= sum;
    val.y \= sum;

    c[idx] = sum;
    dvec[idx] = val;     
} 

[免責事項: ブラウザで書かれている、コンパイルされていない、テストされていない、GPU を起動しない保証がない、自己責任で使用する]

ここでは、ベクトル型を使用してメモリ スループットを向上させ、各スレッドが 1 組の値を処理します。N 値の場合、N/2 スレッドを実行します。131070 を超える入力値 (65535 ペア) がある場合は、複数の入力を処理するようにカーネルを変更する必要があります。そのような不測の事態が発生した場合に備えて、それは読者の演習として残しておきます。

于 2012-11-14T16:05:38.790 に答える