<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/"><channel><title>MoE | The Logos</title><link>https://thelogos.dev/tags/moe/</link><description>기술이 설명하지 못하는 삶을, 신앙과 철학으로 묻습니다. 기독교 신앙에 뿌리를 둔 엔지니어의 관점.</description><generator>Hugo 0.168.0</generator><language>ko-KR</language><managingEditor>The Logos</managingEditor><webMaster>The Logos</webMaster><lastBuildDate>Thu, 29 Oct 2026 03:40:09 +0000</lastBuildDate><atom:link href="https://thelogos.dev/tags/moe/index.xml" rel="self" type="application/rss+xml"/><item><title>토큰에서 답변까지: LLM의 계산과 GPU 데이터 흐름</title><link>https://thelogos.dev/posts/llm-computation-gpu-data-flow/</link><pubDate>Thu, 29 Oct 2026 11:05:00 +0900</pubDate><dc:creator>The Logos</dc:creator><category>engineering</category><category>LLM</category><category>Transformer</category><category>GPU</category><category>Attention</category><category>MoE</category><category>KV Cache</category><guid isPermaLink="true">https://thelogos.dev/posts/llm-computation-gpu-data-flow/</guid><description>&lt;h2 id="llm-전체-구조-시각화--kimi-k3-사례"&gt;LLM 전체 구조 시각화 — Kimi K3 사례&lt;/h2&gt;
&lt;p&gt;전체 93층과 각 층의 연산을 탐색할 수 있습니다. 구조는 모델별 사례이며, 내부 숫자 실험은 교육용 축소 계산입니다.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://thelogos.dev/interactive/llm-spatial-explorer/"&gt;전체 모델 시각화를 큰 화면으로 열기 →&lt;/a&gt;&lt;/p&gt;</description><content:encoded>&lt;![CDATA[<h2 id="llm-전체-구조-시각화--kimi-k3-사례">LLM 전체 구조 시각화 — Kimi K3 사례</h2><p>전체 93층과 각 층의 연산을 탐색할 수 있습니다. 구조는 모델별 사례이며, 내부 숫자 실험은 교육용 축소 계산입니다.</p><p><a href="/interactive/llm-spatial-explorer/">전체 모델 시각화를 큰 화면으로 열기 →</a></p><iframe src="/interactive/llm-spatial-explorer/" title="LLM 전체 구조 시각화 — Kimi K3 사례" loading="eager" allowfullscreen= style="display:block;width:100%;height:900px;max-height:90vh;min-height:680px;border:1px solid #30465d;border-radius:12px;background:#080d17;margin:20px 0 36px;"/><p>이 원본 시각화의 전체 모델 지도·회전·층 선택·GPU/하네스 보기와 수치 실험을 그대로 탐색할 수 있습니다. 실제 가중치나 내부 활성값을 실행·측정하는 화면은 아니며, 숫자 실험은 대표 한 층·단일 헤드·8차원으로 축소되어 있습니다.</p><h2 id="범용-동작-원리">범용 동작 원리</h2><p>문장을 입력하면 모델 안에서는 무엇이 일어날까? 이 글은<strong>자기회귀 Transformer 계열 언어 모델의 대표적인 추론 경로</strong>를 따라간다. 모든 LLM이 동일한 Attention, 메모리 구조, 병렬화 방식을 쓰는 것은 아니다. 특정 제품의 비공개 구현이나 모델별 수치는 다루지 않는다.</p><p>생성 과정의 구조도를 먼저 보고 싶다면<a href="https://thelogos.dev/posts/llm-text-generation-architecture/">LLM 텍스트 생성 아키텍처</a>를 참고하자. 여기서는 그 계산이 GPU에서 어떻게 실행되고 서비스와 어떻게 연결되는지까지 살펴본다.</p><p>먼저 다음 세 층을 나누면 이해하기 쉽다.</p><ul><li><strong>모델의 계산:</strong> 벡터를 변환하고, 문맥 정보를 섞고, 다음 토큰의 점수를 계산한다.</li><li><strong>하드웨어 실행:</strong> 메모리에 있는 숫자를 읽어 연산 장치에서 처리하고 결과를 저장한다.</li><li><strong>서비스와 하네스:</strong> 요청을 전달하고, 대화 문맥과 도구 실행을 관리하며, 결과를 사용자에게 보낸다.</li></ul><h2 id="1-입력-문장은-토큰-id로-바뀐다">1. 입력 문장은 토큰 ID로 바뀐다</h2><p>대화형 서비스는 사용자 문장 외에도 역할, 이전 대화, 시스템 지시 등을 모델에 맞는 형식으로 구성한다. 이<strong>대화 템플릿</strong>은 모델마다 다를 수 있다. 같은 문장을 넣어도 역할 구분이나 특수 토큰을 잘못 구성하면 학습 때와 다른 입력이 된다.<a href="https://huggingface.co/docs/transformers/main/chat_templating">Hugging Face: Chat templates</a></p><p>토크나이저는 문자열을 토큰으로 분할하고 각 토큰을 정수 ID에 대응시킨다. 토큰은 항상 단어 하나가 아니다. 단어의 일부, 문자 또는 바이트에 대응하는 단위가 될 수 있으며, 분할 방식은 어휘와 알고리즘에 달려 있다. BPE, WordPiece, Unigram 등이 대표적인 방식이다. 토큰 ID의 크기는 의미의 크기나 중요도를 나타내지 않는다.<a href="https://huggingface.co/docs/transformers/main/tokenizer_summary">Hugging Face: Tokenization algorithms</a></p><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>대화 메시지 → 모델별 대화 형식 → 토큰화 → 정수 ID 배열</span></span></code></pre></div><h2 id="2-임베딩은-id를-계산-가능한-벡터로-바꾼다">2. 임베딩은 ID를 계산 가능한 벡터로 바꾼다</h2><p>학습된 임베딩 행렬 E에서 토큰 ID에 해당하는 행을 읽는다.</p><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>x_t = E[token_id_t]</span></span></code></pre></div><p>어휘 크기가 V, 벡터 차원이 d라면 E의 모양은 V × d다. 토큰은 d개의 수로 표현된다. 이후 계층은 이 벡터를 문맥에 따라 바꾼다. 순서 정보도 필요하며, 이를 반영하는 위치 표현 방식은 모델마다 다르다.<a href="https://arxiv.org/html/1706.03762v7">Attention Is All You Need, §3.4–3.5</a></p><p><strong>교육용 예시:</strong> d = 4라면 한 토큰을 [0.2, -0.4, 0.7, 0.1]처럼 나타낼 수 있다. 이는 실제 모델에서 추출한 값이 아니다. 각 칸에 ‘문법’, ‘정답’, ‘사물’ 같은 고정 이름을 붙이는 대신, 여러 수와 후속 계산의 관계로 표현을 이해하는 편이 안전하다.</p><h2 id="3-attention과-ffn이-표현을-갱신한다">3. Attention과 FFN이 표현을 갱신한다</h2><h3 id="attention-다른-위치의-정보를-얼마나-가져올까">Attention: 다른 위치의 정보를 얼마나 가져올까?</h3><p>한 헤드의 대표적인 계산은 다음과 같다. X는 현재 계층의 입력 표현이다.</p><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Q = XW_Q, K = XW_K, V = XW_V</span></span><span style="display:flex;"><span>A = softmax(QKᵀ / √d_k + M)</span></span><span style="display:flex;"><span>O = AV</span></span></code></pre></div><p>Q와 K의 내적으로 관련도 점수를 만들고, √d_k로 크기를 조절한다. M은 접근할 수 없는 위치를 막는 마스크다. 자기회귀 생성에서는 미래 토큰을 볼 수 없도록 한다. Softmax로 얻은 가중치 A를 사용해 V를 합친다. 여러 헤드는 서로 다른 투영으로 이 계산을 수행한다. 여기서<strong>Key는 GPU 메모리 주소가 아니라 학습된 벡터</strong>다.<a href="https://arxiv.org/html/1706.03762v7">Attention Is All You Need, §3.2</a></p><h3 id="ffn-각-위치의-특징을-다시-변환한다">FFN: 각 위치의 특징을 다시 변환한다</h3><p>기본적인 FFN은 선형 변환 사이에 비선형 함수를 둔다.</p><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>FFN(x) = φ(xW₁ + b₁)W₂ + b₂</span></span></code></pre></div><p>Attention이 위치 사이의 정보를 섞는다면, 이 FFN은 각 위치의 표현을 변환한다. 잔차 연결은 입력과 변환 결과를 연결하며, 정규화도 함께 사용된다. 활성화 함수, 게이트, 정규화 위치와 잔차 구조는 구현마다 다르다.<a href="https://arxiv.org/html/1706.03762v7">Attention Is All You Need, §3.1–3.3</a></p><h2 id="4-moe는-모델-내부의-선택적-계산이다">4. MoE는 모델 내부의 선택적 계산이다</h2><p>일부 모델은 여러 FFN 모듈인<strong>Expert</strong>와 이를 선택하는 Router를 사용한다. Router가 입력별 점수를 만들고 일부 Expert의 결과를 조합하는 방식이 희소 MoE의 기본 아이디어다. 모든 모델이 MoE를 사용하는 것은 아니며, 선택 개수와 점수 계산법도 다르다.<a href="https://arxiv.org/abs/1701.06538">Sparsely-Gated Mixture-of-Experts 논문</a></p><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>토큰 표현 → Router → 선택된 Expert들 → 결과 결합</span></span></code></pre></div><p>Expert를 곧바로 ‘법률 담당’, ‘코딩 담당’ 같은 사람의 직무와 동일시하면 구조를 오해하기 쉽다. 또한 한 토큰에서 일부 Expert만 계산하더라도, 전체 모델 가중치의 저장 비용까지 같은 비율로 줄어드는 것은 아니다.<strong>활성 연산량과 전체 파라미터 저장량은 별도로 보아야 한다.</strong></p><h2 id="5-gpu에서는-숫자가-저장되고-이동하며-계산된다">5. GPU에서는 숫자가 저장되고 이동하며 계산된다</h2><p>추론 중 다루는 데이터는 크게 세 가지다.</p><table><thead><tr><th>데이터</th><th>역할</th></tr></thead><tbody><tr><td>가중치</td><td>학습으로 정해진 변환 계수</td></tr><tr><td>활성값</td><td>현재 입력을 처리하며 만들어지는 중간 결과</td></tr><tr><td>캐시·상태</td><td>이전 계산에서 다음 생성 단계에 재사용할 정보</td></tr></tbody></table><p>GPU 커널은 주소와 실행 명령에 따라 데이터를 처리한다. NVIDIA CUDA에서는 스레드 블록이 SM에 배치되고, 블록 안의 스레드가 공유 메모리를 활용할 수 있다. 문장의 의미에 따라 특정 트랜지스터를 지정하는 방식으로 이해해서는 안 된다.<a href="https://docs.nvidia.com/cuda/cuda-programming-guide/01-introduction/programming-model.html">NVIDIA CUDA Programming Model</a></p><p>HBM을 사용하는 GPU에서는 대용량 데이터가 HBM에 놓이고, 커널 실행 과정에서 캐시·공유 메모리·레지스터 같은 저장 공간이 활용된다. 다음은<strong>개념도</strong>이며 모든 데이터가 반드시 같은 순서로 통과한다는 뜻은 아니다.</p><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>GPU 외부 메모리 ↔ 캐시 / 온칩 저장 공간 ↔ 연산 장치</span></span><span style="display:flex;"><span> ↕</span></span><span style="display:flex;"><span> 중간 결과의 재사용</span></span></code></pre></div><p>메모리 계층별 용량, 접근 비용, 재사용 방식 때문에 FLOPS만으로 실행 속도를 설명할 수 없다. FlashAttention은 타일 단위 계산으로 HBM과 온칩 SRAM 사이의 읽기·쓰기를 줄이는 대표적인 예다. Attention의 수학적 기능을 유지하면서 데이터 이동을 바꾸는 최적화다.<a href="https://docs.nvidia.com/cuda/cuda-c-programming-guide/#memory-hierarchy">NVIDIA CUDA 메모리 계층</a>,<a href="https://arxiv.org/abs/2205.14135">FlashAttention 논문</a></p><p><strong>용량 계산 예시:</strong> 80억 개 가중치를 각각 2바이트로 저장하면 가중치만 약 160억 바이트, 즉 16 GB가 필요하다. 여기에 캐시, 활성값, 작업 공간 등이 추가된다. 양자화도 비트 수만 곱한 값 외에 스케일·메타데이터 등의 비용을 고려해야 한다. 이 계산은 특정 모델의 실제 배포 메모리 측정값이 아니다.</p><h2 id="6-prefill과-decode-입력-처리와-반복-생성">6. Prefill과 Decode: 입력 처리와 반복 생성</h2><p>입력 문맥을 먼저 처리하는 단계를<strong>Prefill</strong>, 이후 새 토큰을 생성하며 계산을 이어가는 단계를<strong>Decode</strong>라고 구분한다. 입력을 한꺼번에 다루는 Prefill과 달리, Decode에는 앞서 생성한 결과를 기다리는 순차 의존성이 있다. 실제 병목은 배치 크기와 문맥 길이, 하드웨어와 구현에 따라 달라진다.<a href="https://developer.nvidia.com/blog/mastering-llm-techniques-inference-optimization/">NVIDIA: Mastering LLM Techniques — Inference Optimization</a></p><p>일반적인 causal self-attention에서는 이전 토큰의 Key와 Value를 계층별로 저장하는<strong>KV 캐시</strong>를 활용한다. 새 토큰을 처리할 때 과거 K/V를 전부 다시 계산하지 않도록 하는 것이다. 문맥이 길어지면 보관하고 참조할 데이터도 증가한다. 캐시는 모델이 새 사실을 학습하여 가중치를 갱신하는 과정과 다르다.<a href="https://huggingface.co/docs/transformers/main/cache_explanation">Hugging Face: How caching works</a></p><p>단순한 전체 문맥 KV 캐시의 저장량은 다음처럼 추산할 수 있다.</p><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>바이트 수 ≈ 2 × L × B × S × H_kv × D_head × b</span></span></code></pre></div><ul><li>2: Key와 Value</li><li>L: 계층 수, B: 배치 크기, S: 저장된 토큰 수</li><li>H_kv: KV 헤드 수, D_head: 헤드 차원</li><li>b: 원소당 바이트 수</li></ul><p>이는 동일한 캐시 구조를 가진 계층을 가정한 텐서 크기 계산이다. 압축 캐시, 슬라이딩 윈도, 다른 상태 저장 방식이나 혼합 구조에는 그대로 적용할 수 없다. 할당 여유 공간 등 실제 구현의 추가 비용도 제외되어 있다.</p><h2 id="7-다음-토큰의-점수가-문장으로-이어진다">7. 다음 토큰의 점수가 문장으로 이어진다</h2><p>마지막 표현에서 어휘별 점수인<strong>Logit</strong>을 계산하고 다음 토큰을 선택한다. 탐욕적 선택은 가장 높은 점수의 토큰을 고르고, 샘플링은 확률 분포에 따라 선택한다. 선택된 토큰이 이후 생성의 문맥에 들어가면서 문장이 이어진다.<a href="https://huggingface.co/docs/transformers/main/generation_strategies">Hugging Face: Generation strategies</a></p><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>마지막 표현 → 어휘별 Logit → 선택 규칙 → 다음 토큰</span></span><span style="display:flex;"><span> ↓</span></span><span style="display:flex;"><span> 다음 생성 단계</span></span></code></pre></div><p>토큰의 확률은 문맥에서 그 토큰을 생성할 가능성이다. 문장의 사실 여부를 별도로 판정한 점수로 읽어서는 안 된다. 매끄러운 답변에도 근거 확인이 필요한 이유다.</p><p>선택된 ID들은 토크나이저의 디코딩 규칙에 따라 텍스트로 복원된다. 서비스는 이를 모아 보내거나 일부씩 스트리밍할 수 있다. 모델의 토큰 단위와 네트워크 전송 단위는 별개의 설계 층이다.</p><h2 id="8-모델-라우팅-하네스를-구분하자">8. 모델, 라우팅, 하네스를 구분하자</h2><p>‘라우팅’이라는 말을 사용할 때는 무엇을 선택하거나 이동시키는지 먼저 확인해야 한다.</p><table><thead><tr><th>구분</th><th>무엇을 하는가</th></tr></thead><tbody><tr><td>네트워크 전달</td><td>사용자 요청과 응답을 서버와 클라이언트 사이에서 전송</td></tr><tr><td>메모리 접근</td><td>주소에 따라 텐서 데이터를 읽고 저장</td></tr><tr><td>Attention</td><td>벡터 간 점수에 따라 정보를 가중합</td></tr><tr><td>MoE Router</td><td>모델 내부에서 계산할 Expert를 선택</td></tr><tr><td>분산 실행</td><td>여러 연산 장치에 작업과 텐서를 배분</td></tr><tr><td>하네스</td><td>도구 호출 실행, 문맥 관리, 결과 확인 등을 조율</td></tr></tbody></table><p>이 표는 서로 다른 추상화 수준을 구분하기 위한 정리다. 예를 들어 MoE의 Expert 선택은 IP 패킷의 목적지를 결정하는 네트워크 라우팅과 다르다.</p><p><strong>모델은 도구 호출 내용을 생성하고, 실행 환경은 그 호출을 수행한다.</strong> 함수 호출 API의 전형적인 흐름은 도구 정의 제공 → 모델의 호출 생성 → 애플리케이션 실행 → 결과 반환 → 후속 응답이다.<a href="https://developers.openai.com/api/docs/guides/function-calling">OpenAI: Function calling</a></p><p>하네스를 설계할 때는 검색 결과의 출처, 입력 검증, 실행 권한, 테스트 결과를 확인해야 한다. 도구를 붙였다는 사실만으로 답변의 정확성이 보장되지는 않는다. 모델의 능력, 사용할 수 있는 정보, 도구의 신뢰성, 검증 절차를 함께 평가하는 것이 좋다.</p><h2 id="정리-같은-요청을-세-가지-관점에서-보기">정리: 같은 요청을 세 가지 관점에서 보기</h2><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>서비스: 요청 수신 → 문맥 구성 → 모델 호출</span></span><span style="display:flex;"><span> → 필요 시 도구 실행 → 응답 전송</span></span><span style="display:flex;"><span>모델: 토큰 ID → 임베딩 → 반복 계층의 계산</span></span><span style="display:flex;"><span> → Logit → 토큰 선택</span></span><span style="display:flex;"><span>GPU: 데이터 읽기 → 병렬 연산 → 저장·재사용</span></span><span style="display:flex;"><span> → 필요 시 장치 간 교환</span></span></code></pre></div><p>이 세 흐름을 구분하면 새로운 모델을 볼 때도 확인할 항목이 분명해진다. 어떤 토크나이저를 쓰는지, 문맥을 어떤 계산과 상태로 처리하는지, 무엇이 메모리를 차지하는지, 어떤 작업을 모델 밖에서 실행하는지를 각각 살펴보면 된다.</p><p>교육용 시각화의 블록과 화살표는 계산 관계를 이해하는 도구다. 실제 칩의 물리적 배치, 실제 모델의 내부 활성값, 측정된 성능과는 구분해서 읽어야 한다.</p><h2 id="보조-학습">보조 학습</h2><p>기초 행렬 계산을 더 작게 나누어 보고 싶다면<a href="/interactive/llm-lab/">1계층 Transformer 토큰 계산 실험실</a>을 참고할 수 있습니다.</p>
]]></content:encoded></item></channel></rss>