정채홍 | #ML Engineer
들어가며
지난 블로그 글에서 우리가 토크나이저를 교체하여 비용과 성능을 모두 잡는 방법에 대해서 소개해드렸습니다. 제타에서는 모델의 성능만큼이나 좋은 모델을 더 많은 유저분들에게 빠르고 효율적으로 제공하는 것도 중요합니다. 아무리 성능이 좋은 모델이라도 서빙에 너무 많은 비용이 들거나 속도가 느리다면 실제 서비스에 적용하기 어렵기 때문입니다. 우리는 모델의 성능을 한 단계 더 높이기 위해 기존보다 더 큰 규모의 MoE 모델을 학습했습니다. 그동안 제타를 운영하며 쌓아온 데이터와 학습 레시피를 더 큰 모델에 적용해본 것이죠. 결과는 기대한 대로였습니다. 기존 모델 대비 분명한 성능 개선을 확인할 수 있었습니다.
문제는 그다음이었습니다. 모델의 규모가 커진 만큼 서빙에 필요한 GPU도 늘어났고, 그만큼 비용도 증가했습니다. 성능은 충분히 좋아졌으니, 이제 이 모델을 어떻게 더 가볍고 효율적으로 서빙할 것인가가 다음 과제였습니다.
이번 글에서는 이렇게 학습한 큰 MoE 모델을 실제 서비스에서 효율적으로 활용하기 위해 어떤 실험을 했는지 소개합니다. 결론부터 말씀드리면, 모델을 구성하는 전문가(expert)의 절반을 덜어냈지만 유저 지표에서는 유의미한 차이를 발견하지 못했습니다. 반면 같은 서버에서 처리할 수 있는 대화량은 1.6배로 늘었습니다.
우리가 실험해보려는 모델
우리가 실험해보려는 큰 모델은 MoE(Mixture-of-Experts) 모델입니다. 층마다 여러 개의 전문가를 두고, 라우터가 토큰마다 그중 일부만 골라 통과시키는 구조죠[1].
MoE 모델 구조의 특징은 계산량과 점유하는 메모리가 일치하지 않는다는 점입니다. 토큰 하나가 실제로 통과하는 전문가는 몇 개뿐이라 계산은 가볍습니다. 파라미터 수는 늘리면서도 토큰당 계산량은 그대로 두는 것이 MoE의 출발점이었습니다. 그런데 어느 토큰이 어느 전문가로 갈지 미리 알 수 없으니, 파라미터는 전부 메모리에 올려 둬야 합니다. 전체 파라미터의 압도적인 비중이 이 전문가들입니다.
서빙에서 GPU 메모리를 많이 점유하는 부분은 이 전문가 쪽입니다. 이 전문가들을 가볍게 만들어 점유하는 GPU 메모리를 줄여보려고 합니다.
전문가는 고르게 쓰이지 않는다
먼저 확인해야 할 게 있었습니다. 어떤 전문가들이 어떻게 사용되고 있는가?
실제 서비스 대화를 모델에 통과시키면서, 전문가마다 토큰이 몇 번씩 배정되는지를 전부 세어 봤습니다. 분포는 예상보다 훨씬 기울어 있었습니다.

측정 | 값 |
상위 10%의 전문가가 가져가는 라우팅 | 70.4% |
하위 50%의 전문가가 가져가는 라우팅 | 4.8% |
라우팅의 90%를 덮는 데 필요한 전문가 | 전체의 약 1/3 |
유효 전문가 수 | 전체의 평균 21% |
표 1. 실제 서비스 데이터에서 측정한 전문가 사용량 분포.
마지막 줄의 유효 전문가 수는 라우팅이 얼마나 고르게 퍼져 있는지를 전문가 수로 환산한 값입니다. 전문가 가 받은 라우팅의 비율을 라 할 때, 그 분포의 엔트로피를 지수로 되돌립니다.
모두가 똑같이 쓰이면 는 전체 전문가 수가 되고, 한 명에게만 쏠리면 1이 됩니다. 실험 대상 모델은 전체의 21% 수준이었습니다.
절반의 전문가가 전체 일의 5%도 하지 않으면서, 메모리는 정확히 절반을 차지하고 있었습니다.

