<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>orangingq</title>
    <link>https://orangingq.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Thu, 11 Jun 2026 19:01:11 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>오렌징큐</managingEditor>
    <image>
      <title>orangingq</title>
      <url>https://tistory1.daumcdn.net/tistory/5368487/attach/5d501c18ebc746db8953974b569d35db</url>
      <link>https://orangingq.tistory.com</link>
    </image>
    <item>
      <title>NVIDIA GPUDirect Async (IBGDA)</title>
      <link>https://orangingq.tistory.com/entry/NVIDIA-GPUDirect-Async-IBGDA</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;참고자료: &lt;a href=&quot;https://developer.nvidia.com/blog/improving-network-performance-of-hpc-systems-using-nvidia-magnum-io-nvshmem-and-gpudirect-async&quot;&gt;Improving Network Performance of HPC Systems Using NVIDIA Magnum IO NVSHMEM and GPUDirect Async | NVIDIA Technical Blog&lt;/a&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;What is IBGDA?&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;GPU Node 간 통신할 때, GPU가 CPU를 시켜서 네트워크 통신하는 게 아니라, &lt;br /&gt;&lt;b&gt;GPU가 직접 NIC(InfiniBand 카드)한테 일을 시키는&lt;/b&gt; 기술.&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-end=&quot;370&quot; data-start=&quot;360&quot; data-ke-size=&quot;size16&quot;&gt;예전 구조: `GPU &amp;rarr; CPU Proxy Thread &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&amp;rarr;&lt;span&gt; InfiniBand NIC &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&amp;rarr;&lt;span&gt;&amp;nbsp;목적지 GPU`&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;676&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mOMwo/dJMcahYWl6I/PwparnlYYOqHQnRLGW8tb0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mOMwo/dJMcahYWl6I/PwparnlYYOqHQnRLGW8tb0/img.png&quot; data-alt=&quot;Fig 1. CPU를 거쳐가야 했던 이전 전송 구조.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mOMwo/dJMcahYWl6I/PwparnlYYOqHQnRLGW8tb0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmOMwo%2FdJMcahYWl6I%2FPwparnlYYOqHQnRLGW8tb0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;686&quot; height=&quot;362&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;676&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Fig 1. CPU를 거쳐가야 했던 이전 전송 구조.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-end=&quot;370&quot; data-start=&quot;360&quot; data-ke-size=&quot;size16&quot;&gt;GPU가 다른 노드의 GPU로 데이터를 보내고 싶을 때, GPU가 CPU한테 먼저 요청을 해서, CPU가 NIC(Netword Interface Card)에게 전달, 그러면 NIC이 데이터를 전송하는 순서였다.&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;370&quot; data-start=&quot;360&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-end=&quot;370&quot; data-start=&quot;360&quot; data-ke-size=&quot;size16&quot;&gt;통신 library &lt;b&gt;NVSHMEM&lt;/b&gt;과 InfiniBand용 NIC (e.g., ConnectX-6 &lt;b&gt;HCA&lt;/b&gt;)가 지원되는 환경 가정,&lt;/p&gt;
&lt;p data-end=&quot;370&quot; data-start=&quot;360&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;좀 더 자세한 기존 순서 설명:&lt;/span&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;application이 GPU memory에 data 생성하는 CUDA kernel launch. (Fig 1. ①)&lt;/li&gt;
&lt;li&gt;application이 통신을 위해 NVSHMEM 연산 (e.g., `nvshmem_put`)을 호출.&lt;/li&gt;
&lt;li&gt;NVSHMEM 연산이 host memory (RAM)에 있는 proxy buffer로 work descriptor를 write. (②)&lt;/li&gt;
&lt;li&gt;NVSHMEM proxy thread가 work descriptor 감지하고 network 연산 개시. (③)&lt;/li&gt;
&lt;li&gt;proxy thread가 work descriptor를 만들고 host memory에 있는 work queue (WQ) 버퍼에 enqueue. (④)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;work descriptor: RDMA write 같은 요청한 연산들, source/dest 주소, 데이터 크기 등등 network 관련 정보 명시.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;CPU가 host mem에 있는 doorbell record (DBR) 버퍼를 update. (⑤)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;DBR buffer: NIC이 doorbell (DB)에 write하는 걸 drop하는 불상사를 대처하기 위한 recovery path 때 사용.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;CPU가 NIC의 DB 레지스터에 write하면 (doorbell &quot;띵동~&quot;), NIC에서 읽음 (&quot;예 누구세요&quot;). (⑥)&lt;/li&gt;
&lt;li&gt;그러면 NIC이 WQ buffer에서 work descriptor를 읽고 (⑦)&lt;/li&gt;
&lt;li&gt;GPUDirect RDMA를 통해 GPU mem에 있는 data를 copy해서 (⑧)&lt;/li&gt;
&lt;li&gt;목적지 node로 data를 전송한다. (⑨)&lt;/li&gt;
&lt;li&gt;전송 완료했다는걸 CPU한테 알리기 위해서, NIC이 host memory의 completion queue (CQ) buffer에 event를 write. (⑩)&lt;/li&gt;
&lt;li&gt;CPU는 그러면 CQ buffer에서 polling 해가지고 NIC이 전송 완료했음을 감지, 그리고 GPU한테 그걸 알림. (GPU mem에 바로 notification flag를 쓰기도 하고 proxy buffer 통해서 알리기도 함.)&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;370&quot; data-start=&quot;360&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;370&quot; data-start=&quot;360&quot; data-ke-size=&quot;size16&quot;&gt;-) CPU가 bottleneck이 된다.&amp;nbsp;요즘 H100 같은 GPU는 엄청난 속도로 연산한다. 게다가 MoE 연산 같은 경우 연산량 자체는 적은 반면 전송량이 작게 많다 (작은 데이터 패킷을 많이!! 발생시킨다). 그러면 CPU proxy thread는 그 많은 요청을 매번 하나하나 처리한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;370&quot; data-start=&quot;360&quot; data-ke-size=&quot;size16&quot;&gt;최신 NIC는 초당 수억 건의 통신 요청을 처리할 수 있고, GPU 역시 이 정도 속도로 요청을 생성할 수 있다. 반면, CPU 프록시의 처리 속도는 그보다 수 자릿수(orders of magnitude, $10^N$ 배) 낮기 때문에 세밀한(fine-grain) 통신 패턴에서 병목이 발생한다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;ada&quot;&gt;&lt;code&gt;GPU : 야 빨리 보내

CPU : 잠깐만...
CPU : 이것도 처리해야 하고...
CPU : 이것도...
CPU : 이것도...&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;=&amp;gt; 그래서 낸 생각:&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;blockquote data-end=&quot;1009&quot; data-start=&quot;935&quot; data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&quot;아니 CPU 거쳐가려니까 너무 느린데, GPU가 직접 NIC를 건드리면 안 되나?&quot;&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-end=&quot;1009&quot; data-start=&quot;935&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1141&quot; data-start=&quot;1080&quot; data-ke-size=&quot;size16&quot;&gt;그 결과가 GPUDirect Async다. 그리고 이를 InfiniBand에 적용한 것이 IBGDA다.&lt;/p&gt;
&lt;p data-end=&quot;1141&quot; data-start=&quot;1080&quot; data-ke-size=&quot;size16&quot;&gt;이제 CPU를 거치지 않고 바로: ` &lt;span&gt;GPU&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;rarr; InfiniBand NIC &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&amp;rarr; 목적지 GPU` 이렇게 데이터가 바로 전송된다.&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;847&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c3PjW6/dJMcabLg3Ks/sdPqxWdFRLpHbvTDIBWto1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c3PjW6/dJMcabLg3Ks/sdPqxWdFRLpHbvTDIBWto1/img.png&quot; data-alt=&quot;Fig 2. IBGDA의 데이터 전송 구조.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c3PjW6/dJMcabLg3Ks/sdPqxWdFRLpHbvTDIBWto1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc3PjW6%2FdJMcabLg3Ks%2FsdPqxWdFRLpHbvTDIBWto1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;592&quot; height=&quot;392&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;847&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Fig 2. IBGDA의 데이터 전송 구조.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-end=&quot;1141&quot; data-start=&quot;1080&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1319&quot; data-start=&quot;1312&quot; data-ke-size=&quot;size16&quot;&gt;자세히 말하면, GPU가 직접&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-end=&quot;1365&quot; data-start=&quot;1321&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li data-end=&quot;1336&quot; data-start=&quot;1321&quot; data-section-id=&quot;el5sfs&quot;&gt;Work Queue 작성&lt;/li&gt;
&lt;li data-end=&quot;1352&quot; data-start=&quot;1337&quot; data-section-id=&quot;1q74p5s&quot;&gt;Doorbell 업데이트&lt;/li&gt;
&lt;li data-end=&quot;1365&quot; data-start=&quot;1353&quot; data-section-id=&quot;zmirlz&quot;&gt;RDMA 요청 생성&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1412&quot; data-start=&quot;1367&quot; data-ke-size=&quot;size16&quot;&gt;을 수행한다.&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-end=&quot;1412&quot; data-start=&quot;1367&quot; data-ke-size=&quot;size16&quot;&gt;더 자세히 말하면 (Fig 2 참고):&lt;/p&gt;
&lt;p data-end=&quot;1412&quot; data-start=&quot;1367&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;①&lt;/span&gt; 애플리케이션이 CUDA 커널을 실행하고, 이 커널이 GPU 메모리에 데이터를 생성한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;②&lt;/span&gt; 애플리케이션이 통신하기 위해 NVSHMEM 연산(예: nvshmem_put)을 호출한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;②&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;NVSHMEM 연산은 GPU의 SM을 사용하여 NIC용 Work Descriptor를 생성한 뒤 이를 Work Queue(WQ) 버퍼에 직접 기록한다. CPU Proxy 방식과 달리, 이 WQ 버퍼는 CPU 메모리가 아닌 GPU 메모리에 위치한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;③&lt;/span&gt;&amp;nbsp;SM은 GPU 메모리에 위치한 Doorbell Record(DBR) 버퍼를 업데이트한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;④&lt;/span&gt;&amp;nbsp;이어서 SM은 NIC의 Doorbell(DB) 레지스터에 값을 기록하여 NIC에 새로운 작업이 등록되었음을 알린다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;⑤&lt;/span&gt; NIC는 GPUDirect RDMA를 사용하여 GPU 메모리에 있는 WQ 버퍼로부터 Work Descriptor를 읽어온다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;⑥&lt;/span&gt; NIC는 GPUDirect RDMA를 사용하여 GPU 메모리에 저장된 실제 데이터도 직접 읽어온다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;⑦&lt;/span&gt; NIC는 해당 데이터를 목적지 노드로 전송한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;⑧&lt;/span&gt; 네트워크 작업이 완료되면 NIC는 GPUDirect RDMA를 사용하여 Completion Queue(CQ) 버퍼에 완료 정보를 기록함으로써 GPU에 작업 완료를 알린다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;=&amp;gt; 이로써 CPU 도움 없이 깔끔하게 전송!!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1412&quot; data-start=&quot;1367&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1946&quot; data-start=&quot;1929&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.engineering.fyi/article/improving-network-performance-of-hpc-systems-using-nvidia-magnum-io-nvshmem-and-gpudirect-async?utm_source=chatgpt.com&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;NVIDIA가 공개한 자료&lt;/a&gt;에서는 작은 메시지 전송 시, &lt;b&gt;최대 약 9.5배 높은 처리량(throughput)&lt;/b&gt;과 &lt;b&gt;더 낮고 안정적인 지연시간(latency)&lt;/b&gt;을 보여준다. 특히 1KB 이하의 작은 메시지에서 효과가 크다.&lt;/p&gt;</description>
      <category>분산 ML</category>
      <category>GPUDirect RDMA</category>
      <category>HCA</category>
      <category>IBGDA</category>
      <category>infiniband</category>
      <category>MOE</category>
      <category>NVSHMEM</category>
      <author>오렌징큐</author>
      <guid isPermaLink="true">https://orangingq.tistory.com/231</guid>
      <comments>https://orangingq.tistory.com/entry/NVIDIA-GPUDirect-Async-IBGDA#entry231comment</comments>
      <pubDate>Thu, 4 Jun 2026 18:31:52 +0900</pubDate>
    </item>
    <item>
      <title>Context Parallelism v.s. Sequence Parallelism (Megatron-LM 기준)</title>
      <link>https://orangingq.tistory.com/entry/Context-Parallelism-vs-Sequence-Parallelism-Megatron-LM-%EA%B8%B0%EC%A4%80</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;참고 코드: &lt;a href=&quot;https://github.com/nvidia/megatron-lm&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/nvidia/megatron-lm&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1779880434527&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - NVIDIA/Megatron-LM: Ongoing research training transformer models at scale&quot; data-og-description=&quot;Ongoing research training transformer models at scale - NVIDIA/Megatron-LM&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/nvidia/megatron-lm&quot; data-og-url=&quot;https://github.com/NVIDIA/Megatron-LM&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/hYPuD/dJMb8ZvHZ7S/EdfKrRXbPk6u1UViDVuQnK/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/eJPUsx/dJMb9iaXC6W/pO1mS0qKeHYPtyZZ3bAVF0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/hFu69/dJMb9gxrW3H/OMKDWkdHImjb7WcYrqkiXk/img.png?width=4737&amp;amp;height=2125&amp;amp;face=0_0_4737_2125&quot;&gt;&lt;a href=&quot;https://github.com/nvidia/megatron-lm&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/nvidia/megatron-lm&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/hYPuD/dJMb8ZvHZ7S/EdfKrRXbPk6u1UViDVuQnK/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/eJPUsx/dJMb9iaXC6W/pO1mS0qKeHYPtyZZ3bAVF0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/hFu69/dJMb9gxrW3H/OMKDWkdHImjb7WcYrqkiXk/img.png?width=4737&amp;amp;height=2125&amp;amp;face=0_0_4737_2125');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - NVIDIA/Megatron-LM: Ongoing research training transformer models at scale&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Ongoing research training transformer models at scale - NVIDIA/Megatron-LM&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고 글: &lt;a href=&quot;https://insujang.github.io/2024-09-20/introducing-context-parallelism/&quot;&gt;Introducing Context Parallelism &amp;middot; Better Tomorrow with Computer Science - &lt;/a&gt;&lt;a href=&quot;https://insujang.github.io/2024-09-20/introducing-context-parallelism/&quot;&gt;https://insujang.github.io/2024-09-20/introducing-context-parallelism/&lt;/a&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Sequence Parallelism (SP)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기준 논문 [MLSys'23]: &lt;a href=&quot;https://proceedings.mlsys.org/paper_files/paper/2023/file/80083951326cf5b35e5100260d64ed81-Paper-mlsys2023.pdf&quot;&gt;REDUCING ACTIVATION RECOMPUTATION IN LARGE TRANSFORMER MODELS&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2202&quot; data-origin-height=&quot;831&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bQUPby/dJMcadIQoUz/JXNa2N1AljPLs18Ru6KXy0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bQUPby/dJMcadIQoUz/JXNa2N1AljPLs18Ru6KXy0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bQUPby/dJMcadIQoUz/JXNa2N1AljPLs18Ru6KXy0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbQUPby%2FdJMcadIQoUz%2FJXNa2N1AljPLs18Ru6KXy0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2202&quot; height=&quot;831&quot; data-origin-width=&quot;2202&quot; data-origin-height=&quot;831&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;SP(Sequence Parallelism)&lt;/b&gt; 는 Megatron-LM 기준으로 &lt;b&gt;TP에 붙어서 동작하는 보조 기법&lt;/b&gt;에 가깝다. TP에서는 linear layer의 output이 hidden dimension 기준으로 all-reduce 이후 TP rank마다 동일한 activation이 생긴다. 그러면 LayerNorm, Dropout처럼 TP가 직접 적용되지 않는 구간 (i.e., weight가 hidden dim으로 나뉘지 않는 구간)에서는 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;rank마다 연산이&lt;/span&gt; 불필요하게 중복된다. 중복 연산으로 인한 연산량 자체는 뭐 크지 않더라도, activation 저장을 할 때 중복 저장하는 memory overhead를 줄이고 싶은 것이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 SP는 activation을 sequence dimension으로 다시 나누어, TP rank들이 동일한 activation을 중복 저장하지 않도록 한다. 즉, SP는 주로 &lt;b&gt;TP 내부에서 이미 존재하던 통신 패턴을 all-reduce 대신 reduce-scatter + all-gather 형태로 재구성&lt;/b&gt;하는 방식이다. all-reduce = reduce-scatter + all-gather로 볼 수 있기 때문에, 통신량 자체는 크게 늘지 않으면서 activation memory를 줄일 수 있다. 이 때문에 SP는 보통 &lt;b&gt;추가 computation/communication overhead가 거의 없고, 시간 overhead도 작다&lt;/b&gt;고 볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Context Parallelism (CP)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Megatron-LM / Megatron-Core 기준으로, &lt;b&gt;Context Parallelism(CP)&lt;/b&gt;은 긴 sequence를 여러 GPU에 나누어 저장하고 계산하기 위한 parallelism이다. 즉, batch나 hidden dimension이 아니라 &lt;b&gt;sequence length / context dimension을 shard&lt;/b&gt;한다.&lt;br /&gt;&lt;br /&gt;`context_parallel_size` &amp;gt; 1일 때 켜지고, 기본값은 1이라서 CP가 꺼진 상태다. Megatron-Core 문서 기준으로 CP는 TP, PP, DP와 함께 조합 가능하며, 전체 GPU 수(`world_size`)는 기본적으로 TP &amp;times; CP &amp;times; PP &amp;times; DP 구조로 잡힌다. `DP x CP` 수만큼 model weight가 replicate되고, `TP x PP` 수만큼 model weight shard된다. 각 `DP` rank의 model replica에 대해서 서로 다른 data batch가 들어오고, 그 안에서 `CP` rank만큼 이 batch가 sequence length가 잘라진다.&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;541&quot; data-start=&quot;419&quot; data-ke-size=&quot;size16&quot;&gt;context_parallel_size &amp;gt; 1 일 때 CP가 켜지고, 기본값은 1이므로 기본적으로는 CP가 꺼져 있다. CP는 TP, PP, DP와 함께 조합 가능하며, 전체 GPU 수는 보통 다음과 같이 구성된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;$$ \text{world\_size} = TP \times CP \times PP \times DP&lt;/span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;$$&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-end=&quot;858&quot; data-start=&quot;604&quot; data-ke-size=&quot;size16&quot;&gt;CP는 weight를 shard하지 않는다. Sequence activation만 나누기 때문에, 같은 CP group 안의 GPU들은 model weight를 복제해서 가진다. Megatron-LM 코드 주석에서도 CP는 sequence length를 partition하므로 weight에는 영향을 주지 않고, CP group 내에서는 weight가 duplicated된다고 설명한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2208&quot; data-origin-height=&quot;754&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ToIso/dJMcabRRc7W/zSOZa798R7okE4qxsbEUOk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ToIso/dJMcabRRc7W/zSOZa798R7okE4qxsbEUOk/img.png&quot; data-alt=&quot;4D parallelism (출처: Scaling Llama 3 Training with Efficient Parallelism Strategies - https://dl.acm.org/doi/epdf/10.1145/3695053.3731410)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ToIso/dJMcabRRc7W/zSOZa798R7okE4qxsbEUOk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FToIso%2FdJMcabRRc7W%2FzSOZa798R7okE4qxsbEUOk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2208&quot; height=&quot;754&quot; data-origin-width=&quot;2208&quot; data-origin-height=&quot;754&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;4D parallelism (출처: Scaling Llama 3 Training with Efficient Parallelism Strategies - https://dl.acm.org/doi/epdf/10.1145/3695053.3731410)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-end=&quot;885&quot; data-start=&quot;860&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;885&quot; data-start=&quot;860&quot; data-ke-size=&quot;size16&quot;&gt;따라서 직관적으로는 다음과 같이 볼 수 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-end=&quot;1064&quot; data-start=&quot;887&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li data-end=&quot;927&quot; data-start=&quot;887&quot; data-section-id=&quot;1augxh2&quot;&gt;TP &amp;times; PP 방향으로는 model weight가 shard된다.&lt;/li&gt;
