iBetter Books
수정

시스템이 느리면 아무리 정확해도 쓰기 어렵습니다. 이 장에서는 추론 속도를 끌어올리는 첫 번째 방법으로, PART 07에서 만난 ONNX Runtime의 최적화 손잡이들을 다룹니다. 실행 장치 고르기, 스레드 조정, 배치 처리 세 가지입니다.

어디서 느린지부터 찾기

최적화의 첫 단계는 측정입니다. PART 02·06에서처럼 각 단계의 시간을 재서 병목을 찾습니다. 검출이 느린지, 인식이 느린지, 전후처리가 느린지 모른 채 최적화하면 엉뚱한 곳에 힘을 씁니다.

# 파일: profile.py (개념)import timet0 = time.perf_counter(); faces = detect(img);   t1 = time.perf_counter()embs = [embed(f) for f in faces];                 t2 = time.perf_counter()print(f"검출 {(t1-t0)*1000:.0f}ms, 인식 {(t2-t1)*1000:.0f}ms")

병목을 안 다음에야 아래 방법들을 그곳에 적용합니다.

실행 장치 — provider

PART 07에서 본 provider가 가장 큰 손잡이입니다. CPU만 쓰던 것을 GPU나 전용 가속기로 바꾸면 수 배 빨라집니다.

# 파일: ort_provider.pyimport onnxruntime as ortprint(ort.get_available_providers())   # 무엇을 쓸 수 있는지 먼저 확인# 우선순위 순으로 지정 (앞이 가능하면 앞을 씀)sess = ort.InferenceSession("model.onnx",                            providers=["CUDAExecutionProvider",                                       "CPUExecutionProvider"])

InsightFace 같은 라이브러리도 내부에서 onnxruntime을 쓰므로, FaceAnalysis(providers=[...])로 같은 선택을 합니다(PART 07). 주의할 점은 PART 07에서 말했듯, 지정한 가속기가 없으면 조용히 CPU로 떨어진다는 것입니다. 실제로 어떤 provider가 활성화됐는지 꼭 확인하세요.

스레드 조정

CPU로 돌릴 때는 스레드 수가 속도에 영향을 줍니다. SessionOptions로 조정합니다.

# 파일: ort_threads.pyimport onnxruntime as ortopt = ort.SessionOptions()opt.intra_op_num_threads = 4        # 한 연산 내부 병렬 스레드 수opt.graph_optimization_level = ort.GraphOptimizationLevel.ORT_ENABLE_ALLsess = ort.InferenceSession("model.onnx", sess_options=opt,                            providers=["CPUExecutionProvider"])

intra_op_num_threads는 보통 물리 코어 수에 맞추면 좋습니다. 다만 무조건 크게 한다고 빨라지지 않습니다. 여러 요청을 동시에 처리하는 서버라면, 한 요청에 모든 코어를 몰아주기보다 요청들에 코어를 나누는 편이 전체 처리량이 높을 수 있습니다.

배치 처리

여러 얼굴(또는 여러 이미지)을 하나씩 처리하는 대신 한 번에 묶어 넣으면 훨씬 효율적입니다. GPU는 특히 배치에서 진가를 발휘합니다.

# 파일: batch.py (개념)# 얼굴 10개를 하나씩 (느림)embs = [model.run(None, {"input": face[None]})[0] for face in faces]# 10개를 한 배치로 묶어 한 번에 (빠름)batch = np.stack(faces)                       # shape (10, ...)embs = model.run(None, {"input": batch})[0]   # 한 번의 호출

하나씩 열 번 호출하는 것과 열 개를 한 번에 넣는 것은, 모델을 열 번 깨우느냐 한 번 깨우느냐의 차이입니다. 사진 수천 장을 등록(PART 07)할 때처럼 대량 처리에서 배치는 큰 차이를 만듭니다. 다만 실시간 단일 프레임처럼 한 번에 하나뿐이면 배치 이점은 없습니다.

최적화의 우선순위

방법 효과 적용 시점
provider(GPU) 매우 큼 GPU가 있으면 먼저
배치 처리 큼(대량) 대량 등록·처리
스레드 조정 중간 CPU 환경
모델 경량화 다음 장(엣지)

실무 팁. 최적화는 "측정 → 한 가지 바꾸기 → 다시 측정"의 반복이어야 합니다. 여러 개를 한꺼번에 바꾸면 무엇이 효과였는지 알 수 없습니다. 또 "충분히 빠른가"의 기준을 먼저 정하세요. 실시간 30fps가 목표인데 이미 60fps가 나온다면 더 최적화할 필요가 없습니다. 목표 없는 최적화는 시간 낭비입니다.

이 장에서 기억할 것

성능 최적화는 측정으로 병목을 찾는 것에서 시작합니다. onnxruntime에서는 provider(GPU 가속)가 가장 큰 손잡이이고, CPU에서는 스레드 조정, 대량 처리에서는 배치가 효과적입니다. 지정한 가속기가 없으면 CPU로 조용히 떨어지니 활성 provider를 확인하고, "측정 → 한 가지 변경 → 재측정"을 반복합니다. 목표 속도를 먼저 정하세요. 다음 장에서는 Intel 환경과 엣지 기기를 위한 OpenVINO 최적화를 살펴봅니다.