- layers/sequential.py 모델 컨테이너 + 오케스트레이터
- 빌드/요약/파라미터 유틸 ( build() / parameters() / zero_grad() 등)
- 정적 경로 : compile() - (고정 입력/모델 전체) 캡처 준비 - one_step() 로 재생
- 동적 경로 : one_step_dynamic() - 분기/반복/EaryExit 경로 평탄화 - 경로별 키 생성, 캐시 조회 - 미스 시 캡처 후 풀에 저장 - 이후 재생
- 풀 : graph_executor.py 의 graph_pool + 내부 풀백
- graph/captrue_plan.py 캡처 사전계획 생성기
- 레이어 타입별 플래너 registry 로 forward 출력, pre-act, backward, workspace 를 사전할당 - 캡처 구간의 동적 malloc 제거
- API : make_plan_for_sequential(model, in_shape) / make_plan_for_path(path_layers, in_shape)
- 드롭아웃 마스크 롤링 : advance_dropout(plan, seed_bump)
- graph/graph_exec.py 한 스텝 ( fwd - loss - bwd - opt) 캡처/재생
- 러너 : _run_fwd(layers, plan, X, stream_ptr), _run_bwd(layers, plan, g_in, stream_ptr)
- 캡처 : record_step_graph() - 워밍업 1회 - cuda.graph.capture_stream - instantiate() 또는 폴백 실행자
- 실행 핸들 : TrainGraph(gexec, io, stream) - set_batch() / launch()
- graph/graph_executor.py 키/폴만 유지하는 전역 캐시
- GraphSignature(shape, dtype, layout) + GraphKey(signature, branch_id, variant)
- MultiGraphPool ( LRU, 스레드 세이프 ) & 전역 graph_pool 인스턴스
- sequential 이 동적 경로 그래프를 키로 조회/저장해 재사용
[Sequential] ──uses──> [capture_plan] ──produces──> CapturePlan(per_layer, loss.dY, ...)
│ │
│ └─(buffers/workspaces for each layer)
│
├─(static/dynamic)──calls──> [graph_exec.record_step_graph]
│ │
│ └─captures fwd→loss→bwd→opt as CUDA Graph
│ │
│ └─returns TrainGraph(gexec, io, stream)
│
└─(dynamic only)──uses──> [graph_executor.graph_pool]
└─keyed by GraphKey(signature+branch+variant)
실행 순서: 정적 캡처/재생
전제 : 모델 구조/입력 shape 가 고정, 모든 레이어가 capture-ready
- Sequential.compile(input_shape, loss, optimier, ... )
- (필요 시) build()
- CapturePlan 생성 : make_plan_for_sequential(model, in_shape) - 레이어별 PerLayerBufs(y, z, gA, gW, gB, work) 사전 할당, loss.dY 준비
- 옵티마이저 바인딩(필요 시) : try_rebind_grads(self, optimizer, plan)
- 그래프 캡처 record_step_graph(self, loss, optimizer.step_into, plan, X_buf, y_buf, stream, loss_out)
- 워밍업 1회 (fwd - loss - bwd - opt) 로 버퍼/WS 고정
- capture_stream 내 동일 시쿠너스 캡처 - instantiate()
- TrainGraph 생성/보관 : self._tg = TrainGraph(gexec, io, stream)
- Sequential.one_step(X, y)
- self._tg.set_batch(X, y)
- self._tg.launch() ( CUDA Graph 재생 )
- loss_out.get() 반환
핵심 포인트
- Plan 단계에서 모든 메모리가 준비돼 캡처 내 malloc 금지
- _run_fwd/_run_bwd 가 model.layers 기준으로 순회
주요 데이터 구조 & 불변식
- CapturePlan
- per_layer[i] <-> layers[i] 1:1 정렬 ( 정적은 model.layers, 동적은 path_layers )
- PerLayerBufs
- y : 다음 레이어 입력, z : pre_activation
- gA/gW/gB : backward 버퍼
- work : Conv/GEMM/RNN 등 WS 묶음
- loss.dY : CE 등 일부 손실의 dY 고정 버퍼
- TrainGraph
- io : 고정 X, y, logits 버퍼 핸들
- set_batch() 는 그래프와 같은 스트림에서 H2D/D2D 복사
- launch() 는 내부 gexec.launch(stream_ptr) 호출
- GraphKey
- signature + batch_id + variant
- 키가 같으면 가은 경로 모드 입력서명을 가리키므로 재사용 가능
'dev_AI_framework' 카테고리의 다른 글
| Graph Execution & Planning 과 CUDA Graph Capture & Stability 의 차이 (0) | 2025.10.28 |
|---|---|
| 단순 복붙, 각 부분 수정 필요함, 단 이는 최적화 단계에서, 일단 구현 먼저 다 하자 으쌰으쌰 (0) | 2025.10.28 |
| AI Model 의 정적, 동적 경로 조건 (0) | 2025.10.28 |
| epilogue 실행 방식 고민 - 모놀리식 통합형 ( 항상 커널 내부에 epilogue 가 존재하도록 !!! ) (0) | 2025.10.20 |
| epilogue - ep_apply (0) | 2025.10.20 |