깊이에 따라서도 달랐습니다. 입력에 가까운 층은 그나마 여러 전문가가 일을 나눠 갖는데, 출력에 가까워질수록 소수에 쏠립니다. 가장 깊은 층에서는 상위 3개가 라우팅의 절반 가까이를 가져갔습니다.
어떤 전문가를 남겨야 할까 — 세 가지 기준
모델은 우리 서비스 데이터를 다룰 때 보유한 전문가에 비해 훨씬 적은 수만 쓰고 있었습니다. 이제 어떤 전문가를 남길지 정해야 합니다.
전문가를 골라 덜어내는 접근 자체는 이전부터 연구돼 왔습니다[2]. 그런데 기준을 고르는 일은 단순하지 않았습니다. "중요한 전문가"라는 게 무엇인지부터 정해야 하니까요. 단순하게 자주 사용되는 쪽일지, 아니면 적게 사용되지만 사용될 때 큰 일을 하는 쪽일지 정하기 나름입니다. 우리는 성격이 뚜렷하게 갈리는 세 가지를 골라 각각 실험을 해봤습니다.
먼저 표기를 정리하겠습니다.
기호 | 뜻 |
한 층 안의 전문가 | |
캘리브레이션 토큰 | |
토큰 가 라우팅된 전문가 집합 (top-k) | |
라우터가 전문가 에 준 게이트 값 | |
전문가 가 토큰 에 대해 내놓은 출력 벡터 | |
전문가 가 선택된 총 횟수 |
REAP — 지웠을 때 출력이 얼마나 흔들리나
가장 직접적인 발상입니다. 이 전문가를 지우면 층의 출력이 얼마나 달라지는가?
전문가 를 지우면 그 자리로 가던 토큰은 살아남은 다른 전문가 에게 넘어갑니다. 이때 생기는 오차의 상한이 이렇게 잡힙니다[3].
는 가 빠진 뒤 남은 전문가들 사이에서 다시 정규화된 의 게이트 값입니다.
오른쪽을 보면 게이트 값과 출력 크기의 곱이 오차를 지배합니다. 그렇다면 그 항이 작은 전문가부터 지우면 됩니다. 그게 REAP입니다.
앞의 가 중요합니다. 총합이 아니라 선택된 토큰에 대한 평균이라, 몇 번 불렸는지는 점수에서 빠집니다. 그래서 REAP은 "불릴 때마다 게이트도 높고 출력도 큰" 전문가를 남깁니다. 호출이 잦다는 이유만으로는 점수를 얻지 못합니다.
MSAN — 게이트를 아예 보지 않는다
REAP은 라우터를 신뢰합니다. 게이트 값이 높다는 건 라우터가 "이 토큰은 이 전문가한테 맡겨야 한다"고 판단했다는 뜻이니까요.
그런데 게이트 값에는 어떤 데이터로 점수를 쟀는지가 묻어납니다. 라우터의 선택은 캘리브레이션에 쓴 데이터의 분포를 따라가기 때문에, 게이트를 점수에 넣으면 그 데이터에만 맞는 판단이 되기 쉽습니다. MSAN을 제안한 연구는 게이트 가중을 뺄수록 서로 다른 캘리브레이션 데이터 사이의 선택 일치도가 올라간다는 것을 보였습니다. 게이트가 데이터별 선호를 인코딩하고 있다는 뜻이죠[4]. 그렇다면 라우터를 빼고 전문가가 실제로 내놓는 출력만 보면 어떨까요.
게이트가 사라졌고, norm이 제곱으로 들어갔습니다. 제곱은 큰 출력을 더 크게 쳐주는 효과를 냅니다. 한 번씩 강하게 작동하는 전문가가 유리해지죠. 제곱을 빼면 같은 계열의 MAN이 됩니다.
MSAN이 남기는 건 자주 불리지는 않지만 불릴 때마다 확실한 일을 하는 희귀 스페셜리스트입니다.
EasyEP — 모든 토큰을 똑같이 세지 않는다
앞의 둘은 모든 토큰을 똑같이 취급합니다. 그런데 전문가들의 출력이 잔차 흐름에 미치는 영향은 토큰마다 크게 다릅니다. 어떤 토큰은 MoE 블록을 지나도 표현이 99% 이상 그대로인 반면, 어떤 토큰은 확 달라집니다.
갈리는 지점은 여기입니다. 표현이 크게 달라지는 토큰은 그 자리의 전문가를 바꿨을 때 분포가 크게 흔들릴 위험이 큰 토큰입니다. 거꾸로 블록이 거의 아무 일도 하지 않은 토큰이라면, 누가 그 자리에 있었는지는 별로 중요하지 않습니다. 그래서 EasyEP는 토큰마다 이 블록이 표현을 얼마나 바꿨는지를 재서 가중치로 씁니다.
는 MoE 블록에 들어가기 전의 표현, 는 통과한 뒤의 표현입니다. 둘이 똑같으면 , 방향이 크게 틀어질수록 1에 가까워집니다.
이 가중치를 앞서 본 게이트×출력에 곱하고, 이번에는 평균이 아니라 총합으로 모읍니다[5].
앞에 가 없다는 게 특징입니다. 호출 빈도가 그대로 점수에 들어갑니다. 그래서 EasyEP는 REAP·MSAN과 정반대로 "자주 불리는 주력 일꾼"을 남깁니다.

