Skip to content

Commit 8226d44

Browse files
authored
fix container not clear bug for inference (#14674)
1 parent c7153f8 commit 8226d44

File tree

5 files changed

+51
-9
lines changed

5 files changed

+51
-9
lines changed

paddle/fluid/inference/analysis/analysis_pass.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,6 @@ class AnalysisPass {
4646
protected:
4747
// User should implement these.
4848
virtual void RunImpl(Argument* argument) = 0;
49-
50-
Argument* argument_{nullptr};
5149
};
5250

5351
} // namespace analysis

paddle/fluid/inference/api/analysis_predictor.cc

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -190,9 +190,13 @@ bool AnalysisPredictor::Run(const std::vector<PaddleTensor> &inputs,
190190
}
191191
VLOG(3) << "predict cost: " << timer.toc() << "ms";
192192

193-
// Fix TensorArray reuse not cleaned bug.
194-
tensor_array_batch_cleaner_.CollectTensorArrays(scope_.get());
195-
tensor_array_batch_cleaner_.ResetTensorArray();
193+
// All the containers in the scope will be hold in inference, but the
194+
// operators assume that the container will be reset after each batch.
195+
// Here is a bugfix, collect all the container variables, and reset then to a
196+
// bool; the next time, the operator will call MutableData and construct a new
197+
// container again, so that the container will be empty for each batch.
198+
tensor_array_batch_cleaner_.CollectNoTensorVars(sub_scope_);
199+
tensor_array_batch_cleaner_.ResetNoTensorVars();
196200
return true;
197201
}
198202

@@ -417,7 +421,7 @@ std::unique_ptr<ZeroCopyTensor> AnalysisPredictor::GetOutputTensor(
417421
bool AnalysisPredictor::ZeroCopyRun() {
418422
executor_->Run();
419423
// Fix TensorArray reuse not cleaned bug.
420-
tensor_array_batch_cleaner_.CollectTensorArrays(scope_.get());
424+
tensor_array_batch_cleaner_.CollectTensorArrays(sub_scope_);
421425
tensor_array_batch_cleaner_.ResetTensorArray();
422426
return true;
423427
}

paddle/fluid/inference/api/api_impl.cc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -154,9 +154,9 @@ bool NativePaddlePredictor::Run(const std::vector<PaddleTensor> &inputs,
154154
}
155155
VLOG(3) << "predict cost: " << timer.toc() << "ms";
156156

157-
// Fix TensorArray reuse not cleaned bug.
158-
tensor_array_batch_cleaner_.CollectTensorArrays(scope_.get());
159-
tensor_array_batch_cleaner_.ResetTensorArray();
157+
// For some other vector like containers not cleaned after each batch.
158+
tensor_array_batch_cleaner_.CollectNoTensorVars(scope_.get());
159+
tensor_array_batch_cleaner_.ResetNoTensorVars();
160160
return true;
161161
}
162162

paddle/fluid/inference/api/details/reset_tensor_array.cc

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,5 +46,28 @@ void TensorArrayBatchCleaner::ResetTensorArray() {
4646
}
4747
}
4848

49+
void TensorArrayBatchCleaner::CollectNoTensorVars(framework::Scope *scope) {
50+
if (no_tensor_flag_) {
51+
for (auto &var_name : scope->LocalVarNames()) {
52+
auto *var = scope->FindVar(var_name);
53+
if (!var->IsInitialized()) continue;
54+
if (!valid_types_.count(var->Type())) {
55+
no_tensor_vars_.insert(var);
56+
}
57+
}
58+
59+
for (auto *kid : scope->kids()) {
60+
CollectTensorArrays(kid);
61+
}
62+
no_tensor_flag_ = false; // Only collect one time.
63+
}
64+
}
65+
66+
void TensorArrayBatchCleaner::ResetNoTensorVars() {
67+
for (auto *var : no_tensor_vars_) {
68+
var->Clear();
69+
}
70+
}
71+
4972
} // namespace details
5073
} // namespace paddle

paddle/fluid/inference/api/details/reset_tensor_array.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,23 +14,40 @@
1414

1515
#pragma once
1616

17+
#include <unordered_set>
1718
#include <vector>
1819
#include "paddle/fluid/framework/lod_tensor_array.h"
1920
#include "paddle/fluid/framework/scope.h"
21+
#include "paddle/fluid/framework/variable.h"
2022

2123
namespace paddle {
2224
namespace details {
2325

2426
// Clean the TensorArray each batch to make the behavior the same with the
2527
// training phase.
2628
struct TensorArrayBatchCleaner {
29+
TensorArrayBatchCleaner() {
30+
valid_types_.insert(typeid(framework::Tensor));
31+
valid_types_.insert(typeid(framework::LoDTensor));
32+
}
33+
// Collect the variables that are not Tensor or LoDTensor, and reset them to a
34+
// bool(trick), because some of them are containers, and some operators just
35+
// keep inserting new items without clearing the containers first; So the
36+
// memory grow larger and larger in inference service deployed online.
37+
void CollectNoTensorVars(framework::Scope *scope);
38+
void ResetNoTensorVars();
39+
2740
// Fix the tensor array not clear in the inference scenarios.
2841
void CollectTensorArrays(framework::Scope *scope);
2942
void ResetTensorArray();
3043

3144
private:
3245
bool flag_{true};
46+
bool no_tensor_flag_{true};
3347
std::vector<framework::LoDTensorArray *> arrays_;
48+
49+
std::unordered_set<std::type_index> valid_types_;
50+
std::unordered_set<framework::Variable *> no_tensor_vars_;
3451
};
3552

3653
} // namespace details

0 commit comments

Comments
 (0)