日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

TVM如何训练TinyML

發布時間:2023/11/28 生活经验 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 TVM如何训练TinyML 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

TVM如何訓練TinyML
機器學習研究人員和從業人員對“裸機”(低功耗,通常沒有操作系統)設備產生了廣泛的興趣。盡管專家已經有可能在某些裸機設備上運行某些模型,但是為各種設備優化模型的挑戰非常艱巨,通常需要手動優化設備特定的庫。對于那些沒有Linux支持的平臺,不存在用于部署模型的可擴展解決方案。因此,為了定位新設備,開發人員必須實現一次性的定制軟件堆棧,以管理系統資源和調度模型執行。
機器學習軟件的手動優化不是裸機設備領域獨有的。實際上,對于使用其它硬件后端(例如GPU和FPGA)的開發人員來說,這已成為一個共同的主題。TVM已被證明可以抵御新硬件目標的沖擊,但直到現在,仍無法解決微控制器的獨特特性。為了解決這一領域的問題,擴展了TVM以提供稱為μTVM(腳注:發音為“ MicroTVM”)的微控制器后端。μTVM促進了主機驅動的裸機設備上張量程序的執行,并通過TVM內置的張量程序優化器AutoTVM實現了這些程序的自動優化。下圖顯示了μTVM + AutoTVM基礎架構的鳥瞰圖:

功能
在討論什么是TVM / MicroTVM或它如何工作之前,讓看一下實際使用示例。

標準μTVM設置,主機通過JTAG與設備通信。
上面,有一塊STM32F746ZG板,其中裝有ARM Cortex-M7處理器,考慮到在低功耗封裝中的強大性能,邊緣AI的理想部件。使用其USB-JTAG端口將其連接到臺式機。在桌面上,運行OpenOCD來打開與設備的JTAG連接。反過來,OpenOCD允許μTVM使用與設備無關的TCP套接字控制M7處理器。完成此設置后,可以使用如下所示的TVM代碼運行CIFAR-10分類器(此處為完整腳本):
OPENOCD_SERVER_ADDR = ‘127.0.0.1’
OPENOCD_SERVER_PORT = 6666
TARGET = tvm.target.create(‘c -device=micro_dev’)
DEV_CONFIG = stm32f746xx.default_config(OPENOCD_SERVER_ADDR, OPENOCD_SERVER_PORT)

module, params = get_cifar10_cnn()
with micro.Session(device_config) as sess:
graph, c_module, params = relay.build(module[‘main’], target=TARGET, params=params)
micro_mod = micro.create_micro_mod(c_module, DEV_CONFIG)
graph_mod = graph_runtime.create(graph, micro_mod, ctx=tvm.micro_dev(0))
graph_mod.run(data=data_np)
prediction = CIFAR10_CLASSES[np.argmax(graph_mod.get_output(0).asnumpy())]
print(f’prediction was {prediction}’)
與CMSIS-NN版本5.7.0(commit a65b7c9a)(一種手動優化的ML內核庫)相比,以下是MicroTVM的性能結果。

如所見,開箱即用的性能并不好,但這就是AutoTVM表現的地方??梢詾樵O備編寫調度模板,進行一輪自動調整,然后獲得明顯更好的結果。要插入自動調整的結果,只需要替換以下行:
graph, c_module, params = relay.build(module[‘main’], target=TARGET, params=params)
這些行:
with TARGET, autotvm.apply_history_best(TUNING_RESULTS_FILE):
graph, c_module, params = relay.build(module[‘main’], target=TARGET, params=params)
現在,結果如下所示:

性能提高了約2倍,現在,離CMSIS-NN更近了。盡管MicroTVM CIFAR10的實現與類似的TFLite / CMSIS-NN模型相比具有競爭優勢,但這項工作才剛剛開始利用TVM的優化功能。通過加速其它運營商(如密集/完全連接)并利用TVM特定于模型的量化和運營商融合功能,還有進一步優化的空間。帶有μTVM的TVM使能夠充分發揮作用。怎樣工作的?幕后發生了什么事?
設計