위 도표는 세 기준으로 자른 모델 간에 남은 전문가가 얼마나 겹치는지 측정한 값입니다. REAP과 MSAN은 92.5%가 겹쳤고, EasyEP는 둘 모두와 74~77%만 겹쳤습니다. 어떤 기준을 쓰느냐에 따라 실제로 다른 전문가가 잘려 나갔다는 뜻입니다. 다만 기준이 달라도 4분의 3가량은 여전히 겹쳤습니다.
학습
이제 어떤 전문가들을 잘라야 하는지 기준을 정했습니다. 모델의 각 층마다 점수 상위 개를 남기고, 라우터의 게이트 행렬에서도 잘린 전문가에 해당하는 행을 같이 지웁니다.
학습은 사전학습을 다시 하지 않고, 평소의 SFT를 그대로 진행하였습니다. 세 기준으로 각각 전문가의 절반을 덜어내고, 전부 같은 데이터로 같은 스텝만큼 다시 학습시켰습니다.
두 시점의 loss를 봤습니다. 하나는 step 0, 학습을 전혀 하지 않은 상태의 loss입니다. 다른 하나는 다시 학습을 마친 뒤의 loss입니다. step 0의 loss는 학습 이전에 우리 데이터를 얼마나 잘 파악하는지 간접적으로 확인해보기 위해 측정하였습니다.
후보 | step 0 loss | 최종 loss |
자르지 않은 원본(무프루닝) | 0.8303 | 0.55400 |
REAP 절반 | 0.7902 (1위) | 0.55954 (2위) |
MSAN 절반 | 0.7971 (2위) | 0.56173 (3위) |
EasyEP 절반 | 0.8059 (3위) | 0.55806 (1위) |
표 2. 세 기준의 step 0 loss와 다시 학습한 뒤의 loss.
step 0의 loss는 최종 loss 순위를 결정짓지 않았습니다. step 0 순위는 REAP → MSAN → EasyEP였는데, 최종 순위는 EasyEP → REAP → MSAN이었습니다. 자른 직후에 덜 망가져 있다고 해서 학습을 마친 뒤에도 더 낫다는 보장은 없었던 셈입니다.
그런데 최종 loss의 차이 자체가 아주 작았습니다. 1위와 3위의 간격이 0.0037인데, 같은 설정으로 다시 학습시켜도 loss는 0.003 정도 흔들립니다. 세 기준이 서로 다른 전문가를 골라냈는데도, 그 결과물은 loss만 놓고 보면 구별하기 어려운 수준이었습니다. 대규모 MoE를 압축하고 연속 학습을 붙인 연구도 서로 다른 one-shot 전문가 압축 방법들이 결국 비슷한 성능으로 수렴한다고 보고합니다[6].
결국 loss만으로는 세 기준을 가를 수 없었습니다. 판정을 다음 단계로 넘겼습니다.
내부 평가, 그리고 A/B 테스트
우리는 모델을 내보내기 전에 두 단계를 더 거칩니다. 사람이 직접 학습된 모델을 사용해보는 내부 평가, 그리고 실제 유저 트래픽에 붙이는 A/B입니다.
MSAN 절반은 내부 평가에서 떨어졌습니다. 사유는 "어색하고, 특정 기능이 깨진다"였습니다. loss 차이가 노이즈 수준이었던 걸 생각하면, 실제로 셋을 가른 건 loss가 아니라 이 단계였습니다.
남은 둘, REAP 절반과 EasyEP 절반을 실제 유저에게 내보냈습니다.
제타는 한국·일본에서 WAU 약 300만 규모로 운영되는 서비스이고, 모델 후보를 실제 유저 트래픽에 A/B로 붙여 며칠 안에 지표로 답을 받는 파이프라인을 갖추고 있습니다. 이 중 주요하게 보는 지표는 유저당 이용 시간입니다.

