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