parent
be72940b76
commit
ca5d96bb3d
@ -0,0 +1,189 @@
|
|||||||
|
// Copyright (c) 2018 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 <set>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "paddle/fluid/operators/distributed/parameter_send.h"
|
||||||
|
|
||||||
|
#include "paddle/fluid/framework/lod_tensor.h"
|
||||||
|
#include "paddle/fluid/framework/scope.h"
|
||||||
|
#include "paddle/fluid/framework/selected_rows.h"
|
||||||
|
#include "paddle/fluid/framework/tensor.h"
|
||||||
|
|
||||||
|
#include "paddle/fluid/operators/distributed/distributed.h"
|
||||||
|
#include "paddle/fluid/operators/distributed/rpc_client.h"
|
||||||
|
#include "paddle/fluid/operators/distributed/variable_response.h"
|
||||||
|
#include "paddle/fluid/operators/distributed_ops/send_recv_util.h"
|
||||||
|
|
||||||
|
namespace paddle {
|
||||||
|
namespace operators {
|
||||||
|
namespace distributed {
|
||||||
|
|
||||||
|
using LoDTensor = framework::LoDTensor;
|
||||||
|
using LoDTensor = framework::LoDTensor;
|
||||||
|
using SelectedRows = framework::SelectedRows;
|
||||||
|
using DDim = framework::DDim;
|
||||||
|
|
||||||
|
static size_t GetSectionIndex(int64_t id,
|
||||||
|
const std::vector<int64_t>& abs_sections) {
|
||||||
|
for (size_t i = 1; i < abs_sections.size(); ++i) {
|
||||||
|
if (id < abs_sections[i]) {
|
||||||
|
return i - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return abs_sections.size() - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::vector<int64_t> ToAbsoluteSection(
|
||||||
|
const std::vector<int>& height_sections) {
|
||||||
|
std::vector<int64_t> abs_sections;
|
||||||
|
abs_sections.resize(height_sections.size());
|
||||||
|
abs_sections[0] = 0;
|
||||||
|
for (size_t i = 1; i < height_sections.size(); ++i) {
|
||||||
|
abs_sections[i] = height_sections[i - 1] + abs_sections[i - 1];
|
||||||
|
}
|
||||||
|
return abs_sections;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::vector<std::vector<int64_t>> SplitIds(
|
||||||
|
const std::vector<int64_t>& ids_vector,
|
||||||
|
const std::vector<int>& height_section, framework::Scope* scope) {
|
||||||
|
std::set<int64_t> all_ids;
|
||||||
|
for (auto id : ids_vector) {
|
||||||
|
all_ids.insert(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto abs_sections = ToAbsoluteSection(height_section);
|
||||||
|
std::vector<std::vector<int64_t>> splited_ids;
|
||||||
|
splited_ids.resize(height_section.size() + 1);
|
||||||
|
for (auto& id : all_ids) {
|
||||||
|
auto section_index = GetSectionIndex(id, abs_sections);
|
||||||
|
splited_ids[section_index].push_back(id - abs_sections[section_index]);
|
||||||
|
}
|
||||||
|
return splited_ids;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void SplitIdsIntoMultipleVarsBySection(
|
||||||
|
const std::vector<std::string>& in_var_names,
|
||||||
|
const std::vector<int>& height_section,
|
||||||
|
const std::vector<std::vector<int64_t>>& splited_ids,
|
||||||
|
framework::Scope* scope) {
|
||||||
|
PADDLE_ENFORCE_EQ(in_var_names.size(), height_section.size(), "");
|
||||||
|
|
||||||
|
auto place = platform::CPUPlace();
|
||||||
|
|
||||||
|
for (size_t i = 0; i < in_var_names.size(); ++i) {
|
||||||
|
auto* id_tensor =
|
||||||
|
scope->Var(in_var_names[i])->GetMutable<framework::LoDTensor>();
|
||||||
|
auto& ids = splited_ids[i];
|
||||||
|
if (!ids.empty()) {
|
||||||
|
auto* id_tensor_data = id_tensor->mutable_data<int64_t>(
|
||||||
|
framework::make_ddim({static_cast<int64_t>(ids.size()), 1}), place);
|
||||||
|
memcpy(id_tensor_data, ids.data(), sizeof(int64_t) * ids.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void send(const std::string& var_name,
|
||||||
|
const std::vector<std::string>& send_varnames,
|
||||||
|
const std::vector<std::string>& epmap,
|
||||||
|
const std::vector<int>& height_sections,
|
||||||
|
const framework::ExecutionContext& context,
|
||||||
|
const framework::Scope& scope, bool sync) {
|
||||||
|
framework::Scope* local_scope = scope.NewTmpScope();
|
||||||
|
|
||||||
|
platform::DeviceContextPool& pool = platform::DeviceContextPool::Instance();
|
||||||
|
auto& cpu_ctx = *pool.Get(platform::CPUPlace());
|
||||||
|
auto& actual_ctx = *pool.Get(context.GetPlace());
|
||||||
|
|
||||||
|
distributed::RPCClient* rpc_client =
|
||||||
|
distributed::RPCClient::GetInstance<RPCCLIENT_T>(
|
||||||
|
context.Attr<int>("trainer_id"));
|
||||||
|
|
||||||
|
auto* send_var = scope.FindVar(var_name);
|
||||||
|
size_t out_num = send_varnames.size();
|
||||||
|
if (send_var->IsType<framework::LoDTensor>()) {
|
||||||
|
auto& send_tensor = send_var->Get<framework::LoDTensor>();
|
||||||
|
auto& send_tensor_dims = send_tensor.dims();
|
||||||
|
std::vector<framework::DDim> outs_dims;
|
||||||
|
outs_dims.reserve(out_num);
|
||||||
|
|
||||||
|
// infer output shape
|
||||||
|
int num = context.Attr<int>("num");
|
||||||
|
if (num > 0) {
|
||||||
|
int64_t in_axis_dim = send_tensor_dims[0];
|
||||||
|
PADDLE_ENFORCE_EQ(in_axis_dim % num, 0,
|
||||||
|
"tensor split does not result"
|
||||||
|
" in an equal division");
|
||||||
|
size_t out_axis_dim = in_axis_dim / num;
|
||||||
|
for (size_t i = 0; i < out_num; ++i) {
|
||||||
|
auto dim = send_tensor_dims;
|
||||||
|
dim[0] = out_axis_dim;
|
||||||
|
outs_dims.push_back(dim);
|
||||||
|
}
|
||||||
|
} else if (height_sections.size() > 0) {
|
||||||
|
PADDLE_ENFORCE_EQ(height_sections.size(), out_num,
|
||||||
|
"tensor split sections size"
|
||||||
|
"should be equal to output size.");
|
||||||
|
for (size_t i = 0; i < out_num; ++i) {
|
||||||
|
auto dim = send_tensor_dims;
|
||||||
|
dim[0] = height_sections[i];
|
||||||
|
outs_dims.push_back(dim);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// create output var in local scope
|
||||||
|
size_t row_offset = 0;
|
||||||
|
for (auto i = 0; i < out_num; ++i) {
|
||||||
|
auto* out =
|
||||||
|
local_scope->Var(send_varnames[i])->GetMutable<framework::Tensor>();
|
||||||
|
*out = send_tensor.Slice(row_offset, row_offset + outs_dims[i][0]);
|
||||||
|
row_offset += outs_dims[i][0];
|
||||||
|
}
|
||||||
|
} else if (send_var->IsType<framework::LoDTensor>()) {
|
||||||
|
// create output var in local scope
|
||||||
|
for (auto& name : send_varnames) {
|
||||||
|
local_scope->Var(name)->GetMutable<framework::SelectedRows>();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
PADDLE_THROW("unsupported var type");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<distributed::VarHandlePtr> rets;
|
||||||
|
for (size_t i = 0; i < send_varnames.size(); i++) {
|
||||||
|
auto& send_var_name = send_varnames[i];
|
||||||
|
auto& endpoint = epmap[i];
|
||||||
|
if (NeedSend(*local_scope, send_var_name)) {
|
||||||
|
VLOG(3) << "sending " << send_var_name << " to " << endpoint;
|
||||||
|
rets.push_back(rpc_client->AsyncSendVar(endpoint, cpu_ctx, *local_scope,
|
||||||
|
send_var_name));
|
||||||
|
} else {
|
||||||
|
VLOG(3) << "don't send non-initialized variable: " << send_varnames[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sync) {
|
||||||
|
for (size_t i = 0; i < rets.size(); i++) {
|
||||||
|
PADDLE_ENFORCE(rets[i]->Wait(), "internal error in RPCClient");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delete local_scope;
|
||||||
|
}
|
||||||
|
|
||||||
|
}; // namespace distributed
|
||||||
|
}; // namespace operators
|
||||||
|
}; // namespace paddle
|
@ -0,0 +1,35 @@
|
|||||||
|
// Copyright (c) 2018 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 <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "paddle/fluid/framework/operator.h"
|
||||||
|
|
||||||
|
namespace paddle {
|
||||||
|
namespace operators {
|
||||||
|
namespace distributed {
|
||||||
|
|
||||||
|
void send(const std::string& var_name,
|
||||||
|
const std::vector<std::string>& send_varnames,
|
||||||
|
const std::vector<std::string>& epmap,
|
||||||
|
const std::vector<int>& height_sections,
|
||||||
|
const framework::ExecutionContext& context,
|
||||||
|
const framework::Scope& scope, bool sync);
|
||||||
|
|
||||||
|
}; // namespace distributed
|
||||||
|
}; // namespace operators
|
||||||
|
}; // namespace paddle
|
Loading…
Reference in new issue