add fleet pslib pull and push sparse op and push dense op (#23139)
* add fleet pslib pull and push sparse op and push dense op * test=developrevert-23830-2.0-beta
parent
0536b5263d
commit
3a45767d49
@ -0,0 +1,143 @@
|
||||
// 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.
|
||||
|
||||
#include "paddle/fluid/operators/pull_sparse_op.h"
|
||||
#include <string>
|
||||
|
||||
namespace paddle {
|
||||
namespace operators {
|
||||
|
||||
class PullSparseOp : public framework::OperatorWithKernel {
|
||||
public:
|
||||
using framework::OperatorWithKernel::OperatorWithKernel;
|
||||
void InferShape(framework::InferShapeContext* ctx) const override {
|
||||
PADDLE_ENFORCE_GE(ctx->Inputs("Ids").size(), 1UL,
|
||||
platform::errors::InvalidArgument(
|
||||
"Input(Ids) of PullSparseOp can not be null"));
|
||||
PADDLE_ENFORCE_GE(ctx->Outputs("Out").size(), 1UL,
|
||||
platform::errors::InvalidArgument(
|
||||
"Output(Out) of PullSparseOp can not be null"));
|
||||
|
||||
auto hidden_size =
|
||||
static_cast<uint32_t>(ctx->Attrs().Get<int>("EmbeddingDim"));
|
||||
auto all_ids_dim = ctx->GetInputsDim("Ids");
|
||||
const size_t n_ids = all_ids_dim.size();
|
||||
std::vector<framework::DDim> outs_dims;
|
||||
outs_dims.resize(n_ids);
|
||||
for (size_t i = 0; i < n_ids; ++i) {
|
||||
const auto ids_dims = all_ids_dim[i];
|
||||
int ids_rank = ids_dims.size();
|
||||
PADDLE_ENFORCE_EQ(ids_dims[ids_rank - 1], 1,
|
||||
platform::errors::InvalidArgument(
|
||||
"Shape error in %lu id, the last dimension of "
|
||||
" the 'Ids' tensor must be 1.",
|
||||
i));
|
||||
auto out_dim = framework::vectorize(
|
||||
framework::slice_ddim(ids_dims, 0, ids_rank - 1));
|
||||
out_dim.push_back(hidden_size);
|
||||
outs_dims[i] = framework::make_ddim(out_dim);
|
||||
}
|
||||
ctx->SetOutputsDim("Out", outs_dims);
|
||||
for (size_t i = 0; i < n_ids; ++i) {
|
||||
ctx->ShareLoD("Ids", "Out", i, i);
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
framework::OpKernelType GetExpectedKernelType(
|
||||
const framework::ExecutionContext& ctx) const override {
|
||||
return framework::OpKernelType(framework::proto::VarType::FP32,
|
||||
ctx.device_context());
|
||||
}
|
||||
};
|
||||
|
||||
class PullSparseOpMaker : public framework::OpProtoAndCheckerMaker {
|
||||
public:
|
||||
void Make() override {
|
||||
AddInput("Ids",
|
||||
"Input tensors with type int64 contains "
|
||||
"the ids to be looked up in PSLib. "
|
||||
"The last dimension size must be 1.")
|
||||
.AsDuplicable();
|
||||
AddInput("W", "The lookup table tensors.").AsDuplicable();
|
||||
AddOutput("Out", "The lookup results tensors.").AsDuplicable();
|
||||
AddAttr<int>("EmbeddingDim", "(int, the embedding hidden size")
|
||||
.SetDefault(11);
|
||||
AddAttr<int>("TableId", "(int, the table id of this embedding")
|
||||
.SetDefault(0);
|
||||
AddAttr<std::string>("AccessorClass", "(string, the class name of accessor")
|
||||
.SetDefault("");
|
||||
AddAttr<std::string>("CtrLabelName", "(string, ctr label name")
|
||||
.SetDefault("");
|
||||
AddAttr<int>("PaddingId", "(int, the padding id of this embedding")
|
||||
.SetDefault(0);
|
||||
AddAttr<bool>("ScaleSparseGrad",
|
||||
"(bool, whether scale sparse gradient with batch size")
|
||||
.SetDefault(true);
|
||||
AddAttr<std::vector<std::string>>("InputNames", "(vector, slot names")
|
||||
.SetDefault(std::vector<std::string>());
|
||||
AddAttr<bool>("is_distributed", "(bool, it must be true").SetDefault(true);
|
||||
AddComment(R"DOC(
|
||||
Pull Sparse Operator.
|
||||
|
||||
This operator is used to perform lookups on the PSLib
|
||||
then concatenated into a dense tensor.
|
||||
|
||||
The input Ids can carry the LoD (Level of Details) information,
|
||||
or not. And the output only shares the LoD information with input Ids.
|
||||
|
||||
)DOC");
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class PushSparseOpMaker : public framework::SingleGradOpMaker<T> {
|
||||
public:
|
||||
using framework::SingleGradOpMaker<T>::SingleGradOpMaker;
|
||||
|
||||
protected:
|
||||
void Apply(GradOpPtr<T> retv) const override {
|
||||
retv->SetType("push_sparse");
|
||||
retv->SetInput("Ids", this->Input("Ids"));
|
||||
retv->SetInput(framework::GradVarName("Out"), this->OutputGrad("Out"));
|
||||
retv->SetInput("W", this->Input("W"));
|
||||
retv->SetOutput(framework::GradVarName("Out"), this->OutputGrad("Out"));
|
||||
retv->SetAttrMap(this->Attrs());
|
||||
}
|
||||
};
|
||||
|
||||
class PushSparseOp : public framework::OperatorWithKernel {
|
||||
public:
|
||||
using framework::OperatorWithKernel::OperatorWithKernel;
|
||||
|
||||
void InferShape(framework::InferShapeContext* ctx) const override {}
|
||||
|
||||
protected:
|
||||
framework::OpKernelType GetExpectedKernelType(
|
||||
const framework::ExecutionContext& ctx) const override {
|
||||
return framework::OpKernelType(OperatorWithKernel::IndicateVarDataType(
|
||||
ctx, framework::GradVarName("Out")),
|
||||
ctx.device_context());
|
||||
}
|
||||
};
|
||||
} // namespace operators
|
||||
} // namespace paddle
|
||||
|
||||
namespace ops = paddle::operators;
|
||||
REGISTER_OPERATOR(pull_sparse, ops::PullSparseOp, ops::PullSparseOpMaker,
|
||||
ops::PushSparseOpMaker<paddle::framework::OpDesc>,
|
||||
ops::PushSparseOpMaker<paddle::imperative::OpBase>);
|
||||
REGISTER_OPERATOR(push_sparse, ops::PushSparseOp);
|
||||
REGISTER_OP_CPU_KERNEL(pull_sparse, ops::PullSparseCPUKernel<float>)
|
||||
REGISTER_OP_CPU_KERNEL(push_sparse, ops::PushSparseCPUKernel<float>)
|
@ -0,0 +1,77 @@
|
||||
// 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.
|
||||
|
||||
#pragma once
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "paddle/fluid/framework/fleet/fleet_wrapper.h"
|
||||
#include "paddle/fluid/framework/op_registry.h"
|
||||
#include "paddle/fluid/framework/tensor.h"
|
||||
|
||||
namespace paddle {
|
||||
namespace operators {
|
||||
|
||||
template <typename T>
|
||||
void PullSparseFunctor(const framework::ExecutionContext& ctx) {
|
||||
auto inputs = ctx.MultiInput<framework::LoDTensor>("Ids");
|
||||
auto outputs = ctx.MultiOutput<framework::LoDTensor>("Out");
|
||||
uint32_t fea_dim = static_cast<uint32_t>(ctx.Attr<int>("EmbeddingDim"));
|
||||
uint64_t padding_id = static_cast<uint64_t>(ctx.Attr<int>("PaddingId"));
|
||||
auto table_id = static_cast<uint32_t>(ctx.Attr<int>("TableId"));
|
||||
// note: GetInstance() is not thread-safe
|
||||
// we assume FleetWrapper has been already initialized
|
||||
auto fleet_ptr = framework::FleetWrapper::GetInstance();
|
||||
fleet_ptr->PullSparseToTensorSync(table_id, fea_dim, padding_id,
|
||||
ctx.GetPlace(), &inputs, &outputs);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void PushSparseFunctor(const framework::ExecutionContext& ctx) {
|
||||
auto inputs = ctx.MultiInput<framework::LoDTensor>("Ids");
|
||||
auto grads =
|
||||
ctx.MultiInput<framework::LoDTensor>(framework::GradVarName("Out"));
|
||||
uint32_t fea_dim = static_cast<uint32_t>(ctx.Attr<int>("EmbeddingDim"));
|
||||
std::string accesor = ctx.Attr<std::string>("AccessorClass");
|
||||
bool scale_sparse = ctx.Attr<bool>("ScaleSparseGrad");
|
||||
uint64_t padding_id = static_cast<uint64_t>(ctx.Attr<int>("PaddingId"));
|
||||
const std::string& label_name = ctx.Attr<std::string>("CtrLabelName");
|
||||
const framework::Scope& scope = ctx.scope();
|
||||
auto input_names = ctx.Attr<std::vector<std::string>>("InputNames");
|
||||
auto table_id = static_cast<uint32_t>(ctx.Attr<int>("TableId"));
|
||||
// note: GetInstance() is not thread-safe
|
||||
// we assume FleetWrapper has been already initialized
|
||||
auto fleet_ptr = framework::FleetWrapper::GetInstance();
|
||||
fleet_ptr->PushSparseFromTensorWithLabelAsync(
|
||||
scope, table_id, fea_dim, padding_id, scale_sparse, accesor, label_name,
|
||||
ctx.GetPlace(), input_names, &inputs, &grads);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
class PullSparseCPUKernel : public framework::OpKernel<T> {
|
||||
public:
|
||||
void Compute(const framework::ExecutionContext& ctx) const override {
|
||||
PullSparseFunctor<T>(ctx);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class PushSparseCPUKernel : public framework::OpKernel<T> {
|
||||
public:
|
||||
void Compute(const framework::ExecutionContext& ctx) const override {
|
||||
PushSparseFunctor<T>(ctx);
|
||||
}
|
||||
};
|
||||
} // namespace operators
|
||||
} // namespace paddle
|
@ -0,0 +1,135 @@
|
||||
// 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.
|
||||
|
||||
#include "paddle/fluid/operators/pull_sparse_v2_op.h"
|
||||
#include <string>
|
||||
|
||||
namespace paddle {
|
||||
namespace operators {
|
||||
|
||||
class PullSparseV2Op : public framework::OperatorWithKernel {
|
||||
public:
|
||||
using framework::OperatorWithKernel::OperatorWithKernel;
|
||||
void InferShape(framework::InferShapeContext* ctx) const override {
|
||||
PADDLE_ENFORCE_GE(ctx->Inputs("Ids").size(), 1UL,
|
||||
platform::errors::InvalidArgument(
|
||||
"Input(Ids) of PullSparseV2Op can not be null"));
|
||||
PADDLE_ENFORCE_GE(ctx->Outputs("Out").size(), 1UL,
|
||||
platform::errors::InvalidArgument(
|
||||
"Output(Out) of PullSparseV2Op can not be null"));
|
||||
|
||||
auto hidden_size =
|
||||
static_cast<uint32_t>(ctx->Attrs().Get<int>("EmbeddingDim"));
|
||||
auto all_ids_dim = ctx->GetInputsDim("Ids");
|
||||
const size_t n_ids = all_ids_dim.size();
|
||||
std::vector<framework::DDim> outs_dims;
|
||||
outs_dims.resize(n_ids);
|
||||
for (size_t i = 0; i < n_ids; ++i) {
|
||||
const auto ids_dims = all_ids_dim[i];
|
||||
auto out_dim = framework::vectorize(ids_dims);
|
||||
out_dim.push_back(hidden_size);
|
||||
outs_dims[i] = framework::make_ddim(out_dim);
|
||||
}
|
||||
ctx->SetOutputsDim("Out", outs_dims);
|
||||
for (size_t i = 0; i < n_ids; ++i) {
|
||||
ctx->ShareLoD("Ids", "Out", i, i);
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
framework::OpKernelType GetExpectedKernelType(
|
||||
const framework::ExecutionContext& ctx) const override {
|
||||
return framework::OpKernelType(framework::proto::VarType::FP32,
|
||||
ctx.device_context());
|
||||
}
|
||||
};
|
||||
|
||||
class PullSparseV2OpMaker : public framework::OpProtoAndCheckerMaker {
|
||||
public:
|
||||
void Make() override {
|
||||
AddInput("Ids",
|
||||
"Input tensors with type int64 contains "
|
||||
"the ids to be looked up in PSLib. ")
|
||||
.AsDuplicable();
|
||||
AddInput("W", "The lookup table tensors.").AsDuplicable();
|
||||
AddOutput("Out", "The lookup results tensors.").AsDuplicable();
|
||||
AddAttr<int>("EmbeddingDim", "(int, the embedding hidden size")
|
||||
.SetDefault(11);
|
||||
AddAttr<int>("TableId", "(int, the table id of this embedding")
|
||||
.SetDefault(0);
|
||||
AddAttr<std::string>("AccessorClass", "(string, the class name of accessor")
|
||||
.SetDefault("");
|
||||
AddAttr<std::string>("CtrLabelName", "(string, ctr label name")
|
||||
.SetDefault("");
|
||||
AddAttr<int>("PaddingId", "(int, the padding id of this embedding")
|
||||
.SetDefault(0);
|
||||
AddAttr<bool>("ScaleSparseGrad",
|
||||
"(bool, whether scale sparse gradient with batch size")
|
||||
.SetDefault(true);
|
||||
AddAttr<std::vector<std::string>>("InputNames", "(vector, slot names")
|
||||
.SetDefault(std::vector<std::string>());
|
||||
AddAttr<bool>("is_distributed", "(bool, it must be true").SetDefault(true);
|
||||
AddComment(R"DOC(
|
||||
Pull Sparse V2 Operator.
|
||||
|
||||
This operator is used to perform lookups on the PSLib
|
||||
then concatenated into a dense tensor.
|
||||
|
||||
The input Ids can carry the LoD (Level of Details) information,
|
||||
or not. And the output only shares the LoD information with input Ids.
|
||||
|
||||
)DOC");
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class PushSparseV2OpMaker : public framework::SingleGradOpMaker<T> {
|
||||
public:
|
||||
using framework::SingleGradOpMaker<T>::SingleGradOpMaker;
|
||||
|
||||
protected:
|
||||
void Apply(GradOpPtr<T> retv) const override {
|
||||
retv->SetType("push_sparse_v2");
|
||||
retv->SetInput("Ids", this->Input("Ids"));
|
||||
retv->SetInput(framework::GradVarName("Out"), this->OutputGrad("Out"));
|
||||
retv->SetInput("W", this->Input("W"));
|
||||
retv->SetOutput(framework::GradVarName("Out"), this->OutputGrad("Out"));
|
||||
retv->SetAttrMap(this->Attrs());
|
||||
}
|
||||
};
|
||||
|
||||
class PushSparseV2Op : public framework::OperatorWithKernel {
|
||||
public:
|
||||
using framework::OperatorWithKernel::OperatorWithKernel;
|
||||
|
||||
void InferShape(framework::InferShapeContext* ctx) const override {}
|
||||
|
||||
protected:
|
||||
framework::OpKernelType GetExpectedKernelType(
|
||||
const framework::ExecutionContext& ctx) const override {
|
||||
return framework::OpKernelType(OperatorWithKernel::IndicateVarDataType(
|
||||
ctx, framework::GradVarName("Out")),
|
||||
ctx.device_context());
|
||||
}
|
||||
};
|
||||
} // namespace operators
|
||||
} // namespace paddle
|
||||
|
||||
namespace ops = paddle::operators;
|
||||
REGISTER_OPERATOR(pull_sparse_v2, ops::PullSparseV2Op, ops::PullSparseV2OpMaker,
|
||||
ops::PushSparseV2OpMaker<paddle::framework::OpDesc>,
|
||||
ops::PushSparseV2OpMaker<paddle::imperative::OpBase>);
|
||||
REGISTER_OPERATOR(push_sparse_v2, ops::PushSparseV2Op);
|
||||
REGISTER_OP_CPU_KERNEL(pull_sparse_v2, ops::PullSparseV2CPUKernel<float>)
|
||||
REGISTER_OP_CPU_KERNEL(push_sparse_v2, ops::PushSparseV2CPUKernel<float>)
|
@ -0,0 +1,43 @@
|
||||
// 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.
|
||||
|
||||
#pragma once
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "paddle/fluid/framework/fleet/fleet_wrapper.h"
|
||||
#include "paddle/fluid/framework/op_registry.h"
|
||||
#include "paddle/fluid/framework/tensor.h"
|
||||
#include "paddle/fluid/operators/pull_sparse_op.h"
|
||||
|
||||
namespace paddle {
|
||||
namespace operators {
|
||||
|
||||
template <typename T>
|
||||
class PullSparseV2CPUKernel : public framework::OpKernel<T> {
|
||||
public:
|
||||
void Compute(const framework::ExecutionContext& ctx) const override {
|
||||
PullSparseFunctor<T>(ctx);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class PushSparseV2CPUKernel : public framework::OpKernel<T> {
|
||||
public:
|
||||
void Compute(const framework::ExecutionContext& ctx) const override {
|
||||
PushSparseFunctor<T>(ctx);
|
||||
}
|
||||
};
|
||||
} // namespace operators
|
||||
} // namespace paddle
|
@ -0,0 +1,70 @@
|
||||
// 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.
|
||||
|
||||
#include "paddle/fluid/operators/push_dense_op.h"
|
||||
#include <string>
|
||||
|
||||
namespace paddle {
|
||||
namespace operators {
|
||||
|
||||
class PushDenseOp : public framework::OperatorWithKernel {
|
||||
public:
|
||||
using framework::OperatorWithKernel::OperatorWithKernel;
|
||||
void InferShape(framework::InferShapeContext* ctx) const override {
|
||||
PADDLE_ENFORCE_GE(ctx->Inputs("Ids").size(), 1UL,
|
||||
platform::errors::InvalidArgument(
|
||||
"Input(Ids) of PushDenseOp can not be null."));
|
||||
}
|
||||
|
||||
protected:
|
||||
framework::OpKernelType GetExpectedKernelType(
|
||||
const framework::ExecutionContext& ctx) const override {
|
||||
return framework::OpKernelType(framework::proto::VarType::FP32,
|
||||
ctx.device_context());
|
||||
}
|
||||
};
|
||||
|
||||
class PushDenseOpMaker : public framework::OpProtoAndCheckerMaker {
|
||||
public:
|
||||
void Make() override {
|
||||
AddInput("Ids", "the tensor to get batch size").AsDuplicable();
|
||||
AddAttr<int>("TableId", "(int, the table id of this embedding")
|
||||
.SetDefault(-1);
|
||||
AddAttr<float>("ScaleDataNorm", "(float, scale data norm gradient")
|
||||
.SetDefault(-1.0f);
|
||||
AddAttr<std::vector<std::string>>("InputNames", "(vector, slot names")
|
||||
.SetDefault(std::vector<std::string>());
|
||||
AddComment(R"DOC(
|
||||
Push Dense Operator.
|
||||
|
||||
push dense gradients to PSLib's Parameter Server.
|
||||
|
||||
The input gradients is all dense gradient tensors in a table.
|
||||
|
||||
)DOC");
|
||||
}
|
||||
};
|
||||
|
||||
DECLARE_NO_NEED_BUFFER_VARS_INFERER(PushDenseNoNeedBufferVarsInference, "Ids");
|
||||
|
||||
} // namespace operators
|
||||
} // namespace paddle
|
||||
|
||||
namespace ops = paddle::operators;
|
||||
REGISTER_OPERATOR(
|
||||
push_dense, ops::PushDenseOp, ops::PushDenseOpMaker,
|
||||
paddle::framework::EmptyGradOpMaker<paddle::framework::OpDesc>,
|
||||
paddle::framework::EmptyGradOpMaker<paddle::imperative::OpBase>,
|
||||
ops::PushDenseNoNeedBufferVarsInference);
|
||||
REGISTER_OP_CPU_KERNEL(push_dense, ops::PushDenseCPUKernel<float>)
|
@ -0,0 +1,68 @@
|
||||
// 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.
|
||||
|
||||
#pragma once
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "paddle/fluid/framework/device_worker.h"
|
||||
#include "paddle/fluid/framework/fleet/fleet_wrapper.h"
|
||||
#include "paddle/fluid/framework/no_need_buffer_vars_inference.h"
|
||||
#include "paddle/fluid/framework/op_registry.h"
|
||||
#include "paddle/fluid/framework/tensor.h"
|
||||
|
||||
namespace paddle {
|
||||
namespace operators {
|
||||
|
||||
template <typename T>
|
||||
void PushDenseFunctor(const framework::ExecutionContext& ctx) {
|
||||
#ifdef PADDLE_WITH_PSLIB
|
||||
const auto& input_names = ctx.Attr<std::vector<std::string>>("InputNames");
|
||||
auto table_id = static_cast<uint32_t>(ctx.Attr<int>("TableId"));
|
||||
PADDLE_ENFORCE_GT(table_id, 0,
|
||||
platform::errors::InvalidArgument(
|
||||
"table id should > 0, but value is ", table_id));
|
||||
float scale_datanorm = ctx.Attr<float>("ScaleDataNorm");
|
||||
const auto& ids = ctx.MultiInput<framework::LoDTensor>("Ids");
|
||||
int batch_size =
|
||||
ids[0]->lod().size() ? ids[0]->lod()[0].size() - 1 : ids[0]->dims()[0];
|
||||
PADDLE_ENFORCE_GT(batch_size, 0,
|
||||
platform::errors::InvalidArgument(
|
||||
"batch size should > 0, but value is ", batch_size));
|
||||
|
||||
auto fleet_ptr = framework::FleetWrapper::GetInstance();
|
||||
fleet_ptr->PushDenseVarsAsync(ctx.scope(), table_id, input_names, nullptr,
|
||||
scale_datanorm, batch_size);
|
||||
|
||||
// note: GetInstance() is not thread-safe
|
||||
// we assume PullDenseWorker has been already initialized in DistMultiTrainer
|
||||
auto pull_dense_worker = framework::PullDenseWorker::GetInstance();
|
||||
PADDLE_ENFORCE_NE(pull_dense_worker, nullptr,
|
||||
platform::errors::PreconditionNotMet(
|
||||
"pull_dense_worker should not be null"));
|
||||
int thread_id = pull_dense_worker->GetThreadIdByScope(&ctx.scope());
|
||||
pull_dense_worker->IncreaseThreadVersion(thread_id, table_id);
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
class PushDenseCPUKernel : public framework::OpKernel<T> {
|
||||
public:
|
||||
void Compute(const framework::ExecutionContext& ctx) const override {
|
||||
PushDenseFunctor<T>(ctx);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace operators
|
||||
} // namespace paddle
|
@ -0,0 +1,227 @@
|
||||
# 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.
|
||||
"""Test fleet."""
|
||||
|
||||
from __future__ import print_function
|
||||
import os
|
||||
import unittest
|
||||
import paddle.fluid.incubate.fleet.base.role_maker as role_maker
|
||||
|
||||
|
||||
class TestFleet2(unittest.TestCase):
|
||||
"""Test cases for fleet ops."""
|
||||
|
||||
def setUp(self):
|
||||
"""Set up, set envs."""
|
||||
os.environ["PADDLE_TRAINERS_NUM"] = "2"
|
||||
os.environ[
|
||||
"PADDLE_PSERVERS_IP_PORT_LIST"] = "127.0.0.1:36001,127.0.0.2:36001"
|
||||
|
||||
def test_pslib_1(self):
|
||||
"""Test cases for pslib."""
|
||||
import paddle.fluid as fluid
|
||||
from paddle.fluid.incubate.fleet.parameter_server.pslib import fleet
|
||||
from paddle.fluid.incubate.fleet.parameter_server.pslib import \
|
||||
fleet_embedding, _prepare_params, _fleet_embedding, \
|
||||
_fleet_embedding_v2, FLEET_GLOBAL_DICT
|
||||
from paddle.fluid.incubate.fleet.base.role_maker import GeneralRoleMaker
|
||||
try:
|
||||
import netifaces
|
||||
except:
|
||||
print("warning: no netifaces, skip test_pslib_1")
|
||||
return
|
||||
os.environ["POD_IP"] = "127.0.0.1"
|
||||
os.environ["PADDLE_PORT"] = "36001"
|
||||
os.environ["TRAINING_ROLE"] = "TRAINER"
|
||||
os.environ["PADDLE_TRAINER_ENDPOINTS"] = "127.0.0.1:36001"
|
||||
os.environ["PADDLE_PSERVERS_IP_PORT_LIST"] = "127.0.0.1:36002"
|
||||
os.environ["PADDLE_TRAINER_ID"] = "0"
|
||||
role_maker = GeneralRoleMaker()
|
||||
role_maker.generate_role()
|
||||
place = fluid.CPUPlace()
|
||||
exe = fluid.Executor(place)
|
||||
fleet.init(role_maker)
|
||||
train_program = fluid.Program()
|
||||
startup_program = fluid.Program()
|
||||
scope = fluid.Scope()
|
||||
global FLEET_GLOBAL_DICT
|
||||
with fluid.program_guard(train_program, startup_program):
|
||||
show = fluid.layers.data(name="show", shape=[-1, 1], \
|
||||
dtype="int64", lod_level=1, append_batch_size=False)
|
||||
click = fluid.layers.data(name="click", shape=[-1, 1], \
|
||||
dtype="int64", lod_level=1, append_batch_size=False)
|
||||
with fleet_embedding(click_name=click.name):
|
||||
emb = fluid.layers.embedding(input=show, size=[1, 1], \
|
||||
is_sparse=True, is_distributed=True, \
|
||||
param_attr=fluid.ParamAttr(name="embedding"))
|
||||
emb = fluid.layers.data_norm(
|
||||
input=emb,
|
||||
name="a",
|
||||
epsilon=1e-4,
|
||||
param_attr={
|
||||
"batch_size": 1e4,
|
||||
"batch_sum_default": 0.0,
|
||||
"batch_square": 1e4
|
||||
})
|
||||
fc = fluid.layers.fc(input=emb, size=1, act=None)
|
||||
label = fluid.layers.data(name="click", shape=[-1, 1], \
|
||||
dtype="int64", lod_level=1, append_batch_size=False)
|
||||
label_cast = fluid.layers.cast(label, dtype='float32')
|
||||
cost = fluid.layers.log_loss(fc, label_cast)
|
||||
try:
|
||||
adam = fluid.optimizer.Adam(learning_rate=0.000005)
|
||||
adam = fleet.distributed_optimizer(
|
||||
adam,
|
||||
strategy={
|
||||
"embedding": {
|
||||
"sparse_accessor_class": "DownpourSparseValueAccessor"
|
||||
}
|
||||
})
|
||||
adam.minimize([cost], [scope])
|
||||
except:
|
||||
print("do not support pslib test, skip")
|
||||
return
|
||||
FLEET_GLOBAL_DICT["cur_accessor"] = "DownpourCtrAccessor"
|
||||
try:
|
||||
_prepare_params(input=show, size=[1, 1])
|
||||
except:
|
||||
print("catch expected exception of param_attr=None")
|
||||
try:
|
||||
_prepare_params(
|
||||
input=show, size=[1, 1], param_attr=fluid.ParamAttr())
|
||||
except:
|
||||
print("catch expected exception of name=None")
|
||||
try:
|
||||
tmp = fluid.ParamAttr(name="embedding")
|
||||
_prepare_params(input=show, size=1, param_attr=tmp)
|
||||
except:
|
||||
print("catch expected exception of size not list")
|
||||
try:
|
||||
tmp = fluid.ParamAttr(name="embedding")
|
||||
_prepare_params(input=show, size=[-1, 12], param_attr=tmp)
|
||||
except:
|
||||
print("catch expected exception of size not equal")
|
||||
try:
|
||||
tmp = fluid.ParamAttr(name="embedding")
|
||||
_prepare_params(
|
||||
input=show, size=[-1, 1], param_attr=tmp, is_sparse=False)
|
||||
except:
|
||||
print("catch expected exception of is_sparse=False")
|
||||
try:
|
||||
tmp = fluid.ParamAttr(name="embedding")
|
||||
_prepare_params(input=show, size=[-1, 1], param_attr=tmp, \
|
||||
is_sparse=True, is_distributed=False)
|
||||
except:
|
||||
print("catch expected exception of is_distributed=False")
|
||||
try:
|
||||
_prepare_params(input=show, size=[-1, 1], \
|
||||
param_attr=fluid.ParamAttr(name="embedding"), \
|
||||
is_sparse=True, is_distributed=True, dtype="abc")
|
||||
except:
|
||||
print("catch expected exception of unknown dtype")
|
||||
try:
|
||||
FLEET_GLOBAL_DICT["emb_to_accessor"]["embedding"] = "unknown"
|
||||
tmp = fluid.ParamAttr(name="embedding")
|
||||
_prepare_params(input=show, size=[-1, 1], param_attr=tmp)
|
||||
except:
|
||||
print("catch expected exception of unknown accessor")
|
||||
FLEET_GLOBAL_DICT["cur_accessor"] = "DownpourCtrAccessor"
|
||||
try:
|
||||
_fleet_embedding(input=show, size=[-1, 1], is_sparse=True, \
|
||||
is_distributed=True, dtype="float32", \
|
||||
param_attr=fluid.ParamAttr(name="embedding"))
|
||||
except:
|
||||
print("catch expected exception of unknown accessor")
|
||||
try:
|
||||
_fleet_embedding_v2(input=show, size=[-1, 1], is_sparse=True, \
|
||||
is_distributed=True, dtype="float32", \
|
||||
param_attr=fluid.ParamAttr(name="embedding"))
|
||||
except:
|
||||
print("catch expected exception of unknown accessor")
|
||||
|
||||
adam1 = fluid.optimizer.Adam(learning_rate=0.000005)
|
||||
adam1 = fleet.distributed_optimizer(
|
||||
adam1,
|
||||
strategy={
|
||||
"embedding": {
|
||||
"sparse_accessor_class": "DownpourSparseValueAccessor"
|
||||
}
|
||||
})
|
||||
try:
|
||||
pre = FLEET_GLOBAL_DICT["emb_to_table"]
|
||||
FLEET_GLOBAL_DICT["emb_to_table"] = {}
|
||||
adam1.minimize([cost], [scope])
|
||||
except:
|
||||
FLEET_GLOBAL_DICT["emb_to_table"] = pre
|
||||
print("catch expected exception of empty emb_to_table")
|
||||
try:
|
||||
pre = FLEET_GLOBAL_DICT["emb_to_table"]
|
||||
FLEET_GLOBAL_DICT["emb_to_table"] = {}
|
||||
FLEET_GLOBAL_DICT["emb_to_table"]["emb1"] = 0
|
||||
adam1.minimize([cost], [scope])
|
||||
except:
|
||||
FLEET_GLOBAL_DICT["emb_to_table"] = pre
|
||||
print("catch expected exception of error emb_to_table")
|
||||
try:
|
||||
adam2 = fluid.optimizer.Adam(learning_rate=0.000005)
|
||||
adam2 = fleet.distributed_optimizer(adam2)
|
||||
adam2.supported_embedding_types = []
|
||||
adam2.minimize([cost], [scope])
|
||||
except:
|
||||
print("catch expected exception of embedding_types")
|
||||
try:
|
||||
adam3 = fluid.optimizer.Adam(learning_rate=0.000005)
|
||||
adam3 = fleet.distributed_optimizer(
|
||||
adam3,
|
||||
strategy={
|
||||
"embedding": {
|
||||
"sparse_accessor_class": "DownpourSparseValueAccessor",
|
||||
"sparse_embedx_dim": 999
|
||||
}
|
||||
})
|
||||
adam3.minimize([cost], [scope])
|
||||
except:
|
||||
print("catch expected exception of embedx_dim error")
|
||||
|
||||
try:
|
||||
adam4 = fluid.optimizer.Adam(learning_rate=0.000005)
|
||||
adam4 = fleet.distributed_optimizer(
|
||||
adam4,
|
||||
strategy={
|
||||
"embedding": {
|
||||
"sparse_accessor_class": "DownpourCtrAccessor",
|
||||
"sparse_embedx_dim": 999
|
||||
}
|
||||
})
|
||||
adam4.minimize([cost], [scope])
|
||||
except:
|
||||
print("catch expected exception of embedx_dim error")
|
||||
train_program1 = fluid.Program()
|
||||
startup_program1 = fluid.Program()
|
||||
FLEET_GLOBAL_DICT["emb_to_accessor"] = {}
|
||||
with fluid.program_guard(train_program1, startup_program1):
|
||||
show = fluid.layers.data(name="show", shape=[-1, 1], \
|
||||
dtype="int64", lod_level=1, append_batch_size=False)
|
||||
with fleet_embedding(click_name=click.name):
|
||||
emb = fluid.layers.embedding(input=show, size=[1, 1], \
|
||||
is_sparse=True, is_distributed=True, \
|
||||
param_attr=fluid.ParamAttr(name="embedding"))
|
||||
with fleet_embedding(click_name=click.name):
|
||||
emb1 = fluid.embedding(input=show, size=[1, 1], \
|
||||
is_sparse=True, is_distributed=True, \
|
||||
param_attr=fluid.ParamAttr(name="embedding"))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
@ -0,0 +1,107 @@
|
||||
# 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.
|
||||
"""Test fleet."""
|
||||
|
||||
from __future__ import print_function
|
||||
import os
|
||||
import paddle.fluid as fluid
|
||||
import unittest
|
||||
import paddle.fluid.incubate.fleet.base.role_maker as role_maker
|
||||
from paddle.fluid.incubate.fleet.parameter_server.pslib import fleet
|
||||
from paddle.fluid.incubate.fleet.parameter_server.pslib import \
|
||||
fleet_embedding, _prepare_params, _fleet_embedding, \
|
||||
_fleet_embedding_v2, FLEET_GLOBAL_DICT
|
||||
from paddle.fluid.incubate.fleet.base.role_maker import GeneralRoleMaker
|
||||
|
||||
|
||||
class TestFleet2(unittest.TestCase):
|
||||
"""Test cases for fleet ops."""
|
||||
|
||||
def test_in_memory_dataset_run_fleet(self):
|
||||
"""
|
||||
Testcase for InMemoryDataset from create to run.
|
||||
"""
|
||||
with open("test_in_memory_dataset_run_fleet_a.txt", "w") as f:
|
||||
data = "1 1 1 2 2 3 3 4 5 5 5 5 1 1\n"
|
||||
data += "1 0 1 3 2 3 4 4 6 6 6 6 1 2\n"
|
||||
data += "1 1 1 4 2 3 5 4 7 7 7 7 1 3\n"
|
||||
f.write(data)
|
||||
with open("test_in_memory_dataset_run_fleet_b.txt", "w") as f:
|
||||
data = "1 0 1 5 2 3 3 4 5 5 5 5 1 4\n"
|
||||
data += "1 1 1 6 2 3 4 4 6 6 6 6 1 5\n"
|
||||
data += "1 0 1 7 2 3 5 4 7 7 7 7 1 6\n"
|
||||
data += "1 1 1 8 2 3 6 4 8 8 8 8 1 7\n"
|
||||
f.write(data)
|
||||
|
||||
slots = ["click", "slot1", "slot2", "slot3", "slot4"]
|
||||
slots_vars = []
|
||||
for slot in slots:
|
||||
var = fluid.layers.data(
|
||||
name=slot, shape=[1], dtype="int64", lod_level=1)
|
||||
slots_vars.append(var)
|
||||
click = slots_vars[0]
|
||||
embs = []
|
||||
for slot in slots_vars[1:3]:
|
||||
with fleet_embedding(click_name=click.name):
|
||||
emb = fluid.layers.embedding(input=slot, size=[-1, 11], \
|
||||
is_sparse=True, is_distributed=True, \
|
||||
param_attr=fluid.ParamAttr(name="embedding"))
|
||||
embs.append(emb)
|
||||
for slot in slots_vars[3:5]:
|
||||
with fleet_embedding(click_name=click.name):
|
||||
emb = fluid.embedding(input=slot, size=[-1, 11], \
|
||||
is_sparse=True, is_distributed=True, \
|
||||
param_attr=fluid.ParamAttr(name="embedding"))
|
||||
emb = fluid.layers.reshape(emb, [-1, 11])
|
||||
embs.append(emb)
|
||||
concat = fluid.layers.concat([embs[0], embs[3]], axis=1)
|
||||
fc = fluid.layers.fc(input=concat, size=1, act=None)
|
||||
label_cast = fluid.layers.cast(slots_vars[1], dtype='float32')
|
||||
cost = fluid.layers.log_loss(fc, label_cast)
|
||||
cost = fluid.layers.mean(cost)
|
||||
|
||||
try:
|
||||
fleet.init()
|
||||
adam = fluid.optimizer.Adam(learning_rate=0.000005)
|
||||
adam = fleet.distributed_optimizer(adam)
|
||||
scope = fluid.Scope()
|
||||
adam.minimize([cost], [scope])
|
||||
except:
|
||||
print("do not support pslib test, skip")
|
||||
return
|
||||
|
||||
dataset = fluid.DatasetFactory().create_dataset("InMemoryDataset")
|
||||
dataset.set_batch_size(1)
|
||||
dataset.set_thread(2)
|
||||
dataset.set_filelist([
|
||||
"test_in_memory_dataset_run_fleet_a.txt",
|
||||
"test_in_memory_dataset_run_fleet_b.txt"
|
||||
])
|
||||
dataset.set_pipe_command("cat")
|
||||
dataset.set_use_var(slots_vars)
|
||||
dataset.load_into_memory()
|
||||
|
||||
exe = fluid.Executor(fluid.CPUPlace())
|
||||
exe.run(fluid.default_startup_program())
|
||||
exe.train_from_dataset(fluid.default_main_program(), dataset)
|
||||
fleet._opt_info["stat_var_names"] = ["233"]
|
||||
exe.infer_from_dataset(fluid.default_main_program(), dataset)
|
||||
fleet._opt_info = None
|
||||
fleet._fleet_ptr = None
|
||||
os.remove("./test_in_memory_dataset_run_fleet_a.txt")
|
||||
os.remove("./test_in_memory_dataset_run_fleet_b.txt")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
Loading…
Reference in new issue