본문 바로가기

AI Compiler framework

AICF v2 실행 파이프라인 ( optimize 생략 버전 )

큰 그림

  • Layer.emit / Model.add
    • Builder 에 value 와 Op 쌓음
    • 여기서 CUDA 호출에 필요한 불변 정보를 emitter 가 미리 쌓음
  • compile_cuda
    • Builder - lower_ir_cuda 로 LoweredOp 생ㅅ어
    • make_exec_plan_cuda 로 런타임 결정을 담은 ExecPlan 생성
  • CudaExecutor.run / run_compiled
    • feed 로 들어온 tensor 를 value 슬롯에 bind / alloc
    • plan.alias 적용
    • plan.lowered 순서대로 _C.op_call 실행
    • 선택적으로 CUDA Graph capture / replay 로 반복 실행 최적화

 

1) IR 생성 단계 Layer - Builder

Model.add 가 하는 일

  • model.add
    • layer.emit 호출

여기서 ctx 는 backend 별 emitter 컨텍스트 용도

 

Builder 에 쌓이는 데이터

Value

  • 생성 위치 : Builder.input / param / state / value
  • 저장 필드
    • vid : 정수 id
    • name : 디버그 / 출력 키에 쓰임
    • spec : TensorSpec(shape, dtype, device)
    • role : input | param | state | tmp | output
    • producer_op, users : 그래프 연결 정보

이 Value 는 런타임 슬롯 테이블의 인덱스가 된다.

 

Op ( 연산 노드 )

  • 생성 위치
  • 저장 필드
    • kind : 문자열
    • inputs : in_vids
    • outputs : out_vids
    • attrs : 사람이 읽기쉬운 dict
    • constraints / hints / saved : 플래너 / 트레이닝 정책 힌트
    •  emitter-first 캐시
      • kind_id : C++ enum OpKind 와 일치하는 int
      • attrr_schema : ABI 구분자 
      • attr_blob : 커널에 넘길 packed bytes

 

2) Emitter-first : emitters / cuda 가 채우는 불변 호출 스펙

emitter 가 실제로 채우는 것

각 emitter 의 패턴

  • 입력 / 출력 vid 구성은 layer 가 결정
  • emitter 는 다음을 완성
    • kind_id
    • attr_schema
    • attr_blob

Builder.emit 을 호출하면서 Op.kind_id, attr_schema, attr_blob 를 함께 저장

 

3) Compile 단계 : Builder(IR) - ExecPlan

3.1 compile_cuda

b0 = m.b
b1 = optimize_ir(b0)          # 현재 identity
lowered = lower_ir_cuda(b1)   # emitter-first: serialize only
plan = make_exec_plan_cuda(b1, lowered)
plan = optimize_plan(plan)    # 현재 identity
return CompiledProgram(plan)

 

3.2 lower_ir_cuda

  • 입력 : Builder.ops
  • 출력 : List[LowerdOp]

각 op 에서

  • op.kind_id, op.attr_schema, op.attr_blob 필수

LoweredOp 구조

  • kind_id, attr_schema, attr_blob
  • in_vids, out_vids
  • constraints 전달

lower 는 이제 커널 호출 스펙을 런타임 형태로 옮기는 단계

 

3.3 make_exec_plan_cuda

  • 입력
    • builder
    • lowered ops
  • 출력
    • execplan
  • inplace 가능 같은 constraints 기반으로
  • out_vid 가 in_vid 슬롯을 그대로 쓰도록 alias 결정을 담음

 

4) Runtime 단계 : ExecPlan 실행 ( Eager )

bind_and_alloc_slots

입력

  • Builder
  • feed : Dict[str, torch.Tensor]

출력

  • slots : List[torch.Tensor]

동작 개념

  • externals 은 feed 에서 가져옴
  • tmp / output 은 spec 기반으로 새로 alloc
  • contig() 정책 처리

 

plan.alias 적용

for out_vid, in_vid in plan.alias.items():
    slots[out_vid] = slots[in_vid]

out_vid 는 별도 텐서가 아닌 in_vid 와 동일한 storage 를 참조할수 있음

 

lowered 실행

for lop in plan.lowered:
    ins = [slots[v] for v in lop.in_vids]
    outs = [slots[v] for v in lop.out_vids]
    op_call(lop.kind_id, ins, outs, lop.attr_schema, lop.attr_blob, stream)

 실제로 backend 에 전달되는 최종 스펙

  • kind_id
  • attr_schema
  • attr_blob
  • ins / outs

 

5) CUDA Graph 경로 : capture + replay

cache key

  • (mode, plan_key, static_roles, copy_roles, feed_signature)
  • externals 이름 + shape, dtype, device 포함
  • contig 은 제외

 

capture 정책

  • static_roles 캡처 중 고정 슬롯으로 유지할 role
    • ingerence
    • train
  • copy_roles : replay 마다 feed 에서 복사해 업데이트할 role
    • inference 기본 : input
    • train 기본 : input

 

replay 보안 성질

train 모드에서 replay 시

  • feed 로 w/step 을 바꿔도 무시됨
  • 오직 input 만 매 replay 반영
  • 그래서 step 은 계속 증가하고, w 는 reset 되지 않음