μTVM設備在RAM中的存儲器布局
μTVM旨在通過最大限度的減少必須滿足的一組要求,支持設備的最小公分母。特別是,用戶只需要提供:

  1. 設備的C交叉編譯器工具鏈
  2. 一種用于讀取/寫入設備內存并在設備上執行代碼的方法
  3. 包含設備的內存布局和一般體系結構特征的規范
  4. 一個代碼片段,為設備執行功能做準備
    大多數裸機設備都支持C和JTAG(調試協議),因此(1)和(2)通常是免費提供的!此外,(3)和(4)通常是很小的要求。以下是STM32F746系列板卡的(3)和(4)的示例。
    device_config = {
    ‘device_id’: ‘arm.stm32f746xx’, # unique identifier for the device
    ‘toolchain_prefix’: ‘arm-none-eabi-’, # prefix of each binary in the cross-compilation toolchain (e.g., arm-none-eabi-gcc)
    ‘base_addr’: 0x20000000, # first address of RAM
    ‘section_sizes’: { # dictionary of desired section sizes in bytes
    ‘text’: 18000,
    ‘rodata’: 100,
    ‘data’: 100,

    },
    ‘word_size’: 4, # device word size
    ‘thumb_mode’: True, # whether to use ARM’s thumb ISA
    ‘comms_method’: ‘openocd’, # method of communication with the device
    ‘server_addr’: ‘127.0.0.1’, # OpenOCD server address (if ‘comms_method’ is ‘openocd’)
    ‘server_port’: 6666, # OpenOCD server port (if ‘comms_method’ is ‘openocd’)
    }
    .syntax unified
    .cpu cortex-m7
    .fpu softvfp
    .thumb

