Lumen 사이드 2편 – 표준 도구 두고 왜 컴파일러를 직접 짰나

Detailed shot of an open book emphasizing printed

1편에서 LLM 추론이 컴퓨터 입장에서 정확히 어떤 일인지 큰 그림을 잡았어요. 670MB 도시 청사진을 한 번 통과시켜서 다음 단어 1개 결정하는 일이라고. 이번 편은 좀 더 회고 톤이에요. 이 일을 왜 직접 짜려고 했나가 주제거든요.

솔직히 말하면 이번 결정 자체가 “효율로만 따지면 잘못된 결정”이에요. 그걸 알면서도 짰고, 짠 다음에도 “잘 짠 결정이었다”고 정리할 수 있는 이유를 풀어볼게요. 작년 가을부터 시작한 사이드들이 9개월씩 흐지부지 끝났는데, 이번 사이드만큼은 다르게 끝낼 수 있었던 배경도 같이.

혹시 사이드 프로젝트 시작하려는데 “이미 잘 짜진 도구가 있는데 굳이 내가 다시 짤 이유가 있나” 고민하시는 분이라면 도움이 될 거 같아요. 저도 6주 전까지 같은 고민이었거든요. 결론부터 말하면, 도구가 목표면 짜지 말고, 지식과 경험이 목표면 짜라는 거예요. 이 차이가 진짜 큰 차이거든요.

나무 책상 위의 코딩 화면 노트북

이미 있는 거대 건설 회사 – llama.cpp 얘기

LLM을 빠르게 돌리기 위한 도구는 이미 충분히 좋은 게 있어요. llama.cpp가 대표적입니다. 내부 엔진을 ggml이라고 부르는데, 두 이름은 거의 같은 의미로 쓰여요. 게오르기 게르가노프(Georgi Gerganov)라는 분이 2023년에 시작해서 지금은 수백 명이 기여하는 오픈소스. GitHub star 8만 개. 어마어마한 도구예요.

도시 건설 비유로 풀면 llama.cpp는 이런 회사예요.

  • 5년 이상 누적된 거대 건설 회사
  • 거의 모든 종류의 도시 청사진(LLM 모델 양식) 처리 가능 — Llama, Qwen, Mistral, Phi 등 수십 종
  • 시설별로 손코딩된 매뉴얼이 수백 개 — 각 시설(매트멀 형상)에 정확히 맞춤
  • 사용자 수가 많아 문제 빨리 잡힘, 새 청사진 양식(새 모델)도 며칠 안에 지원
  • CPU·GPU 다 지원. Mac M1/M2 metal, NVIDIA CUDA, AMD ROCm, OpenCL 등 거의 모든 백엔드
  • 한국어 모델(Qwen, Llama-Korean 등)도 별도 패치 없이 그대로 동작

요약하면 이미 최적화가 잘 되어 있는, 잘 작동하는 도구예요. 저도 사이드 시작하기 전에 llama.cpp 한 번 깔아서 Qwen2.5-0.5B 돌려봤거든요. 5분 만에 동작하더라구요. 답도 잘 나오고 속도도 빠르고. “이걸 직접 짤 이유가 있나” 의심이 슬쩍 들 정도였어요.

근데 우리는 이걸 안 쓰고 작은 건축가 한 명이 처음부터 짜기로 했습니다. Lumen이 그거예요. 왜 그랬을까요. 거대 건설 회사 두고 작은 건축가 한 명이 자기 도시 짓겠다고 나선 거니까 이상해 보일 수 있죠. 솔직히 부모님 입장에서 보면 “그 시간에 회사 일이나 더 잘하지” 싶을 만한 결정이에요.

효율로만 따지면 잘못된 결정

가장 먼저 인정하고 시작합니다. 목표가 “LLM을 빠르게 돌리는 도구를 만든다”는 거였다면 이건 잘못된 결정이에요. 거대 건설 회사 llama.cpp를 그냥 고용하는 게 훨씬 빠르고 안정적입니다. 우리가 6주 동안 짠 결과의 멀티스레드 성능은 llama.cpp의 약 77%. 6주 더 짜도 90% 따라가기 어려워요. 5년 vs 6주의 차이거든요.

직접 짜는 게 효율로만 따지면 안 좋은 이유는 명확합니다.

  • 시간: 똑같이 동작하는 걸 만드는 데 6주 이상. llama.cpp 설치는 5분.
  • 품질: 5년 누적 코드를 단기간에 따라잡기 어려움. 버그도 많고, 새 모델 지원도 늦고, OS 호환성도 부족.
  • 유지 보수: 우리만 쓰는 코드라 외부 사람의 개선이 들어올 일 없음.
  • 모험: 같은 기능 만들면서 새 기능을 0개 추가했음. 똑같은 일을 다른 방식으로 다시 한 거예요.

