4. 動態圖轉靜態圖: (沒細看)
4.1 基本用法
PaddlePaddle 主要的動轉靜方式是 基於源代碼級別轉換的 ProgramTranslator。 其基本原理是通過 分析 Python代碼開將動態圖代碼轉寫為 靜態圖代碼,並在底層自動幫助用戶是呀9哦那個靜態圖執行器運行。
-
基於源代碼轉寫的 ProgramTranslator
- 用法: 只需要在轉換的函數(該函數可以是 Model 定義的動態圖 forward函數)前添加一個裝飾器 @paddle.jit.to_static
-
基於 trace 的 TraceLayer
4.2 內部架構原理:基於源代碼轉寫的 ProgramTranslator
-
函數與緩存
-
動態圖源碼轉 AST(抽象語法樹)
-
AST 改寫和靜態圖源碼 轉換
動轉靜 最核心的部分, 對支持的各種語法進行 ast 轉寫。 其中最重要的就是 Python控制流, if-else、 while、 for 循環 被分別轉換為 POaddlePaddle 靜態圖接口 cond, while_loop 等接口實現。 -
靜態圖源碼作為動態圖一部分運行的技術
-
易用性 與 Debug 功能在動轉靜過程的實現
4.3 支持語法列表
-
動轉靜支持語法:
- 控制流相關關鍵詞
- if-elif-else 條件
- while 循環
- for 循環
- break, continue
- return
- 一些需要轉換的 運算類型
- +,-,,/,*, >, <, >= , <=, == 等Python內置運算
- and、or、not 邏輯運算
- 類型轉換
- python 函數相關
- len
- lambda 表達式
- 函數內再調用函數
- 控制流相關關鍵詞
-
報錯異常相關:
-
Python 基本容器
- list
- dict
-
動轉靜無法正確運行的情況
- 改變變量的shape 后調用其 shape 作為 paddle API 參數
- 多重list嵌套讀寫 Tensor
- Tensor 值 在被裝飾函數中轉成 numpy array 進行計算
- 一個函數遞歸調用本身
4.4 InputSpec 功能介紹
動轉靜時,需要給模型傳入 Tensor 數據並執行 一次前向,以確保正確地推導出 網絡中 各Tensor 的 shape。 此轉換流程需要顯示的執行一次動態圖函數,增加了 接口使用的成本。 同時,傳入實際Tensor 數據則無法定制化模型輸入的 shape,如指定某些維度為 None。
為此: paddle提供了 InputSpec 接口,可以更加便捷的執行動轉靜功能,以及定制化輸入 Tensor 的 shape, name等信息。
4.4.1 一、InputSpec 對象構造方法
-
1.1 直接構造 InputSpec 對象
-
1.2 根據 Tensor 構造 InputSpec 對象
-
1.3 根據 numpy.ndarray 構造 InputSpec 對象
4.4.2 二、基本使用方法
-
2.1 to_static 裝飾器模式
-
2.2 to_static 函數調用
-
2.3 支持 list 和 dict 推導
-
2.4 指定非 Tensor 參數類型
4.5 報錯信息處理
- 動轉靜過程中的異常
- 運行轉換后的代碼報錯
4.6 調試方法
- 斷點調試,pdb.set_trace()
- 打印轉換后的代碼
- 使用print
- 日志打印
🌟 paddle.jit 動態圖轉靜態圖相關API
🌙 動態圖轉靜態圖相關API
-
1.paddle.jit.to_static() 動轉靜to_static 裝飾器
本裝飾器將函數內的動態圖API轉化為靜態圖API。此裝飾器自動處理靜態圖模式下的Program和Executor,並將結果作為動態圖Tensor返回。輸出的動態圖Tensor可以繼續進行動態圖訓練、預測或其他運算。如果被裝飾的函數里面調用其他動態圖函數,被調用的函數也會被轉化為靜態圖函數 from paddle.jit import to_static @to_static def func(x): if paddle.mean(x) < 0: x_v = x - 1 else: x_v = x + 1 return x_v x = paddle.ones([1, 2], dtype='float32') x_v = func(x) print(x_v) # [[2. 2.]]
-
2.paddle.jit.save(layer, path, input_spec=None, **configs) 動轉靜 模型存儲接口
將輸入的 Layer 存儲為 paddle.jit.TranslatedLayer 格式的模型,載入后可用於 預測推理 或 fine-tune 訓練 該接口將 輸入 Layer 轉寫后的模型 Program 和 所有必要的吃酒參數變量 存儲至 輸出路徑path. path 是存儲目標的前綴,存儲的模型結構 Program 文件的后綴為 .pdmodel, 存儲的持久變量的文件的后綴為 .pdiparams, 同時這里也會將一些變量描述信息存儲至文件,后綴為 .pdiparams.info, 這些額外信息將在 fine-tune 訓練中使用。 存儲模型使用范圍: 1.paddle.jit.load() 2.paddle.static.load_inference_model() 3.其他預測庫API 參數: 1.layer: Layer, 需要保存的 Layer 對象 2.path:str, 存儲模型的路徑前綴,格式為: dirname/file_prefix 或 file_prefix 3.input_spec (list[InputSpec|Tensor], 可選) - 描述存儲模型forward方法的輸入,可以通過InputSpec或者示例Tensor進行描述。如果為 None ,所有原 Layer forward方法的輸入變量將都會被配置為存儲模型的輸入變量。默認為 None。 返回: 無 import paddle.nn as nn import paddle.optimizer as opt BATCH_SIZE = 16 BATCH_NUM = 4 EPOCH_NUM = 4 IMAGE_SIZE = 784 CLASS_NUM = 10 # define a random dataset class RandomDataset(paddle.io.Dataset): def __init__(self, num_samples): self.num_samples = num_samples def __getitem__(self, idx): image = np.random.random([IMAGE_SIZE]).astype('float32') label = np.random.randint(0, CLASS_NUM - 1, (1, )).astype('int64') return image, label def __len__(self): return self.num_samples class LinearNet(nn.Layer): def __init__(self): super(LinearNet, self).__init__() self._linear = nn.Linear(IMAGE_SIZE, CLASS_NUM) @paddle.jit.to_static def forward(self, x): return self._linear(x) def train(layer, loader, loss_fn, opt): for epoch_id in range(EPOCH_NUM): for batch_id, (image, label) in enumerate(loader()): out = layer(image) loss = loss_fn(out, label) loss.backward() opt.step() opt.clear_grad() print("Epoch {} batch {}: loss = {}".format( epoch_id, batch_id, np.mean(loss.numpy()))) # 1. train & save model. # create network layer = LinearNet() loss_fn = nn.CrossEntropyLoss() adam = opt.Adam(learning_rate=0.001, parameters=layer.parameters()) # create data loader dataset = RandomDataset(BATCH_NUM * BATCH_SIZE) loader = paddle.io.DataLoader(dataset, batch_size=BATCH_SIZE, shuffle=True, drop_last=True, num_workers=2) # train train(layer, loader, loss_fn, adam) # save path = "example_model/linear" paddle.jit.save(layer, path)
-
3.paddle.jit.load(path, **config) 動轉靜 模型載入接口
將接口 paddle.jit.save 或者 paddle.static.save_inference_model 存儲的模型載入為 paddle.jit.TranslatedLayer ,用於預測推理或者fine-tune訓練 參數:path (str) - 載入模型的路徑前綴。格式為 dirname/file_prefix 或者 file_prefix 返回: TranslatedLayer,一個能夠執行存儲模型的 Layer 對象 # train train(layer, loader, loss_fn, adam) # save path = "example_model/linear" paddle.jit.save(layer, path) # 2. load model # load loaded_layer = paddle.jit.load(path) # inference loaded_layer.eval() x = paddle.randn([1, IMAGE_SIZE], 'float32') pred = loaded_layer(x) # fine-tune loaded_layer.train() adam = opt.Adam(learning_rate=0.001, parameters=loaded_layer.parameters()) train(loaded_layer, loader, loss_fn, adam)
-
4.paddle.jit.ProgramTranslator() 動轉靜控制主類 ProgramTranslator
-
5.paddle.jit.TracedLayer() 備選根據trace 動轉靜的 接口, TrancedLayer
Debug 動態圖轉靜態圖相關
-
paddle.jit.set_code_level() 設置級別代碼,打印該 級別動轉靜轉換后 的代碼
-
paddle.jit.set_verbosity() 設置動態圖 轉 靜態圖 的日志詳細級別。