&lt;li data-end=&quot;972&quot; data-start=&quot;928&quot; data-section-id=&quot;1azk88&quot;&gt;DP &amp;times; CP 방향으로는 model weight가 replicate된다.&lt;/li&gt;
&lt;li data-end=&quot;1012&quot; data-start=&quot;973&quot; data-section-id=&quot;vy8a5d&quot;&gt;각 DP rank에는 서로 다른 data batch가 들어간다.&lt;/li&gt;
&lt;li data-end=&quot;1064&quot; data-start=&quot;1013&quot; data-section-id=&quot;23gvs4&quot;&gt;그 batch 안에서 CP rank들이 sequence length를 나누어 가진다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;핵심 목적은 &lt;b&gt;long-context training에서 activation memory를 줄이는 것&lt;/b&gt;이다. Sequence length가 길어질수록 transformer activation memory가 커지기 때문에 (기본 attention일 경우 $O(L^2)$) OOM이 발생하기 쉽다. 물론 activation recomputation을 쓰면 activation을 저장하지 않고 backward 때 다시 계산해주기 때문에 메모리 용량이 줄지만, 그러면 사실상 forward pass를 한번씩 더 돌아야 하는거라 forward-backward 연산 시간이 약 1.33배 (forward:backward time=1:2) 증가한다. CP는 각 GPU가 전체 sequence가 아니라 자기에게 할당된 sequence chunk만 저장/처리하게 해서 per-GPU activation memory를 CP size에 비례해 줄인다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-end=&quot;73&quot; data-start=&quot;0&quot; data-section-id=&quot;1qne7tz&quot; data-ke-size=&quot;size23&quot;&gt;구현 특이점: Symmetric chunk assignment&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1612&quot; data-origin-height=&quot;850&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bCrNwp/dJMcacQMSwh/fl4a63Kf40FtzfSQknbYt1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bCrNwp/dJMcacQMSwh/fl4a63Kf40FtzfSQknbYt1/img.png&quot; data-alt=&quot;좌: 기본 naive partitioning / 우: megatron의 head-tail partitioning. (출처: USP - https://arxiv.org/abs/2405.07719)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bCrNwp/dJMcacQMSwh/fl4a63Kf40FtzfSQknbYt1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbCrNwp%2FdJMcacQMSwh%2Ffl4a63Kf40FtzfSQknbYt1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;559&quot; height=&quot;295&quot; data-origin-width=&quot;1612&quot; data-origin-height=&quot;850&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;좌: 기본 naive partitioning / 우: megatron의 head-tail partitioning. (출처: USP - https://arxiv.org/abs/2405.07719)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-end=&quot;336&quot; data-start=&quot;75&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;336&quot; data-start=&quot;75&quot; data-ke-size=&quot;size16&quot;&gt;Megatron-LM의 CP는 sequence를 단순히 앞에서부터 `cp_size`개로 균등하게 자르지 않는다. 특히 &lt;b&gt;causal attention에서는 attention의 유효 영역이 lower triangular 형태&lt;/b&gt;이므로, causal mask를 실제로 활용해 불필요한 upper-triangle 계산을 생략하는 attention kernel (e.g., FlashAttention)에서는 &lt;b&gt;뒤쪽 query chunk일수록 attend해야 하는 key/value 범위가 길어지고 연산량이 커진다&lt;/b&gt;. 즉, 같은 길이의 chunk라도 앞쪽 chunk는 연산량이 작고, 뒤쪽 chunk는 연산량이 크다. 따라서 sequence를 contiguous하게 나누면 뒤쪽 chunk를 맡은 rank에 load가 몰리는 imbalance가 생긴다.&lt;/p&gt;
&lt;p data-end=&quot;527&quot; data-start=&quot;338&quot; data-ke-size=&quot;size16&quot;&gt;이를 완화하기 위해 Megatron-LM은 sequence를 먼저 `&lt;b&gt;2 &amp;times; cp_size`개 chunk&lt;/b&gt;로 나눈 뒤, 앞쪽 chunk와 뒤쪽 chunk를 하나의 CP rank에 pair로 배정한다. 예를 들어 cp_size = 4라면 sequence를 8개 chunk로 나누고, 각 rank는 다음과 같이 두 chunk를 가진다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;rank 0: chunk 0 + chunk 7
rank 1: chunk 1 + chunk 6
rank 2: chunk 2 + chunk 5
rank 3: chunk 3 + chunk 4&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;894&quot; data-start=&quot;721&quot; data-ke-size=&quot;size16&quot;&gt;이 구조 &lt;span style=&quot;letter-spacing: 0px;&quot;&gt;때문에 실제 indexing도 일반적인 slicing과 다르다. 각 CP rank의 local sequence는 원래 sequence에서 연속된 한 구간이 아니므로, attention input, position id, attention mask, packed sequence metadata가 모두 이 앞/뒤 pairing 구조를 따라야 한다. 특히 RoPE는 token의 position 정보를 사용하므로, local rank 안에서 position을 단순히 0, 1, 2, ...로 다시 매기면 안 된다. 예를 들어 rank 0이 chunk 0 + chunk 7을 들고 있다면, RoPE position도 chunk 0의 global positions와 chunk 7의 global positions를 함께 가져와야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 이 방식에서는 sequence를 `cp_size`개 chunk가 아닌 `2 &amp;times; cp_size`개 chunk로 균등하게 나눌 수 있어야 하므로, sequence length가 `2 &amp;times; cp_size`의 배수가 되도록 padding을 맞춰야 한다. 그렇지 않으면 rank별 chunk 크기나 앞/뒤 pairing index가 맞지 않아 CP layout이 깨질 수 있다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;CP vs SP&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3101&quot; data-origin-height=&quot;1384&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/SrQQW/dJMcaf7NI2a/oC6jxVCKRdrQwheEUTr9Z0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/SrQQW/dJMcaf7NI2a/oC6jxVCKRdrQwheEUTr9Z0/img.png&quot; data-alt=&quot;SP는 TP에 합쳐져 있다고 보면 되고, RS/AG 와 AG/RS 사이 Dropout, LN 부분이 SP가 활성화되는 구간이라고 보면 된다. 저 Ring Attention 부분이 CP로 인한 통신 overhead. (출처: https://docs.nvidia.com/megatron-core/developer-guide/0.16.0/user-guide/features/context_parallel.html)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/SrQQW/dJMcaf7NI2a/oC6jxVCKRdrQwheEUTr9Z0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSrQQW%2FdJMcaf7NI2a%2FoC6jxVCKRdrQwheEUTr9Z0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3101&quot; height=&quot;1384&quot; data-origin-width=&quot;3101&quot; data-origin-height=&quot;1384&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;SP는 TP에 합쳐져 있다고 보면 되고, RS/AG 와 AG/RS 사이 Dropout, LN 부분이 SP가 활성화되는 구간이라고 보면 된다. 저 Ring Attention 부분이 CP로 인한 통신 overhead. (출처: https://docs.nvidia.com/megatron-core/developer-guide/0.16.0/user-guide/features/context_parallel.html)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;공통점&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;둘 다 sequence length를 sharding한다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;activation memory가 병목이 되는 long-context training 상황에서 sequence 축으로 activation을 shard해서 per-GPU memory 사용량을 줄이는 것을 목표로 한다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;둘 다 보통 TP/DP/PP와 함께 조합되는 보조 parallelism으로 쓰인다. 특히 Megatron-LM 계열에서는 TP, PP, DP 위에 SP 또는 CP를 추가해서 메모리 병목을 완화한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;차이점&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;적용 범위:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;SP: 주로 LayerNorm, Dropout 등 TP가 적용되지 않는 일부 activation을 sequence dimension으로 shard.&lt;/li&gt;
&lt;li&gt;CP: input batch와 대부분의 activation 전체를 sequence dimension으로 partition.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Communication 방식:&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;SP: TP와 SP 사이 boundary에서 reduce-scatter (hidden dim 축 shard를 reduce - sequence dim 축 shard로 scatter) / all-gather. (근데 사실상 identity/all-reduce -&amp;gt; reduce-scatter/all-gather 라서 통신량 자체는 같다.)&lt;/li&gt;
&lt;li&gt;CP: attention 연산 때 K, V head를 ring-style P2P 방식 (또는 all-gather도 가능)으로 통신 &amp;amp; 연산. 통신량이 $O(LH_{kv})$ ($H_{kv}$: kv chunk의 head 수)만큼 증가. 통신 지연 시간을 고려하면 순수&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Memory 이점:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;SP: TP에서 중복되는 activation memory 감소. LayerNorm 전에 TP에서 all-reduce를 하고 나면 LayerNorm에서는 모든 TP rank들이 동일한 activation 값을 가지게 되는데 굳이 이렇게 중복 값을 가져서 쓸데없는 메모리 소모를 해야 할까? -&amp;gt; 이 때 바로 sequence 축으로 sharding을 해줌으로써 per-GPU activation memory를 늘 $1/TP$만큼으로 유지.&lt;/li&gt;
&lt;li&gt;CP: sequence 축이 있는 모든 input, activation에 대해 $1/CP$만큼으로 감소시킴.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>분산 ML</category>
      <author>오렌징큐</author>
      <guid isPermaLink="true">https://orangingq.tistory.com/229</guid>
      <comments>https://orangingq.tistory.com/entry/Context-Parallelism-vs-Sequence-Parallelism-Megatron-LM-%EA%B8%B0%EC%A4%80#entry229comment</comments>
      <pubDate>Wed, 27 May 2026 20:28:07 +0900</pubDate>
    </item>
    <item>
      <title>Deep EP</title>
      <link>https://orangingq.tistory.com/entry/Deep-EP</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;참고 사이트:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/deepseek-ai/DeepEP&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/deepseek-ai/DeepEP&lt;/a&gt; &amp;nbsp;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.deepep.org/&quot;&gt;DeepEP - &lt;/a&gt;&lt;a href=&quot;https://www.deepep.org/&quot;&gt;https://www.deepep.org/&lt;/a&gt;&amp;nbsp;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://discuss.pytorch.kr/t/deepep-mixture-of-experts-feat-deepseek/6212&quot;&gt;https://discuss.pytorch.kr/t/deepep-mixture-of-experts-feat-deepseek/6212&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고논문 : &lt;a href=&quot;https://arxiv.org/pdf/2512.19849&quot;&gt;UCCL-EP - &lt;/a&gt;&lt;a href=&quot;https://arxiv.org/pdf/2512.19849&quot;&gt;https://arxiv.org/pdf/2512.19849&lt;/a&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;MoE 상황에서 더 빠른 Expert Parallelism를 위한 Communication Library.&lt;br /&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MoE 장인 DeepSeek AI에서, NVLi&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;nk 및 GPUDirect RDMA를 통한 저지연 통신을 활용해 &lt;/span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;b&gt;MoE &amp;amp; Expert Parallelism 전용 Comm. Library&lt;/b&gt;를 만들었다. MoE의 dispatch / combine 연산의 all-to-all 통신을 최적화해주는 고성능 GPU kernel을 제공하고, FP8 연산이나 heterogeneous domain (e.g., NVLink domain vs InfiniBand domain) 간 통신도 지원한다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;MoE&amp;nbsp;Forward&amp;nbsp;Pass&amp;nbsp;in&amp;nbsp;Expert&amp;nbsp;Parallelism&lt;/h2&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;DeepEP가 필요해진 문제 상황을 이해하려면, MoE가 어떻게 진행되는지, ragged 방식과 padding/drop 방식의 차이에 대한 이해부터 필요하다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어 Expert가 128개, 그 중에 active experts가 4개인 MoE 구조 (아래 GPT-OSS 120B 구조)를 EP=8로 분산학습 한다고 생각해보자.&amp;nbsp;그러면 한 GPU에는 experts가 128/8=16개씩 올라간다.&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;처음에 한 batch로 들어온 input batch (batch size $B$ x token length $N$ x hidden dim size $H$)가 먼저 Attention block을 통과하고 residual connection을 거쳐서 MoE block에 도달한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;591&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bIfioo/dJMcagytdy4/Z0wkokcCaBr6TESKA9A6Kk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bIfioo/dJMcagytdy4/Z0wkokcCaBr6TESKA9A6Kk/img.jpg&quot; data-alt=&quot;GPT-OSS 모델 구조&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bIfioo/dJMcagytdy4/Z0wkokcCaBr6TESKA9A6Kk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbIfioo%2FdJMcagytdy4%2FZ0wkokcCaBr6TESKA9A6Kk%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;591&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;591&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;GPT-OSS 모델 구조&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 MoE layer의 첫 단추, Router에서는 이 input batch를 token-wise하게 바라보고 (dim &lt;b&gt;flatten&lt;/b&gt;: $ B \times N \times H&amp;nbsp; \rightarrow BN \times H$ ), 각 token마다 어느 expert로 보내야 할지를 결정한다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1) Router&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 &lt;b&gt;Router&lt;/b&gt;는 $BN \times H$ 를 input으로 받아서 &lt;b&gt;gate weight score가 가장 큰 top-$k$ experts의 index와 score을 반환&lt;/b&gt;한다 (index와 score 둘다 $BN \times k$ 크기). 여기서 $k$는 활성화되는 experts 수, 즉 우리 상황에서는 $k$=4가 되겠다.&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2) Dispatch&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 이제 어떤 experts로 보내야 할지 알았으니, 진짜 보내야 한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요즘 기본으로 쓰는 통신 방식은 &lt;b&gt;(Dropless) Ragged tensor / Concat 방식&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Expert 별 router에 의해 할당된 token 수가 다 다를텐데, 이걸 굳이 똑같게 맞추려 하지 말고 variable size로 (GPU i가 Expert j에게 보내는 token 수 x H)만큼씩 &lt;b&gt;All2All 통신&lt;/b&gt;을 한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;통신 후 각 GPU의 각 expert는 tokens_per_expert x $H$ 만큼의 input을 가지게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Drop/Padding 방식&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$BN \times H$ 였던 dimension shape을 expert 기준으로 $E \times C \time H$ 로 재배열한다 (&lt;b&gt;group-by expert&lt;/b&gt;):&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;$E$: 총 expert 수. 이 사례에서는 $E=128$.&lt;/li&gt;
&lt;li&gt;$C$: 각 expert가 품을 수 있는 최대 token 수 (capacity).&amp;nbsp;&lt;/li&gt;
&lt;li&gt;$H$: hidden dimension.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러니까 각 expert에게 배정된 token들을 줄 세워서 $C$ 만큼 자르고 남은 token들은 &lt;b&gt;drop&lt;/b&gt;. 만약에 배정된 token 수가 $C$보다 작은 expert 행의 경우에는 $C$ dimension에 맞게 &lt;b&gt;padding&lt;/b&gt; 처리한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 이제 i-번째 row $C\times H$를 expert i에게 발송 (&lt;b&gt;dispatch&lt;/b&gt;)한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;이때 모든 GPU에서 $ECH$ 크기의 padding처리된 sparse한 input을 발송하고, 각 GPU에 experts가 16개씩 있다고 했으니까,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;sparse All-to-All 통신&lt;/b&gt;을 하게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;통신 후 각 GPU는 자기가 맡은 experts 수 ($E_{local}$. 이 사례에서는 $E_{local}=16$)만큼의 input을 받기 때문에 $E_{local}\times C \times H$ 만큼의 input을 가지고, 각 expert는 $C \times H$만큼의 input을 가진다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;Megatron-LM&amp;nbsp;코드&amp;nbsp;기준&lt;/i&gt;,&amp;nbsp;기본값은&amp;nbsp;Ragged&amp;nbsp;(dropless)&amp;nbsp;방식이다. Drop/Padding은 `--moe-expert-capacity-factor` 설정 시 활성화되고, capacity 초과 토큰은 probs 또는 position 정책으로 drop된다.&lt;/p&gt;
&lt;br /&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 315px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style13&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;&lt;b&gt;항목&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;&lt;b&gt;Ragged&amp;nbsp;(Dropless)&amp;nbsp;방식&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;&lt;b&gt;Padding&amp;nbsp;(Capacity-based)&amp;nbsp;방식&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;&lt;b&gt;기본 아이디어&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;expert별 token 수를 그대로 유지 (variable length)&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;모든 expert 입력을 동일한 크기(C)로 맞춤&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;&lt;b&gt;데이터 형태&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;variable-sized tensor (ragged)&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;fixed-sized dense tensor&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;&lt;b&gt;통신 방식&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;각 expert별 서로 다른 크기로 All-to-All&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;동일 크기 기준으로 All-to-All&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;&lt;b&gt;추가 정보&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;offset / index 등의 metadata 필요&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;metadata 거의 불필요&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;&lt;b&gt;메모리 효율&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;&lt;b&gt;+) 높음 (불필요한 padding 없음)&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;낮음 (padding으로 낭비 발생)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;&lt;b&gt;compute 효율&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;&lt;b&gt;+) 높음 (실제 token만 연산)&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;낮음 (padding까지 연산)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;&lt;b&gt;load imbalance 대응&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;token drop 없고, throughput이 줄어듦.&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;capacity 초과 시 token drop.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;&lt;b&gt;throughput&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;workload에 따라 다름 (irregularity 영향)&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;&lt;b&gt;+) 안정적 (uniform workload)&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;&lt;b&gt;사용 사례&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;training (특히 최신 MoE 모델)&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;inference 환경&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 각 expert는 자기에게 할당된 input에 대해 &lt;b&gt;FFN 연산&lt;/b&gt;을 수행한다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1519&quot; data-origin-height=&quot;454&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dEDXE2/dJMcacJFI7M/QkHNsjwqUaWWoGmGYl6NOk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dEDXE2/dJMcacJFI7M/QkHNsjwqUaWWoGmGYl6NOk/img.png&quot; data-alt=&quot;MoE 모델 (EP)의 통신 패턴&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dEDXE2/dJMcacJFI7M/QkHNsjwqUaWWoGmGYl6NOk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdEDXE2%2FdJMcacJFI7M%2FQkHNsjwqUaWWoGmGYl6NOk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;753&quot; height=&quot;225&quot; data-origin-width=&quot;1519&quot; data-origin-height=&quot;454&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;MoE 모델 (EP)의 통신 패턴&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3) Combine&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;top-k routing (우리 상황: $k$=4) 기준으로 보면, 각 토큰은 expert E1, E2, E3, E4에게 할당되어 각 $H$ 길이만큼의 FFN output을 얻은 상황이다. &lt;span style=&quot;letter-spacing: 0px;&quot;&gt;이제 이 experts 연산 결과를 다시 합쳐야 (combine) 한다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;dispatch 때와 정반대로 reverse &lt;b&gt;all-to-all 통신&lt;/b&gt;으로 combine.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;각 token이 expert 4개로부터 얻은 결과를 weighted sum으로 합쳐 하나의 output을 가지게 된다.&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;Problem&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;그런데 위 상황의 dropless ragged 방식은 전통적인 NCCL All-to-All에 잘&amp;nbsp;맞지&amp;nbsp;않는다.&amp;nbsp;&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전통적인 CC (collective comm.)는 각 GPU가 미리 정해진 크기의 buffer를 모든 GPU와 교환하는 구조인데, 따라서 보내기 전에 각 peer 간에 보낼 &lt;b&gt;&lt;i&gt;data 크기를 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;미리&lt;span&gt; &lt;/span&gt;&lt;/span&gt;알고 있어야&lt;/i&gt;&lt;/b&gt; 하고,&lt;i&gt;&lt;b&gt; data shape이 가능하면 균일해야&lt;/b&gt;&lt;/i&gt; 한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;315&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/crhDxc/dJMcadocAfA/KpGh9ahWnwOGuCg2r9PpT0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/crhDxc/dJMcadocAfA/KpGh9ahWnwOGuCg2r9PpT0/img.png&quot; data-alt=&quot;NCCL All-to-All을 사용한 기존 MoE 방식: CPU가 껴있어서 GPU stream 내에서도 유휴시간이 발생하고, Dispatch - Comp. - Combine이 순차적으로 발생.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/crhDxc/dJMcadocAfA/KpGh9ahWnwOGuCg2r9PpT0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcrhDxc%2FdJMcadocAfA%2FKpGh9ahWnwOGuCg2r9PpT0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;315&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;315&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;NCCL All-to-All을 사용한 기존 MoE 방식: CPU가 껴있어서 GPU stream 내에서도 유휴시간이 발생하고, Dispatch - Comp. - Combine이 순차적으로 발생.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 &lt;b&gt;dropless ragged 방식은&lt;/b&gt; expert마다 할당되는 token 수가 dynamic하게 결정되니까 &lt;b&gt;data 크기가 그때그때 매번 다르고 균일하지도 않다 (fragmented GPU-GPU transfer)&lt;/b&gt;. 그럼 어떡하냐?:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;균일한 조각 단위(tensor)으로 잘게 쪼개서 여러 번 통신하기
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;-) 이러면 NIC의 WQE (work queue entry)가 폭증...! -&amp;gt; latency + overhead 증가.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;expert 별로, token input들을 &lt;b&gt;하나의 contiguous buffer로 packing&lt;/b&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;해서 보내기&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;-) 통신 latency 자체는 효율적이나, packing/unpacking하는데 overhead 생김. &lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Dropless Ragged 방식 포기하고 &lt;b&gt;Padding/Drop 방식&lt;/b&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt; 택하기&amp;nbsp;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;-) 위 더보기란에서 표로 정리했듯, padding/drop 방식은 padding으로 인한 추가 overhead와 drop으로 인한 학습 불안정성이 발생한다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아무튼, 이러나 저러나 비효율적이다. 그래서 이 old NCCL All-to-All 대신 &lt;b&gt;MoE ragged 방식에 찰떡으로 맞는 communication library가 없을까?&lt;/b&gt; 해서 나온 게 바로바로~~~ &lt;b&gt;DeepEP&lt;/b&gt; (딥 이피 라고 읽음..ㅎ)이다!&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot; data-section-id=&quot;1clp63m&quot; data-start=&quot;1227&quot; data-end=&quot;1243&quot;&gt;DeepEP: GPU-initiated Token-level Communication&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;GPU thread가 host OS를 거치지 않고 &amp;nbsp;NVIDIA IBGDA (InfiniBand GPUDirect Async) &amp;amp; NVSHMEM (NVIDIA Shared Memory)를 활용해서 NIC한테 direct하게 transfer command를 날린다 (submit한다).&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;DeepEP는 inference decoding용 &lt;b&gt;low-latency mode&lt;/b&gt;와 training용 &lt;b&gt;high-throughput mode&lt;/b&gt; 두 가지 모드를 제공한다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;low-latency mode에서는 IBGDA + NVSHMEM을 활용.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;High-throughput mode에서는 CPU-initiated RDMA를 활용.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;466&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/czhRDF/dJMcadBGvVN/kBORShKWtflrPhjjSzU8n0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/czhRDF/dJMcadBGvVN/kBORShKWtflrPhjjSzU8n0/img.png&quot; data-alt=&quot;DeepEP를 통해 훨씬 빨라진 MoE 연산 &amp;amp;amp; 통신.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/czhRDF/dJMcadBGvVN/kBORShKWtflrPhjjSzU8n0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FczhRDF%2FdJMcadBGvVN%2FkBORShKWtflrPhjjSzU8n0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;466&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;466&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;DeepEP를 통해 훨씬 빨라진 MoE 연산 &amp;amp; 통신.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;GPU-initiated RDMA (IBGDA)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;기존 EP 방식: CPU &amp;rarr; NIC에게 send/recv 요청, GPU는 메모리만 제공&lt;/li&gt;
&lt;li&gt;DeepEP 방식: GPU thread (SM)가 직접 NIC에게 요청, &lt;b&gt;CPU 개입 없음&lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;b&gt; NVIDIA GPUDirect Async (IBGDA)&lt;/b&gt; 기술을 통해 GPU kernel 내부에서 통신을 직접 실행한다.&lt;/li&gt;
&lt;li&gt;+) 빠름.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Token-level Communication Kernel&lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;기존 EP 방식: large batched All-to-All&lt;/li&gt;
&lt;li&gt;DeepEP 방식: token-level fine-grained transfer.
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;token 단위로 send/recv. =&amp;gt; dynamic routing 그대로 반영 가능,&amp;nbsp;&lt;/li&gt;
&lt;li&gt;+) packing/unpacking 비용 제거 =&amp;gt; latency $\downarrow$, throughput $\uparrow$&lt;/li&gt;
&lt;li&gt;참고) latency=output 한 번 내는데 걸리는 시간 / throughput=단위 시간에 몇 개의 output을 내는지. 한번 output 내는데 소요되는 end-to-end time은 길지만 병렬처리가 뛰어난 경우에는 latency가 높고 throughput도 높다.&amp;nbsp;&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Asynchronous &amp;amp; Overlap Execution&lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;기존 EP 방식 (Drop/Padding): 모든 token이 한꺼번에 도착 후, 한번에 FFN 실행.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;DeepEP 방식: 일부 token이 도착하면 전체가 sync되기를 기다리지 않고 &lt;b&gt;streaming 방식&lt;/b&gt;으로 바로 FFN 실행.&amp;nbsp;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;HOW? comm. kernel이랑 computation kernel이랑 섞지 않고, GPU SM 일부를 아예 communication kernel에 할당.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;hook-based comm.-computation overlapping method&amp;nbsp;&lt;/li&gt;
&lt;li&gt;+) training / inference workload에 맞게 이 kernel 할당 비율을 tuning 가능. (&lt;b&gt;SM Resource Control&lt;/b&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;+) expert load imbalance 문제로 인해서 slow expert가 전체를 기다리게 하는 문제를 완화해줌. 기존 synchronous 방식은 barrier를 걸어서, 모든 expert가 자기 token을 받을 때까지 기다렸다가 다같이 FFN compute를 시작하고, 모든 experts가 FFN compute를 끝나야만 combine A2A 통신을 진행한다. 반면 이 streaming 방식은 먼저 token 받으면 먼저 compute 시작할 수 있고, FFN 끝난 token은 바로 async하게 combine 전송할 수 있다.
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;=&amp;gt; +) 빨라짐.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 마디로 정리하면, DeepEP 덕분에 같은 MoE 연산에 대해 더 빠른 처리가 가능해졌다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존 NCCL에서는 `총 시간 = Dispatch Comm. + FFN Compute + Combine Comm.` 으로 걸렸다면, DeepEP에서는 Comm kernel과 Compute kernel을 따로 구분하니까, 대강.. `총 시간 = max(Dispatch+Combine Comm., FFN Compute)` 으로 걸린다고 보면 됨.&lt;/p&gt;</description>
      <category>분산 ML</category>
      <author>오렌징큐</author>
      <guid isPermaLink="true">https://orangingq.tistory.com/227</guid>
      <comments>https://orangingq.tistory.com/entry/Deep-EP#entry227comment</comments>
      <pubDate>Fri, 24 Apr 2026 00:28:27 +0900</pubDate>
    </item>
    <item>
      <title>Distributed Optimizer &amp;harr; FSDP 차이 (Megatron 코드 기준)</title>
      <link>https://orangingq.tistory.com/entry/Distributed-Optimizer-%E2%86%94-FSDP-%EC%B0%A8%EC%9D%B4-Megatron-%EC%BD%94%EB%93%9C-%EA%B8%B0%EC%A4%80</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고자료:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.nvidia.com/megatron-core/developer-guide/latest/user-guide/features/dist_optimizer.html&quot;&gt;Distributed Optimizer &amp;mdash; Megatron Core - &lt;/a&gt;&lt;a href=&quot;https://docs.nvidia.com/megatron-core/developer-guide/latest/user-guide/features/dist_optimizer.html&quot;&gt;https://docs.nvidia.com/megatron-core/developer-guide/latest/user-guide/features/dist_optimizer.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.nvidia.com/megatron-core/developer-guide/latest/user-guide/features/custom_fsdp.html&quot;&gt;Megatron FSDP &amp;mdash; Megatron Core - &lt;/a&gt;&lt;a href=&quot;https://docs.nvidia.com/megatron-core/developer-guide/latest/user-guide/features/custom_fsdp.html&quot;&gt;https://docs.nvidia.com/megatron-core/developer-guide/latest/user-guide/features/custom_fsdp.html&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;FSDP (Stage 1,2,3)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 &lt;b&gt;FSDP (fully-sharded DP=Stage 3)를 적용했을 때의 학습 Flow&lt;/b&gt;는 다음과 같다:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;* 정의 상으로 FSDP는 DeepSpeed ZeRO Stage 3과 같은데, Megatron FSDP는 Stage 1 (optimizer state만 sharding), stage 2 (optim state + grad sharding)도 지원한다. 일단 Stage 3 기준으로 설명한다.&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;FSDP degree=d, param 수=N, param dtype=bf16, Adam optimizer 가정.&lt;/blockquote&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;578&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ciVvxC/dJMcadIom62/6dD4qchxXlTR8MwCRUuqO1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ciVvxC/dJMcadIom62/6dD4qchxXlTR8MwCRUuqO1/img.png&quot; data-alt=&quot;FSDP (Stage 3) 적용했을 때의 학습 flow&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ciVvxC/dJMcadIom62/6dD4qchxXlTR8MwCRUuqO1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FciVvxC%2FdJMcadIom62%2F6dD4qchxXlTR8MwCRUuqO1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;578&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;578&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;FSDP (Stage 3) 적용했을 때의 학습 flow&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #1a1a1a; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;0. 처음에 각 dp rank 별로 model param shard (N/d x fp16 -&amp;gt; 2N/d Byte), optim state shard (2N/d&lt;span style=&quot;background-color: #ffffff; color: #1a1a1a; text-align: start;&quot;&gt;&amp;nbsp;x&lt;/span&gt; fp32 -&amp;gt; 8N/d Byte), main param shard (N/d x fp32 -&amp;gt; 4N/d Byte) 가지고 있음.&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;585&quot; data-origin-height=&quot;374&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/diHh57/dJMcafM3nqL/cyAWWTCESbeigbVKW8DGlk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/diHh57/dJMcafM3nqL/cyAWWTCESbeigbVKW8DGlk/img.png&quot; data-alt=&quot;기본적으로 알아야 하는 Model State&amp;amp;nbsp; Memory &amp;amp;amp; Residual State Memory 종류. 근데 물론 구현마다 조금씩은 다르다. 예를 들어 megatron에서 gradients (FP16) 메모리는 parameter update할 때 잠깐 만들었다가 다시 free 시켜서 사실 steady state로 존재하지 않는다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/diHh57/dJMcafM3nqL/cyAWWTCESbeigbVKW8DGlk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdiHh57%2FdJMcafM3nqL%2FcyAWWTCESbeigbVKW8DGlk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;515&quot; height=&quot;329&quot; data-origin-width=&quot;585&quot; data-origin-height=&quot;374&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;기본적으로 알아야 하는 Model State&amp;nbsp; Memory &amp;amp; Residual State Memory 종류. 근데 물론 구현마다 조금씩은 다르다. 예를 들어 megatron에서 gradients (FP16) 메모리는 parameter update할 때 잠깐 만들었다가 다시 free 시켜서 사실 steady state로 존재하지 않는다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;각 dp rank의 model param shard를 &lt;b&gt;all-gather&lt;/b&gt; 통해 full param으로 모은다. (param: 2N/d -&amp;gt; 2N)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;stage 1, 2에서는 param sharding을 하지 않긴 하지만, optimizer update를 자기 param shard에 대해서만 하기 때문에 sync를 맞춰주고자 all-gather를 해줘야 한다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;i&gt;&lt;b&gt;[Forward]&lt;/b&gt;&lt;/i&gt; full param 가지고 각 dp rank에서 local하게 forward 진행.&lt;/li&gt;
