본문 바로가기

AI Compiler framework

Linear layer 를 통한 설계 의도 관찰

역할

Linear 는 고수준 레이어지만, 실제 실행은 GEMM + (optional) BiasADd 의 emitter 시퀀스로 내려간다

 

y / y2 의 분리 이유 : 출력 버퍼 소유권과 후속 최적화 선택권을 planner 에게 넘김

y  = b.value(f"{self.name}.out", y_spec)        # gemm output
y2 = b.value(f"{self.name}.out_bias", y_spec)   # bias_add output

이러한 두 개의 value 를 만든 의도는

  • IR 상에서 데이터 흐름을 명확히 하기
    • gemm 의 결과는 y
    • bias_add 의 결과는 y2
    • 그래프를 보면 Linear 는 2-step 이 눈에 띄게 드러남
  • inplace / alias 를 기본값이 아니라 플래너 결정으로 만들기
    • 만약 bias_add 가 항상 y 에 in-place 로 써버리면,
      • 디버깅 / 검증에서 중간값 y 를 남기기 어려워지고
      • 어떤 패스에서는 중간 결과를 참조가 필요할 수도
      • CUDA Graph capture 에서 메모리 alias 정책을 바꿀 여지도 줄어듦
    • 기본은 out 분리 - 최적화 가능하니 나중에 합침
  • 퓨전과의 호환성
    • 최적의 경우 bias_add 자체가 사라지고 gemm epilogue 로 들어가야 함
    • 그건 가능할 때만
    • out 을 분리해두면
      • fuse 가 되면 y2 를 gemm output 으로 매핑
      • fuse 가 안 되면 기존대로 2-kernel

 

constraints / hints 문서화 포인트

constraints = {"inplace_ok":True}

  • 이ㅣ op 는 입력과 출력을 같은 버퍼로 alias 해도 의미가 보존된다.
  • planner 가 실제 결정
  • planner 판단 요소 예시
    • x 가 이후에 다시 사용되는지
    • 메모리 재사용 / 피크 메모리 감소 목표가 있는지
    • CUDA Graph capture 안정성을 위해 pointer 재배치가 제한되는지

 

hints={"prefer_epilogue_fusion":True}

  • 이 op 는 가능하면 op 와 fuse 되는 방향을 선호
  • 강제가 아닌 선호도 힌트
  • fuse 조건들의 존재