13장. 엔진 설계와 벤치마크#

이 장에서 배우는 것

  • 속도를 높인 방법 — 벡터화, 컴파일, 메모리 구조

  • 벤치마크 수치와 직접 재 보는 법

  • 튜토리얼을 마치며

1장부터 12장까지 IFRS 17 측정을 개념부터 실무까지 따라왔습니다. 마지막 장은 본문에서 한 걸음 비켜서서, 엔진이 그 측정을 빠르게 수행하기 위해 어떤 일들을 하는지를 봅니다. 엔진을 그냥 사용해서 BEL / RA / CSM을 계산하는 데는 꼭 필요한 내용은 아니니, 내부가 궁금하지 않다면 13.4로 건너뛰어도 됩니다.

13.1 속도 지향 설계#

속도는 다섯 가지가 함께 만들어 냅니다.

모델포인트 축 전체를 한꺼번에. 계약끼리 서로 독립입니다 — 계약 A의 보유계약·현금흐름은 계약 B와 무관합니다(4장). 그래서 엔진은 계약을 하나씩 반복문으로 돌지 않고, 수백만 계약을 한 배열로 묶어 한 달치 계산을 일괄 처리합니다. 순서를 지켜야 하는 것은 시간 축뿐입니다.

컴파일된 커널. 시간 루프는 numba(파이썬 코드를 기계어로 컴파일해 주는 도구)로 컴파일됩니다 — 파이썬 인터프리터를 거치지 않습니다. 게다가 모델포인트 차원은 여러 CPU 코어에 나뉘어 병렬로 수행됩니다.

연속 메모리 배치. 벡터화가 빠르려면 데이터도 메모리에 연속으로 붙어 있어야 합니다. 흩어진 파이썬 객체였다면 CPU가 매번 메모리를 새로 읽어야 해서 느려집니다. 모델포인트는 열 단위 연속 배열로, 담보는 모든 계약의 담보를 한 줄로 이어 붙인 CSR(Compressed Sparse Row) 구조로 담아 이를 보장합니다.

융합. 빠른 경로 measure(full=False)는 한 번의 융합된(여러 단계를 한 루프로 합치는) 패스로 돕니다. 보유계약을 숫자 하나로 들고 시간 루프를 돌 뿐, 월별 중간 배열을 메모리에 만들지 않습니다.

상품별 전용 커널. 상품마다 보유계약의 상태전이 가 다릅니다 — 단순 사망보장 정기보험은 한 상태 (보유 중) 뿐이고, 보험료 납입면제가 있는 상품은 납입 중 과 면제 두 상태 사이를, 재진단암 같은 상품은 건강 / 1차 진단 후 / 2차 진단 후 처럼 더 많은 상태를 거칩니다. 엔진은 각 상품의 상태전이에 맞춰진 코드를 런타임에 생성 하고 numba 가 컴파일하게 합니다. 생성된 코드에는 그 상품의 상태 개수 / 전이 / 보장 옵션이 숫자가 아니라 코드 자체 로 박혀 있어서, 컴파일된 커널에 배열 접근 / 분기가 거의 사라지고 순수 스칼라 산술만 남습니다. 컴파일 결과는 디스크에 캐시되어 같은 상품의 두 번째 평가는 컴파일 비용을 안 냅니다 — 첫 호출만 약간의 컴파일 시간이 들고, 이후 호출은 즉시.

13.2 고정 메뉴를 택한 까닭#

상품마다 전용 커널을 자동 생성한다 해도, 그 커널이 다룰 수 있는 담보 메커니즘 자체 는 고정된 메뉴로 한정되어 있습니다 — CalculationMethod 의 다섯 가지 (DEATH / MORBIDITY / DIAGNOSIS / ANNUITY / MATURITY) 가 그 메뉴입니다. 메뉴가 고정이라 엔진은 사람이 새 케이스를 손으로 추가하지 않고도 그 안의 모든 조합을 처리할 수 있습니다.

그래서 사용자가 메뉴에 없는 메커니즘을 직접 짜 넣을 수는 없습니다. 새 메커니즘은 엔진의 다음 버전에 CalculationMethod 값으로 더해집니다.

13.3 벤치마크#

사용자의 환경에서 속도를 측정할 수 있습니다. examples/benchmark.py는 합성 포트폴리오를 만들어 measure(full=False)의 시간을 잽니다. 직접 돌려 보려면 터미널에서:

python examples/benchmark.py

테스트 환경:

항목

사양

OS

Ubuntu 24.04

CPU

AMD Ryzen 7 3700X (2019.07 출시, 8코어 16쓰레드)

RAM

128GB

GPU (선택)

NVIDIA RTX 2070 SUPER (2019.07 출시)

보험기간 120개월, 사망 단독 계약 기준:

계약 수

CPU 시간

1만

0.006초

10만