&lt;li&gt;backward 전까지 full param 필요 없으니까 &lt;b&gt;free&lt;/b&gt;. (param: 2N -&amp;gt; 2N/d)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;stage 1, 2에서는 param sharding을 하지 않으니 이 부분 생략.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;backward 전에, &lt;b&gt;all-gather&lt;/b&gt; 통해 다시 full param 모은다. (param: 2N/d -&amp;gt; 2N)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;stage 1, 2에서는 param sharding을 하지 않으니 이 부분 생략.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;i&gt;&lt;b&gt;[Backward]&lt;/b&gt;&lt;/i&gt; full param 가지고 각 dp rank의 data shard에 대한 backward prop. (local하게 독립적으로 수행. gradient 4N Byte 생성.)&lt;/li&gt;
&lt;li&gt;각 dp rank의 gradient를 &lt;b&gt;reduce-scatter&lt;/b&gt; 통해서 sync 해준다. (param 2N, grad 4N -&amp;gt; param 2N, grad 4N/d)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;stage 1에서는 gradient sharding을 하지 않으니 reduce-scatter 대신 &lt;b&gt;all-reduce&lt;/b&gt;. (-&amp;gt; param 2N, grad 4N)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;이제 full param도 자기 shard 빼고는 &lt;b&gt;free&lt;/b&gt;. (param 2N, grad 4N/d -&amp;gt; param 2N/d, grad 4N/d)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;stage 1, 2에서는 param sharding을 하지 않으니 이 부분 생략. (stage 1: param 2N, grad 4N / stage 2: param 2N, grad 4N/d)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;..이걸 microbatch별로, grad_accum_step 만큼 또 반복을 해주다가. optimizer update 때가 되면??&lt;/li&gt;
&lt;li&gt;&lt;i&gt;&lt;b&gt;[Optimizer]&lt;/b&gt;&lt;/i&gt; 각 dp rank에서 local하게 &lt;b&gt;자기 param shard에 대해서만&lt;/b&gt; optim update.&amp;nbsp;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;stage 1, 2에서도 마찬가지로, 자기 shard에 대해서만 update. 왜냐면 optimizer state가 sharding되어 있어서 전체 update가 불가.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Distributed Optimizer&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;540&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nG2B6/dJMcaaLIXUb/KGK4VXcB2M57SvODi0TT70/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nG2B6/dJMcaaLIXUb/KGK4VXcB2M57SvODi0TT70/img.png&quot; data-alt=&quot;Distributed Optimizer data flow&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nG2B6/dJMcaaLIXUb/KGK4VXcB2M57SvODi0TT70/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnG2B6%2FdJMcaaLIXUb%2FKGK4VXcB2M57SvODi0TT70%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;960&quot; height=&quot;540&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;540&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Distributed Optimizer data flow&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Distributed Optimizer는 ZeRO-1 (stage 1)와 관점이 조금 다를 뿐, 구현 자체는 굉장히 비슷하다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유일한 다른 점은,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Distributed Optimizer&lt;/b&gt;은: throughput 향상과 일관된 parameter state 지향 -&amp;gt; eager sync -&amp;gt; &lt;b&gt;optimizer update 직후에 parameter를 sync&lt;/b&gt; (=allgather).&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반면 &lt;b&gt;ZeRO Series&lt;/b&gt;는: memory consumption 최소화 목적 -&amp;gt; lazy on-demand sync -&amp;gt; &lt;b&gt;forward 직전에 필요한 시점에 parameter sync&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;lazy sync를 한다는 건, optim update 후 param sync 전까지동안, full parameter를 가지고는 있으나 사실상 유효한 (updated) parameter는 해당 dp shard의 parameter 뿐이라는 것이다. 반면 eager sync는 optimizer update 직후에 바로 sync해버리니까 늘 parameter가 synchronized 되어 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Q. Megatron에서 왜 lazy sync 대신 eager sync를 선택했는가?&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;Megatron은 TP/PP와의 hybrid parallelism을 고려해서, 구현의 용이성을 위해 parameter의 consistency를 유지하고 싶었을 것이다.&lt;/li&gt;
&lt;li&gt;미리 sync를 시작하면 comm. overlap 기능을 통해 좀 더 여유롭게(?) parameter bucket들을 sync할 수 있으니까 throughput 측면에서도 이득일 것이다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Q. 헷갈리는 점은, Megatron FSDP는 stage 1, 2, 3을 모두 지원하는데, distributed optimizer도 같이 써야 한다는 점이다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;DO가 ZeRO-2랑 비슷하다고 했는데, 그러면 Megatron FSDP stage 1/2/3이랑 DO랑 같이 옵션을 켜면 어떻게 되는겨?&lt;/b&gt;&lt;br /&gt;A. 구현 상에서, 그러면 &lt;b&gt;Megatron FSDP를 먼저 따라간다&lt;/b&gt;. sharding 정책의 주도권은 Megatron-FSDP에 있고, Distributed Optimizer는 optimizer step / state / checkpoint 쪽 wrapper로 얹히는 형태.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 `--use-distributed-optimizer --use-megatron-fsdp --data-parallel-sharding-strategy optim_grads_params` 이렇게 세 가지 옵션을 동시에 켰을 때, 그러니까 Distributed Optimizer도 쓰면서 Megatron-FSDP stage 3도 쓰면,&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;model grad (fp16/bf16) -&amp;gt; main grad (fp32) 복사: 건너뜀.
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;`megatron/core/optimizer/distrib_optimizer.py &amp;gt; DistributedOptimizer class &amp;gt; _copy_model_grads_to_main_grads()`&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;main param (fp32) -&amp;gt; model param (fp16/bf16) 복사: FSDP buffer api 사용
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;` megatron/core/optimizer/distrib_optimizer.py &amp;gt; DistributedOptimizer class &amp;gt; _copy_main_params_to_model_params()`&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;optimizer step 후 param sync할 때: FSDP의 start_param_sync() 호출
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;`megatron/core/optimizer/distrib_optimizer.py&amp;gt;DistributedOptimizer class&amp;gt;step_with_ready_grads()`&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 Distributed Optimizer 없이 Megatron-FSDP를 쓰는 것도 현재 지원되지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.nvidia.com/megatron-core/developer-guide/latest/user-guide/features/custom_fsdp.html?utm_source=chatgpt.com&quot;&gt;https://docs.nvidia.com/megatron-core/developer-guide/latest/user-guide/features/custom_fsdp.html&lt;/a&gt; &amp;lt;- 여기에 &quot;The custom FSDP must be used with a distributed optimizer since it provides distributed checkpointing.&quot; 라고 써 있다.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;총정리&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Memory Sharding State 비교&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Column 설명:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #333333; text-align: start;&quot; data-source-line=&quot;208&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-source-line=&quot;208&quot;&gt;&lt;b&gt;DDP&lt;/b&gt;:&amp;nbsp;Distributed&amp;nbsp;Optimizer&amp;nbsp;/&amp;nbsp;Megatron-FSDP&amp;nbsp;없이&amp;nbsp;DDP만&amp;nbsp;사용. &lt;/li&gt;
&lt;li data-source-line=&quot;208&quot;&gt;&lt;b&gt;D.O.&amp;nbsp;only&lt;/b&gt;:&amp;nbsp;Megatron-FSDP&amp;nbsp;없이&amp;nbsp;Distributed&amp;nbsp;Optimizer만&amp;nbsp;사용. &lt;/li&gt;
&lt;li data-source-line=&quot;208&quot;&gt;&lt;b&gt;FSDP&amp;nbsp;Stage&amp;nbsp;1&lt;/b&gt;:&amp;nbsp;`--use-distributed-optimizer`&amp;nbsp;+&amp;nbsp;`--use-megatron-fsdp`&amp;nbsp;+&amp;nbsp;`--parallel-sharding-strategy&amp;nbsp;optim` &lt;/li&gt;
&lt;li data-source-line=&quot;208&quot;&gt;&lt;b&gt;FSDP&amp;nbsp;Stage&amp;nbsp;2&lt;/b&gt;:&amp;nbsp;`--use-distributed-optimizer`&amp;nbsp;+&amp;nbsp;`--use-megatron-fsdp`&amp;nbsp;+&amp;nbsp;`--parallel-sharding-strategy&amp;nbsp;optim_grads` &lt;/li&gt;
&lt;li data-source-line=&quot;208&quot;&gt;&lt;b&gt;FSDP&amp;nbsp;Stage&amp;nbsp;3&lt;/b&gt;:&amp;nbsp;`--use-distributed-optimizer`&amp;nbsp;+&amp;nbsp;`--use-megatron-fsdp`&amp;nbsp;+&amp;nbsp;`--parallel-sharding-strategy&amp;nbsp;optim_grdas_params` &lt;/li&gt;
&lt;li data-source-line=&quot;208&quot;&gt;Distributed&amp;nbsp;Optimizer&amp;nbsp;없이&amp;nbsp;Megatron-FSDP만&amp;nbsp;쓰는&amp;nbsp;것은&amp;nbsp;현재&amp;nbsp;지원되지&amp;nbsp;않는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Row 설명:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;optimizer state&lt;/b&gt; (fp32): Adam optimizer 계열 기준, 두 종류 (`exp_avg`, `exp_avg_sq`) 가 high-precision으로 저장됨.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;optimizer에&amp;nbsp;의해&amp;nbsp;저장/관리되는&amp;nbsp;steady-state&amp;nbsp;memory.&amp;nbsp;optimizer&amp;nbsp;계산용으로&amp;nbsp;저장되는&amp;nbsp;high-precision&amp;nbsp;parameter&amp;nbsp;값.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;main param&lt;/b&gt; (fp32): optimizer 계산용으로 저장되는 high-precision parameter 값.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;main grad&lt;/b&gt; (fp32): optimizer step, grad norm, clipping, update에는 high-precision으로 쓰인다. (dtype custom 지정 가능)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;model param&lt;/b&gt; (fp16/bf16): 매 forward 때 사용되는 model parameter 값.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Shard&amp;nbsp;factor&amp;nbsp;`d`&amp;nbsp;설명: &lt;b&gt;&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Non-MoE&lt;/b&gt; parameter의 shard factor: `d = WORLD_SIZE/(DPxCP)` (distributed optimizer state is sharded jointly over DP+CP.)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;MoE expert&lt;/b&gt; parameter의&amp;nbsp;shard&amp;nbsp;factor:&amp;nbsp;`d&amp;nbsp;=&amp;nbsp;WORLD_SIZE/EDP`&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 135px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;height: 21px; width: 22.4419%;&quot;&gt;&lt;b&gt;항목&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px; width: 11.5117%;&quot;&gt;&lt;b&gt;DDP&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px; width: 10.2326%;&quot;&gt;&lt;b&gt;FSDP &lt;br /&gt;Stage 1&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px; width: 10.2324%;&quot;&gt;&lt;b&gt;D.O.&amp;nbsp;only&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px; width: 10.3488%;&quot;&gt;&lt;b&gt; FSDP &lt;/b&gt;&lt;br /&gt;&lt;b&gt;Stage 2&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 12.5582%; height: 21px;&quot;&gt;&lt;b&gt;FSDP&lt;/b&gt;&lt;br /&gt;&lt;b&gt;Stage 3&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px; width: 22.4419%;&quot;&gt;&lt;b&gt;optimizer state (2N x 4Byte)&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 20px; width: 11.5117%;&quot;&gt;❌ full&lt;/td&gt;
&lt;td style=&quot;height: 20px; width: 10.2326%;&quot;&gt;✅ 1/d&lt;/td&gt;
&lt;td style=&quot;height: 20px; width: 10.2324%;&quot;&gt;✅ 1/d&lt;/td&gt;
&lt;td style=&quot;height: 20px; width: 10.3488%;&quot;&gt;✅ 1/d&lt;/td&gt;
&lt;td style=&quot;width: 12.5582%; height: 20px;&quot;&gt;✅ 1/d&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 22.4419%; height: 20px;&quot;&gt;&lt;b&gt;main param (N&lt;span&gt;&amp;nbsp;&lt;/span&gt;x 4Byte)&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 11.5117%; height: 20px;&quot;&gt;❌&amp;nbsp;full&lt;/td&gt;
&lt;td style=&quot;width: 10.2326%; height: 20px;&quot;&gt;✅&amp;nbsp;1/d&lt;/td&gt;
&lt;td style=&quot;width: 10.2324%; height: 20px;&quot;&gt;✅ 1/d&lt;/td&gt;
&lt;td style=&quot;width: 10.3488%; height: 20px;&quot;&gt;✅&amp;nbsp;1/d&lt;/td&gt;
&lt;td style=&quot;width: 12.5582%; height: 20px;&quot;&gt;✅ 1/d&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 22.4419%; height: 20px;&quot;&gt;&lt;b&gt;main grad (N x 4Byte)&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 11.5117%; height: 20px;&quot;&gt;❌&amp;nbsp;full&lt;/td&gt;
&lt;td style=&quot;width: 10.2326%; height: 20px;&quot;&gt;❌&amp;nbsp;full&lt;/td&gt;
&lt;td style=&quot;width: 10.2324%; height: 20px;&quot;&gt;❌&amp;nbsp;full&lt;/td&gt;
&lt;td style=&quot;width: 10.3488%; height: 20px;&quot;&gt;✅&amp;nbsp;1/d&lt;/td&gt;
&lt;td style=&quot;width: 12.5582%; height: 20px;&quot;&gt;✅ 1/d&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 22.4419%; height: 20px;&quot;&gt;&lt;b&gt;model param (N x 2Byte)&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 11.5117%; height: 20px;&quot;&gt;❌&amp;nbsp;full&lt;/td&gt;
&lt;td style=&quot;width: 10.2326%; height: 20px;&quot;&gt;❌&amp;nbsp;full&lt;/td&gt;
&lt;td style=&quot;width: 10.2324%; height: 20px;&quot;&gt;❌&amp;nbsp;full&lt;/td&gt;
&lt;td style=&quot;width: 10.3488%; height: 20px;&quot;&gt;❌&amp;nbsp;full&lt;/td&gt;
&lt;td style=&quot;width: 12.5582%; height: 20px;&quot;&gt;✅&amp;nbsp;1/d&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 34px;&quot;&gt;
&lt;td style=&quot;height: 34px; width: 22.4419%;&quot;&gt;&lt;b&gt;residual memory &lt;br /&gt;(e.g. activation, ...)&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 34px; width: 11.5117%;&quot;&gt;❌ full&lt;/td&gt;
&lt;td style=&quot;height: 34px; width: 10.2326%;&quot;&gt;❌ full&lt;/td&gt;
&lt;td style=&quot;height: 34px; width: 10.2324%;&quot;&gt;&lt;br /&gt;❌&amp;nbsp;full&lt;/td&gt;
&lt;td style=&quot;height: 34px; width: 10.3488%;&quot;&gt;❌ full&lt;/td&gt;
&lt;td style=&quot;width: 12.5582%; height: 34px;&quot;&gt;❌ full&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p style=&quot;background-color: #ffffff; color: #1a1a1a; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;background-color: #ffffff; color: #1a1a1a; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;Communication Overhead 비교&lt;/h4&gt;
&lt;table style=&quot;border-collapse: collapse; width: 98.0236%; height: 183px;&quot; border=&quot;1&quot; data-ke-style=&quot;style12&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 11.6706%; height: 21px;&quot;&gt;&lt;b&gt;항목&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 13.7379%; height: 21px;&quot;&gt;&lt;b&gt;DDP&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 14.3896%; height: 21px;&quot;&gt;&lt;b&gt;FSDP&lt;br /&gt;Stage 1&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 13.8379%; height: 21px;&quot;&gt;&lt;b&gt;FSDP&lt;br /&gt;Stage 2&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 13.9487%; height: 21px;&quot;&gt;&lt;b&gt;Distributed&lt;br /&gt;Optimizer&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 13.7129%; height: 21px;&quot;&gt;&lt;b&gt;FSDP &lt;/b&gt;&lt;br /&gt;&lt;b&gt;Stage 3&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 11.6706%;&quot;&gt;&lt;b&gt;Forward 전&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 13.7379%;&quot;&gt;None&lt;/td&gt;
&lt;td style=&quot;width: 14.3896%;&quot;&gt;Param (2N) AG&lt;/td&gt;
&lt;td style=&quot;width: 13.8379%;&quot;&gt;Param&amp;nbsp;(2N)&amp;nbsp;AG&lt;/td&gt;
&lt;td style=&quot;width: 13.9487%;&quot;&gt;None&lt;/td&gt;
&lt;td style=&quot;width: 13.7129%;&quot;&gt;Param&amp;nbsp;(2N)&amp;nbsp;AG&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 11.6706%;&quot;&gt;&lt;b&gt;Forward 후&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 13.7379%;&quot;&gt;None&lt;/td&gt;
&lt;td style=&quot;width: 14.3896%;&quot;&gt;None&lt;/td&gt;
&lt;td style=&quot;width: 13.8379%;&quot;&gt;None&lt;/td&gt;
&lt;td style=&quot;width: 13.9487%;&quot;&gt;None&lt;/td&gt;
&lt;td style=&quot;width: 13.7129%;&quot;&gt;None&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 11.6706%;&quot;&gt;&lt;b&gt;Backward 전&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 13.7379%;&quot;&gt;None&lt;/td&gt;
&lt;td style=&quot;width: 14.3896%;&quot;&gt;None&lt;/td&gt;
&lt;td style=&quot;width: 13.8379%;&quot;&gt;None&lt;/td&gt;
&lt;td style=&quot;width: 13.9487%;&quot;&gt;None&lt;/td&gt;
&lt;td style=&quot;width: 13.7129%;&quot;&gt;Param&amp;nbsp;(2N)&amp;nbsp;AG&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 11.6706%;&quot;&gt;&lt;b&gt;Backward 후&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 13.7379%;&quot;&gt;Grad (2N) AR&lt;/td&gt;
&lt;td style=&quot;width: 14.3896%;&quot;&gt;Grad (2N) RS&lt;/td&gt;
&lt;td style=&quot;width: 13.8379%;&quot;&gt;Grad (2N) RS&lt;/td&gt;
&lt;td style=&quot;width: 13.9487%;&quot;&gt;Grad (2N) RS&lt;/td&gt;
&lt;td style=&quot;width: 13.7129%;&quot;&gt;&lt;span style=&quot;background-color: #f9f9f9; color: #333333; text-align: start;&quot;&gt;Grad (2N) RS&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 11.6706%;&quot;&gt;&lt;b&gt;Optim. Update&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 13.7379%;&quot;&gt;None&lt;/td&gt;
&lt;td style=&quot;width: 14.3896%;&quot;&gt;None&lt;/td&gt;
&lt;td style=&quot;width: 13.8379%;&quot;&gt;None&lt;/td&gt;
&lt;td style=&quot;width: 13.9487%;&quot;&gt;Param (2N) AG&lt;/td&gt;
&lt;td style=&quot;width: 13.7129%;&quot;&gt;None&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p style=&quot;background-color: #ffffff; color: #1a1a1a; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;* gradient 통신할 때의 dtype은 설정하기 나름이긴 한데, 기본값은 model param의 dtype을 따른다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;근데 여기서 AR = AG + RS 인 관계로, 사실상 통신량 자체는 DDP = FSDP Stage 1 = FSDP Stage 2 = Distributed Optimizer &amp;lt; FSDP Stage 3 로 볼 수 있다.&lt;/p&gt;</description>
      <category>분산 ML</category>
      <author>오렌징큐</author>
      <guid isPermaLink="true">https://orangingq.tistory.com/226</guid>
      <comments>https://orangingq.tistory.com/entry/Distributed-Optimizer-%E2%86%94-FSDP-%EC%B0%A8%EC%9D%B4-Megatron-%EC%BD%94%EB%93%9C-%EA%B8%B0%EC%A4%80#entry226comment</comments>
      <pubDate>Wed, 15 Apr 2026 18:03:50 +0900</pubDate>
    </item>
    <item>
      <title>CUDA Multicast</title>
      <link>https://orangingq.tistory.com/entry/CUDA-Multicast</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;CUDA multicast는 하나의 데이터를 여러 GPU에 동시에 전달해서 GPU 간 통신을 효율화하는 기술입니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;구분&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;Unicast&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;Broadcast&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;Multicast&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;통신 방식&lt;/td&gt;