.section .text.UTVMInit
.type UTVMInit, %function
UTVMInit:
/* enable fpu /
ldr r0, =0xE000ED88
ldr r1, [r0]
ldr r2, =0xF00000
orr r1, r2
str r1, [r0]
dsb
isb
/
set stack pointer /
ldr sp, =_utvm_stack_pointer_init
bl UTVMMain
.size UTVMInit, .-UTVMInit
μTVM基礎架構和設備Runtime僅用于滿足這些要求,正在努力通過支持通用的開源Runtime平臺(例如mBED OS)來處理編譯和鏈接過程,以降低這些要求。
設備會話
鑒于微控制器交互的網絡性質,通過引入的概念略微偏離了標準TVM代碼MicroSession。
μTVM中的每個功能,都依賴于與目標設備的開放會話。如果熟悉TVM,可能會注意到有一行代碼與第一個代碼段中的規范有所不同-即,這是一個代碼:

with micro.Session(device_config) as sess:

該with塊內的每一行都可以調用μTVM中的函數,上下文是由所指定的設備device_config。這條線在做很多事情,拆開包裝。
首先,使用指定的任何一種通信方法(通常是OpenOCD)來初始化與設備的連接。然后,使用指定的交叉編譯器交叉編譯μTVM設備的Runtime。最后,由主機分配用于已編譯二進制文件的空間,并使用打開的連接將二進制文件加載到設備上。
有了設備上的Runtime,自然會希望一些功能通過運行。
模塊加載
TVM中的核心抽象之一是模塊的抽象。模塊存儲用于特定設備/Runtime目標的一組相關功能。鑒于微控制器通常沒有操作系統,因此μTVM需要做很多額外的工作來維持這種高級抽象。要查看發生了什么,將跟蹤創建和加載與μTVM兼容的模塊的過程。
假設有一個micro.Session開放的設備和一個實現2D卷積的TVM調度。如果想將其加載到微控制器上,需要發出C代碼。為此,只需要target在tvm.build或中設置即可relay.build。例子:
graph, c_module, params = relay.build(module[‘main’], target=‘c -device=micro_dev’, params=params)
通過這樣設置目標,構建過程將貫穿C代碼生成后端。但是,生成的C模塊仍駐留在主機上。為了將其加載到設備上,通過μTVM基礎架構中的核心功能之一運行create_micro_mod。例子:
micro_mod = micro.create_micro_mod(c_module, DEV_CONFIG)
上面的行交叉編譯模塊中的C源代碼,為所得的二進制文件分配空間(以便可以與Runtime在設備內存中共存),然后將二進制文件的每個部分發送到其在設備上分配的插槽中。一旦模塊二進制文件貼緊在設備內存中,便會修補二進制文件中的功能指針,以使模塊可以在設備Runtime訪問輔助功能(例如,用于分配暫存器)。
現在,在將內核加載到設備上之后,可以獲取卷積函數的遠程句柄,如下所示:
micro_func = micro_mod[‘conv2d’]
張量加載
如果要調用算子,首先需要一些張量作為參數:
data_np, kernel_np = get_conv_inputs()
ctx = tvm.micro_dev(0)
data = tvm.nd.array(data_np, ctx=ctx)
kernel = tvm.nd.array(kernel_np, ctx=ctx)
根據它的數據類型(例如,int8,float32等)和形狀,各張量的字節大小被計算,并在主機分配所述設備的堆存儲器的區域中。然后將張量的數據加載到分配的區域中。
函數調用
算子執行可能是該系統中最棘手的部分。為了簡化其表示,將首先介紹嚴格執行(在調用操作符后立即執行操作),然后是延遲執行(僅在需要其結果后才執行操作符)–后者是系統的實際運行方式。
嚴格執行
調用函數時,輸入張量和輸出張量均作為參數傳遞,即所謂的目標傳遞風格:
conv2D(data, kernel, output)
鑒于這些張量已在設備上分配,只需要將元數據發送到設備(設備地址,形狀和數據類型),知道要使用哪個駐留張量。函數調用的Runtime表示形式包括此元數據以及被調用函數的地址(如下所示)。在構造此表示形式之前,需要將元數據序列化到為此目的明確存在的設備上的arguments部分中。
/

  • task struct for uTVM
    /
    typedef struct {
    /
    pointer to function to call for this task /
    int32_t (func)(void, void
    , int32_t);
    /* array of argument tensors /
    TVMValue
    arg_values;
    /* array of datatype codes for each argument /
    int
    arg_type_codes;
    /* number of arguments */
    int32_t num_args;
    } UTVMTask;
    在嚴格的設置中,只有一個全局UTVMTask實例,從主機端將其寫入其中。一旦寫入任務,Runtime就具有執行該功能所需的一切,并且可以在Runtime的入口點開始執行。Runtime將執行一些輕量級的初始化,運行算子,然后將控制權返回給主機。
    執行
    在實踐中,由于通信開銷開始占主導地位,一旦用戶要求執行算子就變得非常耗資源??梢酝ㄟ^延遲評估,直到用戶希望獲得調用結果的方式來提高系統的吞吐量。
    從實現的角度來看,UTVMTask現在不急于序列化參數元數據和數據,而是需要在主機端累積函數調用元數據,然后再將其刷新到設備中。設備Runtime還需要進行一些更改:(1)現在必須具有的全局數組,UTVMTask并且(2)需要依次遍歷并執行每個任務。
    帶MicroTVM的AutoTVM
    到目前為止,描述的Runtime對于模型部署似乎并不是很有用,因為非常依賴主機。這是有意為之的,實際上,Runtime是為實現另一個目標而設計的:AutoTVM支持。
    通常,AutoTVM會提出候選內核,并使用隨機輸入在目標后端上運行,然后使用計時結果來改善其搜索過程。鑒于AutoTVM只關心單個算子的執行,將Runtime設計為面向算子,而不是面向模型。但是對于μTVM,與設備的通信通常會占據執行時間。惰性執行使可以多次運行同一算子,而無需將控制權交還給主機,因此,通信成本在每次Runtime均攤銷,可以更好地了解性能概況。
    由于AutoTVM需要在大量候選內核上進行快速迭代,因此μTVM基礎架構目前僅使用RAM。但是,對于自托管Runtime,肯定需要同時使用閃存和RAM。
    托管圖Runtime
    盡管托管的Runtime是為AutoTVM設計的,但仍然可以運行完整的模型(只要沒有任何控制流)。僅通過使用TVM的圖形Runtime即可免費使用此功能,但具有μTVM上下文。實際上,圖Runtime對主機的唯一依賴是張量分配和算子調度(這只是依賴圖的一種拓撲類型)。
    評估
    有了這個基礎架構,試圖回答以下問題:
  1. μTVM是否真的與設備無關?
  2. 使用μTVM進行優化試驗需要多少精力?
    為了評估(1),在兩個目標上進行了實驗:
    ? 一個手臂STM32F746NG開發板,采用了的Cortex-M7處理器
    ? μTVM主機仿真設備,可在主機上創建一個內存競技場,與之連接的主機就像裸機設備一樣。
    為了評估(2),探索了Arm板的優化方案,這些方案可以最大程度地降低成本。
    作為比較,從Arm的本教程中提取了量化的CIFAR-10 CNN。CMSIS-NN(Arm專家高度優化的內核庫)用作算子庫,使該CNN成為完美的評估目標,因為現在可以直接將μTVM的結果與Arm上的CMSIS-NN進行比較木板。