이 4가지를 다 알면서도 짰어요. 그 이유는 목표가 “도구”가 아니라 “경험과 지식“이었기 때문입니다.

이게 사이드 프로젝트의 핵심 정의예요. 도구가 목표면 사이드를 만들 게 아니라 그냥 좋은 도구 골라 쓰면 돼요. 사이드를 만드는 이유는 도구를 만드는 과정에서 머릿속에 들어가는 지식·경험·메타 패턴이에요. 결과물은 그 부산물이고요.

저도 이거 정리하기 전엔 좀 헷갈렸어요. “사이드도 결국 결과물이 중요하지 않나?” 싶었거든요. 근데 막상 6주 끝나고 결과 손에 쥐어 보니 진짜 가치는 측정 인프라랑 회고 블로그 17편이었어요. 코드 자체는 llama.cpp가 더 잘 만든 거 인정하고, 우리 코드는 그냥 우리가 잘 이해하는 코드일 뿐이에요. 그 차이가 진짜 자산이고요.

그리고 한 가지 더. 사이드를 “도구 만들기”로 잡으면 끝이 안 보여요. 5년 도구 따라잡으려면 5년 걸리는 거고, 그 동안 도구 작자들은 또 앞서 나가요. 영원히 못 따라잡는 레이스. “지식과 경험”으로 잡으면 6주에 끝나요. 6주 안에 충분한 경험과 측정 데이터가 쌓이고 release tag 박을 수 있어요.

책으로 배운 지식과 직접 짠 지식의 차이

LLM 추론을 책으로 배운다고 가정해 봅시다. Engineering a Compiler(컴파일러 책), High Performance Computing(고성능 컴퓨팅), llama.cpp 소스 코드 분석 글들, 양자화 논문 등을 다 읽는다고 합시다. 100시간 정도 읽으면 이런 지식이 머리에 들어와요.

  • LLM은 매트멀이 95%
  • SIMD는 한 명령으로 여러 데이터를 동시 처리
  • 양자화는 fp32를 int8로 압축
  • JIT은 런타임에 코드를 생성
  • 어텐션은 시퀀스 길이의 제곱 비용
  • 메모리 대역폭이 코어 수와 무관하다

100시간 후 이 지식이 머리에 있어도 다음 질문에 답하기 어려워요.

  • “AMD Zen 4 CPU에서 AVX-512가 YMM보다 빠르냐?”
  • “VNNI 가속이 짧은 K 매트멀에 win, 긴 K에 loss인 이유?”
  • “8 스레드 가속이 4배만 나오는 이유?”
  • “prefill batching이 decode 32회보다 빨라야 하는데 왜 느려졌나?”
  • “prefetch 명령이 1 thread는 win인데 8 thread는 -49% 회귀인 이유?”

이 질문들은 책에 답이 없어요. 직접 짜서 측정해야 답이 나옵니다. 책은 “일반 원리”를 주고, 현실은 “그 일반 원리가 이 칩, 이 메모리, 이 OS 조건에서 어떻게 변형되는가”의 문제거든요.

우리가 6주 동안 11번 가설을 세웠는데 그중 8번이 측정으로 부정당했어요(9편에서 자세히). 직관이 자주 틀리는 분야라는 뜻이에요. 책 100번 읽어도 직관이 안 늘어나고, 한 번 직접 짜고 측정하면 그 직관 1개가 정확히 보정됩니다.

이게 사이드 시작 전엔 잘 와닿지 않았어요. “내가 책 잘 읽고 머리에 잘 정리하면 비슷한 지식 아닌가?” 싶었거든요. 근데 막상 11번 측정 부정 당해 보니까 그게 아니더라구요. 책의 일반 원리는 “초기 가설”을 세우는 데는 도움 되지만, 그 가설이 맞을 거라는 자신감을 만들어 주진 않아요. 자신감은 측정에서만 옵니다.

측정으로 부정되는 게 정상이라는 걸 받아들이고 나면 사이드의 호흡이 바뀌어요. “가설 짜고 → 짜고 → 측정 → 부정 → 다음 가설”의 사이클이 자연스러워져요. 1주에 win이 한 번도 없어도 부정 데이터가 누적된 거니까 진척이 있는 거예요. 이 마음가짐이 책으로는 안 들어와요. 책 저자가 책에서 “여러분, 부정도 자산입니다” 한 줄 적어도 그게 진짜 마음에 새겨지진 않아요. 부정 8번 직접 겪어야 들어와요.