&lt;td&gt;1 &amp;rarr; 1&lt;/td&gt;
&lt;td&gt;1 &amp;rarr; 전체&lt;/td&gt;
&lt;td&gt;1 &amp;rarr; 특정 그룹&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;대상&lt;/td&gt;
&lt;td&gt;한 개&lt;/td&gt;
&lt;td&gt;모든 노드&lt;/td&gt;
&lt;td&gt;선택된 여러 노드&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;효율성&lt;/td&gt;
&lt;td&gt;낮음 (여러 번 전송 필요)&lt;/td&gt;
&lt;td&gt;비효율적 (불필요한 대상 포함)&lt;/td&gt;
&lt;td&gt;가장 효율적&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;네트워크 부담&lt;/td&gt;
&lt;td&gt;높음&lt;/td&gt;
&lt;td&gt;매우 높음&lt;/td&gt;
&lt;td&gt;낮음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;example&lt;/td&gt;
&lt;td&gt;&lt;b&gt; 한 사람에게 전화&lt;/b&gt; &lt;br /&gt;* GPU0 &amp;rarr; GPU1&lt;/td&gt;
&lt;td&gt;&lt;b&gt; 마이크로 모든 사람에게 방송&lt;/b&gt;&lt;br /&gt;* GPU0 &amp;rarr; 모든 GPU&lt;/td&gt;
&lt;td&gt;&lt;b&gt; 특정 그룹방에만 메시지 전송&lt;/b&gt; &lt;br /&gt;* GPU0 &amp;rarr; GPU1, GPU3, GPU5&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;구현 방식&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;기본 NCCL &lt;i&gt;&amp;harr;&lt;/i&gt; CUDA 관계 구조&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[사용자&amp;nbsp;코드]&lt;/b&gt; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;darr; &lt;br /&gt;&lt;b&gt;[NCCL (고수준 통신)]&lt;/b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;* CUDA 기반으로, multi-GPU 통신 패턴 (broadcast, all-reduce, ...) 제공.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;* 각 패턴 내부에서, &lt;i&gt;hardware topology&lt;/i&gt; (NVLink/NVSwitch 여부, PCIe tree 구조, NUMA 등)를 보고, &lt;i&gt;어떤 알고리즘&lt;/i&gt;이 적합할지 (ring? tree? NVLS? ...), 그래서 data를 &lt;i&gt;어떤 GPU &amp;harr; GPU 경로&lt;/i&gt;로 보낼지 (direct? relay?) 결정 최적화.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;darr; &lt;br /&gt;&lt;b&gt;[CUDA (저수준 실행 + 메모리)]&lt;/b&gt;&amp;nbsp; &amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;* low-level에서 &lt;i&gt;GPU 메모리 관리 / 커널 실행 / GPU &amp;harr; GPU 데이터 복사&lt;/i&gt; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;darr; &lt;br /&gt;&lt;b&gt;[GPU&amp;nbsp;HW&amp;nbsp;(NVLink,&amp;nbsp;PCIe,&amp;nbsp;NVSwitch)]&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Unicast&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;NCCL P2P Send/Recv:&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서는 P2P 통신이기 때문에 ring/tree 같은 collective 알고리즘까지 고려하지는 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만 hardware topology 고려해서 NVLink (또는 NVLink 없으면 PCIe P2P)로 direct GPU &lt;i&gt;&amp;harr;&lt;/i&gt; GPU transport할지 / 아니면 아예 P2P 불가능하다면 Host staging ( GPU&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;i&gt;&amp;harr;&lt;/i&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt; C&lt;/span&gt;PU &lt;i&gt;&amp;harr;&lt;/i&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;GPU) 할지 정도는 고려.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;* `NCCL_P2P_DISABLE=1`: NVLink나 PCIe를 사용하는 direct GPU-to-GPU P2P transport를 끄는 옵션.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;* `NCCL_P2P_LEVEL`:&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1776048240905&quot; class=&quot;cpp&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;cpp&quot;&gt;&lt;code&gt;// rank 0 -&amp;gt; rank 1
if (rank == 0) {
  ncclSend(sendbuf, count, ncclFloat, 1, comm, stream);
} else if (rank == 1) {
  ncclRecv(recvbuf, count, ncclFloat, 0, comm, stream);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;NCCL 없이 CUDA만으로 P2P Copy 구현:&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1776046610543&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// GPU0 -&amp;gt; GPU1 로 1회 전송
cudaSetDevice(0);
float* src;
size_t bytes = N * sizeof(float);
cudaMalloc(&amp;amp;src, bytes);
// src 채우기 ...

cudaSetDevice(1);
float* dst;
cudaMalloc(&amp;amp;dst, bytes);

// device 0의 메모리를 device 1로 복사
cudaMemcpyPeerAsync(dst, 1, src, 0, bytes, stream1);&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Broadcast&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;NCCL Broadcast:&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;NCCL이 ring/tree/NVLS 등 사용 가능한 알고리즘 중에서 topology에 맞춰 선택하므로, root 단일 병목이 줄고 전체 fabric을 더 잘 쓴다. 공식 문서상 기본값은 topology와 architecture에 따라 자동 선택.&lt;/p&gt;
&lt;pre id=&quot;code_1776046659638&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 모든 rank가 같은 collective 호출
ncclBroadcast(
    sendbuff,     // root에서만 의미 있음
    recvbuff,
    count,
    ncclFloat,
    /*root=*/0,
    comm,
    stream);&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Multicast&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Multicast는 Broadcast의 좀더 general한 개념. broadcast는 &quot;모든&quot; GPU에게 방송하는 방식인 반면, multicast는 &quot;여러 몇몇&quot; GPU에게 방송하는 방식.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;NCCL에는 &amp;ldquo;사용자가 직접 `ncclMulticast(...)`를 호출하는 API&amp;rdquo;는 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앱 코드에서는 여전히 `ncclBroadcast(...);` 또는 `ncclAllReduce(...);` 호출.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 내부적으로 지원 환경이면 multicast/offload 성격의 hardware 경로를 사용할 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대신 NCCL 문서에 따르면 알고리즘 선택 변수 `NCCL_ALGO`에 `NVLS`, `NVLSTree`가 있으며, 이들은 NVLink SHARP offload를 사용.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-section-id=&quot;17m41lm&quot; data-start=&quot;6051&quot; data-end=&quot;6095&quot;&gt;&lt;b&gt;최고 성능 가능성&lt;/b&gt;: multicast-capable fabric일 때&lt;/li&gt;
&lt;li data-section-id=&quot;1k8xizs&quot; data-start=&quot;6096&quot; data-end=&quot;6158&quot;&gt;&lt;b&gt;하지만 조건이 까다로움&lt;/b&gt;: NVSwitch/NVLink SHARP 지원, 라이브러리/알고리즘 지원 필요&lt;/li&gt;
&lt;li data-section-id=&quot;f9d90c&quot; data-start=&quot;6159&quot; data-end=&quot;6195&quot;&gt;&lt;b&gt;일반 PCIe-only 환경&lt;/b&gt;에서는 이런 이점이 없습니다&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;Q. &lt;b&gt;NVLink SHARP?&lt;/b&gt;&lt;br /&gt;A. GPU 간 통신 + 연산을 &lt;b&gt;&lt;i&gt;&amp;ldquo;네트워크(NVSwitch)&amp;rdquo; 안에서&lt;/i&gt;&lt;/b&gt; 처리하는 기술.&lt;br /&gt;&lt;b&gt;SHARP&lt;/b&gt; = Scalable Hierarchical Aggregation and Reduction Protocol. 네트워크 switch 안에서 reduce (sum, max 등) 연산을 수행하게 하는 기술이다. 원래는 노드 간 통신 때 쓰이는 InfiniBand에서 나온 기술임.&lt;br /&gt;&lt;br /&gt;이걸 NVIDIA intra-node 환경(NVLink + NVSwitch)으로 끌고 와서, &lt;b&gt;NVLink SHARP&lt;/b&gt;란, 이 SHARP 기술을 같은 노드 내 GPU 간 네트워크 (NVLink + NVSwitch)에 적용한 것이다. 따라서 NVSwitch가 단순히 네트워크 switch가 아니라 data 복제 + reduction 연산까지 수행할 수 있게 한다. (GPU &amp;harr; NVSwitch &amp;harr; GPU)&lt;br /&gt;&lt;br /&gt;Ex) 기존 software 기반 allreduce는 GPU가 직접 연산을 하고 통신량이 많다:&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;GPU0 &amp;rarr; GPU1 &amp;rarr; GPU2 &amp;rarr; GPU3 (데이터 이동 + 각 GPU에서 sum)&lt;br /&gt;&lt;br /&gt;반면 NVLink SHARP는 각 GPU가 NVSwitch로 데이터를 보내면 NVSwitch가 연산하고 결과를 각 GPU에 분배한다:&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; NVSwitch &lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;/&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;|&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;\ &lt;br /&gt;GPU0 GPU1 GPU2 GPU3&lt;br /&gt;&lt;br /&gt;즉, &lt;b&gt;NVLink SHARP offload&lt;/b&gt;란 말은, 원래 GPU가 하던 연산을 NVSwitch한테 offloading한다는 뜻!&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;DGX A100 Hardware Topology&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고 사항) 아래 그림은 &lt;b&gt;NVIDIA DGX A100 노드의 hardware topology&lt;/b&gt;이다. 하단부를 보면 GPU 8대가 각각 모두 6대의 NVSwitch에 NVLink로 연결되어 있고, NVSwitch가 중간다리 역할을 해주고 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 &lt;b&gt;다른 DGX 노드에 data를 전송&lt;/b&gt;하기 위해서는:&lt;/p&gt;
&lt;pre id=&quot;code_1776128587720&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;GPU memory -&amp;gt; PCIe Bus -&amp;gt; PCIe Switch -&amp;gt; PCIe Bus -&amp;gt; NIC (InfiniBand HCA) 
    -&amp;gt; [InfiniBand Network: InfiniBand Cable -&amp;gt; InfiniBand Switch(es) -&amp;gt; InfiniBand Cable]
        -&amp;gt; Destination Node NIC -&amp;gt; ... -&amp;gt; Destination GPU memory&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게, NVSwitch 말고 PCIe Switch를 거쳐서 InfiniBand로 연결된다. (CPU도 안 거친다. a.k.a. GPU direct RDMA)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;1639&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lcS3M/dJMcabDQizh/Ul50O1FbKwj958Zc4Sj8h0/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lcS3M/dJMcabDQizh/Ul50O1FbKwj958Zc4Sj8h0/img.webp&quot; data-alt=&quot;NVIDIA DGX A100 host (official 8-card machine) hardware topology 출처: https://www.naddod.com/blog/high-performance-gpu-server-hardware-topology-and-cluster-networking-2?srsltid=AfmBOooe4aSDdrvDSFdmrJDCWpPYn7Fr81pEGr6cTsLqH3s9gK1JiHkH&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lcS3M/dJMcabDQizh/Ul50O1FbKwj958Zc4Sj8h0/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlcS3M%2FdJMcabDQizh%2FUl50O1FbKwj958Zc4Sj8h0%2Fimg.webp&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;1639&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;1639&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;NVIDIA DGX A100 host (official 8-card machine) hardware topology 출처: https://www.naddod.com/blog/high-performance-gpu-server-hardware-topology-and-cluster-networking-2?srsltid=AfmBOooe4aSDdrvDSFdmrJDCWpPYn7Fr81pEGr6cTsLqH3s9gK1JiHkH&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>분산 ML</category>
      <category>cuda</category>
      <category>multicast</category>
      <author>오렌징큐</author>
      <guid isPermaLink="true">https://orangingq.tistory.com/224</guid>
      <comments>https://orangingq.tistory.com/entry/CUDA-Multicast#entry224comment</comments>
      <pubDate>Mon, 13 Apr 2026 12:03:50 +0900</pubDate>
    </item>
    <item>
      <title>DISTMM: Accelerating Distributed Multimodal Model Training</title>
      <link>https://orangingq.tistory.com/entry/DISTMM-Accelerating-Distributed-Multimodal-Model-Training</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;논문 (NSDI'24) : &lt;a href=&quot;https://www.usenix.org/system/files/nsdi24-huang.pdf&quot;&gt;DistMM - &lt;/a&gt;&lt;a href=&quot;https://www.usenix.org/system/files/nsdi24-huang.pdf&quot;&gt;https://www.usenix.org/system/files/nsdi24-huang.pdf&lt;/a&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;Multimodal model을 분산학습시키는 상황. &lt;br /&gt;이 상황에서 분산학습 시스템의 시간/연산 효율성을 개선하려면?&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Summary&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;✨ 기존 분산 학습 시스템들은 이종적인(heterogeneous) 멀티모달 모델의 특성과 대규모 배치(large batch)를 요구하는 Contrastive Loss를 고려하지 않아 비효율적이었다.&lt;/li&gt;
