<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          TorchScript 系列解讀(一):初識 TorchScript

          共 5783字,需瀏覽 12分鐘

           ·

          2022-04-19 12:37


          什么是 TorchScript?


          PyTorch 無疑是現(xiàn)在最成功的深度學(xué)習(xí)訓(xùn)練框架之一,是各種頂會頂刊論文實(shí)驗(yàn)的大熱門。比起其他的框架,PyTorch 最大的賣點(diǎn)是它對動態(tài)網(wǎng)絡(luò)的支持,比其他需要構(gòu)建靜態(tài)網(wǎng)絡(luò)的框架擁有更低的學(xué)習(xí)成本。PyTorch 源碼 Readme 中還專門為此做了一張動態(tài)圖:



          對研究員而言,PyTorch 能極大地提高想 idea、做實(shí)驗(yàn)、發(fā)論文的效率,是訓(xùn)練框架中的豪杰,但是它不適合部署。動態(tài)建圖帶來的優(yōu)勢對于性能要求更高的應(yīng)用場景而言更像是缺點(diǎn),非固定的網(wǎng)絡(luò)結(jié)構(gòu)給網(wǎng)絡(luò)結(jié)構(gòu)分析并進(jìn)行優(yōu)化帶來了困難,多數(shù)參數(shù)都能以 Tensor 形式傳輸也讓資源分配變成一件鬧心的事。另外由于圖是由 python 代碼來構(gòu)建的,一方面部署要依賴 python 環(huán)境,另一方面模型也毫無保密性可言。


          而 TorchScript 就是為了解決這個問題而誕生的工具。包括代碼的追蹤及解析、中間表示的生成、模型優(yōu)化、序列化等各種功能,可以說是覆蓋了模型部署的方方面面。今天我們先簡要地介紹一些 TorchScript 的功能,讓大家有一個初步的認(rèn)識,進(jìn)階的解讀會陸續(xù)推出~


          模型轉(zhuǎn)換



          作為模型部署的一個范式,通常我們都需要生成一個模型的中間表示(IR),這個 IR 擁有相對固定的圖結(jié)構(gòu),所以更容易優(yōu)化,讓我們看一個例子:


          import torchfrom torchvision.models import resnet18
          # 使用PyTorch model zoo中的resnet18作為例子model = resnet18()model.eval()
          # 通過trace的方法生成IR需要一個輸入樣例dummy_input = torch.rand(1, 3, 224, 224)
          # IR生成with torch.no_grad(): ? ?jit_model = torch.jit.trace(model, dummy_input)


          到這里就將 PyTorch 的模型轉(zhuǎn)換成了 TorchScript 的 IR。這里我們使用了 trace 模式來生成 IR,所謂 trace 指的是進(jìn)行一次模型推理,在推理的過程中記錄所有經(jīng)過的計(jì)算,將這些記錄整合成計(jì)算圖。關(guān)于 trace 的過程我們會在未來的分享中進(jìn)行解讀。


          那么這個 IR 中到底都有些什么呢?我們可以可視化一下其中的 layer1 看看:


          jit_layer1 = jit_model.layer1print(jit_layer1.graph)
          # graph(%self.6 : __torch__.torch.nn.modules.container.Sequential,# ? ? ? %4 : Float(1, 64, 56, 56, strides=[200704, 3136, 56, 1], requires_grad=0, device=cpu)):# ? %1 : __torch__.torchvision.models.resnet.___torch_mangle_10.BasicBlock = prim::GetAttr[name="1"](%self.6)# ? %2 : __torch__.torchvision.models.resnet.BasicBlock = prim::GetAttr[name="0"](%self.6)# ? %6 : Tensor = prim::CallMethod[name="forward"](%2, %4)# ? %7 : Tensor = prim::CallMethod[name="forward"](%1, %6)# ? return (%7)


          是不是有點(diǎn)摸不著頭腦?TorchScript 有它自己對于 Graph 以及其中元素的定義,對于第一次接觸的人來說可能比較陌生,但是沒關(guān)系,我們還有另一種可視化方式:


          print(jit_layer1.code)
          # def forward(self,# ? ? argument_1: Tensor) -> Tensor:# ? _0 = getattr(self, "1")# ? _1 = (getattr(self, "0")).forward(argument_1, )# ? return (_0).forward(_1, )


          沒錯,就是代碼!TorchScript 的 IR 是可以還原成 python 代碼的,如果你生成了一個 TorchScript 模型并且想知道它的內(nèi)容對不對,那么可以通過這樣的方式來做一些簡單的檢查。


          剛才的例子中我們使用 trace 的方法生成 IR。除了 trace 之外,PyTorch 還提供了另一種生成 TorchScript 模型的方法:script。這種方式會直接解析網(wǎng)絡(luò)定義的 python 代碼,生成抽象語法樹 AST,因此這種方法可以解決一些 trace 無法解決的問題,比如對 branch/loop 等數(shù)據(jù)流控制語句的建圖。script 方式的建圖有很多有趣的特性,會在未來的分享中做專題分析,敬請期待。


          模型優(yōu)化



          聰明的同學(xué)可能發(fā)現(xiàn)了,上面的可視化中只有 resnet18 里 forward 的部分,其中的子模塊信息是不是丟失了呢?如果沒有丟失,那么怎么樣才能確定子模塊的內(nèi)容是否正確呢?別擔(dān)心,還記得我們說過 TorchScript 支持對網(wǎng)絡(luò)的優(yōu)化嗎,這里我們就可以用一個 pass 解決這個問題:


          # 調(diào)用inline pass,對graph做變換torch._C._jit_pass_inline(jit_layer1.graph)print(jit_layer1.code)
          # def forward(self,# ? ? argument_1: Tensor) -> Tensor:# ? _0 = getattr(self, "1")# ? _1 = getattr(self, "0")# ? _2 = _1.bn2# ? _3 = _1.conv2# ? _4 = _1.bn1# ? input = torch._convolution(argument_1, _1.conv1.weight, None, [1, 1], [1, 1], [1, 1], False, [0, 0], 1, False, False, True, True)# ? _5 = _4.running_var# ? _6 = _4.running_mean# ? _7 = _4.bias# ? input0 = torch.batch_norm(input, _4.weight, _7, _6, _5, False, 0.10000000000000001, 1.0000000000000001e-05, True)# ? input1 = torch.relu_(input0)# ? input2 = torch._convolution(input1, _3.weight, None, [1, 1], [1, 1], [1, 1], False, [0, 0], 1, False, False, True, True)# ? _8 = _2.running_var# ? _9 = _2.running_mean# ? _10 = _2.bias# ? out = torch.batch_norm(input2, _2.weight, _10, _9, _8, False, 0.10000000000000001, 1.0000000000000001e-05, True)# ? input3 = torch.add_(out, argument_1, alpha=1)# ? input4 = torch.relu_(input3)# ? _11 = _0.bn2# ? _12 = _0.conv2# ? _13 = _0.bn1# ? input5 = torch._convolution(input4, _0.conv1.weight, None, [1, 1], [1, 1], [1, 1], False, [0, 0], 1, False, False, True, True)# ? _14 = _13.running_var# ? _15 = _13.running_mean# ? _16 = _13.bias# ? input6 = torch.batch_norm(input5, _13.weight, _16, _15, _14, False, 0.10000000000000001, 1.0000000000000001e-05, True)# ? input7 = torch.relu_(input6)# ? input8 = torch._convolution(input7, _12.weight, None, [1, 1], [1, 1], [1, 1], False, [0, 0], 1, False, False, True, True)# ? _17 = _11.running_var# ? _18 = _11.running_mean# ? _19 = _11.bias# ? out0 = torch.batch_norm(input8, _11.weight, _19, _18, _17, False, 0.10000000000000001, 1.0000000000000001e-05, True)# ? input9 = torch.add_(out0, input4, alpha=1)# ? return torch.relu_(input9)


          這里我們就能看到卷積、batch_norm、relu 等熟悉的算子了。


          上面代碼中我們使用了一個名為 inline 的 pass,將所有子模塊進(jìn)行內(nèi)聯(lián),這樣我們就能看見更完整的推理代碼。pass 是一個來源于編譯原理的概念,一個 TorchScript 的 pass 會接收一個圖,遍歷圖中所有元素進(jìn)行某種變換,生成一個新的圖。我們這里用到的 inline 起到的作用就是將模塊調(diào)用展開,盡管這樣做并不能直接影響執(zhí)行效率,但是它其實(shí)是很多其他 pass 的基礎(chǔ)。PyTorch 中定義了非常多的 pass 來解決各種優(yōu)化任務(wù),未來我們會做一些更詳細(xì)的介紹。


          序列化



          不管是哪種方法創(chuàng)建的 TorchScript 都可以進(jìn)行序列化,比如:


          # 將模型序列化jit_model.save('jit_model.pth')# 加載序列化后的模型jit_model = torch.jit.load('jit_model.pth')


          序列化后的模型不再與 python 相關(guān),可以被部署到各種平臺上。


          PyTorch 提供了可以用于 TorchScript 模型推理的 c++ API,序列化后的模型終于可以不依賴 python 進(jìn)行推理了:


          // 加載生成的torchscript模型auto module = torch::jit::load('jit_model.pth');// 根據(jù)任務(wù)需求讀取數(shù)據(jù)std::vector inputs = ...;// 計(jì)算推理結(jié)果auto output = module.forward(inputs).toTensor();


          與其他組件的關(guān)系?


          與 torch.onnx 的關(guān)系




          ONNX 是業(yè)界廣泛使用的一種神經(jīng)網(wǎng)絡(luò)中間表示,PyTorch 自然也對 ONNX 提供了支持。torch.onnx.export 函數(shù)可以幫助我們把 PyTorch 模型轉(zhuǎn)換成 ONNX 模型,這個函數(shù)會使用 trace 的方式記錄 PyTorch 的推理過程。聰明的同學(xué)可能已經(jīng)想到了,沒錯,ONNX 的導(dǎo)出,使用的正是 TorchScript 的 trace 工具。具體步驟如下:


          1. 使用 trace 的方式先生成一個 TorchScipt 模型,如果你轉(zhuǎn)換的本身就是 TorchScript 模型,則可以跳過這一步。

          2. 使用許多 pass 對 1 中生成的模型進(jìn)行變換,其中對 ONNX 導(dǎo)出最重要的一個 pass 就是ToONNX,這個 pass 會進(jìn)行一個映射,將 TorchScript 中 prim、aten 空間下的算子映射到onnx空間下的算子。

          3. 使用 ONNX 的 proto 格式對模型進(jìn)行序列化,完成 ONNX 的導(dǎo)出。


          關(guān)于 ONNX 導(dǎo)出的實(shí)現(xiàn)以及算子映射的方式將會在未來的分享中詳細(xì)展開。


          與 torch.fx 的關(guān)系



          PyTorch1.9 開始添加了 torch.fx 工具,根據(jù)官方的介紹,它由符號追蹤器 (symbolic tracer),中間表示(IR), Python 代碼生成 (Python code generation) 等組件組成,實(shí)現(xiàn)了 python->python 的翻譯。是不是和 TorchScript 看起來有點(diǎn)像?


          其實(shí)他們之間聯(lián)系不大,可以算是互相垂直的兩個工具,為解決兩個不同的任務(wù)而誕生。


          TorchScript 的主要用途是進(jìn)行模型部署,需要記錄生成一個便于推理優(yōu)化的 IR,對計(jì)算圖的編輯通常都是面向性能提升等等,不會給模型本身添加新的功能。


          FX 的主要用途是進(jìn)行 python->python 的翻譯,它的 IR 中節(jié)點(diǎn)類型更簡單,比如函數(shù)調(diào)用、屬性提取等等,這樣的 IR 學(xué)習(xí)成本更低更容易編輯。使用 FX 來編輯圖通常是為了實(shí)現(xiàn)某種特定功能,比如給模型插入量化節(jié)點(diǎn)等,避免手動編輯網(wǎng)絡(luò)造成的重復(fù)勞動。


          這兩個工具可以同時(shí)使用,比如使用 FX 工具編輯模型來讓訓(xùn)練更便利、功能更強(qiáng)大;然后用 TorchScript 將模型加速部署到特定平臺。


          GiantPandaCV

          長按二維碼關(guān)注我們

          本公眾號專注:

          1. 技術(shù)分享;

          2.?學(xué)術(shù)交流

          3.?資料共享。

          歡迎關(guān)注我們,一起成長!


          瀏覽 73
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  青青草手机在线免费激情视频欧美精华 | 国产免费操逼 | 亚洲激情操逼 | 欧美A色 欧美爱色 | AAA黄色 |