한 번 지어본 지식의 구체적 모양 – AVX-512 ZMM 일화

추상적이라 한 가지 일화를 봅니다. AVX-512 ZMM 명령어가 AVX2 YMM보다 2배 빨라야 한다는 게 책의 상식이에요. ZMM은 한 명령으로 16개 float을 다루고 YMM은 8개를 다루니까 단순 비례로 보면 2배 빨라야 합니다.

저도 처음엔 “당연히 2배”라고 생각했어요. 그래서 Lumen 5편 (SIMD)에서 AVX-512 ZMM 인코더를 짰거든요. 이거 짜는 데 약 5일 걸렸어요. 인코더 짜는 게 그렇게 단순한 일이 아니에요. EVEX prefix 4바이트 디코딩, 레지스터 매핑, 메모리 주소 형식 등 매뉴얼 100쪽 읽어 가면서 한 명령씩 짭니다. 다 짜고 단위 테스트 통과한 다음에 측정해 봤더니…

AMD Ryzen 9 7950X (Zen 4 마이크로아키텍처):
  AVX2 YMM (8 float):  baseline
  AVX-512 ZMM (16 float): -4.5%  (오히려 느림!)

“이게 뭐야” 싶었어요. 책 상식이면 2배인데 측정은 -4.5%. 한참 디버깅하다가 알아낸 게 이거예요. Zen 4가 AVX-512를 내부적으로 256비트 두 번으로 쪼개서 실행하는 “double-pumped” 구현이라서. 청사진은 16차선인데 시공은 8차선 × 2 신호등인 셈. 그래서 실제 처리량은 YMM과 거의 같고, 명령 디코드 오버헤드만 더 큰 거예요.

이 사실은 어디에도 안 적혀 있지 않습니다. AMD Software Optimization Guide PDF 어딘가에 있어요. 그런데 측정으로 부딪치기 전에는 그 문서 페이지를 펴 볼 이유가 없습니다. 문제에 부딪쳐 봐야 정답을 찾으러 가게 돼요. 200쪽짜리 매뉴얼 다 읽고 시작할 사람은 없잖아요.

그래서 직접 짜본 사람은 책으로만 배운 사람과 같은 사실을 알아도 그 사실의 “맥락”을 압니다. “AVX-512가 Zen 4에서는 YMM과 비슷하다”라는 한 줄 사실 뒤에 “내가 5일 짜고 측정해서 부정당하고 AMD 문서 뒤졌더니 double-pumped였더라”는 경험이 깔려 있는 거예요. 이 경험이 다음 프로젝트에서 결정을 빠르게 만들어 줘요.

예를 들면 1년 후 다른 분야 사이드에서 “Intel CPU에서 새 명령어 추가됐는데 빨라질까?” 같은 가설이 나오면, 책 읽기 전에 50줄 마이크로벤치부터 짜자는 결정이 자연스럽게 나와요. 책에서 “당연히 빠르다”라고 적혀 있어도 그 말을 믿지 않게 돼요. Zen 4의 ZMM 경험이 그 직관을 만들어 준 거예요.

도시 건설로 풀면 이런 거예요. 책에서 “고층 빌딩은 강풍 견디게 짓는다”고 배웠어요. 근데 실제로 한 번 빌딩 시공해 보면 그 지역 특유의 바람 패턴(예: 도시 협곡 효과)을 만나서 강풍 대응이 책의 일반 매뉴얼과 다르게 가야 한다는 걸 알게 됩니다. 책의 일반 지식이 그 지역의 특수 조건을 만나면 어떻게 변형되는지 — 그게 “한 번 지어본 지식”이에요.

이 맥락이 사이드 프로젝트의 진짜 자산이에요. 결과물 자체가 아니라 결과물을 만드는 과정에서 만나는 부정 데이터들이요.

사이드 프로젝트가 만드는 5가지 자산

직접 지어본 사람이 가지게 되는 자산을 5가지로 정리해 볼게요. 이 5가지는 책 100번 읽어서는 안 들어오는 자산이에요.

  1. 직관 보정
  2. 디버깅 깊이
  3. 메타 패턴 누적
  4. GitHub 공개 자산
  5. 동기 부여

한 번에 하나씩 풀어볼게요.

자산 1번 – 직관 보정의 진짜 의미