&lt;li&gt; ️ DISTMM은 Modality-aware Partitioner, Data Load Balancer, Heterogeneity-aware Placement Manager를 통해 서브모듈의 이질성을 활용하고 통신 오버헤드를 줄이며, Pipeline Executor의 `batch-sync instruction` 및 DISTMM-Pipe 스케줄로 대규모 배치 요구사항을 충족한다.&lt;/li&gt;
&lt;li&gt;  다양한 구조와 규모(1.1B~26B 파라미터)의 CLIP, CoCa, LiT 모델 실험에서 DISTMM은 기존 Megatron-LM보다 1.32배에서 3.27배 빠른 학습 속도를 보였다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Problem&lt;/h2&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Multimodal model의 submodules&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;(모델 조각들)이&lt;/span&gt;&amp;nbsp;모델 구조로보나, input 크기로 보나 서로 이종적(heterogeneous)이다. -&amp;gt; -) 연산 비효율성을 초래한다.&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;기존 Multimodal Model의 특징:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;b&gt;Heterogeneous submodules:&lt;/b&gt; 각 modality마다 특징이나 구조가 다르고, 또 multimodal task가 어떤 modality를 주력으로 하는지에 따라서도 학습 구조가 달라짐. 그리고 이 modality의 구조적 이종성이 GPU utilization에도 영향을 미침.&amp;nbsp;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;CLIP: Vision module (ViT) 크기 &amp;gt;&amp;gt; Text module 크기&lt;/li&gt;
&lt;li&gt;LiT: Vision module 크기 &amp;lt;&amp;lt; Text module 크기&lt;/li&gt;
&lt;li&gt;CoCa (Contrastive captioner): Vision module 크기 $\approx$ Text module 크기&lt;/li&gt;
&lt;li&gt;-) 이 각 submodules을 동등하게 취급하면 sub-optimal한 시간 효율성을 가지게 됨.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Imbalanced input sizes:&lt;/b&gt; modality type에 따라 input size가 다름.&amp;nbsp;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;e.g., CLIP: text input은 77 단어, image는 512x512 pixel 크기 제한.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Large batch size requirement:&lt;/b&gt; 기존 연구에 따르면 contrastive learning할 때 batch size 큰 게 더 성능 차원 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;(robust &amp;amp; generalized representation)&lt;/span&gt;이나 수렴 속도 차원에서 좋다.
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;-) 여기에 pipeline parallelism을 적용하려면 최대 마이크로 배치 크기가 $(M-\frac{M_s}{P})/M_a$​로 제한되어 batch size 키우기가 어렵다. ($M$: GPU total memory, $M_s$: &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;static memory(weight, gradient, state)​, $M_a$: activation memory​)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Multimodal Model Taxonomy:&lt;/b&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 376px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;height: 21px; width: 13.4883%;&quot;&gt;&lt;b&gt; 항목&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px; width: 18.4885%;&quot;&gt;&lt;b&gt; Dual Encoder&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px; width: 21.279%;&quot;&gt;&lt;b&gt; Dual-Stream Fusion&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px; width: 23.6046%;&quot;&gt;&lt;b&gt; MLLM (LLM-based) &lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 51px;&quot;&gt;
&lt;td style=&quot;height: 51px; width: 13.4883%;&quot;&gt;&lt;b&gt;아키텍처 예시&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 51px; width: 18.4885%;&quot;&gt;- image &amp;rarr; Enc &amp;rarr;v&lt;br /&gt;- text &amp;rarr; Enc &amp;rarr;t&lt;br /&gt;=&amp;gt; sim(v,t)&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;height: 51px; width: 21.279%;&quot;&gt;- image &amp;rarr; Enc &amp;rarr;v_tokens&lt;br /&gt;- text &amp;rarr; Enc &amp;rarr;t_tokens&lt;br /&gt;=&amp;gt; cross-attn&lt;/td&gt;
&lt;td style=&quot;height: 51px; width: 23.6046%;&quot;&gt;- image&amp;rarr;Enc&amp;rarr;proj&amp;rarr;LLM&lt;br /&gt;- text&amp;rarr;LLM&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;height: 21px; width: 13.4883%;&quot;&gt;&lt;b&gt;구조 특징&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px; width: 18.4885%;&quot;&gt;완전 분리&lt;/td&gt;
&lt;td style=&quot;height: 21px; width: 21.279%;&quot;&gt;encoder 분리 후 fusion&lt;/td&gt;
&lt;td style=&quot;height: 21px; width: 23.6046%;&quot;&gt;LLM 중심 구조&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 38px;&quot;&gt;
&lt;td style=&quot;height: 38px; width: 13.4883%;&quot;&gt;&lt;b&gt;interaction 시점&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 38px; width: 18.4885%;&quot;&gt;없음&lt;/td&gt;
&lt;td style=&quot;height: 38px; width: 21.279%;&quot;&gt;중간&lt;/td&gt;
&lt;td style=&quot;height: 38px; width: 23.6046%;&quot;&gt;LLM 내부&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 38px;&quot;&gt;
&lt;td style=&quot;height: 38px; width: 13.4883%;&quot;&gt;&lt;b&gt;attention 구조&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 38px; width: 18.4885%;&quot;&gt;없음&lt;/td&gt;
&lt;td style=&quot;height: 38px; width: 21.279%;&quot;&gt;cross-attention&lt;/td&gt;
&lt;td style=&quot;height: 38px; width: 23.6046%;&quot;&gt;causal self-attention&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;height: 21px; width: 13.4883%;&quot;&gt;&lt;b&gt;대표 모델&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px; width: 18.4885%;&quot;&gt;&lt;b&gt;CLIP&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px; width: 21.279%;&quot;&gt;&lt;b&gt;BLIP, ALBEF&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px; width: 23.6046%;&quot;&gt;&lt;b&gt;LLaVA, Qwen-VL&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;height: 21px; width: 13.4883%;&quot;&gt;&lt;b&gt;입력 형태&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px; width: 18.4885%;&quot;&gt;modality별 입력&lt;/td&gt;
&lt;td style=&quot;height: 21px; width: 21.279%;&quot;&gt;tokenized separately&lt;/td&gt;
&lt;td style=&quot;height: 21px; width: 23.6046%;&quot;&gt;image&amp;rarr;token + text&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;height: 21px; width: 13.4883%;&quot;&gt;&lt;b&gt;출력 형태&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px; width: 18.4885%;&quot;&gt;embedding&lt;/td&gt;
&lt;td style=&quot;height: 21px; width: 21.279%;&quot;&gt;multimodal feature&lt;/td&gt;
&lt;td style=&quot;height: 21px; width: 23.6046%;&quot;&gt;text sequence&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;height: 21px; width: 13.4883%;&quot;&gt;&lt;b&gt;주요 목적&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px; width: 18.4885%;&quot;&gt;alignment&lt;/td&gt;
&lt;td style=&quot;height: 21px; width: 21.279%;&quot;&gt;multimodal task&lt;/td&gt;
&lt;td style=&quot;height: 21px; width: 23.6046%;&quot;&gt;generation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 34px;&quot;&gt;
&lt;td style=&quot;height: 34px; width: 13.4883%;&quot;&gt;&lt;b&gt;loss function&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 34px; width: 18.4885%;&quot;&gt;contrastive&lt;/td&gt;
&lt;td style=&quot;height: 34px; width: 21.279%;&quot;&gt;contrastive / ITM / LM&lt;/td&gt;
&lt;td style=&quot;height: 34px; width: 23.6046%;&quot;&gt;LM (cross entropy)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 34px;&quot;&gt;
&lt;td style=&quot;height: 34px; width: 13.4883%;&quot;&gt;&lt;b&gt;학습 방식&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 34px; width: 18.4885%;&quot;&gt;representation learning&lt;/td&gt;
&lt;td style=&quot;height: 34px; width: 21.279%;&quot;&gt;hybrid learning&lt;/td&gt;
&lt;td style=&quot;height: 34px; width: 23.6046%;&quot;&gt;instruction tuning&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 34px;&quot;&gt;
&lt;td style=&quot;height: 34px; width: 13.4883%;&quot;&gt;&lt;b&gt;장점&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 34px; width: 18.4885%;&quot;&gt;효율적&lt;/td&gt;
&lt;td style=&quot;height: 34px; width: 21.279%;&quot;&gt;성능 균형&lt;/td&gt;
&lt;td style=&quot;height: 34px; width: 23.6046%;&quot;&gt;reasoning / generation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;height: 21px; width: 13.4883%;&quot;&gt;&lt;b&gt;단점&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px; width: 18.4885%;&quot;&gt;interaction 없음&lt;/td&gt;
&lt;td style=&quot;height: 21px; width: 21.279%;&quot;&gt;구조 복잡&lt;/td&gt;
&lt;td style=&quot;height: 21px; width: 23.6046%;&quot;&gt;매우 무거움&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;Method&lt;/h2&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;rArr; 이 논문에서는 총 4가지 요소를 가지고 멀티모달 모델의 분산학습 시스템을 구성한다:&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;Modality-aware Partitioner: &lt;/b&gt;전체&amp;nbsp;멀티모달&amp;nbsp;모델을&amp;nbsp;입력&amp;nbsp;모달리티(modality)에&amp;nbsp;기반하여&amp;nbsp;하위&amp;nbsp;모듈(submodules)로&amp;nbsp;분할한다.&amp;nbsp;각&amp;nbsp;하위&amp;nbsp;모듈의&amp;nbsp;신경망&amp;nbsp;아키텍처와&amp;nbsp;구성이&amp;nbsp;다르다는&amp;nbsp;점을&amp;nbsp;활용하여,&amp;nbsp;하위&amp;nbsp;모듈&amp;nbsp;크기에&amp;nbsp;따라&amp;nbsp;독립적인&amp;nbsp;병렬화&amp;nbsp;전략을&amp;nbsp;적용한다.&amp;nbsp;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;e.g., 연산이 많은 submodule은 TP를 쓰고, 단일장치에 load 가능한 작은 크기의 submodule은 DP를 쓰도록.&lt;/li&gt;
&lt;li&gt;+)&amp;nbsp;각&amp;nbsp;모달&amp;nbsp;하위&amp;nbsp;모듈의&amp;nbsp;계산&amp;nbsp;지속&amp;nbsp;시간을&amp;nbsp;균형&amp;nbsp;있게&amp;nbsp;맞춰&amp;nbsp;전체적인&amp;nbsp;높은&amp;nbsp;계산&amp;nbsp;효율성을&amp;nbsp;달성.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Data Load Balancer&lt;/b&gt;: Modality-aware Partitioner에 의해 분할된 하위 모듈과 클러스터 구성을 입력으로 받아, 각 하위 모듈 파티션에 할당할 장치 수와 데이터 배치 크기를 결정한다. (Dynamic programming으로 최적화)
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;+) 각 모달 하위 모듈의 계산 지속 시간을 균형 있게 맞춰 전체적인 높은 계산 효율성을 달성.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Heterogeneity-aware Placement Manager:&lt;/b&gt; 각 submodule의 locality (=어떤 submodule을 어떤 node의 어떤 GPU에 배치할지)를 최적화했다.
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;노드 내 NVLink와 노드 간 Ethernet의 bandwidth 차이를 고려.&lt;/li&gt;
&lt;li&gt;e.g., 동일 modality 내 submodules -&amp;gt; 서로 가깝게 배치하여 고대역폭 링크를 활용 / 다른 modality의 submodules -&amp;gt; 별도의 노드에 배치하여 저대역폭 링크에서의 통신량(communication volume)을 줄임.&lt;/li&gt;
&lt;li&gt;+) submodule 간 통신량을 고려하여 배치함으로써 통신량, 통신 시간 최적화.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Pipeline Executor:&lt;/b&gt; 기존의 pipeline execution schedule의 batch size 한계를 극복하고자 새로운 pipeline executor를 제안.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1357&quot; data-origin-height=&quot;505&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c1Yfkw/dJMcagEO6z0/odyT1N9yjKqiNR4jKCuDOk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c1Yfkw/dJMcagEO6z0/odyT1N9yjKqiNR4jKCuDOk/img.png&quot; data-alt=&quot;DistMM Overview&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c1Yfkw/dJMcagEO6z0/odyT1N9yjKqiNR4jKCuDOk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc1Yfkw%2FdJMcagEO6z0%2FodyT1N9yjKqiNR4jKCuDOk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1357&quot; height=&quot;505&quot; data-origin-width=&quot;1357&quot; data-origin-height=&quot;505&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;DistMM Overview&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그림을 보면,&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;Modality-aware Partitioner&lt;/b&gt;가 image module (파랑)과 text module (노랑)을 각각 4등분, 16등분한다. 아마도 parameter size 같은 모델의 meta 정보 가지고 4와 16이라는 값을 결정한듯. 이 4등분/16등분 값은 다시 말해 TP degree x PP degree를 의미한다. (e.g., 파랑 모듈: TP degree x PP degree = 4가 되어야 함)&lt;/li&gt;
&lt;li&gt;그 다음, &lt;b&gt;Data Load Balancer&lt;/b&gt;가 전체 batch size (Gbs=72)에 맞춰서, DP degree와 각 DP group 별 batch size를 결정. 그래서 파랑 모듈은 4개의 replica가 필요하고 (dp degree=4, 각 replica 당 batchsize (Rbs)=18), 노랑 모듈은 3개의 replica가 필요하다 (dp degree=3, Rbs=24).&amp;nbsp;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Heterogeneity-aware Placement Manager&lt;/b&gt;가 이제 마지막으로 실제로 GPU를 할당해주고, 이에 따라 TP degree와 PP degree도 결정된다. 이 예시에서는 전체 GPU cluster가 8개 GPU 짜리 node 8개인 상황에서, &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;GPU 16개짜리&lt;span&gt; &lt;/span&gt;&lt;/span&gt;노랑 모듈 replica 3개와 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;GPU 4개짜리&lt;span&gt; &lt;/span&gt;&lt;/span&gt;파랑 모듈 replica 4개를 통신 효율적으로 배치해야 한다.
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;아무래도 DP replica들은 sync를 해줘야 하니까 replica들끼리는 TP degree / PP degree가 통일되는 게 연산 시간을 맞추는데 도움이 되겠지.&lt;/li&gt;
&lt;li&gt;노랑이 먼저 생각해보면 TP deg x PP deg = 16이어야 하는데, TP가 통신량이 많이 heavy하니까 TP degree를 낮추고 TP group끼리는 같은 node에 배치해주어야 함. 그러면 TP deg = 2이거나 4 정도가 적당. 근데 TP deg =2인 경우는 PP deg=8이 되어 pipeline bubble 현상이 심화되는 문제도 발생할 수 있고, 파랑 모듈 replica들을 모두 서로 다른 node에 배치시켜야 해서 파랑 모듈의 DP grad sync 통신량도 상당해진다. 뭐 이러저러한 계산 결과로.. (실제 결정할 때는 이렇게 heuristic하게 결정하지는 않겠지. &lt;s&gt;아님 말고&lt;/s&gt;)&amp;nbsp;&lt;/li&gt;
&lt;li&gt;결과적으로 ... 최종 degree (DP deg, PP deg, TP deg)는 노랑 모듈: (3, 4, 4), 파랑 모듈: (4, 2, 2) 로 결정이 난다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&amp;nbsp;마지막, &lt;b&gt;Pipeline Executor&lt;/b&gt;가 이 PP deg를 고려해서 interleaved 1f1b schedule을 만들었다. 이 때 각 GPU의 메모리 사정을 고려했을 때 microbatch size (Mbs)는 노랑 모듈이 3, 파랑 모듈이 2가 되고, 기존에 Rbs가 각각 18, 24이었으니까 microbatch 수는 각각 6, 12가 된다.&amp;nbsp;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;이 때 노랑 모듈과 파랑 모듈 feature vector를 짬뽕해서 similarity 계산하는 modality interactive module의 경우 언제 연산해주어야 하느냐? (이 모듈을 학습할 때는 노랑 pipeline과 파랑 pipeline 간 sync가 필요한 상황.) 얘는 모듈 간 통신이 필요하다보니까 매 microbatch마다 연산하지 않고, 그림에서 Interactive Computations로 적힌 빨간 선 부분에서 한번에 통합해서 연산함.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Modality-aware Partitioner&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존 분산학습 시스템에서는 submodule을 다 통합 고려해서 전체 모델 대상으로 모델을 split했다면, 이 Modality-aware Partitioner에서는 각 submodule을 독립적으로 고려해서 split한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 이 단계에서는 &lt;b&gt;GPU에다가 모델 쪼개는 방식을 최적화.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1006&quot; data-origin-height=&quot;562&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lf9U7/dJMcagktN2j/NKfKaHhD4ht2MreRrRKHe1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lf9U7/dJMcagktN2j/NKfKaHhD4ht2MreRrRKHe1/img.png&quot; data-alt=&quot;(a) 기존 Colocated solution 대비 (b) DistMM의 Modality-aware Partitioner&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lf9U7/dJMcagktN2j/NKfKaHhD4ht2MreRrRKHe1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Flf9U7%2FdJMcagktN2j%2FNKfKaHhD4ht2MreRrRKHe1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;335&quot; data-origin-width=&quot;1006&quot; data-origin-height=&quot;562&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;(a) 기존 Colocated solution 대비 (b) DistMM의 Modality-aware Partitioner&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;modality interactive submodule 같은 경우는 연산이 heavy하지 않고 통신량도 적기 때문에 각 device에 균등하게 나눠담는다.&lt;/li&gt;
&lt;li&gt;그리고 각 modal module의 경우, efficiency를 최대화하는 방향으로 adaptive하게, 그리고 독립적으로 split해서 device에 나눠담는다.&amp;nbsp;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;이 때 parallelism strategy라던가 parallelism degree 같은 것들은 common practice를 따른다 (model size 고려해서 DP를 할 수도 있고 TP를 할 수도 있고 PP를 할 수도 있고).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Data Load Balancer&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서 모델을 잘 쪼개줬다면,&amp;nbsp;Data Load Balancer는 &lt;b&gt;cluster setup&lt;/b&gt;(node 몇 개고 node 당 device 몇 개인지)과 &lt;b&gt;training config&lt;/b&gt;(Modality-aware partitioner에 의해 쪼개진 model partition들 정보와 global batch size)&lt;b&gt;를 input으로 받아서&lt;/b&gt;, &lt;b&gt;각 model partition이 몇 개의 device에 할당될지&lt;/b&gt; (e.g., DP의 경우 여러 대 GPU에 model partition replica를 load해야 함)&lt;b&gt;를 결정(&quot;resource assignment plan&quot;)&lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;목표는 가장 느린 model partition의 연산 시간을 최소화하는 것.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1006&quot; data-origin-height=&quot;568&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MMAO3/dJMcagLAcDL/ikHBot2ekK3cK9sOgMMh90/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MMAO3/dJMcagLAcDL/ikHBot2ekK3cK9sOgMMh90/img.png&quot; data-alt=&quot;(a) 기존 Colocated solution 대비 (b) DistMM의 Data load balancer&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MMAO3/dJMcagLAcDL/ikHBot2ekK3cK9sOgMMh90/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMMAO3%2FdJMcagLAcDL%2FikHBot2ekK3cK9sOgMMh90%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;603&quot; height=&quot;340&quot; data-origin-width=&quot;1006&quot; data-origin-height=&quot;568&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;(a) 기존 Colocated solution 대비 (b) DistMM의 Data load balancer&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Heterogeneity-aware Placement Manager&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 각 model partition 별 GPU 수가 정해졌으니, 이를 바탕으로 Heterogeneity-aware Placement Manager에서는 bandwidth를 고려해 communication-efficient한 방식으로 실제 device에 배치해준다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서 모델 어떻게 쪼개서 몇 개 GPU 쓰라고 결정했다면 여기서는 &lt;b&gt;&quot;그래서 어떤 GPU에 어떤 model partition을 배정할지&quot;&lt;/b&gt;를 정하는 단계.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;998&quot; data-origin-height=&quot;564&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zK6hZ/dJMcacJbHIq/NGKDMUGKhuAtPXKIPI3OG1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zK6hZ/dJMcacJbHIq/NGKDMUGKhuAtPXKIPI3OG1/img.png&quot; data-alt=&quot;(a) 기존 Colocated solution 대비 (b) DistMM의 Heterogeneity-aware Placement&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zK6hZ/dJMcacJbHIq/NGKDMUGKhuAtPXKIPI3OG1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzK6hZ%2FdJMcacJbHIq%2FNGKDMUGKhuAtPXKIPI3OG1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;601&quot; height=&quot;340&quot; data-origin-width=&quot;998&quot; data-origin-height=&quot;564&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;(a) 기존 Colocated solution 대비 (b) DistMM의 Heterogeneity-aware Placement&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 그림 예시를 보면, 원래 colocated solution에서는 파랑색 모달과 주황색 모달 모두 4개 GPU에 쪼갰다보니 4개 GPU가 다 통합적으로 gradient AllReduce를 해야 했는데, 이제는 파랑색 모달은 GPU 하나에 담겨서 allreduce가 필요 없어지고 주황색 모달은 3개 GPU끼리만 allreduce하면 돼서 확실히 comm. efficient해졌다.&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Pipeline Executor&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 PP를 적용할 때 가장 포인트는, 학습에서 요구되는 batch size (Required batch size, Rbs)와 실제 GPU의 메모리가 감당할 수 있는 micro batch size (Mbs)의 격차를 고려하는 것이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;K=Rbs/Mbs라고 할 때, DistMM-Pipe는 Mbs/2 크기의 2K개 microbatch로 쪼개서 ...???&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;305&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/coyD2i/dJMcajapB3I/utQHKpd2Zbu5Sh2pRr9dr1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/coyD2i/dJMcajapB3I/utQHKpd2Zbu5Sh2pRr9dr1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/coyD2i/dJMcajapB3I/utQHKpd2Zbu5Sh2pRr9dr1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcoyD2i%2FdJMcajapB3I%2FutQHKpd2Zbu5Sh2pRr9dr1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;305&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;305&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Pipeline Executor는 실행 스케줄 명령하는 Batch-sync instruction 부분과&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원래 PP에서는 각 stage에서 gradient까지Contrastive Learning할 때 similarity를 계산하는데, 이걸 위해서는 ...???&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Batch-sync instruction은 총 4단계로 구성됨:&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Memory movement: 이전 K개 microbatch의 forward 결과 feature vector를 continuous feature vector로 합치는 작업.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;Forward pass&amp;nbsp;of modal interactive&amp;nbsp;submodule&lt;/li&gt;
&lt;li&gt;Backward pass of&amp;nbsp;modal&amp;nbsp;interactive&amp;nbsp;submodule: modality interactive submodule의 backward 실행 -&amp;gt; continuous feature vector에 대한 gradient 생성.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;Memory dispatching: continuous gradients를 각 microbatch의 feature vector에 대한 개별적인 gradient (총 K개)로 분리하는 작업.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-) 근데 솔직히 .. pipeline executor 부분 이해 못했음. 그림에서 overhead reduction은 그냥 GPipe 쓸 거 1f1b 쓰고 microbatch 두 배로 쪼개서 줄어든 거 아니야? 이 논문의 novelty에 의한 감소는 아닌 거 같은데.. 그리고 논문에서 Mbs/2 크기의 2K개 microbatch로 나눴다는데, 왜 굳이 2야?&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Strength&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;+) VLM의 모달리티 간 독립성을 고려한 분산 시스템 디자인이라는 점.&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Weakness&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-) 그리고 전반적으로 dual encoder (e.g., CLIP) 구조에 맞춰서 설계된 거 같다. 요즘 많이 쓰는 MLLM 구조랑은 잘 안 맞는 듯.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-) 그리고 transformer 구조들은 Sequence Parallelism도 많이 쓰는데 여기서는 고려가 안 되어 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>분산 ML</category>
      <category>Distributed_Learning</category>
      <category>Multimodal</category>
      <author>오렌징큐</author>
      <guid isPermaLink="true">https://orangingq.tistory.com/223</guid>
      <comments>https://orangingq.tistory.com/entry/DISTMM-Accelerating-Distributed-Multimodal-Model-Training#entry223comment</comments>
      <pubDate>Wed, 18 Mar 2026 13:52:44 +0900</pubDate>
    </item>
    <item>
      <title>Sequence Parallelism: Long Sequence Training from System Perspective</title>
      <link>https://orangingq.tistory.com/entry/Sequence-Parallelism-Long-Sequence-Training-from-System-Perspective</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;논문 (ACL'23) :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://arxiv.org/abs/2105.13120&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Sequence Parallelism: Long Sequence Training from System Perspective&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://aclanthology.org/2023.acl-long.134.pdf&quot;&gt;(https://aclanthology.org/2023.acl-long.134.pdf)&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1773366743168&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Sequence Parallelism: Long Sequence Training from System Perspective&quot; data-og-description=&quot;Transformer achieves promising results on various tasks. However, self-attention suffers from quadratic memory requirements with respect to the sequence length. Existing work focuses on reducing time and space complexity from an algorithm perspective. In t&quot; data-og-host=&quot;arxiv.org&quot; data-og-source-url=&quot;https://arxiv.org/abs/2105.13120&quot; data-og-url=&quot;https://arxiv.org/abs/2105.13120v3&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bCmDU8/dJMb9kmbgBy/EPKHTxJ0vkHchYIKp5dsgK/img.png?width=1200&amp;amp;height=700&amp;amp;face=0_0_1200_700,https://scrap.kakaocdn.net/dn/jWTlN/dJMb9iIFAzP/VqrikIDEoUZb49tthZKmZ0/img.png?width=1000&amp;amp;height=1000&amp;amp;face=0_0_1000_1000&quot;&gt;&lt;a href=&quot;https://arxiv.org/abs/2105.13120&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://arxiv.org/abs/2105.13120&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bCmDU8/dJMb9kmbgBy/EPKHTxJ0vkHchYIKp5dsgK/img.png?width=1200&amp;amp;height=700&amp;amp;face=0_0_1200_700,https://scrap.kakaocdn.net/dn/jWTlN/dJMb9iIFAzP/VqrikIDEoUZb49tthZKmZ0/img.png?width=1000&amp;amp;height=1000&amp;amp;face=0_0_1000_1000');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Sequence Parallelism: Long Sequence Training from System Perspective&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Transformer achieves promising results on various tasks. However, self-attention suffers from quadratic memory requirements with respect to the sequence length. Existing work focuses on reducing time and space complexity from an algorithm perspective. In t&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;arxiv.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이 논문은 &lt;i&gt;&lt;b&gt;긴 context를 다루는 Transformer 모델에 대해 분산학습하는 상황&lt;/b&gt;&lt;/i&gt;을 가정한다.&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;#Long-Context #Transformer #Distributed_Learning&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;Problem&lt;/h2&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Transformer 모델에서 긴 context를 다루는 능력은 중요하고 많이 쓰이는데,&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;문제가 context size를 $ L $이라고 하면, &lt;b&gt;메모리 요구량&lt;/b&gt;이 $ L^2 $에 비례한다. 그래서 메모리의 한계로 인해 긴 context 학습이 어려운 상황이었다.&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Q. 기존 분산학습 방법들을 가지고 해결할 수 없나?&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;A. 기존 분산학습은 주로 DP / PP / TP 방식이 있고, 이거도 방법은 될 수 있지만, directly $L$-term을 손 보는 게 아니라 다른 차원의 메모리량을 줄여서 (e.g., hidden_dim size를 줄인다거나 (TP), batch size를 줄인다거나 (DP), layer 단위로 모델을 잘라서 각 GPU에 넣는다거나 (PP)...) 전체 메모리 요구량을 줄이는 방식이다.&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;rArr; 이 논문은 long-context Transformer 모델의 메모리 요구량을 낮추기 위해 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;시스템 관점에서 &lt;b&gt;직접적으로 context size (or sequence length) $ L $ 차원을 쪼개는&lt;/b&gt; 방법을 택한다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;아래 TP와의 비교 그림을 보면, layer의 hidden_dim 차원으로 모델을 쪼개는 TP와 달리 &lt;b&gt;SP는 Input을 token dim으로 분리&lt;/b&gt;한다. 그래서 엄밀히 말하면 모델은 쪼개지지 않고 각 device에 replica로 올라간다. 모델을 안 쪼개고 input을 쪼갠다는 관점에서 오히려 DP랑 비슷한 느낌. Transformer를 위한 DP 느낌.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2084&quot; data-origin-height=&quot;849&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xlN9M/dJMcabpTI8c/rQf3YpkpFO9zuzk0u4HvzK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xlN9M/dJMcabpTI8c/rQf3YpkpFO9zuzk0u4HvzK/img.png&quot; data-alt=&quot;TP vs SP&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xlN9M/dJMcabpTI8c/rQf3YpkpFO9zuzk0u4HvzK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxlN9M%2FdJMcabpTI8c%2FrQf3YpkpFO9zuzk0u4HvzK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;651&quot; height=&quot;265&quot; data-origin-width=&quot;2084&quot; data-origin-height=&quot;849&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;TP vs SP&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;Method: Ring Self-Attention&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Input을 token-level로 쪼개서 각 device에 나눠담는다.
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;input $X^{(n)}$: $ (L/N, d) $ (기본 transformer 구조에서 attention block 직전의 input dim이 $ (L, d) $이고 이걸 $N$개 GPU에 나눠담는다 가정)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;각 GPU에서 local하게 Q, K, V projection 연산 ($Q ^{(n)} =X ^{(n)} W_Q, K ^{(n)} =X ^{(n)} W_K, V ^{(n)} =X ^{(n)} W_V$).&amp;nbsp;&lt;br /&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;Parameters $W_Q, W_K, W_V$: $(d, d_h) $가 각각 head 수 $H$개 만큼씩 있음. ($ d_h $: head 별 hidden dim.) 이거는 기본 transformer랑 동일함. 각 local device에 같은 parameter replica들이 복사되어 올라감.&lt;/li&gt;
&lt;li&gt;$Q ^{(n)} , K ^{(n)} , V ^{(n)} $: $(L/N, d_h) $&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Attention 연산 ($A ^{(n)} = softmax(\frac{Q ^{(n)} K^\top}{\sqrt{d}})$).
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;$K=\{K ^{(1)}, K ^{(2)} ,\dots, K ^{(N)} \}$ all-gather (Fig. 2 (a)): 원래 transformer 같으면 그냥 $QK^ \top $ 연산하면 되는데 여기는 $Q ^{(n)} , K ^{(n)} $로 쪼개져 있으니까 최소한 $K ^{(n)} $는 all-gather를 해줘야 함. 자기가 갖고 있던/혹은 받은 $K ^{(n)} $를 다음 device에 circular하게 총 $N-1$번 넘겨준다. =&amp;gt; 모든 device가 전체 $L \times d_h$ 크기의 full $K$를 가지게 됨.&lt;/li&gt;
&lt;li&gt;$A ^{(n)} $: $(L/N, L)$. 쪼개진 $Q ^{(n)} $이랑 full $K$랑 matmul하고 softmax까지.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Output 연산 ($O&amp;nbsp;^{(n)} = A ^{(n)}V$).
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;$V=\{V^{(1)}, V ^{(2)} ,\dots, V ^{(N)} \}$ all-gather (Fig. 2 (b)): 비슷하게 각 device에서 갖고 있던 / 혹은 이전 device로부터 받은 Value embedding $V^{(n)}$을 다음 device에 circular하게 총 $N-1$번 넘겨준다. =&amp;gt; 모든 device가 전체 $L \times d_h$ 크기의 full $V$를 가지게 됨.&lt;/li&gt;
&lt;li&gt;$O ^{(n)} $: $(L/N, d_h)$&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2228&quot; data-origin-height=&quot;1482&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ckw3G0/dJMcahcy9h3/W3Hxo9vU3cslcRQKehfbCk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ckw3G0/dJMcahcy9h3/W3Hxo9vU3cslcRQKehfbCk/img.png&quot; data-alt=&quot;Ring Self-Attention 제안.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ckw3G0/dJMcahcy9h3/W3Hxo9vU3cslcRQKehfbCk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fckw3G0%2FdJMcahcy9h3%2FW3Hxo9vU3cslcRQKehfbCk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;565&quot; height=&quot;376&quot; data-origin-width=&quot;2228&quot; data-origin-height=&quot;1482&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Ring Self-Attention 제안.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Q. 왜 꼭 ring style P2P 해야 하나? 사실상 결과 all-gather랑 같은 거 아닌가?&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;A. GPT의 정리에 의하면... 한마디로, ring-style P2P가 all-gather에 비해 시간이 더 오래걸리고 대신 memory usage를 줄인 버전이라고 보면 될듯. 약간 &lt;b&gt;online streaming 버전의 all-gather&lt;/b&gt; 느낌.&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 469px;&quot; border=&quot;1&quot; data-end=&quot;1061&quot; data-start=&quot;142&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;height: 17px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;height: 17px;&quot;&gt;&lt;b&gt;All-Gather&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 17px;&quot;&gt;&lt;b&gt;Ring-style P2P&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 42px;&quot; data-end=&quot;294&quot; data-start=&quot;201&quot;&gt;
&lt;td style=&quot;height: 42px;&quot; data-col-size=&quot;sm&quot; data-end=&quot;211&quot; data-start=&quot;201&quot;&gt;기본 아이디어&lt;/td&gt;
&lt;td style=&quot;height: 42px;&quot; data-end=&quot;252&quot; data-start=&quot;211&quot; data-col-size=&quot;md&quot;&gt;각 GPU shard를 &lt;b&gt;모두 모아서 full tensor 생성&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 42px;&quot; data-end=&quot;294&quot; data-start=&quot;252&quot; data-col-size=&quot;md&quot;&gt;tensor block을 &lt;b&gt;GPU 사이에서 순환 전달하면서 계산&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 128px;&quot;&gt;
&lt;td style=&quot;height: 128px;&quot;&gt;통신 패턴&lt;/td&gt;
&lt;td style=&quot;height: 128px;&quot;&gt;각 GPU i가 xi 들고 있을 때, &amp;nbsp;All-Gather 한 번으로 &amp;rarr;&lt;br /&gt;GPU0:&amp;nbsp;[x0&amp;nbsp;x1&amp;nbsp;x2&amp;nbsp;x3]&lt;br /&gt;GPU1:&amp;nbsp;[x0&amp;nbsp;x1&amp;nbsp;x2&amp;nbsp;x3]&lt;br /&gt;GPU2:&amp;nbsp;[x0&amp;nbsp;x1&amp;nbsp;x2&amp;nbsp;x3]&lt;br /&gt;GPU3: [x0 x1 x2 x3]&lt;br /&gt;모든&amp;nbsp;GPU가&amp;nbsp;full&amp;nbsp;tensor&amp;nbsp;보유&lt;/td&gt;
&lt;td style=&quot;height: 128px;&quot;&gt;GPU0 &amp;rarr; GPU1 &amp;rarr; GPU2 &amp;rarr; GPU3 &amp;rarr; GPU0&lt;br /&gt;총 N-1번의 P2P가 발생하고, 각 step 마다:&lt;br /&gt;1) receive &lt;span style=&quot;background-color: #f9f9f9; color: #333333; text-align: start;&quot;&gt;xi&lt;/span&gt; &lt;br /&gt;2) compute (e.g., attention A 연산)&lt;br /&gt;3) send &lt;span style=&quot;background-color: #f9f9f9; color: #333333; text-align: start;&quot;&gt;xi&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot; data-end=&quot;366&quot; data-start=&quot;295&quot;&gt;
&lt;td style=&quot;height: 21px;&quot; data-col-size=&quot;sm&quot; data-end=&quot;303&quot; data-start=&quot;295&quot;&gt;통신 방식&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot; data-end=&quot;334&quot; data-start=&quot;303&quot; data-col-size=&quot;md&quot;&gt;&lt;b&gt;Collective communication&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot; data-end=&quot;366&quot; data-start=&quot;334&quot; data-col-size=&quot;md&quot;&gt;&lt;b&gt;Point-to-point streaming&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot; data-end=&quot;409&quot; data-start=&quot;367&quot;&gt;
&lt;td style=&quot;height: 17px;&quot; data-col-size=&quot;sm&quot; data-end=&quot;382&quot; data-start=&quot;367&quot;&gt;GPU topology&lt;/td&gt;
&lt;td style=&quot;height: 17px;&quot; data-end=&quot;401&quot; data-start=&quot;382&quot; data-col-size=&quot;md&quot;&gt;broadcast / tree&lt;/td&gt;
&lt;td style=&quot;height: 17px;&quot; data-end=&quot;409&quot; data-start=&quot;401&quot; data-col-size=&quot;md&quot;&gt;ring&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot; data-end=&quot;453&quot; data-start=&quot;410&quot;&gt;
&lt;td style=&quot;height: 21px;&quot; data-col-size=&quot;sm&quot; data-end=&quot;418&quot; data-start=&quot;410&quot;&gt;통신 단계&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot; data-end=&quot;431&quot; data-start=&quot;418&quot; data-col-size=&quot;md&quot;&gt;&lt;b&gt;1 step&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot; data-end=&quot;453&quot; data-start=&quot;431&quot; data-col-size=&quot;md&quot;&gt;&lt;b&gt;N-1 steps&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot; data-end=&quot;623&quot; data-start=&quot;554&quot;&gt;
&lt;td style=&quot;height: 21px;&quot; data-col-size=&quot;sm&quot; data-end=&quot;568&quot; data-start=&quot;554&quot;&gt;통신 후 tensor&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot; data-end=&quot;604&quot; data-start=&quot;568&quot; data-col-size=&quot;md&quot;&gt;full tensor 크기&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot; data-end=&quot;623&quot; data-start=&quot;604&quot; data-col-size=&quot;md&quot;&gt;여전히 local shard&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot; data-end=&quot;894&quot; data-start=&quot;859&quot;&gt;
&lt;td style=&quot;height: 21px;&quot; data-col-size=&quot;sm&quot; data-end=&quot;869&quot; data-start=&quot;859&quot;&gt;latency&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot; data-end=&quot;874&quot; data-start=&quot;869&quot; data-col-size=&quot;md&quot;&gt;낮음&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot; data-end=&quot;894&quot; data-start=&quot;874&quot; data-col-size=&quot;md&quot;&gt;높음 (N-1 iteration)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot; data-end=&quot;951&quot; data-start=&quot;895&quot;&gt;
&lt;td style=&quot;height: 21px;&quot; data-col-size=&quot;sm&quot; data-end=&quot;914&quot; data-start=&quot;895&quot;&gt;pipeline overlap&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot; data-end=&quot;920&quot; data-start=&quot;914&quot; data-col-size=&quot;md&quot;&gt;제한적&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot; data-end=&quot;951&quot; data-start=&quot;920&quot; data-col-size=&quot;md&quot;&gt;가능 (compute + comm overlap)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot; data-end=&quot;1061&quot; data-start=&quot;1010&quot;&gt;
&lt;td style=&quot;height: 21px;&quot; data-col-size=&quot;sm&quot; data-end=&quot;1023&quot; data-start=&quot;1010&quot;&gt;softmax 처리&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot; data-end=&quot;1036&quot; data-start=&quot;1023&quot; data-col-size=&quot;md&quot;&gt;일반 softmax&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot; data-end=&quot;1061&quot; data-start=&quot;1036&quot; data-col-size=&quot;md&quot;&gt;&lt;b&gt;online softmax 필요&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Q. 이렇게 했을 때, PP나 TP 대비 memory usage / communication overhead 차원에서 어떤 이점이 있나?&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;A. 일단 &lt;b&gt;메모리 차원 분석&lt;/b&gt;: 표 1에서 TP와의 memory 비교 제공함. TP와 SP를 비교하면, TP는 parameter들을 쪼갰고, SP는 input을 쪼갠다. 그래서 TP는 다음 layer의 input dim을 유지하기 위해 output dimension을 맞춰줘야 하고, 그러기 위해 output을 매번 all-gather해줘야 한다. 반면, SP는 어차피 다음 layer의 input dim도 쪼개진 상태니까 굳이 output dim을 맞추기 위해 추가적인 all-gather가 필요하지 않다. 다시 말해 output dim도 쪼개진 상태로 유지 가능!&amp;nbsp; &amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1538&quot; data-origin-height=&quot;1229&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/baRqXQ/dJMcadgXH1s/pX7ViiiYpijklOBsaa2igk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/baRqXQ/dJMcadgXH1s/pX7ViiiYpijklOBsaa2igk/img.png&quot; data-alt=&quot;Memory Usage Comparison: TP vs SP (B: batch size, H: hidden dim (=$d$), Z: head 수 (=$H$), A: (=$d_h$))&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/baRqXQ/dJMcadgXH1s/pX7ViiiYpijklOBsaa2igk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbaRqXQ%2FdJMcadgXH1s%2FpX7ViiiYpijklOBsaa2igk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1538&quot; height=&quot;1229&quot; data-origin-width=&quot;1538&quot; data-origin-height=&quot;1229&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Memory Usage Comparison: TP vs SP (B: batch size, H: hidden dim (=$d$), Z: head 수 (=$H$), A: (=$d_h$))&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1980&quot; data-origin-height=&quot;574&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bInAyN/dJMcafeOJCr/mwe3bTpMeFkUFkaHGfUqkK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bInAyN/dJMcafeOJCr/mwe3bTpMeFkUFkaHGfUqkK/img.png&quot; data-alt=&quot;Tensor Parallelism 구조&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bInAyN/dJMcafeOJCr/mwe3bTpMeFkUFkaHGfUqkK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbInAyN%2FdJMcafeOJCr%2Fmwe3bTpMeFkUFkaHGfUqkK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1980&quot; height=&quot;574&quot; data-origin-width=&quot;1980&quot; data-origin-height=&quot;574&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Tensor Parallelism 구조&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 &lt;b&gt;communication cost&lt;/b&gt;도 비교해보면:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;TP: forward, backward 때 한 layer당 각 2번 (=&amp;gt; 총 4번)의 all-gather 필요, 한 번 all gather 당 N-1 번의 송/수신 (=&amp;gt; 총 2(N-1)번) 필요 (ring all-gather), 매번 $(B, L, H/N)$ 크기의 data 송/수신
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;=&amp;gt; 총 $8(N-1) \times (BLH/N) $.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;SP: forward 때 ring-style P2P가 (N-1)번씩 두 번 (each for K, V of size $BLH/N $) 발생, backward 때는 $\frac{\partial L}{\partial W^O}$와 $\frac{\partial L}{\partial A}$를 구하기 위해 all-reduce 한 번씩, $\frac{\partial L}{\partial K}$와 $\frac{\partial L}{\partial V}$ 얻기 위해 ring-style P2P (N-1)번씩 $BLH/N$ 크기의 data 통신.
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;=&amp;gt; 총 $6(N-1)\times (BLH/N)$.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;Strength&lt;/h2&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;+) context scaling에 좋은 기법인듯. TP랑 비슷하면서도 memory usage나 communication cost는 더 적고.&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;Weakness&lt;/h2&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;-) online softmax를 썼을 것으로 추정되는데 관련 언급이 별로 없는..? online softmax가 전체 convergence에도 영향을 줄 것 같은데. Appendix B 보면 convergence performance가 TP랑 SP랑 완전히 같지가 않다. 물론 논문에서는 SP가 더 빠르게 수렴한다고 주장하지만, 좀 더 분석이 필요할지도.&lt;/p&gt;</description>
      <category>분산 ML</category>
      <author>오렌징큐</author>
      <guid isPermaLink="true">https://orangingq.tistory.com/222</guid>
      <comments>https://orangingq.tistory.com/entry/Sequence-Parallelism-Long-Sequence-Training-from-System-Perspective#entry222comment</comments>
      <pubDate>Sun, 15 Mar 2026 00:18:13 +0900</pubDate>
    </item>
    <item>
      <title>DeepSpeed-Ulysses</title>
      <link>https://orangingq.tistory.com/entry/DeepSpeed-Ulysses</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;논문 (ArXiv'23) : &lt;a href=&quot;https://arxiv.org/abs/2309.14509&quot;&gt;DeepSpeed Ulysses: System Optimizations for Enabling Training of Extreme Long Sequence Transformer Models&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1773212903413&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;DeepSpeed Ulysses: System Optimizations for Enabling Training of Extreme Long Sequence Transformer Models&quot; data-og-description=&quot;Computation in a typical Transformer-based large language model (LLM) can be characterized by batch size, hidden dimension, number of layers, and sequence length. Until now, system works for accelerating LLM training have focused on the first three dimensi&quot; data-og-host=&quot;arxiv.org&quot; data-og-source-url=&quot;https://arxiv.org/abs/2309.14509&quot; data-og-url=&quot;https://arxiv.org/abs/2309.14509v2&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/caOb34/dJMb9iIFp2K/cH1APt8XCZIrY6ukPY9oI0/img.png?width=1200&amp;amp;height=700&amp;amp;face=0_0_1200_700,https://scrap.kakaocdn.net/dn/4CRAq/dJMb9kT1iso/xIwZwuWHoWxIIjmvE4kCr1/img.png?width=1000&amp;amp;height=1000&amp;amp;face=0_0_1000_1000&quot;&gt;&lt;a href=&quot;https://arxiv.org/abs/2309.14509&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://arxiv.org/abs/2309.14509&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/caOb34/dJMb9iIFp2K/cH1APt8XCZIrY6ukPY9oI0/img.png?width=1200&amp;amp;height=700&amp;amp;face=0_0_1200_700,https://scrap.kakaocdn.net/dn/4CRAq/dJMb9kT1iso/xIwZwuWHoWxIIjmvE4kCr1/img.png?width=1000&amp;amp;height=1000&amp;amp;face=0_0_1000_1000');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;DeepSpeed Ulysses: System Optimizations for Enabling Training of Extreme Long Sequence Transformer Models&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Computation in a typical Transformer-based large language model (LLM) can be characterized by batch size, hidden dimension, number of layers, and sequence length. Until now, system works for accelerating LLM training have focused on the first three dimensi&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;arxiv.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사이트 : &lt;a href=&quot;https://github.com/deepspeedai/DeepSpeed/tree/master/blogs/deepspeed-ulysses&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/deepspeedai/DeepSpeed/tree/master/blogs/deepspeed-ulysses&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1773213106607&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;DeepSpeed/blogs/deepspeed-ulysses at master &amp;middot; deepspeedai/DeepSpeed&quot; data-og-description=&quot;DeepSpeed is a deep learning optimization library that makes distributed training and inference easy, efficient, and effective. - deepspeedai/DeepSpeed&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/deepspeedai/DeepSpeed/tree/master/blogs/deepspeed-ulysses&quot; data-og-url=&quot;https://github.com/deepspeedai/DeepSpeed/tree/master/blogs/deepspeed-ulysses&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/sfOI4/dJMb9fZtD0r/8GSB2zb1ZzxllpCBRsWUTk/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/bp6NYj/dJMb9dHmnCf/7KMYetnWkaDEBRmfFjMJXk/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/YXfRZ/dJMb9frDMxf/JUKxK3hzijIMtvYZF0vgp0/img.png?width=4409&amp;amp;height=2484&amp;amp;face=0_0_4409_2484&quot;&gt;&lt;a href=&quot;https://github.com/deepspeedai/DeepSpeed/tree/master/blogs/deepspeed-ulysses&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/deepspeedai/DeepSpeed/tree/master/blogs/deepspeed-ulysses&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/sfOI4/dJMb9fZtD0r/8GSB2zb1ZzxllpCBRsWUTk/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/bp6NYj/dJMb9dHmnCf/7KMYetnWkaDEBRmfFjMJXk/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/YXfRZ/dJMb9frDMxf/JUKxK3hzijIMtvYZF0vgp0/img.png?width=4409&amp;amp;height=2484&amp;amp;face=0_0_4409_2484');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;DeepSpeed/blogs/deepspeed-ulysses at master &amp;middot; deepspeedai/DeepSpeed&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;DeepSpeed is a deep learning optimization library that makes distributed training and inference easy, efficient, and effective. - deepspeedai/DeepSpeed&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 당시 (2023년) 분산학습 기법은 크게 3 가지 (DP / TP / PP)로 나뉘었다. 그런데 얘네들은 long sequence Transformer model에 특화된 기법들이 아니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;Q. long sequence를 다루는 transformer 모델이 왜 중요하냐?&amp;nbsp;&lt;br /&gt;A. &quot;긴 문서에 대해 통합적으로 한번에 context를 이해하는 능력&quot;이 어디에 중요할까?&lt;br /&gt;- 긴 문서 (e.g., 책 한 권) 기반 요약 / reasoning / RAG 이런데에 잘 쓰임.&lt;br /&gt;- video generation task에서도 spatial / temporal domain에서 하나의 video를 하나의 긴 context라고 볼 수 있음. -&amp;gt; 하나의 video를 통합적으로 이해하는 능력.&amp;nbsp;&lt;br /&gt;- multimodal 상황에서도, 일단 이미지가 들어가면 기본적으로 먹고 들어가는 token 수가 많아짐. 이미지를 보고 reasoning하려면 모델 자체가 long context를 다룰 줄 알아야 함.&amp;nbsp;&amp;nbsp;&lt;br /&gt;- structure biology, large molecular simulation, weather forecasting 같은 과학 AI 분야에도 활용성이 높음.&amp;nbsp;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-) Long sequence transformer model에 기존 분산학습 기법들을 적용했을 때의 한계점:&amp;nbsp;&lt;b&gt;sequence dimension으로 scaling이 안됨.&lt;/b&gt; 다시 말해, 'sequence 길이 늘어나면 그냥 지금 분산학습 구조에 GPU 하나 더 추가하면 되잖아~' 같은 발상이 (안되는건 아니겠지만 구현하기가) 어려움.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;Previous Works: Sequence Parallelism&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;=&amp;gt; 그래서 sequence (tokens)-dimension으로 자르는 &lt;b&gt;Sequence Parallelism (SP)&lt;/b&gt;이란 게 나왔다.&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;Related Work 1)&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a style=&quot;color: #0070d1;&quot; href=&quot;https://aclanthology.org/2023.acl-long.134.pdf&quot;&gt;Sequence Parallelism: Long Sequence Training from System Perspective&lt;/a&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;layer의 hidden_dim 차원으로 모델을 쪼개는 TP와 달리, Input을 token dim으로 분리한다. 그래서 엄밀히 말하면 모델은 쪼개지지 않고 각 device에 replica로 올라간다. 오히려 DP랑 비슷한 느낌. Transformer를 위한 DP 느낌.&lt;/li&gt;