유저당 이용 시간 (무프루닝 = 기준) | REAP 절반 | EasyEP 절반 |
일자별 차이의 평균 | +0.5% | −2.5% |
판정 | 구별 불가 (신뢰구간이 0을 포함) | 열세 (신뢰구간이 0 아래) |
표 3. 같은 예산(절반)에서 기준만 바꾼 A/B 결과. 무프루닝 대비 상대값.
REAP 절반은 무프루닝과 구별되지 않았고, EasyEP 절반은 분명히 밀렸습니다. 같은 양을 잘라냈고 loss 차이는 노이즈 수준이었는데도 그렇습니다.
앞에서 세 기준이 고르는 전문가가 얼마나 겹치는지 봤습니다. REAP과 MSAN은 92.5%가 겹쳤고, EasyEP만 75% 안팎으로 떨어졌죠. 그 차이를 만든 건 호출 빈도를 점수에 넣느냐 하나였습니다. 그 하나가 loss에서는 거의 드러나지 않았는데, 유저 지표에서는 2.5%로 나타났습니다. 자주 불린다는 이유로 남긴 구성이, 불릴 때마다 큰 일을 한다는 이유로 남긴 구성보다 나빴습니다.
이제 기준은 정해졌습니다. 그러면 얼마나 더 자를 수 있을까요?
어디까지 자를 수 있을까
여기서부터는 기준을 REAP으로 고정하고, 남길 비율만 바꿔 가며 전부 같은 조건으로 학습을 진행했습니다.

남긴 전문가 | valid loss | 무프루닝 대비 | 체크포인트 |
전체 | 0.55400 | — | 1.00× |
절반 | 0.55954 | +0.0055 | 0.51× |
7/16 | 0.56355 | +0.0096 | 0.45× |
3/8 | 0.56932 | +0.0153 | 0.39× |
5/16 | 0.57933 | +0.0253 | 0.33× |
1/4 | 0.59092 | +0.0369 | 0.27× |
1/8 | 0.65669 | +0.1027 | 0.15× |
표 4. 남긴 비율에 따른 최종 결과. 모두 동일 데이터·동일 하이퍼파라미터로 같은 길이만큼 학습.
남기는 전문가 수를 줄일 때마다 예상대로 valid loss가 꾸준히 증가합니다. 하지만 절반의 전문가를 줄였을 때의 손실은 valid loss만 두고 보면 원본 대비 큰 차이가 없었습니다. 같은 양을 덜어낼 때마다 치르는 비용으로 환산하면 이 구간이 가장 좋았습니다. 20B에서 1T까지의 MoE 모델을 폭넓게 비교한 연구도, 코드 생성 과제에서는 전문가를 절반 덜어내도 사실상 무손실이었다고 보고합니다[3].
1/4로 줄인 모델부터는 손실이 눈에 띄기 시작하고, 1/8 구간에서는 기울기가 꺾입니다. 같은 양을 덜어내는 데 드는 비용이 직전 구간의 2.8배로 뛰었고, 그때까지의 추세로 외삽한 예측보다도 50% 나빴습니다. "더 자르면 그만큼 나빠진다"는 매끄러운 관계가 성립하는 범위는 1/4까지였고, 그 아래는 다른 국면이었습니다.
유저는 알아봤을까
loss 위에서 본 차이가 실제 유저 지표에서도 같은 모양으로 나타나는지 확인해야 했습니다.