책의 상식이 어디까지 맞고 어디서 안 맞는지를 알게 됨. 11번 측정 중 8번 부정당하면 “직관은 자주 틀린다”가 체험으로 들어와요. 다음 프로젝트 시작할 때 측정 인프라부터 짭니다. 이게 안 짠 사람과 가장 큰 차이.

구체적으로 어떻게 다르냐면, 측정 안 해본 사람은 “이렇게 하면 빠를 거다”라고 가설 세우고 짜기 시작해요. 짜는 동안 한 번도 의심 안 해요. 다 짜고 나서 측정하면 가속이 없거나 회귀거나. 그제서야 “왜 이러지” 디버깅 시작. 시간 다 까먹은 다음에요.

측정 해본 사람은 가설 세우면서 동시에 “이거 검증할 50줄 마이크로벤치부터 짜자”가 자동으로 나와요. 50줄 벤치가 1시간이면 끝나니까, 1시간 후엔 가설이 맞는지 틀린지 안 다음에 본격 작업 들어가요. 이 마음가짐 차이가 6주 사이드에서 2주를 살려요.

저도 4주차쯤에 이게 체득됐어요. 그 전엔 “이렇게 하면 좋겠지”라고 막연한 기대로 5일 작업했다가 마지막에 측정해서 부정당하는 패턴을 두 번 겪었거든요. 5주차부터는 “가설 – 마이크로벤치 – 측정 – 본격 작업” 순서가 굳어졌어요. 그게 6주 사이드 결말을 가능하게 만든 호흡이었어요.

산업 기어와 기계 부품 클로즈업

자산 2번 – 디버깅 깊이

llama.cpp가 우리 컴퓨터에서 이상하게 동작할 때, 직접 짜본 사람은 어디부터 의심해야 하는지 압니다. 매트멀 형상이 안 맞는지, 양자화 변환이 잘못됐는지, CPU 명령어 호환성 문제인지. 사용자로만 써본 사람은 “왜 이래”로 끝나지만, 짜본 사람은 한 단계 더 들어가요.

도시로 풀면 이래요. 외주 건설사가 지은 빌딩에 누수가 생겼을 때, 본인이 직접 시공해 본 사람은 “방수층이 어느 단계에서 문제 났을지” 짐작이 갑니다. 한 번도 시공 안 해본 사람은 외주사 부르는 것 외에 할 수 있는 게 없어요. 외주사가 와서 “이거 자재 문제예요”라고 해도 그 말이 맞는지 검증할 능력이 없죠.

실제로 회사에서 외부 도구 도입 검토할 때도 이 깊이가 차이를 만들어요. 깊이가 있으면 “이 도구는 우리 워크로드에 안 맞을 수도 있겠다”가 보이고, 깊이가 없으면 벤더 자료 그대로 믿고 도입한 다음 1년 후에 못 쓰는 도구라고 결론 내리는 패턴.

저는 회사에서 정보보안 일을 합니다. 매일 보는 도구가 SIEM, EDR, 취약점 점검 도구 같은 거예요. 이 도구들이 가끔 이상한 동작을 할 때, 도구를 한 번도 짜본 적 없으면 벤더 지원 부르는 것 외에 방법이 없어요. 짜본 사람은 “아 이 부분 패치 우선순위가 이렇겠구나”가 보여요. 사이드 분야가 회사 일과 멀어도 “도구를 짜본 경험”의 메타 능력은 회사 일에도 도움이 되는 거예요.

자산 3번 – 메타 패턴 누적

측정 → 부정 → 인프라 유지 → 다른 조건 기다림. 이런 의사 결정 패턴이 누적돼요. 이게 다음 사이드 프로젝트에서도 그대로 적용됩니다. 완전히 다른 분야(임베디드, 분산 시스템, 무엇이든)에서도 같은 패턴이 작동해요.

저도 이번 Lumen에서 “default-off 인프라 유지” 패턴을 한 번 체험했거든요. VNNI 명령어가 처음 시도에서 -2.7% 회귀였는데 코드 폐기 안 하고 둔 게, 그 다음 phase에서 shape-aware dispatch와 결합해서 win이 됐어요. 부정 후에도 인프라 유지하는 결정이 미래 win의 근거가 된 거예요. 이런 패턴 한 번 체험하면 다음 프로젝트에서도 자연스럽게 “이건 부정됐지만 코드는 살리자”가 나와요.