&lt;li&gt;자세한 내용은 이 글 참고 -&amp;gt; &lt;a style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot; href=&quot;https://orangingq.tistory.com/entry/Sequence-Parallelism-Long-Sequence-Training-from-System-Perspective&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2026.03.15 - [분산 ML] - Sequence Parallelism: Long Sequence Training from System Perspective&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2084&quot; data-origin-height=&quot;849&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xlN9M/dJMcabpTI8c/rQf3YpkpFO9zuzk0u4HvzK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xlN9M/dJMcabpTI8c/rQf3YpkpFO9zuzk0u4HvzK/img.png&quot; data-alt=&quot;TP vs SP&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xlN9M/dJMcabpTI8c/rQf3YpkpFO9zuzk0u4HvzK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxlN9M%2FdJMcabpTI8c%2FrQf3YpkpFO9zuzk0u4HvzK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;651&quot; height=&quot;265&quot; data-origin-width=&quot;2084&quot; data-origin-height=&quot;849&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;TP vs SP&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;Related Work 2) &lt;a href=&quot;https://proceedings.mlsys.org/paper_files/paper/2023/file/80083951326cf5b35e5100260d64ed81-Paper-mlsys2023.pdf&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Reducing Activation Recomputation in Large Transformer Models&lt;/a&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;기본 Megatron TP 구조에서, TP가 적용 안되는 Dropout, LayerNorm 같은 부분에 SP 적용. 따라서 중간 activation 값들도 device에 나눠 저장하게 되니까 전체 memory 요구량이 줄어듦. -&amp;gt; 원래는 이 activation 저장 용량이 커서 activation recomputation 같은 기법을 적용했는데, 이제 굳이 필요가 없어진,,&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1644&quot; data-origin-height=&quot;464&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kXIPi/dJMcabjbapi/dYCpqtsM9zfWKS6LpaXkhk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kXIPi/dJMcabjbapi/dYCpqtsM9zfWKS6LpaXkhk/img.png&quot; data-alt=&quot;TP &amp;amp;amp; SP 짬뽕&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kXIPi/dJMcabjbapi/dYCpqtsM9zfWKS6LpaXkhk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkXIPi%2FdJMcabjbapi%2FdYCpqtsM9zfWKS6LpaXkhk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;708&quot; height=&quot;200&quot; data-origin-width=&quot;1644&quot; data-origin-height=&quot;464&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;TP &amp;amp; SP 짬뽕&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-) 근데 기존 SP는 memory, communication 차원에서 여전히 비효율적이다.&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;Communication Volume이 여전히 크다. Memory efficiency도 여전히 크다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;ColAI-SP (Related Work 1)의 경우 기존 self-attention 대신 특별한 ring self-attention을 사용해서 불편하다 (?).&lt;/li&gt;
&lt;li&gt;기존 분산학습 코드가 좀 드러움 (=error prone, intrusive) -&amp;gt; 사용성이 떨어짐. (이거 실제로 돌려본 사람 입장에서 완전 인정ㅎ,, 특히 Megatron. 사용성 측면에서는 torchtitan이 탑임.)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;=&amp;gt; 이 논문:&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2704&quot; data-origin-height=&quot;594&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cdmcDZ/dJMcabQY29w/jkREY7CPkm4zYIVdHjsbE0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cdmcDZ/dJMcabQY29w/jkREY7CPkm4zYIVdHjsbE0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cdmcDZ/dJMcabQY29w/jkREY7CPkm4zYIVdHjsbE0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcdmcDZ%2FdJMcabQY29w%2FjkREY7CPkm4zYIVdHjsbE0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;651&quot; height=&quot;143&quot; data-origin-width=&quot;2704&quot; data-origin-height=&quot;594&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;기존 두 SP 방식에 비해 communication volume ($M$)을 GPU 수 ($P$)에 비례하게 줄였다.&lt;/li&gt;
&lt;li&gt;FSDP (DeepSpeed ZeRO)를 짬뽕해놔서 memory efficiency도 올렸다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Method&lt;/h2&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2194&quot; data-origin-height=&quot;1177&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cIOmEa/dJMcaa5zvsE/KD2SkZlA89zCgocE1tJmhK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cIOmEa/dJMcaa5zvsE/KD2SkZlA89zCgocE1tJmhK/img.png&quot; data-alt=&quot;기본 Transformer 연산 구조&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cIOmEa/dJMcaa5zvsE/KD2SkZlA89zCgocE1tJmhK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcIOmEa%2FdJMcaa5zvsE%2FKD2SkZlA89zCgocE1tJmhK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;619&quot; height=&quot;332&quot; data-origin-width=&quot;2194&quot; data-origin-height=&quot;1177&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;기본 Transformer 연산 구조&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본 Transformer (Multi-head attention) 병렬연산 구조:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;QKV 연산까지는 각 GPU에서 하든, 한 GPU에서 하든 해서 암튼 각자 연산함.&lt;/li&gt;
&lt;li&gt;그리고 각 GPU가 각각 서로 다른 head를 담당해서 attention 연산. (head-wise 병렬 처리)&lt;/li&gt;
&lt;li&gt;그 다음에 all-gather를 하든 gather를 하든 해서 head 별 P 값($P_h=S_h\cdot V_h$)을 한 GPU로 모은 다음에 마지막 $W_o$ 곱해서 output $O$ 만듦.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기에 Sequence Parallelism를 적용해보면, 처음에 input $x$를 $(N, d) \rightarrow (N/P, d)$로 분할하는 건 모든 SP 방식들에서 동일.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 그 뒤에 어떤 임베딩을 어떤 방식으로 통신할거냐에서 조금씩 다름.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://orangingq.tistory.com/entry/Sequence-Parallelism-Long-Sequence-Training-from-System-Perspective&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;기존 SP 구조&lt;/a&gt;에서는 K랑 V embedding을 ring-style P2P로 모든 GPU가 값을 공유했다 :&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;Attention 연산 전에, K embedding을 ring-style P2P로 GPU들 간 값 공유.&lt;br /&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;Communication Volume: $Nd/P \times (P-1)=O(Nd) $ (각 GPU가 총 P-1개 GPU로부터 Nd/P 크기의 데이터를 받음.)&lt;/li&gt;
&lt;li&gt;Communication Time: P2P 통신시간 x (P-1) 회&lt;/li&gt;
&lt;li&gt;Memory Complexity: $O(Nd/P)$&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;attention score에 V 곱하기 위해, V embedding을 ring-style P2P로 GPU 간 공유.
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;Communication Volume / Time / Memory Complexity는 K embedding 때랑 동일.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2734&quot; data-origin-height=&quot;1445&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b9Ar4A/dJMcabi78Xw/wzSJ952c8JzqRuM4g99SB1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b9Ar4A/dJMcabi78Xw/wzSJ952c8JzqRuM4g99SB1/img.png&quot; data-alt=&quot;DeepSpeed-Ulysses 연산 구조&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b9Ar4A/dJMcabi78Xw/wzSJ952c8JzqRuM4g99SB1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb9Ar4A%2FdJMcabi78Xw%2FwzSJ952c8JzqRuM4g99SB1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;614&quot; height=&quot;325&quot; data-origin-width=&quot;2734&quot; data-origin-height=&quot;1445&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;DeepSpeed-Ulysses 연산 구조&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 이 DeepSpeed-Ulysses는 &lt;b&gt;ring-style P2P 대신 all2all 통신&lt;/b&gt;을 한다고 한다. 그리고 특이한 게, 이 논문에서는 all2all 통신을 할 때, 각 local에 원래 $(N/P, d)$ 차원의 tensor가 있었다면 (sequence-wise splitted), 이걸 all2all 통신을 통해 head-wise split으로 바꿔서 $(N, d/P)$ 차원의 tensor를 가지게 한다. 그러므로 통신 전후로 각 GPU가 가지는 memory 요구량은 동일한데, 통신량은 기존 ring-style P2P에 비해 줄어든다.&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 212px;&quot; border=&quot;1&quot; data-end=&quot;1061&quot; data-start=&quot;142&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;height: 17px; width: 11.0465%;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;height: 17px; width: 27.0931%;&quot;&gt;&lt;b&gt;All-Gather&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 32.2092%; height: 17px;&quot;&gt;&lt;b&gt;Ring-style P2P&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 17px; width: 29.6512%;&quot;&gt;&lt;b&gt;이 논문의 All-to-All 통신&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;height: 19px; width: 11.0465%;&quot; data-col-size=&quot;sm&quot; data-end=&quot;211&quot; data-start=&quot;201&quot;&gt;기본 아이디어&lt;/td&gt;
&lt;td style=&quot;height: 19px; width: 27.0931%;&quot; data-end=&quot;252&quot; data-start=&quot;211&quot; data-col-size=&quot;md&quot;&gt;각 GPU shard를&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;모두 모아서 full tensor 생성&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 32.2092%; height: 19px;&quot;&gt;tensor block을&amp;nbsp;&lt;b&gt;GPU 사이에서 순환 전달하면서 계산&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 19px; width: 29.6512%;&quot; data-end=&quot;294&quot; data-start=&quot;252&quot; data-col-size=&quot;md&quot;&gt;&lt;b&gt;쪼개는 차원을 다르게.&amp;nbsp;&lt;/b&gt;&lt;br /&gt;$(N/P, d) \rightarrow (N, d/P)$&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 108px;&quot;&gt;
&lt;td style=&quot;height: 108px; width: 11.0465%;&quot;&gt;통신 패턴&lt;/td&gt;
&lt;td style=&quot;height: 108px; width: 27.0931%;&quot;&gt;각 GPU i가 xi 들고 있을 때, &amp;nbsp;All-Gather 한 번으로 &amp;rarr;&lt;br /&gt;GPU0:&amp;nbsp;[x0&amp;nbsp;x1&amp;nbsp;x2&amp;nbsp;x3]&lt;br /&gt;GPU1:&amp;nbsp;[x0&amp;nbsp;x1&amp;nbsp;x2&amp;nbsp;x3]&lt;br /&gt;GPU2:&amp;nbsp;[x0&amp;nbsp;x1&amp;nbsp;x2&amp;nbsp;x3]&lt;br /&gt;GPU3: [x0 x1 x2 x3]&lt;br /&gt;모든&amp;nbsp;GPU가&amp;nbsp;full&amp;nbsp;tensor&amp;nbsp;보유&lt;/td&gt;
&lt;td style=&quot;width: 32.2092%; height: 108px;&quot;&gt;GPU0&amp;nbsp;&amp;rarr;&amp;nbsp;GPU1&amp;nbsp;&amp;rarr;&amp;nbsp;GPU2&amp;nbsp;&amp;rarr;&amp;nbsp;GPU3&amp;nbsp;&amp;rarr;&amp;nbsp;GPU0 &lt;br /&gt;총&amp;nbsp;N-1번의&amp;nbsp;P2P가&amp;nbsp;발생하고,&amp;nbsp;각&amp;nbsp;step&amp;nbsp;마다: &lt;br /&gt;1)&amp;nbsp;receive&amp;nbsp;xi &lt;br /&gt;2)&amp;nbsp;compute&amp;nbsp;(e.g.,&amp;nbsp;attention&amp;nbsp;A&amp;nbsp;연산) &lt;br /&gt;3)&amp;nbsp;send&amp;nbsp;xi&lt;/td&gt;
&lt;td style=&quot;height: 108px; width: 29.6512%;&quot;&gt;각&amp;nbsp;GPU&amp;nbsp;i가&amp;nbsp;full&amp;nbsp;tensor&amp;nbsp;$X$의&amp;nbsp;$X_{(i,:)}$를&amp;nbsp;들고&amp;nbsp;있었다면,&amp;nbsp;all-to-all&amp;nbsp;통신으로&amp;nbsp;$X_{(:,i)}$를&amp;nbsp;가지게&amp;nbsp;됨.&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 11.0465%; height: 17px;&quot;&gt;Output Memory&lt;/td&gt;
&lt;td style=&quot;width: 27.0931%; height: 17px;&quot;&gt;V&amp;nbsp; &amp;nbsp;(V: full tensor 크기)&lt;/td&gt;
&lt;td style=&quot;width: 32.2092%; height: 17px;&quot;&gt;&lt;span style=&quot;background-color: #f9f9f9; color: #333333; text-align: start;&quot;&gt;&lt;b&gt;V/P&lt;/b&gt;&amp;nbsp; &amp;nbsp;(P: GPU 수)&amp;nbsp;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 29.6512%; height: 17px;&quot;&gt;&lt;b&gt;V/P&amp;nbsp;&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 11.0465%; height: 17px;&quot;&gt;중간 peak memory&lt;/td&gt;
&lt;td style=&quot;width: 27.0931%; height: 17px;&quot;&gt;V (어쨌든 full tensor를 모아야 하기에)&lt;/td&gt;
&lt;td style=&quot;width: 32.2092%; height: 17px;&quot;&gt;&lt;b&gt;V/P&lt;/b&gt; (가장 streaming스러운. 메모리 절약형)&lt;/td&gt;
&lt;td style=&quot;width: 29.6512%; height: 17px;&quot;&gt;V/P와 V 사이. (차원을 바꾸려면 어쨌든 V/P보다는 많이 필요.)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 34px;&quot;&gt;
&lt;td style=&quot;width: 11.0465%; height: 34px;&quot;&gt;Comm. Volume&lt;/td&gt;
&lt;td style=&quot;width: 27.0931%; height: 34px;&quot;&gt;O(V) (각 GPU가 $V/P$ 크기 데이터를 보내고, $V\cdot (P-1)/P$ 만큼의 데이터를 받음.)&lt;/td&gt;
&lt;td style=&quot;width: 32.2092%; height: 34px;&quot;&gt;O(V)&amp;nbsp; (각 GPU가 $V/P \cdot (P-1)$ 만큼의 데이터를 보내고/받음.)&lt;/td&gt;
&lt;td style=&quot;width: 29.6512%; height: 34px;&quot;&gt;&lt;b&gt;O(V/P)&lt;/b&gt; (각 GPU가 $V/P \cdot (P-1)/P$ 만큼의 데이터를 보내고/받음.&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자세한 순서를 보면:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;Attention 연산 전에, Q, K, V embeddings를 &lt;b&gt;sequence-wise에서 head-wise로 all-to-all&lt;/b&gt; &lt;b&gt;재분배&lt;/b&gt;.
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;Communication Volume: &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;$3Nd/P=O(Nd/P) $ (각 GPU가 3Nd/P 크기의 데이터를 전송.)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;Communication Time: All2All 통신시간 x 1회 (아무래도 기준 시간은 All2All이 P2P보다 느리긴 하겠지)&lt;/li&gt;
&lt;li&gt;Memory Complexity:&lt;span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;$O(Nd/P)$ &lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;각 GPU에서 자기에게 해당되는 head에 대해 self-attention 연산.&lt;/li&gt;
&lt;li&gt;MLP block을 sequence parallel하게 처리하기 위해서 output $P_h=S_hV_h$를 다시 &lt;b&gt;head-wise -&amp;gt; sequence-wise로 all-to-all 재분배&lt;/b&gt;.&amp;nbsp;&lt;br /&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;Communication Volume:&amp;nbsp;&amp;nbsp;$Nd/P=O(Nd/P) $ (각 GPU가 Nd/P 크기의 데이터를 전송.)&lt;/li&gt;
&lt;li&gt;Communication Time: All2All 통신시간 x 1회&amp;nbsp;&lt;/li&gt;
&lt;li&gt;Memory Complexity:&lt;span&gt; &lt;/span&gt;$O(Nd/P)$&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;+ DS-Ulysses는 DeepSpeed ZeRO-3를 결합한다. model states나 gradient를 각 GPU에 쪼개 담는 ZeRO 방식(FSDP)을 적용해서, 전체 DP x SP groups에 걸쳐서 분할하고, 연산에 필요한 순간에만 all-gather를 통해 분할된 조각들을 가져온다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;A. ring-style P2P vs all2all (all-gather) 통신 차이:&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;한마디로, ring-style P2P가 all-gather에 비해 시간이 더 오래걸리고 대신 memory usage를 줄인 버전이라고 보면 될듯. 약간 &lt;b&gt;online streaming 버전의 all-gather&lt;/b&gt; 느낌.&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 237px;&quot; border=&quot;1&quot; data-ke-style=&quot;style12&quot; data-ke-align=&quot;alignLeft&quot; data-start=&quot;142&quot; data-end=&quot;1061&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;height: 17px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;height: 17px;&quot;&gt;&lt;b&gt;All-Gather&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 17px;&quot;&gt;&lt;b&gt;Ring-style P2P&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot; data-start=&quot;201&quot; data-end=&quot;294&quot;&gt;
&lt;td style=&quot;height: 19px;&quot; data-start=&quot;201&quot; data-end=&quot;211&quot; data-col-size=&quot;sm&quot;&gt;기본 아이디어&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot; data-col-size=&quot;md&quot; data-start=&quot;211&quot; data-end=&quot;252&quot;&gt;각 GPU shard를 &lt;b&gt;모두 모아서 full tensor 생성&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot; data-col-size=&quot;md&quot; data-start=&quot;252&quot; data-end=&quot;294&quot;&gt;tensor block을 &lt;b&gt;GPU 사이에서 순환 전달하면서 계산&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 108px;&quot;&gt;
&lt;td style=&quot;height: 108px;&quot;&gt;통신 패턴&lt;/td&gt;
&lt;td style=&quot;height: 108px;&quot;&gt;각 GPU i가 xi 들고 있을 때, &amp;nbsp;All-Gather 한 번으로 &amp;rarr;&lt;br /&gt;GPU0:&amp;nbsp;[x0&amp;nbsp;x1&amp;nbsp;x2&amp;nbsp;x3]&lt;br /&gt;GPU1:&amp;nbsp;[x0&amp;nbsp;x1&amp;nbsp;x2&amp;nbsp;x3]&lt;br /&gt;GPU2:&amp;nbsp;[x0&amp;nbsp;x1&amp;nbsp;x2&amp;nbsp;x3]&lt;br /&gt;GPU3: [x0 x1 x2 x3]&lt;br /&gt;모든&amp;nbsp;GPU가&amp;nbsp;full&amp;nbsp;tensor&amp;nbsp;보유&lt;/td&gt;
&lt;td style=&quot;height: 108px;&quot;&gt;GPU0 &amp;rarr; GPU1 &amp;rarr; GPU2 &amp;rarr; GPU3 &amp;rarr; GPU0&lt;br /&gt;총 N-1번의 P2P가 발생하고, 각 step 마다:&lt;br /&gt;1) receive &lt;span style=&quot;background-color: #f9f9f9; color: #333333; text-align: start;&quot;&gt;xi&lt;/span&gt; &lt;br /&gt;2) compute (e.g., attention A 연산)&lt;br /&gt;3) send &lt;span style=&quot;background-color: #f9f9f9; color: #333333; text-align: start;&quot;&gt;xi&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot; data-start=&quot;295&quot; data-end=&quot;366&quot;&gt;
&lt;td style=&quot;height: 19px;&quot; data-start=&quot;295&quot; data-end=&quot;303&quot; data-col-size=&quot;sm&quot;&gt;통신 방식&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot; data-col-size=&quot;md&quot; data-start=&quot;303&quot; data-end=&quot;334&quot;&gt;&lt;b&gt;Collective communication&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot; data-col-size=&quot;md&quot; data-start=&quot;334&quot; data-end=&quot;366&quot;&gt;&lt;b&gt;Point-to-point streaming&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot; data-start=&quot;367&quot; data-end=&quot;409&quot;&gt;
&lt;td style=&quot;height: 17px;&quot; data-start=&quot;367&quot; data-end=&quot;382&quot; data-col-size=&quot;sm&quot;&gt;GPU topology&lt;/td&gt;
&lt;td style=&quot;height: 17px;&quot; data-col-size=&quot;md&quot; data-start=&quot;382&quot; data-end=&quot;401&quot;&gt;broadcast / tree&lt;/td&gt;
&lt;td style=&quot;height: 17px;&quot; data-col-size=&quot;md&quot; data-start=&quot;401&quot; data-end=&quot;409&quot;&gt;ring&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot; data-start=&quot;410&quot; data-end=&quot;453&quot;&gt;
&lt;td style=&quot;height: 19px;&quot; data-start=&quot;410&quot; data-end=&quot;418&quot; data-col-size=&quot;sm&quot;&gt;통신 단계&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot; data-col-size=&quot;md&quot; data-start=&quot;418&quot; data-end=&quot;431&quot;&gt;&lt;b&gt;1 step&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot; data-col-size=&quot;md&quot; data-start=&quot;431&quot; data-end=&quot;453&quot;&gt;&lt;b&gt;N-1 steps&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot; data-start=&quot;554&quot; data-end=&quot;623&quot;&gt;
&lt;td style=&quot;height: 19px;&quot; data-start=&quot;554&quot; data-end=&quot;568&quot; data-col-size=&quot;sm&quot;&gt;통신 후 tensor&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot; data-col-size=&quot;md&quot; data-start=&quot;568&quot; data-end=&quot;604&quot;&gt;full tensor 크기&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot; data-col-size=&quot;md&quot; data-start=&quot;604&quot; data-end=&quot;623&quot;&gt;여전히 local shard&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot; data-start=&quot;859&quot; data-end=&quot;894&quot;&gt;
&lt;td style=&quot;height: 19px;&quot; data-start=&quot;859&quot; data-end=&quot;869&quot; data-col-size=&quot;sm&quot;&gt;latency&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot; data-col-size=&quot;md&quot; data-start=&quot;869&quot; data-end=&quot;874&quot;&gt;낮음&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot; data-col-size=&quot;md&quot; data-start=&quot;874&quot; data-end=&quot;894&quot;&gt;높음 (N-1 iteration)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;비교하면,&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 55px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 21px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 21px;&quot;&gt;&lt;b&gt;ColAI-SP (첫 SP 논문)&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 21px;&quot;&gt;&lt;b&gt;Megatron-SP (TP+SP)&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 21px;&quot;&gt;&lt;b&gt;DS-Ulysses (FSDP+SP)&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;통신 방법&lt;/td&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;ring-style P2P&lt;/td&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;all-gather, reduce-scatter&lt;/td&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;gather, scatter&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;Comm. Volume&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;$2Nd$&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;$4Nd$&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;$4Nd/P$&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Strength&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;+) 기존 방법들보다 communication volume이 더 줄었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;+) ring-style P2P 때처럼 특이한 연산구조를 하지 않아도 (?) 된다.&amp;nbsp;&lt;/p&gt;</description>
      <category>분산 ML</category>
      <author>오렌징큐</author>
      <guid isPermaLink="true">https://orangingq.tistory.com/221</guid>
      <comments>https://orangingq.tistory.com/entry/DeepSpeed-Ulysses#entry221comment</comments>
      <pubDate>Fri, 13 Mar 2026 10:51:29 +0900</pubDate>
    </item>
    <item>
      <title>NVIDIA GeForce RTX3090 Architecture</title>
      <link>https://orangingq.tistory.com/entry/NVIDIA-GeForce-RTX3090-Architecture</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;출처: &lt;a href=&quot;https://www.nvidia.com/content/PDF/nvidia-ampere-ga-102-gpu-architecture-whitepaper-v2.pdf&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.nvidia.com/content/PDF/nvidia-ampere-ga-102-gpu-architecture-whitepaper-v2.pdf&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;RTX 3090에는 Ampere GA102 architecture가 사용되었다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2500&quot; data-origin-height=&quot;1574&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xDdR5/btsPt9FQs10/a2qUJ8C9Le4KaMDlb98FD0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xDdR5/btsPt9FQs10/a2qUJ8C9Le4KaMDlb98FD0/img.png&quot; data-alt=&quot;GA102 Full GPU with 84 SMs&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xDdR5/btsPt9FQs10/a2qUJ8C9Le4KaMDlb98FD0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxDdR5%2FbtsPt9FQs10%2Fa2qUJ8C9Le4KaMDlb98FD0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2500&quot; height=&quot;1574&quot; data-origin-width=&quot;2500&quot; data-origin-height=&quot;1574&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;GA102 Full GPU with 84 SMs&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;749&quot; data-origin-height=&quot;782&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tDhGF/btsPuC2goZJ/Kam4dZWhKCg5i55ycsf3Rk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tDhGF/btsPuC2goZJ/Kam4dZWhKCg5i55ycsf3Rk/img.png&quot; data-alt=&quot;GPC 구조&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tDhGF/btsPuC2goZJ/Kam4dZWhKCg5i55ycsf3Rk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtDhGF%2FbtsPuC2goZJ%2FKam4dZWhKCg5i55ycsf3Rk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;406&quot; height=&quot;424&quot; data-origin-width=&quot;749&quot; data-origin-height=&quot;782&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;GPC 구조&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;High-Level Architecture&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전 NVIDIA GPU들과 비슷하게, GA102는 다음과 같이 구성된다:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;b&gt;7 Graphics Processing Clusters (GPCs)&lt;/b&gt; : 주요 graphics processing units가 다 들어 있는 hardware block.&amp;nbsp;&amp;nbsp;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;각 GPC 안에는 Raster Engine, 2 ROP partitions (각 파티션에 8 ROP units 있음), 6 TPC가 있음.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;Raster Engine&lt;/li&gt;