지표 (무프루닝 = 기준) | 절반 | 1/4 | 1/8 |
유저당 이용 시간 | +0.5% | −2.6% | −5.1% |
유저당 메시지 수 | +7.5% | +7.4% | +3.2% |
표 5. 남긴 비율에 따른 실제 유저 트래픽 A/B 결과. 무프루닝 대비 상대값.
절반 프루닝은 무프루닝과 구별되지 않았습니다. 일자별 차이의 평균이 +0.5%이고 신뢰구간이 0을 포함하고 있습니다. 반면 1/4 프루닝은 −2.6%로 0을 벗어납니다. 일자별로 펼쳐 보면 절반 프루닝은 실험 내내 기준선에 붙어 있고, 1/4은 날이 갈수록 벌어집니다.
1/8은 절벽 아래라는 게 유저 지표에서도 확인됐습니다. −5.1%로, 1/4보다 확실히 더 밀립니다. loss 곡선에서 본 꺾임이 유저 쪽에서도 같은 자리에 있었습니다. 성능이 급격히 떨어져 있었기에 실험은 끝까지 보지 않고 조기에 종료하였습니다.
결과적으로 절반 프루닝은 무프루닝과 구별되지 않았고, 1/4은 약 2.6% 하락, 1/8은 사실상 폐기라고 볼 수 있습니다.
처리량이 얼마나 오를까
더 큰 모델로 학습하여 모델 성능을 끌어 올릴 수 있었습니다. 하지만 그만큼 비용이 비싸지기 때문에 바로 제타 서비스에 적용하기에는 무리가 있었죠. 그래서 전문가를 줄이는 쪽으로 방향을 잡았습니다. 전문가를 줄이면 가중치가 가벼워지고, 줄어든 자리가 그대로 KV 캐시로 갑니다. KV 캐시가 모자라면 한 번에 묶어 처리할 수 있는 요청 수가 그만큼 줄어듭니다[7]. 한 대가 받는 대화 수가 늘면 그만큼 적은 GPU로 같은 트래픽을 감당할 수 있고, 그게 곧 비용입니다.
프로덕션과 동일한 서빙 스펙으로 실측한 값을 유저 지표와 나란히 놓으면 결론이 한 장에 들어옵니다.

