현재 각 기능, ops 를 추가 구현하면서 바인딩 코드가 계속 늘어나고, 유지 및 보수에 불리해짐을 느낌, 각 ops 별 독립 모듈로써 작동하도록 변경 필요
1) 디렉터리/레이아웃 정리
각 op 디렉터리(예: backends/cuda/ops/gemm) 안에 모든 의존 자원을 국소화한다.
backends/cuda/ops/<op>/
┣ include/ # 이 op만 쓰는 내부 헤더(필요시)
┣ kernels/ # CUDA 커널 소스들(.cu)
┣ api.hpp # 이 op의 C++ public API(런처 선언 등)
┣ launcher.cu # 텐서/attrs → 커널 파라미터 매핑/호출
┣ (backward.cu) # 있으면
┣ (common.hpp) # 공유 유틸(있으면)
┗ (traits.hpp) # 커널 컴파일 특성(있으면)
gemm처럼 커널이 전용일 때, 공유 폴더 kernels/regemm_epilogue는 제거하고, backends/cuda/ops/gemm/kernels/로 이관(중복·다중정의 방지).
2) 공통 헤더 의존성 → “경량 shim”으로 치환
기존에는 #include "ai/tensor.hpp", #include "ai/dispatch.hpp" 같은 코어 헤더에 의존했는데, 독립 모듈에서는 최소 타입만 필요한 경량 shim으로 갈아끼운다.
- 방법 A(추천): backends/cuda/ops/_shim/ 폴더에 아주 작은 대체 헤더 두 개 정의
- tensor_shim.hpp : dtype, layout, device, Tensor(desc+data) 정도
- op_schema_shim.hpp : 이 op에 필요한 attrs만(예: GemmAttrs{act, leaky_slope, trans_a,b})
- dispatch_shim.hpp : using StreamHandle = void*; enum class Status {...};
- 각 op의 api.hpp/launcher.cu/backward.cu 등에서 코어 헤더 대신 shim 헤더를 include:
- (예) #include "ops_shim/tensor_shim.hpp" (상대 경로는 CMake include로 해결)
이렇게 하면 코어 라이브러리 없이도 컴파일/링크가 독립된다. (CUDA 런타임/ cuBLAS만 링크)
3) 런처 코드 수정 포인트
- include 교체: ai/* → shim 헤더
- 텐서/속성/Status/StreamHandle 타입은 shim 네임스페이스로 변경(또는 namespace ai {} 유지해도 되지만 타입 실체는 shim)
- 디버그 로그/외부 레지스트리 의존 제거
- 커널 호출은 op 내부 kernels/*.cu에 있는 함수만 부른다.
- 필요한 변환 유틸(infer_ld, bias_kind 추론 등)은 common.hpp 같은 op-로컬 유틸로 모듈화
4) 바인딩(파이썬) 모듈을 op 단위로 분리
- 새 타깃: src/bindings/<op>_pybind.cpp → _ops_<op>로 빌드
- 바인딩은 numpy API 또는 (필요 시) 얇은 텐서 포장 중 택1
- 빠르게 쓰려면 우리가 만든 forward_numpy(...), backward_numpy(...) 식으로 numpy만 받는 래퍼 제공
- 내부에서 host→device 복사/실행/결과 device→host 복귀(이미 gemm 테스트에서 검증)
- 에러 매핑: Status → std::runtime_error 식으로 간단 변환
이미 _ops_gemm로 검증 끝. 다른 op도 동일 패턴으로 복제하면 된다.
5) CMake: 각 op를 완전 독립 타깃으로
최상위 CMakeLists.txt에 아래 재사용 가능한 함수/매크로를 추가해 두면, ops 추가가 1~2줄로 끝남.
# 공통: 독립 op 모듈을 만드는 헬퍼
function(add_standalone_op OP_NAME)
# 예: OP_NAME=gemm → 타깃명 _ops_gemm, 소스 경로 구성
set(OP_DIR ${CMAKE_SOURCE_DIR}/backends/cuda/ops/${OP_NAME})
pybind11_add_module(_ops_${OP_NAME} MODULE
${CMAKE_SOURCE_DIR}/src/bindings/${OP_NAME}_pybind.cpp
${OP_DIR}/launcher.cu
${OP_DIR}/kernels/*.cu # 필요에 따라 glob or 나열
${OP_DIR}/backward.cu # 있으면
)
target_include_directories(_ops_${OP_NAME}
PRIVATE
${OP_DIR} # api.hpp, common.hpp
${OP_DIR}/include # 이 op 전용 내부 include
${CMAKE_SOURCE_DIR}/backends/cuda/ops/_shim # 경량 shim
)
target_link_libraries(_ops_${OP_NAME}
PRIVATE CUDA::cudart CUDA::cublas
)
set_target_properties(_ops_${OP_NAME} PROPERTIES
CUDA_SEPARABLE_COMPILATION ON
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/python/graph_executor_v2/ops"
)
if (WIN32)
set_target_properties(_ops_${OP_NAME} PROPERTIES
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/python/graph_executor_v2/ops"
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/python/graph_executor_v2/ops"
)
endif()
endfunction()
# 필요 op들을 간단히 나열
add_standalone_op(gemm)
# add_standalone_op(rmsnorm)
# add_standalone_op(softmax) ...
이렇게 하면 코어/백엔드 타깃 불필요.
_ops_<op>가 CUDA 런타임/BLAS만 링크하고 독립적으로 떨어짐.
6) 빌드 & 실행
# 설정
cmake -S . -B build -G "Ninja" -DCMAKE_BUILD_TYPE=Release ^
-DCMAKE_CUDA_ARCHITECTURES=86 ^
-DPython3_EXECUTABLE="C:\Path\to\python.exe" ^
-Dpybind11_DIR="...\site-packages\pybind11\share\cmake\pybind11"
# 특정 op만 빌드
cmake --build build --target _ops_gemm -j
실행 시:
- Windows면 CUDA DLL 경로 os.add_dll_directory()로 보장
- python/graph_executor_v2/ops/_ops_gemm*.pyd 로드 확인
7) 마이그레이션 작업 순서(요약 체크리스트)
- 커널 이관
- 공유 kernels/regemm_epilogue → backends/cuda/ops/gemm/kernels/로 이동
- 중복 정의 제거(하나만 컴파일)
- shim 도입
- backends/cuda/ops/_shim/{tensor_shim.hpp, op_schema_shim.hpp, dispatch_shim.hpp} 작성
- 런처/커널/바인딩에서 ai헤더 대신 shim include
- 런처 정리
- ai:: → shim 타입으로 치환
- 공용 유틸(common.hpp)로 infer_ld/bias_kind 등 캡슐화
- 코어/레지스트리 호출 제거
- 바인딩 추가
- src/bindings/<op>_pybind.cpp 작성(넘파이 API or 얇은 텐서 API)
- Status→예외 변환, 문서 문자열, all 등
- CMake 타깃 추가
- add_standalone_op(<op>)로 간단 등록
- 의존성은 CUDA 런타임/BLAS만
- 테스트
- 간단 forward/backward shape/값 검증
- (선택) 수치미분 케이스
- dumpbin /DEPENDENTS(Win)로 외부 의존성에 ai_core가 없는지 확인
8) 자주 부딪히는 이슈 & 해결
- 다중정의(nvlink error): 커널을 두 군데서 빌드하지 않도록 소스 중복 제거.
- 런타임 DLL 문제(Win): os.add_dll_directory(CUDA\bin) 확보.
- ABI 충돌: shim 헤더는 C++17 고정·extern "C" 필요 없음(전부 템플릿/inline이면 안전).
- 성능/타일 파라미터: 각 op config.h에서 독립 관리(빌드 옵션으로 override 가능).
'dev_AI_framework' 카테고리의 다른 글
| GPU 연산 최적화 - 내가 잘못생각하고 있었음, gpu-cpu 간 이동이 발생하는 경우에 대해 사실은 모두 gpu 내에서 실행 (0) | 2025.09.30 |
|---|---|
| Z - caching in epilogue gemm backward ( 연산 비용 - 메모리 Trade-off) (0) | 2025.09.30 |
| 파이프 라인 수정... - IR → 패스 → 커널선택(디스패치) → 스케줄/메모리플랜 → 실행으로 이어지는 컴파일러형 학습 파이프라인 (0) | 2025.09.29 |
| 어느 단위 레벨까지 구현해야 할까 에 대한 고민 - 기본 레벨 연산들은 끝도 없 (0) | 2025.09.24 |
| CUDA Backend: Slice & Concat 연산 문서 (0) | 2025.09.24 |