長日智能股份有限公司
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights New
    • Engagement control
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Note Insights Versions and GitHub Sync Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Engagement control Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       Owned this note    Owned this note      
    Published Linked with GitHub
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    使用 Python 編寫 CUDA 核心的 1,001 種方法 [S72449] ![image](https://hackmd.io/_uploads/SJw81Ch2yx.png) Leo Fang,Python CUDA 技術主管, NVIDIA 您必須編寫一個 CUDA 核心。你知道不離開 Python 就可以做到這一點嗎?我們將探索使用 Python 編寫 CUDA 核心的最佳實踐,使開發人員能夠充分利用 GPU 加速的潛力。清楚了解 CUDA 核心的結構和功能,學習如何在 Python 應用程式中有效地實現它們。我們將介紹實現高效能的關鍵概念,包括記憶體管理、執行緒組織和最佳化技術。 重要提示:由於座位數量有限,強烈建議提前到達。與會者將以先到先得的原則入場。 關鍵要點: 探索 CuPy、Numba、cuda.cooperative 和 nvmath.device 等技術,讓您能夠以 Python 原生方式編寫高效的 CUDA 內核 了解應採用的最佳實務以及應避免的常見陷阱 學習使用 Python 優化和調試 GPU 程式碼的策略 獲得使用 Python 編寫強大的 CUDA 核心所需的技能和見解,使您能夠加速應用程式並提高專案的運算效率 主題:開發和最佳化 - 程式語言/編譯器 行業細分:所有行業 技術等級:技術 - 中級 目標對象:開發人員/工程師 所有目標受眾類型:開發人員/工程師 3 月 20 日,星期四 凌晨 2:00 - 凌晨 2:40 中部標準時間 AI逐字稿 這是一個系列講座。我們今年正在為GTC(GPU Technology Conference)準備這些內容。這次的講座是關於Python的演講。這已經是連續第三次的講座了,我們一直在探討所有與Python相關的事物。而這場演講特別聚焦於如何編寫內核(kernels)。到目前為止,我相信在座的大多數人都已經看過那些關於Python技術棧(Python stack)的圖表,這些圖表涵蓋了Python程式碼中的所有層面——從運行時(runtime)編譯器無法提供的功能,一直到支援設備層(device layer),再到框架(frameworks)和領域特定語言(DSLs,Domain-Specific Languages)。這意味著什麼呢?這意味著我們希望能夠全面支持整個Python生態系統(Python ecosystem)。對Python的使用者和開發者來說,這具體代表什麼呢?就是這個圖表中的所有元素應該都能夠互相混合使用,就像你所期待的那樣,不再受限於單一的Python套件(packages)。你應該能夠同時改進多個Python套件,並在你的使用者程式碼(user code)中將它們結合起來使用。這是我們正在努力實現的一個重要使命。 在這場演講中,我將特別帶領大家從技術棧的基礎開始,一步步了解如何以不同的方式開發內核。為了做到這一點,我想使用一個教學範例來說明,也就是「片段歸約」(segment reduction)。這個問題是用來展示我們如何編寫內核,以不同的方式解決同一個問題,這一點非常重要。問題的陳述如下:假設我們有一個一維緩衝區(1D buffer)或是陣列(array),裡面存放了許多不同的片段(segments),這些片段分別由紅色、藍色、黃色等顏色標記。我們希望對每個不同的片段進行歸約運算(reduction)。例如,紅色片段的所有數字加總起來得到10;藍色片段加總起來得到26,以此類推。這就是我們的問題陳述。 假設你之前沒有聽過我們今年提供的其他教育講座或這些新材料,你可能會好奇:我該如何用CUDA(Compute Unified Device Architecture)來實現這個功能呢?你可能會試著參考一些線上資源,然後嘗試用C++自己編寫內核程式碼。正如你稍後會看到的,這並不是現在唯一的方法。但假設我們真的採用這種方式,我們會怎麼做呢?我們會先引入Thrust庫(Thrust library)來填充輸入向量(input vectors),然後定義問題的規模(problem size),並在設備端(device)準備好所需的緩衝區(buffers)。接著,我們會啟動自己編寫的內核來執行計算,在內核運算完成後進行同步(synchronize),然後將資料從設備端拷貝回主機端(host),以便進行後處理(post-processing)或驗證(verification)等工作。 所以,真正的問題在於:我們該如何編寫這個內核呢? 好吧,嗯?所以呢,有很多方法可以做到這一點。這是其中一種方式,我們可以將一個片段(segment)分配給一個區塊(block)。比如說,如果我們有3個片段,我們就啟動3個區塊;如果有100萬個片段,我們就啟動100萬個區塊,以此類推。為了讓這一切盡可能通用,我將這個內核(kernel)寫成了一連串的模板內核(template kernel)。這樣我就可以對輸入資料型別(input data types)、偏移型別(offset types)進行模板化處理。同時,我還能將區塊大小(block size)和每個執行緒處理的項目數(items per thread)編碼為模板參數(template parameters),這樣它們就可以在編譯時(compile time)指定,並由編譯器用來協助優化(optimization)。為了簡單起見,在這場演講中,我假設片段大小是我們指定的區塊大小的倍數。 那麼我們要做什麼呢?我們首先分配共享記憶體(shared memory),因為我們希望區塊中的所有執行緒(threads)能夠彼此通訊並在後續協作。接下來,我們會計算後續所需的索引(indexes),也就是我在這個區塊中作為一個執行緒的位置,以及我在整個片段集合中的片段位置。有了這兩個數字,我們就可以計算偏移量(offset),並為每個執行緒載入指定的資料,將資料載入到暫存器(register)中,然後進行部分聚合(partial aggregation)。因為我們假設片段的大小可能遠大於區塊大小,所以我們需要透過這個區塊來覆蓋整個片段。完成這一步後,每個執行緒都會有自己的部分聚合結果。接著,我們將這些結果寫入共享記憶體,並對區塊中的所有執行緒進行同步(synchronize)。 最後,我們使用共享記憶體中的資料進行部分歸約(partial reduction)。基本上,這意味著區塊的一半會使用自己擁有的資料,以及區塊另一半的資料,進行計算並寫回共享記憶體。然後,區塊的四分之一會做同樣的事情,八分之一也是如此。最終,只有一個執行緒會產生我們所需的最终結果,並將其寫回全域記憶體(global memory)。對吧?我們稍後會再回顧這個圖表。 這是一個教學範例,它確實解決了問題。它的表現還算不錯,對於與效能(performance)相關的講座來說也沒什麼問題。如果你想了解更多關於效能的內容,可以參考我同事喬治(George)的演講,那是今天稍早之前的場次。但在這裡,你會發現,要編寫這樣的內核,你需要了解很多東西,比如CUDA程式模型(CUDA programming model)、執行緒與記憶體層次結構(thread and memory hierarchy),以及GPU架構(GPU architecture),才能讓它具備高效能。此外,你還需要在這些硬體機制(GPU machinery)之上表達你的演算法(algorithm),以便在內核中完成計算。最後,隨著你的程式規模擴大…… 這不僅僅是一個玩具程式碼(toy code)。你會想要了解C++的完整工作流程(C++ completion workflow),這樣你才能知道如何建立你的專案(project),並將它交付給你的使用者(users)。這需要學習的東西真的很多。但我想強調一點:我不會深入探討這些內容的效能細節(performance details),因為這些已經被我同事們在許多精彩的演講中涵蓋了。他們從程式設計模型(programming model)中學到的東西是可以跨語言轉移的(transferable across languages)。所以無論你是從C++講座還是Python講座中學到這些,只要你掌握了它們的運作原理,這些知識都能通用,對吧? 如果你是一位追求效率的開發者(developer),並且習慣編寫C++程式碼,就像我剛才展示的那樣,那麼這對你來說很棒。我們還有更多進階的系列講座(sequence talks),今天稍早由我的同事喬治(Georgie)和普萊斯(Price)已經講過了。如果你還沒參加,可以去看看錄影(recording)。對吧?這場演講的重點是,我們希望保持高效(productive),並且希望留在Python的環境中。但問題來了:留在Python中如何幫助你,讓你的開發生活(developed life)更輕鬆呢?對吧? 我在這裡要對比的是典型的Python專案工作流程(Python project workflow),它允許使用者內核(user kernel)在GPU上從Python端啟動(launched on GPU)。這樣就不需要依賴那些傳統的NVCC機制(NVCC machinery),這些機制通常仰賴主機編譯器(host compiler),像是GCC或MSVC,這取決於你是使用Linux還是Windows。我們必須提供多種不同的方式,將你的使用者程式碼(user code)或使用者內核編譯成可在GPU上執行的機器碼(machine code)。這些黑盒部分(black parts)代表了這樣的機制(machinery)。這些黑盒的實現方式各有不同,在不同的專案中,它們可能是由低階(low-level)技術堆疊(stack)、中間層編譯器(MIR-rated compiler)、優化技術(optimizations),或者第一方編譯器庫(first-party compiler libraries)——像是NVRT、NVLink和NVVM——所混合構成的。 關鍵在於,因為我們有了這些線上編譯(online compilation)或高效編譯機制(cheap completion of machineries),我們不再需要依賴C++的主機編譯器。這對於交付你的Python專案來說非常重要,因為你不會想要要求使用者預先安裝GCC或MSVC——這些東西不像應用程式(app)那樣可以輕鬆安裝(installable),而且安裝和設定工作環境(working environment)的過程一點也不有趣。為了進一步說明這個問題,舉個簡單的例子:假設我們剛才寫了一個內核,作為一個函式庫開發者(library developer),我們希望支援多種資料型別(data types)。我之前提到過,我們的內核已經足夠通用,可以支援片段中儲存的雙精度浮點數(double)、單精度浮點數(float)或整數(integer)值。 好吧,所以你可能會像右邊這樣編寫分派器(dispatcher),試圖根據容器型別(container type)分派到不同的資料型別(data types)。但這意味著什麼呢?這意味著所有這些型別都必須在你的專案編譯時(compile time)或構建時(build time)預先實例化(pre-instantiate)。對吧?相比之下,在Python中你會怎麼做呢?通常,你只會實例化你需要的東西,並且只編譯你需要的部分,這是由輸入參數(input arguments)決定的。比如說,如果你提供給內核(kernel)一個陣列(array),它是float64型別,那麼我們就只會編譯一個針對float64的內核,以此類推。這種動態編譯(decompletion)讓我們能夠減少二進位檔案的大小(binary size),並縮短編譯時間(compile time),因為你不需要一次性地構建整個世界(whole world)。你可以根據需求逐步構建你的內核,然後快取最終的輸出(cache the final output)。 為了說明這一點,我想使用CUDA Core(CUDA Core),這是我們的一個新專案,來強調這個觀點。CUDA Core 是我們從Python內部存取CUDA API(CUDA API)功能的新方式。它為你提供了所有常見的程式碼物件(code objects),例如初學者會用到的串流(stream)、事件(event)、設備(device)和記憶體分配(memory allocation)。除此之外,我們還支援所有線上編譯工具鏈(online compiler toolchains),包括NVRTC、NVJLink,以及後來的NVVM。這樣你就可以使用CUDA Core的功能來編寫和編譯你的程式碼。這裡右邊展示的是,我剛才在頭檔案中寫的那段程式碼,我可以直接將它作為Python字串(Python string)載入。對吧?然後我可以指定內核的模板特化(kernel specialization template),比如我想實例化一個適用於float型別、特定區塊大小(block size)和每個執行緒處理的項目數(items per thread)的內核。接著,我可以編譯這個特定的內核,將它載入到設備(device)並在GPU上啟動它。我甚至可以與參考實作(reference implementation)——比如從CUDA中來的——進行比較,以檢查結果。 這是一個非常棒的機制,因為這意味著所有那些C++相關的編譯資訊,例如模板參數(template parameters)、常數(constants)等等,現在都變成了Python的執行時(runtime)資訊,可以在執行時決定,而且完全在Python環境中實現。所以,在這個例子中,所有C++的模板內核(template kernels)都變成了執行時實例化的東西。即使你是一位C++開發者(developer),我也不建議你開發多個內核。我強烈推薦你試試在Python中開發,這樣可以快速迭代(iterate)。一旦你完成了程式碼,你可以將它移回你的C++程式碼庫(codebase)。正如我所說的,它涵蓋了大量的CUDA功能(CUDA functionality),我們正在擴展這個專案。目前,它已經支援了多種平台,包括Linux和Windows等所有主流執行環境(runtimes),並且支援最新的CUDA主要版本(major versions),目前是11和12。 但是,如果你看看這段程式碼,對吧?我們這裡有一群Python開發者,我們真的不想寫C++,如果可以避免的話。對吧?因為它有很多需要學習的東西。如果可能的話,我們真的更希望留在Python環境中。那麼,我們該怎麼做呢? 所以,這裡我要介紹一種在Python中編寫CUDA內核(CUDA kernels)的方法,那就是使用Numba(Numba code)。這是一個開源專案(open source project),由Anaconda團隊(Anaconda team)支持,並得到了Numba團隊和相關社群的協助。我們正在與Numba團隊密切合作,將CUDA目標(CUDA target)從上游的Numba專案中獨立出來,這樣可以減輕Numba團隊的維護負擔(maintenance burden),同時加速這個專案的發展,並將它與Numba的發佈週期(release cycle)解耦(decouple)。這裡我展示了一個簡單的程式碼範例,在C++中,它基本上是取一個輸入陣列(input array),將每個元素平方(square),然後將結果寫入輸出陣列(output array)。同樣的邏輯,在下面的範例中,我們可以看到使用Numba可以用更清晰的語法(cleaner syntax)來編寫相同的程式碼。Python的語法中包含了一些特性,例如使用「**」運算符,這在標準Python中表示二次方(power of two)。 有了Numba程式碼(Numba code),讓我們重新審視剛才的程式碼。我們之前說過,這段程式碼很難寫,因為你需要了解很多東西,才能編寫它、檢查效能(performance)、驗證正確性(correctness)等等。那如果我們用Numba CUDA重寫這段程式碼呢?它會是什麼樣子?嗯,這就是結果,這就是它的樣子。我剛才提到,所有那些模板參數(template parameters)在Python中變成了執行時參數(runtime parameters)。所以你可以在啟動內核之前,先明確指定區塊大小(block size)和每個執行緒處理的項目數(items per thread),然後在內核中使用它們。但除此之外,邏輯本身並沒有太大改變,你仍然需要載入資料(load data)、執行計算(computation),並知道如何編寫平行執行緒歸約(parallel thread reduction)等等。 那麼,我們完全擺脫C++了嗎?絕對是的。這現在是一個純Python範例(pure Python example)。你可以將這個內核插回我剛才展示的CUDA Core範例中,這樣就完全是Python實現了。但這是否意味著它更容易編寫呢?不一定。就像我說的,你還是需要了解很多東西,比如GPU架構(GPU architecture)等等,才能把程式碼寫得漂亮又乾淨。特別是,在這段程式碼中,有兩部分我真的很想去除。我希望有人已經幫我完成了這些工作,這樣我就不必自己去搞清楚如何高效載入資料(load perform)。我不想知道如何以高效的方式載入資料(efficient load),甚至是向量化的載入(vectorized load),也不知道如何使用指令級並行(instruction-level parallelism)。同樣的,對於歸約(reduction),我真的不想去學習執行緒歸約(thread reduction)的細節。對吧?那我該怎麼辦呢? 嗯,以前這涉及到將所有這些程式碼編寫為設備函數(device functions),這樣我們就可以把這些邏輯抽象出來,並提供設備函數庫(device function libraries)。但以前這有一個問題。問題在於,我們唯一能支援Python設備函數庫的方式,要麼是透過C++,這帶來了很大的開銷(overhead);我們希望把它放回Python環境中,要麼是將它作為PTX(PTX)格式發佈。但PTX並不支援CUDA次要版本(minor version)的廣泛相容性(virgin compatibility)。所以你會遇到麻煩,這取決於使用者的驅動程式版本(driver version)。它可能無法載入(loadable),也可能無法連結(linkable)。對吧? 從CUDA 12.0版本開始,出現了一個新的函式庫叫做NVJLink(NVJLink),它終於幫我們解決了這些問題。它的邏輯是這樣的:如果你正在發佈設備函數庫(device libraries),無論是用C++還是Python編寫,你會希望將它們編譯成一種叫做LTOIR(LTOIR)的格式。這種格式能被NVJLink識別,NVJLink可以用來將多個部分連結在一起,包括你的使用者內核(user kernel)、使用者設備函數(user device functions),以及第三方或第一方的設備函數庫(third-party or first-party device libraries)。它會將所有這些設備函數連結起來並內聯(inline),這樣就不會有額外的函數呼叫開銷(function call overhead)。這讓我們能夠生成一個效能媲美C++對應版本的內核(kernel)。基本上,這在某種程度上延長了Numba內核(Numba kernel)的生命週期,我的一位同事馬可(Marco)曾經很好地整理了一份說明,解釋了Numba內部的處理流程(internal pipeline)。 現在,我們終於有了一個完整的解決方案,來提供Python的設備函數和設備函數庫(device libraries)。接下來我要給你們看兩個例子。第一個例子是一個新的CUDA Python專案,我們稱它為CUDA Cooperative(CUDA Cooperative)。它基於CUPC(CUPC)這款C++函式庫,提供了一套高效能的C++演算法(algorithms)。我們找到了一個方法,利用這些機制(machinery)把它們整合起來,並讓它們暴露給Numba CUDA的使用者(Numba CUDA users)。你需要做的是,再次指定所有的模板參數(template parameters)和你想要處理的資料型別(type)。然後,你使用這些參數來定義你的載入設備函數(load device function)。這些函數會生成LTOIR格式的程式碼(LTOIR generated)。對於歸約(reduction),我們需要定義二元運算(binary operation)。在這個例子中,它只是簡單的「A + B」。我們希望對某個片段(segment)進行高效能的加總(performance sum),對吧? 有了這個使用者定義的Python函數(user-defined Python function),我們可以在幕後使用工具生成LTOIR(LTOIR),然後生成設備函數(device function)。這讓我們能夠實現一個區塊級的歸約(block-wide reduction)。這樣,我的用戶內核(user kernel),原本在幻燈片上占滿整整一頁,現在只剩下半頁,變得非常乾淨且易於管理。你只需要將資料載入到本地暫存器(local registers),然後準備共享記憶體(shared memory)供演算法使用,接著呼叫區塊歸約(block reduce)來執行區塊級的歸約運算,最後將資料寫回全域記憶體(global memory)。對吧? 這個函式庫(library)目前仍在開發中。我們還沒有推出任何測試版(beta release),但它完全是公開開發的(developed in the public)。所以今天你就可以複製(clone)這個儲存庫(repository),從原始碼(source)構建並試用它。這種方法最棒的特點在於,它不僅支援構建基本的資料型別(data types),像是浮點數(floats)、雙精度浮點數(doubles)等等,還允許支援在Python中部分定義的自訂資料型別(custom data types)和自訂運算子(custom operators)。對吧?因為它會將整個套件(package)編譯成GPU相容的格式。如果你採用這種方式,你會發現這個CUDA方法的專案體積非常小。而且它是開源的(open source)。對吧?在這個過程中,你可以使用CU(CUDA Utility)提供的區塊載入(block load)和區塊歸約(block reduce)功能。 請給我們回饋(feedback),我們會在封裝(packaging)和相關細節上繼續努力,讓它更容易安裝、更方便使用。但最重要的是,我們想知道你希望從這個函式庫中獲得什麼,你需要什麼功能。請試試看吧!這裡有一些觀察。剛才我給你們看過一個圖表,裡面有黃色的箭頭表示多個執行緒(threads)協同工作,最終產生一個結果。如果你分解這些步驟,你會發現有些是並行步驟(parallel steps),有些是每個執行緒獨立執行的序列步驟(serial steps)。所有執行緒是並行運行的(run in parallel),但最終它們需要一起合作,才能生成最終輸出(final output)。這是某些部分的特性(quality)。 這意味著,當你編寫我們所謂的CUDA單指令多資料(SIMD, Single Instruction, Multiple Data)內核(CUDA SIMD kernel)時,這種程式模型(programming model)是我們在Numba CUDA和C++端使用的。當你編寫這樣一個簡單的內核時,你仍然需要協作API(cooperative APIs)來幫助你生成最終輸出,並執行一些非平凡的任務(nontrivial tasks),比如掃描(scan)、歸約(reduction),甚至更高級的操作(made more)。對吧? 說到矩陣乘法(matrix multiplication),這是看待同一個問題的另一種方式,並探索不同的機制(machinery)。片段歸約(segment reduction)其實可以看作是一個矩陣向量乘法(matrix-vector multiplication)。如果你把這些片段範圍(range of segments)想像成一個二維矩陣(2D matrix),然後乘以一個全為1的向量(vector of ones),那麼這就變成了同一個問題,只是以不同的方式表述。但為什麼要這樣思考呢?對吧?我們之所以想用這種方式思考,是因為它讓我們能夠探索不同的機制和不同的設備函數庫(device libraries)。在這個例子中,我使用了NVMath Device(NVMath Device)來在我的Numba CUDA內核(Numba CUDA kernel)中執行矩陣乘法(matrix multiplication)。 具體來說,過程是這樣的:我先宣告區塊大小(chunk size)和陣列的資料型別(data type of array)。然後,我使用NVMath Device的矩陣乘法功能(matrix multiplication function)來宣告一個最小的設備函數(minimal device function)。這個函數會告訴我需要在內核中分配的共享記憶體大小(shared memory size)。於是,在我的內核中,我可以像之前處理矩陣乘法一樣,分配共享記憶體(shared memory)給A、B、C三個變數,並計算C = A × B。對吧?接下來,我們的矩陣A會從由多個片段組成的二維矩陣中載入資料(load data)。而對於矩陣B,你甚至不需要載入任何東西。對吧?如果我們事先知道這個向量全都是1,那麼我們可以直接在共享記憶體中將它初始化為全1(initialize with ones),根本不需要在全域記憶體(global memory)中實體化這個陣列(materialize the array)。 然後,我們對區塊中的所有執行緒(threads in the block)進行同步(synchronize),因為我們正在準備共享記憶體。接著,我們呼叫這個矩陣乘法API(matrix multiplication API)來計算C = A × B。計算完成後,我們再次同步。最後,我們將共享記憶體中的C資料寫入輸出陣列(output array)。這種方式讓我們能以不同的角度表達問題,並利用矩陣乘法的機制來計算相同的問題。這裡的重點是,它在幕後使用了張量核心(tensor cores)來進行計算(computation)。 我們已經看過很多這樣的協作案例(cooperative cases)。矩陣乘法是協作的,加總(sum)也是協作的。所有的執行緒都需要參與其中,才能產生最終結果(final result)。有了這些理解,我們正在引入一個新的程式設計模型(programming model),叫做CUDA Tile(CUDA Tile)。這個模型內建了協作的本質(cooperative nature)。我們不再單獨控制和管理每個執行緒(individual threads),而是控制我們稱之為「瓦片區塊」(tile block)的單位。每個瓦片區塊會將一塊資料(chunk of data)載入到暫存器(registers)中。然後,我們對這些載入的瓦片(loaded tiles)執行非純量運算(non-scalar operations)。你可以執行像A + B這樣的運算,它會對兩個瓦片中的所有元素進行逐一加總(element-wise summation)。 然後我們將結果全部儲存回全域記憶體(global memory)。這種方式讓你可以用非常簡潔的三行程式碼來處理這個特定的案例:載入資料(load)、沿著某個軸進行加總(sum over the axis),然後將最終的瓦片(tile)儲存回去。關於更多與瓦片(tile)相關的講座,我的同事史蒂芬·瓊斯(Steven Jones)在昨天的演講中介紹了CUDA的新功能。如果你有興趣,請務必去看看。 這是我們提出的新舊程式設計模型(programming model)的對比。兩者都受到支援。CUDA Tile(CUDA Tile)是CUDA的擴展,它讓你可以將執行緒計算邏輯(thread multiplication logic)與資料載入邏輯(data loading logic)分開。這樣你就不需要控制所有的個別執行緒(individual threads),也不用擔心如何進行指標運算(pointer arithmetic)、如何計算全域陣列的偏移量(offset into a global array)等等,因為這些事情都由編譯器(compiler)替你處理。正如我之前說的,協作的本質(cooperative nature)非常重要。有了這種程式設計模型,基本上所有的運算都是非純量的(non-scalar)。這些瓦片(tiles)可以被視為瓦片陣列(tile arrays),它們只是內核(kernel)中的陣列。這種方式讓你可以表達我剛才提到的所有想法,比如掃描(scan)、原地計算(compute in place)和矩陣乘法(matrix multiplication)。對吧?這讓你在CUDA內核中可以編寫非純量的程式碼(non-scalar code)。 今年晚些時候,我們將釋出CUDA Tile(CUDA Tile),你就可以試用它了。之前我們展示了C++和Numba程式碼(Numba code)中的平方內核(square kernel),但現在有了這個瓦片程式設計模型(tile programming model),我們可以用同樣的方式做到這一點。我們可以從全域記憶體載入資料(load data from global memory),然後計算平方(square),——抱歉,不是平方根(square root),是平方——然後將輸出的瓦片(output tile)寫回全域記憶體。 對於熟悉NVIDIA Warp(NVIDIA Warp)的人來說,NVIDIA Warp 是一個可微框架(differentiable framework),讓你能為幾何模擬(geometric simulations)、空間計算(spatial computing)和AI工作負載(AI workload)編寫內核。這個新的Numba庫Warp(Warp library)的核心在於,當你編寫內核時,它有能力為你合成反向模式(reverse mode)的自動微分內核(auto-differentiable kernels)。所以當你在螢幕上編寫這樣的內核時,它會為你生成一個反向內核(backward kernel),讓你能直接將它插入到你的機器學習(machine learning)或模擬工作負載(simulation workloads)中,然後自動提供反向計算(backward computation)。這樣你就不需要自己準備這些東西了。最近,Warp也引入了這個新的瓦片程式設計模型(tile programming model),讓你可以在Warp內核中編寫類似的瓦片程式碼(tile-like code),這和我剛才講的內容幾乎一樣。請去看看吧!Warp現在已將許可證更改為Apache 2.0(Apache 2.0),並在GitHub上開源(open source)。對吧? 我之前提到過張量核心(tensor cores),對吧?我們讓Python能夠利用張量核心。但如果你是個追求極致的專家(ninja),你可能會想要完全掌控張量核心。卡爾斯(Carles)的團隊今年也將宣布對CuPy(CuPy)的Python支援,讓你可以直接在Python程序中編寫CuPy的領域特定語言(DSL, Domain-Specific Language)。這樣,你就能完全存取所有底層功能(APIs),控制張量核心,並編寫出極速內核(speed-of-light kernel),從我們的GPU中榨取出最大的效能(maximum performance)。這裡最好的部分是,因為不再有C++相關的機制(C++ machinery),也不需要處理和編譯C++模板(C++ template processing and compiling),這大幅降低了編譯時間(compiler time)。編譯速度變得非常快,讓你能在Python中快速且高效地迭代你的內核(iterate over your kernels),同時仍然保持相同的效能。 所以,請去看看吧!CuPy的相關講座將在星期五舉行。你會從CuPy團隊那裡學到更多細節。對吧? 到目前為止,我已經向你們介紹了一些用來編寫內核(kernels)的工具。這些工具目前主要來自NVIDIA,但也有許多社群工具(community tools),它們同樣能讓你表達相同的想法。例如,你可以使用CuPy的歸約內核(CuPy reduction kernel)來編寫相同的片段歸約(segment reduction),或者使用CuPy的API(CuPy API)以CuPy語法(CuPy syntax)編寫一個高效能的內核,這與Numba CUDA(Numba CUDA)的語法非常相似。或者你也可以使用Triton(Triton),對吧?Triton提供了基於區塊的程式設計模型(block-based programming model)。你還可以手動計算指標偏移量(pointer offsets),然後用這種方式編寫內核。你可以用Triton做到同樣的事情。所以,市場上真的有很多工具,無論是第一方(first-party)還是第三方(third-party)的,我們都支援它們。 那麼問題來了:哪個工具是編寫我的內核的最佳選擇呢?對吧?我可以挑選的東西太多了,什麼才是我的最佳解決方案(best solution)?答案當然是「看情況」(it depends)。很遺憾,我無法給你一個簡單明瞭的答案。因為你需要考慮的限制條件(constraints)實在太多了,對吧?比如,如果你已經陷入了依賴地獄(dependency hell),需要解決這個問題,那麼你可能會想要利用現有的套件(existing packages)。有些套件可能已經提供了編寫內核的方法,你或許應該先試試這些。又或者,如果你的支援矩陣(support matrix)很龐大,而某些套件無法涵蓋你想要支援的範圍——比如不同的Python版本、不同的CUDA版本(CUDA versions)、驅動程式版本(driver versions)、作業系統(operating systems),以及CPU和GPU架構(CPU/GPU architectures)——那你也得把這些因素考慮進去。此外,這還取決於你想如何封裝(package)和部署(deploy)你的Python專案,以及你的專案能提供什麼樣的使用者體驗(user experience)。 對吧?也許你的組織或公司對於某些套件有偏好,或者限制了你能使用或不能使用的工具。這些事情也需要納入你的決策考量(decision making)。當然,還有一些效能方面的考量(performance considerations),我今天無法一一涵蓋。但重點是,要選出最佳選擇(best choice),你需要考慮的事情實在太多了。所以,最好的選擇其實是——如果你能完全避免自己編寫內核的話。對吧? 我們想告訴你的是,現在有非常多的函式庫(libraries)和套件(packages)可供使用,它們提供了各種解決方案。或許已經有人考慮過你的問題,並為你打造了一個高效能的解決方案(performance solution)。所以,你真的應該去看看社群(community)裡正在發生什麼,外面有些什麼資源(in the wild)。看看是否有人已經幫你解決了問題,然後直接使用它們,而不是自己從頭編寫一個內核(kernel),因為這是一件非常不簡單的事情(highly nontrivial)。 這是我們創建的一個新專案,我們稱它為CUDA Parallel(CUDA Parallel)。這個專案讓你不需要自己編寫內核,卻仍然能獲得與C++版本(C++ counterpart)相同的功能和效能。在這個例子中,它基於Thrust C++函式庫(Thrust C++ library),讓你能在Python中編寫類似Thrust的程式碼(Thrust-like code),並存取Thrust和CuPy暴露出的高效演算法(period algorithms)。在這種情況下,你需要創建迭代器(iterators),然後以某種方式定義你的問題,將這些迭代器融合到你的問題定義中。最後,你可以在主機端(host)啟動這個演算法(launch the algorithm)。對吧?這個函式庫提供的主機API(host APIs)讓你能編寫相同的內核,並獲得優異的效能。幕後的實現依然基於LTOIR(LTOIR)和NVJLink(NVJLink),為你生成高效的內核。 這是公開開發(open development)的專案,所以請去試試看。我們很快會進行封裝相關工作(packaging-related work),釋出一個版本,讓你更容易安裝(easier to install)。但在那之前,我們還是很想聽聽你的回饋(feedback)。我們剛剛提到過NVMath Python(NVMath Python),它既有設備API(device APIs),也有主機API(host APIs)。所以,我們可以用NVMath或任何這些Python套件來完成相同的矩陣向量乘法(matrix-vector multiplication)。對吧?在這種情況下,你唯一需要付出的代價是,你得在全域記憶體(global memory)中實體化一個全1的向量(vector of ones),這樣才能進行矩陣向量乘法。但或許你的工作負載(workload)中已經有了這個向量。如果是這樣的話,這可能只是一個很小的操作(cheap operation)。 最後,對於那些熟悉Python中陣列程式設計(array programming)的人來說,看看這個問題的定義,甚至是我在某個程式碼片段中展示的驗證程式碼(verification code),你可能已經注意到,這其實就是對二維矩陣(2D matrix)的連續列(contiguous rows)進行加總(sum)。對吧?你可以用一行程式碼完成這件事,就是「xp.sum()」,其中axis設為-1(xp.sum with axis=-1)。對吧?為什麼會這樣呢? 這真的很棒,因為它具有可攜性(portable)。它符合陣列API標準(Array API standard)嗎?因為現在有很多Python陣列函式庫(Python array libraries),像是CuPy(CuPy)、NumPy(NumPy)、JAX(JAX)、Dask(Dask Python),它們都遵循Python的陣列API標準(Python Array API standard)。這意味著,只要你寫了一次程式碼,就可以用不同的陣列函式庫來試試看。你可以把「from cupy import xp」改成「from torch import xp」,然後看看結果如何。這讓你能快速探索(explore)各種不同的函式庫。最後,回到我們最初的C++解決方案(C++ solution),我們真正想做的是用CuPy的設備端片段歸約(CuPy device segmented reduction)來取代那些手寫的內核(handwritten kernels)。 總結來說,我們為你提供了許多工具,讓你能編寫內核(kernels),從而提升生產力(productivity)。你可以在Python中快速迭代(iterate),但仍然保持與C++相同的效能(performance)。對吧?如果沒有現代編譯器技術(modern compiler technologies),像是MIR(MIR)、NVJLink(NVJLink)這些東西,這是不可能的。所以,現在Python設備函數庫(Python device libraries)已經成為現實,我們真的可以發佈Python設備函數庫了。新的CUDA Tile程式設計模型(CUDA Tile programming model)技術更進一步,讓許多協作設備API(cooperative device APIs)成為程式設計模型的一部分。對吧? 但有一個壞消息是,如果你能完全避免自己編寫內核(writing kernels),如果外面已經有現成的解決方案(solution in the wild),你應該先試試看,看看效果如何,再決定是否要捲起袖子(roll your sleeves)自己動手寫內核。所以,根據你的限制條件(constraints)、效能目標(performance targets)、個人喜好(personal tastes)等等,混合搭配(mix and match)這些工具來選擇最適合你的方案。我們在這裡隨時回答你的問題。事實上,今天下午我們會有一場與專家面對面的活動(connect with exposition),讓你能與我們交流。我們可以回答你的問題,提供回饋(feedback)和指引(guidance)。同時,如果你對CUDA Python團隊(CUDA Python team)有任何需求,我們也很想聽聽你的意見。 今年真的很不一樣,因為我們正在打造許多與開發者相關的內容(developer-related content),包括不同的講座(talks)和主題軌(tracks),涵蓋CUDA程式設計(CUDA programming)的各種話題。所以,請現在就去看看。如果你錯過了任何講座,之後都可以觀看錄影(recording)。最後,我想感謝所有的團隊成員。我們有一個很棒的團隊(big routine),多個團隊合作,創造了這些內容,為Python使用者提供了非常棒且友善的解決方案(Python solutions)。我要感謝整個團隊,也感謝你們的聆聽。 講者2:謝謝你,LEO。我們還有時間回答幾個問題。 講者3:在Blackwell中,你們引入了FP4(FP4),這是一種縮放區塊型別(scaled block type)。 講者1:是的。 講者3:我還沒看到有人討論如何在Python中使用它。 講者1:嗯,你指的是MXFP8(MXFP8)吧? 講者3:或者是FP4,或者FP—— 講者1:FP4。 講者3:基本上是一個縮放—— 講者1:比例因子(scale factor)。是的,最近我們推出了一些東西,已經為FP8和MXFP8提供了0.3.0版本的支援(0.3.0 support)。但我認為FP4(FP4)的支援已經在我們的路線圖(roadmap)上了。 講者4:對吧? 講者1:所以我們最終都會實現這個目標。對吧,好吗? 講者3:在另一個版本中,我想看到一個使用它的例子。 講者1:當然可以。 講者2:嗯,有了這個,如果我想在Python中提供我的內核(kernels),然後使用它們並將它們預編譯(pre-compile)或連結(link)到C++或其他環境中,這背後的故事是什麼? 講者1:是的,對。這個問題涉及到你如何在Python中捕捉(catch)這些內核。因為最終你可能會生成PTX(PTX)或CUDA二進位檔案(CUDA binary),對吧?我的建議是直接生成CUDA二進位檔案。但你需要有一個方法來識別這個二進位檔案是對應哪個內核的——抱歉,我的意思是,這個二進位檔案是為哪個內核生成的,對吧?你需要能夠將輸出的成品(output artifact)與你想在C++中替換的內核關聯起來。 講者2:是的,所以…… 講者1:所以你需要有一個方法來識別它。你可以使用驅動程式API(Driver API)將它們載入回來。 講者2:嘿,謝謝你的文件。嗯,另一個在Python中非常受歡迎的函式庫是Triton(Triton)。我想知道你能不能告訴我們CUDA Tile(CUDA Tile)和Triton有什麼不同?比如,它試圖解決什麼問題?它和Triton相比解決了什麼不同的東西? 講者1:嗯,抱歉,你剛才的問題是什麼來著?哪個問題? 講者2:有一個很受歡迎的領域叫做Triton,它就像是讓你把東西寫在資料的瓦片(tiles)上。我想知道CUDA Tile和它有什麼不同? 講者1:哦,我其實不太熟悉那個函式庫。所以我需要查一下,才能給你一個更好的回答。我試著理解,你說的是Triton(Triton)對吧?我覺得它們只是不同的程式設計模型(programming model),編寫內核(kernels)的方式不同而已。 講者4:所以這真的是很多東西啊。嗯……

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully