Skip to content

Commit 55d6950

Browse files
committed
rewrite conv_bn fuse pass to eigen
test=develop
1 parent 9c77b65 commit 55d6950

File tree

1 file changed

+39
-96
lines changed

1 file changed

+39
-96
lines changed

paddle/fluid/framework/ir/conv_bn_fuse_pass.cc

Lines changed: 39 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -44,87 +44,16 @@ namespace ir {
4444
GET_IR_NODE_FROM_SUBGRAPH(bn_saved_mean, bn_saved_mean, pattern_name); \
4545
GET_IR_NODE_FROM_SUBGRAPH(bn_saved_variance, bn_saved_variance, pattern_name)
4646

47-
template <typename UnaryOperation>
48-
LoDTensor tensor_apply(const LoDTensor& vec, UnaryOperation f) {
49-
LoDTensor vec_y;
50-
vec_y.Resize(vec.dims());
51-
const float* x = vec.data<float>();
52-
float* y = vec_y.mutable_data<float>(platform::CPUPlace());
53-
for (int64_t i = 0; i < vec.numel(); i++) {
54-
y[i] = f(x[i]);
55-
}
56-
return vec_y;
57-
}
58-
59-
void tensor_apply_inplace(LoDTensor* vec, float (*f)(float)) {
60-
float* data = vec->mutable_data<float>(platform::CPUPlace());
61-
for (int64_t i = 0; i < vec->numel(); i++) {
62-
data[i] = f(data[i]);
63-
}
64-
}
65-
66-
template <typename BinaryOperation>
67-
LoDTensor tensor_apply_eltwise(const LoDTensor& vec_a, const LoDTensor& vec_b,
68-
BinaryOperation f) {
69-
PADDLE_ENFORCE_EQ(vec_a.dims(), vec_b.dims());
70-
LoDTensor vec_y;
71-
vec_y.Resize(vec_a.dims());
72-
const float* a = vec_a.data<float>();
73-
const float* b = vec_b.data<float>();
74-
float* y = vec_y.mutable_data<float>(platform::CPUPlace());
75-
for (int64_t i = 0; i < vec_a.numel(); i++) {
76-
y[i] = f(a[i], b[i]);
77-
}
78-
return vec_y;
79-
}
80-
81-
template <typename BinaryOperation>
82-
LoDTensor tensor_apply_eltwise_broadcast(const LoDTensor& vec_a,
83-
const LoDTensor& vec_b,
84-
BinaryOperation f) {
85-
PADDLE_ENFORCE_EQ(vec_a.dims().size(), 2);
86-
PADDLE_ENFORCE_EQ(vec_b.dims().size(), 2);
87-
PADDLE_ENFORCE_EQ(vec_a.dims()[0], vec_b.dims()[0]);
88-
PADDLE_ENFORCE_EQ(vec_b.dims()[1], 1);
89-
LoDTensor vec_y;
90-
vec_y.Resize(vec_a.dims());
91-
const float* a = vec_a.data<float>();
92-
const float* b = vec_b.data<float>();
93-
float* y = vec_y.mutable_data<float>(platform::CPUPlace());
94-
size_t a_height = vec_a.dims()[0];
95-
size_t a_width = vec_a.dims()[1];
96-
for (size_t h = 0; h < a_height; h++) {
97-
for (size_t w = 0; w < a_width; ++w) {
98-
*(y++) = f(*(a++), b[h]);
99-
}
100-
}
101-
return vec_y;
102-
}
103-
10447
// reshape to two dimensions {A, B * C * ...}
105-
void make_tensor_2d(LoDTensor* tensor_to_reshape) {
106-
auto dims_count = tensor_to_reshape->dims().size();
48+
DDim make_dims_2d(DDim dims) {
49+
auto dims_count = dims.size();
10750
PADDLE_ENFORCE_GT(dims_count, 0);
10851

10952
int size2 = 1;
11053
for (int i = 1; i < dims_count; i++) {
111-
size2 *= tensor_to_reshape->dims()[i];
54+
size2 *= dims[i];
11255
}
113-
tensor_to_reshape->Resize(make_ddim({tensor_to_reshape->dims()[0], size2}));
114-
}
115-
116-
void recompute_conv_weights(LoDTensor* weights, LoDTensor* tmp) {
117-
// remember the weights tensor shape {A, B, C, ...}
118-
auto weights_shape = weights->dims();
119-
// reduce the weights to 2d {A, B * C * ...}
120-
make_tensor_2d(weights);
121-
// make tmp tensor 2d by adding 1 as second dim {A, 1}
122-
make_tensor_2d(tmp);
123-
124-
*weights =
125-
tensor_apply_eltwise_broadcast(*weights, *tmp, std::multiplies<float>());
126-
// reshape weights to the original dims {A, B, C, ...}
127-
weights->Resize(weights_shape);
56+
return make_ddim({dims[0], size2});
12857
}
12958

13059
void recompute_bias_and_weights(const Scope* scope,
@@ -135,6 +64,13 @@ void recompute_bias_and_weights(const Scope* scope,
13564
const ir::Node& bn_variance, //
13665
LoDTensor* eltwise_y_in_tensor, //
13766
float epsilon) {
67+
using EigenVectorArrayMap =
68+
Eigen::Map<Eigen::Array<float, Eigen::Dynamic, 1>>;
69+
using ConstEigenVectorArrayMap =
70+
Eigen::Map<const Eigen::Array<float, Eigen::Dynamic, 1>>;
71+
using EigenMatrixArrayMap = Eigen::Map<
72+
Eigen::Array<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>>;
73+
13874
// Re-compute bias of conv2d from BN
13975
PADDLE_ENFORCE_EQ(eltwise_y_in_tensor->dims(), bn_bias_tensor.dims());
14076

@@ -143,31 +79,38 @@ void recompute_bias_and_weights(const Scope* scope,
14379
scope->FindVar(bn_variance.Name())->GetMutable<LoDTensor>();
14480
auto* mean_tensor = scope->FindVar(bn_mean.Name())->GetMutable<LoDTensor>();
14581

146-
auto std_tensor = LoDTensor();
147-
std_tensor.Resize(bn_bias_tensor.dims());
148-
std_tensor =
149-
tensor_apply(*variance_tensor, [&](float x) { return x + epsilon; });
82+
ConstEigenVectorArrayMap scale_array(scale_tensor->data<float>(),
83+
scale_tensor->numel(), 1);
84+
EigenVectorArrayMap variance_array(
85+
variance_tensor->mutable_data<float>(platform::CPUPlace()),
86+
variance_tensor->numel(), 1);
87+
ConstEigenVectorArrayMap mean_array(mean_tensor->data<float>(),
88+
mean_tensor->numel(), 1);
89+
ConstEigenVectorArrayMap bn_bias_array(bn_bias_tensor.data<float>(),
90+
bn_bias_tensor.numel(), 1);
15091

151-
using EigenVectorArrayMap =
152-
Eigen::Map<Eigen::Array<float, Eigen::Dynamic, 1>>;
92+
// variance will not be used anymore, so make it std_array and then tmp_array
93+
variance_array += epsilon;
94+
variance_array = variance_array.sqrt();
95+
variance_array = scale_array / variance_array;
96+
97+
EigenVectorArrayMap eltwise_y_in_array(
98+
eltwise_y_in_tensor->mutable_data<float>(platform::CPUPlace()),
99+
eltwise_y_in_tensor->numel(), 1);
153100

154-
EigenVectorArrayMap std_vec(
155-
std_tensor.mutable_data<float>(platform::CPUPlace()), std_tensor.numel(),
156-
1);
157-
std_vec = std_vec.sqrt();
158-
auto tmp_tensor =
159-
tensor_apply_eltwise(*scale_tensor, std_tensor, std::divides<float>());
160-
auto tensor_minus = tensor_apply_eltwise(*eltwise_y_in_tensor, *mean_tensor,
161-
std::minus<float>());
162-
auto tensor_mul =
163-
tensor_apply_eltwise(tensor_minus, tmp_tensor, std::multiplies<float>());
164-
*eltwise_y_in_tensor =
165-
tensor_apply_eltwise(tensor_mul, bn_bias_tensor, std::plus<float>());
101+
eltwise_y_in_array =
102+
((eltwise_y_in_array - mean_array) * variance_array) + bn_bias_array;
166103

167104
// Re-compute weight of conv2d from BN
168-
auto* current_param =
169-
scope->FindVar(conv_weight->Name())->GetMutable<LoDTensor>();
170-
recompute_conv_weights(current_param, &tmp_tensor);
105+
auto* weights = scope->FindVar(conv_weight->Name())->GetMutable<LoDTensor>();
106+
auto weights_shape = weights->dims();
107+
auto weights_shape_2d = make_dims_2d(weights_shape);
108+
109+
EigenMatrixArrayMap weights_array_2d(
110+
weights->mutable_data<float>(platform::CPUPlace()), weights_shape_2d[0],
111+
weights_shape_2d[1]);
112+
113+
weights_array_2d.colwise() *= variance_array;
171114
}
172115

173116
std::unique_ptr<ir::Graph> ConvBNFusePass::ApplyImpl(

0 commit comments

Comments
 (0)