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() 设置动态图 转 静态图 的日志详细级别。
