상태: 초안 (2026-10-06), 원리 글입니다. 원리 설명은 각 모델의 공식 자료(글 끝에 링크)와 일반적인 추론 이론에 근거하고, 검산에 쓴 숫자는 20편에서 필자가 직접 잰 값입니다. 계산식은 현상을 이해하기 위해 단순화한 것이며, 어느 부분이 검증되었고 어느 부분이 추정인지 절마다 밝혔습니다. 작성 규칙: 실측 데이터가 기본이고, 못 잰 것은 「미실측」으로 표시합니다.
목차
- 1. 한눈에 보기: 부품마다 시간을 정하는 것이 다르다
- 2. 대화 LLM: 토큰 하나를 만들 때마다 모델을 통째로 읽는다
- 3. 음성합성: 만들 패치 수만큼 반복한다
- 4. 스트리밍 음성인식: 한 번 계산한 것은 다시 계산하지 않는다
- 5. 이어 붙이면: 병목의 종류가 부품마다 다르다
- 6. 면접에서 나올 만한 질문
- 외부 근거: 논문과 공식 자료로 확인한 것
- 확인하지 못한 것
- 참고 자료
- 확인한 버전과 날짜
1. 한눈에 보기: 부품마다 시간을 정하는 것이 다르다
20편의 값은 「얼마나 걸렸는가」였고, 이 글은 「왜 그만큼 걸리는가」입니다.
| 부품 | 시간을 정하는 것 | 원리로 예측한 값 | 직접 잰 값 | 일치 |
|---|---|---|---|---|
| 대화 LLM, 토큰 생성 | 토큰마다 가중치 전체를 메모리에서 읽는 시간 | 상한 약 129 tok/s(잰 대역폭 기준) | 85.6 tok/s | 상한의 66% |
| 대화 LLM, 입력 처리 | 연산량 | 생성보다 훨씬 빠름 | 700 tok/s(67토큰), 1,024토큰 이상에서는 연산 한계의 약 75~80% | 일치, 짧은 입력은 느림 |
| 생성 속도의 대역폭 상한 | 가중치 바이트 × 속도 ≤ 대역폭 | 잰 대역폭 250GB/s | 모델 네 개에서 86~98% | 일치 |
| 음성합성(VoxCPM2) | 만들어야 할 패치(걸음) 수 | 오디오 1초 = 6.25 패치(패치 하나 = 160ms 분량) | 1초당 0.475초, 패치당 약 76ms | 계산으로 연결, 논문 구조와 일치 |
| 스트리밍 음성인식 | 청크 = 프레임 수 × 80ms | 청크 5종 | 카드의 5개 값과 검산 일치 | 일치 |
2. 대화 LLM: 토큰 하나를 만들 때마다 모델을 통째로 읽는다
원리
트랜스포머가 다음 토큰 하나를 계산하려면 모든 층의 가중치를 한 번씩 써야 합니다. 요청이 하나뿐이면 가중치 하나당 곱셈을 한두 번만 하고 끝나므로, GPU 의 연산 장치는 놀고 가중치를 메모리에서 가져오는 속도(메모리 대역폭) 가 시간을 정합니다. 그래서 토큰 생성 속도의 이론적 상한은 이렇습니다.
초당 토큰 수 ≤ 메모리 대역폭 ÷ 가중치 바이트 수
반대로 입력(프롬프트)을 처리하는 단계는 토큰 수십 개를 한꺼번에 계산하므로 같은 가중치를 여러 토큰이 재사용하고, 이때는 연산 능력이 한계입니다. 같은 모델인데 입력 처리가 생성보다 훨씬 빠른 이유입니다.
검산
| 항목 | 값 | 출처 |
|---|---|---|
| GPU 메모리 대역폭 | 약 905GB/s(24GB급 소비자용 GPU, 읽기 전용 합산, 3회 반복 903~905) | 직접 측정(PyTorch 로 1GiB 텐서를 읽는 시험). 복사(읽기+쓰기)는 865GB/s. 사양서의 약 936GB/s 는 기억에 의존한 값이라 쓰지 않음 |
| 가중치(4비트 QAT) | 7.0GB | 모델 파일 크기를 공개 API 로 확인 |
| 이론 상한 | 905 ÷ 7.0 ≈ 129 tok/s | 계산 |
| 측정한 생성 속도 | 85.6 tok/s(토큰당 11.6ms) | 20편 측정, 서버 계측과 일치 |
| 효율 | 85.6 ÷ 129 ≈ 66% | 계산 |
| 입력 처리 속도 | 700 tok/s(67토큰에 95.7ms) | 서버 계측 |
- 상한의 66% 를 쓰고 있습니다. 나머지는 어텐션이 읽는 KV 캐시, 양자화 구간을 되돌리는 계산, 층마다 커널을 시작하는 간격 등으로 나뉠 텐데, 어느 것이 얼마인지는 분해하지 않았습니다(추정).
- 입력 처리는 생성의 8.2배입니다(700 ÷ 85.6). 원리가 말하는 방향과 같고, 그래서 입력이 길어도 첫 토큰이 크게 늦어지지 않습니다. 반대로 긴 답변은 토큰 수에 정비례해 늦어집니다. 다만 67토큰은 짧아서 요청마다 드는 고정 비용이 섞인 값입니다. 입력을 길이별로 쟀을 때의 값은 아래 「입력 처리는 연산이 한계이고, 짧은 입력은 느리게 나온다」에 있습니다.
- 양자화가 속도에 곧바로 나타납니다. 같은 모델을 16비트로 두면 가중치가 약 25GB(130억 파라미터 × 2바이트, 계산)라서, 같은 식의 상한이 905 ÷ 25 ≈ 36 tok/s 로 3분의 1 아래로 내려갑니다. 이 GPU 의 메모리 24GB 에는 들어가지도 않으므로 4비트가 선택이 아니라 전제입니다. 이 모델의 16비트 속도는 측정하지 않았습니다(미실측, 계산). 작은 모델로 정밀도를 반으로 줄이면 계산이 말하는 이득보다 조금 작게(1.7배 대신 1.54배) 나타났으므로(아래 직접 검증), 4비트와 16비트의 차이도 계산값보다는 작게 나올 가능성이 큽니다.
- 생각 토큰도 같은 속도로 생성됩니다. 20편의 사고에서 80토큰을 전부 생각에 쓴 응답이 약 1.0초 걸렸습니다(80 ÷ 85.6 ≈ 0.93초와 일치). 음성 대화에서 모델이 생각 토큰 N 개를 쓰면 사용자는 N ÷ 85초 동안 침묵을 듣습니다. 생각을 꺼야 하는 이유가 감이 아니라 계산으로 나옵니다.
직접 검증: 크기와 정밀도가 다른 모델로 상한을 확인한다
위 검산은 대역폭 값을 사양에서 가져왔기 때문에 상한 자체가 맞는지는 확인하지 못했습니다. 그래서 8GB급 GPU 한 장에서 대역폭을 먼저 직접 재고, 크기와 정밀도가 다른 모델 네 개의 생성 속도를 같은 방법으로 쟀습니다(vLLM 0.31.0, 동시 요청 1개, 128토큰 생성의 5회 중앙값).
- GPU 의 읽기 전용 대역폭: 250GB/s(PyTorch 로 큰 텐서를 읽어 합산, 중앙값), 복사 227GB/s
- fp16 행렬곱 4096³: 31.8 TFLOPS(중앙값)
| 모델 | 적재된 가중치 | 생성 속도 | 가중치 × 속도 | 잰 대역폭 대비 |
|---|---|---|---|---|
| 0.6B, bf16 | 1.12GiB | 180.4 tok/s | 217GB/s | 87% |
| 1.7B, bf16 | 3.22GiB | 68.8 tok/s | 238GB/s | 95% |
| 1.7B, fp8 | 1.90GiB | 105.7 tok/s | 216GB/s | 86% |
| 4B, fp8 | 4.32GiB | 52.7 tok/s | 244GB/s | 98% |
가중치 크기는 서버 로그의 적재 메모리이고, 「가중치 × 속도」는 토큰 하나를 만드는 동안 가중치를 한 번씩 읽었다고 가정한 계산입니다.
- 원리가 맞습니다. 모델 크기가 달라도 「가중치 × 속도」가 대역폭 근처(86~98%)에 모입니다. 속도를 정하는 것은 파라미터 수가 아니라 읽어야 하는 바이트라는 뜻입니다.
- 정밀도를 반으로 줄인 효과는 계산보다 작았습니다. 1.7B 를 bf16 에서 fp8 로 바꾸면 가중치는 1.7배 작아지지만(3.46GB 대 2.04GB, 계산) 속도는 1.54배(68.8 대 105.7)만 올랐습니다. 토큰당 걸리는 시간으로 보면 읽기 시간 외에 토큰마다 0.4~1.3ms 가 더 듭니다(계산: 1 ÷ 속도 − 가중치 ÷ 250GB/s). 어텐션, 층마다의 커널 시작, 8비트 값을 되돌리는 계산이 들어 있을 것으로 보지만 어느 것이 얼마인지는 분해하지 않았습니다(추정).
- 24GB급 GPU 의 대역폭도 같은 방법으로 쟀습니다. 읽기 전용 905GB/s(사양서 값으로 알려진 약 936GB/s 의 약 97%)였고, 12B 4비트 모델의 생성 속도 × 가중치(85.6 × 7.0)는 약 599GB/s 로 잰 대역폭의 66% 였습니다. 즉 앞에서 사양값으로 계산한 64% 는 잰 값으로도 거의 같은 66% 입니다. 대역폭을 가정했기 때문에 생긴 차이가 아니라는 뜻이고, 8GB급 GPU 의 vLLM 결과(86~98%)보다 낮은 것은 엔진(llama.cpp 와 vLLM), 4비트 형식(구간별 되돌리기 계산), 모델 구조의 차이 중 어느 것 때문인지 가르지 못했습니다(미확인). 같은 GPU 에서 같은 모델을 두 엔진으로 재는 시험이 남은 일입니다.
동시 요청이 늘어도 느려지지 않는 이유와 한계
가중치를 읽는 비용은 요청 수와 무관하게 한 번이므로, 여러 요청을 한꺼번에 묶어 처리하면(연속 배칭) 읽기 비용을 나눠 갖습니다. 20편에서 동시에 2개를 보냈을 때 첫 토큰이 0.206초, 4개는 중앙값 0.352초였습니다. 이 서버는 슬롯을 2개만 열어 두어서 4개일 때는 2개씩 줄을 선 값이라, 배칭의 이득을 깨끗하게 보여 주는 실험은 아니었습니다.
그래서 위의 네 모델을 슬롯 16개로 열고 동시 요청 수를 늘려 총 처리량을 쟀습니다(요청마다 128토큰 생성, 3회 중앙값).
| 동시 요청 | 0.6B bf16 | 1.7B bf16 | 1.7B fp8 | 4B fp8 |
|---|---|---|---|---|
| 1 | 180 | 69 | 106 | 53 |
| 4 | 670 | 264 | 405 | 205 |
| 16 | 2,484 | 1,007 | 1,544 | 775 |
| 16개일 때 1개의 몇 배인가 | 13.8배 | 14.6배 | 14.6배 | 14.7배 |
| 16개일 때 요청 하나의 속도 | 155(86%) | 63(91%) | 97(91%) | 48(92%) |
단위는 총 처리량(tok/s)이고, 마지막 두 줄은 위 표에서 계산했습니다. 요청을 16배로 늘렸는데 요청 하나는 8~14% 만 느려지고 총량이 거의 14~15배가 되었습니다. 가중치를 읽는 비용을 나눠 갖는다는 원리가 그대로 나타납니다.
이 이득이 끝나는 지점은 계산으로만 가늠했습니다. 토큰 하나는 파라미터당 2번의 연산을 하므로, 잰 연산 처리량(31.8 TFLOPS)과 잰 대역폭(250GB/s)으로 bf16 에서는 동시 요청이 약 130개를 넘을 때, fp8 에서는 약 64개를 넘을 때 연산이 한계로 바뀝니다(계산, 어텐션과 KV 캐시 읽기는 무시한 단순화). 이번에는 16개까지만 열었으므로 그 지점은 확인하지 못했고(미실측), 16개 시점의 4B 모델도 연산은 잰 한계의 약 18%(2 × 3.6B × 775 ≈ 5.6 TFLOPS)여서 여전히 대역폭 쪽 영역에 있습니다.
입력 처리는 연산이 한계이고, 짧은 입력은 느리게 나온다
입력 처리는 같은 서버로, 접두사 캐시를 끄고 요청마다 다른 무작위 입력으로 쟀습니다.
| 입력 길이 | 1.7B bf16 | 4B fp8 |
|---|---|---|
| 256토큰 | 5,709 tok/s(45ms) | 3,129 tok/s(82ms) |
| 1,024토큰 | 8,634 tok/s(119ms) | 3,438 tok/s(298ms) |
| 2,048토큰 | 8,730 tok/s(235ms) | 3,365 tok/s(609ms) |
| 3,500토큰 | 8,244 tok/s(425ms) | 3,182 tok/s(1.10초) |
- 1,024토큰 이상에서 속도가 일정해집니다. 같은 모델의 생성(69, 53 tok/s)보다 각각 약 127배, 약 65배 빠릅니다. 계산으로 맞춰 보면 1.7B 는 임베딩을 뺀 파라미터가 1.4B 라서 8,730 tok/s 가 약 24 TFLOPS(2 × 1.4B × 8,730), 4B 는 3.6B 라서 3,438 tok/s 가 약 25 TFLOPS 입니다. 두 모델 모두 잰 행렬곱 처리량 31.8 TFLOPS 의 약 75~80% 라서, 입력 처리는 연산이 한계라는 원리와 숫자가 서로 맞습니다.
- 짧은 입력은 토큰당 비용이 큽니다. 256토큰에서 속도가 1.7B 는 약 35%, 4B 는 약 9% 낮았습니다. 요청마다 드는 고정 비용이 짧은 입력에서는 나눌 토큰이 적어 크게 보이기 때문입니다. 음성 대화의 입력은 보통 짧으므로, 위 12B 측정의 700 tok/s(67토큰) 도 이 영향을 받은 값으로 읽어야 합니다.
- 첫 측정이 틀렸고, 연산 한계와 대조해서 알았습니다. 처음에는 같은 문장을 반복해 보냈는데 4B 가 약 91,000 tok/s 로 나왔습니다. 이는 약 660 TFLOPS(2 × 3.6B × 91,240)에 해당해서 GPU 가 낼 수 없는 값입니다. 접두사 캐시가 적중해 입력을 계산하지 않은 탓이었고, 캐시를 끄고 요청마다 다른 입력으로 다시 재서 위 표를 얻었습니다. 측정값을 하드웨어 한계에 대 보는 것만으로 걸러낼 수 있는 오류입니다.
3. 음성합성: 만들 패치 수만큼 반복한다
원리
두 합성 모델은 모두 소리를 한꺼번에 내놓지 않고 짧은 단위(VoxCPM2 는 160ms 분량의 패치, Magpie 는 코덱 프레임)를 앞에서부터 하나씩 만들어 갑니다(자기회귀). 그래서 시간은 오디오 길이에 정비례하고, 문장의 시작에는 길이와 상관없는 고정 비용이 붙습니다. 20편에서 열두 점으로 맞춘 식이 그 모양입니다.
합성 시간 ≈ 0.475 × 오디오 길이(초) + 0.23초
VoxCPM2: 패치당 76ms
VoxCPM2 기술 보고서에 따르면 이 모델은 이산 토큰을 쓰지 않고 연속적인 잠재 표현을 확산과 자기회귀로 만드는 구조입니다. 음성을 초당 25개의 잠재 프레임(40ms)으로 줄이고, 프레임 4개를 한 패치로 묶어 패치를 한 번에 하나씩 만듭니다. 그래서 자기회귀의 한 걸음은 오디오 160ms 에 해당하고 초당 6.25걸음입니다. 이 숫자를 측정과 이으면 이렇습니다.
| 항목 | 값 |
|---|---|
| 오디오 1초에 필요한 걸음(패치) | 6.25 |
| 오디오 1초를 만드는 시간(측정 기울기) | 0.475초 |
| 걸음(패치) 하나에 드는 시간 | 0.475 ÷ 6.25 ≈ 76ms |
| 서버 설정의 확산 반복 횟수 | 10(inference_timesteps=10, 서버 코드에서 확인) |
| 확산 한 번당(위 76ms 를 10 으로 나눈 값) | 약 7.6ms(상한. 걸음당 시간에는 언어 모델 한 스텝과 디코딩이 들어 있고, 논문에 따르면 확산 단계마다 확산 모듈을 두 번 계산하는 분류자 없는 가이던스(CFG)도 들어 있어 실제 한 번당 값은 더 작을 수 있음) |
걸음 하나마다 언어 모델 한 스텝과 확산 10번을 도는 비용이 76ms 라는 이야기이고, 이 구조에서는 확산 반복 횟수를 줄이면 거의 비례해서 빨라질 것으로 예상할 수 있습니다. 반복 횟수를 줄였을 때의 속도와 품질은 시험하지 않았습니다(미실측). 고정 비용 0.23초는 논문에서도 근거를 찾지 못했습니다. 논문의 실시간 계수는 고정 비용을 포함한 벽시계 값이라 길이가 길수록 기울기에 가까워지는데, 이 0.23초가 문장 인코딩, 참조 음성 처리, 디코더 초기화, 서버 래퍼 중 무엇인지는 어느 자료도 알려 주지 않으며 분해하지 않았습니다(미확인).
공식 설명은 이 모델이 스트리밍 생성(generate_streaming)을 지원한다고 하고, 기술 보고서(표 11)는 소비자용 상위급 GPU(24GB급) 한 장에서 PyTorch 구현의 실시간 계수 0.30(피크 VRAM 약 8GB), 서빙 엔진(Nano-vLLM) 사용 시 0.13 을 보고합니다. 우리가 잰 기울기 0.475 는 논문의 0.30 보다 약 1.6배 느린데, GPU 종류, 문장 전체를 합성해 돌려주는 서버 방식, 래퍼 오버헤드 중 무엇 때문인지 가르지 못했습니다(미확인). VRAM(6,600~6,900MiB)은 논문의 약 8GB 와 같은 범위입니다.
Magpie TTS: 한 번에 두 프레임
Magpie TTS Multilingual 은 파라미터가 3억 6,400만 개인 인코더-디코더 트랜스포머입니다. 공식 설명의 핵심은 두 가지입니다. 프레임 쌓기는 디코더가 한 스텝에 오디오 프레임 두 개를 한꺼번에 예측해 반복 횟수를 절반으로 줄이는 방법이고, 로컬 트랜스포머는 그렇게 만든 프레임들 사이의 의존 관계를 다듬어 줄어든 품질을 되찾는 작은 모듈입니다. 같은 길이의 소리를 만드는 데 필요한 디코더 스텝 수가 절반이 되는 셈입니다.
| 항목 | VoxCPM2 | Magpie TTS |
|---|---|---|
| 파라미터 | 약 20억 | 약 3억 6,400만 |
| 생성 방식 | 연속 잠재 표현을 확산과 자기회귀로 | 코덱 프레임을 자기회귀로(두 프레임씩) |
| GPU 메모리(측정) | 약 6,600~6,900MiB | 약 750MiB |
| 실시간 계수(측정) | 0.494~0.582, 중앙값 0.521 | 0.447~0.541, 중앙값 0.466(한국어 제외) |
- 파라미터가 5배 이상 작고 메모리가 9배 작은데 속도는 비슷합니다. 시간을 정하는 것이 파라미터 수가 아니라 「만들어야 할 스텝 수 × 스텝당 비용」이라는 해석과 맞습니다. 다만 두 모델을 서로 다른 GPU 에서 쟀고, Magpie 의 프레임 비율을 확인하지 못해서 VoxCPM2 처럼 프레임당 시간을 계산하지는 못했습니다(미확인).
- 공식 첫 소리 지연(H100 에서 47ms 등)은 스트리밍 기준입니다. 측정에서 쓴 것은 문장 전체를 합성해 받는 방식이라 같은 숫자로 비교할 수 없습니다.
- 한국어는 이 환경에서 정상적으로 만들어지지 않았습니다(20편 3-2). 구조의 문제인지 설정의 문제인지는 확인하지 못했습니다.
스트리밍 합성이 첫 소리를 줄이는 원리
패치를 앞에서부터 만들기 때문에, 문장 끝까지 기다릴 필요 없이 첫 패치가 나오는 즉시 재생을 시작할 수 있습니다(VoxCPM2 보고서는 생성한 패치를 곧바로 소리로 바꾸는 구조라고 설명합니다). 첫 소리까지의 시간이 「문장 전체의 합성 시간」(20편 측정: 1.2~2.1초)에서 「문장당 고정 비용과 첫 패치 하나의 시간」(0.23초 + 0.08초, 약 0.3초)으로 줄어듭니다. 이것은 계산이고 측정에 쓴 서버에서 시험하지 않았습니다. 재생이 합성보다 느리므로(실시간 계수 0.5) 이어지는 소리가 끊기지 않는다는 조건도 필요합니다.
4. 스트리밍 음성인식: 한 번 계산한 것은 다시 계산하지 않는다
원리
음성인식 모델 Nemotron 3.5 ASR 은 FastConformer 인코더 24층과 RNNT 디코더로 이루어져 있습니다. 두 가지가 지연을 만듭니다.
- 프레임 길이. 인코더가 소리를 8배로 줄여서 인코더 프레임 하나가 80ms 입니다(특징을 10ms 간격으로 뽑는 일반적인 설정 기준이며, 모델 카드의 청크 값 80ms 가 이 해석과 맞습니다).
- 오른쪽 문맥(앞을 내다보는 양). 지금 프레임의 뜻을 정하려고 조금 뒤의 프레임까지 보고 싶습니다. 그 프레임이 도착할 때까지 기다려야 하므로, 내다보는 양이 곧 지연입니다.
모델은 att_context_size = [왼쪽, 오른쪽] 으로 이 둘을 정합니다. 왼쪽 56프레임은 과거 4.48초(56 × 80ms)를 기억하는 양이고, 오른쪽이 청크를 정합니다. 한 번에 처리하는 청크의 길이는 (오른쪽 + 1) × 80ms 입니다.
att_context_size |
계산: (오른쪽 + 1) × 80ms | 모델 카드의 청크 값 | 일치 |
|---|---|---|---|
| [56, 0] | 1 × 80 = 80ms | 80ms | 일치 |
| [56, 1] | 2 × 80 = 160ms | 160ms | 일치 |
| [56, 3] | 4 × 80 = 320ms | 320ms | 일치 |
| [56, 6] | 7 × 80 = 560ms | 560ms | 일치 |
| [56, 13] | 14 × 80 = 1,120ms | 1.12초 | 일치 |
다섯 값이 모두 카드의 표와 맞아서, 「청크 = (오른쪽 문맥 + 1) × 80ms」라는 해석이 맞다고 볼 수 있습니다.
캐시가 하는 일
예전의 스트리밍 방식(버퍼 방식)은 최근 소리를 겹치는 창으로 잘라 매번 처음부터 다시 인코딩했습니다. 겹친 구간을 여러 번 계산하는 셈입니다. 캐시 인지 방식은 모든 셀프어텐션 층과 컨볼루션 층의 인코더 표현을 캐시에 저장하고, 새 소리가 오면 새 프레임만 계산해 캐시를 갱신합니다. 공식 설명대로 각 프레임이 정확히 한 번만 처리됩니다. 그 결과 계산량이 소리 길이가 아니라 새로 들어온 길이에 비례합니다. 처리량은 벤더 수치로, 다국어 3.5 모델 카드가 H100 한 장에서 청크 80ms 설정에 동시 스트림 약 240개(버퍼 방식 기준선 Parakeet 1.1B 는 약 14개), 1.12초 설정에 약 2,400개(기준선 약 400개)라고 적고, 영어 전용 모델의 NVIDIA 블로그가 320ms 청크에서 560스트림을 적습니다(두 모델의 값이라 섞어 읽으면 안 됩니다). 「확정 결과까지 중앙값 24ms」는 영어 모델 블로그의 협력사 파이프라인 값입니다. 필자의 실험 환경에서는 재현하지 않았습니다.
RNNT 디코더는 인코더 프레임이 하나 나올 때마다 글자(또는 「아직 없음」을 뜻하는 빈 기호)를 내놓는 구조라서, 프레임이 들어오는 대로 글자가 이어집니다. 그래서 말이 끝나기 전에 결과가 흘러나오고, 말이 끝나면 마지막 청크만 확정하면 됩니다.
청크 크기를 키우면 정확해지는가
오른쪽 문맥이 길수록 모델이 더 많은 미래를 보고 판단하므로 일반적으로 정확도가 오르고 지연도 함께 오릅니다. 같은 12개 음성에 청크 크기별 설정을 적용해 평균 글자 오류율을 재면 이렇습니다(파일 전체에 설정을 적용한 근사이며 실제 스트리밍이 아닙니다).
| 청크 | 80ms | 160ms | 320ms | 560ms | 1,120ms |
|---|---|---|---|---|---|
| 평균 글자 오류율 | 4.3% | 4.0% | 3.9% | 3.9% | 11.3% |
- 80ms 에서 320ms 로 가며 4.3% 에서 3.9% 로 조금 좋아지고, 그 뒤로는 같습니다. 이 합성 음성 12개에서는 320ms 이상의 문맥이 더 도움이 되지 않았다는 뜻입니다. 지연을 가장 짧게 하는 80~160ms 로 바꿔도 정확도 손실은 0.4~0.3 퍼센트포인트였습니다. 합성 음성이라 깨끗하다는 점이 이 결과를 낙관적으로 만들었을 수 있습니다.
- 1,120ms 의 11.3% 는 설명하지 못했습니다. 한 개 음성이 빈 결과로 나온 탓이고 두 번 재도 같았습니다. 모델 카드의 한국어 FLEURS 글자 오류율은 오히려 1.12초 설정에서 가장 낮아(7.12%) 우리 값은 카드와 반대 방향입니다. 사람이 읽은 한국어 FLEURS 30문장으로 다시 재니 청크 크기와 관계없이 빈 결과가 0개이고 글자 오류율이 5.6~6.2% 로 평평했으므로(20편 4-3절), 이 현상은 모델의 일반적 성질이 아니라 합성 음성 12개 표본에서만 나타난 것으로 보입니다. 원인은 분해하지 않았습니다.
5. 이어 붙이면: 병목의 종류가 부품마다 다르다
| 부품 | 병목의 종류 | 줄이는 방법의 방향 |
|---|---|---|
| 음성인식 | 계산(새 프레임 수에 비례), 매우 가벼움 | 거의 손댈 필요 없음 |
| 대화 LLM | 메모리 대역폭 | 가중치를 작게(양자화), 더 넓은 대역폭의 GPU, 생각 끄기 |
| 음성합성 | 프레임을 순서대로 만드는 반복 | 스트리밍, 짧은 구절 먼저, 반복 횟수 조절 |
20편의 한 턴 계산에서 합성이 60~85% 였던 이유가 여기 있습니다. 음성인식은 가벼운 계산이고, LLM 은 대역폭 상한의 66% 까지 쓰고 있어 더 짜낼 여지가 작으며, 합성만 「오디오 길이만큼 반복」 이라는 구조라서 문장이 길수록 선형으로 늘어납니다.
6. 면접에서 나올 만한 질문
- LLM 토큰 생성 속도의 상한은 어떻게 어림하는가? 메모리 대역폭을 가중치 바이트 수로 나눈다. 4비트 12B 모델은 잰 대역폭 905GB/s ÷ 7.0GB ≈ 129 tok/s 이고 실측 85.6 tok/s(66%)였다.
- 같은 모델에서 입력 처리가 생성보다 훨씬 빠른 이유는? 입력은 가중치를 한 번 읽어 여러 토큰이 재사용해서 연산이 한계이고, 생성은 토큰마다 가중치를 다시 읽어서 대역폭이 한계다(1.7B 모델에서 8,730 대 69 tok/s).
- 요청을 16개로 늘리면 요청 하나는 얼마나 느려지는가? 작은 모델 네 개에서 8~14% 만 느려지고 총 처리량은 약 14~15배가 되었다. 가중치를 읽는 비용을 나눠 갖기 때문이다.
- 측정값이 맞는지 어떻게 의심하는가? 하드웨어 한계와 대 본다. 입력 처리 91,000 tok/s 는 GPU 가 낼 수 없는 연산량이라, 접두사 캐시가 적중한 것을 알아챘다.
- 양자화는 왜 속도에도 도움이 되는가? 가중치 바이트가 줄면 대역폭 상한이 그만큼 오른다. 4비트는 16비트의 약 3.5배(계산). 작은 모델에서 16비트에서 8비트로 바꿨을 때는 계산이 1.7배인데 실측 1.54배여서, 토큰마다 드는 고정 비용만큼 이득이 줄었다.
- 캐시 인지 스트리밍 음성인식이 버퍼 방식과 다른 점은? 겹치는 창을 다시 인코딩하지 않고 층별 표현을 캐시에 둬서 각 프레임을 한 번만 계산한다. 청크는 (오른쪽 문맥 + 1) × 80ms 이다.
- 자기회귀 음성합성에서 첫 소리를 줄이는 방법은? 스트리밍으로 처음 몇 프레임이 나오면 바로 재생한다. 재생이 합성보다 느려야(실시간 계수 < 1) 끊기지 않는다.
외부 근거: 논문과 공식 자료로 확인한 것
이 글의 수치는 직접 잰 값이고, 원리 서술은 아래 자료로 대조했습니다. 외부 수치는 모델, GPU, 부하가 달라 직접 비교하지 않고 구조와 방향의 일치만 판정했습니다.
| 주제 | 자료와 확인한 위치 | 확인한 내용과 조건 | 이 글과의 관계 |
|---|---|---|---|
| 디코딩의 메모리 한계 | Pope 외, 「Efficiently Scaling Transformer Inference」, arXiv 2211.05102, 2절. Yuan 외, 「LLM Inference Unveiled: Survey and Roofline Model Insights」, arXiv 2402.16363, 3.1.1절 | 배치와 문맥이 작으면 가중치를 읽는 시간이 지배하고, 배치가 크면 연산 한계로 바뀜. 가중치를 압축해도 연산 한계 구간에서는 시간이 줄지 않음(Llama-2-13b, 문맥 1,024) | 지지. 2절 원리와 같음. 「상한 = 대역폭 ÷ 가중치 바이트」 식을 한 줄로 적은 논문은 찾지 못했고, 이 글의 식은 KV 읽기 항을 뺀 단순화 |
| 대역폭 활용률 | Databricks 기술 블로그 「LLM Inference Performance Engineering: Best Practices」(2023-10-12) | 모델 대역폭 활용률(MBU)이 배치 1 에서 2×H100 60%, 4×A100-40GB 55%(TensorRT-LLM, 텐서 병렬). 배치가 커지면 낮아짐 | 제한적으로 지지. 분모가 사양서의 최고 대역폭이라 우리 86~98%(분모는 직접 잰 읽기 대역폭)와 같은 척도가 아님 |
| 활용률의 편차 | Chen, 「Memory-Bound but Not Bandwidth-Limited」, arXiv 2605.30571(2026, 단독 저자 프리프린트, 동료 심사 미확인) | 배치 1 에서 PyTorch 기본 경로 기준 L4 에서 약 81%, H100 에서 약 27% 를 보고하고 실행 시작 비용 때문이라고 설명 | 제한적으로 지지. 고대역폭 GPU 에서는 같은 도달률이 나오지 않을 수 있음. 우리 값은 8GB급과 24GB급 두 GPU 에서만 확인 |
| VoxCPM2 구조 | 「VoxCPM2 Technical Report」, arXiv 2606.06928, 3.1절, 3.7절, 4.6절 표 11 | 25Hz 잠재 프레임 4개를 한 패치로 묶어 6.25Hz 자기회귀(한 걸음 = 160ms). 확산 단계마다 확산 모듈을 두 번 계산(CFG). 소비자용 상위급 GPU(24GB급) 한 장 PyTorch 실시간 계수 0.30, 피크 VRAM 약 8GB, 서빙 엔진 0.13 | 제한적으로 지지. 길이 비례 구조는 맞음. 걸음당 시간의 내역과 고정 비용 0.23초는 논문에 근거가 없고, 우리 기울기 0.475 는 논문보다 1.6배 느림 |
| 프레임 쌓기 | Fejgin 외(NVIDIA), 「Frame-Stacked Local Transformers for Efficient Multi-Codebook Speech Generation」, arXiv 2509.19592, ICASSP 2026 | NanoCodec(초당 21.5프레임, 코드북 8개) 기반 영어 모델에서 쌓기 계수 2 일 때 자기회귀 국소 트랜스포머가 병렬 예측 기준선보다 2.1배 빠름 | 관련. Magpie 의 「한 번에 두 프레임」 설명과 같은 방법이나, 공개된 다국어 모델과 같은 실험 모델인지는 모델 카드가 밝히지 않음 |
| 캐시 인지 스트리밍 ASR | Noroozi 외, 「Stateful Conformer with Cache-based Inference for Streaming ASR」, arXiv 2312.17279, ICASSP 2024, 표 1, 표 2 | 약 1.14억 파라미터, LibriSpeech test-other, RNNT 의 단어 오류율이 미리 보는 양 0ms 9.5%, 240ms 7.8%, 520ms 7.5%, 1,360ms 6.3%. 버퍼 방식 기준선(RNNT 11.3%, 평균 지연 2,000ms)보다 지연이 짧고 정확 | 지지. 문맥이 길수록 정확해지는 방향. 논문의 「지연」은 청크 크기와 다른 정의 |
| 청크별 한국어 정확도 | nvidia/nemotron-3.5-asr-streaming-0.6b 모델 카드(FLEURS, 언어 지정 모드) |
한국어 글자 오류율 80ms 7.59, 160ms 7.70, 320ms 7.27, 560ms 7.18, 1.12초 7.12(%). 청크 값 80, 160, 320, 560, 1,120ms 가 att_context_size 의 (오른쪽+1)×80ms 와 일치 |
지지. 4절 표의 청크 해석과 방향은 같음. 사람 음성 FLEURS 30문장으로 다시 재니 한국어 글자 오류율이 청크 1,120에서 80ms 까지 5.8, 5.9, 5.6, 6.2, 6.1% 로 평평해 카드(7.12~7.70%)와 어긋나지 않음. 합성 음성 12개에서 1,120ms 만 나빴던 것은 재현되지 않음 |
| 비원어민 음성 | McGuire, arXiv 2503.06924, 표 2, 3(L2-ARCTIC 읽기 음성). Kim 외, LearnerVoice, Interspeech 2024, arXiv 2407.04280. Oh 외, ETRI Journal 42(5), 2020 | 읽기 음성에서 Whisper large-v3 의 오류율이 원어민 0.007, 한국어 화자 0.033(약 4.7배), 중국어 화자 0.053, 베트남어 화자 0.124. 한국인 학습자의 영어 자발 발화 WER 19.18%(원어민 대화와 비슷한 수준이라 자발 대화 특성도 큰 요인). 구형 한국어 모델은 원어민 3.42%, 비원어민 36.74%(음절 오류율) | 지지. 합성 음성 값이 낙관적이라는 서술의 근거. 합성 음성 값에 곱할 일반 배율은 근거가 없음. 한국어·일본어·중국어 학습자 음성의 현대 모델 측정은 열 수 있는 자료에서 찾지 못함 |
벤더 수치(모델 카드의 H100 동시 스트림 등)는 조건이 카드에 일부만 적혀 있어 방향만 인용했습니다. PNAS 와 일부 모델 카드는 접근이 제한되어 다른 사본이나 논문으로 대신 읽었고, 열지 못한 자료의 수치는 쓰지 않았습니다.
확인하지 못한 것
- 66% 와 86~98% 의 차이의 원인. 대역폭은 두 GPU 모두 직접 쟀지만, 24GB급은 llama.cpp 의 4비트 모델, 8GB급은 vLLM 의 bf16·fp8 모델이라 엔진과 형식이 다릅니다. 같은 GPU 에서 같은 모델을 두 엔진으로 재야 가를 수 있습니다.
- 66% 의 나머지 34% 가 어디로 가는지. KV 캐시 읽기, 어텐션, 커널 간격을 분해하지 않았습니다.
- VoxCPM2 의 프레임당 76ms 의 내역과 확산 반복 횟수를 줄였을 때의 효과, 고정 비용 0.23초의 정체.
- 스트리밍 합성의 첫 소리 시간과 스트리밍 음성인식의 실제 확정 지연. 측정에서 스트리밍 경로를 쓰지 않았습니다.
- 12B 모델의 16비트 속도(37 tok/s 는 계산). 작은 모델에서는 정밀도 효과가 계산보다 작았습니다.
- 동시 요청 16개를 넘는 구간. 연산이 한계로 바뀌는 지점(bf16 약 130개, fp8 약 64개)은 계산이고 측정하지 않았습니다.
- 입력 처리의 짧은 입력 고정 비용의 정체. 256토큰에서 속도가 낮아지는 이유(요청 처리, 커널 시작 등)를 분해하지 않았습니다.
- 다른 추론 엔진과의 비교. 직접 검증은 vLLM 한 가지 엔진으로 했고, 위의 12B 측정(llama.cpp)과 엔진을 맞추지 않았습니다.
- 모델 구조에 대한 설명은 공식 문서의 서술을 따랐고 논문 원문까지 읽지는 않았습니다.
참고 자료
- Nemotron Speech ASR 의 캐시 인지 스트리밍 설명: https://huggingface.co/blog/nvidia/nemotron-speech-asr-scaling-voice-agents
- Nemotron 3.5 ASR 모델 카드: https://huggingface.co/nvidia/nemotron-3.5-asr-streaming-0.6b
- VoxCPM: https://github.com/OpenBMB/VoxCPM
- Magpie TTS 설명: https://huggingface.co/blog/nvidia/magpie-tts-multilingual-voice-agents
- 이 시리즈의 20편(실측), 8편(KV 캐시 크기 계산), 4편(vLLM 내부)
확인한 버전과 날짜
2026-10-06 기준. llama.cpp b11429, Gemma 4 12B QAT q4_0, vLLM 0.31.0(Qwen3 0.6B·1.7B·4B-Instruct-2507 FP8 로 대역폭·동시성·입력 처리 검증), VoxCPM2(voxcpm 2.0.3), Nemotron 3.5 ASR Streaming 0.6B, NeMo 3.0.0.