0.010초

100만

0.058초

500만

0.309초

테스트 머신은 특별할 것 없는 데스크탑입니다 — Ryzen 3700X는 가성비로 평가받던 칩이지 비싼 고급 제품이 아닙니다. 그런 평범한 한 대가 500만 계약을 0.3초에 처리합니다.

GPU의 활용#

fastcashflow에는 CUDA 백엔드도 있습니다 — gmm.measure(model_points, basis, full=False, backend="gpu"). 그런데 위 환경(NVIDIA RTX 2070 SUPER)에서 GPU는 CPU보다 오히려 느렸습니다 — 1만~2천만 계약 어디서도 CPU의 0.7배 안팎. 이유는 둘입니다.

고정비용. CPU가 이미 워낙 빨라서, GPU로 일을 보내고(커널 실행, 메모리 전송) 받아오는 고정비용이 이득을 덮습니다. 이 고정비용은 포트폴리오가 훨씬 커져야 상대적으로 작아집니다.

소비자용 GPU의 배정밀도 한계. 더 근본적인 이유입니다. fastcashflow는 모든 계산을 배정밀도(FP64 — 64비트 부동소수점)로 합니다. 그런데 소비자용 GPU는 배정밀도 연산을 단정밀도(FP32)의 1/32~1/64 속도로만 처리합니다 (RTX 2070 SUPER는 1/32). GPU의 화려한 연산력이 대부분 단정밀도용이라, 배정밀도로는 그 일부만 쓰는 셈입니다. 데이터센터용 GPU(NVIDIA A100·H100 등)는 배정밀도 속도가 단정밀도의 1/2 수준이라 사정이 다릅니다 — 거기서는 GPU가 분명히 앞섭니다.

그렇다면 최신 소비자용 GPU는 어떨까요? 큰 포트폴리오라면 분명히 빨라집니다. RTX 5090(2025년 1월, Blackwell 아키텍처)도 소비자용 카드라 배정밀도를 단정밀도의 1/64로 제한합니다 — 비율만 보면 2070 SUPER의 1/32보다 오히려 더 깎입니다. 그런데도 빨라지는 건 칩 자체가 훨씬 커서입니다. 아래에서 TFLOPS는 초당 1조 번의 부동소수점 연산입니다.

GPU

FP32

FP64 (실사용)

RTX 2070 SUPER

~9 TFLOPS

~0.28 TFLOPS (1/32)

RTX 5090

~105 TFLOPS

~1.6 TFLOPS (1/64)

1/64로 깎여도 5090의 배정밀도 절대 성능이 2070 SUPER의 약 5~6배입니다. 메모리 대역폭(초당 GPU 메모리에서 옮기는 데이터양)도 ~4배(약 1.8 TB/s)라, 메모리를 많이 읽고 쓰는 이 엔진에 도움이 됩니다. 그래서 큰 포트폴리오라면 5090은 2070 SUPER를 확실히 앞섭니다. 이 테스트의 3700X CPU(2019년 보급형)도 넘어설 수 있지만, CPU가 최신 칩이라면 그 우위는 줄어듭니다.

정리하면, 일반적인 데스크탑에서는 CPU 경로가 이미 충분히 빠르고 권장 기본값입니다. GPU 백엔드는 최신 고사양 GPU나 데이터센터급 GPU로 큰 포트폴리오를 다룰 때 의미가 생깁니다.

13.4 마치며#

여기까지가 튜토리얼입니다. 되짚어 보면:

  • 1~2장 — IFRS 17이 무엇이고, 보험계약부채가 BEL·RA·CSM으로 이뤄진다는 것

  • 3~4장 — 모델포인트와 산출기초라는 입력, 그리고 엔진이 현금흐름을 만들어 내는 방식

  • 5~7장 — BEL·RA·CSM을 차례로 계산하고 손으로 검증

  • 8장 — 엔진으로 직접 측정하기

  • 9~10장 — 나머지 두 회계모형, PAA와 VFA

  • 11~12장 — 실무에서의 활용: 입력 파일, 시각화, 변동분석, 리포트

  • 13장 — 엔진 설계와 벤치마크

이제 measure() 한 줄 안에서 무엇이 어떤 순서로 일어나는지를 끝까지 펼쳐 본 셈입니다. 1.6절에서 한 약속을 지킨 거죠.

마지막으로 한 가지. 엔진이 내놓는 BEL·RA·CSM은 넣어 준 가정만큼만 정확합니다. 엔진은 모형을 충실하고 빠르게 계산하지만, 그 가정이 현실에 맞는지는 말해 주지 못합니다. 가정을 세우고 검증하는 일 — 담당자의 판단 — 이야말로 측정에서 가장 어렵고 중요한 몫입니다. 이 엔진은 그 판단을 숫자로 옮기는 빠르고 투명한 도구입니다.