또 다른 메타 패턴: “commit message에 추측 적지 말기”. Phase 8.D.3에서 “attention이 원인일 것”이라고 commit message에 추측 적었어요. 다음 날 측정해 보니 attention이 아니라 매트멀 codegen이 원인. 그 commit message가 부메랑처럼 돌아와서 자기 자신을 비웃었어요. 그 다음부턴 commit message에 “측정 안 한 추측”은 안 적게 됐어요. 이런 게 다 메타 패턴이에요.

메타 패턴은 분야를 가리지 않아요. 컴파일러 짜다가 배운 패턴이 분산 시스템에서도 작동하고, 모바일 앱에서도 작동해요. 이게 사이드 프로젝트의 진짜 장기 자산이에요. 결과물(Lumen 코드)은 1년 후엔 거의 쓸 일 없겠지만, 메타 패턴은 10년 뒤 다른 프로젝트에서도 살아 있어요.

자산 4번 – GitHub 공개 자산

면접 자리에서 “이런 거 짜봤다” 할 수 있는 코드. 회고 블로그까지 같이 묶으면 “어떻게 의사 결정 했는지”도 보여줄 수 있어요. CV에 적힌 줄과 달라요. 실제 코드, 실제 측정 데이터, 실제 가설 부정 경험이 다 보이거든요.

저도 이번에 Lumen GitHub 정리하면서 회고 17편을 같이 묶었어요. “Phase 8.D에서 prefill batching이 2.9배 회귀했고, 다음 날 attention이 원인이라고 commit message에 추측 적었다가, 측정해 보니 매트멀 N=32 codegen이 진짜 원인이더라” 같은 디테일이 다 적혀 있어요. 이게 면접에서 “사이드 뭐 해보셨어요”보다 “이런 식으로 의사결정 합니다”를 보여주는 자료가 돼요.

GitHub star가 많을 필요는 없어요. 우리 같은 학습 목적 도구는 star가 적은 게 정상이에요. 진짜 가치는 코드 + 회고의 묶음이에요. 면접관이나 동료가 “이 사람 어떻게 일하는 사람인지”를 1시간 정도 보면 알 수 있는 자료. 이게 진짜 자산이에요.

또 한 가지 부수 효과. 회고 블로그 쓰면서 “내가 진짜로 뭘 배웠는지”가 정리돼요. 머릿속에 흐릿한 상태로 있던 경험이 글로 적으면 명확해져요. 글로 안 정리하면 6개월 후에 거의 다 잊어요. 17편 글 쓴 게 6주 사이드의 가장 큰 자산일 수도 있어요.

자산 5번 – 동기 부여

책만 읽으면 6주째에 흐지부지됩니다. 작동하는 결과물이 매 commit마다 늘어나는 게 동기 부여로 작동해요. v0.1.0에서 “안녕”이라는 한국어 토큰 하나가 컴퓨터에서 처음 나왔을 때의 감동이 기억에 박힙니다. 첫 입주민이 자기 도시에 이사 온 순간 같은 감동. 그 감동이 다음 phase의 연료가 돼요.

이게 책 읽기랑 진짜 다른 점이에요. 책은 100쪽 읽어도 “내가 뭘 만든 거지?”라는 결과물이 없어요. 직접 짜면 첫 주에 21개 단위 테스트 통과하는 매트멀 파서가 손에 있고, 둘째 주에 자체 매트멀이 naive와 비트 단위로 똑같이 작동하고. 매주 결과물이 늘어나니까 6주가 짧게 느껴져요.

저는 직장인이고 두 아이의 부모예요. 사이드에 할당 가능한 시간이 매일 1~2시간. 이 시간에 책만 100시간 읽으면 6주가 길게 느껴져요. 같은 시간에 직접 짜면 매주 commit이 쌓이고 단위 테스트 통과 횟수가 늘어요. 같은 시간이라도 직접 짜는 쪽이 호흡이 가벼워요. 동기 부여가 곧 호흡이거든요.

한 가지 팁. 동기 부여 끊기지 않으려면 매 commit이 “동작하는 상태”여야 해요. 다음 commit 시작할 때 직전 commit에서 작동하던 게 더 잘 작동하는 식. 동작 안 하는 단계가 며칠 누적되면 동기가 빨리 떨어져요. Lumen은 매 phase가 “기존 기능 유지 + 새 기능 추가”로 갔어요. 회귀가 있으면 그 commit 안에서 막아요. 이 호흡이 6주에 결말을 봐 준 결정적 요인이었어요.

그래도 효율은 효율이다 – 무엇을 포기하나

