Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
PaddlePaddle
Paddle-Lite
提交
2bbf3ec6
P
Paddle-Lite
项目概览
PaddlePaddle
/
Paddle-Lite
通知
331
Star
4
Fork
1
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
271
列表
看板
标记
里程碑
合并请求
78
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
P
Paddle-Lite
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
271
Issue
271
列表
看板
标记
里程碑
合并请求
78
合并请求
78
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
提交
2bbf3ec6
编写于
3月 13, 2019
作者:
H
hjchen2
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'backup' of
https://github.com/hjchen2/paddle-mobile
into backup
上级
5470cfa8
b4fa2264
变更
7
隐藏空白更改
内联
并排
Showing
7 changed file
with
79 addition
and
59 deletion
+79
-59
src/framework/executor.cpp
src/framework/executor.cpp
+12
-9
src/framework/scope.cpp
src/framework/scope.cpp
+11
-3
src/framework/scope.h
src/framework/scope.h
+1
-2
src/io/api_paddle_mobile.cc
src/io/api_paddle_mobile.cc
+0
-12
src/io/api_paddle_mobile.h
src/io/api_paddle_mobile.h
+0
-2
src/io/paddle_inference_api.h
src/io/paddle_inference_api.h
+1
-2
test/fpga/test_rfcn_api.cpp
test/fpga/test_rfcn_api.cpp
+54
-29
未找到文件。
src/framework/executor.cpp
浏览文件 @
2bbf3ec6
...
@@ -520,11 +520,12 @@ void Executor<Device, T>::FeedData(const Tensor &t) {
...
@@ -520,11 +520,12 @@ void Executor<Device, T>::FeedData(const Tensor &t) {
template
<
typename
Device
,
typename
T
>
template
<
typename
Device
,
typename
T
>
void
Executor
<
Device
,
T
>::
FeedData
(
const
std
::
vector
<
void
*>
&
v
)
{
void
Executor
<
Device
,
T
>::
FeedData
(
const
std
::
vector
<
void
*>
&
v
)
{
auto
input_size
=
v
.
size
();
auto
input_size
=
v
.
size
();
auto
vars
=
program_
.
scope
->
VarContain
(
"feed"
);
int
index
=
0
;
auto
vars
=
program_
.
scope
->
VarContain
(
"feed"
,
&
index
);
PADDLE_MOBILE_ENFORCE
(
input_size
==
vars
.
size
(),
PADDLE_MOBILE_ENFORCE
(
input_size
==
vars
.
size
(),
"input data number not correct"
);
"input data number not correct"
);
for
(
int
i
=
0
;
i
<
input_size
;
i
++
)
{
for
(
int
i
=
0
;
i
<
input_size
;
i
++
)
{
auto
var
=
vars
[
i
]
;
auto
var
=
program_
.
scope
->
Var
(
"feed"
,
i
+
index
)
;
auto
feed_tensor
=
var
->
template
GetMutable
<
LoDTensor
>();
auto
feed_tensor
=
var
->
template
GetMutable
<
LoDTensor
>();
feed_tensor
->
external_data
=
v
[
i
];
feed_tensor
->
external_data
=
v
[
i
];
}
}
...
@@ -533,11 +534,12 @@ void Executor<Device, T>::FeedData(const std::vector<void *> &v) {
...
@@ -533,11 +534,12 @@ void Executor<Device, T>::FeedData(const std::vector<void *> &v) {
template
<
typename
Device
,
typename
T
>
template
<
typename
Device
,
typename
T
>
void
Executor
<
Device
,
T
>::
FeedTensorData
(
const
vector
<
framework
::
Tensor
>
&
v
)
{
void
Executor
<
Device
,
T
>::
FeedTensorData
(
const
vector
<
framework
::
Tensor
>
&
v
)
{
auto
input_size
=
v
.
size
();
auto
input_size
=
v
.
size
();
auto
vars
=
program_
.
scope
->
VarContain
(
"feed"
);
int
index
=
0
;
auto
vars
=
program_
.
scope
->
VarContain
(
"feed"
,
&
index
);
PADDLE_MOBILE_ENFORCE
(
input_size
==
vars
.
size
(),
PADDLE_MOBILE_ENFORCE
(
input_size
==
vars
.
size
(),
"input data number not correct"
);
"input data number not correct"
);
for
(
int
i
=
0
;
i
<
input_size
;
i
++
)
{
for
(
int
i
=
0
;
i
<
input_size
;
i
++
)
{
auto
var
=
vars
[
i
]
;
auto
var
=
program_
.
scope
->
Var
(
"feed"
,
i
+
index
)
;
auto
feed_tensor
=
var
->
template
GetMutable
<
LoDTensor
>();
auto
feed_tensor
=
var
->
template
GetMutable
<
LoDTensor
>();
feed_tensor
->
ShareDataWith
(
v
[
i
]);
feed_tensor
->
ShareDataWith
(
v
[
i
]);
}
}
...
@@ -547,12 +549,13 @@ template <typename Device, typename T>
...
@@ -547,12 +549,13 @@ template <typename Device, typename T>
void
Executor
<
Device
,
T
>::
GetResults
(
std
::
vector
<
void
*>
*
v
)
{
void
Executor
<
Device
,
T
>::
GetResults
(
std
::
vector
<
void
*>
*
v
)
{
auto
output_size
=
v
->
size
();
auto
output_size
=
v
->
size
();
PADDLE_MOBILE_ENFORCE
(
output_size
>
0
,
"Empty output"
);
PADDLE_MOBILE_ENFORCE
(
output_size
>
0
,
"Empty output"
);
auto
vars
=
program_
.
scope
->
VarContain
(
"fetch"
);
int
index
=
0
;
auto
vars
=
program_
.
scope
->
VarContain
(
"fetch"
,
&
index
);
PADDLE_MOBILE_ENFORCE
(
output_size
==
vars
.
size
(),
PADDLE_MOBILE_ENFORCE
(
output_size
==
vars
.
size
(),
"output data number not correct"
);
"output data number not correct"
);
for
(
int
i
=
0
;
i
<
output_size
;
i
++
)
{
for
(
int
i
=
0
;
i
<
output_size
;
i
++
)
{
auto
var
=
vars
[
i
]
;
auto
var
=
program_
.
scope
->
Var
(
"fetch"
,
i
+
index
)
;
auto
fetch_tensor
=
var
->
template
GetMutable
<
LoDTensor
>();
auto
fetch_tensor
=
var
->
template
GetMutable
<
LoDTensor
>();
(
*
v
)[
i
]
=
fetch_tensor
->
template
data
<
float
>();
(
*
v
)[
i
]
=
fetch_tensor
->
template
data
<
float
>();
}
}
...
@@ -561,11 +564,11 @@ void Executor<Device, T>::GetResults(std::vector<void *> *v) {
...
@@ -561,11 +564,11 @@ void Executor<Device, T>::GetResults(std::vector<void *> *v) {
template
<
typename
Device
,
typename
T
>
template
<
typename
Device
,
typename
T
>
void
Executor
<
Device
,
T
>::
GetTensorResults
(
void
Executor
<
Device
,
T
>::
GetTensorResults
(
std
::
vector
<
framework
::
Tensor
*>
*
v
)
{
std
::
vector
<
framework
::
Tensor
*>
*
v
)
{
auto
vars
=
program_
.
scope
->
VarContain
(
"fetch"
);
int
index
=
0
;
auto
vars
=
program_
.
scope
->
VarContain
(
"fetch"
,
&
index
);
auto
output_size
=
vars
.
size
();
auto
output_size
=
vars
.
size
();
for
(
int
i
=
0
;
i
<
output_size
;
i
++
)
{
for
(
int
i
=
0
;
i
<
output_size
;
i
++
)
{
auto
var
=
vars
[
i
]
;
auto
var
=
program_
.
scope
->
Var
(
"fetch"
,
i
+
index
)
;
auto
fetch_tensor
=
var
->
template
GetMutable
<
LoDTensor
>();
auto
fetch_tensor
=
var
->
template
GetMutable
<
LoDTensor
>();
v
->
push_back
(
fetch_tensor
);
v
->
push_back
(
fetch_tensor
);
}
}
...
...
src/framework/scope.cpp
浏览文件 @
2bbf3ec6
...
@@ -116,18 +116,26 @@ Variable *Scope::Var(const std::string &name, const int id) {
...
@@ -116,18 +116,26 @@ Variable *Scope::Var(const std::string &name, const int id) {
return
Var
(
name
+
std
::
to_string
(
id
));
return
Var
(
name
+
std
::
to_string
(
id
));
}
}
std
::
vector
<
Variable
*>
Scope
::
VarContain
(
const
std
::
string
substring
)
{
std
::
vector
<
Variable
*>
Scope
::
VarContain
(
const
std
::
string
substring
,
int
*
min
)
{
std
::
vector
<
Variable
*>
v
;
std
::
vector
<
Variable
*>
v
;
int
temp
=
9999
;
auto
len0
=
substring
.
length
();
for
(
auto
pair
:
vars_
)
{
for
(
auto
pair
:
vars_
)
{
if
(
pair
.
first
.
find
(
substring
)
==
0
)
{
if
(
pair
.
first
.
find
(
substring
)
==
0
)
{
v
.
push_back
(
pair
.
second
);
v
.
push_back
(
pair
.
second
);
auto
len1
=
pair
.
first
.
length
();
int
index
=
std
::
stoi
(
pair
.
first
.
substr
(
len0
,
len1
));
if
(
index
<
temp
)
{
temp
=
index
;
}
}
}
}
}
*
min
=
temp
;
return
v
;
return
v
;
}
}
void
Scope
::
InsertVar
(
const
std
::
string
str
,
Variable
*
var
)
{}
void
Scope
::
print_vars
()
{
void
Scope
::
print_vars
()
{
DLOG
<<
"====================start to print variables================="
;
DLOG
<<
"====================start to print variables================="
;
for
(
auto
pair
:
vars_
)
{
for
(
auto
pair
:
vars_
)
{
...
...
src/framework/scope.h
浏览文件 @
2bbf3ec6
...
@@ -77,8 +77,7 @@ class Scope {
...
@@ -77,8 +77,7 @@ class Scope {
#ifdef PADDLE_MOBILE_FPGA
#ifdef PADDLE_MOBILE_FPGA
Variable
*
Var
(
const
std
::
string
&
name
,
const
int
id
);
Variable
*
Var
(
const
std
::
string
&
name
,
const
int
id
);
std
::
vector
<
Variable
*>
VarContain
(
const
std
::
string
substring
);
std
::
vector
<
Variable
*>
VarContain
(
const
std
::
string
substring
,
int
*
min
);
void
InsertVar
(
const
std
::
string
str
,
Variable
*
var
);
void
print_vars
();
void
print_vars
();
#endif
#endif
...
...
src/io/api_paddle_mobile.cc
浏览文件 @
2bbf3ec6
...
@@ -172,18 +172,6 @@ void PaddleMobilePredictor<Device, T>::GetPaddleTensor(const std::string &name,
...
@@ -172,18 +172,6 @@ void PaddleMobilePredictor<Device, T>::GetPaddleTensor(const std::string &name,
ConvertTensors
(
*
t
,
output
);
ConvertTensors
(
*
t
,
output
);
}
}
template
<
typename
Device
,
typename
T
>
void
PaddleMobilePredictor
<
Device
,
T
>::
FeedData
(
const
std
::
vector
<
void
*>
&
inputs
)
{
paddle_mobile_
->
FeedData
(
inputs
);
}
template
<
typename
Device
,
typename
T
>
void
PaddleMobilePredictor
<
Device
,
T
>::
GetResults
(
std
::
vector
<
void
*>
*
outputs
)
{
paddle_mobile_
->
GetResults
(
outputs
);
}
template
<
typename
Device
,
typename
T
>
template
<
typename
Device
,
typename
T
>
void
PaddleMobilePredictor
<
Device
,
T
>::
Predict_From_To
(
int
start
,
int
end
)
{
void
PaddleMobilePredictor
<
Device
,
T
>::
Predict_From_To
(
int
start
,
int
end
)
{
paddle_mobile_
->
Predict_From_To
(
start
,
end
);
paddle_mobile_
->
Predict_From_To
(
start
,
end
);
...
...
src/io/api_paddle_mobile.h
浏览文件 @
2bbf3ec6
...
@@ -33,8 +33,6 @@ class PaddleMobilePredictor : public PaddlePredictor {
...
@@ -33,8 +33,6 @@ class PaddleMobilePredictor : public PaddlePredictor {
std
::
vector
<
PaddleTensor
>*
output_data
,
std
::
vector
<
PaddleTensor
>*
output_data
,
int
batch_size
=
-
1
)
override
;
int
batch_size
=
-
1
)
override
;
#ifdef PADDLE_MOBILE_FPGA
#ifdef PADDLE_MOBILE_FPGA
void
FeedData
(
const
std
::
vector
<
void
*>&
inputs
)
override
;
void
GetResults
(
std
::
vector
<
void
*>*
outputs
)
override
;
void
Predict_From_To
(
int
start
,
int
end
)
override
;
void
Predict_From_To
(
int
start
,
int
end
)
override
;
void
FeedPaddleTensors
(
const
std
::
vector
<
PaddleTensor
>&
inputs
)
override
;
void
FeedPaddleTensors
(
const
std
::
vector
<
PaddleTensor
>&
inputs
)
override
;
void
FetchPaddleTensors
(
std
::
vector
<
PaddleTensor
>*
outputs
)
override
;
void
FetchPaddleTensors
(
std
::
vector
<
PaddleTensor
>*
outputs
)
override
;
...
...
src/io/paddle_inference_api.h
浏览文件 @
2bbf3ec6
...
@@ -113,6 +113,7 @@ class PaddlePredictor {
...
@@ -113,6 +113,7 @@ class PaddlePredictor {
// `inputs`. `inputs` should be available until Run returns. Caller should be
// `inputs`. `inputs` should be available until Run returns. Caller should be
// responsible for the output tensor's buffer, either allocated or passed from
// responsible for the output tensor's buffer, either allocated or passed from
// outside.
// outside.
virtual
bool
Run
(
const
std
::
vector
<
PaddleTensor
>&
inputs
,
virtual
bool
Run
(
const
std
::
vector
<
PaddleTensor
>&
inputs
,
std
::
vector
<
PaddleTensor
>*
output_data
,
std
::
vector
<
PaddleTensor
>*
output_data
,
int
batch_size
=
-
1
)
=
0
;
int
batch_size
=
-
1
)
=
0
;
...
@@ -126,8 +127,6 @@ class PaddlePredictor {
...
@@ -126,8 +127,6 @@ class PaddlePredictor {
std
::
string
param_file
;
std
::
string
param_file
;
};
};
#ifdef PADDLE_MOBILE_FPGA
#ifdef PADDLE_MOBILE_FPGA
virtual
void
FeedData
(
const
std
::
vector
<
void
*>&
inputs
)
=
0
;
virtual
void
GetResults
(
std
::
vector
<
void
*>*
outputs
)
=
0
;
virtual
void
Predict_From_To
(
int
start
,
int
end
)
=
0
;
virtual
void
Predict_From_To
(
int
start
,
int
end
)
=
0
;
virtual
void
FeedPaddleTensors
(
const
std
::
vector
<
PaddleTensor
>&
inputs
)
=
0
;
virtual
void
FeedPaddleTensors
(
const
std
::
vector
<
PaddleTensor
>&
inputs
)
=
0
;
virtual
void
FetchPaddleTensors
(
std
::
vector
<
PaddleTensor
>*
outputs
)
=
0
;
virtual
void
FetchPaddleTensors
(
std
::
vector
<
PaddleTensor
>*
outputs
)
=
0
;
...
...
test/fpga/test_rfcn_api.cpp
浏览文件 @
2bbf3ec6
...
@@ -52,8 +52,21 @@ PaddleMobileConfig GetConfig() {
...
@@ -52,8 +52,21 @@ PaddleMobileConfig GetConfig() {
return
config
;
return
config
;
}
}
PaddleMobileConfig
GetConfig1
()
{
PaddleMobileConfig
config
;
config
.
precision
=
PaddleMobileConfig
::
FP32
;
config
.
device
=
PaddleMobileConfig
::
kFPGA
;
config
.
model_dir
=
"../models/resnet50"
;
config
.
thread_num
=
1
;
config
.
batch_size
=
1
;
config
.
optimize
=
true
;
config
.
quantification
=
false
;
return
config
;
}
int
main
()
{
int
main
()
{
open_device
();
open_device
();
PaddleMobileConfig
config
=
GetConfig
();
PaddleMobileConfig
config
=
GetConfig
();
auto
predictor
=
auto
predictor
=
CreatePaddlePredictor
<
PaddleMobileConfig
,
CreatePaddlePredictor
<
PaddleMobileConfig
,
...
@@ -61,46 +74,22 @@ int main() {
...
@@ -61,46 +74,22 @@ int main() {
std
::
cout
<<
"Finishing loading model"
<<
std
::
endl
;
std
::
cout
<<
"Finishing loading model"
<<
std
::
endl
;
float
img_info
[
3
]
=
{
768
,
1536
,
768.0
f
/
960
.0
f
};
float
img_info
[
3
]
=
{
432
,
1280
,
1
.0
f
};
int
img_length
=
768
*
1536
*
3
;
int
img_length
=
432
*
1280
*
3
;
auto
img
=
reinterpret_cast
<
float
*>
(
fpga_malloc
(
img_length
*
sizeof
(
float
)));
auto
img
=
reinterpret_cast
<
float
*>
(
fpga_malloc
(
img_length
*
sizeof
(
float
)));
readStream
(
g_image
,
reinterpret_cast
<
char
*>
(
img
));
readStream
(
g_image
,
reinterpret_cast
<
char
*>
(
img
));
std
::
cout
<<
"Finishing initializing data"
<<
std
::
endl
;
std
::
cout
<<
"Finishing initializing data"
<<
std
::
endl
;
/*
predictor->FeedData({img_info, img});
predictor->Predict_From_To(0, -1);
std::cout << " Finishing predicting " << std::endl;
std::vector<void *> v(3, nullptr);
predictor->GetResults(&v);
int post_nms = 300;
for (int num = 0; num < post_nms; num ++){
for (int i = 0; i < 8; i ++){
std:: cout << ((float*)(v[0]))[num * 8 + i] << std::endl;
}
}
for (int num = 0; num < post_nms; num ++){
for (int i = 0; i < 8; i ++){
std:: cout << ((float*)(v[1]))[num * 8 + i] << std::endl;
}
}
for (int num = 0; num < post_nms; num ++){
for (int i = 0; i < 4; i ++){
std:: cout << ((float*)(v[2]))[num * 4 + i] << std::endl;
}
}
*/
struct
PaddleTensor
t_img_info
,
t_img
;
struct
PaddleTensor
t_img_info
,
t_img
;
t_img
_info
.
dtype
=
FLOAT32
;
t_img
.
dtypeid
=
typeid
(
float
)
;
t_img_info
.
layout
=
LAYOUT_HWC
;
t_img_info
.
layout
=
LAYOUT_HWC
;
t_img_info
.
shape
=
std
::
vector
<
int
>
({
1
,
3
});
t_img_info
.
shape
=
std
::
vector
<
int
>
({
1
,
3
});
t_img_info
.
name
=
"Image information"
;
t_img_info
.
name
=
"Image information"
;
t_img_info
.
data
.
Reset
(
img_info
,
3
*
sizeof
(
float
));
t_img_info
.
data
.
Reset
(
img_info
,
3
*
sizeof
(
float
));
t_img
.
dtype
=
FLOAT32
;
t_img
.
dtype
id
=
typeid
(
float
)
;
t_img
.
layout
=
LAYOUT_HWC
;
t_img
.
layout
=
LAYOUT_HWC
;
t_img
.
shape
=
std
::
vector
<
int
>
({
1
,
768
,
1536
,
3
});
t_img
.
shape
=
std
::
vector
<
int
>
({
1
,
432
,
1280
,
3
});
t_img
.
name
=
"Image information"
;
t_img
.
name
=
"Image information"
;
t_img
.
data
.
Reset
(
img
,
img_length
*
sizeof
(
float
));
t_img
.
data
.
Reset
(
img
,
img_length
*
sizeof
(
float
));
predictor
->
FeedPaddleTensors
({
t_img_info
,
t_img
});
predictor
->
FeedPaddleTensors
({
t_img_info
,
t_img
});
...
@@ -113,6 +102,9 @@ int main() {
...
@@ -113,6 +102,9 @@ int main() {
std
::
vector
<
PaddleTensor
>
v
;
// No need to initialize v
std
::
vector
<
PaddleTensor
>
v
;
// No need to initialize v
predictor
->
FetchPaddleTensors
(
&
v
);
// Old data in v will be cleared
predictor
->
FetchPaddleTensors
(
&
v
);
// Old data in v will be cleared
std
::
cout
<<
"Output number is "
<<
v
.
size
()
<<
std
::
endl
;
std
::
cout
<<
"Output number is "
<<
v
.
size
()
<<
std
::
endl
;
std
::
cout
<<
"out[0] length "
<<
v
[
0
].
data
.
length
()
<<
std
::
endl
;
std
::
cout
<<
"out[1] length "
<<
v
[
1
].
data
.
length
()
<<
std
::
endl
;
std
::
cout
<<
"out[2] length "
<<
v
[
2
].
data
.
length
()
<<
std
::
endl
;
auto
post_nms
=
v
[
0
].
data
.
length
()
/
sizeof
(
float
)
/
8
;
auto
post_nms
=
v
[
0
].
data
.
length
()
/
sizeof
(
float
)
/
8
;
for
(
int
num
=
0
;
num
<
post_nms
;
num
++
)
{
for
(
int
num
=
0
;
num
<
post_nms
;
num
++
)
{
...
@@ -135,6 +127,8 @@ int main() {
...
@@ -135,6 +127,8 @@ int main() {
}
}
std
::
cout
<<
"Finish getting vector values"
<<
std
::
endl
;
std
::
cout
<<
"Finish getting vector values"
<<
std
::
endl
;
////////////////////////////////////////////////////
PaddleTensor
tensor
;
PaddleTensor
tensor
;
predictor
->
GetPaddleTensor
(
"fetch2"
,
&
tensor
);
predictor
->
GetPaddleTensor
(
"fetch2"
,
&
tensor
);
for
(
int
i
=
0
;
i
<
post_nms
;
i
++
)
{
for
(
int
i
=
0
;
i
<
post_nms
;
i
++
)
{
...
@@ -142,5 +136,36 @@ int main() {
...
@@ -142,5 +136,36 @@ int main() {
std
::
cout
<<
p
[
+
i
]
<<
std
::
endl
;
std
::
cout
<<
p
[
+
i
]
<<
std
::
endl
;
}
}
//////////////////////////////////////////////////////
PaddleMobileConfig
config1
=
GetConfig1
();
auto
predictor1
=
CreatePaddlePredictor
<
PaddleMobileConfig
,
PaddleEngineKind
::
kPaddleMobile
>
(
config1
);
std
::
cout
<<
"Finishing loading model"
<<
std
::
endl
;
int
img_length1
=
224
*
224
*
3
;
auto
img1
=
reinterpret_cast
<
float
*>
(
fpga_malloc
(
img_length1
*
sizeof
(
float
)));
std
::
cout
<<
"Finishing initializing data"
<<
std
::
endl
;
struct
PaddleTensor
t_img1
;
t_img1
.
dtypeid
=
typeid
(
float
);
t_img1
.
layout
=
LAYOUT_HWC
;
t_img1
.
shape
=
std
::
vector
<
int
>
({
1
,
224
,
224
,
3
});
t_img1
.
name
=
"Image information"
;
t_img1
.
data
.
Reset
(
img1
,
img_length1
*
sizeof
(
float
));
predictor1
->
FeedPaddleTensors
({
t_img1
});
predictor1
->
Predict_From_To
(
0
,
-
1
);
std
::
cout
<<
"Finishing predicting "
<<
std
::
endl
;
std
::
vector
<
PaddleTensor
>
v1
;
// No need to initialize v
predictor1
->
FetchPaddleTensors
(
&
v1
);
// Old data in v will be cleared
std
::
cout
<<
"Output number is "
<<
v1
.
size
()
<<
std
::
endl
;
std
::
cout
<<
"out[0] length "
<<
v1
[
0
].
data
.
length
()
<<
std
::
endl
;
return
0
;
return
0
;
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录