2012-08-08 2 views
4

내부 구조체의 배열의 할당 난이 구조체를했습니다 :CUDA : 구조체

typedef struct neuron 
{ 
float* weights; 
int n_weights; 
}Neuron; 


typedef struct neurallayer 
{ 
Neuron *neurons; 
int n_neurons; 
int act_function; 
}NLayer; 

"NLayer는"구조체는 "신경 세포"의 임의의 수를 포함 할 수 있습니다 내가 해봤

가 할당 이 방법으로 호스트로부터 5 '뉴런'와 'NLayer'구조체 :

NLayer* nL; 
int i; 
int tmp=9; 
cudaMalloc((void**)&nL,sizeof(NLayer)); 
cudaMalloc((void**)&nL->neurons,6*sizeof(Neuron)); 
for(i=0;i<5;i++) 
    cudaMemcpy(&nL->neurons[i].n_weights,&tmp,sizeof(int),cudaMemcpyHostToDevice); 

는 ... 그때는 수정을 시도한 그 커널 변수를 "nL-> 뉴런 [0] .n_weights" :

__global__ void test(NLayer* n) 
      { 
       n->neurons[0].n_weights=121; 
      } 

하지만 컴파일 시간 NVCC 반환에서 63,210 그 커널의 유일한 라인과 관련 "경고"

Warning: Cannot tell what pointer points to, assuming global memory space 

커널이 작업을 완료 할 때 구조체에 연결할 시작합니다.

아마도 배정 과정에서 뭔가 잘못하고있는 것 같습니다. 누군가 나를 도와 줄 수 있을까요 ?? 대단히 고마워, 내 영어로 미안해! :)

UPDATE

: 올란드에

덕분에 내가 구조체 "NLayer"의 인스턴스를 할당해야이 기능을 만들어 내 코드를 수정했습니다

NLayer* setNLayer(int numNeurons,int weightsPerNeuron,int act_fun) 
{ 
    int i; 
    NLayer h_layer; 
    NLayer* d_layer; 
    float* d_weights; 

    //SET THE LAYER VARIABLE OF THE HOST NLAYER 
    h_layer.act_function=act_fun; 
    h_layer.n_neurons=numNeurons; 
    //ALLOCATING THE DEVICE NLAYER 
    if(cudaMalloc((void**)&d_layer,sizeof(NLayer))!=cudaSuccess) 
     puts("ERROR: Unable to allocate the Layer"); 
    //ALLOCATING THE NEURONS ON THE DEVICE 
    if(cudaMalloc((void**)&h_layer.neurons,numNeurons*sizeof(Neuron))!=cudaSuccess) 
     puts("ERROR: Unable to allocate the Neurons of the Layer"); 
    //COPING THE HOST NLAYER ON THE DEVICE 
    if(cudaMemcpy(d_layer,&h_layer,sizeof(NLayer),cudaMemcpyHostToDevice)!=cudaSuccess) 
       puts("ERROR: Unable to copy the data layer onto the device"); 

    for(i=0;i<numNeurons;i++) 
    { 
     //ALLOCATING THE WEIGHTS' ARRAY ON THE DEVICE 
     cudaMalloc((void**)&d_weights,weightsPerNeuron*sizeof(float)); 
     //COPING ITS POINTER AS PART OF THE i-TH NEURONS STRUCT 
     if(cudaMemcpy(&d_layer->neurons[i].weights,&d_weights,sizeof(float*),cudaMemcpyHostToDevice)!=cudaSuccess) 
       puts("Error: unable to copy weights' pointer to the device"); 
    } 


    //RETURN THE DEVICE POINTER 
    return d_layer; 
} 

을 그리고 난 그 함수를 호출 (커널 "test"는 이전에 선언 된 것입니다.) :

int main() 
{ 
    NLayer* nL; 
    int h_tmp1; 
    float h_tmp2; 

    nL=setNLayer(10,12,13); 
    test<<<1,1>>>(nL); 
    if(cudaMemcpy(&h_tmp1,&nL->neurons[0].n_weights,sizeof(float),cudaMemcpyDeviceToHost)!=cudaSuccess); 
     puts("ERROR!!"); 
    printf("RESULT:%d",h_tmp1); 

} 

이 코드를 컴파일하면 컴파일러가 표시됩니다 나에게 경고하고, 프로그램을 실행할 때 화면에 출력한다 :

Error: unable to copy weights' pointer to the device 
Error: unable to copy weights' pointer to the device 
Error: unable to copy weights' pointer to the device 
Error: unable to copy weights' pointer to the device 
Error: unable to copy weights' pointer to the device 
Error: unable to copy weights' pointer to the device 
Error: unable to copy weights' pointer to the device 
Error: unable to copy weights' pointer to the device 
Error: unable to copy weights' pointer to the device 
Error: unable to copy weights' pointer to the device 
ERROR!! 
RESULT:1 