직접 짜기로 결정하면 포기하는 것들이 명확해요. 이걸 미리 알아야 6주째에 후회 안 합니다.

  • production-ready 도구를 만들겠다는 욕심: 5년 누적된 도구를 따라잡기 어려움. 그건 인정하고 시작하세요. 목표는 “내가 이해한 LLM 추론”이지 “더 빠른 llama.cpp”가 아닙니다. 작은 건축가 한 명이 거대 건설 회사를 이기는 게 목표가 아니에요. 그 건축가의 머릿속에 도시 시공의 전 단계가 들어가는 게 목표.
  • 빠른 결과: 첫 commit이 의미 있는 결과를 내는 데 1~2주 걸려요. 본격 가속이 보이는 데는 3~4주. 매일 작은 진척만 누적됩니다.
  • 외부 사용자: 우리만 쓰는 도구라 GitHub star 1000개 같은 건 어려워요. 그건 곁가지로 두세요. 진짜 도구로 쓰는 사람은 llama.cpp 쓰지 우리 거 안 써요.
  • 새 기능 추가의 짜릿함: 같은 기능을 다른 방식으로 만드는 거라, “이거 신기능 추가했다” 같은 짜릿함은 적어요. 대신 “이거 측정해 봤더니 직관이 틀렸다” 같은 발견의 즐거움이 채웁니다.

이 4가지를 받아들이고 들어가야 흐지부지 안 됩니다. 저도 사이드 처음 시작할 땐 “어쩌면 GitHub star 많이 받을 수도 있지 않을까” 같은 욕심이 살짝 있었는데, 2주차쯤에 인정하고 내려놨어요. 그 인정이 있어야 매 phase가 가벼워져요.

그리고 인정을 안 하면 6주째에 무너져요. “5주 동안 짰는데 ggml보다 느리네”가 충격으로 다가오거든요. 처음부터 “ggml보다 느릴 것이고, 그게 정상이고, 우리 목표는 다른 것”이라고 받아들이고 가면 5주째 측정 결과가 충격이 아니라 데이터로 보여요.

9개월 흐지부지 끝낸 사이드들이 가르쳐 준 것

이건 좀 다른 얘기인데, Lumen 시작할 때 가장 많이 의심한 게 “또 흐지부지 끝나는 거 아닐까”였어요. 작년 가을부터 시작한 사이드들이 9개월씩 흐지부지 끝나 있었거든요. 책상 위에 그 사이드 자료들이 그대로 쌓여 있고, GitHub 비공개 레포는 마지막 commit이 3개월 전.

그 사이드들에서 배운 패턴을 정리하면 이래요.

패턴 1 – 첫 commit이 너무 거대했다

“전체 아키텍처를 다 그려놓고 시작하자”는 욕심이 매번 막혔어요. 아키텍처 도면 그리는 데 일주일 쓰면 둘째 주에 첫 commit인데, 그 첫 commit이 너무 무겁고 정답 검증이 안 되니까 진척감이 없어요.

Lumen은 첫 commit이 그냥 빈 Cargo.toml + 한 줄 README였어요. 그 위에 작은 milestone 하나씩 쌓아 올라간 게 맞았어요. “한 줄 매트멀 파싱 통과”가 첫 milestone, 그 다음이 “21개 단위 테스트 통과”, 그 다음이 “자체 매트멀이 naive와 비트 동일”식.

패턴 2 – 결과물 검증 없이 짰다

작년 사이드 중 하나는 한국어 형태소 분석기였는데, 짜는 동안 “이게 맞는 거 맞아?”라는 검증이 없었어요. 끝까지 짠 다음에야 측정해 보니 기존 도구보다 정확도 낮고 속도 느렸어요. 그 시점엔 이미 너무 많이 짜서 어디 고쳐야 할지도 모르는 상태.

Lumen은 매 phase마다 naive 구현과 비트 단위 비교 + ggml과 속도 비교를 자동화했어요. 그래서 매 commit이 검증된 상태로 누적됐어요. 회귀가 있으면 그 commit에서 막혀요. 6주 동안 정답성 문제로 1주 이상 잃은 적 없어요.

패턴 3 – 잘 끝낼 줄 몰랐다

작년 사이드들이 흐지부지 끝난 이유 중 하나가 “끝낼 줄을 몰라서”예요. 매일 더 짤 게 보이니까 계속 짜다가 어느 순간 동기 부여 떨어져서 손 놓는 패턴.

Lumen은 v0.5.0에서 release tag 박고 maintenance mode 선언으로 의식적으로 끝냈어요. “더 짤 게 있지만 여기서 일단 매듭짓자”는 결정. 그래서 결과물 + 회고가 손에 남았어요. 사실 ROADMAP.md에 다음 cycle 항목이 12개 있는데, 그건 다음 사이드(또는 새 사이드)에서 다시 시작.