CIFAR-10 CNN圖
方法
在實驗中,使用HEAD的TVM(commit 9fa8341),CMSIS-NN的5.7.0版(commit a65b7c9a),STM32CubeF7的1.16.0版以及Arm的適用于Arm嵌入式處理器的GNU工具的GCC 9-2019-q4-major 9.2 .1工具鏈(修訂版277599)。實驗中使用的主機運行Ubuntu Linux 18.04.4 LTS,并運行帶有62GB RAM的AMD Ryzen Threadripper 2990WX 32核處理器。
特定于手臂的優化
使用CMSIS-NN,第一個卷積映射到其RGB卷積實現(專門用于輸入層),而后兩個卷積映射到其“快速”卷積實現。經過較早的泛型優化后,覺得性能對于RGB卷積已經足夠接近了,但是對快速卷積結果卻不滿意。幸運的是,Arm發布了一篇描述CMSIS-NN中使用的優化的論文,發現正在從SIMD內在函數中獲得巨大的加速。在本文中,提出了一種使用SIMD內在函數的矩陣乘法微內核(下圖)。雖然可以在TVM的代碼生成工具中添加對內在函數的一流支持,這從長遠來看可能是最好的做法,但TVM提供了張量化是支持SIMD的“快捷方法”。

CMSIS-NN論文的圖表顯示了2x2矩陣乘法微內核
張量化通過定義可插入TVM算子最內層循環的微內核來工作。使用這種機制,添加對Arm板的SIMD支持就像在C中定義一個微內核一樣簡單(可在此處找到),該微內核反映了其論文中的實現。定義了一個調度,使用該微內核(在此處找到),對其進行自動調整,然后得到“ μTVM SIMD調整”結果。
盡管能夠使用SIMD微內核進行直接卷積,但是CMSIS-NN使用他們所謂的“部分im2col”作為其實現策略,這在性能和內存使用之間進行了權衡。代替一次顯示整個im2col矩陣,部分im2col一次只生成幾列。然后,對于每一批,他們可以將矩陣發送到其SIMD matmul函數。
假設是,除其它優化外,可以通過自動調整找到最佳的批量大小。在實踐中,發現部分im2col比直接卷積實現要慢得多,因此在其余結果中不包括。
當然,還可以從CMSIS-NN中獲得其它優化來進一步縮小差距:
? 將int8權重批量擴展為int16,以減少SIMD的重復擴展
? 將卷積拆分為3x3的圖塊以減少填充檢查
但是,目標是展示μTVM可以完成的工作的大致范圍。即使這樣,這也不是競爭,因為CMSIS-NN(以及任何其它手動優化的庫)可以使用Bring Your Own Codegen框架直接插入TVM 。
端到端
CIFAR-10
在探索卷積優化之后,著手測量其對端到端性能的影響。對于ARM板,收集了未調整的結果,這是調整的結果沒有任何使用SIMD,這是調整的結果與SIMD和結果使用CMSIS-NN。對于模擬的主機設備,僅收集未調整的結果和通用的調整結果。
https://github.com/areusch/microtvm-blogpost-eval

int8Arm STM32F746NG進行量化的CIFAR-10 CNN比較(從上方轉貼)

int8μTVM的仿真主機設備上對量化的CIFAR-10 CNN進行比較
在Arm STM32系列板上,與最初的未調整算子相比,能夠將性能提高約2倍,并且所獲得的結果更接近CMSIS-NN。此外,能夠顯著提高主機仿真設備上的性能。盡管x86的數字意義不大,表明可以使用相同的基礎架構(μTVM)來在極為不同的體系結構上優化性能。
隨著更廣泛地擴展此方法,在將來繼續關注更多端到端基準測試。
自托管Runtime:最終領域

設想的μTVM優化和部署流程
如上所述,雖然當前Runtime已經可以獲取端到端基準測試結果,但目前仍在路線圖上以獨立能力部署這些模型。差距在于面向AutoTVM的Runtime當前依賴于主機來分配張量并計劃函數執行。然而,為了在邊緣是有用的,需要通過μTVM,其產生一個管道單一待裸機設備上運行的二進制。然后,用戶可以通過在邊緣應用程序中包含此二進制文件,輕松地將快速ML集成到他們的應用程序中。該管道的每個階段都已經到位,現在只需將粘合在一起即可,因此期待在此方面的最新進展。
結論
用于單內核優化的MicroTVM現已準備就緒,并且是該用例的選擇。現在,當建立自托管的部署支持時,希望也和使μTVM成為模型部署的選擇一樣興奮。但是,這不只是一場觀看比賽-記住:這都是開源的!μTVM仍處于起步階段,因此每個人對其軌跡都會產生很大的影響。

總結

以上是生活随笔為你收集整理的TVM如何训练TinyML的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。