커널 호출에 주석을 달면 마지막 오류는 비교되지 않는다.

내가 틀렸어? 나는 어떻게 해야할지 모르겠다 당신의 도움에 감사드립니다!

답변

0

모두 사용하는 GPU 카드에 따라 다릅니다. 페르미 카드는 공유 및 전역 메모리 공간의 균일 한 주소 지정을 사용하지만 페르미 전 카드는 사용하지 않습니다.

pre-Fermi의 경우 주소를 공유할지 또는 전체 주소인지 여부를 알 수 없습니다. 컴파일러는 보통 이것을 알아낼 수 있지만, 그렇지 않은 경우가 있습니다. 공유 메모리에 대한 포인터가 필요할 때, 보통 공유 변수의 주소를 취하고 컴파일러는이를 인식 할 수 있습니다. 이것이 명시 적으로 정의되지 않은 경우 "전역으로 가정"메시지가 나타납니다. 당신이 2.x 또는 그 이상의 컴퓨팅 capabiilty을 가진 GPU를 사용하는 경우

, 그것은 -arch = sm_20 컴파일러 플래그

+0

경고에 대해 잘 알고 있지만 프로그램의 비정상적인 동작을 일으키는 원인인지는 의심 스럽습니다. 결국, 전 세계 emory 공간에 상주하는 구조에 대한 컴파일러의 가정은 정확합니다 ... – aland

+0

1.2 능력이있는 NVIDIA GeForce 320M 256MB를 사용하고있어서 "Fermi"카드라고 생각하지 않습니다. –

5

문제와 함께 작동해야 할 것은 여기에 있습니다 : 처음에

cudaMalloc((void**)&nL,sizeof(NLayer)); 
cudaMalloc((void**)&nL->neurons,6*sizeof(Neuron)); 

줄에 nL이 장치의 전역 메모리에서 구조를 가리키고 있습니다. 따라서 두 번째 줄에서 cudaMalloc의 첫 번째 인수는 정의되지 않은 동작 인 GPU에있는 주소입니다 (테스트 시스템에서는 segfault가 발생하지만, 경우에 따라 더 미묘한 부분이 있음).

당신이 원하는 것을 할 수있는 올바른 방법은, 호스트 메모리에 구조를 만들 데이터로 채우기 위해 처음으로, 다음과 같이 장치에 복사 :

NLayer* nL; 
NLayer h_nL; 
int i; 
int tmp=9; 
// Allocate data on device 
cudaMalloc((void**)&nL, sizeof(NLayer)); 
cudaMalloc((void**)&h_nL.neurons, 6*sizeof(Neuron)); 
// Copy nlayer with pointers to device 
cudaMemcpy(nL, &h_nL, sizeof(NLayer), cudaMemcpyHostToDevice); 

또한, 잊지 마세요 CUDA 루틴의 오류를 항상 확인하십시오. 코드의 두 번째 버전에서

UPDATE

:

cudaMemcpy(&d_layer->neurons[i].weights,&d_weights,...) --- 다시, 당신은 호스트 장치 포인터 (d_layer)를 역 참조한다. 대신, 당신은 여기

cudaMemcpy(&h_layer.neurons[i].weights,&d_weights,sizeof(float*),cudaMemcpyHostToDevice 

당신이 h_layer (호스트 구조) 걸릴를 사용해야 장치 메모리에 대한 포인터의 요소 (h_layer.neurons)를 참조하십시오. 그런 다음 포인터 연산을 수행합니다 (&h_layer.neurons[i].weights). 이 주소를 계산하려면 장치 메모리에 액세스 할 필요가 없습니다.

+0

내 코드를 수정했는데 작동하지 않습니다. 새 코드는 처음 게시물에 있습니다 ... 감사합니다! –

+0

오! 고마워요 !! 나는 단 한가지 더 질문한다. 만약 호스트로부터 정수 변수 **로 변환 된 데이터에 접근하고 싶다면 d_layer-> neurons [0] .n_weights ** 나는 이전에 호스트에 ** d_layer **를 복사해야만한다. 그런 다음 호스트에 ** d_layer-> neurons [0] **을 복사 한 다음 마침내 d_layer-> neurons [0] .n_weights 변수를 사용할 수 있습니다. 나는 "d_layer-> neurons [0] .n_weights를 cudaMemcpy (...)로 직접 복사하려고 시도했지만 항상"잘못된 인수 "오류를 반환합니다. –

+0

@AndreaSylarSolla 당신은 단순히'int t; cudaMemcpy (& t, & h_layer.neurons [0] .n_weights, ....)'또는'Neuron t; cudaMemcpy (& t, & h_layer.neurons [0], ....)'. 'd_layer'를 복사 할 필요가 없습니다. 단지'neurons' 포인터 만 필요하기 때문입니다. 그러나'h_layer'에 아주 같은 값이 있습니다. – aland