&lt;li&gt;Raster Operators (ROPS) : GPC 구조 그림에서 밑줄 파란색 직사각형들.&lt;br /&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;예전 GPU 구조들에서는 ROPs가 memory controller에 달려 있었는데, 이번 구조부터는 GPC 내부로 들어왔다. =&amp;gt; raster operation performance $\uparrow$&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Texture Processing Clusters (TPCs)&lt;/b&gt; :&amp;nbsp;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;각 TPC 안에는 2개의 SM, 1 PolyMorph Engine이 있음.&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;&lt;b&gt;Streaming Multiprocessors (SMs)&lt;/b&gt; :&lt;/span&gt;&lt;br /&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;각 SM은 128개의 CUDA Cores, 4개의 3rd-gen Tensor Cores, 256KB Register file, 4 Texture Units, 1 Ray Tracing Core, 128KB L1/Shared Memory를 가진다. &lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;b&gt;12 Memory controllers :&lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;전체 GA102에는 12개의 32-bit memory controller와 각 memory controller에 달린 512 KB짜리 L2 cache가 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;$\therefore$ Full GA102 GPU는 7 GPCs, 42 TPCs&lt;/b&gt; (=7 GPCs x 6 TPCs/GPC), &lt;b&gt;84 SMs&lt;/b&gt; (=7 GPCs x 6 TPCs/GPC x 2 SMs/TPC)&lt;b&gt;를 가진다.&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;GA10x SM Architecture&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 그림에서 보이듯이, GA10x SM은 4개의 큰 processing block으로 이루어진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 processing block에는:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;b&gt;64KB register file :&lt;/b&gt; GPU가 SIMD (Single Instruction, Multiple Data)가 아닌 SIMT (-, Multiple Threads)인 이유는, 하나의 thread에서 하나의 명령어로 여러 개의 데이터를 처리하는 SIMD 구조와 달리, GPU에서는 한 warp로 묶인 각 thread가 서로 다른 자기만의 execution context를 가지고 있기 때문이다. 이 각 thread 별 context는 바로 register로 관리된다. 한 SM에 배정된 thread block 내 모든 thread들이 각자의 register 영역을 가진다. 예를 들어 thread block 안에 512개 thread가 있으면 register file이 512등분되고 thread들이 이를 하나씩 사용한다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;L0 instruction cache&lt;/li&gt;
&lt;li&gt;1 warp scheduler : 다음에 처리할 warp를 결정한다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;1 dispatch unit : 다음에 처리될 warp에 명령을 내린다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;1 3rd Gen Tensor Core : FP16 연산 담당.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;2 datapaths. 각 datapath는 연두색 한 길쭉 직사각형을 의미.&amp;nbsp;&amp;nbsp;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;b&gt;16 FP32 CUDA Cores&lt;/b&gt; = clock 당 16개의 FP32 operation을 처리할 수 있음.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;16 FP32 CUDA Cores &amp;amp; 16 INT32 Cores&lt;/b&gt; : 1 clock에 FP32 / INT32 연산 16개를 동시 처리 가능.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;즉 한 clock 당 32개의 FP32 연산을 하거나, FP32 연산 16 + INT32 연산 16개를 처리할 수 있는 셈.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;이전 GPU 구조인 turing 구조에서는 두 datapath 중 하나만 FP32 연산을 지원했는데 (나머지 하나는 INT32 only), 요즘에는 단순 integer 덧셈 연산에 비해 복잡한 floating point 연산이 부쩍 많아져서, 이번에는 두 datapath 모두 FP32 연산을 지원하게 되었다. 그래서 FP32 연산의 peak processing rate이 두 배가 되었다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 이 4개의 processing blocks는 하나의 128 KB L1 data cache / shared memory subsystem을 공유한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 memory 공간을 cache와 shared memory로 쪼개서 사용할 수 있는 건데,&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 128 KB 전체를 L1 cache로만 쓸 수도 있고, 공유 메모리를 많이 써야 한다면 L1 cache 영역을 28 KB로 줄이고 shared memory를 100 KB로 설정할 수도 있다. 설정하기 나름임.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1562&quot; data-origin-height=&quot;2500&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b9WkzA/btsPss1AU48/960OWjR0J3cSL2ZR3EXkuK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b9WkzA/btsPss1AU48/960OWjR0J3cSL2ZR3EXkuK/img.png&quot; data-alt=&quot;GA10x Streaming Multiprocessor (SM)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b9WkzA/btsPss1AU48/960OWjR0J3cSL2ZR3EXkuK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb9WkzA%2FbtsPss1AU48%2F960OWjR0J3cSL2ZR3EXkuK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;563&quot; height=&quot;901&quot; data-origin-width=&quot;1562&quot; data-origin-height=&quot;2500&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;GA10x Streaming Multiprocessor (SM)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Fine-Grained&amp;nbsp;Structured&amp;nbsp;Sparsity&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AI-based graphics inference 연산할 때, 속도를 더 높이고자 재밌는 방식을 지원한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;딥러닝할 때, 사실 weights 중에서 중요한 정보를 담고 있는 weights는 일부고 나머지는 거의 0에 가까운 noise를 가진다. 이런 sparsity를 활용해서 아래 그림처럼 dense trained weights를 절반으로 압축해버린다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 연산 속도가 두배에 가깝게 빨라지겠지!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1132&quot; data-origin-height=&quot;608&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zES8y/btsPuB3vXhk/f90l2Pe8RkQBDUsxDtgU60/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zES8y/btsPuB3vXhk/f90l2Pe8RkQBDUsxDtgU60/img.png&quot; data-alt=&quot;Fine-Grained Structured Sparsity&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zES8y/btsPuB3vXhk/f90l2Pe8RkQBDUsxDtgU60/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzES8y%2FbtsPuB3vXhk%2Ff90l2Pe8RkQBDUsxDtgU60%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1132&quot; height=&quot;608&quot; data-origin-width=&quot;1132&quot; data-origin-height=&quot;608&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Fine-Grained Structured Sparsity&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;RTX IO&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;RTX IO는 게임 성능 향상을 위해 개발된 GPU 가속 storage 기술이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요즘 게임이 하도 삐까뻔쩍하니까 큰 게임은 200GB가 넘기도 한다. 어쨌든 그래서 system memory에 기본 적재할 수는 없고, hard drive에 넣던가 SSD에 넣던가 해야된다. 그래서 hard disk나 SSD에 game file을 넣어놓으면 그걸 CPU로 가지고 가서 decompress를 해서 게임을 로드했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;게임 로딩 시간을 빠르게 하려면 SSD에 넣어놓는게 훨씬 빠르겠지. 원래는 hard drive에서 main memory로 load해오는 storage I/O가 병목이었는데, 요즘은 SSD 성능도 하도 좋아지고, 개발자들이 lossless compression을 써서 설치 용량도 줄이고 하니까, 오히려 이제 storage I/O보다 CPU에서 decompression 하는 게 병목이 되어버렸다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;옛날에 100MB/s 속도의 hard drive 시절에는 storage IO가 느리니까 압축 해제는 CPU core 몇 개만 써도 충분했다. 근데 이제는 PCIe Gen4 SSD는 7GB/s 속도로 가지고 와서, 그 속도에 맞춰서 decompress하려면 CPU core가 20개 이상이 필요해졌다.&amp;nbsp; &amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1552&quot; data-origin-height=&quot;769&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bHr16m/btsPs1biWE6/9vKLDgNbyvGrs06B3dwTCk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bHr16m/btsPs1biWE6/9vKLDgNbyvGrs06B3dwTCk/img.png&quot; data-alt=&quot;Games Bottlenecked by Traditional I/O&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bHr16m/btsPs1biWE6/9vKLDgNbyvGrs06B3dwTCk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbHr16m%2FbtsPs1biWE6%2F9vKLDgNbyvGrs06B3dwTCk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;763&quot; height=&quot;378&quot; data-origin-width=&quot;1552&quot; data-origin-height=&quot;769&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Games Bottlenecked by Traditional I/O&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 NVIDIA에서 RTX IO는 Microsoft의 DirectStorage API와 최신 NVMe SSD가 장착된 gaming PC에서 가능한, &lt;b&gt;GPU-based lossless decompression&lt;/b&gt; 기술을 지원한다. 다시 말해, CPU에서 먼저 decompress할 필요 없이 DirectStorage API를 통해 compress된 상태로 GPU로 읽어온 다음에 GPU에서 decompression을 진행한다. 그러니까 이제 CPU의 연산 부담을 확 줄여준 셈.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1274&quot; data-origin-height=&quot;627&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/YAmqa/btsPsrPbVTk/AxnTglbVEviIKIRzx9IQj0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/YAmqa/btsPsrPbVTk/AxnTglbVEviIKIRzx9IQj0/img.png&quot; data-alt=&quot;RTX IO Delivers 100x throughput, 20x lower CPU utilization&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/YAmqa/btsPsrPbVTk/AxnTglbVEviIKIRzx9IQj0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYAmqa%2FbtsPsrPbVTk%2FAxnTglbVEviIKIRzx9IQj0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;799&quot; height=&quot;393&quot; data-origin-width=&quot;1274&quot; data-origin-height=&quot;627&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;RTX IO Delivers 100x throughput, 20x lower CPU utilization&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;</description>
      <author>오렌징큐</author>
      <guid isPermaLink="true">https://orangingq.tistory.com/218</guid>
      <comments>https://orangingq.tistory.com/entry/NVIDIA-GeForce-RTX3090-Architecture#entry218comment</comments>
      <pubDate>Tue, 22 Jul 2025 15:48:26 +0900</pubDate>
    </item>
    <item>
      <title>CUDA 함수들</title>
      <link>https://orangingq.tistory.com/entry/CUDA-%ED%95%A8%EC%88%98%EB%93%A4</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;Host Code &amp;lt;-&amp;gt; Device Code&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;419&quot; data-origin-height=&quot;213&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Ej8u8/btsPdegPUqS/UhoQZokIOun2aEn8k6cWU0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Ej8u8/btsPdegPUqS/UhoQZokIOun2aEn8k6cWU0/img.png&quot; data-alt=&quot;https://ianfinlayson.net/class/cpsc425/notes/21-cuda&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Ej8u8/btsPdegPUqS/UhoQZokIOun2aEn8k6cWU0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEj8u8%2FbtsPdegPUqS%2FUhoQZokIOun2aEn8k6cWU0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;289&quot; height=&quot;147&quot; data-origin-width=&quot;419&quot; data-origin-height=&quot;213&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://ianfinlayson.net/class/cpsc425/notes/21-cuda&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CUDA 프로그램은 host code와 device code로 구성됨.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;b&gt;host code:&lt;/b&gt; CPU용. 컴퓨터 시스템의 기본 연산 장치는 CPU니까 기본적으로 필요함. 이 host code에서 kernel을 호출해야만 GPU 등 다른 연산 장치에 접근, 사용할 수 있음.&amp;nbsp;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;b&gt;host&lt;/b&gt;: CPU&lt;/li&gt;
