Je suis en train d'écrire du code pour activer les réseaux de neurones sur CUDA, et je suis confronté à un problème. Je ne reçois pas la somme correcte des poids entrant dans un neurone donné.Coder un noyau CUDA dont plusieurs threads écrivent dans le même index?
Donc, voici le code du noyau, et je vais essayer de l'expliquer un peu plus clairement avec les variables.
__global__ void kernelSumWeights(float* sumArray, float* weightArray, int2* sourceTargetArray, int cLength)
{
int nx = threadIdx.x + TILE_WIDTH*threadIdx.y;
int index_in = (blockIdx.x + gridDim.x*blockIdx.y)*TILE_WIDTH*TILE_WIDTH + nx;
if(index_in < cLength)
{
sumArray[sourceTargetArray[index_in].y] += fabs(weightArray[index_in]);
//__threadfence();
__threadfence_block();
}
}
Tout d'abord, le nombre de connexions dans le réseau est cLength
. Pour chaque connexion, il y a un neurone source et un neurone cible, ainsi qu'un poids pour cette connexion. SourceTargetArray
contient cette information. Ainsi, l'index i
de sourceTargetArray
est l'index de neurones source de la connexion i
, et l'index neuronal cible de la connexion i
. Le weightArray
contient les informations de poids (l'index i
de weightArray
correspond à la connexion i
).
Comme vous pouvez le voir, SumArray
est l'endroit où je stocke les sommes. Ainsi, le noyau incrémente le sumArray
(à l'index de neurones cible de la connexion i
) par la valeur absolue du poids de la connexion i
. Intuitivement, pour toutes les connexions entrantes au neurone, additionnez tous les poids. C'est vraiment tout ce que j'essaie de faire avec ce noyau. Finalement, je vais normaliser les poids en utilisant cette somme.
Le problème est que c'est faux. Je l'ai fait en série, et la réponse est différente. La réponse diffère, généralement d'environ 12-15x (donc la bonne réponse sera 700.0 et ce que je reçois est quelque chose dans la gamme des années 50).
Vous pouvez voir que j'ai ajouté __threadfence()
(et __threadfence_block()
pour essayer de m'assurer que les écritures n'étaient pas effectuées en même temps par chaque thread). Je ne suis pas sûr si c'est le problème avec mon code. Je me suis assuré que le tableau de poids est identique à la version en série que j'ai testé, et que les informations source/cible sont identiques. Qu'est-ce que je fais mal?
EDIT: Pour référence, __threadfence()
usaged est décrite dans le Guide de programmation CUDA v3.1 Annexe B.5 Fonctions de clôture de la mémoire
Dans l'exemple de code ci-dessus, 'cache [cacheIndex] + 1' devrait être' cache [cacheIndex + 1] '. –