<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>sang_hyeob</title>
    <link>https://ksh0416.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Wed, 8 Apr 2026 14:33:35 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>Kim_sang_hyeob</managingEditor>
    <item>
      <title>GPGPU 총정리 - (3)</title>
      <link>https://ksh0416.tistory.com/161</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt; CUDA Programming Mode&amp;nbsp;&lt;/b&gt;&lt;/h2&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;1202&quot; data-origin-height=&quot;724&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d0P1YQ/dJMcaibFEF4/ChKxZ3o8K8hSVS5AtbOUtK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d0P1YQ/dJMcaibFEF4/ChKxZ3o8K8hSVS5AtbOUtK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d0P1YQ/dJMcaibFEF4/ChKxZ3o8K8hSVS5AtbOUtK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd0P1YQ%2FdJMcaibFEF4%2FChKxZ3o8K8hSVS5AtbOUtK%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;755&quot; height=&quot;455&quot; data-origin-width=&quot;1202&quot; data-origin-height=&quot;724&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CUDA 는 기본적으로 Host + Device 로 나뉘어진다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CPU 를 Host , gpu 쪽을 device 라고 부른다. 프로그램은 항상 host 에서 시작하며 , host 코드가 device 메모리 할당 , 데이터 복사 , kernel launch 같은 일을 담당한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제로 대량 병렬 계산은device 에서 kernel 이 수행한다.&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;또 , Host와 Device는 각각 별도의 메모리 공간을 DRAM에 유지한다. 이것이 CUDA 프로그래밍에서 명시적인 데이터 전송(`cudaMemcpy`)이 필요한 근본적인 이유이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만, CUDA는 Unified Memory 기능도 제공한다.&amp;nbsp;Unified&amp;nbsp;Memory를&amp;nbsp;사용하면&amp;nbsp;모든&amp;nbsp;프로세서가&amp;nbsp;단일&amp;nbsp;일관된&amp;nbsp;메모리&amp;nbsp;이미지(coherent&amp;nbsp;memory&amp;nbsp;image)를&amp;nbsp;공통&amp;nbsp;주소&amp;nbsp;공간에서&amp;nbsp;볼&amp;nbsp;수&amp;nbsp;있도록&amp;nbsp;managed&amp;nbsp;memory&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;/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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1258&quot; data-origin-height=&quot;813&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/z1ySo/dJMcad2qvYQ/UpL355POUwFi4R4yoVHIcK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/z1ySo/dJMcad2qvYQ/UpL355POUwFi4R4yoVHIcK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/z1ySo/dJMcad2qvYQ/UpL355POUwFi4R4yoVHIcK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fz1ySo%2FdJMcad2qvYQ%2FUpL355POUwFi4R4yoVHIcK%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;752&quot; height=&quot;486&quot; data-origin-width=&quot;1258&quot; data-origin-height=&quot;813&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Host&amp;nbsp; ( CPU )&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- CPU 코어들이 c++ 프로그램 실행하면서 CUDA RT API ( runttime api 호출 )&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- cudaMalloc, cudaMemcpy, cudaFree, 커널 런치 등 모든게 HOST 코드 쪽에서 api 를 통해 실행된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아직 나오지는 않았지만 Pinned memory 영역인데 ,&amp;nbsp; 원래 malloc 으로 할당한 메모리는 pageable 이라 OS 가 swap 할 수 있는데 , pinned memory 는 물리 메모리라서 (locked ) copy Engine 이 DMA 로 직접 전송이 가능하다고 한다 ( 속도 더 빠름 )&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;Device 0&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SM 들이 그려져 있다. 안에 물결 모양이 아마도 cuda core 나타내는 것 같고 커널 코드가 SM 위에서 작동하는 형식이다.&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;copy engine : Host memory 와 device 사이의 데이터 전송을 담당한다. ( D2H , H2D 둘다 가능 )&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 엔진은 SM 과 독립적으로 작동해서 ,&amp;nbsp; 커널 실행과 데이터 전송을 동시에 수행( OVERLAP ) 할 수 있다.&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;CONTEXT :&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CUDA context 가 GPU 자원 관리의 첫 단위이다. ( 레지스터 , 메모리 할당 ,커널 등등 .. 상태 관리 )&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;cuda api 호출시 이 컨텍스트 생성에 시간이 걸리는게 GPU initialization overhead의 원인이기도 하다 ( 그래서 과제에 시간 측정을 하는 코드에 warm-up 을 해야하는 것. )&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;STREAMS :&amp;nbsp;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;s&gt;Default : 같은 strema 내 명령은 순서대로 실행된다.&amp;nbsp;&lt;/s&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;s&gt;Non default : 서로다른 stream 의 명령은 동시에 실행될 수 있다.&amp;nbsp;&lt;/s&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Device 1&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GPU 가 2개 이상일 수도 있다는걸 보여주고 싶었던듯 ,&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;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1244&quot; data-origin-height=&quot;777&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bgJJVJ/dJMcaaEH3EP/iKiEjlSadcXPKoMHXO35bk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bgJJVJ/dJMcaaEH3EP/iKiEjlSadcXPKoMHXO35bk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bgJJVJ/dJMcaaEH3EP/iKiEjlSadcXPKoMHXO35bk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbgJJVJ%2FdJMcaaEH3EP%2FiKiEjlSadcXPKoMHXO35bk%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;778&quot; height=&quot;486&quot; data-origin-width=&quot;1244&quot; data-origin-height=&quot;777&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;.cu 파일에는 보통 host code &amp;amp; device code 가 같이 들어가 있다.&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1324&quot; data-start=&quot;1286&quot;&gt;__global__ : GPU에서 실행되는 &lt;b&gt;kernel&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;1365&quot; data-start=&quot;1325&quot;&gt;__device__ : GPU에서만 호출 가능한 device 함수&lt;/li&gt;
&lt;li data-end=&quot;1453&quot; data-start=&quot;1366&quot;&gt;__host__ : CPU에서 실행되는 함수 (안 쓰면 기본적으로 host 함수)&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 우리가 쓰는 c/c++ 에서 함수 앞에 원래는 __host__ 가 붙어있는거다 ! 이정도만 알면된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또, cuda 문법이 들어가 있는 파일은 nvcc 로 컴파일 해야한다. nvcc 는 .cu 파일을 host code / device code 로 분리해서 알아서 잘 컴파일 해준다.&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;Kernel lanch : &amp;lt;&amp;lt;&amp;lt; &amp;gt;&amp;gt;&amp;gt; 문법에 대한 이해 .&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1774426816514&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;vectorAdd&amp;lt;&amp;lt;&amp;lt;grid_dim, block_dim, dynamic_smem_bytes, stream&amp;gt;&amp;gt;&amp;gt;(args); 

보통 이런식으로 자주 쓴다. 
vectorAdd&amp;lt;&amp;lt;&amp;lt;blocksPerGrid, threadsPerBlock&amp;gt;&amp;gt;&amp;gt;(d_A, d_B, d_C, N);&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;grid_dim : block 이 몇개 있는지&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;block_dim : 각 block 안에 thread 가 몇개인지&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-------- 위 2개는 필수--------&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;dynamic : block 당 동적 shared memory 크기&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;stream : 어떤 CUDA stream 에서 처리할까&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;예를들어서 N 개의 원소 처리 + block 당 256 thread 쓴다고 하면&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1774426943781&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int threadsPerBlock = 256;
int blocksPerGrid = (N + threadsPerBlock - 1) / threadsPerBlock;
vectorAdd&amp;lt;&amp;lt;&amp;lt;blocksPerGrid, threadsPerBlock&amp;gt;&amp;gt;&amp;gt;(...);&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;그리고 kernel 에서는 if (i &amp;lt; N ) 범위로 한번 더 체크하는게 CUDA 에서 거의 기본이라고 한다.&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;일단 먼저 풀 코드를 보고 이해를 해보려고 시도해보자.&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;Sample Programming&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1774427039254&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// Vector addition: C = A + B
#include &amp;lt;stdio.h&amp;gt;
#include &amp;lt;cuda_runtime.h&amp;gt;
#include &amp;lt;device_launch_parameters.h&amp;gt;

// ── (1) Host 함수 정의 ──
void vectorAdd_host(const float* A, const float* B, float* C, int numElements) {
    for (int i = 0; i &amp;lt; numElements; i++)
        C[i] = A[i] + B[i];
}

// ── (2) Device 함수(커널) 정의 ── [C++ language extension: __global__]
__global__ void vectorAdd(const float *A, const float *B, float *C, int numElements) {
    int i = blockDim.x * blockIdx.x + threadIdx.x;  // [C++ language extension: built-in variables]
    if (i &amp;lt; numElements)
        C[i] = A[i] + B[i];
}

int main(void) {
    int numElements = 8000000;
    size_t size = numElements * sizeof(float);

    // ── (3) Host 메모리 할당 ──
    float *h_A = (float *)malloc(size);
    float *h_B = (float *)malloc(size);
    float *h_C_host = (float *)malloc(size);
    float *h_C_device = (float *)malloc(size);

    // ── (4) 에러 체크 ──
    if (h_A == NULL || h_B == NULL || h_C_host == NULL || h_C_device == NULL) {
        fprintf(stderr, &quot;Failed to allocate host vectors!\n&quot;);
        exit(EXIT_FAILURE);
    }

    // ── (5) 데이터 생성 ──
    for (int i = 0; i &amp;lt; numElements; ++i) {
        h_A[i] = rand() / (float)RAND_MAX;
        h_B[i] = rand() / (float)RAND_MAX;
    }

    // ── (6) Host 함수 호출 (CPU에서 벡터 덧셈) ──
    vectorAdd_host(h_A, h_B, h_C_host, numElements);

    // ── (7) Device 메모리 할당 ── [CUDA Runtime API]
    float *d_A = NULL;
    cudaMalloc((void **)&amp;amp;d_A, size);
    float *d_B = NULL;
    cudaMalloc((void **)&amp;amp;d_B, size);
    float *d_C = NULL;
    cudaMalloc((void **)&amp;amp;d_C, size);

    // ── (8) 데이터 전송: H2D ── [CUDA Runtime API]
    cudaMemcpy(d_A, h_A, size, cudaMemcpyHostToDevice);
    cudaMemcpy(d_B, h_B, size, cudaMemcpyHostToDevice);

    // ── (9) Grid과 Thread Block 설정 ──
    int threadsPerBlock = 256;
    int blocksPerGrid = (numElements + threadsPerBlock - 1) / threadsPerBlock;

    // ── (10) 커널 런치 ── [C++ language extension: &amp;lt;&amp;lt;&amp;lt;...&amp;gt;&amp;gt;&amp;gt;]
    vectorAdd &amp;lt;&amp;lt;&amp;lt;blocksPerGrid, threadsPerBlock&amp;gt;&amp;gt;&amp;gt; (d_A, d_B, d_C, numElements);

    // ── (11) 데이터 전송: D2H ── [CUDA Runtime API]
    cudaMemcpy(h_C_device, d_C, size, cudaMemcpyDeviceToHost);

    // ── (12) 결과 검증 ── [C++ language extension: fabs]
    for (int i = 0; i &amp;lt; numElements; ++i) {
        if (fabs(h_C_host[i] - h_C_device[i]) / h_C_host[i] &amp;gt; 1.0e-6) {
            fprintf(stderr, &quot;Result verification failed at element %d!\n&quot;, i);
            exit(EXIT_FAILURE);
        }
    }
    fprintf(stdout, &quot;\nTest PASSED\n&quot;);

    // ── (13) Device 메모리 해제 ──
    cudaFree(d_A);
    cudaFree(d_B);
    cudaFree(d_C);

    // ── (14) Host 메모리 해제 ──
    free(h_A);
    free(h_B);
    free(h_C_host);
    free(h_C_device);

    fprintf(stdout, &quot;\nDone\n&quot;);
    return 0;
}&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;(자세한 참고)&amp;nbsp;&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;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;div style=&quot;background-color: #1e1e1e; color: #d4d4d4;&quot;&gt;
&lt;div&gt;&lt;span style=&quot;color: #569cd6;&quot;&gt;실행 흐름 상세&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;div&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;위 프로그램의 실행 흐름을 단계별로 추적하면 다음과 같다:&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;div&gt;&lt;span style=&quot;color: #569cd6;&quot;&gt;**Step 1 &amp;mdash; Host 메모리 할당 (&lt;/span&gt;&lt;span style=&quot;color: #ce9178;&quot;&gt;`malloc`&lt;/span&gt;&lt;span style=&quot;color: #569cd6;&quot;&gt;)**&lt;/span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt; &amp;nbsp;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;CPU 쪽 메모리에 입력 벡터 &lt;/span&gt;&lt;span style=&quot;color: #ce9178;&quot;&gt;`h_A`&lt;/span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #ce9178;&quot;&gt;`h_B`&lt;/span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;와 출력 벡터 &lt;/span&gt;&lt;span style=&quot;color: #ce9178;&quot;&gt;`h_C_host`&lt;/span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;(CPU 결과), &lt;/span&gt;&lt;span style=&quot;color: #ce9178;&quot;&gt;`h_C_device`&lt;/span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;(GPU 결과 수신용)를 할당한다. 이 메모리는 일반적인 C의 &lt;/span&gt;&lt;span style=&quot;color: #ce9178;&quot;&gt;`malloc()`&lt;/span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;으로 할당되는 pageable 메모리이다.&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;div&gt;&lt;span style=&quot;color: #569cd6;&quot;&gt;**Step 2 &amp;mdash; 데이터 생성 (&lt;/span&gt;&lt;span style=&quot;color: #ce9178;&quot;&gt;`rand()`&lt;/span&gt;&lt;span style=&quot;color: #569cd6;&quot;&gt;)**&lt;/span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt; &amp;nbsp;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span style=&quot;color: #ce9178;&quot;&gt;`h_A`&lt;/span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;와 &lt;/span&gt;&lt;span style=&quot;color: #ce9178;&quot;&gt;`h_B`&lt;/span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;에 0.0~1.0 범위의 랜덤 float 값을 채운다.&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;div&gt;&lt;span style=&quot;color: #569cd6;&quot;&gt;**Step 3 &amp;mdash; Host 함수 실행**&lt;/span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt; &amp;nbsp;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;CPU에서 순차적으로 벡터 덧셈을 수행하여 &lt;/span&gt;&lt;span style=&quot;color: #ce9178;&quot;&gt;`h_C_host`&lt;/span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;에 저장한다. 이것은 나중에 GPU 결과를 검증하기 위한 참조값이다.&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;div&gt;&lt;span style=&quot;color: #569cd6;&quot;&gt;**Step 4 &amp;mdash; Device 메모리 할당 (&lt;/span&gt;&lt;span style=&quot;color: #ce9178;&quot;&gt;`cudaMalloc`&lt;/span&gt;&lt;span style=&quot;color: #569cd6;&quot;&gt;)**&lt;/span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt; &amp;nbsp;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;GPU 메모리(global memory)에 &lt;/span&gt;&lt;span style=&quot;color: #ce9178;&quot;&gt;`d_A`&lt;/span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #ce9178;&quot;&gt;`d_B`&lt;/span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #ce9178;&quot;&gt;`d_C`&lt;/span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;를 할당한다. &lt;/span&gt;&lt;span style=&quot;color: #ce9178;&quot;&gt;`cudaMalloc`&lt;/span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;은 CUDA Runtime API 함수로, 첫 번째 인자로 포인터의 주소(&lt;/span&gt;&lt;span style=&quot;color: #ce9178;&quot;&gt;`void **`&lt;/span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;)를 받는다. 이 포인터는 GPU 메모리의 주소를 가리키게 되며, Host 코드에서 직접 역참조(dereference)할 수 없다. 오직 &lt;/span&gt;&lt;span style=&quot;color: #ce9178;&quot;&gt;`cudaMemcpy`&lt;/span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;나 커널 인자로만 사용 가능하다.&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;div&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;```c&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span style=&quot;color: #569cd6;&quot;&gt;float&lt;/span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt; *d_A = &lt;/span&gt;&lt;span style=&quot;color: #569cd6;&quot;&gt;NULL&lt;/span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span style=&quot;color: #dcdcaa;&quot;&gt;cudaMalloc&lt;/span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;((&lt;/span&gt;&lt;span style=&quot;color: #569cd6;&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt; **)&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #9cdcfe;&quot;&gt;d_A&lt;/span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;, size);&lt;/span&gt;&lt;span style=&quot;color: #6a9955;&quot;&gt; &amp;nbsp;// d_A는 이제 GPU 메모리를 가리킴&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;```&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;div&gt;&lt;span style=&quot;color: #569cd6;&quot;&gt;**Step 5 &amp;mdash; 데이터 전송: Host &amp;rarr; Device (&lt;/span&gt;&lt;span style=&quot;color: #ce9178;&quot;&gt;`cudaMemcpy`&lt;/span&gt;&lt;span style=&quot;color: #569cd6;&quot;&gt;, H2D)**&lt;/span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt; &amp;nbsp;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span style=&quot;color: #ce9178;&quot;&gt;`h_A`&lt;/span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;와 &lt;/span&gt;&lt;span style=&quot;color: #ce9178;&quot;&gt;`h_B`&lt;/span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;의 데이터를 GPU 메모리의 &lt;/span&gt;&lt;span style=&quot;color: #ce9178;&quot;&gt;`d_A`&lt;/span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;와 &lt;/span&gt;&lt;span style=&quot;color: #ce9178;&quot;&gt;`d_B`&lt;/span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;로 복사한다. &lt;/span&gt;&lt;span style=&quot;color: #ce9178;&quot;&gt;`cudaMemcpyHostToDevice`&lt;/span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt; 플래그로 전송 방향을 지정한다. 이 호출은 &lt;/span&gt;&lt;span style=&quot;color: #569cd6;&quot;&gt;**동기적(synchronous)**&lt;/span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;이다 &amp;mdash; CPU는 전송이 완료될 때까지 블록된다.&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;div&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;```c&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span style=&quot;color: #dcdcaa;&quot;&gt;cudaMemcpy&lt;/span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;(d_A, h_A, size, cudaMemcpyHostToDevice);&lt;/span&gt;&lt;span style=&quot;color: #6a9955;&quot;&gt; &amp;nbsp;// dst, src, size, direction&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span style=&quot;color: #dcdcaa;&quot;&gt;cudaMemcpy&lt;/span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;(d_B, h_B, size, cudaMemcpyHostToDevice);&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;```&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;div&gt;&lt;span style=&quot;color: #569cd6;&quot;&gt;**Step 6 &amp;mdash; Grid/Block 설정 및 커널 런치**&lt;/span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt; &amp;nbsp;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span style=&quot;color: #ce9178;&quot;&gt;`threadsPerBlock = 256`&lt;/span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;으로 각 블록의 스레드 수를 설정하고, &lt;/span&gt;&lt;span style=&quot;color: #ce9178;&quot;&gt;`blocksPerGrid`&lt;/span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;를 계산하여 전체 데이터를 커버하도록 한다. ceiling division 공식 &lt;/span&gt;&lt;span style=&quot;color: #ce9178;&quot;&gt;`(N + T - 1) / T`&lt;/span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;를 사용한다.&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;div&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;```c&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span style=&quot;color: #569cd6;&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt; threadsPerBlock = &lt;/span&gt;&lt;span style=&quot;color: #b5cea8;&quot;&gt;256&lt;/span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span style=&quot;color: #569cd6;&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt; blocksPerGrid = (numElements + threadsPerBlock - &lt;/span&gt;&lt;span style=&quot;color: #b5cea8;&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;) / threadsPerBlock;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span style=&quot;color: #6a9955;&quot;&gt;// = (8000000 + 255) / 256 = 31250&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;```&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;div&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;커널 런치는 &lt;/span&gt;&lt;span style=&quot;color: #ce9178;&quot;&gt;`&amp;lt;&amp;lt;&amp;lt;blocksPerGrid, threadsPerBlock&amp;gt;&amp;gt;&amp;gt;`&lt;/span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt; 문법으로 수행된다. &lt;span style=&quot;background-color: #1b711d;&quot;&gt;이 호출은 &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #1b711d;&quot;&gt;&lt;span style=&quot;color: #569cd6;&quot;&gt;**비동기적(asynchronous)**&lt;/span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;이다 &amp;mdash; CPU는 커널을 GPU에 제출하고 즉시 다음 코드로 진행한다.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;div&gt;&lt;span style=&quot;color: #569cd6;&quot;&gt;**Step 7 &amp;mdash; 데이터 전송: Device &amp;rarr; Host (&lt;/span&gt;&lt;span style=&quot;color: #ce9178;&quot;&gt;`cudaMemcpy`&lt;/span&gt;&lt;span style=&quot;color: #569cd6;&quot;&gt;, D2H)**&lt;/span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt; &amp;nbsp;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;GPU 결과 &lt;/span&gt;&lt;span style=&quot;color: #ce9178;&quot;&gt;`d_C`&lt;/span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;를 CPU 메모리 &lt;/span&gt;&lt;span style=&quot;color: #ce9178;&quot;&gt;`h_C_device`&lt;/span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;로 복사한다. 이 &lt;/span&gt;&lt;span style=&quot;color: #ce9178;&quot;&gt;`cudaMemcpy`&lt;/span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt; 호출은 동기적이므로, GPU에서 커널 실행이 완료되고 데이터 전송까지 끝날 때까지 CPU가 대기한다. 따라서 별도의 &lt;/span&gt;&lt;span style=&quot;color: #ce9178;&quot;&gt;`cudaDeviceSynchronize()`&lt;/span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt; 없이도 결과가 안전하게 전달된다.&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;div&gt;&lt;span style=&quot;color: #569cd6;&quot;&gt;**Step 8 &amp;mdash; 결과 검증**&lt;/span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt; &amp;nbsp;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;CPU 결과와 GPU 결과를 원소별로 비교하여 상대 오차가 1.0e-6 이내인지 확인한다.&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;div&gt;&lt;span style=&quot;color: #569cd6;&quot;&gt;**Step 9 &amp;mdash; 메모리 해제**&lt;/span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt; &amp;nbsp;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span style=&quot;color: #ce9178;&quot;&gt;`cudaFree()`&lt;/span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;로 GPU 메모리를, &lt;/span&gt;&lt;span style=&quot;color: #ce9178;&quot;&gt;`free()`&lt;/span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;로 CPU 메모리를 해제한다.&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&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;특히 여기서 코드 짤 때 가장 익숙하지 않았던 부분은 kernel 쪽 코드는 &quot;thread&quot; 기준으로 작성을 해야 한다는 것이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러니까 기존 c/c++ 에서는 어떤 배열을 관리할때 순서대로 접근하고 , 해당 index 안에서 돌아갈 로직을 결정해주는 것을 명시적으로 코드로 작성해야 했다면 ,&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;kernel 쪽 함수에서는 thread_id 를 하나 지정하고 , 해당 thread 가 어떤 것을 처리해야 하는지에 대한 관점으로 생각해야한다 ( 추후에 더 설명 )&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;nvcc 컴파일 과정을 한번 살펴보자.&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;1263&quot; data-origin-height=&quot;829&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bGeDwu/dJMcafF0mHI/PkKopbi2DgVZ8E5veCYXUk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bGeDwu/dJMcafF0mHI/PkKopbi2DgVZ8E5veCYXUk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bGeDwu/dJMcafF0mHI/PkKopbi2DgVZ8E5veCYXUk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbGeDwu%2FdJMcafF0mHI%2FPkKopbi2DgVZ8E5veCYXUk%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;718&quot; height=&quot;471&quot; data-origin-width=&quot;1263&quot; data-origin-height=&quot;829&quot;/&gt;&lt;/span&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;1. Code separation&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;nvcc 가 .cu 파일 받으면 먼저 코드 분리 부터 시작한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;판별 기준은 간단하다 . __global__&amp;nbsp; , __device__ , blockIdx , trheaIdx 같은 CUDA C++ languageExtension 사용하는 부분이 device&amp;nbsp; / 나머지는 host code 이다.&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;2. Device code compilation&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;PTX :&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가상 GPU 아키텍쳐용 어셈블리이다. C++ -&amp;gt; ptx -&amp;gt; sass&amp;nbsp; 정도이다.&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;SASS :&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제 gpu 아키텍쳐용 기계어이다. sm_xx 옵션으로 지정할 수 있다.&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;&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;3. Host code compilation&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 nvcc 가 &amp;lt;&amp;lt;&amp;lt; ... &amp;gt;&amp;gt;&amp;gt; 문법을 표준 CUDA Runtime API 호출로 변환한다&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;pre id=&quot;code_1774429009052&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 변환 전 (CUDA extension)
vectorAdd &amp;lt;&amp;lt;&amp;lt;blocksPerGrid, threadsPerBlock&amp;gt;&amp;gt;&amp;gt; (d_A, d_B, d_C, n);

// 변환 후 (표준 C++)
void* args[] = { (void*)&amp;amp;d_A, (void*)&amp;amp;d_B, (void*)&amp;amp;d_C, (void*)&amp;amp;n };
cudaLaunchKernel((const void*)vectorAdd, dim3(blocksPerGrid), 
                  dim3(threadsPerBlock), args, 0, 0);&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;이런식으로 자동으로 변환한다.&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;변환된 코드를 C++ 컴파일러에 넘긴다.&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;4. Linking&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;host 파일 + device 코드 + cuda runtime library 합쳐서 단일 실행파일을 만든다.&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;u&gt;&lt;b&gt;정리&lt;/b&gt;&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[1]&amp;nbsp;.cu&amp;nbsp;파일&amp;nbsp;작성 &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;-&amp;nbsp;host&amp;nbsp;code &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;-&amp;nbsp;device&amp;nbsp;code &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;-&amp;nbsp;CUDA&amp;nbsp;문법&amp;nbsp;포함 &lt;br /&gt;&lt;br /&gt;[2]&amp;nbsp;nvcc가&amp;nbsp;분리 &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;-&amp;nbsp;host&amp;nbsp;부분&amp;nbsp;추출 &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;-&amp;nbsp;device&amp;nbsp;부분&amp;nbsp;추출 &lt;br /&gt;&lt;br /&gt;[3]&amp;nbsp;device&amp;nbsp;부분&amp;nbsp;컴파일 &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;-&amp;nbsp;PTX&amp;nbsp;생성&amp;nbsp;(compute_XX) &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;-&amp;nbsp;SASS/cubin&amp;nbsp;생성&amp;nbsp;(sm_XX) &lt;br /&gt;&lt;br /&gt;[4]&amp;nbsp;host&amp;nbsp;부분&amp;nbsp;컴파일 &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;-&amp;nbsp;&amp;lt;&amp;lt;&amp;lt;&amp;gt;&amp;gt;&amp;gt;&amp;nbsp;를&amp;nbsp;CUDA&amp;nbsp;runtime&amp;nbsp;API&amp;nbsp;호출로&amp;nbsp;변환 &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;-&amp;nbsp;gcc/clang/cl.exe&amp;nbsp;로&amp;nbsp;일반&amp;nbsp;C++처럼&amp;nbsp;컴파일 &lt;br /&gt;&lt;br /&gt;[5]&amp;nbsp;링크 &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;-&amp;nbsp;host&amp;nbsp;object&amp;nbsp;+&amp;nbsp;device&amp;nbsp;binary&amp;nbsp;+&amp;nbsp;CUDA&amp;nbsp;runtime &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;- 최종 executable 생성&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&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lfCi4/dJMb99Ti11M/GBXLBKuL0RVxm9RC4GXio0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lfCi4/dJMb99Ti11M/GBXLBKuL0RVxm9RC4GXio0/img.png&quot; data-origin-width=&quot;1233&quot; data-origin-height=&quot;824&quot; data-is-animation=&quot;false&quot; style=&quot;width: 46.3693%; margin-right: 10px;&quot; data-widthpercent=&quot;46.91&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lfCi4/dJMb99Ti11M/GBXLBKuL0RVxm9RC4GXio0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlfCi4%2FdJMb99Ti11M%2FGBXLBKuL0RVxm9RC4GXio0%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;1233&quot; height=&quot;824&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bPxGAV/dJMcafTxyRP/Yfl4qgHWHVOS61FVwztRkk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bPxGAV/dJMcafTxyRP/Yfl4qgHWHVOS61FVwztRkk/img.png&quot; data-origin-width=&quot;1214&quot; data-origin-height=&quot;717&quot; data-is-animation=&quot;false&quot; style=&quot;width: 52.4679%;&quot; data-widthpercent=&quot;53.09&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bPxGAV/dJMcafTxyRP/Yfl4qgHWHVOS61FVwztRkk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbPxGAV%2FdJMcafTxyRP%2FYfl4qgHWHVOS61FVwztRkk%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;1214&quot; height=&quot;717&quot;/&gt;&lt;/span&gt;&lt;/div&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;1. __global__&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;실행 위치: device(GPU)&lt;br /&gt;기본 호출 위치: host(CPU)&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CC 5.0 이상에서는 device에서도 호출 가능(동적 병렬성)&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;__global__ 이 kernel entry function 이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;kernel&lt;/span&gt;&lt;span&gt;&amp;lt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span&gt;grid&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;block&lt;/span&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;args&lt;/span&gt;&lt;span&gt;);&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이것 처럼 execution oncifuration 이 필요하다&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;왜냐하면 , 함수 호출 몇개가 아니라&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&quot; GPU 에 Thread 몇개 , block 몇개를 만들어서 병렬 실행하라 &quot; 라는 요청이기 때문.&amp;nbsp;&lt;/span&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;span&gt;쉽게 이야기하면 __global__ 은 단순 함수가 아니라 GPU 작업의 진입점 ( entry point ) 이다.&amp;nbsp;&amp;nbsp;&lt;/span&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;&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;4가지 특성&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&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;반드시 void 반환&lt;/b&gt; &amp;mdash; GPU에서 실행되는 함수가 CPU로 값을 직접 return할 방법이 없다. 결과는 device memory에 쓰고, cudaMemcpy로 가져와야 함.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;실행 구성 필수&lt;/b&gt; &amp;mdash; &amp;lt;&amp;lt;&amp;lt;grid, block&amp;gt;&amp;gt;&amp;gt;을 반드시 붙여야 함. &quot;몇 개의 스레드를 어떤 구조로 런치할 것인가&quot;를 지정합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;비동기 호출&lt;/b&gt; &amp;mdash; CPU가 커널을 GPU에 제출하면 &lt;b&gt;즉시 반환&lt;/b&gt;합니다. GPU가 아직 실행 중인데 CPU는 이미 다음 줄을 실행해요. 결과를 확인하려면 cudaDeviceSynchronize()나 동기적 cudaMemcpy가 필요합니다. ( 그래서 시간 젤 때 , 명시적으로 cpu 를 돌지 못하도록 막음)&amp;nbsp; -
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;6282&quot; data-start=&quot;6256&quot;&gt;launch 했다 = GPU에 일 시켰다&lt;/li&gt;
&lt;li data-end=&quot;6295&quot; data-start=&quot;6283&quot;&gt;끝났다 = 아님&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;재귀 불가&lt;/b&gt; &amp;mdash; __global__ 함수는 자기 자신을 호출할 수 없다. (단, CC 5.0+ 에서 Dynamic Parallelism으로 다른 __global__ 함수를 호출하는 건 가능)&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;2. __device__&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;GPU 내부 전용 함수이다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;6859&quot; data-start=&quot;6846&quot;&gt;device에서 실행&lt;/li&gt;
&lt;li data-end=&quot;6877&quot; data-start=&quot;6860&quot;&gt;device에서만 호출 가능&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1774430715724&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;예시 ) 
__device__ float helper(float x) { return x * x; }

__global__ void kernel(float *data, int n) {
    int i = blockDim.x * blockIdx.x + threadIdx.x;
    if (i &amp;lt; n) data[i] = helper(data[i]);  // 커널 안에서만 호출 가능
}&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추가로 device 와 global 을 함께 쓰는 것은 불가능하다.&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;( __device__ 함수는 kernel이 아니다 -&amp;gt; 그냥 GPU 내부 코드에서 보조 함수처럼 호출한다.&amp;nbsp; )&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;3. __host__&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리가 원래 쓰는 c/c++ 함수들이다 ( 그냥 CPU 에서 돌아가는.. )&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;__device__&amp;nbsp; __host__ 같이 쓰면 host 와 device 둘다 컴파일이 된다고 한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;근데 주의해야할 점이 CPU / GPU 용 함수가 이렇게 둘 다 생기게 됩니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(nvcc 가 함수를 두번 컴파일 - host / device 용 )&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;lt; 요약 테이블 &amp;gt;&amp;nbsp;&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;1135&quot; data-origin-height=&quot;425&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bKqBbN/dJMcaipcgib/blekCuLh4iZbFGynDrfPv1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bKqBbN/dJMcaipcgib/blekCuLh4iZbFGynDrfPv1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bKqBbN/dJMcaipcgib/blekCuLh4iZbFGynDrfPv1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbKqBbN%2FdJMcaipcgib%2FblekCuLh4iZbFGynDrfPv1%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;662&quot; height=&quot;248&quot; data-origin-width=&quot;1135&quot; data-origin-height=&quot;425&quot;/&gt;&lt;/span&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;&amp;nbsp;&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;1207&quot; data-origin-height=&quot;740&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/byzCs9/dJMcaaSflH7/2zsdxos5djE8WAl7agQWDk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/byzCs9/dJMcaaSflH7/2zsdxos5djE8WAl7agQWDk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/byzCs9/dJMcaaSflH7/2zsdxos5djE8WAl7agQWDk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbyzCs9%2FdJMcaaSflH7%2F2zsdxos5djE8WAl7agQWDk%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;363&quot; data-origin-width=&quot;1207&quot; data-origin-height=&quot;740&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Built-in Vector Types&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;cuda 가 기본 정수/부동 소수점 묶어서 제공하는 구조체이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GPU 에서 데이터를 2, 3, ,4개씩 묶어서 loag/store 할때 좋다.&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;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;float4 pixel = make_float4(r, g, b, a); // RGBA 색상 &lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;float2 coord = make_float2(u, v); // &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;텍스처 좌표 &lt;/span&gt;&lt;span&gt;int2 pos = make_int2(row, col); // 2D 인덱스&amp;nbsp;&lt;/span&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;span&gt;대략 이런식으로 사용할 수 있겠다.&amp;nbsp;&lt;/span&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;1251&quot; data-origin-height=&quot;785&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bTiPj9/dJMcahX6R2F/TLR5RBcQMUhL2sCHw9W3A0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bTiPj9/dJMcahX6R2F/TLR5RBcQMUhL2sCHw9W3A0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bTiPj9/dJMcahX6R2F/TLR5RBcQMUhL2sCHw9W3A0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbTiPj9%2FdJMcahX6R2F%2FTLR5RBcQMUhL2sCHw9W3A0%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;591&quot; height=&quot;371&quot; data-origin-width=&quot;1251&quot; data-origin-height=&quot;785&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그중에서도 dim3 를 가장 자주쓴다.&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;unit3 기반의 정수 벡터 타입이고 x,y,z 성분을 가진다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;용도로는 kernel configuration ( grid 와 block 의 차원 지정하고 읽어오는 것. ) - 지정하지 않으면 기본 값은 1로 설정한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;cuda 의 grid 와 block 이 1/2/3 D 가 가능하기 때문 .&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;h2 data-ke-size=&quot;size26&quot;&gt;Thread Hierarchy (Prior to CC 9.0)&amp;nbsp;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기 파트는 뭐랄까 c 언어 처음배울때로 돌아가서 ( 자료구조처럼 ? ) 배열에 대해서 자리값 계산하고.. 이런 일을 종종 처음에 하는데 , 여기 파트도 그런 느낌이다.&amp;nbsp;&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;948&quot; data-origin-height=&quot;620&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7NNLg/dJMcab4M24A/qZwqEBeBhoNZQPasxQjJ9K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7NNLg/dJMcab4M24A/qZwqEBeBhoNZQPasxQjJ9K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7NNLg/dJMcab4M24A/qZwqEBeBhoNZQPasxQjJ9K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7NNLg%2FdJMcab4M24A%2FqZwqEBeBhoNZQPasxQjJ9K%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;729&quot; height=&quot;477&quot; data-origin-width=&quot;948&quot; data-origin-height=&quot;620&quot;/&gt;&lt;/span&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;&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;2. built-in variables for dimensions and indices&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;built-in 변수 5개&amp;nbsp; ( device 에서 실행되는 함수안에서만 유효 )&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;변수&amp;nbsp; | 타입 | 의미
&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;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;gridDim&lt;/td&gt;
&lt;td&gt;dim3&lt;/td&gt;
&lt;td&gt;grid의 크기 &amp;rarr; 블록이 몇 개인지 (x, y, z)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;blockDim&lt;/td&gt;
&lt;td&gt;dim3&lt;/td&gt;
&lt;td&gt;thread block의 크기 &amp;rarr; 블록 당 thread 개수&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;blockIdx&lt;/td&gt;
&lt;td&gt;uint3&lt;/td&gt;
&lt;td&gt;이 block이 grid 안에서 몇 번째인지&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;threadIdx&lt;/td&gt;
&lt;td&gt;uint3&lt;/td&gt;
&lt;td&gt;이 thread가 block 안에서 몇 번째인지&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;warpSize&lt;/td&gt;
&lt;td&gt;int&lt;/td&gt;
&lt;td&gt;warp 크기 = 32 (상수)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 숙지하고 1D / 2D example 들을 확인해보려고 한다.&amp;nbsp;&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;945&quot; data-origin-height=&quot;622&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cpigDo/dJMcabDJEYE/N8npgkScgFYeV9lU00Fyf1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cpigDo/dJMcabDJEYE/N8npgkScgFYeV9lU00Fyf1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cpigDo/dJMcabDJEYE/N8npgkScgFYeV9lU00Fyf1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcpigDo%2FdJMcabDJEYE%2FN8npgkScgFYeV9lU00Fyf1%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;741&quot; height=&quot;488&quot; data-origin-width=&quot;945&quot; data-origin-height=&quot;622&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1D 에서는 비교적 계산이 쉽다.&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;span&gt;int&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt; = &lt;/span&gt;&lt;span&gt;blockDim&lt;/span&gt;&lt;span&gt;.x &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;blockIdx&lt;/span&gt;&lt;span&gt;.x &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;threadIdx&lt;/span&gt;&lt;span&gt;.x;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;-&amp;gt; (몇개의 thread 가 한 블럭에 있는지) * (몇번째 블록인지) + ( 해당 thread 안에서 내가 몇번째인지 ) &lt;/span&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;span&gt;이런식으로 나타내면 된다. 처음볼때는 변수명이랑 매칭이 안되서 살짝 헷갈리는데 보다보면 익숙해져서 괜찮다.&amp;nbsp;&lt;/span&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;&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;2D 부터는 살짝 귀찮지만 , 못할정도는 아니다.&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;874&quot; data-origin-height=&quot;614&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2pFBC/dJMcahqp8xC/1EhMYYRSgbTYTu0hZyF9Xk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2pFBC/dJMcahqp8xC/1EhMYYRSgbTYTu0hZyF9Xk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2pFBC/dJMcahqp8xC/1EhMYYRSgbTYTu0hZyF9Xk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2pFBC%2FdJMcahqp8xC%2F1EhMYYRSgbTYTu0hZyF9Xk%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;706&quot; height=&quot;496&quot; data-origin-width=&quot;874&quot; data-origin-height=&quot;614&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;871&quot; data-origin-height=&quot;555&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bu44Dg/dJMcac3F7Ep/7TflcfDzLOxTkcaWN00L7K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bu44Dg/dJMcac3F7Ep/7TflcfDzLOxTkcaWN00L7K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bu44Dg/dJMcac3F7Ep/7TflcfDzLOxTkcaWN00L7K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbu44Dg%2FdJMcac3F7Ep%2F7TflcfDzLOxTkcaWN00L7K%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;720&quot; height=&quot;459&quot; data-origin-width=&quot;871&quot; data-origin-height=&quot;555&quot;/&gt;&lt;/span&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;총 thread 수 = 4096 x 2160&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;block 크기 = 32 x 16 -&amp;gt; ( blockDIM.x x blockDIM.y )&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;block 개수 = (4096 / 32 ) * ( 2160 / 16 ) -&amp;gt; ( gridDim.x * gridDim.y )&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;* block 안에서 나는 몇번쨰 trhead 인가 ?&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Thread ID = blockDim.x * threadIdx.y +&amp;nbsp; threadIdx.x&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- x 먼저 채우고 , 다 차면 y 가 올라가는 row-major 순서이므로.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 여기서 blockDim x = 32 / y = 16&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- threadIdx 는 해당 블럭에서 x,y 가 지금 어디있는지 알려주므로.. ( 예시에서는 3,2 )&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;u&gt;한 행의 길이(blockDim.x) &amp;times; 몇 번째 행(threadIdx.y) + 그 행에서 몇 번째(threadIdx.x)&amp;nbsp;&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; Thread ID = 32 * 2 + 3 으로 계산하면 된다.&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;* 전체 grid 에서 global ID&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;x = blockDim.x * blockIdx.x + threadIdx.x ( 열방향 )&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;y = blockDim.y * blockIdx.y + threadIdx.y&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;span&gt;&lt;span&gt;global_id = gridDim.x * blockDim.x * (blockDim.y * blockIdx.y + threadIdx.y) &lt;/span&gt;&lt;/span&gt;&lt;span&gt; + blockDim.x * blockIdx.x + threadIdx.x&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;( Global ID = ROW * gridDim.x * blockDim.x + ROW )&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;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;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;879&quot; data-origin-height=&quot;604&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/55wkZ/dJMb99MEiCh/kRUeiLcij9spzloAMKpBSk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/55wkZ/dJMb99MEiCh/kRUeiLcij9spzloAMKpBSk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/55wkZ/dJMb99MEiCh/kRUeiLcij9spzloAMKpBSk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F55wkZ%2FdJMb99MEiCh%2FkRUeiLcij9spzloAMKpBSk%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;611&quot; height=&quot;420&quot; data-origin-width=&quot;879&quot; data-origin-height=&quot;604&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt; = &lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;축에서의&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;시작점 &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;축에서의&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;내&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;로컬&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;위치&lt;/span&gt;&lt;br /&gt;&lt;span&gt;y&lt;/span&gt;&lt;span&gt; = &lt;/span&gt;&lt;span&gt;y&lt;/span&gt;&lt;span&gt;축에서의&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;시작점 &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;y&lt;/span&gt;&lt;span&gt;축에서의&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;내&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;로컬&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;위치&amp;nbsp;&lt;/span&gt;&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;span&gt;int&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt; = &lt;/span&gt;&lt;span&gt;blockIdx&lt;/span&gt;&lt;span&gt;.x &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;blockDim&lt;/span&gt;&lt;span&gt;.x &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;threadIdx&lt;/span&gt;&lt;span&gt;.x;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;y&lt;/span&gt;&lt;span&gt; = &lt;/span&gt;&lt;span&gt;blockIdx&lt;/span&gt;&lt;span&gt;.y &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;blockDim&lt;/span&gt;&lt;span&gt;.y &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;threadIdx&lt;/span&gt;&lt;span&gt;.y;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 여기까지는 Linear index 계산임 ! ( 전역 좌표 계산을 했고 . )&amp;nbsp;&lt;br /&gt;&lt;br /&gt;이미지가 row-major 로 1차원 배열에 저장되어 있으면 1차원 메모리 index 계산을 해야한다.&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;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-end=&quot;2437&quot; data-start=&quot;2422&quot; data-section-id=&quot;1fe5lsj&quot; data-ke-size=&quot;size23&quot;&gt;1) 전역 좌표 계산&lt;/h3&gt;
&lt;p data-end=&quot;2455&quot; data-start=&quot;2438&quot; data-ke-size=&quot;size16&quot;&gt;이건 그냥 위치를 구하는 거다.&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;&amp;nbsp;&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;div&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt; = &lt;/span&gt;&lt;span&gt;blockIdx&lt;/span&gt;&lt;span&gt;.x &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;blockDim&lt;/span&gt;&lt;span&gt;.x &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;threadIdx&lt;/span&gt;&lt;span&gt;.x;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;y&lt;/span&gt;&lt;span&gt; = &lt;/span&gt;&lt;span&gt;blockIdx&lt;/span&gt;&lt;span&gt;.y &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;blockDim&lt;/span&gt;&lt;span&gt;.y &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;threadIdx&lt;/span&gt;&lt;span&gt;.y;&lt;/span&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;2584&quot; data-start=&quot;2555&quot; data-ke-size=&quot;size16&quot;&gt;여기에는 &lt;b&gt;gridDim.x가 안 들어감.&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;2584&quot; data-start=&quot;2555&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-end=&quot;2609&quot; data-start=&quot;2586&quot; data-section-id=&quot;1kon9da&quot; data-ke-size=&quot;size23&quot;&gt;2) 1차원 메모리 index 계산&lt;/h3&gt;
&lt;p data-end=&quot;2650&quot; data-start=&quot;2610&quot; data-ke-size=&quot;size16&quot;&gt;이미지가 row-major로 1차원 배열에 저장&lt;/p&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;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;div&gt;&lt;span&gt;idx&lt;/span&gt;&lt;span&gt; = &lt;/span&gt;&lt;span&gt;y&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;width&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;;&lt;/span&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;width ( 한 줄 길이 )&lt;/div&gt;
&lt;div&gt;width = gridDim.x * blockDim.x&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2690&quot; data-start=&quot;2685&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;( &lt;span&gt;먼저 (x, y)를 구함 &lt;/span&gt;&lt;span&gt;그 다음 필요하면 idx = y * width + x 로 1차원 인덱스로 바꿈 )&lt;/span&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;So,&lt;/span&gt;&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;idx&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;=&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;y&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&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 style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;gridDim.x * blockDim.x&amp;nbsp;&lt;/span&gt; )&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&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;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;x&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2028&quot; data-origin-height=&quot;1314&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qRGUy/dJMcagE4m9h/kTuo3t1RShakMqRWBD09rK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qRGUy/dJMcagE4m9h/kTuo3t1RShakMqRWBD09rK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qRGUy/dJMcagE4m9h/kTuo3t1RShakMqRWBD09rK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqRGUy%2FdJMcagE4m9h%2FkTuo3t1RShakMqRWBD09rK%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;957&quot; height=&quot;620&quot; data-origin-width=&quot;2028&quot; data-origin-height=&quot;1314&quot;/&gt;&lt;/span&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;(기본 문법 )&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;armasm&quot; style=&quot;color: #14181f;&quot;&gt;&lt;code&gt;kernelFunc&amp;lt;&amp;lt;&amp;lt;grid_dim, block_dim, dynamic_smem_bytes, stream&amp;gt;&amp;gt;&amp;gt;(인자들);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;grid_dim&lt;/b&gt;: 블록 몇 개 만들지 (필수)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;block_dim&lt;/b&gt;: 블록당 스레드 몇 개 (필수)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;dynamic_smem_bytes&lt;/b&gt;: 동적 shared memory 크기 (선택, 기본 0)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;stream&lt;/b&gt;: 어느 stream에서 실행할지 (선택, 기본 0)&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;&amp;lt;&amp;lt;&amp;lt; &amp;gt;&amp;gt;&amp;gt; -&amp;gt; nvcc 컴파일러가 컴파일하면 API 호출로 변환됨 ( 위 코드 참조 )&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;&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;2021&quot; data-origin-height=&quot;1317&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ctde6V/dJMcaaY7fX3/f1hJLfaTd9sylWmHKcEdD0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ctde6V/dJMcaaY7fX3/f1hJLfaTd9sylWmHKcEdD0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ctde6V/dJMcaaY7fX3/f1hJLfaTd9sylWmHKcEdD0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fctde6V%2FdJMcaaY7fX3%2Ff1hJLfaTd9sylWmHKcEdD0%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;2021&quot; height=&quot;1317&quot; data-origin-width=&quot;2021&quot; data-origin-height=&quot;1317&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1975&quot; data-origin-height=&quot;1032&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bU320a/dJMcadhe5OK/kFzdamXe5GX4XczRJkXkhk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bU320a/dJMcadhe5OK/kFzdamXe5GX4XczRJkXkhk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bU320a/dJMcadhe5OK/kFzdamXe5GX4XczRJkXkhk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbU320a%2FdJMcadhe5OK%2FkFzdamXe5GX4XczRJkXkhk%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;1975&quot; height=&quot;1032&quot; data-origin-width=&quot;1975&quot; data-origin-height=&quot;1032&quot;/&gt;&lt;/span&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;CUDA API 동기화 동작에는 2가지가 있다.&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;1. Asynchoronous ( 비동기 )&amp;nbsp; : CPU 가 gpu 한테 명령 보내고 기다리지 않고 바로 다음줄 실행 ( &amp;lt;&amp;lt;&amp;lt; &amp;gt;&amp;gt;&amp;gt; 역시 여기 포함 )&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. synchoronous ( 동기 ) : GPU 가 끝날때까지 멈춰서 기다리는 것&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- cudaMemcpy ( D -&amp;gt; H ) 가 여기에 해당한다.&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;Explicit synchronization : 비동기 작업 ㅎ웨 cpu 가 결과를 써야 하는 경우 cudaDeviceSynchronize()를 호출해서 수동으로 GPU 작업 완료를 기다리는 것.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를들어서 시간 측정하는 경우에 cpu 에서 기다렸다가 시간을 측정해야 하기 때문에 , cpu 를 명시적이 코드를 사용해서 멈춰두는것.&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;( 따로 그림을 첨부하지는 않고 설명 )&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&amp;lt; GPU Initilization &amp;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;NVIDIA Nsight 프로파일링 결과들을 확인해보면&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;- WARM_UP 의 경우 첫 커널이 cuLibraryLoadData 같은 초기화 때문에 오래 걸림&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- gpu 처음쓸 때 드라이버 초기화 , 컨텍슽트 생성 , 라이브러리 로딩 등 땜 느리다 !&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;&amp;nbsp;&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;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Warp Occupancy Revisited&amp;nbsp;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1825&quot; data-origin-height=&quot;1181&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/6yYNZ/dJMcajn9JrB/ceNnG7wDTIKF8piqg0crZ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/6yYNZ/dJMcajn9JrB/ceNnG7wDTIKF8piqg0crZ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/6yYNZ/dJMcajn9JrB/ceNnG7wDTIKF8piqg0crZ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F6yYNZ%2FdJMcajn9JrB%2FceNnG7wDTIKF8piqg0crZ0%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;1825&quot; height=&quot;1181&quot; data-origin-width=&quot;1825&quot; data-origin-height=&quot;1181&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1793&quot; data-origin-height=&quot;1191&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/OYQUJ/dJMcahxcnKJ/lucN32KgKfE1HdUK5wkG7K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/OYQUJ/dJMcahxcnKJ/lucN32KgKfE1HdUK5wkG7K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/OYQUJ/dJMcahxcnKJ/lucN32KgKfE1HdUK5wkG7K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOYQUJ%2FdJMcahxcnKJ%2FlucN32KgKfE1HdUK5wkG7K%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;1793&quot; height=&quot;1191&quot; data-origin-width=&quot;1793&quot; data-origin-height=&quot;1191&quot;/&gt;&lt;/span&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;다시 warp occupacy 에 대해서 복습을 하고 이번 강을 마치도록 하자.&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;Warp occupancy 란 ?&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;warp occupancy = Sm 에 현재 active 한 warp 수 / SM이 가질 수 있는 최대 warp 수&amp;nbsp;&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;TB가 SM에 배정되려면?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 Thread Block(TB)이 SM에 올라가려면, 그 SM이 TB가 필요로 하는 &lt;b&gt;레지스터&lt;/b&gt;와 &lt;b&gt;shared memory&lt;/b&gt;를 제공할 수 있어야 한다. 자원이 허용하는 한도 내에서 여러 TB가 동시에 한 SM에서 실행될 수 있고.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전에 4가지 정도 제한을 잘 살펴봐야한다고 했는데 , 그런 이유들로 TB 이 SM 에 배정되는 경우가 다르다.&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;다만, OCCUPANCY 를 100%까지 맞출 필요는 없고 ( 불가능하고 ) , 적당히 약 70%정도 까지는 체워야 성능이 좀 나온다고 한다.&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;예제를 몇가지 살펴보자.&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;예제 1:&lt;/b&gt; 32x32 크기의 2D TB 2개를 한 SM에 동시에 실행 가능할까?&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;gt; 32 X 32 (1024 ) thread 이게 2개면 , 2048 thread 인데 , cc 8.6 에서는 보면 SM 당 최대 1536 개 제한이 있으므로 불가능하다.&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;예제 2:&lt;/b&gt; 256 크기의 1D TB은 최대 몇 개?&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;256 / 32(warp 단위 ) = 8개warp 가 있다. ( cf. 하나의 thread block 은 하나의 SM 에 배정되어야 한다.&amp;nbsp; )&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;- 블럭 수 제한 : 16개 -&amp;gt; 16개 까지 들어갈 수 있음.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- WARP 수 : 48개 -&amp;gt; 6개 까지 들어갈 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- THREAD 수 제한 : 1536 / 256 = 6개&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;위 3개의 조건에서 최소값이 6개 이므로 -&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;A : 6개의 thread block 이 들어갈 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 총 48개의 warp 가 상주 할 수 있으므로 ( block 당 warp 수가 6개 )&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 48/48 이다. ( 100 % )&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;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;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;h3 data-end=&quot;2366&quot; data-start=&quot;2305&quot; data-section-id=&quot;vhwc8i&quot; data-ke-size=&quot;size23&quot;&gt;1) TB size 16x16, regs/thread = 32, shared memory = 2048B&lt;/h3&gt;
&lt;p data-end=&quot;2413&quot; data-start=&quot;2368&quot; data-ke-size=&quot;size16&quot;&gt;16x16 = 256 threads니까 block당 warp는 여전히 8개야.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2588&quot; data-start=&quot;2415&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2440&quot; data-start=&quot;2415&quot; data-section-id=&quot;181zhyl&quot;&gt;thread limit &amp;rarr; 6 blocks&lt;/li&gt;
&lt;li data-end=&quot;2464&quot; data-start=&quot;2441&quot; data-section-id=&quot;1b3lmrb&quot;&gt;warp limit &amp;rarr; 6 blocks&lt;/li&gt;
&lt;li data-end=&quot;2534&quot; data-start=&quot;2465&quot; data-section-id=&quot;1g1e63t&quot;&gt;reg usage: 256 &amp;times; 32 = 8192 regs/block &amp;rarr; 65536 / 8192 = 8 blocks&lt;/li&gt;
&lt;li data-end=&quot;2588&quot; data-start=&quot;2535&quot; data-section-id=&quot;q3qwqx&quot;&gt;smem usage: 2048B/block &amp;rarr; shared memory는 훨씬 여유 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;2719&quot; data-start=&quot;2590&quot; data-ke-size=&quot;size16&quot;&gt;결국 병목은 thread/warp 제한이므로 &lt;b&gt;6 blocks&lt;/b&gt;, &lt;b&gt;48 warps&lt;/b&gt;, occupancy는 48/48 = 1.0. 슬라이드 결과와 맞아.&lt;/p&gt;
&lt;h3 data-end=&quot;2782&quot; data-start=&quot;2721&quot; data-section-id=&quot;yfww50&quot; data-ke-size=&quot;size23&quot;&gt;2) TB size 16x16, regs/thread = 40, shared memory = 2048B&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2897&quot; data-start=&quot;2784&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2806&quot; data-start=&quot;2784&quot; data-section-id=&quot;1911iqx&quot;&gt;block당 threads = 256&lt;/li&gt;
&lt;li data-end=&quot;2825&quot; data-start=&quot;2807&quot; data-section-id=&quot;1dguc62&quot;&gt;block당 warps = 8&lt;/li&gt;
&lt;li data-end=&quot;2868&quot; data-start=&quot;2826&quot; data-section-id=&quot;1ebt9ii&quot;&gt;reg usage: 256 &amp;times; 40 = 10240 regs/block&lt;/li&gt;
&lt;li data-end=&quot;2897&quot; data-start=&quot;2869&quot; data-section-id=&quot;mtrv1u&quot;&gt;65536 / 10240 = 6 blocks&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;3195&quot; data-start=&quot;2980&quot; data-ke-size=&quot;size16&quot;&gt;( 여기는 오타가 좀 있는듯 ) -&amp;gt; occpancy 1 이 맞는거 것 같음.&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;3195&quot; data-start=&quot;2980&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-end=&quot;3258&quot; data-start=&quot;3197&quot; data-section-id=&quot;t44c44&quot; data-ke-size=&quot;size23&quot;&gt;3) TB size 16x16, regs/thread = 41, shared memory = 2048B&lt;/h3&gt;
&lt;p data-end=&quot;3371&quot; data-start=&quot;3260&quot; data-ke-size=&quot;size16&quot;&gt;여기가 진짜 재밌는 부분이야. 41개로 딱 1개 늘었는데 block 수가 6개에서 5개로 떨어진다. 이유는 &lt;b&gt;register allocation granularity&lt;/b&gt; 때문이야. 슬라이드 계산에도&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 id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;div&gt;&lt;span&gt;CEILING(41*32, 256) = 1536&lt;/span&gt;&lt;br /&gt;&lt;span&gt;...&lt;/span&gt;&lt;br /&gt;&lt;span&gt;결과적으로 register 제한으로 5 blocks&lt;/span&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;3730&quot; data-start=&quot;3446&quot; data-ke-size=&quot;size16&quot;&gt;라고 나와 있어. 즉 warp 단위/정렬 단위 때문에 register 사용량이 계단식으로 튀어 올라간다. 그래서 41 regs/thread에서는 &lt;b&gt;5 blocks&lt;/b&gt;, &lt;b&gt;40 warps&lt;/b&gt;가 resident하고, occupancy는 40/48 = 0.833이 된다. 이 값은 슬라이드의 TB 5 / W 40 (Occupancy = 0.833)와 정확히 맞아&lt;/p&gt;
&lt;p data-end=&quot;3730&quot; data-start=&quot;3446&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;3730&quot; data-start=&quot;3446&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;3730&quot; data-start=&quot;3446&quot; data-ke-size=&quot;size16&quot;&gt;--&amp;gt; 256단위로 배정하는건 어디 ?&amp;nbsp;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1800&quot; data-origin-height=&quot;1200&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Sl79M/dJMcajhqcYA/HqbpU8zW8IQC7DQgtFChl0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Sl79M/dJMcajhqcYA/HqbpU8zW8IQC7DQgtFChl0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Sl79M/dJMcajhqcYA/HqbpU8zW8IQC7DQgtFChl0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSl79M%2FdJMcajhqcYA%2FHqbpU8zW8IQC7DQgtFChl0%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;1800&quot; height=&quot;1200&quot; data-origin-width=&quot;1800&quot; data-origin-height=&quot;1200&quot;/&gt;&lt;/span&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;&lt;span&gt;&lt;span&gt;Register allocation unit size -&amp;nbsp; 256 &lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Register allocation granularity - warp&amp;nbsp;&lt;/span&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;&amp;nbsp;&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;warp 단위&lt;/b&gt;로 할당된다 (thread 단위가 아님)&lt;/li&gt;
&lt;li&gt;할당할 때 &lt;b&gt;256개 단위&lt;/b&gt;로 올림해서 배정한다&amp;nbsp;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;b&gt;① 블록 크기 제한&lt;/b&gt;&lt;b&gt;② 레지스터 제한&lt;/b&gt; &amp;larr; 여기가 핵심41&amp;times;32 = 1312인데, 256 단위로 올림하니까 &lt;b&gt;1536&lt;/b&gt;이 됨. reg=40일 때는 1280이었는데, 1개 늘었을 뿐인데 256 올라감.4 단위로 내림하니까 42&amp;rarr;&lt;b&gt;40&lt;/b&gt;.&lt;b&gt;③ Shared Memory 제한&lt;/b&gt;&lt;b&gt;④ 최종 결과&lt;/b&gt;
&lt;div&gt;제한 요소최대 TB 수
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;블록/워프 크기&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;레지스터&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;5&lt;/b&gt; &amp;larr; 병목&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Shared Memory&lt;/td&gt;
&lt;td&gt;32&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;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;angelscript&quot; style=&quot;color: #14181f;&quot;&gt;&lt;code&gt;TB = 5개
Warps = 5 &amp;times; 8 = 40
Occupancy = 40 / 48 = 0.833 (83%)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
reg=40 vs reg=41 비교레지스터 &lt;b&gt;1개&lt;/b&gt; 차이인데, 256 단위 할당(allocation unit size) 때문에 warp당 256개가 추가로 잡히면서 TB가 하나 빠지고, occupancy가 17%나 떨어지는 거야. 이게 계단식 변화의 대표적인 예시.&lt;/li&gt;
&lt;li&gt;reg=40reg=41
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;warp당 할당 레지스터&lt;/td&gt;
&lt;td&gt;1280&lt;/td&gt;
&lt;td&gt;&lt;b&gt;1536&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SM 최대 warp&lt;/td&gt;
&lt;td&gt;48&lt;/td&gt;
&lt;td&gt;&lt;b&gt;40&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;최대 TB&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;&lt;b&gt;5&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Occupancy&lt;/td&gt;
&lt;td&gt;&lt;b&gt;1.0&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;0.833&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/li&gt;
&lt;li&gt;세 제한 중 가장 작은 값이 적용됨:&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;angelscript&quot; style=&quot;color: #14181f;&quot;&gt;&lt;code&gt;MySharedMemPerBlock = CEILING(2048, 128) = 2048
최대 TB 수 = FLOOR(65536/2048, 1) = 32  &amp;larr; 여유로움&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;angelscript&quot; style=&quot;color: #14181f;&quot;&gt;&lt;code&gt;레지스터 기준 최대 TB 수 = FLOOR(40/8, 1) &amp;times; FLOOR(65536/65536, 1)
                         = 5 &amp;times; 1 
                         = 5&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;angelscript&quot; style=&quot;color: #14181f;&quot;&gt;&lt;code&gt;SM 전체 최대 warp 수 = FLOOR(65536 / 1536, 4) 
                      = FLOOR(42.67, 4) 
                      = 40&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;angelscript&quot; style=&quot;color: #14181f;&quot;&gt;&lt;code&gt;warp당 레지스터 할당량 = CEILING(41 &amp;times; 32, 256) 
                       = CEILING(1312, 256) 
                       = 1536&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;angelscript&quot; style=&quot;color: #14181f;&quot;&gt;&lt;code&gt;warps/block = CEILING(256/32, 1) = 8
블록 수 제한 = MIN(16, FLOOR(48/8, 1)) = MIN(16, 6) = 6&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;기본 조건:&lt;/b&gt; TB size 16&amp;times;16 = 256 threads, 8 warps/TB, smem 2048 bytes, CC 8.6&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1809&quot; data-origin-height=&quot;1179&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eLaUDj/dJMcacJqZqw/iC5Bf90ajfKE4keCkibQ10/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eLaUDj/dJMcacJqZqw/iC5Bf90ajfKE4keCkibQ10/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eLaUDj/dJMcacJqZqw/iC5Bf90ajfKE4keCkibQ10/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeLaUDj%2FdJMcacJqZqw%2FiC5Bf90ajfKE4keCkibQ10%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;1809&quot; height=&quot;1179&quot; data-origin-width=&quot;1809&quot; data-origin-height=&quot;1179&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1809&quot; data-origin-height=&quot;1179&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bcPnaD/dJMcacJqZqr/NfQL5mwQLGCeaDvOUomuLk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bcPnaD/dJMcacJqZqr/NfQL5mwQLGCeaDvOUomuLk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bcPnaD/dJMcacJqZqr/NfQL5mwQLGCeaDvOUomuLk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbcPnaD%2FdJMcacJqZqr%2FNfQL5mwQLGCeaDvOUomuLk%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;1809&quot; height=&quot;1179&quot; data-origin-width=&quot;1809&quot; data-origin-height=&quot;1179&quot;/&gt;&lt;/span&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;역시 그저 계산과 공식인 영역이라. 나중에 필요할때 참고하면 된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중요한건 warp 을 얼마나 잘 배정할것이냐. 이걸 어떻게 분배해야 적당한 값으로 최대의 효율을 낼 수 있는가의 문제이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>GPGPU</category>
      <author>Kim_sang_hyeob</author>
      <guid isPermaLink="true">https://ksh0416.tistory.com/161</guid>
      <comments>https://ksh0416.tistory.com/161#entry161comment</comments>
      <pubDate>Wed, 25 Mar 2026 17:24:23 +0900</pubDate>
    </item>
    <item>
      <title>GPGPU 총정리 - (2)</title>
      <link>https://ksh0416.tistory.com/160</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;What is CUDA ?&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;956&quot; data-origin-height=&quot;616&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b5VS5D/dJMcacvABMf/qdJeSTA9SQpLPQ8gkvLQEk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b5VS5D/dJMcacvABMf/qdJeSTA9SQpLPQ8gkvLQEk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b5VS5D/dJMcacvABMf/qdJeSTA9SQpLPQ8gkvLQEk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb5VS5D%2FdJMcacvABMf%2FqdJeSTA9SQpLPQ8gkvLQEk%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;646&quot; height=&quot;416&quot; data-origin-width=&quot;956&quot; data-origin-height=&quot;616&quot;/&gt;&lt;/span&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;CUDA 란 무엇인가 ?&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;NVIDIA GPU의 병렬 연산 엔진을 활용하기 위한 범용 병렬 컴퓨팅 플랫폼이자 프로그래밍 모델이다.&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;- GPU 하드웨어 : 진짜 계산하는 기계&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- CUDA : 그 기계를 프로그래머가 쓰게 해주는 규칙 ( api , 컴파일 방식,&amp;nbsp; 모델 등등 )&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간단하게 cuda 를 계산 장치로 다루는 방식 정도로 이해하면 될 것 같다.&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;CUDA 가 왜필요한가 ?&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;GPU 는 많은 수의 연산 유닛으로 같은 종류의 계싼을 엄청 동시에 많이 처리하는데 강하다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CUDA 는 이런 상황에서 &quot; 이 많은 데이터 각각에 대해 같은 연산을 해라 &quot; 를 gpu 에게 효율적으로 시키는 방식(모델) 이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본적으로 CUDA 는 큰 문제 를 아주 작은 작업(task)로 쪼개고 그걸 수많은 thread 로 병렬 처리한다.&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Driver API vs Runtime API&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;엄청 중요한건 아니고 Driver API 는 더 low-levl 이고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Runtime API 는 상대적으로 high levl 이다. 보통 cuda 프로그래밍할때 runtime api 를 쓰는걸로 알고 있다.&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;960&quot; data-origin-height=&quot;613&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nGohE/dJMcafy4AVV/zKLFGnsuTRvBNp863N1y10/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nGohE/dJMcafy4AVV/zKLFGnsuTRvBNp863N1y10/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nGohE/dJMcafy4AVV/zKLFGnsuTRvBNp863N1y10/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnGohE%2FdJMcafy4AVV%2FzKLFGnsuTRvBNp863N1y10%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;714&quot; height=&quot;456&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;613&quot;/&gt;&lt;/span&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;Compute Cability (CC) 란?&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;GPU의 세대/기능 수준 표시정도로 알면된다.&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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&amp;lt; 용어정리 &amp;gt;&amp;nbsp;&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;961&quot; data-origin-height=&quot;628&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/blgCPJ/dJMcab4t46K/78aewKfLqj0iTPaiKkPdZk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/blgCPJ/dJMcab4t46K/78aewKfLqj0iTPaiKkPdZk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/blgCPJ/dJMcab4t46K/78aewKfLqj0iTPaiKkPdZk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FblgCPJ%2FdJMcab4t46K%2F78aewKfLqj0iTPaiKkPdZk%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;774&quot; height=&quot;506&quot; data-origin-width=&quot;961&quot; data-origin-height=&quot;628&quot;/&gt;&lt;/span&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;&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;1. Kernel&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GPU 에서 실행되는 &quot;함수&quot; 이다.&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;CUDA 에서는 특별한 함수 하나를 GPU 에 올려서 , 그 함수를 엄청 많은 thread 가 동시에 실행하게 한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;거기서 &quot;함수&quot; 가 kernel 이다.&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;pre id=&quot;code_1773321147910&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;__global__ void add(float* A, float* B, float* C) {
    int i = ...
    C[i] = A[i] + B[i];
}&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;여기서 add 함수 가 kernel 이다.&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;그래서 커널 하나를 실행한다는건 이 연산을 GPU 의 많은 thread 에게 동시에 시키는거라고 보면 된다.&amp;nbsp;&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;268&quot; data-origin-height=&quot;223&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cFNP9o/dJMcagdF29Y/vSyMUhQqZMm8xX2zkuMlZK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cFNP9o/dJMcagdF29Y/vSyMUhQqZMm8xX2zkuMlZK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cFNP9o/dJMcagdF29Y/vSyMUhQqZMm8xX2zkuMlZK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcFNP9o%2FdJMcagdF29Y%2FvSyMUhQqZMm8xX2zkuMlZK%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;268&quot; height=&quot;223&quot; data-origin-width=&quot;268&quot; data-origin-height=&quot;223&quot;/&gt;&lt;/span&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. Thread&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;thread는 커널의 한 실행 인스턴스, 혹은 작업 한 개를 맡는 추상적 실행 단위다.&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;task 를 thread 라고 하고 , 실제로 cuda 에서 각각의 data element 에 대입이 되는 느낌이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;( 다만 모든 문제에서 무조건 data element 당 1:1 인 것은 아니고 .. )&amp;nbsp;&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;/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;CUDA thread&lt;/b&gt; = 프로그래머가 쓰는 &lt;b&gt;논리적 실행 단위&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;CUDA core / SM / warp scheduler&lt;/b&gt; = GPU 안의 &lt;b&gt;물리적 실행 자원&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, thread는 &lt;b&gt;&amp;ldquo;일감 하나&amp;rdquo;를 표현하는 단위&lt;/b&gt;에 가깝다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 비유로 먼저 잡자&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 공장에 기계 10대가 있는데, 처리해야 할 박스는 10,000개라고 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;박스 10,000개&lt;/b&gt; = CUDA threads&lt;/li&gt;
&lt;li&gt;&lt;b&gt;실제 기계 10대&lt;/b&gt; = 물리적인 연산 자원(CUDA cores 등)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;박스가 기계보다 훨씬 많아도 괜찮다.&lt;br /&gt;기계가 박스를 한 번에 조금씩 처리하고, 다음 박스를 또 처리하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CUDA도 비슷하다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;thread를 수천, 수만, 수백만 개 만들어도&lt;/li&gt;
&lt;li&gt;실제 GPU가 그걸 &lt;b&gt;한 번에 전부 물리적으로 동시에&lt;/b&gt; 돌리는 건 아니다&lt;/li&gt;
&lt;li&gt;가능한 만큼만 동시에 실행하고&lt;/li&gt;
&lt;li&gt;나머지는 순서대로 이어서 처리한다&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 그럼 thread는 &amp;ldquo;가짜&amp;rdquo;냐?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가짜라고 하면 좀 이상하고,&lt;br /&gt;&lt;b&gt;&amp;ldquo;논리적이다&amp;rdquo;&lt;/b&gt; 라고 하는 게 맞다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 thread는 실제로 의미가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 thread는 자기만의:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;thread index&lt;/li&gt;
&lt;li&gt;register state&lt;/li&gt;
&lt;li&gt;program counter 같은 실행 문맥&lt;/li&gt;
&lt;li&gt;local 변수&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;를 가진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 그 thread 하나하나가 &lt;b&gt;독립된 물리 코어 하나&lt;/b&gt;에 대응되는 건 아니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 왜 &amp;ldquo;추상적 실행 단위&amp;rdquo;라고 부르냐?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;네가 CUDA 코드를 짤 때는 보통 이렇게 생각하잖아:&lt;/p&gt;
&lt;pre class=&quot;matlab&quot;&gt;&lt;code&gt;int i = blockIdx.x * blockDim.x + threadIdx.x;
C[i] = A[i] + B[i];
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 threadIdx.x가 다르면 각 thread가 다른 원소를 처리한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 프로그래머 입장에서는:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;0번 thread&lt;/li&gt;
&lt;li&gt;1번 thread&lt;/li&gt;
&lt;li&gt;2번 thread&lt;/li&gt;
&lt;li&gt;...&lt;/li&gt;
&lt;li&gt;999999번 thread&lt;/li&gt;
&lt;/ul&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;프로그래밍 모델&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 하드웨어 입장에서는 이 많은 thread를 실제로는:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;warp(32개) 단위로 묶고&lt;/li&gt;
&lt;li&gt;SM 위에서&lt;/li&gt;
&lt;li&gt;스케줄러가 가능한 warp를 골라&lt;/li&gt;
&lt;li&gt;순차/병렬 섞어서 실행한다&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 &lt;b&gt;프로그래머가 보는 thread 세계&lt;/b&gt;와&lt;br /&gt;&lt;b&gt;하드웨어가 실제 처리하는 방식&lt;/b&gt;이 다르다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. CPU thread랑도 조금 다르다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CPU에서 thread라고 하면 보통:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;OS가 관리하고&lt;/li&gt;
&lt;li&gt;스택도 있고&lt;/li&gt;
&lt;li&gt;context switch 비용도 있고&lt;/li&gt;
&lt;li&gt;꽤 무거운 실행 단위&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 느낌이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CUDA thread는 훨씬 가볍고, 훨씬 많이 만들 수 있고, GPU용으로 설계된 thread다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 CUDA thread를 보고&lt;br /&gt;&amp;ldquo;이게 OS thread 같은 건가?&amp;rdquo;&lt;br /&gt;라고 생각하면 안 된다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. 그러면 실제 물리적 실체는 뭐냐?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CUDA에서 실제 물리적 실체에 더 가까운 건 이런 것들이다.&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;SM&lt;/b&gt;: block/warp를 실행하는 큰 하드웨어 단위&lt;/li&gt;
&lt;li&gt;&lt;b&gt;warp scheduler&lt;/b&gt;: ready된 warp를 고르는 스케줄러&lt;/li&gt;
&lt;li&gt;&lt;b&gt;CUDA core&lt;/b&gt;: 산술 연산 수행 유닛&lt;/li&gt;
&lt;li&gt;&lt;b&gt;register file / shared memory&lt;/b&gt;: thread들이 쓰는 실제 저장 자원&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 thread 자체가 금속으로 된 어떤 부품인 건 아니고,&lt;br /&gt;&lt;b&gt;그 thread를 실행시키기 위한 상태와 연산 자원은 실제 하드웨어에 존재한다&lt;/b&gt;고 보면 된다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. 아주 중요: thread와 core는 1:1이 아니다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이게 핵심이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;많이들 처음에 이렇게 생각한다:&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;thread 1024개 만들었으면 core도 1024개 필요하나?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;thread 1024개 생성&lt;/li&gt;
&lt;li&gt;block 256개씩 4 block&lt;/li&gt;
&lt;li&gt;각 block은 8 warps&lt;/li&gt;
&lt;li&gt;GPU는 available한 SM들에서 이 warp들을 차례로 실행&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 thread가 많다는 건&lt;br /&gt;&lt;b&gt;할 일이 많다&lt;/b&gt;는 뜻이지,&lt;br /&gt;그 개수만큼 물리 코어가 생긴다는 뜻이 아니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;7. 그럼 thread는 어디에 &amp;ldquo;존재&amp;rdquo;하냐?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;좋은 질문이다.&lt;br /&gt;정확히는 thread는 **실행 상태(context)**의 형태로 존재한다고 보면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 thread는 실행 중에 필요한 상태를 가진다:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;지금 몇 번째 instruction까지 왔는지&lt;/li&gt;
&lt;li&gt;어떤 register 값을 갖고 있는지&lt;/li&gt;
&lt;li&gt;자기 thread index가 뭔지&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 상태는 GPU 내부 자원에 유지된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 완전히 허상은 아니다.&lt;br /&gt;다만 &lt;b&gt;&amp;ldquo;하드웨어 부품 하나&amp;rdquo;로 존재하는 건 아니다.&lt;/b&gt;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;8. 한 줄로 정리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;네 질문에 가장 직접적으로 답하면:&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;CUDA thread는 물리 코어 같은 실체가 아니라, GPU 위에서 실행될 작업을 표현하는 논리적 실행 단위다.&lt;/b&gt;&lt;br /&gt;다만 실행될 때 필요한 상태(register, PC 등)는 실제 하드웨어 자원에 저장된다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;9. 더 직관적으로 구분&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 구분하면 된다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;[논리적 개념]
thread -&amp;gt; block -&amp;gt; grid

[물리적 하드웨어]
warp scheduler -&amp;gt; SM -&amp;gt; CUDA cores / registers / shared memory
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;thread/block/grid&lt;/b&gt;로 코드를 짠다&lt;/li&gt;
&lt;li&gt;GPU는 그걸 &lt;b&gt;warp/SM 중심으로 실제 실행&lt;/b&gt;한다&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;10. 네가 지금 딱 이해해야 할 포인트&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금 단계에서는 이것만 정확히 잡으면 된다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;A. thread는 &amp;ldquo;일 하나&amp;rdquo;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예: 벡터 덧셈에서 원소 하나 담당&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;B. thread는 물리 코어가 아님&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제 하드웨어 자원 위에 스케줄링됨&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;C. 실제 하드웨어는 warp 단위로 움직임&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;thread 32개가 warp로 묶여 처리됨&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;D. 그래서 CUDA는 엄청 많은 thread를 만들어도 됨&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GPU가 알아서 나눠서 처리함&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원하면 내가 다음 답변에서&lt;br /&gt;&lt;b&gt;&amp;ldquo;logical thread &amp;harr; physical warp/SM 관계&amp;rdquo;를 ASCII 그림으로&lt;/b&gt; 아주 직관적으로 다시 보여주겠다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. Thread Block&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;block 은 thread 를 여러 묶음으로 묶은 그룹이다 ( 말이 이상하네 )&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;그래서 이 block 단위로 GPU 가 배치하고 관리한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;block 안의 thread 들은 같은 블럭에 속해 있을 뿐만 아니라&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;b&gt;shared memory 공유할 수 있고 ( 중요 )&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 동기화도 가능하다 ( 물론 이것도 block 내부에서만 ! )&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만 , 다른 block 끼리는 독립적으로 움직인다.&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;4. Grid&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;grid 는 전체 block 의 집합이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 kernel 한번으로 생성되는 block 의 모음으로 보면 되겠다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;( grid = 이번 kernel(함수) 실행 전체 규모 )&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;5. warp&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- warp 는 trehad block 이 다시 쪼개진 더 작은 처리 단위이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- CUDA 에서는 32 thread로 구성되고 , GPU 의 기본 processing unit 이다.&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;그래서 예를들어서 block이 256 thread 라면&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;256 / 32 = 8개의 warp 생김.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GPU 는&amp;nbsp; warp 단위로 스케줄링하고 실행한다.&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;가장 중요한건 thread block 을 어떻게 넣느냐 보다 warp 를 지금 내가 어떻게 다루고 있는지가 개발자가 가장 신경써야 하는 부분이라고 한다.&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;[ 이 5개는 자주 헷갈리기도 하고 , 여기서 용어 관계를 정리를 잘 해야 하므로 외워두고 가도록 하자. ]&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-end=&quot;7831&quot; data-start=&quot;7792&quot; data-ke-size=&quot;size16&quot;&gt;C[i] = A[i] + B[i]를 N개 원소에 대해 한다고 하자.&lt;/p&gt;
&lt;p data-end=&quot;7847&quot; data-start=&quot;7833&quot; data-ke-size=&quot;size16&quot;&gt;CUDA 식으로 생각하면:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;8024&quot; data-start=&quot;7849&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;7882&quot; data-start=&quot;7849&quot; data-section-id=&quot;1jjrfpe&quot;&gt;&lt;b&gt;kernel&lt;/b&gt;: &amp;ldquo;원소 하나 더하라&amp;rdquo;는 GPU 함수&lt;/li&gt;
&lt;li data-end=&quot;7911&quot; data-start=&quot;7883&quot; data-section-id=&quot;d4b7j9&quot;&gt;&lt;b&gt;thread&lt;/b&gt;: 각 원소 i 하나 담당&lt;/li&gt;
&lt;li data-end=&quot;7942&quot; data-start=&quot;7912&quot; data-section-id=&quot;1ft5cm3&quot;&gt;&lt;b&gt;block&lt;/b&gt;: thread 256개 같은 묶음&lt;/li&gt;
&lt;li data-end=&quot;7981&quot; data-start=&quot;7943&quot; data-section-id=&quot;v0yk4q&quot;&gt;&lt;b&gt;grid&lt;/b&gt;: 전체 N개 원소를 덮도록 필요한 block 전체&lt;/li&gt;
&lt;li data-end=&quot;8024&quot; data-start=&quot;7982&quot; data-section-id=&quot;4inon1&quot;&gt;&lt;b&gt;warp&lt;/b&gt;: block 안에서 32개 thread씩 하드웨어가 처리&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;8051&quot; data-start=&quot;8026&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어 N=1024, block=256이면&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;8117&quot; data-start=&quot;8053&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;8070&quot; data-start=&quot;8053&quot; data-section-id=&quot;1yx7wqp&quot;&gt;총 thread = 1024&lt;/li&gt;
&lt;li data-end=&quot;8084&quot; data-start=&quot;8071&quot; data-section-id=&quot;13k9vv4&quot;&gt;block 수 = 4&lt;/li&gt;
&lt;li data-end=&quot;8117&quot; data-start=&quot;8085&quot; data-section-id=&quot;3356w8&quot;&gt;각 block 안 warps = 256 / 32 = 8&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;&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;973&quot; data-origin-height=&quot;631&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nZ5Hb/dJMcac96VlT/fIx9SFJ2kzQQLgq0TX42bK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nZ5Hb/dJMcac96VlT/fIx9SFJ2kzQQLgq0TX42bK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nZ5Hb/dJMcac96VlT/fIx9SFJ2kzQQLgq0TX42bK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnZ5Hb%2FdJMcac96VlT%2FfIx9SFJ2kzQQLgq0TX42bK%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;670&quot; height=&quot;435&quot; data-origin-width=&quot;973&quot; data-origin-height=&quot;631&quot;/&gt;&lt;/span&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;가볍게 보고 넘어가자.&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;GPU를 Streaming Multiprocessor(SM) 들의 배열로 보고, multithreaded program을 독립적으로 실행 가능한 block들로 나눔으로써, SM이 많은 GPU에서는 더 빨리 실행되도록 설계된 모델이라고 설명한다. 이걸 scalable programming model이라고 부른다.&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;이렇게 구성이 되면 오른쪽 그림처럼 SM 의 수가 달라져도 프로그램이 GPU 크기에 맞춰 자동으로 스케일 된다고 한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;( 교수님 피셜로는 사실 이건 이상적인거고 엔비디아에서 아마 GPU 마다 적당한 최적화는 따로 한다고 하신다. )&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;p data-ke-size=&quot;size16&quot;&gt;&quot;block 끼리 독립적이여야 한다&quot;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래야 어떤 block 을 먼저 실행하든 탈이 나지 않는다.&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;그래서 block 은 독립적으로 실행된다는 사실을 한번더 짚고 넘어가는게 좋겠다.&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;&amp;nbsp;&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;CUDA Execution Model&amp;nbsp;&lt;/h2&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;971&quot; data-origin-height=&quot;639&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bUSzJd/dJMcajnQztJ/b7i2UdxSYAVFjvubfwHnj0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bUSzJd/dJMcajnQztJ/b7i2UdxSYAVFjvubfwHnj0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bUSzJd/dJMcajnQztJ/b7i2UdxSYAVFjvubfwHnj0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbUSzJd%2FdJMcajnQztJ%2Fb7i2UdxSYAVFjvubfwHnj0%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;707&quot; height=&quot;465&quot; data-origin-width=&quot;971&quot; data-origin-height=&quot;639&quot;/&gt;&lt;/span&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;강의 자료 설명 그대로 보통 task 가 CUDA core 보다 훨씬 많다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그니까 task 1 개 = CUDA core 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;-&amp;gt; 각 tasks 들을 논리적 thread 로 표현해두고 -&amp;gt; GPU 가 이를 겹쳐서 처리하도록 하자.&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;&amp;nbsp;그래서 문제의 각 작업 단위를 CUDA thread 라는 &lt;b&gt;추상적인 실행 단위&lt;/b&gt;로 표현 한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;( thread 는 물리 코어가 아니라 논리 작업 단위임 )&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;972&quot; data-origin-height=&quot;577&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bGEthG/dJMcafTmLOR/XLoHhAeHWVukR6Uho4Btv1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bGEthG/dJMcafTmLOR/XLoHhAeHWVukR6Uho4Btv1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bGEthG/dJMcafTmLOR/XLoHhAeHWVukR6Uho4Btv1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbGEthG%2FdJMcafTmLOR%2FXLoHhAeHWVukR6Uho4Btv1%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;772&quot; height=&quot;458&quot; data-origin-width=&quot;972&quot; data-origin-height=&quot;577&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제는 잘 알고 있지만 , thread 를 그냥 하나씩 두는게 아니라 block 으로 묶는다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전체 CUDA thread 들을 동일한 갯수의 thread block 으로 분할한다.&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;전체 thread 수 : 2 ^ 24&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;thread per block = 2 ^ 8 ( 256 ) 이라고 가정하면&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;총 block 수 = 2 ^ 24 / 2 ^ 8 = 2 ^ 16 개의 thread block 이 하나의 grid 안에 들어가 있는 것이다.&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;b&gt;Kernel lauch 란 ?&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Host (cpu) 에서 kernel 수행 명령을 내린다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;당연하게도 cpu 가 GPU 에게 일을 지시하는 부분이 있을 것이고 이게 그부분이다.&amp;nbsp;&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;span&gt;CombineTwoArraysKernel&lt;/span&gt;&lt;span style=&quot;color: #14181f;&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #14181f;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;dimGrid&lt;/span&gt;&lt;span style=&quot;color: #2b303b;&quot;&gt;,&lt;/span&gt;&lt;span&gt; dimBlock&lt;/span&gt;&lt;span style=&quot;color: #14181f;&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #14181f;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #2b303b;&quot;&gt;(&lt;/span&gt;&lt;span&gt;d_A&lt;/span&gt;&lt;span style=&quot;color: #2b303b;&quot;&gt;,&lt;/span&gt;&lt;span&gt; d_B&lt;/span&gt;&lt;span style=&quot;color: #2b303b;&quot;&gt;,&lt;/span&gt;&lt;span&gt; d_C&lt;/span&gt;&lt;span style=&quot;color: #2b303b;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #2b303b;&quot;&gt;;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 이때 넘기는 정보는 두 가지다&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;(1) 커널 함수 이름 + 인자&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;(2) grid/block dimension. 이 한 줄이 GPU에 &quot;이 함수를 이 구조로 병렬 실행해라&quot;는 명령. &lt;/span&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;Combine... : GPU 에서 돌릴 함수 이름&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;dimGrid : block 이 몇개 필요한지&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;dimBlock : block 당 thread 를 몇개 둘껀지 ?&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;이런식으로 명령을 보통 준다. 그래서 host(cpu) 가 단순하게 커널(함수) 호출 하는게 아니라&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GPU 에서 어떤 구성을 할지 같이 넘겨주는 식이다.&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;&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;970&quot; data-origin-height=&quot;621&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/claxvG/dJMcafeNa8Q/TnQu20nuJPuCpQI8yk9gGK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/claxvG/dJMcafeNa8Q/TnQu20nuJPuCpQI8yk9gGK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/claxvG/dJMcafeNa8Q/TnQu20nuJPuCpQI8yk9gGK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FclaxvG%2FdJMcafeNa8Q%2FTnQu20nuJPuCpQI8yk9gGK%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;729&quot; height=&quot;467&quot; data-origin-width=&quot;970&quot; data-origin-height=&quot;621&quot;/&gt;&lt;/span&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;&amp;nbsp;&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;851&quot; data-origin-height=&quot;598&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Ol0AO/dJMcac3nbME/9EEoWw8O9yaYm6T4ZhgtI1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Ol0AO/dJMcac3nbME/9EEoWw8O9yaYm6T4ZhgtI1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Ol0AO/dJMcac3nbME/9EEoWw8O9yaYm6T4ZhgtI1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOl0AO%2FdJMcac3nbME%2F9EEoWw8O9yaYm6T4ZhgtI1%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;698&quot; height=&quot;490&quot; data-origin-width=&quot;851&quot; data-origin-height=&quot;598&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SM 은 무한히 많은 block 을 가질수는 없다.&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;SM 에 배정할 수 있는 thread block 수가 제한이 걸리는데 대략 4가지 정도 이유를 설명해 보겠다.&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;1. SM 당 최대 resident block 수&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하드웨어 마다 SM 당 최대 몇개의 block 을 가질 수 있는지 상한선이 정해져 있다.&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;2. SM 당 최대 thread ( resident warp ) 수&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SM 당 최대 48 warp 를 가질 수 있다 ( 숫자는 변동 가능 )&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;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;block size = 256 / threads = 8 warps &lt;br /&gt;&amp;rarr;&amp;nbsp;48&amp;nbsp;/&amp;nbsp;8&amp;nbsp;=&amp;nbsp;6&amp;nbsp;blocks&amp;nbsp;가능&amp;nbsp;(warp&amp;nbsp;제한) &lt;br /&gt;&amp;rarr;&amp;nbsp;min(6,&amp;nbsp;16)&amp;nbsp;=&amp;nbsp;6&amp;nbsp;blocks &lt;br /&gt;&lt;br /&gt;block size = 64 /&amp;nbsp; threads = 2 warps&amp;nbsp;&amp;nbsp; &lt;br /&gt;&amp;rarr;&amp;nbsp;48&amp;nbsp;/&amp;nbsp;2&amp;nbsp;=&amp;nbsp;24&amp;nbsp;blocks&amp;nbsp;가능&amp;nbsp;(warp&amp;nbsp;제한) &lt;br /&gt;&amp;rarr;&amp;nbsp;min(24,&amp;nbsp;16)&amp;nbsp;=&amp;nbsp;16&amp;nbsp;blocks&amp;nbsp;(block&amp;nbsp;상한에&amp;nbsp;걸림) &lt;br /&gt;&lt;br /&gt;block size = 1024 / threads = 32 warps &lt;br /&gt;&amp;rarr;&amp;nbsp;48&amp;nbsp;/&amp;nbsp;32&amp;nbsp;=&amp;nbsp;1&amp;nbsp;block&amp;nbsp;(warp&amp;nbsp;제한) &lt;br /&gt;&amp;rarr;&amp;nbsp;min(1,&amp;nbsp;16)&amp;nbsp;=&amp;nbsp;1&amp;nbsp;block&lt;/p&gt;
&lt;/div&gt;
&lt;/div&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;3. Register 용량&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SM 당 레지스터 파일은 64K 32-bit 로 고정이 되어 있는데 , 이걸 SM 에 올라간 모든 thread 들이 나눠 써야한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;커널이 컴파일되면 thread 당 레지스터 사용량이 결정되고 , 이게 block 수를 제한할 수 있다.&amp;nbsp;&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;thread당&amp;nbsp;레지스터&amp;nbsp;=&amp;nbsp;40개 &lt;br /&gt;block&amp;nbsp;size&amp;nbsp;=&amp;nbsp;256&amp;nbsp;threads &lt;br /&gt;&amp;rarr;&amp;nbsp;block&amp;nbsp;하나가&amp;nbsp;필요한&amp;nbsp;레지스터&amp;nbsp;=&amp;nbsp;256&amp;nbsp;&amp;times;&amp;nbsp;40&amp;nbsp;=&amp;nbsp;10,240개 &lt;br /&gt;&amp;rarr;&amp;nbsp;65,536&amp;nbsp;/&amp;nbsp;10,240&amp;nbsp;=&amp;nbsp;6.4&amp;nbsp;&amp;rarr;&amp;nbsp;6&amp;nbsp;blocks&amp;nbsp;(내림) &lt;br /&gt;&lt;br /&gt;thread당&amp;nbsp;레지스터&amp;nbsp;=&amp;nbsp;96개&amp;nbsp;(Occupancy&amp;nbsp;Calculator&amp;nbsp;예시) &lt;br /&gt;block&amp;nbsp;size&amp;nbsp;=&amp;nbsp;256&amp;nbsp;threads &lt;br /&gt;&amp;rarr;&amp;nbsp;256&amp;nbsp;&amp;times;&amp;nbsp;96&amp;nbsp;=&amp;nbsp;24,576개 &lt;br /&gt;&amp;rarr;&amp;nbsp;65,536&amp;nbsp;/&amp;nbsp;24,576&amp;nbsp;=&amp;nbsp;2.67&amp;nbsp;&amp;rarr;&amp;nbsp;2&amp;nbsp;blocks&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 번째 경우 레지스터 때문에 2개 block밖에 못 올려. warp로는 16개(2&amp;times;8)뿐이니까 occupancy = 16/48 = 33%. 슬라이드 24의 Occupancy Calculator에서 &quot;Limited by Registers per Multiprocessor&quot; 라고 빨간색으로 뜨는 게 바로 이 상황이야.&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;thread당 레지스터를 줄이면 더 많은 block이 올라가지만, 레지스터가 부족하면 &lt;b&gt;register spill&lt;/b&gt; &amp;mdash; 레지스터에 못 담는 변수가 local memory(실제로는 global memory)로 넘어가서 성능 급감. 그래서 이것도 trade-off야.&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;4. Shared Memory 용량&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SM 당 shared memory 도 정해져있다 (당연하게도) . 그래서 이런 부분도 신경써야한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;shared memory 많이 쓰면 특정 부분의 최적화에 유리하지만 , shared memory 는 L1 Cache 와 같은 공간을 사용하는데 이때문에 resident block 수가 줄어 들 수 있다 ( 3번 참고 ).&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;shared memory 를 안쓰는 경우에 occupancy 는 높아지지만 , 반대로 global memory 접근이 많아져서 이때는 bandwidth bottleneck이 심해진다.&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;실제 SM 에 올라가는 block 수는 4가지 중에 가장 작은 값으로 결정된다고 보면 된다.&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;resident&amp;nbsp;blocks&amp;nbsp;=&amp;nbsp;min(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;하드웨어&amp;nbsp;max&amp;nbsp;block&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;larr;&amp;nbsp;①&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;max_warps&amp;nbsp;/&amp;nbsp;(block당&amp;nbsp;warp&amp;nbsp;수),&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;larr;&amp;nbsp;②&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;총&amp;nbsp;registers&amp;nbsp;/&amp;nbsp;(block당&amp;nbsp;register),&amp;larr;&amp;nbsp;③&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;총&amp;nbsp;shared_mem&amp;nbsp;/&amp;nbsp;(block당&amp;nbsp;smem)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;larr;&amp;nbsp;④&lt;br /&gt;)&lt;/p&gt;
&lt;/div&gt;
&lt;/div&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;942&quot; data-origin-height=&quot;541&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/G7JKA/dJMcahRap5u/gzcIKKCMoI5lSrrUHKdjD1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/G7JKA/dJMcahRap5u/gzcIKKCMoI5lSrrUHKdjD1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/G7JKA/dJMcahRap5u/gzcIKKCMoI5lSrrUHKdjD1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FG7JKA%2FdJMcahRap5u%2FgzcIKKCMoI5lSrrUHKdjD1%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;792&quot; height=&quot;455&quot; data-origin-width=&quot;942&quot; data-origin-height=&quot;541&quot;/&gt;&lt;/span&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;Thread Blcok Processing&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;계에속 설명 했듯이 block 은 다시 warp 단위로 쪼개진다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;block 이 SM 에 올라가도 실제 처리 단위는 &quot;warp&quot; 이다.&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;서로 다른 block 의 warp 가 섞여서 처리될 수 있다는 점이다.&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;한 SM 안에 여러 block 이 올라올 수 있으므로 , 서로 다른 block 에서 생성된 warp 들이 혼재되어서 처리될 수 있다.&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;예를들어서 한 SM 안에 block 0 , 1 이 resident 하다면 , warp scheduler 는 이 둘을 섞어서 실행할 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만,&amp;nbsp; 같은 block 안의 warp 도 &quot;순서&quot; 를 지정하는 것은 불가능하다. 이는 스케줄러가 알아서 처리하는 부분이다.&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;또 warp 간 &quot;자동 동기화&quot; 는 없다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만 같은 block 내부의 warp 끼리는 shared memory 를 통해서 동기화가 가능하게 설정할 수 는 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단 , 절대로 &quot; block 간 &quot; 동기화는 이루어 지지 않는다. 이는 cuda 프로그래밍 철칙에 어긋난다.&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;&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;984&quot; data-origin-height=&quot;633&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lFkby/dJMcajalDgA/atd8pJYjrxjjQm4PNK8KkK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lFkby/dJMcajalDgA/atd8pJYjrxjjQm4PNK8KkK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lFkby/dJMcajalDgA/atd8pJYjrxjjQm4PNK8KkK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlFkby%2FdJMcajalDgA%2Fatd8pJYjrxjjQm4PNK8KkK%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;728&quot; height=&quot;468&quot; data-origin-width=&quot;984&quot; data-origin-height=&quot;633&quot;/&gt;&lt;/span&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;&quot; warp 가 GPU 의 가장 기본적인 SIMT processing unit &quot; 이라는 점이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리가 CUDA 코드를 thread 기준으로 작성하더라도 , 하드웨어가 실제로 잡아서 실행을 하는 단위는 warp 이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 이 warp 를 얼마나 잘 활용하느냐가 cuda 프로그래밍에서 중요한 포인트가 될 것이다.&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;그림을 설명해 보자면 다음과 같다.&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;1. TB ( 0 , 1 ,,,, P )&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;thread block 이다. kernel launch 하면 grid 안에 block 들이 저런식으로 생길 것이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예 :&amp;nbsp; &lt;span&gt;kernel&lt;/span&gt;&lt;span&gt;&amp;lt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span&gt;gridDim&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;blockDim&lt;/span&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span&gt;(...);&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 gridDim 만큼 block 이 생기고 , blockDim 만큼 하나의 thread block 안에 thread 가 존재할 것이다.&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;다만 여기서 , block 들이 한번에 전부 동시에 실행 되는 것이 아니라&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일부가 SM 에 올라가고 , 나머지는 기다리는 식이다.&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;2. GPU scheduler&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 GPU scheduler 는 전체 grid 의 block 들을 보고 어떤 SM 에 올릴지 결정하는 역할이다.&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;여기서 중요한 부분은&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;block scheduling&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- block 은 SM 단위로 배정된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 어느 block 이 어떤 SM 으로 갈지는 프로그래머가 직접 정하지는 않는다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- block 은 독립적으로 실행된다.&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;&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;814&quot; data-origin-height=&quot;439&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ci97HA/dJMcaf6TmPU/6gv8AxYlwkL8YKPogdwPo1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ci97HA/dJMcaf6TmPU/6gv8AxYlwkL8YKPogdwPo1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ci97HA/dJMcaf6TmPU/6gv8AxYlwkL8YKPogdwPo1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fci97HA%2FdJMcaf6TmPU%2F6gv8AxYlwkL8YKPogdwPo1%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;593&quot; height=&quot;320&quot; data-origin-width=&quot;814&quot; data-origin-height=&quot;439&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. SM 내부&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;가장 오른쪽 박스가 SM ( streaming Multiprocessor ) 를 나타낸다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러가지 TB 가 있고 , 이중에서 TB 1 ,5 ,7 , 12 가 하나의 SM 에 들어왔다고 가정을 해보자.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 그 블록들이 resident 한 상태이다.&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;또 , 다른 thread block ( TB ) 에서 나온&amp;nbsp; WARP 들이 같은 SM 에 존재할 수 있다.&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;p data-ke-size=&quot;size16&quot;&gt;TB1 - w2&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TB5 - w2&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이게 왜 같이있지? 라고 생각했었고 warp 가 그러면 겹치는건가 ? 이렇게 생각해서 의아했었는데&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;이건 그냥 다른 thread block 에서 나온 warp 이다.&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;&quot;TB1 에 속한 WARP 2&quot; 이니까 TB5 에서도 그냥 똑같이 자른 것중에서 두번쨰 WARP 인것이다. ( 중요한건 아니다 )&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;[ warp pool ]&amp;nbsp; 이라는 개념이 여기 있는데 별건 아니고&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SM 안에 지금 resident 한 block 들이 있고 , 해당 블록들에서 나온 warp 들이 여러개 대기하고 있는데&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대기중인 warp 집합을 슬라이드 에서는 warp pool 로 표현한 것이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 나중에는 스케줄러가 이들 중에서 실행 가능한 warp 들을 골라서 연산 연산 하는 곳으로 보낸다 ( tensor / cuda&amp;nbsp; 아마도. )&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;&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;4. warp 내의 32 개 thread 들을 SIMT 형태로 처리&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;SIMT = &quot;Single Instruction , Multiple Threads&quot;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- warp 안에 32개 thread 있고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 안에 thread 들은 같은 instruction 따라가면서&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;그니까 명령은 같고 데이터만 같다고 이해하면 된다.&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;&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;5. Zero-cost context switching&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다시 중요한 내용이다. 한 processing block 에 배정된 warp 가 global memory 에 접근해야할 일이 있을 수 있다. 그러면 access 가 느리기 때문에 해당 warp 때문에 다른 처리를 못하고 기다려야 하는 상황이 올 수 있다. 따라서 이런 상태를 stall ( 대기 ) 라고 생각하면 된다.&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;이를 해결하고자 GPU 에서는 zero-cost context switching 을 한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CPU 에서는 thread 를 바꾸는게 상대적으로 무거운데&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GPU 에서는 애초에 SM 안에 warp 의 상태를 다 가지고 있기 때문에 context switching 의 cost 가 사실상 zero 에 가깝다 .&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;( program counter / register context / warp state - on chip 으로 가지고 있다. )&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;그래서 warp A 가 stall 상태에 있으면 바로 다른 warp 를 집어 넣으면 된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 zero-cost context switching 이라고 부른다.&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;b&gt; hiding memory latency with ALU operations&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 연결되는 이야기인데 , zero-cost context switiching 을 하니까 사실상 GPU 메모리는 latency 를 매우 잘 숨길 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;warp A 가 기다리는 동안 warp B 를 돌리고 , 다시 global memory access 하면 warp A 돌리고 ....&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;그래서 멀리서 보면 SM 이 쉬지않고 일 하는 것 처럼 보이고 이게 latency hiding 이다.&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;또 마지막으로 그래서 warp 를 많이 resident 하게 두면 좋은점이 이와 관련이 있는데 ,&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;warp 가 여러개 SM 에 존재하면 더 memory latency 를 가릴 여지가 커진다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 warp 를 얼마나 SM 에 잘 띄울 수 있냐 가 프로그래머에게 중요한 포인트이다.&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;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Warp Occupancy&amp;nbsp;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;978&quot; data-origin-height=&quot;646&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/UDGx6/dJMcadg1T9U/wXa77UdbiEkBCe8IYUK4NK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/UDGx6/dJMcadg1T9U/wXa77UdbiEkBCe8IYUK4NK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/UDGx6/dJMcadg1T9U/wXa77UdbiEkBCe8IYUK4NK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUDGx6%2FdJMcadg1T9U%2FwXa77UdbiEkBCe8IYUK4NK%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;630&quot; height=&quot;416&quot; data-origin-width=&quot;978&quot; data-origin-height=&quot;646&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;계속 반복되는 이야기 이지만 GPU 는 thread 하나씩 보는게 아니라 , warp ( 32개 thread 묶음 ) 단위로 보아야한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;occupancy 를 대략적으로 이야기 해보자면 &quot; SM 안에 지금 대기/상주 하고 있는 warp 가 얼마나 되는가 ? &quot; 에 대한 이야기 이다.&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;' 동시에 active한 warp 수 / 그 SM이 가질 수 있는 최대 warp 수 ' 이다.&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;그렇다면 occupancy 가 왜 중요한가 ?&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전에도 이야기 했지만 GPU 가 memory latency 를 숨기는 핵심 메커니즘이 warp 간 zero-cost context switching 인데 , warp 가 메모리 접근 ( 시간이 오래 걸리는 동작 ) 으로 stall 되면 , warp scheduler 가 바로 ready 상태의 warp 를 실행시켜서 파이프라인을 채운다. 근데 SM 에 올라와 있는 warp 수가 적으면 교체할 warp 가 줄어들고 , 그러면 poor instruction issue efficiency 가 된다.&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;occupancy 가 높으면 항상 좋은가 ?&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;ccupancy가 충분히 높아져서 latency hiding이 이미 되는 상태라면&lt;/b&gt;, 그 이상 더 높인다고 항상 좋은 게 아니다. 오히려 thread당 쓸 수 있는 resource가 줄어서 성능이 나빠질 수도 있다. ( 그니까 적절히 잘 설계 해야한다 . 적절하다는건 늘 어렵다 )&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;( Better Performance at Lower Occupancy 라는 논문을 참고해보자. -&amp;gt; 간단하게 이야기 해보면 낮은 occpancy 에서도 높은 성능을 달성했다는 뜻. occpancy 도 결국 latency hiding 의 한가지 수단이고 다른 방식도 고려해야한다는 주장을 펼친다. )&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;Occpancy 를 제한하는 것들&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;이부분도 이전에 설명이 어렴풋이 나왔는데 , 보통 핵심 제안 요소는 4가지이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2317&quot; data-start=&quot;2284&quot; data-section-id=&quot;ys3y3&quot;&gt;&lt;b&gt;max resident blocks per SM&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;2360&quot; data-start=&quot;2318&quot; data-section-id=&quot;qqe9ef&quot;&gt;&lt;b&gt;max resident threads / warps per SM&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;2384&quot; data-start=&quot;2361&quot; data-section-id=&quot;nqfcu3&quot;&gt;&lt;b&gt;registers per SM&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;2412&quot; data-start=&quot;2385&quot; data-section-id=&quot;1vfx3hq&quot;&gt;&lt;b&gt;shared memory per SM&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;2426&quot; data-start=&quot;2414&quot; data-ke-size=&quot;size16&quot;&gt;그리고 커널 쪽에서는:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2521&quot; data-start=&quot;2428&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2464&quot; data-start=&quot;2428&quot; data-section-id=&quot;143x40m&quot;&gt;&lt;b&gt;block size (threads per block)&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;2491&quot; data-start=&quot;2465&quot; data-section-id=&quot;10oq09n&quot;&gt;&lt;b&gt;registers per thread&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;2521&quot; data-start=&quot;2492&quot; data-section-id=&quot;dy0bim&quot;&gt;&lt;b&gt;shared memory per block&lt;/b&gt;&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;이 자원을 얼마나 쓰는지 중요하다.&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;thread block 은 warp 로 쪼개지는데 ( warp = 32 thread )&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;block 하나를 SM 에 올리면 해당 block 의 warp &quot;전체&quot; 가 SM 자리를 차지한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약에 애매하게 걸쳐서 warp 를 전체다 SM 에 한번에 올리지 못하는 경우에 아마 좋지 못한 성능을 낼 것이다.&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;반대로 block 이 너무 작아도 , block 갯수에 제한이 있기 때문에 충분히 채우지 못할 수도 있다.&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;&amp;nbsp;&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;Synchronization within a Thread Block&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;982&quot; data-origin-height=&quot;640&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/F9wwz/dJMcagx2fxm/jwfkDqqn5eEmKBnVqRU8ik/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/F9wwz/dJMcagx2fxm/jwfkDqqn5eEmKBnVqRU8ik/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/F9wwz/dJMcagx2fxm/jwfkDqqn5eEmKBnVqRU8ik/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FF9wwz%2FdJMcagx2fxm%2FjwfkDqqn5eEmKBnVqRU8ik%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;723&quot; height=&quot;471&quot; data-origin-width=&quot;982&quot; data-origin-height=&quot;640&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;b&gt;왜 synchronization 이 필요한가 ?&amp;nbsp;&lt;/b&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;GPU 는 Thread 를 아주 &quot;많이 &quot; &quot;동시&quot; 에 돌린다. 하지만 같은 thread block 안의 스레드들도 같은 속도로 실행이 보장되지는 않는다. 결국 thread 마다 제각기 다른 step 을 밟고 있을 확률이 매우매우 높고 이부분은 우리가 어떻게 할 수 있는 부분은 아니다 ( 스케줄러가 알아서 처리하는 부분이다. )&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 thread 간에 데이터를 주고 받으려면 &quot;동기화&quot; 가 필수로 필요하다.&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;Thread block 안에서 동기화 ( 같은 thread block 내의 warp 사이의 동기화를 이야기 하고 있다. )&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여전시 thread blocks 간 동기화는 다루지 않고 있다.&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;b&gt; __syncthreads(): Block-level Barrier &lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;__syncthreads()는 같은 thread block 안의 모든 non-exited thread가 해당 지점에 도달할 때까지 기다리는 barrier다&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 같은 block 의 thread 사이의 조율을 담당한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 같은 intrinsic call 에 모든 (non-exited) thread 가 도달하거나 , exit 할떄 까지 기다린다.&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;어렵게 생각할 필요 없이 thread 간에 처리 단계의 차이가 있는데 , 이걸 막기 위해서 모두 같은 단계까지 기다리게 하는 것이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 이렇게 단순하게 대기만이 아니라 memory visibility 도 보장한다&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;b&gt;Memory visibility&amp;nbsp;&lt;/b&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;barrier 이전의 global/shared memory access가 block 내 모든 thread에 visible하다. 이게 또 중요한 포인트이다.&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;thread A,B 가 있는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;thread A 가 shared memory 에 쓴 값&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;thread B 가 barrier 뒤에서 읽는 값&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;만약에 barrier 가 없으면 함수를 실행하다보면 thread 간 속도 차이 때문에 오류가 생길 수 있는 부분을 방지할 수 있다.&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;(Programing Guide 공식 문서 참고)&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;shared memory 에서 이런 기능을 많이 사용한다. shared memory 를 같은 thread block 의 모든 thread 가 접근 가능한 on-chip memory 이고 , 안에서 data race 를 피하려면 __synthreads() 를 사용해야한다고 한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 한 thread가 합계를 읽기 전에 다른 thread들의 write가 모두 끝났음을 보장하기 위해 barrier를 둔다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1774075767164&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;__shared__ float buf[256];

buf[threadIdx.x] = some_value;
__syncthreads();

float x = buf[threadIdx.x ^ 1];   // 다른 thread가 쓴 값 읽기&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;만약에 __syncthreads() 를 사용하지 않고 다른 idx 에 접근하면 거기서부터 race 가 생긴다.&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;이처럼 shared memory 를 공동 작업장 처럼 쓰는 패턴에서는 barrier 가 반드시 들어가야 한다.&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;예시 )&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;1366&quot; data-origin-height=&quot;880&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ZBltQ/dJMcaiil2q4/VlfzFOW3G6JgIje4DNrdKk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ZBltQ/dJMcaiil2q4/VlfzFOW3G6JgIje4DNrdKk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ZBltQ/dJMcaiil2q4/VlfzFOW3G6JgIje4DNrdKk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZBltQ%2FdJMcaiil2q4%2FVlfzFOW3G6JgIje4DNrdKk%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;1366&quot; height=&quot;880&quot; data-origin-width=&quot;1366&quot; data-origin-height=&quot;880&quot;/&gt;&lt;/span&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;그래도 너무 벗어난 내용들은 아니고 , 결국 &quot;동기화&quot; 를 어떻게 잘해줄 것이냐의 문제이다.&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;span&gt;&lt;span&gt;__syncthreads() &amp;rarr; 블록 전체 512개 스레드가 여기서 만남 &lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;__syncwarp() &amp;rarr; 내가 속한 warp 32개 스레드만 여기서 만남&lt;/span&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;&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;기본 셋팅 설명 ( with gpt )&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;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;블록 하나가 맡은 데이터들을 다 더해서, block당 결과 1개를 y[blockIdx.x]에 저장하는 것&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 &lt;b&gt;reduction(합 축소)&lt;/b&gt; 예제다.&lt;br /&gt;슬라이드 코드도 reduce4(float* y, float* x, int N) 형태로 되어 있고, block 안에서는 tsum[]라는 shared memory를 써서 합을 줄여 나간다. 앞부분은 __syncthreads(), 마지막 warp 구간은 __syncwarp()를 쓴다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;0) 먼저 전체 그림&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 커널은 한 번에 최종합을 바로 만드는 커널이라기보다,&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;입력 x의 일부를&lt;/li&gt;
&lt;li&gt;&lt;b&gt;각 block이 자기 몫만 먼저 더해서&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;y[blockIdx.x]에 &lt;b&gt;partial sum(부분합)&lt;/b&gt; 을 저장하는 구조다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 block이 여러 개면 결과 y도 여러 개 나온다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;x 전체 데이터
   &amp;darr;
block 0  &amp;rarr; 부분합 y[0]
block 1  &amp;rarr; 부분합 y[1]
block 2  &amp;rarr; 부분합 y[2]
...
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 이 커널 하나만으로 최종합이 끝날 수도 있고,&lt;br /&gt;아니면 y를 다시 reduce하는 다음 단계 커널이 또 필요할 수도 있다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;1) 코드에서 변수들이 뭔지부터&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;슬라이드 코드의 앞부분은 이렇다.&lt;/p&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;__global__ void reduce4(float* y, float* x, int N) {
    extern __shared__ float tsum[];
    int id = threadIdx.x;
    int tid = blockDim.x * blockIdx.x + threadIdx.x;
    int stride = gridDim.x * blockDim.x;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이걸 하나씩 보면:&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;tsum[]&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;extern __shared__ float tsum[];&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;shared memory 배열&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;같은 block 안 thread들이 같이 쓰는 scratchpad&lt;/li&gt;
&lt;li&gt;launch할 때 크기를 정해준다&lt;/li&gt;
&lt;li&gt;슬라이드 launch 문에서 세 번째 인자가 threads * sizeof(float)인데, 이게 바로 tsum 크기다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 thread가 256개면:&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;tsum[0] ~ tsum[255]
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;까지 생긴다고 보면 된다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;id = threadIdx.x&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;block 내부 local thread 번호&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;0, 1, 2, ..., blockDim.x-1&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 blockDim.x=256이면 id는 0~255다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;tid = blockDim.x * blockIdx.x + threadIdx.x&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;grid 전체 기준 global thread 번호&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 block 크기가 256이면:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;block 0의 thread 0 &amp;rarr; tid 0&lt;/li&gt;
&lt;li&gt;block 0의 thread 1 &amp;rarr; tid 1&lt;/li&gt;
&lt;li&gt;...&lt;/li&gt;
&lt;li&gt;block 1의 thread 0 &amp;rarr; tid 256&lt;/li&gt;
&lt;li&gt;block 1의 thread 1 &amp;rarr; tid 257&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 식이다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;stride = gridDim.x * blockDim.x&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;grid 전체에 있는 총 thread 수&lt;/li&gt;
&lt;li&gt;grid-stride loop에서 다음에 내가 맡을 index로 점프할 간격이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;blocks = 80&lt;/li&gt;
&lt;li&gt;threads = 256&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[&lt;br /&gt;stride = 80 \times 256&lt;br /&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;2) launch 문도 같이 이해해야 한다&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;슬라이드 맨 아래 launch는 이거다.&lt;/p&gt;
&lt;pre class=&quot;cs&quot;&gt;&lt;code&gt;reduce4&amp;lt;&amp;lt;&amp;lt;blocks, threads, threads * sizeof(float)&amp;gt;&amp;gt;&amp;gt;(d_B, d_A, N);
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 triple chevron에서:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;첫 번째 blocks = block 개수&lt;/li&gt;
&lt;li&gt;두 번째 threads = block당 thread 개수&lt;/li&gt;
&lt;li&gt;세 번째 threads * sizeof(float) = &lt;b&gt;dynamic shared memory 크기&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 tsum은 block마다 threads개짜리 float 배열로 만들어진다.&lt;br /&gt;Programming Guide도 dynamic shared memory는 launch의 세 번째 인자로 바이트 수를 주고, 커널 안에서는 extern __shared__로 선언한다고 설명한다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;3) 제일 먼저 하는 일: 각 thread가 자기 local sum 만들기&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드:&lt;/p&gt;
&lt;pre class=&quot;gml&quot;&gt;&lt;code&gt;tsum[id] = 0.0f;
for (int k = tid; k &amp;lt; N; k += stride)
    tsum[id] += x[k];
__syncthreads();
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 부분이 중요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;( cf. 여기서 stride = 전체 스레드수 를 말하는 것이다. )&amp;nbsp;&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;의미&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 thread는 입력 x에서 &lt;b&gt;한 원소만 처리하는 게 아니라&lt;/b&gt;,&lt;br /&gt;k += stride로 점프하면서 여러 원소를 자기 혼자 먼저 더한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉:&lt;/p&gt;
&lt;pre class=&quot;prolog&quot;&gt;&lt;code&gt;thread tid 는
x[tid], x[tid + stride], x[tid + 2*stride], ...
를 다 더해서 tsum[id]에 저장
&lt;/code&gt;&lt;/pre&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;grid-stride loop&lt;/b&gt;라고 부른다. 슬라이드도 그대로 그 형태를 쓰고 있다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;왜 이렇게 하냐&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;입력 N이 grid 전체 thread 수보다 훨씬 클 수 있기 때문이다.&lt;br /&gt;그래서 각 thread가 일정 간격으로 여러 원소를 맡는다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;예시&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;blocks = 2&lt;/li&gt;
&lt;li&gt;threads = 4&lt;/li&gt;
&lt;li&gt;그러면 전체 thread 수 = 8&lt;/li&gt;
&lt;li&gt;stride = 8&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이면&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;tid 0 &amp;rarr; x[0], x[8], x[16], ...&lt;/li&gt;
&lt;li&gt;tid 1 &amp;rarr; x[1], x[9], x[17], ...&lt;/li&gt;
&lt;li&gt;...&lt;/li&gt;
&lt;li&gt;tid 7 &amp;rarr; x[7], x[15], x[23], ...&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 맡는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 그 합을 각자 tsum[id]에 넣는다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;4) 왜 여기서 __syncthreads()를 하나&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫 번째 barrier:&lt;/p&gt;
&lt;pre class=&quot;abnf&quot;&gt;&lt;code&gt;__syncthreads();
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이건 block 안 모든 thread가 &lt;b&gt;자기 local sum을 tsum[]에 다 써놓을 때까지 기다리자&lt;/b&gt;는 뜻이다.&lt;br /&gt;__syncthreads()는 같은 block의 모든 non-exited thread가 같은 위치에 도달할 때까지 기다리고, 그 이전의 shared/global memory access가 block 안 다른 thread에게 visible하게 만든다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 여기서의 의미는:&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제부터는 남이 쓴 tsum[...]도 읽을 건데,&lt;br /&gt;그 전에 전부 다 write 끝내고 오자.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;5) 그다음은 &amp;ldquo;반씩 줄여가며 더하기&amp;rdquo;다&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제부터 reduction이 시작된다.&lt;/p&gt;
&lt;pre class=&quot;gml&quot;&gt;&lt;code&gt;if (id &amp;lt; 256 &amp;amp;&amp;amp; id + 256 &amp;lt; blockDim.x)
    tsum[id] += tsum[id + 256];
__syncthreads();

if (id &amp;lt; 128)
    tsum[id] += tsum[id + 128];
__syncthreads();

if (id &amp;lt; 64)
    tsum[id] += tsum[id + 64];
__syncthreads();
&lt;/code&gt;&lt;/pre&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;pairwise reduction tree&lt;/b&gt;다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;핵심 아이디어&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음엔 tsum에 thread 개수만큼 값이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 blockDim.x = 256이면:&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;tsum[0], tsum[1], tsum[2], ... tsum[255]
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 256개가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이걸:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;256개 &amp;rarr; 128개&lt;/li&gt;
&lt;li&gt;128개 &amp;rarr; 64개&lt;/li&gt;
&lt;li&gt;64개 &amp;rarr; 32개&lt;/li&gt;
&lt;li&gt;32개 &amp;rarr; 16개&lt;/li&gt;
&lt;li&gt;16개 &amp;rarr; 8개&lt;/li&gt;
&lt;li&gt;8개 &amp;rarr; 4개&lt;/li&gt;
&lt;li&gt;4개 &amp;rarr; 2개&lt;/li&gt;
&lt;li&gt;2개 &amp;rarr; 1개&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로 줄여 가는 것이다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;6) 왜 if (id &amp;lt; 256) tsum[id] += tsum[id + 256] 같은 형태인가&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이건 &amp;ldquo;앞 절반 thread만 살아남아서 뒤 절반 값을 자기 자리로 끌어와 더한다&amp;rdquo;는 뜻이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 blockDim.x = 512면 처음엔 512개 값이 있다.&lt;/p&gt;
&lt;pre class=&quot;basic&quot;&gt;&lt;code&gt;0   1   2   ... 255 | 256 257 258 ... 511
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때&lt;/p&gt;
&lt;pre class=&quot;applescript&quot;&gt;&lt;code&gt;if (id &amp;lt; 256)
    tsum[id] += tsum[id + 256];
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;를 하면:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;thread 0 &amp;rarr; tsum[0] += tsum[256]&lt;/li&gt;
&lt;li&gt;thread 1 &amp;rarr; tsum[1] += tsum[257]&lt;/li&gt;
&lt;li&gt;...&lt;/li&gt;
&lt;li&gt;thread 255 &amp;rarr; tsum[255] += tsum[511]&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 이제 의미 있는 값은 앞 256개 칸에만 남고, 뒤쪽은 버려도 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉:&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;512개 값  &amp;rarr;  256개 값으로 축소
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가 된다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;7) 왜 매 단계마다 __syncthreads()를 또 하나&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이게 제일 중요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어:&lt;/p&gt;
&lt;pre class=&quot;applescript&quot;&gt;&lt;code&gt;if (id &amp;lt; 128)
    tsum[id] += tsum[id + 128];
__syncthreads();
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 thread 0이 tsum[128]을 읽으려면,&lt;br /&gt;그 tsum[128] 값은 &lt;b&gt;이전 단계&lt;/b&gt;에서 thread 128이 이미 계산해서 써놓았어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 GPU thread들은 완전히 같은 속도로 줄 맞춰 달리는 게 아니므로,&lt;br /&gt;어떤 thread는 이미 다음 줄에 왔고, 어떤 thread는 아직 이전 줄 계산 중일 수 있다. 그래서 block-level barrier가 필요하다. 슬라이드도 __syncthreads()를 같은 block thread들 사이 communication 조율용 barrier로 설명한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 단계마다 barrier를 두는 이유는:&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;이전 단계 결과가 다 써진 뒤에야 다음 단계가 읽게 하려는 것&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;8) 아주 작은 장난감 예제로 reduction 감각 잡기&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제 코드는 32/64/128/256 단위지만,&lt;br /&gt;직관을 위해 8개 값만 있다고 생각해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음:&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;tsum = [3, 1, 4, 2, 5, 6, 7, 8]
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1단계: 앞 절반이 뒤 절반을 더함&lt;/h3&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;tsum[0] += tsum[4]   &amp;rarr; 3+5 = 8
tsum[1] += tsum[5]   &amp;rarr; 1+6 = 7
tsum[2] += tsum[6]   &amp;rarr; 4+7 = 11
tsum[3] += tsum[7]   &amp;rarr; 2+8 = 10
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이후:&lt;/p&gt;
&lt;pre class=&quot;json&quot;&gt;&lt;code&gt;[8, 7, 11, 10, -, -, -, -]
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2단계&lt;/h3&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;tsum[0] += tsum[2]   &amp;rarr; 8+11 = 19
tsum[1] += tsum[3]   &amp;rarr; 7+10 = 17
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이후:&lt;/p&gt;
&lt;pre class=&quot;json&quot;&gt;&lt;code&gt;[19, 17, -, -, -, -, -, -]
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3단계&lt;/h3&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;tsum[0] += tsum[1]   &amp;rarr; 19+17 = 36
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최종합:&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;tsum[0] = 36
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금 슬라이드 코드는 이걸 &lt;b&gt;실제 warp 단위에 맞춰&lt;/b&gt; 512&amp;rarr;256&amp;rarr;128&amp;rarr;64&amp;rarr;32&amp;rarr;16&amp;rarr;8&amp;rarr;4&amp;rarr;2&amp;rarr;1 식으로 한 것이다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;9) 여기서 왜 __syncthreads()는 64까지 쓰고, 그 뒤는 __syncwarp()인가&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;슬라이드에 이렇게 적혀 있다.&lt;/p&gt;
&lt;pre class=&quot;gml&quot;&gt;&lt;code&gt;if (id &amp;lt; 64) tsum[id] += tsum[id + 64];
__syncthreads();

// warp 0 only from here
if (id &amp;lt; 32) tsum[id] += tsum[id + 32];
__syncwarp();
...
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 말의 핵심은:&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;64까지는 여러 warp가 같이 관여한다.&lt;br /&gt;32부터는 warp 0 하나만 남는다.&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;blockDim.x = 256이라고 생각해보자&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;256 threads = 8 warps다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;warp 0: id 0~31&lt;/li&gt;
&lt;li&gt;warp 1: id 32~63&lt;/li&gt;
&lt;li&gt;warp 2: id 64~95&lt;/li&gt;
&lt;li&gt;...&lt;/li&gt;
&lt;li&gt;warp 7: id 224~255&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;if (id &amp;lt; 64)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 단계는 id 0~63이 일한다.&lt;br /&gt;즉 &lt;b&gt;warp 0, warp 1 두 개가 관여&lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 이 단계 뒤에는 &lt;b&gt;warp 간 동기화&lt;/b&gt;가 필요하다.&lt;br /&gt;따라서 __syncthreads()를 쓴다. __syncthreads()는 block 전체 barrier다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;if (id &amp;lt; 32)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제부터는 id 0~31만 일한다.&lt;br /&gt;즉 &lt;b&gt;warp 0 한 개만 관여&lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제는 block 전체를 기다릴 필요가 없다.&lt;br /&gt;warp 0 내부 thread들끼리만 맞추면 되므로 __syncwarp()를 쓴다. 슬라이드도 __syncwarp()는 warp 내부 communication을 위한 barrier이고, __syncthreads()보다 훨씬 가볍다고 설명한다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;10) 그런데 왜 warp 안에서도 sync가 필요한가&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 포인트가 pg.34~37과 연결된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예전에는 warp 안 thread들이 lock-step처럼 같이 움직인다고 생각하는 코드가 어느 정도 통했지만, Volta(CC 7.0) 이후에는 &lt;b&gt;Independent Thread Scheduling&lt;/b&gt; 때문에 warp 안 thread들도 더 독립적으로 전진할 수 있다. 슬라이드는 Before Volta는 warp가 single PC/call stack으로 lock-step이고, Since Volta는 각 thread가 own instruction address counter와 register state를 가져 더 독립적으로 진행할 수 있다고 설명한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 warp 내부에서&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;어떤 thread가 값을 shared memory에 쓰고&lt;/li&gt;
&lt;li&gt;다른 thread가 바로 다음 줄에서 그 값을 읽는&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;패턴이면, 이제는 __syncwarp()로 명시적으로 맞춰 주는 게 안전하다. __syncwarp()는 같은 warp의 participating thread 사이 memory ordering을 보장한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 슬라이드의 마지막 구간은 단순히 &amp;ldquo;warp니까 알아서 되겠지&amp;rdquo;가 아니라,&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;warp 0 내부 reduction도 memory communication이 있으니, 명시적으로 __syncwarp() 넣자&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;라는 의미다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;11) 마지막 부분은 왜 저렇게 끝나나&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드 마지막:&lt;/p&gt;
&lt;pre class=&quot;gml&quot;&gt;&lt;code&gt;if (id &amp;lt; 2) tsum[id] += tsum[id + 2];
__syncwarp();

if (id == 0)
    y[blockIdx.x] = tsum[0] + tsum[1];
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;슬라이드 그대로다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;많이 헷갈리는 부분인데, 왜 마지막에 그냥 tsum[0]을 쓰지 않고 tsum[0] + tsum[1]을 하냐?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이유는 reduction을 &lt;b&gt;완전히 1개 값으로 만들기 직전 단계까지만&lt;/b&gt; 코드로 썼기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 직전 상태는 대략:&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;tsum[0], tsum[1]
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 개가 살아 있는 상태고,&lt;br /&gt;마지막 한 번을 thread 0이 직접&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;tsum[0] + tsum[1]
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로 해서 output에 저장한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 이 줄은 사실상 &amp;ldquo;마지막 reduction 한 번 더&amp;rdquo;다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;12) 전체 흐름을 한 번에 다시 그려보면&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 코드의 논리는 이렇게 보면 된다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;단계 A. 각 thread가 global memory에서 자기 local sum 생성&lt;/h2&gt;
&lt;pre class=&quot;lasso&quot;&gt;&lt;code&gt;x 여러 원소들
   &amp;darr;
thread 0 &amp;rarr; local sum
thread 1 &amp;rarr; local sum
thread 2 &amp;rarr; local sum
...
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 결과를 tsum[id]에 저장.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;단계 B. block 내부 shared memory reduction&lt;/h2&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;tsum[0..blockDim-1]
   &amp;darr;
절반씩 줄임
   &amp;darr;
64개
   &amp;darr;
32개
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;64까지는 여러 warp가 섞여 있으니 __syncthreads().&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;단계 C. 마지막 warp만 남음&lt;/h2&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;32개
&amp;darr;
16개
&amp;darr;
8개
&amp;darr;
4개
&amp;darr;
2개
&amp;darr;
1개
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기는 warp 0만 관여하므로 __syncwarp().&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;단계 D. block 결과 저장&lt;/h2&gt;
&lt;pre class=&quot;armasm&quot;&gt;&lt;code&gt;y[blockIdx.x] = block partial sum
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;13) 이 코드에서 꼭 기억해야 하는 포인트&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;포인트 1: tsum[]은 shared memory다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같은 block 안 thread들이 공동으로 쓰는 공간이다.&lt;br /&gt;그래서 barrier 없이 읽고 쓰면 race/hazard가 날 수 있다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;포인트 2: __syncthreads()는 block 전체 barrier다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같은 block의 모든 non-exited thread가 도달할 때까지 기다리고, 이전 memory access를 block 내 다른 thread에게 보이게 한다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;포인트 3: __syncwarp()는 warp 내부 barrier다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;warp 내부 communication용이다. Volta 이후에는 warp 안도 필요할 때 explicit sync가 필요하다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;포인트 4: 64까지 __syncthreads(), 32부터 __syncwarp()&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이유는 &amp;ldquo;여러 warp가 아직 살아 있느냐 / 이제 한 warp만 남았느냐&amp;rdquo; 차이다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;포인트 5: 이 커널 결과는 block당 1개&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 y[blockIdx.x]는 &lt;b&gt;최종 global sum이 아니라 partial sum&lt;/b&gt;이다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;14) 네가 지금 가장 헷갈려하면 안 되는 부분만 딱 찌르면&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 예제의 본질은 사실 아래 한 줄이다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;ldquo;여러 thread가 각자 계산한 값을 shared memory에 모아 놓고, 그 값을 단계적으로 합칠 때, 여러 warp가 섞이는 구간은 __syncthreads(), 마지막 한 warp만 남는 구간은 __syncwarp()를 쓴다.&amp;rdquo;&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이걸 reduction 예제로 보여준 것이다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;15) 마지막으로, 이 코드를 네 머릿속에 제일 쉽게 넣는 비유&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 thread를 학생이라고 생각해보자.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;처음엔 학생마다 자기 시험지 여러 장을 먼저 채점해서&lt;br /&gt;&lt;b&gt;개인 점수&lt;/b&gt;를 만든다&lt;br /&gt;&amp;rarr; for (...) tsum[id] += x[k];&lt;/li&gt;
&lt;li&gt;그다음 둘씩 짝지어서 점수를 합친다&lt;br /&gt;&amp;rarr; reduction&lt;/li&gt;
&lt;li&gt;이때 여러 조가 동시에 움직이면&lt;br /&gt;&lt;b&gt;&amp;ldquo;다 끝나고 다음 라운드로 넘어가&amp;rdquo;&lt;/b&gt;&lt;br /&gt;가 필요하다&lt;br /&gt;&amp;rarr; __syncthreads()&lt;/li&gt;
&lt;li&gt;마지막엔 한 조(=한 warp) 안 학생들만 남으니까&lt;br /&gt;이제 반 전체를 세울 필요는 없고&lt;br /&gt;&lt;b&gt;그 조 안에서만 맞추면 된다&lt;/b&gt;&lt;br /&gt;&amp;rarr; __syncwarp()&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 생각하면 된다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원하면 다음 답변에서는 내가 이 코드를 &lt;b&gt;blockDim.x = 256 기준으로 id=0,1,2,...가 실제로 어떤 값을 읽고 쓰는지&lt;/b&gt; 표처럼 한 단계씩 완전히 펼쳐서 보여주겠다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;cf.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;//&amp;nbsp;여기는&amp;nbsp;스레드&amp;nbsp;0~255가&amp;nbsp;일함&amp;nbsp;&amp;rarr;&amp;nbsp;Warp&amp;nbsp;0~7이&amp;nbsp;관여&amp;nbsp;&amp;rarr;&amp;nbsp;여러&amp;nbsp;warp &lt;br /&gt;if&amp;nbsp;(id&amp;nbsp;&amp;lt;&amp;nbsp;256)&amp;nbsp;tsum[id]&amp;nbsp;+=&amp;nbsp;tsum[id&amp;nbsp;+&amp;nbsp;256]; &lt;br /&gt;__syncthreads();&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;여러&amp;nbsp;warp&amp;nbsp;기다려야&amp;nbsp;하니까&amp;nbsp;무거운&amp;nbsp;동기화 &lt;br /&gt;&lt;br /&gt;//&amp;nbsp;여기는&amp;nbsp;스레드&amp;nbsp;0~31만&amp;nbsp;일함&amp;nbsp;&amp;rarr;&amp;nbsp;Warp&amp;nbsp;0&amp;nbsp;하나만&amp;nbsp;관여 &lt;br /&gt;if&amp;nbsp;(id&amp;nbsp;&amp;lt;&amp;nbsp;32)&amp;nbsp;tsum[id]&amp;nbsp;+=&amp;nbsp;tsum[id&amp;nbsp;+&amp;nbsp;32]; &lt;br /&gt;__syncwarp();&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;warp&amp;nbsp;하나니까&amp;nbsp;가벼운&amp;nbsp;동기화로&amp;nbsp;충분 &lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; warp 안에서도 동기화가 안되기 떄문에 ( 기본적으로 ) 처렇게 index 참조하는 경우에 이상해질 수 있다. 따라서 하나의 warp 안에서도 반드시 이런식으로 동기화를 해서 관리를 해줘야 문제가 생기지 않는다.&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;4677&quot; data-start=&quot;4625&quot;&gt;앞부분은 여러 warp가 같이 살아 있다&lt;br /&gt;&amp;rarr; block-level sync 필요&lt;/li&gt;
&lt;li data-end=&quot;4746&quot; data-start=&quot;4678&quot;&gt;마지막엔 warp 0 하나만 남는다&lt;br /&gt;&amp;rarr; block 전체 sync는 과하다&lt;br /&gt;&amp;rarr; warp 내부만 맞추면 된다&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;4940&quot; data-start=&quot;4900&quot;&gt;&lt;b&gt;여러 warp가 협업할 때&lt;/b&gt; &amp;rarr; __syncthreads()&lt;/li&gt;
&lt;li data-end=&quot;4984&quot; data-start=&quot;4941&quot;&gt;&lt;b&gt;이제 한 warp 안에서만 협업할 때&lt;/b&gt; &amp;rarr; __syncwarp()&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;라고 보면된다.&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;__syncthreads() 적용 범위 : 같은 block 만.&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;위에서 설명했던 내용 처럼 우리는 계속 &quot; 같은 블럭 &quot; 을 기준으로 동기화 하는 것을 보고 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;block 0 와 block 1 은 전혀 서로가 뭘 하는지 알 수 없다. CUDA 의 기본 execution model 에서는 각 block 이 논리적으로 독립적이고 , block 간 scheduling 순서 보장이 없다.&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;&amp;nbsp;&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;1293&quot; data-origin-height=&quot;500&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b1q2Wt/dJMcabjgtiL/7ChGD0DJyrSH9OTdTMOqT0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b1q2Wt/dJMcabjgtiL/7ChGD0DJyrSH9OTdTMOqT0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b1q2Wt/dJMcabjgtiL/7ChGD0DJyrSH9OTdTMOqT0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb1q2Wt%2FdJMcabjgtiL%2F7ChGD0DJyrSH9OTdTMOqT0%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;793&quot; height=&quot;307&quot; data-origin-width=&quot;1293&quot; data-origin-height=&quot;500&quot;/&gt;&lt;/span&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;&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;Conditional 안에서 쓸 떄 조심해야한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;__syncthread() 가 conditional code 안에서도 허용은 되나 , 조건이 thread block 전체에서 동일하게 평가될 경우만 안전하다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇지 않으면 deadlock 이나 , unintended side effects 가 발생할 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;6000&quot; data-start=&quot;5986&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어 이건 위험하다.&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 id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;div&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;threadIdx&lt;/span&gt;&lt;span&gt;.x &lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;64&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;br /&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;__syncthreads&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;br /&gt;&lt;span&gt;}&lt;/span&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;6066&quot; data-start=&quot;6061&quot; data-ke-size=&quot;size16&quot;&gt;왜냐하면:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;6139&quot; data-start=&quot;6068&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;6110&quot; data-start=&quot;6068&quot;&gt;threadIdx.x &amp;lt; 64인 thread만 barrier에 들어감&lt;/li&gt;
&lt;li data-end=&quot;6139&quot; data-start=&quot;6111&quot;&gt;나머지 thread는 barrier에 안 들어감&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;6218&quot; data-start=&quot;6141&quot; data-ke-size=&quot;size16&quot;&gt;그럼 barrier에 들어간 thread들은 &amp;ldquo;block 전체가 올 때까지 기다려야 하는데&amp;rdquo;&lt;br /&gt;나머지는 영원히 안 오므로 멈춰버린다. -&amp;gt; 즉 deadlock.&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;&lt;i&gt;&lt;u&gt;( 몇가지 케이스는 만들어서 확인좀 해보기 )&amp;nbsp;&lt;/u&gt;&lt;/i&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;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;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;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;비유: 회전문&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;__syncthreads()는 &lt;b&gt;512명이 다 모여야 열리는 회전문&lt;/b&gt;이야.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;케이스 1: 전원이 같은 길로 감&lt;/h3&gt;
&lt;pre class=&quot;jboss-cli&quot;&gt;&lt;code&gt;if (N &amp;gt; 1000) {
    // ... 계산 ...
    __syncthreads();   // 회전문
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N=2000이면:&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;512명 전원: &quot;N 크네? 이쪽 길로 가자&quot;
         &amp;rarr; 전원 회전문 도착
         &amp;rarr; 512명 다 왔네 &amp;rarr; 열림 ✅
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;케이스 2: 갈림길에 회전문을 놓음&lt;/h3&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;if (threadIdx.x &amp;lt; 128) {
    __syncthreads();   // 회전문을 왼쪽 길에만 놓음
}
&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;1c&quot;&gt;&lt;code&gt;0~127번:   &quot;왼쪽 길로 갈게&quot; &amp;rarr; 회전문 도착 &amp;rarr; &quot;512명 와야 열린대...&quot;
128~511번: &quot;오른쪽 길로 갈게&quot; &amp;rarr; 회전문 안 만남 &amp;rarr; 그냥 지나감

왼쪽 128명: 영원히 기다림  
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;케이스 3: 양쪽 길에 각각 회전문&lt;/h3&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;if (threadIdx.x &amp;lt; 256) {
    __syncthreads();   // 회전문 A
} else {
    __syncthreads();   // 회전문 B
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이것도 데드락이야:&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;0~255번:   회전문 A 도착 &amp;rarr; &quot;512명 와야 열린대...&quot; &amp;rarr; 256명밖에 없음  
256~511번: 회전문 B 도착 &amp;rarr; &quot;512명 와야 열린대...&quot; &amp;rarr; 256명밖에 없음  
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;회전문 A와 B는 &lt;b&gt;다른 회전문&lt;/b&gt;이야. A에 256명, B에 256명 와봤자 소용없어. 각 회전문이 각각 512명을 기다림.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;케이스 4: 올바른 패턴&lt;/h3&gt;
&lt;pre class=&quot;gml&quot;&gt;&lt;code&gt;if (threadIdx.x &amp;lt; 256) {
    tsum[id] += tsum[id + 256];   // 일부만 계산
}
__syncthreads();   // 회전문은 길이 합쳐진 곳에 놓음
&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;0~255번:   계산하고 나옴
256~511번: if 건너뜀

전원 회전문 도착 &amp;rarr; 512명 다 왔네 &amp;rarr; 열림 ✅
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이게 reduce 코드에서 쓴 패턴이야. 계산은 일부만, 동기화는 전원이.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 내용과 비슷한 결인데 , non-exited threads 의미&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 이미 함수에서 return 해버린 thread 는 barrier 대상이 아니고&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 살아있는 thread 기리는 &quot;모두&quot; barrier 에 도달해야한다. ( 특히 예시를 보면 if - else 문에 서로 동기화를 하는 것 처럼 보이지만 , 이것도 결국 하나의 sync 에서 다 모여야 하는거라 오류다 )&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;lt; predicate variant &amp;gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;7672&quot; data-start=&quot;7633&quot;&gt;__syncthreads_count(int predicate);&lt;/li&gt;
&lt;li data-end=&quot;7710&quot; data-start=&quot;7673&quot;&gt;__syncthreads_and(int predicate);&lt;/li&gt;
&lt;li data-end=&quot;7747&quot; data-start=&quot;7711&quot;&gt;__syncthreads_or(int predicate);&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 함수들은 barrier 역할 하면서 , predicate 결과를 추가로모아주는 함수들이다.&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;&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같은 block의 thread들이 shared/global memory를 통해 협업할 때,&lt;br /&gt;어느 시점 이전에 쓴 데이터가 이후에 안전하게 읽히도록,&lt;br /&gt;전원이 한 지점에 도착할 때까지 묶어두는 장치가 __syncthreads()다.&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;&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;h2 data-ke-size=&quot;size26&quot;&gt;Extensions to the Classical CUDA Execution Model: Independent Thread Scheduling (Volta/CC 7.0 or Later)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Before Volta:&lt;/b&gt; warp 안 32개 thread가 거의 &amp;ldquo;한 몸처럼&amp;rdquo; lock-step으로 감&lt;br /&gt;&lt;b&gt;Since Volta:&lt;/b&gt; warp 안 thread들도 더 독립적으로 전진할 수 있음&lt;br /&gt;&amp;rarr; 그래서 예전에는 암묵적으로 맞던 warp-synchronous 코드가 지금은 깨질 수 있음.&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;h4 data-ke-size=&quot;size20&quot;&gt;[ Before Volta ]&amp;nbsp;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1394&quot; data-origin-height=&quot;848&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ludnK/dJMcaf0dMKb/mBv50wErDi4iBfvzkctfl0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ludnK/dJMcaf0dMKb/mBv50wErDi4iBfvzkctfl0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ludnK/dJMcaf0dMKb/mBv50wErDi4iBfvzkctfl0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FludnK%2FdJMcaf0dMKb%2FmBv50wErDi4iBfvzkctfl0%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;729&quot; height=&quot;443&quot; data-origin-width=&quot;1394&quot; data-origin-height=&quot;848&quot;/&gt;&lt;/span&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;Before Volta 에서는 warp 안 32 thread 가 거의 한 몸 처럼 같이 움직였다. 즉 warp 마다 PC ( programing counter )와 call stack 이 1개였고 , 같은 instructin 을 lock - step 으로 실행했다.&amp;nbsp; warp 는 32개의 thread 로 이루어져 있고 이게 GPU 의 기본 실행 단위이다.&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;b&gt;&quot; warp 당 PC 를 하나 &quot; 이게 여기서 가장 핵심이다.&amp;nbsp;&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;Single PC and Call stack per warp&amp;nbsp;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;쉽게 말해서 PC 가 한개 밖에 없으니까 warp 32 개 스레드가 PC 를 공유하게 되고 , 그러면 32 개 스레드 모두 같은 명령을 수행하고 있을것이다 ( 코드에서 같은 줄을 보고 있으니까. )&amp;nbsp;&lt;/li&gt;
&lt;li&gt;그냥 같은 Warp 안 thread 들이 같은 thread 를 같이 하고있는걸 lock-step 이라고 한다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;single instruction address counter &amp;amp; register state 로 관리된다.&amp;nbsp;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;각 스레드가 다루는 데이터는 다르다 ( 같은 줄이여도 ) , 그래서 명령어는 같지만 데이터 ( reigster 값 ) 은 다르다. ( 이걸 SIMT 라고 부르기도 하고 )&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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Example: Branch divergence&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;1342&quot; data-origin-height=&quot;269&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Sf2WD/dJMcah4PRtZ/U8qcXE01NJMlEDBlq7a450/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Sf2WD/dJMcah4PRtZ/U8qcXE01NJMlEDBlq7a450/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Sf2WD/dJMcah4PRtZ/U8qcXE01NJMlEDBlq7a450/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSf2WD%2FdJMcah4PRtZ%2FU8qcXE01NJMlEDBlq7a450%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;695&quot; height=&quot;139&quot; data-origin-width=&quot;1342&quot; data-origin-height=&quot;269&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇다면 if 문 처럼 분기가 생기면 어떻게 처리할까 ?&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;warp 안 thread 들이 data-dependent conditional branch 때문에 갈라지게 되면 , warp 는 각 branch path 를 하나씩 실행하고 그 path 에 속하지 않는 thread 는 disable/inactivate 된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그니까 거기에 속하지 않는 thread 는 mask 처리해서 연산을 안하고 , 서로 따로 thread 를 실행시킨 다음에 합치면 된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;( 현재 instruction 에 참여하는 thread = active / 아니면 inactive )&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;( warp 안 thread들이 같은 길로 갈수록 좋고, branch divergence가 많을수록 비효율 - 뭐 당연한거다 )&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1344&quot; data-origin-height=&quot;775&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cCbLrG/dJMcafsovbS/BoK6OeWyp8Jxn3XIHbgvW0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cCbLrG/dJMcafsovbS/BoK6OeWyp8Jxn3XIHbgvW0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cCbLrG/dJMcafsovbS/BoK6OeWyp8Jxn3XIHbgvW0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcCbLrG%2FdJMcafsovbS%2FBoK6OeWyp8Jxn3XIHbgvW0%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;779&quot; height=&quot;449&quot; data-origin-width=&quot;1344&quot; data-origin-height=&quot;775&quot;/&gt;&lt;/span&gt;&lt;/figure&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;1286&quot; data-origin-height=&quot;406&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/csJjht/dJMcahDJAEZ/0ykKjzmTZRcYxrvl4CSszk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/csJjht/dJMcahDJAEZ/0ykKjzmTZRcYxrvl4CSszk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/csJjht/dJMcahDJAEZ/0ykKjzmTZRcYxrvl4CSszk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcsJjht%2FdJMcahDJAEZ%2F0ykKjzmTZRcYxrvl4CSszk%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;756&quot; height=&quot;239&quot; data-origin-width=&quot;1286&quot; data-origin-height=&quot;406&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1) Only active threads of a warp participate in the current instruction&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 현재 instruction 실행하는건 active thread 뿐 ( 앞에서 말했던 내용 그대로 )&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;nbsp; acitve 가 되는 3가지 이유&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;어떤 thread 가 임지 return 하거나 작업이 끝나서 빠져나가고 , 같은 warp 의 다른 thread 는 실행중인 경우.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;위에서 살펴봤던 if 문 떄문에 barnch 가 나눠져서&amp;nbsp;&lt;/li&gt;
&lt;li&gt;warp 크기가 32 인데 , block 크기가 32의 배수가 아닌경우 . 그러면 마지막에 빈부분이 생길텐데 그부분은 inactive 처럼 취급한다.&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;2)&amp;nbsp; Instructions are always synced between threads in a warp&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;warp 안에 thread 들은 instruction 수준에서는 항상 맞춰져 있다&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜 ? berfore volat 에서는 warp 가 single PC 와 call stack 을 공유하고 lock-step 으로 움직였기 떄문이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 같은 warp 안 thread 들이 instruction 단위로 흩어질까 걱정해서 별도의 barrier 를 넣을 필요는 없다.&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;3) Memory operations may not be synced&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 memory 동기화는 필요하다. 같은 명령어를 실행해도 메모리에 쓰는 타이밍은 다를 수 있기 떄문이다.&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;pre id=&quot;code_1774084079117&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 라인 1: 32개 스레드 동시 실행 &amp;mdash; 각자 자기 칸에 write
tsum[id] = my_value;

// 라인 2: 32개 스레드 동시 실행 &amp;mdash; 남의 칸을 read
float x = tsum[31 - id];   // 스레드 0은 tsum[31]을 읽음
                            // 근데 스레드 31의 write가 아직 메모리에 안 도착했을 수도!&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;명령어 자체는 line 1,&amp;nbsp; 2 가 lock-step 으로 같이 실행하나 , 라인 1의 write 결과가 메모리에 반영되기 전에 라인2 의 read 가 실행될 수 있기 떄문에 이런 memory 쪽은 동기화를 시켜줘야 했다.&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;4) 같은 메모리 주소에 여러 스레드가 접근하면&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;warp 안 여러 thread 가 같은 메모리 주솔르 동시에 건드리면 , 그 순서가 정의되지 않는다.&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;Non atomic write : 같은 warp 의 둘 이상의 thread 가 memory location 에 대해 non-atomic write 하면 그 write 들은 serialized ( 직렬화 ) 한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 쉽게 말하면 동시에 한 주소에 막쓰면 충돌 나니까 , 하드웨어가 사실상 줄 세워서 하나씩 처리하는 것 이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 serialized 되더라도 최종적으로 어떤 thread 값이 남는지는 불문명하다.&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;atomic : global memory location 에 대해 여러 thread 에서 실행되면 , 순서는 알 수없지만 결과는 정확하다.&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;&amp;lt;정리&amp;gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;5505&quot; data-start=&quot;5487&quot;&gt;warp = 32 thread&lt;/li&gt;
&lt;li data-end=&quot;5524&quot; data-start=&quot;5506&quot;&gt;&lt;b&gt;warp마다 PC 하나&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;5568&quot; data-start=&quot;5525&quot;&gt;warp 안 thread들은 &lt;b&gt;같은 instruction을 같이 실행&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;5607&quot; data-start=&quot;5569&quot;&gt;divergence가 나면 &lt;b&gt;한 branch씩 순서대로 실행&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;5730&quot; data-start=&quot;5608&quot;&gt;현재 path에 없는 thread는 &lt;b&gt;inactive(masked)&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;[ Volta ]&amp;nbsp;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 Volta ( cc 7.0 2017) 부터 생기는 변화들을 자세히 알아보자.&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;986&quot; data-origin-height=&quot;629&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/TdCOJ/dJMcadnMNvq/MlQ9J69XR4lzCHcA0Mrwik/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/TdCOJ/dJMcadnMNvq/MlQ9J69XR4lzCHcA0Mrwik/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/TdCOJ/dJMcadnMNvq/MlQ9J69XR4lzCHcA0Mrwik/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTdCOJ%2FdJMcadnMNvq%2FMlQ9J69XR4lzCHcA0Mrwik%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;738&quot; height=&quot;471&quot; data-origin-width=&quot;986&quot; data-origin-height=&quot;629&quot;/&gt;&lt;/span&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;위에서도 자세히 살펴 봤듯이 Before Volta 에서는 warp 하나가 Single PC &amp;amp; call stack 을 공유했다. warp 전체가 하나의 instruction address counter 로 관리되었고 , lock-step 으로 실행되었다. 하지만 Volta 부터는 완전히 바뀌게 되었다.&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;Volta&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1507&quot; data-start=&quot;1460&quot; data-section-id=&quot;1u238yr&quot;&gt;&lt;b&gt;thread마다 개별 program counter / call stack&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;1538&quot; data-start=&quot;1508&quot; data-section-id=&quot;1ygmcn6&quot;&gt;&lt;b&gt;warp-level independence&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;1569&quot; data-start=&quot;1539&quot; data-section-id=&quot;gsiubu&quot;&gt;&lt;b&gt;finer-grained mechanism&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;1649&quot; data-start=&quot;1570&quot; data-section-id=&quot;1han5z9&quot;&gt;&lt;b&gt;필요하면 intra-warp synchronization 필요&lt;/b&gt;&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;이렇게 크게 4가지 정도가 존재한다.&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;1. Thread 마다 PC / register state&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;volta 부터는 warp 안 각 thread 가 자기만의 instruction address counter 와 register 를 가진다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;( 이전에는 warp 당 PC 1개 )&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;2. Warp-level independence&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Independent threas scheduling 이 primarily operates within a warp 이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉&amp;nbsp; , grid 전체나 block 전체가 갑자기 thread - by - thread 로 스케줄 된다는게 아니라 , 같은 warp 안에서도 개별 thread 가 stall 시 더 독립적으로 진행하능하다는 것이다. 어떤 thread 가 stall 되더라도 예전처럼 warp 전체를 묶어서 기다리게 하지 않고 , 가능한 thread 들은 더 진행할 수 있다.&amp;nbsp;&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;이렇게되면 한 thread 가 메모리 대기나 늦어진다고 해서 , 같은 warp 의 다른 thread 까지 무조건 같이 대기할 필요가 없어진다.&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; Q : 그러면 다른 warp의 부분을 돌린다는건가 ?&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;A : 아니다.&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;(With claude)&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;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;핵심부터: Warp는 여전히 스케줄링의 기본 단위&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Independent Thread Scheduling이라고 해서 쓰레드가 CPU처럼 개별적으로 자유롭게 돌아다니는 게 &lt;b&gt;아니야.&lt;/b&gt; Warp 32개 쓰레드는 여전히 같은 Processing Block의 32개 CUDA Core에 1:1로 매핑되어 있고, &lt;b&gt;Warp Scheduler가 warp 단위로 issue&lt;/b&gt;하는 구조는 바뀌지 않았어.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;Warp Scheduler
     │
     ▼ (warp 단위로 선택)
┌─────────────────────────────┐
│  Warp 7의 32 threads        │
│  &amp;rarr; 32 CUDA Cores에 매핑     │
│  &amp;rarr; 이번 cycle에 실행         │
└─────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;그러면 뭐가 달라진 건데?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;달라진 건 &lt;b&gt;warp 내부에서 divergence를 처리하는 방식&lt;/b&gt;이야.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Before Volta&lt;/b&gt;: diverge하면 branch A 쓰레드 전부 &amp;rarr; branch B 쓰레드 전부, 이렇게 &lt;b&gt;완전히 순차 실행&lt;/b&gt;. 하나의 PC를 공유하니까 선택지가 없음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Since Volta&lt;/b&gt;: 각 쓰레드가 자기 PC를 갖고 있으니까, 하드웨어가 &lt;b&gt;sub-warp 단위&lt;/b&gt;로 &quot;이번 cycle에는 branch A 쓰레드들 실행, 다음 cycle에는 branch B 쓰레드들 실행&quot;을 더 유연하게 &lt;span style=&quot;background-color: #ee2323;&quot;&gt;&lt;b&gt;interleave&lt;/b&gt; &lt;/span&gt;할 수 있어. 핵심은 여전히 &lt;b&gt;한 warp 안에서&lt;/b&gt; 일어나는 일이라는 거야.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;Before Volta (rigid serial):
  cycle 1~4: [A; A; B; B;]  &amp;larr; thread 0~15만 (16~31 stall)
  cycle 5~8: [X; X; Y; Y;]  &amp;larr; thread 16~31만 (0~15 stall)
  cycle 9~:  reconverge &amp;rarr; [P; Q;]

Since Volta (flexible interleave):
  cycle 1: [A]  thread 0~15
  cycle 2: [X]  thread 16~31    &amp;larr; 바로 교대 가능
  cycle 3: [B]  thread 0~15
  cycle 4: [Y]  thread 16~31
  cycle 5: [P]  thread 0~15     &amp;larr; 먼저 도달 가능
  ...
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&quot;다른 warp의 쓰레드가 빈 자리에 들어오는 거냐?&quot;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;아니야.&lt;/b&gt; 32개 CUDA Core는 현재 실행 중인 warp에 전속되어 있어. 다른 warp의 thread가 끼어들지 않아.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만 네가 생각하는 메커니즘이 &lt;b&gt;warp-level context switching&lt;/b&gt;(= latency hiding)이랑 헷갈린 것 같은데, 그건 &lt;b&gt;Volta 이전부터 항상 있던 기능&lt;/b&gt;이야:&lt;/p&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;Warp Scheduler가 가진 resident warp pool:
  [Warp 0] [Warp 1] [Warp 2] ... [Warp N]

cycle 1: Warp 0 실행 &amp;rarr; memory access로 stall
cycle 2: Warp 0 전체가 대기 &amp;rarr; Scheduler가 Warp 3 선택해서 실행
cycle 3: Warp 3 실행
cycle 4: Warp 0의 데이터 도착 &amp;rarr; 다시 ready 상태로
...
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이건 &lt;b&gt;warp 간&lt;/b&gt; 전환이고, Independent Thread Scheduling은 &lt;b&gt;warp 내부&lt;/b&gt;의 얘기야. 두 개는 서로 다른 레벨의 메커니즘이지.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;그래서 warp로 묶는 이유?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여전히 warp가 존재하는 이유는 &lt;b&gt;하드웨어 효율&lt;/b&gt; 때문이야:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;명령어 fetch/decode 비용 절감&lt;/b&gt; &amp;mdash; 32개 쓰레드가 (가능하면) 같은 명령어를 실행하니까, instruction fetch와 decode를 1번만 하면 32개 연산이 나가. 만약 쓰레드마다 완전히 독립적으로 스케줄링하면 fetch/decode 유닛이 32배 필요하겠지. GPU가 수천 개의 쓰레드를 돌릴 수 있는 건 이 &quot;SIMT 묶음 실행&quot; 덕분이야.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Convergence Optimizer의 역할&lt;/b&gt; &amp;mdash; Volta가 한 건, 엄밀히 말하면 &quot;warp를 없앤 게 아니라, divergence 상황에서 warp 내부를 더 스마트하게 관리하는 것&quot;이야. 쓰레드들이 같은 PC에 다시 모이면 Convergence Optimizer가 즉시 reconverge 시켜서 다시 32-wide SIMT 효율을 회복해.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;내 이전 설명 정정&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;stall된 쓰레드를 기다리지 않아도 됨&quot;이라고 쓴 부분은 좀 과하게 표현했어. 더 정확하게는: &lt;b&gt;divergent branch 상황에서 active thread subset이 inactive thread를 기다리며 완전히 block되지 않고, 하드웨어가 sub-warp 단위로 유연하게 교차 실행할 수 있게 됐다&lt;/b&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;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. Fine-grained mechanism&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;branch에서 warp의 일부만 active라면, active thread들은 계속 가고 inactive thread는 기다릴 수 있다. 또는 그 반대도 가능하다&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;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;983&quot; data-origin-height=&quot;655&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/EVSla/dJMcabwLazH/UI4wL4O51IBvgxkLrypHz0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/EVSla/dJMcabwLazH/UI4wL4O51IBvgxkLrypHz0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/EVSla/dJMcabwLazH/UI4wL4O51IBvgxkLrypHz0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEVSla%2FdJMcabwLazH%2FUI4wL4O51IBvgxkLrypHz0%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;741&quot; height=&quot;494&quot; data-origin-width=&quot;983&quot; data-origin-height=&quot;655&quot;/&gt;&lt;/span&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;&amp;lt; Before Volta &amp;gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드를 보면 warp 안 0~15 thread 는 A,B&amp;nbsp; / 나머지는 x,y 로 간다.&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;여기서는 warp 가 lock-step 이라서 실제로 :&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. A,B path 실행될 차례&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 해당 안되는 곳은 mask off&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. x,y path 차례&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 마찬가지&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. reconverge&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. P/Q 공통 구간 실행&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;lt;Since Volta &amp;gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 divergent branch 의 statment 들이 interleaved 될 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 어떤 lane 들은 branch path 써서 더 빨리 진행하고 어떤 lane 은 아직 다른 path 에 남아 있을 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(그래서 슬라이드에 P ??? 써져있는 것임 )&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;그래서 volta 에서는 Q 가 실행되는 시점에 warp 안 thread 들이 병렬로 계산해 두어야할 p 까지 데이터가 정말 다 있는가 ?&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;4. warp - levl synchronization&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서! warp 간의 동기화가 필요한 것이다. ( 기억이 날지 모르곘는데 앞에서&amp;nbsp; 코드에서 해멨던 이유가 이쪽 파트를 제대로 못들어서 그런 듯 하다 )&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;위 그림에서도 볼 수 있듯이 __syncwarp()&amp;nbsp; 를 써야 한다.&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;__syncwarp()&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Q 가 warp 안에 다른 thread 들의 P 단계 결과에 의존을&amp;nbsp; 할 경우에 , P 뒤에서 warp-level barrier 를 넣어야 한다.&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;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Synchronization within a Warp (Volta/CC 7.0 or Later)&amp;nbsp;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바로 이야기가 진행된다. __synwarp() 가 무엇이며 __synthreads() 와는 무엇이 다를까 ?&amp;nbsp;&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;968&quot; data-origin-height=&quot;627&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dqKq17/dJMcahKxHQn/ZYKvsnmec8qK3m0vet8g4k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dqKq17/dJMcahKxHQn/ZYKvsnmec8qK3m0vet8g4k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dqKq17/dJMcahKxHQn/ZYKvsnmec8qK3m0vet8g4k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdqKq17%2FdJMcahKxHQn%2FZYKvsnmec8qK3m0vet8g4k%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;789&quot; height=&quot;511&quot; data-origin-width=&quot;968&quot; data-origin-height=&quot;627&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;i&gt; &lt;span&gt;void&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;__syncwarp&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;unsigned&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;mask&lt;/span&gt;&lt;span&gt; = &lt;/span&gt;&lt;span&gt;0xffffffff&lt;/span&gt;&lt;span&gt;);&amp;nbsp;&lt;/span&gt;&lt;/i&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;의미 : mask 에 지정된 warp lane 들이 모두 같은 __syncwarp() call 에 도달할때 까지 기다린다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;그리고 그 thread 사이에 memory ordering 도 보장한다.&amp;nbsp;&lt;/span&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;span&gt;즉 2가지&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1371&quot; data-start=&quot;1339&quot; data-section-id=&quot;k17hui&quot;&gt;&lt;b&gt;execution synchronization&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;1410&quot; data-start=&quot;1372&quot; data-section-id=&quot;y2qve6&quot;&gt;&lt;b&gt;memory ordering / visibility 보장&lt;/b&gt;&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;cf.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;execution synchronization 이란 ?&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;: warp 안에서 내가 지정한 lane 들이 모두 이 지점까지 오기 전에는, 먼저 온 thread 도 다음으로 못간다.&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;P -&amp;gt; __synwarp() -&amp;gt; Q&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;형태에서 먼저 온 thread 는 기다리고 , 나머지 participating lane 도 &quot;다&quot; 도착하면 그 다음에 다같이 Q 로 간다. \&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Volta 이후 깨질 수 있는 암묵적 하자를 명시적 barrier 로 다시 만들어주는 것이다.&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;memory ordering 보장&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2087&quot; data-start=&quot;2022&quot; data-section-id=&quot;1yse2l6&quot;&gt;barrier 이전에 warp thread들이 global/shared memory에 수행한 read/write는&lt;/li&gt;
&lt;li data-end=&quot;2189&quot; data-start=&quot;2088&quot; data-section-id=&quot;13ev0tb&quot;&gt;barrier 이후에 같은 warp의 participating thread들에게 visible하다고 설명한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이것도 어려운게 아니라 thread 들이 메모리 통해서 통신하려면 다음과 같이 ,&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1774097140219&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;shared[lane] = my_value;
__syncwarp();
x = shared[other_lane];&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;1. 각 thread 가 먼저 자기 값을 shared / globla 메모리에 쓰고&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. __synwarp() 에서 participating lane 들이 다 도착할때 기다리고 ( 이때 memory ordering 을 보장 )&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 이후에는 안전하게 읽을 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;( 아까도 설명했지만 , memory ordering 이 없으면 코드 자체는 수행이 끝났으나 메모리에 적는 시간차이로 인해서 race 가 발생할 수 있기 때문. )&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;Notes&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- __syncthreads() 보다 훨씬 가볍고 빠르다 ( block 전체가 아니라 warp 32 개 내부여서 )&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- mask&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;&lt;b&gt; __activemask()&amp;nbsp;&lt;/b&gt;&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;: 지금 이 순간, 이 warp에서 실행 중인 쓰레드가 누구냐 를 알려주는 조회용 intrinsic. ( 그냥 읽기만 )&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반환값은 32-bit unsigned int 이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 bit 가 warp 의 lane 0~31 에 대응한다 ( bit = 1 -&amp;gt; active )&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;( __activemask() + __syncwarp() 조합 패턴 )&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;unsigned active_threads = __activemask();&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;__syncwarp(active_threads);&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;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;h1 data-end=&quot;2972&quot; data-start=&quot;2957&quot; data-section-id=&quot;xupal&quot;&gt;&lt;span&gt;mask는 뭔가&lt;/span&gt;&lt;/h1&gt;
&lt;p data-end=&quot;3202&quot; data-start=&quot;2974&quot; data-ke-size=&quot;size16&quot;&gt;__syncwarp(mask)의 mask는 &lt;b&gt;어떤 lane들이 이 sync에 참여하는지 나타내는 32-bit 비트마스크&lt;/b&gt;다.&lt;br /&gt;강의자료는 __activemask()도 같이 소개하는데, 이 함수는 &lt;b&gt;현재 calling warp에서 active한 thread들의 32-bit mask&lt;/b&gt;를 반환한다. n번째 lane이 active면 n번째 bit가 1이다. inactive lane은 0이다.&lt;/p&gt;
&lt;p data-end=&quot;3221&quot; data-start=&quot;3204&quot; data-ke-size=&quot;size16&quot;&gt;그래서 보통 이런 식으로 쓴다.&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;&amp;nbsp;&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;div&gt;&lt;span&gt;unsigned&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;active_threads&lt;/span&gt;&lt;span&gt; = &lt;/span&gt;&lt;span&gt;__activemask&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;br /&gt;&lt;span&gt;__syncwarp&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;active_threads&lt;/span&gt;&lt;span&gt;);&lt;/span&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;3309&quot; data-start=&quot;3305&quot; data-ke-size=&quot;size16&quot;&gt;의미는:&lt;/p&gt;
&lt;blockquote data-end=&quot;3360&quot; data-start=&quot;3311&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;3360&quot; data-start=&quot;3313&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;지금 실제로 active한 lane들만 기준으로 warp barrier를 걸자&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-end=&quot;3390&quot; data-start=&quot;3362&quot; data-ke-size=&quot;size16&quot;&gt;이다. 강의자료도 이 사용 예를 그대로 보여준다.&lt;/p&gt;
&lt;p data-end=&quot;3390&quot; data-start=&quot;3362&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;3390&quot; data-start=&quot;3362&quot; data-ke-size=&quot;size16&quot;&gt;그니까 쉽게 말해서 &quot; &lt;b&gt;현재 active인 쓰레드끼리만 sync하겠다 &quot; 라는 뜻이다.&amp;nbsp;&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;3390&quot; data-start=&quot;3362&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜 이게 유용하냐면, 상황에 따라 warp 32개 중 일부만 살아있는 경우가 있거든:&lt;/p&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;&amp;nbsp;&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;pre class=&quot;reasonml&quot; style=&quot;color: #14181f;&quot;&gt;&lt;code&gt;if (threadIdx.x &amp;lt; 24) {
    // lane 0~23만 여기 진입
    shmem[threadIdx.x] = compute_something();

    // 여기서 __syncwarp() 기본값(0xFFFFFFFF)을 쓰면?
    // &amp;rarr; lane 24~31도 여기 도달하길 기다림
    // &amp;rarr; 근데 걔들은 else branch에 있어서 영원히 안 옴
    // &amp;rarr; DEADLOCK 또는 UNDEFINED BEHAVIOR!

    // 올바른 방법:
    unsigned active = __activemask();    // 0x00FFFFFF
    __syncwarp(active);                  // 0~23끼리만 sync
    
    result = shmem[threadIdx.x ^ 1];    // 안전하게 이웃 값 읽기
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;3390&quot; data-start=&quot;3362&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;3390&quot; data-start=&quot;3362&quot; data-ke-size=&quot;size16&quot;&gt;다음과 같다.&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;3390&quot; data-start=&quot;3362&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;3390&quot; data-start=&quot;3362&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;3390&quot; data-start=&quot;3362&quot; data-ke-size=&quot;size16&quot;&gt;** 의문점. 그러면 어떤식으로 __activemask() 활성화를 아는거지 ?&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;3390&quot; data-start=&quot;3362&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;3390&quot; data-start=&quot;3362&quot; data-ke-size=&quot;size16&quot;&gt;( with claude )&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;3390&quot; data-start=&quot;3362&quot; data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 미리 예측하는 게 아니라, 호출하는 바로 그 순간의 하드웨어 상태를 읽는 것.&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;하드웨어가 관리하는 active mask&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Warp Scheduler는 항상 warp 내 32개 lane 각각이 active인지 inactive인지를 &lt;b&gt;하드웨어 레지스터로 추적&lt;/b&gt;하고 있어. 이건 프로그래머가 만드는 게 아니라 하드웨어가 실시간으로 관리하는 거야.&lt;/p&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;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;yaml&quot; style=&quot;color: #14181f;&quot;&gt;&lt;code&gt;Warp Scheduler 내부 상태 (항상 존재):

lane:   0  1  2  3  4  5  ... 30 31
state:  1  1  1  0  0  1  ...  1  0
        &amp;uarr;                       &amp;uarr;
      active                 inactive&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;if문을 만나면 하드웨어가 조건 평가 결과에 따라 이 mask를 자동으로 갱신해:&lt;/p&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;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;angelscript&quot; style=&quot;color: #14181f;&quot;&gt;&lt;code&gt;if (threadIdx.x &amp;lt; 16) {
    // 하드웨어가 자동으로:
    // lane 0~15 &amp;rarr; active
    // lane 16~31 &amp;rarr; inactive (다른 branch path)
    
    // 이 시점에서 __activemask() 호출하면
    // 하드웨어가 &quot;지금 내 active mask 읽어줘&quot; &amp;rarr; 0x0000FFFF 반환
}
```

## `__activemask()`는 그냥 스냅샷

`__activemask()`가 하는 일은 딱 하나야: **&quot;하드웨어야, 지금 이 warp의 active mask 값 좀 알려줘&quot;** &amp;rarr; 그 순간의 값을 32-bit int로 반환. 끝.
```
__activemask()의 동작:

1. 하드웨어 active mask 레지스터 읽기
2. 그 값을 unsigned int로 반환
3. 끝. 다른 거 없음.&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 &lt;b&gt;같은 코드 줄이라도 호출 시점에 따라 값이 다를 수 있다&lt;/b&gt;는 거야. 하드웨어 상태는 매 순간 바뀌니까.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;비유하자면&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;카페에서 &quot;지금 이 방에 누가 있어?&quot; 하고 사진을 찍는 거랑 같아. 사진 찍는 순간 방에 있는 사람만 찍히지, 1분 후에 들어올 사람은 안 찍혀. __activemask()도 마찬가지로, &lt;b&gt;호출하는 그 clock cycle에 active인 쓰레드만&lt;/b&gt; 반환하는 거야. 곧 도착할 쓰레드는 모르고, 미리 예측하지도 않아.&lt;/p&gt;
&lt;p data-end=&quot;3390&quot; data-start=&quot;3362&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;3390&quot; data-start=&quot;3362&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;3390&quot; data-start=&quot;3362&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;q.&lt;/p&gt;
&lt;p style=&quot;background-color: #f0eee6; color: #141413; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;으응.. 엥 ? 그러면 알수가 없는거 아니야 ? 그니까 하드웨어가 activemask() 호출을 할때&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #f0eee6; color: #141413; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;만약에 1 , 2 번만 active 였는데 나중에 3번도 사실은 active 일수도 있잖아 ( thread 연산 차이가 나면 ? )&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #f0eee6; color: #141413; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;맞아, 정확히 그거야. 그게 바로 __activemask()의 한계인 거야.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;네가 말한 상황 그대로&lt;/h2&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;코드: 분기 없음, 32개 쓰레드 전부 같은 path

하드웨어 실행 상태 (어떤 시점):
  lane 0: ██████ __activemask() 호출 시점 &amp;larr; 여기
  lane 1: ██████ __activemask() 호출 시점 &amp;larr; 여기
  lane 2: █████░ &amp;larr; 아직 이전 연산 처리 중
  lane 3: ████░░ &amp;larr; 더 느림

  __activemask() 반환값: 0x...0011  (lane 0,1만)
  
  실제로는 lane 2,3도 곧 도착할 건데, 
  이 시점에선 &quot;아직 안 왔으니까 inactive&quot;로 찍힘
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;네 말이 100% 맞아.&lt;/b&gt; 그래서 __activemask()는 &quot;지금 누가 있냐&quot;는 알려주지만, &quot;누가 있어야 하냐&quot;는 모르는 거야.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;그럼 __activemask()는 언제 믿을 수 있어?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;확실하게 믿을 수 있는 경우는 딱 하나: branch 안에서.&lt;/b&gt; if문으로 갈라진 상황에서는 하드웨어가 조건 평가를 통해 &quot;이 branch에 속하는 쓰레드&quot;를 &lt;b&gt;정확히&lt;/b&gt; 결정했으니까:&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;if (threadIdx.x &amp;lt; 16) {
    // 여기 들어온 건 확실히 lane 0~15
    // 16~31은 else에 있으니 절대 안 옴
    unsigned mask = __activemask();  // 0x0000FFFF &amp;larr; 믿을 수 있음
    __syncwarp(mask);                // 안전
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이건 &quot;연산 속도 차이로 늦게 도착&quot;이 아니라 **&quot;조건에 의해 구조적으로 여기 안 오는 것&quot;**이니까, active mask가 정확해.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;믿을 수 없는 경우: 분기 없는 코드&lt;/h2&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;// 분기 없음 &amp;mdash; 32개 전부 같은 path
shmem[threadIdx.x] = val;
unsigned mask = __activemask();  // &amp;larr; 0xFFFFFFFF가 아닐 수 있음!
__syncwarp(mask);                // &amp;larr; 일부 쓰레드를 빠뜨릴 수 있음
result = shmem[threadIdx.x + 1]; // &amp;larr; 위험!
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 경우는 그냥 mask를 직접 써:&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;shmem[threadIdx.x] = val;
__syncwarp(0xFFFFFFFF);          // &quot;32개 전부 기다려&quot; &amp;mdash; 확실
result = shmem[threadIdx.x + 1]; // 안전
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;정리&lt;/h2&gt;
&lt;pre class=&quot;sqf&quot;&gt;&lt;code&gt;__activemask() 신뢰도:

  branch 내부에서 사용    &amp;rarr; 신뢰 가능 (구조적으로 active set 확정)
  분기 없는 코드에서 사용  &amp;rarr; 신뢰 불가 (Independent Thread Scheduling 때문)

결론:
  &quot;누가 참여해야 하는지&quot; 프로그래머가 아는 상황이면
  &amp;rarr; mask를 직접 지정하는 게 더 안전
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;네가 짚은 포인트가 정확히 __activemask()의 근본적 한계야.&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;/div&gt;
&lt;/div&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;( mask 규칙: Each calling thread must have its own bit set in the mask and all non-exited threads named in mask must execute a corresponding __syncwarp() with the same mask, or the result is undefined. )&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;1. 자기 bit 가 mask 에 켜져 있어야함 ( 당연하게도 )&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. mask에 지정된 모든 non-exited 쓰레드가 동일한 mask로 호출해야 함&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;다만 __activemask() 가 위험성이 있다.&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;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;//&amp;nbsp;divergence&amp;nbsp;없는&amp;nbsp;코드인데도: &lt;br /&gt;unsigned&amp;nbsp;mask&amp;nbsp;=&amp;nbsp;__activemask(); &lt;br /&gt;//&amp;nbsp;Volta&amp;nbsp;이후에는&amp;nbsp;일부&amp;nbsp;쓰레드가&amp;nbsp;다른&amp;nbsp;속도로&amp;nbsp;진행&amp;nbsp;중일&amp;nbsp;수&amp;nbsp;있어서 &lt;br /&gt;//&amp;nbsp;mask가&amp;nbsp;반드시&amp;nbsp;0xFFFFFFFF라는&amp;nbsp;보장이&amp;nbsp;없음! &lt;br /&gt;``` &lt;br /&gt;&lt;br /&gt;그래서&amp;nbsp;NVIDIA&amp;nbsp;공식&amp;nbsp;가이드에서는&amp;nbsp;`__activemask()`를&amp;nbsp;sync&amp;nbsp;목적으로&amp;nbsp;쓰는&amp;nbsp;걸&amp;nbsp;신중하게&amp;nbsp;하라고&amp;nbsp;해.&amp;nbsp;확실한&amp;nbsp;동기화가&amp;nbsp;필요하면&amp;nbsp;**프로그래머가&amp;nbsp;mask를&amp;nbsp;직접&amp;nbsp;계산**해서&amp;nbsp;넘기는&amp;nbsp;게&amp;nbsp;더&amp;nbsp;안전한&amp;nbsp;경우도&amp;nbsp;있어. &lt;br /&gt;&lt;br /&gt;##&amp;nbsp;정리 &lt;br /&gt;``` &lt;br /&gt;__activemask() &lt;br /&gt;├──&amp;nbsp;역할:&amp;nbsp;현재&amp;nbsp;active&amp;nbsp;쓰레드&amp;nbsp;조회&amp;nbsp;(read-only,&amp;nbsp;상태&amp;nbsp;변경&amp;nbsp;없음) &lt;br /&gt;├──&amp;nbsp;반환:&amp;nbsp;32-bit&amp;nbsp;mask&amp;nbsp;(bit&amp;nbsp;n&amp;nbsp;=&amp;nbsp;1이면&amp;nbsp;lane&amp;nbsp;n이&amp;nbsp;active) &lt;br /&gt;├──&amp;nbsp;용도:&amp;nbsp;__syncwarp()에&amp;nbsp;넘길&amp;nbsp;mask&amp;nbsp;생성 &lt;br /&gt;├──&amp;nbsp;장점:&amp;nbsp;branch&amp;nbsp;안에서&amp;nbsp;&quot;나랑&amp;nbsp;같이&amp;nbsp;있는&amp;nbsp;애들끼리만&amp;nbsp;sync&quot;&amp;nbsp;가능 &lt;br /&gt;└──&amp;nbsp;주의:&amp;nbsp;Volta&amp;nbsp;이후&amp;nbsp;동일&amp;nbsp;코드&amp;nbsp;위치에서도&amp;nbsp;시점에&amp;nbsp;따라&amp;nbsp;값이&amp;nbsp;달라질&amp;nbsp;수&amp;nbsp;있음 &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;rarr;&amp;nbsp;확실한&amp;nbsp;sync가&amp;nbsp;필요하면&amp;nbsp;mask를&amp;nbsp;직접&amp;nbsp;계산하는&amp;nbsp;것도&amp;nbsp;고려&lt;/p&gt;
&lt;/div&gt;
&lt;/div&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;다시 이전에 본 예제로 돌아오면&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;970&quot; data-origin-height=&quot;636&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cj8tVD/dJMcag5VBGN/6AKaONAsZx7fKrPrLrYFT0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cj8tVD/dJMcag5VBGN/6AKaONAsZx7fKrPrLrYFT0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cj8tVD/dJMcag5VBGN/6AKaONAsZx7fKrPrLrYFT0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcj8tVD%2FdJMcag5VBGN%2F6AKaONAsZx7fKrPrLrYFT0%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;703&quot; height=&quot;461&quot; data-origin-width=&quot;970&quot; data-origin-height=&quot;636&quot;/&gt;&lt;/span&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;이제는 훨씬 오른쪽 코드의 의미가 분명해졌다.&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;id&amp;lt;64 까지는 여러 warp 가 관여하기 때문에 synthreads() 로 관리를 한 것이고 ( block-wise sync )&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;id &amp;lt;32 부터는 warp 0 하나만 관여 하기 때문에 block 전체를 기다릴 필요 없이 warp 내부만 맞추면 된다.&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;&amp;nbsp;&lt;/p&gt;
&lt;p 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;h1 data-end=&quot;5198&quot; data-start=&quot;5163&quot; data-section-id=&quot;1m0q3q5&quot;&gt;&lt;span&gt;__syncwarp()를 쓸 때 지켜야 하는 규칙&lt;/span&gt;&lt;/h1&gt;
&lt;p data-end=&quot;5243&quot; data-start=&quot;5200&quot; data-ke-size=&quot;size16&quot;&gt;강의자료와 Programming Guide 둘 다 아주 중요한 제약을 말한다.&lt;/p&gt;
&lt;h3 data-end=&quot;5256&quot; data-start=&quot;5245&quot; data-section-id=&quot;1my84gu&quot; data-ke-size=&quot;size23&quot;&gt;강의자료 요약&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;5448&quot; data-start=&quot;5257&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;5307&quot; data-start=&quot;5257&quot; data-section-id=&quot;8o4l62&quot;&gt;각 calling thread는 자기 own bit가 mask에 set되어 있어야 한다&lt;/li&gt;
&lt;li data-end=&quot;5386&quot; data-start=&quot;5308&quot; data-section-id=&quot;1gs432s&quot;&gt;mask에 포함된 모든 non-exited thread는 **같은 mask 값으로 대응되는 __syncwarp()**를 실행해야 한다&lt;/li&gt;
&lt;li data-end=&quot;5448&quot; data-start=&quot;5387&quot; data-section-id=&quot;xhgxr9&quot;&gt;아니면 결과는 undefined다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;5485&quot; data-start=&quot;5450&quot; data-section-id=&quot;1858gll&quot; data-ke-size=&quot;size23&quot;&gt;Programming Guide가 더 자세히 말하는 조건&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;5756&quot; data-start=&quot;5486&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;5520&quot; data-start=&quot;5486&quot; data-section-id=&quot;119v5cw&quot;&gt;calling thread가 mask에 포함되어 있어야 함&lt;/li&gt;
&lt;li data-end=&quot;5594&quot; data-start=&quot;5521&quot; data-section-id=&quot;rkhddn&quot;&gt;mask에 포함된 non-exited thread는 결국 같은 program point에서 같은 intrinsic을 호출해야 함&lt;/li&gt;
&lt;li data-end=&quot;5656&quot; data-start=&quot;5595&quot; data-section-id=&quot;167788&quot;&gt;conditional code 안이라면, mask에 포함된 thread들에 대해 조건 평가가 일관되어야 함&lt;/li&gt;
&lt;li data-end=&quot;5756&quot; data-start=&quot;5657&quot; data-section-id=&quot;ewz430&quot;&gt;disjoint한 mask라면 서로 다른 warp sync intrinsics를 동시에 써도 가능하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;5770&quot; data-start=&quot;5758&quot; data-ke-size=&quot;size16&quot;&gt;즉 아주 쉽게 말하면:&lt;/p&gt;
&lt;blockquote data-end=&quot;5818&quot; data-start=&quot;5772&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;5818&quot; data-start=&quot;5774&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;같이 기다리기로 한 lane들은, 진짜 다 같은 약속 장소로 와야 한다.&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-end=&quot;5896&quot; data-start=&quot;5820&quot; data-ke-size=&quot;size16&quot;&gt;누군가 mask에 이름이 올라가 있는데 안 오면,&lt;br /&gt;barrier semantics가 깨져서 undefined behavior가 난다.&lt;/p&gt;
&lt;hr data-end=&quot;5901&quot; data-start=&quot;5898&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h1 data-end=&quot;5927&quot; data-start=&quot;5903&quot; data-section-id=&quot;1etks&quot;&gt;11) 잘못 쓰는 예를 감으로 이해해보자&lt;/h1&gt;
&lt;p data-end=&quot;5947&quot; data-start=&quot;5929&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어 이런 상황은 위험하다.&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;&amp;nbsp;&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;div&gt;&lt;span&gt;unsigned&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;mask&lt;/span&gt;&lt;span&gt; = &lt;/span&gt;&lt;span&gt;0xffffffff&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;lane&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;16&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;br /&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;__syncwarp&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;mask&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span&gt;}&lt;/span&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;6038&quot; data-start=&quot;6030&quot; data-ke-size=&quot;size16&quot;&gt;왜 위험하냐면:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;6096&quot; data-start=&quot;6040&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;6065&quot; data-start=&quot;6040&quot; data-section-id=&quot;pbb9in&quot;&gt;mask는 32 lane 전부를 포함하는데&lt;/li&gt;
&lt;li data-end=&quot;6096&quot; data-start=&quot;6066&quot; data-section-id=&quot;a0jfak&quot;&gt;실제로 호출하는 건 0~15 lane뿐이기 때문이다&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;6247&quot; data-start=&quot;6098&quot; data-ke-size=&quot;size16&quot;&gt;그러면 16~31 lane은 barrier에 안 오는데, mask에는 포함되어 있으니 조건이 안 맞는다.&lt;br /&gt;이런 류는 Programming Guide 기준으로 invalid/undefined다.&lt;/p&gt;
&lt;p data-end=&quot;6268&quot; data-start=&quot;6249&quot; data-ke-size=&quot;size16&quot;&gt;반대로 이런 구조는 더 자연스럽다.&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;&amp;nbsp;&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;div&gt;&lt;span&gt;unsigned&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;mask&lt;/span&gt;&lt;span&gt; = &lt;/span&gt;&lt;span&gt;__activemask&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;br /&gt;&lt;span&gt;__syncwarp&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;mask&lt;/span&gt;&lt;span&gt;);&lt;/span&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;6432&quot; data-start=&quot;6332&quot; data-ke-size=&quot;size16&quot;&gt;혹은 divergence된 두 집단이 &lt;b&gt;서로 disjoint mask&lt;/b&gt;를 써서 각각 sync하는 형태다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&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;h2 data-ke-size=&quot;size26&quot;&gt;Extensions to the Classical CUDA Execution Model: Grid Synchronization Using Cooperative Groups (Volta/CC 7.0)&amp;nbsp;&lt;/h2&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;971&quot; data-origin-height=&quot;647&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vkVll/dJMcafeUxtd/em9yPE5A5KQS4PO0381xkk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vkVll/dJMcafeUxtd/em9yPE5A5KQS4PO0381xkk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vkVll/dJMcafeUxtd/em9yPE5A5KQS4PO0381xkk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvkVll%2FdJMcafeUxtd%2Fem9yPE5A5KQS4PO0381xkk%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;711&quot; height=&quot;474&quot; data-origin-width=&quot;971&quot; data-origin-height=&quot;647&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Classical CUDA 모델에서는 동기화에 두 가지 한계가 있었어:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Block 내부만 동기화 가능:&lt;/b&gt; __syncthreads()는 하나의 thread block 안의 thread들끼리만 barrier 동기화를 걸 수 있었다.. 서로 다른 block 간에는 동기화 수단이 전혀 없었다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Grid 전체 동기화 = kernel 종료:&lt;/b&gt; Grid 내 모든 thread block이 특정 지점까지 실행됐는지 보장하려면, kernel을 아예 끝내고 새 kernel을 launch하는 수밖에 없었다. 이건 커널 launch overhead가 크기 때문에 비효율적이다.&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;Cooperative Groups 를 쓰면 조건부로 grid 전체 block 까지 한번에 동기화가 가능해진다.&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;b&gt; &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;Cooperative Groups&lt;span&gt;&amp;nbsp; 이란 ?&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Cooperative Groups&lt;/b&gt;는 CUDA C++에서&lt;br /&gt;&amp;ldquo;협력하는 thread들의 그룹&amp;rdquo;을 명시적으로 다루는 기능이다.&lt;br /&gt;이걸 쓰면 &lt;b&gt;커널을 끝내지 않고도&lt;/b&gt; 특정 범위의 thread들을 동기화할 수 있다.&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;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;863&quot; data-start=&quot;823&quot; data-section-id=&quot;1hnor1d&quot;&gt;&lt;b&gt;tiled partition&lt;/b&gt;: block 내부의 더 작은 그룹&lt;/li&gt;
&lt;li data-end=&quot;901&quot; data-start=&quot;864&quot; data-section-id=&quot;dkkhh7&quot;&gt;&lt;b&gt;thread block group&lt;/b&gt;: 현재 block 전체&lt;/li&gt;
&lt;li data-end=&quot;934&quot; data-start=&quot;902&quot; data-section-id=&quot;1fnem0g&quot;&gt;&lt;b&gt;grid group&lt;/b&gt;: grid 전체 block들&lt;/li&gt;
&lt;li data-end=&quot;976&quot; data-start=&quot;935&quot; data-section-id=&quot;1bv9msl&quot;&gt;&lt;b&gt;cluster group&lt;/b&gt;: Hopper에서의 cluster 단위&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;여기서 Grid synchornization 파트만 조금 더 자세히 본다.&amp;nbsp;&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;940&quot; data-origin-height=&quot;555&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bnreR1/dJMcabwLbX9/6hGZmCWw9fTsXIPg3JLlsK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bnreR1/dJMcabwLbX9/6hGZmCWw9fTsXIPg3JLlsK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bnreR1/dJMcabwLbX9/6hGZmCWw9fTsXIPg3JLlsK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbnreR1%2FdJMcabwLbX9%2F6hGZmCWw9fTsXIPg3JLlsK%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;664&quot; height=&quot;392&quot; data-origin-width=&quot;940&quot; data-origin-height=&quot;555&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;grid-levl synchoronziation&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CG 를 쓰면 grid 전체 block 들이 커널 안에서 만나서 barrier 를 걸 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;별거 없고 앞에서 이야기 했던 barrier 의 기준이 thread block 간으로 바뀌었다고 보면 된다.&amp;nbsp;&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;span style=&quot;background-color: #f3c000;&quot;&gt;** 중요한 조건이 있다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;co-residency contraint 인데&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;grid sync 를 하려면 해당 grid 의 &quot;모든&quot; block 이 동시에 GPU 에 올라와 있어야 한다 &quot; ( 중요 )&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그니까 GPU 에 올라와 있어야 한다는 말은 즉 , SM 에 있어야 한다는 말인데. 이게 매우 어렵다.&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: disc;&quot; data-end=&quot;1928&quot; data-start=&quot;1870&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1901&quot; data-start=&quot;1870&quot; data-section-id=&quot;5mu94m&quot;&gt;GPU가 동시에 올릴 수 있는 block 수: 20개&lt;/li&gt;
&lt;li data-end=&quot;1928&quot; data-start=&quot;1902&quot; data-section-id=&quot;m1nq4r&quot;&gt;네가 launch한 block 수: 100개&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;2019&quot; data-start=&quot;1930&quot; data-ke-size=&quot;size16&quot;&gt;그러면 처음엔 20개만 resident 상태다.&lt;br /&gt;그런데 이 20개가 먼저 grid.sync()에 도착하면, 나머지 80개도 barrier에 와야 풀린다.&lt;/p&gt;
&lt;p data-end=&quot;2025&quot; data-start=&quot;2021&quot; data-ke-size=&quot;size16&quot;&gt;문제는:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2115&quot; data-start=&quot;2026&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2055&quot; data-start=&quot;2026&quot; data-section-id=&quot;bpj64d&quot;&gt;먼저 도착한 20개가 SM 자리를 차지하고 기다림&lt;/li&gt;
&lt;li data-end=&quot;2084&quot; data-start=&quot;2056&quot; data-section-id=&quot;1tcls4p&quot;&gt;아직 실행도 못 한 80개는 올라올 자리가 없음&lt;/li&gt;
&lt;li data-end=&quot;2115&quot; data-start=&quot;2085&quot; data-section-id=&quot;gbtcb2&quot;&gt;결국 서로 기다리기만 하면서 &lt;b&gt;deadlock&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;2122&quot; data-start=&quot;2117&quot; data-ke-size=&quot;size16&quot;&gt;그래서 block 간 동기화를 위해서는 반드시 모든 block 이 SM 에 올라와 있어야 한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2122&quot; data-start=&quot;2117&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2122&quot; data-start=&quot;2117&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2122&quot; data-start=&quot;2117&quot; data-ke-size=&quot;size16&quot;&gt;그러면 과연 큰 데이터셋에서는 어떻게 잘 돌려볼 만한 방법이 없을까 ?&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2122&quot; data-start=&quot;2117&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2122&quot; data-start=&quot;2117&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Grid-stride loop&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;2122&quot; data-start=&quot;2117&quot; data-ke-size=&quot;size16&quot;&gt;큰 데이터셋을 -&amp;gt; 적은 수의 block 으로 나눈 다음에 처리한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2122&quot; data-start=&quot;2117&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2122&quot; data-start=&quot;2117&quot; data-ke-size=&quot;size16&quot;&gt;그러니까 원래 큰 데이터면 보통 block 수를 엄청 많이 launch 하고 싶어하는데 , grid sync 쓰려면 block 이 다 올라와 있어야 한다. 그래서&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2122&quot; data-start=&quot;2117&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2122&quot; data-start=&quot;2117&quot; data-ke-size=&quot;size16&quot;&gt;block 수를 launch 할 수 있는 만큼 작게 유지하고&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2122&quot; data-start=&quot;2117&quot; data-ke-size=&quot;size16&quot;&gt;대신 각 thread 가 여러 원소를 반복 처리한다. ( 작게 잘라서 )&amp;nbsp;&lt;/p&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;p data-end=&quot;2122&quot; data-start=&quot;2117&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-end=&quot;2122&quot; data-start=&quot;2117&quot; data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-end=&quot;2122&quot; data-start=&quot;2117&quot; data-ke-size=&quot;size26&quot;&gt;Extensions to the Classical CUDA Execution Model: Thread Block Cluster (Hopper/CC 9.0)&amp;nbsp;&lt;/h2&gt;
&lt;p data-end=&quot;2122&quot; data-start=&quot;2117&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2122&quot; data-start=&quot;2117&quot; data-ke-size=&quot;size16&quot;&gt;방금 위에서 말했던 예외 말고도 thread block 을 동기화 할 수 있는 방법이 한개 더있다.&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;494&quot; data-origin-height=&quot;230&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cqUWDQ/dJMcabwLb2Q/yalAKdUOYLd9v1DnZEAJ00/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cqUWDQ/dJMcabwLb2Q/yalAKdUOYLd9v1DnZEAJ00/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cqUWDQ/dJMcabwLb2Q/yalAKdUOYLd9v1DnZEAJ00/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcqUWDQ%2FdJMcabwLb2Q%2FyalAKdUOYLd9v1DnZEAJ00%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;494&quot; height=&quot;230&quot; data-origin-width=&quot;494&quot; data-origin-height=&quot;230&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-end=&quot;2122&quot; data-start=&quot;2117&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2122&quot; data-start=&quot;2117&quot; data-ke-size=&quot;size16&quot;&gt;cc 9.0 부터 Thread Block Cluster 라는 중간 계층 ( optional hierarchy ) 가 추가 되었다. 원래&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2122&quot; data-start=&quot;2117&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;grid&lt;/span&gt;&lt;br /&gt;&lt;span&gt; └─ thread block&lt;/span&gt;&lt;br /&gt;&lt;span&gt; └─ thread&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-end=&quot;2122&quot; data-start=&quot;2117&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2122&quot; data-start=&quot;2117&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이런 계층이였다면&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-end=&quot;2122&quot; data-start=&quot;2117&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2122&quot; data-start=&quot;2117&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;grid&lt;/span&gt;&lt;br /&gt;&lt;span&gt; └─ thread block cluster &amp;lt;- optional&lt;/span&gt;&lt;br /&gt;&lt;span&gt; └─ thread block&lt;/span&gt;&lt;br /&gt;&lt;span&gt; └─ thread&lt;/span&gt;&lt;/p&gt;
&lt;p data-end=&quot;2122&quot; data-start=&quot;2117&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2122&quot; data-start=&quot;2117&quot; data-ke-size=&quot;size16&quot;&gt;이런식으로 하나 더생겼다고 한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2122&quot; data-start=&quot;2117&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2122&quot; data-start=&quot;2117&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2122&quot; data-start=&quot;2117&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2122&quot; data-start=&quot;2117&quot; data-ke-size=&quot;size16&quot;&gt;예외는 그냥 그정도가 있다 ! 정도로 알고 넘어가도 당장은 큰 지장은 없어보이긴 하나&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2122&quot; data-start=&quot;2117&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;965&quot; data-origin-height=&quot;616&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dnfod0/dJMb99Z3BdW/GhOBVNYu6rHzwZpngYZcPK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dnfod0/dJMb99Z3BdW/GhOBVNYu6rHzwZpngYZcPK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dnfod0/dJMb99Z3BdW/GhOBVNYu6rHzwZpngYZcPK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdnfod0%2FdJMb99Z3BdW%2FGhOBVNYu6rHzwZpngYZcPK%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;663&quot; height=&quot;423&quot; data-origin-width=&quot;965&quot; data-origin-height=&quot;616&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-end=&quot;2122&quot; data-start=&quot;2117&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2122&quot; data-start=&quot;2117&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2122&quot; data-start=&quot;2117&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2122&quot; data-start=&quot;2117&quot; data-ke-size=&quot;size16&quot;&gt;이제 진짜 진짜 마지막으로 마무리하고 이번 챕터는 끝내보도록 하겠다. 사실 크게 어려운 내용은 없으면서도&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2122&quot; data-start=&quot;2117&quot; data-ke-size=&quot;size16&quot;&gt;(&amp;nbsp; 오히려 시프같은 과목보다 양이 훨씬 적은것 같다 ) 원래 개념과 좀 다른 부분이 GPU 에 있어서 gpu 방식으로 생각하는게 약간 걸렸지만 , GPGPU 잘 따라 오다 보니까 확실히 GPU 에 대해서 이해도가 높아진거 같기는하다.&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2122&quot; data-start=&quot;2117&quot; data-ke-size=&quot;size16&quot;&gt;그래서 뭐 MAMBA 나 FLASH ATTENTION 같은 하드웨어 쪽과 붙어있는 논문을 읽을때도 확실히 이해가 많이 높아져서 좋다.&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2122&quot; data-start=&quot;2117&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2122&quot; data-start=&quot;2117&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-end=&quot;2122&quot; data-start=&quot;2117&quot; data-ke-size=&quot;size26&quot;&gt;Important Notes&amp;nbsp;&lt;/h2&gt;
&lt;p data-end=&quot;2122&quot; data-start=&quot;2117&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;935&quot; data-origin-height=&quot;456&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/m8TCT/dJMcacCsGhN/MgTd97ansNDCKRGkm8MviK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/m8TCT/dJMcacCsGhN/MgTd97ansNDCKRGkm8MviK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/m8TCT/dJMcacCsGhN/MgTd97ansNDCKRGkm8MviK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fm8TCT%2FdJMcacCsGhN%2FMgTd97ansNDCKRGkm8MviK%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;935&quot; height=&quot;456&quot; data-origin-width=&quot;935&quot; data-origin-height=&quot;456&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;910&quot; data-origin-height=&quot;559&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nwqB5/dJMcabp13YH/r8PbFY8YZhWrzPhpZAdQ51/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nwqB5/dJMcabp13YH/r8PbFY8YZhWrzPhpZAdQ51/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nwqB5/dJMcabp13YH/r8PbFY8YZhWrzPhpZAdQ51/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnwqB5%2FdJMcabp13YH%2Fr8PbFY8YZhWrzPhpZAdQ51%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;910&quot; height=&quot;559&quot; data-origin-width=&quot;910&quot; data-origin-height=&quot;559&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-end=&quot;2122&quot; data-start=&quot;2117&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;h2 data-ke-size=&quot;size26&quot;&gt;Q1: Warp 내 32개 thread가 항상 같은 instruction을 실행하는가?&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Before Volta (CC &amp;lt; 7.0): Yes&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Warp 전체가 &lt;b&gt;PC 하나를 공유&lt;/b&gt;하고 lock-step으로 진행했어. Branch divergence가 발생하면 한쪽을 먼저 실행하고, 다른 쪽은 &lt;b&gt;thread masking&lt;/b&gt;으로 비활성화시켜서 순차 처리했지.&lt;/p&gt;
&lt;pre class=&quot;tp&quot;&gt;&lt;code&gt;if (threadIdx.x &amp;lt; 16) { A; B; }
else                  { X; Y; }
P; Q;

[Pre-Volta 실행 타임라인]

           time ──────────────────────►
thread 0~15:   ██ A ██ B ██ stall ██ P ██ Q ██
thread 16~31:  ██ stall ██ X ██ Y ██ P ██ Q ██
                         &amp;uarr;              &amp;uarr;
                      diverge       reconverge

&amp;rarr; 한 시점에 active한 쪽만 실행, 나머지는 놀고 있음
&amp;rarr; 대신 lock-step이니까 reconverge 후 warp 내 동기화가 &quot;암묵적으로&quot; 보장됨
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Since Volta (CC 7.0+): No&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 thread가 &lt;b&gt;개별 PC + 개별 call stack&lt;/b&gt;을 갖게 됨. Divergent branch의 양쪽이 &lt;b&gt;interleave&lt;/b&gt;되어 실행될 수 있어서 효율이 올라갔어.&lt;/p&gt;
&lt;pre class=&quot;tp&quot;&gt;&lt;code&gt;[Since Volta 실행 타임라인]

           time ──────────────────────►
thread 0~15:   ██ A ██ B ██ P ██ ??? ██ Q ██
thread 16~31:  ██ X ██ Y ██ P ██ ??? ██ Q ██
                                  &amp;uarr;
                    여기서 다른 thread의 P 결과가 보장 안 됨!
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;효율은 좋아졌지만, 대가로 &lt;b&gt;암묵적 동기화 보장이 깨졌어&lt;/b&gt;. Q에서 다른 thread가 P까지 계산한 결과를 읽어야 한다면, 반드시 명시적 동기화를 넣어야 해:&lt;/p&gt;
&lt;pre class=&quot;abnf&quot;&gt;&lt;code&gt;P;
__syncwarp();   // &amp;larr; 이거 없으면 다른 thread의 P 결과를 못 볼 수 있음
Q;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;__syncwarp() 외에 __shfl_up_sync() 같은 _sync suffix intrinsic들도 암묵적으로 warp 동기화를 포함하고 있어.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Q2: Grid 내 thread block들끼리 동기화할 수 있는가?&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Default: No&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 thread block은 &lt;b&gt;논리적으로 독립&lt;/b&gt; 실행돼. 어떤 block이 어떤 SM에 언제 배정될지 알 수 없고, block 간 실행 순서도 보장 안 돼. 전체 block이 공통 지점에 도달했음을 보장하는 유일한 방법은 &lt;b&gt;kernel을 종료&lt;/b&gt;하는 것뿐이야.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Exception 1: Cooperative Groups (CC 7.0+)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;grid.sync()로 &lt;b&gt;kernel 종료 없이&lt;/b&gt; grid 전체를 동기화할 수 있어. 단, &lt;b&gt;모든 block이 동시에 SM에 상주(co-residency)&lt;/b&gt; 해야 하기 때문에, block 수가 GPU가 동시에 수용 가능한 수를 넘으면 사용 불가.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Exception 2: Thread Block Cluster (CC 9.0+)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;cluster.sync()로 &lt;b&gt;같은 GPC에 co-schedule된 cluster 내 block들(최대 8개)&lt;/b&gt; 만 동기화. Grid 전체가 아닌 부분 동기화라 co-residency 제약이 훨씬 가벼움. 추가로 cluster 내 block들은 서로의 shared memory에 접근 가능 (Distributed Shared Memory).&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;동기화 계층 요약&lt;/h2&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;범위        수단                  조건                     도입 시점
─────────────────────────────────────────────────────────────────
Warp 내     __syncwarp()         Volta부터 명시적 필요      CC 7.0
Block 내    __syncthreads()      항상 가능                  초기부터
Cluster 내  cluster.sync()       같은 GPC co-schedule      CC 9.0
Grid 전체   grid.sync()          전체 block co-residency   CC 7.0
Grid 간     kernel 종료 후 재launch   항상 가능              초기부터
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;핵심 메시지: Volta 이후로는 **&quot;암묵적 동기화에 의존하지 마라&quot;**가 원칙이고, 동기화 가능한 범위가 warp &amp;rarr; block &amp;rarr; cluster &amp;rarr; grid로 점점 확장되어 왔다는 흐름이야.&lt;/p&gt;
&lt;p data-end=&quot;2122&quot; data-start=&quot;2117&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2122&quot; data-start=&quot;2117&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2122&quot; data-start=&quot;2117&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2122&quot; data-start=&quot;2117&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2122&quot; data-start=&quot;2117&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2122&quot; data-start=&quot;2117&quot; 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;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;QnA&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Q. &lt;span style=&quot;background-color: #f0eee6; color: #141413; text-align: start;&quot;&gt; warp &amp;lt; thread block 인데 thread block 단위로 shared memory 쓸 수 있으니까 한 블럭안에 들어간 SM 끼리는 warp 끼리도 통신가능한거지 ?&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #f0eee6; color: #141413; text-align: start;&quot;&gt;&lt;/span&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;A.&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Thread Block &amp;rarr; SM 매핑은 N:1이 아니라 반대야.&lt;/b&gt; 하나의 thread block은 &lt;b&gt;하나의 SM에 통째로 할당&lt;/b&gt;돼. 쪼개져서 여러 SM에 분산되는 일은 없어. 반대로 하나의 SM은 리소스(레지스터, shared memory)가 허용하는 한 &lt;b&gt;여러 block을 동시에&lt;/b&gt; 들고 있을 수 있고.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 구조를 정리하면:&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;SM (하드웨어)
├── Block A (shared memory A)
│   ├── Warp 0  (thread 0~31)
│   ├── Warp 1  (thread 32~63)
│   └── ...
├── Block B (shared memory B)  &amp;larr; 같은 SM이지만 별도 shared memory
│   ├── Warp 0
│   └── ...
&lt;/code&gt;&lt;/pre&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;같은 block 안의 warp끼리&lt;/b&gt; &amp;mdash; shared memory로 통신 가능. __syncthreads()로 동기화도 됨. 네가 말한 게 이 경우라면 맞아.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;같은 SM에 올라간 다른 block의 warp끼리&lt;/b&gt; &amp;mdash; shared memory가 block 단위로 격리되어 있어서 &lt;b&gt;직접 통신 불가&lt;/b&gt;. 같은 SM 위에 물리적으로 같이 있어도 논리적으로는 완전히 독립이야.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 &quot;SM끼리 통신&quot;이라는 표현보다는, &lt;b&gt;block 내부에서 warp 간 shared memory 공유가 가능하다&lt;/b&gt;고 이해하는 게 정확해. SM은 그냥 block을 실행해주는 하드웨어 유닛이고, 프로그래머가 신경 쓰는 추상화 단위는 block과 grid야.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 줄 요약: &lt;b&gt;shared memory의 scope = thread block. warp가 아니라 block 기준으로 공유/격리가 결정돼.&lt;/b&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Q. 어떤 계산 같은 문제가 나올 것같은데 ( 그니까 뭐 grid 갯수 부터 해서 warp 어쩌구 저쩌구.. ) 이건 어떻게 할까&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;A. 족보가 나온다고 하니 그때 생각해보자. 개념을 우선으로 하고 시험기간에만 계산에 친숙해지는걸로&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;Q. 데이터가 같은데 명령이 다르면 ? WARP 로 못묶이나 ?&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;A.&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;4456&quot; data-start=&quot;4447&quot; data-ke-size=&quot;size16&quot;&gt;결론부터 말하면:&lt;/p&gt;
&lt;blockquote data-end=&quot;4579&quot; data-start=&quot;4458&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;4579&quot; data-start=&quot;4460&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;warp는 무조건 32-thread 묶음으로 만들어진다.&lt;/b&gt;&lt;br /&gt;문제는 &amp;ldquo;못 묶이는가&amp;rdquo;가 아니라,&lt;br /&gt;&lt;b&gt;같은 warp 안 thread들이 서로 다른 실행 경로를 가면 divergence가 생긴다&lt;/b&gt;는 것이다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-end=&quot;4667&quot; data-start=&quot;4581&quot; data-ke-size=&quot;size16&quot;&gt;즉 warp 생성은 block을 32개씩 자르는 기계적인 과정이다.&lt;br /&gt;명령어가 같을지 다를지는 &lt;b&gt;실행 도중 분기(if/else)&lt;/b&gt; 에서 문제가 된다.&lt;/p&gt;
&lt;p data-end=&quot;4845&quot; data-start=&quot;4669&quot; data-ke-size=&quot;size16&quot;&gt;Volta 이전 classical model에서는 warp가 한 번에 한 경로씩 실행하면서 다른 thread를 mask off했다. 강의자료도 warp 내 branch divergence 시 각 branch path를 따로 실행한다고 설명한다.&lt;/p&gt;
&lt;p data-end=&quot;4865&quot; data-start=&quot;4847&quot; data-ke-size=&quot;size16&quot;&gt;즉 네 질문에 대한 정확한 답은:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;4956&quot; data-start=&quot;4867&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;4913&quot; data-start=&quot;4867&quot; data-section-id=&quot;16r3kl1&quot;&gt;&amp;ldquo;명령어가 다르면 warp로 못 묶이나?&amp;rdquo; &amp;rarr; &lt;b&gt;아니오, 여전히 warp다&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;4956&quot; data-start=&quot;4914&quot; data-section-id=&quot;lspl2x&quot;&gt;대신 &amp;rarr; &lt;b&gt;효율이 나빠질 수 있다(branch divergence)&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>GPGPU</category>
      <author>Kim_sang_hyeob</author>
      <guid isPermaLink="true">https://ksh0416.tistory.com/160</guid>
      <comments>https://ksh0416.tistory.com/160#entry160comment</comments>
      <pubDate>Sat, 21 Mar 2026 23:10:07 +0900</pubDate>
    </item>
    <item>
      <title>[발표자료] Aligning Multimodal Representations through an Information Bottleneck</title>
      <link>https://ksh0416.tistory.com/159</link>
      <description>&lt;figure class=&quot;fileblock&quot; data-ke-align=&quot;alignCenter&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/lSs6V/dJMcafZ3ee2/dh5B3HNcnKnS6khviTbf4K/%EB%B0%9C%ED%91%9C%EC%9A%A9.pptx?attach=1&amp;amp;knm=tfile.pptx&quot; class=&quot;&quot;&gt;
    &lt;div class=&quot;image&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;desc&quot;&gt;&lt;div class=&quot;filename&quot;&gt;&lt;span class=&quot;name&quot;&gt;발표용.pptx&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;1.33MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;&lt;br&gt;&amp;nbsp;&lt;br&gt;결국 도메인 gap 을 줄이는데 ( 정확히는 align 할때 )&amp;nbsp;&lt;br&gt;문제점을 조금 더 파고드는게 중요하다는 생각이 들기는한다&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;1) 도메인 gap 을 줄이는 연구가 과연 아직 유효한가&amp;nbsp; ?&amp;nbsp;&lt;br&gt;-&amp;gt; 그렇긴하나 예전보다 더 세분화해서 봐야할 것 같다.&amp;nbsp;&lt;br&gt;&amp;nbsp;&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;global alignment&lt;/b&gt;는 좋아 보여도 &lt;b&gt;local pairwise alignment&lt;/b&gt;는 깨질 수 있음&lt;/li&gt;&lt;li&gt;modality-shared semantics와 modality-specific residue가 뒤엉켜 있을 수 있음&lt;/li&gt;&lt;li&gt;retrieval에는 좋은데 generation/grounding/transfer에는 안 좋을 수 있음&lt;/li&gt;&lt;li&gt;two-modal에서는 괜찮은데 multi-modal로 가면 conflict가 커질 수 있음&lt;/li&gt;&lt;li&gt;같은 contrastive model이어도 &lt;b&gt;uniformity, isotropy, spectral structure, effective rank&lt;/b&gt;가 다를 수 있음&lt;/li&gt;&lt;/ul&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;대략 이런문제는 남아있다고 한다 (정확히 리서치는 안해봄 )&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;2) CLIP 류 contrastive learnig 으로 뭘 더 해볼 수 있을까?&amp;nbsp;&amp;nbsp;&lt;/p&gt;&lt;h4 data-ke-size=&quot;size20&quot;&gt;(a) contrastive objective의 구조적 한계 분석&lt;/h4&gt;&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;&lt;li&gt;alignment vs uniformity trade-off&lt;/li&gt;&lt;li&gt;false negatives / semantic neighbors 문제&lt;/li&gt;&lt;li&gt;information asymmetry (image가 text보다 정보량이 많음)&lt;/li&gt;&lt;li&gt;dimension collapse / spectral collapse&lt;/li&gt;&lt;li&gt;cone effect, anisotropy, rank deficiency&lt;/li&gt;&lt;li&gt;pairwise alignment와 global distribution alignment의 불일치&lt;/li&gt;&lt;/ul&gt;&lt;h4 data-ke-size=&quot;size20&quot;&gt;(b) “contrastive만으로 충분한가?”를 묻는 연구&lt;/h4&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;최근 정리성 글들도 멀티모달 표현학습을 contrastive 하나로만 보지 않고, &lt;b&gt;generative objective, reconstruction, masking, distillation, modular disentanglement&lt;/b&gt;와 같이 보려는 흐름을 정리합니다. 예를 들어 survey 성격의 recent overview는 ImageBind, mPLUG-2, VALOR-L, InternVideo-L 같은 다양한 프레임을 함께 다루며, 멀티모달 representation learning이 이미 &lt;b&gt;contrastive-only 패러다임을 넘어서고 있다&lt;/b&gt;는 그림을 보여줍니다.&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;추후 읽어볼만한 논문&amp;nbsp;&lt;br&gt;Towards Uniformity and Alignment for Multimodal Representation Learning&amp;nbsp;&lt;br&gt;Principled Multimodal Representation Learning&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;-&amp;gt;&amp;nbsp;&lt;br&gt;헤드라인&amp;nbsp;이름 &lt;br&gt;슬라이드에&amp;nbsp;정보가&amp;nbsp;너무&amp;nbsp;많다. &lt;br&gt;ppt&amp;nbsp;를&amp;nbsp;보는게&amp;nbsp;의미가&amp;nbsp;없을&amp;nbsp;정도로&amp;nbsp;정보량이&amp;nbsp;많다.&amp;nbsp; &lt;br&gt;용어정리&amp;nbsp;(&amp;nbsp;align&amp;nbsp;-&amp;gt;&amp;nbsp;이&amp;nbsp;뭔지도&amp;nbsp;설명을&amp;nbsp;했으면&amp;nbsp;좋겠다&amp;nbsp;)&amp;nbsp;&lt;/p&gt;</description>
      <category>Paper</category>
      <category>Aligning Multimodal Representations through an Information Bottleneck</category>
      <category>논문리뷰</category>
      <author>Kim_sang_hyeob</author>
      <guid isPermaLink="true">https://ksh0416.tistory.com/159</guid>
      <comments>https://ksh0416.tistory.com/159#entry159comment</comments>
      <pubDate>Sun, 8 Mar 2026 13:18:53 +0900</pubDate>
    </item>
    <item>
      <title>GPGPU 총정리 - (1)</title>
      <link>https://ksh0416.tistory.com/158</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;여러가지 하면서 느낀건데 GPU 에 대해서는 언젠가 아주 자세하게 알아야 할 필요가 있다고 뼈저리게 느꼈다. 따라서 이번 기회를 통해 GPGPU 에 대해서 깊게 이해할 뿐만 아니라 , 직접 GPGPU 코드도 작성해보면서 이를 더 깊게 이해해보려고 한다. ( 문법이 꽤나 C++ / C 와 다른 점이 많다. )&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AD102 를 기준으로 GPU 구조를 설명한다&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;989&quot; data-origin-height=&quot;659&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dt0qwn/dJMcacbbEn4/Pm08hk17TdxozldE1f9OIk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dt0qwn/dJMcacbbEn4/Pm08hk17TdxozldE1f9OIk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dt0qwn/dJMcacbbEn4/Pm08hk17TdxozldE1f9OIk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdt0qwn%2FdJMcacbbEn4%2FPm08hk17TdxozldE1f9OIk%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;989&quot; height=&quot;659&quot; data-origin-width=&quot;989&quot; data-origin-height=&quot;659&quot;/&gt;&lt;/span&gt;&lt;/figure&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;AD102 한 장 요약 (칩 구조)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;12 GPC&lt;/b&gt; (Graphics Processing Clusters)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;GPC당 6 TPC &amp;rarr; 총 72 TPC&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;TPC당 2 SM &amp;rarr; 총 144 SM&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;메모리 인터페이스: 384-bit (12&amp;times;32-bit 컨트롤러)&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보기 쉽게 정리하면 다음과 같이 정리된다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1772715087649&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;GPU (AD102 전체)
 └── GPC &amp;times; 12 개  (Graphics Processing Cluster)
       └── TPC &amp;times; 6 개  (Texture Processing Cluster)
             └── SM &amp;times; 2 개  (Streaming Multiprocessor)
                   └── Processing Block &amp;times; 4 개
                         └── CUDA Core (FP32) &amp;times; 32 개&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;652&quot; data-start=&quot;436&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;455&quot; data-start=&quot;436&quot;&gt;&lt;b&gt;GPU&lt;/b&gt; = 공장 전체&lt;/li&gt;
&lt;li data-end=&quot;474&quot; data-start=&quot;456&quot;&gt;&lt;b&gt;GPC&lt;/b&gt; = 공장 동&lt;/li&gt;
&lt;li data-end=&quot;497&quot; data-start=&quot;475&quot;&gt;&lt;b&gt;TPC&lt;/b&gt; = 작업 라인 묶음&lt;/li&gt;
&lt;li data-end=&quot;517&quot; data-start=&quot;498&quot;&gt;&lt;b&gt;SM&lt;/b&gt; = 실제 작업장&lt;/li&gt;
&lt;li data-end=&quot;545&quot; data-start=&quot;518&quot;&gt;&lt;b&gt;warp&lt;/b&gt; = 32명으로 묶인 작업팀&lt;/li&gt;
&lt;li data-end=&quot;577&quot; data-start=&quot;546&quot;&gt;&lt;b&gt;register&lt;/b&gt; = 각 작업자의 개인 책상&lt;/li&gt;
&lt;li data-end=&quot;616&quot; data-start=&quot;578&quot;&gt;&lt;b&gt;shared memory&lt;/b&gt; = 팀이 같이 쓰는 화이트보드&lt;/li&gt;
&lt;li data-end=&quot;652&quot; data-start=&quot;617&quot;&gt;&lt;b&gt;L2 cache&lt;/b&gt; = 공장 전체가 같이 쓰는 중앙 창고&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;673&quot; data-start=&quot;654&quot; data-ke-size=&quot;size16&quot;&gt;먼저 하나씩 대략적으로 본 뒤 wrap + SM 쪽 구조를 중요하게 확인해야한다 ( 젤 중요 )&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;673&quot; data-start=&quot;654&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;GPC&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1016&quot; data-origin-height=&quot;621&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lcg6M/dJMcadgReJ0/GdEebsH9OA3n4xRVUyRpVk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lcg6M/dJMcadgReJ0/GdEebsH9OA3n4xRVUyRpVk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lcg6M/dJMcadgReJ0/GdEebsH9OA3n4xRVUyRpVk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Flcg6M%2FdJMcadgReJ0%2FGdEebsH9OA3n4xRVUyRpVk%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;719&quot; height=&quot;439&quot; data-origin-width=&quot;1016&quot; data-origin-height=&quot;621&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GPC 란 ?&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- GPU 전체를 여러 구역으로 나눈 최상단 단위 이다. ( AD102 에는 총 12개가 존재한다 )&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 각 GPC 는 독립적으로 돌아간다.&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;GPC 안에는 무엇이 있나 ?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 6 TPC : 각 TPC 마다 ( SM x 2 / PolyMorph Engine x 1 )&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 1개의 Raster Engine : 3D 그래픽스에서 삼각형을 픽셀로 변환하는 고정 기능 유닛 ( 그래픽스에서 쓰는 )&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 2개의 rop 파티션 ( 각 파이션에 8개 ROP 유닛 ) : 최종 픽셀을 메모리(프레임 버퍼) 에 기록&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;왜 이런 묶음 (GPC) 를 구성했는가 ?&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래픽 파이프라인은 연산(SM) 만 빠르다고 끝이 아니라&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1403&quot; data-start=&quot;1384&quot;&gt;기하 처리(PolyMorph),&lt;/li&gt;
&lt;li data-end=&quot;1420&quot; data-start=&quot;1404&quot;&gt;래스터( Raster ),&lt;/li&gt;
&lt;li data-end=&quot;1457&quot; data-start=&quot;1421&quot;&gt;픽셀 출력(ROP)&lt;br /&gt;이 세 단계가 같이 돌아야 프레임이 뽑힌다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 &quot; SM 묶음 + 그래픽 전용 블록 &quot; 을 한 덩어리 (GPC) 로 묶어서&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 여러 GPC 가 병렬로 프레임 처리하도록 한다.&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;( GPC 는 그래픽 파이프라인 스케일링 단위로 보면 정확 )&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;b&gt;TPC&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GPC 안에 더 작은 단위&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- SM 2 개&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 1 개의 PolyMorph Engine ( 3D 그래픽스에서 vertex 처리 담당 )&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;그리고 가장 중요한 SM 구조에 대해서는 매우 자세히 살펴보도록 하겠다.&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;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;SM ( Streaming Multiprocessor )&amp;nbsp;&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1023&quot; data-origin-height=&quot;671&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cIWiDB/dJMcagxRLEP/Tn1lCjTp5wRMQKEfOanHY1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cIWiDB/dJMcagxRLEP/Tn1lCjTp5wRMQKEfOanHY1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cIWiDB/dJMcagxRLEP/Tn1lCjTp5wRMQKEfOanHY1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcIWiDB%2FdJMcagxRLEP%2FTn1lCjTp5wRMQKEfOanHY1%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;690&quot; height=&quot;453&quot; data-origin-width=&quot;1023&quot; data-origin-height=&quot;671&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;603&quot; data-origin-height=&quot;899&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sRLUA/dJMcagxRL1y/Ujjk1fwcTn54DV22KF0IW1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sRLUA/dJMcagxRL1y/Ujjk1fwcTn54DV22KF0IW1/img.png&quot; data-alt=&quot;작아서 잘 안보이는걸 방지하기 위함.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sRLUA/dJMcagxRL1y/Ujjk1fwcTn54DV22KF0IW1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsRLUA%2FdJMcagxRL1y%2FUjjk1fwcTn54DV22KF0IW1%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;899&quot; data-origin-width=&quot;603&quot; data-origin-height=&quot;899&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;작아서 잘 안보이는걸 방지하기 위함.&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;SM 은 GPU 에서 실제 연산이 일어나는 핵심 단위이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;( SM = &amp;ldquo;연산 유닛 몇 개&amp;rdquo;가 아니라, 스케줄러 + 레지스터 + 캐시 + load/store + 특수 연산 유닛까지 다 갖춘 작은 병렬 실행 엔진 )&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하나의 SM 에는 다음과 같은 것이 담겨져 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;778&quot; data-start=&quot;752&quot;&gt;&lt;b&gt;4개의 processing block&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;815&quot; data-start=&quot;779&quot;&gt;&lt;b&gt;128KB &lt;span style=&quot;background-color: #f3c000;&quot;&gt;L1 Cache / Shared Memory&lt;/span&gt;&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;837&quot; data-start=&quot;816&quot;&gt;&lt;b&gt;4 Texture Units&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;/b&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;( 그래픽스에서 이미지 샘플링 빠르게 하려고 만든 것 )&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;862&quot; data-start=&quot;838&quot;&gt;&lt;b&gt;1개 3rd Gen RT core&lt;/b&gt;&amp;nbsp; &lt;span style=&quot;color: #9d9d9d; text-align: start;&quot;&gt;( Ray Tracking 전용 가속기 )&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;882&quot; data-start=&quot;863&quot;&gt;&lt;b&gt;2개 FP64 units&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/b&gt;&lt;span style=&quot;color: #9d9d9d; text-align: start;&quot;&gt;( 64bit float 연산용 유닛 )&amp;nbsp;&amp;nbsp;&lt;/span&gt;&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;b&gt;L1 Cache / Shared Memory&amp;nbsp; ( 128 kb )&amp;nbsp;&lt;/b&gt;&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- SRAM 하나의 풀을 L1 Cache / Shared Memory 로 나눠서 사용하는 형태이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 둘다 SM 의 on-chip Memory 라서 빠르다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;( SM 기준으로 VRAM 은 off-chip 이다.&amp;nbsp; )&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;L1 Cache &lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 하드웨어가 알아서 관리&amp;nbsp;&lt;b&gt;&lt;/b&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;Shared Memory&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- __shared__ 로 명시적으로 배열 만들고 / thread 들이 global 에서 가져온 데이터들을 shared 에 올려놓는다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 같은 block 의 thread 끼리 공유해서 재사용 하는 테크닉.&amp;nbsp;&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;cf .그럼 왜이렇게 설계했는가 ?&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;둘 다 sm 근처의 빠른 SRAM 을 필요로 하는데 워크로드에 따라서 요구가 다르다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 행렬곱/컨볼루션/타일링 -&amp;gt; shared 크게 주면 이득 ( 딥러닝에서 자주 쓰이는. )&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;&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;size18&quot;&gt;&lt;b&gt;Processing block&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;Processing block = &amp;ldquo;warp를 뽑아서(issue) 연산/메모리를 처리하는 미니-SM&amp;rdquo;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하나의 SM 을 4개의 Processing Block 으로 나눌 수 있다. 각 블록 역시 독립적으로 명령어 스케줄링하고 실행할 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 Processing Block 안에는 다음과 같은 것들이 존재한다.&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;649&quot; data-origin-height=&quot;776&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ecdil3/dJMcadnACKo/tnxPrUhVQX1qvYkVO8rPtk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ecdil3/dJMcadnACKo/tnxPrUhVQX1qvYkVO8rPtk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ecdil3/dJMcadnACKo/tnxPrUhVQX1qvYkVO8rPtk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fecdil3%2FdJMcadnACKo%2FtnxPrUhVQX1qvYkVO8rPtk%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;407&quot; height=&quot;487&quot; data-origin-width=&quot;649&quot; data-origin-height=&quot;776&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;967&quot; data-start=&quot;916&quot;&gt;&lt;span style=&quot;background-color: #f3c000;&quot;&gt;&lt;b&gt;16 FP32 CUDA cores + 16 FP32/INT32 CUDA cores ( 128 CUDA cores per SM )&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;994&quot; data-start=&quot;968&quot;&gt;&lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;&lt;b&gt;L0 instruction cache&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;1035&quot; data-start=&quot;995&quot;&gt;&lt;b&gt;1 warp scheduler + 1 dispatch unit&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;1080&quot; data-start=&quot;1036&quot;&gt;&lt;b&gt;64KB register file (16,384 &amp;times; 32-bit)&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;1092&quot; data-start=&quot;1081&quot;&gt;&lt;b&gt;1 SFU&amp;nbsp;&lt;/b&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt; ( 나눗셈 / 사인&amp;amp;코사인 계산이 원클락에 안되니까 그걸 잘 하기 위한 추가 special function )&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;1117&quot; data-start=&quot;1093&quot;&gt;&lt;b&gt;4 Load/Store units&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;1155&quot; data-start=&quot;1118&quot;&gt;&lt;b&gt;1 Ada 4th Gen Tensor Core&lt;/b&gt;&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;span style=&quot;background-color: #ffc1c8;&quot;&gt;&amp;nbsp;(A) L0 cache&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- instruction ( 명령어 ) 미리 가져다 놓는 캐시&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 매번 메모리에서 가져오면 느리니까 Processing block 에 직접 달아버림.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- SM 내부에 있다.&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;span style=&quot;background-color: #f3c000;&quot;&gt;(B) CUDA core&amp;nbsp;( 16 FP32 CUDA cores + 16 FP32/INT32 CUDA cores ( 128 CUDA cores per SM )&amp;nbsp; )&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CUDA core : FP 32 부동소수점 연산 1개를 1클럭에 처리하는 ALU 1개&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- ALU : 산술 연산 하는 하드웨어 회로&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- CPU 안에도 ALU 가 있고 , GPU 의 CUDA core 도 ALU 다. 다만 GPU 용으로 단순화 되어 있는 대신에 양이 매우매우 많다. ( 16384 개있음 ) ( = &lt;span style=&quot;background-color: #f89009;&quot;&gt;32&lt;/span&gt;개 X 4 ( processing block ) x 2 ( Sm ) x 6 (TPC) x 12 ( GPC ))&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 32 x 4 여서 128 개 있다고 하는거다 ( SM 안에 )&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;두종류의 CUDA core 가 존재한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- INT 32 도 지원하는 연산 회로는 FP 32 만 하는 회로보다 트랜지스터가 많이 필요하다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;fp32 전용 core -&amp;gt; 단순회로 , 면적 작음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;fp32/int 32&amp;nbsp; &amp;nbsp; &amp;nbsp; -&amp;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;span style=&quot;background-color: #f89009;&quot;&gt;32&lt;/span&gt; 라는 숫자가 매우 중요하다. (어찌나 여러번 말하시던지 외워버림)&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;뒤에서 더 설명하겠지만 warp 라는 개념이 나오는데 이것과 관련이 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 일단 GPU 는 warp ( 32 threads) 를 기본 실행 단위로 SIMT 방식으로 처리한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- thread 1개 단위가 아니라 warp 단위로&amp;nbsp; 스케줄/실행된다. ( 중요 )&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;1. warp1개 = 32 threads&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 32 thread 가 SM 안의 32 개 CUDA Core 에 1:1 mapping 되어서 작동한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 동일한 명령어를 32개가 동시에 1클럭에 실행한다 ( SIMT )&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;( warp 는 같은 instruction 을 같이 실행하는 단위이다 - 다른 instruction 을 수행하는게 아님. )&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;( 뭐 조건이 복잡하면 1클럭은 아닐 수 있지만 편의상 그렇게 설명한 듯 싶다. )&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;문제&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot; 이렇게 core(레지스터) 가 많아도 부족하다 &quot;&amp;nbsp;&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #9feec3;&quot;&gt;(C) Tensor Core&lt;/span&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;- CUDA core (ALU) 와 별개로, GPU 안에 있는 행렬곱 전용 유닛이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- D = A x B + C&amp;nbsp; 기본형태는 이렇다 ( 딥러닝에서 매우매우 자주 쓰이는 모양 )&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;cf.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;RTX 4090 성능 비교: &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;CUDA Core (FP32): 82.6 TFLOPS &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Tensor Core (FP16): 330 TFLOPS &amp;larr; 4배 &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Tensor Core (FP8): 1,321 TOPS &amp;larr; 16배 &lt;/span&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;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;(D) WRAP&amp;nbsp;&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1187&quot; data-origin-height=&quot;743&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dhLsda/dJMcahDxJ8N/kbra4T16Fs95zD76TjwvE1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dhLsda/dJMcahDxJ8N/kbra4T16Fs95zD76TjwvE1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dhLsda/dJMcahDxJ8N/kbra4T16Fs95zD76TjwvE1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdhLsda%2FdJMcahDxJ8N%2Fkbra4T16Fs95zD76TjwvE1%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;1187&quot; height=&quot;743&quot; data-origin-width=&quot;1187&quot; data-origin-height=&quot;743&quot;/&gt;&lt;/span&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. warp 란 무엇인가 ?&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- warp = 32 개의 thread 를 묶은 실행 단위&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- SM 이 다루는 기본 실행 단위이다. ( 즉 , 직접 다루는 단위가 thread 하나가 아니라 warp 이다. )&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- GPU 는 내부적으로 32 개의 Thread 를 한 덩어리로 처리하겠다는 전제로 설계&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;SM은 4개의 Processing block 으로 나뉘고 , 각 processing block 에는 warp scheduler 가 한개씩있다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;( SM 안에는 총 4개의 warp sceheduler )&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; SM 하나가 통쨰로 한번에 warp 하나만 처리하는게 아니라 . 여러 warp 를 resident 상태로 들고 있으면서 , 각 scheuler 가 매 순간 실행 가능한 warp 를 골라 instruction 을 issue 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1772757782596&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SM
├─ Processing Block 0 ─ Warp Scheduler 0 ──&amp;gt; 어떤 warp 하나 선택
├─ Processing Block 1 ─ Warp Scheduler 1 ──&amp;gt; 어떤 warp 하나 선택
├─ Processing Block 2 ─ Warp Scheduler 2 ──&amp;gt; 어떤 warp 하나 선택
└─ Processing Block 3 ─ Warp Scheduler 3 ──&amp;gt; 어떤 warp 하나 선택&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;issue 시점마다 ( 매 cycle ? ) 각 scheduler 는 &quot; 지금 당장 다음 instruction을 실행할 수 있는 warp가 누구냐? &quot; 를 보고 골라서 보낸다.&amp;nbsp;&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;span style=&quot;color: #f89009;&quot;&gt;2. resident / active /ready warp&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 이부분이 강의를 들으면서 좀 헷갈렸던 부분이다. 아마 편의상 그냥 warp 로 설명하시고 넘어 가신 것 같은데 듣는 입장에서는 약간 의아했던 부분이 있어서 정리를 좀 해보려고 한다 (내 집중력이 안좋았을수도 있고..) . 일단 먼저 warp 를 3가지로 구분하면 이해가 쉽다.&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;A) resident warp&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 현재 SM 안에 올라와 있는 warp&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- block 이 SM 에 배정되면 그 block 의 warp 들이 SM 의 자원&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;3514&quot; data-start=&quot;3460&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;3470&quot; data-start=&quot;3460&quot; data-section-id=&quot;xwdxtt&quot;&gt;register&lt;/li&gt;
&lt;li data-end=&quot;3486&quot; data-start=&quot;3471&quot; data-section-id=&quot;p3h4jk&quot;&gt;shared memory&lt;/li&gt;
&lt;li data-end=&quot;3501&quot; data-start=&quot;3487&quot; data-section-id=&quot;am55n5&quot;&gt;thread slots&lt;/li&gt;
&lt;li data-end=&quot;3514&quot; data-start=&quot;3502&quot; data-section-id=&quot;1boxljf&quot;&gt;warp slots&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;3544&quot; data-start=&quot;3516&quot; data-ke-size=&quot;size16&quot;&gt;을 차지하면서 &lt;b&gt;resident&lt;/b&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;B) active warp&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보통 resident 이면서 아직 실행이 끝나지 않은 warp 를 말한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;( 사실상 resident == active 비슷하다고 보면 된다 )&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;C) ready warp&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바로 다음 instruction 을 실행할 수 있는 warp&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;어떤 warp 가 global memory load 결과를 기다리는 중이면 resident 이긴 하지만 ready 는 아닐 수 있다.&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;s&gt;(맞나 이게?)&lt;/s&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;s&gt;그니까 1개의 SM 에 최대 48개의 warp 를 가질 수 있고 실행할 수 있다는건&amp;nbsp;&lt;/s&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;s&gt;보통 생각하는 것 처럼 그냥 하나의 warp 가 cuda core 에 붙어서 연산이 끝날때 까지 쭉 계산하는 형태가 아니라&amp;nbsp;&lt;/s&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;s&gt;스위칭을 통해서 엄청 자주 바뀌면서 돌아가는 것 같다 ( 마치 시프에서 배웠던 context switiching 을 통해서 하면 쭉 연산하는 것 처럼 보이게 하는 착각을 일으키는 ? )&amp;nbsp;&lt;/s&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2105&quot; data-start=&quot;2045&quot; data-ke-size=&quot;size16&quot;&gt;GPU에서 warp execution은 CPU처럼 &amp;ldquo;한 스레드가 코어를 오래 점유&amp;rdquo;하는 느낌보다&lt;/p&gt;
&lt;p data-end=&quot;2105&quot; data-start=&quot;2045&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;여러 warp가 SM 안에 대기하고 있고, scheduler가 그때그때 ready한 warp를 빠르게 골라 instruction을 발행하는 구조&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2214&quot; data-start=&quot;2203&quot; data-ke-size=&quot;size16&quot;&gt;즉 어떤 warp가:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2323&quot; data-start=&quot;2216&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2247&quot; data-start=&quot;2216&quot; data-section-id=&quot;g0bgoa&quot;&gt;arithmetic instruction 몇 개 수행&lt;/li&gt;
&lt;li data-end=&quot;2278&quot; data-start=&quot;2248&quot; data-section-id=&quot;1u1uoyy&quot;&gt;global memory load 만나서 stall&lt;/li&gt;
&lt;li data-end=&quot;2286&quot; data-start=&quot;2279&quot; data-section-id=&quot;nadf7o&quot;&gt;잠시 대기&lt;/li&gt;
&lt;li data-end=&quot;2303&quot; data-start=&quot;2287&quot; data-section-id=&quot;xgl1eg&quot;&gt;그동안 다른 warp 수행&lt;/li&gt;
&lt;li data-end=&quot;2323&quot; data-start=&quot;2304&quot; data-section-id=&quot;1yrfbe4&quot;&gt;나중에 다시 돌아와 이어서 수행&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또 , SM 에 최대 48warps 가 있다고 이야기 한건 정확히는&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;한 SM 이 최대 48개의 resident / active warp 를 동시에 보유할 수 있음&quot; 이다.&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;이 말이 곧 48개가 모두 동시에 한 사이클에 실행된다는 뜻이 아니라. SM 안에 최대 48warp 의 문맥을 돌려두고&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그중 ready 한 warp 들을 스케줄러들이 선택해서 issue 하는 느낌이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;( 그니까 보유 capacity 와 issue 된 것들과는 다른 것이고 , 이를 다 합쳐서 48개라고 하는 뜻. )&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;하지만 엄연히 CPU context swithcing 과는 다른데, 이 이유를&amp;nbsp; zero-cost context swithcing 에서 알아보도록 하겠다.&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. Warp processing&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- SM 에서는 여러 warp 가 독립적으로 처리된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- SM 은 이 warp 들을 여러개 동시에 올려놓고 관리한다 ( 즉 , sm 이 한번에 warp 하나만 들고 있는 것이 아니라 , 여러 warp 를 resident 상태를 유지하면서 그중 실행 가능한 warp 를 골라서 처리한다. )&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;u&gt;execution context 란 ?&amp;nbsp;&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 warp의 32 개 thread 에 대해 다음과 같은 실행 상태가 SM 내부 ( on-chip ) 에 유지된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- ( program counters, registers, and so on ) 이런 정보를 통틀어서 execution context 라고 볼 수 있다.&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;어떤 warp 가 도중에 멈춰도 warp 상태가 이미 SM 내부에 저장되어 있어서 나중에 다시 이어서 실행할 수 있다.&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;* 추가설명 ( ai 와 질문하면서 필요한 부분 그대로 발췌 )&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;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;SM 이 warp 를 들고 있는 형식이 정확히 어떤 의미인지 이해가 잘 안갔다. ( 아래 zero-cost context switching 에서도 또 나오는 개념이므로 )&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;&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;1. SM 이 warp 를 들고있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;= SM 안에 resident한 warp들의 &lt;b&gt;실행 상태(execution context)&lt;/b&gt; 를 유지할 수 있는 하드웨어 자원들이 있다는 뜻이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;296&quot; data-start=&quot;283&quot; data-ke-size=&quot;size16&quot;&gt;상태에는 대표적으로:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;387&quot; data-start=&quot;298&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;322&quot; data-start=&quot;298&quot; data-section-id=&quot;1q19deh&quot;&gt;다음에 실행할 instruction 위치&lt;/li&gt;
&lt;li data-end=&quot;346&quot; data-start=&quot;323&quot; data-section-id=&quot;1rxww00&quot;&gt;각 thread의 register 값들&lt;/li&gt;
&lt;li data-end=&quot;374&quot; data-start=&quot;347&quot; data-section-id=&quot;1dpgb43&quot;&gt;warp의 active mask / 실행 상태&lt;/li&gt;
&lt;li data-end=&quot;387&quot; data-start=&quot;375&quot; data-section-id=&quot;1ld016s&quot;&gt;스케줄링 대상 여부&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;547&quot; data-start=&quot;389&quot; data-ke-size=&quot;size16&quot;&gt;같은 정보가 포함된다. 강의자료와 CUDA Programming Guide도 warp의 execution context로 &lt;b&gt;program counters, registers, etc.&lt;/b&gt; 를 들고, 이것이 warp lifetime 동안 &lt;b&gt;on-chip&lt;/b&gt;에 유지된다고 설명한다.&lt;/p&gt;
&lt;p data-end=&quot;551&quot; data-start=&quot;549&quot; data-ke-size=&quot;size16&quot;&gt;즉,&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;699&quot; data-start=&quot;553&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;583&quot; data-start=&quot;553&quot; data-section-id=&quot;1eorakr&quot;&gt;&lt;b&gt;warp = 32개 thread의 실행 단위&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;614&quot; data-start=&quot;584&quot; data-section-id=&quot;n2jdfi&quot;&gt;&lt;b&gt;SM = 그 warp들을 실행시키는 하드웨어&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;699&quot; data-start=&quot;615&quot; data-section-id=&quot;12g74nr&quot;&gt;&lt;b&gt;SM이 warp를 들고 있다 = 그 32개 thread가 지금까지 어디까지 실행했고 어떤 값을 갖고 있는지 SM 내부 자원에 저장해 둔 상태&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;708&quot; data-start=&quot;701&quot; 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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&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;2. 그럼 SM은 뭘 실제로 저장하나?&lt;/p&gt;
&lt;p data-end=&quot;1207&quot; data-start=&quot;1148&quot; data-ke-size=&quot;size16&quot;&gt;이걸 감각적으로 보면, resident warp 하나당 SM은 대충 이런 정보를 관리한다고 생각하면 된다.&lt;/p&gt;
&lt;h2 data-end=&quot;1226&quot; data-start=&quot;1209&quot; data-section-id=&quot;1i5gh8u&quot; data-ke-size=&quot;size26&quot;&gt;warp 단위로 필요한 것&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1364&quot; data-start=&quot;1227&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1263&quot; data-start=&quot;1227&quot; data-section-id=&quot;1mxy57d&quot;&gt;이 warp가 &lt;b&gt;다음에 실행할 instruction 위치&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;1298&quot; data-start=&quot;1264&quot; data-section-id=&quot;17r09ia&quot;&gt;이 warp가 &lt;b&gt;현재 ready인지 / stall인지&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;1344&quot; data-start=&quot;1299&quot; data-section-id=&quot;1uo69l2&quot;&gt;현재 instruction에 참여하는 &lt;b&gt;active thread mask&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;1364&quot; data-start=&quot;1345&quot; data-section-id=&quot;128ha5x&quot;&gt;스케줄러가 참고할 warp 상태&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;1385&quot; data-start=&quot;1366&quot; data-section-id=&quot;1ws7sd0&quot; data-ke-size=&quot;size26&quot;&gt;thread 단위로 필요한 것&lt;/h2&gt;
&lt;p data-end=&quot;1424&quot; data-start=&quot;1386&quot; data-ke-size=&quot;size16&quot;&gt;warp 안에는 32개 thread가 있으니까, 각 thread마다:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1515&quot; data-start=&quot;1426&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1442&quot; data-start=&quot;1426&quot; data-section-id=&quot;23elbr&quot;&gt;자기 register 값들&lt;/li&gt;
&lt;li data-end=&quot;1476&quot; data-start=&quot;1443&quot; data-section-id=&quot;17fkkdf&quot;&gt;자기 thread-local execution state&lt;/li&gt;
&lt;li data-end=&quot;1515&quot; data-start=&quot;1477&quot; data-section-id=&quot;1j83rsr&quot;&gt;(Volta 이후에는 더 독립적인 per-thread state)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1528&quot; data-start=&quot;1517&quot; data-ke-size=&quot;size16&quot;&gt;같은 것이 필요하다.&lt;/p&gt;
&lt;p data-end=&quot;1841&quot; data-start=&quot;1530&quot; data-ke-size=&quot;size16&quot;&gt;강의자료는 &amp;ldquo;every warp currently resident in an SM&amp;rdquo;에 대해 &lt;b&gt;각 32 threads의 execution context&lt;/b&gt; 가 on-chip에 유지된다고 하고 &lt;span data-state=&quot;closed&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;CUDA Programming Guide는 SM의 &lt;b&gt;32-bit registers가 warps 사이에 partition&lt;/b&gt; 되며, shared memory는 thread blocks 사이에 partition된다고 설명한다.&lt;/p&gt;
&lt;p data-end=&quot;1841&quot; data-start=&quot;1530&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1852&quot; data-start=&quot;1843&quot; data-ke-size=&quot;size16&quot;&gt;즉 물리적으로는:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1995&quot; data-start=&quot;1854&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1873&quot; data-start=&quot;1854&quot; data-section-id=&quot;cp3oav&quot;&gt;&lt;span style=&quot;background-color: #f3c000;&quot;&gt;&lt;b&gt;register file&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;1901&quot; data-start=&quot;1874&quot; data-section-id=&quot;1aq3t8r&quot;&gt;&lt;b&gt;warp scheduling state&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;1933&quot; data-start=&quot;1902&quot; data-section-id=&quot;n8mvtr&quot;&gt;&lt;b&gt;PC / mask / control state&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;1969&quot; data-start=&quot;1934&quot; data-section-id=&quot;169pbmm&quot;&gt;&lt;b&gt;shared memory allocation info&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;1995&quot; data-start=&quot;1970&quot; data-section-id=&quot;11it0zs&quot;&gt;기타 pipeline bookkeeping&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;2045&quot; data-start=&quot;1997&quot; data-ke-size=&quot;size16&quot;&gt;같은 하드웨어 자원들에 resident warp들의 상태가 배치되어 있다고 보면 된다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1438&quot; data-origin-height=&quot;943&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cbm13T/dJMcaibqDM7/epKkee2vkOM2AO4zeV4DbK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cbm13T/dJMcaibqDM7/epKkee2vkOM2AO4zeV4DbK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cbm13T/dJMcaibqDM7/epKkee2vkOM2AO4zeV4DbK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcbm13T%2FdJMcaibqDM7%2FepKkee2vkOM2AO4zeV4DbK%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;1438&quot; height=&quot;943&quot; data-origin-width=&quot;1438&quot; data-origin-height=&quot;943&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1 data-end=&quot;2079&quot; data-start=&quot;2052&quot; data-section-id=&quot;1ue7rsv&quot;&gt;&amp;nbsp;register file이 핵심이다&lt;/h1&gt;
&lt;p data-end=&quot;2095&quot; data-start=&quot;2081&quot; data-ke-size=&quot;size16&quot;&gt;이 부분이 가장 중요하다.&lt;/p&gt;
&lt;p data-end=&quot;2346&quot; data-start=&quot;2097&quot; data-ke-size=&quot;size16&quot;&gt;강의자료 1에서 Ada SM의 각 processing block에는 &lt;b&gt;64 KB register file: 16,384 x 32-bit&lt;/b&gt; 가 있다고 나온다. &lt;span data-state=&quot;closed&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-end=&quot;2346&quot; data-start=&quot;2097&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span data-state=&quot;closed&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;또 CUDA Programming Guide는 register가 &lt;b&gt;SM에 위치&lt;/b&gt;하며 thread-local storage로 쓰인다고 설명한다. &lt;span data-state=&quot;closed&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2356&quot; data-start=&quot;2348&quot; data-ke-size=&quot;size16&quot;&gt;이 말의 뜻은:&lt;/p&gt;
&lt;blockquote data-end=&quot;2454&quot; data-start=&quot;2358&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;2454&quot; data-start=&quot;2360&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;warp 안 32개 thread 각각이 자기 register들을 갖고 있고, 그 register 값들이 SM 내부 register file에 잡혀 있다&lt;/b&gt;는 뜻이다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-end=&quot;2486&quot; data-start=&quot;2456&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어 어떤 thread가 kernel 실행 중에:&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;&amp;nbsp;&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;div&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;a&lt;/span&gt;&lt;span&gt; = ...&lt;/span&gt;&lt;br /&gt;&lt;span&gt;float&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt; = ...&lt;/span&gt;&lt;br /&gt;&lt;span&gt;float&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;y&lt;/span&gt;&lt;span&gt; = &lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;;&lt;/span&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;2587&quot; data-start=&quot;2543&quot; data-ke-size=&quot;size16&quot;&gt;이런 중간값들을 만들면, 이런 값들 중 많은 부분은 register에 들어간다.&lt;/p&gt;
&lt;p data-end=&quot;2660&quot; data-start=&quot;2589&quot; data-ke-size=&quot;size16&quot;&gt;warp 하나에는 32 threads가 있으니,&lt;br /&gt;실제로는 &lt;b&gt;32개 thread 각각의 register 묶음&lt;/b&gt;이 필요하다.&lt;/p&gt;
&lt;p data-end=&quot;2685&quot; data-start=&quot;2662&quot; data-ke-size=&quot;size16&quot;&gt;즉 resident warp가 많아질수록:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2767&quot; data-start=&quot;2687&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2727&quot; data-start=&quot;2687&quot; data-section-id=&quot;1elawul&quot;&gt;많은 thread의 register 상태를 동시에 들고 있어야 하므로&lt;/li&gt;
&lt;li data-end=&quot;2767&quot; data-start=&quot;2728&quot; data-section-id=&quot;tpkicy&quot;&gt;register file 용량이 occupancy를 제한하게 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;2861&quot; data-start=&quot;2769&quot; data-ke-size=&quot;size16&quot;&gt;그래서 CUDA PG도 resident block/warp 수가 kernel의 register 사용량과 shared memory 사용량에 따라 달라진다고 설명한다.&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h1 data-end=&quot;4511&quot; data-start=&quot;4476&quot; data-section-id=&quot;1phkrur&quot;&gt;&amp;ldquo;그럼 warp는 어디 있다?&amp;rdquo;를 더 물리적으로 말하면&lt;/h1&gt;
&lt;p data-end=&quot;4538&quot; data-start=&quot;4513&quot; data-ke-size=&quot;size16&quot;&gt;이건 아주 거칠게 말하면 다음처럼 보면 된다.&lt;/p&gt;
&lt;h2 data-end=&quot;4552&quot; data-start=&quot;4540&quot; data-section-id=&quot;9awrql&quot; data-ke-size=&quot;size26&quot;&gt;warp 그 자체&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;4598&quot; data-start=&quot;4553&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;4571&quot; data-start=&quot;4553&quot; data-section-id=&quot;x0qab0&quot;&gt;thread ID 32개 묶음&lt;/li&gt;
&lt;li data-end=&quot;4598&quot; data-start=&quot;4572&quot; data-section-id=&quot;40ygsr&quot;&gt;scheduler가 한 단위로 다루는 엔트리&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;4616&quot; data-start=&quot;4600&quot; data-section-id=&quot;1v56nun&quot; data-ke-size=&quot;size26&quot;&gt;warp의 상태는 어디?&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;4747&quot; data-start=&quot;4617&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;4635&quot; data-start=&quot;4617&quot; data-section-id=&quot;19s90u3&quot;&gt;register file 일부&lt;/li&gt;
&lt;li data-end=&quot;4678&quot; data-start=&quot;4636&quot; data-section-id=&quot;bpcg0v&quot;&gt;warp state table / scheduler bookkeeping&lt;/li&gt;
&lt;li data-end=&quot;4706&quot; data-start=&quot;4679&quot; data-section-id=&quot;1kbog0v&quot;&gt;PC / mask / control state&lt;/li&gt;
&lt;li data-end=&quot;4747&quot; data-start=&quot;4707&quot; data-section-id=&quot;1xykeno&quot;&gt;shared memory allocation과 연관된 block 상태&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;4845&quot; data-start=&quot;4749&quot; data-ke-size=&quot;size16&quot;&gt;즉 &lt;b&gt;&amp;ldquo;warp가 저장되는 하나의 통 박스&amp;rdquo;&lt;/b&gt; 가 있다기보다,&lt;br /&gt;SM 내부 여러 자원에 그 warp를 재개하는 데 필요한 상태가 분산되어 있다고 이해하는 쪽이 가깝다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-end=&quot;5331&quot; data-start=&quot;5324&quot; data-section-id=&quot;1pr9w1w&quot; data-ke-size=&quot;size26&quot;&gt;질문 1&lt;/h2&gt;
&lt;blockquote data-end=&quot;5356&quot; data-start=&quot;5332&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;5356&quot; data-start=&quot;5334&quot; data-ke-size=&quot;size16&quot;&gt;warp를 그러면 뭐 어떻게 들고있는데?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-end=&quot;5360&quot; data-start=&quot;5358&quot; data-ke-size=&quot;size16&quot;&gt;답:&lt;/p&gt;
&lt;p data-end=&quot;5431&quot; data-start=&quot;5362&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;resident warp를 다시 실행할 수 있게 해 주는 상태 정보들을 SM 내부 하드웨어 자원에 유지한다&lt;/b&gt;는 뜻이다.&lt;/p&gt;
&lt;p data-end=&quot;5436&quot; data-start=&quot;5433&quot; data-ke-size=&quot;size16&quot;&gt;특히:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;5526&quot; data-start=&quot;5438&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;5455&quot; data-start=&quot;5438&quot; data-section-id=&quot;zy51zc&quot;&gt;program counter&lt;/li&gt;
&lt;li data-end=&quot;5482&quot; data-start=&quot;5456&quot; data-section-id=&quot;md27do&quot;&gt;active mask / warp state&lt;/li&gt;
&lt;li data-end=&quot;5510&quot; data-start=&quot;5483&quot; data-section-id=&quot;1eldgd4&quot;&gt;32개 thread 각각의 register 값&lt;/li&gt;
&lt;li data-end=&quot;5526&quot; data-start=&quot;5511&quot; data-section-id=&quot;ui0wgl&quot;&gt;scheduling 상태&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;5533&quot; data-start=&quot;5528&quot; data-ke-size=&quot;size16&quot;&gt;등이다.&lt;/p&gt;
&lt;hr data-end=&quot;5538&quot; data-start=&quot;5535&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;5547&quot; data-start=&quot;5540&quot; data-section-id=&quot;1pr9w1z&quot; data-ke-size=&quot;size26&quot;&gt;질문 2&lt;/h2&gt;
&lt;blockquote data-end=&quot;5609&quot; data-start=&quot;5548&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;5609&quot; data-start=&quot;5550&quot; data-ke-size=&quot;size16&quot;&gt;진짜로 thread들은 32개가 있을꺼고.. warp 에 대한 정보를 뭐 어떻게 들고있다는건데 SM 이 ?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-end=&quot;5613&quot; data-start=&quot;5611&quot; data-ke-size=&quot;size16&quot;&gt;답:&lt;/p&gt;
&lt;p data-end=&quot;5709&quot; data-start=&quot;5615&quot; data-ke-size=&quot;size16&quot;&gt;warp는 32개 thread의 묶음이고,&lt;br /&gt;SM은 그 thread들의 &lt;b&gt;register state&lt;/b&gt; 와 warp의 &lt;b&gt;control state&lt;/b&gt; 를 들고 있다.&lt;/p&gt;
&lt;p data-end=&quot;5871&quot; data-start=&quot;5711&quot; data-ke-size=&quot;size16&quot;&gt;특히 register 값은 SM의 &lt;b&gt;register file&lt;/b&gt; 에 있고,&lt;br /&gt;warp scheduler가 참고하는 상태 정보도 on-chip에 있다. Ada SM의 processing block마다 register file과 warp scheduler가 있다고 강의자료가 설명한다.&lt;/p&gt;
&lt;p data-end=&quot;5875&quot; data-start=&quot;5873&quot; data-ke-size=&quot;size16&quot;&gt;즉:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;6011&quot; data-start=&quot;5877&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;5908&quot; data-start=&quot;5877&quot; data-section-id=&quot;dp9sbx&quot;&gt;&lt;b&gt;thread 값들&lt;/b&gt; &amp;rarr; register file&lt;/li&gt;
&lt;li data-end=&quot;5974&quot; data-start=&quot;5909&quot; data-section-id=&quot;3rd1zu&quot;&gt;&lt;b&gt;warp가 어디까지 왔는지 / 지금 실행 가능한지&lt;/b&gt; &amp;rarr; warp control/scheduling state&lt;/li&gt;
&lt;li data-end=&quot;6011&quot; data-start=&quot;5975&quot; data-section-id=&quot;1ijfcbi&quot;&gt;&lt;b&gt;block 간 공유 데이터&lt;/b&gt; &amp;rarr; shared memory&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;6035&quot; data-start=&quot;6013&quot; data-ke-size=&quot;size16&quot;&gt;이런 식으로 역할이 나뉜다고 보면 된다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. Zero-cost context switching&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞에서 언급한 execution context 와 이어지는 내용이다.&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;568&quot; data-origin-height=&quot;65&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/btiX6D/dJMcagdBwf6/S3bTfwWmkvaWHT1e9LcVzk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/btiX6D/dJMcagdBwf6/S3bTfwWmkvaWHT1e9LcVzk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/btiX6D/dJMcagdBwf6/S3bTfwWmkvaWHT1e9LcVzk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbtiX6D%2FdJMcagdBwf6%2FS3bTfwWmkvaWHT1e9LcVzk%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;533&quot; height=&quot;61&quot; data-origin-width=&quot;568&quot; data-origin-height=&quot;65&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이해하기 쉽게 CPU 에서는 thread 를 바꿀때는 보통&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 현재 상태 저장 ( PC 저장 / Register 저장 / stack pointer 저장 etc ... )&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 다른 thread 상태 복원 ( pc 불러오고 / register 불러오고 ... )&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 GPU 에서는 warp 들의 execution context 가 이미 SM on-chip 에 유지되고 있기 때문에&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떤 warp 가 stall 되면 다른 warp 로 바꾸는데 별도의 무거운 과정이 필요 하지 않는다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;( 이미 정보들이 SM 위에 on chip 으로 있기 때문에 switching cost 가 거의 없다. )&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이로 인해 GPU는 warp를 번갈아 실행하면서 memory latency를 숨기고 throughput을 높일 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 이걸 zero-cost context switching 이라고 부른다.&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;span style=&quot;background-color: #f3c000;&quot;&gt;GPU는 메모리 latency 를 어떻게 hiding 하는가 ?&amp;nbsp;&lt;/span&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;한 warp 가 memory access 떄문에 멈추면 , SM 이 다른 ready warp 를 바로 실행해서 기다리는 시간을 가린다.&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;GPU 는 latency 를 없애는 것이 아니라 다른 warp 일을 시켜서 기다리는 시간이 안보이게 만드는 것이고&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 &quot; latency hiding &quot; 이라고 한다.&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; GPU의 latency hiding&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;830&quot; data-start=&quot;481&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;541&quot; data-start=&quot;481&quot; data-section-id=&quot;2r035f&quot;&gt;어떤 warp가 global memory load를 수행하면, 데이터가 올 때까지 오래 기다릴 수 있다.&lt;/li&gt;
&lt;li data-end=&quot;596&quot; data-start=&quot;542&quot; data-section-id=&quot;1kpl3v7&quot;&gt;이때 그 warp는 &lt;b&gt;stall&lt;/b&gt; 되어 당장 다음 instruction을 실행할 수 없다.&lt;/li&gt;
&lt;li data-end=&quot;638&quot; data-start=&quot;597&quot; data-section-id=&quot;1vsmhci&quot;&gt;하지만 SM 안에는 여러 resident warp가 이미 올라와 있다.&lt;/li&gt;
&lt;li data-end=&quot;715&quot; data-start=&quot;639&quot; data-section-id=&quot;1wnagax&quot;&gt;warp scheduler는 stall된 warp 대신 &lt;b&gt;다른 ready warp&lt;/b&gt;를 골라 instruction을 issue한다.&lt;/li&gt;
&lt;li data-end=&quot;770&quot; data-start=&quot;716&quot; data-section-id=&quot;1uwkaj&quot;&gt;따라서 메모리 응답을 기다리는 동안에도 ALU는 다른 warp의 연산을 계속 수행할 수 있다.&lt;/li&gt;
&lt;li data-end=&quot;830&quot; data-start=&quot;771&quot; data-section-id=&quot;1kh9tsi&quot;&gt;결과적으로 긴 memory latency가 &lt;b&gt;다른 warp 실행에 의해 가려진다(hide 된다).&lt;/b&gt;&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;span style=&quot;background-color: #f89009;&quot;&gt;많은 warp 를 띄워두는게 좋다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-end=&quot;924&quot; data-start=&quot;904&quot; data-section-id=&quot;u7s2b9&quot; data-ke-size=&quot;size26&quot;&gt;경우 A: warp가 별로 없음&lt;/h2&gt;
&lt;p data-end=&quot;961&quot; data-start=&quot;925&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어 SM 안에 ready warp가 2개밖에 없다고 하자.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1079&quot; data-start=&quot;963&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;970&quot; data-start=&quot;963&quot; data-section-id=&quot;17cvk02&quot;&gt;W0 실행&lt;/li&gt;
&lt;li data-end=&quot;997&quot; data-start=&quot;971&quot; data-section-id=&quot;jq3joe&quot;&gt;W0 memory access &amp;rarr; stall&lt;/li&gt;
&lt;li data-end=&quot;1005&quot; data-start=&quot;998&quot; data-section-id=&quot;17cs0v7&quot;&gt;W1 실행&lt;/li&gt;
&lt;li data-end=&quot;1033&quot; data-start=&quot;1006&quot; data-section-id=&quot;2qg40r&quot;&gt;W1도 memory access &amp;rarr; stall&lt;/li&gt;
&lt;li data-end=&quot;1057&quot; data-start=&quot;1034&quot; data-section-id=&quot;1pgko2g&quot;&gt;이제 실행할 ready warp가 없음&lt;/li&gt;
&lt;li data-end=&quot;1079&quot; data-start=&quot;1058&quot; data-section-id=&quot;1am5fj9&quot;&gt;그러면 SM의 연산 유닛이 놀게 됨&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1104&quot; data-start=&quot;1081&quot; data-ke-size=&quot;size16&quot;&gt;즉 &lt;b&gt;latency를 숨길 수 없다.&lt;/b&gt;&lt;/p&gt;
&lt;hr data-end=&quot;1109&quot; data-start=&quot;1106&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1128&quot; data-start=&quot;1111&quot; data-section-id=&quot;qqiyhy&quot; data-ke-size=&quot;size26&quot;&gt;경우 B: warp가 많음&lt;/h2&gt;
&lt;p data-end=&quot;1167&quot; data-start=&quot;1129&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어 SM 안에 warp가 32개, 48개 가까이 있다고 하자.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1272&quot; data-start=&quot;1169&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1179&quot; data-start=&quot;1169&quot; data-section-id=&quot;1drq6cp&quot;&gt;W0 stall&lt;/li&gt;
&lt;li data-end=&quot;1187&quot; data-start=&quot;1180&quot; data-section-id=&quot;hr4sui&quot;&gt;그럼 W1&lt;/li&gt;
&lt;li data-end=&quot;1198&quot; data-start=&quot;1188&quot; data-section-id=&quot;1m0rgo8&quot;&gt;W1 stall&lt;/li&gt;
&lt;li data-end=&quot;1206&quot; data-start=&quot;1199&quot; data-section-id=&quot;hr4suh&quot;&gt;그럼 W2&lt;/li&gt;
&lt;li data-end=&quot;1217&quot; data-start=&quot;1207&quot; data-section-id=&quot;7202ej&quot;&gt;W2 stall&lt;/li&gt;
&lt;li data-end=&quot;1225&quot; data-start=&quot;1218&quot; data-section-id=&quot;hr4sug&quot;&gt;그럼 W3&lt;/li&gt;
&lt;li data-end=&quot;1231&quot; data-start=&quot;1226&quot; data-section-id=&quot;1o23ba&quot;&gt;...&lt;/li&gt;
&lt;li data-end=&quot;1272&quot; data-start=&quot;1232&quot; data-section-id=&quot;6zq4wy&quot;&gt;이런 식으로 ready warp가 계속 있으면 연산 유닛이 쉬지 않음&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1314&quot; data-start=&quot;1274&quot; data-ke-size=&quot;size16&quot;&gt;즉 &lt;b&gt;memory 기다리는 시간을 다른 warp들로 메꿀 수 있다.&lt;/b&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;&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;- 이상 첫번째 GPGPU 수업 정리를 마친다.&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;</description>
      <category>GPGPU</category>
      <category>CUDA</category>
      <category>GPGPU</category>
      <category>GPU</category>
      <category>Nvidia</category>
      <category>tensor</category>
      <author>Kim_sang_hyeob</author>
      <guid isPermaLink="true">https://ksh0416.tistory.com/158</guid>
      <comments>https://ksh0416.tistory.com/158#entry158comment</comments>
      <pubDate>Thu, 5 Mar 2026 17:39:18 +0900</pubDate>
    </item>
    <item>
      <title>[발표자료] Modality Gap-Driven Subspace Alignment Training Paradigm For Multimodal L</title>
      <link>https://ksh0416.tistory.com/156</link>
      <description>&lt;figure class=&quot;fileblock&quot; data-ke-align=&quot;alignCenter&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/bGKbvl/dJMcajutgpc/aPA0MpVvXRiJukaxviagz1/Modality%20Gap%20-%20Driven%20subspace%20Alignment%20Training%20Paradigm.pptx?attach=1&amp;amp;knm=tfile.pptx&quot; class=&quot;&quot;&gt;
    &lt;div class=&quot;image&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;desc&quot;&gt;&lt;div class=&quot;filename&quot;&gt;&lt;span class=&quot;name&quot;&gt;Modality Gap - Driven subspace Alignment Training Paradigm.pptx&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;2.68MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;중간에 내용이 부족해서 Modality gap 쪽으로 정리한 부분을 추가 공유 &lt;/p&gt;</description>
      <category>Paper</category>
      <author>Kim_sang_hyeob</author>
      <guid isPermaLink="true">https://ksh0416.tistory.com/156</guid>
      <comments>https://ksh0416.tistory.com/156#entry156comment</comments>
      <pubDate>Mon, 23 Feb 2026 11:04:53 +0900</pubDate>
    </item>
    <item>
      <title>[The Principles of Diffusion Models] 이해하기 - CH 3. Score-Based Perspective: From EBMs to NCSN</title>
      <link>https://ksh0416.tistory.com/150</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;573&quot; data-origin-height=&quot;645&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sJQ6m/dJMcaaYgmm8/HYaBtwnj4kQKiX1y02LL5K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sJQ6m/dJMcaaYgmm8/HYaBtwnj4kQKiX1y02LL5K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sJQ6m/dJMcaaYgmm8/HYaBtwnj4kQKiX1y02LL5K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsJQ6m%2FdJMcaaYgmm8%2FHYaBtwnj4kQKiX1y02LL5K%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;573&quot; height=&quot;645&quot; data-origin-width=&quot;573&quot; data-origin-height=&quot;645&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;u&gt;(&amp;nbsp; 3.3.4 Why DSM is Denoising: Tweedie&amp;rsquo;s Formula 부분 수정 필요 )&amp;nbsp;&lt;/u&gt;&lt;/span&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;이번 챕터에서는 이제 Energy-Based Model 부터 NCSN 을 배우게 됩니다.&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;이전에 다루었던 VAE 관점에서 벗어나서 , 데이터를 Energy landscape 와 Gradient 를 통해 해석하는 방식을 배웁니다.&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;1. 에너지 기반 모델 (EBM)&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;즉 , 생성 모델의 목표는 이 에너지 지형을 학습하여 , 에너지가 낮은 골짜기가 어디인지 알내는 것입니다.&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;2. Langevin Dynamics 과 score&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터 생성(샘플링) 하는 과정이 Langevin Dynamics 을 따른다. 에너지가 낮은 방향 ( 데이터가 있을 확률이 높은 방향) 으로 조금씩 이동&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;score : 이동해야 할 방향을 알려주는 역할.&amp;nbsp; (수학적으로는 확률 밀도 함수의 기울기 )&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;3. Score-based Diffusion Models&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;이제 본격적으로 더 깊게 알아보도록 하겠습니다.&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;&amp;nbsp;&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;3.1 Energy-Based Models&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 논문에서는 설명되어 있지 않지만 먼저 들어가기 앞서 Energy based models 에 대한 기본 컨셉을 이해해보고자 합니다.&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;a href=&quot;https://process-mining.tistory.com/215&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://process-mining.tistory.com/215&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물리학에서 시스템이 가장 에너지가 가장 낮은 상태로 가려는 성질이 있는데 (엔트로피도 그렇고. ) EBM 은 이 원리를 확률 분포에 이식한것 입니다.&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;에너지 E(x) : 데이터 x 가 진짜 데이터와 얼마나 거리가 먼지 나타내는 척도&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;noisy 한 데이터 = 에너지 높음&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;1) EBM 의 정의 : 확률 = exp(-에너지) / z&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;445&quot; data-origin-height=&quot;75&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nGKjZ/dJMcagRIcW3/qjglTmuONNNR5X89mGD8ok/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nGKjZ/dJMcagRIcW3/qjglTmuONNNR5X89mGD8ok/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nGKjZ/dJMcagRIcW3/qjglTmuONNNR5X89mGD8ok/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnGKjZ%2FdJMcagRIcW3%2FqjglTmuONNNR5X89mGD8ok%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;445&quot; height=&quot;75&quot; data-origin-width=&quot;445&quot; data-origin-height=&quot;75&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터 x 에 대해서 에너지함수 E(x) 를 학습합니다.&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;- exp(-E ) : 에너지가 낮을수록 -&amp;gt; 값이 커짐 -&amp;gt; 확률(p) 가 커짐&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- z : 정규화 상수&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 딱 봐도 z 자체가 계산하기 어려운 문제가 보이죠 ?&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;2) 에너지는 상대값만 의미가 있다 ( 상수항을 건드려도 분포는 동일하다 )&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;558&quot; data-origin-height=&quot;343&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Stojc/dJMcajt5iqa/mz5TcKUmINOSt2mKKhCI5k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Stojc/dJMcajt5iqa/mz5TcKUmINOSt2mKKhCI5k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Stojc/dJMcajt5iqa/mz5TcKUmINOSt2mKKhCI5k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FStojc%2FdJMcajt5iqa%2Fmz5TcKUmINOSt2mKKhCI5k%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;558&quot; height=&quot;343&quot; data-origin-width=&quot;558&quot; data-origin-height=&quot;343&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 에너지를 바꾼다고 가정해봅시다 ( +c )&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 그러면 분자는 다음과 같이 변하고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 분모도 다음과 같이 변하게 됩니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. 따라서 확률을 계산해 봤더니 ..? -&amp;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;그래서 수식적으로 EBM 에서 중요한게 &quot;에너지의 절댓값&quot; 이 아니라 에너지의 &quot;상대적&quot; 차이가 중요한 것을 알 수 있습니다.&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;&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;h3 data-ke-size=&quot;size23&quot;&gt;3.1.1 Modeling Probability Distributions Using Energy Functions&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서 설명한것과 동일하게 EBM 은 에너지 함수 &lt;span&gt;Eϕ(x)를 다음과 같이 정의합니다.&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;592&quot; data-origin-height=&quot;84&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/byGu8W/dJMcaa411VU/tYGsY1Y7r1qfsQEi8vicc1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/byGu8W/dJMcaa411VU/tYGsY1Y7r1qfsQEi8vicc1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/byGu8W/dJMcaa411VU/tYGsY1Y7r1qfsQEi8vicc1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbyGu8W%2FdJMcaa411VU%2FtYGsY1Y7r1qfsQEi8vicc1%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;84&quot; data-origin-width=&quot;592&quot; data-origin-height=&quot;84&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;exp(-&lt;span&gt;Eϕ(x)) : 점수 &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;- 에너지가 낮을수록 -&amp;gt; exp 커짐 =&amp;gt; 낮은 에너지 (= 높은 확률 )&amp;nbsp;&amp;nbsp;&lt;/span&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;span&gt;z : 정규화 상수 &lt;/span&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;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qp2Mp/dJMcadADTj3/eoeD7thyTfedxMJ47SydBk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qp2Mp/dJMcadADTj3/eoeD7thyTfedxMJ47SydBk/img.png&quot; data-origin-width=&quot;206&quot; data-origin-height=&quot;70&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;46.67&quot; style=&quot;width: 46.131%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qp2Mp/dJMcadADTj3/eoeD7thyTfedxMJ47SydBk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fqp2Mp%2FdJMcadADTj3%2FeoeD7thyTfedxMJ47SydBk%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;206&quot; height=&quot;70&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vSXGA/dJMcaa411XA/46s2LpCgikzaLXQABUGdK0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vSXGA/dJMcaa411XA/46s2LpCgikzaLXQABUGdK0/img.png&quot; data-origin-width=&quot;232&quot; data-origin-height=&quot;69&quot; data-is-animation=&quot;false&quot; style=&quot;width: 52.7063%;&quot; data-widthpercent=&quot;53.33&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vSXGA/dJMcaa411XA/46s2LpCgikzaLXQABUGdK0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvSXGA%2FdJMcaa411XA%2F46s2LpCgikzaLXQABUGdK0%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;232&quot; height=&quot;69&quot;/&gt;&lt;/span&gt;&lt;/div&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;그리고 위에서 이야기 했듯이 , EBM 에서는 에너지의 절대적인 값 보다 에너지의 상대값만 의미가 있습니다.&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;하지만 여기서 하나의 문제점이 있는데 Global trade-off 라는 문제점이 있습니다 ( 풍선효과 )&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;마찬가지로 EBM 은 특정 지역의 확률을 독립적으로 할당하는게 아니라 적분해서 값이 1 이기 때문에 , 한 지점의 에너지를 낮추는 순간 -&amp;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;이 global trade off 때문에 EBM 을 학습시키기가 매우 어렵다고 합니다. ( 나머지 모든곳의 에너지를 골고루 높여야 되기 때문 . )&amp;nbsp;&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;848&quot; data-origin-height=&quot;399&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kV7q9/dJMcachtH9h/u0G5dyHPBrhMGLEAphj5qk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kV7q9/dJMcachtH9h/u0G5dyHPBrhMGLEAphj5qk/img.png&quot; data-alt=&quot;좋은 데이터는 높이고 , 안좋은 데이터는 낮추고, ( 에너지를 )&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kV7q9/dJMcachtH9h/u0G5dyHPBrhMGLEAphj5qk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkV7q9%2FdJMcachtH9h%2Fu0G5dyHPBrhMGLEAphj5qk%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;657&quot; height=&quot;309&quot; data-origin-width=&quot;848&quot; data-origin-height=&quot;399&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;좋은 데이터는 높이고 , 안좋은 데이터는 낮추고, ( 에너지를 )&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; Challenges of Maximum Likelihood Training in EBMs. &lt;/b&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;EBM 을 MLE 로 학습하기 위해서 수식을 다음과 같이 분해하면&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;736&quot; data-origin-height=&quot;181&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b8C9oM/dJMcagEcKrS/2NDLCw7kXS4BdhtKPlhVv0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b8C9oM/dJMcagEcKrS/2NDLCw7kXS4BdhtKPlhVv0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b8C9oM/dJMcagEcKrS/2NDLCw7kXS4BdhtKPlhVv0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb8C9oM%2FdJMcagEcKrS%2F2NDLCw7kXS4BdhtKPlhVv0%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;736&quot; height=&quot;181&quot; data-origin-width=&quot;736&quot; data-origin-height=&quot;181&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;poisitve phase ( lowers energy of data )&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 실제 데이터 샘플을 가져와서 그 지점의 에너지를 낮추는 방향으로 업데이트 함&amp;nbsp; (계산 쉬움)&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;Negative phase&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 정규화(전체 적분 1 ) 이 깨지지 않도록 전역적으로 균형을 맞추는 부분 ( 아까 말한 global regularization )&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 계산하기 어렵다. ( intractable )&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;log z 의 미분을 전개해보면 다음과 같은데&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;533&quot; data-origin-height=&quot;295&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/XJ2yG/dJMcabXbnyu/8Ob55Bzr2LepNqDp73Hg8K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/XJ2yG/dJMcabXbnyu/8Ob55Bzr2LepNqDp73Hg8K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/XJ2yG/dJMcabXbnyu/8Ob55Bzr2LepNqDp73Hg8K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXJ2yG%2FdJMcabXbnyu%2F8Ob55Bzr2LepNqDp73Hg8K%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;533&quot; height=&quot;295&quot; data-origin-width=&quot;533&quot; data-origin-height=&quot;295&quot;/&gt;&lt;/span&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;span&gt;&lt;span&gt;x&amp;sim;pϕ&lt;/span&gt;&lt;/span&gt;에서 샘플을 뽑아야 계산을 할 수 있는 형태로 나오게 됩니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;pϕ 를 MC 로 샘플링을 직접 해야하는데 , 이게 매우 어려운 일라고 합니다.&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; &amp;nbsp;cf . Diffusion policy 에서도 이런 언급을 했었습니다 . - negative sample 이 있어야 하는 단점이 있다 . )&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;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.1.2 Motivation:What Is the Score?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;( 핵심 : 확률 밀도 P(x) 를 그 자체로 맞추기 보다 , 그 로그의 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;i&gt;&lt;b&gt;&lt;u&gt;기울기&lt;/u&gt; &lt;/b&gt;&lt;/i&gt;&lt;/span&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. Score 의 정의&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;424&quot; data-origin-height=&quot;54&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/z5FYf/dJMcagxpjYk/TWHvKG6rJgz9EKMjVBezVK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/z5FYf/dJMcagxpjYk/TWHvKG6rJgz9EKMjVBezVK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/z5FYf/dJMcagxpjYk/TWHvKG6rJgz9EKMjVBezVK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fz5FYf%2FdJMcagxpjYk%2FTWHvKG6rJgz9EKMjVBezVK%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;424&quot; height=&quot;54&quot; data-origin-width=&quot;424&quot; data-origin-height=&quot;54&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;확률 밀도 p(x) 가 있을때 score 는 다음과 같이 정의됩니다.&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;- log p(x) 를 지형의 높이라고 한다면 score 는 가장 가파르게 높아지는 방향을 가리키는 벡터입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 기울기x(스코어) 는 x를 조금 움직였을때 log p 가 가장 빨리 증가하는 방향을 알려줍니다.&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;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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;821&quot; data-origin-height=&quot;534&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cVTJuB/dJMcadADUmf/Aj7joP1y02eKTHptcgwKL0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cVTJuB/dJMcadADUmf/Aj7joP1y02eKTHptcgwKL0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cVTJuB/dJMcadADUmf/Aj7joP1y02eKTHptcgwKL0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcVTJuB%2FdJMcadADUmf%2FAj7joP1y02eKTHptcgwKL0%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;665&quot; height=&quot;433&quot; data-origin-width=&quot;821&quot; data-origin-height=&quot;534&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;딥러닝 처음 공부할때 gradient 에서 보던 그림들이랑 매우 유사하죠?&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; Why Model Scores Instead of Densities?&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜 density 대신 score 를 모델링 하는지 설명합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 정규화 상수 z 에서 자유롭다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 스코어는 분포를 완전히 표현한다.&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;1. Freedom from Normalization Constants. &lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정규화 상수 z 에 대해서 자유롭게 됩니다.&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;EBM 이면 위에서 본 수식과 동일하지만&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;374&quot; data-origin-height=&quot;74&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cHvAGv/dJMcabCROEI/MRcipqtKmBgHJYXH3JyFUK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cHvAGv/dJMcabCROEI/MRcipqtKmBgHJYXH3JyFUK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cHvAGv/dJMcabCROEI/MRcipqtKmBgHJYXH3JyFUK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcHvAGv%2FdJMcabCROEI%2FMRcipqtKmBgHJYXH3JyFUK%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;374&quot; height=&quot;74&quot; data-origin-width=&quot;374&quot; data-origin-height=&quot;74&quot;/&gt;&lt;/span&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;Score 를 보면 ( 정의에 있는 수식 그대로 가지고 온것 )&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;709&quot; data-origin-height=&quot;76&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bc0dix/dJMcagqDPdL/gsGF7KmWtiRQUVK7vGHLE0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bc0dix/dJMcagqDPdL/gsGF7KmWtiRQUVK7vGHLE0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bc0dix/dJMcagqDPdL/gsGF7KmWtiRQUVK7vGHLE0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbc0dix%2FdJMcagqDPdL%2FgsGF7KmWtiRQUVK7vGHLE0%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;709&quot; height=&quot;76&quot; data-origin-width=&quot;709&quot; data-origin-height=&quot;76&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;log z 가 x 에 대한 상수라서 미분하면 사라지게 됩니다.&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;원래 density 학습(MLE) 는 log Z 때문에 막히지만 , Score 학습은 log Z 를 원칙적으로 bypass 할 수 있게됩니다.&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; 2. A Complete Representation. &lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;score s(x) ( log p 미분값 / 기울 ) 을 모든 x 에 대해서 알고 있다면 , log p(x) 를 전부 복원이 가능해 집니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;( 적분하면 상수가 나오지만 , 마지막 상수의 값은 적분한p 값 = 1 이라는 성질을 통해서 결정가능해 집니다. )&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;( 너무 간략하게 나와있어서 좋은 방식으로 설명하기 어려워 gpt 에게 도움을 좀 받았습니다 )&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;667&quot; data-origin-height=&quot;468&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/DEtMh/dJMcagRIdVV/pAq7lJtU0w2kZoUSSD5qO0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/DEtMh/dJMcagRIdVV/pAq7lJtU0w2kZoUSSD5qO0/img.png&quot; data-alt=&quot;with gpt&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/DEtMh/dJMcagRIdVV/pAq7lJtU0w2kZoUSSD5qO0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDEtMh%2FdJMcagRIdVV%2FpAq7lJtU0w2kZoUSSD5qO0%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;646&quot; height=&quot;453&quot; data-origin-width=&quot;667&quot; data-origin-height=&quot;468&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;with gpt&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;기준점 xo 에서 x 까지 가는 경로 하나 잡고 계산하면&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;621&quot; data-origin-height=&quot;65&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/smQeh/dJMcac9zBaj/44UItEarA7Srh2KWymasJ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/smQeh/dJMcac9zBaj/44UItEarA7Srh2KWymasJ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/smQeh/dJMcac9zBaj/44UItEarA7Srh2KWymasJ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsmQeh%2FdJMcac9zBaj%2F44UItEarA7Srh2KWymasJ0%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;621&quot; height=&quot;65&quot; data-origin-width=&quot;621&quot; data-origin-height=&quot;65&quot;/&gt;&lt;/span&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;- 경로 위에서 score 이 가리키는 방향 성분 계속 더하면 --&amp;gt; 최종적인 log p 의 높이 변화량을 얻을 수 있습니다.&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;h3 data-ke-size=&quot;size23&quot;&gt;3.1.3 Training EBMs via Score Matching&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전부터 계속 EBM 에서 MLE 가 어려운 이유를 뽑을때 z 가 intractable 하기 때문에 MLE 가 어렵다고 했었죠 ?&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 그걸 bypass 하기 위해서 스코어 ( 로그 미분 ) 형태로 보면 z 를 몰라도 괜찮었습니다.&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;진짜 score 와 모델 score 를 맞추는 과정이 있어야 합니다(당연하게도). 따라서 수식은 아래와 같습니다.&amp;nbsp;&amp;nbsp;&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;736&quot; data-origin-height=&quot;56&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MHSgf/dJMcajnjFsj/SlV5kRRnwpayTaPJNudomK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MHSgf/dJMcajnjFsj/SlV5kRRnwpayTaPJNudomK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MHSgf/dJMcajnjFsj/SlV5kRRnwpayTaPJNudomK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMHSgf%2FdJMcajnjFsj%2FSlV5kRRnwpayTaPJNudomK%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;736&quot; height=&quot;56&quot; data-origin-width=&quot;736&quot; data-origin-height=&quot;56&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- log p_phi (x) : 학습할 score ( 모델이 제시하는 확률이 증가하는 방향장 )&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- log p_data (x) : 데이터 분포의 score ( 진짜 데이터 분포의 확률이 증가하는 방향장 )&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;근데 여기서 문제가 p_data 를 모른다는것 입니다 ( 자연스럽게 log 취한 형식도 모르게 됨 . )&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;( 앞에 파트에서도 마찬가지로 p_data 는 사실상 저희가 구할 수 있는 형태였던적이 한번도 없었습니다. 이번에는 어떻게 우회하는지 잘 살펴보면 됩니다. )&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해결책 : 부분적으로 해결한다.&amp;nbsp;&amp;nbsp;&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;622&quot; data-origin-height=&quot;65&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/z7nhU/dJMcadADUYq/a8EDXzXIeLC0IAHOpJxiqK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/z7nhU/dJMcadADUYq/a8EDXzXIeLC0IAHOpJxiqK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/z7nhU/dJMcadADUYq/a8EDXzXIeLC0IAHOpJxiqK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fz7nhU%2FdJMcadADUYq%2Fa8EDXzXIeLC0IAHOpJxiqK%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;622&quot; height=&quot;65&quot; data-origin-width=&quot;622&quot; data-origin-height=&quot;65&quot;/&gt;&lt;/span&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;( Proof . )&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;D.2.1 ( appendix )&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;어떻게 해서 이 수식이 나오게 되었는지 따로 깊게 설명하고 있지는 않고 appendix 부분으로 빠져있는데 , 이부분도 공부 많이될거 같아서 가져왔습니다.&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;u&gt;&lt;b&gt;1) norm 수식을 전개한다.&lt;/b&gt;&lt;/u&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존 수식 L_sm 에서 제곱을 전개만 한 형태입니다 .&amp;nbsp;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;887&quot; data-origin-height=&quot;211&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bGd0pO/dJMcagdexek/71TxW1A8ENaQUTWKkGlSpK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bGd0pO/dJMcagdexek/71TxW1A8ENaQUTWKkGlSpK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bGd0pO/dJMcagdexek/71TxW1A8ENaQUTWKkGlSpK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbGd0pO%2FdJMcagdexek%2F71TxW1A8ENaQUTWKkGlSpK%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;887&quot; height=&quot;211&quot; data-origin-width=&quot;887&quot; data-origin-height=&quot;211&quot;/&gt;&lt;/span&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;근데 마지막 E(s(x)) 는 상수취급 하니까 C 로 묶습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 사실상&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;481&quot; data-origin-height=&quot;78&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bblqzd/dJMcab33EGg/cRAvSGZpknk7vlDp8FUvHK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bblqzd/dJMcab33EGg/cRAvSGZpknk7vlDp8FUvHK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bblqzd/dJMcab33EGg/cRAvSGZpknk7vlDp8FUvHK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbblqzd%2FdJMcab33EGg%2FcRAvSGZpknk7vlDp8FUvHK%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;481&quot; height=&quot;78&quot; data-origin-width=&quot;481&quot; data-origin-height=&quot;78&quot;/&gt;&lt;/span&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;2) 교차항 처리&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;908&quot; data-origin-height=&quot;232&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/3QcMg/dJMcacBUB5y/uCK7UrJ0GZ9UqMuqUTKQ1k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/3QcMg/dJMcacBUB5y/uCK7UrJ0GZ9UqMuqUTKQ1k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/3QcMg/dJMcacBUB5y/uCK7UrJ0GZ9UqMuqUTKQ1k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F3QcMg%2FdJMcacBUB5y%2FuCK7UrJ0GZ9UqMuqUTKQ1k%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;698&quot; height=&quot;178&quot; data-origin-width=&quot;908&quot; data-origin-height=&quot;232&quot;/&gt;&lt;/span&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;1. 기대값을 적분으로 쓴다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;603&quot; data-origin-height=&quot;73&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cP61eP/dJMcah4hSfh/sW71xYWHiyKjToKFzCSkxk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cP61eP/dJMcah4hSfh/sW71xYWHiyKjToKFzCSkxk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cP61eP/dJMcah4hSfh/sW71xYWHiyKjToKFzCSkxk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcP61eP%2FdJMcah4hSfh%2FsW71xYWHiyKjToKFzCSkxk%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;578&quot; height=&quot;70&quot; data-origin-width=&quot;603&quot; data-origin-height=&quot;73&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;s(x) 는 데이터 스코어 이고 기대값 정의에 따라서 수식을 만듭니다.&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;2. 데이터 스코어 정의&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;288&quot; data-origin-height=&quot;52&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/YdIjB/dJMcacIGww0/lRqy57kjktWkYCaZlQoK4k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/YdIjB/dJMcacIGww0/lRqy57kjktWkYCaZlQoK4k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/YdIjB/dJMcacIGww0/lRqy57kjktWkYCaZlQoK4k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYdIjB%2FdJMcacIGww0%2FlRqy57kjktWkYCaZlQoK4k%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;288&quot; height=&quot;52&quot; data-origin-width=&quot;288&quot; data-origin-height=&quot;52&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;337&quot; data-origin-height=&quot;96&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bo7gP8/dJMcajuc6dl/7Z2k3Ct2YentcPD6Zhra91/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bo7gP8/dJMcajuc6dl/7Z2k3Ct2YentcPD6Zhra91/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bo7gP8/dJMcajuc6dl/7Z2k3Ct2YentcPD6Zhra91/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbo7gP8%2FdJMcajuc6dl%2F7Z2k3Ct2YentcPD6Zhra91%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;337&quot; height=&quot;96&quot; data-origin-width=&quot;337&quot; data-origin-height=&quot;96&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;그냥 스코어의 정의를 가지고와서 다시 쓴 형태입니다.&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;3. 대입한다. ( p_data 가 약분된다 )&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;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;890&quot; data-origin-height=&quot;103&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bCnV6G/dJMcahpGG6c/QjK23OnpX3JmdbRyse4AMk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bCnV6G/dJMcahpGG6c/QjK23OnpX3JmdbRyse4AMk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bCnV6G/dJMcahpGG6c/QjK23OnpX3JmdbRyse4AMk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbCnV6G%2FdJMcahpGG6c%2FQjK23OnpX3JmdbRyse4AMk%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;716&quot; height=&quot;83&quot; data-origin-width=&quot;890&quot; data-origin-height=&quot;103&quot;/&gt;&lt;/span&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;그럼 여기서 p_data(x) 가 약분하는 형태가 됩니다. 그래서 맨 위 수식에서 두번째 줄 수식이 나오게 됩니다.&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;&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;&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;&lt;u&gt;&lt;b&gt;&amp;nbsp;3) 성분별로 분해 ( 내적 -&amp;gt; 좌표합으로 )&amp;nbsp;&lt;/b&gt;&lt;/u&gt;&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;838&quot; data-origin-height=&quot;638&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/p1V6N/dJMcaiozGi3/yvkXHvOAkfayI9kTCTiZX1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/p1V6N/dJMcaiozGi3/yvkXHvOAkfayI9kTCTiZX1/img.png&quot; data-alt=&quot;with gpt&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/p1V6N/dJMcaiozGi3/yvkXHvOAkfayI9kTCTiZX1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fp1V6N%2FdJMcaiozGi3%2FyvkXHvOAkfayI9kTCTiZX1%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;567&quot; height=&quot;432&quot; data-origin-width=&quot;838&quot; data-origin-height=&quot;638&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;with gpt&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;이부분은 별거 없습니다. 그냥 성분대로 수식에 넣고 정리한겁니다.&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;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;i&gt;&lt;b&gt;&lt;u&gt;&amp;lt; 핵심&amp;nbsp; : 부분적분 전개 &amp;gt;&lt;/u&gt;&lt;/b&gt;&lt;/i&gt;&lt;/span&gt;&lt;/h3&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;cf. Lemma ( 다변수 부분 적분 )-&amp;gt; 수능볼떄 많이 쓰는 그거 맞습니다 ( 그적 미적 .. 오랜만이네요 )&amp;nbsp;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;670&quot; data-origin-height=&quot;99&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bMyyXN/dJMcafrQ9OH/wu6KsZBv7QlMuNmXBQCaOk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bMyyXN/dJMcafrQ9OH/wu6KsZBv7QlMuNmXBQCaOk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bMyyXN/dJMcafrQ9OH/wu6KsZBv7QlMuNmXBQCaOk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbMyyXN%2FdJMcafrQ9OH%2Fwu6KsZBv7QlMuNmXBQCaOk%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;670&quot; height=&quot;99&quot; data-origin-width=&quot;670&quot; data-origin-height=&quot;99&quot;/&gt;&lt;/span&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;결국 저희 수식도 위와 똑같이 전개하면.&amp;nbsp;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1071&quot; data-origin-height=&quot;108&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/QlNlv/dJMcaiIQAGb/U3xIoW0qfeCECBjkwJs8Y1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/QlNlv/dJMcaiIQAGb/U3xIoW0qfeCECBjkwJs8Y1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/QlNlv/dJMcaiIQAGb/U3xIoW0qfeCECBjkwJs8Y1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQlNlv%2FdJMcaiIQAGb%2FU3xIoW0qfeCECBjkwJs8Y1%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;1071&quot; height=&quot;108&quot; data-origin-width=&quot;1071&quot; data-origin-height=&quot;108&quot;/&gt;&lt;/span&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;여기서 계항이 0이 되게 됩니다. 왜냐하면 증명에서 다음과 같은 가정을 두는데&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;575&quot; data-origin-height=&quot;57&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bknYWd/dJMcadtZnMt/wKK1WpKcPhyFrkWaS7LDHk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bknYWd/dJMcadtZnMt/wKK1WpKcPhyFrkWaS7LDHk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bknYWd/dJMcadtZnMt/wKK1WpKcPhyFrkWaS7LDHk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbknYWd%2FdJMcadtZnMt%2FwKK1WpKcPhyFrkWaS7LDHk%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;504&quot; height=&quot;50&quot; data-origin-width=&quot;575&quot; data-origin-height=&quot;57&quot;/&gt;&lt;/span&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;&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;그래서 R 을 점점 크게 보내면 p_data(R) 은 -&amp;gt; 0 에 수렴하게 됩니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 위 수식이 0에 가까워지는 것이죠&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;그래서 결론적으로 뒤에있는 수식이 0이 됩니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;자 다시 돌아와서 이제 경계항이 0이라는 것 까지 이해했으면 , 부분적분 결과 i = 1 .... d 를 합쳐서 다시 표현해야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;642&quot; data-origin-height=&quot;96&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bcorSA/dJMcahJZFi8/Kk3B1t6vbXUauzIjHiMfc1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bcorSA/dJMcahJZFi8/Kk3B1t6vbXUauzIjHiMfc1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bcorSA/dJMcahJZFi8/Kk3B1t6vbXUauzIjHiMfc1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbcorSA%2FdJMcahJZFi8%2FKk3B1t6vbXUauzIjHiMfc1%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;582&quot; height=&quot;87&quot; data-origin-width=&quot;642&quot; data-origin-height=&quot;96&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;방금 위에서 부분적분 전개해서 얻은 식이 이거죠 ? 이걸 i = 1 ... D 를 다시 전부 합치기만 하면 됩니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;876&quot; data-origin-height=&quot;267&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bl2Vpn/dJMcagqK0W2/IKB7QPKYj2gm7kvIpnjbm1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bl2Vpn/dJMcagqK0W2/IKB7QPKYj2gm7kvIpnjbm1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bl2Vpn/dJMcagqK0W2/IKB7QPKYj2gm7kvIpnjbm1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbl2Vpn%2FdJMcagqK0W2%2FIKB7QPKYj2gm7kvIpnjbm1%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;629&quot; height=&quot;192&quot; data-origin-width=&quot;876&quot; data-origin-height=&quot;267&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;이떄 안에 수식이 Trace 이므로&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;( s(x) 는 D X D 야코비안이고 , 대각원소가 정확히 안에 수식과 같으니까 -&amp;gt; Trace 가 정확히 그 합이 되게 됩니다. )&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 수식이&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;542&quot; data-origin-height=&quot;80&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HPdv0/dJMcaia3vyQ/ZMD8Q4YkHNtIiCOR8uMCik/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HPdv0/dJMcaia3vyQ/ZMD8Q4YkHNtIiCOR8uMCik/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HPdv0/dJMcaia3vyQ/ZMD8Q4YkHNtIiCOR8uMCik/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHPdv0%2FdJMcaia3vyQ%2FZMD8Q4YkHNtIiCOR8uMCik%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;76&quot; data-origin-width=&quot;542&quot; data-origin-height=&quot;80&quot;/&gt;&lt;/span&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;다음과 같이 정리됩니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이걸 다시 loss 식에 그대로 대입 하면&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;463&quot; data-origin-height=&quot;92&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/WqmpH/dJMcaaqysi3/NFiPpEaFOuBj0QaVeuCvlk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/WqmpH/dJMcaaqysi3/NFiPpEaFOuBj0QaVeuCvlk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/WqmpH/dJMcaaqysi3/NFiPpEaFOuBj0QaVeuCvlk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWqmpH%2FdJMcaaqysi3%2FNFiPpEaFOuBj0QaVeuCvlk%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;463&quot; height=&quot;92&quot; data-origin-width=&quot;463&quot; data-origin-height=&quot;92&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;747&quot; data-origin-height=&quot;141&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cvl12u/dJMcafSWEzo/KApQAKW4BFpQqU6LKZKJR1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cvl12u/dJMcafSWEzo/KApQAKW4BFpQqU6LKZKJR1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cvl12u/dJMcafSWEzo/KApQAKW4BFpQqU6LKZKJR1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcvl12u%2FdJMcafSWEzo%2FKApQAKW4BFpQqU6LKZKJR1%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;625&quot; height=&quot;118&quot; data-origin-width=&quot;747&quot; data-origin-height=&quot;141&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;( 위쪽에 있는 수식에 대입만 하면 다음과 같은 수식이 됩니다. / C 는 아까 말했던 상수취급 )&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;증명 끗&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&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;span&gt;&lt;span&gt;E&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;ϕ&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;) :&amp;nbsp; 해당 값이 낮을 수록 x 는 그럴듯한 데이터 ( 확률 높고 ) / 해당값이 높으면 그럴듯 하지 않다.&amp;nbsp;&lt;/span&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;span&gt;그래서 학습의 목표는 데이터가 자주 나오는 곳은 낮은 에너지로 만들고 , 데이터 주변은 높은 에너지로 만든다. 였습니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;( 데이터가 있는 지점을 에너지 골짜기의 '가장 깊은 바닥'으로 만들어라 -&amp;gt; 이걸 2개라 나눠서 만든다고 생각하면 됩니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;가장 깊은&quot; + &quot; 바닥&quot; 이런 식으로 말이죠&amp;nbsp;&lt;span&gt;)&lt;/span&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;수식에서 항 2개가 있는데 하나씩 살펴보면&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;항1 ) : 1/2 || &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&amp;nabla;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;E&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;ϕ&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;(x) || ^2&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;nabla; &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;E&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;ϕ&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;(x) 는 지형의 경사인데&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;&amp;nabla;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;E&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;ϕ&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;(x) || ^2 이 크면 데이터 근처에서 지형이 매우 급경사라는 의미의미로&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;- 데이터 주변에서 데이터가 너무 크게 요동치지 않게 만들고&amp;nbsp;&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;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;항2 ) Tr( &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&amp;nabla;^2&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;E&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;ϕ&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;(x) )&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;span style=&quot;color: #333333; text-align: start;&quot;&gt;&amp;nabla;^2&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;E&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;ϕ&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;(x) 는 지형의 곡률인데 ( 얼마나 휘었는지 ? )&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;trace 가 그 곡률을 합친 값입니다.&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;- 골짜기 모양이 되도록 휘어짐을 맞추는 역할을 해준다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 조금 더 직관적으로 설명하자면 , 앞 수식에 데이터가 존재하는 곳이 &quot;평평&quot; 하게 만들라고 수식을 정했었죠 ?&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 평평한 조건만 가지고는 해당 부분이 2차원 함수처럼 위로 볼록한지 아래로 볼록한지 알 수 없습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 이 수식이 &quot;곡률&quot; 을 조절하게 해주는데 스코어 매칭을 최소화 하는 과정에서 이항이&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터 주위의 벡터들이 오목한 valley 로 만들게 해주는 것 입니다.&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;&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;참 이런걸 어떻게 생각했는지 대단한것 같습니다.&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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt; 3.1.4 Langevin Sampling with Score Functions&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저희가 지금까지 알아본 SCORES 는 데이터가 있을 확률을 가르키는 &quot;방향&quot; 에 대한 이야기였고&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;에너지가 낮을수록 P(X) 는 높고 ( 좋은 샘플이고 ) / 그 반대는 나쁜 샘플을 생성합니다.&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;그래서 샘플링은 아래 그림처럼 에너지를 낮추는 방향으로 X 를 움직이면 좋은 샘플이 나오게 될 것 입니다.&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1023&quot; data-origin-height=&quot;640&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bS6k8E/dJMcai28DlI/gw0o2KmzM7CJ7PUxokJqC0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bS6k8E/dJMcai28DlI/gw0o2KmzM7CJ7PUxokJqC0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bS6k8E/dJMcai28DlI/gw0o2KmzM7CJ7PUxokJqC0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbS6k8E%2FdJMcai28DlI%2Fgw0o2KmzM7CJ7PUxokJqC0%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;703&quot; height=&quot;440&quot; data-origin-width=&quot;1023&quot; data-origin-height=&quot;640&quot;/&gt;&lt;/span&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; Discrete-Time Langevin Dynamics.&lt;/b&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;샘플링 수식은 다음과 같이 되는데&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;822&quot; data-origin-height=&quot;54&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dPpaaG/dJMcagxwDZz/xBc8ClEz8kVnyppZDZo1tk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dPpaaG/dJMcagxwDZz/xBc8ClEz8kVnyppZDZo1tk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dPpaaG/dJMcagxwDZz/xBc8ClEz8kVnyppZDZo1tk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdPpaaG%2FdJMcagxwDZz%2FxBc8ClEz8kVnyppZDZo1tk%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;670&quot; height=&quot;44&quot; data-origin-width=&quot;822&quot; data-origin-height=&quot;54&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;985&quot; data-origin-height=&quot;168&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oEGW3/dJMcacu8ope/EvKPEKCOI8bjZV6dWcZP6k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oEGW3/dJMcacu8ope/EvKPEKCOI8bjZV6dWcZP6k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oEGW3/dJMcacu8ope/EvKPEKCOI8bjZV6dWcZP6k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoEGW3%2FdJMcacu8ope%2FEvKPEKCOI8bjZV6dWcZP6k%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;772&quot; height=&quot;132&quot; data-origin-width=&quot;985&quot; data-origin-height=&quot;168&quot;/&gt;&lt;/span&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;(1) &lt;span&gt;&amp;minus;&lt;/span&gt;&lt;span&gt;&amp;eta;&lt;/span&gt;&lt;span&gt;&amp;nabla;&lt;/span&gt;&lt;span&gt;E&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;- 에너지가 가장 빠르게 감소하는 방향을 의미합니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;- 해당 xn 에서 다음 스탭으로 갈때 가장 빠르게 감소하는 방향로 가게 해 줍니다.&amp;nbsp;&lt;/span&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;span&gt;(2) &lt;span&gt;+root(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;&amp;eta;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​)&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;ϵ&lt;/span&gt; &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;- 무작위로 흔들어주는 노이즈 역할을 합니다.&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;- 앞의 수식만 사용하면 local minia 에 갇히기 쉬운데 노이즈를 더해줘서 이 문제를 해결하고자 하였습니다.&amp;nbsp;&lt;/span&gt;&lt;/span&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;span&gt;&lt;span&gt;-&amp;gt; 그렇다면 왜 노이즈 스케일이 root(2n) 인가 ?&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;- &lt;span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;&amp;eta;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;가 작아지면 한 스텝 이동량이 줄어든다.&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;- 노이즈도 거기에 맞춰서 줄어야지 Continuous-Time 에서 깔끔하게 수렴한다 .&amp;nbsp;&lt;/span&gt;&lt;/span&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; Continuous-Time Langevin Dynamics.&lt;/b&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;앞에서 본 수식에서&amp;nbsp; &lt;span&gt;&lt;span&gt;&amp;eta;&lt;/span&gt;&lt;/span&gt;를 &amp;ldquo;시간 간격&quot; 이라고 보고 , 해당 간격을 매우 작게 쪼개면 SDE 확률 과정으로 수렴하게 되고&lt;br /&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;509&quot; data-origin-height=&quot;47&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nd4IY/dJMcaaKQ9aY/HO1dxxFSwP4wtj2sp8YI7k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nd4IY/dJMcaaKQ9aY/HO1dxxFSwP4wtj2sp8YI7k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nd4IY/dJMcaaKQ9aY/HO1dxxFSwP4wtj2sp8YI7k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fnd4IY%2FdJMcaaKQ9aY%2FHO1dxxFSwP4wtj2sp8YI7k%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;477&quot; height=&quot;44&quot; data-origin-width=&quot;509&quot; data-origin-height=&quot;47&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음과 같이 SDE 입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;( &lt;a href=&quot;https://process-mining.tistory.com/207&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://process-mining.tistory.com/207&lt;/a&gt;&amp;nbsp; - sde 에 관해서 참고 )&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;SDE 형태가 결국 두부분인데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 드리프트 : 결정적인 방향성 ( 우리는 여기서 스코어 )&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 무작위한 변화 : Brownian motion 이라고 하는 무작위 노이즈 .&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ODE 와는 다르게 SDE 는 같은 Xo 에서 시작해도 매번 실행할떄마다 결과가 조금씩 달라짐.&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;( Continuous-Time Langevin Dynamics ~ Inherent Challenges of Langevin Sampling. 보충 설명 필요 )&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://seanlife.tistory.com/entry/%EB%B8%8C%EB%9D%BC%EC%9A%B4-%EC%9A%B4%EB%8F%99Brownian-motion-%EA%B3%B5%EA%B8%B0-%EC%A4%91-%EB%A8%BC%EC%A7%80%EC%97%90%EC%84%9C%EB%B6%80%ED%84%B0-%EC%A3%BC%EC%8B%9D%EA%B9%8C%EC%A7%80&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://seanlife.tistory.com/entry/%EB%B8%8C%EB%9D%BC%EC%9A%B4-%EC%9A%B4%EB%8F%99Brownian-motion-%EA%B3%B5%EA%B8%B0-%EC%A4%91-%EB%A8%BC%EC%A7%80%EC%97%90%EC%84%9C%EB%B6%80%ED%84%B0-%EC%A3%BC%EC%8B%9D%EA%B9%8C%EC%A7%80&lt;/a&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;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3.2 From Energy-Based to Score-Based Generative Models&amp;nbsp;&lt;/h2&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;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.2.1 Training with Score Matching&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다시 돌아와서 score는 다음과 같습니다.&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;304&quot; data-origin-height=&quot;66&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bHYwVL/dJMcacB20L9/iR1wj5RHq5j9kK472J25m0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bHYwVL/dJMcacB20L9/iR1wj5RHq5j9kK472J25m0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bHYwVL/dJMcacB20L9/iR1wj5RHq5j9kK472J25m0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbHYwVL%2FdJMcacB20L9%2FiR1wj5RHq5j9kK472J25m0%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;272&quot; height=&quot;59&quot; data-origin-width=&quot;304&quot; data-origin-height=&quot;66&quot;/&gt;&lt;/span&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;- log p(x) 는 이 위치x 에서 얼마나 그럴듯한지 ( 높은 확률 밀도인지 ) 이고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- log p(x) 의 기울기는 어느 방향으로 움직이면 더 그럴듯한지 인지 알려주는 방향 화살표라고 보시면 됩니다.&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;앞서서 계속 이야기 했지만 , 결국 저희는 P_data 를 알 수 없기 떄문에 신경망으로 파라미터화된 벡터장으로 근사합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;( score s(x) 를 신경망으로 배우는 것이죠. )&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;225&quot; data-origin-height=&quot;68&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/PFrQO/dJMcag5wDCM/dOrt5jIgUMb8wm36vvZfoK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/PFrQO/dJMcag5wDCM/dOrt5jIgUMb8wm36vvZfoK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/PFrQO/dJMcag5wDCM/dOrt5jIgUMb8wm36vvZfoK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPFrQO%2FdJMcag5wDCM%2FdOrt5jIgUMb8wm36vvZfoK%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;225&quot; height=&quot;68&quot; data-origin-width=&quot;225&quot; data-origin-height=&quot;68&quot;/&gt;&lt;/span&gt;&lt;/figure&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;1186&quot; data-origin-height=&quot;728&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/q9oVj/dJMcadVcSSI/IV4bvu7iNmgc6rxv1OdhJ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/q9oVj/dJMcadVcSSI/IV4bvu7iNmgc6rxv1OdhJ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/q9oVj/dJMcadVcSSI/IV4bvu7iNmgc6rxv1OdhJ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fq9oVj%2FdJMcadVcSSI%2FIV4bvu7iNmgc6rxv1OdhJ1%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;736&quot; height=&quot;452&quot; data-origin-width=&quot;1186&quot; data-origin-height=&quot;728&quot;/&gt;&lt;/span&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;score matching : 정답 socre 에 MSE 로 맞춘다.&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;MSE 로 아래와 같이 근사를 하고 싶은데 s(x) 를 모르기 때문에 계산을 할 수 없습니다.&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;857&quot; data-origin-height=&quot;119&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2wkA9/dJMcaiIZp5h/aJJ7yonJdklzesGRttdQNK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2wkA9/dJMcaiIZp5h/aJJ7yonJdklzesGRttdQNK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2wkA9/dJMcaiIZp5h/aJJ7yonJdklzesGRttdQNK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2wkA9%2FdJMcaiIZp5h%2FaJJ7yonJdklzesGRttdQNK%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;756&quot; height=&quot;105&quot; data-origin-width=&quot;857&quot; data-origin-height=&quot;119&quot;/&gt;&lt;/span&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;그래서 다시 Tractable Score Matching 으로 넘깁니다.&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;앞서 증명했던 방식으로 정답 score 없는 형식으로 바꿉니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- S(X) 가 들어가는 항이 없고 ,&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;b&gt;&lt;span&gt;&lt;span&gt;sϕ&lt;/span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;와 데이터 샘플만으로 계산 가능한 형태&lt;/b&gt;로 바꿉니다.&amp;nbsp;&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;1060&quot; data-origin-height=&quot;470&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zgWDT/dJMcahXEGhx/L5fMozdiHsopPUTcKWcg0k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zgWDT/dJMcahXEGhx/L5fMozdiHsopPUTcKWcg0k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zgWDT/dJMcahXEGhx/L5fMozdiHsopPUTcKWcg0k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzgWDT%2FdJMcahXEGhx%2FL5fMozdiHsopPUTcKWcg0k%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;675&quot; height=&quot;299&quot; data-origin-width=&quot;1060&quot; data-origin-height=&quot;470&quot;/&gt;&lt;/span&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; Intuition of Equation (3.2.2).&amp;nbsp;&lt;/b&gt;&lt;b&gt;&lt;/b&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1) magnitude 항 : 고밀도 영역을 stationary 로 만든다.&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;99&quot; data-origin-height=&quot;54&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bNKPlz/dJMcabXqFat/bI3sVtvKIrOrGmwWPKMTu1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bNKPlz/dJMcabXqFat/bI3sVtvKIrOrGmwWPKMTu1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bNKPlz/dJMcabXqFat/bI3sVtvKIrOrGmwWPKMTu1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbNKPlz%2FdJMcabXqFat%2FbI3sVtvKIrOrGmwWPKMTu1%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;99&quot; height=&quot;54&quot; data-origin-width=&quot;99&quot; data-origin-height=&quot;54&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기대값이 x ~ p_data 에서 계산되므로 , 데이터 밀도가 큰 영역이 loss에 가장 크게 기여합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 이 항을 최소화 하면 해당영역에서 &lt;b&gt;&lt;span&gt;&lt;span&gt;sϕ 가&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;span&gt;&lt;span&gt;0이 되도록 만듭니다. 따라서 고밀도 영역에서 벡터장이 0에 가까워지면서 움직이지않는 정지점 ( stationary ) 가 되도록 만듭니다.&amp;nbsp;&lt;/span&gt;&lt;/span&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;span&gt;&lt;span&gt;하지만 이것만 조재한다면 stationary 가 안정적인지 불안정인지 결정이 안됩니다.&lt;/span&gt;&lt;/span&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;2) divergence 항 : stationary 를 끌어당기는 sink 로 만든다.&amp;nbsp;&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;339&quot; data-origin-height=&quot;63&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bxzqJy/dJMb99L3Xak/lOqFkoP13bwSKrzRzRdu4K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bxzqJy/dJMb99L3Xak/lOqFkoP13bwSKrzRzRdu4K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bxzqJy/dJMb99L3Xak/lOqFkoP13bwSKrzRzRdu4K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbxzqJy%2FdJMb99L3Xak%2FlOqFkoP13bwSKrzRzRdu4K%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;339&quot; height=&quot;63&quot; data-origin-width=&quot;339&quot; data-origin-height=&quot;63&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 divergence 항이 음수면 sink ( =&amp;nbsp; 정지점으로 모이는 것 ) 입니다. ( LOSS 이기 떄문에 작으면 작을수록 좋다 . )&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;( 반대로 0보다 크면 발산 . )&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;앞서 mangitude 항에서는 0이라서 멈추게 되지만 주변은 수축 ( 음수 ) 로 만드니까 근처 출발점들이 stationary 쪽으로 모여들게 됩니다. 따라서 stationary 지점이 멈춤 이 아니라 주변을 발아들이는 sink 가 됩니다.&amp;nbsp;&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;b&gt;3.2.2 Sampling with Langevin Dynamics&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 저희가 가진 모델은 스코어 모델 = sϕ&amp;times; (x)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- P_data(x) 에서 샘플을 뽑는게 목표였지만 그 자체는 알 수 없기때문에&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 스코어 &lt;span&gt;&lt;span&gt;&amp;nabla;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;lo&lt;span&gt;g &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;p_&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;data&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;) 를 근사하는 sϕ&amp;times; (x) 를 학습시켰습니다.&amp;nbsp;&lt;/span&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;599&quot; data-origin-height=&quot;40&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/WvL8b/dJMcaa5iIlE/VyRCk2g317yrvakUjXcqo0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/WvL8b/dJMcaa5iIlE/VyRCk2g317yrvakUjXcqo0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/WvL8b/dJMcaa5iIlE/VyRCk2g317yrvakUjXcqo0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWvL8b%2FdJMcaa5iIlE%2FVyRCk2g317yrvakUjXcqo0%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;599&quot; height=&quot;40&quot; data-origin-width=&quot;599&quot; data-origin-height=&quot;40&quot;/&gt;&lt;/span&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;xn : 현재 위치&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;span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;&amp;eta;&lt;/span&gt;&lt;span&gt;&lt;span&gt;s&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;ϕ&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&amp;lowast;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;n&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; : 확률 높은 쪽으로 이동&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 스코어가 가리키는 방향으로 조금 이동 ( 앞 변수는 learning rate )&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;( 보다 조금 더 다양한 경로를 위함 . )&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;continuous version : SDE&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;319&quot; data-origin-height=&quot;45&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bd8iUb/dJMcabJVOwe/jnrog1sV6eVXWk9gMuuP20/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bd8iUb/dJMcabJVOwe/jnrog1sV6eVXWk9gMuuP20/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bd8iUb/dJMcabJVOwe/jnrog1sV6eVXWk9gMuuP20/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbd8iUb%2FdJMcabJVOwe%2Fjnrog1sV6eVXWk9gMuuP20%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;319&quot; height=&quot;45&quot; data-origin-width=&quot;319&quot; data-origin-height=&quot;45&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 내용을 SDE 방식&amp;nbsp; (그니까 시간이 계속 흐른다고 보고 ) 적은 방식이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 앞쪽 : 확률 높은 방향으로 움직이는 DRIFT&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 뒤쪽 : 무작위로 흔들리는 ( diffusion )&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;결국 SDE 를 컴퓨터에 그대로 못 돌리니까 시간 간격을 잘라서 근사하면 위의 Langevin update 가 나옵니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;( SDE -&amp;gt; 작은 스텝으로 쪼개서 구현 == Langevin update )&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;&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;h2 data-ke-size=&quot;size26&quot;&gt;3.3 Denoising Score Matching&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.3.1 Motivation&lt;/h3&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;677&quot; data-origin-height=&quot;99&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/beVeaW/dJMcahXFkFV/xkJbCMQKVG9Hz3P0koHmwk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/beVeaW/dJMcahXFkFV/xkJbCMQKVG9Hz3P0koHmwk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/beVeaW/dJMcahXFkFV/xkJbCMQKVG9Hz3P0koHmwk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbeVeaW%2FdJMcahXFkFV%2FxkJbCMQKVG9Hz3P0koHmwk%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;444&quot; height=&quot;65&quot; data-origin-width=&quot;677&quot; data-origin-height=&quot;99&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 수식은 tractable 하지만 , 여전히 Jacobian Tr(s(X)) 를 계산해야하는 문제가 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를들어서 이미지면 보통 256 X 256 X 3&amp;nbsp; = 2,000,000 정도라고 가정하면 jacobian 은 200,00 x 200,000 행렬 이므로 원소만해도 어마어마합니다. 따라서 jacobian 을 만들어서 trace 를 구하는건 거의 불가능합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또 , 대각선만 필요하니까 대각선만 계산하자 라고 해도 대각 원소 미분값들을 모두 구해야해서 구현상 D 번 수준의 미분/역전파가 들어갈 수 있고 최악의 경우 O(D^2) 까지 커질 수 있습니다.&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;b&gt; Sliced Score Matching and Hutchinson&amp;rsquo;s Estimator&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;( 해당 부분에 대해서 좀 자세하게 서술했으나 , 네트워크 문제로 다 날라가서.. 일단은 이정도 서술 하도록 하겠습니다. )&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;계산하기 너무 어려우니까 적당한 u 를 뽑아서 몇개 샘플링의 평균으로 계산을 대체하자는게 해당 아이디어 입니다.&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;어떤 행렬 A 에 대해서 평균이 0이고 분산인 I 인 ( istropic ) 한 랜덤백터 u 가 있으면 수식이 다음과 같이 변하고&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Tr(A) = E(uT A u )&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;span&gt;sϕ(x) 쪽 역시 raom projection 으로 표현됩니다.&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;761&quot; data-origin-height=&quot;80&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MVIVO/dJMcacWmoJg/a5a8Q6rKbgj40xsba5pCxk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MVIVO/dJMcacWmoJg/a5a8Q6rKbgj40xsba5pCxk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MVIVO/dJMcacWmoJg/a5a8Q6rKbgj40xsba5pCxk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMVIVO%2FdJMcacWmoJg%2Fa5a8Q6rKbgj40xsba5pCxk%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;704&quot; height=&quot;74&quot; data-origin-width=&quot;761&quot; data-origin-height=&quot;80&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;647&quot; data-origin-height=&quot;70&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/l4ZEi/dJMcabDa9w4/MvBsZzkuc4kUHs8PKkLiQ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/l4ZEi/dJMcabDa9w4/MvBsZzkuc4kUHs8PKkLiQ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/l4ZEi/dJMcabDa9w4/MvBsZzkuc4kUHs8PKkLiQ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fl4ZEi%2FdJMcabDa9w4%2FMvBsZzkuc4kUHs8PKkLiQ1%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;647&quot; height=&quot;70&quot; data-origin-width=&quot;647&quot; data-origin-height=&quot;70&quot;/&gt;&lt;/span&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;&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;1. D 차원 공간에서 전체 trace(발산) 을 알고싶다 ( 모든 축 방향 변화의 합 )&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 하지만 계산이 너무 어렵다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. (ssm) 매번 랜덤 방향 u 를 뽑아서 X 에서 U 방향으로 slice 를 잘라 해당 slice 위에서 곡률/trace 를 측정&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. 여러 u 를 평균냄.&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;br /&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;915&quot; data-origin-height=&quot;1298&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yH4yB/dJMcachMz43/24K7PThfkeKd7JkRkU11H1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yH4yB/dJMcachMz43/24K7PThfkeKd7JkRkU11H1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yH4yB/dJMcachMz43/24K7PThfkeKd7JkRkU11H1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyH4yB%2FdJMcachMz43%2F24K7PThfkeKd7JkRkU11H1%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;543&quot; height=&quot;770&quot; data-origin-width=&quot;915&quot; data-origin-height=&quot;1298&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;직접한번 2차원두고 작성해보니 이해가 더 잘되더라구요.&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;jvp/vjp 로 행렬없이&amp;nbsp; uT J u 를 구할 수 있어서 계산이 빨라진다고 합니다.&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;b&gt; From Sliced to Denoising Score Matching&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;4&quot; data-ke-size=&quot;size16&quot;&gt;Sliced Score Matching은 복잡한 수학 계산(Jacobian)을 피하려고 만든 기법입니다. 하지만 다음과 같은 치명적인 단점이 있습니다.&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 data-index-in-node=&quot;0&quot; data-path-to-node=&quot;5,0,0&quot;&gt;매니폴드(Manifold) 가설의 함정:&lt;/b&gt; 고해상도 이미지 데이터는 사실 광활한 공간 전체에 퍼져 있지 않고, 아주 얇고 구부러진 특정 영역(저차원 매니폴드)에만 밀집해 있습니다. 데이터가 없는 구역에서는 &quot;어느 방향이 데이터가 있는 방향인지&quot; 가르쳐주는 수치(&lt;span data-index-in-node=&quot;149&quot; data-math=&quot;\nabla_x \log p_{data}(x)&quot;&gt;log p_{data}(x)&lt;/span&gt;) 자체가 정의되지 않거나 매우 불안정합니다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;5,1,0&quot;&gt;좁은 시야:&lt;/b&gt; 실제 데이터가 있는 '점' 위에서만 학습이 이루어지다 보니, 그 점을 조금만 벗어나도 모델이 길을 잃어버립니다. (주변 동네에 대한 정보가 부족함)&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;5,2,0&quot;&gt;계산 효율과 노이즈:&lt;/b&gt; 매번 계산할 때마다 방향을 무작위로 정해 확인해야 하므로(Probe-induced variance), 결과가 들쑥날쑥하고 반복적인 계산 비용이 큽니다.&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 이런문제점을 보안하고자 DSM(Denoising Score Matching) 라는 방식을 제안합니다.&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;DSM 의 아이디어&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원본 데이터 x 를 그대로 쓰지 않고 노이즈를 섞은 데이터를 가지고 score 를 학습한다.&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;- 명확한 정답 제거 : 저희가 noise 를 투입한 것이기 때문에 노이즈의 양을 알고 있습니다. 따라서 노이즈 섞인 데이터를 원래 데이터 로 되돌리면 어느 방향으로 가야하는지를 학습 목표로 세울 수 있습니다.&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;h4 data-ke-size=&quot;size20&quot;&gt;3.3.2 Training&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 챕터에서는 DSM 이 intractable 한 p_data(x) 없이도 score 를 학습할 수 있는가에 대해서 정리한 챕터입니다.&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;먼저 원래 목표를 revisit 해보겠습니다. 원래 계산하고 싶던 수식은 다음과 같았죠?&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;703&quot; data-origin-height=&quot;75&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b3TQ9a/dJMcacoxiCU/zBUgK5KksK08FTtBpxW3V1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b3TQ9a/dJMcacoxiCU/zBUgK5KksK08FTtBpxW3V1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b3TQ9a/dJMcacoxiCU/zBUgK5KksK08FTtBpxW3V1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb3TQ9a%2FdJMcacoxiCU%2FzBUgK5KksK08FTtBpxW3V1%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;64&quot; data-origin-width=&quot;703&quot; data-origin-height=&quot;75&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 여기서 p_data(x) 를 알 수 없었고 , 저희는 샘플 x 만 있고 당연하게도 p_data 밀도 함수 자체가 없기 때문에&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;trace 형태의 score matching 으로 바꿨었고 ( SSM 은 ) 거기서 trace 를 hutchinson 으로 처리했습니다.&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;b&gt; Vincent (2011)&amp;rsquo;s Solution by Conditioning&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2011 년에 나온 아이디어라니 참 신기합니다&amp;nbsp; (얼마나 앞서간거야.. )&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;- 노이즈를 섞으면 score 가 계산 가능한 조건부가 생긴다. ( 위에서 이야기 했던것과 유사합니다. )&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;1. &lt;b&gt;데이터에 노이즈를 섞습니다&amp;nbsp;&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;367&quot; data-origin-height=&quot;61&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cUsaKn/dJMcafS6QNL/znAkx0khgIKl3J0OdIrX8K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cUsaKn/dJMcafS6QNL/znAkx0khgIKl3J0OdIrX8K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cUsaKn/dJMcafS6QNL/znAkx0khgIKl3J0OdIrX8K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcUsaKn%2FdJMcafS6QNL%2FznAkx0khgIKl3J0OdIrX8K%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;319&quot; height=&quot;53&quot; data-origin-width=&quot;367&quot; data-origin-height=&quot;61&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 오른쪽 p() 는 직접 설계한 ( known 분포 ) 입니다. ( 가지고 있는 데이터 x 에 직접 noise 를 추가했기 떄문 )&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 하면 노이즈가 섞인 샘플 의 marginal 분포가 생깁니다.&amp;nbsp;&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;512&quot; data-origin-height=&quot;75&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bi2gnM/dJMcagkafoo/M4SlgqkUDyx1muPR2cPnjK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bi2gnM/dJMcagkafoo/M4SlgqkUDyx1muPR2cPnjK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bi2gnM/dJMcagkafoo/M4SlgqkUDyx1muPR2cPnjK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbi2gnM%2FdJMcagkafoo%2FM4SlgqkUDyx1muPR2cPnjK%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;341&quot; height=&quot;50&quot; data-origin-width=&quot;512&quot; data-origin-height=&quot;75&quot;/&gt;&lt;/span&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;이식은 p_data 를 gaussian 으로 convolution 한 smooting 분포라고 생각하면 됩니다.&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;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;위 수식은 그냥 노이즈 섞은 결과의 전체 분포를 쓰는 수식입니다.&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;x~p_data : 원본 데이터에서 하나 뽑음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;x~ &amp;sim; p&amp;sigma;(x~∣x) : 그 x 에 노이즈를 섞어서 x~ 를 만듦 ( 노이즈 이미지 )&amp;nbsp;&lt;/span&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;span&gt;결국 노이즈 이미지 x~ 는 어떤 x 에서 왔는지 모르기 때문에 ( 학습할떄는 pair 로 알고 있지만 , x~ 만 보고 원본이 뭐였는지는 알 수 없음 )&amp;nbsp;&lt;/span&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;span&gt;따라서 x~ 의 분포 p(x~) 는 가능한 원본 x 에 대해&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;x 가 나올확률 x ( 그 x 에서 x~ 로 노이즈가 만들어질 확률) 를 다합친 값입니다. ( 이게 해당 위의 적분 식 )&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. &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;p data-ke-size=&quot;size16&quot;&gt;이제 모델이 clean x 가 아니라 noisy x~ 에서 score 를 맞추도록 합니다.&amp;nbsp;&amp;nbsp;&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;1057&quot; data-origin-height=&quot;87&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2tuxH/dJMcah4sudX/kVwyK4uTwkyDZ1hPQ9QqP0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2tuxH/dJMcah4sudX/kVwyK4uTwkyDZ1hPQ9QqP0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2tuxH/dJMcah4sudX/kVwyK4uTwkyDZ1hPQ9QqP0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2tuxH%2FdJMcah4sudX%2FkVwyK4uTwkyDZ1hPQ9QqP0%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;703&quot; height=&quot;58&quot; data-origin-width=&quot;1057&quot; data-origin-height=&quot;87&quot;/&gt;&lt;/span&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;&amp;nabla;log⁡p&amp;sigma;(x~) 는 marignal score 라서 일반적으로 intractable 한 문제를 conditioning trick 을 사용해서 이를 해결합니다.&amp;nbsp;&lt;/span&gt;&lt;/span&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;좀더 쉽게 이야기하면 결국 p(x~) 수식 역시 적분으로 정의된 분포라서 lot p(x~) 와 해당 기울기도 보통 계산이 어려운 단점이 있습니다.&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; Conditioning Trick&amp;nbsp;&lt;/b&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;위의 3.3.1 수식에서는 x 를 같이 알면 계산이 쉬워지는 것을 이용합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;( 이전 diffusion 에서도 마찬가지로 원본 x 를 알고있다고 가정한 수식으로 인해서 엄청 계산이 편리해졌습니다. 여기서도 마찬가지 트릭을 이용해서 해결합니다. )&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;DSM loss ( Denoising Score Matching loss ) :&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;1219&quot; data-origin-height=&quot;204&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c7xyyN/dJMcabwpKcJ/VejlVuzldFt5Zwf6ft4JIK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c7xyyN/dJMcabwpKcJ/VejlVuzldFt5Zwf6ft4JIK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c7xyyN/dJMcabwpKcJ/VejlVuzldFt5Zwf6ft4JIK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc7xyyN%2FdJMcabwpKcJ%2FVejlVuzldFt5Zwf6ft4JIK%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;662&quot; height=&quot;111&quot; data-origin-width=&quot;1219&quot; data-origin-height=&quot;204&quot;/&gt;&lt;/span&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;여기서는 조건부 수식으로 바뀌는데&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 학습할때 원본 데이터 x 를 샘플로 가지고 있고&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 노이즈를 우리가 직접 섞어서 x~ 를 만들었고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 그러면 p(x~|x) 는 직접 정한 노이즈 모델이라서 수식이 매우 명확하기 때문에 lot p(x~|x ) 역시 closed form 으로 계산이 가능해집니다.&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;&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;1) MSE regression 의 최적해 = 조건부 기대값.&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;351&quot; data-origin-height=&quot;64&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/3dkBj/dJMcacPD9Pr/fHogp5ZJxbGry1uqDqoVHk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/3dkBj/dJMcacPD9Pr/fHogp5ZJxbGry1uqDqoVHk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/3dkBj/dJMcacPD9Pr/fHogp5ZJxbGry1uqDqoVHk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F3dkBj%2FdJMcacPD9Pr%2FfHogp5ZJxbGry1uqDqoVHk%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;247&quot; height=&quot;45&quot; data-origin-width=&quot;351&quot; data-origin-height=&quot;64&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위처럼 두면 ( loss 수식에서 뒷부분 )&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;그러면 DSM 이&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;343&quot; data-origin-height=&quot;73&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qpHCg/dJMcaih0Fgc/AulkQFM0NYTUAKCqmYAD5K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qpHCg/dJMcaih0Fgc/AulkQFM0NYTUAKCqmYAD5K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qpHCg/dJMcaih0Fgc/AulkQFM0NYTUAKCqmYAD5K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqpHCg%2FdJMcaih0Fgc%2FAulkQFM0NYTUAKCqmYAD5K%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;268&quot; height=&quot;57&quot; data-origin-width=&quot;343&quot; data-origin-height=&quot;73&quot;/&gt;&lt;/span&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;우리는 X~ 는 고정이고 ( 노이즈가 추가된 X 가 입력값이니까 )&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;T(x,x~) 가 랜덤이므로&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;( DSM 은 사실상 X~ 를 입력으로 받았을때 X 에 의해 바뀌는 조건부 SCORE 의 평균으로 제일 잘 맞추는 함수를 찾는 문제로 보면 된다. )&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;( 이해가 잘 안갈 수 있지만 , 입력 x~ 는 같을 수 있어도 ( 노이즈이니까 ) 원본 x 에 따라서 타겟이 달라지게 된다. )&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;( 완전 noise -&amp;gt; 강아지 or 고양이 일 수 있기 떄문.&amp;nbsp; - 이건 x (원본이미지) 에 전적으로 달려있다. )&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;( MSE 에서는 결국 최적의 해는 조건부 기대값이므로 ( 그래야 LOSS 가 제일 작다 ) 아래와 같은 수식 전개가 되는 것이다. )&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;MSE regression 에서 최적 예측값은 조건부 기대값이므로 , 따라서 최적해는 다음과 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;441&quot; data-origin-height=&quot;64&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c4N02r/dJMcab4fR6P/VLRNDJGQeSMJV52iS1Ln7k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c4N02r/dJMcab4fR6P/VLRNDJGQeSMJV52iS1Ln7k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c4N02r/dJMcab4fR6P/VLRNDJGQeSMJV52iS1Ln7k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc4N02r%2FdJMcab4fR6P%2FVLRNDJGQeSMJV52iS1Ln7k%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;358&quot; height=&quot;52&quot; data-origin-width=&quot;441&quot; data-origin-height=&quot;64&quot;/&gt;&lt;/span&gt;&lt;/figure&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;479&quot; data-origin-height=&quot;66&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/QH2AR/dJMcagLhS1E/sLcc0Nx0xRVaIQTjPkYYIK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/QH2AR/dJMcagLhS1E/sLcc0Nx0xRVaIQTjPkYYIK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/QH2AR/dJMcagLhS1E/sLcc0Nx0xRVaIQTjPkYYIK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQH2AR%2FdJMcagLhS1E%2FsLcc0Nx0xRVaIQTjPkYYIK%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;399&quot; height=&quot;55&quot; data-origin-width=&quot;479&quot; data-origin-height=&quot;66&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DSM 을 최소화하면 결과적으로&amp;nbsp;&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;330&quot; data-origin-height=&quot;57&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/chzqCC/dJMcabXuCAO/6Nv6kFwPsW7K4YR9vk42ak/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/chzqCC/dJMcabXuCAO/6Nv6kFwPsW7K4YR9vk42ak/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/chzqCC/dJMcabXuCAO/6Nv6kFwPsW7K4YR9vk42ak/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FchzqCC%2FdJMcabXuCAO%2F6Nv6kFwPsW7K4YR9vk42ak%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;208&quot; height=&quot;36&quot; data-origin-width=&quot;330&quot; data-origin-height=&quot;57&quot;/&gt;&lt;/span&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;이게 책에서 이야기하는 (3.3.2) 의 optimal minizier 가 (3.3.1)의 optimal minimzer 와 같다는 말이다.&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;결론 : DSM 의 최적해는 noisy marginal score 이다.&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;2) 가우시안 노이즈면 closed form 이라 tractable 이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아까 위에서 cloased form 이라 tractable 하다고 하고 넘어 갔는데 조금 더 자세히 살펴보겠습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;( 책에서 &lt;u&gt;&lt;b&gt;special case : Additive Gaussian Noise&lt;/b&gt;&lt;/u&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;( 노이즈 주입 정의 )&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;716&quot; data-start=&quot;696&quot;&gt;&lt;span&gt;&lt;span&gt;x&amp;sim;pdata&lt;/span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;751&quot; data-start=&quot;717&quot;&gt;&lt;span&gt;&lt;span&gt;ϵ&amp;sim;N(0,I)&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;787&quot; data-start=&quot;752&quot;&gt;&lt;span&gt;&lt;span&gt;x~=x+&amp;sigma;ϵ&lt;/span&gt;&lt;/span&gt;&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;다음과 같이 정의되고 이러면 조건부 분포가 다음과 같이 된다.&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;392&quot; data-origin-height=&quot;71&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ebaD19/dJMcad11OCz/H6CrzpG7iJ6gldo4wYk1U1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ebaD19/dJMcad11OCz/H6CrzpG7iJ6gldo4wYk1U1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ebaD19/dJMcad11OCz/H6CrzpG7iJ6gldo4wYk1U1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FebaD19%2FdJMcad11OCz%2FH6CrzpG7iJ6gldo4wYk1U1%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;282&quot; height=&quot;51&quot; data-origin-width=&quot;392&quot; data-origin-height=&quot;71&quot;/&gt;&lt;/span&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;( x 를 중심으로 분산 &amp;sigma;^2 짜리 gaussian 뿌려서 x~ 만듬 )&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그림으로 보면 아래와 같을것이구요.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1246&quot; data-origin-height=&quot;586&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mWpAD/dJMcagEwLt5/qqMz4HZHGqcO3vNaWWsu61/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mWpAD/dJMcagEwLt5/qqMz4HZHGqcO3vNaWWsu61/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mWpAD/dJMcagEwLt5/qqMz4HZHGqcO3vNaWWsu61/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmWpAD%2FdJMcagEwLt5%2FqqMz4HZHGqcO3vNaWWsu61%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;679&quot; height=&quot;319&quot; data-origin-width=&quot;1246&quot; data-origin-height=&quot;586&quot;/&gt;&lt;/span&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;왼쪽 log p_data (x) : 직접 계산이 불가능하고&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오른쪽 score log p(x~|x)&amp;nbsp; : 계산이 가능해집니다.&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;그래서 조건부 score 가 다음과 같이 나오게 됩니다.&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;395&quot; data-origin-height=&quot;110&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c428i0/dJMcaca3hHY/LcILVvpAKdUhsbWL5bS6N0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c428i0/dJMcaca3hHY/LcILVvpAKdUhsbWL5bS6N0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c428i0/dJMcaca3hHY/LcILVvpAKdUhsbWL5bS6N0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc428i0%2FdJMcaca3hHY%2FLcILVvpAKdUhsbWL5bS6N0%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;305&quot; height=&quot;85&quot; data-origin-width=&quot;395&quot; data-origin-height=&quot;110&quot;/&gt;&lt;/span&gt;&lt;/figure&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;통계학이 가물가물하네요&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;Gaussian PDF&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://gaussian37.github.io/math-pb-about_gaussian/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://gaussian37.github.io/math-pb-about_gaussian/&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;가우시안 pdf 밀도는&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;794&quot; data-origin-height=&quot;103&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vBZ48/dJMcagdsbWC/URxfV71CaHbdCU9QXT832K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vBZ48/dJMcagdsbWC/URxfV71CaHbdCU9QXT832K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vBZ48/dJMcagdsbWC/URxfV71CaHbdCU9QXT832K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvBZ48%2FdJMcagdsbWC%2FURxfV71CaHbdCU9QXT832K%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;694&quot; height=&quot;90&quot; data-origin-width=&quot;794&quot; data-origin-height=&quot;103&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;아래와 다음과 같고 이걸 우리 case 에 대입해보면 ..&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;&amp;Sigma;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&amp;sigma;^&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;2 &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;I 이므로 ( 아래와 같은 수식이였으니까 )&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;353&quot; data-origin-height=&quot;64&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bGNQU1/dJMcahi8Mxd/6Whqb9mgK9BVTloKeLKDC1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bGNQU1/dJMcahi8Mxd/6Whqb9mgK9BVTloKeLKDC1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bGNQU1/dJMcahi8Mxd/6Whqb9mgK9BVTloKeLKDC1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbGNQU1%2FdJMcahi8Mxd%2F6Whqb9mgK9BVTloKeLKDC1%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;314&quot; height=&quot;57&quot; data-origin-width=&quot;353&quot; data-origin-height=&quot;64&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;이걸 대입해서 정리하면.. ( 여차여차 정리하시면 )&amp;nbsp;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;577&quot; data-origin-height=&quot;92&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kKzZX/dJMcabpGKah/I3GbQ23Z76LEWIkIgt6t0K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kKzZX/dJMcabpGKah/I3GbQ23Z76LEWIkIgt6t0K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kKzZX/dJMcabpGKah/I3GbQ23Z76LEWIkIgt6t0K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkKzZX%2FdJMcabpGKah%2FI3GbQ23Z76LEWIkIgt6t0K%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;577&quot; height=&quot;92&quot; data-origin-width=&quot;577&quot; data-origin-height=&quot;92&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;다음과 같이 됩니다.&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;여기서 log 씌워주고 미분하면 담과 같이 정리됩니다.&amp;nbsp;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;603&quot; data-origin-height=&quot;238&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cVF0ee/dJMcahpSRIB/ZVAbTnVksWRAP7IMY26fg1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cVF0ee/dJMcahpSRIB/ZVAbTnVksWRAP7IMY26fg1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cVF0ee/dJMcahpSRIB/ZVAbTnVksWRAP7IMY26fg1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcVF0ee%2FdJMcahpSRIB%2FZVAbTnVksWRAP7IMY26fg1%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;474&quot; height=&quot;187&quot; data-origin-width=&quot;603&quot; data-origin-height=&quot;238&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;직관적으로 x~ 가 x 에서 멀어질수록 원본 x 쪽으로 끌어당기는 힘이 세지고&amp;nbsp; , 분산이 크면 그 힘이 약해지는 형태를 띄게 됩니다.&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;( 그래서 DMS loss 가 어떻게 단순해지는지 ? )&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서 정의한 수식을 DSM 에 그대로 대입하면 다음과 같이 됩니다.&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;1214&quot; data-origin-height=&quot;302&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/XmF2b/dJMcagEwLTR/6lVTfL0DHtsaBwkziFUchk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/XmF2b/dJMcagEwLTR/6lVTfL0DHtsaBwkziFUchk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/XmF2b/dJMcagEwLTR/6lVTfL0DHtsaBwkziFUchk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXmF2b%2FdJMcagEwLTR%2F6lVTfL0DHtsaBwkziFUchk%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;699&quot; height=&quot;174&quot; data-origin-width=&quot;1214&quot; data-origin-height=&quot;302&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫번째줄 s( ) 에서&amp;nbsp;&lt;span&gt;&lt;span&gt;x~=x+&amp;sigma;ϵ 치환하면 아래 수식이 되게 됩니다.&amp;nbsp;&lt;/span&gt;&lt;/span&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;해당 수식이 왜 denosing 인지 / &amp;sigma; 크거나 작으면 무슨일이 일어나는지 , 그래서 종합적으로 왜 생성이 가능한지 더 서술합니다.&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;1) &amp;sigma;가 작으면 &lt;span&gt;&lt;span&gt;p&amp;sigma;&lt;/span&gt;&lt;/span&gt;와 &lt;span&gt;&lt;span&gt;pdata&lt;/span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;의 high-density region &amp;amp; score가 거의 같다&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;418&quot; data-origin-height=&quot;64&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yhZ9m/dJMcaa5mkbY/qTIYWU2DD1xGZiqm20ZfR1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yhZ9m/dJMcaa5mkbY/qTIYWU2DD1xGZiqm20ZfR1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yhZ9m/dJMcaa5mkbY/qTIYWU2DD1xGZiqm20ZfR1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyhZ9m%2FdJMcaa5mkbY%2FqTIYWU2DD1xGZiqm20ZfR1%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;346&quot; height=&quot;53&quot; data-origin-width=&quot;418&quot; data-origin-height=&quot;64&quot;/&gt;&lt;/span&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;근데 여기서 &amp;sigma; 가 작으면 -&amp;gt; 블러가 거의 없고 -&amp;gt; 분포 모양도 이전 스텝과 거의 같겠죠 ?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 확률이 큰 영역도 거의 그대로 일 것이고 , 따라서 score 도 거의 비슷할 것 입니다. 따라서..&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;535&quot; data-origin-height=&quot;66&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bxTAJA/dJMcabDcSc2/XVvL76WzKMoeKXbG4u1UA1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bxTAJA/dJMcabDcSc2/XVvL76WzKMoeKXbG4u1UA1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bxTAJA/dJMcabDcSc2/XVvL76WzKMoeKXbG4u1UA1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbxTAJA%2FdJMcabDcSc2%2FXVvL76WzKMoeKXbG4u1UA1%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;454&quot; height=&quot;56&quot; data-origin-width=&quot;535&quot; data-origin-height=&quot;66&quot;/&gt;&lt;/span&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;&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;2) noisy score 방향으로 한 스텝 가면 clean 분포의 고확률 영역으로 간다&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;327&quot; data-origin-height=&quot;59&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bvZgb4/dJMcaibgGH8/KHsa6sy9XB8iy9pWPoANuK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bvZgb4/dJMcaibgGH8/KHsa6sy9XB8iy9pWPoANuK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bvZgb4/dJMcaibgGH8/KHsa6sy9XB8iy9pWPoANuK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbvZgb4%2FdJMcaibgGH8%2FKHsa6sy9XB8iy9pWPoANuK%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;227&quot; height=&quot;41&quot; data-origin-width=&quot;327&quot; data-origin-height=&quot;59&quot;/&gt;&lt;/span&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;score = log 확률의 증가 방향&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 score 방향으로 조금 움직이면 p(x~) 가 커지는 쪽으로 가게 됩니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 다시 아까 위에서 &amp;sigma; 가 작으면 p&amp;sigma; 아 p_data 가 거의 유사하다고 했으니까 --&amp;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;3) 그래서 이걸 왜 denoising 이라고 부르나 ?&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;아까 3.3.4 에서 가우시안 조건부 score 수식이 다음과 같았으므로.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;341&quot; data-origin-height=&quot;91&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lR6t0/dJMcahi8NG6/Sst4lWI5sPEEflAMCY2Hd1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lR6t0/dJMcahi8NG6/Sst4lWI5sPEEflAMCY2Hd1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lR6t0/dJMcahi8NG6/Sst4lWI5sPEEflAMCY2Hd1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlR6t0%2FdJMcahi8NG6%2FSst4lWI5sPEEflAMCY2Hd1%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;221&quot; height=&quot;59&quot; data-origin-width=&quot;341&quot; data-origin-height=&quot;91&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 수식은 x~ 를 x 로 되돌리는 방향을 의미하므로 !&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Tweeie 공식을 이용해서 denoising 과 score 를 직접 연결하는데&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;--&amp;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;+) &amp;sigma;가 크면 왜 over-smooth(평균으로 수축)하나?&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;sigma;가 크면 p&amp;sigma;가 엄청 블러한 분포일텐데&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 이러면 모든 디테일이 섞여서 사라지고 분포가 큰 구름 하나처러 ㅁ되어서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; score 마찬가지로 디테일한 모드가 아니라 그냥 전체 질량이 큰 대충 평균 중심으로 끌어당기는 벡터가 되어서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;denoising 을 하더라도&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 디테일이 살아나는게 아니라 coarse 한 denoising 이 되어서 over smooth 가 발생한다.&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;&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;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1214&quot; data-origin-height=&quot;446&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dhUDH9/dJMcabJZnPX/zQxgPfJvrYpKxQGtWSgz7K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dhUDH9/dJMcabJZnPX/zQxgPfJvrYpKxQGtWSgz7K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dhUDH9/dJMcabJZnPX/zQxgPfJvrYpKxQGtWSgz7K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdhUDH9%2FdJMcabJZnPX%2FzQxgPfJvrYpKxQGtWSgz7K%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;770&quot; height=&quot;283&quot; data-origin-width=&quot;1214&quot; data-origin-height=&quot;446&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 원래 L_SM ( 노이즈가 들어간 분포의 정답 score 를 맞추는 MSE ) 는 정답 socre log p(x~) 떄문에 직접 계산이 어려워서&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- L_DSM ( denosing score matching ) 으로 바꾸면 정답 score 를 조건부의 닫힌형으로 바꿔서 학습할 수 있고 , 놀랍게 두손실은&amp;nbsp; ϕ 에 대해 동일한 최적해를 갖게 됩니다.&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;( 4장에서 더 자세히 다루므로 이정도 다루고 가겠습니다 . )&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1202&quot; data-origin-height=&quot;353&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0JAmW/dJMcaaqK8DQ/AsuYSfomzd8BKoFKk2oQKK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0JAmW/dJMcaaqK8DQ/AsuYSfomzd8BKoFKk2oQKK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0JAmW/dJMcaaqK8DQ/AsuYSfomzd8BKoFKk2oQKK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0JAmW%2FdJMcaaqK8DQ%2FAsuYSfomzd8BKoFKk2oQKK%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;659&quot; height=&quot;194&quot; data-origin-width=&quot;1202&quot; data-origin-height=&quot;353&quot;/&gt;&lt;/span&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;- 원래 목표가 marginal 이라서 계산이 어려운걸 , 원본 데이터 x 에 조건 (condition) 을 걸어 conditional 로 바꿔서 Monte Carlo 로 추정을 할 수 있게 합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 그리고 그 조건부 목표를 평균내면 다시 원래 marginal 목표와 연결되게 됩니다.&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;이게 DDPM 과 Flow matching 에서도 똑같은 패턴이 발생합니다. 간략하게 작성해보면&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;1) DSM 에서 condition&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;376&quot; data-origin-height=&quot;82&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/IUA4O/dJMcacB6XV2/VTcCEFLywrR20H4xSzBek1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/IUA4O/dJMcacB6XV2/VTcCEFLywrR20H4xSzBek1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/IUA4O/dJMcacB6XV2/VTcCEFLywrR20H4xSzBek1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIUA4O%2FdJMcacB6XV2%2FVTcCEFLywrR20H4xSzBek1%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;316&quot; height=&quot;69&quot; data-origin-width=&quot;376&quot; data-origin-height=&quot;82&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정답이 closed form 이라서 샘플 (x , x~ ) 만 있으면 MSE를 몬테 카를로로 바로 학습 가능하게 되고&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;2) ddpm 에서 conditioning&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DDPM 에서 보통 ELBO 를 최대화 하는 형태인데 , 이걸 직접 다루려면 어렵기 떄문에&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;forward : ( 여기는 직접 x 에서 샘플링 하기떄문에 쉽고 )&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;backward : 여기서도 xo 를 conditioning 으로 쓰면 closed form 으로 계산가능합니다.&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;( 이부분은 2장 참고 하시면 됩니다.)&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;읽으면서도 뭔가 직관적으로 이런 부분이 score 랑 비슷하겠구나 .. 싶었는데 책에서 정리해주네요 . 뭔가 뿌듯합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아무튼 이런식으로 tractable 하게 만들어줍니다.&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;3) flow matching&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요즘 FLUX 나 QWEN 같은 프론티어 모델들도 보통 flow 를 많이 쓰는데요 . 역시 마찬가지로 비슷합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이부분은 flow matching 때 다시 보는걸로 하겠습니다.&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;h3 data-ke-size=&quot;size23&quot;&gt;3.3.3 Sampling&lt;/h3&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;학습된 스코어 모델이 있따면 , 이걸 이용해서 실제 데이터와 유사한 샘플을 만들 수 있는데 , 이때 사용하는 방법이 langevin dynamics 입니다.&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;- 무작위 초기값 Xo 에서 시작해서 , score 를 따라서 조금 씩 이동하면서 한 스탭마다 noise 를 추가해서&amp;nbsp; coverage 개선을 할 뿐만 아니라 공간 전체에 데이터를 퍼지게 하는 효과를 줄 수 있습니다. ( 실제 데이터는 전체 공간에 비해서 매우 좁은 영역에만 몰려 있기 떄문. )&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;812&quot; data-origin-height=&quot;101&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/w4KIx/dJMcabi1mjA/G0In7WAYy6vBc4kjMC5Rqk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/w4KIx/dJMcabi1mjA/G0In7WAYy6vBc4kjMC5Rqk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/w4KIx/dJMcabi1mjA/G0In7WAYy6vBc4kjMC5Rqk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fw4KIx%2FdJMcabi1mjA%2FG0In7WAYy6vBc4kjMC5Rqk%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;659&quot; height=&quot;82&quot; data-origin-width=&quot;812&quot; data-origin-height=&quot;101&quot;/&gt;&lt;/span&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;수식은 다음과 같은데&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;S() : 드리프트 항 ( 확률이 높은 곳으로 끌어가는 항 )&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;노이즈 항&lt;/b&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;b&gt; Advantages of Noise Injection.&amp;nbsp;&lt;/b&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;1. Well-defined gradients&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제 데이터 분포 p_data 는 매우 얇은 manifold 근처에 몰려있다. ( 전체 공간 D 에 퍼져있지 않고 대부분 아주 얇은 층 위에 존재한다 . )&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 경우 log p_data(x) 를 전체 D 차원에서 정의하기가 어렵고 학습이 잘 되지 않는다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 gaussian convolution 을 한 &lt;span&gt;p&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&amp;sigma; ( = p_data *&amp;nbsp; &lt;span&gt;N&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;sigma;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;I&lt;/span&gt;&lt;span&gt;) ) 는 훨씬 더 매끈하고 score 를 잘 정의할 수 있다.&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&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;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;-&amp;gt; 데이터 분포에 두께를 줘서 , score 공간 전체에서 보다 더 안정적으로 정의할 수 있게 해준다.&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&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;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;2. Improved converage&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&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;데이터 분포는 여러 모드가 있고 ( 모드 = 클러스터 ? )&amp;nbsp; , 그 사이가 거의 밀도가 0인 경우가 많다.&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;근데 문제가 있는데 해당 사이 밀도가 0 인 경우에 ( score 가 거의 없거나 불안정 ) 하기 떄문에 샘플이 한 모드에 갇혀서 다른 모드로 못넘어간다.&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대략 시각적으로 보면 이렇다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;559&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cxM2X0/dJMcaiPUoMc/gzdqksy31o27f9facc1Cc1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cxM2X0/dJMcaiPUoMc/gzdqksy31o27f9facc1Cc1/img.png&quot; data-alt=&quot;한번 시험삼아 시켜봤습니다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cxM2X0/dJMcaiPUoMc/gzdqksy31o27f9facc1Cc1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcxM2X0%2FdJMcaiPUoMc%2Fgzdqksy31o27f9facc1Cc1%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;642&quot; height=&quot;350&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;559&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;한번 시험삼아 시켜봤습니다.&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;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3.3.4 Why DSM is Denoising: Tweedie&amp;rsquo;s Formula&amp;nbsp;&lt;/h4&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;p data-ke-size=&quot;size16&quot;&gt;원인 : 이미지 x ( 수많은 고양이 사진 중 하나 )&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결과 : 노이즈가 섞여 나온 x~&amp;nbsp; ( x 에 가우시안 노이즈가 더해진 결과물 )&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;그런데 x~ 는 정해진 하나의 x 에서 나오는게 아니라 p_data(X) 전체에서 x 가 뽑히고, 거기에 노이즈가 더해져서 만든 랜덤 결과이다. 따라서 우리는 x~ 를 보고 원본 x 를 찾아야 하는게 원래 목표였는데 , x~ 만 보고 x 를 하나로 정해지지 않으므로&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;( 결국 이를 잘 정의해야 loss 를 정의할 수 있기 때문에 .. )&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;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;글을 한번에 읽고 작성하는게 아니다 보니 이쯤오면 기억이 안나는 부분이 있어서 리마인드를 한번 하고 갈까 한다.&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;1. 우리가 아는건 한가지 정보이다.&amp;nbsp;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;383&quot; data-origin-height=&quot;56&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yByGh/dJMcacWus15/kP3SQkJv4wJQwmUnmlfp5k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yByGh/dJMcacWus15/kP3SQkJv4wJQwmUnmlfp5k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yByGh/dJMcacWus15/kP3SQkJv4wJQwmUnmlfp5k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyByGh%2FdJMcacWus15%2FkP3SQkJv4wJQwmUnmlfp5k%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;383&quot; height=&quot;56&quot; data-origin-width=&quot;383&quot; data-origin-height=&quot;56&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;276&quot; data-origin-height=&quot;61&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ba7WiN/dJMcafr9zYL/xX18Hi7FhBoZmKtHQziKk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ba7WiN/dJMcafr9zYL/xX18Hi7FhBoZmKtHQziKk0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ba7WiN/dJMcafr9zYL/xX18Hi7FhBoZmKtHQziKk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fba7WiN%2FdJMcafr9zYL%2FxX18Hi7FhBoZmKtHQziKk0%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;276&quot; height=&quot;61&quot; data-origin-width=&quot;276&quot; data-origin-height=&quot;61&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;꺠끗한 X 에 NOISE 를 추가해서 X~ 를 만들었다는 것.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, X 가 주어지면 X~ 는 평균 ax 인 가우시안에서 나오게 된다는 의미이다.&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;2. 이 가우시안 score&amp;nbsp; ( log 밀도 기울기 ) 를 직접 계산한다.&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;score :&amp;nbsp;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;190&quot; data-origin-height=&quot;66&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ta7IR/dJMcajuxbc3/REIhd2S8nqtruGy7ZB3GsK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ta7IR/dJMcajuxbc3/REIhd2S8nqtruGy7ZB3GsK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ta7IR/dJMcajuxbc3/REIhd2S8nqtruGy7ZB3GsK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fta7IR%2FdJMcajuxbc3%2FREIhd2S8nqtruGy7ZB3GsK%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;190&quot; height=&quot;66&quot; data-origin-width=&quot;190&quot; data-origin-height=&quot;66&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;이걸 이제 계산해보면 ..&amp;nbsp;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;495&quot; data-origin-height=&quot;96&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/LWEq2/dJMcajuxbdu/C4X1GXavdvzfpJFiO5UIn0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/LWEq2/dJMcajuxbdu/C4X1GXavdvzfpJFiO5UIn0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/LWEq2/dJMcajuxbdu/C4X1GXavdvzfpJFiO5UIn0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLWEq2%2FdJMcajuxbdu%2FC4X1GXavdvzfpJFiO5UIn0%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;495&quot; height=&quot;96&quot; data-origin-width=&quot;495&quot; data-origin-height=&quot;96&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;다음과 같다. 여기서 x~ 로 미분하고 적절히 계산하면 .&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;332&quot; data-origin-height=&quot;71&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/crVjFA/dJMcafloIei/VDM68pWW8RxYVbYX0DUE4k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/crVjFA/dJMcafloIei/VDM68pWW8RxYVbYX0DUE4k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/crVjFA/dJMcafloIei/VDM68pWW8RxYVbYX0DUE4k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcrVjFA%2FdJMcafloIei%2FVDM68pWW8RxYVbYX0DUE4k%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;332&quot; height=&quot;71&quot; data-origin-width=&quot;332&quot; data-origin-height=&quot;71&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 되면 항상 x~ 를 ax 쪽으로 끌어당기는 방향이다&amp;nbsp; ( 이게 score )&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자 그래서 여기서 x 를 우리는 모르기 때문에 ( x~ 만 보니까 ) x~ 를 봤을떄 x 가 뭘지에 대한 분포 (posterior ) 는 존재한다.&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;346&quot; data-origin-height=&quot;105&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ODVSC/dJMb99ZOm5e/naDbfsspYzNfpCVI7KnoXK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ODVSC/dJMb99ZOm5e/naDbfsspYzNfpCVI7KnoXK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ODVSC/dJMb99ZOm5e/naDbfsspYzNfpCVI7KnoXK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FODVSC%2FdJMb99ZOm5e%2FnaDbfsspYzNfpCVI7KnoXK%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;237&quot; height=&quot;72&quot; data-origin-width=&quot;346&quot; data-origin-height=&quot;105&quot;/&gt;&lt;/span&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;&amp;nbsp;&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;542&quot; data-origin-height=&quot;117&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/osvjk/dJMcad178sU/SmflBSBByHsyXbLkS2Xwp0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/osvjk/dJMcad178sU/SmflBSBByHsyXbLkS2Xwp0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/osvjk/dJMcad178sU/SmflBSBByHsyXbLkS2Xwp0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fosvjk%2FdJMcad178sU%2FSmflBSBByHsyXbLkS2Xwp0%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;542&quot; height=&quot;117&quot; data-origin-width=&quot;542&quot; data-origin-height=&quot;117&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&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;498&quot; data-origin-height=&quot;73&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/UeEEX/dJMcafTeUu3/0G2sNNtIcDJ88e9mxJsLg0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/UeEEX/dJMcafTeUu3/0G2sNNtIcDJ88e9mxJsLg0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/UeEEX/dJMcafTeUu3/0G2sNNtIcDJ88e9mxJsLg0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUeEEX%2FdJMcafTeUu3%2F0G2sNNtIcDJ88e9mxJsLg0%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;498&quot; height=&quot;73&quot; data-origin-width=&quot;498&quot; data-origin-height=&quot;73&quot;/&gt;&lt;/span&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;&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;u&gt;여기서 가장 핵심적인 부분이 나온다.&amp;nbsp;&lt;/u&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;u&gt;&quot; DSM이 score &lt;span&gt;&lt;span&gt;&amp;nabla;x~log⁡p&amp;sigma;(x~)&lt;/span&gt;&lt;/span&gt;를 배우면, 그걸로 &amp;ldquo;최적 디노이즈(=posterior 평균)&amp;rdquo;를 바로 만들 수 있다. &quot;&amp;nbsp;&lt;/u&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;486&quot; data-origin-height=&quot;61&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/TrGWp/dJMcai3q2qC/E3EU5s8vTkjfd9cImITr60/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/TrGWp/dJMcai3q2qC/E3EU5s8vTkjfd9cImITr60/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/TrGWp/dJMcai3q2qC/E3EU5s8vTkjfd9cImITr60/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTrGWp%2FdJMcai3q2qC%2FE3EU5s8vTkjfd9cImITr60%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;422&quot; height=&quot;53&quot; data-origin-width=&quot;486&quot; data-origin-height=&quot;61&quot;/&gt;&lt;/span&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;수식으로 바꾸면 다음과 같다.&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;관측 x~ 가 에 대한 marginal p(x~) 의 score ( 기울기) 는 x~ 를 만든 원인 x 가 무엇인지에 대해서 posterior 평균낸 조건부 기울기와 같다고 주장한다. ( 실제로 수식적으로도 증명한다. )&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;414&quot; data-origin-height=&quot;85&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cUjsQo/dJMcah4AESY/BBFut2yneou2tatNtgh7JK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cUjsQo/dJMcah4AESY/BBFut2yneou2tatNtgh7JK/img.png&quot; data-alt=&quot;원래 정의&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cUjsQo/dJMcah4AESY/BBFut2yneou2tatNtgh7JK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcUjsQo%2FdJMcah4AESY%2FBBFut2yneou2tatNtgh7JK%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;375&quot; height=&quot;77&quot; data-origin-width=&quot;414&quot; data-origin-height=&quot;85&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;원래 정의&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래에서 p (x~) 정의를 보면 다음과 같은데 , 처음부터 원인 x 를 적분해서 만든 분포이므로 , x~ 기울기를 구할떄에도 내부에 들어있는 p(x~|x ) 의 기울기가 x에 대한 posterior 로 평균되어 나오는게 꽤나 그럴 듯 하다&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #009a87;&quot;&gt;&amp;lt; 이부분 조금 더 설명하기 &amp;gt;&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;1151&quot; data-origin-height=&quot;406&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ebsTbl/dJMcagkia5N/cATI78XK9xEZekZ0Yp6cO0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ebsTbl/dJMcagkia5N/cATI78XK9xEZekZ0Yp6cO0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ebsTbl/dJMcagkia5N/cATI78XK9xEZekZ0Yp6cO0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FebsTbl%2FdJMcagkia5N%2FcATI78XK9xEZekZ0Yp6cO0%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;707&quot; height=&quot;249&quot; data-origin-width=&quot;1151&quot; data-origin-height=&quot;406&quot;/&gt;&lt;/span&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;&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;&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;h2 data-ke-size=&quot;size26&quot;&gt;3.4 Multi-Noise Levels of Denoising Score Matching (NCSN)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.4.1 Motivation&amp;nbsp;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 이번 섹션 (3.4) 에서는 왜 노이즈를 한번만 넣어서 DSM 를 학습하면 샘플링이 어렵고 , 품질의 한계가 생기는지 설명하고 -&amp;gt; 그래서 여러 노이즈 레벨을 동시에 학습하고 , 샘플링떄는 큰 노이즈 -&amp;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;1) 단일 DSM의 구조 및 한계&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DSM 은 이전에서 설명했던 것과 비슷하게&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 데이터 X ~ P_data&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 노이즈 주입&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 네트워크가 noise 추가된 분포의 score 를 맞추도록 학습 한다.&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; &amp;sigma; 만 사용하면 샘플링이 힘들어진다.&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;(A) &amp;sigma; 가 너무 작은 경우&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- P_ &amp;sigma; 와 P_data 가 너무 비슷해진다. ( 이렇게 되면 원래 데이터 분포는 보통 mode 사이에 밀도가 매우 낮은데 이렇게 되면 mode 사이의 영역에서는 사실상 샘플링이 불가능하게 된다. / 이전에 설명했던 단점이 또 나오는 것이다. )&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 따라서 저밀도 구간에서는 gradinet 가 약하거나 틀릴 수 있어서 다른 mode 로 넘어가기 매우 어렵게 된다.&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;span style=&quot;color: #333333; text-align: start;&quot;&gt;(B)&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&amp;sigma; 가 너무큰 경우&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 분포가 너무 smoothing 된다. 이러면 대략적인 구조는 맞출 수 있는데 세부 디테일이 뭉개져 버린다.&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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1146&quot; data-start=&quot;1099&quot;&gt;작은 &lt;span&gt;&lt;span&gt;&amp;sigma;&lt;/span&gt;&lt;/span&gt;: 디테일은 가능하지만 탐색/모드 이동이 어려움&lt;/li&gt;
&lt;li data-end=&quot;1219&quot; data-start=&quot;1147&quot;&gt;큰 &lt;span&gt;&lt;span&gt;&amp;sigma;&lt;/span&gt;&lt;/span&gt;: 탐색은 쉽지만 디테일 회복 불가&lt;br /&gt;&amp;rarr; 하나의 &lt;span&gt;&lt;span&gt;&amp;sigma;&lt;/span&gt;&lt;/span&gt;로는 둘을 동시에 잡기 힘듦&amp;nbsp;&lt;/li&gt;
&lt;li data-end=&quot;1219&quot; data-start=&quot;1147&quot;&gt;따라서 다양한 noise 를 사용하자 !&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;cf .&amp;nbsp;&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;1116&quot; data-origin-height=&quot;696&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/coxv3e/dJMcai3q2Vf/lxkJW3t0N6gOGVVZkR5MKk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/coxv3e/dJMcai3q2Vf/lxkJW3t0N6gOGVVZkR5MKk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/coxv3e/dJMcai3q2Vf/lxkJW3t0N6gOGVVZkR5MKk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcoxv3e%2FdJMcai3q2Vf%2FlxkJW3t0N6gOGVVZkR5MKk%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;639&quot; height=&quot;399&quot; data-origin-width=&quot;1116&quot; data-origin-height=&quot;696&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;941&quot; data-origin-height=&quot;626&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kNOzT/dJMcaiPUpML/AKh5up7cjrclwacQBL4v2k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kNOzT/dJMcaiPUpML/AKh5up7cjrclwacQBL4v2k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kNOzT/dJMcaiPUpML/AKh5up7cjrclwacQBL4v2k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkNOzT%2FdJMcaiPUpML%2FAKh5up7cjrclwacQBL4v2k%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;518&quot; height=&quot;345&quot; data-origin-width=&quot;941&quot; data-origin-height=&quot;626&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;검은 화살표 : 학습된&amp;nbsp; score&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파란 화살표 : 정답 score&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;그래서 그림을 보면&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;노란색 구역 ( high density ) : 여기서는 실제 데이터 p_data 가 밀집되어 있는 구역이라서 , 해당 구간에서는 score 가 더 정확하다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;빨간색 구역 ( low density ) : 데이터가 거의 존재하지 않는 빈 공간이다. 모델이 이 구역의 데이터는 거의 본 적이 없기 때문에 문제가 생기는 구간이다.&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;b&gt;NCSN&amp;nbsp;&lt;/b&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;그래서 Noise 를 여러 단계로 바꿔가면서 , 각 단계에서 지금 이 노이즈 수준에서 데이터가 더 좋은 방향 (score ) 로 알려주는 신경망을 학습하고 , 생성할때는 noise 를 큰단계 -&amp;gt; 작은 단계로 내려오면서 점점 디테일을 복원하는 방식입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;( 다른 논문들이나 생성 모델도 보통 coarse 를 먼저 잡고 그다음에 fine 을 잡는 형식으로 생성하는걸 확인했었습니다 )&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-start=&quot;1099&quot; data-end=&quot;1146&quot;&gt;작은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;sigma;&lt;/span&gt;&lt;/span&gt;: 디테일은 가능하지만 탐색/모드 이동이 어려움&lt;/li&gt;
&lt;li data-start=&quot;1147&quot; data-end=&quot;1219&quot;&gt;큰&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;sigma;&lt;/span&gt;&lt;/span&gt;: 탐색은 쉽지만 디테일 회복 불가&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;라고 설명했는데&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 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;1113&quot; data-origin-height=&quot;589&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FU6tq/dJMcaaYGmbv/Lz8JVA6NKouKVwySb6yvR1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FU6tq/dJMcaaYGmbv/Lz8JVA6NKouKVwySb6yvR1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FU6tq/dJMcaaYGmbv/Lz8JVA6NKouKVwySb6yvR1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFU6tq%2FdJMcaaYGmbv%2FLz8JVA6NKouKVwySb6yvR1%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;713&quot; height=&quot;377&quot; data-origin-width=&quot;1113&quot; data-origin-height=&quot;589&quot;/&gt;&lt;/span&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;여기서 x 는 원본 이미지 샘플이고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;xi 는 x 에 노이즈를 섞어서 만든 샘플입니다.&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;( forward )&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위쪽 검은 화살표가 &lt;span&gt;&lt;span&gt;p_&amp;sigma;(x&amp;sigma;∣x) 를 나타내는데 원본 x 로부터 각각 따로 샘플링 (x1 .... xL ) 합니다.&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;forward 는 시간에 따라 x -&amp;gt; x1 -&amp;gt; .... -&amp;gt; xL 을 실제로 연쇄적으로 변환한다기 보다 각 노이즈 레벨별로 직접 생성합니다.&amp;nbsp;&lt;/span&gt;&lt;/span&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;(Reverse )&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;회색 점선 화살표가 생성(샘플링) 인데, 큰 noise 에서 작은 noise 로 진행되게 됩니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 하면 위에서 말했듯이 큰 noise 부분에서는 밀도가 낮은 곳에서도 샘플링할 대략적인 위치를 알 수 있게 됩니다.&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;(langevin)&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 단계마다 Langvein 을 여러번 반복하게 됩니다.&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;노이즈 레벨 i 를 고정한채 , langevin 업데이트를 여러 스텝 반복하게 됩니다.&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;이부분은 뒤에서 조금 더 자세히 설명하겠습니다.&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3.4.2 Training&lt;/h4&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;362&quot; data-origin-height=&quot;47&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/SbCDq/dJMcaivCwjO/7oDDzg69JIfCx4T0CFkegk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/SbCDq/dJMcaivCwjO/7oDDzg69JIfCx4T0CFkegk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/SbCDq/dJMcaivCwjO/7oDDzg69JIfCx4T0CFkegk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSbCDq%2FdJMcaivCwjO%2F7oDDzg69JIfCx4T0CFkegk%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;362&quot; height=&quot;47&quot; data-origin-width=&quot;362&quot; data-origin-height=&quot;47&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;계속이야기 했듯이 noise 의 크기를 다양하게 가져간다.&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;838&quot; data-origin-height=&quot;365&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bHFszR/dJMcabXBf3q/XDDb0IhOgwYKIahyrHw4u0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bHFszR/dJMcabXBf3q/XDDb0IhOgwYKIahyrHw4u0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bHFszR/dJMcabXBf3q/XDDb0IhOgwYKIahyrHw4u0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbHFszR%2FdJMcabXBf3q%2FXDDb0IhOgwYKIahyrHw4u0%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;519&quot; height=&quot;226&quot; data-origin-width=&quot;838&quot; data-origin-height=&quot;365&quot;/&gt;&lt;/span&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;다음과같이 원본 분포의 score 가 아니라 가우시안으로 스무딩된 여러 버전의 p 들의 score 를 전부 학습해서 큰 noise 에서부터 작은 noise 를 단계적으로 갖출 수 있게 한다.&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;b&gt; Training Objective of NCSN&amp;nbsp;&lt;/b&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;1109&quot; data-origin-height=&quot;278&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lkyCR/dJMcabJ5VTv/alcwb5CCqcQ9gIUy6EpKrk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lkyCR/dJMcabJ5VTv/alcwb5CCqcQ9gIUy6EpKrk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lkyCR/dJMcabJ5VTv/alcwb5CCqcQ9gIUy6EpKrk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlkyCR%2FdJMcabJ5VTv%2Falcwb5CCqcQ9gIUy6EpKrk%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;669&quot; height=&quot;168&quot; data-origin-width=&quot;1109&quot; data-origin-height=&quot;278&quot;/&gt;&lt;/span&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;전체 L_ncsn loss 는 위와 같습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;L개의 다양한 noise 에 대해서 각각 DSM loss 를 구한뒤에 , 이를 모두 한번에 더해서 한꺼번에 학습시킵니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 각 가중치 ( = 각 노이즈 레벨별로 얼마나 중요하게 다룰지 결정 ) 까지 곱한뒤 더해서 총 los s를 구하게 됩니다.&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;아래 수식은 DSM loss 한개 ( noise levl 고정 ) 을 한 수식입니다. 이건 앞에서 많이 이야기했으니 자세한 설명은 패스하겠습니다.&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;( 앞선 설명 3.3.1 참조 )&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;652&quot; data-origin-height=&quot;61&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bsd3vW/dJMcafr9Cje/sdE2nKyfsvVitZe0SUtgs0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bsd3vW/dJMcafr9Cje/sdE2nKyfsvVitZe0SUtgs0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bsd3vW/dJMcafr9Cje/sdE2nKyfsvVitZe0SUtgs0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbsd3vW%2FdJMcafr9Cje%2FsdE2nKyfsvVitZe0SUtgs0%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;545&quot; height=&quot;51&quot; data-origin-width=&quot;652&quot; data-origin-height=&quot;61&quot;/&gt;&lt;/span&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;결국 DSM 최소화 =&amp;gt; 진짜 score 복원과 같은 의미이므로.&amp;nbsp; ( 3.3.1 참고 )&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;x~ 가 주어졌을때 원래 x 가 어디였을지 posterior 평균 방향으로 끌어당기는벡터가 , 바로 x~ 분포에서 확률이 커지는 방향을 score 라고 이해하고 넘어가심됩니다.&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;&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; Relationship with DDPM Loss&amp;nbsp;&lt;/b&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;앞에서 했던 이야기 다시 리마인드 정도입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;score 랑 DDPM 이 어떻게 같은지에 대한 서술입니다.&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;439&quot; data-origin-height=&quot;71&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dFYWJc/dJMcac9Zkwn/znysBkgzgxFkvMJdupbbu1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dFYWJc/dJMcac9Zkwn/znysBkgzgxFkvMJdupbbu1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dFYWJc/dJMcac9Zkwn/znysBkgzgxFkvMJdupbbu1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdFYWJc%2FdJMcac9Zkwn%2FznysBkgzgxFkvMJdupbbu1%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;359&quot; height=&quot;58&quot; data-origin-width=&quot;439&quot; data-origin-height=&quot;71&quot;/&gt;&lt;/span&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;좌변 : score&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우변 : noise x 가 주어졌을때 노이즈가 평균적으로 얼마나 섞였는지 조건부 평균 스케일링&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 노이즈 평균 알면 score 알 수 있다.&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;앞서 이야기 했던 Tweedie 때문에 ( 최적 score = DDPM denoise )&amp;nbsp;&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;1032&quot; data-origin-height=&quot;393&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mPKVy/dJMcaaRW47E/mmhsElVnW8BTEoZVZX2RX0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mPKVy/dJMcaaRW47E/mmhsElVnW8BTEoZVZX2RX0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mPKVy/dJMcaaRW47E/mmhsElVnW8BTEoZVZX2RX0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmPKVy%2FdJMcaaRW47E%2FmmhsElVnW8BTEoZVZX2RX0%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;658&quot; height=&quot;251&quot; data-origin-width=&quot;1032&quot; data-origin-height=&quot;393&quot;/&gt;&lt;/span&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;둘이 파라미터 ( 대략 여기서는 스케일 ) 만 다르지 결국 동일한 함수 정보를 가진다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;( 더 자세한 이야기는 ch 6 에서 다룬다 )&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;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt; 3.4.3 Samplining&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 알고리즘 1 은 SCORE 가 있을때 샘플링 하는 방식을알려준다. ( ncsn 식 샘플링 )&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;1113&quot; data-origin-height=&quot;670&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yeegX/dJMcacWuuVW/Y2MPFS7oU7hZzzXdJUTY70/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yeegX/dJMcacWuuVW/Y2MPFS7oU7hZzzXdJUTY70/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yeegX/dJMcacWuuVW/Y2MPFS7oU7hZzzXdJUTY70/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyeegX%2FdJMcacWuuVW%2FY2MPFS7oU7hZzzXdJUTY70%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;621&quot; height=&quot;374&quot; data-origin-width=&quot;1113&quot; data-origin-height=&quot;670&quot;/&gt;&lt;/span&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;큰 노이즈 (L) 부터 시작해서 각 노이즈 레벨에서 Langevin 을 Nt 번 반복한 뒤&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;큰 노이즈에서 작은 노이즈로 내려가면서 복원 ( coarse -&amp;gt; fine )&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;848&quot; data-origin-height=&quot;59&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vtmab/dJMcafyW3w5/9mNGXjHRqTjE7TLEvaLUv1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vtmab/dJMcafyW3w5/9mNGXjHRqTjE7TLEvaLUv1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vtmab/dJMcafyW3w5/9mNGXjHRqTjE7TLEvaLUv1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fvtmab%2FdJMcafyW3w5%2F9mNGXjHRqTjE7TLEvaLUv1%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;647&quot; height=&quot;45&quot; data-origin-width=&quot;848&quot; data-origin-height=&quot;59&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;( 각 noise level 마다 langevin dynamics 실행 )&amp;nbsp;&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;langevin 업데이트 수식을 보면 두번째 수식은 score 가 확률이 커지는 방향으로 가지고 가고 , 세번째는 noise 를 추가하는 항 입니다.&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;782&quot; data-origin-height=&quot;50&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bzEjhN/dJMcagLonle/RlnDYmUMx3LO1MNFk7TfVk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bzEjhN/dJMcagLonle/RlnDYmUMx3LO1MNFk7TfVk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bzEjhN/dJMcagLonle/RlnDYmUMx3LO1MNFk7TfVk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbzEjhN%2FdJMcagLonle%2FRlnDYmUMx3LO1MNFk7TfVk%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;782&quot; height=&quot;50&quot; data-origin-width=&quot;782&quot; data-origin-height=&quot;50&quot;/&gt;&lt;/span&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;그래서 MCMC 로 p_i 에서 샘플링하려는 업데이트이고&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;step size 같은 경우는 다음과 같이 스케일링 합니다.&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;516&quot; data-origin-height=&quot;110&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c8Dq6Y/dJMcaiI9xNa/njeaw7LDtKHu1vnu7IBPCk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c8Dq6Y/dJMcaiI9xNa/njeaw7LDtKHu1vnu7IBPCk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c8Dq6Y/dJMcaiI9xNa/njeaw7LDtKHu1vnu7IBPCk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc8Dq6Y%2FdJMcaiI9xNa%2Fnjeaw7LDtKHu1vnu7IBPCk%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;516&quot; height=&quot;110&quot; data-origin-width=&quot;516&quot; data-origin-height=&quot;110&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;노이즈가 큰 레벨은 좀 거칠고 안전한 반면 , 작은 레벨은 예민하기 때문에&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 큰 노이즈 에서는 smoothing 분포라서 score 필드가 덜 sharp 하고 조금 움직여서 필드가 안 꺠지는 반면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 작은 노이즈에서는 p 가 원본 분포에 가까워져 sharp 하게 딘다.&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;따라서 작은 noise step 에서는 step 을 더 작게 잡아야 한다.&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; Slow Sampling Speed of NCSN.&amp;nbsp;&lt;/b&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;NCSN 은 당연하게도 구조적으로 엄청 느립니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 샘플링이 MCMC 라서 K 번 반복이 필요하다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 노이즈 레벨이 여러개이므로 더 오래 걸린다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 게다가 병렬화도 안된다 ( 더 큰 NOISE 쪽의 OUTPUT 이 나와야 그다음을 돌릴 수 있다 )&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;&amp;nbsp;&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;b&gt;Summary : A Comparative View of NCSN and DDPM&amp;nbsp;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;NCSN 과 DDPM 의 공통점과 차이점을 한번 정리하고 가려고 합니다.&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;- Forward : 원본 x 에서 noise 를 추가한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Reverse : noise 에서 시작해서 x 로 돌아온다.&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;p data-ke-size=&quot;size16&quot;&gt;NCSN : 각 노이즈 레벨에서 score ( log p(x) ) 를 직접 근사해서&amp;nbsp; Langevin dynamics 로 샘플링한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DDPM : reverse trasition p(x_i-1 | x i ) 를 모델링 ( 그니까 noise 예측 ) 을 통해서 Markov chain 으로 한 스텝씩 뒤로 되돌린다.&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;아래 Table 3.1 을 보면 더 정리가 직관적으로 된다.&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;913&quot; data-origin-height=&quot;334&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c2x1Io/dJMcaaxDV2A/jTCtJgFIKScHyf5PYojrX0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c2x1Io/dJMcaaxDV2A/jTCtJgFIKScHyf5PYojrX0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c2x1Io/dJMcaaxDV2A/jTCtJgFIKScHyf5PYojrX0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc2x1Io%2FdJMcaaxDV2A%2FjTCtJgFIKScHyf5PYojrX0%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;721&quot; height=&quot;264&quot; data-origin-width=&quot;913&quot; data-origin-height=&quot;334&quot;/&gt;&lt;/span&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 첫번째 줄 ( x i+1 | x i )&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DDPM 쪽은 Forward 시 markov chain 으로 정의하는 걸 볼 수 있습니다.&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;beta 스케줄이 얼마나 노이즈를 넣을지 정하게 됩니다.&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;NCSN&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ncsn 에서는 노이즈 레벨 별로 두고 (&amp;nbsp; &lt;span&gt;&lt;span&gt;&amp;sigma;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;i )&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;( xi = x + &lt;span&gt;&lt;span&gt;&amp;sigma;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;i&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​ &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;ϵ )&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;각 레벨에서의 pertubed distribution 정의 한 뒤에 적절히 유도하면 맨 첫번째 수식이 나오게 됩니다. ( 유도과정은 앞쪽에 있으니 생략할께요 )&amp;nbsp;&lt;/span&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;span&gt;2. 두번쨰 ( xi | x )&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;원본 x 에서 xi 가 어떻게 생기는지&amp;nbsp;&lt;/span&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;xi = (scale) * x + (noise scale ) * ϵ&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. prior&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;NCSN : 가장 큰 노이즈 레벨 ( L )&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DDPM : 순수한 NOISE&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. Loss&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;NCSN 과 DDPM 둘을 수식 전개를 해보면 결국 가우시안에서 score 와 노이즈는 선형변환관계와 유사하게 됩니다.&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;따라서 score 맞추는것과 노이즈 맞추는게 표현만 다르고 거의 본질적으로 비슷하게 되는 것 이죠&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;5. Sampling&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;NCSN : 각 레벨에서 Langevin 을 여러번 돌리면서 업데이트를 하고&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DDPM : reverse Markov chain 을 한 스텝씩 합니다.&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;&amp;lt; A shared Bottleneck &amp;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;DDPM &amp;amp; NCSN 둘다 time / noise 축을 매우 많이 돌려야 성능이 나와서 , 샘플링 시 매우 많은 step 을 거쳐야 해서 느립니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;( 제가 알기로 DDPM 의 경우 1000 step 정도였던 것 같습니다 )&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;( 이부분에 대한 해결 방안은 ch 9 / 10 에서 설명한다고 합니다 )&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;h2 data-ke-size=&quot;size26&quot;&gt;3.6 Closing Remarks&amp;nbsp;&lt;/h2&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;1. EBM&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- EBM 은 데이터의 확률 분포를 학습할 수 있는 방식이지만 , tractable 한 문제가 있었습니다. (&amp;nbsp; z 라는 정규화 상수 때문에 )&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 로그를 취한뒤 미분을 통한 Score function 을 이용해서 이 문제를 우회했습니다.&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;2. score -&amp;gt; DSM&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 기존 score matching 은 모델 score 가 데이터 score 를 맞추는 형식이지만 p_data 를 직접 계산할 수 없는 단점이 있어서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- DSM 에서는 p_data 분포에 노이즈를 넣어 x~ 를 만들고 , x~ 의 분포 p(x~) 의 score 를 학습시킵니다.&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;3. Tweedie formula&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- score = denoise 라는 것을 수식적으로 증명하면서 score &amp;amp; denoising 을 묶어주는 역할을 합니다.&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;4. NCSN &amp;amp; Diffusion&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- NCSN 과 DDPM 이 결국 유사한 구조를 가지게 됨을 배웠습니다.&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;TODO :&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 DDPM 과 NCSN 의 모델이 수렴이 우연이 아니고 , 더 깊은 수학적인 구조를 암시한다고 말합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 더 깊은 구조가 score SDE 프레임 워크이고 이는 챕터에서 더 깊게 배워보도록 하겠습니다.&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;- 소감 :&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;score 쪽 이해도 괜찮았고 NCSN 자체도 큰 문제는 없었는데 Tweedie 나오면서 이해가 살짝 무너졌다.&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;&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;&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;헷갈린 점들&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- training vs sampling 에서 noise 항의 필요성에 대해서 .&amp;nbsp; (sampling 할때는 왜 필요한 것인가 ? )&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;이부분은 gpt 를 이용해서 이해를 보강해보는 것을 추천.&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;- DDPM 와 SCORE 의 연결성 ( 수식적으로 )&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;- vector field 의 divergence &lt;a href=&quot;https://angeloyeo.github.io/2019/08/25/divergence.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://angeloyeo.github.io/2019/08/25/divergence.html&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- trace&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- ( 혼자 생각하다가 의문이들어서 ) : 그러면 diffusion 으로 학습시키고 score처럼 샘플링해도 되는거 아닌가 ? -&amp;gt; 여기에 대한 해답은 DDIM 에 있다. DDIM 을 확인하면 내 의문 처럼 diffusion 으로 학습시키고 Score 처럼 샘플링한다. ( 10~100 배정도 샘플링이 빠르고 퀄리티가 좋다고 한다 )&amp;nbsp;&lt;/p&gt;</description>
      <category>The Principle of Diffusion</category>
      <author>Kim_sang_hyeob</author>
      <guid isPermaLink="true">https://ksh0416.tistory.com/150</guid>
      <comments>https://ksh0416.tistory.com/150#entry150comment</comments>
      <pubDate>Sat, 21 Feb 2026 11:51:22 +0900</pubDate>
    </item>
    <item>
      <title>PyAV stream 문제 ( 해결 완 ) - 아카이빙용</title>
      <link>https://ksh0416.tistory.com/155</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;NVDEC 로 디코딩을 계속해서 순차적 스트림으로 받을때 스트림이 잘 안닫혀서 명시적으로 직접 닫도록 코드를 작성했는데 , 분명히 이게 자동으로 닫히게 하는 방법이 있거나 ( 혹은 내가 스트림을 닫는 방법을 잘 못 알았거나 )&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;대부분 gpt , claude , gemini 를 통해서 해결했으므로..&amp;nbsp; 아카이빙용으로 trouble shooting 과정을 좀 남겨본다.&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. FFmpeg 가 파일을 읽는다는건 뭘까 ?&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;&amp;ldquo;FFmpeg가 읽는다&amp;rdquo;는 말은 &lt;b&gt;(1) 파일을 열고 컨테이너를 파싱(demux 준비)&lt;/b&gt; 하는 단계까지를 뜻하는 경우가 많고, &lt;b&gt;그 자체가 곧바로 &amp;ldquo;디코딩&amp;rdquo;은 아니야.&lt;/b&gt; 디코딩은 보통 &lt;b&gt;그 다음 단계&lt;/b&gt;에서 일어난다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래처럼 3단계로 생각하면 깔끔함.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;0) 동영상 파일 안에는 뭐가 있나?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대부분의 동영상 파일(mp4, mkv 등)은:&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;컨테이너(container)&lt;/b&gt;: mp4/mkv 같은 &amp;ldquo;포장 상자&amp;rdquo;&lt;/li&gt;
&lt;li&gt;그 안에 여러 &lt;b&gt;스트림(stream)&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;비디오 스트림(H.264/HEVC/AV1 등으로 &amp;ldquo;압축된 비트스트림&amp;rdquo;)&lt;/li&gt;
&lt;li&gt;오디오 스트림(AAC/Opus 등)&lt;/li&gt;
&lt;li&gt;자막 등&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 파일 안에는 보통 &amp;ldquo;이미 압축된 데이터&amp;rdquo;가 들어있고, 아직 픽셀 이미지가 아님.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1) &amp;ldquo;읽는다(open)&amp;rdquo; = 컨테이너 파싱 + 스트림 목록 만들기 (디코딩 아님)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;av.open(&quot;a.mp4&quot;)를 하면 FFmpeg는 대략 이렇게 함:&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;파일 핸들 열기(디스크/네트워크)&lt;/li&gt;
&lt;li&gt;컨테이너 헤더 파싱(mp4 박스, mkv EBML 등)&lt;/li&gt;
&lt;li&gt;&amp;ldquo;이 파일에 비디오 1개, 오디오 1개가 있네&amp;rdquo;&lt;/li&gt;
&lt;li&gt;각 스트림의 메타데이터/코덱 정보 수집
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;코덱 타입(H.264 등)&lt;/li&gt;
&lt;li&gt;해상도, fps, time_base, extradata(SPS/PPS 같은 것) 등&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;➡️ 이 단계는 **&amp;ldquo;목차와 포장 구조 읽기&amp;rdquo;**에 가까움.&lt;br /&gt;&lt;b&gt;아직 프레임을 픽셀로 풀지(디코딩) 않는다.&lt;/b&gt;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2) Demux(디먹스) = 컨테이너에서 &amp;ldquo;압축 패킷(packet)&amp;rdquo;을 꺼내기 (여전히 디코딩 아님)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 다음에 보통:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;for packet in container.demux(video_stream): ...&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 FFmpeg는 컨테이너(mp4)에서 비디오 트랙에 해당하는 데이터를 시간 순서로 꺼내서&lt;br /&gt;&lt;b&gt;압축된 조각(packet)&lt;/b&gt; 단위로 줌.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비유:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;컨테이너는 &amp;ldquo;도시락 상자&amp;rdquo;&lt;/li&gt;
&lt;li&gt;demux는 &amp;ldquo;반찬 칸에서 반찬을 꺼내 접시에 놓는 것&amp;rdquo;&lt;/li&gt;
&lt;li&gt;아직 &amp;ldquo;씹어서 소화(디코딩)&amp;rdquo;는 안 함&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3) Decode(디코드) = 패킷을 &amp;ldquo;프레임(frame)&amp;rdquo;으로 푸는 것 (여기가 진짜 디코딩)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;for frame in packet.decode(): ...&lt;br /&gt;또는&lt;/li&gt;
&lt;li&gt;for frame in container.decode(video=0): ...&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 FFmpeg 디코더(H.264 디코더 등)가:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;압축 비트스트림 &amp;rarr; &lt;b&gt;YUV/RGB 같은 실제 픽셀 프레임&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;B-frame 재정렬, 참조 프레임 버퍼 관리 등&lt;/li&gt;
&lt;li&gt;내부적으로 디코더 상태/버퍼를 유지&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;➡️ 여기서부터가 &amp;ldquo;동영상이 디코딩된다&amp;rdquo;가 맞음.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;( 여기서 나는 NVDEC 로 디코딩을 하는 것 )&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;PyAV 관점에서 &amp;ldquo;container / stream이 뭘 의미하나&amp;rdquo;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;container(AVFormatContext 래퍼):&lt;br /&gt;&lt;b&gt;파일 열기 + demux 관리&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;stream(AVStream/코덱 관련 래퍼):&lt;br /&gt;&lt;b&gt;특정 트랙(비디오/오디오) 선택 + 디코딩에 필요한 정보/상태로 연결&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 &amp;ldquo;stream close 안 하면 문제&amp;rdquo;는 보통&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;참조 프레임 버퍼&lt;/b&gt;, &lt;b&gt;재정렬 큐&lt;/b&gt;, &lt;b&gt;내부 캐시&lt;/b&gt; 같은 C 메모리가&lt;/li&gt;
&lt;li&gt;파이썬 객체 생명주기/참조 때문에 &lt;b&gt;제때 해제 안 되는 상황&lt;/b&gt;이 생겨서 발생.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;머릿속 그림 (초간단)&lt;/h2&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;open()   : 컨테이너 구조 읽기 (목차 파싱)  [디코딩 X]
demux()  : 압축 패킷 꺼내기              [디코딩 X]
decode() : 패킷 &amp;rarr; 픽셀 프레임             [디코딩 O]

close()  : &amp;larr; 여기서 열었던 것들을 역순으로 다 반환해야 함
  codec_context.close()  &amp;rarr; NVDEC 세션 + GPU 버퍼 해제
  stream.close()         &amp;rarr; 스트림 내부 버퍼 해제
  container.close()      &amp;rarr; 파일 핸들(FD) 반환&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 대략 FFmpeg 에 대한 이해를 먼저 하고&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;2. NVDEC 디코딩 흐름&lt;br /&gt;-&amp;gt; 그다음 왜 내 코드에서는 오류가 났는지 파악하기 전에 NVDEC 디코딩 흐름에 대해서 먼저 살펴보기로 했다.&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;h2 data-ke-size=&quot;size26&quot;&gt;NVDEC 디코딩 흐름&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;영상 파일 하나를 처리하는 과정을 생각해보면:&lt;/p&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;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;angelscript&quot; style=&quot;color: #14181f;&quot;&gt;&lt;code&gt;1. 파일 열기 (av.open)
   &amp;rarr; OS가 파일 디스크립터(FD) 하나 할당
   &amp;rarr; NVDEC 하드웨어 디코더 세션 생성
   &amp;rarr; GPU VRAM 일부 할당

2. 프레임 디코딩 (container.decode)
   &amp;rarr; NVDEC이 H.264 &amp;rarr; NV12 변환
   &amp;rarr; 프레임을 큐에 넣음

3. 파일 닫기 (container.close)
   &amp;rarr; FD 반환
   &amp;rarr; NVDEC 세션 해제
   &amp;rarr; VRAM 반환&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제는 &lt;b&gt;3번이 제대로 안 되는 것&lt;/b&gt;입니다.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 왜 안닫히는데&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;PyAV에서 container.close()를 호출하면 &lt;b&gt;파일만 닫힘&lt;/b&gt;. 근데 그 안에 있는 **디코더(codec_context)**와 **스트림(stream)**은 아직 살아있어요. 비유하자면:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;makefile&quot; style=&quot;color: #14181f;&quot;&gt;&lt;code&gt;container  = 건물
stream     = 건물 안의 사무실
codec_ctx  = 사무실 안의 기계(NVDEC)

container.close()  &amp;rarr; 건물 문만 잠금
                   &amp;rarr; 사무실 안 기계는 아직 돌아가고 있음
                   &amp;rarr; 전기(VRAM), 수도(FD) 계속 쓰는 중&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 &lt;b&gt;기계 먼저 끄고 &amp;rarr; 사무실 닫고 &amp;rarr; 건물 닫아야&lt;/b&gt; 합니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;지금 시스템에서 왜 심각하냐&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;8카메라 &amp;times; 1분 세그먼트 &amp;times; 10시간 = &lt;b&gt;약 4,800번&lt;/b&gt; 파일을 열고 닫음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;매번 안 닫히는 게 쌓이면:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;angelscript&quot; style=&quot;color: #14181f;&quot;&gt;&lt;code&gt;세그먼트 1:   FD 8개 릭, VRAM 조금 릭
세그먼트 100: FD 800개 릭 &amp;rarr; &quot;Too many open files&quot; 에러
세그먼트 500: VRAM 누적 &amp;rarr; CUDA out of memory&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&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;4. 해결&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;bash&quot; style=&quot;color: #14181f;&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;해결: 안쪽부터 바깥으로 닫기

# ❌ 기존 (부족한 정리)
container = av.open(str(video_path))
for frame in container.decode(video=0):
    ...
container.close()

# ✅ 수정 (완전한 정리)
container = None
try:
    container = av.open(str(video_path))
    stream = container.streams.video[0]
    for frame in container.decode(video=0):
        ...
finally:
    if container:
        for s in container.streams:
            s.codec_context.close()
            s.close()
        container.close()


혹은 

권장 순서(보수적/안전): stream(=decoder) 먼저 닫고 &amp;rarr; container(=file) 닫기
이유: stream 쪽이 **디코더 상태(특히 NVDEC surfaces/프레임 버퍼 등)**를 물고 있는 경우가 많아서, 이걸 먼저 내려야 컨테이너를 닫아도 뒤가 깔끔하게 정리됩니다.
다만 PyAV에서는 보통:


with av.open(path) as container:
	stream = container.streams.video[0] 
    for frame in container.decode(stream): 
    	... 
    stream.close() # (가능하면) 여기서 한 번 더 보수적으로 # with 블록을 나가면서 container.close()가 호출
이렇게 &amp;ldquo;with + stream.close()&amp;rdquo; 조합을 쓰면, GC 타이밍/참조 잔존 때문에 늦게 풀리는 문제를 많이 줄입니다.

핵심: &amp;ldquo;파일을 먼저 닫고 stream을 닫는다&amp;rdquo;라기보단, 디코더(스트림/코덱컨텍스트)를 확실히 내려서 C 리소스를 풀어라가 요지입니다.&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5. 근데 nvdec 를 열어두고 계속 쓰면 안되나 ?&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;h2 data-ke-size=&quot;size26&quot;&gt;NVDEC을 그냥 열어두고 계속 쓰면 안 되나?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 질문이 핵심인데, &lt;b&gt;그게 안 돼서 문제가 생기는 거예요.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금 구조를 보면:&lt;/p&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;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;angelscript&quot; style=&quot;color: #14181f;&quot;&gt;&lt;code&gt;파일1 열기 &amp;rarr; NVDEC 세션 생성 &amp;rarr; 디코딩 &amp;rarr; 파일1 닫기 &amp;rarr; (세션 해제 안 됨!)
파일2 열기 &amp;rarr; NVDEC 세션 또 생성 &amp;rarr; 디코딩 &amp;rarr; 파일2 닫기 &amp;rarr; (세션 해제 안 됨!)
파일3 열기 &amp;rarr; NVDEC 세션 또 생성 &amp;rarr; ...&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;av.open()을 할 때마다 &lt;b&gt;새로운 NVDEC 세션이 만들어져요.&lt;/b&gt; 그리고 제대로 안 닫으면 이전 세션이 GPU에 좀비처럼 남아있는 거죠. RTX 3080/3090의 NVDEC 하드웨어 세션 수에는 한계가 있어서, 이게 쌓이면 결국 터지는 겁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이상적으로는 이렇게 하고 싶은 거잖아요:&lt;/p&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;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;angelscript&quot; style=&quot;color: #14181f;&quot;&gt;&lt;code&gt;NVDEC 세션 하나 열기
  &amp;rarr; 파일1 넣기 &amp;rarr; 디코딩
  &amp;rarr; 파일2 넣기 &amp;rarr; 디코딩
  &amp;rarr; 파일3 넣기 &amp;rarr; 디코딩
NVDEC 세션 닫기&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;근데 &lt;b&gt;PyAV로는 이게 안 돼요.&lt;/b&gt; PyAV는 av.open()할 때마다 container &amp;rarr; stream &amp;rarr; codec_context가 세트로 생기고, 그 안에 NVDEC 세션이 묶여있어요. 파일을 바꾸려면 이 세트를 통째로 버리고 새로 만들어야 해요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 현실적인 답은:&lt;/p&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;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;angelscript&quot; style=&quot;color: #14181f;&quot;&gt;&lt;code&gt;파일1 열기 &amp;rarr; NVDEC 세션 생성 &amp;rarr; 디코딩 &amp;rarr; 확실하게 닫기 (세션 해제)
파일2 열기 &amp;rarr; NVDEC 세션 생성 &amp;rarr; 디코딩 &amp;rarr; 확실하게 닫기 (세션 해제)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;매번 새 세션이 만들어지는 건 어쩔 수 없지만, 이전 세션을 확실하게 닫아서 자리를 비워줘야&lt;/b&gt; 다음 세션이 문제 없이 들어갈 수 있는 거예요. 지금 문제는 &quot;자리를 안 비워서&quot; 계속 쌓이는 거고요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;NVIDIA의 PyNvVideoCodec이라는 라이브러리는 디코더 세션을 재사용하는 걸 지원하긴 하는데, PyAV 기반 파이프라인에서는 갈아엎어야 해서 현재 단계에서는 &quot;확실하게 닫기&quot;가 가장 현실적인 해결책입니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;+)&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;5455&quot; style=&quot;background-color: #ffffff; color: #242424; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size23&quot;&gt;전반적으로 NVDEC를 이해하기 위해서 아래 블로그를 참조했습니다.&amp;nbsp;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://monday9pm.com/nvidia-video-codec-sdk%EB%A1%9C-pytorch%EC%97%90%EC%84%9C-%EB%B9%84%EB%94%94%EC%98%A4-%EC%B2%98%EB%A6%AC-%EA%B0%80%EC%86%8D%ED%99%94%ED%95%98%EA%B8%B0-a1c1d55ab3d5&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://monday9pm.com/nvidia-video-codec-sdk%EB%A1%9C-pytorch%EC%97%90%EC%84%9C-%EB%B9%84%EB%94%94%EC%98%A4-%EC%B2%98%EB%A6%AC-%EA%B0%80%EC%86%8D%ED%99%94%ED%95%98%EA%B8%B0-a1c1d55ab3d5&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;&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;700&quot; data-origin-height=&quot;402&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/u9AnO/dJMcacWjNJx/10zyKnqSj5ioKusypeDtrK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/u9AnO/dJMcacWjNJx/10zyKnqSj5ioKusypeDtrK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/u9AnO/dJMcacWjNJx/10zyKnqSj5ioKusypeDtrK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fu9AnO%2FdJMcacWjNJx%2F10zyKnqSj5ioKusypeDtrK%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;700&quot; height=&quot;402&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;402&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 그래서 파일은 1분짜리인데 계속해서 디코딩을 열면 오버헤드가 생길 것 같아서 ( 뭘 확인해보지는 않았습니다만 )&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;span style=&quot;color: #333333; text-align: start;&quot;&gt;PyNV vs&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #f0eee6; color: #141413; text-align: start;&quot;&gt;pynvvideocodec&lt;span&gt;&amp;nbsp;&lt;/span&gt;ㅂ&lt;/span&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;&amp;nbsp;&lt;/p&gt;
&lt;div data-test-render-count=&quot;1&quot;&gt;
&lt;div&gt;
&lt;div data-is-streaming=&quot;false&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;PyAV 방식&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;properties&quot; style=&quot;color: #14181f;&quot;&gt;&lt;code&gt;Python (PyAV)
   &amp;darr;
FFmpeg (C 라이브러리)
   &amp;darr;
NVDEC 하드웨어&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PyAV는 FFmpeg의 Python 래퍼예요. FFmpeg가 중간에 끼어서 NVDEC을 대신 제어하는 구조인데, FFmpeg는 원래 &lt;b&gt;&quot;파일 하나 열고 &amp;rarr; 처리하고 &amp;rarr; 닫기&quot;&lt;/b&gt; 를 전제로 설계된 거라, 파일이 바뀌면 디코더 세션을 통째로 버리고 새로 만들어요. 세션을 재사용하는 개념 자체가 FFmpeg 설계에 없습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 PyAV가 FFmpeg의 C 구조체를 Python 객체로 감싸는 과정에서, Python GC와 C 메모리 해제 타이밍이 안 맞아서 릭이 생기는 거고요.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;PyNvVideoCodec 방식&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;properties&quot; style=&quot;color: #14181f;&quot;&gt;&lt;code&gt;Python (PyNvVideoCodec)
   &amp;darr;
NVIDIA Video Codec SDK (C++)
   &amp;darr;
NVDEC 하드웨어&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PyNvVideoCodec은 NVIDIA가 직접 만든 거라, &lt;b&gt;FFmpeg를 안 거칩니다&lt;/b&gt; (demux 할 때만 내부적으로 FFmpeg 씀). NVDEC 하드웨어를 직접 제어하니까:&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;캐시하고 재사용&lt;/b&gt; 가능&lt;/li&gt;
&lt;li&gt;파일이 바뀌어도 같은 코덱이면 &lt;b&gt;세션 유지, 버퍼만 교체&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;GPU 메모리 할당/해제를 &lt;b&gt;라이브러리가 직접 관리&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;비유로 정리하면&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;avrasm&quot; style=&quot;color: #14181f;&quot;&gt;&lt;code&gt;PyAV:
  &quot;택시를 탔는데 기사님(FFmpeg)한테 목적지를 말함&quot;
  &amp;rarr; 기사가 알아서 운전
  &amp;rarr; 목적지 도착하면 택시 내려야 함 (세션 종료)
  &amp;rarr; 다음 목적지? 새 택시 잡아야 함 (세션 새로 생성)
  &amp;rarr; 이전 택시가 안 가고 길에 서있는 문제 발생 (릭)

PyNvVideoCodec:
  &quot;내가 직접 운전 (NVDEC 직접 제어)&quot;
  &amp;rarr; 목적지 도착해도 차에서 안 내림
  &amp;rarr; 다음 목적지? 네비만 바꾸면 됨 (버퍼만 교체)
  &amp;rarr; 차는 하나로 계속 씀 (세션 재사용)&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;
&lt;/div&gt;
&lt;div&gt;
&lt;div data-state=&quot;closed&quot;&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;--&amp;gt; 그래서 PyNvVideoCodec 을 사용하려고 하는데 뭔가 이전 레거시 코드랑 살짝 엇갈림&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div data-state=&quot;closed&quot;&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div data-state=&quot;closed&quot;&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div data-state=&quot;closed&quot;&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&amp;lt; 해결 방안 &amp;gt;&amp;nbsp;&lt;/h2&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PyNvVideoCodec 으로 교체&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;( Decoder.py - 대략 디코더가 하는일 )&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&amp;nbsp;①&amp;nbsp;probe_video_duration&amp;nbsp;(cv2)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;larr;&amp;nbsp;안전한&amp;nbsp;duration&amp;nbsp;사전&amp;nbsp;조회 &lt;br /&gt;&amp;nbsp;&amp;nbsp;②&amp;nbsp;CreateDemuxer&amp;nbsp;(NVDEC)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;larr;&amp;nbsp;파일&amp;nbsp;열기&amp;nbsp;+&amp;nbsp;컨테이너&amp;nbsp;파싱 &lt;br /&gt;&amp;nbsp;&amp;nbsp;③&amp;nbsp;CreateDecoder&amp;nbsp;(NVDEC)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;larr;&amp;nbsp;GPU&amp;nbsp;디코더&amp;nbsp;할당 &lt;br /&gt;&amp;nbsp;&amp;nbsp;④&amp;nbsp;Demux()&amp;nbsp;&amp;rarr;&amp;nbsp;Decode()&amp;nbsp;루프&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;larr;&amp;nbsp;패킷&amp;nbsp;&amp;rarr;&amp;nbsp;프레임&amp;nbsp;디코딩 &lt;br /&gt;&amp;nbsp;&amp;nbsp;⑤&lt;s&gt; nv12_to_rgb (DLPack + torch)&amp;nbsp;&amp;nbsp;&amp;larr; 색공간 변환 + 리사이즈 ( 역시 GPU 위에서 )&amp;nbsp;&lt;/s&gt; ( Bottle neck 있었던 부분 )&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;⑥&amp;nbsp;gpu_input_queue.put()&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;larr;&amp;nbsp;추론&amp;nbsp;큐에&amp;nbsp;전달 &lt;br /&gt;&amp;nbsp;&amp;nbsp;⑦&amp;nbsp;del&amp;nbsp;decoder&amp;nbsp;/&amp;nbsp;del&amp;nbsp;demuxer&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;larr;&amp;nbsp;리소스&amp;nbsp;해제&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;PyAV (이전) vs PyNvVideoCodec (현재)
&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;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;중간 레이어&lt;/td&gt;
&lt;td&gt;FFmpeg가 NVDEC 제어&lt;/td&gt;
&lt;td&gt;NVIDIA SDK가 직접 제어&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;리소스 정리&lt;/td&gt;
&lt;td&gt;codec_context.close() &amp;rarr; stream.close() &amp;rarr; container.close() 3단계 필요&lt;/td&gt;
&lt;td&gt;del decoder &amp;rarr; del demuxer 로 단순화&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;세션 관리&lt;/td&gt;
&lt;td&gt;FFmpeg 구조에 묶여서 재사용 불가&lt;/td&gt;
&lt;td&gt;원칙적으론 재사용 가능 (현재는 안 하고 있음)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;EOF 처리&lt;/td&gt;
&lt;td&gt;불안정 (hang 유발)&lt;/td&gt;
&lt;td&gt;상대적으로 나음 + probe_video_duration으로 사전 확인&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 구성한 이유가 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;PyNvVideoCodec&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt; 가 반환 객체 ( 그니까 파일을 close 하고 나서 ) 명시적인 메서드가 없는 상황이라 파일을 먼저 사전 조회를 하고 (cv2 통해서 ) 그다음에 디코딩이 된 걸 가지고 계산해서 파일 닫힘을 얻은 뒤에 del 을 통해 정리하게 된다.&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;( 추가로 서치해봐도 API reference 를 뒤져봤는데 decoder 클래스에 목록에 전혀 없다. / 추가로 Demux 에서도 마찬가지. )&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;lt; 추가 &amp;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;PyNvVideoCodec은 FFmpeg(PyAV)처럼 컨테이너/스트림에 대한 명시적 close()나 EOF 이벤트를 제공하지 않는다. 대신 스트림 종료는 Demux()/Decode() 호출 결과가 비어있는 형태로 반복되며 간접적으로 나타난다. 문제는 EOF 근처에서 이러한 &amp;ldquo;empty 결과&amp;rdquo;가 한 번만 발생하는 것이 아니라 여러 번 연속 발생할 수 있고, 환경에 따라 이 구간에서 루프가 종료되지 않으면 hang로 이어질 수 있다는 점이다.&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;이를 방지하기 위해 디코딩 루프에 EOF streak(연속 empty 카운트) 기반 종료 정책을 도입했다. Demux()/Decode() 결과가 비어있다고 판단되면 empty_count를 증가시키고, 정상 프레임이 나오면 이를 0으로 리셋한다. empty_count가 사전에 정의한 임계치(EMPTY_THRESHOLD) 이상 누적되면 스트림이 종료된 것으로 간주하고 루프를 종료한다. 또한 PyNvVideoCodec이 duration 정보를 직접 제공하지 않으므로, cv2 기반 probe_video_duration으로 사전 조회한 duration을 상한으로 사용해 EOF 판정의 안정성을 보강했다&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;결과적으로 명시적 close API 부재로 인한 EOF 처리 불안정성을, (1) duration 사전 조회와 (2) empty streak 임계치 종료의 조합으로 안정적으로 해소했다.&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;&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;&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;&amp;nbsp;&lt;/p&gt;</description>
      <author>Kim_sang_hyeob</author>
      <guid isPermaLink="true">https://ksh0416.tistory.com/155</guid>
      <comments>https://ksh0416.tistory.com/155#entry155comment</comments>
      <pubDate>Sat, 14 Feb 2026 12:17:40 +0900</pubDate>
    </item>
    <item>
      <title>VIST3A 리뷰 발표자료</title>
      <link>https://ksh0416.tistory.com/154</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;제가 하고 싶은 연구의 이상적인 방향인것 같아서 오랜만에 깊게 읽었습니다. Appendix 도 읽었고,,, 깊게 고민도 했습니다.&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;아카이빙용이라 appendix 나 이런게 긁어온것 중에서 이해되는 부분 넣어둔거긴 한데 , 보실때는 이게 이해가 더 잘될 것 같아서 올려봅니다. 마침 코드도 최근에 공개 되어서 아직 사용은 못해도 (파라미터가 다 안올라온걸로 알아서 ) 조만간 올라오면 fork 떠서 실제로 좀 여러가지 살펴봐야겠다고 생각이 들었습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;fileblock&quot; data-ke-align=&quot;alignCenter&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/bdt5Kq/dJMcac22UNo/W7JNrN1NOHZVOiNlVpR7mk/VIST3A_%EC%95%84%EC%B9%B4%EC%9D%B4%EB%B9%99%EC%9A%A9.pptx?attach=1&amp;amp;knm=tfile.pptx&quot; class=&quot;&quot;&gt;
    &lt;div class=&quot;image&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;desc&quot;&gt;&lt;div class=&quot;filename&quot;&gt;&lt;span class=&quot;name&quot;&gt;VIST3A_아카이빙용.pptx&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;3.07MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&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;&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;lt; 앞으로 주의 사항 &amp;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;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;</description>
      <category>Paper</category>
      <author>Kim_sang_hyeob</author>
      <guid isPermaLink="true">https://ksh0416.tistory.com/154</guid>
      <comments>https://ksh0416.tistory.com/154#entry154comment</comments>
      <pubDate>Sun, 8 Feb 2026 00:44:31 +0900</pubDate>
    </item>
    <item>
      <title>What is HexPlane ( with 4DGS )</title>
      <link>https://ksh0416.tistory.com/153</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;4DGS 프로젝트를 하기에 앞서서 먼저 Hex plane 에 대해서 더 이해를 해야될 것 같아서 정리한다.&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;4D공간 ( xyz + time t ) 에서 featrue field D(x,y,z,t) 를 6개의&lt;b&gt; 2D feature plane&lt;/b&gt;(XY, XZ, YZ, XT, YT, ZT) 으로 나눠서 저장하고 , 4D 에서 점을 물어보면 ( 그니까 time + space ) 를 물어보면 해당 점을 각 plane 에 투영해서 샘플링 --&amp;gt; 결합 해서 그점의 feature 를 빠르게 복원하는 형식이다.&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;Plane 은 총 6개인데&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(x,y,z,t) 에서 두 축을 고르면 2D plane 이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;489&quot; data-start=&quot;466&quot;&gt;공간-공간: XY, XZ, YZ&lt;/li&gt;
&lt;li data-end=&quot;513&quot; data-start=&quot;490&quot;&gt;공간-시간: XT, YT, ZT&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;&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;HexPlane 이 단순히 6개에서 feature 뽑고 concat 하는게 아니라 (공간 plane) x ( 공간-시간 plane) 을 elemtewise product 으로 묶어서 4D 상호작용 만들고 선형결합해서 feature 로 출력한다.&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;516&quot; data-origin-height=&quot;344&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yjNgm/dJMcaaYrgDE/WJUN3hbzfrJY9vjGkL1MU1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yjNgm/dJMcaaYrgDE/WJUN3hbzfrJY9vjGkL1MU1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yjNgm/dJMcaaYrgDE/WJUN3hbzfrJY9vjGkL1MU1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyjNgm%2FdJMcaaYrgDE%2FWJUN3hbzfrJY9vjGkL1MU1%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;516&quot; height=&quot;344&quot; data-origin-width=&quot;516&quot; data-origin-height=&quot;344&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;- 만약에 (XY) 만쓰면 시간에 무관한 정보가 들어가고&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- (ZT) 는 시간이 포함된 Plane 이 움직임/변화를 담당하고&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 둘을 곱하면 어떤 xy 위치에서 , 시간/깊이(zt) 에 따라 달라지는지 알 수 있는 결합효과가 생긴다.&amp;nbsp;&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;1069&quot; data-origin-height=&quot;427&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bFfGoK/dJMcagRTUE2/skLv4ru1azkymuAYJJVo0K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bFfGoK/dJMcagRTUE2/skLv4ru1azkymuAYJJVo0K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bFfGoK/dJMcagRTUE2/skLv4ru1azkymuAYJJVo0K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbFfGoK%2FdJMcagRTUE2%2FskLv4ru1azkymuAYJJVo0K%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;835&quot; height=&quot;334&quot; data-origin-width=&quot;1069&quot; data-origin-height=&quot;427&quot;/&gt;&lt;/span&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;그래서 위와 같이 둘 (XY - ZT ) 을 결합해서 사용한다.&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;이때 왜 xy - zt 를 결합(페어링) 하는지 의문일 수 있는데 , 일단 한 곱 안에 x,y,z,t 가 모두 들어가야한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2076&quot; data-start=&quot;2057&quot; data-ke-size=&quot;size16&quot;&gt;그리고 HexPlane가 쓰는 3개 곱은:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2161&quot; data-start=&quot;2078&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2105&quot; data-start=&quot;2078&quot;&gt;(XY)&amp;times;(ZT) &amp;rarr; (x,y)와 (z,t)&lt;/li&gt;
&lt;li data-end=&quot;2133&quot; data-start=&quot;2106&quot;&gt;(XZ)&amp;times;(YT) &amp;rarr; (x,z)와 (y,t)&lt;/li&gt;
&lt;li data-end=&quot;2161&quot; data-start=&quot;2134&quot;&gt;(YZ)&amp;times;(XT) &amp;rarr; (y,z)와 (x,t)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;2212&quot; data-start=&quot;2163&quot; data-ke-size=&quot;size16&quot;&gt;각 항이 4개 변수 전부를 포함하고, 동시에 서로 다른 방식으로 얽힘을 잡을 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2212&quot; data-start=&quot;2163&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2246&quot; data-start=&quot;2214&quot;&gt;XT는 &amp;ldquo;x 방향 움직임 vs 시간&amp;rdquo; 상관을 잡기 좋고&lt;/li&gt;
&lt;li data-end=&quot;2269&quot; data-start=&quot;2247&quot;&gt;YT는 &amp;ldquo;y 방향 움직임 vs 시간&amp;rdquo;&lt;/li&gt;
&lt;li data-end=&quot;2289&quot; data-start=&quot;2270&quot;&gt;ZT는 &amp;ldquo;깊이/변형 vs 시간&amp;rdquo;&lt;/li&gt;
&lt;li data-end=&quot;2314&quot; data-start=&quot;2290&quot;&gt;XY/XZ/YZ는 각각 공간 구조를 잡음&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;그래서 이 세 항을 더하면&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 시간에 따른 이동 ( Translation )&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 시간에 따른 형태 변화 ( deformation )&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;이 3가지를 다른 관점에서 커버 가능하다고 합니다.&amp;nbsp;&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;HexPlane 은 결국 4D field 를 low-rank 의 곱의 합으로 근사할 수 있게 된 것이다.&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;&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;743&quot; data-origin-height=&quot;416&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bmQdlE/dJMcab36xpO/SEs0imHyeiLHrIUdglFkK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bmQdlE/dJMcab36xpO/SEs0imHyeiLHrIUdglFkK1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bmQdlE/dJMcab36xpO/SEs0imHyeiLHrIUdglFkK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbmQdlE%2FdJMcab36xpO%2FSEs0imHyeiLHrIUdglFkK1%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;743&quot; height=&quot;416&quot; data-origin-width=&quot;743&quot; data-origin-height=&quot;416&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;743&quot; data-origin-height=&quot;534&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/boEiu9/dJMcagj3atd/l8zdVmL9ofxSFnGmiOPjF1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/boEiu9/dJMcagj3atd/l8zdVmL9ofxSFnGmiOPjF1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/boEiu9/dJMcagj3atd/l8zdVmL9ofxSFnGmiOPjF1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FboEiu9%2FdJMcagj3atd%2Fl8zdVmL9ofxSFnGmiOPjF1%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;743&quot; height=&quot;534&quot; data-origin-width=&quot;743&quot; data-origin-height=&quot;534&quot;/&gt;&lt;/span&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. XY Plane 에 무엇이 들어가 있는가 ?&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;XY Plane 에는 &quot;(x,y)&amp;nbsp; 위치에 필요한 latent vector &quot; 가 들어간다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;밀도랑 rgb 예측하기 위해 학습되는 latent 입니다.&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;그래서 조금 헷갈렸던게 왜 움직이는데 xy 는 고정인가 ? 고민을 좀 했었는데&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;xy 에는 시간축이 없어서 &quot; 모든 시간에 공유되는 basis / 공간 구조 힌트&quot; 역할을 하게 됩니다.&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;- xy 는 좀 폭넓게 ? 그니까 시간에 따라 덜 바뀌거나 혹은 공통의 패턴을 담을 확률이 높습니다.&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;그래서 xy plane 은 좀 static 을 담는다 ? 아니면 학습 과정에서 이런 역할분담이 자연스럽게 생긴다 ? 정도로 이해하면 될 것 같습니다.&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;cf. 4dgs 에서 좀 역동적인 동작이 어려운 이유가 여기 있을 수도 있겠네요&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이거 관련해서 좀 더 리서치를 잠깐 해봤는데 ( context 가 좀 섞여서 4dgs - hexaplane 이 조금 잘못 섞여서 리서치한것 같다 )&amp;nbsp;&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;일단&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;&quot; 다만 &amp;ldquo;XY plane이 시간축이 없어서 static이라서&amp;rdquo;가 원인이라기보단, **(HexPlane/K-Planes 계열의) plane factorization 자체가 갖는 &amp;lsquo;저랭크(low-rank) 가정&amp;rsquo;**이 강한 동작(복잡한 non-rigid, 빠른 motion, topology change 등)에서 병목이 되는 경우가 많습니다. 그리고 &lt;b&gt;여러 4DGS(=dynamic Gaussian splatting) 방법들이 효율 때문에 비슷한 &amp;lsquo;저랭크/기저 공유&amp;rsquo; 형태의 motion parameterization&lt;/b&gt;을 쓰기 때문에, 질문하신 직관이 꽤 맞닿아 있어요 &quot;&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 일단 low rank 가정이 역동적인 동작에 불리할 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p 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;일단 부드러운 움직이면 low rank 도 잘맞느는데&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;동작이 복잡해지면 rank 가 커져야한다. rank 가 부족하면 결국 잘 안된다.&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 data-ke-size=&quot;size16&quot;&gt;( Spacetime Gaussian Feature Splatting for Real-Time Dynamic View Synthesis )&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Grid like 표현 방식이 장면의 구조나 움직임에 유연하게 적응하지 못하고 디테일이 부족하다.&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;gt; 3dgs 에서 temporal opactiy 랑 polynomial 기반 움직임 회전 추가&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;2. 그래서 4DGS 에서도 비슷한 이유로 나타는 건가 ?&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;u&gt;&lt;b&gt;&amp;lt; Deformable 3D Gaussians for High-Fidelity Monocular Dynamic Scene Reconstruction &amp;gt;&amp;nbsp;&lt;/b&gt;&lt;/u&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;-&amp;nbsp; Canonical space + deformation field 개념 도입해서 해결 ( 그니까 Plane 을 나눈 부류가 아님 )&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;( Canonical space )&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 기본형태인 3DGS 세트 정의&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;(Deformation Field )&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 시간 t 가 주어졌을떄 공간에 있는 가우시안들이 어떻게 움직이고 변형되어야 하는지 계싼하는 MLP&amp;nbsp;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;889&quot; data-origin-height=&quot;261&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/RYTM0/dJMcac2YXEa/KmYYt5kWIPeFLWCfjFH330/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/RYTM0/dJMcac2YXEa/KmYYt5kWIPeFLWCfjFH330/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/RYTM0/dJMcac2YXEa/KmYYt5kWIPeFLWCfjFH330/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRYTM0%2FdJMcac2YXEa%2FKmYYt5kWIPeFLWCfjFH330%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;889&quot; height=&quot;261&quot; data-origin-width=&quot;889&quot; data-origin-height=&quot;261&quot;/&gt;&lt;/span&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;&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2593&quot; data-start=&quot;2412&quot;&gt;&lt;b&gt;Spacetime Gaussian Feature Splatting (CVPR 2024)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2593&quot; data-start=&quot;2473&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2593&quot; data-start=&quot;2473&quot;&gt;HexPlane 같은 grid/plane factorization이 &lt;b&gt;동적 구조에 잘 적응 못 해 디테일을 방해&lt;/b&gt;할 수 있다고 한계를 언급.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;2856&quot; data-start=&quot;2595&quot;&gt;&lt;b&gt;SC-GS (CVPR 2024)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2856&quot; data-start=&quot;2625&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2720&quot; data-start=&quot;2625&quot;&gt;동적 장면에서 motion을 **sparse control points(기저)**로 두고, &amp;ldquo;동작이 compact subspace로 표현 가능&amp;rdquo;하다는 관찰을 사용.&lt;/li&gt;
&lt;li data-end=&quot;2856&quot; data-start=&quot;2724&quot;&gt;동시에 &lt;b&gt;low-rank assumption 때문에 high-rank dynamic scenes에서 underperform&lt;/b&gt; 가능함을 관련연구 문맥에서 언급.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;3029&quot; data-start=&quot;2858&quot;&gt;&lt;b&gt;MotionGS (NeurIPS 2024)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;3029&quot; data-start=&quot;2894&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;3029&quot; data-start=&quot;2894&quot;&gt;기존 동적 Gaussian 계열이 &lt;b&gt;명시적 motion 제약이 부족해 최적화가 어렵고 성능 저하&lt;/b&gt;가 난다고 지적하고, flow 기반 motion prior로 보강.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;3152&quot; data-start=&quot;3031&quot;&gt;&lt;b&gt;4D Gaussian Splatting (CVPR 2024)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;3152&quot; data-start=&quot;3077&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;3152&quot; data-start=&quot;3077&quot;&gt;per-frame 3DGS 대신 4D를 통으로 다루는 방향.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;3316&quot; data-start=&quot;3154&quot;&gt;&lt;b&gt;CoDa-4DGS (ICCV 2025)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;3316&quot; data-start=&quot;3188&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;3316&quot; data-start=&quot;3188&quot;&gt;&amp;ldquo;복잡하고 highly dynamic&amp;rdquo;한 환경(자율주행)을 겨냥해 &lt;b&gt;context + temporal deformation awareness&lt;/b&gt;로 보강.&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;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. ZT Plane&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마찬가지로 grid 형태의 latent feature 가 들어갑니다.&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;ZT 는 그러면 z 축 위치 별로 시간이 바뀌면서 어떻게 장면이 달라지는지에 대한 느낌일 것이구요&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;그래서 위 그림을 보면&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;xy : 육안으로 봐도 좀 그럴듯한 feature 모양이라면&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;zt : 띠 모양 형태로 시간에 따라서 위치가 이동하는 ( 시간축에서 z 의 이동 . )&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;&amp;lt; Gating &amp;gt;&amp;nbsp;&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;341&quot; data-origin-height=&quot;68&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/do27aw/dJMcafMeA7G/cfxiotK4rLgJYdULp8F3JK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/do27aw/dJMcafMeA7G/cfxiotK4rLgJYdULp8F3JK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/do27aw/dJMcafMeA7G/cfxiotK4rLgJYdULp8F3JK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdo27aw%2FdJMcafMeA7G%2FcfxiotK4rLgJYdULp8F3JK%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;341&quot; height=&quot;68&quot; data-origin-width=&quot;341&quot; data-origin-height=&quot;68&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런식으로 (x,y) - (z,t ) 를 곱하게 되는 형태가 된다.&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;만약에 같은 (x,y) 라도 , f(z,t) 가 바뀌면 결과값이 달라지는데&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;if&amp;nbsp; f(z,t) = 0&amp;nbsp; -&amp;gt; 결과값도 0&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 ZT 가 이시간 , 이 Z 축에서는 이 채널의 ON/OFF 를 적용하는 효과를 가지게 된다.&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;그래서 좀 더 쉽게 이야기 해보면&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;지금 시간 t 에서 Z 가 이 위치일때 , XY ( 단면 ) 을 키자 . ( 공간 X 위치 ) 를 자연스럽게 표현하게 된다.&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;lt; 그러면 4DGS 에서는&amp;nbsp; ? &amp;gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-end=&quot;410&quot; data-start=&quot;391&quot; data-ke-size=&quot;size23&quot;&gt;HexPlane ( field )&amp;nbsp;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;535&quot; data-start=&quot;411&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;503&quot; data-start=&quot;411&quot;&gt;물어보는 방식: (x,y,z,t) 좌표를 query &amp;rarr; &lt;span&gt;&lt;span&gt;&amp;sigma;,rgb&lt;/span&gt;&lt;/span&gt;를 예측 &amp;rarr; ray marching/volume rendering&lt;/li&gt;
&lt;li data-end=&quot;535&quot; data-start=&quot;504&quot;&gt;핵심 자원: 필드 파라미터(plane/MLP)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;555&quot; data-start=&quot;537&quot; data-ke-size=&quot;size23&quot;&gt;4DGS&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;676&quot; data-start=&quot;556&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;614&quot; data-start=&quot;556&quot;&gt;그리는 방식: Gaussian들을 화면에 투영(splat) &amp;rarr; alpha compositing&lt;/li&gt;
&lt;li data-end=&quot;676&quot; data-start=&quot;615&quot;&gt;핵심 자원: Gaussians(중심/공분산/opacity/color) + &amp;ldquo;시간에 따른 변화 모델&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;691&quot; data-start=&quot;678&quot; data-ke-size=&quot;size16&quot;&gt;이라고 합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;691&quot; data-start=&quot;678&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;793&quot; data-origin-height=&quot;270&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uX34p/dJMcaiPEMVD/2UsMv8orTbjk2e2VZeoN41/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uX34p/dJMcaiPEMVD/2UsMv8orTbjk2e2VZeoN41/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uX34p/dJMcaiPEMVD/2UsMv8orTbjk2e2VZeoN41/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuX34p%2FdJMcaiPEMVD%2F2UsMv8orTbjk2e2VZeoN41%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;793&quot; height=&quot;270&quot; data-origin-width=&quot;793&quot; data-origin-height=&quot;270&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1029&quot; data-start=&quot;855&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1029&quot; data-start=&quot;855&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1029&quot; data-start=&quot;855&quot; data-ke-size=&quot;size16&quot;&gt;결론적으로 output 값이 좀 다른데&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1029&quot; data-start=&quot;855&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1029&quot; data-start=&quot;855&quot; data-ke-size=&quot;size16&quot;&gt;위치변화 , 회전변화 , 스케일 변화 이걸 합쳐서 변형된 Gaussian 을 만듭니다.&lt;/p&gt;
&lt;p data-end=&quot;1029&quot; data-start=&quot;855&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1029&quot; data-start=&quot;855&quot; data-ke-size=&quot;size16&quot;&gt;참고로 HexPlane 방법말고 deformation 방법도&amp;nbsp; 4dgs 에서 주로 쓰이고는 합니다 ( 2가지 모두 자주 사용 )&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1029&quot; data-start=&quot;855&quot; data-ke-size=&quot;size16&quot;&gt;deformation 은 HexPlane 보다는 연산량이 많지만 보다 더 다이나믹한 움직임을 표현할때 자주 쓰이는 것 같아요&amp;nbsp;&lt;/p&gt;</description>
      <category>ai</category>
      <author>Kim_sang_hyeob</author>
      <guid isPermaLink="true">https://ksh0416.tistory.com/153</guid>
      <comments>https://ksh0416.tistory.com/153#entry153comment</comments>
      <pubDate>Sat, 31 Jan 2026 23:58:49 +0900</pubDate>
    </item>
    <item>
      <title>Diffusion Policy 발표자료</title>
      <link>https://ksh0416.tistory.com/149</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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;fileblock&quot; data-ke-align=&quot;alignCenter&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/b7mQaD/dJMcajgt1Mp/36NtPhZ8iCzwijH4E2KWXK/Diffusion%20Policy%20%28%20Notion%20%EC%A0%95%EB%A6%AC%EB%B3%B8%20%29.pdf?attach=1&amp;amp;knm=tfile.pdf&quot; class=&quot;&quot;&gt;
    &lt;div class=&quot;image&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;desc&quot;&gt;&lt;div class=&quot;filename&quot;&gt;&lt;span class=&quot;name&quot;&gt;Diffusion Policy ( Notion 정리본 ).pdf&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;2.98MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&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;&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;fileblock&quot; data-ke-align=&quot;alignCenter&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/bmKmiZ/dJMb9953SQa/KVAsFqzngXhnoNYeM1JDE1/diffusion%20policy%20_%20%EB%B0%9C%ED%91%9C%EC%9A%A9.pptx?attach=1&amp;amp;knm=tfile.pptx&quot; class=&quot;&quot;&gt;
    &lt;div class=&quot;image&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;desc&quot;&gt;&lt;div class=&quot;filename&quot;&gt;&lt;span class=&quot;name&quot;&gt;diffusion policy _ 발표용.pptx&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;2.27MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&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;( 카드 뉴스 )&amp;nbsp;&lt;/p&gt;</description>
      <category>Paper</category>
      <author>Kim_sang_hyeob</author>
      <guid isPermaLink="true">https://ksh0416.tistory.com/149</guid>
      <comments>https://ksh0416.tistory.com/149#entry149comment</comments>
      <pubDate>Wed, 24 Dec 2025 21:50:35 +0900</pubDate>
    </item>
  </channel>
</rss>