Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
PaddlePaddle
Paddle-js
提交
e8d8f20c
P
Paddle-js
项目概览
PaddlePaddle
/
Paddle-js
通知
22
Star
2
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
11
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
P
Paddle-js
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
11
Issue
11
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
提交
e8d8f20c
编写于
5月 19, 2020
作者:
G
gaowenling
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
[d][change] add optimization tool to model convert; add documentation
上级
3687a96f
变更
4
隐藏空白更改
内联
并排
Showing
4 changed file
with
526 addition
and
0 deletion
+526
-0
tools/ModelConverter/README_cn.md
tools/ModelConverter/README_cn.md
+71
-0
tools/ModelConverter/convertModel.py
tools/ModelConverter/convertModel.py
+267
-0
tools/ModelConverter/convertToPaddleJSModel.py
tools/ModelConverter/convertToPaddleJSModel.py
+107
-0
tools/ModelConverter/optimizeModel.py
tools/ModelConverter/optimizeModel.py
+81
-0
未找到文件。
tools/ModelConverter/README_cn.md
0 → 100644
浏览文件 @
e8d8f20c
# PaddleJS Model Converter
PaddleJS Model Converter 是适用于 PaddleJS 的模型转换工具,其作用是将 PaddlePaddle 模型(或称为 fluid 模型)转化为 PaddleJS 模型这种浏览器友好的格式,以供在 PaddleJS 和浏览器中加载预测使用。此外,PaddleJS Model Converter 还提供了强大的模型优化能力,帮助开发者对模型结构进行优化,提高运行时性能。
## 1. 使用教程
### 1.1. 环境搭建
#### Python 版本确认
确认运行平台的 Python 环境与版本是否满足要求,若使用 Python3 ,则可能需要将后续命令中的
`python`
换成
`python3`
:
-
Python3: 3.5.1+ / 3.6 / 3.7
-
Python2: 2.7.15+
#### 安装虚拟环境
*由于开发环境可能安装了多个版本的 Python,相关依赖包可能存在不同的版本,为避免产生冲突,**强烈建议**使用 Python 虚拟环境执行转换工具所需的各项命令,以免产生各种问题。若不使用虚拟环境或已安装虚拟环境,可跳过该步骤。*
以 Anaconda 为例:
前往
[
Anaconda
](
https://www.anaconda.com/
)
主页,选择对应平台、Python 版本的 Anaconda 按照官方提示,进行安装;
安装完毕后,在命令行执行以下命令,创建Python 虚拟环境:
```
bash
conda create
--name
<your_env_name>
```
执行以下命令,切换至虚拟环境
```
bash
# Linux 或 macOS下请执行
source
activate <your_env_name>
# Windows 下请执行
activate <your_env_name>
```
#### 安装依赖
-
如果
`不需要`
使用优化模型的能力,执行命令:
```
bash
python
-m
pip
install
paddlepaddle
-i
https://mirror.baidu.com/pypi/simple
```
-
如果
`需要`
使用优化模型的能力,执行命令:
```
bash
python
-m
pip
install
paddlepaddle
paddlelite
==
2.6.0
-i
https://mirror.baidu.com/pypi/simple
```
### 1.2. 快速上手
-
如果待转换的 fluid 模型为
`合并参数文件`
,即一个模型对应一个参数文件:
```
bash
python convertToPaddleJSModel.py
--modelPath
=
<fluid_model_file_path>
--paramPath
=
<fluid_param_file_path>
--outputDir
=
<paddlejs_model_directory>
```
-
如果待转换的 fluid 模型为
`分片参数文件`
,即一个模型文件对应多个参数文件:
```
bash
# 注意,使用这种方式调用转换器,需要保证 inputDir 中,模型文件名为'__model__'
python convertToPaddleJSModel.py
--inputDir
=
<fluid_model_directory>
--outputDir
=
<paddlejs_model_directory>
```
`
模型转换器将生成以下两种类型的文件以供 PaddleJS 使用:
- model.json (模型结构与参数清单)
- chunk_\*.dat (二进制参数文件集合)
## 2. 详细文档
参数 | 描述
:-: | :-:
--inputDir | fluid 模型所在目录,当且仅当使用分片参数文件时使用该参数,将忽略 `
modelPath
` 和 `
paramPath
` 参数,且模型文件名必须为`
__model__
`
--modelPath | fluid 模型文件所在路径,使用合并参数文件时使用该参数
--paramPath | fluid 参数文件所在路径,使用合并参数文件时使用该参数
--outputDir | `
必要参数
`, paddleJS 模型输出路径
--optimize | 是否进行模型优化, `
0
` 为关闭优化,`
1
` 为开启优化(需安装 PaddleLite ),默认关闭优化
--logModelInfo | 是否打印模型结构信息, `
0
` 为不打印, `
1
` 为打印,默认不打印
--sliceDataSize | 分片输出 PaddleJS 参数文件时,每片文件的大小,单位:KB,默认 4096
## 3. 其他信息
若需要转换的模型为 `
TensorFlow/Caffe/ONNX
` 格式,可使用 PaddlePaddle 项目下的 `
X2Paddle
`
工具,将其他格式的模型转为 fluid 模型后,再使用本工具转化为 PaddleJS 模型。
详细请参考
[
X2Paddle 项目
](
https://github.com/PaddlePaddle/X2Paddle
)
\ No newline at end of file
tools/
toWeb
Model.py
→
tools/
ModelConverter/convert
Model.py
浏览文件 @
e8d8f20c
...
...
@@ -2,199 +2,110 @@
# -*- coding: UTF-8 -*-
import
json
import
paddle.fluid
as
fluid
import
paddle
import
numpy
as
np
import
collections
import
math
import
sys
as
sys
import
sys
import
os
import
struct
import
argparse
import
shutil
import
stat
import
traceback
import
numpy
as
np
import
paddle.fluid
as
fluid
#常量控制
#抽样打印数据数量
logDataCount
=
50
# 输入模型所在目录
modelDir
=
"humanseg/"
modelDir
=
None
# 输入模型名
modelName
=
"model"
modelName
=
None
# 输入参数名,当且仅当所有模型参数被保存在一个单独的二进制文件中,它才需要被指定,若为分片模型,请设置为None
paramsName
=
None
# 模型feed shape
inputShape
=
(
1
,
3
,
192
,
192
)
# 输入数据
inputData
=
np
.
full
(
inputShape
,
1
,
"float32"
)
# 是否打印模型信息
enableLogModelInfo
=
False
# 输出模型目录
outputDir
=
"../dist/model/humanseg/"
# 权重分片扩展名
extensionName
=
".dat"
# 输出各var数据
outputVarData
=
False
# 确认fluid的版本号
print
(
paddle
.
__version__
)
# 采样输出list数据,采样的个数logDataCount为常量
def
stridePrint1
(
data
):
dataCount
=
len
(
data
)
stride
=
math
.
floor
(
dataCount
/
logDataCount
)
if
stride
==
0
:
stride
=
1
nums
=
[]
# outputCount = logDataCount
# if dataCount < logDataCount:
# outputCount = dataCount
# for i in range(outputCount):
# # nums.append(str(i) + ": " + str(data[i]))
# nums.append(data[i])
for
i
in
range
(
0
,
logDataCount
):
item
=
data
[
i
*
stride
]
nums
.
append
(
str
(
i
*
stride
)
+
": "
+
str
(
item
))
print
(
nums
)
def
stridePrint
(
tensor
):
length
=
len
(
tensor
)
# if length < 3000:
# print(tensor)
# return
size
=
20
stride
=
math
.
floor
(
length
/
size
)
if
stride
==
0
:
stride
=
1
size
=
math
.
floor
(
length
/
stride
)
nums
=
[]
for
i
in
range
(
0
,
size
):
item
=
tensor
[
i
*
stride
]
nums
.
append
(
str
(
i
*
stride
)
+
": "
+
str
(
item
))
print
(
nums
)
# 对字典进行排序,返回有序字典,默认升序
def
sortDict
(
oldDict
,
reverse
=
False
):
outputDir
=
None
# 分片文件大小,单位:KB
sliceDataSize
=
4
*
1024
# paddlepaddle运行程序实例
program
=
None
# 存放模型结构
modelInfo
=
{
"vars"
:
[],
"ops"
:
[]}
# 存放参数数值(未排序)
paramValuesDict
=
{}
def
logModel
(
info
):
""" 打印信息 """
if
enableLogModelInfo
:
print
(
info
)
def
sortDict
(
oldDict
,
reverse
=
False
):
""" 对字典进行排序,返回有序字典,默认升序 """
# 获得排序后的key list
keys
=
sorted
(
oldDict
.
keys
(),
reverse
=
reverse
)
keys
=
sorted
(
oldDict
.
keys
(),
reverse
=
reverse
)
orderDict
=
collections
.
OrderedDict
()
# 遍历 key 列表
for
key
in
keys
:
orderDict
[
key
]
=
oldDict
[
key
]
return
orderDict
def
dumpModelToJsonFile
():
""" 导出模型数据到json文件 """
print
(
"Dumping model structure to json file..."
)
if
not
os
.
path
.
exists
(
outputDir
):
os
.
makedirs
(
outputDir
)
outputModelPath
=
os
.
path
.
join
(
outputDir
,
"model.json"
)
with
open
(
outputModelPath
,
'w'
)
as
outputFile
:
json
.
dump
(
modelInfo
,
outputFile
,
indent
=
4
,
separators
=
(
", "
,
": "
),
sort_keys
=
True
)
print
(
"Dumping model structure to json file successfully"
)
# 将权重数据分片输出到文件,默认分片策略为按4M分片
def
sliceDataToBinaryFile
(
weightValueList
,
sliceMethod
=
0
):
# TODO: 分片这里不太对,待修改
totalWeightCount
=
len
(
weightValueList
)
countPerSlice
=
0
# sliceCount = 0
if
sliceMethod
==
0
:
# 分片策略 0:按4M分片
countPerSlice
=
int
(
4
*
1024
*
1024
/
4
)
# sliceCount = math.ceil(totalWeightCount / countPerSlice)
else
:
# 分片策略 1:按<=4M等分
# TODO: 待实现
countPerSlice
=
0
# sliceCount = 0
def
sliceDataToBinaryFile
(
paramValueList
):
""" 将参数数据分片输出到文件,默认分片策略为按4M分片 """
totalParamValuesCount
=
len
(
paramValueList
)
countPerSlice
=
int
(
sliceDataSize
*
1024
/
4
)
if
not
os
.
path
.
exists
(
outputDir
):
os
.
makedirs
(
outputDir
)
currentChunkIndex
=
0
current
Weight
Index
=
0
current
ParamData
Index
=
0
while
current
WeightIndex
<
totalWeight
Count
-
1
:
remainCount
=
total
WeightCount
-
currentWeight
Index
while
current
ParamDataIndex
<
totalParamValues
Count
-
1
:
remainCount
=
total
ParamValuesCount
-
currentParamData
Index
if
remainCount
<
countPerSlice
:
countPerSlice
=
remainCount
chunkPath
=
o
utputDir
+
'chunk_%s'
%
(
currentChunkIndex
+
1
)
+
extensionName
chunkPath
=
o
s
.
path
.
join
(
outputDir
,
'chunk_%s.dat'
%
(
currentChunkIndex
+
1
))
file
=
open
(
chunkPath
,
'wb'
)
for
i
in
weightValueList
[
currentWeightIndex
:
currentWeight
Index
+
countPerSlice
]:
for
i
in
paramValueList
[
currentParamDataIndex
:
currentParamData
Index
+
countPerSlice
]:
byte
=
struct
.
pack
(
'f'
,
float
(
i
))
file
.
write
(
byte
)
file
.
close
()
current
WeightIndex
=
currentWeight
Index
+
countPerSlice
current
ParamDataIndex
=
currentParamData
Index
+
countPerSlice
currentChunkIndex
=
currentChunkIndex
+
1
# for debug
print
(
"第"
+
str
(
currentChunkIndex
+
1
)
+
"片权重输出完毕,输出个数:"
+
str
(
countPerSlice
)
+
" 剩余个数:"
+
str
(
totalWeightCount
-
currentWeightIndex
)
)
print
(
"Output No."
+
str
(
currentChunkIndex
)
+
" binary file, remain "
+
str
(
totalParamValuesCount
-
currentParamDataIndex
)
+
" param values."
)
print
(
"Slicing data to binary files successfully. ("
+
str
(
currentChunkIndex
)
+
" output files and "
+
str
(
currentParamDataIndex
)
+
" param values)"
)
# for debug
print
(
"========权重输出完毕,共"
+
str
(
currentWeightIndex
)
+
"个数据,"
+
str
(
currentChunkIndex
)
+
"个分片文件"
+
"========"
)
def
reorderParamsValue
():
""" 对参数文件中的数值,按照variable.name字母序排序,返回排序后组合完成的value list """
paramValuesOrderDict
=
sortDict
(
paramValuesDict
)
paramValues
=
[]
for
value
in
paramValuesOrderDict
.
values
():
paramValues
+=
value
return
paramValues
# 处理fluid的OP type与PaddleJS的OP type不对应情况
def
mapToPaddleJSTypeName
(
fluidOPName
):
""" 处理fluid的OP type与PaddleJS的OP type不对应情况 """
if
fluidOPName
==
"batch_norm"
:
return
"batchnorm"
return
fluidOPName
return
fluidOPName
# 将shape扩充为4维
def
padToFourDimShape
(
shape
):
fourDimShape
=
[]
if
len
(
shape
)
==
4
:
fourDimShape
=
shape
elif
len
(
shape
)
<
4
:
for
i
in
range
(
0
,
4
-
len
(
shape
)):
fourDimShape
.
append
(
1
)
fourDimShape
=
fourDimShape
+
shape
else
:
return
[]
return
fourDimShape
# for debug,将NCHW排布的数据转为NHWC排布的数据
def
convertNCHW2NHWC
(
data
,
shape
):
fourDimShape
=
padToFourDimShape
(
shape
)
N
=
fourDimShape
[
0
]
C
=
fourDimShape
[
1
]
H
=
fourDimShape
[
2
]
W
=
fourDimShape
[
3
]
print
(
fourDimShape
)
HXW
=
H
*
W
CXHXW
=
C
*
H
*
W
def
organizeModelVariableInfo
():
""" 组织参数信息 """
print
(
"Organizing model variables info..."
)
index
=
0
nhwcData
=
[]
for
n
in
range
(
0
,
N
):
for
h
in
range
(
0
,
H
):
for
w
in
range
(
0
,
W
):
for
c
in
range
(
0
,
C
):
nhwcData
.
append
(
data
[
n
*
CXHXW
+
c
*
HXW
+
h
*
W
+
w
])
index
=
index
+
1
return
nhwcData
# for debug 输出特定varName对应的数据
def
writeTempOutputData
(
name
):
# FIXME:待完善
return
dataList
=
np
.
array
(
fluid
.
global_scope
().
find_var
(
name
).
get_tensor
()).
flatten
().
tolist
()
path
=
'/Users/bluebird/baidu/fluid_tools/check-temp/filter.txt'
if
os
.
path
.
exists
(
path
):
os
.
remove
()
file
=
open
(
path
,
'a'
)
for
a
in
range
(
0
,
len
(
dataList
)):
file
.
write
(
str
(
dataList
[
a
]))
file
.
write
(
","
)
file
.
close
()
def
convertToPaddleJSModel
():
# 1. 初始化fluid运行环境和配置
exe
=
fluid
.
Executor
(
fluid
.
CPUPlace
())
[
prog
,
feed_target_names
,
fetch_targets
]
=
fluid
.
io
.
load_inference_model
(
dirname
=
modelDir
,
executor
=
exe
,
model_filename
=
modelName
,
params_filename
=
paramsName
)
out
=
exe
.
run
(
prog
,
feed
=
{
feed_target_names
[
0
]:
inputData
},
fetch_list
=
fetch_targets
,
return_numpy
=
False
)
print
(
out
)
index
=
0
# 存放模型结构
modelInfo
=
{
"vars"
:
[],
"ops"
:
[]}
# 存放var信息(未排序)
varInfoDict
=
{}
# 存放权重数值(未排序)
weightValueDict
=
{}
# 2. 获取program中所有的var,遍历并获取所有未排序的var信息和权重数值
vars
=
list
(
prog
.
list_vars
())
# 获取program中所有的var,遍历并获取所有未排序的var信息和参数数值
vars
=
list
(
program
.
list_vars
())
for
v
in
vars
:
# 跳过feed和fetch
if
"feed"
==
v
.
name
:
...
...
@@ -202,10 +113,6 @@ def convertToPaddleJSModel():
if
"fetch"
==
v
.
name
:
continue
print
(
"Var index:"
+
str
(
index
)
+
" name:"
+
v
.
name
)
print
(
v
)
index
+=
1
varShape
=
list
(
v
.
shape
)
# FIXME:start paddlejs 不支持shape中为-1,这里需要手动过滤一下,支持了以后可以删除
...
...
@@ -220,40 +127,37 @@ def convertToPaddleJSModel():
# 存放variable信息,在dump成json时排序
varInfo
=
{}
varInfo
[
"shape"
]
=
varShape
# 数据是否是持久化数据,如
weight
为持久化数据,op的output不是持久化数据
# 数据是否是持久化数据,如
tensor
为持久化数据,op的output不是持久化数据
# 只输出持久化数据,paddlejs中也仅读取持久化数据
varInfo
[
"persistable"
]
=
v
.
persistable
varInfoDict
[
v
.
name
]
=
varInfo
# for debug,输出var变量
if
outputVarData
:
writeTempOutputData
(
v
.
name
)
logModel
(
"[Var index:"
+
str
(
index
)
+
" name:"
+
v
.
name
+
"]"
)
jsonDumpsIndentStr
=
json
.
dumps
(
varInfo
,
indent
=
2
)
logModel
(
jsonDumpsIndentStr
)
logModel
(
""
)
index
+=
1
# persistable数据存入
weight
Dict,等待排序
# persistable数据存入
paramValues
Dict,等待排序
if
v
.
persistable
:
data
=
np
.
array
(
fluid
.
global_scope
().
find_var
(
v
.
name
).
get_tensor
()).
flatten
().
tolist
()
weightValue
Dict
[
v
.
name
]
=
data
paramValues
Dict
[
v
.
name
]
=
data
#
3.
对var信息dict,按照key(var名)进行字母顺序排序
# 对var信息dict,按照key(var名)进行字母顺序排序
varInfoOrderDict
=
sortDict
(
varInfoDict
)
#
4.
将var信息按照顺序,添加到model info的vars中
# 将var信息按照顺序,添加到model info的vars中
for
key
,
value
in
varInfoOrderDict
.
items
():
value
[
"name"
]
=
key
modelInfo
[
"vars"
].
append
(
value
)
# 5. 对权重数值dict,按照key(权重名)进行字母顺序排序,并组合到一起
weightValueOrderDict
=
sortDict
(
weightValueDict
)
weightValues
=
[]
for
key
,
value
in
weightValueOrderDict
.
items
():
weightValues
+=
value
# 6. 分片输出权重
sliceDataToBinaryFile
(
weightValues
)
print
(
"Organizing model variables info successfully."
)
# 7. 获取program中所有的op,按op顺序加入到model info
ops
=
prog
.
current_block
().
ops
def
organizeModelOpInfo
():
""" 组织模型OP结构信息 """
print
(
"Organizing model operators info..."
)
ops
=
program
.
current_block
().
ops
feedOutputName
=
None
index
=
0
for
op
in
ops
:
opInfo
=
{}
...
...
@@ -267,9 +171,7 @@ def convertToPaddleJSModel():
if
len
(
value
)
<=
0
:
continue
if
value
[
0
]
==
feedOutputName
:
# FIXME:workaround,PaddleJSfeed 输入必须是image,且为单输入
# 这里修改feed后面的OP的input为image,建立前后关联
# 这里可能会有问题
# FIXME:workaround,PaddleJSfeed 输入必须是image,且为单输入,这里修改feed后面的OP的input为image,建立前后关联
inputs
[
name
]
=
[
"image"
]
else
:
inputs
[
name
]
=
value
...
...
@@ -282,8 +184,7 @@ def convertToPaddleJSModel():
if
len
(
value
)
<=
0
:
continue
if
op
.
type
==
"feed"
:
# FIXME:workaround,PaddleJSfeed 输入必须是image,且为单输入
# 这里可能会有问题
# FIXME:workaround,PaddleJSfeed 输入必须是image,且为单输入,这里保存原始的输出名,以便映射
feedOutputName
=
value
[
0
]
outputs
[
name
]
=
[
"image"
]
else
:
...
...
@@ -302,12 +203,65 @@ def convertToPaddleJSModel():
# 存入modelInfo
modelInfo
[
"ops"
].
append
(
opInfo
)
logModel
(
"[OP index:"
+
str
(
index
)
+
" type:"
+
op
.
type
+
"]"
)
jsonDumpsIndentStr
=
json
.
dumps
(
opInfo
,
indent
=
2
)
logModel
(
jsonDumpsIndentStr
)
logModel
(
""
)
index
+=
1
print
(
"Organizing model operators info successfully."
)
# 8. 模型信息按照key字母顺序导出到json
outputModelPath
=
outputDir
+
"model.json"
with
open
(
outputModelPath
,
'w'
)
as
outputFile
:
json
.
dump
(
modelInfo
,
outputFile
,
indent
=
4
,
separators
=
(
", "
,
": "
),
sort_keys
=
True
)
def
convertToPaddleJSModel
():
""" 转换fluid modle为paddleJS model """
# 初始化fluid运行环境和配置
exe
=
fluid
.
Executor
(
fluid
.
CPUPlace
())
result
=
fluid
.
io
.
load_inference_model
(
dirname
=
modelDir
,
executor
=
exe
,
model_filename
=
modelName
,
params_filename
=
paramsName
)
global
program
program
=
result
[
0
]
# 获取program中所有的op,按op顺序加入到model info
organizeModelOpInfo
()
# 获取program中所有的var,按照字母顺序加入到model info,同时读取参数数值
organizeModelVariableInfo
()
print
(
"========模型结构输出完毕========"
)
# 导出模型文件到json
dumpModelToJsonFile
()
convertToPaddleJSModel
()
# 对参数数值dict,按照key(参数名)进行字母顺序排序,并组合到一起
paramValues
=
reorderParamsValue
()
# 导出分片参数文件
sliceDataToBinaryFile
(
paramValues
)
if
__name__
==
"__main__"
:
try
:
p
=
argparse
.
ArgumentParser
(
description
=
'模型转换参数解析'
)
p
.
add_argument
(
'--inputDir'
,
help
=
'fluid模型所在目录。当且仅当使用分片参数文件时使用该参数。将过滤modelPath和paramsPath参数,且模型文件名必须为`__model__`'
,
required
=
False
)
p
.
add_argument
(
'--modelPath'
,
help
=
'fluid模型文件所在路径,使用合并参数文件时使用该参数'
,
required
=
False
)
p
.
add_argument
(
'--paramPath'
,
help
=
'fluid参数文件所在路径,使用合并参数文件时使用该参数'
,
required
=
False
)
p
.
add_argument
(
"--outputDir"
,
help
=
'paddleJS模型输出路径,必要参数'
,
required
=
True
)
p
.
add_argument
(
"--logModelInfo"
,
type
=
int
,
default
=
0
,
help
=
'是否输出模型结构信息,非必要参数,0为不输出,1为输出,默认不输出'
,
required
=
False
)
p
.
add_argument
(
"--sliceDataSize"
,
type
=
int
,
default
=
4096
,
help
=
'分片输出参数文件时,每片文件的大小,单位:KB,非必要参数,默认4096KB'
,
required
=
False
)
args
=
p
.
parse_args
()
modelDir
=
args
.
inputDir
modelPath
=
args
.
modelPath
paramPath
=
args
.
paramPath
if
not
modelDir
:
modelDir
,
modelName
=
os
.
path
.
split
(
modelPath
)
paramDir
,
paramsName
=
os
.
path
.
split
(
paramPath
)
if
paramDir
!=
modelDir
:
print
(
"
\033
[31mModel and param file should be put in a same directory!
\033
[0m"
)
raise
Exception
()
outputDir
=
args
.
outputDir
sliceDataSize
=
args
.
sliceDataSize
if
args
.
logModelInfo
==
1
:
enableLogModelInfo
=
True
convertToPaddleJSModel
()
except
Exception
as
identifier
:
print
(
"
\033
[31mA fetal error occured. Failed to convert model.
\033
[0m"
)
print
(
traceback
.
format_exc
())
pass
\ No newline at end of file
tools/ModelConverter/convertToPaddleJSModel.py
0 → 100644
浏览文件 @
e8d8f20c
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
import
sys
import
os
import
argparse
import
shutil
import
stat
import
traceback
def
cleanTempModel
(
optimizedModelTempDir
):
""" 清理opt优化完的临时模型文件 """
if
os
.
path
.
exists
(
optimizedModelTempDir
):
print
(
"Cleaning optimized temporary model..."
)
shutil
.
rmtree
(
optimizedModelTempDir
,
onerror
=
grantWritePermission
)
def
grantWritePermission
(
func
,
path
,
execinfo
):
""" 文件授权 """
os
.
chmod
(
path
,
stat
.
S_IWRITE
)
func
(
path
)
if
__name__
==
"__main__"
:
"""
Example:
'python convertToPaddleJSModel.py --modelPath=../infer_model/MobileNetV2/__model__ --paramPath=../infer_model/MobileNetV2/params --outputDir=../jsmodel --optimize=1'
"""
try
:
p
=
argparse
.
ArgumentParser
(
description
=
'转化为PaddleJS模型参数解析'
)
p
.
add_argument
(
'--inputDir'
,
help
=
'fluid模型所在目录。当且仅当使用分片参数文件时使用该参数。将过滤modelPath和paramsPath参数,且模型文件名必须为`__model__`'
,
required
=
False
)
p
.
add_argument
(
'--modelPath'
,
help
=
'fluid模型文件所在路径,使用合并参数文件时使用该参数'
,
required
=
False
)
p
.
add_argument
(
'--paramPath'
,
help
=
'fluid参数文件所在路径,使用合并参数文件时使用该参数'
,
required
=
False
)
p
.
add_argument
(
"--outputDir"
,
help
=
'paddleJS模型输出路径,必要参数'
,
required
=
True
)
p
.
add_argument
(
"--optimize"
,
type
=
int
,
default
=
0
,
help
=
'是否进行模型优化,非必要参数,0为关闭优化,1为开启优化,默认关闭优化'
,
required
=
False
)
p
.
add_argument
(
"--logModelInfo"
,
type
=
int
,
default
=
0
,
help
=
'是否输出模型结构信息,非必要参数,0为不输出,1为输出,默认不输出'
,
required
=
False
)
p
.
add_argument
(
"--sliceDataSize"
,
type
=
int
,
default
=
4096
,
help
=
'分片输出参数文件时,每片文件的大小,单位:KB,非必要参数,默认4096KB'
,
required
=
False
)
args
=
p
.
parse_args
()
# TODO: 由于PaddleLite和PaddlePaddle存在包冲突,因此将整个模型转换工具拆成两个python文件,由一个入口python文件通过命令行调用
optimizeCmd
=
" optimizeModel.py"
convertCmd
=
" convertModel.py"
inputDir
=
args
.
inputDir
modelPath
=
args
.
modelPath
paramPath
=
args
.
paramPath
outputDir
=
args
.
outputDir
enableOptimization
=
args
.
optimize
enableLogModelInfo
=
args
.
logModelInfo
sliceDataSize
=
args
.
sliceDataSize
optimizedModelTempDir
=
None
if
enableOptimization
==
1
:
optimizedModelTempDir
=
os
.
path
.
join
(
outputDir
,
"optimize"
)
if
inputDir
:
optimizeCmd
=
optimizeCmd
+
" --inputDir="
+
inputDir
convertCmd
=
convertCmd
+
" --inputDir="
+
optimizedModelTempDir
else
:
optimizeCmd
=
optimizeCmd
+
" --modelPath="
+
modelPath
+
" --paramPath="
+
paramPath
# optimizeModelPath, modelName = os.path.split(modelPath)
# optimizeParamPath, paramName = os.path.split(paramPath)
optimizeModelPath
=
os
.
path
.
join
(
optimizedModelTempDir
,
"model"
)
optimizeParamPath
=
os
.
path
.
join
(
optimizedModelTempDir
,
"params"
)
convertCmd
=
convertCmd
+
" --modelPath="
+
optimizeModelPath
+
" --paramPath="
+
optimizeParamPath
optimizeCmd
=
optimizeCmd
+
" --outputDir="
+
optimizedModelTempDir
else
:
if
inputDir
:
convertCmd
=
convertCmd
+
" --inputDir="
+
inputDir
else
:
convertCmd
=
convertCmd
+
" --modelPath="
+
modelPath
+
" --paramPath="
+
paramPath
convertCmd
=
convertCmd
+
" --outputDir="
+
outputDir
+
" --sliceDataSize="
+
str
(
sliceDataSize
)
+
" --logModelInfo="
+
str
(
args
.
logModelInfo
)
print
(
"============Convert Model Args============="
)
if
inputDir
:
print
(
"inputDir: "
+
inputDir
)
else
:
print
(
"modelPath: "
+
modelPath
)
print
(
"paramPath: "
+
paramPath
)
print
(
"outputDir: "
+
outputDir
)
print
(
"enableOptimizeModel: "
+
str
(
enableOptimization
))
print
(
"enableLogModelInfo: "
+
str
(
enableLogModelInfo
))
print
(
"sliceDataSize:"
+
str
(
sliceDataSize
))
pythonCmd
=
"python"
print
(
"Starting..."
)
if
enableOptimization
:
print
(
"Optimizing model..."
)
os
.
system
(
pythonCmd
+
optimizeCmd
)
print
(
"
\033
[32m
\n
Optimizing model successfully.
\033
[0m"
)
else
:
print
(
"
\033
[33mYou choosed not to optimize model, consequently, optimizing model is skiped.
\033
[0m"
)
print
(
"Converting model..."
)
os
.
system
(
pythonCmd
+
convertCmd
)
print
(
"
\033
[32mConverting model successfully.
\033
[0m"
)
if
enableOptimization
:
cleanTempModel
(
optimizedModelTempDir
)
print
(
"Temporary files has been deleted successfully."
)
print
(
"
\033
[32m============ALL DONE============
\033
[0m"
)
except
Exception
as
identifier
:
print
(
"
\033
[31mA fetal error occured. Failed to convert model.
\033
[0m"
)
print
(
traceback
.
format_exc
())
pass
\ No newline at end of file
tools/ModelConverter/optimizeModel.py
0 → 100644
浏览文件 @
e8d8f20c
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
import
collections
import
argparse
import
traceback
import
paddlelite.lite
as
lite
def
optimizeModel
(
inputDir
,
modelPath
,
paramPath
,
outputDir
):
""" 使用opt python接口执行模型优化 """
opt
=
lite
.
Opt
()
if
inputDir
:
# 分片参数文件优化
opt
.
set_model_dir
(
inputDir
)
else
:
# 合并参数文件优化
opt
.
set_model_file
(
modelPath
)
opt
.
set_param_file
(
paramPath
)
opt
.
set_valid_places
(
"arm"
)
opt
.
set_model_type
(
"protobuf"
)
opt
.
set_optimize_out
(
outputDir
)
optimize_passes
=
[
"lite_conv_elementwise_fuse_pass"
,
"lite_conv_bn_fuse_pass"
,
"lite_conv_elementwise_fuse_pass"
,
"lite_conv_activation_fuse_pass"
,
"lite_var_conv_2d_activation_fuse_pass"
,
"lite_fc_fuse_pass"
,
"lite_shuffle_channel_fuse_pass"
,
"lite_transpose_softmax_transpose_fuse_pass"
,
"lite_interpolate_fuse_pass"
,
"identity_scale_eliminate_pass"
,
"elementwise_mul_constant_eliminate_pass"
,
"lite_sequence_pool_concat_fuse_pass"
,
"lite_elementwise_add_activation_fuse_pass"
,
"static_kernel_pick_pass"
,
"variable_place_inference_pass"
,
"argument_type_display_pass"
,
"type_target_cast_pass"
,
"variable_place_inference_pass"
,
"argument_type_display_pass"
,
"io_copy_kernel_pick_pass"
,
"argument_type_display_pass"
,
"variable_place_inference_pass"
,
"argument_type_display_pass"
,
"type_precision_cast_pass"
,
"variable_place_inference_pass"
,
"argument_type_display_pass"
,
"type_layout_cast_pass"
,
"argument_type_display_pass"
,
"variable_place_inference_pass"
,
"argument_type_display_pass"
,
"runtime_context_assign_pass"
,
"argument_type_display_pass"
]
opt
.
set_passes_internal
(
optimize_passes
)
opt
.
run
()
if
__name__
==
"__main__"
:
try
:
p
=
argparse
.
ArgumentParser
(
'模型优化参数解析'
)
p
.
add_argument
(
'--inputDir'
,
help
=
'fluid模型所在目录。当且仅当使用分片参数文件时使用该参数。将过滤modelPath和paramsPath参数,且模型文件名必须为`__model__`'
,
required
=
False
)
p
.
add_argument
(
'--modelPath'
,
help
=
'fluid模型文件所在路径,使用合并参数文件时使用该参数'
,
required
=
False
)
p
.
add_argument
(
'--paramPath'
,
help
=
'fluid参数文件所在路径,使用合并参数文件时使用该参数'
,
required
=
False
)
p
.
add_argument
(
"--outputDir"
,
help
=
'优化后fluid模型目录,必要参数'
,
required
=
True
)
args
=
p
.
parse_args
()
inputDir
=
args
.
inputDir
modelPath
=
args
.
modelPath
paramPath
=
args
.
paramPath
outputDir
=
args
.
outputDir
optimizeModel
(
inputDir
,
modelPath
,
paramPath
,
outputDir
)
except
Exception
as
identifier
:
print
(
"
\033
[31mA fetal error occured. Failed to optimize model.
\033
[0m"
)
print
(
traceback
.
format_exc
())
pass
\ No newline at end of file
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录