CUDA 기초 이해

CUDA를 활용하면 GPU의 성능을 최대한 활용할 수 있습니다. CUDA에서 함수 호출 방식은 세 가지로 구분됩니다:

  1. __global__: CPU에서 호출되며, GPU에서 실행됩니다 (비동기).
  2. __device__: GPU 내부에서 호출되며, GPU에서 실행됩니다.
  3. __host__: CPU에서 호출되며, CPU에서 실행됩니다 (동기).

함수 선언 및 호출 방법

CUDA에서는 다음과 같이 함수를 선언합니다:

__global__ void FuncA(float input) 
{ 
    // GPU 작업 수행
}

__device__ void FuncB(int input) 
{ 
    // GPU 내부 작업 수행
}

__host__ void FuncC(char input) 
{ 
    // CPU 작업 수행
}

GPU 코어는 다중 스레드 환경에서 작동하므로, 각 스레드가 어떤 위치에 있는지 확인해야 합니다. 이를 위해 CUDA에서는 grid-block-thread 구조를 사용합니다.

Grid와 Block 정의

예를 들어 4x4 크기의 grid와 block을 생성하는 방법은 다음과 같습니다:

dim3 grid(4, 4);
dim3 block(4, 4);

각 thread의 위치를 결정하는 코드는 다음과 같습니다:

int i = blockIdx.x * blockDim.x + threadIdx.x;
int j = blockIdx.y * blockDim.y + threadIdx.y;

데이터 전송과 메모리 관리

CPU와 GPU 간 데이터 전송은 cudaMalloccudaMemcpy를 사용하여 수행됩니다:

float *gpu_input;
size_t size = N * sizeof(float);
cudaMalloc((void**)&gpu_input, size);
cudaMemcpy(gpu_input, cpu_input, size, cudaMemcpyHostToDevice);

dim3 blockSize(16, 16);
dim3 gridSize(16, 16);
FuncA<<<gridSize, blockSize>>>(gpu_input);

결과를 CPU로 다시 가져오는 과정도 유사합니다:

float *gpu_output;
cudaMalloc((void**)&gpu_output, size);
FuncA<<<gridSize, blockSize>>>(gpu_input, gpu_output);
cudaMemcpy(cpu_output, gpu_output, size, cudaMemcpyDeviceToHost);

CUDA 라이브러리 사용

CUDA는 다양한 수학 및 행렬 연산 라이브러리를 제공합니다. 예를 들어, sigmoid 함수는 다음과 같이 작성할 수 있습니다:

template <typename T>
__device__ __forceinline__ T Sigmoid(T z) {
    return 1.0 / (1.0 + exp(-z));
}

행렬 연산은 cuBLAS 라이브러리를 통해 쉽게 처리할 수 있습니다:

cublasHandle_t handle;
cublasCreate(&handle);
cublasSgemm(handle, CUBLAS_OP_N, CUBLAS_OP_N, M, N, K, &alpha, A, lda, B, ldb, &beta, C, ldc);

이러한 기능들을 활용하면 복잡한 신경망 계산도 효율적으로 수행할 수 있습니다.

태그: CUDA cuBLAS

6월 5일 20:35에 게시됨