&lt;li&gt;&lt;b&gt;host memory&lt;/b&gt;: system의 기본 DRAM 메모리 영역. 모든 데이터는 기본적으로 host memory에 저장되어 있음. GPU를 이용해 data를 처리하려면 host mem에 있는 data를 device mem으로 복사해야 함.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;device code:&lt;/b&gt; GPU 등 다른 연산 장치를 사용하기 위해서 쓰는 코드.&amp;nbsp;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;b&gt;device&lt;/b&gt;: GPU&lt;/li&gt;
&lt;li&gt;&lt;b&gt;device memory&lt;/b&gt;:&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;CUDA program 흐름&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;363&quot; data-origin-height=&quot;352&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sG5vS/btsPdar14na/okKmWsjktf0uFdsp15rofK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sG5vS/btsPdar14na/okKmWsjktf0uFdsp15rofK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sG5vS/btsPdar14na/okKmWsjktf0uFdsp15rofK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsG5vS%2FbtsPdar14na%2FokKmWsjktf0uFdsp15rofK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;301&quot; height=&quot;292&quot; data-origin-width=&quot;363&quot; data-origin-height=&quot;352&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;host -&amp;gt; device data 복사 through PCI bus.&lt;/li&gt;
&lt;li&gt;host code에서 kernel call, GPU에게 연산 주문.&lt;/li&gt;
&lt;li&gt;GPU의 연산 using device memory.&lt;/li&gt;
&lt;li&gt;&amp;nbsp;device memory의 저장된 연산 결과를 다시 host memory (main memory)로 복사.&amp;nbsp;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;`cudaMalloc(void ** ptr, size_t size)`
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;b&gt;device memory에&lt;/b&gt;, `ptr` 포인터 변수가 가리키는 시작 주소부터 `size` 만큼의 Byte &lt;b&gt;공간을 할당&lt;/b&gt;하기. 성공하면 0 (`cudaSuccess`) 반환, 실패하면 에러 코드 (ex. `cudaErrorMemoryAllocation`=2) 반환.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;`cudaFree(void *ptr)`
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;`ptr`이 가리키는 &lt;b&gt;device 메모리 공간을 해제&lt;/b&gt;. 성공하면 0, 실패하면 에러 코드 반환.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;`cudaMemset(void *ptr, int value, size_t size)`
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;`ptr`이 가리키는 시작 주소부터 `size` Byte만큼 &lt;b&gt;`value` 값으로 device memory 초기화&lt;/b&gt;하기.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;`cudaMemcpy(void *dst, void* src, size_t size, enum cudaMemcpyKind kind)`&lt;br /&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; text-align: left;&quot;&gt;`src` 주소로부터 `size` Byte만큼의 &lt;b&gt;data를&lt;/b&gt; `dst` 주소로 &lt;b&gt;복사&lt;/b&gt;.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; text-align: left;&quot;&gt;`cudaMemcpyKind`&lt;span&gt; 종류들:&lt;/span&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;`cudaMemcpyHostToHost`: host memory `src` 주소로부터 `size`만큼의 data를 host memory `dst` 주소로 복사&lt;/li&gt;
&lt;li&gt;`cudaMemcpyHostToDevice`: host memory `src` 주소로부터 `size`만큼의 data를 device memory `dst` 주소로 복사&lt;/li&gt;
&lt;li&gt;`cudaMemcpyDeviceToHost`: device memory `src` 주소로부터 `size`만큼의 data를 host memory `dst` 주소로 복사&lt;/li&gt;
&lt;li&gt;`cudaMemcpyDeviceToDevice`: device memory `src` 주소로부터 `size`만큼의 data를 &lt;span style=&quot;color: #333333; text-align: left;&quot;&gt;device&lt;span&gt; &lt;/span&gt;&lt;/span&gt;memory `dst` 주소로 복사&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;CUDA Thread 계층&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;412&quot; data-origin-height=&quot;235&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bpkwk2/btsPcy1lRHc/GNjQe8vHy7aozXU0d0kOe1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bpkwk2/btsPcy1lRHc/GNjQe8vHy7aozXU0d0kOe1/img.jpg&quot; data-alt=&quot;https://jdriven.com/blog/2024/02/gpu_part2&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bpkwk2/btsPcy1lRHc/GNjQe8vHy7aozXU0d0kOe1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbpkwk2%2FbtsPcy1lRHc%2FGNjQe8vHy7aozXU0d0kOe1%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;412&quot; height=&quot;235&quot; data-origin-width=&quot;412&quot; data-origin-height=&quot;235&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://jdriven.com/blog/2024/02/gpu_part2&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;b&gt;Thread&lt;/b&gt;: CUDA thread hierarchy에서 가장 작은 unit. CUDA core를 사용하는 기본 단위.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Warp&lt;/b&gt;: 연속된&amp;nbsp; &lt;span style=&quot;color: #333333; text-align: left;&quot;&gt;32개의 thread를 하나로 묶은 것. &lt;span style=&quot;color: #333333; text-align: left;&quot;&gt;CUDA의 기본 수행 단위.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt; &lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;한 warp에 속한 32개의 thread들은 하나의 제어 장치에 의해 제어됨.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;GPU의 SIMT 구조의 &quot;Multiple Thread&quot;가 한 warp를 의미함. 하나의 instruction에 따라 32개의 thread가 동시에 움직이는.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Block (thread block)&lt;/b&gt;:&amp;nbsp;warp들의 집합.
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;하나의 block에 포함된 각 thread는 자신만의 고유한 thread ID를 가진다. 약간 좌표값 마냥.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Grid&lt;/b&gt;: 여러 개의 block을 포함하는 block들의 그룹. GPU를 사용하는 단위.&amp;nbsp;&amp;nbsp;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;kernel이 호출되면 grid가 생성된다. kernel call : grid = 1:1 대응.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;하나의 grid에 포함된 blocks는 서로 다른 고유한 block ID를 가진다. 따라서 grid 내 특정 block의 특정 thread를 지칭하려면, block ID와 thread ID를 표기하면 됨. 해당 block ID의 block 내에서 해당 thread ID를 가지는 thread를 찾을 수 있다. block ID가 단지 내 건물 번호면 thread ID는 건물 내 방 번호 (101호 같이).&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;커널 호출할 때:&lt;/p&gt;
&lt;pre id=&quot;code_1752135948875&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Dim3 dimGrid(4,1,1); // (4,1,1) 차원의 그리드 생성하라는 뜻. 한 그리드 내에 4개의 block이 생성.
dim3 dimBlock(8,1,1); // (8,1,1) 차원의 block 생성하라는 뜻. 한 block 내에 8개의 thread 생성.
kernel&amp;lt;&amp;lt;&amp;lt;dimGrid, dimBlock&amp;gt;&amp;gt;&amp;gt;(); // kernel 호출.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;CUDA Thread 계층 &amp;lt;-&amp;gt; GPU Hardware&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;521&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/deD0Ns/btsPb1wg0kO/J63NPTJ8j2HFpwkN4UwgiK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/deD0Ns/btsPb1wg0kO/J63NPTJ8j2HFpwkN4UwgiK/img.png&quot; data-alt=&quot;[개념 정리] GPU 메모리 구조 및 용어 - https://xoft.tistory.com/75&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/deD0Ns/btsPb1wg0kO/J63NPTJ8j2HFpwkN4UwgiK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdeD0Ns%2FbtsPb1wg0kO%2FJ63NPTJ8j2HFpwkN4UwgiK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;521&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;521&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;[개념 정리] GPU 메모리 구조 및 용어 - https://xoft.tistory.com/75&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;b&gt;Grid -&amp;gt; GPU&lt;/b&gt;: CUDA kernel call -&amp;gt; grid 생성. 하나의 grid는 한 GPU에서 실행된다.&amp;nbsp;&amp;nbsp;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Thread Block -&amp;gt; SM&lt;/b&gt;: grid가 배정된 GPU 속에서, 각 thread block은 각 SM에 배정된다.&amp;nbsp;&amp;nbsp;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;b&gt;active block:&lt;/b&gt; SM에 할당된 block 중 현재 필요한 메모리 자원(register, shared memory 등)를 모두 할당 받고 실행할 수 있는 상태인 thread block. 활성 블록의 수가 많아야 GPU가 효율적으로 사용되고 있다고 말할 수 있음. 즉, 메모리 자원을 적절히 잘 조절 및 통제해야 GPU의 utilization을 높일 수 있음.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Warp &amp;amp; Thread -&amp;gt; SM 내 CUDA core&lt;/b&gt;:&amp;nbsp;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;warp 하나를 명령 하나로 보면 됨. 그리고 SM 내의 datapath 하나가 warp 하나를 병렬 처리한다.&lt;/li&gt;
&lt;li&gt;SM 내에 datapath가 보통 2개 있는데, 각 datapath가 16개의 CUDA core 묶음에 연결돼 있다.&amp;nbsp;&amp;nbsp;&lt;/li&gt;
&lt;li&gt;즉 SM 내부의 CUDA core 총 개수는 대체로 32의 배수임. 이는 warp가 32개의 thread로 구성되었기 때문.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;CUDA의 동기화 (Synchronization)&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;동기화 (synchronization) : 둘 이상의 연산 주체가 서로 정보를 교환하는 행위.&amp;nbsp;&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;`cudaMemcpyAsync`&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;`cudaMemsetAsync`&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;`cudaStreamWaitEvent`&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;`cudaEventSynchronize`&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;`cudaStreamSynchronize`&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;`vectorized_elementwise_kernel`&lt;/p&gt;</description>
      <category>Computer Itself</category>
      <author>오렌징큐</author>
      <guid isPermaLink="true">https://orangingq.tistory.com/217</guid>
      <comments>https://orangingq.tistory.com/entry/CUDA-%ED%95%A8%EC%88%98%EB%93%A4#entry217comment</comments>
      <pubDate>Sun, 29 Jun 2025 23:50:32 +0900</pubDate>
    </item>
  </channel>
</rss>