paddle06-paddle.jit 動態圖轉靜態圖相關API


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 函數相關
      • print
      • 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() 設置動態圖 轉 靜態圖 的日志詳細級別。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM