未验证 提交 d93af72b 编写于 作者: J Jason 提交者: GitHub

Merge pull request #392 from SunAhong1993/me

add optimizer and aten for shufflenet
...@@ -44,6 +44,11 @@ x2paddle --framework=caffe --prototxt=deploy.prototxt --weight=deploy.caffemodel ...@@ -44,6 +44,11 @@ x2paddle --framework=caffe --prototxt=deploy.prototxt --weight=deploy.caffemodel
``` ```
x2paddle --framework=onnx --model=onnx_model.onnx --save_dir=pd_model x2paddle --framework=onnx --model=onnx_model.onnx --save_dir=pd_model
``` ```
### PyTorch
```
x2paddle --framework=pytorch --model=resnet50.pt --save_dir=pd_model
```
### Paddle2ONNX ### Paddle2ONNX
``` ```
# 注意:paddle_infer_model_dir下需包含__model__和__params__两个文件 # 注意:paddle_infer_model_dir下需包含__model__和__params__两个文件
...@@ -56,7 +61,7 @@ x2paddle --framework=paddle2onnx --model=paddle_infer_model_dir --save_dir=onnx_ ...@@ -56,7 +61,7 @@ x2paddle --framework=paddle2onnx --model=paddle_infer_model_dir --save_dir=onnx_
|--prototxt | 当framework为caffe时,该参数指定caffe模型的proto文件路径 | |--prototxt | 当framework为caffe时,该参数指定caffe模型的proto文件路径 |
|--weight | 当framework为caffe时,该参数指定caffe模型的参数文件路径 | |--weight | 当framework为caffe时,该参数指定caffe模型的参数文件路径 |
|--save_dir | 指定转换后的模型保存目录路径 | |--save_dir | 指定转换后的模型保存目录路径 |
|--model | 当framework为tensorflow/onnx时,该参数指定tensorflow的pb模型文件或onnx模型路径 | |--model | 当framework为tensorflow/onnx/pytorch时,该参数指定tensorflow的pb模型文件或onnx模型路径或者pytorch的script模型 |
|--caffe_proto | **[可选]** 由caffe.proto编译成caffe_pb2.py文件的存放路径,当存在自定义Layer时使用,默认为None | |--caffe_proto | **[可选]** 由caffe.proto编译成caffe_pb2.py文件的存放路径,当存在自定义Layer时使用,默认为None |
|--without_data_format_optimization | **[可选]** For TensorFlow, 当指定该参数时,关闭NHWC->NCHW的优化,见[文档Q2](FAQ.md) | |--without_data_format_optimization | **[可选]** For TensorFlow, 当指定该参数时,关闭NHWC->NCHW的优化,见[文档Q2](FAQ.md) |
|--define_input_shape | **[可选]** For TensorFlow, 当指定该参数时,强制用户输入每个Placeholder的shape,见[文档Q2](FAQ.md) | |--define_input_shape | **[可选]** For TensorFlow, 当指定该参数时,强制用户输入每个Placeholder的shape,见[文档Q2](FAQ.md) |
...@@ -81,6 +86,7 @@ X2Paddle提供了工具解决如下问题,详见[tools/README.md](tools/README ...@@ -81,6 +86,7 @@ X2Paddle提供了工具解决如下问题,详见[tools/README.md](tools/README
3. [X2Paddle测试模型库](x2paddle_model_zoo.md) 3. [X2Paddle测试模型库](x2paddle_model_zoo.md)
4. [PyTorch模型导出为ONNX模型](pytorch_to_onnx.md) 4. [PyTorch模型导出为ONNX模型](pytorch_to_onnx.md)
5. [X2Paddle内置的Caffe自定义层](caffe_custom_layer.md) 5. [X2Paddle内置的Caffe自定义层](caffe_custom_layer.md)
6. [PyTorch模型导出为ScriptModule模型](pytorch_to_script.md)
## 更新历史 ## 更新历史
2019.08.05 2019.08.05
......
## PyTorch模型导出为ONNX模型
目前pytorch2paddle主要支持pytorch ScriptModule。 用户可通过如下示例代码,将torchvison或者自己开发写的模型转换成ScriptModule model:
```
#coding: utf-8
import torch
import torch.nn as nn
from torchvision.models.utils import load_state_dict_from_url
# 定义模型
class AlexNet(nn.Module):
def __init__(self, num_classes=1000):
super(AlexNet, self).__init__()
self.features = nn.Sequential(
nn.Conv2d(3, 64, kernel_size=11, stride=4, padding=2),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=3, stride=2),
nn.Conv2d(64, 192, kernel_size=5, padding=2),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=3, stride=2),
nn.Conv2d(192, 384, kernel_size=3, padding=1),
nn.ReLU(inplace=True),
nn.Conv2d(384, 256, kernel_size=3, padding=1),
nn.ReLU(inplace=True),
nn.Conv2d(256, 256, kernel_size=3, padding=1),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=3, stride=2),
)
self.avgpool = nn.AdaptiveAvgPool2d((6, 6))
self.classifier = nn.Sequential(
nn.Dropout(0.0),
nn.Linear(256 * 6 * 6, 4096),
nn.ReLU(inplace=True),
nn.Dropout(0.0),
nn.Linear(4096, 4096),
nn.ReLU(inplace=True),
nn.Linear(4096, num_classes),
)
def forward(self, x):
x = self.features(x)
for i in range(1):
x = self.avgpool(x)
x = torch.flatten(x, 1)
x = self.classifier(x)
return x
# 初始化模型
model = AlexNet()
# 加载参数
state_dict = load_state_dict_from_url('https://download.pytorch.org/models/alexnet-owt-4df8aa71.pth',
progress=True)
model.load_state_dict(state_dict)
# 设置模式
model.eval()
# 生成ScriptModule并保存
script = torch.jit.script(model)
torch.jit.save(script, "alexnet.pt")
```
...@@ -88,6 +88,12 @@ def arg_parser(): ...@@ -88,6 +88,12 @@ def arg_parser():
action="store_true", action="store_true",
default=False, default=False,
help="define whether merge the params") help="define whether merge the params")
parser.add_argument(
"--input_shapes",
"-is",
action='append',
default=None,
help="define the inputs' shape")
return parser return parser
...@@ -174,6 +180,45 @@ def onnx2paddle(model_path, save_dir, params_merge=False): ...@@ -174,6 +180,45 @@ def onnx2paddle(model_path, save_dir, params_merge=False):
print("Paddle model and code generated.") print("Paddle model and code generated.")
def pytorch2paddle(model_path, save_dir, input_shapes):
# check pytorch installation and version
try:
import torch
version = torch.__version__
ver_part = version.split('.')
print(ver_part)
if int(ver_part[1]) < 5:
print("[ERROR] pytorch>=1.5.0 is required")
return
except:
print(
"[ERROR] Pytorch is not installed, use \"pip install torch==1.5.0 torchvision\"."
)
return
print("Now translating model from pytorch to paddle.")
from x2paddle.decoder.pytorch_decoder import PyTorchDecoder
from x2paddle.op_mapper.pytorch2paddle import pytorch_op_mapper
model = PyTorchDecoder(model_path)
mapper = pytorch_op_mapper.PyTorchOpMapper(model)
mapper.graph.build()
print("Model optimizing ...")
from x2paddle.optimizer.optimizer import GraphOptimizer
graph_opt = GraphOptimizer()
graph_opt.optimize(mapper.graph)
print("Model optimized.")
if input_shapes is not None:
real_input_shapes = list()
for shape in input_shapes:
sp = shape[1:-1].split(",")
for i, s in enumerate(sp):
sp[i] = int(s)
real_input_shapes.append(sp)
else:
real_input_shapes = None
mapper.graph.gen_model(save_dir, real_input_shapes)
def paddle2onnx(model_path, save_dir, opset_version=10): def paddle2onnx(model_path, save_dir, opset_version=10):
from x2paddle.decoder.paddle_decoder import PaddleDecoder from x2paddle.decoder.paddle_decoder import PaddleDecoder
from x2paddle.op_mapper.paddle2onnx.paddle_op_mapper import PaddleOpMapper from x2paddle.op_mapper.paddle2onnx.paddle_op_mapper import PaddleOpMapper
...@@ -243,6 +288,9 @@ def main(): ...@@ -243,6 +288,9 @@ def main():
if args.params_merge: if args.params_merge:
params_merge = True params_merge = True
onnx2paddle(args.model, args.save_dir, params_merge) onnx2paddle(args.model, args.save_dir, params_merge)
elif args.framework == "pytorch":
assert args.model is not None, "--model should be defined while translating pytorch model"
pytorch2paddle(args.model, args.save_dir, args.input_shapes)
elif args.framework == "paddle2onnx": elif args.framework == "paddle2onnx":
assert args.model is not None, "--model should be defined while translating paddle model to onnx" assert args.model is not None, "--model should be defined while translating paddle model to onnx"
......
...@@ -15,6 +15,8 @@ ...@@ -15,6 +15,8 @@
from __future__ import print_function from __future__ import print_function
from __future__ import division from __future__ import division
import paddle.fluid as fluid import paddle.fluid as fluid
import os.path as osp
import paddle
from paddle.fluid.proto import framework_pb2 from paddle.fluid.proto import framework_pb2
from collections import OrderedDict from collections import OrderedDict
import numpy import numpy
...@@ -101,11 +103,6 @@ class PaddleGraph(object): ...@@ -101,11 +103,6 @@ class PaddleGraph(object):
self.clear_edges() self.clear_edges()
outputs_from_nodes = dict() outputs_from_nodes = dict()
for layer_id, layer in self.layers.items(): for layer_id, layer in self.layers.items():
# if "x5109" in layer.outputs or "x5110" in layer.outputs:
# print(layer.kernel)
# print(layer.inputs)
# print(layer.outputs)
# print(layer.attrs)
for input_key, input_var in layer.inputs.items(): for input_key, input_var in layer.inputs.items():
vs = input_var vs = input_var
if not isinstance(vs, list): if not isinstance(vs, list):
...@@ -131,12 +128,33 @@ class PaddleGraph(object): ...@@ -131,12 +128,33 @@ class PaddleGraph(object):
for output in layer.outputs: for output in layer.outputs:
outputs_from_nodes[output] = layer_id outputs_from_nodes[output] = layer_id
# 将block的输出用于父图
if inputs is not None and outputs is not None and set(
layer.outputs).issubset(outputs):
if layer_id not in self.edges_out:
self.edges_out[layer_id] = list()
self.edges_out[layer_id].append(-1)
# 处理子图
if len(layer.blocks) > 0: if len(layer.blocks) > 0:
for block in layer.blocks: for block in layer.blocks:
block.build(layer.inputs, layer.outputs) block.build(layer.inputs, layer.outputs)
# 删除不必要的节点
invalid_list = list()
for layer_id, layer in self.layers.items():
if len(self.layers) > 1:
if self.edges_in.get(layer_id, 0) == 0 and self.edges_out.get(
layer_id, 0) == 0 and layer.kernel != "prim.assert" \
and layer.kernel != "prim.exception" \
and layer.kernel != "prim.warnings":
invalid_list.append(layer_id)
for layer_id in invalid_list:
self.layers.pop(layer_id)
if self.graph_type == "dygraph": if self.graph_type == "dygraph":
self.get_dygraph_inputs() self.get_dygraph_inputs()
if len(self.outputs) == 0:
self.get_dygraph_outputs() self.get_dygraph_outputs()
def get_global_layers(self): def get_global_layers(self):
...@@ -169,8 +187,8 @@ class PaddleGraph(object): ...@@ -169,8 +187,8 @@ class PaddleGraph(object):
f, [ f, [
"from paddle.fluid.initializer import Constant", "from paddle.fluid.initializer import Constant",
"from paddle.fluid.param_attr import ParamAttr", "from paddle.fluid.param_attr import ParamAttr",
"import paddle.fluid as fluid" "import paddle.fluid as fluid", "import math", "",
"", "def x2paddle_net():" "def x2paddle_net():"
], ],
indent=0) indent=0)
for layer_id, layer in self.layers.items(): for layer_id, layer in self.layers.items():
...@@ -208,7 +226,9 @@ class PaddleGraph(object): ...@@ -208,7 +226,9 @@ class PaddleGraph(object):
indent=1) indent=1)
f.close() f.close()
def gen_model(self, save_dir): def gen_model(self, save_dir, input_shapes=None):
if not os.path.exists(save_dir):
os.makedirs(save_dir)
if self.graph_type == "static": if self.graph_type == "static":
code_dir = os.path.join(save_dir, 'model_with_code') code_dir = os.path.join(save_dir, 'model_with_code')
infer_dir = os.path.join(save_dir, 'inference_model') infer_dir = os.path.join(save_dir, 'inference_model')
...@@ -244,6 +264,9 @@ class PaddleGraph(object): ...@@ -244,6 +264,9 @@ class PaddleGraph(object):
else: else:
self.gen_dygraph_code(save_dir) self.gen_dygraph_code(save_dir)
self.dump_dygraph_parameter(save_dir) self.dump_dygraph_parameter(save_dir)
if input_shapes is not None:
# 如果input_shapes非空,则导出推理模型;其值类似[[None, 3, 224, 224]]
self.dygraph2static(save_dir, input_shapes)
def dump_parameter(self, param_name, param, save_dir): def dump_parameter(self, param_name, param, save_dir):
if not os.path.exists(save_dir): if not os.path.exists(save_dir):
...@@ -296,6 +319,8 @@ class PaddleGraph(object): ...@@ -296,6 +319,8 @@ class PaddleGraph(object):
update(self.layers) update(self.layers)
self.inputs = list(set(self.inputs)) self.inputs = list(set(self.inputs))
if self.inputs is not None:
self.inputs.sort()
def get_dygraph_outputs(self): def get_dygraph_outputs(self):
for layer_id, layer in self.layers.items(): for layer_id, layer in self.layers.items():
...@@ -325,6 +350,7 @@ class PaddleGraph(object): ...@@ -325,6 +350,7 @@ class PaddleGraph(object):
[ [
"from paddle.fluid.initializer import Constant", "from paddle.fluid.initializer import Constant",
"from paddle.fluid.param_attr import ParamAttr", "from paddle.fluid.param_attr import ParamAttr",
"import paddle",
"import paddle.fluid as fluid", "import paddle.fluid as fluid",
"", "",
"class {}(fluid.dygraph.Layer):".format(self.name), "class {}(fluid.dygraph.Layer):".format(self.name),
...@@ -343,7 +369,7 @@ class PaddleGraph(object): ...@@ -343,7 +369,7 @@ class PaddleGraph(object):
indent=1)) indent=1))
def write_code(code_dir): def write_code(code_dir):
f = open(os.path.join(code_dir, 'code.py'), 'w') f = open(os.path.join(code_dir, 'x2paddle_code.py'), 'w')
for code_line in self.head: for code_line in self.head:
f.write(code_line) f.write(code_line)
init_writen_codes = [] init_writen_codes = []
...@@ -365,13 +391,9 @@ class PaddleGraph(object): ...@@ -365,13 +391,9 @@ class PaddleGraph(object):
gen_head() gen_head()
for layer_id, layer in self.layers.items(): for layer_id, layer in self.layers.items():
if len(self.layers) > 1: if ("paddle.nn" in layer.kernel and "functional" not in layer.kernel
if self.edges_in.get(layer_id, 0) == 0 and self.edges_out.get( ) or layer.kernel == "fluid.dygraph.base.to_variable" or \
layer_id, 0) == 0 and layer.kernel != "prim.assert" \ "paddle.fluid.dygraph" in layer.kernel:
and layer.kernel != "prim.exception" \
and layer.kernel != "prim.warnings":
continue
if "dygraph" in layer.kernel:
line = "{}".format( line = "{}".format(
layer.outputs[0] layer.outputs[0]
) if layer.kernel == "fluid.dygraph.base.to_variable" and not layer.attrs[ ) if layer.kernel == "fluid.dygraph.base.to_variable" and not layer.attrs[
...@@ -442,3 +464,24 @@ class PaddleGraph(object): ...@@ -442,3 +464,24 @@ class PaddleGraph(object):
params_output = open(os.path.join(code_dir, 'model.pdparams'), 'wb') params_output = open(os.path.join(code_dir, 'model.pdparams'), 'wb')
pickle.dump(self.parameters, params_output) pickle.dump(self.parameters, params_output)
params_output.close() params_output.close()
def dygraph2static(self, save_dir, input_shapes=[]):
from paddle.fluid.dygraph.jit import declarative
sepc_list = list()
for i, name in enumerate(self.inputs):
sepc_list.append(
paddle.static.InputSpec(
shape=input_shapes[i], name=name))
import sys
path = osp.abspath(save_dir)
sys.path.insert(0, save_dir)
import x2paddle_code
place = fluid.CPUPlace()
with fluid.dygraph.guard(place):
restore, _ = fluid.load_dygraph(osp.join(save_dir, "model"))
model = getattr(x2paddle_code, self.name)(restore)
model.set_dict(restore)
model.eval()
model.forward = declarative(model.forward, sepc_list)
fluid.dygraph.jit.save(
layer=model, model_path=osp.join(save_dir, "inference"))
...@@ -28,6 +28,7 @@ class PyTorchDecoder(object): ...@@ -28,6 +28,7 @@ class PyTorchDecoder(object):
torch._C._jit_pass_lint(graph) torch._C._jit_pass_lint(graph)
torch._C._jit_pass_dce(graph) torch._C._jit_pass_dce(graph)
torch._C._jit_pass_lint(graph) torch._C._jit_pass_lint(graph)
graph = torch._C._jit_pass_canonicalize(graph) torch._C._jit_pass_canonicalize(graph)
torch._C._jit_pass_lint(graph) torch._C._jit_pass_lint(graph)
torch._C._jit_pass_constant_propagation(graph)
return graph return graph
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
# limitations under the License. # limitations under the License.
import torch import torch
import numpy as np
from x2paddle.core.util import * from x2paddle.core.util import *
...@@ -27,14 +28,56 @@ def prim_Constant(mapper, graph, node): ...@@ -27,14 +28,56 @@ def prim_Constant(mapper, graph, node):
output_name = mapper._get_outputs_name(node)[0] output_name = mapper._get_outputs_name(node)[0]
output = list(node.outputs())[0] output = list(node.outputs())[0]
value = output.toIValue() value = output.toIValue()
mapper.attrs[output_name] = value output_type = output.type()
if isinstance(value, str): if isinstance(value, str):
value = string(value) value = string(value)
if str(output_type) == "Tensor":
# value = "paddle.to_tensor({})".format(value)
value = "{}".format(value)
if "inf" in str(value):
t = str(type(value)).split("'")[1]
if str(value).startswith("-"):
value = "-{}({})".format(t, string(str(value)[1:]))
else:
value = "{}({})".format(t, string(str(value)))
if "9223372036854775807" in str(value):
import math
value = int(math.pow(2, 31) - 1)
mapper.attrs[output_name] = value
graph.add_layer( graph.add_layer(
"prim.constant", inputs={}, outputs=[output_name], value=value) "prim.constant", inputs={}, outputs=[output_name], value=value)
return [], [output_name] return [], [output_name]
def prim_data(mapper, graph, node):
""" 构造Tensor的PaddleLayer。
TorchScript示例:
%4336 : Tensor = prim::data(%out.6)
参数含义:
%4336 (Tensor): 输出Tensor。
%out.6 (Tensor): 原始Tensor。
【注意】Paddle中无此用法,所以此处翻译成赋值。
"""
output_name = mapper._get_outputs_name(node)[0]
layer_outputs = [output_name]
layer_inputs = {}
layer_attrs = {}
inputs_name, inputs_node = mapper._get_inputs_name(node)
# 获取当前节点输出的list
current_outputs = [output_name]
# 处理输入0,即%4336
mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs)
layer_inputs["input"] = inputs_name[0]
# 获取当前节点输入的list
current_inputs = list(layer_inputs.values())
graph.add_layer("prim.equal", inputs=layer_inputs, outputs=layer_outputs)
return current_inputs, current_outputs
def prim_GetAttr(mapper, graph, node): def prim_GetAttr(mapper, graph, node):
""" 获取attribute信息。 """ 获取attribute信息。
...@@ -61,11 +104,56 @@ def prim_GetAttr(mapper, graph, node): ...@@ -61,11 +104,56 @@ def prim_GetAttr(mapper, graph, node):
param = getattr(part_script, field_name) param = getattr(part_script, field_name)
if isinstance(param, torch.Tensor): if isinstance(param, torch.Tensor):
param = param.detach().numpy() param = param.detach().numpy()
if len(param.shape) == 0:
param = np.reshape(param, 1)
if str(param.dtype) == "uint8":
param = param.astype("int32")
mapper.pytorch_params[output_name] = param mapper.pytorch_params[output_name] = param
part_script = param part_script = param
return [], [output_name] return [], [output_name]
def prim_If(mapper, graph, node):
""" 构造if控制流的PaddleLayer。
TorchScript示例:
%input.5 : Tensor = prim::If(%107)
block0():
%109 : Tensor = aten::t(%102)
%ret.2 : Tensor = aten::addmm(%103, %101, %109, %104, %104)
-> (%ret.2)
block1():
%111 : Tensor = aten::t(%102)
...
-> (%output.4)
参数含义:
%107 (bool): if判断条件。
%input.5 (Tensor): if控制流的输出,与%output.4对应。
"""
outputs_name = mapper._get_outputs_name(node)
node_outputs = outputs_name.copy()
current_outputs = outputs_name.copy()
input_node = list(node.inputs())[0].node()
script_input_unique_id = list(node.inputs())[0].unique()
input_node_name = mapper.outputs_info[script_input_unique_id]
mapper._check_input(graph, input_node, input_node_name, current_outputs)
graph.add_layer("prim.if", {'input': input_node_name}, node_outputs)
current_layer = list(graph.layers.values())[-1]
block0 = list(node.blocks())[0]
block0_graph, graph_inputs0 = mapper.traverse(block0, current_layer)
len0 = 0
for i, input_name in enumerate(graph_inputs0):
current_layer.inputs['input-{}'.format(i)] = input_name
len0 = i
current_layer.add_block(block0_graph)
block1 = list(node.blocks())[1]
block1_graph, graph_inputs1 = mapper.traverse(block1, current_layer)
for i, input_name in enumerate(graph_inputs1):
current_layer.inputs['input-{}'.format(len0 + 1 + i)] = input_name
current_layer.add_block(block1_graph)
return list(current_layer.inputs.values()), current_outputs
def prim_ListConstruct(mapper, graph, node): def prim_ListConstruct(mapper, graph, node):
""" 构造list的PaddleLayer。 """ 构造list的PaddleLayer。
...@@ -92,28 +180,31 @@ def prim_ListConstruct(mapper, graph, node): ...@@ -92,28 +180,31 @@ def prim_ListConstruct(mapper, graph, node):
return current_inputs, current_outputs return current_inputs, current_outputs
def prim_RaiseException(mapper, graph, node): def prim_ListUnpack(mapper, graph, node):
""" 构造抛出异常的PaddleLayer。 """ 构造获取list中元素的PaddleLayer。
TorchScript示例: TorchScript示例:
= prim::RaiseException(%76) %x1.4 : Tensor, %x2.4 : Tensor = prim::ListUnpack(%4354)
参数含义: 参数含义:
%76 (str): 异常信息。 %x1.4 (Tensor): 输出,list的第一个元素。
%x2.4 (Tensor): 输出,list的第二个元素。
%4354 (list): 列表。
""" """
output_name = mapper._get_outputs_name(node)[0] outputs_name = mapper._get_outputs_name(node)
layer_outputs = [output_name] layer_outputs = outputs_name.copy()
layer_inputs = {} layer_inputs = {}
inputs_name, inputs_node = mapper._get_inputs_name(node) inputs_name, inputs_node = mapper._get_inputs_name(node)
# 获取当前节点输出的list # 获取当前节点输出的list
current_outputs = [output_name] current_outputs = layer_outputs.copy()
# 处理输入0,即%76 # 处理输入0,即%4354
mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs)
layer_inputs["input"] = inputs_name[0] layer_inputs["input"] = inputs_name[0]
# 获取当前节点输入的list # 获取当前节点输入的list
current_inputs = list(layer_inputs.values()) current_inputs = list(layer_inputs.values())
graph.add_layer( graph.add_layer(
"prim.exception", inputs=layer_inputs, outputs=layer_outputs) "prim.list_unpack", inputs=layer_inputs, outputs=layer_outputs)
mapper.split_len[list(layer_inputs.values())[0]] = len(layer_outputs)
return current_inputs, current_outputs return current_inputs, current_outputs
...@@ -180,68 +271,93 @@ def prim_Loop(mapper, graph, node): ...@@ -180,68 +271,93 @@ def prim_Loop(mapper, graph, node):
return list(current_layer.inputs.values()), node_outputs return list(current_layer.inputs.values()), node_outputs
def prim_If(mapper, graph, node): def prim_min(mapper, graph, node):
""" 构造if控制流的PaddleLayer。 """ 构造min的PaddleLayer。
TorchScript示例: TorchScript示例:
%input.5 : Tensor = prim::If(%107) %87 : int = prim::min(%86)
block0():
%109 : Tensor = aten::t(%102)
%ret.2 : Tensor = aten::addmm(%103, %101, %109, %104, %104)
-> (%ret.2)
block1():
%111 : Tensor = aten::t(%102)
...
-> (%output.4)
参数含义: 参数含义:
%107 (bool): if判断条件 %86 (list): 输入
%input.5 (Tensor): if控制流的输出,与%output.4对应 %87 (int): 输出
""" """
output_name = mapper._get_outputs_name(node)[0] output_name = mapper._get_outputs_name(node)[0]
node_outputs = [output_name] layer_outputs = [output_name]
input_node = list(node.inputs())[0].node() layer_inputs = {}
script_input_unique_id = list(node.inputs())[0].unique() inputs_name, inputs_node = mapper._get_inputs_name(node)
input_node_name = mapper.outputs_info[script_input_unique_id] # 获取当前节点输出的list
mapper._check_input(graph, input_node, input_node_name, node_outputs) current_outputs = [output_name]
graph.add_layer("prim.if", {'input': input_node_name}, [output_name]) # 处理输入0,即%86
current_layer = list(graph.layers.values())[-1] mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs)
block0 = list(node.blocks())[0] layer_inputs["input"] = inputs_name[0]
block0_graph, graph_inputs0 = mapper.traverse(block0, current_layer) # 获取当前节点输入的list
len0 = 0 current_inputs = list(layer_inputs.values())
for i, input_name in enumerate(graph_inputs0):
current_layer.inputs['input-{}'.format(i)] = input_name
len0 = i
current_layer.add_block(block0_graph)
block1 = list(node.blocks())[1]
block1_graph, graph_inputs1 = mapper.traverse(block1, current_layer)
for i, input_name in enumerate(graph_inputs1):
current_layer.inputs['input-{}'.format(len0 + 1 + i)] = input_name
current_layer.add_block(block1_graph)
return list(current_layer.inputs.values()), node_outputs
graph.add_layer("prim.min", inputs=layer_inputs, outputs=layer_outputs)
return current_inputs, current_outputs
def prim_min(mapper, graph, node):
""" 构造min的PaddleLayer。 def prim_NumToTensor(mapper, graph, node):
""" 构造转为Tensor的PaddleLayer。
TorchScript示例: TorchScript示例:
%87 : int = prim::min(%86) %other.2 : Tensor = prim::NumToTensor(%1736)
参数含义: 参数含义:
%86 (list): 输入 %other.2 (Tensor): 输出
%87 (int): 输出 %1736 (-): 输入
""" """
output_name = mapper._get_outputs_name(node)[0] output_name = mapper._get_outputs_name(node)[0]
layer_outputs = [output_name] layer_outputs = [output_name]
layer_inputs = {} layer_inputs = {}
layer_attrs = {}
inputs_name, inputs_node = mapper._get_inputs_name(node) inputs_name, inputs_node = mapper._get_inputs_name(node)
# 获取当前节点输出的list # 获取当前节点输出的list
current_outputs = [output_name] current_outputs = [output_name]
# 处理输入0,即%86 # 处理输入0,即%86
mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs)
if inputs_node[0].kind() == "aten::size":
layer_inputs["input"] = inputs_name[0] layer_inputs["input"] = inputs_name[0]
# 获取当前节点输入的list # 获取当前节点输入的list
current_inputs = list(layer_inputs.values()) current_inputs = list(layer_inputs.values())
graph.add_layer(
"prim_equal", inputs=layer_inputs, outputs=layer_outputs)
else:
layer_inputs["value"] = inputs_name[0]
# 获取当前节点输入的list
current_inputs = list(layer_inputs.values())
input_type = list(node.inputs())[0].type()
layer_attrs["dtype"] = input_type
layer_attrs["persistable"] = True
layer_attrs["shape"] = [1]
graph.add_layer(
"fluid.layers.create_global_var",
inputs=layer_inputs,
outputs=layer_outputs,
**layer_attrs)
return current_inputs, current_outputs
graph.add_layer("prim.min", inputs=layer_inputs, outputs=layer_outputs)
def prim_RaiseException(mapper, graph, node):
""" 构造抛出异常的PaddleLayer。
TorchScript示例:
= prim::RaiseException(%76)
参数含义:
%76 (str): 异常信息。
"""
output_name = mapper._get_outputs_name(node)[0]
layer_outputs = [output_name]
layer_inputs = {}
inputs_name, inputs_node = mapper._get_inputs_name(node)
# 获取当前节点输出的list
current_outputs = [output_name]
# 处理输入0,即%76
mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs)
layer_inputs["input"] = inputs_name[0]
# 获取当前节点输入的list
current_inputs = list(layer_inputs.values())
graph.add_layer(
"prim.exception", inputs=layer_inputs, outputs=layer_outputs)
return current_inputs, current_outputs return current_inputs, current_outputs
...@@ -326,7 +442,8 @@ def prim_shape(mapper, graph, node): ...@@ -326,7 +442,8 @@ def prim_shape(mapper, graph, node):
# 获取当前节点输入的list # 获取当前节点输入的list
current_inputs = list(layer_inputs.values()) current_inputs = list(layer_inputs.values())
graph.add_layer("prim.shape", inputs=layer_inputs, outputs=layer_outputs) graph.add_layer(
"fluid.layers.shape", inputs=layer_inputs, outputs=layer_outputs)
return current_inputs, current_outputs return current_inputs, current_outputs
...@@ -381,6 +498,34 @@ def prim_TupleUnpack(mapper, graph, node): ...@@ -381,6 +498,34 @@ def prim_TupleUnpack(mapper, graph, node):
return current_inputs, current_outputs return current_inputs, current_outputs
def prim_unchecked_cast(mapper, graph, node):
""" 构造确认类型的PaddleLayer。
TorchScript示例:
%size.64 : int[] = prim::unchecked_cast(%size.63)
参数含义:
%size.64 (-): 输出。
%size.63 (-): 输入。
【注意】Paddle中无此用法,所以此处翻译成赋值。
"""
output_name = mapper._get_outputs_name(node)[0]
layer_outputs = [output_name]
layer_inputs = {}
layer_attrs = {}
inputs_name, inputs_node = mapper._get_inputs_name(node)
# 获取当前节点输出的list
current_outputs = [output_name]
# 处理输入0,即%size.63
mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs)
layer_inputs["input"] = inputs_name[0]
# 获取当前节点输入的list
current_inputs = list(layer_inputs.values())
graph.add_layer("prim.equal", inputs=layer_inputs, outputs=layer_outputs)
return current_inputs, current_outputs
def prim_Uninitialized(mapper, graph, node): def prim_Uninitialized(mapper, graph, node):
""" 构造表示编译器永远不会使用的值的PaddleLayer,该节点转换为None。 """ 构造表示编译器永远不会使用的值的PaddleLayer,该节点转换为None。
......
...@@ -62,28 +62,61 @@ def prim_append(layer, indent=1, init_func=[], forward_func=[]): ...@@ -62,28 +62,61 @@ def prim_append(layer, indent=1, init_func=[], forward_func=[]):
def prim_assert(layer, indent=1, init_func=[], forward_func=[]): def prim_assert(layer, indent=1, init_func=[], forward_func=[]):
if layer.attrs["type"] == "eq": if layer.attrs["type"] == "eq":
if isinstance(layer.attrs["value"], list): values = get_value(layer, "key")
if "value" in layer.attrs:
values = layer.attrs["value"]
if isinstance(values, list):
s = "" s = ""
for v in layer.attrs["value"]: for v in values:
s += "{} == {} or ".format(layer.attrs["key"], v) s += "{} == {} or ".format(get_value(layer, "key"), v)
if len(s) > 0: if len(s) > 0:
s = s[:-4] s = s[:-4]
line = "assert {}, \'The {} must be {}!\'".format( line = "assert {}, \'The {} must be {}!\'".format(
s, layer.attrs["key"], layer.attrs["value"]) s, get_value(layer, "key"), get_value(layer, "value"))
else: else:
line = "assert {} == {}, \'The {} must be {}!\'".format( line = "assert {} == {}, \'The {} must be {}!\'".format(
layer.attrs["key"], layer.attrs["value"], layer.attrs["key"], get_value(layer, "key"),
layer.attrs["value"]) get_value(layer, "value"),
get_value(layer, "key"), get_value(layer, "value"))
else: else:
raise Exception("Not implement yet!") raise Exception("Not implement yet!")
forward_func.extend(gen_codes([line], indent=indent)) forward_func.extend(gen_codes([line], indent=indent))
def prim_check_dim(layer, indent=1, init_func=[], forward_func=[]):
lines = []
lines.append("if {} < 0:".format(get_value(layer, "dim")))
lines.append(" {} = {} + {}".format(layer.outputs[
0], get_value(layer, "dim"), get_value(layer, "len")))
lines.append("else:")
lines.append(" {} = {}".format(layer.outputs[0], get_value(layer,
"dim")))
forward_func.extend(gen_codes(lines, indent=indent))
def prim_constant(layer, indent=1, init_func=[], forward_func=[]): def prim_constant(layer, indent=1, init_func=[], forward_func=[]):
line = "{} = {}".format(layer.outputs[0], layer.attrs["value"]) line = "{} = {}".format(layer.outputs[0], layer.attrs["value"])
forward_func.extend(gen_codes([line], indent=indent)) forward_func.extend(gen_codes([line], indent=indent))
def prim_contain(layer, indent=1, init_func=[], forward_func=[]):
line = "{} = {} in {}".format(layer.outputs[0],
get_value(layer, "element"),
get_value(layer, "input"))
forward_func.extend(gen_codes([line], indent=indent))
def prim_dict(layer, indent=1, init_func=[], forward_func=[]):
line = "{} = dict()".format(layer.outputs[0])
forward_func.extend(gen_codes([line], indent=indent))
def prim_div(layer, indent=1, init_func=[], forward_func=[]):
line = "{} = {} / {}".format(layer.outputs[0],
get_value(layer, "x"), get_value(layer, "y"))
forward_func.extend(gen_codes([line], indent=indent))
def prim_eq(layer, indent=1, init_func=[], forward_func=[]): def prim_eq(layer, indent=1, init_func=[], forward_func=[]):
line = "{} = {} == {}".format(layer.outputs[0], line = "{} = {} == {}".format(layer.outputs[0],
get_value(layer, "x"), get_value(layer, "y")) get_value(layer, "x"), get_value(layer, "y"))
...@@ -100,6 +133,36 @@ def prim_exception(layer, indent=1, init_func=[], forward_func=[]): ...@@ -100,6 +133,36 @@ def prim_exception(layer, indent=1, init_func=[], forward_func=[]):
forward_func.extend(gen_codes([line], indent=indent)) forward_func.extend(gen_codes([line], indent=indent))
def prim_float(layer, indent=1, init_func=[], forward_func=[]):
line = "{} = float({})".format(layer.outputs[0], get_value(layer, "input"))
forward_func.extend(gen_codes([line], indent=indent))
def prim_floor(layer, indent=1, init_func=[], forward_func=[]):
line = "{} = math.floor({})".format(layer.outputs[0],
get_value(layer, "input"))
forward_func.extend(gen_codes([line], indent=indent))
def prim_floordiv(layer, indent=1, init_func=[], forward_func=[]):
line = "{} = {} // {}".format(layer.outputs[0],
get_value(layer, "x"), get_value(layer, "y"))
forward_func.extend(gen_codes([line], indent=indent))
def prim_getitem(layer, indent=1, init_func=[], forward_func=[]):
line = "{} = {}[{}]".format(layer.outputs[0],
get_value(layer, "list"),
get_value(layer, "index"))
forward_func.extend(gen_codes([line], indent=indent))
def prim_gt(layer, indent=1, init_func=[], forward_func=[]):
line = "{} = {} > {}".format(layer.outputs[0],
get_value(layer, "x"), get_value(layer, "y"))
forward_func.extend(gen_codes([line], indent=indent))
def prim_if(layer, indent=1, init_func=[], forward_func=[]): def prim_if(layer, indent=1, init_func=[], forward_func=[]):
line = "if {} :".format(get_value(layer, "input")) line = "if {} :".format(get_value(layer, "input"))
forward_func.extend(gen_codes([line], indent=indent)) forward_func.extend(gen_codes([line], indent=indent))
...@@ -109,27 +172,40 @@ def prim_if(layer, indent=1, init_func=[], forward_func=[]): ...@@ -109,27 +172,40 @@ def prim_if(layer, indent=1, init_func=[], forward_func=[]):
forward_func.extend(b_forward_lines) forward_func.extend(b_forward_lines)
block = layer.blocks[1] block = layer.blocks[1]
if len(block.layers) > 0: if len(block.layers) > 0:
line = "else:"
forward_func.extend(gen_codes([line], indent=indent))
b_init_lines, b_forward_lines = block.gen_dygraph_code( b_init_lines, b_forward_lines = block.gen_dygraph_code(
indent=indent + 1) indent=indent + 1)
if len(b_forward_lines) != 0:
line = "else:"
forward_func.extend(gen_codes([line], indent=indent))
init_func.extend(b_init_lines) init_func.extend(b_init_lines)
forward_func.extend(b_forward_lines) forward_func.extend(b_forward_lines)
def prim_getitem(layer, indent=1, init_func=[], forward_func=[]): def prim_int(layer, indent=1, init_func=[], forward_func=[]):
line = "{} = {}[{}]".format(layer.outputs[0], line = "{} = int({})".format(layer.outputs[0], get_value(layer, "input"))
get_value(layer, "list"),
get_value(layer, "index"))
forward_func.extend(gen_codes([line], indent=indent)) forward_func.extend(gen_codes([line], indent=indent))
def prim_gt(layer, indent=1, init_func=[], forward_func=[]): def prim_is(layer, indent=1, init_func=[], forward_func=[]):
line = "{} = {} > {}".format(layer.outputs[0], line = "{} = {} is {}".format(layer.outputs[0],
get_value(layer, "x"), get_value(layer, "y")) get_value(layer, "x"), get_value(layer, "y"))
forward_func.extend(gen_codes([line], indent=indent)) forward_func.extend(gen_codes([line], indent=indent))
def prim_isinstance(layer, indent=1, init_func=[], forward_func=[]):
line = "{} = isinstance({}, {})".format(layer.outputs[0],
get_value(layer, "input"),
layer.attrs["cls"])
forward_func.extend(gen_codes([line], indent=indent))
def prim_isnot(layer, indent=1, init_func=[], forward_func=[]):
line = "{} = {} is not {}".format(layer.outputs[0],
get_value(layer, "x"),
get_value(layer, "y"))
forward_func.extend(gen_codes([line], indent=indent))
def prim_le(layer, indent=1, init_func=[], forward_func=[]): def prim_le(layer, indent=1, init_func=[], forward_func=[]):
line = "{} = {} <= {}".format(layer.outputs[0], line = "{} = {} <= {}".format(layer.outputs[0],
get_value(layer, "x"), get_value(layer, "y")) get_value(layer, "x"), get_value(layer, "y"))
...@@ -141,6 +217,14 @@ def prim_len(layer, indent=1, init_func=[], forward_func=[]): ...@@ -141,6 +217,14 @@ def prim_len(layer, indent=1, init_func=[], forward_func=[]):
forward_func.extend(gen_codes([line], indent=indent)) forward_func.extend(gen_codes([line], indent=indent))
def prim_len2list(layer, indent=1, init_func=[], forward_func=[]):
lines = []
lines.append("{} = []".format(layer.outputs[0]))
lines.append("for i in range({}):".format(get_value(layer, "len")))
lines.append(" {}.append(i)".format(layer.outputs[0]))
forward_func.extend(gen_codes(lines, indent=indent))
def prim_lt(layer, indent=1, init_func=[], forward_func=[]): def prim_lt(layer, indent=1, init_func=[], forward_func=[]):
line = "{} = {} < {}".format(layer.outputs[0], line = "{} = {} < {}".format(layer.outputs[0],
get_value(layer, "x"), get_value(layer, "y")) get_value(layer, "x"), get_value(layer, "y"))
...@@ -157,6 +241,11 @@ def prim_list(layer, indent=1, init_func=[], forward_func=[]): ...@@ -157,6 +241,11 @@ def prim_list(layer, indent=1, init_func=[], forward_func=[]):
forward_func.extend(gen_codes([line], indent=indent)) forward_func.extend(gen_codes([line], indent=indent))
def prim_list_unpack(layer, indent=1, init_func=[], forward_func=[]):
line = "{} = {}".format(", ".join(layer.outputs), get_value(layer, "input"))
forward_func.extend(gen_codes([line], indent=indent))
def prim_loop(layer, indent=1, init_func=[], forward_func=[]): def prim_loop(layer, indent=1, init_func=[], forward_func=[]):
loop_range = get_value(layer, "input") loop_range = get_value(layer, "input")
line = "for {} in range({}):".format(layer.outputs[1], loop_range) line = "for {} in range({}):".format(layer.outputs[1], loop_range)
...@@ -194,12 +283,33 @@ def prim_not(layer, indent=1, init_func=[], forward_func=[]): ...@@ -194,12 +283,33 @@ def prim_not(layer, indent=1, init_func=[], forward_func=[]):
forward_func.extend(gen_codes([line], indent=indent)) forward_func.extend(gen_codes([line], indent=indent))
def prim_or(layer, indent=1, init_func=[], forward_func=[]):
line = "{} = {} or {}".format(layer.outputs[0],
get_value(layer, "x"), get_value(layer, "y"))
forward_func.extend(gen_codes([line], indent=indent))
def prim_replaceitem(layer, indent=1, init_func=[], forward_func=[]):
line = "{}[{}] = {}".format(
get_value(layer, "list"),
get_value(layer, "index"), get_value(layer, "item"))
forward_func.extend(gen_codes([line], indent=indent))
def prim_requires_grad(layer, indent=1, init_func=[], forward_func=[]): def prim_requires_grad(layer, indent=1, init_func=[], forward_func=[]):
line = "{} = not {}.stop_gradient".format(layer.outputs[0], line = "{} = not {}.stop_gradient".format(layer.outputs[0],
get_value(layer, "input")) get_value(layer, "input"))
forward_func.extend(gen_codes([line], indent=indent)) forward_func.extend(gen_codes([line], indent=indent))
def prim_rsub(layer, indent=1, init_func=[], forward_func=[]):
line = "{} = {} - {} * {}".format(layer.outputs[0],
get_value(layer, "y"),
get_value(layer, "x"),
get_value(layer, "alpha"))
forward_func.extend(gen_codes([line], indent=indent))
def prim_select(layer, indent=1, init_func=[], forward_func=[]): def prim_select(layer, indent=1, init_func=[], forward_func=[]):
line = "{} = {}[".format(layer.outputs[0], get_value(layer, "input")) line = "{} = {}[".format(layer.outputs[0], get_value(layer, "input"))
for dim in range(layer.attrs["dim"]): for dim in range(layer.attrs["dim"]):
...@@ -213,8 +323,17 @@ def prim_set_attr(layer, indent=1, init_func=[], forward_func=[]): ...@@ -213,8 +323,17 @@ def prim_set_attr(layer, indent=1, init_func=[], forward_func=[]):
forward_func.extend(gen_codes([line], indent=indent)) forward_func.extend(gen_codes([line], indent=indent))
def prim_shape(layer, indent=1, init_func=[], forward_func=[]): def prim_set_item(layer, indent=1, init_func=[], forward_func=[]):
line = "{} = {}.shape".format(layer.outputs[0], get_value(layer, "input")) line = "{}[{}] = {}".format(
get_value(layer, "dict"),
get_value(layer, "key"), get_value(layer, "value"))
forward_func.extend(gen_codes([line], indent=indent))
def prim_shape_dim(layer, indent=1, init_func=[], forward_func=[]):
line = "{} = fluid.layers.shape({})[{}]".format(layer.outputs[0],
get_value(layer, "input"),
get_value(layer, "dim"))
forward_func.extend(gen_codes([line], indent=indent)) forward_func.extend(gen_codes([line], indent=indent))
...@@ -227,6 +346,11 @@ def prim_slice(layer, indent=1, init_func=[], forward_func=[]): ...@@ -227,6 +346,11 @@ def prim_slice(layer, indent=1, init_func=[], forward_func=[]):
forward_func.extend(gen_codes([line], indent=indent)) forward_func.extend(gen_codes([line], indent=indent))
def prim_str(layer, indent=1, init_func=[], forward_func=[]):
line = "{} = str({})".format(layer.outputs[0], get_value(layer, "input"))
forward_func.extend(gen_codes([line], indent=indent))
def prim_sub(layer, indent=1, init_func=[], forward_func=[]): def prim_sub(layer, indent=1, init_func=[], forward_func=[]):
line = "{} = {} - {}".format(layer.outputs[0], line = "{} = {} - {}".format(layer.outputs[0],
get_value(layer, "x"), get_value(layer, "y")) get_value(layer, "x"), get_value(layer, "y"))
...@@ -249,6 +373,17 @@ def prim_tuple_unpack(layer, indent=1, init_func=[], forward_func=[]): ...@@ -249,6 +373,17 @@ def prim_tuple_unpack(layer, indent=1, init_func=[], forward_func=[]):
forward_func.extend(gen_codes([line], indent=indent)) forward_func.extend(gen_codes([line], indent=indent))
def prim_type(layer, indent=1, init_func=[], forward_func=[]):
line = "{} = {}.dtype".format(layer.outputs[0], get_value(layer, "input"))
forward_func.extend(gen_codes([line], indent=indent))
def prim_var2list(layer, indent=1, init_func=[], forward_func=[]):
line = "{} = {}.numpy().tolist()".format(layer.outputs[0],
get_value(layer, "input"))
forward_func.extend(gen_codes([line], indent=indent))
def prim_warnings(layer, indent=1, init_func=[], forward_func=[]): def prim_warnings(layer, indent=1, init_func=[], forward_func=[]):
lines = ["import warnings"] lines = ["import warnings"]
line = "warnings.warn({}, stacklevel={})".format( line = "warnings.warn({}, stacklevel={})".format(
......
...@@ -31,6 +31,7 @@ class PyTorchOpMapper(OpMapper): ...@@ -31,6 +31,7 @@ class PyTorchOpMapper(OpMapper):
self.attrs = {} # key为节点名,value为属性值 self.attrs = {} # key为节点名,value为属性值
self.output_index = 0 self.output_index = 0
self.dygraph_name_id = {} # 动态图__init__输出名字中的id,key为kernel类型,value为id self.dygraph_name_id = {} # 动态图__init__输出名字中的id,key为kernel类型,value为id
self.split_len = {} # split的长度
# 转换 # 转换
self.check_op(decoder.graph) self.check_op(decoder.graph)
self.graph, _ = self.traverse(decoder.graph) self.graph, _ = self.traverse(decoder.graph)
...@@ -80,6 +81,7 @@ class PyTorchOpMapper(OpMapper): ...@@ -80,6 +81,7 @@ class PyTorchOpMapper(OpMapper):
node = ivalue.node() node = ivalue.node()
if str(ivalue.type()) != "Tensor": if str(ivalue.type()) != "Tensor":
graph.set_name(str(ivalue.type()).split(".")[-1]) graph.set_name(str(ivalue.type()).split(".")[-1])
continue
inputs, outputs = self.data(graph, node, ivalue.unique()) inputs, outputs = self.data(graph, node, ivalue.unique())
# 转换中间节点 # 转换中间节点
for node in script_graph.nodes(): for node in script_graph.nodes():
...@@ -108,9 +110,19 @@ class PyTorchOpMapper(OpMapper): ...@@ -108,9 +110,19 @@ class PyTorchOpMapper(OpMapper):
parent_layer=parent_layer, parent_layer=parent_layer,
index=i) index=i)
_update_graph_inputs("equal", inputs, outputs) _update_graph_inputs("equal", inputs, outputs)
# 设置graph的参数
# 设置graph的参数和输出节点
if isinstance(script_graph, torch._C.Graph): if isinstance(script_graph, torch._C.Graph):
graph.set_parameters(self.paddle_params) graph.set_parameters(self.paddle_params)
if hasattr(script_graph, 'return_node'):
inputs_name, inputs_node = self._get_inputs_name(
script_graph.return_node())
graph.outputs = inputs_name
# 更新split参数
for layer in graph.layers.values():
if layer.kernel == "fluid.layers.split" and "num_or_sections" in layer.attrs:
layer.attrs["num_or_sections"] = self.split_len[layer.outputs[
0]]
return graph, graph_inputs return graph, graph_inputs
def _get_outputs_name(self, node, attr_name=None): def _get_outputs_name(self, node, attr_name=None):
......
...@@ -12,13 +12,17 @@ ...@@ -12,13 +12,17 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
from .fc_fuser import FcFuser from .adaptive_pool2d_fuser import AdaptivePool2dFuser
from .fc_fuse_pass import FcFusePass from .adaptive_pool2d_fuse_pass import AdaptivePool2dFusePass
from .nn_adaptive_pool2d_fuser import NnAdaptivePool2dFuser
from .nn_adaptive_pool2d_fuse_pass import NnAdaptivePool2dFusePass
from .functional_adaptive_pool2d_fuser import FunctionalAdaptivePool2dFuser
from .functional_adaptive_pool2d_fuse_pass import FunctionalAdaptivePool2dFusePass
from .constant_fuser import ConstantFuser
from .constant_fuse_pass import ConstantFusePass
from .batchnorm2d_fuser import BatchNorm2dFuser from .batchnorm2d_fuser import BatchNorm2dFuser
from .batchnorm2d_fuse_pass import BatchNorm2dFusePass from .batchnorm2d_fuse_pass import BatchNorm2dFusePass
from .constant_fuser import ConstantFuser
from .constant_fuse_pass import ConstantFusePass
from .dropout_fuser import DropoutFuser
from .dropout_fuse_pass import DropoutFusePass
from .fc_fuser import FcFuser
from .fc_fuse_pass import FcFusePass
from .interpolate_bilinear_fuser import InterpolateBilinearFuser
from .interpolate_bilinear_fuse_pass import InterpolateBilinearFusePass
from .reshape_fuser import ReshapeFuser
from .reshape_fuse_pass import ReshapeFusePass
# Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from x2paddle.optimizer.pass_ import Pass
from x2paddle.optimizer.fusion import AdaptivePool2dFuser
from x2paddle.optimizer.pass_manager import pass_register
@pass_register
class AdaptivePool2dFusePass(Pass):
name = "adaptive_pool2d_fuse_pass"
def __init__(self):
Pass.__init__(self)
def apply(self, graph):
fuser = AdaptivePool2dFuser()
fuser.operate(graph, match_kind="topo")
# 用于注册
adaptive_pool2d_fuse_pass = AdaptivePool2dFusePass()
# Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import numpy as np
from x2paddle.optimizer.pattern_matcher import FuseBase
from x2paddle.core.program import PaddleGraph, PaddleLayer
from x2paddle.core.util import *
class AdaptivePool2dFuser(FuseBase):
def __init__(self):
super(AdaptivePool2dFuser, self).__init__(graph_type="dygraph")
def build_pattern(self):
""" 描述需要替换的adaptive pool2d图结构。
adaptive pool2d层模式python实现代码示例:
x68 = fluid.layers.shape(input=x60)
x69 = len(x68)
x70 = x69 <= 2
if x70 :
raise RaiseException('Exception')
x73 = []
x74 = x68[-2: 2147483647: 1]
x75 = len(x74)
x76 = [2, x75]
x77 = min(x76)
for _x79 in range(x77):
x80 = [6, 6][_x79]
x73.append(x80)
x81 = fluid.layers.adaptive_pool2d(input=x60, pool_size=x73, pool_type='avg')
"""
def gen_name(id):
return "x" + str(id)
self.pattern.add_layer(
"fluid.layers.shape",
inputs={'input': "pool-input-0"},
outputs=[gen_name(1)])
self.pattern.add_layer(
"prim.len", inputs={"input": gen_name(1)}, outputs=[gen_name(6)])
self.pattern.add_layer(
"prim.le", inputs={"x": gen_name(6)}, outputs=[gen_name(8)], y=2)
self.pattern.add_layer("prim.if", {'input': gen_name(8)}, [gen_name(9)])
if_layer = self.pattern.layers[list(self.pattern.layers.keys())[-1]]
pattern_block0 = PaddleGraph(if_layer, graph_type="dygraph")
pattern_block0.add_layer(
"prim.exception",
inputs={},
outputs=[gen_name(9)],
input="Exception")
if_layer.add_block(pattern_block0)
pattern_block1 = PaddleGraph(if_layer, graph_type="dygraph")
if_layer.add_block(pattern_block1)
self.pattern.add_layer("prim.list", inputs={}, outputs=[gen_name(10)])
self.pattern.add_layer(
"prim.slice",
inputs={"input": gen_name(1), },
outputs=[gen_name(12)],
start=-1,
end=100,
step=1)
self.pattern.add_layer(
"prim.len", inputs={"input": gen_name(12)}, outputs=[gen_name(14)])
self.pattern.add_layer(
"prim.list",
inputs={"input1": gen_name(14)},
outputs=[gen_name(15)],
input0=2)
self.pattern.add_layer(
"prim.min", inputs={"input": gen_name(15)}, outputs=[gen_name(16)])
self.pattern.add_layer("prim.loop", {'input': gen_name(16)},
[gen_name(17), gen_name(18)])
loop_layer = self.pattern.layers[list(self.pattern.layers.keys())[-1]]
pattern_block = PaddleGraph(loop_layer, graph_type="dygraph")
pattern_block.add_layer(
"prim.getitem",
inputs={"index": gen_name(18)},
outputs=[gen_name(19)],
list=[6, 6])
pattern_block.add_layer(
"prim.append",
inputs={"list": gen_name(10),
"index": gen_name(19)},
outputs=[gen_name(20)])
loop_layer.inputs["input-0"] = gen_name(10)
loop_layer.add_block(pattern_block)
pool_attrs = {'pool_type': string("avg")}
self.pattern.add_layer(
"fluid.layers.adaptive_pool2d",
inputs={'input': "pool-input-0",
"pool_size": gen_name(10)},
outputs=[gen_name(21)],
**pool_attrs)
self.pattern.build(inputs={"input-0": "pool-input-0", })
def insert_new_layer(self, graph, parameters, matches):
parameters = graph.parameters
new_layer = self.gen_new_layer(parameters, matches)
new_layer_id = list(matches.keys())[0]
graph.layers[new_layer_id] = new_layer
matches.pop(new_layer_id)
def gen_new_layer(self, parameters, matches):
layers_id = list(matches.keys())
layer = matches[layers_id[11]]
pool_size = layer.attrs["list"]
layer = matches[layers_id[0]]
input_name = layer.inputs["input"]
layer = matches[layers_id[-1]]
output_name = layer.outputs[0]
pool_type = layer.attrs["pool_type"]
attrs = dict()
attrs["pool_size"] = pool_size
attrs["pool_type"] = pool_type
new_layer = PaddleLayer(
layers_id[0],
"fluid.layers.adaptive_pool2d",
inputs={"input": input_name},
outputs=[output_name],
**attrs)
return new_layer
# Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from x2paddle.optimizer.pass_ import Pass
from x2paddle.optimizer.fusion import BatchNorm2dFuser
from x2paddle.optimizer.pass_manager import pass_register
@pass_register
class BatchNorm2dFusePass(Pass):
name = "batchnorm2d_fuse_pass"
def __init__(self):
Pass.__init__(self)
def apply(self, graph):
fuser = BatchNorm2dFuser()
fuser.operate(graph, match_kind="topo")
# 用于注册
batchnorm2d_fuse_pass = BatchNorm2dFusePass()
# Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import numpy as np
from x2paddle.optimizer.pattern_matcher import FuseBase
from x2paddle.core.program import PaddleGraph, PaddleLayer
from x2paddle.core.util import *
class BatchNorm2dFuser(FuseBase):
def __init__(self):
super(BatchNorm2dFuser, self).__init__(graph_type="dygraph")
def build_pattern(self):
""" 描述需要替换的batchnorm2d图结构。
batchnorm2d层模式python实现代码示例:
x336 = fluid.layers.shape(input=x334)
x336 = len(x336)
x337 = x336 != 4
if x337 :
raise RaiseException('Exception')
if False :
x351 = fluid.layers.shape(input=x334)
x352 = x351[0]
x353 = len(x351)
x354 = x353 - 2
x357 = x352
for _x356 in range(x354):
x358 = _x356 + 2
x359 = x351[x358]
x360 = x357 * x359
x355 = x360
x361 = x355 == 1
if x361 :
raise RaiseException('Exception')
x364 = self.batchnorm7(x334)
"""
def gen_name(id):
return "x" + str(id)
self.pattern.add_layer(
"fluid.layers.shape",
inputs={'input': "bn-input-0"},
outputs=[gen_name(0)])
self.pattern.add_layer(
"prim.len", inputs={'input': gen_name(0)}, outputs=[gen_name(0)])
self.pattern.add_layer(
"prim.ne", inputs={"x": gen_name(0)}, outputs=[gen_name(1)], y=4)
self.pattern.add_layer("prim.if", {'input': gen_name(1)}, [gen_name(2)])
if_layer1 = self.pattern.layers[list(self.pattern.layers.keys())[-1]]
pattern_block0 = PaddleGraph(if_layer1, graph_type="dygraph")
pattern_block0.add_layer(
"prim.exception",
inputs={},
outputs=[gen_name(3)],
input="Exception")
if_layer1.add_block(pattern_block0)
pattern_block1 = PaddleGraph(if_layer1, graph_type="dygraph")
if_layer1.add_block(pattern_block1)
self.pattern.add_layer("prim.if", {}, [gen_name(4)], input=False)
if_layer2 = self.pattern.layers[list(self.pattern.layers.keys())[-1]]
pattern_block0 = PaddleGraph(if_layer2, graph_type="dygraph")
pattern_block0.add_layer(
"fluid.layers.shape",
inputs={'input': "bn-input-0"},
outputs=[gen_name(5)])
pattern_block0.add_layer(
"prim.getitem",
inputs={"list": gen_name(5)},
outputs=[gen_name(6)],
index=0)
pattern_block0.add_layer(
"prim.len", inputs={"input": gen_name(5)}, outputs=[gen_name(7)])
pattern_block0.add_layer(
"prim.sub", inputs={"x": gen_name(7)}, outputs=[gen_name(8)], y=2)
pattern_block0.add_layer(
"prim.equal", inputs={"input": gen_name(6)}, outputs=[gen_name(9)])
pattern_block0.add_layer(
"prim.loop",
inputs={"input": gen_name(8)},
outputs=[gen_name(8.1), gen_name(10)])
loop_layer = pattern_block0.layers[list(pattern_block0.layers.keys())[
-1]]
pattern_block0_block0 = PaddleGraph(loop_layer, graph_type="dygraph")
pattern_block0_block0.add_layer(
"prim.add", inputs={"x": gen_name(10)}, outputs=[gen_name(11)], y=2)
pattern_block0_block0.add_layer(
"prim.getitem",
inputs={"list": gen_name(5),
"index": gen_name(11)},
outputs=[gen_name(12)])
pattern_block0_block0.add_layer(
"prim.mul",
inputs={"x": gen_name(9),
"y": gen_name(12)},
outputs=[gen_name(13)])
pattern_block0_block0.add_layer(
"prim.equal",
inputs={"input": gen_name(13)},
outputs=[gen_name(8.1)])
loop_layer.inputs["input-1"] = gen_name(5)
loop_layer.inputs["input-2"] = gen_name(9)
loop_layer.add_block(pattern_block0_block0)
pattern_block0.add_layer(
"prim.eq", inputs={"x": gen_name(8.1)}, outputs=[gen_name(14)], y=1)
pattern_block0.add_layer(
"prim.if", inputs={"input": gen_name(14)}, outputs=[gen_name(15)])
if_layer21 = pattern_block0.layers[list(pattern_block0.layers.keys())[
-1]]
pattern_block0_block0 = PaddleGraph(if_layer21, graph_type="dygraph")
pattern_block0_block0.add_layer(
"prim.exception",
inputs={},
outputs=[gen_name(15)],
input="Exception")
if_layer21.add_block(pattern_block0_block0)
pattern_block0_block1 = PaddleGraph(if_layer21, graph_type="dygraph")
if_layer21.add_block(pattern_block0_block1)
if_layer2.add_block(pattern_block0)
pattern_block1 = PaddleGraph(if_layer2, graph_type="dygraph")
if_layer2.add_block(pattern_block1)
if_layer2.inputs["input-0"] = "bn-input-0"
self.pattern.add_layer(
"paddle.nn.BatchNorm",
inputs={"input": "bn-input-0"},
outputs=[gen_name(16), gen_name(17)],
is_test=True,
num_channels=160,
momentum=0.1,
epsilon=0.001)
self.pattern.build(inputs={"input-0": "bn-input-0"})
def insert_new_layer(self, graph, parameters, matches):
new_layer = self.gen_new_layer(parameters, matches)
new_layer_id = list(matches.keys())[0]
graph.layers[new_layer_id] = new_layer
matches.pop(new_layer_id)
# for layer in matches.values():
# print(layer.outputs)
# print("-------")
def gen_new_layer(self, parameters, matches):
layers_id = list(matches.keys())
layer = matches[layers_id[-1]]
return layer
# Licensed under the Apache License, Version 2.0 (the "License"
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from x2paddle.optimizer.pass_ import Pass
from x2paddle.optimizer.fusion import ConstantFuser
from x2paddle.optimizer.pass_manager import pass_register
@pass_register
class ConstantFusePass(Pass):
name = "constant_fuse_pass"
def __init__(self):
Pass.__init__(self)
def apply(self, graph):
fuser = ConstantFuser()
fuser.operate(graph, match_kind="topo")
# 用于注册
constant_fuse_pass = ConstantFuser()
# Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import numpy as np
from x2paddle.optimizer.pattern_matcher import FuseBase
from x2paddle.core.program import PaddleGraph, PaddleLayer
from x2paddle.core.util import *
class ConstantFuser(FuseBase):
def __init__(self):
super(ConstantFuser, self).__init__(graph_type="dygraph")
def build_pattern(self):
""" 描述需要替换的constant图结构。
constant层模式python实现代码示例:
x3 = 10
for _x70 in range(x3):
...
"""
self.pattern.add_layer(
"prim.constant", inputs={}, outputs=["x1"], value=2)
self.pattern.build()
self.pattern.outputs = ["x1"]
def insert_new_layer(self, graph, parameters, matches):
def replace_value(layer_connect, match_name, match_value):
for k, v in layer_connect.inputs.items():
if v == match_name:
layer_connect.inputs.pop(k)
layer_connect.attrs[k] = match_value
break
for k, v in layer_connect.attrs.items():
if v == match_name:
layer_connect.attrs[k] = match_value
break
if layer_connect.kernel == "prim.loop" or \
layer_connect.kernel == "prim.if":
for block in layer_connect.blocks:
for b_layer_id, b_layer in block.layers.items():
if block.edges_in.get(b_layer_id, 0) != 0 and \
-1 in block.edges_in[b_layer_id]:
replace_value(b_layer, match_name, match_value)
layer_id = list(matches.keys())[0]
layer = list(matches.values())[0]
layer_output_name = layer.outputs[0]
layer_value = layer.attrs["value"]
if graph.edges_out.get(layer_id, 0) != 0:
for layer_id_out in graph.edges_out[layer_id]:
layer_connect = graph.layers[layer_id_out]
replace_value(layer_connect, layer_output_name, layer_value)
# Licensed under the Apache License, Version 2.0 (the "License"
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from x2paddle.optimizer.pass_ import Pass
from x2paddle.optimizer.fusion import DropoutFuser
from x2paddle.optimizer.pass_manager import pass_register
@pass_register
class DropoutFusePass(Pass):
name = "dropout_fuse_pass"
def __init__(self):
Pass.__init__(self)
def apply(self, graph):
fuser = DropoutFuser()
fuser.operate(graph, match_kind="topo")
# 用于注册
dropout_fuse_pass = DropoutFuser()
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
...@@ -19,11 +19,10 @@ from x2paddle.optimizer.pass_manager import PassManager ...@@ -19,11 +19,10 @@ from x2paddle.optimizer.pass_manager import PassManager
class GraphOptimizer(object): class GraphOptimizer(object):
def __init__(self): def __init__(self):
self.passes = [ self.passes = [
"fc_fuse_pass", "constant_fuse_pass", "batchnorm2d_fuse_pass",
# "nn_adaptive_pool2d_fuse_pass", "interpolate_bilinear_fuse_pass", "fc_fuse_pass",
# "functional_adaptive_pool2d_fuse_pass", "adaptive_pool2d_fuse_pass", "reshape_fuse_pass",
# "batchnorm2d_fuse_pass", "dropout_fuse_pass"
"constant_fuse_pass"
] ]
def optimize(self, graph): def optimize(self, graph):
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册