무프루닝 | 절반 프루닝 | 1/4 프루닝 | |
GPU당 모델 메모리 | 1.00× | 0.53× | 0.29× |
GPU당 KV 캐시 | 1.00× | 1.60× | 1.87× |
유저당 이용 시간 | 기준 | 구별 불가 (+0.5%) | 열세 (−2.6%) |
표 6. 동일 서빙 스펙 실측치와 유저 지표를 합친 최종 결론.
읽는 법은 간단합니다. 절반 프루닝은 품질을 그대로 두고 1.6배를 가져갑니다. 유저가 알아채지 못하는 사이에 같은 GPU가 1.6배의 대화를 받게 된 것이니, 이 줄이 이번 작업의 결론입니다. 실제 배포에서도 서버 한 대가 담당하는 유저 수 설정을 높일 수 있었습니다.
1/4 프루닝은 1.87배를 주지만 유저 이용 시간은 하락합니다. 비용이 많이 줄어도 유저가 체감할 만한 성능 하락이 있는 모델이라 사용할 수는 없지만, 다른 방법으로 비용을 줄이면서도 성능은 유지되는 방법을 계속 찾고 있습니다.
아직 열려 있는 것
여기까지가 잘된 이야기이고, 실제로는 이것저것 더 시도했습니다. 여러 가설을 세워 실험해 봤지만 결과가 잘 나오지 않은 쪽이 훨씬 많았습니다.
두 번에 나눠서 자르기. 한 번에 절반으로 가는 대신, 먼저 조금 자르고 학습시킨 다음 다시 자르는 방식입니다. 조금씩 잘라 모델이 적응할 시간을 주면 성능 손실이 줄어들 것 같았습니다. 하지만 학습 비용과 시간이 추가로 드는 데 비해 한 번에 자른 것과 구별되지 않았습니다.
기준을 더 잘 고를 여지도 남아 있습니다. 이번에는 세 기준 중 하나를 고르는 데서 멈췄지만, 층마다 다른 기준을 쓰거나 기준들을 섞는 방향은 아직 손대지 않았습니다.
무엇보다 지금까지의 판단은 전부 "절반씩 잘라서 한 번 학습시킨" 조건 위에 있습니다. 학습을 더 길게 가져가면 1/4의 손실도 따라잡힐 수 있고, 그러면 "어디까지 자를 수 있나"의 답 자체가 달라집니다. 대규모 연속 학습을 붙였을 때 압축 방법 간 차이가 사라졌다는 보고[6]가 그 방향을 가리킵니다.
마치며
더 큰 모델로 옮겨 품질을 얻고, 전문가를 덜어내 비용을 줄인 방식이 실제로 성립했습니다. 다만 실제 제타에 올리기에는 비용이 여전히 비싸서, 아직 완전히 해결된 건 아닙니다. 그래도 절반을 줄이면 유저 지표에서 구별되지 않았고, 1/4까지는 어느 정도 감내할 손실을 치르면 갈 수 있었으며, 그 아래로는 쓰기 어려웠습니다.
이 글에 적은 건 결론이 난 것들뿐입니다. 정작 재미있는 쪽은 아직 안 끝난 것들이에요. 1/4을 살려낼 수 있을지, 층마다 다른 기준을 쓰면 뭐가 달라질지는 지금도 실험이 돌아가고 있습니다.
스캐터랩 ML 팀에서는 이런 질문을 끝까지 따라가 볼 수 있습니다. 모델을 학습시키는 데서 끝나지 않고, 직접 서빙에 올리고, 실제 유저 지표로 답을 받는 데까지가 한 사람의 일입니다. 지난주에 떠올린 아이디어가 이번 주에 수백만 명의 대화에 닿는 일이 실제로 일어납니다.
우리가 어떤 식으로 일하는지, 이런 실험을 어떻게 굴리는지 궁금하시다면 편하게 티타임 신청해 주세요. 이직을 결심하지 않으셨어도 괜찮습니다. 이 글에 다 쓰지 못한 실패담이 훨씬 많거든요.
참고 문헌
[1] Fedus, W., Zoph, B., Shazeer, N. Switch Transformers: Scaling to Trillion Parameter Models with Simple and Efficient Sparsity. Journal of Machine Learning Research 23, 2022. arXiv:2101.03961
[2] Lu, X. et al. Not All Experts are Equal: Efficient Expert Pruning and Skipping for Mixture-of-Experts Large Language Models. ACL 2024. arXiv:2402.14800
[3] Lasby, M. et al. REAP the Experts: Why Pruning Prevails for One-Shot MoE Compression. ICLR 2026. arXiv:2510.13999
[4] Liu, Z. et al. How to Score Experts for One-Shot MoE Expert Pruning: A Unified Formulation and Selection Principle. arXiv preprint, 2026. arXiv:2606.15716
[5] Dong, Z. et al. Domain-Specific Pruning of Large Mixture-of-Experts Models with Few-shot Demonstrations (EASY-EP). NeurIPS 2025. arXiv:2504.06792
[6] Tang, S. et al. SlimQwen: Exploring the Pruning and Distillation in Large MoE Model Pre-training. arXiv preprint, 2026. arXiv:2605.08738
[7] Kwon, W. et al. Efficient Memory Management for Large Language Model Serving with PagedAttention. SOSP 2023. arXiv:2309.06180
Share article