이 3가지 패턴이 9개월 흐지부지 사이드들이 가르쳐 준 거예요. Lumen은 이걸 의식적으로 회피하려고 했고, 다행히 6주에 결말이 났어요.

사이드 시작하시려는 분이 이거 보시면 한 번 생각해 보세요. “내가 이 사이드의 v0.5.0에서 멈출 수 있는가”. 답이 “글쎄”면 시작 전부터 흐지부지 가능성이 높아요. “그 시점에 release tag 박고 maintenance mode 선언하자”는 결정이 가능해야 사이드가 결말을 봅니다.

Lumen이 결국 얻은 것

6주 작업의 정직한 결과를 미리 정리합니다. 시리즈 후반부 편들에서 어떤 일들이 일어나는지 미리 그림이 잡혀요.

  • v0.1.0 → v0.5.0 (총 5번 release)
  • 단위 토큰 생성 속도 약 15배 가속 (4.43 → 67 토큰/초)
  • llama.cpp와 비교해서 8 스레드 격차 1.30배 (쫓아가는 위치)
  • 단일 스레드에서는 llama.cpp보다 13% 빠름 (의외의 발견)
  • 측정-주도 의사 결정 11회 (가속 2, 진단 1, 부정 8)
  • 회고 블로그 17편
  • GitHub 공개 코드 약 1만 라인 Rust + 50KB 정도 IR/codegen 디자인

이 중에 가장 큰 자산은 사실 부정된 8번회고 블로그 17편입니다. 가속 2번보다 이게 더 가치 있어요. 왜냐하면 가속은 다른 사람도 비슷한 패턴이 가능하지만, 부정 사례 + 진단 패턴은 같은 분야에 한 번 직접 발 디뎌야만 얻는 자산이거든요.

거대 건설 회사가 지은 빌딩 옆에서 작은 건축가가 자기 빌딩 하나 지으면서 11번 시공 시도하고 그중 8번이 잘 안 됐어요. 1년 후 다른 분야 빌딩(예: 임베디드 시스템, 분산 시스템) 시공할 때 그 11번 경험이 처음 시공자와 차이를 만들어요.

그리고 “단일 스레드에서 llama.cpp보다 13% 빠름”이라는 의외 발견도 자산이에요. 6주 노력으로 5년 도구를 한 차원에서 이긴 거니까. 다른 차원(8 스레드)에서는 졌지만, 이긴 차원이 하나라도 있다는 게 중요해요. “이래서 직접 짠 이유가 있구나” 정리 가능. 책으로만 배웠으면 절대 못 얻었을 수치예요.

물론 이 +13%는 우연일 가능성도 있어요. ggml이 1 thread에 최적화를 덜 했고 우리는 1 thread를 잘 봤을 수도. 그래도 측정 데이터는 데이터예요. “직접 짜본 사람이 표준 도구보다 한 차원에서는 +13% 빨랐다”는 사실 자체가 자산.

직접 짜는 게 안 맞는 상황도 있다

균형을 위해 반대 케이스도 짚고 갑니다. 다음 같은 상황이라면 직접 안 짜는 게 맞아요.

  • 회사 일이 이미 비슷한 분야: 매일 8시간 쓰는 분야를 또 사이드로 하면 호흡이 빨리 무거워져요. 사이드는 회사 일의 휴식 영역이어야 해요.
  • 결과물을 빨리 보여줘야 하는 상황: 면접 마감 1달 같은 시점이면 직접 짜기보다 llama.cpp로 데모 만드는 게 훨씬 빠릅니다.
  • 목표가 학습이 아니라 도구: 학습이 목표가 아니라 진짜로 빠른 LLM이 필요한 거라면 직접 짜지 마세요. 도구를 잘 골라 쓰는 게 더 능력입니다.
  • 이미 잘 알고 있는 분야: 이미 잘 아는 걸 또 짜면 직관 보정이 안 됩니다. 잘 모르는 분야로 가세요.
  • 가족·건강 신호가 무리: 사이드는 회사 외 시간에 짜는 거라 자기 호흡과 가족 호흡을 살펴야 해요. 둘째 막 태어났거나 가족이 아프면 사이드는 일단 미뤄두세요.

저는 회사에서 정보보안 일을 합니다. 취약점 점검·보안 진단 쪽이에요. 컴파일러와 LLM 추론은 회사 일과 거리가 멀어요. 그래서 사이드로 적합했어요. 만약 백엔드 개발자라면 LLM 컴파일러보다 다른 사이드가 더 좋을 거예요. 사이드 프로젝트의 핵심은 회사 일과 충분히 다른 분야입니다.

