这是我在CUDA中实现的伪代码的一部分,作为图像重建算法的一部分:
for each xbin(0->detectorXDim/2-1):
for each ybin(0->detectorYDim-1):
rayInit=(xbin*xBinSize+0.5,ybin*xBinSize+0.5,-detectordistance)
rayEnd=beamFocusCoord
slopeVector=rayEnd-rayInit
//knowing that r=rayInit+t*slopeVector;
//x=rayInit[0]+t*slopeVector[0]
//y=rayInit[1]+t*slopeVector[1]
//z=rayInit[2]+t*slopeVector[2]
//to find ray xx intersections:
for each xinteger(xbin+1->detectorXDim/2):
solve t for x=xinteger*xBinSize;
find corresponding y and z
add to intersections array
//find ray yy intersections(analogous to xx intersections)
//find ray zz intersections(analogous to xx intersections)
到目前为止,这是我提出的:
__global__ void sysmat(int xfocus,int yfocus, int zfocus, int xbin,int xbinsize,int ybin,int ybinsize, int zbin, int projecoes){
int tx=threadIdx.x, ty=threadIdx.y,tz=threadIdx.z, bx=blockIdx.x, by=blockIdx.y,i,x,y,z;
int idx=ty+by*blocksize;
int idy=tx+bx*blocksize;
int slopeVectorx=xfocus-idx*xbinsize+0.5;
int slopeVectory=yfocus-idy*ybinsize+0.5;
int slopeVectorz=zfocus-zdetector;
__syncthreads();
//points where the ray intersects x axis
int xint=idx+1;
int yint=idy+1;
int*intersectionsx[(detectorXDim/2-xint)+(detectorYDim-yint)+(zfocus)];
int*intersectionsy[(detectorXDim/2-xint)+(detectorYDim-yint)+(zfocus)];
int*intersectionsz[(detectorXDim/2-xint)+(detectorYDim-yint)+(zfocus)];
for(xint=xint; xint<detectorXDim/2;xint++){
x=xint*xbinsize;
t=(x-idx)/slopeVectorx;
y=idy+t*slopeVectory;
z=z+t*slopeVectorz;
intersectionsx[xint-1]=x;
intersectionsy[xint-1]=y;
intersectionsz[xint-1]=z;
__syncthreads();
}
...
}
这只是代码的一部分。我知道可能存在一些错误(如果它们明显错误,你可以指出它们)但我更关心的是:
每个线程(对应于检测器区域)需要三个数组,因此它可以保存光线(通过此线程/ bin)与x,y和z轴的倍数相交的点。每个数组的长度取决于探测器和beamFocusCoord(固定的)中线程/ bin(它的索引)的位置。为了做到这一点,我编写了这段代码,我确信无法完成(用一个小的测试内核确认它并返回错误:“表达式必须具有常量值”):
int*intersectionsx[(detectorXDim/2-xint)+(detectorXDim-yint)+(zfocus)];
int*intersectionsy[(detectorXDim/2-xint)+(detectorXDim-yint)+(zfocus)];
int*intersectionsz[(detectorXDim/2-xint)+(detectorXDim-yint)+(zfocus)];
所以最后,我想知道是否有替代这段代码,其中向量的长度取决于分配该向量的线程的索引。
提前谢谢你;)
编辑:假设每个线程必须保存一个数组,其中包含光线(从光束源到探测器)和xx,yy和zz轴之间的交点坐标,并且空间尺寸是周围(我目前没有确切的数字,但它们非常接近实际价值)1400x3600x60,CUDA这个问题是否可行?
例如,线程(0,0)在x轴上有1400个交点,在y轴上有3600个交叉点,在z轴上有60个交叉点,这意味着我将不得不创建一个大小的数组(1400 + 3600 + 60)* sizeof(float),每个线程约20kb。
因此,假设每个线程超过16kb本地内存,那是不可能的。另一个选择是分配那些数组,但是,通过更多的数学运算,我们得到(1400 + 3600 + 60)* 4 *数字线程(即1400 * 3600),这也超过了可用的全局存储量:(
所以我没有想法来解决这个问题,任何帮助都表示赞赏。
答案 0 :(得分:3)
没有
CUDA中的每一块内存都必须在内核启动时知道。在内核运行时,您无法分配/取消分配/更改任何内容。这适用于全局内存,共享内存和寄存器。
常见的解决方法是预先分配所需的最大内存大小。这可以像分配一个线程线程所需的最大大小一样简单,也可以像将所有那些线程需要的大小相加到总最大值并计算到该数组中的适当线程偏移一样复杂。这是内存分配和偏移计算时间之间的权衡。
如果可以的话,可以选择简单的解决方案,如果必须的话,由于内存限制,可以使用复杂的解决方案。
答案 1 :(得分:0)
为什么不使用纹理?使用2D或3D纹理可以使这个问题更容易。 GPU是设计的来进行非常快速的浮点插值,而CUDA则提供了极好的支持。该文献具有在GPU上进行投影重建的示例,例如, Accelerating simultaneous algebraic reconstruction technique with motion compensation using CUDA-enabled GPU,纹理是他们算法不可或缺的一部分。你自己的手动坐标计算只能比GPU提供的更慢,更容易出错,除非你需要像sinc插值这样奇怪的东西。
1400x3600x60对于单个3D纹理来说有点大,但您可以将问题分解为2D切片,3D子体积或分层多分辨率重建。这些都已被其他研究人员使用。只需搜索PubMed。