또 한 가지. 사이드를 골라야 한다면 “결과물이 동작하는 게 검증 가능한 분야”가 좋아요. Lumen은 매 commit마다 “naive 구현과 비트 단위 동일한가” + “ggml과 비교해서 몇 % 속도인가”가 명확히 검증돼요. 이런 분야가 흐지부지 안 됩니다. 검증이 모호한 분야(예: 디자인 시스템, 글쓰기 도구)는 6주째에 “이게 좋아진 거 맞아?” 의심이 들어요.

저희 집은 첫째가 두 살, 둘째가 곧 태어나요. 매일 1~2시간 정도가 사이드에 쓸 수 있는 시간이에요. 이 호흡으로 6주 사이드가 끝나려면 분야 선택이 중요해요. 분야가 크면 6주 안에 결말 못 봐서 흐지부지될 가능성이 커지거든요. Lumen이 6주에 결말 본 건 LLM 추론이라는 분야가 작은 모델(0.5B) 기준으로는 6주에 가능한 크기였기 때문이에요.

2편 정리

  1. llama.cpp(ggml)이라는 거대 건설 회사가 이미 있다. 효율로 따지면 그걸 고용하는 게 맞다. 우리도 ggml의 약 77% 성능을 6주에 만든 수준.
  2. 그래도 직접 짠 이유는 “지식과 경험”이 목표였기 때문. 책으로 배우는 지식과 직접 짠 지식은 깊이가 다르다. 책 100시간 vs 짜고 측정 한 번의 차이.
  3. 사이드 프로젝트가 만드는 자산 5가지: 직관 보정, 디버깅 깊이, 메타 패턴, GitHub 공개 자산, 동기 부여.
  4. 한 번 지어본 지식의 구체 모양: AVX-512 ZMM이 Zen 4에서 -4.5% 회귀라는 발견. 책엔 적혀 있지만 직접 부딪쳐 봐야 그 사실의 맥락이 들어옴.
  5. 포기해야 하는 것도 명확하다: production-ready, 빠른 결과, 외부 사용자, 새 기능 추가의 짜릿함. 이걸 받아들이고 들어가야 흐지부지 안 된다.
  6. 9개월 흐지부지 사이드들이 가르쳐 준 3패턴: 첫 commit 거대화, 검증 없이 짜기, 끝낼 줄 모르기. Lumen은 의식적으로 회피.
  7. 모든 분야가 직접 짜기에 적합한 건 아니다. 회사 일과 거리가 먼 분야, 학습이 목표인 경우, 결과물 검증 가능한 분야, 가족·건강 호흡이 맞는 시점에 잘 맞는다.

사이드 프로젝트 시작하려는 분이라면 이번 편이 가장 도움 될 거 같아요. 솔직히 1편(LLM 추론 원리)은 컴파일러 짜는 분에게만 직접 적용되지만, 2편(사이드 결정과 자산)은 어떤 분야 사이드든 적용되거든요.

다음 편 미리보기

3편부터는 본격적으로 Lumen 컴파일러의 내부 구조로 들어갑니다. DSL, AST, IR이 정확히 뭐고 왜 필요한지. 1편의 도시 비유에서는 “청사진”이라고 한 줄로 풀었지만 실제로는 청사진을 만드는 과정이 4단계로 나뉘어요. 손 스케치 → 평면도(AST) → 시공 도면(IR) → 현장 작업 지시서(코드 생성)의 4단계. 그 4단계가 무엇이고 왜 그렇게 나누는지를 실제 Lumen 코드의 짧은 예제로 풀게요.

4편은 JIT(Just-In-Time) 컴파일이에요. 이게 진짜 신기한 영역이거든요. 컴퓨터가 실행 중에 자기 자신을 위한 어셈블리 코드를 만들어서 즉시 실행하는 일이에요. “메모리에 코드를 쓰고 그걸 함수처럼 호출”이 어떻게 가능한지를 풀어볼게요.

이 시리즈 본문 전체는 GitHub에도 정리해 뒀어요. github.com/redchupa/lumen/docs/tutorial에서 원문 격으로 보실 수 있어요.

그럼 다음 편에서 뵐게요. 혹시 비슷한 6주짜리 사이드 시작하시는 분 계시면 댓글로 어떤 분야인지 알려주세요. 응원할게요.

댓글 달기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다

위로 스크롤